Index: trunk/src/testing/app-3rd-party/sagepdf/dxt.cpp
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/dxt.cpp	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app-3rd-party/sagepdf/intrinsic.cpp
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app-3rd-party/sagepdf/util.h
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/util.h	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/util.h	(revision 4)
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
Index: trunk/src/testing/app-3rd-party/sagepdf/Changelog.txt
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/Changelog.txt	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/Changelog.txt	(revision 4)
@@ -0,0 +1,24 @@
+20110316 CKW - version 0.4
+  - replace all GdkPixbuf operations including poppler_page_render_to_pixbuf()
+    (deprecated since poppler-0.16)
+  - change applications.conf example entry so that DXT won't be used by default
+  - don't render existing page again
+  - when the local window ends, shutdown the SAGE instance of sagepdf too
+
+20110315 CKW - version 0.3
+  - vary width & height args for poppler_page_render_to_pixbuf()
+    depending on poppler version ( > 0.12 )
+  - add display pointer event handling
+  - add same events to local display
+  - add DXT support
+  - fit Makefile into SAGE environment
+  - change args to match pdfviewer but add and use -scale option,
+rather than deriving a scaleFactor from window_width & window_height.
+
+20110311 CKW - version 0.2
+  -  try to ensure the supplied pdf file has an absolute location
+     (and that we have access to read it).
+
+20110309 CKW - Version 0.1
+  - sagepdf is a PDF viewer for a tiled display running SAGE.
+
Index: trunk/src/testing/app-3rd-party/sagepdf/TODO
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/TODO	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/TODO	(revision 4)
@@ -0,0 +1,3 @@
+1. Add ability to resize sagepdf window on local display
+2. Let scale factor be non integer i.e allow 1.7
+
Index: trunk/src/testing/app-3rd-party/sagepdf/dxt.h
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/dxt.h	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/dxt.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app-3rd-party/sagepdf/libdxt.cpp
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/libdxt.cpp	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app-3rd-party/sagepdf/COPYING
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/COPYING	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/COPYING	(revision 4)
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: trunk/src/testing/app-3rd-party/sagepdf/sagepdf.cpp
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/sagepdf.cpp	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/sagepdf.cpp	(revision 4)
@@ -0,0 +1,551 @@
+/**************************************************************************
+    sagepdf - a PDF viewer for SAGE tiled displays.
+    Copyright (C) 2011  Christoph Willing
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+**************************************************************************/
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cairo.h>
+#include <libgen.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <glib/poppler.h>
+#include <math.h>
+
+#define SAGEPDF_DEF_SCALEFACTOR	(4)
+
+int npages;
+int firstPage = 0;
+PopplerDocument *document;
+PopplerPage *page;
+double	width, height;
+cairo_t *cr, *sage_cr;
+cairo_surface_t *surface, *sage_surface;
+int scaleFactor;
+
+#ifndef NOSAGE
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+sail sageInf; // sail object
+
+// for dxt compression
+#include "libdxt.h"
+
+using namespace std;
+bool useDXT = true;
+
+byte *sageBuffer = NULL;  // buffers for sage and dxt data
+byte *dxt = NULL;
+byte *rgba = NULL;
+
+float lastX = 0;
+float lastY = 0;
+float dist = 0;
+
+GdkWindow *local_window = NULL;
+#endif
+
+float local_startX = 0;
+float local_startY = 0;
+float local_dist = 0;
+bool button1_is_pressed = false;
+
+
+void
+show_page()
+{
+	/* Clear window */
+	cairo_rectangle(cr, 0, 0, width, height);
+	cairo_stroke_preserve(cr);
+	cairo_set_source_rgb(cr, 1, 1, 1);
+	cairo_fill(cr);
+
+
+	cairo_set_source_surface(cr, surface, 0, 0);
+	cairo_translate(cr, 0, 0);
+	cairo_scale(cr, 1, 1);
+	poppler_page_render(page, cr);
+
+	cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
+	cairo_set_source_rgb(cr, 1, 1, 1);
+	cairo_paint(cr);
+
+
+#ifndef NOSAGE
+	if( useDXT )
+	{
+		int cairo_height, cairo_width, cairo_rowstride;
+		unsigned int numBytes, *src;
+		unsigned char *cairo_data, *dst;
+
+		sage_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width*scaleFactor, height*scaleFactor);
+		sage_cr = cairo_create(sage_surface);
+		cairo_save (sage_cr);
+		/* Flip */
+		cairo_translate(sage_cr, 0, height*scaleFactor);
+		cairo_scale(sage_cr, scaleFactor, -scaleFactor);
+		poppler_page_render (page, sage_cr);
+		cairo_restore (sage_cr);
+
+		cairo_set_operator(sage_cr, CAIRO_OPERATOR_DEST_OVER);
+		cairo_set_source_rgba(sage_cr, 1, 1, 1, 1);
+		cairo_paint(sage_cr);
+
+		/* We'd like to apply the sage_surface data directly to the
+		*  DXT compression engine but it is in the wrong colour space.
+		*  Therefore we extract it manually to the rgba buffer.
+		*/
+		cairo_height = cairo_image_surface_get_height (sage_surface);
+		cairo_width = cairo_image_surface_get_width (sage_surface);
+		cairo_rowstride = cairo_image_surface_get_stride (sage_surface);
+		cairo_data = cairo_image_surface_get_data (sage_surface);
+		for (int y = 0; y < cairo_height; y++)
+		{
+			src = (unsigned int *) (cairo_data + y * cairo_rowstride);
+			dst = rgba + y * cairo_rowstride;
+			for (int x = 0; x < cairo_width; x++) 
+			{
+				dst[0] = (*src >> 16) & 0xff;
+				dst[1] = (*src >> 8) & 0xff; 
+				dst[2] = (*src >> 0) & 0xff;
+				dst[3] = (*src >> 24) & 0xff;
+				dst += 4;
+				src++;
+			}
+		}
+
+		numBytes = CompressDXT(rgba, dxt, scaleFactor * width, scaleFactor * height, FORMAT_DXT1, 1);
+		sageBuffer = (byte*)sageInf.getBuffer();
+		memcpy(sageBuffer, dxt, scaleFactor * scaleFactor * width*height*4/8);
+		sageInf.swapBuffer();
+
+		cairo_destroy(sage_cr);
+	}
+	else
+	{
+		sage_surface = cairo_image_surface_create_for_data ((unsigned char*)sageInf.getBuffer(),
+					     CAIRO_FORMAT_ARGB32, width * scaleFactor, height * scaleFactor,
+					     cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width * scaleFactor));
+		sage_cr = cairo_create(sage_surface);
+
+		/* Clear SAGE window */
+		cairo_rectangle(sage_cr, 0, 0, width * scaleFactor, height * scaleFactor);
+		cairo_stroke_preserve(sage_cr);
+		cairo_set_source_rgb(sage_cr, 1, 1, 1);
+		cairo_fill(sage_cr);
+
+		cairo_set_source_surface(sage_cr, sage_surface, 0, 0);
+		cairo_scale(sage_cr, scaleFactor, scaleFactor);
+		poppler_page_render(page, sage_cr);
+		cairo_set_operator(sage_cr, CAIRO_OPERATOR_DEST_OVER);
+		cairo_set_source_rgb(sage_cr, 1, 1, 1);
+		cairo_paint(sage_cr);
+
+		sageInf.swapBuffer();
+		cairo_destroy(sage_cr);
+	}
+#endif
+
+}
+
+void
+show_absolute_page(int requested_page)
+{
+	if( requested_page < 0 )
+		requested_page = 0;
+	if( requested_page >= npages )
+		requested_page = npages - 1;
+
+	/* Don't render again if we're already at that page */
+	if( poppler_page_get_index(page) == requested_page )
+		return;
+
+	page = poppler_document_get_page(document, requested_page);
+	show_page();
+}
+
+void
+show_next_page(int next)
+{
+	show_absolute_page(poppler_page_get_index(page) + next);
+/*
+	int ncurrent = poppler_page_get_index(page) + next;
+	if( (ncurrent > -1) && (ncurrent < npages) )
+		page = poppler_document_get_page(document, ncurrent);
+	show_page();
+*/
+}
+
+gint
+check_sage_messages(gpointer data)
+{
+#ifndef NOSAGE
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+		char *data = (char*) msg.getData();
+
+		switch (msg.getCode()) {
+			case APP_QUIT : {
+				sageInf.shutdown();
+				gtk_main_quit();
+				break;
+
+			case EVT_CLICK:
+				// Click event x and y location normalized to size of window
+				float clickX, clickY;
+
+				// Click device Id, button Id, and is down flag
+				int clickDeviceId, clickButtonId, clickIsDown, clickEvent;
+
+				// Parse message
+				sscanf(data, 
+				       "%d %f %f %d %d %d", 
+				       &clickDeviceId, &clickX, &clickY, 
+				       &clickButtonId, &clickIsDown, &clickEvent);
+				//printf("Pointer click at %f,%f\n", clickX, clickY);
+
+				// record the click position so we know how far we moved
+				if (clickIsDown && clickEvent == EVT_PAN) {
+				    lastX = clickX;
+				    lastY = clickY;
+				}
+
+				if( clickIsDown )
+				{
+					//printf("Pointer click by button %d\n", clickButtonId);
+
+					cr = gdk_cairo_create(local_window);
+					if( clickButtonId == 1 )
+						show_next_page(1);
+					else
+						show_next_page(-1);
+				}
+
+				break;
+
+			case EVT_PAN: 
+				// Pan event properties
+				int panDeviceId;
+
+				// Pan event x and y location and change in x, y and z direction
+				// normalized to size of window
+				float startX, startY, panDX, panDY, panDZ;
+				sscanf(data, 
+					"%d %f %f %f %f %f", 
+					&panDeviceId, &startX, &startY, &panDX, &panDY, &panDZ);
+
+				// keep track of distance
+				dist += panDX;
+
+				// we started a new drag
+				if (lastX != startX) {
+					lastX = startX;
+					dist = 0;
+				}
+				else if( fabs(dist) > 0.07 ) { // if we dragged more than a certain distance, change a page
+					cr = gdk_cairo_create(local_window);
+					if (dist > 0)
+						show_next_page(1);
+					else
+						show_next_page(-1);
+
+					// reset the counter
+					lastX = startX;
+					dist = 0;
+				}
+				break;
+
+			}
+		}      
+	}
+#endif
+	return TRUE;
+}
+
+static gboolean
+on_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
+{
+	float local_lastX = event->x;
+	local_dist = local_lastX - local_startX; 
+
+	if( button1_is_pressed )
+		if( fabs(local_dist / width) > 0.07 )
+		{
+			cr = gdk_cairo_create(widget->window);
+			local_startX = local_lastX;
+			if( local_dist > 0 )
+				show_next_page(1);
+			else
+				show_next_page(-1);
+		}
+
+	return true;
+}
+
+static gboolean
+on_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+	cr = gdk_cairo_create(widget->window);
+	button1_is_pressed = false;
+	switch(event->button)
+	{
+		case 1:
+			button1_is_pressed = true;
+			local_startX = event->x;
+			show_next_page(1);
+			break;
+		case 3:
+			show_next_page(-1);
+			break;
+		default:
+			// printf("Unhandled button press: %d\n", event->button);
+			return false;
+			break;
+	}
+	return true;
+}
+
+static gboolean
+on_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+	cr = gdk_cairo_create(widget->window);
+	switch(event->keyval)
+	{
+		case GDK_Home:
+			show_absolute_page(0);
+			break;
+		case GDK_End:
+			show_absolute_page(npages);
+			break;
+		case GDK_Page_Up:
+		case GDK_Left:
+			show_next_page(-1);
+			break;
+		case GDK_Page_Down:
+		case GDK_Right:
+			show_next_page(1);
+			break;
+		case GDK_Escape:
+			printf("Quit\n");
+			gtk_main_quit();
+			break;
+		default:
+			// printf("XXXXXXXXXX Unhandled key: %d\n", event->keyval);
+			return false;
+			break;
+	}
+	return true;
+}
+
+static gboolean
+on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+	cr = gdk_cairo_create(widget->window);
+	show_page();
+
+	return FALSE;
+}
+
+
+int main(int argc, char *argv[])
+{
+	unsigned int window_width=-1, window_height=-1;  // sage window size
+	GtkWidget *window;
+
+	char *filename;
+	char pathbuf[PATH_MAX];
+	char uri[256];
+	char *dirc, *basec, *dname, *bname;
+	int     i=0;
+
+	gtk_init(&argc, &argv);
+	scaleFactor = SAGEPDF_DEF_SCALEFACTOR;
+#ifndef NOSAGE
+	sage::initUtil();
+#endif
+
+	// parse command line arguments
+	if( argc < 2 )
+	{
+#ifndef NOSAGE
+		sage::printLog("PDF> sagepdf filename [width] [height] [-show_original] [-page num] [-scale num]");
+#else
+		fprintf(stderr, "PDF> sagepdf filename [width] [height] [-show_original] [-page num] [-scale num]\n");
+#endif
+		exit(1);
+	}
+	for (int argNum=2; argNum<argc; argNum++)
+	{
+		if( strcmp(argv[argNum], "-page") == 0 )
+		{
+			int p = atoi(argv[argNum+1]);
+			if( p > 0 )
+				firstPage = p - 1;
+			if( p < 0 )
+				firstPage = 0;
+			argNum++;
+		}
+#ifndef NOSAGE
+		else if (strcmp(argv[argNum], "-show_original") == 0)
+		{
+			useDXT = false;
+		}
+#endif
+		else if( strcmp(argv[argNum], "-scale") == 0 )
+		{
+			scaleFactor = atoi(argv[argNum+1]);
+			if( scaleFactor < 1 )
+				scaleFactor = 1;
+			argNum++;
+		}
+		else if(atoi(argv[argNum]) != 0 && atoi(argv[argNum+1]) != 0)
+		{
+			window_width = atoi( argv[argNum] );
+			window_height = atoi( argv[argNum+1] );
+			argNum++;
+		}
+	}
+
+	/* Check that the filename is an absolute pathname */
+	filename = argv[1];
+	dirc = strdup(filename);
+	basec = strdup(filename);
+	dname = dirname(dirc);
+	bname = basename(basec);
+
+	if( dname[0] != '/' )
+	{
+		fprintf(stderr, "Need absolute path for PDF file\n");
+
+		/* We could try to construct a path -
+		 * assume the path givern is relative to here
+		 */
+		if( ! getcwd(pathbuf, PATH_MAX) )
+			exit(1);
+		sprintf(pathbuf + strlen(pathbuf), "/\0");
+		strcat(pathbuf, filename);
+		fprintf(stderr, "Lets try %s\n", pathbuf);
+	}
+	else
+	{
+		sprintf(pathbuf, "%s\0", filename);
+	}
+	/* Can we read it ? */
+	if( access(pathbuf, R_OK ) )
+	{
+		fprintf(stderr, "Can't access %s - exiting now ...\n", filename);
+		exit(2);
+	}
+
+	sprintf(uri, "file://%s\0", pathbuf);
+	document = poppler_document_new_from_file(uri, NULL, NULL);
+	npages = poppler_document_get_n_pages(document);
+
+	if( npages <= firstPage )
+		firstPage = npages - 1;
+	page = poppler_document_get_page(document, firstPage);
+	poppler_page_get_size(page, &width, &height);
+	printf("Page %d has size %fx%f\n", firstPage, width, height);
+
+
+#ifndef NOSAGE
+	if (useDXT)
+	{
+		if ((int)width % 4 != 0 || (int)height % 4 != 0)
+		{
+			fprintf(stderr, "\n**** Image cropped a few pixels to be a multiple of 4 for dxt");
+			width -= (int)width % 4; width = (int)width * 1.0;
+			height -= (int)height % 4; height = (int)height * 1.0;
+		}
+
+		// allocate buffers 
+		rgba = (byte*) memalign(16, scaleFactor * scaleFactor * width*height*4);
+		dxt = (byte*) memalign(16, scaleFactor * scaleFactor * width*height*4/8);
+	}
+
+	// SAGE setup
+	sailConfig cfg;
+	cfg.init("sagepdf.conf");   // every app has a config file named "appName.conf"
+	std::cout << "SAIL configuration was initialized by sagepdf.conf" << std::endl;
+
+	cfg.setAppName("sagepdf");
+	cfg.rank = 0;
+	cfg.resX = width * scaleFactor;
+	cfg.resY = height * scaleFactor;
+	cfg.winWidth = width * scaleFactor;
+	cfg.winHeight = height * scaleFactor;
+
+	sageRect renderImageMap;
+	renderImageMap.left = 0.0;
+	renderImageMap.right = 1.0;
+	renderImageMap.bottom = 0.0;
+	renderImageMap.top = 1.0;
+
+	cfg.imageMap = renderImageMap;
+	if( useDXT )
+	{
+		cfg.pixFmt = PIXFMT_DXT;
+		cfg.rowOrd = BOTTOM_TO_TOP;
+	}
+	else
+	{
+		cfg.pixFmt = PIXFMT_8888_INV;
+		cfg.rowOrd = TOP_TO_BOTTOM;
+	}
+	cfg.master = TRUE;
+
+	sageInf.init(cfg);
+	std::cout << "sail initialized " << std::endl;
+#endif
+
+	//printf("Using page size %fx%f\n", width, height);
+	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+	gtk_window_set_default_size(GTK_WINDOW(window), width, height); 
+	gtk_widget_set_app_paintable(window, TRUE);
+
+
+	g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL);
+	g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+	g_signal_connect(window, "key_release_event", G_CALLBACK (on_key_release_event), NULL);
+	g_signal_connect(window, "button_press_event", G_CALLBACK (on_button_press_event), NULL);
+	g_signal_connect(window, "motion_notify_event", G_CALLBACK (on_motion_notify_event), NULL);
+	gtk_widget_set_events (window,	GDK_KEY_RELEASE |
+					GDK_BUTTON_PRESS_MASK |
+					GDK_BUTTON_MOTION_MASK |
+					GDK_POINTER_MOTION_HINT_MASK );
+
+	gtk_widget_show_all(window);
+#ifndef NOSAGE
+	local_window = window->window;
+#endif
+
+	g_timeout_add (200, check_sage_messages, NULL);
+
+	gtk_main();
+	sageInf.shutdown();
+	cairo_surface_destroy(surface);
+
+	return 0;
+}
+
Index: trunk/src/testing/app-3rd-party/sagepdf/README.mac
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/README.mac	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/README.mac	(revision 4)
@@ -0,0 +1,14 @@
+20110311 CKW
+
+sagepdf has been built and run on a Mac OSX (Leopard).
+Assuming Mac Ports have already been installed and
+sufficient ports have been installed to successfully
+build the SAGE software itself, the further ports
+required to build sagepdf are cairo-devel and poppler
+i.e. run:
+	sudo port install cairo-devel
+	sudo port install poppler
+
+Evrything else, including building sagepdf itself is
+as per the plain README file.
+
Index: trunk/src/testing/app-3rd-party/sagepdf/libdxt.h
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/libdxt.h	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app-3rd-party/sagepdf/Makefile
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/Makefile	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/Makefile	(revision 4)
@@ -0,0 +1,105 @@
+include ../../config.mk
+SAGE_DIR = ../..
+#include ${SAGE_DIRECTORY}/config.mk
+#SAGE_DIR=${SAGE_DIRECTORY}
+
+USE_POPPLER=$(shell pkg-config --atleast-version=0.5 poppler && echo 1)
+#USE_POPPLER=0
+
+SDIR=${SAGE_DIR}
+QUANTA_CFLAGS=-I${SDIR}/QUANTA/include
+QUANTA_LDFLAGS=-L${SDIR}/lib -lquanta
+
+ifeq ($(USE_POPPLER), 1)
+
+USE_POPPLER12=$(shell pkg-config --atleast-version=0.12 poppler && echo 1)
+
+ifeq ($(USE_POPPLER12), 1)
+CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=5 `pkg-config --cflags poppler-glib` `pkg-config --cflags gtk+-2.0` -I$(SAGE_DIR)/include -fno-stack-protector $(QUANTA_CFLAGS) $(PORTAUDIO_CFLAGS)
+LIBS= `pkg-config --libs poppler-glib` `pkg-config --libs gtk+-2.0` -L$(SAGE_DIR)/lib -lsail $(QUANTA_LDFLAGS) $(PAUDIO_LIB) -lpthread
+NOSAGE_CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=5 `pkg-config --cflags poppler-glib` `pkg-config --cflags gtk+-2.0` -fno-stack-protector $(PORTAUDIO_CFLAGS)
+NOSAGE_LIBS= `pkg-config --libs poppler-glib` `pkg-config --libs gtk+-2.0` $(PAUDIO_LIB) -lpthread
+else
+CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=12 `pkg-config --cflags poppler` `pkg-config --cflags gtk+-2.0` -I$(SAGE_DIR)/include -fno-stack-protector $(QUANTA_CFLAGS) $(PORTAUDIO_CFLAGS)
+LIBS= `pkg-config --libs poppler` `pkg-config --libs gtk+-2.0` -L$(SAGE_DIR)/lib -lsail $(QUANTA_LDFLAGS) $(PAUDIO_LIB) -lpthread
+NOSAGE_CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=12 `pkg-config --cflags poppler` `pkg-config --cflags gtk+-2.0` -fno-stack-protector $(PORTAUDIO_CFLAGS)
+NOSAGE_LIBS= `pkg-config --libs poppler` `pkg-config --libs gtk+-2.0` $(PAUDIO_LIB) -lpthread
+endif
+
+else
+	error - need poppler
+endif
+
+
+#----------------  BEGIN FastDXT stuff  ----------------#
+
+OPTIM=1
+
+ifeq ($(MACHINE), Darwin)
+
+CFLAGS+=-m32
+LIBS+=-L/opt/local/lib
+
+CFLAGS+=-I/opt/local/include
+
+ifeq ($(ARCHITECTURE), i386)
+        # Intel Mac
+
+ifeq ($(OPTIM), 1)
+# MacPro
+# CXXFLAGS+=-march=nocona -msse3 -DDXT_INTR
+
+# MacbookPro
+# CFLAGS+=-march=i686 -msse2 -DDXT_INTR
+CFLAGS+=-DDXT_INTR
+endif
+
+endif
+
+ifeq ($(ARCHITECTURE), powerpc)
+        # PowerPC Mac
+echo "Disabling SSE instructions on PowerPC"
+CFLAGS+=
+endif
+endif
+
+ifeq ($(ARCHITECTURE), x86_64)
+CFLAGS+=-msse2 -DDXT_INTR
+
+else
+
+        # everything considered i386/linux
+CFLAGS+=-msse2 -DDXT_INTR
+
+endif
+
+
+
+#------------------  END FastDXT stuff  -------------------#
+
+
+
+default:	sagepdf
+
+install:	sagepdf
+		install -m 0755 sagepdf ${SAGE_DIR}/bin/
+
+sagepdf:	sagepdf.o dxt.o libdxt.o util.o intrinsic.o
+ifeq ($(MACHINE), Darwin)
+		g++ -m32 -o sagepdf sagepdf.o dxt.o libdxt.o intrinsic.o $(LIBS)
+else
+		g++ -o sagepdf sagepdf.o dxt.o libdxt.o intrinsic.o $(LIBS)
+endif
+
+
+nosage:		sagepdf.cpp
+		g++ -DNOSAGE $(NOSAGE_CFLAGS) -o sagepdf sagepdf.cpp $(NOSAGE_LIBS)
+
+
+%.o: %.cpp
+	g++ $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f sagepdf *.o
+
+
Index: trunk/src/testing/app-3rd-party/sagepdf/README
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/README	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/README	(revision 4)
@@ -0,0 +1,54 @@
+20110309 CKW
+
+sagepdf is a PDF viewer for a tiled display running SAGE.
+
+Prerequisites to compile include poppler, cairo and gtk+.
+To build the full version, run:
+	make
+
+To install the compiled sagepdf application
+(into $SAGE_DIRECTORY/bin), run:
+	make install
+
+
+To display a PDF on both local and tiled displays,
+run:
+	sagepdf /full/path/to/yourfile.pdf [-show_original] [-page num] [-scale num]
+
+The PDF filename is a mandatory argument; the remainder are optional.
+	-show_original
+means no DXT compression is used
+
+	-page num
+(num is some integer) denotes which page number
+should be displayed at startup
+
+	-scale num
+(num is some integer) denotes a scaling factor
+to be applied _before_ the conversion from pdf to bitmap
+is made for the tiled display (defaults to 4). The
+scaling factor has no effect on the locally displayed
+output.
+
+To run just on the desktop, build with the command:
+	make nosage
+
+No connection to a tiled display is (or can be) made
+when running this version. This may be useful for
+experimenting with just the gui code.
+
+
+Interaction with the local pdf window is, firstly,
+via the keyboard:
+	Home			= go to 1st page
+	End			= go to last page
+	Page Up, Left Arrow	= go back 1 page
+	Page Down, Right Arrow	= go forward 1 page
+
+The local pdf window also responds to the same mouse events
+as the tiled display instance:
+	Left Click	= go forward 1 page
+	Drag Right	= go forward pages while dragging
+	Right Click	= go back 1 page
+	Drag Left	= go back pages while dragging
+
Index: trunk/src/testing/app-3rd-party/sagepdf/util.cpp
===================================================================
--- trunk/src/testing/app-3rd-party/sagepdf/util.cpp	(revision 4)
+++ trunk/src/testing/app-3rd-party/sagepdf/util.cpp	(revision 4)
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+void aLog(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+}
+
+void aError(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+
+    exit(1);
+}
+
+
+
+void* aAlloc(size_t const n)
+{
+	void* result;
+#if defined(WIN32)
+	result = LocalAlloc(0,n);
+#else
+	result = malloc(n);
+#endif
+	// Filling with zeros
+	memset(result, 0, n);
+
+	if(!result)
+		aError("Aura: not enough memory for %d bytes",n);
+	return result;
+}
+
+void aFree(void* const p)
+{
+#if defined(WIN32)
+	LocalFree(p);
+#else
+	if (p)
+        free(p);
+    else
+        aError("Alloc> Trying to free a NULL pointer\n");
+#endif
+}
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
Index: trunk/src/testing/DevNote
===================================================================
--- trunk/src/testing/DevNote	(revision 4)
+++ trunk/src/testing/DevNote	(revision 4)
@@ -0,0 +1,29 @@
+1. Port Forwarding Support
+
+  When a SAGE application cannot directly access display nodes,
+  set TCP port forwarding from a gateway node to the display nodes and
+  configure the application to connect to the display nodes 
+  via the gateway node.
+ 
+  For example, create a ssh tunnel on the gateway node as follows 
+
+  ssh -g -f -L gatewayPort:displayIP:displayPort displayIP -N
+
+  The tile display config has a new line starting by "Forward"
+
+  DisplayNode
+        IP displayIP:displayPort
+        Forward gatewayIP:gatewayPort
+        Monitors 1 (0,0)
+
+  Application config file (atlantis.conf, render.conf, ....)  has 
+  a new parameter called "portForwarding"
+
+  If portForwarding = 1, the application tries to connect 
+  to gatewayIP:gatewayPort.
+  If portForwarding = 0, the application tries to connect 
+  to displayIP:displayPort (normal case).
+
+  * If omit 'displayPort' in the tile config file, 'receiverStreamPort' 
+    in 'fsManager.conf' is used as 'displayPort.'
+     
Index: trunk/src/testing/sageConfig/stdtile-2.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-2.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-2.conf	(revision 4)
@@ -0,0 +1,17 @@
+TileDisplay
+	Dimensions 2 1 
+	Mullions 0.0 0.0 0.0 0.0
+	Resolution 960 1200
+	PPI 90
+	Machines 2
+
+DisplayNode 
+	Name local
+	IP 127.0.0.1:22000
+	Monitors 1 (0,0) 
+
+DisplayNode 
+	Name local
+	IP 127.0.0.1:22002
+	Monitors 1 (1,0) 
+	Pos (960,0)
Index: trunk/src/testing/sageConfig/stdtile-20.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-20.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-20.conf	(revision 4)
@@ -0,0 +1,56 @@
+TileDisplay
+	Dimensions 4 5 
+	Mullions 0.625 0.625 0.625 0.625
+	Resolution 1600 1200
+	PPI 90
+	Machines 10
+
+DisplayNode 
+	Name node1-10
+	IP 10.0.8.121
+	Monitors 2 (2,0) (3,0)  
+
+DisplayNode 
+	Name node2-10
+	IP 10.0.8.122
+	Monitors 2 (2,1) (3,1)  
+
+DisplayNode 
+	Name node3-10
+	IP 10.0.8.123
+	Monitors 2 (2,2) (3,2) 
+
+DisplayNode 
+	Name node4-10
+	IP 10.0.8.124
+	Monitors 2 (2,3) (3,3)  
+
+DisplayNode 
+	Name node5-10
+	IP 10.0.8.125
+	Monitors 2 (2,4) (3,4) 
+
+DisplayNode 
+	Name node6-10
+	IP 10.0.8.126
+	Monitors 2 (0,0) (1,0)  
+
+DisplayNode 
+	Name node7-10
+	IP 10.0.8.127
+	Monitors 2 (0,1) (1,1)  
+
+DisplayNode 
+	Name node8-10
+	IP 10.0.8.128
+	Monitors 2 (0,2) (1,2) 
+
+DisplayNode 
+	Name node9-10
+	IP 10.0.8.129
+	Monitors 2 (0,3) (1,3)  
+
+DisplayNode 
+	Name node10-10
+	IP 10.0.8.130
+	Monitors 2 (0,4) (1,4) 
Index: trunk/src/testing/sageConfig/stdtile.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile.conf	(revision 4)
@@ -0,0 +1,11 @@
+TileDisplay
+	Dimensions 1 1 
+	Mullions 0.0 0.0 0.0 0.0
+	Resolution 800 600
+	PPI 90
+	Machines 1
+
+DisplayNode 
+	Name local
+	IP 127.0.0.1
+	Monitors 1 (0,0) 
Index: trunk/src/testing/sageConfig/stdtile-4.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-4.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-4.conf	(revision 4)
@@ -0,0 +1,30 @@
+TileDisplay
+	Dimensions 2 2 
+	Mullions 0.0 0.0 0.0 0.0
+	Resolution 960 600
+	PPI 90
+	Machines 4
+
+DisplayNode 
+	Name local
+	IP 127.0.0.1:22000
+	Monitors 1 (0,1) 
+	Pos (0,0)
+
+DisplayNode 
+	Name local-1
+	IP 127.0.0.1:22002
+	Monitors 1 (1,1) 
+	Pos (960,0)
+
+DisplayNode 
+	Name local-2
+	IP 127.0.0.1:22004
+	Monitors 1 (0,0)
+ 	Pos (0, 600)
+
+DisplayNode 
+	Name local-3
+	IP 127.0.0.1:22006
+	Monitors 1 (1,0) 
+	Pos (960,600)
Index: trunk/src/testing/sageConfig/sageBridge.conf
===================================================================
--- trunk/src/testing/sageConfig/sageBridge.conf	(revision 4)
+++ trunk/src/testing/sageConfig/sageBridge.conf	(revision 4)
@@ -0,0 +1,13 @@
+masterIP 127.0.0.1
+#slaveList 1 10.0.8.122
+#slaveList 3 10.0.8.122 10.0.8.123 10.0.8.124
+slaveList 0
+streamPort 41000
+msgPort 42000
+syncPort 43000
+screenRes 1000 1000
+
+rcvNwBufSize 16000000
+sendNwBufSize 65536
+MTU 1450
+
Index: trunk/src/testing/sageConfig/stdtile-55.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-55.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-55.conf	(revision 4)
@@ -0,0 +1,154 @@
+TileDisplay
+	Dimensions 11 5 
+	Mullions 0.625 0.625 0.625 0.625
+	Resolution 1600 1200
+	PPI 92
+	Machines 28
+
+
+DisplayNode 
+	Name node3-10
+	IP 10.0.8.113
+	Monitors 2 (0,3) (0,4) 
+	
+DisplayNode 
+	Name node2-10
+	IP 10.0.8.112
+	Monitors 2 (0,1) (0,2) 
+	
+DisplayNode 
+	Name node1-10
+	IP 10.0.8.111
+	Monitors 1 (0,0)
+
+
+
+DisplayNode 
+	Name machine1-10
+	IP 10.0.8.121
+	Monitors 2 (9,0) (10,0) 
+	
+DisplayNode 
+	Name machine2-10
+	IP 10.0.8.122
+	Monitors 2 (9,1) (10,1) 
+	
+DisplayNode 
+	Name machine3-10
+	IP 10.0.8.123
+	Monitors 2 (9,2) (10,2)
+
+DisplayNode 
+	Name machine4-10
+	IP 10.0.8.124
+	Monitors 2 (9,3) (10,3) 
+	
+DisplayNode 
+	Name machine5-10
+	IP 10.0.8.125
+	Monitors 2 (9,4) (10,4)
+
+
+DisplayNode 
+	Name machine6-10
+	IP 10.0.8.126
+	Monitors 2 (7,0) (8,0)
+
+DisplayNode 
+	Name machine7-10
+	IP 10.0.8.127
+	Monitors 2 (7,1) (8,1) 
+	
+DisplayNode 
+	Name machine8-10
+	IP 10.0.8.128
+	Monitors 2 (7,2) (8,2)
+
+DisplayNode 
+	Name machine9-10
+	IP 10.0.8.129
+	Monitors 2 (7,3) (8,3) 
+	
+DisplayNode 
+	Name machine10-10
+	IP 10.0.8.130
+	Monitors 2 (7,4) (8,4)
+
+
+DisplayNode 
+	Name machine11-10
+	IP 10.0.8.131
+	Monitors 2 (5,0) (6,0)
+
+DisplayNode 
+	Name machine12-10
+	IP 10.0.8.132
+	Monitors 2 (5,1) (6,1) 
+	
+DisplayNode 
+	Name machine13-10
+	IP 10.0.8.133
+	Monitors 2 (5,2) (6,2)
+
+DisplayNode 
+	Name machine14-10
+	IP 10.0.8.134
+	Monitors 2 (5,3) (6,3) 
+	
+DisplayNode 
+	Name machine15-10
+	IP 10.0.8.135
+	Monitors 2 (5,4) (6,4)
+
+
+DisplayNode 
+	Name machine16-10
+	IP 10.0.8.136
+	Monitors 2 (3,0) (4,0)
+
+DisplayNode 
+	Name machine17-10
+	IP 10.0.8.137
+	Monitors 2 (3,1) (4,1)
+
+DisplayNode 
+	Name machine18-10
+	IP 10.0.8.138
+	Monitors 2 (3,2) (4,2)
+
+DisplayNode 
+	Name machine19-10
+	IP 10.0.8.139
+	Monitors 2 (3,3) (4,3)
+
+DisplayNode 
+	Name machine20-10
+	IP 10.0.8.140
+	Monitors 2 (3,4) (4,4)
+
+
+DisplayNode 
+	Name node4-10
+	IP 10.0.8.114
+	Monitors 2 (1,0) (2,0)
+
+DisplayNode 
+	Name node5-10
+	IP 10.0.8.115
+	Monitors 2 (1,1) (2,1) 
+	
+DisplayNode 
+	Name node6-10
+	IP 10.0.8.116
+	Monitors 2 (1,2) (2,2)
+	
+DisplayNode 
+	Name node7-10
+	IP 10.0.8.117
+	Monitors 2 (1,3) (2,3)
+	
+DisplayNode 
+	Name node8-10
+	IP 10.0.8.118
+	Monitors 2 (1,4) (2,4) 
+	
Index: trunk/src/testing/sageConfig/applications/atlantis.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/atlantis.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/atlantis.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1000
+winHeight 1000
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/sageConfig/applications/render.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/render.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/render.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1000
+winHeight 1000
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/sageConfig/applications/atlantis-mpi.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/atlantis-mpi.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/atlantis-mpi.conf	(revision 4)
@@ -0,0 +1,11 @@
+masterIP 10.0.8.131
+nwID     1
+msgPort  23020
+syncPort 13020
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+winWidth 6000
+winHeight 6000
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/sageConfig/applications/checker.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/checker.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/checker.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 1
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1000
+winHeight 1000
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/sageConfig/applications/imageviewer.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/imageviewer.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/imageviewer.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 500
+winHeight 500
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/sageConfig/applications/applications.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/applications.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/applications.conf	(revision 4)
@@ -0,0 +1,122 @@
+#################################################
+# sage application configuration file
+#-----------------------------------------------
+# 
+# Sample app config format:
+# 
+# atlantis {                  # name of application (HAS TO BE THE SAME AS THE APP CONFIG FILE IT'S TRYING TO LOAD)
+# configName default          # name of this particular configuration
+# nodeNum 1                   # OPTIONAL - number of nodes (used only for parallel applications)
+# Init 100 100 2000 1500      # initial position and size of this app's window on SAGE
+# exec 10.0.8.160 atlantis params    # ip addres where to execute the application and all its parameters
+# nwProtocol TCP              # OPTIONAL - TCP or UDP protocol used for streaming (default TCP)
+# bridgeIP 10.0.8.160         # OPTIONAL - sageBridge information to use for visualcasting 
+# bridgePort 42000            #            (default is specified at the bottom of this file) 
+# staticApp                   # should be specified for static applications that do not refresh often
+# binDir some_dir             # OPTIONAL - specifies where the application binary resides (use full paths) - default is $SAGE_DIRECTORY/bin
+# sync NO_SYNC | SOFT_SYNC | HARD_SYNC   # OPTIONAL... specifies the syncronization mode for the application streams
+# audioFile some_file         # OPTIONAL - specify the audio file to play with the app (without this the audio wont play)
+# sampleFormat Int16          # OPTIONAL - the format of the file (default is "Int16")
+# samplingRate 44000          # OPTIONAL - the sampling rate of the file (default is 44000)
+# }
+#
+##################################################
+
+
+atlantis {
+
+configName default
+Init 100 100 1000 1000
+exec 127.0.0.1 atlantis
+masterIP 127.0.0.1
+
+}
+
+#------------------------------
+
+sagepdf {
+
+configName default
+Init 100 100 -1 -1
+exec 127.0.0.1 sagepdf
+staticApp
+masterIP 127.0.0.1
+sync SAGE_BLOCK_NO_SYNC
+
+}
+#------------------------------
+
+pdfviewer {
+
+configName default
+Init 100 100 -1 -1
+exec 127.0.0.1 pdfviewer
+staticApp
+masterIP 127.0.0.1
+sync SAGE_BLOCK_NO_SYNC
+
+}
+
+#------------------------------
+
+imageviewer {
+
+configName default
+Init 100 100 -1 -1
+exec 127.0.0.1 imageviewer
+masterIP 127.0.0.1
+sync SAGE_BLOCK_NO_SYNC
+staticApp
+}
+
+#------------------------------
+
+render {
+
+configName default
+Init 100 100 1000 1000
+exec 127.0.0.1 render
+staticApp
+masterIP 127.0.0.1
+
+}
+
+#------------------------------
+
+mplayer {
+
+configName default
+Init 100 100 -1 -1
+exec 127.0.0.1 mplayer
+nwProtocol TCP
+masterIP 127.0.0.1
+
+}
+
+#------------------------------
+
+VNCViewer {
+
+configName MyDesktop
+Init 100 100 1024 768
+exec 127.0.0.1 VNCViewer
+staticApp
+masterIP 127.0.0.1
+sync SAGE_BLOCK_NO_SYNC
+
+}
+
+
+#----------------------------------------------------
+# These are the default values that will be used in
+# case sageBridge information is not specified 
+# for each app separately.
+# However, the application will only use sageBridge
+# if it is run in sageBridge mode from the SAGE UI,
+# otherwise it will ignore sageBridge info
+#----------------------------------------------------
+
+
+defaultBridgeIP 10.0.8.160
+defaultBridgePort 42000
+
Index: trunk/src/testing/sageConfig/applications/VNCViewer.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/VNCViewer.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/VNCViewer.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1920
+winHeight 1200
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/sageConfig/applications/sagepdf.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/sagepdf.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/sagepdf.conf	(revision 4)
@@ -0,0 +1,20 @@
+bridgeIP 130.102.110.56
+bridgePort 42000
+bridgeOn true
+bridgeOn false
+fsIP 127.0.0.1
+fsPort 20002
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+nwProtocol TCP
+asyncUpdate true
+streamType SAGE_BLOCK_HARD_SYNC
+
Index: trunk/src/testing/sageConfig/applications/bitplayer.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/bitplayer.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/bitplayer.conf	(revision 4)
@@ -0,0 +1,19 @@
+bridgeOn false
+fsIP 67.58.62.100
+fsPort 20002
+masterIP 10.0.8.122
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 1
+launcherID 131.193.78.203:19010
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1920
+winHeight 1080
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/sageConfig/applications/pdfviewer.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/pdfviewer.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/pdfviewer.conf	(revision 4)
@@ -0,0 +1,18 @@
+bridgeOn false
+fsIP localhost
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 0
+winY 0
+winWidth -1
+winHeight -1
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/sageConfig/applications/svc.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/svc.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/svc.conf	(revision 4)
@@ -0,0 +1,18 @@
+bridgeOn false
+fsIP 67.58.62.100
+fsPort 20002
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 2
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1280
+winHeight 720
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/sageConfig/applications/svt.conf
===================================================================
--- trunk/src/testing/sageConfig/applications/svt.conf	(revision 4)
+++ trunk/src/testing/sageConfig/applications/svt.conf	(revision 4)
@@ -0,0 +1,25 @@
+fsIP 67.58.62.100
+fsPort 20002
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    10
+pixelBlockSize 128 72
+winX 0
+winY 0
+winWidth 1920
+winHeight 1080
+nwProtocol TCP
+asyncUpdate false
+streamType SAGE_BLOCK_HARD_SYNC
+
+audioOn true
+audioKeyFrame 100
+audioType capture
+audioPort 26000
+sampleFormat Int16
+samplingRate 44100
+audionwProtocol TCP
+channels 2
Index: trunk/src/testing/sageConfig/fileServer/fileServer.conf
===================================================================
--- trunk/src/testing/sageConfig/fileServer/fileServer.conf	(revision 4)
+++ trunk/src/testing/sageConfig/fileServer/fileServer.conf	(revision 4)
@@ -0,0 +1,35 @@
+### FILE SERVER CONFIG FILE
+### Author: Ratko Jagodic
+### January, 2006
+
+
+### first we specify the top most folder where all the files are stored
+### (relative to your where the file_server.py is executed from... otherwise specify an absolute path)
+FILES_DIR = fileLibrary
+
+
+
+### now we specify which types of files we support
+### you specify them as:
+### "type:"type = list_of_file_extensions
+### the "type" will become an official type of those files so use the same one throughout
+type:image = .jpg .jpeg .gif .png .tif .tiff .bmp .pcx .rgb .rgba .ico
+type:video = .avi .mpg .mpeg .mov .mp4
+#type:text = .txt
+type:pdf = .pdf
+
+
+
+### finally, we specify the applications used to run each one of those types
+### basically, these lines will be read by the file server and sent to the SAGE UI which
+### will in turn send them to SAGE to execute them
+### specify all the parameters you need to get your stuff running
+### since this file is read every time a file is executed, there is no need to restart
+### the server when you modify this file
+### the format is (make sure that the type matches the one specified above):
+### "app:"type = app_binary_name param1 param2 param3 ...
+app:image = imageviewer
+app:video = mplayer -nosound -loop 0 -quiet -vo sage
+app:pdf = pdfviewer
+#app:pdf = sagepdf
+#app:text = imageviewer
Index: trunk/src/testing/sageConfig/stdtile-55-cwave.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-55-cwave.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-55-cwave.conf	(revision 4)
@@ -0,0 +1,154 @@
+TileDisplay
+	Dimensions 11 5 
+	Mullions 0.625 0.625 0.625 0.625
+	Resolution 1600 1200
+	PPI 92
+	Machines 28
+
+DisplayNode 
+	Name nico1-10
+	IP 67.58.62.91
+	Monitors 1 (0,0)
+
+DisplayNode 
+	Name nico3-10
+	IP 67.58.62.93
+	Monitors 2 (0,3) (0,4) 
+	
+DisplayNode 
+	Name nico2-10
+	IP 67.58.62.92
+	Monitors 2 (0,1) (0,2) 
+	
+
+
+
+DisplayNode 
+	Name yorda1-10
+	IP 67.58.62.101
+	Monitors 2 (9,0) (10,0) 
+	
+DisplayNode 
+	Name yorda2-10
+	IP 67.58.62.102
+	Monitors 2 (9,1) (10,1) 
+	
+DisplayNode 
+	Name yorda3-10
+	IP 67.58.62.103
+	Monitors 2 (9,2) (10,2)
+
+DisplayNode 
+	Name yorda4-10
+	IP 67.58.62.104
+	Monitors 2 (9,3) (10,3) 
+	
+DisplayNode 
+	Name yorda5-10
+	IP 67.58.62.105
+	Monitors 2 (9,4) (10,4)
+
+
+DisplayNode 
+	Name yorda6-10
+	IP 67.58.62.106
+	Monitors 2 (7,0) (8,0)
+
+DisplayNode 
+	Name yorda7-10
+	IP 67.58.62.107
+	Monitors 2 (7,1) (8,1) 
+	
+DisplayNode 
+	Name yorda8-10
+	IP 67.58.62.108
+	Monitors 2 (7,2) (8,2)
+
+DisplayNode 
+	Name yorda9-10
+	IP 67.58.62.109
+	Monitors 2 (7,3) (8,3) 
+	
+DisplayNode 
+	Name yorda10-10
+	IP 67.58.62.110
+	Monitors 2 (7,4) (8,4)
+
+
+DisplayNode 
+	Name yorda11-10
+	IP 67.58.62.111
+	Monitors 2 (5,0) (6,0)
+
+DisplayNode 
+	Name yorda12-10
+	IP 67.58.62.112
+	Monitors 2 (5,1) (6,1) 
+	
+DisplayNode 
+	Name yorda13-10
+	IP 67.58.62.113
+	Monitors 2 (5,2) (6,2)
+
+DisplayNode 
+	Name yorda14-10
+	IP 67.58.62.114
+	Monitors 2 (5,3) (6,3) 
+	
+DisplayNode 
+	Name yorda15-10
+	IP 67.58.62.115
+	Monitors 2 (5,4) (6,4)
+
+
+DisplayNode 
+	Name yorda16-10
+	IP 67.58.62.116
+	Monitors 2 (3,0) (4,0)
+
+DisplayNode 
+	Name yorda17-10
+	IP 67.58.62.117
+	Monitors 2 (3,1) (4,1)
+
+DisplayNode 
+	Name yorda18-10
+	IP 67.58.62.118
+	Monitors 2 (3,2) (4,2)
+
+DisplayNode 
+	Name yorda19-10
+	IP 67.58.62.119
+	Monitors 2 (3,3) (4,3)
+
+DisplayNode 
+	Name yorda20-10
+	IP 67.58.62.120
+	Monitors 2 (3,4) (4,4)
+
+
+DisplayNode 
+	Name nico4-10
+	IP 67.58.62.94
+	Monitors 2 (1,0) (2,0)
+
+DisplayNode 
+	Name nico5-10
+	IP 67.58.62.95
+	Monitors 2 (1,1) (2,1) 
+	
+DisplayNode 
+	Name nico6-10
+	IP 67.58.62.96
+	Monitors 2 (1,2) (2,2)
+	
+DisplayNode 
+	Name nico7-10
+	IP 67.58.62.97
+	Monitors 2 (1,3) (2,3)
+	
+DisplayNode 
+	Name nico8-10
+	IP 67.58.62.98
+	Monitors 2 (1,4) (2,4) 
+	
Index: trunk/src/testing/sageConfig/fsManager.conf
===================================================================
--- trunk/src/testing/sageConfig/fsManager.conf	(revision 4)
+++ trunk/src/testing/sageConfig/fsManager.conf	(revision 4)
@@ -0,0 +1,44 @@
+fsManager       local 127.0.0.1 
+systemPort      20002
+uiPort          20001
+trackPort       20003
+#conManager      74.114.99.36 15557    
+
+tileConfiguration stdtile-1.conf
+
+receiverSyncPort  12000
+receiverStreamPort   22000
+receiverBufSize    50
+fullScreen     0
+winTime		0
+winStep     1
+
+audio false 
+audioConfiguration audio-stdtile-1.conf
+receiverAudioSyncPort 28000
+receiverAudioPort 26000
+syncPort 24000
+
+rcvNwBufSize 4M
+sendNwBufSize 65K
+MTU 1450
+
+# Synchronization mode
+# 0  //no sync
+# 	no syncCheckThread is created. no syncServer and Client are created
+# 	All application will be running in NO_SYNC mode regardless of their config
+# 1  //data sync only (default)
+# 2  //1 + swap buffer sync
+syncLevel 1
+
+# 2nd phase of the new sync
+syncBarrierPort 24381
+
+# syncMaster mainLoop while() timeout value in Hz
+# should be faster than the frame rate of the fastest video
+# higher value will affect sage performance
+refreshInterval 120
+
+# syncMaster mainLoop select() return timer in usec. 0 for constant polling
+syncMasterPollingInterval 100
+
Index: trunk/src/testing/sageConfig/audio-stdtile-1.conf
===================================================================
--- trunk/src/testing/sageConfig/audio-stdtile-1.conf	(revision 4)
+++ trunk/src/testing/sageConfig/audio-stdtile-1.conf	(revision 4)
@@ -0,0 +1,12 @@
+AudioTileDisplay
+	DeviceID -1 
+	SampleFormat Float32
+	SamplingRate 44100
+	Channels 2
+	FramePerBuffer 1024
+	Machines 1
+
+AudioNode 
+	Name win32
+	IP 67.58.62.27
+	
Index: trunk/src/testing/sageConfig/stdtile-1.conf
===================================================================
--- trunk/src/testing/sageConfig/stdtile-1.conf	(revision 4)
+++ trunk/src/testing/sageConfig/stdtile-1.conf	(revision 4)
@@ -0,0 +1,12 @@
+TileDisplay
+	Dimensions 1 1 
+	Mullions 0.0 0.0 0.0 0.0
+	Resolution 800 600
+	PPI 90
+	Machines 1
+
+DisplayNode 
+	Name local
+	IP 127.0.0.1
+	Monitors 1 (0,0)
+
Index: trunk/src/testing/shader/RLECompare.frag
===================================================================
--- trunk/src/testing/shader/RLECompare.frag	(revision 4)
+++ trunk/src/testing/shader/RLECompare.frag	(revision 4)
@@ -0,0 +1,37 @@
+// Generating RLE Sequence for RLE compression
+// 
+// author : Byungil Jeong
+//
+
+uniform sampler2D colorMap;
+uniform vec2		winSize;
+uniform vec2		blockSize;
+uniform float		blockPixels;
+uniform vec2		blockDim;
+
+void main(void)
+{
+   const vec2 offset = vec2(1.0 / winSize.x, 1.0/winSize.y);
+	const vec4 zeroColor = vec4(0.0);
+	
+   vec2 texCoord = gl_TexCoord[0].xy;
+	vec2 pixelCoord = floor(texCoord*winSize);
+	float pixelIdx = pixelCoord.y * winSize.x + pixelCoord.x;
+	float blockIdx = floor(pixelIdx/blockPixels);
+	vec2 blockPos = vec2(mod(blockIdx,blockDim.x), floor(blockIdx/blockDim.x));
+	float innerIdx = mod(pixelIdx,blockPixels);
+	vec2 innerPos = vec2(mod(innerIdx,blockSize.x), floor(innerIdx/blockSize.x));
+	
+	vec2 finalPos = blockPos*blockSize + innerPos; 
+	vec2 myCoord = texCoord + (finalPos - pixelCoord)*offset;
+	vec4 myColor = texture2D(colorMap, myCoord);
+
+	vec4 uniquePixel = vec4(1.0, 0.0, 0.0, 0.0);
+	vec2 neighborCoord = vec2(myCoord.x - offset.x, myCoord.y);
+	vec4 neighborColor = texture2D(colorMap, neighborCoord);
+	if (myColor.rgb == neighborColor.rgb && innerPos.x > 0.0)
+		uniquePixel.r = 0.0;
+
+	gl_FragData[0] = myColor;
+	gl_FragData[1] = uniquePixel;
+}
Index: trunk/src/testing/shader/blockGeneration.frag
===================================================================
--- trunk/src/testing/shader/blockGeneration.frag	(revision 4)
+++ trunk/src/testing/shader/blockGeneration.frag	(revision 4)
@@ -0,0 +1,30 @@
+// Generating RLE Sequence for RLE compression
+// 
+// author : Byungil Jeong
+//
+
+uniform sampler2D colorMap;
+uniform vec2		winSize;
+uniform vec2		blockSize;
+uniform float		blockPixels;
+uniform vec2		blockDim;
+
+void main(void)
+{
+   const vec2 offset = vec2(1.0 / winSize.x, 1.0/winSize.y);
+	const vec4 zeroColor = vec4(0.0);
+	
+   vec2 texCoord = gl_TexCoord[0].xy;
+	vec2 pixelCoord = floor(texCoord*winSize);
+	float pixelIdx = pixelCoord.y * winSize.x + pixelCoord.x;
+	float blockIdx = floor(pixelIdx/blockPixels);
+	vec2 blockPos = vec2(mod(blockIdx,blockDim.x), floor(blockIdx/blockDim.x));
+	float innerIdx = mod(pixelIdx,blockPixels);
+	vec2 innerPos = vec2(mod(innerIdx,blockSize.x), floor(innerIdx/blockSize.x));
+	
+	vec2 finalPos = blockPos*blockSize + innerPos; 
+	vec2 myCoord = texCoord + (finalPos - pixelCoord)*offset;
+	vec4 myColor = texture2D(colorMap, myCoord);
+
+	gl_FragColor = myColor;
+}
Index: trunk/src/testing/bin/performance_server.py
===================================================================
--- trunk/src/testing/bin/performance_server.py	(revision 4)
+++ trunk/src/testing/bin/performance_server.py	(revision 4)
@@ -0,0 +1,473 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# SAGE LAUNCHER - A GUI for launching SAGE and all related components
+#
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+#
+############################################################################
+
+import Numeric, random
+import socket, sys, os
+from wx.lib.plot import *
+
+ARRAY_SIZE=100
+
+class LineFrame(wx.Dialog):
+    def _createObjects(self):
+        print "create ", self.numgraphs, "graphs"
+        self.current = {}
+        self.datasets = {}
+        for i in range(self.numgraphs):
+            self.current[i] = 0
+            self.datasets[i] = Numeric.arange(ARRAY_SIZE*2)/float(ARRAY_SIZE*2)
+            self.datasets[i].shape = (ARRAY_SIZE, 2)
+            self.datasets[i][:,1] = 0
+        
+    def _addPoint(self,values):
+        x = float(values[0])
+        for j in range(self.numgraphs):
+            ar = [x, float(values[j+1])]
+            if self.current[j] < ARRAY_SIZE:
+                for i in range(self.current[j],ARRAY_SIZE):
+                    self.datasets[j][i] = ar
+                self.current[j] = self.current[j] + 1
+            else:
+                for i in range(1,ARRAY_SIZE):
+                    self.datasets[j][i-1] = self.datasets[j][i]
+                self.datasets[j][ARRAY_SIZE-1] = ar
+        self.client.Draw(self._drawObjects())
+        
+    def _drawObjects(self):
+        # ARRAY_SIZE points, plotted as red line
+        lines = []
+        for i in range(self.numgraphs):
+            lines.append( PolyLine(self.datasets[i], legend=self.ytitle[i], width=3,
+                                   colour=self.colors[i%6]) )
+        return PlotGraphics(lines, self.title, self.xtitle, "")
+
+    def __init__(self, parent, id, title):
+        wx.Dialog.__init__(self, parent, id, title,
+                          wx.DefaultPosition, (600, 400),style=wx.DEFAULT_FRAME_STYLE)
+        self.frame = parent
+
+        # Network connection
+        self.conn = None
+        
+        # self.timer = wx.Timer(self)
+        # self.timer.Start(10)
+        # self.Bind(wx.EVT_TIMER, self.OnTimer)
+        self.Bind(wx.EVT_IDLE, self.OnTimer)
+        
+        self.client = PlotCanvas(self)
+        # Create mouse event for showing cursor coords in status bar
+        self.client.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
+        self.Show(True)
+
+        self.colors = ['red', 'blue', 'black', 'green', 'yellow', 'cyan', 'magenta' ]
+        
+        # settings
+        self.title  = title
+        self.xtitle = "X Title"
+        self.ytitle = {}
+        self.ytitle[0] = "Y Title"
+        self.numgraphs = 1
+        self.client.SetEnableLegend(0)
+        self.client.SetEnableGrid(1)
+
+        # draw
+        self.resetDefaults()
+
+    def SetClient(self, conn):
+        self.conn = conn
+
+    def SetNumGraphs(self, n):
+        self.numgraphs = n
+        self._createObjects()
+    def SetTitle(self, t):
+        self.title = t
+    def SetXtitle(self, t):
+        self.xtitle = t
+    def SetYtitle(self, ind, t):
+        self.ytitle[ind] = t
+        self.numgraphs = ind+1
+
+    def OnTimer(self, event):
+        if self.conn:
+            data = 1
+            it = 0
+            while data and (it<5):
+                try:
+                    msglen = 12*(self.numgraphs+1) + self.numgraphs
+                    data = self.conn.recv(msglen)
+                    if data:
+                        values = data.split()
+                        self._addPoint(values)
+                        it = it + 1
+                    else:
+                        return
+                except:
+                    return
+        self.client.Draw(self._drawObjects())
+        #event.RequestMore(True)
+        
+    def OnMouseLeftDown(self,event):
+        s= "Left Mouse Down at Point: (%.4f, %.4f)" % self.client.GetXY(event)
+        self.frame.SetStatusText(s)
+        event.Skip()
+
+    def OnFilePageSetup(self, event):
+        self.client.PageSetup()
+        
+    def OnFilePrintPreview(self, event):
+        self.client.PrintPreview()
+        
+    def OnFilePrint(self, event):
+        self.client.Printout()
+        
+    def OnSaveFile(self, event):
+        self.client.SaveFile()
+
+    def OnFileExit(self, event):
+        self.Close()
+
+    def OnPlotRedraw(self,event):
+        self.client.Redraw()
+
+    def OnPlotClear(self,event):
+        self.client.Clear()
+        
+    def OnPlotScale(self, event):
+        if self.client.last_draw != None:
+            graphics, xAxis, yAxis= self.client.last_draw
+            self.client.Draw(graphics,(1,3.05),(0,1))
+
+    def OnEnableZoom(self, event):
+        self.client.SetEnableZoom(event.IsChecked())
+        
+    def OnEnableGrid(self, event):
+        self.client.SetEnableGrid(event.IsChecked())
+        
+    def OnEnableLegend(self, event):
+        self.client.SetEnableLegend(event.IsChecked())
+
+    def OnScrUp(self, event):
+        self.client.ScrollUp(1)
+        
+    def OnScrRt(self,event):
+        self.client.ScrollRight(2)
+
+    def OnReset(self,event):
+        self.client.Reset()
+
+    def OnHelpAbout(self, event):
+        from wx.lib.dialogs import ScrolledMessageDialog
+        about = ScrolledMessageDialog(self, __doc__, "About...")
+        about.ShowModal()
+
+    def resetDefaults(self):
+        """Just to reset the fonts back to the PlotCanvas defaults"""
+        self.client.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.NORMAL))
+        self.client.SetFontSizeAxis(12)
+        self.client.SetFontSizeLegend(12)
+        self.client.SetXSpec('auto')
+        self.client.SetYSpec('auto')
+        
+
+class MatrixCanvas(wx.Window):
+    def __init__(self, parent, id = -1, pos=wx.DefaultPosition,
+            size=wx.DefaultSize, style= wx.DEFAULT_FRAME_STYLE, name= ""):
+        wx.Window.__init__(self, parent, id, pos, size, style, name)
+        self.border = (1,1)
+
+        self.SetBackgroundColour("black")
+        
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+        self.parent= parent
+
+        self.last_draw = None
+
+        # now on Mac, this seems to be a problem
+        #self.OnSize(None) # sets the initial size based on client size
+
+        
+    def Draw(self, graphics):
+        # allows using floats for certain functions 
+        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
+            
+        dc.BeginDrawing()
+        dc.Clear()
+
+        Size  = self.GetClientSize()
+        width, height, colors =  graphics
+        stepw = (Size[0] - 60) / width
+        steph = (Size[1] - 60) / height
+        dc.SetPen(wx.Pen(wx.BLUE,1))
+        k = 0
+        for i in range(width):
+            for j in range(height):
+                dc.SetBrush(wx.Brush(colors[k]))
+		#if os.uname()[0] == 'Darwin':
+		#    dc.DrawRectangle( (30+i*stepw,30+j*steph), (stepw,steph))
+		#else:
+                dc.DrawRectangle( 30+i*stepw,30+j*steph, stepw,steph)
+                k = k + 1
+        self.last_draw = graphics
+
+        dc.EndDrawing()
+        
+    def Redraw(self, dc= None):
+        """Redraw the existing plot."""
+        if self.last_draw:
+            self.Draw(last_draw)
+
+    def Clear(self):
+        """Erase the window."""
+        dc = wx.BufferedDC(wx.ClientDC(self), self._Buffer)
+        dc.Clear()
+        self.last_draw = None
+
+    def OnPaint(self, event):
+        # All that is needed here is to draw the buffer to screen
+        dc = wx.BufferedPaintDC(self, self._Buffer)        
+        
+    def OnSize(self,event):
+        # The Buffer init is done here, to make sure the buffer is always
+        # the same size as the Window
+        Size = self.GetClientSize()
+        self._Buffer = wx.EmptyBitmap(Size[0],Size[1])
+        if self.last_draw is None:
+            self.Clear()
+        else:
+            self.Draw(self.last_draw)
+
+        
+class MatrixFrame(wx.Dialog):
+    def _createObjects(self):
+        print "create matrix"
+        self.data = Numeric.arange(self.w*self.h)/3.0
+        self.data.shape = (self.w,self.h)
+        self.data[:] = 0.0
+
+    def _drawObjects(self):        
+        ar = []
+        for i in range(self.w):
+            for j in range(self.h):
+                val = self.data[i][j]
+                col = wx.Color( int(val*255.),
+                                int(val*255.),
+                                int(val*255.))
+                ar.append( col )
+        return (self.w, self.h, ar)
+
+    def _addPoint(self,values):
+        x   = int(values[0])
+        y   = int(values[1])
+        val = float(values[2])
+        self.data[x][y] = val
+        self.client.Draw(self._drawObjects())
+        
+    def __init__(self, parent, id, title, xs, ys):
+        wx.Dialog.__init__(self, parent, id, title,
+                          wx.DefaultPosition, (500, 400),style=wx.DEFAULT_FRAME_STYLE)
+        self.frame = parent
+
+        # Network connection
+        self.conn = None
+
+        # Drawing object
+        self.client = MatrixCanvas(self)        
+        
+        self.Bind(wx.EVT_IDLE, self.OnTimer)
+        self.Show(True)
+
+        self.w = xs
+        self.h = ys
+        print "Matrix size", xs, ys
+
+        self._createObjects()
+        
+        # settings
+        self.title  = title
+        self.xtitle = "X Title"
+        self.ytitle = "Y Title"
+
+    def SetClient(self, conn):
+        self.conn = conn
+    def SetTitle(self, t):
+        self.title = t
+    def SetXtitle(self, t):
+        self.xtitle = t
+    def SetYtitle(self, t):
+        self.ytitle = t
+
+    def OnTimer(self, event):
+        if self.conn:
+            data = 1
+            it = 0
+            while data and (it<5):
+                try:
+                    msglen = 6 + 1 + 6 + 1 + 12  # x y value
+                    data = self.conn.recv(msglen)
+                    if data:
+                        values = data.split()
+                        self._addPoint(values)
+                        it = it + 1
+                    else:
+                        return
+                except:
+                    return
+        self.client.Draw(self._drawObjects())
+        #event.RequestMore(True)
+
+class MyApp(wx.App):
+
+    def OnIdle(self, event):
+        try:
+            conn, addr = self.s.accept()
+            conn.setblocking(1)
+            print 'Connected by', addr
+            type = conn.recv(64)
+            type = type.strip()
+            print "\t type[", type, "]"
+            if type == "lines":
+                title = conn.recv(64)
+                title = title.strip()
+                print "\t title[", title, "]"
+                xtitle = conn.recv(64)
+                xtitle = xtitle.strip()
+                print "\t xtitle[", xtitle, "]"
+                numgraphs = int( conn.recv(6) )
+                print "\t numgraphs", numgraphs
+                ytitle = {}
+                for i in range(numgraphs):
+                    ytitle[i] = conn.recv(64)
+                    ytitle[i] = ytitle[i].strip()
+                    print "\t\t graph", i, " name[", ytitle[i], "]"
+                frame = LineFrame(self.myframe, -1, title)
+                frame.SetNumGraphs(numgraphs)
+                frame.SetXtitle(xtitle)
+                for i in range(numgraphs):
+                    frame.SetYtitle(i, ytitle[i])
+                frame.SetClient(conn)
+                conn.send("1")
+                conn.setblocking(0)
+            if type == "matrix":
+                title = conn.recv(64)
+                title = title.strip()
+                print "\t title[", title, "]"
+                xtitle = conn.recv(64)
+                xtitle = xtitle.strip()
+                print "\t xtitle[", xtitle, "]"
+                sizes = conn.recv(13)
+                sizes = sizes.strip()
+                xs,ys = sizes.split()
+                xs = int(xs)
+                ys = int(ys)
+                numgraphs = 2
+                print "\t numgraphs", numgraphs
+                ytitle = {}
+                for i in range(numgraphs):
+                    ytitle[i] = conn.recv(64)
+                    ytitle[i] = ytitle[i].strip()
+                    print "\t\t graph", i, " name[", ytitle[i], "]"
+                frame = MatrixFrame(self.myframe, -1, title, xs, ys)
+                #frame.SetXtitle(xtitle)
+                #for i in range(numgraphs):
+                #    frame.SetYtitle(i, ytitle[i])
+                frame.SetClient(conn)
+                conn.send("1")
+                conn.setblocking(0)
+        except:
+            pass
+        event.RequestMore(True)
+
+    def OnInit(self):
+        wx.InitAllImageHandlers()
+        self.myframe= wx.Frame(None, -1, "MainFrame")
+
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+        
+        # Now Create the menu bar and items
+        self.myframe.mainmenu = wx.MenuBar()
+
+        menu = wx.Menu()
+        menu.Append(200, 'Page Setup...', 'Setup the printer page')        
+        menu.Append(201, 'Print Preview...', 'Show the current plot on page')
+        menu.Append(202, 'Print...', 'Print the current plot')
+        menu.Append(203, 'Save Plot...', 'Save current plot')
+        menu.Append(205, 'E&xit', 'Enough of this already!')
+        self.myframe.mainmenu.Append(menu, '&File')
+
+        menu = wx.Menu()
+
+        menu.Append(211, '&Redraw', 'Redraw plots')
+        menu.Append(212, '&Clear', 'Clear canvas')
+        menu.Append(213, '&Scale', 'Scale canvas')
+        menu.Append(214, 'Enable &Zoom', 'Enable Mouse Zoom', kind=wx.ITEM_CHECK)
+        menu.Append(215, 'Enable &Grid', 'Turn on Grid', kind=wx.ITEM_CHECK)
+        menu.Append(220, 'Enable &Legend', 'Turn on Legend', kind=wx.ITEM_CHECK)
+        menu.Append(225, 'Scroll Up 1', 'Move View Up 1 Unit')
+        menu.Append(230, 'Scroll Rt 2', 'Move View Right 2 Units')
+        menu.Append(235, '&Plot Reset', 'Reset to original plot')
+
+        self.myframe.mainmenu.Append(menu, '&Plot')
+
+        menu = wx.Menu()
+        menu.Append(300, '&About', 'About this thing...')
+        self.myframe.mainmenu.Append(menu, '&Help')
+
+        self.myframe.SetMenuBar(self.myframe.mainmenu)
+
+        # A status bar to tell people what's happening
+        self.myframe.CreateStatusBar(1)
+        self.myframe.Show(True)
+
+        HOST = ''                 # Symbolic name meaning the local host
+        PORT = 50008              # Arbitrary non-privileged port
+        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.s.bind((HOST, PORT))
+        self.s.listen(5)
+        self.s.setblocking(0)
+                    
+        self.SetTopWindow(self.myframe)
+        
+        return True
+
+            
+app = MyApp(0)
+app.MainLoop()
+
Index: trunk/src/testing/bin/sage
===================================================================
--- trunk/src/testing/bin/sage	(revision 4)
+++ trunk/src/testing/bin/sage	(revision 4)
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+cd $SAGE_DIRECTORY/bin
+
+# Use the 2.4 version of python if running in Rocks environment
+PYTHONEXE=python
+[ -x /opt/rocks/bin/python ] && PYTHONEXE=/opt/rocks/bin/python
+
+# run sageLauncher differently if linux or if macos
+if [ `uname` = "Linux" ]
+then
+    $PYTHONEXE sageLauncher.py
+else
+    pythonw sageLauncher.py
+fi
+
Index: trunk/src/testing/bin/subprocess.py
===================================================================
--- trunk/src/testing/bin/subprocess.py	(revision 4)
+++ trunk/src/testing/bin/subprocess.py	(revision 4)
@@ -0,0 +1,1158 @@
+# subprocess - Subprocesses with accessible I/O streams
+#
+# For more information about this module, see PEP 324.
+#
+# Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of the
+# author not be used in advertising or publicity pertaining to
+# distribution of the software without specific, written prior
+# permission.
+#
+# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""subprocess - Subprocesses with accessible I/O streams
+
+This module allows you to spawn processes and connect to their
+input/output/error pipes and obtain their return codes under Unix.
+This module intends to replace several other, older modules and
+functions, like:
+
+os.system
+os.spawn*
+os.popen*
+popen2.*
+commands.*
+
+Information about how the subprocess module can be used to replace these
+modules and functions can be found below.
+
+
+
+Using the subprocess module
+===========================
+This module defines one class called Popen:
+
+class Popen(args, bufsize=0, executable=None,
+            stdin=None, stdout=None, stderr=None,
+            preexec_fn=None, close_fds=False, shell=False,
+            cwd=None, env=None, universal_newlines=False,
+            startupinfo=None, creationflags=0):
+
+
+Arguments are:
+
+args should be a string, or a sequence of program arguments.  The
+program to execute is normally the first item in the args sequence or
+string, but can be explicitly set by using the executable argument.
+
+On UNIX, with shell=False (default): In this case, the Popen class
+uses os.execvp() to execute the child program.  args should normally
+be a sequence.  A string will be treated as a sequence with the string
+as the only item (the program to execute).
+
+On UNIX, with shell=True: If args is a string, it specifies the
+command string to execute through the shell.  If args is a sequence,
+the first item specifies the command string, and any additional items
+will be treated as additional shell arguments.
+
+On Windows: the Popen class uses CreateProcess() to execute the child
+program, which operates on strings.  If args is a sequence, it will be
+converted to a string using the list2cmdline method.  Please note that
+not all MS Windows applications interpret the command line the same
+way: The list2cmdline is designed for applications using the same
+rules as the MS C runtime.
+
+bufsize, if given, has the same meaning as the corresponding argument
+to the built-in open() function: 0 means unbuffered, 1 means line
+buffered, any other positive value means use a buffer of
+(approximately) that size.  A negative bufsize means to use the system
+default, which usually means fully buffered.  The default value for
+bufsize is 0 (unbuffered).
+
+stdin, stdout and stderr specify the executed programs' standard
+input, standard output and standard error file handles, respectively.
+Valid values are PIPE, an existing file descriptor (a positive
+integer), an existing file object, and None.  PIPE indicates that a
+new pipe to the child should be created.  With None, no redirection
+will occur; the child's file handles will be inherited from the
+parent.  Additionally, stderr can be STDOUT, which indicates that the
+stderr data from the applications should be captured into the same
+file handle as for stdout.
+
+If preexec_fn is set to a callable object, this object will be called
+in the child process just before the child is executed.
+
+If close_fds is true, all file descriptors except 0, 1 and 2 will be
+closed before the child process is executed.
+
+if shell is true, the specified command will be executed through the
+shell.
+
+If cwd is not None, the current directory will be changed to cwd
+before the child is executed.
+
+If env is not None, it defines the environment variables for the new
+process.
+
+If universal_newlines is true, the file objects stdout and stderr are
+opened as a text files, but lines may be terminated by any of '\n',
+the Unix end-of-line convention, '\r', the Macintosh convention or
+'\r\n', the Windows convention.  All of these external representations
+are seen as '\n' by the Python program.  Note: This feature is only
+available if Python is built with universal newline support (the
+default).  Also, the newlines attribute of the file objects stdout,
+stdin and stderr are not updated by the communicate() method.
+
+The startupinfo and creationflags, if given, will be passed to the
+underlying CreateProcess() function.  They can specify things such as
+appearance of the main window and priority for the new process.
+(Windows only)
+
+
+This module also defines two shortcut functions:
+
+call(*args, **kwargs):
+    Run command with arguments.  Wait for command to complete, then
+    return the returncode attribute.
+
+    The arguments are the same as for the Popen constructor.  Example:
+
+    retcode = call(["ls", "-l"])
+
+
+Exceptions
+----------
+Exceptions raised in the child process, before the new program has
+started to execute, will be re-raised in the parent.  Additionally,
+the exception object will have one extra attribute called
+'child_traceback', which is a string containing traceback information
+from the childs point of view.
+
+The most common exception raised is OSError.  This occurs, for
+example, when trying to execute a non-existent file.  Applications
+should prepare for OSErrors.
+
+A ValueError will be raised if Popen is called with invalid arguments.
+
+
+Security
+--------
+Unlike some other popen functions, this implementation will never call
+/bin/sh implicitly.  This means that all characters, including shell
+metacharacters, can safely be passed to child processes.
+
+
+Popen objects
+=============
+Instances of the Popen class have the following methods:
+
+poll()
+    Check if child process has terminated.  Returns returncode
+    attribute.
+
+wait()
+    Wait for child process to terminate.  Returns returncode attribute.
+
+communicate(input=None)
+    Interact with process: Send data to stdin.  Read data from stdout
+    and stderr, until end-of-file is reached.  Wait for process to
+    terminate.  The optional stdin argument should be a string to be
+    sent to the child process, or None, if no data should be sent to
+    the child.
+
+    communicate() returns a tuple (stdout, stderr).
+
+    Note: The data read is buffered in memory, so do not use this
+    method if the data size is large or unlimited.
+
+The following attributes are also available:
+
+stdin
+    If the stdin argument is PIPE, this attribute is a file object
+    that provides input to the child process.  Otherwise, it is None.
+
+stdout
+    If the stdout argument is PIPE, this attribute is a file object
+    that provides output from the child process.  Otherwise, it is
+    None.
+
+stderr
+    If the stderr argument is PIPE, this attribute is file object that
+    provides error output from the child process.  Otherwise, it is
+    None.
+
+pid
+    The process ID of the child process.
+
+returncode
+    The child return code.  A None value indicates that the process
+    hasn't terminated yet.  A negative value -N indicates that the
+    child was terminated by signal N (UNIX only).
+
+
+Replacing older functions with the subprocess module
+====================================================
+In this section, "a ==> b" means that b can be used as a replacement
+for a.
+
+Note: All functions in this section fail (more or less) silently if
+the executed program cannot be found; this module raises an OSError
+exception.
+
+In the following examples, we assume that the subprocess module is
+imported with "from subprocess import *".
+
+
+Replacing /bin/sh shell backquote
+---------------------------------
+output=`mycmd myarg`
+==>
+output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
+
+
+Replacing shell pipe line
+-------------------------
+output=`dmesg | grep hda`
+==>
+p1 = Popen(["dmesg"], stdout=PIPE)
+p2 = Popen(["grep", "hda"], stdin=p1.stdout)
+output = p2.communicate()[0]
+
+
+Replacing os.system()
+---------------------
+sts = os.system("mycmd" + " myarg")
+==>
+p = Popen("mycmd" + " myarg", shell=True)
+sts = os.waitpid(p.pid, 0)
+
+Note:
+
+* Calling the program through the shell is usually not required.
+
+* It's easier to look at the returncode attribute than the
+  exitstatus.
+
+A more real-world example would look like this:
+
+try:
+    retcode = call("mycmd" + " myarg", shell=True)
+    if retcode < 0:
+        print >>sys.stderr, "Child was terminated by signal", -retcode
+    else:
+        print >>sys.stderr, "Child returned", retcode
+except OSError, e:
+    print >>sys.stderr, "Execution failed:", e
+
+
+Replacing os.spawn*
+-------------------
+P_NOWAIT example:
+
+pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+pid = Popen(["/bin/mycmd", "myarg"]).pid
+
+
+P_WAIT example:
+
+retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+retcode = call(["/bin/mycmd", "myarg"])
+
+
+Vector example:
+
+os.spawnvp(os.P_NOWAIT, path, args)
+==>
+Popen([path] + args[1:])
+
+
+Environment example:
+
+os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
+==>
+Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
+
+
+Replacing os.popen*
+-------------------
+pipe = os.popen(cmd, mode='r', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
+
+pipe = os.popen(cmd, mode='w', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
+
+
+(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdin, child_stdout) = (p.stdin, p.stdout)
+
+
+(child_stdin,
+ child_stdout,
+ child_stderr) = os.popen3(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
+(child_stdin,
+ child_stdout,
+ child_stderr) = (p.stdin, p.stdout, p.stderr)
+
+
+(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
+
+
+Replacing popen2.*
+------------------
+Note: If the cmd argument to popen2 functions is a string, the command
+is executed through /bin/sh.  If it is a list, the command is directly
+executed.
+
+(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
+==>
+p = Popen(["somestring"], shell=True, bufsize=bufsize
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+
+(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
+==>
+p = Popen(["mycmd", "myarg"], bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
+except that:
+
+* subprocess.Popen raises an exception if the execution fails
+* the capturestderr argument is replaced with the stderr argument.
+* stdin=PIPE and stdout=PIPE must be specified.
+* popen2 closes all filedescriptors by default, but you have to specify
+  close_fds=True with subprocess.Popen.
+
+
+"""
+
+import sys
+mswindows = (sys.platform == "win32")
+
+import os
+import types
+import traceback
+
+if mswindows:
+    import threading
+    import msvcrt
+    if 0: # <-- change this to use pywin32 instead of the _subprocess driver
+        import pywintypes
+        from win32api import GetStdHandle, STD_INPUT_HANDLE, \
+                             STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
+        from win32api import GetCurrentProcess, DuplicateHandle, \
+                             GetModuleFileName, GetVersion
+        from win32con import DUPLICATE_SAME_ACCESS
+        from win32pipe import CreatePipe
+        from win32process import CreateProcess, STARTUPINFO, \
+                                 GetExitCodeProcess, STARTF_USESTDHANDLES, \
+                                 CREATE_NEW_CONSOLE
+        from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
+    else:
+        from _subprocess import *
+        class STARTUPINFO:
+            dwFlags = 0
+            hStdInput = None
+            hStdOutput = None
+            hStdError = None
+        class pywintypes:
+            error = IOError
+else:
+    import select
+    import errno
+    import fcntl
+    import pickle
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call"]
+
+try:
+    MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+    MAXFD = 256
+
+# True/False does not exist on 2.2.0
+try:
+    False
+except NameError:
+    False = 0
+    True = 1
+
+_active = []
+
+def _cleanup():
+    for inst in _active[:]:
+        inst.poll()
+
+PIPE = -1
+STDOUT = -2
+
+
+def call(*args, **kwargs):
+    """Run command with arguments.  Wait for command to complete, then
+    return the returncode attribute.
+
+    The arguments are the same as for the Popen constructor.  Example:
+
+    retcode = call(["ls", "-l"])
+    """
+    return Popen(*args, **kwargs).wait()
+
+
+def list2cmdline(seq):
+    """
+    Translate a sequence of arguments into a command line
+    string, using the same rules as the MS C runtime:
+
+    1) Arguments are delimited by white space, which is either a
+       space or a tab.
+
+    2) A string surrounded by double quotation marks is
+       interpreted as a single argument, regardless of white space
+       contained within.  A quoted string can be embedded in an
+       argument.
+
+    3) A double quotation mark preceded by a backslash is
+       interpreted as a literal double quotation mark.
+
+    4) Backslashes are interpreted literally, unless they
+       immediately precede a double quotation mark.
+
+    5) If backslashes immediately precede a double quotation mark,
+       every pair of backslashes is interpreted as a literal
+       backslash.  If the number of backslashes is odd, the last
+       backslash escapes the next double quotation mark as
+       described in rule 3.
+    """
+
+    # See
+    # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
+    result = []
+    needquote = False
+    for arg in seq:
+        bs_buf = []
+
+        # Add a space to separate this argument from the others
+        if result:
+            result.append(' ')
+
+        needquote = (" " in arg) or ("\t" in arg)
+        if needquote:
+            result.append('"')
+
+        for c in arg:
+            if c == '\\':
+                # Don't know if we need to double yet.
+                bs_buf.append(c)
+            elif c == '"':
+                # Double backspaces.
+                result.append('\\' * len(bs_buf)*2)
+                bs_buf = []
+                result.append('\\"')
+            else:
+                # Normal char
+                if bs_buf:
+                    result.extend(bs_buf)
+                    bs_buf = []
+                result.append(c)
+
+        # Add remaining backspaces, if any.
+        if bs_buf:
+            result.extend(bs_buf)
+
+        if needquote:
+            result.append('"')
+
+    return ''.join(result)
+
+
+class Popen(object):
+    def __init__(self, args, bufsize=0, executable=None,
+                 stdin=None, stdout=None, stderr=None,
+                 preexec_fn=None, close_fds=False, shell=False,
+                 cwd=None, env=None, universal_newlines=False,
+                 startupinfo=None, creationflags=0):
+        """Create new Popen instance."""
+        _cleanup()
+
+        if mswindows:
+            if preexec_fn is not None:
+                raise ValueError("preexec_fn is not supported on Windows "
+                                 "platforms")
+            if close_fds:
+                raise ValueError("close_fds is not supported on Windows "
+                                 "platforms")
+        else:
+            # POSIX
+            if startupinfo is not None:
+                raise ValueError("startupinfo is only supported on Windows "
+                                 "platforms")
+            if creationflags != 0:
+                raise ValueError("creationflags is only supported on Windows "
+                                 "platforms")
+
+        self.stdin = None
+        self.stdout = None
+        self.stderr = None
+        self.pid = None
+        self.returncode = None
+        self.universal_newlines = universal_newlines
+
+        # Input and output objects. The general principle is like
+        # this:
+        #
+        # Parent                   Child
+        # ------                   -----
+        # p2cwrite   ---stdin--->  p2cread
+        # c2pread    <--stdout---  c2pwrite
+        # errread    <--stderr---  errwrite
+        #
+        # On POSIX, the child objects are file descriptors.  On
+        # Windows, these are Windows file handles.  The parent objects
+        # are file descriptors on both platforms.  The parent objects
+        # are None when not using PIPEs. The child objects are None
+        # when not redirecting.
+
+        (p2cread, p2cwrite,
+         c2pread, c2pwrite,
+         errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+        self._execute_child(args, executable, preexec_fn, close_fds,
+                            cwd, env, universal_newlines,
+                            startupinfo, creationflags, shell,
+                            p2cread, p2cwrite,
+                            c2pread, c2pwrite,
+                            errread, errwrite)
+
+        if p2cwrite:
+            self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
+        if c2pread:
+            if universal_newlines:
+                self.stdout = os.fdopen(c2pread, 'rU', bufsize)
+            else:
+                self.stdout = os.fdopen(c2pread, 'rb', bufsize)
+        if errread:
+            if universal_newlines:
+                self.stderr = os.fdopen(errread, 'rU', bufsize)
+            else:
+                self.stderr = os.fdopen(errread, 'rb', bufsize)
+
+        _active.append(self)
+
+
+    def _translate_newlines(self, data):
+        data = data.replace("\r\n", "\n")
+        data = data.replace("\r", "\n")
+        return data
+
+
+    if mswindows:
+        #
+        # Windows methods
+        #
+        def _get_handles(self, stdin, stdout, stderr):
+            """Construct and return tupel with IO objects:
+            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+            """
+            if stdin == None and stdout == None and stderr == None:
+                return (None, None, None, None, None, None)
+
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin == None:
+                p2cread = GetStdHandle(STD_INPUT_HANDLE)
+            elif stdin == PIPE:
+                p2cread, p2cwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                p2cwrite = p2cwrite.Detach()
+                p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+            elif type(stdin) == types.IntType:
+                p2cread = msvcrt.get_osfhandle(stdin)
+            else:
+                # Assuming file-like object
+                p2cread = msvcrt.get_osfhandle(stdin.fileno())
+            p2cread = self._make_inheritable(p2cread)
+
+            if stdout == None:
+                c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
+            elif stdout == PIPE:
+                c2pread, c2pwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                c2pread = c2pread.Detach()
+                c2pread = msvcrt.open_osfhandle(c2pread, 0)
+            elif type(stdout) == types.IntType:
+                c2pwrite = msvcrt.get_osfhandle(stdout)
+            else:
+                # Assuming file-like object
+                c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+            c2pwrite = self._make_inheritable(c2pwrite)
+
+            if stderr == None:
+                errwrite = GetStdHandle(STD_ERROR_HANDLE)
+            elif stderr == PIPE:
+                errread, errwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                errread = errread.Detach()
+                errread = msvcrt.open_osfhandle(errread, 0)
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif type(stderr) == types.IntType:
+                errwrite = msvcrt.get_osfhandle(stderr)
+            else:
+                # Assuming file-like object
+                errwrite = msvcrt.get_osfhandle(stderr.fileno())
+            errwrite = self._make_inheritable(errwrite)
+
+            return (p2cread, p2cwrite,
+                    c2pread, c2pwrite,
+                    errread, errwrite)
+
+
+        def _make_inheritable(self, handle):
+            """Return a duplicate of handle, which is inheritable"""
+            return DuplicateHandle(GetCurrentProcess(), handle,
+                                   GetCurrentProcess(), 0, 1,
+                                   DUPLICATE_SAME_ACCESS)
+
+
+        def _find_w9xpopen(self):
+            """Find and return absolut path to w9xpopen.exe"""
+            w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
+                                    "w9xpopen.exe")
+            if not os.path.exists(w9xpopen):
+                # Eeek - file-not-found - possibly an embedding
+                # situation - see if we can locate it in sys.exec_prefix
+                w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
+                                        "w9xpopen.exe")
+                if not os.path.exists(w9xpopen):
+                    raise RuntimeError("Cannot locate w9xpopen.exe, which is "
+                                       "needed for Popen to work with your "
+                                       "shell or platform.")
+            return w9xpopen
+
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines,
+                           startupinfo, creationflags, shell,
+                           p2cread, p2cwrite,
+                           c2pread, c2pwrite,
+                           errread, errwrite):
+            """Execute program (MS Windows version)"""
+
+            if not isinstance(args, types.StringTypes):
+                args = list2cmdline(args)
+
+            if shell:
+                comspec = os.environ.get("COMSPEC", "cmd.exe")
+                args = comspec + " /c " + args
+                if (GetVersion() >= 0x80000000L or
+                        os.path.basename(comspec).lower() == "command.com"):
+                    # Win9x, or using command.com on NT. We need to
+                    # use the w9xpopen intermediate program. For more
+                    # information, see KB Q150956
+                    # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
+                    w9xpopen = self._find_w9xpopen()
+                    args = '"%s" %s' % (w9xpopen, args)
+                    # Not passing CREATE_NEW_CONSOLE has been known to
+                    # cause random failures on win9x.  Specifically a
+                    # dialog: "Your program accessed mem currently in
+                    # use at xxx" and a hopeful warning about the
+                    # stability of your system.  Cost is Ctrl+C wont
+                    # kill children.
+                    creationflags |= CREATE_NEW_CONSOLE
+
+            # Process startup details
+            if startupinfo == None:
+                startupinfo = STARTUPINFO()
+            if not None in (p2cread, c2pwrite, errwrite):
+                startupinfo.dwFlags |= STARTF_USESTDHANDLES
+                startupinfo.hStdInput = p2cread
+                startupinfo.hStdOutput = c2pwrite
+                startupinfo.hStdError = errwrite
+
+            # Start the process
+            try:
+                hp, ht, pid, tid = CreateProcess(executable, args,
+                                         # no special security
+                                         None, None,
+                                         # must inherit handles to pass std
+                                         # handles
+                                         1,
+                                         creationflags,
+                                         env,
+                                         cwd,
+                                         startupinfo)
+            except pywintypes.error, e:
+                # Translate pywintypes.error to WindowsError, which is
+                # a subclass of OSError.  FIXME: We should really
+                # translate errno using _sys_errlist (or simliar), but
+                # how can this be done from Python?
+                raise WindowsError(*e.args)
+
+            # Retain the process handle, but close the thread handle
+            self._handle = hp
+            self.pid = pid
+            ht.Close()
+
+            # Child is launched. Close the parent's copy of those pipe
+            # handles that only the child should have open.  You need
+            # to make sure that no handles to the write end of the
+            # output pipe are maintained in this process or else the
+            # pipe will not close when the child process exits and the
+            # ReadFile will hang.
+            if p2cread != None:
+                p2cread.Close()
+            if c2pwrite != None:
+                c2pwrite.Close()
+            if errwrite != None:
+                errwrite.Close()
+
+
+        def poll(self):
+            """Check if child process has terminated.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
+                    self.returncode = GetExitCodeProcess(self._handle)
+                    _active.remove(self)
+            return self.returncode
+
+
+        def wait(self):
+            """Wait for child process to terminate.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                obj = WaitForSingleObject(self._handle, INFINITE)
+                self.returncode = GetExitCodeProcess(self._handle)
+                _active.remove(self)
+            return self.returncode
+
+
+        def _readerthread(self, fh, buffer):
+            buffer.append(fh.read())
+
+
+        def communicate(self, input=None):
+            """Interact with process: Send data to stdin.  Read data from
+            stdout and stderr, until end-of-file is reached.  Wait for
+            process to terminate.  The optional input argument should be a
+            string to be sent to the child process, or None, if no data
+            should be sent to the child.
+
+            communicate() returns a tuple (stdout, stderr)."""
+            stdout = None # Return
+            stderr = None # Return
+
+            if self.stdout:
+                stdout = []
+                stdout_thread = threading.Thread(target=self._readerthread,
+                                                 args=(self.stdout, stdout))
+                stdout_thread.setDaemon(True)
+                stdout_thread.start()
+            if self.stderr:
+                stderr = []
+                stderr_thread = threading.Thread(target=self._readerthread,
+                                                 args=(self.stderr, stderr))
+                stderr_thread.setDaemon(True)
+                stderr_thread.start()
+
+            if self.stdin:
+                if input != None:
+                    self.stdin.write(input)
+                self.stdin.close()
+
+            if self.stdout:
+                stdout_thread.join()
+            if self.stderr:
+                stderr_thread.join()
+
+            # All data exchanged.  Translate lists into strings.
+            if stdout != None:
+                stdout = stdout[0]
+            if stderr != None:
+                stderr = stderr[0]
+
+            # Translate newlines, if requested.  We cannot let the file
+            # object do the translation: It is based on stdio, which is
+            # impossible to combine with select (unless forcing no
+            # buffering).
+            if self.universal_newlines and hasattr(open, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
+    else:
+        #
+        # POSIX methods
+        #
+        def _get_handles(self, stdin, stdout, stderr):
+            """Construct and return tupel with IO objects:
+            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+            """
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin == None:
+                pass
+            elif stdin == PIPE:
+                p2cread, p2cwrite = os.pipe()
+            elif type(stdin) == types.IntType:
+                p2cread = stdin
+            else:
+                # Assuming file-like object
+                p2cread = stdin.fileno()
+
+            if stdout == None:
+                pass
+            elif stdout == PIPE:
+                c2pread, c2pwrite = os.pipe()
+            elif type(stdout) == types.IntType:
+                c2pwrite = stdout
+            else:
+                # Assuming file-like object
+                c2pwrite = stdout.fileno()
+
+            if stderr == None:
+                pass
+            elif stderr == PIPE:
+                errread, errwrite = os.pipe()
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif type(stderr) == types.IntType:
+                errwrite = stderr
+            else:
+                # Assuming file-like object
+                errwrite = stderr.fileno()
+
+            return (p2cread, p2cwrite,
+                    c2pread, c2pwrite,
+                    errread, errwrite)
+
+
+        def _set_cloexec_flag(self, fd):
+            try:
+                cloexec_flag = fcntl.FD_CLOEXEC
+            except AttributeError:
+                cloexec_flag = 1
+
+            old = fcntl.fcntl(fd, fcntl.F_GETFD)
+            fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
+
+
+        def _close_fds(self, but):
+            for i in range(3, MAXFD):
+                if i == but:
+                    continue
+                try:
+                    os.close(i)
+                except:
+                    pass
+
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines,
+                           startupinfo, creationflags, shell,
+                           p2cread, p2cwrite,
+                           c2pread, c2pwrite,
+                           errread, errwrite):
+            """Execute program (POSIX version)"""
+
+            if isinstance(args, types.StringTypes):
+                args = [args]
+
+            if shell:
+                args = ["/bin/sh", "-c"] + args
+
+            if executable == None:
+                executable = args[0]
+
+            # For transferring possible exec failure from child to parent
+            # The first char specifies the exception type: 0 means
+            # OSError, 1 means some other error.
+            errpipe_read, errpipe_write = os.pipe()
+            self._set_cloexec_flag(errpipe_write)
+
+            self.pid = os.fork()
+            if self.pid == 0:
+                # Child
+                try:
+                    # Close parent's pipe ends
+                    if p2cwrite:
+                        os.close(p2cwrite)
+                    if c2pread:
+                        os.close(c2pread)
+                    if errread:
+                        os.close(errread)
+                    os.close(errpipe_read)
+
+                    # Dup fds for child
+                    if p2cread:
+                        os.dup2(p2cread, 0)
+                    if c2pwrite:
+                        os.dup2(c2pwrite, 1)
+                    if errwrite:
+                        os.dup2(errwrite, 2)
+
+                    # Close pipe fds.  Make sure we doesn't close the same
+                    # fd more than once.
+                    if p2cread:
+                        os.close(p2cread)
+                    if c2pwrite and c2pwrite not in (p2cread,):
+                        os.close(c2pwrite)
+                    if errwrite and errwrite not in (p2cread, c2pwrite):
+                        os.close(errwrite)
+
+                    # Close all other fds, if asked for
+                    if close_fds:
+                        self._close_fds(but=errpipe_write)
+
+                    if cwd != None:
+                        os.chdir(cwd)
+
+                    if preexec_fn:
+                        apply(preexec_fn)
+
+                    if env == None:
+                        os.execvp(executable, args)
+                    else:
+                        os.execvpe(executable, args, env)
+
+                except:
+                    exc_type, exc_value, tb = sys.exc_info()
+                    # Save the traceback and attach it to the exception object
+                    exc_lines = traceback.format_exception(exc_type,
+                                                           exc_value,
+                                                           tb)
+                    exc_value.child_traceback = ''.join(exc_lines)
+                    os.write(errpipe_write, pickle.dumps(exc_value))
+
+                # This exitcode won't be reported to applications, so it
+                # really doesn't matter what we return.
+                os._exit(255)
+
+            # Parent
+            os.close(errpipe_write)
+            if p2cread and p2cwrite:
+                os.close(p2cread)
+            if c2pwrite and c2pread:
+                os.close(c2pwrite)
+            if errwrite and errread:
+                os.close(errwrite)
+
+            # Wait for exec to fail or succeed; possibly raising exception
+            data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
+            os.close(errpipe_read)
+            if data != "":
+                child_exception = pickle.loads(data)
+                raise child_exception
+
+
+        def _handle_exitstatus(self, sts):
+            if os.WIFSIGNALED(sts):
+                self.returncode = -os.WTERMSIG(sts)
+            elif os.WIFEXITED(sts):
+                self.returncode = os.WEXITSTATUS(sts)
+            else:
+                # Should never happen
+                raise RuntimeError("Unknown child exit status!")
+
+            _active.remove(self)
+
+
+        def poll(self):
+            """Check if child process has terminated.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                try:
+                    pid, sts = os.waitpid(self.pid, os.WNOHANG)
+                    if pid == self.pid:
+                        self._handle_exitstatus(sts)
+                except os.error:
+                    pass
+            return self.returncode
+
+
+        def wait(self):
+            """Wait for child process to terminate.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                pid, sts = os.waitpid(self.pid, 0)
+                self._handle_exitstatus(sts)
+            return self.returncode
+
+
+        def communicate(self, input=None):
+            """Interact with process: Send data to stdin.  Read data from
+            stdout and stderr, until end-of-file is reached.  Wait for
+            process to terminate.  The optional input argument should be a
+            string to be sent to the child process, or None, if no data
+            should be sent to the child.
+
+            communicate() returns a tuple (stdout, stderr)."""
+            read_set = []
+            write_set = []
+            stdout = None # Return
+            stderr = None # Return
+
+            if self.stdin:
+                # Flush stdio buffer.  This might block, if the user has
+                # been writing to .stdin in an uncontrolled fashion.
+                self.stdin.flush()
+                if input:
+                    write_set.append(self.stdin)
+                else:
+                    self.stdin.close()
+            if self.stdout:
+                read_set.append(self.stdout)
+                stdout = []
+            if self.stderr:
+                read_set.append(self.stderr)
+                stderr = []
+
+            while read_set or write_set:
+                rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+                if self.stdin in wlist:
+                    # When select has indicated that the file is writable,
+                    # we can write up to PIPE_BUF bytes without risk
+                    # blocking.  POSIX defines PIPE_BUF >= 512
+                    bytes_written = os.write(self.stdin.fileno(), input[:512])
+                    input = input[bytes_written:]
+                    if not input:
+                        self.stdin.close()
+                        write_set.remove(self.stdin)
+
+                if self.stdout in rlist:
+                    data = os.read(self.stdout.fileno(), 1024)
+                    if data == "":
+                        self.stdout.close()
+                        read_set.remove(self.stdout)
+                    stdout.append(data)
+
+                if self.stderr in rlist:
+                    data = os.read(self.stderr.fileno(), 1024)
+                    if data == "":
+                        self.stderr.close()
+                        read_set.remove(self.stderr)
+                    stderr.append(data)
+
+            # All data exchanged.  Translate lists into strings.
+            if stdout != None:
+                stdout = ''.join(stdout)
+            if stderr != None:
+                stderr = ''.join(stderr)
+
+            # Translate newlines, if requested.  We cannot let the file
+            # object do the translation: It is based on stdio, which is
+            # impossible to combine with select (unless forcing no
+            # buffering).
+            if self.universal_newlines and hasattr(open, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
+
+def _demo_posix():
+    #
+    # Example 1: Simple redirection: Get process list
+    #
+    plist = Popen(["ps"], stdout=PIPE).communicate()[0]
+    print "Process list:"
+    print plist
+
+    #
+    # Example 2: Change uid before executing child
+    #
+    if os.getuid() == 0:
+        p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
+        p.wait()
+
+    #
+    # Example 3: Connecting several subprocesses
+    #
+    print "Looking for 'hda'..."
+    p1 = Popen(["dmesg"], stdout=PIPE)
+    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+    print repr(p2.communicate()[0])
+
+    #
+    # Example 4: Catch execution error
+    #
+    print
+    print "Trying a weird file..."
+    try:
+        print Popen(["/this/path/does/not/exist"]).communicate()
+    except OSError, e:
+        if e.errno == errno.ENOENT:
+            print "The file didn't exist.  I thought so..."
+            print "Child traceback:"
+            print e.child_traceback
+        else:
+            print "Error", e.errno
+    else:
+        print >>sys.stderr, "Gosh.  No error."
+
+
+def _demo_windows():
+    #
+    # Example 1: Connecting several subprocesses
+    #
+    print "Looking for 'PROMPT' in set output..."
+    p1 = Popen("set", stdout=PIPE, shell=True)
+    p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
+    print repr(p2.communicate()[0])
+
+    #
+    # Example 2: Simple execution of program
+    #
+    print "Executing calc..."
+    p = Popen("calc")
+    p.wait()
+
+
+if __name__ == "__main__":
+    if mswindows:
+        _demo_windows()
+    else:
+        _demo_posix()
Index: trunk/src/testing/bin/sageProxy/README
===================================================================
--- trunk/src/testing/bin/sageProxy/README	(revision 4)
+++ trunk/src/testing/bin/sageProxy/README	(revision 4)
@@ -0,0 +1,134 @@
+---------------------------------------------------
+		
+         	SAGE PROXY README
+
+---------------------------------------------------
+(last updated on July, 2007)	
+
+
+(0) DESCRIPTION
+---------------------------------------------------
+SageProxy exposes SAGE commands through web-services (XML-RPC). This allows
+you to easily talk to SAGE without using sockets and writing your own 
+complete client. This is mainly used by the SAGE Web UI for now.
+
+
+
+(1) REQUIREMENTS (none for binary distributions):
+---------------------------------------------------
+- Python 2.3    	(www.python.org)
+
+
+
+(2) HOW TO RUN:
+---------------------------------------------------
+- sageProxy is easily run through the SageLauncher included with SAGE v2.5 and later
+- to run by hand, see all the command line arguments with "python sageProxy.py -h"
+
+
+
+(3) CONTROLLING SAGE THROUGH SAGE PROXY (via XML-RPC):
+-------------------------------------------------------
+- the description of the methods is as follows:
+
+
+*******    bringToFront    *********
+
+Brings the application window to front (on top of the other ones).
+Returns: 1 if everythin went OK and the message was sent
+Returns: -1 if the message was not sent for whatever reason (including
+         if the app was already on top)
+
+
+
+********    closeApp    *********
+
+Closes the app corresponding to the specified appId.
+Returns: the new status of all the apps in the same format as getAppStatus
+        (sleeps 2 seconds before returning it to ensure that the datastructure was updated
+         by the messages from SAGE about the closed app)
+Returns: -1 if failed for whatever reason
+
+
+
+********    executeApp    *********
+
+Starts a new application with appName (string) and configNum (int). You can also optionally specify
+initial position and size of the application window that you pass in as a tuple of integers.
+If the application itself requires some command line arguments during startup, those can be
+specified as well with the optionalArgs parameter (string).
+Shareable parameter is used when you want to run the application through sageBridge which
+means that it can be shared among other displays. If False it will run the app locally.
+Returns: the new status of all the apps in the same format as getAppStatus
+        (sleeps 2 seconds before returning it to ensure that the datastructure was updated
+         by the messages from SAGE about the new app)
+Returns: -1 if failed for whatever reason
+
+
+
+********    getAllAppID    *********
+
+Returns all the app ID currently running on SAGE
+
+
+
+********    getAppList    *********
+
+Returns: a list (strings) of app names available for running
+Returns: -1 if failed for whatever reason
+
+
+
+********    getAppStatus    *********
+
+If called without parameters it will return the status for all currently running applications.
+If called with appId parameter it will return the status just for that application.
+Returns: a hash where the key is appId (string) and the value is a list of app status:
+        [string appName, int appId, int left, int right, int bottom,
+         int top, int sailID, int zValue, int configNum, string title]
+Returns: -1 if failed for whatever reason
+
+
+
+********    getDisplayInfo    *********
+
+Returns: a list (integers): [totalNumTiles, numTilesX, numTilesY, totalWidth,
+                             totalHeight, tileWidth, tileHeight]
+Returns: -1 if failed for whatever reason
+
+
+
+********    getZValues    *********
+
+Returns: a list (integers) of z values [numChanges, appId, zValue, appId, zValue ....]
+Returns: -1 if failed for whatever reason
+
+
+
+********    moveWindow    *********
+
+Moves a window to the specified location (absolute position) in tiled display coordinates.
+The x,y is interpreted as the lower left corner of the application.
+All parameters are integers.
+Returns: 1 if successful.
+Returns: -1 if failed for whatever reason.
+
+
+
+********    resizeWindow    *********
+
+Resizes a window to the specified size in tiled display coordinates.
+The lower left corner of the display is considered 0,0.
+All parameters are integers.
+Returns: 1 if successful.
+Returns: -1 if failed for whatever reason.
+
+
+
+********    shareApp    *********
+
+Sends a request to fsManager to share the specified application to the specified display
+Parameters: - appId of the application you want to share
+            - ip address and port number of the machine to stream to
+Returns: 1 if succeeded
+Returns: -1 if failed for whatever reason
Index: trunk/src/testing/bin/sageProxy/SAGEApp.py
===================================================================
--- trunk/src/testing/bin/sageProxy/SAGEApp.py	(revision 4)
+++ trunk/src/testing/bin/sageProxy/SAGEApp.py	(revision 4)
@@ -0,0 +1,193 @@
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import sys, string
+
+### Class to hold sage application info
+### An instance of this class should exist for every app Id on SAGE
+class SAGEApp :
+
+        
+    def __init__(self, name, id, left=0, right=0, bottom=0, top=0, sailID=0, zValue=0, configNum=1, title="untitled"):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.sailID = sailID
+        self.appName = name
+        self.id = id
+        self.zValue = zValue
+        self.configNum = configNum
+        self.title = title
+
+    def setAll(self, name, id, left, right, bottom, top, sailID, zValue):#, configNum, title):
+        self.appName = name
+        self.id = id
+        self.left = left
+        self.right = right
+        self.bottom = bottom
+        self.top = top
+        self.sailID = sailID
+        self.zValue = zValue
+        #self.configNum = configNum
+        #self.title = title
+
+    def getAll(self):
+        return [self.appName, self.id, self.left, self.right,
+                self.bottom, self.top, self.sailID, self.zValue,
+                self.configNum, self.title]
+
+    #### Set the values of the application
+    #### @arg left Left position of the window
+    #### @arg right right position of the window
+    #### @arg top top position of the window
+    #### @arg bottom bottom position of the window
+    #### @arg sailID sailID of the app
+    def setValues(self, id, left, right, top, bottom, sailID, zValue) :
+        self.id = id
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.sailID = sailID
+        self.zValue = zValue
+
+    def getLeft(self):
+        return self.left
+
+    def getRight(self):
+        return self.right
+
+    def getTop(self):
+        return self.top
+
+    def getBottom(self):
+        return self.bottom
+
+    def getId(self):
+        return self.id
+
+    def getConfigNum(self):
+        return self.configNum
+
+    def getTitle(self):
+        return self.title
+
+    def setTitle(self, newTitle):
+        self.title = newTitle
+    
+    #   Set the app name
+    #   @arg appName Name of the app
+    def setName(self, appName):
+        self.appName = appName
+
+    #   Get the app name
+    #   @return Returns the app name
+    def getName(self):
+        return self.appName
+    
+    #### Get the application window values
+    #### @return Returns a list Format: [<left>, <right>, <top>, <bottom>]
+    def getValues(self) :
+        return [self.left, self.right, self.top, self.bottom]
+
+    #### Get the app's sailID
+    def getSailID(self):
+        return self.sailID
+
+    #   Set the Z value of the app
+    #   @arg value Z value of the app
+    def setZvalue(self, value):
+        self.zValue = value
+
+    #   get the Z value of the app
+    def getZvalue(self):
+        return self.zValue
+
+    def getWidth(self):
+        return self.right - self.left
+
+    def getHeight(self):
+        return self.top - self.bottom
+
+
+
+
+### a class to hold the information about all the available apps that SAGE supports
+class SAGEAppInitial:
+
+    def __init__ (self, name, configNames):
+        self._name = name
+        self._configNames = configNames
+        
+    def GetName (self):
+        return self._name
+
+    def SetName (self, name):
+        self._name = name
+
+    def GetConfigNames(self):
+        return self._configNames
+    
+    ## # execution configurations
+##     def AddConfig (self, name, stConfig):
+##         self._execConfigs[ len(self._execConfigs)+1 ] = (name, string.strip(stConfig))
+
+##     def GetNumConfigs(self):
+##         return self._numConfigs
+    
+##     def GetConfigHash (self):
+##         return self._execConfigs
+
+##     def GetConfig (self, configNum):
+##         if self._execConfigs.has_key( configNum ):
+##             return self._execConfigs[ configNum ]
+##         else:
+##             print "Error: No configuration number ", configNum
+##             return "No Configuration"
+
+##     # instances already started
+##     def AddInstanceId (self, instanceId):
+##         self._appInstanceIds.append( instanceId )
+
+##     def GetInstanceIds (self):
+##         return self._appInstanceIds
+
+    
Index: trunk/src/testing/bin/sageProxy/SAGEGate.py
===================================================================
--- trunk/src/testing/bin/sageProxy/SAGEGate.py	(revision 4)
+++ trunk/src/testing/bin/sageProxy/SAGEGate.py	(revision 4)
@@ -0,0 +1,502 @@
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+
+"""
+	SAGE UI --> SAGE
+	---------------------------	
+	Register 			1000
+	Execute				1001
+	Shutdown			1002
+	Move				1003
+	Resize				1004
+	Start Performance		1005
+	Stop Performance		1006
+	BackColor			1007
+	Z Value Change                  1008
+	Bring To Front                  1010
+	App Properties Change           1011
+	App Frame Rate Change           1012
+	SAGE Shutdown                   1100
+	
+
+	SAGE ----> SAGE UI
+	--------------------------
+	Status				40000 
+	App Info			40001 APPID L R T B SAIL-ID
+	Performance			40002
+	App Shutdown                    40003
+	Display Info                    40004
+	Z Order Change                  40005
+	
+
+	STORE INFORMATION
+"""
+
+
+
+from threading import Thread
+import socket, sys, string, os.path, xmlrpclib
+
+
+TIMEOUT_INTERVAL = 2
+BLANK = ' '
+HEADER_ITEM_LEN = 8
+APP_LAUNCHER_PORT = 19010
+
+
+class SAGEGate:
+
+	def __init__(self, logFunc ):
+                self.hashCallbackFunction = {}    # (AKS 2004-10-16)
+		self.threadkilled = False
+		self.connected = False
+		self.WriteLog = logFunc  #redirect output
+	
+		# used for printing out informative messages (on sending and receiving)
+		self.hashOutgoingMessages = {}  #RJ 2005-01-24
+		self.hashOutgoingMessages[1000] = "Register UI"
+		self.hashOutgoingMessages[1001] = "App Start"
+		self.hashOutgoingMessages[1002] = "App Shutdown"
+		self.hashOutgoingMessages[1003] = "Move"
+		self.hashOutgoingMessages[1004] = "Resize"
+		self.hashOutgoingMessages[1005] = "Request Performance"
+		self.hashOutgoingMessages[1006] = "Stop Performance"
+		self.hashOutgoingMessages[1007] = "Background Color"
+		self.hashOutgoingMessages[1008] = "Z Value"
+		self.hashOutgoingMessages[1010] = "Bring To Front"
+		self.hashOutgoingMessages[1011] = "App Properties Change"
+		self.hashOutgoingMessages[1012] = "App Frame Rate Change"
+		self.hashOutgoingMessages[1015] = "Stream Request"
+		self.hashOutgoingMessages[1100] = "Shutdown"
+
+		self.hashIncomingMessages = {} #RJ 2005-01-24
+		self.hashIncomingMessages[40000] = "SAGE Status Message"
+		self.hashIncomingMessages[40001] = "App Info Return"
+		self.hashIncomingMessages[40002] = "Performance Info"
+		self.hashIncomingMessages[40003] = "App Shutdown"
+		self.hashIncomingMessages[40004] = "Display Info"
+		self.hashIncomingMessages[40005] = "Z Change"
+		
+
+					
+	def makemsg(self,dst,code,appcode,size,data):
+		msg = '%8s\0%8s\0%8s\0%s\0' %(dst,code,appcode,data)
+		size = len(msg) + 9
+		msg = '%8s\0%s' %(size,msg)
+		return msg	
+
+
+	def connectToAppLauncher(self, host=socket.gethostname(), port=APP_LAUNCHER_PORT):
+		self.appLauncher = xmlrpclib.ServerProxy("http://" + host + ":" + str(port))
+		try:
+			self.getAppList()
+		except socket.error:
+			return False
+		except:
+			pass
+		return True
+		
+	
+	##################################################################	
+	#  Connect To Sage
+	##################################################################	
+	def connectToSage(self,host=socket.gethostname(),port=20001):
+		if self.connected == True: return 0
+
+		## connect to the app launcher first
+		if not self.connectToAppLauncher(host, APP_LAUNCHER_PORT):
+			self.WriteLog("\n===> Can't connect to the appLauncher")
+			return -1
+		
+		## create socket
+		self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
+		if self.sock is None: return 0
+
+		if host: self.sageHost = host
+		if port > 0: self.sagePort = port
+		## connect
+		try:
+			self.sock.connect((host,port))
+		except socket.error:
+			self.WriteLog('can\'t connect to SAGE on '+ self.sageHost + ":" + str(self.sagePort))
+			return 0
+
+                #### RJ 2005-01-21
+                # without this, this thread will never exit because sock.recv is blocking and it will wait until
+                # something comes in. What happens is, "while" checks if threadkilled is false, it is so it goes
+                # in here and blocks until something is received. In the meantime, we want to quit so we set
+                # threadkilled to True but since we are blocked by sock.recv, we wont be able to get to the "while" again
+                self.sock.settimeout(TIMEOUT_INTERVAL)  
+		
+		##### FOR Thread
+		self.t = Thread(target=self.recvWorker,args=())
+		self.t.setDaemon(True)
+		self.t.start()
+
+		self.threadkilled = False
+		self.connected = True
+
+		#print 'connected to SAGE',self.sageHost,self.sagePort
+		return 1 
+	
+	def disconnectFromSage(self):
+		if self.connected == False: return 0
+		
+		self.threadkilled = True
+		self.connected = False
+		
+		self.t.join()
+		self.sock.close()
+		del self.sock
+		#print 'disconnected from SAGE',self.sageHost,self.sagePort
+
+		return 1
+	#################################################################
+
+	def sendmsg(self,msg):
+		totalcount = 0
+		try:
+			totalcount = self.sock.send(msg)
+		except socket.error:
+			#print 'socket error'
+			totalcount = -1
+		except Exception:
+			totalcount = -1
+		return totalcount
+
+
+	# get the applist from the applauncher first and call the appropriate function
+	def getAppList(self):
+		try:
+			appList = self.appLauncher.getAppList()
+		except socket.error:
+			return -1  #the server is not running
+		else:
+			self.hashCallbackFunction[ 40000 ]( appList )
+			
+
+
+	##################################################################	
+	# Register
+	##################################################################	
+	# 1000 none
+	# #############40000 SAGE-STATUS Format (?)
+	# 40004 display info format
+	# 40001 app-inst-ID left right top bottom sail-ID
+	##################################################################	
+	def registerSage(self):
+		if self.connected == False:
+			return 0
+		msg = self.makemsg('',1000,'',0,'')
+		status = self.sendmsg(msg)
+		return status
+
+	##################################################################	
+	# Execute
+	##################################################################	
+	# 1001 app-name 100 100 (app-name(?)) 
+	# 40001 app-inst-ID left right top bottom sail-ID
+	##################################################################	
+	def executeApp(self, appName, configName="default", pos=False, size=False, shareable=False, optionalArgs=""):
+		if self.connected == False: return 0
+		if not appName: return 0
+
+		return self.appLauncher.startDefaultApp(appName, self.sageHost, self.sagePort+1, shareable, configName, pos, size, optionalArgs)
+
+		
+
+
+	##################################################################	
+	# Shutdown
+	##################################################################	
+	# 1002 app-instance
+	# 40003 app-Inst-ID (?)
+	##################################################################	
+	def shutdownApp(self,appId):
+		if self.connected == False: return 0
+		#if not appId: return 0
+
+		#msg = self.makemsg('',1002,'',len(appId),appId)
+		data = "" + str(appId)
+		msg = self.makemsg('',1002,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+		
+	##################################################################	
+	# Move
+	##################################################################	
+	# 1003 app-instance dist-X,dist-Y
+	##################################################################	
+	def moveWindow(self,appId,distX,distY):
+		if self.connected == False: return 0
+
+		#make sure all the coordinates are ints
+		distX = int(distX)
+		distY = int(distY)
+		
+		data = str(appId) + BLANK + str(distX) + BLANK + str(distY)
+		msg = self.makemsg('',1003,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+	
+   	##############################################################
+	# Resize
+	# 1004 app-instance lef,right,top,bottom
+	##################################################################
+	def resizeWindow(self,appId,left=0,right=0,bottom=0,top=0):
+		if self.connected == False: return 0
+		#if not appId: return 0
+
+		#make sure all the coordinates are ints
+		left = int(left)
+		right = int(right)
+		bottom = int(bottom)
+		top = int(top)
+
+		data = str(appId) + BLANK + str(left) + BLANK + str(right) + BLANK + str(bottom) + BLANK + str(top)
+		msg = self.makemsg('',1004,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+
+	###########################################################
+	# Performance Information
+	###########################################################
+	# 1005 app-instance sending-rate
+	# 1006 app-instance 	
+	###########################################################	
+	def startPerformance(self,appId,sendingrate=2):
+		if self.connected == False: return 0
+		data = "%d %d" % (appId, sendingrate )
+		msg = self.makemsg('',1005,'',len(data),data)
+		status = self.sendmsg(msg)	
+		return status
+	
+	def stopPerformance(self,appId):
+		if self.connected == False: return 0
+		appId = str(appId) # convert the data to string format
+		
+		msg = self.makemsg('',1006,'',len(appId),appId)
+		status = self.sendmsg(msg)
+		return status
+
+
+	####################################	
+	# Background Color
+	# 1007 red,green blue	
+	##################################################################
+	def setBgColor(self,(red,green,blue)=(1,1,1)):
+		if self.connected == False: return 0
+
+		data = str(red) + BLANK + str(green) + BLANK + str(blue)
+		msg = self.makemsg('',1007,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+
+
+	####################################	
+	# bring the application window to the top (front)
+	# 1010 app-inst-ID 
+	##################################################################
+	def bringToFront(self, appId):
+		if self.connected == False: return 0
+
+		data = str(appId)
+		msg = self.makemsg('',1010,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+
+
+	####################################	
+	# Change App Properties
+	# 1011 appId, fsmIP, fsmPort, appConfigNum	
+	##################################################################
+	def changeAppProperties(self,appId, newTitle, newTitleColor=(-1,-1,-1), newBorderColor=(-1,-1,-1)):
+		if self.connected == False: return 0
+
+		data = str(appId) + BLANK + str(newTitle)
+		data = data + BLANK + str(newTitleColor[0]) + BLANK + str(newTitleColor[1]) + BLANK + str(newTitleColor[2])
+		data = data + BLANK + str(newBorderColor[0]) + BLANK + str(newBorderColor[1]) + BLANK + str(newBorderColor[2])
+		#data = data + BLANK + str(newTitle)
+		msg = self.makemsg('',1011,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+
+	####################################	
+	# Change App Frame Rate
+	# 1012 appId, fsmIP, fsmPort, appConfigNum	
+	##################################################################
+	def changeAppFrameRate(self,appId, newFrameRate):
+		if self.connected == False: return 0
+
+		data = str(appId) + BLANK + str(newFrameRate)
+		msg = self.makemsg('',1012,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+
+
+	####################################	
+	# Stream Request
+	# 1015 appId, fsmIP, fsmPort
+	##################################################################
+	def streamApp(self,appId, fsmIP, fsmPort):
+		if self.connected == False: return 0
+
+		data = str(appId) + BLANK + str(fsmIP) + BLANK + str(fsmPort)
+		msg = self.makemsg('',1015,'',len(data),data)
+		status = self.sendmsg(msg)
+		return status
+	
+
+	####################################	
+	# SAGE shutdown
+	# 1100 	<none>
+	##################################################################
+	def shutdownSAGE(self):
+		if self.connected == False: return 0
+		msg = self.makemsg('',1100,'',0,'')
+		status = self.sendmsg(msg)
+		return status
+
+
+	### informs the user when the connection breaks
+	def showConnectionClosedDialog(self):
+		pass
+
+	
+	##############
+	## Recv Worker Thread
+	##################################################################
+	def recvWorker(self):
+		
+		while self.threadkilled == False:   #doesn't work as expected without the sock.settimeout (look below)
+
+			#############################
+			try:
+
+				code = ""
+				incomingMsg = ""
+				msgSize = ""
+				
+				# first make sure you read the whole 8 bytes for the size
+				while len(msgSize) < HEADER_ITEM_LEN:
+					msgSize = self.sock.recv(HEADER_ITEM_LEN)
+					if len( msgSize ) == 0:
+						self.threadkilled = True
+						break
+					
+				if self.threadkilled == True:
+					#wx.CallAfter(self.showConnectionClosedDialog)
+					break
+
+				# this is the number of bytes that the total message contains
+				msgSize = msgSize.replace('\x00', '')
+				sizeLeft = int(msgSize) - HEADER_ITEM_LEN    # we already read the size so read the rest of the bytes
+
+				# read the rest of the message
+				while len( incomingMsg ) < sizeLeft:
+					incomingMsg = incomingMsg + self.sock.recv( sizeLeft - len(incomingMsg) )
+
+				
+				# extract the tokens from the message
+				if len( incomingMsg ) > 0:
+					incomingMsg = incomingMsg.replace('\x00', ' ')
+					dst = incomingMsg[ 1:9 ].strip()
+					code = incomingMsg[ 10:18 ].strip()
+					appCode = incomingMsg[ 19:27 ].strip()
+					data = incomingMsg[ 28: ].strip()
+
+					# print the message out
+					if int(code) in self.hashIncomingMessages and int(code) != 40002:
+						self.WriteLog("\n\tRECEIVED:  " + self.hashIncomingMessages[int(code)])
+						lines = data.split('\n')
+						if len(lines) < 2:
+							self.WriteLog("\t\t   [" + lines[0] + "]\n\n")
+						else:
+							for i in range(0, len(lines)):
+								if i == 0:
+									self.WriteLog("\t\t   [" + lines[i])
+								elif i == len(lines)-1:
+									self.WriteLog("\t\t    " + lines[i] + "]\n\n")
+								else:
+									self.WriteLog("\t\t    " + lines[i])
+
+				    
+			except socket.timeout:
+				continue
+			except socket.error:
+				#print 'socket error on receive'
+				continue
+			except:
+				self.WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+				continue
+		
+
+			## SAGE Status
+                        if self.threadkilled:
+                            break
+
+		        # now call the appropriate function to update the datastructure
+		        if self.hashCallbackFunction.has_key( int(code) ):
+			    self.hashCallbackFunction[ int(code) ]( data )
+
+		
+
+
+	# converts all non-printable characters from the buffer to white spaces
+	# (so that they can be removed using string.strip() function)
+        def cleanBuffer( self, stBuffer ):
+            stNewBuffer = ""
+            
+            for ch in stBuffer:
+                if ( ch in string.printable ):
+                    stNewBuffer = stNewBuffer + ch
+                else:
+                    stNewBuffer = stNewBuffer + " "
+            
+            return stNewBuffer
+
+
+
+
+        def registerCallbackFunction( self, msgID, function ):
+            self.hashCallbackFunction[ msgID ] = function
+                
+
Index: trunk/src/testing/bin/sageProxy/sageDisplayInfo.py
===================================================================
--- trunk/src/testing/bin/sageProxy/sageDisplayInfo.py	(revision 4)
+++ trunk/src/testing/bin/sageProxy/sageDisplayInfo.py	(revision 4)
@@ -0,0 +1,67 @@
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+class sageDisplayInfo :
+
+    # Constructor
+    def __init__(self) :
+        self.tileNumber = 0
+        self.dimX = 0
+        self.dimY = 0
+        self.desktopWidth = 0
+        self.desktopHeight = 0
+        self.tileWidth = 0
+        self.tileHeight = 0
+
+    def setValues(self, tileNum, dimX, dimY, deskWidth, deskHeight,
+                  tileWidth, tileHeight) :
+
+        self.tileNumber = tileNum
+        self.dimX = dimX
+        self.dimY = dimY
+        self.desktopWidth = deskWidth
+        self.desktopHeight = deskHeight
+        self.tileWidth = tileWidth
+        self.tileHeight = tileHeight
+
+    def getValues(self) :
+        return [self.tileNumber, self.dimX, self.dimY,
+                self.desktopWidth, self.desktopHeight,
+                self.tileWidth, self.tileHeight]
+        
Index: trunk/src/testing/bin/sageProxy/sageProxy.py
===================================================================
--- trunk/src/testing/bin/sageProxy/sageProxy.py	(revision 4)
+++ trunk/src/testing/bin/sageProxy/sageProxy.py	(revision 4)
@@ -0,0 +1,356 @@
+#!/usr/bin/python
+
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+from SimpleXMLRPCServer import *
+from time import sleep
+import socket, sys, string, os.path, SocketServer, base64, time, optparse
+from sageUIDataInfo import *
+from SAGEGate import *
+import traceback as tb
+from threading import RLock
+
+XMLRPC_PORT = 20001 #9192
+REDIRECT = True
+
+
+# to output all the error messages to a file
+outputLock = RLock()
+def WriteLog(message):
+    outputLock.acquire()
+    try:
+        if not REDIRECT:
+            #tb.print_exc()
+            print message
+        else:
+            f = open("sage_proxy.log", "a")
+            #tb.print_exc(file=f)
+            f.write(message+"\n")
+            f.close()
+    except:
+        pass
+    outputLock.release()
+
+
+
+
+
+# a mix-in class for adding the threading support to the XMLRPC server
+class ThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
+    allow_reuse_address = True
+
+
+class Proxy:
+    def __init__(self, host=socket.gethostname(), port=20001, passwd=""):
+        self.sageData = sageUIDataInfo()   # a datastructure that stores the display and app state
+        
+        self.sageGate = SAGEGate(WriteLog)         # communication channel with sage
+        self.sageGate.registerCallbackFunction( 40000, self.sageData.setSageStatus )
+        self.sageGate.registerCallbackFunction( 40001, self.sageData.setSageAppInfo )
+        self.sageGate.registerCallbackFunction( 40003, self.sageData.sageAppShutDown )
+        self.sageGate.registerCallbackFunction( 40004, self.sageData.setSageDisplayInformation )
+        self.sageGate.registerCallbackFunction( 40005, self.sageData.setSageZValue )
+
+        # now connect to sage and register with it
+        if self.sageGate.connectToSage(host, port) == 0:
+            sys.exit(0)
+        self.sageGate.registerSage()
+	self.sessionPassword = passwd
+
+
+    def getDisplayInfo(self):
+        """ Returns: a list (integers): [totalNumTiles, numTilesX, numTilesY, totalWidth,
+                                         totalHeight, tileWidth, tileHeight]
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            return self.sageData.getSageDisplayInformation()
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def getAppList(self):
+        """ Returns: a list (strings) of app names available for running
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            return self.sageData.getAvailableAppNames()
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def getZValues(self):
+        """ Returns: a list (integers) of z values [numChanges, appId, zValue, appId, zValue ....]
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            return self.sageData.getZvalues()
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def getAppStatus(self, appId=-1):
+        """ If called without parameters it will return the status for all currently running applications.
+            If called with appId parameter it will return the status just for that application.
+            Returns: a hash where the key is appId (string) and the value is a list of app status:
+                    [string appName, int appId, int left, int right, int bottom,
+                     int top, int sailID, int zValue, int configNum, string title]
+            Returns: -1 if failed for whatever reason
+             
+        """
+        try:
+            if appId == -1:
+                return self.sageData.getAllAppInfo()
+            else:
+                return self.sageData.getAppInfo(appId)
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def getAllAppID(self):
+	""" Returns all the app ID currently running on SAGE
+        """
+	try:
+	    return self.sageData.getAllAppIDs()
+	except:
+	    WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+	    return -1
+
+
+    def getNewAppID(self):
+	try:
+	   return self.sageData.getNewAppID()
+	except:
+	   WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+           return -1
+
+
+    def bringToFront(self, appId):
+        """ Brings the application window to front (on top of the other ones).
+            Returns: 1 if everythin went OK and the message was sent
+            Returns: -1 if the message was not sent for whatever reason (including
+                     if the app was already on top)
+        """
+        try:
+                if self.sageData.appExists(appId) and \
+                   (not self.sageData.isTopWindow(appId)) and \
+                   self.sageGate.bringToFront(appId):
+                    return 1
+                else:
+                    return -1
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+        
+
+    def moveWindow(self, appId, x, y):
+        """ Moves a window to the specified location (absolute position) in tiled display coordinates.
+            The x,y is interpreted as the lower left corner of the application.
+            All parameters are integers.
+            Returns: 1 if successful.
+            Returns: -1 if failed for whatever reason.
+        """
+        try:
+            app = self.sageData.getSAGEApp(appId)
+            left = x
+            right = x+app.getWidth()
+            bottom = y
+            top = y+app.getHeight()
+            if self.sageGate.resizeWindow(appId, left, right, bottom, top) == -1:
+                return -1
+            return 1
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def resizeWindow(self, appId, left, right, bottom, top):
+        """ Resizes a window to the specified size in tiled display coordinates.
+            The lower left corner of the display is considered 0,0.
+            All parameters are integers.
+            Returns: 1 if successful.
+            Returns: -1 if failed for whatever reason.
+        """
+        try:
+            
+            # prevent 0 or negative size
+            if (right-left < 1) or (top-bottom < 1):
+                app = self.sageData.getSAGEApp(appId)
+                ar = app.getWidth() / float(app.getHeight())
+                if ar > 1:
+                    newH = 300 # min app size
+                    newW = newH*ar
+                else:
+                    newW = 300 # min app size
+                    newH = newW/ar
+                
+                right = left+newW
+                top = bottom+newH
+
+            if self.sageGate.resizeWindow(appId, left, right, bottom, top) == -1:
+                return -1
+            return 1
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def executeApp(self, appName, configName="default", pos=False, size=False, shareable=False, optionalArgs=""):
+        """ Starts a new application with appName (string) and configNum (int). You can also optionally specify
+            initial position and size of the application window that you pass in as a tuple of integers.
+            If the application itself requires some command line arguments during startup, those can be
+            specified as well with the optionalArgs parameter (string).
+            Shareable parameter is used when you want to run the application through sageBridge which
+            means that it can be shared among other displays. If False it will run the app locally.
+            Returns: the new status of all the apps in the same format as getAppStatus
+                    (sleeps 2 seconds before returning it to ensure that the datastructure was updated
+                     by the messages from SAGE about the new app)
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            if self.sageGate.executeApp(appName, configName, pos, size, shareable, optionalArgs) == -1:
+                return -1
+            sleep(2)        #wait for the message to arrive from sage and then return the status
+            return self.sageData.getAllAppInfo()
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+
+    def closeApp(self, appId):
+        """ Closes the app corresponding to the specified appId.
+            Returns: the new status of all the apps in the same format as getAppStatus
+                    (sleeps 2 seconds before returning it to ensure that the datastructure was updated
+                     by the messages from SAGE about the closed app)
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            if not self.sageData.appExists(appId):
+                return -1
+            
+            if self.sageGate.shutdownApp(appId) == -1:
+                return -1
+            sleep(2)        #wait for the message to arrive from sage and then return the status
+            return self.sageData.getAllAppInfo()
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+        
+
+    def shareDesktop(self, sz, displayNum, ip, passwd, shareable=False):
+        oa = ip +" "+ str(displayNum) +" "+ str(sz[0]) +" "+ str(sz[1]) +" "+ passwd
+        return self.executeApp("VNCViewer", "default", False, sz, shareable, oa)
+
+
+    def shareApp(self, appId, fsIP, fsPort):
+        """ Sends a request to fsManager to share the specified application to the specified display
+            Parameters: - appId of the application you want to share
+                        - ip address and port number of the machine to stream to
+            Returns: 1 if succeeded
+            Returns: -1 if failed for whatever reason
+        """
+        try:
+            if self.sageGate.streamApp(appId, fsIP, fsPort) == -1:
+                return -1
+            else:
+                return 1
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return -1
+
+        
+    def authenticate(self, passwd):
+	if (self.sessionPassword == passwd):
+	   return 1
+	else:
+	   return -1	
+
+
+
+
+### sets up the parser for the command line options
+def get_commandline_options():
+    parser = optparse.OptionParser()
+
+    h = "if set, prints output to console, otherwise to sage_proxy.log"
+    parser.add_option("-v", "--verbose", action="store_true", help=h, dest="verbose", default=False)
+
+    h = "which machine is sage running on (default is localhost)"
+    parser.add_option("-s", "--server", dest="server", help=h, default="localhost")
+
+    h = "the port number where sage is accepting ui connections (default is 20001)"
+    parser.add_option("-p", "--port", help=h, type="int", dest="port", default=20001)
+
+    h = "specify the password for SAGE Web UI access (default is empty)"
+    parser.add_option("-x", "--pass", dest="passwd", help=h, default="")
+
+    return parser.parse_args()
+
+
+
+def main(argv):
+    global REDIRECT
+    
+    (options, args) = get_commandline_options()
+    REDIRECT = not options.verbose
+    port = options.port
+    host = options.server
+    passwd = options.passwd
+    
+    p = Proxy(host, port, passwd)
+
+    # always use the fsManager ui port + 3 for the xmlrpc port
+    global XMLRPC_PORT
+    XMLRPC_PORT = port+3
+    
+    server = ThreadedXMLRPCServer(("", XMLRPC_PORT), SimpleXMLRPCRequestHandler, False)
+    server.allow_reuse_address = True
+    server.register_instance(p)
+    server.register_introspection_functions()
+    server.serve_forever()
+	
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
Index: trunk/src/testing/bin/sageProxy/sageUIDataInfo.py
===================================================================
--- trunk/src/testing/bin/sageProxy/sageUIDataInfo.py	(revision 4)
+++ trunk/src/testing/bin/sageProxy/sageUIDataInfo.py	(revision 4)
@@ -0,0 +1,303 @@
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# python stuff
+import sys, string
+import os.path
+import os
+
+
+# my imports
+from SAGEApp import SAGEApp, SAGEAppInitial
+from sageDisplayInfo import sageDisplayInfo
+
+
+
+## Main class to store all the messages returned by SAGE
+class sageUIDataInfo:
+
+    #### constructor initializes member values       
+    def __init__(self):
+        self.hashApps = {}           # all the apps available for running??
+        self.hashAppStatusInfo = {}  # apps currently running
+        self.displayInfo = sageDisplayInfo()
+        self.newAppID = -1
+        
+    #### Set the sage status
+    def setSageStatus(self, appHash) :  
+
+        # loop through the available apps and create SAGEAppInitial objects for all of them
+        for appName, configs in appHash.iteritems():
+            hashSingleAppInfo = {}
+            self.hashApps[appName] = SAGEAppInitial(appName, configs)
+            
+
+    #----------------------------------------------------------------------
+
+
+##     ### Set the possible execution configurations for each app
+##     def setSageAppExecConfig(self, data):
+##         tokens = string.split( data, '\n', 1 )
+##         appName = tokens[0]
+##         data = tokens[1] #the rest
+##         configList = string.split( data, "config ")
+
+##         del configList[0]  #remove the first item in the list
+
+##         for config in configList:
+##             if appName in self.hashApps.keys():
+##                 (name, stringConfig) = string.split(config, ":", 1)
+##                 self.hashApps[appName].AddConfig(name, stringConfig)
+
+
+    #----------------------------------------------------------------------
+    
+    ### sets the display information for the display we are currently connected to
+    ### this data is received from the fsManager
+    def setSageDisplayInformation(self, data):
+        listTokens = string.split(data, '\n')
+        tileNumTokens = string.split(listTokens[0], ' ')
+        desktopTokens = string.split(listTokens[1], ' ')
+        tileConfTokens = string.split(listTokens[2], ' ')
+
+        self.displayInfo.setValues(int(tileNumTokens[0]), int(tileNumTokens[1]), int(tileNumTokens[2]),
+                                   int(desktopTokens[0]), int(desktopTokens[1]),
+                                   int(tileConfTokens[0]), int(tileConfTokens[1]))
+
+        return
+
+
+    #----------------------------------------------------------------------
+    
+
+    #### Get the new list of z values from SAGE and update local hashes
+    def setSageZValue(self, message):
+        tokens = string.split(message)
+        numZChanges = int(tokens[0])  #the first item that comes in is the number of z changes
+
+        # loop through all the tokens and update the z values of the apps
+        for i in range(numZChanges):
+            self.setZvalue( int(tokens[i*2+1]), int(tokens[i*2+2]) )
+
+            
+    #----------------------------------------------------------------------
+
+
+    ### returns True if the app is already on top, False otherwise
+    def isTopWindow(self, appId):
+        if self.getZvalue(appId) == 0:
+            return True   # meaning the app was already on top
+        else:
+            return False
+        
+        
+    #----------------------------------------------------------------------
+
+    
+    #### Set the SAGE app status
+    #### prints Invalid app ID if does not exists
+    def setSageAppInfo(self, stData):
+        listTokens = string.split(stData)
+
+        iAppID = int( listTokens[ 1 ] )
+        if iAppID in self.hashAppStatusInfo:
+            self.hashAppStatusInfo[ iAppID ].setAll( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), int(listTokens[7])) 
+        else:
+            self.hashAppStatusInfo[ iAppID ] = SAGEApp( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), int(listTokens[7]))
+
+
+            
+
+##     ### increase the z value of all the apps (because the new one will be on top)
+##     def updateZsAfterAdd(self, appId):
+##         for app in self.hashAppStatusInfo.itervalues():
+##             app.setZvalue(app.getZvalue() + 1)
+
+
+    #----------------------------------------------------------------------
+    
+    
+    ##### ShutDown the sage application
+    ##### prints invalid app ID if doesn't exist
+    def sageAppShutDown(self, stData):
+        listTokens = string.split(stData)
+        appId = int(listTokens[0])
+
+#        self.updateZsAfterRemove(appId) 
+
+        if appId in self.hashAppStatusInfo :
+            del self.hashAppStatusInfo[appId]
+
+
+##     ### decrease the z value of all the apps that were below the deleted one
+##     def updateZsAfterRemove(self, appId):
+##         deletedApp = self.hashAppStatusInfo[appId]
+##         for app in self.hashAppStatusInfo.itervalues():
+##             if app.getZvalue() > deletedApp.getZvalue() and app.getId() != deletedApp.getId():
+##                 app.setZvalue(app.getZvalue() - 1)
+
+    #----------------------------------------------------------------------
+
+    
+    #   Get the z value of the app
+    def getZvalue(self, appInstId):
+        if appInstId in self.hashAppStatusInfo:
+            appInfo = self.hashAppStatusInfo.get(appInstId)
+            return appInfo.getZvalue()
+        else:
+            #print("getZvalue: Invalid app instance ID")
+            return -1
+
+            
+    #----------------------------------------------------------------------
+
+
+    #   Set the Z value of the app
+    def setZvalue(self, appId, value):
+        if (appId in self.hashAppStatusInfo):
+            self.hashAppStatusInfo[appId].setZvalue(value)
+        else:
+            print ('setZvalue: Invalid app instance ID')
+        return -1
+
+
+    #----------------------------------------------------------------------
+
+
+    def getSageDisplayInformation(self) :
+        return self.displayInfo.getValues()
+
+
+    #----------------------------------------------------------------------
+    
+    
+    ### Get the sage app Info
+    def getAppInfo(self, appId):
+        if appId in self.hashAppStatusInfo:
+            return {str(appId): self.hashAppStatusInfo[appId].getAll()}
+        else:
+            return -1
+
+
+    #----------------------------------------------------------------------
+
+
+    def getAllAppInfo(self):
+        appStatus = {}  #key = appId, value = list of app params
+        for appId, sageApp in self.hashAppStatusInfo.iteritems():
+            appStatus[str(appId)] = sageApp.getAll()
+        return appStatus
+    
+
+    #----------------------------------------------------------------------
+
+
+    # returns the SAGEApp associated with the given appInstId
+    def getSAGEApp(self, appId):
+        return self.hashAppStatusInfo[appId]
+
+    
+    #----------------------------------------------------------------------
+
+
+    # returns true if the app with a specified appId is currently running
+    def appExists(self, appId):
+        return appId in self.hashAppStatusInfo
+    
+
+    #----------------------------------------------------------------------
+ 
+
+    ### Get all app IDs currently running on sage
+    def getAllAppIDs(self) :
+        return self.hashAppStatusInfo.keys()
+
+   
+    #----------------------------------------------------------------------
+
+    ### Get the new APP ID
+    def getNewAppID(self) :
+	return self.newAppID
+
+
+    #----------------------------------------------------------------------
+ 
+     ### Returns a list of all currently running apps
+    def getAllApps( self ):
+        return self.hashAppStatusInfo
+    
+
+    #----------------------------------------------------------------------
+    
+
+    ### Get list of application names that are available for running
+    def getAvailableAppNames( self ):
+        return self.hashApps.keys()
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### Returns a list of all the available apps
+    def getAvailableApps( self ):
+        return self.hashApps
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### Returns a list of z values in the following format:
+    ### [numChanges, appId, zValue, appId, zValue...]
+    def getZvalues( self ):
+        apps = self.getAllApps()
+        zValues = []  #this will hold the return list of z values
+        zValues.append(len(apps))
+        for app in apps.itervalues():
+            zValues.append(app.getId())
+            zValues.append(app.getZvalue())
+             
+        return zValues
+
+
+
+
Index: trunk/src/testing/bin/sage.cmd
===================================================================
--- trunk/src/testing/bin/sage.cmd	(revision 4)
+++ trunk/src/testing/bin/sage.cmd	(revision 4)
@@ -0,0 +1,1 @@
+sageLauncher.py
Index: trunk/src/testing/bin/sagePath.py
===================================================================
--- trunk/src/testing/bin/sagePath.py	(revision 4)
+++ trunk/src/testing/bin/sagePath.py	(revision 4)
@@ -0,0 +1,106 @@
+############################################################################
+#
+# SAGE LAUNCHER - A GUI for launching SAGE and all related components
+#
+# Copyright (C) 2010 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+import os.path, os, sys
+import traceback as tb
+
+opj = os.path.join
+
+
+CONFIG_DIR = ".sageConfig"
+USER_DIR = os.path.expanduser("~")
+USER_CONFIG_DIR = opj( USER_DIR, CONFIG_DIR )
+SAGE_DIR = os.path.realpath(os.environ["SAGE_DIRECTORY"])    # where sage is located
+DEFAULT_CONFIG_DIR = opj( SAGE_DIR, CONFIG_DIR.lstrip(".") )
+
+
+# first make the user config dir if it doesnt exist
+if not os.path.isdir(USER_CONFIG_DIR):
+    os.makedirs(USER_CONFIG_DIR)
+    os.makedirs( opj(USER_CONFIG_DIR, "applications", "pid") )
+
+
+# searches two paths: ~/.sageConfig and $SAGE_DIRECTORY/sageConfig
+def getPath(*args):
+    fileName = ""
+    for a in args:
+        fileName = opj(fileName, a)
+
+    userPath = opj( USER_CONFIG_DIR, fileName )
+    defaultPath = opj( DEFAULT_CONFIG_DIR, fileName )
+    currentPath = opj( os.getcwd(), args[len(args)-1])  # last argument
+
+    if os.path.isfile( currentPath ):
+        return currentPath
+    elif os.path.isfile( userPath ):
+        return userPath
+    else:
+        return defaultPath
+
+
+# to get a path to a file in the user's home config directory
+def getUserPath(*args):
+    p = USER_CONFIG_DIR
+    for a in args:
+        p = opj(p, a)
+
+    # make the directory... if it doesnt exist
+    # this will make the directory even if a file is passed in with some directories before it
+    if not os.path.exists(p):
+        try:
+            d, ext = os.path.splitext(p)
+            if ext == "":   # it's a directory
+                d = os.path.splitext(p)[0]
+            else:           # it's a file
+                d = os.path.dirname(p)                
+            if not os.path.exists(d): os.makedirs(d)
+            
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+    return p
+    
+
+
+# to get a path to a file in the default config directory
+def getDefaultPath(*args):
+    p = DEFAULT_CONFIG_DIR
+    for a in args:
+        p = opj(p, a)
+    return p
Index: trunk/src/testing/bin/KILL_ALL
===================================================================
--- trunk/src/testing/bin/KILL_ALL	(revision 4)
+++ trunk/src/testing/bin/KILL_ALL	(revision 4)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+for node in `cat tileNodes.list`
+do
+	ssh -fx $node "killall -9  fsManager sageDisplayManager JuxtaView JuxtaSCUI bplay-noglut init_magic_frames VNCViewer render atlantis atlantis-mpi checker" 
+done
Index: trunk/src/testing/bin/sageLauncher.py
===================================================================
--- trunk/src/testing/bin/sageLauncher.py	(revision 4)
+++ trunk/src/testing/bin/sageLauncher.py	(revision 4)
@@ -0,0 +1,4641 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# SAGE LAUNCHER - A GUI for launching SAGE and all related components
+#
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import wx, cPickle, os, sys, os.path, stat, string, copy, time, cStringIO, zlib, pickle
+import wx.lib.filebrowsebutton as fb
+import wx.lib.buttons as buttons
+import wx.lib.hyperlink as hl
+import wx.lib.scrolledpanel as scrolled
+from wx import BitmapFromImage, ImageFromStream
+import traceback as tb
+import subprocess as sp
+from threading import Thread
+
+
+# shortcut
+opj = os.path.join
+from sagePath import getUserPath, SAGE_DIR, getPath, getDefaultPath
+
+
+# --------------------------------------------------------
+#
+#                   GLOBALS   
+#
+# --------------------------------------------------------
+
+# component types and official names
+APP_LAUNCHER = "Application Launcher"
+FILE_SERVER  = "File Server"
+SAGE_PROXY   = "SAGE Proxy"
+SAGE_UI      = "SAGE UI"
+SAGE         = "SAGE"     
+componentNames = [SAGE, APP_LAUNCHER, SAGE_UI, FILE_SERVER, SAGE_PROXY]
+
+# this is where all the information about the components is stored
+components = {}   # key=componentType, value=Component()
+
+# tileConfig file (structure of the cluster driving the display)
+tileConfig = None
+
+MAX_TEXT_LEN = 64000     # max characters in the output text ctrl
+PREFS_FILE = getUserPath("sageLauncherSettings.pickle")   # store the settings in a pickle file
+PY_EXEC = sys.executable    # platform dependent python executable
+
+# quit if the SAGE_DIRECTORY env var is not set
+if not "SAGE_DIRECTORY" in os.environ:
+    print "SAGE_DIRECTORY environment variable not set."
+    print "Please first set the SAGE_DIRECTORY environment variable to your sage directory."
+    sys.exit(0)
+
+# default frame background color on windows (screwed up otherwise)
+global colour   
+
+
+
+
+
+# --------------------------------------------------------
+#
+#               CONVENIENCE FUNCTIONS
+#
+# --------------------------------------------------------
+
+
+def makeBoldFont(widget):
+    f = widget.GetFont()
+    f.SetWeight(wx.BOLD)
+    widget.SetFont(f)
+
+def makeBiggerFont(widget):
+    f = widget.GetFont()
+    ps = f.GetPointSize()
+    f.SetPointSize(ps + ps*0.2)  # make it 20% bigger
+    widget.SetFont(f)
+
+def makeSmallerFont(widget):
+    f = widget.GetFont()
+    ps = f.GetPointSize()
+    f.SetPointSize(ps - ps*0.2)  # make it 20% smaller
+    widget.SetFont(f)
+
+def makeBiggerBoldFont(widget):
+    makeBoldFont(widget)
+    makeBiggerFont(widget)    
+
+def isWin():
+    return "__WXMSW__" in wx.PlatformInfo
+
+
+
+# if the loadSettings fails for some reason (other than first execution),
+# do not save (since you will overwrite the previous good settings)
+DO_SAVE = True   
+def saveSettings():
+    if DO_SAVE:
+        # first assemble a dictionary of all the settings and then store it
+        settings = {}
+        for componentType, comp in components.iteritems():
+            settings[componentType] = comp.settings
+
+        # now try and save the dictionary
+        try:
+            f = open(PREFS_FILE, "wb")
+            cPickle.Pickler(f, cPickle.HIGHEST_PROTOCOL).dump(settings)
+            f.close()
+        except:
+            print " ***** Error occured while saving settings:"
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+                        
+
+
+def loadSettings():
+    """ try loading the settings and if it fails just return the default
+        if it succeeds, update the default with the saved settings """
+
+    # default settings
+    settings = {}
+    settings[APP_LAUNCHER] = AppLauncherSettings(APP_LAUNCHER)
+    settings[FILE_SERVER] = FileServerSettings(FILE_SERVER)
+    settings[SAGE_PROXY] = SageProxySettings(SAGE_PROXY)
+    settings[SAGE_UI] = SageUISettings(SAGE_UI)
+    settings[SAGE] = SageSettings(SAGE)
+
+    # try loading the saved ones
+    try:
+        if os.path.isfile(PREFS_FILE):
+            f = open(PREFS_FILE, "rb")
+            (d) = cPickle.Unpickler(f).load()
+            f.close()
+            settings.update(d)
+    except:
+        print " ***** Error occured while loading saved settings and the changes you make will not be saved after you quit sageLauncher:"
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        global DO_SAVE
+        DO_SAVE = False
+        
+    return settings
+
+
+
+
+def getTileConfig():
+    """ returns the full path of the currently used tile
+        config file as specifed in the fsManager.conf """
+    
+    f = open( getPath("fsManager.conf"), "r")
+    for line in f:
+        line = line.strip()
+        if line.startswith('tileConfiguration'):
+            config = line.split()[1].strip()
+    f.close()
+    return getPath(config)
+
+
+
+
+# --------------------------------------------------------
+#
+#                      COMPONENTS
+#
+# --------------------------------------------------------
+
+
+class Component:
+    """ this is the class that contains all the information
+        about each of the components:
+         - settings, output field, process object
+        There is one of these for each component and they are
+        all stored in a global dictionary
+    """
+    def __init__(self, componentType):
+        self.componentType = componentType
+        self.settings = None
+        self.output = None
+        self.process = None
+
+
+
+
+
+# --------------------------------------------------------
+#
+#             COMPONENT SETTINGS
+#
+# --------------------------------------------------------
+
+# these are the objects that store all the information about
+# a component and will be saved in a file
+# they define how things are run and other specific settings
+
+
+class ComponentSettings:
+    """ this is the base class for all the settings """
+    def __init__(self, t):
+        self.inBG = False
+        self.doRun = True
+        self.cmd = ""
+        self.componentType = t
+        self.pid = -1  # pid from the started process
+
+
+    def getStartCommand(self):
+        """ this must be implemented by the subclasses
+            it should return the final command that is used to run the component
+        """
+        raise NotImplemented
+
+
+    def getCwd(self):
+        """ this must be implemented by the subclasses
+            returns the current working directory
+        """
+        raise NotImplemented
+        
+
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+
+
+
+
+class SageSettings(ComponentSettings):
+    def __init__(self, componentType):
+        ComponentSettings.__init__(self, componentType)
+        self.doRun = True
+        self.onStart = "xhost +local:\npython ../dim/dim.py\npython ../dim/hwcapture/localPointer.py localhost"  # a string of commands to be executed after shutdown (split by \n)
+        self.onStop = "fuser -k 19010/tcp"
+
+        # things to kill on each node
+        self.toKill = "fsManager sageDisplayManager sageAudioManager svc imageviewer mplayer bplay bplay-noglut VNCViewer render atlantis atlantis-mpi checker pdfviewer sagepdf"
+        
+
+    def getStartCommand(self):
+        """ commmand used to run this component """
+        return ["fsManager"]
+
+
+    def getCwd(self):
+        """ returns the current working directory """
+        return opj(SAGE_DIR, "bin")
+
+
+    def getKillCmd(self):
+        """ returns a list of kill commands to run for stopping sage
+            On Windows just kill the stuff on the local machine for now
+        """
+        cmds = []   # this will be returned as a list of lists
+        killString = self.toKill   # processes to be killed on each node
+
+        # windows
+        if isWin():
+            # first append .exe to the processes
+            killList = [proc + ".exe" for proc in killString.split()]
+            
+            # generate the commands to kill each process
+            c = ["taskkill", "/F"]
+            for proc in killList:
+                c.extend(["/IM", proc])
+            cmds.append(c)
+            
+        # Mac + Linux
+        else:           
+            # get the ip addresses of the nodes of the cluster
+            # + the master node
+            tileConfig.readConfigFile(getTileConfig())
+            IPs = tileConfig.getAllIPs()  
+            IPs.append("127.0.0.1")
+
+            for node in IPs:
+                c = []
+                k = "/usr/bin/killall -9 %s" % killString
+                c.extend( ["/usr/bin/ssh", "-fx", node, k] ) 
+                cmds.append(c)
+
+        return cmds
+    
+        
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+    
+
+
+class AppLauncherSettings(ComponentSettings):
+    def __init__(self, componentType):
+        ComponentSettings.__init__(self, componentType)
+        self.doReport = False
+        self.doRun = True
+        self.server = "sage.sl.startap.net"
+        self.port = 19010
+
+
+    def getAppConfigFilename(self):
+        return getPath("applications", "applications.conf")
+
+    def getStartCommand(self):
+        """ commmand used to run this component """
+        cmd = [PY_EXEC, "-u", opj(self.getCwd(), "appLauncher.py"), "-v", "-p", str(self.port)]
+
+        # report to sage server?
+        if self.doReport: cmd.extend( ["-s", self.server] )
+        else: rep = cmd.append("-n")
+
+        # run in background?
+        if self.inBG and not isWin(): cmd.append("&")
+        
+        return cmd
+
+
+    def getKillCmd(self):
+        """ returns the command to kill the appLauncher """
+        return [PY_EXEC, "KILL_LAUNCHER.py", str(self.port)]
+        
+        
+    def getCwd(self):
+        """ returns the current working directory """
+        return opj(SAGE_DIR, "bin", "appLauncher")
+
+        
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+
+
+
+class FileServerSettings(ComponentSettings):
+    def __init__(self, componentType):
+        ComponentSettings.__init__(self, componentType)
+
+
+    def getConfigFilename(self):
+        return getPath("fileServer", "fileServer.conf")
+
+
+    def getStartCommand(self):
+        """ commmand used to run this component """
+        if self.inBG and not isWin(): bg = "&"
+        else: bg = ""
+        return [PY_EXEC, "-u", opj(self.getCwd(), "fileServer.py"), "-v", bg]
+
+
+    def getCwd(self):
+        """ returns the current working directory """
+        return opj(SAGE_DIR, "bin", "fileServer")
+
+        
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+
+
+
+
+class SageProxySettings(ComponentSettings):
+    def __init__(self, componentType):
+        ComponentSettings.__init__(self, componentType)
+        self.host = 'localhost'
+        self.port = 20001
+        self.password = "pass"
+
+
+    def getStartCommand(self):
+        """ commmand used to run this component """
+        return [PY_EXEC, "-u", opj(self.getCwd(), "sageProxy.py"),
+                "-s", self.host, "-p", str(self.port), "-x", self.password, "-v"]
+
+
+    def getCwd(self):
+        """ returns the current working directory """
+        return opj(SAGE_DIR, "bin", "sageProxy")
+
+        
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+
+
+
+class SageUISettings(ComponentSettings):
+    def __init__(self, componentType):
+        ComponentSettings.__init__(self, componentType)
+        self.host = 'sage.sl.startap.net'
+        self.port = 15558
+        self.doRun = True
+        self.autologinMachine = ""
+        self.loadState = ""
+
+
+    def getStartCommand(self):
+        """ commmand used to run this component """
+        cmd = [PY_EXEC, "-u", opj(self.getCwd(),"sageui.py"), "-v", "-s", self.host, "-p", str(self.port), "-t"]
+        if self.autologinMachine != "":
+            cmd.extend( ["-a", self.autologinMachine] )
+        if self.loadState != "":
+            cmd.extend( ["-o", self.loadState] )
+        return cmd
+
+
+    def getCwd(self):
+        """ returns the current working directory """
+        return opj(SAGE_DIR, "ui")
+
+
+    def __getinitargs__(self):
+        """ for pickling to work properly if we add some
+            more settings to this class at a later time """
+        return (self.componentType,)
+
+    
+
+
+
+
+
+# --------------------------------------------------------
+#
+#                 UI STUFF 
+#
+# --------------------------------------------------------
+
+
+###
+### these are the specific frames for each component that let's you configure the component
+###
+
+
+class ComponentFrame(wx.Frame):
+    def __init__(self, parent, componentType):
+        s = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL
+        wx.Frame.__init__(self, parent, wx.ID_ANY, componentType+" Configuration", style=s)
+        if isWin(): self.SetBackgroundColour(colour)
+        self.settings = components[componentType].settings
+        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.SetIcon(getSageIcon())
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+
+    def MakeWidgets(self):
+        okBtn = wx.Button(self, wx.ID_ANY, "OK")
+        okBtn.Bind(wx.EVT_BUTTON, self.DoClose)
+        self.mainSizer.Add(okBtn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 15)
+        self.SetSizerAndFit(self.mainSizer)
+
+
+    def DoClose(self, evt=None):
+        self.Close(True)
+        
+
+    def OnClose(self, evt):
+        """ save everything here but let the subclasses do that
+        since it's specific for each... therefore it must be implemented """
+        raise NotImplemented
+
+
+        
+
+
+class AppLauncherFrame(ComponentFrame):
+    def __init__(self, parent):
+        ComponentFrame.__init__(self, parent, APP_LAUNCHER)
+        self.configs = AppConfigurations(self.settings.getAppConfigFilename())
+        self.currentConfig = None   #current config object being edited
+        self.MakeWidgets()
+        self.Show()
+
+
+    def MakeWidgets(self):
+        self.run = wx.CheckBox(self, wx.ID_ANY, "Run in background")
+        self.run.SetToolTipString(HELP_INBG)
+        self.run.SetValue(self.settings.inBG)
+
+        self.mainSizer.Add(self.MakeConnectionBox(), 0, wx.EXPAND | wx.ALL, 10)
+        self.mainSizer.Add(self.MakeAppConfigBox(), 0, wx.EXPAND | wx.ALL, 10)
+        self.mainSizer.Add(self.run, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.ALL, 5)
+        ComponentFrame.MakeWidgets(self)
+
+
+    def MakeConnectionBox(self):
+        # the box
+        box = wx.StaticBox(self, wx.ID_ANY, "Public access:")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.VERTICAL )
+
+        # widgets
+        hostLabel = wx.StaticText(self, wx.ID_ANY, "Hostname / IP:")
+        self.hostText = wx.TextCtrl(self, wx.ID_ANY, self.settings.server)
+        self.hostText.SetMinSize((150, -1))
+        self.hostText.SetToolTipString(HELP_AL_PUBLIC_HOST)
+
+        #portLabel = wx.StaticText(self, wx.ID_ANY, "Port:")
+        #self.portText = wx.TextCtrl(self, wx.ID_ANY, str(self.settings.port))
+
+        self.reportCheck = wx.CheckBox(self, wx.ID_ANY, "Allow public access?")
+        self.reportCheck.SetToolTipString(HELP_AL_PUBLIC)
+        self.reportCheck.SetValue(self.settings.doReport)
+        self.reportCheck.Bind(wx.EVT_CHECKBOX, self.OnPublicCheck)
+        self.OnPublicCheck(None)
+        
+        # add widgets to the boxSizer
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer.Add(hostLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        hSizer.Add(self.hostText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+        hSizer.Add((10,10))
+        #hSizer.Add(portLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        #hSizer.Add(self.portText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+
+        boxSizer.Add(self.reportCheck, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(hSizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        
+        return boxSizer
+
+
+    def MakeAppConfigBox(self):
+        # the box
+        box = wx.StaticBox(self, wx.ID_ANY, "SAGE Applications:")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.HORIZONTAL )
+
+        # apps label and list
+        appsLabel = wx.StaticText(self, wx.ID_ANY, "Applications:")
+        makeBoldFont(appsLabel)
+        self.appsList = wx.ListBox(self, wx.ID_ANY, choices=self.configs.getAppList())
+        self.appsList.Bind(wx.EVT_LISTBOX, self.OnAppList)
+        self.appsList.SetToolTipString(HELP_AL_APPS)
+        addBtn = wx.Button(self, wx.ID_ANY, "Add", style=wx.BU_EXACTFIT)
+        addBtn.Bind(wx.EVT_BUTTON, self.OnAppAdd)
+        delBtn = wx.Button(self, wx.ID_ANY, "Delete", style=wx.BU_EXACTFIT)
+        delBtn.Bind(wx.EVT_BUTTON, self.OnAppDel)
+
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(addBtn, 1, wx.ALIGN_CENTER | wx.ALL, 4)
+        btnSizer.Add(delBtn, 1, wx.ALIGN_CENTER | wx.RIGHT | wx.TOP | wx.BOTTOM, 4)
+                     
+        appsSizer = wx.BoxSizer(wx.VERTICAL)
+        appsSizer.Add(appsLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        appsSizer.Add(self.appsList, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        appsSizer.Add(btnSizer, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 1)
+              
+        # add widgets to the boxSizer
+        self.confSizer = self.MakeConfigBox()
+        boxSizer.Add(appsSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.VERTICAL), 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.confSizer, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+
+        return boxSizer
+
+
+    def MakeConfigBox(self):
+        self.configSizers = {}
+        
+        # configuration list
+        configLabel = wx.StaticText(self, wx.ID_ANY, "Configurations:")
+        makeBoldFont(configLabel)
+        self.configCombo = wx.ComboBox(self, wx.ID_ANY, choices=[])
+        self.configCombo.SetMinSize((180, -1))
+        self.configCombo.Bind(wx.EVT_COMBOBOX, self.OnConfigCombo)
+        self.configCombo.SetToolTipString(HELP_AL_CFG)
+        newBtn = wx.Button(self, wx.ID_ANY, " Add ", style=wx.BU_EXACTFIT)
+        newBtn.Bind(wx.EVT_BUTTON, self.OnAddConfig)
+        delBtn = wx.Button(self, wx.ID_ANY, " Delete ", style=wx.BU_EXACTFIT)
+        delBtn.Bind(wx.EVT_BUTTON, self.OnDelConfig)
+        copyBtn = wx.Button(self, wx.ID_ANY, " Make Copy ", style=wx.BU_EXACTFIT)
+        copyBtn.Bind(wx.EVT_BUTTON, self.OnCopyConfig)
+        copyBtn.SetToolTipString(HELP_AL_CFG_COPY)
+
+        self.comboSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.comboSizer.Add(configLabel, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+        self.comboSizer.Add(self.configCombo, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+        self.comboSizer.Add(newBtn, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+        self.comboSizer.Add(delBtn, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+        self.comboSizer.Add(copyBtn, 0, wx.ALIGN_CENTER | wx.ALL, 5)
+
+        # add all to the main config sizer
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        vSizer.Add(self.comboSizer, 1, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP | wx.ALL, 9)
+        l = wx.StaticLine(self, wx.ID_ANY);  l.Disable()
+        vSizer.Add(l, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+
+        # static app
+        self.staticCheck = wx.CheckBox(self, wx.ID_ANY, "Static application")#, style=wx.ALIGN_RIGHT)
+        self.staticCheck.SetValue(True)
+        self.staticCheck.Bind(wx.EVT_KILL_FOCUS, self.OnStaticFocus)
+        self.staticCheck.SetToolTipString(HELP_AL_CFG_STATIC)
+        vSizer.Add(self.staticCheck, 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 10)
+
+        # execution
+        execFoldBar = FoldBar(self, 101, "Execution", self.OnFoldBtn)
+        self.configSizers[101] = self.MakeExecutionSection()
+        vSizer.Add(execFoldBar, 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 5)
+        vSizer.Add(self.configSizers[101], 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM | wx.RIGHT, 15)
+        vSizer.Show(self.configSizers[101], False, True)
+        
+        # size and pos
+        sizePosFoldBar = FoldBar(self, 100, "Size and position", self.OnFoldBtn)
+        self.configSizers[100] = self.MakeSizePosSection()
+        vSizer.Add(sizePosFoldBar, 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 5)
+        vSizer.Add(self.configSizers[100], 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM | wx.RIGHT, 15)
+        vSizer.Show(self.configSizers[100], False, True)
+        
+        # parallel application stuff
+        parallelFoldBar = FoldBar(self, 102, "Parallel Applications", self.OnFoldBtn)
+        self.configSizers[102] = self.MakeParallelSection()
+        vSizer.Add(parallelFoldBar, 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 5)
+        vSizer.Add(self.configSizers[102], 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM | wx.RIGHT, 15)
+        vSizer.Show(self.configSizers[102], False, True)
+        
+        # advanced stuff...
+        advFoldBar = FoldBar(self, 103, "Advanced", self.OnFoldBtn)
+        self.configSizers[103] = self.MakeAdvancedSection()
+        vSizer.Add(advFoldBar, 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 5)
+        vSizer.Add(self.configSizers[103], 0, wx.EXPAND | wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM | wx.RIGHT, 15)
+        vSizer.Show(self.configSizers[103], False, True)
+        
+        return vSizer
+
+
+    def MakeParallelSection(self):
+        # parallel checkbox
+        self.parallelCheck = wx.CheckBox(self, wx.ID_ANY, "This is a parallel application", style=wx.ALIGN_RIGHT)
+        self.parallelCheck.Bind(wx.EVT_CHECKBOX, self.OnParallelCheck)
+        
+        # number of nodes
+        nodeNumLabel = wx.StaticText(self, wx.ID_ANY, "Number of nodes:")
+        self.nodeNumSpin = wx.SpinCtrl(self, wx.ID_ANY, min=1, initial=1)
+        self.nodeNumSpin.SetToolTipString(HELP_AL_CFG_NUM_NODES)
+        self.nodeNumSpin.Disable()
+        self.nodeNumSpin.Bind(wx.EVT_KILL_FOCUS, self.OnNodeNumFocus)
+
+        # master ip
+        masterIPLabel = wx.StaticText(self, wx.ID_ANY, "Master node:")
+        self.masterIPText = wx.TextCtrl(self, wx.ID_ANY)
+        self.masterIPText.SetToolTipString(HELP_AL_CFG_MASTER)
+        self.masterIPText.SetMinSize((120, -1))
+        self.masterIPText.Disable()
+        self.masterIPText.Bind(wx.EVT_KILL_FOCUS, self.OnMasterIPFocus)
+
+        # sizer stuff
+        pSizer = wx.FlexGridSizer(2,2,5,5)
+        pSizer.Add(nodeNumLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, 5)
+        pSizer.Add(self.nodeNumSpin, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT, 5)
+        pSizer.Add(masterIPLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, 5)
+        pSizer.Add(self.masterIPText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT, 5)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self.parallelCheck, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
+        sizer.Add(pSizer, 0, wx.ALIGN_LEFT | wx.ALL, 5)
+
+        return sizer
+    
+
+    def MakeExecutionSection(self):
+        appLabel = wx.StaticText(self, wx.ID_ANY, "Run application")
+        appLabel.SetMinSize((100, -1))
+        self.appText = wx.TextCtrl(self, wx.ID_ANY)
+        self.appText.SetToolTipString(HELP_AL_CFG_APP)
+        self.appText.Bind(wx.EVT_KILL_FOCUS, self.OnAppTextFocus)
+
+        dirLabel = wx.StaticText(self, wx.ID_ANY, "from directory")
+        dirLabel.SetMinSize((100, -1))
+        self.dirText = wx.TextCtrl(self, wx.ID_ANY)
+        self.dirText.SetToolTipString(HELP_AL_CFG_DIR)
+        self.dirText.Bind(wx.EVT_KILL_FOCUS, self.OnDirTextFocus)
+            
+        machineLabel = wx.StaticText(self, wx.ID_ANY, "on host")
+        self.machineText = wx.TextCtrl(self, wx.ID_ANY)
+        self.machineText.SetToolTipString(HELP_AL_CFG_MACHINE)
+        self.machineText.SetMinSize((140, -1))
+        self.machineText.Bind(wx.EVT_KILL_FOCUS, self.OnMachineTextFocus)
+        
+        sizer = wx.FlexGridSizer(3,2, 3,10)
+        sizer.Add(appLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.appText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        sizer.Add(dirLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.dirText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        sizer.Add(machineLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.machineText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        sizer.AddGrowableCol(1)
+        
+        return sizer
+
+
+    def MakeSizePosSection(self):
+        # sage window size
+        szLabel = wx.StaticText(self, wx.ID_ANY, "Initial SAGE window size")
+        szLabel.SetMinSize((180, -1))
+        wLabel = wx.StaticText(self, wx.ID_ANY, "W")
+        self.wText = wx.TextCtrl(self, wx.ID_ANY, "1000")
+        self.wText.Bind(wx.EVT_KILL_FOCUS, self.OnSizeTextFocus)
+        self.wText.SetToolTipString(HELP_AL_CFG_SIZE)
+        hLabel = wx.StaticText(self, wx.ID_ANY, "H")
+        self.hText = wx.TextCtrl(self, wx.ID_ANY, "1000")
+        self.hText.SetToolTipString(HELP_AL_CFG_SIZE)
+        self.hText.Bind(wx.EVT_KILL_FOCUS, self.OnSizeTextFocus)
+        
+        # sage window position
+        posLabel = wx.StaticText(self, wx.ID_ANY, "Initial SAGE window position")
+        posLabel.SetMinSize((180, -1))
+        xLabel = wx.StaticText(self, wx.ID_ANY, "X")
+        self.xText = wx.TextCtrl(self, wx.ID_ANY, "100")
+        self.xText.Bind(wx.EVT_KILL_FOCUS, self.OnPosTextFocus)
+        yLabel = wx.StaticText(self, wx.ID_ANY, "Y")
+        self.yText = wx.TextCtrl(self, wx.ID_ANY, "100")
+        self.yText.Bind(wx.EVT_KILL_FOCUS, self.OnPosTextFocus)
+
+        # add to sizer
+        sizer = wx.FlexGridSizer(2,5, 5,0)
+        sizer.Add(szLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(wLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(self.wText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(hLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(self.hText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+
+        sizer.Add(posLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(xLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(self.xText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(yLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        sizer.Add(self.yText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, border=5)
+        
+        return sizer
+
+
+    def MakeAdvancedSection(self):
+        pbLabel = wx.StaticText(self, wx.ID_ANY, "Pixel block size")
+        pbLabel.SetMinSize((130, -1))
+        self.pbSpin = wx.SpinCtrl(self, wx.ID_ANY, min=1, max=512, initial=64)
+        self.pbSpin.Bind(wx.EVT_KILL_FOCUS, self.OnPBSpinFocus)
+        self.pbSpin.SetToolTipString(HELP_AL_CFG_BP)
+
+        #protoLabel = wx.StaticText(self, wx.ID_ANY, "Streaming protocol")
+        #protoLabel.SetMinSize((130, -1))
+        #self.protoCombo = wx.ComboBox(self, wx.ID_ANY, choices=["TCP"])
+
+        bridgeIPLabel = wx.StaticText(self, wx.ID_ANY, "SAGE Bridge host")
+        bridgeIPLabel.SetMinSize((130, -1))
+        self.bridgeIPText = wx.TextCtrl(self, wx.ID_ANY)
+        self.bridgeIPText.SetMinSize((150, -1))
+        self.bridgeIPText.Bind(wx.EVT_KILL_FOCUS, self.OnBridgeIPTextFocus)
+        self.bridgeIPText.SetToolTipString(HELP_AL_CFG_BHOST)
+
+        bridgePortLabel = wx.StaticText(self, wx.ID_ANY, "SAGE Bridge port")
+        bridgePortLabel.SetMinSize((130, -1))
+        self.bridgePortText = wx.TextCtrl(self, wx.ID_ANY)
+        self.bridgePortText.SetMinSize((150, -1))
+        self.bridgePortText.Bind(wx.EVT_KILL_FOCUS, self.OnBridgePortTextFocus)
+        self.bridgePortText.SetToolTipString(HELP_AL_CFG_BPORT)
+        
+        sizer = wx.FlexGridSizer(3,2, 3,10)
+        #sizer.Add(protoLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        #sizer.Add(self.protoCombo, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(pbLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.pbSpin, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(bridgeIPLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.bridgeIPText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        sizer.Add(bridgePortLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        sizer.Add(self.bridgePortText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        sizer.AddGrowableCol(1)
+        
+        return sizer
+
+
+    def OnFoldBtn(self, sectionId, collapse):
+        self.confSizer.Show(self.configSizers[sectionId], not collapse, True)
+        self.Fit()
+        
+
+    def OnParallelCheck(self, evt):
+        self.nodeNumSpin.Enable( self.parallelCheck.IsChecked() )
+        self.masterIPText.Enable( self.parallelCheck.IsChecked() )
+        if not self.parallelCheck.IsChecked():
+            self.nodeNumSpin.SetValue(1)
+            self.currentConfig.setNodeNum(1)
+
+
+    def OnAddConfig(self, evt):
+        """ add a new configuration for the currently selected app """
+
+        # an app must be selected first
+        appName = self.appsList.GetStringSelection()
+        if appName == "":
+            wx.MessageBox("Please select an application first", "Error", parent=self)
+            return
+        app = self.configs.getApp(appName)
+
+        # get the config name, do nothing if cancel pressed
+        configName = wx.GetTextFromUser("Enter new configuration name", "Config Name", parent=self)
+        if configName == "":  return
+        if configName in app.getAllConfigNames():
+            wx.MessageBox("Configuration with that name already exists", "Error", parent=self)
+            return
+
+        # add the new config and clear the config fields
+        conf = OneConfig(configName, appName)
+        app.addConfig(conf)
+        self.ClearConfig()
+        self.currentConfig = conf
+        self.configCombo.Append(configName)
+        self.configCombo.SetStringSelection(configName)
+
+
+    def OnDelConfig(self, evt):
+        # an app must be selected first
+        appName = self.appsList.GetStringSelection()
+        if appName == "":
+            wx.MessageBox("Please select an application first", "Error", parent=self)
+            return
+        app = self.configs.getApp(appName)
+
+        # get the config name, do nothing if cancel pressed
+        configName = self.configCombo.GetValue()
+        if configName == "":  return
+
+        # there must be at least one config per app
+        if len(app.getAllConfigNames()) < 2:
+            wx.MessageBox("Cannot delete the last configuration. There must be at least one configuration per application.", "Cannot Delete", parent=self)
+            return
+
+        # add the new config and clear the config fields
+        app.delConfig(configName)
+        self.configCombo.Delete(self.configCombo.FindString(configName))
+        self.configCombo.SetValue("")
+        self.ClearConfig()
+        self.currentConfig = None
+
+
+    def OnCopyConfig(self, evt):
+        # an app must be selected first
+        appName = self.appsList.GetStringSelection()
+        if appName == "":
+            wx.MessageBox("Please select an application first", "Error", parent=self)
+            return
+        app = self.configs.getApp(appName)
+
+        # get the config name, do nothing if cancel pressed
+        configName = self.configCombo.GetValue()
+        if configName == "":  return
+
+        # get the new config name, do nothing if cancel pressed
+        newConfigName = wx.GetTextFromUser("Enter new configuration name", "Config Name", parent=self)
+        if newConfigName == "":  return
+        if newConfigName in app.getAllConfigNames():
+            wx.MessageBox("Configuration with that name already exists", "Error", parent=self)
+            return
+
+        # copy the old config, change its name and add it to the app
+        conf = copy.deepcopy( app.getConfig(configName) )
+        conf.setName(newConfigName)
+        app.addConfig(conf)
+
+        # select the new config
+        self.configCombo.Append(newConfigName)
+        self.configCombo.SetStringSelection(newConfigName)
+        self.__SetConfig(conf)
+        
+    
+    def OnAppList(self, evt):
+        """ refill configCombo, select the first one and fill the fields for it"""
+        a = evt.GetString()
+        if not a: return
+        self.configCombo.Clear()
+        for c in self.configs.getApp(a).getAllConfigNames():
+            self.configCombo.Append(c)
+        self.configCombo.SetSelection(0)
+        conf = self.configs.getConfig(a, self.configCombo.GetString(0))
+        self.__SetConfig(conf)
+
+
+    def OnConfigCombo(self, evt):
+        configName = self.configCombo.GetValue()
+        appName = self.appsList.GetStringSelection()
+        c = self.configs.getConfig(appName, configName)
+        self.__SetConfig(c)
+
+
+    def __SetConfig(self, conf):
+        """ fill all the widgets with correct values for this configuration """
+        self.currentConfig = conf
+        
+        self.staticCheck.SetValue( conf.getStaticApp() )
+
+        # execution
+        self.dirText.SetValue( conf.getBinDir() )
+        self.machineText.SetValue( conf.getTargetMachine() )
+        self.appText.SetValue( conf.getCommand() )
+
+        # size and pos
+        self.wText.SetValue( str(conf.getSize()[0]) )
+        self.hText.SetValue( str(conf.getSize()[1]) )
+        self.yText.SetValue( str(conf.getPosition()[1]) )
+        self.xText.SetValue( str(conf.getPosition()[0]) )
+
+        # parallel section
+        if conf.getNodeNum() == 1:
+            self.parallelCheck.SetValue(False)
+            self.nodeNumSpin.SetValue(1)
+            self.nodeNumSpin.Enable(False)
+            self.masterIPText.Enable(False)
+        else:
+            self.parallelCheck.SetValue(True)
+            self.nodeNumSpin.SetValue( conf.getNodeNum() )
+            if conf.getMasterIP():  # could be none
+                self.masterIPText.SetValue( conf.getMasterIP() )        
+            self.nodeNumSpin.Enable(True)
+            self.masterIPText.Enable(True)
+
+
+        # advanced
+        self.pbSpin.SetValue( conf.getBlockSize()[0] )
+        self.bridgeIPText.SetValue( conf.getBridgeIP() )
+        self.bridgePortText.SetValue( conf.getBridgePort() )
+
+
+    def OnAppAdd(self, evt):
+        appName = wx.GetTextFromUser("Enter new application name.\nHas to be the same as the sage app configuration file the application\nis trying to load (e.g. \"atlantis\" is trying to load \"atlantis.conf\")", "App Name", parent=self)
+        if appName == "":  return
+        if appName in self.configs.getAppList():
+            wx.MessageBox("Application already exists", "Error", parent=self)
+            return
+        
+        configName = wx.GetTextFromUser("Enter first configuration name", "Config Name", parent=self)
+        if configName == "":  return
+        self.ClearConfig(clearConfigNames=True)
+
+        # add to the list of apps
+        self.appsList.Append(appName)
+        self.appsList.SetStringSelection(appName)
+
+        # add to the list of configs
+        self.configCombo.Append(configName)
+        self.configCombo.SetStringSelection(configName)
+
+        # change the actual datastructure
+        self.configs.addNewApp(appName)
+        conf = OneConfig(configName, appName)
+        self.currentConfig = conf
+        self.configs.getApp(appName).addConfig(conf)
+
+
+    def OnAppDel(self, evt):
+        appName = self.appsList.GetStringSelection()
+        if appName == "":  return  #nothing selected
+        self.configs.delApp(appName)
+        self.ClearConfig(clearConfigNames=True)
+        self.currentConfig = None
+        self.appsList.Delete( self.appsList.FindString(appName) )
+        
+
+    def ClearConfig(self, clearConfigNames=False):
+        """ clears all the config fields to their default values """
+        self.pbSpin.SetValue(64)
+        self.bridgeIPText.SetValue("")
+        self.bridgePortText.SetValue("")
+        self.masterIPText.SetValue("")
+        self.nodeNumSpin.SetValue(1)
+        self.parallelCheck.SetValue(False)
+        self.nodeNumSpin.Enable(False)
+        self.masterIPText.Enable(False)
+        self.xText.SetValue("100")
+        self.yText.SetValue("100")
+        self.hText.SetValue("1000")
+        self.wText.SetValue("1000")
+        self.staticCheck.SetValue(True)
+        self.dirText.SetValue("$SAGE_DIRECTORY/bin")
+        self.machineText.SetValue("127.0.0.1")
+        self.appText.SetValue("")
+        if clearConfigNames:
+            self.configCombo.Clear()
+            self.configCombo.SetValue("")
+
+
+    def OnPublicCheck(self, evt):
+        if self.reportCheck.IsChecked():
+            self.hostText.Enable()
+            #self.portText.Enable()
+        else:
+            self.hostText.Disable()
+            #self.portText.Disable()
+
+
+    ####  KILL FOCUS EVENT HANDLERS (for saving config data right away)
+
+    def OnStaticFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setStaticApp(self.staticCheck.IsChecked())
+
+    def OnNodeNumFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setNodeNum(self.nodeNumSpin.GetValue())
+
+    def OnMasterIPFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setMasterIP(self.masterIPText.GetValue())
+
+    def OnAppTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setCommand(self.appText.GetValue())
+
+    def OnDirTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setBinDir(self.dirText.GetValue())
+
+    def OnMachineTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setTargetMachine(self.machineText.GetValue())
+
+    def OnSizeTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setSize((int(self.wText.GetValue()),
+                                       int(self.hText.GetValue())))
+
+    def OnPosTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setPosition((int(self.xText.GetValue()),
+                                           int(self.yText.GetValue())))
+
+    def OnPBSpinFocus(self, evt):
+        if self.currentConfig:
+            sz = self.pbSpin.GetValue()
+            self.currentConfig.setBlockSize((sz,sz))
+
+    def OnBridgePortTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setBridgePort(self.bridgePortText.GetValue())
+            
+    def OnBridgeIPTextFocus(self, evt):
+        if self.currentConfig:
+            self.currentConfig.setBridgeIP(self.bridgeIPText.GetValue())
+
+    
+    def OnClose(self, evt):
+        """ save stuff here """
+        self.settings.doReport = self.reportCheck.IsChecked()
+        self.settings.server = self.hostText.GetValue()
+        #self.settings.port = self.portText.GetValue()
+        self.settings.inBG = self.run.GetValue()
+        saveSettings()
+        self.configs.writeConfig()
+        evt.Skip()
+
+
+
+
+
+
+class FileServerFrame(ComponentFrame):
+    def __init__(self, parent):
+        ComponentFrame.__init__(self, parent, FILE_SERVER)
+
+        # for reading the config file
+        self.types ={}
+        self.viewers = {}
+        self.filesDir = ""
+        self.ReadConfigFile()
+        
+        self.MakeWidgets()
+        self.Show()
+
+
+    def MakeWidgets(self):
+        self.run = wx.CheckBox(self, wx.ID_ANY, "Run in background")
+        self.run.SetToolTipString(HELP_INBG)
+        self.run.SetValue(self.settings.inBG)
+
+        self.mainSizer.Add(self.MakeConfigBox(), 1, wx.EXPAND | wx.ALL, 10)
+        self.mainSizer.Add(self.run, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.ALL, 10)
+        ComponentFrame.MakeWidgets(self)
+
+
+
+    def MakeConfigBox(self):
+        # the box
+        box = wx.StaticBox(self, wx.ID_ANY, "File Server Configuration:")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.VERTICAL )
+
+        # widgets
+        self.fbb = fb.DirBrowseButton(self, wx.ID_ANY, labelText='Library Root:',
+                                      dialogTitle="Choose Library Root",
+                                      startDirectory=opj(SAGE_DIR,"bin"),
+                                      toolTip=HELP_FS_ROOT)
+        self.fbb.SetValue(self.filesDir)
+        self.fbb.label.SetMinSize((80, -1))
+        self.fbb.SetMinSize((600,-1))
+
+        # types label and list
+        typesLabel = wx.StaticText(self, wx.ID_ANY, "File types:")
+        self.typesList = wx.ListBox(self, wx.ID_ANY, choices=self.types.keys())
+        self.typesList.Bind(wx.EVT_LISTBOX, self.OnList)
+        self.typesList.SetToolTipString(HELP_FS_TYPES)
+        
+        addBtn = wx.Button(self, wx.ID_ANY, "Add", style=wx.BU_EXACTFIT)
+        addBtn.Bind(wx.EVT_BUTTON, self.OnAdd)
+        delBtn = wx.Button(self, wx.ID_ANY, "Delete", style=wx.BU_EXACTFIT)
+        delBtn.Bind(wx.EVT_BUTTON, self.OnDel)
+
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(addBtn, 1, wx.ALIGN_CENTER | wx.ALL, 4)
+        btnSizer.Add(delBtn, 1, wx.ALIGN_CENTER | wx.RIGHT | wx.TOP | wx.BOTTOM, 4)
+                     
+        typesSizer = wx.BoxSizer(wx.VERTICAL)
+        typesSizer.Add(typesLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        typesSizer.Add(self.typesList, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        typesSizer.Add(btnSizer, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 1)
+        
+
+        # details (extensions and application)
+        extLabel = wx.StaticText(self, wx.ID_ANY, "File extensions:")
+        self.extText = wx.TextCtrl(self, wx.ID_ANY)
+        self.extText.Bind(wx.EVT_KILL_FOCUS, self.OnExtText)
+        self.extText.SetToolTipString(HELP_FS_EXT)
+        
+        appLabel = wx.StaticText(self, wx.ID_ANY, "Run with application (and any optional arguments):")
+        self.appText = wx.TextCtrl(self, wx.ID_ANY)
+        self.appText.Bind(wx.EVT_KILL_FOCUS, self.OnAppText)
+        self.appText.SetToolTipString(HELP_FS_APP)
+
+        detailSizer = wx.BoxSizer(wx.VERTICAL)
+        detailSizer.Add(extLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        detailSizer.Add(self.extText, 0, wx.ALIGN_LEFT | wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
+        detailSizer.Add(appLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        detailSizer.Add(self.appText, 0, wx.ALIGN_LEFT | wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 5)
+
+        # add the above two to the horizontal sizer
+        horSizer = wx.BoxSizer(wx.HORIZONTAL)
+        horSizer.Add(typesSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL, 10)
+        horSizer.Add(detailSizer, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL, 10)
+        
+        # add widgets to the boxSizer
+        boxSizer.Add(self.fbb, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 10)
+        boxSizer.Add(horSizer, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+
+        return boxSizer
+
+
+
+    def ReadConfigFile(self):
+        # reinitialize everything
+        self.types = {}
+        self.viewers = {}
+
+        # read the config file
+        try:
+            f = open(self.settings.getConfigFilename(), "r")
+        except:
+            m = """
+            File Server configuration file doesn't exist yet which usually means
+            that it hasn't been compiled yet. Please compile it first by running "make install" from
+            %s.""" % opj(SAGE_DIR,"app","FileViewer")
+            wx.MessageBox(m, "No FileServer")
+            self.Destroy()
+            return
+                
+        for line in f:
+            line = line.strip()
+
+            # read root library directory
+            if line.startswith("FILES_DIR"):
+                self.filesDir = line.split("=")[1].strip()
+
+            # read types
+            elif line.startswith("type:"):
+                line = line.split(":",1)[1]
+                (type, extensions) = line.split("=")
+                self.types[type.strip()] = extensions.strip().split(" ")
+
+            # read apps for types
+            elif line.startswith("app:"):
+                line = line.split(":", 1)[1].strip()
+                (type, app) = line.split("=")
+                tpl = app.strip().split(" ", 1)
+                if len(tpl) == 1:  params = ""
+                else:  params = tpl[1].strip()
+                app = tpl[0].strip()
+                self.viewers[type.strip()] = (app, params)
+        f.close()
+        
+
+    def WriteConfigFile(self):
+        try:
+            self.filesDir = self.fbb.GetValue()
+            
+            f = open(getUserPath("fileServer", "fileServer.conf"), "w")
+            f.write("FILES_DIR = "+ self.filesDir+"\n")
+
+            f.write("\n#"+"----"*12+"\n\n")  # separator
+            
+            # write types out and their extensions
+            for t, ext in self.types.iteritems():
+                f.write("type:" + t + " = " + " ".join(ext) + "\n")
+
+            f.write("\n#"+"----"*12+"\n\n")  # separator
+            
+            # write apps out and their parameters
+            for t, appTuple in self.viewers.iteritems():
+                f.write("app:"+ t + " = " + " ".join(appTuple) + "\n")
+            
+            f.close()
+        except:
+            print " ***** Error while writing file server config file"
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            return False
+
+
+    def OnAdd(self, evt):
+        newType = wx.GetTextFromUser("Enter new file type to the file library:", "New Type", parent=self)
+        if newType != "":
+            if newType in self.types:
+                wx.MessageBox("File type already exists", "Error", parent=self)
+                return
+            self.extText.Clear()
+            self.appText.Clear()
+            self.types[newType] = []
+            self.viewers[newType] = ()
+            self.typesList.AppendAndEnsureVisible(newType)
+            self.typesList.SetStringSelection(newType)
+
+
+    def OnDel(self, evt):
+        t = self.typesList.GetStringSelection()
+        if t != "":
+            self.extText.Clear()
+            self.appText.Clear()
+            del self.types[t]
+            del self.viewers[t]
+            self.typesList.Delete( self.typesList.FindString(t) )
+            
+
+    def OnList(self, evt):
+        t = evt.GetString()
+        self.extText.SetValue(" ".join(self.types[t]))
+        self.appText.SetValue(" ".join(self.viewers[t]))
+
+
+    def OnAppText(self, evt):
+        """ gets called when the text ctrl loses focus so we save the data """
+        t = self.typesList.GetStringSelection()
+        tpl = self.appText.GetValue().strip().split(" ", 1)
+        if len(tpl) == 1:  params = ""
+        else:  params = tpl[1].strip()
+        app = tpl[0].strip()
+        self.viewers[t] = (app, params)
+        
+
+    def OnExtText(self, evt):
+        """ gets called when the text ctrl loses focus so we save the data """
+        t = self.typesList.GetStringSelection()
+        self.types[t] = self.extText.GetValue().strip().split(' ')
+
+
+    def OnClose(self, evt):
+        """ save stuff here """
+        self.settings.inBG = self.run.GetValue()
+        self.WriteConfigFile()
+        saveSettings()
+        evt.Skip()
+
+
+
+
+        
+
+class SageProxyFrame(ComponentFrame):
+    def __init__(self, parent):
+        ComponentFrame.__init__(self, parent, SAGE_PROXY)
+        self.MakeWidgets()
+        self.Show()
+
+
+    def MakeWidgets(self):
+        # add the boxes to the main sizer
+        self.mainSizer.Add(self.MakeConnectionBox(), 0, wx.EXPAND | wx.ALL, 10)
+        self.mainSizer.Add(self.MakePasswordBox(), 0, wx.EXPAND | wx.ALL, 10)
+        ComponentFrame.MakeWidgets(self)
+
+
+    def MakeConnectionBox(self):
+        # sage connection box
+        box = wx.StaticBox(self, wx.ID_ANY, "Run Proxy for SAGE on:")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.HORIZONTAL )
+
+        # widgets
+        hostLabel = wx.StaticText(self, wx.ID_ANY, "Hostname / IP:")
+        self.hostText = wx.TextCtrl(self, wx.ID_ANY, self.settings.host)
+        self.hostText.SetToolTipString(HELP_SP_HOST)
+        self.hostText.SetMinSize((150, -1))
+
+        portLabel = wx.StaticText(self, wx.ID_ANY, "Port:")
+        self.portText = wx.TextCtrl(self, wx.ID_ANY, str(self.settings.port))
+        self.portText.SetToolTipString(HELP_SP_PORT)
+        
+        # add widgets to the boxSizer
+        boxSizer.Add(hostLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.hostText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+        boxSizer.Add((10,10))
+        boxSizer.Add(portLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.portText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+
+        return boxSizer
+
+
+    def MakePasswordBox(self):
+        # password box
+        box = wx.StaticBox(self, wx.ID_ANY, "Password for SAGE Web UI access:")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.HORIZONTAL )
+
+        # widgets
+        passLabel = wx.StaticText(self, wx.ID_ANY, "Password:")
+        self.passText = wx.TextCtrl(self, wx.ID_ANY, self.settings.password)
+        self.passText.SetToolTipString(HELP_SP_PASS)
+        self.passText.SetMinSize((150, -1))
+
+        # add widgets to the boxSizer
+        boxSizer.Add(passLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.passText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+
+        return boxSizer
+
+
+    def OnClose(self, evt):
+        """ save stuff here """
+        self.settings.host = self.hostText.GetValue()
+        self.settings.port = int(self.portText.GetValue())
+        self.settings.password = self.passText.GetValue()
+        saveSettings()
+        evt.Skip()
+        
+
+
+
+class SageUIFrame(ComponentFrame):
+    def __init__(self, parent):
+        ComponentFrame.__init__(self, parent, SAGE_UI)
+        self.MakeWidgets()
+        self.Show()
+
+        
+    def MakeWidgets(self):
+        # make the box first (this is REQUIRED since the box is a
+        # sibling of the widgets inside it and not their parent)
+        
+        box = wx.StaticBox(self, wx.ID_ANY, "Connection Manager")
+        box.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box )
+        boxSizer = wx.StaticBoxSizer( box, wx.HORIZONTAL )
+
+        # widgets
+        hostLabel = wx.StaticText(self, wx.ID_ANY, "Hostname / IP:")
+        self.hostText = wx.TextCtrl(self, wx.ID_ANY, self.settings.host)
+        self.hostText.SetToolTipString(HELP_SU_HOST)
+        self.hostText.SetMinSize((150, -1))
+
+        portLabel = wx.StaticText(self, wx.ID_ANY, "Port:")
+        self.portText = wx.TextCtrl(self, wx.ID_ANY, str(self.settings.port))
+        self.portText.SetToolTipString(HELP_SU_HOST)
+
+        autologinLabel = wx.StaticText(self, wx.ID_ANY, "Autologin to (enter sage session name):")
+        self.autologinText = wx.TextCtrl(self, wx.ID_ANY, self.settings.autologinMachine)
+        self.autologinText.SetToolTipString(HELP_SU_AUTOLOGIN)
+        self.autologinText.SetMinSize((150, -1))
+        
+        # add widgets to the boxSizer
+        boxSizer.Add(hostLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.hostText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+        boxSizer.Add((10,10))
+        boxSizer.Add(portLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        boxSizer.Add(self.portText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.RIGHT | wx.BOTTOM | wx.TOP, 5)
+
+        # autologin sizer
+        loginSizer = wx.BoxSizer(wx.HORIZONTAL)
+        loginSizer.Add(autologinLabel, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        loginSizer.Add(self.autologinText, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL, 5)
+        
+        # add the box to the main sizer
+        self.mainSizer.Add(boxSizer, 0, wx.EXPAND | wx.ALL, 10)
+        self.mainSizer.Add(loginSizer, 0, wx.EXPAND | wx.ALL, 10)
+        ComponentFrame.MakeWidgets(self)   # call this last
+
+
+    def OnClose(self, evt):
+        """ save stuff here """
+        self.settings.host = self.hostText.GetValue()
+        self.settings.port = int(self.portText.GetValue())
+        self.settings.autologinMachine = self.autologinText.GetValue()
+        saveSettings()
+        evt.Skip()
+
+
+
+class SageFrame(ComponentFrame):
+    def __init__(self, parent):
+        ComponentFrame.__init__(self, parent, SAGE)
+        self.MakeWidgets()
+        self.Show()
+
+        
+    def MakeWidgets(self):
+        box1 = wx.StaticBox(self, wx.ID_ANY, "ON SAGE STARTUP")
+        box1.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box1 )
+        box1Sizer = wx.StaticBoxSizer( box1, wx.VERTICAL )
+
+        box2 = wx.StaticBox(self, wx.ID_ANY, "ON SAGE SHUTDOWN")
+        box2.SetForegroundColour(wx.BLUE)
+        makeBiggerBoldFont( box2 )
+        box2Sizer = wx.StaticBoxSizer( box2, wx.VERTICAL )
+
+        # start stuff
+        startLabel = wx.StaticText(self, wx.ID_ANY, "Specify any additional commands to be executed before SAGE starts")
+        self.start = wx.TextCtrl(self, wx.ID_ANY, self.settings.onStart, style=wx.TE_MULTILINE)
+        self.start.SetToolTipString(HELP_S_START)
+        box1Sizer.AddSpacer((10,10)) 
+        box1Sizer.Add(startLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        box1Sizer.Add(self.start, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+
+        # stop stuff
+        stopLabel = wx.StaticText(self, wx.ID_ANY, "Specify any additional commands to be executed after SAGE is stopped")
+        self.stop = wx.TextCtrl(self, wx.ID_ANY, self.settings.onStop, style=wx.TE_MULTILINE)
+        self.stop.SetToolTipString(HELP_S_STOP)
+        procLabel = wx.StaticText(self, wx.ID_ANY, "List all processes to be killed on the nodes and the master during SAGE shutdown")
+        self.proc = wx.TextCtrl(self, wx.ID_ANY, self.settings.toKill)
+        self.proc.SetToolTipString(HELP_S_PROC)
+                
+        box2Sizer.AddSpacer((10,10)) 
+        box2Sizer.Add(stopLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        box2Sizer.Add(self.stop, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        box2Sizer.AddSpacer((20,20)) 
+        box2Sizer.Add(procLabel, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        box2Sizer.Add(self.proc, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+
+        self.mainSizer.Add(box1Sizer, 1, wx.EXPAND | wx.ALL, 15)
+        self.mainSizer.Add(box2Sizer, 1, wx.EXPAND | wx.ALL, 15)
+        ComponentFrame.MakeWidgets(self)   # call this last
+
+
+    def OnClose(self, evt):
+        """ save stuff here """
+        self.settings.onStop = self.stop.GetValue().strip()
+        self.settings.onStart = self.start.GetValue().strip()
+        self.settings.toKill = self.proc.GetValue().strip()
+        saveSettings()
+        evt.Skip()
+
+
+
+        
+
+###
+### the following are the main frame UI components
+###
+        
+class ComponentSummary(wx.Panel):
+    """ this is the container for one SAGE component...
+        it has 3 widgets: name, run checkbox and edit button
+    """
+    def __init__(self, parent, componentType):
+        wx.Panel.__init__(self, parent, wx.ID_ANY, style=wx.SIMPLE_BORDER)
+        self.color = wx.Colour(252,172,130)
+        self.componentType = componentType
+        self.SetMinSize((250,70))
+        self.SetMaxSize((250,70))
+        self.settings = components[componentType].settings
+        self.MakeWidgets()
+        
+        # for selecting the component on click
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnRunCheck)
+        self.name.Bind(wx.EVT_LEFT_DOWN, self.OnRunCheck)
+        self.SetBackgroundColour(self.color)
+        
+        # where the console output will be printed
+        # it's a child of the whole ComponentsPanel
+        # since it's placed inside a sizer there
+        self.output = wx.TextCtrl(self.GetParent().outputNotebook, wx.ID_ANY, style=wx.TE_MULTILINE | wx.TE_READONLY)
+        self.output.SetMinSize((800, 300))
+        self.output.SetMaxLength(MAX_TEXT_LEN)
+        components[componentType].output = self.output
+
+        # the process tied with the component
+        components[componentType].process = Process(componentType)
+
+
+    def ChangeColor(self, newColor):
+        self.color = newColor
+        self.SetBackgroundColour(self.color)
+        self.run.faceDnClr = self.color
+        self.Refresh()
+        
+
+    def MakeWidgets(self):    
+        # make all the widgets
+        self.MakeName()
+        self.MakeRun()
+        self.MakeEdit()
+        self.MakeStopBtn()
+        
+        # add the widgets to the sizers
+        vSizer = wx.BoxSizer(wx.VERTICAL)
+        hSizer = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer2 = wx.BoxSizer(wx.HORIZONTAL)
+
+        hSizer.Add(self.run, 0, wx.ALIGN_LEFT | wx.ALL, 0)
+        hSizer.Add(self.name, 1, wx.ALIGN_LEFT | wx.ALL, 5)
+
+        hSizer2.Add(self.stopBtn, 0, wx.ALIGN_RIGHT | wx.RIGHT, 20)
+        hSizer2.Add(self.editBtn, 0, wx.ALIGN_RIGHT | wx.RIGHT, 3)
+        
+        vSizer.Add(hSizer, 1, wx.ALIGN_TOP | wx.ALIGN_LEFT | wx.ALL, 3)
+        vSizer.Add(hSizer2, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.BOTTOM, 1)
+
+        self.SetSizer(vSizer)
+
+
+    def MakeStopBtn(self):
+        self.stopBtn = buttons.GenBitmapButton(self, wx.ID_ANY, getStopBitmap(), style=wx.BORDER_NONE)
+        self.stopBtn.faceDnClr = self.color
+        self.stopBtn.SetBestSize((24,24))
+        self.stopBtn.Bind(wx.EVT_BUTTON, self.OnStopBtn)
+        self.stopBtn.SetToolTipString(HELP_COMP_STOP)
+           
+    def MakeName(self):
+        self.name = wx.StaticText(self, wx.ID_ANY, self.componentType)
+        makeBoldFont(self.name)
+        try: self.name.Wrap(150)  # wrap the text if longer than 150 pixels
+        except: pass
+        help = ""
+        if self.componentType == APP_LAUNCHER:
+            help = HELP_AL
+        elif self.componentType == FILE_SERVER:
+            help = HELP_FS
+        elif self.componentType == SAGE_UI:
+            help = HELP_SU
+        elif self.componentType == SAGE_PROXY:
+            help = HELP_SP
+        elif self.componentType == SAGE:
+            help = HELP_S
+        self.name.SetToolTipString(help)
+        self.SetToolTipString(help)
+
+
+    def MakeRun(self):
+        bmp = getRunBitmap(self.settings.doRun)
+        self.run = buttons.GenBitmapButton(self, wx.ID_ANY, bmp, style=wx.BORDER_NONE)
+        self.run.SetBitmapSelected(bmp)
+        self.run.Bind(wx.EVT_BUTTON, self.OnRunCheck)
+        self.run.SetToolTipString(HELP_RUN)
+        self.run.faceDnClr = self.color
+        
+                
+    def MakeEdit(self):
+        self.editBtn = wx.Button(self, wx.ID_ANY, "Settings")
+        self.editBtn.Bind(wx.EVT_BUTTON, self.OnEdit)
+        self.editBtn.SetToolTipString(HELP_EDIT)
+
+
+    def OnEdit(self, evt):
+        if self.componentType == APP_LAUNCHER:
+            frame = AppLauncherFrame(self)
+        elif self.componentType == FILE_SERVER:
+            frame = FileServerFrame(self)
+        elif self.componentType == SAGE_PROXY:
+            frame = SageProxyFrame(self)
+        elif self.componentType == SAGE_UI:
+            frame = SageUIFrame(self)
+        elif self.componentType == SAGE:
+            frame = SageFrame(self)
+
+
+    def OnRunCheck(self, evt):
+        self.settings.doRun = not self.settings.doRun # reverse the value 
+        bmp = getRunBitmap(self.settings.doRun)
+        self.run.SetBitmapLabel(bmp, False)
+        self.run.SetBitmapSelected(bmp)
+        self.run.Refresh()
+
+
+    def OnStopBtn(self, evt):
+        components[self.componentType].process.stop()
+
+
+
+
+
+
+class ComponentsPanel(scrolled.ScrolledPanel):
+    """ this holds the summaries for each component on the main frame """
+
+    def __init__(self, parent):
+        scrolled.ScrolledPanel.__init__(self, parent, wx.ID_ANY)
+        self.MakeWidgets()
+
+
+    def ChangeAllColors(self, newColor):
+        for c in self.compSummary.itervalues():
+            c.ChangeColor(newColor)
+
+
+    def MakeWidgets(self):
+        mainSizer = wx.BoxSizer( wx.HORIZONTAL )
+        compSizer = wx.BoxSizer( wx.VERTICAL )
+
+        # notebook
+        self.outputNotebook = wx.Notebook(self, wx.ID_ANY, style=wx.NO_BORDER)
+
+        # component objects
+        self.compSummary = {}
+        for componentType, c in components.iteritems():
+            self.compSummary[componentType] = ComponentSummary(self, componentType)
+
+        # add components to the compSizer
+        label = wx.StaticText(self, wx.ID_ANY, "Components to Start:")
+        makeBoldFont(label)
+        compSizer.Add(label, 0, wx.EXPAND | wx.TOP | wx.LEFT, 10)
+        for cName in componentNames:
+            c = self.compSummary[cName]
+            compSizer.Add(c, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP | wx.ALL, 10)
+            self.outputNotebook.AddPage(c.output, cName)  # add the notebook pages
+            
+        # run controls
+        self.runPanel = RunPanel(self)
+        compSizer.Add(self.runPanel, 1, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP | wx.ALL, 5)
+
+        # create the output label and sizer
+        self.outLabel = wx.StaticText(self, wx.ID_ANY, "Output from:")
+        makeBoldFont(self.outLabel)
+        self.outSizer = wx.BoxSizer(wx.VERTICAL)
+        self.outSizer.Add(self.outLabel, 0, wx.EXPAND | wx.TOP | wx.LEFT, 15)
+        self.outSizer.Add(self.outputNotebook, 1, wx.EXPAND | wx.TOP | wx.LEFT | wx.BOTTOM, 5)
+
+        # add the stuff to the main sizer
+        mainSizer.Add(compSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, 5)
+        mainSizer.Add(self.outSizer, 1, wx.EXPAND | wx.LEFT | wx.BOTTOM, 15)
+
+        # select the default component
+        self.SetSizerAndFit(mainSizer)
+        self.SetAutoLayout(1)
+        self.SetupScrolling()
+
+
+
+
+class RunPanel(wx.Panel):
+    """ the run panel on the main frame for starting and stopping sage """
+
+    def __init__(self, parent):
+        wx.Panel.__init__(self, parent, wx.ID_ANY)
+        self.MakeWidgets()
+
+        
+    def MakeWidgets(self):
+        mainSizer = wx.BoxSizer( wx.VERTICAL )
+        boxSizer = wx.BoxSizer( wx.HORIZONTAL )
+
+        # add components to the boxSizer
+        self.runBtn = wx.Button(self, 1, "START")
+        self.runBtn.Bind(wx.EVT_BUTTON, self.OnRun)
+        self.runBtn.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
+        self.runBtn.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeaveWindow)
+        makeBiggerBoldFont(self.runBtn)
+        makeBiggerFont(self.runBtn)
+
+        self.stopBtn = wx.Button(self, 2, "STOP")
+        self.stopBtn.Bind(wx.EVT_BUTTON, self.OnStop)
+        self.stopBtn.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
+        self.stopBtn.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeaveWindow)
+        makeBiggerBoldFont(self.stopBtn)
+        makeBiggerFont(self.stopBtn)
+
+        self.helpNote = wx.StaticText(self, wx.ID_ANY, "\n", style=wx.ALIGN_CENTRE)
+        self.helpNote.SetMinSize((-1, 30))
+
+        self.simpleBtn = hl.HyperLinkCtrl(self, wx.ID_ANY, "<- Simple Mode")
+        self.simpleBtn.SetBackgroundColour(self.GetBackgroundColour())
+        self.simpleBtn.AutoBrowse(False)
+        self.simpleBtn.Bind(hl.EVT_HYPERLINK_LEFT, self.OnSimple)
+
+        boxSizer.Add(self.runBtn, 0, wx.ALIGN_CENTER | wx.TOP | wx.RIGHT, 15)
+        boxSizer.Add(self.stopBtn, 0, wx.ALIGN_CENTER | wx.TOP | wx.LEFT, 15)
+
+        mainSizer.Add(boxSizer, 0, wx.ALIGN_CENTER)
+        mainSizer.Add(self.helpNote, 0, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP | wx.ALL, 5)
+        mainSizer.AddSpacer((10,10), 1)
+        mainSizer.Add(self.simpleBtn, 0, wx.ALIGN_BOTTOM | wx.ALIGN_LEFT | wx.ALL, 10)
+    
+        self.SetSizerAndFit(mainSizer)
+
+
+    def OnSimple(self, evt):
+        wx.GetApp().GetTopWindow().advancedFrame.Hide()
+        wx.GetApp().GetTopWindow().Show()
+
+
+    def OnMouseEnterWindow(self, evt):
+        if evt.GetId() == 1:
+            self.helpNote.SetLabel("Start all the checked components\nthat are not already running.")
+        else:
+            self.helpNote.SetLabel("Stop all the components that are\nnot running in the background.")
+        evt.Skip()
+        
+
+    def OnMouseLeaveWindow(self, evt):
+        self.helpNote.SetLabel("")
+        self.GetSizer().Layout()
+        evt.Skip()
+            
+
+    def OnRun(self, evt):
+        """ start all the checked processes... but start sage before everything else
+            because some components need sage running already
+        """
+
+        # first start sage and then sleep for a few seconds
+        sage = components[SAGE]
+        if sage.settings.doRun:
+            sage.process.start()
+            time.sleep(2)
+
+        # now start the rest of the components
+        for c in components.itervalues():
+            if c.componentType != SAGE and c.settings.doRun:
+                c.process.start()
+        saveSettings()  # to save the changed PIDs
+        
+
+    def OnStop(self, evt):
+        for c in components.itervalues():
+            if not c.settings.inBG:
+                c.process.stop()
+        saveSettings()  # to save the changed PIDs
+        
+
+
+
+
+class QuickFrame(wx.Frame):
+    def __init__(self):
+        wx.Frame.__init__(self, None, wx.ID_ANY, "SAGE Launcher",
+                          style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
+        self.SetBackgroundColour(wx.Colour(14,51,51))
+        #self.SetClientSize((373, 315))
+        self.SetMinSize((377, 315))
+        self.MakeWidgets()
+        self.SetThemeEnabled(False)
+        self.SetIcon(getSageIcon())
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        self.Centre()
+        self.Show()
+        
+
+    def MakeWidgets(self):
+        ms = wx.BoxSizer(wx.VERTICAL)
+        self.panel = wx.Panel(self, wx.ID_ANY)
+        self.panel.SetBackgroundColour(self.GetBackgroundColour())
+        self.panel.Bind(wx.EVT_PAINT, self.OnPaint)
+        ms.Add(self.panel, 1, wx.EXPAND)
+        
+        self.runBtn = buttons.GenBitmapButton(self.panel, 1, getSageStartUpBitmap(), style=wx.BORDER_NONE)
+        self.runBtn.SetBitmapSelected(getSageStartDownBitmap())
+        self.runBtn.faceDnClr = self.GetBackgroundColour()
+        self.runBtn.Bind(wx.EVT_BUTTON, self.OnRun)
+            
+        self.stopBtn = buttons.GenBitmapButton(self.panel, 2, getSageStopUpBitmap(), style=wx.BORDER_NONE)
+        self.stopBtn.SetBitmapSelected(getSageStopDownBitmap())
+        self.stopBtn.faceDnClr = self.GetBackgroundColour()
+        self.stopBtn.Bind(wx.EVT_BUTTON, self.OnStop)
+
+        self.advancedBtn = hl.HyperLinkCtrl(self.panel, wx.ID_ANY, "Advanced Mode ->")
+        self.advancedBtn.SetBackgroundColour(self.GetBackgroundColour())
+        self.advancedBtn.SetForegroundColour(wx.Colour(103,153,102))
+        self.advancedBtn.AutoBrowse(False)
+        self.advancedBtn.Bind(hl.EVT_HYPERLINK_LEFT, self.OnAdvanced)
+        
+        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
+        btnSizer.Add(self.runBtn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.TOP | wx.RIGHT, 15)
+        btnSizer.Add(self.stopBtn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.TOP | wx.LEFT, 15)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add((150,150))
+        sizer.Add(self.MakeStatesPanel(self.panel), 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.ALL, 10)
+        sizer.Add(btnSizer, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM | wx.ALL, 10)
+        sizer.Add(self.advancedBtn, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT | wx.ALL, 10)
+
+        self.panel.SetSizer(sizer)
+        self.SetSizer(ms)
+        self.Fit()
+
+
+    def MakeStatesPanel(self, parent):
+        def OnSelectedRadioButton(evt):
+            session = evt.GetEventObject().GetLabel()
+            if session == "New session":
+                session = ""
+            components[SAGE_UI].settings.loadState = session
+
+        stateHash = self.GetStateList()
+        
+        statesPanel = scrolled.ScrolledPanel(parent, wx.ID_ANY, size=(200,200))
+        statesPanel.SetBackgroundColour(wx.Colour(14,51,51))
+        statesPanel.SetForegroundColour(wx.Colour(200,200,200))
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        # add the default radio button
+        choices = {}
+        states = stateHash.keys()
+        states.sort()
+        defaultBtn = wx.RadioButton(statesPanel, -1, "New session", style=wx.RB_GROUP)
+        defaultBtn.Bind(wx.EVT_RADIOBUTTON, OnSelectedRadioButton, defaultBtn)
+        #defaultBtn.SetBackgroundColour(wx.Colour(14,51,51))
+        #defaultBtn.SetForegroundColour(wx.Colour(200,200,200))
+        defaultBtn.SetToolTipString("Empty display wall with nothing running")
+        choices["new"] = defaultBtn
+        sizer.Add(defaultBtn, 0, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.TOP, border=5)
+        sizer.Add(wx.StaticLine(statesPanel, -1), 0, wx.EXPAND | wx.ALL, border=5)
+
+        # add the rest of them
+        if len(stateHash) == 0:
+            t = wx.StaticText(statesPanel, wx.ID_ANY, "Any sessions you save through SAGE UI will show up here.")
+            try: t.Wrap(200)
+            except: pass
+            sizer.Add(t, 0, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.BOTTOM | wx.TOP, border=2)
+            
+        for stateName in states:
+            btn = wx.RadioButton(statesPanel, wx.ID_ANY, stateName)
+            btn.SetToolTipString(stateHash[stateName])
+            #btn.SetBackgroundColour(wx.Colour(14,51,51))
+            #btn.SetForegroundColour(wx.Colour(200,200,200))
+            choices[stateName] = btn
+            btn.Bind(wx.EVT_RADIOBUTTON, OnSelectedRadioButton, btn)
+            sizer.Add(btn, 0, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.BOTTOM | wx.TOP, border=2)
+
+        choices["new"].SetValue(True)
+        components[SAGE_UI].settings.loadState = ""
+
+        statesPanel.SetSizer(sizer)
+        statesPanel.SetAutoLayout(1)
+        statesPanel.SetupScrolling(scroll_x = False)
+        
+        return statesPanel
+
+
+    def GetStateList(self):
+        """ returns a hash of key=stateName, value=description """
+        savedStatesDir = getUserPath("saved-states")
+        stateHash = {}
+        appList = []
+        description = ""
+
+        if not os.path.isdir(savedStatesDir):
+            return {}
+        
+        # load all the states and read descriptions from them
+        for fileName in os.listdir(savedStatesDir):
+            filePath = opj(savedStatesDir, fileName)
+            if os.path.isfile(filePath) and os.path.splitext(filePath)[1] == ".state":
+                try:
+                    stateName = os.path.splitext( os.path.split(filePath)[1] )[0]
+                    f = open(filePath, "rb")
+                    (description, appList) = pickle.Unpickler(f).load()
+                    f.close()
+                    stateHash[stateName] = description
+                except:
+                    print "\nUnable to read saved state file: "+filePath
+                    continue
+
+        return stateHash
+        
+
+    def OnPaint(self, evt):
+        dc = wx.PaintDC(self.panel)
+        self.Redraw(dc)
+
+
+    def Redraw(self, dc=None):
+        if not dc:
+            dc = wx.ClientDC(self.panel)
+        dc.DrawBitmap(getSageBitmap(), 0, 0, False)
+        
+        
+    def OnClose(self, evt):
+        saveSettings()
+
+        # stop all the read threads from the executed processes
+        for c in components.itervalues():
+            c.process.stopRead()
+        
+        evt.Skip()
+
+
+    def OnAdvanced(self, evt):
+        self.Hide()
+        self.advancedFrame.Show()
+
+
+    def OnRun(self, evt):
+        """ start all the checked processes... but start sage before everything else
+            because some components need sage running already
+        """
+
+        # first start sage and then sleep for a few seconds
+        sage = components[SAGE]
+        if sage.settings.doRun:
+            sage.process.start()
+            time.sleep(2)
+
+        # now start the rest of the components
+        for c in components.itervalues():
+            if c.componentType != SAGE and c.settings.doRun:
+                c.process.start()
+        saveSettings()  # to save the changed PIDs
+        
+
+    def OnStop(self, evt):
+        for c in components.itervalues():
+            if not c.settings.inBG:
+                c.process.stop()
+        saveSettings()  # to save the changed PIDs
+        
+
+
+
+
+
+class AdvancedFrame(wx.Frame):
+    def __init__(self, parent):
+        wx.Frame.__init__(self, parent, wx.ID_ANY, "SAGE Launcher - Advanced Settings")
+        self.MakeWidgets()
+        self.SetThemeEnabled(False)
+        self.SetIcon(getSageIcon())
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+            
+        # a hack to get correct frame colour on Windows
+        if isWin():
+            global colour
+            colour = self.componentsPanel.GetBackgroundColour()
+            self.SetBackgroundColour(colour)
+
+
+    def MakeWidgets(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        
+        # set up tooltips globally
+        tt = wx.ToolTip("")
+        tt.SetDelay(500)
+        tt.Enable(True)
+        
+        t = HELP_INTRO
+        introText = wx.StaticText(self, wx.ID_ANY, t)
+        
+        self.componentsPanel = ComponentsPanel(self)
+        sizer.Add(introText, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 20)
+        sizer.Add(self.componentsPanel, 1, wx.EXPAND | wx.ALL, 10)
+        self.SetSizerAndFit(sizer)
+
+
+    def OnClose(self, evt):
+        self.GetParent().Close()
+
+
+
+ 
+# --------------------------------------------------------
+#
+#                  MAIN ENTRY POINT 
+#
+# --------------------------------------------------------
+
+
+def main():
+    """ main called at the bottom of this file """
+
+    # load the settings before everything else
+    settings = loadSettings()  # a hash comes back
+
+    # read the tile config
+    global tileConfig
+    tileConfig = TileConfig(getTileConfig())
+
+    # create the Component objects and set their settings
+    global components
+    for componentType in componentNames:
+        c = Component(componentType)
+        c.settings = settings[componentType]
+        components[componentType] = c
+        
+    # create our GUI
+    app = wx.App(redirect = False)
+    quickFrame = QuickFrame()
+    advancedFrame = AdvancedFrame(quickFrame)
+    quickFrame.advancedFrame = advancedFrame
+    app.SetTopWindow( quickFrame )
+
+    # start the app
+    app.MainLoop()
+
+
+
+
+
+
+
+
+
+
+
+
+# --------------------------------------------------------
+#
+#            MISCELLANEOUS HELPER CLASSES
+#
+# --------------------------------------------------------
+
+
+
+
+class Process:
+    """ there is one instance of this class for each component
+        that is running (or needs to run). It starts the process
+        itself and creates a thread to read data from that
+        process.
+    """
+    def __init__(self, componentType):
+        self.componentType = componentType
+        self.settings = components[componentType].settings
+        self.output = components[componentType].output
+        self.running = False
+        self.p = None    # Popen process object
+        self.t = None    # thread reading the output from the process
+        self._extraProcesses = []  # pids of extra processes started before SAGE
+
+
+    def start(self):
+        """ if the process is already running do nothing...
+            otherwise launch the new process and 
+        """
+        if self.isAlive():
+            self.output.SetInsertionPointEnd()
+            self.output.WriteText("\n\n**** Already running ****\n\n")
+        else:
+            cmd = self.settings.getStartCommand()
+            cwdir = self.settings.getCwd()
+
+            try:
+                # execute any extra commands first
+                self.__startExtra()
+                
+                self.p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.STDOUT, bufsize=1, cwd=cwdir)
+                self.t = Thread(target=self.__readOutput)
+                self.t.setDaemon(True)
+                self.doRead = True
+                self.t.start()
+                self.running = True
+                self.settings.pid = self.p.pid  # save the pid for later
+                
+            except:
+                print " ***** Error while starting", self.componentType
+                print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+                self.running = False
+                self.doRead = False
+                self.t = None
+                self.p = None
+
+
+    def __startExtra(self):
+        """ if the component has any extra commands to execute
+            before startup, this will start them """
+        if hasattr(self.settings, 'onStart'):
+            if self.settings.onStart != "":
+                for cmd in self.settings.onStart.splitlines():
+                    if not cmd.strip().startswith("#"):
+                        proc = sp.Popen(cmd.split())
+                        self._extraProcesses.append(proc.pid)  # save the pid for later killing
+        
+
+    def stop(self):
+        """ stops the read thread and the process """
+        try:
+            # kill SAGE unconditionally
+            if self.componentType == SAGE:
+                for c in self.settings.getKillCmd():
+                    sp.Popen(c)
+
+                # kill extra stuff started before sage
+                for pid in self._extraProcesses:
+                    self.__killProcess(pid)
+                self._extraProcesses = []
+                
+
+            # kill appLauncher unconditionally (because we can)
+            elif self.componentType == APP_LAUNCHER:
+                sp.Popen(self.settings.getKillCmd(), cwd=self.settings.getCwd())
+
+            # kill the other processes depending on whether they are running or not
+            elif self.isAlive():
+
+                # get the pid from the current object or from the saved settings
+                if self.p:    pid = self.p.pid
+                else:         pid = self.settings.pid
+
+                # execute a kill command
+                self.__killProcess(pid)
+
+            # execute any extra commands
+            self.__stopExtra()
+            
+        except:
+            print " ***** Error while stopping",self.componentType
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            
+        self.settings.pid = -1
+        self.running = False
+        self.doRead = False
+        self.p = None
+        self.t = None
+
+
+    def __stopExtra(self):
+        """ if the component has any extra commands to execute
+            after stopping, this will execute them """
+        if hasattr(self.settings, 'onStop'):
+            if self.settings.onStop != "":
+                for cmd in self.settings.onStop.splitlines():
+                    sp.Popen(cmd.split())
+
+
+    def isAlive(self):
+        """ return true if the process is currently running, false otherwise """
+        if self.running or  \
+           (self.p and (self.p.poll() is None)) or \
+           self.settings.pid != -1:
+
+            # if it's presumably running but its process object is dead,
+            # it's a zombie so report it as dead and close it's read thread
+            if self.p and not (self.p.poll() is None):
+                self.stopRead()
+                if self.t: self.t.join(1) # wait for the old read thread to die
+                return False
+            
+            return True
+
+        else:
+            return False
+
+
+    def __killProcess(self, pid):
+        """ execute a kill command depending on the OS
+            the Windows version will only work on XP
+        """
+        if isWin():
+            sp.Popen(["taskkill", "/F", "/PID", str(pid)])
+        else:
+            sp.Popen(["/bin/kill", "-9", str(pid)])
+                
+
+    def stopRead(self):
+        self.doRead = False
+        
+    
+    def __readOutput(self):
+        """ this runs in a thread and it checks for the output
+            from the executed process. Once the output comes in,
+            it tells the main wx thread to add the text that was
+            just read.
+        """
+        while self.doRead:
+            txt = os.read(self.p.stdout.fileno(), 2048)
+            wx.CallAfter(self.fillText, txt)
+            time.sleep(0.3)   # read at most twice / sec
+
+
+    def fillText(self, txt):
+        """ first check whether the text we are about to insert
+            will overflow the control or not. If it would, remove
+            some text from the beginning and then append the
+            new text. If not, just append the new text.
+        """
+        if len(txt) + self.output.GetLastPosition() > MAX_TEXT_LEN:
+            self.output.Remove(0, 2048)
+        self.output.SetInsertionPointEnd()
+        self.output.WriteText(txt)
+
+
+
+
+
+
+class FoldBar(wx.Panel):
+    """ This class represents the fold bar title for the individual
+        application configuration in the app launcher frame.
+        When clicked it expands/collapses the sizer that's holding the actual controls
+        for this section. It does that through the callback that's passed to this panel
+    """
+    
+    def __init__(self, parent, btnId, title, callback):
+        wx.Panel.__init__(self, parent, wx.ID_ANY, style = wx.NO_BORDER)
+        label = wx.StaticText(self, wx.ID_ANY, title)
+        label.Bind(wx.EVT_LEFT_DOWN, self.OnBtn)
+        makeBoldFont(label)
+        self.btn = buttons.GenBitmapButton(self, btnId, GetCollapsedIconBitmap(), style=wx.BORDER_NONE)
+        self.btn.Bind(wx.EVT_BUTTON, self.OnBtn)
+
+        sizer = wx.BoxSizer(wx.HORIZONTAL)
+        sizer.Add(label, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        sizer.Add(self.btn, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        self.SetSizer(sizer)
+        self.Fit()
+
+        self.callback = callback
+        self.collapsed = True
+        
+        
+    def OnBtn(self, evt):
+        if self.collapsed:
+            self.collapsed = False
+            self.btn.SetBitmapLabel(GetExpandedIconBitmap())
+            self.btn.Refresh()
+            self.callback(self.btn.GetId(), False)
+        else:
+            self.collapsed = True
+            self.btn.SetBitmapLabel(GetCollapsedIconBitmap())
+            self.btn.Refresh()
+            self.callback(self.btn.GetId(), True)
+
+
+
+
+
+####                                        #####  
+####       TILE CONFIGURATION CLASSES       #####
+####                                        #####
+
+class Tile:
+    """ describes one tile """
+
+    def __init__(self):
+        self.name = "node"
+        self.ip = "127.0.0.1"
+        self.numMonitors = 0
+        self.monitors = []  # a list of positions for each monitor (tuples)
+
+
+    def addMonitor(self, pos):
+        if pos in self.monitors:
+            return
+        self.monitors.append(pos)
+        self.numMonitors += 1
+
+
+    def delMonitor(self, pos):
+        if pos in self.monitors:
+            self.monitors.remove(pos)
+            self.numMonitors -= 1
+
+
+    def toString(self):
+        s = "\n\nDisplayNode\n"
+        s += "\tName %s\n" % self.name
+        s += "\tIP %s\n" % self.ip
+        s += "\tMonitors %s " %self.numMonitors
+        for m in self.monitors:
+            s += str(m) + " "
+
+        return s
+
+
+
+        
+
+class TileConfig:
+    """ describes the whole tiled display configuration """
+
+    def __init__(self, configName):
+        self.dim = [1,1]                # dimensions of the display (xTiles, yTiles)
+        self.mullions = ["0.75", "0.75", "0.75", "0.75"]  # mullions on top, down, left, right
+        self.resolution = [800, 600]    # of each tile in pixels
+        self.ppi = 72                   # pixels-per-inch of each tile
+        self.numMachines = 1            # total number of machines in the display
+        self.tiles = {}                 # key=IP, value=Tile object
+        self.readConfigFile(configName)
+
+
+    def getAllIPs(self):
+        return self.tiles.keys()
+        
+
+    def readConfigFile(self, filename):
+        f = open(filename, "r")
+        lines = f.readlines()
+        f.close()
+
+        # reinitialize variables
+        self.tiles = {}
+        currentTile = None
+
+        # read the file line by line
+        for line in lines:
+
+            if '#' in line:     # allow comments with # anywhere in the line
+                line = line.split('#')[0].strip()
+            line = line.strip()
+
+            if 'Dimensions' in line:
+                d = line.lstrip('Dimensions').strip().split(' ',1)
+                self.dim = [int(d[0]), int(d[1])]
+
+            elif 'Mullions' in line:
+                m = line.lstrip('Mullions').strip().split(' ',3)
+                self.mullions = [m[0], m[1], m[2], m[3]]
+
+            elif 'Resolution' in line:
+                r = line.lstrip('Resolution').strip().split(' ',1)
+                self.resolution = [int(r[0]), int(r[1])]
+
+            elif 'PPI' in line:
+                self.ppi = int( float ( line.lstrip('PPI').strip() ) )
+            
+            elif 'Machines' in line:
+                self.numMachines = int( line.lstrip('Machines').strip() )
+
+
+            # reading the tiles
+            elif 'DisplayNode' in line:
+                if currentTile:  # store the previous Tile if exists
+                    self.tiles[ currentTile.ip ] = currentTile
+                currentTile = Tile()
+
+            elif 'Name' in line:
+                currentTile.name = line.lstrip('Name').strip()
+
+            elif 'IP' in line:
+                currentTile.ip = line.lstrip('IP').split(":")[0].strip()
+
+            elif 'Monitors' in line:
+                (num, positions) = line.lstrip('Monitors').strip().split(' ', 1)
+                nums = positions.replace('(', ' ').replace(')', ' ').replace(',', ' ').split()
+                for i in range(0, len(nums)-1, 2):
+                    currentTile.addMonitor( (int(nums[i]),int(nums[i+1])) )
+
+        # add the last one
+        self.tiles[ currentTile.ip ] = currentTile
+
+        
+
+    def writeConfigFile(self):
+        # first the global stuff
+        s = "TileDisplay\n"
+        s += "\tDimensions %d %d\n" % (self.dim[0], self.dim[1])
+        s += "\tMullions %s %s %s %s\n" % (self.mullions[0], self.mullions[1],
+                                           self.mullions[2], self.mullions[3])
+        s += "\tResolution %d %d\n" % (self.resolution[0], self.resolution[1])
+        s += "\tPPI %d\n" % self.ppi
+        s += "\tMachines %d\n" % self.numMachines
+
+        # now each node
+        for t in self.tiles.itervalues():
+            s += t.toString()
+
+        return s
+    
+        
+    
+        
+
+####                                        #####  
+####   APP LAUNCHER CONFIGURATION CLASSES   #####
+####                                        #####
+class OneConfig:
+    ''' describes one configuration for an app '''
+    
+    def __init__(self, name, appName, dynamic=False):
+        self._configName = name
+        self._dynamic = dynamic     # dynamic config???
+        self._appName = appName
+        self._configFilename = appName+".conf"
+        self._launcherId = ""
+
+        self._binDir = "$SAGE_DIRECTORY/bin/"  # where the binary resides - this is where the config is copied to
+        self._nodeNum = 1
+        self._position = (100, 100)        # initial position of the window on SAGE
+        self._size = (1000, 1000)          # initial size of the window on SAGE
+        self._command = ""                 # the actual command used to start the application
+        self._targetMachine = "127.0.0.1"           # the render machine where the app will be started
+        self._protocol = "TCP"
+        self._masterIP = None              # the master machine of a parallel application
+        self._fsIP = None                  # which SAGE will the app connect to (if not using sageBridge)
+        self._fsPort = None                # which SAGE will the app connect to (if not using sageBridge)
+        self._useBridge = False            # if True the app will connect to sageBridge instead of fsManager
+        self._bridgeIP = ""                # the machine for sage bridge
+        self._bridgePort = ""              # the machine for sage bridge
+
+        self._additionalParams = ""        # any additional parameters you want to specify... used for testing
+
+        # audio stuff
+        self._audioFile = ""
+             
+        self._nwID = 1
+        self._msgPort = 23010
+        self._syncPort = 13010
+        self._nodeNum = 1
+        self._appId = 0                    # the port number for the app on the render machine
+        self._blockSize = (64,64)
+        self._blockThreshold = 0
+        self._streamType = "SAGE_BLOCK_HARD_SYNC"    # sync mode
+        self._staticApp = False             # static applications dont refresh their windows so sage needs to keep the last frame
+        self._runOnNodes = False    # if an app has to connect to the outside world or requires
+                                    #an SDL/GLUT window for rendering then it can't run on the nodes
+        
+
+    def getName(self): return self._configName
+    def getAppName(self): return self._appName
+    def isDynamic(self): return self._dynamic
+    def getConfigFilename(self): return self._configFilename
+
+    # audio stuff
+    def setAudioFile(self, f):
+        self._audioFile = f
+    def getAudioFile(self):
+        return self._audioFile
+
+  
+    def getLauncherId(self):
+        return self._launcherId
+    def setLauncherId(self, launcherId):
+        self._launcherId = launcherId
+
+    def setBinDir(self, d):
+        self._binDir = d
+    def getBinDir(self):
+        return self._binDir
+
+    def setNodeNum(self, num): self._nodeNum = num
+    def getNodeNum(self): return self._nodeNum
+
+    def setPosition(self, pos): self._position = pos
+    def getPosition(self): return self._position
+
+    def setSize(self, size): self._size = size
+    def getSize(self): return self._size
+
+    def setCommand(self, command): self._command = command
+    def getCommand(self): return self._command
+
+    def setTargetMachine(self, target): self._targetMachine = target
+    def getTargetMachine(self): return self._targetMachine
+
+    def setProtocol(self, protocol):
+        if protocol == "tvTcpModule.so" or protocol=="TCP":
+            self._protocol = "TCP"
+        else:
+            self._protocol = "UDP"
+    def getProtocol(self): return self._protocol
+
+    def setMasterIP(self, ip):
+        self._masterIP = ip
+    def getMasterIP(self):
+        return self._masterIP
+
+    def setFSIP(self, ip):
+        self._fsIP = ip
+    def getFSIP(self):
+        return self._fsIP
+    
+    def setFSPort(self, port):
+        self._fsPort = port
+    def getFSPort(self):
+        return self._fsPort
+
+    def setBridgeIP(self, ip):
+        self._bridgeIP = ip
+    def getBridgeIP(self):
+        return self._bridgeIP
+
+    def setBridgePort(self, port):
+        self._bridgePort = port
+    def getBridgePort(self):
+        return self._bridgePort
+
+    def setUseBridge(self, doUse):
+        self._useBridge = doUse
+    def getUseBridge(self):
+        return self._useBridge
+
+    def setNWId(self, id):
+        self._nwID = id
+    def getNWId(self):
+        return self._nwID
+
+    def setMsgPort(self, port):
+        self._msgPort = port
+    def getMsgPort(self):
+        return self._msgPort
+
+    def setSyncPort(self, port):
+        self._syncPort = port
+    def getSyncPort(self):
+        return self._syncPort
+
+    def setAppId(self, id):
+        self._appId = id
+    def getAppId(self):
+        return self._appId
+
+    def setBlockSize(self, size):
+        self._blockSize = size
+    def getBlockSize(self):
+        return self._blockSize
+
+    def setBlockThreshold(self, threshold):
+        self._blockThreshold = threshold
+    def getBlockThreshold(self):
+        return self._blockThreshold
+
+    def setStreamType(self, mode):
+        self._streamType = mode
+    def getStreamType(self):
+        return self._streamType
+
+    def setStaticApp(self, do):
+        self._staticApp = do
+    def getStaticApp(self):
+        return self._staticApp
+
+    def setRunOnNodes(self, run):
+        self._runOnNodes = run
+    def getRunOnNodes(self):
+        return self._runOnNodes
+
+    def setAdditionalParams(self, param):
+        self._additionalParams += param + "\n"
+    def getAdditionalParams(self):
+        return self._additionalParams
+
+    def writeToFile(self):
+        s = ""
+
+        # sage bridge stuff
+        if self.getUseBridge():      # using sageBridge
+            s += 'bridgeOn true\n'
+            s += 'bridgeIP %s\n'% self.getBridgeIP()
+            s += 'bridgePort %s\n'% self.getBridgePort()
+        else:                        # not using sageBridge
+            s += 'bridgeOn false\n'
+            
+        s += 'fsIP %s\n'% self.getFSIP()
+        s += 'fsPort %s\n'% self.getFSPort()
+        s += 'masterIP %s\n'% self.getMasterIP()
+        s += 'nwID %d\n' % self.getNWId()
+        s += 'msgPort %d\n' % self.getMsgPort()
+        s += 'syncPort %d\n' % self.getSyncPort()
+        s += 'nodeNum %d\n' % self.getNodeNum()
+        s += 'appID %d\n' % self.getAppId()
+        s += 'launcherID %s\n' % self.getLauncherId()
+        s += 'pixelBlockSize %d %d\n' % (self.getBlockSize()[0], self.getBlockSize()[1])
+        s += 'blockThreshold %d\n' % self.getBlockThreshold()
+        s += 'winX %d\n' % self.getPosition()[0]
+        s += 'winY %d\n' % self.getPosition()[1]
+        s += 'winWidth %d\n' % self.getSize()[0]
+        s += 'winHeight %d\n' % self.getSize()[1]
+        s += 'streamType %s\n' % self.getStreamType()
+        s += 'nwProtocol %s\n' % self.getProtocol()
+
+        # audio
+        if self.getAudioFile():
+            s += 'audioOn true\n'
+            s += 'audioFile %s\n' % self.getAudioFile()
+            s += 'audioType read\ndeviceNum -1\n'
+            s += 'framePerBuffer 512\n'
+            
+        # static app
+        if self.getStaticApp():
+            s += 'asyncUpdate true\n'
+        else:
+            s += 'asyncUpdate false\n'
+
+        # additional params
+        s += self.getAdditionalParams()
+            
+        f = open(self._configFilename, "w")
+        f.write(s)
+        f.close()
+
+
+    def getConfigString(self):
+        """ returns a tuple of strings: (configName, optionalArgs that the app was started with) """
+        return (self.getName(), self.getCommand().split(" ", 1)[1].strip())
+
+    
+    def getAppLauncherConfig(self):
+        """ this returns the appLauncher config format (for applications.conf)"""
+
+        s = ""
+
+        # common parameters
+        s += 'configName %s\n' % self.getName()
+        s += 'Init %d %d %d %d\n' % (self.getPosition()[0],
+                                     self.getPosition()[1],
+                                     self.getSize()[0],
+                                     self.getSize()[1])
+        s += 'exec %s %s\n' % (self.getTargetMachine(), self.getCommand())
+
+        # now the optional parameters
+        if self.getNodeNum() != 1:
+            s += 'nodeNum %d\n' % self.getNodeNum()
+        
+        if self.getStaticApp():
+            s += 'staticApp\n'
+
+        if self.getProtocol() != "TCP":
+            s += 'nwProtocol %s\n' % self.getProtocol()
+            
+        if self.getBinDir() != "$SAGE_DIRECTORY/bin/":
+            s += 'binDir %s\n' % self.getBinDir()
+            
+        if self.getBridgeIP() != "":
+            s += 'bridgeIP %s\n' % self.getBridgeIP()
+            s += 'bridgePort %s\n' % self.getBridgePort()
+
+        if self.getBlockSize() != (64,64):
+            s += 'pixelBlockSize %s %s\n' % (self.getBlockSize()[0],
+                                             self.getBlockSize()[1])
+            
+        if self.getMasterIP():
+            s += 'masterIP %s\n' % self.getMasterIP()
+
+        if self.getRunOnNodes():
+            s += 'runOnNodes\n'
+            
+        if self.getStreamType() != "SAGE_BLOCK_HARD_SYNC":
+            s += 'sync %s\n' % self.getStreamType()
+
+        if self.getAudioFile():
+            s += 'audioFile %s\n' % self.getAudioFile()
+
+        s += self.getAdditionalParams()
+
+        return s
+
+
+
+
+class AppConfig:
+    ''' a collection of all the configurations for an app '''
+    
+    def __init__(self, appName):
+        self._configs = {}   #key=configName, value=OneConfig object
+        self._appName = appName
+
+    def getAppName(self):
+        return self._appName
+
+    def addConfig(self, oneConfig):
+        self._configs[oneConfig.getName()] = oneConfig
+
+    def addNewConfig(self, configName):
+        cfg = OneConfig(configName, self._appName)
+        self._configs[configName] = cfg
+
+    def delConfig(self, configName):
+        if configName in self._configs:
+            del self._configs[configName]
+        
+    def getConfig(self, configName):
+        return self._configs[configName]
+    
+    def getDefaultConfig(self):
+        return self._configs.values()[0]  #return an arbitrary config file
+
+    def getAllConfigs(self):
+        return self._configs
+    
+    def getAllConfigNames(self):
+        return self._configs.keys()
+    
+    def makeConfigFile(self, configName):
+        config = self.getConfig(configName)
+        config.writeToFile()
+
+
+
+    
+
+class AppConfigurations:
+    ''' a collection of all applications and their configurations '''
+    
+    def __init__(self, configFile):
+        self._configFile = configFile
+        self._lastModTime = None  #last modification time to the config file
+        # sageBridge stuff
+        self._bridgeIP = None
+        self._bridgePort = None
+
+        self._appConfigs = {}   #key=appName, value=AppConfig object
+        self._readConfig()
+        #self._printConfig()
+
+
+        # so that we can change the config file without restarting the appLauncher
+        # checks the last modification time so that we don't reload unnecessarily
+    def reloadConfigFile(self):
+        try:
+            lastModTime = os.path.getmtime(self._configFile)
+            if lastModTime != self._lastModTime:
+                self._appConfigs = {}  #empty out the hash
+                self._readConfig()
+                self._lastModTime = lastModTime
+        except:
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+
+    def addNewApp(self, appName):
+        self._appConfigs[appName] = AppConfig(appName)
+
+    def delApp(self, appName):
+        if appName in self._appConfigs:
+            del self._appConfigs[appName]
+          
+    def getConfig(self, appName, configName):   #returns a copy so that it can be safely modified without the destroying what's in the config file
+        return self._appConfigs[appName].getConfig(configName)
+
+    def getDefaultConfig(self, appName):   #returns a copy so that it can be safely modified without destroying what's in the config file
+        return self._appConfigs[appName].getDefaultConfig()
+
+    def getApp(self, appName):
+        return self._appConfigs[appName]
+
+    def getAppList(self):   # returns just the names of the apps
+        return self._appConfigs.keys()
+
+    def getBridgeIP(self):
+        return self._bridgeIP
+
+    def getBridgePort(self):
+        return self._bridgePort
+
+    def _printConfig(self):
+        for name, app in self._appConfigs.iteritems():
+            print "\n----------------------------------------"
+            print "Config For: ", name
+            for name, config in app.getAllConfigs().iteritems():
+                print "Config: ", name
+                print "nodeNum = ", config.getNodeNum()
+                print "pos = ", config.getPosition()
+                print "size = ", config.getSize()
+                print "command = ", config.getCommand()
+                print "target = ", config.getTargetMachine()
+                print "protocol = ", config.getProtocol()
+                print "runOnNodes = ", config.getRunOnNodes()
+
+        print "\n----------------------------------------"
+        print "bridgePort = ", self._bridgePort
+        print "bridgeIP = ", self._bridgeIP
+
+
+    def getConfigHash(self):
+        """ returns a hash of all the configurations without the objects... just tuples of strings and ints """
+        strHash = {}   #keyed by appName, value = a list of configNames
+        for appName, app in self._appConfigs.iteritems():
+            strHash[appName] = app.getAllConfigNames()
+        return strHash
+    
+                
+    def _readConfig(self):
+        f = open(self._configFile, "r")
+        lines = f.readlines()
+        f.close()
+
+        self.appconfig = None
+        self.oneconfig = None
+        self.lineCounter = 0
+        
+        for line in lines:
+            self.lineCounter += 1
+
+            # allow comments with #
+            if '#' in line:
+                line = line.split('#')[0].strip()
+                
+                
+            if '{' in line:
+                appName = line.replace('{', ' ').strip()
+                self.appconfig = AppConfig(appName)
+                
+            elif 'configName' in line:
+                if self.oneconfig:
+                    self.appconfig.addConfig(self.oneconfig)
+                self.oneconfig = OneConfig(line.lstrip('configName').strip(), self.appconfig.getAppName())
+
+            elif 'nodeNum' in line:
+                self.oneconfig.setNodeNum(int(line.lstrip('nodeNum').strip()))
+
+            elif 'Init' in line:
+                lineTokens = line.split()
+                pos = (int(lineTokens[1]), int(lineTokens[2]))
+                size = (int(lineTokens[3]), int(lineTokens[4]))
+                self.oneconfig.setPosition(pos)
+                self.oneconfig.setSize(size)
+
+            elif 'exec' in line:
+                bla, target, command = line.split(' ', 2)
+                self.oneconfig.setTargetMachine(target.strip())
+                if not self.oneconfig.getMasterIP():   #if it has been set, dont overwrite it
+                    self.oneconfig.setMasterIP(target.strip())
+                self.oneconfig.setCommand(command.strip())
+
+            elif 'nwProtocol' in line:
+                self.oneconfig.setProtocol(line.lstrip('nwProtocol').strip())
+
+            elif 'bridgeIP' in line:
+                self.oneconfig.setBridgeIP(line.split()[1].strip())
+
+            elif 'bridgePort' in line:
+                self.oneconfig.setBridgePort(line.split()[1].strip())
+
+            elif 'runOnNodes' in line:
+                self.oneconfig.setRunOnNodes(True)
+
+            elif 'staticApp' in line:
+                self.oneconfig.setStaticApp(True)
+
+            elif 'pixelBlockSize' in line:
+                s = line.split()
+                self.oneconfig.setBlockSize( (int(s[1].strip()), int(s[2].strip()))  )
+
+            elif 'binDir' in line:
+                p = line.split()[1].strip()
+                if not p.endswith("/"):
+                    p += "/"
+                self.oneconfig.setBinDir(p)
+
+            elif 'masterIP' in line:
+                self.oneconfig.setMasterIP(line.split()[1].strip())
+
+            elif 'audioFile' in line:
+                self.oneconfig.setAudioFile(line.split()[1].strip())
+
+            elif 'sync' in line:
+                mode = line.split()[1].strip()
+                if not mode.startswith("SAGE_BLOCK_"):
+                    mode = "SAGE_BLOCK_" + mode
+                    
+                if mode == "SAGE_BLOCK_NO_SYNC" or \
+                   mode == "SAGE_BLOCK_SOFT_SYNC" or \
+                   mode == "SAGE_BLOCK_HARD_SYNC":
+                    self.oneconfig.setStreamType(mode)
+                else:
+                    WriteLog("\n*** Invalid streamType mode on line: "+str(self.lineCounter)+". Defaulting to NO_SYNC")
+
+            elif '}' in line:
+                self.appconfig.addConfig(self.oneconfig)   #save the last config
+                self._appConfigs[self.appconfig.getAppName()] = self.appconfig   #save the appConfig
+                self.appconfig = None   #reinitialize everything
+                self.oneconfig = None
+
+
+            elif 'defaultBridgeIP' in line:
+                self._bridgeIP = line.split()[1].strip()
+
+            elif 'defaultBridgePort' in line:
+                self._bridgePort = line.split()[1].strip()
+
+
+            elif line in string.whitespace:
+                pass
+            
+            else:    # if line is not recognized
+                self.oneconfig.setAdditionalParams(line.strip())
+             
+
+    def writeConfig(self):
+        """ write applications.conf based on the current configuration """
+        self._configFile = getUserPath("applications", "applications.conf")
+        f = open(self._configFile, "w")
+
+        # loop through all the apps and write their configs to a file
+        for appName, app in self._appConfigs.iteritems():
+            f.write("\n"+appName+" {\n")
+
+            # write all the configs
+            for configName, conf in app.getAllConfigs().iteritems():
+                f.write("\n")
+                f.write(conf.getAppLauncherConfig())
+                f.write("\n")
+                
+            f.write("}\n\n#"+"-"*30+"\n")   # finish the app
+
+        if self._bridgeIP: f.write("\ndefaultBridgeIP "+self._bridgeIP)
+        if self._bridgePort: f.write("\ndefaultBridgePort "+self._bridgePort+"\n")
+            
+        f.close()
+
+
+        
+
+
+
+
+
+
+# --------------------------------------------------------
+#
+#                    HELP STRINGS
+#
+# --------------------------------------------------------
+
+HELP_INTRO = \
+"""
+This SAGE Launcher helps you run SAGE and all the related components listed below. Check the components you wish to run with SAGE and click START.
+For more information hover your mouse over any area. """
+
+HELP_FS = "File Server allows you to easily show and organize\n"\
+          "common multimedia files in a SAGE environment from\n"\
+          "SAGE UI. Showing files is as easy as drag-and-drop\n"\
+          "of files onto the UI."
+
+HELP_AL = "Application Launcher takes care of starting SAGE applications\n"\
+          "either on a local machine or any node of a rendering cluster.\n"\
+          "Applications are started through SAGE UI."
+
+HELP_SU = "SAGE UI is the main interface for controlling your SAGE display."
+
+HELP_SP = "SAGE Proxy allows interaction with SAGE through XML-RPC as opposed\n"\
+          "to regular sockets. Primarily used by the SAGE Web UI."
+
+HELP_S = "SAGE itself (i.e. fsManager)"
+
+HELP_RUN = "If checked this component will run when START is pressed."
+
+HELP_EDIT = "Configure component specific settings."
+
+HELP_COMP_STOP = "Kills the component now.\n"\
+                 "To restart it, make sure that it's checked and then press START below."
+
+HELP_INBG = "If run in background, the component will keep running\n"\
+            "even after STOP is pressed and they need not be restarted.\n"\
+            "Usually you want to do this if the components are used\n"\
+            "independently of your local SAGE session."
+
+
+### SAGE help stuff
+
+HELP_S_START = "These are just shell commands\n(each line is executed as a separate command)"
+
+HELP_S_STOP = "These are just shell commands\n(each line is executed as a separate command)"
+
+HELP_S_PROC = "Typically these are SAGE applications and SAGE itself.\n"\
+              "This should not include components as they are killed separately."
+
+
+### AppLauncher help stuff
+
+HELP_AL_PUBLIC = "Makes the appLauncher visible to other SAGE UIs connected to\n"\
+                 "remote SAGE displays. This appLauncher can then be used by\n"\
+                 "remote SAGE UIs to start applications and stream to their SAGE display."
+
+HELP_AL_PUBLIC_HOST = "Which connection manager/SAGE server to report to?"
+
+HELP_AL_APPS = "List of applications currently configured with this appLauncher\n"\
+               "and available for running from the SAGE UI."
+
+HELP_AL_CFG = "Different configurations for a particular application.\n"\
+                  "Configurations usually specify different running scenarios\n"\
+                  "of an application. All will show up in the SAGE UI."
+
+HELP_AL_CFG_COPY = "Makes a copy of the current configuration with\n"\
+                      "a different name but same parameters."
+
+HELP_AL_CFG_STATIC = "This should be checked for applications that are not animated\n"\
+                        "(i.e. do not refresh on a regular basis)" 
+
+HELP_AL_CFG_APP = "This is the actual command executed (could also be a script)\n"\
+                  "Full paths and/or parameters can be specified as well."
+
+HELP_AL_CFG_DIR = "The directory where the app configuration file will be copied to.\n"\
+                  "This must be in the same directory as the executable that's\n"\
+                  "initializing SAIL and connecting to SAGE (basically your app).\n"\
+                  "If empty it defaults to $SAGE_DIRECTORY/bin."
+
+HELP_AL_CFG_MACHINE = "This is the remote machine that the application will be started\n"\
+                      "on. SSH and SCP need to be set up for this to work.\n"\
+                      "If left empty it defaults to the local machine."
+
+HELP_AL_CFG_SIZE = "This is just the initial SAGE window size. Sometimes it is\n"\
+                   "overwritten at startup by the application (such as imageviewer\n"\
+                   "or mplayer) to get the correct aspect ratio for the data being displayed."
+
+HELP_AL_CFG_NUM_NODES = "Specify the number of nodes of this application that are\n"\
+                        "streaming pixels to SAGE (this may or may not include the\n"\
+                        "master node depending on whether it's doing any rendering)"
+
+HELP_AL_CFG_MASTER = "This is the IP address of the master node for your parallel\n"\
+                     "application."
+
+HELP_AL_CFG_BP = "Block size that SAGE splits the image into and streams."
+
+HELP_AL_CFG_BHOST = "Used in visualcasting for sharing applications between displays.\n"\
+                    "Specify the address of the SAGE Bridge that's handling this."
+
+HELP_AL_CFG_BPORT = "Used in visualcasting for sharing applications between displays.\n"\
+                    "Specify the port of the SAGE Bridge that's handling this."
+
+
+### SAGE UI help stuff
+
+HELP_SU_HOST = "Specify the connection manager/SAGE server to connect to\n"\
+               "in order to find the running SAGE sessions. This should be\n"\
+               "the same as for SAGE and the appLauncher."
+
+HELP_SU_AUTOLOGIN = "To automatically log in to a sage session specify its name here\n"\
+                    "(the name should be exactly the same as the one that fsManager reports"\
+                    "to the connection manager... from the first line of fsManager.conf)"
+
+### FileServer help
+
+HELP_FS_ROOT = "All the multimedia files will be organized under this directory.\n"\
+               "Either specify a relative path to $SAGE_DIRECTORY/bin or a full path."
+
+HELP_FS_TYPES = "These are all the file types supported by the File Server.\n"\
+                "All types have file extensions associated with them and all\n"\
+                "the files are checked against that and matched to the correct\n"\
+                "application for opening the files."
+
+HELP_FS_EXT = "List all the file extensions that match this file type\n"\
+              "and can be opened by the specified application."
+
+HELP_FS_APP = "Specify the application for opening this file type.\n"\
+              "When the application is started by the appLauncher,\n"\
+              "the filename to open will always be the last argument."
+
+
+### SageProxy help
+
+HELP_SP_HOST = "Specify the SAGE machine to connect to"
+
+HELP_SP_PORT = "Specify port on which SAGE is accepting UI connections."
+
+HELP_SP_PASS = "This password is only used by the SAGE Web UI to restrict\n"\
+               "access to this SAGE session. Since no encryption is used,\n"\
+               "this is more of a determent."
+
+
+
+#----------------------------------------------------------------------
+#
+#                           IMAGES
+#
+#----------------------------------------------------------------------
+
+
+def GetCollapsedIconData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
+\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
+\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\
+\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\
+\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\
+H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\
+\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\
+\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\
+\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\
+\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\
+zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\
+\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\
+~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\
+\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\
+\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\
+\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\
+0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\
+\x00\x00\x00IEND\xaeB`\x82' 
+
+def GetCollapsedIconBitmap():
+    return BitmapFromImage(GetCollapsedIconImage())
+
+def GetCollapsedIconImage():
+    stream = cStringIO.StringIO(GetCollapsedIconData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def GetExpandedIconData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
+\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
+\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\
+\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\
+\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\
+\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\
+\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\
+\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\
+\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\
+\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\
+\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\
+\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\
+\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\
+\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\
+\x05\x10\x81\xce\xc9\xa8\xf6><G\xd8\xed\xbbA)X\xd9\x0c\x01\x9a\xc6Q\x14\xd9h\
+[\x04\xda\xd6c\xadFkE\xf0\xc2\xab\xd7\xb7\xc9\x08\x00\xf8\xf6\xbd\x1b\x8cQ\
+\xd8|\xb9\x0f\xd3\x9a\x8a\xc7\x08\x00\x9f?\xdd%\xde\x07\xda\x93\xc3{\x19C\
+\x8a\x9c\x03\x0b8\x17\xe8\x9d\xbf\x02.>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\
+\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\
+`\x82' 
+
+def GetExpandedIconBitmap():
+    return BitmapFromImage(GetExpandedIconImage())
+
+def GetExpandedIconImage():
+    stream = cStringIO.StringIO(GetExpandedIconData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def getCheckedData():
+    return zlib.decompress(
+'x\xda\x01\xaf\x01P\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x17\
+\x00\x00\x00\x16\x08\x06\x00\x00\x00+v\x07\x05\x00\x00\x00\x04sBIT\x08\x08\
+\x08\x08|\x08d\x88\x00\x00\x01fIDAT8\x8d\xc5\x95Mj\xc2P\x14\x85\xbf\x17\xad\
+\xd6\x1fp\t\x82#\xc76\x11\x91B\xad\xa3\x16\xa4\xa8\x9d\xb8\x10\xe9*\xa4\xd3"\
+\xddA\xd1\x06;\x97\x96\x8eK7\xe3@1!\xb7\x03m\x88&\x9a\xa8)\xbd!\x83\xf3\xee\
+\xe1{\x87\x97\xfb\x08JK\x10\xd7kL\x0c\xf1\xea$1T\xdd\xac\xc9\x92\xa5o]\x8b\
+\x03\x1e\x04\x06NK^5uqp\\]\xa4\xc8\x17\xdf\xae>)\xb9\x17\x8c\x03\xe3\x8e\xa9\
+\xbc\xfd\xa3\x92\xebfE\xbc\xba\xa0\nL\xef\xdf\xd5\xb6\xcfM~\xf9Z\x97\xbaY\
+\x93mCh\tL\xdb~\xb0\x0b\xd7\xcd\x8a,\xd4\x82%K\xc260\xcc\x8b\x8d\xbef\xef>\
+\xd9d\xcd\xac\x8a\x8d\xed.\xa4%\xbd\x13*\xac\x9e\xdf\xeaez\xf4;\x0f\x81\xa9W\
+\x1b{\xc0\x00\xb6\xd8\x81F/\x14\xc0\xb1\x1c\xfa7\xbb\xc1\x10\xf0A\xe7j\xbe\
+\xa1\xb7\xc7\r\xa0q\xde`\xd0y\xdc\x0b\x86\x1d\xa3\xd8}k\x0b@{t\xe7\x03;\x96\
+\xc3\xe06\x1c\x0c\xa0\x8c\x89\x11mB\x04J\x94x\xe9\x8e"\x81\x01\xb4\x9c\x95\
+\x8bd,\xaa\xe2A`\x00\xad\xac\x95\xf7\x1a\xc4\x12\x8c3\xc3w\xfb"\xc1\xc3\x0cz\
+V\xe7\xa95<\x18\x0c\xa0\x94\x96\xf0]gX%\xd6\xb3:\xc3\xd6\xf3Q`X\'O\x91\xf25\
+\x9a\x99\xe6I`X\'\x07\xb8\x1e_\xc9L\x9b\x01\x90\'\xcfG\xe7\xf3$\xf0\x06\xfc/\
+*\x96?\xd1\xbf\xc0\x7f\x00\x07#sW\xd1Zw\x10\x00\x00\x00\x00IEND\xaeB`\x82\
+\x03\t\xb8>' )
+
+def getCheckedBitmap():
+    return BitmapFromImage(getCheckedImage())
+
+def getCheckedImage():
+    stream = cStringIO.StringIO(getCheckedData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def getUncheckedData():
+    return zlib.decompress(
+'x\xda\x01\xe4\x01\x1b\xfe\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\
+\x13\x00\x00\x00\x16\x08\x06\x00\x00\x00"\x9d\xa7\x7f\x00\x00\x00\x04sBIT\
+\x08\x08\x08\x08|\x08d\x88\x00\x00\x01\x9bIDAT8\x8d\xb5U;O\xc30\x10\xbe\xb3\
+\xa9H\x93\x896\xc9\xd6f\xec\xd0\xb1]`\xe8\x06##\xfc\x84\xfe\x1d\xf8;\xb0C\'\
+\xd8*\xb1u)\x12Q\x1f\x03mB\x1f\xc91D6\x8e\xed\x14\x89\xc7\'EQ\xee\xce\x9f\
+\xbf{\xd8Ad\x1c\xfe\nL7\xe4\x94S\x1a\xb5\xe9\xd0\xa24jS\x1a\xb5i_w\xe8\xf5\
+\xfaJ\xc6\x96\xc8\x84c\xddl\x1eTP\x8bc`\xab\x15d\xae\x0b\xcer)\xed(\xd2\xdc4\
+\x1b\x04\x00\xc0\x93\x04X\x92\x14;!C\x95d_wH\xf8\x00\x00v\xbe\x0f<I\xe0(\xfd\
+\xc0\x92\xb2\xe3\xf9\x02\xb9\x12h\x03\xb3\xf8\xe3\xcb\xcb\xaf\x0fd\\>\x84H\
+\xfa\xb3\xeev)\xf3<\xc3\xbe\r\x02R\xd7"\xe3\xe5\x9a\xe5\xaek\xec\xec\x8e\xc7\
+\x86\xa2\x9d\xef\xc3\xba\xd73\x95\x97\x82\xc2\xd0J\xa8\xe3=\x8a\xa0qw\x8f\
+\x86C\x97\x8a\x8c\xc36\x08\x8c\xb4\x08\x912\xcf\xa3y\xbfo\xa4gMSUXe\xf7\x9f\
+\x9eME\xb64\x05jql\r\xce\xbe)\x81A\xb6i6\xa86\x9bY\x83\x9d\xc9\x04\xd4\x89\
+\xd7\x81\xea\xd9\xd4\x87\x12\xa0\xe8\xb0n\xd3\x87\xd9\xaa\xccF\xa4\xbe\x05\
+\xaa\xd41\x80"\xb5\x9cr#\xe0e8\x94\xcdP\tOF#X\\\x9c\x1b\xf1\x0c\xa08\x8f6ton\
+K\xe9\x08\xc2\xaaF 2\x0ei\xd4&\xb5\x83,IJuY\x9f\x9d\x12\x9bN%\xd1\xb6\xd5\
+\xb2\x0e-\x13\x01\x99\xeb\xc2.\x0c\xad\xbbz\x0f\x8f\x08P\\MUD\x92l\xdbj\xc9\
+\xdapM\x95@\xda\xe9\xc0\xdb`PI$\xd3\x14\xd8\xd7\x1d\x12w\xd3O\x80\xff\xfa\
+\x0f\xf8\r>\x01lo\xba\\\x08x\xd9{\x00\x00\x00\x00IEND\xaeB`\x82\xd6d\xd4\xb4\
+' )
+
+def getUncheckedBitmap():
+    return BitmapFromImage(getUncheckedImage())
+
+def getUncheckedImage():
+    stream = cStringIO.StringIO(getUncheckedData())
+    return ImageFromStream(stream)
+
+
+def getRunBitmap(checked=False):
+    if checked:
+        bmp = getCheckedBitmap()
+    else:
+        bmp = getUncheckedBitmap()
+    return bmp
+
+
+#----------------------------------------------------------------------
+def getStopData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x18\x08\x06\
+\x00\x00\x00\xe0w=\xf8\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\
+\x038IDATH\x89\xa5\x95]o\x1bE\x14\x86\x9f\xfd\xb0\xd7\x1fk\xc7\x9441m#\x12(T\
+\x14\x81PDS\xae\xe0"w\xdcrU\xa9\xff\xaf?\x01n\xb8\xa7v\x89T\x90\xa8\x84R@\
+\x04Gi\x9a\xb8q\xfc\x91\xf5\xec\xcc\x1c.v\xd7\xd9\x8d\x137\x88W\xb2\xb4\xda3\
+\xf3\xbcg\x8e\xcf\x9eq\x1c\xd7\xe3:\xeav\xb4\x008\x0e\x88\xc0\x83-\xdf\xb9\
+\xce>g\x91A\xb7\xa3\xe5/{\x82\t4\x81x\x94+\xe71\x15\x81V\x0e\xebnk\xa1\xd9\
+\x9c\xc1\xde\x9b\xb1\xbc\xda\r\xf8m\xda\xa7\\\xb7l\xdc\x08x\xbf\x15P/{TK\x1e\
+\x0e`E\x88\xb4\xe5$\xd2\xec\x9f*\xf6\x8f5k\xe6\x1d\xbe|0o4g\xd0\xedh\xf9\xc5\
+\x1e\xb2\xd5.\xb1\xbe\xda\xa4^^\\B+p\x1aiv\xf6\xc6\xb4FKs&\x05\x83g]-\xcf\
+\xcd!_\xaf\xd7\xf8`9L\x17,\xe4\xcf$\x02\xcfzC\xbc\xc3F\xc1df\x90\x87\x7fx3\
+\xbc\x1e\xf5\x12u\xff)\x9a\xb8Y\xe0\xb99\xe4\x8b\x15\xff\x7f\xc1\x016o\x85\
+\x9c\x84\x03:;S\x01\xf0!\xa9\xfb\xcb\xd2\x11\x1b+\xcd\xc2b}t\x8c\xff\xea`!P\
+\xaf\xb6\xf1\x97\xdf\x05\xc0X\xc1\x08\xdc\xbd\x19\xf0\xfa\x0f\x8f\xfe(\x12\
+\x1f\xe0\x85\xeaso5\xa0U\xf5\x0b\x9b\xbd\x1f\xbe\x87\'O\xe6\xa9\x9e\x07\xc6$\
+\x8f\x8f\x1e\xc1\xe3\xc7(#\x00\xc4\xc6\xd2\xac\xf8\xbc\xb4Sv\x7f\xf7\x93\x12\
+\xc5\xbe\xe6V\xb3|\xbd\x1a\xe4\xe0\x00N\x18"\x92\x80\x93_b$K\x11\x00n\xb7\
+\xa3\xa5\x1e\xb8\xb4*\xfe\xa5\xbc\x194S\x0e\x0e \xa3\x11\xc4\x8a\xd8\x08\xb1\
+\x11\x94\xb1(cy\xaf\xe12T\x1a7k\xc3\x8a\xefr\xa5.@/J\xa6S\x00\x94\xb1\xc4V\
+\x88\xadP\xf6\x1dFg\x86Y\xda\x9e{\xcd\x86\xcf+w\xb2\x0cn\xd2\x12\xa9dt\xe1\
+\x8a\xa4IZ\xf9\xef\x06\xe9\xc9\xecT\xcd\xe0\xb1\xd6\xc4Z32\x10V\xbd\xe4OVc\
+\x97H\xdb\xb7fyY\xcc\x99L\x00\x88\xa61\xb1\xd6\xb3\xec\x87\x13KX\xb7\xb8\xd9\
+$<\x1e\xc7I6\x92\x9cF\x94Zl\x92v\x93\xd4j\xa8\xd4$\x83[\xady3H*\xe2\x03\xdc\
+\x0fn\xb0\xfbz\xc0\xed\xa5\x00\x93\xb6\\\x8d\xa4\x05\xcd\'\xf7\x17V\xc9\x05\
+\x94["\x8a\xe2\xe2\xfb\xbe\xe6\xe1W\xcb\x8e\x0f\xc9\xa0\xda?6\x1c\xb4\x15\
+\xad\x8aOl\x84\x01.\xcd\xedm\x9c\xedm\xecT\x156\xab\xc9\x04\xe5\x96(\xdb\x04\
+\xda\x93\xe0<f\x85\xbfO\x1c\xee\xac\xd5\x81\xdc\xb0\xeb\xecL\xa5\xc7)\xdf|\
+\xdcH\x16\xa6]\x91)\xeb\x0e\xa0Pk\x9b=\xa7k\xe3\xa9\xa1\xf7\xa7\xc3w\xdf\xb6\
+\x8b\xc3nk3p\x9a\xaa\xc6\xce\xde\x18el\x01\x9c\xef\x8eXk\x94\x16\xa2(\xc6j\
+\x8d\xb22\x07\xff|\xf3\xfc\xea+|\xbe\x8d\xb2\xcfpP\xe1g\x19\xf3\xe9Ju.\xdbL\
+\x198\xaf\x0c~{C\xf8\xa8\xdd\x9a\xbf\x0f\xf2\xfa\xf1\xa7\xb1\xf4\xf4\x98{k%\
+\xc24<\xba\xf01\xfb&\x9e\x81\xf7\x06%\xdc\xbe\xe6\xceZ\x9d\x87\x9f5\xae\xbe\
+\xd1\xf2z\xfa\xebP\x0e\x8e\x84A)\xa2QshT]\x1a\xb5\xa4\xa2\xc3\x89exf\x19N\
+\x84\xfa\xa9\xbd\x14\xfcV\x83\xbc\xd1h\xec2:3\xe8\xb3\t\xe3\xa6\xcbR\\!\xacz\
+\x84u{%8\xd3\xbf\x07\xf8\xd8d\xb6\xf93\n\x00\x00\x00\x00IEND\xaeB`\x82'
+
+def getStopBitmap():
+    return BitmapFromImage(getStopImage())
+
+def getStopImage():
+    stream = cStringIO.StringIO(getStopData())
+    return ImageFromStream(stream)
+
+
+#----------------------------------------------------------------------
+
+def getSageIconData():
+    return zlib.decompress(
+'x\xda\x01s\x06\x8c\xf9\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\
+\x00\x00 \x08\x02\x00\x00\x00\xfc\x18\xed\xa3\x00\x00\x00\x03sBIT\x08\x08\
+\x08\xdb\xe1O\xe0\x00\x00\x06+IDATH\x89\xb5V[oU\xc7\x15^k\xcd\xec\xbd\xcf\
+\xdd\xe7\xd8.6\x17\x03\xe6j\x0c\xae0\xd4Ih\xa0\t)A\xa8IT\xd4(/\x95\xfa\x90\
+\xa8?\xa8}\xe8[[\xa9J\x1b\xb5\xaa\xa0JS\xf5!j\xa9Dn$\x90\x00\xa1\\\xe2\x10HC\
+\x08\x81\xe3\xdb\xf1\xf1\xb9\xec=3\xeb\xeb\xc3\x01\x83\xaa \x15J\xd7\xd3\xd6\
+\xec\xf5}\xeb2#}\x1f\xef<\xfc\xc3\x85\xc5E\x80\x0103=\x8a\xe8Q1\xa3\xaf\\\
+\xb6\xf5\xd9\xd9f\xab\ra\xc1#!\xbf\x1d\xca\xc4\n\xe7\x9c5&"#L\xa4 \xe2GT\xa4\
+\xb7\x0b\xc3\xc6D\xc2\xcc\xacPU\x00\xcbC\x88>\xf0\xae\x96!\x02\x02\xa0\xaa\
+\xac`f\xdb;ef\xb9\xf3\x9b\x88\x88\xf1\xc0\x1b\xbb\x07b\x98\x94\x99@Dd\x97\
+\x13\x94I@\xbd>\x96?\x1e`\x82\xfb`\xe5\x1b\xb3\x1f|C\xf7\x85\xd8\xe5\xa7)\
+\xca\xbd1{\xa3<D,\x03EY\xefPXU\xcd\xb2,\x80X\x19\xc2\xacP\xa3y\x9bx\n>c1\nR(\
+\x91\xd1|R\x88HR\xcd\xd2,\x18\xcf\x1c\x8b@\x88T\x95l\x12G\x1c\x1a\x9d\xae\
+\x10\x1bc,1\x14\x1d\xc7\xc5\xa2\xb7\n\xfa\xf6\xb6M\xc3\xab\xfbE\x08\x81D\x08\
+dO\xbc\x7f\xbeT\x88\x1f{|w1F1.\xe5\xe2|\xa5R\xbat\xf9\xf3#o\x1e\x13\xe2\xa9\
+\x9d;\xd6\x8d\x0e\xda\xd8\xb3\x18\x0b\x13\xe7\xe3k\x9f\xd5?<s\xf5\xe5\x1f\
+\x1cZ\xbfj0sh\xb4\x17\x9a\xdaqi\xe7\xd2\xf9\xaf\xed\xf8\xd8\xc8\xd43#Jj\x94\
+\x85\xa2\x8c;L\xf6\xe2\xf9\xca\xe4\x13\xeb7\xee\xe8\x8b\x9a\xc5\x88L_\xb9rp\
+\xcf\xde\xf7\xce]|\xf5\xf57\x0e~o\xcf\xae\xef\xaf\x0c.\xa3n\xc1S\xd0\x94:iV\
+\xac\x16\x96\x16\x9b?:\xf4tl\xf5\xe4\xb9K\xca1[\xca\xd7dh\xc5\xb8]72\x08\xf8\
+so\xcd\x9d97mH\x9e}~\xe7\xc8\xe6\x1c3\x95+9M\xc3/~y\xa4\x99v\xb6\xac]\xfd\
+\xc5\x17\xf5\xa3\xc7\x8e\xe5l\x92\x14\xc0\xd0O?\x9a;~\xfc\x12\xc7v\xb86\xf0\
+\xe2\xe1}\x0b7\xafv\x83{\xef\xd4\xc7\xcdf\xf3g\xbf\xf9C)_0l\x7f\xf2\xd3\xef\
+\x96\x8ay\x0b1b\xf9\xe6\xd7\x0b7\xeau\x11\xb9\xf0\xd1\xf5\xfa\x8d\xf2B\xb3\
+\xf9\xee\xf1O\xca\x85|\xa3\xd5.\x98h\xdb\xe6\xedo\xbf\x7fz\xfa\xf2\xd5|\xb1\
+\xf4\xce\x07\xd3&\xe1\xe9K33\x8d\x19k\xa3\xe6\xfc\xdc\xc9S\xfd\x93c\xdb\x0b\
+\xb9w\xcf~2\xbdfx\xd8\x10\x03!(\x03\x89\x04\xb6\xce)\x14{\x0fn\x98zr\x84-\
+\xa7i\xb8rqv\xa1\xd1\x18\x1e\xac\x8e\x8d\r\x8fO\xad\xc9\x1b\xfa\xce\xd8\xc4\
+\xc7g\n\'.\x9c\xb5\xaa\xc5\\T\x1b\xccW\xfaK\xcf\x1d\xd8[\xae\x19\x0f\xef\x1d\
+\xb5}\x8b\xc4$69\xf0\xc4\xee\\\x91S\xb4<\xfb\\\x9f\x0f\x99\xb7gNMG\xf1\xa6\
+\xd2\x80$U\x03p\xae\xea\x9e\x1cY\xdbl\xa5\xbb\xf7\x8d\x14k\xc1\xb5\x12\x84\
+\xee\xec\xd2\xc2\xee\x89\x89\\\xf2z\xd6u\xb5\x95\xa55\xa3\xfd\x17N\xd6GG\x87\
+\xca\xab\xad\xcbP.\x13\xb9\xd8{mv\x97\n\xe5R\xb5Th8\x9f\x89v\x9b!\x0eb\x17\
+\x96\xdao\xfc\xe9\x84\xc9\x19\x86\xf1]=ph\xd7\xda\xed\xe9\xd0`\x1f\xb1K\xeb\
+\xf1\x1f_{;\r\xd9\x96u_\xbd\xf2\xd2K\xc5b\xf1V\xeb\x16\xbcs!\x03\xeb\xef~\
+\xff\xb7|>\'0/\xbf\xf2,\x8b\xf3\xdd\xf6\xd6\xb5\xeb\xff\xfa\xe6[\xbf:r4\xc9\
+\x17\x0c\xc8{_-W\xed\xfe\xa7v\x8el\xa8\xfc\xf6\xd7\xc7\xaf~u\x9d\x9c.-\xb6\
+\xd8TI\xc9\xb2\xb4:Y\xbd\xb1H\xc6\xa7\x99k,\xce\x97\xf3\xc9\xc0\xfa\x8d\x99k\
+\x82-\xac4\xe6\x1a\x8b\xb9\x0e{\xb26:}\xfab\x9ae\xe3\x9b\xd7\xbf\xf3\xe1\xd9\
+\xa5F\xb3\xeb2\xf5\xe6\xc7/\xee\xcf\x15c\x1bG\xe4\x93\xf6\x9e\xa7\xc6\xc7n\
+\x8e\x90\t\xabF\xfb\xbc\xf76\xc7.\xa0\\\x8b\xf7=\xbe]A\x93[v\xd4\xe7\xe7\xb6\
+n\xdc\xb4n\xc5\xd0\x07\x9f\x9d\xd5\xd0\x99\x9cZ\xb5\xa2V\xf4\xc4B\xbe\xd6_\
+\x99\x99\xef\xd4\xaa\xb54M\'\xb6n\xde\xb7w\x8a\x89l,\xab\xb6\x95b\x9fX\xcb\
+\x11A6\x8c\x95\xedx\xd5\x91\x0b\x81\x96f\xa2sg\xff900\xd1\xbf!y\xe6\x85\x89\
+\x1c\x15\x1f\xdb\xb4\xeb\xe8\x9f\xff^-\x15\'\xb6o\xf9\xcb\xb1\x7f\xb4g\xc7j\
+\x03\x18ZYVE\xce$\x85bd\xc0CC+>\xbdv\xfd\x85\xfd\xfb\x922\xcda\x0e\x94:\xe7\
+\xae\\\x9c\xe3\x89\xc3\xcfC\x19\xc1\x89X x\xefgg\x96Zi;_.\x0c\rT\xe0a\xa2d\
+\xcf\xe4\xe4\xf4\x95\xab\x95B~\xdb\xe8\xa6\x9f\xbf\xf6j\xb5\xd4W\xab\xf6\x19\
+\x06\x04\xd6\xc4I\x92\xa8\xd3\\\x12\xb9\xe0\xab\x95\xf2\x97\xd7o\x92U\xf8\
+\xe0\x95\xd2\xd4\xd9\xf9\x85\xa5\xb9\xd9\xf9 \xc4\x10""\x811b\x12\xe9v\xbb\
+\xff\xfa\xbc\x1d\x98XH\x9df!4\n\xc9|\xb3].\xe4;\xddv\xf3Z\x13\x86\x00\x108\
+\x12\xb3rE\xed\xd6\xac:\xd7\xbd\x8c\xd0Z\xea\x1a&\x02\x8b\xc8`\xb5j\r\x8b\
+\x8d\xd8\x08\x1b\x15\x00j\x84\xc0\x02\x80\x83\x89"\x16\xb1\x1an\xdc\xba\x01k\
+\xeb\rJ\xf8V\x08\x81\x19\x12Y\x16\xe2@\xccL\x1cn\xd4\xe7\x8cae\x81\x0f\xb9(\
+\x860\x00V\xa8\t\x16\xc4L\x96\x01\x05\x89\x11V\xcfdU\x94aY\xc8 \x80)0\xc4;O\
+\x1c\xc8\x0b\x1b%0\x1b(D<\xb3\x81\x1a\x12\n\x04\t\xc2\x02(X\t\xe2`,\x91\xb5D\
+D\x1c\x88D\r\x03$l\x94!j\x08\x80\x90\xb2\x12\x89h\xc4\xa4\xc2d@\x81\x95\x99\
+\x05\x8e\x85\x03\x0c\x81\x8c\xa8\x80\x03\x91\xb0:\x82\x11\x10\x0c!\x12\x90\
+\x04X\xe1\xdbbc\xf4\x1eW\xc1\xa0\xdb\xfa\'\xbd\x0e@$D\xb8\xabE\x02\x90\x10\
+\x88\x08`"2 \xcf0`\xea!{TF,p\x1b\xa1\x82e9}\x08\xc9\xbcW\xd4\x96\xe5\x0c\xc0\
+7k\xf2CH\xe6\xfd \xf6?2\xeeZ\xa3\xff\xa1\xc6\xbd\xc6\xe2v\x01\x00\x01l\xf8\
+\x8e\xf5\xb8G\xb5\xff[\xf6;\x10\x01\x05\x10\x11z\x97a\x01@X\x88\xa1\xa4|\xf7\
+>\x1e\xb4\xfde\x88211\x0b\x83\x08\x80\r\xc1QP\x08K\xaf\xea\xa3\t(\x88\x15!8\
+\xfb\xad\x81\x81(\x8a\xfeO\xf6\xbdZ\xa9\xfc\x1b\'\x9f`y\x8c\\\xb8\xf0\x00\
+\x00\x00\x00IEND\xaeB`\x82e\xd2)\xef' )
+
+def getSageIconBitmap():
+    return BitmapFromImage(getSageIconImage())
+
+def getSageIconImage():
+    stream = cStringIO.StringIO(getSageIconData())
+    return ImageFromStream(stream)
+
+def getSageIcon():
+    icon = wx.EmptyIcon()
+    icon.CopyFromBitmap(getSageIconBitmap())
+    return icon
+
+
+#----------------------------------------------------------------------
+def getSageData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01u\x00\x00\x01;\x08\x06\x00\
+\x00\x00"\xaf\x11\xd4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00 \
+\x00IDATx\x9c\xec\xbd{x\x1c\xe5y6~\xcfaO\xda\x83v\xad\xf5J\xb2\x0e\x16\xb21\
+\x08[\x8aA\x96c\x08\xf6U\x88\x82\x81\x12N\r\x816!?\xd2\x03Iq\x93&_RZ\xda\x92\
+4\x906m\x9a4|I\xe0KH\x9a\xf2\x85\xf0\x05Jj\x08%\t6\x0e\xa6\xb6\x03\xc4\xb6\
+\xc0\xf8$\x03\x96,\xeb`I\xeb\x95w\xb5\x07\xedi\x0e\xbf?F\xef\xec\xcc\xec\xec\
+jw\xb5+\xad\x94\xb9\xafK\xd7\xca\xab\xdd\xf5\xec\xcc;\xf7\xfb\xbc\xf7\xfb<\
+\xf7C\xb9\xba\xbbE\x180`\xc0\x80\x81e\x01z\xb1\x0f\xc0\x80\x01\x03\x06\x0c\
+\x94\x0f\x06\xa9\x1b0`\xc0\xc02\x82A\xea\x06\x0c\x180\xb0\x8c`\x90\xba\x01\
+\x03\x06\x0c,#\x18\xa4n\xc0\x80\x01\x03\xcb\x08\x06\xa9\x1b0`\xc0\xc02\x82A\
+\xea\x06\x0c\x180\xb0\x8c`\x90\xba\x01\x03\x06\x0c,#\x18\xa4n\xc0\x80\x01\
+\x03\xcb\x08\x06\xa9\x1b0`\xc0\xc02\x82A\xea\x06\x0c\x180\xb0\x8c`\x90\xba\
+\x01\x03\x06\x0c,#\x18\xa4n\xc0\x80\x01\x03\xcb\x08\x06\xa9\x1b0`\xc0\xc02\
+\x82A\xea\x06\x0c\x180\xb0\x8c`\x90\xba\x01\x03\x06\x0c,#\x18\xa4n\xc0\x80\
+\x01\x03\xcb\x08\x06\xa9\x1b0`\xc0\xc02\x82A\xea\x06\x0c\x180\xb0\x8c`\x90\
+\xba\x01\x03\x06\x0c,#\x18\xa4n\xc0\x80\x01\x03\xcb\x08\x06\xa9\x1b0`\xc0\
+\xc02\x82A\xea\x06\x0c\x180\xb0\x8c`\x90\xba\x01\x03\x06\x0c,#\x18\xa4n\xc0\
+\x80\x01\x03\xcb\x08\x06\xa9\x1b0`\xc0\xc02\x02\xbb\xd8\x07`\xc0\x00\x01MQe\
+\xf9\x1cA\x14\xcb\xf29\x06\x0c,E\x18\xa4n`Q\xa1%r\x96a\xe6\xf5y\x1c\xcf\xab>\
+\xd3 \xf8\xfc(t"5\xce\xe3\xd2\x81A\xea\x06\x16\rz\x84\xce\xf1\xbcL\xec\xac\
+\xc9\x94\xf3\xbd\\:\r\xd6d\x02\x97Ng\x9eS\xbc\x97\xe3y\xf9\xff0\x08)\x1b\xc5\
+\xae\x8a\xc8\xeb\x8dsY\xfd0H\xdd\xc0\xa2@I*\xca\xe8\x9ce\x98\xbcd.\xbfn\xf65\
+\x85\xbc\xd6 v\tzD^\xcc\xca\xc8X\x05-\r\x18\xa4n`\xc1A\x88AK(Z\x82\xb6\x9a\
+\xcds~V"\x95R\xbd\x9fD\xeeF\xc4\x9e\x81\xf2|+W3z \xd7@\xb9\x02\x92\xff\xa68\
+\xa7\xe4\xb3\x94\xf8]=\xbf\xd5\x06\x83\xd4\r,(r-\xfb\t\x99h\x89\xdcf\xb5\xe8\
+\xbe>\x9eHf\xbd>\x91J\xa9H)\x17\xf9\xfc. \xd7^E!\xd2V\xbe\xbfs\xe9\xb4\xea\
+\xb3\x94\xe7\xf6wy\xe2\xac&\x18\xa4n`Q\xa0G.J\x82\xd6\x92\xb9\xddfC,\x1e\x97\
+\x1f\xbd\x1e7b\xf1\xb8\xfc\xf7x")\xbf_I\xee\xe4\xff"\xd2\xc1r%\x9d\x9c\x93e\
+\x9e\xd5P!+!\x02\xb2"\xd2\xeec\x142i\x96+\xab\xa9\x14,\xd7\xeb\x9d\x0f\x94\
+\xab\xbb\xfbw\xef[\xff\x0e#\xdf\r\xa6\xbd\x01\xc42\xde\x10\x14E\xa9H\x95\xa6\
+(\x95~N\x08FI\xe6v\x9bm\xce\xcf\x8d\xc5\xe3r\xd4\xae\x94b\x08\x08\x01\x11\
+\xe2)\xf7M\xae\xfcN\xa2(B\x10\x04\x08\x82 \xff\x9d\x17*\x7f{14\x854\xc7I\xc7\
+C3\xaa\xe7\xa5\xe72\xe5(&\x96\xcd\xda\xb7\xb0\x9a\xcd9WD@fU\x04\xa8\xcf\xb1\
+\x9eD\x93\xe28\xd5y \xdf_\x10xp\xb3\xc7\xb8P`Y\x164\xcd\xa8\xce\x03M\xd3\xf2\
+X\x04\x96\'\xe9\x1b\x91\xfa\xef\x00\x04Q\x84(\x08Hs<\x04!\x13U\x91\x9b\x8ce\
+\xb3\x87\x81\xf2f\xa8\x148\x86\x01\x95N\x83\xa2(9\x9b\x05\x90\x88]I\xe8.\xa7\
+3\xeb\xbd\xe1H\x04\xa3\x93~Yf\x11D\x11\xa2(\xca7lV\x84Z\x86h]\x10E@\x14\xc1\
+\xf3<xA\x94\x89\x8aeY\x98X\x16&\x9a\x81\xd3\xe1\x98\x93$\x17\n\xb9&E\xe5\xf9\
+t;\x9c\x08E#\x08G"\x00\xd4\x93$ ]\x0b\xbd\xef\xa2\x95\xba\xa4\xf7%\xc0\xb2,\
+\xac\x16\x0b\x9c\x0e\x07<.\xa7|\x1c\xe4\xfft;\xb2\xafe%\x10\x8aJ\xdf\'\x1c\
+\x89\xc8\xdf)\x91J!63\x83\x99x\\\xben4\xcd\xc0lbAQ\x14\xa8E\\Q\x94\x13\xcb\
+\x8e\xd4i\x8a\x02/\x08\xe08N\xbe\xf1\x96"L,\x0b\x8b\xd9\\2\x01\xd1\x14\x85d*\
+\x854\xc7\xc1\xc4\xb2\xa8u\xb9\xd0\\\xefCk\xe3*\xb4\xaej\xc4\nW-\x00\xa0\xde\
+d\x82\xbd\xc1\'\xbf\xcf\xdb\xe8@`<\no\xa3\xa3,\xdfC\x0b\xf2\xd9\x81\xf1\xa8\
+\xfc\\l\xc2\x8f\xc9\xd9\xa8opt\x14\xe1hT\xbe)\x95 \x84\xf0\xe6\xc9\x93\x08\
+\x04\x83\x00 \xdf\x88\xca\x9bR\x10E\xa48N\x97\xdc\x8bE:\x9d\x96\xa3`\x13\xcb\
+\xc2n\xb3ae\xdd\n4\xfa|\xe8Z\xb7\x0e+\\\xb5hoi\x82\xb7\xd1\x01/\xed\x81\xb5\
+\xae\x06\xde\xda:\xf9\xfd\xf5\x1e\x1f&\x83\xfeE{\x9c\xeb8\x00\xe0o\xbe\xfe-<\
+\x7f\xfc\x84\xfcZ\xe5\xca\xa3\xce\xed\x86\xd7\xe3\x96\xaeS<\x0e\x9b\xd5"K]\
+\x89T\n\x91h\x14&\x96\xc5\xfa\x8b\xd7\xe2\xea\xeenlZ\x7f\x19\xbc\x8d\x0e4\
+\xafl\x9a\xf3<T\x02\xda\xcfV\x9e\x03\x00\x18\x1d\x1cA@\x08\xe2\xec[\x83x\xfd\
+\xcc\x19\x1c\x7f\xef]\x9c>;\x8c\xe8\xcc\x0ch\x9a\x81\xc5lZ\xf2\xe4\xbel\xe4\
+\x17\x9a\xa2\xc0\xf1<\xa2\xb1\x18\x00\xc0\xe9p\xc8\x03\xd2\xe5t\xc2\xedp\xc2\
+\xe5\xa8\x0cQU\x02\xc7\xdf{\x17\xfd\x03\x83`J$\xa5\x99x\x1c&\x96\xc5\r\xdb\
+\xb6\xe1\xf6\x0f}\x10\x1b\xbb.\xc1\xfa\xb6\x8e\x9c\xaf\xd7#\x82B\xa0|O1\x843\
+\x17&\x83~\x8c\x0e\x8e\xe0\xd4\xd8\x08\x06G\xc6p\xe4\xd4)\x00\xc0\xf0\xf8\
+\xb9\xa2\xce\x8b\x92\xd8\x95\xdao\xbe\xc9\x92\xa6(\xcc$\x92H\xa5\x92\xb0\xd7\
+\xd4\xa0uU#\xde\xdf\xf5>\\y\xd1E\xf8\xc0u[u\xcf\xa3\xf2\xbc\x05\xa6\xa7\xe4\
+\xdf\x13S3\xb0\xd6\xd5`\xf4\xfc\x18\xbc\xb4\x07\x01!\xb8`\x8f\xcd+\x9b\x90\
+\x98\x9a\x91\x8f\xc5ZW#\x1f\x0f\x00\xfcf\xf7~<\xf2\xf3\xe71|n\x1c\x14M\x83\
+\x02\xb2\x08M\x10\x04\\\xda~\x11\\NgV4\x1f\x8d\xc5\xb0\xad\xa7\x07\xf7~\xe2\
+\x16l\xef\xe9\xcdy>\x94\xe7Dy<\xcac\xd5C0>\x05\x8f\xad\x0e\x81\xf1(\x18wR\
+\xf75Zxlu\xaa\x7f\x93\x89\x16@\xd6$C\xd0\xd7\xd7\x87\x9f\xec\xde\x85]\x07\
+\x0e\xa0\xff\xf4\x00lV\xeb\xbc\x02\xaa\xc5\xc6\xb2!\xf5\x99\xd9M\xb3m\x9b{\
+\xd0\xb5n\x1d\xae\xef\xdd,G\x0b\x95\x8a\n*\x89\x87\x1f}\x14_\xfa\xf6\xb7\xe1\
+v\xb9\x8a\x1a\\4E!:3\x83\xe6\x86\x06|\xf5/?\x83\x8f\xdd|+\x80\x0cI\xbe\x17;\
+\r\x00\x08\xc5B\x88Fc\xba\x9f\x11\r%\xe0p[u\xff\xe6\n: \xb4\x88\xa0G(\x84=Q\
+\xf9\xdf\x00@\x8fP\xf2\xef\x00\xe0L\xd7\xab\xde\xcb\xb8\x93\xe0C\x16\xf9\x06\
+%7\xa0\xf2\xc6\x0327\x9f\xf2\xba\x9d\x18\xea\xc7\x91\xa3\xef\xe0\x1f\xbf\xff\
+8\x86F\xc7`* ?\x9d\xc0\xac\x90\x97\xe6\xd2\xd6\x05A@4\x16\x83\xd7\xe3\xc1M\
+\xd7\\\x83\xde+\xdf\x8f\xde\xadW\xc9\xc7B\xcec@\x08\xe2L`\x00\xd1h\x0c\x11q\
+\x1a\xb1d\x0c\xf1d\x12\x9c i\xceI.\x05\x8e\xd7K\x0b4\xa9\x9e/\xf4\xdf\xca\
+\xc7|`g5u\x86f\xc0\x0b<\x18\x9a\x01K+6\xa0-\x16\xd8-v\x1c\xf8\xd5Y\xbc\xf2\
+\xda\xeb0\x9b-\xb0Zro\x98\n\xa2\x08GM\r.[\xbb\x06@F\xce\x00\x80\xbf\xfb\xd4\
+\xbd\xaa\xf1\x15\x98\x9eBbjFE\xd2\xc1\xb8D\xe6\xe4\xba\x87b!\xd5\xe7k\xc7`4\
+\x94\xc8y,!!\n\xea\x82\x03\xe2\ni\x95\x17N\x85u_\x97BH>O\xe4\\\xb2\x8c\t,\
+\xcd\xc0\xc2\xda`\xb3X\xd0`]\x85\xe6\xfa&\\l_\x8b\xe6\xf6\x16\xd4{|81\xd4\
+\x8f\x1f\xfe\xf49\xfc\xf0\xd9\x9f!\x95\xe6Pc\xb5,Ib_\xf2\xa4\x9eN\xa7\x11O$p\
+\xedUW\xe2\x8fo\xbb5\xe7\rH\x06W5#\x14\x0b\xe1"\xef\x1al\xef\xe9-\x89\xd4\t\
+\xa1_\xdc\xb6\x1aO>\xf40\xba\xbb\xbbqb\xa8\x1f\xbf:\xf4+\x9c\x9c\x18\x84\xc0\
+\xc4@\xf3\xf6\xbc\x9f\xe12\xbb\xe4\xdf\xc9\rD]p\xa0\xd6\x9b\xfdZ&U\x0b\x9bO"\
+\xe8\xb8\xdf"\xff\xae$~%\xc9\x03\x12\xd1k\xa3.\xbd\xe8\n\x80*\xc2"\xd7\xb4\
+\xe7#\x7f\x80\x13\xef\x9d.;\xa9\x8b\xa2\x88x"\x81\x1a\xb3\x05\xb7_\xbf\x1d\
+\x7f\xf1\x91\x8f\xa0\xbb\xbb\x1b\x804\xa1\x1c\x1b>\x8a\xfe\x89\x93\x08\x84/ \
+\x96\x8af\x11\xb6\x92l\xf5\x88\xb5R`i38!\xa5"n@"o%\xec\x16\xe9\xba;\xa9Z\x8c\
+^\x08\xe0\xa9\xffx\x05\x89t\x1a,M\xcf=\xbe\x04\n\xeb\xda[\xd1\xda\xb8\n\xc3\
+\xe3\xe7\xe0r:q\xff}\x1f\xc7\xf6\x9e^\x99\xccG\xcf\x8fe\xbd\x8dD\xda\xda{\
+\x8f\x0fY\x101M\xc2\x99\xaeG\xc44)\x8f\x13e\xa0\x10\xf6D\x11\xf7[\xc0\x9b\
+\xa7u\x0f)$Du\x9f\x0f\xa7\xc2\xb0\xd9(\xc4\xe3"L\x96\xcc5\xe2geXN\xe0\xb3&M\
+\xaf\xb3\x0e\x9bV\xf7\xe0\xaemw\x02\x00\x9ez\xe1y|\xf1_\xbf\x89\xc0\x85\x0b\
+\xa8)`\xb3\xbe\xda\xb0\xa45\xf5\x99x\x1c\xde\x15+\xf0\xc8\x8e\x1d\xb8\xf7\
+\xde{\x01H7\xe0\xdec{q\xf8\xec!\x04"S\xba\xd1R5\xe3t\xe0=\xd5R\xb6\x98H\x81D\
+\xe8\x84\xd0w\x1d\xda\x83\x9f\x1ez\n\x1c\x9f\x86\x19n\x15\xa1\xdbl\x14L\xbcz\
+\xd3\xcaM;\x10\x12\xa2p\xd3\xb32\x95\x17\x00\x1c\xb3\x8f\x12\x08\x91kI\x1c\
+\xbe(\x1c\x0e\xbb\x8a\xc8\xc9#!re\x94\x0e\xe4&s\x00\xaa\xc8\x9d,\xdd\x03\xd3\
+S\x08\x04\xd5\x91^\xa1 \xa9x\xda\rS\xb2\x07\x13\x89F\xb1\xa9s\x03\xbe\xfa\
+\xd7\x7f.\x9f\xff]\x87\xf6\xe0\xb53\xfb1\x11\x9a@,\x19\x93\x89\x9b\xa5\x19\
+\x15q\xe7C9\t]K\xdc\xb9\x9e\xcfG\xe8\x0e\x87\x1d\xbfy\xe67\x88\xc5\xe3`Y\xa6\
+\xa0\xf1\xc5\x8b\x9c\x1c\x9d\xbb\x9cN\xfc\xf1m\xb7\xaa\x08=15\xa3+\xa3h\t]{\
+\xfd#\xa6I\x00P\x11:\x00\x99\xd0m\xbe$\xa2:\x97;\x1f\xa1\xbb\xcc.\xa4\x11\
+\x81\xcdF\x01PNx\xd2\n\x8a\xa1\x19XX\xe9|\xf1\x02\x0fN\xe0\x11\x88L\xe1\xc5\
+\xb7\xff\x1b\x87\xcf\x1e\xc2\'\xb7\xfe\t>v\xf3\xad\xf06:\xf0\xf1\xcf\xfc=\
+\xc2\xb1\x99\xbc+\x99j\xc4\x92%\xf5p$\x82\x8e\xb5kT\x11\xe9\xfe\xfe}x\xe3\
+\xcc\x1b\xf22\x95U\\\xc0\xa5\x80X2&\xdf\x80\x04\x85fk\xa4\xd3i\x98X\x16_\xfd\
+\xcb\xcf\xc8\x84\xfe\xe4\x1bO\xc0\x0c7jm\x92N\xaa"q\x9d\xfd\xe3\\7\x8b\x12JB\
+\'\x11\x95,\xc38D\xe9\xf7\x11)R\'\x91\x18A\xc44\t7\xa4M7>d\x01t\x82 \xa2\xfb\
+\xe6\x832Eo.\x98Y6+\xb7Z\tN\x10\x10\x8dFq\xfbu\xd7\xe1\xb1\x87\x1eD\xbd\xc7\
+\x87\xbe\xbe>\xfc\xf4\xe4O1\x11\x9a\x90\xc7\x91\xf6\xba,$r\x919\x81\xcdbA<\
+\x99\xcc"s\x00\xaa\xe3v8\xec8\x1dx\x0f\xa3\x93\x92\xdeMQ\x85\x9dG\x8a\xa2\
+\x10\x0cKz\xfa\x9dW^%K.\x84\xd0\xb5{\x06\x04\xdaH\x9dL\xeczQ\xba\xd0"\xc25\
+\xe2\x90\x89\x9d\x8c3\x98\xb3\xe5\x18e\xf0\xa1\x1c\xb36\x1b\x854"\x88\xc7EE\
+\xb4\x0eY\x12\xd3\x82\xa1\x19y\xd2\xb5\xb0fL\x84&\xf0\xb5\xff\xfeG\xdc\xbd\
+\xe5\x1el\xef\xe9\xc5#\x7f\x1b\xc5\x9f=\xf8e\x08\x82P\xd4\x98[l,\x9d#U`&\x1e\
+\xc7\xa6\xce\rx\xf6\xd1o\xca\x04\xf6\xed\xdd\x8f\xe0\xc0\xe9\xfd\xf2\rha\xcd\
+\x15]\xf6V\x1b\xe2\x89\x04\xee\xbc\xf1F|\xec\xe6[qb\xa8\x1f?=\xf4\x14\xccpg\
+\x067\xefD\x9a\x89\xe4\xd4!It.G\xe9:p\xb8\xad\xaa\x08\x9d\x909\x90\x89\xb6\
+\x1c\x0e\xbb\x9cM\xa3\xbcy\x81\x8c\xc6\xee\xb1\xd5eI0\x84\x10\x94\x1by\x80zs\
+\xcb[[\x87\xf6\xd6\x16\xa4\xb9\xe22\x9a\xacf\xb3n\x85\xa4(\x8a\x88F\xa3\xb8\
+\xe7\xf6\xdb\xf1\xd8C\x0f\x02\x00\xbe\xf7\xab\xef\xe3;\xbf\xfd.\x02\x91\xa9\
+\xaa\x18G\xf9\x08\xddf\xb1\xc8D\xae\x17\x9d+\t\xddI\xd5\x82\xf6Q\xe0f\xcc\
+\xe0\xd2\xe9\xa2H\x8a\xa6i\x04.\\\x00\x00\xdcr\x87D\xe8\'\x86\xfa\x01($2\xc5\
+*\x8b@\xb9\x12\xe3C\xd2\xf11\xee\xa4<&\x9c\xe9z\xd5~\x0c!tW\xd0!\x8f3&U\x9b\
+\xf3\xb8\xb4A\x88\x89w\xc2\xc4;e\t\xd1f\xa3\xe6\x9c\x10\x95\xb0[\xec`\x19\
+\x13\x9e\xed{\x1a\'\x86\xfa\xf1\xb1\x9bo\xc5\r\xdb\xb6!\x91L.j\x01U\xb1Xr\
+\xa4\x1e\x8eD\xb0\xb1\xe3R<\xf1\x8d\xafb}[\x07\x9e\xde\xf7\x0c\x9e|\xe3\t9\
+\xca\xfd]"r\x82t:\r\x9b\xd5\x8a\xbbn\xff \x00\xe0?\x0f>\r\x00\xb3K\xd0\xcc#\
+\xa0\xd6\xcc\x95P\xc9.:\xd0\xbb\xb9H\xa4\xae\x95]\x94$\xce\xb8\x93p\xdb\xdd\
+\xaa\xa57\x89\xe0\xb4\xd0n\x98\x02R4\xa8$\xf6\xaeu\xeb\x8aNSM\xa4R\xba\x91z<\
+\x91\xc0\xa6\xce\r\xf8\xe7\xfb?\x8fz\x8f\x0fO\xee\xf9\x89\x1c\x18,\xe6\n\x8f\
+\x10\x91\x1e!\x11"\xcf\x17\x95kW\x15Dv\x11\xfc"\x9aWx\xe1\xb0\xdbU\x05R\x85\
+\x80\xd44h3\xa4\xc8\xaaJ/\x83E)\xbd\x90k\xaf\x8d\xd4\x81\x0c\xa1;\x1cvyLi%>-\
+r\x8d\xd5p*\x8c4#E\xeb\x00\xe4\xc7B\xc9\xdd\xc2\x9a\x91H\'\xf0\x1f\xfb\xff\
+\x1d\x00\xf0\xd0\x17\xee\x83\xa3\xa6fIYM,)RO$S\xf0z<\xf8\xea_\xff\xb9L\xe8/\
+\xbe\xfd\xdf\xb0\x9a\xac\x8b\xba<\xae$\n\xd2<\x05\x11m\xcdM\xd8\xb8\xb6\x0b\
+\'\x86\xfa129%\xeb\xe7$z!\xbfk\xe1\xa6\x1d\xf2\x8f\x1e\x98T-\x1cnk\x96\xec\
+\x02@\x97\xd0\x9d\xe9z\xd0#\x94|\xd3\xf2!K\xc1Z\xba\x9e\xf4B\x08\x9d\xe8\xea\
+\xd7\xf7n\x86\xcdj-\x88\x94h\x8a\x82\xc3.\x9d\x07m\xa4\xce\xf1<\x1c55\xf8\
+\xde\x03\x7f\x8bz\x8f\x0f\xdfx\xf6\xdfpd\xe2MXM\xd6\xaa\x08\x0c\xf4tr%\x91\
+\x93H\x9c\xfc\\\x08%\x10\x08_\xc8\x8a\xce\t\xa1G\xa31\xd0>\n\xcd\xf5M\xb8\
+\xe2\xb2\xcb\xe4\xdc\xfb\x82\x8f\x87e1<~.+%U\x19\xa9\xe7\xd2\xd4\x95\xd7[\
+\x19\xa9\x03\x90\xa3u2\x8e\x94\xd1\xba,\xc1\xe8\x80D\xe9\xdaq\xeb2\xbb\xe4h\
+\x9d\xc80d3\xb9P\xd8-vL\x84&\xd0\xd7\xd7\x87\xf5m\x1d\xb8b\xc3\xfa%\x15\xad/\
+)RO\xa5\x92\xf8\xec\xddwc{O/v\x1d\xda#\x13z5\xdc\x84\x95B!\x03I\x10xt\xb4\
+\xafA\xbd\xc7\x87c\xc3G!0R\x9a\x98\x89w\xca\x91K.\x90\x9b#\x97\x9e\xce\x9b\
+\xa7\x11\r%dB\x8f\xfb-\xaa\x1b/\x1a\x8d\xc9\xd2\x0b E\xe9B\x8b\xa8\x8a\xc6\
+\xb4R\x8b6\x1bBI\x06Z\xe9\x85\x909!\xf7\x8dk\xbb\xf0\xa1\xab\xaeB4\x16\x9b\
+\xf3\xdc\x90\xfct\xad\xc7\t\xcb0\x88\xc6b\xb8\xe7\xf6\xdbd\xf9\xaeZ\x08}.2\
+\x07$\xd2\x89%c\x18\x99\x9cB ,\xc9"g\xdf\x8cb\xefs\x03\x002d\xae\x84\xc3a\
+\x87+&=w\xc7\x1dW\xa3\xb9\xa1\x01|\x11\xd1\xa7\xc5lF\xff\xc0 \xfe\xf9{?\xc4\
+\x89\xa1~\xd5\xea\t\x90\xae[\xf3\xca\xa6\xac\xf7)5u"\xc1\x90\xb1\x01H\x85g\
+\xd1h\x0c\xd1hL\x1eWq\xbf\x05\xe7\xa8\x00\xa2\xa1\x84*\xfbe: \x8dS\xe5X\x1dN\
+\x9c\x03 E\xe8\xda\x1f@\x8a\xd4\xe3q\xb1(\x19\x86`\xef\xe0\xff\x00\x90\xf6\
+\x11\xa4b\xc6\xe2V7\x8b\x85%\xb1QJ\x8aA6un\xc0\xbd\x7ft\x07&\x83~\xbc\xf0\
+\xf6\xcf\xc12\xa6E\xbf\t\xab\x014\xcd\xa0uU#\x00)-\x92\xe3\xd3\xa8\xb5Q\x08\
+\xc73\xe9]\xb0IKR=\xf9e8q\x0e.\xb3+\x8b\xd8\x95Q\x90D\xee\x00\xcc\x89LF\x82\
+\x07\xb3\x91T\x0c\xf0@\xde\xe8")\x8d$\x1a\x0b\xc5BY\x190\xca\x08N.\x9a\x99\
+\xd2\xcfzQ\xa2\xde\xe3\x93\xbfk\xbeU\x8c(\x8a`M&\xd8\xac\x16y\x93\x8f@2\x04\
+\xf3\xe0O\xff\xf06\x00\xc0\xcb\xa7^\x02P\xdeL\x15 \x93]\x01 o\x16\x962\x1d2\
+\t\x85\x950\xcd\xc8\x11&!%\x9b\xc5\x82@\xf8\x02~\xf9\xd3\x93\x08\x85\xc3\xb0\
+Z\xad\xf0\xb8\x9c\x88\'\x92\x18\x1a\x1d\xc5\xf1\xfdk\xf0\xa1\x1bW\xc9\xf9\
+\xdf\x0e\x87\x14\xb9\xd3>\n\x98M\t\xf7\xd8\xeap\xcbG\xdf\x8f\xff\xf3\xdd\x17\
+ab\xd9\x82V\x83\x0c#e\xca|\xf7\'O\xe1@_\x1f\xbe\xf0\xd9\x8f\xe2\x9a\xcekT\
+\x9b\xa5\x85f\xc1\xb8\xedn\x00I\\d[#gV\x91J\xe3`|\n\xa8\x07\xc8\x1f\xc8x\xe1\
+C\x160\x97\xa87Z\x01\xa86\xe2\x01u\xde{D\x9c\xc6t0\x8dp*<+\xc3\x98d)r\xae\
+\xc8\x9deL\x98\x98\x9d0\xba\xbb\xbb\xe1v\xb9\x90L\xa5\x8aJ\xa5],,\tR\x17D\
+\xa9\xdc\xffs\x9f\xb8\x1b\xf5\x1e\x1f\xbe\xf7\xab\xefc:\x1e\\\xb6\x92K)\xe8\
+\xa8\x93n\x82\xf1\x884\x109!\x05\x93\x05\x00\xcc2\xb1\x93\xec\x00 \x13\xc5\
+\x03\xc0\xe6\xb5\x9dp\xdb\xdd\xb8\xd8\xbe6K\xd3\xce\x05\x12Ek\xa3i\xad\x06\
+\xae\x07eua@\x08\xca\x95\x85\xda\xff{\xae\xcf\xc9\x07\x11\x90\xbdGHI;\x01\
+\xd9T^\xdf\xd6\x81]\x87\xf6`"4Q\x96\xb1DH\x9cd_\xd9\xcd\x0e\xb8g\x8b}\x00dE\
+\xcfJD\xc4\xe9\xbc\x7fW\x92\xf3\xb97\x03\xb80\xfd\xbala0\x1d\x0e\x83\xa6i\
+\x98\xcd\x16\x0c\x8f\x9f\x03\xb0\x01\xaev\x07\x04\xbf(\xbf\x87D\xe9d"\xbd\
+\xe1\x8ak\xb1\xbb\xf5\x08\x06\x86G\x0bN\xd9\xa3)\nV\xab\x15\x87\x8f\x1d\xc77\
+\xbf\rt~\xa3\x0b@f"&\xd7Q\t2yw\xb6v\xc1\xdb\xb9\xb0\x85\x80D\xfb\x0fLO\xe1\
+\xd8\xf0Q\xec\x7f\xf7\x80\xac\xb1\xdbl\xd2w\xceE\xee\x16\xd6\x8c@d\n\x93A?\
+\xacu5p\xbb\\\x18\x9d\x980H\xbd\\\x98\x89\xc7qq\xdbj\xf4n\xbd\n\x93A?\x0e\
+\x9f=4ge\x9d\x1e\x947\xddBb>\x84QP\x14ES*\xff\x16\xe5\xb9!y\xbaJb\x8f\xc7E\
+\xc4\x11FK}\x1d>\xba\xf9.\xb9\xec\xbdX\x8b\x00B\xba\xda\x0c\x15\x82\\\x04/\
+\x97\xd9\xb7I\x0f\'\x86\xfau\xb5t\xbd\xf7O\x06\xfd\x18>7\x0e w\xba\xa7 \x08\
+\xf0z\xb2\xb31X\x93\t\x89D\x02f\xb3\x05\xbdW\xbe\x1f\x00\xf0\xda\x99\xfd%\
+\x8d%%H\xf5h\xad\xcd\x83Kk/Bg[WE\xab\x99\'\xdb\xfd\xf8\xc5\xae>\x1c}\xe7=0,\
+\r\x13\xc3@\x14\x05X\xcc,\x86F\xc7p\xf0\xf41lFg\x86\xccu\n\x87\x9bW6\xe1\xa3\
+\xb7^\x8d\x7f|\xe4)9_\xbf\x10\xd0\x14\x05\xb3\xd9\x82\xd1I?\x12S3hno\x91\'ib\
+K\xa0\x8c\xd6/\xb6\xaf\x95\x8b\xb8&\x83~\xf4\xf5\xf5\xe1\xd4\xd8\x88\xec\xf7\
+s!,\xc9++\\\xb5\xb8\x10\x9e\xce\xf9\xa8\xf7\x9a\\\xef\x03 \xfb\xf1\x90\xebp\
+\xd7\xb6;\xd1\xd9\xda\x85\xff<\xf84F&\xa5\xe3%)\x8f\xf9@\xc6\xa0\xd7\xe3\xc6\
+\xd0\xe8hA\xe7h\xb1\xb1$H\x9d\xe38l\xbf\xfaj\xd4{|xz\xdf3H\xa4\x13E\x13%\xb9\
+\xf1\x1a\xdc\rh\xb0\xae\x92#\x1fi)X9\x84b!\x1c\x1b;\x8e$\x17/iy_H\x9e:\xb17%\
+\xa4\xcc\xf1iU\xf6\x06\x89F\xa4\x9c]\x80,C\t\xa1?\xf5\xc2\xf3\xd8\xf3\xfao1<\
+1\x8eq\xbf_eeK\xa2\\\xed\xa3\x16\xca\xbf\xeb\x818/\xba\x9cN\xb464\xa2\xbd\
+\xb9\x19\xed-M\xe8\xddz\x15\xd6\xb7u\xe0\x04\xfaU\xe9\x8cz\x84^\xef\xf1I\x05\
+AG\x8e\xc0^S\xa3{^x\x9e\x87\x89eU&T\xca\xe3Ks\x1cV\xf9Vbc\xd7%\x98\x0c\xfa1\
+\x11\x9a(9\xd3\x85\x17x$\xd2\t\xd4\xda<\xd8\xba\xeej\\\xd3yMV5\xf3\x11\xe1(\
+\xce\xbe58\xe7g\xd9\x1b|\x88M\xf8U\xbf+\'j-\xae\xee\xeeF \x18B(\x1cF\x9a\xe3\
+T\x0e\x9cO\xffp?\x8e]<\x8e\xdf\xdf\xde\r\xd7%\xb5\xba\x99F\x00p\xc7\x87n\xc3\
+/v\xf5\xe1\xf0\xb1\xe3EU.34\x85D"!\xf9\xcb\xa0E\xf57\xe5f\xb7\x97\xf6\xa0\
+\xbb\xbb\x1b\x93A?\xfe\xf9{?\xc4\xae\x03\x0700,\x11\xe3BX\xf1\x9a\xcd\x16\
+\xb8\xec5hkn\xc2\x9f]\xb7\x1d\xf7\xde{/\xee\xab\xdd\x81\x87\xfe\xeba\xb9\xe2\
+4\xdf&*\xc7\xa7\xa5\xfc\xfb\xda:\xd9er)x\xf2W=\xa9\xa7\xd3i\x98\xcd\x16\\\
+\xdf\xbb\x19\x00\xd0?q\xb2\xe8\xc8*\x96\x8caM\xfd\x1a\\u\xd1Vl\\\xdb\xb5\xe0\
+K\xc0\xf1\x97\xcf\xe1l`\xb8b\xfa?CS\xb2\xab\xa2\xb2\xf21\x17\x04&\x86\xce\
+\xa6-X\xdf\xd6\x81\xc7\x1f\x7f\x1c\x9f\xf9\xcew\x91J%u-x\xf5@\xcfYEI\xc1D3\
+\x00\xc5\x80f\xa4\x8d\xc9D*\x85`8\x02k0\x84\xc1\xe1\x11\xfc\xf6\xe8\xdb\xb0\
+\xdbl\x18\x1c\x19\xc3\x83;vH\x91\xb9\xe23\xf4"\xf5\xa7^x\x1e\x7f\xff\xbf\xbf\
+\x83\x0b\xa1\xe9\x9c\x92\x01\xb1|U\x1aP\xa9\xbe\xbb \xa0\xbd\xb5E\x96^\x92\\\
+\xaa$R\'\x84~\xf5\xda\xad\xb8m\xcbm\xb2w\xc8\xcf\x9f}\x1e\xbb\x8e\x1dC\xff\
+\xe0\x00\xceO]@8\x96]H%\x08<h\x9a\x91\x1fS)i\x12U\x9e\x7f\x9af`b\x19\x95\xff\
+9\xb1\xf4%\x93c{\xabD\xa8\xe3~\xbf\xdc<\xe4\xbd\xa1\xb3\xb0Z\xad8\xd2\x7f\n\
+\xa7\xcf\x0e\xe3\xda-[\xd0\xb2A"\xa4\xe6\x15^t\xb6u\xc1\xdb\xe3\x01\x86\xa4\
+\x15\xd3\xe7>q7\xfe\xe2\xe1\x7fD\x9a\xe3\x8a2\x8f\x13xIZ\xa9\xf7\xf8\xb2\xf6\
+>\xacu5\xc0\xf9 \x9a\xdb\xa5\xe3\xfb\x9b\xaf\x7f\x0bO\xec\xdc\xa9\xf2\x99QV\
+\xf4\x02s\x1b\xaci_\x93\xf5\x9c@\x01t\xc6\xab_\x10E@\xa0\x10O&q\xf8\xd8q\x1c\
+>v\x1c\x00p\xef\xbd\xf7\xa2\xb3i\x03\xde8\xf3\x06H\xc5\xe9\\P\xf2E\xb5\x13:\
+\xb0\x14H\x9d\xe3\xd0\xdc\xd0\x80\xe6\x95M\x98\x0c\xfa1vaL.\xd1.\x04\xb1d\
+\x0c\x1b\x1b\xae\xc0\xdd\xbd\x1fW\xddx\xfdS\x01\x84\xc2\x11\x84\xa3sWQ\x96\n\
+=\xf7\xbaJ\xa0\x98F\x0c\xc4\x03ck\xc76L\x06\xfd\xf8\xc1\xee]H\xa5\x92p\xd9]\
+\xaa\x9b"\x17\xb4\x83:g\x03\xe9\x1cM\x18\x88\xc77\x89|^=|\x08\x9b\x0f\xed\
+\xc1\xf6\x9e\xde,r \xf2\xc5\x89\xa1~|\xe3\xfb?\xc6\xb3/\xbd\x84d*\x95\xd7\
+\x8f\xc3\xe3r\xa2\xd1\xa7\x9e\xb4\x95v\xb1\x11\x9aF\xd7\xbau\x002Y8\xc5\xa6\
+\xbc\x11\x19\xef\xa6\xf7}\x18wm\xbb\x13\x93A?>\xff\xb5\x7f\xc2\xf3{~\x8d\xd1\
+\x89\t\x95W\xb7\x89e@e\x15\xfa\x98T\x8ff\xb3IER4E\xc9\xdfQ\xd9<D\xeb\x8fN\
+\xac\x88\xdd\x0e\'6^z)\xee\xfd\xa3;p\xdf\x97\x1e\xc6\xce\xdd\xbba6[\x90L\xa5\
+\xf0\xab}\xfb`z\xdd\x84D2\x85\x1a\xab\x05n\xd7/p\xc5e\x97\xa1\xb3\xab\x11G\
+\xea\xdf\x81\xb7\xd1\x81\xb5\xab[q\xe2\xbd\xd3\x05\x93\xba\x94B\xbb\x12\x9d\
+\xad]\x98\x0c\xfaU\xfb*\x80\xb4W\xd2\xbc\xb2I\xae\xce}q\xef^\xb8].U\x97$2\
+\x8e\n!I]\x89M\xfb\x1c-f\xff\x8d\x16\xc1\x08,\xdc.\x17B\xe10~\xb0{\x17n\xb9\
+\xe3Vl\xed\xd86K\xeasc)xFiQ\xf5\xa4\xceq\x1c\xda[[\xe0\xad\xad\xc3\xe8\xe0HQ\
+\xd2K\x92K\xa1\xd6\xe6\x91\t\xfd\xf3_\xfb\'\xfc\xf0g\xff\x85T*\xa3\xa9W\xc2o\
+\x9d,+\xb7wv\x02=\xd2\xc4R*\x8a\x8d\x0c\xe2\xc9\xb9-J-\xacY>\x9f\xa3\x93~\
+\x98\xcd\x16\xfd\x9b\xa2\xc0\xe3\xcb7\t(\xe5\x18-\xa1\x13R"\xde\xeaz\xd1\xf9\
+?\xfc\xe0\x9f\xf0\xfd\x1f\xff\n\x81\x0b\x17`b\xd99\r\x96F&&\x11\x0cG\xd0\\\
+\xefS\xfd\x9f\x80\xd4\xc1\x87\xa2iySytR2\xa1Rf\x98\x14B\xee\x89tB&\xf4\x13C\
+\xfd\xf8\xecW\xfeEv<\xb4\x98\xcdE\x9b@\xe5j\xc4M\xa0mRA\xce_(\x1a\x91\x9b\\\
+\x00RD\xf9\xd0\x17\xee\x83\xcb\xe1\xc0\x8b{\xf7"\x14\x89H\x16\xb2\x82\x00\
+\xb3\x89E\x9a\xe30\x19\x08\xe0\x85W^\xc1\x8b\xaff\xfe/\x97\xbd\xa6\xe0\r@Q\
+\x14\xc1\xd0\x14>w\xcb\xadX\xdf\xd6!\xfb\xbfh\x89\x9d\xa0\xaf\xaf\x0f\x89tZ*\
+\xe0\xc9a\xd5PQ\xd0"\x04\x11p\xd8\xed\x18\x1a\x95\xae\xb7\xb7\xb6\x0e\x16\
+\xd6\\\xd4*m\xa1\x9a{\x94\x03UO\xea\x80tB\xeb=>\xec\x8d\xed-\xea}\x1c\x9f\
+\xc6\xd6u\x92\x16\xff\xf0\xa3\x8f\xe2\x91\'\xfe/lVk\xc5\rz\x04A\x00\xcf\xf3\
+\xb07H\xd5w\xa4\x98\xa1\x94e~%4<\xa7M:\x9fG\x84\xa3\xf3\xbe\xd1\x94\x84N\x1a\
+=\xe7kQ\xa7$t\xe2oO\xb4d \xb3\xd1\xbag\xffkx\xe4\xc7O\xe2\xf0\xb1\xe3\xb0Y\
+\xad\x05\x13%q\xaa\xec\x1f\x18\x84\xcdb\x91\x8b\x8fH\x07\x1fGMM\xc6\xc6@\x9c\
+\x86\x855\xcb\xe9\x82dS9\x1f\xb1\x93\x95\x1f\x89\xd0\xef\xd8\xf1\x05\xf4\x9f\
+\x1eP\xadtJ\x85\xf6\xfc\x11\xc4\x13I\xd8\xac\x16\xb9Gk8\x12\xd1\xed\x06Ep\
+\xe5G.\xc2\xfa+V\xe2\x99g~#m\xa6\xd2\x94L\xda\x0c\xc3\xc0d2A\x14E\x88\x00(H-\
+\xe8\x8a\x01/\x88\xe8\x9f\xca\x88eZB\x97\xb4vio\xa4\x7f*\x00V\xb1RY\xacF\xe0\
+\x14E!\x95Latp\x04\xcd\xed-`i\xb3*}t9aI\x90\xba2\x07\xbb\x18\xb0\x8cI^"\xfe\
+\xf4\x97\xbf\x90\xda\x8e-@J\x12EQ\xb2$B\xf4\xb8\xf9fX\xe4\x84P\\\x95\x1b\xa7\
+Y\x99$R\xa9\xb2\xb4\xad\xcb\xd5\xa5^)\xbb\xe8\x11\xba\xdb\xe5\x94\xbb\x1e\
+\x91\x8d\xd0\xc7\x7f\xfcs\xec:p\x00\xb1\x99\x99\xbc\xe4\x95\x0b4E\x01\x0c\
+\x83d:\x8d\xc4l\x87$2\xc1\xb0&\x13.mj\xd1\xcd\xf4\xd1+\xcfW\x12</\xf0\xb0\
+\x9a\xac\xb8\xa1\xe7\x06\x00\xc0\x1f\xfd\xaf\xfb\xd1\x7fz\xa0h\xcf\xfb\xb9\
+\xa0l\xed\x97\x0b\x84\xd8\xf5:D\t~\x11\xcd\xf5M\xf8\xc2g?\x8a]\xbf:\x82\x17\
+\xf7\xeeE<\x99T\xc9+\x14E\xa1\x94\xabNQ\x14\x18\x9a\xc2\xf7\x9f~\x06\x9b\xd6\
+_&{\riA&\xe7P8\xa2\x1a\x1b$\x88X\xe8\rG\x8a\xa2\x10\x9e\x89\xca\x9b\xbb6\x8b\
+\x05\xb1T\xe5\xa4\xd7\xc5\xc4\x92\xa8(%iJ@\xe1\xe4\xc8\x0b<\xecf\x07\xd6\xb7\
+u\xe0\xc8\xe9\xa3\x18;7\x01S\x81\x1b\x81\xe5\x00!\xca\xc9\xa0\x1f\xb1d\xac*-\
+\x80\x03\xe3Q\xa9\xfc\xb9D\x07\xba\xb9d\x17\xad\x8e\x0e\xa8\x97\xb1\xee\xd9<\
+\xf2\xfaY\x02{\xfc\xf1\xc7q\xd7}\x0f`\xe7\xee\xdd\x10\x04\x01n\x97\xbeOM\xa1\
+\xa0(Jn6\x9cL\xa7\x11O&1\x1d\x0e\xe3\x97od\xf4T\x966\xeb\xfa\xa8(AH>\x91N`\
+\xd3\xea\x1e9c\xe8\x95\xd7^\x87\xab\xc6>or\xd2{?!?\x92iD2\x92H6O.\x90\xcc\
+\x93\xb0]J\xf9\xbb\xeb\xf6\x0fb\xc7\x9f\xdc\x0c\x8a\xa2\x90H\xa6\xc0\xf3\xfc\
+\xbc\x1b\x8a\x9bL&\xa49\x0e\x7f\xff\xbf\xbf\x93U]*\xa74\xceF\xee\x95\xdc\xb3\
+*\x064E\x81eYU\x1b\xc5\xe5\x8a\xaa\'ueF\x00)\xac)\x04\x9c\xc0\xc3\xebZ\x01\
+\x008\xfb\xd6 \x12\x1c\xb7(\xf6\x99\xf5\x1e\x9f\xec\xfeV\n\xe6$\x8cy.\xf9\
+\x01\x14m\xee\xa4\x85V\x0b\xce\xa5\xa3\x13Bw9\x1c2\xa1\xafp\xd5\xc2\xde m\
+\x86~\xf9\xc9\'\x11\n\x87\xe1r:a2\x99\xca\x1a\xc9Q\x14\x05\x86a\xc0\x0b"\xbe\
+\xf1\xefO\xe0\xf1\xff\xf7\xac\xaa\xd8G\x8f\xd8\xb5r\x8c\xd5dE\x8fo\x13\x00\
+\xe0\x91\x1f?)\xbd\x88)\xcf\x98"\xdfUO\x9a\xd0\xa6\x90\x12b\'\xd9=\xe1HD\xce\
+\xdb\x06\xa4\xaaJRx\x14\x8cO\xe1\xd2K\xd6\xe0\xba\x0f|\x00kZ\x9ba\xb3X\x90L\
+\xa51\x13\x8fc&\x1eG8\x12\xc1L<^\xf4\x18p\xd4\xd4`ht\x14\x9f\xfd\xca\xbfd\
+\xed\x83\x04\x84 \xbc\xb5u\xf2jH\xbb\xea\x98o\xdf\xd8\xc5\x80\xde\x8a\xa8Z\
+\xb1$\xe4\x17\x82|\x15w\xf9^?\x99N#\x95J\xc2lZ\xf8\n\xd4\\\xb9\xe3\x85b!\x96\
+\xa9\xe5\x9a\xec\x947\xaf\x9e\x8e\x0ed\x13: 5\xbb\xfe\xe1O\x9f\xc3\x84\xdf\
+\x0fg\x85\xfb\xc8Z-f\xa4\xd3)\xfch\xe7N\xfc\xc1=\x97\xc3\xebZ!od\x13b\'\x9b\
+\xcdJ9&\xc9\xc5\xe1\xb6\xbb\xd1\xdc\xde\x82\xbe\xbe>\x0c\x8d\x8e\xc1f\xd5o\
+\xf9W.he\x18\x12\xadk\xf5u\xd5\xf7\xab\xab\x01f\xd3\xe2\xc3\xf6i\xb9\x92\xf4\
+\xdeO\xdc\x82`|\n\xa3\x93c\x18;\x9d\xc0\xd1w\xdfU\xbdopx\x04S\xa1P\xc1M\x97\
+\x05Q\x84\xcb\xe9\xc4\xbe\x83\x87p\xe4\xe8;\xe8\xddzU\xa6\xce\xe0|\xc6&\x80\
+\x90\xa1^}\xc3b\xe5|\x97\x92\xd2ll\x94V\x08\x11Q\xbf\xb5\x95\x1e8>-\x17\x18\
+\x91(f!#\xf5j\xd5\xd4\xcb\x85\\\x19\x1bzQ:\x80\xac\xc6\xdf\xca\xca\xbf\xb3o\
+\r\xe2\xf9=\xbf\x86\xd9l\x01SH{\xb5y\xc2d2atb\x02g\x0e&\xb1ak\xf6D\xaf%w\x82\
+\x06\xeb*\xd4{|x\xfc\x8dg\x11\x08\x06\xe5M\xd8r\x83l\x98\x02\x19b\'\x84h5\
+\x9b\xb36N\x95\x92\xcc\xe8\xf91\xe9>\x89\x02\x0e\xd8\x11BH\xf6}\xf1\xd8\xea\
+\xe0i\xab\xc3\r=M2\x01\xafo\xeb\x903x&\x03\x81\xa2\xf6\x9ch\x8a\x02\xc7q\xd8\
+\xf3\xfao\xb1\xb1\xeb\x12]\x97M-\x19j;P-$H}\xc5|\x93\x17\xaa\x1dU/\xbf(Ql\
+\xa4\xbe\x98X0M]G~\xe1\xf84x\x81\xd7\xfdY\x08h\xa3t\xad\x8eN\x08\x9dh\xe9\
+\xfdS\x01\x9c\xf3\x9f\x87\xd5\xb2p\x1d\xdcmV\x0b^;r\x04@vC\t\xd5\xebf7\xd4\
+\x12\xe9\x04\x9a\xeb%\x17\xc2\xc1\xd9r\xf1r\xcb\x08\xca\xef\xce\xf1\xbcLz\
+\xca\x0c%=\x8d=\x9eH"4kZ\xa6\xd7\xacB\xf0\x8b\x08\xdb\xa7\x11\x8cOI\xd1\xfa\
+\xf91\x95\xe9\x96\xb7\xb6\x0e\xe3\xfe\xe2,"\xc8\xf1\xda\xacV\xfc\xf6\xe8\xdb\
+\xf2sz\xbe\xea\xb9\xaa\x8c\x17\x1a$}y)6\xa2/\x06K\x8a\xd4\x8b\x89\xd4u\xc1/\
+\xbcu\xa62R\xcfE\xb4\xf9\xc8\xb6X\x92#\xfa/G|n\xb4?|\xba\xa0\\\xf6B\xa0\x8c\
+\xb6\xb4\xba\xa9\xb6P\xc6\xa5\x91U\xeaM&9\xb5\xf0@__Y\x8e\xa7\x18P\x14\x8dH4\
+\x8a\x81\xc9\x019X\xd0\x12\xbb\xd7\xb5\x02\x13\xa1\t\xfc\xe2\xc7\xfd\x18\x7f\
+\x93\x95\xcb\xed\x87\'\xc6+v\\\xda\xeb\x9d\x8b\xd8\x13\xa9\x14\xe2\x89$\xe2\
+\x89\xa4J\xd6\x08\x08A\xc4\x921D\xc4i\x8cG\xce\xc9\xae\x85\x82_\x94\xb3\xc7\
+\x08\xb9\x13\x8c\x0e\x8e \x18\x8e\x80)!\x91\x80a\x18\x04\xc3\x11\xb9\xf1\xb4\
+\xde\xa4BP-\xe4\x0e\xcc\xafv\xa4\xda\xb1\xa4\xe4\x97yG\xeae\xda\xd4*\x06JM\
+\xbd\x90h];\xd8\x8a\xd1\x1d\xeb=>|\xf6\xba\xcf\x15\x7f\x90%B)\x13\x00\xd97\
+\xad6\x1dQ\x19\xa5+14:\x06\x13\xbb\xf0\x9bg\x82 \xe0\xcd\x97.`\xe3=\x99\xe7\
+\x88W9\x00\x04\xc2\x17\xf0\x9b\xe7\xc7\xd1\xd6\xdc\x84\xcb\xaf\xf5\xe2\xc97\
+\x9e\xc0\xc1\x83\xef \x1c\x89\x14l\xa9PN\x10b\'\x13(\xf1\xda\xd1\xd6\x1a\xd8\
+-v\xb99\x86\x12\xc4\xe7H\xeb\x05\x13\x10\x82\x98\x89%PJ\x0f\x08\x8a\xa20\x1d\
+\x0e\xe3L`\x00\x1b\xd7vat\x8e\xfe\xb2\xd5\x00"\xbf,W,)R\x9fw\xa4\xbe\x08\xa8\
+\xf7\xf8\xf0\xc9\xad\x7f"G2\x80\xbaK\x8c\xd6\x7fZ\xaf\xd1@>\x08\xa2\x08\xab\
+\xc9\x82\xb3o\r\xe2\xc4\xca\xec|\xe1\\81\xd4\x8f\xc1\x911\xd04S\xf0\xe6\x98\
+\x16z\xb9\xe9\xdarv\xad\x96\x0ed\xa2to\xa3\x03/\xed9\x88X<\xbe(\x96\xa64M#\
+\x18\x8e\xc8\xb6\xb7d|\x11b\xdf\xfb\xdc\x00F\'&P\xb7v\x1a\xbf|:\x8e\xfe\xd3\
+\x03\xb8\xe7\xf6\x16\xd5dU\x89\xcd>\xad\xc7\x89\xbc\x1aR\xe8\xec\x00d\xad=\
+\x91J\xc9\xa9\x83\xdb{z\xb1qmW\xce\xcfV\xb6\xa3#\xab\xc8\xb3o\r"\x91N\x96T\
+\x94GQ\x14\xe2\x89\x04\xce\x0fr\x08t\xe4.\xa9\'V\r\xe4\xb8\x17\xa5\xbat\x16\
+\xcb]~YR\xa4\xbe\x944u\x9a\xa6\xe5JIom]\xc6n\xb6\x00\x14c\x81KS\x14@\x89\xf8\
+\xf2\x93O\xc2\xfa\xcc3E\x1dc"\x95\x82\xc5l*\x99\xd4\xf5\x10O$\xb3\xa4\x17 w\
+\x94>|n\x1c\xbc b\xe1)=\x83X2\x86F\xef*D"\x99\xa0\xe1\xcc\xc1\xa4\x9c\xe1\
+\xf2\xde!\n\x89\xf4(\\v\x17\xee\xba\xfd\x83\xf8\xfac?\xa9\xb8\xc3 \x81Vg\x07\
+\xb2\xc9\x1d\x90\xb2L\xfatd,\xbd\x9e\xaf\x804&I\x8ey\xffT`\xdev\x19q\xc1\x83\
+\xb5\x00\x00 \x00IDAT\x83\xa3\xa3\x19S\xb6\xf3\xd9\xbaz.\x14b\xe8Un\x14k1\
+\xbd\xd4\xb0\xa4H\xbd,\x9a\xfa\x02H0$\'\xfa\x91\x9f?\x8f\x1f\xec\xde\x05 \
+\x93[\xac\xcdV P>o\xb7\xd9\x10\x08\x86\xa4\x06\xc1\x05\x0e\xf6H4\x8a\x0b\x9c\
+tc2\xb4T\xd1\xaa\xf7\xa8\x04M\xd3E9\xf3\x15\x02\xb2I\x9a\xaf\x12\x94h\xe9\
+\x81\xf1(\xfa\x07\x07\xcaR\xd1Z\nh\x9a\xc6t8\x8c\xb7^\t`\xedG/VE\xebR\xb3\t\
+\xe9Z\x82\x92\xaeA\xef\x07\xb6\xa0ye\xd3\xa2\xc9/\xc4gGK\xee,\xc3\xe0\xcd\
+\xe3\'\xd0\xfb\xe9Og9:\x12\x90\x8a^\xb2r"i\xa5\x1du^\x1c}\xf7]X\xe6\xa1w\x9b\
+\xcd\x16\xb8]N]\xef\x17 \xdb\xbbf\xb1QJ\xa4n\xe4\xa9W\x08\xf3\x8d\xd4E\xba\
+\xb4\xd2\xe8R14:\x864\xc7\xc9\xae}\x00T\xbf+\xa1}\xdeb6\x17E\xb8\x0c\xc3\xa8\
+^o\xca\xf18_h\xabH\xb5>/s\xa1^#\xb3\x9c\x9f\xba\xb0(Ea@f\xf2=\xda\x7f\n\x9d\
+\xc3\xabpi\xebj \x9a\x1d<\x90^\x9e\xf7~\xe2\x96yuc*\x07\xc8$\xafG\xee\x80Zo\
+\x07\xf4\xdd\x1d\x89T\xd3\xde\xdc\x0c@\x92\xc8\x04A(i\x82\'\xd5\xa9+\\\xb5\
+\xb2I\\\xb5\xa3\x94H\xdd\xc8S\xaf\x10\xe6\x1b\xa9\x97Sf(\x04&\x93I7\x02R\xde\
+\x98\xb9\xb0\x14|\x9b\x01u\x81\x8c6"\xd3\xd3\xd3\'\xd3i\xb4\x03\xb2\x9e\x9eH\
+\xa7u\xaci\x17\x0e4M#\x14\x89\xe07/\xbf\x83\xe6;\xbdp8\xec\xf8\xd5\x7f\x1eE\
+\xff\xc0 X\x96A:\x9dF\xad\xcb\x85\xcb\xd6\xae)z\xbf\xa3\x92P\xbac\xea\xe5\
+\xb5\x13\x10\x1d\x9b\x10;qv\x04f\xeb7f%\xb1R2_\x00\xa9m`\x8d\xd5\x82\xf6\x96\
+&\x04\xa6\xa7\xb2\x8a\x8f\xaa\x11\x86\xa6^E(5R\x0f\x85\x17o\xe9\x94\x8f\x9c\
+\x97\nq\xe7\x83\x96@\xb4\xc4\x1e\x8eFeC6@\x1d\xa9\x87\xc2\x11\xf09V.\x0b\x89\
+\x1a\x9b\r\'\xde;\x8d#\x136\x8c\xbf\xc9\xe2\xf57\xdf\x02\xcb2H\xa68\xacim\
+\xc6U\x1f^U\xf1\x0eY\xa5 W\xd4\xae,X"+("\xed\xe9\xc9b\xca\xebS,x\x8eCKs\x13.\
+mjY\xd6\x91\xfaR\xc2\x92"\xf5b"u\x961\xc99\xbaD?\x14Eq\xc1\xa3\xf5\xdf%h\t=\
+\x14\x8d\xa0\xb5\xa1\x11\xa1pD^\xea\x13\x04\xc6\xa3\x18\x9e\x18G\x9a\xe3\xaa\
+\xa2\x99/\xcb\xb2x\xe1\x89~\x00"\xd8\xd9\xf4J\xb3\xd9\x84+\xae_\x01\xb7\xdd\
+\x8dH|\xe9h\xaaZ\xe4\x9al\x81Le/MQ%\xdd\x1f\xbc \xa2\xd1\xe7\x83\xb5\xaeFWS\
+\xd7\xae\xd4\xaa\x01\xcb=R_R\xc5G\xa5F\xea\x1du^\xb0,\x0b\xbd\xb8\x98\xa6\
+\xa8\x8a\xfe,W\x90\xc2\xa3|\xa9iJ\x1d\x92X5\x08-\x99\xabp\xf2\xf4\xc0\x9c\
+\xad\xf1\x16\n\x14E\xcd\xfeH\xb7\x84 \x88\xf0\xba\xddhp7\x00\x90\x1a\xae\xe8\
+\xa1\x1aV[z\x192\x04\x89TJw\xb2\xd5Z64\xd5\xfb\x8a\xce\xe8\xa1)\n\x82\xc0\
+\xa3\xb5\xa11\xe7^C\xb5\xb84*aD\xeaU\x84b5\xf5\x89\x84\x94\xc1\xb0\xfa\xf2v\
+\x98X\x16\xd1h\x146\xab\x15\xbc V\xa4\xe3Q.\xc8m\xcdd\xe2X<\xb2\'\xcd\x110K\
+\x04\xa2(\x16\xe5\xd0G<mH\xc6J\x9a\xa6\xc1$S\x80C"\x10\x8f\xcb\x99\x95\xdd\
+\xa3$\x90\xf3\x83\x1c\x9c\xb3\xbd\x8a\x9b\xeb}\x98\xf0\xfbUM\x1c\xaa\x03\x12\
+Y}\xe0VI\x96\x88\'\x93Y-\x14\x17*\xa5\xb1P\xe8J1\xb3\xe7T\x19\xa9\x87#\x11\
+\xb46\xaeB8\x1a\x85\xcb\xe1\xc0\x85\xf04:\xea\xbc\xf8\xc3\x1b\x7f\x1f?\xda\
+\xb9\xb3(\xff\x17\xf2\x7f\xaen\xcf\xbf\x89\xa8ld\xce\xa5\xd3\xe0x\x1e\x82("\
+\xad\x08\x08*\xbdY\xce#s\xcd\x96{\xa4\xbe\xa4H\xbd\x98H\xdd\xc2\x9a\x11\x88L\
+\xa1\xaf\xaf\x0f\xdb{z\xf1\xc0\xbd\xf7\xe2\xa7\xbf\xfc\x85\xbca\xd4\xda\xb8J\
+\x95\xdaU\t\x90\x1e\xa8\xc3\xe3\xe7\x10\x08\x860\x19\x08 =;\xb0L\x0b\xd4\xb0\
+C\x10\x04\xa4\xd2\x9cj\x12#\xff\xb7(\x8ap\xd8\xedY\xe9o\xc5B\x99]\x91\xcfb\
+\x17\x90\x0c\xbc\x00i\xa3\xf4\xab\x7f\xfd\xe78x\xf0\x1d\xfch\xe7N\x04\x82\
+\xc1\x05\xcd\x82\x11\x04Aw\x82\x15D\x11<\xc7\xe1\xca+.G\x83\xdb;\xaf\xffc\
+\xbe\xbe\xe5\xa5@@\x86\xd89\x9e\x87U\xe1$\x19\x8b\xc7\xd1\xe8\xf3\xa96K\x01\
+\xc8MJ\x80\xd2\xc8u:\x90\xfbo.\x87\x03^Of?\x82L\xf8\x84\xe8\x17\x126\x8b\x05\
+\xdeF\x87\x11\xa9W\x03\xc8\xd2\xdd\xe1\xb0\x83\x9b(\xce\xc2\xf6\x85\x81\x17\
+\xd0\xdc\xde\x82\x07w\xec\xc0\x83;vT\xea\x10\xe7\xc4d\xd0\x8f#\xa7\x8f\xe2\
+\xe0\xc1w\xf0\xea\xe1Cx\xf3\xf8\t\x84\xc2a\xd8\xacV\xa9\x8fd\x19\t\x80\xdc\
+\xd4\xd1X\x0c,\xcb\xc2\xbbb\x05\x9a\xeb}\xd8p\xf1:\xb477\xa3\xbdE\xda\xd8\
+\x02 w|\x072\xd5\x86\xf3}\xd4~V>l\xef\xe9\xc5\x8d[\xb6\xe0#\xf7\xdf/\x9bzU\
+\x1a\xa2(\xe2\xd2\xf6\x8b04:\x86D:-\xcbd\xa2("\x95J\xe3\xeaMW\xe0\xf2k%B/\
+\xc5\'\x87\xa6(\xa49\x0e\xb1\x99\xc5/\x997\'\x92\xa8\xb1Z\x10\x8d1p\xd8\xed\
+\x18\xf7\xfb3\x1e\xf7\x8a\x15\xd4\xe0\xe8(\xce_\xb8PRZ#IDP:4\x06\xa6\xa7\xb0\
+\xbe\xad\x03\xff|\xff\xe7\xe7\xf9\r\xca\x8bR\xa3t#O\xbd\x8c\xe08N\x1e4\xc5f \
+XX3\x06&\x07\xf0\xaf/~\x1d\x9bV\xf7\xc0c\xabS\x95\xe5\x07\xe3SE\xb7\xc8+\x06\
+\xe4x/\xb6\xaf\x85\xb5\xae\x06\x1b\xd7va{O/\x1e\x04\xb0\xeb\xd0\x1e<\xbd\xf3\
+\xd7x\xf6\xa5\x97\xe4\xc6\x10\xe5\x00\xe9\xd1\t\x00\xd7^u%~oS\x0fn\xdc\xb2\
+\x05\xcd\xed-\xaa\x01M\xc8W\xb9\xb95:8\x02k]M\xc9\x8f\xaa>\x95\xb3\xbf+\x9f\
+\xd3\xd3]\xeb=>4\xb7\xb7\xc0\xebqcht\x145VKEujQ\x14\x91L\xa5\xb1\xe1\xe2uhm\
+\\\x85\x17_\xfd\x1f\xd4X-Hs\x1c\xd2\x1c\x8f\xaeK.\x96\t]\tm\x1b\xc0|Hs\x1cZW\
+5b\xfb\xd5W\x97\xf3\xd0K\x86\xb6\x92Wi\xa6\x06\x00\x976\xb5\xe0\xbb?\xfb\x19\
+\xd2\x1c_\x14\xa9\xd3\x14\x05\x9afd\xdd\\k\xbd\x9b+"\xce\xd7\xa8\xba\xd2\x08\
+LO!15\x83X2V\x94\x1d\xb6\x91\xa7^f\x0cO\x8cc2\xe8\xcf2"*\x04v\x8b\x1d\x81\
+\xc8\x14^|\xfb\xbf\xc12\xa6Ek+g\xb7\xd8\xe1\xb49\xb1\xd6{1z|\x9b\xb0\xbd\xa7\
+\x17\xdb{zq\xd7\xed\x1f\xc4\xdf\xff\xcb\xff\xc1\xe1c\xc7\xe1p8\xe6\xbd\xb9\
+\x1a\x9d\x99\xc1\xc5m\xab\xf1w\x9f\xba\x17\xbd[\xaf\x92\x89\xbc\xaf\xaf\x0f{\
+c{1:9&\xef5\x90\x8c\x0e\xe2\x12I\\\x1c\xf3A\xefFP\xae\x9c\x9c6\xa7\xfc}\x01\
+\xc8\xc6RZ3)/\xedQM\x04\xe5\x9a\xd4\xe6\x025\xbb\xb9\x17\x8eF\xf1\xa1\x1b7\
+\xe0\xcd\x93\'1:1\x01\xb7\xd3\x89\xf7o\xbc\x14W\xdf\xb0\x1a\x80d\x1d@\xa2\
+\xf4|\x8d\xa8\xb5\xa0)\n\xe1\x99\x19t\xb4\xaf\xc1\xb7\x1e\xf8\xdb\x8a|\x87\
+\x8a\xe0g?C*\x95,jR%\xaf\x0bE#Y\x04=z~\x0c\xc7\x86\x8f\x82\x0fI\xb2^\xc44\tz\
+\x84B\xd8\x13E\xdco\x01o\xce\xde\x1f\x0b\t\x99M\xd54\x13\x81\x89w"\xcdd"\xe4\
+b\xaeC!X\x8e^\xea\xc0\x12 u\xb3\xd9\x82\x93\xa7\x07\x10\x98\x9e\xc2\xf6\x9e^\
+\xbc\xf0\xf6\xcf\x91\xe4\xe2`\x8a\xc8\x9a\x90:\xc6\xcf\x96T\xeb\xbc\xaf\x98\
+\xcf*\x05\xc4^7\x10\x99\xc2Dh\x02\x07N\xef\xc7\x9a\x815\xb8y\xcd\xcd\x92\x01\
+\xd3\x0f\xba\xf07_\xff\x16\x9e\xd8\xb9\x13\xf6\x9a\x1a\x98X\xb6\xe8hU\x10ED\
+\xa3Q\xdc~\xddux\xec\xa1\x07Q\xef\x91Z\xc4=\xf7\xc6s86v\x1c\xd3\xf1LA\x88\
+\x96\x98Y\x9a\x01\'\xf0`iF\xf7\xfc\xe4\x82\xf2\xbc)\x9b5\x13(\xf7@B\xb1P\xd6\
+J\x8b4j\xf0\xd6\xd6\xa1k\xdd:\xbc\xf2\xda\xeb\xe0g\xb5\xeeJ#\x14\x8d\x80\xf6\
+Q\xf8\x83{.\xc7\x85P\x026\x1b\xa5\xea\x82\xa4\x94]\xe6\xd3y\xfe\xc4P?\xf6\
+\xf7\xef+\xcb1\x17\x03\xb7\xdd\xad{\xce\x01\xb5Kc\xf3\xca&\xaco\xeb\xc0\xf0\
+\xc48\xcc\xe6\xe2WI\x0cMey\xb1kM\xea\x94\x84\x0e \x8b\xd0\x95dN\x10\x8f\x8b\
+\x88#,\xff[`b\xf28\x9d/X\x9a\xa9\xf8=\xbf\x98\xa8zR\xb7\x98M\x98\xf0\xfb\xf1\
+\x9b\xdd\xfb\xb1\xfe\xde\x0et6m\xc0\x81\xd3\xfb\x8b\xb6\xce\\\xcc\x8bH\xfeo\
+\x86f\xe4\xe8``r\x00\xdf\x9a\xfc\x16\xae\xf6o\xc5m[n\xc3\x7f|\xedkhon\xc6\
+\x97\xbe\xfdm\xd8\xac\xd6\xa26QE\x1dB\xff\xde\xaf\xbe\x8f\xc3g\x0f!\x91N\xc0\
+j\xb2\xc2j\xb2\xe6=\x07\xa5\x9e\x1f%\x99k\xfb|\x12\xf7C@_:S\x9aM]\xdf\xbb\
+\x19?\xf9\xf9\x0b\x08\xc7f\x16DW\x07$\x8f\xf1\x06\xeb*\xd8\xeb%\x92\xd1#\xf4\
+\xf9F\x87\xc7\x86\x8f\xe2\xc0\xe9\xfd\x00*\xd8\xfd*\x0f\xc8x#\r\xb6\xb5+\xa8\
+\xe6\x95M\x98\x0c\xfa18<R\xb2\xfd1\xd9\xf4$\x86^\xa4\xf94l\x00l\x00\x13O\x82\
+o\xb0@0\x89\xa0G(`\xd6r=\x1aJ\x00\x00\xdc\xb4#\x8b\xd8m6J\x15\xa9s\x82\xf4=\
+\x963\x19\x97\x0bU\x9f\xa7\xce\xd04X\x96\xc5\x0fv\xef\xc2d\xd0\x8f\xdb\xb6\
+\xdc\x06\xbb\xc5\x9e3ox\xa9\xc0n\xb1\xc3j\xb2\xe2\xc0\xe9\xfdx\xec\xe5G1\x19\
+\xf4\xe3\xc1\x1d;\xf0\xb9{\xfe?\xc4\x13\x89\xa2\xd2\x0c\xe3\x89\x046un\xc0c\
+\x0f=\x08\x00\xf8\xc6\xb3\xff&\x13\x89\xddb\x07S\xc1\xc8\xa4P\xd2S6h\x00\xd4\
+\x1dr\x02\xd3S\xd8\xb8\xb6\x0b7]s\r\x04a\xfe\xdd\xee\x0b\xc5x\xe4\x9c\x9c&[L\
+\xd3\x04=C\xb6\\ Q\xb1\xd5d\x85\x855/\xc8\x8f\xdd\xec\x90\x7f\x9c6\'\x9c6\
+\xa7L\xe8N\xaa6\xcbk\xfd\xc8\xe9\xa3\xb8p\xa1\xb4\xec#\x86a\x90H\xa5T\xd6\
+\xd2\xd6\xba\x1a\xd5\xf5\xf5\xd8\xea\xc0\xb8\x93p\xa6\xebao\xf0\xc1\xe1\xb0\
+\xc3\x15t\xc0\xe1\xb6\xc2\xe1\xb6\x82I\xd5\xc2M;\xe4\x1f\x000\xf1\x199.\x1e\
+\x17uW\x82\x06\xf4Q\xf5\xa4.\x88"jl6\x1c\xe9?\x85\xc7\xff\xdf\xb3\xa8\xf7\
+\xf8p\xfb\xe5w\x80\xe3\xd3K\x9e\xd8\x19\x9a\x81\xddb\x977s\'\x83~|\xeb\x81\
+\xbf\xc5\xb5W]\x89h\xac0\x92\x11E\x11&\x96\xc5W\xff\xfa\xcfQ\xef\xf1\xe1\xb9\
+7\x9e\xc3\x91\x897e2\xaf$\xc8\x8dF\x88\xbd\xd8L\x11m?\xcb\xbbn\xff \xdcNg\
+\xd1\x9d\xedKA8\x12\x91W\x11\xb9\x08\x9d\x13R\x99\xef\xa8\xd8k\xd0\xb3\x16\
+\x9e\x0b\x0b\x19a\xeaM\xb4$B\xd7\xab\xf58\xfb\xd6 \x12\x1cW\x9a\xecEQ\x98\
+\x89f\x9f?e\x07$2\x913\xee\xcc\xf8\x10ZD\x99\xdcm\xbe\xa4L\xf0\x00T\x04\xbfR\
+l\x84\xcb\xec\x82\x89w\xc2&\xd6\x81\xa5\xcd\x06\xc1\xcf\x81\xaa\'u\x02\x13\
+\xcb\xe2\xdbO>)\xe7\x9d\xdf\xf4\xbe\x0f/\x0bb\x07\xa4(n"4\x81\'\xf7\xfc\x04\
+\x00\xf0\xf5\xbf\xf8\x0c\xbc\x1e\x8f\xec\x0e\x98\x0f\xf1D\x02W^q9\xb6\xf7\
+\xf4\xa2\xaf\xaf\x0fo\x9cyc\xc1\x96\xf9\xf9\xa2t%QFunz\x02%\xb17\xafl\xaaX3g\
+%H\x15\xab\x96\xe0\xe2\xc9d\xd6\xe6(y\\\x0c\xe9\xa4\x9cP^\x0f\x12\xa5\xd3\
+\xbe\xd9>\xba\xf3hXA\x01Hp\x1c\x02\xe3\x19\xf9D;Y\x93\xd5\n\xd94%P\xea\xec\
+\x00\x10\xf7[\xc0\xa4\xb2kQH\xf4\x0eH\x11\xbc\x89wJr\x92A\xf2\xbaX:\xa4n2!\
+\x14\x89\xe0\xee/=\x88\x13C\xfd\xb8k\xdb\x9d\xb8{\xcb=\x00\x96~\xbfA\x86f`5Y\
+qd\xe2M\xec:\xb4\x07\xdd\xdd\xdd\xf8\xf8-7#63\x937\x1b\x86ts\xff\xe3\xdbn\
+\x05\x00\xec\x1d\xfc\x1fp|qy\xfc\xe5\x80\xdeMU\xe8\x9e\x07\xd1\xd5I\x9a\x9b\
+\xd7\xe3\xaex\xa4\xae\xf4o\xd7\x1b;\xca\x08]\x0f\xc5\xc8/\x04\x0b\xd5\xf4;\
+\x17\x94Z:\x99d]1\x89@_=|h^\x15\xd6\x82\xc0cpdL\xf5\x9cR~Q\xf6C\x8d\x98&\x01\
+H\x84N,#\\A\x07\xe2~\x0bl\xbe\xe4\x9cY1\x04Do\x8f\xc7\xa5\xcfH\'M\x15%\xf7\
+\xa5\x94\xa7\xbedH\x1d\x90\xdc\xf4\xfaO\x0f\xe0\x8e\x1d_\x90#\xf6\xbf\xba\
+\xf1~4\xb8\x1b\x10K\xc6\x16\xfd\xc6\x99\x0f\xc8\xf2\xfc\xe5S/a2\xe8\xc7\x9f\
+\xfe\xe1mh\xf0\xf9\xe4\nT=$S)4\xf8|\xd8\xd8u\t&\x83~\x9c\x99>\xb3(\x11%\'\
+\xa4\xb2$\x18B\x96\xcahX[\x13\xa0\xd7y\xbe\xb5q\x95lEPI\xc4\xe2q\x15\xa1k\
+\xa5\xa3|\xab\x90R\xe4\x97\x85\x84\x1e\xb9\xe9E\xea\x80\xb4\x91;\xee\xf7\x97\
+\xec\xc1C\xcd\x06\x16J2\xb6\xd6\xd5\xa8\xe4\x17\x8f\xad\x0e|\xc8"\xeb\xea\
+\x80$\xbf\xd0#\xd2\xe4\x1a\xf6Da\xf3%\x11\xf7gW5\x87\x84\xa8*R\' )\x8f\x046\
+\x1bU\xf6\x94G%\x96R\x9e\xfa\x92"u@\xcag\xee?=\x80\x8f\xdc\x7f?\x9ez\xe1y\
+\xaco\xeb\xc0_\xddt?nz\xdf\x87\x01`I\x93\xbb\xddb\xc7Dh\x02GN\x1f\xc5\xfa\
+\xb6\x0e\\\xb5qc\xceh\x9d\x9e\xed\ry\xd9\xda5X\xdf\xd6\x81\xd1\xc1\x11L\xc7\
+\x83\x0b\x16\xa5\xe7;\xc7\xf1d\x12\xdcL\xee\xe3 \x91\x9b\x97\xf6d-\xd5[W5.\
+\xa8/\x0fP\xd8^\x00\xc7\xa7\xb3\x8e\xb5\x18T\x93\xa6N"u\x8f\xad\x0eo\xf4\xbf\
+\x8d\xd1\x89I\x98M%\xfa\xa9\x8b"X\x96UY\x05h\xcfS0>\x05\xc6\x9d\x94\xe5\x17%\
+\x99\xbb\x82\x12a\x93H]\x0b\xbd\xcc\x18@\x8a\xd4\xc3\xa90l\xb6YO\xf99VW\xbfK\
+\xa8\xfa\x94F=\xb8\x9cN\x8cNL\xe0\xcf\x1e\xfc2\x0e\x9f8\x89\xbf\xf9\xf4\x9f\
+\xe2\xaemw\xa2\xb3\xb5\x0b\xfb\xfb\xf7\xcd\x99\x97]n(s\xbb\xcbq\xf3\x1e\x1b:\
+*\x15\'uvb\xe7\xee\xddys\xb7[\x1b$\xd3\xa9>d\xf7\xa7,\x04\xbc\xc0#\x91N\xe4\
+\xfc{\xbe\x82-\xe5yei\x06\xbc \xd5\x0f\xb0\xb4\x19lM\n\xd3A\xe9\xa6\x8c\xd4N\
+\x03Q)B$\x11\x1b E\xea\x84\xd8\x89\x0c\xa3\xd7\xc7\xb4\xdc\xa0iZ\xd7{$_\xa4\
+\xc72\xa6\xac~\x9f\x85\x80L`\x0b\xb5\xf7#\xd5d\xe4&7\x92\xf9B\xfb(\x04cS\x18\
+9\x1eA$\x1a\x85s\x1e\x16\xb9V\x8bEu\xdd\xacu5r6\x0c\xf9\xfe|\xc8"K/QO\x0c\
+\x88JD\x0e_TJm4\'\x10\rI>2\xb5^\xb5\xe4\x12N\x85\xe12\xbb\x10N\x85\xa1\x05\
+\x91_R\x88\x01X\xda2l\xb9\xb0$I\x1d\x90\xa4\x18\x9e\xe7\xf1\xc8\x13\xff\x17\
+\xbb\x0e\x1c\x90+(?}\xc3\xa7d\x9f\x953\x81\x01D\xa31L$\xce\x95\xe4\xe1Q\x088\
+!\x05^\xe0\xe5\xa2\x08B\x90,c*)j\xb6\x9a\xac83}\x06\x00\xd0\xdd\xdd\r\xaf\
+\xc7\xa3\x9b\xbb\xcd\xcf\xea\xce\xc4\xa7<<X\x9c\xc5)!s\xab\xc9\x8a5\xf5k\xe0\
+\xa4j\xd1\\/\x99m\x95R\xb9K@\nOH\xc5h\xce\xd7\xe5\xb0\x0choi\xaa\xb8\x1d/\
+\xd1\xec\xe3\xc9\xa4*\xb7\x9e\xa5\xcdr\xc4\x97w\x13\xb8\x84\x94\xc6\xb9\xc8\
+\xb6\x9c($j\x15\xfc"`\x07\xee\xb8\xe3j\x0c\x8f\x9f\xc3\x89\xf7N\x97l0\'\x8a\
+\xa2l\xd4\x06d\xf2\xd4\xadu5hF\x93\x14\xb9\xdb\x01\xa0E\x92\xdc\x88\x0bC[\
+\xe63\x02\xe3Qx\x1b\x1d\x08\xc6\xa7\xe4\x89_\xfb\x08dKx\x95D4\x1a\xc3\xc5\
+\xf6\xb5\xaa\xe7\x96BO\x86%K\xea\x80\x94#\xebv\xb9\xf0\xde\xd0Y\xdc\xf3\xc0\
+\xdfac\xc7\xa5\xb8\xf9\x9akq\xfb\xef_\x8b\xed=\xbd\x00z\x01\xa8}N\x88\xe7D\
+\xb9\x1e\x95HL\xcd  \x04ql\xe8(\xceL\x9f\xc1t<XR\x91T,\x15\xc5\x89\xa1~4\xb7\
+\xb7`e\xdd\n\x84"\xd9\x9b4\x82 \xc0f\xb5\xca7SD\x9c.xEB&\xa1\xab\xd7n\xc5\
+\xd6\x8em\xf0\xd6\xd6U\xc4\x8eTk\xf6U\x08\xbc\x8d\x0e\xd4X-\xe0x\xbeb\xae\
+\x8dz\x9f\xab$\xf1\xb9\xb4\xd9b4\xf5\x8dk\xbb\xd0\xbc\xf2\xef\xca>\xeer=\x1e\
+\x1b>\x8a\x97\x8e\xbf\x04\xd6l\xce*\x06S\x9d\x03\x1f\x05\xc4\x80\xce\xd6.|\
+\xef\x81\xb5\xb8~\xc7\x0e$R\xa9\xa2\xcf\xb9\x08\x80\xa2iU\xba"\x00\xb5\xd7P[\
+Q\x1fY\xd5\xa8vB\x07\x968\xa9\x03\x99<vA\x10p\xa4\xff\x14\x8e\xf4\x9f\xc2cO?\
+\x8d\xcb\xd6\xaeA\xd7\xbau\xe8\xa8\xf3b\xf5\xe5\xedY^#\xe5z$\xf0\xd6\xd6\xa1\
+\xbe\xad\x03\x80\xe4<8\x19\xf4\xe3\xb97\x9e\x93R\x0c\x8b,\xfe\xe1\xf84F\xcf\
+\x8f\xc1[[\x87F\x9f\x0f\xfd\xa7\x07r\xbe\xd6\xdb(-\x9b\x03\xe1\x0b\x05\x97\
+\xf8s\x02\x8f\xeb7\\\x8f\xbb\xb6\xdd\t@2\x17;x\xf0\x1d\x0c\x8e\x8e"\x1c\x8d"\
+\x14\x8d \x1c\x89\xa8"R\xbb\xcd\x86X<\xae\xfb\xa8\x07\xe2\xe5\xa2\xb4\xe1\
+\x05\xa4.Td\xa9N\x8c\xa5\xbc\x8d\x8e\xd9IX\x8a\xf4\xdd.\x17&\x03\x81\x8a\x91\
+\xba^vM\xbe\xe8\x9c/\xc0\x13G\xfe\xecY\x8d\x19\x90\xfcv\x94\xd9=\x95|\x04 \
+\xed\xad(\x8a\x80\xb4+\x11\xd5q\xceF\xea\x80D\xc0\x0e\xbb\xbd\xa4\xd5\xac(\
+\x08p:\x1c\xb8\xd8\xbe6sLB\x10\xcd\x90\xdc?\x1f~\xf4Q\xd9e\x15X\xdc\xd6\x92\
+\xa5"\x1c\x8d\xe2\xcd\x93\'aS\xd8\x18W3\x96<\xa9\x13\xd04-\x93\xfb\x85\xd04^\
+y\xedu\xec;x\x084\xcd\x80\xa1)X\xccf\xb99/k2\xc9}\x1c\xe7\xfbH`5\x9b\xe1\xf5\
+\xb8\xd1\xda\xb8\n\xdb;;q\xcb\x1d\xb7\xe2\xd37|\n\xee}n\xbc\xf8\xf6\x7f\xcfY\
+\xa6\xafE0>\x85z\x8fO\xd6\xcc\xb5\x10\x04\x01&\xc6\xac\xca2(\x04I.\x85\r+;q\
+\xd7\xb6;qb\xa8\x1f\xf7|\xf1\xefq\xf4\x9d\xf7 \x08<8\x9d~\xa1D\n)d\xf3Rn\x06\
+B\xd3\xb0\x9aL`M&\xd9\xab\xddn\xb3\xc1\xe5tJ\x93F8"\xf9\xac\xbbj\x81\x911\
+\x00Mr4o\xad\xab\x81\xd7\xe3\xc69\xffyTj\'\x84aY\xa9a\x83\x90\x02`\x99S\xae(\
+v\x9f\xa4\xc6f\xc3+o\xbc\x81}\x87\x0e\xc9c\xa4\\\xe3M\xef1\x95L\xa1\xf7\xea\
+\x0f\xe0\xbf\xbe\xf3\x1d\xd5q\x10B\xd7Z\x03\x00\xc5;\x9e\xe6\x82 \x08\xf0\
+\xb8\x9c*\xa9\x8d\x8c\xc9\xc9\xa0\x1f\xaf\x1e>\x84\xa3\xfd\xa7\x00HM2DQD\x9a\
+\xe3\xe5\xf1\xb6\x14\xc0\xb2,\xac\x16K\x955r\xc9\x8deC\xea\x044M\xc3j1\xcb\
+\x1a\xb4 \x8a\xa0\x00p\x82\x00n6B\x13\x93IP\x14U\x96G\x82iA\xc0d \x80#\xfd\
+\xa7\xb0s\xf7n<\xf2\xf3\xe7\xf1\xec\xa3\xdf\xc4]\xdb\xeeD\xff\xc4I\x9c\r\x0c\
+\x17E\x0eD;\xcc\xd5\xc4\x83\x17D\xd4\xba\xa4\xc8a2\xe8/*\x9d\xeb\x86\x9e\x1b\
+\x00\x00\x9f\xfd\xca\xbf\xe0\xf0\xb1\xe3\xb0\xd7\xd4\x80\xa1,\x80\xad\xb4TB\
+\x92\x9d\xa3\x9c4I\xc3c%\xa1\xeb\xa5\x85\xd5\x9bL\xf06:d\x99\xc6[[\x87\xd6\
+\xc6U8\xd2\x7fJj\x97V\t\xcb\x001\x93\xdb\x8c\x02\x95\x14\xa5\xb4U\x88\xa6.\
+\x88"\x12\xa9\x140Kd\xe5\x1aoY\x8f4\x8d\xe8L\xac\xe0<\xeah4\x06W\xbbC\xdeS\
+\xf4\xd6\xd6a\xcf\xfe\xd7JnRBz\x94*\xe5He\xa4\xeev8\xe5\x822\x87\xdd.\x9d\
+\x13 \xd3\x01\x89\x07 \x16\x90\xedD\xcd\xde;\xf4\xe2\xb7\x0f\xacv,\xb9\x94\
+\xc6bA\xcfv\xb7Q\xf6\re\x18\x064M\x97\xe5\x91\xfc\x98L&\x98L&\xd4\xcc\x12X\
+\xff\xe9\x01|\xe3\xfb?\x06\x00t4\\V\xd41g\xb9(\xb2lN?\x94b22\x92\\\n^g\x1d\
+\xbc\xb5u\xe8\xeb\xeb\xc3\xe1#Ga6[$\x0f\xed\x05\xb8Y\xb4\xbd1\tH5"\xd1`[W5\
+\x82\xe3\xb8\xca\xf9\xaaS\x94\xaa\xb7\xea\\\x1b\xa3Z\x14\xaa\xa9\xd34]\xb6q\
+\x96\xeb\x91\x9d%\xe2B\xf3\xa8\x1d\x0e\xbb$\xbd\xcc"0=\x85=\xaf\xff\x16\x89\
+\xd9\x89\xa2\x18\x90\x1e\xa5]\xeb\xd6\xc9\xcf\xc9f^:\xd0\x12\xba\xf4!"\xc0\
+\xd0s\xff\xd0\xa2A\xe8\x05b\xd9\x93\xfa\xa2@\xa0\xc0\xb2,^=x\x10\x93A?:[\xbb\
+fS\xfe\n\xcf\xbf\x1e\x8fH\x9e\xe7+\\\xb5\xba\xcb\xd4Rr\xb99>\r\xbb\xc5\x8ez\
+\x8f\x0f\xa7\xc6F\x10\x9e\x89U\xcc\x11\x91\xdc\xc0Zh\x1b\x11+K\xd4\xc9\x86\
+\xf6B\xa45\x02\x92\x9dk\xa1\x98o\x9ez\xa5\xa1\x8c\xd4\xe7\xda[!\xf6\x00\x1e[\
+\x1dF\xcf\x8f\xe1\xd5\x83\x07ab\x8b_\xb4\x0b\xa2\x08\x9af\xb2\xd2\x19\x95EeK\
+\xa9\x12s\xb9\xc0 \xf5J\x80\x96L\xb6\xa2\xb1\x18F\x07G\xe0\xad\xad\x83\x85-\
+\xae\n\xb1\x98~\xac\xa5|\xae\xb6\xac{\xa1\xa0\x8d\xd4\xeb\x15:%\x89\xd4\xdb[\
+\x9a`\xb3Z+g\x17 \x8aH%\x0b\x8f\xccy\x81/9O}\xa1\xa0\x8c\xd49\x81\xcf\xab\
+\xa7\x13{\x00\x00xi\xcfA\x8cNL\x94\xd4\xc6N\x10\x04X-fl\xde|\x89,\xbdh\'>\
+\xb7\xc3\xa9\x9a\xe0\xb9y\xf8\xcc\x18(\x0c\x06\xa9W\x10\xb1x\x1c\xa7\xc6FP\
+\xef\xf1\xc1f\xb1\x14e\xf0\xaf5\x9b*\x97\x1d-\xb9\xb1IF\xc2|;-)\xc1\xe51 \
+\x0b\xcf\xa6e\x16\x12\xa9\xc7&\xfc\x92=B\x05\xd2\xc7DQ\x84(\x8a\xd8\xb4\xb1\
+\x0b^g]A\x19\x1f\xda\xbd\x90R\xbc_\x16\x12\x85dA\x91\xfc\xf9\xa3\xef\xbe\x0b\
+\xa0\xb4\x86\xd3\x89d\x12\xeb\xdaV\xa3yeS\xce\xd7\x18\x91\xfa\xc2\xc3 \xf5\n\
+\x81\xa6i\x95\x87I\xb1\xf9\xea\xcb\x016k&\x9d.W\xbb:\xbdH\xfd\xf53R\xf1\x15[\
+\x81\x94FQ\x14\xc1P,:\xb7\xac\xca\xba&\x85\x16\x07U\x9b\xf7\x8b6cI\x0b\xe5\
+\xaa\x8fH/\x00p&0\x80\xa3\xfd\xa7`1\x97&\xc1q\x1c\x87\xab\xbb\xbbu\x0b\xc9\
+\xb4PE\xeb\xb3\x93\x7f%{\xd1\xfe.\xc3 \xf5\nB\x10x\xc4&\xa4\xe8\xb3RrJ\xa9X\
+\x88|ae)~8\x12\xd1\xdd\xcc#\x91\xba\xb6Iq\xa5\xd2\xddh\x9aF\x9aOa\xe4\xb8\
+\xfa\xfb\x97+O}1\xa0=Wde\xa1\xe7\xa1\xee\x8a\xd5\xcaQ\xfa;G\xa6\x10\x8aDJ\
+\x92^x\x9e\x87\xd9l\xc1\xa6\xf5\xea$\x00=\x93\xb6\\(\xe7*\xd1@\x06K\x86\xd4i\
+M\x06K\xa1?\x8b\x05\x92I\xa0\x94\x17\xaa\x99\x18\xca\r\xab&\xfas9\x9d\xbaKq\
+\x12\xa9++N{\xaf|?\x1cv{^9g>Hs\x1cB\xd1H\xc1\x96\xcd\xd5\xdcB\x8d-\x80\x90\
+\x95~/@\xc6\x8f\xe5@_i~A\x80\xe4\x10\xba\xca\xb7\x12\x976\xb5\xc8\xcf\xe5\
+\xca|\xc9\xa5\xa3\x1b\x91ze\xb0$\xf2\xd4y\x9eGb\xb6`\xa1\x18\x90b\x98R"\x91r\
+\xa3\x982\xfeJBYt2\xd7\xb2\xbdX(\t&\x91Je\x11\xbb\x1e&\xd3i\xb4\x93\xdf\x15\
+\xd1z%=6L,;\xab\xf1{a\xb3X$W\xc99R\x1a\x8b\xcdS_H\x14z\x1dI\x15\xa9\xc7V\x87\
+3\x81\x01\xbcs\xe6\x8cJ"+\x06\x1c\xc7\xe1\xf76oFs{\x8b\xaa\xaa\x95D\xea\xc4\
+\xba\xc0\xc0\xc2cI\x90\xba\xcdb\x81\xd3Q\x1a!r\xe94R\x8bX\xb9F"\xd1j\x91_\
+\x94\x86H\x95\xac\xe8\xcbE\xe8se\xbfL\x06\xfd\xd8\xf3\xfao\x11\x9b\x99\x81\
+\xdb\xe5\xaaX4\x17\x08*\xceC\x01&^JT\x8b\xa6\x9ek%\xaa\xdc\x1b\xc8UE\xfa\xdb\
+}C\x88\'\x92\xa8)\xe1\xbb\xa4\xd3ix=\x1e\xdcu\xfb\x07\xe5\xe7d\xa7\xcd\xf3\
+\x12\xa9+\t\x9d\xe3y\xb9\xfa\x95\xc0\x88\xd2+\x87\xaa\'\xf5t:\x8d/~\xf2\x93\
+\xb8\xf7\x8f\xee\xc8\xf2[)\x04\xbf\xd9\xbd\x1f\x9f{\xf4Q\xb9`c\xa11\x9fVa\
+\xcb\rn\x87d\x13\xa0W\x80\xa44\xfd\x1a\x9e\x18/j\x15!\xccZ\x13\x17\x1a\xd9\
+\x93q\x10\x89G\xe0\xb49\x0b\xda \x95\xf3\xd4\x97H\xf4\xa9\xd4\xd3\x1d\xc8l\
+\x08\x13=\xfd\xb7G\xdf.y\x834\xcdq\xd8\xd6\xd3\x83\x8dk\xbb\xe4{\xd2ZW\xa3Jg\
+\xcc\x15\xa9WJR+\x14\xe9t\xba\xe8&,\x0cM-\x19\x8b\x00`)\x90:\xc7\xa1\xbd\xa5\
+\xa9$\x17\xc1z\x8f\x0f\xa3\x97\x8f\x81\x17DT\x81\x02\xb3(\xad\xe6\xf2\xa1\
+\xdc\xf2\x8b\x12\x89T\n\x9e\x1c\x16\x07J\xeb\x03"\xbf\x90\xeb\x1b\x98\x9e\
+\xc2\xb8\xdf\x0f\x13\xcb\x16\x1c\xcd\xd14-\xa7*\x16B\xec4M!\x1a\x8b\xc96\x01\
+sy\xbfT{\x9ez>\xabb\xb2B$\xae\x8c\x80\xe4\xd7?21\t\x9a.M\xde2\xb1,\xde<y\x12\
+GN\x1f\x95\x89]\x9b\x9f\x9eKza\x19fQ\x89\xbd\xd6\xe5*\xe9}\x89D"o_\x83jB\xd5\
+\x93\xba\x12\x8f\xbd\xfc(\xce\x06\x86\xe7$F^\xe0\xe1\xb6\xbb\xf1\x8d\xbb\xbf\
+\xa1j\x88\xbb\x18 \xf2B5j\xea@\xe5\x96\xc1V\xb3\x19\xf1DR\xa5\xd9\x86\xa2\
+\x11\xb464f\x0c\xbd\xa0\x96_\x00`\xf4\xfc\x18\xceO](h\x1fD\x10\x04X\xcdf|\
+\xfc\x96\x9bq\xa0\xaf\x0fG\xfaO\x15$\'Hn@\xa4\xa2\xd4:\xa7\xf4\xc2\xd0\x0c\
+\x12\xe9\x84\x1c\xa9W\x83\xa6\x9e/\t\x80\x14\x1e)%?e\xc1\xd1\xeb\xfb\xce \
+\x95J\xc3l6\xa1\x14\x8a\xa2i\x1a\x81`P\xba\xb7f\xed\xc6\x95\x8d1\x00u\xa4\
+\xae\xdc\n#\x84^1_\x9f<H$S\xf8\xe2\'?\x89\xdb\x7f\xff\xda\xa2\xdew\xe4\xe8;\
+\xf8\xe2\xbf~\x13\xd3\xe1\xf0\x92\x88\xd8\x97\x14\xa9\xc7\x92\xb193H\xd8\xd9\
+\x1b\x90\x80X\xd3.\x16\x88\xfcR\xad\x9a\xfa|o.-\xb9(\x9d+\xb5\x9bpD~i]\xa5\
+\xef<\tH>0zMA\xf4\x90Js\xd8\xfc\xbe.|\xeb\x81\xbf\xc5\xc3\x8f>\x8aw\x87\xce\
+\x82\xe7\xf99\'\x04\n\x12\xb9\xd0\xbc$K\x14\xaa\xa9\x13\xa3\xaaj\xd1\xd4\t\
+\x18M\xc4\x1dO&e\xf9\x85\xe8\xe9a\xfb4V\x0b\xed\x08\xc6\xa7\xd0?(Y9\x97\x9a\
+\x1d\x96\xe6x\xacim\xc6\xc6\xaeK\xe4\xe7H\xe6\x8bnJc!\x86]\x15\x06\xf1\xa9io\
+i\xc2\xfa\xb6\x8e\xac\x14\xda\\P*\x04\xbc V\xcc9\xb4\x9c\xa8zRWn\xe6\xd9-\
+\xf6\x82,l\x95\x11\xf1bF\xea\xcae\xb1\xb6Bt\xb9BkI\xac%@\xad\x9eN\xe4\x17\
+\xa2\xa9\xc7&\xfc\x10\x04~\xce\xc9\x86\xa6(\xa4RI\xfc\xf1m\xb7\x02\x00n\xdc\
+\xb2\x05\xaf\x1e>\x84\xd7\xdf|kNR\'\x9f\xaa\x8c\xd4\x0bE\xbd\xc7\x87\xd6\xc6\
+U8|\xecx\xd5n\xf6\x91H]\xa9\xa7\xbbb\xb5\x80\r\x18\x9d\x1c\xc3\xd8\xa4\x1f&v\
+~z\xa4\xd6\x99Q\xa9\xa9\x07\xe3S\xd8X\xdb%\xbfV,Q\xe6\xa9$\xe6Z\xf5\xf3\x02\
+\x0f\x86f\xf0\xd0\x1d\x0f/\xf0\x91\xcd\x1fK&O\x1d\x98\x8d\xd4\x8bLk\\\xecH\
+\x9d`\xbe\x91z%\xb4\xbcrj\xeaJ\xdb\xdd\xb9\x10\nGT\x8d2\x80LD4\x99N\x83\xa6\
+\x999\t}&\x91\xc4\xa6\xce\r\xe8\xddz\x15&\x83\xfe\xa2\x8a^\xc8\xf1\x92H\xbdP\
+\x9c\tH\x11n\xbe\x95F5A\xa5\xa7\xcf\xe2\xf5}g0\x13\x8f\xcf+i@\x10\xf8\xacB2\
+\xd2\xf5\x0b\x906c\x95I\r\xe5\xb2\xb8(\x17&\x83~y\xd5\xcf\x0b\xbc\xee\x0f\'\
+\xf0\x0b\xd6W\xb6\xdc\xa8zRW\x12O)\xa5\xf6\x81\xf1h\xd6\xf2t\xa1 \x08\xbcJ3.\
+\xb5\xf8\xa8\x92\x1b\x9a\xe5\x8a6sm~\xe9\xe9\xcfn\x97S\xf6\x9e\xd1f\x07]\x08\
+O\xcfY\x8f \x88"\x04\x81\xc7\x9f]\xb7\x1d\xf5\x1e\x1f\xea=>\x04\xc6\xa3\x18\
+\xf7\x17\xb6\xa4\x86(\xaa&\x1fNH\x15\x94\xa7N\x9c37\xad\xbf\x0c,\xcb\x82_\
+\xa4\r\xbfbe\x13b\xb5\x1b\x8cOax\\\xfa\x0e\xf3\r\x12\xf42\x98\x8am\xd8\xb2X\
+\xa8\xf7\xf8d.af\xbb\x92i\x7fX\x9a\x91\xa3\xf8jv\xe7\xd4C\xd5\x93\xba\x12\
+\xb1d\xac\xe0\x96m\x04\xdeF\x87d\x0e\xb5\xc0\xd0F\'\xa5n\x94\xb6\xb74I\xde\
+\xe2er,Tn\x94\x12M\xbd\x1c\xc8U\xd9H\x1adh\xa1\x8d\xd4\t\x86\xcf\x8d\x03\xc8\
+O\\3\xf18.n[\x8d\x0f\\\xb7U\xf5\xbc\xd2\x96 \x1f\xc8\xb51Y\xa4\t\x85\xc8/\
+\xf9d\x18\x96f0\x11\x9a\xc0d\xd0\x8f\x8d]\x97\xa0\xb9\xa1\x01in\xf1\xb5b`n3.\
+\xb7\xdd\r\x8f\xad\x0e\xa1X\x08C\xa3c%\xd9\xecf}\xa6&\xb3Ik\xb9\xab:>TA\xea\
+\x99\x02\x85\xea\xe9\x04\xd5\x9a\xf5\x94\x0bUO\xeaZM\xbdX\xf9%0\x1e\xadxwz=\
+\x08\x82\x00\xab\xd5\n{\x83$+\x14Z\x92\xae\x07\x96e+gC[\x01\x14RI\xaa\x85\
+\xf6F\xcb\xb5\x82\x10E\x11\x1c\xc7\xe1\x0fo\xfc}\xac\x9f\xed\t\x0bH\xce\x8e\
+\xd1X\xe1\xe7\xd8j6\xc3is\xaa\\\x1a\xe7\xca\x80\x89%c8r\xfa(\xd6\xb7u\xe0\
+\xf76oF*U|O\xcf\x85\x82R\xee\x0b\xdb\xa5UQ4\x1a\x9bwCoQ\xc7C\x1d\xd0\xb7\x08\
+\xa8\xf7\xf8$\x99\xa6J\x9a[p\x1c\'\xcb\xb1\xb1d\xac*\xb2\xd1*\x81\xaa\'\xf5\
+\xf9\xc2\xdb\xe8X4\xf9\xc5QS\x83K\x9bZ0\x19\xf4#\x9eL\x16\xb5\xca\x88%cR{\
+\xb7FGY"+\x02e\xf6\xcb|e\x9db\xa2|\xb7\xc3\xa9_t4+\xbf\x90j\xd2\xe1\xf1sy\'\
+\xe1d*\x8d\xb6\xe6f\xdc\xb8eK\xd6\xdf\n\xcd\x7fNs<\xbc\x1ew\xd1r\x1e\xcb\x98\
+\xf0\xf2\xa9\x97\x00\x00_\xfc\xd4\'\xd0\xe0\xf3I\xfa\xf4"\xe5.\xb3\x0c\x03\
+\xd6d\xd2\x95R"\xe2\xb4\xae\x7fz\xa5\xa0\x8cf\x89\xb7L\xb5\x81e\xd9EOq^\x08T\
+=\xa9+\x89\xa7\x94h70\x1e-\xba\x82\xac\x1cHs\x1c\x9a\xeb}\xe8\xee\xee\xc6\
+\xe8\xe0\x08b\xa9h\xc1\xc6P,\xcd\xc8\x11\xa4\x97\xf6\x94\\\xf9\x97\x0fn\x97\
+\xb3\xa26\x01\xdat\xc6P4\x92\xe5\xa5\x0ed\xcb/\x81`(\xef$,\x08<\xae\xb8\xec2\
+4\xb7\xb7\xc8\xd1=y\xb4\x16\xd8\xed=\x95J\xa2\xb5qU\xd6\xe6\xf5\\Y0D\x82yz\
+\xdf3X\xdf\xd6\x81\'\xfe\xed\xcb\xa8\xb1\xd4 \x14\x0e/\x9a\x81\x9c\x9eYV\xae\
+\xc9*\x1aJ\xc8}z\xf5 \x8a\xe2\x9c\xfb\x04\xd4lj\xe0\xe0\xe8\xa8\xeay\xedF)\
+\x81\xdeD\xbe\x18 ]\x9aJM\x9c\xb0\x9a\xcd%u\x1b[\x0cT=\xa9+Q\xcaF\xa9\xb7\
+\xd1\xb1`\x17\x83T5&f\xbb\xea|\xee\x13w\x03\x00\x0e\xf9\x0f\x17\xbdI\x9a\xe4\
+\xe2\x08LO\xa1\xb9\xbd\x05n\x97\xabl\x13S4*M\x8c\xe5l\x19\x97+\xf3E\x99\xceH\
+"\xf5\\\x8d\xb4\x01\xe0\xe7\xcf>\x8f\xf3\x17.\x80\xc9\xb1\x82\x10\x04\x01&\
+\x96\xc5\xf6\xceNU\xfep\xbd\xc7\'\xcb\\sI\x0b\x84x]\x0e\x07\x9a\xeb\x9bT\x92\
+\xcb\\\x9b\xa5\x0c\xcd\xc0j\xb2b\xcf\xc9\x97\xd1\xd7\xd7\x87\xed=\xbd\xf8\
+\xcf\xef\x7f\r\x9b:7 \x14\x0e#:3\x03\x9e\xe7!\x08\x82<\x16\xca\re\xaa\'\xf1T\
+\xa1(*\x8b<\x9dT-\xa2\xd1\x98*\xf3\x85@/\xb2\xe7y\x1e\xf6\x9a\x1at\xaci\x87y\
+\x8ej^\x9af0<!\xed}\x90\x02#k]\x8d,\xbf\x04\xe3\x99\n\xd3\xf6\xe6f\xd5{\xc9X\
+Y\xe8tPA\x14Qc\xb5\xc8\r=\ni\x8e\xb2T\xb1\xa4\xf2\xd4KA`<\n\x8e\xe3\x10\xe5\
+\xb8\x8af\x91(\xd1\xdc\xd0\x80\x07\xee\xbc\x13\x1f\xbb\xf9V\x9c\x18\xea\xc7\
+\xe1\xb3\x87`5\x15\x16E\x12p\x02/W0\xea9\xe9\x11\x89\xa2\x18?\x12\x961a"!e?\
+\xdc\xb8e\x0b\x1ez\xec1Dgf`\xb3ZU7\xfa\\\x11\'\xb9!\x05Q\x9c\xf3\xb5\xb9\x9a\
+c\x00\xd9Q\xfa\xaec\xc7\x10\x9b\x99\xc9\xf9\x1eQ\x14Q\xebr\xa1\xbb\xbb[\xa5\
+\xc1\x93\xdf=.\'\xa6\xc3\xe1\xbcy\xea\x1c\xcf\x83eY\xf4^\xf9~xl\x19",\xd4\
+\xd0\x8b\xa1\x19$\xb9\x14\x1e\xef{\x1c\xb7\x0bw`{O/6\xfe\xa0\x0b{\xf6\xbf\
+\x86\x1f=\xf7<N\x9e\x1e@$\x1aEb\x81H\x83\x13\x04D\xa3\xd1\xacUPD\x9cF\xa3s\
+\x95\xec\xccH@*I\xb5Hs<\xacf3n\xbe\xe6Z\xfch\xe7N\xc4\x02\x01\xd09\xd2S\x19\
+\x9a\xc2\xb8\xdf\xafJ[Tf\x88xlur\xd4~\xe3\x96-\xf8\xf6\x93O":3\x03\xab\xc9\
+\xb4\xa0\x16\x01dR\x15\x04\x01\xb1\x99\x19l\xea\xdc\x80\xf5m\x1d81\xd4\x8fX*\
+Zt\xd2\xc5RA\xd5\x93\xba\x12\xa5\xc8/\x976\xb5`S\xe7\x86\xbc\xe42\x1f\x90|]\
+\x97\xc3\x81\xf6\xe6f\xb4\xb74\xa1w\xebU\xa8\xf7\xf8pb\xa8\x1f\xff\xb1\xff\
+\xdf\x91H\'\xaa\xa2\xf3\x91\x855#\x10\x99\xc2\x89\xa1~tww\xe3\xe37\xdf\x8c\
+\x9f\xbc\xf0\x02":\xb2H\xb1\xe9\x9d<w\x00\x00\x1a1IDAT`YV\xb6:\xe6,\x16$R)\
+\xc4\x13I\xc4\xe2\xf1\xac\x02$\x12\xad\x13=}s\xa3\x03\'\x86\xfa\xd1?8\x90w\
+\xe2\x15\x04\x01\xcd\xf5>4\xb7\xb7\xe8\xfe\xbd\xd1\xe7\xc3\xd0h\xfe\xde\xab\
+\xa94\x07\xef\x8a\x15\xd8\xd8u\t\xbc\xb5u\xd8\xf9\xd6\xb3\x00\xe6\x8e\xd2\
+\x95\xb0\xb0f$\xb9\x14~z\xe8)\x9c\t\x0c\xe0\xb6-\xb7\xe1c7\xdf*O\xe2\xa3\xe7\
+\xc7p\xf0\xe0;\xb8\x10\x9e\x96\xb3y*\xd5\xd6\xcd\xed\x90|\xea7^z\xa9\xeay=\
+\xcf\x17\x19\xa2\xa8\xdb*0\x1a\x8ba\xf3\xe6Kp\xe4\xd4ex\xf1\xd5\xff\xc9Y=\
+\xa9\\5\x92\x02$\xad\xa1W0\x9e\x19g\x9f\xbd\xfbn<\xf6\xf4\xd3\xb8\x10\x9a^\
+\x94\xcde\x96e\xd1\xe0\xf3\xc9+\xe7\xfd\xfd\xfb\x8a\xf6aJ\xa4R\x8b\x92pQ\n\
+\xaa\x9e\xd4\xb5y\xea\x81Hq\x9b0\xdd\xdd\xdd8\xf4\xb3\xff*\xf7a\xe5\xc5\x89\
+\xa1~\xec=\xb6\x17\xfb\xdf=\x80X*Z2\xa1\x17\x93J\xc5\xd2f\xf0Ba\x9e$\xffy\
+\xf0i\xdcW\xbb\x03\xff\xf1\xb5\xaf\xe1\xae\xdb?\x88\x83\x07\xdf\x915\xd2p4Z\
+\x10\x01\x91\xc9\x8c\xbcV[\x8cB\xe4\x00B\xe0\xca\x14F"\x95\x104\xaflBbj\x06\
+\xc1p$\xef\x8d\x93\xe6\xb8\x9c\x93\xf3\xa5M-\xe8Z\xb7\x0e\xbf=\xf2v\xde\xe3f\
+h\n\\Zr\\\xaco\xeb\x80\xd3\xe6D$\x1e)\xcaz\x17\x90\x88\x9d\x17x\x1c8\xbd\x1f\
+\x87\xcf\x1e\xc2\xa6\xd5=\xb8\xc8\xbb\x06\x1b\xd7v\xc1[[\x87\xed=\xbd\x05\
+\x7fV%\xa1\x8c\xd4C\x824y\xe7\xcbQ\xf7\xd2\x1e\xb4\xaej,Z\xb2$\x9a\xba\xd2*`\
+\xf4\xfc\x18\xbc\xb5uxp\xc7\x0e\xdc\xb8e\x0bN\x8d\x8d\xe0\xf0\x89\x93\xd2\
+\xb1,@\xe7-2\xf6:\xea\xbc\xf8\xc0u[\xe5(\xbd\xd0\x953\xd9cIL\xcd\x80K\xa7\
+\x17-\xe1\xa2XT=\xa9+Qh\x9e:\xd9h|z\xdf3\x002\x1b7\xc1\xf8TE~\x072Y%\xe3\x91\
+s\x98\x08M\xc8)S\xa5\xba2\x92\xef\x19\x98\x9eBP\xe7\x06`h\n\x89\x84\xe4qS\
+\xef\xf1\x15LH\x16\xd6\x8c\x81\xc9\x01<\xf6\xf2\xa3\xf8\xe8\xe6\xbb\xb0\xbd\
+\xa77\x8b\x80H\xc9~\xbeG\xf2\xff\x92\xd7\x93\x7fk_\xabE\xae\xe7\x9f:\xfa\xbc\
+$\x9d\xe4\xb8q\xf4d\x9e\xc0\xf4\x94\\|T\xdf-}\xe6\x13;\x9f\xcb\x9b\xb6\xc7\
+\xb2,B\x91\x08~\xf9\xc6\x1b\xe8\xee\xee\xc6\xa6\xd5=x\xe9\xf8K\x00[\xb8\x04C\
+\xc0\xd0\x0c\xec\x16;\x92\\\n\x07N\xef\xc7\x81\xd3\xfb\xb1\xf3-;\x1a\xdc\r\
+\xb2\x8f9\xa9\x0b\xf0\xd8\xea\xca6\xe6\xf2\x81\x8cG=\x0fu7M\xf6\x97\xb2cp-\
+\x89\xe7\x9b\\\x19\x9a\xc2\xf9\xa9\x0b8r\xf4\x1d\xf4n\xbd\n\xc0\xac\xa6>\x05\
+uU\xe9x\x14{\xe3{\xd1\xd9\xda\x85\xee\xeentww\xe3c7\xdf:\xe7w\xa8\x04&\x83~\
+\xec:\xb4\x07\xcf\xf6=\rN\xe0\xe7\xbc/9\x81\x87\xdbbA\xbd\xc7\x87#\xc2Q\x84c\
+3\x06\xa9\x97\x0b\xda<\xf5@dj\xce,\x12I\xf7\x8cK7+2\x95\x9c,c*\xfb\xefZ\x90\
+\xdc\xd7\xf9\xc8-\x9c\xc0c\xb5\xb7\x15\xeb\xdb:\xf0\xd4\x0b\xcf#\x12\xcd\xae\
+\x8a\xa5i\x1a3\x89\xa4|\x13\x15\x13\xa9\xdb-v\x9c\r\x0c\xe3[/}\x13n\xbb\x1b\
+\r\xd6Uh\xae\xcft\x84W\x12P\xa1d\xa2\x04\xd90\x1b\xc5\x88\xfc\x1cYuxk\xebpb\
+\xa8_\xfe\x9d`pd\x0c\xf1D\x02\xce<\xd9\x12\xda\xfd\x15om\x9dJ[onoA\xa3o\xa5,\
+y\xe8\x81\xa2(\xd04\x83W\x0f\x1f\xc2\x83\x00:[\xbb\xb0\xf7\xd4+\xe0\x05\x1e@\
+ie\xe1\x16\xd6,G\xeeI.\x85\x81\xc9\x01\xdd\xd7\x95:\xb6\xc8\x98R\xbe\x06\x90\
+&~\xa9\xfa\xd1,\xfb\xbd\xd8-\xf6\xac\x1c\xf5\xd5\x82\xd4[j:\x909\x07\xba\xc7\
+7\xab\xa1_\xdf\xbb\x19?\xf9\xf9\x0bH\xa6\xd3\xba\xaf5\x99L\x08\x04\x83\xd8\
+\xf9\xf2\xafeR\xd7"\x18\x9f\x02\xe3\x06\xf8\x90\x05\xfbc\xfb\xb0\xbf\x7f\x1f\
+\x9c\xe9z0\xee\xa4j<i\xc7Y9\xd3!\x95\x81V |\x01\xd3\xf1 \xac&kA\x81\x16\xc7\
+\xa7\xd1`]\x05\x008\xfb\xd6 R\xa9$\x1cU\x92\xc93\x17\xaa\x9e\xd4K\x05)\xf7\
+\x05\xa0\xba\x88\x95\xf8\xbd\xdc\xe0\xf84\xae\xbaH\xaa\x96$]\x80r\x91\x1d\
+\xc9\xbb\xf5\xbaV\xe0l`\xb8\xe0\xb4Ir\xfc\x81\xc8\x14&B\x1382\xf1&\x80\x0c\
+\xa9\x10\xe2\xa0y;\x04&\x96\xd3\'\xc5e\x96\xfc\xa9\xdd\xb4\xfa\xf8\x1cniyK\
+\xa2U~\xcc\x02o\xa3CZ\x92\x13\xd2\'\xddr\x00Y\xfe)\xa6|]\xaf\x11C\xa3\xcf\
+\x87\x81\xe1\xd1\xbc\x9b\xa55V\x0b\x8e\xf6\x9f\xc2S/<\x8f\x8f\xdd|+.o\xb9\
+\x02\x07N\xefG\xad\xcdST\xa4\xae\x05\x19s\xf9\xc6\xc6|\xc6\x16y^\x99z\xa9$s=\
+\xb8b\xb5\x08b\n\x17\xdb\xd7b\xdaq\xae\x80o\x01l\\\xdb\x85\xb6\xe6&\x1c}\xe7\
+\xbd\xbcn\x99\xc3\xe3\xe7r6\xae\xd1\x124=Ba\xdc3\x08L\x02\xa7B\xdaIo\x00\xd3\
+\x01@\\\xa1\x96\xce\xc2\xa9p\xd6\xe7J&l\xc5Yn\xb0\x8c\t\xec\xec\xaa\xaa\x18\
+\x90@\xa7\x7fJ\x9a\rY\x9a\xaeZ\x137%\xaa>\xa5q\xbey\xeaK\r\xb1d\x0ck\xea\xd7\
+`{O/\xfa\xfa\xfa\xf0\xea\xc1\x830\x9b-YdG\xd34R\xa9$\x06G\xa4\x8dA\'U[\x92\
+\xb7\x8c\x855\xc3n\xb1\xcb?\x16\xd6\x8cZ\x9bGz\xde,\x11\xb5\xdd\xec\x80\xcdF\
+\xc1f\xa3\xe02\xbbT?zd\xeep[\xe1\n:\xe0p\xd8\xe1L\xd7\x83\x0fY\xc0\xb8\xb37\
+\xc8\x94{\x06$E._6\r\x19\x0b\x84H\xf4\x1a1t\xad[\x87T*\x99\xf3sDQ\x94\xd3\
+\xea~\xf4\xdc\xf3\x00\x80\xad\x1d\xdbPk\xf3 \x96\xaa\xee\xc2\x14\x966\xeb\
+\x12\xba\x12\xca\xf6u$\x9dQ\x99\x8d\x02\x00\x10\xf4\xcf\x8d\xb2\x12\xd8\xe5t\
+\xcan\x99s\xc1[[\x97\xd7\x1f\xc5\x99\xae\x87\xd0"\xc2\xe1\xb0K\xe3\xc2m\xc5*\
+\xd1\xabzM\xadW\n\x0c\x94\xe3I9\xce\xc8\xf8\xa3y;\xecf\x87j\xcc\xce\xf5ca\
+\xcdE5\x0f\xe7g\xa5\xa8\xce\xd6.L\x06\xfd8\xd0\xd7\'Uu/\x01B\x07\x96\x00\xa9\
++Q\r\x19$\x95D,\x19C\xad\xcd\x83\xfb>\xb4\x03\x00\xf0OO<\x81\xa1\xd1Q\xddh\
+\x89\x90<1\xc6R\xca\'\xf3\x852Z\xb5\xd9(\xc4\xe3"L\xbc\x13\xf1\xb8\x884\xa3\
+\xd6\xf7CB4\x8b\xd8\xb5\xd0.\xb9\xb5HL\xcd\x14n\xc6\x05\xa8,_\xb5\x91\xe2\
+\xc7\xaf\xdb\x8e\xb6\xe6f$S\xf9#n\x87\xdd\x8e\xd7\xdf|\x0b\x8f?\xfe8\xd6\xb7\
+u\xe0\xe6\xf7\xdd\x02 sCW\x1b\xb4\x85QJB\'\xf7\x85\xb6\x98JYI\xda\xbc\xb2\t\
+\xe2\xb9\xd9\x82\xb3\x1ce\xfb\xc54\xa1V\x06[$\xfbE\x0f\x8c;\x89\x88i\x12\xce\
+t\xbd\\#\x01\x00aO\x14L*\xbbVBo<\xa5\x99\x88<\xfel\xb6\xca\xeb\xda\x89t\x02\
+\r\xee\x06\xaco\xeb\xc0\xe8\xe0\x08N\x9d\x19\x82\xad\xc0\xc2\xb6j@\xd5\x93z%\
+\xab\x1e\xab\t2\xa1\xf7\xde\x87z\x8f\x0f\x0f?\xfa(^x\xe5\x95\x9c\xb2\x0b\x89\
+\xa0\x8e\xbe\xfb.&\x83~t\xb6J\xfe\xd5\xe5 %B \x9c\x90\x92o\xa44\x13\x81\xcb\
+\xec\x82\x89Wg\x9f\xb8i\x87\x9cU\xe1p[\x11\xf7g\x13\x03\x1f\xcaO\x16\x01!\
+\x88`8\x02\x9b\xd5\x9a7\x1a"c\x81\xc8.\xcaG\x82\xee\xeen\xdc\xda\xfbA\xc4\
+\x13\t\xdd\xcf\xa0(\n\x1c\xcf#\x91J\xc1n\xb3\xe1\xcbO>\x89]\x87\xf6`{O/\xae\
+\xdfp=\x12\xe9D\xd5Z\xae\xce%\r\xe5\xf3\xec\']\x89\n\xad\xd5p;\n\xaf8V\xae\
+\x98\xb4\xfe/|\xc8\x02g\xba\x1e\x11\xd3$\x1c\x0e;\xc2\x1ei\xac\xc4\xfd\x16\
+\xd8|\xfa\xe9\x8dd<\x11\xc4\xe3\xd2\x98 \x84\x1e\x8f\x8bEy\xe0\x17\x03r\xff|\
+\xe8\xd2\xeb\x01\x00\xdf\xfd\xd9\xcf\x10\x8dF\xc1,B\x7f\xe3R\xb1t\x8e\x14\
+\xcbS~Ir)Yr\xb9\xaf\xf7>ys\xf4_~\xf8CX\xcc\xe6\x9c\x1a\xb3 \x8ap\xd8\xed8t\
+\xf4\x18F\x07G\xb0\xbe\xad\x03\r\xee\x06U\xd7\xa7RA\xc8\x83\xa5\xcd\xaa\x1b)\
+\xcdD\xb2tNed\x15\r%`\xf3%\xe1\n: \xb4d\xc8\x99q\'e}\x95\xa4\xbc)\xf3\x9a\
+\x03\xe3Q\xcc\xc4\xe3yupA\x14\xc1\xb2,Z\x1b\x1a\xb3d\x17\xe5\xbf\'\x83~t\xd4\
+y\xf3\x9a\xa0\xf1\xb3\xcf;\xecvDgf\xf0\xf9\x7f\xf87\xf4\xf5\xf5\xe1\xaemw\
+\xe2\xee-\xf7\x80\x9d5\xef\xaa\x16h]$\xf5\xa2t@_zQB\xcf\xa6\x81@\x99\xedB&\
+\xc9\xb9&\x80X<._\xc3\xc4\xec\xfe\x88\x9eSc\xc44)\xfd\x1f#\xb3\xd5\xbcA\x07l\
+\xbe\xa4n\x00\xa0\xb7\xeaSF\xe7$\xc8\x98\xcf\xdeG>$\xd2\tll\xb8B\x96?_\xdc\
+\xbb\x17\x0e\xbb}\xc9H/\xc0\x12 \xf5\xf9\xfa\xa9W+\x08\x99[X3nz\xdf\x87q\xdf\
+\x87v`}[\x07\x1e~\xf4Q\xfc\xd9\x83_F\x9a\x9b\xbb-\x1b\xcb0\x88D\xa3\xf8\xc9\
+\xee]\x002\xd1E\xb9"Mr\xe3\xc4\xe3\xa2\x1c\xa5\x93\x8d\xd1|\x08{\xa2\xa0G(8\
+\xd3\xf5\xf2sD~!\xb9\xcc\t\xc5&il\xc2_P\xe3\x06\x9afp\xe5E\x17I\x9f\xa3\x88\
+\xce\xb5\x12\x8c\xec\xd1\x9eG\x0f&\x9e)\x8e\x9a\x1a\x0c\x0c\x8f\xe2\xee/=(\
+\x97\xfe\x7f\xfe\xfa/`M\xfd\x1a\xc4\x92\xb1\xaa\x8d\xdas\x81H\x1c\xc4C]\t\
+\x97\xc3\x913\xfa\x16\x04^U$F\xea\x0c\xf8\x1c\x13#M3\x88+\xb2\xaf\xb4\xc5G\
+\x00\xe4\xbd\x14\xe58 \xd1z\xdco\x01o\xce^Yh\xa3t\x000\xf1N9\x98\xa8\x94\xfc\
+\xc2\x0b<b\xc9\x1866\\\x81\xbb{?\x8e\xc9\xa0\x1f\xf7\x7f\xf7;\x08E"\xf3r\xb5\
+\\\x0c,\xa9\xa3-\xc5O}1\xa1\xed\xa6B\x88<\xc9\xa5\xe0u\xd6\xe1\xa6\xf7}\x18\
+\x0f\xdd\xf10\xee\xdav\'\x00\xe0\x93\x0f<\x80\x87\x1e{\x0c\xbc \xf9T\xcc\x05\
+A\x14a\xaf\xa9\xc1\x8f\xfek\xa7,!\xdc\xbd\xe5\x1ep|\x1a\xb1dL\xfe\x7fK\x85\
+\x1c\x19\xda(\x84Sa\xddH]\t\xa5\xfc"\xb4\x88r\x84\xa6\x84^#\x05m\xa3\x0c=\
+\xf0<\x8fU\xbe\x95X}y{\xe6\xb3\x14\x12\x0cA\xbd\xc7\x87\x0b\xe1\xe9\xa2\xbc\
+\xe2]\xf6\x1a\xbc7t\x167}\xeesx\xea\x85\xe7\xb1\xbe\xad\x03_\xf9\xe8Wp\xf7\
+\x96{\xe0u\xd6!\x96\x8c\xc9\xd7m\xbe\xe7\xb4T\xcc\x15\x99\x12=}\xaeH}\xae\
+\xe8\x9b\x90t8*YV\xe7\xcbFJ\xe8\xec[(\xaf/\xe3N\x82\x0fYdM\x9dL\xf6\x00`\xf3\
+%u5u ;Z\x0f\xa7\xc2p\x99]\xb2\x0cC\x1e\xe7\x03\xed=\xc9\xd0\x0cnz\xdf\x87\
+\xf1\xc5;\xfe\x17\xea=>\xfc\xcd\xd7\xbf\x85W^{}Ii\xe9\x04U\x9f\xd2\xa8\x8d,\
+\xca!/,\x14H*\x15C3p\xda\x9cr>xgk\x97\xec\x05>\x19\xf4\xe3\xf1\xc7\x1f\xc7\
+\xd7\x9ey\x06C\xa3\xa3\xb0\xd7\xd4\xc0T\xc4N;\xc30H$S\xf8\xfc?\xfc\x1b\x9e|\
+\xc8\x83\xed=\xbdh^\xd9\x84\xfd\xfd\xfbpl\xec8b\xa9\xe8<\xceY\xc6s\x9a\x86]\
+\xbe\x99\x94\xc4\xee2\xbb2\xd1U\x08\x809\x01\xc0\nz\x84B\xd8\x13\x85\xd3"El\
+\x81P\x14\xdeF\x87L\x1a\xcah\x9d\x90p.\xd0\x14\x85\xf0\xcc\x0c\xb6_}5\x9aW6\
+\xe9n\x92\x12r\x9f\x0c\xfa\x8b\xaaV\xb4\x9a\xcdH\x00p;%\xdf\x98\x8f\xff\xd5_\
+c\xe7\xcb\xbf\xc6C_\xb8O.\xcc:1\xd4\x8f\xfd\xfd\xfbp:\xf0\x1e"\xf1\x08\x92\\\
+jA\xc7!\xcbH\xe4\x99D\n,\xcd\xc8\x8d\xb2U\x98\x8d\x01"\x91iI\x86\x81\x1d!\
+\x84\xe0\xb6\xbbq\x96\x1e\xc4j\xa1\xbd\xacV\x05\x0cMa&\x96)~#\x9b\xa5D\xbb\
+\xd7\xe6\x9b\xc7&\xfc\x80GZ\xc5EC\xb3\xe7\xce,=J\xe9\x8c\x99\x08=$D\xb3\x82\
+\x07\xf2\xefx\\\x84\xc0\xc4\x10K\x96\xd6E\x8c\x80\x14\x06\xba\xednlZ\xdd\x83\
+k:\xaf\x91\x8b\xe6\xee\xfb\xd2\xc3\xd8\xb9{7\x1cv{E\xdaHV\x1aUO\xeaJlZ\xdd\
+\x83Q\xeb\x98\x1c\x8dT+H\xa7\x19@\xca:\xf0\xd6\xd6\xa9\xaa(\'\x83~\xf4\xf5\
+\xf5\xe1\'\xbbwa\xd7\x81\x03\xe8?=\x00\xb3\xd9"\x97\xc0\x17\xab\xdfY-f\xf4\
+\x9f\x1e\xc0G\xee\xbf\x1f_\xfd\xcb\xcf\xa0w\xebU\xf8\xf4\r\x9f\xc2d\xd0\x8f\
+\xd1\xc1\x11i#2>\xa5\xf2R/7Ha\t \x91\xb8\xf7\xf2L\xb4E\xa27\xbd\x0c\te\x94\
+\x9d\xab\xd94/\x080\x9b-\xd8\xde\xd9\xa9\x9b\xc6\xa8\xfc\x9cz\x8f/\xaf\x13$\
+\x81\x9e\xb1\x94\xddf\x83\xc9d\xc2\xce\xdd\xbb\xb1\xef\xd0!\xdct\xcd5\xf8\
+\x8b\x8f|\x04\xcd\xed-\xf8\xf4\r\x9f\x02 ]\xbb\xc0\xf4\x14F\xcf\x8feU\x13/\
+\x06\x94\x15\xa3\x04\xdaL\xa3\xce\xba.\x8c\x9e\x1f\xc3\xb8\xdf\x9f\xd7\xc6\
+\x99\x8c\xbf\xc4\xd4\x0c\\\x8e\xfc\xee\xa6\x0c\xc3`&9#\xd7I\x90 \x85\\\x87\
+\xc0\xf4\xacS\xa3\x1d\x08\x08\x0e@\x91\xc1\x18\x18\x8f\xcaQ<\x000\x97d~\xd7[\
+\xdd\xcd\x07\xda\xf3C\xce\x8d\x97\xf6\xc0ZW\x933\xb8\xaa\x94W\xd4B\xa0\xeaI]\
+\xb9\\$2\xc5R\x02!\xd6=c\xaf!6\xe1\xc7\xebg\xce\xe0\xf8{\xef\xa2\x7f`\x10\
+\xb1\x99\x19\x98\xcd\x16\xb8]\xaeyo\xc4\xb8].\x8cNL\xe0\x8f\xff\xeeK\xb8z\
+\xd3\x15\xb8\xf3\xca\xab\xd0\xdd\xdd\x8d\xe6\xf6\x16t{\xba\xcb\xf4m*\x03\xe2\
+\x0b\xa3w\x0eh\x8aBt\xb6}\xdd-w\xdc\xaak1\xa0EG\x9d\xc4 \xa2(\xeaFZT\x8e\xc9\
+\x03\x00\xcc,\x0b\xaf\xc7\x83X<\x8e\'v\xee\xc4\xf3{\xf6\xe0\x8a\r\xeb\xf1{\
+\x9bz\xd0\xde\xd2\x84K\x9bZ\xd0\xdc\xde\xa2\xea\xba\xb4\x14\xf0\x8d\xef\xff\
+\x18\xfd\xa7\x07\xf2\x92U8\x92\x89\xe4\xdd.g\xde\xe6,4M\xc3\xc4\xb2\xd8\xf9\
+\xf2\xaf\x01H\xde;\xd6\xba\x1a9\x80\xa9\xf7\xf8\x80\xb6\xb2\x1d~\xd9A&\xe7\
+\xa7^x\x1e\x87O\x9c\xc4\x81\xbe>\x1c>v\xbcl\xf7\xe3b\xa2\xeaI\xddb6c\xe7\xcb\
+\xbf\x96\x8bl\xaa\x19\x17\xc2\xd3\x08\x85#\xb2)V8\x12A \x18B"\x95Btf\x06\x89\
+DB\x96\x19lVk\xc9\x91\xb9\x1e\x04Q\x84\xa3\xa6\x06i\x8e\xc3+\xaf\xbd\x8e\x03\
+\x87\xdf\xc4\nw-\x9a\xeb}p9\x9dhmh\x04 \xdd\xac\xe5\xf4R\xd7Bi\xa7\xab5\xeeR\
+6( Y0^\xda\x83#\xa7N\xc1l\xd6\xdfC \xe7\xc6n\xb3a\xcf\xfe\xd7\xb2\x9a\x1c\
+\xe4jv\xecp8 \x08B\xce\xcdfQ\x14\x91H\xa5\xb2Z\xef\x91\x08\xde\xf2\xff\xb7ww\
+\xbfm[w\x1c\xc6\xbf\x14E\xd9\x8ad\xcf\xdd\xda4\xe9\x1b\x06\xf7\xaa\xd7\xf9\
+\x97w\xbb\x9b\xdd\xec\x05E.z\xd1`\xc3\x80\r\x05\xd6\x15\xd9\x16\xb4i\x1b\'\
+\xee\xe6\xda\x92\x15\xd9\xa6D\xeeB:\xf4\xe11)Q\xb6\x93H\xbf<\x1f h\x91\xc4\
+\x8aM&\x8f\x8e\x0f\x0f\x0f;\x1dmu::\xbf\xb8\xd0\xc3/\x1f\xe9\xe1\x97\x8f\xd4\
+\xef\xf7\xf5\xee\xde\x9e\xba\xdb[\xba\x7f\xf7\xee\x95\xa79\xbd\xeac\xeb{?I\
+\xf4"M\x17\x1eoiv\xcc\xff\xf0\xf9_\xf4\xdb?\xfdQ\xfd^\xfdw\xb8\xadV\xac\x1f^\
+\x1c\xea\xbb\xbf=\xd1\xbb\x0f\x1e\x14_G\xdd\x1b\xa3t\xb9[\xe3\xe8\xf9\xa1~3\
+\xdf\xa8\xab\x89Wu\x8c\xc2\x07w\xf8\xfc\x95?\xfe\xbf\xcd\xe3\xc1@\xc7\x83\
+\xd9\xd4N\xbf\xdf\xaf\xfdnq\x93\xac}\xd4\xe38\xd6\xef\xbf\xf8B\xbf{\xf8\xf0M\
+\x7f*\x0b\xb5Z\xb1\xe2V\xa4\xf1\xd9Y\xb1\rm\x96M\x8b\xa5bq+\xd2\xf6\xd6\x96Z\
+\xc16\xb4\xb7)\xcbs\xc5q\xac\xdd\x9d\x1dM\xa7S\x1d\x1d\x9f\xe8\xe8\xf8DY6-\
+\xcdY\xdft_y\xf7Z\xee\xeb\x8c[\x91\x92$Q\xa7\xddV;I\xb4\xdd\xe9\xa8\xbb\xbdU\
+<t\xda\x8f_\xb8k\xa34\xbb\xdd\xbcn\xb3\xa4,\xcfu\xa7\xdb\xd5\'\xf7?\xd0\xe7\
+\x8f\xfe\\\xfc|\xd5\xeb\xf8>\xbe\xf7\xfe\xc2\xed\x02\xc2P\xb5\x93D\x934U;\
+\x8e\x8b\xb0gy\xae$I\x94$I\xf1l\xd4g\x87?I\x92\xfe\xf5\xedwW\xae\x03\xdc\xe6\
+~\xfd\xe1\xf9r\xc79\x8e\xe3bUO\xff\xcel:\xcb\x1d\xef\xf1\xd9\xb9NG\xa3\xd29\
+\x90\xa4\x83\xc3\x9f\x94e\xf9\xc2\xd5T\x9d\xa4\xad\x97\xa3\xb3\xcb\xc7\x0b&\
+\x89z\xdd\xae\xc6\xe7\xe7\xb5\x1f\x97e\xd3b\x9e\xfe\x97\xbb\xbf(\x065O\x9f\
+\x1f\x14\xa3~7\xa8y9\x1e+MSM\xb3\xbc\x98\xd6\x99\xdc\xf23\x0eZ\xadx\xe1\xd6\
+\xbe\xedv\xbb\xf83\xdd\xf1\x94\xa4\x9d~\x7f#\xe7\xce\xeb\xac}\xd4\xa5\xd9\
+\x06B\xaf\xeb\x01\x177\x11E\xb3\xb8\xad\x838\x8e\x97\xae\xfb\xbe\x8e\xf0\xb1\
+m\xee9\x99\x92J1\x97T\x04\xdd\xa9\x0b\xf1h\xbc`#\xb2<W\xc7;\xa6u\xaf\xe1\xb6\
+\xf4\x1d=?T\xef\xde]}\xb6\xff\xa9\x9e>;X8\xd2\x9c\xa4\xa9\xd4\xf0Q\x81\xee\
+\xdc.;\xbb\xb7\xf5\xb4#\xf79\x87\xc7\xba\xf8\xffy\xb8%\x15A?:9\x99\xad\xcdO\
+\xd3b\x8f\xfc\xa8\xd5R+\x8a\x96.\x8f\xcd\xf3\\\xad\xf9?\xb1\xfff?\xabw\xef\
+\xae\xfa\xbd\x9eF\x0b\xee\x1fp\x03\x16\xf7F\xe0.P\xbbs>\x18\x0e\xd5\xdd\xdeR\
+w{kvAz\xbeZf\x92\xa6\xa57\xce\xf0\x98U\x9d\xaf\xf0\xefk\xf8;\xdc\xc7\xf8w_\
+\xe7y6\xff\xb5\x8dZ\xe4wc\x1b\xf3\xd5FQ\xb4\xf6?6\x89\x8b\xf3\xaa?\x9aX\x18\
+\xe9\n\xe3\xb3\xfa\xd1`\xc8\x85\xc3m\x8f ]N\xf9\xb8)\xbaa\xf2B\x9f|p_I\xbb\
+\xbd0\xb2.,\xe1\x14\xccM\xbc\xaa\xbfKa\xd0\xa5\xf2\x92\xc2\xb3\x8b\x8b\xd9\
+\xd7\x1aE\x8at\xf9\xa6\xde\xf4\x9c\xa5\x93\xa9\xee\xdf}O\xef\'\xc9\xe5&q\xef\
+\xec)]\xb0*)nEW\xe6\xe1C\xbdnW\xe3\xb3\xcb\xd1s\xd53U\x9b\xfc;\n\xff\x1e6\
+\xf9\x98(j\xbduA\x976(\xea\xd8\x1c\xfeM,U\xcb\xe8\xfc \x1f\rN*\xd7;\xfb\xc2g\
+\x9f\x86\xdcH\xf1\xbd\xfd\xb6^\xa4\xa9Z\xdfG\xfa\xea\xf1c\xa5\x93I\xa3\x1bG\
+\xc2?\xbf\xdd\xf0\r\xe6u\xf2W\xeb\xf8atO\x98\xda\xeet\xf4\xab\xbd=\xbd\xbb\
+\xb7\xa7\xde\x9d;\x951wA\xcc\xb2\xac\xf81\x9dN5\x9dN\x95\xb4c}\xb6\xffii^\
+\xbe\xc9\n\x10\xf7\x06\x1e^O\n\x7f\x1d\xaf\xcf\xfa\xcfi`\xa3\xb8Q\x99\x0b\
+\xbb?\xfdr<\x18\x16\xa39?\xec\xdb\x9d\x8eNG\xd5\xb7\xe5\xe7y\xaew\xe6\x1f38=\
+\xd5n\xbf_\xbc\xce\xd1\xe0\xa4\x98\x86y\x91\xa6\xd2\x13i\xff\xe3\x0f\xf5\xd7\
+\x7f|\xad\xaf\xfe\xf9\xcd\xd2\xcf\xd5\xc5\xdb\x9f\x1a\x90.\x03\xba\x0e\x17\
+\xcd\xfc\xe7\xc0N\xa6\xd3\xe2s\x9e\xa4ii\xc4\xeeO\xc5t\xb7\xb7\xa4`\xd4\xec\
+\xaeoH\xd2\xc1\xe1aq\x9e\xdcE\xdfO\xee\xdd\xd7\xfeG\x1f\xe9\xc9\xf7?V>\x9d\
+\xaaJ\xab\xd5\xd2\xcf\x83a\xe9\\\xe2\xcd#\xea\xb8U\xe1N\x7f\xc7\xa7C\xed\xf5\
+w\x8a \xd7}L\xd54I\x9e\xe7J\xdam\xdd\xbf\xbb<0\xd2l\x1a\xe6\xc9\xf7?\xea\xe9\
+\xb3\x03\rF/\x17\xee\x05\xbe\xa9\x16\x85\xdd\xe7\xceC\xf8|XI\xfal\xffSI\xe5G\
+\x0e\xfa\xd7(^\xa4\xa9\xf6U^\xe2X%\x9a\x7f\x17Tu\xb3\xd7`8,\x8d\xd2\x97}7\
+\x86\xdb\xc3\xf4\x0bn\x95?\x7fZ\xe5x0,E\xe0x0\x9c?\x9b\xf4\xea_E7W\xea\xc7\
+\xc5-M\xab\x9a[wK\xfcv\xfb}u:\x89\xa6K\x9e\\\xefvk\x0c\xbfKX\xb7\xe9\x97,\
+\xcfK\xdf1\x84S1\xe1t\x8c\x9b\x92q\x0f\xfevqu\xc7\xd1M\x8f\xf8\xc7\xf2hpR:\
+\x96\xee\xfa\xc4\xa2\xc7\xda\xb5\xa2\xd9#\x15\xdd\xeb4}\xbe\xad\x7f\x91\x14\
+\xb7\x8f\xa8\xe3\xc6\xaa.~I\xf5\x11\x91.\xe3\xfe\xf4\xf9\x81^\x8e\xc7\xf5+T\
+\xe6\x01X\x14\x8b0\xec{\xbb;\xdan\xb0\n)\xcbs\x9d\xbe|\xa9\xf34-\x9e\xf7\xba\
+\xce\xfc\xb8O\xa6\xd3\xa5q\x97.\xdfd\x9b\x84]\xd2\xcaS)n\xc3/\xff\xdc\xfao\
+\xc2\x8b\xde\xe4\x9b^\xc4\xc5j\x88:\xae\xed:#\xdap\xfb\xd7\xc1pX\xbbEn\x96e\
+\xa5\x95)u!\x92te\xa4\xd9\xef\xf5j_\xd7\xe7VR\xd4\x8d\x84\xd7\xd1\xb2\xb8;~\
+\xd8\xdd\xa8]*\x87\xfd\xf8tX\x19\xf6\xbf\x7f\xf3\x8d\xbe\xfd\xe1Gu:\x8b\xdf\
+\x1c\xf3<\xd7\xd3\x83g\xc5\xeb\xb9\xd7\xae\x9az\t\xdf\xfc\x19\xa9\xbf\x1aD\
+\x1d\xb7\xc6\x9f7\xad\x1b\x19J\xb3(\xbb\x1fu\xab#\\\xd0\x7f\xfd\xd1\x87\xa5U\
+\x18Ua\x0f\xe3.\xad\xf6\x14\x9f\xdc\xbb\x18Y\xfa\x1c\xd6<:\xe1\x1b\x91\x8b{U\
+\xd8\x9d\xf0\xbc8\xee|<}v\xa0\xaf\x1e?\xd6\xe7\x8f\x1e\xe9,M\x1b\x8f\xa6\xab\
+V\xbc,\x1a\xa5\xaf\xfb\xb1\xddd\\(\xc5\xca\xdc\x8a\x0c\xff\xa2\x9do|v^\x19U\
+\xf7\x0f\xdf_\x11\xd3\xebv\xafL\xbd\xe4y^\x04]*\x07hwg\xa7\xf2\xe2kx\xb1n\
+\xd9\xdc\xbe/\x8a\xa2\xcb\x8b\x8fk>J\x0f\xb98\x86+d\\\xd8\xdbIR\xac\x8eq\xe7\
+e4\x1e\xab\xd7\xed\x16\xc7\xd5\xad\x869\xbb\xb8\xd0$M5\x9a\xefm\xdf\xe4\xde\
+\x81(\x8a4\x1a\x8f\xb5\xbb\xb3S\xba8\xea\x8e\x7f8J\xdf\xb4\xe3\xbb\x89\x88:n\
+$\x0c\xbb\x1f\x10I\xa5x\xb8\x11w8?\x9e\xab|\x87`\x96e\xc5\xaa\x0e\x17\xa0\
+\x90\x1fvI\xa5\x955\xee\xe7\xaa.\xbeV\xdda\xda\xf1\xeeV\xf6\xb7\t\xd8$\xcb\
+\x96>V\x85\xfd\xa7\xff\x1d\xe9l\x1e\xdb<sw_\xae~W\xf4\xcf\x83\xa1z\xdd\xee\
+\xd2\xa0\xe3\xf5 \xea\xb8\x91\xaa\xe5u>?\xca~\xdc\x07\xc3\xa1vwv4\x1a\x8f\
+\xb5\x9d$\xba\xf0\xee\\\xecn\xcdn+w\x91p\xff\r\xdf \xfc\x91\x7f\xb8a\xd3\xd9\
+\xc5\xc5\x95x\xbb)\x9db\x9f\x17\xef\xf3\rG\x92\x9b8=P\x17v\'|\xc3\xbd\x98L\
+\x14i\xbe\xca\xe8\x9a+~\xdcQj\x12\xf4\xc9t\xba\x91\xc7u\xd3D\xbb\x0f\x1ep\
+\x94\xb1\xb2\xaa=I\xfcH\xfa7\xc38U#ni\x16\x84p\xba\xc4}\\8\x95\x13\xbeF\xdd]\
+\x8f_\xff\xfb?\xb3\xa5\x8a\xde\x1e*w\xba\xdd\xe2F&7\xdd ]\r\x8f\xb4\x99Qw\
+\x9a\x9e\x9b\xd3\xd1H\xe7i\xdax\x8b\x8b\xf0^\x82\xb8\xd5R;\x8eK\xbb?\x96n\
+\xe2\xaa8\xae\xd2f\x1f\xdbM@\xd4qmM\xe3!\xadv\xe1\xb2n>\xbci\xdc\xfd\x15\x18\
+\xfek\xb9\x8d\xaf\xa4\xea\xf8X\x08\xba\xb3h#0\xc7\xddI\xdbt9gx\x8e\xfd\xf3\
+\x1b^\x90\xad\x9bC\xb7pl\xd7\x1dQ\xc7\xb55\r\x87\xaf*\xeeU\x11w\x91X\xf6\xf1\
+u\xa3\x7f_\xdd\xd4\x80T\x1d\x1f+\xe1\xa9;?R\xfd~:\xabnnV\x17s\x89\xa0\xbf)D\
+\x1d7\xd2$\xecR\xb3X4\xb9\x95|\x95\xd1\xbf\x9b\xba\xf1\xdf4\x96M\x0fX\nO\xd5\
+r\xc4\xa6q_E\xd5\x85P\x82\xfe\xe6\x10u\xdc\xd8uF\x84\x8b\xf8\x171\xab.\xc0V\
+\xbdA\xb8x\x87\x11w\x9a\x8c(\xad\x86\'<?uKQW9Wu+Z\x88\xf9\x9bG\xd4qc\xe1\x88\
+\xf0:a_\xb6\xec\xed:\xd3\x05U#\xffE\xeb\xa5\xad\x07\xa8\xeeF\xa2U\xee\x0c\
+\x0e\xdf\x10,N[m:\x964\xe2\xc6\xaan\x80\x91\xca\xcb\x1dWUZk]\x11\xe0\xba\xdd\
+\t+_+\xf8\xf3\x8b\x1bt\xde\xb2 \x85_cx\xbe\x9ab4\xbe\xde\x88:nM\x16\xdcn\xef\
+\xc7\xb3\xc9h0\x8cm\xf8\xe6P\xfa\xbdA\xa8\xc3\xe9\x9a\xbay\xde\xf0\x8d\xe2m\
+\x0e\x92\xff\xb5\xaf\xba\xb9\xd6\xdb|\xdc\xd6\x1dQ\xc7\xad\xaa\x1b\xb57\x1d\
+\rV\xfd\xbeE\x1f\x1b\xbe\t\xb8[\xe4\xeb>\x86\x98W\xe3x\xd8A\xd4\xf1J\xbc\xae\
+H\xb8;Q\xcf\xe7#s\xb7\x83!\xdb\xba\xe2mE\xd4a\x82\x7fW$A\xc7\xdb\x8c\xadw\
+\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\
+\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\
+\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\
+\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\
+\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\
+\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\
+\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\
+\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\
+\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\
+\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\
+\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\
+\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\
+\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\
+\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\
+\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\
+\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88\
+:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\
+\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\
+\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\
+\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\
+\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\
+\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\
+\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\
+\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\
+\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\
+\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\
+\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\
+\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\
+\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\
+\x00\x0c!\xea\x00`\x08Q\x07\x00C\x88:\x00\x18B\xd4\x01\xc0\x10\xa2\x0e\x00\
+\x86\x10u\x000\x84\xa8\x03\x80!D\x1d\x00\x0c\xf9?\xd2xo\xfe\xadF\xd4\xef\x00\
+\x00\x00\x00IEND\xaeB`\x82' 
+
+
+
+def getSageImage():
+    stream = cStringIO.StringIO(getSageData())
+    return ImageFromStream(stream)
+
+sageImg = getSageImage()#.Rescale(300,254)
+def getSageBitmap():
+    return BitmapFromImage(sageImg)#getSageImage())
+
+
+
+#----------------------------------------------------------------------
+def getSageStartUpData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x82\x00\x00\x002\x08\x06\
+\x00\x00\x00\x90\xc9\x03\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\
+\x00\x00\t&IDATx\x9c\xed\x9c_l\xdb\xc6\x1d\xc7\xbf\x92%eV\x9c\x00.\xed\rv\
+\xe4\xd8\xc8*\xd9\xe8\x1cL\x9b\x03t\xb2\x83!\x813\xa4\xe8\xacb\x0fE\xeb\x05\
+\xc5\xe0\xbe\xac\xe8\xd6>9\x18\x86"o\xc1\x02\x0c\x8d\x9f\x83\x0e\xc1\xea\xbe\
+\xac\x80\xd1=d\xf20\x14M\x16\x03K\xa6\x16\xb5\r\xadq1[n\x13\xff\x91ld"\xedX\
+\x94\xf8_\xe2\x1e\x18\xd2\xa4I\xd92-\xff\x91\xc3\xcf\x8bt\xd4\xf1\xeeD~y\xf7\
+\xfb\xfd\xeex.\x97\xbb\x06\xa5\xb8\xff\xdf\x7f\xc9\xeaw\x86gJ\xe6s8xHE\t\x00\
+ J"x\x89\x87(\x89\xb8\xf4\xd37\\\xa5\xf2\xbb\xac\x840\xf9\xed\xb8\x0c\x00\
+\xac\xc0\x02PD\xa0\x16,\x15\xa4\xca\xb7\xda\xa1\xa2\xc8\xb2\xf6\xfcj"\xe0D\
+\x0e4G\x83\x17y\xfc\xee\x17\xbf7\t\xc2$\x84\xc9o\xc7\xe5\x8d\x02\xd0\xab\xca\
+\xa1\xba\xe0DN\xfb\xae\n\x81fi\\\xfd\xe5\x1f\x0cb\xd0\x84\xa0\x1f\x06\x00 \
+\xcbf\x91\xe3r\x0659T/\xbc\xc8\x03\x00\x04I@\x96\xc9\x82\x17y\xe4\xf9<n\xfe\
+\xe6\xcf.\x00\xf0l<\x81\xe1\x19<a\x9e\x80fi\xd0\x1c\r\x9a\xa5\xb5B\xd4O\x87\
+\xea\xe2\x88\xf7\x88!\xcd\x8b<\x18\x9e\x81\xc0\n\xda1\x97\xcb]\x83\x7fL\xfe]\
+\x06\x94\xf1\x9f\x139\xd0,\x8d\xa5\xd5%M9bA\xd4l\x04\xc08\x069\x1cL\\\xae\
+\xf5\x9e\xdf\xe3\xf6\xc0[\xe3\xd5\xd2\xac\xc8\x82\xcbs\xe0\xf3<\xb8<\x87[\
+\x7f\x8c\xb9<\x00\xb4\xb1\x9f\x97x,\xad.\x81fid\x19ehP\x05\xe0\xdc\xfc\xeaB\
+\x7f\xbf\xa4\xa2\x04\xa9(\xc1\xe3V\x06\x00I\x90 \xf2"\xb8<\x07.\xa7\xd8\x10\
+\xae\x8f\xef},\x03\xebF\x05I\x93 \xb3\xa4#\x82C\x86\xbe\x87P{\x83\xfcj\x1e\
+\xb9\xd5\x1c\x00\xc0\xa3\xb7*I\x9a\xd4l\x02\xb1\xe0x\x08\x87\tY\x96\xe1r\xb9\
+\xb4\x87\xba \x16 \n\xca=\xcef\xb2\xf0\xe8\xbd\x01A\x124\x11\xe8Or8\x1c\xe8\
+\xef\xa7(\x88(\x88\x05d3Y\x00\x80[\xfdA\xef\x19HE\xc9\x11\xc13\x04Gs\x8a\xfb\
+X\t\xf7\xd0\xef\xf3\xe3\x04q\xc2t<M\xa5\xc1\x08Nx\xfa "\t\xeb\x9e\xa0G\x1fh\
+\xb0C$\x14\xc1\x85\xd3\x17\x10 \x02%\xf3\xb0\x02\x8b\x99\xa5\x19L\xa7\xa7\
+\xf1\xc5\xec\x17e\x0b\xe3\x83_\x7f\xa0}O.\'1\x14\x1b\xb2\xd5\xc6jf/\xae\x81(\
+\x88\xe6\x80\x12P\x9e\x97\xe0\xf7\xf91\x18\x1d\xdcT\x00*\xb5\xbeZ\x84\xdb\
+\xc2\x08\xb7\x85\x91ZIavyv\xfb\xadu\xd8U,\x85P\x0eo_|\xdb \x02\xf5\xa9OQ)\
+\xedX\xa89\x84\x16\xa2\x05\xb5\xbe\xda\x9d\xb5\xd2a\xd7\xb1%\x84\xce\x93\x9d\
+\x085\x85\xb4t<\x19\xc7\xc8\xbfG\xcc]\xfe\x84\xf2\xd1\xda\xd8\x8aS\xdf=\x85\
+\xb3\x1dgm7\xb4R\x04\x9b\x82\xe8h\xee\x00q\x8c\x00q\x8c\xd0\x8e3<\x83\x14\
+\x95\xc2W\x0b_a>3_vy\x1bm#2Kb5\xbf\xaa\xa5;Ov\xe2\x85\x13/\xa0\xa5\xa1E;\xb6\
+H."\x93\xcd\xe0\xee\xd7ww\xf8o*\x87\xeb\xfd\xbf\xbd/\x03\xeb\xaec\x96\xc9n9\
+\x86\x0f\x9c\x1b@$\x14\x01\xa0\xf4\x04\xef\xfd\xe5\xbd\x1d\x1b\x84\x83\xd1A\
+\x83\xb8\xecp=v\xddr\xd8\xa9?Z\x8f\xfe\x9e~\x84\xdb\xc2e\x95\x13O\xc61<6\\V\
+\xde`S\x10\x97\xa3\x97\xb5\xf4\xe8\xc4(b\x131\x04\x9b\x82x\xf3\xfc\x9b \xea\
+\x88\x92\xe7\xbe\xf5\xa7\xb7\x0c\xe9\xdd\xbc\x06zx\x86\xc7\xda\xff\xd6\xb0\
+\xf6x\r\xd9L\x164E\xdb\xeb\x11\xf4O\x12ES\x07\xde+h8\xdeP\xb6\x08\x00\xc5\
+\x00fx\x06#\xf1\x11[\xf5EB\x11\x0c\x9c\x1b\xb0u\xee~a\xdbFP\t\x10\x01\xb46\
+\xb6n\xab;\xddO\x12s\tL\xa7\xa7\x91ZI\x81\xcc\x92\x00\x80\x13\xc4\t\\\xfc\
+\xe1E\xc3\xd3\xd8\xdd\xdemK\x08\xe1\xb6\xb0\xc9vZ\xa4\x16\x91\\J\x828F \xdc\
+\x16>\x906\x93-!P4\x054\xad\xa7_\xfe\xd1\xcb\xf8h\xec\xa3\x1d\xf5\x0cVnQ\xa5\
+\\\'A\x120:1\x8a;\x0f\xeeX\xb6q5\xbf\x8a\xa9\x85)C\xd7\\\xeb\xabE\xb0)\xb8m\
+\x0fG/\x02\xab:7\xeb\xfew\xf3\x1al\x85{\xeb,ff\x96f\x0c\xe9p[\x18W^\xbd\x82\
+\xf3?8\x0f\xbf\xcf_\x91\x86U\x92\xf9\xcc<b\x13\xb1-\x85:\xf9p\xd2\x90\x0e<\
+\xb7\xb5kl\x05+\xb0\xb8\x1e\xbb^V\x9d\x07\x05[=B<\x19Gw{\xb7A\xd9D\x1d\x81\
+\xfe\x9e~\xf4\xf7\xf4#1\x97@b.\x81x2^\xb1\x86\xee\x05\xa9\x95\x94!]\xf7\x9d:\
+[\xe5\xdc\xfc\xe7\xcd\x92=\xc9\'\x9f\x7f\x02\x9f\xc7g\xab\xdc\xdd\xc4\xb6\
+\x8dp\xe3\xd3\x1bx\xad\xfb5\xcd{\xd0\xa3\x06\x8f^\xef~\x1d\x89\xb9\x04\xc6\
+\x1f\x8ecjajG\r\xad\x16\xee<\xb8\xb3\xe9\x7f=\xa8\xb6\x94m!0\x02\x83\xe1\xb1\
+a\xdc\x9f\xb9\x8fW\xce\xbcb9\xee\xd5\xfaj\x11\tE\x10\tE@\xe5(|x\xf7\xc3\x03\
+\x11U,\x15K\xa8\xc4\xb0\xa6.\xfc\xad6v\xec5\xcc.\xcfb(6\x84\xd6\xc6V\xbc\xf8\
+\xfc\x8b\xe8n\xef\xb6\xb4\x8a\x89:\x02\x97\xa3\x971<6\xbcoCF\xb4+\x8aH{dS\
+\xdf\xfeYe\xc7BP\x99\xcf\xccc>3\x8f\x91\xf8\x08:Ov\xe2\xcc\xa93\x96\xc3\xc6\
+\xc0\xb9\x01\x904\xb9\xa7=C\xfd\xd1z\xbc\xf3\xd2;\x96\xf3"\xc9\xe5\xa4\xf6\
+\xdd\xef\xf3\x975wr\x18\xa9\x98\x10\xf4L-Laja\n\xb7\xbe\xbc\x85\xb3\x1dg\xd1\
+\xd7\xd5g\xf8\xbd\xbf\xbb\x1fW\xffzu7\xaa6\xe1\xf7\xf9M"H\xcc%p\xfb\xc1m\x93\
+\x187F\t\x9f%vE\x08*\xab\xf9U\xc4&b i\xd2\x10i\xdb\xcb\xa7\xae\xf7t\xaf\xc9\
+\xb7\x8fM\xc4\xf6\xac\xfej\xc1V\x1ca\xbb\xc4\x93\xf1}3\xa2"\xed\xeb\xc3\x13+\
+\xb0\x8e\x08J\xb0\'B\x00\x80Ejq\xaf\xaa2\xa07\x0c\xab%\xb8\xb3\x1f\xd8\x12B\
+\xe7\xc9\xcem\xe5\xf7\xfb\xfch!\xd6\xa7a\xa9\x1cU\xd6y\xfa|\x95p\xed\x88:\
+\xc2\xd2\x80U\xcb\xefi\xef\xd9q\x1d\x95Fo\xcc\xea]\xddJcK\x08\xef\xbe\xf4.\
+\xae]\xba\x86hW\x14\xf5G\xeb7\xcd[\x7f\xb4\x1e\x83\xd1A\x83K\x19\x9f)\xcf}\\\
+$\xd7{\x91\x00\x11@\xb4+\xba\xed\xb6n\x14\xdd\x85\xd3\x17L\xa2\x8a\x84"\xb8\
+\xf2\xea\x15\x93Hv\xf3\xc2\x97\x0bE\xaf\xb7\x9f\xa8#vmV\xd3\xb6\xb1H\xd4\x11\
+\xe8\xeb\xeaC_W\x1fRT\n3K3\xc8d3Z\x98\xb6\xa3\xb9\x03\x01"`\x9a\xfeMQ\xa9\
+\xb2\xc7\xe9\xc4\\\xc2p~_W\x1f\xc2ma$\xe6\x12\xa6\xbc\xa1\xe6\x10&\x1fN\x9a\
+\x16{|\xf6\x9f\xcf\xd0\xdf\xd3\xaf\xa5\x03D\x00\xd7.]\xd3\x86\xaa\xcdVP\xa9\
+\xc2\xa0h\n\xf7\xa6\xef\x19\x16\x9c\xec\x15\xe3\x0f\xc7\r\x02\x8d\x84"\x085\
+\x87\x90x\x940\xd9]\xa5\xaeA9T\xc4k\x08\x10\x81\xb2<\x81\xe4r\x127>\xbdQv\
+\xb9\xf1d\xdc\xb40v\xb3\xba\x92KI\xd3\xb1\xbb_\xdfEkc\xab\xe1b\xd6\xfaj-#\
+\xa1\xa3\x13\xa3&\x0fG\x7f\xde~\x18\x9aS\x0bSHQ)\xc3\x7f&\xea\x08\xf4\x9e\
+\xee\xb5\xccou\r\xca\xc1\x96\x10\x86\xc7\x86\x11n\x0b\xa3\xa5\xa1\xa5\xac(]\
+\x8aJ\xe1\xf6\x83\xdb\xb6"\x8aC\xb1\xa1\x92s\x1a\xe52<6\x0c\x8a\xa6\xd0{\xba\
+\xd7\xf2\xe9\x8f\'\xe3\xb8\xf5\xe5-\xed\x89oon7\xd5\x97\xe3r\xb6\xeb\xdf)C\
+\xb1!\xf4u\xf5\x95\x8c\xdaV\x02[K\xd5\xf4\xa8k\xf6\x02\xcf\x05L\xb3u\x8f2\
+\x8f\x90\xa6\xd2\x15\xebR\x83MA4\x1ck@\xc3\xb1\x06\xed\x18I\x93 i\x12\x82$\
+\x945\xa1\x13l\n\x1a\xd2\xa5"\x9c\xad\x8d\xad\xda,\xe1\xc6u\x88\xfbI%\xae\
+\x81\xd5R\xb5\x1d\x0ba+\x9cW\xe7\x0e\x1eVBp\x03\xf6_n)\x07G\x04\x07\x8c\xa7\
+\xb7\xa3 \x14\x0c\x87\xdd\xbb)\x02\x87\xea@dE\xe3K\xb0\xce\xd68\x87\x1f\x192\
+D~\xfdux\x8eV\xb6E\xf0X\xdd|\xf5]z\x87C\x86\x0c\x14\xa5"\x00h{#\x88\x82\xa8\
+\xbc\xfb\xb8\xb1\'P\xf7F\x80\x0c\xc0\xd1\xc2\xa1B\x86\x0cI\x94 \xb2\xa2\xb2\
+\x7f\x12\xcdAdE\x14\xc5"<\xfa-r\xb4\x13\x9e\x1ax.\xd9\xe5\x88\xe1\x90 \xcb2\
+\x8aRQ\xd9;)\xc7!\x9b\xc9B\x14\x14A\x00OwU\xfb\xd5\xd0\x1b\x06\xd3\xde\xe3U\
+\xe2Ln\x8f\x1b.8b\xa8jd\xa5\'(JE\xb09\x16\xcc\x1a\x83\xb5\xc7kHO\xa7\x91#\
+\x95 \xd9\xf27\x8f\x95]\xd5\x98\'\x8c6fx}^\xd4xk\xe0\xf6\xb8\xe1=\xe2\x85\
+\xc7\xeb\x81\xdb\xa3\xd8\x94\x8e(\xaa\x04Y\xfdP\x04 \x89\x92a\xf3,\xbd\x08T\
+\xb4\x9dW/\xfe\xf6grAT|\xcb\x1ao\x8d"\x08_\x8dA\x18\x0e\xd5\x83j\x14\x16\xc4\
+\x02\xb8\x1c\x07.\xcfa%\xbd\x02\x9a\xa2\r"X\xfe\xe6\xb1q\xe7\xd5\x82X\xc0Jz\
+\x05\xc7\x1b\x8fc%\xbd\x02\x008\xdex|O\x1b\xefPy\xd4\xcd\xb28\x9a\xc3Zf\rE\
+\xb1h\x99\xcf\xb4)\xf7\x8f\x7f\x1e\x96U\xdf\xd2\xa1z\xd1\xdcCVq\x0f7\n@\xed\
+\tT,\xb7\xe9\x0f\xfe\xe4\xfbr\xa9\x02\x1c\xaa\x9f\x8d"\x00J\x08A\xa5\xe9\xf9\
+\xef9\x13\x05\x87\x08+\x01\xa8\xfc\x1f\x05\x81\x11\xc3\xb6\xc2\xdf\x94\x00\
+\x00\x00\x00IEND\xaeB`\x82' 
+
+def getSageStartUpBitmap():
+    return BitmapFromImage(getSageStartUpImage())
+
+def getSageStartUpImage():
+    stream = cStringIO.StringIO(getSageStartUpData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def getSageStartDownData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x82\x00\x00\x002\x08\x06\
+\x00\x00\x00\x90\xc9\x03\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\
+\x00\x00\x06\nIDATx\x9c\xed\x9d1h\xdbX\x18\xc7\xffN\x1b\x1f\x166=xYb,\xf0\
+\xf4\xbc\\\xb1\xc0\x934\x05\x0c\xbd\xc5\xde\x8a\x03]\x128\xae%]\xbd\x95\x0c\
+\x07\x85l\x9eC\xaf\x14|\xcb\r\x86\xa3\x83\xbd\xf4\xa8!\x93\x0cG\x0c\n\xe9bA\
+\xa9\x0f\x99\x18\x8e\xbc.\x0e1u9\xee\x86D\x8ae\xc9\x8e"\xcbv\x1a\xbf\x1f\x84\
+D\xb2\xa4\xf7\xf4\xf4\x7f\xdf\xf7\xbd\xef=+\xa1\xd0\xca=\x8c\xe3\xe7\xfd\x9f\
+\xfe\x1b\xfb!\xe7\x9b\xe3\xf5\xce\x9b\xd0\xb8\xcfBnB\xe0\x02\xb8\xdb\xb8\tbe\
+t\x07\x17\xc1\xdd\xc7\xed\x19[\x16\x81\x0b`91\xad\x83\xc3"p\x96\x93\x15\x80[\
+\x83e\xc6|\xf6\xdc"p\x00\x00\xa1\xa7\xaf\x9erk\xc0\xe1\x16\x81s\x01\x17\x02\
+\x07\x00\x17\x02\xe7\x92\xfbA]H\x08\x0bH\xac%\x1c\xfb;\xa7\x1d\x9c\x0f\xce\
+\x83*\x863#\xa6\x16\x82B\x15d\x1ff\x91 N\x11\x98\xf4\x07}\xe8\':Z\xdd\x16\
+\x1a\xad\x86ga\xbcz\xfa\xca\xfa[\xef\xea(UK\xd3V\xf7\x9bc^m\xe0[\x08BX@1_\
+\x9c(\x00\x93H8\x82t2\x8dt2\r\x83\x19\xd0Ot\xbf\xc5rf\x84o!\xec\xfc\xb8c\x13\
+\x81\xd9\xeb\rfX\xfbh\x9cB$""\xe1\xc8t\xb5\xe4\xcc\x1c_B\x90\x92\x12\xe8:\
+\xb5\xb6\x1bz\x03\x15\xb5\xe24\xf9\xcd\x8b_"\x11A\xe3\x14\nU|W4(h\x9c"\xb5\
+\x9e\x02\x89\x11\x90\x18\xb1\xf6\xf7\xbf\xf4a0\x03Z[\xb3\x89\xf9:Fc#\xd6c`=f\
+mKI\xc9\xea\x10&\x063\xc0z\x0c\xf5\xe3\xfa\x94w\x13\x1c\xbe\x12J\xdb\x1b\xdb\
+\x90\xa9\x0c\xe0\xc2\x12\xbc\xf8\xfd\xc5\xd4\x01a1_\xb4\x89\xcb\x0f\xa5Z\xc9\
+\xd5\xed\x90\x18\xc1\xa6\xbc\x89t2\xed\xe9:\r\xbd\x81\xf2A\xd9\xd3\xb14NQ\
+\xcc\x15\xad\xedZ\xb3\x86j\xb3\n\x1a\xa7\xd8\xde\xd8\x06\x89\x92\xb1\xe7>\
+\xfb\xf5\x99m{\x96mp\x1d\xbe,\xc2pOb=v\xebG\x05$F<\x8b\x00\x00d*\xe3|p\x8e\
+\x8aZ\xf1U\x9eB\x15lml\xf9:wQL=jH\x90\x04D"\xde\xc8\x9c.\x92\xa3\xf6\x11Z\
+\xdd\x96e\x9e\x81\x0b\xd7\x95}\x98\xb5\xf5F\x85*\xbe\x84 %%G\xecd\x06\xc8$F \
+%\xa5[\x193\xf9\x12\x02\xeb1`\xfdj;\x9f\xc9\xa3|P\x9e\xca2\xb8\r\x8b\x82\x1a\
+:\xf5\xbf\xf4Qk\xd6P?\xae\xbb\xd6\x91\xf5\x18\xb4\xb6f3\xcd\x91p\x044Nolf\
+\x87E\xe0V\xe6$\xf3?\xcb6\xb8\x0e_\x99\xc5\xd1\xc6I\'\xd3\xd8}\xbc\x8b\xec\
+\xc3,\x84\xb0\x10H\xc5\x82\xc4`\x06\xaa\xcd\xea\xb5B\xd5\xda\x9am{8\xc0\xbb\
+\t\xfdA\x1f\xa5Z\xc9S\x99\xb7\x05_\x16A\xd5U\xc8)\xd9\xa6l\x12%(\xc8\x05\x14\
+\xe4\x02\x8e\xdaG\xd0\xda\x1aT]\r\xac\xa2\xf3`\xd4\xbd\xf9\x15u\xf9\xa0<\xd6\
+\x92T\xd4\n"\xdf\xdd\x11\xd7\x00\x00\xfb\xef\xf6QP\n\xd6\xe8a\x183yTP\n\xd0\
+\xda\x9a\xf5\xb3\x0c\xd4?\xd4\'\xde\xebm\x8d\xa5|\x0b\xe1|p\x8e\xf2A\x19\xaa\
+\xae"\x9f\xc9\xbb\xfa\xbdH8\x02\x99\xca\x90\xa9\x0cv\xc6&\xf6\x94y2.\x97\x10\
+\x84[\xeb\x7f\xe9O}\x8dE0\xf5\xa8A?\xd1Q:)A$"\xe4\x94\x0c\x85*\xaeQ1\x89\x12\
+\x14sE\xfcv\xf0\xdb\xc2\\F>\x93\x87\x9c\x92\'\x8e\xed\x97\x95\xc0f\x1f\rf\
+\xc0P\rT\xd4\n\xa4\xa4\x04))\xb9\xba\x8d\xad\x8d-\x9c\x9e\x9d\xce\xd52\x90\
+\x18\xc1\xf3G\xcf]\xe7E\xf4\xeeU=\x84\xb0\xe0i\xee\xe4.\x12\x98\x10\x861c\
+\x82j\xb3\n\x85*\xc8er\xb6\xcf7\xe5M\xbc\xfc\xe3\xe5,\x8av \x84\x05\x87\x08\
+\x8e\xdaGx\xff\xe1\xbdC\x8c\xa3Y\xc2eb&B0a=\x86j\xb3\n\xd6c\xb6L\xdb<{\xdd\
+\xe8\x14\xb9\x99\x02\xe6\xd8\x99\xcb\n%UW\xd1\x1f,&\x88\x92SW\xee\xa9?\xe8s\
+\x11\x8canK\xd5\x165l\x1a\x0e\x0c\xbf\x95\xe4\xce"\xf0%\x04))\xdd\xe8x!,\xd8\
+\xb2t\xec\x8cM8\xfa\x8a\xe1\xe3\x82\x18\xda\x91(\x19;\x15.\x84\x85[1M>\xcap0\
+;<\xd4\r\x1a_B\xd8y\xb4\x83\xbd\'{\xc8g\xf2\xd7V\x8e\xc4\x08\x8a\xf9\xa2mH\
+\xd9h5<\x95\xd39\xedX\x7f\'H\x02\xf9L\xfe\xc6u\x1d\x15\x9d[\x1a\\\xa1\nv\x1f\
+\xef:F9\xb3lx\xaf\x0c\xafm Q\x82\xed\x8d\xed\x99\x94\xe3;X$Q\x82\\&\x87\\&\
+\x87\x0e\xeb\xa0\xd5m\x81\xf5\x98\xe5\x02R\xeb)\x88DtL\xffvX\xc7\xb3\x9f\xd6\
+\xda\x9a\xed\xfc\\&\x07))\xb9f\xeeh\x9cBkk\x8e\xc5\x1e\xf5\xe3:\nr\xc1\xdaN\
+\x90\x04\xf6\x9e\xecY\xf5\x9c\xb4\x82\xca\x14\x06\xeb1\xa8\xbaj{(\xf3Bkk6\
+\x81\xcaT\xb6\xeeu4y5\xae\r\xbc\x10\xc8\xa8!A\x12\x9eF\x02zW\xc7\xfe\xbb}\
+\xcf\xd7Uu\xd5\x11\xf5O*\xcb-7Q?\xae_$\xbb\x86\x1a3\x12\x8e\xb8fBk\xcd\x9ac\
+\x843|\xde"\x02M\xad\xad\xa1\xc3:\xb6{&Q\x82\xec\x0fY\xd7\xe3\xfd\xe6g\xeee\
+\xf2\x99_nz\xd2\xe7\xdeg\x84\x10\xc2\xea\xfdUO\xbe\xbb\xc3:x\xfb\xd7[T\x1a\
+\x15|\xfd\xf7\xeb\x8d\xca:\xfcx\x88\x07\xc2\x03O3\x81zW\xb7\xf9T\x13\xad\xad\
+!\x84\x10\xc45\x11\xab\xf7V\x1d\x9f7\xf4\x06\xf6\xff\xdc\xb7\x96\xa9\xad\xc5\
+\xd6\x1c\xe5i\x7fk\xf8\xf4\xcf\'\xc7\xb9$f\x8f;\xc6\xd5a\x1a\x0e?\x1eb\xf5\
+\xfe*\xd6\xbf_w\xad\xff0~\xcb\x9f\xfa\xbb\x8f\xe6\x9a=\x91\x88\x0eQ\x18\xcc\
+\xb0-\x00\x99\x16\x1a\xa7X\x8b\xae9VH\x9d\x9e\x9dZk\x0e\xbd\\c\x98q=H$\xa25K\
+8\xba\x0eq\x91\x04\xd1\x06n\xf0/\xc1r\x00\xf0\xaf\xbcq.\xe1B\xe0\x00\xe0B\
+\xe0\\\xc2\x85\xc0\x01\xc0\x85\xc0\xb9\x84\x0b\x81\x03\x00X\x99\xf4ZV\xcer\
+\xf0z\xe7M\x88[\x04\x0e\x80K\xd7\xc0\xad\xc2\xf2\xc2\xdf\xbc\xca\xb1\xe1x;;\
+\x7f\x0b\xebr0\xea\x05\x1c\x16\x81\xbb\x89\xbb\x8f\xdb3v\xfd\x7f\r&\xdc:\xdc\
+-&u\xf2\xff\x01\x07\x85\x9d\x95\xbbRg\x1a\x00\x00\x00\x00IEND\xaeB`\x82' 
+
+def getSageStartDownBitmap():
+    return BitmapFromImage(getSageStartDownImage())
+
+def getSageStartDownImage():
+    stream = cStringIO.StringIO(getSageStartDownData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def getSageStopDownData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x82\x00\x00\x002\x08\x06\
+\x00\x00\x00\x90\xc9\x03\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\
+\x00\x00\x06}IDATx\x9c\xed\x9dOh\xdbV\x1c\xc7\xbfN[\x0f\x9b\x84\x0c^`\x8d\
+\x91\xc1\xf4 _\x16,p/\xce\xc9`h/\xd2m$l\x97\x18\xc6\n\xee\xd5\xb7\xd0\xc3\
+\x0e%\xb7\xd2\xddL)\x05\xe7\xb2\x81a\xf4\x90\\Z0d=H0\x1a\xb0i;\xf0\x83\x81A"\
+\xbe\xf8\xf5\xe2\x10\xd3\x94\xb1\x1d\x1ci\xd6\x1f\xdbrb\xc9i\xf2>\x97\xe4\
+\xe9\xcf{O\xd2\xf7\xfd~\xbf\xf7{\x8a\x12\x89,\xdc\xc0(~\xaa\xfc\xf8\xef\xc8\
+\x9d\x9c/\x8e\xe7\xa5\x17\x91Q\xfb"^B\xe0\x02\xb8\xdax\tb\xc1\xb9\x81\x8b\
+\xe0\xea\xe3\xf5\x8c-\x8b\xc0\x05p=1\xad\x83\xcb"p\xae\'\x0b\x00\xb7\x06\xd7\
+\x19\xf3\xd9s\x8b\xc0\x01\x00D\x1e<{\xc0\xad\x01\x87[\x04\xce\x00.\x04\x0e\
+\x00.\x04\xce\x197\xe7\xd1h<\x1a\x87\xb0"\xb8\xb6\x1b]\x03\'\xa7\'s\xe8\x11\
+\'T!\xac\x8b\xeb(\xac\x15 \x10\xb7\x08L\xfa\xa7}\xd0#\x8aV\xa7\x05\xad\xa5\
+\xf9\x16\xc6\xb3\x07\xcf\xac\xdfi\x87\xe2\xc9\xde\x93\x0b\xf7\xf7:\x11\x8a\
+\x10\xe2\xd18\xcaJy\xac\x00Lb\xd1\x182\xa9\x0c2\xa9\x0ct\xa6\x83\x1e\xd1\x10\
+z\xc8\tE\x08\xa5\xfb%\x9b\x08\xccQ\xaf3\xdd\xda&&D$I\x12\xb1h,\x8c.q\x1c\x04\
+.\x04)%A\\\x15\xad\xb2F5\xd4\xd4\x9a\xdb\xe4\x1f\x0e~$I\x12bB\xc4\xba\xb8\
+\x1et\xd7&\x12\x8f\xc6!\xa5$\x08+\x02\x92$im\xd7\x99\x0e\xa3k\xa0\xd1n\xf8r]\
+d\x89\x80,\x11\xab<\x1c\x0b\x91%\x82uq\x1dbbp\x8f\xfa\x9f\xfaS\xbb\xc5Y\x10x\
+B\xa9\x98/"\'\xe6\x00\x0c,\xc1\xf6\xaf\xdb\x17\xbe\xc0\xb2R\xb6\x89\xeb<<\
+\xd9\x7f2\xd6\xed(Y\x05\x85\xb5\xc2D\x0b\xb5\x7f\xb8\x8f\xfa\xbb\xfa\xd8kR\
+\xb2\n\xe4\xac\xecj{c}\x03\x85o\x0b\x9e\xe7\xf4O\xfb\xa8\x1eT\xd1h7&\\\xc9l\
+\x08|\xfa8<\x12X\x8f}\x11\xb3\x82b\xbe\x089+\xfbrSrVFY)#\x1e\x8dO\xd5FY)\x8f\
+\x14\x010\x88\x95J\xf7J\x90R\xd2T\xf5\x9e\x97Pg\r\x02\x19\x98\xd8\xe1\xd8\
+\xe0\xb21l\xc1L4\xaaA\xa5*\x8c\xae\x01aE@z5m\xb3\x16\x02\x11P\xba_\xf2=S\xd9\
+\xccmZ1S\xff\xb4\x8fF\xbb\x01\xd6c K\x04RJ\xb2\t\xb0\x98/\xce\xc4\x8aN"p!\
+\xb0\x1e\x03V\xff/+Y\x05\xd5\x83\xea\x85.\xcc\xeb\x86\xcfb\xfa(&D\x97\x08*\
+\xaf+6\xf3L\x8f(\xe8\x11E\xa3\xdd@Y)[\x0fM\\\x1d\xc45*U\'\xb6c\x8a\xc0+^J\
+\x92\xa4\xad\xdeX4\x86\xc2Z\x01{\x87{S_\xcf4\x04\xee\x1a\x9c~8\x93\xca\xe0\
+\xd1w\x8fPX+LmN\x83F\xc9*\xb6\xf2\xfe\xe1\xfeH\x1f\xad3\x1d5\xb5f\xdb&\xdf\
+\x95=\x8f\xf5B\xa3\x9a\xe7\x80\xf0\xaa7\x97\xb6\x8b3\x08\x02\x17\x82JU\xd0\
+\x8e]\x0cd\x91`#\xb7\x81\xa7\xc5\xa7xx\xef\xe1\xa5\x99!8\x03\xd0\xfa\xbb\xfa\
+\xd8sT\xaa\x82\x1d3\xabL\x16\x89mv1\nS\x04\xe3\xea\x1d\x86,\x92\xc0\x07M(k\r\
+\x95W\x15hT\xf3\xdc\x97Ie\xb0\x95\xdf\xc2/\xc5_P\xcc\x17C\x0b\x8e\x9c\x98\
+\xd37\x93f\xbb\xe9\xcb}9-\x86\x9f\xfe\xfbq\x1f\xce\xc1\xe3\x95\x92\x9f%\xa1\
+\x04\x8b\'\xa7\'\xa8\x1eT\xa1R\x15JV\xf1\x9c\xfa\xc5\xa21\xe4\xc4\x1crb\x0e\
+\xec\x98\xa1zP\r5\xab\xe8\x1c\xc9~\x03Z\xa3k\xd8\xca\xb1\xaff\x93\x10s\xc6VA\
+\x13\xea\xea#=\x1a\x04q\x8f\x7f\x7f\x8c\xfa\xfb:\xfa\xa7}\xcf\xe3\xc8"AY._\n\
+\x971\x89\xeeq\xd7V\xf6\xe3\x1a\xfc\xc0z\xccV\x9eU\xbd\xa3\x98\xcb\xea\xa3\
+\xcet\xe8\xea (\x92R\x12\xa4\x94\xe4\x8a\xd6\x01`+\xbf\x85\xeeq\x97\xaf7\xc0\
+-\x8cY3\xf7\xf7\x11\x1a\xed\x06\xaa\x07Ul\xff\xb6\x8d\xfd\xc3}\xd7\xfe\xcd\
+\xdc\xe6\x1cz5\x7f\x86\x13q\x00\x02\xcf#\xcc]\x08&\xac\xc7\xb0w\xb8\x87\xdd\
+\x83]\xdbv?+\x96\xf3\xc4i\xb2ge\xbd\x9cB\xe8\x7f\xf2v\xa3\xb3\xe2\xd2\x08\
+\xc1D\xa5\xea\xc8\xd8!HZ\x9d\x96\xad\xecw\xf6\xe2\x14\xc2\xacL\xf8y\x83\xd7\
+\xf3r\xe9\x84\x00\x04\x7f\xd1^8G\xb2@\x04\xd7\xa8tb\xaeN\x0e\xe3\x14\xd4yp\
+\xa6\x99\x9b\xed\xe6\x85\xeb\x9cD\xe0B\x986/\x10\x8f\xc6m\xa3a8a3\x8e\xe1\
+\xe3\xce\x9b|q\xe6:&\xc5\'\xf2]\xfb\xc2\x14\xedP_\x16a\xd2l\xa8\xb0f_\x8c\nc\
+\x052p!\x94\xee\x95\xb0\xf3\xc3\x0e\x94\xac2q\x84\x91%b\xcb\xb3\x03\x80\xd6\
+\xf2ND9\x19\x9e\xcf\x0bDp\xa5\x8b\xfd\xb0w\xb8gsK\x99T\x06\xc5|\xd1\xf3\xd8\
+\xc2Z\xc1\xb5z\xe8w= \'\xe6PV\xca\x9e\xf7\xa3\x98/\xda\xf2,\x063|%\xa0.J(\
+\xd3G\xb2H ge\xc8Y\x19\x063\xd0\xea\xb4\xc0z\xccr\x01\xe9\xd54\x92$\x89L*c;\
+\xcf`\x86\xef\x9b\xdbh7l\xe7\xcbY\x19RJ\xf2\x1cMbBD\xa3\xddp\xa5\x90Y\x8f\
+\xa1\xa6\xd6\xb0\x95\xdf\xb2\xb6\xe5\xc4\x1c\xc4\x84h\x13\xa4\x94\x92\\Al\
+\xfd}}\xaa@Q\\\x15\xb1\xf3\xfd\x0e4\xaaYV\xc4\xab\xdeq\xa9\xe8Y\x12z\x1eA \
+\x82\xaf\x99\x00\xedPT^U|\xd7\xabR\xd5\xf5b\xec\xb8\xb6F=4s\xf4\r\x8b\xc1\
+\x14\xf2(\xea\xef\xeb\xae\x85\xa2qhT\xb3\xf2&^\xf9\x13\x93\xdd\x83\xdd\xd0\
+\xe2\xa5\x1bY%\xfbs\x90\r|\xec}D\x04\x11\xdc\xbay\xcb\x97\xef6\x98\x81\x97\
+\x7f\xbeDM\xab\xe1\xf3?\x9f\xa7j\xeb\xed\xdfo\xb1\x1c_\xf6\x95\x85\xa3\x1d\
+\xea\xca\xe7\x9b\xe8LG\xb3\xdd\xc4r|\x19\xb7\xbf\xbe=\xb6\x8e\xea\x1fU\xbc\
+\xf9\xeb\xcd\xd8\xb6\xd2\x89\xb4m-\xa3\xa6\xd5\xd0l7q\xe7\x9b;\x9e\xf7\x84v(\
+*\xaf+\xf8`|\x98x\x1d\xb3"\xd4\xbf}4\xff\x9e!I\x92\xae\x1b\xa03\x1d:\xd3g6\
+\xfd\x12\x13"V\x16W\\oHu\x8f\xbb\xe8\x7f\xea\xfb\x1eif\x9f\xd3\xabik\x9b\xe9\
+\xda\xfc\xf6u\xd4\xabjf?\xcd\xfb\xc1z\xcc\xaa;lBu\r\'\xa7\'\xd6\x8b\x1dAC\
+\x8f((.\xdeN\xd0}\x0e\xeb~L\xe2R\xe6\x118\xe1\xc3\x85\xc0\x01\xc0\x85\xc09\
+\x83\x0b\x81\x03\x80\x0b\x81s\x06\xfft\x0e\x07\x00\xb00\xee\xb3\xac\x9c\xeb\
+\xc1\xf3\xd2\x8b\x08w\r\x1c\x00g1\x02\xb7\n\xd7\x17\xfe\xe5U\x8e\r\xd7\xd7\
+\xd9\xf9WX\xaf\x07N/\xe0\xb2\x08\xdcM\\}\xbc\x9e\xb1\xe7\xffk0\xe1\xd6\xe1j1\
+n\x90\xff\x07\x00?\xc8\r\xeep)4\x00\x00\x00\x00IEND\xaeB`\x82' 
+
+def getSageStopDownBitmap():
+    return BitmapFromImage(getSageStopDownImage())
+
+def getSageStopDownImage():
+    stream = cStringIO.StringIO(getSageStopDownData())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def getSageStopUpData():
+    return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x82\x00\x00\x002\x08\x06\
+\x00\x00\x00\x90\xc9\x03\x88\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\
+\x00\x00\t\x91IDATx\x9c\xed\x9coh\x1b\xe7\x1d\xc7\xbf\x92%eV\x9c\x80{\xf66;r\
+,\x92E5\x145\xea\x94\x17S\x12\x863wII\xa5\xd0\x17#8]\x19\x82\xc2\xc0K\xde\
+\x14\x95\x11J\xdf\x8d\x85\x8e\xd6\xb4/\n\xa1\xd0\xaena+1\x85\x91\xd8c+\xd4\
+\x8d\xd9\xe6h\xa5qpk\xc6\xa4\xf3\xda\xd9\xb1\xfe\x90Ig\xc7:Iw\xba;\xe9\xf6\
+\xe2zg\x9dt\xfa\x17K\x8a\xed\xdc\xe7\x8d\xf4\x9c\xee\xcf\xa3\xbb\xef\xf3\xfb\
+ww\x8f\xc1`\xec@%\xe6\xfe\xfdwQ\xfe\x9e\xcde+\xae\xa7\xb3\xfd\x10\n\x02\x00\
+\x80\x17x\xe4\x84\x1cx\x81\xc7\xf3?~\xc1Pi}\x83\x96\x10\xee|}[\x04\x00\x86c\
+\x00H"\x90w,\xe4\x85\xe6\xf7Z\xa7\xa9\x88\xa22~\x15\x11\xb0<\x8b4\x9b\x06\
+\xcb\xb3\xf8\xf5s\x97\xcb\x04Q&\x84;_\xdf\x16K\x05P\xac*\x9d\x9d\x05\xcb\xb3\
+\xcawY\x084C\xe37\x17~\xab\x12\x83"\x84b7\x00\x00)&\x854\x9bV\xa9Ig\xe7"\x0b\
+\x82\x138\xa4\xb2)\xe4\xf8\x1c2\xb9\x0c\xde\xfd\xd5\xef\r\x00`*\xdd \x9b\xcb\
+\xe2~\xf6>h\x86F\x9aM#\xc5H\x1b\x01P>uv\x16{\xcc{T\xed\x1c\x9fC6\x97\x05\xc7\
+p\xca2\x83\xc1\xd8\x81\xbf\xdc\xf9\xb3\x08H\xfe_6\x1d\xb1\xf5\x98\xa2\x1c>\
+\xcf+1\x02\xa0\xf6A:\xdb\x13\x83a\xd3\xf2\x9b\x8c&\x98;\xccJ\x9b\xe1\x19\xb0\
+\x19\x16\xb9L\x0el\x86\xc5\xf5\xdfM\x19L\x00\x14\xdf\x9ff\xd3H\xd2I\xa4\x98\
+\x14RY\xc95\xc8\x02\xd0/\xfe\xce\xa2\xf8z\t\x05\x01BA\x80\xc9(9\x00\x81\x13\
+\xc0\xe7x\xb0\x19\x16lZr\x19\x86\x8f\xfe\xf1\x91\x08l\xfa\x90$\x9dD2\x95\xd4\
+E\xb0\xcb(\xb6\x10\xb25\xc8\xacg\x90^\x97b?SqT\x99\xa4\x93\xa0\x19Zq\x07:\
+\xbb\x07Q\x14a0\x18\x94A\x9d\xe7\xf3\xe09\xe9\x1a\xa7\x12)\x98\x8a\xb3\x01N\
+\xe0\x14\x11\x14o\xa4\xb3;(\xbe\x9e<\xc7#\xcf\xe7\x91J\xa4\x00\x00F\xf9\x07\
+\xd92\xe4\xf8\x1c\x84\x82\xa0\x8b\xe0\x11\x82\xa5Y\xb5khWzh\xb5Xq\x808P\xb6<\
+JE\x91\xe5\xf4Rv\xbb\x10\xb8\xcdLP\xa9#p\x02\xa7\xb9r3\xf18<x\xda\xf94l\x84\
+\xad\xe2:\x0c\xc7 \x1c\x0b#\x14\r\xe1\xf3\xa5\xcf\xeb\x16\xc6;\xbf|G\xf9N\
+\xc6I\x8cO\x8do\xb9\xbf\x8f\n<\xc7\x97\x17\x94\x80\xe6g\tV\x8b\x15\x01_\xa0\
+\xaa\x00d:-\x9dp\xd9]p\xd9]\x88\xacE\xb0\x14_jj_t\xb4\xd1\x14B\xb3\x19;3\xa6\
+\x12\x81<\xea#TDY\xe6\xe8w`\x80\x18@\xa7\xa5\xb3\x1d]\xd2)\xa1\xe5Bp\x1et\
+\xc2\xd1\xe7P\xdaA2\x88\xc9[\x93\xe5&\x7f^\xfa\x18\xec\x1d\xc4\xa1\xef\x1e\
+\xc2\xc9\xa1\x93\xad\xeeZM\xac\x16+\x8e\xda\x8fb\x80\x18\xc0@\xcf\x80\xb2|5\
+\xb9\x8aUj\x15_.\x7fY\x97\xeb\xea\xde\xdb\x8d\x9e\xfd=J\xbb8\x16\xea\xde\xdb\
+\x8d\x93C\'\xe1\xe8\x97\xceQ6\x97m\xd8-6\x03\xc3\xeb7^\x17\x81\xcd\xd41\x95M\
+5\xb5\x03\xfea?<\x0e\x0f\x00\xc9\x12\xbc\xf2\xc7W\xb6\xbc\xff\x80/\xa0\x12\
+\xd7\x83\xf0\xc6\xd4\x1bU\xdd\x8e\xcf\xed\xc3\x88s\xa4\xa6\x85\x9a\x9e\x9f\
+\xc6\xcc\xe2L\xd5\xff\xe4s\xfb\xe0u{\xcb\x8e}\xdes\x1e#\xce\x11\xcdm\x18\x8e\
+\xc1{\x9f\xbd\x87\xc5\xbb\x8b5\xfeI\xe3\xe4\xb29l\xfco\x03\x1b\xf76\x90J\xa4\
+@S\xf4f\xfa\xd8*\x88}\x84\xf2\x9d\xa2\xa9\x1d\x91\x15\xf8\x87\xfd\xf0\xba\
+\xbdu\xb9)\xaf\xdb\x8b\x80/\x00\xab\xc5\xda\xd01\x02\xbe@E\x11\x00R\xact\xe9\
+\x99Kp\x1et6\xb4\xdf\x07\xa5-1\x82\x8c\x8d\xb0a\xb0w\x10+\x89\x95v\x1e\xb6!\
+\x8a-\x98L\x90\x0cb.<\x87(\x15\xc5\x01\xe2\x00\x86\xfa\x87T\xd6\xc2F\xd80vf\
+\xac\xeeLe\xf4\xf8\xa8\x1231\x1c\x83\x85\xe5\x05P4\x05b\x1f\x01\x97\xdd\xa5\
+\x12\xe0\x8b?y\xb1)V\xb4\x16-\x17\x02ES@\xdff\xfb\xecSg\xf1\xc1\xec\x07[\xfa\
+cZ\'\xbc\x19\xe9\xe3\x91\xbe#e"x\xfb\xafo\xab\xcc\xf3R|\tK\xf1%|u\xf7+\xbc\
+\xf4\xecK\xcaEs\xf49\xe0qx\x10$\x835\x8f#\x8b@+^\x1a\xec\x1dT\xed\xb7\xd3\
+\xd2\x89\x11\xe7\x08\xa6\xe6\xa7\x1a\xfe?\x8d\xd0r\xd7\x10\x8e\x85Um\x97\xdd\
+\x85W\x7f\xf6*N=q\xaaas\xdaj\xce\x1d;\xa7jO\xcfOW\xf4\xd1+\x89\x15\\\xbbuM\
+\xb5\xccw\xccW\xf7\xb1\x82d\x10\x13\xb3\x13e\x03Bk\xbf\x9e\xc7\xd5\xe2l\x05-\
+\x17B\x90\x0c\x82\x8c\x93\xaaeD\x17\x81\xd1\x13\xa3x\xd3\xff&\xc6N\x8f\x95\
+\x8d\xc2\x87\x81\xd5b-\x0b@g\x16g\xaan\x13$\x83\xa0\xd2\x94\xd2&\xba\x08\x0c\
+\xf6\x0e\xd6<\x96,\x82j\xbf\x17Ct\x11-\x1f4-\x17\x02\x00\\\xfd\xe4jE\x93\xe9\
+\xb2\xbb\xe0\x1f\xf6\xe3-\xff[\xf0\x0f\xfb\xdb\x16\x1c\x95r\xf8\xfb\x87U\xed\
+\x85\xe5\x85\xba\xdc\xd7\xc2\x7f\x17T\xed\'\x0f>Ys\x9b\xb9\xf0\\\xcduJ\x07\
+\x8fVI\xbe\x99\xb4%X\xccrYL\xccN`.<\x87s\xc7\xcei\xa6~\x9d\x96Nx\x1c\x1ex\
+\x1c\x1ePi\n\xef\xdf|\xbf\xadUE{\xaf]\xd5..vUc\x95ZU\xb5\x9bU\x10+\x8d\xadZM\
+[,\x82\xccR|\t\xe3S\xe3\xb8\xf2\xa7+\x98Y\x9cQ\x1e\x97/\x85\xe8"\xf0\xb2\xef\
+\xe5m\xe12j\x91\xa4\x93\xaavq\xe1i+P4\xa5j\xdb\x1e\xab]\x9e\xdf\nmM\x1feV\
+\x12+XI\xac`28\t\xe7A\'\xdc\x87\xdc\x9a\x17\xdd?\xecG\x92N\xea\xf7\x1bP.\xb8\
+f\xd3V\x8b\xa0\xc5\xe2\xddEL\xccN\xe0\xf2\x1f.cz~\xba\xec\xf7\xd1\xe3\xa3\
+\x0f\xa1W\x0f\x9f\xe2B\x1c\xa0~?\xa1\x15<t!\xc8\xacg\xd615?U\x16M\xd7s\xc7\
+\xf2aRj\xb2\xc9\x18Ya\xcd\xc6(\x15B\xab\x1f\x13\xd86B\x90\t\x92\xc1\x8a\xb1C\
++\t\xc5B\xaa\xb6\xcb\xee\xaak\xbb\xd2t\xb1Y&|\x80P\xc7\x1a\xad\xae\xc6n;!\
+\x00\xe5\x91x;(\x8dCl\x84\r\xdd{\xbb\xabnc\xb5X\xcb\x04\x13\x8a\x86*\xac]?\
+\xce\x83NU\xf6\xb1\xb0\xbcPe\xed\xe6\xd0r!4Z\x17\xb0Z\xac\xaa\xd1P\\\xb0\xa9\
+F\xf1z\x0fZ|)\xadu\x8c\x9e\xa8\x1e\x9f\x94\xde\x98"\xe3$\xd63\xeb5\x8fs\xe2\
+\xf1\x13U\x7f?}\xf4\xb4\xaa\xbd+\x84p\xe9\x99K\xb8\xf2\xfc\x15\xf8\xdc\xbe\
+\x9a#\xac{o7\x02\xbe\x80\xea\xe4\x06\xc3\xb5k\xf7\x80\xf4\x8c\x80\x8c\x8d\
+\xb0\xc1\xe7\xae\xbf\xdc+s\xfd\x8b\xeb*\xb7$\x17\xbb\xb48\xf5\xc4\xa9\xb2\
+\xbb\x877n\xdf\xa8\xeb8\x1e\x87\x07\x01_@\xf3|\xf8\x87\xfd\xaa:K\x84\x8a\xd4\
+u\xffb\xab\xb4%}$\xba\x08x\xdd^x\xdd^D\xa8\x08\xc2\xb10\x12\xa9\x04"kR\xd1f\
+\xa8\x7f\x086\xc2Vff#T\xa4\xee\x9b-\x0b\xcb\x0b\xaa\xed\xbdn/\\v\x97\xe6hr\
+\xf4;p\xe7\x9b;\xb8\xf9\xaf\x9b\xaa\xe5\xeb\x99u\\\xbbuMu\xf1=\x0e\x0f\x1c\
+\xfd\x0e\x95 ]vWY\x10;\xb38\xd3P\x9a\xeb\xe8s\xe0\xb5\x9f\xbf&\x95\xa9\xbf\
+\xad\x19h\xed\xf7\xc3\xbf}X\xf7>\xb7B\xdb\xeb\x086\xc2VW&@\xc6I\\\xfd\xe4j\
+\xdd\xfb\r\x92\xc1\xb2\x07c\xab\x1d\xabRt/\x8f\xbeb1\xc8B\xae\xc4\xcc\xe2\
+\x0c&\x83\x93\r\xf5U\xae\x9bT+\x9aM\xccN\xb4\xed\x96}\xcb\x8501;\x01\x97\xdd\
+\x85\x81\x9e\x01\x10]D\xcd\xf5#T\x04\x9f.~\xfa@\xe6p|j\x1c\xe7\x8f\x9f\xdfrE\
+2H\x06\x11[\x8f\xe1\xecSg\xabf\x0fd\x9c\xc4\x8d\xdb7\x1a.x\xcd\x85\xe70\xff\
+\xcd<.\x9c\xbc\xa0yN\xc88\x89\x8f\xff\xf9q[\x9f\xdbh\xf9\xa3j\xc5\xc8\xef3\
+\xd8\x1e\xb3\xa1\xeb;]\xaa\xdf\x96\x13\xcb\x88P\x91\xba\x82\xadz8\xd2w\x04=\
+\xfbz\xd0\xb3o\xf3Y\xc1$\x9dD\x92N\x82\x13\xb8\xbaO\xb2\xdc\xe7\xa1\xfe!eY(\
+\x16B2\x95\xac\xbb\xaf\x95\x1eU\x93\xfb)\x9f\x8f$\x9dD(\x1aj\xda9\xa8\x84\
+\xd6\xa3jmu\rY.\xab<\xd8\xd1j\x9au\x9cV\xf7\xb9]\xe7\xa3\x16F\xa0=/\xb7\xe8l\
+\x13\xbe}e%\xcf\xe5U\x8b\x8d\xba\x08tx\x86\xdf\xac#\xe4\xf8\x9c>5\xce#\x80\
+\x08\x11|n\xf3ux\x96\x96nf\x99\xb4.\xbe\xfc.\xbd\xce.C\x04\nB\x01\x00\x94\
+\xb9\x11x\x8e\x97\xde},\xb5\x04\xf2\xdc\x08\x10\x01\xe8Z\xd8U\x88\x10!\xf0\
+\x02x\x86\x97\xe6O\xa2Y\xf0\x0c\x8f\x02_\x80\xe1\xe2\xbb\x17\xc5\xe2\x89\xb2\
+\x00\xa0P\x90Tc\x80A\x17\xc3.A\x14E\x14\x84\x02\x984\x03:A#F\xc6@S4\xd2Ii\
+\xa2\x14\x83\xc1\xd8\x81_\x8c\xbf\xa0z\xfd\xd9d\x96\xb2J\xa3\xc9\xa8\x8ba\
+\xa7#J\x96@\x16Av#\x8b\x8d{\x1b\x88\x86\xa2\x8a\x08\xe2\xff\xb9\'\xcd\xaa\
+\x96\xbd\x9fU|\x86\xd9bF\x87\xb9\x03F\x93\x11\xe6=f\x98\xcc&\x18MRL\xa9\x8bb\
+\x87 \xca\x1f\x92\x00\x04^PM\x9eU,\x02\x19e\xe6\xd53\x17\x7f*\xe6y)\xb7\xec0\
+wH\x82\xb0t\xa8\x84\xa1\xb3s\x90\x83\xc2<\x9f\x07\x9bf\xc1fX\xacE\xd7T\xee\
+\x00\x90\xac\x01Pt\xaf!\xcf\xe7\xb1\x16]\xc3\xfe\xde\xfdX\x8b\xae\x01\x00\
+\xf6\xf7\xeeok\xe7u\x9a\x8f<Y\x16K\xb3\xd8Hl\xa0\xc0\x174\xd7+\x9b\x94\xfb\
+\x87\xcf\xbaD9\xb7\xd4\xd9\xb9(\xe9!#\xa5\x87\xa5\x02\x90-\x81\x8c\xe64\xfdG\
+~tX\xac\xb4\x03\x9d\x9dO\xa9\x08\x80\nB\x90\xe9\xfb\xc1\xf7\xf49\xf6v\x11Z\
+\x02\x90\xf9?\xec\x08#j\x16n\xfd\xae\x00\x00\x00\x00IEND\xaeB`\x82' 
+
+def getSageStopUpBitmap():
+    return BitmapFromImage(getSageStopUpImage())
+
+def getSageStopUpImage():
+    stream = cStringIO.StringIO(getSageStopUpData())
+    return ImageFromStream(stream)
+
+
+
+
+
+##########################################################
+##########################################################
+##########################################################
+#
+# start everything
+#
+##########################################################
+
+if __name__ == '__main__':
+    # change to the folder where the script is running
+    # so that the relative paths work out correctly
+    os.chdir(sys.path[0])  
+    main()
Index: trunk/src/testing/bin/tileNodes.list
===================================================================
--- trunk/src/testing/bin/tileNodes.list	(revision 4)
+++ trunk/src/testing/bin/tileNodes.list	(revision 4)
@@ -0,0 +1,1 @@
+localhost
Index: trunk/src/testing/bin/yuv.frag
===================================================================
--- trunk/src/testing/bin/yuv.frag	(revision 4)
+++ trunk/src/testing/bin/yuv.frag	(revision 4)
@@ -0,0 +1,49 @@
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect yuvtex;
+
+void main(void)
+{
+    float nx, ny, tu, tv, ty;
+    float t, dx, dy;
+    float y,u,v;
+    float r,g,b;
+    int m, n;
+    vec4 vy, uy, yv, yu;
+
+    nx=gl_TexCoord[0].s;
+    ny=gl_TexCoord[0].t;
+
+    dx = gl_FragCoord.s;
+    dy = gl_FragCoord.t;
+
+    if(mod(floor(nx),2.0)>0.5) {
+
+	uy = texture2DRect(yuvtex,vec2(nx-1.0,ny));
+	vy = texture2DRect(yuvtex,vec2(nx,ny));
+
+	u  = uy.x;
+	v  = vy.x;
+
+	y  = vy.a;
+    }
+    else {
+	uy = texture2DRect(yuvtex,vec2(nx,ny));
+	vy = texture2DRect(yuvtex,vec2(nx+1.0,ny));
+
+	u  = uy.x;
+ 	v  = vy.x;
+
+	y  = uy.a;
+    }
+
+	 y = 1.1640625 * ( y - 0.0625);
+	 u = u - 0.5;
+	 v = v - 0.5;
+
+     r = y + 1.59765625 * v ;
+     g = y - 0.390625   * u - 0.8125 * v ;
+     b = y + 2.015625   * u ;
+
+     gl_FragColor=vec4(r,g,b,1.0);
+}
Index: trunk/src/testing/bin/sageAudioManager.bat
===================================================================
--- trunk/src/testing/bin/sageAudioManager.bat	(revision 4)
+++ trunk/src/testing/bin/sageAudioManager.bat	(revision 4)
@@ -0,0 +1,1 @@
+sageAudioManager.exe 67.58.62.100 20002 0 12000
Index: trunk/src/testing/bin/yuv.vert
===================================================================
--- trunk/src/testing/bin/yuv.vert	(revision 4)
+++ trunk/src/testing/bin/yuv.vert	(revision 4)
@@ -0,0 +1,7 @@
+#extension GL_ARB_texture_rectangle : enable
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+	gl_Position = ftransform();
+} 
Index: trunk/src/testing/bin/appLauncher/data.py
===================================================================
--- trunk/src/testing/bin/appLauncher/data.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/data.py	(revision 4)
@@ -0,0 +1,506 @@
+############################################################################
+#
+# AppLauncher - Application Launcher for SAGE
+# Copyright (C) 2006 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about AppLauncher to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+import string, os, copy, os.path, sys
+import traceback as tb
+from myprint import *   # handles the printing or logging
+
+opj = os.path.join
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath, SAGE_DIR
+
+## # read the master IP from the fsManager.conf
+## f = open(os.environ["SAGE_DIRECTORY"]+"/bin/fsManager.conf", "r")
+
+## FS_IP = f.readline().split()[2].strip()    #fsManager IP
+## FS_PORT = f.readline().split()[1].strip()  #system port
+## f.close()
+
+     
+
+class OneConfig:
+    ''' describes one configuration for an app '''
+    
+    def __init__(self, name, appName, dynamic=False):
+        self._configName = name
+        self._dynamic = dynamic     # dynamic config???
+        self._appName = appName
+        self._configFilename = getUserPath("applications", appName+".conf")
+        self._launcherId = ""
+
+        self._binDir = "$SAGE_DIRECTORY/bin/"  # where the binary resides - this is where the config is copied to
+        self._nodeNum = 1
+        self._position = (100, 100)        # initial position of the window on SAGE
+        self._size = (-1, -1)          # initial size of the window on SAGE
+        self._command = ""                 # the actual command used to start the application
+        self._targetMachine = ""           # the render machine where the app will be started
+        self._protocol = "TCP"
+        self._masterIP = None              # the master machine of a parallel application
+        self._fsIP = None                  # which SAGE will the app connect to (if not using sageBridge)
+        self._fsPort = None                # which SAGE will the app connect to (if not using sageBridge)
+        self._useBridge = False            # if True the app will connect to sageBridge instead of fsManager
+        self._bridgeIP = ""                # the machine for sage bridge
+        self._bridgePort = ""              # the machine for sage bridge
+
+        self._additionalParams = ""        # any additional parameters you want to specify... used for testing
+
+        # audio stuff
+        self._audioFile = ""
+        self._framePerBuffer = 512
+             
+        self._nwID = 1
+        self._msgPort = 23010
+        self._syncPort = 13010
+        self._nodeNum = 1
+        self._appId = 0                    # the port number for the app on the render machine
+        self._blockSize = (64,64)
+        self._blockThreshold = 0
+        self._streamType = "SAGE_BLOCK_HARD_SYNC"    # sync mode
+        self._staticApp = False             # static applications dont refresh their windows so sage needs to keep the last frame
+        self._runOnNodes = False    # if an app has to connect to the outside world or requires
+                                    #an SDL/GLUT window for rendering then it can't run on the nodes
+        
+
+    def getName(self): return self._configName
+    def getAppName(self): return self._appName
+    def isDynamic(self): return self._dynamic
+    def getConfigFilename(self): return self._configFilename
+
+    # audio stuff
+    def setAudioFile(self, f):
+        self._audioFile = f
+    def getAudioFile(self):
+        return self._audioFile
+    def setFramePerBuffer(self, fpb):
+        self._framePerBuffer = fpb
+    def getFramePerBuffer(self):
+        return self._framePerBuffer
+    
+  
+    def getLauncherId(self):
+        return self._launcherId
+    def setLauncherId(self, launcherId):
+        self._launcherId = launcherId
+
+    def setBinDir(self, d):
+        self._binDir = d
+    def getBinDir(self):
+        return self._binDir
+
+    def setNodeNum(self, num): self._nodeNum = num
+    def getNodeNum(self): return self._nodeNum
+
+    def setPosition(self, pos): self._position = pos
+    def getPosition(self): return self._position
+
+    def setSize(self, size): self._size = size
+    def getSize(self): return self._size
+
+    def setCommand(self, command): self._command = command
+    def getCommand(self): return self._command
+
+    def setTargetMachine(self, target): self._targetMachine = target
+    def getTargetMachine(self): return self._targetMachine
+
+    def setProtocol(self, protocol):
+        if protocol == "tvTcpModule.so" or protocol=="TCP":
+            self._protocol = "TCP"
+        else:
+            self._protocol = "UDP"
+    def getProtocol(self): return self._protocol
+
+    def setMasterIP(self, ip):
+        self._masterIP = ip
+    def getMasterIP(self):
+        return self._masterIP
+
+    def setFSIP(self, ip):
+        self._fsIP = ip
+    def getFSIP(self):
+        return self._fsIP
+    
+    def setFSPort(self, port):
+        self._fsPort = port
+    def getFSPort(self):
+        return self._fsPort
+
+    def setBridgeIP(self, ip):
+        self._bridgeIP = ip
+    def getBridgeIP(self):
+        return self._bridgeIP
+
+    def setBridgePort(self, port):
+        self._bridgePort = port
+    def getBridgePort(self):
+        return self._bridgePort
+
+    def setUseBridge(self, doUse):
+        self._useBridge = doUse
+    def getUseBridge(self):
+        return self._useBridge
+
+    def setNWId(self, id):
+        self._nwID = id
+    def getNWId(self):
+        return self._nwID
+
+    def setMsgPort(self, port):
+        self._msgPort = port
+    def getMsgPort(self):
+        return self._msgPort
+
+    def setSyncPort(self, port):
+        self._syncPort = port
+    def getSyncPort(self):
+        return self._syncPort
+
+    def setAppId(self, id):
+        self._appId = id
+    def getAppId(self):
+        return self._appId
+
+    def setBlockSize(self, size):
+        self._blockSize = size
+    def getBlockSize(self):
+        return self._blockSize
+
+    def setBlockThreshold(self, threshold):
+        self._blockThreshold = threshold
+    def getBlockThreshold(self):
+        return self._blockThreshold
+
+    def setStreamType(self, mode):
+        self._streamType = mode
+    def getStreamType(self):
+        return self._streamType
+
+    def setStaticApp(self, do):
+        self._staticApp = do
+    def getStaticApp(self):
+        return self._staticApp
+
+    def setRunOnNodes(self, run):
+        self._runOnNodes = run
+    def getRunOnNodes(self):
+        return self._runOnNodes
+
+    def setAdditionalParams(self, param):
+        self._additionalParams += param + "\n"
+    def getAdditionalParams(self):
+        return self._additionalParams
+
+    def writeToFile(self):
+        s = ""
+
+        # sage bridge stuff
+        if self.getUseBridge():      # using sageBridge
+            s += 'bridgeOn true\n'
+            s += 'bridgeIP %s\n'% self.getBridgeIP()
+            s += 'bridgePort %s\n'% self.getBridgePort()
+        else:                        # not using sageBridge
+            s += 'bridgeOn false\n'
+            
+        s += 'fsIP %s\n'% self.getFSIP()
+        s += 'fsPort %s\n'% self.getFSPort()
+        s += 'masterIP %s\n'% self.getMasterIP()
+        s += 'nwID %d\n' % self.getNWId()
+        s += 'msgPort %d\n' % self.getMsgPort()
+        s += 'syncPort %d\n' % self.getSyncPort()
+        s += 'nodeNum %d\n' % self.getNodeNum()
+        s += 'appID %d\n' % self.getAppId()
+        s += 'launcherID %s\n' % self.getLauncherId()
+        s += 'pixelBlockSize %d %d\n' % (self.getBlockSize()[0], self.getBlockSize()[1])
+        s += 'blockThreshold %d\n' % self.getBlockThreshold()
+        s += 'winX %d\n' % self.getPosition()[0]
+        s += 'winY %d\n' % self.getPosition()[1]
+        s += 'winWidth %d\n' % self.getSize()[0]
+        s += 'winHeight %d\n' % self.getSize()[1]
+        s += 'streamType %s\n' % self.getStreamType()
+        s += 'nwProtocol %s\n' % self.getProtocol()
+
+        # audio
+        if self.getAudioFile():
+            s += 'audioOn true\n'
+            s += 'audioFile %s\n' % self.getAudioFile()
+            s += 'audioType read\ndeviceNum -1\n'
+            s += 'framePerBuffer %d\n' % self.getFramePerBuffer()
+            
+        # static app
+        if self.getStaticApp():
+            s += 'asyncUpdate true\n'
+        else:
+            s += 'asyncUpdate false\n'
+
+        # additional params
+        s += self.getAdditionalParams()
+            
+        f = open(self._configFilename, "w")
+        f.write(s)
+        f.close()
+
+
+    def getConfigString(self):
+        """ returns a tuple of strings: (configName, optionalArgs that the app was started with) """
+        return (self.getName(), self.getCommand().split(" ", 1)[1].strip())
+    
+
+
+
+class AppConfig:
+    ''' a collection of all the configurations for an app '''
+    
+    def __init__(self, appName):
+        self._configs = {}   #key=configName, value=OneConfig object
+        self._appName = appName
+
+    def getAppName(self):
+        return self._appName
+
+    def addConfig(self, oneConfig):
+        self._configs[oneConfig.getName()] = oneConfig
+
+    def getConfig(self, configName):
+        return self._configs[configName]
+    
+    def getDefaultConfig(self):
+        return self._configs.values()[0]  #return an arbitrary config file
+
+    def getAllConfigs(self):
+        return self._configs
+    
+    def getAllConfigNames(self):
+        return self._configs.keys()
+    
+    def makeConfigFile(self, configName):
+        config = self.getConfig(configName)
+        config.writeToFile()
+
+
+
+    
+
+class Configurations:
+    ''' a collection of all applications and their configurations '''
+    
+    def __init__(self, configFile):
+        self._configFile = configFile
+        self._lastModTime = None  #last modification time to the config file
+        # sageBridge stuff
+        self._bridgeIP = None
+        self._bridgePort = None
+
+        self._appConfigs = {}   #key=appName, value=AppConfig object
+        self._readConfig()
+        #self._printConfig()
+
+
+        # so that we can change the config file without restarting the appLauncher
+        # checks the last modification time so that we don't reload unnecessarily
+    def reloadConfigFile(self):
+        try:
+            lastModTime = os.path.getmtime(self._configFile)
+            if lastModTime != self._lastModTime:
+                self._appConfigs = {}  #empty out the hash
+                self._readConfig()
+                self._lastModTime = lastModTime
+        except:
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+            
+        
+    def getConfig(self, appName, configName):   #returns a copy so that it can be safely modified without the destroying what's in the config file
+        return copy.deepcopy( self._appConfigs[appName].getConfig(configName) )
+
+    def getDefaultConfig(self, appName):   #returns a copy so that it can be safely modified without destroying what's in the config file
+        return copy.deepcopy( self._appConfigs[appName].getDefaultConfig() )   
+
+    def getApp(self, appName):
+        return self._appConfigs[appName]
+
+    def getAppList(self):   # returns just the names of the apps
+        return self._appConfigs.keys()
+
+    def getBridgeIP(self):
+        return self._bridgeIP
+
+    def getBridgePort(self):
+        return self._bridgePort
+
+    def _printConfig(self):
+        for name, app in self._appConfigs.iteritems():
+            print "\n----------------------------------------"
+            print "Config For: ", name
+            for name, config in app.getAllConfigs().iteritems():
+                print "Config: ", name
+                print "nodeNum = ", config.getNodeNum()
+                print "pos = ", config.getPosition()
+                print "size = ", config.getSize()
+                print "command = ", config.getCommand()
+                print "target = ", config.getTargetMachine()
+                print "protocol = ", config.getProtocol()
+                print "runOnNodes = ", config.getRunOnNodes()
+
+        print "\n----------------------------------------"
+        print "bridgePort = ", self._bridgePort
+        print "bridgeIP = ", self._bridgeIP
+
+
+    def getConfigHash(self):
+        """ returns a hash of all the configurations without the objects... just tuples of strings and ints """
+        strHash = {}   #keyed by appName, value = a list of configNames
+        for appName, app in self._appConfigs.iteritems():
+            strHash[appName] = app.getAllConfigNames()
+        return strHash
+    
+                
+    def _readConfig(self):
+        f = open(self._configFile, "r")
+        lines = f.readlines()
+        f.close()
+
+        self.appconfig = None
+        self.oneconfig = None
+        self.lineCounter = 0
+        
+        for line in lines:
+            self.lineCounter += 1
+
+            # allow comments with #
+            if '#' in line:
+                line = line.split('#')[0].strip()
+                
+                
+            if '{' in line:
+                appName = line.replace('{', ' ').strip()
+                self.appconfig = AppConfig(appName)
+                
+            elif 'configName' in line:
+                if self.oneconfig:
+                    self.appconfig.addConfig(self.oneconfig)
+                self.oneconfig = OneConfig(line.lstrip('configName').strip(), self.appconfig.getAppName())
+
+            elif 'nodeNum' in line:
+                self.oneconfig.setNodeNum(int(line.lstrip('nodeNum').strip()))
+
+            elif 'Init' in line:
+                lineTokens = line.split()
+                pos = (int(lineTokens[1]), int(lineTokens[2]))
+                size = (int(lineTokens[3]), int(lineTokens[4]))
+                self.oneconfig.setPosition(pos)
+                self.oneconfig.setSize(size)
+
+            elif 'exec' in line:
+                bla, target, command = line.split(' ', 2)
+                self.oneconfig.setTargetMachine(target.strip())
+                if not self.oneconfig.getMasterIP():   #if it has been set, dont overwrite it
+                    self.oneconfig.setMasterIP(target.strip())
+                self.oneconfig.setCommand(command.strip())
+
+            elif 'nwProtocol' in line:
+                self.oneconfig.setProtocol(line.lstrip('nwProtocol').strip())
+
+            elif 'bridgeIP' in line:
+                self.oneconfig.setBridgeIP(line.split()[1].strip())
+
+            elif 'bridgePort' in line:
+                self.oneconfig.setBridgePort(line.split()[1].strip())
+
+            elif 'runOnNodes' in line:
+                self.oneconfig.setRunOnNodes(True)
+
+            elif 'staticApp' in line:
+                self.oneconfig.setStaticApp(True)
+
+            elif 'pixelBlockSize' in line:
+                s = line.split()
+                self.oneconfig.setBlockSize( (int(s[1].strip()), int(s[2].strip()))  )
+
+            elif 'binDir' in line:
+                p = line.split()[1].strip()
+                if not p.endswith("/"):
+                    p += "/"
+                self.oneconfig.setBinDir(p)
+
+            elif 'masterIP' in line:
+                self.oneconfig.setMasterIP(line.split()[1].strip())
+
+            elif 'audioFile' in line:
+                self.oneconfig.setAudioFile(line.split()[1].strip())
+
+            elif 'framePerBuffer' in line:
+                self.oneconfig.setFramePerBuffer(int(line.split()[1].strip()))
+
+            elif 'sync' in line:
+                mode = line.split()[1].strip()
+                if not mode.startswith("SAGE_BLOCK_"):
+                    mode = "SAGE_BLOCK_" + mode
+                    
+                if mode == "SAGE_BLOCK_NO_SYNC" or \
+                   mode == "SAGE_BLOCK_SOFT_SYNC" or \
+                   mode == "SAGE_BLOCK_HARD_SYNC":
+                    self.oneconfig.setStreamType(mode)
+                else:
+                    WriteLog("\n*** Invalid streamType mode on line: "+str(self.lineCounter)+". Defaulting to NO_SYNC")
+
+            elif '}' in line:
+                self.appconfig.addConfig(self.oneconfig)   #save the last config
+                self._appConfigs[self.appconfig.getAppName()] = self.appconfig   #save the appConfig
+                self.appconfig = None   #reinitialize everything
+                self.oneconfig = None
+
+
+            elif 'defaultBridgeIP' in line:
+                self._bridgeIP = line.split()[1].strip()
+
+            elif 'defaultBridgePort' in line:
+                self._bridgePort = line.split()[1].strip()
+
+
+            elif line in string.whitespace:
+                pass
+            
+            else:    # if line is not recognized
+                self.oneconfig.setAdditionalParams(line.strip())
+             
+
+
+
+
+        
+                                 
+    
Index: trunk/src/testing/bin/appLauncher/KILL_LAUNCHER.py
===================================================================
--- trunk/src/testing/bin/appLauncher/KILL_LAUNCHER.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/KILL_LAUNCHER.py	(revision 4)
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+
+### script that kills the appLauncher running at the optionally specified port
+### this is useful when the appLauncher was started by someone else
+### but you don't have the permissions to kill it
+
+import xmlrpclib, sys, socket
+port = str(19010)
+if len(sys.argv) > 1: port = sys.argv[1]
+try:
+    xmlrpclib.ServerProxy("http://localhost:"+port).killLauncher()
+except socket.error:
+    print "AppLauncher doesn't seem to be running"
Index: trunk/src/testing/bin/appLauncher/GO
===================================================================
--- trunk/src/testing/bin/appLauncher/GO	(revision 4)
+++ trunk/src/testing/bin/appLauncher/GO	(revision 4)
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+
+cd $SAGE_DIRECTORY/bin/appLauncher
+
+echo "Killing previous instances..."
+python KILL_LAUNCHER.py
+
+echo "Starting a new server..."
+python appLauncher.py -a $HOST &
+
+echo "Done."
+
Index: trunk/src/testing/bin/appLauncher/appLauncher.py
===================================================================
--- trunk/src/testing/bin/appLauncher/appLauncher.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/appLauncher.py	(revision 4)
@@ -0,0 +1,327 @@
+############################################################################
+#
+# AppLauncher - Application Launcher for SAGE
+# Copyright (C) 2006 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about AppLauncher to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+from data import *
+from request import CurrentRequests, SSHRequest
+from SimpleXMLRPCServer import *
+import socket, os, sys, xmlrpclib, time, optparse, os.path
+import traceback as tb
+from threading import RLock
+from myprint import *   # handles the printing or logging
+
+opj = os.path.join
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath, SAGE_DIR, getPath, getDefaultPath
+
+
+APP_CONFIG_FILE = getPath("applications", "applications.conf")
+print "AppConfigFile: ", APP_CONFIG_FILE
+TILE_CONFIG_FILE = None
+XMLRPC_PORT = 19010
+SAGE_SERVER_PORT = 8009    # sage server port for reporting to
+SAGE_SERVER = "papyrus" #"sage.sl.startap.net"
+STOP_LAUNCHER = False    #used for stopping the applauncher remotely
+DO_REPORT = True      # for determining whether to report to the sage server or not
+REPORT_NAME = socket.gethostname()
+DEFAULT_SYSTEM_IP = None   # for application pixel streaming
+DEFAULT_SYSTEM_PORT = None
+
+
+# change to the directory of this script
+os.chdir(sys.path[0])
+
+
+# read the SYSTEM_IP from the fsManager.conf
+try:
+    f = open( getPath("fsManager.conf"), "r")
+    for line in f:               # read the fsManager line
+        if line.strip().startswith("fsManager"):
+            lineTokens = line.split()
+            if len(lineTokens) >= 4:
+                DEFAULT_SYSTEM_IP = lineTokens[2]
+        elif line.strip().startswith("systemPort"):
+            DEFAULT_SYSTEM_PORT = line.split()[1]
+        elif line.strip().startswith("tileConfiguration"):
+            TILE_CONFIG_FILE = getPath( line.split()[1] )
+    f.close()
+except:
+    DEFAULT_SYSTEM_IP = None
+
+
+
+
+class AppLauncher:
+    def __init__(self):
+        # read the tile config to get a list of all the nodes in this cluster available for running apps
+        self._nodeHash = {}  #key=IP, value=[0...n]   --> how many apps are running on that node
+
+        if TILE_CONFIG_FILE:
+            self.__readNodeIPs()
+        else:
+            self._nodeHash = {"127.0.0.1":0}
+
+        # read the sage app configuration file and create the container for all the requests
+        WriteLog( "\nUsing config file: " + APP_CONFIG_FILE )
+        self.configs = Configurations(APP_CONFIG_FILE)
+        self.requests = CurrentRequests(self._nodeHash)
+
+        # report ourselves to the sage server
+        self.sageServer = xmlrpclib.ServerProxy("http://"+SAGE_SERVER+":8009")
+        self.launcherId = ""
+        self.reportLauncher()
+
+                            
+
+    def __readNodeIPs(self):
+        f = open(TILE_CONFIG_FILE, "r")
+        for line in f:
+            previous = False  # True if previous line was an IP, False otherwise
+            if previous:
+                previous = False
+                continue
+            elif line.strip().startswith("IP"):
+                self._nodeHash[line.strip().split()[1]] = 0   #add the machine ip to the hash
+        f.close()
+        WriteLog( "\n\nNodeHash = \n" + str(self._nodeHash) + "\n\n" )
+    
+
+    def startDefaultApp(self, appName, fsIP, fsPort, useBridge, configName, pos=False, size=False, optionalArgs=""):
+        """ starts the application based on the entry in applications.conf """
+        return self.startApp(appName, fsIP, fsPort, useBridge, configName, optionalArgs=optionalArgs, pos=pos, size=size)
+        
+
+    def startApp(self, appName, fsIP, fsPort, useBridge, configName="", command="", optionalArgs="", pos=False, size=False, nodeNum=False, protocol=False):
+        """ receive the request for starting an app
+            either start the default app from a predefined config
+            or start a completely custom app with dynamic config
+        """
+        if configName != "":   # this assumes a default config and app startup
+            if configName == "default":
+                config = self.configs.getDefaultConfig(appName)
+            else:
+                config = self.configs.getConfig(appName, configName)
+        elif command != "":    # this assumes a completely custom app startup
+            config = OneConfig(appName+"_temp", appName, True)
+            config.setCommand(command + " " + optionalArgs)
+
+        # common set of parameters that can be changed in either case
+        if pos:      config.setPosition(pos)
+        if size:     config.setSize(size)
+        if nodeNum:  config.setNodeNum(nodeNum)
+        if protocol: config.setProtocol(protocol)
+
+        if not fsIP:
+            fsIP = DEFAULT_SYSTEM_IP
+        config.setFSIP(fsIP)
+
+        if not fsPort:
+            fsPort = DEFAULT_SYSTEM_PORT
+        config.setFSPort(fsPort)
+        
+        config.setUseBridge(useBridge)
+        config.setLauncherId(socket.gethostbyname(socket.gethostname())+":"+str(XMLRPC_PORT))
+        if useBridge:
+            if config.getBridgeIP() == "":   #means that there was no app-specific bridge info set so use the default
+                config.setBridgeIP(self.configs.getBridgeIP())
+                config.setBridgePort(self.configs.getBridgePort())
+
+        config.setCommand(config.getCommand()+" "+optionalArgs)
+
+        # create the request, set the appropriate appId, write the config file and submit it
+        return self.requests.addRequest(config)
+
+        
+    def stopApp(self, appId):
+        """ forcefully kills the application """
+        return self.requests.stopRequest(appId)
+
+
+    def appStatus(self):
+        """ returns a list of currently running applications as a hash key=appId, value=appName-command """
+        return self.requests.getStatus()
+        
+
+    def getAppList(self):
+        """ return configurations for all apps in a hash of strings """
+        self.configs.reloadConfigFile()
+        return self.configs.getConfigHash()
+
+
+    def getAppConfigInfo(self, appId):
+        """ return the configuration information for the running app """
+        if self.requests.getRequest(appId):
+            s = self.requests.getRequest(appId).config.getConfigString()
+            return s
+        else:
+            return -1
+  
+
+    def killLauncher(self):
+        """ used for killing the appLauncher remotely """
+        global STOP_LAUNCHER
+        STOP_LAUNCHER = True
+
+        # unregister from the sage server
+        if self.launcherId:
+            try: self.sageServer.UnregisterLauncher(self.launcherId)
+            except: pass
+
+        return 1
+
+
+    def reportLauncher(self):
+        """ only used to report ourselves to the sage server that we are still alive
+            every time pretend like it's our first time connecting so that even if the
+            sage server was started after the appLauncher, it will still be reported
+        """
+        if not DO_REPORT:
+            return
+        
+        try:
+            self.launcherId = self.sageServer.ReportLauncher( REPORT_NAME, socket.gethostbyname(socket.gethostname()),
+                                                              XMLRPC_PORT, self.getAppList() )
+        except socket.error:
+            pass
+        except:
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+
+
+    def test(self):
+        return 1
+
+        
+
+    # a mix-in class for adding the threading support to the XMLRPC server
+class ThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
+    allow_reuse_address = True
+
+class MySimpleXMLRPCServer(SimpleXMLRPCServer):
+    allow_reuse_address = True
+    
+
+
+
+def get_commandline_options():
+    parser = optparse.OptionParser()
+    h = "if set, prints output to console, otherwise to output.txt"
+    parser.add_option("-v", "--verbose", action="store_true", help=h, dest="verbose", default=False)
+
+    h = "change the port number that the server listens on (default is 19010)"
+    parser.add_option("-p", "--port", help=h, type="int", dest="port", default=19010)
+
+    h = "specify the application configuration file to use (default is applications.conf)"
+    parser.add_option("-c", "--config", dest="config", help=h, default="")
+
+    h = "which sage server to report to (default is sage.sl.startap.net)"
+    parser.add_option("-s", "--server", dest="server", help=h, default="sage.sl.startap.net")
+
+    h = "report yourself as *name* (default is the local machine name)"
+    parser.add_option("-a", "--name", dest="name", help=h, default=socket.gethostname())
+
+    h = "set this flag if you don't want the appLauncher to report to the sage server and become visible by other people"
+    parser.add_option("-n", "--noreport", action="store_true", dest="report", help=h, default=False)
+
+    return parser.parse_args()
+
+
+
+
+def main(argv):
+    global STOP_LAUNCHER
+    global APP_CONFIG_FILE
+    global XMLRPC_PORT
+    global SAGE_SERVER
+    global DO_REPORT
+    global REPORT_NAME
+    
+    # parse the command line params
+    (options, args) = get_commandline_options()
+    doRedirect(not options.verbose)
+    if options.config != "":
+        APP_CONFIG_FILE = options.config
+    XMLRPC_PORT = options.port
+    SAGE_SERVER = options.server
+    DO_REPORT = not options.report
+    REPORT_NAME = options.name
+
+    # set the default timeout so that we don't wait forever
+    socket.setdefaulttimeout(2)    
+        
+    # create the main object for handling requests
+    appLauncher = AppLauncher()
+
+    # start the local server and listen for sage ui connections
+    server = MySimpleXMLRPCServer(("", XMLRPC_PORT), logRequests=False)
+    server.register_function(appLauncher.startDefaultApp)
+    server.register_function(appLauncher.startApp)
+    server.register_function(appLauncher.stopApp)
+    server.register_function(appLauncher.getAppList)
+    server.register_function(appLauncher.getAppConfigInfo)
+    server.register_function(appLauncher.killLauncher)
+    server.register_function(appLauncher.test)
+    server.register_function(appLauncher.appStatus)
+    server.register_introspection_functions()
+
+    # now loop forever and serve the requests
+    oldT = time.time()
+    while not STOP_LAUNCHER:
+        try:
+            # report every 6 seconds that we are still alive 
+            if (time.time() - oldT) > 6:
+                appLauncher.reportLauncher()
+                oldT = time.time()
+
+            # accept and process any xmlrpc requests
+            # this times out every few seconds as defined by the setdefaulttimeout above
+            server.handle_request()
+        except KeyboardInterrupt:
+            break
+        except:
+            WriteLog( "\n=======> XML_RPC SERVER ERROR: ")
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+            continue
+
+    appLauncher.requests.stopSubmitThread()
+    server.server_close()
+    sys.exit(0)
+
+
+
+if __name__ == '__main__':
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
Index: trunk/src/testing/bin/appLauncher/myprint.py
===================================================================
--- trunk/src/testing/bin/appLauncher/myprint.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/myprint.py	(revision 4)
@@ -0,0 +1,62 @@
+############################################################################
+#
+# AppLauncher - Application Launcher for SAGE
+# Copyright (C) 2006 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about AppLauncher to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+import os.path, sys
+opj = os.path.join
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath
+
+
+REDIRECT = True
+
+def doRedirect(redirect):
+    global REDIRECT
+    REDIRECT = redirect
+
+### a global method used for writing output
+def WriteLog(text):
+    if REDIRECT:
+        try:
+            logFile = open(getUserPath("applications","output.txt"), "a")
+            logFile.write( text+"\n" )
+            logFile.flush()  #flush the buffer to a file (especially needed if running as a daemon)
+            logFile.close()
+        except:
+            pass
+    else:
+        print text
Index: trunk/src/testing/bin/appLauncher/README
===================================================================
--- trunk/src/testing/bin/appLauncher/README	(revision 4)
+++ trunk/src/testing/bin/appLauncher/README	(revision 4)
@@ -0,0 +1,56 @@
+#
+#
+#	APP LAUNCHER for SAGE2
+#	
+#
+# Ratko Jagodic - Nov 8, 2006	
+--------------------------------------------------------
+
+
+
+1) INSTALLATION:
+------------------
+- appLauncher comes with sage and is placed in the bin/appLauncher folder
+- there is no need to install it but you do have to have python2.4 or 
+  later in order to run it
+
+
+
+2) CONFIGURATION:
+------------------
+- you need to modify the "applications.conf" file in the appLauncher folder
+- the format of the file and additional comments are in the file itself
+
+
+
+3) HOW TO RUN:
+----------------
+- to run type (from bin/appLauncher directory):
+
+	python appLauncher [sage_config_file][-v]
+
+- the first (optional) parameter is an alternative config file that the appLauncher
+  will use instead of the default "applications.conf"
+- '-v' shows the output of the appLauncher on the console, if not specified
+  the output will be written to 'output.txt' and 'errors.txt'
+- you can also run the appLauncher constantly in the background since it's 
+  not necessary to restart it whenever sage is restarted:
+
+	python appLauncher &
+
+
+
+4) APP CONFIG GENERATION:
+--------------------------
+- one of the main goals of the applauncher is to generate the app config files,
+  copy them to the rendering machine and execute the application
+- for this to work you need to have "scp" enabled and you need to have ssh permissions
+  on the rendering machines (the best is to set up ssh keys so that you dont have to 
+  type in passwords every time you launch an application)
+- the appLauncher also makes use of the SAGE_DIRECTORY environment variable in order 
+  to copy the app config files into SAGE_DIRECTORY/bin 
+- the app config files are generated from the applications.conf AND from the requests made by 
+  SAGE UI when launching applications. For example, if SAGE UI requests that the app be
+  shareable, the appLauncher will write the sageBridge info into the app config file,
+  otherwise the app will connect directly to SAGE and it wont be shareable.
+
Index: trunk/src/testing/bin/appLauncher/admin.py
===================================================================
--- trunk/src/testing/bin/appLauncher/admin.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/admin.py	(revision 4)
@@ -0,0 +1,330 @@
+############################################################################
+#
+# AppLauncher - Application Launcher for SAGE
+# Copyright (C) 2006 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about AppLauncher to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+
+import wx, xmlrpclib, string, socket
+import traceback as tb
+
+
+
+
+class App:
+    """ describes the app that's currently running and that has been executed by an appLauncher"""
+    def __init__(self, name, appId, command, machine, launcher):
+        self.name = name
+        self.appId = appId
+        self.command = command
+        self.machine = machine
+        self.launcher = launcher  #the appLauncherId that started this app
+
+    def getName(self):
+        return self.name
+
+    def getId(self):
+        return self.appId
+
+    def getCommand(self):
+        return self.command
+
+    def getRenderMachine(self):
+        return self.machine
+
+    def getLauncher(self):
+        return self.launcher
+
+    def getStringForm(self):
+        info = "APPLICATION NAME: " + self.name
+        info = info + "\n------------------------------------------------"
+        info = info + "\nEXECUTION COMMAND: " + str(self.command)
+        info = info + "\nRENDERING MACHINE:\t"+str(self.machine) 
+        return info
+    
+
+class AppLauncher:
+
+    def __init__(self, launcherId, name, ip, port, appList):
+        self.port = port
+        self.appList = appList
+        self.ip = ip
+        self.launcherId = launcherId
+        self.name = name
+	self.connected = False
+
+
+    def connect(self):
+	if not self.connected:
+	    socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
+	    self.server = xmlrpclib.ServerProxy("http://" + self.ip + ":" + str(self.port))
+	    try:
+		self.server.test() #just use this as a way of testing whether the server is running or not
+		self.connected = True
+	    except socket.error:
+		return False
+	    except:
+		tb.print_exc()
+		return False
+	return True
+
+
+    def stopApp(self, appId):
+        try:
+            self.connect()  #connect if necessary
+            return self.server.stopApp(appId)
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error stopping application:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+            
+    def appStatus(self):
+        try:
+            self.connect()  #connect if necessary
+            return self.server.appStatus()
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error getting application list:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+        return {}
+
+
+    def killLauncher(self):
+        try:
+            self.connect()  #connect if necessary
+            self.server.killLauncher()
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error killing application launcher:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+
+
+
+    def getId(self):
+        return self.launcherId
+
+    def getIP(self):
+        return self.ip
+
+    def getAppList(self):
+        return self.appList
+
+    def setAppList(self, appList):
+        self.appList = appList
+
+    def getPort(self):
+        return self.port
+
+    def getName(self):
+        return self.name
+
+
+
+
+
+class MainFrame(wx.Frame):
+
+    def __init__(self, serverIP, serverPort=8009):
+        wx.Frame.__init__(self, None, -1, "AppLauncher Admin", pos = (100,100), size=(550,300))
+        self.server = xmlrpclib.ServerProxy("http://"+serverIP+":"+str(serverPort))
+        self.CreateControls()
+        self.updateLauncherList()
+        self.SetBackgroundColour(wx.Colour(51, 102, 102))
+        self.Show(True)
+
+        
+    ### connects to the sage server and retrieves the list of all app launchers running
+    def updateLauncherList(self):
+        self.launcherList.Clear()  #clear the ListBox
+	try:
+	    # a hash comes back (key=launcherId, value=appList - that's another hash of appNames and configs)
+	    launcherHash = self.server.GetRegisteredLaunchers()
+	except socket.error:
+            wx.MessageBox("No connection to the sage server.", "No connection")
+	except:
+	    tb.print_exc()
+	else:
+	    for launcherString, appList in launcherHash.iteritems():
+		(name, launcherId) = launcherString.split(":",1)
+		(ip, port) = launcherId.split(":",1)
+                self.launcherList.Insert(name, 0, AppLauncher(launcherId, name, ip, port, appList))
+		
+	
+    def CreateControls(self):
+        self.launcherLabel = wx.StaticText(self, -1, "Registered AppLaunchers", style=wx.ALIGN_CENTER)
+        self.appLabel = wx.StaticText(self, -1, "Apps Running On: ", style=wx.ALIGN_CENTER)
+        self.appInfoLabel = wx.StaticText(self, -1, "Details for: ", style=wx.ALIGN_CENTER)
+
+        self.launcherLabel.SetForegroundColour(wx.WHITE)
+        self.appLabel.SetForegroundColour(wx.WHITE)
+        self.appInfoLabel.SetForegroundColour(wx.WHITE)
+
+        self.launcherList = wx.ListBox(self, -1, style=wx.LB_SINGLE)
+        self.launcherList.SetMinSize((100,100))
+        self.appList = wx.ListBox(self, -1, style=wx.LB_SINGLE)
+        self.appList.SetMinSize((200,100))
+        self.appInfo = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY | wx.TE_MULTILINE | wx.TE_DONTWRAP)
+        self.appInfo.SetMinSize((300,100))
+        
+        self.killAppBtn = wx.Button(self, -1, "Kill App")
+        self.killLauncherBtn = wx.Button(self, -1, "Kill Launcher")
+        self.refreshBtn = wx.Button(self, -1, "Refresh")
+
+
+        # registering event handlers
+        self.launcherList.Bind(wx.EVT_LISTBOX, self.OnLauncherListSelect)
+        self.appList.Bind(wx.EVT_LISTBOX, self.OnAppListSelect)
+        self.killAppBtn.Bind(wx.EVT_BUTTON, self.OnKillAppBtn)
+        self.killLauncherBtn.Bind(wx.EVT_BUTTON, self.OnKillLauncherBtn)
+        self.refreshBtn.Bind(wx.EVT_BUTTON, self.UpdateLists)
+        
+        # placement of the controls
+        gridSizer = wx.FlexGridSizer(2,3,0,20)
+        gridSizer.Add(self.launcherLabel, 0, wx.ALIGN_CENTER | wx.TOP | wx.LEFT | wx.EXPAND, border=15)
+        gridSizer.Add(self.appLabel, 0, wx.ALIGN_CENTER | wx.TOP, border=15)
+        gridSizer.Add(self.appInfoLabel, 0, wx.ALIGN_CENTER | wx.TOP, border=15)
+
+        gridSizer.Add(self.launcherList, 1, wx.EXPAND | wx.ALL, border=10)
+        gridSizer.Add(self.appList, 1, wx.EXPAND | wx.ALL, border=10)
+        gridSizer.Add(self.appInfo, 1, wx.EXPAND | wx.ALL, border=10)
+
+        gridSizer.Add(self.killLauncherBtn, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=15)
+        gridSizer.Add(self.killAppBtn, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=15)
+        gridSizer.Add(self.refreshBtn, 0, wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border=15)
+
+
+        gridSizer.AddGrowableRow(1)
+        gridSizer.AddGrowableCol(2)
+        
+        self.SetSizer(gridSizer)
+        gridSizer.Fit(self)
+
+        
+    def OnLauncherListSelect(self, event=None):
+        selection = self.launcherList.GetStringSelection()
+        self.appList.Clear()
+        self.appLabel.SetLabel("Apps Running On: " + str(selection))
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: ")
+        appLauncher = event.GetClientData()
+        for appId, (appName, command, machine) in appLauncher.appStatus().iteritems():
+            self.appList.Insert(appName, 0, App(appName, int(appId), command, machine, appLauncher))
+        self.GetSizer().Layout()
+
+
+    def OnAppListSelect(self, event=None):
+        selection = self.appList.GetStringSelection()
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: " + str(selection))
+        self.appInfo.WriteText(event.GetClientData().getStringForm())
+        self.GetSizer().Layout()
+        
+
+    def UpdateLists(self, event=None):
+        self.updateLauncherList()
+        self.appList.Clear()
+        self.appLabel.SetLabel("Apps Running On: ")
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: ")
+        self.GetSizer().Layout()
+
+
+    def OnKillAppBtn(self, event):
+        selection = self.appList.GetSelection()
+        if not selection == wx.NOT_FOUND:
+            app = self.appList.GetClientData(selection)
+            app.getLauncher().stopApp(app.getId())
+            self.UpdateLists()
+
+
+    def OnKillLauncherBtn(self, event):
+        selection = self.launcherList.GetSelection()
+        if not selection == wx.NOT_FOUND:
+            msg = "Really stop this application launcher? You may be interfering with someone else's work."
+            dlg = wx.MessageDialog(None, msg, "Confirm kill", style = wx.OK | wx.CANCEL)
+            if dlg.ShowModal() == wx.ID_OK:
+                appLauncher = self.launcherList.GetClientData(selection)
+                appLauncher.killLauncher()
+                self.UpdateLists()
+
+
+
+
+
+class MyApp(wx.App):
+    def __init__(self):
+        wx.App.__init__(self, redirect=False)
+
+    def OnInit(self):
+        return True
+
+
+
+
+        
+
+def main(argv):
+    name, ext  = os.path.splitext(argv[1])
+
+    if len(argv) == 2:
+        serverIP = "sage.sl.startap.net"
+        serverPort = 8009
+    elif len(argv) == 3:
+        serverIP = argv[2]
+        serverPort = 8009
+    else:
+        print "Usage: python admin.py [SERVER_IP]\n"
+        sys.exit(0)
+
+    app = MyApp()
+    frame = MainFrame(serverIP, serverPort)
+    app.SetTopWindow(frame)
+    app.MainLoop()
+
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
Index: trunk/src/testing/bin/appLauncher/request.py
===================================================================
--- trunk/src/testing/bin/appLauncher/request.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/request.py	(revision 4)
@@ -0,0 +1,285 @@
+############################################################################
+#
+# AppLauncher - Application Launcher for SAGE
+# Copyright (C) 2006 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about AppLauncher to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+import subprocess as sp
+import traceback as tb
+import os, sys, time, os.path
+from myprint import *   # handles the printing or logging
+from threading import RLock, Thread
+
+opj = os.path.join
+
+#######################################################################
+#####    NOT THREAD SAFE  !!!!!
+#####    - needs fixing if multithreaded xmlrpc server is used
+#####    - otherwise the requests are queued and processed one by one
+#######################################################################
+
+class CurrentRequests:
+    def __init__(self, nodeHash):
+        self._requests = {}  #key = id, value = Request()
+        self._nodeHash = nodeHash  #key=IP, value=[0...n]   --> how many apps are running on that node
+
+        self.__submitThread = Thread(target=self.submitRequests)
+        self.__requestsToSubmit = []
+        self.__submitLock = RLock()
+        self.__doRunSubmitThread = True
+        self.__submitThread.start()
+        
+
+    def __getFirstAvailableId(self):
+        """ loops through the running requests until it finds an available id """
+
+        def inQueue(appId):
+            for r in self.__requestsToSubmit:
+                if r.config.getAppId() == appId:
+                    return True
+            return False
+        
+        
+        self.cleanup()  #first clean up all of the dead requests and their appIds
+
+        self.__submitLock.acquire()
+        for i in range(0, 9999):
+            if not self._requests.has_key(i) and not inQueue(i):
+                self.__submitLock.release()
+                return i
+        self.__submitLock.release()
+        
+
+    def __getNextAvailableNode(self):
+        ''' it loops through all the nodes of this cluster and returns the
+            one that is running the fewest apps
+        '''
+        currentMin = 99999
+        currentIP = None
+        for ip, numApps in self._nodeHash.iteritems():
+            #if currentIP == None:  currentIP=ip  #initial case
+            if numApps == 0:
+                self._nodeHash[ip] = numApps+1  #increase the number of apps running on this node
+                return ip
+            elif numApps <= currentMin:   #any machine with less than or equal to apps is a candidate
+                currentMin = numApps
+                currentIP = ip
+
+        self._nodeHash[currentIP] = currentMin+1  #increase the number of apps running on this node
+        return currentIP
+
+
+    def getRequest(self, appId):
+        """ get the request based on its appID (port number in fact) """
+        self.__submitLock.acquire()
+        if self._requests.has_key(appId):
+            r = self._requests[appId]
+            self.__submitLock.release()
+            return r
+        else:
+            self.__submitLock.release()
+            return False
+
+
+    def getStatus(self):
+        """ returns the current app status as a hash of appNames keyed by appId """
+        
+        self.cleanup()
+        status = {}
+        self.__submitLock.acquire()
+        for appId, request in self._requests.iteritems():
+            status[str(appId)] = (request.config.getAppName(), request.command, request.targetMachine)
+
+        self.__submitLock.release()
+        return status
+        
+
+    def addRequest(self, config):
+        """ modifies the appId parameter of the config and creates a new Request object """
+
+        # modify the appId parameter before writing the config to a file
+        appId = self.__getFirstAvailableId()
+        config.setAppId(appId)
+        
+        # if the app can be run on the nodes, get the machine with the lowest load (fewest apps running)
+        if config.getRunOnNodes():
+            nodeIP = self.__getNextAvailableNode()
+            config.setTargetMachine(nodeIP)
+            WriteLog( "\nNODE IP = "+ nodeIP + str(self._nodeHash[nodeIP])+ "\n\n")
+        else:
+            if self._nodeHash.has_key( config.getTargetMachine() ):
+                self._nodeHash[config.getTargetMachine()] += 1
+            
+        # make the request
+        request = SSHRequest(config)
+
+        # submit it... in a separate thread
+        self.__submitLock.acquire()
+        self.__requestsToSubmit.append(request)
+        self.__submitLock.release()
+        
+        return appId
+
+
+    def submitRequests(self):
+        while self.__doRunSubmitThread:
+            
+            if len(self.__requestsToSubmit) > 0:
+                self.__submitLock.acquire()
+                request = self.__requestsToSubmit.pop(0)
+                self.__submitLock.release()
+
+                res = request.submit()
+
+                if res != -1:
+                    self.__submitLock.acquire()
+                    self._requests[ request.config.getAppId() ] = request
+                    self.__submitLock.release()
+
+            time.sleep(1.5)
+
+
+    def stopSubmitThread(self):
+        self.__doRunSubmitThread = False
+        
+
+    def stopRequest(self, appId):
+        """ stops the request forcefully """
+
+        self.__submitLock.acquire()
+        
+        if self._requests.has_key(appId):
+            ret = self._requests[appId].kill()
+            self.__submitLock.release()
+            time.sleep(1)
+            self.cleanup()
+            
+            return ret
+        else:
+            self.__submitLock.release()
+            return False
+
+
+    def cleanup(self):
+        """ this runs every so often and checks whether the requests that we started are still alive
+            if they are not alive, they are removed from the list of requests and their port (appId) is recycled
+        """
+        self.__submitLock.acquire()
+        
+        for appId, request in self._requests.items():
+            if not request.isAlive():
+                WriteLog( ">>>> Cleaning up: " + request.config.getCommand() + "  appId = " + str(appId) )
+                request.deletePIDFile()
+                #if request.config.getRunOnNodes():
+                if self._nodeHash.has_key( request.config.getTargetMachine() ):
+                    self._nodeHash[ request.config.getTargetMachine() ] -= 1  #decrease the num of apps running on this node
+                del self._requests[appId]
+
+        self.__submitLock.release()
+
+
+
+class Request:
+    def __init__(self, config):
+        self.targetMachine = config.getTargetMachine()
+        self.command = config.getCommand()
+        self.configFilename = config.getConfigFilename()
+        self.processObj = None    # the object corresponding to the process we started
+        self.config = config
+
+        
+
+class SSHRequest(Request):
+
+    def submit(self):
+        # copy the configuration file over
+        try:
+            self.config.writeToFile()
+            sp.call(["chmod", "g+w", self.config.getConfigFilename()])  #change the permissions of the temp file
+            
+            retcode = sp.call(["/usr/bin/scp", self.configFilename, self.targetMachine+":"+os.path.basename(self.configFilename)])
+            sp.call(["/usr/bin/ssh", "-x", self.targetMachine, "chmod a+rw "+self.configFilename])
+        except:
+            WriteLog( "===>  ERROR copying config file... application will use the default configuration:")
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+
+        # launch the application via ssh
+        try:
+            WriteLog( "\n\nRunning with command: /usr/bin/ssh -x " + self.targetMachine + " cd "+self.config.getBinDir()+" ;env DISPLAY=:0.0 "+ self.command)
+            self.processObj = sp.Popen(["/usr/bin/ssh", "-x", self.targetMachine, "cd "+self.config.getBinDir(), ";env DISPLAY=:0.0 ", self.command])
+            WriteLog( ">>>>  EXECUTING:  " + self.command + "\nPID = " + str(self.processObj.pid) + "\n")
+        except:
+            WriteLog( "===>  ERROR launching application ---------> :")
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+            return -1
+        
+        return self.config.getAppId()
+
+        
+    def isAlive(self):
+        """ returns true if the process is still alive """
+        return self.processObj.poll() is None
+        
+
+    def kill(self):
+        # forcefully kill the application via ssh and delete its pid file if possible
+        pidPath = opj(os.path.basename(self.configFilename), "pid")
+        killCmd = "/bin/kill -9 `cat "+opj(pidPath, self.config.getAppName()+"_"+str(self.config.getAppId())+".pid")+"`"
+        delCmd = "/bin/rm -rf "+opj(pidPath, self.config.getAppName()+"_"+str(self.config.getAppId())+".pid")
+        try:
+            retcode = sp.Popen(["/usr/bin/ssh", "-x", self.targetMachine, killCmd, ";", delCmd])
+            WriteLog( ">>>>  KILLING:  " + killCmd + "\nPID = " + str(self.processObj.pid) + "\n")
+        except:
+            WriteLog( "===>  ERROR killing application ---------> :")
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+            return -1
+        
+        return True
+
+
+    def deletePIDFile(self):
+        # delete the temp file where the app writes its pid
+        pidPath = opj(os.path.basename(self.configFilename), "pid")
+        delCmd = "/bin/rm -rf "+opj(pidPath, self.config.getAppName()+"_"+str(self.config.getAppId())+".pid")
+        try:
+            retcode = sp.Popen(["/usr/bin/ssh", "-x", self.targetMachine, delCmd], env={"DISPLAY": ":0.0"})
+            WriteLog(">>>>  DELETING:  " + delCmd + "\nPID = " + str(self.processObj.pid) + "\n")
+        except:
+            WriteLog("===>  ERROR deleting temporary pid file ---------> :")
+            WriteLog( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+        #    return False
+        
+        return True
Index: trunk/src/testing/bin/appLauncher/subprocess.py
===================================================================
--- trunk/src/testing/bin/appLauncher/subprocess.py	(revision 4)
+++ trunk/src/testing/bin/appLauncher/subprocess.py	(revision 4)
@@ -0,0 +1,1158 @@
+# subprocess - Subprocesses with accessible I/O streams
+#
+# For more information about this module, see PEP 324.
+#
+# Copyright (c) 2003-2004 by Peter Astrand <astrand@lysator.liu.se>
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of the
+# author not be used in advertising or publicity pertaining to
+# distribution of the software without specific, written prior
+# permission.
+#
+# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""subprocess - Subprocesses with accessible I/O streams
+
+This module allows you to spawn processes and connect to their
+input/output/error pipes and obtain their return codes under Unix.
+This module intends to replace several other, older modules and
+functions, like:
+
+os.system
+os.spawn*
+os.popen*
+popen2.*
+commands.*
+
+Information about how the subprocess module can be used to replace these
+modules and functions can be found below.
+
+
+
+Using the subprocess module
+===========================
+This module defines one class called Popen:
+
+class Popen(args, bufsize=0, executable=None,
+            stdin=None, stdout=None, stderr=None,
+            preexec_fn=None, close_fds=False, shell=False,
+            cwd=None, env=None, universal_newlines=False,
+            startupinfo=None, creationflags=0):
+
+
+Arguments are:
+
+args should be a string, or a sequence of program arguments.  The
+program to execute is normally the first item in the args sequence or
+string, but can be explicitly set by using the executable argument.
+
+On UNIX, with shell=False (default): In this case, the Popen class
+uses os.execvp() to execute the child program.  args should normally
+be a sequence.  A string will be treated as a sequence with the string
+as the only item (the program to execute).
+
+On UNIX, with shell=True: If args is a string, it specifies the
+command string to execute through the shell.  If args is a sequence,
+the first item specifies the command string, and any additional items
+will be treated as additional shell arguments.
+
+On Windows: the Popen class uses CreateProcess() to execute the child
+program, which operates on strings.  If args is a sequence, it will be
+converted to a string using the list2cmdline method.  Please note that
+not all MS Windows applications interpret the command line the same
+way: The list2cmdline is designed for applications using the same
+rules as the MS C runtime.
+
+bufsize, if given, has the same meaning as the corresponding argument
+to the built-in open() function: 0 means unbuffered, 1 means line
+buffered, any other positive value means use a buffer of
+(approximately) that size.  A negative bufsize means to use the system
+default, which usually means fully buffered.  The default value for
+bufsize is 0 (unbuffered).
+
+stdin, stdout and stderr specify the executed programs' standard
+input, standard output and standard error file handles, respectively.
+Valid values are PIPE, an existing file descriptor (a positive
+integer), an existing file object, and None.  PIPE indicates that a
+new pipe to the child should be created.  With None, no redirection
+will occur; the child's file handles will be inherited from the
+parent.  Additionally, stderr can be STDOUT, which indicates that the
+stderr data from the applications should be captured into the same
+file handle as for stdout.
+
+If preexec_fn is set to a callable object, this object will be called
+in the child process just before the child is executed.
+
+If close_fds is true, all file descriptors except 0, 1 and 2 will be
+closed before the child process is executed.
+
+if shell is true, the specified command will be executed through the
+shell.
+
+If cwd is not None, the current directory will be changed to cwd
+before the child is executed.
+
+If env is not None, it defines the environment variables for the new
+process.
+
+If universal_newlines is true, the file objects stdout and stderr are
+opened as a text files, but lines may be terminated by any of '\n',
+the Unix end-of-line convention, '\r', the Macintosh convention or
+'\r\n', the Windows convention.  All of these external representations
+are seen as '\n' by the Python program.  Note: This feature is only
+available if Python is built with universal newline support (the
+default).  Also, the newlines attribute of the file objects stdout,
+stdin and stderr are not updated by the communicate() method.
+
+The startupinfo and creationflags, if given, will be passed to the
+underlying CreateProcess() function.  They can specify things such as
+appearance of the main window and priority for the new process.
+(Windows only)
+
+
+This module also defines two shortcut functions:
+
+call(*args, **kwargs):
+    Run command with arguments.  Wait for command to complete, then
+    return the returncode attribute.
+
+    The arguments are the same as for the Popen constructor.  Example:
+
+    retcode = call(["ls", "-l"])
+
+
+Exceptions
+----------
+Exceptions raised in the child process, before the new program has
+started to execute, will be re-raised in the parent.  Additionally,
+the exception object will have one extra attribute called
+'child_traceback', which is a string containing traceback information
+from the childs point of view.
+
+The most common exception raised is OSError.  This occurs, for
+example, when trying to execute a non-existent file.  Applications
+should prepare for OSErrors.
+
+A ValueError will be raised if Popen is called with invalid arguments.
+
+
+Security
+--------
+Unlike some other popen functions, this implementation will never call
+/bin/sh implicitly.  This means that all characters, including shell
+metacharacters, can safely be passed to child processes.
+
+
+Popen objects
+=============
+Instances of the Popen class have the following methods:
+
+poll()
+    Check if child process has terminated.  Returns returncode
+    attribute.
+
+wait()
+    Wait for child process to terminate.  Returns returncode attribute.
+
+communicate(input=None)
+    Interact with process: Send data to stdin.  Read data from stdout
+    and stderr, until end-of-file is reached.  Wait for process to
+    terminate.  The optional stdin argument should be a string to be
+    sent to the child process, or None, if no data should be sent to
+    the child.
+
+    communicate() returns a tuple (stdout, stderr).
+
+    Note: The data read is buffered in memory, so do not use this
+    method if the data size is large or unlimited.
+
+The following attributes are also available:
+
+stdin
+    If the stdin argument is PIPE, this attribute is a file object
+    that provides input to the child process.  Otherwise, it is None.
+
+stdout
+    If the stdout argument is PIPE, this attribute is a file object
+    that provides output from the child process.  Otherwise, it is
+    None.
+
+stderr
+    If the stderr argument is PIPE, this attribute is file object that
+    provides error output from the child process.  Otherwise, it is
+    None.
+
+pid
+    The process ID of the child process.
+
+returncode
+    The child return code.  A None value indicates that the process
+    hasn't terminated yet.  A negative value -N indicates that the
+    child was terminated by signal N (UNIX only).
+
+
+Replacing older functions with the subprocess module
+====================================================
+In this section, "a ==> b" means that b can be used as a replacement
+for a.
+
+Note: All functions in this section fail (more or less) silently if
+the executed program cannot be found; this module raises an OSError
+exception.
+
+In the following examples, we assume that the subprocess module is
+imported with "from subprocess import *".
+
+
+Replacing /bin/sh shell backquote
+---------------------------------
+output=`mycmd myarg`
+==>
+output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
+
+
+Replacing shell pipe line
+-------------------------
+output=`dmesg | grep hda`
+==>
+p1 = Popen(["dmesg"], stdout=PIPE)
+p2 = Popen(["grep", "hda"], stdin=p1.stdout)
+output = p2.communicate()[0]
+
+
+Replacing os.system()
+---------------------
+sts = os.system("mycmd" + " myarg")
+==>
+p = Popen("mycmd" + " myarg", shell=True)
+sts = os.waitpid(p.pid, 0)
+
+Note:
+
+* Calling the program through the shell is usually not required.
+
+* It's easier to look at the returncode attribute than the
+  exitstatus.
+
+A more real-world example would look like this:
+
+try:
+    retcode = call("mycmd" + " myarg", shell=True)
+    if retcode < 0:
+        print >>sys.stderr, "Child was terminated by signal", -retcode
+    else:
+        print >>sys.stderr, "Child returned", retcode
+except OSError, e:
+    print >>sys.stderr, "Execution failed:", e
+
+
+Replacing os.spawn*
+-------------------
+P_NOWAIT example:
+
+pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+pid = Popen(["/bin/mycmd", "myarg"]).pid
+
+
+P_WAIT example:
+
+retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
+==>
+retcode = call(["/bin/mycmd", "myarg"])
+
+
+Vector example:
+
+os.spawnvp(os.P_NOWAIT, path, args)
+==>
+Popen([path] + args[1:])
+
+
+Environment example:
+
+os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
+==>
+Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
+
+
+Replacing os.popen*
+-------------------
+pipe = os.popen(cmd, mode='r', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
+
+pipe = os.popen(cmd, mode='w', bufsize)
+==>
+pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
+
+
+(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdin, child_stdout) = (p.stdin, p.stdout)
+
+
+(child_stdin,
+ child_stdout,
+ child_stderr) = os.popen3(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
+(child_stdin,
+ child_stdout,
+ child_stderr) = (p.stdin, p.stdout, p.stderr)
+
+
+(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
+==>
+p = Popen(cmd, shell=True, bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
+(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
+
+
+Replacing popen2.*
+------------------
+Note: If the cmd argument to popen2 functions is a string, the command
+is executed through /bin/sh.  If it is a list, the command is directly
+executed.
+
+(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
+==>
+p = Popen(["somestring"], shell=True, bufsize=bufsize
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+
+(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
+==>
+p = Popen(["mycmd", "myarg"], bufsize=bufsize,
+          stdin=PIPE, stdout=PIPE, close_fds=True)
+(child_stdout, child_stdin) = (p.stdout, p.stdin)
+
+The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
+except that:
+
+* subprocess.Popen raises an exception if the execution fails
+* the capturestderr argument is replaced with the stderr argument.
+* stdin=PIPE and stdout=PIPE must be specified.
+* popen2 closes all filedescriptors by default, but you have to specify
+  close_fds=True with subprocess.Popen.
+
+
+"""
+
+import sys
+mswindows = (sys.platform == "win32")
+
+import os
+import types
+import traceback
+
+if mswindows:
+    import threading
+    import msvcrt
+    if 0: # <-- change this to use pywin32 instead of the _subprocess driver
+        import pywintypes
+        from win32api import GetStdHandle, STD_INPUT_HANDLE, \
+                             STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
+        from win32api import GetCurrentProcess, DuplicateHandle, \
+                             GetModuleFileName, GetVersion
+        from win32con import DUPLICATE_SAME_ACCESS
+        from win32pipe import CreatePipe
+        from win32process import CreateProcess, STARTUPINFO, \
+                                 GetExitCodeProcess, STARTF_USESTDHANDLES, \
+                                 CREATE_NEW_CONSOLE
+        from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
+    else:
+        from _subprocess import *
+        class STARTUPINFO:
+            dwFlags = 0
+            hStdInput = None
+            hStdOutput = None
+            hStdError = None
+        class pywintypes:
+            error = IOError
+else:
+    import select
+    import errno
+    import fcntl
+    import pickle
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call"]
+
+try:
+    MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+    MAXFD = 256
+
+# True/False does not exist on 2.2.0
+try:
+    False
+except NameError:
+    False = 0
+    True = 1
+
+_active = []
+
+def _cleanup():
+    for inst in _active[:]:
+        inst.poll()
+
+PIPE = -1
+STDOUT = -2
+
+
+def call(*args, **kwargs):
+    """Run command with arguments.  Wait for command to complete, then
+    return the returncode attribute.
+
+    The arguments are the same as for the Popen constructor.  Example:
+
+    retcode = call(["ls", "-l"])
+    """
+    return Popen(*args, **kwargs).wait()
+
+
+def list2cmdline(seq):
+    """
+    Translate a sequence of arguments into a command line
+    string, using the same rules as the MS C runtime:
+
+    1) Arguments are delimited by white space, which is either a
+       space or a tab.
+
+    2) A string surrounded by double quotation marks is
+       interpreted as a single argument, regardless of white space
+       contained within.  A quoted string can be embedded in an
+       argument.
+
+    3) A double quotation mark preceded by a backslash is
+       interpreted as a literal double quotation mark.
+
+    4) Backslashes are interpreted literally, unless they
+       immediately precede a double quotation mark.
+
+    5) If backslashes immediately precede a double quotation mark,
+       every pair of backslashes is interpreted as a literal
+       backslash.  If the number of backslashes is odd, the last
+       backslash escapes the next double quotation mark as
+       described in rule 3.
+    """
+
+    # See
+    # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
+    result = []
+    needquote = False
+    for arg in seq:
+        bs_buf = []
+
+        # Add a space to separate this argument from the others
+        if result:
+            result.append(' ')
+
+        needquote = (" " in arg) or ("\t" in arg)
+        if needquote:
+            result.append('"')
+
+        for c in arg:
+            if c == '\\':
+                # Don't know if we need to double yet.
+                bs_buf.append(c)
+            elif c == '"':
+                # Double backspaces.
+                result.append('\\' * len(bs_buf)*2)
+                bs_buf = []
+                result.append('\\"')
+            else:
+                # Normal char
+                if bs_buf:
+                    result.extend(bs_buf)
+                    bs_buf = []
+                result.append(c)
+
+        # Add remaining backspaces, if any.
+        if bs_buf:
+            result.extend(bs_buf)
+
+        if needquote:
+            result.append('"')
+
+    return ''.join(result)
+
+
+class Popen(object):
+    def __init__(self, args, bufsize=0, executable=None,
+                 stdin=None, stdout=None, stderr=None,
+                 preexec_fn=None, close_fds=False, shell=False,
+                 cwd=None, env=None, universal_newlines=False,
+                 startupinfo=None, creationflags=0):
+        """Create new Popen instance."""
+        _cleanup()
+
+        if mswindows:
+            if preexec_fn is not None:
+                raise ValueError("preexec_fn is not supported on Windows "
+                                 "platforms")
+            if close_fds:
+                raise ValueError("close_fds is not supported on Windows "
+                                 "platforms")
+        else:
+            # POSIX
+            if startupinfo is not None:
+                raise ValueError("startupinfo is only supported on Windows "
+                                 "platforms")
+            if creationflags != 0:
+                raise ValueError("creationflags is only supported on Windows "
+                                 "platforms")
+
+        self.stdin = None
+        self.stdout = None
+        self.stderr = None
+        self.pid = None
+        self.returncode = None
+        self.universal_newlines = universal_newlines
+
+        # Input and output objects. The general principle is like
+        # this:
+        #
+        # Parent                   Child
+        # ------                   -----
+        # p2cwrite   ---stdin--->  p2cread
+        # c2pread    <--stdout---  c2pwrite
+        # errread    <--stderr---  errwrite
+        #
+        # On POSIX, the child objects are file descriptors.  On
+        # Windows, these are Windows file handles.  The parent objects
+        # are file descriptors on both platforms.  The parent objects
+        # are None when not using PIPEs. The child objects are None
+        # when not redirecting.
+
+        (p2cread, p2cwrite,
+         c2pread, c2pwrite,
+         errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+        self._execute_child(args, executable, preexec_fn, close_fds,
+                            cwd, env, universal_newlines,
+                            startupinfo, creationflags, shell,
+                            p2cread, p2cwrite,
+                            c2pread, c2pwrite,
+                            errread, errwrite)
+
+        if p2cwrite:
+            self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
+        if c2pread:
+            if universal_newlines:
+                self.stdout = os.fdopen(c2pread, 'rU', bufsize)
+            else:
+                self.stdout = os.fdopen(c2pread, 'rb', bufsize)
+        if errread:
+            if universal_newlines:
+                self.stderr = os.fdopen(errread, 'rU', bufsize)
+            else:
+                self.stderr = os.fdopen(errread, 'rb', bufsize)
+
+        _active.append(self)
+
+
+    def _translate_newlines(self, data):
+        data = data.replace("\r\n", "\n")
+        data = data.replace("\r", "\n")
+        return data
+
+
+    if mswindows:
+        #
+        # Windows methods
+        #
+        def _get_handles(self, stdin, stdout, stderr):
+            """Construct and return tupel with IO objects:
+            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+            """
+            if stdin == None and stdout == None and stderr == None:
+                return (None, None, None, None, None, None)
+
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin == None:
+                p2cread = GetStdHandle(STD_INPUT_HANDLE)
+            elif stdin == PIPE:
+                p2cread, p2cwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                p2cwrite = p2cwrite.Detach()
+                p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
+            elif type(stdin) == types.IntType:
+                p2cread = msvcrt.get_osfhandle(stdin)
+            else:
+                # Assuming file-like object
+                p2cread = msvcrt.get_osfhandle(stdin.fileno())
+            p2cread = self._make_inheritable(p2cread)
+
+            if stdout == None:
+                c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
+            elif stdout == PIPE:
+                c2pread, c2pwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                c2pread = c2pread.Detach()
+                c2pread = msvcrt.open_osfhandle(c2pread, 0)
+            elif type(stdout) == types.IntType:
+                c2pwrite = msvcrt.get_osfhandle(stdout)
+            else:
+                # Assuming file-like object
+                c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+            c2pwrite = self._make_inheritable(c2pwrite)
+
+            if stderr == None:
+                errwrite = GetStdHandle(STD_ERROR_HANDLE)
+            elif stderr == PIPE:
+                errread, errwrite = CreatePipe(None, 0)
+                # Detach and turn into fd
+                errread = errread.Detach()
+                errread = msvcrt.open_osfhandle(errread, 0)
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif type(stderr) == types.IntType:
+                errwrite = msvcrt.get_osfhandle(stderr)
+            else:
+                # Assuming file-like object
+                errwrite = msvcrt.get_osfhandle(stderr.fileno())
+            errwrite = self._make_inheritable(errwrite)
+
+            return (p2cread, p2cwrite,
+                    c2pread, c2pwrite,
+                    errread, errwrite)
+
+
+        def _make_inheritable(self, handle):
+            """Return a duplicate of handle, which is inheritable"""
+            return DuplicateHandle(GetCurrentProcess(), handle,
+                                   GetCurrentProcess(), 0, 1,
+                                   DUPLICATE_SAME_ACCESS)
+
+
+        def _find_w9xpopen(self):
+            """Find and return absolut path to w9xpopen.exe"""
+            w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
+                                    "w9xpopen.exe")
+            if not os.path.exists(w9xpopen):
+                # Eeek - file-not-found - possibly an embedding
+                # situation - see if we can locate it in sys.exec_prefix
+                w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
+                                        "w9xpopen.exe")
+                if not os.path.exists(w9xpopen):
+                    raise RuntimeError("Cannot locate w9xpopen.exe, which is "
+                                       "needed for Popen to work with your "
+                                       "shell or platform.")
+            return w9xpopen
+
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines,
+                           startupinfo, creationflags, shell,
+                           p2cread, p2cwrite,
+                           c2pread, c2pwrite,
+                           errread, errwrite):
+            """Execute program (MS Windows version)"""
+
+            if not isinstance(args, types.StringTypes):
+                args = list2cmdline(args)
+
+            if shell:
+                comspec = os.environ.get("COMSPEC", "cmd.exe")
+                args = comspec + " /c " + args
+                if (GetVersion() >= 0x80000000L or
+                        os.path.basename(comspec).lower() == "command.com"):
+                    # Win9x, or using command.com on NT. We need to
+                    # use the w9xpopen intermediate program. For more
+                    # information, see KB Q150956
+                    # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
+                    w9xpopen = self._find_w9xpopen()
+                    args = '"%s" %s' % (w9xpopen, args)
+                    # Not passing CREATE_NEW_CONSOLE has been known to
+                    # cause random failures on win9x.  Specifically a
+                    # dialog: "Your program accessed mem currently in
+                    # use at xxx" and a hopeful warning about the
+                    # stability of your system.  Cost is Ctrl+C wont
+                    # kill children.
+                    creationflags |= CREATE_NEW_CONSOLE
+
+            # Process startup details
+            if startupinfo == None:
+                startupinfo = STARTUPINFO()
+            if not None in (p2cread, c2pwrite, errwrite):
+                startupinfo.dwFlags |= STARTF_USESTDHANDLES
+                startupinfo.hStdInput = p2cread
+                startupinfo.hStdOutput = c2pwrite
+                startupinfo.hStdError = errwrite
+
+            # Start the process
+            try:
+                hp, ht, pid, tid = CreateProcess(executable, args,
+                                         # no special security
+                                         None, None,
+                                         # must inherit handles to pass std
+                                         # handles
+                                         1,
+                                         creationflags,
+                                         env,
+                                         cwd,
+                                         startupinfo)
+            except pywintypes.error, e:
+                # Translate pywintypes.error to WindowsError, which is
+                # a subclass of OSError.  FIXME: We should really
+                # translate errno using _sys_errlist (or simliar), but
+                # how can this be done from Python?
+                raise WindowsError(*e.args)
+
+            # Retain the process handle, but close the thread handle
+            self._handle = hp
+            self.pid = pid
+            ht.Close()
+
+            # Child is launched. Close the parent's copy of those pipe
+            # handles that only the child should have open.  You need
+            # to make sure that no handles to the write end of the
+            # output pipe are maintained in this process or else the
+            # pipe will not close when the child process exits and the
+            # ReadFile will hang.
+            if p2cread != None:
+                p2cread.Close()
+            if c2pwrite != None:
+                c2pwrite.Close()
+            if errwrite != None:
+                errwrite.Close()
+
+
+        def poll(self):
+            """Check if child process has terminated.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
+                    self.returncode = GetExitCodeProcess(self._handle)
+                    _active.remove(self)
+            return self.returncode
+
+
+        def wait(self):
+            """Wait for child process to terminate.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                obj = WaitForSingleObject(self._handle, INFINITE)
+                self.returncode = GetExitCodeProcess(self._handle)
+                _active.remove(self)
+            return self.returncode
+
+
+        def _readerthread(self, fh, buffer):
+            buffer.append(fh.read())
+
+
+        def communicate(self, input=None):
+            """Interact with process: Send data to stdin.  Read data from
+            stdout and stderr, until end-of-file is reached.  Wait for
+            process to terminate.  The optional input argument should be a
+            string to be sent to the child process, or None, if no data
+            should be sent to the child.
+
+            communicate() returns a tuple (stdout, stderr)."""
+            stdout = None # Return
+            stderr = None # Return
+
+            if self.stdout:
+                stdout = []
+                stdout_thread = threading.Thread(target=self._readerthread,
+                                                 args=(self.stdout, stdout))
+                stdout_thread.setDaemon(True)
+                stdout_thread.start()
+            if self.stderr:
+                stderr = []
+                stderr_thread = threading.Thread(target=self._readerthread,
+                                                 args=(self.stderr, stderr))
+                stderr_thread.setDaemon(True)
+                stderr_thread.start()
+
+            if self.stdin:
+                if input != None:
+                    self.stdin.write(input)
+                self.stdin.close()
+
+            if self.stdout:
+                stdout_thread.join()
+            if self.stderr:
+                stderr_thread.join()
+
+            # All data exchanged.  Translate lists into strings.
+            if stdout != None:
+                stdout = stdout[0]
+            if stderr != None:
+                stderr = stderr[0]
+
+            # Translate newlines, if requested.  We cannot let the file
+            # object do the translation: It is based on stdio, which is
+            # impossible to combine with select (unless forcing no
+            # buffering).
+            if self.universal_newlines and hasattr(open, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
+    else:
+        #
+        # POSIX methods
+        #
+        def _get_handles(self, stdin, stdout, stderr):
+            """Construct and return tupel with IO objects:
+            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+            """
+            p2cread, p2cwrite = None, None
+            c2pread, c2pwrite = None, None
+            errread, errwrite = None, None
+
+            if stdin == None:
+                pass
+            elif stdin == PIPE:
+                p2cread, p2cwrite = os.pipe()
+            elif type(stdin) == types.IntType:
+                p2cread = stdin
+            else:
+                # Assuming file-like object
+                p2cread = stdin.fileno()
+
+            if stdout == None:
+                pass
+            elif stdout == PIPE:
+                c2pread, c2pwrite = os.pipe()
+            elif type(stdout) == types.IntType:
+                c2pwrite = stdout
+            else:
+                # Assuming file-like object
+                c2pwrite = stdout.fileno()
+
+            if stderr == None:
+                pass
+            elif stderr == PIPE:
+                errread, errwrite = os.pipe()
+            elif stderr == STDOUT:
+                errwrite = c2pwrite
+            elif type(stderr) == types.IntType:
+                errwrite = stderr
+            else:
+                # Assuming file-like object
+                errwrite = stderr.fileno()
+
+            return (p2cread, p2cwrite,
+                    c2pread, c2pwrite,
+                    errread, errwrite)
+
+
+        def _set_cloexec_flag(self, fd):
+            try:
+                cloexec_flag = fcntl.FD_CLOEXEC
+            except AttributeError:
+                cloexec_flag = 1
+
+            old = fcntl.fcntl(fd, fcntl.F_GETFD)
+            fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
+
+
+        def _close_fds(self, but):
+            for i in range(3, MAXFD):
+                if i == but:
+                    continue
+                try:
+                    os.close(i)
+                except:
+                    pass
+
+
+        def _execute_child(self, args, executable, preexec_fn, close_fds,
+                           cwd, env, universal_newlines,
+                           startupinfo, creationflags, shell,
+                           p2cread, p2cwrite,
+                           c2pread, c2pwrite,
+                           errread, errwrite):
+            """Execute program (POSIX version)"""
+
+            if isinstance(args, types.StringTypes):
+                args = [args]
+
+            if shell:
+                args = ["/bin/sh", "-c"] + args
+
+            if executable == None:
+                executable = args[0]
+
+            # For transferring possible exec failure from child to parent
+            # The first char specifies the exception type: 0 means
+            # OSError, 1 means some other error.
+            errpipe_read, errpipe_write = os.pipe()
+            self._set_cloexec_flag(errpipe_write)
+
+            self.pid = os.fork()
+            if self.pid == 0:
+                # Child
+                try:
+                    # Close parent's pipe ends
+                    if p2cwrite:
+                        os.close(p2cwrite)
+                    if c2pread:
+                        os.close(c2pread)
+                    if errread:
+                        os.close(errread)
+                    os.close(errpipe_read)
+
+                    # Dup fds for child
+                    if p2cread:
+                        os.dup2(p2cread, 0)
+                    if c2pwrite:
+                        os.dup2(c2pwrite, 1)
+                    if errwrite:
+                        os.dup2(errwrite, 2)
+
+                    # Close pipe fds.  Make sure we doesn't close the same
+                    # fd more than once.
+                    if p2cread:
+                        os.close(p2cread)
+                    if c2pwrite and c2pwrite not in (p2cread,):
+                        os.close(c2pwrite)
+                    if errwrite and errwrite not in (p2cread, c2pwrite):
+                        os.close(errwrite)
+
+                    # Close all other fds, if asked for
+                    if close_fds:
+                        self._close_fds(but=errpipe_write)
+
+                    if cwd != None:
+                        os.chdir(cwd)
+
+                    if preexec_fn:
+                        apply(preexec_fn)
+
+                    if env == None:
+                        os.execvp(executable, args)
+                    else:
+                        os.execvpe(executable, args, env)
+
+                except:
+                    exc_type, exc_value, tb = sys.exc_info()
+                    # Save the traceback and attach it to the exception object
+                    exc_lines = traceback.format_exception(exc_type,
+                                                           exc_value,
+                                                           tb)
+                    exc_value.child_traceback = ''.join(exc_lines)
+                    os.write(errpipe_write, pickle.dumps(exc_value))
+
+                # This exitcode won't be reported to applications, so it
+                # really doesn't matter what we return.
+                os._exit(255)
+
+            # Parent
+            os.close(errpipe_write)
+            if p2cread and p2cwrite:
+                os.close(p2cread)
+            if c2pwrite and c2pread:
+                os.close(c2pwrite)
+            if errwrite and errread:
+                os.close(errwrite)
+
+            # Wait for exec to fail or succeed; possibly raising exception
+            data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
+            os.close(errpipe_read)
+            if data != "":
+                child_exception = pickle.loads(data)
+                raise child_exception
+
+
+        def _handle_exitstatus(self, sts):
+            if os.WIFSIGNALED(sts):
+                self.returncode = -os.WTERMSIG(sts)
+            elif os.WIFEXITED(sts):
+                self.returncode = os.WEXITSTATUS(sts)
+            else:
+                # Should never happen
+                raise RuntimeError("Unknown child exit status!")
+
+            _active.remove(self)
+
+
+        def poll(self):
+            """Check if child process has terminated.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                try:
+                    pid, sts = os.waitpid(self.pid, os.WNOHANG)
+                    if pid == self.pid:
+                        self._handle_exitstatus(sts)
+                except os.error:
+                    pass
+            return self.returncode
+
+
+        def wait(self):
+            """Wait for child process to terminate.  Returns returncode
+            attribute."""
+            if self.returncode == None:
+                pid, sts = os.waitpid(self.pid, 0)
+                self._handle_exitstatus(sts)
+            return self.returncode
+
+
+        def communicate(self, input=None):
+            """Interact with process: Send data to stdin.  Read data from
+            stdout and stderr, until end-of-file is reached.  Wait for
+            process to terminate.  The optional input argument should be a
+            string to be sent to the child process, or None, if no data
+            should be sent to the child.
+
+            communicate() returns a tuple (stdout, stderr)."""
+            read_set = []
+            write_set = []
+            stdout = None # Return
+            stderr = None # Return
+
+            if self.stdin:
+                # Flush stdio buffer.  This might block, if the user has
+                # been writing to .stdin in an uncontrolled fashion.
+                self.stdin.flush()
+                if input:
+                    write_set.append(self.stdin)
+                else:
+                    self.stdin.close()
+            if self.stdout:
+                read_set.append(self.stdout)
+                stdout = []
+            if self.stderr:
+                read_set.append(self.stderr)
+                stderr = []
+
+            while read_set or write_set:
+                rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+                if self.stdin in wlist:
+                    # When select has indicated that the file is writable,
+                    # we can write up to PIPE_BUF bytes without risk
+                    # blocking.  POSIX defines PIPE_BUF >= 512
+                    bytes_written = os.write(self.stdin.fileno(), input[:512])
+                    input = input[bytes_written:]
+                    if not input:
+                        self.stdin.close()
+                        write_set.remove(self.stdin)
+
+                if self.stdout in rlist:
+                    data = os.read(self.stdout.fileno(), 1024)
+                    if data == "":
+                        self.stdout.close()
+                        read_set.remove(self.stdout)
+                    stdout.append(data)
+
+                if self.stderr in rlist:
+                    data = os.read(self.stderr.fileno(), 1024)
+                    if data == "":
+                        self.stderr.close()
+                        read_set.remove(self.stderr)
+                    stderr.append(data)
+
+            # All data exchanged.  Translate lists into strings.
+            if stdout != None:
+                stdout = ''.join(stdout)
+            if stderr != None:
+                stderr = ''.join(stderr)
+
+            # Translate newlines, if requested.  We cannot let the file
+            # object do the translation: It is based on stdio, which is
+            # impossible to combine with select (unless forcing no
+            # buffering).
+            if self.universal_newlines and hasattr(open, 'newlines'):
+                if stdout:
+                    stdout = self._translate_newlines(stdout)
+                if stderr:
+                    stderr = self._translate_newlines(stderr)
+
+            self.wait()
+            return (stdout, stderr)
+
+
+def _demo_posix():
+    #
+    # Example 1: Simple redirection: Get process list
+    #
+    plist = Popen(["ps"], stdout=PIPE).communicate()[0]
+    print "Process list:"
+    print plist
+
+    #
+    # Example 2: Change uid before executing child
+    #
+    if os.getuid() == 0:
+        p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
+        p.wait()
+
+    #
+    # Example 3: Connecting several subprocesses
+    #
+    print "Looking for 'hda'..."
+    p1 = Popen(["dmesg"], stdout=PIPE)
+    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
+    print repr(p2.communicate()[0])
+
+    #
+    # Example 4: Catch execution error
+    #
+    print
+    print "Trying a weird file..."
+    try:
+        print Popen(["/this/path/does/not/exist"]).communicate()
+    except OSError, e:
+        if e.errno == errno.ENOENT:
+            print "The file didn't exist.  I thought so..."
+            print "Child traceback:"
+            print e.child_traceback
+        else:
+            print "Error", e.errno
+    else:
+        print >>sys.stderr, "Gosh.  No error."
+
+
+def _demo_windows():
+    #
+    # Example 1: Connecting several subprocesses
+    #
+    print "Looking for 'PROMPT' in set output..."
+    p1 = Popen("set", stdout=PIPE, shell=True)
+    p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
+    print repr(p2.communicate()[0])
+
+    #
+    # Example 2: Simple execution of program
+    #
+    print "Executing calc..."
+    p = Popen("calc")
+    p.wait()
+
+
+if __name__ == "__main__":
+    if mswindows:
+        _demo_windows()
+    else:
+        _demo_posix()
Index: trunk/src/testing/bin/fileServer/makeThumbs.py
===================================================================
--- trunk/src/testing/bin/fileServer/makeThumbs.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/makeThumbs.py	(revision 4)
@@ -0,0 +1,155 @@
+import os, os.path, sys, wx, stat, shutil
+import subprocess as sp
+import traceback as tb
+
+opj = os.path.join
+
+global FILES_DIR, THUMB_DIR
+
+MPLAYER_DIR = "mplayer"  # change if needed
+CONVERT_DIR = "convert"  # imagemagick's convert
+
+wx.InitAllImageHandlers()
+
+
+
+def __GetThumbName(fullPath, fileType):
+    fileSize = os.stat(fullPath).st_size
+    (root, ext) = os.path.splitext( os.path.basename(fullPath) )
+    thumbName = root+str(fileSize)+ext        #construct the thumb name
+
+    # video files have .jpg tacked onto the end
+    thumbName += ".jpg"
+            
+    return opj( THUMB_DIR, thumbName )
+
+
+
+    ### change the permission of the settings file to allow everyone to write to it
+def __SetWritePermissions(*files):
+    for filePath in files:
+        try:
+            flags = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP | stat.S_IROTH
+            os.chmod(filePath, flags)
+        except:
+            print str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2])
+
+
+
+def makeVideoThumb(fullPath, thumbPath):
+    print "\n", 80*"-", "\ncreating video thumbnail with command: "
+    # must create two frames because of mplayer bug
+    createCmd = MPLAYER_DIR+" -vo jpeg -quiet -frames 2 -ss 5 "+ fullPath
+    print createCmd
+    try:
+        sp.check_call(createCmd.split())
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+    # delete one of them
+    try:
+        os.remove("00000001.jpg")
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) 
+
+    # resize it to 300x300
+    try:
+        im = wx.Image("00000002.jpg")  # read the original image
+        if im.Ok():  #the image may be corrupted...
+            im.Rescale(300, 300)        # resize it
+            im.SaveFile("00000002.jpg", wx.BITMAP_TYPE_JPEG)    # save it back to a file
+    except: 
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+    # rename the right one
+    try:
+        shutil.move("00000002.jpg", thumbPath)
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) 
+    
+
+
+def makePDFThumb(fullPath, thumbPath):
+    print "\n", 80*"-", "\ncreating PDF thumbnail with command: "
+    createCmd = CONVERT_DIR+" -thumbnail 300x300 "+fullPath+"[0] "+thumbPath
+    print createCmd
+    try:
+        sp.check_call(createCmd.split())
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+         
+
+
+def makeImageThumb(fullPath, thumbPath):
+    def __GetWxBitmapType(name):
+        ext = os.path.splitext(name)[1]
+        ext = ext.lower()
+        if ext==".jpg": return wx.BITMAP_TYPE_JPEG
+        elif ext==".png": return wx.BITMAP_TYPE_PNG
+        elif ext==".bmp": return wx.BITMAP_TYPE_BMP
+        elif ext==".gif": return wx.BITMAP_TYPE_GIF
+        elif ext==".pcx": return wx.BITMAP_TYPE_PCX
+        elif ext==".pnm": return wx.BITMAP_TYPE_PNM
+        elif ext==".tif": return wx.BITMAP_TYPE_TIF
+        elif ext==".tiff": return wx.BITMAP_TYPE_TIF
+        elif ext==".xpm": return wx.BITMAP_TYPE_XPM
+        elif ext==".ico": return wx.BITMAP_TYPE_ICO
+        elif ext==".cur": return wx.BITMAP_TYPE_CUR
+        else:
+            return False
+
+    try:
+        wxImageType = __GetWxBitmapType(os.path.basename(fullPath))
+        if wxImageType:     # some types just cant be saved by wxPython
+            # write the thumb but name it with a filename and filesize so that they are unique
+            #thumbPath = __GetThumbName(fullPath, "image")           
+            im = wx.Image(fullPath)  # read the original image
+
+            if im.Ok():  #the image may be corrupted...
+                im.Rescale(300, 300)        # resize it
+                im.SaveFile(thumbPath, wx.BITMAP_TYPE_JPEG)    # save it back to a file
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+
+
+
+def makeThumbnail(fullPath, fileType, thumbPath):
+    if not os.path.exists(thumbPath):
+        if fileType == "image":
+            makeImageThumb(fullPath, thumbPath)
+        elif fileType == "video":
+            makeVideoThumb(fullPath, thumbPath)
+        elif fileType == "pdf":
+            makePDFThumb(fullPath, thumbPath)
+        else:
+            print "\nERROR:Don't know how to make thumbnail for:", fileType
+
+        if os.path.exists(thumbPath):
+            __SetWritePermissions(thumbPath)
+            
+
+def main():
+    for d in os.listdir(FILES_DIR):
+        if d=="image" or d=="video" or d=="pdf":
+            for root, dirs, files in os.walk(opj(FILES_DIR, d)):
+                for f in files:
+                    fullPath = opj(root, f)
+                    thumbPath = __GetThumbName(fullPath, d)
+                    if not os.path.exists(thumbPath):
+                        makeThumbnail(fullPath, d, thumbPath)
+
+
+if __name__ == '__main__':
+    import sys, os
+    global FILES_DIR, THUMB_DIR
+
+    if len(sys.argv) < 2:
+        print "USAGE: python makeThumbs.py path_to_file_library"
+    else:
+        FILES_DIR = sys.argv[1]
+        if os.path.exists(FILES_DIR):
+            THUMB_DIR = opj(FILES_DIR, "thumbnails")
+            main()
+        else:
+            print "Given directory doesn't exist... exiting"
+    
Index: trunk/src/testing/bin/fileServer/KILL_SERVER.py
===================================================================
--- trunk/src/testing/bin/fileServer/KILL_SERVER.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/KILL_SERVER.py	(revision 4)
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+
+### script that kills the FileServer running at the optionally specified port
+### this is useful when the FileServer was started by someone else
+### but you don't have the permissions to kill it
+
+import xmlrpclib, sys
+port = str(8800)
+if len(sys.argv) > 1: port = sys.argv[1]
+xmlrpclib.ServerProxy("http://localhost:"+port).Quit(1)
Index: trunk/src/testing/bin/fileServer/dirToDxt.py
===================================================================
--- trunk/src/testing/bin/fileServer/dirToDxt.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/dirToDxt.py	(revision 4)
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc  to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+#
+# Processes all the images in the passed in directory name and converts
+# them to DXT using a imgToDxt
+#
+# Call with: python dirToDxt.py dirName
+#
+# Author: Ratko Jagodic
+#
+
+import os, sys, os.path
+
+if len(sys.argv) < 2:
+    print "\nUsage: python dirToDxt.py directoryName\n"
+    sys.exit(0)
+
+count = 0
+skippedDirs = []
+for root, dirs, files in os.walk(sys.argv[1]):
+
+    # skip dir if we have no write permissions
+    if not os.access(root, os.W_OK):
+        skippedDirs.append(root)
+        print "\n***** No write permissions. Skipping ", root
+        continue
+    
+    for name in files:
+        # skip existing dxt files
+        if name.endswith(".dxt"):
+            continue
+        
+        count += 1
+        filePath = os.path.abspath(os.path.join(root, name))
+        print "\n\n#",count, "   -------------- ", filePath, " ---------------"
+        cmd = "imgToDxt '%s'" % filePath
+        os.system(cmd)
+
+
+print "\n\n", 10 * "------"
+print "Directories skipped due to insufficient write permissions:\n"
+for d in skippedDirs:
+    print d
+print "\n"
+
Index: trunk/src/testing/bin/fileServer/misc/__init__.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/__init__.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/__init__.py	(revision 4)
@@ -0,0 +1,2 @@
+### miscellaneous 3rd party modules used by File Server
+__all__ = ["mmpython", "imsize", "countPDFpages"]
Index: trunk/src/testing/bin/fileServer/misc/imsize.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/imsize.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/imsize.py	(revision 4)
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+# (c) Copyright 2001-2005 Hewlett-Packard Development Company, L.P.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Author: Don Welch
+# Ported from Perl's Image::Size module by Randy J. Ray
+# Modified by Perenzo, 2006
+
+import os, os.path, re, struct
+
+xbm_pat = re.compile(r'^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)', re.IGNORECASE)
+xpm_pat = re.compile(r'"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"', re.IGNORECASE)
+ppm_pat1 = re.compile(r'^\#.*', re.IGNORECASE | re.MULTILINE)
+ppm_pat2 = re.compile(r'^(P[1-6])\s+(\d+)\s+(\d+)', re.IGNORECASE)
+ppm_pat3 = re.compile(r'IMGINFO:(\d+)x(\d+)', re.IGNORECASE)
+tiff_endian_pat = re.compile(r'II\x2a\x00')
+
+def readin(stream, length, offset=0):
+    if offset != 0:
+        stream.seek(offset, 0)
+    return stream.read(length)
+
+def xbmsize(stream):
+    width, height = -1, -1
+    match = xbm_pat.match(readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def xpmsize(stream):
+    width, height = -1, -1
+    match = re.search(xpm_pat, readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def pngsize(stream): # also does MNG
+    width, height = -1, -1
+    if readin(stream, 4, 12) in ('IHDR', 'MHDR'):
+        height, width = struct.unpack("!II", stream.read(8))
+
+    return height, width #width, height
+
+def jpegsize(stream):
+    width, height = -1, -1
+    stream.seek(2)
+    while 1:
+        length = 4
+        buffer = readin(stream, length)
+        try:
+            marker, code, length = struct.unpack("!ccH", buffer)
+        except:
+            break
+        if marker != '\xff':
+            break
+        if 0xc0 <= ord(code) <= 0xc3:
+            length = 5
+            height, width = struct.unpack("!xHH", readin(stream, length))
+        else:
+            readin(stream, length-2)
+    return width, height
+
+def ppmsize(stream):
+    width, height = -1, -1
+    header = re.sub(ppm_pat1, '', readin(stream, 1024))
+    match = ppm_pat2.match(header)
+    typ = ''
+    try:
+        typ = match.group(1)
+        width = int(match.group(2))
+        height = int(match.group(3))
+    except:
+        pass
+    if typ == 'P7':
+        match = ppm_pat3.match(header)
+
+        try:
+            width = int(match.group(1))
+            height = int(match.group(2))
+        except:
+            pass
+    return width, height
+
+def tiffsize(stream):
+    header = readin(stream, 4)
+    endian = ">"
+    match = tiff_endian_pat.match(header)
+    if match is not None:
+        endian = "<"
+    input = readin(stream, 4, 4)
+    offset = struct.unpack('%si' % endian, input)[0]
+    num_dirent = struct.unpack('%sH' % endian, readin(stream, 2, offset))[0]
+    offset += 2
+    num_dirent = offset+(num_dirent*12)
+    width, height = -1, -1
+    while True:
+        ifd = readin(stream, 12, offset)
+        if ifd == '' or offset > num_dirent:
+            break
+        offset += 12
+        tag = struct.unpack('%sH'% endian, ifd[0:2])[0]
+        type = struct.unpack('%sH' % endian, ifd[2:4])[0]
+        if tag == 0x0100:
+            width = struct.unpack("%si" % endian, ifd[8:12])[0]
+        elif tag == 0x0101:
+            height = struct.unpack("%si" % endian, ifd[8:12])[0]
+    return width, height
+
+def bmpsize(stream):
+    width, height = struct.unpack("<II", readin(stream, 8, 18))
+    return width, height
+
+def gifsize(stream):
+    # since we only care about the printed size of the image
+    # we only need to get the logical screen sizes, which are
+    # the maximum extents of the image. This code is much simpler
+    # than the code from Image::Size
+    #width, height = -1, -1
+    buf = readin(stream, 7, 6) # LSx, GCTF, etc
+    height, width, flags, bci, par = struct.unpack('<HHBBB', buf)
+    return height, width #width, height
+
+TYPE_MAP = { re.compile('^GIF8[7,9]a')              : ('image/gif', gifsize),
+             re.compile("^\xFF\xD8")                : ('image/jpeg', jpegsize),
+             re.compile("^\x89PNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+             re.compile("^P[1-7]")                  : ('image/x-portable-pixmap', ppmsize),
+             re.compile('\#define\s+\S+\s+\d+')     : ('image/x-xbitmap', xbmsize),
+             re.compile('\/\* XPM \*\/')            : ('image/x-xpixmap', xpmsize),
+             re.compile('^MM\x00\x2a')              : ('image/tiff', tiffsize),
+             re.compile('^II\*\x00')                : ('image/tiff', tiffsize),
+             re.compile('^BM')                      : ('image/x-bitmap', bmpsize),
+             re.compile("^\x8aMNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+           }
+
+def imagesize(filename, mime_type=''):
+    width, height = -1, -1
+    f = file(filename, 'rb')
+    buffer = f.read(4096)
+    if not mime_type:
+        for t in TYPE_MAP:
+            match = t.search(buffer)
+            if match is not None:
+                mime_type, func = TYPE_MAP[t]
+                break
+    if mime_type and func:
+        f.seek(0)
+        width, height = func(f)
+    else:
+        width, height = -1, -1
+    f.close()
+    return height, width, mime_type
+
+if __name__=="__main__":
+    import sys
+    print imagesize(sys.argv[1])
Index: trunk/src/testing/bin/fileServer/misc/countPDFpages.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/countPDFpages.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/countPDFpages.py	(revision 4)
@@ -0,0 +1,18 @@
+import re
+
+def getPDFPageCount(filename):    
+    """Counts pages in a PDF document. 
+    
+    This is GPLed code written by J.Alet on 2004/06/19
+    """
+    try:
+        infile = open(filename, "rb")
+        regexp = re.compile(r"(/Type) ?(/Page)[/ \r\n]")
+        pagecount = 0
+        for line in infile.xreadlines(): 
+            pagecount += len(regexp.findall(line))
+        infile.close()
+        return pagecount
+    except:
+        return -1
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/__init__.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/__init__.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/__init__.py	(revision 4)
@@ -0,0 +1,178 @@
+#!/usr/bin/python
+#if 0
+# -----------------------------------------------------------------------
+# $Id: __init__.py,v 1.35 2004/10/15 09:02:11 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: __init__.py,v $
+# Revision 1.35  2004/10/15 09:02:11  dischi
+# add ac3 parser
+#
+# Revision 1.34  2004/05/20 15:55:08  dischi
+# add xml file detection
+#
+# Revision 1.33  2004/05/02 08:28:20  dischi
+# dvd iso support
+#
+# Revision 1.32  2004/04/18 09:11:36  dischi
+# improved lsdvd support
+#
+# Revision 1.31  2004/04/17 18:38:54  dischi
+# add lsdvd parser to avoid problems with our own
+#
+# Revision 1.30  2004/01/31 12:24:39  dischi
+# add basic matroska info
+#
+# Revision 1.29  2004/01/27 20:27:52  dischi
+# remove cache, it does not belong in mmpython
+#
+# Revision 1.28  2004/01/03 17:44:04  dischi
+# catch OSError in case the file is removed file scanning
+#
+# Revision 1.27  2003/11/24 20:30:17  dischi
+# fix again, dvd may fail, but datadir may not
+#
+# Revision 1.26  2003/11/24 20:29:26  dischi
+# resort to let dvd work again
+#
+# Revision 1.25  2003/11/07 13:58:52  dischi
+# extra check for dvd
+#
+# Revision 1.24  2003/09/22 16:24:58  the_krow
+# o added flac
+# o try-except block around ioctl since it is not avaiable in all OS
+#
+# Revision 1.23  2003/09/14 13:50:42  dischi
+# make it possible to scan extention based only
+#
+# Revision 1.22  2003/09/10 18:41:44  dischi
+# add USE_NETWORK, maybe there is no network connection
+#
+# Revision 1.20  2003/08/26 13:16:41  outlyer
+# Enabled m4a support
+#
+# Revision 1.19  2003/07/10 11:17:35  the_krow
+# ogminfo is used to parse ogg files
+#
+# Revision 1.18  2003/07/01 21:07:42  dischi
+# switch back to eyed3info
+#
+# Revision 1.17  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+# Do this stuff before importing the info instances since they 
+# depend on this function
+
+import factory
+
+from synchronizedobject import SynchronizedObject
+
+_factory = None
+
+def Factory():
+    global _factory
+
+    # One-time init
+    if _factory == None:
+        _factory = SynchronizedObject(factory.Factory())
+        
+    return _factory
+
+def registertype(mimetype,extensions,type,c):
+    f = Factory()
+    f.register(mimetype,extensions,type,c)    
+
+def gettype(mimetype,extensions):
+    f = Factory()
+    return f.get(mimetype,extensions)    
+    
+
+# Okay Regular imports and code follow
+
+import sys
+import os
+import mediainfo
+#import audio.ogginfo
+import audio.pcminfo
+import audio.m4ainfo
+import audio.ac3info
+import video.riffinfo
+import video.mpeginfo
+import video.asfinfo
+import video.movinfo
+import image.jpginfo
+import image.pnginfo
+import image.tiffinfo
+import image.ImageInfo
+import video.vcdinfo
+import video.realinfo
+import video.ogminfo
+import video.mkvinfo
+import misc.xmlinfo
+
+# import some disc modules (may fail)
+try:
+    import disc.discinfo
+    import disc.vcdinfo
+    import disc.audioinfo
+except ImportError:
+    pass
+
+# find the best working DVD module
+try:
+    import disc.lsdvd
+except ImportError:
+    pass
+
+try:
+    import disc.dvdinfo
+except ImportError:
+    pass
+
+# use fallback disc module
+try:
+    import disc.datainfo
+except ImportError:
+    pass
+
+import audio.eyed3info
+#import audio.mp3info
+import audio.webradioinfo
+import audio.flacinfo
+
+
+
+USE_NETWORK     = 1
+
+
+def parse(filename, ext_only = 0):
+    """
+    parse the file
+    """
+    return Factory().create(filename, ext_only)
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/setup.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/setup.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/setup.py	(revision 4)
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+"""Setup script for the mmpython distribution."""
+
+__revision__ = "$Id: setup.py,v 1.12 2004/05/25 14:10:19 the_krow Exp $"
+
+from distutils.core import setup, Extension
+import popen2
+import version
+
+extensions = [ Extension('mmpython/disc/cdrom', ['disc/cdrommodule.c']) ]
+# check for libdvdread (bad hack!)
+# Windows does not have Popen4, so catch exception here
+try:
+    child = popen2.Popen4('gcc -ldvdread')
+    if child.fromchild.readline().find('cannot find') == -1:
+        # gcc failed, but not with 'cannot find', so libdvd must be
+        # somewhere (I hope)
+        extensions.append(Extension('mmpython/disc/ifoparser', ['disc/ifomodule.c'],
+                                    libraries=[ 'dvdread' ], 
+                                    library_dirs=['/usr/local/lib'],
+                                    include_dirs=['/usr/local/include']))
+    child.wait()
+except AttributeError, e:
+    print "No Popen4 found. This seems to be Windows."
+    print "Installing without libdvdread support."
+    # Hack: disable extensions for Windows. 
+    # This would better be done by a clean detect of windows. But how?
+    extensions = []
+    
+    
+
+setup (# Distribution meta-data
+       name = "mmpython",
+       version = version.VERSION,
+       description = "Module for retrieving information about media files",
+       author = "Thomas Schueppel, Dirk Meyer",
+       author_email = "freevo-devel@lists.sourceforge.net",
+       url = "http://mmpython.sf.net",
+
+       scripts     = [ 'mminfo' ],
+       package_dir = {'mmpython.video': 'video',
+                      'mmpython.audio': 'audio',
+                      'mmpython.audio.eyeD3': 'audio/eyeD3',
+                      'mmpython.image': 'image',
+                      'mmpython.disc' : 'disc',
+                      'mmpython.misc' : 'misc',
+                      'mmpython': ''},
+
+       packages = [ 'mmpython', 'mmpython.video', 'mmpython.audio', 'mmpython.audio.eyeD3',
+                    'mmpython.image', 'mmpython.disc', 'mmpython.misc' ],
+       
+       # Description of the modules and packages in the distribution
+       ext_modules = extensions
+                       
+      )
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/misc/xmlinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/misc/xmlinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/misc/xmlinfo.py	(revision 4)
@@ -0,0 +1,77 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: xmlinfo.py,v 1.2 2004/05/24 10:50:48 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: xmlinfo.py,v $
+# Revision 1.2  2004/05/24 10:50:48  dischi
+# bugfix
+#
+# Revision 1.1  2004/05/20 15:55:09  dischi
+# add xml file detection
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import os
+import mmpython
+from mmpython import mediainfo
+
+DEBUG = mediainfo.DEBUG
+
+try:
+    # XML support
+    from xml.utils import qp_xml
+except:
+    if DEBUG:
+        print 'Python XML not found'
+
+
+XML_TAG_INFO = {
+    'image':  'Bins Image Description',
+    'freevo': 'Freevo XML Definition'
+    }
+    
+class XMLInfo(mediainfo.MediaInfo):
+
+    def __init__(self,file):
+        mediainfo.MediaInfo.__init__(self)
+        self.valid = 0
+        if not file.name.endswith('.xml') and not file.name.endswith('.fxd'):
+            return
+
+        self.mime  = 'text/xml'
+        self.type  = ''
+
+        try:
+            parser = qp_xml.Parser()
+            tree = parser.parse(file)
+        except:
+            return 0
+
+        if tree.name in XML_TAG_INFO:
+            self.type = XML_TAG_INFO[tree.name]
+        else:
+            self.type = 'XML file'
+        self.valid = 1
+        
+
+mmpython.registertype( 'text/xml', ('xml', 'fxd'), mediainfo.TYPE_MISC, XMLInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/synchronizedobject.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/synchronizedobject.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/synchronizedobject.py	(revision 4)
@@ -0,0 +1,59 @@
+# -*- coding: iso-8859-1 -*-
+
+
+#
+# synchronized objects and methods.
+# By André Bjärby
+# From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65202
+# 
+
+from types import *
+
+def _get_method_names (obj):
+    if type(obj) == InstanceType:
+        return _get_method_names(obj.__class__)
+    
+    elif type(obj) == ClassType:
+        result = []
+        for name, func in obj.__dict__.items():
+            if type(func) == FunctionType:
+                result.append((name, func))
+
+        for base in obj.__bases__:
+            result.extend(_get_method_names(base))
+
+        return result
+
+
+class _SynchronizedMethod:
+
+    def __init__ (self, method, obj, lock):
+        self.__method = method
+        self.__obj = obj
+        self.__lock = lock
+
+    def __call__ (self, *args, **kwargs):
+        self.__lock.acquire()
+        try:
+            #print 'Calling method %s from obj %s' % (self.__method, self.__obj)
+            return self.__method(self.__obj, *args, **kwargs)
+        finally:
+            self.__lock.release()
+
+class SynchronizedObject:    
+    def __init__ (self, obj, ignore=[], lock=None):
+        import threading
+
+        self.__methods = {}
+        self.__obj = obj
+        lock = lock and lock or threading.RLock()
+        for name, method in _get_method_names(obj):
+            if not name in ignore:
+                self.__methods[name] = _SynchronizedMethod(method, obj, lock)
+
+    def __getattr__ (self, name):
+        try:
+            return self.__methods[name]
+        except KeyError:
+            return getattr(self.__obj, name)
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/CREDITS
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/CREDITS	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/CREDITS	(revision 4)
@@ -0,0 +1,30 @@
+Credits for mmpython
+====================
+
+$Id: CREDITS,v 1.3 2003/06/09 12:50:07 the_krow Exp $
+
+
+Maintainer: Thomas Schueppel <stain@acm.org>
+
+Developers:
+o Thomas Schueppel <stain@acm.org>
+o Dirk Meyer <dmeyer@tzi.de>
+
+
+
+This package also includes some code from the following projects:
+
+- disc/ifomodule.c is based on ifoinfo from Jens Arnfast
+  http://arnfast.net/projects/ifoinfo.php
+
+- The Python CDDB module from Ben Gertzfield <che@debian.org>
+  http://cddb-py.sourceforge.net/
+
+- bins support by John Cooper, made for the Freevo project
+
+- code from "exifdump.py" originally written by Thierry Bousch
+  <bousch@topo.math.u-psud.fr> and released into the public domain.
+  and code by Gene Cash <gcash@cfl.rr.com>
+
+- code out of Vivake Guptas mp3info which is to be found at
+  http://www.omniscia.org/~vivake/python/MP3Info.py 
Index: trunk/src/testing/bin/fileServer/misc/mmpython/README
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/README	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/README	(revision 4)
@@ -0,0 +1,7 @@
+To install just run 'python setup.py install' as root. For more
+options like build only and making tarballs please run 
+'python setup.py --help' for more commands.
+
+If you have questions, please contact the Freevo mailing list
+(http://freevo.sf.net)
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/factory.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/factory.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/factory.py	(revision 4)
@@ -0,0 +1,306 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: factory.py,v 1.20.2.1 2005/05/07 11:37:08 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: factory.py,v $
+# Revision 1.20.2.1  2005/05/07 11:37:08  dischi
+# make sure all strings are unicode
+#
+# Revision 1.20  2004/05/29 12:30:36  dischi
+# add function to correct data from the different mime modules
+#
+# Revision 1.19  2004/05/28 19:32:31  dischi
+# remove old stuff
+#
+# Revision 1.18  2004/05/17 19:10:57  dischi
+# better DEBUG handling
+#
+# Revision 1.17  2004/05/02 08:28:20  dischi
+# dvd iso support
+#
+# Revision 1.16  2004/02/03 20:41:18  dischi
+# add directory support
+#
+# Revision 1.15  2004/01/31 12:25:20  dischi
+# better ext checking
+#
+# Revision 1.13  2003/09/22 16:24:58  the_krow
+# o added flac
+# o try-except block around ioctl since it is not avaiable in all OS
+#
+# Revision 1.12  2003/09/14 13:50:42  dischi
+# make it possible to scan extention based only
+#
+# Revision 1.11  2003/09/01 19:23:23  dischi
+# ignore case when searching the correct extention
+#
+# Revision 1.10  2003/08/30 12:16:24  dischi
+# special handling for directories
+#
+# Revision 1.8  2003/08/26 18:01:26  outlyer
+# Patch from Lars Eggert for FreeBSD support
+#
+# Revision 1.4  2003/07/04 15:34:45  outlyer
+# Allow 'cdda' as well as 'cd' since we get that sometimes, and make sure
+# we import urllib.
+#
+# Revision 1.3  2003/07/02 09:32:16  the_krow
+# More Keys
+# import traceback was missing in factory
+#
+# Revision 1.1  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import mediainfo
+import stat
+import os
+import urlparse
+import traceback
+import urllib
+
+DEBUG = 0
+
+try:
+    DEBUG = int(os.environ['MMPYTHON_DEBUG'])
+except:
+    pass
+
+
+
+def isurl(url):
+    return url.find('://') > 0
+
+class Factory:
+    """
+    Abstract Factory for the creation of MediaInfo instances. The different Methods
+    create MediaInfo objects by parsing the given medium. 
+    """
+    def __init__(self):
+        self.extmap = {}
+        self.mimemap = {}
+        self.types = []
+        self.device_types = []
+        self.directory_types = []
+        self.stream_types = []
+        
+    def create_from_file(self, file, ext_only=0):
+        """
+        create based on the file stream 'file
+        """
+        # Check extension as a hint
+        for e in self.extmap.keys():
+            if DEBUG > 1: print "trying ext %s" % e
+            if file.name.lower().endswith(e.lower()):
+                if DEBUG == 1: print "trying ext %s" % e
+                try:
+                    file.seek(0,0)
+                    t = self.extmap[e][3](file)
+                    if t.valid: return t
+                except:
+                    if DEBUG:
+                        traceback.print_exc()
+
+        # no searching on all types
+        if ext_only:
+            return None
+
+        if DEBUG:
+            print "No Type found by Extension. Trying all"
+
+        for e in self.types:
+            if DEBUG: print "Trying %s" % e[0]
+            try:
+                file.seek(0,0)
+                t = e[3](file)
+                if t.valid:
+                    if DEBUG: print 'found'
+                    return t
+            except:
+                if DEBUG:
+                    traceback.print_exc()
+        if DEBUG: print 'not found'
+        return None
+
+
+    def create_from_url(self,url):
+        """
+        Create information for urls. This includes file:// and cd://
+        """
+        split  = urlparse.urlsplit(url)
+        scheme = split[0]
+
+        if scheme == 'file':
+            (scheme, location, path, query, fragment) = split
+            return self.create_from_filename(location+path)
+
+        elif scheme == 'cdda':
+            r = self.create_from_filename(split[4])
+            if r:
+                r.url = url
+            return r
+        
+        elif scheme == 'http':
+            # Quick Hack for webradio support
+            # We will need some more soffisticated and generic construction
+            # method for this. Perhaps move file.open stuff into __init__
+            # instead of doing it here...
+            for e in self.stream_types:
+                if DEBUG: print 'Trying %s' % e[0]
+                t = e[3](url)
+                if t.valid:
+                    t.url = url
+                    return t
+            
+        else:
+            (scheme, location, path, query, fragment) = split
+            uhandle = urllib.urlopen(url)
+            mime = uhandle.info().gettype()
+            print "Trying %s" % mime
+            if self.mimemap.has_key(mime):
+                t = self.mimemap[mime][3](file)
+                if t.valid: return t
+            # XXX Todo: Try other types
+        pass
+
+
+    def create_from_filename(self, filename, ext_only=0):
+        """
+        Create information for the given filename
+        """
+        if os.path.isdir(filename):
+            return None
+        if os.path.isfile(filename):
+            try:
+                f = open(filename,'rb')
+            except IOError:
+                print 'IOError reading %s' % filename
+                return None
+            r = self.create_from_file(f, ext_only)
+            f.close()
+            if r:
+                r.correct_data()
+                r.url = 'file://%s' % os.path.abspath(filename)
+                return r
+        return None
+    
+
+    def create_from_device(self,devicename):
+        """
+        Create information from the device. Currently only rom drives
+        are supported.
+        """
+        for e in self.device_types:
+            if DEBUG: print 'Trying %s' % e[0]
+            t = e[3](devicename)
+            if t.valid:
+                t.url = 'file://%s' % os.path.abspath(devicename)
+                return t
+        return None
+            
+
+    def create_from_directory(self, dirname):
+        """
+        Create information from the directory.
+        """
+        for e in self.directory_types:
+            if DEBUG: print 'Trying %s' % e[0]
+            t = e[3](dirname)
+            if t.valid:
+                return t
+        return None
+            
+
+    def create(self, name, ext_only=0):
+        """
+        Global 'create' function. This function calls the different
+        'create_from_'-functions.
+        """
+        try:
+            if isurl(name):
+                return self.create_from_url(name)
+            if not os.path.exists(name):
+                return None
+            try:
+                if (os.uname()[0] == 'FreeBSD' and \
+                    stat.S_ISCHR(os.stat(name)[stat.ST_MODE])) \
+                    or stat.S_ISBLK(os.stat(name)[stat.ST_MODE]):
+                    return self.create_from_device(name)
+            except AttributeError:
+                pass            
+            if os.path.isdir(name):
+                return self.create_from_directory(name)
+            return self.create_from_filename(name, ext_only)
+        except:
+            print 'mmpython.create error:'
+            traceback.print_exc()
+            print
+            print 'Please report this bug to the Freevo mailing list'
+            return None
+
+
+        
+    def register(self,mimetype,extensions,type,c):
+        """
+        register the parser to mmpython
+        """
+        if DEBUG > 0:
+            print "%s registered" % mimetype
+        tuple = (mimetype,extensions,type,c)
+
+        if extensions == mediainfo.EXTENSION_DEVICE:
+            self.device_types.append(tuple)
+        elif extensions == mediainfo.EXTENSION_DIRECTORY:
+            self.directory_types.append(tuple)
+        elif extensions == mediainfo.EXTENSION_STREAM:
+            self.stream_types.append(tuple)
+        else:
+            self.types.append(tuple)
+            for e in extensions:
+                self.extmap[e] = tuple
+            self.mimemap[mimetype] = tuple
+
+
+    def get(self, mimetype, extensions):
+        """
+        return the object for mimetype/extensions or None
+        """
+        if extensions == mediainfo.EXTENSION_DEVICE:
+            l = self.device_types
+        elif extensions == mediainfo.EXTENSION_DIRECTORY:
+            l = self.directory_types
+        elif extensions == mediainfo.EXTENSION_STREAM:
+            l = self.stream_types
+        else:
+            l = self.types
+
+        for info in l:
+            if info[0] == mimetype and info[1] == extensions:
+                return info[3]
+
+        return None
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyed3info.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyed3info.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyed3info.py	(revision 4)
@@ -0,0 +1,331 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: eyed3info.py,v 1.16 2005/01/01 14:18:11 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: eyed3info.py,v $
+# Revision 1.16  2005/01/01 14:18:11  dischi
+# add samplerate, bitrate and mode
+#
+# Revision 1.15  2004/09/09 02:45:58  outlyer
+# Add the TPOS tag for multiple disc sets.
+#
+# Revision 1.14  2004/07/21 18:54:36  outlyer
+# Big bugfix.
+#
+# If a mp3 lacks a genre, then nothing after the genre parsing works. This breaks
+# calculating the length, among other things because it's all in a try except, so
+# self.length takes on a random value. I was getting track lengths like 20000 seconds
+# until I made this change.
+#
+# Revision 1.13  2004/07/11 12:06:03  dischi
+# add genre parsing
+#
+# Revision 1.12  2004/07/07 09:35:50  dischi
+# remove guessing of tracknum in TCON
+#
+# Revision 1.11  2004/05/29 12:31:36  dischi
+# try to find trackof in TCON or trackno
+#
+# Revision 1.10  2004/02/08 17:42:56  dischi
+# reduce debug
+#
+# Revision 1.9  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.8  2003/07/10 13:05:05  the_krow
+# o id3v2 tabled added to eyed3
+# o type changed to MUSIC
+#
+# Revision 1.7  2003/07/02 20:15:42  dischi
+# return nothing, not 0
+#
+# Revision 1.6  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/30 11:38:22  dischi
+# bugfix
+#
+# Revision 1.4  2003/06/29 18:30:14  dischi
+# many many fixes
+#
+# Revision 1.3  2003/06/29 12:03:41  dischi
+# fixed it to be _real_ eyed3 info
+#
+# Revision 1.2  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.1  2003/06/09 23:13:21  the_krow
+# bugfix: unknown files are now resetted before trying if they are valid
+# first rudimentary eyed3 mp3 parser added
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Most of the code of this module was taken from Vivake Guptas mp3info
+# code. Below is his copyright notice. All credit to him.
+#
+# Copyright (c) 2002 Vivake Gupta (vivakeATomniscia.org).  All rights reserved.
+# This software is maintained by Vivake (vivakeATomniscia.org) and is available at:
+#     http://www.omniscia.org/~vivake/python/MP3Info.py
+#
+#
+
+
+from mmpython import mediainfo
+import mmpython
+
+from eyeD3 import tag as eyeD3_tag
+from eyeD3 import frames as eyeD3_frames
+
+import os
+import struct
+import traceback
+import id3 as id3info
+
+MP3_INFO_TABLE = { "APIC": "picture",
+                   "LINK": "link",
+                   "TALB": "album",
+                   "TCOM": "composer",
+                   "TCOP": "copyright",
+                   "TDOR": "release",
+                   "TYER": "date",
+                   "TEXT": "text",
+                   "TIT2": "title",
+                   "TLAN": "language",
+                   "TLEN": "length",
+                   "TMED": "media_type",
+                   "TPE1": "artist",
+                   "TPE2": "artist",
+                   "TRCK": "trackno",
+                   "TPOS": "discs"}
+
+_bitrates = [
+    [ # MPEG-2 & 2.5
+        [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,None], # Layer 1
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None], # Layer 2
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None]  # Layer 3
+    ],
+
+    [ # MPEG-1
+        [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,None], # Layer 1
+        [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,None], # Layer 2
+        [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,None]  # Layer 3
+    ]
+]
+
+_samplerates = [
+    [ 11025, 12000,  8000, None], # MPEG-2.5
+    [  None,  None,  None, None], # reserved
+    [ 22050, 24000, 16000, None], # MPEG-2
+    [ 44100, 48000, 32000, None], # MPEG-1
+]
+
+_modes = [ "stereo", "joint stereo", "dual channel", "mono" ]
+
+_MP3_HEADER_SEEK_LIMIT = 4096
+
+class eyeD3Info(mediainfo.MusicInfo):
+   
+   fileName       = str();
+   fileSize       = int();
+   
+   def __init__(self, file, tagVersion = eyeD3_tag.ID3_ANY_VERSION):
+      mediainfo.MusicInfo.__init__(self)
+      self.fileName = file.name;
+      self.valid = 1
+      self.mime = 'audio/mp3'
+
+      if not eyeD3_tag.isMp3File(file.name):
+         self.valid = 0
+         return
+
+      id3 = None
+      try:
+         id3 = eyeD3_tag.Mp3AudioFile(file.name)
+      except eyeD3_tag.TagException:
+         try:
+            id3 = eyeD3_tag.Mp3AudioFile(file.name)
+         except eyeD3_tag.InvalidAudioFormatException:
+            # File is not an MP3
+            self.valid = 0
+            return
+         except:
+            # The MP3 tag decoder crashed, assume the file is still
+            # MP3 and try to play it anyway
+            if mediainfo.DEBUG:
+               print 'music: oops, mp3 tag parsing failed!'
+               print 'music: filename = "%s"' % file.name
+               traceback.print_exc()
+      except:
+         # The MP3 tag decoder crashed, assume the file is still
+         # MP3 and try to play it anyway
+         if mediainfo.DEBUG:
+            print 'music: oops, mp3 tag parsing failed!'
+            print 'music: filename = "%s"' % file.name
+            traceback.print_exc()
+
+      if not self.valid:
+         return
+
+      if mediainfo.DEBUG > 1:
+         print id3.tag.frames
+      try:
+         if id3 and id3.tag:
+            for k in MP3_INFO_TABLE:
+               if id3.tag.frames[k]:
+                  if k == 'APIC':
+                     pass 
+                  else:
+                     setattr(self, MP3_INFO_TABLE[k], id3.tag.frames[k][0].text)
+            if id3.tag.getYear():
+               self.date = id3.tag.getYear()
+            tab = {}
+            for f in id3.tag.frames:
+                if f.__class__ is eyeD3_frames.TextFrame:                
+                    tab[f.header.id] = f.text
+                elif f.__class__ is eyeD3_frames.UserTextFrame:
+                    tab[f.header.id] = f.text
+                elif f.__class__ is eyeD3_frames.DateFrame:
+                    tab[f.header.id] = f.date_str
+                elif f.__class__ is eyeD3_frames.CommentFrame:
+                    tab[f.header.id] = f.comment
+                elif f.__class__ is eyeD3_frames.URLFrame:
+                    tab[f.header.id] = f.url
+                elif f.__class__ is eyeD3_frames.UserURLFrame:
+                    tab[f.header.id] = f.url
+                elif mediainfo.DEBUG:
+                   print f.__class__
+            self.appendtable('id3v2', tab, 'en')
+
+            if id3.tag.frames['TCON']:
+               genre = None
+               tcon = id3.tag.frames['TCON'][0].text
+               try:
+                  genre = int(tcon)
+               except:
+                  try:
+                      genre = int(tcon[1:tcon.find(')')])
+                  except ValueError:
+                      pass
+               if genre is not None:
+                  try:
+                     self.genre = id3info.GENRE_LIST[genre]
+                  except:
+                     pass
+            # and some tools store it as trackno/trackof in TRCK
+            if not self['trackof'] and self['trackno'] and self['trackno'].find('/') > 0:
+                self['trackof'] = self['trackno'][self['trackno'].find('/')+1:]
+                self['trackno'] = self['trackno'][:self['trackno'].find('/')]
+         if id3:
+            self.length = id3.getPlayTime()
+      except:
+         if mediainfo.DEBUG:
+            traceback.print_exc()
+      offset, header = self._find_header(file)
+      if offset == -1 or header is None:
+         return
+
+      self._parse_header(header)
+      
+
+   def _find_header(self, file):
+      file.seek(0, 0)
+      amount_read = 0
+      
+      # see if we get lucky with the first four bytes
+      amt = 4
+      
+      while amount_read < _MP3_HEADER_SEEK_LIMIT:
+         header = file.read(amt)
+         if len(header) < amt:
+            # awfully short file. just give up.
+            return -1, None
+
+         amount_read = amount_read + len(header)
+         
+         # on the next read, grab a lot more
+         amt = 500
+         
+         # look for the sync byte
+         offset = header.find(chr(255))
+         if offset == -1:
+            continue
+             
+         # looks good, make sure we have the next 3 bytes after this
+         # because the header is 4 bytes including sync
+         if offset + 4 > len(header):
+            more = file.read(4)
+            if len(more) < 4:
+               # end of file. can't find a header
+               return -1, None
+            amount_read = amount_read + 4
+            header = header + more
+
+         # the sync flag is also in the next byte, the first 3 bits
+         # must also be set
+         if ord(header[offset+1]) >> 5 != 7:
+            continue
+
+         # ok, that's it, looks like we have the header
+         return amount_read - len(header) + offset, header[offset:offset+4]
+
+      # couldn't find the header
+      return -1, None
+
+
+   def _parse_header(self, header):
+      # http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+      bytes = struct.unpack('>i', header)[0]
+      mpeg_version =    (bytes >> 19) & 3
+      layer =           (bytes >> 17) & 3
+      bitrate =         (bytes >> 12) & 15
+      samplerate =      (bytes >> 10) & 3
+      mode =            (bytes >> 6)  & 3
+
+      if mpeg_version == 0:
+         self.version = 2.5
+      elif mpeg_version == 2:
+         self.version = 2
+      elif mpeg_version == 3:
+         self.version = 1
+      else:
+         return
+
+      if layer > 0:
+         layer = 4 - layer
+      else:
+         return
+
+      self.bitrate = _bitrates[mpeg_version & 1][layer - 1][bitrate]
+      self.samplerate = _samplerates[mpeg_version][samplerate]
+
+      if self.bitrate is None or self.samplerate is None:
+         return
+
+      self.mode = _modes[mode]
+      self.keys.append('mode')
+
+
+mmpython.registertype( 'audio/mp3', ('mp3',), mediainfo.TYPE_MUSIC, eyeD3Info )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/ogginfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/ogginfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/ogginfo.py	(revision 4)
@@ -0,0 +1,171 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: ogginfo.py,v 1.16 2004/05/18 21:56:18 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: ogginfo.py,v $
+# Revision 1.16  2004/05/18 21:56:18  dischi
+# do not pare the whole file to get the length
+#
+# Revision 1.15  2003/09/22 16:21:20  the_krow
+# o ogg parsing should basically work
+# o utf-8 for vorbis comments
+#
+# Revision 1.14  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.13  2003/06/29 12:03:15  dischi
+# make some debug silent
+#
+# Revision 1.12  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.11  2003/06/10 11:17:39  the_krow
+# - OGG Fixes
+# - changed one DiscInfo reference in vcdinfo I missed before
+#
+# Revision 1.10  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.9  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.8  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.7  2003/06/07 23:32:11  the_krow
+# changed names to new format
+# debug messages
+#
+# Revision 1.6  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.5  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import os, stat
+import struct
+
+from mmpython import mediainfo
+import mmpython
+
+VORBIS_PACKET_INFO = '\01vorbis'
+VORBIS_PACKET_HEADER = '\03vorbis'
+VORBIS_PACKET_SETUP = '\05vorbis'
+
+_print = mediainfo._debug
+
+class OggInfo(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        h = file.read(4+1+1+20+1)
+        if h[:5] != "OggS\00":
+            _print("Invalid header")
+            self.valid = 0
+            return
+        if ord(h[5]) != 2:
+            _print("Invalid header type flag (trying to go ahead anyway)")
+        self.pageSegCount = ord(h[-1])
+        # Skip the PageSegCount
+        file.seek(self.pageSegCount,1)
+        h = file.read(7)
+        if h != VORBIS_PACKET_INFO:
+            _print("Wrong vorbis header type, giving up.")
+            self.valid = 0
+            return
+        self.valid = 1
+        self.mime = 'application/ogg'
+        header = {}
+        info = file.read(23)
+        self.version, self.channels, self.samplerate, bitrate_max, self.bitrate, bitrate_min, blocksize, framing = struct.unpack('<IBIiiiBB',info[:23])
+        # INFO Header, read Oggs and skip 10 bytes
+        h = file.read(4+10+13)        
+        if h[:4] == 'OggS':
+            (serial, pagesequence, checksum, numEntries) = struct.unpack( '<14xIIIB', h )
+            # skip past numEntries
+            file.seek(numEntries,1)
+            h = file.read(7)
+            if h != VORBIS_PACKET_HEADER:
+                # Not a corrent info header
+                return                        
+            self.encoder = self._extractHeaderString(file)
+            numItems = struct.unpack('<I',file.read(4))[0]
+            for i in range(numItems):
+                s = self._extractHeaderString(file)
+                a = re.split('=',s)
+                header[(a[0]).upper()]=a[1]
+            # Put Header fields into info fields
+            if header.has_key('TITLE'):
+                self.title = header['TITLE']
+            if header.has_key('ALBUM'):
+                self.album = header['ALBUM']
+            if header.has_key('ARTIST'):
+                self.artist = header['ARTIST']            
+            if header.has_key('COMMENT'):
+                self.comment = header['COMMENT']
+            if header.has_key('DATE'):
+                self.date = header['DATE']
+            if header.has_key('ENCODER'):
+                self.encoder = header['ENCODER']
+            if header.has_key('TRACKNUMBER'):
+                self.trackno = header['TRACKNUMBER']
+            self.type = 'OGG Vorbis'
+            self.subtype = ''
+            self.length = self._calculateTrackLength(file)
+            self.appendtable('VORBISCOMMENT',header)
+                                            
+    def _extractHeaderString(self,f):
+        len = struct.unpack( '<I', f.read(4) )[0]
+        return unicode(f.read(len), 'utf-8')
+    
+
+    def _calculateTrackLength(self,f):
+        # seek to the end of the stream, to avoid scanning the whole file
+        if (os.stat(f.name)[stat.ST_SIZE] > 20000):
+            f.seek(os.stat(f.name)[stat.ST_SIZE]-10000)
+
+        # read the rest of the file into a buffer
+        h = f.read()
+        granule_position = 0
+        # search for each 'OggS' in h        
+        if len(h):
+            idx = h.rfind('OggS')
+            if idx < 0:
+                return 0
+            pageSize = 0
+            h = h[idx+4:]
+            (check, type, granule_position, absPos, serial, pageN, crc, segs) = struct.unpack( '<BBIIIIIB', h[:23] )            
+            if check != 0:
+                _print(h[:10])
+                return
+            _print("granule = %d / %d" % (granule_position, absPos))
+        # the last one is the one we are interested in
+        return (granule_position / self.samplerate)
+
+mmpython.registertype( 'application/ogg', ('ogg',), mediainfo.TYPE_MUSIC, OggInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/webradioinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/webradioinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/webradioinfo.py	(revision 4)
@@ -0,0 +1,125 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: webradioinfo.py,v 1.7 2003/07/02 11:17:29 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: webradioinfo.py,v $
+# Revision 1.7  2003/07/02 11:17:29  the_krow
+# language is now part of the table key
+#
+# Revision 1.6  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/24 14:37:17  dischi
+# small fix
+#
+# Revision 1.4  2003/06/24 13:52:06  the_krow
+# 302 Handling is done by urllib so no further code for this is
+# needed. Thanks to den_RDC for setting up a server to test it.
+#
+# Revision 1.3  2003/06/24 13:06:46  the_krow
+# stream is being closed in fail-cases.
+#
+# Revision 1.2  2003/06/24 12:59:33  the_krow
+# Added Webradio.
+# Added Stream Type to mediainfo
+#
+# Revision 1.1  2003/06/23 22:23:16  the_krow
+# First Import. Not yet integrated.
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import urlparse
+import string
+import urllib
+
+from mmpython import mediainfo
+import mmpython
+
+_print = mediainfo._debug
+
+# http://205.188.209.193:80/stream/1006
+
+ICY_tags = { 'title': 'icy-name',
+             'genre': 'icy-genre',
+             'bitrate': 'icy-br',
+             'caption': 'icy-url',
+           }
+
+class WebRadioInfo(mediainfo.MusicInfo):
+    def __init__(self, url):
+        mediainfo.MusicInfo.__init__(self)
+        tup = urlparse.urlsplit(url)
+        scheme, location, path, query, fragment = tup
+        if scheme != 'http':
+            self.valid = 0
+            return
+        # Open an URL Connection
+        fi = urllib.urlopen(url)        
+
+        # grab the statusline
+        self.statusline = fi.readline()
+        try:
+            statuslist = string.split(self.statusline)
+        except ValueError:
+            # assume it is okay since so many servers are badly configured
+            statuslist = ["ICY", "200"]
+                    
+        if statuslist[1] != "200":
+            self.valid = 0
+            if fi:
+                fi.close()
+            return
+
+        self.valid = 1
+        self.type = 'audio'
+        self.subtype = 'mp3'
+        # grab any headers for a max of 10 lines
+        linecnt = 0
+        tab = {}
+        lines = fi.readlines(512)        
+        for linecnt in range(0,11):
+            icyline = lines[linecnt]
+            icyline = icyline.rstrip('\r\n')
+            if len(icyline) < 4:
+                break
+            cidx = icyline.find(':')
+            if cidx != -1:
+                # break on short line (ie. really should be a blank line)
+                # strip leading and trailing whitespace                
+                tab[icyline[:cidx].strip()] = icyline[cidx+2:].strip()
+        if fi:
+            fi.close()
+        self.appendtable('ICY', tab)
+        self.tag_map = { ('ICY', 'en') : ICY_tags }
+        # Copy Metadata from tables into the main set of attributes        
+        for k in self.tag_map.keys():
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),self.tag_map[k][x]), self.tag_map[k].keys())
+        self.bitrate = string.atoi(self.bitrate)*1000        
+
+mmpython.registertype( 'text/plain', mediainfo.EXTENSION_STREAM, mediainfo.TYPE_MUSIC, WebRadioInfo )
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/mp3info.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/mp3info.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/mp3info.py	(revision 4)
@@ -0,0 +1,532 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mp3info.py,v 1.12 2003/07/10 13:05:05 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: mp3info.py,v $
+# Revision 1.12  2003/07/10 13:05:05  the_krow
+# o id3v2 tabled added to eyed3
+# o type changed to MUSIC
+#
+# Revision 1.11  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.10  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.9  2003/06/09 22:59:37  the_krow
+# hopefully mp3 files are not detected everytime an mp3 stream is inside a
+# container any longer.
+#
+# Revision 1.8  2003/06/09 14:31:56  the_krow
+# fixes on the mpeg parser
+# resolutions, fps and bitrate should be reported correctly now
+#
+# Revision 1.7  2003/06/09 12:50:08  the_krow
+# mp3 now fills tables
+#
+# Revision 1.6  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.4  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.3  2003/06/07 23:10:50  the_krow
+# Changed mp3 into new format.
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Most of the code of this module was taken from Vivake Guptas mp3info
+# code. Below is his copyright notice. All credit to him.
+#
+# Copyright (c) 2002 Vivake Gupta (vivakeATomniscia.org).  All rights reserved.
+# This software is maintained by Vivake (vivakeATomniscia.org) and is available at:
+#     http://www.omniscia.org/~vivake/python/MP3Info.py
+#
+#
+
+
+import struct
+import string
+from mmpython import mediainfo
+import mmpython
+import re
+
+def _from_synch_safe(synchsafe):
+    if isinstance(synchsafe, type(1)):
+        (b3, b2, b1, b0) = struct.unpack('!4b', struct.pack('!1i', synchsafe))
+    else:
+        while len(synchsafe) < 4:
+            synchsafe = (0,) + synchsafe
+        (b3, b2, b1, b0) = synchsafe
+
+    x = 256
+    return (((b3 * x + b2) * x + b1) * x + b0)
+
+def _strip_zero(s):
+    start = 0
+    while start < len(s) and (s[start] == '\0' or s[start] == ' '):
+        start = start + 1
+
+    end = len(s) - 1
+    while end >= 0 and (s[end] == '\0' or s[end] == ' '):
+        end = end - 1
+
+    return s[start:end+1]
+
+class ID3v2Frame:
+    def __init__(self, file, version):
+        self.name = ""
+        self.version = 0
+        self.padding = 0
+        self.size = 0
+        self.data = ""
+
+        self.flags = {}
+        self.f_tag_alter_preservation = 0
+        self.f_file_alter_preservation = 0
+        self.f_read_only = 0
+        self.f_compression = 0
+        self.f_encryption = 0
+        self.f_grouping_identity = 0
+        self.f_unsynchronization = 0
+        self.f_data_length_indicator = 0
+
+        if version == 2:
+            nameSize = 3
+        else:
+            nameSize = 4
+        self.name = file.read(nameSize)
+
+        self.version = version
+
+        if self.name == nameSize * '\0':
+            self.padding = 1
+            return
+
+        if self.name[0] < 'A' or self.name[0] > 'Z':
+            self.padding = 1
+            return
+
+        size = ()
+        if version == 2:
+            size = struct.unpack('!3b', file.read(3))
+        elif version == 3 or version == 4:
+            size = struct.unpack('!4b', file.read(4))
+
+        if version == 3:  # abc00000 def00000
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_tag_alter_preservation  = flags >> 7 & 1 #a
+            self.f_file_alter_preservation = flags >> 6 & 1 #b
+            self.f_read_only               = flags >> 5 & 1 #c
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_compression             = flags >> 7 & 1 #d
+            self.f_encryption              = flags >> 6 & 1 #e
+            self.f_grouping_identity       = flags >> 5 & 1 #f
+        elif version == 4: # 0abc0000 0h00kmnp
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_tag_alter_preservation  = flags >> 6 & 1 #a
+            self.f_file_alter_preservation = flags >> 5 & 1 #b
+            self.f_read_only               = flags >> 4 & 1 #c
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_grouping_identity       = flags >> 6 & 1 #h
+            self.f_compression             = flags >> 3 & 1 #k
+            self.f_encryption              = flags >> 2 & 1 #m
+            self.f_unsynchronization       = flags >> 1 & 1 #n
+            self.f_data_length_indicator   = flags >> 0 & 1 #p
+        self.size = _from_synch_safe(size)
+        # An ugly hack to obmit crashing for large data
+        if self.size < 65536:
+            self.data = _strip_zero(file.read(self.size))
+
+_genres = [
+    "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
+    "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
+    "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
+    "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
+    "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
+    "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
+    "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
+    "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-industrial",
+    "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
+    "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
+    "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
+    "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
+    "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
+    "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin",
+    "Revival", "Celtic", "Bluegrass", "Avantegarde", "Gothic Rock",
+    "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
+    "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
+    "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
+    "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
+    "Folklore", "Ballad", "Power Ballad", "Rythmic Soul", "Freestyle", "Duet",
+    "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa",
+    "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop",
+    "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
+    "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue",
+    "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop",
+]
+
+class ID3v1:
+    def __init__(self, file):
+        self.valid = 0
+
+        self.tags = { }
+
+        try:
+            file.seek(-128, 2)
+        except IOError:
+            pass
+
+        data = file.read(128)
+        if data[0:3] != 'TAG':
+            return
+        else:
+            self.valid = 1
+
+        self.tags['TT2'] = _strip_zero(data[ 3: 33])
+        self.tags['TP1'] = _strip_zero(data[33: 63])
+        self.tags['TAL'] = _strip_zero(data[63: 93])
+        self.tags['TYE'] = _strip_zero(data[93: 97])
+        self.tags['COM'] = _strip_zero(data[97:125])
+
+        if data[125] == '\0':
+            self.tags['TRK'] = ord(data[126])
+
+        try:
+            self.tags['TCO'] = _genres[ord(data[127])]
+        except IndexError:
+            self.tags['TCO'] = "(%i)" % ord(data[127])
+
+
+class ID3v2:
+    def __init__(self, file):
+        self.valid = 0
+
+        self.tags = { }
+
+        self.header_size = 0
+
+        self.major_version = 0
+        self.minor_version = 0
+
+        self.f_unsynchronization = 0
+        self.f_extended_header = 0
+        self.f_experimental = 0
+        self.f_footer = 0
+
+        self.f_extended_header_zie = 0
+        self.f_extended_num_flag_bytes = 0
+
+        self.ef_update = 0
+        self.ef_crc = 0
+        self.ef_restrictions = 0
+
+        self.crc = 0
+        self.restrictions = 0
+
+        self.frames = []
+        self.tags = {}
+
+        file.seek(0, 0)
+        if file.read(3) != "ID3":
+            return
+        else:
+            self.valid = 1
+
+        (self.major_version, self.minor_version) = struct.unpack('!2b', file.read(2))
+
+        # abcd 0000
+        (flags,) = struct.unpack('!1b', file.read(1))
+        self.f_unsynchronization = flags >> 7 & 1 # a
+        self.f_extended_header   = flags >> 6 & 1 # b
+        self.f_experimental      = flags >> 5 & 1 # c
+        self.f_footer            = flags >> 4 & 1 # d
+
+        self.header_size = _from_synch_safe(struct.unpack('!4b', file.read(4)))
+
+        while 1:
+            if file.tell() >= self.header_size:
+                break
+            frame = ID3v2Frame(file, self.major_version)
+            if frame.padding:
+                file.seek(self.header_size)
+                break
+
+            self.frames.append(frame)
+            self.tags[frame.name] = frame.data
+
+_bitrates = [
+    [ # MPEG-2 & 2.5
+        [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,None], # Layer 1
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None], # Layer 2
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None]  # Layer 3
+    ],
+
+    [ # MPEG-1
+        [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,None], # Layer 1
+        [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,None], # Layer 2
+        [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,None]  # Layer 3
+    ]
+]
+
+_samplerates = [
+    [ 11025, 12000,  8000, None], # MPEG-2.5
+    [  None,  None,  None, None], # reserved
+    [ 22050, 24000, 16000, None], # MPEG-2
+    [ 44100, 48000, 32000, None], # MPEG-1
+]
+
+_modes = [ "stereo", "joint stereo", "dual channel", "mono" ]
+
+_mode_extensions = [
+    [ "4-31", "8-31", "12-31", "16-31" ],
+    [ "4-31", "8-31", "12-31", "16-31" ],
+    [     "",   "IS",    "MS", "IS+MS" ]
+]
+
+_emphases = [ "none", "50/15 ms", "reserved", "CCIT J.17" ]
+
+_MP3_HEADER_SEEK_LIMIT = 4096
+
+class MPEG:
+    def __init__(self, file):
+        self.valid = 0
+        s = file.read(4096)
+        if s[:3] == 'ID3':
+            self.valid = 1
+        if re.compile(r'0*\xFF\xFB\xB0\x04$').search(s):
+            self.valid = 1
+        if re.compile(r'0*\xFF\xFA\xB0\x04$').search(s):
+            self.valid = 1
+        file.seek(0, 2)
+        self.filesize = file.tell()        
+        file.seek(0, 0)
+
+        self.version = 0
+        self.layer = 0
+        self.protection = 0
+        self.bitrate = 0
+        self.samplerate = 0
+        self.padding = 0
+        self.private = 0
+        self.mode = ""
+        self.mode_extension = ""
+        self.copyright = 0
+        self.original = 0
+        self.emphasis = ""
+        self.length = 0
+
+        offset, header = self._find_header(file)
+        if offset == -1 or header is None:
+            return
+
+        self._parse_header(header)
+        ### offset + framelength will find another header. verify??
+        if not self.valid:
+            return
+
+        self._parse_xing(file)
+
+
+    def _find_header(self, file):
+        file.seek(0, 0)
+        amount_read = 0
+
+        # see if we get lucky with the first four bytes
+        amt = 4
+
+        while amount_read < _MP3_HEADER_SEEK_LIMIT:
+            header = file.read(amt)
+            if len(header) < amt:
+                # awfully short file. just give up.
+                return -1, None
+
+            amount_read = amount_read + len(header)
+
+            # on the next read, grab a lot more
+            amt = 500
+
+            # look for the sync byte
+            offset = string.find(header, chr(255))
+            if offset == -1:
+                continue
+            ### maybe verify more sync bits in next byte?
+
+            if offset + 4 > len(header):
+                more = file.read(4)
+                if len(more) < 4:
+                    # end of file. can't find a header
+                    return -1, None
+                amount_read = amount_read + 4
+                header = header + more
+            return amount_read - len(header) + offset, header[offset:offset+4]
+
+        # couldn't find the header
+        return -1, None
+
+    def _parse_header(self, header):
+        # AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
+        (bytes,) = struct.unpack('>i', header)
+        mpeg_version =    (bytes >> 19) & 3  # BB   00 = MPEG2.5, 01 = res, 10 = MPEG2, 11 = MPEG1
+        layer =           (bytes >> 17) & 3  # CC   00 = res, 01 = Layer 3, 10 = Layer 2, 11 = Layer 1
+        protection_bit =  (bytes >> 16) & 1  # D    0 = protected, 1 = not protected
+        bitrate =         (bytes >> 12) & 15 # EEEE 0000 = free, 1111 = bad
+        samplerate =      (bytes >> 10) & 3  # F    11 = res
+        padding_bit =     (bytes >> 9)  & 1  # G    0 = not padded, 1 = padded
+        private_bit =     (bytes >> 8)  & 1  # H
+        mode =            (bytes >> 6)  & 3  # II   00 = stereo, 01 = joint stereo, 10 = dual channel, 11 = mono
+        mode_extension =  (bytes >> 4)  & 3  # JJ
+        copyright =       (bytes >> 3)  & 1  # K    00 = not copyrighted, 01 = copyrighted
+        original =        (bytes >> 2)  & 1  # L    00 = copy, 01 = original
+        emphasis =        (bytes >> 0)  & 3  # MM   00 = none, 01 = 50/15 ms, 10 = res, 11 = CCIT J.17
+
+        if mpeg_version == 0:
+            self.version = 2.5
+        elif mpeg_version == 2:
+            self.version = 2
+        elif mpeg_version == 3:
+            self.version = 1
+        else:
+            return
+
+        if layer > 0:
+            self.layer = 4 - layer
+        else:
+            return
+
+        self.protection = protection_bit
+
+        self.bitrate = _bitrates[mpeg_version & 1][self.layer - 1][bitrate]
+        self.samplerate = _samplerates[mpeg_version][samplerate]
+
+        if self.bitrate is None or self.samplerate is None:
+            return
+
+        self.padding = padding_bit
+        self.private = private_bit
+        self.mode = _modes[mode]
+        self.mode_extension = _mode_extensions[self.layer - 1][mode_extension]
+        self.copyright = copyright
+        self.original = original
+        self.emphasis = _emphases[emphasis]
+
+        if self.layer == 1:
+            self.framelength = ((  12 * (self.bitrate * 1000.0)/self.samplerate) + padding_bit) * 4
+            self.samplesperframe = 384.0
+        else:
+            self.framelength =  ( 144 * (self.bitrate * 1000.0)/self.samplerate) + padding_bit
+            self.samplesperframe = 1152.0
+        self.length = int(round((self.filesize / self.framelength) * (self.samplesperframe / self.samplerate)))
+
+        self.valid = 1
+
+    def _parse_xing(self, file):
+        """Parse the Xing-specific header.
+
+        For variable-bitrate (VBR) MPEG files, Xing includes a header which
+        can be used to approximate the (average) bitrate and the duration
+        of the file.
+        """
+        file.seek(0, 0)
+        header = file.read(128)
+
+        i = string.find(header, 'Xing')
+        if i > 0:
+            (flags,) = struct.unpack('>i', header[i+4:i+8])
+            if flags & 3:
+                # flags says "frames" and "bytes" are present. use them.
+                (frames,bytes) = struct.unpack('>ii', header[i+8:i+16])
+
+                if self.samplerate:
+                    self.length = int(round(frames * self.samplesperframe / self.samplerate))
+                    self.bitrate = ((bytes * 8.0 / self.length) / 1000)
+
+class MP3Info(mediainfo.MusicInfo):
+    def __init__(self, file):
+        mediainfo.MusicInfo.__init__(self)
+        self.valid = 0
+        mpeg = MPEG(file)
+        if not mpeg.valid:
+            self.valid = 0
+            return
+        self.info = {}
+        self.samplerate = mpeg.samplerate
+        self.bitrate = mpeg.bitrate * 1000
+        self.length = mpeg.length
+        self.channels = mpeg.mode
+        if self.samplerate and self.channels and self.bitrate:
+            pass
+        else:
+            self.valid = 0
+            return
+        self.type = 'MPEG %1.f' % mpeg.version
+        self.subtype = 'Layer %d' % mpeg.layer
+        self.valid = 1
+        id3 = ID3v1(file)
+        if id3.valid:
+            self.appendtable('id3v1', id3.tags)
+
+        id3v2 = ID3v2(file)
+        if id3.valid:
+            id3 = id3v2
+            self.appendtable('id3v2', id3.tags)
+
+        if id3 is None:
+            return
+
+        # Set the info fields
+        for tag in id3.tags.keys():
+            if tag == 'TT2' or tag == 'TIT2':
+                self.title = id3.tags[tag]
+            elif tag == 'TP1' or tag == 'TPE1':
+                self.artist = id3.tags[tag]
+            elif tag == 'TRK' or tag == 'TRCK':
+                self.trackno = id3.tags[tag]
+            elif tag == 'TYE' or tag == 'TYER':
+                self.date = id3.tags[tag]
+            elif tag == 'COM' or tag == 'COMM':
+                self.comment = id3.tags[tag]
+            elif tag == 'TCM':
+                self.composer = id3.tags[tag]
+            elif tag == 'TAL' or tag == 'TALB':
+                self.album = id3.tags[tag]
+            elif tag == 'TPA':
+                self.disc = id3.tags[tag]
+            elif tag == 'TCO' or tag == 'TCON':
+                genre = self.genre = id3.tags[tag]
+                if genre and genre[0] == '(' and genre[-1] == ')':
+                    try:
+                        self.info['genre'] = _genres[int(genre[1:-1])]
+                    except IndexError:
+                        self.info['genre'] = ""
+            elif tag == 'TEN' or tag == 'TENC':
+                self.encoder = id3.tags[tag]
+
+
+mmpython.registertype( 'audio/mp3', ('mp3',), mediainfo.TYPE_MUSIC, MP3Info )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/pcminfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/pcminfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/pcminfo.py	(revision 4)
@@ -0,0 +1,81 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: pcminfo.py,v 1.8 2003/06/30 13:17:18 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: pcminfo.py,v $
+# Revision 1.8  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.7  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.6  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.4  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.3  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# -----------------------------------------------------------------------
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import sndhdr
+from mmpython import mediainfo
+import mmpython
+
+class PCMInfo(mediainfo.AudioInfo):
+    def _what(self,f):
+        """Recognize sound headers"""
+        h = f.read(512)
+        for tf in sndhdr.tests:
+            res = tf(h, f)
+            if res:
+                return res
+        return None
+
+    def __init__(self,file):
+       mediainfo.AudioInfo.__init__(self)
+       t = self._what(file)
+       if t:
+           (self.type, self.samplerate, self.channels, self.bitrate, self.samplebits) = t
+           self.mime = "audio/%s" % self.type
+           self.valid = 1
+       else:
+           self.valid = 0
+           return
+       
+
+mmpython.registertype( 'application/pcm', ('wav','aif','voc','au'), mediainfo.TYPE_AUDIO, PCMInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/m4ainfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/m4ainfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/m4ainfo.py	(revision 4)
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Based on a sample implementation posted to daap-dev mailing list by
+# Bob Ippolito <bob@redivi.com>
+#
+# Modifed by Aubin Paul <aubin@outlyer.org> for mmpython/Freevo
+#
+
+import struct
+from mmpython import mediainfo
+import mmpython
+
+#_print = mediainfo._debug
+
+class Mpeg4(mediainfo.MusicInfo):
+    def __init__(self, file):
+        self.containerTags = ('moov', 'udta', 'trak', 'mdia', 'minf', 'dinf', 'stbl',
+                              'meta', 'ilst', '----')
+        self.skipTags = {'meta':4 }
+
+        mediainfo.MusicInfo.__init__(self)
+        self.valid = 0
+        returnval = 0
+        while returnval == 0:
+            try:
+                self.readNextTag(file)
+            except ValueError:
+                returnval = 1
+        if mediainfo.DEBUG and self.valid:
+            print self.title
+            print self.artist
+            print self.album
+            print self.year
+            print self.encoder
+
+    def readNextTag(self, file):
+        length, name = self.readInt(file), self.read(4, file)
+        length -= 8
+        if length < 0 or length > 1000:
+            raise ValueError, "Oops?"
+        #print "%r" % str(name) # (%r bytes, starting at %r)" % \
+        #  (name, length, file.tell() + 8)
+        if name in self.containerTags:
+            self.read(self.skipTags.get(name, 0), file)
+            data = '[container tag]'
+        else:
+            data = self.read(length, file)
+        if name == '\xa9nam':
+            self.title = data[8:]
+            self.valid = 1
+        if name == '\xa9ART':
+            self.artist = data[8:]
+            self.valid = 1
+        if name == '\xa9alb':
+            self.album = data[8:]
+            self.valid = 1
+        if name == 'trkn':
+            # Fix this
+            self.trackno = data
+            self.valid = 1
+        if name == '\xa9day':
+            self.year = data[8:]
+            self.valid = 1
+        if name == '\xa9too':
+            self.encoder = data[8:]
+            self.valid = 1
+        return 0
+        
+    def read(self, b, file):
+        data = file.read(b)
+        if len(data) < b:
+            raise ValueError, "EOF"
+        return data
+
+    def readInt(self, file):
+        return struct.unpack('>I', self.read(4, file))[0]
+        
+mmpython.registertype( 'application/m4a', ('m4a',), mediainfo.TYPE_MUSIC, Mpeg4 )
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/id3.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/id3.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/id3.py	(revision 4)
@@ -0,0 +1,133 @@
+GENRE_LIST = {
+       0 : 'Blues',
+       1 : 'Classic Rock',
+       2 : 'Country',
+       3 : 'Dance',
+       4 : 'Disco',
+       5 : 'Funk',
+       6 : 'Grunge',
+       7 : 'Hip-Hop',
+       8 : 'Jazz',
+       9 : 'Metal',
+      10 : 'New Age',
+      11 : 'Oldies',
+      12 : 'Other',
+      13 : 'Pop',
+      14 : 'R&B',
+      15 : 'Rap',
+      16 : 'Reggae',
+      17 : 'Rock',
+      18 : 'Techno',
+      19 : 'Industrial',
+      20 : 'Alternative',
+      21 : 'Ska',
+      22 : 'Death Metal',
+      23 : 'Pranks',
+      24 : 'Soundtrack',
+      25 : 'Euro-Techno',
+      26 : 'Ambient',
+      27 : 'Trip-Hop',
+      28 : 'Vocal',
+      29 : 'Jazz+Funk',
+      30 : 'Fusion',
+      31 : 'Trance',
+      32 : 'Classical',
+      33 : 'Instrumental',
+      34 : 'Acid',
+      35 : 'House',
+      36 : 'Game',
+      37 : 'Sound Clip',
+      38 : 'Gospel',
+      39 : 'Noise',
+      40 : 'AlternRock',
+      41 : 'Bass',
+      42 : 'Soul',
+      43 : 'Punk',
+      44 : 'Space',
+      45 : 'Meditative',
+      46 : 'Instrumental Pop',
+      47 : 'Instrumental Rock',
+      48 : 'Ethnic',
+      49 : 'Gothic',
+      50 : 'Darkwave',
+      51 : 'Techno-Industrial',
+      52 : 'Electronic',
+      53 : 'Pop-Folk',
+      54 : 'Eurodance',
+      55 : 'Dream',
+      56 : 'Southern Rock',
+      57 : 'Comedy',
+      58 : 'Cult',
+      59 : 'Gangsta',
+      60 : 'Top 40',
+      61 : 'Christian Rap',
+      62 : 'Pop/Funk',
+      63 : 'Jungle',
+      64 : 'Native American',
+      65 : 'Cabaret',
+      66 : 'New Wave',
+      67 : 'Psychadelic',
+      68 : 'Rave',
+      69 : 'Showtunes',
+      70 : 'Trailer',
+      71 : 'Lo-Fi',
+      72 : 'Tribal',
+      73 : 'Acid Punk',
+      74 : 'Acid Jazz',
+      75 : 'Polka',
+      76 : 'Retro',
+      77 : 'Musical',
+      78 : 'Rock & Roll',
+      79 : 'Hard Rock',
+
+      
+    # The following genres are Winamp extensions
+
+      
+      80 : 'Folk',
+      81 : 'Folk-Rock',
+      82 : 'National Folk',
+      83 : 'Swing',
+      84 : 'Fast Fusion',
+      85 : 'Bebob',
+      86 : 'Latin',
+      87 : 'Revival',
+      88 : 'Celtic',
+      89 : 'Bluegrass',
+      90 : 'Avantgarde',
+      91 : 'Gothic Rock',
+      92 : 'Progressive Rock',
+      93 : 'Psychedelic Rock',
+      94 : 'Symphonic Rock',
+      95 : 'Slow Rock',
+      96 : 'Big Band',
+      97 : 'Chorus',
+      98 : 'Easy Listening',
+      99 : 'Acoustic',
+     100 : 'Humour',
+     101 : 'Speech',
+     102 : 'Chanson',
+     103 : 'Opera',
+     104 : 'Chamber Music',
+     105 : 'Sonata',
+     106 : 'Symphony',
+     107 : 'Booty Bass',
+     108 : 'Primus',
+     109 : 'Porn Groove',
+     110 : 'Satire',
+     111 : 'Slow Jam',
+     112 : 'Club',
+     113 : 'Tango',
+     114 : 'Samba',
+     115 : 'Folklore',
+     116 : 'Ballad',
+     117 : 'Power Ballad',
+     118 : 'Rhythmic Soul',
+     119 : 'Freestyle',
+     120 : 'Duet',
+     121 : 'Punk Rock',
+     122 : 'Drum Solo',
+     123 : 'A capella',
+     124 : 'Euro-House',
+     125 : 'Dance Hall'
+}
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/flacinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/flacinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/flacinfo.py	(revision 4)
@@ -0,0 +1,143 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: flacinfo.py,v 1.7 2003/10/05 21:06:24 outlyer Exp $
+# -----------------------------------------------------------------------
+# $Log: flacinfo.py,v $
+# Revision 1.7  2003/10/05 21:06:24  outlyer
+# Cram the VORBIS_COMMENT fields into our standard artist/album/etc. fields
+# so they work in Freevo.
+#
+# The only thing missing from having perfect FLAC support is a way to
+# calculate the song length.
+#
+# Revision 1.6  2003/10/05 20:45:09  outlyer
+# Fix some minor python issues. It works from mediatest.py now, but Freevo
+# isn't using the tag information yet. I don't know why.
+#
+# Revision 1.5  2003/09/22 16:21:20  the_krow
+# o ogg parsing should basically work
+# o utf-8 for vorbis comments
+#
+# Revision 1.4  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.3  2003/08/27 02:53:48  outlyer
+# Still doesn't do anything, but at least compiles now; problem is I don't
+# know how to conver the endian "headers" in to the types we expect, and I'm
+# hardly an expert on binary data.
+#
+# But I flushed out the header types from the FLAC documentation and
+# hopefully Thomas will know what to do...
+#
+# I can provide a FLAC file if necessary...
+#
+# Revision 1.2  2003/08/26 21:21:18  outlyer
+# Fix two more Python 2.3 warnings.
+#
+# Revision 1.1  2003/08/18 13:39:52  the_krow
+# Initial Import. Started on frame parsing.
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython.audio.ogginfo as ogginfo
+import mmpython
+import struct
+import re
+
+# See: http://flac.sourceforge.net/format.html
+
+
+class FlacInfo(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        if file.read(4) != 'fLaC':
+            self.valid = 0
+            return
+        self.valid = 1
+        while 1:
+            (blockheader,) = struct.unpack('>I',file.read(4))
+            lastblock = (blockheader >> 31) & 1
+            type = (blockheader >> 24) & 0x7F
+            numbytes = blockheader & 0xFFFFFF
+            if mmpython.mediainfo.DEBUG:
+                print "Last?: %d, NumBytes: %d, Type: %d" % (lastblock, numbytes, type)                                
+            # Read this blocks the data
+            data = file.read(numbytes)
+            if type == 0:
+                # STREAMINFO
+                bits = struct.unpack('>L', data[10:14])[0]
+                self.samplerate = (bits >> 12) & 0xFFFFF
+                self.channels = ((bits >> 9) & 7) + 1
+                self.samplebits = ((bits >> 4) & 0x1F) + 1
+                md5 = data[18:34]
+            elif type == 1:
+                # PADDING
+                pass            
+            elif type == 2:
+                # APPLICATION 
+                pass            
+            elif type == 3:
+                # SEEKTABLE 
+                pass            
+            elif type == 4:
+                # VORBIS_COMMENT                
+                skip, self.vendor = self._extractHeaderString(data)
+                num, = struct.unpack('<I', data[skip:skip+4])
+                start = skip+4
+                header = {}
+                for i in range(num):
+                    (nextlen, s) = self._extractHeaderString(data[start:])
+                    start += nextlen
+                    a = re.split('=',s)
+                    header[(a[0]).upper()]=a[1]
+                if header.has_key('TITLE'):
+                    self.title = header['TITLE']
+                if header.has_key('ALBUM'):
+                    self.album = header['ALBUM']
+                if header.has_key('ARTIST'):
+                    self.artist = header['ARTIST']            
+                if header.has_key('COMMENT'):
+                    self.comment = header['COMMENT']
+                if header.has_key('DATE'):
+                    self.date = header['DATE']
+                if header.has_key('ENCODER'):
+                    self.encoder = header['ENCODER']
+                if header.has_key('TRACKNUMBER'):
+                    self.trackno = header['TRACKNUMBER']
+ 
+                self.appendtable('VORBISCOMMENT', header)
+            elif type == 5:
+                # CUESHEET 
+                pass
+            else:
+                # UNKNOWN TYPE
+                pass
+            if lastblock:
+                break
+
+    def _extractHeaderString(self,header):
+        len = struct.unpack( '<I', header[:4] )[0]
+        return (len+4,unicode(header[4:4+len], 'utf-8'))
+
+                
+mmpython.registertype( 'application/flac', ('flac',), mediainfo.TYPE_MUSIC, FlacInfo )                
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/ac3info.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/ac3info.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/ac3info.py	(revision 4)
@@ -0,0 +1,128 @@
+from mmpython import mediainfo
+import mmpython
+
+import struct
+
+# http://www.atsc.org/standards/a_52a.pdf
+# fscod: Sample rate code, 2 bits
+#  00  48
+#  01  44.1
+#  10  32
+#  11  reserved
+
+FSCOD = [ 48000, 44100, 32000, 0 ]
+
+# bsmod: Bit stream mode, 3 bits
+# bsmod acmod Type of Service
+#  000  any main audio service: complete main (CM)
+#  001  any main audio service: music and effects (ME)
+#  010  any associated service: visually impaired (VI)
+#  011  any associated service: hearing impaired (HI)
+#  100  any associated service: dialogue (D)
+#  101  any associated service: commentary (C)
+#  110  any associated service: emergency (E)
+#  111  001 associated service: voice over (VO)
+#  111  010 - 111  main audio service: karaoke
+# 
+# acmod: Audio coding mode, 3 bits
+#  000  1+1 2 Ch1, Ch2
+#  001  1/0 1 C
+#  010  2/0 2 L, R
+#  011  3/0 3 L, C, R
+#  100  2/1 3 L, R, S
+#  101  3/1 4 L, C, R, S
+#  110  2/2 4 L, R, SL, SR
+#  111  3/2 5 L, C, R, SL, SR
+
+ACMOD = [ ( '1+1', 2, 'Ch1, Ch2' ),
+          ( '1/0', 1, 'C' ),
+          ( '2/0', 2, 'L, R' ),
+          ( '3/0', 3, 'L, C, R' ),
+          ( '2/1', 3, 'L, R, S' ),
+          ( '3/1', 4, 'L, C, R, S' ),
+          ( '2/2', 4, 'L, R, SL, SR' ),
+          ( '3/2', 5, 'L, C, R, SL, SR' ) ]
+            
+
+# dsurmod: Dolby surround mode, 2 bits
+#  00  not indicated
+#  01  Not Dolby Surround encoded
+#  10  Dolby Surround encoded
+#  11  reserved
+# 
+# lfeon: Low frequency effects channel on, 1 bit
+# This bit has a value of 1 if the lfe (sub woofer) channel is on, and a
+# value of 0 if the lfe channel is off.
+# 
+# frmsizcod:
+#  byte&0x3e = 0x00        \b, 32 kbit/s
+#  byte&0x3e = 0x02        \b, 40 kbit/s
+#  byte&0x3e = 0x04        \b, 48 kbit/s
+#  byte&0x3e = 0x06        \b, 56 kbit/s
+#  byte&0x3e = 0x08        \b, 64 kbit/s
+#  byte&0x3e = 0x0a        \b, 80 kbit/s
+#  byte&0x3e = 0x0c        \b, 96 kbit/s
+#  byte&0x3e = 0x0e        \b, 112 kbit/s
+#  byte&0x3e = 0x10        \b, 128 kbit/s
+#  byte&0x3e = 0x12        \b, 160 kbit/s
+#  byte&0x3e = 0x14        \b, 192 kbit/s
+#  byte&0x3e = 0x16        \b, 224 kbit/s
+#  byte&0x3e = 0x18        \b, 256 kbit/s
+#  byte&0x3e = 0x1a        \b, 320 kbit/s
+#  byte&0x3e = 0x1c        \b, 384 kbit/s
+#  byte&0x3e = 0x1e        \b, 448 kbit/s
+#  byte&0x3e = 0x20        \b, 512 kbit/s
+#  byte&0x3e = 0x22        \b, 576 kbit/s
+#  byte&0x3e = 0x24        \b, 640 kbit/s
+
+FRMSIZCOD = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192,
+              224, 256, 320, 384, 448, 512, 576, 640 ]
+
+class AC3Info(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        if file.name.endswith('.ac3'):
+            # when the ending is ac3, force the detection. It may not be necessary
+            # the the header is at the beginning but in the first 2000 bytes
+            check_length = 1000
+        else:
+            check_length = 1
+        for i in range(check_length):
+            if file.read(2) == '\x0b\x77':
+                break
+        else:
+            self.valid = False
+            return
+
+        info = struct.unpack('<HBBBB',file.read(6))
+        self.samplerate = FSCOD[info[1] >> 6]
+        self.bitrate = FRMSIZCOD[(info[1] & 0x3F) >> 1] * 1000
+        bsmod = info[2] & 0x7
+        channels = ACMOD[info[3] >> 5]
+        acmod = info[3] >> 5
+        self.channels = ACMOD[acmod][1]
+        bits = 0
+        if acmod & 0x01 and not acmod == 0x01:
+            bits += 2
+        if acmod & 0x04:
+            bits += 2
+        if acmod == 0x02:
+            bits += 2
+
+        # info is now 5 bits of info[3] and all bits of info[4] ( == 13 bits)
+        # 'bits' bits (0-6) bits are information we don't need, after that,
+        # the bit we need is lfeon.
+        info = (((info[3] & 0x1F) << 8) + info[4])
+
+        # now we create the mask we need (based on 'bits')
+        # the bit number 13 - 'bits' is what we want to read
+        for i in range(13 - bits - 1):
+            info = info >> 1
+        if info & 1:
+            # subwover
+            self.channels += 1
+        self.valid = True
+        self.codec = 'AC3'
+        self.mime = 'audio/ac3'
+        
+mmpython.registertype( 'audio/ac3', ('ac3',), mediainfo.TYPE_MUSIC, AC3Info )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/binfuncs.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/binfuncs.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/binfuncs.py	(revision 4)
@@ -0,0 +1,123 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#  Copyright (C) 2001  Ryan Finne <ryan@finnie.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+
+# Accepts a string of bytes (chars) and returns an array of bits
+# representing the bytes in big endian byte (Most significant byte/bit first)
+# order.  Each byte can have it's higher bits ignored by passing an sz arg.
+def bytes2bin(bytes, sz = 8):
+   if sz < 1 or sz > 8:
+      raise ValueError("Invalid sz value: " + str(sz));
+
+   retVal = [];
+   for b in bytes:
+      bits = [];
+      b = ord(b);
+      while b > 0:
+         bits.append(b & 1);
+         b >>= 1;
+
+      if len(bits) < sz:
+         bits.extend([0] * (sz - len(bits)));
+      elif len(bits) > sz:
+         bits = bits[:sz];
+
+      # Big endian byte order.
+      bits.reverse();
+      retVal.extend(bits);
+
+   if len(retVal) == 0:
+      retVal = [0];
+   return retVal;
+
+# Convert am array of bits (MSB first) into a string of characters.
+def bin2bytes(x):
+   bits = [];
+   bits.extend(x);
+   bits.reverse();
+
+   i = 0;
+   out = '';
+   multi = 1;
+   ttl = 0;
+   for b in bits:
+      i += 1;
+      ttl += b * multi;
+      multi *= 2;
+      if i == 8:
+         i = 0;
+         out += chr(ttl);
+         multi = 1;
+         ttl = 0;
+
+   if multi > 1:
+      out += chr(ttl);
+
+   out = list(out);
+   out.reverse();
+   out = ''.join(out);
+   return out;
+
+# Convert and array of "bits" (MSB first) to it's decimal value.
+def bin2dec(x):
+   bits = [];
+   bits.extend(x);
+   bits.reverse();
+
+   multi = 1;
+   value = 0;
+   for b in bits:
+      value += b * multi;
+      multi *= 2;
+   return value;
+
+# Convert a decimal value to an array of bits (MSB first), optionally
+# padding the overall size to p bits.
+def dec2bin(n, p = 0):
+   retVal = [];
+
+   while n > 0:
+      retVal.append(n & 1);
+      n >>= 1;
+
+   if p > 0:
+      retVal.extend([0] * (p - len(retVal)));
+   retVal.reverse();
+   return retVal;
+
+# Convert a list of bits (MSB first) to a synch safe list of bits (section 6.2
+# of the ID3 2.4 spec).
+def bin2synchsafe(x):
+   if len(x) > 32 or bin2dec(x) > 268435456:   # 2^28
+      raise ValueError("Invalid value");
+   elif len(x) < 8:
+      return x;
+
+   n = bin2dec(x);
+   bites = "";
+   bites += chr((n >> 21) & 0x7f);
+   bites += chr((n >> 14) & 0x7f);
+   bites += chr((n >>  7) & 0x7f);
+   bites += chr((n >>  0) & 0x7f);
+   bits = bytes2bin(bites);
+   if len(bits) < 32:
+      bits = ([0] * (32 - len(x))) + bits;
+
+   return bits;
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/tag.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/tag.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/tag.py	(revision 4)
@@ -0,0 +1,1638 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+import re, os, string, stat, shutil, tempfile, binascii;
+import mimetypes;
+from stat import *;
+from mmpython.audio.eyeD3 import *;
+
+import utils as utils
+import mp3 as eyeD3_mp3
+
+from frames import *;
+from binfuncs import *;
+
+
+ID3_V1_COMMENT_DESC = "ID3 v1 Comment";
+
+################################################################################
+class TagException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class TagHeader:
+   SIZE = 10;
+
+   version = None;
+   majorVersion = None;
+   minorVersion = None;
+   revVersion = None;
+
+   # Flag bits
+   unsync = 0;
+   extended = 0;
+   experimental = 0;
+   # v2.4 addition
+   footer = 0;
+
+   # The size in the most recently parsed header.
+   tagSize = 0;
+   
+   # Constructor
+   def __init__(self):
+      self.clear();
+
+   def clear(self):
+      self.setVersion(None);
+      self.unsync = 0;
+      self.extended = 0;
+      self.experimental = 0;
+      self.tagSize = 0;
+
+   def setVersion(self, v):
+      if v == None:
+         self.version = None;
+         self.majorVersion = None;
+         self.minorVersion = None;
+         self.revVersion = None;
+         return;
+
+      if v == ID3_CURRENT_VERSION:
+         if self.majorVersion == None or self.minorVersion == None:
+            v = ID3_DEFAULT_VERSION;
+         else:
+            return;
+      elif v == ID3_ANY_VERSION:
+         v = ID3_DEFAULT_VERSION;
+
+      # Handle 3-element lists or tuples.
+      if isinstance(v, tuple) or isinstance(v, list):
+         self.version = utils.versionsToConstant(v);
+         (self.majorVersion,
+          self.minorVersion,
+          self.revVersion) = v;
+      # Handle int constants.
+      elif isinstance(v, int):
+         (self.majorVersion,
+          self.minorVersion,
+          self.revVersion) = utils.constantToVersions(v);
+         self.version = v;
+      else:
+         raise TypeError("Wrong type: %s" % str(type(v)));
+
+   # Given a file handle this method attempts to identify and then parse
+   # a ID3 v2 header.  If successful, the parsed values are stored in
+   # the instance variable.  If the files does not contain an ID3v2 tag
+   # false is returned. A TagException is thrown if a tag is found, but is
+   # not valid or corrupt.
+   def parse(self, f):
+      self.clear();
+
+      # The first three bytes of a v2 header is "ID3".
+      if f.read(3) != "ID3":
+         return 0;
+      TRACE_MSG("Located ID3 v2 tag");
+
+      # The next 2 bytes are the minor and revision versions.
+      version = f.read(2);
+      major = 2;
+      minor = ord(version[0]);
+      rev = ord(version[1]);
+      TRACE_MSG("TagHeader [major]: " + str(major));
+      TRACE_MSG("TagHeader [minor]: " + str(minor));
+      TRACE_MSG("TagHeader [revis]: " + str(rev));
+      if not (major == 2 and (minor == 3 or minor == 4)):
+         raise TagException("ID3 v" + str(major) + "." + str(minor) +\
+                            " is not supported.");
+      # Get all the version madness in sync.
+      self.setVersion([major, minor, rev]);
+
+      # The first 4 bits of the next byte are flags.
+      (self.unsync,
+       self.extended,
+       self.experimental,
+       self.footer) = bytes2bin(f.read(1))[0:4];
+      TRACE_MSG("TagHeader [flags]: unsync(%d) extended(%d) "\
+                "experimental(%d) footer(%d)" % (self.unsync, self.extended,
+                                                 self.experimental,
+                                                 self.footer));
+
+      # The size of the optional extended header, frames, and padding
+      # afer unsynchronization.  This is a sync safe integer, so only the
+      # bottom 7 bits of each byte are used.
+      tagSizeStr = f.read(4);
+      TRACE_MSG("TagHeader [size string]: 0x%02x%02x%02x%02x" %\
+                (ord(tagSizeStr[0]), ord(tagSizeStr[1]),
+                 ord(tagSizeStr[2]), ord(tagSizeStr[3])));
+      self.tagSize = bin2dec(bytes2bin(tagSizeStr, 7));
+      TRACE_MSG("TagHeader [size]: %d (0x%x)" % (self.tagSize, self.tagSize));
+
+      return 1;
+
+   def render(self, tagLen = None):
+      if tagLen != None:
+         self.tagSize = tagLen;
+
+      data = "ID3";
+      data += chr(self.minorVersion) + chr(self.revVersion);
+      # not not the values so we only get 1's and 0's.
+      data += bin2bytes([not not self.unsync,
+                         not not self.extended,
+                         not not self.experimental,
+                         not not self.footer,
+                         0, 0, 0, 0]);
+      TRACE_MSG("Setting tag size to %d" % tagLen);
+      szBytes = bin2bytes(bin2synchsafe(dec2bin(tagLen, 32)));
+      data += szBytes;
+      TRACE_MSG("TagHeader Rendered");
+      return data;
+
+################################################################################
+class ExtendedTagHeader:
+   size = 0;
+   flags = 0;
+   crc = 0;
+   restrictions = 0;
+
+   def isUpdate(self):
+      return self.flags & 0x40;
+   def hasCRC(self):
+      return self.flags & 0x20;
+   def hasRestrictions(self):
+      return self.flags & 0x10;
+
+   def setSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = (v << 6) | (self.restrictions & 0x3f);
+   def getSizeRestrictions(self):
+      return self.restrictions >> 6;
+   def getSizeRestrictionsString(self):
+      val = self.getSizeRestrictions();
+      if val == 0x00:
+         return "No more than 128 frames and 1 MB total tag size.";
+      elif val == 0x01:
+         return "No more than 64 frames and 128 KB total tag size.";
+      elif val == 0x02:
+         return "No more than 32 frames and 40 KB total tag size.";
+      elif val == 0x03:
+         return "No more than 32 frames and 4 KB total tag size.";
+
+   def setTextEncodingRestrictions(self, v):
+      assert(v == 0 or v == 1);
+      self.restrictions ^= 0x20;
+   def getTextEncodingRestrictions(self):
+      return self.restrictions & 0x20;
+   def getTextEncodingRestrictionsString(self):
+      if self.getTextEncodingRestrictions():
+         return "Strings are only encoded with ISO-8859-1 [ISO-8859-1] or "\
+                "UTF-8 [UTF-8].";
+      else:
+         return "None";
+
+   def setTextFieldSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = (v << 3) | (self.restrictions & 0xe7);
+   def getTextFieldSizeRestrictions(self):
+      return (self.restrictions >> 3) & 0x03;
+   def getTextFieldSizeRestrictionsString(self):
+      val = self.getTextFieldSizeRestrictions();
+      if val == 0x00:
+         return "None";
+      elif val == 0x01:
+         return "No string is longer than 1024 characters.";
+      elif val == 0x02:
+         return "No string is longer than 128 characters.";
+      elif val == 0x03:
+         return "No string is longer than 30 characters.";
+
+   def setImageEncodingRestrictions(self, v):
+      assert(v == 0 or v == 1);
+      self.restrictions ^= 0x04;
+   def getImageEncodingRestrictions(self):
+      return self.restrictions & 0x04;
+   def getImageEncodingRestrictionsString(self):
+      if self.getImageEncodingRestrictions():
+         return "Images are encoded only with PNG [PNG] or JPEG [JFIF].";
+      else:
+         return "None";
+
+   def setImageSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = v | (self.restrictions & 0xfc);
+   def getImageSizeRestrictions(self):
+      return self.restrictions & 0x03;
+   def getImageSizeRestrictionsString(self):
+      val = self.getImageSizeRestrictions();
+      if val == 0x00:
+         return "None";
+      elif val == 0x01:
+         return "All images are 256x256 pixels or smaller.";
+      elif val == 0x02:
+         return "All images are 64x64 pixels or smaller.";
+      elif val == 0x03:
+         return "All images are exactly 64x64 pixels, unless required "\
+                "otherwise.";
+
+   def render(self, header, frameData, padding = 0):
+      assert(header.majorVersion == 2);
+
+      data = "";
+      if header.minorVersion == 4:
+         # Version 2.4
+         crc = None;
+         size = 6;
+         # Extended flags.
+         if self.isUpdate():
+            data = "\x00";
+         if self.hasCRC():
+            data += "\x05";
+            self.crc = binascii.crc32(data);
+            data += bin2bytes(dec2bin(self.crc, 40));
+         if self.hasRestrictions():
+            data += "\x01";
+            assert(len(self.restrictions) == 1);
+            data += self.restrictions;
+
+         # Extended header size.
+         size = bin2bytes(bin2synchsafe(dec2bin(len(data) + 6, 32)))
+         assert(len(size) == 4);
+
+         assert(len(self.flags) == 2);
+         data = size + "\x01" + self.flags + data;
+      else:
+         # Version 2.3
+         crc = None;
+         size = 6;
+         # Extended flags.
+         f = [0] * 16;
+         if self.hasCRC():
+            f[0] = 1;
+            self.crc = binascii.crc32(data);
+            crc = bin2bytes(dec2bin(self.crc));
+            assert(len(crc) == 4);
+            size += 4;
+         flags = bin2bytes(f);
+         assert(len(flags) == 2);
+         # Extended header size.
+         size = bin2bytes(dec2bin(size, 32))
+         assert(len(size) == 4);
+         # Padding size
+         paddingSize = bin2bytes(dec2bin(padding, 32));
+
+         data = size + flags + paddingSize;
+         if crc:
+            data += crc;
+      return data; 
+
+   # Only call this when you *know* there is an extened header.
+   def parse(self, fp, header):
+      assert(header.majorVersion == 2);
+
+      # First 4 bytes is the size of the extended header.
+      data = fp.read(4);
+      if header.minorVersion == 4:
+         TRACE_MSG("Parsing extended header for v2.4");
+         # sync-safe
+         sz = bin2dec(bytes2bin(data, 7));
+         TRACE_MSG("Extended header size: %d" % (sz - 4));
+         data = fp.read(sz - 4);
+
+         if ord(data[0]) != 1 or (ord(data[1]) & 0x8f):
+            # As of 2.4 the first byte is 1 and the second can only have
+            # bits 6, 5, and 4 set.
+            raise TagException("Invalid Extended Header");
+
+         offset = 2;
+         self.flags = ord(data[1]);
+         TRACE_MSG("Extended header flags: %x" % self.flags);
+
+         if self.isUpdate():
+            TRACE_MSG("Extended header has update bit set");
+            assert(ord(data[offset]) == 0);
+            offset += 1;
+         if self.hasCRC():
+            TRACE_MSG("Extended header has CRC bit set");
+            assert(ord(data[offset]) == 5);
+            offset += 1;
+            crcData = data[offset:offset + 5];
+            # This is sync-safe.
+            self.crc = bin2dec(bytes2bin(crcData, 7));
+            TRACE_MSG("Extended header CRC: %d" % self.crc);
+            offset += 5;
+         if self.hasRestrictions():
+            TRACE_MSG("Extended header has restrictions bit set");
+            assert(ord(data[offset]) == 5);
+            offset += 1;
+            self.restrictions = ord(data[offset]);
+            offset += 1;
+      else:
+         TRACE_MSG("Parsing extended header for v2.3");
+         # v2.3 is totally different... *sigh*
+         sz = bin2dec(bytes2bin(data));
+         TRACE_MSG("Extended header size: %d" % sz);
+         data = fp.read(sz);
+         tmpFlags = fp.read(2);
+         # Make this look like a v2.4 mask.
+         self.flags = ord(tmpFlags[0]) >> 2;
+         if self.hasCRC():
+            TRACE_MSG("Extended header has CRC bit set");
+            crcData = fp.read(4);
+            self.crc = bin2dec(bytes2bin(crcData));
+            TRACE_MSG("Extended header CRC: %d" % self.crc);
+         # Read the padding size, but it'll be computed during the parse.
+         fp.read(4);
+
+
+################################################################################
+# ID3 tag class.  The class is capable of reading v1 and v2 tags.  ID3 v1.x
+# are converted to v2 frames.
+class Tag:
+   # Latin1 is the default (0x00)
+   encoding = DEFAULT_ENCODING;
+
+   # ID3v1 tags do not contain a header.  The only ID3v1 values stored
+   # in this header are the major/minor version.
+   header = TagHeader();
+
+   # Optional in v2 tags.
+   extendedHeader = ExtendedTagHeader();
+
+   # Contains the tag's frames.  ID3v1 fields are read and converted
+   # the the corresponding v2 frame.  
+   frames = None;
+
+   # Used internally for iterating over frames.
+   iterIndex = None;
+
+   # If this value is None the tag is not linked to any particular file..
+   linkedFile = None;
+
+   # Constructor.  An empty tag is created and the link method is used
+   # to read an mp3 file's v1.x or v2.x tag.  You can optionally set a 
+   # file name, but it will not be read, but may be written to.
+   def __init__(self, fileName = None):
+      if fileName:
+         self.linkedFile = LinkedFile(fileName);
+      self.clear();
+
+   def clear(self):
+      self.header = TagHeader();
+      self.frames = FrameSet(self.header);
+      self.iterIndex = None;
+      linkedFile = None;
+
+   # Returns an read-only iterator for all frames.
+   def __iter__(self):
+      if len(self.frames):
+         self.iterIndex = 0;
+      else:
+         self.iterIndex = None;
+      return self;
+
+   def next(self):
+      if self.iterIndex == None or self.iterIndex == len(self.frames):
+         raise StopIteration;
+      frm = self.frames[self.iterIndex];
+      self.iterIndex += 1;
+      return frm;
+
+   # Returns true when an ID3 tag is read from f which may be a file name
+   # or an aleady opened file object.  In the latter case, the file object 
+   # is not closed when this method returns.
+   #
+   # By default, both ID3 v2 and v1 tags are parsed in that order.
+   # If a v2 tag is found then a v1 parse is not performed.  This behavior
+   # can be refined by passing ID3_V1 or ID3_V2 as the second argument 
+   # instead of the default ID3_ANY_VERSION.
+   #
+   # Converts all ID3v1 data into ID3v2 frames internally.
+   # May throw IOError, or TagException if parsing fails.
+   def link(self, f, v = ID3_ANY_VERSION):
+      self.clear();
+
+      fileName = "";
+      if isinstance(f, file):
+         fileName = f.name;
+      elif isinstance(f, str):
+         fileName = f;
+      else:
+         raise TagException("Invalid type passed to Tag.link: " + 
+                            str(type(f)));
+
+      if v != ID3_V1 and v != ID3_V2 and v != ID3_ANY_VERSION:
+         raise TagException("Invalid version: " + hex(v));
+
+      tagFound = 0;
+      padding = 0;
+      TRACE_MSG("Linking File: " + fileName);
+      if v == ID3_V1:
+         if self.__loadV1Tag(f):
+            tagFound = 1;
+      elif v == ID3_V2:
+         padding = self.__loadV2Tag(f);
+         if padding >= 0:
+            tagFound = 1;
+      elif v == ID3_ANY_VERSION:
+         padding = self.__loadV2Tag(f);
+         if padding >= 0:
+            tagFound = 1;
+         else:
+            padding = 0;
+            if self.__loadV1Tag(f):
+               tagFound = 1;
+
+      self.linkedFile = LinkedFile(fileName);
+      if tagFound:
+         # In the case of a v1.x tag this is zero.
+         self.linkedFile.tagSize = self.header.tagSize;
+         self.linkedFile.tagPadding = padding;
+         return 1;
+      else:
+         self.linkedFile.tagSize = 0;
+         self.linkedFile.tagPadding = 0;
+         return 0;
+
+   # Write the current tag state to the linked file.
+   # The version of the ID3 file format that should be written can
+   # be passed as an argument; the default is ID3_CURRENT_VERSION.
+   def update(self, version = ID3_CURRENT_VERSION, backup = 0):
+      if not self.linkedFile:
+         raise TagException("The Tag is not linked to a file.");
+
+      if backup:
+         shutil.copyfile(self.linkedFile.name, self.linkedFile.name + ".orig");
+
+      self.setVersion(version);
+      version = self.getVersion();
+      # If v1.0 is being for explicitly then so be it, if not and there is
+      # a track number then bumping to v1.1 is /probably/ best.
+      if self.header.majorVersion == 1 and self.header.minorVersion == 0 and\
+         self.getTrackNum()[0] != None and version != ID3_V1_0:
+         version = ID3_V1_1;
+         self.setVersion(version);
+      
+      # If there are no frames then simply remove the current tag.
+      if len(self.frames) == 0:
+         self.remove(version);
+         self.header = TagHeader();
+         self.frames.setTagHeader(self.header);
+         self.linkedFile.tagPadding = 0;
+         self.linkedFile.tagSize = 0;
+         return;
+
+      if version & ID3_V1:
+         self.__saveV1Tag(version);
+         return 1;
+      elif version & ID3_V2:
+         self.__saveV2Tag(version);
+         return 1;
+      else:
+         raise TagException("Invalid version: %s" % hex(version));
+      return 0;
+
+   # Remove the tag.  The version argument can selectively remove specific
+   # ID3 tag versions; the default is ID3_CURRENT_VERSION meaning the version
+   # of the current tag.  A value of ID3_ANY_VERSION causes all tags to be
+   # removed.
+   def remove(self, version = ID3_CURRENT_VERSION):
+      if not self.linkedFile:
+         raise TagException("The Tag is not linked to a file; nothing to "\
+                            "remove.");
+
+      if version == ID3_CURRENT_VERSION:
+         version = self.getVersion();
+
+      retval = 0;   
+      if version & ID3_V1 or version == ID3_ANY_VERSION:
+         tagFile = file(self.linkedFile.name, "r+b");
+         tagFile.seek(-128, 2);
+         if tagFile.read(3) == "TAG":
+            TRACE_MSG("Removing ID3 v1.x Tag");
+            tagFile.seek(-3, 1);
+            tagFile.truncate();
+            retval |= 1;
+         tagFile.close();
+
+      if ((version & ID3_V2) or (version == ID3_ANY_VERSION)) and\
+          self.header.tagSize:
+         tagFile = file(self.linkedFile.name, "r+b");
+         if tagFile.read(3) == "ID3":
+            TRACE_MSG("Removing ID3 v2.x Tag");
+            tagSize = self.header.tagSize + self.header.SIZE;
+            tagFile.seek(tagSize);
+            data = tagFile.read();
+            tagFile.seek(0);
+            tagFile.write(data);
+            tagFile.truncate();
+            tagFile.close();
+            retval |= 1;
+
+      return retval;
+
+
+
+   # Get artist.  There are a few frames that can contain this information,
+   # and they are subtley different. 
+   #   eyeD3.frames.ARTIST_FID - Lead performer(s)/Soloist(s)
+   #   eyeD3.frames.BAND_FID - Band/orchestra/accompaniment
+   #   eyeD3.frames.CONDUCTOR_FID - Conductor/performer refinement
+   #   eyeD3.frames.REMIXER_FID - Interpreted, remixed, or otherwise modified by
+   #
+   # Any of these values can be passed as an argument to select the artist
+   # of interest.  By default, the first one found (searched in the above order)
+   # is the value returned.  Most tags only have the ARTIST_FID, btw.
+   # 
+   # When no artist is found, an empty string is returned.
+   # 
+   def getArtist(self, artistID = ARTIST_FIDS):
+      if isinstance(artistID, list):
+         frameIDs = artistID;
+      else:
+         frameIDs = [artistID];
+
+      for fid in frameIDs:
+         f = self.frames[fid];
+         if f:
+            return f[0].text;
+      return ""; 
+ 
+   def getAlbum(self):
+      f = self.frames[ALBUM_FID];
+      if f:
+         return f[0].text;
+      else:
+         return "";
+
+   # Get the track title.  By default the main title is returned.  Optionally,
+   # you can pass:
+   #   eyeD3.frames.TITLE_FID - The title; the default.
+   #   eyeD3.frames.SUBTITLE_FID - The subtitle.
+   #   eyeD3.frames.CONTENT_TITLE_FID - Conten group description???? Rare.
+   # An empty string is returned when no title exists.
+   def getTitle(self, titleID = TITLE_FID):
+      f = self.frames[titleID];
+      if f:
+         return f[0].text;
+      else:
+         return "";
+
+   def getDate(self, fid = None):
+       if not fid:
+           for fid in ["TDRL", "TDOR", "TDRC",
+                       OBSOLETE_YEAR_FID, OBSOLETE_DATE_FID]:
+               if self.frames[fid]:
+                   return self.frames[fid];
+           return None;
+       return self.frames[fid];
+
+   def getYear(self, fid = None):
+       dateFrame = self.getDate(fid);
+       if dateFrame:
+           return dateFrame[0].getYear();
+       else:
+           return None;
+            
+   # Throws GenreException when the tag contains an unrecognized genre format.
+   # Note this method returns a eyeD3.Genre object, not a raw string.
+   def getGenre(self):
+      f = self.frames[GENRE_FID];
+      if f and f[0].text:
+         g = Genre();
+         g.parse(f[0].text);
+         return g;
+      else:
+         return None;
+
+   # Returns a tuple with the first value containing the track number and the
+   # second the total number of tracks.  One or both of these values may be
+   # None depending on what is available in the tag. 
+   def getTrackNum(self):
+      f = self.frames[TRACKNUM_FID];
+      if f:
+         n = string.split(f[0].text, '/');
+         tn = self.toInt(n[0]);
+         tt = None;
+         if len(n) == 2:
+            tt = self.toInt(n[1]);
+         if tn != None and tt != None:
+            return (tn, tt);
+         elif tn != None:
+            return (tn, None);
+      return (None, None);
+
+   # Since multiple comment frames are allowed this returns a list with 0
+   # or more elements.  The elements are not the comment strings, they are
+   # eyeD3.frames.CommentFrame objects.
+   def getComments(self):
+      return self.frames[COMMENT_FID];
+
+   # Returns a list (possibly empty) of eyeD3.frames.ImageFrame objects.
+   def getImages(self):
+      return self.frames[IMAGE_FID];
+
+   # Returns a list (possibly empty) of eyeD3.frames.URLFrame objects.
+   # Both URLFrame and UserURLFrame objects are returned.  UserURLFrames
+   # add a description and encoding, and have a different frame ID.
+   def getURLs(self):
+      urls = list();
+      for fid in URL_FIDS:
+         urls.extend(self.frames[fid]);
+      urls.extend(self.frames[USERURL_FID]);
+      return urls;
+
+   def getUserTextFrames(self):
+      return self.frames[USERTEXT_FID];
+
+   def getCDID(self):
+      return self.frames[CDID_FID];
+
+   def getVersion(self):
+      return self.header.version;
+
+   def getVersionStr(self):
+      return versionToString(self.header.version);
+
+   # Set the artist name.  Arguments equal to None or "" cause the frame to
+   # be removed. An optional second argument can be passed to select the
+   # actual artist frame that should be set.  By default, the main artist frame
+   # (TPE1) is the value used.
+   def setArtist(self, a, id = ARTIST_FID):
+       self.setTextFrame(id, a);
+
+   def setAlbum(self, a):
+       self.setTextFrame(ALBUM_FID, a);
+
+   def setTitle(self, t, titleID = TITLE_FID):
+       self.setTextFrame(titleID, t);
+
+   def setDate(self, year, month = None, dayOfMonth = None,
+               hour = None, minute = None, second = None, fid = None):
+      if not year and not fid:
+          dateFrame = self.getDate;
+          self.frames.removeFramesByID(dateFrame.id);
+          return;
+      elif not year:
+          self.frames.removeFramesByID(fid);
+
+      dateStr = str(year);
+      if len(dateStr) != 4:
+         raise TagException("Invalid Year field: " + dateStr);
+      if month:
+         dateStr += "-" + self.__padDateField(month);
+         if dayOfMonth:
+            dateStr += "-" + self.__padDateField(dayOfMonth);
+            if hour:
+               dateStr += "T" + self.__padDateField(hour);
+               if minute:
+                  dateStr += ":" + self.__padDateField(minute);
+                  if second:
+                     dateStr += ":" + self.__padDateField(second);
+
+      if not fid:
+          fid = "TDRL";
+      dateFrame = self.frames[fid];
+      try:
+         if dateFrame:
+            dateFrame[0].setDate(self.encoding + dateStr);
+         else:
+            header = FrameHeader(self.header);
+            header.id = fid;
+            dateFrame = DateFrame(self.encoding + dateStr, header);
+            self.frames.addFrame(dateFrame);
+      except FrameException, ex:
+         raise TagException(str(ex));
+
+   # Three types are accepted for the genre parameter.  A Genre object, an
+   # acceptable (see Genre.parse) genre string, or an integer genre id.
+   # Arguments equal to None or "" cause the frame to be removed.
+   def setGenre(self, g):
+      if g == None or g == "":
+         self.frames.removeFramesByID(GENRE_FID);
+         return;
+
+      if isinstance(g, Genre):
+         self.frames.setTextFrame(GENRE_FID, str(g), self.encoding);
+      elif isinstance(g, str):
+         gObj = Genre();
+         gObj.parse(g);
+         self.frames.setTextFrame(GENRE_FID, str(gObj), self.encoding);
+      elif isinstance(g, int):
+         gObj = Genre();
+         gObj.id = g;
+         self.frames.setTextFrame(GENRE_FID, str(gObj), self.encoding);
+      else:
+         raise TagException("Invalid type passed to setGenre: %s" +
+                            str(type(g)));
+
+   # Accepts a tuple with the first value containing the track number and the
+   # second the total number of tracks.  One or both of these values may be
+   # None.  If both values are None, the frame is removed.
+   def setTrackNum(self, n):
+      if n[0] == None and n[1] == None:
+         self.frames.removeFramesByID(TRACKNUM_FID);
+         return;
+
+      totalStr = "";
+      zPadding = 1;
+      if n[1] != None:
+         if n[1] >= 0 and n[1] <= 9:
+            totalStr = "0" + str(n[1]);
+         else:
+            totalStr = str(n[1]);
+         zPadding = len(totalStr) - 1;
+
+      t = n[0];
+      if t == None:
+         t = 0;
+
+      # Pad with zeros according to how large the total count is.
+      trackStr = str(t);
+      if len(trackStr) == 1:
+         trackStr = "0" + trackStr;
+      if len(trackStr) < len(totalStr):
+         trackStr = ("0" * (len(totalStr) - len(trackStr))) + trackStr;
+
+      s = "";
+      if trackStr and totalStr:
+         s = trackStr + "/" + totalStr;
+      elif trackStr and not totalStr:
+         s = trackStr;
+
+      self.frames.setTextFrame(TRACKNUM_FID, s, self.encoding);
+
+   # Add a comment.  This adds a comment unless one is already present with
+   # the same language and description in which case the current value is
+   # either changed (cmt evalues true) or removed (cmt equals "" or None).
+   def addComment(self, cmt, desc = "", lang = DEFAULT_LANG):
+      if not cmt:
+         # A little more then a call to removeFramesByID is involved since we
+         # need to look at more than the frame ID.
+         comments = self.frames[COMMENT_FID];
+         for c in comments:
+            if c.lang == lang and c.description == desc:
+               self.frames.remove(c);
+               break;
+      else:
+         self.frames.setCommentFrame(cmt, desc, lang, self.encoding);
+
+   def removeComments(self):
+       return self.frames.removeFramesByID(COMMENT_FID);
+
+   def addImage(self, type, image_file_path, desc = u""):
+       image_frame = ImageFrame.create(type, image_file_path, desc);
+       self.frames.addFrame(image_frame);
+
+   # Test ID3 major version.
+   def isV1(self):
+      return self.header.majorVersion == 1;
+   def isV2(self):
+      return self.header.majorVersion == 2;
+
+   def setVersion(self, v):
+      if v == ID3_V1:
+         v = ID3_V1_1;
+      elif v == ID3_V2:
+         v = ID3_DEFAULT_VERSION;
+
+      if v != ID3_CURRENT_VERSION:
+         self.header.setVersion(v);
+         self.frames.setTagHeader(self.header);
+   
+   def setTextFrame(self, fid, txt):
+       if not txt:
+          self.frames.removeFramesByID(fid);
+       else:
+          self.frames.setTextFrame(fid, txt, self.encoding);
+
+   def __saveV1Tag(self, version):
+      assert(version & ID3_V1);
+
+      # Build tag buffer.
+      tag = "TAG";
+      tag += self.fixToWidth(self.getTitle().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getArtist().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getAlbum().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getYear().encode("latin_1"), 4);
+
+      cmt = "";
+      for c in self.getComments():
+         if c.description == ID3_V1_COMMENT_DESC:
+            cmt = c.comment;
+            # We prefer this one over "";
+            break; 
+         elif c.description == "":
+            cmt = c.comment;
+            # Keep searching in case we find the description eyeD3 uses.
+      cmt = self.fixToWidth(cmt, 30);
+      if version != ID3_V1_0:
+         track = self.getTrackNum()[0];
+         if track != None:
+            cmt = cmt[0:28] + "\x00" + chr(int(track) & 0xff);
+      tag += cmt;
+
+      if not self.getGenre():
+         genre = 0;
+      else:
+         genre = self.getGenre().getId();
+      tag += chr(genre & 0xff);
+
+      assert(len(tag) == 128);
+
+      tagFile = file(self.linkedFile.name, "r+b");
+      # Write the tag over top an original or append it.
+      try:
+         tagFile.seek(-128, 2);
+         if tagFile.read(3) == "TAG":
+            tagFile.seek(-128, 2);
+         else:
+            tagFile.seek(0, 2);
+      except IOError:
+         # File is smaller than 128 bytes.
+         tagFile.seek(0, 2);
+
+      tagFile.write(tag);
+      tagFile.flush();
+      tagFile.close();
+      
+   def fixToWidth(self, s, n):
+      retval = str(s);
+      retval = retval[0:n];
+      retval = retval + ("\x00" * (n - len(retval)));
+      return retval;
+
+   # Returns false when an ID3 v1 tag is not present, or contains no data.
+   def __loadV1Tag(self, f):
+      if isinstance(f, str):
+         fp = file(f, "rb")
+         closeFile = 1;
+      else:
+         fp = f;
+         closeFile = 0;
+
+      # Seek to the end of the file where all ID3v1 tags are written.
+      fp.seek(0, 2);
+      if fp.tell() > 127:
+         fp.seek(-128, 2);
+         id3tag = fp.read(128);
+         if id3tag[0:3] == "TAG":
+            TRACE_MSG("Located ID3 v1 tag");
+            # 1.0 is implied until a 1.1 feature is recognized.
+            self.setVersion(ID3_V1_0);
+
+            title = re.sub("\x00+$", "", id3tag[3:33].strip());
+            TRACE_MSG("Tite: " + title);
+            if title:
+               self.setTitle(title);
+
+            artist = re.sub("\x00+$", "", id3tag[33:63].strip());
+            TRACE_MSG("Artist: " + artist);
+            if artist:
+               self.setArtist(artist);
+
+            album = re.sub("\x00+$", "", id3tag[63:93].strip());
+            TRACE_MSG("Album: " + album);
+            if album:
+               self.setAlbum(album);
+
+            year = re.sub("\x00+$", "", id3tag[93:97].strip());
+            TRACE_MSG("Year: " + year);
+            try:
+               if year and int(year):
+                  self.setDate(year);
+            except ValueError:
+               # Bogus year strings.
+               pass;
+
+	    if re.sub("\x00+$", "", id3tag[97:127]):
+	       comment = id3tag[97:127];
+               TRACE_MSG("Comment: " + comment);
+               if comment[-2] == "\x00" and comment[-1] != "\x00":
+                  # Parse track number (added to ID3v1.1) if present.
+                  TRACE_MSG("Comment contains track number per v1.1 spec");
+                  track = ord(comment[-1]);
+                  self.setTrackNum((track, None));
+                  TRACE_MSG("Track: " + str(track));
+                  TRACE_MSG("Track Num found, setting version to v1.1s");
+                  self.setVersion(ID3_V1_1);
+		  comment = comment[:-2];
+               else:
+                  track = None
+               comment = re.sub("\x00+$", "", comment).rstrip();
+               TRACE_MSG("Comment: " + comment);
+               if comment:
+                  self.addComment(comment, ID3_V1_COMMENT_DESC);
+
+            genre = ord(id3tag[127:128])
+            TRACE_MSG("Genre ID: " + str(genre));
+            self.setGenre(genre);
+
+      if closeFile:
+         fp.close()
+      return len(self.frames);
+
+   def __saveV2Tag(self, version):
+      assert(version & ID3_V2);
+      TRACE_MSG("Rendering tag version: " + versionToString(version));
+
+      self.setVersion(version);
+
+      currPadding = 0;
+      currTagSize = 0
+      if currTagSize == 0:
+         # We may be converting from 1.x to 2.x so we need to find any
+         # current v2.x tag otherwise we're gonna hork the file.
+         tmpTag = Tag();
+         if tmpTag.link(self.linkedFile.name, ID3_V2):
+            TRACE_MSG("Found current v2.x tag:");
+            currTagSize = tmpTag.linkedFile.tagSize;
+            TRACE_MSG("Current tag size: %d" % currTagSize);
+            currPadding = tmpTag.linkedFile.tagPadding;
+            TRACE_MSG("Current tag padding: %d" % currPadding);
+
+      # Tag it!
+      if self.header.minorVersion == 4:
+          h = FrameHeader(self.header);
+          h.id = "TDTG";
+          dateFrame = DateFrame(self.encoding +\
+                                time.strftime("%Y-%m-%dT%H:%M:%S"), h);
+          self.frames.removeFramesByID("TDTG");
+          self.frames.addFrame(dateFrame);
+
+      # Render all frames first so the data size is known for the tag header.
+      frameData = "";
+      for f in self.frames:
+         TRACE_MSG("Rendering frame: " + f.header.id);
+         raw_frame = f.render();
+         TRACE_MSG("Rendered %d bytes" % len(raw_frame));
+         frameData += raw_frame;
+
+      TRACE_MSG("Rendered tag size: " + str(len(frameData)));
+
+      rewriteFile = 0;
+      paddingSize = 0;
+      headerData = "";
+
+      # Extended header
+      if self.header.extended:
+         # This is sorta lame.  We don't know the total framesize until
+         # this is rendered, yet we can't render it witout knowing the
+         # amount of padding.  Force it.
+         rewriteFile = 1;
+         paddingSize = 2048;
+         TRACE_MSG("Rendering extended header");
+         headerData += self.extendedHeader.render(self.header, frameData,
+                                                  paddingSize);
+
+      if rewriteFile or (10 + len(headerData) + len(frameData)) >= currTagSize:
+         TRACE_MSG("File rewrite required");
+         rewriteFile = 1;
+         paddingSize = 2048;
+      else:
+         paddingSize = currTagSize - (len(headerData) + len(frameData));
+      frameData += ("\x00" * paddingSize);
+
+      # Render the tag header.
+      TRACE_MSG("Rendering %s tag header with size %d" %\
+                (versionToString(self.getVersion()), len(frameData)));
+      headerData = self.header.render(len(frameData));
+
+      # Assemble frame.
+      tagData = headerData + frameData;
+
+      # Write the tag.
+      if not rewriteFile:
+         tagFile = file(self.linkedFile.name, "r+b");
+         TRACE_MSG("Writing %d bytes of tag data" % len(tagData));
+         tagFile.write(tagData);
+         tagFile.close();
+      else:
+         # Open original
+         tagFile = file(self.linkedFile.name, "rb");
+         # Read all audio data
+         tagFile.seek(currTagSize);
+         audioData = tagFile.read();
+         tagFile.close();
+
+         # Open tmp file
+         tmpName = tempfile.mktemp();
+         tmpFile = file(tmpName, "w+b");
+         TRACE_MSG("Writing %d bytes of tag data" % len(tagData));
+         tmpFile.write(tagData);
+         tmpFile.write(audioData);
+         tmpFile.close();
+
+         # Move tmp to orig.
+         shutil.copyfile(tmpName, self.linkedFile.name);
+         os.unlink(tmpName);
+
+      # Update our state.
+      TRACE_MSG("Tag write complete.  Updating state.");
+      self.linkedFile.tagPadding = paddingSize;
+      # XXX: getSize could cache sizes so to prevent rendering again.
+      self.linkedFile.tagSize = self.frames.getSize();
+
+
+   # Returns >= 0 to indicate the padding size of the read frame; -1 returned
+   # when not tag was found.
+   def __loadV2Tag(self, f):
+      if isinstance(f, str):
+         fp = file(f, "rb")
+         closeFile = 1;
+      else:
+         fp = f;
+         closeFile = 0;
+
+      padding = -1;
+      try:
+         # Look for a tag and if found load it.
+         if not self.header.parse(fp):
+            return -1;
+
+         # Read the extended header if present.
+         if self.header.extended:
+            self.extendedHeader.parse(fp, self.header);
+
+         # Header is definitely there so at least one frame *must* follow.
+         self.frames.setTagHeader(self.header);
+         padding = self.frames.parse(fp, self.header);
+         TRACE_MSG("Tag contains %d bytes of padding." % padding);
+      except FrameException, ex:
+         #fp.close();
+         #raise TagException(str(ex));
+         # Technically, it's not a well-formed MP3, but we can still get data out of it.
+         # it's better than crashing....
+         pass
+      except TagException:
+         fp.close();
+         raise;
+
+      if closeFile:
+         fp.close();
+      return padding;
+
+   def toInt(self, s):
+      try:
+         return int(s);
+      except ValueError:
+         return None;
+      except TypeError:
+         return None;
+
+   def __padDateField(self, f):
+      fStr = str(f);
+      if len(fStr) == 2:
+         pass;
+      elif len(fStr) == 1:
+         fStr = "0" + fStr;
+      else:
+         raise TagException("Invalid date field: " + fStr);
+      return fStr;
+
+   # DEPRECATED
+   # This method will return the first comment in the FrameSet
+   # and not all of them.  Multiple COMM frames are common and useful.  Use
+   # getComments which returns a list.
+   def getComment(self):
+      f = self.frames[COMMENT_FID];
+      if f:
+         return f[0].comment;
+      else:
+         return None;
+
+
+################################################################################
+class GenreException(Exception):
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+
+################################################################################
+class Genre:
+   id = None;
+   name = None;
+
+   def __init__(self):
+      pass;
+
+   def getId(self):
+      return self.id;
+   def getName(self):
+      return self.name;
+
+   # Sets the genre id.  The objects name field is set to the corresponding
+   # value obtained from eyeD3.genres.
+   #
+   # Throws GenreException when name does not map to a valid ID3 v1.1. id.
+   # This behavior can be disabled by passing 0 as the second argument.
+   def setId(self, id, verify = 1):
+      if not isinstance(id, int):
+         raise TypeError("Invalid genre id: " + str(id));
+
+      try:
+         name = genres[id];
+      except Exception, ex:
+         if verify:
+            raise GenreException("Invalid genre id: " + str(id));
+
+      if verify and not name:
+         raise GenreException("Genre id maps to a null name: " + str(id));
+
+      self.id = id;
+      self.name = name;
+
+   # Sets the genre name.  The objects id field is set to the corresponding
+   # value obtained from eyeD3.genres.
+   #
+   # Throws GenreException when name does not map to a valid ID3 v1.1. name.
+   # This behavior can be disabled by passing 0 as the second argument.
+   def setName(self, name, verify = 1):
+      if not isinstance(name, str):
+         raise GenreException("Invalid genre name: " + str(name));
+
+      try:
+         id = genres[name];
+         # Get titled case.
+         name = genres[id];
+      except:
+         if verify:
+            raise GenreException("Invalid genre name: " + name);
+
+      self.id = id;
+      self.name = name;
+
+
+   # Sets the genre id and name. 
+   #
+   # Throws GenreException when eyeD3.genres[id] != name (case insensitive). 
+   # This behavior can be disabled by passing 0 as the second argument.
+   def set(self, id, name, verify = 1):
+      if not isinstance(id, int):
+         raise GenreException("Invalid genre id: " + id);
+      if not isinstance(name, str):
+         raise GenreException("Invalid genre name: " + str(name));
+
+      if not verify:
+         self.id = id;
+         self.name = name;
+      else:
+         try:
+            if genres[name] != id:
+               raise GenreException("eyeD3.genres[" + str(id) + "] " +\
+                                    "does not match " + name);
+            self.id = id;
+            self.name = name;
+         except:
+            raise GenreException("eyeD3.genres[" + str(id) + "] " +\
+                                 "does not match " + name);
+      
+   # Parses genre information from genreStr. 
+   # The following formats are supported:
+   # 01, 2, 23, 125 - ID3 v1 style.
+   # (01), (2), (129)Hardcore, (9)Metal - ID3 v2 style with and without
+   #                                      refinement.
+   #
+   # Throws GenreException when an invalid string is passed.
+   def parse(self, genreStr, verify = 1):
+      genreStr = str(genreStr.encode('utf-8')).strip();
+      self.id = None;
+      self.name = None;
+
+      if not genreStr:
+         return;
+
+      # XXX: Utf-16 conversions leave a null byte at the end of the string.
+      while genreStr[len(genreStr) - 1] == "\x00":
+         genreStr = genreStr[:len(genreStr) - 1];
+
+      # ID3 v1 style.
+      # Match 03, 34, 129.
+      regex = re.compile("[0-9][0-9]?[0-9]?$");
+      if regex.match(genreStr):
+         if len(genreStr) != 1 and genreStr[0] == '0':
+            genreStr = genreStr[1:];
+
+         self.setId(int(genreStr), verify);
+         return;
+
+      # ID3 v2 style.
+      # Match (03), (0)Blues, (15) Rap
+      regex = re.compile("\(([0-9][0-9]?[0-9]?)\)(.*)$");
+      m = regex.match(genreStr);
+      if m:
+         (id, name) = m.groups();
+         if len(id) != 1 and id[0] == '0':
+            id = id[1:];
+            
+         if id and name:
+            self.set(int(id), name.strip(), verify);
+         else:
+            self.setId(int(id), verify);
+         return;
+
+      # Non standard, but witnessed.
+      # Match genreName alone.  e.g. Rap, Rock, blues.
+      regex = re.compile("^[A-Z 0-9+/\-&]+\00*$", re.IGNORECASE);
+      if regex.match(genreStr):
+         self.setName(genreStr, verify);
+         return;
+      else:
+          print regex.pattern;
+      raise GenreException("Genre string cannot be parsed: " + genreStr);
+
+   def __str__(self):
+      s = "";
+      if self.id != None:
+         s += "(" + str(self.id) + ")"
+      if self.name:
+         s += self.name;
+      return s;
+
+################################################################################
+class InvalidAudioFormatException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class Mp3AudioFile:
+   fileName       = str();
+   fileSize       = int();
+   header         = eyeD3_mp3.Header();
+   xingHeader     = None;
+   tag            = Tag();
+   invalidFileExc = InvalidAudioFormatException("File is not mp3");
+   # Number of seconds required to play the audio file.
+   playTime       = None;
+
+   def __init__(self, fileName, tagVersion = ID3_ANY_VERSION):
+      self.playTime = None;
+      self.fileName = fileName;
+
+#      if not isMp3File(fileName):
+#         raise self.invalidFileExc;
+
+      # Parse ID3 tag.
+      f = file(fileName, "rb");
+      tag = Tag();
+      hasTag = tag.link(f, tagVersion);
+      # Find the first mp3 frame.
+      if tag.isV1():
+         framePos = 0;
+      elif not hasTag:
+         framePos = 0;
+         tag = None;
+      else:
+         # XXX: Note that v2.4 allows for appended tags; account for that.
+         framePos = tag.header.SIZE + tag.header.tagSize;
+      f.seek(framePos);
+      bString = f.read(4);
+      if len(bString) < 4:
+         raise InvalidAudioFormatException("Unable to find a valid mp3 "\
+                                           "frame");
+      frameHead = bin2dec(bytes2bin(bString));
+      header = eyeD3_mp3.Header();
+      # Keep reading until we find a valid mp3 frame header.
+      while not header.isValid(frameHead):
+         frameHead <<= 8;
+         bString = f.read(1);
+         if len(bString) != 1:
+            raise InvalidAudioFormatException("Unable to find a valid mp3 "\
+                                              "frame");
+         frameHead |= ord(bString[0]);
+      TRACE_MSG("mp3 header %x found at position: %d (0x%x)" % \
+                (frameHead, f.tell() - 4, f.tell() - 4));
+
+      # Decode the header.
+      try:
+         header.decode(frameHead);
+         # Check for Xing header inforamtion which will always be in the
+         # first "null" frame.
+         f.seek(-4, 1);
+         mp3Frame = f.read(header.frameLength);
+         if mp3Frame.find("Xing") != -1:
+            xingHeader = eyeD3_mp3.XingHeader();
+            if not xingHeader.decode(mp3Frame):
+               raise InvalidAudioFormatException("Corrupt Xing header");
+         else:
+            xingHeader = None;
+      except eyeD3_mp3.Mp3Exception, ex:
+         raise InvalidAudioFormatException(str(ex));
+
+      # Compute track play time.
+      tpf = eyeD3_mp3.computeTimePerFrame(header);
+      if xingHeader:
+         self.playTime = int(tpf * xingHeader.numFrames);
+      else:
+         length = self.getSize();
+         if tag and tag.isV2():
+            length -= tag.header.SIZE + tag.header.tagSize;
+            # Handle the case where there is a v2 tag and a v1 tag.
+            f.seek(-128, 2)
+            if f.read(3) == "TAG":
+               length -= 128;
+         elif tag and tag.isV1():
+            length -= 128;
+         self.playTime = int((length / header.frameLength) * tpf);    
+
+      self.header = header;
+      self.xingHeader = xingHeader;
+      self.tag = tag;
+      f.close();
+
+   def getTag(self):
+      return self.tag;
+
+   def getSize(self):
+      if not self.fileSize:
+         self.fileSize = os.stat(self.fileName)[ST_SIZE];
+      return self.fileSize;
+
+   def getPlayTime(self):
+      return self.playTime;
+
+   def getPlayTimeString(self):
+      total = self.getPlayTime();
+      h = total / 3600;
+      m = (total % 3600) / 60;
+      s = (total % 3600) % 60;
+      if h:
+         timeStr = "%d:%.2d:%.2d" % (h, m, s);
+      else:
+         timeStr = "%d:%.2d" % (m, s);
+      return timeStr;
+
+   # Returns a tuple.  The first value is a boolean which if true means the
+   # bit rate returned in the second value is variable.
+   def getBitRate(self):
+      xHead = self.xingHeader;
+      if xHead:
+         tpf = eyeD3_mp3.computeTimePerFrame(self.header);
+         br = int((xHead.numBytes * 8) / (tpf * xHead.numFrames * 1000));
+         vbr = 1;
+      else:
+         br = self.header.bitRate;
+         vbr = 0;
+      return (vbr, br);
+
+   def getBitRateString(self):
+      (vbr, bitRate) = self.getBitRate();
+      brs = "%d kb/s" % bitRate;
+      if vbr:
+         brs = "~" + brs;
+      return brs;
+
+################################################################################
+def isMp3File(fileName):
+    (type, enc) = mimetypes.guess_type(fileName);
+    return type == "audio/mpeg";
+
+################################################################################
+class GenreMap(list):
+
+   #######################################################################
+   # Accepts both int and string keys. Throws IndexError and TypeError.
+   def __getitem__(self, key):
+      if isinstance(key, int):
+         if key >= 0 and key < len(self):
+            v = list.__getitem__(self, key);
+            if v:
+               return v;
+            else:
+               return None;
+         else:
+            raise IndexError("genre index out of range");
+      elif isinstance(key, str):
+         if self.reverseDict.has_key(key.lower()):
+            return self.reverseDict[key.lower()];
+         else:
+            raise IndexError(key + " genre not found");
+      else:
+         raise TypeError("genre key must be type int or string");
+
+   def __init__(self):
+      self.data = []
+      self.reverseDict = {}
+      # ID3 genres as defined by the v1.1 spec with WinAmp extensions.
+      self.append('Blues');
+      self.append('Classic Rock');
+      self.append('Country');
+      self.append('Dance');
+      self.append('Disco');
+      self.append('Funk');
+      self.append('Grunge');
+      self.append('Hip-Hop');
+      self.append('Jazz');
+      self.append('Metal');
+      self.append('New Age');
+      self.append('Oldies');
+      self.append('Other');
+      self.append('Pop');
+      self.append('R&B');
+      self.append('Rap');
+      self.append('Reggae');
+      self.append('Rock');
+      self.append('Techno');
+      self.append('Industrial');
+      self.append('Alternative');
+      self.append('Ska');
+      self.append('Death Metal');
+      self.append('Pranks');
+      self.append('Soundtrack');
+      self.append('Euro-Techno');
+      self.append('Ambient');
+      self.append('Trip-Hop');
+      self.append('Vocal');
+      self.append('Jazz+Funk');
+      self.append('Fusion');
+      self.append('Trance');
+      self.append('Classical');
+      self.append('Instrumental');
+      self.append('Acid');
+      self.append('House');
+      self.append('Game');
+      self.append('Sound Clip');
+      self.append('Gospel');
+      self.append('Noise');
+      self.append('AlternRock');
+      self.append('Bass');
+      self.append('Soul');
+      self.append('Punk');
+      self.append('Space');
+      self.append('Meditative');
+      self.append('Instrumental Pop');
+      self.append('Instrumental Rock');
+      self.append('Ethnic');
+      self.append('Gothic');
+      self.append('Darkwave');
+      self.append('Techno-Industrial');
+      self.append('Electronic');
+      self.append('Pop-Folk');
+      self.append('Eurodance');
+      self.append('Dream');
+      self.append('Southern Rock');
+      self.append('Comedy');
+      self.append('Cult');
+      self.append('Gangsta Rap');
+      self.append('Top 40');
+      self.append('Christian Rap');
+      self.append('Pop / Funk');
+      self.append('Jungle');
+      self.append('Native American');
+      self.append('Cabaret');
+      self.append('New Wave');
+      self.append('Psychedelic');
+      self.append('Rave');
+      self.append('Showtunes');
+      self.append('Trailer');
+      self.append('Lo-Fi');
+      self.append('Tribal');
+      self.append('Acid Punk');
+      self.append('Acid Jazz');
+      self.append('Polka');
+      self.append('Retro');
+      self.append('Musical');
+      self.append('Rock & Roll');
+      self.append('Hard Rock');
+      self.append('Folk');
+      self.append('Folk-Rock');
+      self.append('National Folk');
+      self.append('Swing');
+      self.append('Fast  Fusion');
+      self.append('Bebob');
+      self.append('Latin');
+      self.append('Revival');
+      self.append('Celtic');
+      self.append('Bluegrass');
+      self.append('Avantgarde');
+      self.append('Gothic Rock');
+      self.append('Progressive Rock');
+      self.append('Psychedelic Rock');
+      self.append('Symphonic Rock');
+      self.append('Slow Rock');
+      self.append('Big Band');
+      self.append('Chorus');
+      self.append('Easy Listening');
+      self.append('Acoustic');
+      self.append('Humour');
+      self.append('Speech');
+      self.append('Chanson');
+      self.append('Opera');
+      self.append('Chamber Music');
+      self.append('Sonata');
+      self.append('Symphony');
+      self.append('Booty Bass');
+      self.append('Primus');
+      self.append('Porn Groove');
+      self.append('Satire');
+      self.append('Slow Jam');
+      self.append('Club');
+      self.append('Tango');
+      self.append('Samba');
+      self.append('Folklore');
+      self.append('Ballad');
+      self.append('Power Ballad');
+      self.append('Rhythmic Soul');
+      self.append('Freestyle');
+      self.append('Duet');
+      self.append('Punk Rock');
+      self.append('Drum Solo');
+      self.append('A Cappella');
+      self.append('Euro-House');
+      self.append('Dance Hall');
+      self.append('Goa');
+      self.append('Drum & Bass');
+      self.append('Club-House');
+      self.append('Hardcore');
+      self.append('Terror');
+      self.append('Indie');
+      self.append('BritPop');
+      self.append('Negerpunk');
+      self.append('Polsk Punk');
+      self.append('Beat');
+      self.append('Christian Gangsta Rap');
+      self.append('Heavy Metal');
+      self.append('Black Metal');
+      self.append('Crossover');
+      self.append('Contemporary Christian');
+      self.append('Christian Rock');
+      self.append('Merengue');
+      self.append('Salsa');
+      self.append('Thrash Metal');
+      self.append('Anime');
+      self.append('JPop');
+      self.append('Synthpop');
+
+      # Pad up to 255 with "Unknown"
+      count = len(self);
+      while count < 256:
+         self.append("Unknown");
+         count += 1;
+      
+      for index in range(len(self)):
+         if self[index]:
+	    self.reverseDict[string.lower(self[index])] = index
+class LinkedFile:
+   name = "";
+   tagPadding = 0;
+   tagSize = 0;  # This includes the padding byte count.
+
+   def __init__(self, fileName):
+      self.name = fileName;
+
+def tagToUserTune(tag):
+    audio_file = None;
+    if isinstance(tag, Mp3AudioFile):
+        audio_file = tag;
+        tag = audio_file.getTag();
+        
+    tune =  "<tune xmlns='http://jabber.org/protocol/tune'>\n";
+    if tag.getArtist():
+        tune += "  <artist>" + tag.getArtist() + "</artist>\n";
+    if tag.getTitle():
+        tune += "  <title>" + tag.getTitle() + "</title>\n";
+    if tag.getAlbum():
+        tune += "  <source>" + tag.getAlbum() + "</source>\n";
+    tune += "  <track>" + "file://" + os.path.abspath(tag.linkedFile.name) +\
+            "</track>\n";
+    if audio_file:
+        # XXX: This should be an xs:duration
+        tune += "  <length>" + audio_file.getPlayTimeString() + "</length>\n";
+    tune += "</tune>\n";
+    return tune;
+
+#
+# Module level globals.
+#
+genres = GenreMap();
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/frames.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/frames.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/frames.py	(revision 4)
@@ -0,0 +1,1441 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#  Copyright (C) 2001  Ryan Finne <ryan@finnie.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+import os, os.path, re, zlib, StringIO, time, mimetypes;
+from StringIO import StringIO;
+from utils import *;
+from binfuncs import *;
+
+# Valid time stamp formats per ISO 8601 and used by time.strptime.
+timeStampFormats = ["%Y",
+                    "%Y-%m",
+                    "%Y-%m-%d",
+                    "%Y-%m-%dT%H",
+                    "%Y-%m-%dT%H:%M",
+                    "%Y-%m-%dT%H:%M:%S"];
+
+ARTIST_FID         = "TPE1";
+BAND_FID           = "TPE2";
+CONDUCTOR_FID      = "TPE3";
+REMIXER_FID        = "TPE4";
+COMPOSER_FID       = "TCOM";
+ARTIST_FIDS        = [ARTIST_FID, BAND_FID, CONDUCTOR_FID,
+                      REMIXER_FID, COMPOSER_FID];
+ALBUM_FID          = "TALB";
+TITLE_FID          = "TIT2";
+SUBTITLE_FID       = "TIT3";
+CONTENT_TITLE_FID  = "TIT1";
+TITLE_FIDS         = [TITLE_FID, SUBTITLE_FID, CONTENT_TITLE_FID];
+COMMENT_FID        = "COMM";
+GENRE_FID          = "TCON";
+TRACKNUM_FID       = "TRCK";
+USERTEXT_FID       = "TXXX";
+CDID_FID           = "MCDI";
+IMAGE_FID          = "APIC";
+URL_COMMERCIAL_FID = "WCOM";
+URL_COPYRIGHT_FID  = "WCOP";
+URL_AUDIOFILE_FID  = "WOAF";
+URL_ARTIST_FID     = "WOAR";
+URL_AUDIOSRC_FID   = "WOAS";
+URL_INET_RADIO_FID = "WORS";
+URL_PAYMENT_FID    = "WPAY";
+URL_PUBLISHER_FID  = "WPUB";
+URL_FIDS           = [URL_COMMERCIAL_FID, URL_COPYRIGHT_FID,
+                      URL_AUDIOFILE_FID, URL_ARTIST_FID, URL_AUDIOSRC_FID,
+                      URL_INET_RADIO_FID, URL_PAYMENT_FID,
+                      URL_PUBLISHER_FID];
+USERURL_FID        = "WXXX";
+
+obsoleteFrames = {"EQUA": "Equalisation",
+                  "IPLS": "Involved people list",
+                  "RVAD": "Relative volume adjustment",
+                  "TDAT": "Date",
+                  "TORY": "Original release year",
+                  "TRDA": "Recording dates",
+                  "TYER": "Year"};
+# Both of these are "coerced" into a v2.4 TDRC frame when read, and 
+# recreated when saving v2.3.
+OBSOLETE_DATE_FID            = "TDAT";
+OBSOLETE_YEAR_FID            = "TYER";
+OBSOLETE_TIME_FID            = "TIME";
+OBSOLETE_ORIG_RELEASE_FID    = "TORY";
+OBSOLETE_RECORDING_DATE_FID  = "TRDA";
+
+frameDesc = { "AENC": "Audio encryption",
+              "APIC": "Attached picture",
+              "ASPI": "Audio seek point index",
+
+              "COMM": "Comments",
+              "COMR": "Commercial frame",
+
+              "ENCR": "Encryption method registration",
+              "EQU2": "Equalisation (2)",
+              "ETCO": "Event timing codes",
+
+              "GEOB": "General encapsulated object",
+              "GRID": "Group identification registration",
+
+              "LINK": "Linked information",
+
+              "MCDI": "Music CD identifier",
+              "MLLT": "MPEG location lookup table",
+
+              "OWNE": "Ownership frame",
+
+              "PRIV": "Private frame",
+              "PCNT": "Play counter",
+              "POPM": "Popularimeter",
+              "POSS": "Position synchronisation frame",
+
+              "RBUF": "Recommended buffer size",
+              "RVA2": "Relative volume adjustment (2)",
+              "RVRB": "Reverb",
+
+              "SEEK": "Seek frame",
+              "SIGN": "Signature frame",
+              "SYLT": "Synchronised lyric/text",
+              "SYTC": "Synchronised tempo codes",
+
+              "TALB": "Album/Movie/Show title",
+              "TBPM": "BPM (beats per minute)",
+              "TCOM": "Composer",
+              "TCON": "Content type",
+              "TCOP": "Copyright message",
+              "TDEN": "Encoding time",
+              "TDLY": "Playlist delay",
+              "TDOR": "Original release time",
+              "TDRC": "Recording time",
+              "TDRL": "Release time",
+              "TDTG": "Tagging time",
+              "TENC": "Encoded by",
+              "TEXT": "Lyricist/Text writer",
+              "TFLT": "File type",
+              "TIPL": "Involved people list",
+              "TIT1": "Content group description",
+              "TIT2": "Title/songname/content description",
+              "TIT3": "Subtitle/Description refinement",
+              "TKEY": "Initial key",
+              "TLAN": "Language(s)",
+              "TLEN": "Length",
+              "TMCL": "Musician credits list",
+              "TMED": "Media type",
+              "TMOO": "Mood",
+              "TOAL": "Original album/movie/show title",
+              "TOFN": "Original filename",
+              "TOLY": "Original lyricist(s)/text writer(s)",
+              "TOPE": "Original artist(s)/performer(s)",
+              "TOWN": "File owner/licensee",
+              "TPE1": "Lead performer(s)/Soloist(s)",
+              "TPE2": "Band/orchestra/accompaniment",
+              "TPE3": "Conductor/performer refinement",
+              "TPE4": "Interpreted, remixed, or otherwise modified by",
+              "TPOS": "Part of a set",
+              "TPRO": "Produced notice",
+              "TPUB": "Publisher",
+              "TRCK": "Track number/Position in set",
+              "TRSN": "Internet radio station name",
+              "TRSO": "Internet radio station owner",
+              "TSOA": "Album sort order",
+              "TSOP": "Performer sort order",
+              "TSOT": "Title sort order",
+              "TSRC": "ISRC (international standard recording code)",
+              "TSSE": "Software/Hardware and settings used for encoding",
+              "TSST": "Set subtitle",
+              "TXXX": "User defined text information frame",
+
+              "UFID": "Unique file identifier",
+              "USER": "Terms of use",
+              "USLT": "Unsynchronised lyric/text transcription",
+
+              "WCOM": "Commercial information",
+              "WCOP": "Copyright/Legal information",
+              "WOAF": "Official audio file webpage",
+              "WOAR": "Official artist/performer webpage",
+              "WOAS": "Official audio source webpage",
+              "WORS": "Official Internet radio station homepage",
+              "WPAY": "Payment",
+              "WPUB": "Publishers official webpage",
+              "WXXX": "User defined URL link frame" };
+
+NULL_FRAME_FLAGS = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+TEXT_FRAME_RX = re.compile("^T[A-Z0-9][A-Z0-9][A-Z0-9]$");
+USERTEXT_FRAME_RX = re.compile("^" + USERTEXT_FID + "$");
+URL_FRAME_RX = re.compile("^W[A-Z0-9][A-Z0-9][A-Z0-9]$");
+USERURL_FRAME_RX = re.compile("^" + USERURL_FID + "$");
+COMMENT_FRAME_RX = re.compile("^" + COMMENT_FID + "$");
+CDID_FRAME_RX = re.compile("^" + CDID_FID + "$");
+IMAGE_FRAME_RX = re.compile("^" + IMAGE_FID + "$");
+
+LATIN1_ENCODING   = "\x00";
+UTF_16_ENCODING   = "\x01";
+UTF_16BE_ENCODING = "\x02";
+UTF_8_ENCODING    = "\x03";
+
+DEFAULT_ENCODING = LATIN1_ENCODING;
+DEFAULT_ID3_MAJOR_VERSION = 2;
+DEFAULT_ID3_MINOR_VERSION = 4;
+DEFAULT_LANG = "eng";
+
+def id3EncodingToString(encoding):
+    if encoding == LATIN1_ENCODING:
+        return "latin_1";
+    elif encoding == UTF_8_ENCODING:
+        return "utf_8";
+    elif encoding == UTF_16_ENCODING:
+        return "utf_16";
+    elif encoding == UTF_16BE_ENCODING:
+        return "utf_16_be";
+    else:
+        raise ValueError;
+
+################################################################################
+class FrameException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class FrameHeader:
+   FRAME_HEADER_SIZE = 10;
+   # The tag header
+   majorVersion = DEFAULT_ID3_MAJOR_VERSION;
+   minorVersion = DEFAULT_ID3_MINOR_VERSION;
+   # The 4 character frame ID.
+   id = None;
+   # An array of 16 "bits"...
+   flags = NULL_FRAME_FLAGS;
+   # ...and the info they store.
+   tagAlter = 0;
+   fileAlter = 0;
+   readOnly = 0;
+   compressed = 0;
+   encrypted = 0;
+   grouped = 0;
+   unsync = 0;
+   dataLenIndicator = 0;
+   # The size of the data following this header.
+   dataSize = 0;
+
+   # 2.4 not only added flag bits, but also reordered the previously defined
+   # flags.  So these are mapped once we know the version.
+   TAG_ALTER   = None;   
+   FILE_ALTER  = None;   
+   READ_ONLY   = None;   
+   COMPRESSION = None;   
+   ENCRYPTION  = None;   
+   GROUPING    = None;   
+   UNSYNC      = None;   
+   DATA_LEN    = None;   
+
+   # Constructor.
+   def __init__(self, tagHeader = None):
+      if tagHeader:
+         self.setVersion(tagHeader);
+      else:
+         self.setVersion([DEFAULT_ID3_MAJOR_VERSION,
+                          DEFAULT_ID3_MINOR_VERSION]);
+
+   def setVersion(self, tagHeader):
+      # A slight hack to make the default ctor work.
+      if isinstance(tagHeader, list):
+         self.majorVersion = tagHeader[0];
+         self.minorVersion = tagHeader[1];
+      else:
+         self.majorVersion = tagHeader.majorVersion;
+         self.minorVersion = tagHeader.minorVersion;
+      self.setBitMask();
+
+   def setBitMask(self):
+      major = self.majorVersion;
+      minor = self.minorVersion;
+
+      # 1.x tags are converted to 2.4 frames internally.  These frames are
+      # created with frame flags \x00.
+      if (major == 2 and minor == 3):
+         self.TAG_ALTER   = 0;   
+         self.FILE_ALTER  = 1;   
+         self.READ_ONLY   = 2;   
+         self.COMPRESSION = 8;   
+         self.ENCRYPTION  = 9;   
+         self.GROUPING    = 10;   
+         # This is not really in 2.3 frame header flags, but there is
+         # a "global" unsync bit in the tag header and that is written here
+         # so access to the tag header is not required.
+         self.UNSYNC      = 14;   
+         # And this is mapped to an used bit, so that 0 is returned.
+         self.DATA_LEN    = 4;
+      elif (major == 2 and minor == 4) or \
+           (major == 1 and (minor == 0 or minor == 1)):
+         self.TAG_ALTER   = 1;   
+         self.FILE_ALTER  = 2;   
+         self.READ_ONLY   = 3;   
+         self.COMPRESSION = 12;   
+         self.ENCRYPTION  = 13;   
+         self.GROUPING    = 9;   
+         self.UNSYNC      = 14;   
+         self.DATA_LEN    = 15;   
+      else:
+         raise ValueError("ID3 v" + str(major) + "." + str(minor) +\
+                          " is not supported.");
+
+   def render(self, dataSize):
+      data = self.id;
+
+      if self.minorVersion == 3:
+         data += bin2bytes(dec2bin(dataSize, 32));
+      else:
+         data += bin2bytes(bin2synchsafe(dec2bin(dataSize, 32)));
+
+      self.setBitMask();
+      self.flags = NULL_FRAME_FLAGS;
+      self.flags[self.TAG_ALTER] = self.tagAlter;
+      self.flags[self.FILE_ALTER] = self.fileAlter;
+      self.flags[self.READ_ONLY] = self.readOnly;
+      self.flags[self.COMPRESSION] = self.compressed;
+      self.flags[self.COMPRESSION] = self.compressed;
+      self.flags[self.ENCRYPTION] = self.encrypted;
+      self.flags[self.GROUPING] = self.grouped;
+      self.flags[self.UNSYNC] = self.unsync;
+      self.flags[self.DATA_LEN] = self.dataLenIndicator;
+
+      data += bin2bytes(self.flags);
+
+      return data;
+
+   # Returns 1 on success and 0 when a null tag (marking the beginning of
+   # padding).  In the case of an invalid frame header, a FrameException is 
+   # thrown.
+   def parse(self, f):
+      TRACE_MSG("FrameHeader [start byte]: %d (0x%X)" % (f.tell(),
+                                                         f.tell()));
+      frameId = f.read(4);
+      TRACE_MSG("FrameHeader [id]: %s (0x%x%x%x%x)" % (frameId,
+                                                       ord(frameId[0]),
+                                                       ord(frameId[1]),
+                                                       ord(frameId[2]),
+                                                       ord(frameId[3])));
+
+      if self.isFrameIdValid(frameId):
+         self.id = frameId;
+         # dataSize corresponds to the size of the data segment after
+         # encryption, compression, and unsynchronization.
+         sz = f.read(4);
+         # In ID3 v2.4 this value became a synch-safe integer, meaning only
+         # the low 7 bits are used per byte.
+         if self.minorVersion == 3:
+            self.dataSize = bin2dec(bytes2bin(sz, 8));
+         else:
+            self.dataSize = bin2dec(bytes2bin(sz, 7));
+         TRACE_MSG("FrameHeader [data size]: %d (0x%X)" % (self.dataSize,
+                                                           self.dataSize));
+ 
+         # Frame flags.
+         flags = f.read(2);
+         self.flags = bytes2bin(flags);
+         self.tagAlter = self.flags[self.TAG_ALTER];
+         self.fileAlter = self.flags[self.FILE_ALTER];
+         self.readOnly = self.flags[self.READ_ONLY];
+         self.compressed = self.flags[self.COMPRESSION];
+         self.encrypted = self.flags[self.ENCRYPTION];
+         self.grouped = self.flags[self.GROUPING];
+         self.unsync = self.flags[self.UNSYNC];
+         self.dataLenIndicator = self.flags[self.DATA_LEN];
+         TRACE_MSG("FrameHeader [flags]: ta(%d) fa(%d) ro(%d) co(%d) "\
+                   "en(%d) gr(%d) un(%d) dl(%d)" % (self.tagAlter,
+                                                    self.fileAlter,
+                                                    self.readOnly,
+                                                    self.compressed,
+                                                    self.encrypted,
+                                                    self.grouped,
+                                                    self.unsync,
+                                                    self.dataLenIndicator));
+         if self.minorVersion >= 4 and self.compressed and \
+            not self.dataLenIndicator:
+            raise FrameException("Invalid frame; compressed with no data "
+                                 "length indicator");
+
+      elif frameId == '\x00\x00\x00\x00':
+         TRACE_MSG("FrameHeader: Null frame id found at byte " +\
+                   str(f.tell()));
+         return 0;
+      else:
+         raise FrameException("FrameHeader: Illegal Frame ID: " + frameId);
+      return 1;
+
+
+   def isFrameIdValid(self, id):
+      return re.compile(r"^[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]$").match(id) or \
+             id == 'MP3e' or id[1:] == 'MP3'
+
+   def clearFlags(self):
+      flags = [0] * 16;
+
+################################################################################
+def unsyncData(data):
+   subs = (0, 0);
+   (data, subs[0]) = re.compile("\xff\x00").subn("\xff\x00\x00", data);
+   (data, subs[1]) = re.compile("\xff(?=[\xe0-\xff])").subn("\xff\x00", data);
+   TRACE_MSG("Unsynchronizing data: " + str(subs));
+   return data;
+
+def deunsyncData(data):
+   TRACE_MSG("Frame: [size before deunsync]: " + str(len(data)));
+   data = re.compile("\xff\x00([\xe0-\xff])").sub("\xff\\1", data);
+   TRACE_MSG("Frame: [size after stage #1 deunsync]: " + str(len(data)));
+   data = re.compile("\xff\x00\x00").sub("\xff\x00", data);
+   TRACE_MSG("Frame: [size after deunsync: " + str(len(data)));
+   return data;
+
+################################################################################
+class Frame:
+   header = None;
+   decompressedSize = 0;
+   groupId = 0;
+   encryptionMethod = 0;
+   dataLen = 0;
+
+   def __repr__(self):
+      desc = self.getFrameDesc();
+      return '<%s Frame (%s)>' % (desc, self.header.id);
+
+   def unsync(self, data):
+      if self.header.unsync:
+         data = unsyncData(data);
+      return data;
+
+   def deunsync(self, data):
+      data = deunsyncData(data);
+      return data;
+
+   def decompress(self, data):
+      TRACE_MSG("before decompression: %d bytes" % len(data));
+      data = zlib.decompress(data, 15, self.decompressedSize);
+      TRACE_MSG("after decompression: %d bytes" % len(data));
+      return data;
+
+   def compress(self, data):
+      TRACE_MSG("before compression: %d bytes" % len(data));
+      data = zlib.compress(data);
+      TRACE_MSG("after compression: %d bytes" % len(data));
+      return data;
+
+   def decrypt(self, data):
+      raise FrameException("Ecnyption Not Supported");
+
+   def encrypt(self, data):
+      raise FrameException("Ecnyption Not Supported");
+
+   def disassembleFrame(self, data):
+      # Format flags in the frame header may add extra data to the
+      # beginning of this data.
+      if self.header.minorVersion == 3:
+         # 2.3:  compression(4), encryption(1), group(1) 
+         if self.header.compressed:
+            self.decompressedSize = bin2dec(bytes2bin(data[:4]));
+            data = data[4:];
+            TRACE_MSG("Decompressed Size: %d" % self.decompressedSize);
+         if self.header.encrypted:
+            self.encryptionMethod = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Encryption Method: %d" % self.encryptionMethod);
+         if self.header.grouped:
+            self.groupId = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Group ID: %d" % self.groupId);
+      else:
+         # 2.4:  group(1), encrypted(1), dataLenIndicator(4,7)
+         if self.header.grouped:
+            self.groupId = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+         if self.header.encrypted:
+            self.encryptionMethod = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Encryption Method: %d" % self.encryptionMethod);
+            TRACE_MSG("Group ID: %d" % self.groupId);
+         if self.header.dataLenIndicator:
+            self.dataLen = bin2dec(bytes2bin(data[:4], 7));
+            data = data[4:];
+            TRACE_MSG("Data Length: %d" % self.dataLen);
+            if self.header.compressed:
+               self.decompressedSize = self.dataLen;
+               TRACE_MSG("Decompressed Size: %d" % self.decompressedSize);
+
+      if self.header.unsync:
+         data = self.deunsync(data);
+      if self.header.encrypted:
+         data = self.decrypt(data);
+      if self.header.compressed:
+         data = self.decompress(data);
+      return data;
+
+   def assembleFrame (self, data):
+      formatFlagData = "";
+      if self.header.minorVersion == 3:
+         if self.header.compressed:
+            formatFlagData += bin2bytes(dec2bin(len(data), 32));
+         if self.header.encrypted:
+            formatFlagData += bin2bytes(dec2bin(self.encryptionMethod, 8));
+         if self.header.grouped:
+            formatFlagData += bin2bytes(dec2bin(self.groupId, 8));
+      else:
+         if self.header.grouped:
+            formatFlagData += bin2bytes(dec2bin(self.groupId, 8));
+         if self.header.encrypted:
+            formatFlagData += bin2bytes(dec2bin(self.encryptionMethod, 8));
+         if self.header.compressed or self.header.dataLenIndicator:
+            # Just in case, not sure about this?
+            self.header.dataLenIndicator = 1;
+            formatFlagData += bin2bytes(dec2bin(len(data), 32));
+
+      if self.header.compressed:
+         data = self.compress(data);
+      if self.header.encrypted:
+         data = self.encrypt(data);
+      if self.header.unsync:
+         data = self.unsync(data);
+
+      data = formatFlagData + data;
+      return self.header.render(len(data)) + data;
+
+   def getFrameDesc(self):
+      try:
+         return frameDesc[self.header.id];
+      except KeyError:
+         try:
+            return obsoleteFrames[self.header.id];
+         except KeyError:
+            return "UNKOWN FRAME";
+
+################################################################################
+class TextFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   text = u"";
+
+   # Data string format:
+   # encoding (one byte) + text;
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + text;
+   def set(self, data, frameHeader):
+      fid = frameHeader.id;
+      if not TEXT_FRAME_RX.match(fid) or USERTEXT_FRAME_RX.match(fid):
+         raise FrameException("Invalid frame id for TextFrame: " + fid);
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("TextFrame encoding: %s" % id3EncodingToString(self.encoding));
+      self.text = unicode(data[1:], id3EncodingToString(self.encoding));
+      TRACE_MSG("TextFrame text: %s" % self.text);
+
+   def __repr__(self):
+      return '<%s (%s): %s>' % (self.getFrameDesc(), self.header.id, self.text);
+
+   def render(self):
+       if self.header.minorVersion == 4 and self.header.id == "TSIZ":
+           TRACE_MSG("Dropping deprecated frame TSIZ");
+           return "";
+       data = self.encoding +\
+              self.text.encode(id3EncodingToString(self.encoding));
+       return self.assembleFrame(data);
+
+################################################################################
+class DateFrame(TextFrame):
+   def __init__(self, data, frameHeader):
+      self.date = None;
+      self.date_str = "";
+      self.set(data, frameHeader);
+
+   def set(self, data, frameHeader):
+      TextFrame.set(self, data, frameHeader);
+      if self.header.id[:2] != "TD" and self.header.minorVersion != 3:
+         raise FrameException("Invalid frame id for DateFrame: " + \
+                              self.header.id);
+      self.setDate(self.text);
+   
+   def setDate(self, d):
+      if not d:
+         self.date = None;
+         self.date_str = "";
+         return;
+
+      for fmt in timeStampFormats:
+         try:
+            if isinstance(d, tuple):
+               self.date_str = time.strftime(fmt, d);
+               self.date = d;
+            else:
+               d = d.strip("\x00");
+
+               # Witnessed oddball tags with NULL bytes (ozzy.tag from id3lib)
+               strippedDate = "";
+               for c in d:
+                  if ord(c) != 0:
+                     strippedDate += c;
+               d = strippedDate;
+
+               try:
+                  self.date = time.strptime(d, fmt);
+               except TypeError, ex:
+                  continue;
+               self.date_str = d;
+            break;
+         except ValueError:
+            self.date = None;
+            self.date_str = "";
+            continue;
+      if strictID3() and not self.date:
+         raise FrameException("Invalid Date: " + str(d));
+      self.text = self.date_str;
+
+   def getDate(self):
+      return self.date_str;
+
+   def getYear(self):
+      if self.date:
+	 return self.__padDateField(self.date[0], 4);
+      else:
+         return None;
+
+   def getMonth(self):
+      if self.date:
+	 return self.__padDateField(self.date[1], 2);
+      else:
+         return None;
+
+   def getDay(self):
+      if self.date:
+	 return self.__padDateField(self.date[2], 2);
+      else:
+         return None;
+
+   def getHour(self):
+      if self.date:
+	 return self.__padDateField(self.date[3], 2);
+      else:
+         return None;
+
+   def getMinute(self):
+      if self.date:
+	 return self.__padDateField(self.date[4], 2);
+      else:
+         return None;
+
+   def getSecond(self):
+      if self.date:
+	 return self.__padDateField(self.date[5], 2);
+      else:
+         return None;
+
+   def __padDateField(self, f, sz):
+      fStr = str(f);
+      if len(fStr) == sz:
+         pass;
+      elif len(fStr) < sz:
+         fStr = ("0" * (sz - len(fStr))) + fStr;
+      else:
+         raise TagException("Invalid date field: " + fStr);
+      return fStr;
+
+   def render(self):
+       # Conversion crap
+       if self.header.minorVersion == 4 and\
+          (self.header.id == OBSOLETE_DATE_FID or\
+           self.header.id == OBSOLETE_YEAR_FID or\
+           self.header.id == OBSOLETE_TIME_FID or\
+           self.header.id == OBSOLETE_RECORDING_DATE_FID):
+           self.header.id = "TDRC";
+       elif self.header.minorVersion == 4 and\
+            self.header.id == OBSOLETE_ORIG_RELEASE_FID:
+           self.header.id = "TDOR";
+       elif self.header.minorVersion == 3 and self.header.id == "TDOR":
+           self.header.id = OBSOLETE_ORIG_RELEASE_FID;
+       elif self.header.minorVersion == 3 and self.header.id[:2] == "TD":
+           self.header.id = OBSOLETE_YEAR_FID;
+
+       data = self.encoding + str(self.date_str);
+       data = self.assembleFrame(data);
+       return data;
+
+
+################################################################################
+class UserTextFrame(TextFrame):
+   description = u"";
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + text;
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + text;
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not USERTEXT_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for UserTextFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = USERTEXT_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("UserTextFrame encoding: %s" %\
+                id3EncodingToString(self.encoding));
+      (d, t) = splitUnicode(data[1:], self.encoding);
+      self.description = unicode(d, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserTextFrame description: %s" % self.description);
+      self.text = unicode(t, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserTextFrame text: %s" % self.text);
+
+   def render(self):
+      data = self.encoding +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" +\
+             self.text.encode(id3EncodingToString(self.encoding));
+      return self.assembleFrame(data);
+
+################################################################################
+class URLFrame(Frame):
+   url = "";
+
+   # Data string format:
+   # url
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # url
+   def set(self, data, frameHeader):
+      fid = frameHeader.id;
+      if not URL_FRAME_RX.match(fid) or USERURL_FRAME_RX.match(fid):
+         raise FrameException("Invalid frame id for URLFrame: " + fid);
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.url = data;
+
+   def render(self):
+      data = str(self.url);
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return '<%s (%s): %s>' % (self.getFrameDesc(), self.header.id,
+                                self.url);
+
+################################################################################
+class UserURLFrame(URLFrame):
+   encoding = DEFAULT_ENCODING;
+   description = u"";
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + url;
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + url;
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not USERURL_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for UserURLFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = USERURL_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("UserURLFrame encoding: %s" %\
+                id3EncodingToString(self.encoding));
+      (d, u) = splitUnicode(data[1:], self.encoding);
+      self.description = unicode(d, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserURLFrame description: %s" % self.description);
+      self.url = u;
+      TRACE_MSG("UserURLFrame text: %s" % self.url);
+
+   def render(self):
+      data = self.encoding +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" + self.url;
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return '<%s (%s): %s [Encoding: %s] [Desc: %s]>' %\
+             (self.getFrameDesc(), self.header.id,
+              self.url, self.encoding, self.description)
+
+################################################################################
+class CommentFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   lang = u"";
+   description = u"";
+   comment = u"";
+
+   # Data string format:
+   # encoding (one byte) + lang (three byte code) + description + "\x00" +
+   # text
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + lang (three byte code) + description + "\x00" +
+   # text
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not COMMENT_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for CommentFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = COMMENT_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("CommentFrame encoding: " + id3EncodingToString(self.encoding));
+      try:
+          self.lang = str(data[1:4]).strip("\x00");
+          self.lang = unicode(self.lang, "ascii");
+          if self.lang and \
+             not re.compile("[A-Z][A-Z][A-Z]", re.IGNORECASE).match(self.lang):
+             if strictID3():
+                 raise FrameException("[CommentFrame] Invalid language "\
+                                       "code: %s" % self.lang);
+      except UnicodeDecodeError, ex:
+          if strictID3():
+              raise FrameException("[CommentFrame] Invalid language code: "\
+                                   "[%s] %s" % (ex.object, ex.reason));
+          else:
+              self.lang = "";
+      try:
+         (d, c) = splitUnicode(data[4:], self.encoding);
+         self.description = unicode(d, id3EncodingToString(self.encoding));
+         self.comment = unicode(c, id3EncodingToString(self.encoding));
+      except ValueError:
+          if strictID3():
+              raise FrameException("Invalid comment; no description/comment");
+          else:
+              self.description = u"";
+              self.comment = u"";
+
+   def render(self):
+      data = self.encoding + self.lang.encode("ascii") +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" +\
+             self.comment.encode(id3EncodingToString(self.encoding));
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return "<%s (%s): %s [Lang: %s] [Desc: %s]>" %\
+             (self.getFrameDesc(), self.header.id, self.comment,
+              self.lang, self.description);
+
+################################################################################
+# This class refers to the APIC frame, otherwise known as an "attached
+# picture".
+class ImageFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   mimeType = None;
+   pictureType = None;
+   description = u"";
+   # Contains the image data when the mimetype is image type.
+   # Otherwise it is None.
+   imageData = None;
+   # Contains a URL for the image when the mimetype is "-->" per the spec.
+   # Otherwise it is None.
+   imageURL = None;
+   # Declared "picture types".
+   OTHER               = 0x00;
+   ICON                = 0x01; # 32x32 png only.
+   OTHER_ICON          = 0x02;
+   FRONT_COVER         = 0x03;
+   BACK_COVER          = 0x04;
+   LEAFLET             = 0x05;
+   MEDIA               = 0x06; # label side of cd, picture disc vinyl, etc.
+   LEAD_ARTIST         = 0x07;
+   ARTIST              = 0x08;
+   CONDUCTOR           = 0x09;
+   BAND                = 0x0A;
+   COMPOSER            = 0x0B;
+   LYRICIST            = 0x0C;
+   RECORDING_LOCATION  = 0x0D;
+   DURING_RECORDING    = 0x0E;
+   DURING_PERFORMANCE  = 0x0F;
+   VIDEO               = 0x10;
+   BRIGHT_COLORED_FISH = 0x11; # There's always room for porno.
+   ILLUSTRATION        = 0x12; 
+   BAND_LOGO           = 0x13; 
+   PUBLISHER_LOGO      = 0x14; 
+   MIN_TYPE            = OTHER;
+   MAX_TYPE            = PUBLISHER_LOGO;
+
+   def __init__(self, data = None, frameHeader = None):
+       if data:
+           self.set(data, frameHeader);
+
+   # Factory method
+   def create(type, imgFile, desc = u""):
+       if not isinstance(desc, unicode) or \
+          not isinstance(type, int):
+           raise FrameException("Wrong description and/or image-type type.");
+       # Load img
+       fp = file(imgFile, "rb");
+       imgData = fp.read();
+       mt = mimetypes.guess_type(imgFile);
+       if not mt[0]:
+           raise FrameException("Unable to guess mime-type for %s" % (imgFile));
+
+       frameData = DEFAULT_ENCODING;
+       frameData += mt[0] + "\x00";
+       frameData += bin2bytes(dec2bin(type, 8));
+       frameData += desc.encode(id3EncodingToString(DEFAULT_ENCODING)) + "\x00";
+       frameData += imgData;
+
+       return ImageFrame(frameData);
+   # Make create a static method.  Odd....
+   create = staticmethod(create);
+
+   # Data string format:
+   # <Header for 'Attached picture', ID: "APIC">
+   #  Text encoding      $xx
+   #  MIME type          <text string> $00
+   #  Picture type       $xx
+   #  Description        <text string according to encoding> $00 (00)
+   #  Picture data       <binary data>
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not IMAGE_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for ImageFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = IMAGE_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+
+      input = StringIO(data);
+      TRACE_MSG("APIC frame data size: " + str(len(data)));
+      self.encoding = input.read(1);
+      TRACE_MSG("APIC encoding: " + id3EncodingToString(self.encoding));
+
+      self.mimeType = "";
+      ch = input.read(1);
+      while ch != "\x00":
+         self.mimeType += ch;
+         ch = input.read(1);
+      TRACE_MSG("APIC mime type: " + self.mimeType);
+      if strictID3() and not self.mimeType:
+         raise FrameException("APIC frame does not contain a mime type");
+      if self.mimeType.find("/") == -1:
+         self.mimeType = "image/" + self.mimeType;
+
+      pt = ord(input.read(1));
+      TRACE_MSG("Initial APIC picture type: " + str(pt));
+      if pt < self.MIN_TYPE or pt > self.MAX_TYPE:
+          if strictID3():
+              raise FrameException("Invalid APIC picture type: %d" % (pt));
+          # Rather than force this to UNKNOWN, let's assume that they put a
+          # character literal instead of it's byte value.
+          try:
+              pt = int(chr(pt));
+          except:
+              pt = self.OTHER;
+          if pt < self.MIN_TYPE or pt > self.MAX_TYPE:
+              self.pictureType = self.OTHER;
+      self.pictureType = pt;
+      TRACE_MSG("APIC picture type: " + str(self.pictureType));
+
+      self.desciption = u"";
+      buffer = "";
+      ch = input.read(1);
+      while ch != "\x00":
+         buffer += ch;
+         ch = input.read(1);
+      self.description = unicode(buffer, id3EncodingToString(self.encoding));
+      TRACE_MSG("APIC description: " + self.description);
+
+      if self.mimeType.find("-->") != -1:
+         self.imageData = None;
+         self.imageURL = input.read();
+      else:
+         self.imageData = input.read();
+         self.imageURL = None;
+      TRACE_MSG("APIC image data: " + str(len(self.imageData)) + " bytes");
+      if strictID3() and not self.imageData and not self.imageURL:
+         raise FrameException("APIC frame does not contain any image data");
+
+      input.close();
+
+   def writeFile(self, path = "./", name = None):
+      if not self.imageData:
+         raise IOError("Fetching remote image files is not implemented.");
+      if not name:
+         name = self.getDefaultFileName();
+      imageFile = os.path.join(path, name);
+
+      f = file(imageFile, "wb");
+      f.write(self.imageData);
+      f.flush();
+      f.close();
+   def getDefaultFileName(self):
+      nameStr = self.picTypeToString(self.pictureType);
+      nameStr = nameStr +  "." + self.mimeType.split("/")[1];
+      return nameStr;
+
+   def render(self):
+      data = self.encoding + self.mimeType + "\x00" +\
+             bin2bytes(dec2bin(self.pictureType, 8)) +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00";
+      if self.imageURL:
+          data += self.imageURL.encode("ascii");
+      else:
+          data += self.imageData;
+      return self.assembleFrame(data);
+
+   def stringToPicType(self, s):
+       if s == "OTHER":
+           return self.OTHER;
+       elif s == "ICON":
+           return self.ICON;
+       elif s == "OTHER_ICON":
+           return self.OTHER_ICON;
+       elif s == "FRONT_COVER":
+           return self.FRONT_COVER
+       elif s == "BACK_COVER":
+           return self.BACK_COVER;
+       elif s == "LEAFLET":
+           return self.LEAFLET;
+       elif s == "MEDIA":
+           return self.MEDIA;
+       elif s == "LEAD_ARTIST":
+           return self.LEAD_ARTIST;
+       elif s == "ARTIST":
+           return self.ARTIST;
+       elif s == "CONDUCTOR":
+           return self.CONDUCTOR;
+       elif s == "BAND":
+           return self.BAND;
+       elif s == "COMPOSER":
+           return self.COMPOSER;
+       elif s == "LYRICIST":
+           return self.LYRICIST;
+       elif s == "RECORDING_LOCATION":
+           return self.RECORDING_LOCATION;
+       elif s == "DURING_RECORDING":
+           return self.DURING_RECORDING;
+       elif s == "DURING_PERFORMANCE":
+           return self.DURING_PERFORMANCE;
+       elif s == "VIDEO":
+           return self.VIDEO;
+       elif s == "BRIGHT_COLORED_FISH":
+           return self.BRIGHT_COLORED_FISH;
+       elif s == "ILLUSTRATION":
+           return self.ILLUSTRATION;
+       elif s == "BAND_LOGO":
+           return self.BAND_LOGO;
+       elif s == "PUBLISHER_LOGO":
+           return self.PUBLISHER_LOGO;
+       else:
+         raise FrameException("Invalid APIC picture type: %s" % s);
+
+   def picTypeToString(self, t):
+      if t == self.OTHER:
+         return "OTHER";
+      elif t == self.ICON:
+         return "ICON";
+      elif t == self.OTHER_ICON:
+         return "OTHER_ICON";
+      elif t == self.FRONT_COVER:
+         return "FRONT_COVER";
+      elif t == self.BACK_COVER:
+         return "BACK_COVER";
+      elif t == self.LEAFLET:
+         return "LEAFLET";
+      elif t == self.MEDIA:
+         return "MEDIA";
+      elif t == self.LEAD_ARTIST:
+         return "LEAD_ARTIST";
+      elif t == self.ARTIST:
+         return "ARTIST";
+      elif t == self.CONDUCTOR:
+         return "CONDUCTOR";
+      elif t == self.BAND:
+         return "BAND";
+      elif t == self.COMPOSER:
+         return "COMPOSER";
+      elif t == self.LYRICIST:
+         return "LYRICIST";
+      elif t == self.RECORDING_LOCATION:
+         return "RECORDING_LOCATION";
+      elif t == self.DURING_RECORDING:
+         return "DURING_RECORDING";
+      elif t == self.DURING_PERFORMANCE:
+         return "DURING_PERFORMANCE";
+      elif t == self.VIDEO:
+         return "VIDEO";
+      elif t == self.BRIGHT_COLORED_FISH:
+         return "BRIGHT_COLORED_FISH";
+      elif t == self.ILLUSTRATION:
+         return "ILLUSTRATION";
+      elif t == self.BAND_LOGO:
+         return "BAND_LOGO";
+      elif t == self.PUBLISHER_LOGO:
+         return "PUBLISHER_LOGO";
+      else:
+         raise FrameException("Invalid APIC picture type: %d" % t);
+
+################################################################################
+class UnknownFrame(Frame):
+   data = "";
+
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   def set(self, data, frameHeader):
+      self.header = frameHeader;
+      data = self.disassembleFrame(data);
+      self.data = data;
+
+   def render(self):
+      return self.assembleFrame(self.data)
+
+################################################################################
+class MusicCDIdFrame(Frame):
+   toc = "";
+
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # TODO: Parse the TOC and comment the format.
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not CDID_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for MusicCDIdFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = CDID_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.toc = data;
+
+   def render(self):
+      data = self.toc;
+      return self.assembleFrame(data);
+
+################################################################################
+# A class for containing and managing ID3v2.Frame objects.
+class FrameSet(list):
+   tagHeader = None;
+
+   def __init__(self, tagHeader, l = None):
+      self.tagHeader = tagHeader;
+      if l:
+         for f in l:
+            if not isinstance(f, Frame):
+               raise TypeError("Invalid type added to FrameSet: " +\
+                               f.__class__);
+            self.append(f);
+
+   # Setting a FrameSet instance like this 'fs = []' morphs the instance into
+   # a list object.
+   def clear(self):
+      del self[0:];
+
+   # Read frames starting from the current read position of the file object.
+   # Returns the amount of padding which occurs after the tag, but before the
+   # audio content.  A return valule of 0 DOES NOT imply an error.
+   def parse(self, f, tagHeader):
+      self.tagHeader = tagHeader;
+      paddingSize = 0;
+      sizeLeft = tagHeader.tagSize;
+
+      # Handle a tag-level unsync.  Some frames may have their own unsync bit
+      # set instead.
+      tagData = f.read(sizeLeft);
+      if tagHeader.unsync:
+         TRACE_MSG("Tag has unsync bit set");
+         tagData = deunsyncData(tagData);
+         sizeLeft = len(tagData);
+      # Adding 10 to simulate the tag header in the buffer.  This keeps 
+      # f.tell() values the same as in the file.
+      tagBuffer = StringIO((10 * '\x00') + tagData);
+      tagBuffer.seek(10);
+      tagBuffer.tell();
+
+      while sizeLeft > 0:
+         TRACE_MSG("sizeLeft: " + str(sizeLeft));
+         if sizeLeft < (10 + 1):
+            TRACE_MSG("FrameSet: Implied padding (sizeLeft < minFrameSize)");
+            paddingSize = sizeLeft;
+            break;
+
+         TRACE_MSG("+++++++++++++++++++++++++++++++++++++++++++++++++");
+         TRACE_MSG("FrameSet: Reading Frame #" + str(len(self) + 1));
+         frameHeader = FrameHeader(tagHeader);
+         if not frameHeader.parse(tagBuffer):
+            paddingSize = sizeLeft;
+            break;
+
+         # Frame data.
+         TRACE_MSG("FrameSet: Reading %d (0x%X) bytes of data from byte "\
+                   "pos %d (0x%X)" % (frameHeader.dataSize,
+                                      frameHeader.dataSize, tagBuffer.tell(),
+                                      tagBuffer.tell()));
+         data = tagBuffer.read(frameHeader.dataSize);
+         TRACE_MSG("FrameSet: %d bytes of data read" % len(data));
+
+         self.addFrame(createFrame(frameHeader, data));
+
+         # Each frame contains dataSize + headerSize(10) bytes.
+         sizeLeft -= (frameHeader.FRAME_HEADER_SIZE + frameHeader.dataSize);
+
+      return paddingSize;
+
+   # Returrns the size of the frame data.
+   def getSize(self):
+      sz = 0;
+      for f in self:
+         sz += len(f.render());
+      return sz;
+   
+   def setTagHeader(self, tagHeader):
+      self.tagHeader = tagHeader;
+      for f in self:
+         f.header.setVersion(tagHeader);
+
+   # This methods adds the frame if it is addable per the ID3 spec.
+   def addFrame(self, frame):
+      fid = frame.header.id;
+
+      # Text frame restrictions.
+      # No multiples except for TXXX which must have unique descriptions.
+      if strictID3() and TEXT_FRAME_RX.match(fid) and self[fid]:
+         if not USERTEXT_FRAME_RX.match(fid):
+            raise FrameException("Multiple %s frames now allowed." % fid);
+         userTextFrames = self[fid];
+         for frm in userTextFrames:
+            if frm.description == frame.description:
+               raise FrameException("Multiple %s frames with the same\
+                                     description now allowed." % fid);
+
+      # Comment frame restrictions.
+      # Multiples must have a unique description/language combination.
+      if strictID3() and COMMENT_FRAME_RX.match(fid) and self[fid]:
+         commentFrames = self[fid];
+         for frm in commentFrames:
+            if frm.description == frame.description and\
+               frm.lang == frame.lang:
+               raise FrameException("Multiple %s frames with the same\
+                                     language and description now allowed." %\
+                                     fid);
+
+      # URL frame restrictions.
+      # No multiples except for TXXX which must have unique descriptions.
+      if strictID3() and URL_FRAME_RX.match(fid) and self[fid]:
+         if not USERURL_FRAME_RX.match(fid):
+            raise FrameException("Multiple %s frames now allowed." % fid);
+         userUrlFrames = self[fid];
+         for frm in userUrlFrames:
+            if frm.description == frame.description:
+               raise FrameException("Multiple %s frames with the same\
+                                     description now allowed." % fid);
+
+      # Music CD ID restrictions.
+      # No multiples.
+      if strictID3() and CDID_FRAME_RX.match(fid) and self[fid]:
+         raise FrameException("Multiple %s frames now allowed." % fid);
+
+      # Image (attached picture) frame restrictions.
+      # Multiples must have a unique content desciptor.  I'm assuming that
+      # the spec means the picture type.....
+      if IMAGE_FRAME_RX.match(fid) and self[fid]:
+         imageFrames = self[fid];
+         for frm in imageFrames:
+            if frm.pictureType == frame.pictureType:
+               raise FrameException("Multiple %s frames with the same\
+                                     content descriptor now allowed." % fid);
+      self.append(frame);
+
+   # Set a text frame value.  Text frame IDs must be unique.  If a frame with
+   # the same Id is already in the list it's value is changed, otherwise
+   # the frame is added.
+   def setTextFrame(self, frameId, text, encoding = DEFAULT_ENCODING):
+      if not TEXT_FRAME_RX.match(frameId):
+         raise FrameException("Invalid Frame ID: " + frameId);
+      if USERTEXT_FRAME_RX.match(frameId):
+         raise FrameException("Wrong method, use setUserTextFrame");
+
+      if self[frameId]:
+          curr = self[frameId][0];
+          curr.encoding = encoding;
+          if isinstance(curr, DateFrame):
+              curr.setDate(text);
+          else:
+              curr.text = text;
+      else:
+          h = FrameHeader(self.tagHeader);
+          h.id = frameId;
+          self.addFrame(createFrame(h, encoding + text));
+
+   # If a comment frame with the same language and description exists then
+   # the comment text is replaced, otherwise the frame is added.
+   def setCommentFrame(self, comment, description, lang = DEFAULT_LANG,
+                       encoding = DEFAULT_ENCODING):
+
+      if self[COMMENT_FID]:
+         found = 0;
+         for f in self[COMMENT_FID]:
+            if f.lang == lang and f.description == description:
+               f.comment = comment;
+               f.encoding = encoding;
+               found = 1;
+               break;
+         if not found:
+            h = FrameHeader(self.tagHeader);
+            h.id = COMMENT_FID;
+            self.addFrame(CommentFrame(encoding + lang + description + "\x00" +
+                                       comment, h));
+      else:
+         h = FrameHeader(self.tagHeader);
+         h.id = COMMENT_FID;
+         self.addFrame(CommentFrame(encoding + lang + description + "\x00" +
+                                    comment, h));
+         
+   # This method removes all frames with the matching frame ID.
+   # The number of frames removed is returned.
+   # Note that calling this method with a key like "COMM" may remove more
+   # frames then you really want.
+   def removeFramesByID(self, fid):
+      if not isinstance(fid, str):
+         raise FrameException("removeFramesByID only operates on frame IDs");
+
+      i = 0;
+      count = 0;
+      while i < len(self):
+         if self[i].header.id == fid:
+            del self[i];
+            count += 1;
+         else:
+            i += 1;
+      return count;
+
+   # Removes the frame at index.  True is returned if the element was
+   # removed, and false otherwise.
+   def removeFrameByIndex(self, index):
+      if not isinstance(index, int):
+         raise\
+           FrameException("removeFrameByIndex only operates on a frame index");
+      try:
+         del self.frames[key];
+         return 1;
+      except:
+         return 0;
+
+   # Accepts both int (indexed access) and string keys (a valid frame Id).
+   # A list of frames (commonly with only one element) is returned when the
+   # FrameSet is accessed using frame IDs since some frames can appear
+   # multiple times in a tag.  To sum it all up htis method returns
+   # string or None when indexed using an integer, and a 0 to N length
+   # list of strings when indexed with a frame ID.
+   #
+   # Throws IndexError and TypeError.
+   def __getitem__(self, key):
+      if isinstance(key, int):
+         if key >= 0 and key < len(self):
+            return list.__getitem__(self, key);
+         else:
+            raise IndexError("FrameSet index out of range");
+      elif isinstance(key, str):
+         retList = list();
+         for f in self:
+            if f.header.id == key:
+               retList.append(f);
+         return retList;
+      else:
+         raise TypeError("FrameSet key must be type int or string");
+
+#  Mmmmm!  Cheesy!
+def splitUnicode(data, encoding):
+    if encoding == LATIN1_ENCODING or encoding == UTF_8_ENCODING or\
+       encoding == UTF_16BE_ENCODING:
+        return data.split("\x00", 1);
+    elif encoding == UTF_16_ENCODING:
+        (d, t) = data.split("\x00\x00\x00", 1);
+        d += "\x00";
+        t += "\x00";
+        return (d, t);
+
+
+#######################################################################
+# Create and return the appropriate frame.
+# Exceptions: ....
+def createFrame(frameHeader, data):
+  f = None;
+
+  # Text Frames
+  if TEXT_FRAME_RX.match(frameHeader.id):
+     if USERTEXT_FRAME_RX.match(frameHeader.id):
+        f = UserTextFrame(data, frameHeader);
+     else:
+        if frameHeader.id[:2] == "TD" or\
+           frameHeader.id == OBSOLETE_DATE_FID or\
+           frameHeader.id == OBSOLETE_YEAR_FID or \
+           frameHeader.id == OBSOLETE_ORIG_RELEASE_FID:
+           f = DateFrame(data, frameHeader);
+        else:
+           f = TextFrame(data, frameHeader);
+
+  # Comment Frames.
+  elif COMMENT_FRAME_RX.match(frameHeader.id):
+     f = CommentFrame(data, frameHeader);
+
+  # URL Frames.
+  elif URL_FRAME_RX.match(frameHeader.id):
+     if USERURL_FRAME_RX.match(frameHeader.id):
+        f = UserURLFrame(data, frameHeader);
+     else:
+        f = URLFrame(data, frameHeader);
+
+  # CD Id frame.
+  elif CDID_FRAME_RX.match(frameHeader.id):
+     f = MusicCDIdFrame(data, frameHeader);
+
+  # Attached picture
+  elif IMAGE_FRAME_RX.match(frameHeader.id):
+     f = ImageFrame(data, frameHeader);
+
+  if f == None:
+     f = UnknownFrame(data, frameHeader);
+
+  return f;
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/__init__.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/__init__.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/__init__.py	(revision 4)
@@ -0,0 +1,38 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+
+eyeD3Version = "0.6.1"
+eyeD3Maintainer = "Travis Shirk <travis@pobox.com>"
+
+# Version constants
+ID3_CURRENT_VERSION = 0x00; # The version of the linked tag, if any.
+ID3_V1              = 0x10;
+ID3_V1_0            = 0x11;
+ID3_V1_1            = 0x12;
+ID3_V2              = 0x20;
+#ID3_V2_2            = 0x21; # All versions < v2.3 are obsolete.
+ID3_V2_3            = 0x22;
+ID3_V2_4            = 0x24;
+#ID3_V2_5            = 0x28; # This does not seem imminent.
+ID3_DEFAULT_VERSION = ID3_V2_4;
+ID3_ANY_VERSION     = ID3_V1 | ID3_V2;
+
+from tag import *;
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/mp3.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/mp3.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/mp3.py	(revision 4)
@@ -0,0 +1,321 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+from binfuncs import *;
+from utils import *;
+
+#######################################################################
+class Mp3Exception:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+
+#                   MPEG1  MPEG2  MPEG2.5
+SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
+                     (48000, 24000, 12000),
+                     (32000, 16000, 8000),
+                     (None,  None,  None));
+
+#              V1/L1  V1/L2 V1/L3 V2/L1 V2/L2&L3 
+BIT_RATE_TABLE = ((0,    0,    0,    0,    0),
+                  (32,   32,   32,   32,   8),
+                  (64,   48,   40,   48,   16),
+                  (96,   56,   48,   56,   24),
+                  (128,  64,   56,   64,   32),
+                  (160,  80,   64,   80,   40),
+                  (192,  96,   80,   96,   44),
+                  (224,  112,  96,   112,  56),
+                  (256,  128,  112,  128,  64),
+                  (288,  160,  128,  144,  80),
+                  (320,  192,  160,  160,  96),
+                  (352,  224,  192,  176,  112),
+                  (384,  256,  224,  192,  128),
+                  (416,  320,  256,  224,  144),
+                  (448,  384,  320,  256,  160),
+                  (None, None, None, None, None));
+
+#                             L1    L2    L3
+TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
+
+# Emphasis constants
+EMPHASIS_NONE = "None";
+EMPHASIS_5015 = "50/15 ms";
+EMPHASIS_CCIT = "CCIT J.17";
+
+# Mode constants
+MODE_STEREO              = "Stereo";
+MODE_JOINT_STEREO        = "Joint stereo";
+MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
+MODE_MONO                = "Mono";
+
+# Flag bits
+FRAMES_FLAG    = 0x0001
+BYTES_FLAG     = 0x0002
+TOC_FLAG       = 0x0004
+VBR_SCALE_FLAG = 0x0008
+
+#######################################################################
+def computeTimePerFrame(frameHeader):
+   tpf = TIME_PER_FRAME_TABLE[frameHeader.layer];
+   tpf = float(tpf) / float(frameHeader.sampleFreq);
+   return tpf;
+
+#######################################################################
+class Header:
+   version = float();
+   layer = int();
+   errorProtection = 0;
+   bitRate = int();
+   playTime = long();
+   sampleFreq = int();
+   padding = 0;
+   privateBit = 0;
+   copyright = 0;
+   original = 0;
+   emphasis = str();
+   mode = str();
+   # This value is left as is: 0 <= modeExtension <= 3.  Consult the
+   # mp3 spec here http://www.dv.co.yu/mpgscript/mpeghdr.htm if you wish to 
+   # interpret it.
+   modeExtension = 0;
+
+   # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
+   # header.
+   def isValid(self, header):
+      # Test for the mp3 frame sync: 11 set bits.
+      if (header & 0xffe00000L) != 0xffe00000L:
+         return 0;
+      if not ((header >> 17) & 3):
+         return 0;
+      if ((header >> 12) & 0xf) == 0xf:
+         return 0;
+      if not ((header >> 12) & 0xf):
+         return 0;
+      if ((header >> 10) & 0x3) == 0x3:
+         return 0;
+      if (((header >> 19) & 1) == 1) and (((header >> 17) & 3) == 3) and \
+         (((header >> 16) & 1) == 1):
+         return 0;
+      if (header & 0xffff0000L) == 0xfffe0000L:
+         return 0;
+
+      return 1;
+
+   # This may throw an Mp3Exception if the header is malformed.
+   def decode(self, header):
+      # MPEG audio version from bits 19 and 20.
+      if not header & (1 << 20) and header & (1 << 19):
+         raise Mp3Exception("Illegal MPEG audio version");
+      elif not header & (1 << 20) and not header & (1 << 19):
+         self.version = 2.5;
+      else:
+         if not header & (1 << 19):
+            self.version = 2.0;
+         else:
+            self.version = 1.0;
+
+      
+      # MPEG audio layer from bits 18 and 17.
+      if not header & (1 << 18) and not header & (1 << 17):
+         raise Mp3Exception("Illegal MPEG layer value");
+      elif not header & (1 << 18) and header & (1 << 17):
+         self.layer = 3;
+      elif header & (1 << 18) and not header & (1 << 17):
+         self.layer = 2;
+      else:
+         self.layer = 1;
+
+      # Decode some simple values.
+      self.errorProtection = not (header >> 16) & 0x1;
+      self.padding = (header >> 9) & 0x1;
+      self.privateBit = (header >> 8) & 0x1;
+      self.copyright = (header >> 3) & 0x1;
+      self.original = (header >> 2) & 0x1;
+
+      # Obtain sampling frequency.
+      sampleBits = (header >> 10) & 0x3;
+      if self.version == 2.5:
+         freqCol = 2;
+      else:
+         freqCol = int(self.version - 1);
+      self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
+      if not self.sampleFreq:
+         raise Mp3Exception("Illegal MPEG sampling frequency");
+
+
+      # Compute bitrate.
+      bitRateIndex = (header >> 12) & 0xf;
+      if int(self.version) == 1 and self.layer == 1:
+         bitRateCol = 0;
+      elif int(self.version) == 1 and self.layer == 2:
+         bitRateCol = 1;
+      elif int(self.version) == 1 and self.layer == 3:
+         bitRateCol = 2;
+      elif int(self.version) == 2 and self.layer == 1:
+         bitRateCol = 3;
+      elif int(self.version) == 2 and (self.layer == 2 or \
+                                       self.layer == 3):
+         bitRateCol = 4;
+      else:
+         raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
+                            "combination" % (self.version, self.layer));
+      self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
+      if self.bitRate == None:
+         raise Mp3Exception("Invalid bit rate");
+      # We know know the bit rate specified in this frame, but if the file
+      # is VBR we need to obtain the average from the Xing header.
+      # This is done by the caller since right now all we have is the frame
+      # header.
+
+      # Emphasis; whatever that means??
+      emph = header & 0x3;
+      if emph == 0:
+         self.emphasis = EMPHASIS_NONE;
+      elif emph == 1:
+         self.emphasis = EMPHASIS_5015;
+      elif emph == 2:
+         self.emphasis = EMPHASIS_CCIT;
+      elif strictID3():
+         raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
+
+      # Channel mode.
+      modeBits = (header >> 6) & 0x3;
+      if modeBits == 0:
+         self.mode = MODE_STEREO;
+      elif modeBits == 1:
+         self.mode = MODE_JOINT_STEREO;
+      elif modeBits == 2:
+         self.mode = MODE_DUAL_CHANNEL_STEREO;
+      else:
+         self.mode = MODE_MONO;
+      self.modeExtension = (header >> 4) & 0x3; 
+
+      # Layer II has restrictions wrt to mode and bit rate.  This code
+      # enforces them.
+      if self.layer == 2:
+         m = self.mode;
+         br = self.bitRate;
+         if (br == 32 or br == 48 or br == 56 or br == 80) and \
+            (m != MODE_MONO):
+            raise Mp3Exception("Invalid mode/bitrate combination for layer "\
+                               "II");
+         if (br == 224 or br == 256 or br == 320 or br == 384) and \
+            (m == MODE_MONO):
+            raise Mp3Exception("Invalid mode/bitrate combination for layer "\
+                               "II");
+
+      br = self.bitRate * 1000;
+      sf = self.sampleFreq;
+      p  = self.padding;
+      if self.layer == 1:
+         # Layer 1 uses 32 bit slots for padding.
+         p  = self.padding * 4;
+         self.frameLength = int((((12 * br) / sf) + p) * 4);
+      else:
+         # Layer 2 and 3 uses 8 bit slots for padding.
+         p  = self.padding * 1;
+         self.frameLength = int(((144 * br) / sf) + p);
+
+      # Dump the state.
+      TRACE_MSG("MPEG audio version: " + str(self.version));
+      TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
+      TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
+      TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
+      TRACE_MSG("MPEG channel mode: " + self.mode);
+      TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
+      TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
+      TRACE_MSG("MPEG original: " + str(self.original));
+      TRACE_MSG("MPEG copyright: " + str(self.copyright));
+      TRACE_MSG("MPEG private bit: " + str(self.privateBit));
+      TRACE_MSG("MPEG padding: " + str(self.padding));
+      TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
+      TRACE_MSG("MPEG frame length: " + str(self.frameLength));
+
+#######################################################################
+class XingHeader:
+   numFrames = int();
+   numBytes = int();
+   toc = [0] * 100;
+   vbrScale = int();
+
+   # Pass in the first mp3 frame from the file as a byte string.
+   # If an Xing header is present in the file it'll be in the first mp3
+   # frame.  This method returns true if the Xing header is found in the
+   # frame, and false otherwise.
+   def decode(self, frame):
+      # mp3 version
+      id      = (ord(frame[1]) >> 3) & 0x1;
+      # channel mode.
+      mode    = (ord(frame[3]) >> 6) & 0x3;
+
+      # Find the start of the Xing header.
+      if id:
+         if mode != 3:
+            pos = 32 + 4;
+         else:
+            pos = 17 + 4;
+      else:
+         if mode != 3:
+            pos = 17 + 4;
+         else:
+            pos = 9 + 4;
+      if frame[pos] != 'X' or frame[pos + 1] != 'i' or \
+         frame[pos + 2] != 'n' or frame[pos + 3] != 'g':
+         return 0;
+      TRACE_MSG("Xing header detected");
+      pos += 4;
+
+      # Read Xing flags.
+      headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
+      pos += 4;
+      TRACE_MSG("Xing header flags: 0x%x" % headFlags);
+
+      # Read frames header flag and value if present
+      if headFlags & FRAMES_FLAG:
+         self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing numFrames: %d" % self.numFrames);
+
+      # Read bytes header flag and value if present
+      if headFlags & BYTES_FLAG:
+         self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing numBytes: %d" % self.numBytes);
+
+      # Read TOC header flag and value if present
+      if headFlags & TOC_FLAG:
+         i = 0;
+         self.toc = frame[pos:pos + 100];
+         pos += 100;
+         TRACE_MSG("Xing TOC (100 bytes): PRESENT");
+      else:
+         TRACE_MSG("Xing TOC (100 bytes): NOT PRESENT");
+
+      # Read vbr scale header flag and value if present
+      if headFlags & VBR_SCALE_FLAG:
+         self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing vbrScale: %d" % self.vbrScale);
+
+      return 1;
Index: trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/utils.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/utils.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/audio/eyeD3/utils.py	(revision 4)
@@ -0,0 +1,85 @@
+################################################################################
+#  Copyright (C) 2003-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#  $Id: utils.py,v 1.3 2004/05/14 14:44:59 outlyer Exp $
+################################################################################
+from mmpython.audio.eyeD3 import *
+
+def versionsToConstant(v):
+   major = v[0];
+   minor = v[1];
+   rev = v[2];
+   if major == 1:
+      if minor == 0:
+	 return ID3_V1_0;
+      elif minor == 1:
+	 return ID3_V1_1;
+   elif major == 2:
+      if minor == 3:
+	 return ID3_V2_3;
+      elif minor == 4:
+	 return ID3_V2_4;
+   raise str("Invalid ID3 version: %s" % str(v));
+
+def versionToString(v):
+   if v & ID3_V1:
+      if v == ID3_V1_0:
+	 return "v1.0";
+      elif v == ID3_V1_1:
+	 return "v1.1";
+      elif v == ID3_V1:
+         return "v1.x";
+   elif v & ID3_V2:
+      if v == ID3_V2_3:
+	 return "v2.3";
+      elif v == ID3_V2_4:
+	 return "v2.4";
+      elif v == ID3_V2:
+         return "v2.x";
+
+   if v == ID3_ANY_VERSION:
+      return "v1.x/v2.x";
+   raise str("versionToString - Invalid ID3 version constant: %s" % hex(v));
+
+def constantToVersions(v):
+   if v & ID3_V1:
+      if v == ID3_V1_0:
+         return [1, 0, 0];
+      elif v == ID3_V1_1:
+         return [1, 1, 0];
+      elif v == ID3_V1:
+         return [1, 1, 0];
+   elif v & ID3_V2:
+      if v == ID3_V2_3:
+         return [2, 3, 0];
+      elif v == ID3_V2_4:
+         return [2, 4, 0];
+      elif v == ID3_V2:
+         return [2, 4, 0];
+   raise str("constantToVersions - Invalid ID3 version constant: %s" % hex(v));
+
+################################################################################
+TRACE = 0;
+prefix = "eyeD3 trace> ";
+def TRACE_MSG(msg):
+   if TRACE:
+      print prefix + msg;
+
+STRICT_ID3 = 0;
+def strictID3():
+   return STRICT_ID3;
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/doc/generate
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/doc/generate	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/doc/generate	(revision 4)
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# doc.sh 
+#
+# Dirk Meyer  <dmeyer@tzi.de>
+# $Id: generate,v 1.1 2003/06/08 17:33:59 dischi Exp $
+
+cd `dirname $0`
+
+export PYTHONPATH=../..:$PYTHONPATH
+
+files=`find .. -name \*.py | sed 's/\.py//' | sed 's/^..\//mmpython\//' |\
+     sed 's/\//./g' | sed 's/\.$//' | egrep -v '(build\.|setup|mediatest|cachedir)'`
+
+dirs=`find .. -name __init__.py | grep -v build | sed 's/.__init__.py//' |\
+    sed 's/^..\//mmpython\//' | sed 's/\//./g' | grep -v \\.\\.`
+
+pydoc -w mmpython $files $dirs
+
+# end of doc.sh 
Index: trunk/src/testing/bin/fileServer/misc/mmpython/doc/.cvsignore
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/doc/.cvsignore	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/doc/.cvsignore	(revision 4)
@@ -0,0 +1,2 @@
+*.pyc *.html
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/mpeginfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/mpeginfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/mpeginfo.py	(revision 4)
@@ -0,0 +1,897 @@
+#if 0
+# $Id: mpeginfo.py,v 1.33 2005/02/15 18:52:51 dischi Exp $
+# $Log: mpeginfo.py,v $
+# Revision 1.33  2005/02/15 18:52:51  dischi
+# some strange bugfix (what is this doing?)
+#
+# Revision 1.32  2005/01/21 16:37:02  dischi
+# try to find bad timestamps
+#
+# Revision 1.31  2005/01/08 12:06:45  dischi
+# make sure the buffer is big enough
+#
+# Revision 1.30  2005/01/02 14:57:27  dischi
+# detect ac3 in normal mpeg2
+#
+# Revision 1.29  2004/11/27 14:42:12  dischi
+# remove future warning
+#
+# Revision 1.28  2004/11/15 21:43:36  dischi
+# remove bad debugging stuff
+#
+# Revision 1.27  2004/11/12 18:10:45  dischi
+# add ac3 support in mpeg streams
+#
+# Revision 1.26  2004/10/04 18:06:54  dischi
+# test length of remaining buffer
+#
+# Revision 1.25  2004/07/11 19:37:25  dischi
+# o read more bytes on ts scan
+# o support for AC3 in private streams
+#
+# Revision 1.24  2004/07/03 09:01:32  dischi
+# o fix PES start detection inside TS
+# o try to find out if the stream is progressive or interlaced
+#
+# Revision 1.23  2004/06/23 19:44:10  dischi
+# better length detection, big cleanup
+#
+# Revision 1.22  2004/06/22 21:37:34  dischi
+# o PES support
+# o basic length detection for TS and PES
+#
+# Revision 1.21  2004/06/21 20:37:34  dischi
+# basic support for mpeg-ts
+#
+# Revision 1.20  2004/03/13 23:41:59  dischi
+# add AudioInfo to mpeg for all streams
+#
+# Revision 1.19  2004/02/11 20:11:54  dischi
+# Updated length calculation for mpeg files. This may not work for all files.
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import os
+import struct
+import string
+import fourcc
+
+from mmpython import mediainfo
+import mmpython
+import stat
+
+##------------------------------------------------------------------------
+## START_CODE
+##
+## Start Codes, with 'slice' occupying 0x01..0xAF
+##------------------------------------------------------------------------
+START_CODE = {
+    0x00 : 'picture_start_code',
+    0xB0 : 'reserved',
+    0xB1 : 'reserved',
+    0xB2 : 'user_data_start_code',
+    0xB3 : 'sequence_header_code',
+    0xB4 : 'sequence_error_code',
+    0xB5 : 'extension_start_code',
+    0xB6 : 'reserved',
+    0xB7 : 'sequence end',
+    0xB8 : 'group of pictures',
+}
+for i in range(0x01,0xAF): 
+    START_CODE[i] = 'slice_start_code'
+
+##------------------------------------------------------------------------
+## START CODES
+##------------------------------------------------------------------------
+PICTURE   = 0x00
+USERDATA  = 0xB2
+SEQ_HEAD  = 0xB3
+SEQ_ERR   = 0xB4
+EXT_START = 0xB5
+SEQ_END   = 0xB7
+GOP       = 0xB8
+
+SEQ_START_CODE  = 0xB3
+PACK_PKT        = 0xBA
+SYS_PKT         = 0xBB
+PADDING_PKT     = 0xBE
+AUDIO_PKT       = 0xC0
+VIDEO_PKT       = 0xE0
+PRIVATE_STREAM1 = 0xBD
+PRIVATE_STREAM2 = 0xBf
+
+TS_PACKET_LENGTH = 188
+TS_SYNC          = 0x47
+
+##------------------------------------------------------------------------
+## FRAME_RATE
+##
+## A lookup table of all the standard frame rates.  Some rates adhere to
+## a particular profile that ensures compatibility with VLSI capabilities
+## of the early to mid 1990s.
+##
+## CPB
+##   Constrained Parameters Bitstreams, an MPEG-1 set of sampling and 
+##   bitstream parameters designed to normalize decoder computational 
+##   complexity, buffer size, and memory bandwidth while still addressing 
+##   the widest possible range of applications.
+##
+## Main Level
+##   MPEG-2 Video Main Profile and Main Level is analogous to MPEG-1's 
+##   CPB, with sampling limits at CCIR 601 parameters (720x480x30 Hz or 
+##   720x576x24 Hz). 
+##
+##------------------------------------------------------------------------ 
+FRAME_RATE = [ 
+      0, 
+      round(24000.0/1001*100)/100, ## 3-2 pulldown NTSC (CPB/Main Level)
+      24,           ## Film (CPB/Main Level)
+      25,           ## PAL/SECAM or 625/60 video
+      round(30000.0/1001*100)/100, ## NTSC (CPB/Main Level)
+      30,           ## drop-frame NTSC or component 525/60  (CPB/Main Level)
+      50,           ## double-rate PAL
+      round(60000.0/1001*100)/100, ## double-rate NTSC
+      60,           ## double-rate, drop-frame NTSC/component 525/60 video
+      ]
+
+##------------------------------------------------------------------------
+## ASPECT_RATIO -- INCOMPLETE?
+##
+## This lookup table maps the header aspect ratio index to a common name.
+## These are just the defined ratios for CPB I believe.  As I understand 
+## it, a stream that doesn't adhere to one of these aspect ratios is
+## technically considered non-compliant.
+##------------------------------------------------------------------------ 
+ASPECT_RATIO = [ 'Forbidden',
+                 '1/1 (VGA)',
+                 '4/3 (TV)',
+                 '16/9 (Large TV)',
+                 '2.21/1 (Cinema)',
+               ]
+ 
+
+class MpegInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.sequence_header_offset = 0
+
+        # detect TS (fast scan)
+        self.valid = self.isTS(file) 
+
+        if not self.valid:
+            # detect system mpeg (many infos)
+            self.valid = self.isMPEG(file) 
+
+        if not self.valid:
+            # detect PES
+            self.valid = self.isPES(file) 
+            
+        if self.valid:       
+            self.mime = 'video/mpeg'
+            if not self.video:
+                self.video.append(mediainfo.VideoInfo())
+
+            if self.sequence_header_offset <= 0:
+                return
+
+            self.progressive(file)
+            
+            for vi in self.video:
+                vi.width, vi.height = self.dxy(file)
+                vi.fps, vi.aspect = self.framerate_aspect(file)
+                vi.bitrate = self.bitrate(file)
+                if self.length:
+                    vi.length = self.length
+
+            if not self.type:
+                if self.video[0].width == 480:
+                    self.type = 'MPEG2 video' # SVCD spec
+                elif self.video[0].width == 352:
+                    self.type = 'MPEG1 video' # VCD spec
+                else:
+                    self.type = 'MPEG video'
+
+            if mediainfo.DEBUG > 2:
+                self.__scan__()
+
+            
+    def dxy(self,file):  
+        """
+        get width and height of the video
+        """
+        file.seek(self.sequence_header_offset+4,0)
+        v = file.read(4)
+        x = struct.unpack('>H',v[:2])[0] >> 4
+        y = struct.unpack('>H',v[1:3])[0] & 0x0FFF
+        return (x,y)
+
+        
+    def framerate_aspect(self,file):
+        """
+        read framerate and aspect ratio
+        """
+        file.seek(self.sequence_header_offset+7,0)
+        v = struct.unpack( '>B', file.read(1) )[0] 
+        try:
+            fps = FRAME_RATE[v&0xf]
+        except IndexError:
+            fps = None
+        try:
+            aspect = ASPECT_RATIO[v>>4]
+        except IndexError:
+            if mediainfo.DEBUG:
+                print 'Index error: %s' % (v>>4)
+            aspect = None
+        return (fps, aspect)
+        
+
+    def progressive(self, file):
+        """
+        Try to find out with brute force if the mpeg is interlaced or not.
+        Search for the Sequence_Extension in the extension header (01B5)
+        """
+        file.seek(0)
+        buffer = ''
+        count  = 0
+        while 1:
+            if len(buffer) < 1000:
+                count += 1
+                if count > 1000:
+                    break
+                buffer += file.read(1024)
+            if len(buffer) < 1000:
+                break
+            pos = buffer.find('\x00\x00\x01\xb5')
+            if pos == -1 or len(buffer) - pos < 5:
+                buffer = buffer[-10:]
+                continue
+            ext = (ord(buffer[pos+4]) >> 4)
+            if ext == 8:
+                pass
+            elif ext == 1:
+                if (ord(buffer[pos+5]) >> 3) & 1:
+                    self.keys.append('progressive')
+                    self.progressive = 1
+                else:
+                    self.keys.append('interlaced')
+                    self.interlaced = 1
+                return True
+            else:
+                print 'ext', ext
+            buffer = buffer[pos+4:]
+        return False
+    
+        
+    ##------------------------------------------------------------------------
+    ## bitrate()
+    ##
+    ## From the MPEG-2.2 spec:
+    ##
+    ##   bit_rate -- This is a 30-bit integer.  The lower 18 bits of the 
+    ##   integer are in bit_rate_value and the upper 12 bits are in 
+    ##   bit_rate_extension.  The 30-bit integer specifies the bitrate of the 
+    ##   bitstream measured in units of 400 bits/second, rounded upwards. 
+    ##   The value zero is forbidden.
+    ##
+    ## So ignoring all the variable bitrate stuff for now, this 30 bit integer
+    ## multiplied times 400 bits/sec should give the rate in bits/sec.
+    ##  
+    ## TODO: Variable bitrates?  I need one that implements this.
+    ## 
+    ## Continued from the MPEG-2.2 spec:
+    ##
+    ##   If the bitstream is a constant bitrate stream, the bitrate specified 
+    ##   is the actual rate of operation of the VBV specified in annex C.  If 
+    ##   the bitstream is a variable bitrate stream, the STD specifications in 
+    ##   ISO/IEC 13818-1 supersede the VBV, and the bitrate specified here is 
+    ##   used to dimension the transport stream STD (2.4.2 in ITU-T Rec. xxx | 
+    ##   ISO/IEC 13818-1), or the program stream STD (2.4.5 in ITU-T Rec. xxx | 
+    ##   ISO/IEC 13818-1).
+    ## 
+    ##   If the bitstream is not a constant rate bitstream the vbv_delay 
+    ##   field shall have the value FFFF in hexadecimal.
+    ##
+    ##   Given the value encoded in the bitrate field, the bitstream shall be 
+    ##   generated so that the video encoding and the worst case multiplex 
+    ##   jitter do not cause STD buffer overflow or underflow.
+    ##
+    ##
+    ##------------------------------------------------------------------------ 
+
+
+    ## Some parts in the code are based on mpgtx (mpgtx.sf.net)
+    
+    def bitrate(self,file):
+        """
+        read the bitrate (most of the time broken)
+        """
+        file.seek(self.sequence_header_offset+8,0)
+        t,b = struct.unpack( '>HB', file.read(3) )
+        vrate = t << 2 | b >> 6
+        return vrate * 400
+        
+
+    def ReadSCRMpeg2(self, buffer):
+        """
+        read SCR (timestamp) for MPEG2 at the buffer beginning (6 Bytes)
+        """
+	highbit = (ord(buffer[0])&0x20)>>5
+
+	low4Bytes= ((long(ord(buffer[0])) & 0x18) >> 3) << 30
+	low4Bytes |= (ord(buffer[0]) & 0x03) << 28
+	low4Bytes |= ord(buffer[1]) << 20
+	low4Bytes |= (ord(buffer[2]) & 0xF8) << 12
+	low4Bytes |= (ord(buffer[2]) & 0x03) << 13
+	low4Bytes |= ord(buffer[3]) << 5
+	low4Bytes |= (ord(buffer[4])) >> 3
+
+	sys_clock_ref=(ord(buffer[4]) & 0x3) << 7
+	sys_clock_ref|=(ord(buffer[5]) >> 1)
+
+ 	return (long(highbit * (1<<16) * (1<<16)) + low4Bytes) / 90000
+
+
+    def ReadSCRMpeg1(self, buffer):
+        """
+        read SCR (timestamp) for MPEG1 at the buffer beginning (5 Bytes)
+        """
+	highbit = (ord(buffer[0]) >> 3) & 0x01
+
+	low4Bytes = ((long(ord(buffer[0])) >> 1) & 0x03) << 30
+	low4Bytes |= ord(buffer[1]) << 22;
+	low4Bytes |= (ord(buffer[2]) >> 1) << 15;
+	low4Bytes |= ord(buffer[3]) << 7;
+	low4Bytes |= ord(buffer[4]) >> 1;
+
+	return (long(highbit) * (1<<16) * (1<<16) + low4Bytes) / 90000;
+
+
+    def ReadPTS(self, buffer):
+        """
+        read PTS (PES timestamp) at the buffer beginning (5 Bytes)
+        """
+        high = ((ord(buffer[0]) & 0xF) >> 1)
+        med  = (ord(buffer[1]) << 7) + (ord(buffer[2]) >> 1)
+        low  = (ord(buffer[3]) << 7) + (ord(buffer[4]) >> 1)
+        return ((long(high) << 30 ) + (med << 15) + low) / 90000
+
+
+    def ReadHeader(self, buffer, offset):
+        """
+        Handle MPEG header in buffer on position offset
+        Return -1 on error, new offset or 0 if the new offset can't be scanned
+        """
+        if buffer[offset:offset+3] != '\x00\x00\x01':
+            return -1
+
+        id = ord(buffer[offset+3])
+
+        if id == PADDING_PKT:
+            return offset + (ord(buffer[offset+4]) << 8) + ord(buffer[offset+5]) + 6
+
+        if id == PACK_PKT:
+            if ord(buffer[offset+4]) & 0xF0 == 0x20:
+                self.type     = 'MPEG1 video'
+                self.get_time = self.ReadSCRMpeg1
+                return offset + 12
+            elif (ord(buffer[offset+4]) & 0xC0) == 0x40:
+                self.type     = 'MPEG2 video'
+                self.get_time = self.ReadSCRMpeg2
+                return offset + (ord(buffer[offset+13]) & 0x07) + 14
+            else:
+                # WTF? Very strange
+                return -1
+
+        if 0xC0 <= id <= 0xDF:
+            # code for audio stream
+            for a in self.audio:
+                if a.id == id:
+                    break
+            else:
+                self.audio.append(mediainfo.AudioInfo())
+                self.audio[-1].id = id
+                self.audio[-1].keys.append('id')
+            return 0
+
+        if 0xE0 <= id <= 0xEF:
+            # code for video stream
+            for v in self.video:
+                if v.id == id:
+                    break
+            else:
+                self.video.append(mediainfo.VideoInfo())
+                self.video[-1].id = id
+                self.video[-1].keys.append('id')
+            return 0
+
+        if id == SEQ_HEAD:
+            # sequence header, remember that position for later use
+            self.sequence_header_offset = offset
+            return 0
+
+        if id in (PRIVATE_STREAM1, PRIVATE_STREAM2):
+            # private stream. we don't know, but maybe we can guess later
+            add = ord(buffer[offset+8])
+            # if (ord(buffer[offset+6]) & 4) or 1:
+            # id = ord(buffer[offset+10+add])
+            if buffer[offset+11+add:offset+15+add].find('\x0b\x77') != -1:
+                # AC3 stream
+                for a in self.audio:
+                    if a.id == id:
+                        break
+                else:
+                    self.audio.append(mediainfo.AudioInfo())
+                    self.audio[-1].id = id
+                    self.audio[-1].codec = 'AC3'
+                    self.audio[-1].keys.append('id')
+            return 0
+
+        if id == SYS_PKT:
+            return 0
+        
+        if id == EXT_START:
+            return 0
+        
+        return 0
+
+
+    # Normal MPEG (VCD, SVCD) ========================================
+        
+    def isMPEG(self, file):
+        """
+        This MPEG starts with a sequence of 0x00 followed by a PACK Header
+        http://dvd.sourceforge.net/dvdinfo/packhdr.html
+        """
+        file.seek(0,0)
+        buffer = file.read(10000)
+        offset = 0
+
+        # seek until the 0 byte stop
+        while buffer[offset] == '\0':
+            offset += 1
+        offset -= 2
+
+        # test for mpeg header 0x00 0x00 0x01
+        if not buffer[offset:offset+4] == '\x00\x00\x01%s' % chr(PACK_PKT):
+            return 0
+
+        # scan the 100000 bytes of data
+        buffer += file.read(100000)
+
+        # scan first header, to get basic info about
+        # how to read a timestamp
+        self.ReadHeader(buffer, offset)
+
+        # store first timestamp
+        self.start = self.get_time(buffer[offset+4:])
+        while len(buffer) > offset + 1000 and buffer[offset:offset+3] == '\x00\x00\x01':
+            # read the mpeg header
+            new_offset = self.ReadHeader(buffer, offset)
+
+            # header scanning detected error, this is no mpeg
+            if new_offset == -1:
+                return 0
+
+            if new_offset:
+                # we have a new offset
+                offset = new_offset
+
+                # skip padding 0 before a new header
+                while len(buffer) > offset + 10 and \
+                          not ord(buffer[offset+2]):
+                    offset += 1
+
+            else:
+                # seek to new header by brute force
+                offset += buffer[offset+4:].find('\x00\x00\x01') + 4
+
+        # fill in values for support functions:
+        self.__seek_size__   = 1000000
+        self.__sample_size__ = 10000
+        self.__search__      = self._find_timer_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_(self, buffer):
+        """
+        Return position of timer in buffer or -1 if not found.
+        This function is valid for 'normal' mpeg files
+        """
+        pos = buffer.find('\x00\x00\x01%s' % chr(PACK_PKT))
+        if pos == -1:
+            return -1
+        return pos + 4
+        
+
+
+    # PES ============================================================
+
+
+    def ReadPESHeader(self, offset, buffer, id=0):
+        """
+        Parse a PES header.
+        Since it starts with 0x00 0x00 0x01 like 'normal' mpegs, this
+        function will return (0, -1) when it is no PES header or
+        (packet length, timestamp position (maybe -1))
+        
+        http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
+        """
+        if not buffer[0:3] == '\x00\x00\x01':
+            return 0, -1
+
+        packet_length = (ord(buffer[4]) << 8) + ord(buffer[5]) + 6
+        align         = ord(buffer[6]) & 4
+        header_length = ord(buffer[8])
+
+        # PES ID (starting with 001)
+        if ord(buffer[3]) & 0xE0 == 0xC0:
+            id = id or ord(buffer[3]) & 0x1F
+            for a in self.audio:
+                if a.id == id:
+                    break
+            else:
+                self.audio.append(mediainfo.AudioInfo())
+                self.audio[-1].id = id
+                self.audio[-1].keys.append('id')
+
+        elif ord(buffer[3]) & 0xF0 == 0xE0:
+            id = id or ord(buffer[3]) & 0xF
+            for v in self.video:
+                if v.id == id:
+                    break
+            else:
+                self.video.append(mediainfo.VideoInfo())
+                self.video[-1].id = id
+                self.video[-1].keys.append('id')
+
+            # new mpeg starting
+            if buffer[header_length+9:header_length+13] == \
+                   '\x00\x00\x01\xB3' and not self.sequence_header_offset:
+                # yes, remember offset for later use
+                self.sequence_header_offset = offset + header_length+9
+        elif ord(buffer[3]) == 189 or ord(buffer[3]) == 191:
+            # private stream. we don't know, but maybe we can guess later
+            id = id or ord(buffer[3]) & 0xF
+            if align and buffer[header_length+9:header_length+11] == '\x0b\x77':
+                # AC3 stream
+                for a in self.audio:
+                    if a.id == id:
+                        break
+                else:
+                    self.audio.append(mediainfo.AudioInfo())
+                    self.audio[-1].id = id
+                    self.audio[-1].codec = 'AC3'
+                    self.audio[-1].keys.append('id')
+
+        else:
+            # unknown content
+            pass
+
+        ptsdts = ord(buffer[7]) >> 6
+
+        if ptsdts and ptsdts == ord(buffer[9]) >> 4:
+            if ord(buffer[9]) >> 4 != ptsdts:
+                print 'WARNING: bad PTS/DTS, please contact us'
+                return packet_length, -1
+                
+            # timestamp = self.ReadPTS(buffer[9:14])
+            high = ((ord(buffer[9]) & 0xF) >> 1)
+            med  = (ord(buffer[10]) << 7) + (ord(buffer[11]) >> 1)
+            low  = (ord(buffer[12]) << 7) + (ord(buffer[13]) >> 1)
+            return packet_length, 9
+            
+        return packet_length, -1
+    
+
+
+    def isPES(self, file):
+        if mediainfo.DEBUG:
+            print 'trying mpeg-pes scan'
+        file.seek(0,0)
+        buffer = file.read(3)
+
+        # header (also valid for all mpegs)
+        if not buffer == '\x00\x00\x01':
+            return 0
+
+        self.sequence_header_offset = 0
+        buffer += file.read(10000)
+
+        offset = 0
+        while offset + 1000 < len(buffer):
+            pos, timestamp = self.ReadPESHeader(offset, buffer[offset:])
+            if not pos:
+                return 0
+            if timestamp != -1 and not hasattr(self, 'start'):
+                self.get_time = self.ReadPTS
+                self.start = self.get_time(buffer[offset+timestamp:offset+timestamp+5])
+            if self.sequence_header_offset and hasattr(self, 'start'):
+                # we have all informations we need
+                break
+
+            offset += pos
+            if offset + 1000 < len(buffer) and len(buffer) < 1000000 or 1:
+                # looks like a pes, read more
+                buffer += file.read(10000)
+        
+        if not self.video and not self.audio:
+            # no video and no audio? 
+            return 0
+
+        self.type = 'MPEG-PES'
+
+        # fill in values for support functions:
+        self.__seek_size__   = 10000000  # 10 MB
+        self.__sample_size__ = 500000    # 500 k scanning
+        self.__search__      = self._find_timer_PES_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_PES_(self, buffer):
+        """
+        Return position of timer in buffer or -1 if not found.
+        This function is valid for PES files
+        """
+        pos    = buffer.find('\x00\x00\x01')
+        offset = 0
+        if pos == -1 or offset + 1000 >= len(buffer):
+            return -1
+        
+        retpos   = -1
+        ackcount = 0
+        while offset + 1000 < len(buffer):
+            pos, timestamp = self.ReadPESHeader(offset, buffer[offset:])
+            if timestamp != -1 and retpos == -1:
+                retpos = offset + timestamp
+            if pos == 0:
+                # Oops, that was a mpeg header, no PES header
+                offset  += buffer[offset:].find('\x00\x00\x01')
+                retpos   = -1
+                ackcount = 0
+            else:
+                offset   += pos
+                if retpos != -1:
+                    ackcount += 1
+            if ackcount > 10:
+                # looks ok to me
+                return retpos
+        return -1
+            
+
+    # Transport Stream ===============================================
+    
+    def isTS(self, file):
+        file.seek(0,0)
+
+        buffer = file.read(TS_PACKET_LENGTH * 2)
+        c = 0
+
+        while c + TS_PACKET_LENGTH < len(buffer):
+            if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
+                break
+            c += 1
+        else:
+            return 0
+
+        buffer += file.read(10000)
+        self.type = 'MPEG-TS'
+        
+        while c + TS_PACKET_LENGTH < len(buffer):
+            start = ord(buffer[c+1]) & 0x40
+            # maybe load more into the buffer
+            if c + 2 * TS_PACKET_LENGTH > len(buffer) and c < 500000:
+                buffer += file.read(10000)
+
+            # wait until the ts payload contains a payload header
+            if not start:
+                c += TS_PACKET_LENGTH
+                continue
+
+            tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
+            adapt = (ord(buffer[c+3]) & 0x30) >> 4
+
+            offset = 4
+            if adapt & 0x02:
+                # meta info present, skip it for now
+                adapt_len = ord(buffer[c+offset])
+                offset += adapt_len + 1
+
+            if not ord(buffer[c+1]) & 0x40:
+                # no new pes or psi in stream payload starting
+                pass
+            elif adapt & 0x01:
+                # PES
+                timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:], tsid)[1]
+                if timestamp != -1:
+                    if not hasattr(self, 'start'):
+                        self.get_time = self.ReadPTS
+                        timestamp = c + offset + timestamp
+                        self.start = self.get_time(buffer[timestamp:timestamp+5])
+                    elif not hasattr(self, 'audio_ok'):
+                        timestamp = c + offset + timestamp
+                        start = self.get_time(buffer[timestamp:timestamp+5])
+                        if abs(start - self.start) < 10:
+                            # looks ok
+                            self.audio_ok = True
+                        else:
+                            # timestamp broken
+                            del self.start
+                            if mediainfo.DEBUG:
+                                print 'Timestamp error, correcting'
+                            
+            if hasattr(self, 'start') and self.start and \
+                   self.sequence_header_offset and self.video and self.audio:
+                break
+            
+            c += TS_PACKET_LENGTH
+
+                
+        if not self.sequence_header_offset:
+            return 0
+
+        if hasattr(self, 'start') and self.start:
+            self.keys.append('start')
+            
+        # fill in values for support functions:
+        self.__seek_size__   = 10000000  # 10 MB
+        self.__sample_size__ = 100000    # 100 k scanning
+        self.__search__      = self._find_timer_TS_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_TS_(self, buffer):
+        c = 0
+
+        while c + TS_PACKET_LENGTH < len(buffer):
+            if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
+                break
+            c += 1
+        else:
+            return -1
+        
+        while c + TS_PACKET_LENGTH < len(buffer):
+            start = ord(buffer[c+1]) & 0x40
+            if not start:
+                c += TS_PACKET_LENGTH
+                continue
+
+            tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
+            adapt = (ord(buffer[c+3]) & 0x30) >> 4
+
+            offset = 4
+            if adapt & 0x02:
+                # meta info present, skip it for now
+                offset += ord(buffer[c+offset]) + 1
+
+            if adapt & 0x01:
+                timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:], tsid)[1]
+                return c + offset + timestamp
+            c += TS_PACKET_LENGTH
+        return -1
+
+
+
+    # Support functions ==============================================
+
+    def get_endpos(self):
+        """
+        get the last timestamp of the mpeg, return -1 if this is not possible
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return -1
+
+        file = open(self.filename)
+        file.seek(os.stat(self.filename)[stat.ST_SIZE]-self.__sample_size__)
+        buffer = file.read(self.__sample_size__)
+
+        end = -1
+        while 1:
+            pos = self.__search__(buffer)
+            if pos == -1:
+                break
+            end    = self.get_time(buffer[pos:])
+            buffer = buffer[pos+100:]
+            
+        file.close()
+        return end
+    
+
+    def get_length(self):
+        """
+        get the length in seconds, return -1 if this is not possible
+        """
+        end = self.get_endpos()
+        if end == -1:
+            return -1
+        if self.start > end:
+            return int(((long(1) << 33) - 1 ) / 90000) - self.start + end
+        return end - self.start
+    
+
+    def seek(self, end_time):
+        """
+        Return the byte position in the file where the time position
+        is 'pos' seconds. Return 0 if this is not possible
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return 0
+
+        file    = open(self.filename)
+        seek_to = 0
+        
+        while 1:
+            file.seek(self.__seek_size__, 1)
+            buffer = file.read(self.__sample_size__)
+            if len(buffer) < 10000:
+                break
+            pos = self.__search__(buffer)
+            if pos != -1:
+                # found something
+                if self.get_time(buffer[pos:]) >= end_time:
+                    # too much, break
+                    break
+            # that wasn't enough
+            seek_to = file.tell()
+
+        file.close()
+        return seek_to
+
+
+    def __scan__(self):
+        """
+        scan file for timestamps (may take a long time)
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return 0
+        file = open(self.filename)
+        print 'scanning file...'
+        while 1:
+            file.seek(self.__seek_size__ * 10, 1)
+            buffer = file.read(self.__sample_size__)
+            if len(buffer) < 10000:
+                break
+            pos = self.__search__(buffer)
+            if pos == -1:
+                continue
+            print self.get_time(buffer[pos:])
+
+        file.close()
+        print 'done'
+        print
+
+    
+    
+mmpython.registertype( 'video/mpeg', ('mpeg','mpg','mp4', 'ts'), mediainfo.TYPE_AV, MpegInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/asfinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/asfinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/asfinfo.py	(revision 4)
@@ -0,0 +1,374 @@
+#if 0
+# $Id: asfinfo.py,v 1.18 2004/01/31 12:37:25 dischi Exp $
+# $Log: asfinfo.py,v $
+# Revision 1.18  2004/01/31 12:37:25  dischi
+# remove bad chars
+#
+# Revision 1.17  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.16  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.15  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.14  2003/06/12 14:43:21  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+# Revision 1.13  2003/06/12 10:42:47  the_krow
+# Added Bitrate, Extended Info
+# Still need to identify streams by their streamid
+#
+# Revision 1.12  2003/06/12 09:38:24  the_krow
+# ASF Header parser completed. I need test files or a way to generate
+# them.
+#
+# Revision 1.11  2003/06/12 00:36:30  the_krow
+# ASF Audio parsing
+#
+# Revision 1.10  2003/06/12 00:27:25  the_krow
+# More asf parsing: Width, Height, Video Codec
+#
+# Revision 1.9  2003/06/11 20:51:00  the_krow
+# Title, Artist and some other data sucessfully parsed from wmv, asf, wma
+#
+# Revision 1.8  2003/06/11 19:07:57  the_krow
+# asf,wmv,wma now get the guids right...
+#
+# Revision 1.7  2003/06/11 16:11:08  the_krow
+# asf parsing... asf is really an ugly format.
+#
+# Revision 1.6  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 15:40:26  dischi
+# catch exception, raised for small text files
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import fourcc
+import mmpython
+
+from mmpython import mediainfo
+
+def _guid(input):
+    # Remove any '-'
+    s = string.join(string.split(input,'-'), '')
+    r = ''
+    if len(s) != 32:
+        return ''
+    x = ''
+    for i in range(0,16):
+        r+=chr(int(s[2*i:2*i+2],16))
+    guid = struct.unpack('>IHHBB6s',r)
+    return guid
+
+GUIDS = {        
+'ASF_Header_Object' : _guid('75B22630-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Data_Object' : _guid('75B22636-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Simple_Index_Object' : _guid('33000890-E5B1-11CF-89F4-00A0C90349CB'),
+'ASF_Index_Object' : _guid('D6E229D3-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Media_Object_Index_Object' : _guid('FEB103F8-12AD-4C64-840F-2A1D2F7AD48C'),
+'ASF_Timecode_Index_Object' : _guid('3CB73FD0-0C4A-4803-953D-EDF7B6228F0C'),
+
+'ASF_File_Properties_Object' : _guid('8CABDCA1-A947-11CF-8EE4-00C00C205365'),
+'ASF_Stream_Properties_Object' : _guid('B7DC0791-A9B7-11CF-8EE6-00C00C205365'),
+'ASF_Header_Extension_Object' : _guid('5FBF03B5-A92E-11CF-8EE3-00C00C205365'),
+'ASF_Codec_List_Object' : _guid('86D15240-311D-11D0-A3A4-00A0C90348F6'),
+'ASF_Script_Command_Object' : _guid('1EFB1A30-0B62-11D0-A39B-00A0C90348F6'),
+'ASF_Marker_Object' : _guid('F487CD01-A951-11CF-8EE6-00C00C205365'),
+'ASF_Bitrate_Mutual_Exclusion_Object' : _guid('D6E229DC-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Error_Correction_Object' : _guid('75B22635-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Content_Description_Object' : _guid('75B22633-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Extended_Content_Description_Object' : _guid('D2D0A440-E307-11D2-97F0-00A0C95EA850'),
+'ASF_Content_Branding_Object' : _guid('2211B3FA-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Stream_Bitrate_Properties_Object' : _guid('7BF875CE-468D-11D1-8D82-006097C9A2B2'),
+'ASF_Content_Encryption_Object' : _guid('2211B3FB-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Extended_Content_Encryption_Object' : _guid('298AE614-2622-4C17-B935-DAE07EE9289C'),
+'ASF_Alt_Extended_Content_Encryption_Obj' : _guid('FF889EF1-ADEE-40DA-9E71-98704BB928CE'),
+'ASF_Digital_Signature_Object' : _guid('2211B3FC-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Padding_Object' : _guid('1806D474-CADF-4509-A4BA-9AABCB96AAE8'),
+
+'ASF_Extended_Stream_Properties_Object' : _guid('14E6A5CB-C672-4332-8399-A96952065B5A'),
+'ASF_Advanced_Mutual_Exclusion_Object' : _guid('A08649CF-4775-4670-8A16-6E35357566CD'),
+'ASF_Group_Mutual_Exclusion_Object' : _guid('D1465A40-5A79-4338-B71B-E36B8FD6C249'),
+'ASF_Stream_Prioritization_Object' : _guid('D4FED15B-88D3-454F-81F0-ED5C45999E24'),
+'ASF_Bandwidth_Sharing_Object' : _guid('A69609E6-517B-11D2-B6AF-00C04FD908E9'),
+'ASF_Language_List_Object' : _guid('7C4346A9-EFE0-4BFC-B229-393EDE415C85'),
+'ASF_Metadata_Object' : _guid('C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA'),
+'ASF_Metadata_Library_Object' : _guid('44231C94-9498-49D1-A141-1D134E457054'),
+'ASF_Index_Parameters_Object' : _guid('D6E229DF-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Media_Object_Index_Parameters_Obj' : _guid('6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7'),
+'ASF_Timecode_Index_Parameters_Object' : _guid('F55E496D-9797-4B5D-8C8B-604DFE9BFB24'),
+
+'ASF_Audio_Media' : _guid('F8699E40-5B4D-11CF-A8FD-00805F5C442B'),
+'ASF_Video_Media' : _guid('BC19EFC0-5B4D-11CF-A8FD-00805F5C442B'),
+'ASF_Command_Media' : _guid('59DACFC0-59E6-11D0-A3AC-00A0C90348F6'),
+'ASF_JFIF_Media' : _guid('B61BE100-5B4E-11CF-A8FD-00805F5C442B'),
+'ASF_Degradable_JPEG_Media' : _guid('35907DE0-E415-11CF-A917-00805F5C442B'),
+'ASF_File_Transfer_Media' : _guid('91BD222C-F21C-497A-8B6D-5AA86BFC0185'),
+'ASF_Binary_Media' : _guid('3AFB65E2-47EF-40F2-AC2C-70A90D71D343'),
+
+'ASF_Web_Stream_Media_Subtype' : _guid('776257D4-C627-41CB-8F81-7AC7FF1C40CC'),
+'ASF_Web_Stream_Format' : _guid('DA1E6B13-8359-4050-B398-388E965BF00C'),
+
+'ASF_No_Error_Correction' : _guid('20FB5700-5B55-11CF-A8FD-00805F5C442B'),
+'ASF_Audio_Spread' : _guid('BFC3CD50-618F-11CF-8BB2-00AA00B4E220'),
+}
+
+_print = mediainfo._debug
+
+class AsfInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/asf'
+        self.type = 'asf video'
+        h = file.read(30)
+        if len(h) < 30:
+            return
+        self.valid = 1
+        (guidstr,objsize,objnum,reserved1,reserved2) = struct.unpack('<16sQIBB',h)                
+        guid = self._parseguid(guidstr)
+        if (guid != GUIDS['ASF_Header_Object']):
+            self.valid = 0
+            return
+        if reserved1 != 0x01 or reserved2 != 0x02:
+            self.valid = 0
+        _print("asf header size: %d / %d objects" % (objsize,objnum))
+        header = file.read(objsize-30)
+        for i in range(0,objnum):
+            h = self._getnextheader(header)
+            header = header[h[1]:]
+            
+    def _printguid(self,guid):
+        r = "%.8X-%.4X-%.4X-%.2X%.2X-%s" % guid
+        return r 
+        
+    def _parseguid(self,string):
+        return struct.unpack('<IHHBB6s', string[:16])
+        
+    def _parsekv(self,s):
+        pos = 0    
+        (descriptorlen,) = struct.unpack('<H', s[pos:pos+2])
+        pos += 2
+        descriptorname = s[pos:pos+descriptorlen]
+        pos += descriptorlen
+        descriptortype, valuelen = struct.unpack('<HH', s[pos:pos+4])
+        pos += 4
+        descriptorvalue = s[pos:pos+valuelen]
+        pos += valuelen
+        value = None
+        if descriptortype == 0x0000:
+            # Unicode string
+            value = descriptorvalue
+        elif descriptortype == 0x0001:
+            # Byte Array
+            value = descriptorvalue
+        elif descriptortype == 0x0002:
+            # Bool (?)
+            value = struct.unpack('<I', descriptorvalue)[0] != 0
+        elif descriptortype == 0x0003:
+            # DWORD
+            value = struct.unpack('<I', descriptorvalue)[0]
+        elif descriptortype == 0x0004:
+            # QWORD
+            value = struct.unpack('<Q', descriptorvalue)[0]
+        elif descriptortype == 0x0005:
+            # WORD
+            value = struct.unpack('<H', descriptorvalue)[0]
+        else:
+            _print("Unknown Descriptor Type %d" % descriptortype)
+        return (pos,descriptorname,value)
+
+    def _parsekv2(self,s):
+        pos = 0    
+        (strno,descriptorlen,descriptortype,valuelen) = struct.unpack('<2xHHHI', s[pos:pos+12])
+        pos += 12
+        descriptorname = s[pos:pos+descriptorlen]
+        pos += descriptorlen
+        descriptorvalue = s[pos:pos+valuelen]
+        pos += valuelen
+        value = None
+        #print "%d %s [%d]" % (strno, descriptorname, valuelen)
+        if descriptortype == 0x0000:
+            # Unicode string
+            value = descriptorvalue
+        elif descriptortype == 0x0001:
+            # Byte Array
+            value = descriptorvalue
+        elif descriptortype == 0x0002:
+            # Bool
+            value = struct.unpack('<H', descriptorvalue)[0] != 0
+            pass
+        elif descriptortype == 0x0003:
+            # DWORD
+            value = struct.unpack('<I', descriptorvalue)[0]
+        elif descriptortype == 0x0004:
+            # QWORD
+            value = struct.unpack('<Q', descriptorvalue)[0]
+        elif descriptortype == 0x0005:
+            # WORD
+            value = struct.unpack('<H', descriptorvalue)[0]
+        else:
+            _print("Unknown Descriptor Type %d" % descriptortype)
+        return (pos,descriptorname,value,strno)
+
+        
+    def _getnextheader(self,s):
+        r = struct.unpack('<16sQ',s[:24])
+        (guidstr,objsize) = r
+        guid = self._parseguid(guidstr)
+        if guid == GUIDS['ASF_File_Properties_Object']:
+            _print("File Properties Object")
+            val = struct.unpack('<16s6Q4I',s[24:24+80])
+            (fileid, size, date, packetcount, duration, \
+             senddur, preroll, flags, minpack, maxpack, maxbr) = \
+             val
+            self.length = duration/10000000
+        elif guid == GUIDS['ASF_Stream_Properties_Object']:
+            _print("Stream Properties Object [%d]" % objsize)                        
+            streamtype = self._parseguid(s[24:40])
+            errortype = self._parseguid(s[40:56])
+            offset, typelen, errorlen, flags = struct.unpack('>QIIH4x', s[56:78])
+            strno = flags & 63
+            encrypted = flags >> 15
+            if streamtype == GUIDS['ASF_Video_Media']:
+                vi = mediainfo.VideoInfo()
+                #vi.width, vi.height, formatsize = struct.unpack('<IIxH', s[78:89])
+                vi.width, vi.height, depth, codec, = struct.unpack('<4xII2xH4s', s[89:89+20])
+                vi.codec = fourcc.RIFFCODEC[codec]
+                vi.id = strno
+                self.video.append(vi)  
+            elif streamtype == GUIDS['ASF_Audio_Media']:
+                ai = mediainfo.AudioInfo()
+                twocc, ai.channels, ai.samplerate, bitrate, block, ai.samplebits, = struct.unpack('<HHIIHH', s[78:78+16])
+                ai.bitrate = 8*bitrate  # XXX Is this right?
+                ai.codec = fourcc.RIFFWAVE[twocc]
+                ai.id = strno
+                self.audio.append(ai)  
+            pass
+        elif guid == GUIDS['ASF_Header_Extension_Object']:
+            _print("ASF_Header_Extension_Object %d" % objsize)
+            size = struct.unpack('<I',s[42:46])[0]
+            data = s[46:46+size]
+            while len(data):
+                _print("Sub:")
+                h = self._getnextheader(data)
+                data = data[h[1]:]
+            
+        elif guid == GUIDS['ASF_Codec_List_Object']:
+            _print("List Object")
+            pass
+        elif guid == GUIDS['ASF_Error_Correction_Object']:
+            _print("Error Correction")
+            pass
+        elif guid == GUIDS['ASF_Content_Description_Object']:
+            _print("Content Description Object")
+            val = struct.unpack('<5H', s[24:24+10])
+            pos = 34
+            strings = []
+            for i in val:
+                strings.append(s[pos:pos+i].replace('\0', '').lstrip().rstrip())
+                pos+=i
+            (self.title, self.artist, self.copyright, self.caption, rating) = tuple(strings)
+        elif guid == GUIDS['ASF_Extended_Content_Description_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            descriptor = {}
+            for i in range(0, count):
+                # Read additional content descriptors
+                d = self._parsekv(s[pos:])
+                pos += d[0]
+                descriptor[d[1]] = d[2]
+            self.appendtable('ASFDESCRIPTOR', descriptor)
+        elif guid == GUIDS['ASF_Metadata_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            descriptor = {}
+            for i in range(0, count):
+                # Read additional content descriptors
+                d = self._parsekv2(s[pos:])
+                pos += d[0]
+                descriptor[d[1]] = d[2]
+            # TODO: Find the stream in self.audio and self.video and
+            #       append it there instead of here
+            self.appendtable('ASFMETADATA%d'%d[3], descriptor)
+        elif guid == GUIDS['ASF_Language_List_Object']:
+            count = struct.unpack('<H', s[24:26])[0]
+            pos = 26
+            lang = []
+            for i in range(0, count):
+                idlen = struct.unpack('<B', s[pos:pos+1])[0]
+                idstring = s[pos+1:pos+1+idlen]
+                _print("Language: %d/%d: %s" % (i+1, count, idstring))
+                lang.append(idstring)
+                pos += 1+idlen
+            if len(lang) == 1:
+                self.language = lang[0]
+            else:
+                self.language = tuple(lang)
+            # TODO: Find the stream in self.audio and self.video and
+            #       set it there instead of here
+        elif guid == GUIDS['ASF_Stream_Bitrate_Properties_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            for i in range(0,count):
+                strno, avbitrate = struct.unpack('<HI', s[pos:pos+6])
+                strno &= 63
+                _print("Stream %d Bitrate: %d" % (strno, avbitrate))
+            # TODO: Find the stream in self.audio and self.video and
+            #       set it there instead of here
+        else:
+            # Just print the type:
+            bfail = 1
+            for h in GUIDS.keys():
+                if GUIDS[h] == guid:
+                    _print("Unparsed %s [%d]" % (h,objsize))
+                    bfail = 0
+            if bfail:
+                _print("unknown: %s [%d]" % (self._printguid(guid), objsize))
+        return r
+        
+mmpython.registertype( 'video/asf', ('asf','wmv','wma'), mediainfo.TYPE_AV, AsfInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/movlanguages.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/movlanguages.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/movlanguages.py	(revision 4)
@@ -0,0 +1,109 @@
+QTLANGUAGES = {
+    0 : "en",
+    1 : "fr",
+    2 : "de",
+    3 : "it",
+    4 : "nl",
+    5 : "sv",
+    6 : "es",
+    7 : "da",
+    8 : "pt",
+    9 : "no",
+    10 : "he",
+    11 : "ja",
+    12 : "ar",
+    13 : "fi",
+    14 : "el",
+    15 : "is",
+    16 : "mt",
+    17 : "tr",
+    18 : "hr",
+    19 : "Traditional Chinese",
+    20 : "ur",
+    21 : "hi",
+    22 : "th",
+    23 : "ko",
+    24 : "lt",
+    25 : "pl",
+    26 : "hu",
+    27 : "et",
+    28 : "lv",
+    29 : "Lappish",
+    30 : "fo",
+    31 : "Farsi",
+    32 : "ru",
+    33 : "Simplified Chinese",
+    34 : "Flemish",
+    35 : "ga",
+    36 : "sq",
+    37 : "ro",
+    38 : "cs",
+    39 : "sk",
+    40 : "sl",
+    41 : "yi",
+    42 : "sr",
+    43 : "mk",
+    44 : "bg",
+    45 : "uk",
+    46 : "be",
+    47 : "uz",
+    48 : "kk",
+    49 : "az",
+    50 : "AzerbaijanAr",
+    51 : "hy",
+    52 : "ka",
+    53 : "mo",
+    54 : "ky",
+    55 : "tg",
+    56 : "tk",
+    57 : "mn",
+    58 : "MongolianCyr",
+    59 : "ps",
+    60 : "ku",
+    61 : "ks",
+    62 : "sd",
+    63 : "bo",
+    64 : "ne",
+    65 : "sa",
+    66 : "mr",
+    67 : "bn",
+    68 : "as",
+    69 : "gu",
+    70 : "pa",
+    71 : "or",
+    72 : "ml",
+    73 : "kn",
+    74 : "ta",
+    75 : "te",
+    76 : "si",
+    77 : "my",
+    78 : "Khmer",
+    79 : "lo",
+    80 : "vi",
+    81 : "id",
+    82 : "tl",
+    83 : "MalayRoman",
+    84 : "MalayArabic",
+    85 : "am",
+    86 : "ti",
+    87 : "om",
+    88 : "so",
+    89 : "sw",
+    90 : "Ruanda",
+    91 : "Rundi",
+    92 : "Chewa",
+    93 : "mg",
+    94 : "eo",
+    128 : "cy",
+    129 : "eu",
+    130 : "ca",
+    131 : "la",
+    132 : "qu",
+    133 : "gn",
+    134 : "ay",
+    135 : "tt",
+    136 : "ug",
+    137 : "Dzongkha",
+    138 : "JavaneseRom",
+}
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/vcdinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/vcdinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/vcdinfo.py	(revision 4)
@@ -0,0 +1,122 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# vcdinfo.py - parse vcd track informations from cue/bin files
+# -----------------------------------------------------------------------
+# $Id: vcdinfo.py,v 1.7 2004/06/25 13:20:34 dischi Exp $
+#
+# $Log: vcdinfo.py,v $
+# Revision 1.7  2004/06/25 13:20:34  dischi
+# FreeBSD patches
+#
+# Revision 1.6  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/29 11:59:55  dischi
+# bugfix
+#
+# Revision 1.4  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.3  2003/06/10 11:17:39  the_krow
+# - OGG Fixes
+# - changed one DiscInfo reference in vcdinfo I missed before
+#
+# Revision 1.2  2003/06/10 10:56:54  the_krow
+# - Build try-except blocks around disc imports to make it run on platforms
+#   not compiling / running the C extensions.
+# - moved DiscInfo class to disc module
+# - changed video.VcdInfo to be derived from CollectionInfo instead of
+#   DiskInfo so it can be used without the cdrom extensions which are
+#   hopefully not needed for bin-files.
+#
+# Revision 1.1  2003/06/09 16:09:18  dischi
+# first version of a cue/bin vcd parser
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import os
+
+class VCDInfo(mediainfo.CollectionInfo):
+    def __init__(self, file):
+        mediainfo.CollectionInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        self.valid = self.isVCD(file)
+        self.mime = 'video/vcd'
+        self.type = 'vcd video'        
+
+    def isVCD(self, file):
+        type = None
+
+        buffer = file.readline()
+
+        if not buffer[:6] == 'FILE "':
+            return 0
+
+        bin = os.path.join(os.path.dirname(file.name), buffer[6:buffer[6:].find('"')+6])
+        if not os.path.isfile(bin):
+            return 0
+
+        # At this point this really is a cue/bin disc
+        
+        # brute force reading of the bin to find out if it is a VCD
+        f = open(bin,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+        f.close()
+
+        if buffer.find('SVCD') > 0 and buffer.find('TRACKS.SVD') > 0 and \
+               buffer.find('ENTRIES.SVD') > 0:
+            type = 'SVCD'
+
+        elif buffer.find('INFO.VCD') > 0 and buffer.find('ENTRIES.VCD') > 0:
+            type = 'VCD'
+
+        else:
+            return 0
+
+        counter = 0
+        while 1:
+            buffer = file.readline()
+            if not len(buffer):
+                return 1
+            if buffer[:8] == '  TRACK ':
+                counter += 1
+                # the first track is the directory, that doesn't count
+                if counter > 1:
+                    vi = mediainfo.VideoInfo()
+                    if type == 'VCD':
+                        vi.codec = 'MPEG1'
+                    else:
+                        vi.codec = 'MPEG2'
+                    self.tracks.append(vi)
+
+
+mmpython.registertype( 'video/vcd', ('cue',), mediainfo.TYPE_AV, VCDInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/mkvinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/mkvinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/mkvinfo.py	(revision 4)
@@ -0,0 +1,332 @@
+#if 0
+# -----------------------------------------------------------------------
+# mkvinfo.py - Matroska Streaming Video Files
+# -----------------------------------------------------------------------
+# $Id: mkvinfo.py,v 1.3 2004/04/18 17:55:26 dischi Exp $
+#
+# $Log: mkvinfo.py,v $
+# Revision 1.3  2004/04/18 17:55:26  dischi
+# update, including subtitle support
+#
+# Revision 1.2  2004/03/21 08:57:31  dischi
+# major bugfix
+#
+# Revision 1.1  2004/01/31 12:24:15  dischi
+# add basic matroska info
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import struct
+import re
+import stat
+import os
+import math
+from types import *
+from struct import *
+from string import *
+
+_print = mediainfo._debug
+
+# Main IDs for the Matroska streams
+MATROSKA_VIDEO_TRACK     = 0x01
+MATROSKA_AUDIO_TRACK     = 0x02
+MATROSKA_SUBTITLES_TRACK = 0x11
+
+MATROSKA_HEADER_ID  = 0x1A45DFA3
+MATROSKA_TRACKS_ID  = 0x1654AE6B
+MATROSKA_SEGMENT_ID = 0x18538067
+MATROSKA_SEGMENT_INFO_ID      = 0x1549A966
+MATROSKA_CLUSTER_ID           = 0x1F43B675
+MATROSKA_VOID_ID              = 0xEC
+MATROSKA_CRC_ID               = 0xBF
+MATROSKA_TIMECODESCALE_ID     = 0x2AD7B1
+MATROSKA_DURATION_ID          = 0x4489
+MATROSKA_CRC32_ID             = 0xBF
+MATROSKA_TRACK_TYPE_ID        = 0x83
+MATROSKA_TRACK_LANGUAGE_ID    = 0x22B59C
+MATROSKA_TIMECODESCALE_ID     = 0x4489
+MATROSKA_MUXING_APP_ID        = 0x4D80
+MATROSKA_WRITING_APP_ID       = 0x5741
+MATROSKA_CODEC_ID             = 0x86
+MATROSKA_CODEC_NAME_ID        = 0x258688
+MATROSKA_FRAME_DURATION_ID    = 0x23E383
+MATROSKA_VIDEO_SETTINGS_ID    = 0xE0
+MATROSKA_VID_WIDTH_ID         = 0xB0
+MATROSKA_VID_HEIGHT_ID        = 0xBA
+MATROSKA_AUDIO_SETTINGS_ID    = 0xE1
+MATROSKA_AUDIO_SAMPLERATE_ID  = 0xB5
+MATROSKA_AUDIO_CHANNELS_ID    = 0x9F
+MATROSKA_TRACK_UID_ID         = 0x73C5
+MATROSKA_TRACK_NUMBER_ID      = 0xD7
+
+# This is class that is responsible to handle one Ebml entity as described in the Matroska/Ebml spec
+class EbmlEntity:
+    def __init__(self, inbuf):
+        # Compute the EBML id
+        # Set the CRC len to zero
+        self.crc_len = 0
+        # Now loop until we find an entity without CRC
+        self.build_entity(inbuf)
+        while self.get_id() == MATROSKA_CRC32_ID:
+            self.crc_len += self.get_total_len()
+            inbuf = inbuf[self.get_total_len():]
+            self.build_entity(inbuf)
+
+    def build_entity(self, inbuf):
+        self.compute_id(inbuf)
+        #_print("Entity id : %08X" % self.entity_id)
+        if ( self.id_len == 0):
+            self.valid = 0
+            _print("EBML entity not found, bad file format")
+            return
+        self.valid = 1
+        self.entity_len = self.compute_len(inbuf[self.id_len:])
+        # Obviously, the segment can be very long (ie the whole file, so we truncate it at the read buffer size
+        if (self.entity_len == -1):
+            self.entity_data = inbuf[self.id_len+self.len_size:]
+            self.entity_len = len(self.entity_data) # Set the remaining size
+        else:
+            self.entity_data = inbuf[self.id_len+self.len_size:self.id_len+self.len_size+self.entity_len]
+        #_print("Entity len : %d" % self.entity_len)
+        # if the size is 1, 2 3 or 4 it could be a numeric value, so do the job
+        self.value = 0
+        if self.entity_len == 1:
+            self.value = ord(self.entity_data[0])
+        if self.entity_len == 2:
+            self.value = unpack('!H', self.entity_data)[0]
+        if self.entity_len == 3:
+            self.value = ord(self.entity_data[0])<<16 | ord(self.entity_data[1])<<8 | ord(self.entity_data[2])
+        if self.entity_len == 4:
+            self.value = unpack('!I', self.entity_data)[0]
+
+    def compute_id(self, inbuf):
+        first = ord(inbuf[0])
+        self.id_len = 0
+        if (first & 0x80):
+            self.id_len = 1
+            self.entity_id = first
+        elif (first & 0x40):
+            self.id_len = 2
+            self.entity_id = ord(inbuf[0])<<8 | ord(inbuf[1])
+        elif (first & 0x20):
+            self.id_len = 3
+            self.entity_id = (ord(inbuf[0])<<16) | (ord(inbuf[1])<<8) | (ord(inbuf[2]))
+        elif (first & 0x10):
+            self.id_len = 4
+            self.entity_id = (ord(inbuf[0])<<24) | (ord(inbuf[1])<<16) | (ord(inbuf[2])<<8) | (ord(inbuf[3]))
+        self.entity_str = inbuf[0:self.id_len]
+        return
+
+    def compute_len(self, inbuf):
+        # Here we just handle the size up to 4 bytes
+        # The size above will be truncated by the read buffer itself
+        first = ord(inbuf[0])
+        if (first & 0x80):
+            self.len_size = 1
+            return first - 0x80
+        if (first & 0x40):
+            self.len_size = 2
+            (c1,c2) = unpack('BB',inbuf[:2])
+            return ((c1-0x40)<<8) | (c2)
+        if (first & 0x20):
+            self.len_size = 3
+            (c1, c2, c3) = unpack('BBB',inbuf[:3])
+            return ((c1-0x20)<<16) | (c2<<8) | (c3)
+        if (first & 0x10):
+            self.len_size = 4
+            (len) = unpack('!I',inbuf[:4])
+            return len
+        if (first & 0x08):
+            self.len_size = 5
+            return -1
+        if (first & 0x04):
+            self.len_size = 6
+            return -1
+        if (first & 0x02):
+            self.len_size = 7
+            return -1
+        if (first & 0x01):
+            self.len_size = 8
+            return -1
+
+    def get_crc_len(self):
+        return self.crc_len
+
+    def get_value(self):
+        value = self.value
+        return value
+
+    def get_data(self):
+        return self.entity_data
+
+    def get_id(self):
+        return self.entity_id
+
+    def get_str_id(self):
+        return self.entity_str
+
+    def get_len(self):
+        return self.entity_len
+
+    def get_total_len(self):
+        return self.entity_len+self.id_len+self.len_size
+
+
+# This ithe main Matroska object
+class MkvInfo(mediainfo.AVInfo):
+    def __init__(self, file):
+        mediainfo.AVInfo.__init__(self)
+        self.samplerate = 1
+
+        buffer = file.read(80000)
+        if len(buffer) == 0:
+            # Regular File end
+            return None
+
+        # Check the Matroska header
+        header = EbmlEntity(buffer)
+        if ( header.get_id() == MATROSKA_HEADER_ID ):
+            _print("HEADER ID found %08X" % header.get_id() )
+            self.valid = 1
+            self.mime = 'application/mkv'
+            self.type = 'Matroska'
+            # Now get the segment
+            segment = EbmlEntity(buffer[header.get_total_len():])
+            if ( segment.get_id() == MATROSKA_SEGMENT_ID):
+                _print("SEGMENT ID found %08X" % segment.get_id() )
+                #MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
+                #'date', 'keywords', 'country', 'language', 'url']
+                segtab = self.process_one_level(segment)
+                seginfotab = self.process_one_level(segtab[MATROSKA_SEGMENT_INFO_ID])
+                try:
+                    # Express scalecode in ms instead of ns
+                    # Rescale it to the second
+                    scalecode = float(seginfotab[MATROSKA_TIMECODESCALE_ID].get_value() / (1000*1000))
+                except:
+                    scalecode = 1000
+                try:
+                    duration = float(unpack('!f', seginfotab[MATROSKA_DURATION_ID].get_data() )[0])
+                    duration = float(duration / scalecode)
+                    # Express the time in minutes
+                    self.length = int(duration/60)
+                except:
+                    pass
+                try:
+                    _print ("Searching for id : %X" % MATROSKA_TRACKS_ID)
+                    entity = segtab[MATROSKA_TRACKS_ID]
+                    self.process_tracks(entity)
+                except:
+                    _print("TRACKS ID not found !!" )
+            else:
+                _print("SEGMENT ID not found %08X" % segment.get_id() )
+        else:
+            self.valid = 0
+
+    def process_tracks(self, tracks):
+        tracksbuf = tracks.get_data()
+        indice = 0
+        while indice < tracks.get_len():
+            trackelem = EbmlEntity(tracksbuf[indice:])
+            _print ("ELEMENT %X found" % trackelem.get_id())
+            self.process_one_track(trackelem)
+            indice += trackelem.get_total_len() + trackelem.get_crc_len()
+
+    def process_one_level(self, item):
+        buf = item.get_data()
+        indice = 0
+        tabelem = {}
+        while indice < item.get_len():
+            elem = EbmlEntity(buf[indice:])
+            tabelem[elem.get_id()] = elem
+            indice += elem.get_total_len() + elem.get_crc_len()
+        return tabelem
+
+    def process_one_track(self, track):
+        # Process all the items at the track level
+        tabelem = self.process_one_level(track)
+        # We have the dict of track eleme, now build the MMPYTHON information
+        type = tabelem[MATROSKA_TRACK_TYPE_ID]
+        mytype = type.get_value()
+        _print ("Track type found with UID %d" % mytype)
+        if (mytype == MATROSKA_VIDEO_TRACK ):
+            _print("VIDEO TRACK found !!" )
+            #VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'samplebits',
+            #     'width', 'height', 'fps', 'aspect']
+            vi = mediainfo.VideoInfo()
+            try:
+                elem = tabelem[MATROSKA_CODEC_ID]
+                vi.codec = elem.get_data()
+            except:
+                vi.codec = 'Unknown'
+            try:
+                elem = tabelem[MATROSKA_FRAME_DURATION_ID]
+                vi.fps = 1 / (pow(10, -9) * (elem.get_value()))
+            except:
+                vi.fps = 0
+            try:
+                vinfo = tabelem[MATROSKA_VIDEO_SETTINGS_ID]
+                vidtab = self.process_one_level(vinfo)
+                vi.width  = vidtab[MATROSKA_VID_WIDTH_ID].get_value()
+                vi.height = vidtab[MATROSKA_VID_HEIGHT_ID].get_value()
+            except:
+                _print("No other info about video track !!!")
+            self.video.append(vi)
+        elif (mytype == MATROSKA_AUDIO_TRACK ):
+            _print("AUDIO TRACK found !!" )
+            #AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
+            #     'bitrate', 'language']
+            ai = mediainfo.AudioInfo()
+            try:
+                elem = tabelem[MATROSKA_TRACK_LANGUAGE_ID]
+                ai.language = elem.get_data()
+                ai['language'] = elem.get_data()
+            except:
+                ai.language = 'en'
+                ai['language'] = 'en'
+            try:
+                elem = tabelem[MATROSKA_CODEC_ID]
+                ai.codec = elem.get_data()
+            except:
+                ai.codec = "Unknown"
+            try:
+                ainfo = tabelem[MATROSKA_AUDIO_SETTINGS_ID]
+                audtab = self.process_one_level(vinfo)
+                ai.samplerate  = unpack('!f', audtab[MATROSKA_AUDIO_SAMPLERATE_ID].get_value())[0]
+                ai.channels = audtab[MATROSKA_AUDIO_CHANNELS_ID].get_value()
+            except:
+                _print("No other info about audio track !!!")
+            self.audio.append(ai)
+        elif (mytype == MATROSKA_SUBTITLES_TRACK):
+            try:
+                elem = tabelem[MATROSKA_TRACK_LANGUAGE_ID]
+                language = elem.get_data()
+                _print ("Subtitle language found : %s" % elem.get_data() )
+            except:
+                language = "en" # By default
+            self.subtitles.append(language)
+
+        #_print("Found %d elem for this track" % len(tabelem) )
+
+mmpython.registertype( 'application/mkv', ('mkv', 'mka',), mediainfo.TYPE_AV, MkvInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/movinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/movinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/movinfo.py	(revision 4)
@@ -0,0 +1,375 @@
+#if 0
+# $Id: movinfo.py,v 1.24 2004/07/14 13:42:57 dischi Exp $
+# $Log: movinfo.py,v $
+# Revision 1.24  2004/07/14 13:42:57  dischi
+# small debug updates
+#
+# Revision 1.23  2004/05/24 12:54:35  dischi
+# debug update
+#
+# Revision 1.22  2004/05/11 15:18:59  dischi
+# o more stream infos (like codec)
+# o better error handling for bad i18n tables
+# o language detection
+#
+# Revision 1.21  2004/05/10 15:19:59  dischi
+# o better stream detection
+# o correct length calculation inside the track
+# o support for compressed infos
+#
+# Revision 1.20  2004/03/07 10:27:58  dischi
+# Oops
+#
+# Revision 1.19  2004/03/02 20:48:21  dischi
+# fix gettable
+#
+# Revision 1.18  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.17  2003/07/02 11:17:30  the_krow
+# language is now part of the table key
+#
+# Revision 1.16  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.15  2003/06/29 18:30:56  dischi
+# length is broken, deactivated it until it is fixed
+#
+# Revision 1.14  2003/06/29 11:59:35  dischi
+# make some debug silent
+#
+# Revision 1.13  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.12  2003/06/20 14:53:05  the_krow
+# Metadata are copied from Quicktime Userdata to MediaInfo fields. This
+#  may be broken since it assumes the Quicktime Comment language to be
+#  set to 0.
+#
+# Revision 1.11  2003/06/19 17:31:12  dischi
+# error handling (and nonsense data)
+#
+# Revision 1.10  2003/06/12 18:53:18  the_krow
+# OGM detection added.
+# .ram is a valid extension to real files
+#
+# Revision 1.9  2003/06/12 16:56:53  the_krow
+# Some Quicktime should work.
+#
+# Revision 1.8  2003/06/12 15:58:05  the_krow
+# QT parsing of i18n metadata
+#
+# Revision 1.7  2003/06/12 14:43:22  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+# Revision 1.6  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 15:40:26  dischi
+# catch exception, raised for small text files
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import time
+import zlib
+import fourcc
+import mmpython
+from mmpython import mediainfo
+from movlanguages import *
+
+# http://developer.apple.com/documentation/QuickTime/QTFF/index.html
+
+ATOM_DEBUG = 0
+
+if mediainfo.DEBUG > 1:
+    ATOM_DEBUG = 1
+    
+class MovInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/quicktime'
+        self.type = 'Quicktime Video'
+        h = file.read(8)                
+        (size,type) = struct.unpack('>I4s',h)
+        if type == 'moov':
+            self.valid = 1
+        elif type == 'wide':
+            self.valid = 1
+        else:
+            return
+        # Extended size
+        if size == 1:
+            #print "Extended Size"
+            size = struct.unpack('>Q', file.read(8))                  
+        while self._readatom(file):
+            pass
+        try:
+            info = self.gettable('QTUDTA', 'en')
+            self.setitem('title', info, 'nam')
+            self.setitem('artist', info, 'aut')
+            self.setitem('copyright', info, 'cpy')
+        except:
+            pass
+
+
+    def _readatom(self, file):
+        
+        s = file.read(8)
+        if len(s) < 8:
+            return 0
+
+        atomsize,atomtype = struct.unpack('>I4s', s)
+        if not str(atomtype).decode('latin1').isalnum():
+            # stop at nonsense data
+            return 0
+
+        if mediainfo.DEBUG or ATOM_DEBUG:
+            print "%s [%X]" % (atomtype,atomsize)
+
+        if atomtype == 'udta':
+            # Userdata (Metadata)
+            pos = 0
+            tabl = {}
+            i18ntabl = {}
+            atomdata = file.read(atomsize-8)
+            while pos < atomsize-12:
+                (datasize,datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
+                if ord(datatype[0]) == 169:
+                    # i18n Metadata... 
+                    mypos = 8+pos
+                    while mypos < datasize+pos:
+                        # first 4 Bytes are i18n header
+                        (tlen,lang) = struct.unpack('>HH', atomdata[mypos:mypos+4])
+                        i18ntabl[lang] = i18ntabl.get(lang, {})
+                        i18ntabl[lang][datatype[1:]] = atomdata[mypos+4:mypos+tlen+4]
+                        mypos += tlen+4
+                elif datatype == 'WLOC':
+                    # Drop Window Location
+                    pass
+                else:
+                    if ord(atomdata[pos+8:pos+datasize][0]) > 1:
+                        tabl[datatype] = atomdata[pos+8:pos+datasize]
+                pos += datasize
+            if len(i18ntabl.keys()) > 0:
+                for k in i18ntabl.keys():                
+                    if QTLANGUAGES.has_key(k):
+                        self.appendtable('QTUDTA', i18ntabl[k], QTLANGUAGES[k])
+                        self.appendtable('QTUDTA', tabl, QTLANGUAGES[k])
+            else:
+                #print "NO i18"
+                self.appendtable('QTUDTA', tabl)
+             
+        elif atomtype == 'trak':
+            atomdata = file.read(atomsize-8)
+            pos   = 0
+            vi    = None
+            ai    = None
+            info  = None
+            while pos < atomsize-8:
+                (datasize,datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
+                if datatype == 'tkhd':
+                    tkhd = struct.unpack('>6I8x4H36xII', atomdata[pos+8:pos+datasize])
+                    vi = mediainfo.VideoInfo()
+                    vi.width = tkhd[10] >> 16
+                    vi.height = tkhd[11] >> 16
+                    vi.id = tkhd[3]
+
+                    ai = mediainfo.AudioInfo()
+                    ai.id = tkhd[3]
+                    
+                    try:
+                        # XXX Date number of Seconds is since January 1st 1904!!!
+                        # XXX 2082844800 is the difference between Unix and Apple time
+                        # XXX Fix me to work on Apple, too
+                        self.date = int(tkhd[1]) - 2082844800
+                        self.date = time.strftime('%y/%m/%d', time.gmtime(self.date))
+                    except Exception, e:
+                        print 'ex', e
+                    
+                elif datatype == 'mdia':
+                    pos      += 8
+                    datasize -= 8
+                    if ATOM_DEBUG:
+                        print '--> mdia information'
+
+                    while datasize:
+                        mdia = struct.unpack('>I4s', atomdata[pos:pos+8])
+                        if mdia[1] == 'mdhd':
+                            mdhd = struct.unpack('>IIIIIhh', atomdata[pos+8:pos+8+24])
+                            # duration / time scale
+                            if vi:
+                                vi.length = mdhd[4] / mdhd[3]
+                            if ai:
+                                ai.length = mdhd[4] / mdhd[3]
+                                if mdhd[5] in QTLANGUAGES:
+                                    ai.language = QTLANGUAGES[mdhd[5]]
+                            # mdhd[6] == quality 
+                            self.length = max(self.length, mdhd[4] / mdhd[3])
+                        elif mdia[1] == 'minf':
+                            # minf has only atoms inside
+                            pos -=      (mdia[0] - 8)
+                            datasize += (mdia[0] - 8)
+                        elif mdia[1] == 'stbl':
+                            # stbl has only atoms inside
+                            pos -=      (mdia[0] - 8)
+                            datasize += (mdia[0] - 8)
+                        elif mdia[1] == 'hdlr':
+                            hdlr = struct.unpack('>I4s4s', atomdata[pos+8:pos+8+12])
+                            if hdlr[1] == 'mhlr':
+                                if hdlr[2] == 'vide' and not vi in self.video:
+                                    self.video.append(vi)
+                                    info = vi
+                                if hdlr[2] == 'soun' and not ai in self.audio:
+                                    self.audio.append(ai)
+                                    info = ai
+                        elif mdia[1] == 'stsd':
+                            stsd = struct.unpack('>2I', atomdata[pos+8:pos+8+8])
+                            if stsd[1] > 0 and info:
+                                codec = struct.unpack('>I4s', atomdata[pos+16:pos+16+8])
+                                info.codec = codec[1]
+                                if info.codec == 'jpeg':
+                                    # jpeg is no video, remove it from the list
+                                    self.video.remove(vi)
+                                    info = None
+
+                        elif mdia[1] == 'dinf':
+                            dref = struct.unpack('>I4s', atomdata[pos+8:pos+8+8])
+                            if ATOM_DEBUG:
+                                print '  --> %s, %s' % mdia
+                                print '    --> %s, %s (reference)' % dref
+                            
+                        elif ATOM_DEBUG:
+                            if mdia[1].startswith('st'):
+                                print '  --> %s, %s (sample)' % mdia
+                            elif mdia[1] in ('vmhd', 'smhd'):
+                                print '  --> %s, %s (media information header)' % mdia
+                            else:
+                                print '  --> %s, %s (unknown)' % mdia
+
+                        pos      += mdia[0]
+                        datasize -= mdia[0]
+
+                elif datatype == 'udta' and ATOM_DEBUG:
+                    print struct.unpack('>I4s', atomdata[:8])
+                elif ATOM_DEBUG:
+                    if datatype == 'edts':
+                        print "--> %s [%d] (edit list)" % (datatype, datasize)
+                    else:
+                        print "--> %s [%d] (unknown)" % (datatype, datasize)
+                pos += datasize
+
+        elif atomtype == 'mvhd':
+            # movie header
+            mvhd = struct.unpack('>6I2h', file.read(28))
+            self.length = max(self.length, mvhd[4] / mvhd[3])
+            self.volume = mvhd[6]
+            file.seek(atomsize-8-28,1)
+
+        elif atomtype == 'cmov':
+            # compressed movie
+            datasize, atomtype = struct.unpack('>I4s', file.read(8))
+            if not atomtype == 'dcom':
+                return atomsize
+
+            method = struct.unpack('>4s', file.read(datasize-8))[0]
+
+            datasize, atomtype = struct.unpack('>I4s', file.read(8))
+            if not atomtype == 'cmvd':
+                return atomsize
+
+            if method == 'zlib':
+                data = file.read(datasize-8)
+                try:
+                    decompressed = zlib.decompress(data)
+                except Exception, e:
+                    try:
+                        decompressed = zlib.decompress(data[4:])
+                    except Exception, e:
+                        if mediainfo.DEBUG:
+                            print 'unable to decompress atom'
+                        return atomsize
+                import StringIO
+                decompressedIO = StringIO.StringIO(decompressed)
+                while self._readatom(decompressedIO):
+                    pass
+                
+            else:
+                if mediainfo.DEBUG:
+                    print 'unknown compression %s' % method
+                # unknown compression method
+                file.seek(datasize-8,1)
+        
+        elif atomtype == 'moov':
+            # decompressed movie info
+            while self._readatom(file):
+                pass
+            
+        elif atomtype == 'mdat':
+            pos = file.tell() + atomsize - 8
+            # maybe there is data inside the mdat
+            if ATOM_DEBUG:
+                print 'parsing mdat'
+            while self._readatom(file):
+                pass
+            if ATOM_DEBUG:
+                print 'end of mdat'
+            file.seek(pos, 0)
+            
+        
+        else:
+            if ATOM_DEBUG and not atomtype in ('wide', 'free'):
+                print 'unhandled base atom %s' % atomtype
+
+            # Skip unknown atoms
+            try:
+                file.seek(atomsize-8,1)
+            except IOError:
+                return 0
+
+        return atomsize
+        
+mmpython.registertype( 'video/quicktime', ('mov', 'qt'), mediainfo.TYPE_AV, MovInfo )
+
+# doc links:
+# [1] http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_2.html#//apple_ref/doc/uid/TP40000939-CH206-BBCBIICE
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/ogminfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/ogminfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/ogminfo.py	(revision 4)
@@ -0,0 +1,362 @@
+#if 0
+# -----------------------------------------------------------------------
+# ogminfo.py - Ogg Streaming Video Files
+# -----------------------------------------------------------------------
+# $Id: ogminfo.py,v 1.16 2004/05/20 19:54:52 dischi Exp $
+#
+# $Log: ogminfo.py,v $
+# Revision 1.16  2004/05/20 19:54:52  dischi
+# more ogm fixes
+#
+# Revision 1.15  2004/05/20 08:49:29  dischi
+# more ogm fixes, better length calc (again)
+#
+# Revision 1.14  2004/05/18 21:55:52  dischi
+# o get correct length for ogm files
+# o set metadat for the different streams
+# o chapter support
+#
+# Revision 1.13  2003/09/22 16:21:54  the_krow
+# utf-8 comment parsing
+#
+# Revision 1.12  2003/09/09 19:57:08  dischi
+# bad hack to make length oggs work
+#
+# Revision 1.11  2003/09/09 19:32:26  dischi
+# bugfix for finding oggs
+#
+# Revision 1.10  2003/08/04 08:44:51  the_krow
+# Maximum iterations field added as suggested by Magnus in the
+# freevo list.
+#
+# Revision 1.9  2003/07/13 15:20:53  dischi
+# make the module quiet
+#
+# Revision 1.8  2003/07/10 11:16:31  the_krow
+# o Added length calculation for audio only files.
+# o In the future we will use this as a general parser for ogm/ogg
+#
+# Revision 1.7  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.6  2003/06/29 12:11:16  dischi
+# changed print to _print
+#
+# Revision 1.5  2003/06/23 20:48:11  the_krow
+# width + height fixes for OGM files
+#
+# Revision 1.4  2003/06/23 13:20:51  the_krow
+# basic parsing should now work.
+#
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import struct
+import re
+import stat
+import os
+
+import fourcc
+
+PACKET_TYPE_HEADER   = 0x01
+PACKED_TYPE_METADATA = 0x03
+PACKED_TYPE_SETUP    = 0x05
+PACKET_TYPE_BITS     = 0x07
+PACKET_IS_SYNCPOINT  = 0x08
+
+#VORBIS_VIDEO_PACKET_INFO = 'video'
+
+STREAM_HEADER_VIDEO = '<4sIQQIIHII'
+STREAM_HEADER_AUDIO = '<4sIQQIIHHHI'
+
+_print = mediainfo._debug
+
+VORBISCOMMENT_tags = { 'title': 'TITLE',
+                       'album': 'ALBUM',
+                       'artist': 'ARTIST',
+                       'comment': 'COMMENT',
+                       'date': 'DATE',
+                       'encoder': 'ENCODER',
+                       'trackno': 'TRACKNUMBER',
+                       'language': 'LANGUAGE',
+                       'genre': 'GENRE',
+                     }
+
+MAXITERATIONS = 10
+
+class OgmInfo(mediainfo.AVInfo):
+    def __init__(self, file):
+        mediainfo.AVInfo.__init__(self)
+        self.samplerate  = 1
+        self.all_streams = []           # used to add meta data to streams
+        self.all_header  = []
+
+        for i in range(MAXITERATIONS):
+            granule, nextlen = self._parseOGGS(file)
+            if granule == None:
+                break
+            elif granule > 0:
+                # ok, file started
+                break
+
+        # seek to the end of the stream, to avoid scanning the whole file
+        if (os.stat(file.name)[stat.ST_SIZE] > 50000):
+            file.seek(os.stat(file.name)[stat.ST_SIZE]-49000)
+
+        # read the rest of the file into a buffer
+        h = file.read()
+
+        # find last OggS to get length info
+        if len(h) > 200:
+            idx = h.find('OggS')
+            pos = -49000 + idx
+            if idx:
+                file.seek(os.stat(file.name)[stat.ST_SIZE] + pos)
+            while 1:
+                granule, nextlen = self._parseOGGS(file)
+                if not nextlen:
+                    break
+
+        # Copy metadata to the streams
+        if len(self.all_header) == len(self.all_streams):
+            for i in range(len(self.all_header)):
+                # set length
+                self.length = max(self.all_streams[i].length, self.length)
+
+                # get meta info
+                for key in self.all_streams[i].keys:
+                    if self.all_header[i].has_key(key):
+                        self.all_streams[i][key] = self.all_header[i][key]
+                        del self.all_header[i][key]
+                    if self.all_header[i].has_key(key.upper()):
+                        self.all_streams[i][key] = self.all_header[i][key.upper()]
+                        del self.all_header[i][key.upper()]
+
+                # Extract subtitles:
+                if hasattr(self.all_streams[i], 'type') and \
+                   self.all_streams[i].type == 'subtitle':
+                    self.subtitles.append(self.all_streams[i].language)
+
+                # Chapter parser
+                if self.all_header[i].has_key('CHAPTER01') and not self.chapters:
+                    while 1:
+                        s = 'CHAPTER0%s' % (len(self.chapters) + 1)
+                        if len(s) < 9:
+                            s = '0' + s
+                        if self.all_header[i].has_key(s) and \
+                               self.all_header[i].has_key(s + 'NAME'):
+                            pos = self.all_header[i][s]
+                            try:
+                                pos = int(pos)
+                            except ValueError:
+                                new_pos = 0
+                                for v in pos.split(':'):
+                                    new_pos = new_pos * 60 + float(v)
+                                pos = int(new_pos)
+                                
+                            c = mediainfo.ChapterInfo(self.all_header[i][s + 'NAME'], pos)
+                            del self.all_header[i][s + 'NAME']
+                            del self.all_header[i][s]
+                            self.chapters.append(c)
+                        else:
+                            break
+
+        for stream in self.all_streams:
+            if not stream.length:
+                stream.length = self.length
+                
+        # Copy Metadata from tables into the main set of attributes        
+        for header in self.all_header:
+            self.appendtable('VORBISCOMMENT', header)
+
+        self.tag_map = { ('VORBISCOMMENT', 'en') : VORBISCOMMENT_tags }
+        for k in self.tag_map.keys():
+            _print(k)
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),
+                                      self.tag_map[k][x]), self.tag_map[k].keys())
+
+        
+    def _parseOGGS(self,file):
+        h = file.read(27)
+        if len(h) == 0:
+            # Regular File end
+            return None, None
+        elif len(h) < 27:
+            _print("%d Bytes of Garbage found after End." % len(h))
+            return None, None
+        if h[:4] != "OggS":        
+            self.valid = 0
+            _print("Invalid Ogg")
+            return None, None
+
+        self.valid = 1
+        version = ord(h[4])
+        if version != 0:
+            _print("Unsupported OGG/OGM Version %d." % version)
+            return None, None
+        head = struct.unpack('<BQIIIB', h[5:])
+        headertype, granulepos, serial, pageseqno, checksum, pageSegCount = head
+
+        self.valid = 1
+        self.mime = 'application/ogm'
+        self.type = 'OGG Media'
+        tab = file.read(pageSegCount)
+        nextlen = 0
+        for i in range(len(tab)):
+            nextlen += ord(tab[i])
+        else:
+            h = file.read(1)
+            packettype = ord(h[0]) & PACKET_TYPE_BITS 
+            if packettype == PACKET_TYPE_HEADER:
+                h += file.read(nextlen-1)
+                self._parseHeader(h, granulepos)
+            elif packettype == PACKED_TYPE_METADATA:
+                h += file.read(nextlen-1)
+                self._parseMeta(h)
+            else:
+                file.seek(nextlen-1,1)
+        if len(self.all_streams) > serial:
+            stream = self.all_streams[serial]
+            if hasattr(stream, 'samplerate') and \
+                   stream.samplerate:
+                stream.length = granulepos / stream.samplerate
+            elif hasattr(stream, 'bitrate') and \
+                     stream.bitrate:
+                stream.length = granulepos / stream.bitrate
+
+        return granulepos, nextlen + 27 + pageSegCount
+
+        
+    def _parseMeta(self,h):
+        flags = ord(h[0])
+        headerlen = len(h)
+        if headerlen >= 7 and h[1:7] == 'vorbis':
+            header = {}
+            nextlen, self.encoder = self._extractHeaderString(h[7:])
+            numItems = struct.unpack('<I',h[7+nextlen:7+nextlen+4])[0]
+            start = 7+4+nextlen
+            for i in range(numItems):
+                (nextlen, s) = self._extractHeaderString(h[start:])
+                start += nextlen
+                if s:
+                    a = re.split('=',s)
+                    header[(a[0]).upper()]=a[1]
+            # Put Header fields into info fields
+            self.type = 'OGG Vorbis'
+            self.subtype = ''
+            self.all_header.append(header)
+
+            
+    def _parseHeader(self,header,granule):
+        headerlen = len(header)
+        flags = ord(header[0])
+
+        if headerlen >= 30 and header[1:7] == 'vorbis':
+            #print("Vorbis Audio Header")
+            ai = mediainfo.AudioInfo()
+            ai.version, ai.channels, ai.samplerate, bitrate_max, ai.bitrate, \
+                        bitrate_min, blocksize, framing = \
+                        struct.unpack('<IBIiiiBB',header[7:7+23])
+            ai.codec = 'Vorbis'
+            #ai.granule = granule
+            #ai.length = granule / ai.samplerate
+            self.audio.append(ai)
+            self.all_streams.append(ai)
+            
+        elif headerlen >= 7 and header[1:7] == 'theora':
+            #print "Theora Header"
+            # Theora Header
+            # XXX Finish Me
+            vi = mediainfo.VideoInfo()
+            vi.codec = 'theora'
+            self.video.append(vi)
+            self.all_streams.append(vi)
+
+        elif headerlen >= 142 and header[1:36] == 'Direct Show Samples embedded in Ogg':
+            #print 'Direct Show Samples embedded in Ogg'
+            # Old Directshow format
+            # XXX Finish Me
+            vi = mediainfo.VideoInfo()
+            vi.codec = 'dshow'
+            self.video.append(vi)
+            self.all_streams.append(vi)
+
+        elif flags & PACKET_TYPE_BITS == PACKET_TYPE_HEADER and headerlen >= struct.calcsize(STREAM_HEADER_VIDEO)+1:
+            #print "New Directshow Format"
+            # New Directshow Format
+            htype = header[1:9]
+
+            if htype[:5] == 'video':
+                streamheader = struct.unpack( STREAM_HEADER_VIDEO, header[9:struct.calcsize(STREAM_HEADER_VIDEO)+9] )
+                vi = mediainfo.VideoInfo()
+                (type, ssize, timeunit, samplerate, vi.length, buffersize, \
+                 vi.bitrate, vi.width, vi.height) = streamheader
+
+                vi.width /= 65536
+                vi.height /= 65536
+                # XXX length, bitrate are very wrong
+                try:
+                    vi.codec = fourcc.RIFFCODEC[type]
+                except:
+                    vi.codec = 'Unknown (%s)' % type
+                vi.fps = 10000000 / timeunit
+                self.video.append(vi)
+                self.all_streams.append(vi)
+
+            elif htype[:5] == 'audio':
+                streamheader = struct.unpack( STREAM_HEADER_AUDIO, header[9:struct.calcsize(STREAM_HEADER_AUDIO)+9] )
+                ai = mediainfo.AudioInfo()
+                (type, ssize, timeunit, ai.samplerate, ai.length, buffersize, ai.bitrate, ai.channels, bloc, ai.bitrate) = streamheader
+                self.samplerate = ai.samplerate
+                _print("Samplerate %d" % self.samplerate)
+                self.audio.append(ai)
+                self.all_streams.append(ai)
+
+            elif htype[:4] == 'text':
+                subtitle = mediainfo.MediaInfo()
+                subtitle.keys.append('language')
+                subtitle.type   = 'subtitle'
+                subtitle.length = 0
+                self.all_streams.append(subtitle)
+                
+        else:
+            _print("Unknown Header")
+              
+
+    def _extractHeaderString(self,header):
+        len = struct.unpack( '<I', header[:4] )[0]
+        try:
+            return (len+4,unicode(header[4:4+len], 'utf-8'))
+        except:
+            return (len+4,None)
+
+
+mmpython.registertype( 'application/ogg', ('ogm', 'ogg',), mediainfo.TYPE_AV, OgmInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/realinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/realinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/realinfo.py	(revision 4)
@@ -0,0 +1,129 @@
+#if 0
+# $Id: realinfo.py,v 1.6 2003/07/02 09:09:41 the_krow Exp $
+# $Log: realinfo.py,v $
+# Revision 1.6  2003/07/02 09:09:41  the_krow
+# i18n stuff added to AVI
+# some debug outputs removed
+#
+# Revision 1.5  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.4  2003/06/29 11:59:35  dischi
+# make some debug silent
+#
+# Revision 1.3  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.2  2003/06/12 18:53:19  the_krow
+# OGM detection added.
+# .ram is a valid extension to real files
+#
+# Revision 1.1  2003/06/12 14:43:22  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import struct
+import string
+
+from mmpython import mediainfo
+import mmpython
+
+# http://www.pcisys.net/~melanson/codecs/rmff.htm
+# http://www.pcisys.net/~melanson/codecs/
+
+_print = mediainfo._debug
+
+class RealInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/real'
+        self.type = 'Real Video'
+        h = file.read(10)        
+        (object_id,object_size,object_version) = struct.unpack('>4sIH',h)
+        if object_id == '.RMF':
+            self.valid = 1
+        else:
+            return
+        file_version, num_headers = struct.unpack('>II', file.read(8))
+        _print("size: %d, ver: %d, headers: %d" % (object_size, file_version,num_headers))
+        for i in range(0,num_headers):            
+            (object_id,object_size,object_version) = struct.unpack('>4sIH',file.read(10))
+            self._read_header(object_id, file.read(object_size-10))
+            _print("%s [%d]" % (object_id,object_size-10))
+        # Read all the following headers
+        
+    def _read_header(self,object_id,s):
+        if object_id == 'PROP':
+            prop = struct.unpack('>9IHH', s)
+            _print(prop)
+        if object_id == 'MDPR':
+            mdpr = struct.unpack('>H7I', s[:30])
+            _print(mdpr)
+            self.length = mdpr[7]/1000
+            (stream_name_size,) = struct.unpack('>B', s[30:31])
+            stream_name = s[31:31+stream_name_size]
+            pos = 31+stream_name_size
+            (mime_type_size,) = struct.unpack('>B', s[pos:pos+1])
+            mime = s[pos+1:pos+1+mime_type_size]
+            pos += mime_type_size+1
+            (type_specific_len,) = struct.unpack('>I', s[pos:pos+4])
+            type_specific = s[pos+4:pos+4+type_specific_len]
+            pos += 4+type_specific_len
+            if mime[:5] == 'audio':
+                ai = mediainfo.AudioInfo()
+                ai.id = mdpr[0]
+                ai.bitrate = mdpr[2]
+                self.audio.append(ai)
+            elif mime[:5] == 'video':
+                vi = mediainfo.VideoInfo()
+                vi.id = mdpr[0]
+                vi.bitrate = mdpr[2]
+                self.video.append(vi)
+            else:
+                _print("Unknown: %s" % mime)
+        if object_id == 'CONT':
+            pos = 0
+            (title_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.title = s[2:title_len+2]
+            pos += title_len+2
+            (author_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.artist = s[pos+2:pos+author_len+2]
+            pos += author_len+2
+            (copyright_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.copyright = s[pos+2:pos+copyright_len+2]
+            pos += copyright_len+2
+            (comment_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.comment = s[pos+2:pos+comment_len+2]
+
+mmpython.registertype( 'video/real', ('rm', 'ra', 'ram'), mediainfo.TYPE_AV, RealInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/fourcc.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/fourcc.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/fourcc.py	(revision 4)
@@ -0,0 +1,429 @@
+#if 0
+# $Id: fourcc.py,v 1.3 2003/05/13 12:31:43 the_krow Exp $
+# $Log: fourcc.py,v $
+# Revision 1.3  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+RIFFWAVE = {}
+RIFFCODEC = {}
+
+RIFFWAVE[0x0000] = 'Microsoft Unknown Wave Format';
+RIFFWAVE[0x0001] = 'Microsoft Pulse Code Modulation (PCM)';
+RIFFWAVE[0x0002] = 'Microsoft ADPCM';
+RIFFWAVE[0x0003] = 'IEEE Float';
+RIFFWAVE[0x0004] = 'Compaq Computer VSELP';
+RIFFWAVE[0x0005] = 'IBM CVSD';
+RIFFWAVE[0x0006] = 'Microsoft A-Law';
+RIFFWAVE[0x0007] = 'Microsoft mu-Law';
+RIFFWAVE[0x0010] = 'OKI ADPCM';
+RIFFWAVE[0x0011] = 'Intel DVI/IMA ADPCM';
+RIFFWAVE[0x0012] = 'Videologic MediaSpace ADPCM';
+RIFFWAVE[0x0013] = 'Sierra Semiconductor ADPCM';
+RIFFWAVE[0x0014] = 'Antex Electronics G.723 ADPCM';
+RIFFWAVE[0x0015] = 'DSP Solutions DigiSTD';
+RIFFWAVE[0x0016] = 'DSP Solutions DigiFIX';
+RIFFWAVE[0x0017] = 'Dialogic OKI ADPCM';
+RIFFWAVE[0x0018] = 'MediaVision ADPCM';
+RIFFWAVE[0x0019] = 'Hewlett-Packard CU';
+RIFFWAVE[0x0020] = 'Yamaha ADPCM';
+RIFFWAVE[0x0021] = 'Speech Compression Sonarc';
+RIFFWAVE[0x0022] = 'DSP Group TrueSpeech';
+RIFFWAVE[0x0023] = 'Echo Speech EchoSC1';
+RIFFWAVE[0x0024] = 'Audiofile AF36';
+RIFFWAVE[0x0025] = 'Audio Processing Technology APTX';
+RIFFWAVE[0x0026] = 'AudioFile AF10';
+RIFFWAVE[0x0027] = 'Prosody 1612';
+RIFFWAVE[0x0028] = 'LRC';
+RIFFWAVE[0x0030] = 'Dolby AC2';
+RIFFWAVE[0x0031] = 'Microsoft GSM 6.10';
+RIFFWAVE[0x0032] = 'MSNAudio';
+RIFFWAVE[0x0033] = 'Antex Electronics ADPCME';
+RIFFWAVE[0x0034] = 'Control Resources VQLPC';
+RIFFWAVE[0x0035] = 'DSP Solutions DigiREAL';
+RIFFWAVE[0x0036] = 'DSP Solutions DigiADPCM';
+RIFFWAVE[0x0037] = 'Control Resources CR10';
+RIFFWAVE[0x0038] = 'Natural MicroSystems VBXADPCM';
+RIFFWAVE[0x0039] = 'Crystal Semiconductor IMA ADPCM';
+RIFFWAVE[0x003A] = 'EchoSC3';
+RIFFWAVE[0x003B] = 'Rockwell ADPCM';
+RIFFWAVE[0x003C] = 'Rockwell Digit LK';
+RIFFWAVE[0x003D] = 'Xebec';
+RIFFWAVE[0x0040] = 'Antex Electronics G.721 ADPCM';
+RIFFWAVE[0x0041] = 'G.728 CELP';
+RIFFWAVE[0x0042] = 'MSG723';
+RIFFWAVE[0x0050] = 'Microsoft MPEG';
+RIFFWAVE[0x0052] = 'RT24';
+RIFFWAVE[0x0053] = 'PAC';
+RIFFWAVE[0x0055] = 'MPEG Layer 3';
+RIFFWAVE[0x0059] = 'Lucent G.723';
+RIFFWAVE[0x0060] = 'Cirrus';
+RIFFWAVE[0x0061] = 'ESPCM';
+RIFFWAVE[0x0062] = 'Voxware';
+RIFFWAVE[0x0063] = 'Canopus Atrac';
+RIFFWAVE[0x0064] = 'G.726 ADPCM';
+RIFFWAVE[0x0065] = 'G.722 ADPCM';
+RIFFWAVE[0x0066] = 'DSAT';
+RIFFWAVE[0x0067] = 'DSAT Display';
+RIFFWAVE[0x0069] = 'Voxware Byte Aligned';
+RIFFWAVE[0x0070] = 'Voxware AC8';
+RIFFWAVE[0x0071] = 'Voxware AC10';
+RIFFWAVE[0x0072] = 'Voxware AC16';
+RIFFWAVE[0x0073] = 'Voxware AC20';
+RIFFWAVE[0x0074] = 'Voxware MetaVoice';
+RIFFWAVE[0x0075] = 'Voxware MetaSound';
+RIFFWAVE[0x0076] = 'Voxware RT29HW';
+RIFFWAVE[0x0077] = 'Voxware VR12';
+RIFFWAVE[0x0078] = 'Voxware VR18';
+RIFFWAVE[0x0079] = 'Voxware TQ40';
+RIFFWAVE[0x0080] = 'Softsound';
+RIFFWAVE[0x0081] = 'Voxware TQ60';
+RIFFWAVE[0x0082] = 'MSRT24';
+RIFFWAVE[0x0083] = 'G.729A';
+RIFFWAVE[0x0084] = 'MVI MV12';
+RIFFWAVE[0x0085] = 'DF G.726';
+RIFFWAVE[0x0086] = 'DF GSM610';
+RIFFWAVE[0x0088] = 'ISIAudio';
+RIFFWAVE[0x0089] = 'Onlive';
+RIFFWAVE[0x0091] = 'SBC24';
+RIFFWAVE[0x0092] = 'Dolby AC3 SPDIF';
+RIFFWAVE[0x0097] = 'ZyXEL ADPCM';
+RIFFWAVE[0x0098] = 'Philips LPCBB';
+RIFFWAVE[0x0099] = 'Packed';
+RIFFWAVE[0x0100] = 'Rhetorex ADPCM';
+RIFFWAVE[0x0101] = 'IBM mu-law';
+RIFFWAVE[0x0102] = 'IBM A-law';
+RIFFWAVE[0x0103] = 'IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)';
+RIFFWAVE[0x0111] = 'Vivo G.723';
+RIFFWAVE[0x0112] = 'Vivo Siren';
+RIFFWAVE[0x0123] = 'Digital G.723';
+RIFFWAVE[0x0140] = 'Windows Media Video V8';
+RIFFWAVE[0x0161] = 'Windows Media Audio V7 / V8 / V9';
+RIFFWAVE[0x0162] = 'Windows Media Audio Professional V9';
+RIFFWAVE[0x0163] = 'Windows Media Audio Lossless V9';
+RIFFWAVE[0x0200] = 'Creative Labs ADPCM';
+RIFFWAVE[0x0202] = 'Creative Labs Fastspeech8';
+RIFFWAVE[0x0203] = 'Creative Labs Fastspeech10';
+RIFFWAVE[0x0220] = 'Quarterdeck';
+RIFFWAVE[0x0300] = 'FM Towns Snd';
+RIFFWAVE[0x0300] = 'Fujitsu FM Towns Snd';
+RIFFWAVE[0x0400] = 'BTV Digital';
+RIFFWAVE[0x0680] = 'VME VMPCM';
+RIFFWAVE[0x1000] = 'Olivetti GSM';
+RIFFWAVE[0x1001] = 'Olivetti ADPCM';
+RIFFWAVE[0x1002] = 'Olivetti CELP';
+RIFFWAVE[0x1003] = 'Olivetti SBC';
+RIFFWAVE[0x1004] = 'Olivetti OPR';
+RIFFWAVE[0x1100] = 'Lernout & Hauspie LH Codec';
+RIFFWAVE[0x1400] = 'Norris';
+RIFFWAVE[0x1401] = 'AT&T ISIAudio';
+RIFFWAVE[0x1500] = 'Soundspace Music Compression';
+RIFFWAVE[0x2000] = 'AC3';
+RIFFWAVE[0x7A21] = 'GSM-AMR (CBR, no SID)';
+RIFFWAVE[0x7A22] = 'GSM-AMR (VBR, including SID)';
+RIFFWAVE[0xFFFF] = 'development';
+
+RIFFCODEC['3IV1'] = '3ivx v1'
+RIFFCODEC['3IV2'] = '3ivx v2'
+RIFFCODEC['AASC'] = 'Autodesk Animator'
+RIFFCODEC['ABYR'] = 'Kensington ?ABYR?'
+RIFFCODEC['AEMI'] = 'Array VideoONE MPEG1-I Capture'
+RIFFCODEC['AFLC'] = 'Autodesk Animator FLC'
+RIFFCODEC['AFLI'] = 'Autodesk Animator FLI'
+RIFFCODEC['AMPG'] = 'Array VideoONE MPEG'
+RIFFCODEC['ANIM'] = 'Intel RDX (ANIM)'
+RIFFCODEC['AP41'] = 'AngelPotion Definitive'
+RIFFCODEC['ASV1'] = 'Asus Video v1'
+RIFFCODEC['ASV2'] = 'Asus Video v2'
+RIFFCODEC['ASVX'] = 'Asus Video 2.0 (audio)'
+RIFFCODEC['AUR2'] = 'Aura 2 Codec - YUV 4:2:2'
+RIFFCODEC['AURA'] = 'Aura 1 Codec - YUV 4:1:1'
+RIFFCODEC['BINK'] = 'RAD Game Tools Bink Video'
+RIFFCODEC['BT20'] = 'Conexant Prosumer Video'
+RIFFCODEC['BTCV'] = 'Conexant Composite Video Codec'
+RIFFCODEC['BW10'] = 'Data Translation Broadway MPEG Capture'
+RIFFCODEC['CC12'] = 'Intel YUV12'
+RIFFCODEC['CDVC'] = 'Canopus DV'
+RIFFCODEC['CFCC'] = 'Digital Processing Systems DPS Perception'
+RIFFCODEC['CGDI'] = 'Microsoft Office 97 Camcorder Video'
+RIFFCODEC['CHAM'] = 'Winnov Caviara Champagne'
+RIFFCODEC['CJPG'] = 'Creative WebCam JPEG'
+RIFFCODEC['CLJR'] = 'Cirrus Logic YUV 4 pixels'
+RIFFCODEC['CMYK'] = 'Common Data Format in Printing'
+RIFFCODEC['CPLA'] = 'Weitek 4:2:0 YUV Planar'
+RIFFCODEC['CRAM'] = 'Microsoft Video 1 (CRAM)'
+RIFFCODEC['CVID'] = 'Radius Cinepak'
+RIFFCODEC['CWLT'] = '?CWLT?'
+RIFFCODEC['CWLT'] = 'Microsoft Color WLT DIB'
+RIFFCODEC['CYUV'] = 'Creative Labs YUV'
+RIFFCODEC['CYUY'] = 'ATI YUV'
+RIFFCODEC['D261'] = 'H.261'
+RIFFCODEC['D263'] = 'H.263'
+RIFFCODEC['DIV3'] = 'DivX v3 MPEG-4 Low-Motion'
+RIFFCODEC['DIV4'] = 'DivX v3 MPEG-4 Fast-Motion'
+RIFFCODEC['DIV5'] = '?DIV5?'
+RIFFCODEC['DIVX'] = 'DivX v4'
+RIFFCODEC['divx'] = 'DivX'
+RIFFCODEC['DMB1'] = 'Matrox Rainbow Runner hardware MJPEG'
+RIFFCODEC['DMB2'] = 'Paradigm MJPEG'
+RIFFCODEC['DSVD'] = '?DSVD?'
+RIFFCODEC['DUCK'] = 'Duck True Motion 1.0'
+RIFFCODEC['DVAN'] = '?DVAN?'
+RIFFCODEC['DVE2'] = 'InSoft DVE-2 Videoconferencing'
+RIFFCODEC['dvsd'] = 'DV'
+RIFFCODEC['DVSD'] = 'DV'
+RIFFCODEC['DVX1'] = 'DVX1000SP Video Decoder'
+RIFFCODEC['DVX2'] = 'DVX2000S Video Decoder'
+RIFFCODEC['DVX3'] = 'DVX3000S Video Decoder'
+RIFFCODEC['DX50'] = 'DivX v5'
+RIFFCODEC['DXT1'] = 'Microsoft DirectX Compressed Texture (DXT1)'
+RIFFCODEC['DXT2'] = 'Microsoft DirectX Compressed Texture (DXT2)'
+RIFFCODEC['DXT3'] = 'Microsoft DirectX Compressed Texture (DXT3)'
+RIFFCODEC['DXT4'] = 'Microsoft DirectX Compressed Texture (DXT4)'
+RIFFCODEC['DXT5'] = 'Microsoft DirectX Compressed Texture (DXT5)'
+RIFFCODEC['DXTC'] = 'Microsoft DirectX Compressed Texture (DXTC)'
+RIFFCODEC['EKQ0'] = 'Elsa ?EKQ0?'
+RIFFCODEC['ELK0'] = 'Elsa ?ELK0?'
+RIFFCODEC['ESCP'] = 'Eidos Escape'
+RIFFCODEC['ETV1'] = 'eTreppid Video ETV1'
+RIFFCODEC['ETV2'] = 'eTreppid Video ETV2'
+RIFFCODEC['ETVC'] = 'eTreppid Video ETVC'
+RIFFCODEC['FLJP'] = 'D-Vision Field Encoded Motion JPEG'
+RIFFCODEC['FRWA'] = 'SoftLab-Nsk Forward Motion JPEG w/ alpha channel'
+RIFFCODEC['FRWD'] = 'SoftLab-Nsk Forward Motion JPEG'
+RIFFCODEC['FVF1'] = 'Iterated Systems Fractal Video Frame'
+RIFFCODEC['GLZW'] = 'Motion LZW (gabest@freemail.hu)'
+RIFFCODEC['GPEG'] = 'Motion JPEG (gabest@freemail.hu)'
+RIFFCODEC['GWLT'] = 'Microsoft Greyscale WLT DIB'
+RIFFCODEC['H260'] = 'Intel ITU H.260 Videoconferencing'
+RIFFCODEC['H261'] = 'Intel ITU H.261 Videoconferencing'
+RIFFCODEC['H262'] = 'Intel ITU H.262 Videoconferencing'
+RIFFCODEC['H263'] = 'Intel ITU H.263 Videoconferencing'
+RIFFCODEC['H264'] = 'Intel ITU H.264 Videoconferencing'
+RIFFCODEC['H265'] = 'Intel ITU H.265 Videoconferencing'
+RIFFCODEC['H266'] = 'Intel ITU H.266 Videoconferencing'
+RIFFCODEC['H267'] = 'Intel ITU H.267 Videoconferencing'
+RIFFCODEC['H268'] = 'Intel ITU H.268 Videoconferencing'
+RIFFCODEC['H269'] = 'Intel ITU H.269 Videoconferencing'
+RIFFCODEC['HFYU'] = 'Huffman Lossless Codec'
+RIFFCODEC['HMCR'] = 'Rendition Motion Compensation Format (HMCR)'
+RIFFCODEC['HMRR'] = 'Rendition Motion Compensation Format (HMRR)'
+RIFFCODEC['i263'] = 'Intel ITU H.263 Videoconferencing (i263)'
+RIFFCODEC['I420'] = 'Intel Indeo 4'
+RIFFCODEC['IAN '] = 'Intel RDX'
+RIFFCODEC['ICLB'] = 'InSoft CellB Videoconferencing'
+RIFFCODEC['IGOR'] = 'Power DVD'
+RIFFCODEC['IJPG'] = 'Intergraph JPEG'
+RIFFCODEC['ILVC'] = 'Intel Layered Video'
+RIFFCODEC['ILVR'] = 'ITU-T H.263+'
+RIFFCODEC['IPDV'] = 'I-O Data Device Giga AVI DV Codec'
+RIFFCODEC['IR21'] = 'Intel Indeo 2.1'
+RIFFCODEC['IRAW'] = 'Intel YUV Uncompressed'
+RIFFCODEC['IV30'] = 'Ligos Indeo 3.0'
+RIFFCODEC['IV31'] = 'Ligos Indeo 3.1'
+RIFFCODEC['IV32'] = 'Ligos Indeo 3.2'
+RIFFCODEC['IV33'] = 'Ligos Indeo 3.3'
+RIFFCODEC['IV34'] = 'Ligos Indeo 3.4'
+RIFFCODEC['IV35'] = 'Ligos Indeo 3.5'
+RIFFCODEC['IV36'] = 'Ligos Indeo 3.6'
+RIFFCODEC['IV37'] = 'Ligos Indeo 3.7'
+RIFFCODEC['IV38'] = 'Ligos Indeo 3.8'
+RIFFCODEC['IV39'] = 'Ligos Indeo 3.9'
+RIFFCODEC['IV40'] = 'Ligos Indeo Interactive 4.0'
+RIFFCODEC['IV41'] = 'Ligos Indeo Interactive 4.1'
+RIFFCODEC['IV42'] = 'Ligos Indeo Interactive 4.2'
+RIFFCODEC['IV43'] = 'Ligos Indeo Interactive 4.3'
+RIFFCODEC['IV44'] = 'Ligos Indeo Interactive 4.4'
+RIFFCODEC['IV45'] = 'Ligos Indeo Interactive 4.5'
+RIFFCODEC['IV46'] = 'Ligos Indeo Interactive 4.6'
+RIFFCODEC['IV47'] = 'Ligos Indeo Interactive 4.7'
+RIFFCODEC['IV48'] = 'Ligos Indeo Interactive 4.8'
+RIFFCODEC['IV49'] = 'Ligos Indeo Interactive 4.9'
+RIFFCODEC['IV50'] = 'Ligos Indeo Interactive 5.0'
+RIFFCODEC['JBYR'] = 'Kensington ?JBYR?'
+RIFFCODEC['JPEG'] = 'Still Image JPEG DIB'
+RIFFCODEC['JPGL'] = 'Webcam JPEG Light?'
+RIFFCODEC['KMVC'] = 'Karl Morton\'s Video Codec'
+RIFFCODEC['LEAD'] = 'LEAD Video Codec'
+RIFFCODEC['Ljpg'] = 'LEAD MJPEG Codec'
+RIFFCODEC['M261'] = 'Microsoft H.261'
+RIFFCODEC['M263'] = 'Microsoft H.263'
+RIFFCODEC['M4S2'] = 'Microsoft MPEG-4 (M4S2)'
+RIFFCODEC['m4s2'] = 'Microsoft MPEG-4 (m4s2)'
+RIFFCODEC['MC12'] = 'ATI Motion Compensation Format (MC12)'
+RIFFCODEC['MCAM'] = 'ATI Motion Compensation Format (MCAM)'
+RIFFCODEC['MJ2C'] = 'Morgan Multimedia Motion JPEG2000'
+RIFFCODEC['mJPG'] = 'IBM Motion JPEG w/ Huffman Tables'
+RIFFCODEC['MJPG'] = 'Motion JPEG DIB'
+RIFFCODEC['MP42'] = 'Microsoft MPEG-4 (low-motion)'
+RIFFCODEC['MP43'] = 'Microsoft MPEG-4 (fast-motion)'
+RIFFCODEC['MP4S'] = 'Microsoft MPEG-4 (MP4S)'
+RIFFCODEC['mp4s'] = 'Microsoft MPEG-4 (mp4s)'
+RIFFCODEC['MPEG'] = 'MPEG 1 Video I-Frame'
+RIFFCODEC['MPG4'] = 'Microsoft MPEG-4 Video High Speed Compressor'
+RIFFCODEC['MPGI'] = 'Sigma Designs MPEG'
+RIFFCODEC['MRCA'] = 'FAST Multimedia Mrcodec'
+RIFFCODEC['MRCA'] = 'Martin Regen Codec'
+RIFFCODEC['MRLE'] = 'Microsoft RLE'
+RIFFCODEC['MRLE'] = 'Run Length Encoding'
+RIFFCODEC['MSVC'] = 'Microsoft Video 1'
+RIFFCODEC['MTX1'] = 'Matrox ?MTX1?'
+RIFFCODEC['MTX2'] = 'Matrox ?MTX2?'
+RIFFCODEC['MTX3'] = 'Matrox ?MTX3?'
+RIFFCODEC['MTX4'] = 'Matrox ?MTX4?'
+RIFFCODEC['MTX5'] = 'Matrox ?MTX5?'
+RIFFCODEC['MTX6'] = 'Matrox ?MTX6?'
+RIFFCODEC['MTX7'] = 'Matrox ?MTX7?'
+RIFFCODEC['MTX8'] = 'Matrox ?MTX8?'
+RIFFCODEC['MTX9'] = 'Matrox ?MTX9?'
+RIFFCODEC['MV12'] = '?MV12?'
+RIFFCODEC['MWV1'] = 'Aware Motion Wavelets'
+RIFFCODEC['nAVI'] = '?nAVI?'
+RIFFCODEC['NTN1'] = 'Nogatech Video Compression 1'
+RIFFCODEC['NVS0'] = 'nVidia GeForce Texture (NVS0)'
+RIFFCODEC['NVS1'] = 'nVidia GeForce Texture (NVS1)'
+RIFFCODEC['NVS2'] = 'nVidia GeForce Texture (NVS2)'
+RIFFCODEC['NVS3'] = 'nVidia GeForce Texture (NVS3)'
+RIFFCODEC['NVS4'] = 'nVidia GeForce Texture (NVS4)'
+RIFFCODEC['NVS5'] = 'nVidia GeForce Texture (NVS5)'
+RIFFCODEC['NVT0'] = 'nVidia GeForce Texture (NVT0)'
+RIFFCODEC['NVT1'] = 'nVidia GeForce Texture (NVT1)'
+RIFFCODEC['NVT2'] = 'nVidia GeForce Texture (NVT2)'
+RIFFCODEC['NVT3'] = 'nVidia GeForce Texture (NVT3)'
+RIFFCODEC['NVT4'] = 'nVidia GeForce Texture (NVT4)'
+RIFFCODEC['NVT5'] = 'nVidia GeForce Texture (NVT5)'
+RIFFCODEC['PDVC'] = 'I-O Data Device Digital Video Capture DV codec'
+RIFFCODEC['PGVV'] = 'Radius Video Vision'
+RIFFCODEC['PHMO'] = 'IBM Photomotion'
+RIFFCODEC['PIM1'] = 'Pegasus Imaging ?PIM1?'
+RIFFCODEC['PIM2'] = 'Pegasus Imaging ?PIM2?'
+RIFFCODEC['PIMJ'] = 'Pegasus Imaging Lossless JPEG'
+RIFFCODEC['PVEZ'] = 'Horizons Technology PowerEZ'
+RIFFCODEC['PVMM'] = 'PacketVideo Corporation MPEG-4'
+RIFFCODEC['PVW2'] = 'Pegasus Imaging Wavelet Compression'
+RIFFCODEC['QPEG'] = 'Q-Team QPEG 1.0'
+RIFFCODEC['qpeq'] = 'Q-Team QPEG 1.1'
+RIFFCODEC['RGBT'] = 'Computer Concepts 32-bit support'
+RIFFCODEC['RLE '] = 'Microsoft Run Length Encoder'
+RIFFCODEC['RLE4'] = 'Run Length Encoded 4'
+RIFFCODEC['RLE8'] = 'Run Length Encoded 8'
+RIFFCODEC['RT21'] = 'Intel Indeo 2.1'
+RIFFCODEC['RT21'] = 'Intel Real Time Video 2.1'
+RIFFCODEC['rv20'] = 'RealVideo G2'
+RIFFCODEC['rv30'] = 'RealVideo 8'
+RIFFCODEC['RVX '] = 'Intel RDX (RVX )'
+RIFFCODEC['s422'] = 'Tekram VideoCap C210 YUV 4:2:2'
+RIFFCODEC['SDCC'] = 'Sun Communication Digital Camera Codec'
+RIFFCODEC['SFMC'] = 'CrystalNet Surface Fitting Method'
+RIFFCODEC['SMSC'] = 'Radius SMSC'
+RIFFCODEC['SMSD'] = 'Radius SMSD'
+RIFFCODEC['smsv'] = 'WorldConnect Wavelet Video'
+RIFFCODEC['SPIG'] = 'Radius Spigot'
+RIFFCODEC['SPLC'] = 'Splash Studios ACM Audio Codec'
+RIFFCODEC['SQZ2'] = 'Microsoft VXTreme Video Codec V2'
+RIFFCODEC['STVA'] = 'ST CMOS Imager Data (Bayer)'
+RIFFCODEC['STVB'] = 'ST CMOS Imager Data (Nudged Bayer)'
+RIFFCODEC['STVC'] = 'ST CMOS Imager Data (Bunched)'
+RIFFCODEC['STVX'] = 'ST CMOS Imager Data (Extended CODEC Data Format)'
+RIFFCODEC['STVY'] = 'ST CMOS Imager Data (Extended CODEC Data Format with Correction Data)'
+RIFFCODEC['SV10'] = 'Sorenson Video R1'
+RIFFCODEC['SVQ1'] = 'Sorenson Video'
+RIFFCODEC['SVQ1'] = 'Sorenson Video R3'
+RIFFCODEC['TLMS'] = 'TeraLogic Motion Intraframe Codec (TLMS)'
+RIFFCODEC['TLST'] = 'TeraLogic Motion Intraframe Codec (TLST)'
+RIFFCODEC['TM20'] = 'Duck TrueMotion 2.0'
+RIFFCODEC['TM2X'] = 'Duck TrueMotion 2X'
+RIFFCODEC['TMIC'] = 'TeraLogic Motion Intraframe Codec (TMIC)'
+RIFFCODEC['TMOT'] = 'Horizons Technology TrueMotion S'
+RIFFCODEC['tmot'] = 'Horizons TrueMotion Video Compression'
+RIFFCODEC['TR20'] = 'Duck TrueMotion RealTime 2.0'
+RIFFCODEC['TSCC'] = 'TechSmith Screen Capture Codec'
+RIFFCODEC['TV10'] = 'Tecomac Low-Bit Rate Codec'
+RIFFCODEC['TY0N'] = 'Trident ?TY0N?'
+RIFFCODEC['TY2C'] = 'Trident ?TY2C?'
+RIFFCODEC['TY2N'] = 'Trident ?TY2N?'
+RIFFCODEC['UCOD'] = 'eMajix.com ClearVideo'
+RIFFCODEC['ULTI'] = 'IBM Ultimotion'
+RIFFCODEC['UYVY'] = 'UYVY 4:2:2 byte ordering'
+RIFFCODEC['V261'] = 'Lucent VX2000S'
+RIFFCODEC['V422'] = '24 bit YUV 4:2:2 Format'
+RIFFCODEC['V655'] = '16 bit YUV 4:2:2 Format'
+RIFFCODEC['VCR1'] = 'ATI VCR 1.0'
+RIFFCODEC['VCR2'] = 'ATI VCR 2.0'
+RIFFCODEC['VCR3'] = 'ATI VCR 3.0'
+RIFFCODEC['VCR4'] = 'ATI VCR 4.0'
+RIFFCODEC['VCR5'] = 'ATI VCR 5.0'
+RIFFCODEC['VCR6'] = 'ATI VCR 6.0'
+RIFFCODEC['VCR7'] = 'ATI VCR 7.0'
+RIFFCODEC['VCR8'] = 'ATI VCR 8.0'
+RIFFCODEC['VCR9'] = 'ATI VCR 9.0'
+RIFFCODEC['VDCT'] = 'Video Maker Pro DIB'
+RIFFCODEC['VDOM'] = 'VDOnet VDOWave'
+RIFFCODEC['VDOW'] = 'VDOnet VDOLive (H.263)'
+RIFFCODEC['VDTZ'] = 'Darim Vison VideoTizer YUV'
+RIFFCODEC['VGPX'] = 'VGPixel Codec'
+RIFFCODEC['VIDS'] = 'Vitec Multimedia YUV 4:2:2 CCIR 601 for V422'
+RIFFCODEC['VIDS'] = 'YUV 4:2:2 CCIR 601 for V422'
+RIFFCODEC['VIFP'] = '?VIFP?'
+RIFFCODEC['VIVO'] = 'Vivo H.263 v2.00'
+RIFFCODEC['vivo'] = 'Vivo H.263'
+RIFFCODEC['VIXL'] = 'Miro Video XL'
+RIFFCODEC['VLV1'] = 'Videologic VLCAP.DRV'
+RIFFCODEC['VP30'] = 'On2 VP3.0'
+RIFFCODEC['VP31'] = 'On2 VP3.1'
+RIFFCODEC['VX1K'] = 'VX1000S Video Codec'
+RIFFCODEC['VX2K'] = 'VX2000S Video Codec'
+RIFFCODEC['VXSP'] = 'VX1000SP Video Codec'
+RIFFCODEC['WBVC'] = 'Winbond W9960'
+RIFFCODEC['WHAM'] = 'Microsoft Video 1 (WHAM)'
+RIFFCODEC['WINX'] = 'Winnov Software Compression'
+RIFFCODEC['WJPG'] = 'AverMedia Winbond JPEG'
+RIFFCODEC['WMV1'] = 'Windows Media Video V7'
+RIFFCODEC['WMV2'] = 'Windows Media Video V8'
+RIFFCODEC['WMV3'] = 'Windows Media Video V9'
+RIFFCODEC['WNV1'] = 'Winnov Hardware Compression'
+RIFFCODEC['x263'] = 'Xirlink H.263'
+RIFFCODEC['XLV0'] = 'NetXL Video Decoder'
+RIFFCODEC['XMPG'] = 'Xing MPEG (I-Frame only)'
+RIFFCODEC['XVID'] = 'XviD MPEG-4'
+RIFFCODEC['XXAN'] = '?XXAN?'
+RIFFCODEC['Y211'] = 'YUV 2:1:1 Packed'
+RIFFCODEC['Y411'] = 'YUV 4:1:1 Packed'
+RIFFCODEC['Y41B'] = 'YUV 4:1:1 Planar'
+RIFFCODEC['Y41P'] = 'PC1 4:1:1'
+RIFFCODEC['Y41T'] = 'PC1 4:1:1 with transparency'
+RIFFCODEC['Y42B'] = 'YUV 4:2:2 Planar'
+RIFFCODEC['Y42T'] = 'PCI 4:2:2 with transparency'
+RIFFCODEC['Y8  '] = 'Grayscale video'
+RIFFCODEC['YC12'] = 'Intel YUV 12 codec'
+RIFFCODEC['YC12'] = 'Intel YUV12 Codec'
+RIFFCODEC['YUV8'] = 'Winnov Caviar YUV8'
+RIFFCODEC['YUV9'] = 'Intel YUV9'
+RIFFCODEC['YUY2'] = 'Uncompressed YUV 4:2:2'
+RIFFCODEC['YUYV'] = 'Canopus YUV'
+RIFFCODEC['YV12'] = 'YVU12 Planar'
+RIFFCODEC['YVU9'] = 'Intel YVU9 Planar'
+RIFFCODEC['YVYU'] = 'YVYU 4:2:2 byte ordering'
+RIFFCODEC['ZLIB'] = '?ZLIB?'
+RIFFCODEC['ZPEG'] = 'Metheus Video Zipper'
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/video/riffinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/video/riffinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/video/riffinfo.py	(revision 4)
@@ -0,0 +1,539 @@
+#if 0
+# $Id: riffinfo.py,v 1.33 2005/03/15 17:50:45 dischi Exp $
+# $Log: riffinfo.py,v $
+# Revision 1.33  2005/03/15 17:50:45  dischi
+# check for corrupt avi
+#
+# Revision 1.32  2005/03/04 17:41:29  dischi
+# handle broken avi files
+#
+# Revision 1.31  2004/12/13 10:19:07  dischi
+# more debug, support LIST > 20000 (new max is 80000)
+#
+# Revision 1.30  2004/08/25 16:18:14  dischi
+# detect aspect ratio
+#
+# Revision 1.29  2004/05/24 16:17:09  dischi
+# Small changes for future updates
+#
+# Revision 1.28  2004/01/31 12:23:46  dischi
+# remove bad chars from table (e.g. char 0 is True)
+#
+# Revision 1.27  2003/10/04 14:30:08  dischi
+# add audio delay for avi
+#
+# Revision 1.26  2003/07/10 11:18:11  the_krow
+# few more attributes added
+#
+# Revision 1.25  2003/07/07 21:36:44  dischi
+# make fps a float and round it to two digest after the comma
+#
+# Revision 1.24  2003/07/05 19:36:37  the_krow
+# length fixed
+# fps introduced
+#
+# Revision 1.23  2003/07/02 11:17:30  the_krow
+# language is now part of the table key
+#
+# Revision 1.22  2003/07/01 21:06:50  dischi
+# no need to import factory (and when, use "from mmpython import factory"
+#
+# Revision 1.21  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.20  2003/06/23 20:48:11  the_krow
+# width + height fixes for OGM files
+#
+# Revision 1.19  2003/06/23 20:38:04  the_krow
+# Support for larger LIST chunks because some files did not work.
+#
+# Revision 1.18  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.17  2003/06/20 19:05:56  dischi
+# scan for subtitles
+#
+# Revision 1.16  2003/06/20 15:29:42  the_krow
+# Metadata Mapping
+#
+# Revision 1.15  2003/06/20 14:43:57  the_krow
+# Putting Metadata into MediaInfo from AVIInfo Table
+#
+# Revision 1.14  2003/06/09 16:10:52  dischi
+# error handling
+#
+# Revision 1.13  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.12  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.11  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.10  2003/06/07 23:10:50  the_krow
+# Changed mp3 into new format.
+#
+# Revision 1.9  2003/06/07 22:30:22  the_krow
+# added new avinfo structure
+#
+# Revision 1.8  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.7  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import fourcc
+# import factory
+
+import mmpython
+from mmpython import mediainfo
+
+
+# List of tags
+# http://kibus1.narod.ru/frames_eng.htm?sof/abcavi/infotags.htm
+# http://www.divx-digest.com/software/avitags_dll.html
+# File Format
+# http://www.taenam.co.kr/pds/documents/odmlff2.pdf
+
+_print = mediainfo._debug
+
+AVIINFO_tags = { 'title': 'INAM',
+                 'artist': 'IART',
+                 'product': 'IPRD',
+                 'date': 'ICRD',
+                 'comment': 'ICMT',
+                 'language': 'ILNG',
+                 'keywords': 'IKEY',
+                 'trackno': 'IPRT',
+                 'trackof': 'IFRM',
+                 'producer': 'IPRO',
+                 'writer': 'IWRI',
+                 'genre': 'IGNR',
+                 'copyright': 'ICOP',
+                 'trackno': 'IPRT',
+                 'trackof': 'IFRM',
+                 'comment': 'ICMT',
+               }
+
+
+
+class RiffInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        # read the header
+        h = file.read(12)
+        if h[:4] != "RIFF" and h[:4] != 'SDSS':
+            self.valid = 0
+            return
+        self.valid = 1
+        self.mime = 'application/x-wave'
+        self.has_idx = False
+        self.header = {}
+        self.junkStart = None
+        self.infoStart = None
+        self.type = h[8:12]
+        self.tag_map = { ('AVIINFO', 'en') : AVIINFO_tags }
+        if self.type == 'AVI ':
+            self.mime = 'video/avi'
+        elif self.type == 'WAVE':
+            self.mime = 'application/x-wave'
+        try:
+            while self.parseRIFFChunk(file):
+                pass
+        except IOError:
+            if mediainfo.DEBUG:
+                print 'error in file, stop parsing'
+
+        self.find_subtitles(file.name)
+        
+        # Copy Metadata from tables into the main set of attributes        
+        for k in self.tag_map.keys():
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),self.tag_map[k][x]),
+                self.tag_map[k].keys())
+        if not self.has_idx:
+            _print('WARNING: avi has no index')
+            self.corrupt = 1
+            self.keys.append('corrupt')
+            
+        
+    def _extractHeaderString(self,h,offset,len):
+        return h[offset:offset+len]
+
+    def parseAVIH(self,t):
+        retval = {}
+        v = struct.unpack('<IIIIIIIIIIIIII',t[0:56])
+        ( retval['dwMicroSecPerFrame'],
+          retval['dwMaxBytesPerSec'],           
+          retval['dwPaddingGranularity'], 
+          retval['dwFlags'], 
+          retval['dwTotalFrames'],
+          retval['dwInitialFrames'],
+          retval['dwStreams'],
+          retval['dwSuggestedBufferSize'],
+          retval['dwWidth'],
+          retval['dwHeight'],
+          retval['dwScale'],
+          retval['dwRate'],
+          retval['dwStart'],
+          retval['dwLength'] ) = v
+        if retval['dwMicroSecPerFrame'] == 0:
+            _print("ERROR: Corrupt AVI")
+            self.valid = 0
+            return {}
+        return retval
+        
+    def parseSTRH(self,t):
+        retval = {}
+        retval['fccType'] = t[0:4]
+        _print("parseSTRH(%s) : %d bytes" % ( retval['fccType'], len(t)))
+        if retval['fccType'] != 'auds':
+            retval['fccHandler'] = t[4:8]
+            v = struct.unpack('<IHHIIIIIIIII',t[8:52])
+            ( retval['dwFlags'],
+              retval['wPriority'],
+              retval['wLanguage'],
+              retval['dwInitialFrames'],
+              retval['dwScale'],
+              retval['dwRate'],
+              retval['dwStart'],
+              retval['dwLength'],
+              retval['dwSuggestedBufferSize'],
+              retval['dwQuality'],
+              retval['dwSampleSize'],
+              retval['rcFrame'], ) = v
+        else:
+            try:
+                v = struct.unpack('<IHHIIIIIIIII',t[8:52])
+                ( retval['dwFlags'],
+                  retval['wPriority'],
+                  retval['wLanguage'],
+                  retval['dwInitialFrames'],
+                  retval['dwScale'],
+                  retval['dwRate'],
+                  retval['dwStart'],
+                  retval['dwLength'],
+                  retval['dwSuggestedBufferSize'],
+                  retval['dwQuality'],
+                  retval['dwSampleSize'],
+                  retval['rcFrame'], ) = v
+                self.delay = float(retval['dwStart']) / \
+                             (float(retval['dwRate']) / retval['dwScale'])
+            except:
+                pass
+            
+        return retval
+
+    def parseSTRF(self,t,strh):
+        fccType = strh['fccType']
+        retval = {}
+        if fccType == 'auds':
+            ( retval['wFormatTag'],
+              retval['nChannels'],
+              retval['nSamplesPerSec'],
+              retval['nAvgBytesPerSec'],
+              retval['nBlockAlign'],
+              retval['nBitsPerSample'],
+            ) = struct.unpack('<HHHHHH',t[0:12])
+            ai = mediainfo.AudioInfo()
+            ai.samplerate = retval['nSamplesPerSec']
+            ai.channels = retval['nChannels']
+            ai.samplebits = retval['nBitsPerSample']
+            ai.bitrate = retval['nAvgBytesPerSec'] * 8
+            # TODO: set code if possible
+            # http://www.stats.uwa.edu.au/Internal/Specs/DXALL/FileSpec/Languages
+            # ai.language = strh['wLanguage']
+            try:
+                ai.codec = fourcc.RIFFWAVE[retval['wFormatTag']]
+            except:
+                ai.codec = "Unknown"            
+            self.audio.append(ai)  
+        elif fccType == 'vids':
+            v = struct.unpack('<IIIHH',t[0:16])
+            ( retval['biSize'],
+              retval['biWidth'],
+              retval['biHeight'],
+              retval['biPlanes'],
+              retval['biBitCount'], ) = v
+            retval['fourcc'] = t[16:20]            
+            v = struct.unpack('IIIII',t[20:40])
+            ( retval['biSizeImage'],
+              retval['biXPelsPerMeter'],
+              retval['biYPelsPerMeter'],
+              retval['biClrUsed'],
+              retval['biClrImportant'], ) = v
+            vi = mediainfo.VideoInfo()
+            try:
+                vi.codec = fourcc.RIFFCODEC[t[16:20]]
+            except:
+                vi.codec = "Unknown"
+            vi.width = retval['biWidth']
+            vi.height = retval['biHeight']            
+            vi.bitrate = strh['dwRate']
+            vi.fps = round(float(strh['dwRate'] * 100) / strh['dwScale']) / 100
+            vi.length = strh['dwLength'] / vi.fps 
+            self.video.append(vi)  
+        return retval
+        
+
+    def parseSTRL(self,t):
+        retval = {}
+        size = len(t)
+        i = 0
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i+=8
+        value = t[i:]
+
+        if key == 'strh':
+            retval[key] = self.parseSTRH(value)
+            i += sz
+        else:
+            _print("parseSTRL: Error")
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i+=8
+        value = t[i:]
+
+        if key == 'strf':
+            retval[key] = self.parseSTRF(value, retval['strh'])
+            i += sz
+        return ( retval, i )
+
+            
+    def parseODML(self,t):
+        retval = {}
+        size = len(t)
+        i = 0
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i += 8
+        value = t[i:]
+        if key == 'dmlh':
+            pass
+        else:
+            _print("parseODML: Error")
+
+        i += sz - 8
+        return ( retval, i )
+
+            
+    def parseVPRP(self,t):
+        retval = {}
+        v = struct.unpack('<IIIIIIIIII',t[:4*10])
+        
+        ( retval['VideoFormat'],
+          retval['VideoStandard'],
+          retval['RefreshRate'],
+          retval['HTotalIn'],
+          retval['VTotalIn'],
+          retval['FrameAspectRatio'],
+          retval['wPixel'],
+          retval['hPixel'] ) = v[1:-1]
+
+        # I need an avi with more informations
+        # enum {FORMAT_UNKNOWN, FORMAT_PAL_SQUARE, FORMAT_PAL_CCIR_601,
+        #    FORMAT_NTSC_SQUARE, FORMAT_NTSC_CCIR_601,...} VIDEO_FORMAT; 
+        # enum {STANDARD_UNKNOWN, STANDARD_PAL, STANDARD_NTSC, STANDARD_SECAM}
+        #    VIDEO_STANDARD; 
+        #
+        r = retval['FrameAspectRatio']
+        r = float(r >> 16) / (r & 0xFFFF)
+        retval['FrameAspectRatio'] = r
+        if self.video:
+            map(lambda v: setattr(v, 'aspect', r), self.video)
+        return ( retval, v[0] )
+
+            
+    def parseLIST(self,t):
+        retval = {}
+        i = 0
+        size = len(t)
+
+        while i < size-8:
+            # skip zero
+            if ord(t[i]) == 0: i += 1
+            key = t[i:i+4]
+            sz = 0
+
+            if key == 'LIST':
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                _print("-> SUBLIST: len: %d, %d" % ( sz, i+4 ))
+                i+=8
+                key = "LIST:"+t[i:i+4]
+                value = self.parseLIST(t[i:i+sz])
+                _print("<-")
+                if key == 'strl':
+                    for k in value.keys():
+                        retval[k] = value[k]
+                else:
+                    retval[key] = value
+                i+=sz
+            elif key == 'avih':
+                _print("SUBAVIH")
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                i += 8
+                value = self.parseAVIH(t[i:i+sz])
+                i += sz
+                retval[key] = value
+            elif key == 'strl':
+                i += 4
+                (value, sz) = self.parseSTRL(t[i:])
+                _print("SUBSTRL: len: %d" % sz)
+                key = value['strh']['fccType']
+                i += sz
+                retval[key] = value
+            elif key == 'odml':
+                i += 4
+                (value, sz) = self.parseODML(t[i:])
+                _print("ODML: len: %d" % sz)
+                i += sz
+            elif key == 'vprp':
+                i += 4
+                (value, sz) = self.parseVPRP(t[i:])
+                _print("VPRP: len: %d" % sz)
+                retval[key] = value
+                i += sz
+            elif key == 'JUNK':
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                i += sz + 8
+                _print("Skipping %d bytes of Junk" % sz)
+            else:
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                _print("Unknown Key: %s, len: %d" % (key,sz))
+                i+=8
+                value = self._extractHeaderString(t,i,sz)
+                value = value.replace('\0', '').lstrip().rstrip()
+                if value:
+                    retval[key] = value
+                i+=sz
+        return retval
+        
+
+    def parseRIFFChunk(self,file):
+        h = file.read(8)
+        if len(h) < 4:
+            return False
+        name = h[:4]
+        size = struct.unpack('<I',h[4:8])[0]        
+
+        if name == 'LIST' and size < 80000:
+            pos = file.tell() - 8
+            t = file.read(size)
+            key = t[:4]
+            _print('parse RIFF LIST: %d bytes' % (size))
+            value = self.parseLIST(t[4:])
+            self.header[key] = value
+            if key == 'INFO':
+                self.infoStart = pos
+                self.appendtable( 'AVIINFO', value )
+            elif key == 'MID ':
+                self.appendtable( 'AVIMID', value )
+            elif key in ('hdrl', ):
+                # no need to add this info to a table
+                pass
+            else:
+                _print('Skipping table info %s' % key)
+
+        elif name == 'JUNK':
+            self.junkStart = file.tell() - 8
+            self.junkSize  = size
+            file.seek(size, 1)
+        elif name == 'idx1':
+            self.has_idx = True
+            _print('idx1: %s bytes' % size)
+            # no need to parse this
+            t = file.seek(size,1)
+        elif name == 'LIST':
+            _print('RIFF LIST to long to parse: %s bytes' % size)
+            # no need to parse this
+            t = file.seek(size,1)
+        elif name == 'RIFF':
+            _print("New RIFF chunk, extended avi [%i]" % size)
+            type = file.read(4)
+            if type != 'AVIX':
+                _print("Second RIFF chunk is %s, not AVIX, skipping", type)
+                file.seek(size-4, 1)
+            # that's it, no new informations should be in AVIX
+            return False
+        elif not name.strip(string.printable + string.whitespace):
+            # check if name is something usefull at all, maybe it is no
+            # avi or broken
+            t = file.seek(size,1)
+            _print("Skipping %s [%i]" % (name,size))
+        else:
+            # bad avi
+            _print("Bad or broken avi")
+            return False
+        return True
+
+    def buildTag(self,key,value):
+        text = value + '\0'
+        l = len(text)
+        return struct.pack('<4sI%ds'%l, key[:4], l, text[:l])
+
+
+    def setInfo(self,file,hash):
+        if self.junkStart == None:
+            raise "junkstart missing"
+        tags = []
+        size = 4 # Length of 'INFO'
+        # Build String List and compute req. size
+        for key in hash.keys():
+            tag = self.buildTag( key, hash[key] )
+            if (len(tag))%2 == 1: tag += '\0'
+            tags.append(tag)
+            size += len(tag)
+            _print("Tag [%i]: %s" % (len(tag),tag))
+        if self.infoStart != None:
+            _print("Infostart found. %i" % (self.infoStart))
+            # Read current info size
+            file.seek(self.infoStart,0)
+            s = file.read(12)
+            (list, oldsize, info) = struct.unpack('<4sI4s',s)
+            self.junkSize += oldsize + 8
+        else:
+            self.infoStart = self.junkStart
+            _print("Infostart computed. %i" % (self.infoStart))
+        file.seek(self.infoStart,0)
+        if ( size > self.junkSize - 8 ):
+            raise "Too large"
+        file.write( "LIST" + struct.pack('<I',size) + "INFO" )
+        for tag in tags:
+            file.write( tag )
+        _print("Junksize %i" % (self.junkSize-size-8))
+        file.write( "JUNK" + struct.pack('<I',self.junkSize-size-8) )
+        
+
+
+mmpython.registertype( 'video/avi', ('avi',), mediainfo.TYPE_AV, RiffInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/COPYING
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/COPYING	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/COPYING	(revision 4)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: trunk/src/testing/bin/fileServer/misc/mmpython/PKG-INFO
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/PKG-INFO	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/PKG-INFO	(revision 4)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: mmpython
+Version: 0.4.9
+Summary: Module for retrieving information about media files
+Home-page: http://mmpython.sf.net
+Author: Thomas Schueppel, Dirk Meyer
+Author-email: freevo-devel@lists.sourceforge.net
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
Index: trunk/src/testing/bin/fileServer/misc/mmpython/MANIFEST.in
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/MANIFEST.in	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/MANIFEST.in	(revision 4)
@@ -0,0 +1,4 @@
+include audio/*.py  audio/eyeD3/*.py image/*.py video/*.py disc/*.py disc/*.c misc/*.py
+include doc/* 
+recursive-include i18n  *
+include *.py COPYING CREDITS MANIFEST.in mminfo
Index: trunk/src/testing/bin/fileServer/misc/mmpython/version.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/version.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/version.py	(revision 4)
@@ -0,0 +1,9 @@
+# the intention of this file is to make it possible to check
+# for the program using this lib if it's an up-to-date version
+
+# "offical" version of mmpython
+VERSION = '0.4.9'
+
+# latest major change (date as integer)
+CHANGED = 20040629
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/table.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/table.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/table.py	(revision 4)
@@ -0,0 +1,100 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: table.py,v 1.9 2004/05/28 12:26:24 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: table.py,v $
+# Revision 1.9  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.8  2003/07/02 11:17:29  the_krow
+# language is now part of the table key
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from gettext import GNUTranslations
+import os
+
+LOCALEDIR = 'i18n'
+
+class Table:
+    def __init__(self, hashmap, name, language='en'):
+        self.dict = hashmap
+        self.name = name
+        self.language = language
+        self.translations = {}
+        self.languages = []
+        self.i18ndir = os.path.join(LOCALEDIR, name.lower())
+        try:
+            self.read_translations()
+        except:
+            pass
+    
+    def read_translations(self):
+        for filename in [x for x in os.listdir(self.i18ndir) if x.endswith('.mo')]:
+            lang = filename[:-3]
+            filename = os.path.join(self.i18ndir, filename)
+            f = open(filename, 'rb')
+            self.translations[lang] = GNUTranslations(f)
+            f.close()
+        self.languages = self.translations.keys()
+        
+    def gettext(self, message, language = None):
+        try:
+            return self.translations[language].gettext(unicode(message))
+        except KeyError:
+            return unicode(message)
+        
+    def __setitem__(self,key,value):
+        self.dict[key] = value
+        
+    def __getitem__(self,key):
+        try:
+            return self.dict[key]
+        except KeyError:
+            return None
+         
+    def getstr(self,key):
+        s = self[key]
+        try:
+            if s and len(unicode(s)) < 100: 
+                return s
+            else:
+                return "Not Displayable"
+        except UnicodeDecodeError:
+            return "Not Displayable"
+         
+    def has_key(self, key):
+        return self.dict.has_key(key)    
+    
+    def getEntry(self, key, language = 'en'):
+        pair = (self.gettext(key), unicode(self.dict[key]))
+    
+    def __unicode__(self):
+        header = "\nTable %s (%s):" % (self.name, self.language)
+        result = reduce( lambda a,b: self[b] and "%s\n        %s: %s" % \
+                         (a, self.gettext(b,'en'), self.getstr(b)) or \
+                         a, self.dict.keys(), header )
+        return result
+
+    def accept(self,mi):
+        pass
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/en.po
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/en.po	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/en.po	(revision 4)
@@ -0,0 +1,62 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 11:30+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team:  <>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "613"
+msgstr "Country"
+
+msgid "615"
+msgstr "Transmission"
+
+msgid "552"
+msgstr "Special Instructions"
+
+msgid "617"
+msgstr "Headline"
+
+msgid "517"
+msgstr "Object Name"
+
+msgid "622"
+msgstr "Credits"
+
+msgid "527"
+msgstr "Categories"
+
+msgid "592"
+msgstr "Byline"
+
+msgid "627"
+msgstr "Source"
+
+msgid "628"
+msgstr "Copyright"
+
+msgid "597"
+msgstr "Byline Title"
+
+msgid "567"
+msgstr "Date"
+
+msgid "632"
+msgstr "Caption"
+
+msgid "634"
+msgstr "Caption Writer"
+
+msgid "602"
+msgstr "City"
+
+msgid "607"
+msgstr "State"
+
+msgid "537"
+msgstr "Keywords"
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/iptc.pot
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/iptc.pot	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/iptc/iptc.pot	(revision 4)
@@ -0,0 +1,68 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "613"
+msgstr ""
+
+msgid "615"
+msgstr ""
+
+msgid "552"
+msgstr ""
+
+msgid "617"
+msgstr ""
+
+msgid "517"
+msgstr ""
+
+msgid "622"
+msgstr ""
+
+msgid "527"
+msgstr ""
+
+msgid "592"
+msgstr ""
+
+msgid "627"
+msgstr ""
+
+msgid "628"
+msgstr ""
+
+msgid "597"
+msgstr ""
+
+msgid "567"
+msgstr ""
+
+msgid "632"
+msgstr ""
+
+msgid "634"
+msgstr ""
+
+msgid "602"
+msgstr ""
+
+msgid "607"
+msgstr ""
+
+msgid "537"
+msgstr ""
+
+msgid "522"
+msgstr ""
+
+msgid "512"
+msgstr ""
+
+msgid "256"
+msgstr ""
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/en.po
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/en.po	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/en.po	(revision 4)
@@ -0,0 +1,100 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 13:35+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+# Copyright statement.
+msgid "cpy"
+msgstr "Copyright"
+
+msgid "aut"
+msgstr "Author"
+
+msgid "nam"
+msgstr "Title"
+
+# Date the movie content was created.
+msgid "day"
+msgstr "Day"
+
+msgid "dir"
+msgstr "Name of movies director"
+
+msgid "ed1"
+msgstr "Edit dates and descriptions"
+
+msgid "ed2"
+msgstr "Edit dates and descriptions"
+
+msgid "ed3"
+msgstr "Edit dates and descriptions"
+
+msgid "ed4"
+msgstr "Edit dates and descriptions"
+
+msgid "ed5"
+msgstr "Edit dates and descriptions"
+
+msgid "ed6"
+msgstr "Edit dates and descriptions"
+
+msgid "ed7"
+msgstr "Edit dates and descriptions"
+
+msgid "ed8"
+msgstr "Edit dates and descriptions"
+
+msgid "ed9"
+msgstr "Edit dates and descriptions"
+
+msgid "fmt"
+msgstr "Indication of movie format (computer-generated, digitized, and so on)"
+
+msgid "inf"
+msgstr "Information about the movie"
+
+msgid "prd"
+msgstr "Name of movies producer"
+
+msgid "prf"
+msgstr "Names of performers"
+
+msgid "req"
+msgstr "Special hardware and software requirements"
+
+msgid "src"
+msgstr "Credits for those who provided movie source content"
+
+msgid "wrt"
+msgstr "Name of movies writer"
+
+msgid "name"
+msgstr "Name of object"
+
+msgid "WLOC"
+msgstr "Default window location for movie. Two 16-bit values, {x,y}"
+
+msgid "LOOP"
+msgstr "Looping. This atom is not present unless the movie is set to loop. Long integer indicating looping style. 0 for normal looping, 21 for palindromic looping"
+
+msgid "SelO"
+msgstr "Play selection only. Byte indicating that only the selected area of the movie should be played"
+
+msgid "AllF"
+msgstr "Play all frames. Byte indicating that all frames of video should be played, regardless of timing"
+
+msgid "ptv "
+msgstr "Print to video. Display movie in full screen mode. This atom contains a 16-byte structure, described in Print to Video (Full Screen Mode) (page 46)"
+
+msgid "hnti"
+msgstr "Hint info atom. Data used for real-time streaming of a movie or a track. For more information, see Movie Hint Info Atom (page 188) and Hint Track User Data Atom (page 188)"
+
+msgid "hinf"
+msgstr "Hint track information. Statistical data for real-time streaming of a particular track. For more information, see Hint Track User Data Atom (page 188)"
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/qtudta.pot
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/qtudta.pot	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/qtudta/qtudta.pot	(revision 4)
@@ -0,0 +1,95 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "cpy"
+msgstr "Copyright statement"
+
+msgid "aut"
+msgstr "Author"
+
+msgid "nam"
+msgstr "Title"
+
+msgid "day"
+msgstr "Date the movie content was created"
+
+msgid "dir" 
+msgstr "Name of movies director"
+
+msgid "ed1" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed2" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed3" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed4" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed5" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed6" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed7" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed8" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed9" 
+msgstr "Edit dates and descriptions"
+
+msgid "fmt" 
+msgstr "Indication of movie format (computer-generated, digitized, and so on)"
+
+msgid "inf" 
+msgstr "Information about the movie"
+
+msgid "prd" 
+msgstr "Name of movies producer"
+
+msgid "prf" 
+msgstr "Names of performers"
+
+msgid "req" 
+msgstr "Special hardware and software requirements"
+
+msgid "src" 
+msgstr "Credits for those who provided movie source content"
+
+msgid "wrt" 
+msgstr "Name of movies writer"
+
+msgid "name" 
+msgstr "Name of object"
+
+msgid "WLOC" 
+msgstr "Default window location for movie. Two 16-bit values, {x,y}"
+
+msgid "LOOP" 
+msgstr "Looping. This atom is not present unless the movie is set to loop. Long integer indicating looping style. 0 for normal looping, 21 for palindromic looping"
+
+msgid "SelO" 
+msgstr "Play selection only. Byte indicating that only the selected area of the movie should be played"
+
+msgid "AllF" 
+msgstr "Play all frames. Byte indicating that all frames of video should be played, regardless of timing"
+
+msgid "ptv " 
+msgstr "Print to video. Display movie in full screen mode. This atom contains a 16-byte structure, described in Print to Video (Full Screen Mode) (page 46)"
+
+msgid "hnti" 
+msgstr "Hint info atom. Data used for real-time streaming of a movie or a track. For more information, see Movie Hint Info Atom (page 188) and Hint Track User Data Atom (page 188)"
+
+msgid "hinf"
+msgstr "Hint track information. Statistical data for real-time streaming of a particular track. For more information, see Hint Track User Data Atom (page 188)"
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/id3v2.pot
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/id3v2.pot	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/id3v2.pot	(revision 4)
@@ -0,0 +1,257 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "AENC"
+msgstr "Audio encryption"
+
+msgid "APIC"
+msgstr "Attached picture"
+
+msgid "ASPI"
+msgstr "Audio seek point index"
+
+msgid "COMM"
+msgstr "Comments"
+
+msgid "COMR"
+msgstr "Commercial frame"
+
+msgid "ENCR"
+msgstr "Encryption method registration"
+
+msgid "EQU2"
+msgstr "Equalisation (2)"
+
+msgid "ETCO"
+msgstr "Event timing codes"
+
+msgid "GEOB"
+msgstr "General encapsulated object"
+
+msgid "GRID"
+msgstr "Group identification registration"
+
+msgid "LINK"
+msgstr "Linked information"
+
+msgid "MCDI"
+msgstr "Music CD identifier"
+
+msgid "MLLT"
+msgstr "MPEG location lookup table"
+
+msgid "OWNE"
+msgstr "Ownership frame"
+
+msgid "PRIV"
+msgstr "Private frame"
+
+msgid "PCNT"
+msgstr "Play counter"
+
+msgid "POPM"
+msgstr "Popularimeter"
+
+msgid "POSS"
+msgstr "Position synchronisation frame"
+
+msgid "RBUF"
+msgstr "Recommended buffer size"
+
+msgid "RVA2"
+msgstr "Relative volume adjustment (2)"
+
+msgid "RVRB"
+msgstr "Reverb"
+
+msgid "SEEK"
+msgstr "Seek frame"
+
+msgid "SIGN"
+msgstr "Signature frame"
+
+msgid "SYLT"
+msgstr "Synchronised lyric/text"
+
+msgid "SYTC"
+msgstr "Synchronised tempo codes"
+
+msgid "TALB"
+msgstr "Album/Movie/Show title"
+
+msgid "TBPM"
+msgstr "BPM (beats per minute)"
+
+msgid "TCOM"
+msgstr "Composer"
+
+msgid "TCON"
+msgstr "Content type"
+
+msgid "TCOP"
+msgstr "Copyright message"
+
+msgid "TDEN"
+msgstr "Encoding time"
+
+msgid "TDLY"
+msgstr "Playlist delay"
+
+msgid "TDOR"
+msgstr "Original release time"
+
+msgid "TDRC"
+msgstr "Recording time"
+
+msgid "TDRL"
+msgstr "Release time"
+
+msgid "TDTG"
+msgstr "Tagging time"
+
+msgid "TENC"
+msgstr "Encoded by"
+
+msgid "TEXT"
+msgstr "Lyricist/Text writer"
+
+msgid "TFLT"
+msgstr "File type"
+
+msgid "TIPL"
+msgstr "Involved people list"
+
+msgid "TIT1"
+msgstr "Content group description"
+
+msgid "TIT2"
+msgstr "Title/songname/content description"
+
+msgid "TIT3"
+msgstr "Subtitle/Description refinement"
+
+msgid "TKEY"
+msgstr "Initial key"
+
+msgid "TLAN"
+msgstr "Language(s)"
+
+msgid "TLEN"
+msgstr "Length"
+
+msgid "TMCL"
+msgstr "Musician credits list"
+
+msgid "TMED"
+msgstr "Media type"
+
+msgid "TMOO"
+msgstr "Mood"
+
+msgid "TOAL"
+msgstr "Original album/movie/show title"
+
+msgid "TOFN"
+msgstr "Original filename"
+
+msgid "TOLY"
+msgstr "Original lyricist(s)/text writer(s)"
+
+msgid "TOPE"
+msgstr "Original artist(s)/performer(s)"
+
+msgid "TOWN"
+msgstr "File owner/licensee"
+
+msgid "TPE1"
+msgstr "Lead performer(s)/Soloist(s)"
+
+msgid "TPE2"
+msgstr "Band/orchestra/accompaniment"
+
+msgid "TPE3"
+msgstr "Conductor/performer refinement"
+
+msgid "TPE4"
+msgstr "Interpreted, remixed, or otherwise modified by"
+
+msgid "TPOS"
+msgstr "Part of a set"
+
+msgid "TPRO"
+msgstr "Produced notice"
+
+msgid "TPUB"
+msgstr "Publisher"
+
+msgid "TRCK"
+msgstr "Track number/Position in set"
+
+msgid "TRSN"
+msgstr "Internet radio station name"
+
+msgid "TRSO"
+msgstr "Internet radio station owner"
+
+msgid "TSOA"
+msgstr "Album sort order"
+
+msgid "TSOP"
+msgstr "Performer sort order"
+
+msgid "TSOT"
+msgstr "Title sort order"
+
+msgid "TSRC"
+msgstr "ISRC (international standard recording code)"
+
+msgid "TSSE"
+msgstr "Software/Hardware and settings used for encoding"
+
+msgid "TSST"
+msgstr "Set subtitle"
+
+msgid "TXXX"
+msgstr "User defined text information frame"
+
+msgid "UFID"
+msgstr "Unique file identifier"
+
+msgid "USER"
+msgstr "Terms of use"
+
+msgid "USLT"
+msgstr "Unsynchronised lyric/text transcription"
+
+msgid "WCOM"
+msgstr "Commercial information"
+
+msgid "WCOP"
+msgstr "Copyright/Legal information"
+
+msgid "WOAF"
+msgstr "Official audio file webpage"
+
+msgid "WOAR"
+msgstr "Official artist/performer webpage"
+
+msgid "WOAS"
+msgstr "Official audio source webpage"
+
+msgid "WORS"
+msgstr "Official Internet radio station homepage"
+
+msgid "WPAY"
+msgstr "Payment"
+
+msgid "WPUB"
+msgstr "Publishers official webpage"
+
+msgid "WXXX"
+msgstr "User defined URL link frame"
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/en.po
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/en.po	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/id3v2/en.po	(revision 4)
@@ -0,0 +1,260 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython id3v2\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 15:13+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schueppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "AENC"
+msgstr "Audio encryption"
+
+msgid "APIC"
+msgstr "Attached picture"
+
+msgid "ASPI"
+msgstr "Audio seek point index"
+
+msgid "COMM"
+msgstr "Comments"
+
+msgid "COMR"
+msgstr "Commercial frame"
+
+msgid "ENCR"
+msgstr "Encryption method registration"
+
+msgid "EQU2"
+msgstr "Equalisation (2)"
+
+msgid "ETCO"
+msgstr "Event timing codes"
+
+msgid "GEOB"
+msgstr "General encapsulated object"
+
+msgid "GRID"
+msgstr "Group identification registration"
+
+msgid "LINK"
+msgstr "Linked information"
+
+msgid "MCDI"
+msgstr "Music CD identifier"
+
+msgid "MLLT"
+msgstr "MPEG location lookup table"
+
+msgid "OWNE"
+msgstr "Ownership frame"
+
+msgid "PRIV"
+msgstr "Private frame"
+
+msgid "PCNT"
+msgstr "Play counter"
+
+msgid "POPM"
+msgstr "Popularimeter"
+
+msgid "POSS"
+msgstr "Position synchronisation frame"
+
+msgid "RBUF"
+msgstr "Recommended buffer size"
+
+msgid "RVA2"
+msgstr "Relative volume adjustment (2)"
+
+msgid "RVRB"
+msgstr "Reverb"
+
+msgid "SEEK"
+msgstr "Seek frame"
+
+msgid "SIGN"
+msgstr "Signature frame"
+
+msgid "SYLT"
+msgstr "Synchronised lyric/text"
+
+msgid "SYTC"
+msgstr "Synchronised tempo codes"
+
+msgid "TALB"
+msgstr "Album/Movie/Show title"
+
+msgid "TBPM"
+msgstr "BPM (beats per minute)"
+
+msgid "TCOM"
+msgstr "Composer"
+
+msgid "TCON"
+msgstr "Content type"
+
+msgid "TCOP"
+msgstr "Copyright message"
+
+msgid "TDEN"
+msgstr "Encoding time"
+
+msgid "TDLY"
+msgstr "Playlist delay"
+
+msgid "TDOR"
+msgstr "Original release time"
+
+msgid "TDRC"
+msgstr "Recording time"
+
+msgid "TDRL"
+msgstr "Release time"
+
+msgid "TDTG"
+msgstr "Tagging time"
+
+msgid "TENC"
+msgstr "Encoded by"
+
+msgid "TEXT"
+msgstr "Lyricist/Text writer"
+
+msgid "TFLT"
+msgstr "File type"
+
+msgid "TIPL"
+msgstr "Involved people list"
+
+msgid "TIT1"
+msgstr "Content group description"
+
+msgid "TIT2"
+msgstr "Title/songname/content description"
+
+msgid "TIT3"
+msgstr "Subtitle/Description refinement"
+
+msgid "TKEY"
+msgstr "Initial key"
+
+msgid "TLAN"
+msgstr "Language(s)"
+
+msgid "TLEN"
+msgstr "Length"
+
+msgid "TMCL"
+msgstr "Musician credits list"
+
+msgid "TMED"
+msgstr "Media type"
+
+msgid "TMOO"
+msgstr "Mood"
+
+msgid "TOAL"
+msgstr "Original album/movie/show title"
+
+msgid "TOFN"
+msgstr "Original filename"
+
+msgid "TOLY"
+msgstr "Original lyricist(s)/text writer(s)"
+
+msgid "TOPE"
+msgstr "Original artist(s)/performer(s)"
+
+msgid "TOWN"
+msgstr "File owner/licensee"
+
+msgid "TPE1"
+msgstr "Lead performer(s)/Soloist(s)"
+
+msgid "TPE2"
+msgstr "Band/orchestra/accompaniment"
+
+msgid "TPE3"
+msgstr "Conductor/performer refinement"
+
+msgid "TPE4"
+msgstr "Interpreted, remixed, or otherwise modified by"
+
+msgid "TPOS"
+msgstr "Part of a set"
+
+msgid "TPRO"
+msgstr "Produced notice"
+
+msgid "TPUB"
+msgstr "Publisher"
+
+msgid "TRCK"
+msgstr "Track number/Position in set"
+
+msgid "TRSN"
+msgstr "Internet radio station name"
+
+msgid "TRSO"
+msgstr "Internet radio station owner"
+
+msgid "TSOA"
+msgstr "Album sort order"
+
+msgid "TSOP"
+msgstr "Performer sort order"
+
+msgid "TSOT"
+msgstr "Title sort order"
+
+msgid "TSRC"
+msgstr "ISRC (international standard recording code)"
+
+msgid "TSSE"
+msgstr "Software/Hardware and settings used for encoding"
+
+msgid "TSST"
+msgstr "Set subtitle"
+
+msgid "TXXX"
+msgstr "User defined text information frame"
+
+msgid "UFID"
+msgstr "Unique file identifier"
+
+msgid "USER"
+msgstr "Terms of use"
+
+msgid "USLT"
+msgstr "Unsynchronised lyric/text transcription"
+
+msgid "WCOM"
+msgstr "Commercial information"
+
+msgid "WCOP"
+msgstr "Copyright/Legal information"
+
+msgid "WOAF"
+msgstr "Official audio file webpage"
+
+msgid "WOAR"
+msgstr "Official artist/performer webpage"
+
+msgid "WOAS"
+msgstr "Official audio source webpage"
+
+msgid "WORS"
+msgstr "Official Internet radio station homepage"
+
+msgid "WPAY"
+msgstr "Payment"
+
+msgid "WPUB"
+msgstr "Publishers official webpage"
+
+msgid "WXXX"
+msgstr "User defined URL link frame"
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/en.po
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/en.po	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/en.po	(revision 4)
@@ -0,0 +1,152 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython aviinfo\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 11:30+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schueppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "INAM"
+msgstr "Title"
+
+msgid "IART"
+msgstr "Director"
+
+msgid "ICOP"
+msgstr "Copyright"
+
+msgid "IPRD"
+msgstr "Product"
+
+msgid "ICRD"
+msgstr "Creation Date"
+
+msgid "IGNR"
+msgstr "Genre"
+
+msgid "ISGN"
+msgstr "Secondary Genre"
+
+msgid "ISBJ"
+msgstr "Subject"
+
+msgid "IKEY"
+msgstr "Keywords"
+
+msgid "ICMT"
+msgstr "Comments"
+
+msgid "IWRI"
+msgstr "Written by"
+
+msgid "IPRO"
+msgstr "Produced by"
+
+msgid "ICNM"
+msgstr "Cinematographer"
+
+msgid "IPDS"
+msgstr "Production Designer"
+
+msgid "IEDT"
+msgstr "Edited by"
+
+msgid "ICDS"
+msgstr "Costume Designer"
+
+msgid "IMUS"
+msgstr "Music by"
+
+msgid "ISTD"
+msgstr "Production Studio"
+
+msgid "IDST"
+msgstr "Distributed by"
+
+msgid "ICNT"
+msgstr "Country"
+
+msgid "ILNG"
+msgstr "Language"
+
+msgid "LANG"
+msgstr "Language"
+
+msgid "IRTD"
+msgstr "Rating"
+
+msgid "IPRT"
+msgstr "Part"
+
+msgid "PRT1"
+msgstr "Part"
+
+msgid "IFRM"
+msgstr "Total Number of Parts"
+
+msgid "PRT2"
+msgstr "Total Number of Parts"
+
+msgid "ISTR"
+msgstr "Starring"
+
+msgid "STAR"
+msgstr "Starring"
+
+msgid "ISFT"
+msgstr "Software"
+
+msgid "ISFT"
+msgstr "Software"
+
+msgid "ITCH"
+msgstr "Encoded by"
+
+msgid "ITCH"
+msgstr "Technician"
+
+msgid "CODE"
+msgstr "Encoded by"
+
+msgid "IENC"
+msgstr "Encoded by"
+
+msgid "IRIP"
+msgstr "Ripped by"
+
+msgid "IDIT"
+msgstr "Digitizing Date"
+
+msgid "IWEB"
+msgstr "Internet Address"
+
+msgid "IBSU"
+msgstr "Base URL"
+
+msgid "ISRF"
+msgstr "Source Form"
+
+msgid "IMED"
+msgstr "Medium"
+
+msgid "ISRC"
+msgstr "Source"
+
+msgid "IARL"
+msgstr "Archival Location"
+
+msgid "ICMS"
+msgstr "Commissioned by"
+
+msgid "IENG"
+msgstr "Engineer"
+
+msgid "ICRP"
+msgstr "Cropped"
+
+msgid "ISHP"
+msgstr "Sha"
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot	(revision 4)
@@ -0,0 +1,212 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+msgid "INAM"
+msgstr ""
+
+msgid "IART"
+msgstr ""
+
+msgid "ICOP"
+msgstr ""
+
+msgid "IPRD"
+msgstr ""
+
+msgid "ICRD"
+msgstr ""
+
+msgid "IGNR"
+msgstr ""
+
+msgid "ISGN"
+msgstr ""
+
+msgid "ISBJ"
+msgstr ""
+
+msgid "IKEY"
+msgstr ""
+
+msgid "ICMT"
+msgstr ""
+
+msgid "IWRI"
+msgstr ""
+
+msgid "IPRO"
+msgstr ""
+
+msgid "ICNM"
+msgstr ""
+
+msgid "IPDS"
+msgstr ""
+
+msgid "IEDT"
+msgstr ""
+
+msgid "ICDS"
+msgstr ""
+
+msgid "IMUS"
+msgstr ""
+
+msgid "ISTD"
+msgstr ""
+
+msgid "IDST"
+msgstr ""
+
+msgid "ICNT"
+msgstr ""
+
+msgid "ILNG"
+msgstr ""
+
+msgid "LANG"
+msgstr ""
+
+msgid "IRTD"
+msgstr ""
+
+msgid "IPRT"
+msgstr ""
+
+msgid "PRT1"
+msgstr ""
+
+msgid "IFRM"
+msgstr ""
+
+msgid "PRT2"
+msgstr ""
+
+msgid "ISTR"
+msgstr ""
+
+msgid "STAR"
+msgstr ""
+
+msgid "ISFT"
+msgstr ""
+
+msgid "ISFT"
+msgstr ""
+
+msgid "ITCH"
+msgstr ""
+
+msgid "ITCH"
+msgstr ""
+
+msgid "CODE"
+msgstr ""
+
+msgid "IENC"
+msgstr ""
+
+msgid "IRIP"
+msgstr ""
+
+msgid "IDIT"
+msgstr ""
+
+msgid "IWEB"
+msgstr ""
+
+msgid "IBSU"
+msgstr ""
+
+msgid "ISRF"
+msgstr ""
+
+msgid "IMED"
+msgstr ""
+
+msgid "ISRC"
+msgstr ""
+
+msgid "IARL"
+msgstr ""
+
+msgid "ICMS"
+msgstr ""
+
+msgid "IENG"
+msgstr ""
+
+msgid "ICRP"
+msgstr ""
+
+msgid "ISHP"
+msgstr ""
+
+msgid "IDIM"
+msgstr ""
+
+msgid "ILGT"
+msgstr ""
+
+msgid "IDPI"
+msgstr ""
+
+msgid "IPLT"
+msgstr ""
+
+msgid "IAS1"
+msgstr ""
+
+msgid "IAS2"
+msgstr ""
+
+msgid "IAS3"
+msgstr ""
+
+msgid "IAS4"
+msgstr ""
+
+msgid "IAS5"
+msgstr ""
+
+msgid "IAS6"
+msgstr ""
+
+msgid "IAS7"
+msgstr ""
+
+msgid "IAS8"
+msgstr ""
+
+msgid "IAS9"
+msgstr ""
+
+msgid "ICAS"
+msgstr ""
+
+msgid "ILGU"
+msgstr ""
+
+msgid "ILIU"
+msgstr ""
+
+msgid "IWMU"
+msgstr ""
+
+msgid "IMIU"
+msgstr ""
+
+msgid "IMBI"
+msgstr ""
+
+msgid "IMBU"
+msgstr ""
+
+msgid "IMIT"
+msgstr ""
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/CDDB.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/CDDB.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/CDDB.py	(revision 4)
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+
+# Module for retrieving CDDB v1 data from CDDB servers via HTTP
+
+# Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+# This work is released under the GNU GPL, version 2 or later.
+
+# Release version 1.3
+# CVS ID: $Id: CDDB.py,v 1.4 2004/11/14 19:26:38 dischi Exp $
+
+import urllib, string, socket, os, struct, re
+
+name = 'CDDB.py'
+version = 1.3
+
+if os.environ.has_key('EMAIL'):
+    (default_user, hostname) = string.split(os.environ['EMAIL'], '@')
+else:
+    try:
+        default_user = os.geteuid() or os.environ['USER'] or 'user'
+    except:
+        default_user = 'user'
+    hostname = socket.gethostname() or 'host'
+
+proto = 4
+default_server = 'http://freedb.freedb.org/~cddb/cddb.cgi'
+
+def query(track_info, server_url=default_server,
+	  user=default_user, host=hostname, client_name=name,
+          client_version=version, trying=0):
+
+    disc_id = track_info[0]
+    num_tracks = track_info[1]
+
+    query_str = (('%08lx %d ') % (long(disc_id), num_tracks))
+
+    for i in track_info[2:]:
+	query_str = query_str + ('%d ' % i)
+	
+    query_str = urllib.quote_plus(string.rstrip(query_str))
+
+    url = "%s?cmd=cddb+query+%s&hello=%s+%s+%s+%s&proto=%i" % \
+	  (server_url, query_str, user, host, client_name,
+           client_version, proto)
+
+    response = urllib.urlopen(url)
+    
+    # Four elements in header: status, category, disc-id, title
+    header = string.split(string.rstrip(response.readline()), ' ', 3)
+
+    try:
+        header[0] = string.atoi(header[0])
+    except:
+        if trying > 10:
+            return [ 900, None ]
+        return query(track_info, default_server,
+                     default_user, hostname, name, version, trying+1)
+
+    if header[0] == 200:		# OK
+	result = { 'category': header[1], 'disc_id': header[2], 'title':
+		   header[3] }
+
+	return [ header[0], result ]
+
+    elif header[0] == 211 or header[0] == 210: # multiple matches
+	result = []
+
+	for line in response.readlines():
+	    line = string.rstrip(line)
+
+	    if line == '.':		# end of matches
+		break
+					# otherwise:
+					# split into 3 pieces, not 4
+					# (thanks to bgp for the fix!)
+	    match = string.split(line, ' ', 2)
+
+	    result.append({ 'category': match[0], 'disc_id': match[1], 'title':
+			    match[2] })
+
+	return [ header[0], result ]
+
+    else:
+	return [ header[0], None ]
+
+def read(category, disc_id, server_url=default_server, 
+	 user=default_user, host=hostname, client_name=name,
+         client_version=version, trying=0):
+
+    url = "%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=%i" % \
+	  (server_url, category, disc_id, user, host, client_name,
+           client_version, proto)
+
+    response = urllib.urlopen(url)
+    
+    header = string.split(string.rstrip(response.readline()), ' ', 3)
+
+    try:
+        header[0] = string.atoi(header[0])
+    except:
+        if trying > 10:
+            return [ 900, None ]
+        return read(category, disc_id, default_server, 
+                    user, host, client_name, client_version, trying+1)
+
+    if header[0] == 210 or header[0] == 417: # success or access denied
+	reply = []
+
+	for line in response.readlines():
+	    line = string.rstrip(line)
+
+	    if line == '.':
+		break;
+
+	    line = string.replace(line, r'\t', "\t")
+	    line = string.replace(line, r'\n', "\n")
+	    line = string.replace(line, r'\\', "\\")
+
+	    reply.append(line)
+
+	if header[0] == 210:		# success, parse the reply
+	    return [ header[0], parse_read_reply(reply) ]
+	else:				# access denied. :(
+	    return [ header[0], reply ]
+    else:
+	return [ header[0], None ]
+
+def parse_read_reply(comments):
+    
+    len_re = re.compile(r'#\s*Disc length:\s*(\d+)\s*seconds')
+    revis_re = re.compile(r'#\s*Revision:\s*(\d+)')
+    submit_re = re.compile(r'#\s*Submitted via:\s*(.+)')
+    keyword_re = re.compile(r'([^=]+)=(.*)')
+
+    result = {}
+
+    for line in comments:
+	keyword_match = keyword_re.match(line)
+	if keyword_match:
+	    (keyword, data) = keyword_match.groups()
+
+	    if result.has_key(keyword):
+		result[keyword] = result[keyword] + data
+	    else:
+		result[keyword] = data
+	    continue
+
+	len_match = len_re.match(line)
+	if len_match:
+	    result['disc_len'] = int(len_match.group(1))
+	    continue
+
+	revis_match = revis_re.match(line)
+	if revis_match:
+	    result['revision'] = int(revis_match.group(1))
+	    continue
+
+	submit_match = submit_re.match(line)
+	if submit_match:
+	    result['submitted_via'] = submit_match.group(1)
+	    continue
+
+    return result
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/lsdvd.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/lsdvd.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/lsdvd.py	(revision 4)
@@ -0,0 +1,234 @@
+# -----------------------------------------------------------------------
+# lsdvdinfo.py - parse dvd title structure
+# -----------------------------------------------------------------------
+# $Id: lsdvd.py,v 1.13.2.1 2005/06/30 17:28:24 dischi Exp $
+#
+# Use lsdvd to get dvd informations.
+#
+# -----------------------------------------------------------------------
+# $Log: lsdvd.py,v $
+# Revision 1.13.2.1  2005/06/30 17:28:24  dischi
+# fix to new lsdvd
+#
+# Revision 1.13  2005/01/13 20:19:34  dischi
+# detect video_ts in lower case
+#
+# Revision 1.12  2004/08/27 17:27:44  dischi
+# do not import ifoparser
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+
+
+import os
+import re
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+LSDVD_EXE='lsdvd'
+
+class DVDAudio(mediainfo.AudioInfo):
+    def __init__(self, data):
+        mediainfo.AudioInfo.__init__(self)
+        self.number   = int(data[1])
+        if data[3] != 'xx':
+            self.language = data[3]
+            try:
+                # some DVDs have a very bad language setting
+                self.language.encode()
+            except UnicodeError:
+                self.language = ''
+
+        try:
+            self.codec = data[7]
+            try:
+                self.samplerate = int(data[9])
+            except ValueError, e:
+                if data[9].lower().find('khz') > 0:
+                    pos = data[9].lower().find('khz')
+                    self.samplerate = int(data[9][:pos]) * 1000
+                else:
+                    raise e
+            self.channels = data[13]
+        except Exception, e:
+            # WTF, strange DVD, now try to find the bug (may not work)
+            self.codec = data[data.index('Format:') + 1]
+            try:
+                freq = data[data.index('Frequency:') + 1]
+                self.samplerate = int(freq)
+            except ValueError:
+                if freq.lower().find('khz') > 0:
+                    self.samplerate = int(freq[:freq.lower().find('khz')])*1000
+            self.channels = int(data[data.index('Channels:') + 1])
+
+
+class DVDVideo(mediainfo.VideoInfo):
+    def __init__(self, data):
+        mediainfo.VideoInfo.__init__(self)
+        self.width  = int(data[12])
+        self.height = int(data[14])
+        self.fps    = float(data[5])
+        self.aspect = data[10]
+
+
+class DVDTitle(mediainfo.AVInfo):
+    def __init__(self, data):
+        mediainfo.AVInfo.__init__(self)
+        self.number = int(data[1])
+
+        self.keys.append('subtitles')
+        self.keys.append('chapters')
+        
+        self.mime = 'video/mpeg'
+
+        l = re.split('[:.]', data[3])
+        self.length   = (int(l[0])*60+int(l[1]))*60+int(l[2])
+        self.trackno  = int(data[1])
+        self.chapters = int(data[5])
+        
+            
+class DVDInfo(DiscInfo):
+    def __init__(self, device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        if mediainfo.DEBUG > 1:
+            print 'trying lsdvd for scanning the disc'
+
+        if os.path.isdir(device):
+            self.valid = self.isDVDdir(device)
+        else:
+            self.valid = self.isDisc(device)
+
+        if self.valid and self.tracks:
+            self.keys.append('length')
+            self.length = 0
+            first       = 0
+
+            for t in self.tracks:
+                self.length += t.length
+                if not first:
+                    first = t.length
+            
+            if self.length/len(self.tracks) == first:
+                # badly mastered dvd
+                self.length = first
+
+            if mediainfo.DEBUG > 1:
+                print 'lsdvd detection ok'
+            
+        self.mime    = 'video/dvd'
+        self.type    = 'DVD'
+        self.subtype = 'video'
+
+
+    def lsdvd(self, path):
+        """
+        use lsdvd to get informations about this disc
+        """
+        import popen2
+        child = popen2.Popen3('%s -v -n -a -s "%s"' % \
+                              (LSDVD_EXE, path), 1, 100)
+        for line in child.fromchild.readlines():
+            data = line.replace(',', '').replace('\t', '').\
+                   replace('\n', '').lstrip(' ').split(' ')
+            if len(data) > 2:
+                if data[0] == 'Title:':
+                    ti = DVDTitle(data)
+                    self.appendtrack(ti)
+                elif data[0] == 'Audio:':
+                    self.tracks[-1].audio.append(DVDAudio(data))
+                elif data[0] == 'Subtitle:':
+                    self.tracks[-1].subtitles.append(data[3])
+                elif data[0] == 'VTS:':
+                    self.tracks[-1].video.append(DVDVideo(data))
+                    self.tracks[-1].video[-1].length = self.tracks[-1].length
+                elif data[:3] == ['Number', 'of', 'Angles:']:
+                    self.tracks[-1].angles = int(data[3])
+                    self.tracks[-1].keys.append('angles')
+                    
+        child.wait()
+        child.fromchild.close()
+        child.childerr.close()
+        child.tochild.close()
+
+        if len(self.tracks) > 0:
+            for ti in self.tracks:
+                ti.trackof = len(self.tracks)
+            return 1
+
+        return 0
+    
+            
+    def isDVDdir(self, dirname):
+        if os.path.isdir(dirname+'/VIDEO_TS') or \
+               os.path.isdir(dirname+'/video_ts') or \
+               os.path.isdir(dirname+'/Video_ts'):
+            return self.lsdvd(dirname)
+        return 0
+
+    
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        # brute force reading of the device to find out if it is a DVD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            f.close()
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+        f.close()
+
+        if buffer.find('VIDEO_TS') == -1 and \
+               buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        ret = self.lsdvd(device)
+        if not ret:
+            # we are very sure this is a DVD, maybe the drive was not
+            # ready, let's try again
+            return self.lsdvd(device)
+        return 1
+
+
+if os.environ.has_key('LSDVD') and os.environ['LSDVD']:
+    LSDVD_EXE = os.environ['LSDVD']
+else:
+    for path in os.environ['PATH'].split(':'):
+        if os.path.isfile(os.path.join(path, 'lsdvd')):
+            LSDVD_EXE = os.path.join(path, 'lsdvd')
+            break
+    else:
+        if mediainfo.DEBUG:
+            print 'ImportError: lsdvd not found'
+        raise ImportError
+
+mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DEVICE,
+                       mediainfo.TYPE_AV, DVDInfo )
+mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DIRECTORY,
+                       mediainfo.TYPE_AV, DVDInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/audioinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/audioinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/audioinfo.py	(revision 4)
@@ -0,0 +1,162 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# audioinfo.py - support for audio cds
+# -----------------------------------------------------------------------
+# $Id: audioinfo.py,v 1.22 2004/05/28 19:32:59 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import discinfo
+import DiscID
+import CDDB
+import cdrom
+
+_debug = mediainfo._debug
+
+class AudioDiscInfo(discinfo.DiscInfo):
+    def __init__(self,device):
+        discinfo.DiscInfo.__init__(self)
+        self.context = 'audio'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'audio/cd'
+        self.type = 'CD'
+        self.subtype = 'audio'
+
+    def isDisc(self, device):
+        if discinfo.DiscInfo.isDisc(self, device) != 1:
+            return 0
+        
+        disc_id = DiscID.disc_id(device)
+        if mmpython.USE_NETWORK:
+            try:
+                (query_stat, query_info) = CDDB.query(disc_id)
+            except:
+                # Oops no connection
+                query_stat = 404
+        else:
+            query_stat = 404
+
+
+        if query_stat == 210 or query_stat == 211:
+            # set this to success
+            query_stat = 200
+
+            for i in query_info:
+                if i['title'] != i['title'].upper():
+                    query_info = i
+                    break
+            else:
+                query_info = query_info[0]
+
+        elif query_stat != 200:
+            _debug("failure getting disc info, status %i" % query_stat)
+
+        if query_stat == 200:
+            qi = query_info['title'].split('/')
+            self.artist = qi[0].strip()
+            self.title = qi[1].strip()
+            for type in ('title', 'artist'):
+                if getattr(self, type) and getattr(self, type)[0] in ('"', '\'') \
+                       and getattr(self, type)[-1] in ('"', '\''):
+                    setattr(self, type, getattr(self, type)[1:-1])
+            (read_stat, read_info) = CDDB.read(query_info['category'], 
+                                               query_info['disc_id'])
+            # id = disc_id + number of tracks
+            #self.id = '%s_%s' % (query_info['disc_id'], disc_id[1])
+
+            if read_stat == 210:
+                for i in range(0, disc_id[1]):
+                    mi = mediainfo.MusicInfo()
+                    mi.title = read_info['TTITLE' + `i`]
+                    mi.album = self.title
+                    mi.artist = self.artist
+                    mi.genre = query_info['category']
+                    mi.codec = 'PCM'
+                    mi.samplerate = 44.1
+                    mi.trackno = i+1
+                    mi.trackof = disc_id[1]
+                    self.tracks.append(mi)
+                    for type in ('title', 'album', 'artist', 'genre'):
+                        if getattr(mi, type) and getattr(mi, type)[0] in ('"', '\'') \
+                           and getattr(mi, type)[-1] in ('"', '\''):
+                            setattr(mi, type, getattr(mi, type)[1:-1])
+            else:
+                _debug("failure getting track info, status: %i" % read_stat)
+                # set query_stat to somthing != 200
+                query_stat = 400
+            
+
+        if query_stat != 200:
+            _debug("failure getting disc info, status %i" % query_stat)
+            self.no_caching = 1
+            for i in range(0, disc_id[1]):
+                mi = mediainfo.MusicInfo()
+                mi.title = 'Track %s' % (i+1)
+                mi.codec = 'PCM'
+                mi.samplerate = 44.1
+                mi.trackno = i+1
+                mi.trackof = disc_id[1]
+                self.tracks.append(mi)
+                
+                
+        # read the tracks to generate the title list
+        device = open(device)
+        (first, last) = cdrom.toc_header(device)
+
+        lmin = 0
+        lsec = 0
+
+        num = 0
+        for i in range(first, last + 2):
+            if i == last + 1:
+                min, sec, frames = cdrom.leadout(device)
+            else:
+                min, sec, frames = cdrom.toc_entry(device, i)
+            if num:
+                self.tracks[num-1].length = (min-lmin)*60 + (sec-lsec)
+            num += 1
+            lmin, lsec = min, sec
+        device.close()
+
+        # correct bad titles for the tracks, containing also the artist
+        for t in self.tracks:
+            if not self.artist or not t.title.startswith(self.artist):
+                break
+        else:
+            for t in self.tracks:
+                t.title = t.title[len(self.artist):].lstrip('/ \t-_')
+
+        # correct bad titles for the tracks, containing also the title
+        for t in self.tracks:
+            if not self.title or not t.title.startswith(self.title):
+                break
+        else:
+            for t in self.tracks:
+                t.title = t.title[len(self.title):].lstrip('/ \t-_')
+        return 1
+    
+        
+mmpython.registertype( 'audio/cd', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_AUDIO,
+                       AudioDiscInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/ifomodule.c
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/ifomodule.c	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/ifomodule.c	(revision 4)
@@ -0,0 +1,259 @@
+//based on http://arnfast.net/projects/ifoinfo.php by Jens Arnfast 
+
+#include <Python.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <dvdread/dvd_reader.h>
+#include <dvdread/ifo_types.h>
+#include <dvdread/ifo_read.h>
+
+static PyObject *ifoinfo_open(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_close(PyObject *self, PyObject *args);
+
+static PyObject *ifoinfo_read_title(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_get_audio_tracks(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_get_subtitle_tracks(PyObject *self, PyObject *args);
+
+static PyMethodDef IfoMethods[] = {
+  {"open",  ifoinfo_open, METH_VARARGS},
+  {"close",  ifoinfo_close, METH_VARARGS},
+  {"title", ifoinfo_read_title, METH_VARARGS},
+  {"audio", ifoinfo_get_audio_tracks, METH_VARARGS},
+  {"subtitle", ifoinfo_get_subtitle_tracks, METH_VARARGS},
+  {NULL, NULL}
+};
+
+
+void initifoparser() {
+   (void) Py_InitModule("ifoparser", IfoMethods);
+}
+
+
+dvd_reader_t *dvd;
+ifo_handle_t *ifofile;
+
+static PyObject *ifoinfo_open(PyObject *self, PyObject *args) {
+  tt_srpt_t *tt_srpt;
+  int i, ch, gotopt = -1, dochapters = -1;
+  char *dvddevice;
+
+  if (!PyArg_ParseTuple(args, "s", &dvddevice))
+    return Py_BuildValue("i", 0);
+
+  dvd = DVDOpen(dvddevice);
+  
+  if (!dvd)
+    return Py_BuildValue("i", 0);
+  
+  ifofile = ifoOpen(dvd, 0);
+  if (!ifofile) {
+    DVDClose(dvd);
+    return Py_BuildValue("i", 0);
+  }
+
+  tt_srpt = ifofile->tt_srpt;
+  return Py_BuildValue("i", tt_srpt->nr_of_srpts);
+}
+
+
+static PyObject *ifoinfo_close(PyObject *self, PyObject *args) {
+  ifoClose(ifofile);
+  DVDClose(dvd);
+  return Py_BuildValue("i", 0);
+}
+
+
+static PyObject *ifoinfo_read_title(PyObject *self, PyObject *args) {
+  int i;
+
+  tt_srpt_t *tt_srpt;
+  ifo_handle_t *vtsfile;
+  int vtsnum, ttnnum, j;
+  long playtime;
+
+  if (!PyArg_ParseTuple(args, "i", &i))
+    return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
+
+  i--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum  = tt_srpt->title[i].title_set_nr;
+  ttnnum  = tt_srpt->title[i].vts_ttn;
+     
+  vtsfile = ifoOpen(dvd, vtsnum);
+    
+  if (!vtsfile)
+    return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
+
+  playtime = 0;
+  
+  if (vtsfile->vts_pgcit) {
+    dvd_time_t *ttime;
+    ttime = &vtsfile->vts_pgcit->pgci_srp[0].pgc->playback_time;
+    playtime = ((ttime->hour * 60) + ttime->minute) * 60 + ttime->second;
+  }
+
+  // Number of Chapters, Number of Angles, Playback time, Num Audio tracks,
+  // Num subtitles
+  return Py_BuildValue("(iiiii)", tt_srpt->title[i].nr_of_ptts,
+		       tt_srpt->title[i].nr_of_angles, playtime,		       
+		       vtsfile->vtsi_mat->nr_of_vts_audio_streams,
+		       vtsfile->vtsi_mat->nr_of_vts_subp_streams);
+}
+
+
+static PyObject * ifoinfo_get_subtitle_tracks(PyObject *self, PyObject *args) {
+  char language[5];
+  int trackno;
+  tt_srpt_t *tt_srpt;
+  int vtsnum, ttnnum;
+  ifo_handle_t *vtsfile;
+  int i;
+  subp_attr_t *attr;
+  
+  if (!PyArg_ParseTuple(args, "ii", &i, &trackno))
+    return Py_BuildValue("(s)", "N/A");
+
+  i--;
+  trackno--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum = tt_srpt->title[i].title_set_nr;
+  ttnnum = tt_srpt->title[i].vts_ttn;
+  
+  vtsfile = ifoOpen(dvd, vtsnum);
+  
+  if (vtsfile->vts_pgcit) {
+    attr = &vtsfile->vtsi_mat->vts_subp_attr[trackno];
+
+    if ( attr->type == 0
+	 && attr->lang_code == 0
+	 && attr->zero1 == 0
+	 && attr->zero2 == 0
+	 && attr->lang_extension == 0 ) {
+      return Py_BuildValue("(s)", "N/A");
+    }
+
+    /* language code */
+    if (isalpha((int)(attr->lang_code >> 8)) && isalpha((int)(attr->lang_code & 0xff))) {
+      snprintf(language, 5, "%c%c", attr->lang_code >> 8, attr->lang_code & 0xff);
+    } else {
+      snprintf(language, 5, "%02x%02x", 0xff & (unsigned)(attr->lang_code >> 8), 
+	       0xff & (unsigned)(attr->lang_code & 0xff));
+    }
+
+    return Py_BuildValue("(s)", language);
+  }
+}
+
+
+static PyObject * ifoinfo_get_audio_tracks(PyObject *self, PyObject *args) {
+  char audioformat[10];
+  char audiolang[5];
+  int audiochannels;
+  int audioid;
+  int audiofreq;
+  audio_attr_t *attr;
+  int i;
+  int trackno;
+  tt_srpt_t *tt_srpt;
+  int vtsnum, ttnnum;
+  ifo_handle_t *vtsfile;
+  
+  if (!PyArg_ParseTuple(args, "ii", &i, &trackno))
+    return Py_BuildValue("i", 0);
+
+  i--;
+  trackno--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum = tt_srpt->title[i].title_set_nr;
+  ttnnum = tt_srpt->title[i].vts_ttn;
+  
+  vtsfile = ifoOpen(dvd, vtsnum);
+  
+  if (vtsfile->vts_pgcit && vtsfile->vtsi_mat) {
+    attr = &vtsfile->vtsi_mat->vts_audio_attr[trackno];
+
+    audioid = trackno + 128;
+    
+    if ( attr->audio_format == 0
+	 && attr->multichannel_extension == 0
+	 && attr->lang_type == 0
+	 && attr->application_mode == 0
+	 && attr->quantization == 0
+	 && attr->sample_frequency == 0
+	 && attr->channels == 0
+	 && attr->lang_extension == 0
+	 && attr->unknown1 == 0
+	 && attr->unknown1 == 0) {
+      snprintf(audioformat, 10, "Unknown");
+      return Py_BuildValue("i", 0);
+    }
+    
+    /* audio format */
+    switch (attr->audio_format) {
+    case 0:
+      snprintf(audioformat, 10, "ac3");
+      break;
+    case 1:
+      snprintf(audioformat, 10, "N/A");
+      break;
+    case 2:
+      snprintf(audioformat, 10, "mpeg1");
+      break;
+    case 3:
+      snprintf(audioformat, 10, "mpeg2ext");
+    break;
+    case 4:
+      snprintf(audioformat, 10, "lpcm");
+      break;
+    case 5:
+      snprintf(audioformat, 10, "N/A");
+      break;
+    case 6:
+      snprintf(audioformat, 10, "dts");
+      break;
+    default:
+      snprintf(audioformat, 10, "N/A");
+    }
+    
+    switch (attr->lang_type) {
+    case 0:
+      assert(attr->lang_code == 0 || attr->lang_code == 0xffff);
+      snprintf(audiolang, 5, "N/A");
+      break;
+    case 1:
+      snprintf(audiolang, 5, "%c%c", attr->lang_code>>8, attr->lang_code & 0xff);
+      break;
+    default:
+      snprintf(audiolang, 5, "N/A");
+    }
+    
+    switch(attr->sample_frequency) {
+    case 0:
+      audiofreq = 48;
+      break;
+    case 1:
+      audiofreq = -1;
+      break;
+    default:
+      audiofreq = -1;
+    }
+    
+    audiochannels = attr->channels + 1;
+    
+    //AUDIOTRACK: ID=%i; LANG=%s; FORMAT=%s; CHANNELS=%i; FREQ=%ikHz
+    return Py_BuildValue("(issii)", audioid, audiolang, audioformat, audiochannels,
+			 audiofreq);
+  }
+
+  return NULL;
+}
+
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/discinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/discinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/discinfo.py	(revision 4)
@@ -0,0 +1,295 @@
+# -----------------------------------------------------------------------
+# discinfo.py - basic class for any discs containing collections of
+# media.
+# -----------------------------------------------------------------------
+# $Id: discinfo.py,v 1.23 2004/09/14 20:12:25 dischi Exp $
+#
+# $Log: discinfo.py,v $
+# Revision 1.23  2004/09/14 20:12:25  dischi
+# fix future warning
+#
+# Revision 1.22  2004/08/28 17:27:16  dischi
+# handle empty discs
+#
+# Revision 1.21  2004/06/25 13:20:35  dischi
+# FreeBSD patches
+#
+# Revision 1.20  2004/02/08 17:44:05  dischi
+# close fd
+#
+# Revision 1.19  2004/01/24 18:40:44  dischi
+# add md5 as possible way to generate the id
+#
+# Revision 1.18  2003/11/07 09:43:40  dischi
+# make interface compatible to old one
+#
+# Revision 1.17  2003/11/05 20:58:26  dischi
+# detect mixed audio cds
+#
+# Revision 1.16  2003/10/18 11:13:03  dischi
+# patch from Cyril Lacoux to detect blank discs
+#
+# Revision 1.15  2003/09/23 13:51:27  outlyer
+# More *BSD fixes from Lars; repairs a problem in his older patch.
+#
+# Revision 1.14  2003/09/14 13:32:12  dischi
+# set self.id for audio discs in discinfo.py to make it possible to use the cache for cddb
+#
+# Revision 1.13  2003/09/14 01:41:37  outlyer
+# FreeBSD support
+#
+# Revision 1.12  2003/09/10 18:50:31  dischi
+# error handling
+#
+# Revision 1.11  2003/08/26 21:21:18  outlyer
+# Fix two more Python 2.3 warnings.
+#
+# Revision 1.10  2003/08/26 18:01:26  outlyer
+# Patch from Lars Eggert for FreeBSD support
+#
+# Revision 1.9  2003/08/23 17:54:14  dischi
+# move id translation of bad chars directly after parsing
+#
+# Revision 1.8  2003/07/04 15:32:52  outlyer
+# Fix the label so we don't try to cache into a directory instead of a file.
+#
+# Revision 1.7  2003/07/02 22:04:26  dischi
+# just to be save
+#
+# Revision 1.6  2003/07/02 22:03:13  dischi
+# cache the disc id, it cannot change in 1 sec
+#
+# Revision 1.5  2003/06/23 19:26:16  dischi
+# Fixed bug in the cdrommodule that the file was not closed after usage.
+# The result was a drive you can't eject while the program (e.g. Freevo)
+# is running. Added cvs log for DiscID and cdrommodule to keep track of
+# all changes we did for mmpython.
+#
+# Revision 1.4  2003/06/23 09:22:54  the_krow
+# Typo and Indentation fixes.
+#
+# Revision 1.3  2003/06/10 22:11:36  dischi
+# some fixes
+#
+# Revision 1.2  2003/06/10 11:50:52  dischi
+# Moved all ioctl calls for discs to discinfo.cdrom_disc_status. This function
+# uses try catch around ioctl so it will return 0 (== no disc) for systems
+# without ioctl (e.g. Windows)
+#
+# Revision 1.1  2003/06/10 10:56:54  the_krow
+# - Build try-except blocks around disc imports to make it run on platforms
+#   not compiling / running the C extensions.
+# - moved DiscInfo class to disc module
+# - changed video.VcdInfo to be derived from CollectionInfo instead of
+#   DiskInfo so it can be used without the cdrom extensions which are
+#   hopefully not needed for bin-files.
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+from mmpython import mediainfo
+import os
+import re
+import time
+import array
+import md5
+from struct import *
+
+CREATE_MD5_ID = 0
+
+try:
+    from fcntl import ioctl
+    import DiscID
+except:
+    print 'WARNING: failed to import ioctl, discinfo won\'t work'
+
+
+def cdrom_disc_status(device, handle_mix = 0):
+    """
+    check the current disc in device
+    return: no disc (0), audio cd (1), data cd (2), blank cd (3)
+    """
+    CDROM_DRIVE_STATUS=0x5326
+    CDSL_CURRENT=( (int ) ( ~ 0 >> 1 ) )
+    CDROM_DISC_STATUS=0x5327
+    CDS_AUDIO=100
+    CDS_MIXED=105
+    CDS_DISC_OK=4
+    
+    # FreeBSD ioctls - there is no CDROM.py
+    # XXX 0xc0086305 below creates a warning, but 0xc0086305L
+    # doesn't work. Suppress that warning for Linux users,
+    # until a better solution can be found.
+    if os.uname()[0] == 'FreeBSD':
+        CDIOREADTOCENTRYS = 0xc0086305L
+        CD_MSF_FORMAT = 2
+        
+    try:
+        fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
+        if os.uname()[0] == 'FreeBSD':
+            try:
+                cd_toc_entry = array.array('c', '\000'*4096)
+                (address, length) = cd_toc_entry.buffer_info()
+                buf = pack('BBHP', CD_MSF_FORMAT, 0, length, address)
+                s = ioctl(fd, CDIOREADTOCENTRYS, buf)
+                s = CDS_DISC_OK
+            except:
+                s = CDS_NO_DISC
+        else:
+            s = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)
+    except:
+        print 'ERROR: no permission to read %s' % device
+        print 'Media detection not possible, set drive to \'empty\''
+        
+        # maybe we need to close the fd if ioctl fails, maybe
+        # open fails and there is no fd, maye we aren't running
+        # linux and don't have ioctl
+        try:
+            os.close(fd)
+        except:
+            pass
+        return 0
+
+    if not s == CDS_DISC_OK:
+        # no disc, error, whatever
+        return 0
+    
+    if os.uname()[0] == 'FreeBSD':
+        s = 0
+        # We already have the TOC from above
+        for i in range(0, 4096, 8):
+            control = unpack('B', cd_toc_entry[i+1])[0] & 4
+            track = unpack('B', cd_toc_entry[i+2])[0]
+            if track == 0:
+                break
+            if control == 0 and s != CDS_MIXED:
+                s = CDS_AUDIO
+            elif control != 0:
+                if s == CDS_AUDIO:
+                    s = CDS_MIXED
+                else:
+                    s = 100 + control # ugly, but encodes Linux ioctl returns
+            elif control == 5:
+                s = CDS_MIXED
+
+    else:
+        s = ioctl(fd, CDROM_DISC_STATUS)
+    os.close(fd)
+    if s == CDS_MIXED and handle_mix:
+        return 4
+    if s == CDS_AUDIO or s == CDS_MIXED:
+        return 1
+    
+    try:
+        fd = open(device, 'rb')
+        # try to read from the disc to get information if the disc
+        # is a rw medium not written yet
+        
+        fd.seek(32768) # 2048 multiple boundary for FreeBSD
+        # FreeBSD doesn't return IOError unless we try and read:
+        fd.read(1)
+    except IOError:
+        # not readable
+    	fd.close()
+	return 3
+    else:
+        # disc ok
+    	fd.close()
+    	return 2
+    
+
+id_cache = {}
+
+def cdrom_disc_id(device, handle_mix=0):
+    """
+    return the disc id of the device or None if no disc is there
+    """
+    global id_cache
+    try:
+        if id_cache[device][0] + 0.9 > time.time():
+            return id_cache[device][1:]
+    except:
+        pass
+
+    disc_type = cdrom_disc_status(device, handle_mix=handle_mix)
+    if disc_type == 0 or disc_type == 3:
+        return 0, None
+        
+    elif disc_type == 1 or disc_type == 4:
+        disc_id = DiscID.disc_id(device)
+        id = '%08lx_%d' % (disc_id[0], disc_id[1])
+    else:
+        f = open(device,'rb')
+
+        if os.uname()[0] == 'FreeBSD':
+            # FreeBSD can only seek to 2048 multiple boundaries.
+            # Below works on Linux and FreeBSD:
+            f.seek(32768)
+            id = f.read(829)
+            label = id[40:72]
+            id = id[813:829]
+        else:
+            f.seek(0x0000832d)
+            id = f.read(16)
+            f.seek(32808, 0)
+            label = f.read(32)
+
+        if CREATE_MD5_ID:
+            id_md5 = md5.new()
+            id_md5.update(f.read(51200))
+            id = id_md5.hexdigest()
+
+        f.close()
+            
+        m = re.match("^(.*[^ ]) *$", label)
+        if m:
+            id = '%s%s' % (id, m.group(1))
+        id = re.compile('[^a-zA-Z0-9()_-]').sub('_', id)
+            
+        
+    id_cache[device] = time.time(), disc_type, id
+    id = id.replace('/','_')
+    return disc_type, id
+
+
+class DiscInfo(mediainfo.CollectionInfo):
+    def isDisc(self, device):
+        (type, self.id) = cdrom_disc_id(device, handle_mix=1)
+        if type != 2:
+            if type == 4:
+                self.keys.append('mixed')
+                self.mixed = 1
+                type = 1 
+            return type
+        
+        if CREATE_MD5_ID:
+            if len(self.id) == 32:
+                self.label = ''
+            else:
+                self.label = self.id[32:]
+        else:
+            if len(self.id) == 16:
+                self.label = ''
+            else:
+                self.label = self.id[16:]
+
+        self.keys.append('label')
+        return type
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/DiscID.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/DiscID.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/DiscID.py	(revision 4)
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Module for fetching information about an audio compact disc and
+# returning it in a format friendly to CDDB.
+
+# If called from the command line, will print out disc info in a
+# format identical to Robert Woodcock's 'cd-discid' program.
+
+# Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+# This work is released under the GNU GPL, version 2 or later.
+
+# Release version 1.3
+
+
+# changes for mmpython:
+#
+# $Log: DiscID.py,v $
+# Revision 1.4  2004/11/14 19:26:38  dischi
+# fix future warning
+#
+# Revision 1.3  2003/06/23 19:26:16  dischi
+# Fixed bug in the cdrommodule that the file was not closed after usage.
+# The result was a drive you can't eject while the program (e.g. Freevo)
+# is running. Added cvs log for DiscID and cdrommodule to keep track of
+# all changes we did for mmpython.
+#
+#
+
+try:
+    import cdrom, sys
+except ImportError:
+    # Seems cdrom has either not been compiler or is not supported
+    # on this System
+    pass
+    
+
+def cddb_sum(n):
+    ret = 0
+    
+    while n > 0:
+	ret = ret + (n % 10)
+	n = n / 10
+
+    return ret
+
+def disc_id(device):
+    device = cdrom.open(device)
+    (first, last) = cdrom.toc_header(device)
+
+    track_frames = []
+    checksum = 0
+    
+    for i in range(first, last + 1):
+	(min, sec, frame) = cdrom.toc_entry(device, i)
+	checksum = checksum + cddb_sum(min*60 + sec)
+	track_frames.append(min*60*75 + sec*75 + frame)
+
+    (min, sec, frame) = cdrom.leadout(device)
+    track_frames.append(min*60*75 + sec*75 + frame)
+
+    total_time = (track_frames[-1] / 75) - (track_frames[0] / 75)
+	       
+    discid = ((long(checksum) % 0xff) << 24 | total_time << 8 | last)
+    cdrom.close(device)
+    return [discid, last] + track_frames[:-1] + [ track_frames[-1] / 75 ]
+
+if __name__ == '__main__':
+
+    dev_name = None
+    device = None
+    
+    if len(sys.argv) >= 2:
+	dev_name = sys.argv[1]
+
+    if dev_name:
+        device = open(dev_name)
+    else:
+        device = open()
+        
+    disc_info = disc_id(device)
+
+    print ('%08lx' % disc_info[0]),
+
+    for i in disc_info[1:]:
+	print ('%d' % i),
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/cdrommodule.c
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/cdrommodule.c	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/cdrommodule.c	(revision 4)
@@ -0,0 +1,275 @@
+/* 
+ * cdrommodule.c 
+ * Python extension module for reading in audio CD-ROM data
+ *
+ * Please port me to other OSes besides Linux, Solaris, OpenBSD,
+ * and FreeBSD! 
+ *
+ * See the README for info.
+ *
+ * Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+ * This work is released under the GNU GPL, version 2 or later.
+ *
+ * FreeBSD support by Michael Yoon <michael@yoon.org>
+ * OpenBSD support added by Alexander Guy <alex@andern.org>
+ *
+ * Thanks to Viktor Fougstedt <viktor@dtek.chalmers.se> for info
+ * on the <sys/cdio.h> include file to make this work on Solaris!
+ *
+ * Release version 1.2
+ *
+ *
+ *
+ * changes for mmpython:
+ *
+ * $Log: cdrommodule.c,v $
+ * Revision 1.2  2003/06/23 19:26:16  dischi
+ * Fixed bug in the cdrommodule that the file was not closed after usage.
+ * The result was a drive you can't eject while the program (e.g. Freevo)
+ * is running. Added cvs log for DiscID and cdrommodule to keep track of
+ * all changes we did for mmpython.
+ *
+ *
+ * CVS ID: $Id: cdrommodule.c,v 1.2 2003/06/23 19:26:16 dischi Exp $
+ */
+
+#include "Python.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#ifdef __linux__
+#include <linux/cdrom.h>
+#endif
+
+#if defined(sun) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#include <sys/cdio.h>
+#endif
+
+/* 
+ * Since FreeBSD has identical support but different names for lots
+ * of these structs and constants, we'll just #define CDDB_WHATEVER
+ * so that we don't have to repeat the code.
+ */
+
+#ifdef __FreeBSD__
+
+#define CDDB_TOC_HEADER_STRUCT ioc_toc_header 
+#define CDDB_STARTING_TRACK_FIELD starting_track 
+#define CDDB_ENDING_TRACK_FIELD ending_track
+#define CDDB_READ_TOC_HEADER_FLAG CDIOREADTOCHEADER 
+#define CDDB_TOC_ENTRY_STRUCT ioc_read_toc_single_entry 
+#define CDDB_TRACK_FIELD track 
+#define CDDB_FORMAT_FIELD address_format 
+#define CDDB_MSF_FORMAT CD_MSF_FORMAT 
+#define CDDB_ADDR_FIELD entry.addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDIOREADTOCENTRY 
+#define CDDB_CDROM_LEADOUT 0xaa 
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#define CDDB_DEFAULT_CDROM_FLAGS 0
+
+#elif defined(__OpenBSD__)
+
+#define CDDB_TOC_HEADER_STRUCT ioc_toc_header 
+#define CDDB_STARTING_TRACK_FIELD starting_track 
+#define CDDB_ENDING_TRACK_FIELD ending_track
+#define CDDB_READ_TOC_HEADER_FLAG CDIOREADTOCHEADER 
+#define CDDB_TOC_ENTRY_STRUCT ioc_read_toc_entry 
+#define CDDB_TRACK_FIELD starting_track 
+#define CDDB_FORMAT_FIELD address_format 
+#define CDDB_MSF_FORMAT CD_MSF_FORMAT  
+#define CDDB_ADDR_FIELD data->addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDIOREADTOCENTRIES
+#define CDDB_CDROM_LEADOUT 0xaa 
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#define CDDB_DEFAULT_CDROM_FLAGS 0
+
+#else /* Linux and Solaris */
+
+#define CDDB_TOC_HEADER_STRUCT cdrom_tochdr 
+#define CDDB_STARTING_TRACK_FIELD cdth_trk0 
+#define CDDB_ENDING_TRACK_FIELD cdth_trk1 
+#define CDDB_READ_TOC_HEADER_FLAG CDROMREADTOCHDR 
+#define CDDB_TOC_ENTRY_STRUCT cdrom_tocentry
+#define CDDB_TRACK_FIELD cdte_track 
+#define CDDB_FORMAT_FIELD cdte_format 
+#define CDDB_MSF_FORMAT CDROM_MSF 
+#define CDDB_ADDR_FIELD cdte_addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDROMREADTOCENTRY 
+#define CDDB_CDROM_LEADOUT CDROM_LEADOUT
+
+#ifdef sun
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/vol/alias/cdrom0"
+#else
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#endif /* sun */
+
+#define CDDB_DEFAULT_CDROM_FLAGS O_RDONLY | O_NONBLOCK
+
+#endif /* __FreeBSD__ */
+
+static PyObject *cdrom_error;
+
+static PyObject *cdrom_toc_header(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_HEADER_STRUCT hdr;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_HEADER_FLAG, &hdr) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+    
+    return Py_BuildValue("bb", hdr.CDDB_STARTING_TRACK_FIELD, 
+			 hdr.CDDB_ENDING_TRACK_FIELD);
+}
+
+static PyObject *cdrom_toc_entry(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_ENTRY_STRUCT entry;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+    unsigned char track;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!b", &PyFile_Type, &cdrom_fileobj, &track))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    entry.CDDB_TRACK_FIELD = track;
+    entry.CDDB_FORMAT_FIELD = CDDB_MSF_FORMAT;
+
+#if defined(__OpenBSD__)
+    entry.data = &data;
+    entry.data_len = sizeof(data);
+#endif
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_ENTRY_FLAG, &entry) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    return Py_BuildValue("bbb", entry.CDDB_ADDR_FIELD.msf.minute, 
+			 entry.CDDB_ADDR_FIELD.msf.second, 
+			 entry.CDDB_ADDR_FIELD.msf.frame);
+}
+
+static PyObject *cdrom_leadout(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_ENTRY_STRUCT entry;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    entry.CDDB_TRACK_FIELD = CDDB_CDROM_LEADOUT;
+    entry.CDDB_FORMAT_FIELD = CDDB_MSF_FORMAT;
+
+#if defined(__OpenBSD__)
+    entry.data = &data;
+    entry.data_len = sizeof(data);
+#endif
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_ENTRY_FLAG, &entry) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    return Py_BuildValue("bbb", entry.CDDB_ADDR_FIELD.msf.minute, 
+			 entry.CDDB_ADDR_FIELD.msf.second, 
+			 entry.CDDB_ADDR_FIELD.msf.frame);
+}
+
+int cdrom_close(FILE *cdrom_file) 
+{
+  return 0;
+}
+
+static PyObject *cdrom_really_close(PyObject *self, PyObject *args)
+{
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+    close(cdrom_fd);
+    return Py_BuildValue("b", 1);
+}
+
+static PyObject* cdrom_open(PyObject *self, PyObject *args)
+{
+    int cdrom_fd;
+    FILE *cdrom_file;
+    char *cdrom_device = CDDB_DEFAULT_CDROM_DEVICE;
+    int cdrom_open_flags = CDDB_DEFAULT_CDROM_FLAGS;
+
+    PyObject *cdrom_file_object;
+
+    if (!PyArg_ParseTuple(args, "|si", &cdrom_device, &cdrom_open_flags))
+	return NULL;
+
+    cdrom_fd = open(cdrom_device, cdrom_open_flags);
+
+    if (cdrom_fd == -1) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+    
+    cdrom_file = fdopen(cdrom_fd, "r");
+
+    if (cdrom_file == NULL) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    cdrom_file_object = PyFile_FromFile(cdrom_file, cdrom_device, "r", cdrom_close);
+
+    if (cdrom_file_object == NULL) {
+	PyErr_SetString(cdrom_error, "Internal conversion from file pointer to Python object failed");
+	fclose(cdrom_file);
+	return NULL;
+    }
+
+    return Py_BuildValue("O", cdrom_file_object);
+}
+
+static PyMethodDef cdrom_methods[] = {
+    { "toc_header", cdrom_toc_header, METH_VARARGS },
+    { "toc_entry", cdrom_toc_entry, METH_VARARGS },
+    { "leadout", cdrom_leadout, METH_VARARGS},
+    { "open", cdrom_open, METH_VARARGS},
+    { "close", cdrom_really_close, METH_VARARGS},
+    { NULL, NULL }
+};
+
+void initcdrom(void)
+{
+    PyObject *module, *dict;
+
+    module = Py_InitModule("cdrom", cdrom_methods);
+    dict = PyModule_GetDict(module);
+    cdrom_error = PyErr_NewException("cdrom.error", NULL, NULL);
+    PyDict_SetItemString(dict, "error", cdrom_error);
+}
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/datainfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/datainfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/datainfo.py	(revision 4)
@@ -0,0 +1,50 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# datainfo.py - info about a normal data disc
+# -----------------------------------------------------------------------
+# $Id: datainfo.py,v 1.3 2004/02/28 18:45:05 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+class DataDiscInfo(DiscInfo):
+    def __init__(self,device):
+        DiscInfo.__init__(self)
+        self.context = 'unknown'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'unknown/unknown'
+        self.type = 'CD'
+        self.subtype = 'data'
+
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        return 1
+
+
+
+mmpython.registertype( 'cd/unknown', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_NONE, DataDiscInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/vcdinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/vcdinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/vcdinfo.py	(revision 4)
@@ -0,0 +1,113 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# vcdinfo.py - parse vcd track informations
+# -----------------------------------------------------------------------
+# $Id: vcdinfo.py,v 1.8 2004/06/25 13:20:35 dischi Exp $
+#
+# $Log: vcdinfo.py,v $
+# Revision 1.8  2004/06/25 13:20:35  dischi
+# FreeBSD patches
+#
+# Revision 1.7  2003/06/30 13:17:19  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.6  2003/06/10 22:11:36  dischi
+# some fixes
+#
+# Revision 1.5  2003/06/09 12:47:53  dischi
+# more track info
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+import mmpython
+from mmpython import mediainfo
+from discinfo import DiscInfo
+import cdrom
+
+class VCDInfo(DiscInfo):
+    def __init__(self,device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'video/vcd'
+        self.type = 'CD'        
+        self.subtype = 'video'
+
+    def isDisc(self, device):
+        type = None
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+        
+        # brute force reading of the device to find out if it is a VCD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+        f.close()
+
+        if buffer.find('SVCD') > 0 and buffer.find('TRACKS.SVD') > 0 and \
+               buffer.find('ENTRIES.SVD') > 0:
+            type = 'SVCD'
+
+        elif buffer.find('INFO.VCD') > 0 and buffer.find('ENTRIES.VCD') > 0:
+            type = 'VCD'
+
+        else:
+            return 0
+
+        # read the tracks to generate the title list
+        device = open(device)
+        (first, last) = cdrom.toc_header(device)
+
+        lmin = 0
+        lsec = 0
+
+        num = 0
+        for i in range(first, last + 2):
+            if i == last + 1:
+                min, sec, frames = cdrom.leadout(device)
+            else:
+                min, sec, frames = cdrom.toc_entry(device, i)
+            if num:
+                vi = mediainfo.VideoInfo()
+                # XXX add more static information here, it's also possible
+                # XXX to scan for more informations like fps
+                # XXX Settings to MPEG1/2 is a wild guess, maybe the track
+                # XXX isn't playable at all (e.g. the menu)
+                if type == 'VCD':
+                    vi.codec = 'MPEG1'
+                else:
+                    vi.codec = 'MPEG2'
+                vi.length = (min-lmin) * 60 + (sec-lsec)
+                self.tracks.append(vi)
+            num += 1
+            lmin, lsec = min, sec
+        device.close()
+        return 1
+
+    
+mmpython.registertype( 'video/vcd', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_AV, VCDInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/disc/dvdinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/disc/dvdinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/disc/dvdinfo.py	(revision 4)
@@ -0,0 +1,193 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# dvdinfo.py - parse dvd title structure
+# -----------------------------------------------------------------------
+# $Id: dvdinfo.py,v 1.18 2005/01/13 20:20:20 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+import os
+import ifoparser
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+class DVDAudio(mediainfo.AudioInfo):
+    def __init__(self, title, number):
+        mediainfo.AudioInfo.__init__(self)
+        self.number = number
+        self.title  = title
+        self.id, self.language, self.codec, self.channels, self.samplerate = \
+                 ifoparser.audio(title, number)
+
+
+class DVDTitle(mediainfo.AVInfo):
+    def __init__(self, number):
+        mediainfo.AVInfo.__init__(self)
+        self.number = number
+        self.chapters, self.angles, self.length, audio_num, \
+                       subtitles_num = ifoparser.title(number)
+
+        self.keys.append('chapters')
+        self.keys.append('subtitles')
+        
+        self.mime = 'video/mpeg'
+        for a in range(1, audio_num+1):
+            self.audio.append(DVDAudio(number, a))
+            
+        for s in range(1, subtitles_num+1):
+            self.subtitles.append(ifoparser.subtitle(number, s)[0])
+
+            
+class DVDInfo(DiscInfo):
+    def __init__(self, device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+
+        if mediainfo.DEBUG > 1:
+            print 'trying buggy dvd detection'
+
+        if isinstance(device, file):
+            self.valid = self.isDVDiso(device)
+        elif os.path.isdir(device):
+            self.valid = self.isDVDdir(device)
+        else:
+            self.valid = self.isDisc(device)
+
+        if self.valid and self.tracks:
+            self.keys.append('length')
+            self.length = 0
+            first       = 0
+
+            for t in self.tracks:
+                self.length += t.length
+                if not first:
+                    first = t.length
+            
+            if self.length/len(self.tracks) == first:
+                # badly mastered dvd
+                self.length = first
+
+        self.mime    = 'video/dvd'
+        self.type    = 'DVD'
+        self.subtype = 'video'
+
+
+    def isDVDdir(self, dirname):
+        if not (os.path.isdir(dirname+'/VIDEO_TS') or \
+                os.path.isdir(dirname+'/video_ts') or \
+                os.path.isdir(dirname+'/Video_ts')):
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(dirname)
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+
+        ifoparser.close()
+        return 1
+
+    
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        # brute force reading of the device to find out if it is a DVD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            f.close()
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+        f.close()
+
+        if buffer.find('VIDEO_TS') == -1 and buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(device)
+
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+        
+        ifoparser.close()
+        return 1
+
+
+    def isDVDiso(self, f):
+        # brute force reading of the device to find out if it is a DVD
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+
+        if buffer.find('VIDEO_TS') == -1 and buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(f.name)
+
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+        
+        ifoparser.close()
+        return 1
+
+
+if not mmpython.gettype('video/dvd', mediainfo.EXTENSION_DEVICE):
+    mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DEVICE,
+                           mediainfo.TYPE_AV, DVDInfo )
+
+if not mmpython.gettype('video/dvd', mediainfo.EXTENSION_DIRECTORY):
+    mmpython.registertype('video/dvd', mediainfo.EXTENSION_DIRECTORY,
+                          mediainfo.TYPE_AV, DVDInfo)
+
+mmpython.registertype('video/dvd', ['iso'], mediainfo.TYPE_AV, DVDInfo)
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/EXIF.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/EXIF.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/EXIF.py	(revision 4)
@@ -0,0 +1,1194 @@
+# Library to extract EXIF information in digital camera image files
+#
+# To use this library call with:
+#    f=open(path_name, 'rb')
+#    tags=EXIF.process_file(f)
+# tags will now be a dictionary mapping names of EXIF tags to their
+# values in the file named by path_name.  You can process the tags
+# as you wish.  In particular, you can iterate through all the tags with:
+#     for tag in tags.keys():
+#         if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename',
+#                        'EXIF MakerNote'):
+#             print "Key: %s, value %s" % (tag, tags[tag])
+# (This code uses the if statement to avoid printing out a few of the
+# tags that tend to be long or boring.)
+#
+# The tags dictionary will include keys for all of the usual EXIF
+# tags, and will also include keys for Makernotes used by some
+# cameras, for which we have a good specification.
+#
+# Contains code from "exifdump.py" originally written by Thierry Bousch
+# <bousch@topo.math.u-psud.fr> and released into the public domain.
+#
+# Updated and turned into general-purpose library by Gene Cash
+# <email gcash at cfl.rr.com>
+#
+# This copyright license is intended to be similar to the FreeBSD license.
+#
+# Copyright 2002 Gene Cash All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the
+#       distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GENE CASH ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# This means you may do anything you want with this code, except claim you
+# wrote it. Also, if it breaks you get to keep both pieces.
+#
+# Patch Contributors:
+# * Simon J. Gerraty <sjg@crufty.net>
+#   s2n fix & orientation decode
+# * John T. Riedl <riedl@cs.umn.edu>
+#   Added support for newer Nikon type 3 Makernote format for D70 and some
+#   other Nikon cameras.
+# * Joerg Schaefer <schaeferj@gmx.net>
+#   Fixed subtle bug when faking an EXIF header, which affected maker notes
+#   using relative offsets, and a fix for Nikon D100.
+#
+# 21-AUG-99 TB  Last update by Thierry Bousch to his code.
+# 17-JAN-02 CEC Discovered code on web.
+#               Commented everything.
+#               Made small code improvements.
+#               Reformatted for readability.
+# 19-JAN-02 CEC Added ability to read TIFFs and JFIF-format JPEGs.
+#               Added ability to extract JPEG formatted thumbnail.
+#               Added ability to read GPS IFD (not tested).
+#               Converted IFD data structure to dictionaries indexed by
+#               tag name.
+#               Factored into library returning dictionary of IFDs plus
+#               thumbnail, if any.
+# 20-JAN-02 CEC Added MakerNote processing logic.
+#               Added Olympus MakerNote.
+#               Converted data structure to single-level dictionary, avoiding
+#               tag name collisions by prefixing with IFD name.  This makes
+#               it much easier to use.
+# 23-JAN-02 CEC Trimmed nulls from end of string values.
+# 25-JAN-02 CEC Discovered JPEG thumbnail in Olympus TIFF MakerNote.
+# 26-JAN-02 CEC Added ability to extract TIFF thumbnails.
+#               Added Nikon, Fujifilm, Casio MakerNotes.
+# 30-NOV-03 CEC Fixed problem with canon_decode_tag() not creating an
+#               IFD_Tag() object.
+# 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
+#
+
+# field type descriptions as (length, abbreviation, full name) tuples
+FIELD_TYPES=(
+    (0, 'X',  'Proprietary'), # no such type
+    (1, 'B',  'Byte'),
+    (1, 'A',  'ASCII'),
+    (2, 'S',  'Short'),
+    (4, 'L',  'Long'),
+    (8, 'R',  'Ratio'),
+    (1, 'SB', 'Signed Byte'),
+    (1, 'U',  'Undefined'),
+    (2, 'SS', 'Signed Short'),
+    (4, 'SL', 'Signed Long'),
+    (8, 'SR', 'Signed Ratio')
+    )
+
+# dictionary of main EXIF tag names
+# first element of tuple is tag name, optional second element is
+# another dictionary giving names to values
+EXIF_TAGS={
+    0x0100: ('ImageWidth', ),
+    0x0101: ('ImageLength', ),
+    0x0102: ('BitsPerSample', ),
+    0x0103: ('Compression',
+             {1: 'Uncompressed TIFF',
+              6: 'JPEG Compressed'}),
+    0x0106: ('PhotometricInterpretation', ),
+    0x010A: ('FillOrder', ),
+    0x010D: ('DocumentName', ),
+    0x010E: ('ImageDescription', ),
+    0x010F: ('Make', ),
+    0x0110: ('Model', ),
+    0x0111: ('StripOffsets', ),
+    0x0112: ('Orientation',
+             {1: 'Horizontal (normal)',
+              2: 'Mirrored horizontal',
+              3: 'Rotated 180',
+              4: 'Mirrored vertical',
+              5: 'Mirrored horizontal then rotated 90 CCW',
+              6: 'Rotated 90 CW',
+              7: 'Mirrored horizontal then rotated 90 CW',
+              8: 'Rotated 90 CCW'}),
+    0x0115: ('SamplesPerPixel', ),
+    0x0116: ('RowsPerStrip', ),
+    0x0117: ('StripByteCounts', ),
+    0x011A: ('XResolution', ),
+    0x011B: ('YResolution', ),
+    0x011C: ('PlanarConfiguration', ),
+    0x0128: ('ResolutionUnit',
+             {1: 'Not Absolute',
+              2: 'Pixels/Inch',
+              3: 'Pixels/Centimeter'}),
+    0x012D: ('TransferFunction', ),
+    0x0131: ('Software', ),
+    0x0132: ('DateTime', ),
+    0x013B: ('Artist', ),
+    0x013E: ('WhitePoint', ),
+    0x013F: ('PrimaryChromaticities', ),
+    0x0156: ('TransferRange', ),
+    0x0200: ('JPEGProc', ),
+    0x0201: ('JPEGInterchangeFormat', ),
+    0x0202: ('JPEGInterchangeFormatLength', ),
+    0x0211: ('YCbCrCoefficients', ),
+    0x0212: ('YCbCrSubSampling', ),
+    0x0213: ('YCbCrPositioning', ),
+    0x0214: ('ReferenceBlackWhite', ),
+    0x828D: ('CFARepeatPatternDim', ),
+    0x828E: ('CFAPattern', ),
+    0x828F: ('BatteryLevel', ),
+    0x8298: ('Copyright', ),
+    0x829A: ('ExposureTime', ),
+    0x829D: ('FNumber', ),
+    0x83BB: ('IPTC/NAA', ),
+    0x8769: ('ExifOffset', ),
+    0x8773: ('InterColorProfile', ),
+    0x8822: ('ExposureProgram',
+             {0: 'Unidentified',
+              1: 'Manual',
+              2: 'Program Normal',
+              3: 'Aperture Priority',
+              4: 'Shutter Priority',
+              5: 'Program Creative',
+              6: 'Program Action',
+              7: 'Portrait Mode',
+              8: 'Landscape Mode'}),
+    0x8824: ('SpectralSensitivity', ),
+    0x8825: ('GPSInfo', ),
+    0x8827: ('ISOSpeedRatings', ),
+    0x8828: ('OECF', ),
+    # print as string
+    0x9000: ('ExifVersion', lambda x: ''.join(map(chr, x))),
+    0x9003: ('DateTimeOriginal', ),
+    0x9004: ('DateTimeDigitized', ),
+    0x9101: ('ComponentsConfiguration',
+             {0: '',
+              1: 'Y',
+              2: 'Cb',
+              3: 'Cr',
+              4: 'Red',
+              5: 'Green',
+              6: 'Blue'}),
+    0x9102: ('CompressedBitsPerPixel', ),
+    0x9201: ('ShutterSpeedValue', ),
+    0x9202: ('ApertureValue', ),
+    0x9203: ('BrightnessValue', ),
+    0x9204: ('ExposureBiasValue', ),
+    0x9205: ('MaxApertureValue', ),
+    0x9206: ('SubjectDistance', ),
+    0x9207: ('MeteringMode',
+             {0: 'Unidentified',
+              1: 'Average',
+              2: 'CenterWeightedAverage',
+              3: 'Spot',
+              4: 'MultiSpot'}),
+    0x9208: ('LightSource',
+             {0:   'Unknown',
+              1:   'Daylight',
+              2:   'Fluorescent',
+              3:   'Tungsten',
+              10:  'Flash',
+              17:  'Standard Light A',
+              18:  'Standard Light B',
+              19:  'Standard Light C',
+              20:  'D55',
+              21:  'D65',
+              22:  'D75',
+              255: 'Other'}),
+    0x9209: ('Flash', {0:  'No',
+                       1:  'Fired',
+                       5:  'Fired (?)', # no return sensed
+                       7:  'Fired (!)', # return sensed
+                       9:  'Fill Fired',
+                       13: 'Fill Fired (?)',
+                       15: 'Fill Fired (!)',
+                       16: 'Off',
+                       24: 'Auto Off',
+                       25: 'Auto Fired',
+                       29: 'Auto Fired (?)',
+                       31: 'Auto Fired (!)',
+                       32: 'Not Available'}),
+    0x920A: ('FocalLength', ),
+    0x927C: ('MakerNote', ),
+    # print as string
+    0x9286: ('UserComment', lambda x: ''.join(map(chr, x))),
+    0x9290: ('SubSecTime', ),
+    0x9291: ('SubSecTimeOriginal', ),
+    0x9292: ('SubSecTimeDigitized', ),
+    # print as string
+    0xA000: ('FlashPixVersion', lambda x: ''.join(map(chr, x))),
+    0xA001: ('ColorSpace', ),
+    0xA002: ('ExifImageWidth', ),
+    0xA003: ('ExifImageLength', ),
+    0xA005: ('InteroperabilityOffset', ),
+    0xA20B: ('FlashEnergy', ),               # 0x920B in TIFF/EP
+    0xA20C: ('SpatialFrequencyResponse', ),  # 0x920C    -  -
+    0xA20E: ('FocalPlaneXResolution', ),     # 0x920E    -  -
+    0xA20F: ('FocalPlaneYResolution', ),     # 0x920F    -  -
+    0xA210: ('FocalPlaneResolutionUnit', ),  # 0x9210    -  -
+    0xA214: ('SubjectLocation', ),           # 0x9214    -  -
+    0xA215: ('ExposureIndex', ),             # 0x9215    -  -
+    0xA217: ('SensingMethod', ),             # 0x9217    -  -
+    0xA300: ('FileSource',
+             {3: 'Digital Camera'}),
+    0xA301: ('SceneType',
+             {1: 'Directly Photographed'}),
+    0xA302: ('CVAPattern',),
+    }
+
+# interoperability tags
+INTR_TAGS={
+    0x0001: ('InteroperabilityIndex', ),
+    0x0002: ('InteroperabilityVersion', ),
+    0x1000: ('RelatedImageFileFormat', ),
+    0x1001: ('RelatedImageWidth', ),
+    0x1002: ('RelatedImageLength', ),
+    }
+
+# GPS tags (not used yet, haven't seen camera with GPS)
+GPS_TAGS={
+    0x0000: ('GPSVersionID', ),
+    0x0001: ('GPSLatitudeRef', ),
+    0x0002: ('GPSLatitude', ),
+    0x0003: ('GPSLongitudeRef', ),
+    0x0004: ('GPSLongitude', ),
+    0x0005: ('GPSAltitudeRef', ),
+    0x0006: ('GPSAltitude', ),
+    0x0007: ('GPSTimeStamp', ),
+    0x0008: ('GPSSatellites', ),
+    0x0009: ('GPSStatus', ),
+    0x000A: ('GPSMeasureMode', ),
+    0x000B: ('GPSDOP', ),
+    0x000C: ('GPSSpeedRef', ),
+    0x000D: ('GPSSpeed', ),
+    0x000E: ('GPSTrackRef', ),
+    0x000F: ('GPSTrack', ),
+    0x0010: ('GPSImgDirectionRef', ),
+    0x0011: ('GPSImgDirection', ),
+    0x0012: ('GPSMapDatum', ),
+    0x0013: ('GPSDestLatitudeRef', ),
+    0x0014: ('GPSDestLatitude', ),
+    0x0015: ('GPSDestLongitudeRef', ),
+    0x0016: ('GPSDestLongitude', ),
+    0x0017: ('GPSDestBearingRef', ),
+    0x0018: ('GPSDestBearing', ),
+    0x0019: ('GPSDestDistanceRef', ),
+    0x001A: ('GPSDestDistance', )
+    }
+
+# Nikon E99x MakerNote Tags
+# http://members.tripod.com/~tawba/990exif.htm
+MAKERNOTE_NIKON_NEWER_TAGS={
+    0x0002: ('ISOSetting', ),
+    0x0003: ('ColorMode', ),
+    0x0004: ('Quality', ),
+    0x0005: ('Whitebalance', ),
+    0x0006: ('ImageSharpening', ),
+    0x0007: ('FocusMode', ),
+    0x0008: ('FlashSetting', ),
+    0x0009: ('AutoFlashMode', ),
+    0x000B: ('WhiteBalanceBias', ),
+    0x000C: ('WhiteBalanceRBCoeff', ),
+    0x000F: ('ISOSelection', ),
+    0x0012: ('FlashCompensation', ),
+    0x0013: ('ISOSpeedRequested', ),
+    0x0016: ('PhotoCornerCoordinates', ),
+    0x0018: ('FlashBracketCompensationApplied', ),
+    0x0019: ('AEBracketCompensationApplied', ),
+    0x0080: ('ImageAdjustment', ),
+    0x0081: ('ToneCompensation', ),
+    0x0082: ('AuxiliaryLens', ),
+    0x0083: ('LensType', ),
+    0x0084: ('LensMinMaxFocalMaxAperture', ),
+    0x0085: ('ManualFocusDistance', ),
+    0x0086: ('DigitalZoomFactor', ),
+    0x0088: ('AFFocusPosition',
+             {0x0000: 'Center',
+              0x0100: 'Top',
+              0x0200: 'Bottom',
+              0x0300: 'Left',
+              0x0400: 'Right'}),
+    0x0089: ('BracketingMode',
+             {0x00: 'Single frame, no bracketing',
+              0x01: 'Continuous, no bracketing',
+              0x02: 'Timer, no bracketing',
+              0x10: 'Single frame, exposure bracketing',
+              0x11: 'Continuous, exposure bracketing',
+              0x12: 'Timer, exposure bracketing',
+              0x40: 'Single frame, white balance bracketing',
+              0x41: 'Continuous, white balance bracketing',
+              0x42: 'Timer, white balance bracketing'}),
+    0x008D: ('ColorMode', ),
+    0x008F: ('SceneMode?', ),
+    0x0090: ('LightingType', ),
+    0x0092: ('HueAdjustment', ),
+    0x0094: ('Saturation',
+             {-3: 'B&W',
+              -2: '-2',
+              -1: '-1',
+              0:  '0',
+              1:  '1',
+              2:  '2'}),
+    0x0095: ('NoiseReduction', ),
+    0x00A7: ('TotalShutterReleases', ),
+    0x00A9: ('ImageOptimization', ),
+    0x00AA: ('Saturation', ),
+    0x00AB: ('DigitalVariProgram', ),
+    0x0010: ('DataDump', )
+    }
+
+MAKERNOTE_NIKON_OLDER_TAGS={
+    0x0003: ('Quality',
+             {1: 'VGA Basic',
+              2: 'VGA Normal',
+              3: 'VGA Fine',
+              4: 'SXGA Basic',
+              5: 'SXGA Normal',
+              6: 'SXGA Fine'}),
+    0x0004: ('ColorMode',
+             {1: 'Color',
+              2: 'Monochrome'}),
+    0x0005: ('ImageAdjustment',
+             {0: 'Normal',
+              1: 'Bright+',
+              2: 'Bright-',
+              3: 'Contrast+',
+              4: 'Contrast-'}),
+    0x0006: ('CCDSpeed',
+             {0: 'ISO 80',
+              2: 'ISO 160',
+              4: 'ISO 320',
+              5: 'ISO 100'}),
+    0x0007: ('WhiteBalance',
+             {0: 'Auto',
+              1: 'Preset',
+              2: 'Daylight',
+              3: 'Incandescent',
+              4: 'Fluorescent',
+              5: 'Cloudy',
+              6: 'Speed Light'})
+    }
+
+# decode Olympus SpecialMode tag in MakerNote
+def olympus_special_mode(v):
+    a={
+        0: 'Normal',
+        1: 'Unknown',
+        2: 'Fast',
+        3: 'Panorama'}
+    b={
+        0: 'Non-panoramic',
+        1: 'Left to right',
+        2: 'Right to left',
+        3: 'Bottom to top',
+        4: 'Top to bottom'}
+    return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
+        
+MAKERNOTE_OLYMPUS_TAGS={
+    # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
+    # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
+    0x0100: ('JPEGThumbnail', ),
+    0x0200: ('SpecialMode', olympus_special_mode),
+    0x0201: ('JPEGQual',
+             {1: 'SQ',
+              2: 'HQ',
+              3: 'SHQ'}),
+    0x0202: ('Macro',
+             {0: 'Normal',
+              1: 'Macro'}),
+    0x0204: ('DigitalZoom', ),
+    0x0207: ('SoftwareRelease',  ),
+    0x0208: ('PictureInfo',  ),
+    # print as string
+    0x0209: ('CameraID', lambda x: ''.join(map(chr, x))),
+    0x0F00: ('DataDump',  )
+    }
+
+MAKERNOTE_CASIO_TAGS={
+    0x0001: ('RecordingMode',
+             {1: 'Single Shutter',
+              2: 'Panorama',
+              3: 'Night Scene',
+              4: 'Portrait',
+              5: 'Landscape'}),
+    0x0002: ('Quality',
+             {1: 'Economy',
+              2: 'Normal',
+              3: 'Fine'}),
+    0x0003: ('FocusingMode',
+             {2: 'Macro',
+              3: 'Auto Focus',
+              4: 'Manual Focus',
+              5: 'Infinity'}),
+    0x0004: ('FlashMode',
+             {1: 'Auto',
+              2: 'On',
+              3: 'Off',
+              4: 'Red Eye Reduction'}),
+    0x0005: ('FlashIntensity',
+             {11: 'Weak',
+              13: 'Normal',
+              15: 'Strong'}),
+    0x0006: ('Object Distance', ),
+    0x0007: ('WhiteBalance',
+             {1:   'Auto',
+              2:   'Tungsten',
+              3:   'Daylight',
+              4:   'Fluorescent',
+              5:   'Shade',
+              129: 'Manual'}),
+    0x000B: ('Sharpness',
+             {0: 'Normal',
+              1: 'Soft',
+              2: 'Hard'}),
+    0x000C: ('Contrast',
+             {0: 'Normal',
+              1: 'Low',
+              2: 'High'}),
+    0x000D: ('Saturation',
+             {0: 'Normal',
+              1: 'Low',
+              2: 'High'}),
+    0x0014: ('CCDSpeed',
+             {64:  'Normal',
+              80:  'Normal',
+              100: 'High',
+              125: '+1.0',
+              244: '+3.0',
+              250: '+2.0',})
+    }
+
+MAKERNOTE_FUJIFILM_TAGS={
+    0x0000: ('NoteVersion', lambda x: ''.join(map(chr, x))),
+    0x1000: ('Quality', ),
+    0x1001: ('Sharpness',
+             {1: 'Soft',
+              2: 'Soft',
+              3: 'Normal',
+              4: 'Hard',
+              5: 'Hard'}),
+    0x1002: ('WhiteBalance',
+             {0:    'Auto',
+              256:  'Daylight',
+              512:  'Cloudy',
+              768:  'DaylightColor-Fluorescent',
+              769:  'DaywhiteColor-Fluorescent',
+              770:  'White-Fluorescent',
+              1024: 'Incandescent',
+              3840: 'Custom'}),
+    0x1003: ('Color',
+             {0:   'Normal',
+              256: 'High',
+              512: 'Low'}),
+    0x1004: ('Tone',
+             {0:   'Normal',
+              256: 'High',
+              512: 'Low'}),
+    0x1010: ('FlashMode',
+             {0: 'Auto',
+              1: 'On',
+              2: 'Off',
+              3: 'Red Eye Reduction'}),
+    0x1011: ('FlashStrength', ),
+    0x1020: ('Macro',
+             {0: 'Off',
+              1: 'On'}),
+    0x1021: ('FocusMode',
+             {0: 'Auto',
+              1: 'Manual'}),
+    0x1030: ('SlowSync',
+             {0: 'Off',
+              1: 'On'}),
+    0x1031: ('PictureMode',
+             {0:   'Auto',
+              1:   'Portrait',
+              2:   'Landscape',
+              4:   'Sports',
+              5:   'Night',
+              6:   'Program AE',
+              256: 'Aperture Priority AE',
+              512: 'Shutter Priority AE',
+              768: 'Manual Exposure'}),
+    0x1100: ('MotorOrBracket',
+             {0: 'Off',
+              1: 'On'}),
+    0x1300: ('BlurWarning',
+             {0: 'Off',
+              1: 'On'}),
+    0x1301: ('FocusWarning',
+             {0: 'Off',
+              1: 'On'}),
+    0x1302: ('AEWarning',
+             {0: 'Off',
+              1: 'On'})
+    }
+
+MAKERNOTE_CANON_TAGS={
+    0x0006: ('ImageType', ),
+    0x0007: ('FirmwareVersion', ),
+    0x0008: ('ImageNumber', ),
+    0x0009: ('OwnerName', )
+    }
+
+# see http://www.burren.cx/david/canon.html by David Burren
+# this is in element offset, name, optional value dictionary format
+MAKERNOTE_CANON_TAG_0x001={
+    1: ('Macromode',
+        {1: 'Macro',
+         2: 'Normal'}),
+    2: ('SelfTimer', ),
+    3: ('Quality',
+        {2: 'Normal',
+         3: 'Fine',
+         5: 'Superfine'}),
+    4: ('FlashMode',
+        {0: 'Flash Not Fired',
+         1: 'Auto',
+         2: 'On',
+         3: 'Red-Eye Reduction',
+         4: 'Slow Synchro',
+         5: 'Auto + Red-Eye Reduction',
+         6: 'On + Red-Eye Reduction',
+         16: 'external flash'}),
+    5: ('ContinuousDriveMode',
+        {0: 'Single Or Timer',
+         1: 'Continuous'}),
+    7: ('FocusMode',
+        {0: 'One-Shot',
+         1: 'AI Servo',
+         2: 'AI Focus',
+         3: 'MF',
+         4: 'Single',
+         5: 'Continuous',
+         6: 'MF'}),
+    10: ('ImageSize',
+         {0: 'Large',
+          1: 'Medium',
+          2: 'Small'}),
+    11: ('EasyShootingMode',
+         {0: 'Full Auto',
+          1: 'Manual',
+          2: 'Landscape',
+          3: 'Fast Shutter',
+          4: 'Slow Shutter',
+          5: 'Night',
+          6: 'B&W',
+          7: 'Sepia',
+          8: 'Portrait',
+          9: 'Sports',
+          10: 'Macro/Close-Up',
+          11: 'Pan Focus'}),
+    12: ('DigitalZoom',
+         {0: 'None',
+          1: '2x',
+          2: '4x'}),
+    13: ('Contrast',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    14: ('Saturation',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    15: ('Sharpness',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    16: ('ISO',
+         {0: 'See ISOSpeedRatings Tag',
+          15: 'Auto',
+          16: '50',
+          17: '100',
+          18: '200',
+          19: '400'}),
+    17: ('MeteringMode',
+         {3: 'Evaluative',
+          4: 'Partial',
+          5: 'Center-weighted'}),
+    18: ('FocusType',
+         {0: 'Manual',
+          1: 'Auto',
+          3: 'Close-Up (Macro)',
+          8: 'Locked (Pan Mode)'}),
+    19: ('AFPointSelected',
+         {0x3000: 'None (MF)',
+          0x3001: 'Auto-Selected',
+          0x3002: 'Right',
+          0x3003: 'Center',
+          0x3004: 'Left'}),
+    20: ('ExposureMode',
+         {0: 'Easy Shooting',
+          1: 'Program',
+          2: 'Tv-priority',
+          3: 'Av-priority',
+          4: 'Manual',
+          5: 'A-DEP'}),
+    23: ('LongFocalLengthOfLensInFocalUnits', ),
+    24: ('ShortFocalLengthOfLensInFocalUnits', ),
+    25: ('FocalUnitsPerMM', ),
+    28: ('FlashActivity',
+         {0: 'Did Not Fire',
+          1: 'Fired'}),
+    29: ('FlashDetails',
+         {14: 'External E-TTL',
+          13: 'Internal Flash',
+          11: 'FP Sync Used',
+          7: '2nd("Rear")-Curtain Sync Used',
+          4: 'FP Sync Enabled'}),
+    32: ('FocusMode',
+         {0: 'Single',
+          1: 'Continuous'})
+    }
+
+MAKERNOTE_CANON_TAG_0x004={
+    7: ('WhiteBalance',
+        {0: 'Auto',
+         1: 'Sunny',
+         2: 'Cloudy',
+         3: 'Tungsten',
+         4: 'Fluorescent',
+         5: 'Flash',
+         6: 'Custom'}),
+    9: ('SequenceNumber', ),
+    14: ('AFPointUsed', ),
+    15: ('FlashBias',
+        {0XFFC0: '-2 EV',
+         0XFFCC: '-1.67 EV',
+         0XFFD0: '-1.50 EV',
+         0XFFD4: '-1.33 EV',
+         0XFFE0: '-1 EV',
+         0XFFEC: '-0.67 EV',
+         0XFFF0: '-0.50 EV',
+         0XFFF4: '-0.33 EV',
+         0X0000: '0 EV',
+         0X000C: '0.33 EV',
+         0X0010: '0.50 EV',
+         0X0014: '0.67 EV',
+         0X0020: '1 EV',
+         0X002C: '1.33 EV',
+         0X0030: '1.50 EV',
+         0X0034: '1.67 EV',
+         0X0040: '2 EV'}),
+    19: ('SubjectDistance', )
+    }
+
+# extract multibyte integer in Motorola format (little endian)
+def s2n_motorola(str):
+    x=0
+    for c in str:
+        x=(x << 8) | ord(c)
+    return x
+
+# extract multibyte integer in Intel format (big endian)
+def s2n_intel(str):
+    x=0
+    y=0L
+    for c in str:
+        x=x | (ord(c) << y)
+        y=y+8
+    return x
+
+# ratio object that eventually will be able to reduce itself to lowest
+# common denominator for printing
+def gcd(a, b):
+   if b == 0:
+      return a
+   else:
+      return gcd(b, a % b)
+
+class Ratio:
+    def __init__(self, num, den):
+        self.num=num
+        self.den=den
+
+    def __repr__(self):
+        self.reduce()
+        if self.den == 1:
+            return str(self.num)
+        return '%d/%d' % (self.num, self.den)
+
+    def reduce(self):
+        div=gcd(self.num, self.den)
+        if div > 1:
+            self.num=self.num/div
+            self.den=self.den/div
+
+# for ease of dealing with tags
+class IFD_Tag:
+    def __init__(self, printable, tag, field_type, values, field_offset,
+                 field_length):
+        # printable version of data
+        self.printable=printable
+        # tag ID number
+        self.tag=tag
+        # field type as index into FIELD_TYPES
+        self.field_type=field_type
+        # offset of start of field in bytes from beginning of IFD
+        self.field_offset=field_offset
+        # length of data field in bytes
+        self.field_length=field_length
+        # either a string or array of data items
+        self.values=values
+        
+    def __str__(self):
+        return self.printable
+    
+    def __repr__(self):
+        return '(0x%04X) %s=%s @ %d' % (self.tag,
+                                        FIELD_TYPES[self.field_type][2],
+                                        self.printable,
+                                        self.field_offset)
+
+# class that handles an EXIF header
+class EXIF_header:
+    def __init__(self, file, endian, offset, fake_exif, debug=0):
+        self.file=file
+        self.endian=endian
+        self.offset=offset
+        self.fake_exif=fake_exif
+        self.debug=debug
+        self.tags={}
+        
+    # convert slice to integer, based on sign and endian flags
+    # usually this offset is assumed to be relative to the beginning of the
+    # start of the EXIF information.  For some cameras that use relative tags,
+    # this offset may be relative to some other starting point.
+    def s2n(self, offset, length, signed=0):
+        self.file.seek(self.offset+offset)
+        slice=self.file.read(length)
+        if self.endian == 'I':
+            val=s2n_intel(slice)
+        else:
+            val=s2n_motorola(slice)
+        # Sign extension ?
+        if signed:
+            msb=1L << (8*length-1)
+            if val & msb:
+                val=val-(msb << 1)
+        return val
+
+    # convert offset to string
+    def n2s(self, offset, length):
+        s=''
+        for i in range(length):
+            if self.endian == 'I':
+                s=s+chr(offset & 0xFF)
+            else:
+                s=chr(offset & 0xFF)+s
+            offset=offset >> 8
+        return s
+    
+    # return first IFD
+    def first_IFD(self):
+        return self.s2n(4, 4)
+
+    # return pointer to next IFD
+    def next_IFD(self, ifd):
+        entries=self.s2n(ifd, 2)
+        return self.s2n(ifd+2+12*entries, 4)
+
+    # return list of IFDs in header
+    def list_IFDs(self):
+        i=self.first_IFD()
+        a=[]
+        while i:
+            a.append(i)
+            i=self.next_IFD(i)
+        return a
+
+    # return list of entries in this IFD
+    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0):
+        entries=self.s2n(ifd, 2)
+        for i in range(entries):
+            # entry is index of start of this IFD in the file
+            entry=ifd+2+12*i
+            tag=self.s2n(entry, 2)
+            # get tag name.  We do it early to make debugging easier
+            tag_entry=dict.get(tag)
+            if tag_entry:
+                tag_name=tag_entry[0]
+            else:
+                tag_name='Tag 0x%04X' % tag
+            field_type=self.s2n(entry+2, 2)
+            if not 0 < field_type < len(FIELD_TYPES):
+                # unknown field type
+                raise ValueError, \
+                      'unknown type %d in tag 0x%04X' % (field_type, tag)
+            typelen=FIELD_TYPES[field_type][0]
+            count=self.s2n(entry+4, 4)
+            offset=entry+8
+            if count*typelen > 4:
+                # offset is not the value; it's a pointer to the value
+                # if relative we set things up so s2n will seek to the right
+                # place when it adds self.offset.  Note that this 'relative'
+                # is for the Nikon type 3 makernote.  Other cameras may use
+                # other relative offsets, which would have to be computed here
+                # slightly differently.
+                if relative:
+                    tmp_offset=self.s2n(offset, 4)
+                    offset=tmp_offset+ifd-self.offset+4
+                    if self.fake_exif:
+                        offset=offset+18
+                else:
+                    offset=self.s2n(offset, 4)
+            field_offset=offset
+            if field_type == 2:
+                # special case: null-terminated ASCII string
+                if count != 0:
+                    self.file.seek(self.offset+offset)
+                    values=self.file.read(count)
+                    values=values.strip().replace('\x00','')
+                else:
+                    values=''
+            else:
+                values=[]
+                signed=(field_type in [6, 8, 9, 10])
+                for j in range(count):
+                    if field_type in (5, 10):
+                        # a ratio
+                        value_j=Ratio(self.s2n(offset,   4, signed),
+                                      self.s2n(offset+4, 4, signed))
+                    else:
+                        value_j=self.s2n(offset, typelen, signed)
+                    values.append(value_j)
+                    offset=offset+typelen
+            # now "values" is either a string or an array
+            if count == 1 and field_type != 2:
+                printable=str(values[0])
+            else:
+                printable=str(values)
+            # compute printable version of values
+            if tag_entry:
+                if len(tag_entry) != 1:
+                    # optional 2nd tag element is present
+                    if callable(tag_entry[1]):
+                        # call mapping function
+                        printable=tag_entry[1](values)
+                    else:
+                        printable=''
+                        for i in values:
+                            # use lookup table for this tag
+                            printable+=tag_entry[1].get(i, repr(i))
+            self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
+                                                     field_type,
+                                                     values, field_offset,
+                                                     count*typelen)
+            if self.debug:
+                print ' debug:   %s: %s' % (tag_name,
+                                            repr(self.tags[ifd_name+' '+tag_name]))
+
+    # extract uncompressed TIFF thumbnail (like pulling teeth)
+    # we take advantage of the pre-existing layout in the thumbnail IFD as
+    # much as possible
+    def extract_TIFF_thumbnail(self, thumb_ifd):
+        entries=self.s2n(thumb_ifd, 2)
+        # this is header plus offset to IFD ...
+        if self.endian == 'M':
+            tiff='MM\x00*\x00\x00\x00\x08'
+        else:
+            tiff='II*\x00\x08\x00\x00\x00'
+        # ... plus thumbnail IFD data plus a null "next IFD" pointer
+        self.file.seek(self.offset+thumb_ifd)
+        tiff+=self.file.read(entries*12+2)+'\x00\x00\x00\x00'
+        
+        # fix up large value offset pointers into data area
+        for i in range(entries):
+            entry=thumb_ifd+2+12*i
+            tag=self.s2n(entry, 2)
+            field_type=self.s2n(entry+2, 2)
+            typelen=FIELD_TYPES[field_type][0]
+            count=self.s2n(entry+4, 4)
+            oldoff=self.s2n(entry+8, 4)
+            # start of the 4-byte pointer area in entry
+            ptr=i*12+18
+            # remember strip offsets location
+            if tag == 0x0111:
+                strip_off=ptr
+                strip_len=count*typelen
+            # is it in the data area?
+            if count*typelen > 4:
+                # update offset pointer (nasty "strings are immutable" crap)
+                # should be able to say "tiff[ptr:ptr+4]=newoff"
+                newoff=len(tiff)
+                tiff=tiff[:ptr]+self.n2s(newoff, 4)+tiff[ptr+4:]
+                # remember strip offsets location
+                if tag == 0x0111:
+                    strip_off=newoff
+                    strip_len=4
+                # get original data and store it
+                self.file.seek(self.offset+oldoff)
+                tiff+=self.file.read(count*typelen)
+                
+        # add pixel strips and update strip offset info
+        old_offsets=self.tags['Thumbnail StripOffsets'].values
+        old_counts=self.tags['Thumbnail StripByteCounts'].values
+        for i in range(len(old_offsets)):
+            # update offset pointer (more nasty "strings are immutable" crap)
+            offset=self.n2s(len(tiff), strip_len)
+            tiff=tiff[:strip_off]+offset+tiff[strip_off+strip_len:]
+            strip_off+=strip_len
+            # add pixel strip to end
+            self.file.seek(self.offset+old_offsets[i])
+            tiff+=self.file.read(old_counts[i])
+            
+        self.tags['TIFFThumbnail']=tiff
+        
+    # decode all the camera-specific MakerNote formats
+
+    # Note is the data that comprises this MakerNote.  The MakerNote will
+    # likely have pointers in it that point to other parts of the file.  We'll
+    # use self.offset as the starting point for most of those pointers, since
+    # they are relative to the beginning of the file.
+    #
+    # If the MakerNote is in a newer format, it may use relative addressing
+    # within the MakerNote.  In that case we'll use relative addresses for the
+    # pointers.
+    #
+    # As an aside: it's not just to be annoying that the manufacturers use
+    # relative offsets.  It's so that if the makernote has to be moved by the
+    # picture software all of the offsets don't have to be adjusted.  Overall,
+    # this is probably the right strategy for makernotes, though the spec is
+    # ambiguous.  (The spec does not appear to imagine that makernotes would
+    # follow EXIF format internally.  Once they did, it's ambiguous whether
+    # the offsets should be from the header at the start of all the EXIF info,
+    # or from the header at the start of the makernote.)
+    def decode_maker_note(self):
+        note=self.tags['EXIF MakerNote']
+        make=self.tags['Image Make'].printable
+        model=self.tags['Image Model'].printable
+
+        # Nikon
+        # The maker note usually starts with the word Nikon, followed by the
+        # type of the makernote (1 or 2, as a short).  If the word Nikon is
+        # not at the start of the makernote, it's probably type 2, since some
+        # cameras work that way.
+        if make in ('NIKON', 'NIKON CORPORATION'):
+            if note.values[0:7] == [78, 105, 107, 111, 110, 00, 01]:
+                if self.debug:
+                    print "Looks like a type 1 Nikon MakerNote."
+                self.dump_IFD(note.field_offset+8, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_OLDER_TAGS)
+            elif note.values[0:7] == [78, 105, 107, 111, 110, 00, 02]:
+                if self.debug:
+                    print "Looks like a labeled type 2 Nikon MakerNote"
+                if note.values[12:14] != [0, 42] and note.values[12:14] != [42L, 0L]:
+                    raise ValueError, "Missing marker tag '42' in MakerNote."
+                # skip the Makernote label and the TIFF header
+                self.dump_IFD(note.field_offset+10+8, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_NEWER_TAGS, relative=1)
+            else:
+                # E99x or D1
+                if self.debug:
+                    print "Looks like an unlabeled type 2 Nikon MakerNote"
+                self.dump_IFD(note.field_offset, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_NEWER_TAGS)
+            return
+
+        # Olympus
+        if make[:7] == 'OLYMPUS':
+            self.dump_IFD(note.field_offset+8, 'MakerNote',
+                          dict=MAKERNOTE_OLYMPUS_TAGS)
+            return
+
+        # Casio
+        if make == 'Casio':
+            self.dump_IFD(note.field_offset, 'MakerNote',
+                          dict=MAKERNOTE_CASIO_TAGS)
+            return
+        
+        # Fujifilm
+        if make == 'FUJIFILM':
+            # bug: everything else is "Motorola" endian, but the MakerNote
+            # is "Intel" endian
+            endian=self.endian
+            self.endian='I'
+            # bug: IFD offsets are from beginning of MakerNote, not
+            # beginning of file header
+            offset=self.offset
+            self.offset+=note.field_offset
+            # process note with bogus values (note is actually at offset 12)
+            self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS)
+            # reset to correct values
+            self.endian=endian
+            self.offset=offset
+            return
+        
+        # Canon
+        if make == 'Canon':
+            self.dump_IFD(note.field_offset, 'MakerNote',
+                          dict=MAKERNOTE_CANON_TAGS)
+            for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001),
+                      ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
+                self.canon_decode_tag(self.tags[i[0]].values, i[1])
+            return
+
+    # decode Canon MakerNote tag based on offset within tag
+    # see http://www.burren.cx/david/canon.html by David Burren
+    def canon_decode_tag(self, value, dict):
+        for i in range(1, len(value)):
+            x=dict.get(i, ('Unknown', ))
+            if self.debug:
+                print i, x
+            name=x[0]
+            if len(x) > 1:
+                val=x[1].get(value[i], 'Unknown')
+            else:
+                val=value[i]
+            # it's not a real IFD Tag but we fake one to make everybody
+            # happy. this will have a "proprietary" type
+            self.tags['MakerNote '+name]=IFD_Tag(str(val), None, 0, None,
+                                                 None, None)
+
+# process an image file (expects an open file object)
+# this is the function that has to deal with all the arbitrary nasty bits
+# of the EXIF standard
+def process_file(file, debug=0):
+    # determine whether it's a JPEG or TIFF
+    data=file.read(12)
+    if data[0:4] in ['II*\x00', 'MM\x00*']:
+        # it's a TIFF file
+        file.seek(0)
+        endian=file.read(1)
+        file.read(1)
+        offset=0
+    elif data[0:2] == '\xFF\xD8':
+        # it's a JPEG file
+        # skip JFIF style header(s)
+        fake_exif=0
+        while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM'):
+            length=ord(data[4])*256+ord(data[5])
+            file.read(length-8)
+            # fake an EXIF beginning of file
+            data='\xFF\x00'+file.read(10)
+            fake_exif=1
+        if data[2] == '\xFF' and data[6:10] == 'Exif':
+            # detected EXIF header
+            offset=file.tell()
+            endian=file.read(1)
+        else:
+            # no EXIF information
+            return {}
+    else:
+        # file format not recognized
+        return {}
+
+    # deal with the EXIF info we found
+    if debug:
+        print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format'
+    hdr=EXIF_header(file, endian, offset, fake_exif, debug)
+    ifd_list=hdr.list_IFDs()
+    ctr=0
+    for i in ifd_list:
+        if ctr == 0:
+            IFD_name='Image'
+        elif ctr == 1:
+            IFD_name='Thumbnail'
+            thumb_ifd=i
+        else:
+            IFD_name='IFD %d' % ctr
+        if debug:
+            print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
+        hdr.dump_IFD(i, IFD_name)
+        # EXIF IFD
+        exif_off=hdr.tags.get(IFD_name+' ExifOffset')
+        if exif_off:
+            if debug:
+                print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
+            hdr.dump_IFD(exif_off.values[0], 'EXIF')
+            # Interoperability IFD contained in EXIF IFD
+            intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
+            if intr_off:
+                if debug:
+                    print ' EXIF Interoperability SubSubIFD at offset %d:' \
+                          % intr_off.values[0]
+                hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
+                             dict=INTR_TAGS)
+        # GPS IFD
+        gps_off=hdr.tags.get(IFD_name+' GPSInfo')
+        if gps_off:
+            if debug:
+                print ' GPS SubIFD at offset %d:' % gps_off.values[0]
+            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
+        ctr+=1
+
+    # extract uncompressed TIFF thumbnail
+    thumb=hdr.tags.get('Thumbnail Compression')
+    if thumb and thumb.printable == 'Uncompressed TIFF':
+        hdr.extract_TIFF_thumbnail(thumb_ifd)
+        
+    # JPEG thumbnail (thankfully the JPEG data is stored as a unit)
+    thumb_off=hdr.tags.get('Thumbnail JPEGInterchangeFormat')
+    if thumb_off:
+        file.seek(offset+thumb_off.values[0])
+        size=hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
+        hdr.tags['JPEGThumbnail']=file.read(size)
+        
+    # deal with MakerNote contained in EXIF IFD
+    if hdr.tags.has_key('EXIF MakerNote'):
+        hdr.decode_maker_note()
+
+    # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote
+    # since it's not allowed in a uncompressed TIFF IFD
+    if not hdr.tags.has_key('JPEGThumbnail'):
+        thumb_off=hdr.tags.get('MakerNote JPEGThumbnail')
+        if thumb_off:
+            file.seek(offset+thumb_off.values[0])
+            hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length)
+            
+    return hdr.tags
+
+# library test/debug function (dump given files)
+if __name__ == '__main__':
+    import sys
+    
+    if len(sys.argv) < 2:
+        print 'Usage: %s files...\n' % sys.argv[0]
+        sys.exit(0)
+        
+    for filename in sys.argv[1:]:
+        try:
+            file=open(filename, 'rb')
+        except:
+            print filename, 'unreadable'
+            print
+            continue
+        print filename+':'
+        # data=process_file(file, 1) # with debug info
+        data=process_file(file)
+        if not data:
+            print 'No EXIF information found'
+            continue
+
+        x=data.keys()
+        x.sort()
+        for i in x:
+            if i in ('JPEGThumbnail', 'TIFFThumbnail'):
+                continue
+            try:
+                print '   %s (%s): %s' % \
+                      (i, FIELD_TYPES[data[i].field_type][2], data[i].printable)
+            except:
+                print 'error', i, '"', data[i], '"'
+        if data.has_key('JPEGThumbnail'):
+            print 'File has JPEG thumbnail'
+        print
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/bins.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/bins.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/bins.py	(revision 4)
@@ -0,0 +1,151 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# bins.py - Python interface to bins data files.
+# -----------------------------------------------------------------------
+# $Id: bins.py,v 1.2 2004/05/04 22:02:59 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# $Log: bins.py,v $
+# Revision 1.2  2004/05/04 22:02:59  dischi
+# fix crash with empty exif tag
+#
+# Revision 1.1  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+#
+# -----------------------------------------------------------------------
+# This file Copyright (C) 2002 John Cooper
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from xml.sax import make_parser, ContentHandler
+from xml.sax.handler import feature_namespaces
+import string
+import os
+import re
+
+
+def normalize_whitespace(text):
+    # Remove Redundant whitespace from a string
+    return ' '.join(text.split())
+
+RE_TEXT = re.compile("^[ \n\t]*(.*[^ \n\t])[ \n\t]*$").match
+
+# remove redundant whitespaces/tabs/newlines at the beginning and the end
+def normalize_text(text):
+    m = RE_TEXT(text)
+    if m:
+        return m.group(1)
+    return text
+
+
+def format_text(text):
+    while len(text) and text[0] in (' ', '\t', '\n'):
+        text = text[1:]
+    text = re.sub('\n[\t *]', ' ', text)
+    while len(text) and text[-1] in (' ', '\t', '\n'):
+        text = text[:-1]
+    return text
+
+
+class BinsDiscription(ContentHandler):
+    """
+    This is a handler for getting the information from a bins Album.
+    """
+    def __init__(self):
+        self.desc = {}
+	self.exif = {}
+        self.inDisc = 0
+        self.inField = 0
+	self.inExif = 0
+	self.inTag = 0
+
+    def startElement(self,name,attrs):
+        # Check that we  have a discription section
+        if name == u'description':
+            self.inDisc = 1
+        if name == u'field':
+            self.thisField = normalize_whitespace(attrs.get('name', ''))
+            self.inField = 1
+            self.desc[self.thisField] = ''
+	if name == u'exif':
+	    self.inExif = 1
+	if name == u'tag':
+	    self.inTag = 1
+	    self.thisTag = normalize_whitespace(attrs.get('name', ''))
+	    self.exif[self.thisTag] = ''
+
+
+    def characters(self,ch):
+        if self.inDisc:
+            if self.inField:
+                self.desc[self.thisField] = self.desc[self.thisField] + ch
+        if self.inExif:
+	    if self.inTag:
+	        self.exif[self.thisTag] = self.exif[self.thisTag] + ch
+
+ 
+    def endElement(self,name):
+        if name == 'discription':
+            self.inDisc = 0
+        if name == 'field':
+            self.desc[self.thisField] = normalize_text(self.desc[self.thisField])
+            self.inField = 0
+	if name == 'exif':
+            try:
+                self.exif[self.thisTag] = normalize_text(self.exif[self.thisTag])
+            except:
+                pass
+            self.inExif = 0
+                
+	if name == 'tag':
+	    self.inTag = 0
+
+def get_bins_desc(binsname):
+     parser = make_parser()
+     parser.setFeature(feature_namespaces,0)
+     dh = BinsDiscription()
+     parser.setContentHandler(dh)
+     # check that the xml file exists for a dir or image
+     if os.path.isfile(binsname + '/album.xml'):
+         binsname = binsname + '/album.xml'
+     elif os.path.isfile(binsname + '.xml'):
+         binsname = binsname + '.xml'
+     else:
+         dh.desc['title'] == os.path.basename(dirname)
+
+     # Check that there is a title
+     parser.parse(binsname)
+
+     # remove whitespace at the beginning
+     for d in dh.desc:
+         dh.desc[d] = format_text(dh.desc[d])
+     for d in dh.exif:
+         dh.exif[d] = format_text(dh.exif[d])
+
+     return {'desc':dh.desc , 'exif':dh.exif}
+
+
+if __name__ == '__main__':
+    parser = make_parser()
+    parser.setFeature(feature_namespaces,0)
+    dh = GetAlbum()
+    parser.setContentHandler(dh)
+    parser.parse('album.xml')
+    print dh.desc
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/jpginfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/jpginfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/jpginfo.py	(revision 4)
@@ -0,0 +1,198 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: jpginfo.py,v 1.21 2005/04/16 17:08:40 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: jpginfo.py,v $
+# Revision 1.21  2005/04/16 17:08:40  dischi
+# read metadata from epeg
+#
+# Revision 1.20  2005/04/16 15:01:15  dischi
+# convert exif tags to str
+#
+# Revision 1.19  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.18  2003/06/30 13:17:19  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.17  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.16  2003/06/10 13:02:32  the_krow
+# Softened JPEG parser a little so it accepts jpegs that do not end in FFD9.
+#
+# Revision 1.15  2003/06/09 14:31:57  the_krow
+# fixes on the mpeg parser
+# resolutions, fps and bitrate should be reported correctly now
+#
+# Revision 1.14  2003/06/09 12:50:08  the_krow
+# mp3 now fills tables
+#
+# Revision 1.13  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.12  2003/06/08 16:48:08  dischi
+# Changed self.exif to exif_info and the same for ipc. We should extract
+# everything we need to self.xxx and don't remember where the info came
+# from (it's bad for the cache, we cache everything twice).
+# Also added thumbnail to the list of things we want
+#
+# Revision 1.11  2003/06/08 13:44:57  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.10  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.9  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.8  2003/05/13 18:28:17  the_krow
+# JPEG Resolution
+#
+# Revision 1.7  2003/05/13 17:49:41  the_krow
+# IPTC restructured\nEXIF Height read correctly\nJPEG Endmarker read
+#
+# Revision 1.6  2003/05/13 15:52:42  the_krow
+# Caption added
+#
+# Revision 1.5  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.4  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# Revision 1.3  2003/05/13 12:31:11  the_krow
+# + GNU Copyright Notice
+# + PNG Parsing
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+
+import ImageInfo
+
+# interesting file format info:
+# http://www.dcs.ed.ac.uk/home/mxr/gfx/2d-hi.html
+# http://www.funducode.com/freec/Fileformats/format3/format3b.htm
+
+SOF = { 0xC0 : "Baseline",   
+        0xC1 : "Extended sequential",   
+        0xC2 : "Progressive",   
+        0xC3 : "Lossless",   
+        0xC5 : "Differential sequential",   
+        0xC6 : "Differential progressive",   
+        0xC7 : "Differential lossless",   
+        0xC9 : "Extended sequential, arithmetic coding",   
+        0xCA : "Progressive, arithmetic coding",   
+        0xCB : "Lossless, arithmetic coding",   
+        0xCD : "Differential sequential, arithmetic coding",   
+        0xCE : "Differential progressive, arithmetic coding",   
+        0xCF : "Differential lossless, arithmetic coding",
+}
+
+_debug = mediainfo._debug
+
+class JPGInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        iptc_info = None        
+        self.mime = 'image/jpeg'
+        self.type = 'jpeg image'
+        self.valid = 1
+        if file.read(2) != '\xff\xd8':
+            self.valid = 0
+            return
+        file.seek(-2,2)
+        if file.read(2) != '\xff\xd9':
+            # Normally an JPEG should end in ffd9. This does not however
+            # we assume it's an jpeg for now
+            mediainfo._debug("Wrong encode found for jpeg")
+        file.seek(2)
+        app = file.read(4)
+        self.meta = {}
+        while (len(app) == 4):
+            (ff,segtype,seglen) = struct.unpack(">BBH", app)
+            if ff != 0xff: break
+            _debug("SEGMENT: 0x%x%x, len=%d" % (ff,segtype,seglen))
+            if segtype == 0xd9:
+                break
+            elif SOF.has_key(segtype):
+                data = file.read(seglen-2)
+                (precision,self.height,self.width,num_comp) = struct.unpack('>BHHB', data[:6])
+                #_debug("H/W: %i / %i" % (self.height, self.width))
+            elif segtype == 0xed:
+                app = file.read(seglen-2)
+                iptc_info = IPTC.flatten(IPTC.parseiptc(app))
+                break
+            elif segtype == 0xe7:
+                # information created by libs like epeg
+                data = file.read(seglen-2)
+                if data.count('\n') == 1:
+                    key, value = data.split('\n')
+                    self.meta[key] = value
+            else:
+                file.seek(seglen-2,1)
+            app = file.read(4)
+        file.seek(0)
+        exif_info = EXIF.process_file(file)
+        if exif_info:
+            self.setitem( 'date', exif_info, 'Image DateTime', True )            
+            self.setitem( 'artist', exif_info, 'Image Artist', True )
+            self.setitem( 'hardware', exif_info, 'Image Model', True )
+            self.setitem( 'software', exif_info, 'Image Software', True )
+            self.setitem( 'thumbnail', exif_info, 'JPEGThumbnail', True )
+            self.appendtable( 'EXIF', exif_info )
+        if iptc_info:
+            self.setitem( 'title', iptc_info, 517, True ) 
+            self.setitem( 'date' , iptc_info, 567, True )
+            self.setitem( 'comment', iptc_info, 617, True )
+            self.setitem( 'keywords', iptc_info, 537, True )
+            self.setitem( 'artist', iptc_info, 592, True )
+            self.setitem( 'country', iptc_info, 612, True ) 
+            self.setitem( 'caption', iptc_info, 632, True )
+            self.appendtable( 'IPTC', iptc_info )            
+
+        if len(self.meta.keys()):
+            self.appendtable( 'JPGMETA', self.meta )
+        for key, value in self.meta.items():
+            if key.startswith('Thumb:') or key == 'Software':
+                setattr(self, key, value)
+                if not key in self.keys:
+                    self.keys.append(key)
+
+        ImageInfo.add(file.name, self)
+        return
+       
+
+mmpython.registertype( 'image/jpeg', ('jpg','jpeg'), mediainfo.TYPE_IMAGE, JPGInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/ImageInfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/ImageInfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/ImageInfo.py	(revision 4)
@@ -0,0 +1,124 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: ImageInfo.py,v 1.2 2005/04/16 15:01:53 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: ImageInfo.py,v $
+# Revision 1.2  2005/04/16 15:01:53  dischi
+# read gthumb comment files
+#
+# Revision 1.1  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import mmpython
+from mmpython import mediainfo
+
+import os
+import gzip
+#from xml.utils import qp_xml   #this doesn't exist for some reason
+import xml.parsers.expat as qp_xml
+
+DEBUG = mediainfo.DEBUG
+
+try:
+    import Image
+except:
+    if DEBUG:
+        print 'Python Imaging not found'
+
+import bins
+
+def add(filename, object):
+    if os.path.isfile(filename + '.xml'):
+        try:
+            binsinfo = bins.get_bins_desc(filename)
+            # get needed keys from exif infos
+            for key in mediainfo.IMAGECORE + mediainfo.MEDIACORE:
+                if not object[key] and binsinfo['exif'].has_key(key):
+                    object[key] = binsinfo['exif'][key]
+            # get _all_ infos from description
+            for key in binsinfo['desc']:
+                object[key] = binsinfo['desc'][key]
+                if not key in mediainfo.IMAGECORE + mediainfo.MEDIACORE:
+                    # if it's in desc it must be important
+                    object.keys.append(key)
+        except Exception, e:
+            if DEBUG:
+                print e
+            pass
+
+    comment_file = os.path.join(os.path.dirname(filename),
+                                '.comments',
+                                os.path.basename(filename) + '.xml')
+    if os.path.isfile(comment_file):
+        try:
+            f = gzip.open(comment_file)
+            p = qp_xml.Parser()
+            tree = p.parse(f)
+            f.close()
+            for c in tree.children:
+                if c.name == 'Place':
+                    object.location = c.textof()
+                if c.name == 'Note':
+                    object.description = c.textof()
+        except:
+            pass
+    try:
+        i = Image.open(filename)
+    except:
+        return 0
+
+    if not object.mime:
+        object.mime = 'image/%s' % i.format.lower()
+        
+    object.type = i.format_description
+
+    if i.info.has_key('dpi'):
+        object['dpi'] = '%sx%s' % i.info['dpi']
+
+    if DEBUG:
+        for info in i.info:
+            if not info == 'exif':
+                print '%s: %s' % (info, i.info[info])
+
+    object.mode = i.mode
+    if not object.height:
+        object.width, object.height = i.size
+
+    return 1
+
+
+
+
+
+class ImageInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.mime  = ''
+        self.type  = ''
+        self.valid = add(file.name, self)
+        
+mmpython.registertype( 'image/gif', ('gif',), mediainfo.TYPE_IMAGE, ImageInfo )
+mmpython.registertype( 'image/bmp', ('bmp',), mediainfo.TYPE_IMAGE, ImageInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/IPTC.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/IPTC.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/IPTC.py	(revision 4)
@@ -0,0 +1,117 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: IPTC.py,v 1.9 2004/05/04 22:03:17 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: IPTC.py,v $
+# Revision 1.9  2004/05/04 22:03:17  dischi
+# handle bad jpeg
+#
+# Revision 1.8  2003/06/09 16:11:57  the_krow
+# TIFF parser changed to new tables structure
+# debug statements removed / changed to _debug
+#
+# Revision 1.7  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.6  2003/05/13 17:49:41  the_krow
+# IPTC restructured
+# EXIF Height read correctly
+# JPEG Endmarker read
+#
+# Revision 1.5  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.4  2003/05/13 15:16:02  the_krow
+# width+height hacked
+#
+# Revision 1.3  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+# http://www.ap.org/apserver/userguide/codes.htm
+
+from struct import unpack
+
+def flatten(list):
+    try:
+        for i in list.keys():
+            val = list[i]
+            if len(val) == 0: list[i] = None
+            elif len(val) == 1: list[i] = val[0]
+            else: list[i] = tuple(val)
+        return list
+    except:
+        return []
+
+def parseiptc(app):
+    iptc = {}
+    if app[:14] == "Photoshop 3.0\x00":
+       app = app[14:]
+    if 1:
+       # parse the image resource block
+       offset = 0
+       data = None
+       while app[offset:offset+4] == "8BIM":
+          offset = offset + 4
+          # resource code
+          code = unpack("<H", app[offset:offset+2])[0]
+          offset = offset + 2
+          # resource name (usually empty)
+          name_len = ord(app[offset])
+          name = app[offset+1:offset+1+name_len]
+          offset = 1 + offset + name_len
+          if offset & 1:
+              offset = offset + 1
+          # resource data block
+          size = unpack("<L", app[offset:offset+4])[0]
+          offset = offset + 4
+          if code == 0x0404:
+              # 0x0404 contains IPTC/NAA data
+              data = app[offset:offset+size]
+              break
+          offset = offset + size
+          if offset & 1:
+              offset = offset + 1
+       if not data:
+          return None
+       offset = 0
+       iptc = {}
+       while 1:
+           try:
+               intro = ord(data[offset])
+           except IndexError:
+               return ''
+           if intro != 0x1c:
+               return iptc
+           (key,len) = unpack('>HH',data[offset+1:offset+5])
+           val = data[offset+5:offset+len+5]
+           if iptc.has_key(key):
+               iptc[key].append(val)
+           else:
+               iptc[key] = [val]
+           offset += len + 5
+    return iptc
+    
+    
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/pnginfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/pnginfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/pnginfo.py	(revision 4)
@@ -0,0 +1,144 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: pnginfo.py,v 1.11 2005/04/16 17:09:12 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: pnginfo.py,v $
+# Revision 1.11  2005/04/16 17:09:12  dischi
+# add thumbnail data to internal vars
+#
+# Revision 1.10  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.9  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.8  2003/06/23 20:59:11  the_krow
+# PNG should now fill a correct table.
+#
+# Revision 1.7  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.6  2003/06/08 20:27:42  dischi
+# small fix for broken files and fixed a wrong bins_data call
+#
+# Revision 1.5  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# Revision 1.1  2003/05/13 12:31:11  the_krow
+# + GNU Copyright Notice
+# + PNG Parsing
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+import zlib
+import ImageInfo
+
+# interesting file format info:
+# http://www.libpng.org/pub/png/png-sitemap.html#programming
+# http://pmt.sourceforge.net/pngmeta/
+
+PNGSIGNATURE = "\211PNG\r\n\032\n"
+
+_print = mediainfo._debug
+
+class PNGInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.iptc = None        
+        self.mime = 'image/png'
+        self.type = 'PNG image'
+        self.valid = 1
+        signature = file.read(8)
+        if ( signature != PNGSIGNATURE ):
+            self.valid = 0
+            return
+        self.meta = {}
+        while self._readChunk(file):
+            pass
+        if len(self.meta.keys()):
+            self.appendtable( 'PNGMETA', self.meta )
+        for key, value in self.meta.items():
+            if key.startswith('Thumb:') or key == 'Software':
+                setattr(self, key, value)
+                if not key in self.keys:
+                    self.keys.append(key)
+        ImageInfo.add(file.name, self)
+        return       
+        
+    def _readChunk(self,file):
+        try:
+            (length, type) = struct.unpack('>I4s', file.read(8))
+        except:
+            return 0
+        if ( type == 'tEXt' ):
+          _print('latin-1 Text found.')
+          (data, crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          (key, value) = data.split('\0')
+          self.meta[key] = value
+          _print("%s -> %s" % (key,value))
+        elif ( type == 'zTXt' ):
+          _print('Compressed Text found.')
+          (data,crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          split = data.split('\0')
+          key = split[0]
+          value = "".join(split[1:])
+          compression = ord(value[0])
+          value = value[1:]
+          if compression == 0:
+              decompressed = zlib.decompress(value)
+              _print("%s (Compressed %i) -> %s" % (key,compression,decompressed))
+          else:
+              _print("%s has unknown Compression %c" % (key,compression))
+          self.meta[key] = value
+        elif ( type == 'iTXt' ):
+          _print('International Text found.')
+          (data,crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          (key, value) = data.split('\0')
+          self.meta[key] = value
+          _print("%s -> %s" % (key,value))
+        else:
+          file.seek(length+4,1)
+          _print("%s of length %d ignored." % (type, length))
+        return 1
+
+
+mmpython.registertype( 'image/png', ('png',), mediainfo.TYPE_IMAGE, PNGInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/image/tiffinfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/image/tiffinfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/image/tiffinfo.py	(revision 4)
@@ -0,0 +1,157 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: tiffinfo.py,v 1.11 2004/05/20 15:56:31 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: tiffinfo.py,v $
+# Revision 1.11  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.10  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.9  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.8  2003/06/09 16:11:57  the_krow
+# TIFF parser changed to new tables structure
+# debug statements removed / changed to _debug
+#
+# Revision 1.7  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.6  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.5  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.4  2003/05/13 15:52:43  the_krow
+# Caption added
+#
+# Revision 1.3  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.2  2003/05/13 15:16:02  the_krow
+# width+height hacked
+#
+# Revision 1.1  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# -----------------------------------------------------------------------
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+import ImageInfo
+
+MOTOROLASIGNATURE = 'MM\x00\x2a'
+INTELSIGNATURE = 'II\x2a\x00'
+
+# http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf
+
+_debug = mediainfo._debug
+
+class TIFFInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.iptc = None        
+        self.mime = 'image/tiff'
+        self.type = 'TIFF image'
+        self.intel = 0
+        self.valid = 0
+        iptc = {}
+        header = file.read(8)
+        if header[:4] == MOTOROLASIGNATURE:
+            self.valid = 1
+            self.intel = 0
+            (offset,) = struct.unpack(">I", header[4:8])
+            file.seek(offset)
+            (len,) = struct.unpack(">H", file.read(2))
+            app = file.read(len*12)
+            for i in range(len):
+                (tag, type, length, value, offset) = struct.unpack('>HHIHH', app[i*12:i*12+12])
+                _debug("[%i/%i] tag: 0x%.4x, type 0x%.4x, len %d, value %d, offset %d)" % (i,len,tag,type,length,value,offset))
+                if tag == 0x8649:
+                    file.seek(offset,0)
+                    iptc = IPTC.flatten(IPTC.parseiptc(file.read(1000)))
+                elif tag == 0x0100:
+                    if value != 0:
+                        self.width = value
+                    else:
+                        self.width = offset
+                elif tag == 0x0101:
+                    if value != 0:
+                        self.height = value
+                    else:
+                        self.height = offset
+
+        elif header[:4] == INTELSIGNATURE:
+            self.valid = 1
+            self.intel = 1
+            (offset,) = struct.unpack("<I", header[4:8])
+            file.seek(offset,0)
+            (len,) = struct.unpack("<H", file.read(2))
+            app = file.read(len*12)
+            for i in range(len):
+                (tag, type, length, offset, value) = struct.unpack('<HHIHH', app[i*12:i*12+12])
+                _debug("[%i/%i] tag: 0x%.4x, type 0x%.4x, len %d, value %d, offset %d)" % (i,len,tag,type,length,value,offset))
+                if tag == 0x8649:
+                    file.seek(offset)
+                    iptc = IPTC.flatten(IPTC.parseiptc(file.read(1000)))
+                elif tag == 0x0100:
+                    if value != 0:
+                        self.width = value
+                    else:
+                        self.width = offset
+                elif tag == 0x0101:
+                    if value != 0:
+                        self.height = value
+                    else:
+                        self.height = offset
+        else:
+            ImageInfo.add(file.name, self)
+            return
+            
+        if iptc:
+            self.setitem( 'title', iptc, 517 ) 
+            self.setitem( 'date' , iptc, 567 )
+            self.setitem( 'comment', iptc, 617 )
+            self.setitem( 'keywords', iptc, 537 )
+            self.setitem( 'artist', iptc, 592 )
+            self.setitem( 'country', iptc, 612 ) 
+            self.setitem( 'caption', iptc, 632 )
+            self.appendtable('IPTC', iptc)
+
+        ImageInfo.add(file.name, self)
+        return
+            
+
+mmpython.registertype( 'image/tiff', ('tif','tiff'), mediainfo.TYPE_IMAGE, TIFFInfo )
Index: trunk/src/testing/bin/fileServer/misc/mmpython/mediainfo.py
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/mediainfo.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/mediainfo.py	(revision 4)
@@ -0,0 +1,431 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mediainfo.py,v 1.68.2.1 2005/05/07 11:37:08 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: mediainfo.py,v $
+# Revision 1.68.2.1  2005/05/07 11:37:08  dischi
+# make sure all strings are unicode
+#
+# Revision 1.68  2005/04/16 15:01:15  dischi
+# convert exif tags to str
+#
+# Revision 1.67  2005/02/04 12:44:26  dischi
+# fix unicode bug
+#
+# Revision 1.66  2004/09/14 20:13:59  dischi
+# detect rar vobsub files
+#
+# Revision 1.65  2004/09/14 14:38:11  outlyer
+# Fix the broken 'less than' comparison so it is at least consistent, but I'm
+# not sure why we need to add zeroes to numbers anyway. It looks ugly for
+# albums with less than 10 tracks, and it seems unecessary since the
+# sort functions in Freevo add the '0' as needed.
+#
+# Revision 1.64  2004/09/10 19:43:12  outlyer
+# Added discs to exported dict.
+#
+# Revision 1.63  2004/05/29 12:30:36  dischi
+# add function to correct data from the different mime modules
+#
+# Revision 1.62  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.61  2004/05/27 08:59:50  dischi
+# fix chapters printing
+#
+# Revision 1.60  2004/05/20 15:55:08  dischi
+# add xml file detection
+#
+# Revision 1.59  2004/05/18 21:54:49  dischi
+# add chapter support
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+TYPE_NONE = 0
+TYPE_AUDIO = 1
+TYPE_VIDEO = 2
+TYPE_IMAGE = 4
+TYPE_AV = 5
+TYPE_MUSIC = 6
+TYPE_HYPERTEXT = 8
+TYPE_MISC = 10
+
+import string
+import types
+import table
+import traceback
+import locale
+
+import re
+import urllib
+import urlparse
+import os
+
+LOCAL_ENCODING = locale.getpreferredencoding();
+if not LOCAL_ENCODING or LOCAL_ENCODING == "ANSI_X3.4-1968":
+    LOCAL_ENCODING = 'latin1';
+
+MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
+             'date', 'keywords', 'country', 'language', 'url']
+
+AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
+             'bitrate', 'language']
+
+VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'samplebits',
+             'width', 'height', 'fps', 'aspect']
+
+IMAGECORE = ['description', 'people', 'location', 'event',
+             'width','height','thumbnail','software','hardware', 'dpi']
+
+MUSICCORE = ['trackno', 'trackof', 'album', 'genre','discs']
+
+AVCORE    = ['length', 'encoder', 'trackno', 'trackof', 'copyright', 'product',
+             'genre', 'secondary genre', 'subject', 'writer', 'producer', 
+             'cinematographer', 'production designer', 'edited by', 'costume designer',
+             'music by', 'studio', 'distributed by', 'rating', 'starring', 'ripped by',
+             'digitizing date', 'internet address', 'source form', 'medium', 'source',
+             'archival location', 'commisioned by', 'engineer', 'cropped', 'sharpness',
+             'dimensions', 'lightness', 'dots per inch', 'palette setting',
+             'default audio stream', 'logo url', 'watermark url', 'info url',
+             'banner image', 'banner url', 'infotext', 'delay']
+
+
+UNPRINTABLE_KEYS = [ 'thumbnail', ]
+
+import table
+import mmpython
+
+EXTENSION_DEVICE    = 'device'
+EXTENSION_DIRECTORY = 'directory'
+EXTENSION_STREAM    = 'stream'
+
+DEBUG = 0
+
+try:
+    DEBUG = int(os.environ['MMPYTHON_DEBUG'])
+except:
+    pass
+
+def _debug(text):
+    """
+    Function for debug prints of MediaItem implementations.
+    """
+    if DEBUG > 1:
+        try:
+            print text
+        except:
+            print text.encode('latin-1', 'replace')
+    
+
+class MediaInfo:
+    """
+    MediaInfo is the base class to all Media Metadata Containers. It defines the 
+    basic structures that handle metadata. MediaInfo and its derivates contain
+    a common set of metadata attributes that is listed in keys. Specific derivates
+    contain additional keys to the dublin core set that is defined in MediaInfo.
+    MediaInfo also contains tables of addional metadata. These tables are maps
+    of keys to values. The keys themselves should remain in the format that is
+    defined by the metadata (I.E. Hex-Numbers, FOURCC, ...) and will be translated
+    to more readable and i18nified values by an external entity.
+    """
+    def __init__(self):
+        self.keys = []
+        self._tables = {}
+        for k in MEDIACORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+    def __unicode__(self):
+        import copy
+        keys = copy.copy(self.keys)
+
+        for k in UNPRINTABLE_KEYS:
+            if k in keys:
+                keys.remove(k)
+
+        result = u''
+        result += reduce( lambda a,b: self[b] and b != u'url' and u'%s\n        %s: %s' % \
+                         (a, unicode(b), unicode(self[b])) or a, keys, u'' )
+        if DEBUG:
+            try:
+                for i in self._tables.keys():
+                    try:
+                        result += unicode(self._tables[i])
+                    except AttributeError:
+                        pass
+            except AttributeError:
+                pass
+        return result
+        
+
+    def appendtable(self, name, hashmap, language='en'):
+        """
+        Appends a tables of additional metadata to the Object. 
+        If such a table already exists, the given tables items are
+        added to the existing one.
+        """
+        if not self._tables.has_key((name, language)):
+            self._tables[(name, language)] = table.Table(hashmap, name, language)
+        else:
+            # Append to the already existing table
+            for k in hashmap.keys():
+                self._tables[(name, language)][k] = hashmap[k]
+    
+
+    def correct_data(self):
+        """
+        Correct same data based on specific rules
+        """
+        # make sure all strings are unicode
+        for key in self.keys:
+            value = getattr(self, key)
+            if isinstance(value, str):
+                setattr(self, key, unicode(value, LOCAL_ENCODING, 'replace'))
+
+
+    def gettable(self, name, language='en'):
+        """
+        returns a table of the given name and language        
+        """
+        return self._tables.get((name, language), {})
+    
+
+    def setitem(self, item, dict, key, convert_to_str=False):
+        """
+        set item to a specific value for the dict
+        """
+        try:
+            if self.__dict__.has_key(item):
+                if isinstance(dict[key], str):
+                    self.__dict__[item] = unicode(dict[key])
+                elif convert_to_str:
+                    self.__dict__[item] = unicode(dict[key])
+                else:
+                    self.__dict__[item] = dict[key]
+            else:
+                _debug("Unknown key: %s" % item)
+        except:
+            pass
+
+
+    def __getitem__(self,key):
+        """
+        get the value of 'key'
+        """
+        if self.__dict__.has_key(key):
+            if isinstance(self.__dict__[key], str):
+                return self.__dict__[key].strip().rstrip().replace('\0', '')
+            return self.__dict__[key]
+        elif hasattr(self, key):
+            return getattr(self, key)
+        return None
+
+        
+    def __setitem__(self, key, val):
+        """
+        set the value of 'key' to 'val'
+        """
+        self.__dict__[key] = val
+
+
+    def has_key(self, key):
+        """
+        check if the object has a key 'key'
+        """
+        return self.__dict__.has_key(key) or hasattr(self, key)
+
+
+    def __delitem__(self, key):
+        """
+        delete informations about 'key'
+        """
+        try:
+            del self.__dict__[key]
+        except:
+            pass
+        if hasattr(self, key):
+            setattr(self, key, None)
+
+        
+class AudioInfo(MediaInfo):
+    """
+    Audio Tracks in a Multiplexed Container.
+    """
+    def __init__(self):
+        self.keys = []
+        for k in AUDIOCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+class MusicInfo(AudioInfo):
+    """
+    Digital Music.
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        for k in AUDIOCORE+MUSICCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+    def correct_data(self):
+        """
+        correct trackof to be two digest
+        """
+        AudioInfo.correct_data(self)
+        if self['trackof']:
+            try:
+                # XXX Why is this needed anyway?
+                if int(self['trackno']) < 10:
+                    self['trackno'] = '0%s' % int(self['trackno'])
+            except:
+                pass
+
+            
+class VideoInfo(MediaInfo):
+    """
+    Video Tracks in a Multiplexed Container.
+    """
+    def __init__(self):
+        self.keys = []
+        for k in VIDEOCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+           
+
+class ChapterInfo(MediaInfo):
+    """
+    Chapter in a Multiplexed Container.
+    """
+    def __init__(self, name, pos=0):
+        self.keys = ['name', 'pos']
+        setattr(self,'name', name)
+        setattr(self,'pos', pos)
+           
+
+class AVInfo(MediaInfo):
+    """
+    Container for Audio and Video streams. This is the Container Type for
+    all media, that contain more than one stream. 
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        for k in AVCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+        self.audio = []
+        self.video = []
+        self.subtitles = []
+        self.chapters  = []
+
+
+    def correct_data(self):
+        """
+        correct length to be an int
+        """
+        MediaInfo.correct_data(self)
+        if not self['length'] and len(self.video) and self.video[0]['length']:
+            self['length'] = self.video[0]['length']
+        for container in [ self ] + self.video + self.audio:
+            if container['length']:
+                container['length'] = int(container['length'])
+            
+                                 
+    def find_subtitles(self, filename):
+        """
+        Search for subtitle files. Right now only VobSub is supported
+        """
+        base = os.path.splitext(filename)[0]
+        if os.path.isfile(base+'.idx') and \
+               (os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
+            file = open(base+'.idx')
+            if file.readline().find('VobSub index file') > 0:
+                line = file.readline()
+                while (line):
+                    if line.find('id') == 0:
+                        self.subtitles.append(line[4:6])
+                    line = file.readline()
+            file.close()
+
+            
+    def __unicode__(self):
+        result = u'Attributes:'
+        result += MediaInfo.__unicode__(self)
+        if len(self.video) + len(self.audio) + len(self.subtitles) > 0:
+            result += "\n Stream list:"
+            if len(self.video):
+                result += reduce( lambda a,b: a + u'  \n   Video Stream:' + unicode(b),
+                                  self.video, u'' )
+            if len(self.audio):
+                result += reduce( lambda a,b: a + u'  \n   Audio Stream:' + unicode(b),
+                                  self.audio, u'' )
+            if len(self.subtitles):
+                result += reduce( lambda a,b: a + u'  \n   Subtitle Stream:' + unicode(b),
+                                  self.subtitles, u'' )
+        if not isinstance(self.chapters, int) and len(self.chapters) > 0:
+            result += u'\n Chapter list:'
+            for i in range(len(self.chapters)):
+                result += u'\n   %2s: "%s" %s' % (i+1, unicode(self.chapters[i]['name']),
+                                                  self.chapters[i]['pos'])
+        return result
+
+        
+class ImageInfo(MediaInfo):
+    """
+    Digital Images, Photos, Pictures.
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)        
+        for k in IMAGECORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+class CollectionInfo(MediaInfo):
+    """
+    Collection of Digial Media like CD, DVD, Directory, Playlist
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        self.tracks = []
+        self.keys.append('id')
+        self.id = None
+
+    def __unicode__(self):
+        result = MediaInfo.__unicode__(self)
+        result += u'\nTrack list:'
+        for counter in range(0,len(self.tracks)):
+             result += u' \nTrack %d:\n%s' % (counter+1, unicode(self.tracks[counter]))
+        return result
+    
+    def appendtrack(self, track):
+        self.tracks.append(track)
+
+
+def get_singleton():
+    print "This function is deprecated. Please use 'mmpython.Factory' instead."
+    return mmpython.Factory()
+
+    
Index: trunk/src/testing/bin/fileServer/misc/mmpython/mminfo
===================================================================
--- trunk/src/testing/bin/fileServer/misc/mmpython/mminfo	(revision 4)
+++ trunk/src/testing/bin/fileServer/misc/mmpython/mminfo	(revision 4)
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mminfo,v 1.4 2004/05/28 12:26:24 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: mminfo,v $
+# Revision 1.4  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.3  2004/05/24 12:54:35  dischi
+# debug update
+#
+# Revision 1.2  2004/05/17 19:10:57  dischi
+# better DEBUG handling
+#
+# Revision 1.1  2004/05/17 19:00:58  dischi
+# rename mediatest.py to mminfo and install it as script to bin
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+import sys
+import os
+
+# add .. for source usage
+sys.path = ['..'] + sys.path
+
+
+print 'mmpython media info'
+
+if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help'):
+    print
+    print 'usage: mminfo [options] files'
+    print
+    print 'options:'
+    print '  -d   turn on debug information. For complete debug set -d 2'
+    print
+    print 'A file can be a normal file, a device for VCD/VCD/AudioCD'
+    print
+    print 'Examples:'
+    print '  mminfo foo.avi bar.mpg'
+    print '  mminfo /dev/dvd'
+    print
+    sys.exit(0)
+
+# turn on debug
+if sys.argv[1] == '-d':
+    try:
+        int(sys.argv[2])
+        os.environ['MMPYTHON_DEBUG'] = sys.argv[2]
+        sys.argv = sys.argv[2:]
+    except:
+        os.environ['MMPYTHON_DEBUG'] = '1'
+        sys.argv = sys.argv[1:]
+    
+from mmpython import *
+
+for file in sys.argv[1:]:
+    medium = parse(file)
+    print
+    if len(file) > 70:
+        print "filename : %s[...]%s" % (file[:30], file[len(file)-30:])
+    else:
+        print "filename : %s" % file
+    if medium:
+        print unicode(medium).encode('latin-1', 'replace')
+        print
+        print
+    else:
+        print "No Match found"
Index: trunk/src/testing/bin/fileServer/fileServer.py
===================================================================
--- trunk/src/testing/bin/fileServer/fileServer.py	(revision 4)
+++ trunk/src/testing/bin/fileServer/fileServer.py	(revision 4)
@@ -0,0 +1,829 @@
+#!/usr/bin/env python
+############################################################################
+#
+# -= FileViewer =-
+#
+# FileServer - receives, provides and organizes multimedia files for use with SAGE
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about FileViewer to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+ 
+import os, base64, os.path, socket, shutil, sys, SocketServer, wx, stat, urllib
+from SimpleXMLRPCServer import *
+from threading import Thread
+from time import asctime, time
+import makeThumbs
+
+# miscellaneous stuff (3rd party supporting tools)
+sys.path.append("misc")  #so that we can import packages from "misc" folder
+from imsize import imagesize  # reads the image header and gets the size from it
+import mmpython
+import countPDFpages
+
+# a shortcut
+opj = os.path.join
+
+# for loading the sagePath helper file
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath, getPath
+
+
+## some globals defining the environment
+SCRIPT_PATH = sys.path[0]
+CONFIG_FILE = getPath("fileServer", "fileServer.conf")
+CACHE_DIR = getUserPath("fileServer", "file_server_cache")
+FILES_DIR = opj(SCRIPT_PATH, "file_library")
+REDIRECT = False
+THUMB_DIR = opj(FILES_DIR, "thumbnails")
+RUN_SERVER = True
+
+## holds information about the types that we support (read from the config file)
+dirHash = {}
+viewers = {}
+types = {}
+
+
+def ParseConfigFile():
+    global FILES_DIR
+    global THUMB_DIR
+    global dirHash
+    global types
+    global viewers
+
+    # reinitialize everything
+    FILES_DIR = ""
+    THUMB_DIR = ""
+    dirHash = {}
+    types = {}
+    viewers = {}
+
+    # read the config file
+    f = open(CONFIG_FILE, "r")
+    for line in f:
+        line = line.strip()
+        if line.startswith("FILES_DIR"):
+            FILES_DIR = line.split("=")[1].strip()
+            if not os.path.isabs(FILES_DIR):
+                FILES_DIR = getUserPath("fileServer", FILES_DIR)
+            FILES_DIR = os.path.realpath(FILES_DIR)  #expand any symbolic links in the library directory
+            THUMB_DIR = opj(FILES_DIR, "thumbnails")
+        elif line.startswith("type:"):
+            line = line.split(":",1)[1]
+            (type, extensions) = line.split("=")
+            types[type.strip()] = extensions.strip().split(" ")
+            dirHash[type.strip()] = opj(FILES_DIR, type.strip())
+        elif line.startswith("app:"):
+            line = line.split(":", 1)[1].strip()
+            (type, app) = line.split("=")
+            tpl = app.strip().split(" ", 1)
+            if len(tpl) == 1:  params = ""
+            else:  params = tpl[1].strip()
+            app = tpl[0].strip()
+            viewers[type.strip()] = (app, params)
+    f.close()
+
+
+    # create the folders first if they dont exist
+    if not os.path.isdir(FILES_DIR):
+        os.makedirs(FILES_DIR)
+    if not os.path.isdir(CACHE_DIR):
+        os.makedirs(CACHE_DIR)
+    for type, typeDir in dirHash.items():
+        if not os.path.isdir( ConvertPath(typeDir) ):
+            os.makedirs(typeDir)
+        if not os.path.isdir( ConvertPath( opj(typeDir, "Trash")) ):
+            os.makedirs( opj(typeDir, "Trash") )
+    if not os.path.isdir(THUMB_DIR):
+        os.makedirs(THUMB_DIR)
+
+
+
+# convert the path between the systems (Windows vs. Linux/Mac)
+def ConvertPath(path):
+    return apply(opj, tuple(path.split('\\')))
+
+
+
+
+
+import traceback as tb
+from SocketServer import ThreadingTCPServer, StreamRequestHandler
+
+
+
+class Listener(ThreadingTCPServer):
+    """ the main server listening for connections from HWCapture """
+    
+    allow_reuse_address = True
+    request_queue_size = 2
+    
+    def __init__(self, port, onMsgCallback, fileServer):
+        self.onMsgCallback = onMsgCallback
+        self.fileServer = fileServer
+        ThreadingTCPServer.__init__(self, ('', int(port)), SingleFileUpload)
+        self.socket.settimeout(0.5)
+
+
+    def serve_forever(self):
+        while RUN_SERVER:
+            try:
+                self.handle_request()
+            except socket.timeout:
+                pass
+            except KeyboardInterrupt:
+                break
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                break
+ 
+
+class SingleFileUpload(StreamRequestHandler):      
+    """ one of these per file upload """
+
+    
+    def handle(self):
+        """ this is where we parse the incoming messages """
+        self.request.settimeout(0.5)  # so that we can quit properly
+
+        # read the header
+        header = self.rfile.readline().strip()
+        if len(header) == 0:
+            return
+        (fileName, previewWidth, previewHeight, fileSize) = header.strip().split()
+        previewSize = (int(previewWidth), int(previewHeight))
+        fileSize = int(fileSize)
+        
+        # make sure the filename is ok
+        fileName = os.path.basename(fileName)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.server.fileServer.GetFileType(fileName)
+        if not fileType:
+            return #dont allow upload of anything that doesn't have an extension
+        
+        # make the file
+        fullPath = opj(dirHash[fileType], fileName)
+        try:
+            f=open(fullPath, "wb")
+        except:
+            WriteLog("Cannot create file (have write permissions?):" + filePath)
+            return
+
+        bytesRead = 0
+        while RUN_SERVER and bytesRead < fileSize:
+            try:
+                line = self.rfile.readline()
+                if not line:   # readline doesn't fail when socket is closed... it returns an empty string
+                    f.close()
+                    os.remove(fullPath)
+                    break
+                    
+                bytesRead+=len(line)
+                if bytesRead > fileSize:
+                    line = line.rstrip()   # remove the newline char at the end of transmission
+                f.write(line)
+                
+            except socket.timeout:
+                continue
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                f.close()
+                os.remove(fullPath)
+                break
+        else:
+            f.flush()
+            f.close()
+
+            # tell the client that all went well
+            self.wfile.write("1")  
+            
+            # make the preview if necessary and everything went well
+            self.server.onMsgCallback(fileName, previewSize)
+
+
+
+
+
+
+
+
+class FileLibrary:
+    def __init__(self):
+        ParseConfigFile()
+
+        # start the server that will accept the file data
+        self.fServer = Listener(8802, self.__MakePreview, self)
+        fServerThread = Thread(target=self.fServer.serve_forever)
+        fServerThread.start()
+
+
+        ### used by clients to test the connection with the server
+    def TestConnection(self):
+        return (FILES_DIR, 0)
+
+
+         ### gets the file info:
+        ### full path, file type, application info, size (for images...), file size
+    def GetFileInfo(self, filename, fileSize=-1, path=None):
+        try:
+            ParseConfigFile()
+            fileType = self.GetFileType(filename)
+            size = (-1, -1)
+            fileExists = False
+
+            if fileType:  #is file even supported
+                appName = viewers[fileType][0]
+                params = viewers[fileType][1]
+                if path == None:  # the user dropped a new file on there
+                    fullPath = opj(self.__GetFilePath(fileType), filename)  # return a default path if not passed in
+                    res = self.__FileAlreadyThere(filename, fileType, fileSize)
+                    if res:  #if the file was found it will return its directory
+                        if fileType == "image":   #if the file is an image, return its size
+                            try:
+                                imsize = imagesize(fullPath)
+                                size = (imsize[1], imsize[0])
+                            except:
+                                size = (-1,-1)
+
+                        fullPath = opj(res, filename)  #the path of the found file
+                        fileExists = True
+                        
+                elif not self.__LegalPath(path):
+                    return False
+                else:             # the user is trying to show an existing file
+                    path = ConvertPath(path)
+                    fullPath = opj(path, filename)
+                    ## get the image size... FIX later (remove)
+                    if os.path.isfile(fullPath):
+                        fileExists = True
+                        if fileType == "image":   #if the file is an image, return its size
+                            try:
+                                imsize = imagesize(fullPath)
+                                size = (imsize[1], imsize[0])
+                            except:
+                                size = (-1,-1)
+                return (fileType, size, fullPath, appName, params, fileExists) 
+            else:
+                return False  #file type not supported
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### gets the metadata information about the file
+    def GetMetadata(self, fullPath):
+        fullPath = ConvertPath(fullPath)
+        if not self.__LegalPath(fullPath):
+            return False
+
+        try:
+            fileType = self.GetFileType(fullPath)
+            if not fileType:
+                return False
+            elif fileType == "pdf":    # for pdfs
+                return "Pages: "+str(countPDFpages.getPDFPageCount(fullPath))
+            else:                      # for all other types
+                metadata = mmpython.parse(fullPath)
+                if metadata:   # metadata extracted successfully
+                    return unicode(metadata).encode('latin-1', 'replace')
+                else:
+                    return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return False
+        
+
+        ### construct a hash of all the files keyed by the directory in which the files
+        ### are and return it
+    def GetFiles(self):
+        ParseConfigFile()
+        numDirs = 0
+        numFiles = 0
+        
+        fileHash = {}
+        for fileType in dirHash.iterkeys():
+            fileHash[fileType] = self.__TraverseDir( self.__GetFilePath(fileType), fileType )
+        return fileHash
+    
+
+        ### deletes a folder and all files and dirs in it
+    # FIX to delete the thumbnails for all the images in this folder
+    def DeleteFolder(self, fullPath):
+        try:
+            if self.__LegalPath(fullPath):  # prevent users from deleting anything
+                shutil.rmtree(ConvertPath(fullPath))
+                return True
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### makes a new folder
+    def NewFolder(self, fullPath):
+        try:
+            if self.__LegalPath(fullPath):  # prevent users from deleting anything
+                os.mkdir(ConvertPath(fullPath))
+                self.__SetWritePermissions(ConvertPath(fullPath))
+                return True
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### move the file to Trash
+    def DeleteFile(self, fullPath):
+        try:
+            fullPath = ConvertPath(fullPath)
+            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
+                return False
+            fileType = self.GetFileType(fullPath)
+            if not fileType:  # no extension so don't allow deletion
+                return False
+
+            trashPath = opj( opj(self.__GetFilePath(fileType), "Trash"), os.path.split(fullPath)[1] )
+            self.MoveFile( fullPath, trashPath )
+            return True
+        
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### deletes the file from the library (also deletes it's thumbnail preview if it exists)
+    def DeleteFilePermanently(self, fullPath):
+        try:
+            fullPath = ConvertPath(fullPath)
+            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
+                return False
+            fileType = self.GetFileType(fullPath)
+            if not fileType:  # no extension so don't allow deletion
+                return False
+
+            previewPath = self.__GetPreviewName(fullPath)
+            if os.path.isfile(fullPath): # prevent users from deleting anything 
+                os.remove( fullPath )      #remove the file itself
+                dxtFilePath = fullPath.rstrip(os.path.splitext(fullPath)[1])+".dxt"
+                if os.path.isfile(dxtFilePath):
+                    os.remove( dxtFilePath )  # remove the dxt file if it exists
+            if os.path.isfile( previewPath ):
+                os.remove( previewPath )  #remove its preview thumbnail
+            return True
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### moves the file from one directory to another
+    def MoveFile(self, oldFullPath, newFullPath):
+        oldFullPath = ConvertPath(oldFullPath)
+        newFullPath = ConvertPath(newFullPath)
+        if not self.__LegalPath(oldFullPath, newFullPath):  # restrict the movement to the FILES_DIR
+            return False
+        if os.path.isfile(oldFullPath):
+            try:
+                shutil.move(oldFullPath, newFullPath)
+                oldDxtFilePath = oldFullPath.rstrip(os.path.splitext(oldFullPath)[1])+".dxt"
+                newDxtFilePath = newFullPath.rstrip(os.path.splitext(newFullPath)[1])+".dxt"
+                if os.path.isfile(oldDxtFilePath):
+                    shutil.move(oldDxtFilePath, newDxtFilePath)
+                return True
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                return False
+        else:
+            return False
+
+
+        ### accepts a file encoded as a base64 string and puts it in
+        ### the default directory for that file type
+    def UploadFile(self, name, data, previewSize=(150, 150)):
+        name = os.path.basename(name)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.GetFileType(name)
+        if not fileType:
+            return False  #dont allow upload of anything that doesn't have an extension
+        try:
+            # write the file
+            f=open( opj(dirHash[fileType], name), "wb")
+            f.write( base64.decodestring(data) )
+            f.close()
+            del data
+
+            self.__MakePreview(name, previewSize)
+
+            return True
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+    def UploadLink(self, url):
+        name = os.path.basename(url)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.GetFileType(name)
+        if not fileType:
+            return False  #dont allow upload of anything that doesn't have an extension
+
+        try:
+            filename, headers = urllib.urlretrieve(url, opj(dirHash[fileType], name))
+            return True
+        except:
+            return False
+        
+
+        ### looks if there is a preview already saved... if not, create one and send it back
+    def GetPreview(self, fullPath, previewSize=(150,150)):
+        try:
+            res = self.MakeThumbnail(fullPath)
+            if res:
+                return (self.__ReadFile(res), True)
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+        
+##         fullPath = ConvertPath(fullPath)
+##         if not self.__LegalPath(fullPath):
+##             return False
+##         fileType = self.GetFileType(fullPath)
+
+##         try:
+##             if fileType != "image" or not os.path.isfile(fullPath):
+##                 return False
+##             previewPath = self.__GetPreviewName(fullPath)
+##             wxImageType = self.__GetWxBitmapType(os.path.basename(fullPath))
+##             if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it 
+##                 if wxImageType:               # is writing this file type supported?
+##                     im = wx.Image(fullPath)  # read the original image
+##                     if not im.Ok():   
+##                         return False         # the image is probably corrupted
+##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
+##                     im.SaveFile(previewPath, wxImageType)    # save it back to a file
+##                     self.__SetWritePermissions(previewPath)
+##                 else:     #if writing is not supported, try and read it and resize it on the fly
+##                     im = wx.Image(fullPath)  # read the original image
+##                     if not im.Ok():   
+##                         return False         # the image is probably corrupted
+##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
+##                     data = preview.GetData()
+##                     return (base64.encodestring(data), False)   #return the pixels themselves (isBinary=False)
+            
+##             return (self.__ReadFile(previewPath), True)
+##         except:
+##             WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+##             return False
+
+
+    def MakeThumbnail(self, fullPath):
+        fullPath = ConvertPath(fullPath)
+        if not self.__LegalPath(fullPath):
+            return False
+        fileType = self.GetFileType(fullPath)
+        
+        try:
+            if not os.path.isfile(fullPath):
+                return False
+
+            previewPath = self.__GetPreviewName(fullPath)
+            if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it
+                makeThumbs.makeThumbnail(fullPath, fileType, previewPath)
+                if not os.path.isfile(previewPath):
+                    return False
+                
+            return previewPath
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]))
+            return False
+
+
+
+        ### get the file ready for loading by the app on the "host" machine
+    def PrepareFile(self, fullPath, host):
+        if not self.__LegalPath(fullPath):
+            return False
+        
+        # make the connection with the remote FileServer
+        fileServer = xmlrpclib.ServerProxy("http://"+str(host)+":8800")
+
+        try:
+            # if the file exists already, there's no need to transfer it 
+            filePath = fileServer.FileExists(fullPath, os.stat(fullPath).st_size)
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+        if filePath:
+            return filePath  # if the file is already cached, just send the path back
+        else:
+            try:
+                # file is not cached so read it and send it to the remote FileServer
+                fileData = self.__ReadFile(fullPath)
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                return False
+            else:
+                return fileServer.PutFile(os.path.basename(fullPath), fileData)
+ 
+
+        ### gets the extension of the file that was passed in
+    def GetFileType(self, thefile):
+        try:
+            filename = os.path.basename( thefile )
+            extension = os.path.splitext(filename)[1].lower()
+            fileType = False
+            for fType in types.iterkeys():
+                    if extension in types[ fType ]:
+                        fileType = fType
+            return fileType
+        except:
+            return False
+        
+
+        ### does file exist in the cache already?? if not, someone will have to send it here
+    def FileExists(self, fullPath, size):
+        fullPath = ConvertPath(fullPath)
+        if os.path.isfile(fullPath):  # if the file server is on the same machine then we can 
+            return fullPath           # just read the file directly from the file_library
+        filename = "_".join(os.path.basename(fullPath).split())
+        if filename == "":  # if it's a directory
+            return False
+        path = os.path.abspath( opj(CACHE_DIR, filename) )
+        if os.path.isfile(path) and os.stat(path).st_size==size:  #compare the sizes as well
+            return path
+        else:
+            return False
+
+
+        ### called by the remote FileServer to upload the file 
+    def PutFile(self, filename, data):
+        try:
+            filename = "_".join(os.path.basename(filename).split()) # strip the directory and keep just the name (security reasons)
+            if filename == "":
+                return False
+            f=open( opj(CACHE_DIR, filename), "wb")
+            f.write( base64.decodestring(data) )
+            f.close()
+            self.__SetWritePermissions(opj(CACHE_DIR, filename))
+
+            del data
+            return os.path.abspath( opj(CACHE_DIR, filename) )  #return the path of the file to be passed to the app
+        except:
+            del data
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### so that the server can be quit remotely
+    def Quit(self, var):
+        global RUN_SERVER
+        RUN_SERVER = False
+        return 1
+
+
+
+        
+
+#=======================================#
+########    Auxiliary methods    ########
+
+
+        ### constructs the preview name from the filename
+        ### preview name is: filename+fileSize+original_extension
+        ### (such as trees56893.jpg where 56893 is file size in bytes)
+    def __GetPreviewName(self, fullPath):
+        fileType = self.GetFileType(fullPath)
+
+        fileSize = os.stat(fullPath).st_size
+        (root, ext) = os.path.splitext( os.path.basename(fullPath) )
+        previewName = root+str(fileSize)+ext        #construct the preview name
+
+        # all the files have .jpg tacked onto the end
+        previewName += ".jpg"
+            
+        return opj( THUMB_DIR, previewName )
+
+
+    def __MakePreview(self, name, previewSize):
+        try:
+            wxImageType = self.__GetWxBitmapType(name)
+            if wxImageType:     # some types just cant be saved by wxPython
+                fileType = self.GetFileType(name)
+                # write the preview but name it with a filename and filesize so that they are unique
+                previewPath = self.__GetPreviewName(opj(dirHash[fileType], name))
+                im = wx.Image(opj(dirHash[fileType], name))  # read the original image
+
+                if im.Ok():  #the image may be corrupted...
+                    im.Rescale(previewSize[0], previewSize[1])        # resize it
+                    im.SaveFile(previewPath, wxImageType)    # save it back to a file
+                self.__SetWritePermissions(previewPath, opj(dirHash[fileType], name))
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            pass    # no preview was saved... oh well
+
+
+
+        ### change the permission of the settings file to allow everyone to write to it
+    def __SetWritePermissions(self, *files):
+        for filePath in files:
+            try:
+                flags = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP | stat.S_IROTH
+                os.chmod(filePath, flags)
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                
+        
+        ### reads a file and encodes it in a string (for transfer over the network)
+    def __ReadFile(self, fullPath):
+        f = open(fullPath, "rb")
+        fileData = base64.encodestring( f.read() )
+        f.close()
+        return fileData
+
+
+        ### looks through all the files of the same type 
+        ### and figures out if the files is already there (optionally compare the file sizes as well)
+        ### if the same file is found, it will return its path
+    def __FileAlreadyThere(self, filename, fileType, size):
+        dirPath = self.__GetFilePath(fileType)
+        fileDir = False
+        
+        def LookForFile(dirPath, fileType, fileDir):
+            if fileDir:
+                return fileDir  #this will prevent the recursion to go on if we found a file (base case)
+            dirPath = ConvertPath(dirPath)
+            items = os.listdir(dirPath)
+            files = []
+            dirs = {}
+            for item in items:   #loop through all the items in this directory (files or dirs)
+                if os.path.isfile( opj(dirPath, item) ):  #is it a file
+                    if item.lower() == filename.lower():  #are their filenames equal
+                        if size==-1 or size==os.stat(opj(dirPath, item)).st_size:
+                            fileDir = dirPath
+                            return dirPath
+                elif os.path.isdir( opj(dirPath, item) ):  #is it a directory
+                    LookForFile( opj(dirPath, item), fileType, fileDir)  #if so, search in it
+            return False
+
+        return LookForFile(dirPath, fileType, fileDir)
+
+
+       ### recursively traverses the given directory
+       ### it return a tuple of (dir-path, list-of-dirs, files)
+    def __TraverseDir(self, dirPath, fileType):
+        dirPath = ConvertPath(dirPath)
+        items = os.listdir(dirPath)
+        files = []
+        dirs = {}
+        for item in items:
+            if os.path.isfile( opj(dirPath, item) ):
+                if self.GetFileType(item):  #if the file is supported, add it to the list, otherwise disregard it
+                    files.append(item)
+            elif os.path.isdir( opj(dirPath, item) ):
+                dirs[item] = self.__TraverseDir( opj(dirPath, item), fileType )
+        return (dirPath, dirs, files, fileType)
+
+
+       ### you pass it in a filename and it figures out the wx.BITMAP_TYPE and returns it
+    def __GetWxBitmapType(self, name):
+        ext = os.path.splitext(name)[1]
+        ext = ext.lower()
+        if ext==".jpg": return wx.BITMAP_TYPE_JPEG
+        elif ext==".png": return wx.BITMAP_TYPE_PNG
+        elif ext==".gif": return wx.BITMAP_TYPE_GIF
+        elif ext==".bmp": return wx.BITMAP_TYPE_BMP
+        elif ext==".pcx": return wx.BITMAP_TYPE_PCX
+        elif ext==".pnm": return wx.BITMAP_TYPE_PNM
+        elif ext==".tif": return wx.BITMAP_TYPE_TIF
+        elif ext==".tiff": return wx.BITMAP_TYPE_TIF
+        elif ext==".xpm": return wx.BITMAP_TYPE_XPM
+        elif ext==".ico": return wx.BITMAP_TYPE_ICO
+        elif ext==".cur": return wx.BITMAP_TYPE_CUR
+        else:
+            return False
+
+
+        ### gets the default path for a certain file type
+    def __GetFilePath(self, type=None):
+        if type == None:
+            return FILES_DIR 
+        else:
+            return dirHash[type]
+
+
+
+        ### Checks whether all the paths are still within FILES_DIR (for security issues)
+    def __LegalPath(self, *pathList):
+        try:
+            normedPathList = []
+            normedPathList.append(FILES_DIR)
+            for path in pathList:
+                if path != "":
+                    normedPathList.append( os.path.normpath( os.path.realpath(path) ) )  # normalize all the paths (remove ../ kinda stuff)
+            return (os.path.commonprefix(normedPathList) == FILES_DIR)
+        except:
+            return False   #if anything fails, it's safer to assume that it's an illegal action
+
+
+    def __IsFolder(self, fullPath):
+        return (os.path.splitext(fullPath)[1] == '')
+    
+
+
+
+# to output all the error messages to a file
+def WriteLog(message):
+    try:
+        print message
+    except:
+        pass
+
+
+
+
+
+
+# a mix-in class for adding the threading support to the XMLRPC server
+class ThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
+    allow_reuse_address = True
+
+
+    # so that we can quit the server properly
+class MyServer(ThreadedXMLRPCServer):
+    def serve_forever(self):
+	while RUN_SERVER:
+	    self.handle_request()
+    
+    
+
+
+def main(argv):
+
+    ## global REDIRECT    
+##     if len(argv) > 2:
+##         if "-v" in argv: 
+##             REDIRECT = False
+##         else:
+
+##             # redirect all the output to nothing
+##             class dummyStream:
+##                 ''' dummyStream behaves like a stream but does nothing. '''
+##                 def __init__(self): pass
+##                 def write(self,data): pass
+##                 def read(self,data): pass
+##                 def flush(self): pass
+##                 def close(self): pass
+##             # and now redirect all default streams to this dummyStream:
+##             sys.stdout = dummyStream()
+##             sys.stderr = dummyStream()
+##             sys.stdin = dummyStream()
+##             sys.__stdout__ = dummyStream()
+##             sys.__stderr__ = dummyStream()
+##             sys.__stdin__ = dummyStream()
+
+
+    wx.InitAllImageHandlers()
+
+    # start the XMLRPC server
+    server = MyServer(("", 8800), SimpleXMLRPCRequestHandler, logRequests=False)
+    server.register_instance(FileLibrary())
+    server.serve_forever()
+
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
+    
Index: trunk/src/testing/bin/ips.sys
===================================================================
--- trunk/src/testing/bin/ips.sys	(revision 4)
+++ trunk/src/testing/bin/ips.sys	(revision 4)
@@ -0,0 +1,1 @@
+67.58.62.100
Index: trunk/src/testing/dim/hwcapture.py
===================================================================
--- trunk/src/testing/dim/hwcapture.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture.py	(revision 4)
@@ -0,0 +1,168 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import socket, time
+from threading import Thread
+import traceback as tb
+
+
+# some globals
+
+thisMachine = socket.gethostbyname(socket.gethostname())
+TIMEOUT_INTERVAL = 3    # seconds
+
+
+
+
+class ManagerConnection:
+    """ This should be imported by the hwcapture code and
+        used to send the data to the device manager
+    """
+    
+    def __init__(self, host, port=20005):
+        #self.connections = {}   # key=host, value=OneConnection object
+        self.conn = OneConnection(host, port, doReconnect=True)
+        
+
+##     def newConnection(self, host, port):
+##         # make the initial connection to the manager we specify
+        
+##         conn = OneConnection(host, port)
+##         if host in self.connections:
+##             self.connections[host].disconnect()
+##             del self.connections[host]
+##         self.connections[host] = conn
+##         conn.start()
+        
+
+    def sendMessage(self, deviceName, deviceType, data):
+        """ - deviceName can be anything but it needs to be unique to this machine
+            (for example: mouse1)
+        """
+        deviceId = thisMachine+str(deviceName)
+        msg = deviceId + " " + deviceType + " " + data + "\n"
+        self.conn.sendMessage(msg)
+        
+
+
+
+
+
+
+class OneConnection:
+    """ This is just one connection to the device manager """
+    
+    def __init__(self, host, port, doReconnect):
+        self.doReconnect = doReconnect
+        self.host = host
+        self.port = port
+        self.connected = False
+
+        # connect thread that's constantly running
+        self.connThread = Thread(target=self.connectThread)
+        self.connThread.start()
+    
+
+    def connectThread(self):
+        while True:
+            
+            if not self.connected:
+                # set up the socket
+                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.sock.settimeout(TIMEOUT_INTERVAL)
+
+                # try connecting now
+                try:
+                    self.sock.connect(self.host, self.port)
+
+                    # connection successful so start the receiving thread
+                    self.connected = True
+                    ## self.receiverThread = Thread(target=self.receiver)
+##                     self.receiverThread.start()
+                    
+                except socket.error:
+                    print "failed to connect to: ", (self.host, self.port)
+                    if not self.doReconnect:
+                        break   # one time connections should only connect once
+                    time.sleep(4)  # try reconnecting every 4 seconds
+                                    
+            elif self.doReconnect:    # we are currently connected and we want to reconnect if connection breaks
+                time.sleep(2)  # don't loop like crazy if we are connected already
+
+            else:   # we are connected but we don't want to reconnect if connection breaks
+                break
+            
+
+    def disconnect(self):
+        self.connected = False
+        self.sock.close()
+
+
+    def sendMessage(self, msg):
+        """ try to send the message. Return False if not sent, True otherwise """
+        if not self.connected:  return False
+
+        try:
+            self.sock.sendall(msg)
+        except socket.error:
+            print "unable to send message... socket error"
+            self.disconnect()
+            return False
+        except:
+            tb.print_exc()
+            return False
+            
+        return True
+
+
+    def __sendPing(self):
+        self.sendMessage(" \n")
+            
+
+   ##  def receiver(self):
+##         """ in separate thread """
+        
+##         while self.connected:
+
+##             try:
+                
+##             except socket.timeout:
+##                 self.__sendPing()
+##                 continue
Index: trunk/src/testing/dim/events.py
===================================================================
--- trunk/src/testing/dim/events.py	(revision 4)
+++ trunk/src/testing/dim/events.py	(revision 4)
@@ -0,0 +1,258 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from globals import *
+
+
+
+
+class Event:
+    """ the base class for all the events """
+    
+    def __init__(self, eventId, eventType, toEvtHandler=None):
+        self.eventType = eventType
+        self.eventId = eventId
+        self.toEvtHandler = toEvtHandler
+
+        
+
+#-----------------------------------------------------
+#       DEVICE EVENTS (position dependent)
+#-----------------------------------------------------
+
+
+class MoveEvent(Event):
+    
+    def __init__(self, device, newX, newY, dX, dY, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_MOVE_SPECIAL
+        else:
+            evtId = EVT_MOVE
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.x = newX
+        self.y = newY
+        self.dX = dX
+        self.dY = dY
+
+
+class ClickEvent(Event):
+    
+    def __init__(self, device, x, y, btnId, isDown, forEvt, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_CLICK_SPECIAL
+        else:
+            evtId = EVT_CLICK
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.x = x
+        self.y = y
+        self.btnId = btnId
+        self.isDown = isDown
+        self.forEvt = forEvt
+
+
+class Analog1Event(Event):
+
+    def __init__(self, device, x, y, dX, dY, dZ, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_ANALOG1_SPECIAL
+        else:
+            evtId = EVT_ANALOG1
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.x = x
+        self.y = y
+        self.dX = dX
+        self.dY = dY
+        self.dZ = dZ
+
+
+class Analog2Event(Event):
+
+    def __init__(self, device, x, y, dX, dY, dZ, angle, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_ANALOG2_SPECIAL
+        else:
+            evtId = EVT_ANALOG2
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.x = x
+        self.y = y
+        self.dX = dX
+        self.dY = dY
+        self.dZ = dZ
+        self.angle = angle
+
+
+class Analog3Event(Event):
+
+    def __init__(self, device, x, y, dX, dY, dZ, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_ANALOG3_SPECIAL
+        else:
+            evtId = EVT_ANALOG3
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.x = x
+        self.y = y
+        self.dX = dX
+        self.dY = dY
+        self.dZ = dZ
+
+
+class ArrowEvent(Event):
+
+    def __init__(self, device, arrow, x, y, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_ARROW_SPECIAL
+        else:
+            evtId = EVT_ARROW
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.arrow = arrow
+        self.x = x
+        self.y = y
+
+
+class KeyEvent(Event):
+
+    def __init__(self, device, key, x, y, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_KEY_SPECIAL
+        else:
+            evtId = EVT_KEY
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.key = key
+        self.x = x
+        self.y = y
+
+
+class CustomEvent(Event):
+
+    def __init__(self, device, data, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_CUSTOM_SPECIAL
+        else:
+            evtId = EVT_CUSTOM
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+        self.data = data
+
+
+class WindowEnteredEvent(Event):
+
+    def __init__(self, device, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_ENTERED_WINDOW_SPECIAL
+        else:
+            evtId = EVT_ENTERED_WINDOW
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+
+
+class WindowLeftEvent(Event):
+
+    def __init__(self, device, toEvtHandler=None):
+        if device.specialDevice:
+            evtId = EVT_LEFT_WINDOW_SPECIAL
+        else:
+            evtId = EVT_LEFT_WINDOW
+        Event.__init__(self, evtId, DEVICE_EVENT, toEvtHandler)
+        self.device = device
+
+
+
+#----------------------------------------------------------
+#       GENERIC EVENTS (all who register for it receive it)
+#----------------------------------------------------------
+
+
+class AppInfoEvent(Event):
+
+    def __init__(self, sageApp):
+        Event.__init__(self, EVT_APP_INFO, GENERIC_EVENT)
+        self.app = sageApp
+        
+
+class NewAppEvent(Event):
+
+    def __init__(self, sageApp):
+        Event.__init__(self, EVT_NEW_APP, GENERIC_EVENT)
+        self.app = sageApp
+
+
+class PerfInfoEvent(Event):
+
+    def __init__(self, data):
+        Event.__init__(self, EVT_PERF_INFO, GENERIC_EVENT)
+#        tokens = string.split(data)
+        # FIX - ie complete
+
+
+class DisplayInfoEvent(Event):
+
+    def __init__(self, dispInfo):
+        Event.__init__(self, EVT_DISPLAY_INFO, GENERIC_EVENT)
+        self.displayInfo = dispInfo
+
+
+class AppKilledEvent(Event):
+
+    def __init__(self, sageApp):
+        Event.__init__(self, EVT_APP_KILLED, GENERIC_EVENT)
+        self.app = sageApp
+
+
+class ZChangeEvent(Event):
+
+    def __init__(self, zHash):
+        Event.__init__(self, EVT_Z_CHANGE, GENERIC_EVENT)
+        self.zHash = zHash  # key=appId, value=new z value
+
+        
+class ObjectInfoEvent(Event):
+
+    def __init__(self, data):
+        Event.__init__(self, EVT_OBJECT_INFO, GENERIC_EVENT)
+        self.overlayId = data.split()[0]
+        self.data = data
+        # FIX - ie complete
Index: trunk/src/testing/dim/.pydevproject
===================================================================
--- trunk/src/testing/dim/.pydevproject	(revision 4)
+++ trunk/src/testing/dim/.pydevproject	(revision 4)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/DIM_experimental</path>
+</pydev_pathproperty>
+</pydev_project>
Index: trunk/src/testing/dim/sageData.py
===================================================================
--- trunk/src/testing/dim/sageData.py	(revision 4)
+++ trunk/src/testing/dim/sageData.py	(revision 4)
@@ -0,0 +1,339 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# python stuff
+import string, sys
+
+# my imports
+from sageApp import SageApp, SageAppInitial
+from sageDisplayInfo import SageDisplayInfo
+from globals import *
+import events
+
+
+## Main class to store all the messages returned by SAGE
+class SageData:
+
+
+    #### constructor initializes member values       
+    def __init__(self) :
+        self.hashApps = {}           # all the apps available for running??
+        self.hashAppStatusInfo = {}  # apps currently running
+        self.displayInfo = SageDisplayInfo()
+
+        self.sageGate = getSageGate()
+        self.sageGate.registerCallbackFunction(40000, self.setSageStatus)
+        self.sageGate.registerCallbackFunction(40001, self.setSageAppInfo)
+        #self.sageGate.registerCallbackFunction(40002, self.setSagePerfInfo)
+        self.sageGate.registerCallbackFunction(40003, self.sageAppShutDown)
+        self.sageGate.registerCallbackFunction(40004, self.setDisplayInfo)
+        self.sageGate.registerCallbackFunction(40005, self.setSageZValue)
+        self.sageGate.registerCallbackFunction(40006, self.setSageAppExecConfig)
+        self.sageGate.registerCallbackFunction(40007, self.setDisplayConnections)
+        self.sageGate.registerCallbackFunction(40018, self.setSageObjectInfo)
+
+
+    ### clears the current state (to be done when reconnecting)
+    def clear(self):
+        self.hashApps = {}           # all the apps available for running??
+        self.hashAppStatusInfo = {}
+        
+        
+    #### Set the sage status
+    def setSageStatus(self, appHash) :  
+        for appName, configs in appHash.iteritems():
+            self.hashApps[appName] = SageAppInitial(appName, configs)
+            
+
+    #----------------------------------------------------------------------
+
+
+    ### Set the possible execution configurations for each app
+    def setSageAppExecConfig(self, data):
+        tokens = string.split( data, '\n', 1 )
+        appName = tokens[0]
+        data = tokens[1] #the rest
+        configList = string.split( data, "config ")
+
+        del configList[0]  #remove the first item in the list
+
+        for config in configList:
+            if appName in self.hashApps.keys():
+                (name, stringConfig) = string.split(config, ":", 1)
+                self.hashApps[appName].AddConfig(name, stringConfig)
+
+
+    #----------------------------------------------------------------------
+ 
+    
+    #### Set the SAGE display information
+    #### 
+    def setDisplayInfo(self, data):
+        listTokens = string.split(data, '\n')
+
+        for i in range(0, len(listTokens), 3):
+            tileNumTokens = string.split(listTokens[i], ' ')
+            desktopTokens = string.split(listTokens[i+1], ' ')
+            tileConfTokens = string.split(listTokens[i+2], ' ')            
+            
+            # so that we can support the old sage as well
+            displayId = 0
+            if len(tileConfTokens) > 2:
+                displayId = int(tileConfTokens[2])
+
+            self.displayInfo.addDisplay(int(tileNumTokens[0]), int(tileNumTokens[1]), int(tileNumTokens[2]),
+                                   int(desktopTokens[0]), int(desktopTokens[1]),
+                                   int(tileConfTokens[0]), int(tileConfTokens[1]), displayId)
+
+        # for one display and old SAGE there are no connection messages so just
+        # pretend that one came in for drawing everything correctly
+        if self.displayInfo.getNumDisplays() == 1:
+            self.setDisplayConnections("")
+        
+
+    #----------------------------------------------------------------------
+    
+    # returns the SageDisplayInfo object
+    def getDisplayInfo(self, displayId=0):
+        return self.displayInfo.getDisplay(displayId)
+
+    #----------------------------------------------------------------------
+
+
+    def setDisplayConnections(self, data):
+        if data:
+            for connection in data.split('\n'):
+                tokens = connection.split()
+                displayId = int(tokens[2])
+                self.displayInfo.getDisplay(displayId).placement = int(tokens[1])
+
+        evt = events.DisplayInfoEvent(self.displayInfo)
+        getEvtMgr().postEvent(evt)
+
+
+    #----------------------------------------------------------------------
+    
+
+    #### Get the new list of z values from SAGE
+    #### and update local hashes, then call the function to update the UI visually
+    def setSageZValue(self, message):
+        tokens = string.split(message)
+        numZChanges = int(tokens[0])  #the first item that comes in is the number of z changes
+        zHash = {}   # key=appId, value=new z value
+        
+        # loop through all the tokens and update the z values of the apps
+        for i in range(numZChanges):
+            self.setZvalue( int(tokens[i*2+1]), int(tokens[i*2+2]) )
+            zHash[int(tokens[i*2+1])] = int(tokens[i*2+2])
+            
+        evt = events.ZChangeEvent(zHash)
+        getEvtMgr().postEvent(evt)
+
+
+    #----------------------------------------------------------------------
+
+    
+    #### Set the SAGE app status
+    #### prints Invalid app ID if does not exists
+    def setSageAppInfo(self, data):
+        listTokens = string.split(data)
+
+        # to support old sage as well
+        displayId = 0
+        orientation = 0
+        if len(listTokens) > 8:
+            orientation = int(listTokens[8])
+            displayId = int(listTokens[9])
+            
+
+        appId = int( listTokens[ 1 ] )
+        if appId in self.hashAppStatusInfo:
+            # update the app in the hash 
+            self.hashAppStatusInfo[ appId ].setAll( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), int(listTokens[7]), orientation, displayId)
+
+            # make the event
+            evt = events.AppInfoEvent(self.hashAppStatusInfo[appId])
+        else:
+            # when new app is started it is assigned a z=0 but since previous app on top had z=0,
+            # we set this one even higher temporarily (z=-1) so that it gets drawn on top
+            # the new z order message comes right after the app is started so this -1 is temporary
+            zValue = int(listTokens[7])
+            for app in self.hashAppStatusInfo.itervalues():
+                if app.getZvalue() == zValue:
+                    zValue = -1
+            self.hashAppStatusInfo[ appId ] = SageApp( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), zValue, orientation, displayId)
+
+            # make the event
+            evt = events.NewAppEvent(self.hashAppStatusInfo[appId])
+
+        # post the event about the state change
+        getEvtMgr().postEvent(evt)
+
+
+    #----------------------------------------------------------------------
+    
+    
+    ##### ShutDown the sage application
+    ##### prints invalid app ID if doesn't exist
+    def sageAppShutDown(self, data):
+        listTokens = string.split(data)
+        appId = int(listTokens[0])
+
+        if appId in self.hashAppStatusInfo :
+            # do this first and then remove the app from the hash!!
+            # make and post the event
+            evt = events.AppKilledEvent(self.hashAppStatusInfo[appId])
+            getEvtMgr().postEvent(evt)
+
+            # delete the app
+            del self.hashAppStatusInfo[appId]
+
+
+    #----------------------------------------------------------------------
+
+
+    def setSageObjectInfo(self, data):
+        evt = events.ObjectInfoEvent(data)
+        getEvtMgr().postEvent(evt)
+        
+
+    #----------------------------------------------------------------------
+    
+    
+    #   Get the z value of the app
+    #   @arg appInstID App instance ID of the app
+    #   @return Returns Z value if appID exists else returns -1
+    def getZvalue(self, appId):
+        if appId in self.hashAppStatusInfo:
+            return self.hashAppStatusInfo[appId].getZvalue()
+        else:
+            print("getZvalue: Invalid app instance ID")
+            return
+
+            
+    #----------------------------------------------------------------------
+
+
+    #   Set the Z value of the app
+    #   @arg appInstId App instance ID of the app
+    #   @arg value New Z value to be set
+    def setZvalue(self, appId, value):
+        if (appId in self.hashAppStatusInfo):
+            self.hashAppStatusInfo[appId].setZvalue(value)
+        else:
+            print ('setZvalue: Invalid app instance ID')
+        return
+
+
+    #----------------------------------------------------------------------
+
+
+    # returns the SageApp associated with the given appInstId
+    def getApp(self, appInstId):
+        return self.hashAppStatusInfo[appInstId]
+    
+
+    #----------------------------------------------------------------------
+
+    
+    ### (RJ 2005-01-15)
+    ### Returns a list of all the available apps
+    def getAvailableApps( self ):
+        return self.hashApps
+
+    ### (AKS 2004-10-23)
+    ### Get all app IDs
+    ### currently running on sage
+    ### @return list of app ids
+    def getAllAppIDs(self) :
+        return self.hashAppStatusInfo.keys()
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### Returns a hash of all running apps
+    def getRunningApps( self ):
+        return self.hashAppStatusInfo
+
+
+    #----------------------------------------------------------------------
+
+
+    # checks all the apps and reports whether any one of them was
+    # hit with a click and which region was hit (corners or shape in general)
+    # if more than one shape was hit it returns the one on the top
+    def checkHits(self, x, y):
+        zHash = {}  #key=z value, value=SageApp
+
+        try:
+            for appId, sageApp in self.hashAppStatusInfo.items():
+                zHash[sageApp.getZvalue()] = sageApp
+
+            zKeys = zHash.keys()
+            zKeys.sort()
+
+            for z in zKeys:
+                hitResult = zHash[z].hitTest(x,y)
+                if hitResult >= 0:
+                    return (zHash[z], hitResult)
+        except:
+            pass
+        return (None, -1)
+
+
+    #----------------------------------------------------------------------
+
+
+    # returns (appId, zValue) or (-1,sys.maxint) if no apps
+    def getTopApp(self):
+        minZ = (-1, sys.maxint)
+        try:
+            for appId, app in self.hashAppStatusInfo.items():
+                if app.getZvalue() < minZ[1]:
+                    minZ = (appId, app.getZvalue())
+        except:
+            pass
+        return minZ
+        
Index: trunk/src/testing/dim/dim.py
===================================================================
--- trunk/src/testing/dim/dim.py	(revision 4)
+++ trunk/src/testing/dim/dim.py	(revision 4)
@@ -0,0 +1,148 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# python imports
+import optparse, time, os, sys
+
+# my imports
+from deviceManager import DeviceManager
+from eventManager import EventManager
+from overlayManager import OverlayManager
+from listener import Listener
+from sageGate import SageGate
+from sageData import SageData
+from globals import *
+
+
+# ------------------------------------------------------------------------------
+#
+#                         GLOBALS   
+#
+# ------------------------------------------------------------------------------
+
+VERBOSE = False
+LISTENER_PORT = 20005   # for HW capture modules (ie HW devices sending events)
+
+
+os.chdir(sys.path[0])
+
+
+class DIM:
+    def __init__(self, host, port):
+        # sageGate is the network connection with SAGE
+        self.sageGate = SageGate()
+        setSageGate(self.sageGate)
+
+        # the event manager takes care of properly dispatching events
+        self.evtMgr = EventManager()
+        setEvtMgr(self.evtMgr)
+        self.evtMgr.addHandlers()
+
+        # sageData keeps the current state of the SAGE windows/apps
+        self.sageData = SageData()
+        setSageData(self.sageData)
+        
+        # overlay manager creates, destroys and updates overlays
+        self.overlayMgr = OverlayManager()
+        setOverlayMgr(self.overlayMgr)
+
+        # contains all the devices and takes care of loading plugins for them
+        # also, distributes HW messages to each device 
+        self.devMgr = DeviceManager()
+        setDevMgr(self.devMgr)
+
+        # connect to SAGE
+        for i in range(5):  # try to connect to SAGE for 5 seconds
+            if self.sageGate.connectToSage(host, port) != 0:
+                self.sageGate.registerSage()
+                break
+            time.sleep(1)
+        else:  # we didn't manage to connect to sage in 5 seconds... so quit
+            exitApp()
+
+        # start listening for the device events
+        time.sleep(4)   # wait till all the messages come in
+        self.overlayMgr.addOverlay(OVERLAY_WALL)
+        self.listener = Listener(LISTENER_PORT, self.devMgr.onHWMessage)
+        self.listener.serve_forever()
+
+
+
+### sets up the parser for the command line options
+def get_commandline_options():
+    parser = optparse.OptionParser()
+
+    h = "if set, prints output to console, otherwise to output_log.txt"
+    parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help=h, default=False)
+
+    h = "interaction with which sage? (default=localhost)"
+    parser.add_option("-s", "--sage_host", dest="host", help=h, default="localhost")
+
+    h = "the UI port number for sage (default is 20001)"
+    parser.add_option("-p", "--sage_port", dest="port", help=h, type="int", default=20001)
+
+    return parser.parse_args()
+
+
+
+
+# ------------------------------------------------------------------------------
+#
+#                         MAIN
+#
+# ------------------------------------------------------------------------------
+
+
+def main():
+    global VERBOSE
+    
+    # parse the command line params
+    (options, args) = get_commandline_options()
+    VERBOSE = options.verbose
+    sagePort = options.port
+    sageHost = options.host
+
+    # start everything off
+    DIM(sageHost, sagePort)
+    
+
+    
+if __name__ == '__main__':
+    main()
Index: trunk/src/testing/dim/sageGateBase.py
===================================================================
--- trunk/src/testing/dim/sageGateBase.py	(revision 4)
+++ trunk/src/testing/dim/sageGateBase.py	(revision 4)
@@ -0,0 +1,832 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+"""
+	SAGE UI --> SAGE
+	---------------------------	
+	Register 			1000
+	Execute				1001
+	Shutdown			1002
+	Move				1003
+	Resize				1004
+	Start Performance		1005
+	Stop Performance		1006
+	BackColor			1007
+	Bring to Front                  1010
+	App Properties Change           1011
+	App Frame Rate Change           1012
+	Stream Request                  1014
+        Rotate Window                   1018
+	SAGE Shutdown                   1100
+	Add Object                      1200
+        Move Object                     1201
+        Remove Object                   1202
+        Object Message                  1203
+        Show Object                     1204
+        Hide Object                     1205
+        
+
+	SAGE ----> SAGE UI
+	--------------------------
+	Status				40000 
+	App Info			40001 APPID L R T B SAIL-ID
+	Performance			40002
+	App Shutdown                    40003
+	Display Info                    40004
+	Z Order Change                  40005
+	App Exec Config                 40006
+        Display Connections             40007
+        Overlay Object Info             40018
+	
+
+	STORE INFORMATION
+"""
+
+
+from threading import Thread, RLock
+import socket, sys, string, os.path, xmlrpclib, time
+import traceback as tb
+from globals import *
+
+
+### GLOBALS ###
+
+TIMEOUT_INTERVAL = 0.5
+BLANK = ' '
+HEADER_ITEM_LEN = 8
+APP_LAUNCHER_PORT = 19010  #the default port, usually retrieved from the sage server though
+SAGE_SERVER_PORT = 8009  #the xmlrpc port of the sage server
+
+
+
+class AppLauncher:
+
+    def __init__(self, launcherId, name, ip, port, appList):
+        self.port = port
+        self.appList = appList
+        self.ip = ip
+        self.launcherId = launcherId
+        self.name = name
+	self.connected = False
+
+
+    def connect(self):
+	if not self.connected:
+	    socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
+	    self.server = xmlrpclib.ServerProxy("http://" + self.ip + ":" + str(self.port))
+	    try:
+		self.server.test() #just use this as a way of testing whether the server is running or not
+		self.connected = True
+	    except socket.error:
+		return False
+	    except:
+		tb.print_exc()
+		return False
+	return True
+
+
+    def getId(self):
+        return self.launcherId
+
+    def getIP(self):
+        return self.ip
+
+    def getAppList(self):
+        return self.appList
+
+    def setAppList(self, appList):
+        self.appList = appList
+
+    def getPort(self):
+        return self.port
+
+    def getName(self):
+        return self.name
+    
+    def getServerHandle(self):
+        self.connect()
+        return self.server
+
+
+
+
+
+
+####################################################################
+#
+# DESCRIPTION: This is the base class for communication with SAGE.
+#              You need to inherit from this class and override
+#              the "onMessage" method. You can use the registerCallbackFunction
+#              and the hashCallbackFunction to store your callbacks
+#              and then retrieve them from your overridden onMessage.
+#
+# DATE: Aug, 2007
+#
+####################################################################
+
+class SageGateBase:
+	
+    def __init__(self, sageServerHost="sage.sl.startap.net", useAppLauncher=False, forceAppLauncher=None, onDisconnect=None, verbose=False):
+	self.hashCallbackFunction = {}
+	self.threadkilled = False
+	self.connected = False
+	self.sageHost = None
+	self.sagePort = 20001
+        self.forceAppLauncher = forceAppLauncher         # use this appLauncher if specified
+        self.useAppLauncher = useAppLauncher   # should we use the appLauncher at all?
+        self.onDisconnect = onDisconnect       # call this function if disconnected
+        self.verbose = verbose                 # print the output?
+        self.sageServerHost = sageServerHost           # where the sage server is running
+
+	# used for printing out informative messages (on sending and receiving)
+	self.hashOutgoingMessages = {}  
+	self.hashOutgoingMessages[1000] = "Register UI"
+	self.hashOutgoingMessages[1001] = "App Start"
+	self.hashOutgoingMessages[1002] = "App Shutdown"
+	self.hashOutgoingMessages[1003] = "Move"
+	self.hashOutgoingMessages[1004] = "Resize"
+	self.hashOutgoingMessages[1005] = "Request Performance"
+	self.hashOutgoingMessages[1006] = "Stop Performance"
+	self.hashOutgoingMessages[1007] = "Background Color"
+	self.hashOutgoingMessages[1010] = "Bring To Front"
+	self.hashOutgoingMessages[1011] = "App Properties Change"
+	self.hashOutgoingMessages[1012] = "App Frame Rate Change"
+	self.hashOutgoingMessages[1014] = "Stream Request"
+        self.hashOutgoingMessages[1018] = "Rotate Window"
+        self.hashOutgoingMessages[1200] = "Add Object"
+        self.hashOutgoingMessages[1201] = "Move Object"
+        self.hashOutgoingMessages[1202] = "Remove Object"
+        self.hashOutgoingMessages[1203] = "Object Message"
+	self.hashOutgoingMessages[1100] = "Shutdown"
+
+	self.hashIncomingMessages = {} 
+	self.hashIncomingMessages[40000] = "SAGE Status Message"
+	self.hashIncomingMessages[40001] = "App Info Return"
+	self.hashIncomingMessages[40002] = "Performance Info"
+	self.hashIncomingMessages[40003] = "App Shutdown"
+	self.hashIncomingMessages[40004] = "Display Info"
+	self.hashIncomingMessages[40005] = "Z Change"
+	self.hashIncomingMessages[40006] = "App Exec Config"
+        self.hashIncomingMessages[40007] = "Display Connections"
+        self.hashIncomingMessages[40018] = "Overlay Object Info"
+
+
+
+    def makemsg(self, dst, code, appcode, size, data):
+        # assemble the message into a string
+	msg = '%8s\0%8s\0%8s\0%s\0' % (dst, code, appcode, data)
+	size = len(msg) + 9
+	msg = '%8s\0%s' % (size, msg)
+
+        # print the output if requested
+        if self.verbose and int(code) < 1200:  # dont print the draw object messages cause there are many of them
+            print "\n\tSEND:  " + self.hashOutgoingMessages[int(code)]
+            print "\t       [" + data + "]\n\n"
+            
+	return msg	
+
+
+    def connectToAppLauncher(self, host=socket.gethostname()):
+	socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
+        if self.forceAppLauncher:    # overriding with the one from the command line
+            self.appLauncher = xmlrpclib.ServerProxy("http://" + self.forceAppLauncher)
+        else:                         # try to find the appropriate app launcher
+            self.appLauncher = self.__getMyAppLauncher(host)
+            if type(self.appLauncher) is type(None):  # in case we couldn't find one, just assume it's running
+                self.appLauncher = xmlrpclib.ServerProxy("http://" + host + ":" + str(APP_LAUNCHER_PORT))
+
+        # now test the connection
+	try:
+	    self.appLauncher.listMethods() #just use this as a way of testing whether the server is running or not
+	except socket.error:
+	    return False
+	except:
+	    pass
+	return True
+
+
+    def getPort(self):
+	return self.sagePort
+
+    def getHost(self):
+	return self.sageHost
+
+
+    ##################################################################	
+    #  Connect To Sage
+    ##################################################################	
+    def connectToSage(self, host=socket.gethostname(), port=20001):
+	''' returns 1 if succeeded, 0 if no connection to SAGE and -1 if no connection to appLauncher'''
+	if self.connected == True: return 0
+
+	## create socket
+	self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+	if self.sock is None: return 0
+
+
+        #### RJ 2005-01-21
+	# without this, this thread will never exit because sock.recv is blocking and it will wait until
+	# something comes in. What happens is, "while" checks if threadkilled is false, it is so it goes
+	# in here and blocks until something is received. In the meantime, we want to quit so we set
+	# threadkilled to True but since we are blocked by sock.recv, we wont be able to get to the "while" again
+	self.sock.settimeout(TIMEOUT_INTERVAL)
+        
+
+	if host: self.sageHost = host
+	if port > 0: self.sagePort = port
+	## connect
+	try:
+	    self.sock.connect((host, port))
+	except socket.error:
+	    print 'can\'t connect to SAGE', self.sageHost, self.sagePort	
+	    return 0
+
+	##### FOR Thread
+	self.threadkilled = False
+        self.senderLock = RLock()
+	self.t = Thread(target=self.receiverThread, args=())
+	self.t.start()
+	self.connected = True
+
+        # start the overlay sender thread
+        self.overlayMsgLock = RLock()
+        self.overlayMsgQueue = []   # combined overlay messages (list of string messages)
+        self.overlayMsgFreq = 50    # send messages roughly 50 times a sec
+        self.overlaySender = Thread(target=self.overlaySenderThread)
+        self.overlaySenderKilled = False
+        self.overlaySender.start()
+
+	# now connecting to the appLauncher running on the
+        # same machine as SAGE we are connecting to
+	if self.useAppLauncher and not self.connectToAppLauncher(host):
+	    print "\n===> Can't connect to the appLauncher"
+	    return -1
+	else:
+	    print 'connected to SAGE', self.sageHost, self.sagePort
+	    return 1
+
+
+
+        ### attempts to find the appLauncher that's running on the same machine as myHost
+        ### (by comparing IP addresses of the sage machine and reported appLaunchers)
+    def __getMyAppLauncher(self, myHost):
+        self.updateLauncherList()  #get a new fresh list of appLaunchers
+        
+	def sameByIP(first, second):
+	    try:
+		first = socket.gethostbyname(first)[0]
+		second = socket.gethostbyname(second)[0]
+                if first == second:
+                    return True
+                else:
+                    return False
+            except:
+                return False
+
+        # loop through all the known launchers and try to find the one that matches myHost
+	for launcher in self.launchers.itervalues():
+	    try:
+		if myHost == launcher.getIP():
+		    return launcher.getServerHandle()  #returns the server object that we can call functions on
+                elif sameByIP(myHost, launcher.getIP):
+                    return launcher.getServerHandle()
+                else:
+                    return None
+            except:
+                return None
+                
+    
+    
+    ### connects to the sage server and retrieves the list of all app launchers running
+    def updateLauncherList(self):
+	self.launchers = {}
+	sageServer = xmlrpclib.ServerProxy("http://" + self.sageServerHost + ":" + str(SAGE_SERVER_PORT))
+	try:
+	    # a hash comes back (key=launcherId, value=appList - that's another hash of appNames and configs)
+	    launcherHash = sageServer.GetRegisteredLaunchers()
+	except socket.error:
+	    print "no connection to the sage server... can't get the list of appLaunchers"
+	except:
+	    tb.print_exc()
+	else:
+	    for launcherString, appList in launcherHash.iteritems():
+		(name, launcherId) = launcherString.split(":", 1)
+		(ip, port) = launcherId.split(":", 1)
+		self.launchers[launcherId] = AppLauncher(launcherId, name, ip, port, appList)
+		
+	return self.launchers
+
+
+    ### returns a hash of all the appLaunchers currently running
+    def getLaunchers(self):
+	return self.updateLauncherList()
+    
+
+    # get the applist from the applauncher first and call the appropriate function
+    def getAppList(self):
+        appList = {}
+	try:
+	    appList = self.appLauncher.getAppList()
+            self.hashCallbackFunction[ 40000 ](appList)
+	except socket.error:
+	    self.hashCallbackFunction[ 40000 ](appList) #return appList  #the server is not running
+	except:
+	    tb.print_exc()
+            return False
+
+
+    def isConnected(self):
+        return self.connected
+	
+
+    def disconnectFromSage(self, isSocketError=False):
+        """ isSocketError should be True when we didn't close
+            the connection intentionally but rather the connection
+            broke for some reason. In that case the onDisconnect
+            callback is called.
+        """
+	if self.connected == False: return 0
+
+	self.threadkilled = True
+        self.overlaySenderKilled = True
+	self.connected = False		
+	#self.t.join()
+	self.sock.close()
+	del self.sock
+	print 'disconnected from SAGE', self.sageHost, self.sagePort
+
+        if isSocketError and self.onDisconnect:
+            self.onDisconnect()
+        
+	return 1
+
+
+    def sendmsg(self, data, code, sailId=''):
+        if not self.connected:
+            return 0
+
+        self.senderLock.acquire()
+
+        msg = self.makemsg(sailId, code, '', len(data), data)
+	totalcount = 0
+	try:
+		totalcount = self.sock.send(msg)
+	except socket.error:
+	    print 'SageGateBase: socket error on send'
+	    totalcount = 0
+            self.disconnectFromSage(isSocketError=True)
+	except Exception:
+            tb.print_exc()
+	    totalcount = 0
+
+        self.senderLock.release()
+	return totalcount
+
+
+    ##################################################################	
+    # Register
+    ##################################################################	
+    # 1000 none
+    # 40004 display info format
+    ##################################################################	
+    def registerSage(self):
+ 	if not self.connected:
+	    return 0
+ 	return self.sendmsg('', 1000)
+
+
+    ##################################################################	
+    # Execute
+    ##################################################################	
+    # 1001 app-name 100 100 (app-name(?)) 
+    # 40001 app-inst-ID left right top bottom sail-ID
+    ##################################################################	
+    def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        if not sageIP:  sageIP = self.sageHost
+        if not sagePort: sagePort = self.sagePort + 1
+        
+        # try running the app (return -1 if failed for whatever reason)
+        try:
+            res = self.appLauncher.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+        except socket.error:
+            return -1
+        else:
+            return res
+
+
+    def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        if not sageIP:  sageIP = self.sageHost
+        if not sagePort: sagePort = self.sagePort + 1
+
+        # try running the app (return -1 if failed for whatever reason)
+	if launcherId in self.launchers:
+            server = self.launchers[launcherId].getServerHandle()
+            try:
+                res = server.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+            except socket.error:
+                return -1
+            else:
+                return res
+	else:
+	    print "Launcher not found: ", launcherId
+	    return -1
+
+
+	
+    ##################################################################	
+    # Shutdown
+    ##################################################################	
+    # 1002 app-instance
+    # 40003 app-Inst-ID (?)
+    ##################################################################	
+    def shutdownApp(self, appId):
+	if self.connected == False: return 0
+
+	data = str(appId)
+	return self.sendmsg(data, 1002)
+
+
+    ##################################################################	
+    # Forceful Shutdown
+    ##################################################################	
+    def forceShutdownApp(self, portNum):
+	if self.connected == False: return 0
+
+	# the portNum is basically the appId in the appLauncher context
+	return self.appLauncher.stopApp(portNum)   
+
+
+    ##################################################################	
+    # Move
+    ##################################################################	
+    # 1003 app-instance dist-X,dist-Y
+    ##################################################################	
+    def moveWindow(self, appId, distX, distY):
+	if self.connected == False: return 0
+
+	#make sure all the coordinates are ints
+	distX = int(distX)
+	distY = int(distY)
+
+	data = str(appId) + BLANK + str(distX) + BLANK + str(distY)
+	return self.sendmsg(data, 1003)
+	
+
+    ##############################################################
+    # Resize
+    # 1004 app-instance lef,right,top,bottom
+    ##################################################################
+    def resizeWindow(self, appId, left=0, right=0, bottom=0, top=0):
+	if self.connected == False: return 0
+	#if not appId: return 0
+
+	#make sure all the coordinates are ints
+	left = int(left)
+	right = int(right)
+	bottom = int(bottom)
+	top = int(top)
+
+	data = str(appId) + BLANK + str(left) + BLANK + str(right) + BLANK + str(bottom) + BLANK + str(top)
+	return self.sendmsg(data, 1004)
+	
+
+    ###########################################################
+    # Performance Information
+    ###########################################################
+    # 1005 app-instance sending-rate
+    # 1006 app-instance 	
+    ###########################################################	
+    def startPerformance(self, appId, sendingrate=2):
+	if self.connected == False: return 0
+
+	data = "%d %d" % (appId, sendingrate)
+	return self.sendmsg(data, 1005)	
+	
+
+    def stopPerformance(self, appId):
+	if self.connected == False: return 0
+
+	data = str(appId) # convert the data to string format
+	return self.sendmsg(data, 1006)
+	
+
+
+    ####################################	
+    # Background Color
+    # 1007 red,green blue	
+    ##################################################################
+    def setBgColor(self, (red, green, blue)=(1, 1, 1)):
+	if self.connected == False: return 0
+
+	data = str(red) + BLANK + str(green) + BLANK + str(blue)
+	return self.sendmsg(data, 1007)
+	
+
+    ####################################	
+    # bring the application window to the top (front)
+    # 1010 app-inst-ID 
+    ##################################################################
+    def bringToFront(self, appId):
+	if self.connected == False: return 0
+
+	data = str(appId)
+	return self.sendmsg(data, 1010)
+	
+
+
+    ####################################	
+    # Change App Properties
+    # 1011 appId, fsmIP, fsmPort, appConfigNum	
+    ##################################################################
+    def changeAppProperties(self, appId, newTitle, newTitleColor=(-1, -1, -1), newBorderColor=(-1, -1, -1)):
+	if self.connected == False: return 0
+
+	data = str(appId) + BLANK + str(newTitle)
+	data = data + BLANK + str(newTitleColor[0]) + BLANK + str(newTitleColor[1]) + BLANK + str(newTitleColor[2])
+	data = data + BLANK + str(newBorderColor[0]) + BLANK + str(newBorderColor[1]) + BLANK + str(newBorderColor[2])
+	return self.sendmsg(data, 1011)
+	
+
+    ####################################	
+    # Change App Frame Rate
+    # 1010 appId, fsmIP, fsmPort, appConfigNum	
+    ##################################################################
+    def changeAppFrameRate(self, appId, newFrameRate):
+	if self.connected == False: return 0
+
+	data = str(appId) + BLANK + str(newFrameRate)
+	return self.sendmsg(data, 1012)
+	
+
+
+    ####################################	
+    # Stream Request
+    # 1014 appId, fsmIP, fsmPort
+    ##################################################################
+    def streamApp(self, appId, fsmIP, fsmPort):
+	if self.connected == False: return 0
+
+	data = str(appId) + BLANK + str(fsmIP) + BLANK + str(fsmPort)
+	return self.sendmsg(data, 1014)
+	
+
+
+    ####################################	
+    # Rotate Window
+    # 1018 appId, degree
+    ##################################################################
+    def rotateWindow(self, appId, degree):
+	if self.connected == False: return 0
+
+	data = str(appId) + BLANK + str(degree)
+	return self.sendmsg(data, 1018)
+
+
+
+    ####################################	
+    # Overlay Messages
+    # 1200 - 1205
+    ##################################################################
+    def addOverlay(self, overlayType, x, y, w, h, isGlobal, drawOrder, displayId=0):
+        data = '%s %s %s %s %s %s %s %s' % (overlayType, x, y, w, h, int(isGlobal), drawOrder, displayId)
+        return self.sendmsg(data, 1200)
+
+
+    def moveOverlay(self, id, dx, dy):
+        """ relative movement """
+        data = '%s %s %s' % (id, dx, dy)
+        return self.sendmsg(data, 1201)
+    
+
+    def showOverlay(self, id, doShow):
+        data = '%s %s' % (id, str(int(doShow)))
+        return self.sendmsg(data, 1204)
+
+
+    def sendOverlayMessage(self, id, *data):
+        """ this actually puts the messages in a queue
+            which are then sent at fixed intervals """
+
+        # first assemble the data into a string
+        msg = '%s' % (id)
+        for d in data:   
+            msg += " " + str(d)
+
+        self.overlayMsgLock.acquire()
+        self.overlayMsgQueue.append(msg)
+        self.overlayMsgLock.release()
+
+
+    def __sendMultipleOverlayMessages(self, msg):  # a bunch of messages combined into one
+        return self.sendmsg(msg, 1203)
+
+
+    def removeOverlay(self, id):
+        data = '%s' % (id)
+        return self.sendmsg(data, 1202)
+        
+
+    ####################################	
+    # SAGE App events
+    # 31000 - 31007
+    ##################################################################
+
+    def sendAppEvent(self, eventId, sailId, *data):
+        # first assemble the data into a string
+        msg = ''
+        for d in data:   
+            msg += " " + str(d)
+        self.sendmsg(msg, 31000 + eventId, sailId)
+
+
+    ####################################	
+    # SAGE shutdown
+    # 1100 	<none>
+    ##################################################################
+    def shutdownSAGE(self):
+	if self.connected == False: return 0
+	return self.sendmsg('', 1100)
+
+
+
+    ##############
+    #  Overlay Sender Thread
+    #    - Sends combined overlay messages at fixed intervals
+    ##################################################################
+    def overlaySenderThread(self):
+        while not self.overlaySenderKilled and doRun():
+            self.overlayMsgLock.acquire()
+
+            # iterate through the msg queue and assemble the messages into a string
+            msg = ""
+            for m in self.overlayMsgQueue:
+                msg += m + "\n"            # separate messages with \n
+            self.overlayMsgQueue = []      # clear the queue
+            self.overlayMsgLock.release()
+
+            # send the message if there is something to send
+            msg = msg.strip()
+            if msg != "":
+                self.__sendMultipleOverlayMessages(msg)
+                
+            # sleep for a certain time
+            time.sleep(1.0 / self.overlayMsgFreq)
+
+        print "Overlay message sender thread closed"
+	
+
+    ##############
+    #  Receiver Thread
+    #    - receives messages from SAGE in a thread
+    ##################################################################
+    def receiverThread(self):
+
+	while self.threadkilled == False and doRun():   #doesn't work as expected without the sock.settimeout (look below)
+
+	    #############################
+	    try:
+
+		code = ""
+		incomingMsg = ""
+		msgSize = ""
+
+		# first make sure you read the whole 8 bytes for the size
+		while len(msgSize) < HEADER_ITEM_LEN:
+		    msgSize = self.sock.recv(HEADER_ITEM_LEN)
+		    if len(msgSize) == 0:
+			self.threadkilled = True
+                        self.overlaySenderKilled = True
+                        self.disconnectFromSage(isSocketError=True)
+			break
+
+                if self.threadkilled: break
+                
+		# this is the number of bytes that the total message contains
+		msgSize = msgSize.replace('\x00', '')
+		sizeLeft = int(msgSize) - HEADER_ITEM_LEN    # we already read the size so read the rest of the bytes
+
+		# read the rest of the message
+		while len(incomingMsg) < sizeLeft:
+		    incomingMsg = incomingMsg + self.sock.recv(sizeLeft - len(incomingMsg))
+
+		# extract the tokens from the message
+		if len(incomingMsg) > 0:
+		    incomingMsg = incomingMsg.replace('\x00', ' ')
+		    dst = incomingMsg[ 1:9 ].strip()
+		    code = int(incomingMsg[ 10:18 ].strip())
+		    appCode = incomingMsg[ 19:27 ].strip()
+		    data = incomingMsg[ 28: ].strip()
+
+		    # print the message out (except performance info since there are many of them)
+                    if self.verbose and code in self.hashIncomingMessages and code != 40002:
+                        print "\n\tRECEIVED:  " + self.hashIncomingMessages[code]
+                        lines = data.split('\n')
+                        if len(lines) < 2:
+                            print "\t\t   [" + lines[0] + "]\n\n"
+                        else:
+                            for i in range(0, len(lines)):
+                                if i == 0:
+                                    print "\t\t   [" + lines[i]
+                                elif i == len(lines) - 1:
+                                    print "\t\t    " + lines[i] + "]\n\n"
+                                else:
+                                    print "\t\t    " + lines[i]
+
+
+	    except socket.timeout:
+		continue
+	    except socket.error:
+		print 'SageGateBase: socket error on receive'
+                self.disconnectFromSage(isSocketError=True)
+		continue
+	    #except:
+	    #	print 'exception: ', sys.exc_info()[0], sys.exc_info()[1]
+	    #	break
+	    ############################
+
+	    if self.threadkilled:
+		break
+
+	    # finally, do something with this message (ie call the subclass' message handler)
+            self.onMessage(code, data)
+
+        print "SageGate receiver thread closed"
+        
+
+    def cleanBuffer(self, stBuffer):
+        """ converts all non-printable characters from the buffer to white spaces
+            (so that they can be removed using string.strip() function)
+        """
+	stNewBuffer = ""
+
+	for ch in stBuffer:
+	    if (ch in string.printable):
+		stNewBuffer = stNewBuffer + ch
+	    else:
+		stNewBuffer = stNewBuffer + " "
+
+	return stNewBuffer
+
+
+
+    def onMessage(self, code, data):
+        """ this is the function that gets called after a message arrives successfully
+            it must be overridden by the subclass
+        """
+        raise NotImplementedError
+
+
+    def registerCallbackFunction(self, msgID, function):
+	self.hashCallbackFunction[ msgID ] = function
+
+
+
+
+
+        
+
+
Index: trunk/src/testing/dim/hwcapture/wiimote.py
===================================================================
--- trunk/src/testing/dim/hwcapture/wiimote.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture/wiimote.py	(revision 4)
@@ -0,0 +1,243 @@
+from managerConn import ManagerConnection
+import time, sys
+from pywii import Wii, _ClassWiimote
+import pywii
+import cmath
+
+# types of messages sent to the manager
+MOVE = 0
+TRANSLATE = 1
+ROTATE = 2
+RESIZE = 3
+CHANGE_Z = 4
+FULLSCREEN = 5
+
+
+# wiimote Buttons
+BUTTON_A = 0
+BUTTON_B = 1
+BUTTON_1 = 2
+BUTTON_2 = 3
+BUTTON_PLUS = 4
+BUTTON_MINUS = 5
+BUTTON_HOME = 6
+BUTTON_UP = 7
+BUTTON_DOWN = 8
+BUTTON_LEFT = 9
+BUTTON_RIGHT = 10
+
+# constants for gaussaian smoothing
+HISTORY_LENGTH = 150
+STD_DEVIATION = 15.0
+
+#Rotating constants
+NO_ROTATE = 0
+LEFT_ROTATE = 1
+RIGHT_ROTATE = -1
+
+class Position:
+    def __init__(self, x, y):
+        self.x = x
+        self.y = y
+    
+
+class Wiimote:
+    def __init__(self, manager):
+        self.__buttons = {}
+        for i in range (0, 11):
+            self.__buttons[i] = False
+            
+        self.history = []        
+        self.gauss = []
+        for i in range (-HISTORY_LENGTH + 1, 1):
+            self.gauss.append(abs(1/(cmath.sqrt(2*cmath.pi*pow(STD_DEVIATION,2)))*cmath.exp(-(pow(i,2)/(2*pow(STD_DEVIATION,2)))))) 
+        
+        gaussSum = 0        
+        for i in self.gauss:
+            gaussSum += i 
+            
+        for i in range(0,HISTORY_LENGTH):
+            self.gauss[i] = self.gauss[i] / gaussSum
+            
+        self.pointerPosition = None
+        
+        self.wii = Wii()
+        self.wiimote = self.wii.QuickConnect()[0]
+        self.wiimote.SetMotionSensingMode(self.wiimote.ON)
+        self.wiimote.SetLEDs(_ClassWiimote.LED_1)
+        self.wiimote.IR.SetMode(self.wiimote.IR.ON)
+        self.wiimote.IR.SetAspectRatio(self.wiimote.IR.ASPECT_16_9)
+        
+        self.initialOrientation = [0,0]
+        self.displaySize = [660.0, 370.0]
+        
+        self.outPointerCount = 0
+        
+#        Potrzebne przy obrotach na akcelerometrze
+#        self.rotateInit = 80
+#        self.rotateDone = 40
+#        self.rotating = NO_ROTATE
+
+        self.buttonMap = {}
+        
+        self.buttonMap[BUTTON_A] = self.wiimote.Buttons.BUTTON_A
+        self.buttonMap[BUTTON_B] = self.wiimote.Buttons.BUTTON_B
+        self.buttonMap[BUTTON_1] = self.wiimote.Buttons.BUTTON_ONE
+        self.buttonMap[BUTTON_2] = self.wiimote.Buttons.BUTTON_TWO
+        self.buttonMap[BUTTON_PLUS] = self.wiimote.Buttons.BUTTON_PLUS
+        self.buttonMap[BUTTON_MINUS] = self.wiimote.Buttons.BUTTON_MINUS
+        self.buttonMap[BUTTON_HOME] = self.wiimote.Buttons.BUTTON_HOME
+        self.buttonMap[BUTTON_UP] = self.wiimote.Buttons.BUTTON_UP
+        self.buttonMap[BUTTON_DOWN] = self.wiimote.Buttons.BUTTON_DOWN
+        self.buttonMap[BUTTON_LEFT] = self.wiimote.Buttons.BUTTON_LEFT
+        self.buttonMap[BUTTON_RIGHT] = self.wiimote.Buttons.BUTTON_RIGHT
+        
+        self.buttonHandler = {}
+        
+        self.__registerButtonHandler(BUTTON_A, self.onButtonA)
+        self.__registerButtonHandler(BUTTON_B, self.onButtonB)
+        self.__registerButtonHandler(BUTTON_LEFT, self.onButtonLeft)
+        self.__registerButtonHandler(BUTTON_RIGHT, self.onButtonRight)
+        self.__registerButtonHandler(BUTTON_UP, self.onButtonUp)
+        self.__registerButtonHandler(BUTTON_DOWN, self.onButtonDown)
+        self.__registerButtonHandler(BUTTON_HOME, self.onButtonHome)
+ 
+        self.manager = manager
+        
+        handlerMap = {  self.wiimote.EVENT_EVENT: self.handleEvent }
+        try:
+            self.wii.PollMapped(handlerMap, self.wii.POLL_FOREVER)
+        except:
+            self.manager.quit()
+            sys.exit(0)
+        
+        
+        
+    def __registerButtonHandler(self, buttonCode, buttonHandler):
+        self.buttonHandler[buttonCode] = buttonHandler
+            
+        
+    def __calculateGaussAverage(self):
+        sumx = 0
+        sumy = 0
+        
+        sumweight = 0
+        
+        for i in range(0,len(self.history)):
+            sumx += self.history[i].x * self.gauss[i]
+            sumy += self.history[i].y * self.gauss[i]
+            sumweight += self.gauss[i]
+        
+        if len(self.history) < HISTORY_LENGTH:
+            self.pointerPosition = Position(sumx/sumweight, sumy/sumweight)
+        else:
+            self.pointerPosition = Position(sumx, sumy)
+            
+    def __updatePointerPosition(self, point):
+        if point.x == 0 and point.y == 1:
+            if self.outPointerCount == HISTORY_LENGTH / 3:
+                self.history = []
+                self.pointerPosition = Position(-1,-1)
+            else:
+                self.outPointerCount += 1
+            
+        else:
+            self.history.append(point)
+            self.pointerPosition = None
+            
+            self.outPointerCount = 0
+            
+            if len(self.history) == (HISTORY_LENGTH + 1):
+                self.history.pop(0)
+            self.__calculateGaussAverage()
+            
+    def handleEvent(self, wm):
+        for i in self.buttonHandler:
+            self.__checkSingleButton(wm, i)
+        
+#obroty na akcelerometrze
+#        if wm.Buttons.isPressed(wm.Buttons.BUTTON_A):
+#            pitch, roll, _ = wm.Accelerometer.GetOrientation()
+#            if self.rotating == NO_ROTATE:
+#                if self.initialOrientation[1] - roll > self.rotateInit:
+#                    self.rotating = LEFT_ROTATE
+#                    self.sendMsg(ROTATE,self.rotating)
+#                elif roll - self.initialOrientation[1]> self.rotateInit:
+#                    self.rotating = RIGHT_ROTATE
+#                    self.sendMsg(ROTATE,self.rotating)
+#            elif self.rotating == LEFT_ROTATE and self.initialOrientation[1] - roll < self.rotateDone:
+#                self.rotating = NO_ROTATE
+#                self.sendMsg(ROTATE,self.rotating)
+#            elif self.rotating == RIGHT_ROTATE and roll - self.initialOrientation[1] < self.rotateDone:
+#                self.rotating = NO_ROTATE
+#                self.sendMsg(ROTATE,self.rotating)
+                
+        if wm.isUsingIR() and wm.IR.GetNumDots >= 2:         
+            mx, my = wm.IR.GetCursorPosition()
+            x = float(mx/self.displaySize[0])
+            y = 1-float(my/self.displaySize[1])
+            self.__updatePointerPosition(Position(x,y))
+            if not self.pointerPosition == None:
+                self.sendMsg(MOVE,self.pointerPosition.x, self.pointerPosition.y)
+                
+    def __checkSingleButton(self, wm, buttonCode):
+        if wm.Buttons.isJustPressed(self.buttonMap[buttonCode]):
+            self.__buttons[buttonCode] = True
+            self.buttonHandler[buttonCode](wm, True)            
+            
+        if self.__buttons[buttonCode] and not wm.Buttons.isPressed(self.buttonMap[buttonCode]):
+            self.__buttons[buttonCode] = False
+            self.buttonHandler[buttonCode](wm, False)
+            
+            
+    def onButtonA(self, wm, isDown):
+        if isDown:
+            self.sendMsg(TRANSLATE, 1)
+            self.initialOrientation[0], self.initialOrientation[1], _ = wm.Accelerometer.GetOrientation()
+        else:
+            self.sendMsg(TRANSLATE, 0)
+    
+    def onButtonB(self, wm, isDown):
+        if isDown:
+            self.sendMsg(RESIZE, 1)
+        else:
+            self.sendMsg(RESIZE, 0)
+    
+    def onButtonLeft(self, wm, isDown):
+        if isDown:
+            self.sendMsg(ROTATE, LEFT_ROTATE)
+    
+    def onButtonRight(self, wm, isDown):
+        if isDown:
+            self.sendMsg(ROTATE, RIGHT_ROTATE)
+            
+    def onButtonUp(self, wm, isDown):
+        if isDown:
+            self.sendMsg(CHANGE_Z, 1)
+            
+    def onButtonDown(self, wm, isDown):
+        if isDown:
+            self.sendMsg(CHANGE_Z, -1)
+    
+    def onButtonHome(self, wm, isDown):
+        if isDown:
+            self.sendMsg(FULLSCREEN)
+
+    def sendMsg(self, *data):
+        msg = ""
+        for m in data:
+            msg+=str(m)+" "
+        self.manager.sendMessage("wii", "wiimote", msg)            
+
+# you can optionally pass in a port number of the manager on command line
+port = 20005
+if len(sys.argv) < 2:
+    print "Usage: python " + sys.argv[0] + " sageIP"
+    sys.exit(0)
+elif len(sys.argv) > 2:
+    port = int(sys.argv[2])
+
+# start everything off
+Wiimote( ManagerConnection(sys.argv[1], port) )
+
+    
Index: trunk/src/testing/dim/hwcapture/joystick.py
===================================================================
--- trunk/src/testing/dim/hwcapture/joystick.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture/joystick.py	(revision 4)
@@ -0,0 +1,198 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+
+#### joysticks
+
+from managerConn import ManagerConnection
+import wx, time, sys
+
+
+#DEVICE_TYPE = "joystick"   # a plugin for this type must exist in "devices" called puck.py
+
+# types of messages sent to the manager
+MOVE = "1"
+BUTTON = "2"
+ARROW = "3"
+
+
+class Joystick:
+    def __init__(self, joyId, manager):
+        self.joy = wx.Joystick(joyId)
+
+        self.dontUse = False  # dont report this device
+        if self.joy.GetProductName().startswith('Nintendo'):
+            self.dontUse = True
+            
+        self.isFake = self.joy.GetProductName().startswith('PPJoy')
+        self.isWiimote = False
+        
+        if self.isFake:
+            # determine if it's a wii (PPJoy >= 13 is a wii)
+            self.isWiimote = int(self.joy.GetProductName().lstrip("PPJoy Virtual joystick ")) > 12
+            if self.isWiimote:
+                self.joyId = "joystick"+str(joyId)+"_wiimote"
+            else:
+                self.joyId = "joystick"+str(joyId)+"_fake"
+        else:
+            self.joyId = "joystick"+str(joyId)+"_real"
+
+        self.manager = manager
+        self.xAxis, self.yAxis, self.prevX, self.prevY = 0,0,0,0
+        self.buttons = [False, False, False]
+        self.pov = -1
+
+        # for dealing with drift
+        xmin = self.joy.GetXMin()
+        xmax = self.joy.GetXMax()
+        self.__range = abs(xmax - xmin)
+        self.__center = abs((xmin + xmax)/2.0) #so that 0 <-> max and -max/2 <-> max/2 both work
+        self.drift = 0.1 # maximum of 10% drift accounted for
+        if self.isFake: self.drift = 0.001
+        self.usefulRange = 1 - self.drift
+
+
+    def checkAxis(self):
+        (self.xAxis, self.yAxis) = self.joy.GetPosition()
+        self.__normalize()
+        self.__accountForDrift()
+            
+        # report if there has been change
+        if (not self.isWiimote and (self.xAxis != 0 or self.yAxis != 0)) or \
+               (self.isWiimote and (self.xAxis != self.prevX or self.yAxis != self.prevY)):
+            msg = MOVE +" "+str(self.xAxis)+" "+str(self.yAxis)
+            self.manager.sendMessage(self.joyId, "joystick", msg)
+
+        self.prevX, self.prevY = self.xAxis, self.yAxis   # remember for next time
+
+
+    def checkButtons(self):
+        bits = self.joy.GetButtonState()
+        buttons = [bits & 1 == 1, bits & 2 == 2, bits & 4 == 4]
+        for i in range(0,3):
+            if self.buttons[i] != buttons[i]:
+                self.buttons[i] = buttons[i]
+                msg = BUTTON+" "+str(i+1)+" "+str(int(buttons[i]))
+                self.manager.sendMessage(self.joyId, "joystick", msg)
+
+
+    def checkArrow(self):
+        pov = self.joy.GetPOVPosition()
+        if self.pov != pov:
+            self.pov = pov
+            if pov < 65000:  # ie NOT center
+                msg = ARROW+" "+str(pov)
+                self.manager.sendMessage(self.joyId, "joystick", msg)
+            
+
+
+    def __normalize(self):
+        """ map any type of coords to normalized coords in range -1 to 1 """
+        self.xAxis = ((self.xAxis - self.__center) / (self.__range/2.0))
+        self.yAxis = ((self.yAxis - self.__center) / (self.__range/2.0))
+                        
+        
+    def __accountForDrift(self):
+        x = self.xAxis
+        y = self.yAxis
+        
+        # apply the movement threshold and get the normalized crds
+        if abs(x) <= self.drift:
+            x = 0
+        else:
+            if x > 0:  x = float(x-self.drift)/self.usefulRange
+            else: x = float(x+self.drift)/self.usefulRange
+
+        if abs(y) <= self.drift:
+            y = 0
+        else:
+            if y > 0:  y = float(y-self.drift)/self.usefulRange
+            else: y = float(y+self.drift)/self.usefulRange
+
+        self.xAxis = x
+        self.yAxis = y
+
+            
+
+class CaptureJoysticks:
+    
+    def __init__(self, manager):
+        self.manager = manager
+        self.app = wx.App(redirect=False)
+        self.numJoy = wx.Joystick().GetNumberJoysticks()
+        if self.numJoy > 0:
+            self.createJoysticks()
+            self.capture()
+        else:
+            print "No joysticks connected..."
+            self.manager.quit()
+
+    def createJoysticks(self):
+        self.joysticks = []
+        for j in range(0,self.numJoy):
+            joy = Joystick(j, self.manager)
+            if not joy.dontUse:
+                self.joysticks.append( joy )
+            else:
+                del joy
+        
+    def capture(self):
+        while True:
+            for j in self.joysticks:
+                j.checkButtons()
+                j.checkAxis()
+                j.checkArrow()
+            time.sleep(1.0/40)
+
+
+
+
+# you can optionally pass in a port number of the manager on command line
+port = 20005
+if len(sys.argv) < 2:
+    print "Usage: python "+sys.argv[0]+" sageIP"
+    sys.exit(0)
+elif len(sys.argv) > 2:
+    port = int(sys.argv[2])
+
+# start everything off
+CaptureJoysticks( ManagerConnection(sys.argv[1], port) )
+    
Index: trunk/src/testing/dim/hwcapture/mouse_to_joy.PIE
===================================================================
--- trunk/src/testing/dim/hwcapture/mouse_to_joy.PIE	(revision 4)
+++ trunk/src/testing/dim/hwcapture/mouse_to_joy.PIE	(revision 4)
@@ -0,0 +1,310 @@
+//////////////////////////////////////////////////////////////////////////////////
+//
+// DIM - A Direct Interaction Manager for SAGE
+// Copyright (C) 2007 Electronic Visualization Laboratory,
+// University of Illinois at Chicago
+//
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//  * Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//  * Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following disclaimer
+//    in the documentation and/or other materials provided with the distribution.
+//  * Neither the name of the University of Illinois at Chicago nor
+//    the names of its contributors may be used to endorse or promote
+//    products derived from this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+//
+// Author: Ratko Jagodic
+//        
+////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+// A script for converting 5 mouse-like devices on the system to 5 virtual joysticks
+// For use with the device manager for SAGE
+//
+// Author: Ratko Jagodic
+// Date:   April, 2007
+//
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+// minimze upon startup
+//if var.minimized == 0
+//   MinimizePIE()
+//   var.minimized = 1
+//end if
+
+
+// when converting to joystick -1 <-> 1 axis values, we will
+// blank out the region -drift <-> +drift and start mapping
+// the values at +-var.drift up to +-1
+var.drift= 0.001 //001
+var.range= 400
+
+// mouse1 <-> ppjoy1
+   var.dx_1 = RemoveUnits(mouse1.DirectInputX) - var.oldX_1
+   var.dy_1 = RemoveUnits(mouse1.DirectInputY) - var.oldY_1
+
+   var.oldX_1 = RemoveUnits(mouse1.DirectInputX)
+   var.oldY_1 = RemoveUnits(mouse1.DirectInputY)
+   PPJoy1.analog0 = MapRange(var.dx_1, -var.range,var.range, -1,1)
+   PPJoy1.analog1 = MapRange(var.dy_1, -var.range,var.range, -1,1)
+   /*if Sign(var.dx_1) == -1 then
+      PPJoy1.analog0 = EnsureMapRange(var.dx_1, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_1)== 1 then
+      PPJoy1.analog0 = EnsureMapRange(var.dx_1, 1,var.range, var.drift,1)
+   else
+      PPJoy1.analog0 = 0
+   endif
+
+   if Sign(var.dy_1) == -1 then
+      PPJoy1.analog1 = EnsureMapRange(var.dy_1, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_1)== 1 then
+      PPJoy1.analog1 = EnsureMapRange(var.dy_1, 1,var.range, var.drift,1)
+   else
+      PPJoy1.analog1 = 0
+   endif
+       */
+   PPJoy1.digital1 = mouse1.LeftButton
+   PPJoy1.digital2 = mouse1.RightButton
+   PPJoy1.digital3 = mouse1.MiddleButton
+   mouse1.DirectInputX = 0
+   mouse1.DirectInputY = 0
+
+
+// mouse2 <-> ppjoy2
+   var.dx_2 = RemoveUnits(mouse2.DirectInputX) - var.oldX_2
+   var.dy_2 = RemoveUnits(mouse2.DirectInputY) - var.oldY_2
+
+   var.oldX_2 = RemoveUnits(mouse2.DirectInputX)
+   var.oldY_2 = RemoveUnits(mouse2.DirectInputY)
+
+   if Sign(var.dx_2) == -1 then
+      PPJoy2.analog0 = EnsureMapRange(var.dx_2, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_2)== 1 then
+      PPJoy2.analog0 = EnsureMapRange(var.dx_2, 1,var.range, var.drift,1)
+   else
+      PPJoy2.analog0 = 0
+   endif
+
+   if Sign(var.dy_2) == -1 then
+      PPJoy2.analog1 = EnsureMapRange(var.dy_2, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_2)== 1 then
+      PPJoy2.analog1 = EnsureMapRange(var.dy_2, 1,var.range, var.drift,1)
+   else
+      PPJoy2.analog1 = 0
+   endif
+
+   PPJoy2.digital1 = mouse2.LeftButton
+   PPJoy2.digital2 = mouse2.RightButton
+   PPJoy2.digital3 = mouse2.MiddleButton
+   mouse2.DirectInputX = 0
+   mouse2.DirectInputY = 0
+
+
+// mouse3 <-> ppjoy3
+   var.dx_3 = RemoveUnits(mouse3.DirectInputX) - var.oldX_3
+   var.dy_3 = RemoveUnits(mouse3.DirectInputY) - var.oldY_3
+
+   var.oldX_3 = RemoveUnits(mouse3.DirectInputX)
+   var.oldY_3 = RemoveUnits(mouse3.DirectInputY)
+
+   if Sign(var.dx_3) == -1 then
+      PPJoy3.analog0 = EnsureMapRange(var.dx_3, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_3)== 1 then
+      PPJoy3.analog0 = EnsureMapRange(var.dx_3, 1,var.range, var.drift,1)
+   else
+      PPJoy3.analog0 = 0
+   endif
+
+   if Sign(var.dy_3) == -1 then
+      PPJoy3.analog1 = EnsureMapRange(var.dy_3, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_3)== 1 then
+      PPJoy3.analog1 = EnsureMapRange(var.dy_3, 1,var.range, var.drift,1)
+   else
+      PPJoy3.analog1 = 0
+   endif
+
+   PPJoy3.digital1 = mouse3.LeftButton
+   PPJoy3.digital2 = mouse3.RightButton
+   PPJoy3.digital3 = mouse3.MiddleButton
+   mouse3.DirectInputX = 0
+   mouse3.DirectInputY = 0
+
+
+// mouse4 <-> ppjoy4
+   var.dx_4 = RemoveUnits(mouse4.DirectInputX) - var.oldX_4
+   var.dy_4 = RemoveUnits(mouse4.DirectInputY) - var.oldY_4
+
+   var.oldX_4 = RemoveUnits(mouse4.DirectInputX)
+   var.oldY_4 = RemoveUnits(mouse4.DirectInputY)
+
+   if Sign(var.dx_4) == -1 then
+      PPJoy4.analog0 = EnsureMapRange(var.dx_4, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_4)== 1 then
+      PPJoy4.analog0 = EnsureMapRange(var.dx_4, 1,var.range, var.drift,1)
+   else
+      PPJoy4.analog0 = 0
+   endif
+
+   if Sign(var.dy_4) == -1 then
+      PPJoy4.analog1 = EnsureMapRange(var.dy_4, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_4)== 1 then
+      PPJoy4.analog1 = EnsureMapRange(var.dy_4, 1,var.range, var.drift,1)
+   else
+      PPJoy4.analog1 = 0
+   endif
+
+   PPJoy4.digital1 = mouse4.LeftButton
+   PPJoy4.digital2 = mouse4.RightButton
+   PPJoy4.digital3 = mouse4.MiddleButton
+   mouse4.DirectInputX = 0
+   mouse4.DirectInputY = 0
+
+
+// mouse5 <-> ppjoy5
+   var.dx_5 = RemoveUnits(mouse5.DirectInputX) - var.oldX_5
+   var.dy_5 = RemoveUnits(mouse5.DirectInputY) - var.oldY_5
+
+   var.oldX_5 = RemoveUnits(mouse5.DirectInputX)
+   var.oldY_5 = RemoveUnits(mouse5.DirectInputY)
+
+   if Sign(var.dx_5) == -1 then
+      PPJoy5.analog0 = EnsureMapRange(var.dx_5, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_5)== 1 then
+      PPJoy5.analog0 = EnsureMapRange(var.dx_5, 1,var.range, var.drift,1)
+   else
+      PPJoy5.analog0 = 0
+   endif
+
+   if Sign(var.dy_5) == -1 then
+      PPJoy5.analog1 = EnsureMapRange(var.dy_5, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_5)== 1 then
+      PPJoy5.analog1 = EnsureMapRange(var.dy_5, 1,var.range, var.drift,1)
+   else
+      PPJoy5.analog1 = 0
+   endif
+
+   PPJoy5.digital1 = mouse5.LeftButton
+   PPJoy5.digital2 = mouse5.RightButton
+   PPJoy5.digital3 = mouse5.MiddleButton
+   mouse5.DirectInputX = 0
+   mouse5.DirectInputY = 0
+
+
+// mouse6 <-> ppjoy6
+   var.dx_6 = RemoveUnits(mouse6.DirectInputX) - var.oldX_6
+   var.dy_6 = RemoveUnits(mouse6.DirectInputY) - var.oldY_6
+
+   var.oldX_6 = RemoveUnits(mouse6.DirectInputX)
+   var.oldY_6 = RemoveUnits(mouse6.DirectInputY)
+
+   if Sign(var.dx_6) == -1 then
+      PPJoy6.analog0 = EnsureMapRange(var.dx_6, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_6)== 1 then
+      PPJoy6.analog0 = EnsureMapRange(var.dx_6, 1,var.range, var.drift,1)
+   else
+      PPJoy6.analog0 = 0
+   endif
+
+   if Sign(var.dy_6) == -1 then
+      PPJoy6.analog1 = EnsureMapRange(var.dy_6, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_6)== 1 then
+      PPJoy6.analog1 = EnsureMapRange(var.dy_6, 1,var.range, var.drift,1)
+   else
+      PPJoy6.analog1 = 0
+   endif
+
+   PPJoy6.digital1 = mouse6.LeftButton
+   PPJoy6.digital2 = mouse6.RightButton
+   PPJoy6.digital3 = mouse6.MiddleButton
+   mouse6.DirectInputX = 0
+   mouse6.DirectInputY = 0
+
+
+
+// mouse7 <-> ppjoy7
+   var.dx_7 = RemoveUnits(mouse7.DirectInputX) - var.oldX_7
+   var.dy_7 = RemoveUnits(mouse7.DirectInputY) - var.oldY_7
+
+   var.oldX_7 = RemoveUnits(mouse7.DirectInputX)
+   var.oldY_7 = RemoveUnits(mouse7.DirectInputY)
+
+   if Sign(var.dx_7) == -1 then
+      PPJoy7.analog0 = EnsureMapRange(var.dx_7, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_7)== 1 then
+      PPJoy7.analog0 = EnsureMapRange(var.dx_7, 1,var.range, var.drift,1)
+   else
+      PPJoy7.analog0 = 0
+   endif
+
+   if Sign(var.dy_7) == -1 then
+      PPJoy7.analog1 = EnsureMapRange(var.dy_7, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_7)== 1 then
+      PPJoy7.analog1 = EnsureMapRange(var.dy_7, 1,var.range, var.drift,1)
+   else
+      PPJoy7.analog1 = 0
+   endif
+
+   PPJoy7.digital1 = mouse7.LeftButton
+   PPJoy7.digital2 = mouse7.RightButton
+   PPJoy7.digital3 = mouse7.MiddleButton
+   mouse7.DirectInputX = 0
+   mouse7.DirectInputY = 0
+
+
+
+// mouse8 <-> ppjoy8
+   var.dx_8 = RemoveUnits(mouse8.DirectInputX) - var.oldX_8
+   var.dy_8 = RemoveUnits(mouse8.DirectInputY) - var.oldY_8
+
+   var.oldX_8 = RemoveUnits(mouse8.DirectInputX)
+   var.oldY_8 = RemoveUnits(mouse8.DirectInputY)
+
+   if Sign(var.dx_8) == -1 then
+      PPJoy8.analog0 = EnsureMapRange(var.dx_8, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dx_8)== 1 then
+      PPJoy8.analog0 = EnsureMapRange(var.dx_8, 1,var.range, var.drift,1)
+   else
+      PPJoy8.analog0 = 0
+   endif
+
+   if Sign(var.dy_8) == -1 then
+      PPJoy8.analog1 = EnsureMapRange(var.dy_8, -var.range,1, -1,-var.drift)
+   elseif Sign(var.dy_8)== 1 then
+      PPJoy8.analog1 = EnsureMapRange(var.dy_8, 1,var.range, var.drift,1)
+   else
+      PPJoy8.analog1 = 0
+   endif
+
+   PPJoy8.digital1 = mouse8.LeftButton
+   PPJoy8.digital2 = mouse8.RightButton
+   PPJoy8.digital3 = mouse8.MiddleButton
+   mouse8.DirectInputX = 0
+   mouse8.DirectInputY = 0
+
+mouse.Swallow = true
+
+
+
Index: trunk/src/testing/dim/hwcapture/go.bat
===================================================================
--- trunk/src/testing/dim/hwcapture/go.bat	(revision 4)
+++ trunk/src/testing/dim/hwcapture/go.bat	(revision 4)
@@ -0,0 +1,4 @@
+start c:\Python25\python.exe  joystick.py 67.58.62.40
+
+start C:\GlovePIE029\GlovePIE.exe -mouse_to_joy.PIE
+
Index: trunk/src/testing/dim/hwcapture/pucks.py
===================================================================
--- trunk/src/testing/dim/hwcapture/pucks.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture/pucks.py	(revision 4)
@@ -0,0 +1,177 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+####  lambdatable pucks
+
+from managerConn import ManagerConnection
+import sys, socket, os
+from threading import Thread
+
+
+TRACKING_PORT = 7000  # where the tracker will send UDP data to
+#DEVICE_TYPE = "puck"   # a plugin for this type must exist in "devices" called puck.py
+
+os.chdir(sys.path[0])
+
+class Puck:
+    """ describes one puck """
+    
+    def __init__(self, puckId, x, y, angle, puckType):
+        self.puckId = puckId
+        self.puckType = puckType  # not covered
+        self.x = x   # normalized coords
+        self.y = y   # normalized coords
+        self.angle = angle  # in degrees
+        self.name = "puck"+str(puckId)
+
+        
+    def setAll(self, x, y, angle, puckType):
+        """ returns True if there was a change in any data
+            False otherwise
+        """
+        change = False
+        
+        if self.puckType != puckType: change=True
+        self.puckType = puckType
+
+        if self.x != x: change=True
+        self.x = x
+
+        if self.y != y: change=True
+        self.y = y
+
+        if self.angle != angle: change=True
+        self.angle = angle
+
+        return change
+        
+    
+
+
+class CapturePucks:
+    
+    def __init__(self, manager):
+        self.manager = manager
+        self.pucks = {}  # keyed by ID, value=Puck object
+
+        # create the tracker server for receiving puck data
+        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self.socket.bind(('', TRACKING_PORT))
+        self.socket.settimeout(0.1)
+
+        # some vars
+        self.threadKilled = False
+
+        # start listening for connections in a thread
+        self.t = Thread(target=self.receiver, args=())
+        self.t.start()
+
+
+    def stop(self):
+        self.threadKilled = True
+        self.t.join()
+
+
+    def receiver(self):
+        MSG_SIZE = 60
+        while not self.threadKilled:
+            try:
+                
+                msgString = ""
+                while len(msgString) < MSG_SIZE:
+                    msgString += self.socket.recv(MSG_SIZE)      # receive the fixed message size
+
+                if len(msgString) < 2:
+                    self.stop()
+                    break
+
+                # record only the first reported position OR
+                # record all of them based on the callback variable
+                elif len(msgString) == MSG_SIZE:
+                    msg = msgString.replace('\x00', '').strip()   # remove the NULLs
+                    self.processPuckData(msg)                    
+                    
+            except socket.timeout:
+                pass    # do nothing since it's just a timeout...
+            except socket.error:
+                #print "socket error in connection with the tracker..."
+                #self.stop()
+                continue
+                
+        self.socket.close()
+
+
+    def processPuckData(self, msg):
+        #print "msg = ", msg
+        tokens = msg.split()
+        ## puckId =   int(msg[ 11:21 ].strip())
+##         x =      float(msg[ 21:31 ].strip())
+##         y =      float(msg[ 31:41 ].strip())
+##         angle =  float(msg[ 41:51 ].strip())
+##         puckType = int(msg[ 51:61 ].strip())
+
+        puckId =   int(tokens[1].strip())
+        x =      float(tokens[2].strip())
+        y =      float(tokens[3].strip())
+        angle =  float(tokens[4].strip())
+        puckType = int(tokens[5].strip())
+
+        # send a message to the manager only if it's a new puck or the state of
+        # an existing one changed
+        if not puckId in self.pucks:
+            p = Puck(puckId, x, y, angle, puckType)
+            self.pucks[puckId] = p
+            self.manager.sendMessage(p.name, "puck", msg)
+        else:
+            p = self.pucks[puckId]
+            if p.setAll(x, y, angle, puckType):
+                self.manager.sendMessage(p.name, "puck", msg)
+
+        
+
+# you can optionally pass in a port number of the manager on command line
+port = 20005
+if len(sys.argv) > 2:
+    port = int(sys.argv[2])
+
+# start everything off
+CapturePucks( ManagerConnection(sys.argv[1], port) )
+    
Index: trunk/src/testing/dim/hwcapture/managerConn.py
===================================================================
--- trunk/src/testing/dim/hwcapture/managerConn.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture/managerConn.py	(revision 4)
@@ -0,0 +1,188 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import socket, time
+from threading import Thread
+import traceback as tb
+import signal
+
+
+# some globals
+thisMachine = socket.gethostbyname(socket.gethostname())
+TIMEOUT_INTERVAL = 3    # seconds
+
+
+
+
+class ManagerConnection:
+    """ This should be imported by the hwcapture code and
+        used to send the data to the device manager
+    """
+    
+    def __init__(self, host, port=20005):
+        #self.connections = {}   # key=host, value=OneConnection object
+        self.conn = OneConnection(host, port, doReconnect=True)
+        
+
+##     def newConnection(self, host, port):
+##         # make the initial connection to the manager we specify
+        
+##         conn = OneConnection(host, port)
+##         if host in self.connections:
+##             self.connections[host].disconnect()
+##             del self.connections[host]
+##         self.connections[host] = conn
+##         conn.start()
+        
+
+    
+    def quit(self):
+        #print "quitting"
+        self.conn.quit()
+
+
+    def sendMessage(self, deviceName, deviceType, data):
+        """ - deviceName can be anything but it needs to be unique to this machine
+            (for example: mouse1)
+        """
+        deviceId = thisMachine+":"+str(deviceName)
+        msg = deviceId + " " + deviceType + " " + data + "\n"
+        self.conn.sendMessage(msg)
+        
+
+
+
+
+
+
+class OneConnection:
+    """ This is just one connection to the device manager """
+    
+    def __init__(self, host, port, doReconnect):
+        self.doReconnect = doReconnect
+        self.host = host
+        self.port = int(port)
+        self.connected = False
+        self.doConnecting = True
+        
+        # connect thread that's constantly running
+        self.connThread = Thread(target=self.connectThread)
+        self.connThread.start()
+
+
+    def quit(self):
+        self.doConnecting = False
+        
+
+    def connectThread(self):
+        while self.doConnecting:
+            
+            if not self.connected:
+                # set up the socket
+                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.sock.settimeout(TIMEOUT_INTERVAL)
+
+                # try connecting now
+                try:
+                    self.sock.connect( (self.host, self.port) )
+
+                    # connection successful so start the receiving thread
+                    self.connected = True
+                    print "Connected to: ", self.host
+                    ## self.receiverThread = Thread(target=self.receiver)
+##                     self.receiverThread.start()
+                    
+                except socket.error:
+                    if not self.doReconnect:
+                        break   # one time connections should only connect once
+                    else:
+                        print "Trying to connect to: ", self.host
+                    time.sleep(4)  # try reconnecting every 4 seconds
+                                    
+            elif self.doReconnect:    # we are currently connected and we want to reconnect if connection breaks
+                time.sleep(1)  # don't loop like crazy if we are connected already
+
+            else:   # we are connected but we don't want to reconnect if connection breaks
+                break
+            
+
+    def disconnect(self):
+        self.sock.close()
+        self.connected = False
+
+
+    def sendMessage(self, msg):
+        """ try to send the message. Return False if not sent, True otherwise
+            *******************************
+            ******* NOT THREAD SAFE *******
+            *******************************
+        """
+        if not self.connected:  return False
+
+        try:
+            self.sock.sendall(msg)
+        except socket.error:
+            #print "unable to send message... socket error"
+            self.disconnect()
+            return False
+        except:
+            tb.print_exc()
+            return False
+            
+        return True
+
+
+    def __sendPing(self):
+        self.sendMessage(" \n")
+            
+
+   ##  def receiver(self):
+##         """ in separate thread """
+        
+##         while self.connected:
+
+##             try:
+                
+##             except socket.timeout:
+##                 self.__sendPing()
+##                 continue
+
+
Index: trunk/src/testing/dim/hwcapture/localPointer.py
===================================================================
--- trunk/src/testing/dim/hwcapture/localPointer.py	(revision 4)
+++ trunk/src/testing/dim/hwcapture/localPointer.py	(revision 4)
@@ -0,0 +1,171 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import sys, wx
+#sys.path.append("../dim/hwcapture")
+from managerConn import ManagerConnection
+from threading import Timer
+import time
+
+#if len(sys.argv) > 2:
+SHOW_WINDOW = True
+#else:
+#    SHOW_WINDOW = False
+
+MOVE = 1
+CLICK = 2
+WHEEL = 3
+
+LEFT=1
+RIGHT=2
+MIDDLE = 3  
+
+global lastX, lastY
+lastX = lastY = 0
+global frame, manager, panel, buttons, w, h, label
+buttons = {}  #key=BTN_ID, value=True|False
+
+
+def sendMsg(*data):
+    msg = ""
+    for m in data:
+        msg+=str(m)+" "
+    manager.sendMessage("", "mouse", msg)
+
+
+def onKey(event):
+    if event.GetKeyCode() == wx.WXK_ESCAPE:
+        if panel.HasCapture():
+            panel.ReleaseMouse()
+        frame.Close()
+    elif event.GetKeyCode() == wx.WXK_SPACE:
+        global label
+        if panel.HasCapture():
+            label.SetLabel("Press SPACE to capture mouse")
+            panel.ReleaseMouse()
+        else:
+            label.SetLabel("Press SPACE to release mouse")
+            panel.CaptureMouse()
+
+
+def onMove(event):
+    global lastX, lastY
+    ms = wx.GetMouseState()
+    mx = ms.GetX()
+    my = ms.GetY()
+    x = float(mx/float(w))
+    y = 1-float(my/float(h))
+    if lastX != x or lastY != y:
+        sendMsg(MOVE, x,y)
+        lastX = x
+        lastY = y
+
+
+def onClick(event):
+    isDown=False
+    if event.ButtonDown():  isDown=True
+
+    if event.GetButton() == wx.MOUSE_BTN_LEFT:
+        btnId = LEFT
+    elif event.GetButton() == wx.MOUSE_BTN_RIGHT:
+        btnId = RIGHT
+    else:
+        btnId = MIDDLE
+
+    sendMsg(CLICK, btnId, int(isDown))
+
+
+def onWheel(event):
+    numSteps = event.GetWheelRotation()/event.GetWheelDelta()
+    sendMsg(WHEEL, numSteps)
+            
+
+def onClose(event):
+    manager.quit()
+    frame.Destroy()
+    wx.GetApp().ExitMainLoop()
+
+
+def doCapture():
+    wx.CallAfter(panel.CaptureMouse)
+    
+
+# runs in a thread, captures mouse position and sends to dim regularly
+def captureMouse(mgr):
+    app = wx.App()
+    
+    global manager,w,h
+    manager = mgr
+
+    (w,h) = wx.DisplaySize()
+
+    if SHOW_WINDOW:
+        global frame, panel, label
+        frame = wx.Frame(None, size=(250,80), pos=(100,100))
+        frame.Bind(wx.EVT_CLOSE, onClose)
+        
+        panel = wx.Panel(frame, size=(250,80), pos=(0,0))
+        panel.Bind(wx.EVT_KEY_DOWN, onKey)
+        panel.Bind(wx.EVT_LEFT_DOWN, onClick)
+        panel.Bind(wx.EVT_LEFT_UP, onClick)
+        panel.Bind(wx.EVT_RIGHT_DOWN, onClick)
+        panel.Bind(wx.EVT_RIGHT_UP, onClick)
+        panel.Bind(wx.EVT_MOTION, onMove)
+        panel.Bind(wx.EVT_MOUSEWHEEL, onWheel)
+
+        #label = wx.StaticText(panel, wx.ID_ANY, "Press SPACE to release mouse")
+        label = wx.StaticText(panel, wx.ID_ANY, "Press SPACE to capture mouse")
+        panel.Fit()
+        panel.SetFocus()
+
+        #t = Timer(2.0, doCapture)
+        #t.start()
+              
+        frame.Show()
+        app.MainLoop()
+#    else:
+#        while True:
+#            onIdle()
+    
+if len(sys.argv) < 2:
+    print "USAGE: python localPointer.py SAGE_IP"
+else:
+    print "Connecting to: ", sys.argv[1]
+    captureMouse(ManagerConnection(sys.argv[1], 20005))
Index: trunk/src/testing/dim/eventManager.py
===================================================================
--- trunk/src/testing/dim/eventManager.py	(revision 4)
+++ trunk/src/testing/dim/eventManager.py	(revision 4)
@@ -0,0 +1,182 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from threading import RLock
+from globals import *
+import traceback as tb
+import sys
+from events import *
+
+
+
+class EventManager:
+    """ receives all the events and then forwards them to
+        all the event handlers that want them
+    """
+
+    def __init__(self):
+        self.evtLock = RLock()
+        self.__evtHandlers = {}   # keyed by eventId, value=list of callbacks
+
+        # add other handlers
+        #self.__addHandlers()
+
+
+    def addHandlers(self):
+        """ you can add evtHandlers here manually """
+
+
+    def __onDisplayInfo(self, evt):
+        di = evt.displayInfo
+        for display in di.getAllDisplays():
+            self.__importHandlerPlugin("wall").makeNew(display.getId())  # one for each display
+
+
+    def __importHandlerPlugin(self, name):
+        plugin = __import__("overlays."+name, globals(), locals(), [name])
+        return plugin
+        
+
+    def register(self, eventId, callback):
+        """ register the evtHandler to receive events of eventId """
+        if eventId not in self.__evtHandlers:
+            self.__evtHandlers[eventId] = []
+        self.__evtHandlers[eventId].append( callback )
+
+
+    def unregister(self, callbackHash):
+        """ unregisters the evtHandler from the specified events """
+        for eventId, callback in callbackHash.iteritems():
+            try:
+                self.__evtHandlers[eventId].remove(callback)
+            except:
+                continue
+            
+
+    def postEvent(self, event):
+        """ thread safe """
+        self.evtLock.acquire()
+        
+        # handle differently depending on whether
+        # it's a device event or a generic event
+        if event.eventId in self.__evtHandlers:
+            if event.eventType == DEVICE_EVENT:
+                self.__sendToSingleEvtHandler(event)
+            else:
+                if event.eventType == EVT_DISPLAY_INFO:
+                    self.__onDisplayInfo(event)   # create objects that are display dependent
+                    
+                self.__sendToMultipleEvtHandler(event)
+            
+        self.evtLock.release()
+
+
+    def getCallbackAtPos(self, event):
+        """ returns the callback function for the specified event at pos x,y
+            Or None if no suitable evtHandler was found at that position
+            Considers z ordering
+        """
+        currentCandidate = None  # the candidate based on the z value
+        lastZ = BOTTOM_Z
+        x, y, eventId, displayId = event.x, event.y, event.eventId, event.device.displayId
+        
+        
+        if eventId in self.__evtHandlers:
+            for callback in self.__evtHandlers[eventId]:
+                evtHandler = callback.im_self
+                if evtHandler.displayId == displayId and \
+                       evtHandler.z < lastZ and \
+                       evtHandler.bounds.isIn(x,y):
+                    currentCandidate = callback
+                    lastZ = evtHandler.z
+
+        # check if the handler is already captured
+        if currentCandidate and currentCandidate.im_self.captured:
+            return None
+        
+        return currentCandidate
+                
+
+    def __sendToSingleEvtHandler(self, event):
+        """ forward the event to a handler that is at the position
+            of the event and wants the current event
+        """
+        eventId = event.eventId
+        device = event.device
+        
+        # if the event goes to a specific evtHandler, no need to search for one
+        if event.toEvtHandler:
+            callback = event.toEvtHandler.getCallback(eventId)
+        else:
+            callback = self.getCallbackAtPos(event)
+                
+            # this is here to generate EVT_ENTERED_WINDOW and EVT_LEFT_WINDOW
+            if eventId == EVT_MOVE or eventId == EVT_MOVE_SPECIAL:
+                if callback != device.lastMoveCallback:   # window changed
+                    if device.lastMoveCallback:
+                        evtId = EVT_LEFT_WINDOW
+                        if device.specialDevice: evtId = EVT_LEFT_WINDOW_SPECIAL
+                        self.__sendEvent(WindowLeftEvent(device),
+                                         device.lastMoveCallback.im_self.getCallback(evtId))
+                    if callback:
+                        evtId = EVT_ENTERED_WINDOW
+                        if device.specialDevice: evtId = EVT_ENTERED_WINDOW_SPECIAL
+                        self.__sendEvent(WindowEnteredEvent(device),
+                                         callback.im_self.getCallback(evtId))
+                    device.lastMoveCallback = callback
+                    
+        # send the original event
+        self.__sendEvent(event, callback)
+        
+
+    def __sendToMultipleEvtHandler(self, event):
+        """ forward to all the evtHandlers registered for this eventId """
+        for callback in self.__evtHandlers[event.eventId]:
+            self.__sendEvent(event, callback)
+
+
+    def __sendEvent(self, event, callback):
+        """ executes callback with event as a parameter """
+        if callback:
+            try:
+                callback(event)
+            except AttributeError:   # if the object doesn't exist anymore, remove its callback
+                tb.print_exc()
+                self.__evtHandlers[event.eventId].remove(callback)
Index: trunk/src/testing/dim/overlayManager.py
===================================================================
--- trunk/src/testing/dim/overlayManager.py	(revision 4)
+++ trunk/src/testing/dim/overlayManager.py	(revision 4)
@@ -0,0 +1,189 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from globals import *
+from threading import RLock
+import os, os.path
+
+
+
+class OverlayManager:
+    """ creates and deletes all overlays """
+
+    def __init__(self):
+        self.overlays = {}            # key=overlayId, value=overlay objects
+        self.__appOverlays = {}       # key=appId, value=list of overlayIds
+        self.evtMgr = getEvtMgr()
+        self.sageGate = getSageGate()
+        self.addOverlayLock = RLock()  # for adding one overlay at a time
+        self.addOverlayQueue = []
+
+        # load all the plugins now
+        self.__overlayPlugins = {}  # key=overlayType, value=overlayPlugin
+        self.__loadAllPlugins()
+        
+        # register for events
+        self.evtMgr.register(EVT_NEW_APP, self.__onNewApp)
+        self.evtMgr.register(EVT_APP_KILLED, self.__onAppKilled)
+        self.evtMgr.register(EVT_OBJECT_INFO, self.__onObjectInfo)
+
+        # add other overlays
+        self.__addOverlays()
+        
+        self.specialDevice = 0
+        
+    def __addOverlays(self):
+        """ you can add overlays here manually """
+        pass
+        
+        
+    def __onNewApp(self, event):
+        """ add the overlays that need to be tied to the app """
+        self.__appOverlays[event.app.getId()] = []   # create the list for keeping overlays
+        self.addOverlay(OVERLAY_APP, None, event.app)
+
+
+    def __onAppKilled(self, event):
+        """ remove the overlays tied to the app """
+        appId = event.app.getId() 
+        if appId in self.__appOverlays:
+            for overlayId in self.__appOverlays[appId]:
+                self.overlays[overlayId].destroy()
+                self.removeOverlay(overlayId)
+            del self.__appOverlays[appId]
+
+  
+    def __onObjectInfo(self, event):
+        """ the overlay was successfully added by SAGE and we got the overlayId """
+        self.addOverlayLock.acquire()
+        overlayType, callback, app, displayId = self.addOverlayQueue.pop(0)
+
+        # now add a new one (if there are any)
+        if len(self.addOverlayQueue) > 0:
+            # determine the draw order
+            drawOrder = INTER_DRAW   #inter draw
+            if overlayType == OVERLAY_POINTER:
+                drawOrder = POST_DRAW
+            elif overlayType == OVERLAY_WALL:
+                drawOrder = PRE_DRAW
+            self.sageGate.addOverlay(self.addOverlayQueue[0][0],100,100,100,100, True, drawOrder, displayId)
+        self.addOverlayLock.release()
+
+        # if overlayPlugin isn't loaded yet 
+        if overlayType not in self.__overlayPlugins:  
+            if not self.__loadOverlayPlugin( overlayType ):
+                return   # couldn't load the plugin
+
+        # at this point we have a plugin loaded so create an overlay object
+        if app: # is the overlay tied to the application? 
+            newOverlayObj = self.__overlayPlugins[ overlayType ].makeNew(event.overlayId, app)
+            self.__appOverlays[app.getId()].append(event.overlayId)
+        else:
+            newOverlayObj = self.__overlayPlugins[ overlayType ].makeNew(event.overlayId)
+        self.overlays[ event.overlayId ] = newOverlayObj
+        if self.specialDevice == 1:
+            self.overlays[event.overlayId].setSpecialDevice(1)
+
+        # finally report back to the entity that requested the overlay
+        if callback:
+            callback(newOverlayObj)
+
+    def setSpecialDevice(self, value):
+        for i in self.overlays:
+            self.overlays[i].setSpecialDevice(value)
+        self.specialDevice = value
+
+    def removeOverlay(self, overlayId):
+        """ removes the overlay from SAGE and locally """
+        self.sageGate.removeOverlay(overlayId)
+        if overlayId in self.overlays:
+            del self.overlays[overlayId]
+
+
+    def removeAllOverlays(self):
+        for overlayId in self.overlays.keys():
+            self.removeOverlay(overlayId)
+            
+
+    def addOverlay(self, overlayType, callback=None, app=None, displayId=0):
+        """ specify an optional callback to call once the
+            overlay is successfully added by SAGE
+            Specify an app if you want the overlay to be tied to an application
+            (if so it will be deleted when the app is closed)
+        """
+        self.addOverlayLock.acquire()
+
+        # determine the draw order
+        drawOrder = INTER_DRAW   #inter draw
+        if overlayType == OVERLAY_POINTER:
+            drawOrder = POST_DRAW     
+        elif overlayType == OVERLAY_WALL:
+            drawOrder = PRE_DRAW
+            
+        # if this is the only thing to add, just do it now
+        # otherwise it will be added by the __onObjectInfo when the previous one gets added
+        self.addOverlayQueue.append((overlayType, callback, app, displayId))
+        if len(self.addOverlayQueue) == 1:
+            self.sageGate.addOverlay(overlayType,0,0,100,100, True, drawOrder, displayId)
+            
+        self.addOverlayLock.release()
+
+
+        
+    def __loadAllPlugins(self):
+        """ goes into the 'overlays' directory and loads all the plugins from there """
+
+        for entry in os.listdir("overlays"):
+            if os.path.splitext(entry)[1] == ".py" and entry != "__init__.py":
+                self.__loadOverlayPlugin( os.path.splitext(entry)[0] )
+            
+
+    def __loadOverlayPlugin(self, overlayType):
+        """ try to load the overlayPlugin for the requested overlayType """
+        try:
+            overlayPlugin = __import__("overlays."+overlayType, globals(), locals(), [overlayType])
+            self.__overlayPlugins[ overlayType ] = overlayPlugin
+            print "Overlay plugin loaded: ", overlayType
+            return True
+        
+        except ImportError:
+            return False   # failed to load the module
+
+    
Index: trunk/src/testing/dim/overlays/wall.py
===================================================================
--- trunk/src/testing/dim/overlays/wall.py	(revision 4)
+++ trunk/src/testing/dim/overlays/wall.py	(revision 4)
@@ -0,0 +1,100 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+from eventHandler import EventHandler
+from overlay import Overlay
+from globals import *
+
+WALL_RESOLUTION = 0;
+
+
+
+def makeNew(overlayId):
+    """ this is how we instantiate the object from
+        the main program that loads this plugin """
+    return Wall(overlayId)
+
+
+
+class Wall(EventHandler, Overlay):
+
+    def __init__(self, overlayId):
+        Overlay.__init__(self, OVERLAY_WALL, overlayId)
+        EventHandler.__init__(self)
+#        self.displayId = displayId
+        #self.registerForEvent(EVT_MOVE, self.__onMove)
+        self.registerForEvent(EVT_DISPLAY_INFO, self.__onDispInfo)
+        self.registerForEvent(EVT_OBJECT_INFO, self.__onObjectInfo)
+        self.registerForEvent(EVT_ENTERED_WINDOW, self.__onEnteredWindow)
+        self.registerForEvent(EVT_LEFT_WINDOW, self.__onLeftWindow)
+        self.z = BOTTOM_Z
+
+##     def __onMove(self, event):
+##         """ just resets the pointer for now """
+##         device = event.device
+##         if device.pointer:
+##             device.pointer.resetPointer()
+##             device.pointer.showOutApp()
+
+    def __onLeftWindow(self, event):
+        pass
+        
+
+    def __onEnteredWindow(self, event):
+        pointer = event.device.pointer
+        if pointer:
+            event.device.pointer.resetPointer()
+            event.device.pointer.showOutApp()
+    
+
+    def __onDispInfo(self, event):
+        di = event.displayInfo
+        display = di.getDisplay(self.displayId)
+        self.bounds.setAll(0, display.sageW, display.sageH, 0)
+        
+    def __onObjectInfo(self, event):
+        width = (getSageData().getDisplayInfo().sageW)
+        height = (getSageData().getDisplayInfo().sageH)
+        
+        #!!!Dirty hack for installation in WestPoint!!!
+        width = 8*width/9
+        
+        self.sendOverlayMessage(WALL_RESOLUTION,width,height)
Index: trunk/src/testing/dim/overlays/app.py
===================================================================
--- trunk/src/testing/dim/overlays/app.py	(revision 4)
+++ trunk/src/testing/dim/overlays/app.py	(revision 4)
@@ -0,0 +1,583 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from overlay import Overlay
+from eventHandler import EventHandler
+from globals import *
+from math import cos, sin, radians
+from wx._core import EVT_ENTER_WINDOW
+
+
+def makeNew(overlayId, app):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return App(overlayId, app)
+
+
+
+# pointer states
+RESET  = 0
+DRAG   = 1
+RESIZE = 2
+DOWN   = 3
+UP     = 4
+
+Z_CHANGE = 3
+ON_CORNER = 4
+
+ON_APP = 5
+
+ROTATE = 6
+
+FULLSCREEN = 5
+
+
+# corner orientations
+APP          = 0
+APP_BOTTOM   = -2
+APP_TOP      = -1
+BOTTOM_LEFT  = 1
+TOP_LEFT     = 2
+TOP_RIGHT    = 3
+BOTTOM_RIGHT = 4
+
+
+
+class App(Overlay, EventHandler):
+    
+    def __init__(self, overlayId, app):
+        Overlay.__init__(self, OVERLAY_APP, overlayId)
+        EventHandler.__init__(self)
+        self.app = app   # which app is this overlay tied to
+        self.bounds.setAll(app.left, app.right, app.top, app.bottom)
+        self.displayId = app.getDisplayId()
+        self.aspectRatio = self.bounds.getWidth() / float(self.bounds.getHeight())
+        self.minAppSize = 300   # min app size in either direction
+        self.z = self.app.getZvalue()
+        self.__resetOverlay()
+        self.capturedCorner = APP
+        self.lastClickPos = (0,0)
+        self.lastClickDeviceId = None
+        self.overCorner = APP
+        
+        self.lastClickAction = 0
+        
+        self.modifyTicks = 0
+                
+        # register for the events that are fired when an app changes
+        self.registerForEvent(EVT_APP_INFO, self.__onAppChanged)
+        self.registerForEvent(EVT_Z_CHANGE, self.__onZChanged)
+
+        # register for the events that are fired by devices
+        self.registerForEvent(EVT_MOVE, self.__onOver)
+        self.registerForEvent(EVT_CLICK, self.__onClick)
+        self.registerForEvent(EVT_DRAG, self.__onDrag)
+        self.registerForEvent(EVT_ROTATE, self.__onRotate)
+        self.registerForEvent(EVT_ZOOM, self.__onZoom)
+        self.registerForEvent(EVT_ARROW, self.__onArrow)
+        self.registerForEvent(EVT_LEFT_WINDOW, self.__onLeftWindow)
+
+        # register for the events from the special devices
+        self.registerForEvent(EVT_MOVE_SPECIAL, self.__onSpecialMove)
+        self.registerForEvent(EVT_DRAG_SPECIAL, self.__onDragSpecial)
+        self.registerForEvent(EVT_ROTATE_SPECIAL, self.__onRotateSpecial)
+        self.registerForEvent(EVT_ENTERED_WINDOW_SPECIAL, self.__onEnteredWindowSpecial)
+        self.registerForEvent(EVT_LEFT_WINDOW_SPECIAL, self.__onLeftWindowSpecial)
+        self.registerForEvent(EVT_CLICK_SPECIAL, self.__onClickSpecial)
+        self.registerForEvent(EVT_KEY_SPECIAL, self.__onKeySpecial)
+
+
+    # -------    DENERIC  EVENTS   -----------------    
+    
+    def __onAppChanged(self, event):
+        if self.app == event.app:
+            app = event.app
+            self.bounds.setAll(app.left, app.right, app.top, app.bottom)
+            self.aspectRatio = self.bounds.getWidth() / float(self.bounds.getHeight())
+            self.displayId = app.getDisplayId()
+            self.__resetOverlay()
+                        
+
+    def __onZChanged(self, event):
+        self.z = self.app.getZvalue()
+        self.sendOverlayMessage(Z_CHANGE, self.z)
+
+
+    def __onLeftWindow(self, event):
+        # change the app overlay to default
+        if self.overCorner != APP:
+            self.sendOverlayMessage(ON_CORNER, self.overCorner, 0)
+            self.overCorner = APP
+
+        # change the pointer to default
+        pointer = event.device.pointer
+        event.device.dragMode = False
+        if pointer:
+            pointer.showOutApp()
+            pointer.resetPointer()
+            
+        self.sendOverlayMessage(ON_APP, 0)
+            
+
+    # -------    SPECIAL DEVICE EVENTS   -----------------
+
+    def __onSpecialMove(self, event):
+        x,y = self.__toAppCoords(event.x, event.y)
+        dx,dy = self.__toAppDist(event.dX, event.dY)
+        self.sageGate.sendAppEvent(EVT_MOVE, self.app.getSailID(), event.device.getSpecialId(), x, y, dx, dy)
+
+
+    def __onEnteredWindowSpecial(self, event):
+        self.sendOverlayMessage(ON_APP, 1)
+        pointer = event.device.pointer
+#        if pointer: pointer.hide()
+
+
+    def __onLeftWindowSpecial(self, event):
+        self.sendOverlayMessage(ON_APP, 0)
+        pointer = event.device.pointer
+#        if pointer: pointer.show()
+
+
+
+    # -------    DEVICE EVENTS   -----------------
+    
+    def __onOver(self, event):
+        corner = self.app.hitTest(event.x, event.y, self.cornerSize)
+        device = event.device
+        pointer = device.pointer
+        if pointer:
+            if corner > APP:    # corners
+                pointer.showResizePointer(corner)
+                pointer.showOutApp()
+                device.dragMode = True
+                if self.overCorner != corner:
+                    self.sendOverlayMessage(ON_CORNER, corner, 1)
+                    self.sendOverlayMessage(ON_CORNER, self.overCorner, 0)
+                    self.overCorner = corner
+                    
+            elif corner < APP:   # top and bottom area
+                pointer.showDragPointer()
+                pointer.showOutApp()
+                device.dragMode = True
+                if self.overCorner != corner:
+                    self.sendOverlayMessage(ON_CORNER, corner, 1)
+                    self.sendOverlayMessage(ON_CORNER, self.overCorner, 0)
+                    self.overCorner = corner
+
+            else:      # interior of the app
+                #pointer.resetPointer()
+                pointer.showInApp()
+                device.dragMode = False
+                if self.overCorner != corner:
+                    self.sendOverlayMessage(ON_CORNER, self.overCorner, 0)
+                    self.overCorner = corner
+
+
+                
+    def __onClick(self, event):
+        corner = self.app.hitTest(event.x, event.y, self.cornerSize)
+        pointer = event.device.pointer
+        x, y = event.x, event.y
+        
+        # BUTTON DOWN
+        if event.isDown:
+            self.capturedCorner = corner
+            self.lastClickPos = (x, y)
+            event.device.toEvtHandler = self   # tell the device to forward all events here (until the button goes up)
+            if pointer: pointer.pushState()    # preserve the state of the pointer
+            
+            if corner < APP:  # top or bottom
+                self.captured = True
+                self.lastClickDeviceId = event.device.deviceId
+                if pointer: pointer.showDragPointer()
+                self.sendOverlayMessage(DRAG, 0,0, corner)
+                self.sageGate.bringToFront(self.app.getId())
+
+            elif corner > APP:  # corner
+                self.captured = True
+                self.lastClickDeviceId = event.device.deviceId
+                if pointer: pointer.showResizePointer(corner)
+                self.sendOverlayMessage(RESIZE, 0,0,corner)
+
+            else:         # to app
+                x,y = self.__toAppCoords(x,y)
+                self.sageGate.sendAppEvent(EVT_CLICK, self.app.getSailID(), -1, x, y, event.btnId, 1, event.forEvt)
+
+
+        # BUTTON UP
+        elif not event.isDown:
+            self.captured = False
+            dX = x - self.lastClickPos[0]
+            dY = y - self.lastClickPos[1]
+            if pointer: pointer.popState()   # return to the previous pointer state
+                
+            if self.capturedCorner < APP:    # top/bottom
+                if event.device.deviceId == self.lastClickDeviceId:
+                    self.lastClickDeviceId = None
+                    self.sageGate.moveWindow(self.app.getId(), dX, dY)
+
+            elif self.capturedCorner > APP:  # corners
+                if event.device.deviceId == self.lastClickDeviceId:
+                    self.lastClickDeviceId = None
+                    self.__resizeBounds(dX, self.capturedCorner)
+                    self.sageGate.resizeWindow(self.app.getId(), self.bounds.left,
+                                               self.bounds.right, self.bounds.bottom,
+                                               self.bounds.top)
+            else:    # to app
+                x,y = self.__toAppCoords(x,y)
+                self.sageGate.sendAppEvent(EVT_CLICK, self.app.getSailID(), -1, x, y, event.btnId, 0, event.forEvt)
+                
+    def __whichCorner(self,x,y):
+        normX, normY = self.__toAppCoords(x, y)
+        
+        print normX, " ", normY
+        
+        if (normX < 0.5):
+            if (normY < 0.5):
+                return BOTTOM_LEFT
+            else:
+                return TOP_LEFT
+        else:
+            if (normY < 0.5):
+                return BOTTOM_RIGHT
+            else:
+                return TOP_RIGHT
+
+    def __onClickSpecial(self, event):
+        pointer = event.device.pointer
+        x, y = event.x, event.y
+        
+        # BUTTON DOWN
+        if event.isDown:
+            self.lastClickPos = (x, y)
+            event.device.toEvtHandler = self   # tell the device to forward all events here (until the button goes up)
+#            if pointer: pointer.pushState()    # preserve the state of the pointer
+            
+#            if corner < APP:  # top or bottom
+            self.captured = True
+            self.lastClickDeviceId = event.device.deviceId
+            if event.btnId == 1:
+                self.sendOverlayMessage(DRAG, 0,0, APP_BOTTOM)
+                if pointer: pointer.showDragPointer()
+            elif event.btnId == 3:
+                self.sendOverlayMessage(RESIZE, 0,0, self.capturedCorner)
+                self.capturedCorner = self.__whichCorner(x,y)
+                print self.capturedCorner
+                if pointer: pointer.showResizePointer(self.capturedCorner)
+            self.sageGate.bringToFront(self.app.getId())
+            self.lastClickAction = event.btnId
+            
+            if pointer: pointer.showDownPointer()
+
+#            elif corner > APP:  # corner
+#                self.captured = True
+#                self.lastClickDeviceId = event.device.deviceId
+#                if pointer: pointer.showResizePointer(corner)
+#                self.sendOverlayMessage(RESIZE, 0,0,corner)
+#
+#            else:         # to app
+#                x,y = self.__toAppCoords(x,y)
+#                self.sageGate.sendAppEvent(EVT_CLICK, self.app.getSailID(), -1, x, y, event.btnId, 1, event.forEvt)
+
+
+        # BUTTON UP
+        elif not event.isDown:
+            dX = x - self.lastClickPos[0]
+            dY = y - self.lastClickPos[1]
+            self.modifyTicks = 0
+#            if pointer: pointer.popState()   # return to the previous pointer state
+                
+#            if self.capturedCorner < APP:    # top/bottom
+            if event.device.deviceId == self.lastClickDeviceId:
+                self.lastClickDeviceId = None
+                if self.lastClickAction == 1:
+                    self.sageGate.moveWindow(self.app.getId(), dX, dY)
+                elif self.lastClickAction == 3:
+                    self.__resizeBounds(dX, self.capturedCorner)
+                    self.sageGate.resizeWindow(self.app.getId(), self.bounds.left,
+                                               self.bounds.right, self.bounds.bottom,
+                                               self.bounds.top)
+            self.captured = False
+            if pointer: pointer.showUpPointer()
+
+#            else:    # to app
+#                x,y = self.__toAppCoords(x,y)
+#                self.sageGate.sendAppEvent(EVT_CLICK, self.app.getSailID(), -1, x, y, event.btnId, 0, event.forEvt)
+
+    def __onDrag(self, event):
+        x,y = event.x, event.y
+        dx, dy, dz = event.dX, event.dY, event.dZ
+        pointer = event.device.pointer
+        
+        if self.capturedCorner < APP:  # top or bottom
+            self.sendOverlayMessage(DRAG, dx, dy, self.capturedCorner)
+
+        elif self.capturedCorner > APP:       # corner
+            self.sendOverlayMessage(RESIZE, dx, dy, self.capturedCorner)
+
+        else:               # to app
+            x,y = self.__toAppCoords(x,y)
+            dx,dy = self.__toAppDist(dx, dy)
+            self.sageGate.sendAppEvent(EVT_PAN, self.app.getSailID(), -1, x, y, dx, dy, dz)
+            if pointer: pointer.showDragPointer()
+            
+    def __onDragSpecial(self, event):
+        x,y = event.x, event.y
+        dx, dy, dz = event.dX, event.dY, event.dZ
+        pointer = event.device.pointer
+        
+        if self.lastClickAction == 1:
+            self.sendOverlayMessage(DRAG, dx, dy, APP_BOTTOM)
+            self.modifyTicks+=1
+            if self.modifyTicks == 10:
+                dX = x - self.lastClickPos[0]
+                dY = y - self.lastClickPos[1]
+                self.sageGate.moveWindow(self.app.getId(), dX, dY)
+                self.lastClickPos = (x,y)
+                self.modifyTicks = 0
+        elif self.lastClickAction == 3:
+            self.sendOverlayMessage(RESIZE, dx, dy, self.capturedCorner)
+            self.modifyTicks += 1
+            if self.modifyTicks == 10:
+                dX = x - self.lastClickPos[0]
+                dY = y - self.lastClickPos[1]
+                self.__resizeBounds(dX, self.capturedCorner)
+                self.sageGate.resizeWindow(self.app.getId(), self.bounds.left,
+                                           self.bounds.right, self.bounds.bottom,
+                                           self.bounds.top)
+                self.lastClickPos = (x,y)
+                self.modifyTicks = 0
+        
+#        self.sendOverlayMessage(RESIZE, dx, dy, self.capturedCorner)
+
+
+    def __onRotate(self, event):
+        dx, dy, dz = event.dX, event.dY, event.dZ
+        pointer = event.device.pointer
+        
+        if self.capturedCorner == APP:  # to app
+            x,y = self.__toAppCoords(event.x, event.y)
+            dx,dy = self.__toAppDist(dx, dy)
+            self.sageGate.sendAppEvent(EVT_ROTATE, self.app.getSailID(), -1, x, y, dx, dy, dz)
+            if pointer: pointer.showRotatePointer()
+            
+    def __onRotateSpecial(self, event):
+#        self.sageGate.moveWindow(self.app.getId(), event.dX, event.dY)
+        self.sageGate.rotateWindow(self.app.getId(), event.angle)
+        self.sageGate.bringToFront(self.app.getId())
+
+    def __onZoom(self, event):
+        x,y = event.x, event.y
+        dx, dy, dz = event.dX, event.dY, event.dZ
+        pointer = event.device.pointer
+        
+        if self.capturedCorner == APP:  # to app
+            x,y = self.__toAppCoords(x,y)
+            dx,dy = self.__toAppDist(dx, dy)
+            self.sageGate.sendAppEvent(EVT_ZOOM, self.app.getSailID(), -1, x, y, dx, dy, dz)
+            if pointer: pointer.showZoomPointer()
+
+            
+    def __onArrow(self, event):
+        self.sageGate.sendAppEvent(EVT_ARROW, self.app.getSailID(), -1, event.arrow)
+        
+    def __onKeySpecial(self, event):
+        if event.key == 1:
+            currentZ = self.app.getZvalue()
+            self.sageGate.bringToFront(self.app.getId())
+        elif event.key == -1:
+            bringToFrontOrder = getSageData().getAllAppIDs()[:]
+            bringToFrontOrder.remove(self.app.getId())
+            bringToFrontOrder.sort(key=getSageData().getZvalue, reverse=True)
+            for i in bringToFrontOrder:
+                self.sageGate.bringToFront(i)
+        elif event.key == FULLSCREEN:
+            width = (getSageData().getDisplayInfo().sageW)
+            height = (getSageData().getDisplayInfo().sageH)
+            
+            #!!!Dirty hack for installation in WestPoint!!!
+            width = 8*width/9
+            
+            screenRatio = (float)(width)/(float)(height)
+            
+            print self.aspectRatio, screenRatio
+            
+            if self.aspectRatio < screenRatio:
+                newHeight = (int)(height)
+                newWidth = (int)(round(self.aspectRatio * newHeight))
+                margin = ((width - newWidth) / 2)
+                
+                self.sageGate.resizeWindow(self.app.getId(), margin, width - margin, 0, newHeight)
+            else:
+                newWidth = (int)(width)
+                newHeight = (int)(round((float)(newWidth) / self.aspectRatio))
+                margin = ((height - newHeight) / 2)
+                
+                self.sageGate.resizeWindow(self.app.getId(), 0, newWidth, margin, height - margin)
+
+    # -------    HELPER METHODS   -----------------
+    
+
+    def __resetOverlay(self):
+        self.__setCornerSize()
+        self.sendOverlayMessage(RESET, self.bounds.left,
+                                self.bounds.right, self.bounds.top,
+                                self.bounds.bottom, self.z,
+                                self.cornerSize, self.displayId)
+        self.overCorner = APP
+
+    
+    def __toAppCoords(self, x, y):
+        """ converts to the normalized coords with respect to the app window
+            accounts for orientation of the sage window
+        """
+        orientation = self.app.getOrientation()
+        
+        if orientation == 0:
+            x -= self.bounds.left
+            y -= self.bounds.bottom
+            normX = float(x)/self.bounds.getWidth()
+            normY = float(y)/self.bounds.getHeight()
+        elif orientation == 180:
+            x = self.bounds.right - x
+            y = self.bounds.top - y
+            normX = float(x)/self.bounds.getWidth()
+            normY = float(y)/self.bounds.getHeight()
+        elif orientation == 90:
+            tmp = y
+            y = self.bounds.right - x
+            x = tmp - self.bounds.bottom
+            normX = float(x)/self.bounds.getHeight()
+            normY = float(y)/self.bounds.getWidth()
+            
+        elif orientation == 270:
+            tmp = y
+            y = x - self.bounds.left
+            x = self.bounds.top - tmp
+            normX = float(x)/self.bounds.getHeight()
+            normY = float(y)/self.bounds.getWidth()
+            
+        return normX, normY
+
+            
+    def __toAppDist(self, dx, dy):
+        """ converts to the normalized coords with respect to the app window
+            accounts for orientation of the sage window
+        """
+        orientation = self.app.getOrientation()
+
+        if orientation == 0:
+            normX = float(dx)/self.bounds.getWidth()
+            normY = float(dy)/self.bounds.getHeight()
+        elif orientation == 180:
+            dx = -dx
+            dy = -dy
+            normX = float(dx)/self.bounds.getWidth()
+            normY = float(dy)/self.bounds.getHeight()
+        elif orientation == 90:
+            tmp = dy
+            dy = -dx
+            dx = tmp
+            normX = float(dx)/self.bounds.getHeight()
+            normY = float(dy)/self.bounds.getWidth()
+        elif orientation == 270:
+            tmp = dy
+            dy = dx
+            dx = -tmp
+            normX = float(dx)/self.bounds.getHeight()
+            normY = float(dy)/self.bounds.getWidth()
+            
+        #normX = float(dx)/self.bounds.getWidth()
+        #normY = float(dy)/self.bounds.getHeight()
+
+        return normX, normY
+
+        #return float(dx)/self.bounds.getWidth(), float(dy)/self.bounds.getHeight()
+            
+
+    def __setCornerSize(self):
+        maxSize = 400
+        minSize = 150
+        self.cornerSize = min(maxSize, max(minSize, int(min(self.bounds.getHeight(),
+                                                            self.bounds.getWidth()) / 8)))
+
+        
+    def __resizeBounds(self, dx, corner):
+        # change the bounds based on the amount moved since the click
+        # also, don't resize smaller than the minAppSize
+        (l,r,t,b) = self.bounds.getAll()
+        
+        if corner == BOTTOM_LEFT:
+            l+=dx; b=b+dx/self.aspectRatio
+            if r-l < self.minAppSize and (r-l) <= (t-b):
+                l = r - self.minAppSize
+                b = t - self.minAppSize / self.aspectRatio
+            elif t-b < self.minAppSize and (t-b) < (r-l):
+                b = t - self.minAppSize
+                l = r - self.minAppSize * self.aspectRatio
+        elif corner == TOP_LEFT:
+            l+=dx; t=t-dx/self.aspectRatio 
+            if r-l < self.minAppSize and (r-l) <= (t-b):
+                l = r - self.minAppSize
+                t = b + self.minAppSize / self.aspectRatio
+            elif t-b < self.minAppSize and (t-b) < (r-l):
+                t = b + self.minAppSize
+                l = r - self.minAppSize * self.aspectRatio
+        elif corner == TOP_RIGHT:
+            r+=dx; t=t+dx/self.aspectRatio
+            if r-l < self.minAppSize and (r-l) <= (t-b):
+                r = l + self.minAppSize
+                t = b + self.minAppSize / self.aspectRatio
+            elif t-b < self.minAppSize and (t-b) < (r-l):
+                t = b + self.minAppSize
+                r = l + self.minAppSize * self.aspectRatio
+        elif corner == BOTTOM_RIGHT:
+            r+=dx; b=b-dx/self.aspectRatio
+            if r-l < self.minAppSize and (r-l) <= (t-b):
+                r = l + self.minAppSize
+                b = t - self.minAppSize / self.aspectRatio
+            elif t-b < self.minAppSize and (t-b) < (r-l):
+                b = t - self.minAppSize
+                r = l + self.minAppSize * self.aspectRatio
+
+        self.bounds.setAll(l,r,t,b)
+
+    
Index: trunk/src/testing/dim/overlays/pointer.py
===================================================================
--- trunk/src/testing/dim/overlays/pointer.py	(revision 4)
+++ trunk/src/testing/dim/overlays/pointer.py	(revision 4)
@@ -0,0 +1,188 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+from overlay import Overlay
+from globals import *
+
+
+
+def makeNew(overlayId):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return Pointer(overlayId)
+
+
+
+# pointer states
+RESET  = 0  # normal
+MOVE   = 1
+DRAG   = 2
+RESIZE = 3
+DOWN   = 4
+UP     = 5
+IN_APP = 6  # just change the color
+ANGLE  = 7  # where the down side of the cursor is
+ZOOM   = 8
+ROTATE = 9
+
+
+
+class Pointer(Overlay):
+
+    def __init__(self, overlayId):
+        Overlay.__init__(self, OVERLAY_POINTER, overlayId)
+        self.state = RESET
+        self.lastOrientation = 0
+        self.inApp = False
+        self.__savedState = [self.state, self.lastOrientation, self.inApp]
+        
+        # some devices only produce one analog event so set it here if so
+        # (e.g. a zoom-only puck)
+        # this is used when the device enters an application in order to show
+        # the correct pointer shape describing what the device can do
+        self.onlyAnalogEvent = None   
+
+
+    def pushState(self):
+        self.__savedState = [self.state, self.lastOrientation, self.inApp]
+
+
+    def popState(self):
+        state, lastOrientation, inApp = self.__savedState
+
+        # apply the state
+        if self.state != state and state != RESIZE:
+            self.sendOverlayMessage(state)
+            self.state = state
+
+        # apply the orientation
+        if self.state != state and state == RESIZE:
+            self.showResizePointer(self.lastOrientation)
+
+        # apply the inApp modifier
+        if inApp: self.showInApp()
+        else: self.showOutApp()
+        
+
+    def setAnalogEvent(self, eventId):
+        self.onlyAnalogEvent = eventId
+        
+        
+    def resetPointer(self):
+        if self.state != RESET:
+            self.sendOverlayMessage(RESET)
+            self.state = RESET
+            self.lastOrientation = 0
+            #print "RESET"
+            #self.inApp = False
+            
+
+    def showDownPointer(self):
+        if self.state != DOWN:
+            self.sendOverlayMessage(DOWN)
+            self.state = DOWN
+
+
+    def showUpPointer(self):
+        if self.state != UP:
+            self.sendOverlayMessage(UP)
+            self.state = UP
+            
+
+    def showResizePointer(self, orientation):
+        if self.state != RESIZE or self.lastOrientation != orientation:
+            self.sendOverlayMessage(RESIZE, orientation)
+            self.state = RESIZE
+            self.lastOrientation = orientation
+
+
+    def showDragPointer(self):
+        if self.state != DRAG:
+            self.sendOverlayMessage(DRAG)
+            self.state = DRAG
+            #print "DRAG"
+
+
+    def showZoomPointer(self):
+        if self.state != ZOOM:
+            self.sendOverlayMessage(ZOOM)
+            self.state = ZOOM
+
+
+    def showRotatePointer(self):
+        if self.state != ROTATE:
+            self.sendOverlayMessage(ROTATE)
+            self.state = ROTATE
+
+
+    def movePointer(self, x, y):
+        self.sendOverlayMessage(MOVE, x, y)
+
+
+    def pointerAngle(self, angle):
+        self.sendOverlayMessage(ANGLE, int(angle))
+
+
+    def showInApp(self):
+        if not self.inApp:
+            self.sendOverlayMessage(IN_APP, 1)
+            self.inApp = True
+            #print "IN APP"
+            # set the correct pointer shape if the device
+            # can produce only one analog event
+            if self.onlyAnalogEvent == EVT_DRAG:
+                self.showDragPointer()
+            elif self.onlyAnalogEvent == EVT_ROTATE:
+                self.showRotatePointer()
+            elif self.onlyAnalogEvent == EVT_ZOOM:
+                self.showZoomPointer()
+            elif self.onlyAnalogEvent == None:
+                self.resetPointer()
+
+
+    def showOutApp(self):
+        if self.inApp:
+            #print "OUT APP"
+            self.sendOverlayMessage(IN_APP, 0)
+            self.inApp = False
+            #self.resetPointer()
+            
+
Index: trunk/src/testing/dim/eventHandler.py
===================================================================
--- trunk/src/testing/dim/eventHandler.py	(revision 4)
+++ trunk/src/testing/dim/eventHandler.py	(revision 4)
@@ -0,0 +1,91 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from globals import *
+
+
+
+class EventHandler:
+    """ The base class for any objects wanting to receive device events.
+        Make sure the bounds member is up to date since it's used
+        in deciding whether an event should be delivered to it or not.
+        Also, make sure you update the z value (if applicable)
+
+        Example of registering for events:
+        ----------------------------------------
+        self.registerForEvent(EVT_CLICK, self.onClick)
+        def onClick(self, event):
+            # do something with the click event...
+    """
+
+    def __init__(self):
+        self.evtMgr = getEvtMgr()  # for registering for events
+        self.captured = False
+        self.bounds = Bounds()     # the bounds for detecting the events
+        self.displayId = 0         # the bounds will depend on this...
+        self.z = TOP_Z   # always on top
+        self.__callbacks = {}  # key eventId, value=callback
+
+ ##        # kind of a hack to make sure that enter and
+##         # leave events get delivered properly
+##         self.registerForEvent(EVT_MOVE, self.dummyOnMove)
+
+
+##     def dummyOnMove(self, event):
+##         # kind of a hack to make sure that enter and
+##         # leave events get delivered properly
+##         pass
+        
+
+    def registerForEvent(self, eventId, callback):
+        self.__callbacks[eventId] = callback
+        self.evtMgr.register(eventId, callback)
+
+
+    def getCallback(self, eventId):
+        if eventId in self.__callbacks:
+            return self.__callbacks[eventId]
+
+
+    def destroy(self):
+        """ may be overridden but you need to call this base class' method """
+        self.evtMgr.unregister(self.__callbacks)
+        
+        
Index: trunk/src/testing/dim/sageApp.py
===================================================================
--- trunk/src/testing/dim/sageApp.py	(revision 4)
+++ trunk/src/testing/dim/sageApp.py	(revision 4)
@@ -0,0 +1,230 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import sys, string
+
+### Class to hold sage application info
+### An instance of this class should exist for every app Id on SAGE
+class SageApp :
+
+        
+    def __init__(self, name, id, left, right, bottom, top, sailID, zValue, orientation, displayId, title=""):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.sailID = sailID
+        self.appName = name
+        self.id = id
+        self.zValue = zValue
+        self.configNum = 1
+        self.title = title
+        self.capture = -1  # which pointer captured it
+        self.orientation = 0  # in degrees
+        self.displayId = 0
+        
+
+    def setAll(self, name, id, left, right, bottom, top, sailID, zValue, orientation, displayId):
+        self.appName = name
+        self.id = id
+        self.left = left
+        self.right = right
+        self.bottom = bottom
+        self.top = top
+        self.sailID = sailID
+        self.zValue = zValue
+        self.orientation = orientation
+        self.displayId = displayId
+        #self.title = title
+        
+
+    def getLeft(self):
+        return self.left
+
+    def getRight(self):
+        return self.right
+
+    def getTop(self):
+        return self.top
+
+    def getBottom(self):
+        return self.bottom
+
+    def getId(self):
+        return self.id
+
+    def getConfigNum(self):
+        return self.configNum
+
+    def getTitle(self):
+        return self.title
+
+    def setTitle(self, newTitle):
+        self.title = newTitle
+
+    def getWidth(self):
+        return self.right - self.left
+
+    def getHeight(self):
+        return self.top - self.bottom
+
+    def getDisplayId(self):
+        return self.displayId
+
+    def getOrientation(self):
+        return self.orientation
+    
+    def setName(self, appName):
+        self.appName = appName
+
+    def getName(self):
+        return self.appName
+    
+    #### Get the application window values
+    #### @return Returns a list Format: [<left>, <right>, <top>, <bottom>]
+    def getBounds(self) :
+        return [self.left, self.right, self.top, self.bottom]
+
+    #### Get the app's sailID
+    def getSailID(self):
+        return self.sailID
+
+    def setZvalue(self, value):
+        self.zValue = value
+
+    def getZvalue(self):
+        return self.zValue
+
+    def hasCapture(self):
+        if self.capture == -1:
+            return False
+        else:
+            return True
+
+    def captureMouse(self, pointerId):
+        self.capture = pointerId
+        
+    def releaseMouse(self):
+        self.capture = -1
+        
+
+    # checks whether (x,y) hit something on the shape
+    # calculations are done in the sage coordinate system (bottom left = 0,0)
+    # 0 = everything else... inside the app
+    # -2 = hit but not on the corners (BOTTOM)
+    # -1 = hit but not on the corners (TOP)
+    # 1 = bottom left corner
+    # 2 = top left corner
+    # 3 = top right
+    # 4 = bottom right
+    def hitTest(self, x, y, cornerSize=250):
+
+        # utility function
+        def __inRegion(r):
+            if x >= r[0] and x <= r[1] and y<=r[2] and y>=r[3]:
+                return True
+            return False
+            
+        (l,r,t,b,cs) = (self.left, self.right, self.top, self.bottom, cornerSize)
+
+        # define the regions we need to test
+        testRegions = {}  # keyed by -2,-1,1,2,3,4
+        testRegions[-2] = (l+cs, r-cs, b+cs, b)
+        testRegions[-1] = (l+cs, r-cs, t, t-cs)
+        testRegions[1] = (l, l+cs, b+cs, b)
+        testRegions[2] = (l, l+cs, t, t-cs)
+        testRegions[3] = (r-cs, r, t, t-cs)
+        testRegions[4] = (r-cs, r, b+cs, b)
+        
+        # now loop through the regions and test whether x,y is in it
+        result = 0
+        for rid, r in testRegions.iteritems():
+            if __inRegion(r):
+                return rid
+                                
+        return result
+
+
+
+
+
+
+
+### a class to hold the information about all the available apps that SAGE supports
+class SageAppInitial:
+
+    def __init__ (self, name, configNames):
+        self._name = name
+        self._configNames = configNames
+        
+    def GetName (self):
+        return self._name
+
+    def SetName (self, name):
+        self._name = name
+
+    def GetConfigNames(self):
+        return self._configNames
+    
+    ## # execution configurations
+##     def AddConfig (self, name, stConfig):
+##         self._execConfigs[ len(self._execConfigs)+1 ] = (name, string.strip(stConfig))
+
+##     def GetNumConfigs(self):
+##         return self._numConfigs
+    
+##     def GetConfigHash (self):
+##         return self._execConfigs
+
+##     def GetConfig (self, configNum):
+##         if self._execConfigs.has_key( configNum ):
+##             return self._execConfigs[ configNum ]
+##         else:
+##             print "Error: No configuration number ", configNum
+##             return "No Configuration"
+
+##     # instances already started
+##     def AddInstanceId (self, instanceId):
+##         self._appInstanceIds.append( instanceId )
+
+##     def GetInstanceIds (self):
+##         return self._appInstanceIds
+
+    
Index: trunk/src/testing/dim/sageGate.py
===================================================================
--- trunk/src/testing/dim/sageGate.py	(revision 4)
+++ trunk/src/testing/dim/sageGate.py	(revision 4)
@@ -0,0 +1,118 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import sageGateBase as sgb
+from globals import *
+
+
+
+####################################################################
+#
+# DESCRIPTION: This class provides the main communication interface
+#              with SAGE. It subclasses the SageGateBase in order
+#              to customize some parameters.
+#
+# DATE: Aug, 2007
+#
+####################################################################
+
+class SageGate(sgb.SageGateBase):
+    """ this class provides the main communication interface with SAGE
+        subclasses the SageGateBase in order to customize some parameters
+    """
+    
+    def __init__(self):
+        sgb.SageGateBase.__init__(self,
+                                  sageServerHost=getSAGEServer(),
+                                  useAppLauncher=True,
+                                  #forceAppLauncher=getAppLauncher(),
+                                  onDisconnect=self.showConnectionClosedDialog,
+                                  verbose=True)
+        
+
+    def showConnectionClosedDialog(self):
+        """ informs the user when the connection breaks """
+        print "Connection to SAGE closed"
+        exitApp()
+
+
+##     def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+##         """ overridden in order to figure out the correct port and host for the target machine
+##             The reason is that SageGateBase doesn't have access to all the machine info (ie usersData)
+##         """
+
+##         # figure out the correct system ports for data streaming (if not overridden by the user)
+##         sageIP, sagePort = self.__getMachineInfo(sageIP, sagePort)
+        
+##         return sgb.SageGateBase.executeApp(self, appName, configName, pos, size,
+##                                            optionalArgs, useBridge, sageIP, sagePort)
+
+
+##     def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+##         """ overridden in order to figure out the correct port and host for the target machine
+##             The reason is that SageGateBase doesn't have access to all the machine info (ie usersData)
+##         """
+
+##         # figure out the correct system ports for data streaming (if not overridden by the user)
+##         sageIP, sagePort = self.__getMachineInfo(sageIP, sagePort)
+        
+##         return sgb.SageGateBase.executeRemoteApp(self, launcherId, appName, configName, pos, size,
+##                                                  optionalArgs, useBridge, sageIP, sagePort)
+        
+
+    def onMessage(self, code, data):
+        """ handles the incoming messages """
+        if code in self.hashCallbackFunction:
+            self.hashCallbackFunction[ code ](data)
+
+            
+##     def __getMachineInfo(self, sageIP, sagePort):
+##         if not sageIP:
+##             machine = getUsersData().FindMachineByIP(self.sageHost)
+##             if machine:
+##                 sageIP = machine.GetSystemIP()     # the machine told the server what to use for streaming
+##                 if not sagePort: sagePort = machine.GetSystemPort()
+##             else:
+##                 sageIP = self.sageHost    # use the default ip and port
+##                 if not sagePort: sagePort = self.sagePort+1
+##         return (sageIP, sagePort)
+
+
+    
Index: trunk/src/testing/dim/overlay.py
===================================================================
--- trunk/src/testing/dim/overlay.py	(revision 4)
+++ trunk/src/testing/dim/overlay.py	(revision 4)
@@ -0,0 +1,104 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+from globals import *
+
+SPECIAL_DEVICE = 100
+
+class Overlay:
+    """ this describes the basic overlay - ie an object
+        that's drawn on the screen
+    """
+
+    def __init__(self, overlayType, overlayId):
+        #self.overlayId
+        self.overlayType = overlayType
+        self.overlayId = overlayId
+        self.displayId = 0
+        self.sageGate = getSageGate()
+        self.visible = True
+        #self.x = 0  # position in SAGE coords
+        #self.y = 0
+
+    def setSpecialDevice(self, value):
+        self.sendOverlayMessage(SPECIAL_DEVICE, value)
+
+    def getId(self):
+        return self.overlayId
+    
+
+    def getType(self):
+        return self.overlayType
+
+
+    def isVisible(self):
+        return self.visible
+
+
+    def sendOverlayMessage(self, *params):
+        self.sageGate.sendOverlayMessage(self.overlayId, *params)
+    
+
+    def hide(self):
+        if self.visible:
+            self.visible = False
+            self.sageGate.showOverlay(self.overlayId, False)
+
+
+    def show(self):
+        if not self.visible:
+            self.visible = True
+            self.sageGate.showOverlay(self.overlayId, True)
+
+
+    def update(self, now):
+        """ do something to update your drawing or whatever
+            the *now* parameter is the current time in seconds... float
+        """
+        pass
+
+
+##     def destroy(self):
+##         """ Called when the object is deleted.
+##             Make sure you call this method if you override it.
+##         """
+##         pass
+
+
+    
Index: trunk/src/testing/dim/sageDisplayInfo.py
===================================================================
--- trunk/src/testing/dim/sageDisplayInfo.py	(revision 4)
+++ trunk/src/testing/dim/sageDisplayInfo.py	(revision 4)
@@ -0,0 +1,125 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+# placement
+MIDDLE = -1
+LEFT = 0
+RIGHT = 1
+BOTTOM = 2
+TOP = 3
+
+
+class SageDisplay:
+    def __init__(self, tn,x,y,w,h,tw,th,dId):
+        self.tileNumber = tn
+        self.dimX = x
+        self.dimY = y
+        self.cols = x   # just an alias
+        self.rows = y
+        self.desktopWidth = w
+        self.desktopHeight = h
+        self.tileWidth = tw
+        self.tileHeight = th
+        self.sageW = w 
+        self.sageH = h 
+        self.displayId = dId
+        self.placement = MIDDLE  # where this display is with respect to display 0 (-1 means this is display 0 = middle)
+        #self.orientation = 0  # where down is in degrees. 0 is down, 90 is right, 180 is up, 270 is left
+        
+    def getValues(self):
+        return [self.tileNumber, self.dimX, self.dimY,
+                self.desktopWidth, self.desktopHeight,
+                self.tileWidth, self.tileHeight, self.displayId]
+
+    def getId(self):
+        return self.displayId
+    
+
+
+class SageDisplayInfo:
+
+    def __init__(self):
+        self.displays = {}
+
+
+    def getAllDisplays(self):
+        """ returns a list of SageDisplay objects """
+        return self.displays.values()
+
+
+    def getNumDisplays(self):
+        return len(self.displays)
+    
+
+    def addDisplay(self, tileNum, dimX, dimY, deskWidth, deskHeight, tileWidth, tileHeight, displayId=0):
+        d = SageDisplay(tileNum, dimX, dimY, deskWidth, deskHeight, tileWidth, tileHeight, displayId)
+        self.displays[displayId] = d
+
+
+    def getTotalWidth(self):
+        totalW = 0
+        for disp in self.displays.values():
+            pos = disp.placement
+            if pos == LEFT or pos == MIDDLE or pos == RIGHT:
+                totalW += disp.sageW
+        return totalW
+
+
+    def getTotalHeight(self):
+        totalH = 0
+        for disp in self.displays.values():
+            pos = disp.placement
+            if pos == TOP or pos == MIDDLE or pos == BOTTOM:
+                totalH += disp.sageH
+        return totalH
+    
+
+    def getDisplay(self, displayId):
+        if not displayId in self.displays:
+            displayId = 0
+        return self.displays[displayId]
+
+            
+    def getDisplayInfo(self, displayId=0):
+        if not displayId in self.displays:
+            displayId = 0
+        return self.displays[displayId].getValues()
+                
Index: trunk/src/testing/dim/globals.py
===================================================================
--- trunk/src/testing/dim/globals.py	(revision 4)
+++ trunk/src/testing/dim/globals.py	(revision 4)
@@ -0,0 +1,283 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# overlay types (these are same as SAGEDrawObject types)
+OVERLAY_POINTER = "pointer"   
+OVERLAY_APP = "app"      # app checker
+OVERLAY_WALL = "wall"
+
+# btnIDs
+BTN_LEFT   = 1
+BTN_RIGHT  = 2
+BTN_MIDDLE = 3
+
+# arrow IDs
+ARROW_UP    = 1
+ARROW_DOWN  = 2
+ARROW_LEFT  = 3
+ARROW_RIGHT = 4
+
+
+# pointer orientations
+BOTTOM_LEFT  = 1
+TOP_LEFT     = 2
+TOP_RIGHT    = 3
+BOTTOM_RIGHT = 4
+
+
+# z order
+BOTTOM_Z = 99999
+TOP_Z    = -1
+
+
+# draw order for SAGE
+POST_DRAW = 0
+INTER_DRAW = 1
+PRE_DRAW = 2
+
+
+#-----------------------------------------------------
+#       EVENTS
+#-----------------------------------------------------
+
+# EVENT TYPES
+DEVICE_EVENT    = 1  # position dependent
+GENERIC_EVENT   = 2  # sent to everybody that is listening
+
+# device event IDs
+EVT_CLICK   = 0
+EVT_MOVE    = 2
+EVT_ANALOG1 = 3
+EVT_PAN     = 3 # alias
+EVT_DRAG    = 3 # alias
+EVT_ANALOG2 = 4
+EVT_ROTATE  = 4 # alias
+EVT_ANALOG3 = 5
+EVT_ZOOM    = 5 # alias
+EVT_ARROW   = 6
+EVT_KEY     = 7
+EVT_CUSTOM  = 8
+EVT_ENTERED_WINDOW = 9
+EVT_LEFT_WINDOW = 10
+
+# special device events
+EVT_CLICK_SPECIAL   = 20
+EVT_MOVE_SPECIAL    = 22
+EVT_ANALOG1_SPECIAL = 23
+EVT_PAN_SPECIAL     = 23 # alias
+EVT_DRAG_SPECIAL    = 23 # alias
+EVT_ANALOG2_SPECIAL = 24
+EVT_ROTATE_SPECIAL  = 24 # alias
+EVT_ANALOG3_SPECIAL = 25
+EVT_ZOOM_SPECIAL    = 25 # alias
+EVT_ARROW_SPECIAL   = 26
+EVT_KEY_SPECIAL     = 27
+EVT_CUSTOM_SPECIAL  = 28
+EVT_ENTERED_WINDOW_SPECIAL = 29
+EVT_LEFT_WINDOW_SPECIAL = 30
+
+# generic event IDs
+EVT_APP_INFO  = 50
+EVT_PERF_INFO = 51
+EVT_NEW_APP   = 52
+EVT_APP_KILLED = 53
+EVT_Z_CHANGE  = 54
+EVT_OBJECT_INFO = 55
+EVT_DISPLAY_INFO = 56
+
+
+
+#-----------------------------------------------------
+#       GLOBAL ACCESS VARIABLES
+#-----------------------------------------------------
+
+# EventManager - so that everybody can access it
+global evtMgr
+def setEvtMgr(em):
+    global evtMgr
+    evtMgr = em
+
+def getEvtMgr():
+    return evtMgr
+
+
+
+# DeviceManager - so that everybody can access it
+global devMgr
+def setDevMgr(dm):
+    global devMgr
+    devMgr = dm
+
+def getDevMgr():
+    return devMgr
+
+
+
+# OverlayManager - so that everybody can access it
+global overlayMgr
+def setOverlayMgr(om):
+    global overlayMgr
+    overlayMgr = om
+
+def getOverlayMgr():
+    return overlayMgr
+
+
+
+# SageGate - so that everybody can access it
+global sageGate
+def setSageGate(q):
+    global sageGate
+    sageGate = q
+
+def getSageGate():
+    return sageGate
+
+
+# SageData - so that everybody can access it
+global sageData
+def setSageData(d):
+    global sageData
+    sageData = d
+
+def getSageData():
+    return sageData
+
+
+
+    
+sageServer = "localhost"
+def setSAGEServer(server):
+    global sageServer
+    sageServer = server
+
+def getSAGEServer():
+    return sageServer
+
+
+
+# for quitting the whole application
+global run
+run = True
+def exitApp():
+    global run
+    run = False
+    getOverlayMgr().removeAllOverlays()
+def doRun():
+    return run
+
+
+
+
+class Bounds:
+    """ used in event conversion """
+    def __init__(self, left=0, right=0, top=0, bottom=0):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.setAspectRatio()
+
+
+    def setAll(self, left, right, top, bottom):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.setAspectRatio()
+
+    def getAll(self):
+        return self.left, self.right, self.top, self.bottom
+
+    def setAspectRatio(self):
+        if self.getHeight() != 0:
+            self.aspectRatio = self.getWidth() / float(self.getHeight())
+        else:
+            self.aspectRatio = 1.0
+
+    def getAspectRatio(self):
+        return self.aspectRatio
+
+    def getWidth(self):
+        return self.right - self.left
+
+    def setWidth(self, w):
+        self.right = self.left + w
+        self.setAspectRatio()
+
+    def getHeight(self):
+        return self.top - self.bottom
+
+    def setHeight(self, h):
+        self.top = self.bottom + h
+        self.setAspectRatio()
+
+    def setSize(self, w, h):
+        self.setWidth(w)
+        self.setHeight(h)
+
+
+    def getX(self):
+        return self.left
+
+    def getY(self):
+        return self.bottom
+
+    def setPos(self, x, y):
+        self.setX(x)
+        self.setY(y)
+        
+    def setX(self, x):
+        w = self.getWidth()
+        self.left = x
+        self.right = x + w
+
+    def setY(self, y):
+        h = self.getHeight()
+        self.bottom = y
+        self.top = y + h
+
+
+    def isIn(self, x, y):
+        """ returns True if the (x,y) is in Bounds, False otherwise """
+        if self.left <= x and self.right >= x and self.bottom <= y and self.top >= y:
+            return True
+        else:
+            return False
Index: trunk/src/testing/dim/listener.py
===================================================================
--- trunk/src/testing/dim/listener.py	(revision 4)
+++ trunk/src/testing/dim/listener.py	(revision 4)
@@ -0,0 +1,118 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import traceback as tb
+from SocketServer import ThreadingTCPServer, StreamRequestHandler
+import socket
+from globals import *
+
+
+
+class Listener(ThreadingTCPServer):
+    """ the main server listening for connections from HWCapture """
+    
+    allow_reuse_address = True
+    request_queue_size = 50
+    
+    def __init__(self, port, onMsgCallback):
+        self.onMsgCallback = onMsgCallback
+        ThreadingTCPServer.__init__(self, ('', int(port)), SingleHWCapture)
+        self.socket.settimeout(0.5)
+
+        
+    def verify_request(self, request, client_address):
+        """ check whether this client already exists """
+        return True
+
+
+    def serve_forever(self):
+        while doRun():
+            try:
+                self.handle_request()
+            except socket.timeout:
+                pass
+            except KeyboardInterrupt:
+                exitApp()
+                break
+        print "Listener closed"
+        
+
+
+class SingleHWCapture(StreamRequestHandler):      
+    """ one of these per HWCapture client """
+
+    
+    def handle(self):
+        """ this is where we parse the incoming messages
+            and pass the data to the correct device objects.
+        """
+        self.connection.settimeout(0.5)  # so that we can quit properly
+        self.deviceId = None
+        
+        while doRun():
+            try:
+                # read one line from the socket (blocking mode)
+                msg = self.rfile.readline().strip()
+                if len(msg) == 0:
+                    break
+
+                # separate into pieces
+                (deviceId, deviceType, data) = msg.split(' ', 2)
+                self.deviceId = deviceId
+                
+                # call the function that's going to handle this further
+                self.server.onMsgCallback(deviceId, deviceType, data)
+
+            except socket.timeout:
+                continue
+            except:
+                tb.print_exc()  
+                break
+                
+        print "HWCapture receiver closed"
+        
+
+
+    def finish(self):
+        """ do some cleanup here... ie remove all the
+            devices connected to that machine """
+
+        # remove the device
+        getDevMgr().removeDevice(self.deviceId)
+        StreamRequestHandler.finish(self)
Index: trunk/src/testing/dim/deviceManager.py
===================================================================
--- trunk/src/testing/dim/deviceManager.py	(revision 4)
+++ trunk/src/testing/dim/deviceManager.py	(revision 4)
@@ -0,0 +1,116 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import os, os.path
+
+
+class DeviceManager:
+    
+    def __init__(self):
+        self.devices = {}  # key=deviceId, value=deviceObj
+
+        # load all the plugins now
+        self.__devicePlugins = {}  # key=deviceType, value=devicePlugin
+        self.__loadAllPlugins()
+
+        # for special devices and assigning unique ids
+        self.__specialDevices = []  # a list of special devices
+        
+        
+        
+    def onHWMessage(self, deviceId, deviceType, data):
+        """ this gets called when a message arrives from any hw device """
+        
+        # check whether the device already exists, if so pass the message to it
+        if deviceId in self.devices:
+            self.devices[ deviceId ].onMessage(data, False)
+            
+        else:
+            if deviceType not in self.__devicePlugins:  # devicePlugin isn't loaded yet 
+                if not self.__loadDevicePlugin( deviceType ):
+                    return   # couldn't load the plugin
+            # at this point we have a plugin loaded so create a device object to do the conversion
+
+            newDeviceObj = self.__devicePlugins[ deviceType ].makeNew(deviceId)
+            self.devices[ deviceId ] = newDeviceObj
+
+            # set a special id if the device is special
+            if newDeviceObj.specialDevice:
+                specId = len(self.__specialDevices)
+                newDeviceObj.setSpecialId(specId)
+                self.__specialDevices.append(deviceId)
+                
+            newDeviceObj.onMessage(data, firstMsg=True)
+
+
+    def removeDevice(self, deviceId):
+        # remove from the list of devices
+        if deviceId in self.devices:
+            self.devices[ deviceId ].destroy()
+            del self.devices[ deviceId ]
+
+        # remove from the list of special devices if necessary
+        if deviceId in self.__specialDevices:
+            self.__specialDevices.remove(deviceId)
+            
+
+    def __loadAllPlugins(self):
+        """ goes into the 'devices' directory and loads all the plugins from there """
+
+        for entry in os.listdir("devices"):
+            if os.path.splitext(entry)[1] == ".py" and entry != "__init__.py":
+                self.__loadDevicePlugin( os.path.splitext(entry)[0] )
+            
+
+    def __loadDevicePlugin(self, deviceType):
+        """ try to load the devicePlugin for the requested deviceType """
+        try:
+            #(f, path, desc) = imp.find_module(deviceType, "devices")
+            #devicePlugin = imp.load_module(deviceType, f, path, desc)
+            devicePlugin = __import__("devices."+deviceType, globals(), locals(), [deviceType])
+            self.__devicePlugins[ deviceType ] = devicePlugin
+            print "Device plugin loaded: ", deviceType
+            return True
+                
+        except ImportError:
+            return False   # failed to load the module
+
+    
Index: trunk/src/testing/dim/devices/wiimote.py
===================================================================
--- trunk/src/testing/dim/devices/wiimote.py	(revision 4)
+++ trunk/src/testing/dim/devices/wiimote.py	(revision 4)
@@ -0,0 +1,112 @@
+import device
+from globals import *
+import time
+from threading import Thread
+
+def makeNew(deviceId):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return Wiimote(deviceId)
+
+
+# types of messages sent to the manager
+MOVE = 0
+TRANSLATE = 1
+ROTATE = 2
+RESIZE = 3
+CHANGE_Z = 4
+FULLSCREEN = 5
+
+class Wiimote(device.Device):
+    
+    def __init__(self, deviceId):
+        device.Device.__init__(self, "wiimote", deviceId, needPointer=True)
+        self.x = 0
+        self.y = 0
+        
+        self.dx = 0
+        self.dy = 0
+        
+        self.clickX = 0
+        self.clickY = 0
+        
+        self.translate = 0
+        self.resize = 0
+        
+        self.specialDevice = True
+        
+        getOverlayMgr().setSpecialDevice(1)
+        
+    def onMessage(self, data, firstMsg=False):
+        tokens = data.strip().split()
+        msgCode = int(tokens[0])
+
+        # click
+        if msgCode == MOVE:
+            x = float(tokens[1].strip())
+            y = float(tokens[2].strip())
+            
+            if x == -1 and y == -1:
+                if self.translate:    
+                    self.translate = False
+                    self.postEvtClick(self.x, self.y, TRANSLATE, False, EVT_CLICK)
+                if self.resize:
+                    self.resize = False
+                    self.postEvtClick(self.x, self.y, RESIZE, False, EVT_CLICK)
+                if self.pointer:
+                    self.pointer.movePointer(-50000,-50000)
+                    self.postEvtMove(-50000, -50000, 0, 0)
+            else:
+                x = self.bounds.getX() + int(round(float(x) * self.bounds.getWidth()))
+                y = self.bounds.getY() + int(round(float(y) * self.bounds.getHeight()))
+                
+    #            x,y = self.smooth(x,y)
+                
+                self.dx = self.dy = 0
+                if self.x != x or self.y != y:
+                    self.dx = x - self.x ;  self.x = x
+                    self.dy = y - self.y ;  self.y = y
+                
+    #            print "(%d,%d) -- [%d,%d] --> (%d,%d)" % (self.clickX, self.clickY, self.dx, self.dy, self.x, self.y)
+                
+                if self.pointer:
+                    self.pointer.movePointer(self.x, self.y)
+                
+                if self.translate:
+                    self.postEvtAnalog1(self.x, self.y, self.dx, self.dy, 0)
+                elif self.resize:
+                    self.postEvtAnalog1(self.x, self.y, self.dx, self.dy, 0)
+                else:
+                    self.postEvtMove(self.x, self.y, self.dx, self.dy)
+
+        elif msgCode == TRANSLATE or msgCode == RESIZE:
+            value = int(tokens[1])
+            isDown = False
+            if value == 1:
+                isDown = True
+            if isDown:
+                self.clickX, self.clickY = self.x, self.y
+            self.postEvtClick(self.x, self.y, msgCode, isDown, EVT_CLICK)
+            if msgCode == TRANSLATE:
+                self.translate = isDown
+            elif msgCode == RESIZE:
+                self.resize = isDown
+        
+        elif msgCode == ROTATE:
+            value = int(tokens[1])
+            if (value == -1):
+                self.postEvtAnalog2(self.x, self.y, self.dx, self.dy, 0, -90)
+            elif (value == 1):
+                self.postEvtAnalog2(self.x, self.y, self.dx, self.dy, 0, 90)
+                
+        elif msgCode == CHANGE_Z:
+            value = int(tokens[1])
+#            if (value == 0):
+#                for a in getSageData().getAllAppIDs():
+#                    print "APP: ",a," Z=",getSageData().getZvalue(a)
+#            else:
+            self.postEvtKey(value, self.x, self.y)
+        elif msgCode == FULLSCREEN:
+            self.postEvtKey(FULLSCREEN, self.x, self.y)
+            
+
Index: trunk/src/testing/dim/devices/joystick.py
===================================================================
--- trunk/src/testing/dim/devices/joystick.py	(revision 4)
+++ trunk/src/testing/dim/devices/joystick.py	(revision 4)
@@ -0,0 +1,177 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import device
+from globals import *
+
+
+def makeNew(deviceId):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return Joystick(deviceId)
+
+UP_ARROW = 1
+DOWN_ARROW = 2
+LEFT_ARROW = 3
+RIGHT_ARROW = 4
+
+
+class Joystick(device.Device):
+    
+    def __init__(self, deviceId):
+        device.Device.__init__(self, "joystick", deviceId, True, displayId=0)
+        isFake = deviceId.split("_")[1].startswith('fake')
+        self.isWiimote = deviceId.split("_")[1].startswith('wiimote')
+        
+        if isFake:
+            self.joyToMouseRatio = 600
+        else:
+            self.joyToMouseRatio = 40
+        self.displayFactor = 1
+        
+        # current state of the device
+        self.buttons = [False, False, False]   # left, right, middle
+        self.x = 100   # position in SAGE coords
+        self.y = 100   # position in SAGE coords
+        self.clickX = 0  # where the click happened 
+        self.clickY = 0  # where the click happened
+
+        
+
+    def onMessage(self, data, firstMsg=False):
+        tokens = data.strip().split()
+        msgCode = tokens[0]
+           
+        # move
+        if msgCode == "1":
+            
+            # the axis information
+            xAxis = float(tokens[1])
+            yAxis = float(tokens[2])
+
+            # determine x, y, dX, dY
+            (dX, dY) = self.__toSAGEPos(xAxis, yAxis)
+                    
+            # fire the appropriate event
+            if self.buttons[0]:     # analog1, pan
+                self.postEvtAnalog1(self.clickX, self.clickY, dX, dY, 0)
+
+            elif self.buttons[1]:   # analog2, rotate
+                self.postEvtAnalog3(self.clickX, self.clickY, dX, dY, 0)
+                
+            elif self.buttons[2]:   # analog3, zoom
+                self.postEvtAnalog2(self.clickX, self.clickY, dX, dY, 0)
+
+            else:                   # move
+                self.postEvtMove(self.x, self.y, dX, dY)
+                
+
+            # move the pointer
+            if self.pointer: self.pointer.movePointer(self.x, self.y)
+            
+
+        # button press
+        elif msgCode == "2":  # button press
+            btnId = int(tokens[1])
+            isDown = bool(int(tokens[2]))
+            
+            # apply the state change if it's a valid buttonId
+            if btnId <= len(self.buttons):
+                forEvt = 0
+                if btnId == 0:  forEvt = 31000+EVT_PAN
+                elif btnId == 1:  forEvt = 31000+EVT_ROTATE
+                elif btnId == 2:  forEvt = 31000+EVT_ZOOM
+                self.buttons[btnId-1] = isDown
+                self.postEvtClick(self.x, self.y, btnId, isDown, forEvt)
+                self.clickX, self.clickY = self.x, self.y
+                
+
+        elif msgCode == "3":  # arrow
+            pov = int(tokens[1])
+
+            arrow = -1
+            if pov == 0:
+                arrow = UP_ARROW
+            elif pov == 9000:
+                arrow = RIGHT_ARROW
+            elif pov == 18000:
+                arrow = DOWN_ARROW
+            elif pov == 27000:
+                arrow = LEFT_ARROW
+                
+            if arrow > -1:
+                self.postEvtArrow(arrow, self.x, self.y)
+                
+
+    def __toSAGEPos(self, xAxis, yAxis):
+        
+        if self.isWiimote:
+            # wiimote is directly mapped to the whole display
+            halfWidth = self.bounds.getWidth()/2.0
+            halfHeight = self.bounds.getHeight()/2.0
+            newX = int( halfWidth + halfWidth*xAxis)
+            newY = int( halfHeight + halfHeight*yAxis)
+            dX = newX - self.x
+            dY = newY - self.y
+        else:
+            dX = int(xAxis * self.joyToMouseRatio * self.displayFactor)
+            dY = int(yAxis * self.joyToMouseRatio * self.displayFactor) * (-1)  # -1 for reverse
+
+        # make sure the pointer is within display bounds
+        # check left and right (x)
+        if (self.x + dX) > self.bounds.right:
+            dX = self.bounds.right - self.x
+        elif (self.x + dX) < self.bounds.left:
+            dX = -self.x
+
+        # check top and bottom (y)
+        if (self.y + dY) > self.bounds.top:
+            dY = self.bounds.top - self.y
+        elif (self.y + dY) < self.bounds.bottom:
+            dY = -self.y
+
+        # update the position
+        self.x += dX
+        self.y += dY
+
+        return dX, dY
+        
+        
Index: trunk/src/testing/dim/devices/puck.py
===================================================================
--- trunk/src/testing/dim/devices/puck.py	(revision 4)
+++ trunk/src/testing/dim/devices/puck.py	(revision 4)
@@ -0,0 +1,198 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import device
+from globals import *
+from math import cos, sin, radians
+
+
+def makeNew(deviceId):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return Puck(deviceId)
+
+
+# what each puck does
+PAN_PUCK = [1, 3]
+ROTATE_PUCK = [2]
+ZOOM_PUCK = [4]
+SPECIAL_PUCK = [5]
+
+
+# puck types
+DOWN = 2
+UP = 1
+
+
+class Puck(device.Device):
+    
+    def __init__(self, deviceId):
+        device.Device.__init__(self, "puck", deviceId, needPointer=True)
+        
+        # current state of the device
+        self.puckType = 1
+        self.x = 0   # position in SAGE coords
+        self.y = 0   # position in SAGE coords
+        self.clickX = 0  # where the click happened 
+        self.clickY = 0  # where the click happened
+        self.angle = 0   # current angle
+        self.prevDx = 0  # used for zoom
+        self.prevDy = 0
+        puckName = deviceId.split(":")[1]
+        self.puckId = int(puckName[ len(puckName)-1 ])   # the actual puckId from the tracker
+
+        if self.puckId in SPECIAL_PUCK:
+            self.specialDevice = True     # e.g. a magic carpet lens... generates different events
+
+
+    def onPointerAdded(self, pointerOverlay):
+        """ overriden so that we can set the correct pointer shape
+            for the event that this puck produces """
+        self.pointer = pointerOverlay
+
+        if self.puckId in PAN_PUCK:
+            self.pointer.setAnalogEvent(EVT_PAN)
+        elif self.puckId in ZOOM_PUCK:
+            self.pointer.setAnalogEvent(EVT_ZOOM)
+        elif self.puckId in ROTATE_PUCK:
+            self.pointer.setAnalogEvent(EVT_ROTATE)
+            
+
+    def onMessage(self, data, firstMsg=False):
+        tokens = data.split()
+        puckId =   int(tokens[1].strip())
+        x =      float(tokens[2].strip())
+        y =      float(tokens[3].strip())
+        angle =  float(tokens[4].strip())+90
+        puckType = int(tokens[5].strip())
+
+        # always convert to SAGE coords first
+        x = int(round(float(x) * self.displayBounds.getWidth()))
+        y = int(round(float(y) * self.displayBounds.getHeight()))
+
+        ## # if in local mode, convert to local coords based on bounds
+##         if not self.globalMode:
+##             x = float(x - self.bounds.left) / self.bounds.getWidth()
+##             y = float(y - self.bounds.bottom) / self.bounds.getHeight()
+
+        # set the correct state for the first msg
+        ## if firstMsg:
+##             self.x = x
+##             self.y = y
+##             self.angle = angle
+##             self.puckType = puckType
+##             if self.pointer:
+##                 self.pointer.movePointer(self.x, self.y)
+##                 self.pointer.pointerAngle(int(self.angle))
+##             return
+
+
+        # click
+        if (self.puckType != puckType) and (self.puckId not in SPECIAL_PUCK):
+            self.clickX, self.clickY = x, y
+            self.prevDy = self.prevDx = 0
+            self.puckType = puckType
+            forEvt = 0
+            if self.puckId in PAN_PUCK or self.dragMode:  
+                forEvt = 31000+EVT_PAN
+            elif self.puckId in ROTATE_PUCK:
+                forEvt = 31000+EVT_ROTATE
+            elif self.puckId in ZOOM_PUCK:
+                forEvt = 31000+EVT_ZOOM
+                
+            self.postEvtClick(x, y, 1, puckType==DOWN, forEvt)  # if puckType=2, isDown=True
+        
+        
+        # move
+        dx = dy = 0
+        if self.x != x or self.y != y:
+            dx = x - self.x ;  self.x = x
+            dy = y - self.y ;  self.y = y
+
+            if puckType == UP:    # no buttons pressed
+                self.postEvtMove(self.x, self.y, dx, dy)
+
+            elif puckType == DOWN:  # button pressed means different things depending on the puck
+                if self.puckId in PAN_PUCK or self.dragMode:  
+                    self.postEvtAnalog1(self.clickX, self.clickY, dx, dy, 0)
+                elif self.puckId in ROTATE_PUCK:
+                    self.postEvtAnalog2(self.clickX, self.clickY, dx, dy, 0)
+                elif self.puckId in ZOOM_PUCK:
+                    dx = self.x - self.clickX  # accumulated dx,dy from the click pos
+                    dy = self.y - self.clickY
+                    dx, dy = self.__rotatePoints(dx, dy)
+                    self.postEvtAnalog3(self.clickX, self.clickY, dx-self.prevDx, dy-self.prevDy, 0)
+                    self.prevDx = dx
+                    self.prevDy = dy
+                    
+                    
+            # move the pointer
+            if self.pointer: self.pointer.movePointer(self.x, self.y)        
+
+
+        # rotation
+        if self.angle != angle:
+            da = angle - self.angle
+            self.angle = angle
+            if da < -300:    # we went over the zero degree line counterclockwise, a hack
+                da = 360 + da
+            elif da > 300:   # we went over the zero degree line clockwise, a hack
+                da = (360 - da)*(-1)
+
+            if self.pointer: self.pointer.pointerAngle(int(self.angle))
+
+            # convert to normalized angle
+            da = (da/360.0)
+
+            # send the events based on which puck this is
+            #if self.puckId in ROTATE_PUCK and self.puckType == 2:
+            #    self.postEvtAnalog2(self.x, self.y, 0, 0, da)
+            #elif self.puckId in ZOOM_PUCK:
+            #    self.postEvtAnalog3(self.x, self.y, da, da, da)
+
+
+    def __rotatePoints(self, x, y):
+        """ rotate a point around origin... used for making
+            rotation events orientation independent """
+        a = -radians(self.angle)
+        newX = x*cos(a) - y*sin(a)
+        newY = x*sin(a) + y*cos(a)
+        return newX, newY
+    
Index: trunk/src/testing/dim/devices/mouse.py
===================================================================
--- trunk/src/testing/dim/devices/mouse.py	(revision 4)
+++ trunk/src/testing/dim/devices/mouse.py	(revision 4)
@@ -0,0 +1,176 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import device
+from globals import *
+import time
+from threading import Thread
+
+
+def makeNew(deviceId):
+    """ this is how we instantiate the device object from
+        the main program that loads this plugin """
+    return Mouse(deviceId)
+
+
+MOVE = 1
+CLICK = 2
+WHEEL = 3
+COLOR = 4
+
+LEFT=1
+RIGHT=2
+MIDDLE=3
+
+
+WHEEL_CLICK_TIME = 0.75  # seconds before there is a click event after wheel event
+
+
+class Mouse(device.Device):
+    
+    def __init__(self, deviceId):
+        device.Device.__init__(self, "mouse", deviceId, needPointer=True)
+        
+        # current state of the device
+        self.x = 0   # position in SAGE coords
+        self.y = 0   # position in SAGE coords
+        self.clickX = 0  # where the click happened 
+        self.clickY = 0  # where the click happened
+
+        self.buttons = {}  #key=BTN_ID, value=True|False
+        self.buttons[0] = False
+        self.buttons[LEFT] = False
+        self.buttons[RIGHT] = False
+        self.buttons[MIDDLE] = False
+        self.lastBtn = 0
+
+##         self.lastWheelTime = time.time()
+##         self.wheelClickThread = Thread(target=self.postWheelUpClick)
+##         self.wheelClickThread.start()
+##         self.wheeling = False
+                
+
+ ##    def postWheelUpClick(self):
+##         while doRun():
+##             if (time.time() - self.lastWheelTime) > WHEEL_CLICK_TIME and self.wheeling:
+##                 forEvt = EVT_ZOOM
+##                 self.postEvtClick(self.x, self.y, 4, False, forEvt)
+##                 self.wheeling = False
+
+##             time.sleep(0.1)
+            
+
+    def onMessage(self, data, firstMsg=False):
+        tokens = data.strip().split()
+        msgCode = int(tokens[0])
+
+        
+        # click
+        if msgCode == CLICK:
+            btnId = int(tokens[1])
+            isDown = bool(int(tokens[2]))
+            forEvt = 0
+            
+            if self.buttons[btnId] != isDown:
+                self.buttons[btnId] = isDown
+                self.lastBtn = btnId
+
+                if isDown:
+                    self.clickX, self.clickY = self.x, self.y
+                
+                if btnId == LEFT:
+                    forEvt = EVT_PAN
+                elif btnId == RIGHT:
+                    forEvt = EVT_ROTATE
+                elif btnId == MIDDLE:
+                    forEvt = EVT_ZOOM
+
+                self.postEvtClick(self.x, self.y, btnId, isDown, forEvt)
+
+
+        elif msgCode == WHEEL:
+            pass
+##             forEvt = EVT_ZOOM
+##             numSteps = -1*int(tokens[1])
+
+##             if (time.time() - self.lastWheelTime) > WHEEL_CLICK_TIME:
+##                 self.wheeling = True
+##                 self.postEvtClick(self.x, self.y, 4, True, forEvt)
+               
+##             #self.postEvtAnalog3(self.clickX, self.clickY, self.x, self.y, numSteps*15, 0, 0)
+##             self.postEvtAnalog3(self.clickX, self.clickY, numSteps*15, 0, 0)
+##             self.lastWheelTime = time.time()
+
+        
+            
+        elif msgCode == MOVE:
+            x = float(tokens[1].strip())
+            y = float(tokens[2].strip())
+            
+            # always convert to SAGE coords first
+            x = self.bounds.getX() + int(round(float(x) * self.bounds.getWidth()))
+            y = self.bounds.getY() + int(round(float(y) * self.bounds.getHeight()))
+            
+            x,y = self.smooth(x,y)
+
+            
+            dx = dy = 0
+            if self.x != x or self.y != y:
+                dx = x - self.x ;  self.x = x
+                dy = y - self.y ;  self.y = y
+
+                if self.buttons[self.lastBtn]:
+                    if self.lastBtn == LEFT:
+                        self.postEvtAnalog1(self.clickX, self.clickY, dx, dy, 0)
+                    elif self.lastBtn == RIGHT:
+                        self.postEvtAnalog2(self.clickX, self.clickY, dx, dy, 0)
+                    elif self.lastBtn == MIDDLE:
+                        self.postEvtAnalog3(self.clickX, self.clickY, dx, dy, 0)
+                else:
+                    self.postEvtMove(self.x, self.y, dx, dy)
+                    
+                # move the pointer
+                if self.pointer: self.pointer.movePointer(self.x, self.y)        
+
+
+        elif msgCode == COLOR:
+            #if self.pointer: self.pointer.setColor(tokens[1], tokens[2], tokens[3])
+            pass
Index: trunk/src/testing/dim/.project
===================================================================
--- trunk/src/testing/dim/.project	(revision 4)
+++ trunk/src/testing/dim/.project	(revision 4)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>DIM_experimental</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>
Index: trunk/src/testing/dim/device.py
===================================================================
--- trunk/src/testing/dim/device.py	(revision 4)
+++ trunk/src/testing/dim/device.py	(revision 4)
@@ -0,0 +1,202 @@
+############################################################################
+#
+# DIM - A Direct Interaction Manager for SAGE
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+import events
+from globals import *
+
+
+# for smoothing of input data
+SMOOTHING_BUFFER_SIZE = 10   # how many previous values do we take into account?
+SMOOTHING_MODIFIER    = 0.2  # the amount of smoothing, and delay (0=none, 1=tons)
+
+
+
+class Device:
+    """ events is a list of eventIds that this device can generate """
+
+    def __init__(self, deviceType, deviceId, needPointer, displayId=0):
+        self.deviceType = deviceType
+        self.deviceId = deviceId
+        self.displayId = displayId
+        self.__smoothingBuffer = []  # history of previous values (tuples of (x,y))
+        
+        # set the bounds
+        di = getSageData().getDisplayInfo(self.displayId)
+        self.bounds = Bounds(0, di.sageW, di.sageH, 0)
+        self.displayBounds = self.bounds   # first bounds are always equal to the display size
+        #self.globalMode = True  # False if in appMode... ie the events are forwarded to the app
+        self.toEvtHandler = None  # all our the events should go to this handler (ie device captured by the evtHandler)
+        self.lastMoveCallback = None  # this is used for generating EVT_LEFT_WINDOW and EVT_ENTERED_WINDOW
+        self.dragMode = False     # an overlay can request this device to produce drag event for a bit
+
+        # this is for app specific stuff such as magic carpet lenses
+        # these devices send special events
+        self.specialDevice = False   
+        self.specialId = 0        
+        
+        self.evtMgr = getEvtMgr()  # from globals
+        self.overlayMgr = getOverlayMgr()  # from globals
+
+        # we create a pointer if needed
+        self.pointer = None   
+        if needPointer:
+            self.overlayMgr.addOverlay(OVERLAY_POINTER, self.onPointerAdded, displayId=self.displayId)
+
+
+    def destroy(self):
+        if self.pointer:
+            self.overlayMgr.removeOverlay(self.pointer.overlayId)
+
+
+    def onPointerAdded(self, pointerOverlay):
+        self.pointer = pointerOverlay
+
+
+    ## def changeMode(self, toGlobal, newBounds):
+##         """ Changes the current mode for this device.
+##             toGlobal=False for appMode, True for globalMode
+##             You need to pass the new bounds in as well. If changing
+##             to appMode, pass in the appBounds in SAGE coords, otherwise
+##             pass in the SAGE display bounds.
+##         """
+    
+##         self.bounds = newBounds
+##         self.globalMode = toGlobal
+
+##         # now convert the position to those new bounds
+##         self.x = float(self.x - newBounds.left) / newBounds.getWidth()
+##         self.y = float(self.y - newBounds.bottom) / newBounds.getHeight()
+
+        
+        
+    def onMessage(self, data, firstMsg=False):
+        """ This method gets called when a message arrives from the HWCapture
+            for this device. In here you should provide the conversion from
+            HW events to the SAGE App Events. FirstMsg just signifies
+            that this is the very first message right after the device creation.
+            
+            Must be implemented by the subclass.
+        """
+        
+        raise NotImplementedError
+
+
+    def setSpecialId(self, newId):
+        self.specialId = newId
+
+
+    def getSpecialId(self):
+        """ When using special devices you need to specify which deviceId will be reported """
+        return self.specialId
+    
+
+    ### these are the methods to call when an event occurs
+    ### this will pass the event on to the system to be handled
+    
+    def postEvtMove(self, newX, newY, dX, dY):
+        evt = events.MoveEvent(self, newX, newY, dX, dY, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+            
+
+    def postEvtAnalog1(self, x, y, dX, dY, dZ):
+        evt = events.Analog1Event(self, x, y, dX, dY, dZ, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+
+
+    def postEvtAnalog2(self, x, y, dX, dY, dZ, angle = 0):
+        evt = events.Analog2Event(self, x, y, dX, dY, dZ, angle, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+
+
+    def postEvtAnalog3(self, x, y, dX, dY, dZ):
+        evt = events.Analog3Event(self, x, y, dX, dY, dZ, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+
+    
+    def postEvtClick(self, x, y, btnId, isDown, forEvt):
+        evt = events.ClickEvent(self, x, y, btnId, isDown, forEvt, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+        if not isDown:
+            self.toEvtHandler = None  # not captured anymore
+
+
+    def postEvtArrow(self, arrow, x, y):
+        evt = events.ArrowEvent(self, arrow, x, y, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+
+
+    def postEvtKey(self, key, x, y):
+        evt = events.KeyEvent(self, key, x, y, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+
+
+    def postEvtCustom(self, data):
+        evt = events.CustomEvent(self, data, self.toEvtHandler)
+        self.evtMgr.postEvent( evt )
+        
+
+
+
+    ### should be called by the subclass if smoothing is desired for every frame (new input)
+    ### takes in two new values for x and y and returns smoothed values for x and y
+    def smooth(self, newX, newY, bufSize=SMOOTHING_BUFFER_SIZE, smoothAmount=SMOOTHING_MODIFIER):
+        self.__smoothingBuffer.insert(0, (newX, newY))   # insert the newest
+
+        if len(self.__smoothingBuffer) > bufSize:
+            del self.__smoothingBuffer[ len(self.__smoothingBuffer)-1 ]  # delete the oldest
+
+        # do the non-linear averaging
+        totX, totY, totMod = 0.0, 0.0, 0.0
+        mod = 1.0 
+        for i in range(0, len(self.__smoothingBuffer)):
+            totX += self.__smoothingBuffer[i][0]*mod
+            totY += self.__smoothingBuffer[i][1]*mod
+            totMod += mod
+            mod = mod*smoothAmount
+
+        smoothX = int(round(totX / totMod))
+        smoothY = int(round(totY / totMod))
+
+        # record the new value
+        self.__smoothingBuffer[0] = (smoothX, smoothY)
+                
+        return smoothX, smoothY
+        
Index: trunk/src/testing/readme.txt
===================================================================
--- trunk/src/testing/readme.txt	(revision 4)
+++ trunk/src/testing/readme.txt	(revision 4)
@@ -0,0 +1,243 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+-------------------------------------------------------------------------------
+
+		         README file for SAGE v2.5
+		
+		written by Byungil(Brent) Jeong, Ratko Jagodic
+		
+-------------------------------------------------------------------------------
+
+
+########################################################################
+   
+   NEEDS TO BE CHANGED FOR SAGE 3!!!   (Ratko, 07/12/04)
+
+########################################################################
+
+
+
+0. Differences from v2.1
+	(1) Direct interaction with the display is now possible with a joystick
+	    connected to a machine where the UI is running
+	    (read more about it in ui/README)
+	(2) Launching SAGE and all of the components is now greatly simplified
+	    through SageLauncher. All of the components can be configured as well.
+	(3) SageProxy is now included in the SAGE distribution
+	    (for more info check bin/sageProxy/README)
+	(4) Bug fixes, minor changes to the applications
+
+	
+1. Install libraries
+	For SAGE:
+
+	- SAGE needs Quanta0.4 or greater (www.evl.uic.edu/cavern/quanta)
+	- SDL-1.2.8 or greater
+	- readline (runtime and development packages)
+
+	For SageLauncher, SageProxy, AppLauncher, FileServer:
+
+	- python 2.3 or later
+	- wxPython 2.6.2 or later
+	- numarray or Numeric
+
+
+2. Setup Environments 
+	(1) Set environment variable SAGE_DIRECTORY in your profile
+		setenv SAGE_DIRECTORY path_to_sage_directory in .tcshrc
+		export SAGE_DIRECTORY=path_to_sage_directory in .bashrc
+	(2) Add $SAGE_DIRECTORY/bin to your path
+		set path = ($SAGE_DIRECTORY/bin $path) in .tcshrc
+		export path=$SAGE_DIRECTORY/bin:$path  in .bashrc
+	(3) Add $SAGE_DIRECTORY/lib to LD_LIBRARY_PATH
+		setenv LD_LIBRARY_PATH $SAGE_DIRECTORY/lib:$LD_LIBRARY_PATH in .tcshrc
+		export LD_LIBRARY_PATH=$SAGE_DIRECTORY/lib:$LD_LIBRARY_PATH in .bashrc	
+
+
+3. Modify make file
+	open Makefile in $SAGE_DIRECTORY/src
+	(1) set QUANTA_DIR to QUANTA include directory in your machine
+
+	  
+4. Compile
+	(1) execute make in $SAGE_DIRECTORY
+	(2) if you get errors, check include paths and library paths in make files in subdirectories
+	(3) execute make install in SAGE_DIRECTORY
+
+
+5. Edit Configuration Files
+	(1) go to $SAGE_DIRECTORY/bin
+	(2) open "fsManager.conf" and edit following parameters
+	  a. fsManager : name and IP address of the machine on which
+			Free Space Manager runs. Usually the master node of cluster.
+			You can specify two IP addresses here from v1.3.
+			The first IP adderss will be used for system components
+			(SAIL, SAGE Receiver) and the second IP address will be used
+			for UI connections (sent to connection manager).
+			If only one IP address is specified, it will be used for both.
+
+	  b. systemPort : port for SAGE system message channel
+
+	  c. uiPort : port for SAGE UI message	channel
+
+	  d. trackPort : port for tracking data (for LambdaTable)
+
+	  e. conManager : the ip address and port number of Connection Manager
+		  - Connection manager is an UI server which manages connections among
+		    SAGE UIs and fsManagers
+		  - If you don't have a connection manager, just leave these fields 
+		    as they are
+
+	  f. tileConfiguration : name of tile configuration file	(stdtile-1.conf)	
+	  
+	  g. receiverSyncPort : port number of sync connection on displaying side
+	  h. receiverBufSize : upper bound of receiving buffer size for a pixel stream in MB
+	  i. fullScreen : 1 for full screen mode display
+	  j. winTime : set the window move/resize latency. If users set this value bigger than 0,
+	  		# of window animation steps are dynamically changed to keep this constraint. 
+			(under development)
+	  k. winStep : set the number of steps in window animation
+	  l. rcvNwBufSize : socket buffer size of receivers (SAGE display)
+	  m. sendNwBufSize : socket buffer size of senders (SAIL)
+	  n. MTU : MTU size for UDP
+	  	
+	(4) open "stdtile-1.conf" and edit following parameters
+	  a. Dimensions : number of columns and rows of tiled display
+	  b. Mullions : width(inches) of top, down, left, and right mullions
+	  c. Resolution : screen resolution of each tile
+	  d. PPI : pixels per inch of each tile
+	  e. Machines : number of display nodes which drive tiled display
+	  f. for each DisplayNode
+	  		Name : name of each display node (not critical)
+			IP : ip address of each display node
+			Monitors : number of tiles which each node drives
+			  (xPos, yPos) of each tile
+			  (0,0) is the tile at the lower left corner
+	(5) open "tileNodes.list" and list the ip addresses 
+		of all your cluster nodes					
+
+
+6. Test Whether SAGE is Working Properly
+	In $SAGE_DIRECTORY/bin
+	(1) Execute "fsManager". Tiled display becomes black if it runs correctly.
+		Users can specify a configuration file name as command-line argument.
+		Otherwise "fsManager.conf" is used.
+	(2) Open another terminal and execute "render"
+	(3) Open another terminal and execute "fsConsole"
+	(4) press TAB key twice. fsConsole commands are listed.
+	(5) ? or help command gives you short description for each command
+	(6) If you type initial character of a command and press TAB key,
+		the command is completed. Then, press TAB key again. You can see
+		the description of the command.
+	(7) move 0 1000 0 : move the app window
+
+
+7. Shutdown SAGE
+	(1) you can shutdown SAGE using fsConsole command "shutdown"
+	(2) if the command doesn't work, execute the script KILL_ALL 
+
+
+7. Typical Usage - Using SageLauncher to set up, start and stop everything
+	You will need all additional dependencies installed - python, wxPython, numarray
+	(1) In $SAGE_DIRECTORY/bin type "sage". This will start the SageLauncher which 
+	    will help you set up all the SAGE components and get them running easily
+	(2) Press START to run SAGE and the checked components 
+	    (the default settings should work just fine)
+	(3) To shutdown running components (incl SAGE), press STOP.
+	(3) Alternatively, check different components that you wish to run with SAGE. 
+	    You can also change the settings on each component from the Launcher.
+	    
+
+8. Using SAGE Bridge
+	(1) SAGE Bridge receives pixel streams from applications and distributes
+		to multiple SAGE sessions (a fsManager per session).
+	(2) SAGE Bridge is supposed to be executed on high-performance PCs bridging
+		rendering clusters and display clusters.
+		
+	(3) Install SAGE on the SAGE Bridge nodes in the same manner
+	(4) Edit sageBridge.conf in $SAGE_DIRECTORY/bin
+		- masterIP : the ip address of master node of SAGE Bridge cluster
+		- slaveList slaveNum ip1 ip2 ip3 ... : the slave node list of  
+			SAGE Bridge cluster (note : multi-node SAGE Bridge is currently 
+			unstable. Set the slave number to zero for now. Instead, you
+			can run multiple single-node SAGE Bridges independently)
+		- streamPort : base port number to be used for the pixel streams between
+			apps and SAGE Bridge
+		- msgPort : message channel port number
+		- syncPort : synchronization channel port number
+		- screenRes : debugging window resolution.
+			SAGE Bridge can display received pixels for debugging.
+			This feature can be on/off by adding/removing BRIDGE_DEBUG_ flag
+			in the makefile in $SAGE_DIRECTORY/src
+		- rcvNwBufSize, sendNwBufSize, MTU : network parmeters used for
+			the pixel streams between apps and SAGE Bridge
+
+	(5) Execute the binary "sageBridge" in $SAGE_DIRECTORY/bin.
+		Users can specify a configuration file name as command-line argument.
+		Otherwise "sageBridge.conf" is used.
+	(6) Execute "fsManager" on display cluster
+
+	(7) Make sure app configuration file includes following items:
+		 (appLauncher will generate these automatically if the application
+		 was started with a right click from the SAGE UI)
+		- bridgeOn true : determine whether this app uses sageBridge or not
+		- bridgeIP 192.168.81.1 : master IP of SAGE Bridge
+		- bridgePort 42000 : message port of SAGE Bridge
+		- fsIP     192.168.81.11 
+		- fsPort   20002 : IP and system port of the first fsManager
+		
+	(8) Launch applications. This is best done through SAGE UI. When the application
+		is started with a right-click on the app icon in the UI, it will use
+		sageBridge and can then be shared with other SAGE sessions.
+
+	(9) If users want to share this app to another SAGE session through SAGE UI,
+	        just drag an application window from one SAGE session onto the tab 
+		of the other session and the app will be shared (obviously you must
+		be connected to both SAGE sessions for this to work)
+
+		Alternatively, you can share the applications using uiConsole:
+		execute "uiConsole" to be connected to the first fsManager
+		> uiConsole fsManager-1.conf (config file for the first fsManager)
+
+		Then, execute following command
+		
+		share appID fsIP2 fsPort2 (appIDs are assigned in execution order
+			ex) 0, 1, 2,...  
+			fsIP2, fsPort2 : IP and port number of the second fsManager)
+
+		Then, the app window shows up on the second SAGE session.
+		
Index: trunk/src/testing/config.mk
===================================================================
--- trunk/src/testing/config.mk	(revision 4)
+++ trunk/src/testing/config.mk	(revision 4)
@@ -0,0 +1,169 @@
+# Machine specific settings
+MACHINE=$(shell uname -s)
+   #Darwin  MacOSX
+   #Linux   linux
+   #Solaris SunOS
+
+ARCHITECTURE=$(shell uname -m)
+   #i386  MacOSX
+   #i686    Linux 32bit
+   #x86_64  Linux 64bit
+   #ia64    Linux Itanium 64bit
+   #ppc64   Linux PPC PS3
+
+ifneq ($(MACHINE), Darwin)
+GLSL_YUV=1
+endif
+# To enable audio, uncomment the following line
+#AUDIO=1
+#SAIL_ONLY=1
+#SUN_GCC=1
+FS_CONSOLE=fsConsole
+
+COMPILER=g++
+SAGE_CFLAGS=-fPIC 
+SAGE_LDFLAGS=-Wl,-rpath=${SAGE_DIRECTORY}/lib
+
+# QUANTA settings
+QUANTA_DIR=${SAGE_DIRECTORY}/QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L${SAGE_DIRECTORY}/lib -lquanta
+QUANTA_LIB=libquanta.so
+
+# SDL
+ifndef SAIL_ONLY
+SDL_CFLAGS=`sdl-config --cflags`
+SDL_LIBS=`sdl-config --libs`
+endif
+
+# GLUT
+GLUT_CFLAGS=
+GLUT_LDFLAGS=-lglut
+
+# READLINE settings
+READLINE_CFLAGS=
+READLINE_LIB=-lreadline
+
+ifdef AUDIO
+#PORTAUDIO
+PORTAUDIO_DIR=/usr/local
+PORTAUDIO_CFLAGS=-I${PORTAUDIO_DIR}/include -DSAGE_AUDIO
+PAUDIO_LIB= -L${PORTAUDIO_DIR}/lib -lportaudio -lasound
+endif
+
+
+# SAIL library name
+SAIL_LIB=libsail.so
+
+# how to build a shared library
+SHLD_FLAGS=-shared 
+
+# GPU programming setting
+ifeq ($(GLSL_YUV), 1)
+  GLEW_LIB= -lGLEW
+  GLEW_CFLAGS=
+  GLSL_YUV_DEFINE=-DGLSL_YUV
+else
+  GLEW_LIB=
+  GLEW_CFLAGS=
+  GLSL_YUV_DEFINE=
+endif
+
+ifeq ($(MACHINE), Darwin)
+  # SAIL library name
+  SAIL_LIB=libsail.dylib
+
+ifdef AUDIO
+  PORTAUDIO_DIR=/opt/local
+  PORTAUDIO_CFLAGS=-I${PORTAUDIO_DIR}/include -DSAGE_AUDIO
+  PAUDIO_LIB= -L${PORTAUDIO_DIR}/lib -lportaudio
+endif
+
+  SDL_CFLAGS=-I/Library/Frameworks/SDL.framework/Headers -FSDL -FSDL_ttf -FOpenGL
+  SDL_LIBS=-framework SDL -framework Cocoa
+  FONT_LIB=-framework SDL_ttf
+
+  SAGE_CFLAGS=-fPIC -m32
+  SAGE_LDFLAGS=-m32
+
+  MAGICK_CFLAGS=-I/opt/local/include
+  MAGICK_LIBS=-L/opt/local/lib -lfreetype -lz -lMagick -ltiff -ljpeg -lpthread -lm -lWand
+
+  # QUANTA library name
+  QUANTA_LIB=libquanta.dylib
+
+  # READLINE settings
+  READLINE_CFLAGS=-I/opt/local/include
+  READLINE_LIB=-L/opt/local/lib -lreadline -lcurses
+
+  # Lower-level graphics library
+  XLIBS= -framework OpenGL -lobjc -framework aGL -framework Carbon -framework QuartzCore
+
+  # how to build a shared library
+  SHLD_FLAGS=-m32 -dynamiclib -flat_namespace -undefined suppress
+
+else
+
+ifeq ($(ARCHITECTURE), x86_64)
+  # Lower-level graphics library
+  XLIBS=-L/usr/X11R6/lib64 -lGLU -lGL -lXmu -lXi -lXext -lX11
+else
+
+ifeq ($(ARCHITECTURE), ppc64)
+  # SDL
+  SDL_CFLAGS=`sdl-config --cflags`
+  SDL_LIBS=-lSDL
+
+  # Lower-level graphics library
+  XLIBS=-L/usr/X11R6/lib -lGLU -lGL -lXmu -lXi -lXext -lX11
+else
+
+ifeq ($(ARCHITECTURE), ia64)
+  # Lower-level graphics library
+  XLIBS=-L/usr/X11R6/lib64 -lGLU -lGL -lXmu -lXi -lXext -lX11
+else
+
+  # anything else is 32bit 
+
+  # READLINE settings
+  READLINE_LIB=-lreadline
+
+  # Lower-level graphics library
+  XLIBS=-L/usr/X11R6/lib -lGLU -lGL -lXmu -lXi -lXext -lX11
+
+ifdef AUDIO
+  PAUDIO_LIB= -L${PORTAUDIO_DIR}/lib -lportaudio -lasound
+endif
+
+endif
+endif
+endif
+endif
+
+
+ifeq ($(MACHINE), SunOS)
+
+ifndef SUN_GCC
+COMPILER=CC
+SAGE_CFLAGS=-Kpic -m64
+SUN_LIBS=-lrt -lnsl -lsocket -lCrun -lCstd
+SHLD_FLAGS=-G -Kpic -m64 
+else
+COMPILER=c++
+SAGE_CFLAGS=-m64 -Wno-deprecated -fPIC 
+SUN_LIBS=-lrt -lnsl -lsocket 
+SHLD_FLAGS=-shared -m64 
+endif
+
+SAGE_LDFLAGS=-m64
+SUN_INCLUDE=-I/usr/local/include 
+
+GLUT_CFLAGS=-I/opt/SUNWfreeglut/include
+GLUT_LDFLAGS=-L/opt/SUNWfreeglut/lib/amd64 -lglut
+
+# READLINE settings
+READLINE_CFLAGS=-I/usr/local/include 
+READLINE_LIB=-L/usr/local/lib/64 -lreadline -lcurses
+
+endif
+
Index: trunk/src/testing/etc/rpm/sage.spec
===================================================================
--- trunk/src/testing/etc/rpm/sage.spec	(revision 4)
+++ trunk/src/testing/etc/rpm/sage.spec	(revision 4)
@@ -0,0 +1,431 @@
+Summary: SAGE Scalable Adaptive Graphics Environment
+Name: sage-graphics
+Version: 3.2
+Release: 176
+Source0: %{name}-%{version}.tar.gz
+License: BSD
+Group: Graphics/Streaming
+Provides: sage  
+BuildRoot: %{_tmppath}/%{name}-%{version}-root 
+
+%if 0%{?suse_version} > 1120
+BuildRequires: gcc-c++, libSDL-devel, libreadline6, readline-devel, freeglut, freeglut-devel, ImageMagick, ImageMagick-devel, libjpeg-devel, glew-devel
+Requires: libjpeg, libSDL-1_2-0
+%endif
+%if 0%{?suse_version} == 1120
+BuildRequires: gcc-c++, libSDL-1_2-0, libSDL-devel, libreadline6, readline-devel, libncurses6, ncurses-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libMagickWand2, glew-devel
+%endif
+%if 0%{?suse_version} == 1110
+BuildRequires: gcc, gcc43, gcc-c++, gcc43-c++, SDL, SDL-devel, libreadline5, libncurses5, readline-devel, ncurses-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libMagickWand1, glew-devel
+%endif
+%if 0%{?suse_version} == 1100
+BuildRequires: gcc, gcc43, gcc-c++, gcc43-c++, SDL, SDL-devel, libreadline5, libncurses5, readline-devel, ncurses-devel,freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libMagickWand1, glew-devel
+%endif
+%if 0%{?centos_version} > 500
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libXmu, libXmu-devel, libXi, libXi-devel, glew-devel
+%endif
+%if 0%{?fedora} == 10
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libXmu, libXmu-devel, libXi, libXi-devel, glew-devel
+%endif
+%if 0%{?fedora} == 11
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libXmu, libXmu-devel, libXi, libXi-devel, glew-devel
+%endif
+%if 0%{?fedora} == 12
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libXmu, libXmu-devel, libXi, libXi-devel, glew-devel
+%endif
+%if 0%{?rhel_version} == 406
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, ncurses, ncurses-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, glew-devel
+%endif
+%if 0%{?rhel_version} == 501
+BuildRequires: gcc, gcc-c++, SDL, SDL-devel, ncurses, ncurses-devel, readline, readline-devel, freeglut, freeglut-devel, libjpeg, libjpeg-devel, ImageMagick, ImageMagick-devel, libXmu, libXmu-devel, libXi, libXi-devel, glew-devel
+%endif
+
+#!BuildIgnore: post-build-checks
+
+%description
+SAGE is a graphics streaming architecture for supporting collaborative scientific visualization environments with potentially hundreds of megapixels of contiguous display resolution. In collaborative scientific visualization, it is crucial to share high-resolution imagery as well as high-definition video among groups of collaborators at local or remote sites. The network-centered architecture of SAGE allows collaborators to simultaneously run various applications (such as 3D rendering, remote desktop, video streams and 2D maps) on local or remote clusters, and share them by streaming the pixels of each application over ultra-high-speed networks to large tiled displays. SAGE streaming architecture is designed so that the output of arbitrary M by N pixel rendering cluster nodes can be streamed to X by Y pixel display screens, allowing user-definable layouts on the display. The dynamic pixel routing capability of SAGE lets users freely move and resize each application's imagery over tiled displays in run-time, tightly synchronizing the multiple visualization streams to form a single stream.
+
+
+%package devel  
+License:        BSD
+Summary:        Include Files mandatory for Development  
+Group:          Graphics/Streaming
+Requires:       sage = %{version}
+ 
+%description devel
+This package contains the necessary include files needed to develop SAGE applications.
+
+
+%prep
+%setup
+%build
+./configure
+make
+%install
+make PREFIX=${RPM_BUILD_ROOT} install
+%clean
+%{__rm} -rf %{buildroot}  
+
+%post
+ldconfig
+
+%files
+%defattr(-,root,root)
+/etc/profile.d/sage.csh
+/etc/profile.d/sage.sh
+/etc/ld.so.conf.d/sage.conf
+/usr/local/sage/sageConfig/applications/applications.conf
+/usr/local/sage/sageConfig/applications/imageviewer.conf
+/usr/local/sage/sageConfig/applications/atlantis.conf
+/usr/local/sage/sageConfig/applications/render.conf
+/usr/local/sage/sageConfig/applications/VNCViewer.conf
+/usr/local/sage/sageConfig/applications/bitplayer.conf
+/usr/local/sage/sageConfig/sageBridge.conf
+/usr/local/sage/sageConfig/stdtile.conf
+/usr/local/sage/sageConfig/fsManager.conf
+/usr/local/sage/sageConfig/stdtile-1.conf
+/usr/local/sage/sageConfig/stdtile-20.conf
+/usr/local/sage/sageConfig/stdtile-2.conf
+/usr/local/sage/sageConfig/fileServer/fileServer.conf
+/usr/local/sage/dim/device.py
+/usr/local/sage/dim/overlays/__init__.py
+/usr/local/sage/dim/overlays/wall.py
+/usr/local/sage/dim/overlays/pointer.py
+/usr/local/sage/dim/overlays/app.py
+/usr/local/sage/dim/listener.py
+/usr/local/sage/dim/devices/__init__.py
+/usr/local/sage/dim/devices/puck.py
+/usr/local/sage/dim/devices/joystick.py
+/usr/local/sage/dim/devices/mouse.py
+/usr/local/sage/dim/hwcapture/go.bat
+/usr/local/sage/dim/hwcapture/pucks.py
+/usr/local/sage/dim/hwcapture/localPointer.py
+/usr/local/sage/dim/hwcapture/managerConn.py
+/usr/local/sage/dim/hwcapture/joystick.py
+/usr/local/sage/dim/hwcapture/mouse_to_joy.PIE
+/usr/local/sage/dim/__init__.py
+/usr/local/sage/dim/sageGate.py
+/usr/local/sage/dim/overlayManager.py
+/usr/local/sage/dim/dim.py
+/usr/local/sage/dim/eventManager.py
+/usr/local/sage/dim/sageGateBase.py
+/usr/local/sage/dim/sageApp.py
+/usr/local/sage/dim/deviceManager.py
+/usr/local/sage/dim/events.py
+/usr/local/sage/dim/eventHandler.py
+/usr/local/sage/dim/globals.py
+/usr/local/sage/dim/sageData.py
+/usr/local/sage/dim/hwcapture.py
+/usr/local/sage/dim/sageDisplayInfo.py
+/usr/local/sage/dim/overlay.py
+/usr/local/sage/bin/bplay-noglut
+/usr/local/sage/bin/appLauncher/appLauncher.py
+/usr/local/sage/bin/appLauncher/subprocess.py
+/usr/local/sage/bin/appLauncher/myprint.py
+/usr/local/sage/bin/appLauncher/data.py
+/usr/local/sage/bin/appLauncher/KILL_LAUNCHER.py
+/usr/local/sage/bin/appLauncher/admin.py
+/usr/local/sage/bin/appLauncher/README
+/usr/local/sage/bin/appLauncher/GO
+/usr/local/sage/bin/appLauncher/request.py
+/usr/local/sage/bin/VNCViewer
+/usr/local/sage/bin/fsManager
+/usr/local/sage/bin/subprocess.py
+/usr/local/sage/bin/sageLauncher.py
+/usr/local/sage/bin/sagePath.py
+/usr/local/sage/bin/checker
+/usr/local/sage/bin/atlantis
+/usr/local/sage/bin/fsConsole
+/usr/local/sage/bin/yuv.frag
+/usr/local/sage/bin/uiConsole
+/usr/local/sage/bin/render
+/usr/local/sage/bin/sageProxy/sageUIDataInfo.py
+/usr/local/sage/bin/sageProxy/SAGEGate.py
+/usr/local/sage/bin/sageProxy/sageProxy.py
+/usr/local/sage/bin/sageProxy/sageDisplayInfo.py
+/usr/local/sage/bin/sageProxy/SAGEApp.py
+/usr/local/sage/bin/fileServer/dirToDxt.py
+/usr/local/sage/bin/fileServer/makeThumbs.py
+/usr/local/sage/bin/fileServer/KILL_SERVER.py
+/usr/local/sage/bin/fileServer/misc/countPDFpages.py
+/usr/local/sage/bin/fileServer/misc/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/discinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/cdrommodule.c
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/audioinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/datainfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/vcdinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/lsdvd.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/dvdinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/ifomodule.c
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/CDDB.py
+/usr/local/sage/bin/fileServer/misc/mmpython/disc/DiscID.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/jpginfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/IPTC.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/bins.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/tiffinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/ImageInfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/pnginfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/image/EXIF.py
+/usr/local/sage/bin/fileServer/misc/mmpython/table.py
+/usr/local/sage/bin/fileServer/misc/mmpython/version.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/tag.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/frames.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/binfuncs.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/utils.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyeD3/mp3.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/flacinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/ogginfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/eyed3info.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/pcminfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/m4ainfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/webradioinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/id3.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/mp3info.py
+/usr/local/sage/bin/fileServer/misc/mmpython/audio/ac3info.py
+/usr/local/sage/bin/fileServer/misc/mmpython/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/synchronizedobject.py
+/usr/local/sage/bin/fileServer/misc/mmpython/mminfo
+/usr/local/sage/bin/fileServer/misc/mmpython/COPYING
+/usr/local/sage/bin/fileServer/misc/mmpython/doc/generate
+/usr/local/sage/bin/fileServer/misc/mmpython/doc/.cvsignore
+/usr/local/sage/bin/fileServer/misc/mmpython/PKG-INFO
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/iptc/iptc.pot
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/iptc/en.mo
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/iptc/en.po
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/qtudta/qtudta.pot
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/qtudta/en.mo
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/qtudta/en.po
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/aviinfo/en.mo
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/aviinfo/en.po
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/id3v2/en.mo
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/id3v2/en.po
+/usr/local/sage/bin/fileServer/misc/mmpython/i18n/id3v2/id3v2.pot
+/usr/local/sage/bin/fileServer/misc/mmpython/README
+/usr/local/sage/bin/fileServer/misc/mmpython/misc/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/misc/xmlinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/CREDITS
+/usr/local/sage/bin/fileServer/misc/mmpython/MANIFEST.in
+/usr/local/sage/bin/fileServer/misc/mmpython/video/movinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/mkvinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/mpeginfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/vcdinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/__init__.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/asfinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/ogminfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/movlanguages.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/fourcc.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/riffinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/video/realinfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/mediainfo.py
+/usr/local/sage/bin/fileServer/misc/mmpython/setup.py
+/usr/local/sage/bin/fileServer/misc/mmpython/factory.py
+/usr/local/sage/bin/fileServer/misc/imsize.py
+/usr/local/sage/bin/fileServer/fileServer.py
+/usr/local/sage/bin/sageDisplayManager
+/usr/local/sage/bin/sageBridge
+/usr/local/sage/bin/bridgeConsole
+/usr/local/sage/bin/imageviewer
+/usr/local/sage/bin/sage
+/usr/local/sage/bin/yuv.vert
+/usr/local/sage/lib64/libquanta.so
+/usr/local/sage/lib64/libsail.so
+/usr/local/sage/ui/Graph.py
+/usr/local/sage/ui/fileViewer.py
+/usr/local/sage/ui/canvases.py
+/usr/local/sage/ui/images/back_up.jpg
+/usr/local/sage/ui/images/pause_up.jpg
+/usr/local/sage/ui/images/atlantis_down.jpg
+/usr/local/sage/ui/images/play_over.jpg
+/usr/local/sage/ui/images/no_preview.png
+/usr/local/sage/ui/images/hdmovie_up.jpg
+/usr/local/sage/ui/images/teravision_up.jpg
+/usr/local/sage/ui/images/SAGEapp_19.jpg
+/usr/local/sage/ui/images/vra_down.jpg
+/usr/local/sage/ui/images/minimize_shape.gif
+/usr/local/sage/ui/images/SAGEapp_08.jpg
+/usr/local/sage/ui/images/stats_BW_up.jpg
+/usr/local/sage/ui/images/inst_down.jpg
+/usr/local/sage/ui/images/gadgets_up.jpg
+/usr/local/sage/ui/images/default_down.jpg
+/usr/local/sage/ui/images/red_circle.gif
+/usr/local/sage/ui/images/handle1.jpg
+/usr/local/sage/ui/images/play_down.jpg
+/usr/local/sage/ui/images/render_up.jpg
+/usr/local/sage/ui/images/magicarpet_down.jpg
+/usr/local/sage/ui/images/faster_down.jpg
+/usr/local/sage/ui/images/stats_BW_over.jpg
+/usr/local/sage/ui/images/stop_over.jpg
+/usr/local/sage/ui/images/default_over.jpg
+/usr/local/sage/ui/images/stats_FPS_down.jpg
+/usr/local/sage/ui/images/stop_down.jpg
+/usr/local/sage/ui/images/slower_up.jpg
+/usr/local/sage/ui/images/stats_FPS_over.jpg
+/usr/local/sage/ui/images/bitplay_over.jpg
+/usr/local/sage/ui/images/rotate_shape.gif
+/usr/local/sage/ui/images/back_over.jpg
+/usr/local/sage/ui/images/magicarpet_up.jpg
+/usr/local/sage/ui/images/inst_up.jpg
+/usr/local/sage/ui/images/app_panel_background.png
+/usr/local/sage/ui/images/stats_Nodes_over.jpg
+/usr/local/sage/ui/images/scrollRight_down.jpg
+/usr/local/sage/ui/images/SAGEapp_14.jpg
+/usr/local/sage/ui/images/bitplay_down.jpg
+/usr/local/sage/ui/images/mplayer_over.jpg
+/usr/local/sage/ui/images/teravision_down.jpg
+/usr/local/sage/ui/images/svc_down.jpg
+/usr/local/sage/ui/images/handle.jpg
+/usr/local/sage/ui/images/stats_BW_down.jpg
+/usr/local/sage/ui/images/gadgets_down.jpg
+/usr/local/sage/ui/images/stats_Streams_down.jpg
+/usr/local/sage/ui/images/scrollLeft_down.jpg
+/usr/local/sage/ui/images/remote_down.jpg
+/usr/local/sage/ui/images/stop_up.jpg
+/usr/local/sage/ui/images/mplayer_up.jpg
+/usr/local/sage/ui/images/vncviewer_up.jpg
+/usr/local/sage/ui/images/juxtaview_up.jpg
+/usr/local/sage/ui/images/SAGEapp_01.jpg
+/usr/local/sage/ui/images/teravision_over.jpg
+/usr/local/sage/ui/images/remote_over.jpg
+/usr/local/sage/ui/images/mplayer_down.jpg
+/usr/local/sage/ui/images/play_up.jpg
+/usr/local/sage/ui/images/scrollRight_up.jpg
+/usr/local/sage/ui/images/app_info_background.png
+/usr/local/sage/ui/images/atlantis_up.jpg
+/usr/local/sage/ui/images/remote_up.jpg
+/usr/local/sage/ui/images/juxtaview_over.jpg
+/usr/local/sage/ui/images/stats_FPS_up.jpg
+/usr/local/sage/ui/images/SAGEapp_15.jpg
+/usr/local/sage/ui/images/default_up.jpg
+/usr/local/sage/ui/images/back_down.jpg
+/usr/local/sage/ui/images/reset_down.jpg
+/usr/local/sage/ui/images/slower_over.jpg
+/usr/local/sage/ui/images/SAGEapp_07.jpg
+/usr/local/sage/ui/images/SAGEapp_17.jpg
+/usr/local/sage/ui/images/pause_over.jpg
+/usr/local/sage/ui/images/SAGEapp_04.jpg
+/usr/local/sage/ui/images/svc_up.jpg
+/usr/local/sage/ui/images/slower_down.jpg
+/usr/local/sage/ui/images/juxtaview_down.jpg
+/usr/local/sage/ui/images/menu_bar.jpg
+/usr/local/sage/ui/images/close_shape.gif
+/usr/local/sage/ui/images/retrieving_preview.png
+/usr/local/sage/ui/images/scrollLeft_up.jpg
+/usr/local/sage/ui/images/stats_Nodes_down.jpg
+/usr/local/sage/ui/images/vncviewer_down.jpg
+/usr/local/sage/ui/images/svc_over.jpg
+/usr/local/sage/ui/images/help.png
+/usr/local/sage/ui/images/gadgets_over.jpg
+/usr/local/sage/ui/images/atlantis_over.jpg
+/usr/local/sage/ui/images/SAGEapp_05.jpg
+/usr/local/sage/ui/images/stats_green.jpg
+/usr/local/sage/ui/images/green_circle.gif
+/usr/local/sage/ui/images/render_down.jpg
+/usr/local/sage/ui/images/magicarpet_over.jpg
+/usr/local/sage/ui/images/faster_up.jpg
+/usr/local/sage/ui/images/SAGEapp_10.jpg
+/usr/local/sage/ui/images/stats_Streams_up.jpg
+/usr/local/sage/ui/images/hdmovie_over.jpg
+/usr/local/sage/ui/images/SAGEapp_02.jpg
+/usr/local/sage/ui/images/bitplay_up.jpg
+/usr/local/sage/ui/images/vra_up.jpg
+/usr/local/sage/ui/images/stats_Streams_over.jpg
+/usr/local/sage/ui/images/maximize_shape.gif
+/usr/local/sage/ui/images/hdmovie_down.jpg
+/usr/local/sage/ui/images/pause_down.jpg
+/usr/local/sage/ui/images/faster_over.jpg
+/usr/local/sage/ui/images/SAGEapp_06.jpg
+/usr/local/sage/ui/images/scrollRight_over.jpg
+/usr/local/sage/ui/images/SAGEapp_18.jpg
+/usr/local/sage/ui/images/stats_Nodes_up.jpg
+/usr/local/sage/ui/images/SAGEapp_03.jpg
+/usr/local/sage/ui/images/scrollLeft_over.jpg
+/usr/local/sage/ui/preferences.py
+/usr/local/sage/ui/sageGate.py
+/usr/local/sage/ui/pointers.py
+/usr/local/sage/ui/Mywx.py
+/usr/local/sage/ui/SAGEShape.py
+/usr/local/sage/ui/sageGateBase.py
+/usr/local/sage/ui/sageApp.py
+/usr/local/sage/ui/launcherAdmin.py
+/usr/local/sage/ui/sageui.py
+/usr/local/sage/ui/sageAppPerfInfo.py
+/usr/local/sage/ui/help.py
+/usr/local/sage/ui/misc/__init__.py
+/usr/local/sage/ui/misc/imsize.py
+/usr/local/sage/ui/SAGEDrawObject.py
+/usr/local/sage/ui/globals.py
+/usr/local/sage/ui/sageData.py
+/usr/local/sage/ui/users.py
+/usr/local/sage/ui/sageDisplayInfo.py
+/usr/local/sage/ui/setup.py
+/usr/local/sage/ui/connectionManager/admin.py
+/usr/local/sage/ui/connectionManager/README
+/usr/local/sage/ui/connectionManager/ConnectionManager.py
+/usr/local/sage/ui/SAGESession.py
+
+%files devel  
+%defattr(-,root,root)
+/usr/local/sage/include/appInstance.h
+/usr/local/sage/include/appleMultiContext.h
+/usr/local/sage/include/audioConverter.h
+/usr/local/sage/include/audioFileReader.h
+/usr/local/sage/include/audioFileWriter.h
+/usr/local/sage/include/audioFormatManager.h
+/usr/local/sage/include/displayContext.h
+/usr/local/sage/include/displayInstance.h
+/usr/local/sage/include/envInterface.h
+/usr/local/sage/include/fsClient.h
+/usr/local/sage/include/fsCore.h
+/usr/local/sage/include/fsManager.h
+/usr/local/sage/include/fsServer.h
+/usr/local/sage/include/messageInterface.h
+/usr/local/sage/include/misc.h
+/usr/local/sage/include/overlayApp.h
+/usr/local/sage/include/overlayPointer.h
+/usr/local/sage/include/pixelDownloader.h
+/usr/local/sage/include/sageAppAudio.h
+/usr/local/sage/include/sageAudioBridge.h
+/usr/local/sage/include/sageAudioCircBuf.h
+/usr/local/sage/include/sageAudio.h
+/usr/local/sage/include/sageAudioManager.h
+/usr/local/sage/include/sageAudioModule.h
+/usr/local/sage/include/sageAudioReceiver.h
+/usr/local/sage/include/sageAudioSync.h
+/usr/local/sage/include/sageBase.h
+/usr/local/sage/include/sageBlock.h
+/usr/local/sage/include/sageBlockPartition.h
+/usr/local/sage/include/sageBlockPool.h
+/usr/local/sage/include/sageBlockQueue.h
+/usr/local/sage/include/sageBridge.h
+/usr/local/sage/include/sageBuf.h
+/usr/local/sage/include/sageConfig.h
+/usr/local/sage/include/sageDisplay.h
+/usr/local/sage/include/sageDisplayManager.h
+/usr/local/sage/include/sageDoubleBuf.h
+/usr/local/sage/include/sageDraw.h
+/usr/local/sage/include/sageDrawObject.h
+/usr/local/sage/include/sageEvent.h
+/usr/local/sage/include/sageFrame.h
+/usr/local/sage/include/sage.h
+/usr/local/sage/include/sagePixelType.h
+/usr/local/sage/include/sageReceiver.h
+/usr/local/sage/include/sageRect.h
+/usr/local/sage/include/sageSharedData.h
+/usr/local/sage/include/sageStreamer.h
+/usr/local/sage/include/sageSync.h
+/usr/local/sage/include/sageTcpModule.h
+/usr/local/sage/include/sageUdpModule.h
+/usr/local/sage/include/sageVersion.h
+/usr/local/sage/include/sageVirtualDesktop.h
+/usr/local/sage/include/sail.h
+/usr/local/sage/include/sdlSingleContext.h
+/usr/local/sage/include/streamInfo.h
+/usr/local/sage/include/streamProtocol.h
+/usr/local/sage/include/suil.h
+/usr/local/sage/include/tileConfig.h
+/usr/local/sage/include/wavConverter.h
Index: trunk/src/testing/etc/debian/debian.rules
===================================================================
--- trunk/src/testing/etc/debian/debian.rules	(revision 4)
+++ trunk/src/testing/etc/debian/debian.rules	(revision 4)
@@ -0,0 +1,92 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# This is the debhelper compatibility version to use.
+export DH_COMPAT=4
+
+
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+
+	touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp 
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE)
+	#docbook-to-man debian/sage-graphics.sgml > sage-graphics.1
+
+	touch $@
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+
+	# Add here commands to clean up after the build process.
+	-$(MAKE) clean
+
+	dh_clean 
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+
+	# Add here commands to install the package into debian/sage-graphics.
+	$(MAKE) install PREFIX=/usr/src/packages/BUILD/debian/sage-graphics install
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+#	dh_installdebconf
+	dh_installdocs
+	dh_installexamples
+	dh_installmenu
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_installinit
+	dh_installcron
+	dh_installman
+	dh_installinfo
+#	dh_undocumented
+	dh_installchangelogs
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_makeshlibs
+	dh_installdeb
+#	dh_perl
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
Index: trunk/src/testing/etc/debian/debian.control
===================================================================
--- trunk/src/testing/etc/debian/debian.control	(revision 4)
+++ trunk/src/testing/etc/debian/debian.control	(revision 4)
@@ -0,0 +1,11 @@
+Source: sage-graphics
+Section: graphics
+Priority: optional
+Maintainer: Luc Renambot <renambot@uic.edu>
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libsvga1, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+
+Package: sage-graphics
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: SAGE Scalable Adaptive Graphics Environment
+ SAGE is a graphics streaming architecture for supporting collaborative scientific visualization environments with potentially hundreds of megapixels of contiguous display resolution. In collaborative scientific visualization, it is crucial to share high-resolution imagery as well as high-definition video among groups of collaborators at local or remote sites. The network-centered architecture of SAGE allows collaborators to simultaneously run various applications (such as 3D rendering, remote desktop, video streams and 2D maps) on local or remote clusters, and share them by streaming the pixels of each application over ultra-high-speed networks to large tiled displays. SAGE streaming architecture is designed so that the output of arbitrary M by N pixel rendering cluster nodes can be streamed to X by Y pixel display screens, allowing user-definable layouts on the display. The dynamic pixel routing capability of SAGE lets users freely move and resize each application's imagery over tiled displays in run-time, tightly synchronizing the multiple visualization streams to form a single stream.  
Index: trunk/src/testing/etc/debian/sage-graphics_3.1-2.dsc
===================================================================
--- trunk/src/testing/etc/debian/sage-graphics_3.1-2.dsc	(revision 4)
+++ trunk/src/testing/etc/debian/sage-graphics_3.1-2.dsc	(revision 4)
@@ -0,0 +1,9 @@
+Format: 1.0
+Source: sage-graphics
+Version: 3.2-179
+Binary: sage-graphics
+Maintainer: Luc Renambot <renambot@uic.edu>
+Architecture: any
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libsvga1, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+Files: 
+ b1cdc9a97cfe3f15277dc5273764b172 80385138 sage-graphics_3.2.tar.gz
Index: trunk/src/testing/etc/debian/sage-graphics_3.2-179.dsc
===================================================================
--- trunk/src/testing/etc/debian/sage-graphics_3.2-179.dsc	(revision 4)
+++ trunk/src/testing/etc/debian/sage-graphics_3.2-179.dsc	(revision 4)
@@ -0,0 +1,9 @@
+Format: 1.0
+Source: sage-graphics
+Version: 3.2-179
+Binary: sage-graphics
+Maintainer: Luc Renambot <renambot@uic.edu>
+Architecture: any
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libsvga1, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+Files: 
+ b1cdc9a97cfe3f15277dc5273764b172 80385138 sage-graphics_3.2.tar.gz
Index: trunk/src/testing/etc/debian/debian.changelog
===================================================================
--- trunk/src/testing/etc/debian/debian.changelog	(revision 4)
+++ trunk/src/testing/etc/debian/debian.changelog	(revision 4)
@@ -0,0 +1,7 @@
+sage-graphics (3.2-179) stable; urgency=low
+
+  * Initial release.
+  * Added UI
+
+ -- Luc Renambot <renambot@uic.edu>  Tue, 05 Jan 2010 17:02:10 -0600
+
Index: trunk/src/testing/etc/ubuntu/debian.control
===================================================================
--- trunk/src/testing/etc/ubuntu/debian.control	(revision 4)
+++ trunk/src/testing/etc/ubuntu/debian.control	(revision 4)
@@ -0,0 +1,11 @@
+Source: sage-graphics
+Section: graphics
+Priority: optional
+Maintainer: Luc Renambot <renambot@uic.edu>
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+
+Package: sage-graphics
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: SAGE Scalable Adaptive Graphics Environment
+ SAGE is a graphics streaming architecture for supporting collaborative scientific visualization environments with potentially hundreds of megapixels of contiguous display resolution. In collaborative scientific visualization, it is crucial to share high-resolution imagery as well as high-definition video among groups of collaborators at local or remote sites. The network-centered architecture of SAGE allows collaborators to simultaneously run various applications (such as 3D rendering, remote desktop, video streams and 2D maps) on local or remote clusters, and share them by streaming the pixels of each application over ultra-high-speed networks to large tiled displays. SAGE streaming architecture is designed so that the output of arbitrary M by N pixel rendering cluster nodes can be streamed to X by Y pixel display screens, allowing user-definable layouts on the display. The dynamic pixel routing capability of SAGE lets users freely move and resize each application's imagery over tiled displays in run-time, tightly synchronizing the multiple visualization streams to form a single stream.  
Index: trunk/src/testing/etc/ubuntu/sage-graphics_3.1-2.dsc
===================================================================
--- trunk/src/testing/etc/ubuntu/sage-graphics_3.1-2.dsc	(revision 4)
+++ trunk/src/testing/etc/ubuntu/sage-graphics_3.1-2.dsc	(revision 4)
@@ -0,0 +1,9 @@
+Format: 1.0
+Source: sage-graphics
+Version: 3.2-179
+Binary: sage-graphics
+Maintainer: Luc Renambot <renambot@uic.edu>
+Architecture: any
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+Files: 
+ b1cdc9a97cfe3f15277dc5273764b172 80385138 sage-graphics_3.2.tar.gz
Index: trunk/src/testing/etc/ubuntu/sage-graphics_3.2-179.dsc
===================================================================
--- trunk/src/testing/etc/ubuntu/sage-graphics_3.2-179.dsc	(revision 4)
+++ trunk/src/testing/etc/ubuntu/sage-graphics_3.2-179.dsc	(revision 4)
@@ -0,0 +1,9 @@
+Format: 1.0
+Source: sage-graphics
+Version: 3.2-179
+Binary: sage-graphics
+Maintainer: Luc Renambot <renambot@uic.edu>
+Architecture: any
+Build-Depends: debhelper, libreadline5, libreadline5-dev, libglu1-mesa, libglu1-mesa-dev, libsdl1.2debian, libsdl-dev, libsdl-ttf2.0-0, libsdl-ttf2.0-dev, libxmu6, libxmu-dev, freeglut3, freeglut3-dev, libxi6, libxi-dev, libmagickwand1|libmagick10|libmagickcore2, libmagickwand1|libmagickwand2|libmagick10, libmagick9-dev|libmagickwand-dev, libjpeg62, libjpeg62-dev
+Files: 
+ b1cdc9a97cfe3f15277dc5273764b172 80385138 sage-graphics_3.2.tar.gz
Index: trunk/src/testing/etc/ubuntu/debian.changelog
===================================================================
--- trunk/src/testing/etc/ubuntu/debian.changelog	(revision 4)
+++ trunk/src/testing/etc/ubuntu/debian.changelog	(revision 4)
@@ -0,0 +1,7 @@
+sage-graphics (3.2-179) stable; urgency=low
+
+  * Initial release.
+  * Added UI
+
+ -- Luc Renambot <renambot@uic.edu>  Tue, 05 Jan 2010 17:02:10 -0600
+
Index: trunk/src/testing/etc/ubuntu/debian.rules
===================================================================
--- trunk/src/testing/etc/ubuntu/debian.rules	(revision 4)
+++ trunk/src/testing/etc/ubuntu/debian.rules	(revision 4)
@@ -0,0 +1,92 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# This is the debhelper compatibility version to use.
+export DH_COMPAT=4
+
+
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	# Add here commands to configure the package.
+
+	touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp 
+	dh_testdir
+
+	# Add here commands to compile the package.
+	$(MAKE)
+	#docbook-to-man debian/sage-graphics.sgml > sage-graphics.1
+
+	touch $@
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp configure-stamp
+
+	# Add here commands to clean up after the build process.
+	-$(MAKE) clean
+
+	dh_clean 
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k 
+	dh_installdirs
+
+	# Add here commands to install the package into debian/sage-graphics.
+	$(MAKE) install PREFIX=/usr/src/packages/BUILD/debian/sage-graphics install
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+#	dh_installdebconf
+	dh_installdocs
+	dh_installexamples
+	dh_installmenu
+#	dh_installlogrotate
+#	dh_installemacsen
+#	dh_installpam
+#	dh_installmime
+#	dh_installinit
+	dh_installcron
+	dh_installman
+	dh_installinfo
+#	dh_undocumented
+	dh_installchangelogs
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+#	dh_makeshlibs
+	dh_installdeb
+#	dh_perl
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
Index: trunk/src/testing/etc/sage.conf
===================================================================
--- trunk/src/testing/etc/sage.conf	(revision 4)
+++ trunk/src/testing/etc/sage.conf	(revision 4)
@@ -0,0 +1,1 @@
+/usr/local/sage/lib64
Index: trunk/src/testing/etc/sage.sh
===================================================================
--- trunk/src/testing/etc/sage.sh	(revision 4)
+++ trunk/src/testing/etc/sage.sh	(revision 4)
@@ -0,0 +1,6 @@
+
+# Add paths for the SAGE package
+
+export SAGE_DIRECTORY=/usr/local/sage
+export PATH="$PATH:$SAGE_DIRECTORY/bin"
+
Index: trunk/src/testing/etc/sage.csh
===================================================================
--- trunk/src/testing/etc/sage.csh	(revision 4)
+++ trunk/src/testing/etc/sage.csh	(revision 4)
@@ -0,0 +1,6 @@
+
+# Add paths for the SAGE package
+
+setenv SAGE_DIRECTORY /usr/local/sage
+setenv PATH ${PATH}:${SAGE_DIRECTORY}/bin
+
Index: trunk/src/testing/etc/README
===================================================================
--- trunk/src/testing/etc/README	(revision 4)
+++ trunk/src/testing/etc/README	(revision 4)
@@ -0,0 +1,24 @@
+To build the SAGE RPM:
+	rpmbuild -ba SPECS/sage.spec
+
+
+Directory /etc/profile.d:
+
+file sage.csh:
+	# Add paths for the SAGE package
+	setenv SAGE_DIRECTORY /usr/local/sage
+	setenv PATH ${PATH}:${SAGE_DIRECTORY}/bin
+
+file sage.sh:
+	# Add paths for the SAGE package
+	export SAGE_DIRECTORY=/usr/local/sage
+	export PATH="$PATH:$SAGE_DIRECTORY/bin"
+
+
+
+
+Directory /etc/ld.so.conf.d:
+
+file sage.conf:
+	/usr/local/sage/lib64
+
Index: trunk/src/testing/ui/setup.py
===================================================================
--- trunk/src/testing/ui/setup.py	(revision 4)
+++ trunk/src/testing/ui/setup.py	(revision 4)
@@ -0,0 +1,136 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+"""
+A distutils script to make a standalone .exe of superdoodle for
+Windows platforms.  You can get py2exe from
+http://py2exe.sourceforge.net/.  Use this command to build the .exe
+and collect the other needed files:
+
+    python setup.py py2exe
+
+A distutils script to make a standalone .app of superdoodle for
+Mac OS X.  You can get py2app from http://undefined.org/python/py2app.
+Use this command to build the .app and collect the other needed files:
+
+   python setup.py py2app
+"""
+
+
+####  this is used for building on Windows
+####  without this we'll get some ugly looking controls
+
+manifest = """
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
+manifestVersion="1.0">
+<assemblyIdentity
+    version="0.64.1.0"
+    processorArchitecture="x86"
+    name="Controls"
+    type="win32"
+/>
+<description>SAGE UI</description>
+<dependency>
+    <dependentAssembly>
+        <assemblyIdentity
+            type="win32"
+            name="Microsoft.Windows.Common-Controls"
+            version="6.0.0.0"
+            processorArchitecture="X86"
+            publicKeyToken="6595b64144ccf1df"
+            language="*"
+        />
+    </dependentAssembly>
+</dependency>
+</assembly>
+"""
+            
+#### end windows crap
+
+
+
+
+VERSION = "3.0"
+NAME = "sageui"
+DESCRIPTION = "SAGE UI v"+str(VERSION)
+
+from distutils.core import setup, Distribution
+import sys, glob
+
+
+#####    MAC   ######
+# RUN WITH: python setup.py py2app --site-packages
+#
+if sys.platform == 'darwin':
+    import py2app
+    opts = dict(argv_emulation=True, 
+                iconfile="images/sageUIIcon.icns",
+                dist_dir="sageui")
+    setup(app=['sageui.py'],
+	  name = NAME,
+	  options=dict(py2app=opts),
+          data_files = [(".", ["README","RECENT_CHANGES", "images", "prefs"]),
+			("images", glob.glob("images\\*.*")),
+                        ("prefs", glob.glob("prefs\\*.*"))],
+	  )
+	  
+
+#####   WINDOWS   ######
+# RUN WITH: python setup.py py2exe -b 1
+#
+
+elif sys.platform == 'win32':
+    import py2exe
+    opts = dict(dist_dir="sageui")
+    setup(windows=[{"script":"sageui.py"}],
+                    #"other_resources": [(24,1,manifest)]
+                   #}],
+	  name = NAME,
+	  version = str(VERSION),
+	  description = DESCRIPTION,
+	  options=dict(py2exe=opts),
+          data_files = [(".", ["README", "RECENT_CHANGES", "gdiplus.dll", "MSVCP90.dll", "msvcr90.dll"]),
+			("images", glob.glob("images\\*.*")),
+                        ("prefs", glob.glob("prefs\\*.*"))],
+	  )
+	  
+
+
+
Index: trunk/src/testing/ui/SAGEShape.py
===================================================================
--- trunk/src/testing/ui/SAGEShape.py	(revision 4)
+++ trunk/src/testing/ui/SAGEShape.py	(revision 4)
@@ -0,0 +1,1165 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#         Allan Spale
+#         Andrew Johnson
+#
+############################################################################
+
+
+
+import wx.lib.ogl as ogl
+from wx.lib.ogl._oglmisc import *     #needed for the MyShape class (MakeControlPoints)
+import wx
+from globals import *
+from Mywx import MyImage
+
+
+############################################################################
+#
+#  CLASS:       MyShape
+#
+#  DESCRIPTION: Extends the original ogl.Shape class so that the resizing
+#               control points behave as we want them. There are only 4 control
+#               points on the corners and they resize the shape while preserving
+#               the aspect ratio (optional). The control points have also been
+#               overridden to MyControlPoint.
+#
+#  DATE:        October 11, 2004
+#
+############################################################################
+
+class MyShape(ogl.Shape):
+    def __init__(self, canvas = None):
+      ogl.Shape.__init__(self, canvas)
+      self._shadowOffsetX = 6
+      self._shadowOffsetY = 6
+      self._shadowBrush = wx.Brush(shapeShadowColor)
+      self._timer = MouseCaptureTimer()
+      self._timer.SetCallback(self.ReleaseCapture)
+
+    
+    # Overriden method for creating the resizing points 
+    # (corner ones behave the same as the ones on the side)
+
+    def MakeControlPoints(self):
+        """Make a list of control points (draggable handles) appropriate to
+        the shape.
+        """
+
+        maxX, maxY = self.GetBoundingBoxMax()
+        minX, minY = self.GetBoundingBoxMin()
+
+        widthMin = minX - CONTROL_POINT_SIZE   #+ CONTROL_POINT_SIZE + 2
+        heightMin = minY - CONTROL_POINT_SIZE  #+ CONTROL_POINT_SIZE + 2
+
+        # Offsets from main object
+        top = -heightMin / 2.0
+        bottom = heightMin / 2.0 #+ (maxY - minY)
+        left = -widthMin / 2.0
+        right = widthMin / 2.0 #+ (maxX - minX)
+
+
+        # TOP LEFT
+        control = MyControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, top, CONTROL_POINT_DIAGONAL, "NW")
+        self._canvas.AddShape(control)
+        self._controlPoints.append(control)
+
+        # TOP RIGHT
+        control = MyControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, top, CONTROL_POINT_DIAGONAL, "NE")
+        self._canvas.AddShape(control)
+        self._controlPoints.append(control)
+
+        # BOTTOM RIGHT
+        control = MyControlPoint(self._canvas, self, CONTROL_POINT_SIZE, right, bottom, CONTROL_POINT_DIAGONAL, "SE")
+        self._canvas.AddShape(control)
+        self._controlPoints.append(control)
+
+        # BOTTOM LEFT
+        control = MyControlPoint(self._canvas, self, CONTROL_POINT_SIZE, left, bottom, CONTROL_POINT_DIAGONAL, "SW")
+        self._canvas.AddShape(control)
+        self._controlPoints.append(control)
+
+
+
+    ### RJ 2005-02-02
+    ### overridden to have the shapes resizable from corners only
+
+    def ResetControlPoints(self):
+        """Reset the positions of the control points (for instance when the
+        shape's shape has changed).
+        """
+        self.ResetMandatoryControlPoints()
+
+        if len(self._controlPoints) == 0:
+            return
+
+        maxX, maxY = self.GetBoundingBoxMax()
+        minX, minY = self.GetBoundingBoxMin()
+
+        widthMin = minX - CONTROL_POINT_SIZE  #+ CONTROL_POINT_SIZE + 2
+        heightMin = minY - CONTROL_POINT_SIZE  #+ CONTROL_POINT_SIZE + 2
+
+        # Offsets from main object
+        top = -heightMin / 2.0
+        bottom = heightMin / 2.0 #+ (maxY - minY)
+        left = -widthMin / 2.0
+        right = widthMin / 2.0 #+ (maxX - minX)
+
+
+        self._controlPoints[0]._xoffset = left
+        self._controlPoints[0]._yoffset = top
+
+        self._controlPoints[1]._xoffset = right
+        self._controlPoints[1]._yoffset = top
+
+        self._controlPoints[2]._xoffset = right
+        self._controlPoints[2]._yoffset = bottom
+
+        self._controlPoints[3]._xoffset = left
+        self._controlPoints[3]._yoffset = bottom
+        
+
+#----------------------------------------------------------------------
+
+
+    ### RJ 2005-02-07
+    ### overridden to have the shapes resizable from corners only
+    # Control points ('handles') redirect control to the actual shape, to
+    # make it easier to override sizing behaviour.
+
+    def OnSizingDragLeft(self, pt, draw, x, y, keys = 0, attachment = 0):
+        bound_x, bound_y = self.GetBoundingBoxMin()
+
+        dc = wx.ClientDC(self.GetCanvas())
+        self.GetCanvas().PrepareDC(dc)
+
+        dc.SetLogicalFunction(OGLRBLF)
+
+        dottedPen =  wx.Pen(wx.Colour(1, 0, 1), 2, wx.SOLID)
+        dc.SetPen(dottedPen)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+        # Don't maintain the same centre point
+        newX1 = min(pt._controlPointDragStartX, x)
+        newY1 = min(pt._controlPointDragStartY, y)
+        newX2 = max(pt._controlPointDragStartX, x)
+        newY2 = max(pt._controlPointDragStartY, y)
+
+        if self.GetMaintainAspectRatio():
+            newH = (newX2 - newX1) * (float(pt._controlPointDragStartHeight) / pt._controlPointDragStartWidth)
+            if self.GetY() > pt._controlPointDragStartY:
+                newY2 = newY1 + newH
+            else:
+                newY1 = newY2 - newH
+
+        newWidth = float(newX2 - newX1)
+        newHeight = float(newY2 - newY1)
+
+        pt._controlPointDragPosX = newX1 + newWidth / 2.0
+        pt._controlPointDragPosY = newY1 + newHeight / 2.0
+        if self.GetFixedWidth():
+            newWidth = bound_x
+
+        if self.GetFixedHeight():
+            newHeight = bound_y
+
+        pt._controlPointDragEndWidth = newWidth
+        pt._controlPointDragEndHeight = newHeight
+        self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
+
+
+#----------------------------------------------------------------------
+
+
+    ### RJ 2005-02-07
+    ### overridden to have the shapes resizable from corners only
+
+    def OnSizingBeginDragLeft(self, pt, x, y, keys = 0, attachment = 0):
+        self._canvas.CaptureMouse()
+        self._timer.Start(5000, True)   # automatically release the mouse after 5 secs
+        
+
+        dc = wx.ClientDC(self.GetCanvas())
+        self.GetCanvas().PrepareDC(dc)
+
+        dc.SetLogicalFunction(OGLRBLF)
+
+        bound_x, bound_y = self.GetBoundingBoxMin()
+        self.GetEventHandler().OnBeginSize(bound_x, bound_y)
+
+        # Choose the 'opposite corner' of the object as the stationary
+        # point in case this is non-centring resizing.
+        if pt.GetX() < self.GetX():
+            pt._controlPointDragStartX = self.GetX() + bound_x / 2.0
+        else:
+            pt._controlPointDragStartX = self.GetX() - bound_x / 2.0
+
+        if pt.GetY() < self.GetY():
+            pt._controlPointDragStartY = self.GetY() + bound_y / 2.0
+        else:
+            pt._controlPointDragStartY = self.GetY() - bound_y / 2.0
+
+        # We may require the old width and height
+        pt._controlPointDragStartWidth = bound_x
+        pt._controlPointDragStartHeight = bound_y
+
+        dottedPen = wx.Pen(wx.Colour(1, 0, 1), 2, wx.SOLID)
+        dc.SetPen(dottedPen)
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+
+        # Don't maintain the same centre point
+        newX1 = min(pt._controlPointDragStartX, x)
+        newY1 = min(pt._controlPointDragStartY, y)
+        newX2 = max(pt._controlPointDragStartX, x)
+        newY2 = max(pt._controlPointDragStartY, y)
+
+        if self.GetMaintainAspectRatio():
+            newH = (newX2 - newX1) * (float(pt._controlPointDragStartHeight) / pt._controlPointDragStartWidth)
+            if pt.GetY() > pt._controlPointDragStartY:
+                newY2 = newY1 + newH
+            else:
+                newY1 = newY2 - newH
+
+        newWidth = float(newX2 - newX1)
+        newHeight = float(newY2 - newY1)
+
+        pt._controlPointDragPosX = newX1 + newWidth / 2.0
+        pt._controlPointDragPosY = newY1 + newHeight / 2.0
+        if self.GetFixedWidth():
+            newWidth = bound_x
+
+        if self.GetFixedHeight():
+            newHeight = bound_y
+
+        pt._controlPointDragEndWidth = newWidth
+        pt._controlPointDragEndHeight = newHeight
+        self.GetEventHandler().OnDrawOutline(dc, pt._controlPointDragPosX, pt._controlPointDragPosY, newWidth, newHeight)
+
+
+#----------------------------------------------------------------------
+
+
+    ### RJ 2005-02-07
+    ### overridden to have the shapes resizable from corners only
+
+    def OnSizingEndDragLeft(self, pt, x, y, keys = 0, attachment = 0):
+        dc = wx.ClientDC(self.GetCanvas())
+        self.GetCanvas().PrepareDC(dc)
+
+        if self._canvas.HasCapture():
+            self._canvas.ReleaseMouse()
+        dc.SetLogicalFunction(wx.COPY)
+        self.Recompute()
+        self.ResetControlPoints()
+
+        self.Erase(dc)
+
+        self.SetSize(pt._controlPointDragEndWidth, pt._controlPointDragEndHeight)
+        self.Move(dc, pt._controlPointDragPosX, pt._controlPointDragPosY)
+
+        # Recursively redraw links if we have a composite
+        if len(self.GetChildren()):
+            self.DrawLinks(dc, -1, True)
+
+        width, height = self.GetBoundingBoxMax()
+        self.GetEventHandler().OnEndSize(width, height)
+
+        if not self._canvas.GetQuickEditMode() and pt._eraseObject:
+            self._canvas.Redraw(dc)
+        
+
+    def ReleaseCapture(self):
+        """ called with a timer to release the capture after a certain time """
+        if self._canvas.HasCapture():
+            self._canvas.ReleaseMouse()
+
+
+class MouseCaptureTimer(wx.Timer):
+    def SetCallback(self, cb):
+        self.callback = cb
+    def Notify(self):
+        self.callback()
+
+
+
+
+
+class MyControlPoint(ogl.ControlPoint):
+    def __init__(self, theCanvas, object, size, the_xoffset, the_yoffset, the_type, location):
+        ogl.ControlPoint.__init__(self, theCanvas, object, size, the_xoffset, the_yoffset, the_type)
+        self.location = location
+        self.SetPen(wx.TRANSPARENT_PEN)
+        self.SetBrush(wx.TRANSPARENT_BRUSH)
+
+
+# these are the buttons for maximizing, minimizing and closing shapes
+# they are not buttons per se but just images drawn on top of shapes
+# the clicks are handled manually (by comparing mouse coordinates) through
+# the OnLeftClick event handler for the shape
+class ShapeButton(MyImage):
+    def __init__(self, shape, handler, bitmap, x=0, y=0, rotate=False):
+        MyImage.__init__(self, bitmap, x,y, False, 20, 20)
+        self.shape = shape
+        self.handler = handler
+        self._visible = True
+        self.rotate = rotate
+
+        if rotate:
+            self.originalImage = self.image  # preserve the orientation of the original image
+            
+
+    def SetOrientation(self, degrees):
+        if degrees > 0:
+            timesToRotate = int(degrees/90)
+            self.image = self.originalImage
+            for i in range(timesToRotate):
+                self.image = self.image.Rotate90(False) 
+        else:
+            self.image = self.originalImage
+        self.bitmap = wx.BitmapFromImage(self.image)
+        
+        
+    def OnPaint(self, dc):
+        if self.GetVisible():
+            dc.DrawBitmap(self.bitmap, self.GetX(), self.GetY(), self.transparent)
+
+    def SetVisible(self, visible):
+        self._visible = visible
+
+    def GetVisible(self):
+        return self._visible
+
+    def Move(self, newX, newY):
+        self.SetX(newX)
+        self.SetY(newY)
+
+        # test if a click on the shape landed on this button (used instead of an event handler)
+    def HitTest(self, x, y):
+        btnWidth = self.bitmap.GetWidth()
+        btnHeight = self.bitmap.GetHeight()
+        
+        if ((x >= self.GetX()) and (x <= self.GetX()+btnWidth) and
+            (y >= self.GetY()) and (y <= self.GetY()+btnHeight)):
+            self.handler()  # call the correct handler because we hit the button
+            return True
+        else:
+            return False    # it was a miss
+    
+
+
+
+    
+############################################################################
+#
+#  CLASS:       MyRectangleShape
+#
+#  DESCRIPTION: Extends the original ogl.RectangleShape class. The original
+#               RectangleShape class extends ogl.Shape but we overrode ogl.Shape
+#               so we had to make MyRectangleShape extend MyShape. However, 
+#               since this is still a rectangle, we also have to extend from
+#               ogl.RectangleShape. The only method we override is the
+#               constructor since this is where we specify which Shape class
+#               are we based on. Hope this makes sense.
+#
+#  DATE:        October 12, 2004
+#
+############################################################################
+
+class MyRectangleShape(ogl.RectangleShape, MyShape):
+    
+    #overridden constructor so that it uses MyShape class and not ogl.Shape
+    def __init__(self, w, h, app, sageGate, canvas=None, title="untitled"):
+        MyShape.__init__(self, canvas)
+        self.app = app
+        self.initialWidth = w
+        self.initialHeight = h
+        self._width = w
+        self._height = h
+        self._cornerRadius = 0.0
+        self.SetDefaultRegionSize()
+        self.Z = 0
+        self.name = ""
+        self.title = title
+        self.borderColor = wx.Colour(255,255,255)
+        self.titleColor = wx.Colour(255,255,255)
+        self.sageGate = sageGate
+        self.displayCanvas = canvas
+        self.oldWidth = 0
+        self.oldHeight = 0
+        self.oldX = 0
+        self.oldY = 0
+        self.maximized = False
+        self.minimized = False
+        self.minimizedPosition = -1
+
+        self.oldLeft = 0
+        self.oldRight = 0
+        self.oldTop = 0
+        self.oldBottom = 0
+
+        # control buttons in the top right corner
+        self.buttons = []
+        self.buttonsVisible = True
+        self.buttons.append( ShapeButton(self, self.Close, "images/close_shape.gif", self._xpos, self._ypos))
+        self.buttons.append( ShapeButton(self, self.Maximize, "images/maximize_shape.gif", self._xpos, self._ypos))
+        self.buttons.append( ShapeButton(self, self.Rotate, "images/rotate_shape.gif", self._xpos, self._ypos, rotate=True))
+
+        self.SetOrientation(self.app.getOrientation())
+
+
+        # go through all the buttons and check if we clicked on any of the shape's buttons
+        # if we did, return True, otherwise False
+    def ButtonsClicked(self, x,y):
+        if self.buttons[0].GetVisible():  #if buttons are visible at all, check for clicks
+            for button in self.buttons:
+                if button.HitTest(x,y):  # HitTest will also call the right event handler if the button was indeed hit
+                    return True
+        return False
+    
+
+    def Close(self):
+        self.sageGate.shutdownApp(self.GetId())
+
+
+    def Rotate(self):
+        self.sageGate.rotateWindow(self.GetId(), 90)
+
+
+    def Maximize(self):
+        if not self.GetMaximized():
+            dispUIBounds = self.displayCanvas.GetUIDisplayBounds(self.app.getDisplayId())
+            width, height = self.GetBoundingBoxMin()
+
+            # old values are already preserved if the app was minimized
+            if not self.GetMinimized():  
+                self.PreserveOldParams()
+
+            # now set the new parameters (maximized)
+            # place the maximized shape in the center of the screen
+            self.SetX(round(dispUIBounds.left + dispUIBounds.getWidth() / 2))
+            self.SetY(round(dispUIBounds.top + dispUIBounds.getHeight() / 2))
+
+            # figure out by how much to multiply the size of the shape in order
+            # to fill the tiled display and not go over all while preserving the aspect ratio (if needed)
+            if self.displayCanvas.GetMaintainAspectRatio():
+                widthRatio = dispUIBounds.getWidth() / float(width)
+                heightRatio = dispUIBounds.getHeight() / float(height)
+                if widthRatio > heightRatio:
+                    maximizeRatio = heightRatio
+                else:
+                    maximizeRatio = widthRatio
+                self.SetSize( round(width*maximizeRatio), round(height*maximizeRatio))
+            else:  #do not maintain aspect ratio
+                self.SetSize( dispUIBounds.getWidth(), dispUIBounds.getHeight() )
+
+            self.SetMaximized(True)
+            
+        else:   #restore
+            #pull out the old parameters and resize/move the shape
+            self.RestoreOldParams()
+            self.SetMaximized(False)
+
+        self.SetMinimized(False) # an app can't be maximized and minimized at the same time
+        self.displayCanvas.FreeMinimizedPosition(self.minimizedPosition, self.app)
+        self.UpdateSAGEParams()
+
+        
+            
+    def Minimize(self):
+        if self.GetMinimized(): #restore
+            #pull out the old parameters and resize/move the shape
+            self.RestoreOldParams()
+            self.SetMinimized(False)
+            self.displayCanvas.FreeMinimizedPosition(self.minimizedPosition, self.app)
+        else:  #minimize
+            dispUIBounds = self.displayCanvas.GetUIDisplayBounds(self.app.getDisplayId())
+            minimizedWidth = dispUIBounds.getWidth()/10  #height of the minimized apps
+            
+            width, height = self.GetBoundingBoxMin()
+            self.SetMinimized(True)
+            if not self.GetMaximized():
+                self.PreserveOldParams()
+        
+            aspectRatio = float( height / float(width) )
+            newHeight = aspectRatio * minimizedWidth
+            self.SetSize( minimizedWidth, newHeight )
+            self.minimizedPosition = self.displayCanvas.GetNextMinimizedPosition(self.app)
+            self.SetX( dispUIBounds.left + minimizedWidth/2 + minimizedWidth*self.minimizedPosition)
+            self.SetY( dispUIBounds.bottom - newHeight/2 )
+
+        self.SetMaximized(False)  # an app can't be maximized and minimized at the same time
+        self.UpdateSAGEParams()
+
+                    
+    def HideButtons(self):
+        for button in self.buttons:
+            button.SetVisible(False)
+        self.buttonsVisible = False
+
+    def ShowButtons(self):
+        for button in self.buttons:
+            button.SetVisible(True)
+        self.buttonsVisible = True
+
+                        
+        # overridden so that we can display buttons on the shape (min, max, close...)
+    def OnDrawContents(self, dc):
+        self.SetFont(StandardFont())
+        btnWidth = self.buttons[0].GetWidth()
+        if btnWidth+20 < self.GetWidth():
+            self.ShowButtons()
+        else:
+            self.HideButtons()
+
+        # dont draw anything if buttons aren't visible (there's not enough space for them)
+        if not self.buttonsVisible:
+            return
+        
+        i = 0
+        for i in range(len(self.buttons)):
+            self.buttons[i].Move( self.GetRight() - btnWidth*(i+1)-1, self.GetTop()+1 )
+            self.buttons[i].OnPaint(dc)
+            i = i+1
+        ogl.Shape.OnDrawContents(self, dc)
+
+
+
+        # convert all the boundries and send a message to SAGE about the new size and/or position
+        # of the app
+    def UpdateSAGEParams(self):
+        left = self.displayCanvas.ToSAGECoordsX( self.GetLeft(), self.app.getDisplayId() )
+        right = self.displayCanvas.ToSAGECoordsX( self.GetRight(), self.app.getDisplayId() )
+        top = self.displayCanvas.ToSAGECoordsY( self.GetTop(), self.app.getDisplayId() )
+        bottom = self.displayCanvas.ToSAGECoordsY( self.GetBottom(), self.app.getDisplayId() )
+        self.sageGate.resizeWindow( self.GetId(), left, right, bottom, top )
+        
+
+#----------------------------------------------------------------------
+
+
+    # these methods have been overridden in order to make the center of the
+    # shape appear to be in the top left corner and not in the center
+    # NOTE!!!!
+    # if you are going to use these methods at the same time when you are changing
+    # the size of the shape, make sure you CHANGE THE SIZE OF THE SHAPE FIRST and
+    # then use these functions since they rely on the size
+    def GetMyX(self):
+        width, height = self.GetBoundingBoxMin()
+        return ogl.Shape.GetX(self) - width/2
+      
+    def GetMyY(self):
+        width, height = self.GetBoundingBoxMin()
+        return ogl.Shape.GetY(self) - height/2
+
+    def SetMyY(self, newY):
+        width, height = self.GetBoundingBoxMin()
+        self.SetY( newY + height/2 )
+
+    def SetMyX(self, newX):
+        width, height = self.GetBoundingBoxMin()
+        self.SetX( newX + width/2 )
+
+#----------------------------------------------------------------------
+
+
+    # for returning the boundries of the shape
+    def GetLeft(self):
+        return self.GetMyX()
+
+    def GetRight(self):
+        width, height = self.GetBoundingBoxMin()
+        return self.GetMyX() + width
+
+    def GetTop(self):
+        return self.GetMyY()
+
+    def GetBottom(self):
+        width, height = self.GetBoundingBoxMin()
+        return self.GetMyY() + height
+
+    def GetWidth(self):
+        return self.GetBoundingBoxMin()[0]
+
+    def GetHeight(self):
+        return self.GetBoundingBoxMin()[1]
+    
+
+    #----------------------------------------------------------------------
+
+
+    def SetOrientation(self, degrees):
+        for b in self.buttons:
+            if b.rotate: b.SetOrientation(degrees)
+    
+
+    #for maximizing/minimizing
+    def SetOldWidth(self, w):
+        self.oldWidth = w
+
+    def SetOldHeight(self, h):
+        self.oldHeight = h
+
+    def GetOldWidth(self):
+        return self.oldWidth
+
+    def GetOldHeight(self):
+        return self.oldHeight
+
+
+    def SetOldX(self, x):
+        self.oldX = x
+
+    def SetOldY(self, y):
+        self.oldY = y
+
+    def GetOldX(self):
+        return self.oldX
+
+    def GetOldY(self):
+        return self.oldY
+
+
+    def PreserveOldParams(self):
+        width, height = self.GetBoundingBoxMin()
+        self.SetOldX(self.GetLeft() + width/2)
+        self.SetOldY(self.GetTop() + height/2)
+        self.SetOldWidth(width)
+        self.SetOldHeight(height)
+
+    def RestoreOldParams(self):
+        self.SetSize(self.GetOldWidth(), self.GetOldHeight())
+        self.SetX(self.GetOldX())
+        self.SetY(self.GetOldY())
+
+
+    def GetMaximized(self):
+        return self.maximized
+
+    def SetMaximized(self, max):
+        self.maximized = max
+
+    def GetMinimized(self):
+        return self.minimized
+
+    def SetMinimized(self, min):
+        self.minimized = min
+      
+
+#----------------------------------------------------------------------
+
+    # z-ordering
+    def SetZ(self, newZ):
+        self.Z = newZ
+
+    def GetZ(self):
+        return self.Z
+
+
+    # sets the title of the app
+    def SetTitle(self, title):
+        self.title = title
+        self.ClearText()
+        self.AddText(self.name + " " + str(self.GetId()))
+        self.AddText(title)
+
+    def GetTitle(self):
+        return self.title
+    
+
+    # sets the name of the app 
+    def SetName(self, name):
+        self.name = name
+        #self.ClearText()
+        #self.AddText(name)
+
+    def GetName(self):
+        return self.name
+
+
+    # highlights the app when a mouse goes over the app instance button
+    def Highlight(self, doHightlight):
+        if doHightlight:
+            self.SetBrush(wx.Brush(shapeHighlightColor))#wx.MEDIUM_GREY_BRUSH)
+        else:
+            if not self.Selected():
+                self.SetBrush(wx.Brush(shapeColor))
+            else:
+                self.SetBrush(wx.Brush(shapeSelectedColor))#wx.GREY_BRUSH)
+        self.GetCanvas().Redraw()
+
+
+    # applies the new size and position to the shape (after screen resize)
+    def Recalculate(self, left, right, top, bottom):
+        self.SetSize( (right - left), (bottom - top) )
+        self.SetMyX(left)
+        self.SetMyY(top)
+
+        self.ResetControlPoints()
+
+    # changes the border of the shape if it's selected
+    def Select(self, doSelect, dc=None):
+        if doSelect:
+            self.SetTextColour(shapeSelectedTextColor)
+            self.SetPen(wx.Pen(shapeSelectedBorderColor, 2))#.SetWidth(2)
+            self.SetBrush( wx.Brush(shapeSelectedColor) ) #wx.GREY_BRUSH )
+        else:
+            self.SetTextColour(shapeTextColor)
+            self.SetPen(wx.Pen(shapeBorderColor,1))#wx.Colour(0,0,0), 1))#self.SetPen().SetWidth(1)
+            self.SetBrush( wx.Brush(shapeColor) ) #wx.GREY_BRUSH )
+        ogl.RectangleShape.Select(self, doSelect, dc)
+
+            
+#----------------------------------------------------------------------
+
+
+    ### this function figures out the right Z order of the windows and sends it to SAGE
+    def BringToFront(self):
+        if self.GetCanvas().GetTopShape() == self.GetId():
+            return  #the shape is already on top
+        
+        # now send a message to SAGE
+        self.sageGate.bringToFront(self.GetId())
+                
+
+#----------------------------------------------------------------------
+
+
+    # if we try to resize the shape beyond the edges of the display, this will
+    # size the shape down so that it fits inside the display
+    def SizeDown(self, pt):
+      
+        displayCanvas = self.GetCanvas()
+        myWidth, myHeight = self.GetBoundingBoxMin()  #get the size without the shadow
+        newWidth = myWidth
+        newHeight = myHeight
+        ratio = myWidth/myHeight  #remember the aspect ratio
+        minSize = 30    # the min size of the window on the screen
+
+            
+        # figure out if we resized the shape too much so that it's out of bounds
+        # of the tiled display
+        if self.GetBottom() > displayCanvas.GetBottom():
+            newHeight = displayCanvas.GetBottom() - self.GetTop()
+            newWidth = ratio * newHeight
+            if pt.location == "SE":
+                self.SetX(self.GetLeft() + newWidth/2)
+            else:
+                self.SetX(self.GetRight() - newWidth/2)
+            self.SetY(self.GetTop() + newHeight/2)
+            self.SetSize(newWidth, newHeight)
+        if self.GetTop() < displayCanvas.GetTop():
+            width, height = self.GetBoundingBoxMin()
+            newHeight = self.GetBottom() - displayCanvas.GetTop() 
+            newWidth = ratio * newHeight
+            if pt.location == "NE":
+                self.SetX(self.GetLeft() + newWidth/2)
+            else:
+                self.SetX(self.GetRight() - newWidth/2)
+            self.SetY(self.GetBottom() - newHeight/2)
+            self.SetSize(newWidth, newHeight)
+        if self.GetLeft() < displayCanvas.GetLeft():
+            width, height = self.GetBoundingBoxMin()
+            newWidth = self.GetRight() - displayCanvas.GetLeft()
+            newHeight = newWidth / ratio
+            self.SetX(self.GetRight() - newWidth/2)
+            if pt.location == "SW":
+                self.SetY(self.GetTop() + newHeight/2)
+            else:
+                self.SetY(self.GetBottom() - newHeight/2)
+            self.SetSize(newWidth, newHeight)
+        if self.GetRight() > displayCanvas.GetRight():
+            width, height = self.GetBoundingBoxMin()
+            newWidth = displayCanvas.GetRight() - self.GetLeft()
+            newHeight = newWidth / ratio
+            self.SetX(self.GetLeft() + newWidth/2)
+            if pt.location == "SE":
+                self.SetY(self.GetTop() + newHeight/2)
+            else:
+                self.SetY(self.GetBottom() - newHeight/2)
+            self.SetSize(newWidth, newHeight)
+
+
+        # dont allow the windows to be smaller than "minSize" pixels
+        if newWidth < minSize or newHeight < minSize:
+            widthRatio = minSize / newWidth
+            heightRatio = minSize / newHeight
+            if widthRatio > heightRatio:
+                resizeRatio = widthRatio
+            else:
+                resizeRatio = heightRatio
+            self.SetSize( round(newWidth * resizeRatio), round(newHeight * resizeRatio) )
+
+
+        # set the final size of the app window
+        #self.SetSize( int(newWidth), int(newHeight) )
+        self.SetX( round(self.GetX()) )
+        self.SetY( round(self.GetY()) )
+
+
+        # since we manually changed the parameters of the shape,
+        # we manually have to redraw the screen
+        self.ResetControlPoints() 
+        displayCanvas.Redraw()
+
+
+#----------------------------------------------------------------------
+
+
+    # if we tried to move the app window beyond the edges of the tiled display
+    # this would snap it to the edge
+
+    def SnapToEdges(self, oldx, oldy):
+        width, height = self.GetBoundingBoxMin()
+        displayCanvas = self.GetCanvas()
+        
+        # RJ
+        # october 15, 2004
+        # modified Gideon's code to "snap" windows to the edges if they go over
+	if self.GetTop() < displayCanvas.GetTop():
+            self.SetMyY(displayCanvas.GetTop())       
+            self.SetMyX(self.GetMyX())
+        if self.GetLeft() < displayCanvas.GetLeft():
+            self.SetMyX(displayCanvas.GetLeft())       
+            self.SetMyY(self.GetMyY())
+        if self.GetRight() > displayCanvas.GetRight():
+            self.SetMyX(displayCanvas.GetRight() - width)   
+            self.SetMyY(self.GetMyY())
+        if self.GetBottom() > displayCanvas.GetBottom():
+            self.SetMyY(displayCanvas.GetBottom() - height)        
+            self.SetMyX(self.GetMyX())
+
+
+        # redraw the screen
+        self.ResetControlPoints() 
+        displayCanvas.Redraw()
+      
+
+
+
+
+############################################################################
+#
+#  CLASS:       MyEvtHandler
+#
+#  DESCRIPTION: Extends the original ogl.ShapeEvtHandler class. 
+#               This is the main event handler for all the actions performed
+#               on the shapes themselves. It handles resizing, moving, click
+#               and double click. It also sends corresponding messages to SAGE
+#               about the actions performed.
+#
+#  DATE:        October 2004
+#
+############################################################################
+
+class MyEvtHandler(ogl.ShapeEvtHandler):
+
+    def __init__(self, log, statBarFrame, sageGate, displayCanvas):
+        ogl.ShapeEvtHandler.__init__(self)
+        self.log = log
+        self.statbarFrame = statBarFrame
+        self.sageGate = sageGate #we need access to the SAGE messenger
+        self.displayCanvas = displayCanvas
+        self.usersData = getUsersData()
+        
+#----------------------------------------------------------------------
+
+    def UpdateStatusBar(self, shape):
+        x, y = shape.GetX(), shape.GetY()
+        width, height = shape.GetBoundingBoxMax()
+        myID = shape.GetId() # always 0
+        #self.statbarFrame.SetStatusText("ID: %d Pos: (%d, %d)  Size: (%d, %d)" %
+        #                                (myID, x, y, width, height))
+
+        
+#----------------------------------------------------------------------
+
+    def OnLeftClick(self, x, y, keys=0, attachment=0):
+        shape = self.GetShape()
+        canvas = shape.GetCanvas()
+        dc = wx.ClientDC(canvas)
+        canvas.PrepareDC(dc)
+
+
+        # here we check if the user actually clicked on any of the shape buttons (min, max, close...)
+        # and if so, don't continue with this event handler
+        if shape.ButtonsClicked(x,y):
+            return
+                
+        # we clicked on the shape so bring it to front (above all other windows) and send a message to SAGE
+        shape.BringToFront()
+        
+        if shape.Selected():
+            return
+        else:
+            redraw = False
+            shapeList = canvas.GetDiagram().GetShapeList()
+            toUnselect = []
+
+            for s in shapeList:
+                if s.Selected():
+                    # If we unselect it now then some of the objects in
+                    # shapeList will become invalid (the control points are
+                    # shapes too!) and bad things will happen...
+                    toUnselect.append(s)
+
+            shape.Select(True, dc)
+
+            if toUnselect:
+                for s in toUnselect:
+                    s.Select(False, dc)
+                    #s.GetPen().SetWidth(1)
+                #canvas.Redraw(dc)
+
+        del dc
+                    
+        self.UpdateStatusBar(shape)
+
+        # bring up the performance data
+        canvas.GetParent().GetAppInfoPanel().GetInfoPanel().ShowData(shape.GetName(), shape.GetId())
+        
+        # since we manually changed the parameters of the shape,
+        # we manually have to redraw the screen
+        #canvas.Redraw(dc)#Refresh()
+        
+        
+        
+
+#----------------------------------------------------------------------
+
+    def OnEndDragLeft(self, x, y, keys=0, attachment=0):
+        shape = self.GetShape()
+
+        # test if the user dropped the application window onto another tab
+        # if so, just send a message to SAGE to stream that app to that new display
+        if shape.GetCanvas().GetParent().GetNotebook().DropTest(shape.GetId(), (x,y)):
+            if shape.GetCanvas().HasCapture():
+                shape.GetCanvas().ReleaseMouse()
+            return 
+
+        #if not shape.Selected():
+        self.OnLeftClick(x, y, keys, attachment)
+
+
+        oldx, oldy = shape.GetX(), shape.GetY()
+        ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment)
+
+
+        # check for move (note: NOT resize) out of bounds
+        # i.e. shape partially outside of "tiled" region
+        #shape.SnapToEdges(oldx, oldy)
+
+
+        # figure out the distance moved and send a message to SAGE
+        self.sageGate.moveWindow(shape.GetId(),
+                                 self.displayCanvas.ToSAGEDistX( oldx, shape.GetX(), shape.app.getDisplayId() ),
+                                 self.displayCanvas.ToSAGEDistY( oldy, shape.GetY(), shape.app.getDisplayId() ))
+
+        self.UpdateStatusBar(shape)
+        
+
+#----------------------------------------------------------------------
+
+
+    def OnSizingEndDragLeft(self, pt, x, y, keys, attch):
+      shape = self.GetShape()
+      
+      # call the overridden method for handling the sizing
+      shape.OnSizingEndDragLeft(pt, x, y, keys, attch)
+
+      # figure out if we resized the shape beyond the edge of our UI tiled display
+      # if so, resize it down to the maximum allowable size
+      #shape.SizeDown(pt)
+
+      # convert the new coords and send a message to SAGE
+      left = self.displayCanvas.ToSAGECoordsX( shape.GetLeft(), shape.app.getDisplayId() )
+      right = self.displayCanvas.ToSAGECoordsX( shape.GetRight(), shape.app.getDisplayId() )
+      top = self.displayCanvas.ToSAGECoordsY( shape.GetTop(), shape.app.getDisplayId() )
+      bottom = self.displayCanvas.ToSAGECoordsY( shape.GetBottom(), shape.app.getDisplayId() )
+      self.sageGate.resizeWindow( shape.GetId(), left, right, bottom, top )
+      
+      # if we were maximized and we tried to resize a shape, reset the maximized state
+      shape.SetMaximized(False)
+      self.UpdateStatusBar(shape)
+
+#----------------------------------------------------------------------
+
+    # (AKS 2005-01-28)
+    # Use this for displaying performance graphs
+    def OnRightClick(self, x, y, keys=0, attachment=0):
+        shape = self.GetShape()
+        menu = wx.Menu()
+    
+        machineMenu = wx.Menu()        
+        machines = self.usersData.GetMachinesStatus()
+        c = 30
+        for mId, m in machines.iteritems():
+            if m.IsAlive(): txt=m.GetName()+"  ( + )"
+            else: txt=m.GetName()+"  ( - )"
+            mi = machineMenu.Append(c, txt)
+            mi.SetHelp(mId)   #set the help to the machineId... we will use this later to get the right SAGEMachine
+            machineMenu.Bind(wx.EVT_MENU, self.OnStreamMenu, id=c)
+            c+=1
+            
+        menu.Append(1, "Edit Properties")        
+        menu.AppendMenu(3, "Stream To:", machineMenu)
+        menu.Bind(wx.EVT_MENU, self.OnContextMenu)
+        self.displayCanvas.PopupMenu(menu)
+        #self.rightClickFunctionCallback( shape.GetName(), shape.GetId() )
+
+
+    def OnStreamMenu(self, event):
+        mi = event.GetEventObject().FindItemById(event.GetId())
+        machine = self.usersData.GetMachine(mi.GetHelp())  # help string actually contains the machineId
+        self.sageGate.streamApp(self.GetShape().GetId(), machine.GetIP(), machine.GetPort())
+        
+
+    def OnContextMenu(self, event):
+        shape = self.GetShape()
+        eventId = event.GetId()
+        
+        if eventId == 1:  #this must be the "Edit Properties"
+            self._ShowPropertiesDialog(shape)
+        elif eventId >= 30 and eventId < 40:
+            mi = event.GetEventObject().FindItemById(event.GetId())
+            machine = self.usersData.GetMachine(mi.GetHelp())  # help string actually contains the machineId
+            self.sageGate.streamApp(self.GetShape().GetId(), machine.GetIP(), machine.GetPort())
+
+            
+    def _ShowPropertiesDialog(self, shape):
+        dlg = wx.Dialog(None, -1, "Edit Properties", style=wx.CLOSE_BOX | wx.RESIZE_BORDER)
+        okBtn = wx.Button(dlg, wx.ID_OK, "OK")
+        cancelBtn = wx.Button(dlg, wx.ID_CANCEL, "Cancel")
+        
+        line1 = "Enter a new title for "+str(shape.GetName()+" "+str(shape.GetId()))
+        text1 = wx.StaticText(dlg, -1, line1, style = wx.ALIGN_LEFT)
+        titleEntry = wx.TextCtrl(dlg, -1, shape.GetTitle())
+        titleColorBtn = wx.Button(dlg, -1, "Title Color")
+        self.titleColorText = wx.StaticText(dlg, -1, "unchanged", style = wx.ALIGN_CENTER)
+        titleColorBtn.Bind(wx.EVT_BUTTON, self._ChangeTitleColor) #(shape.titleColor, "title", titleColorText))
+        borderColorBtn = wx.Button(dlg, -1, "Border Color")
+        self.borderColorText = wx.StaticText(dlg, -1, "unchanged", style = wx.ALIGN_CENTER)
+        borderColorBtn.Bind(wx.EVT_BUTTON, self._ChangeBorderColor) #(shape.borderColor, "border", borderColorText))
+        self.sliderText = "Maximum frame rate: "
+        self.frameRateText = wx.StaticText(dlg, -1, self.sliderText + "UNCHANGED", style = wx.ALIGN_CENTER)
+        self.frameRateSlider = wx.Slider(dlg, -1, 0, 0, 60, style = wx.SL_LABELS | wx.SL_HORIZONTAL)
+        self.frameRateSlider.Bind(wx.EVT_SCROLL, self._ProcessSliderEvent)
+
+        hSizer1 = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer1.Add(titleColorBtn, 0, wx.ALIGN_LEFT | wx.LEFT,  border=0)
+        hSizer1.Add(self.titleColorText, 0, wx.ALIGN_LEFT | wx.LEFT, border=20)
+        hSizer2 = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer2.Add(borderColorBtn, 0, wx.ALIGN_LEFT | wx.LEFT, border=0)
+        hSizer2.Add(self.borderColorText, 0, wx.ALIGN_LEFT | wx.LEFT, border=10)
+        hSizer3 = wx.BoxSizer(wx.HORIZONTAL)
+        hSizer3.Add(cancelBtn, 0, wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border=10)
+        hSizer3.Add(okBtn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border=10)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.AddSpacer((20,20))
+        sizer.Add(text1, 0, wx.ALIGN_LEFT | wx.LEFT, border=15)
+        sizer.Add(titleEntry, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.EXPAND, border=15)
+        sizer.AddSpacer((20,20))
+        sizer.Add(hSizer1, 0, wx.ALIGN_LEFT | wx.LEFT, border=15)
+        sizer.AddSpacer((10,10))
+        sizer.Add(hSizer2, 0, wx.ALIGN_LEFT | wx.LEFT, border=15)
+        sizer.AddSpacer((25,25))
+        sizer.Add(self.frameRateText, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, border=15)
+        sizer.Add(self.frameRateSlider, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.EXPAND, border=15)
+        sizer.AddSpacer((30,30))
+        sizer.Add(hSizer3, 0, wx.ALIGN_CENTER, border=15)
+        sizer.AddSpacer((10,10))
+        
+
+        dlg.SetSizer(sizer)
+        dlg.Fit()
+        if dlg.ShowModal() == wx.ID_OK:
+            shape.SetTitle(titleEntry.GetValue())
+            retValTitleColor = (-1,-1,-1)
+            retValBorderColor = (-1,-1,-1)
+            if not self.titleColorText.GetLabel() == "unchanged":
+                retValTitleColor = (shape.titleColor.Red(),shape.titleColor.Green(),shape.titleColor.Blue())
+            if not self.borderColorText.GetLabel() == "unchanged":
+                retValBorderColor = (shape.borderColor.Red(),shape.borderColor.Green(),shape.borderColor.Blue())
+        
+            self.sageGate.changeAppProperties(shape.GetId(), shape.GetTitle(), retValTitleColor, retValBorderColor)
+
+            if not self.frameRateSlider.GetValue() == 0:
+                self.sageGate.changeAppFrameRate(shape.GetId(), self.frameRateSlider.GetValue())
+            self.displayCanvas.Redraw()
+
+        dlg.Destroy()
+        
+
+    def _ChangeTitleColor(self, event):
+        shape = self.GetShape()
+        newColor = ShowColorDialog(shape.titleColor)
+        if not newColor == (-1,-1,-1):
+            shape.titleColor = newColor
+            self.titleColorText.SetLabel( str(newColor) )
+
+        
+    def _ChangeBorderColor(self, event):
+        shape = self.GetShape()
+        newColor = ShowColorDialog(shape.borderColor)
+        if not newColor == (-1,-1,-1):
+            shape.borderColor = newColor
+            self.borderColorText.SetLabel( str(newColor) )
+
+    def _ProcessSliderEvent(self, event):
+        if self.frameRateSlider.GetValue() == 0:
+            self.frameRateText.SetLabel(self.sliderText + str("UNCHANGED"))
+        else:
+            if not self.frameRateText.GetLabel() == self.sliderText:
+                self.frameRateText.SetLabel(self.sliderText)
+
+        
+#----------------------------------------------------------------------
+
+
+    def OnMovePost(self, dc, x, y, oldX, oldY, display):
+        ogl.ShapeEvtHandler.OnMovePost(self, dc, x, y, oldX, oldY, display)
+        self.UpdateStatusBar(self.GetShape())
+        
+
+#----------------------------------------------------------------------
+
+   # (AKS 2005-01-28) Added so that GraphManager gets called when someone
+   # right clicks on the SAGE window
+    #def RegisterRightClickFunction( self, function ):
+    #    self.rightClickFunctionCallback = function
+
+
+
Index: trunk/src/testing/ui/fileViewer.py
===================================================================
--- trunk/src/testing/ui/fileViewer.py	(revision 4)
+++ trunk/src/testing/ui/fileViewer.py	(revision 4)
@@ -0,0 +1,1342 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import xmlrpclib, base64, sys, cStringIO, socket, pickle, copy, os.path, os
+from httplib import HTTPException
+import wx.lib.scrolledpanel
+from wx import ProgressDialog
+from globals import ConvertPath, Message, ChoiceDialog, appPanelColor, dialogColor
+import help  #my own
+import preferences as prefs  #my own
+from math import ceil
+from threading import *
+from misc.imsize import imagesize  # reads the image header and gets the size from it
+import wx.lib.throbber as throb
+import urllib
+
+XMLRPC_PORT = "8800"
+FILE_GRABBER_PORT = "8801"
+FILE_SERVER_BIN_PORT = 8802
+PREVIEW_SIZE = (150,150)
+DEFAULT_TIMEOUT = None  # no timeout because server side processing might take a while
+
+# used so that we don't create two connections to the same server... no reason
+# keyed by IP address of the server (host)
+fileServers = {}
+def GetFileServer(host, port):
+    global fileServers
+    if fileServers.has_key(host):
+        return fileServers[host]
+    else:
+        fs = FileServer(host, port)
+        fileServers[host] = fs
+        return fileServers[host]
+
+
+
+### stuff needed in order to customize the sending...
+class MyConnection:
+    def __init__(self, conn):
+        self.conn = conn
+
+        ### if data is bigger (>100KB), show the progress bar
+    def send(self, data):
+        dataLength = len(data)
+        if dataLength > 100000:
+            try:
+                dlg = wx.ProgressDialog("Uploading File", "Uploading... (0/%.2f)"%(dataLength/1048576),
+                                        style=wx.PD_SMOOTH | wx.PD_CAN_ABORT |
+                                        wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME | wx.PD_AUTO_HIDE)
+                chunkSize = 8192
+                for i in range (0, dataLength, chunkSize):  #send chunks of 8192 bytes
+                    self.conn.send(data[i:i+chunkSize])
+                    if not dlg.Update(ceil((float(i)/dataLength)*100), "Uploading... (%.2f/%.2f MB)"%
+                                      (float(i)/1048576, float(dataLength)/1048576)):
+                        self.conn.close()
+                        break
+                dlg.Destroy()
+            except socket.error:
+                dlg.Destroy()
+                Message("Error while uploading file. This is most likely a server-side error and it should be possible to continue.", "Upload Failed")
+        else:
+            self.conn.send(data)
+
+        ### overridden so that we can catch the exception when we press cancel during upload
+    def getreply(self):
+        ret = (None, None, None)
+        try:
+            ret = self.conn.getreply()
+        except HTTPException:
+            pass
+        return ret
+
+    
+    def __getattr__(self, key):
+        return getattr(self.conn, key)
+
+
+class MyTransport(xmlrpclib.Transport):
+    def make_connection(self, host):
+        conn = xmlrpclib.Transport.make_connection(self, host)
+        return MyConnection(conn)
+
+
+
+
+class FileServer:
+    
+    def __init__(self, host, port):
+        self.host = host  #where the FileLibrary is running
+        self.port = port
+        self.connected = False
+        self.Connect()
+
+
+        # try to connect to the server
+        # if we failed, set the flag
+        # if we succeed, get the path where the images are stored so that we can send it to the app
+    def Connect(self):
+        if self.connected: return True
+
+        print "\nConnecting to XMLRPC server at: http://"+str(self.host)+":"+self.port
+        socket.setdefaulttimeout(DEFAULT_TIMEOUT)
+        self.server = xmlrpclib.ServerProxy("http://"+str(self.host)+":"+self.port, transport=MyTransport())
+        #socket.setdefaulttimeout(3)
+        try:
+            self.connected = True
+            global FILE_GRABBER_PORT
+            FILE_GRABBER_PORT = self.server.TestConnection()[1]  #just see if the connection opened correctly
+        except:
+            print "Could not connect to the file server at: "+str(self.host)+":"+self.port
+            self.connected = False
+            return False
+        else:
+            print "Connected to the XMLRPC server at: http://"+str(self.host)+":"+self.port
+            return True
+
+
+    def IsConnected(self):
+        return self.Connect()
+
+
+        # uploads the file to the file library and returns information about the file
+    def UploadFile(self, fullPath):
+        try:
+            
+            # get the file info first
+            fileInfo = self.GetNewFileInfo(fullPath)
+            if not fileInfo: return False            # file type not supported
+            else: (fileType, appName, fullRemotePath, size, params, fileExists) = fileInfo
+
+            if fileExists:                           # if the file exists on the server, just show it (ie. dont send it)
+                return (fileType, appName, fullRemotePath, size, params, fileExists) #no need to upload
+            else:
+                if self.__SendFile(fullPath):    # did upload fail for some reason?
+                    return (fileType, appName, fullRemotePath, size, params, fileExists)
+                else:                           
+                    return False                     # upload failed so whatever you are doing after this (ShowFile maybe), don't do it
+
+        except socket.error: 
+            Message("Unable to upload file. There is no connection with the File Server.", "No connection")
+            return False
+        except xmlrpclib.ProtocolError:
+            return False
+    
+
+        # gets the information about the file and the supporting app from the file library
+    def GetNewFileInfo(self, fullPath):
+        #c = wx.BusyCursor()
+        (path, filename) = os.path.split(fullPath)
+        filename = "_".join(filename.split())
+
+        # check if the file type is supported
+        # if it is, it will get some data about the file (type, viewerApp ...)
+        fileSize = os.stat(fullPath).st_size  #get the size in bytes
+        fileInfo = self.server.GetFileInfo( filename, fileSize )
+        if not fileInfo:
+            #del c
+            extension = os.path.splitext(filename)[1].lower()
+            Message("File type <"+extension+"> not supported.", "Invalid File Type")
+            return False
+
+        (fileType, size, fullRemotePath, appName, params, fileExists) = fileInfo
+
+        # prepare for showing the file (filename, path, size if necessary...)
+        if fileType == "image":
+            try:
+                imsize = imagesize(fullPath)
+                size = (imsize[1], imsize[0])
+            except:
+                size = (-1,-1)
+        #del c
+        return (fileType, appName, fullRemotePath, size, params, fileExists)
+
+
+    def __SendFile(self, fullPath):
+        try:
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.connect((self.host, FILE_SERVER_BIN_PORT))
+
+            #convert to a filename with _ instead of empty spaces
+            convertedFilename = "_".join(os.path.basename(fullPath).split())
+            
+            # send the header first
+            fileSize = os.path.getsize(fullPath)
+            header = convertedFilename + " " + str(PREVIEW_SIZE[0]) + " " + str(PREVIEW_SIZE[1]) + \
+                     " " + str(fileSize) + "\n"
+            s.sendall(header)     
+
+            # show the progress dialog if file is bigger
+            doDlg = False
+            if fileSize > 100000:
+                dlg = wx.ProgressDialog("Uploading File", "Uploading... (0/%.2f)"%(fileSize/1048576),
+                                        style=wx.PD_SMOOTH | wx.PD_CAN_ABORT |
+                                        wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME | wx.PD_AUTO_HIDE)
+                doDlg = True
+                
+            # send the file data
+            f=open(fullPath, "rb")
+            t = 0
+            for line in f:
+                s.sendall(line)
+                t += len(line)
+
+                # update the dialog if needed
+                if doDlg and not dlg.Update(ceil((float(t)/fileSize)*100), "Uploading... (%.2f/%.2f MB)"%
+                                            (float(t)/1048576, float(fileSize)/1048576)):
+                    s.close()
+                    f.close()
+                    dlg.Destroy()
+                    return False
+
+            if doDlg:  dlg.Destroy()
+                
+            s.sendall("\n")  # because the other side is reading lines
+            f.close()
+            s.recv(1)
+        except:
+            print "Error sending file to File Server: ", sys.exc_info()[0], sys.exc_info()[1]
+            if doDlg:  dlg.Destroy()
+            Message("Could not upload file "+str(os.path.basename(fullPath)), "Error")
+            return False
+
+        return True
+                
+        #return self.server.UploadFile( convertedFilename, data, PREVIEW_SIZE )
+
+
+    
+### the base class for accepting the dropped files
+class FileDropTarget(wx.PyDropTarget):
+    def __init__(self, host=None, port=None):
+
+        # set up data objects  (Composite works correctly on Windows)
+        if "__WXMSW__" in wx.PlatformInfo:
+            self.do = wx.DataObjectComposite()
+            self.filedo = wx.FileDataObject()
+            self.textdo = wx.TextDataObject()
+            self.do.Add(self.textdo)
+            self.do.Add(self.filedo, True)
+        else:
+            self.do = wx.FileDataObject()
+        
+        wx.PyDropTarget.__init__(self, self.do)
+        
+        # delayed server object creation for the CanvasDropTarget
+        # when a file is dropped, we dont know which library to upload the file to so
+        # that's when we decide which library to connect to
+        if host!=None and port!=None:
+            self.serverObj = GetFileServer(host, port)
+            self.server = self.serverObj.server
+
+
+        # this must be called if you passed in None to the constructor
+    def SetLibrary(self, host, port):
+        self.serverObj = GetFileServer(host, port)
+        self.server = self.serverObj.server
+
+
+    def GetServer(self):
+        return self.server
+
+    
+    def OnData(self, x, y, d):
+        if not self.serverObj.IsConnected():
+            Message("Unable to upload/show file. There is no connection with the File Server.", "No connection")
+            return False
+        
+        self.GetData() #get the dropped data
+
+        if "__WXMSW__" in wx.PlatformInfo:
+            if self.textdo.GetTextLength() > 1:    # empty text has length = 1
+                droppedText = self.textdo.GetText()
+                self.textdo.SetText("")   #reset the text
+                return self.__DownloadURL(droppedText)
+            else:
+                files = self.filedo.GetFilenames()[0]  #extract the filenames from the dropped data
+                #files = unicode(files, "utf_8")
+                if os.path.isdir(files):
+                    Message("You cannot upload directories. Only individual files.", "Upload Failed")
+                    return False
+                else:
+                    return files
+        else:
+	    filenames = self.do.GetFilenames()
+	    if not filenames: return False
+	    files = filenames[0]  #extract the filenames from the dropped data
+	    if os.path.isdir(files):
+                Message("You cannot upload directories. Only individual files.", "Upload Failed")
+                return False
+            else:
+                return files
+
+            
+        # checks if the file the url is pointing to is valid,
+        # if so, it downloads it and returns the local path to it
+    def __DownloadURL(self, url):
+        if os.path.isfile(url):  # if it's a local file so just return it's path
+            return url
+        elif url.startswith("http://") or url.startswith("ftp://"):   #if it's a url
+            filename = os.path.basename(url)
+            if self.server.GetFileType(filename):   # is the file type even supported?
+                urllib.urlcleanup()  #cleanup the cache
+                urllib.urlretrieve(url, filename)
+                return os.path.abspath(filename)
+            else:                                # file type not supported
+                extension = os.path.splitext(filename)[1].lower()
+                Message("File type <"+extension+"> not supported.", "Invalid File Type")
+                return False
+        else:
+            return False
+
+
+
+class CanvasDropTarget(FileDropTarget):
+    def __init__(self, canvas):
+        self.canvas = canvas
+        self.sageGate = self.canvas.sageGate
+        self.sageHost = self.sageGate.sageHost  #for the filegrabber
+        self.lastX = 0
+        self.lastY = 0
+        
+        FileDropTarget.__init__(self) # dont provide library location right away since we will let the user choose that each time
+
+
+    def OnDrop(self, x, y):
+        self.lastX = self.canvas.ToSAGECoordsX(x, 0)
+        self.lastY = self.canvas.ToSAGECoordsY(y, 0)
+        return True
+
+
+    def OnData(self, x, y, d):   # just upload the file to the libary on the machine we are connected to
+        self.SetLibrary(self.sageHost, XMLRPC_PORT)  
+        filePath = FileDropTarget.OnData(self,x,y,d)
+        if filePath:
+            uploadResult = self.serverObj.UploadFile(filePath)
+        else: return False
+            
+        if uploadResult:  #if upload succeeded
+            (fileType, appName, fullRemotePath, size, params, fileExists) = uploadResult
+            self.ShowFile(fileType, appName, fullRemotePath, size, params, True)
+        return d
+
+
+            # run the show file in a thread
+    def ShowFile(self, fileType, fullPath, appName, params, size, doPrep=True):
+        t = Thread(target=self.DoShowFile, args=(fileType, fullPath, appName, params, size, doPrep))
+        t.start()
+
+
+    def DoShowFile(self, fileType, appName, fullRemotePath, size, params, doPrep=True):
+        # first, make sure that the file exists
+        if doPrep:
+            prepResult = self.server.PrepareFile(fullRemotePath, self.sageHost)
+            if not prepResult:
+                Message("Unable to show file because the transfer of file from the FileServer to the SAGE machine failed.", "Error")
+                return
+            else:
+                fullPath = prepResult #the path was returned by the FileGrabber
+            
+        totalDisplayWidth = self.canvas.tiledDisplayWidth
+        totalDisplayHeight = self.canvas.tiledDisplayHeight
+
+        if fileType == "image":
+            imageWidth = size[0]
+            imageHeight = size[1]
+            imageAspectRatio = float( imageWidth/imageHeight )
+
+            # figure out if the image is going to fit, if not, reposition and resize it as necessary
+            # first resize if necessary
+            widthRatio = float(totalDisplayWidth / float(imageWidth))
+            heightRatio = float(totalDisplayHeight / float(imageHeight))
+            if widthRatio < 1 or heightRatio < 1:
+                if widthRatio > heightRatio:   #we'll resize based on height
+                    resizeRatio = heightRatio
+                else:
+                    resizeRatio = widthRatio   #we'll resize based on width
+                imageWidth = int(imageWidth * resizeRatio)
+                imageHeight = int(imageHeight * resizeRatio)         
+
+            # now reposition
+            cornerX = self.lastX - int(imageWidth/2)
+            cornerY = self.lastY - int(imageHeight/2)
+
+            # is the image off the screen up or down?
+            if (totalDisplayHeight - cornerY) < imageHeight:
+                cornerY = int(totalDisplayHeight - imageHeight)
+            elif cornerY < 0:
+                cornerY = 0
+
+            # is the image off the screen left or right?
+            if (totalDisplayWidth - cornerX) < imageWidth:
+                cornerX = int(totalDisplayWidth - imageWidth)
+            elif cornerX < 0:
+                cornerX = 0
+            res = self.sageGate.executeApp(appName, pos=(cornerX, cornerY), size=(imageWidth,imageHeight), optionalArgs = fullRemotePath+" "+str(imageWidth)+" "+str(imageHeight)+" "+params)
+            
+        elif fileType == "video" or fileType == "pdf":
+            res = self.sageGate.executeApp(appName, pos=(self.lastX, self.lastY), optionalArgs=params+" "+fullRemotePath)
+            
+        else:  #for other types
+            res = self.sageGate.executeApp(appName, optionalArgs=fullRemotePath+" "+params)
+
+        if res == -1:
+            Message("Application not started. Either application failed, the application launcher is not running or the application  <<"+appName+">>  is not configured in application launcher.", "Application Launch Failed")
+        
+
+
+
+class LibraryDropTarget(FileDropTarget):
+    def __init__(self, parent, host, port=XMLRPC_PORT):
+        self.parent = parent
+        FileDropTarget.__init__(self, host, port)
+        
+        
+    def OnData(self, x, y, d):
+        filePath = FileDropTarget.OnData(self,x,y,d)
+        if not filePath: return
+        uploadResult = self.serverObj.UploadFile(filePath)
+        if uploadResult:  #if upload succeeded
+            (fileType, appName, fullRemotePath, size, params, fileExists) = uploadResult
+            if not fileExists:  #only add a file to the tree if the file doesnt exist yet
+                self.parent.OnNewFile(fullRemotePath, fileType)
+            else:
+                Message("File already exists in the file library.", "Duplicate Found")
+
+
+
+dirTextColor = wx.Colour(204, 153, 102)#250,50,50)
+
+class FileLibrary(wx.Frame):
+    def __init__(self, parent, parentPos):
+        self.canvas = parent 
+        self.sageGate = self.canvas.sageGate
+        self.sageHost = self.sageGate.sageHost  #for the filegrabber
+
+        res = LibraryChoiceDialog(parent).ShowDialog()
+        if not res:
+            return  #user pressed cancel when choosing the library
+        else:
+            (self.libName, self.libHost) = res
+
+        
+        self.dt = LibraryDropTarget(self, self.libHost, XMLRPC_PORT)
+        self.server = self.dt.GetServer()
+        self.serverObj = self.dt.serverObj
+
+        # we must be connected in order to see the library
+        if not self.serverObj.IsConnected():
+            Message("Unable to access file library. There is no connection with the File Server.", "No connection")
+        else:
+            x,y=parentPos
+            wx.Frame.__init__(self, parent, help.FILE_LIBRARY, "File Library - "+self.libName, pos=(x+200, y+200), size=(550,550))
+            self.previewSize = (150,150)
+            self.panel = wx.lib.scrolledpanel.ScrolledPanel(self, wx.ID_ANY)
+            self.__SetupLayout()
+            
+            # so that wherever we press F1 key it will bring up help for that window
+            # the help.ShowHelp function will check for the correct key press
+            self.Bind(wx.EVT_CHAR, help.ShowHelp)
+
+            # make the tree
+            self.tree = wx.TreeCtrl(self.panel, wx.ID_ANY, style=wx.TR_NO_LINES | wx.TR_SINGLE | wx.TR_HAS_BUTTONS)
+            self.tree.SetDropTarget(self.dt)
+            self.root = self.tree.AddRoot("Files")
+            self.imList = wx.ImageList(16,16)
+            self.tree.SetImageList(self.imList)  #image list must be created in order to have DnD capabiliy... weird
+            self.MakeTree()
+            self.tree.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick)
+            self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
+            self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnShowButton)
+            self.tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag)
+            self.tree.Bind(wx.EVT_TREE_END_DRAG, self.OnEndDrag)
+            self.tree.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
+            self.tree.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
+            self.tree.Bind(wx.EVT_MOTION, self.OnMouseMove)
+            self.currentItemId = None
+
+            # set the colors
+            self.tree.SetBackgroundColour(appPanelColor)
+            self.tree.SetForegroundColour(wx.WHITE)
+            self.panel.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
+            self.panel.SetBackgroundColour(dialogColor)
+            self.SetForegroundColour(wx.WHITE)
+
+            # add main things to the sizer
+            self.mainSizer.Add(self.tree, 1, wx.EXPAND)
+            self.mainSizer.Add(self.vertLine, 0, wx.EXPAND )
+            self.mainSizer.Add(self.vertSizer, 0, wx.EXPAND)
+
+            # attach the sizer to the panel
+            self.panel.SetSizer(self.mainSizer)
+            self.panel.SetAutoLayout(1)
+            self.panel.SetupScrolling()
+
+            wx.Frame.Show(self)
+
+
+    def __SetupLayout(self):        
+        self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.vertSizer = wx.BoxSizer(wx.VERTICAL)
+        self.horSizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        self.vertLine = wx.StaticLine(self.panel, style=wx.LI_VERTICAL)
+
+        self.showBtn = wx.Button(self.panel, wx.ID_ANY, "Show")
+        self.showBtn.Bind(wx.EVT_BUTTON, self.OnShowButton)
+        self.showBtn.Disable()
+        self.__SetupButton(self.showBtn)
+        
+        self.shareCheckBox = wx.CheckBox(self.panel, wx.ID_ANY, "Shareable app? (uses sageBridge)")
+        self.shareCheckBox.SetForegroundColour(wx.WHITE)
+        self.shareCheckBox.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
+        self.shareCheckBox.SetBackgroundColour(dialogColor)
+
+        self.dxtCheckBox = wx.CheckBox(self.panel, wx.ID_ANY, "Use DXT (faster, lower quality)")
+        self.dxtCheckBox.SetValue(True)
+        self.dxtCheckBox.SetForegroundColour(wx.WHITE)
+        self.dxtCheckBox.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
+        self.dxtCheckBox.SetBackgroundColour(dialogColor)
+
+        self.refreshBtn = wx.Button(self.panel, wx.ID_ANY, "Refresh")
+        self.refreshBtn.Bind(wx.EVT_BUTTON, self.RefreshTree)
+        self.__SetupButton(self.refreshBtn, smaller=True)
+                
+        self.browseBtn = wx.Button(self.panel, wx.ID_ANY, "Browse")
+        self.browseBtn.Bind(wx.EVT_BUTTON, self.BrowseFiles)
+        self.__SetupButton(self.browseBtn, smaller=True)
+        
+        self.helpBtn = wx.Button(self.panel, help.FILE_LIBRARY, "Help")
+        self.helpBtn.Bind(wx.EVT_BUTTON, help.ShowHelp)
+        self.__SetupButton(self.helpBtn, smaller=True)
+
+        self.searchField = wx.TextCtrl(self.panel, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
+        self.searchField.Bind(wx.EVT_TEXT_ENTER, self.OnSearch)
+        self.searchField.Bind(wx.EVT_TEXT, self.OnSearch)
+        tTip = wx.ToolTip("Search as you type...\npress ENTER to search again")
+        tTip.SetDelay(200)
+        self.searchMsg = wx.StaticText(self.panel, wx.ID_ANY, "", style=wx.ALIGN_CENTRE)
+        self.searchMsg.SetForegroundColour(wx.WHITE)
+        self.searchField.SetToolTip(tTip)
+        self.searchBtn = wx.Button(self.panel, wx.ID_ANY, "Find Next")
+        self.searchBtn.Bind(wx.EVT_BUTTON, self.OnSearch)
+        self.__SetupButton(self.searchBtn)
+        tTip = wx.ToolTip("Same as pressing ENTER in the search field")
+        tTip.SetDelay(200)
+        self.searchBtn.SetToolTip(tTip)
+                              
+        self.horSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5)
+        self.horSizer.Add(self.browseBtn, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10)
+        self.horSizer.Add(self.helpBtn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5)
+        
+        self.no_preview = wx.Image(ConvertPath("images/no_preview.png")).ConvertToBitmap()
+        self.retrieving_preview = wx.Image(ConvertPath("images/retrieving_preview.png")).ConvertToBitmap()
+        self.currentImage = wx.StaticBitmap(self.panel, wx.ID_ANY, self.no_preview, size=self.previewSize)
+
+        self.vertSizer.Add(self.horSizer, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP | wx.TOP | wx.EXPAND, border=10)
+        self.vertSizer.Add(wx.StaticLine(self.panel, style=wx.LI_HORIZONTAL), 0, wx.EXPAND | wx.ALIGN_TOP | wx.TOP, border=5)
+        self.vertSizer.AddSpacer((1,1),1)
+        self.vertSizer.Add(self.currentImage, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP, border=20)
+        self.vertSizer.Add(self.showBtn, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5)
+        self.vertSizer.Add(self.shareCheckBox, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5)
+        self.vertSizer.Add(self.dxtCheckBox, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=5)
+        self.vertSizer.AddSpacer((1,1),1)
+        self.vertSizer.Add(wx.StaticLine(self.panel, style=wx.LI_HORIZONTAL), 0, wx.EXPAND | wx.ALIGN_BOTTOM | wx.BOTTOM, border=10)
+        self.vertSizer.Add(self.searchField, 0, wx.ALIGN_BOTTOM | wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)
+        self.vertSizer.Add(self.searchMsg, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, border=5)
+        self.vertSizer.Add(self.searchBtn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.LEFT | wx.RIGHT | wx.TOP | wx.BOTTOM, border=10)
+
+        
+    def __SetupButton(self, btn, smaller=False):
+        if "__WXMAC__" not in wx.PlatformInfo:
+            if smaller:
+                sz = btn.GetSize()
+                btn.SetMaxSize((sz[0], sz[1]-5))
+            btn.SetBackgroundColour(wx.Colour(153, 255, 255))
+            btn.SetForegroundColour(wx.BLACK)
+        
+
+    def MakeTree(self):
+        self._alreadyFound = []  # a list of already found itemIds
+        self._searchString = ""  # a current search string
+        self.branches = {}   #treeItemIds keyed by file types
+        self.favoritesBranches = {}   #treeItemIds keyed by file types
+        
+        # get the newest list of files from the File Server 
+        try:
+            fileHash = self.server.GetFiles()
+        except socket.error:
+            Message("Unable to retrieve the file list. No connection with the File Server.", "No Connection")
+            return
+
+        # make the parents (main folders)
+        for fType, tpl in fileHash.iteritems():
+            tpl[2].sort(lambda x, y: cmp(x.lower(), y.lower()))
+            self.MakeBranch(fType, tpl[0])  #include the dir path
+            self.MakeNodes(self.branches[fType], tpl)
+
+        # make the favorites folder
+        self.MakeBranch("favorites", None)  #None dirPath (virtual directory)
+        for fType in self.branches.iterkeys():
+            if fType != "favorites":
+                self.MakeFavoritesBranch(fType)
+
+        self.LoadFavorites()
+
+        # bind events and finish the tree
+        self.tree.Expand(self.root)
+
+
+        ### recursively go through the data retrieved from server.GetFiles
+        ### and recreate the directory structure as a tree
+    def MakeNodes(self, parentId, tpl):
+        (dirPath, dirs, files, fileType) = tpl
+        sortedDirs = dirs.keys()
+        sortedDirs.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        
+        for dirName in sortedDirs:
+            dirTpl = dirs[dirName]
+            dirId = self.tree.AppendItem(parentId, dirName)
+            dirObj = Node(dirName, fileType, dirPath, False, False)
+            self.tree.SetItemTextColour(dirId, dirTextColor)
+            self.tree.SetPyData(dirId, dirObj)
+            self.MakeNodes(dirId, dirTpl)
+
+        files.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        for f in files:
+            fileObj = Node(f, fileType, dirPath, True, False)
+            fId = self.tree.AppendItem(parentId, f)
+            self.tree.SetPyData(fId, fileObj)
+
+
+        ### opens a file browser for your local machine so that you can add files to the library that way
+    def BrowseFiles(self, event=None):
+        dlg = wx.FileDialog(self, str("Add to the file library"), defaultDir=os.getcwd(), style=wx.OPEN | wx.FILE_MUST_EXIST)
+        if dlg.ShowModal() == wx.ID_OK:
+            uploadResult = self.serverObj.UploadFile(dlg.GetPath())  # do the checks, upload the file...
+            if uploadResult:  #if upload succeeded
+                (fileType, appName, fullRemotePath, size, params, fileExists) = uploadResult
+                if not fileExists:  #only add a file to the tree if the file doesnt exist yet
+                    self.OnNewFile(fullRemotePath, fileType)
+                else:
+                    Message("File already exists in the file library.", "Duplicate Found")
+        dlg.Destroy()
+
+
+        # called when a new file is dropped on the file library
+    def OnNewFile(self, fullRemotePath, fileType):
+        def AlreadyThere(filename, type):
+            (siblingId, cookie) = self.tree.GetFirstChild(self.branches[type])
+            while siblingId.IsOk():
+                if self.tree.GetPyData(siblingId).GetName() == filename:
+                    return True   # no need to add to favorites since it already exists in there
+                siblingId = self.tree.GetNextSibling(siblingId)
+            return False  #if we got here that means that there are no files with the same name already
+            
+
+        (path, filename) = os.path.split(fullRemotePath)
+        if AlreadyThere(filename, fileType): return   # check if the file already exists in the tree... if it does no need to update it
+        itemId = self.tree.AppendItem(self.branches[fileType], filename)
+        self.tree.SetPyData(itemId, Node(filename, fileType, path, True, False))
+      
+
+    def MakeBranch(self, fType, path):
+        if not self.branches.has_key(fType):
+            self.branches[fType] = self.tree.AppendItem(self.root, fType)
+            self.tree.SetItemTextColour(self.branches[fType], dirTextColor)
+            self.tree.SetPyData(self.branches[fType], Node("", fType, path, False, fType=="favorites", True))
+
+
+    def MakeFavoritesBranch(self, fType):
+        if not self.favoritesBranches.has_key(fType):
+            self.favoritesBranches[fType] = self.tree.AppendItem(self.branches["favorites"], fType)
+            self.tree.SetItemTextColour(self.favoritesBranches[fType], dirTextColor)
+            self.tree.SetPyData(self.favoritesBranches[fType], Node(fType, fType, "", False, True, True))
+
+
+    def RefreshTree(self, event=None):  #does not refresh favorites
+        self.tree.CollapseAndReset(self.root)
+        self.MakeTree()
+        self.currentImage.SetBitmap(self.no_preview)
+
+
+    def OnSearch(self, event):
+        self.searchMsg.SetLabel("")
+        if event.GetEventType() == wx.EVT_TEXT_ENTER.evtType[0] or event.GetEventType() == wx.EVT_BUTTON.evtType[0]:
+            selectedItemId = self.tree.GetSelection()
+            self._alreadyFound.append(selectedItemId)
+        elif event.GetEventType() == wx.EVT_TEXT.evtType[0]:
+            self._alreadyFound = []  #if the user changed the search string, restart the search
+
+        # start the search
+        resultItemId = self.SearchAndSelect(self.root, self.searchField.GetValue())
+        if resultItemId != None and resultItemId.IsOk():
+            self.tree.SelectItem(resultItemId, True)
+        else:
+            if resultItemId == None:
+                self.searchMsg.SetLabel("")  # display nothing for the empty string
+            else:
+                self.searchMsg.SetLabel("Nothing Found.")
+
+
+        # search through a tree recursively
+    def SearchAndSelect(self, root, searchString):
+        if len(searchString) == 0:
+            self._alreadyFound = []
+            return  #dont search for an empty string
+
+        (itemId, cookie) = self.tree.GetFirstChild( root )
+        while itemId.IsOk():
+            itemData = self.tree.GetPyData(itemId)
+            if itemData.GetType() == "favorites":  #skip the favorites
+                (itemId, cookie) = self.tree.GetNextChild( root, cookie )
+                continue
+            if searchString.lower() in itemData.GetName().lower():
+                if not itemId in self._alreadyFound:
+                    self._alreadyFound.append(itemId)
+                    return itemId 
+            if self.tree.ItemHasChildren( itemId ):
+                itemId = self.SearchAndSelect( itemId, searchString )
+                if itemId.IsOk():
+                    return itemId
+            (itemId, cookie) = self.tree.GetNextChild( root, cookie )
+
+        return itemId
+
+            
+    def OnBeginDrag(self, evt):
+        self.draggedItemId = evt.GetItem()
+        itemData = self.tree.GetPyData(self.draggedItemId)
+        if itemData != None and itemData.IsFile() and not itemData.IsFavorite():
+            evt.Allow()
+            
+
+    def OnEndDrag(self, evt):
+        onItemId = evt.GetItem() #, flags = self.tree.HitTest(evt.GetPoint())
+        if onItemId.IsOk():  #make sure that we dropped it on a legal spot
+            onItemData = self.tree.GetPyData(onItemId)
+            draggedItemData = self.tree.GetPyData(self.draggedItemId)
+            draggedFilename = draggedItemData.GetName()
+            draggedType = draggedItemData.GetType()
+
+            if onItemData == None:  # files can't be dropped on the root nor can we drag favorites
+                return
+
+            elif onItemData.IsFavorite():   # we dropped it in the "favorites" part
+                if prefs.favorite_files.AlreadyFavorite(draggedItemData): return # check if the file already exists in favs
+                favItemId = self.tree.AppendItem(self.favoritesBranches[draggedType], draggedFilename)
+                favItemData = copy.copy(draggedItemData)
+                favItemData.SetFavorite(True)  #we use the same data from the original file but mark it as a favorite
+                self.tree.SetPyData(favItemId, favItemData)
+                prefs.favorite_files.AddFavorite(favItemData)
+            
+            elif onItemData.GetType() == draggedType:  # dropped it in a non-favorites area
+                parentId = onItemId
+                newFullPath = os.path.join(onItemData.GetFullPath(), draggedFilename)
+                oldFullPath = draggedItemData.GetFullPath()
+                if onItemData.IsFile():  #if we dropped it on a file pretend it was the directory above
+                    parentId = self.tree.GetItemParent(onItemId)
+                    parentData = self.tree.GetPyData(parentId)
+                    newFullPath = os.path.join( parentData.GetFullPath(), draggedFilename)
+                if newFullPath == oldFullPath:  #if the file was dropped within the same dir, do nothing
+                    return
+                try:
+                    res = self.server.MoveFile(oldFullPath, newFullPath)
+                except socket.error:
+                    Message("Error moving file. No connection with the File Server.", "No Connection")
+                else:
+                    if res != True:
+                        Message("Error occured while moving the file. Does the file exist?", "Move Unsuccessful")
+                        self.RefreshTree()
+                    else: # move successful, rearrange the tree
+                        self.MoveNode(parentId, self.draggedItemId, newFullPath, draggedType)
+
+
+    def MoveNode(self, parentId, oldItemId, newFullPath, fileType):
+        self.tree.Delete(oldItemId)  #first delete the old node
+        (path, filename) = os.path.split(newFullPath)
+        itemId = self.tree.AppendItem(parentId, filename)
+        self.tree.SetPyData(itemId, Node(filename, fileType, path, True, False))
+
+
+    def LoadFavorites(self):  #must be done after the favorites branches have been built already
+        favoriteFilesData = prefs.favorite_files.GetFavorites()
+        if not favoriteFilesData: return
+
+        # insert the nodes into the tree
+        for type, items in favoriteFilesData.iteritems():
+            if self.favoritesBranches.has_key(type):
+                for itemData in items:
+                    itemId = self.tree.AppendItem(self.favoritesBranches[type], itemData.GetName())
+                    self.tree.SetPyData(itemId, itemData)
+
+
+    def OnMouseEnter(self, evt):
+        if evt.Dragging():
+            self.__DestroyPopup()
+            evt.Skip()
+
+
+    def OnMouseLeave(self, evt):
+        self.__DestroyPopup()
+
+
+    def __DestroyPopup(self):
+        if hasattr(self, "pd"): self.pd.Destroy(); del self.pd
+        self.currentItemId = None
+
+
+        # when we move a mouse over a file, display its metadata
+    def OnMouseMove(self, evt):
+        if evt.Dragging():
+            evt.Skip()
+        pt = evt.GetPosition()
+        itemId, flags = self.tree.HitTest(pt)
+        if not itemId.IsOk():
+            self.__DestroyPopup()
+            return
+        self.ShowMetadata(itemId)
+
+        # shows the metadata for a given itemId inside a popup
+    def ShowMetadata(self, itemId):
+        itemData = self.tree.GetPyData(itemId)
+        
+        if itemData == None:
+            self.__DestroyPopup()
+            return    #don't do anything if the user moved over the root
+
+        # get the metadata now if it's a file we are over
+        if itemData.IsFile():
+            if self.currentItemId == itemId:
+                return   #we already have a tooltip for this one
+            self.__DestroyPopup()
+            self.currentItemId = itemId
+            metadata = self.server.GetMetadata(itemData.GetFullPath())
+            if metadata:
+                md = itemData.GetName()+"\n"+metadata
+                self.pd = PopupDialog(self.tree)#popup.PopupControl(self.tree)#, metadata)
+                text = wx.StaticText(self.pd, wx.ID_ANY, md, pos=(2,2))# etadata.lstrip())
+                self.pd.SetContent(text)
+                self.pd.Display()
+            else:
+                self.__DestroyPopup()
+
+
+    def OnRightClick(self, evt):
+        pt = evt.GetPosition()
+        itemId, flags = self.tree.HitTest(pt)
+        itemData = self.tree.GetPyData(itemId)
+        self.tree.SelectItem(itemId)
+        
+        if itemData == None: 
+            return    #don't do anything if the user right-clicked on the root
+
+        # show the menu now
+        menu = wx.Menu()
+        if itemData.IsFile():                     # FILES
+            if itemData.IsFavorite():
+                delMenuItem = menu.Append(1, "Remove From Favorites")
+                menu.Bind(wx.EVT_MENU, self.OnRemoveFavoritesFile, delMenuItem)
+            else:
+                delMenuItem = menu.Append(1, "Delete File")
+                menu.Bind(wx.EVT_MENU, self.OnDeleteFile, delMenuItem)
+        elif not itemData.IsFile() and not itemData.IsFavorite():        # FOLDERS
+            newMenuItem = menu.Append(1, "New Folder")
+            menu.Bind(wx.EVT_MENU, self.OnNewFolder, newMenuItem)
+            if not itemData.IsBranch():           # you cant delete branches
+                delMenuItem = menu.Append(2, "Delete Folder")
+                menu.Bind(wx.EVT_MENU, self.OnDeleteFolder, delMenuItem)
+        
+        self.tree.PopupMenu(menu)
+
+
+    def OnNewFolder(self, evt):
+        newFolderName = wx.GetTextFromUser("New Folder Name: ", "New Folder")
+        newFolderName = "_".join(newFolderName.split())
+        if newFolderName == "":
+            return
+        itemId = self.tree.GetSelection()
+        itemData = self.tree.GetPyData(itemId)
+        itemType = itemData.GetType()
+        newFullPath = os.path.join( itemData.GetFullPath(), newFolderName)
+        try:
+            res = self.server.NewFolder(newFullPath)
+        except socket.error:
+            Message("Error creating the directory. No connection with the File Server.", "No Connection")
+        else:
+            if res != True:
+                Message("Error occured while creating the directory. Does the path leading to it still exist?", "Directory Creation Unsuccessful")
+                self.RefreshTree()
+            else: # make successful, rearrange the tree
+                self.MakeFolder(itemId, newFullPath, itemType)
+
+
+    def MakeFolder(self, parentId, newFullPath, fileType):
+        (path, name) = os.path.split(newFullPath)
+        itemId = self.tree.AppendItem(parentId, name)
+        self.tree.SetItemTextColour(itemId, dirTextColor)
+        self.tree.SetPyData(itemId, Node(name, fileType, path, False, False))
+        self.tree.SelectItem(itemId)
+        
+
+    def OnDeleteFolder(self, evt):
+        itemId = self.tree.GetSelection()
+        itemData = self.tree.GetPyData(itemId)
+        fullPath = itemData.GetFullPath()
+        if ChoiceDialog("This will delete the DIR and all the FILES in it permanently from the File Server which means that no " \
+                        "user will be able to access it/them anymore.\nAre you sure you want to continue?", \
+                        "Deletion Confirmation"):
+            try:
+                res = self.server.DeleteFolder(fullPath)
+            except socket.error:
+                Message("Error deleting the directory. No connection with the File Server.", "No Connection")
+            else:
+                if res != True:
+                    Message("Error occured while deleting the directory. Are the permissions correct?", "Directory Deletion Unsuccessful")
+                    self.RefreshTree()
+                else: # delete successful, rearrange the tree
+                    self.tree.Delete(itemId)
+
+
+    def OnDeleteFile(self, evt):
+        itemId = self.tree.GetSelection()
+        itemData = self.tree.GetPyData(itemId)
+        if itemData == None:
+            return  #the user clicked on one of the root folders which are not modifiable
+        if ChoiceDialog("This will delete the file permanently from the File Server which means that no " \
+                        "user will be able to access it anymore.\nAre you sure you want to continue?", \
+                        "Deletion Confirmation"):
+            try:
+                res = self.server.DeleteFile(itemData.GetFullPath())
+            except socket.error:
+                Message("Error deleting file. No connection with the File Server.", "No Connection")
+            else:
+                if res != True:
+                    Message("Error occured while deleting file. Does the file exist?", "Delete Unsuccessful")
+                    self.RefreshTree()
+                else:  # delete that node from the tree
+                    self.tree.Delete(itemId)
+                    self.currentImage.SetBitmap(self.no_preview)
+
+
+    def OnRemoveFavoritesFile(self, event):
+        itemId = self.tree.GetSelection()
+        prefs.favorite_files.RemoveFavorite(self.tree.GetPyData(itemId))  # you must do this before deleting the item
+        self.tree.Delete(itemId)
+        #self.SaveFavorites()
+
+
+
+    def OnShowButton(self, evt):
+        itemId = self.tree.GetSelection()
+        if not itemId.IsOk():
+            return
+        itemData = self.tree.GetPyData( itemId )
+  
+
+        # check if the user double clicked on a parent and not a leaf
+        # if so, expand/collapse the parent
+        if itemData == None or not itemData.IsFile():
+            if self.tree.IsExpanded(itemId):
+                self.tree.Collapse(itemId)
+            else:
+                self.tree.Expand(itemId)
+            return
+
+        # show the file (check if it exists first)
+        try:
+            c = wx.BusyCursor()
+            fileInfo = self.server.GetFileInfo(itemData.GetName(), 0, itemData.GetPath())
+            del c
+            if not fileInfo:   #file not supported
+                Message("File type <"+os.path.splitext(itemData.GetName())[1]+"> not supported.", "Invalid File Type")
+                return
+            (fileType, size, fullPath, appName, params, fileExists) = fileInfo
+            if not fileExists:  #file doesnt exist
+                Message("File <"+itemData.GetName()+"> does not seem to exist anymore.\nTry closing the library and opening it again in order to refresh the file list.", "Invalid Filename")
+                return
+            self.ShowFile(fileType, fullPath, appName, params, size)
+        except socket.error:
+            del c
+            Message("Unable to show file. There is no connection with the File Library.", "No connection")
+        
+
+    def OnSelChanged(self, evt):
+        class PreviewTimer(wx.Timer):
+            def __init__(self, action, itemId):
+                self.action = action
+                self.itemId = itemId
+                wx.Timer.__init__(self)
+            def Notify(self):
+                c = wx.BusyCursor()
+                try:
+                    self.action(self.itemId)
+                except socket.error, xmlrpclib.ProtocolError:
+                    pass   # no preview retrieved... oh well
+                del c
+
+        def GetPreview(itemId):
+            itemData = self.tree.GetPyData(itemId)
+            if itemData == None or not itemData.IsFile():
+                self.showBtn.Disable()
+                return  # do nothing if a leaf wasn't selected
+            self.showBtn.Enable()
+
+            # no preview if we didnt select an image
+            #if itemData.GetType() != "image":
+            #    self.currentImage.SetBitmap(self.no_preview)
+            #    return
+
+            # get the preview from the server (and get other info like the size of the image)
+            self.currentImage.SetBitmap(self.retrieving_preview)
+            try:
+                preview = self.server.GetPreview(itemData.GetFullPath(), self.previewSize)
+            except:
+                self.currentImage.SetBitmap(self.no_preview)
+                return
+            if not preview:  #preview retrieval failed for some reason
+                self.currentImage.SetBitmap(self.no_preview)
+            else:
+                (previewData, isBinary) = preview
+                if isBinary:
+                    stream=wx.InputStream(cStringIO.StringIO(base64.decodestring(previewData))) #make a stream out of the image
+                    im = wx.ImageFromStream(stream)
+                    im.Rescale(PREVIEW_SIZE[0], PREVIEW_SIZE[1])
+                else:
+                    im = wx.EmptyImage(PREVIEW_SIZE[0], PREVIEW_SIZE[1])
+                    im.SetData(base64.decodestring(previewData))
+
+                if im.Ok():
+                    self.currentImage.SetBitmap(im.ConvertToBitmap())
+                else:
+                    self.currentImage.SetBitmap(self.no_preview)
+                
+        # show the preview on a timer (done so that search-as-you-type is faster)
+        if hasattr(self, "_timer"):
+            if self._timer.IsRunning():
+                self._timer.Stop()
+        self._timer = PreviewTimer(GetPreview, evt.GetItem())
+        self._timer.Start(300, True)
+
+
+        # run the show file in a thread
+    def ShowFile(self, fileType, fullPath, appName, params, size):
+        t = Thread(target=self.DoShowFile, args=(fileType, fullPath, appName, params, size))
+        t.start()
+
+    
+    def DoShowFile(self, fileType, fullPath, appName, params, size):
+        prepResult = self.server.PrepareFile(fullPath, self.sageHost)
+        bridge = self.shareCheckBox.GetValue()
+
+        if self.dxtCheckBox.GetValue():
+            useDXT = ""
+        else:
+            useDXT = "-show_original"
+        
+        if not prepResult:
+            Message("Unable to show file because the transfer of file from the FileServer to the SAGE machine failed.", "Error")
+            return
+        else:
+            fullPath = prepResult #the path was returned by the FileGrabber
+
+        if fileType == "image":
+            totalDisplayWidth = self.canvas.tiledDisplayWidth
+            totalDisplayHeight = self.canvas.tiledDisplayHeight
+            imageWidth = size[0]
+            imageHeight = size[1]
+            imageAspectRatio = float( imageWidth/imageHeight )
+
+            # figure out if the image is going to fit, if not, reposition and resize it as necessary
+            # first resize if necessary
+            widthRatio = float(totalDisplayWidth / float(imageWidth))
+            heightRatio = float(totalDisplayHeight / float(imageHeight))
+            if widthRatio < 1 or heightRatio < 1:
+                if widthRatio > heightRatio:   #we'll resize based on height
+                    resizeRatio = heightRatio
+                else:
+                    resizeRatio = widthRatio   #we'll resize based on width
+                imageWidth = int(imageWidth * resizeRatio)
+                imageHeight = int(imageHeight * resizeRatio)         
+
+            # now reposition
+            cornerX = 0
+            cornerY = 0
+            
+            res = self.sageGate.executeApp(appName ,pos=(cornerX, cornerY), size=(imageWidth,imageHeight), optionalArgs = fullPath+" "+str(imageWidth)+" "+str(imageHeight)+" "+useDXT+" "+params, useBridge=bridge)
+        elif fileType == "video" or fileType=="pdf":
+            res = self.sageGate.executeApp(appName, optionalArgs=params+" "+fullPath, useBridge=bridge)
+        else:  #for other types
+            res = self.sageGate.executeApp(appName, optionalArgs=fullPath+" "+params, useBridge=bridge)
+
+        if res == -1:
+            Message("Application not started. Either application failed, the application launcher is not running or the application  <<"+appName+">>  is not configured in application launcher.", "Application Launch Failed")
+            
+
+
+### shows the dialog with a list of file libraries that you can
+### connect to. ShowDialog returns the selected library (Actually it's
+### IP address)
+class LibraryChoiceDialog(wx.Dialog):
+    def __init__(self, parent):
+        wx.Dialog.__init__(self, parent, wx.ID_ANY, "Choose File Library", style=wx.CAPTION | wx.CLOSE_BOX | wx.RESIZE_BORDER)
+        self.SetBackgroundColour(dialogColor)
+        self.SetForegroundColour(wx.WHITE)
+        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.horSizer1 = wx.BoxSizer(wx.HORIZONTAL)
+        self.SetMinSize((100, 200))
+        self.__MakeControls()
+        
+
+
+    def __MakeControls(self):
+        self.ID_ADD = 500
+        self.ID_DEL = 501
+        self.ID_UPLOAD = 502
+        self.ID_SHOW = 503
+        
+        self.libList = wx.ListBox(self, wx.ID_ANY, choices=prefs.fileLib.GetLibraryList(), style=wx.LB_SINGLE)
+        self.libList.SetStringSelection( prefs.fileLib.GetDefault()[0] )
+        self.libList.Bind(wx.EVT_LISTBOX_DCLICK, self.__OnDoubleClick)
+        #self.libList.SetTextColour(wx.WHITE)
+        #self.libList.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        #self.libList.SetBackgroundColour(appPanelColor)        
+        #self.libList.SetBackgroundColour(appPanelColor)
+        #self.libList.SetForegroundColour(wx.WHITE)
+        
+        addBtn = wx.Button(self, self.ID_ADD, "Add", size=(60,20))
+        smallFont = addBtn.GetFont()
+        smallFont.SetPointSize(smallFont.GetPointSize() - smallFont.GetPointSize()/5)
+        addBtn.SetFont(smallFont)
+        delBtn = wx.Button(self, self.ID_DEL, "Remove", size=(60,20))
+        delBtn.SetFont(smallFont)
+
+        self.horSizer1.Add(addBtn, 0, wx.ALIGN_CENTER | wx.RIGHT, border=10)
+        self.horSizer1.Add(delBtn, 0, wx.ALIGN_CENTER )
+        self.mainSizer.Add(self.libList, 1, wx.ALIGN_CENTER | wx.ALIGN_TOP | wx.ALL | wx.EXPAND, border=20)
+        self.mainSizer.Add(self.horSizer1, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=5)
+        self.mainSizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_CENTER | wx.ALL, border=15)
+        self.SetSizer(self.mainSizer)
+        self.Fit()
+
+        self.Bind(wx.EVT_BUTTON, self.__OnAdd, id=self.ID_ADD)
+        self.Bind(wx.EVT_BUTTON, self.__OnRemove, id=self.ID_DEL)
+        self.Bind(wx.EVT_BUTTON, self.__OnUpload, id=self.ID_UPLOAD)
+        self.Bind(wx.EVT_BUTTON, self.__OnShow, id=self.ID_SHOW)
+        
+
+    def ShowDialog(self):
+        res = self.ShowModal()
+        if res==wx.ID_OK or res==self.ID_UPLOAD:
+            libName = self.libList.GetStringSelection()
+            libHost = prefs.fileLib.GetLibraryIP( libName )
+            prefs.fileLib.SetDefault( libName, libHost )
+            self.Destroy()
+            return (libName, libHost)
+        else:
+            self.Destroy()
+            return False
+
+
+    def __OnDoubleClick(self, evt):
+        self.EndModal(self.ID_UPLOAD)
+
+
+    def __OnUpload(self, evt):
+        self.EndModal(self.ID_UPLOAD)
+
+
+    def __OnShow(self, evt):
+        self.EndModal(self.ID_SHOW)
+
+            
+    def __OnAdd(self, evt):
+        dlg = wx.Dialog(self, wx.ID_ANY, "Add New Library")
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        nameLabel = wx.StaticText(dlg, wx.ID_ANY, "Library name (label):")
+        nameField = wx.TextCtrl(dlg, wx.ID_ANY)
+        ipLabel = wx.StaticText(dlg, wx.ID_ANY, "Library IP address (or hostname):")
+        ipField = wx.TextCtrl(dlg, wx.ID_ANY)
+
+        sizer.Add(nameLabel, 0, wx.ALIGN_LEFT | wx.ALL, border = 10)
+        sizer.Add(nameField, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.EXPAND, border = 10)
+        sizer.Add(ipLabel, 0, wx.ALIGN_LEFT | wx.ALL, border = 10)
+        sizer.Add(ipField, 0, wx.ALIGN_LEFT | wx.LEFT | wx.BOTTOM | wx.RIGHT | wx.EXPAND, border = 10)
+        sizer.Add(dlg.CreateButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTER|wx.ALL, border=10)
+        dlg.SetSizer(sizer)
+        dlg.Fit()
+        if dlg.ShowModal() == wx.ID_OK:
+            prefs.fileLib.AddLibrary(ipField.GetValue(), nameField.GetValue())
+            self.libList.Set(prefs.fileLib.GetLibraryList())
+            self.libList.SetStringSelection(nameField.GetValue())
+            dlg.Destroy()
+        else:
+            dlg.Destroy()
+        
+
+    def __OnRemove(self, evt):
+        selection = self.libList.GetStringSelection()
+        if selection != "":
+            prefs.fileLib.RemoveLibrary(selection)
+            self.libList.Set(prefs.fileLib.GetLibraryList())
+        return
+
+
+
+class PopupDialog(wx.Dialog):
+    def __init__(self,parent,content = None):
+        wx.Dialog.__init__(self,parent,wx.ID_ANY,'', style = wx.NO_BORDER | wx.STAY_ON_TOP)
+
+        self.ctrl = parent
+        self.win = wx.Window(self,-1,pos = (0,0),style = wx.NO_BORDER)
+
+        if content:
+            self.SetContent(content)
+
+
+    def SetContent(self,content):
+        self.content = content
+        self.content.Reparent(self.win)
+        self.win.SetBackgroundColour(dialogColor)#102, 153, 153))#appPanelColor)
+        self.content.SetForegroundColour(wx.WHITE)
+        self.content.Show(True)
+        sz = self.content.GetSize()
+        self.win.SetClientSize((sz[0]+6, sz[1]+6))
+        self.SetSize(self.win.GetSize())
+        
+
+    def Display(self):
+        class InfoTimer(wx.Timer):
+            def __init__(self, action):
+                self.action = action
+                wx.Timer.__init__(self)
+            def Notify(self):
+                try:
+                    self.action()
+                except socket.error, xmlrpclib.ProtocolError:
+                    pass   # no info retrieved... oh well
+            
+        def __ActuallyShow():
+            pos = wx.GetMousePosition()
+            posX = pos[0]-(30+self.GetSize()[0])
+            posY = pos[1]
+            self.Move((posX, posY))
+            self.Show()
+        
+        # show the info on a timer 
+        if hasattr(self, "_timer"):
+            if self._timer.IsRunning():
+                self._timer.Stop()
+        self._timer = InfoTimer(__ActuallyShow)
+        self._timer.Start(500, True)
+
+    
+
+        
+    
+class Node:
+    def __init__(self, name, fileType, path, isFile, isFavorite, isBranch=False):
+        self.name = name
+        self.fileType = fileType
+        self.path = path
+        self.isFavorite = isFavorite
+        self.isFile = isFile
+        self.isBranch = isBranch
+    
+    def GetName(self):
+        return self.name
+
+    def GetPath(self):
+        return self.path
+
+    def GetFullPath(self):
+        return os.path.join(self.path, self.name)
+
+    def GetType(self):
+        return self.fileType
+
+    def IsFavorite(self):
+        return self.isFavorite
+
+    def SetFavorite(self, fav):
+        self.isFavorite = fav
+
+    def IsFile(self):
+        return self.isFile
+
+    def IsBranch(self):
+        return self.isBranch
+
+    def __eq__(self, other):
+        if hasattr(other, "GetName"):
+            if self.GetName() == other.GetName():
+                return True
+            else:
+                return False
+        return False
+    
+    def __ne__(self, other):
+        if hasattr(other, "GetName"):
+            if self.GetName() != other.GetName():
+                return True
+            else:
+                return False
+        return True
+    
+    
Index: trunk/src/testing/ui/Graph.py
===================================================================
--- trunk/src/testing/ui/Graph.py	(revision 4)
+++ trunk/src/testing/ui/Graph.py	(revision 4)
@@ -0,0 +1,1116 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Allan Spale
+#         Ratko Jagodic
+#
+############################################################################
+
+
+import wx
+import time
+import wx.lib.newevent
+import thread
+
+# (AKS 2005-04-14) Modified a single line of wx.lib.plot to remove
+# an obstructed call if the platform was Mac
+#import plot 
+from wx.lib import plot
+
+import string
+import random
+import sys
+import time
+import os
+from globals import *
+from Mywx import *
+
+# This creates a new Event class and a EVT binder function
+(UpdateDataEvent, EVT_UPDATE_GRAPH) = wx.lib.newevent.NewEvent()
+
+
+
+
+
+
+
+############################################################################
+
+# it gets the data from the SAGE messages (sageUIdataInfo).
+# this is the actual graph (lines and data)
+# 
+
+class PerformanceGraph:  
+    def __init__( self, appName, stDataTitle, iArraySize, iPerfUpdateInterval ):  
+
+        # CLASS CONSTANTS
+        # self.__fMin, self.__fMax, self.__fAvg, self.__fCurrent
+        self.I_MINIMUM = 0
+        self.I_MAXIMUM = 1
+        self.I_AVERAGE = 2
+        self.I_CURRENT = 3
+
+        # instance variables
+        self.__fAvg = 0.0
+        self.__fMax = 0.0
+        self.__fMin = 0.0
+        self.__fCurrent = 0.0
+        self.__iArraySize = iArraySize
+        self.__stDataTitle = stDataTitle
+        self.__stLabel = ""
+        self.__stAppName = appName
+
+        # (AKS 2005-05-03) Performance update interval
+        self.__iPerformanceUpdateInterval = iPerfUpdateInterval
+
+
+        # create panel
+        #self.__wxpGraphPanel = wx.Panel( self.__wxContainer, id=wx.ID_ANY,
+        #                                 pos=(-1,-1), size=(-1,-1) )
+
+        # setup data structure
+        self.__naData = [ [0]*2 for i in range(self.__iArraySize) ]
+
+
+        # (AKS 2004-10-26) Because data is in reverse order (most recent value
+        # is index 0), it is necessary to reverse the x values in the array
+        iTimeValue = -(self.__iArraySize-1) * self.__iPerformanceUpdateInterval
+        for index in range( 0, self.__iArraySize ):
+            # print self.__iArraySize - index - 1
+            #RJ self.__naData[ self.__iArraySize - index - 1, 0 ] = iTimeValue
+            self.__naData[ self.__iArraySize - index - 1][ 0 ] = iTimeValue
+            
+            iTimeValue = iTimeValue + self.__iPerformanceUpdateInterval
+            
+            #self.__naData[ index - self.__iArraySize, 0 ] = index
+
+
+        # create graph
+        self.__lines = plot.PolyLine(self.__naData, colour='red', width=3)
+
+        self.__graph = plot.PlotGraphics( [self.__lines],"", "Time (s)",
+                                            self.__stDataTitle)
+
+#------------------------------------------------------------------------------        
+    
+    def update( self, naNewData ):
+        # Because naData is sent as a reference, it is necessary to copy the
+        # data from naNewData to naData to preserve these references
+
+        # (AKS 2005-05-09)
+        self.__fCurrent = float( naNewData[ 0 ] )
+        
+        fSum = 0.0
+
+        # (AKS 2005-02-08) Max and min for a range
+        self.__fAvg = 0.0
+        self.__fMax = 0.0
+        self.__fMin = float( sys.maxint )
+      
+        for index in range( 0, self.__iArraySize ):
+            # (AKS 2005-05-09)
+            item = float( naNewData[ index ] )
+
+            #RJ self.__naData[ index, 1 ] = item
+            self.__naData[ index ][ 1 ] = item
+            fSum = fSum + item
+
+            # Set maximum value
+            if ( item > self.__fMax ):
+                self.__fMax = item
+
+            # Set minimum value
+            elif ( item < self.__fMin ):
+                self.__fMin = item
+
+        # Calculate average
+        #self.__fAvg = fSum / self.__iArraySize
+
+        # (AKS 2005-05-09)
+        self.__fAvg = float( fSum / self.__iArraySize )
+        
+
+        # (AKS 2005-03-08) Update graph
+        self.__lines = plot.PolyLine(self.__naData, colour='red', width=3)
+
+        self.__graph = plot.PlotGraphics( [self.__lines],"", "Time (s)",
+                                          self.__stDataTitle)
+      
+
+#------------------------------------------------------------------------------
+
+    def setGraphType( self, stType ):
+        if ( stType == 'frame rate' ):
+            self.__stLabel = " fps"
+        elif ( stType == 'bandwidth' ):
+            self.__stLabel = " Mbps"
+    
+#------------------------------------------------------------------------------        
+    
+    def getGraph( self ):
+        return self.__graph
+    
+#------------------------------------------------------------------------------
+
+    def getStatistics( self ):
+        return ( self.__fMin, self.__fMax, self.__fAvg, self.__fCurrent )
+
+#------------------------------------------------------------------------------
+
+    def getCurrentValue( self ):
+        return self.__fCurrent
+
+#------------------------------------------------------------------------------
+
+    def getPolyLine( self ):
+        return self.__lines
+
+
+
+
+
+
+
+
+   
+############################################################################
+
+# (AKS 2005-04-26) Acts like PerformanceGraph (used with SimpleGraph) but supports
+# multiple plots of the same metric (i.e. bandwidth, frame rate) although this is
+# more of a usage rule rather than a code-enforced rule.  This class will contain
+# an array of PerformanceGraph instances across applications.
+
+class MultiPerformanceGraph:
+    # NEED TO CHANGE listPerformanceGraphs to hashPerformanceGraphs to allow
+    # for easy addition and deletion as apps come and go.
+    def __init__( self, hashPerformanceGraphs, stDataTitle ):  
+
+        # CLASS CONSTANTS
+        # self.__fMin, self.__fMax, self.__fAvg, self.__fCurrent
+        self.I_MINIMUM = 0
+        self.I_MAXIMUM = 1
+        self.I_AVERAGE = 2
+        self.I_CURRENT = 3
+
+        # instance variables
+        self.__fAvg = 0.0
+        self.__fMax = 0.0
+        self.__fMin = 0.0
+        self.__fCurrent = 0.0
+        self.__stDataTitle = stDataTitle
+        self.__stLabel = ""
+
+        self.__listLines = []
+        self.__hashPerformanceGraphs = {}
+
+        for windowId in hashPerformanceGraphs:
+            graph = hashPerformanceGraphs[ windowId ]
+            self.__hashPerformanceGraphs[ windowId ] = graph
+            self.__listLines.append( graph.getPolyLine() )
+
+        # create graph
+        self.__graph = plot.PlotGraphics( self.__listLines, "", "Time (s)",
+                                            self.__stDataTitle)
+
+#------------------------------------------------------------------------------        
+    
+    def update( self ):
+        if ( len( self.__hashPerformanceGraphs ) > 0 ):
+            # Because naData is sent as a reference, it is necessary to copy the
+            # data from naNewData to naData to preserve these references
+
+            # Get current data
+            #print ">>> UPDATE WITH: ", naNewData
+            #print "new data size = ", len( naNewData )
+            #print "plottable data size = ", self.__naData.shape
+            self.__fCurrent = naNewData[ 0 ]
+
+            fSum = 0.0
+
+            # (AKS 2005-02-08) Max and min for a range
+            self.__fAvg = 0.0
+            self.__fMax = 0.0
+            self.__fMin = float( sys.maxint )
+
+            for graph in self.__hashPerformanceGraphs.values():
+                fMin, fMax, fAvg, fCurrent = graph.getStatistics()
+                
+                #print index
+                fSum = fSum + fCurrent
+
+                # Set maximum value
+                if ( fMax > self.__fMax ):
+                    self.__fMax = fMax
+
+                    # Set minimum value
+                elif ( fMin < self.__fMin ):
+                    self.__fMin = fMin
+                    
+            # end loop
+
+
+            # Calculate average
+            self.__fAvg = fSum / self.__iArraySize
+
+
+            # (AKS 2005-03-08) Update graph
+            del self.__lines[ 0:len( self.__lines ) ]
+        
+            for windowId in self.__hashPerformanceGraphs:
+                graph = self.__hashPerformanceGraphs[ windowId ]
+                self.__listLines.append( graph.getPolyLine() )
+
+                self.__graph = plot.PlotGraphics( self.__listLines,"", "Time",
+                                                  self.__stDataTitle)
+        # end
+
+        else:
+            self.__fAvg = 0.0
+            self.__fMax = 0.0
+            self.__fMin = 0.0
+            self.__fCurrent = 0.0
+
+        # end if
+
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-04-29) Need this function because apps come and go.
+    def addPerformanceGraph( self, windowId, pgGraph ):
+        self.__hashPerformanceGraphs[ windowId ] = pgGraph
+
+#------------------------------------------------------------------------------
+
+    def removePerformanceGraph( self, windowId ):
+        del self.__hashPerformanceGraphs[ windowId ]
+
+#------------------------------------------------------------------------------
+
+    def setGraphType( self, stType ):
+        if ( stType == 'frame rate' ):
+            self.__stLabel = " fps"
+        elif ( stType == 'bandwidth' ):
+            self.__stLabel = " Mbps"
+    
+#------------------------------------------------------------------------------        
+    
+    def getGraph( self ):
+        return self.__graph
+    
+#------------------------------------------------------------------------------
+
+    def getStatistics( self ):
+        return ( self.__fCurrent, self.__fMin, self.__fMax, self.__fAvg )
+
+#------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+############################################################################
+
+# the main panel that shows the totals for an application for all the
+# different metrics.
+# one of these exists for every application
+
+class SparklineGraphs( wx.Panel ):
+    def __init__( self, wxfParentFrame, list_pgGraph, list_stWindowTitle,
+                  list_stGraphTitle, list_stYAxisTitle, stSingleWindowTitle, id, frame=None ):
+
+        ### Setup element sizes
+        btnSize = ( 89, 24 )
+
+        ### initial spacing and positioning constants
+        xOrigin = 5
+        yOrigin = 5
+        titleY = yOrigin
+        titleX = xOrigin
+        titleHeight = 25
+        renderX = xOrigin
+        renderY = titleY + titleHeight
+        renderHeight = 40 - titleHeight
+        btnX = xOrigin
+        btnY = renderY + renderHeight
+        btnHeight = btnSize[1]
+        btnWidth = btnSize[0]
+        labelXOffset = 15         #from the end of the buttons (or app label) to the right
+        labelX = btnX + btnWidth + labelXOffset
+        labelY = 0 #yOrigin
+        labelWidth = 60
+        labelHeight = titleHeight
+        perfLabelX = labelX
+        numArea1X = btnX + btnWidth
+        numArea1Y = btnY
+        numAreaWidth = 4*labelWidth + labelXOffset + 10 #numArea1X + 4*labelWidth
+        numAreaHeight = 2*btnHeight
+        numArea2X = numArea1X
+        numArea2Y = numArea1Y + numAreaHeight + renderHeight
+
+        # panel size
+        width = numArea1X + numAreaWidth + xOrigin #415
+        height = numArea2Y + numAreaHeight
+        self._buffer = wx.EmptyBitmap(width, height)  # for double buffering
+
+        self.frame = frame
+        wx.Panel.__init__(self, wxfParentFrame, wx.ID_ANY, (3,3), (width,height))
+        self.Bind(wx.EVT_CLOSE, self.shutdown)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.SetBackgroundColour(appPanelColor)
+        # since SetBackgroundColour doesnt work always, manually draw the background
+        #self.background = MyImage( "images/app_info_background.png", 0,0, False, width, height)
+        
+        # Font setup
+        dc = wx.ClientDC(self)   # this makes font the same size on all platforms
+        ppp = 72.0 / dc.GetPPI().height
+        del dc
+        self.boldFont = BoldFont()
+        self.normalFont = StandardFont()
+
+        # Order of items in the list must adhere to the following constants
+        # INTERNAL CLASS CONSTANTS
+        self.I_RENDER_BW = 0
+        self.I_RENDER_FPS = 1
+        self.I_RENDER_NODES = 2
+        self.I_RENDER_STREAMS = 3        
+        self.I_DISPLAY_BW = 4
+        self.I_DISPLAY_FPS = 5
+        self.I_DISPLAY_NODES = 6
+        self.I_DISPLAY_STREAMS = 7        
+        
+        # Initialize instance variables
+        self.__windowId = id   # (AKS 2005-03-10) Added for shutdown callback
+        self.__list_stGraphTitle = list_stGraphTitle
+        self.__list_stWindowTitle = list_stWindowTitle
+
+        # FIX: delete the metrics we are not using this time... just use the bw and fps for rendering and display
+        self.__list_pgGraph = list_pgGraph
+        #self.__
+
+        self.__list_stYAxisTitle = list_stYAxisTitle
+        self.__stAppName = stSingleWindowTitle
+
+        ### Header Row
+        self.__colLabels = []
+        self.__colLabels.append((self.__stAppName + " " + str(self.__windowId), xOrigin, 0, btnWidth, titleHeight))
+        self.__colLabels.append(("Current", labelX, labelY, labelWidth, labelHeight))
+        labelX = labelX + labelWidth
+        self.__colLabels.append(("Min", labelX, labelY, labelWidth, labelHeight))
+        labelX = labelX + labelWidth
+        self.__colLabels.append(("Ave", labelX, labelY, labelWidth, labelHeight))
+        labelX = labelX + labelWidth
+        self.__colLabels.append(("Max", labelX, labelY, labelWidth, labelHeight))
+        
+        ### backgrounds for the two areas with the actual numbers
+        self.__numAreaBg = []
+        self.__numAreaBg.append(MyImage( "images/stats_green.jpg",
+                                         numArea1X, numArea1Y, False,
+                                         numAreaWidth, numAreaHeight))
+        self.__numAreaBg.append(MyImage( "images/stats_green.jpg",
+                                         numArea2X, numArea2Y, False,
+                                         numAreaWidth, numAreaHeight))
+        
+
+        self.__divLabels = []
+        self.__divLabels.append(("RENDER", renderX+185, renderY-2, btnWidth, renderHeight))
+        self.__divLabels.append(("DISPLAY", renderX+185, btnY + btnHeight*2-2, btnWidth, renderHeight))
+        
+        # graphs and performance data
+        self.__graphButtons = {}  #stores the graph buttons keyed by data type
+        self.__hash_sgSimpleGraph = {}
+        self.__perfNumLabels = {}  # stores the top-left corners of the first label and the size of each label
+
+        # buttons for showing the graphs for each metric
+        #self.__btnList = {0:"BW", 1:"FPS", 2:"Nodes", 3:"Streams", 4:"BW", 5:"FPS", 6:"Nodes", 7:"Streams"} 
+        self.__btnList = {0:"BW", 1:"FPS", 4:"BW", 5:"FPS"} 
+        
+
+        # load the buttons and create the labels that will hold all the performance data
+        for row in [0,1,4,5]: #range( 0, len( self.__btnList ) ):
+            # Space between each row
+            if row == 4:
+                btnY = btnY + renderHeight
+            if row == 0:
+                pass  #we already set the first one
+            else:
+                btnY = btnY + btnHeight
+
+            btnId =  row ##wx.ID_ANY  ## RJ 05-08-2005 - id by row
+            btn = PerfToggleButton(self, btnId,
+                                     self.__createGraph,
+                                     self.removeGraph,
+                                     "images/stats_"+self.__btnList[btnId]+"_up.jpg",
+                                     "images/stats_"+self.__btnList[btnId]+"_down.jpg",
+                                     "images/stats_"+self.__btnList[btnId]+"_over.jpg",
+                                     ( btnX, btnY ), btnSize) 
+            self.__graphButtons[btnId] = btn
+            
+            self.__perfNumLabels[row] = (perfLabelX, btnY, labelWidth, btnHeight)
+        # end of loop
+
+        self.__redraw()
+
+
+    def Redraw(self):
+        self.__redraw()
+
+#------------------------------------------------------------------------------
+                
+    def registerShutdownCallback( self, function ):
+        self.__shutdownCallback = function        
+        
+#------------------------------------------------------------------------------    
+
+    def shutdown( self, evt=None ):
+        self.__shutdownCallback( self.__windowId )
+
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-03-17)  This function will be called if the user closed a "higher-
+    # level" window that sends a "close event" down the window hierarchy.  In this
+    # case, the higher-level window will be able to track what IDs to remove from
+    # its data structures and will not need to receive any "callback" function
+    # to indicate this information.
+
+    def manualShutdown( self ):
+        # shutdown all the associated SingleGraphs
+        for iKey in self.__hash_sgSimpleGraph:
+            self.__hash_sgSimpleGraph[ iKey ].manualShutdown()
+        
+        # (AKS 2005-03-17) Clear all keys after graphs are shutdown
+        self.__hash_sgSimpleGraph.clear()
+        self.Destroy()       # destroy panel
+
+
+#------------------------------------------------------------------------------
+
+    def getGraphList( self ):
+        return self.__list_pgGraph
+
+#------------------------------------------------------------------------------
+
+    def removeGraph( self, iGraphID ):
+        self.__hash_sgSimpleGraph[ iGraphID ].manualShutdown()
+        del self.__hash_sgSimpleGraph[ iGraphID ]
+        
+        # Untoggle button
+        self.__graphButtons[ iGraphID ].SetValue( False )
+
+#------------------------------------------------------------------------------
+
+    # Call in case no function was registered
+    def __ignoreFunction( self ):
+        pass
+
+#------------------------------------------------------------------------------                
+
+    def OnPaint(self, event):
+	# for some reason double buffered panel doesnt show up right on macs so just 
+	# do the normal drawing... single buffering
+	if "__WXMAC__" in wx.PlatformInfo:
+	    dc = wx.PaintDC(self)
+	    self.__redraw(dc=dc)
+	else:
+	    dc = wx.BufferedPaintDC(self, self._buffer)
+	
+
+    def __redraw( self, evt=None, dc=None ):
+        if not self.IsShown():  #only redraw the panel if it's shown
+            return
+	if "__WXMAC__" in wx.PlatformInfo:
+	    if dc == None: dc = wx.ClientDC(self)
+	else:
+	    dc = wx.BufferedDC(wx.ClientDC(self), self._buffer)
+	dc.SetBackground( wx.Brush(self.GetBackgroundColour()))
+        dc.SetTextForeground(wx.WHITE)
+	dc.Clear()
+
+        # draw the column labels
+        dc.SetFont(self.normalFont)
+        i = 0
+        for col in self.__colLabels:
+            if i==0:
+                dc.SetFont(self.boldFont)
+                dc.DrawLabel(col[0], wx.Rect(col[1], col[2], col[3], col[4]), wx.ALIGN_TOP | wx.ALIGN_LEFT)
+                dc.SetFont(self.normalFont)
+            else: dc.DrawLabel(col[0], wx.Rect(col[1], col[2], col[3], col[4]), wx.ALIGN_TOP | wx.ALIGN_RIGHT)
+            i=1
+
+        # draw the "render" and "display" labels
+        dc.SetTextForeground(wx.Colour(102, 204, 153))
+        for div in self.__divLabels:
+            dc.DrawLabel(div[0], wx.Rect(div[1], div[2], div[3], div[4]), wx.ALIGN_LEFT)
+        dc.SetTextForeground(wx.WHITE)
+                        
+        # draw the number area backgrounds
+        for im in self.__numAreaBg:
+            dc.DrawBitmap( im.GetBitmap(), im.GetX(), im.GetY(), im.IsTransparent())
+
+        # update the SparklineGraph panel
+        for iIndex in [0,1,4,5]: #range( 0, 4): #len( self.__list_pgGraph ) ):
+	    pgGraph = self.__list_pgGraph[ iIndex ]
+            (x,y, w,h) = self.__perfNumLabels[iIndex]  # get the location and size of the first label in each row
+
+            # Get statistics               
+            tupleStats = pgGraph.getStatistics()
+
+            # draw the labels for each metric
+            for index in (pgGraph.I_CURRENT, pgGraph.I_MINIMUM, pgGraph.I_AVERAGE, pgGraph.I_MAXIMUM):
+                if (iIndex == self.I_RENDER_BW) or (iIndex == self.I_RENDER_FPS) or (iIndex == self.I_DISPLAY_BW) or (iIndex == self.I_DISPLAY_FPS):
+                    stFormatString = "%5.1f" % tupleStats[ index ]
+                else:
+                    stFormatString = "%5d" % tupleStats[ index ]
+                dc.DrawLabel(stFormatString, wx.Rect(x,y,w,h), wx.ALIGN_CENTRE | wx.ALIGN_RIGHT)
+                x+=w  # move the next label to the right by the width of the label
+
+	# redraw the buttons on mac
+        if "__WXMAC__" in wx.PlatformInfo:
+            del dc
+            for btn in self.__graphButtons.itervalues():
+                btn.OnPaint()
+        
+        # now update all the SingleGraphs
+        for k, singleGraph in self.__hash_sgSimpleGraph.iteritems():
+            singleGraph.Redraw()
+                
+
+
+
+    ### RJ 05-08-2005 - this function replaces the 8 below
+    def __OnToggleButton(self, event):
+        button = event.GetEventObject()
+        if button.GetValue():   #RJ 05-08-2005
+            self.__createGraph( button.GetId() )
+        else:
+            self.removeGraph( button.GetId() )
+
+
+        
+#------------------------------------------------------------------------------
+
+        
+    def __createGraph( self, iGraphCode ):
+        stRevisedWindowTitle = self.__stAppName + ": " + self.__list_stWindowTitle[ iGraphCode ]
+
+        #if self.frame = None
+        self.__hash_sgSimpleGraph[ iGraphCode ] = SingleGraph(
+            self.frame, self.__list_pgGraph[ iGraphCode ], stRevisedWindowTitle,
+            self.__list_stGraphTitle[ iGraphCode ],
+            self.__list_stYAxisTitle[ iGraphCode ], iGraphCode )
+
+        # registered call
+        #print "........creating graph and registering shutdown callback for graph #", iGraphCode
+        self.__hash_sgSimpleGraph[ iGraphCode ].registerShutdownCallback( self.removeGraph )
+            
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-05-03) Send a list of PerformanceGraphs related to a single app.
+    # Then add each PerformanceGraph to the appropriate MultiPerformanceGraph
+    # (one MultiPerformanceGraph for each performance metric).
+    # CAUTION: Ordering of performance metrics is assumed to be identical
+    # to the related graphs in listPerformanceGraphs
+
+    def addAppPerformanceGraphList( self, windowId, listPerformanceGraphs,
+                                    iPerformanceMetricCount ):
+
+        # CAUTION: Only works for MultiPerformanceGraph instances
+        for iIndex in range( 0, iPerformanceMetricCount ):
+            self.__list_pgGraph[ iIndex ].addPerformanceGraph(
+                windowId, listPerformanceGraphs[ index ] )
+                
+        # end loop        
+
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-05-03) Remove a PerformanceGraph with the given windowId from each
+    # MultiPerformanceGraph.
+    # CAUTION: Ordering of performance metrics is assumed to be identical
+    # to the related graphs in listPerformanceGraphs
+
+    def reomveAppPerformanceGraphList( self, windowId, iPerformanceMetricCount ):
+        print "Removing from totals sparkline APP ID #", windowId
+
+        for iIndex in range( 0, iPerformanceMetricCount ):
+            self.__list_pgGraph[ iIndex ].removePerformanceGraph( windowId )
+
+        # end loop
+
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-05-04) ONLY CALL WHEN USING MultiPerformanceGraphs in this class
+    # so that totals can be calculated.
+
+    def updateMultiPerformanceGraphs( self, iPerformanceMetricCount ):
+        print "Updating totals sparkline..."        
+        for iIndex in range( 0, iPerformanceMetricCount ):
+            self.__list_pgGraph[ iIndex ].update()
+        
+
+
+
+
+
+
+############################################################################
+# it displays only one metric as a graph in a frame
+# it runs in a separate thread spawned by the SparklineGraph
+
+class SingleGraph( wx.Frame ):
+    def __init__( self, wxfParentFrame, pgGraph, stWindowTitle, stGraphTitle, stYAxisTitle, iGraphCode ):
+
+        # Font setup
+        self.normalFont = StandardFont()#wx.Font( 11, wx.DEFAULT, wx.NORMAL, wx.NORMAL )
+
+        # Initialize instance variables
+        self.__stGraphTitle = stGraphTitle
+        self.__stWindowTitle = stWindowTitle
+        self.__pgGraph = pgGraph
+        self.__stYAxisTitle = stYAxisTitle
+        self.__iGraphCode = iGraphCode
+
+        # (AKS 2005-05-05) Pause playback flag
+        self.__bPausePlayback = False
+
+        # Setup window                
+        wx.Frame.__init__(self, wxfParentFrame, wx.ID_ANY, stWindowTitle, wx.DefaultPosition, size=( 400, 300 ))
+        wx.EVT_CLOSE(self, self.shutdown)
+        
+        self.CenterOnParent()
+
+        # (AKS 2005-04-26) Use status bar instead
+        self.CreateStatusBar()
+
+        # (AKS 2005-05-05) Create menu bar to pause
+        self.SetMenuBar( self.CreateMenu() )
+
+        # Setup graph
+        self.__wxpcPlotCanvas = plot.PlotCanvas( self )#, wx.ID_ANY, pos=( 0, 0 ), size=( 400,300 ) )
+	self.__wxpcPlotCanvas.SetSize((400,300))
+        # this is a workaround for what appears to be a bug in wx.lib.plot
+        # On macs OnSize is not getting called therefore the buffer is not getting
+        # created anywhere so we forcefully call it here
+        #if wx.Platform == "__WXMAC__":
+	#    print "calling on size..."
+	#self.__wxpcPlotCanvas.OnSize(None)
+            
+        #self.__wxpcPlotCanvas.OnSize(wx.EVT_SIZE)
+        self.__wxpcPlotCanvas.SetEnableZoom( True )
+        self.__wxpcPlotCanvas.SetEnableGrid( True )
+
+        self.Bind( EVT_UPDATE_GRAPH, self.__redraw )
+        self.__redraw()
+        self.Show( True )
+
+
+    def Redraw(self):
+        self.__redraw()
+
+#------------------------------------------------------------------------------    
+
+    def shutdown( self, evt=None ):
+        # registered callback function to notify any listeners that graph
+        # was destroyed
+        self.__shutdownCallback( self.__iGraphCode )  
+        
+#------------------------------------------------------------------------------
+
+    # (AKS 2005-03-17)  This function will be called if the user closed a "higher-
+    # level" window that sends a "close event" down the window hierarchy.  In this
+    # case, the higher-level window will be able to track what IDs to remove from
+    # its data structures and will not need to receive any "callback" function
+    # to indicate this information.
+    
+    def manualShutdown( self ):
+        self.Destroy()
+        
+#------------------------------------------------------------------------------
+    
+    def registerShutdownCallback( self, function ):
+        self.__shutdownCallback = function
+        
+#------------------------------------------------------------------------------
+
+    def __redraw( self, evt=None ):
+        #print "...redraw..."
+        tupleStats = self.__pgGraph.getStatistics()
+
+        if ( self.__bPausePlayback == False ):
+        
+            stStatusText = "Minimum: %4.2f   Average: %4.2f   Maximum: %4.2f   Current: %4.2f" % (
+                tupleStats[ self.__pgGraph.I_MINIMUM ],
+                tupleStats[ self.__pgGraph.I_AVERAGE ],
+                tupleStats[ self.__pgGraph.I_MAXIMUM ],
+                tupleStats[ self.__pgGraph.I_CURRENT ] )
+
+            #self.__wxsInfoLine.SetLabel( stStatusText )
+
+            fNewMax = tupleStats[ self.__pgGraph.I_MAXIMUM ] * 1.2
+            # graphics are already stored in PerformanceGraph
+	    self.__wxpcPlotCanvas.Draw( self.__pgGraph.getGraph(), yAxis=(0, fNewMax) ) #, xAxis="Time",
+                                        #yAxis=self.__stYAxisTitle )
+        else:
+            stStatusText = "|| DRAWING PAUSED || Minimum: %4.2f   Average: %4.2f   Maximum: %4.2f   Current: %4.2f" % (
+                tupleStats[ self.__pgGraph.I_MINIMUM ],
+                tupleStats[ self.__pgGraph.I_AVERAGE ],
+                tupleStats[ self.__pgGraph.I_MAXIMUM ],
+                tupleStats[ self.__pgGraph.I_CURRENT ] )
+
+        # end if
+
+        # (AKS 2005-04-26) Use status bar instead
+        self.SetStatusText( stStatusText )
+
+#------------------------------------------------------------------------------
+
+    def CreateMenu(self):
+        menuBar = wx.MenuBar()
+
+        # Playback
+        menuFile = wx.Menu()
+        self.miPlaybackPause = menuFile.Append(-1, "&Pause\tAlt-P", "", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnPause, self.miPlaybackPause)
+        menuBar.Append(menuFile, "&Playback")
+
+        return menuBar
+
+#------------------------------------------------------------------------------
+    
+    def OnPause( self, evt ):
+        if ( self.miPlaybackPause.IsChecked() == True ):
+            self.__bPausePlayback = True
+        else:
+            self.__bPausePlayback = False
+
+
+
+
+
+
+
+
+    
+###########################################################################
+
+# it encapsulates all the performance data monitoring for all the apps
+# it creates SparklineGraphs
+# created only once during the execution of the program
+
+class GraphManager:
+    def __init__( self, wxfParentFrame, sageAppState ):
+
+        # (AKS 2005-04-29) Put MultiPerformanceGraph instances in GraphManager.
+        # There is one MultiPerformanceGraph for each metric listed in
+        # self.__list_stGraphTitles.  Multiple applications will post their
+        # PerformanceGraph PolyLine data into MultiPerformanceGraph.
+        
+
+        # UTILITY FUNCTIONS FOR GUI BUILDING...
+        normalFont = StandardFont()#wx.Font( 11, wx.DEFAULT, wx.NORMAL, wx.NORMAL )
+
+        self.__gmSageAppState = sageAppState
+        self.__wxfParentFrame = wxfParentFrame
+        self.__hashAppGraph = {}
+        self.__hashAppGraphUpdateFlag = {}
+        #self.__bCloseSparklines = False
+        self.__updateList = []   #all the containers that need updating
+        
+        # (AKS 2005-05-03) Use the variable to store the performance update interval
+        self.__iPerformanceUpdateInterval = 2
+
+        self.__hashCallback = {}
+
+        
+        self.__list_stGraphTitles = [ "Rendering Bandwidth (Mbps)",
+            "Rendering Frame Rate (Frames/Sec)", "Rendering Nodes", "Rendering Streams",
+            "Display Bandwidth (Mbps)", "Display Frame Rate (Frames/Sec)", "Display Nodes",
+            "Display Streams" ]
+
+        self.__list_stYAxisTitles = [ "Mbps", "fps", "Nodes", "Streams",
+                                      "Mbps", "fps", "Nodes", "Streams" ]
+
+        self.__list_stOverallGraphTitles = [ "Total Rendering Bandwidth",
+            "Rendering: Average Frames/Sec", "Total Rendering Streams",
+            "Total Rendering Bandwidth", "Rendering: Average Frames/Sec",
+            "Total Rendering Streams" ]
+
+        self.__list_stOverallYAxisTitles = [ "Mbps", "fps", "Streams",
+                                             "Mbps", "fps", "Streams" ]        
+
+
+        # (AKS 2005-05-03) Create totals launcher for multiplot graphs
+        self.__bTotalsLauncherExists = False
+
+
+#------------------------------------------------------------------------------    
+
+    # Responds to 40002...remember, all data comes at once
+    def update( self, windowId ):
+        # Send the update message
+        if windowId in self.__hashAppGraph:
+
+            # Get graphs from Sparklines
+            sgAppSparklines = self.__hashAppGraph[ windowId ]
+            list_pgGraphs = sgAppSparklines.getGraphList()
+
+            #print "Get render bandwidth..."
+            list_pgGraphs[ sgAppSparklines.I_RENDER_BW ].update(
+                self.__gmSageAppState.getRenderItem( 'bandWidth', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_RENDER_FPS ].update(
+                self.__gmSageAppState.getRenderItem( 'frameRate', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_RENDER_NODES ].update(
+                self.__gmSageAppState.getRenderItem( 'nodes', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_RENDER_STREAMS ].update(
+                self.__gmSageAppState.getRenderItem( 'cpu', windowId, 30 ) )
+            
+
+            #print "Get display bandwidth..."        
+            list_pgGraphs[ sgAppSparklines.I_DISPLAY_BW ].update(
+                self.__gmSageAppState.getDisplayItem( 'bandWidth', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_DISPLAY_FPS ].update(
+                self.__gmSageAppState.getDisplayItem( 'frameRate', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_DISPLAY_NODES ].update(
+                self.__gmSageAppState.getDisplayItem( 'nodes', windowId, 30 ) )
+
+            list_pgGraphs[ sgAppSparklines.I_DISPLAY_STREAMS ].update(
+                self.__gmSageAppState.getDisplayItem( 'cpu', windowId, 30 ) )
+            
+
+            self.__hashAppGraphUpdateFlag[ windowId ] = True
+            
+            
+        
+
+        # send an update to all the windows
+        for win in self.__updateList:    
+            try:
+                win.GetSize()
+            except Exception:
+                #print "exception occured... deleting the window"
+                del win
+            else:
+                win.Redraw()  # call redraw on SparklineGraph
+        
+
+        # (AKS 2005-05-04) ALWAYS EXECUTE...Call update function for totals Sparkline;
+        # instances of PerformanceGraphs in MultiPerformanceGRaphs in Sparkline
+        # have already updated since they share the same reference address
+        # (hopefully).  Now, just call a special update that will get the
+        # totals Sparkline to calculate totals based on these updates.
+        
+        if ( self.__bTotalsLauncherExists == True ):
+            self.__sgTotalsLauncher.updateMultiPerformanceGraphs( self.__iPerformanceMetricCount )
+
+             
+#------------------------------------------------------------------------------
+    
+    # Responds to 40000, 40001...OR JUST RIGHT-CLICK
+    def addGraph( self, stAppName, windowId, parent=None ):  #RJ added "parent=None"
+        if parent == None:
+            parent = self.__wxfParentFrame
+        list_pgGraphs = []
+
+        for stGraphTitle in self.__list_stGraphTitles:
+            list_pgGraphs.append( PerformanceGraph( 
+                stAppName, stGraphTitle, 30, self.__iPerformanceUpdateInterval ) )
+
+        
+        # Create an application Sparkline graph launcher
+        # (AKS 2005-05-03) Only create the SparklineGraph if it has not already been created
+
+        if ( windowId not in self.__hashAppGraph ):
+            
+            slTotalsGraphLauncher = SparklineGraphs( parent,   #RJ - put parent instead of __wxf...
+                list_pgGraphs, self.__list_stGraphTitles,
+                self.__list_stGraphTitles, self.__list_stYAxisTitles, stAppName, windowId, self.__wxfParentFrame )
+            
+
+            # (AKS 2005-03-10) Register callback to destroy graph when the sparklines
+            # window is closed.
+            slTotalsGraphLauncher.registerShutdownCallback( self.removeGraph )
+
+            # Update the hashes
+            self.__hashAppGraph[ windowId ] = slTotalsGraphLauncher
+            self.__hashAppGraphUpdateFlag[ windowId ] = False
+            self.AddToUpdateList(slTotalsGraphLauncher)
+
+            # (AKS 2005-05-04) Add newly created PerformanceGraphs to totals Sparkline
+            if ( self.__bTotalsLauncherExists == True ):
+                self.__sgTotalsLauncher.addAppPerformanceGraphList( windowId, list_pgGraphs,
+                    self.__iPerformanceMetricCount )                                   
+                
+        # end...else do nothing
+
+
+    # RJ 05-08-2005
+    def GetSparklineGraph(self, windowId):
+        if not windowId in self.__hashAppGraph:
+            return -1
+        else:
+            return self.__hashAppGraph[ windowId ]
+
+
+    def AddToUpdateList(self, win):
+        if not win in self.__updateList:
+            self.__updateList.append(win)
+
+    def RemoveFromUpdateList(self, win):
+        if win in self.__updateList:
+            self.__updateList.remove(win)
+        
+    
+#------------------------------------------------------------------------------
+
+    # Responds to 40003...or nothing
+    def removeGraph( self, windowId ):
+        if windowId in self.__hashAppGraph:
+            
+            # (AKS 2005-05-04) Remove performance data related to departing application
+            # from totals Sparkline
+            if ( self.__bTotalsLauncherExists == True ):
+                self.__sgTotalsLauncher.reomveAppPerformanceGraphList( windowId,
+                    self.__iPerformanceMetricCount )
+                
+            
+            sgAppSparklines = self.__hashAppGraph[ windowId ]
+            self.RemoveFromUpdateList(sgAppSparklines)
+            sgAppSparklines.manualShutdown()
+            
+            del self.__hashAppGraph[ windowId ]     # remove app id
+            
+        # else, do nothing          
+            
+#------------------------------------------------------------------------------
+
+    def showTotalsGraph( self ):
+        self.__bCloseSparklines = False
+
+        list_pgGraphs = []
+
+        # Create totals graphs
+        for iIndex in range( 0,len( self.__list_stOverallGraphTitles ) ):
+            list_pgGraphs.append( PerformanceGraph( "SAGE Totals",
+                self.__list_stOverallGraphTitles[ iIndex ], 30 ) )
+
+        # (AKS 2005-03-10) Need "bogus app id" for totals graph; it will be 88888888
+        self.__slTotalsGraphLauncher = SparklineGraphs(
+            self.__wxfParentFrame, list_pgGraphs, self.__list_stOverallGraphTitles,
+            self.__list_stOverallGraphTitles, self.__list_stOverallYAxisTitles, 88888888 )
+
+        self.__slTotalsGraphLauncher.registerCallback( self.onCloseTotalsGraph )
+
+#------------------------------------------------------------------------------
+    
+    def onCloseTotalsGraph( self ):
+        self.__slTotalsGraphLauncher = None
+    
+#------------------------------------------------------------------------------
+        
+    def shutdown( self ):
+        # For each graph, shut down
+        keys = self.__hashAppGraph.keys()
+        for key in keys:
+            self.__hashAppGraph[ key ].shutdown()
+
+        # Makes sure to only call shutdown if the window still exists
+        if ( self.__bTotalsLauncherExists == True ):
+            self.__bTotalsLauncherExists = False
+            self.__slTotalsGraphLauncher.shutdown()
+
+
+#------------------------------------------------------------------------------
+    # (AKS 2005-05-03) Get the performance data update interval
+    def getPerformanceUpdateInterval( self ):
+        return self.__iPerformanceUpdateInterval
+
+#------------------------------------------------------------------------------
+    # (AKS 2005-05-03) Create the totals performance graph
+
+    def createTotalsLauncher( self ):
+        # Create list of MultiPerformanceGraphs...one for each performance metric
+        list_mpgMultiPerfGraphs = []
+        
+        for index in range( 0, len( self.__list_stGraphTitles ) ):
+            list_mpgMultiPerfGraphs.append( MultiPerformanceGraph(
+                {}, self.__list_stGraphTitles ) )
+
+        # end loop
+        
+        # Create the "totals" SparklineGraphs object...need bogus app id of -1
+        # CAREFUL: DIFFERENT TYPE...SENDING LIST OF MultiPerformanceGraph instances
+        # and not PerformanceGraph instances!!!
+        
+        self.__sgTotalsLauncher = SparklineGraphs( self.__wxfParentFrame,
+            list_mpgMultiPerfGraphs, self.__list_stGraphTitles,
+            self.__list_stGraphTitles, self.__list_stYAxisTitles,
+            "SAGE Application Totals", -1 )
+
+        self.__iPerformanceMetricCount = len( self.__list_stGraphTitles )
+        
+        # Populate the MultiPerformanceGraphs from existing app SparklineGraphs
+        for windowId in self.__hashAppGraph:
+            sgAppLauncher = self.__hashAppGraph[ windowId ]
+            list_pgGraphs = sgAppLauncher.getGraphList()
+
+            self.__sgTotalsLauncher.addPerformanceGraphList( list_pgGraphs,
+                self.__iPerformanceMetricCount )
+
+        # end loop
+        self.__bTotalsLauncherExists = True
+
+#------------------------------------------------------------------------------
+    # (AKS 2005-05-04) Shutdown the totals performance graph; since this
+    # exists independent of the SparklineGraph objects, the totals launcher
+    # can be destroyed independently and created independently at any time
+    
+    def shutdownTotalsLauncher( self ):
+        if ( ( self.__sgTotalsGraphLauncher != None ) and
+             ( self.__sgTotalsGraphLauncher.__class__.__name__ ==
+                 SparklineGraphs.__name__ ) ):
+            self.__sgTotalsGraphLauncher.shutdown()
+
+
+    def getSparkline( self, windowId ):
+        if ( windowId in self.__hashAppGraph ):
+            return self.__hashAppGraph[ windowId ]
+
+
+
Index: trunk/src/testing/ui/preferences.py
===================================================================
--- trunk/src/testing/ui/preferences.py	(revision 4)
+++ trunk/src/testing/ui/preferences.py	(revision 4)
@@ -0,0 +1,333 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+###   MODULE FOR SAVING SAGE UI PREFERENCES   ###
+
+import os, os.path, cPickle, copy, sys
+
+from globals import *
+from sagePath import getUserPath
+
+# where we store all the prefs
+PREFS_DIR = getUserPath("sageui", "prefs")
+FILE_LIB_FILE = opj(PREFS_DIR, "file_libs.pickle")
+USERNAMES_FILE = opj(PREFS_DIR, "usernames.pickle")
+VISUAL_FILE = opj(PREFS_DIR, "visuals.pickle")
+FAVORITES_FILE = opj(PREFS_DIR, "favorite_files.pickle")
+MACHINES_FILE = opj(PREFS_DIR, "machines.pickle")
+VNC_FILE = opj(PREFS_DIR, "vnc.pickle")
+
+global fileLib
+global usernames
+global visual
+global favorite_files
+global machines
+global vnc
+
+
+#-------------------------------------------------------
+### for saving and loading preferences
+#-------------------------------------------------------    
+
+def readAllPreferences():
+    global fileLib
+    global usernames
+    global visual
+    global favorite_files
+    global machines
+    global vnc
+
+    
+    p = readPreferences(FILE_LIB_FILE)
+    if not p: fileLib = FileLibraryPrefs()
+    else: fileLib = p
+    
+    p = readPreferences(USERNAMES_FILE)
+    if not p: usernames = Usernames()
+    else: usernames = p
+    
+    p = readPreferences(VISUAL_FILE)
+    if not p: visual = VisualPrefs()
+    else: visual = p
+
+    p = readPreferences(FAVORITES_FILE)
+    if not p: favorite_files = FavoriteFiles()
+    else: favorite_files = p
+    
+    p = readPreferences(MACHINES_FILE)
+    if not p: machines = MachinePrefs()
+    else: machines = p
+    
+    p = readPreferences(VNC_FILE)
+    if not p: vnc = VNCPrefs()
+    else: vnc = p
+
+
+
+### reads the preferences from a file
+def readPreferences(sourceFile):
+    try:
+        f = open(sourceFile, "rb")
+        (objToLoad) = cPickle.Unpickler(f).load()
+        f.close()
+        return objToLoad
+    except:
+        #print sys.exc_info()[0], sys.exc_info()[1]
+        return False
+
+
+### saves the provided object into a specified file
+def savePreferences(objToSave, targetFile):
+    try:
+        f = open(targetFile, "wb")
+        cPickle.Pickler(f, cPickle.HIGHEST_PROTOCOL).dump(objToSave)
+        f.close()
+    except:
+        #print sys.exc_info()[0], sys.exc_info()[1]
+        return False
+
+
+
+
+#-------------------------------------------------------    
+# datastructures for preferences
+#-------------------------------------------------------
+
+
+class VNCPrefs:
+    def __init__(self):
+        self.__profiles = {}  #keyed by profile name
+
+    def AddProfile(self, profileName, ip, displayNum, size, passwd):
+        self.__profiles[profileName] = (ip, displayNum, size, passwd)
+        self.__Save()
+
+    def DeleteProfile(self, profileName):
+        if self.__profiles.has_key(profileName):
+            del self.__profiles[profileName]
+            self.__Save()
+
+    def ProfileExists(self, profileName):
+        return self.__profiles.has_key(profileName)
+
+    def GetProfileList(self):
+        return copy.deepcopy(self.__profiles.keys())
+
+    def GetProfile(self, profileName):
+        return self.__profiles[profileName]
+
+    def __Save(self):
+        savePreferences(self, VNC_FILE)
+
+        
+            
+class Usernames:
+    def __init__(self):
+        self.__usernames = ["New-user"]
+        self.__default = "New-user"
+
+    def AddUsername(self, username):
+        if not username in self.__usernames:
+            self.__usernames.append(str(username))
+        self.__default = str(username)
+        self.__Save()
+
+    def GetDefault(self):
+        return self.__default
+
+    def GetUsernames(self):
+        return copy.deepcopy(self.__usernames)
+
+    def __Save(self):
+        savePreferences(self, USERNAMES_FILE)
+
+
+
+class MachinePrefs:
+    def __init__(self):
+        self.__machines = {}
+     
+    def GetMachineHash(self):
+        return copy.deepcopy(self.__machines)
+    
+    def AddMachine(self, sageMachine):
+        self.__machines[sageMachine.GetId()] = sageMachine
+        self.__Save()
+
+    def RemoveMachine(self, sageMachine):
+        if self.__machines.has_key(sageMachine.GetId()):
+            del self.__machines[sageMachine.GetId()]
+            self.__Save()
+
+    def __Save(self):
+        savePreferences(self, MACHINES_FILE)
+
+            
+
+class VisualPrefs:
+    def __init__(self):
+        self.__frameSize = None
+        self.__framePos = None 
+        self.__chatShown = None
+        self.__receivePerfData = True
+        self.__keepAspectRatio = True
+
+    def SetFrameSize(self, size):
+        self.__frameSize = size
+        self.__Save()
+
+    def SetFramePos(self, pos):
+        self.__framePos = pos
+        self.__Save()
+
+    def ShowChat(self, doShow):
+        self.__chatShown = doShow
+        self.__Save()
+
+    def SetReceivePerformanceData(self, doReceive):
+        self.__receivePerfData = doReceive
+        self.__Save()
+
+    def SetKeepAspectRatio(self, doKeep):
+        self.__keepAspectRatio = doKeep
+        self.__Save()
+
+    def GetKeepAspectRatio(self):
+        return self.__keepAspectRatio
+
+    def GetReceivePerformanceData(self):
+        return self.__receivePerfData
+        
+    def GetFramePos(self):
+        return self.__framePos
+
+    def GetFrameSize(self):
+        return self.__frameSize
+
+    def IsChatShown(self):
+        return self.__chatShown
+
+    def SetAll(self, size, pos, chatShow):
+        self.__frameSize = size
+        self.__framePos = pos
+        self.__chatShown = chatShow
+        self.__Save()
+
+    def __Save(self):
+        savePreferences(self, VISUAL_FILE)
+
+
+
+class FavoriteFiles:
+    def __init__(self):
+        self.__favorites = {}
+
+    def AddFavorite(self, itemData):
+        type = itemData.GetType()
+        if not self.__favorites.has_key(type):
+            self.__favorites[type] = []
+        self.__favorites[type].append(itemData)
+        self.__Save()
+
+    def RemoveFavorite(self, itemData):
+        type = itemData.GetType()
+        if self.AlreadyFavorite(itemData):
+            self.__favorites[type].remove(itemData)
+            self.__Save()
+
+    def AlreadyFavorite(self, itemData):
+        type = itemData.GetType()
+        if self.__favorites.has_key(type) and (itemData in self.__favorites[type]):
+            return True
+        else:
+            return False
+
+    def GetFavorites(self):
+        return copy.deepcopy(self.__favorites)
+
+    def __Save(self):
+        savePreferences(self, FAVORITES_FILE)
+
+
+
+class FileLibraryPrefs:
+    def __init__(self):
+        self.__libs = {"local":"localhost"}  #keyed by name
+        self.__default = ("local", "localhost")
+
+    def AddLibrary(self, ip, name):
+        if self.__libs.has_key(name):
+            return False
+        else:
+            self.__libs[name] = ip
+            self.__Save()
+
+    def RemoveLibrary(self, name):
+        if self.__libs.has_key(name):
+            del self.__libs[name]
+            self.__Save()
+
+    def GetLibraries(self):
+        return copy.deepcopy(self.__libs)  #prevent the user from modifying it directly
+
+    def GetLibraryIP(self, name):
+        if self.__libs.has_key(name):
+            return self.__libs[name]
+        else:
+            return False
+
+    def GetLibraryList(self):
+        return self.__libs.keys()
+
+    def SetDefault(self, name, ip):
+        if not ip:
+            return
+        self.__default = (str(name), str(ip))
+        self.__Save()
+
+    def GetDefault(self):
+        return self.__default
+
+    def __Save(self):
+        savePreferences(self, FILE_LIB_FILE)
+
+
+
+
+
Index: trunk/src/testing/ui/users.py
===================================================================
--- trunk/src/testing/ui/users.py	(revision 4)
+++ trunk/src/testing/ui/users.py	(revision 4)
@@ -0,0 +1,1378 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+from threading import Thread, RLock
+import time, socket, string, os.path, sys, wx
+
+from globals import *
+from Mywx import MyButton
+from sageui import AboutDialog
+import preferences as prefs
+
+# some globals for this module
+CHUNK_SIZE = 2048 #4096
+SOCKET_TIMEOUT = 1
+MSGLEN = CHUNK_SIZE
+SEPARATOR = '\0'
+
+
+
+#  MESSAGES:
+#
+#
+#  Notes:
+#  --------------------
+#  All messages are sent in this format (as strings):
+#  code
+#  data
+#
+#  For example:
+#  "2002"
+#  "Ratko"
+#
+#
+#  All machines are always keyed by machineId that the users should connect to to control SAGE
+#
+#
+#  <<< UI  --->  SERVER >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+#  2000    username                register this user with the Users server
+#          info
+#          machine_id              the machines the user is connected to
+#
+#  2001    from={username}         send a chat message to one person or to all
+#          to={"all" | id}         id = specific to users connected to a sepcific SAGE machine
+#          message
+#
+#  2002    username                check username for duplicates
+#
+#  2003    username                unregister this username from the machine specified
+#          machine_id
+#
+#          
+#  <<< SERVER  --->  UI >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+# 
+#  30000   machine_name            a status list of all the MACHINES registered with the server
+#          ip
+#          port
+#          machineId
+#          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+#          displayInfo             in this format: "Xtiles Ytiles tileWidth tileHeight"
+#          "\x00"               < --- a break between different blocks of data
+#          machine_name
+#          ip
+#          port
+#          machineId
+#          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+#          displayInfo             in this format: "Xtiles Ytiles tileWidth tileHeight"
+#          "\x00"
+#          ....
+#
+#
+#  30001   username                receive a list of USERS that are connected and their info
+#          info
+#          machine_id              the machines the user is connected to
+#          machine_id
+#          "\x00"               < --- a break between different users' info
+#          username
+#          info
+#          machine_id
+#          "\x00"
+#          ....
+#
+#  30002   from={username}         receive a chat message from one person,
+#          to={"all" | id}        id = specific to users connected to a specific SAGE machine
+#          message
+#
+#  30003   "1" | "0"              1=username OK, 0=username already in use
+#
+#  31000   message                an informative message... just any string
+#
+#
+#
+#  <<< SAGE  --->  SERVER >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+#  
+#  100     machine_name           "i am alive" message from SAGE
+#          ip                   < --- machine ip and port that SAGE UIs should connect to
+#          port
+#
+
+
+
+
+class MachineListCtrl(wx.ListCtrl):
+    
+    def __init__(self, dialogClass, parent, pos, size):
+        wx.ListCtrl.__init__(self, parent, -1, pos, size, style=wx.LC_SINGLE_SEL | wx.LC_REPORT | wx.LC_NO_HEADER)
+        if "__WXMAC__" not in wx.PlatformInfo:
+            self.SetTextColour(wx.WHITE)
+            self.SetBackgroundColour(appPanelColor)
+        self.parent = parent
+        self.usersData = getUsersData()
+        self.host = None
+        self.port = 20001
+        self.hostname = ""
+        self.dialogClass = dialogClass
+        
+        # holds the two images for 
+        imageList = wx.ImageList(16, 16)
+        greenImg = wx.Image(ConvertPath("images/green_circle.gif"))
+        redImg = wx.Image(ConvertPath("images/red_circle.gif"))
+        greenBmp = greenImg.Rescale(16,16).ConvertToBitmap()
+        redBmp = redImg.Rescale(16,16).ConvertToBitmap()
+        self.greenIndex = imageList.Add(greenBmp)
+        self.redIndex = imageList.Add(redBmp)
+        self.AssignImageList(imageList, wx.IMAGE_LIST_SMALL)
+        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnDoubleClick)
+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectItem)
+        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnDeselectItem)
+        
+        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
+        self.currentIndex = -1
+
+        self.InsertColumn(0, "", wx.LIST_FORMAT_LEFT)
+        self.SetColumnWidth(0, self.GetSize().width-2)
+        
+        self.machineHash = {}   #contains all the machines currently displayed in the list
+        self.RefreshMachineList()  #this will fill the self.machineHash and fill the list with it
+        
+
+    def OnSelectItem(self, evt):
+        self.dialogClass.EnableButtons()
+
+    def OnDeselectItem(self, evt):
+        self.dialogClass.EnableButtons(False)
+        
+
+            #returns the last selected SAGEMachine, if none was selected, returns None
+    def GetSelectedMachine(self):
+        index  = self.GetFirstSelected()
+        if self.toolTipHash.has_key(index):
+            return self.toolTipHash[index]
+        return None
+
+
+            # gets the hash of machines from the config file,
+            # gets the hash of machines received from the server,
+            # combines them into one hash (self.machineHash),
+            # if there are overlaps, the one from the server gets precedence
+            # everything is keyed by the ID of each machine and the data
+            # stored in every hash is actually a bunch of SAGEMachines
+    def RefreshMachineList(self, data=None):
+        self.DeleteAllItems()     #first delete everything
+
+        #now update the hash holding all the machines
+        self.machineHash = {}
+        self.machineHash = self.usersData.GetMachinesStatus().copy()
+
+        # insert the sorted list of machines into the control
+        self.toolTipHash = {}  # a hash of sageMachines indexed by their ListCtrl index
+        index = 0
+        machines = self.machineHash.values()
+        machines.sort(lambda x, y: cmp(x.GetName().lower(), y.GetName().lower()))
+        for sageMachine in machines: 
+            self.toolTipHash[index] = sageMachine  #used for creation of correct tooltips
+            self.InsertRow(sageMachine, index)
+            index = index + 1
+
+        self.dialogClass.EnableButtons(False)
+
+
+##     def GetMachineForAutoload(self, name):
+##         self.machineHash = {}
+##         print "usersData machinestatus: ", self.usersData.GetMachinesStatus()
+##         self.machineHash = self.usersData.GetMachinesStatus().copy()
+##         return self.GetMachineByName(name)
+    
+        
+            # inserts an item into the ListCtrl and sets the appropriate icon for it
+            # it compares the machines based on their IDs 
+    def InsertRow(self, sageMachine, index=-1):
+        if index == -1:  #if true, insert at the end
+            index = self.GetItemCount()
+
+        if self.usersData.HasMachine(sageMachine.GetId()):  # set the correct icon
+            if sageMachine.IsAlive():
+                self.InsertImageStringItem(index, sageMachine.GetName(), self.greenIndex )
+            else:               #the machine is not running but the room is still open since there are users in it
+                self.InsertImageStringItem(index, sageMachine.GetName(), self.redIndex )
+        else:                   #the machine is not even running
+            self.InsertImageStringItem(index, sageMachine.GetName(), self.redIndex )
+
+        if self.GetItemCount() > self.GetCountPerPage():  # a visual fix 
+            self.SetColumnWidth(0, self.GetSize().width - 25 - 2)
+        else:
+            self.SetColumnWidth(0, self.GetSize().width - 2)
+            
+
+    #---------------------------------------------------------------
+    # for tooltips
+    #---------------------------------------------------------------
+    
+    def OnMouseMotion(self, event):
+        return
+        (index, flag) = self.HitTest(event.GetPosition())
+        if not index == wx.NOT_FOUND:
+            if self.currentIndex == index:  # if the tooltip is already displayed, just return
+                return
+            self.currentIndex = index
+            #sageMachine = self.GetMachineByName( self.GetItem(index).GetText() )
+            self.MakeToolTip(self.toolTipHash[index])
+
+
+    def GetMachineByName(self, name):    #returns the first machine with the specified name, or None
+        for sageMachine in self.machineHash.itervalues():
+            if sageMachine.GetName() == name:
+                return sageMachine
+        return None
+
+        
+    def MakeToolTip(self, sageMachine):
+        name = string.upper(sageMachine.GetName())
+        ip = "\nIP: "+sageMachine.GetIP()
+        port = "\nPort: "+str(sageMachine.GetPort())
+        if sageMachine.GetNumTiles()[0] == 0:
+            size = "\nSize: ? x ?"
+        else:
+            size = "\nSize: "+str(sageMachine.GetNumTiles()[0])+" x "+str(sageMachine.GetNumTiles()[1])  
+        ttString =  name + ip + port + size 
+        tt = wx.ToolTip(ttString)
+        tt.SetDelay(300)
+        self.SetToolTip(tt)
+
+    #---------------------------------------------------------------
+
+    def OnDoubleClick(self, event):
+        self.hostname = self.GetItemText(event.GetIndex())
+        if hasattr(self.parent, "IsModal") and self.parent.IsModal():
+            self.parent.EndModal(wx.ID_OK)
+
+
+            # when the user presses "Add" button
+    def AddMachine(self, name, host, port, sysIP, sysPort):
+        newMachine = SAGEMachine(name, host, port, sysIP, sysPort, host+":"+str(port), False)
+        prefs.machines.AddMachine(newMachine)    # add it to the preferences
+        self.usersData.AddNewSAGEMachine(newMachine)  # and then to the list of all the machines
+        self.RefreshMachineList()  #this will refresh the list
+
+
+            # when the user presses "Delete" button
+    def RemoveMachine(self, sageMachine):
+        prefs.machines.RemoveMachine(sageMachine)   # remove from preferences
+        self.usersData.RemoveMachine(sageMachine)   # now remove from the datastructure as well
+        self.RefreshMachineList()   # refresh the list visually
+
+
+
+
+
+
+
+
+class ConnectionDialog:
+
+    def __init__(self, sageGate, usersClient, usersServerIP="sage.sl.startap.net", usersServerPort=15558, firstConnection=True, autologinMachine=None):
+        self.sageGate = sageGate
+        self.client = usersClient
+        self.usersData = getUsersData()
+        self.selectedMachine = None
+        self.firstConnection = firstConnection  # first SAGE connection for this UI
+        self.__firstTry = True   # first try of this connection... to disable autologin after the first try
+        self.connectedToServer = False
+        self.autologinMachine = autologinMachine
+        if self.firstConnection:
+            if not self.client.Connect(usersServerIP, usersServerPort):
+                dlg = wx.MessageDialog(None, "Could not connect to sage server \"" + usersServerIP + "\". Chat will be unavailable."
+                                       , "Connection Error", style=wx.OK)
+                dlg.ShowModal()
+                dlg.Destroy()
+            else:
+                self.connectedToServer = True
+        self.usernameOK = None  #it's None until we get a reply from the UsersServer about the validity of the chosen username
+        
+        # data produced by this dialog
+        self.machine = None
+
+
+        # the machine that we are trying to connect to
+    def GetMachine(self):
+        return self.machine
+
+
+        # show the initial connection dialog
+        # if "Connect" was pressed, check the username for duplicate and if that's OK,
+        # try to connect to SAGE
+    def ShowDialog(self):
+        while True:  # loop until the user gets it right or quits
+            if not self.ShowConfigDialog():  #user pressed "Quit"
+                return False
+            else:     # first check the username with the UsersServer and then try to connect to SAGE
+                if self.TryStart():
+                    if self.firstConnection:
+                        self.usersData.UnregisterUICallback(30000)  #FIX, for multiple connections
+                    return True
+                else:  # something failed so show the dialog again
+                    self.usernameOK = None  # so that we have to check the username again
+
+
+        # this does all the checks
+    def TryStart(self):
+        if self.firstConnection and self.connectedToServer:
+            usernameResult = self.CheckUsername() 
+            if usernameResult == False:
+                dlg = wx.MessageDialog(None, "Username \"" + self.usersData.GetMyUsername() + "\" already taken. Please choose another one."
+                                 , "Username Invalid", style=wx.OK)
+                dlg.ShowModal()
+                dlg.Destroy()
+                return False
+
+            elif usernameResult == -1:  #connection failed but we'll let the user continue
+                dlg = wx.MessageDialog(None, "Connection to sage server failed.\nChat will be unavailable."
+                                 , "Connection Failed", style=wx.OK)
+                dlg.ShowModal()
+                dlg.Destroy()
+            
+        # if we got here, username checked out OK so try to connect to SAGE and Register
+        if self.ConnectToSAGE():
+            if self.firstConnection or (not self.usersData.AmIConnectedTo(self.machine.GetId())):
+                self.RegisterUser()  #only register if the connection to SAGE succeeded
+            return True
+        else:
+            return False
+
+
+        # enables or disables the buttons that require that a selection in the list
+        # is made before proceeding  (Connect and Delete buttons notably)
+    def EnableButtons(self, doEnable=True):
+        if hasattr(self, "okBtn"):
+            if doEnable:
+                self.okBtn.Enable(True)
+                self.delButton.Enable(True)
+                self.infoButton.Enable(True)
+            else:
+                self.okBtn.Enable(False)
+                self.delButton.Enable(False)
+                self.infoButton.Enable(False)
+
+
+    def ShowConfigDialog(self):
+        
+        # UI elements
+        yOffset = 7
+        dialog = wx.Dialog(None, -1, "SAGE Connection")#, size=(200, 240))#, style = wx.SIMPLE_BORDER)
+        if "__WXMAC__" not in wx.PlatformInfo:
+            dialog.SetBackgroundColour(dialogColor)
+            dialog.SetForegroundColour(wx.WHITE)
+        dialog.SetClientSizeWH(200, 300+yOffset)
+        
+        #helpButton = MyButton(dialog, (170, 10+yOffset), (20,20), self.OnHelp, "images/help.png", tTip="Help")
+        self.machineList = MachineListCtrl(self, dialog, (20,35+yOffset), (160,125))
+        if self.firstConnection:
+            self.usersData.RegisterUICallback( 30000, self.machineList.RefreshMachineList) #so that we receive updates even if we are not registered yet
+        text = wx.StaticText(dialog, -1, "Connect To:", (10, 10+yOffset))
+        addButton = wx.Button(dialog, -1, "Add",  (15, 160+yOffset), (50, 20))
+        addButton.SetClientSize((50, 20))
+        smallFont = addButton.GetFont()
+        smallFont.SetPointSize(smallFont.GetPointSize() - smallFont.GetPointSize()/5)
+        addButton.SetFont(smallFont)
+        self.infoButton = wx.Button(dialog, -1, "Info", (75, 160+yOffset), (50, 20))
+        self.infoButton.SetClientSize((50,20))
+        self.infoButton.SetFont(smallFont)
+        self.infoButton.Enable(False)
+        self.delButton = wx.Button(dialog, -1, "Delete", (135, 160+yOffset), (50, 20))
+        self.delButton.Enable(False)
+        self.delButton.SetClientSize((50, 20))
+        self.delButton.SetFont(smallFont)
+        self.okBtn = wx.Button(dialog, wx.ID_OK, "Connect", (10, 264+yOffset))
+        self.okBtn.Enable(False)
+        if self.firstConnection:  #if it's a first connection, allow the user to enter a username
+            cancelBtn = wx.Button(dialog, wx.ID_CANCEL, "Quit", (110, 264+yOffset))
+            userLabel = wx.StaticText(dialog, -1, "Connect As:", (10, 195+yOffset))
+            initialUsername = prefs.usernames.GetDefault()
+            userText = wx.ComboBox(dialog, -1, initialUsername, (10,215+yOffset), (180,25), choices=prefs.usernames.GetUsernames(), style=wx.CB_DROPDOWN)
+            userText.SetForegroundColour(wx.BLACK)
+            userText.Bind(wx.EVT_KEY_DOWN, self.OnEnter, userText)
+            userText.SetFocus()
+        else:                   # login under the same name but to a another machine
+            cancelBtn = wx.Button(dialog, wx.ID_CANCEL, "Cancel", (110, 264+yOffset))
+            userLabel = wx.StaticText(dialog, -1, "Connect As: "+self.usersData.GetMyUsername(), (10, 205))
+
+        dialog.Bind(wx.EVT_BUTTON, self.OnAddButton, addButton)
+        dialog.Bind(wx.EVT_BUTTON, self.OnDelButton, self.delButton)
+        dialog.Bind(wx.EVT_BUTTON, self.OnInfoButton, self.infoButton)
+        #### - end UI elements
+
+
+        # try autologging first... if that fails display the dialog
+        if self.__firstTry and self.autologinMachine and self.usernameOK == None:
+            print "Autologin to:", self.autologinMachine
+            tries = 0
+            while not self.machineList.GetMachineByName(self.autologinMachine) and tries < 10:
+                time.sleep(0.5)
+                tries += 1
+                self.machineList.RefreshMachineList()
+                print "Trying to autologin... try#", tries
+            self.machine = self.machineList.GetMachineByName(self.autologinMachine)
+
+        
+        # so that we don't try to autologin after the first try...
+        # go back to the manual mode
+        if self.__firstTry:  self.__firstTry = False
+        else: self.machine = None
+    
+
+        # display the dialog
+        if not self.machine:
+            while self.machineList.GetFirstSelected() == -1:  #loop until the user selects something
+                if not dialog.ShowModal() == wx.ID_OK:   
+                    return False
+            self.machine = self.machineList.GetSelectedMachine()  #get the selected SAGEMachine
+        
+        if self.firstConnection:  #get the username... but only if this is our first connection
+            if userText.GetValue() == "": #if user entered nothing, use the default
+                self.usersData.SetMyUsername("No Name")
+            else:
+                self.usersData.SetMyUsername( userText.GetValue() )
+                prefs.usernames.AddUsername(userText.GetValue())
+            self.usersData.SetMyInfo("no info")
+        return True
+
+
+    def ShowNewConnectionDialog(self):
+        dialog = wx.Dialog(None, -1, "New Connection", size=(260, 250))#, style = wx.SIMPLE_BORDER)
+        dialog.SetClientSizeWH(250, 250)
+        
+        hostLabel = wx.StaticText(dialog, -1, "Host:", (20, 20))
+        hostText = wx.TextCtrl(dialog, -1, "", (20, 40), (120, 22))
+        portLabel = wx.StaticText(dialog, -1, "Port:", (160, 20))
+        portText = wx.TextCtrl(dialog, -1, "20001", (160, 40), (70, 22))
+
+        sysIPLabel = wx.StaticText(dialog, -1, "System IP (optional):", (20, 90))
+        sysIPText = wx.TextCtrl(dialog, -1, "", (20, 110), (120, 22))
+        sysPortLabel = wx.StaticText(dialog, -1, "System Port:", (160, 90))
+        sysPortText = wx.TextCtrl(dialog, -1, "20002", (160, 110), (70, 22))
+
+        labelLabel = wx.StaticText(dialog, -1, "Label this connection as:", (20, 160))
+        labelText = wx.TextCtrl(dialog, -1, "", (20, 180), (140, 22))
+        self.okBtn = wx.Button(dialog, wx.ID_OK, "Save", (40, 210))
+        cancelBtn = wx.Button(dialog, wx.ID_CANCEL, "Cancel", (140, 210))
+
+        # so that the user can just click ENTER when they are done entering the data
+        labelText.Bind(wx.EVT_KEY_DOWN, self.OnEnter, labelText)
+        
+        if dialog.ShowModal() == wx.ID_OK:
+            return (labelText.GetValue(), hostText.GetValue(), portText.GetValue(), sysIPText.GetValue(), sysPortText.GetValue())
+        else:
+            return (None, None, None, None, None)
+
+
+    def OnHelp(self):
+        AboutDialog(None)
+    
+
+        # sends a request to the usersServer asking if the username already exists
+    def CheckUsername(self):
+        if self.client.IsConnected():
+            self.client.CheckUsername(self.usersData.GetMyUsername())
+            self.totalTime = 0
+            return self.WaitForUsernameReply()
+        else:  #we are not even connected so dont bother
+            return -1
+
+
+        # returns: True if username is valid, False if invalid and0
+        # -1 if something went wrong but we should still continue execution w/o the chat
+    def RegisterUser(self):
+        if self.client.IsConnected():
+            self.client.Register( self.machine.GetId() )
+
+
+        # waits for 5 seconds and sleeps every 1/2 second
+        # once the message from UsersServer arrives informing us of validity of
+        # the chosen username, this function returns True if username was accepted or False otherwise
+    def WaitForUsernameReply(self):
+        while self.client.usernameOK == None:
+            time.sleep(0.5)
+            self.totalTime = self.totalTime + 0.5
+            if self.totalTime > 3:  #dont wait forever... if we waited longer than 5 secs... return -1 (means "failed")
+                self.totalTime = 0
+                return -1
+        else:   # we got a reply back
+            self.totalTime = 0
+            return self.client.usernameOK
+
+
+        # try to connect to the selected machine
+    def ConnectToSAGE(self):
+        retVal = self.sageGate.connectToSage( self.machine.GetIP(), self.machine.GetPort() )
+        if retVal == 1: 
+            return True
+        elif retVal == -1:
+            dlg = wx.MessageDialog(None, "Could not connect to the appLauncher on " + self.machine.GetName(), "AppLauncher Connection Failed", wx.OK)
+            dlg.ShowModal()
+            return True
+        else:
+            dlg = wx.MessageDialog(None, "Could not connect to SAGE on " + self.machine.GetName() + " (" + self.machine.GetId() + ")", "Connection Failed", wx.OK)
+            dlg.ShowModal()
+            return False
+
+            
+        # so that the user can press ENTER to connect (when focus is on the username text field)
+    def OnEnter(self, evt):
+        if evt.GetKeyCode() == wx.WXK_RETURN:
+            obj =  evt.GetEventObject() 
+            if hasattr(obj, "EndModal"):  #since we use this in NewConnection and Config dialogs
+                obj.EndModal(wx.ID_OK) #OnEnter was bound to a dialog
+            else:
+                obj.GetParent().EndModal(wx.ID_OK)  #OnEnter was bound to a child of a dialog
+        else:
+            evt.Skip()
+
+
+        # shows the info about a selected machine
+    def OnInfoButton(self, evt):
+        sageMachine = self.machineList.GetSelectedMachine()
+        if sageMachine == None:
+            return
+
+        info = "MACHINE: " + str(sageMachine.GetName())
+        info += "\n-----------------------------------------------------"
+        info += "\nIP ADDRESS: " + str(sageMachine.GetIP())
+        info += "\nPORT FOR SAGE UI CONNECTIONS: " + str(sageMachine.GetPort())
+        info += "\nSYSTEM IP: " + sageMachine.GetSystemIP()
+        info += "\nSYSTEM PORT: " + sageMachine.GetSystemPort()
+        if sageMachine.IsAlive():
+            info += "\nRUNNING:\tYes"
+        else:
+            info += "\nRUNNING:\tNo"
+        info += "\nTILE ARRANGEMENT:\t"+str(sageMachine.GetNumTiles()[0])+" x "+str(sageMachine.GetNumTiles()[1]) 
+        info += "\nDISPLAY SIZE:\t"+str(sageMachine.GetDisplaySize()[0])+" x "+str(sageMachine.GetDisplaySize()[1])+" pixels"
+        info += "\nTILE SIZE:\t"+str(sageMachine.GetTileSize()[0])+" x "+str(sageMachine.GetTileSize()[1])+ " pixels"
+        
+        dialog = wx.MessageDialog(None, info, "Details for "+str(sageMachine.GetName()), style=wx.OK)
+        dialog.ShowModal()
+        dialog.Destroy()
+        
+
+    def OnAddButton(self, evt):
+        while True:
+            (name, host, port, sysIP, sysPort) = self.ShowNewConnectionDialog()
+            if host==None:  #user pressed "Cancel"
+                return
+            break
+        if len(sysIP) < 2:
+            sysIP = host  #in case user hasnt filled the sysIP field
+        self.machineList.AddMachine(name, host, port, sysIP, sysPort)  #inserts the item into the machineList and update the config file
+
+
+    def OnDelButton(self, evt):
+        selectedMachine = self.machineList.GetSelectedMachine()
+        if not selectedMachine == None:   #if the user actually has something selected
+            self.machineList.RemoveMachine(selectedMachine)
+
+
+
+
+
+class ChatRoom(wx.Panel):
+
+    def __init__(self, parent, machineId, machine_name, usersClient):
+        wx.Panel.__init__(self, parent, -1)
+        self.SetBackgroundColour(dialogColor)
+        self.SetForegroundColour(wx.WHITE)
+        self.client = usersClient
+        self.machineId = machineId  #the machine this chatRoom corresponds to
+        self.machine_name = machine_name  #the machine this chatRoom corresponds to
+        self.usersData = getUsersData()
+        
+        self.MakeControls()
+
+
+    def GetId(self):
+        return self.machineId
+
+    def GetMachineName(self):
+        return self.machine_name
+    
+
+    def MakeControls(self):
+        # create the sizer and the panel
+        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.mainSizer.Fit(self)
+        self.SetSizer(self.mainSizer)
+
+        # create the users list
+        self.userListLabel = wx.StaticText(self, -1, "Connected Users:")
+        self.userList = wx.ListBox(self, -1, choices=self.usersData.GetUsernames(self.machineId))#, style=wx.LB_SINGLE)
+        self.userList.SetSizeHints(-1, -1, -1, maxH = 200)
+        
+        # create the chat window
+        self.chatLabel = wx.StaticText(self, -1, "Chat Window:")
+        self.chatWindow = wx.SplitterWindow(self, -1, style = wx.SP_3DSASH )#| wx.SP_LIVE_UPDATE )
+        self.typePanel = wx.TextCtrl(self.chatWindow, -1, "Type your message here and press ENTER to send", style=wx.TE_MULTILINE )
+        self.typePanel.Bind(wx.EVT_KEY_DOWN, self.SendMessage)  #when you press enter, the message is sent
+        self.typePanel.Bind(wx.EVT_SET_FOCUS, self.OnFocus)  #when it receives focus, remove the info
+        self.chatPanel = wx.TextCtrl(self.chatWindow, -1, style=wx.TE_MULTILINE | wx.TE_RICH | wx.TE_LINEWRAP)
+        self.chatPanel.SetEditable(False)
+        
+        self.chatWindow.SetMinimumPaneSize(45)
+        self.chatWindow.SplitHorizontally(self.chatPanel, self.typePanel, -45)
+        self.chatWindow.SetBackgroundColour(dialogColor)#appPanelColor)
+        self.chatWindow.SetForegroundColour(wx.WHITE)
+        # add them to the sizer in the right order
+        self.mainSizer.Add(self.userListLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.TOP | wx.LEFT, border=10)
+        self.mainSizer.Add(self.userList, 1, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL | wx.EXPAND, border=5)
+        self.mainSizer.Add(self.chatLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.TOP | wx.LEFT, border=10)
+        self.mainSizer.Add(self.chatWindow, 2, wx.ALIGN_LEFT | wx.ALIGN_TOP | wx.ALL | wx.EXPAND, border=5)
+        #self.mainSizer.Layout()  #causes  "QPixmap: Invalid pixmap parameters" error
+        self.chatWindow.SetSashGravity(1.0) #must set the gravity here, otherwise default size gets screwed up
+
+        if "__WXMSW__" in wx.PlatformInfo:   #windows has problems showing splitterWindow in the beginning
+            e = wx.SizeEvent(self.chatWindow.GetSize())
+            self.chatWindow.ProcessEvent(e)
+
+        # send a message when user presses ENTER inside the typePanel
+    def SendMessage(self, event):
+        if event.GetKeyCode() == wx.WXK_RETURN or event.GetKeyCode() == wx.WXK_NUMPAD_ENTER:
+            if not self.client.IsConnected():  #if we are not even connected, dont send anything
+                dlg = wx.MessageDialog(None, "Message could not be sent since there is no connection to the sage server."
+                             , "Message not sent", style=wx.OK)
+                dlg.ShowModal()
+                dlg.Destroy()
+                return
+            
+            if self.typePanel.GetValue() != "":  #did the user actually type something
+                if not self.usersData.AmIConnectedTo(self.GetId()):   #if the message was sent from a room that this user is not logged into
+                    if self.usersData.HasMachine(self.usersData.GetMyConnections()[0]):
+                        fromUser = self.usersData.GetMyUsername() + "@" + self.usersData.GetMachine(self.usersData.GetMyConnections()[0]).GetName()
+                    else:
+                        fromUser = self.usersData.GetMyUsername() + "@none"
+                else:  #i am in the room that i am connected to so just print my name
+                    fromUser = self.usersData.GetMyUsername()
+                self.client.SendChatMessage(fromUser, self.GetId(), self.typePanel.GetValue())
+                self.typePanel.Clear()
+        else:
+            event.Skip()
+
+        #when it receives focus, remove the info "Type your message here and press ENTER to send"
+    def OnFocus(self, event):
+        self.typePanel.Clear()
+        
+    
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS
+#-------------------------------------------------------
+
+    def OnUsersStatus(self):
+        # update the ListBox control with the new data from UsersDatastructure
+        self.userList.Set(self.usersData.GetUsernames(self.GetId()))
+        
+
+        #just write the message to the screen with the right font properties
+    def OnChatMessage(self, fromUser, message):
+        self.chatPanel.SetDefaultStyle(wx.TextAttr(wx.BLUE))
+        self.chatPanel.SetInsertionPointEnd()
+        self.chatPanel.AppendText(fromUser + ": ")
+        self.chatPanel.SetDefaultStyle(wx.TextAttr(wx.BLACK))
+        self.chatPanel.AppendText(message+"\n") 
+
+
+
+
+############################################################################
+#
+#  CLASS: UsersPanel
+#  
+#  DESCRIPTION: This is the panel on the side of SAGE UI that contains the
+#               list of users logged in to this SAGE environment. It also
+#               enables users to chat.
+#
+#  DATE:        May, 2005
+#
+############################################################################
+
+class UsersPanel(wx.Frame):
+
+    def __init__(self, parent, usersClient):
+        wx.Frame.__init__(self, parent, -1, "SAGE UI Chat")#, style= wx.SIMPLE_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
+        #self.SetBackgroundColour(wx.Colour(155,200,200))
+        #self.SetBackgroundColour(dialogColor)
+        #self.SetForegroundColour(wx.WHITE)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
+        self.Bind(wx.EVT_MOVE, self.OnMove)
+        self.frame = parent
+        self.sticky = True   #if it moves together with the main frame
+
+        #resize and position it correctly
+        self.SetSize( (300, 500) )
+        self.OnFrameMove()
+        
+        # register functions that will be called when messages arrive
+        self.client = usersClient
+        self.usersData = getUsersData()
+        self.usersData.RegisterUICallback( 30000, self.OnMachinesStatus )
+        self.usersData.RegisterUICallback( 30001, self.OnUsersStatus )
+        self.usersData.RegisterUICallback( 30002, self.OnChatMessage )
+
+        # local data storage
+        self.CreateNotebook()
+        #self.Show()   < -- this is done in DisplayCanvas.OnStatusMessage()  (canvases.py)
+                
+
+    def CreateNotebook(self):
+        self.notebook = wx.Notebook(self, -1)
+        #self.notebook.SetBackgroundColour(appPanelColor)
+        #self.notebook.SetForegroundColour(wx.WHITE)
+        self.chatRooms = {} # a collection of ChatRooms objects (basically pages in self.notebook)
+        
+        # first make the image list:
+        il = wx.ImageList(16, 16)
+        aliveImage = wx.Image(ConvertPath("images/green_circle.gif"))
+        aliveBmp = aliveImage.Rescale(16,16).ConvertToBitmap()
+
+        deadImage = wx.Image(ConvertPath("images/red_circle.gif"))
+        deadBmp = deadImage.Rescale(16,16).ConvertToBitmap()
+        il.Add( aliveBmp )
+        il.Add( deadBmp )
+        self.notebook.AssignImageList(il)
+
+        # create the pages (chat rooms) for every SAGE machine that's currently running
+        # but first, insert the "All" page in the beginning
+        self.chatRooms["all"] = ChatRoom(self.notebook, "all", "all", self.client)
+        self.notebook.AddPage(self.chatRooms["all"], "All")
+        
+        # now add the rest of them
+        for machineId in self.usersData.GetMachinesStatus():
+            if self.usersData.AmIConnectedTo(machineId):
+                self.AddChatRoom(machineId, doSelect=True)
+            else:
+                self.AddChatRoom(machineId)
+
+
+            #make this frame follow the main frame if sticky
+    def OnMove(self, evt):
+        frameX = self.frame.GetSize().width + self.frame.GetPosition().x
+        frameY = self.frame.GetPosition().y
+        if abs(evt.GetPosition().x - frameX) < 40:
+            self.sticky = True
+            self.OnFrameMove()
+        else:
+            self.sticky = False
+
+
+        # called whenever the main frame moves so that this Users Frame follows it
+    def OnFrameMove(self):
+        if self.sticky:
+            x = self.frame.GetSize().width + self.frame.GetPosition().x + 3
+            y = self.frame.GetPosition().y + 20
+            self.MoveXY(x,y)
+
+
+    def OnCloseFrame(self, evt):
+        self.Hide()
+        self.frame.miOptionsShowChat.Check(False)
+
+
+    def Disconnect(self):
+        self.client.Disconnect()
+
+
+    def IsConnected(self):
+        return self.client.IsConnected()
+
+
+    def AddChatRoom(self, machineId, machine_name="All", doSelect=False):
+        if self.usersData.HasMachine(machineId):  #if false, assign a custom name that was passed in
+            machine_name = self.usersData.GetMachine(machineId).GetName()
+
+        # now create the page and add it to the notebook
+        self.chatRooms[machineId] = ChatRoom(self.notebook, machineId, machine_name, self.client)
+        self.notebook.AddPage(self.chatRooms[machineId], machine_name, select=doSelect)
+
+        # set the appropriate icon for it
+        if not machine_name == "All":   #"All" has no icon
+            if self.usersData.HasMachine(machineId) and self.usersData.GetMachine(machineId).IsAlive():
+                self.notebook.SetPageImage(self.notebook.GetPageCount()-1, 0)
+            else:
+                self.notebook.SetPageImage(self.notebook.GetPageCount()-1, 1)
+
+    
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS
+#-------------------------------------------------------
+
+    def OnMachinesStatus(self):
+        # first create new pages for new machines
+        for machineId in self.usersData.GetMachinesStatus():
+            if not self.chatRooms.has_key(machineId): #if the room doesnt exist already...
+               self.AddChatRoom(machineId)
+               
+        # now update the icons for pages that are no longer valid (ie the machine died)
+        pageIndexToDelete = -1
+        pageIdToDelete = -1
+        for pageIndex in range(1, self.notebook.GetPageCount()): #start from 1 since the 0th page is "All" = no icon
+            chatRoom = self.notebook.GetPage(pageIndex)
+            machineId = chatRoom.GetId()
+            if not self.usersData.HasMachine(machineId): #the machine died and there are no more people in that room, so remove the tab
+                pageIndexToDelete = pageIndex  # perform delayed deletion since page indices
+                pageIdToDelete = machineId            # would not be valid if we deleted a page now
+            else:   #otherwise, the machine may not be running but there are still people in there so don't remove the tab
+                if self.usersData.GetMachine(machineId).IsAlive():
+                    self.notebook.SetPageImage(pageIndex, 0)
+                else:
+                    self.notebook.SetPageImage(pageIndex, 1)  #the machine died but there are still people in that room, so keep it open
+
+        # finally delete the page (if there were any for deletion)
+        if pageIndexToDelete > -1:
+            self.notebook.DeletePage(pageIndexToDelete)
+            del self.chatRooms[pageIdToDelete]
+            
+
+    def OnUsersStatus(self):
+        # update all the chatRooms with the new data from UsersDatastructure
+        try:
+            for chatRoom in self.chatRooms.itervalues():
+                chatRoom.OnUsersStatus()
+        except wx.PyDeadObjectError:  # a fix so that the error doesnt show up on exit (it happens because some events might still be in the queue)
+            pass
+
+        
+    def OnChatMessage(self, message):
+        tokens = string.split(message, "\n", 2)
+        fromUser = tokens[0]
+        toRoom = tokens[1]
+        message = tokens[2]
+
+        # write the message to the appropriate window
+        if toRoom == "all":
+            for chatRoom in self.chatRooms.itervalues():
+                chatRoom.OnChatMessage(fromUser, message)
+        else:    #send a message to the specific room
+            if self.chatRooms.has_key(toRoom):
+                self.chatRooms[toRoom].OnChatMessage(fromUser, message)
+
+
+
+
+
+############################################################################
+#
+#  CLASS: UsersClient
+#  
+#  DESCRIPTION: This is the connection to the SAGE users server. It connects
+#               to the server, it receives and sends messages. The receiving
+#               is done in a thread that constantly loops and checks for new
+#               messages on a socket. It sends messages about the apps that
+#               this UI started and also sends all the chat messages.
+#
+#  DATE:        May, 2005
+#
+############################################################################
+
+class UsersClient:
+    
+    def __init__(self):
+        self.connected = False
+        self.threadKilled = False
+        self.usersData = getUsersData()
+        self.usernameOK = None
+
+
+#-------------------------------------------------------
+#  CONNECTION
+#-------------------------------------------------------
+
+    def IsConnected(self):
+        return self.connected
+    
+
+    def Connect(self, host, port):
+        if self.connected: return False
+        
+        # make the socket
+        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        if self.socket is None:
+            print "\n\nUsersClient: socket could not be created"
+            return False
+
+        # set the timeout the first time to 5 secs so that we dont wait for too long when
+        # you cant connect to the users server... the timeout will be reset below
+        self.socket.settimeout(2)
+        
+        # try to connect
+        try:
+            self.socket.connect((host, port))
+        except socket.error, socket.timeout:
+            print "\n\nUsersClient: can't connect to SAGE UI Users Server."
+            return False
+
+        # set some socket options
+        self.socket.settimeout(SOCKET_TIMEOUT)
+
+
+        # start the receiver in a thread
+        self.receiverThread = Thread(target=self.Receiver, args=())
+        self.receiverThread.start()
+        self.threadKilled = False
+        self.connected = True
+
+        return True
+
+  
+
+    def Disconnect(self):
+        #if not self.connected: return False
+		
+        self.threadKilled = True
+        self.connected = False
+        
+	if hasattr(self, "receiverThread"):
+	    self.receiverThread.join()
+	
+        self.socket.close()
+        del self.socket
+        return True
+
+
+#-------------------------------------------------------
+#  SENDING
+#-------------------------------------------------------
+
+           # for formatting the messages correctly and sending them
+    def MakeMsg(self,code,data):
+        if not self.connected:
+            print "UsersClient: not connected to server, message",code,"was not sent"
+            return False
+        
+        msg = '%8s\n%s' %(code,data)
+        msg = msg + ' ' * (MSGLEN-len(msg))
+        self.Send(msg)
+        return msg
+
+
+           # for sending string data (used by MakeMsg)
+    def Send(self, msg):
+        try:
+            self.socket.send(msg)
+        except socket.error:
+            print "UsersClient: Could not send message - socket error"
+            self.connected = False
+        
+
+            # register with the UsersServer
+    def Register(self, machineId):
+        data = self.usersData.GetMyUsername() + "\n" + self.usersData.GetMyInfo() + "\n" + machineId
+        self.usersData.AddMyConnection(machineId)
+        self.MakeMsg(2000, data)
+
+
+    def Unregister(self, machineId):
+        data = self.usersData.GetMyUsername() + "\n" + machineId
+        self.usersData.RemoveMyConnection(machineId)
+        self.MakeMsg(2003, data)
+        
+
+    def SendChatMessage(self, fromUser, toRoom, message):
+        data = fromUser + "\n" + toRoom + "\n" + message
+        self.MakeMsg(2001, data)
+
+
+    def CheckUsername(self, username):
+        self.usernameOK = None
+        self.MakeMsg(2002, username + "\n" + str(getUIVersion()))
+
+
+#-------------------------------------------------------
+#  RECEIVING
+#-------------------------------------------------------
+        
+    # this runs in a thread, loops forever and receives messages
+    def Receiver(self):
+
+        while not self.threadKilled:
+            try:
+                
+                msg = self.socket.recv(CHUNK_SIZE)  #retrieve the message from the socket
+                if len( msg ) < 2:
+                    print "UsersClient: connection closed"
+                    break
+
+                # since recv is not guaranteed to receive exactly CHUNK_SIZE bytes
+                # so keep receiving until it gets the whole chunk
+                while len( msg ) < CHUNK_SIZE:
+                    msg = msg + self.socket.recv(CHUNK_SIZE - len( msg))
+
+                if self.threadKilled:
+                    break
+
+                # strip all the empty spaces from the message and retrieve useful information
+                cleanMsg = self.CleanBuffer( msg )
+                cleanMsg = string.strip( cleanMsg )
+                msgHeader = string.split(cleanMsg, "\n", 1)
+                if len(msgHeader) < 1:
+                    continue
+                code = int(msgHeader[0])
+                if len(msgHeader) == 1:
+                    data = ""
+                else:
+                    data = msgHeader[1]
+
+                
+            except socket.timeout:
+                continue
+            except socket.error:
+                print "UsersClient: socket error on socket.receive"
+                break
+	    #except:
+                #print 'UsersClient: exception occured in Receiver: ', sys.exc_info()[0], sys.exc_info()[1]
+            #    break	    
+
+
+            ##################
+            # Call function for updating ui-information
+            # wx.CallAfter is used because we pass this onto the GUI thread
+            # to do since wx functions need to be called from the main thread (the GUI thread)
+            ###########################################
+            
+            # call the appropriate function to update the datastructure
+            if code == 30000:
+                self.usersData.OnMachinesStatus(data)
+            if code == 30001:
+                wx.CallAfter(self.usersData.OnUsersStatus, data)
+            if code == 30002:
+                if data == "": continue
+                wx.CallAfter(self.usersData.OnChatMessage, data )
+            if code == 30003:
+                self.SaveUsernameOK(data)
+
+        # exited the while loop so we are not connected anymore
+        self.connected = False
+        self.threadKilled = True
+		
+
+    # converts all non-printable characters from the buffer to white spaces
+    # (so that they can be removed using string.strip() function)
+    def CleanBuffer( self, stBuffer ):
+        stNewBuffer = ""
+        
+        for ch in stBuffer:
+            if ch == '\0':   #this is our message separator so handle it separately
+                stNewBuffer += ch
+            elif ch in string.printable:
+                stNewBuffer += ch
+            else:
+                stNewBuffer += " "
+        return stNewBuffer
+        
+
+        # when user tries to register, it first has to check the username so
+        # this message comes back to confirm the validity of it
+    def SaveUsernameOK(self, data):
+        self.usernameOK = bool(int(data))
+
+
+
+
+
+# a data structure to hold all the machines, users and so on
+class UsersDatastructure:
+
+    def __init__(self):
+        self.usersStatusHash = {}
+        self.machinesStatusHash = {}
+        self.uiCallback = {}   # functions for updating the UI
+        self.myconnections = []    # the machines this user is connected to (SAGEMachine objects keyed by machineId)
+        self._username = "No Name"  # this user's username
+        self._info = "No Info"     # this user's info
+        self.machinesStatusHash.update(prefs.machines.GetMachineHash().copy())
+        
+
+        # for updating the UI once the datastructure has been updated
+    def RegisterUICallback(self, code, func):
+        self.uiCallback[code] = func
+
+    def UnregisterUICallback(self, code):
+        if code in self.uiCallback:
+            del self.uiCallback[code]
+        
+
+    ##### UPDATE DATA  -----------------------------------------------------
+
+            # updates the data structure when the new machine status comes in
+    def OnMachinesStatus(self, data):
+        machines = string.split(data, SEPARATOR)
+        self.ClearMachinesStatus()
+
+        # first add the machines from the preferences
+        self.machinesStatusHash.update(prefs.machines.GetMachineHash().copy())
+        if data != "":   # when no machines are reported we get an empty message from the server
+            # now add the machines from the server (but they first need to be created)
+            for machine in machines:
+                machineData = machine.splitlines()
+                name = machineData[0]
+                ip = machineData[1]
+                port = machineData[2]
+                machineId = machineData[3]
+                alive = bool( int(machineData[4]) )
+                displayInfo = str(machineData[5])
+                displayData = string.split(displayInfo)    #extract the data from the displayInfo string
+                if len(machineData) > 6: # the first time we connect we dont get the system port/ip
+                    (sysIP, sysPort) = machineData[6].split()
+                else:
+                    (sysIP, sysPort) = (ip, port+str(1))
+                self.AddNewMachine(name, ip, port, sysIP, sysPort, machineId, alive, displayData) 
+
+        # update the ui
+        if 30000 in self.uiCallback:
+                wx.CallAfter(self.uiCallback[30000])
+        
+
+        # updates the data structure when the new machine status comes in
+    def OnUsersStatus(self, data):
+        users = string.split(data, SEPARATOR)  #split it into individual client's status
+        self.ClearUsersStatus()  #recreate the hash from scratch
+        for user in users:
+            if user == "":
+                break
+            userData = string.split(user, "\n",2)
+            username = userData[0]
+            info = userData[1]
+            if len(userData) > 2:
+                machineList = string.split(userData[2], "\n")  #split the machines into a list
+            else:
+                machineList = []
+            self.AddNewUser(username, info, machineList)  #store info about all the users in a hash
+
+        # update the ui
+        if 30001 in self.uiCallback:
+            self.uiCallback[30001]()
+
+
+        # actually just relays the message to the appropriate UI component
+    def OnChatMessage(self, data):
+        # update the ui
+        if 30002 in self.uiCallback:
+            self.uiCallback[30002](data)
+        
+
+    ##### MY DATA  ---------------------------------------------------------
+
+    def GetMyInfo(self):
+        return self._info
+
+    def SetMyInfo(self, newInfo):
+        self._info = newInfo
+
+    def GetMyUsername(self):
+        return self._username
+
+    def SetMyUsername(self, username):
+        self._username = username
+        
+    def GetMyConnections(self):
+        return self.myconnections
+
+    def AddMyConnection(self, machineId):
+        self.myconnections.append(machineId) 
+
+    def RemoveMyConnection(self, machineId):
+        if machineId in self.GetMyConnections():
+            self.myconnections.remove(machineId)
+
+    def AmIConnectedTo(self, machineId):
+        return machineId in self.GetMyConnections()
+
+
+    ##### MACHINES  ----------------------------------------------------------
+
+    def HasMachine(self, machineId):
+        return self.GetMachinesStatus().has_key(machineId)   #True of False
+
+    def FindMachineByIP(self, ip):
+        for machine in self.machinesStatusHash.itervalues():
+            if machine.HasIP(ip):
+                return machine
+        return False
+
+    def GetMachine(self, machineId):
+        return self.GetMachinesStatus()[machineId]   #returns SAGEMachine
+
+    def GetMachineNames(self):
+        tempList = []
+        for sageMachine in self.GetMachinesStatus().itervalues():
+            tempList.append(sageMachine.GetName())
+        return tempList
+
+    def GetMachinesStatus(self):  #returns SAGEMachines hash
+        return self.machinesStatusHash 
+
+    def AddNewMachine(self, name, ip, port, sysIP, sysPort, machineId, alive, displayInfo=[]):
+        self.machinesStatusHash[ machineId ] = SAGEMachine(name, ip, port, sysIP, sysPort, machineId, alive, displayInfo)
+
+    def AddNewSAGEMachine(self, newMachine):
+        self.machinesStatusHash[ newMachine.GetId() ] = newMachine
+
+    def RemoveMachine(self, machine):
+        if machine.GetId() in self.machinesStatusHash:
+            del self.machinesStatusHash[ machine.GetId() ]
+
+    def ClearMachinesStatus(self):
+        del self.machinesStatusHash
+        self.machinesStatusHash = {}
+
+        
+    ##### USERS  -------------------------------------------------------------
+        
+    def HasUsername(self, username):
+        return self.GetUsersStatus().has_key(username)
+
+    def GetUser(self, username):
+        return self.GetUsersStatus()[username]
+
+    def GetUsernames(self, machine="all"):  #if machine is specified, it returns a list of all the users connected to that machine
+        if machine == "all":
+            return self.GetUsersStatus().keys()
+        else:
+            tempList = []
+            # loop through all the users and see if the machine they are connected to matches
+            # the machine we passed in here
+            for username, sageUser in self.GetUsersStatus().iteritems():
+                if machine in sageUser.GetMachines():
+                    tempList.append(username)
+            return tempList
+
+    def GetUsersStatus(self):   #returns SAGEUsers
+        return self.usersStatusHash
+
+    def AddNewUser(self, username, info, machineList=[]):
+        self.usersStatusHash[ username ] = SAGEUser(username, info, machineList)
+            
+    def ClearUsersStatus(self):
+        del self.usersStatusHash
+        self.usersStatusHash = {}
+
+
+
+    
+
+
+# holds info about every connected user
+class SAGEUser:
+
+    def __init__(self, username, info, machineList=[]):
+        self._username = username
+        self._info = info
+        self._machines = machineList[:]  #the list of machines this user is connected to
+
+        
+    def GetName(self):
+        return self._username
+
+    def SetName(self, name):
+        self._username = name
+
+    def GetInfo(self):
+        return self._info
+
+    def SetInfo(self, info):
+        self._info = info
+
+    def GetMachines(self):
+        return self._machines
+
+
+
+# holds info about every currently running SAGE machine
+class SAGEMachine:
+
+    def __init__(self, name, ip, port, sysIP, sysPort, machineId, alive, displayInfo=[] ):
+        self.name = name
+        self.ip = ip
+        self.port = int(port)
+        self.sysIP = sysIP
+        self.sysPort = sysPort
+        self.machineId = machineId
+        self.alive = alive
+        if not len(displayInfo) == 6:
+            displayInfo = ["?","?","?","?","?","?"]
+            
+        self.xTiles = displayInfo[0]
+        self.yTiles = displayInfo[1]
+        self.displayWidth = displayInfo[2]
+        self.displayHeight = displayInfo[3]
+        self.tileWidth = displayInfo[4]
+        self.tileHeight = displayInfo[5]
+
+    def GetName(self):
+        return self.name
+
+    def GetIP(self):
+        return self.ip
+
+    def GetPort(self):
+        return self.port
+
+    def GetSystemIP(self):
+        return self.sysIP
+
+    def GetSystemPort(self):
+        return self.sysPort
+
+    def GetId(self):
+        return self.machineId
+
+    def IsAlive(self):
+        return self.alive
+
+    def GetNumTiles(self):
+        return (self.xTiles, self.yTiles)   #returns a tuple of (x*y) number of tiles
+
+    def GetDisplaySize(self):
+        return (self.displayWidth, self.displayHeight)
+
+    def GetTileSize(self):
+        return (self.tileWidth, self.tileHeight)
+
+    def HasIP(self, ip):
+        return self.sysIP==ip or self.ip==ip
Index: trunk/src/testing/ui/connectionManager/README
===================================================================
--- trunk/src/testing/ui/connectionManager/README	(revision 4)
+++ trunk/src/testing/ui/connectionManager/README	(revision 4)
@@ -0,0 +1,138 @@
+###################################################
+		
+	   SAGE Users Server README
+
+###################################################
+(last updated on Semptember 19, 2005)	
+
+
+
+
+(1) REQUIREMENTS:
+-----------------
+
+- Python 2.3    	(www.python.org)
+
+
+
+(2) HOW TO RUN:
+---------------
+
+- python UsersServer.py [UI_PORT] [SAGE_PORT] &
+- "&" is added at the end so that the server can run in the background even when you log out (on Linux only)
+- UI_PORT is an optional parameter for specifying on which port will the server accept connections from the SAGE UIs
+- SAGE_PORT is an optional parameter for specifying on which port will the server accept connections from the fsManagers
+- NOTE: you must specify both ports at the same time (or no ports at all)
+
+
+- to run the admin tool: 
+  python admin.py [XMLRPC_SERVER_IP] [XMLRPC_SERVER_PORT]
+- the XMLRPC server is started up when the usersServer is started and is constantly running on port 8008.
+- the IP is just the IP of the machine where the usersServer is running.
+- NOTE: this tool should only be used in case something goes wrong and some sockets are still left open even though the connections should have closed.
+
+
+(3) MORE INFORMATION:
+----------------------
+
+DEFAULT PORTS USED:
+- 15555 for SAGE UI connections (i.e. user connections)
+- 15556 for SAGE connections (fsManagers)
+- 8008  for XMLRPC server (for the admin.py tool connection)
+
+LOGGING: 
+the usersServer logs all activity in a local file "log.txt", however the content of the messages is not logged. The format is very crude but it still gives an idea of what was happening if something goes wrong. Some major events such as connection/disconnection of SAGE and SAGE UI have timestamps on them.
+
+MESSAGES: 
+  ------------------------------------------------------------
+  All messages are sent in this format (as strings):
+  code
+  data
+
+  For example:
+  "2002"\n
+  "Ratko"
+ 
+  Note that every line is separated by a newline character.
+
+
+  All machines are always keyed by IP that the users should connect to to control SAGE
+  All users are always keyed by their username, hence the username checking (for duplicates)
+  All messages are of fixed size and that's currently 2048 bytes
+
+
+  The format for every message is explained below:
+
+  <<< UI  --->  SERVER >>>
+  CODE    FORMAT                 MESSAGE
+  ----------------------------------------------------------------
+  2000    username                register this user with the Users server
+          info
+          machine_ip              the machines the user is connected to
+          machine_ip
+          ...
+
+  2001    from={username}         send a chat message to one person or to all
+          to={"all" | ip}         ip = specific to users connected to a sepcific SAGE machine
+          message
+
+  2002    username                check username for duplicates
+
+  2003    username                unregister this username from the machine specified
+          machine_ip
+
+          
+  <<< SERVER  --->  UI >>>
+  CODE    FORMAT                 MESSAGE
+  ----------------------------------------------------------------
+ 
+  30000   machine_name            a status list of all the MACHINES registered with the server
+          ip
+          port
+          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+          displayInfo             in this format: "Xtiles Ytiles totalWidth totalHeight tileWidth tileHeight"
+          "!#%$"               < --- a break between different blocks of data
+          machine_name
+          ip
+          port
+          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+          displayInfo             in this format: "Xtiles Ytiles totalWidth totalHeight tileWidth tileHeight"
+          "!#%$"
+          ....
+
+
+  30001   username                receive a list of USERS that are connected and their info
+          info
+          machine_ip              the machines the user is connected to
+          machine_ip
+          "!#%$"               < --- a break between different users' info
+          username
+          info
+          machine_ip
+          "!#%$"
+          ....
+
+  30002   from={username}         receive a chat message from one person,
+          to={"all" | ip}        ip = specific to users connected to a specific SAGE machine
+          message
+
+  30003   "1" | "0"              1=username OK, 0=username already in use
+
+  31000   message                an informative message... just any string
+
+
+
+  <<< SAGE  --->  SERVER >>>
+  CODE    FORMAT                 MESSAGE
+  ----------------------------------------------------------------
+  
+  100     machine_name           "i am alive" message from SAGE
+          ip                   < --- machine ip and port that SAGE UIs should connect to
+          port
+          displayInfo             in this format: "Xtiles Ytiles totalWidth totalHeight tileWidth tileHeight"
+
+
+
+---------------------------------------------
+September 19, 2005
+Ratko Jagodic - rjagodic@evl.uic.edu
Index: trunk/src/testing/ui/connectionManager/admin.py
===================================================================
--- trunk/src/testing/ui/connectionManager/admin.py	(revision 4)
+++ trunk/src/testing/ui/connectionManager/admin.py	(revision 4)
@@ -0,0 +1,207 @@
+############################################################################
+#
+# SAGE UI Users Server - A server that handles users, fsManagers and chat for SAGE
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import wx
+import xmlrpclib
+import string
+
+server = None
+REGISTERED_USERS = 1
+CONNECTED_USERS = 2
+
+
+class MyFrame(wx.Frame):
+
+    def __init__(self):
+        wx.Frame.__init__(self, None, -1, "SAGE Server Admin", pos = (100,100), size=(450,500))
+        self.CreateControls()
+        self.usersType = REGISTERED_USERS
+        
+        self.Show(True)
+
+
+    def CreateControls(self):
+        userLabel = wx.StaticText(self, -1, "Registered Users", style=wx.ALIGN_CENTER)
+        #self.userCombo = wx.ComboBox(self, -1, "Registered Users", choices=["Registered Users", "Connected Users"], style = wx.CB_DROPDOWN | wx.CB_READONLY)
+        machineLabel = wx.StaticText(self, -1, "Registered Machines", style=wx.ALIGN_CENTER)
+        self.userList = wx.ListBox(self, -1, choices=server.GetRegisteredUsers(), style=wx.LB_SINGLE)
+        self.machineList = wx.ListBox(self, -1, choices=server.GetRegisteredMachines(), style=wx.LB_SINGLE)
+        self.disconnectUserBtn = wx.Button(self, -1, "Disconnect User")
+        self.disconnectMachineBtn = wx.Button(self, -1, "Disconnect Machine")
+        self.infoArea = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY | wx.TE_MULTILINE)
+        self.refreshBtn = wx.Button(self, -1, "Refresh")
+
+
+        # registering event handlers
+        self.userList.Bind(wx.EVT_LISTBOX, self.OnUserListSelect)
+        self.machineList.Bind(wx.EVT_LISTBOX, self.OnMachineListSelect)
+        self.disconnectUserBtn.Bind(wx.EVT_BUTTON, self.OnUserDisconnectBtn)
+        self.disconnectMachineBtn.Bind(wx.EVT_BUTTON, self.OnMachineDisconnectBtn)
+        self.refreshBtn.Bind(wx.EVT_BUTTON, self.UpdateLists)
+        #self.userCombo.Bind(wx.EVT_COMBOBOX, self.OnUserComboBox)
+        
+        # placement of the controls
+        gridSizer = wx.FlexGridSizer(3,2,0,20)
+        gridSizer.Add(userLabel, 0, wx.ALIGN_CENTER | wx.BOTTOM | wx.LEFT | wx.EXPAND, border=5)
+        gridSizer.Add(machineLabel, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=5)
+        gridSizer.Add(self.userList, 1, wx.EXPAND | wx.LEFT, border=15)
+        gridSizer.Add(self.machineList, 1, wx.EXPAND | wx.RIGHT, border=15)
+        gridSizer.Add(self.disconnectUserBtn, 0, wx.ALIGN_CENTER | wx.TOP, border=5)
+        gridSizer.Add(self.disconnectMachineBtn, 0, wx.ALIGN_CENTER | wx.TOP, border=5)
+        gridSizer.AddGrowableRow(1)
+        gridSizer.AddGrowableCol(0)
+        gridSizer.AddGrowableCol(1)
+        
+        boxSizer = wx.BoxSizer(wx.VERTICAL)
+        boxSizer.AddSpacer((10,10))
+        boxSizer.Add( gridSizer, 1, wx.ALIGN_CENTER | wx.EXPAND)
+        boxSizer.AddSpacer((10,10))
+        boxSizer.Add( self.infoArea, 1, wx.ALIGN_CENTER | wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 15)
+        boxSizer.AddSpacer((20,20))
+        boxSizer.Add( self.refreshBtn, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=10)
+        self.SetSizer(boxSizer)
+
+
+##     def OnUserComboBox(self, event):
+##         if self.userCombo.GetValue() == "Registered Users":
+##             self.usersType = REGISTERED_USERS
+##         else:
+##             self.usersType = CONNECTED_USERS
+##         self.UpdateLists()
+
+    def OnUserListSelect(self, event):
+        if event.IsSelection():
+            if self.usersType == REGISTERED_USERS:
+                machines = server.GetUserInfo( event.GetString() )
+                if machines == -1:
+                    machines = "Unable to retrieve a list of connections"
+            else:
+                machines = "This user is not even registered with the server so he\nis not connected to any machines yet"
+            info = "USER: " + event.GetString() + "\nCONNECTED TO: " + str(machines)
+            self.infoArea.Clear()
+            self.infoArea.WriteText(info)
+
+    def OnMachineListSelect(self, event):
+        if event.IsSelection():
+            (name, ip, port, machineId, alive, displayString, userList) = server.GetMachineInfo( event.GetString().split(" - ", 1)[1].strip() )
+            info = "MACHINE: " + str(event.GetString())
+            info = info + "\n---------------------------------------------------------"
+            if name == -1:
+                info = info + str("\nCould not retrieve additional information")
+            else:
+                displayInfo = displayString.split(" ", 5)
+                info = info + "\nPORT FOR SAGE UI CONNECTIONS:" + str(port)
+                if alive == 1:
+                    info = info + "\nRUNNING:\tYes"
+                else:
+                    info = info + "\nRUNNING:\tNo"
+                info = info + "\nTILE ARRANGEMENT:\t"+str(displayInfo[0])+" x "+str(displayInfo[1]) 
+                info = info + "\nDISPLAY SIZE:\t"+str(displayInfo[2])+" x "+str(displayInfo[3])+" pixels"
+                info = info + "\nTILE SIZE:\t"+str(displayInfo[4])+" x "+str(displayInfo[5])+ " pixels"
+                info = info + "\nUSERS CONNECTED:\t"+str(userList)
+            
+            self.infoArea.Clear()
+            self.infoArea.WriteText(info)
+            
+
+    def UpdateLists(self, event=None):
+        if self.usersType == REGISTERED_USERS:
+            self.userList.Set(server.GetRegisteredUsers())
+        else:
+            self.userList.Set(server.GetConnectedUsers())
+        self.machineList.Set(server.GetRegisteredMachines())
+        self.infoArea.Clear()
+
+
+    def OnUserDisconnectBtn(self, event):
+        selection = self.userList.GetStringSelection()
+        if not selection == "":
+            if self.usersType == REGISTERED_USERS:
+                server.DisconnectUser(selection)
+            else:
+                server.DisconnectConnectedUser(selection)
+            self.UpdateLists()
+
+    def OnMachineDisconnectBtn(self, event):
+        selection = self.machineList.GetStringSelection()
+        if not selection == "":
+            server.DisconnectMachine(selection.split(" - ", 1)[1].strip())
+            self.UpdateLists()
+
+
+
+class MyApp(wx.App):
+    def __init__(self):
+        wx.App.__init__(self, redirect=False)
+
+
+    def OnInit(self):
+        self.frame = MyFrame()
+        self.SetTopWindow(self.frame)
+        return True
+
+        
+
+def main(argv):
+    name, ext  = os.path.splitext(argv[1])
+    module = __import__(name)
+
+    if len(argv) == 2:
+        serverIP = "sage.sl.startap.net"
+        serverPort = 8009
+    elif len(argv) == 3:
+        print "Usage: python status.py [SERVER_IP] [SERVER_PORT]\n"
+        sys.exit(0)
+    else:
+        serverIP = argv[2]
+        serverPort = int(argv[3])
+
+    global server
+    server = xmlrpclib.ServerProxy("http://"+serverIP+":"+str(serverPort)) 
+    print "\nServer running:", server
+
+    app = MyApp()
+    app.MainLoop()
+
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
Index: trunk/src/testing/ui/connectionManager/ConnectionManager.py
===================================================================
--- trunk/src/testing/ui/connectionManager/ConnectionManager.py	(revision 4)
+++ trunk/src/testing/ui/connectionManager/ConnectionManager.py	(revision 4)
@@ -0,0 +1,1308 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# SAGE UI Users Server - A server that handles users, fsManagers and chat for SAGE
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+from threading import *
+import string, socket, os, os.path, sys, time, SimpleXMLRPCServer, xmlrpclib
+
+
+# some global constants
+
+CHUNK_SIZE = 2048          # we use fixed size messages... in bytes
+SOCKET_TIMEOUT = 1         # in seconds
+MSGLEN = CHUNK_SIZE
+SEPARATOR = '\0'         # null character for separation
+NEW_STYLE_VER = "2.82"   # below this UIs don't support system IP/port for machines
+
+USER_SERVER_PORT = 15558  # port for the server to listen for User connections
+SAGE_SERVER_PORT = 15557   # port for the server to listen for SAGE connections
+MAX_USER_CONNECTIONS = 100  # maximum number of simultaneous User connections
+MAX_SAGE_CONNECTIONS = 50  # maximum number of simultaneous SAGE connections
+
+PRINT_TO_SCREEN = False  # for debugging
+                        #(prints our messages onto the screen as well as the log file)
+
+socket.setdefaulttimeout(SOCKET_TIMEOUT)
+
+
+messageNames = {}
+messageNames[ 2000 ] = "Register"
+messageNames[ 2001 ] = "Incoming Chat Message"
+messageNames[ 2002 ] = "Check Username"
+messageNames[ 2003 ] = "Unregister from room"
+messageNames[ 30000 ] = "Machine Status"
+messageNames[ 30001 ] = "User Status"
+messageNames[ 30002 ] = "Outgoing Chat Message"
+messageNames[ 30003 ] = "Username OK"
+messageNames[ 31000 ] = "Info Message"
+
+
+
+
+#  MESSAGES:
+#
+#
+#  Notes:
+#  --------------------
+#  All messages are sent in this format (as strings):
+#  code
+#  data
+#
+#  For example:
+#  "2002"
+#  "Ratko"
+#
+#
+#  All machines are always keyed by machineId that the users should connect to to control SAGE
+#
+#
+#  <<< UI  --->  SERVER >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+#  2000    username                register this user with the Users server
+#          info
+#          machine_id              the machines the user is connected to
+#
+#  2001    from={username}         send a chat message to one person or to all
+#          to={"all" | id}         id = specific to users connected to a sepcific SAGE machine
+#          message
+#
+#  2002    username                check username for duplicates
+#
+#  2003    username                unregister this username from the machine specified
+#          machine_id
+#
+#          
+#  <<< SERVER  --->  UI >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+# 
+#  30000   machine_name            a status list of all the MACHINES registered with the server
+#          ip
+#          port
+#          machineId
+#          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+#          displayInfo             in this format: "Xtiles Ytiles tileWidth tileHeight"
+#          systemIP systemPort     older UIs don't support this so not sent to them
+#          "\x00"               < --- a break between different blocks of data
+#          machine_name
+#          ip
+#          port
+#          machineId
+#          alive={"1" | "0"}       if the machine is alive, send 1, otherwise send 0
+#          displayInfo             in this format: "Xtiles Ytiles tileWidth tileHeight"
+#          systemIP systemPort     older UIs don't support this so not sent to them
+#          "\x00"
+#          ....
+#
+#
+#  30001   username                receive a list of USERS that are connected and their info
+#          info
+#          machine_id              the machines the user is connected to
+#          machine_id
+#          "\x00"               < --- a break between different users' info
+#          username
+#          info
+#          machine_id
+#          "\x00"
+#          ....
+#
+#  30002   from={username}         receive a chat message from one person,
+#          to={"all" | id}        id = specific to users connected to a specific SAGE machine
+#          message
+#
+#  30003   "1" | "0"              1=username OK, 0=username already in use
+#
+#  31000   message                an informative message... just any string
+#
+#
+#
+#  <<< SAGE  --->  SERVER >>>
+#  CODE    FORMAT                 MESSAGE
+#  ----------------------------------------------------------------
+#  
+#  100     machine_name version   "i am alive" message from SAGE
+#          pubIP pubPort          < --- machine ip and port that SAGE UIs should connect to
+#          sysIP sysPort          < --- machine ip and port that the apps should use for streaming
+#          displayInfo
+
+
+
+# log the actions in a file
+os.chdir(sys.path[0])  #change to the folder where the script is running
+logFile = open("/tmp/log.txt", "a")
+logFileLock = RLock()  #since multiple threads are writing to the same file
+
+def WriteToFile(text):
+    logFileLock.acquire()
+    logFile.write( text )
+    if PRINT_TO_SCREEN:
+        print text
+    logFile.flush()  #flush the buffer to a file (especially needed if running as a daemon)
+    logFileLock.release()
+
+
+# record some stats to a file
+statsFile = open("/tmp/stats.txt", "a")
+statsFileLock = RLock()
+
+def WriteStats(text):
+    statsFileLock.acquire()
+    statsFile.write( text )
+    if PRINT_TO_SCREEN:
+        print text
+    statsFile.flush()  #flush the buffer to a file (especially needed if running as a daemon)
+    statsFileLock.release()
+
+
+
+
+############################################################################
+#
+#  CLASS: SingleMachine
+#  
+#  DESCRIPTION: This is basically a thread that deals with the connection
+#               to ONLY ONE SAGE. It's created by the Server class upon
+#               connection from sage and it receives a clientsocket that
+#               was internally created by the Server. It then uses this
+#               socket for all the communication. One of these exists for
+#               every sage that is connected to this Server and the Server class
+#               keeps these SingleMachine objects in a list.
+#
+#  DATE:        May, 2005
+#
+############################################################################
+
+class SingleMachine(Thread):
+    
+    def __init__(self, socket, address, server):
+        Thread.__init__(self)
+        self.socket = socket
+        self.socket.settimeout(SOCKET_TIMEOUT)
+        self.server = server
+        self.threadKilled = False
+        self.name = ""
+        self.ip = address[0]  # these 2 are use for control communication
+        self.port = ""
+        self.systemIP = ""   # these 2 are used for streaming the data
+        self.systemPort = ""
+        self.sageVersion = None   #version of SAGE
+        self.oldStyleSAGE = False
+        self.machineId = self.ip+":"+str(self.port)
+        self.displayInfo = ""
+        self.receivedRegisterMessage = False   # in case SAGE connects but never registers the thread will be running forever
+        self.lastReportTime = None  #this will be the time of the last report from fsManager
+        self.maxReportInterval = 6.0   #allow up to 6 seconds between the sage reports and then consider the fsManager disconnected
+
+        t = Timer(10, self.WaitForRegisterMessage)
+        t.start()
+
+
+    def WaitForRegisterMessage(self):
+        if not self.receivedRegisterMessage:
+            self.Stop(False)
+
+
+        # stops the thread, breaks the connection and unregisters the machine from this server
+    def Stop(self, unregister=True):
+        # record the stats
+        stats = "\nSAGE disconnected: "+self.name+" "+str(self.machineId)+" "+str(self.displayInfo)+" "+str(time.asctime())
+        WriteStats(stats)
+        
+        WriteToFile( "\n*** Connection closed with SAGE: \"" + self.name + "\"  <" + time.asctime() + ">")
+        self.threadKilled = True
+        if unregister:
+            self.server.UnregisterMachine(self.GetId())
+        self.socket.close()
+    
+
+    #-----------------------------------------------
+    # data access methods
+    #-----------------------------------------------
+
+    def GetIP(self):
+        return self.ip
+
+    def GetName(self):
+        return self.name
+
+    def GetSystemIP(self):
+        return self.systemIP
+
+    def GetSystemPort(self):
+        return self.systemPort
+
+    def GetPort(self):
+        return self.port
+    
+    def IsAlive(self):
+        return not self.threadKilled
+
+    def GetDisplayInfo(self):
+        return self.displayInfo
+
+    def GetId(self):
+        return self.machineId
+
+
+#-------------------------------------------------------
+#  RECEIVING
+#-------------------------------------------------------
+
+        # runs in a thread... started in the Server class
+    def run(self):        
+        while not self.threadKilled:
+            try:              
+                # this first receive will receive the length of the data
+                cleanMsg = self.GetMessage()
+                if not cleanMsg:
+                    break  #connection was closed
+                msgHeader = string.split( cleanMsg, "\n", 1 )
+                if len( msgHeader ) > 0:
+                    code = int(msgHeader[0])
+                    data = msgHeader[1]
+                else:
+                    WriteToFile( "\n ERROR: message could not be split correctly into (code, data)")
+                    break
+
+                
+                # call the appropriate function to handle the incoming data
+                if code == 100:
+                    self.OnRegisterMachineMessage(data)
+                	    
+            
+            except socket.timeout:
+                # if the fsManager hasn't reported in a while, assume it's dead and quit
+                if self.lastReportTime:
+                    if time.time() - self.lastReportTime > self.maxReportInterval:
+                        WriteToFile( "\nERROR: Time expired with SAGE connection " + self.name)
+                        self.Stop()
+                continue
+            except socket.error:
+                WriteToFile( "\nERROR: UsersServer: socket error in connection with SAGE: " + self.name)
+                self.Stop()
+                break
+       
+        # outside of while loop
+        self.threadKilled = True
+        WriteToFile("\nThread from "+self.name +" died")
+		
+			    
+    def GetMessage(self, MSG_SIZE=CHUNK_SIZE):
+        # this first receive will receive the length of the data
+        msg = self.socket.recv(MSG_SIZE)
+        if len( msg ) < 2:
+            WriteToFile("\nERROR: message length < 2. Closing the connection with SAGE "+self.name)
+            self.Stop()   #connection was closed
+            return False
+        
+
+        # since recv is not guaranteed to receive exactly CHUNK_SIZE bytes
+        # so keep receiving until it gets the whole chunk
+        while len( msg ) < MSG_SIZE:
+            msg = msg + self.socket.recv(MSG_SIZE - len( msg))
+
+
+        # strip all the empty spaces from the message
+        cleanMsg = self.CleanBuffer( msg )
+        cleanMsg = string.strip( cleanMsg )
+        return cleanMsg
+        
+    
+    
+    # converts all non-printable characters from the buffer to white spaces
+    # (so that they can be removed using string.strip() function)
+    def CleanBuffer( self, stBuffer ):
+        stNewBuffer = ""
+            
+        for ch in stBuffer:
+            if ( ch in string.printable ):
+                stNewBuffer = stNewBuffer + ch
+            else:
+                stNewBuffer = stNewBuffer + " "
+			    
+        return stNewBuffer
+
+
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS
+#-------------------------------------------------------
+
+    def OnRegisterMachineMessage(self, data):
+        """ there are two different fsManagers so handle them differently """
+        if self.receivedRegisterMessage:
+            # record the time when it was reported
+            self.lastReportTime = time.time()
+            return
+        
+        self.receivedRegisterMessage = True
+        tokens = string.split(data, "\n", 3)
+        if len(tokens[0].split()) == 1: # based on this we will know which fsManger is this
+            self.name = tokens[0]
+            self.ip = tokens[1] 
+            self.port = int(tokens[2])
+            self.systemIP = self.ip   #make them the same as public if not given
+            self.systemPort = self.port
+            self.oldStyleSAGE = True
+        else:  # new style SAGE includes the system port/ip as well as the sage version
+            (self.name, self.sageVersion) = tokens[0].split()
+            sys = tokens[1].split()
+            self.systemIP = sys[0].strip()
+            self.systemPort = int(sys[1].strip())
+
+            pub = tokens[2].split()
+            self.ip = pub[0].strip()
+            self.port = int(pub[1].strip())
+            
+        self.machineId = self.ip+":"+str(self.port)
+        self.displayInfo = tokens[3]
+        self.server.RegisterMachine(self)
+
+        # record the stats
+        stats = "\nSAGE connected: "+self.name+" "+str(self.machineId)+" "+str(self.displayInfo)+" "+str(time.asctime())
+        WriteStats(stats)
+        
+
+
+
+
+
+
+############################################################################
+#
+#  CLASS: SingleUser
+#  
+#  DESCRIPTION: This is basically a thread that deals with the connection
+#               to ONLY ONE SAGE UI. It's created by the Server class upon
+#               connection from a user and it receives a clientsocket that
+#               was internally created by the Server. It then uses this
+#               socket for all the communication. One of these exists for
+#               every user that is connected to this Server and the Server class
+#               keeps these SingleUser objects in a list.
+#
+#  DATE:        May, 2005
+#
+############################################################################
+
+class SingleUser(Thread):
+    
+    def __init__(self, socket, address, server):
+        Thread.__init__(self)
+        self.socket = socket
+        self.socket.settimeout(SOCKET_TIMEOUT)
+        self.server = server
+        self.threadKilled = False
+        self.username = ""
+        self.info = ""
+        self.machineList = []   # the SAGE machines that this user is connected to ( a list of machineIds )
+        self.ip = address[0]
+        self.registered = False
+        self.ui_version = "2.0"  # default
+        self.newStyle = False
+        
+        self.messageCallback = {}
+        self.messageCallback[ 2000 ] = self.OnRegister
+        self.messageCallback[ 2001 ] = self.OnChatMessage
+        self.messageCallback[ 2002 ] = self.OnCheckUsername
+        self.messageCallback[ 2003 ] = self.OnUnregisterUser
+
+        # send the first reply message with machine status
+        self.server.OnConnectUser(self)
+        self.stopped = False
+
+
+    def Stop(self, unregister=True):
+        self.stopped = True
+        # record the stats
+        stats = "\nUser disconnected: "+self.GetName()+" "+str(self.ip)+" "+str(time.asctime())
+        WriteStats(stats)
+        self.threadKilled = True
+        WriteToFile( "\n*** Connection closed with user: \"" + self.username + "\"  <" + time.asctime() + ">")
+        if unregister and self.registered:
+            self.server.UnregisterUser(self, self.username)
+        self.server.OnDisconnectUser(self)
+        #self.threadKilled = True
+        self.socket.close()
+    
+
+    def GetInfo(self):
+        return self.info
+
+    def GetName(self):
+        return self.username
+
+    def GetMachines(self):
+        return self.machineList
+
+    def IsNewStyle(self):
+        return self.newStyle
+
+    
+#-------------------------------------------------------
+#  RECEIVING
+#-------------------------------------------------------
+
+        # runs in a thread... started in the Server class
+    def run(self):        
+        while not self.threadKilled:
+            try:
+                # this first receive will receive the length of the data
+                cleanMsg = self.GetMessage()
+                if not cleanMsg:
+                    break  #connection was closed
+                msgHeader = string.split( cleanMsg, "\n", 1 )
+                if len( msgHeader ) > 0:
+                    code = int(msgHeader[0])
+                    data = msgHeader[1]
+                else:
+                    WriteToFile( "\n ERROR: message could not be split correctly into (code, data)")
+                    break
+
+                # print what we received
+                if messageNames.has_key(code):
+                    WriteToFile( "RECEIVED: \"" + messageNames[code] + "\" from " + self.username + "   (" + str(self.ip) + ")")
+                
+                # call the appropriate function to handle the incoming data
+                if self.messageCallback.has_key( code ):
+                    self.messageCallback[ code ](data)
+                else:
+                    WriteToFile("\nERROR: Message code " + str(code) + " unrecognized")
+                	    
+            
+            except socket.timeout:
+                continue
+            except socket.error:
+                WriteToFile( "\nERROR: UsersServer: socket error in connection with: " + self.username)
+                self.Stop()
+                break
+ 
+        if self.stopped == False:
+            WriteToFile("Stopping the thread")
+            self.Stop()
+        WriteToFile("Thread from " + self.username + " has died")
+			    
+    def GetMessage(self, clean=True, MSG_SIZE=CHUNK_SIZE):
+        # this first receive will receive the length of the data
+        msg = self.socket.recv(MSG_SIZE)
+        if len( msg ) < 2:
+            self.Stop()   #connection was closed
+            return False
+		    
+
+        # since recv is not guaranteed to receive exactly CHUNK_SIZE bytes
+        # so keep receiving until it gets the whole chunk
+        while len( msg ) < MSG_SIZE:
+            msg = msg + self.socket.recv(MSG_SIZE - len( msg))
+
+        if clean:
+            # strip all the empty spaces from the message
+            cleanMsg = self.CleanBuffer( msg )
+            cleanMsg = string.strip( cleanMsg )
+            return cleanMsg
+        else:
+            return msg
+
+    
+    
+    # converts all non-printable characters from the buffer to white spaces
+    # (so that they can be removed using string.strip() function)
+    def CleanBuffer( self, stBuffer ):
+            stNewBuffer = ""
+
+            for ch in stBuffer:
+                if ch == '\0':   #this is our message separator so handle it separately
+                    stNewBuffer += ch
+                elif ch in string.printable:
+                    stNewBuffer += ch
+                else:
+                    stNewBuffer += " "
+            return stNewBuffer
+    
+
+
+#-------------------------------------------------------
+#  SENDING
+#-------------------------------------------------------
+
+        # make the message with the right code and send it
+    def MakeMsg(self, code, data):
+        msg = '%8s\n%s' %(code,data)
+        WriteToFile( "SEND: \"" + messageNames[code] + "\" to " + self.username)
+        msg = msg + ' ' * (MSGLEN-len(msg))
+        self.Send(msg)
+
+        # just performs the send operation
+    def Send(self, msg):
+        try:
+            self.socket.send(msg)
+        except socket.error:
+            WriteToFile( "\nERROR: UsersServer: Could not send message: socket error with: "+self.username )
+            self.socket.close()
+            #self.Stop()
+
+            # record the stats
+            stats = "\nUser disconnected: "+self.GetName()+" "+str(self.ip)+" "+str(time.asctime())
+            WriteStats(stats)
+            #self.Stop()
+            # the run() method will catch this as well and it will handle the cleanup
+
+        # these functions are called by the main Server class in order to send
+        # messages to all the users via their own sockets used in this SingleUser class
+    def SendChatMessage(self, message):
+        self.MakeMsg(30002, message)
+
+
+        # form a message and send the users status
+    def SendUsersStatusMessage(self, statusList):
+        message = ""
+
+        # make the message out of the machine status list
+        for userInfo in statusList:
+            if message != "":  message += SEPARATOR   #add the separator before adding each new machine info    
+            for infoItem in userInfo:
+                message += str(infoItem) + "\n"
+
+        self.MakeMsg(30001, message)
+
+
+        # form a message and send the machine status
+    def SendMachinesStatusMessage(self, statusList):
+        message = ""
+
+        # make the message out of the machine status list
+        for machineInfo in statusList:
+            if message != "":  message += SEPARATOR   #add the separator before adding each new machine info    
+            for infoItem in machineInfo:
+                message += str(infoItem) + "\n"
+            
+        self.MakeMsg(30000, message)
+        
+
+    def SendUsernameOKMessage(self, usernameOK):
+        self.MakeMsg( 30003, str(int(usernameOK)) )
+
+
+        
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS
+#-------------------------------------------------------
+
+    def OnRegister(self, data):
+        tokens = string.split(data, "\n")
+        self.username = tokens[0]
+        self.info = tokens[1]
+        machineId = tokens[2]
+        if not machineId in self.machineList:
+            self.machineList.append(machineId)
+
+        # record the stats
+        stats = "\nUser registered: "+self.GetName()+" "+str(self.ip)+" "+str(machineId)+" "+str(time.asctime())
+        WriteStats(stats)
+
+        self.server.RegisterUser(self, self.username)
+
+        # if the version of the connected UI handles system ip/port
+        # for each machine, send it after the registration message
+        if self.IsNewStyle():
+            status = self.server.MakeNewMachinesStatusList()
+            self.SendMachinesStatusMessage(status)
+        
+
+    def OnChatMessage(self, data):
+        tokens = string.split(data, "\n", 2)
+        if tokens[1] == "all":
+            toRoom = "all"
+        else:
+            toRoom = tokens[1]
+        self.server.ForwardChatMessage(self, toRoom, data)
+        
+
+    def OnCheckUsername(self, data):
+        tokens = string.split(data, "\n")
+        if len(tokens) > 1:  # sageui v2.82+ sends a version number
+            self.ui_version == tokens[1].strip()
+            self.newStyle = True
+        self.SendUsernameOKMessage(self.server.IsUsernameOK(self, tokens[0]) )
+
+
+    def OnUnregisterUser(self, data):
+        tokens = string.split(data, "\n")
+        username = tokens[0]
+        machineId = tokens[1]
+        if machineId in self.GetMachines():
+            self.machineList.remove(machineId)
+            # record the stats
+            stats = "User unregistered: "+self.GetName()+" "+str(self.ip)+" "+str(machineId)+" "+str(time.asctime())
+            WriteStats(stats)
+            self.server.UpdateUsers()
+        
+    
+
+
+############################################################################
+#
+#  CLASS: SingleLauncher
+#  
+#  DESCRIPTION: This class describes one appLauncher connection for use by
+#               SAGE UIs. It mainly contains a list of applications and their configs
+#
+#
+############################################################################
+
+class SingleLauncher:
+    def __init__(self, launcherId, name, ip, port, appList):
+        self.port = port
+        self.appList = appList
+        self.ip = ip
+        self.launcherId = launcherId
+        self.name = name
+        self.oldT = time.time()
+        self.maxReportTime = 10  #allow maximum 8 seconds between reports
+
+    def getId(self):
+        return self.launcherId
+
+    def getIP(self):
+        return self.ip
+
+    def getAppList(self):
+        return self.appList
+
+    def setAppList(self, appList):
+        self.appList = appList
+
+    def getPort(self):
+        return self.port
+
+    def getName(self):
+        return self.name
+    
+    def isAlive(self):
+        if (time.time() - self.oldT) < self.maxReportTime:
+            return True
+        else:
+            return False
+
+    def report(self):
+        self.oldT = time.time()
+
+
+
+############################################################################
+#
+#  CLASS: Server
+#  
+#  DESCRIPTION: This server should run as a deamon and constantly listen for
+#               connections on a certain port. Once it accepts a connection
+#               it spawns a thread (SingleUser) that takes care of listening for the
+#               incoming messages and sending messages on that socket.
+#               It also relays all the incoming messages to their corresponding
+#               recepients. To do that it keeps track of all the users connected
+#               in a list registeredUsers[]. It also listens for connections
+#               from fsManagers and keeps track of them in connectedMachines[] (
+#               a hash of singleMachines).
+#
+#  DATE:        May, 2005
+#
+############################################################################
+
+class Server:
+    def __init__(self):
+        self.serverRunning = True
+
+        # start the XMLRPC server in a thread
+        xmlrpcServer = Thread(target=self.StartXMLRPCServer)
+        xmlrpcServer.start()
+
+        # start the two servers listening on separate ports
+        machinesServer = Thread(target=self.StartMachinesServer)
+        machinesServer.start()
+
+        try:
+            self.StartUsersServer()  #start this one in the main thread so that we can capture
+                                 #keystrokes such as Ctrl-C
+        except KeyboardInterrupt:
+            WriteToFile ("\n******  Shutting down the server  *******")
+            self.serverRunning = False
+            self.CloseAllUserConnections()
+            self.CloseAllSAGEConnections()
+            self.xmlrpc.server_close()
+            #logFile.close()
+
+
+
+#------------------------------------------------------------------------------
+#  XML-RPC STUFF  -  FOR REMOTE ADMINISTRATION, APPLAUNCHER AND SAGE UI PROXY
+#------------------------------------------------------------------------------
+
+    def StartXMLRPCServer(self):
+        self.registeredLaunchers = {}  #key=launcherID, value=SingleLauncher object
+        
+        # start the XML-RPC server
+        self.xmlrpc = XMLRPCServer(("", 8009))
+
+        # users
+        self.xmlrpc.register_function(self.GetRegisteredUsers)
+        self.xmlrpc.register_function(self.GetUserInfo)
+        self.xmlrpc.register_function(self.DisconnectUser)
+
+        # machines
+        self.xmlrpc.register_function(self.GetMachineInfo)
+        self.xmlrpc.register_function(self.GetRegisteredMachines)
+        self.xmlrpc.register_function(self.DisconnectMachine)
+
+        # appLauncher
+        self.xmlrpc.register_function(self.ReportLauncher)
+        self.xmlrpc.register_function(self.GetRegisteredLaunchers)
+        self.xmlrpc.register_function(self.UnregisterLauncher)
+
+        WriteToFile ("Starting the XML-RPC Server...\n")
+        while self.serverRunning:
+            try:
+                self.xmlrpc.handle_request()  #accept and process xmlrpc requests
+                self.__checkLaunchers()   #check to see whether every launcher is still alive
+            except socket.timeout:
+                continue
+            except:
+                WriteToFile( "\n=====> XMLRPC Server ERROR:" )
+                WriteToFile( "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) )
+                continue
+
+
+
+        ### loops through all the app launchers and checks whether they are still alive
+        ### the minimum frequency of checks is defined by the timeout set int XMLRPCServer constructor
+    def __checkLaunchers(self):
+        for l in self.registeredLaunchers.values():
+            if not l.isAlive():
+                WriteToFile("Launcher "+l.getName()+"("+l.getId()+") unregistered")
+                self.UnregisterLauncher(l.getId())
+                
+            
+        ### called by each appLauncher in order to register with the server
+    def ReportLauncher(self, launcherName, launcherIP, launcherPort, appList):
+        launcherId = launcherIP+":"+str(launcherPort)
+        if launcherId in self.registeredLaunchers:
+            self.registeredLaunchers[launcherId].report()  # launcher already exists so just update its last report time
+            self.registeredLaunchers[launcherId].setAppList(appList)
+        else:
+            l = SingleLauncher(launcherId, launcherName, launcherIP, launcherPort, appList)
+            WriteToFile("Launcher "+l.getName()+"("+l.getId()+") registered")
+            self.registeredLaunchers[launcherId] = l
+        return launcherId
+
+
+        ### removes the appLauncher from a list of registered ones
+    def UnregisterLauncher(self, launcherId):
+        if launcherId in self.registeredLaunchers:
+            del self.registeredLaunchers[ launcherId ] 
+        return 1
+    
+
+        ### return a hash of all the app launchers running
+        ### key= "name:launcherId" , value=appList  (that's another hash of appNames and their configs)
+    def GetRegisteredLaunchers(self):
+        tempHash = {}
+        for l in self.registeredLaunchers.itervalues():
+            tempHash[ l.getName()+":"+l.getId() ] = l.getAppList()
+        return tempHash
+    
+
+
+        ### return a list of currently registered users and machines
+    def GetRegisteredUsers(self):
+        self.registeredUsersLock.acquire()
+        users = self.registeredUsers.keys()
+        self.registeredUsersLock.release()
+        return users
+
+    def GetRegisteredMachines(self):
+        self.connectedMachinesLock.acquire()
+        machineList = []
+        for machineId, singleMachine in self.connectedMachines.iteritems():
+            machineList.append(singleMachine.GetName() + " - " + str(machineId))
+        self.connectedMachinesLock.release()
+        return machineList
+
+##     def GetConnectedUsers(self):
+##         self.connectedUsersLock.acquire()
+##         users = []
+##         for user in self.connectedUsers:
+##             users.append(user.GetName())
+##         self.connectedUsersLock.release()
+##         return users
+
+        ### return user and machine info
+    def GetUserInfo(self, username):
+        self.registeredUsersLock.acquire()
+        if self.registeredUsers.has_key(username):
+            singleUser = self.registeredUsers[username]
+            machineList = []
+            self.connectedMachinesLock.acquire()
+            for machineId in singleUser.GetMachines():
+                if self.connectedMachines.has_key(machineId):
+                    machineList.append(self.connectedMachines[machineId].GetName())
+            self.connectedMachinesLock.release()
+            self.registeredUsersLock.release()
+            return machineList  #singleUser.GetMachines()
+        else:
+            self.registeredUsersLock.release()
+            return -1
+
+    def GetMachineInfo(self, machineId):
+        self.connectedMachinesLock.acquire()
+        if self.connectedMachines.has_key(machineId):
+            m = self.connectedMachines[machineId]
+            self.connectedMachinesLock.release()
+
+            #now make a list of all the users that are connected to this machine
+            self.registeredUsersLock.acquire()
+            userList = []
+            for name, singleUser in self.registeredUsers.iteritems():
+                if machineId in singleUser.GetMachines():
+                    userList.append(name)
+            self.registeredUsersLock.release()
+            return (m.GetName(), m.GetIP(), m.GetPort(), m.GetId(), m.IsAlive(), m.GetDisplayInfo(), userList)
+        else:
+            self.connectedMachinesLock.release()
+            return (-1,-1,-1,-1,-1,-1,-1)
+
+
+        ### allow the user to close individual connections with SAGE and users
+    def DisconnectUser(self, username):
+        self.registeredUsersLock.acquire()
+        if self.registeredUsers.has_key(username):
+            singleUser = self.registeredUsers[username]
+            singleUser.Stop()
+        self.registeredUsersLock.release()
+        return True
+
+
+    def DisconnectMachine(self, machineId):
+        self.connectedMachinesLock.acquire()
+        if self.connectedMachines.has_key(machineId):
+            singleMachine = self.connectedMachines[machineId]
+            singleMachine.Stop()
+        self.connectedMachinesLock.release()
+        return True
+
+
+
+#----------------------------------------------------------------------------------------
+#   THE SERVERS RUNNING IN THREADS RECEIVING CONNECTIONS FROM USERS AND SAGES
+#----------------------------------------------------------------------------------------
+
+
+        # runs in the main thread
+    def StartUsersServer(self):
+        self.registeredUsers = {}   # a hash of SingleUsers for every registered user  (keyed by username)
+        self.registeredUsersLock = RLock()  #used to lock the access to self.registeredUsers hash
+
+        self.connectedUsers = []    # this includes all the users that are connected to the server
+        self.connectedUsersLock = RLock()  # but not necessarily registered with it. (so registeredUsers is a subset of this)
+
+        self.pendingUsernames = []   # usernames that have been checked with the server but not yet registered
+        self.pendingUsernamesLock = RLock()
+        
+        # create the server socket and accept a connection
+        serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        if serversocket is None:
+                WriteToFile( "\n\nERROR: Server socket could not be created... exiting" )
+                return False
+        serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        serversocket.bind(("", USER_SERVER_PORT))
+        serversocket.listen(MAX_USER_CONNECTIONS)
+        serversocket.settimeout(SOCKET_TIMEOUT)
+
+        WriteToFile( "Users Server waiting for connections on port " +  str(USER_SERVER_PORT) +  "...\n" )
+        while self.serverRunning:
+            try:
+                (clientsocket, address) = serversocket.accept()
+            except socket.timeout:
+                continue
+            except:
+                WriteToFile( "\n\nUsers Server Not accepting any more connections... exiting  <" + time.asctime() + ">\n" )
+                self.CloseAllUserConnections()
+                self.serverRunning = False
+                break
+
+            WriteToFile( "\n*** Connection accepted from " + str(address[0]) + " <" + time.asctime() + ">" )
+            # create a SingleUser instance and start the receiver in a thread
+            t = SingleUser(clientsocket, address, self)
+            self.connectedUsersLock.acquire()
+            self.connectedUsers.append(t)   #add the user to the list of all connected users
+            self.connectedUsersLock.release()
+            t.start()
+        WriteToFile("\nUsers Server exited")
+        
+
+        # runs in a thread
+    def StartMachinesServer(self):
+        self.connectedMachines = {}   # a hash of SingleMachines for every connected SAGE (keyed by id)            
+        self.connectedMachinesLock = RLock()
+
+                # create the server socket and accept a connection
+        serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        if serversocket is None:
+                WriteToFile( "\n\nERROR: SAGE Server socket could not be created... exiting" )
+                return False
+        serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        serversocket.bind(("", SAGE_SERVER_PORT))
+        serversocket.listen(MAX_SAGE_CONNECTIONS)  
+        serversocket.settimeout(SOCKET_TIMEOUT)
+        
+        WriteToFile( "SAGE Server waiting for connections on port " +  str(SAGE_SERVER_PORT) +  "...\n" )
+        while self.serverRunning:
+            try:
+                (clientsocket, address) = serversocket.accept()
+            except socket.timeout:
+                continue
+            except:
+                WriteToFile( "\n\nSAGE Server Not accepting any more connections... exiting  <" + time.asctime() + ">\n" )
+                self.CloseAllSAGEConnections()
+                self.serverRunning = False
+                break
+
+            WriteToFile( "\n*** SAGE Connection accepted from " + str(address[0]) + " <" + time.asctime() + ">" )
+            # create a SingleMachine instance and start the receiver in a thread
+            t = SingleMachine(clientsocket, address, self)
+            t.start()
+        WriteToFile("\nSAGE Server exited")
+        self.xmlrpc.server_close()
+
+
+    def CloseAllUserConnections(self):
+        for singleUser in self.registeredUsers.itervalues():
+            singleUser.Stop(unregister=False) #we dont want to unregister because the server is closing anyway
+
+    def CloseAllSAGEConnections(self):
+        for singleMachine in self.connectedMachines.itervalues():
+            singleMachine.Stop(unregister=False) #we dont want to unregister because the server is closing anyway
+            
+
+
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS - USERS
+#-------------------------------------------------------
+
+        # when the user connects, we need to send him the list of all the SAGE
+        # machines registered with this server
+    def OnConnectUser(self, singleUser):
+        self.connectedMachinesLock.acquire()
+        singleUser.SendMachinesStatusMessage(self.MakeMachinesStatusList())
+        self.connectedMachinesLock.release()
+
+
+        # if the user connected but never registered, we still have to remove him from this list
+    def OnDisconnectUser(self, singleUser):
+
+        # remove from the pending usernames if connected
+        self.pendingUsernamesLock.acquire()
+        if singleUser.GetName() in self.pendingUsernames:
+            self.pendingUsernames.remove(singleUser.GetName())
+        self.pendingUsernamesLock.release()
+
+        # remove from connected users list
+        self.connectedUsersLock.acquire()
+        if singleUser in self.connectedUsers:
+            self.connectedUsers.remove(singleUser)
+        self.connectedUsersLock.release()
+        
+
+        # adds the new user keyed by its name and makes the new status list
+        # returns: true if successful, false otherwise (if username already exists)
+    def RegisterUser(self, singleUser, username):
+        self.registeredUsersLock.acquire()
+        if not self.registeredUsers.has_key(username) or self.registeredUsers[username].ip == singleUser.ip:
+            self.registeredUsers[ username ] = singleUser  # add the user to the list
+            singleUser.registered = True
+            
+        # remove from the list of pending usernames
+        self.pendingUsernamesLock.acquire()
+        if username in self.pendingUsernames:
+            self.pendingUsernames.remove(username)
+        self.pendingUsernamesLock.release()
+
+        # update the status of other users
+        self.UpdateUsers()
+        self.registeredUsersLock.release()
+
+
+
+    def UnregisterUser(self, singleUser, username):
+        
+        # remove the user from the list of all the connected users
+        self.connectedUsersLock.acquire()
+        if singleUser in self.connectedUsers:
+            self.connectedUsers.remove(singleUser)
+            WriteToFile("removed "+username+" from connectedUsers")
+        self.connectedUsersLock.release()
+
+        # now remove him from the list of registered users
+        self.registeredUsersLock.acquire()
+        if self.registeredUsers.has_key( username ):
+            del self.registeredUsers[ username ]
+            self.UpdateUsers()
+            WriteToFile("removed "+username+" from registeredUsers")
+        self.registeredUsersLock.release()
+
+        # now, check all the rooms that the user was connected to and see if any
+        # of them are empty now that the user has left... if there are empty rooms,
+        # close them
+        emptyRooms = False
+        self.connectedMachinesLock.acquire()
+        for room in self.connectedMachines.keys()[:]:  #loop through all the machines just in case there are some daemons
+            if self.connectedMachines.has_key(room) and (not self.connectedMachines[room].IsAlive()) and self.IsRoomEmpty(room):
+                emptyRooms = True
+                del self.connectedMachines[room]
+                WriteToFile("closed the room "+room)
+        if emptyRooms:
+            self.UpdateMachines()
+        self.connectedMachinesLock.release()
+
+
+        # updates all the users with the new status (based on self.registeredUsers)
+    def UpdateUsers(self):
+        self.registeredUsersLock.acquire()
+        statusList = self.MakeUsersStatusList()
+        for username, singleUser in self.registeredUsers.iteritems():
+            if len(singleUser.GetMachines()) > 0:
+                singleUser.SendUsersStatusMessage(statusList)
+        self.registeredUsersLock.release()
+
+        
+        # forwads the chat message either to all the chat rooms or a specific one
+    def ForwardChatMessage(self, sender, toRoom, message):
+        self.registeredUsersLock.acquire()
+        for name, singleUser in self.registeredUsers.iteritems():
+            singleUser.SendChatMessage(message)
+        self.registeredUsersLock.release()
+
+
+        # checks for duplicates in usernames
+    def IsUsernameOK(self, singleUser, username):
+        self.registeredUsersLock.acquire()
+        self.pendingUsernamesLock.acquire()
+        if username in self.registeredUsers:   # username already exists
+            if self.registeredUsers[username].ip == singleUser.ip:  # its the same user reconnecting so it's OK
+                usernameTaken = False
+            else:
+                usernameTaken = True
+        elif username in self.pendingUsernames:
+            usernameTaken = True
+        else:
+            usernameTaken = False
+            
+        if not usernameTaken:
+            self.pendingUsernames.append(username)
+            t = Timer(2, self.ExpireUsername, [username])
+            t.start()
+        self.pendingUsernamesLock.release()
+        self.registeredUsersLock.release()
+        return not usernameTaken
+
+
+    def ExpireUsername(self, username):
+        # remove from the list of pending usernames
+        self.pendingUsernamesLock.acquire()
+        if username in self.pendingUsernames:
+            self.pendingUsernames.remove(username)
+        self.pendingUsernamesLock.release()
+        
+    
+        #make the status list consisting of name,info,machine,name,info,machine...
+    def MakeUsersStatusList(self):
+        statusList = []   
+        keys = self.registeredUsers.keys()
+        keys.sort()
+        for username in keys:
+            user = self.registeredUsers[username]
+            tempList = []
+            tempList.append(username)
+            tempList.append(user.GetInfo())
+            for machine in user.GetMachines():
+                tempList.append(machine)
+            statusList.append(tempList)
+        return statusList
+
+
+
+#-------------------------------------------------------
+#  MESSAGE CALLBACKS - MACHINES
+#-------------------------------------------------------
+
+        #registers SAGE with the server so that it's visible to the users
+    def RegisterMachine(self, singleMachine):
+        machineId = singleMachine.GetId()
+        self.connectedMachinesLock.acquire()
+        if not self.connectedMachines.has_key( machineId ):
+            self.connectedMachines[ machineId ] = singleMachine
+            self.UpdateMachines()  #update all the users with the new machine status
+        else:  #the old singleMachine was still preserved since there were some users in it still
+            WriteToFile("\n* The machine "+str(machineId)+" already exists so trying to close the connection with the previous one")
+            self.connectedMachines[ machineId ].Stop(False)  # this is a preventative measure just in case it was a zombie
+            del self.connectedMachines[ machineId ]  #delete the old one and save the new one
+            self.connectedMachines[ machineId ] = singleMachine
+            self.UpdateMachines()
+        self.connectedMachinesLock.release()
+
+
+        # updates all the users with the new machine status (based on self.connectedMachines)
+    def UpdateMachines(self):
+        self.connectedUsersLock.acquire()
+        statusList = self.MakeMachinesStatusList()
+        newStatusList = self.MakeNewMachinesStatusList()
+        for singleUser in self.connectedUsers:
+            if singleUser.IsNewStyle():  # ui 2.82 and above gets the systemip/port info as well
+                singleUser.SendMachinesStatusMessage(newStatusList)
+            else:
+                singleUser.SendMachinesStatusMessage(statusList)
+        self.connectedUsersLock.release()
+
+
+        # removes the machine keyed by its machineId
+    def UnregisterMachine(self, machineId):
+        self.connectedMachinesLock.acquire()
+        if self.connectedMachines.has_key( machineId ):
+            if self.IsRoomEmpty( machineId ):  #if the room was determined to be empty, close it
+                del self.connectedMachines[machineId]    
+            self.UpdateMachines()
+        self.connectedMachinesLock.release()
+
+
+        # check if there are any users still left in this room,
+        # if there are, return FALSE, otherwise return TRUE
+    def IsRoomEmpty(self, machineId):
+        roomEmpty = True
+        self.registeredUsersLock.acquire()
+        registeredUsers = self.registeredUsers.copy()
+        self.registeredUsersLock.release()
+        for singleUser in registeredUsers.values():
+            if machineId in singleUser.GetMachines():
+                roomEmpty = False
+                break   # there is at least one user still left in the room, so leave it open
+        return roomEmpty
+                
+
+        # it makes the list of currently connected machines
+    def MakeMachinesStatusList(self):
+        statusList = []   #make the status list consisting of [name,ip,port,id,alive], [name,ip,port,id,alive], ....
+        keys = self.connectedMachines.keys()
+        keys.sort()
+        for machineId in keys:
+            tempList = []
+            singleMachine = self.connectedMachines[machineId]
+            tempList.append( singleMachine.GetName() )
+            tempList.append( singleMachine.GetIP() )
+            tempList.append( singleMachine.GetPort() )
+            tempList.append( machineId )
+            tempList.append( int(singleMachine.IsAlive()) )
+            tempList.append( singleMachine.GetDisplayInfo() )
+            statusList.append(tempList)
+        return statusList
+
+    
+        # this is for new style UIs that accept system ip/port
+        # as well
+    def MakeNewMachinesStatusList(self):
+        statusList = [] 
+        keys = self.connectedMachines.keys()
+        keys.sort()
+        for machineId in keys:
+            tempList = []
+            singleMachine = self.connectedMachines[machineId]
+            tempList.append( singleMachine.GetName() )
+            tempList.append( singleMachine.GetIP() )
+            tempList.append( singleMachine.GetPort() )
+            tempList.append( machineId )
+            tempList.append( int(singleMachine.IsAlive()) )
+            tempList.append( singleMachine.GetDisplayInfo() )
+            tempList.append( singleMachine.GetSystemIP()+" "+str(singleMachine.GetSystemPort()))
+            statusList.append(tempList)
+        return statusList
+
+
+        
+
+
+#-----------------------------------------------------------------------------------------------
+
+
+class XMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+    allow_reuse_address = True
+    def __init__(self, addr):
+        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, addr, logRequests=False)
+        self.socket.settimeout(2)  # so that handle_request times out and we can check all appLaunchers
+
+        
+
+def main( argv ):
+    global USER_SERVER_PORT
+    global SAGE_SERVER_PORT
+    global PRINT_TO_SCREEN
+    
+    WriteToFile("\n\n\n#####################################################################\n")
+    WriteToFile("   SAGE Server HAS BEEN RESTARTED\t<" + time.asctime() + ">")
+    WriteToFile("\n#####################################################################\n\n\n")
+
+    WriteStats("\n\nSERVER RESTARTED\t"+str(time.asctime())+"\n\n")
+    
+    # get the arguments (port)
+    if len(argv) == 3:
+        if "-v" in argv:
+            PRINT_TO_SCREEN = True
+        else:
+            print "Usage: python UsersServer.py [USER_SERVER_PORT] [SAGE_SERVER_PORT]\n"
+            sys.exit(0)
+    elif len(argv) > 3:
+        USER_SERVER_PORT = int(argv[2])
+        SAGE_SERVER_PORT = int(argv[3])
+        if "-v" in argv:
+            PRINT_TO_SCREEN = True
+        
+
+    # start the server accepting connections at the specified port
+    server = Server()
+
+    
+	
+if __name__ == '__main__':
+	main( ['', os.path.basename( sys.argv[0] )] + sys.argv[1:] )
Index: trunk/src/testing/ui/canvases.py
===================================================================
--- trunk/src/testing/ui/canvases.py	(revision 4)
+++ trunk/src/testing/ui/canvases.py	(revision 4)
@@ -0,0 +1,1720 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#         Allan Spale
+#
+############################################################################
+
+
+
+# my imports
+from SAGEShape import *
+from sageData import *
+from Mywx import *
+import Graph
+from globals import *
+#from pointers import Pointers
+import fileViewer
+import preferences as prefs
+
+# python imports
+import time
+from threading import Timer
+from time import sleep
+from math import floor,ceil
+import os.path
+import ConfigParser
+import wx.lib.buttons as btns
+
+
+DEBUG = False
+if DEBUG: import pdb
+
+
+
+
+class OneDisplay:
+    """ contains the shapes for on """
+    def __init__(self, l, r, t, b, sageDisplay, canvas):
+        self.sageDisplay = sageDisplay
+        self.canvas = canvas
+        self.diagram = canvas.GetDiagram()
+        self.cols = self.sageDisplay.cols
+        self.rows = self.sageDisplay.rows
+        self.sageW = self.sageDisplay.sageW
+        self.sageH = self.sageDisplay.sageH
+        self.bounds = Bounds(l,r,t,b)   # these are the bounds of the display... we have to make these panels fit here
+        
+        # create all the panels (Shapes)
+        self.__CreatePanels()
+
+
+    def __CreatePanels(self):
+        self.__panels = [ [None]*self.cols for i in range(self.rows) ]
+        
+        panelW = self.bounds.getWidth() / self.cols
+        panelH = self.bounds.getHeight() / self.rows
+        
+        for xOffset in range(self.cols):
+            for yOffset in range(self.rows):
+                self.__panels[yOffset][xOffset] = self.__AddShape(
+                    ogl.RectangleShape(panelW, panelH), 
+                    xOffset*panelW + (panelW/2) + self.bounds.left, 
+                    yOffset*panelH + (panelH/2) + self.bounds.top,
+                    wx.Pen(wx.Color(51, 102, 102), 1), wx.Brush(tileColor), "")
+
+
+    # draw boxes in the background as the frames
+    # which should not be choosable or clickable
+    def __AddShape(self, shape, x, y, pen, brush, text):
+        shape.SetDraggable(False, False)
+        shape.SetCanvas(self.canvas)
+        shape.SetX(x)
+        shape.SetY(y)
+        if pen:    shape.SetPen(pen)
+        if brush:  shape.SetBrush(brush)
+        if text:
+            for line in text.split('\n'):
+                shape.AddText(line)
+        self.diagram.AddShape(shape)
+        shape.Show(True)
+        
+        return shape
+
+
+    def Resize(self, l, r, t, b):
+        # resize and reposition the panels here
+        self.bounds.setAll(l,r,t,b)
+
+        # resize and reposition the display tiles
+        panelW = self.bounds.getWidth() / self.cols
+        panelH = self.bounds.getHeight() / self.rows
+        
+        for xOffset in range(self.cols):
+            for yOffset in range(self.rows):
+                self.__panels[yOffset][xOffset].SetX(xOffset*panelW + (panelW/2) + self.bounds.left)
+                self.__panels[yOffset][xOffset].SetY(yOffset*panelH + (panelH/2) + self.bounds.top)
+                self.__panels[yOffset][xOffset].SetSize(panelW, panelH)
+                    
+    
+
+
+class Backdrop:
+    """ consists of OneDisplays """
+    def __init__(self, sageDisplayInfo, canvas):
+        self.displays = {}  # key=displayId, value=OneDisplay
+        self.bounds = Bounds() # what's the area we have available for drawing
+        self.sageDisplayInfo = sageDisplayInfo
+        self.canvas = canvas
+        self.dispByPos = {}   # key=placement, value=OneDisplay
+        self.widths = {}      # key=placement, value=width in UI coords
+        self.heights = {}     # key=placement, value=height in UI coords
+        self.positions = {}   # key=placement, value=tuple of (l,r,t,b)
+
+
+
+    def GetDisplayBounds(self, displayId):
+        return self.displays[displayId].bounds
+    
+
+    def SetupDisplays(self,l,r,t,b):
+        self.bounds.setAll(l,r,t,b)
+                
+        # first create all the displays
+        for sageDisplay in self.sageDisplayInfo.getAllDisplays():
+            newDisp = OneDisplay(l,r,t,b,sageDisplay,self.canvas)
+            self.displays[ sageDisplay.getId() ] = newDisp
+            self.dispByPos[ sageDisplay.placement ] = newDisp
+            
+        self.SetSize(self.bounds.left, self.bounds.right, self.bounds.top, self.bounds.bottom)
+        
+            
+    def SetSize(self, l, r, t, b):
+        self.bounds.setAll(l,r,t,b)
+        
+        self.__CalculateDisplayWidths()
+        self.__CalculateDisplayHeights()
+
+        # loop through each display and set the correct bounds for each
+        for pos, disp in self.dispByPos.iteritems():
+            if pos == LEFT_DISP:
+                l = self.bounds.left
+                r = l + self.widths[LEFT_DISP]
+                t = self.bounds.top + self.heights[TOP_DISP]
+                b = t + self.heights[LEFT_DISP]
+                
+            elif pos == MIDDLE_DISP:
+                l = self.bounds.left + self.widths[LEFT_DISP]
+                r = l + self.widths[MIDDLE_DISP]
+                t = self.bounds.top + self.heights[TOP_DISP]
+                b = t + self.heights[MIDDLE_DISP]
+                            
+            elif pos == RIGHT_DISP:
+                l = self.bounds.left + self.widths[LEFT_DISP] + self.widths[MIDDLE_DISP]
+                r = l + self.widths[RIGHT_DISP]
+                t = self.bounds.top + self.heights[TOP_DISP]
+                b = t + self.heights[RIGHT_DISP]
+                
+            elif pos == TOP_DISP:
+                l = self.bounds.left + self.widths[LEFT_DISP]
+                r = l + self.widths[TOP_DISP]
+                t = self.bounds.top
+                b = t + self.heights[TOP_DISP]
+
+            elif pos == BOTTOM_DISP:
+                l = self.bounds.left + self.widths[LEFT_DISP]
+                r = l + self.widths[BOTTOM_DISP]
+                t = self.bounds.top + self.heights[TOP_DISP] + self.heights[MIDDLE_DISP]
+                b = t + self.heights[BOTTOM_DISP]
+            
+            # finally apply the size
+            disp.Resize(l,r,t,b)
+            
+                
+                            
+
+    def __CalculateDisplayWidths(self):
+        self.widths = {MIDDLE_DISP:0, LEFT_DISP:0, RIGHT_DISP:0, BOTTOM_DISP:0, TOP_DISP:0}
+        totalW = self.sageDisplayInfo.getTotalWidth()
+        
+        # in UI coords
+        for pos, disp in self.dispByPos.iteritems():
+            self.widths[pos] = (disp.sageW / float(totalW)) * self.bounds.getWidth()
+            
+    def __CalculateDisplayHeights(self):
+        self.heights = {MIDDLE_DISP:0, LEFT_DISP:0, RIGHT_DISP:0, BOTTOM_DISP:0, TOP_DISP:0}
+        totalH = self.sageDisplayInfo.getTotalHeight()
+        
+        # in UI coords
+        for pos, disp in self.dispByPos.iteritems():
+            self.heights[pos] = (disp.sageH / float(totalH)) * self.bounds.getHeight()
+
+
+
+
+
+############################################################################
+#
+#  CLASS: DisplayCanvas
+#  
+#  DESCRIPTION: This class describes the canvas where the tiled display
+#               representation is drawn. It draws all the shapes, updates
+#               the visual state of the UI as a result of messages received
+#               from SAGE, it draws all the decorative graphics pertaining
+#               to it. It also contains all the coordinate conversion methods.
+#               All the drawing is done in the OnPaint() and Redraw() methods
+#               so that way when you call canvas.Refresh() or canvas.Redraw()
+#               it will use these overloaded methods. Another reason for
+#               overloading these methods is to force them to use double buffering
+#
+#  DATE:        October, 2004
+#
+############################################################################
+
+class DisplayCanvas(ogl.ShapeCanvas):
+    def __init__(self, log, parent, sageGate, sageData, gmGraphManager, title):
+        # the size passed in here is being changed later so it doesnt really matter
+        ogl.ShapeCanvas.__init__(self, parent, -1, (0,0), (710,300), wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
+
+
+        # some global parameters
+        displaySize = wx.DisplaySize()  #the resolution of the current screen... we will base our frame size on that
+        if displaySize[1] > 900:
+            self._maxCanvasWidth = 800
+            self._borderWidth = 25
+        else:
+            self._maxCanvasWidth = 650
+            self._borderWidth = 20
+        self.frame = parent.GetFrame()#wx.GetApp().GetTopWindow() #parent
+        self.parent = parent
+        self._maxCanvasHeight = 0
+        self._maxDisplayHeight = 0
+        self._maxDisplayWidth = 0
+        self._aspectRatio = 1   #the aspect ratio for the whole canvas... this is not for the apps
+        self.title = title
+        self.displayInfoArrived = False
+        self._minimizedShapes = {}  # key=displayId, value=hash of minimized shapes
+        self._shapesTiled = False
+        
+        # main data and communication objects
+        self.sageGate = sageGate
+        self.sageData = sageData
+        self.__gmGraphManager = gmGraphManager
+
+        # support for file viewing and drag-and-dropping inside the UI
+        self.dt = fileViewer.CanvasDropTarget(self)
+        self.SetDropTarget(self.dt)
+        
+        # register sageData callbacks
+        self.sageData.registerCallbackFunction(40000, self.OnSAGEStatusMsg)
+        self.sageData.registerCallbackFunction(40001, self.OnSAGEAppInfoMsg)
+        self.sageData.registerCallbackFunction(40002, self.OnSAGEPerfInfoMsg)
+        self.sageData.registerCallbackFunction(40003, self.OnSAGEAppShutdownMsg)
+        self.sageData.registerCallbackFunction(40004, self.OnSAGEDisplayInfoMsg)
+        self.sageData.registerCallbackFunction(40005, self.OnSAGEZChangeMsg)
+        self.sageData.registerCallbackFunction(40006, self.OnSAGEAppExecConfig)
+        self.sageData.registerCallbackFunction(40007, self.OnSAGEDisplaysConnection)
+
+        # set up the canvas
+        self.log = log
+        self.SetBackgroundColour('#006666')
+        self.diagram = ogl.Diagram()
+        self.SetDiagram(self.diagram)
+        self.diagram.SetCanvas(self)
+        self.shapes = {}  #a hash of all the apps that are CURRENTLY RUNNING (keyed by windowId)
+        self.availableApps = {}     #a hash of all the apps available for running
+                                        # in this form  key:value = windowId:SAGEAppInitial
+        # now tell SAGE that we exist so we can get the current SAGE status
+        self.sageGate.registerSage()
+        
+        # at this point we know we succeeded in connecting to SAGE so load all the images
+        self.LoadImages()   #creates a hash with the "Images" keyed by the name        
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.Chillout)
+        self.Bind(wx.EVT_MOTION, self.OnMouseEnter)
+        self.Bind(wx.EVT_CLOSE, self.OnClose)
+        self.cursorSet = False
+  
+
+
+#----------------------------------------------------------------------
+# DRAWING METHODS
+#----------------------------------------------------------------------    
+    
+    def OnPaint( self, event ):
+        if DEBUG: print "OnPaint --> DisplayCanvas"; sys.stdout.flush()
+        if not self.displayInfoArrived:
+            if "__WXMSW__" in wx.PlatformInfo:  #windows needs a PaintDC created even if we dont use it
+                dc = wx.PaintDC(self)
+            return
+        dc = wx.BufferedPaintDC( self, self.swapBuffer )
+
+    def Chillout(self, event):
+        """ For intercepting the EVT_ERASE_BACKGROUND. Do nothing here on purpose
+            in order to reduce the flicker during drawing"""
+        pass
+
+
+    def OnClose(self, evt):
+        pass
+
+
+#----------------------------------------------------------------------
+
+
+    # overridden so that we can specify the order in which the drawing occurs (because of the decorative images)
+    def Redraw( self, dc=None):
+        if DEBUG: print "Redraw --> DisplayCanvas"; sys.stdout.flush()
+        if not self.displayInfoArrived:
+            return
+        # create the right kind of DC for double buffering
+        if dc == None: 
+            cdc = wx.ClientDC(self)
+            self.PrepareDC(cdc)
+            dc = wx.BufferedDC(cdc, self.swapBuffer)
+            dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+            dc.Clear()
+
+        if self.GetDiagram().GetShapeList():
+            self.SetCursor(wx.HOURGLASS_CURSOR)
+
+        # first draw the underlying shapes (LCD panels)
+        for object in self.GetDiagram().GetShapeList():
+            if ((object.__class__.__name__ != MyRectangleShape.__name__ ) and
+               (object.__class__.__name__ != MyControlPoint.__name__ )):
+                   object.Draw(dc)
+
+        # then draw the decorative images
+        for name, image in self.images.iteritems():
+            dc.DrawBitmap( image.bitmap, image.GetX(), image.GetY(), image.IsTransparent() )
+
+        # draw the title (user @ machine)
+        dc.SetTextForeground(wx.WHITE)
+        textSize = dc.GetTextExtent(self.title)
+        dc.DrawText(self.title, self.GetCanvasWidth()/2 - textSize[0]/2, (self.GetBorderWidth() - textSize[1])/2) 
+
+        # finally draw the app shapes on top of everything
+        for object in self.GetDiagram().GetShapeList():
+            if ((object.__class__.__name__ == MyRectangleShape.__name__ ) or
+               (object.__class__.__name__ == MyControlPoint.__name__ )):
+                   object.Draw(dc)
+   
+        self.SetCursor(wx.STANDARD_CURSOR)
+
+
+    #----------------------------------------------------------------------
+
+
+    def OnSize(self, event=None):
+        if DEBUG: print "OnSize --> DisplayCanvas"; sys.stdout.flush()        
+        if not self.displayInfoArrived:
+            return
+        # manually maintain the aspect ratio of the display canvas
+        parentSize = self.parent.GetClientSize()
+        self.SetCanvasWidth( parentSize.width )
+        self.SetCanvasHeight( round(self.GetCanvasWidth() / self.GetAspectRatio()) )
+        self.SetSize((self.GetCanvasWidth(), self.GetCanvasHeight()))
+        
+        # change the display width now
+        self.SetDisplayWidth( self.GetCanvasWidth() - 2 * self.GetBorderWidth() )
+        heightFactor = self.tiledDisplayWidth / float (self.GetDisplayWidth() )
+        self.SetDisplayHeight( self.GetCanvasHeight() - 1.5*self.GetBorderWidth()) #round (self.tiledDisplayHeight / heightFactor ) )
+
+        # update the size of the swap buffer
+        self.swapBuffer = wx.EmptyBitmap(self.GetCanvasWidth(), self.GetCanvasHeight())
+        
+        # reposition and resize all of the following
+        self.RecalculateImages() #decorative images
+        self.RecalculateTiles()  
+        self.RecalculateShapes() 
+        
+        self.Redraw()
+        #event.Skip()
+
+           
+    #----------------------------------------------------------------------
+
+
+    def LoadImages(self):
+        # load all the decorative images
+        wx.InitAllImageHandlers()
+        self.images = {}
+        self.imageNames = [ "top_left", "top", "top_right", "left", 
+                            "right", "bottom_left", "bottom", "bottom_right" ]
+        for i in range(1, 9):
+            self.images[ self.imageNames[i-1] ] = MyImage( "images/SAGEapp_0"+str(i)+".jpg" )       
+
+
+    def RecalculateImages(self):
+        # figure out all the sizes and positions for the decorative images and apply them
+        positions = [ (0, 0),                 (self.GetLeft(), 0),                 (self.GetRight(), 0),
+                      (0, self.GetTop()),                                          (self.GetRight(), self.GetTop()),
+                      (0, self.GetBottom()),  (self.GetLeft(), self.GetBottom()),  (self.GetRight(), self.GetBottom()) ]
+
+        sizes = [ (self.GetBorderWidth(), self.GetBorderWidth()),    (self.GetDisplayWidth(), self.GetBorderWidth()),    (self.GetBorderWidth(), self.GetBorderWidth()),
+                  (self.GetBorderWidth(), self.GetDisplayHeight()),                                                      (self.GetBorderWidth(), self.GetDisplayHeight()),
+                  (self.GetBorderWidth(), self.GetBorderWidth()/2),  (self.GetDisplayWidth(), self.GetBorderWidth()/2),  (self.GetBorderWidth(), self.GetBorderWidth()/2) ]
+
+        for i in range(0, 8):
+            image = self.images[ self.imageNames[i] ]
+            image.Rescale( sizes[i][0], sizes[i][1] )
+            image.SetX( positions[i][0] )
+            image.SetY( positions[i][1] )
+            
+
+    def RecalculateTiles(self):
+        l = self.GetBorderWidth()
+        r = self.GetCanvasWidth() - self.GetBorderWidth()
+        t = self.GetBorderWidth()
+        b = t + self.GetDisplayHeight()
+        self.backdrop.SetSize(l,r,t,b)
+        
+
+    def RecalculateShapes(self):
+        # resize and reposition all the shapes
+        # get the SAGE coordinates for the shape and convert them to UI coords again
+        for s in self.GetShapeList():
+            sageApp = self.sageData.getApp(s.GetId())
+            s.Recalculate(
+                self.ToUICoordsX(sageApp.getLeft(), sageApp.getDisplayId()),
+                self.ToUICoordsX(sageApp.getRight(), sageApp.getDisplayId()),
+                self.ToUICoordsY(sageApp.getTop(), sageApp.getDisplayId()),
+                self.ToUICoordsY(sageApp.getBottom(), sageApp.getDisplayId())
+                )
+
+
+
+
+#----------------------------------------------------------------------
+# TILING SHAPES
+#----------------------------------------------------------------------
+
+    def TileShapes(self):
+        if self._shapesTiled:  # restore the shape to their previous state
+            for shape in self.GetShapeList():
+                if not shape.GetMinimized():
+                    shape.RestoreOldParams()
+                    shape.UpdateSAGEParams()
+            self._shapesTiled = False
+            return
+
+
+
+        # figure out by how much we need to size down each shape so that they have a chance
+        # of fitting them inside the tiled display (if perfectly tiled... which is very unlikely to happen))
+        displayArea = self.GetDisplayHeight() * self.GetDisplayWidth()
+        totalShapeArea = 0
+        for shape in self.GetShapeList():
+            if not shape.GetMinimized():
+                totalShapeArea = totalShapeArea + shape.GetWidth() * shape.GetHeight()
+
+        resizeRatio = 1
+        if displayArea <= totalShapeArea*0.8:
+            resizeRatio = totalShapeArea*0.8 / displayArea
+
+        # set aside the shapes that are eligible for tiling (meaning no minimized shapes)
+        # and preserve their size and position for later restore
+        hashByArea = {}
+        for shape in self.GetShapeList():
+            if shape.GetMinimized():
+                continue       #skip minimized shapes
+            if not shape.GetMaximized(): 
+                shape.PreserveOldParams()  #preserve the current size and position
+            shape.SetSize( shape.GetWidth()/resizeRatio, shape.GetHeight()/resizeRatio )
+            shape.UpdateSAGEParams()
+            hashByArea[ (shape.GetWidth() * shape.GetHeight()) ] = shape  #key the shapes eligible for tiling by their area
+
+
+        # now the hardest part, reposition the shapes so that they fit nicely (or as nice as it gets)
+        # actually, try the other way around... first reposition the shapes and then resize them
+        # so that they all fit inside the display
+        
+
+        self._shapesTiled = True
+
+        
+#----------------------------------------------------------------------
+# DEALING WITH THE SHAPES
+#----------------------------------------------------------------------
+
+    def GetShape(self, windowId):
+        if self.shapes.has_key(windowId):
+            return self.shapes[windowId]
+        else:
+            return None
+
+    def GetShapeList(self):  # returns a copy of the shape list
+        tempList = []
+        for s in self.diagram.GetShapeList(): 
+            if ( s.__class__.__name__ == MyRectangleShape.__name__ ):
+                tempList.append(s)
+        return tempList
+
+    def GetTopShape(self):  # returns the windowId of the shape that's on top
+        minZ = sys.maxint
+        windowId = sys.maxint
+        for s in self.shapes.values():
+            if s.GetZ() < minZ or (s.GetZ() == minZ and s.GetId() < windowId):
+                minZ = s.GetZ()
+                windowId = s.GetId()
+        return windowId
+    
+##     # draw boxes in the background as the frames
+##     # which should not be choosable or clickable
+##     def MyAddBackShape(self, shape, x, y, pen, brush, text):
+##         # Composites have to be moved for all children to get in place
+##         shape.SetDraggable(False, False)
+##         shape.SetCanvas(self)
+##         shape.SetX(x)
+##         shape.SetY(y)
+##         if pen:    shape.SetPen(pen)
+##         if brush:  shape.SetBrush(brush)
+##         if text:
+##             for line in text.split('\n'):
+##                 shape.AddText(line)
+##         self.diagram.AddShape(shape)
+##         shape.Show(True)
+
+##         return shape
+
+
+    #----------------------------------------------------------------------
+
+
+    # creates the shape that corresponds to the app and adds it to the diagram.
+    def MyAddShape(self, app):
+        name = app.getName()
+        left = self.ToUICoordsX(app.getLeft(), app.getDisplayId())
+        right = self.ToUICoordsX(app.getRight(), app.getDisplayId())
+        bottom = self.ToUICoordsY(app.getBottom(), app.getDisplayId())
+        top = self.ToUICoordsY(app.getTop(), app.getDisplayId())
+        width = right - left
+        height = bottom - top
+        id = app.getId()
+        z = app.getZvalue()
+        title = app.getTitle()
+        
+        shape = MyRectangleShape(width, height, app, self.sageGate, self, title) 
+        text = name + " " + str(id)
+                           
+        shape.SetDraggable(True, True)
+        shape.SetCanvas(self)
+        shape.SetMyX(left)
+        shape.SetMyY(top)
+        shape.SetId(id) #this is windowId
+        shape.SetZ(z) 
+        shape.SetPen(wx.Pen(shapeBorderColor))#wx.BLACK_PEN)
+        shape.SetBrush( wx.Brush(shapeColor) ) #wx.GREY_BRUSH )
+        shape.SetTextColour("grey")
+        shape.SetFont(wx.Font(14, wx.MODERN, wx.NORMAL, wx.BOLD))
+            
+        if text:
+            shape.SetName(name)
+            for line in text.split('\n'):
+                shape.AddText(line)
+            shape.AddText(shape.GetTitle())
+        shape.SetShadowMode(ogl.SHADOW_NONE)#RIGHT) # uncomment for shadow
+        shape.SetMaintainAspectRatio(prefs.visual.GetKeepAspectRatio()) 
+        shape.SetCentreResize(False)   #resize the shape from one corner only
+        self.diagram.AddShape(shape)  #add the shape to the end (draws on the top)
+        shape.Show(True)
+
+        evthandler = MyEvtHandler(self.log, self.frame, self.sageGate, self)
+        evthandler.SetShape(shape)
+        evthandler.SetPreviousHandler(shape.GetEventHandler())
+        shape.SetEventHandler(evthandler)
+
+        self.shapes[id] = shape #store the newly created shape in a hash
+        return shape
+
+    #----------------------------------------------------------------------
+
+    # removes the shape from the canvas and deletes it
+    def MyRemoveShape(self, id):
+        shape = self.shapes[id]
+        canvas = shape.GetCanvas()
+        self.FreeMinimizedPosition(shape.minimizedPosition, shape.app)
+        del self.shapes[id] #remove the shape from the hash
+        shape.RemoveFromCanvas(self)
+        del shape
+
+    #----------------------------------------------------------------------
+
+##      # here there's no need to refill the diagram since all the shapes are in order
+##     # we just have to update their z values. No messages are sent to SAGE
+##     def UpdateZsForAdd(self):
+##         for s in self.GetShapeList(): #[:]:
+##             s.SetZ(s.GetZ()+1)
+
+    def OrderByZ(self):
+        diagram = self.GetDiagram()
+        shapeList = self.GetShapeList()
+        tempHash = {}  #shapes keyed by Z value for easy ordering
+        selectedShape = None
+
+        # now go through all the shapes and update them visually according to the new z values
+        for s in shapeList[:]:
+            s.SetZ( self.sageData.getZvalue(s.GetId()) )
+            tempHash[ s.GetZ() ] = s
+            if s.Selected():
+                selectedShape = s
+            diagram.RemoveShape(s)
+        
+        # sort the shapes so that they are in the right order for drawing
+        tempKeys = tempHash.keys()
+        tempKeys.sort()
+        tempKeys.reverse()
+
+        # now add all the shapes back sorted by Z
+        for z in tempKeys:
+            tempHash[z].DeleteControlPoints()
+            diagram.AddShape(tempHash[z])
+
+        # select the previously selected shape
+        if selectedShape is not None:
+            selectedShape.MakeControlPoints()
+
+       
+    #----------------------------------------------------------------------
+
+    # detects when the mouse pointer is over a control point and changes the pointer itself
+    def OnMouseEnter(self, event):
+        x = event.GetX()
+        y = event.GetY()
+
+        # stop this event here so that we can make other events
+        # (clicks on the shape to resize it)
+        event.StopPropagation()
+        event.Skip()
+        
+        shape = self.FindShape(x,y)[0]
+        if shape == None:
+            return
+
+        # set the correct cursor based on the location of the control point
+        if shape.__class__.__name__ == MyControlPoint.__name__:
+            if not self.cursorSet:   # set the cursor only once (ie, if it's set, don't set it again)
+                if shape.location == "NE" or shape.location == "SW":
+                    self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENESW))
+                else:
+                    self.SetCursor(wx.StockCursor(wx.CURSOR_SIZENWSE))
+                self.cursorSet = True
+
+        elif self.cursorSet:    # we only want to reset the cursor if it was previously set
+            self.cursorSet = False
+            self.SetCursor(wx.STANDARD_CURSOR)
+
+
+    #----------------------------------------------------------------------
+
+        # this keeps track of where the minimized app should be located
+        # the hash holds windowIds but the keys are actually more important
+        # if a key exists, that means that there is an app in that spot so
+        # return the first free spot
+    def GetNextMinimizedPosition(self, app):
+        for i in range(0,30):
+            if not i in self._minimizedShapes[app.getDisplayId()]:
+                self._minimizedShapes[app.getDisplayId()][i] = app
+                return i
+
+        # when the app is not minimized anymore, it has to free its spot
+    def FreeMinimizedPosition(self, pos, app):
+        if pos in self._minimizedShapes[app.getDisplayId()]:
+            if self._minimizedShapes[app.getDisplayId()][pos] == app:
+                del self._minimizedShapes[app.getDisplayId()][pos]
+            
+
+#----------------------------------------------------------------------
+# CANVAS PREFERENCES AND PROPERTIES
+#----------------------------------------------------------------------
+
+    def ShowLibrary(self):
+        #reload(fileViewer)  # for debugging only!
+        fileViewer.FileLibrary(self, self.frame.GetPositionTuple())
+
+    def ChangeBackgroundColor(self, (r,g,b)):
+        return
+    
+    ##     tileColor = wx.Colour(r,g,b)
+##         for xOffset in range(self.iTileColumns):
+##             for yOffset in range(self.iTileRows):
+##                 self._LCDPanels[yOffset][xOffset].SetBrush(wx.Brush(tileColor))
+##         self.Redraw()
+        
+
+    def SetMaintainAspectRatio(self, ar):
+        prefs.visual.SetKeepAspectRatio(ar)
+
+    def GetMaintainAspectRatio(self):
+        return prefs.visual.GetKeepAspectRatio()
+
+
+        # stop or start receiving performance data
+    def ReceivePerformanceData(self, doReceive):
+        if doReceive:
+            prefs.visual.SetReceivePerformanceData(True)
+            for shape in self.GetShapeList():
+                self.sageGate.startPerformance(shape.GetId())
+        else:
+            prefs.visual.SetReceivePerformanceData(False)
+            for shape in self.GetShapeList():
+                self.sageGate.stopPerformance(shape.GetId())
+
+
+        # returns the bounds of the display in UI coords
+    def GetUIDisplayBounds(self, displayId):
+        return self.backdrop.GetDisplayBounds(displayId)
+    
+    
+    # for getting the bounds of the area where the displays will be
+    def GetLeft(self):
+        return self.GetBorderWidth()
+
+    def GetRight(self):
+        return self.GetDisplayWidth() + self.GetBorderWidth()
+
+    def GetTop(self):
+        return self.GetBorderWidth()
+
+    def GetBottom(self):
+        return self.GetDisplayHeight() + self.GetBorderWidth()
+
+
+    # tiled display are size (in the UI) - this is not for every individual display...
+    def GetDisplayWidth(self):
+        return self._maxDisplayWidth
+
+    def GetDisplayHeight(self):
+        return self._maxDisplayHeight
+
+    def SetDisplayWidth(self, newWidth):
+        self._maxDisplayWidth = newWidth
+        
+    def SetDisplayHeight(self, newHeight):
+        self._maxDisplayHeight = newHeight
+
+
+    # the top part of the UI (the window that holds the tiled display)
+    def GetCanvasWidth(self):
+        return self._maxCanvasWidth
+
+    def GetCanvasHeight(self):
+        return self._maxCanvasHeight
+
+    def SetCanvasWidth(self, newWidth):
+        self._maxCanvasWidth = newWidth
+
+    def SetCanvasHeight(self, newHeight):
+        self._maxCanvasHeight = newHeight
+
+    def GetBorderWidth(self):
+        return self._borderWidth
+
+    def SetBorderWidth(self, newWidth):
+        self._borderWidth = newWidth
+
+    def SetAspectRatio(self, ratio):
+        self._aspectRatio = ratio
+
+    def GetAspectRatio(self):
+        return self._aspectRatio
+        
+
+    def GetGraphManager(self):
+        return self.__gmGraphManager
+
+
+
+#----------------------------------------------------------------------
+# SAGEGATE CALLBACKS
+#----------------------------------------------------------------------
+
+    ### 40000 ###
+    def OnSAGEStatusMsg(self):
+        # this is where we make all the buttons for all the apps that SAGE supports
+        hashAvailableApps = self.sageData.getAvailableApps()
+
+        # figure out the positions for all the app buttons so that they are evenly spaced and centered
+        # then, create the SAGEAppInitial for every one of them and make the buttons on the bottom panel
+        buttonOffset = 40
+        buttonNum = 1  
+
+        # add the remote app button first
+        self.parent.GetAppPanel().AddRemoteButton("REMOTE APPS", (buttonNum*buttonOffset, 10), self.sageGate)
+
+        # now add the rest of the buttons from the local appLauncher (local to our SAGE)
+        apps = hashAvailableApps.keys()
+        apps.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        
+        for appName in apps:
+            buttonNum = buttonNum + 2
+            temp = hashAvailableApps[appName]
+            self.availableApps[appName] = hashAvailableApps[appName]
+            self.parent.GetAppPanel().AddButton(self.availableApps[appName], (buttonNum*buttonOffset, 10))
+            self.parent.GetAppPanel().AddConfigMenu(self.availableApps[appName])
+
+               
+    #----------------------------------------------------------------------
+    
+
+    ### 40001 ###
+    def OnSAGEAppInfoMsg(self, sageApp):
+        # Here we just check if a shape for this "sageApp" exists and
+        # if it does, well, then we dont wanna create a new one but modify the old one
+        windowId = sageApp.getId()
+        if not self.shapes.has_key(windowId):  # CREATING A NEW SHAPE
+            newShape = self.MyAddShape(sageApp)
+            self.parent.GetAppInfoPanel().AddInstanceButton(sageApp)
+            self.OrderByZ()  # the shapes may arrive out of order
+            
+            # (AKS 2005-04-05) Only start performance monitoring when a new application
+            # is generated.
+            if prefs.visual.GetReceivePerformanceData():
+                self.sageGate.startPerformance( windowId, 2 )
+            
+        else:                          # MODIFYING A SHAPE
+            shape = self.shapes[windowId]
+            newWidth = self.ToUIWidth( sageApp.getLeft(), sageApp.getRight(), sageApp.getDisplayId() )
+            newHeight = self.ToUIHeight( sageApp.getBottom(), sageApp.getTop(), sageApp.getDisplayId() )
+            shape.SetSize(newWidth, newHeight)          
+            shape.SetX( round (self.ToUICoordsX( sageApp.getLeft(), sageApp.getDisplayId() ) + int(newWidth/2)) )
+            shape.SetY( round (self.ToUICoordsY( sageApp.getTop(), sageApp.getDisplayId() ) + int(newHeight/2)) )
+            shape.SetTitle( sageApp.getTitle() )
+            shape.SetOrientation( sageApp.getOrientation() )
+            shape.ResetControlPoints() 
+            
+
+        self.Redraw()
+            
+                
+    #----------------------------------------------------------------------
+    
+
+    # 40002
+    def OnSAGEPerfInfoMsg(self, windowId ):
+        # (AKS 2005-04-05) Performance monitoring information
+        ## print "**** sageui >> 40002 >> update graph manager"
+        self.__gmGraphManager.update( windowId )
+        #print
+        #print "TOTALS"
+        #print "------"
+        stats = self.sageData.getTotals()
+        #print "Render total bandwidth = ", stats[ self.sageData.I_RENDER_TOTAL_BANDWIDTH ]
+        #print "Render average framerate = ", stats[ self.sageData.I_RENDER_AVG_FRAME_RATE ]
+        #print "Render total nodes = ", stats[ self.sageData.I_RENDER_TOTAL_NODES ]
+        #print "Display total bandwidth = ", stats[ self.sageData.I_DISPLAY_TOTAL_BANDWIDTH ]
+        #print "Display average framerate = ", stats[ self.sageData.I_DISPLAY_AVG_FRAME_RATE ]
+        #print "Display total nodes = ", stats[ self.sageData.I_DISPLAY_TOTAL_NODES ]
+
+
+
+    #----------------------------------------------------------------------
+
+
+    # 40003
+    def OnSAGEAppShutdownMsg(self, sageApp):
+        # turn the button off and close the app
+        self.MyRemoveShape(sageApp.getId())
+        self.parent.GetAppInfoPanel().RemoveInstanceButton(sageApp)
+        self.Redraw()
+
+
+        ## # (AKS 2005-04-05) Stop performance monitoring that began "by default"
+        # when a new application had started.
+        #self.sageGate.stopPerformance( windowId )  #this needs to be called BEFORE we close the app and not after...
+        
+        self.__gmGraphManager.removeGraph( sageApp.getId() )
+
+        
+    #----------------------------------------------------------------------
+    
+
+    # 40004
+    def OnSAGEDisplayInfoMsg(self):
+        self.displayInfo = self.sageData.getDisplayInfo()
+
+        # create the hash for each of the displays that holds the minimized shapes
+        for sageDisplay in self.displayInfo.getAllDisplays():
+            self._minimizedShapes[sageDisplay.displayId] = {}
+        
+        # for one display and old SAGE there are no connection messages so just
+        # pretend that one came in for drawing everything correctly
+        if self.displayInfo.getNumDisplays() == 1:
+            self.OnSAGEDisplaysConnection()
+
+             
+    #----------------------------------------------------------------------
+
+
+    # 40007
+    def OnSAGEDisplaysConnection(self):
+        self.tiledDisplayWidth = self.displayInfo.getTotalWidth()
+        self.tiledDisplayHeight = self.displayInfo.getTotalHeight()
+        
+        # now we have all the data needed to set up the sizes of the canvas and display part
+        self.SetDisplayWidth( self.GetCanvasWidth() - 2 * self.GetBorderWidth() )
+        heightFactor = self.tiledDisplayWidth / float (self.GetDisplayWidth() )
+        self.SetDisplayHeight( round (self.tiledDisplayHeight / heightFactor ) )
+        self.SetCanvasHeight( self.GetDisplayHeight() + 1.5 * self.GetBorderWidth())
+        
+        self.EnableScrolling(False, False)
+        self.SetSize((self.GetCanvasWidth(), self.GetCanvasHeight()))
+        self.SetAspectRatio( float(self.GetCanvasWidth()) / self.GetCanvasHeight() )
+
+
+        # figure out the backdrop panels
+        self.displayInfoArrived = True  #set the flag so that we can begin resizing
+        l = self.GetBorderWidth()
+        r = self.GetCanvasWidth() - self.GetBorderWidth()
+        t = self.GetBorderWidth()
+        b = self.GetCanvasHeight() - self.GetBorderWidth()
+
+        self.backdrop = Backdrop(self.displayInfo, self)
+        self.backdrop.SetupDisplays(l,r,t,b)
+
+
+        # resize the parent to be of the right size for its contents
+        if self.parent.GetNotebook().GetPageCount() < 2:  #if this is the first display, resize the frame
+            displaySize = wx.DisplaySize()  #the resolution of the current screen
+            if prefs.visual.GetFrameSize() != None:  # read the last state from the preferences
+                self.frame.SetSizeHints(400, 350, displaySize[0], displaySize[1])
+                self.frame.SetClientSize( prefs.visual.GetFrameSize() )
+            else:                                    # there are no previous preferences saved so figure it out
+                appCanvasWidth, appCanvasHeight = self.parent.GetAppInfoPanel().GetSize()
+                self.frame.SetSizeHints(400, 350, displaySize[0], displaySize[1])  #minimum size = (400, 400)
+                self.frame.SetClientSize((self.GetCanvasWidth(), self.GetCanvasHeight() + appCanvasHeight)) # set the initial size of the frame
+                if self.frame.GetSize().GetHeight() > displaySize[1]:  #is the frame too big for the desktop??? if so, size it back down
+                    heightDifference = self.frame.GetSize().GetHeight() - displaySize[1]
+                    self.frame.SetClientSize((self.GetCanvasWidth(), self.GetCanvasHeight() + appCanvasHeight - heightDifference))
+            
+            # figure out the positions and the sizes of all the decorative images
+            self.RecalculateImages()
+            ##set up a swap buffer for double buffering
+            self.swapBuffer = wx.EmptyBitmap(self.GetCanvasWidth(), self.GetCanvasHeight())
+            dc = wx.BufferedDC(None, self.swapBuffer)
+            dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+            dc.Clear()
+            self.Redraw(dc)
+        else:   # since we didn't resize the frame, we have to fit the contents inside of it
+            ##set up a swap buffer for double buffering
+            self.swapBuffer = wx.EmptyBitmap(self.GetCanvasWidth(), self.GetCanvasHeight())
+            dc = wx.BufferedDC(None, self.swapBuffer)
+            dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
+            dc.Clear()
+            self.parent.OnSize()
+            #self.Redraw(dc)
+        del dc
+
+        # call the parent if something needs to be done
+        self.parent.OnDisplayInfo()
+
+        # add the pointers
+        #self.ptrs = Pointers(self.sageGate, self.sageData)
+        
+        # show the frame when all the buttons have been created (just for visual purposes)
+        self.frame.Show()
+        if self.frame.usersClient.connected:
+            if prefs.visual.IsChatShown() == None or prefs.visual.IsChatShown():
+                self.frame.GetUsersPanel().Show()
+
+
+    
+        
+    #----------------------------------------------------------------------
+    
+
+    # 40005
+    def OnSAGEZChangeMsg(self):
+        self.OrderByZ() # redraw the shapes based on the new order
+        self.Redraw()
+
+        
+    #----------------------------------------------------------------------
+    
+
+    # 40006
+    def OnSAGEAppExecConfig(self, appInitial):
+        self.parent.GetAppPanel().AddConfigMenu(appInitial)
+
+
+
+#----------------------------------------------------------------------
+#  UI ---> SAGE coordinate conversion
+#----------------------------------------------------------------------
+
+    def ToSAGECoordsX (self, uiX, displayId, doRound=True):
+        bounds = self.backdrop.GetDisplayBounds(displayId)
+        uiX = uiX - bounds.left
+        sageX = (float(uiX) / bounds.getWidth()) * self.displayInfo.getDisplay(displayId).sageW
+        if doRound:
+            sageX = round(sageX)
+        return sageX
+
+    def ToSAGECoordsY (self, uiY, displayId, doRound=True):
+        bounds = self.backdrop.GetDisplayBounds(displayId)
+        uiY = uiY - bounds.top
+        sageY = (1-(float(uiY) / bounds.getHeight())) * self.displayInfo.getDisplay(displayId).sageH
+        if doRound:
+            sageY = round(sageY)
+        return sageY
+
+    def ToSAGEDistX (self, oldX, newX, displayId):   
+        return round( self.ToSAGECoordsX( newX, displayId, False ) - self.ToSAGECoordsX( oldX, displayId, False ) )
+
+    def ToSAGEDistY (self, oldY, newY, displayId):   
+        return round( self.ToSAGECoordsY( newY, displayId, False ) - self.ToSAGECoordsY( oldY, displayId, False ) )
+    
+
+#----------------------------------------------------------------------
+#  SAGE ---> UI coordinate conversion   
+#----------------------------------------------------------------------
+
+    def ToUICoordsX (self, sageX, displayId, doRound=True):
+        bounds = self.backdrop.GetDisplayBounds(displayId)
+        uiX = (float(sageX) / self.displayInfo.getDisplay(displayId).sageW) * bounds.getWidth()
+        uiX += bounds.left
+        
+        if doRound:
+            uiX = round(uiX)
+        return uiX
+
+    def ToUICoordsY (self, sageY, displayId, doRound=True):
+        bounds = self.backdrop.GetDisplayBounds(displayId)
+        uiY = (1 - (float(sageY) / self.displayInfo.getDisplay(displayId).sageH)) * bounds.getHeight()
+        uiY += bounds.top
+        
+        if doRound:
+            uiY = round(uiY)
+        return uiY
+
+    def ToUIWidth (self, leftSageX, rightSageX, displayId): 
+        return round( abs(self.ToUICoordsX( leftSageX, displayId, False ) - self.ToUICoordsX( rightSageX, displayId, False )) )
+    
+    def ToUIHeight (self, bottomSageY, topSageY, displayId):
+        return round( abs(self.ToUICoordsY( bottomSageY, displayId, False ) - self.ToUICoordsY( topSageY, displayId, False )) )
+
+
+
+
+
+############################################################################
+#
+#  CLASS: AppInfoPanel
+#  
+#  DESCRIPTION: It describes the canvas that holds all the buttons for
+#               starting and stopping SAGE apps from within the SAGE UI.
+#               It also draws all the graphics that is used instead of the
+#               regular wx controls. It handles button clicks and other app
+#               specific actions. It does all the drawing with double buffering.
+#
+#  DATE:        December 26, 2004
+#
+############################################################################
+
+class AppInfoPanel(wx.Panel):
+    def __init__(self, frame, sageGate, parent, id, position, size, style):
+        wx.Panel.__init__(self, parent, id, position, size, style)
+        self.SetBackgroundColour('#888888')
+        self.sageGate = sageGate
+        self.parent = parent
+        self.visible = True
+        self.shrinkInfoPanel = False
+        self.infoPanelMinimized = False
+
+        # load the images for the arrows
+        self.arrowLeft = MyBitmapButton(self, (self.GetDisplayCanvas().GetBorderWidth(), 10), (20,40), "images/scrollLeft_up.jpg", "images/scrollLeft_down.jpg", "images/scrollLeft_over.jpg") 
+        self.arrowRight = MyBitmapButton(self, (self.GetDisplayCanvas().GetBorderWidth(), 10), (20,40), "images/scrollRight_up.jpg", "images/scrollRight_down.jpg", "images/scrollRight_over.jpg")
+        self.arrowLeft.Bind(wx.EVT_LEFT_DOWN, self.OnLeftArrowDown)
+        self.arrowLeft.Bind(wx.EVT_LEFT_UP, self.OnLeftArrowUp)
+        self.arrowRight.Bind(wx.EVT_LEFT_DOWN, self.OnRightArrowDown)
+        self.arrowRight.Bind(wx.EVT_LEFT_UP, self.OnRightArrowUp)
+
+        # load the decorative images (edges)
+        border = self.GetDisplayCanvas().GetBorderWidth()
+        self.borderImages = []
+        self.borderImages.append( MyImage( "images/SAGEapp_10.jpg", 0,0, False, border, size[1] - border/2))
+        self.borderImages.append( MyImage( "images/SAGEapp_14.jpg", border,0, False, size[0]-2*border, size[1]-border/2))
+        self.borderImages.append( MyImage( "images/SAGEapp_15.jpg", size[0]-border,0, False, border, size[1] - border/2))
+        self.borderImages.append( MyImage( "images/SAGEapp_17.jpg", 0,size[1]-border/2, False, border, border/2))
+        self.borderImages.append( MyImage( "images/SAGEapp_18.jpg", border,size[1]-border/2, False, size[0]-2*border,border/2))
+        self.borderImages.append( MyImage( "images/SAGEapp_19.jpg", size[0]-border,size[1]-border/2, False, border,border/2))
+        
+        # bind events for the panel
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.Chillout)
+        if "__WXMSW__" in wx.PlatformInfo:  # this is needed on windows for proper painting after resize
+            self.Bind(wx.EVT_SIZE, self.OnSize)
+
+        # set up the area for the buttons to be in
+        self.appPanel = AppPanel(self, 20,20, border+self.arrowLeft.GetSize().width,10)
+        self.infoPanel = InfoPanel(self, 50,20, 100,20)
+
+        # the show/hide buttons
+        self.hideAppPanelButton = MyBitmapButton(self, (0,0), (40,12), "images/handle1.jpg")
+        self.hideAppPanelButton.Bind(wx.EVT_LEFT_UP, self.OnHideAppPanelButton)
+        self.hideInfoPanelButton = MyBitmapButton(self, (0,0), (12,40), "images/handle.jpg")
+        self.hideInfoPanelButton.Bind(wx.EVT_LEFT_UP, self.OnHideInfoPanelButton)
+
+        
+
+    #----------------------------------------------------------------------
+
+
+    def OnPaint(self, event=None):
+        if DEBUG: print "    OnPaint --> AppInfoPanel"; sys.stdout.flush()
+        dc = wx.PaintDC(self)
+        if not self.GetDisplayCanvas().displayInfoArrived:
+            return
+        self.Redraw(dc)  # redraw first and then swap the buffer
+            
+
+    #----------------------------------------------------------------------
+    
+
+    def Redraw(self, dc=None):
+        if DEBUG: print "    Redraw --> AppInfoPanel"; sys.stdout.flush()
+        if not self.GetDisplayCanvas().displayInfoArrived:
+            return
+        if dc == None:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self)
+
+        # decorative images
+        for image in self.borderImages:
+            dc.DrawBitmap( image.bitmap, image.GetX(), image.GetY(), image.IsTransparent() )        
+
+        del dc # to stop mac os from complaining about nested wxDCs
+
+        # redraw the children
+        self.infoPanel.Redraw()
+        self.appPanel.Redraw()
+
+        # redraw the controls on the panel
+        self.hideAppPanelButton.OnPaint()
+        self.hideInfoPanelButton.OnPaint()
+        self.arrowLeft.OnPaint()
+        self.arrowRight.OnPaint()
+        
+
+        
+
+    #----------------------------------------------------------------------
+
+    
+    def Chillout(self, event):
+        """ For intercepting the EVT_ERASE_BACKGROUND. Do nothing here on purpose
+            in order to reduce the flicker during drawing"""
+        pass
+
+
+    #----------------------------------------------------------------------
+
+
+    def OnSize(self, event=None):
+        if DEBUG: print "    OnSize --> AppInfoPanel"; sys.stdout.flush()
+        if not self.GetDisplayCanvas().displayInfoArrived:
+            return
+        # move the panel first to the bottom of the canvas
+        canvasHeight = self.parent.GetDisplayCanvas().GetCanvasHeight()
+        self.MoveXY(0, canvasHeight - 1)
+        
+        # resize the main AppInfoPanel now
+        parentSize = self.parent.GetClientSize()
+        if "__WXMSW__" in wx.PlatformInfo:  # a visual hack for windows
+            newHeight = parentSize.height - canvasHeight - 21#canvasSize.height - 21
+        else:
+            newHeight = parentSize.height - canvasHeight #canvasSize.height
+	if newHeight < 1:
+	   newHeight = 1
+           
+        self.SetSize( (parentSize.width, newHeight) )
+
+        # rescale and reposition all the decorative images (edges)
+        border = self.parent.GetDisplayCanvas().GetBorderWidth()
+        size = self.GetSizeTuple()
+        if size[0] > 0 and size[1] > 0:    # resize only if the parent has a reasonable size
+            self.borderImages[0].Recalculate( border, size[1] - border/2, 0,0)
+            self.borderImages[1].Recalculate( size[0]-2*border, size[1]-border/2, border,0)
+            self.borderImages[2].Recalculate( border, size[1] - border/2, size[0]-border,0)
+            self.borderImages[3].Recalculate( border, border/2, 0,size[1]-border/2)
+            self.borderImages[4].Recalculate( size[0]-2*border,border/2, border,size[1]-border/2)
+            self.borderImages[5].Recalculate( border,border/2, size[0]-border,size[1]-border/2)
+
+        # as we are sizing down, make the infoPanel disappear if the frame size got small enough
+        self.shrinkInfoPanel = parentSize.width < (border*2 + 2*self.arrowLeft.GetSize().width + self.infoPanel.GetCurrentMinSize() + 50)
+                
+        if (self.shrinkInfoPanel and self.infoPanel.visible):  # hide the info panel
+            self.infoPanel.Minimize()
+            self.hideInfoPanelButton.Hide()
+        elif (not self.shrinkInfoPanel) and (not self.infoPanel.visible) and (not self.infoPanelMinimized):  #show it (once)
+            self.infoPanel.Maximize()
+            self.hideInfoPanelButton.Show()
+
+        # now resize the children
+        self.infoPanel.OnSize()
+        self.appPanel.OnSize()
+
+        # reposition the scrolling arrows for the appPanel
+        self.arrowLeft.MoveXY(self.GetDisplayCanvas().GetBorderWidth(), 20)
+        self.arrowRight.MoveXY(self.GetDisplayCanvas().GetBorderWidth()+self.appPanel.GetSize().width+self.GetArrowWidth(), 20)
+        self.hideAppPanelButton.MoveXY( size[0]/2 - self.hideAppPanelButton.GetSize()[0]/2,  0 )
+        self.hideInfoPanelButton.MoveXY( self.infoPanel.GetPosition().x - 16,  self.infoPanel.GetPosition().y + self.infoPanel.GetSize().height/2 - self.hideInfoPanelButton.GetSize()[1]/2 )
+
+        self.Redraw()
+
+
+    #----------------------------------------------------------------------
+
+
+    def OnHideAppPanelButton(self, event=None):
+        if self.visible:
+            self.parent.HideAppInfoPanel()
+            self.visible = False
+            self.arrowRight.Hide()
+            self.arrowLeft.Hide()
+        else:
+            self.parent.ShowAppInfoPanel()
+            self.visible = True
+            self.arrowRight.Show()
+            self.arrowLeft.Show()
+
+    def OnHideInfoPanelButton(self, event=None):
+        if self.infoPanel.visible:  #hide it
+            self.infoPanel.Minimize()
+            self.infoPanelMinimized = True
+            self.OnSize()
+        else:              # it's already hidden so show it
+            self.infoPanel.Maximize()
+            self.infoPanelMinimized = False
+            self.OnSize()
+
+            
+    def OnLeftArrowDown(self, event):
+        self.arrowLeft.OnLeftDown(event)
+        self.appPanel.ScrollLeft()
+
+    def OnRightArrowDown(self, event):
+        self.arrowRight.OnLeftDown(event)
+        self.appPanel.ScrollRight()
+
+    def OnLeftArrowUp(self, event):
+        self.arrowLeft.OnLeftUp(event)
+        self.appPanel.ScrollLeft()
+
+    def OnRightArrowUp(self, event):
+        self.arrowRight.OnLeftUp(event)
+        self.appPanel.ScrollRight()
+        
+
+    #----------------------------------------------------------------------
+    
+    
+    def AddInstanceButton(self, sageApp):
+        # once the 40001 message arrives and the app doesnt exists yet, create an instance button for it
+        self.appPanel.AddInstanceButton(sageApp)
+	self.Refresh()
+
+    def RemoveInstanceButton(self, sageApp):
+        # once the 40003 message arrives and we close the app, remove the instance button for it
+        self.appPanel.RemoveInstanceButton(sageApp)
+        self.Refresh()
+
+        
+    #----------------------------------------------------------------------
+
+    def GetDisplayCanvas(self):
+        return self.parent.GetDisplayCanvas()
+
+    def GetArrowWidth(self):
+        return self.arrowLeft.GetSize().width
+
+    def GetInfoPanel(self):
+        return self.infoPanel
+    
+    def GetAppPanel(self):
+        return self.appPanel
+
+
+
+############################################################################
+#
+#  CLASS: AppPanel
+#  
+#  DESCRIPTION: It describes the canvas that holds all the buttons for
+#               starting and stopping SAGE apps from within the SAGE UI.
+#               It also draws all the graphics that is used instead of the
+#               regular wx controls. It handles button clicks and other app
+#               specific actions. It does all the drawing with double buffering.
+#
+#  DATE:        April, 2005
+#
+############################################################################
+
+class AppPanel(wx.Panel):
+
+    def __init__(self, parent, width, height, x, y):
+        wx.Panel.__init__(self, parent, -1, (x,y), (width,height), wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
+        self.SetBackgroundColour(appPanelColor)
+        self.page = parent.parent
+        self.parent = parent
+        self.visible = True
+        self._appButtonWidth = 40
+        self.appButtons = {} # has to store all the buttons keyed by the app_inst_IDs
+        self.appNames = [] # list of all app names that we got from sage
+        self.buttonOffset = 0 #used for positioning the buttons
+        self.scrollWidth = width  #the minimum width required to draw all the app buttons
+        self.first = None  # used for scrolling... these are first and last app buttons
+        self.last = None
+
+        # background for the app buttons
+        self.bar = MyImage( "images/menu_bar.jpg", 0,10, False, 1500, self.GetButtonWidth())
+        self.background = MyImage( "images/app_panel_background.png", 0,0, False, width, height)
+
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.Chillout)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        if wx.Platform == "__WXMSW__":  # this is needed on windows for proper painting after resize
+            self.Bind(wx.EVT_SIZE, self.OnSize)
+        
+
+    #----------------------------------------------------------------------
+
+    def OnPaint(self, event=None):
+        if DEBUG: print "\tOnPaint --> AppPanel"; sys.stdout.flush()
+        dc = wx.PaintDC(self)
+        self.PrepareDC(dc)
+	self.Redraw(dc)
+
+   
+    def Redraw(self, dc=None):
+        if DEBUG: print "\tRedraw --> AppPanel"; sys.stdout.flush()
+	if dc == None:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self)
+            self.PrepareDC(dc)
+
+        # first draw the bar and the background
+        dc.DrawBitmap( self.background.bitmap, self.background.GetX(), self.background.GetY(), self.background.IsTransparent())
+        dc.DrawBitmap( self.bar.bitmap, self.bar.GetX(), self.bar.GetY(), self.bar.IsTransparent() )
+        del dc  # for mac os to stop complaining about nested wxDCs
+
+        # draw all the app buttons in their respective locations
+        for name, button in self.appButtons.iteritems():
+            button.OnPaint()
+        
+
+    def Chillout(self, event):
+        """ For intercepting the EVT_ERASE_BACKGROUND. Do nothing here on purpose
+            in order to reduce the flicker during drawing"""
+        pass
+
+
+    def OnSize(self, event=None):
+        if DEBUG: print "\tOnSize --> AppPanel"; sys.stdout.flush()
+        # get some measures that will help us determine the size of the panel
+        parentSize = self.parent.GetClientSize()
+        borderWidth = self.parent.GetDisplayCanvas().GetBorderWidth()
+        arrowWidth = self.parent.GetArrowWidth()
+        infoPanelWidth = self.parent.GetInfoPanel().GetSize().width#GetInfoPanelWidth()
+
+        # determine the new size
+        newWidth = parentSize.width - infoPanelWidth - 2*arrowWidth - 2*borderWidth - 20
+        newHeight = parentSize.height - 1.5*borderWidth
+	if newHeight < 1:
+	   newHeight = 1
+	if newWidth < 1:
+	   newWidth = 1
+        self.SetSize( (newWidth, newHeight) )
+
+        #resize the background image
+        self.background.Rescale(newWidth, newHeight)
+        self.Redraw()
+
+
+    #----------------------------------------------------------------------
+
+    
+    def ScrollLeft(self):
+        if not self.IsButtonVisible( self.first ):
+            self.ScrollWindow( 30, 0 )
+            self.Update()
+                
+
+    def ScrollRight(self):
+        if not self.IsButtonVisible( self.last ):
+            self.ScrollWindow( -30, 0 )
+            self.Update()
+
+
+    def IsButtonVisible(self, button):
+        # Used in scrolling... checks if a button is on the screen.
+        # If not, return false so that we have to scroll
+        x = button.GetPosition().x
+        width = button.GetSize().width
+
+        if (x > 0) and ((x+width) < self.GetSize().width):
+            return True
+        else:
+            return False
+            
+
+    #----------------------------------------------------------------------
+
+
+    def AddRemoteButton(self, name, (x,y), sageGate):
+        self.appNames.append(name)
+        
+        # create the buttons and check if images are available for them
+        if os.path.isfile( ConvertPath("images/remote_up.jpg")):
+            bitmapName = "images/remote"
+        else:
+            bitmapName = "images/default"
+        self.appButtons[ name ] = RemoteAppButton( self, bitmapName+"_up.jpg", bitmapName+"_down.jpg", bitmapName+"_over.jpg", (x,y), (self.GetButtonWidth(),self.GetButtonWidth()), sageGate)
+        self.buttonOffset = self.buttonOffset + 1
+
+        # this is the total area taken by the buttons (so that they are all displayed at once)
+        self.scrollWidth = self.GetButtonWidth() * 2 * len(self.appButtons)
+    
+        # remember which is the first and the last button... used for scrolling
+        if self.first == None:
+            self.first = self.appButtons[ name ]
+            self.last = self.appButtons[ name ]  #the first is also the last
+        else:
+            self.last = self.appButtons[ name ]
+
+
+    def AddButton(self, app, (x,y)):
+        self.appNames.append(app.GetName())
+        
+        # create the buttons and check if images are available for them
+        if os.path.isfile( ConvertPath("images/" + string.lower(app.GetName()) + "_up.jpg")):
+            bitmapName = "images/" + string.lower(app.GetName())
+        else:
+            bitmapName = "images/default"
+        self.appButtons[ app.GetName() ] = AppButton( self, bitmapName+"_up.jpg", bitmapName+"_down.jpg", bitmapName+"_over.jpg", (x,y), (self.GetButtonWidth(),self.GetButtonWidth()), app)
+        self.buttonOffset = self.buttonOffset + 1
+
+        # this is the total area taken by the buttons (so that they are all displayed at once)
+        self.scrollWidth = self.GetButtonWidth() * 2 * len(self.appButtons)
+    
+        # remember which is the first and the last button... used for scrolling
+        if self.first == None:
+            self.first = self.appButtons[ app.GetName() ]
+        else:
+            self.last = self.appButtons[ app.GetName() ]
+
+
+    def RepositionAppButtons(self):
+        # repositions all the app buttons and redraws them
+        # the app buttons then reposition all the instance buttons and redraw them
+        buttonOffset = round( self.GetSize().width / float( len(self.appNames)*2+1 ) )
+        buttonNum = 1
+        
+        for k, btn in self.appButtons.iteritems():
+            btn.MoveXY(buttonNum*buttonOffset, 10)
+            buttonNum = buttonNum + 2
+
+
+    def GetButtonWidth(self):
+        return self._appButtonWidth
+    
+    def GetAppInfoPanel(self):
+        return self.parent
+
+
+    #----------------------------------------------------------------------
+
+    # fills the remote application button with the correct menu data for each app launcher
+    def AddLauncherMenu(self, name, launcherHash):
+        self.appButtons[ name ].AddLauncherMenu(launcherHash)    
+
+    # once the 40006 message arrives, we add a menu to the button
+    def AddConfigMenu(self, appInitial):
+        self.appButtons[ appInitial.GetName() ].AddConfigMenu(appInitial)
+    
+    # once the 40001 message arrives and the app doesnt exists yet, create an instance button for it
+    def AddInstanceButton(self, sageApp):
+        if sageApp.getName() in self.appButtons:
+            self.appButtons[ sageApp.getName() ].AddInstanceButton(sageApp)
+
+    # once the 40003 message arrives and we close the app, remove the instance button for it
+    def RemoveInstanceButton(self, sageApp):
+        if sageApp.getName() in self.appButtons:
+            self.appButtons[ sageApp.getName() ].RemoveInstanceButton(sageApp.getId())
+            self.GetAppInfoPanel().GetInfoPanel().OnPerfPanelRemoved(sageApp.getId())
+
+
+
+
+        
+############################################################################
+#
+#  CLASS: InfoPanel
+#  
+#  DESCRIPTION: It describes the canvas that holds all the buttons for
+#               starting and stopping SAGE apps from within the SAGE UI.
+#               It also draws all the graphics that is used instead of the
+#               regular wx controls. It handles button clicks and other app
+#               specific actions. It does all the drawing with double buffering.
+#
+#  DATE:        April, 2005
+#
+############################################################################
+
+class InfoPanel(wx.Panel):
+
+    def __init__(self, parent, width, height, x, y):
+        wx.Panel.__init__(self, parent, -1, (x,y), (width,height), wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
+        self.SetBackgroundColour(appPanelColor)
+        self.page = parent.parent
+        self.parent = parent
+        self.SetVirtualSize( (width, height) )
+        self.visible = True
+        self._minWidth = 250
+        self.width = 0 #initial width  
+        self.displayCanvas = self.page.GetDisplayCanvas()
+        self.dataPanels = []
+        
+        self.background = MyImage( "images/app_panel_background.png", 0,0, False, width, height)
+        
+        if "__WXMSW__" in wx.PlatformInfo:  # this is needed on windows for proper painting after resize
+            self.Bind(wx.EVT_SIZE, self.OnSize)
+        elif "__WXGTK__" in wx.PlatformInfo:
+            self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, self.Chillout)
+        
+    #----------------------------------------------------------------------
+
+    def Chillout(self, event):
+        """ For intercepting the EVT_ERASE_BACKGROUND. Do nothing here on purpose
+            in order to reduce the flicker during drawing"""
+        pass
+
+
+    def OnPaint(self, event=None):
+        if not self.visible: dc=wx.PaintDC(self); return
+        if DEBUG: print "\tOnPaint --> InfoPanel"; sys.stdout.flush()
+        dc = wx.PaintDC(self)
+        self.PrepareDC(dc)
+      	self.Redraw(dc)
+
+   
+    def Redraw(self, dc=None):
+        if not self.visible: return
+        if DEBUG: print "\tRedraw --> InfoPanel"; sys.stdout.flush()
+        if dc == None:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self)
+            self.PrepareDC(dc)
+        
+        if "__WXMSW__" in wx.PlatformInfo:
+            self.Refresh()
+            self.Update()
+
+        dc.DrawBitmap( self.background.bitmap, self.background.GetX(), self.background.GetY(), self.background.IsTransparent())
+        dc.SetBrush(wx.TRANSPARENT_BRUSH)
+        dc.SetPen(wx.BLACK_PEN)
+        dc.DrawRectangle(2, 2, self.GetClientSize()[0]-2, self.GetClientSize()[1]-2)
+        dc.SetPen(wx.Pen(wx.Colour(153, 153, 153)))
+        dc.DrawRectangle(0, 0, self.GetClientSize()[0]-2, self.GetClientSize()[1]-2)
+        del dc
+        
+
+        
+    def OnSize(self, event=None):
+        #if not self.visible: return
+        if DEBUG: print "\tOnSize --> InfoPanel"; sys.stdout.flush()
+        # get some measures that will help us determine the size of the panel
+        parentSize = self.GetAppInfoPanel().GetClientSize()
+        borderWidth = self.GetAppInfoPanel().GetDisplayCanvas().GetBorderWidth()
+        arrowWidth = self.GetAppInfoPanel().GetArrowWidth()
+
+        # the new size depends on if there is a dataPanel in there or not
+        # if not, the whole InfoPanel will be of default size
+        if not self.visible or self.GetDataPanelWidth() == 0:   #not visible, setting width to 0
+            newWidth = 0
+            self.Hide()
+        else:          #dataPanel, setting width to dataPanelWidth
+            self.Show()
+            newWidth = self.GetDataPanelWidth() + 7  #+5 added to allow for the border
+        newHeight = parentSize.height - 1.5*borderWidth
+
+        # apply the changes 
+        self.SetSize( (newWidth, newHeight) )
+        self.SetVirtualSize( (self.GetVirtualSize().width, self.GetVirtualSize().height) )
+        self.MoveXY( parentSize.width - borderWidth - newWidth, self.GetPosition().y)
+
+        # hide the little scrolly thingy button from the AppInfoPanel
+        if newHeight < 2:
+            self.GetAppInfoPanel().hideInfoPanelButton.Hide()
+        else:
+            self.GetAppInfoPanel().hideInfoPanelButton.Show()
+
+        #resize the background image
+        self.background.Rescale(newWidth, newHeight)
+        self.Redraw()
+        
+
+    #----------------------------------------------------------------------
+    
+
+    def Minimize(self):
+        self.visible = False
+        self.Hide()
+
+    def Maximize(self):
+        self.visible = True
+        self.Show()
+
+    def GetCurrentMinSize(self):
+        if self.GetDataPanelWidth() == 0:  #no dataPanel, setting width to default
+            newWidth = self.GetMinimumWidth()
+        else:          #dataPanel, setting width to dataPanelWidth
+            newWidth = self.GetDataPanelWidth()
+        return newWidth
+
+    def GetAppInfoPanel(self):
+        return self.page.GetAppInfoPanel()
+    
+    def GetMinimumWidth(self):
+        return self._minWidth
+
+    def SetMinimumWidth(self, newMinWidth):
+        self._minWidth = newMinWidth
+
+        
+    #----------------------------------------------------------------------
+
+
+    # this shows all the data that's relevant to the app
+    def ShowData(self, appName, windowId):
+	if self.visible:
+	    self.ShowPerformanceData(appName, windowId)
+        
+
+        # shows the performance data panel in this InfoPanel
+    def ShowPerformanceData(self, appName, windowId):
+        if self.displayCanvas.GetGraphManager().GetSparklineGraph(windowId) == -1: #does the panel exist yet?
+            self.displayCanvas.GetGraphManager().addGraph(appName, windowId, self)
+            dataPanel = self.displayCanvas.GetGraphManager().GetSparklineGraph(windowId)
+            self.dataPanels.append(dataPanel)  # add it to the list of panels
+	    if len(self.dataPanels) < 2:
+		self.Freeze()
+		self.GetAppInfoPanel().OnSize()  #refresh/resize the panels
+		self.Thaw()
+        else:   #panel already exists so just show it on top of the other ones
+            dataPanel = self.displayCanvas.GetGraphManager().GetSparklineGraph(windowId)
+            self.Freeze()
+	    for p in self.dataPanels:  #hide all the other panels but show the one that's selected
+                try:
+                    p.Hide()
+                except Exception:  # an exception will occur if there are panels in the list that dont exist anymore
+                    del p  #this will delete it from the list as well
+            dataPanel.Show()
+	    self.Thaw()
+            #if not "__WXGTK__" in wx.PlatformInfo:  #extra refresh needed on Mac and Windows
+            #    self.GetAppInfoPanel().OnSize()
+
+            
+            # returns the width of the dataPanel, if none exist it returns a 0
+    def GetDataPanelWidth(self):
+        try:
+            width = self.dataPanels[0].GetSize().width
+        except Exception:
+            del self.dataPanels
+            self.dataPanels = []
+            return 0
+        else:
+            return width
+
+
+        # resizes the parent panel to a default size if there are no more perf panels in here
+    def OnPerfPanelRemoved(self, windowId):
+        dataPanel = self.displayCanvas.GetGraphManager().GetSparklineGraph(windowId)
+
+        try:
+            self.dataPanels.remove(dataPanel)
+        except Exception:
+            pass
+        else:
+            if len(self.dataPanels) < 1:
+                self.GetAppInfoPanel().OnSize()  #resize and refresh the parent panel
+
+
+
Index: trunk/src/testing/ui/pointers.py
===================================================================
--- trunk/src/testing/ui/pointers.py	(revision 4)
+++ trunk/src/testing/ui/pointers.py	(revision 4)
@@ -0,0 +1,488 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import wx, time
+from SAGEDrawObject import PointerObject
+
+
+class DeviceManager:
+    """ An object that brings all the devices under one roof and manages them """
+    def __init__(self, sageData, sageGate):
+        self.sageData = sageData
+        self.sageGate = sageGate
+        self.minAppSize = 250
+        self.pointers = {}  # key=pointerId, value=PointerObject
+
+
+    def __addPointerObject(self, pointerId):
+        if pointerId not in self.pointers:
+            self.pointers[pointerId] = PointerObject(pointerId, self.sageGate)
+        return self.pointers[pointerId]
+
+
+    def processMouseMove(self, pointerId, x, y):
+        ptr = self.__addPointerObject(pointerId)
+        (app, regionId) = self.sageData.checkHits(x,y)
+        if ptr.leftDown:
+            # release the mouse button after 15 secs
+            if time.time() - ptr.leftDownTime > 15:
+                self.processMouseUp(pointerId, x, y)
+            return
+        
+        ptr.updateRegion(regionId, app)
+        
+        if regionId > 0:
+            if ptr.lastRegion != ptr.region:  # corner
+                ptr.showResizePointer()
+        elif ptr.lastRegion[0] > 0:  # it was on a corner previously and now it's not
+            ptr.reset()
+            ptr.lastRegion = [regionId, app]
+            
+        #self.sageGate.movePointer(pointerId, dx, dy)
+
+        
+    def processMouseDown(self, pointerId, x, y):
+        ptr = self.__addPointerObject(pointerId)
+        (app, regionId) = self.sageData.checkHits(x,y)
+        if regionId < 0 or app.hasCapture():
+            return
+        
+        # record the info about this click
+        ptr.onMouseDown(app, regionId, x, y)
+
+        # process the click
+        if regionId == 0:
+            app.captureMouse(pointerId)
+            self.__handleAppWindowHit(pointerId, app.getId())
+        else:
+            app.captureMouse(pointerId)
+            self.__handleAppCornerHit(pointerId, app.getId(), regionId)
+
+
+        
+    def processMouseUp(self, pointerId, x, y):
+        ptr = self.__addPointerObject(pointerId)
+        if not ptr.leftDown: return
+        
+        ptr.onMouseUp()
+
+        if ptr.lastRegion[0] == 0:    # move
+            ptr.lastRegion[1].releaseMouse()
+            # bring the app to front if necessary and then move it
+            if self.sageData.getTopApp()[0] != ptr.lastRegion[1].getId():
+                self.sageGate.bringToFront(ptr.lastRegion[1].getId())
+            self.sageGate.moveWindow(ptr.lastRegion[1].getId(), x-ptr.clickPos[0], y-ptr.clickPos[1])
+            
+        elif ptr.lastRegion[0] > 0:   # resize
+            (l,r,t,b) = ptr.lastRegion[1].getBounds()
+            w = r-l
+            h = t-b
+            aspectRatio = w/float(h)
+            ptr.lastRegion[1].releaseMouse()
+            
+            # don't allow resizing below minAppSize
+            dx = x-ptr.clickPos[0]
+            if ptr.lastRegion[0] == 1:
+                l+=dx; b=b+dx/aspectRatio
+                if r-l < self.minAppSize: l = r - self.minAppSize
+                if t-b < self.minAppSize: b = t - self.minAppSize
+            elif ptr.lastRegion[0] == 2:
+                l+=dx; t=t-dx/aspectRatio 
+                if r-l < self.minAppSize: l = r - self.minAppSize
+                if t-b < self.minAppSize: t = b + self.minAppSize
+            elif ptr.lastRegion[0] == 3:
+                r+=dx; t=t+dx/aspectRatio
+                if r-l < self.minAppSize: r = l + self.minAppSize
+                if t-b < self.minAppSize: t = b + self.minAppSize
+            elif ptr.lastRegion[0] == 4:
+                r+=dx; b=b-dx/aspectRatio
+                if r-l < self.minAppSize: r = l + self.minAppSize
+                if t-b < self.minAppSize: b = t - self.minAppSize      
+           
+            self.sageGate.resizeWindow(ptr.lastRegion[1].getId(), l, r, b, t)
+        
+        
+
+    def __handleAppCornerHit(self, pointerId, windowId, cornerId):
+        """ a corner of a window was hit """
+        (l,r,t,b) = self.sageData.getApp(windowId).getBounds()
+        self.sageGate.setMouseResizeState(pointerId, cornerId, l, r, t, b)
+        
+
+    def __handleAppWindowHit(self, pointerId, windowId):
+        """ an app window was hit but not the corner """
+        (l,r,t,b) = self.sageData.getApp(windowId).getBounds()
+        self.sageGate.setMouseMoveState(pointerId, l, r, t, b)
+        
+
+
+
+
+
+class PollTimer(wx.Timer):
+    def SetCallback(self, cb):
+        self.callback = cb
+    def Notify(self):
+        self.callback()
+
+
+
+
+class Pointers:
+    """ main class that keeps track of and manages all the devices on this machine """
+    def __init__(self, sageGate, sageData):
+        self.sageGate = sageGate
+        self.sageData = sageData
+        self.dispSize = sageData.getSageDisplayInformation()[3:5]
+        self.devManager = DeviceManager(sageData, sageGate)
+
+        # out devices
+        self.numJoy = wx.Joystick().GetNumberJoysticks()
+        self.joysticks = {}
+        self.__addJoystick()
+##         self.mouse = None  # it will be MousePointer
+
+        # start the timer that will periodically poll the devices
+        self.t = PollTimer()
+        period = 50  # poll X times/sec (roughly)
+        self.t.SetCallback(self.poll)
+        self.t.Start(1000/period)
+
+
+    def __addJoystick(self):
+        self.sageGate.registerCallbackFunction( 40018, self.onNewJoystickDevice )
+        if len(self.joysticks) < self.numJoy:
+            self.sageGate.addPointer()
+##         else:
+##             print "adding a mouse!"
+##             self.sageGate.registerCallbackFunction( 40018, self.onNewMouseDevice )
+##             self.sageGate.addPointer()
+
+
+    def onNewJoystickDevice(self, data):
+        pointerId = int(data.split()[0])
+        self.joysticks[pointerId] = JoyPointer( self.dispSize, pointerId, \
+                                                len(self.joysticks), \
+                                                self.onButtonDown, self.onButtonUp )
+        self.sageGate.showObject(pointerId)
+        if len(self.joysticks) < self.numJoy:  #add another one
+            self.sageGate.addPointer()
+##         else:   # finally add a mouse
+##             self.sageGate.registerCallbackFunction( 40018, self.onNewMouseDevice )
+##             self.sageGate.addPointer()
+            
+
+##     def onNewMouseDevice(self, data):
+##         pointerId = int(data.split()[0])
+##         self.sageGate.showObject(pointerId)
+##         self.mouse = MousePointer(self.dispSize, pointerId, self.onButtonDown, self.onButtonUp)
+        
+
+##     def shareMouse(self):
+##         if self.mouse:
+##             self.mouse.start()
+        
+
+    def stop(self):
+        if self.t.IsRunning():
+            self.t.Stop()
+
+        for pointerId in self.joysticks.iterkeys():
+            self.sageGate.removePointer(pointerId)
+        ## if self.mouse:
+##             self.sageGate.removePointer(self.mouse.getId())
+
+
+    def onButtonDown(self, pointerId, btn, x, y):
+        self.devManager.processMouseDown(pointerId, x, y)
+
+
+    def onButtonUp(self, pointerId, btn, x, y):
+        self.devManager.processMouseUp(pointerId, x, y)
+
+        
+    def poll(self):
+        """ here we poll the device just for their position
+            the button clicks are dealt with through event handling
+        """
+        for id, joy in self.joysticks.iteritems():
+            dX, dY = joy.getPos()
+            if dX != 0 or dY != 0: 
+                self.devManager.processMouseMove(id, joy.getX(), joy.getY())
+                self.sageGate.movePointer(id, dX, dY)
+
+##         if self.mouse and self.mouse.isShared():
+##             dX, dY = self.mouse.getPos()
+##             if dX != 0 or dY != 0: 
+##                 self.devManager.processMouseMove(self.mouse.getId(), self.mouse.getX(), self.mouse.getY())
+##                 print "moving pointer to", dX, dY
+##                 self.sageGate.movePointer(self.mouse.getId(), dX, dY)
+
+
+
+class JoyPointer:
+    def __init__(self, dispSize, pointerId, deviceId, onDown, onUp):
+        self.dispSize = dispSize
+        self.pointerId = pointerId
+        self.onDown = onDown
+        self.onUp = onUp
+        self.x = self.y = 100
+
+        # the top frame will capture all our joystick events
+        self.win = wx.GetApp().GetTopWindow()
+        self.joy = wx.Joystick(deviceId)
+        self.joy.SetCapture(self.win)
+        self.win.Bind(wx.EVT_JOY_BUTTON_DOWN, self.onButton)
+        self.win.Bind(wx.EVT_JOY_BUTTON_UP, self.onButton)
+        
+        # analog axis parameters and calibration values
+        # we'll make an assumption that both axis have the
+        # same range of values
+        xmin = self.joy.GetXMin()
+        xmax = self.joy.GetXMax()
+        rng = abs(xmax - xmin)
+        self.centerX = abs( int((xmin + xmax)/2)) #so that 0 <-> max and -max/2 <-> max/2 both work
+        self.drift = int(0.08*rng)
+        self.usefulRange = abs( int( rng/2 - self.drift) )
+
+        # for converting the movement from joystick axis position
+        # to pixel distance on the SAGE display
+        # it depends on the joystick position AND on the display size
+        joyToMouseRatio = 70
+        displayFactor = dispSize[0] / 10000.0 + 0.2
+        self.moveRatio = joyToMouseRatio * displayFactor
+
+
+    def getId(self):
+        return self.pointerId
+    
+
+    def getX(self):
+        return self.x
+
+
+    def getY(self):
+        return self.y
+
+
+    def onButton(self, evt):
+        """ left=1, right=2, middle=3 """
+        btn = -1
+        
+        if evt.GetButtonChange() == 0:                 btn = 1
+        elif evt.GetButtonChange() == wx.JOY_BUTTON1:  btn = 2       
+        elif evt.GetButtonChange() == wx.JOY_BUTTON2:  btn = 3
+        elif evt.GetButtonChange() == wx.JOY_BUTTON3:  btn = 4
+        if btn == -1: return  #dont act on any other button
+        
+        if evt.ButtonUp():
+            self.onUp(self.pointerId, btn, self.x, self.y)
+        else:
+            self.onDown(self.pointerId, btn, self.x, self.y)
+        
+        
+    def getPos(self):
+        """ returns (x, y) """
+
+        # get the analog axis position and map it to some
+        # pixel distance in sage coordinates
+        (dx,dy) = self.joy.GetPosition()
+        (dx,dy) = self.toSAGECoords(dx,dy)
+        
+        dx = int(round(dx))
+        dy = int(round(dy))
+        
+        # keep the pointer inside the display
+        if self.x + dx < 0:
+            dx = -self.x
+        elif self.x + dx > self.dispSize[0]:
+            dx = self.dispSize[0] - self.x
+        if self.y + dy < 0:
+            dy = -self.y
+        elif self.y + dy > self.dispSize[1]:
+            dy = self.dispSize[1] - self.y
+
+        # accumulate the position
+        self.x += dx
+        self.y += dy
+        
+        return dx, dy
+
+            
+    def toSAGECoords(self, x, y):
+        # first map the values from 0-max to -max/2 to max/2 (if needed)
+        x -= self.centerX
+        y -= self.centerX
+
+        # apply the movement threshold and get the normalized crds
+        if abs(x) <= self.drift:
+            x = 0
+        else:
+            if x > 0:  x = float(x-self.drift)/self.usefulRange
+            else: x = float(x+self.drift)/self.usefulRange
+            x *= self.moveRatio #50
+
+        if abs(y) <= self.drift:
+            y = 0
+        else:
+            if y > 0:  y = float(y-self.drift)/self.usefulRange
+            else: y = float(y+self.drift)/self.usefulRange
+            y *= -self.moveRatio #(-50)
+
+        return (x,y)
+
+
+
+    
+## class MousePointer:
+##     def __init__(self, dispSize, pointerId, onDown, onUp):
+##         self.dispSize = dispSize
+##         self.pointerId = pointerId
+##         self.onDown = onDown
+##         self.onUp = onUp
+##         self.screenSize = wx.GetDisplaySize()
+##         self.frame = wx.GetApp().GetTopWindow()
+
+##         # figure out the mapping between the local screen and the display
+##         i = self.dispSize.index( max(self.dispSize[0], self.dispSize[1]) )
+##         self.moveRatio = self.dispSize[i] / float(self.screenSize[i])
+##         self.x = self.y = 100
+##         self.__shared = False
+
+        
+##     def getX(self):
+##         return self.x
+
+
+##     def getY(self):
+##         return self.y
+
+
+##     def getId(self):
+##         return self.pointerId
+
+
+##     def isShared(self):
+##         return self.__shared
+    
+
+##     def makeControls(self):
+##         winSize = (400, 200)
+##         winPos = (self.screenSize[0]/2 - winSize[0]/2, self.screenSize[1]/2 - winSize[1]/2)
+##         self.dlg = wx.Frame(self.frame, wx.ID_ANY, "", \
+##                              winPos, winSize)
+##         self.dlg.Bind(wx.EVT_CLOSE, self.onClose)
+##         self.dlg.Bind(wx.EVT_KEY_DOWN, self.onKey)
+##         self.dlg.Bind(wx.EVT_LEFT_DOWN, self.onButton)
+##         self.dlg.Bind(wx.EVT_RIGHT_DOWN, self.onButton)
+##         self.dlg.Bind(wx.EVT_MIDDLE_DOWN, self.onButton)
+##         self.dlg.Bind(wx.EVT_LEFT_UP, self.onButton)
+##         self.dlg.Bind(wx.EVT_RIGHT_UP, self.onButton)
+##         self.dlg.Bind(wx.EVT_MIDDLE_UP, self.onButton)
+        
+##         sizer = wx.BoxSizer(wx.VERTICAL)
+##         label = wx.StaticText(self.dlg, wx.ID_ANY, "Press ESC to stop sharing your mouse")
+##         sizer.Add(label, 0, wx.ALIGN_CENTER | wx.BOTTOM | wx.LEFT | wx.RIGHT, border=5)
+##         self.dlg.SetSizer(sizer)
+##         self.dlg.CaptureMouse()
+##         self.__shared = True
+##         self.dlg.Show()
+
+
+##     def onClose(self, evt):
+##         self.stop()
+        
+
+##     def onKey(self, evt):
+##         if evt.GetKeyCode() == wx.WXK_ESCAPE:
+##             self.Close(True)
+##         else:
+##             evt.Skip()
+
+
+##     def onButton(self, evt):
+##         btn = -1
+##         if evt.Button(wx.MOUSE_BTN_LEFT):     btn = 1
+##         elif evt.Button(wx.MOUSE_BTN_RIGHT):  btn = 2
+##         elif evt.Button(wx.MOUSE_BTN_MIDDLE): btn = 3
+
+##         if btn == -1: return  #dont act on any other button
+        
+##         if evt.ButtonUp():
+##             self.onUp(self.pointerId, btn, self.x, self.y)
+##         else:
+##             self.onDown(self.pointerId, btn, self.x, self.y)
+            
+
+##     def start(self):
+##         self.makeControls()
+        
+
+##     def stop(self):
+##         self.__shared = False
+##         if self.dlg.HasCapture():
+##             self.dlg.ReleaseMouse()
+##         self.dlg.Destroy()
+
+
+##     def getPos(self):
+##         # get the new mouse position and figure out how
+##         # much it moved in sage coordinates
+##         p = wx.GetMousePosition().Get()
+##         newPos = [ int(p[0]*self.moveRatio), int(p[1]*self.moveRatio) ]
+##         dx = newPos[0] - self.x
+##         dy = newPos[1] - self.y
+        
+##         # keep the pointer inside the display
+##         if self.x + dx < 0:
+##             dx = -self.x
+##         elif self.x + dx > self.dispSize[0]:
+##             dx = self.dispSize[0] - self.x
+##         if self.y + dy < 0:
+##             dy = -self.y
+##         elif self.y + dy > self.dispSize[1]:
+##             dy = self.dispSize[1] - self.y
+            
+##         # accumulate the position
+##         self.x += dx
+##         self.y += dy
+        
+##         return dx, dy
+            
Index: trunk/src/testing/ui/misc/__init__.py
===================================================================
--- trunk/src/testing/ui/misc/__init__.py	(revision 4)
+++ trunk/src/testing/ui/misc/__init__.py	(revision 4)
@@ -0,0 +1,2 @@
+### miscellaneous 3rd party modules used by SAGE UI
+__all__ = ["pyDes", "imsize"]
Index: trunk/src/testing/ui/misc/imsize.py
===================================================================
--- trunk/src/testing/ui/misc/imsize.py	(revision 4)
+++ trunk/src/testing/ui/misc/imsize.py	(revision 4)
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+# (c) Copyright 2001-2005 Hewlett-Packard Development Company, L.P.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Author: Don Welch
+# Ported from Perl's Image::Size module by Randy J. Ray
+# Modified by Perenzo, 2006
+
+import os, os.path, re, struct
+
+xbm_pat = re.compile(r'^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)', re.IGNORECASE)
+xpm_pat = re.compile(r'"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"', re.IGNORECASE)
+ppm_pat1 = re.compile(r'^\#.*', re.IGNORECASE | re.MULTILINE)
+ppm_pat2 = re.compile(r'^(P[1-6])\s+(\d+)\s+(\d+)', re.IGNORECASE)
+ppm_pat3 = re.compile(r'IMGINFO:(\d+)x(\d+)', re.IGNORECASE)
+tiff_endian_pat = re.compile(r'II\x2a\x00')
+
+def readin(stream, length, offset=0):
+    if offset != 0:
+        stream.seek(offset, 0)
+    return stream.read(length)
+
+def xbmsize(stream):
+    width, height = -1, -1
+    match = xbm_pat.match(readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def xpmsize(stream):
+    width, height = -1, -1
+    match = re.search(xpm_pat, readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def pngsize(stream): # also does MNG
+    width, height = -1, -1
+    if readin(stream, 4, 12) in ('IHDR', 'MHDR'):
+        height, width = struct.unpack("!II", stream.read(8))
+
+    return height, width #width, height
+
+def jpegsize(stream):
+    width, height = -1, -1
+    stream.seek(2)
+    while 1:
+        length = 4
+        buffer = readin(stream, length)
+        try:
+            marker, code, length = struct.unpack("!ccH", buffer)
+        except:
+            break
+        if marker != '\xff':
+            break
+        if 0xc0 <= ord(code) <= 0xc3:
+            length = 5
+            height, width = struct.unpack("!xHH", readin(stream, length))
+        else:
+            readin(stream, length-2)
+    return width, height
+
+def ppmsize(stream):
+    width, height = -1, -1
+    header = re.sub(ppm_pat1, '', readin(stream, 1024))
+    match = ppm_pat2.match(header)
+    typ = ''
+    try:
+        typ = match.group(1)
+        width = int(match.group(2))
+        height = int(match.group(3))
+    except:
+        pass
+    if typ == 'P7':
+        match = ppm_pat3.match(header)
+
+        try:
+            width = int(match.group(1))
+            height = int(match.group(2))
+        except:
+            pass
+    return width, height
+
+def tiffsize(stream):
+    header = readin(stream, 4)
+    endian = ">"
+    match = tiff_endian_pat.match(header)
+    if match is not None:
+        endian = "<"
+    input = readin(stream, 4, 4)
+    offset = struct.unpack('%si' % endian, input)[0]
+    num_dirent = struct.unpack('%sH' % endian, readin(stream, 2, offset))[0]
+    offset += 2
+    num_dirent = offset+(num_dirent*12)
+    width, height = -1, -1
+    while True:
+        ifd = readin(stream, 12, offset)
+        if ifd == '' or offset > num_dirent:
+            break
+        offset += 12
+        tag = struct.unpack('%sH'% endian, ifd[0:2])[0]
+        type = struct.unpack('%sH' % endian, ifd[2:4])[0]
+        if tag == 0x0100:
+            width = struct.unpack("%si" % endian, ifd[8:12])[0]
+        elif tag == 0x0101:
+            height = struct.unpack("%si" % endian, ifd[8:12])[0]
+    return width, height
+
+def bmpsize(stream):
+    width, height = struct.unpack("<II", readin(stream, 8, 18))
+    return width, height
+
+def gifsize(stream):
+    # since we only care about the printed size of the image
+    # we only need to get the logical screen sizes, which are
+    # the maximum extents of the image. This code is much simpler
+    # than the code from Image::Size
+    #width, height = -1, -1
+    buf = readin(stream, 7, 6) # LSx, GCTF, etc
+    height, width, flags, bci, par = struct.unpack('<HHBBB', buf)
+    return height, width #width, height
+
+TYPE_MAP = { re.compile('^GIF8[7,9]a')              : ('image/gif', gifsize),
+             re.compile("^\xFF\xD8")                : ('image/jpeg', jpegsize),
+             re.compile("^\x89PNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+             re.compile("^P[1-7]")                  : ('image/x-portable-pixmap', ppmsize),
+             re.compile('\#define\s+\S+\s+\d+')     : ('image/x-xbitmap', xbmsize),
+             re.compile('\/\* XPM \*\/')            : ('image/x-xpixmap', xpmsize),
+             re.compile('^MM\x00\x2a')              : ('image/tiff', tiffsize),
+             re.compile('^II\*\x00')                : ('image/tiff', tiffsize),
+             re.compile('^BM')                      : ('image/x-bitmap', bmpsize),
+             re.compile("^\x8aMNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+           }
+
+def imagesize(filename, mime_type=''):
+    width, height = -1, -1
+    f = file(filename, 'rb')
+    buffer = f.read(4096)
+    if not mime_type:
+        for t in TYPE_MAP:
+            match = t.search(buffer)
+            if match is not None:
+                mime_type, func = TYPE_MAP[t]
+                break
+    if mime_type and func:
+        f.seek(0)
+        width, height = func(f)
+    else:
+        width, height = -1, -1
+    f.close()
+    return height, width, mime_type
+
+if __name__=="__main__":
+    import sys
+    print imagesize(sys.argv[1])
Index: trunk/src/testing/ui/Mywx.py
===================================================================
--- trunk/src/testing/ui/Mywx.py	(revision 4)
+++ trunk/src/testing/ui/Mywx.py	(revision 4)
@@ -0,0 +1,871 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import wx, os, os.path, socket, math
+from globals import *
+import wx.lib.foldpanelbar as fpb
+import preferences as prefs
+
+
+############################################################################
+#
+#  CLASS: MyImage
+#  
+#  DESCRIPTION: This is just a data storage class for decorative bitmaps used
+#               in the ui. You need to pass it a bitmap and optionally position,
+#               transparency and new size. If the new size is passed in, the
+#               bitmap will be automatically resized to that size.
+#
+#  DATE:        March, 2005
+#
+############################################################################
+
+class MyImage(wx.Object):
+
+    def __init__(self, bitmap, x=0, y=0, transparent=False, resizeWidth=0, resizeHeight=0):
+        self.image = wx.Image(ConvertPath(str(bitmap)))
+        self.x = x
+        self.y = y
+        self.transparent = transparent
+        if resizeHeight != 0:  # you can resize the image during creation
+            self.Rescale(resizeWidth, resizeHeight)
+        else:
+            self.bitmap = wx.BitmapFromImage(self.image)#.ConvertToBitmap()
+
+    def GetBitmap(self):
+        return self.bitmap
+
+    def GetWidth(self):
+        return self.bitmap.GetWidth()
+
+    def GetHeight(self):
+        return self.bitmap.GetHeight()
+
+    def SetX(self, x):
+        self.x = x
+
+    def SetY(self, y):
+        self.y = y
+
+    def GetY(self):
+        return self.y
+
+    def GetX(self):
+        return self.x
+
+    def IsTransparent(self):
+        return self.transparent
+
+    def Rescale(self, newWidth, newHeight):
+        if newWidth < 1:
+            newWidth = 1
+        if newHeight < 1:
+            newHeight = 1
+        self.bitmap = wx.BitmapFromImage(self.image.Rescale( round(newWidth), round(newHeight) ))#.ConvertToBitmap()
+        return self.bitmap
+
+
+    def Recalculate(self, newWidth, newHeight, x=-1, y=-1):
+        # set the position if it was passed in
+        if x != -1:
+            self.x = x
+        if y != -1:
+            self.y = y
+            
+        return self.Rescale(newWidth, newHeight)
+
+
+    def Hide(self):
+        if not self.IsTransparent():
+            self.transparent = True
+
+    def Show(self):
+        if self.IsTransparent():
+            self.transparent = False
+
+
+############################################################################
+#
+#  CLASS: MyBitmapButton
+#  
+#  DESCRIPTION: A template class for a bitmap button. It handles the images,
+#               resizes them and changes them based on the state of the button.
+#               It also handles basic painting (just draws the button on the
+#               screen). All bitmap buttons should extend this class and
+#               override some methods for specific behavior. In most cases
+#               OnLeftUp() will have to be overwritten to define what happens
+#               on a mouse click. In your overwride a method make sure you call
+#               the same named method of this class since that will visually
+#               update the button.
+#
+#  DATE:        March, 2005
+#
+############################################################################
+
+class MyBitmapButton(wx.Window):
+
+    def __init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap=None, over_bitmap=None, tTip="", id=-1 ):        
+        # call the superclass' constructor
+        wx.Window.__init__(self, parent, id, (x,y), (resizeWidth, resizeHeight), wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE)
+        self.parent = parent
+
+        self.tTip = tTip
+        
+        if self.tTip != "":
+            self.toolTip = wx.ToolTip( self.tTip )
+            self.toolTip.SetDelay( 100 )
+            self.SetToolTip( self.toolTip )
+
+        self.resizeWidth = resizeWidth
+        self.resizeHeight = resizeHeight
+
+        # get the images and rescale them
+        if down_bitmap == None:
+            down_bitmap = up_bitmap
+        self.up_image = wx.Image(ConvertPath( str(up_bitmap) ))
+        self.down_image = wx.Image(ConvertPath( str(down_bitmap) ))
+        self.up_bitmap = self.RescaleBitmap(self.up_image, resizeWidth, resizeHeight)
+        self.down_bitmap = self.RescaleBitmap(self.down_image, resizeWidth, resizeHeight)
+        if over_bitmap:
+            self.over_image = wx.Image(ConvertPath( str(over_bitmap) ))
+            self.over_bitmap = self.RescaleBitmap(self.over_image, resizeWidth, resizeHeight)
+        self.currentImage = self.up_image
+        self.currentBitmap = self.up_bitmap
+
+        # register events and the event handlers
+        self.Bind( wx.EVT_LEFT_UP, self.OnLeftUp )
+        self.Bind( wx.EVT_LEFT_DOWN, self.OnLeftDown )
+        self.Bind( wx.EVT_RIGHT_UP, self.OnRightUp )
+        self.Bind( wx.EVT_RIGHT_DOWN, self.OnRightDown )
+        self.Bind( wx.EVT_ENTER_WINDOW, self.OnMouseEnter )
+        self.Bind( wx.EVT_LEAVE_WINDOW, self.OnMouseLeave )
+        self.Bind( wx.EVT_PAINT, self.OnPaint )
+        self.Bind( wx.EVT_ERASE_BACKGROUND, self.Chillout)
+
+
+    def Chillout(self, event):
+        pass   # this intercepts the ERASE_BACKGROUND event and therefore minimizes the flicker
+
+
+    def Rescale(self, newWidth, newHeight):
+        self.up_bitmap = self.RescaleBitmap(self.up_image, newWidth, newHeight)
+        self.down_bitmap = self.RescaleBitmap(self.down_image, newWidth, newHeight)
+        self.currentBitmap = self.RescaleBitmap(self.currentImage, newWidth, newHeight)
+        if hasattr(self, "over_bitmap"):
+            self.over_bitmap = self.RescaleBitmap(self.over_image, newWidth, newHeight)
+        self.SetSize( (newWidth, newHeight) )
+            
+    def RescaleBitmap(self, image, newWidth, newHeight):
+        if newWidth < 1:
+            newWidth = 1
+        if newHeight < 1:
+            newHeight = 1
+        bitmap = wx.BitmapFromImage(image.Rescale( round(newWidth), round(newHeight) )) #.ConvertToBitmap()
+        return bitmap
+
+
+    def SetUpBitmap(self, newBitmap):
+        self.up_image = wx.Image(ConvertPath( str(newBitmap) ))
+        self.up_bitmap = self.RescaleBitmap(self.up_image, self.resizeWidth, self.resizeHeight)
+
+    def SetDownBitmap(self, newBitmap):
+        self.down_image = wx.Image(ConvertPath( str(newBitmap) ))
+        self.down_bitmap = self.RescaleBitmap(self.down_image, self.resizeWidth, self.resizeHeight)
+
+    def SetOverBitmap(self, newBitmap):
+        self.over_image = wx.Image(ConvertPath( str(newBitmap) ))
+        self.over_bitmap = self.RescaleBitmap(self.over_image, self.resizeWidth, self.resizeHeight)
+
+        
+    #  event handlers
+    def OnPaint(self, event=None):
+        if not event == None:    
+            dc = wx.PaintDC(self)
+        else:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self)
+        dc.DrawBitmap( self.currentBitmap, 0, 0, True )
+
+    def OnMouseEnter(self, event):        
+        if hasattr(self, "over_bitmap"):
+            self.currentBitmap = self.over_bitmap
+            self.currentImage = self.over_image
+            self.OnPaint() 
+        
+    def OnMouseLeave(self, event):
+        self.currentBitmap = self.up_bitmap
+        self.currentImage = self.up_image
+        self.OnPaint()
+    
+    def OnLeftUp(self, event):
+        self.currentBitmap = self.up_bitmap
+        self.currentImage = self.up_image
+        self.OnPaint()
+
+    def OnLeftDown(self, event):
+        self.currentBitmap = self.down_bitmap
+        self.currentImage = self.down_image
+        self.OnPaint()
+
+    def OnRightUp(self, event):
+        self.currentBitmap = self.up_bitmap
+        self.currentImage = self.up_image
+        self.OnPaint()
+
+    def OnRightDown(self, event):
+        self.currentBitmap = self.down_bitmap
+        self.currentImage = self.down_image
+        self.OnPaint()
+        
+        
+            
+
+
+############################################################################
+#
+#  CLASS: AppButton
+#  
+#  DESCRIPTION: This class describes the buttons with which you start apps.
+#               It extends MyBitmapButton and adds a few methods for specific
+#               stuff. Also, all the app buttons are anchors for all the
+#               instances of that particular application. This class creates,
+#               positions and draws all of the InstanceButtons.
+#
+#  DATE:        March, 2005
+#
+############################################################################
+
+class AppButton(MyBitmapButton):    
+
+    def __init__(self, parent, up_bitmap, down_bitmap, over_bitmap, (x,y), (resizeWidth, resizeHeight), app):
+        tTip = "-- "+app.GetName().upper()+" --\nLEFT click to start application normally.\nRIGHT click to start the application through sageBridge for sharing."
+        if not os.path.isfile(over_bitmap):
+            over_bitmap = up_bitmap
+        MyBitmapButton.__init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap, over_bitmap, tTip)#app.GetName() )
+        self.SetName( app.GetName() )
+        self.app = app
+        self.leftClick = True   #a hack to detect which mouse button was clicked (used in config menu popup)
+        self.instanceButtons = {}  #keyed by windowId
+
+    
+    def AddConfigMenu(self, app):
+        # make the config popup menu (ids of the menuItems are the config numbers)
+        self.configMenu = wx.Menu()
+        num = 1
+        configs = self.app.GetConfigNames()
+        configs.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        for configName in configs:
+            menuItem = self.configMenu.Append( num, configName )
+            self.configMenu.Bind(wx.EVT_MENU, self.OnConfigMenuItem, menuItem)
+            num+=1
+            #self.configMenu.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuItemHighlight, menuItem)
+        #self.configMenu.Bind(wx.EVT_MENU_CLOSE, self.OnCloseMenu)
+            
+
+    def AddInstanceButton(self, sageApp):
+        size = (16, 30)
+        x = self.GetPosition().x + (self.GetSize().GetWidth() - size[0]) / 2
+        y = self.GetPosition().y + self.GetSize().GetHeight() + len(self.instanceButtons)*size[1]
+        self.instanceButtons[ sageApp.getId() ] = InstanceButton(self, (x,y), size, "images/inst_up.jpg", "images/inst_up.jpg", "images/inst_down.jpg", sageApp)
+        self.OnPaint()
+
+    def RemoveInstanceButton(self, windowId):
+        self.instanceButtons[ windowId ].Destroy()  #remove the InstanceButton
+        del self.instanceButtons[ windowId ]  #remove it from the hash
+        self.OnPaint()
+
+
+    #  EVENT HANDLERS
+    def OnPaint(self, event=None):
+        if not event == None:    
+            dc = wx.PaintDC(self.parent)
+            MyBitmapButton.OnPaint(self, event)
+        else:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self.parent)
+            MyBitmapButton.OnPaint(self)
+        
+        # then draw the instance buttons (update their position first)
+        yOffset = 0
+        for id, instance in self.instanceButtons.iteritems():
+            instance.MoveXY( self.GetPosition().x + (self.GetSize().GetWidth() - instance.GetSize().GetWidth()) / 2,
+                             self.GetPosition().y + self.GetSize().GetHeight() + yOffset*instance.GetSize().GetHeight())
+            yOffset = yOffset + 1
+            instance.Refresh()#OnPaint(event)
+
+        
+    def OnConfigMenuItem(self, event):
+        self.currentBitmap = self.up_bitmap
+        configName = self.configMenu.GetLabel(event.GetId())
+
+	# check if the user pressed on a vnc button... if so, add some vnc specific params
+	if self.GetName().lower().find("vnc") == -1:
+            if self.leftClick:
+                res = self.parent.parent.sageGate.executeApp(self.GetName(), configName)
+            else:
+                res = self.parent.parent.sageGate.executeApp(self.GetName(), configName, useBridge=True)
+	else:
+	    myIP = socket.gethostbyname(socket.gethostname())
+	    displayNum = "0"
+	    displaySize = wx.DisplaySize()
+            res = self.__ShowSimpleVNCDialog(myIP, displayNum, displaySize)
+            if res: params=res[1]; displaySize=res[0]
+            else: return
+
+            if self.leftClick:
+                res = self.parent.parent.sageGate.executeApp(self.GetName(), configName, size=displaySize, optionalArgs=params)
+            else:
+                res = self.parent.parent.sageGate.executeApp(self.GetName(), configName, size=displaySize, optionalArgs=params, useBridge=True)
+
+        if res == -1:
+            Message("Application not started. Either application failed or the application launcher is not running", "Application Launch Failed")
+
+
+##     def __EncryptPassword(self, passwd):
+##         key = chr(23)+chr(82)+chr(107)+chr(6)+chr(35)+chr(78)+chr(88)+chr(7)
+##         obj = pyDes.des(key, pyDes.CBC, "\0\0\0\0\0\0\0\0")
+##         string = obj.encrypt(passwd, "\0")
+##         #print "string = ",string.decode("ascii")#, 'replace')
+##         return string.decode("utf-16")#, 'replace')
+
+
+    def __ShowSimpleVNCDialog(self, myIP, displayNum, displaySize):#, password):
+        def __CaptureReturn(event):
+            if event.GetKeyCode() == wx.WXK_RETURN or event.GetKeyCode() == wx.WXK_NUMPAD_ENTER:
+                dialog.EndModal(wx.ID_OK)
+            else:
+                event.Skip()
+                
+        # make the dialog
+        if "__WXMSW__" in wx.PlatformInfo:
+            dialog = wx.Dialog(self, wx.ID_ANY, "Desktop Sharing")
+        else:
+            dialog = wx.Dialog(self, wx.ID_ANY, "Desktop Sharing", style=wx.RESIZE_BORDER | wx.CLOSE_BOX)
+        dialog.SetBackgroundColour(dialogColor)
+        dialog.SetForegroundColour(wx.WHITE)
+
+        # make the control
+        ipText = wx.StaticText(dialog, wx.ID_ANY, "IP Address:")
+        ipField = wx.TextCtrl(dialog, wx.ID_ANY, myIP)
+        displayNumText = wx.StaticText(dialog, wx.ID_ANY, "Display Number:")
+        displayNumField = wx.TextCtrl(dialog, wx.ID_ANY, displayNum)
+        sizeText = wx.StaticText(dialog, wx.ID_ANY, "Screen Size:")
+        widthText = wx.StaticText(dialog, wx.ID_ANY, "W")
+        widthField = wx.TextCtrl(dialog, wx.ID_ANY,str(displaySize[0]))
+        heightText = wx.StaticText(dialog, wx.ID_ANY, "H")
+        heightField = wx.TextCtrl(dialog, wx.ID_ANY,str(displaySize[1]))
+        passwordText = wx.StaticText(dialog, wx.ID_ANY, "Password:")
+        passwordField = wx.TextCtrl(dialog, wx.ID_ANY, style=wx.TE_PASSWORD)
+        passwordField.SetFocus()
+        passwordField.Bind(wx.EVT_KEY_DOWN, __CaptureReturn)
+        okBtn = wx.Button(dialog, wx.ID_OK, "Share Desktop")
+
+        # layout (sizers)
+        horSizer = wx.BoxSizer(wx.HORIZONTAL)
+        horSizer.Add(widthText, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, border=3)
+        horSizer.Add(widthField, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, border=3)
+        horSizer.Add(heightText, 0, wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP, border=3)
+        horSizer.Add(heightField, 0, wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT, border=3)
+        
+        gridSizer = wx.FlexGridSizer(4, 2, 2, 4)
+        gridSizer.AddMany([ (ipText, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.TOP, 3), (ipField, 0, wx.EXPAND),
+                     (displayNumText, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.TOP, 3), (displayNumField, 0, wx.EXPAND),
+                     (sizeText, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.TOP, 3), (horSizer, 0),
+                     (passwordText, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.TOP, 3), (passwordField, 0, wx.EXPAND)
+                   ])
+        gridSizer.AddGrowableCol(0)
+
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(gridSizer, 1, wx.ALIGN_LEFT | wx.EXPAND | wx.ALL, border=5)
+        mainSizer.Add(okBtn, 0, wx.ALIGN_CENTRE | wx.BOTTOM | wx.TOP, border=10)
+
+        # do the size stuff with some corrections because of the FoldPanelBar complications
+        dialog.SetSizer(mainSizer)
+        dialog.Fit()
+
+        # show it and get the result
+        if dialog.ShowModal() == wx.ID_OK:
+            ip = ipField.GetValue().strip()
+            dispNum = displayNumField.GetValue().strip()
+            w = widthField.GetValue().strip()
+            h = heightField.GetValue().strip()
+            passwd = passwordField.GetValue().strip()
+            return ((int(w),int(h)), (ip+" "+dispNum+" "+w+" "+h+" "+ passwd))
+        else:
+            return False
+
+
+
+
+    def __ShowVNCDialog(self, myIP, displayNum, displaySize, password):
+        def __OnStateChange(evt):
+            isExpanded = evt.GetFoldStatus()
+            s = dialog.GetSize()
+            if isExpanded:
+                dialog.SetSize((s[0], s[1]-150))
+            else:
+                dialog.SetSize((s[0], s[1]+150))
+            evt.Skip()
+
+        def __GetControlValues():
+            ip = ipField.GetValue()
+            dispNum = displayNumField.GetValue()
+            size = sizeField.GetValue().lower()
+            if "x" in size:
+                size = size.split("x")
+            elif "*" in size:
+                size = size.split("*")
+            else:
+                size = (1024, 768)
+            passwd = passwordField.GetValue()
+            profile = profileField.GetValue()
+            return (ip, dispNum, (int(size[0]), int(size[1])), passwd, profile)
+
+        def __FillControls(profile):#, ip, dispNum, size, passwd):
+            (myIP, displayNum, displaySize, password) = prefs.vnc.GetProfile(profile)
+            ipField.SetValue(myIP)
+            displayNumField.SetValue(displayNum)
+            sizeField.SetValue(str(displaySize[0])+" x "+str(displaySize[1]))
+            passwordField.SetValue(password)
+            profileField.SetValue(profile)
+            
+        def __OnComboBox(evt):
+            __FillControls( profileCombo.GetStringSelection() )
+            
+
+        def __OnDelete(evt):
+            sel = profileCombo.GetStringSelection()
+            if sel == "My Desktop":
+                return  # do not allow the deletion of the default profile
+            prefs.vnc.DeleteProfile( sel )
+            profileCombo.Delete( profileCombo.GetSelection() )
+            profileCombo.SetSelection(0)
+            __FillControls( profileCombo.GetStringSelection() )
+                
+        if "__WXMSW__" in wx.PlatformInfo:
+            dialog = wx.Dialog(self, wx.ID_ANY, "VNC Setup")#, style=wx.CLOSE_BOX)
+        else:
+            dialog = wx.Dialog(self, wx.ID_ANY, "VNC Setup", style=wx.RESIZE_BORDER | wx.CLOSE_BOX)#, style=wx.CLOSE_BOX | wx.THICK_FRAME)
+
+
+        foldBar = fpb.FoldPanelBar(dialog, wx.ID_ANY)#, wx.DefaultPosition, wx.DefaultSize, fpb.FPB_DEFAULT_STYLE | fpb.FPB_VERTICAL)
+        foldBar.Bind(fpb.EVT_CAPTIONBAR, __OnStateChange)
+        foldPanel = foldBar.AddFoldPanel("Advanced Options", collapsed=True)
+        p = wx.Panel(foldPanel, wx.ID_ANY)
+
+        # store the default vnc values... or if the default already exists, load it
+        if prefs.vnc.ProfileExists("My Desktop"):
+            # compare the IPs of the current machine and the stored profile
+            # if they are the same, use those values, otherwise use the detected values
+            defaultProfile = prefs.vnc.GetProfile("My Desktop")
+            if defaultProfile[0] == myIP:
+                (myIP, displayNum, displaySize, password) = defaultProfile
+        prefs.vnc.AddProfile("My Desktop", myIP, displayNum, displaySize, password)
+        
+        # controls
+        text = wx.StaticText(dialog, wx.ID_ANY, "VNC Profile:")
+        profileCombo = wx.ComboBox(dialog, wx.ID_ANY, "My Desktop", choices=prefs.vnc.GetProfileList(), style=wx.CB_DROPDOWN|wx.CB_READONLY)
+        profileCombo.SetMinSize((130, profileCombo.GetSize()[1]))
+        dialog.Bind(wx.EVT_COMBOBOX, __OnComboBox)
+        
+        ipText = wx.StaticText(p, wx.ID_ANY, "The IP ADDRESS of the machine you are trying to show:")
+        ipField = wx.TextCtrl(p, wx.ID_ANY)
+        ipField.SetMinSize((100, ipField.GetSize()[1]))
+        displayNumText = wx.StaticText(p, wx.ID_ANY, "The DISPLAY NUMBER where the VNC server is running (Linux or Mac):")
+        displayNumField = wx.TextCtrl(p, wx.ID_ANY)
+        sizeText = wx.StaticText(p, wx.ID_ANY, "The SIZE of the desktop you are trying to show (width x height):")
+        sizeField = wx.TextCtrl(p, wx.ID_ANY)
+        passwordText = wx.StaticText(p, wx.ID_ANY, "The PASSWORD for your vnc server:")
+        passwordField = wx.TextCtrl(p, wx.ID_ANY, style=wx.TE_PASSWORD)
+        profileText = wx.StaticText(p, wx.ID_ANY, "Save this profile as: ")
+        profileField = wx.TextCtrl(p, wx.ID_ANY)
+        profileField.SetMinSize((100, profileField.GetSize()[1]))
+        deleteBtn = wx.Button(p, wx.ID_ANY, "Delete")
+        p.Bind(wx.EVT_BUTTON, __OnDelete)
+        okBtn = wx.Button(dialog, wx.ID_OK, "Show")
+        __FillControls("My Desktop")
+
+        # layout (sizers)
+        horSizer2 = wx.BoxSizer(wx.HORIZONTAL)
+        horSizer2.Add(text, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, border=10)
+        horSizer2.Add(profileCombo, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        
+        gridSizer = wx.FlexGridSizer(4, 2, 2, 0)
+        gridSizer.AddMany([ (ipText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL), (ipField, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL),
+                     (displayNumText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL), (displayNumField, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL),
+                     (sizeText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL), (sizeField, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL),
+                     (passwordText, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL), (passwordField, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
+                   ])
+        gridSizer.AddGrowableCol(0)
+
+        horSizer = wx.BoxSizer(wx.HORIZONTAL)
+        horSizer.Add((0,0), 1)
+        horSizer.Add(profileText, 0, wx.ALIGN_CENTER)
+        horSizer.Add(profileField, 0, wx.ALIGN_CENTER)
+        horSizer.Add((0,0), 1)
+        horSizer.Add(deleteBtn, 0, wx.ALIGN_RIGHT)
+
+        vertSizer = wx.BoxSizer(wx.VERTICAL)
+        vertSizer.Add(gridSizer, 1, wx.EXPAND | wx.ALIGN_TOP)
+        vertSizer.Add(horSizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_TOP | wx.TOP, border=5)
+        vertSizer.Add(wx.StaticLine(p), 0, wx.ALIGN_TOP | wx.EXPAND | wx.TOP, border=10)
+        
+        p.SetSizer(vertSizer)
+        p.Fit()
+        foldBar.AddFoldPanelWindow(foldPanel, p, fpb.FPB_ALIGN_LEFT)
+        
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        mainSizer.Add(horSizer2, 0, wx.ALIGN_LEFT | wx.LEFT | wx.TOP | wx.BOTTOM, border=10)
+        mainSizer.Add(foldBar, 1, wx.ALIGN_LEFT | wx.EXPAND | wx.ALL, border=5)
+        mainSizer.Add(okBtn, 0, wx.ALIGN_CENTRE | wx.BOTTOM | wx.TOP, border=10)
+
+        # do the size stuff with some corrections because of the FoldPanelBar complications
+        dialog.SetSizer(mainSizer)
+        dialog.Fit()
+        minS = vertSizer.GetMinSize()
+        s=dialog.GetSize()
+        if s[0] < minS: dialog.SetSize((minS[0]+20, s[1]+10))
+        
+        
+        # show it and get the result
+        if dialog.ShowModal() == wx.ID_OK:
+            (ip, dispNum, size, passwd, profile) = __GetControlValues()
+            (w, h) = size
+            prefs.vnc.AddProfile(profile, ip, dispNum, size, passwd)
+            return (size, (ip+" "+str(dispNum)+" "+str(w)+" "+str(h)+" "+ str(passwd))) #self.__EncryptPassword(str(passwd))))
+        else:
+            return False
+
+        
+    def OnLeftDown(self, event):
+        MyBitmapButton.OnLeftDown(self, event)
+        if "imageviewer" in self.GetName() or "mplayer" in self.GetName():
+            Message("You cannot start these directly. Please use the file library to show multimedia files (F2)", "")
+        else:
+            self.leftClick = True #a hack to detect which mouse button was clicked
+            self.PopupMenu(self.configMenu)#, event.GetPosition())
+            self.OnPaint()
+        
+
+    def OnRightDown(self, event):
+        MyBitmapButton.OnRightDown(self, event)
+        if "imageviewer" in self.GetName() or "mplayer" in self.GetName():
+            Message("You cannot start these directly. Please use the file library to show multimedia files (F2)", "")
+        else:
+            self.leftClick = False  #a hack to detect which mouse button was clicked
+            self.PopupMenu(self.configMenu)#, event.GetPosition())
+            self.OnPaint()
+
+
+
+
+class RemoteAppButton(MyBitmapButton):
+    def __init__(self, parent, up_bitmap, down_bitmap, over_bitmap, (x,y), (resizeWidth, resizeHeight), sageGate):
+        tTip = "-- REMOTE APPLICATIONS --\nLEFT click to start application normally.\nRIGHT click to start the application through sageBridge for sharing."
+        if not os.path.isfile(over_bitmap):
+            over_bitmap = up_bitmap
+        MyBitmapButton.__init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap, over_bitmap, tTip)
+        self.SetName("REMOTE APPLICATIONS")
+        self.sageGate = sageGate
+        self.leftClick = True   #a hack to detect which mouse button was clicked (used in config menu popup)
+        #self.AddLauncherMenu()
+
+        
+    def AddLauncherMenu(self):
+        self.launcherMenu = wx.Menu()
+        launcherHash = self.sageGate.getLaunchers()
+
+        # appLaunchers
+        k=1
+        
+        # sort the appLaunchers by name
+        launchers = launcherHash.values()
+        launchers.sort(lambda x, y: cmp(x.getName().lower(), y.getName().lower()))
+        
+        for l in launchers:   
+
+            # applications
+            i = k*100
+            appMenu = wx.Menu()
+            appHash = l.getAppList()
+            appList = appHash.keys()
+            appList.sort(lambda x, y: cmp(x.lower(), y.lower()))
+            for appName in appList:   
+                configList = appHash[appName]
+                configList.sort(lambda x, y: cmp(x.lower(), y.lower()))
+                
+                # app configs
+                j=i*100
+                configMenu = wx.Menu()
+                for appConfig in configList:
+                    item = configMenu.Append(j, appConfig, help=l.getId())
+                    j+=1
+                    self.Bind(wx.EVT_MENU, self.OnConfigMenu, item)
+                    
+                mi = appMenu.AppendMenu(i, appName, configMenu, l.getId())
+                i+=1
+                
+            menuItem = self.launcherMenu.AppendMenu(k, l.getName(), appMenu, l.getId())
+            k+=1
+            
+    
+
+    #  EVENT HANDLERS
+    def OnPaint(self, event=None):
+        if not event == None:    
+            dc = wx.PaintDC(self.parent)
+            MyBitmapButton.OnPaint(self, event)
+        else:
+            if "__WXMAC__" in wx.PlatformInfo:
+                self.Refresh()
+                return
+            dc = wx.ClientDC(self.parent)
+            MyBitmapButton.OnPaint(self)
+
+
+    def OnConfigMenu(self, event):
+        configId = event.GetId()
+        windowId =  int(math.floor(configId/100))
+        lId = int(math.floor(windowId/100))
+
+        launcherMenu = self.launcherMenu.FindItemById(lId).GetSubMenu()
+        appMenuItem = launcherMenu.FindItemById(windowId)
+        appMenu = appMenuItem.GetSubMenu()
+        configMenuItem = appMenu.FindItemById(configId)
+        configMenu = configMenuItem.GetSubMenu()
+        
+        appName = appMenuItem.GetLabel() 
+        configName = configMenuItem.GetLabel()
+        appLauncherId = appMenuItem.GetHelp()
+        
+        if self.leftClick:
+            res = self.sageGate.executeRemoteApp(appLauncherId, appName, configName)
+        else:
+            res = self.sageGate.executeRemoteApp(appLauncherId, appName, configName, useBridge=True)
+
+        if res == -1:
+            Message("Application not started. Either application failed or the application launcher "+str(appLauncherId)+" is not running", "Application Launch Failed")
+        
+
+    def OnLeftDown(self, event):
+        MyBitmapButton.OnLeftDown(self, event)
+        self.leftClick = True #a hack to detect which mouse button was clicked
+
+        # get a new list from the sage server and make the menu
+        self.AddLauncherMenu()
+
+        self.PopupMenu(self.launcherMenu)#, event.GetPosition())
+        self.OnPaint()
+                    
+
+    def OnRightDown(self, event):
+        MyBitmapButton.OnRightDown(self, event)
+        self.leftClick = False  #a hack to detect which mouse button was clicked
+
+        # get a new list from the sage server and make the menu
+        self.AddLauncherMenu()
+        
+        self.PopupMenu(self.launcherMenu)#, event.GetPosition())
+        self.OnPaint()
+
+
+        
+
+
+
+############################################################################
+#
+#  CLASS: InstanceButton
+#  
+#  DESCRIPTION: This class describes the buttons that represents instances of
+#               one application. It extends MyBitmapButton and adds a few
+#               methods for specific stuff. These buttons are created when a
+#               40001 message comes back and the app doesn't exists yet. They
+#               are anchored at the appButton for that application so that
+#               they are drawn underneith it. Also they are all positioned
+#               relative to one another so that when one instance is closed,
+#               the button for it goes away and all the other ones are
+#               repositioned.
+#
+#  DATE:        March, 2005
+#
+############################################################################
+
+class InstanceButton(MyBitmapButton):
+    
+    def __init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap, over_bitmap, app):        
+        MyBitmapButton.__init__(self, parent.parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap, over_bitmap, app.getName()+" "+str(app.getId()), app.getId() )
+        self.SetName( self.GetToolTip().GetTip() )
+        self.app = app  #SAGEApp
+        self.anchor = parent  # parent is the AppButton that this instance corresponds to
+        self.displayCanvas = self.anchor.parent.parent.GetDisplayCanvas()
+        self.drawX = x
+        self.drawY = y
+        self.infoPanel = self.anchor.parent.parent.GetInfoPanel()
+        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
+        
+
+    def SetDrawX(self, newX):
+        self.drawX = newX
+
+    def SetDrawY(self, newY):
+        self.drawY = newY
+
+    
+    #  EVENT HANDLERS
+    def OnRightUp(self, event):
+        menu = wx.Menu()
+        closeMenuItem = menu.Append( self.GetId()+1, "Close "+self.GetName() )  # +1 because Mac doesn't like 0 menuItem id
+        menu.Bind(wx.EVT_MENU, self.OnCloseMenuItem, closeMenuItem)
+        self.PopupMenu(menu, event.GetPosition())
+        menu.Destroy()
+
+    def OnCloseMenuItem(self, event):
+        # (AKS 2005-04-05) Stop performance monitoring that began "by default"
+        # when a new application had started.
+        self.displayCanvas.sageGate.shutdownApp(self.GetId())  
+        
+    def OnPaint(self, event=None):
+        MyBitmapButton.OnPaint(self, event)
+           
+    def OnMouseEnter(self, event):
+        shape = self.displayCanvas.GetShape(self.GetId())
+        
+        # update the tooltip first because the name might have changed
+        if self.tTip != "":
+            self.tTip = shape.GetName()+" "+str(shape.GetId())+" - "+shape.GetTitle()
+            self.toolTip = wx.ToolTip( self.tTip )
+            self.toolTip.SetDelay( 200 )
+            self.SetToolTip( self.toolTip )
+            
+        shape.Highlight(True)
+        MyBitmapButton.OnMouseEnter(self, event)
+        
+    def OnMouseLeave(self, event):
+        self.displayCanvas.GetShape(self.GetId()).Highlight(False)
+        MyBitmapButton.OnMouseLeave(self, event)        
+        
+    def OnLeftUp(self, event):
+        MyBitmapButton.OnLeftUp(self, event)
+        self.displayCanvas.GetShape(self.GetId()).BringToFront()
+        self.infoPanel.ShowData(self.app.getName(), self.app.getId())
+        #self.infoPanel.ShowPerformanceData(self.app.getName(), self.app.getId())
+        #self.PopupMenu(self.configMenu, event.GetPosition())
+    
+
+
+class PerfToggleButton(MyBitmapButton):    
+
+    def __init__(self, parent, btnId, onClick, onDeClick, up_bitmap, down_bitmap, over_bitmap, (x,y), (resizeWidth, resizeHeight)):
+        if not os.path.isfile(over_bitmap):
+            over_bitmap = up_bitmap
+        MyBitmapButton.__init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap, over_bitmap )
+        self.__pressed = False  #the current state of the button
+        self.__id = btnId
+        self.__clickAction = onClick
+        self.__deClickAction = onDeClick
+
+    def OnLeftUp(self, event):
+        if self.__pressed:  #the button was pressed
+            self.__pressed = False
+            self.currentBitmap = self.up_bitmap
+	    self.currentImage = self.up_image
+            self.__deClickAction( self.__id )
+        else:
+            self.__pressed = True
+            self.currentBitmap = self.down_bitmap
+	    self.currentImage = self.down_image
+            self.__clickAction( self.__id )
+        self.OnPaint()
+
+
+    def OnLeftDown(self, event):
+        pass  # override the superclass handler
+
+    def OnMouseLeave(self, event):
+        if self.__pressed:
+            self.currentBitmap = self.down_bitmap
+	    self.currentImage = self.down_image
+        else:
+            self.currentBitmap = self.up_bitmap
+	    self.currentImage = self.up_image
+        self.OnPaint()
+
+    def GetValue(self):
+        return self.__pressed
+
+    def SetValue(self, press):
+        if self.__pressed == press:  #dont do anything if the button is already at that state
+            return
+        self.__pressed = press
+        if self.__pressed:
+            self.currentBitmap = self.down_bitmap
+	    self.currentImage = self.down_image
+        else:
+            self.currentBitmap = self.up_bitmap
+	    self.currentImage = self.up_image
+        self.OnPaint()
+        
+
+
+class MyButton(MyBitmapButton):
+    
+    def __init__(self, parent, (x,y), (resizeWidth, resizeHeight), function, up_bitmap, down_bitmap=None, over_bitmap=None, tTip="", id=-1 ):        
+        # call the superclass' constructor
+        MyBitmapButton.__init__(self, parent, (x,y), (resizeWidth, resizeHeight), up_bitmap, down_bitmap=None, over_bitmap=None, tTip="", id=-1 )        
+        self.function = function  # this is the function to be called when user presses the button
+                
+##     def OnPaint(self, event=None):
+##         if not event == None:    
+##             dc = wx.PaintDC(self)
+##         else:
+##             dc = wx.ClientDC(self)
+        
+##         #mask = wx.Mask(self.currentBitmap, wx.Colour(0,0,0))
+## 	#self.currentBitmap.SetMask(mask)
+##         print "painting the help button"
+##         dc.DrawBitmap( self.currentBitmap, 0, 0, True )
+
+    def OnLeftDown(self, event):
+        MyBitmapButton.OnLeftDown(self, event)
+        self.function()
Index: trunk/src/testing/ui/README
===================================================================
--- trunk/src/testing/ui/README	(revision 4)
+++ trunk/src/testing/ui/README	(revision 4)
@@ -0,0 +1,55 @@
+---------------------------------------------------
+		
+		SAGE UI README
+                (version 3.0a)
+
+---------------------------------------------------
+(last updated on Feb, 2008)	
+
+
+
+
+(1) REQUIREMENTS (none for binary distributions):
+-------------------------------------------------
+
+- Python 2.4    	(www.python.org)
+- wxPython 2.6.2    	(www.wxPython.org)
+- either one of the following (numpy preferred):
+      - numpy     (http://numpy.scipy.org)
+      - nummarray (it's being phased out though so SAGE UI has been made
+      		  compatible with the first two packages) 
+
+
+(2) HOW TO RUN:
+---------------
+
+- make sure that fsManager is already running on the machine you are trying to connect to
+- run SAGE UI:
+	
+	FROM BINARY:
+		Windows - sageui [options]
+		Mac     - ./sageui [options]
+
+	FROM SOURCE:
+		Linux, Windows - python  sageui.py [options]
+	        Mac            - pythonw sageui.py [options]
+		      
+	- to see a list of options run the UI with "-h" (such as python sageui.py -h)
+
+
+
+(3) KNOWN BUGS:
+----------------
+
+- under some versions of KDE the background color of the panel that shows the performance
+  data might look odd.The reason behind this is that the new versions of wxPython strictly 
+  obey the current theme's colors and will not allow them to be changed by the application 
+  itself. The issue seems to be related to the QT drawing used in KDE themes. Since GNOME 
+  uses GTK (which is what linux version of wxPython uses for its drawing), it won't exhibit 
+  the same problem and the colors will look normal.
+
+
+
+---------------------------------------------
+Feb, 2008
+Ratko Jagodic - rjagodic@gmail.com
Index: trunk/src/testing/ui/sageAppPerfInfo.py
===================================================================
--- trunk/src/testing/ui/sageAppPerfInfo.py	(revision 4)
+++ trunk/src/testing/ui/sageAppPerfInfo.py	(revision 4)
@@ -0,0 +1,152 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+import sys, string
+
+### Class to hold all the performace information
+### Instance of this class has to be created for every app instance ID on SAGE
+class sageAppPerfInfo:
+
+    def __init__(self) :
+        self.displayArray = {}
+        self.renderArray = {}
+        self.dataArray = {}
+        
+        self.displayArray['bandWidth'] = self.__zerosHash(30)
+        self.displayArray['frameRate'] = self.__zerosHash(30)
+        self.displayArray['nodes'] = self.__zerosHash(30)
+        self.displayArray['cpu'] = self.__zerosHash(30)
+        self.displayArrayIndex = 0
+
+        self.renderArray['bandWidth'] = self.__zerosHash(30)
+        self.renderArray['frameRate'] = self.__zerosHash(30)
+        self.renderArray['nodes'] = self.__zerosHash(30)
+        self.renderArray['cpu'] = self.__zerosHash(30)
+        self.renderArrayIndex = 0
+
+        self.dataArray['bandWidth'] = self.__zerosHash(30)
+        self.dataArray['nodes'] = self.__zerosHash(30)
+        self.dataArray['cpu'] = self.__zerosHash(30)
+        self.dataArrayIndex = 0
+
+    #### Set the display performance Info
+    #### @arg bandwidth Bandwidth
+    #### @arg frameRate Frame rate
+    #### @arg nodes Number of nodes
+    #### @arg cpuUsage CPU utilisation
+    def setDisplayPerfInfo(self, bandWidth, frameRate, nodes, cpuUsage):
+        if (self.displayArrayIndex >= 30):
+            self.displayArrayIndex = 0
+
+        self.displayArray['bandWidth'][self.displayArrayIndex % 30] = bandWidth
+        self.displayArray['frameRate'][self.displayArrayIndex % 30] = frameRate
+        self.displayArray['nodes'][self.displayArrayIndex % 30] = nodes
+        self.displayArray['cpu'][self.displayArrayIndex % 30] = cpuUsage
+
+        self.displayArrayIndex = self.displayArrayIndex + 1
+
+
+
+    #### Set the rendering performance Info
+    #### @arg bandwidth Bandwidth
+    #### @arg frameRate Frame rate
+    #### @arg nodes Number of nodes
+    #### @arg cpuUsage CPU utilisation
+    def setRenderPerfInfo(self, bandWidth, frameRate, nodes, cpuUsage):
+        if (self.renderArrayIndex >= 30):
+            self.renderArrayIndex = 0
+
+        self.renderArray['bandWidth'][self.renderArrayIndex] = bandWidth
+        self.renderArray['frameRate'][self.renderArrayIndex] = frameRate
+        self.renderArray['nodes'][self.renderArrayIndex] = nodes
+        self.renderArray['cpu'][self.renderArrayIndex] = cpuUsage
+
+        self.renderArrayIndex = self.renderArrayIndex + 1
+
+
+
+    #### Get display information based on the specified item
+    #### @arg interval No of values required (max = 30)
+    #### @return Returns an array
+    def getDisplayInformation(self, stItemName, interval):
+
+        if (interval > 30 or interval < 0):
+            print ('Out of bound range specified')
+            return 0
+        newArray = self.__zerosHash(interval)    #zeros(type='Float32', shape=interval)
+        newArrayIndex = self.displayArrayIndex - 1
+
+        for x in range(0, interval):
+            if newArrayIndex < 0:
+                newArrayIndex = 29
+
+            newArray[x] = self.displayArray[ stItemName ][newArrayIndex]
+            newArrayIndex = newArrayIndex - 1
+
+        return newArray
+
+
+
+    #### Get rendering information based on the specified item
+    #### @arg interval No of values required (max = 30)
+    #### @return Returns an array
+    def getRenderInformation(self, stItemName, interval):
+
+        if (interval > 30 or interval < 0):
+            print ('Out of bound range specified')
+            return 0
+        newArray = self.__zerosHash(interval)   #zeros(type='Float32', shape=interval)
+        newArrayIndex = self.renderArrayIndex - 1
+
+        for x in range(0, interval):
+
+            if newArrayIndex < 0:
+                newArrayIndex = 29
+
+            newArray[x] = self.renderArray[ stItemName ][newArrayIndex]
+            newArrayIndex = newArrayIndex - 1
+  
+        return newArray
+
+
+    # creates a hash of size "size" and initializes all the values to 0
+    def __zerosHash(self, size):
+        h = {}
+        for i in range(0, size):
+            h[i] = 0
+        return h
Index: trunk/src/testing/ui/sageData.py
===================================================================
--- trunk/src/testing/ui/sageData.py	(revision 4)
+++ trunk/src/testing/ui/sageData.py	(revision 4)
@@ -0,0 +1,846 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# python stuff
+import sys, string, pickle, time, os.path, os, xmlrpclib, shutil
+import traceback as tb
+
+# my imports
+from sageApp import SageApp, SageAppInitial
+from sageAppPerfInfo import sageAppPerfInfo
+from sageDisplayInfo import SageDisplayInfo
+import Graph
+from globals import *
+from sagePath import getUserPath
+
+
+## Main class to store all the messages returned by SAGE
+class SageData:
+
+
+    #### constructor initializes member values       
+    def __init__(self, sageGate, autosave, displayName):
+        self.noOfApps = 0
+        self.hashCallback = {}       # functions to call in sageui.py for updating the UI
+        self.hashApps = {}           # all the apps available for running??
+        self.hashAppStatusInfo = {}  # apps currently running
+        self.hashAppPerfInfo = {}
+        self.hashFileInfo = {}
+        self.displayInfo = SageDisplayInfo()
+        self.sageGate = sageGate
+        self.autosave = autosave
+        self.timeStarted = time.strftime("%Y%m%d-%H%M%S", time.localtime())
+        self.displayName = displayName.strip()
+        self.__firstAutosave = True
+        
+        self._sageColor = (0,0,0)
+        self.__bPerformanceLogging = True
+
+        # (AKS 2005-02-15) The hash below is used for determining when to
+        # calculate the total values for all active applications.  This
+        # hash originally belonged in GraphManager of Graph.py.  However,
+        # the implementation was not clean and lent itself to infinite
+        # recursion.  So, having the total calculation at the source of
+        # where the data is kept seemed to make the most sense.
+        #self.__hashAppGraphUpdateFlag = {}
+
+
+        # Constants used for keys in __hashAppPerfTotals (public scope)
+        self.I_RENDER_TOTAL_BANDWIDTH = 10
+        self.I_RENDER_AVG_FRAME_RATE = 20
+        self.I_RENDER_TOTAL_NODES = 30
+        self.I_DISPLAY_TOTAL_BANDWIDTH = 40
+        self.I_DISPLAY_AVG_FRAME_RATE = 50
+        self.I_DISPLAY_TOTAL_NODES = 60
+
+        self.__hashAppPerfTotals = {}
+        self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_BANDWIDTH ] = 0.0
+        self.__hashAppPerfTotals[ self.I_RENDER_AVG_FRAME_RATE ] = 0.0
+        self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_NODES ] = 0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_BANDWIDTH ] = 0.0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_AVG_FRAME_RATE ] = 0.0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_NODES ] = 0
+        
+        # for knowing when to zero out the totals since
+        # sage doesnt send perf data when it's 0
+        self.__lastTotalsUpdate = time.time()  
+
+        # (AKS 2005-05-07) Create two PerformanceGraphs (one for total render bandwidth
+        # and one for total display bandwidth).  This is a hack...2 is specified in
+        # the GraphManager class not for updating purposes but so that the x-axis values
+        # are computed correctly.  The created numarray object takes the place of what
+        # sageAppPerfInfo does (well, it's adjusted manually later)
+        self.__iMaxArraySize = 30
+        self.__iUpdateInterval = 2
+
+        self.__pgTotalRenderBandwidth = Graph.PerformanceGraph( "Totals", "Render Bandwidth (Mbps)",
+            self.__iMaxArraySize, self.__iUpdateInterval )
+
+        self.__pgTotalDisplayBandwidth = Graph.PerformanceGraph( "Totals", "Display Bandwidth (Mbps)",
+            self.__iMaxArraySize, self.__iUpdateInterval )
+        self.__sapiPerfTotals = sageAppPerfInfo()
+
+        
+    #### Set the sage status
+    def setSageStatus(self, appHash) :  
+        self.noOfApps = len(appHash) 
+
+        #for line in listTokens:
+        for appName, configs in appHash.iteritems():
+            hashSingleAppInfo = {}
+            self.hashApps[appName] = SageAppInitial(appName, configs)
+            
+        # when done processing the incoming data, call a function in the UI to update the screen
+        if ( 40000 in self.hashCallback ):
+            self.hashCallback[ 40000 ]()
+
+
+
+    #----------------------------------------------------------------------
+
+
+    ### Set the possible execution configurations for each app
+    def setSageAppExecConfig(self, data):
+        tokens = string.split( data, '\n', 1 )
+        appName = tokens[0]
+        data = tokens[1] #the rest
+        configList = string.split( data, "config ")
+
+        del configList[0]  #remove the first item in the list
+
+        for config in configList:
+            if appName in self.hashApps.keys():
+                (name, stringConfig) = string.split(config, ":", 1)
+                self.hashApps[appName].AddConfig(name, stringConfig)
+
+        if ( 40006 in self.hashCallback ):
+            self.hashCallback[ 40006 ](self.hashApps[appName])
+       
+
+    #----------------------------------------------------------------------
+    
+     
+    #### Set the SAGE display information
+    #### 
+    def setDisplayInfo(self, data):
+        listTokens = string.split(data, '\n')
+
+        for i in range(0, len(listTokens), 3):
+            tileNumTokens = string.split(listTokens[i], ' ')
+            desktopTokens = string.split(listTokens[i+1], ' ')
+            tileConfTokens = string.split(listTokens[i+2], ' ')            
+            
+            # so that we can support the old sage as well
+            displayId = 0
+            if len(tileConfTokens) > 2:
+                displayId = int(tileConfTokens[2])
+
+            self.displayInfo.addDisplay(int(tileNumTokens[0]), int(tileNumTokens[1]), int(tileNumTokens[2]),
+                                   int(desktopTokens[0]), int(desktopTokens[1]),
+                                   int(tileConfTokens[0]), int(tileConfTokens[1]), displayId)
+
+        # (AKS 2004-10-23) Provide the app-id to the callback
+        if ( 40004 in self.hashCallback ):
+            self.hashCallback[ 40004 ]()
+
+
+    #----------------------------------------------------------------------
+
+
+    # returns the SageDisplayInfo object
+    def getDisplayInfo(self, displayId=0):
+        return self.displayInfo
+
+
+    #----------------------------------------------------------------------
+
+
+    def setDisplayConnections(self, data):
+        for connection in data.split('\n'):
+            tokens = connection.split()
+            displayId = int(tokens[2])
+            self.displayInfo.getDisplay(displayId).placement = int(tokens[1])
+
+        if ( 40007 in self.hashCallback ):
+            self.hashCallback[ 40007 ]()    
+
+
+    #----------------------------------------------------------------------
+    
+
+    #### Get the new list of z values from SAGE
+    #### and update local hashes, then call the function to update the UI visually
+    def setSageZValue(self, message):
+        tokens = string.split(message)
+        numZChanges = int(tokens[0])  #the first item that comes in is the number of z changes
+        
+        # loop through all the tokens and update the z values of the apps
+        for i in range(numZChanges):
+            self.setZvalue( int(tokens[i*2+1]), int(tokens[i*2+2]) )
+
+        # now call the appropriate function to update the UI visually
+        if ( 40005 in self.hashCallback ):
+            self.hashCallback[ 40005 ]( )
+          
+        
+    #----------------------------------------------------------------------
+
+    
+    #### Set the SAGE app status
+    #### prints Invalid app ID if does not exists
+    def setSageAppInfo(self, data):
+        listTokens = string.split(data)
+        listApps = self.hashApps.keys()
+
+        # to support old sage as well
+        displayId = 0
+        orientation = 0
+        appId = 0
+        launcherId = "none"
+        if len(listTokens) > 8:
+            orientation = int(listTokens[8])
+            displayId = int(listTokens[9])
+            if len(listTokens) > 11:
+                appId = int(listTokens[10])
+                launcherId = listTokens[11]
+                    
+        # now update the app properties... or create a new one
+        windowId = int( listTokens[ 1 ] )
+        if windowId in self.hashAppStatusInfo:   # app exists
+            self.hashAppStatusInfo[ windowId ].setAll( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), int(listTokens[7]), orientation, displayId, appId, launcherId) 
+        else:
+            # when new app is started it is assigned a z=0 but since previous app on top had z=0,
+            # we set this one even higher temporarily (z=-1) so that it gets drawn on top
+            # the new z order message comes right after the app is started so this -1 is temporary
+            zValue = int(listTokens[7])
+            for app in self.hashAppStatusInfo.itervalues():
+                if app.getZvalue() == zValue:
+                    zValue = -1
+            self.hashAppStatusInfo[ windowId ] = SageApp( listTokens[0], int(listTokens[1]),
+                   int(listTokens[2]), int(listTokens[3]), int(listTokens[4]), int(listTokens[5]),
+                   int(listTokens[6]), zValue, orientation, displayId, appId, launcherId) 
+
+
+        # (AKS 2004-10-23) Provide the app-id to the callback
+        if ( 40001 in self.hashCallback ):
+            self.hashCallback[ 40001 ]( self.hashAppStatusInfo[windowId] )
+
+        if self.autosave:
+            if self.__firstAutosave:
+                self.__deleteOldAutosaves()
+                self.__firstAutosave = False
+            self.saveState("_autosave_LATEST", "")
+
+        return
+
+    #----------------------------------------------------------------------
+    
+    
+    ##### ShutDown the sage application
+    ##### prints invalid app ID if doesn't exist
+    def sageAppShutDown(self, data):
+        listTokens = string.split(data)
+        windowId = int(listTokens[0])
+        listApps = self.hashApps.keys()
+
+
+        # do this first and then remove the app from the hash!!
+        if ( 40003 in self.hashCallback ):
+            self.hashCallback[ 40003 ]( self.hashAppStatusInfo[windowId]  )
+            
+        if windowId in self.hashAppStatusInfo :
+            del self.hashAppStatusInfo[windowId]
+        if windowId in self.hashAppPerfInfo :
+            del self.hashAppPerfInfo[windowId]
+
+        if windowId in self.hashFileInfo :
+            fileObject = self.hashFileInfo.get(windowId)
+            fileObject.close()
+            del self.hashFileInfo[windowId]
+            
+
+    #----------------------------------------------------------------------
+
+    def getLogFileHash(self):
+        return self.hashFileInfo
+
+
+    #----------------------------------------------------------------------
+
+       
+    #### Set the SAGE app performance status
+    #### prints Invalid app ID if does not exists
+    def setSagePerfInfo(self, data):
+        #print ">>> SET SAGE PERF INFO <<<"
+        listTokens = string.split(data, '\n', 1)
+        windowId = int(listTokens[0])
+        data = listTokens[1]
+
+        
+        if not windowId in self.hashAppPerfInfo:
+            self.hashAppPerfInfo[windowId] = sageAppPerfInfo()
+
+        appPerfInfo = self.hashAppPerfInfo.get(windowId)
+        
+        if (appPerfInfo):
+            lineTokens = string.split(data, '\n')
+
+            displayItemTokens = string.split(lineTokens[0])
+            appPerfInfo.setDisplayPerfInfo(float(displayItemTokens[1]), float(displayItemTokens[2]),\
+                                           float(displayItemTokens[3]), int(displayItemTokens[4]))
+
+            renderItemTokens = string.split(lineTokens[1])
+            # FIX: this is just a hack for now.. there actually is no data coming in for the last
+            # two entries in the array but we fill it with 0s so that we dont have to change everything
+            # (it might be used later as well)
+            # in Graph.py we jsut decide not to print the last two values
+            #renderItemTokens.append(0.0)
+            #print "renderItemTokens = ", renderItemTokens
+            renderItemTokens.append(0)
+            appPerfInfo.setRenderPerfInfo(float(renderItemTokens[1]), float(renderItemTokens[2]),\
+                                           float(renderItemTokens[3]), int(renderItemTokens[4]))
+
+
+        # Now open a file and log the data on it
+            try:   #in case the file and directory permissions are not right
+
+                if not windowId in self.hashFileInfo:
+                    sageApp = self.hashAppStatusInfo[ windowId ]
+                    stAppName = sageApp.getName()
+                    stDateTime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
+                    stFilename = stAppName + '-' + str(windowId) + '-' + stDateTime
+                    
+                    stPath = opj(DATA_DIR, stFilename + ".txt")
+                    stFilename = os.path.normpath( stPath )
+                    fileObject = open(stFilename, "w")
+
+                    fileObject.write( stAppName + ":" + str(windowId) + " >> " + time.asctime() + "\n" )
+                    fileObject.write( '-' * 120 + "\n\n" )
+                    tempString = (' Disp BW    Disp FR    Packet Loss    Num Receivers        Rend BW    Rend FR    Packet Loss    Num Receivers\n')
+                    fileObject.write(tempString)
+                    fileObject.write( '-' * len(tempString) + "\n" )
+                    self.hashFileInfo[windowId] = fileObject
+                    fileObject.flush()
+                # end of initialization
+
+                if ( self.__bPerformanceLogging == True ):
+
+                    fileObject = self.hashFileInfo.get(windowId)
+                    tempString = "%8.3f    %7.3f    %3.2f    %8d       " % (float(displayItemTokens[1]), float(displayItemTokens[2]),
+                                                                            float(displayItemTokens[3]), int(displayItemTokens[4]))
+
+                    fileObject.write(tempString)
+
+                    tempString = "%8.3f    %7.3f    %3.2f    %8d\n" % (float(renderItemTokens[1]), float(renderItemTokens[2]),
+                                                                       float(renderItemTokens[3]), int(renderItemTokens[4]))
+                    fileObject.write(tempString)
+                    fileObject.flush()
+            # >>> end file writing...else, nothing
+            except:
+                pass  #do nothing if something fails (such as permissions)
+
+                
+            # calculate totals
+        self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_BANDWIDTH ] = 0.0
+        self.__hashAppPerfTotals[ self.I_RENDER_AVG_FRAME_RATE ] = 0.0
+        self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_NODES ] = 0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_BANDWIDTH ] = 0.0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_AVG_FRAME_RATE ] = 0.0
+        self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_NODES ] = 0
+        
+        fSumRenderFrameRate = 0.0
+        fSumDisplayFrameRate = 0.0
+        
+        #print "zeroing..."
+
+        # (AKS 2005-04-05) This comment is de
+        # For each application, I am taking each of its metrics and adding them to the
+        # totals which are stored in the hash.  The hash is just a dictionary of totals
+        # for metrics for *ALL* application instances.
+        
+        for iKey in self.hashAppPerfInfo:
+            #print "hash perf: ", self.hashAppPerfInfo
+            sapiAppStats = self.hashAppPerfInfo[ iKey ]
+            
+            self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_BANDWIDTH ] = self.__hashAppPerfTotals[
+                self.I_RENDER_TOTAL_BANDWIDTH ] + sapiAppStats.getRenderInformation(
+                'bandWidth', 1 )[0]
+            
+            fSumRenderFrameRate = fSumRenderFrameRate + sapiAppStats.getRenderInformation(
+                'frameRate', 1 )[0]
+            
+            self.__hashAppPerfTotals[ self.I_RENDER_TOTAL_NODES ] = self.__hashAppPerfTotals[
+                self.I_RENDER_TOTAL_NODES ] + sapiAppStats.getRenderInformation(
+                'nodes', 1 )[0]
+            
+            self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_BANDWIDTH ] = self.__hashAppPerfTotals[
+                self.I_DISPLAY_TOTAL_BANDWIDTH ] + sapiAppStats.getDisplayInformation(
+                'bandWidth', 1 )[0]
+            
+            fSumDisplayFrameRate = fSumRenderFrameRate + sapiAppStats.getDisplayInformation(
+                'frameRate', 1 )[0]             
+            
+            self.__hashAppPerfTotals[ self.I_DISPLAY_TOTAL_NODES ] = self.__hashAppPerfTotals[
+                self.I_DISPLAY_TOTAL_NODES ] + sapiAppStats.getDisplayInformation(
+                'nodes', 1 )[0]
+
+            
+            # Make sure to clear update flag since data has been processed
+            #self.__hashAppGraphUpdateFlag[ iKey ] = False
+            
+        # end of loop
+
+        iAppCount = len( self.hashAppStatusInfo )
+
+        # Calculate averages for frame rates
+        if ( iAppCount == 0 ):
+            self.__hashAppPerfTotals[ self.I_RENDER_AVG_FRAME_RATE ] = 0.0
+            self.__hashAppPerfTotals[ self.I_DISPLAY_AVG_FRAME_RATE ] = 0.0
+                
+        else:
+            self.__hashAppPerfTotals[ self.I_DISPLAY_AVG_FRAME_RATE ] = fSumDisplayFrameRate / iAppCount
+            self.__hashAppPerfTotals[ self.I_RENDER_AVG_FRAME_RATE ] = fSumRenderFrameRate / iAppCount
+                    
+        
+        # (AKS 2005-01-24) Performance data information is not posted at this time
+        #tempString = "%8.3f \t %4d \t %7.3f \n" % (float(dataItemTokens[1]), int(dataItemTokens[2]), float(dataItemTokens[3]))
+        #fileObject.write(tempString)
+
+
+        # (AKS 2005-05-07) Now that the total bandwidth metrics have been calculated,
+        # update their respective PerformanceGraphs
+        self.__sapiPerfTotals.setDisplayPerfInfo( float( self.__hashAppPerfTotals[
+            self.I_DISPLAY_TOTAL_BANDWIDTH ] ), 0.0, 0.0, 0 )
+        
+        self.__sapiPerfTotals.setRenderPerfInfo( float( self.__hashAppPerfTotals[
+            self.I_RENDER_TOTAL_BANDWIDTH ] ), 0.0, 0.0, 0 )
+
+        self.__pgTotalRenderBandwidth.update( self.__sapiPerfTotals.getRenderInformation( 'bandWidth', 30 ) )
+        self.__pgTotalDisplayBandwidth.update( self.__sapiPerfTotals.getDisplayInformation( 'bandWidth', 30 ) )
+
+
+        self.__lastTotalsUpdate = time.time()
+        
+        # (AKS 2004-10-23): Changed to send ID back
+        if ( 40002 in self.hashCallback ):
+            self.hashCallback[ 40002 ]( windowId )
+
+
+    #----------------------------------------------------------------------
+
+    # saves the performance data totals into a file from this SAGE site only
+    def saveSiteTotals(self, siteName):
+        totalsID = -10 # save the totals as appId = -10
+        try:
+            if not totalsID in self.hashFileInfo and self.__bPerformanceLogging:  
+                stDateTime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
+                stFilename = "SITE_TOTAL-" + siteName + '-' + stDateTime
+                #stPath = "./data/" + stFilename + ".txt"
+                stPath = opj(DATA_DIR, stFilename + ".txt")
+                stFilename = os.path.normpath( stPath )
+                fileObject = open(stFilename, "w")
+
+                fileObject.write( siteName + "\n" + time.asctime() + "\n" )
+                fileObject.write( '-' * 65 + "\n" )
+                tempString = (' Timestamp(s)    Disp BW(Gbps)    Rend BW(Gbps)\n')
+                fileObject.write(tempString)
+                fileObject.write( '-' * len(tempString) + "\n" )
+                self.hashFileInfo[totalsID] = fileObject
+                fileObject.flush()
+            # end of initialization
+            
+            if ( self.__bPerformanceLogging ):
+                
+                fileObject = self.hashFileInfo[totalsID]
+                tempString = "%12d    %12.4f    %12.4f\n" % (getTimeStamp(),
+                                                            self.getDisplayBWTotal(),
+                                                            self.getRenderBWTotal())
+                fileObject.write(tempString)
+                fileObject.flush()
+
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+
+    #----------------------------------------------------------------------
+
+
+    def getRenderBWTotal(self):
+        # zero out the totals if it hasn't been update in a while
+        if time.time() - self.__lastTotalsUpdate > 2.0: 
+            self.__hashAppPerfTotals[self.I_RENDER_TOTAL_BANDWIDTH] = 0.0
+        return float(self.__hashAppPerfTotals[self.I_RENDER_TOTAL_BANDWIDTH])/1000.0
+
+
+    def getDisplayBWTotal(self):
+        # zero out the totals if it hasn't been update in a while
+        if time.time() - self.__lastTotalsUpdate > 2.0: 
+            self.__hashAppPerfTotals[self.I_DISPLAY_TOTAL_BANDWIDTH] = 0.0
+        return float(self.__hashAppPerfTotals[self.I_DISPLAY_TOTAL_BANDWIDTH])/1000.0
+    
+
+    #----------------------------------------------------------------------
+    
+    #   Get the z value of the app
+    #   @arg windowId App instance ID of the app
+    #   @return Returns Z value if windowId exists else returns -1
+    def getZvalue(self, windowId):
+        if windowId in self.hashAppStatusInfo:
+            return self.hashAppStatusInfo[windowId].getZvalue()
+        else:
+            print("getZvalue: Invalid app instance ID")
+            return
+
+            
+    #----------------------------------------------------------------------
+
+
+    #   Set the Z value of the app
+    #   @arg windowId App instance ID of the app
+    #   @arg value New Z value to be set
+    def setZvalue(self, windowId, value):
+        if (windowId in self.hashAppStatusInfo):
+            self.hashAppStatusInfo[windowId].setZvalue(value)
+        else:
+            print ('setZvalue: Invalid app instance ID: %d'% (windowId))
+        return
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### Get the sage app Info
+    ### @arg windowId Instance id of the application
+    ### @returns A list of format [<left>, <right>, <top>, <bottom>]
+    def getAppInfo(self, windowId):
+        if windowId in self.hashAppStatusInfo:
+            return self.hashAppStatusInfo[windowId].getBounds()
+        else:
+            print("getAppInfo: Invalid app instance ID")
+            return []
+
+
+    #----------------------------------------------------------------------
+
+
+    # returns the SageApp associated with the given windowId
+    def getApp(self, windowId):
+        return self.hashAppStatusInfo[windowId]
+    
+
+    #----------------------------------------------------------------------
+
+
+    ### Get the sage app display information
+    ### @arg windowId Instance id of the application
+    ### @arg interval Total no of values required (max = 30)
+    ### @returns A array   
+    def getDisplayItem(self, stItemName, windowId, interval):
+        if windowId in self.hashAppPerfInfo:
+            appInfo = self.hashAppPerfInfo.get(windowId)
+            return appInfo.getDisplayInformation( stItemName, interval )
+        else:
+            print("getDisplayItem: Invalid app instance ID")
+
+
+    ### Get the sage app render information
+    ### @arg windowId Instance id of the application
+    ### @arg interval Total no of values required (max = 30)
+    ### @returns A array
+    def getRenderItem(self, stItemName, windowId, interval):
+        if windowId in self.hashAppPerfInfo:
+            appInfo = self.hashAppPerfInfo.get(windowId)
+            return appInfo.getRenderInformation( stItemName, interval )
+        else:
+            print("Invalid app instance ID")
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### Get the sage app data service bandwidth
+    ### @arg windowId Instance id of the application
+    ### @arg interval Total no of values required (max = 30)
+    ### @returns A array
+    def getDataBandWidth(self, windowId, interval):
+        if windowId in self.hashAppPerfInfo:
+            appInfo = self.hashAppPerfInfo.get(windowId)
+            return appInfo.getDataBandWidth(interval)
+        else:
+            print("Invalid app instance ID")
+
+
+    #----------------------------------------------------------------------
+    
+
+    ### So that SageData knows what to call when a message arrives
+    def registerCallbackFunction( self, iSageID, function ):
+        self.hashCallback[ iSageID ] = function
+
+
+    #----------------------------------------------------------------------
+
+    
+    ### (RJ 2005-01-15)
+    ### Returns a list of all the available apps
+    def getAvailableApps( self ):
+        return self.hashApps
+
+    #----------------------------------------------------------------------
+
+    ### sage background color
+    def setSAGEColor(self, (r,g,b)):
+        self._sageColor = (r,g,b)
+
+    #----------------------------------------------------------------------
+
+    ### sage background color
+    def getSAGEColor(self):
+        return self._sageColor
+    
+    #----------------------------------------------------------------------
+
+    # checks all the apps and reports whether any one of them was
+    # hit with a click and which region was hit (corners or shape in general)
+    # if more than one shape was hit it returns the one on the top
+    def checkHits(self, x, y):
+        zHash = {}  #key=z value, value=SageApp
+
+        for windowId, sageApp in self.hashAppStatusInfo.iteritems():
+            zHash[sageApp.getZvalue()] = sageApp
+
+        zKeys = zHash.keys()
+        zKeys.sort()
+
+        for z in zKeys:
+            hitResult = zHash[z].hitTest(x,y)
+            if hitResult >= 0:
+                return (zHash[z], hitResult)
+
+        return (None, -1)
+
+
+    #----------------------------------------------------------------------
+
+    # returns (windowId, zValue) or (-1,sys.maxint) if no apps
+    def getTopApp(self):
+        minZ = (-1, sys.maxint)
+        for windowId, app in self.hashAppStatusInfo.iteritems():
+            if app.getZvalue() < minZ[1]:
+                minZ = (windowId, app.getZvalue())
+        return minZ
+
+    #----------------------------------------------------------------------
+
+    ### (AKS 2005-02-16)
+    ### Return totals/averages for performance metrics for applications
+    def getTotals( self ):
+        return self.__hashAppPerfTotals
+    
+    #----------------------------------------------------------------------
+
+    ### (AKS 2005-02-16)
+    ### Set the logging flag and close all the logging files
+    def setLoggingFlag( self, bFlag ):
+        self.__bPerformanceLogging = bFlag
+
+    def isLoggingEnabled(self):
+        return self.__bPerformanceLogging
+
+    #----------------------------------------------------------------------
+    
+    ### (RJ 2005-5-18)
+    ### Stops the logging and closes all the logging files
+    def stopLogging(self):
+        for windowId, fileObject in self.getLogFileHash().iteritems():
+            fileObject.close()
+
+    #----------------------------------------------------------------------
+
+    ### (AKS 2005-05-07)
+    ### Get render bandwidth graph
+    def getRenderBandwidthGraph( self ):
+        return self.__pgTotalRenderBandwidth
+
+
+    #----------------------------------------------------------------------
+
+    ### (AKS 2005-05-07)
+    ### Get display bandwidth graph
+    def getDisplayBandwidthGraph( self ):
+        return self.__pgTotalDisplayBandwidth
+
+
+    #----------------------------------------------------------------------
+
+
+    def saveState(self, stateName, description):
+        appLaunchers = self.sageGate.getLaunchers()
+        appList = []
+
+        # gather all the data that needs to be saved for each app
+        for app in self.hashAppStatusInfo.values():
+
+            # get the config info from the right appLauncher
+            if app.getLauncherId() != "none":
+                appLauncher = xmlrpclib.ServerProxy("http://" + app.getLauncherId())
+                try:
+                    res = appLauncher.getAppConfigInfo( app.getAppId() )
+                except:
+                    print "\nUnable to connect to appLauncher on", app.getLauncherId(), \
+                          "so not saving this app: ", app.getName() 
+                    continue
+                
+                if res == -1:
+                    continue   # skip this app... something went wrong
+                configName, optionalArgs = res
+
+                # get the other app parameters from sageApp object
+                pos = (app.getLeft(), app.getBottom())
+                size = (app.getWidth(), app.getHeight())
+                
+                # append the tuple of app's data to the list that will be saved
+                appList.append( (app.getLauncherId(), app.getName(), configName,
+                                 pos, size, optionalArgs) )
+
+      
+        # open the file and write to it
+        try:   #in case the file and directory permissions are not right
+            f = open( opj(SAVED_STATES_DIR, stateName+".state"), "w")
+            pickle.Pickler(f, 0).dump( (description, appList) )
+            f.close()
+        except IOError:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            return False
+
+        return True
+
+
+    def __deleteOldAutosaves(self):
+        # remove old autosave files...
+        try:
+            sd = SAVED_STATES_DIR
+            saves = os.listdir(sd)
+            if "_autosave_PREV.state" in saves:
+                os.remove(opj(sd, "_autosave_PREV.state"))
+            if "_autosave_LATEST.state" in saves:
+                shutil.move(opj(sd, "_autosave_LATEST.state"), opj(sd, "_autosave_PREV.state"))
+        except:
+            print "ERROR while deleting old states:"
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+
+
+    def loadState(self, stateName):
+        """ tries to reload the apps from the saved state """
+        appList = []
+        description = ""
+
+        # load the state from a file
+        try:
+            f = open( opj(SAVED_STATES_DIR, stateName+".state"), "r")
+            (description, appList) = pickle.Unpickler(f).load()
+            f.close()
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            print "\nUnable to read saved state file: "+"saved-states/"+stateName+".state"
+            return False
+
+        # try re-running all the apps
+        count = 0
+        for appInfo in appList: 
+            launcherId, appName, configName, pos, size, optionalArgs = appInfo
+            self.sageGate.executeRemoteApp(launcherId, appName, configName, pos, size, optionalArgs)
+            count+=1
+            
+        return True
+
+
+
+    def deleteState(self, stateName):
+        """ tries to delete an existing state """
+        try:
+            filePath = opj(SAVED_STATES_DIR, stateName+".state")
+            os.remove(filePath)
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            print "\nUnable to delete the saved state: ", filePath
+            return False
+
+        return True
+
+            
+
+    def getStateList(self):
+        """ returns a hash of key=stateName, value=description """
+        stateHash = {}
+        appList = []
+        description = ""
+
+        sd = SAVED_STATES_DIR
+        
+        # load all the states and read descriptions from them
+        for fileName in os.listdir( sd ):
+            filePath = opj(sd, fileName)
+            if os.path.isfile(filePath) and os.path.splitext(filePath)[1] == ".state":
+                try:
+                    stateName = os.path.splitext( os.path.split(filePath)[1] )[0]
+                    f = open(filePath, "rb")
+                    (description, appList) = pickle.Unpickler(f).load()
+                    f.close()
+                    stateHash[stateName] = description
+                except:
+                    print "\nUnable to read saved state file: "+filePath
+                    continue
+
+        return stateHash
+
+
+
+    def closeAllApps(self):
+        for app in self.hashAppStatusInfo.itervalues():
+            if app.getId() == -5:
+                continue
+            self.sageGate.shutdownApp(app.getId())
+            time.sleep(0.5)
+
+
+
Index: trunk/src/testing/ui/launcherAdmin.py
===================================================================
--- trunk/src/testing/ui/launcherAdmin.py	(revision 4)
+++ trunk/src/testing/ui/launcherAdmin.py	(revision 4)
@@ -0,0 +1,340 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+import wx, xmlrpclib, string, socket
+import traceback as tb
+
+
+
+
+class App:
+    """ describes the app that's currently running and that has been executed by an appLauncher"""
+    def __init__(self, name, windowId, command, machine, launcher):
+        self.name = name
+        self.windowId = windowId
+        self.command = command
+        self.machine = machine
+        self.launcher = launcher  #the appLauncherId that started this app
+
+    def getName(self):
+        return self.name
+
+    def getId(self):
+        return self.windowId
+
+    def getCommand(self):
+        return self.command
+
+    def getRenderMachine(self):
+        return self.machine
+
+    def getLauncher(self):
+        return self.launcher
+
+    def getStringForm(self):
+        info = "APPLICATION NAME: " + self.name
+        info = info + "\n------------------------------------------------"
+        info = info + "\nEXECUTION COMMAND: " + str(self.command)
+        info = info + "\nRENDERING MACHINE:\t"+str(self.machine) 
+        return info
+    
+
+class AppLauncher:
+
+    def __init__(self, launcherId, name, ip, port, appList):
+        self.port = port
+        self.appList = appList
+        self.ip = ip
+        self.launcherId = launcherId
+        self.name = name
+	self.connected = False
+
+
+    def connect(self):
+	if not self.connected:
+	    socket.setdefaulttimeout(2)  #set the timeout to 3 seconds so that we dont wait forever
+	    self.server = xmlrpclib.ServerProxy("http://" + self.ip + ":" + str(self.port))
+	    try:
+		self.server.test() #just use this as a way of testing whether the server is running or not
+		self.connected = True
+	    except socket.error:
+		return False
+	    except:
+		tb.print_exc()
+		return False
+	return True
+
+
+    def stopApp(self, windowId):
+        try:
+            self.connect()  #connect if necessary
+            return self.server.stopApp(windowId)
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error stopping application:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+            
+    def appStatus(self):
+        try:
+            self.connect()  #connect if necessary
+            return self.server.appStatus()
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error getting application list:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+        return {}
+
+
+    def killLauncher(self):
+        try:
+            self.connect()  #connect if necessary
+            self.server.killLauncher()
+        except socket.error:
+            wx.MessageBox("No connection to the appLauncher: "+str(self.launcherId), "Failed")
+            self.connected = False
+        except:
+            wx.MessageBox("There was an error killing application launcher:\n\n"+
+                          str("".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))),
+                          "Failed")
+
+
+
+    def getId(self):
+        return self.launcherId
+
+    def getIP(self):
+        return self.ip
+
+    def getAppList(self):
+        return self.appList
+
+    def setAppList(self, appList):
+        self.appList = appList
+
+    def getPort(self):
+        return self.port
+
+    def getName(self):
+        return self.name
+
+
+
+
+
+class MainFrame(wx.Frame):
+
+    def __init__(self, serverIP, serverPort=8009):
+        wx.Frame.__init__(self, None, -1, "AppLauncher Admin", pos = (100,100), size=(550,300))
+        self.server = xmlrpclib.ServerProxy("http://"+serverIP+":"+str(serverPort))
+        self.CreateControls()
+        self.launcherHash = {}
+        self.appHash = {}
+        self.updateLauncherList()
+        self.SetBackgroundColour(wx.Colour(51, 102, 102))
+        self.Show(True)
+
+        
+    ### connects to the sage server and retrieves the list of all app launchers running
+    def updateLauncherList(self):
+        self.launcherList.ClearAll()  #clear the ListBox
+        self.launcherHash = {}
+	try:
+	    # a hash comes back (key=launcherId, value=appList - that's another hash of appNames and configs)
+	    launchers = self.server.GetRegisteredLaunchers()
+	except socket.error:
+            wx.MessageBox("No connection to the sage server.", "No connection")
+	except:
+	    tb.print_exc()
+	else:
+	    for launcherString, appList in launchers.iteritems():
+		(name, launcherId) = launcherString.split(":",1)
+		(ip, port) = launcherId.split(":",1)
+                newId = wx.NewId()
+                item = wx.ListItem()
+                item.SetText(name)
+                item.SetData(newId)
+                self.launcherHash[newId] = AppLauncher(launcherId, name, ip, port, appList)
+                self.launcherList.InsertItem(item)
+		
+	
+    def CreateControls(self):
+        self.launcherLabel = wx.StaticText(self, -1, "Registered AppLaunchers", style=wx.ALIGN_CENTER)
+        self.appLabel = wx.StaticText(self, -1, "Apps Running On: ", style=wx.ALIGN_CENTER)
+        self.appInfoLabel = wx.StaticText(self, -1, "Details for: ", style=wx.ALIGN_CENTER)
+
+        self.launcherLabel.SetForegroundColour(wx.WHITE)
+        self.appLabel.SetForegroundColour(wx.WHITE)
+        self.appInfoLabel.SetForegroundColour(wx.WHITE)
+
+        self.launcherList = wx.ListCtrl(self, -1, style=wx.LC_LIST | wx.LC_SINGLE_SEL )
+        self.launcherList.SetMinSize((100,100))
+        self.appList = wx.ListCtrl(self, -1, style=wx.LC_LIST | wx.LC_SINGLE_SEL )
+        self.appList.SetMinSize((200,100))
+        self.appInfo = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY | wx.TE_MULTILINE | wx.TE_DONTWRAP)
+        self.appInfo.SetMinSize((300,100))
+        
+        self.killAppBtn = wx.Button(self, -1, "Kill App")
+        self.killLauncherBtn = wx.Button(self, -1, "Kill Launcher")
+        self.refreshBtn = wx.Button(self, -1, "Refresh")
+
+
+        # registering event handlers
+        self.launcherList.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnLauncherListSelect)
+        self.appList.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnAppListSelect)
+        self.killAppBtn.Bind(wx.EVT_BUTTON, self.OnKillAppBtn)
+        self.killLauncherBtn.Bind(wx.EVT_BUTTON, self.OnKillLauncherBtn)
+        self.refreshBtn.Bind(wx.EVT_BUTTON, self.UpdateLists)
+        
+        # placement of the controls
+        gridSizer = wx.FlexGridSizer(2,3,0,20)
+        gridSizer.Add(self.launcherLabel, 0, wx.ALIGN_CENTER | wx.TOP | wx.LEFT | wx.EXPAND, border=15)
+        gridSizer.Add(self.appLabel, 0, wx.ALIGN_CENTER | wx.TOP, border=15)
+        gridSizer.Add(self.appInfoLabel, 0, wx.ALIGN_CENTER | wx.TOP, border=15)
+
+        gridSizer.Add(self.launcherList, 1, wx.EXPAND | wx.ALL, border=10)
+        gridSizer.Add(self.appList, 1, wx.EXPAND | wx.ALL, border=10)
+        gridSizer.Add(self.appInfo, 1, wx.EXPAND | wx.ALL, border=10)
+
+        gridSizer.Add(self.killLauncherBtn, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=15)
+        gridSizer.Add(self.killAppBtn, 0, wx.ALIGN_CENTER | wx.BOTTOM, border=15)
+        gridSizer.Add(self.refreshBtn, 0, wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT, border=15)
+
+        gridSizer.AddGrowableRow(1)
+        gridSizer.AddGrowableCol(2)
+        
+        self.SetSizer(gridSizer)
+        gridSizer.Fit(self)
+
+        
+    def OnLauncherListSelect(self, event=None):
+        selection = event.GetText()
+        self.appList.ClearAll()
+        self.appLabel.SetLabel("Apps Running On: " + str(selection))
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: ")
+        appLauncher = self.launcherHash[event.GetData()] 
+        for windowId, (appName, command, machine) in appLauncher.appStatus().iteritems():
+            newId = wx.NewId()
+            item = wx.ListItem()
+            item.SetText(appName)
+            item.SetData(newId)
+            self.appHash[newId] = App(appName, int(windowId), command, machine, appLauncher)
+            self.appList.InsertItem(item)
+        self.GetSizer().Layout()
+
+
+    def OnAppListSelect(self, event=None):
+        selection = event.GetText()
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: " + str(selection))
+        self.appInfo.WriteText(self.appHash[event.GetData()].getStringForm())
+        self.GetSizer().Layout()
+        
+
+    def UpdateLists(self, event=None):
+        self.updateLauncherList()
+        self.appList.ClearAll()
+        self.appLabel.SetLabel("Apps Running On: ")
+        self.appInfo.Clear()
+        self.appInfoLabel.SetLabel("Details for: ")
+        self.GetSizer().Layout()
+
+
+    def OnKillAppBtn(self, event):
+        selection = self.appList.GetFirstSelected()
+        if selection > -1:
+            app = self.appHash[self.appList.GetItemData(selection)]
+            app.getLauncher().stopApp(app.getId())
+            self.UpdateLists()
+
+
+    def OnKillLauncherBtn(self, event):
+        selection = self.launcherList.GetFirstSelected()
+        if selection > -1:
+            msg = "Really stop this application launcher? You may be interfering with someone else's work."
+            dlg = wx.MessageDialog(None, msg, "Confirm kill", style = wx.OK | wx.CANCEL)
+            if dlg.ShowModal() == wx.ID_OK:
+                appLauncher = self.launcherHash[self.launcherList.GetItemData(selection)]
+                appLauncher.killLauncher()
+                self.UpdateLists()
+
+
+
+
+class MyApp(wx.App):
+    def __init__(self):
+        wx.App.__init__(self, redirect=False)
+
+    def OnInit(self):
+        return True
+
+
+
+
+        
+
+def main(argv):
+    name, ext  = os.path.splitext(argv[1])
+
+    if len(argv) == 2:
+        serverIP = "sage.sl.startap.net"
+        serverPort = 8009
+    elif len(argv) == 3:
+        serverIP = argv[2]
+        serverPort = 8009
+    else:
+        print "Usage: python admin.py [SERVER_IP]\n"
+        sys.exit(0)
+
+    app = MyApp()
+    frame = MainFrame(serverIP, serverPort)
+    app.SetTopWindow(frame)
+    app.MainLoop()
+
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
Index: trunk/src/testing/ui/sageGateBase.py
===================================================================
--- trunk/src/testing/ui/sageGateBase.py	(revision 4)
+++ trunk/src/testing/ui/sageGateBase.py	(revision 4)
@@ -0,0 +1,835 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+
+"""
+	SAGE UI --> SAGE
+	---------------------------	
+	Register 			1000
+	Execute				1001
+	Shutdown			1002
+	Move				1003
+	Resize				1004
+	Start Performance		1005
+	Stop Performance		1006
+	BackColor			1007
+	Bring to Front                  1010
+	App Properties Change           1011
+	App Frame Rate Change           1012
+	Stream Request                  1014
+        Rotate Window                   1018
+	SAGE Shutdown                   1100
+	Add Object                      1200
+        Move Object                     1201
+        Remove Object                   1202
+        Object Message                  1203
+        Show Object                     1204
+        Hide Object                     1205
+        
+
+	SAGE ----> SAGE UI
+	--------------------------
+	Status				40000 
+	App Info			40001 APPID L R T B SAIL-ID
+	Performance			40002
+	App Shutdown                    40003
+	Display Info                    40004
+	Z Order Change                  40005
+	App Exec Config                 40006
+        Display Connections             40007
+        Overlay Object Info             40018
+	
+
+	STORE INFORMATION
+"""
+
+
+from threading import Thread, RLock
+import socket, sys, string, os.path, xmlrpclib, time
+import traceback as tb
+from globals import *
+
+
+### GLOBALS ###
+
+TIMEOUT_INTERVAL = 0.5
+BLANK = ' '
+HEADER_ITEM_LEN = 8
+APP_LAUNCHER_PORT = 19010  #the default port, usually retrieved from the sage server though
+SAGE_SERVER_PORT = 8009  #the xmlrpc port of the sage server
+
+
+
+class AppLauncher:
+
+    def __init__(self, launcherId, name, ip, port, appList):
+        self.port = port
+        self.appList = appList
+        self.ip = ip
+        self.launcherId = launcherId
+        self.name = name
+	self.connected = False
+
+
+    def connect(self):
+	if not self.connected:
+	    socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
+	    self.server = xmlrpclib.ServerProxy("http://" + self.ip + ":" + str(self.port))
+	    try:
+		self.server.test() #just use this as a way of testing whether the server is running or not
+		self.connected = True
+	    except socket.error:
+		return False
+	    except:
+		tb.print_exc()
+		return False
+	return True
+
+
+    def getId(self):
+        return self.launcherId
+
+    def getIP(self):
+        return self.ip
+
+    def getAppList(self):
+        return self.appList
+
+    def setAppList(self, appList):
+        self.appList = appList
+
+    def getPort(self):
+        return self.port
+
+    def getName(self):
+        return self.name
+    
+    def getServerHandle(self):
+        self.connect()
+        return self.server
+
+
+
+
+
+
+####################################################################
+#
+# DESCRIPTION: This is the base class for communication with SAGE.
+#              You need to inherit from this class and override
+#              the "onMessage" method. You can use the registerCallbackFunction
+#              and the hashCallbackFunction to store your callbacks
+#              and then retrieve them from your overridden onMessage.
+#
+# DATE: Aug, 2007
+#
+####################################################################
+
+class SageGateBase:
+	
+    def __init__(self, sageServerHost="sage.sl.startap.net", useAppLauncher=False, forceAppLauncher=None, onDisconnect=None, verbose=False):
+	self.hashCallbackFunction = {}
+	self.threadkilled = False
+	self.connected = False
+	self.sageHost = None
+	self.sagePort = 20001
+        self.forceAppLauncher = forceAppLauncher         # use this appLauncher if specified
+        self.useAppLauncher = useAppLauncher   # should we use the appLauncher at all?
+        self.onDisconnect = onDisconnect       # call this function if disconnected
+        self.verbose = verbose                 # print the output?
+        self.sageServerHost = sageServerHost           # where the sage server is running
+        self.launchers={}                      # a hash of appLaunchers currently running
+
+	# used for printing out informative messages (on sending and receiving)
+	self.hashOutgoingMessages = {}  
+	self.hashOutgoingMessages[1000] = "Register UI"
+	self.hashOutgoingMessages[1001] = "App Start"
+	self.hashOutgoingMessages[1002] = "App Shutdown"
+	self.hashOutgoingMessages[1003] = "Move"
+	self.hashOutgoingMessages[1004] = "Resize"
+	self.hashOutgoingMessages[1005] = "Request Performance"
+	self.hashOutgoingMessages[1006] = "Stop Performance"
+	self.hashOutgoingMessages[1007] = "Background Color"
+	self.hashOutgoingMessages[1010] = "Bring To Front"
+	self.hashOutgoingMessages[1011] = "App Properties Change"
+	self.hashOutgoingMessages[1012] = "App Frame Rate Change"
+	self.hashOutgoingMessages[1014] = "Stream Request"
+        self.hashOutgoingMessages[1018] = "Rotate Window"
+        self.hashOutgoingMessages[1200] = "Add Object"
+        self.hashOutgoingMessages[1201] = "Move Object"
+        self.hashOutgoingMessages[1202] = "Remove Object"
+        self.hashOutgoingMessages[1203] = "Object Message"
+	self.hashOutgoingMessages[1100] = "Shutdown"
+
+	self.hashIncomingMessages = {} 
+	self.hashIncomingMessages[40000] = "SAGE Status Message"
+	self.hashIncomingMessages[40001] = "App Info Return"
+	self.hashIncomingMessages[40002] = "Performance Info"
+	self.hashIncomingMessages[40003] = "App Shutdown"
+	self.hashIncomingMessages[40004] = "Display Info"
+	self.hashIncomingMessages[40005] = "Z Change"
+	self.hashIncomingMessages[40006] = "App Exec Config"
+        self.hashIncomingMessages[40007] = "Display Connections"
+        self.hashIncomingMessages[40018] = "Overlay Object Info"
+
+
+
+    def makemsg(self,dst,code,appcode,size,data):
+        # assemble the message into a string
+	msg = '%8s\0%8s\0%8s\0%s\0' %(dst,code,appcode,data)
+	size = len(msg) + 9
+	msg = '%8s\0%s' %(size,msg)
+
+        # print the output if requested
+        if self.verbose and int(code) < 1200:  # dont print the draw object messages cause there are many of them
+            print "\n\tSEND:  " + self.hashOutgoingMessages[int(code)]
+            print "\t       [" + data + "]\n\n"
+            
+	return msg	
+
+
+    def connectToAppLauncher(self, host=socket.gethostname()):
+	socket.setdefaulttimeout(3)  #set the timeout to 3 seconds so that we dont wait forever
+        if self.forceAppLauncher:    # overriding with the one from the command line
+            self.appLauncher = xmlrpclib.ServerProxy("http://"+self.forceAppLauncher)
+        else:                         # try to find the appropriate app launcher
+            self.appLauncher = self.__getMyAppLauncher(host)
+            if type(self.appLauncher) is type(None):  # in case we couldn't find one, just assume it's running
+                self.appLauncher = xmlrpclib.ServerProxy("http://" + host + ":" + str(APP_LAUNCHER_PORT))
+
+        # now test the connection
+	try:
+	    self.appLauncher.listMethods() #just use this as a way of testing whether the server is running or not
+	except socket.error:
+	    return False
+	except:
+	    pass
+	return True
+
+
+    def getPort(self):
+	return self.sagePort
+
+    def getHost(self):
+	return self.sageHost
+
+
+    ##################################################################	
+    #  Connect To Sage
+    ##################################################################	
+    def connectToSage(self,host=socket.gethostname(),port=20001):
+	''' returns 1 if succeeded, 0 if no connection to SAGE and -1 if no connection to appLauncher'''
+	if self.connected == True: return 0
+
+	## create socket
+	self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
+	if self.sock is None: return 0
+
+
+        #### RJ 2005-01-21
+	# without this, this thread will never exit because sock.recv is blocking and it will wait until
+	# something comes in. What happens is, "while" checks if threadkilled is false, it is so it goes
+	# in here and blocks until something is received. In the meantime, we want to quit so we set
+	# threadkilled to True but since we are blocked by sock.recv, we wont be able to get to the "while" again
+	self.sock.settimeout(TIMEOUT_INTERVAL)
+        
+
+	if host: self.sageHost = host
+	if port > 0: self.sagePort = port
+	## connect
+	try:
+	    self.sock.connect((host,port))
+	except socket.error:
+	    print 'can\'t connect to SAGE', self.sageHost,self.sagePort	
+	    return 0
+
+	##### FOR Thread
+	self.threadkilled = False
+        self.senderLock = RLock()
+	self.t = Thread(target=self.receiverThread,args=())
+	self.t.start()
+	self.connected = True
+
+        # start the overlay sender thread
+        self.overlayMsgLock = RLock()
+        self.overlayMsgQueue = []   # combined overlay messages (list of string messages)
+        self.overlayMsgFreq = 50    # send messages roughly 50 times a sec
+        self.overlaySender = Thread(target=self.overlaySenderThread)
+        self.overlaySenderKilled = False
+        self.overlaySender.start()
+
+	# now connecting to the appLauncher running on the
+        # same machine as SAGE we are connecting to
+	if self.useAppLauncher and not self.connectToAppLauncher(host):
+	    print "\n===> Can't connect to the appLauncher"
+	    return -1
+	else:
+	    print 'connected to SAGE',self.sageHost,self.sagePort
+	    return 1
+
+
+
+        ### attempts to find the appLauncher that's running on the same machine as myHost
+        ### (by comparing IP addresses of the sage machine and reported appLaunchers)
+    def __getMyAppLauncher(self, myHost):
+        self.updateLauncherList()  #get a new fresh list of appLaunchers
+        
+	def sameByIP(first, second):
+	    try:
+		first = socket.gethostbyname(first)[0]
+		second = socket.gethostbyname(second)[0]
+                if first == second:
+                    return True
+                else:
+                    return False
+            except:
+                return False
+
+        # loop through all the known launchers and try to find the one that matches myHost
+	for launcher in self.launchers.itervalues():
+	    try:
+		if myHost == launcher.getIP():
+		    return launcher.getServerHandle()  #returns the server object that we can call functions on
+                elif sameByIP(myHost, launcher.getIP):
+                    return launcher.getServerHandle()
+                else:
+                    return None
+            except:
+                return None
+                
+    
+    
+    ### connects to the sage server and retrieves the list of all app launchers running
+    def updateLauncherList(self):
+	sageServer = xmlrpclib.ServerProxy("http://"+self.sageServerHost+":"+str(SAGE_SERVER_PORT))
+	try:
+	    # a hash comes back (key=launcherId, value=appList - that's another hash of appNames and configs)
+	    launcherHash = sageServer.GetRegisteredLaunchers()
+	except socket.error:
+	    print "no connection to the sage server... can't get the list of appLaunchers"
+	except:
+	    tb.print_exc()
+	else:
+            self.launchers={}
+	    for launcherString, appList in launcherHash.iteritems():
+		(name, launcherId) = launcherString.split(":",1)
+		(ip, port) = launcherId.split(":",1)
+		self.launchers[launcherId] = AppLauncher(launcherId, name, ip, port, appList)
+		
+	return self.launchers
+
+
+    ### returns a hash of all the appLaunchers currently running
+    def getLaunchers(self):
+	return self.updateLauncherList()
+    
+
+    # get the applist from the applauncher first and call the appropriate function
+    def getAppList(self):
+        appList = {}
+	try:
+	    appList = self.appLauncher.getAppList()
+            self.hashCallbackFunction[ 40000 ]( appList )
+	except socket.error:
+	    self.hashCallbackFunction[ 40000 ]( appList ) #return appList  #the server is not running
+	except:
+	    tb.print_exc()
+            return False
+
+
+    def isConnected(self):
+        return self.connected
+	
+
+    def disconnectFromSage(self, isSocketError=False):
+        """ isSocketError should be True when we didn't close
+            the connection intentionally but rather the connection
+            broke for some reason. In that case the onDisconnect
+            callback is called.
+        """
+	if self.connected == False: return 0
+
+	self.threadkilled = True
+        self.overlaySenderKilled = True
+	self.connected = False		
+	#self.t.join()
+	self.sock.close()
+	del self.sock
+	print 'disconnected from SAGE',self.sageHost,self.sagePort
+
+        if isSocketError and self.onDisconnect:
+            self.onDisconnect()
+        
+	return 1
+
+
+    def sendmsg(self, data, code, sailId=''):
+        if not self.connected:
+            return 0
+
+        self.senderLock.acquire()
+
+        msg = self.makemsg(sailId,code,'',len(data),data)
+	totalcount = 0
+	try:
+	    totalcount = self.sock.send(msg)
+	except socket.error:
+	    print 'SageGateBase: socket error on send'
+	    totalcount = 0
+            self.disconnectFromSage( isSocketError=True )
+	except Exception:
+            tb.print_exc()
+	    totalcount = 0
+
+        self.senderLock.release()
+	return totalcount
+
+
+    ##################################################################	
+    # Register
+    ##################################################################	
+    # 1000 none
+    # 40004 display info format
+    ##################################################################	
+    def registerSage(self):
+ 	if not self.connected:
+	    return 0
+ 	return self.sendmsg('', 1000)
+
+
+    ##################################################################	
+    # Execute
+    ##################################################################	
+    # 1001 app-name 100 100 (app-name(?)) 
+    # 40001 app-inst-ID left right top bottom sail-ID
+    ##################################################################	
+    def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        if not sageIP:  sageIP = self.sageHost
+        if not sagePort: sagePort = self.sagePort+1
+        
+        # try running the app (return -1 if failed for whatever reason)
+        try:
+            res = self.appLauncher.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            return -1
+        else:
+            return res
+
+
+    def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        if not sageIP:  sageIP = self.sageHost
+        if not sagePort: sagePort = self.sagePort+1
+
+        # try running the app (return -1 if failed for whatever reason)
+	if launcherId in self.launchers:
+            server = self.launchers[launcherId].getServerHandle()
+            try:
+                res = server.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+            except:
+                print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+                return -1
+            else:
+                return res
+	else:
+	    print "Launcher not found: ", launcherId
+	    return -1
+
+
+	
+    ##################################################################	
+    # Shutdown
+    ##################################################################	
+    # 1002 app-instance
+    # 40003 app-Inst-ID (?)
+    ##################################################################	
+    def shutdownApp(self,windowId):
+	if self.connected == False: return 0
+
+	data = str(windowId)
+	return self.sendmsg(data, 1002)
+
+
+    ##################################################################	
+    # Forceful Shutdown
+    ##################################################################	
+    def forceShutdownApp(self, portNum):
+	if self.connected == False: return 0
+
+	# the portNum is basically the windowId in the appLauncher context
+	return self.appLauncher.stopApp(portNum)   
+
+
+    ##################################################################	
+    # Move
+    ##################################################################	
+    # 1003 app-instance dist-X,dist-Y
+    ##################################################################	
+    def moveWindow(self,windowId,distX,distY):
+	if self.connected == False: return 0
+
+	#make sure all the coordinates are ints
+	distX = int(distX)
+	distY = int(distY)
+
+	data = str(windowId) + BLANK + str(distX) + BLANK + str(distY)
+	return self.sendmsg(data, 1003)
+	
+
+    ##############################################################
+    # Resize
+    # 1004 app-instance lef,right,top,bottom
+    ##################################################################
+    def resizeWindow(self,windowId,left=0,right=0,bottom=0,top=0):
+	if self.connected == False: return 0
+	#if not windowId: return 0
+
+	#make sure all the coordinates are ints
+	left = int(left)
+	right = int(right)
+	bottom = int(bottom)
+	top = int(top)
+
+	data = str(windowId) + BLANK + str(left) + BLANK + str(right) + BLANK + str(bottom) + BLANK + str(top)
+	return self.sendmsg(data, 1004)
+	
+
+    ###########################################################
+    # Performance Information
+    ###########################################################
+    # 1005 app-instance sending-rate
+    # 1006 app-instance 	
+    ###########################################################	
+    def startPerformance(self,windowId,sendingrate=2):
+	if self.connected == False: return 0
+
+	data = "%d %d" % (windowId, sendingrate )
+	return self.sendmsg(data, 1005)	
+	
+
+    def stopPerformance(self,windowId):
+	if self.connected == False: return 0
+
+	data = str(windowId) # convert the data to string format
+	return self.sendmsg(data, 1006)
+	
+
+
+    ####################################	
+    # Background Color
+    # 1007 red,green blue	
+    ##################################################################
+    def setBgColor(self,(red,green,blue)=(1,1,1)):
+	if self.connected == False: return 0
+
+	data = str(red) + BLANK + str(green) + BLANK + str(blue)
+	return self.sendmsg(data, 1007)
+	
+
+    ####################################	
+    # bring the application window to the top (front)
+    # 1010 app-inst-ID 
+    ##################################################################
+    def bringToFront(self, windowId):
+	if self.connected == False: return 0
+
+	data = str(windowId)
+	return self.sendmsg(data, 1010)
+	
+
+
+    ####################################	
+    # Change App Properties
+    # 1011 windowId, fsmIP, fsmPort, appConfigNum	
+    ##################################################################
+    def changeAppProperties(self,windowId, newTitle, newTitleColor=(-1,-1,-1), newBorderColor=(-1,-1,-1)):
+	if self.connected == False: return 0
+
+	data = str(windowId) + BLANK + str(newTitle)
+	data = data + BLANK + str(newTitleColor[0]) + BLANK + str(newTitleColor[1]) + BLANK + str(newTitleColor[2])
+	data = data + BLANK + str(newBorderColor[0]) + BLANK + str(newBorderColor[1]) + BLANK + str(newBorderColor[2])
+	return self.sendmsg(data, 1011)
+	
+
+    ####################################	
+    # Change App Frame Rate
+    # 1010 windowId, fsmIP, fsmPort, appConfigNum	
+    ##################################################################
+    def changeAppFrameRate(self,windowId, newFrameRate):
+	if self.connected == False: return 0
+
+	data = str(windowId) + BLANK + str(newFrameRate)
+	return self.sendmsg(data, 1012)
+	
+
+
+    ####################################	
+    # Stream Request
+    # 1014 windowId, fsmIP, fsmPort
+    ##################################################################
+    def streamApp(self,windowId, fsmIP, fsmPort):
+	if self.connected == False: return 0
+
+	data = str(windowId) + BLANK + str(fsmIP) + BLANK + str(fsmPort)
+	return self.sendmsg(data, 1014)
+	
+
+
+    ####################################	
+    # Rotate Window
+    # 1018 windowId, degree
+    ##################################################################
+    def rotateWindow(self, windowId, degree):
+	if self.connected == False: return 0
+
+	data = str(windowId) + BLANK + str(degree)
+	return self.sendmsg(data, 1018)
+
+
+
+    ####################################	
+    # Overlay Messages
+    # 1200 - 1205
+    ##################################################################
+    def addOverlay(self, overlayType, x, y, w, h, isGlobal, drawOrder):
+        data = '%s %s %s %s %s %s %s' % (overlayType, x, y, w, h, int(isGlobal), drawOrder)
+        return self.sendmsg(data, 1200)
+
+
+    def moveOverlay(self, id, dx, dy):
+        """ relative movement """
+        data = '%s %s %s' % (id, dx, dy)
+        return self.sendmsg(data, 1201)
+    
+
+    def showOverlay(self, id, doShow):
+        data = '%s %s' % (id, str(int(doShow)))
+        return self.sendmsg(data, 1204)
+
+
+    def sendOverlayMessage(self, id, *data):
+        """ this actually puts the messages in a queue
+            which are then sent at fixed intervals """
+
+        # first assemble the data into a string
+        msg = '%s' % (id)
+        for d in data:   
+            msg += " "+str(d)
+
+        self.overlayMsgLock.acquire()
+        self.overlayMsgQueue.append(msg)
+        self.overlayMsgLock.release()
+
+
+    def __sendMultipleOverlayMessages(self, msg):  # a bunch of messages combined into one
+        return self.sendmsg(msg, 1203)
+
+
+    def removeOverlay(self, id):
+        data = '%s' % (id)
+        return self.sendmsg(data, 1202)
+        
+
+    ####################################	
+    # SAGE App events
+    # 31000 - 31007
+    ##################################################################
+
+    def sendAppEvent(self, eventId, sailId, *data):
+        # first assemble the data into a string
+        msg = ''
+        for d in data:   
+            msg += " "+str(d)
+        self.sendmsg(msg, 31000+eventId, sailId)
+
+
+    ####################################	
+    # SAGE shutdown
+    # 1100 	<none>
+    ##################################################################
+    def shutdownSAGE(self):
+	if self.connected == False: return 0
+	return self.sendmsg('', 1100)
+
+
+
+    ##############
+    #  Overlay Sender Thread
+    #    - Sends combined overlay messages at fixed intervals
+    ##################################################################
+    def overlaySenderThread(self):
+        while not self.overlaySenderKilled and doRun():
+            self.overlayMsgLock.acquire()
+
+            # iterate through the msg queue and assemble the messages into a string
+            msg = ""
+            for m in self.overlayMsgQueue:
+                msg += m + "\n"            # separate messages with \n
+            self.overlayMsgQueue = []      # clear the queue
+            self.overlayMsgLock.release()
+
+            # send the message if there is something to send
+            msg = msg.strip()
+            if msg != "":
+                self.__sendMultipleOverlayMessages(msg)
+                
+            # sleep for a certain time
+            time.sleep(1.0/self.overlayMsgFreq)
+
+        print "Overlay message sender thread closed"
+	
+
+    ##############
+    #  Receiver Thread
+    #    - receives messages from SAGE in a thread
+    ##################################################################
+    def receiverThread(self):
+
+	while self.threadkilled == False and doRun():   #doesn't work as expected without the sock.settimeout (look below)
+
+	    #############################
+	    try:
+
+		code = ""
+		incomingMsg = ""
+		msgSize = ""
+
+		# first make sure you read the whole 8 bytes for the size
+		while len(msgSize) < HEADER_ITEM_LEN:
+		    msgSize = self.sock.recv(HEADER_ITEM_LEN)
+		    if len( msgSize ) == 0:
+			self.threadkilled = True
+                        self.overlaySenderKilled = True
+                        self.disconnectFromSage( isSocketError=True )
+			break
+
+                if self.threadkilled: break
+                
+		# this is the number of bytes that the total message contains
+		msgSize = msgSize.replace('\x00', '')
+		sizeLeft = int(msgSize) - HEADER_ITEM_LEN    # we already read the size so read the rest of the bytes
+
+		# read the rest of the message
+		while len( incomingMsg ) < sizeLeft:
+		    incomingMsg = incomingMsg + self.sock.recv( sizeLeft - len(incomingMsg) )
+
+		# extract the tokens from the message
+		if len( incomingMsg ) > 0:
+		    incomingMsg = incomingMsg.replace('\x00', ' ')
+		    dst = incomingMsg[ 1:9 ].strip()
+		    code = int(incomingMsg[ 10:18 ].strip())
+		    appCode = incomingMsg[ 19:27 ].strip()
+		    data = incomingMsg[ 28: ].strip()
+
+		    # print the message out (except performance info since there are many of them)
+                    if self.verbose and code in self.hashIncomingMessages and code != 40002:
+                        print "\n\tRECEIVED:  " + self.hashIncomingMessages[code]
+                        lines = data.split('\n')
+                        if len(lines) < 2:
+                            print "\t\t   [" + lines[0] + "]\n\n"
+                        else:
+                            for i in range(0, len(lines)):
+                                if i == 0:
+                                    print "\t\t   [" + lines[i]
+                                elif i == len(lines)-1:
+                                    print "\t\t    " + lines[i] + "]\n\n"
+                                else:
+                                    print "\t\t    " + lines[i]
+
+
+	    except socket.timeout:
+		continue
+	    except socket.error:
+		#print 'SageGateBase: socket error on receive'
+                #self.disconnectFromSage( isSocketError=True )
+		continue
+	    #except:
+	    #	print 'exception: ', sys.exc_info()[0], sys.exc_info()[1]
+	    #	break
+	    ############################
+
+	    if self.threadkilled:
+		break
+
+	    # finally, do something with this message (ie call the subclass' message handler)
+            self.onMessage( code, data )
+
+        print "SageGate receiver thread closed"
+        
+
+    def cleanBuffer( self, stBuffer ):
+        """ converts all non-printable characters from the buffer to white spaces
+            (so that they can be removed using string.strip() function)
+        """
+	stNewBuffer = ""
+
+	for ch in stBuffer:
+	    if ( ch in string.printable ):
+		stNewBuffer = stNewBuffer + ch
+	    else:
+		stNewBuffer = stNewBuffer + " "
+
+	return stNewBuffer
+
+
+
+    def onMessage(self, code, data):
+        """ this is the function that gets called after a message arrives successfully
+            it must be overridden by the subclass
+        """
+        raise NotImplementedError
+
+
+    def registerCallbackFunction( self, msgID, function ):
+	self.hashCallbackFunction[ msgID ] = function
+
+
+
+
+
+        
+
+
Index: trunk/src/testing/ui/sageui.py
===================================================================
--- trunk/src/testing/ui/sageui.py	(revision 4)
+++ trunk/src/testing/ui/sageui.py	(revision 4)
@@ -0,0 +1,1292 @@
+#!/usr/bin/env python
+
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#         Allan Spale
+#
+############################################################################
+
+
+
+
+############################################################################
+#
+#  IMPORTS
+#
+############################################################################
+
+# python and wx stuff
+import string, sys, os, copy, optparse, time
+from threading import Timer
+import traceback as tb
+
+# hyperlink module is not (yet) included with wxPython as a standard module
+# so not all distributions have it
+global use_hyperlink
+use_hyperlink = True
+try:
+    import wx.lib.hyperlink as hyperlink    #for the about box
+except:
+    use_hyperlink = False
+
+# if this UI should autosave
+global autosave
+
+# my stuff
+import Graph
+from sageGate import *
+from sageData import *
+from canvases import *
+from globals import *
+from users import * 
+import preferences as prefs
+import launcherAdmin as lAdmin
+from sagePath import getUserPath
+
+
+############################################################################
+#
+#  GLOBAL CONSTANTS
+#
+############################################################################
+
+# current version of the UI
+VERSION = "3.0a"
+setUIVersion(VERSION)
+
+
+### IDS used for the menu items:
+SAVE_STATE = 10
+LOAD_STATE = 1
+ASPECT_RATIO = 2
+SAGE_COLOR = 3
+PERF_DATA = 4
+LOG_PERF_DATA = 5
+RENDER_BW = 6
+DISPLAY_BW = 7
+RECORD_SESSION = 8
+READ_SESSION = 9
+SAGE_SHUTDOWN = 11
+TILE_WINDOWS = 12
+
+
+
+############################################################################
+
+class Log:
+    def WriteText(self, text):
+        if text[-1:] == '\n':
+            text = text[:-1]
+        wx.LogMessage(text)
+    write = WriteText
+
+
+assertMode = wx.PYAPP_ASSERT_DIALOG
+
+
+
+############################################################################
+#
+#  CLASS: DisplayNotebook
+#  
+#  DESCRIPTION: This is the main container (notebook) for the UI. It holds
+#               one DisplayPage for every connection to SAGE. It also handles
+#               page changes and menu changes when switching pages.
+#
+#  DATE:        June, 2005
+#
+############################################################################
+
+class DisplayNotebook(wx.Notebook):
+
+    def __init__(self, parent):
+        wx.Notebook.__init__(self, parent, -1, style=wx.NO_BORDER)
+        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChange)
+
+        # open the file for recording totals for all sites
+        try:
+            stDateTime = time.strftime("%Y%m%d-%H%M%S", time.localtime())
+            stFilename = "ALL_SITES_TOTALS-" + stDateTime
+            stPath = opj(DATA_DIR, stFilename + ".txt")
+            self._totalsFile = open(stPath, "w")
+            self._totalsFile.write( time.asctime() + "\n" )
+            self._totalsFile.write( '-' * 40 + "\n" )
+            tempString = (' Timestamp(s)    Disp BW(Gbps)    Rend BW(Gbps)   Num Sites\n')
+            self._totalsFile.write(tempString)
+            self._totalsFile.write( '-' * len(tempString) + "\n" )
+            self._totalsFile.flush()
+        except:
+            print "\n\nERROR: Unable to record performance totals in a file:\n"
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            self._totalsFile = None
+
+        # start the timer to periodically record totals
+        self.Bind(wx.EVT_TIMER, self.onPerfTimer)
+        self.perfTimer = wx.Timer(self)
+        self.perfTimer.Start(1000)
+
+
+        ### this timer is called once per second to write the performance
+        ### data totals to a file (for each sage connection)
+    def onPerfTimer(self, event):
+        totalR,totalD = 0,0  # totals for ALL sites... render and display
+        recordTotals = False
+        
+        for pageIndex in range(0, self.GetPageCount()):
+            p = self.GetPage(pageIndex)
+            p.SaveSiteTotals()
+            totalR += p.GetRenderTotal()
+            totalD += p.GetDisplayTotal()
+
+            # if no sites are logging data, dont record totals either
+            if p.sageData.isLoggingEnabled():
+                recordTotals = True
+                
+        
+        # now save the total of all sites
+        if recordTotals and self._totalsFile:
+            temp = "%12d    %12.4f    %12.4f       %d\n" % (getTimeStamp(),
+                                                            totalD,
+                                                            totalR,
+                                                            self.GetPageCount())
+            self._totalsFile.write(temp)
+            self._totalsFile.flush()
+
+
+        ### test whether an application window was dropped on a notebook tab
+        ### if it was, send a message to SAGE about the request
+        ### used to request streaming of an application to multiple displays
+    def DropTest(self, windowId, pt):
+        tab_tuple = self.HitTest((pt[0], pt[1]*(-1)))  # *(-1) since tabs are above the canvas (negative y coordinate with respect to it)
+        newTab = tab_tuple[0]
+        currentTab = self.GetSelection()
+        
+        if newTab == wx.NOT_FOUND or newTab == currentTab:
+            return False
+        else:
+            currentPage = self.GetPage(currentTab)
+            newPageMachine = self.GetPage(newTab).GetMachine()
+            fsmIP = newPageMachine.GetSystemIP()
+            fsmPort = newPageMachine.GetSystemPort() 
+            currentPage.sageGate.streamApp(windowId, fsmIP, fsmPort)  #send a message
+            self.SetSelection( newTab )  #open the new tab
+            return True
+
+
+
+    def GetFrame(self):
+        return self.GetParent()
+
+
+        ### this takes care of setting the proper menu items in the frame when a page changes
+        ### it basically pulls the state of all the menu check items from the newly selected
+        ### page and copies that hash into the hash of menu check items of the frame
+    def OnPageChange(self, event):
+        currentPageIndex = event.GetSelection() #must use event.GetSelection() instead of self.GetSelection() because WXMSW and WXMAC report the old selection otherwise 
+        if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
+            newPage = self.GetPage(currentPageIndex)
+            self.GetFrame().UpdateMenuItems(newPage.GetCurrentMenuItems())  #refresh the menu now so that it reflects the menu Items from the different page
+        event.Skip()
+
+
+    def SetDefaultMenuCheckItems(self, hashItems):
+        self.defaultMenuCheckItems = hashItems.copy()
+
+
+    def GetDefaultMenuCheckItems(self):
+        return self.defaultMenuCheckItems.copy()
+
+
+    def CloseCurrentPage(self, closeUI=True):
+        if self.GetPageCount() < 2 and closeUI:
+            self.GetFrame().Close(True)
+        elif self.GetPageCount() > 1:
+            currentPageIndex = self.GetSelection()
+            if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
+                page = self.GetPage(currentPageIndex)
+                page.OnClose()
+                self.DeletePage(currentPageIndex)
+
+                #refresh the menu now so that it reflects the menu Items from the different page
+                newPageIndex = self.GetSelection()
+                newPage = self.GetPage(newPageIndex)
+                self.GetFrame().UpdateMenuItems(newPage.GetCurrentMenuItems())
+        else:   # this is the case if the user reconnected to SAGE when there was only one tab open previously
+            currentPageIndex = self.GetSelection()
+            if not currentPageIndex == -1:  #windows reports -1 for some reason during creation
+                page = self.GetPage(currentPageIndex)
+                page.OnClose()
+                self.DeletePage(currentPageIndex)
+
+    
+    def OnClose(self, event):
+        for pageIndex in range(0, self.GetPageCount()):
+            self.GetPage(pageIndex).OnClose(event)
+
+        if self._totalsFile: self._totalsFile.close()
+        self.perfTimer.Stop()
+        
+
+    def OnKeyEvent(self, event):
+        if event.GetKeyCode() == wx.WXK_F9:
+            currentPage = self.GetPage(self.GetSelection())
+            currentPage.GetDisplayCanvas().TileShapes()
+
+ 
+    def OnMenuEvent(self, event):
+        eventId = event.GetId()  
+        menuItem = self.GetFrame().GetMenuBar().FindItemById(eventId)
+        currentPage = self.GetPage(self.GetSelection())
+        
+        # this ONLY changes the specific page's state of the selected menu item
+        if menuItem.IsCheckable():
+            if menuItem.IsChecked():
+                currentPage.CheckMenuItem(eventId)
+            else:
+                currentPage.UncheckMenuItem(eventId)
+                
+        # call the correct menu event handler
+        if eventId == SAVE_STATE:
+            currentPage.OnSaveState()
+        elif eventId == LOAD_STATE:
+            currentPage.OnLoadState()
+        elif eventId == ASPECT_RATIO:
+            currentPage.OnMaintainAspectRatio(menuItem)
+        elif eventId == SAGE_COLOR:
+            currentPage.OnSAGEColorChange()
+        elif eventId == PERF_DATA:
+            currentPage.OnReceivePerfData(menuItem)
+        elif eventId == LOG_PERF_DATA:
+            currentPage.OnLogPerfData(menuItem)
+        elif eventId == RENDER_BW:
+            currentPage.OnShowRenderBW(menuItem)
+        elif eventId == DISPLAY_BW:
+            currentPage.OnShowDisplayBW(menuItem)
+        elif eventId == RECORD_SESSION:
+            currentPage.OnRecordSession(menuItem)
+        elif eventId == READ_SESSION:
+            currentPage.OnReadSession()
+        elif eventId == SAGE_SHUTDOWN:
+            currentPage.OnSAGEShutdown()
+        else:
+            pass  #nothing... we dont know how to handle anything else
+
+
+
+
+
+############################################################################
+#
+#  CLASS: DisplayPage
+#  
+#  DESCRIPTION: DisplayPage is a panel that holds all the controls associated
+#               with one SAGE connection (DisplayCanvas and AppInfoPanel). There
+#               is one for every connection and they are all placed in a notebook
+#               (DisplayNotebook). 
+#
+#  DATE:        June, 2005
+#
+############################################################################
+
+class DisplayPage(wx.Panel):
+    def __init__(self, parent, sageGate, usersClient, machineId, title):
+        wx.Panel.__init__(self, parent, -1, style=wx.NO_BORDER)
+
+        self.parent = parent
+        # create main data storage and conectivity objects
+        self.machineId = machineId
+        self.usersClient = usersClient
+        self.usersData = getUsersData()
+        self.sageGate = sageGate
+        self.sageData = SageData(sageGate, autosave, title.split('@')[1])
+        self.RegisterCallbacks()
+        self.menuCheckItems = self.GetParent().GetDefaultMenuCheckItems()
+        self.GetParent().GetFrame().UpdateMenuItems(self.GetCurrentMenuItems()) #update the menu items
+
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+
+        # get the machine name
+        self.siteName = machineId
+        m = self.usersData.GetMachine(machineId)
+        if m:
+            self.siteName = m.GetName()
+        
+        # (AKS 2005-01-27) Performance graph object
+        self.gmGraphManager = Graph.GraphManager( self, self.sageData )
+        # (AKS 2005-05-07) Create constants to identify totals graphs
+        self.I_RENDER_BW_GRAPH = 1
+        self.I_DISPLAY_BW_GRAPH = 2
+        
+        self.displayCanvas = DisplayCanvas(Log(), self, self.sageGate, self.sageData, self.gmGraphManager, title)
+        self.appPanel = AppInfoPanel(self, self.sageGate, self, -1, (0,0), (self.displayCanvas.GetCanvasWidth(), 200), wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE)
+        self.sageGate.getAppList()  # this will get the list and fill the appPanel with it
+        #self.Show()  < -- this is done in DisplayCanvas.OnStatusMessage()  (canvases.py)
+
+
+    def GetFrame(self):
+        return self.GetParent().GetParent()
+
+    def GetNotebook(self):
+        return self.GetParent()
+
+    def GetNumPages(self):
+        return self.GetNotebook().GetPageCount()
+
+    def GetCurrentMenuItems(self):
+        return self.menuCheckItems.copy()  #return the current state of menu items specific to this display
+
+    def CheckMenuItem(self, menuItemId):
+        self.menuCheckItems[menuItemId] = True
+
+    def UncheckMenuItem(self, menuItemId):
+        self.menuCheckItems[menuItemId] = False
+
+    def GetMachineId(self):
+        return self.machineId
+
+    def GetMachine(self):
+        return self.usersData.GetMachine(self.machineId)
+
+    
+    #----------------------------------------------------------------------    
+
+    def RegisterCallbacks(self):
+        # (AKS 2005-01-13)
+        # Register callbacks from SageData with SageGate
+        # Whenever SageGate receives an update message from SAGE,
+        # the client-side "app database" stored in SageData
+        # will be updated and then issue its own callback function
+        # to tell the registering app to retrieve and process
+        # the updated data
+
+        self.sageGate.registerCallbackFunction( 40000, self.sageData.setSageStatus )
+        self.sageGate.registerCallbackFunction( 40001, self.sageData.setSageAppInfo )
+        self.sageGate.registerCallbackFunction( 40002, self.sageData.setSagePerfInfo )
+        self.sageGate.registerCallbackFunction( 40003, self.sageData.sageAppShutDown )
+        self.sageGate.registerCallbackFunction( 40004, self.sageData.setDisplayInfo )
+        self.sageGate.registerCallbackFunction( 40005, self.sageData.setSageZValue )
+        self.sageGate.registerCallbackFunction( 40006, self.sageData.setSageAppExecConfig )
+        self.sageGate.registerCallbackFunction( 40007, self.sageData.setDisplayConnections )
+        
+        return self.sageData
+
+
+    #----------------------------------------------------------------------
+    
+
+    def GetDisplayCanvas(self):
+        return self.displayCanvas
+
+    def GetAppInfoPanel(self):
+        return self.appPanel
+
+    def GetAppPanel(self):
+        return self.appPanel.GetAppPanel()
+
+    def GetInfoPanel(self):
+        return self.appPanel.GetInfoPanel()
+
+    def HideAppInfoPanel(self): 
+        self.oldHeight = self.GetClientSize().height
+        newHeight = self.oldHeight - self.GetAppInfoPanel().GetSize().height + 60
+        self.GetFrame().SetClientSize( (self.GetFrame().GetClientSize().width, newHeight) )
+        self.GetAppInfoPanel().OnSize()
+            
+    def ShowAppInfoPanel(self):
+        self.GetFrame().SetClientSize( (self.GetFrame().GetClientSize().width, self.oldHeight) )
+        self.GetAppInfoPanel().OnSize()
+    
+
+    def SaveSiteTotals(self):
+        self.sageData.saveSiteTotals(self.siteName)
+
+    def GetRenderTotal(self):
+        """ returns total display bandwidth in gbps """
+        return self.sageData.getRenderBWTotal()
+
+    def GetDisplayTotal(self):
+        """ returns total rendering bandwidth in gbps """
+        return self.sageData.getDisplayBWTotal()
+    
+
+    #----------------------------------------------------------------------
+    # EVENT HANDLERS
+    #----------------------------------------------------------------------
+
+    def OnDisplayInfo(self):
+        pass
+        
+        
+    def OnSize(self, event=None):
+        self.SetSize(self.GetParent().GetClientSize())#event.GetSize())
+        if "__WXMSW__" in wx.PlatformInfo:   #to bypass MS Windows' deferred resizing crap
+            def doResize():
+                self.GetDisplayCanvas().OnSize(event)
+                self.GetAppInfoPanel().OnSize(event)
+            wx.CallAfter(doResize)
+        else:
+            self.GetDisplayCanvas().OnSize(event)
+            self.GetAppInfoPanel().OnSize(event)
+        
+
+    def OnClose(self, evt=None):
+        self.GetDisplayCanvas().Close()
+        self.gmGraphManager.shutdown()  # close all the graphs that might be open
+        
+        # close the "Totals" graphs (if open)
+        #if self.menuCheckItems[RENDER_BW]:
+        #    self.removeGraph(self.I_RENDER_BW_GRAPH)
+        #if self.menuCheckItems[DISPLAY_BW]:
+        #    self.removeGraph(self.I_DISPLAY_BW_GRAPH)
+
+        # stop all the running features
+        self.usersClient.Unregister(self.machineId)  #tell the server that we are not registered in this room anymore
+        self.sageData.stopLogging()
+        #self.sageGate.StopRecording()
+        self.sageGate.disconnectFromSage()  #break the connection with SAGE
+
+
+       # Menu -> Options -> Change SAGE Background Color
+    def OnSAGEColorChange(self):
+        (r,g,b) = self.sageData.getSAGEColor()
+        colorData = wx.ColourData()
+        colorData.SetColour(wx.Colour(r,g,b))
+        dlg = wx.ColourDialog(None, colorData)
+        dlg.GetColourData().SetChooseFull(True)
+        if dlg.ShowModal() == wx.ID_OK:
+            data = dlg.GetColourData()
+            self.sageData.setSAGEColor(data.GetColour().Get())
+            self.sageGate.setBgColor(self.sageData.getSAGEColor())
+            self.GetDisplayCanvas().ChangeBackgroundColor(self.sageData.getSAGEColor())
+        dlg.Destroy()
+
+
+        # Menu -> File -> Shutdown SAGE
+    def OnSAGEShutdown(self):
+        dlg = wx.MessageDialog(self, "You are about to shutdown SAGE. All the currently connected "+
+                                     "users will be disconnected and all applications closed. \nAre "+
+                                     "you sure you want to continue?", "SAGE Shutdown", wx.YES_NO | wx.ICON_EXCLAMATION)
+        if dlg.ShowModal() == wx.ID_YES:
+            self.sageGate.shutdownSAGE()
+            
+
+    # Menu -> File -> Save State
+    def OnSaveState(self):
+        def OnStateSelected(evt):
+            if nameText.GetValue() in stateHash:
+                descriptionText.SetValue( stateHash[nameText.GetValue()] )
+                
+        def OnDeleteState(evt):
+            stateName = nameText.GetValue()
+            if stateName in stateHash:
+                if self.sageData.deleteState(stateName):
+                    descriptionText.Clear()
+                    nameText.Delete(nameText.FindString(stateName))
+                    nameText.SetValue("")
+                else:
+                    Message("Error deleting the saved state. Do you have the required permissions?", "Error Deleting")
+                                 
+        
+        stateHash = self.sageData.getStateList()
+        
+        dlg = wx.Dialog(self, -1, "Save Display Session")
+        okBtn = wx.Button(dlg, wx.ID_OK, "Save")
+        delBtn = wx.Button(dlg, wx.ID_OK, " Delete ", style=wx.BU_EXACTFIT)
+        delBtn.Bind(wx.EVT_BUTTON, OnDeleteState)
+
+        states = stateHash.keys()
+        states.sort()
+        nameLabel = wx.StaticText(dlg, -1, "Session name:")
+        nameText = wx.ComboBox(dlg, -1, "", choices=states, style=wx.CB_DROPDOWN)
+        nameText.Bind(wx.EVT_COMBOBOX, OnStateSelected)
+        nameText.SetFocus()
+        descriptionLabel = wx.StaticText(dlg, -1, "Description:")
+        descriptionText = wx.TextCtrl(dlg, -1, "", style=wx.TE_MULTILINE)
+        
+        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
+        nameSizer.Add(nameLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
+        nameSizer.Add(nameText, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        nameSizer.Add(delBtn, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=5)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(nameSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, border=10)
+        sizer.Add(descriptionLabel, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.TOP, border=10)
+        sizer.Add(descriptionText, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.RIGHT | wx.LEFT, border=10)
+        sizer.AddSpacer((15,15))
+        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
+        sizer.AddSpacer((5,5))
+
+        dlg.SetSizer(sizer)
+        dlg.SetSize((350, 300))
+
+        stateName = ""
+        description = ""
+        while dlg.ShowModal() == wx.ID_OK:
+            stateName = nameText.GetValue()
+            description = descriptionText.GetValue()
+            if stateName == "":
+                Message("Please name the session you are saving", "Session name required")
+                continue
+            elif stateName in stateHash:
+                if wx.MessageBox("Session with that name already exists. Overwrite?",
+                                 "Overwrite?", style=wx.YES_NO) == wx.YES:
+                    dlg.Destroy()
+                else:
+                    continue
+            self.sageData.saveState(stateName, description)
+            break
+            
+        return
+        
+
+
+    # Menu -> File -> Load State
+    def OnLoadState(self):
+        def OnStateSelected(evt):
+            descriptionText.SetLabel( stateHash[stateList.GetStringSelection()] )
+            
+        def OnDeleteState(evt):
+            stateName = stateList.GetStringSelection()
+            if stateName in stateHash:
+                if self.sageData.deleteState(stateName):
+                    stateList.Delete(stateList.FindString(stateName))
+                    if not stateList.IsEmpty():
+                        stateList.Select(0)
+                        descriptionText.SetLabel(stateHash[stateList.GetString(0)])
+                    else:
+                        descriptionText.SetLabel("")
+                else:
+                    Message("Error deleting the saved state. Do you have the required file permissions?", "Error Deleting")
+
+                                 
+        stateHash = self.sageData.getStateList()
+        if len(stateHash) == 0:
+            Message("No saved sessions exist", "")
+            return
+    
+        dlg = wx.Dialog(self, -1, "Load Saved Session")
+        okBtn = wx.Button(dlg, wx.ID_OK, "Load")
+        okBtn.Disable()
+        delBtn = wx.Button(dlg, wx.ID_OK, " Delete ", style=wx.BU_EXACTFIT)
+        delBtn.Bind(wx.EVT_BUTTON, OnDeleteState)
+
+        states = stateHash.keys()
+        states.sort()
+        states = stateHash.keys()
+        states.sort()
+        stateLabel = wx.StaticText(dlg, -1, "Saved Sessions:")
+        stateList = wx.Choice(dlg, -1, choices=states)
+        stateList.Bind(wx.EVT_CHOICE, OnStateSelected)
+        descriptionBox = wx.StaticBox(dlg, -1, "Description:")
+        descriptionText = wx.StaticText(dlg, -1, "", style=wx.ST_NO_AUTORESIZE)
+
+        dbSizer = wx.StaticBoxSizer(descriptionBox, wx.VERTICAL)
+        dbSizer.Add(descriptionText, 1, wx.EXPAND | wx.ALL, border=5)
+        
+        if len(stateHash) > 0:
+            stateList.SetSelection(0)
+            descriptionText.SetLabel( stateHash[stateList.GetString(0)] )
+            okBtn.Enable()
+        
+        stateSizer = wx.BoxSizer(wx.HORIZONTAL)
+        stateSizer.Add(stateLabel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
+        stateSizer.Add(stateList, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
+        stateSizer.Add(delBtn, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=5)
+        
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(stateSizer, 0, wx.EXPAND | wx.ALIGN_LEFT | wx.ALL, border=10)
+        sizer.Add(dbSizer, 1, wx.EXPAND | wx.ALIGN_LEFT | wx.RIGHT | wx.LEFT, border=10)
+        sizer.AddSpacer((15,15))
+        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
+        sizer.AddSpacer((5,5))
+
+        dlg.SetSizer(sizer)
+        dlg.SetSize((350, 300))
+
+        if dlg.ShowModal() == wx.ID_OK:
+            stateName = stateList.GetStringSelection()
+            dlg.Destroy()
+            if stateName == "":
+                Message("No saved sessions exist", "")
+                return
+            self.sageData.loadState(stateName)
+
+        return
+        
+        
+
+    # Menu -> Options -> RecordSession
+    def OnRecordSession(self, menuItem):
+        if menuItem.IsChecked():
+            self.sageGate.StartRecording(menuItem)
+        else:
+            self.sageGate.StopRecording()
+
+
+    # Menu -> Options -> ReadSession
+    def OnReadSession(self):
+        self.sageGate.PlaySession(self)
+        
+        
+    # Menu -> Options -> MaintainAspectRatio
+    def OnMaintainAspectRatio(self, menuItem):
+        diagram = self.GetDisplayCanvas().GetDiagram()
+        shapeList = diagram.GetShapeList()
+
+        # store the flag for future apps
+        self.GetDisplayCanvas().SetMaintainAspectRatio( menuItem.IsChecked() )
+
+        # change all the current apps' flags
+        for s in shapeList:
+            if ( s.__class__.__name__ == MyRectangleShape.__name__ ):
+                s.SetMaintainAspectRatio( self.displayCanvas.GetMaintainAspectRatio() )
+
+
+    # Menu -> Performance -> Logging
+    def OnLogPerfData(self, menuItem):
+        self.sageData.setLoggingFlag( menuItem.IsChecked() )
+
+
+    # Menu -> Performance -> Receive Performance Data
+    def OnReceivePerfData(self, menuItem):
+        self.GetDisplayCanvas().ReceivePerformanceData( menuItem.IsChecked() )
+
+
+    # (AKS 2005-05-07)
+    def OnShowRenderBW( self, menuItem ):
+        if ( menuItem.IsChecked() == True ):
+            self.__sgRenderBWGraph = Graph.SingleGraph(
+                self, self.sageData.getRenderBandwidthGraph(), "Totals: Render Bandwidth",
+                "Totals: Render Bandwidth", "Bandwidth (Mbps)", self.I_RENDER_BW_GRAPH )
+            self.__sgRenderBWGraph.registerShutdownCallback( self.removeGraph )
+            self.gmGraphManager.AddToUpdateList(self.__sgRenderBWGraph)
+        else:
+            self.gmGraphManager.RemoveFromUpdateList(self.__sgRenderBWGraph)
+            self.__sgRenderBWGraph.manualShutdown()
+
+        # end if
+
+
+    # (AKS 2005-05-07)
+    def OnShowDisplayBW( self, menuItem ):
+        if ( menuItem.IsChecked() == True ):
+            self.__sgDisplayBWGraph = Graph.SingleGraph(
+                self, self.sageData.getDisplayBandwidthGraph(), "Totals: Display Bandwidth",
+                "Totals: Display Bandwidth", "Bandwidth (Mbps)", self.I_DISPLAY_BW_GRAPH )
+            self.__sgDisplayBWGraph.registerShutdownCallback( self.removeGraph )
+            self.gmGraphManager.AddToUpdateList(self.__sgDisplayBWGraph)
+        else:
+            self.gmGraphManager.RemoveFromUpdateList(self.__sgDisplayBWGraph)
+            self.__sgDisplayBWGraph.manualShutdown()
+
+        # end if
+        
+
+    # (AKS 2005-05-07)
+    def removeGraph( self, iGraphID ):
+        if ( iGraphID == self.I_RENDER_BW_GRAPH ):
+            self.gmGraphManager.RemoveFromUpdateList(self.__sgRenderBWGraph)
+            self.__sgRenderBWGraph.manualShutdown()
+            self.UncheckMenuItem(RENDER_BW)
+            self.GetFrame().UpdateMenuItems(self.GetCurrentMenuItems())  #we must manually update the frame
+
+        elif ( iGraphID == self.I_DISPLAY_BW_GRAPH ):
+            self.gmGraphManager.RemoveFromUpdateList(self.__sgDisplayBWGraph)
+            self.__sgDisplayBWGraph.manualShutdown()
+            self.UncheckMenuItem(DISPLAY_BW)
+            self.GetFrame().UpdateMenuItems(self.GetCurrentMenuItems())  #we must manually update the frame
+
+        # end if; else, do nothing
+
+
+
+
+
+
+
+############################################################################
+#
+#  CLASS: SAGEuiFrame
+#  
+#  DESCRIPTION: It describes the main frame that holds all the other controls.
+#               It creates the two main canvases for the UI:
+#                       - the tiled display representation (upper canvas)
+#                       - the area for displaying app info (lower canvas)
+#
+#  DATE:        February 28, 2005
+#
+############################################################################
+
+class SAGEuiFrame(wx.Frame):
+
+    def __init__(self, sageGate, usersClient, firstMachineId, loadState, title=""):
+        self.loadState = loadState  # for automatically loading a saved display state upon startup
+        
+        if prefs.visual.GetFramePos() != None:
+            position = prefs.visual.GetFramePos()
+        else:
+            position = (50,0)
+            if "__WXMAC__" in wx.PlatformInfo:
+                position = (50,50)
+                
+        wx.Frame.__init__(self, None, -1, "SAGE UI",
+                          pos=position,
+                          size=(500,300),
+                          style=wx.DEFAULT_FRAME_STYLE )#| wx.FULL_REPAINT_ON_RESIZE)
+        
+        # this is the only common thing between the pages
+        self.usersClient = usersClient
+        self.usersData = getUsersData()
+
+        # so that we can kill SAGE from the UI
+        self.sageGate = sageGate
+        
+        # make the menu
+        self.SetMenuBar( self.CreateMenu() )
+
+        # bind any events we need
+        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_MOVE, self.OnMove)
+        self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
+                  
+        # This creates some pens and brushes that the OGL library uses.
+        # It should be called after the app object has been created, but
+        # before OGL is used.
+        ogl.OGLInitialize()    
+        
+        self.notebook = DisplayNotebook(self)
+        tempHash = {}    #extract the values of all the checkable menu items and send them to the notebook as default values
+        for key, mi in self.menuCheckItems.iteritems():
+            tempHash[key] = mi.IsChecked()
+        self.notebook.SetDefaultMenuCheckItems(tempHash)
+        self.notebook.AddPage(DisplayPage(self.notebook, sageGate, usersClient, firstMachineId, title), title.split('@')[1], True)
+        self.usersPanel = UsersPanel(self, usersClient)
+        #self.Show()  < -- this is done in DisplayCanvas.OnSAGEDisplaysConnection()  (canvases.py)
+
+
+    #----------------------------------------------------------------------
+
+
+    def CreateMenu(self):      
+        self.menuBar = wx.MenuBar()
+
+        # File
+        menuFile = wx.Menu()
+
+        miFileNew = menuFile.Append(-1, "&New Connection\tCtrl-N", "Connect to another display")
+        self.Bind(wx.EVT_MENU, self.OnNewConnection, miFileNew)
+
+        miFileClose = menuFile.Append(-1, "Close Connection\tCtrl-W", "Close connection with this display")
+        self.Bind(wx.EVT_MENU, self.OnCloseConnection, miFileClose)
+
+        menuFile.AppendSeparator()
+        
+        miFileSave = menuFile.Append(SAVE_STATE, "&Save Session\tCtrl-S", "Save current session")
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileSave)
+
+        miFileLoad = menuFile.Append(LOAD_STATE, "&Load Session\tCtrl-O", "Load previously saved session")
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileLoad)
+
+        menuFile.AppendSeparator()
+
+        miFileSAGEShutdown = menuFile.Append(SAGE_SHUTDOWN, "Shutdown SAGE", "Shutdown SAGE")
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, miFileSAGEShutdown)
+
+        menuFile.AppendSeparator()
+
+        miFileExit = menuFile.Append(-1, "E&xit\tAlt-X", "Exit demo")
+        self.Bind(wx.EVT_MENU, self.OnExitButton, miFileExit)
+        
+        self.menuBar.Append(menuFile, "&File")
+
+
+        # Options
+        menuOptions = wx.Menu()
+
+        self.miOptionsLibrary = menuOptions.Append(-1, "&File Library\tF2" , "Show File Library")
+        self.Bind(wx.EVT_MENU, self.OnShowLibrary, self.miOptionsLibrary)
+        
+        self.miOptionsAspectRatio = menuOptions.Append(ASPECT_RATIO, "Preserve Aspect Ratio" , "Maintain Aspect Ratio?", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miOptionsAspectRatio)
+        self.miOptionsAspectRatio.Check(prefs.visual.GetKeepAspectRatio())
+
+        self.miOptionsSAGEColor = menuOptions.Append(SAGE_COLOR, "Change SAGE Background Color" , "Change SAGE Background Color?")
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miOptionsSAGEColor)
+
+        self.miOptionsShowChat = menuOptions.Append(-1, "Show Chat Window", "", wx.ITEM_CHECK)
+        if self.usersClient.connected:
+            if prefs.visual.IsChatShown() != None:
+                self.miOptionsShowChat.Check(prefs.visual.IsChatShown())
+        self.Bind(wx.EVT_MENU, self.OnChatShow, self.miOptionsShowChat)
+
+        self.miOptionsOutput = menuOptions.Append(-1, "Show Console Output", "", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnShowConsoleOutput, self.miOptionsOutput)
+        self.miOptionsOutput.Check(False)
+
+        self.miOptionsLauncherAdmin = menuOptions.Append(-1, "AppLauncher Admin" , "AppLauncher Admin Tool")
+        self.Bind(wx.EVT_MENU, self.OnLauncherAdmin, self.miOptionsLauncherAdmin)
+
+        self.menuBar.Append(menuOptions, "&Options")
+
+
+        # Performance
+        menuPerformance = wx.Menu()
+
+        self.miPerformancePerformance = menuPerformance.Append(PERF_DATA, "Receive Performance Data", "", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformancePerformance)
+        self.miPerformancePerformance.Check(prefs.visual.GetReceivePerformanceData())
+
+        self.miPerformanceLogging = menuPerformance.Append(LOG_PERF_DATA, "Log Performance Data" , "Permit performance data logging to a file.", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceLogging)
+        self.miPerformanceLogging.Check(True)
+
+        self.miPerformanceRenderBWGraph = menuPerformance.Append(RENDER_BW, "Show Total Rendering Bandwidth" , "Show the graph for Total Rendering Bandwidth.", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceRenderBWGraph)
+        self.miPerformanceRenderBWGraph.Check(False)
+
+        self.miPerformanceDisplayBWGraph = menuPerformance.Append(DISPLAY_BW, "Show Total Display Bandwidth" , "Show the graph for Total Display Bandwidth.", wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miPerformanceDisplayBWGraph)
+        self.miPerformanceDisplayBWGraph.Check(False)
+
+        self.menuBar.Append(menuPerformance, "&Performance")
+        
+
+        # Session
+        ## menuSession = wx.Menu()
+##         self.miSessionRecord = menuSession.Append(RECORD_SESSION, "Record Session" , "", wx.ITEM_CHECK)
+##         self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miSessionRecord)
+##         self.miSessionRead = menuSession.Append(READ_SESSION, "Read Session" , "")
+##         self.Bind(wx.EVT_MENU, self.OnMenuItem, self.miSessionRead)
+##         self.menuBar.Append(menuSession, "&Session")
+
+
+        # Help
+        menuHelp = wx.Menu()
+        self.miAbout = menuHelp.Append(-1, "About SAGE UI\tF1", "")
+        self.Bind(wx.EVT_MENU, self.OnAbout, self.miAbout)
+        self.menuBar.Append(menuHelp, "&Help")
+
+
+        # store all the menu check items that are display dependent
+        self.menuCheckItems = {}
+        self.menuCheckItems[ASPECT_RATIO] = self.miOptionsAspectRatio#.IsChecked()
+        self.menuCheckItems[PERF_DATA] = self.miPerformancePerformance#.IsChecked()
+        self.menuCheckItems[LOG_PERF_DATA] = self.miPerformanceLogging#.IsChecked()
+        self.menuCheckItems[RENDER_BW] = self.miPerformanceRenderBWGraph#.IsChecked()
+        self.menuCheckItems[DISPLAY_BW] = self.miPerformanceDisplayBWGraph#.IsChecked()
+        #self.menuCheckItems[RECORD_SESSION] = self.miSessionRecord#.IsChecked()
+
+
+        # bind keystrokes to the frame
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyEvent)
+
+        return self.menuBar
+
+
+    #----------------------------------------------------------------------
+
+    def UpdateMenuItems(self, newMenuItems):
+        # update the menu with the specific menu items from the current page
+        for k,mi in self.menuCheckItems.iteritems():
+            mi.Check(newMenuItems[k])
+        self.menuBar.Refresh()
+            
+    
+    def GetUsersPanel(self):
+        return self.usersPanel
+
+
+
+##     def Reconnect(self):
+##         dlg = wx.MessageDialog(None, "Connection to SAGE has closed.\nYou will have to reconnect when SAGE becomes available again.", "SAGE Connection Closed", style=wx.OK)
+##         #btn = wx.Button(dlg, 999, "Reconnect")
+##         if dlg.ShowModal() == wx.ID_OK:
+##             self.notebook.CloseCurrentPage(closeUI=False)
+##             sageGate = SageGate()
+##             cd = ConnectionDialog(sageGate, self.usersClient, firstConnection=False)
+##             title = self.usersData.GetMyUsername() + " @ " + cd.hostname
+##             self.notebook.AddPage(DisplayPage(self.notebook, sageGate, self.usersData, self.usersClient, cd.host, title), title, True)
+                         
+##         dlg.Destroy()
+
+    #----------------------------------------------------------------------
+    # EVENT HANDLERS
+    #----------------------------------------------------------------------
+
+
+    def OnActivated(self, evt):
+        """ happens only when the frame is shown because we unbind the event below """
+        self.Disconnect(-1,-1,wx.wxEVT_ACTIVATE)
+        
+        # load the saved state of the display if requested
+        if self.loadState:
+            sageData = self.notebook.GetPage(self.notebook.GetSelection()).sageData
+            t = Timer(4, sageData.loadState, [self.loadState])
+            t.start()
+        
+
+    def OnSize(self, event=None):
+        if "__WXMSW__" in wx.PlatformInfo:   #to bypass windows' deferred resizing crap
+            def doResize():
+                #self.notebook.OnSize(event)
+                if self.usersClient.connected:
+                    self.usersPanel.OnFrameMove()
+            wx.CallAfter(doResize)
+        else:
+            #self.notebook.OnSize(event)
+            if self.usersClient.connected:
+                self.usersPanel.OnFrameMove()
+        event.Skip()  #resize the notebook
+        
+
+    def OnMove(self, event):
+        if self.usersClient.connected:
+            self.usersPanel.OnFrameMove()
+
+
+    def OnKeyEvent(self, event):
+        #self.notebook.OnKeyEvent(event)
+        event.Skip()
+
+        
+    def OnCloseFrame(self, evt):
+        # save the visual preferences (frame size, position, chat panel)
+        prefs.visual.SetAll(self.GetClientSize(), self.GetPosition(), self.usersPanel.IsShown())
+        
+        # close all connections to SAGEs
+        self.notebook.OnClose(evt)
+        
+        #if self.usersClient.connected:
+        self.usersPanel.Disconnect()
+
+        
+        # (AKS 2005-05-06) Delete all temp files of size 0 created when ignoring logging function
+        # Instead of allowing for the possibility that new apps start and their respective log
+        # files are not made causing an error, allow the new app's file to be created but do
+        # not write to it.  Later, delete the 0-size file.
+        try:   #in case the file and directory permissions are not right
+            listFilenames = os.listdir( DATA_DIR )
+
+            # remove files that were never written or minimally written (i.e. <= 1K)
+            for stFilename in listFilenames:
+                stFilename = opj(DATA_DIR, stFilename)
+                stCompleteFilename = os.path.normcase( stFilename )
+                structStats = os.stat( stCompleteFilename )
+
+                if ( structStats.st_size <= 1024 ):
+                    os.remove( stCompleteFilename )
+                    print "Deleting", stCompleteFilename
+                # end if
+            # end loop
+        except:
+            pass
+        
+        self.DestroyChildren()
+        self.Destroy()
+        wx.GetApp().ExitMainLoop()
+
+
+    #----------------------------------------------------------------------
+    # MENU HANDLERS
+    #----------------------------------------------------------------------
+
+
+    ### this catches all the menu events that are display specific
+    def OnMenuItem(self, event):
+        self.notebook.OnMenuEvent(event)
+
+    # Menu -> File -> Exit
+    def OnExitButton(self, evt):
+        self.Close(True)
+
+    # Menu -> Help -> About
+    def OnAbout(self, evt):
+        AboutDialog(self)
+
+    # Menu -> Chat -> Show
+    def OnChatShow(self, evt):
+        if self.miOptionsShowChat.IsChecked():
+            self.usersPanel.Show()
+        else:
+            self.usersPanel.Hide()
+
+    # Menu -> Options -> AppLauncher Admin
+    def OnLauncherAdmin(self, evt):
+        lAdmin.MainFrame(getSAGEServer())
+
+    # Menu -> Options -> Show File Library
+    def OnShowLibrary(self, evt):
+        self.notebook.GetPage(self.notebook.GetSelection()).displayCanvas.ShowLibrary() 
+
+    # Menu -> Options -> Show Console Output
+    def OnShowConsoleOutput(self, evt):
+        if self.miOptionsOutput.IsChecked():
+            wx.GetApp().RestoreStdio()
+        else:
+            try:
+                wx.GetApp().RedirectStdio( LOG_FILE )
+            except IOError:
+                message = "\nCould not redirect output to a log file. Probably because of file permissions."
+                message = message+"\nInstead, output will be printed in the console"
+                dlg = wx.MessageDialog(self, message, "Error redirecting output", style=wx.OK)
+                dlg.ShowModal()
+                dlg.Destroy()
+                wx.GetApp().RestoreStdio()
+                self.miOptionsOutput.Check(True)
+
+    # Menu -> File -> New
+    def OnNewConnection(self, event):
+        sageGate = SageGate()
+
+        # initialize the dialog and show it. If it returns False, the user pressed quit
+        # otherwise the connection to SAGE was successful and the username was accepted
+        # so create the tab, show it and continue with execution
+        cd = ConnectionDialog(sageGate, self.usersClient, firstConnection=False)
+        if cd.ShowDialog():        
+            title = self.usersData.GetMyUsername() + " @ " + cd.GetMachine().GetName()
+            self.notebook.AddPage(DisplayPage(self.notebook, sageGate, self.usersClient, cd.GetMachine().GetId(), title), cd.GetMachine().GetName(), True)
+                         
+        return True
+
+    # Menu -> File -> Close
+    def OnCloseConnection(self, event):
+        self.notebook.CloseCurrentPage()
+
+
+############################################################################
+#
+#  CLASS: AboutDialog
+#  
+#  DESCRIPTION: It just displays the about box.
+#
+#  DATE:        June 2005
+#
+############################################################################
+
+class AboutDialog(wx.Dialog):
+    def __init__(self, parent):
+        titleText = "SAGE Graphical User Interface"
+        contentText = "version " + str(VERSION) + "\n\n\n" + "For more information go to:"
+        linkUrl = "www.evl.uic.edu/cavern/sage"
+        link2Text = "Direct questions or comments to:"
+        link2Url = "www.evl.uic.edu/cavern/forum"
+                
+        wx.Dialog.__init__(self, parent, -1, "About SAGE UI", style=wx.CLOSE_BOX)
+        okBtn = wx.Button(self, wx.ID_OK, "OK")
+        title = wx.StaticText(self, -1, titleText, style=wx.ALIGN_CENTER)
+        title.SetFont(BoldFont(title))
+        
+        if use_hyperlink: 
+            link = hyperlink.HyperLinkCtrl(self, wx.ID_ANY, linkUrl, URL="http://"+linkUrl)
+            link.AutoBrowse(True)
+            link2 = hyperlink.HyperLinkCtrl(self, wx.ID_ANY, link2Url, URL="http://"+link2Url)
+            link2.AutoBrowse(True)
+        else:
+            link = wx.StaticText(self, -1, linkUrl, style=wx.ALIGN_CENTER)
+            link2 = wx.StaticText(self, -1, link2Url, style=wx.ALIGN_CENTER)
+
+        text = wx.StaticText(self, -1, contentText, style=wx.ALIGN_CENTER)
+        text2 = wx.StaticText(self, -1, link2Text, style=wx.ALIGN_CENTER)
+        
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.AddSpacer((20, 20))
+        sizer.Add(title, 0, wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border=15)
+        sizer.Add(text, 0, wx.ALIGN_CENTER)
+        sizer.Add(link, 0, wx.ALIGN_CENTER)
+        sizer.AddSpacer((15,15))
+        sizer.Add(text2, 0, wx.ALIGN_CENTER)
+        sizer.Add(link2, 0, wx.ALIGN_CENTER)
+        sizer.AddSpacer((15,15))
+        sizer.Add(okBtn, 0, wx.ALIGN_CENTER)
+        sizer.AddSpacer((5,5))
+        self.SetSizer(sizer)
+        self.Fit()
+        self.ShowModal()
+        self.Destroy()
+                
+
+
+
+
+############################################################################
+#
+#  CLASS: SAGEui
+#  
+#  DESCRIPTION: This is a starting point for wx. It extends wx.App and
+#               creates the SAGEuiFrame to place the canvases in. It also displays
+#               the initial dialogs for the User profile and SAGE connection.
+#
+#  DATE:        October 2004
+#
+############################################################################
+
+class SAGEui(wx.App):
+    def __init__(self, usersServerIP, usersServerPort, verbose, autologinMachine, loadState):
+        self.usersServerIP = usersServerIP
+        self.usersServerPort = usersServerPort
+        self.autologinMachine = autologinMachine
+        self.loadState = loadState
+        
+        if verbose:
+            wx.App.__init__(self, redirect=False)
+        else:
+            try:
+                wx.App.__init__(self, redirect=True, filename=LOG_FILE)
+            except IOError:
+                print "\nError: Could not redirect output to a log file. Possibly because of file permissions."
+                print "Instead, output will be printed in the console"
+                wx.App.__init__(self, redirect=False)
+
+    def Skip( self, evt ):
+        pass
+
+    def OnInit(self):
+        wx.Log_SetActiveTarget(wx.LogStderr())
+        self.SetAssertMode(assertMode)
+        socket.setdefaulttimeout(2)
+    
+        # initialize network communication with:
+        # sageGate...   the connection to SAGE
+        # usersClient...the connection to UsersServer
+        # usersData...  the datastructure used in conjunction with usersClient
+        usersData = UsersDatastructure()
+        setUsersData(usersData) #store it in a global scope
+        sageGate = SageGate()
+        usersClient = UsersClient()
+
+        # initialize the dialog and show it. If it returns False, the user pressed quit
+        # otherwise the connection to SAGE was successful and the username was accepted
+        # so show the frame and continue with execution
+        cd = ConnectionDialog(sageGate, usersClient, self.usersServerIP, usersServerPort = self.usersServerPort, autologinMachine=self.autologinMachine)
+        if cd.ShowDialog():        
+            title = usersData.GetMyUsername() + " @ " + cd.GetMachine().GetName()
+            self.frame = SAGEuiFrame(sageGate, usersClient, cd.GetMachine().GetId(), self.loadState, title)       
+            self.SetTopWindow(self.frame)
+        else:
+            usersClient.Disconnect()
+            sys.exit(0)
+                         
+        return True
+
+
+
+
+############################################################################
+#
+# Main entry point for the application
+#
+############################################################################
+
+### sets up the parser for the command line options
+def get_commandline_options():
+    parser = optparse.OptionParser()
+
+    h = "if set, prints output to console, otherwise to ~/.sageConfig/sageui/output_log.txt"
+    parser.add_option("-v", "--verbose", action="store_true", help=h, dest="verbose", default=False)
+
+    h = "which sage server / connection manager to use (default is sage.sl.startap.net)"
+    parser.add_option("-s", "--server", dest="server", help=h, default="sage.sl.startap.net")
+
+    h = "change the port number of the sage server (default is 15558)"
+    parser.add_option("-p", "--port", help=h, type="int", dest="port", default=15558)
+
+    h = "override which application launcher to use (by default it looks for one on the same machine as sage master. Specify as machine:port)"
+    parser.add_option("-l", "--launcher", dest="launcher", help=h, default="")
+
+    h = "try autologin to this sage name (what fsManager reports to connection manager from fsManager.conf )"
+    parser.add_option("-a", "--autologin", dest="autologin", help=h, default=None)
+
+    h = "upon startup load this saved state (write saved state name from saved-states directory)"
+    parser.add_option("-o", "--load_state", dest="load_state", help=h, default=None)
+
+    h = "perform autosave?"
+    parser.add_option("-t", "--autosave", action="store_true", help=h, dest="autosave", default=False)
+
+    return parser.parse_args()
+
+
+
+def main(argv):
+    os.chdir(sys.path[0])  # change to the folder where script is running
+    global autosave
+    verbose = False
+    usersServerIP = "74.114.99.36"
+    usersServerPort = 15558
+    
+    # parse the command line params
+    (options, args) = get_commandline_options()
+    verbose = options.verbose
+    usersServerPort = options.port
+    usersServerIP = options.server
+    appLauncher = options.launcher
+    autologinMachine = options.autologin
+    loadState = options.load_state
+    autosave = options.autosave
+    
+    # set the overridden app launcher
+    if appLauncher != "":
+        setAppLauncher(appLauncher)
+        
+    # set the global variable for the SAGE SERVER
+    setSAGEServer(usersServerIP)
+    
+    # print some information about the system currently running
+    print "\nCurrently running:\n--------------------------"
+    print "SAGE UI version: ", VERSION
+    print "Python version:  ", string.split(sys.version, "(", 1)[0]
+    print "wxPython version: "+str(wx.VERSION[0])+"."+str(wx.VERSION[1])+"."+str(wx.VERSION[2])+"."+str(wx.VERSION[3])+"\n"  
+
+    # read all the preferences
+    import preferences as prefs
+    prefs.readAllPreferences()
+
+    app = SAGEui(usersServerIP, usersServerPort, verbose, autologinMachine, loadState)
+    app.MainLoop()
+    
+    
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
+
+
+    
+    
+
+
Index: trunk/src/testing/ui/sageGate.py
===================================================================
--- trunk/src/testing/ui/sageGate.py	(revision 4)
+++ trunk/src/testing/ui/sageGate.py	(revision 4)
@@ -0,0 +1,182 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import sageGateBase as sgb
+import wx, socket, xmlrpclib, sys
+from globals import *
+import traceback as tb
+
+
+
+####################################################################
+#
+# DESCRIPTION: This class provides the main communication interface
+#              with SAGE. It subclasses the SageGateBase in order
+#              to customize some parameters.
+#
+# DATE: Aug, 2007
+#
+####################################################################
+
+class SageGate(sgb.SageGateBase):
+    """ this class provides the main communication interface with SAGE
+        subclasses the SageGateBase in order to customize some parameters
+    """
+    
+    def __init__(self):
+        sgb.SageGateBase.__init__(self,
+                                  sageServerHost=getSAGEServer(),
+                                  useAppLauncher=True,
+                                  forceAppLauncher=getAppLauncher(),
+                                  onDisconnect=self.initiateClosedConnectionDialog,
+                                  verbose=True)
+        
+
+    def showConnectionClosedDialog(self):
+        """ informs the user when the connection breaks """
+        m = getUsersData().FindMachineByIP(self.sageHost)
+        if m: machineName = m.GetName()
+        else: machineName = self.sageHost
+
+        msg = "Connection to  <<"+machineName+">>  closed.\nYou will have to reconnect when SAGE becomes available again."
+        dlg = wx.MessageDialog(None, msg, "SAGE Connection Closed", style=wx.OK)
+	dlg.ShowModal()
+	dlg.Destroy()
+
+
+    def initiateClosedConnectionDialog(self):
+        wx.CallAfter(self.showConnectionClosedDialog)
+
+
+    def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        # figure out the correct system ports for data streaming (if not overridden by the user)
+        if not sageIP:
+            machine = getUsersData().FindMachineByIP(self.sageHost)
+            if machine:
+                sageIP = machine.GetSystemIP()     # the machine told the server what to use for streaming
+                if not sagePort: sagePort = machine.GetSystemPort()
+            else:
+                sageIP = self.sageGate.sageHost    # use the default ip and port
+                if not sagePort: sagePort = self.sageGate.sagePort+1
+
+        # try running the app (return -1 if failed for whatever reason)
+        try:
+            res = self.appLauncher.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            return -1
+        else:
+            return res
+
+
+    def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+	if self.connected == False: return 0
+	if not appName: return 0
+
+        # figure out the correct system ports for data streaming (if not overridden by the user)
+        if not sageIP:
+            machine = getUsersData().FindMachineByIP(self.sageHost)
+            if machine:
+                sageIP = machine.GetSystemIP()     # the machine told the server what to use for streaming
+                if not sagePort: sagePort = machine.GetSystemPort()
+            else:
+                sageIP = self.sageGate.sageHost    # use the default ip and port
+                if not sagePort: sagePort = self.sageGate.sagePort+1
+
+        # try running the app (return -1 if failed for whatever reason)
+	#if launcherId in self.launchers:
+            #server = self.launchers[launcherId].getServerHandle()
+        try:
+            server = xmlrpclib.ServerProxy("http://" + launcherId)
+            res = server.startDefaultApp(appName, sageIP, sagePort, useBridge, configName, pos, size, optionalArgs)
+        except:
+            print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+            print "\nCould not start remote app through appLauncher running on:", launcherId
+            return -1
+        else:
+            return res
+        
+	
+
+##     def executeApp(self, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+##         """ overridden in order to figure out the correct port and host for the target machine
+##             The reason is that SageGateBase doesn't have access to all the machine info (ie usersData)
+##         """
+
+##         # figure out the correct system ports for data streaming (if not overridden by the user)
+##         sageIP, sagePort = self.__getMachineInfo(sageIP, sagePort)
+        
+##         return sgb.SageGateBase.executeApp(self, appName, configName, pos, size,
+##                                            optionalArgs, useBridge, sageIP, sagePort)
+
+
+##     def executeRemoteApp(self, launcherId, appName, configName="default", pos=False, size=False, optionalArgs="", useBridge=False, sageIP=None, sagePort=None):
+##         """ overridden in order to figure out the correct port and host for the target machine
+##             The reason is that SageGateBase doesn't have access to all the machine info (ie usersData)
+##         """
+
+##         # figure out the correct system ports for data streaming (if not overridden by the user)
+##         sageIP, sagePort = self.__getMachineInfo(sageIP, sagePort)
+        
+##         return sgb.SageGateBase.executeRemoteApp(self, launcherId, appName, configName, pos, size,
+##                                                  optionalArgs, useBridge, sageIP, sagePort)
+        
+
+    def onMessage(self, code, data):
+        """ handles the incoming messages """
+        if code in self.hashCallbackFunction:
+            wx.CallAfter(self.hashCallbackFunction[ code ], data)
+
+            
+##     def __getMachineInfo(self, sageIP, sagePort):
+##         if not sageIP:
+##             machine = getUsersData().FindMachineByIP(self.sageHost)
+##             if machine:
+##                 sageIP = machine.GetSystemIP()     # the machine told the server what to use for streaming
+##                 if not sagePort: sagePort = machine.GetSystemPort()
+##             else:
+##                 sageIP = self.sageHost    # use the default ip and port
+##                 if not sagePort: sagePort = self.sagePort+1
+##         return (sageIP, sagePort)
+
+
+    
Index: trunk/src/testing/ui/sageApp.py
===================================================================
--- trunk/src/testing/ui/sageApp.py	(revision 4)
+++ trunk/src/testing/ui/sageApp.py	(revision 4)
@@ -0,0 +1,240 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+import sys, string
+
+### Class to hold sage application info
+### An instance of this class should exist for every app Id on SAGE
+class SageApp :
+
+        
+    def __init__(self, name, windowId, left, right, bottom, top, sailID, zValue, orientation, displayId, appId, launcherId, title=""):
+        self.left = left
+        self.right = right
+        self.top = top
+        self.bottom = bottom
+        self.sailID = sailID
+        self.appName = name
+        self.windowId = windowId
+        self.appId = appId
+        self.launcherId = launcherId
+        self.zValue = zValue
+        self.configNum = 0
+        self.title = title
+        self.capture = -1  # which pointer captured it
+        self.orientation = 0  # in degrees
+        self.displayId = 0
+        
+
+    def setAll(self, name, windowId, left, right, bottom, top, sailID, zValue, orientation, displayId, appId, launcherId):
+        self.appName = name
+        self.windowId = windowId
+        self.appId = appId
+        self.launcherId = launcherId
+        self.left = left
+        self.right = right
+        self.bottom = bottom
+        self.top = top
+        self.sailID = sailID
+        self.zValue = zValue
+        self.orientation = orientation
+        self.displayId = displayId
+        #self.title = title
+        
+
+    def getLeft(self):
+        return self.left
+
+    def getRight(self):
+        return self.right
+
+    def getTop(self):
+        return self.top
+
+    def getBottom(self):
+        return self.bottom
+
+    def getId(self):
+        return self.windowId
+
+    def getAppId(self):
+        return self.appId
+
+    def getLauncherId(self):
+        return self.launcherId
+
+    def getConfigNum(self):
+        return self.configNum
+
+    def getTitle(self):
+        return self.title
+
+    def setTitle(self, newTitle):
+        self.title = newTitle
+
+    def getWidth(self):
+        return self.right - self.left
+
+    def getHeight(self):
+        return self.top - self.bottom
+
+    def getDisplayId(self):
+        return self.displayId
+
+    def getOrientation(self):
+        return self.orientation
+    
+    def setName(self, appName):
+        self.appName = appName
+
+    def getName(self):
+        return self.appName
+    
+    #### Get the application window values
+    #### @return Returns a list Format: [<left>, <right>, <top>, <bottom>]
+    def getBounds(self) :
+        return [self.left, self.right, self.top, self.bottom]
+
+    #### Get the app's sailID
+    def getSailID(self):
+        return self.sailID
+
+    def setZvalue(self, value):
+        self.zValue = value
+
+    def getZvalue(self):
+        return self.zValue
+
+    def hasCapture(self):
+        if self.capture == -1:
+            return False
+        else:
+            return True
+
+    def captureMouse(self, pointerId):
+        self.capture = pointerId
+        
+    def releaseMouse(self):
+        self.capture = -1
+        
+
+    # checks whether (x,y) hit something on the shape
+    # calculations are done in the sage coordinate system (bottom left = 0,0)
+    # 0 = everything else... inside the app
+    # -2 = hit but not on the corners (BOTTOM)
+    # -1 = hit but not on the corners (TOP)
+    # 1 = bottom left corner
+    # 2 = top left corner
+    # 3 = top right
+    # 4 = bottom right
+    def hitTest(self, x, y, cornerSize=250):
+
+        # utility function
+        def __inRegion(r):
+            if x >= r[0] and x <= r[1] and y<=r[2] and y>=r[3]:
+                return True
+            return False
+            
+        (l,r,t,b,cs) = (self.left, self.right, self.top, self.bottom, cornerSize)
+
+        # define the regions we need to test
+        testRegions = {}  # keyed by -2,-1,1,2,3,4
+        testRegions[-2] = (l+cs, r-cs, b+cs, b)
+        testRegions[-1] = (l+cs, r-cs, t, t-cs)
+        testRegions[1] = (l, l+cs, b+cs, b)
+        testRegions[2] = (l, l+cs, t, t-cs)
+        testRegions[3] = (r-cs, r, t, t-cs)
+        testRegions[4] = (r-cs, r, b+cs, b)
+        
+        # now loop through the regions and test whether x,y is in it
+        result = 0
+        for rid, r in testRegions.iteritems():
+            if __inRegion(r):
+                return rid
+                                
+        return result
+
+
+
+
+
+
+
+### a class to hold the information about all the available apps that SAGE supports
+class SageAppInitial:
+
+    def __init__ (self, name, configNames):
+        self._name = name
+        self._configNames = configNames
+        
+    def GetName (self):
+        return self._name
+
+    def SetName (self, name):
+        self._name = name
+
+    def GetConfigNames(self):
+        return self._configNames
+    
+    ## # execution configurations
+##     def AddConfig (self, name, stConfig):
+##         self._execConfigs[ len(self._execConfigs)+1 ] = (name, string.strip(stConfig))
+
+##     def GetNumConfigs(self):
+##         return self._numConfigs
+    
+##     def GetConfigHash (self):
+##         return self._execConfigs
+
+##     def GetConfig (self, configNum):
+##         if self._execConfigs.has_key( configNum ):
+##             return self._execConfigs[ configNum ]
+##         else:
+##             print "Error: No configuration number ", configNum
+##             return "No Configuration"
+
+##     # instances already started
+##     def AddInstanceId (self, instanceId):
+##         self._appInstanceIds.append( instanceId )
+
+##     def GetInstanceIds (self):
+##         return self._appInstanceIds
+
+    
Index: trunk/src/testing/ui/sageDisplayInfo.py
===================================================================
--- trunk/src/testing/ui/sageDisplayInfo.py	(revision 4)
+++ trunk/src/testing/ui/sageDisplayInfo.py	(revision 4)
@@ -0,0 +1,120 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# placement
+MIDDLE = -1
+LEFT = 0
+RIGHT = 1
+BOTTOM = 2
+TOP = 3
+
+
+class SageDisplay:
+    def __init__(self, tn,x,y,w,h,tw,th,dId):
+        self.tileNumber = tn
+        self.dimX = x
+        self.dimY = y
+        self.cols = x   # just an alias
+        self.rows = y
+        self.desktopWidth = w
+        self.desktopHeight = h
+        self.tileWidth = tw
+        self.tileHeight = th
+        self.sageW = w
+        self.sageH = h
+        self.displayId = dId
+        self.placement = MIDDLE  # where this display is with respect to display 0 (-1 means this is display 0 = middle)
+        #self.orientation = 0  # where down is in degrees. 0 is down, 90 is right, 180 is up, 270 is left
+        
+    def getValues(self):
+        return [self.tileNumber, self.dimX, self.dimY,
+                self.desktopWidth, self.desktopHeight,
+                self.tileWidth, self.tileHeight, self.displayId]
+
+    def getId(self):
+        return self.displayId
+    
+
+
+class SageDisplayInfo:
+
+    def __init__(self):
+        self.displays = {}
+
+
+    def getAllDisplays(self):
+        """ returns a list of SageDisplay objects """
+        return self.displays.values()
+
+
+    def getNumDisplays(self):
+        return len(self.displays)
+    
+
+    def addDisplay(self, tileNum, dimX, dimY, deskWidth, deskHeight, tileWidth, tileHeight, displayId=0):
+        d = SageDisplay(tileNum, dimX, dimY, deskWidth, deskHeight, tileWidth, tileHeight, displayId)
+        self.displays[displayId] = d
+
+
+    def getTotalWidth(self):
+        totalW = 0
+        for disp in self.displays.values():
+            pos = disp.placement
+            if pos == LEFT or pos == MIDDLE or pos == RIGHT:
+                totalW += disp.sageW
+        return totalW
+
+
+    def getTotalHeight(self):
+        totalH = 0
+        for disp in self.displays.values():
+            pos = disp.placement
+            if pos == TOP or pos == MIDDLE or pos == BOTTOM:
+                totalH += disp.sageH
+        return totalH
+    
+
+    def getDisplay(self, displayId):
+        return self.displays[displayId]
+
+            
+    def getDisplayInfo(self, displayId=0):
+        return self.displays[displayId].getValues()
+                
Index: trunk/src/testing/ui/RECENT_CHANGES
===================================================================
--- trunk/src/testing/ui/RECENT_CHANGES	(revision 4)
+++ trunk/src/testing/ui/RECENT_CHANGES	(revision 4)
@@ -0,0 +1,174 @@
+
+
+HOW TO FIND OUT WHICH VERSION OF SAGE UI YOU HAVE
+----------------------------------------------------
+Versions prior to 2.5 weren't labeled so there is no way to find out version nubmers for those.
+However, from v2.5 on, SAGE UI has an About Box that shows the current version of the UI.
+
+
+CHANGES in v3.0a    (Feb 11, 2007)
+-----------------------------------------
+- this is the development version for SAGE3.0 (it's alpha since sage3 hasn't
+  been officially released at this point)
+- there are mostly minor changes... the biggest one being the change in
+  dependencies (numpy is now preferred over numarray since numarray is 
+  being phased out)
+- autologin to a machine feature (with -a command line parameter)
+- rotation of sage windows
+- support for multiple physical displays in one sage session - experimental!
+- some bug fixes (there are still some significant issues with MacOS)
+
+
+CHANGES in v2.84    (May 15, 2007)
+-----------------------------------------
+- direct interaction with the sage display using joysticks
+- the requirement for the minimum wxPython version has been dropped
+  to 2.6.2 (the one that ships with Suse 10.1). This solves the problem 
+  with non-functioning appLauncher admin tool on the earlier wxPython versions
+- there is a timeout on the mouseCapture call when moving applications which 
+  prevents capturing the system mouse on rare occasions
+
+
+CHANGES in v2.83    (March 5, 2007)
+-----------------------------------------
+- the sage server now reports system and public ip addresses and ports for each fsManager
+  therefore changes have been made to the server and the UI. System IP is the one reported
+  to the applications about where they should look for fsManager.
+- there is a "Remote Applications" button that enables you to start applications from remote
+  machines and tell them to stream their data to the current fsManager you are connected to
+  (this requires the appLauncher to report to the sage server)
+- added the appLauncher admin tool from which you can control application launchers (needs wxPython 2.6.3)
+- the vnc dialog has been simplified
+- some older and currently non-working features have been removed (session playback, saving state...)
+- bug fixes (z ordering, retrieving empty machine info...)
+
+
+CHANGES in v2.80    (November 20, 2006)
+-----------------------------------------
+- this is an official version of SAGE UI for SAGE2 and therefore some messages have changed
+- SAGE now does z-ordering so that has been taken out of SAGE UI
+- appLauncher is used for application launching instead of fsManager so an xmlrpc connection
+  is made to the appLauncher at startup to get the list of applications
+- left-click on app button launches the app normally (w/o sageBridge)
+- right-click launches the app through sageBridge so that the app can be shared
+- sage ui will run even without the appLauncher running
+- to stream already running apps either drag-and-drop the app onto a
+  new tab OR right-click on the app window and choose "Stream To:"
+  and select a machine from a submenu
+- fileLibrary can also run the applications through sageBridge by
+  checking a checkBox
+- performance data is ON by default but it will remember whether it was
+  on or off next time you start the UI
+- fixed some issues with VNC password saving and other preferences
+- VNC password is no longer encrypted because there were some issues with that
+- performance data format has changed so now there are only bandwidth and framerate available
+- when dropping the file onto the UI from the desktop, it will be automatically shown and
+  it wont ask you whether you want to upload it permanently or not
+
+- SAGE Server has changed in order to keep track of machines by their machine ID as opposed
+  to just IP addresses... the new default ports are 15557 for SAGE and 15558 for UI clients
+
+
+
+CHANGES in v2.72    (April 18, 2006)
+-----------------------------------------
+- file library interface changed a bit
+- can connect to and use multiple file libraries
+- shows metadata for the files in the library
+- retrieves previews of the files (images only) - previews are cached so their retrieval is fast
+- local and remote files are compared by size as well as by name
+- some other file library changes and fixes
+- file library can be stored remotely
+- file library has another component, file grabber, that fetches data 
+  from a remote machine (it caches the data locally)
+- imageviewer and mplayer buttons have been disabled in the ui
+- sage ui now has global preferences that are stored in binary pickle files as opposed to text files
+- all the preferences files are kept in the prefs/ subdirectory of sage ui
+- current preferences: usernames used, machines connected to, 
+  vnc profiles, favorite files from the file lib, visual prefs (chat panel shown/hidden, 
+  frame size and pos), file libraries connected to)
+
+
+
+CHANGES in v2.7:    (February 13, 2006)
+-----------------------------------------
+- Drag-and-drop of the multimedia files onto the UI itself (the file will show up on the
+  tiled display exactly where you dropped it in the UI). Currently images, videos and pdf
+  files are supported.
+- FileLibrary has been implemented - keeps track of, stores and organizes all the files that
+  have been shown on the display. It also lists all the files currently on the server that are available
+  for showing. It allows users to organize the files by directories and even save favorites.
+  In order of this to work a File Server has to be running that is included with SAGE.
+- The application performance panel has been redone (double buffered)
+- A timeout when users server / connection manager is not available (5 seconds)
+- Some speedup during resizing of the UI
+- Fixed a bug that was showing total render data for both graphs: total render and display.
+- support for easier vnc sessions is included in the ui (showing your desktop on a sage display)
+
+
+CHANGES in v2.61:   (September 19, 2005)
+------------------------------------------
+- a bug in usersServer was fixed (if SAGE connected but did not send 
+  a register message, it would stay connected forever)
+- a simple tool "admin.py" was made to check and modify the 
+  internal state of the usersServer. This should be used
+  only when things go wrong so that the individual connections with SAGE 
+  and/or users can be closed without restarting the server.
+- in the SAGE UI, console output is now redirected to a log file "output_log.txt" by default. 
+  In order to view the output in the
+  console, check "Menu -> Options -> Show Console Ouput"
+- since ListCtrl tooltips aren't working correctly on Windows and Mac, 
+  there is now an "Info" button in the connection dialog
+  that, if pressed, shows a dialog with information about the selected machine
+- Info, Connect and Delete buttons are greyed out if no selection is made in the connection dialog
+- last used username shows up first in the username combo box in the connection dialog
+- data displayed in the performance panel has been reorganized and rearranged a bit to improve clarity
+- there is little help question mark button in the connection dialog 
+  that brings up the about box with contact information
+
+
+
+CHANGES in v2.6:   (September 9, 2005)
+------------------------------------------
+- fixed a bug where sometimes machines were staying registered even when all 
+  the users have left the room and the machine died
+- fixed a bug that occurs when there is no hyperlink module in wxPython
+- fixed a bug with tool tips in the connection dialog so now they show the correct IP 
+  addresses even when there are multiple machines in the list with the same name but different IPs
+- fixed a bug where menu items weren't getting updated properly when a new connection was 
+  opened (when more than one connection was opened at once)
+- fixed a bug that caused the UI to crash when the user who ran the UI didn't have write permissions
+- all the usernames used to log in are stored locally in a file 
+  and can be chosen upon startup with the combo box
+- when starting SAGE UI, you can now specify the location of the 
+  connection manager (port number and IP address)
+- shapes now have icons in the top right corner for maximizing, minimizing and closing
+- minimize feature was also implemented where apps keep stacking 
+  themselves in the bottom left corner of the display
+- ability to shutdown SAGE from within the UI (File -> Shutdown SAGE)
+- saving and loading sessions is now handled through system dialogs
+- clicking the instance buttons now brings that app to the front
+
+
+
+CHANGES in v2.5:  (July 20, 2005)
+---------------------------------------------
+- the frame is now resizable based on the size of the display it is run on (and borders)
+- the displayCanvas tells the current user @ machine (ie Username @ yorda)
+- if the connection was unsuccessful, SAGE UI won't quit but instead 
+  will show the connection dialog again
+- fixed the ip addresses to that 1.2.3.4 is accepted as well as ico.evl.uic.edu
+- added ability to change SAGE background color
+- chat capability added with a room for every fsManager running... 
+  and for "All"...detachable/resizable panel
+- username login at the beginning
+- the beginning dialog changed
+- MS Windows draw problems fixed
+- MS Windows dialog problems fixed
+- optimized drawing a bit
+- fixed a CPU hogging bug on MS Windows
+- different app configurations now have short descriptive names (assigned in sage.conf)
+- connection to multiple SAGE environments at once is now possible (with the same username)
+- "About" dialog
+- minimum version requirements changed (wxPython --> min 2.6.1)
+- some minor bugs were fixed
Index: trunk/src/testing/ui/SAGESession.py
===================================================================
--- trunk/src/testing/ui/SAGESession.py	(revision 4)
+++ trunk/src/testing/ui/SAGESession.py	(revision 4)
@@ -0,0 +1,401 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+import os.path
+import os 
+import time
+from math import ceil
+import string
+import wx
+from Mywx import MyBitmapButton
+from threading import Timer
+from globals import *
+
+# some global vars
+hashRecordingWords = {}  #RJ 2005-04-07
+hashRecordingWords[1001] = "exec"
+hashRecordingWords[1002] = "kill"
+hashRecordingWords[1003] = "move"
+hashRecordingWords[1004] = "resize"
+hashRecordingWords[1007] = "bg"
+hashRecordingWords[1008] = "depth"
+hashRecordingWords[1100] = "shutdown"
+
+
+
+############################################################################
+#
+#  CLASS: SessionRecorder
+#
+#  DESCRIPTION: A class for recording user actions to a file in a directory.
+#               To use just create an instance of this class and call
+#               RecordAction(code, data) to write a line to a file. "Code" is
+#               the message code sent to SAGE and it gets mapped to a text string
+#               according to a hash defined here. "Data" is whatever you want to
+#               record in a file and it's code dependent. The last (optional)
+#               parameter to RecordAction is a boolean signifying if you want
+#               to insert a pause after an action. By default pauses are inserted
+#               in the file with the value of the elapsed time since the last
+#               recorded message. When done recording, just call Close() and
+#               destroy the object.
+#
+#  DATE:        April, 2005
+#
+############################################################################
+
+class SessionRecorder:
+
+    def __init__(self, filename):
+        #recDir = ConvertPath("./sessions/")  # a dir to write session files to
+        print "Session recording started. Session will be saved in ", filename
+        self.file = open(filename, "w")
+        
+        self.prevTime = 0
+        
+
+
+    def RecordAction(self, code, data, insertPause = True):
+        # only record if the action is supported
+        if hashRecordingWords.has_key( int(code) ):
+            #record a pause, a session always starts with a 2 second pause!
+            if self.prevTime == 0:
+                    pauseTime = 2
+            else:
+                    pauseTime = int( ceil( time.time() - self.prevTime ) )
+            self.prevTime = time.time()
+
+            # finally, do the writing
+            if insertPause:
+                self.file.write("pause " + str(pauseTime) + "\n")
+            self.file.write( hashRecordingWords[int(code)] +" "+ data+"\n" )
+
+
+    def Close(self):
+        print "Session recording stopped"
+        self.file.close()
+        
+
+        
+
+
+############################################################################
+#
+#  CLASS: SessionReader
+#
+#  DESCRIPTION: A class for reading user actions from a specified file.
+#               To use, create an instance of this class and pass in a
+#               filename to read from. Once created, keep calling ReadAction()
+#               in order to read new lines from a file. It returns data in this
+#               format: (code, data). It is your job to use this data then.
+#               This class also has options to pause, stop, speed up and slow
+#               down the playback of the session file. It does all that by
+#               playing with the length of the pause (speed), repeatedly
+#               returning pause (pausing) or returning a fake EOF (stopping
+#               prematurely).
+#
+#
+#  DATE:        April, 2005
+#
+############################################################################
+
+class SessionReader:
+
+    def __init__(self, sessionFile):           
+        if os.path.isfile(sessionFile):
+            self.file = open(sessionFile, "r")
+        else:
+            print "ERROR: Sessions file \"", sessionFile, "\" doesn't exist."
+
+        # control variables
+        self.speed = 1.0
+        self.stop = False
+        self.paused = False
+
+
+    def SetPause(self, doPause):
+        self.paused = doPause
+
+        
+
+    # reads the file one line at a time
+    # it returns a tuple in this format: (code, data)
+    # code is: -1 (paused), 0 (EOF) or **** (message code)
+    # data depends on the message
+    def ReadAction(self):
+
+        # this is how we stop session playback
+        if self.stop:
+            return (0, "EOF")
+
+        # this is how we pause playback (pretend that we encountered a
+        # pause in the file. Instead we are pausing the playback and
+        # not reading any new lines from the file
+        if self.paused:
+            return (-1, "0.5") 
+        
+        if not hasattr(self, "file"):
+            return
+
+        line = self.file.readline()
+        line = string.strip(line)  # remove the newline char
+
+        # EOF case
+        if line == "":
+            self.file.close()
+            return (0, "EOF")
+        
+        # split the line into action and data
+        action, data = string.split(line, " ", 1)
+
+        # send a pause separately
+        if action == "pause":
+            data = float(data) * self.speed
+            return (-1, str(data))
+
+        # this is the actual message to be sent to SAGE
+        code = -2 # any non-existent code
+        for k, v in hashRecordingWords.iteritems():
+            if v == action:
+                code = int(k)   #extract the code            
+        return (code, data)
+
+
+
+    def GoSlower(self):
+        self.speed = self.speed * 2
+        if self.speed > 8:
+            self.speed = 8
+
+        if self.speed > 1:
+            return "1/" + str(int(self.speed))
+        elif self.speed == 1:
+            return "1"
+        elif self.speed < 1:
+            return str(int((0.125 / self.speed) * 8))
+
+
+    def GoFaster(self):
+        self.speed = float(self.speed) / 2
+        
+        if self.speed < 0.125:
+            self.speed = 0.125
+
+        if self.speed > 1:
+            return "1/" + str(int(self.speed))
+        elif self.speed == 1:
+            return "1"
+        elif self.speed < 1:
+            return str(int((0.125 / self.speed) * 8))
+        
+
+    def Stop(self):
+        self.stop = True
+        
+    def Close(self):
+        if hasattr(self, "file"):
+           self.file.close() 
+        
+            
+
+
+
+############################################################################
+#
+#  CLASS: PlaybackDialog
+#
+#  DESCRIPTION: This class describes the dialog box that controls the session
+#               playback. It's a modal dialog so the UI can't be interacted
+#               with during the playback. However, you can speed up or slow
+#               down the playback, pause it or quit it prematurely.
+#
+#  NOTE:        This dialog is not neccessary for the operation of playback
+#               but it gives user more control over it.
+#
+#  DATE:        April, 2005
+#
+############################################################################
+
+class PlaybackDialog(wx.Dialog):
+
+    def __init__(self, parent, sessionReader):
+        wx.Dialog.__init__(self, parent, -1, "Session Playback")#, style = wx.STATIC_BORDER)
+        self.sessionReader = sessionReader
+        self.SetSize((250, 120))
+        self.SetBackgroundColour(wx.Colour(0, 51, 52))  #003334
+        self.SetForegroundColour(wx.Colour(255, 255, 255))
+        self.CenterOnParent(wx.BOTH)
+        self.SetFont(StandardFont())
+        wx.StaticText(self, -1, "Playback in progress...", (50, 20))
+        #self.CaptureMouse()
+        self.pause = False
+
+        # create the controls for the dialog
+        self.pauseBtn = MyBitmapButton( self, (30, 50), (30, 30), "images/pause_up.jpg", "images/pause_down.jpg", "images/pause_over.jpg")
+        self.stopBtn = MyBitmapButton( self, (70, 50), (30, 30), "images/stop_up.jpg", "images/stop_down.jpg", "images/stop_over.jpg")
+        self.slowerBtn = MyBitmapButton( self, (135, 50), (30, 30), "images/slower_up.jpg", "images/slower_down.jpg", "images/slower_over.jpg")
+        self.speedText = wx.StaticText( self, -1, "x 1", (172, 60), style = wx.ALIGN_CENTRE)
+        self.fasterBtn = MyBitmapButton( self, (208, 50), (30, 30), "images/faster_up.jpg", "images/faster_down.jpg", "images/faster_over.jpg")
+
+        # bind the events and event handlers for the buttons
+        self.pauseBtn.Bind( wx.EVT_LEFT_UP, self.OnPause)
+        self.stopBtn.Bind( wx.EVT_LEFT_UP, self.OnClose)
+        self.fasterBtn.Bind( wx.EVT_LEFT_UP, self.OnFaster)
+        self.slowerBtn.Bind( wx.EVT_LEFT_UP, self.OnSlower)
+        self.Bind( wx.EVT_CLOSE, self.OnClose)
+        
+        self.Show()
+
+    
+    def OnPause(self, evt):
+        if self.pause:
+            self.pauseBtn.SetUpBitmap("images/pause_up.jpg")
+            self.pauseBtn.SetDownBitmap("images/pause_down.jpg")
+            self.pauseBtn.SetOverBitmap("images/pause_over.jpg")
+            self.pause = False
+            self.sessionReader.SetPause(False)
+        else:
+            self.pauseBtn.SetUpBitmap("images/play_up.jpg")
+            self.pauseBtn.SetDownBitmap("images/play_down.jpg")
+            self.pauseBtn.SetOverBitmap("images/play_over.jpg")
+            self.pause = True
+            self.sessionReader.SetPause(True)
+
+        MyBitmapButton.OnLeftUp(evt.GetEventObject(), evt)
+        
+
+    # this just hides the window since sageGate will close it when it's done
+    # it also tells the sessionReader to stop the playback
+    def OnClose(self, evt):
+        self.sessionReader.Stop()
+        #self.Destroy()
+        self.Show(False) # SAGEGate is the one that destroys the window so just hide it for now
+        
+
+    # sageGate calls this function when EOF has been reached
+    def Close(self):
+        #self.ReleaseMouse()
+        self.Destroy()
+        
+
+    # this calls SessionReader and sets the speed of playback (basically it
+    # changes the multiplier of the pauses)
+    def OnFaster(self, evt):
+        MyBitmapButton.OnLeftUp(evt.GetEventObject(), evt)
+        newSpeed = self.sessionReader.GoFaster()
+        self.speedText.SetLabel("x " + newSpeed)
+
+
+    # this calls SessionReader and sets the speed of playback (basically it
+    # changes the multiplier of the pauses)
+    def OnSlower(self, evt):
+        MyBitmapButton.OnLeftUp(evt.GetEventObject(), evt)
+        newSpeed = self.sessionReader.GoSlower()
+        self.speedText.SetLabel("x " + newSpeed)
+
+
+
+def ShowLoadSessionDialog():
+    if not os.path.isdir("sessions"):  #make the directory if it doesnt exist
+        try:   #in case the file and directory permissions are not right
+            os.mkdir("sessions")    
+        except:
+            dlg = wx.FileDialog(None, "Session to load:", os.path.abspath("."), "", "*.ses", style=wx.OPEN )
+        else:
+            dlg = wx.FileDialog(None, "Session to load:", os.path.abspath("sessions"), "", "*.ses", style=wx.OPEN )
+    else:
+        dlg = wx.FileDialog(None, "Session to load:", os.path.abspath("sessions"), "", "*.ses", style=wx.OPEN )
+
+
+    if dlg.ShowModal() == wx.ID_OK:
+        if "__WXMSW__" in wx.PlatformInfo:
+            chosenFile = ConvertPath(dlg.GetPath())
+        elif not ConvertPath(dlg.GetPath())[0] == "/":
+            chosenFile = "/"+ConvertPath(dlg.GetPath())
+        else:
+            chosenFile = ConvertPath(dlg.GetPath())
+
+        #make sure that the extension is ".ses"
+        (path, ext) = os.path.splitext(chosenFile)
+        if not ext == ".ses":
+            chosenFile = chosenFile+".ses"
+
+    else:
+        chosenFile = None
+    dlg.Destroy()
+    return chosenFile
+
+
+def ShowSaveSessionDialog():
+    if not os.path.isdir("sessions"):  #make the directory if it doesnt exist
+        try:   #in case the file and directory permissions are not right
+            os.mkdir("sessions")    
+        except:
+            dlg = wx.FileDialog(None, "Save session as:", os.path.abspath("."), "", "*.ses", style=wx.SAVE | wx.OVERWRITE_PROMPT )
+        else:
+            dlg = wx.FileDialog(None, "Save session as:", os.path.abspath("sessions"), "", "*.ses", style=wx.SAVE | wx.OVERWRITE_PROMPT )
+    else:
+        dlg = wx.FileDialog(None, "Save session as:", os.path.abspath("sessions"), "", "*.ses", style=wx.SAVE | wx.OVERWRITE_PROMPT )
+
+    
+    if dlg.ShowModal() == wx.ID_OK:
+        if "__WXMSW__" in wx.PlatformInfo:
+            chosenFile = ConvertPath(dlg.GetPath())
+        elif not ConvertPath(dlg.GetPath())[0] == "/":
+            chosenFile = "/"+ConvertPath(dlg.GetPath())
+        else:
+            chosenFile = ConvertPath(dlg.GetPath())
+
+        #make sure that the extension is ".ses"
+        (path, ext) = os.path.splitext(chosenFile)
+        if not ext == ".ses":
+            chosenFile = chosenFile+".ses"
+
+        # check if we have a permission to write to this folder
+        (head, tail) = os.path.split(chosenFile)
+        if not os.access(head, os.W_OK):
+            ShowWriteFailedDialog(tail)
+            chosenFile = None
+    else:
+        chosenFile = None
+    dlg.Destroy()
+    return chosenFile
+
+
+
+
Index: trunk/src/testing/ui/globals.py
===================================================================
--- trunk/src/testing/ui/globals.py	(revision 4)
+++ trunk/src/testing/ui/globals.py	(revision 4)
@@ -0,0 +1,301 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+# this file holds functions and constants used throughout the application
+
+import os.path, time, wx, sys
+
+# shortcut
+opj = os.path.join
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath, getPath, SAGE_DIR
+
+
+#------------------------------------------------------------------------
+#     COLORS  
+#------------------------------------------------------------------------
+
+# display
+tileColor = wx.Colour(102, 204, 204)
+
+# shapes
+shapeColor          = wx.Colour(153, 255, 255)
+shapeBorderColor    = wx.Colour(204, 153, 102)
+shapeTextColor      = "grey"  
+shapeSelectedTextColor = "white"
+shapeBorderColor    = wx.Colour(51,153,153)
+shapeHighlightColor = wx.Colour(255, 204, 102)
+shapeShadowColor    = wx.Colour(51, 102, 102)
+shapeSelectedBorderColor = wx.Colour(153,255,204)
+shapeSelectedColor  = wx.Colour(51,153,153)
+
+dialogColor = wx.Colour(51, 102, 102)
+
+# app panel
+appPanelColor = wx.Colour(0,51,52)
+
+# info panel
+infoPanelColor = wx.Colour(102,204,153)
+
+# performance panel
+perfButtonColor     = wx.Colour(0, 153, 153)
+perfButtonTextColor = wx.Colour(255, 255, 255)
+perfPanelColor = wx.Colour(102,204,153)
+
+
+
+#------------------------------------------------------------------------
+#     PATHS
+#------------------------------------------------------------------------
+
+def ConvertPath(path):
+    """Convert paths to the platform-specific separator"""
+    return apply(opj, tuple(path.split('\\')))
+
+
+DATA_DIR = getUserPath("sageui", "data")
+LOG_FILE = getUserPath("sageui", "output_log.txt")
+SAVED_STATES_DIR = getUserPath("saved-states")
+
+
+#------------------------------------------------------------------------
+#     DIALOG UTILITY FUNCTIONS 
+#------------------------------------------------------------------------
+
+def ShowWriteFailedDialog(filename):
+    dialog = wx.MessageDialog(None, "Unable to write to file <"+filename+">. Check write permissions for the file or directory.",
+                              "Write Failed", wx.OK)
+    dialog.ShowModal()
+
+
+def Message(msg, title):
+    """ for thread safety """
+    wx.CallAfter(_ShowMessage, msg, title)
+
+def _ShowMessage(msg, title):
+    dlg = wx.MessageDialog(None, msg, title, style = wx.OK)
+    dlg.ShowModal()
+
+def ChoiceDialog(msg, title):
+    dlg = wx.MessageDialog(None, msg, title, style = wx.OK | wx.CANCEL)
+    if dlg.ShowModal() == wx.ID_OK:
+        return True
+    else:
+        return False
+
+
+def ShowColorDialog(previousColor=None):
+    """ takes in (r,g,b) tuple and returns the same """
+    if not previousColor == None:
+        colorData = wx.ColourData()
+        colorData.SetColour(previousColor)
+        dlg = wx.ColourDialog(None, colorData)
+    else:
+        dlg = wx.ColourDialog(None)
+
+    dlg.GetColourData().SetChooseFull(True)
+    if dlg.ShowModal() == wx.ID_OK:
+        color = dlg.GetColourData().GetColour()
+        dlg.Destroy()
+        return color
+    else:
+        dlg.Destroy()
+        return (-1,-1,-1)
+
+
+
+
+def doRun():
+    return True
+
+
+#------------------------------------------------------------------------
+#     FONTS  
+#------------------------------------------------------------------------
+
+def StandardFont(window = None):
+    if window == None:
+        ss = wx.SystemSettings
+        ssFont = ss.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        return ssFont
+    else:
+        winFont = window.GetFont()
+        return winFont
+    
+
+def BoldFont(window = None):
+    if window == None:
+        ss = wx.SystemSettings
+        ssFont = ss.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+        ssFont.SetWeight(wx.BOLD)
+        return ssFont
+    else:
+        winFont = window.GetFont()
+        winFont.SetWeight(wx.BOLD)
+        return winFont
+
+
+
+#------------------------------------------------------------------------
+#    LOCATION OF THE SAGE SERVER 
+#------------------------------------------------------------------------
+    
+SAGE_SERVER = "sage.sl.startap.net"
+def setSAGEServer(server):
+    global SAGE_SERVER
+    SAGE_SERVER = server
+
+def getSAGEServer():
+    return SAGE_SERVER
+    
+
+
+
+#------------------------------------------------------------------------
+#    LOCATION OF THE APP LAUNCHER
+#------------------------------------------------------------------------
+    
+APP_LAUNCHER = ""
+def setAppLauncher(server):
+    global APP_LAUNCHER
+    APP_LAUNCHER = server
+
+def getAppLauncher():
+    return APP_LAUNCHER
+
+
+
+#------------------------------------------------------------------------
+#    SAGE UI VERSION 
+#------------------------------------------------------------------------
+
+global UI_VERSION
+def setUIVersion(v):
+    global UI_VERSION
+    UI_VERSION = v
+
+def getUIVersion():
+    return UI_VERSION
+
+
+
+
+#------------------------------------------------------------------------
+#     USERS DATA (data from sage server about all the connections)
+#------------------------------------------------------------------------
+
+global USERSDATA
+def setUsersData(d):
+    global USERSDATA
+    USERSDATA = d
+
+def getUsersData():
+    return USERSDATA
+
+
+
+#------------------------------------------------------------------------
+#    POINTER STATES AND TYPES
+#------------------------------------------------------------------------
+#### Sage Draw Object types
+POINTER_TYPE = 1
+
+
+#### MOUSE STATES
+PTR_NORMAL_STATE = 1
+PTR_MOVE_STATE   = 2
+PTR_RESIZE_STATE = 3
+
+
+
+
+#------------------------------------------------------------------------
+#    FOR RECORDING PERFROMANCE DATA TOTALS 
+#------------------------------------------------------------------------
+global startTime
+startTime = -1
+def getTimeStamp():
+    global startTime
+    if startTime == -1:  # set the start time on first request... so that we start from 0
+        startTime = time.time()
+    return int(round(time.time() - startTime))
+
+
+
+#------------------------------------------------------------------------
+#    FOR MULTIPLE SAGE DISPLAYS ON ONE FSMANAGER
+#------------------------------------------------------------------------
+
+MIDDLE_DISP = -1
+LEFT_DISP = 0
+RIGHT_DISP = 1
+BOTTOM_DISP = 2
+TOP_DISP = 3
+
+
+class Bounds:
+    """ used in event conversion """
+    def __init__(self, left=0, right=0, top=0, bottom=0):
+        self.left = int(round(left))
+        self.right = int(round(right))
+        self.top = int(round(top))
+        self.bottom = int(round(bottom))
+
+    def setAll(self, left, right, top, bottom):
+        self.left = int(round(left))
+        self.right = int(round(right))
+        self.top = int(round(top))
+        self.bottom = int(round(bottom))
+
+    def getAll(self):
+        return self.left, self.right, self.top, self.bottom
+
+    def getWidth(self):
+        return self.right - self.left
+
+    def getHeight(self):
+        return self.bottom - self.top   # top is 0
+
+##     def isIn(self, x, y):
+##         """ returns True if the (x,y) is in Bounds, False otherwise """
+##         if self.left <= x and self.right >= x and self.bottom <= y and self.top >= y:
+##             return True
+##         else:
+##             return False
Index: trunk/src/testing/ui/SAGEDrawObject.py
===================================================================
--- trunk/src/testing/ui/SAGEDrawObject.py	(revision 4)
+++ trunk/src/testing/ui/SAGEDrawObject.py	(revision 4)
@@ -0,0 +1,114 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+############################################################################
+
+
+
+from globals import *
+import time
+
+class SageDrawObject:
+    """ describes a base class for a sage draw object """
+    def __init__(self, objectId, objectType, sageGate):
+        self.objectId = objectId
+        self.objectType = objectType
+        self.visible = False
+        self.sageGate = sageGate
+        
+    def getId(self):
+        return self.objectId
+
+    def getType(self):
+        return self.objectType
+    
+    def isVisible(self):
+        return self.visible
+
+    def show(self):
+        if not self.visible:
+            self.visible = True
+            self.sageGate.showObject(self.objectId)
+
+    def hide(self):
+        if self.visible:
+            self.visible = False
+            self.sageGate.hideObject(self.objectId)
+        
+    
+
+
+
+class PointerObject(SageDrawObject):
+    """ describes a sage draw object for pointers """
+    def __init__(self, objectId, sageGate):
+        SageDrawObject.__init__(self, objectId, POINTER_TYPE, sageGate)
+        self.clickPos = [-1,-1]  # last click position [x,y]
+        self.lastRegion = [-1, None]     # [regionId, app]
+        self.region = [-1, None]     # [regionId, app]
+        self.state = PTR_NORMAL_STATE  # controls all the drawing of the pointer
+        self.ptrState = PTR_NORMAL_STATE  # only used to control the drawing of the cursor itself
+        self.leftDown = False
+        self.leftDownTime = 0.0
+
+
+    def updateRegion(self, regionId, app):
+        self.lastRegion = self.region
+        self.region = [regionId, app]
+        
+
+    def showResizePointer(self):
+        self.ptrState = PTR_RESIZE_STATE
+        self.sageGate.showResizeMouse(self.objectId, self.region[0])
+
+
+    def reset(self):
+        self.ptrState = PTR_NORMAL_STATE
+        self.state = PTR_NORMAL_STATE
+        self.sageGate.resetMouseState(self.objectId)
+
+
+    def onMouseDown(self, app, regionId, x, y):
+        self.leftDown = True
+        self.leftDownTime = time.time()
+        self.clickPos = [x,y]
+        self.lastRegion = [regionId, app]
+        self.sageGate.sendMouseDown(self.objectId)
+        
+
+    def onMouseUp(self):
+        self.leftDown = False
+        self.sageGate.sendMouseUp(self.objectId)
Index: trunk/src/testing/ui/help.py
===================================================================
--- trunk/src/testing/ui/help.py	(revision 4)
+++ trunk/src/testing/ui/help.py	(revision 4)
@@ -0,0 +1,125 @@
+############################################################################
+#
+# SAGE UI - A Graphical User Interface for SAGE
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+import wx.lib.dialogs
+from globals import *
+from wx.lib import layoutf
+
+# a list of IDs for all the help text
+FILE_LIBRARY = 9000
+
+
+
+
+allHelpStrings = {}  # help strings keyed by the above IDs
+
+# checks if the event that triggered this is a EVT_CHAR and it comes from an F1 key
+def ShowHelp(event):
+    if hasattr(event,"GetKeyCode") and not event.GetKeyCode() == wx.WXK_F1:
+        event.Skip()  #propagate the event further cause someone else might need it
+    else:
+        dlg = ScrolledMessageDialog(None, allHelpStrings[event.GetId()], "Help", size=(500,400))
+        dlg.ShowModal()
+
+
+
+class ScrolledMessageDialog(wx.Dialog):
+    def __init__(self, parent, msg, caption,
+                 pos=wx.DefaultPosition, size=(500,300),
+                 style=wx.DEFAULT_DIALOG_STYLE):
+        wx.Dialog.__init__(self, parent, -1, caption, pos, size, style)
+        self.SetBackgroundColour(dialogColor)
+        self.SetForegroundColour(wx.WHITE)
+        x, y = pos
+        if x == -1 and y == -1:
+            self.CenterOnScreen(wx.BOTH)
+
+        text = wx.TextCtrl(self, -1, msg, 
+                           style=wx.TE_MULTILINE | wx.TE_READONLY)
+        #text.SetBackgroundColour(appPanelColor)
+        #text.SetDefaultStyle(wx.TextAttr(wx.WHITE, appPanelColor))
+        ok = wx.Button(self, wx.ID_OK, "OK")
+        ok.SetDefault()
+        lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)) 
+        text.SetConstraints(lc)
+
+        lc = layoutf.Layoutf('b=b5#1;x%w50#1;w!80;h*', (self,))
+        ok.SetConstraints(lc)
+        
+        self.SetAutoLayout(1)
+        self.Layout()
+
+
+
+
+allHelpStrings[ FILE_LIBRARY ]='''File Library Help\n-------------------------\n
+All the files are organized by their type and for each type there is a directory. Under each directory you can have multiple sub-directories to help you organize the files better. The tree you see is a direct representation of the actual directory tree on the server, except from the "favorites" which is explained later. You can add files, delete them, move them, create and delete directories, view previews and show files on the tiled display.
+
+
+NOTE: Most of the following actions directly affect the files and directories on the server.
+
+SEARCH:
+- you can search as you type. By pressing ENTER or RETURN in the search box you search for the next occurence of the same string. "Find Again" button performs the same action.\n
+REFRESH:
+- this refreshes the whole directory tree to bring it up to date with any changes other users made. The tree will be automatically refreshed if a file could not be found in any of the below operations.\n
+ADD FILES:
+- just drag and drop a file from your computer anywhere on the tree (or use the "Browse for Files). The file will be uploaded to the server automatically and initially stored in the directory that matches its type. If a file with the same filename and file size exists, it will not be uploaded.\n
+DELETE FILES:
+- right click on a file you wish to delete and click "Delete File". The file will be permanently deleted from the server.\n
+MOVE FILES:
+- to organize your files you can move them from one directory to another (but only within the same "type" folder). To move a file just drag and drop it where you want it. You can even drop the file on another file and it will be moved to the same folder as that file. Note however, that directories cannot be moved nor can favorite files. If you drop the file on a wrong place the move will be ignored.\n
+CREATE DIRECTORY:
+- to create a sub-directory right click on any directory and click "New Folder". A new directory will be created as a sub-dir of the clicked one. You can then populate this new directory with files.\n
+DELETE DIRECTORY:
+- to delete a directory and all the files in it right click on a directory and click "Delete Folder".\n
+VIEW PREVIEW:
+- previews are automatically shown when a file is clicked on. However, previews are only available for images.\n
+SHOW FILE:
+- Simply double-click on a file and it will be shown. Another way is when a file is selected the show button is enabled and you can click it to show the file. The execution information (app name, params...) used for showing the file is retrieved from the server which in turn reads it from a config file.\n\n
+FAVORITES:
+-----------------
+- the last outermost folder is called "favorites" and this is where you can store your favorite files (think of them as bookmarks or symbolic links). This whole folder and the files in it are just virtual and do not really exist on the server or your computer. However, the list of files in there is automatically stored on your local computer whenever there is a change and they are automatically reloaded upon startup.\n
+ADD FILES TO FAVORITES:
+- drag and drop a file from anywhere to anywhere in the favorites part of the tree. The file link will be automatically put under the correct type. The file itself will not be moved on the server, just a symbolic link will be created so when original files location changes this link will be invalid.\n
+REMOVE FILES FROM FAVORITES:
+- right click on a file and select "Remove From Favorites". This action will not remove the file from the server.\n
+SHOW A FILE FROM FAVORITES:
+- the same procedure as above (double-click or "Show" button)
+
+NOTE: You cannot create new folders or move files within the favorites folder. Also, these files might become invalid if the orginal files that they point to have been moved/removed. In that case remove the file from favorites and add it again.
+'''
Index: trunk/src/testing/Makefile
===================================================================
--- trunk/src/testing/Makefile	(revision 4)
+++ trunk/src/testing/Makefile	(revision 4)
@@ -0,0 +1,134 @@
+MACHINE=$(shell uname -s)
+SHELL=/bin/bash
+preprojects = QUANTA/src
+subprojects = app/render app/atlantis app/checker app/FileViewer app/bitplay app/vnc
+
+PREFIX=${RPM_BUILD_ROOT}
+
+
+default:
+	@for i in `echo $(preprojects)`; do cd $$i; $(MAKE) install; cd - ; done
+	@cd src; $(MAKE) install; cd -
+	@for i in `echo $(subprojects)`; do cd $$i; $(MAKE); cd - ; done
+
+build: default
+	@for i in `echo $(preprojects)`; do cd $$i; $(MAKE) install; cd - ; done
+	@for i in `echo $(subprojects)`; do cd $$i; $(MAKE) install; cd - ; done
+
+install: build
+# make directories
+	mkdir -p ${PREFIX}/usr/local/sage/bin
+	mkdir -p ${PREFIX}/usr/local/sage/bin/fileServer
+	mkdir -p ${PREFIX}/usr/local/sage/sageConfig/
+	mkdir -p ${PREFIX}/usr/local/sage/sageConfig/applications
+	mkdir -p ${PREFIX}/usr/local/sage/sageConfig/fileServer
+	mkdir -p ${PREFIX}/usr/local/sage/bin/sageProxy
+	mkdir -p ${PREFIX}/usr/local/sage/bin/log
+	mkdir -p ${PREFIX}/usr/local/sage/bin/appLauncher
+	mkdir -p ${PREFIX}/usr/local/sage/include
+ifeq ($(MACHINE), Darwin)
+	mkdir -p ${PREFIX}/usr/local/sage/lib
+else
+	mkdir -p ${PREFIX}/usr/local/sage/lib64
+endif
+	mkdir -p ${PREFIX}/usr/local/sage/dim
+	mkdir -p ${PREFIX}/usr/local/sage/dim/devices
+	mkdir -p ${PREFIX}/usr/local/sage/dim/hwcapture
+	mkdir -p ${PREFIX}/usr/local/sage/dim/overlays
+	mkdir -p ${PREFIX}/usr/local/sage/dim/sounds
+	mkdir -p ${PREFIX}/usr/local/sage/dim/ui
+	mkdir -p ${PREFIX}/usr/local/sage/ui
+	mkdir -p ${PREFIX}/usr/local/sage/ui/misc
+	mkdir -p ${PREFIX}/usr/local/sage/ui/connectionManager
+	mkdir -p ${PREFIX}/usr/local/sage/ui/images
+	mkdir -p ${PREFIX}/usr/local/sage/ui/sessions
+	mkdir -p ${PREFIX}/etc/profile.d
+	mkdir -p ${PREFIX}/etc/ld.so.conf.d
+# copy OS environment settings
+	cp etc/sage.csh ${PREFIX}/etc/profile.d
+	cp etc/sage.sh ${PREFIX}/etc/profile.d
+	cp etc/sage.conf ${PREFIX}/etc/ld.so.conf.d
+# copy binaries
+	cp bin/fsManager ${PREFIX}/usr/local/sage/bin
+	cp bin/sageDisplayManager ${PREFIX}/usr/local/sage/bin
+ifeq ($(MACHINE), Darwin)
+	cp -r bin/sageDisplayManager.app ${PREFIX}/usr/local/sage/bin
+endif
+	cp bin/render ${PREFIX}/usr/local/sage/bin
+	cp bin/atlantis ${PREFIX}/usr/local/sage/bin
+	cp bin/checker ${PREFIX}/usr/local/sage/bin
+	cp bin/imageviewer ${PREFIX}/usr/local/sage/bin
+	cp bin/pdfviewer ${PREFIX}/usr/local/sage/bin
+	cp bin/bplay-noglut ${PREFIX}/usr/local/sage/bin
+	cp bin/bridgeConsole ${PREFIX}/usr/local/sage/bin
+	cp bin/fsConsole ${PREFIX}/usr/local/sage/bin
+	cp bin/sageBridge ${PREFIX}/usr/local/sage/bin
+	cp bin/uiConsole ${PREFIX}/usr/local/sage/bin
+	cp bin/VNCViewer ${PREFIX}/usr/local/sage/bin
+# copy configuration files
+	cp sageConfig/applications/atlantis.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/applications/bitplayer.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/applications/imageviewer.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/applications/pdfviewer.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/applications/render.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/applications/VNCViewer.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp sageConfig/fsManager.conf ${PREFIX}/usr/local/sage/sageConfig
+	cp sageConfig/sageBridge.conf ${PREFIX}/usr/local/sage/sageConfig
+	cp sageConfig/stdtile.conf ${PREFIX}/usr/local/sage/sageConfig
+	cp sageConfig/stdtile-1.conf ${PREFIX}/usr/local/sage/sageConfig
+	cp sageConfig/stdtile-2.conf ${PREFIX}/usr/local/sage/sageConfig
+	cp sageConfig/stdtile-20.conf ${PREFIX}/usr/local/sage/sageConfig
+# copy utility files
+	cp bin/yuv.vert ${PREFIX}/usr/local/sage/bin
+	cp bin/yuv.frag ${PREFIX}/usr/local/sage/bin
+	cp bin/sage ${PREFIX}/usr/local/sage/bin
+	cp bin/sageLauncher.py ${PREFIX}/usr/local/sage/bin
+	cp bin/sagePath.py ${PREFIX}/usr/local/sage/bin
+	cp bin/subprocess.py ${PREFIX}/usr/local/sage/bin
+# copy includes
+	cp include/*.h ${PREFIX}/usr/local/sage/include
+# copy libraries
+ifeq ($(MACHINE), Darwin)
+	cp lib/libquanta.dylib ${PREFIX}/usr/local/sage/lib
+	cp lib/libsail.dylib ${PREFIX}/usr/local/sage/lib
+else
+	cp lib/libquanta.so ${PREFIX}/usr/local/sage/lib64
+	cp lib/libsail.so ${PREFIX}/usr/local/sage/lib64
+endif
+# copy appLauncher files
+	cp bin/appLauncher/*.py ${PREFIX}/usr/local/sage/bin/appLauncher
+	cp bin/appLauncher/GO ${PREFIX}/usr/local/sage/bin/appLauncher
+	cp sageConfig/applications/applications.conf ${PREFIX}/usr/local/sage/sageConfig/applications
+	cp bin/appLauncher/README ${PREFIX}/usr/local/sage/bin/appLauncher
+# copy file server files
+	cp bin/fileServer/*.py ${PREFIX}/usr/local/sage/bin/fileServer
+	cp sageConfig/fileServer/fileServer.conf ${PREFIX}/usr/local/sage/sageConfig/fileServer
+ifeq ($(MACHINE), Darwin)
+	cp -fr bin/fileServer/misc ${PREFIX}/usr/local/sage/bin/fileServer
+else
+	cp -fru bin/fileServer/misc ${PREFIX}/usr/local/sage/bin/fileServer
+endif
+# copy sage proxy files
+	cp bin/sageProxy/*.py ${PREFIX}/usr/local/sage/bin/sageProxy
+# copy UI files
+	cp ui/*.py ${PREFIX}/usr/local/sage/ui/
+	cp ui/misc/*.py ${PREFIX}/usr/local/sage/ui/misc/
+	cp ui/connectionManager/*.py ${PREFIX}/usr/local/sage/ui/connectionManager/
+	cp ui/connectionManager/README ${PREFIX}/usr/local/sage/ui/connectionManager/
+	cp ui/images/*.jpg ${PREFIX}/usr/local/sage/ui/images/
+	cp ui/images/*.png ${PREFIX}/usr/local/sage/ui/images/
+	cp ui/images/*.gif ${PREFIX}/usr/local/sage/ui/images/
+# compile and copy DIM files
+	cp dim/*.py ${PREFIX}/usr/local/sage/dim/
+	cp dim/devices/*.py ${PREFIX}/usr/local/sage/dim/devices/
+	cp dim/hwcapture/*.py ${PREFIX}/usr/local/sage/dim/hwcapture/
+	cp dim/hwcapture/go.bat ${PREFIX}/usr/local/sage/dim/hwcapture/
+	cp dim/hwcapture/mouse_to_joy.PIE ${PREFIX}/usr/local/sage/dim/hwcapture/
+	cp dim/overlays/*.py ${PREFIX}/usr/local/sage/dim/overlays/
+	cp dim/*.png ${PREFIX}/usr/local/sage/dim/
+
+
+clean:
+	@for i in `echo $(preprojects)`; do cd $$i; $(MAKE) $@; cd - ; done
+	@for i in `echo src $(subprojects)`; do cd $$i; $(MAKE) $@; cd - ; done
+
Index: trunk/src/testing/app/volvis/Makefile.cluster.mac
===================================================================
--- trunk/src/testing/app/volvis/Makefile.cluster.mac	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.cluster.mac	(revision 4)
@@ -0,0 +1,33 @@
+# Makefile for  cluster volvis
+# The slaves run the volvis with their respective frustum using MPI
+# Master does the interaction (MPI) 
+# The transfer-fn UI communicates with the master (QUANTA), and master broadcasts this to slaves(MPI)
+#QUANTA_HOME=/home/cavern/Q2
+#QUANTA_HOME=${HOME}/Q2
+#QUANTA_HOME=/home/luc/Q2
+#QUANTA_HOME=${HOME}/QUANTA64
+QUANTA_HOME=/usr/local
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore 
+LIBRARY_DIR 	= -L${QUANTA_HOME}/lib -L../../lib
+LIBRARIES 	= -framework GLUT -framework OpenGL -framework Cg -lm -lquanta_32 -lobjc -lstdc++ -lsail
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_DISTRIBUTED -DV_NETDATA $(COMPILER_FLAGS) -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(INCLUDE_DIR) -FGLUT -FOpenGL -FCg -DV_SAGE -I../../include
+CXX		= mpicc 
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= mpicc -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vARB.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o 
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/Makefile.cluster
===================================================================
--- trunk/src/testing/app/volvis/Makefile.cluster	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.cluster	(revision 4)
@@ -0,0 +1,34 @@
+# Makefile for  cluster volvis
+# The slaves run the volvis with their respective frustum using MPI
+# Master does the interaction (MPI) 
+# The transfer-fn UI communicates with the master (QUANTA), and master broadcasts this to slaves(MPI)
+#QUANTA_HOME=/home/cavern/Q2
+#QUANTA_HOME=${HOME}/Q2
+#QUANTA_HOME=/home/luc/Q2
+#QUANTA_HOME=${HOME}/QUANTA64
+QUANTA_HOME=/usr/local
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore 
+LIBRARY_DIR 	= -L/usr/lib -L/usr/X11R6/lib64 -L${QUANTA_HOME}/lib64 -Wl,-rpath ${QUANTA_HOME}/lib64 -L../../lib
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64 -lsail
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_DISTRIBUTED -DV_NETDATA $(COMPILER_FLAGS) -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(INCLUDE_DIR)  -DV_SAGE -I../../include
+CXX		= mpiCC -Wno-deprecated
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= mpiCC -O3 -Wno-deprecated
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vARB.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o 
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+		/bin/cp $(EXEC) ../../bin
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/caDataManagerClient.h
===================================================================
--- trunk/src/testing/app/volvis/caDataManagerClient.h	(revision 4)
+++ trunk/src/testing/app/volvis/caDataManagerClient.h	(revision 4)
@@ -0,0 +1,156 @@
+/******************************************************************************
+ * OptiStore - A Data Processing Server
+ * Copyright (C) 2003 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * Authors: Luc Renambot luc@evl.uic.edu
+ *          Shalini Venkataraman shalini@evl.uic.edu
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about OptiStore to luc@evl.uic.edu
+ *****************************************************************************/
+
+#include "private.h"
+#include "directions.h"
+
+typedef struct _NetVertexBuffer
+{
+    float          *vertex;
+    float          *normal;
+    unsigned int   *index;
+    unsigned short *length;
+    int  lengths, nbpts, nbindices;
+    //sort of copy constructor
+    void copy(struct _NetVertexBuffer* src) {
+	nbpts = src->nbpts;
+	lengths = src->lengths;
+	nbindices = src->nbindices;
+
+	vertex = (float*)malloc( nbpts * 3 * sizeof(float) );
+	memcpy(vertex,src->vertex, nbpts * 3 * sizeof(float));
+
+	normal = (float*)malloc( nbpts * 3 * sizeof(float) );
+	memcpy(normal,src->normal,nbpts * 3 * sizeof(float));
+
+	index  = (unsigned int*)malloc( nbindices * sizeof(unsigned int) );
+	memcpy(index, src->index,nbindices * sizeof(unsigned int));
+
+	length = (unsigned short*)malloc( lengths * sizeof(unsigned short) );
+	memcpy(length, src->length,lengths * sizeof(unsigned short));
+    }
+    void freeArrays() {
+	    free(vertex);
+	    free(normal);
+	    free(index);
+	    free(length);
+    }
+
+} NetVertexBuffer;
+
+typedef struct _NetPointBuffer
+{
+    float *vertex;
+    int    nbpts;
+} NetPointBuffer;
+
+
+    //attribute for each data
+typedef struct _DataDesc
+{
+    char* name;
+    int x,y,z;
+} DataDesc;
+
+////////////////////////////////////////////////////////////
+
+class cDataManagerClient
+{
+protected:
+    QUANTAnet_tcpClient_c *client;
+#if defined(USE_RBUDP)
+    QUANTAnet_rbudpReceiver_c *blastee;
+#endif
+
+    int port;
+    char *hostname;
+    int id;
+    int num_datasets;
+    DataDesc *datasets;
+
+
+private:
+    int status, dataSize;
+    unsigned int command;
+    int sizes[6];
+    NetVertexBuffer *vb;
+    NetPointBuffer  *pb;
+    unsigned char  *dataptr;
+    unsigned short *gradptr;
+
+
+public:
+
+    static int RBUDP_PORT;
+
+    cDataManagerClient(char *_hostname = "localhost");
+    ~cDataManagerClient();
+
+
+    void Open(int _port = 6544);
+    void Init();
+    void Exit();
+    int  Query();
+
+    void Load(int ds);
+    void Resample(int sx, int sy, int sz);
+    void Crop(int ox, int oy, int oz, int sx, int sy, int sz);
+
+    unsigned char*  Volume();
+    unsigned short* Gradient();
+
+    int* Histogram();
+    unsigned char* Histogram2D();
+
+    NetVertexBuffer* Isosurface(int isoval, int gaussp, float decim);
+    NetPointBuffer* IsoPoints(int isoval, int inc, int maxp);
+
+        // Get the name of a dataset
+    char *Name(int _idx);
+
+        //Given the symbolic name of a volume, returns its index
+        //if the volume is not found return -1;
+    int Lookup(const char* name) ;
+
+
+	//Given the symbolic name of a volume as a wild card, returns list of indices that match
+	//if not found, return 0;
+	//caller has to free the memory
+	int GetMatching(char* wildcard, int *&indexList);
+        //get the data dimesions for the data indexed by idx
+    void GetDataDims(unsigned int idx, unsigned int& x, unsigned int& y, unsigned int& z);
+};
Index: trunk/src/testing/app/volvis/machines.dat
===================================================================
--- trunk/src/testing/app/volvis/machines.dat	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat	(revision 4)
@@ -0,0 +1,15 @@
+3 0.66 19.46 1.2 32.4 0.0 0.0 1.0 1.0
+6 20.78 39.58 1.2 32.4 0.0 0.0 1.0 1.0
+9 40.9 59.7 1.2 32.4 0.0 0.0 1.0 1.0
+12 61.2 79.82 1.2 32.4 0.0 0.0 1.0 1.0
+15 81.14 99.94 1.2 32.4 0.0 0.0 1.0 1.0
+2 0.66 19.46 34.8 66.0 0.0 0.0 1.0 1.0
+5 20.78 39.58 34.8 66.0 0.0 0.0 1.0 1.0
+8 40.9 59.7 34.8 66.0 0.0 0.0 1.0 1.0
+11 61.2 79.82 34.8 66.0 0.0 0.0 1.0 1.0
+14 81.14 99.94 34.7 66.0 0.0 0.0 1.0 1.0
+1 0.66 19.46 68.4 99.6 0.0 0.0 1.0 1.0
+4 20.78 39.58 68.4 99.6 0.0 0.0 1.0 1.0
+7 40.9 59.7 68.4 99.6 0.0 0.0 1.0 1.0
+10 61.2 79.82 68.4 99.6 0.0 0.0 1.0 1.0
+13 81.14 99.94 68.4 99.6 0.0 0.0 1.0 1.0
Index: trunk/src/testing/app/volvis/Makefile.standalone
===================================================================
--- trunk/src/testing/app/volvis/Makefile.standalone	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.standalone	(revision 4)
@@ -0,0 +1,32 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+#for evl
+#QUANTA_HOME=${HOME}/Q2
+QUANTA_HOME=/usr/local
+#for ncmir
+#QUANTA_HOME=/home/cavern/Q2
+#for igpp
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L/usr/lib -L/usr/X11R6/lib64 -L${QUANTA_HOME}/lib -Wl,-rpath ${QUANTA_HOME}/lib
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR) 
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= g++ -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) ../OptiStore/directions.o ../OptiStore/caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/machines.dat.ncmir
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.ncmir	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.ncmir	(revision 4)
@@ -0,0 +1,4 @@
+1 0.0 23.4375 0.0 100.0
+2 23.4375 46.875 0.0 100.0
+3 53.125 76.5625 0.0 100.0
+4 76.5625 100.0 0.0 100.0
Index: trunk/src/testing/app/volvis/optiAdam.dat
===================================================================
--- trunk/src/testing/app/volvis/optiAdam.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiAdam.dat	(revision 4)
@@ -0,0 +1,16 @@
+0 10.1.1.112
+1 10.1.1.113
+2 10.1.1.117
+3 10.1.1.112
+4 10.1.1.113
+5 10.1.1.117
+6 10.1.1.112
+7 10.1.1.113
+8 10.1.1.117
+9 10.1.1.112
+10 10.1.1.113
+11 10.1.1.117
+12 10.1.1.112
+13 10.1.1.113
+14 10.1.1.117
+15 10.1.1.112
Index: trunk/src/testing/app/volvis/vCG.h
===================================================================
--- trunk/src/testing/app/volvis/vCG.h	(revision 4)
+++ trunk/src/testing/app/volvis/vCG.h	(revision 4)
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//vCG.h
+//contains cg related code from Luc
+#if defined(ADDCGGL)
+#ifndef _VCG_H_
+#define _VCG_H_
+
+#include "glUE.h"
+#include <assert.h>
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+
+extern CGcontext context;
+extern CGprogram vertexProgram, fragmentProgram;
+extern CGprofile fprofile, vprofile;
+extern CGparameter ModelViewProj;
+extern CGparameter hTexture0, hTexture1;
+extern CGparameter param;
+
+void handleCgError();
+int initCG();
+void exitCG();
+void enableCG(unsigned int);
+void disableCG();
+void setCurTextureCG(int name) ;
+
+#endif
+#endif
Index: trunk/src/testing/app/volvis/vSliceView.h
===================================================================
--- trunk/src/testing/app/volvis/vSliceView.h	(revision 4)
+++ trunk/src/testing/app/volvis/vSliceView.h	(revision 4)
@@ -0,0 +1,66 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _vSliceView_h_
+#define _vSliceView_h_
+
+#include "glUE.h"
+#include "vPrimitive.h"
+
+//class that handles the probe
+class vProbe: public vPrimitive {
+public:
+	vProbe();
+	virtual ~vProbe();
+	void init();
+	void draw();
+};
+
+
+//class that handles the probe
+class vSliceView: public vPrimitive {
+public:
+	vSliceView();
+	virtual ~vSliceView();
+	void init();
+	void draw();
+//	int select();
+private:
+	vProbe axialProbe;		//probe for the axial slice view
+	vProbe coronalProbe;		//probe for the coronal slice view
+	vProbe sagittalProbe;		//probe for the sagittal slice view
+};
+
+
+#endif
Index: trunk/src/testing/app/volvis/vGeometry.h
===================================================================
--- trunk/src/testing/app/volvis/vGeometry.h	(revision 4)
+++ trunk/src/testing/app/volvis/vGeometry.h	(revision 4)
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _V_GEOMETRY_H
+#define _V_GEOMETRY_H
+#include "global.h"
+#include "vPrimitive.h"
+
+//handles displaying geometry
+class vGeometry : public vPrimitive {
+public:
+	vGeometry();
+	vGeometry(NetVertexBuffer* theGeom );
+	vGeometry(char* wildcard, char* serverName, float scale) ;
+	virtual ~vGeometry();
+
+	void setCurFrame(int curFrame) ;
+	void          init();
+	void          draw();
+	void		next();
+	void 	prev();
+	//int select() ;
+	void drawBoundBox() ;
+
+	float angle;
+	float axes[3];
+    cDataManagerClient* opClient;
+	int* indexList;
+	int numFrames, curFrame;
+	vector<NetVertexBuffer*> cache;
+	float initScale;
+
+	//for the point buffer
+	//NetPointBuffer* pb;
+	//vGeometry(NetPointBuffer* thePoints );
+
+
+	/*virtual  int           key(unsigned char k, int x, int y);
+	virtual  int           special(int k, int x, int y);
+	virtual  int           mouse(int button, int state, int x, int y);
+	virtual  int           move(int x, int y);
+	virtual  int           release();   //tells widget it is done
+
+	void			setNext(vPrimitive *p);  //set next in list
+	vPrimitive		*getNext();                   //get next in list
+	void			remove(vPrimitive *p);   //remove from list
+	void			setName(const char *PName);  //just a name
+	*/
+};
+
+#endif
+
Index: trunk/src/testing/app/volvis/vFPSText.h
===================================================================
--- trunk/src/testing/app/volvis/vFPSText.h	(revision 4)
+++ trunk/src/testing/app/volvis/vFPSText.h	(revision 4)
@@ -0,0 +1,103 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//CFrameTimer & vFPSText.h Class
+//Calculates FPS depending on frame history
+//so that the transition is smooth
+//abd vFPSText.just draw the text and queries the timer
+//Shalini Venkataraman Apr 2002
+// Added changes for linux port, Atul Nayak , Jun 27 2002
+#ifndef _VFPSTEXT_H_
+#define _VFPSTEXT_H_
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#if defined(linux) || defined(__APPLE__)
+#include <sys/time.h>
+#endif
+
+#define FRAME_HISTORY 10 //number of frames used in smoothing
+#include "vPrimitive.h"
+
+class CFrameTimer {
+	double elapsedTime; //time elapsed since timer was instantiated
+#ifdef WIN32
+  	LARGE_INTEGER last; //last counter
+#endif
+#if defined(linux) || defined(__APPLE__)
+	struct timeval _tstart;
+	struct timezone tz;
+#endif
+
+	double timerResolution; //time for one count
+	double frameTimes[FRAME_HISTORY]; //array of previous times
+	int frameLocation; //next index into frameTimes array
+	unsigned int framesProcessed; //no of times the counter was pinged
+public:
+	CFrameTimer();
+	//ping counter to calculate the time elapsed and store it
+	void pingFrameCounter();
+	//get the current smoothed FPS depending on frame history
+	float getFPS();
+
+};
+class vText : public vPrimitive {
+public:
+	vText():vPrimitive() { };
+	vText(const char* str);
+	void draw();
+	void init();
+	char myText[256];
+};
+
+class vFPSText : public vText {
+public:
+	vFPSText():vText() {};
+	void draw();
+	void init();
+private:
+	CFrameTimer* timer;
+};
+
+class vVolText : public vText {
+public:
+	vVolText():vText() {};
+	void draw();
+	void init();
+private:
+};
+
+#endif
+
Index: trunk/src/testing/app/volvis/Makefile.mac
===================================================================
--- trunk/src/testing/app/volvis/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.mac	(revision 4)
@@ -0,0 +1,33 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+#for evl
+#QUANTA_HOME=${HOME}/Q2
+QUANTA_HOME=/usr/local
+#for ncmir
+#QUANTA_HOME=/home/cavern/Q2
+#for igpp
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L${QUANTA_HOME}/lib -L../../lib
+LIBRARIES 	= -framework GLUT -framework OpenGL -framework Cg -lobjc -lm -lquanta_32 -lsail
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR)  -DV_SAGE -I../../include -FGLUT -FOpenGL -FCg
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= g++ -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+		cp $(EXEC) ../../bin
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC) directions.o caDataManagerClient.o
+
Index: trunk/src/testing/app/volvis/Makefile
===================================================================
--- trunk/src/testing/app/volvis/Makefile	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile	(revision 4)
@@ -0,0 +1,33 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+#for evl
+#QUANTA_HOME=${HOME}/Q2
+QUANTA_HOME=/usr/local
+#for ncmir
+#QUANTA_HOME=/home/cavern/Q2
+#for igpp
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L/usr/lib -L/usr/X11R6/lib64 -L${QUANTA_HOME}/lib -Wl,-rpath ${QUANTA_HOME}/lib -L../../lib
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64 -lsail
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR)  -DV_SAGE -I../../include
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= g++ -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+		cp $(EXEC) ../../bin
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/glUE.cpp
===================================================================
--- trunk/src/testing/app/volvis/glUE.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/glUE.cpp	(revision 4)
@@ -0,0 +1,604 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include "glUE.h"
+#include "global.h"
+#include <string.h>
+
+#ifdef WIN32
+//3D texture
+PFNGLTEXIMAGE3DPROC glTexImage3DEXT;
+
+#ifdef GL_EXT_blend_minmax
+PFNGLBLENDEQUATIONEXTPROC glBlendEquationEXT;
+#endif
+
+#ifdef GL_EXT_color_table
+//palated texture
+PFNGLCOLORTABLEEXTPROC  glColorTableEXT;
+#endif
+
+#ifdef GL_EXT_pixel_texture
+GLPIXELTEXGENEXTFUNCPTR glPixelTexGenEXT;
+#endif
+
+//multi-texture
+#ifdef GL_ARB_multitexture
+PFNGLACTIVETEXTUREARBPROC       glActiveTexture;
+PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture;
+PFNGLMULTITEXCOORD1FARBPROC     glMultiTexCoord1fARB;
+PFNGLMULTITEXCOORD1FVARBPROC    glMultiTexCoord1fvARB;
+PFNGLMULTITEXCOORD2FARBPROC     glMultiTexCoord2fARB;
+PFNGLMULTITEXCOORD2FVARBPROC    glMultiTexCoord2fvARB;
+PFNGLMULTITEXCOORD3FARBPROC     glMultiTexCoord3fARB;
+PFNGLMULTITEXCOORD3FVARBPROC    glMultiTexCoord3fvARB;
+#endif
+
+//Secondary color
+#ifdef GL_EXT_secondary_color
+PFNGLSECONDARYCOLOR3FEXTPROC   glSecondaryColor3fEXT;
+#endif
+
+//Register Combiners
+#ifdef GL_NV_register_combiners
+PFNGLCOMBINERPARAMETERFVNVPROC              glCombinerParameterfvNV;
+PFNGLCOMBINERPARAMETERFNVPROC               glCombinerParameterfNV;
+PFNGLCOMBINERPARAMETERIVNVPROC              glCombinerParameterivNV;
+PFNGLCOMBINERPARAMETERINVPROC               glCombinerParameteriNV;
+PFNGLCOMBINERINPUTNVPROC                    glCombinerInputNV;
+PFNGLCOMBINEROUTPUTNVPROC                   glCombinerOutputNV;
+PFNGLFINALCOMBINERINPUTNVPROC               glFinalCombinerInputNV;
+PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC      glGetCombinerInputParameterfvNV;
+PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC      glGetCombinerInputParameterivNV;
+PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC     glGetCombinerOutputParameterfvNV;
+PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC     glGetCombinerOutputParameterivNV;
+PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glGetFinalCombinerInputParameterfvNV;
+PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glGetFinalCombinerInputParameterivNV;
+#endif
+
+//Fragment Shaders
+#ifdef GL_ATI_fragment_shader
+PFNGLGENFRAGMENTSHADERSATIPROC   glGenFragmentShadersATI;
+PFNGLBINDFRAGMENTSHADERATIPROC   glBindFragmentShaderATI;
+PFNGLDELETEFRAGMENTSHADERATIPROC glDeleteFragmentShaderATI;
+PFNGLBEGINFRAGMENTSHADERATIPROC  glBeginFragmentShaderATI;
+PFNGLENDFRAGMENTSHADERATIPROC    glEndFragmentShaderATI;
+PFNGLPASSTEXCOORDATIPROC         glPassTexCoordATI;
+PFNGLSAMPLEMAPATIPROC            glSampleMapATI;
+PFNGLCOLORFRAGMENTOP1ATIPROC     glColorFragmentOp1ATI;
+PFNGLCOLORFRAGMENTOP2ATIPROC     glColorFragmentOp2ATI;
+PFNGLCOLORFRAGMENTOP3ATIPROC     glColorFragmentOp3ATI;
+PFNGLALPHAFRAGMENTOP1ATIPROC     glAlphaFragmentOp1ATI;
+PFNGLALPHAFRAGMENTOP2ATIPROC     glAlphaFragmentOp2ATI;
+PFNGLALPHAFRAGMENTOP3ATIPROC     glAlphaFragmentOp3ATI;
+PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glSetFragmentShaderConstantATI;
+#endif
+
+//env-bump
+#ifdef GL_ATIX_envmap_bumpmap
+PFNGLTEXBUMPPARAMETERIVATIXPROC     glTexBumpParameterivATIX;
+PFNGLTEXBUMPPARAMETERFVATIXPROC     glTexBumpParameterfvATIX;
+PFNGLGETTEXBUMPPARAMETERIVATIXPROC  glGetTexBumpParameterivATIX;
+PFNGLGETTEXBUMPPARAMETERFVATIXPROC  glGetTexBumpParameterfvATIX;
+#endif
+
+//wgl extensions ...
+#ifdef WGL_ARB_pbuffer
+PFNWGLCREATEPBUFFERARBPROC    wglCreatePbufferARB;
+PFNWGLGETPBUFFERDCARBPROC     wglGetPbufferDCARB;
+PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+PFNWGLDESTROYPBUFFERARBPROC   wglDestroyPbufferARB;
+PFNWGLQUERYPBUFFERARBPROC     wglQueryPbufferARB;
+#endif
+#ifdef WGL_ARB_pixel_format
+PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
+PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
+PFNWGLCHOOSEPIXELFORMATARBPROC      wglChoosePixelFormatARB;
+#endif
+#ifdef WGL_ARB_render_texture //render to texture
+PFNWGLBINDTEXIMAGEARBPROC     wglBindTexImageARB;
+PFNWGLRELEASETEXIMAGEARBPROC  wglReleaseTexImageARB;
+PFNWGLSETPBUFFERATTRIBARBPROC wglSetBufferAttribARB;
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+void LoadAllExtensions()
+{
+	cerr << "-----------------------------------------------------" << endl;
+	//-------------------- Open GL spec 1.2 -----------------------------
+	getOGL12();
+  //------------------- Register Combiners ----------------------------
+	getNV20();
+  //------------------- ATI Radeon 8000 -------------------------------
+	getATI8K();
+	//--------------------- wgl extensions ... ---------------------------
+	getWGL();
+	cerr << "-----------------------------------------------------" << endl << endl;
+
+
+}
+#endif
+
+GLboolean QueryExtension(char *extName)
+{
+  /*
+    ** Search for extName in the extensions string. Use of strstr()
+    ** is not sufficient because extension names can be prefixes of
+    ** other extension names. Could use strtok() but the constant
+    ** string returned by glGetString might be in read-only memory.
+    */
+    char *p;
+    char *end;
+    int extNameLen;
+
+    extNameLen = strlen(extName);
+
+    p = (char *)glGetString(GL_EXTENSIONS);
+    if (0 == p) {
+		cerr << "ERROR:: could not query extensions" << endl;
+        return GL_FALSE;
+    }
+
+    end = p + strlen(p);
+
+	if(!strcmp(extName, "Print")){
+		for(int i=0; i< (int)strlen(p); ++i){
+			cerr << p[i];
+		} cerr << endl;
+		return GL_FALSE;
+	}
+
+    while (p < end) {
+        int n = strcspn(p, " ");
+        if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
+            return GL_TRUE;
+        }
+        p += (n + 1);
+    }
+    return GL_FALSE;
+
+}
+
+int checkGfx() {
+	QueryExtension("Print");
+	int r, g, b, a, ar, ag, ab, aa, d, s;
+	GLboolean db,st, aux;
+
+	glGetIntegerv(GL_RED_BITS,           &r);
+	glGetIntegerv(GL_GREEN_BITS,         &g);
+	glGetIntegerv(GL_BLUE_BITS,          &b);
+	glGetIntegerv(GL_ALPHA_BITS,         &a);
+	glGetIntegerv(GL_ACCUM_RED_BITS,     &ar);
+	glGetIntegerv(GL_ACCUM_GREEN_BITS,   &ag);
+	glGetIntegerv(GL_ACCUM_BLUE_BITS,    &ab);
+	glGetIntegerv(GL_ACCUM_ALPHA_BITS,   &aa);
+	glGetIntegerv(GL_DEPTH_BITS,         &d);
+	glGetIntegerv(GL_STENCIL_BITS,       &s);
+	glGetBooleanv(GL_DOUBLEBUFFER,       &db);
+	glGetBooleanv(GL_STEREO,             &st);
+	glGetBooleanv(GL_AUX_BUFFERS,        &aux);
+
+	cerr << "Window Attributes" << endl;
+	cerr << "-----------------" << endl;
+	cerr << "color:    " << r + g + b + a << " bits";
+	cerr << " (" << r << "," << g << "," << b << "," << a << ")" << endl;
+	cerr << "accum:    " << ar+ag+ab+aa   << " bits";
+	cerr << " (" << ar << "," << ag << "," << ab << "," << aa << ")" << endl;
+	cerr << "depth:    " << d << " bits" << endl;
+	cerr << "stencil:  " << s << " bits" << endl;
+	cerr << "double:   ";
+	if(db) cerr << "YES" << endl;
+	else   cerr << "NO" << endl;
+	cerr << "aux:      ";
+	if(aux) cerr << "YES" << endl;
+	else    cerr << "NO" << endl;
+	cerr << "stereo :  ";
+	if(st) cerr << "YES" << endl;
+	else   cerr << "NO" << endl;
+	cerr << "-----------------" << endl;
+	if(QueryExtension("GL_ATI_fragment_shader")){
+		cerr << "PLATFORM:  ATI Radeon 8000 series" << endl;
+		return (int)GPATI8K;
+	}
+	if(QueryExtension("GL_NV_texture_shader")){
+		cerr << "PLATFORM:  nVidia GeForce 3" << endl;
+		return (int)GPNV20;
+	}
+	return 0;
+
+}
+
+//=====================================================================
+int GlErr(char *location, char *glfuncname)
+{
+  GLenum errCode;
+  const GLubyte *errString;
+
+  if((errCode = glGetError()) != GL_NO_ERROR){
+    errString = gluErrorString(errCode);
+    cerr << "OpenGL ERROR : " << location << "::" << glfuncname << " : "
+	 << (char *) errString << endl;
+    return 1;
+  }
+  return 0;
+}
+
+//=====================================================================
+int CardProfile()
+{
+
+
+	return 0;
+}
+
+
+#ifdef WIN32
+
+void getOGL12()
+{
+	glTexImage3DEXT = 0;
+
+	if(QueryExtension("GL_EXT_texture3D")){
+		cerr << "3D Texture is available!" << endl;
+		if(!(glTexImage3DEXT =
+			(PFNGLTEXIMAGE3DPROC)wglGetProcAddress("glTexImage3DEXT"))){
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"glTexImage3DEXT\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "*********************************" << endl;
+		}
+	} else if((glTexImage3DEXT = (PFNGLTEXIMAGE3DPROC)wglGetProcAddress("glTexImage3D")))
+			cerr << "OGL1.2 3D texture is available" << endl;
+	else cerr << "3D texture is NOT available" << endl;
+
+	//-------------------------------------------------------------------
+	//  blending
+#ifdef GL_EXT_blend_minmax
+	glBlendEquationEXT = 0;
+	if(!(glBlendEquationEXT =
+			(PFNGLBLENDEQUATIONEXTPROC)wglGetProcAddress("glBlendEquationEXT"))){
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"glBlendEquationEXT\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "*********************************" << endl;
+		}
+#endif
+
+	//-------------------------------------------------------------------
+	//-------------------- palated textures -----------------------------
+#ifdef GL_EXT_color_table
+	glColorTableEXT = 0;
+	if(QueryExtension("GL_EXT_color_table")){
+		cerr << "Color Table is available" << endl;
+		glColorTableEXT =
+      (PFNGLCOLORTABLEEXTPROC)wglGetProcAddress("glColorTableEXT");
+		if(!glColorTableEXT){
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"glColorTableEXT\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "*********************************" << endl;
+		}
+	} else cerr << "Color Table is not available" << endl;
+#endif
+
+
+	//HEY MOFO, THIS DOESN"T GO HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+	//HEY MOFO, THIS DOESN"T GO HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+#ifdef GL_EXT_pixel_texture
+	glPixelTexGenEXT = 0;
+	if(QueryExtension("GL_EXT_pixel_texture")){
+	  cerr << "Pixel texture is available" << endl;
+	}
+	else cerr << "Pixel Texture is NOT available" << endl;
+#endif
+
+	//-------------------------------------------------------------------
+	//-------------------- Multi-texture --------------------------------
+#ifdef GL_ARB_multitexture
+	glActiveTexture       = 0;
+	glClientActiveTexture = 0;
+	glMultiTexCoord1fARB  = 0;
+	glMultiTexCoord1fvARB = 0;
+	glMultiTexCoord2fARB  = 0;
+	glMultiTexCoord2fvARB = 0;
+	glMultiTexCoord3fARB  = 0;
+	glMultiTexCoord3fvARB = 0;
+
+	if(QueryExtension("GL_ARB_multitexture")){
+		cerr << "ARB multitexture is available!" << endl;
+		glActiveTexture =
+			(PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
+		glClientActiveTexture =
+			(PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
+		glMultiTexCoord1fARB =
+			(PFNGLMULTITEXCOORD1FARBPROC)wglGetProcAddress("glMultiTexCoord1fARB");
+		glMultiTexCoord1fvARB =
+			(PFNGLMULTITEXCOORD1FVARBPROC)wglGetProcAddress("glMultiTexCoord1fvARB");
+		glMultiTexCoord2fARB =
+			(PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");
+		glMultiTexCoord2fvARB =
+			(PFNGLMULTITEXCOORD2FVARBPROC)wglGetProcAddress("glMultiTexCoord2fvARB");
+		glMultiTexCoord3fARB =
+			(PFNGLMULTITEXCOORD3FARBPROC)wglGetProcAddress("glMultiTexCoord3fARB");
+		glMultiTexCoord3fvARB =
+			(PFNGLMULTITEXCOORD3FVARBPROC)wglGetProcAddress("glMultiTexCoord3fvARB");
+
+		if ((!glActiveTexture)||(!glClientActiveTexture)||(!glMultiTexCoord1fARB)||
+			(!glMultiTexCoord1fvARB)||(!glMultiTexCoord2fARB)||
+			(!glMultiTexCoord2fvARB)||(!glMultiTexCoord3fARB)||
+			(!glMultiTexCoord3fvARB)) {
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"glARBmultitexture\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "NOTE: You may need to get a new driver from ATI/NVIDIA" << endl;
+			cerr << (int) glActiveTexture << " " << (int)glClientActiveTexture << endl;
+			cerr << (int) glMultiTexCoord1fARB << " " << (int) glMultiTexCoord1fvARB << endl
+				 << (int) glMultiTexCoord2fARB << " " << (int) glMultiTexCoord2fvARB << endl
+				 << (int) glMultiTexCoord3fARB << " " << (int) glMultiTexCoord3fvARB << endl;
+			cerr << "*********************************" << endl;
+
+		}
+	} else cerr << "ARB multitexture texture is NOT available" << endl;
+#endif
+	//-------------------------------------------------------------------
+	//------------------- GL_ARB_texture_env_combine --------------------
+	if(QueryExtension("GL_ARB_texture_env_combine")){
+		cerr << "GL_ARB_texture_env_combine is available!" << endl;
+	} else cerr << "GL_ARB_texture_env_combine is NOT available" << endl;
+
+	//-------------------------------------------------------------------
+	//----------------- Secondary color ---------------------------------
+#ifdef GL_EXT_secondary_color
+	glSecondaryColor3fEXT = 0;
+	if(QueryExtension("GL_EXT_secondary_color")){
+		cerr << "Secondary Color is available!" << endl;
+		glSecondaryColor3fEXT =
+			(PFNGLSECONDARYCOLOR3FEXTPROC)wglGetProcAddress("glSecondaryColor3fEXT");
+		if(!glSecondaryColor3fEXT){
+			cerr << "Error aquiring Secondary Color function pointer" << endl;
+		}
+	} else {
+		cerr << "Secondary Color is not available" << endl;
+	}
+#endif
+
+}
+
+//=====================================================================
+//=====================================================================
+
+void getNV20()
+{
+#ifdef GL_NV_register_combiners
+	if(QueryExtension("GL_NV_register_combiners")){
+		cerr << "GL_NV_register_combiners is available!" << endl;
+		glCombinerParameterfvNV =
+			(PFNGLCOMBINERPARAMETERFVNVPROC)wglGetProcAddress("glCombinerParameterfvNV");
+		glCombinerParameterfNV =
+			(PFNGLCOMBINERPARAMETERFNVPROC)wglGetProcAddress("glCombinerParameterfNV");
+		glCombinerParameterivNV =
+			(PFNGLCOMBINERPARAMETERIVNVPROC)wglGetProcAddress("glCombinerParameterivNV");
+		glCombinerParameteriNV =
+			(PFNGLCOMBINERPARAMETERINVPROC)wglGetProcAddress("glCombinerParameteriNV");
+		glCombinerInputNV =
+			(PFNGLCOMBINERINPUTNVPROC)wglGetProcAddress("glCombinerInputNV");
+		glCombinerOutputNV =
+			(PFNGLCOMBINEROUTPUTNVPROC)wglGetProcAddress("glCombinerOutputNV");
+		glFinalCombinerInputNV =
+			(PFNGLFINALCOMBINERINPUTNVPROC)wglGetProcAddress("glFinalCombinerInputNV");
+		glGetCombinerInputParameterfvNV =
+			(PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)wglGetProcAddress("glGetCombinerInputParameterfvNV");
+		glGetCombinerInputParameterivNV =
+			(PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)wglGetProcAddress("glGetCombinerInputParameterivNV");
+		glGetCombinerOutputParameterfvNV =
+			(PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)wglGetProcAddress("glGetCombinerOutputParameterfvNV");
+		glGetCombinerOutputParameterivNV=
+			(PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)wglGetProcAddress("glGetCombinerOutputParameterivNV");
+		glGetFinalCombinerInputParameterfvNV =
+			(PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)wglGetProcAddress("glGetFinalCombinerInputParameterfvNV");
+		glGetFinalCombinerInputParameterivNV =
+			(PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)wglGetProcAddress("glGetFinalCombinerInputParameterivNV");
+		if(!glCombinerParameterfvNV){
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"GL_NV_register_combiners\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "*********************************" << endl;
+		}
+	} else cerr << "GL_NV_register_combiners is NOT available" << endl;
+
+#endif
+	//-------------------------------------------------------------------
+
+}
+
+//=====================================================================
+//=====================================================================
+
+void getATI8K()
+{
+#ifdef GL_ATIX_envmap_bumpmap
+	//------------------- GL_ATIX_envmap_bumpmap ------------------------
+	glTexBumpParameterivATIX = 0;
+	glTexBumpParameterfvATIX = 0;
+	glGetTexBumpParameterivATIX = 0;
+	glGetTexBumpParameterivATIX = 0;
+
+	if(QueryExtension("GL_ATIX_envmap_bumpmap")){
+		cerr << "GL_ATIX_envmap_bumpmap is available!" << endl;
+		glTexBumpParameterivATIX=
+			(PFNGLTEXBUMPPARAMETERIVATIXPROC)wglGetProcAddress("glTexBumpParameterivATIX");
+		glTexBumpParameterfvATIX=
+			(PFNGLTEXBUMPPARAMETERFVATIXPROC)wglGetProcAddress("glTexBumpParameterfvATIX");
+		glGetTexBumpParameterivATIX=
+			(PFNGLGETTEXBUMPPARAMETERIVATIXPROC)wglGetProcAddress("glGetTexBumpParameterivATIX");
+		glGetTexBumpParameterfvATIX=
+			(PFNGLGETTEXBUMPPARAMETERFVATIXPROC)wglGetProcAddress("glGetTexBumpParameterfvATIX");
+
+		if((!glTexBumpParameterivATIX)||(!glTexBumpParameterfvATIX)||
+			(!glGetTexBumpParameterivATIX)||(!glGetTexBumpParameterfvATIX)){
+			cerr << "*********************************" << endl;
+			cerr << "wglGetProcAddress(\"GL_ATIX_envmap_bumpmap\") failed!" << endl;
+			cerr << "GetLastError(): " << GetLastError() << endl;
+			cerr << "NOTE: You may need to get a new driver from ATI/NVIDIA" << endl;
+			cerr << (int)glTexBumpParameterivATIX  << " " << 	(int)glTexBumpParameterfvATIX << endl;
+			cerr << (int)glGetTexBumpParameterivATIX << " " << (int)glGetTexBumpParameterivATIX << endl;
+			cerr << "*********************************" << endl;
+		} else { //see what the capabilites are
+			int matsz;
+			glGetTexBumpParameterivATIX(GL_BUMP_ROT_MATRIX_SIZE_ATIX, &matsz);
+			cerr << "    -Bump rot matrix size = " << matsz << endl;
+			int numtex;
+			glGetTexBumpParameterivATIX(GL_BUMP_NUM_TEX_UNITS_ATIX, &numtex);
+			cerr << "    -Number of available texture units = " << numtex << endl;
+			int texunits[32];
+			glGetTexBumpParameterivATIX(GL_BUMP_TEX_UNITS_ATIX, texunits);
+			cerr << "    -Texture unit ids:" << endl;
+			for(int i=0; i<numtex; ++i){
+				if(texunits[i] == GL_TEXTURE0_ARB) cerr << "       GL_TEXTURE0_ARB" << endl;
+				if(texunits[i] == GL_TEXTURE1_ARB) cerr << "       GL_TEXTURE1_ARB" << endl;
+				if(texunits[i] == GL_TEXTURE2_ARB) cerr << "       GL_TEXTURE2_ARB" << endl;
+				if(texunits[i] == GL_TEXTURE3_ARB) cerr << "       GL_TEXTURE3_ARB" << endl;
+				if(texunits[i] == GL_TEXTURE4_ARB) cerr << "       GL_TEXTURE4_ARB" << endl;
+				if(texunits[i] == GL_TEXTURE5_ARB) cerr << "       GL_TEXTURE5_ARB" << endl;
+			}
+		}
+	} else  cerr << "GL_ATIX_envmap_bumpmap is NOT available!" << endl;
+#endif //end radeon
+
+#ifdef GL_ATI_fragment_shader
+	//------------------- GL_ATI_fragment_shader ------------------------
+	glGenFragmentShadersATI = 0;
+	glBindFragmentShaderATI = 0;
+	glDeleteFragmentShaderATI = 0;
+	glBeginFragmentShaderATI = 0;
+	glEndFragmentShaderATI = 0;
+	glPassTexCoordATI = 0;
+	glSampleMapATI = 0;
+	glColorFragmentOp1ATI = 0;
+	glColorFragmentOp2ATI = 0;
+	glColorFragmentOp3ATI = 0;
+	glAlphaFragmentOp1ATI = 0;
+	glAlphaFragmentOp2ATI = 0;
+	glAlphaFragmentOp3ATI = 0;
+	glSetFragmentShaderConstantATI = 0;
+
+	if(QueryExtension("GL_ATI_fragment_shader")){
+		cerr << "GL_ATI_fragment_shader is available" << endl;
+		glGenFragmentShadersATI =
+			(PFNGLGENFRAGMENTSHADERSATIPROC)wglGetProcAddress("glGenFragmentShadersATI");
+		glBindFragmentShaderATI =
+			(PFNGLBINDFRAGMENTSHADERATIPROC) wglGetProcAddress("glBindFragmentShaderATI");
+		glDeleteFragmentShaderATI=
+			(PFNGLDELETEFRAGMENTSHADERATIPROC) wglGetProcAddress("glDeleteFragmentShaderATI");
+		glBeginFragmentShaderATI =
+			(PFNGLBEGINFRAGMENTSHADERATIPROC)  wglGetProcAddress("glBeginFragmentShaderATI");
+		glEndFragmentShaderATI =
+			(PFNGLENDFRAGMENTSHADERATIPROC)    wglGetProcAddress("glEndFragmentShaderATI");
+		glPassTexCoordATI =
+			(PFNGLPASSTEXCOORDATIPROC)         wglGetProcAddress("glPassTexCoordATI");
+		glSampleMapATI =
+			(PFNGLSAMPLEMAPATIPROC)            wglGetProcAddress("glSampleMapATI");
+		glColorFragmentOp1ATI =
+			(PFNGLCOLORFRAGMENTOP1ATIPROC)     wglGetProcAddress("glColorFragmentOp1ATI");
+		glColorFragmentOp2ATI =
+			(PFNGLCOLORFRAGMENTOP2ATIPROC)     wglGetProcAddress("glColorFragmentOp2ATI");
+		glColorFragmentOp3ATI =
+			(PFNGLCOLORFRAGMENTOP3ATIPROC)     wglGetProcAddress("glColorFragmentOp3ATI");
+		glAlphaFragmentOp1ATI =
+			(PFNGLALPHAFRAGMENTOP1ATIPROC)     wglGetProcAddress("glAlphaFragmentOp1ATI");
+		glAlphaFragmentOp2ATI =
+			(PFNGLALPHAFRAGMENTOP2ATIPROC)     wglGetProcAddress("glAlphaFragmentOp2ATI");
+		glAlphaFragmentOp3ATI =
+			(PFNGLALPHAFRAGMENTOP3ATIPROC)     wglGetProcAddress("glAlphaFragmentOp3ATI");
+		glSetFragmentShaderConstantATI =
+			(PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) wglGetProcAddress("glSetFragmentShaderConstantATI");
+	} else {
+		cerr << "GL_ATI_fragment_shader is NOT available!" << endl;
+	}
+
+#endif
+
+}
+
+//=====================================================================
+//=====================================================================
+
+void getWGL()
+{
+#ifdef WGL_ARB_pbuffer
+	if((wglCreatePbufferARB =
+		  (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB"))){
+		cerr << "Pbuffer is available!" << endl;
+	}
+	else cerr << "Pbuffer is NOT available!" << endl;
+	wglGetPbufferDCARB =
+		(PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
+	wglReleasePbufferDCARB =
+		(PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
+	wglDestroyPbufferARB =
+		(PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
+	wglQueryPbufferARB =
+		(PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
+#endif
+
+#ifdef WGL_ARB_pixel_format
+	if((wglGetPixelFormatAttribivARB=
+		(PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB"))){
+		cerr << "WGL_ARB_pixel_format is available" << endl;
+	} else cerr << "WGL_ARB_pixel_format is NOT available" << endl;
+	wglGetPixelFormatAttribfvARB=
+		(PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
+	wglChoosePixelFormatARB=
+		(PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+#endif
+
+#ifdef WGL_ARB_render_texture //render to texture
+	if((wglBindTexImageARB=
+		(PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB"))){
+		cerr << "WGL_ARB_render_texture is available" << endl;
+	} else cerr << "WGL_ARB_render_texture is NOT available" << endl;
+	wglReleaseTexImageARB=
+		(PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
+	wglSetBufferAttribARB=
+		(PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetBufferAttribARB");
+#endif
+
+}
+
+
+#endif //ifdef WIN32
+
Index: trunk/src/testing/app/volvis/vProbe.cpp
===================================================================
--- trunk/src/testing/app/volvis/vProbe.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vProbe.cpp	(revision 4)
@@ -0,0 +1,101 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//implements a probe or a 3d pointer
+#include "vProbe.h"
+#include "VectorMath.h"    //usefull vector/matrix operations
+enum {SPHERE = 1, CONE};
+
+vProbe::vProbe() :vPrimitive() {
+	xform.scale = 1.0f/(float)global.volume->maxDim;
+}
+
+//do opngl initialization here
+void vProbe::init() {
+}
+
+vProbe::~vProbe() {
+}
+
+//draws the cone here
+void vProbe::draw()
+{
+	color[0] = 0.0f;
+	color[1] = 1.0f;
+	color[2] = 0.0f;
+	glPushMatrix();
+        glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
+	glTranslatef(xform.trans[0],xform.trans[1],xform.trans[2]);
+	glMultMatrixf(xform.rotn);
+	glutSolidSphere(xform.scale,20,20);
+        glPopAttrib();
+	glPopMatrix();
+	return;
+}
+
+//the pointer for the environment
+vPointer::vPointer() :vPrimitive() {
+	xform.scale = 0.02;
+}
+
+//do opngl initialization here
+void vPointer::init() {
+}
+
+vPointer::~vPointer() {
+}
+
+//draws the cone here
+void vPointer::draw()
+{
+	//update translation
+	xform.trans[0] = global.pointerPos[0];
+	xform.trans[1] = global.pointerPos[1];
+	xform.trans[2] = global.pointerPos[2];
+	color[0] = 0.25f;
+	color[1] = 0.5f;
+	color[2] = 0.5f;
+	glPushMatrix();
+        glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
+	glTranslatef(xform.trans[0],xform.trans[1],xform.trans[2]);
+	glMultMatrixf(xform.rotn);
+	glRotatef(180.0f,0.0f,1.0f,0.0f);
+	glutSolidCone(0.02, 0.1, 8, 8);
+        glPopAttrib();
+	glPopMatrix();
+	return;
+}
+
Index: trunk/src/testing/app/volvis/vFileVolume.cpp
===================================================================
--- trunk/src/testing/app/volvis/vFileVolume.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vFileVolume.cpp	(revision 4)
@@ -0,0 +1,267 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//temporarily commented for the demo
+#if 0
+//Class vFileVolume: Defines the 3D volume thats loaded from a file
+//This class only manages the data(doesnt do the rendering)
+//Shalini Venkataraman, Luc Renambot
+//Sep 7 2003
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "glUE.h"
+#include "vVolume.h"
+#include "VectorMath.h"
+#include "global.h"
+
+vFileVolume::vFileVolume(const char* fname, int c, int r, int d):vVolume(c,r,d) {
+	strcpy(this->filename,fname);
+	padY = padX = padZ =0;
+	filename[0] = '\0';
+	gradientFile = 0;
+	fileBuffer = 0;
+	//vVolume(c,r,d);
+}
+
+vFileVolume::~vFileVolume() {
+	if (gradientFile)
+		delete [] gradientFile;
+}
+
+
+void vFileVolume::load(int loadx, int loady, int loadz) {
+	setLoadDims(loadx,loady,loadz);
+	voxelData = new GLubyte[dimZ*dimY*dimX];
+	loadVolumeFromFile(filename);
+	if (gradientFile)
+		loadGradientFromFile(gradientFile);
+	else
+		calcGradient(); //create grad volume
+}
+
+void vFileVolume::loadVolumeFromFile(const char* filename){
+	int rc= mmap.setFilename(filename, 0);
+	cout << " == " << rc <<endl;
+	// Call mmap
+	fileBuffer= (unsigned char *)mmap.doMmap();
+	// Did the mapping work?
+	if((char*)fileBuffer== (char *)-1)
+	{
+		cerr << "mmap failed -- No memory :-( " << endl;
+		exit(1);
+	}
+
+	printf("Loading Volume %s\n",filename);
+	int filePlaneDims = fileX*fileY;//plane in a volume file
+	int planeDims = dimX*dimY; //plane in the volume that we want to load
+	GLubyte* plane = new GLubyte[planeDims];
+	padVolume(); //pad volume if necessary
+	//if we padded, just fill the dimesions in the file
+	int fillZ = padZ?fileZ:dimZ;
+	int fillY = padY?fileY:dimY;
+	int fillX = padX?fileX:dimX;
+	//if there is a dimZ to skip, skip it
+	unsigned char* curFilePtr = fileBuffer+filePlaneDims*offsetZ*sizeof(GLubyte);
+	//load the volume one plane at a time
+	for (int r=0;r<fillZ;r++) {
+		readASlice(plane,curFilePtr);
+		for (int t=0;t< fillY;t++) {
+			for (int s=0;s< fillX;s++) {
+				setValue(r+padZ,t+padY,s+padX,plane[(t*fillX+s)]);
+			}
+		}
+	}
+	printf("Loading Textures\n");
+	delete [] plane;
+}
+
+
+//if the volume is bigger than the file size, this will pad the volume
+//else do nothing
+void vFileVolume::padVolume() {
+	unsigned int r, s, t;
+	int lastSlice;
+	//pad a little with black if fileZ < dimZ
+	if (dimZ>fileZ) {
+		padZ = (dimZ-fileZ)/2;
+		lastSlice = (dimZ-padZ);
+		for (r=0;r<padZ;r++){
+			for (t=0;t<dimY;t++){
+				for (s=0;s<dimX;s++){
+					setValue(r,t,s,0);
+					setValue(r+lastSlice,t,s,0);
+				}
+			}
+		}
+	}
+	if (dimY>fileY) {
+		//pad a little with black if fileY doesnt match dimY
+		padY = (dimY-fileY)/2;
+		lastSlice = (dimY-padY);
+		for (r=0;r<dimZ;r++){
+			for (t=0;t<padY;t++){
+				for (s=0;s<dimX;s++){
+					setValue(r,t,s,0);
+					setValue(r,t+lastSlice,s,0);
+				}
+			}
+		}
+	}
+
+	if (dimX>fileX) {
+		//pad a little with black if fileX doesnt match dimX
+		padX = (dimX-fileX)/2;
+		lastSlice = (dimX-padX);
+		for (r=0;r<dimZ;r++){
+			for (t=0;t<dimY;t++){
+				for (s=0;s<padX;s++){
+					setValue(r,t,s,0);
+					setValue(r,t,s+lastSlice,0);
+				}
+			}
+		}
+	}
+}
+
+//reads a slice skipping the Y and X offsets
+void vFileVolume::readASlice(GLubyte* plane, unsigned char* &curFilePtr) {
+	//calculating the remaining rows and colums to skip once a sub image is read in
+        int remainingX = fileX-offsetX-dimX;
+	int remainingY = fileY-offsetY-dimY;
+
+	//skip the rows on one slice to start the read
+	curFilePtr += fileX*offsetY*sizeof(GLubyte);
+        GLubyte* volDataPtr = plane;
+        for (int i=0;i<dimY;i++) {
+		//skip the offset X
+		curFilePtr += offsetX*sizeof(GLubyte);
+		//read the sub-cols
+		memcpy(volDataPtr,curFilePtr,dimX);
+		//skip the cols read
+		curFilePtr += dimX*sizeof(GLubyte);
+		//skip the remaining cols
+		curFilePtr += remainingX*sizeof(GLubyte);
+                volDataPtr += dimX;//skip in the volume
+        }
+	//skip the remaining rows
+	curFilePtr += remainingY*fileX*sizeof(GLubyte);
+	fprintf(stderr,"ok here\n");
+}
+
+
+
+void vFileVolume::loadGradientFromFile(const char* filename) {
+	FILE* fp;
+	if (!(fp=fopen(filename,"rb"))) {
+		printf("Error: unable to open volume file %s\n",filename);
+		exit(0);
+	}
+	else
+		fprintf(stderr,"Opening file %s\n",filename);
+	int volSize = dimY*dimX*dimZ;
+	gradData = new unsigned char[volSize];
+	int numRead = fread(gradData,sizeof(unsigned char), volSize,fp);
+	if (numRead != volSize)
+		fprintf(stderr,"Error: gradient data size %d doesnt match volume size %d\n",numRead,volSize);
+	fclose(fp);
+}
+
+//calculate the value, gradient components of the volume
+//- may be needed by the transfer functions
+void vFileVolume::calcGradient()
+{
+	unsigned char *vdata = (unsigned char*)voxelData;
+	float *gradV3 = new float[dimX*dimY*dimZ*3]; //individual components of the gradient
+	float *gmag = new float[dimX*dimY*dimZ]; //gradient magnitude
+	float gmmax = -100000000;
+	float gmmin = 100000000;
+	float dmax = -100000000;
+	float dmin = 100000000;
+
+
+	//compute the gradient
+	cerr << "   computing 1st derivative";
+	int i;
+	for(i = 0; i < dimZ; ++i){
+		for(int j = 0; j < dimY; ++j){
+			for(int k = 0; k < dimX; ++k){
+				if((k<1)||(k>dimX-2)||(j<1)||(j>dimY-2)||(i<1)||(i>dimZ-2)){
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 0] = 0;
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 1] = 0;
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 2] = 0;
+					gmag[i*dimX*dimY + j*dimX + k] = 0;
+				}
+				else {
+					float dx = (float)(vdata[i*dimX*dimY + j*dimX + (k+1)]
+									- vdata[i*dimX*dimY + j*dimX + (k-1)]);
+					float dy = (float)(vdata[i*dimX*dimY + (j+1)*dimX + k]
+									- vdata[i*dimX*dimY + (j-1)*dimX + k]);
+					float dz = (float)(vdata[(i+1)*dimX*dimY + j*dimX + k]
+									- vdata[(i-1)*dimX*dimY + j*dimX + k]);
+
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 0] = dx;
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 1] = dy;
+					gradV3[i*dimX*dimY*3 + j*dimX*3 + k*3 + 2] = dz;
+					gmag[i*dimX*dimY + j*dimX + k] = (float)sqrt(dx*dx+dy*dy+dz*dz);
+					gmmax = MAX(gmag[i*dimX*dimY + j*dimX + k], gmmax);
+					gmmin = MIN(gmag[i*dimX*dimY + j*dimX + k], gmmin);
+					dmax = MAX(vdata[i*dimX*dimY + j*dimX +k], dmax);
+					dmin = MIN(vdata[i*dimX*dimY + j*dimX +k], dmin);
+				}
+			}
+		}
+	}
+	cerr << " - done" << endl;
+	cerr << "   quantizing";
+	gradData = new unsigned char[dimX*dimY*dimZ]; //stores the 1st derivative
+
+	for(i = 0; i < dimZ; ++i){
+		for(int j = 0; j < (dimY); ++j){
+			for(int k = 0; k < (dimX); ++k){
+				if((k<1)||(k>dimX-2)||(j<1)||(j>dimY-2)||(i<1)||(i>dimZ-2)){
+					gradData[i*dimX*dimY + j*dimX + k] = 0;
+				}
+				else {
+					gradData[i*dimX*dimY + j*dimX + k] = (unsigned char)affine(gmmin, gmag[i*dimX*dimY + j*dimX + k], gmmax, 0, 255);
+				}
+			}
+		}
+	}
+	cerr << " - done" << endl;
+	delete [] gradV3;
+	delete [] gmag;
+}
+#endif
Index: trunk/src/testing/app/volvis/vVolume.cpp
===================================================================
--- trunk/src/testing/app/volvis/vVolume.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vVolume.cpp	(revision 4)
@@ -0,0 +1,196 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//Class vVolume: Defines the 3D volume and the associated operations
+//the inherited class should override the load/roam function
+//This class only manages the data(doesnt do the rendering)
+//Shalini Venkataraman, Luc Renambot
+//Sep 7 2003
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "glUE.h"
+#include "vVolume.h"
+#include "VectorMath.h"
+#include "global.h"
+
+//constructor
+vVolume::vVolume(int x, int y, int z) {
+	fileY = y;
+	fileX = x;
+	fileZ = z;
+	dimY = dimX = dimZ = maxDim = 128;
+	offsetX  = offsetY = offsetZ = 0;
+	spacingX  = spacingY = spacingZ = 1.0f;
+	probeX = probeY = probeZ = 0;
+	curVolume = numVolumes = 0;
+	probeValue = 0;
+	isoValue = 128;
+}
+
+//destructor
+vVolume::~vVolume() {
+	for (int i=0;i<cache.size();i++) {
+		delete [] cache[i].voxelData;
+		//delete [] cache[i].gradData;
+		delete [] cache[i].hist;
+	}
+}
+
+void vVolume::setLoadDims(int x, int y, int z) {
+	//now get the power of 2
+	dimY = makepow2_max(y);
+	dimX = makepow2_max(x);
+	dimZ = makepow2_max(z);
+	maxDim = dimY;
+	maxDim = MAX(dimY,dimX);
+	maxDim = MAX(maxDim,dimZ);
+	probeX = dimX/2;
+	probeY = dimY/2;
+	probeZ = dimZ/2;
+}
+
+void vVolume::probe(int dx, int dy, int dz) {
+	//calculate new probe(cos the orig offset is unsigned..)
+	int newProbeX = probeX + dx;
+	int newProbeY = probeY + dy;
+	int newProbeZ = probeZ + dz;
+	if (newProbeX== dimX)
+		newProbeX = dimX-1;
+	if (newProbeY== dimY)
+		newProbeY = dimY-1;
+	if (newProbeZ== dimZ)
+		newProbeZ = dimZ-1;
+
+	if (newProbeX < 0)
+		newProbeX = 0;
+	if (newProbeY < 0)
+		newProbeY = 0;
+	if (newProbeZ < 0)
+		newProbeZ = 0;
+	//copy to the offset
+	probeX = newProbeX;
+	probeY = newProbeY;
+	probeZ = newProbeZ;
+	probeValue = getValue(probeZ, probeY, probeX);
+}
+
+
+int vVolume::hist2D(unsigned char *normHist)
+{
+	float *hist = new float[H2D_DIM];
+	int i;
+	for(i=0; i<H2D_DIM; ++i){
+		hist[i] = 0;
+	}
+
+	for(i=0; i<dimZ; ++i){
+		for(int j=0; j<dimY; ++j){
+			for(int k=0; k<dimX; ++k){
+				int vox = i*dimX*dimY + j*dimX + k;
+				hist[cache[curVolume].voxelData[vox] + cache[curVolume].gradData[vox]*256] += 1;
+			}
+		}
+	}
+
+	float max = 0;
+	for(i = 0; i< H2D_DIM; ++i){
+		hist[i] = (float)log(hist[i]);
+		max = MAX(hist[i], max);
+	}
+	for(i=0; i< H2D_DIM; ++i){
+		normHist[i] = (unsigned char)(hist[i]/(float)max*255);
+	}
+	delete[] hist;
+	return 1;
+}
+
+int vVolume::hist1D(unsigned char *normHist)
+{
+	float *hist = new float[H2D_DIM];
+	int i;
+	for(i=0; i<H2D_DIM; ++i){
+		hist[i] = 0;
+	}
+
+	for(i=0; i<dimZ; ++i){
+		for(int j=0; j<dimY; ++j){
+			for(int k=0; k<dimX; ++k){
+				int vox = i*dimX*dimY + j*dimX + k;
+				for (int row = 0;row<256;row++)
+					hist[cache[curVolume].voxelData[vox]+row*256] += 1;
+			}
+		}
+	}
+
+	float max = 0;
+	for(i = 0; i< H2D_DIM; ++i){
+	//	hist[i] = (float)log(hist[i]);
+		max = MAX(hist[i], max);
+	}
+	for(i=0; i< H2D_DIM; ++i){
+		normHist[i] = (unsigned char)(hist[i]/(float)max*255);
+	}
+	delete[] hist;
+	return 1;
+}
+
+void vVolume::saveVolume(const char* prefix) {
+	FILE* fp;
+	char filename[256];
+	sprintf(filename,"%s%dx%dx%d.raw",prefix,dimX,dimY,dimZ);
+	if( (fp = fopen(filename, "wb" )) != NULL ) {
+		int numwritten = fwrite(cache[curVolume].voxelData, sizeof(GLubyte), dimY*dimX*dimZ, fp );
+		printf( "vVolume::saveVolume: Wrote %d bytes to file %s\n", numwritten, filename);
+		fclose( fp );
+	}
+	else
+		printf( "vVolume::saveVolume: Problem opening the file\n" );
+}
+
+void vVolume::saveGradient(const char* prefix) {
+        FILE* fp;
+        char filename[256];
+        sprintf(filename,"%s%dx%dx%d.raw",prefix,dimX,dimY,dimZ);
+        if( (fp = fopen(filename, "wb" )) != NULL ) {
+                int numwritten = fwrite(cache[curVolume].gradData, sizeof(unsigned char), dimY*dimX*dimZ, fp );
+                printf( "saveGradient: Wrote %d bytes to file %s\n", numwritten, filename);
+                fclose( fp );
+        }
+        else
+                printf( "saveGradient: Problem opening the file\n" );
+}
+
+
Index: trunk/src/testing/app/volvis/onlyonemachine.dat
===================================================================
--- trunk/src/testing/app/volvis/onlyonemachine.dat	(revision 4)
+++ trunk/src/testing/app/volvis/onlyonemachine.dat	(revision 4)
@@ -0,0 +1,2 @@
+0 localhost
+1 localhost
Index: trunk/src/testing/app/volvis/vTF.cpp
===================================================================
--- trunk/src/testing/app/volvis/vTF.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vTF.cpp	(revision 4)
@@ -0,0 +1,181 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifdef V_NETTF
+#include "vTF.h"
+#include "vUI.h"
+#include "global.h"
+#include <string.h>
+
+//send the UI events to the network.
+//Checks if there is a new tcp client that has connected in
+//Add that to the image list
+void* netThreadCB(void* data) {
+	vTF* tf = (vTF*)data;
+	while(1) {
+		tf->process();
+		QUANTAusleep(100);
+	}
+}
+
+vTF::vTF()
+{
+	tcpServer = 0;
+	tcpClient = 0;
+}
+
+vTF::~vTF() {
+	tcpClient->close();
+	tcpServer->close();
+}
+
+void vTF::init()
+{
+	//quanta stuff
+//	QUANTAinit();
+	//create a TCP server that gets the image data
+	tcpServer= new QUANTAnet_tcpServer_c;
+	if (tcpServer->init(7352) == 0)    {
+		exit(1);
+	}
+	QUANTAts_thread_c *networkListenerThread = new QUANTAts_thread_c;
+	networkListenerThread->create(netThreadCB, (void*) this);
+}
+
+void vTF::checkForConnections() {
+	QUANTAnet_tcpClient_c* newClient = tcpServer->checkForNewConnections(0);
+	if (newClient) { //new client is connecting
+		if (tcpClient) { //if an old client already exists
+			fprintf(stderr,"Deleting Old client\n");
+			tcpClient->close(); //close the old client
+			delete tcpClient; //deallocate it
+		}
+		tcpClient = newClient;
+		tcpClient->getRemoteIP(clientIP);
+		fprintf(stderr,"New Client %s connected at port %u \n", clientIP, tcpClient->getSelfPort());
+	}
+}
+#define HISTSIZE 256*256
+void vTF::sendHistogram() {
+	unsigned char histogram[HISTSIZE];
+	int haveHist = global.volume->hist2D(histogram);
+	int size;
+
+	//fprintf(stderr,"Going to send update histogram %d\n",haveHist);
+	//writing whether we need to update the histogram
+	size = sizeof(int);
+	tcpClient->setSockOptions(QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE, size);
+	int status = tcpClient->write((char*)&haveHist, &size, QUANTAnet_tcpClient_c::BLOCKING);
+	//fprintf(stderr,"Sinished send update histogram %d\n",haveHist);
+	if (status != QUANTAnet_tcpClient_c::OK)
+		tcpClient->showStatus(status, size);
+#ifdef SHOW_STATS
+	tcpClient->showStats("After sending update histogram"," ");
+#endif
+	if (haveHist) { //if we have to update the hist, send the histogram
+		size = HISTSIZE*sizeof(unsigned char);
+		tcpClient->setSockOptions(QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE, size);
+		int status = tcpClient->write((char*)histogram, &size, QUANTAnet_tcpClient_c::BLOCKING);
+		if (status != QUANTAnet_tcpClient_c::OK)
+			tcpClient->showStatus(status, size);
+		else {
+		//	fprintf(stderr,"vTF::sendHistogram: have Hist and finished sending\n");
+		}
+#ifdef SHOW_STATS
+		tcpClient->showStats("After sending histogram"," ");
+#endif
+	}
+
+}
+
+void vTF::process() {
+	checkForConnections();
+	//now read from client
+	if (tcpClient) {
+		//fprintf(stderr,"Going to send hist and read from client\n");
+		//send histogram
+		sendHistogram();
+		int haveLUT;
+		//read if there is LUT
+		int dataSize = sizeof(int);
+		tcpClient->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, dataSize);
+		int status = tcpClient->read((char*)&haveLUT, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+		if (status == QUANTAnet_tcpClient_c::OK)  {
+			//fprintf(stderr,"Reading Have LUT %d \n",haveLUT);
+		}
+		else if (status != QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA) {
+			fprintf(stderr,"Error while Reading Have LUT \n");
+			tcpClient->showStatus(status, dataSize);
+			//conection close just close the client
+			tcpClient->close();
+			delete tcpClient;
+			tcpClient = 0;
+		}
+#ifdef SHOW_STATS
+		tcpClient->showStats("After receive"," ");
+#endif
+		if (haveLUT) {
+		//fprintf(stderr,"New LUT:Trying to read\n");
+		//set buffer size to the network data size
+		int dataSize = 256*4*sizeof(char)+sizeof(int);
+		char* netBuffer= new char[dataSize];
+		tcpClient->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, dataSize);
+		int status = tcpClient->read(netBuffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+		//fprintf(stderr,"Reading LUT %d bytes\n",dataSize);
+		if (status == QUANTAnet_tcpClient_c::OK)  {
+			setLUT(dataSize,(unsigned char*)netBuffer);
+			//fprintf(stderr,"Got LUT %d bytes\n",dataSize);
+		}
+		else if (status != QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA) {
+			fprintf(stderr,"Connection close with client %s\n", clientIP);
+			tcpClient->showStatus(status, dataSize);
+			//conection close just close the client
+			tcpClient->close();
+			delete tcpClient;
+			tcpClient = 0;
+		}
+#ifdef SHOW_STATS
+		tcpClient->showStats("After receive"," ");
+#endif
+		delete [] netBuffer;
+		}
+		else {
+		//	fprintf(stderr,"No LUT received\n");
+		}
+
+	}
+
+}
+
+#endif
Index: trunk/src/testing/app/volvis/optiYorda.dat
===================================================================
--- trunk/src/testing/app/volvis/optiYorda.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiYorda.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 192.168.81.120
+1 192.168.81.121
+2 192.168.81.122
+3 192.168.81.123
+4 192.168.81.124
+5 192.168.81.125
+6 192.168.81.126
+7 192.168.81.127
+8 192.168.81.128
Index: trunk/src/testing/app/volvis/vRenderer.h
===================================================================
--- trunk/src/testing/app/volvis/vRenderer.h	(revision 4)
+++ trunk/src/testing/app/volvis/vRenderer.h	(revision 4)
@@ -0,0 +1,124 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _VRENDERER_H
+#define _VRENDERER_H
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "global.h"
+#include "vVolume.h"
+#include "vCut.h"
+#include "vPrimitive.h"
+#include "vSliceView.h"
+#define depX 256
+#define depY 256
+class vRenderer :public vPrimitive
+{
+public:
+	vRenderer();
+	virtual ~vRenderer();
+	//the volume to render
+	void setVolume(vVolume* theVolume) {
+		myVolume = theVolume;
+	}
+
+	void init();          //primitive call-back
+	void draw();          //primitive call-back
+	void update();		//update the variables here - called every loop
+	int select() ;
+	inline void enableCut() {
+		cutEnabled = true;
+	}
+
+	inline void disableCut() {
+		cutEnabled = false;
+	}
+	inline void enableShowOverview() {
+		showOverview = true;
+	}
+
+	inline void disableShowOverview() {
+		showOverview = false;
+	}
+	void prev();
+	void next();
+
+private:
+	//loads the buffer to the texture mem
+	void loadTexture3D(unsigned char *tex, int sx, int sy, int sz);
+	//draw the bounding box
+	void drawBoundBox();
+	//draw the bounding box for the subvolume if any
+	void drawSubvolBoundBox();
+	//draws the 3 orthogonal slice views
+	void drawSliceView();
+	void renderAll();     //renders 3d texture, slice views, clip plane, bound box etc
+
+
+	//generic slice allong axis volume renderer
+	void renderTexture3D(float sampleFrequency,
+		              GLdouble mv[16],  //Model View Matrix
+		              float vo[8][3],	  //volume vertex coords model-space coords
+		              float tx[8][3],	  //texture vertex coords tex-space coords
+		              float axis[3]);	  //axis to slice along world-space coords
+	//to render one slice -called in the loop from renderTexture3D
+	inline void renderSlice(int edges, float tc[6][3],float pc[6][3],int   order[6]);
+	//does the intersection between a slice plane and the texture3D
+	inline int intersect(const float p0[3], const float p1[3], //line end points
+		     const float t0[3], const float t1[3], //texture points
+		     const float v0[3], const float v1[3], //view coord points
+		     const float sp[3], const float sn[3], //plane point & norm
+		     float pnew[3], float tnew[3], float vnew[3]); //new values
+
+	//Dependant texture related functions
+	//loads a dependant texture(interactive or good) for CG to handle the map
+	void loadDepTex(unsigned int deptexName, unsigned char *dtex);
+	//takes the data from the 2d texture sent from the UI and copies it to the dependant texture(1D)
+	//that will be passed to CG
+	//For now, just extract the first row of the UI 2d texture to the dependant texture
+	//scale the alpha values depending on the sample rate
+	void copyScale(float sampleRate, unsigned char *cgTex);
+
+	//---------------------member variables--------------
+	vVolume*	myVolume; //pointer to the volume Im supposed to render
+	vCut cut;			//cutting plane
+	vProbe volProbe;		//probe for the volume
+	float xptr, yptr, zptr;		//location of the probe in the volume
+	bool cutEnabled;	//whether cutplane is enabled
+	bool showOverview; //show the subvolumes that are rendered
+};
+
+#endif
Index: trunk/src/testing/app/volvis/directions.cpp
===================================================================
--- trunk/src/testing/app/volvis/directions.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/directions.cpp	(revision 4)
@@ -0,0 +1,16726 @@
+/******************************************************************************
+ * OptiStore - A Data Processing Server
+ * Copyright (C) 2003 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * Authors: Luc Renambot luc@evl.uic.edu
+ *          Shalini Venkataraman shalini@evl.uic.edu
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about OptiStore to luc@evl.uic.edu
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define NUM_DIRECTIONS 16643
+
+static float *val_dir = NULL;
+
+void GetDirection(int idx, float *x, float *y, float *z)
+{
+	*x = val_dir[idx*3 + 0];
+	*y = val_dir[idx*3 + 1];
+	*z = val_dir[idx*3 + 2];
+}
+
+float *ConvertDirections(int sx,int sy,int sz,unsigned short *data)
+{
+	float *good, x, y, z;
+
+	good = (float*)malloc(sx*sy*sz*sizeof(float)*3);
+	memset(good, 0, sx*sy*sz*sizeof(float)*3);
+
+	for (int i=0;i<sx*sy*sz;i++)
+	{
+		unsigned short val = data[i];
+		GetDirection(val, &x,&y,&z);
+		good[ i*3 + 0 ] = x;
+		good[ i*3 + 1 ] = y;
+		good[ i*3 + 2 ] = z;
+	}
+
+	return good;
+}
+
+
+void InitDirectionsTable()
+{
+	if (val_dir == NULL)
+	{
+		val_dir = (float*)malloc( NUM_DIRECTIONS * sizeof(float) * 3);
+		assert (val_dir != NULL);
+		memset(val_dir, 0,  NUM_DIRECTIONS * sizeof(float) * 3);
+
+        val_dir[0*3 + 0] = 0.0f;	val_dir[0*3 + 1] = -1.0f;	val_dir[0*3 + 2] = 0.0f;
+        val_dir[1*3 + 0] = 0.015871f;	val_dir[1*3 + 1] = -0.999874f;	val_dir[1*3 + 2] = 0.0f;
+        val_dir[2*3 + 0] = 0.032241f;	val_dir[2*3 + 1] = -0.999480f;	val_dir[2*3 + 2] = 0.0f;
+        val_dir[3*3 + 0] = 0.049121f;	val_dir[3*3 + 1] = -0.998793f;	val_dir[3*3 + 2] = 0.0f;
+        val_dir[4*3 + 0] = 0.066519f;	val_dir[4*3 + 1] = -0.997785f;	val_dir[4*3 + 2] = 0.0f;
+        val_dir[5*3 + 0] = 0.084443f;	val_dir[5*3 + 1] = -0.996428f;	val_dir[5*3 + 2] = 0.0f;
+        val_dir[6*3 + 0] = 0.102899f;	val_dir[6*3 + 1] = -0.994692f;	val_dir[6*3 + 2] = 0.0f;
+        val_dir[7*3 + 0] = 0.121891f;	val_dir[7*3 + 1] = -0.992543f;	val_dir[7*3 + 2] = 0.0f;
+        val_dir[8*3 + 0] = 0.141421f;	val_dir[8*3 + 1] = -0.989949f;	val_dir[8*3 + 2] = 0.0f;
+        val_dir[9*3 + 0] = 0.161489f;	val_dir[9*3 + 1] = -0.986875f;	val_dir[9*3 + 2] = 0.0f;
+        val_dir[10*3 + 0] = 0.182089f;	val_dir[10*3 + 1] = -0.983282f;	val_dir[10*3 + 2] = 0.0f;
+        val_dir[11*3 + 0] = 0.203216f;	val_dir[11*3 + 1] = -0.979134f;	val_dir[11*3 + 2] = 0.0f;
+        val_dir[12*3 + 0] = 0.224860f;	val_dir[12*3 + 1] = -0.974391f;	val_dir[12*3 + 2] = 0.0f;
+        val_dir[13*3 + 0] = 0.247004f;	val_dir[13*3 + 1] = -0.969015f;	val_dir[13*3 + 2] = 0.0f;
+        val_dir[14*3 + 0] = 0.269630f;	val_dir[14*3 + 1] = -0.962964f;	val_dir[14*3 + 2] = 0.0f;
+        val_dir[15*3 + 0] = 0.292714f;	val_dir[15*3 + 1] = -0.95620f;	val_dir[15*3 + 2] = 0.0f;
+        val_dir[16*3 + 0] = 0.316228f;	val_dir[16*3 + 1] = -0.948683f;	val_dir[16*3 + 2] = 0.0f;
+        val_dir[17*3 + 0] = 0.340136f;	val_dir[17*3 + 1] = -0.940376f;	val_dir[17*3 + 2] = 0.0f;
+        val_dir[18*3 + 0] = 0.364399f;	val_dir[18*3 + 1] = -0.931243f;	val_dir[18*3 + 2] = 0.0f;
+        val_dir[19*3 + 0] = 0.388972f;	val_dir[19*3 + 1] = -0.921250f;	val_dir[19*3 + 2] = 0.0f;
+        val_dir[20*3 + 0] = 0.413803f;	val_dir[20*3 + 1] = -0.910366f;	val_dir[20*3 + 2] = 0.0f;
+        val_dir[21*3 + 0] = 0.438835f;	val_dir[21*3 + 1] = -0.898567f;	val_dir[21*3 + 2] = 0.0f;
+        val_dir[22*3 + 0] = 0.464007f;	val_dir[22*3 + 1] = -0.885832f;	val_dir[22*3 + 2] = 0.0f;
+        val_dir[23*3 + 0] = 0.489251f;	val_dir[23*3 + 1] = -0.872143f;	val_dir[23*3 + 2] = 0.0f;
+        val_dir[24*3 + 0] = 0.514496f;	val_dir[24*3 + 1] = -0.857493f;	val_dir[24*3 + 2] = 0.0f;
+        val_dir[25*3 + 0] = 0.539666f;	val_dir[25*3 + 1] = -0.841879f;	val_dir[25*3 + 2] = 0.0f;
+        val_dir[26*3 + 0] = 0.564684f;	val_dir[26*3 + 1] = -0.825307f;	val_dir[26*3 + 2] = 0.0f;
+        val_dir[27*3 + 0] = 0.589469f;	val_dir[27*3 + 1] = -0.807791f;	val_dir[27*3 + 2] = 0.0f;
+        val_dir[28*3 + 0] = 0.613941f;	val_dir[28*3 + 1] = -0.789352f;	val_dir[28*3 + 2] = 0.0f;
+        val_dir[29*3 + 0] = 0.638018f;	val_dir[29*3 + 1] = -0.770022f;	val_dir[29*3 + 2] = 0.0f;
+        val_dir[30*3 + 0] = 0.661622f;	val_dir[30*3 + 1] = -0.749838f;	val_dir[30*3 + 2] = 0.0f;
+        val_dir[31*3 + 0] = 0.684675f;	val_dir[31*3 + 1] = -0.728848f;	val_dir[31*3 + 2] = 0.0f;
+        val_dir[32*3 + 0] = 0.707107f;	val_dir[32*3 + 1] = -0.707107f;	val_dir[32*3 + 2] = 0.0f;
+        val_dir[33*3 + 0] = 0.728848f;	val_dir[33*3 + 1] = -0.684675f;	val_dir[33*3 + 2] = 0.0f;
+        val_dir[34*3 + 0] = 0.749838f;	val_dir[34*3 + 1] = -0.661622f;	val_dir[34*3 + 2] = 0.0f;
+        val_dir[35*3 + 0] = 0.770022f;	val_dir[35*3 + 1] = -0.638018f;	val_dir[35*3 + 2] = 0.0f;
+        val_dir[36*3 + 0] = 0.789352f;	val_dir[36*3 + 1] = -0.613941f;	val_dir[36*3 + 2] = 0.0f;
+        val_dir[37*3 + 0] = 0.807791f;	val_dir[37*3 + 1] = -0.589469f;	val_dir[37*3 + 2] = 0.0f;
+        val_dir[38*3 + 0] = 0.825307f;	val_dir[38*3 + 1] = -0.564684f;	val_dir[38*3 + 2] = 0.0f;
+        val_dir[39*3 + 0] = 0.841879f;	val_dir[39*3 + 1] = -0.539666f;	val_dir[39*3 + 2] = 0.0f;
+        val_dir[40*3 + 0] = 0.857493f;	val_dir[40*3 + 1] = -0.514496f;	val_dir[40*3 + 2] = 0.0f;
+        val_dir[41*3 + 0] = 0.872143f;	val_dir[41*3 + 1] = -0.489251f;	val_dir[41*3 + 2] = 0.0f;
+        val_dir[42*3 + 0] = 0.885832f;	val_dir[42*3 + 1] = -0.464007f;	val_dir[42*3 + 2] = 0.0f;
+        val_dir[43*3 + 0] = 0.898567f;	val_dir[43*3 + 1] = -0.438835f;	val_dir[43*3 + 2] = 0.0f;
+        val_dir[44*3 + 0] = 0.910366f;	val_dir[44*3 + 1] = -0.413803f;	val_dir[44*3 + 2] = 0.0f;
+        val_dir[45*3 + 0] = 0.921250f;	val_dir[45*3 + 1] = -0.388972f;	val_dir[45*3 + 2] = 0.0f;
+        val_dir[46*3 + 0] = 0.931243f;	val_dir[46*3 + 1] = -0.364399f;	val_dir[46*3 + 2] = 0.0f;
+        val_dir[47*3 + 0] = 0.940376f;	val_dir[47*3 + 1] = -0.340136f;	val_dir[47*3 + 2] = 0.0f;
+        val_dir[48*3 + 0] = 0.948683f;	val_dir[48*3 + 1] = -0.316228f;	val_dir[48*3 + 2] = 0.0f;
+        val_dir[49*3 + 0] = 0.95620f;	val_dir[49*3 + 1] = -0.292714f;	val_dir[49*3 + 2] = 0.0f;
+        val_dir[50*3 + 0] = 0.962964f;	val_dir[50*3 + 1] = -0.269630f;	val_dir[50*3 + 2] = 0.0f;
+        val_dir[51*3 + 0] = 0.969015f;	val_dir[51*3 + 1] = -0.247004f;	val_dir[51*3 + 2] = 0.0f;
+        val_dir[52*3 + 0] = 0.974391f;	val_dir[52*3 + 1] = -0.224860f;	val_dir[52*3 + 2] = 0.0f;
+        val_dir[53*3 + 0] = 0.979134f;	val_dir[53*3 + 1] = -0.203216f;	val_dir[53*3 + 2] = 0.0f;
+        val_dir[54*3 + 0] = 0.983282f;	val_dir[54*3 + 1] = -0.182089f;	val_dir[54*3 + 2] = 0.0f;
+        val_dir[55*3 + 0] = 0.986875f;	val_dir[55*3 + 1] = -0.161489f;	val_dir[55*3 + 2] = 0.0f;
+        val_dir[56*3 + 0] = 0.989949f;	val_dir[56*3 + 1] = -0.141421f;	val_dir[56*3 + 2] = 0.0f;
+        val_dir[57*3 + 0] = 0.992543f;	val_dir[57*3 + 1] = -0.121891f;	val_dir[57*3 + 2] = 0.0f;
+        val_dir[58*3 + 0] = 0.994692f;	val_dir[58*3 + 1] = -0.102899f;	val_dir[58*3 + 2] = 0.0f;
+        val_dir[59*3 + 0] = 0.996428f;	val_dir[59*3 + 1] = -0.084443f;	val_dir[59*3 + 2] = 0.0f;
+        val_dir[60*3 + 0] = 0.997785f;	val_dir[60*3 + 1] = -0.066519f;	val_dir[60*3 + 2] = 0.0f;
+        val_dir[61*3 + 0] = 0.998793f;	val_dir[61*3 + 1] = -0.049121f;	val_dir[61*3 + 2] = 0.0f;
+        val_dir[62*3 + 0] = 0.999480f;	val_dir[62*3 + 1] = -0.032241f;	val_dir[62*3 + 2] = 0.0f;
+        val_dir[63*3 + 0] = 0.999874f;	val_dir[63*3 + 1] = -0.015871f;	val_dir[63*3 + 2] = 0.0f;
+        val_dir[64*3 + 0] = 1.0f;	val_dir[64*3 + 1] = 0.0f;	val_dir[64*3 + 2] = 0.0f;
+        val_dir[65*3 + 0] = 0.0f;	val_dir[65*3 + 1] = -0.999874f;	val_dir[65*3 + 2] = 0.015871f;
+        val_dir[66*3 + 0] = 0.016125f;	val_dir[66*3 + 1] = -0.999740f;	val_dir[66*3 + 2] = 0.016125f;
+        val_dir[67*3 + 0] = 0.032765f;	val_dir[67*3 + 1] = -0.999329f;	val_dir[67*3 + 2] = 0.016382f;
+        val_dir[68*3 + 0] = 0.049931f;	val_dir[68*3 + 1] = -0.998614f;	val_dir[68*3 + 2] = 0.016644f;
+        val_dir[69*3 + 0] = 0.067632f;	val_dir[69*3 + 1] = -0.997567f;	val_dir[69*3 + 2] = 0.016908f;
+        val_dir[70*3 + 0] = 0.085876f;	val_dir[70*3 + 1] = -0.996158f;	val_dir[70*3 + 2] = 0.017175f;
+        val_dir[71*3 + 0] = 0.104669f;	val_dir[71*3 + 1] = -0.994354f;	val_dir[71*3 + 2] = 0.017445f;
+        val_dir[72*3 + 0] = 0.124015f;	val_dir[72*3 + 1] = -0.992122f;	val_dir[72*3 + 2] = 0.017716f;
+        val_dir[73*3 + 0] = 0.143917f;	val_dir[73*3 + 1] = -0.989426f;	val_dir[73*3 + 2] = 0.017990f;
+        val_dir[74*3 + 0] = 0.164372f;	val_dir[74*3 + 1] = -0.986229f;	val_dir[74*3 + 2] = 0.018264f;
+        val_dir[75*3 + 0] = 0.185376f;	val_dir[75*3 + 1] = -0.982493f;	val_dir[75*3 + 2] = 0.018538f;
+        val_dir[76*3 + 0] = 0.206922f;	val_dir[76*3 + 1] = -0.978177f;	val_dir[76*3 + 2] = 0.018811f;
+        val_dir[77*3 + 0] = 0.228998f;	val_dir[77*3 + 1] = -0.973240f;	val_dir[77*3 + 2] = 0.019083f;
+        val_dir[78*3 + 0] = 0.251587f;	val_dir[78*3 + 1] = -0.967641f;	val_dir[78*3 + 2] = 0.019353f;
+        val_dir[79*3 + 0] = 0.274668f;	val_dir[79*3 + 1] = -0.961339f;	val_dir[79*3 + 2] = 0.019619f;
+        val_dir[80*3 + 0] = 0.298216f;	val_dir[80*3 + 1] = -0.954291f;	val_dir[80*3 + 2] = 0.019881f;
+        val_dir[81*3 + 0] = 0.322198f;	val_dir[81*3 + 1] = -0.946458f;	val_dir[81*3 + 2] = 0.020137f;
+        val_dir[82*3 + 0] = 0.346578f;	val_dir[82*3 + 1] = -0.93780f;	val_dir[82*3 + 2] = 0.020387f;
+        val_dir[83*3 + 0] = 0.371312f;	val_dir[83*3 + 1] = -0.928279f;	val_dir[83*3 + 2] = 0.020628f;
+        val_dir[84*3 + 0] = 0.396350f;	val_dir[84*3 + 1] = -0.917863f;	val_dir[84*3 + 2] = 0.020861f;
+        val_dir[85*3 + 0] = 0.421637f;	val_dir[85*3 + 1] = -0.906520f;	val_dir[85*3 + 2] = 0.021082f;
+        val_dir[86*3 + 0] = 0.447112f;	val_dir[86*3 + 1] = -0.894224f;	val_dir[86*3 + 2] = 0.021291f;
+        val_dir[87*3 + 0] = 0.472709f;	val_dir[87*3 + 1] = -0.880957f;	val_dir[87*3 + 2] = 0.021487f;
+        val_dir[88*3 + 0] = 0.498354f;	val_dir[88*3 + 1] = -0.866703f;	val_dir[88*3 + 2] = 0.021668f;
+        val_dir[89*3 + 0] = 0.523973f;	val_dir[89*3 + 1] = -0.851455f;	val_dir[89*3 + 2] = 0.021832f;
+        val_dir[90*3 + 0] = 0.549484f;	val_dir[90*3 + 1] = -0.835215f;	val_dir[90*3 + 2] = 0.021979f;
+        val_dir[91*3 + 0] = 0.574805f;	val_dir[91*3 + 1] = -0.817992f;	val_dir[91*3 + 2] = 0.022108f;
+        val_dir[92*3 + 0] = 0.599852f;	val_dir[92*3 + 1] = -0.799803f;	val_dir[92*3 + 2] = 0.022217f;
+        val_dir[93*3 + 0] = 0.624540f;	val_dir[93*3 + 1] = -0.780675f;	val_dir[93*3 + 2] = 0.022305f;
+        val_dir[94*3 + 0] = 0.648784f;	val_dir[94*3 + 1] = -0.760644f;	val_dir[94*3 + 2] = 0.022372f;
+        val_dir[95*3 + 0] = 0.672504f;	val_dir[95*3 + 1] = -0.739754f;	val_dir[95*3 + 2] = 0.022417f;
+        val_dir[96*3 + 0] = 0.695620f;	val_dir[96*3 + 1] = -0.718059f;	val_dir[96*3 + 2] = 0.022439f;
+        val_dir[97*3 + 0] = 0.718059f;	val_dir[97*3 + 1] = -0.695620f;	val_dir[97*3 + 2] = 0.022439f;
+        val_dir[98*3 + 0] = 0.739754f;	val_dir[98*3 + 1] = -0.672504f;	val_dir[98*3 + 2] = 0.022417f;
+        val_dir[99*3 + 0] = 0.760644f;	val_dir[99*3 + 1] = -0.648784f;	val_dir[99*3 + 2] = 0.022372f;
+        val_dir[100*3 + 0] = 0.780675f;	val_dir[100*3 + 1] = -0.624540f;	val_dir[100*3 + 2] = 0.022305f;
+        val_dir[101*3 + 0] = 0.799803f;	val_dir[101*3 + 1] = -0.599852f;	val_dir[101*3 + 2] = 0.022217f;
+        val_dir[102*3 + 0] = 0.817992f;	val_dir[102*3 + 1] = -0.574805f;	val_dir[102*3 + 2] = 0.022108f;
+        val_dir[103*3 + 0] = 0.835215f;	val_dir[103*3 + 1] = -0.549484f;	val_dir[103*3 + 2] = 0.021979f;
+        val_dir[104*3 + 0] = 0.851455f;	val_dir[104*3 + 1] = -0.523973f;	val_dir[104*3 + 2] = 0.021832f;
+        val_dir[105*3 + 0] = 0.866703f;	val_dir[105*3 + 1] = -0.498354f;	val_dir[105*3 + 2] = 0.021668f;
+        val_dir[106*3 + 0] = 0.880957f;	val_dir[106*3 + 1] = -0.472709f;	val_dir[106*3 + 2] = 0.021487f;
+        val_dir[107*3 + 0] = 0.894224f;	val_dir[107*3 + 1] = -0.447112f;	val_dir[107*3 + 2] = 0.021291f;
+        val_dir[108*3 + 0] = 0.906520f;	val_dir[108*3 + 1] = -0.421637f;	val_dir[108*3 + 2] = 0.021082f;
+        val_dir[109*3 + 0] = 0.917863f;	val_dir[109*3 + 1] = -0.396350f;	val_dir[109*3 + 2] = 0.020861f;
+        val_dir[110*3 + 0] = 0.928279f;	val_dir[110*3 + 1] = -0.371312f;	val_dir[110*3 + 2] = 0.020628f;
+        val_dir[111*3 + 0] = 0.93780f;	val_dir[111*3 + 1] = -0.346578f;	val_dir[111*3 + 2] = 0.020387f;
+        val_dir[112*3 + 0] = 0.946458f;	val_dir[112*3 + 1] = -0.322198f;	val_dir[112*3 + 2] = 0.020137f;
+        val_dir[113*3 + 0] = 0.954291f;	val_dir[113*3 + 1] = -0.298216f;	val_dir[113*3 + 2] = 0.019881f;
+        val_dir[114*3 + 0] = 0.961339f;	val_dir[114*3 + 1] = -0.274668f;	val_dir[114*3 + 2] = 0.019619f;
+        val_dir[115*3 + 0] = 0.967641f;	val_dir[115*3 + 1] = -0.251587f;	val_dir[115*3 + 2] = 0.019353f;
+        val_dir[116*3 + 0] = 0.973240f;	val_dir[116*3 + 1] = -0.228998f;	val_dir[116*3 + 2] = 0.019083f;
+        val_dir[117*3 + 0] = 0.978177f;	val_dir[117*3 + 1] = -0.206922f;	val_dir[117*3 + 2] = 0.018811f;
+        val_dir[118*3 + 0] = 0.982493f;	val_dir[118*3 + 1] = -0.185376f;	val_dir[118*3 + 2] = 0.018538f;
+        val_dir[119*3 + 0] = 0.986229f;	val_dir[119*3 + 1] = -0.164372f;	val_dir[119*3 + 2] = 0.018264f;
+        val_dir[120*3 + 0] = 0.989426f;	val_dir[120*3 + 1] = -0.143917f;	val_dir[120*3 + 2] = 0.017990f;
+        val_dir[121*3 + 0] = 0.992122f;	val_dir[121*3 + 1] = -0.124015f;	val_dir[121*3 + 2] = 0.017716f;
+        val_dir[122*3 + 0] = 0.994354f;	val_dir[122*3 + 1] = -0.104669f;	val_dir[122*3 + 2] = 0.017445f;
+        val_dir[123*3 + 0] = 0.996158f;	val_dir[123*3 + 1] = -0.085876f;	val_dir[123*3 + 2] = 0.017175f;
+        val_dir[124*3 + 0] = 0.997567f;	val_dir[124*3 + 1] = -0.067632f;	val_dir[124*3 + 2] = 0.016908f;
+        val_dir[125*3 + 0] = 0.998614f;	val_dir[125*3 + 1] = -0.049931f;	val_dir[125*3 + 2] = 0.016644f;
+        val_dir[126*3 + 0] = 0.999329f;	val_dir[126*3 + 1] = -0.032765f;	val_dir[126*3 + 2] = 0.016382f;
+        val_dir[127*3 + 0] = 0.999740f;	val_dir[127*3 + 1] = -0.016125f;	val_dir[127*3 + 2] = 0.016125f;
+        val_dir[128*3 + 0] = 0.999874f;	val_dir[128*3 + 1] = 0.0f;	val_dir[128*3 + 2] = 0.015871f;
+        val_dir[129*3 + 0] = -0.015871f;	val_dir[129*3 + 1] = -0.999874f;	val_dir[129*3 + 2] = 0.0f;
+        val_dir[130*3 + 0] = 0.0f;	val_dir[130*3 + 1] = -0.999480f;	val_dir[130*3 + 2] = 0.032241f;
+        val_dir[131*3 + 0] = 0.016382f;	val_dir[131*3 + 1] = -0.999329f;	val_dir[131*3 + 2] = 0.032765f;
+        val_dir[132*3 + 0] = 0.033296f;	val_dir[132*3 + 1] = -0.998891f;	val_dir[132*3 + 2] = 0.033296f;
+        val_dir[133*3 + 0] = 0.050753f;	val_dir[133*3 + 1] = -0.998138f;	val_dir[133*3 + 2] = 0.033835f;
+        val_dir[134*3 + 0] = 0.068761f;	val_dir[134*3 + 1] = -0.997041f;	val_dir[134*3 + 2] = 0.034381f;
+        val_dir[135*3 + 0] = 0.087330f;	val_dir[135*3 + 1] = -0.995567f;	val_dir[135*3 + 2] = 0.034932f;
+        val_dir[136*3 + 0] = 0.106466f;	val_dir[136*3 + 1] = -0.993683f;	val_dir[136*3 + 2] = 0.035489f;
+        val_dir[137*3 + 0] = 0.126172f;	val_dir[137*3 + 1] = -0.991353f;	val_dir[137*3 + 2] = 0.036049f;
+        val_dir[138*3 + 0] = 0.146450f;	val_dir[138*3 + 1] = -0.988540f;	val_dir[138*3 + 2] = 0.036613f;
+        val_dir[139*3 + 0] = 0.167299f;	val_dir[139*3 + 1] = -0.985205f;	val_dir[139*3 + 2] = 0.037178f;
+        val_dir[140*3 + 0] = 0.188713f;	val_dir[140*3 + 1] = -0.981307f;	val_dir[140*3 + 2] = 0.037743f;
+        val_dir[141*3 + 0] = 0.210683f;	val_dir[141*3 + 1] = -0.976804f;	val_dir[141*3 + 2] = 0.038306f;
+        val_dir[142*3 + 0] = 0.233197f;	val_dir[142*3 + 1] = -0.971653f;	val_dir[142*3 + 2] = 0.038866f;
+        val_dir[143*3 + 0] = 0.256235f;	val_dir[143*3 + 1] = -0.965810f;	val_dir[143*3 + 2] = 0.039421f;
+        val_dir[144*3 + 0] = 0.279776f;	val_dir[144*3 + 1] = -0.959233f;	val_dir[144*3 + 2] = 0.039968f;
+        val_dir[145*3 + 0] = 0.303791f;	val_dir[145*3 + 1] = -0.951877f;	val_dir[145*3 + 2] = 0.040505f;
+        val_dir[146*3 + 0] = 0.328244f;	val_dir[146*3 + 1] = -0.943701f;	val_dir[146*3 + 2] = 0.041030f;
+        val_dir[147*3 + 0] = 0.353096f;	val_dir[147*3 + 1] = -0.934665f;	val_dir[147*3 + 2] = 0.041541f;
+        val_dir[148*3 + 0] = 0.378298f;	val_dir[148*3 + 1] = -0.924729f;	val_dir[148*3 + 2] = 0.042033f;
+        val_dir[149*3 + 0] = 0.403799f;	val_dir[149*3 + 1] = -0.913860f;	val_dir[149*3 + 2] = 0.042505f;
+        val_dir[150*3 + 0] = 0.429537f;	val_dir[150*3 + 1] = -0.902027f;	val_dir[150*3 + 2] = 0.042954f;
+        val_dir[151*3 + 0] = 0.455447f;	val_dir[151*3 + 1] = -0.889206f;	val_dir[151*3 + 2] = 0.043376f;
+        val_dir[152*3 + 0] = 0.481457f;	val_dir[152*3 + 1] = -0.875376f;	val_dir[152*3 + 2] = 0.043769f;
+        val_dir[153*3 + 0] = 0.507490f;	val_dir[153*3 + 1] = -0.860527f;	val_dir[153*3 + 2] = 0.044130f;
+        val_dir[154*3 + 0] = 0.533465f;	val_dir[154*3 + 1] = -0.844653f;	val_dir[154*3 + 2] = 0.044455f;
+        val_dir[155*3 + 0] = 0.559297f;	val_dir[155*3 + 1] = -0.827759f;	val_dir[155*3 + 2] = 0.044744f;
+        val_dir[156*3 + 0] = 0.584898f;	val_dir[156*3 + 1] = -0.809858f;	val_dir[156*3 + 2] = 0.044992f;
+        val_dir[157*3 + 0] = 0.610179f;	val_dir[157*3 + 1] = -0.790973f;	val_dir[157*3 + 2] = 0.045198f;
+        val_dir[158*3 + 0] = 0.635053f;	val_dir[158*3 + 1] = -0.771136f;	val_dir[158*3 + 2] = 0.045361f;
+        val_dir[159*3 + 0] = 0.659432f;	val_dir[159*3 + 1] = -0.750388f;	val_dir[159*3 + 2] = 0.045478f;
+        val_dir[160*3 + 0] = 0.683231f;	val_dir[160*3 + 1] = -0.728780f;	val_dir[160*3 + 2] = 0.045549f;
+        val_dir[161*3 + 0] = 0.706372f;	val_dir[161*3 + 1] = -0.706372f;	val_dir[161*3 + 2] = 0.045572f;
+        val_dir[162*3 + 0] = 0.728780f;	val_dir[162*3 + 1] = -0.683231f;	val_dir[162*3 + 2] = 0.045549f;
+        val_dir[163*3 + 0] = 0.750388f;	val_dir[163*3 + 1] = -0.659432f;	val_dir[163*3 + 2] = 0.045478f;
+        val_dir[164*3 + 0] = 0.771136f;	val_dir[164*3 + 1] = -0.635053f;	val_dir[164*3 + 2] = 0.045361f;
+        val_dir[165*3 + 0] = 0.790973f;	val_dir[165*3 + 1] = -0.610179f;	val_dir[165*3 + 2] = 0.045198f;
+        val_dir[166*3 + 0] = 0.809858f;	val_dir[166*3 + 1] = -0.584898f;	val_dir[166*3 + 2] = 0.044992f;
+        val_dir[167*3 + 0] = 0.827759f;	val_dir[167*3 + 1] = -0.559297f;	val_dir[167*3 + 2] = 0.044744f;
+        val_dir[168*3 + 0] = 0.844653f;	val_dir[168*3 + 1] = -0.533465f;	val_dir[168*3 + 2] = 0.044455f;
+        val_dir[169*3 + 0] = 0.860527f;	val_dir[169*3 + 1] = -0.507490f;	val_dir[169*3 + 2] = 0.044130f;
+        val_dir[170*3 + 0] = 0.875376f;	val_dir[170*3 + 1] = -0.481457f;	val_dir[170*3 + 2] = 0.043769f;
+        val_dir[171*3 + 0] = 0.889206f;	val_dir[171*3 + 1] = -0.455447f;	val_dir[171*3 + 2] = 0.043376f;
+        val_dir[172*3 + 0] = 0.902027f;	val_dir[172*3 + 1] = -0.429537f;	val_dir[172*3 + 2] = 0.042954f;
+        val_dir[173*3 + 0] = 0.913860f;	val_dir[173*3 + 1] = -0.403799f;	val_dir[173*3 + 2] = 0.042505f;
+        val_dir[174*3 + 0] = 0.924729f;	val_dir[174*3 + 1] = -0.378298f;	val_dir[174*3 + 2] = 0.042033f;
+        val_dir[175*3 + 0] = 0.934665f;	val_dir[175*3 + 1] = -0.353096f;	val_dir[175*3 + 2] = 0.041541f;
+        val_dir[176*3 + 0] = 0.943701f;	val_dir[176*3 + 1] = -0.328244f;	val_dir[176*3 + 2] = 0.041030f;
+        val_dir[177*3 + 0] = 0.951877f;	val_dir[177*3 + 1] = -0.303791f;	val_dir[177*3 + 2] = 0.040505f;
+        val_dir[178*3 + 0] = 0.959233f;	val_dir[178*3 + 1] = -0.279776f;	val_dir[178*3 + 2] = 0.039968f;
+        val_dir[179*3 + 0] = 0.965810f;	val_dir[179*3 + 1] = -0.256235f;	val_dir[179*3 + 2] = 0.039421f;
+        val_dir[180*3 + 0] = 0.971653f;	val_dir[180*3 + 1] = -0.233197f;	val_dir[180*3 + 2] = 0.038866f;
+        val_dir[181*3 + 0] = 0.976804f;	val_dir[181*3 + 1] = -0.210683f;	val_dir[181*3 + 2] = 0.038306f;
+        val_dir[182*3 + 0] = 0.981307f;	val_dir[182*3 + 1] = -0.188713f;	val_dir[182*3 + 2] = 0.037743f;
+        val_dir[183*3 + 0] = 0.985205f;	val_dir[183*3 + 1] = -0.167299f;	val_dir[183*3 + 2] = 0.037178f;
+        val_dir[184*3 + 0] = 0.988540f;	val_dir[184*3 + 1] = -0.146450f;	val_dir[184*3 + 2] = 0.036613f;
+        val_dir[185*3 + 0] = 0.991353f;	val_dir[185*3 + 1] = -0.126172f;	val_dir[185*3 + 2] = 0.036049f;
+        val_dir[186*3 + 0] = 0.993683f;	val_dir[186*3 + 1] = -0.106466f;	val_dir[186*3 + 2] = 0.035489f;
+        val_dir[187*3 + 0] = 0.995567f;	val_dir[187*3 + 1] = -0.087330f;	val_dir[187*3 + 2] = 0.034932f;
+        val_dir[188*3 + 0] = 0.997041f;	val_dir[188*3 + 1] = -0.068761f;	val_dir[188*3 + 2] = 0.034381f;
+        val_dir[189*3 + 0] = 0.998138f;	val_dir[189*3 + 1] = -0.050753f;	val_dir[189*3 + 2] = 0.033835f;
+        val_dir[190*3 + 0] = 0.998891f;	val_dir[190*3 + 1] = -0.033296f;	val_dir[190*3 + 2] = 0.033296f;
+        val_dir[191*3 + 0] = 0.999329f;	val_dir[191*3 + 1] = -0.016382f;	val_dir[191*3 + 2] = 0.032765f;
+        val_dir[192*3 + 0] = 0.999480f;	val_dir[192*3 + 1] = 0.0f;	val_dir[192*3 + 2] = 0.032241f;
+        val_dir[193*3 + 0] = 0.999874f;	val_dir[193*3 + 1] = 0.015871f;	val_dir[193*3 + 2] = 0.0f;
+        val_dir[194*3 + 0] = -0.016125f;	val_dir[194*3 + 1] = -0.999740f;	val_dir[194*3 + 2] = 0.016125f;
+        val_dir[195*3 + 0] = 0.0f;	val_dir[195*3 + 1] = -0.998793f;	val_dir[195*3 + 2] = 0.049121f;
+        val_dir[196*3 + 0] = 0.016644f;	val_dir[196*3 + 1] = -0.998614f;	val_dir[196*3 + 2] = 0.049931f;
+        val_dir[197*3 + 0] = 0.033835f;	val_dir[197*3 + 1] = -0.998138f;	val_dir[197*3 + 2] = 0.050753f;
+        val_dir[198*3 + 0] = 0.051586f;	val_dir[198*3 + 1] = -0.997335f;	val_dir[198*3 + 2] = 0.051586f;
+        val_dir[199*3 + 0] = 0.069907f;	val_dir[199*3 + 1] = -0.996175f;	val_dir[199*3 + 2] = 0.052430f;
+        val_dir[200*3 + 0] = 0.088806f;	val_dir[200*3 + 1] = -0.994623f;	val_dir[200*3 + 2] = 0.053283f;
+        val_dir[201*3 + 0] = 0.108288f;	val_dir[201*3 + 1] = -0.992644f;	val_dir[201*3 + 2] = 0.054144f;
+        val_dir[202*3 + 0] = 0.128359f;	val_dir[202*3 + 1] = -0.990201f;	val_dir[202*3 + 2] = 0.055011f;
+        val_dir[203*3 + 0] = 0.149019f;	val_dir[203*3 + 1] = -0.987254f;	val_dir[203*3 + 2] = 0.055882f;
+        val_dir[204*3 + 0] = 0.170267f;	val_dir[204*3 + 1] = -0.983762f;	val_dir[204*3 + 2] = 0.056756f;
+        val_dir[205*3 + 0] = 0.192095f;	val_dir[205*3 + 1] = -0.979683f;	val_dir[205*3 + 2] = 0.057628f;
+        val_dir[206*3 + 0] = 0.214494f;	val_dir[206*3 + 1] = -0.974972f;	val_dir[206*3 + 2] = 0.058498f;
+        val_dir[207*3 + 0] = 0.237449f;	val_dir[207*3 + 1] = -0.969584f;	val_dir[207*3 + 2] = 0.059362f;
+        val_dir[208*3 + 0] = 0.260941f;	val_dir[208*3 + 1] = -0.963475f;	val_dir[208*3 + 2] = 0.060217f;
+        val_dir[209*3 + 0] = 0.284944f;	val_dir[209*3 + 1] = -0.956597f;	val_dir[209*3 + 2] = 0.061059f;
+        val_dir[210*3 + 0] = 0.309426f;	val_dir[210*3 + 1] = -0.948908f;	val_dir[210*3 + 2] = 0.061885f;
+        val_dir[211*3 + 0] = 0.334351f;	val_dir[211*3 + 1] = -0.940361f;	val_dir[211*3 + 2] = 0.062691f;
+        val_dir[212*3 + 0] = 0.359673f;	val_dir[212*3 + 1] = -0.930917f;	val_dir[212*3 + 2] = 0.063472f;
+        val_dir[213*3 + 0] = 0.385341f;	val_dir[213*3 + 1] = -0.920537f;	val_dir[213*3 + 2] = 0.064223f;
+        val_dir[214*3 + 0] = 0.411298f;	val_dir[214*3 + 1] = -0.909185f;	val_dir[214*3 + 2] = 0.064942f;
+        val_dir[215*3 + 0] = 0.437479f;	val_dir[215*3 + 1] = -0.896831f;	val_dir[215*3 + 2] = 0.065622f;
+        val_dir[216*3 + 0] = 0.463812f;	val_dir[216*3 + 1] = -0.883452f;	val_dir[216*3 + 2] = 0.066259f;
+        val_dir[217*3 + 0] = 0.490222f;	val_dir[217*3 + 1] = -0.869030f;	val_dir[217*3 + 2] = 0.066848f;
+        val_dir[218*3 + 0] = 0.516626f;	val_dir[218*3 + 1] = -0.853556f;	val_dir[218*3 + 2] = 0.067386f;
+        val_dir[219*3 + 0] = 0.542936f;	val_dir[219*3 + 1] = -0.837027f;	val_dir[219*3 + 2] = 0.067867f;
+        val_dir[220*3 + 0] = 0.569064f;	val_dir[220*3 + 1] = -0.819453f;	val_dir[220*3 + 2] = 0.068288f;
+        val_dir[221*3 + 0] = 0.594917f;	val_dir[221*3 + 1] = -0.800850f;	val_dir[221*3 + 2] = 0.068644f;
+        val_dir[222*3 + 0] = 0.620403f;	val_dir[222*3 + 1] = -0.781248f;	val_dir[222*3 + 2] = 0.068934f;
+        val_dir[223*3 + 0] = 0.645429f;	val_dir[223*3 + 1] = -0.760684f;	val_dir[223*3 + 2] = 0.069153f;
+        val_dir[224*3 + 0] = 0.669905f;	val_dir[224*3 + 1] = -0.739205f;	val_dir[224*3 + 2] = 0.069301f;
+        val_dir[225*3 + 0] = 0.693746f;	val_dir[225*3 + 1] = -0.716871f;	val_dir[225*3 + 2] = 0.069375f;
+        val_dir[226*3 + 0] = 0.716871f;	val_dir[226*3 + 1] = -0.693746f;	val_dir[226*3 + 2] = 0.069375f;
+        val_dir[227*3 + 0] = 0.739205f;	val_dir[227*3 + 1] = -0.669905f;	val_dir[227*3 + 2] = 0.069301f;
+        val_dir[228*3 + 0] = 0.760684f;	val_dir[228*3 + 1] = -0.645429f;	val_dir[228*3 + 2] = 0.069153f;
+        val_dir[229*3 + 0] = 0.781248f;	val_dir[229*3 + 1] = -0.620403f;	val_dir[229*3 + 2] = 0.068934f;
+        val_dir[230*3 + 0] = 0.800850f;	val_dir[230*3 + 1] = -0.594917f;	val_dir[230*3 + 2] = 0.068644f;
+        val_dir[231*3 + 0] = 0.819453f;	val_dir[231*3 + 1] = -0.569064f;	val_dir[231*3 + 2] = 0.068288f;
+        val_dir[232*3 + 0] = 0.837027f;	val_dir[232*3 + 1] = -0.542936f;	val_dir[232*3 + 2] = 0.067867f;
+        val_dir[233*3 + 0] = 0.853556f;	val_dir[233*3 + 1] = -0.516626f;	val_dir[233*3 + 2] = 0.067386f;
+        val_dir[234*3 + 0] = 0.869030f;	val_dir[234*3 + 1] = -0.490222f;	val_dir[234*3 + 2] = 0.066848f;
+        val_dir[235*3 + 0] = 0.883452f;	val_dir[235*3 + 1] = -0.463812f;	val_dir[235*3 + 2] = 0.066259f;
+        val_dir[236*3 + 0] = 0.896831f;	val_dir[236*3 + 1] = -0.437479f;	val_dir[236*3 + 2] = 0.065622f;
+        val_dir[237*3 + 0] = 0.909185f;	val_dir[237*3 + 1] = -0.411298f;	val_dir[237*3 + 2] = 0.064942f;
+        val_dir[238*3 + 0] = 0.920537f;	val_dir[238*3 + 1] = -0.385341f;	val_dir[238*3 + 2] = 0.064223f;
+        val_dir[239*3 + 0] = 0.930917f;	val_dir[239*3 + 1] = -0.359673f;	val_dir[239*3 + 2] = 0.063472f;
+        val_dir[240*3 + 0] = 0.940361f;	val_dir[240*3 + 1] = -0.334351f;	val_dir[240*3 + 2] = 0.062691f;
+        val_dir[241*3 + 0] = 0.948908f;	val_dir[241*3 + 1] = -0.309426f;	val_dir[241*3 + 2] = 0.061885f;
+        val_dir[242*3 + 0] = 0.956597f;	val_dir[242*3 + 1] = -0.284944f;	val_dir[242*3 + 2] = 0.061059f;
+        val_dir[243*3 + 0] = 0.963475f;	val_dir[243*3 + 1] = -0.260941f;	val_dir[243*3 + 2] = 0.060217f;
+        val_dir[244*3 + 0] = 0.969584f;	val_dir[244*3 + 1] = -0.237449f;	val_dir[244*3 + 2] = 0.059362f;
+        val_dir[245*3 + 0] = 0.974972f;	val_dir[245*3 + 1] = -0.214494f;	val_dir[245*3 + 2] = 0.058498f;
+        val_dir[246*3 + 0] = 0.979683f;	val_dir[246*3 + 1] = -0.192095f;	val_dir[246*3 + 2] = 0.057628f;
+        val_dir[247*3 + 0] = 0.983762f;	val_dir[247*3 + 1] = -0.170267f;	val_dir[247*3 + 2] = 0.056756f;
+        val_dir[248*3 + 0] = 0.987254f;	val_dir[248*3 + 1] = -0.149019f;	val_dir[248*3 + 2] = 0.055882f;
+        val_dir[249*3 + 0] = 0.990201f;	val_dir[249*3 + 1] = -0.128359f;	val_dir[249*3 + 2] = 0.055011f;
+        val_dir[250*3 + 0] = 0.992644f;	val_dir[250*3 + 1] = -0.108288f;	val_dir[250*3 + 2] = 0.054144f;
+        val_dir[251*3 + 0] = 0.994623f;	val_dir[251*3 + 1] = -0.088806f;	val_dir[251*3 + 2] = 0.053283f;
+        val_dir[252*3 + 0] = 0.996175f;	val_dir[252*3 + 1] = -0.069907f;	val_dir[252*3 + 2] = 0.052430f;
+        val_dir[253*3 + 0] = 0.997335f;	val_dir[253*3 + 1] = -0.051586f;	val_dir[253*3 + 2] = 0.051586f;
+        val_dir[254*3 + 0] = 0.998138f;	val_dir[254*3 + 1] = -0.033835f;	val_dir[254*3 + 2] = 0.050753f;
+        val_dir[255*3 + 0] = 0.998614f;	val_dir[255*3 + 1] = -0.016644f;	val_dir[255*3 + 2] = 0.049931f;
+        val_dir[256*3 + 0] = 0.998793f;	val_dir[256*3 + 1] = 0.0f;	val_dir[256*3 + 2] = 0.049121f;
+        val_dir[257*3 + 0] = 0.999740f;	val_dir[257*3 + 1] = 0.016125f;	val_dir[257*3 + 2] = 0.016125f;
+        val_dir[258*3 + 0] = -0.032241f;	val_dir[258*3 + 1] = -0.999480f;	val_dir[258*3 + 2] = 0.0f;
+        val_dir[259*3 + 0] = -0.016382f;	val_dir[259*3 + 1] = -0.999329f;	val_dir[259*3 + 2] = 0.032765f;
+        val_dir[260*3 + 0] = 0.0f;	val_dir[260*3 + 1] = -0.997785f;	val_dir[260*3 + 2] = 0.066519f;
+        val_dir[261*3 + 0] = 0.016908f;	val_dir[261*3 + 1] = -0.997567f;	val_dir[261*3 + 2] = 0.067632f;
+        val_dir[262*3 + 0] = 0.034381f;	val_dir[262*3 + 1] = -0.997041f;	val_dir[262*3 + 2] = 0.068761f;
+        val_dir[263*3 + 0] = 0.052430f;	val_dir[263*3 + 1] = -0.996175f;	val_dir[263*3 + 2] = 0.069907f;
+        val_dir[264*3 + 0] = 0.071067f;	val_dir[264*3 + 1] = -0.994937f;	val_dir[264*3 + 2] = 0.071067f;
+        val_dir[265*3 + 0] = 0.090299f;	val_dir[265*3 + 1] = -0.993291f;	val_dir[265*3 + 2] = 0.072239f;
+        val_dir[266*3 + 0] = 0.110133f;	val_dir[266*3 + 1] = -0.991201f;	val_dir[266*3 + 2] = 0.073422f;
+        val_dir[267*3 + 0] = 0.130573f;	val_dir[267*3 + 1] = -0.988627f;	val_dir[267*3 + 2] = 0.074613f;
+        val_dir[268*3 + 0] = 0.151620f;	val_dir[268*3 + 1] = -0.985527f;	val_dir[268*3 + 2] = 0.075810f;
+        val_dir[269*3 + 0] = 0.173269f;	val_dir[269*3 + 1] = -0.981859f;	val_dir[269*3 + 2] = 0.077009f;
+        val_dir[270*3 + 0] = 0.195515f;	val_dir[270*3 + 1] = -0.977577f;	val_dir[270*3 + 2] = 0.078206f;
+        val_dir[271*3 + 0] = 0.218347f;	val_dir[271*3 + 1] = -0.972636f;	val_dir[271*3 + 2] = 0.079399f;
+        val_dir[272*3 + 0] = 0.241747f;	val_dir[272*3 + 1] = -0.966988f;	val_dir[272*3 + 2] = 0.080582f;
+        val_dir[273*3 + 0] = 0.265694f;	val_dir[273*3 + 1] = -0.960585f;	val_dir[273*3 + 2] = 0.081752f;
+        val_dir[274*3 + 0] = 0.290159f;	val_dir[274*3 + 1] = -0.953381f;	val_dir[274*3 + 2] = 0.082903f;
+        val_dir[275*3 + 0] = 0.315109f;	val_dir[275*3 + 1] = -0.945328f;	val_dir[275*3 + 2] = 0.084029f;
+        val_dir[276*3 + 0] = 0.340503f;	val_dir[276*3 + 1] = -0.936382f;	val_dir[276*3 + 2] = 0.085126f;
+        val_dir[277*3 + 0] = 0.366291f;	val_dir[277*3 + 1] = -0.92650f;	val_dir[277*3 + 2] = 0.086186f;
+        val_dir[278*3 + 0] = 0.392419f;	val_dir[278*3 + 1] = -0.915644f;	val_dir[278*3 + 2] = 0.087204f;
+        val_dir[279*3 + 0] = 0.418823f;	val_dir[279*3 + 1] = -0.903777f;	val_dir[279*3 + 2] = 0.088173f;
+        val_dir[280*3 + 0] = 0.445435f;	val_dir[280*3 + 1] = -0.890871f;	val_dir[280*3 + 2] = 0.089087f;
+        val_dir[281*3 + 0] = 0.472178f;	val_dir[281*3 + 1] = -0.876903f;	val_dir[281*3 + 2] = 0.089939f;
+        val_dir[282*3 + 0] = 0.498970f;	val_dir[282*3 + 1] = -0.861857f;	val_dir[282*3 + 2] = 0.090722f;
+        val_dir[283*3 + 0] = 0.525723f;	val_dir[283*3 + 1] = -0.845728f;	val_dir[283*3 + 2] = 0.091430f;
+        val_dir[284*3 + 0] = 0.552345f;	val_dir[284*3 + 1] = -0.828517f;	val_dir[284*3 + 2] = 0.092057f;
+        val_dir[285*3 + 0] = 0.578741f;	val_dir[285*3 + 1] = -0.810237f;	val_dir[285*3 + 2] = 0.092599f;
+        val_dir[286*3 + 0] = 0.604815f;	val_dir[286*3 + 1] = -0.790912f;	val_dir[286*3 + 2] = 0.093048f;
+        val_dir[287*3 + 0] = 0.630470f;	val_dir[287*3 + 1] = -0.770574f;	val_dir[287*3 + 2] = 0.093403f;
+        val_dir[288*3 + 0] = 0.655610f;	val_dir[288*3 + 1] = -0.749269f;	val_dir[288*3 + 2] = 0.093659f;
+        val_dir[289*3 + 0] = 0.680144f;	val_dir[289*3 + 1] = -0.727051f;	val_dir[289*3 + 2] = 0.093813f;
+        val_dir[290*3 + 0] = 0.703985f;	val_dir[290*3 + 1] = -0.703985f;	val_dir[290*3 + 2] = 0.093865f;
+        val_dir[291*3 + 0] = 0.727051f;	val_dir[291*3 + 1] = -0.680144f;	val_dir[291*3 + 2] = 0.093813f;
+        val_dir[292*3 + 0] = 0.749269f;	val_dir[292*3 + 1] = -0.655610f;	val_dir[292*3 + 2] = 0.093659f;
+        val_dir[293*3 + 0] = 0.770574f;	val_dir[293*3 + 1] = -0.630470f;	val_dir[293*3 + 2] = 0.093403f;
+        val_dir[294*3 + 0] = 0.790912f;	val_dir[294*3 + 1] = -0.604815f;	val_dir[294*3 + 2] = 0.093048f;
+        val_dir[295*3 + 0] = 0.810237f;	val_dir[295*3 + 1] = -0.578741f;	val_dir[295*3 + 2] = 0.092599f;
+        val_dir[296*3 + 0] = 0.828517f;	val_dir[296*3 + 1] = -0.552345f;	val_dir[296*3 + 2] = 0.092057f;
+        val_dir[297*3 + 0] = 0.845728f;	val_dir[297*3 + 1] = -0.525723f;	val_dir[297*3 + 2] = 0.091430f;
+        val_dir[298*3 + 0] = 0.861857f;	val_dir[298*3 + 1] = -0.498970f;	val_dir[298*3 + 2] = 0.090722f;
+        val_dir[299*3 + 0] = 0.876903f;	val_dir[299*3 + 1] = -0.472178f;	val_dir[299*3 + 2] = 0.089939f;
+        val_dir[300*3 + 0] = 0.890871f;	val_dir[300*3 + 1] = -0.445435f;	val_dir[300*3 + 2] = 0.089087f;
+        val_dir[301*3 + 0] = 0.903777f;	val_dir[301*3 + 1] = -0.418823f;	val_dir[301*3 + 2] = 0.088173f;
+        val_dir[302*3 + 0] = 0.915644f;	val_dir[302*3 + 1] = -0.392419f;	val_dir[302*3 + 2] = 0.087204f;
+        val_dir[303*3 + 0] = 0.92650f;	val_dir[303*3 + 1] = -0.366291f;	val_dir[303*3 + 2] = 0.086186f;
+        val_dir[304*3 + 0] = 0.936382f;	val_dir[304*3 + 1] = -0.340503f;	val_dir[304*3 + 2] = 0.085126f;
+        val_dir[305*3 + 0] = 0.945328f;	val_dir[305*3 + 1] = -0.315109f;	val_dir[305*3 + 2] = 0.084029f;
+        val_dir[306*3 + 0] = 0.953381f;	val_dir[306*3 + 1] = -0.290159f;	val_dir[306*3 + 2] = 0.082903f;
+        val_dir[307*3 + 0] = 0.960585f;	val_dir[307*3 + 1] = -0.265694f;	val_dir[307*3 + 2] = 0.081752f;
+        val_dir[308*3 + 0] = 0.966988f;	val_dir[308*3 + 1] = -0.241747f;	val_dir[308*3 + 2] = 0.080582f;
+        val_dir[309*3 + 0] = 0.972636f;	val_dir[309*3 + 1] = -0.218347f;	val_dir[309*3 + 2] = 0.079399f;
+        val_dir[310*3 + 0] = 0.977577f;	val_dir[310*3 + 1] = -0.195515f;	val_dir[310*3 + 2] = 0.078206f;
+        val_dir[311*3 + 0] = 0.981859f;	val_dir[311*3 + 1] = -0.173269f;	val_dir[311*3 + 2] = 0.077009f;
+        val_dir[312*3 + 0] = 0.985527f;	val_dir[312*3 + 1] = -0.151620f;	val_dir[312*3 + 2] = 0.075810f;
+        val_dir[313*3 + 0] = 0.988627f;	val_dir[313*3 + 1] = -0.130573f;	val_dir[313*3 + 2] = 0.074613f;
+        val_dir[314*3 + 0] = 0.991201f;	val_dir[314*3 + 1] = -0.110133f;	val_dir[314*3 + 2] = 0.073422f;
+        val_dir[315*3 + 0] = 0.993291f;	val_dir[315*3 + 1] = -0.090299f;	val_dir[315*3 + 2] = 0.072239f;
+        val_dir[316*3 + 0] = 0.994937f;	val_dir[316*3 + 1] = -0.071067f;	val_dir[316*3 + 2] = 0.071067f;
+        val_dir[317*3 + 0] = 0.996175f;	val_dir[317*3 + 1] = -0.052430f;	val_dir[317*3 + 2] = 0.069907f;
+        val_dir[318*3 + 0] = 0.997041f;	val_dir[318*3 + 1] = -0.034381f;	val_dir[318*3 + 2] = 0.068761f;
+        val_dir[319*3 + 0] = 0.997567f;	val_dir[319*3 + 1] = -0.016908f;	val_dir[319*3 + 2] = 0.067632f;
+        val_dir[320*3 + 0] = 0.997785f;	val_dir[320*3 + 1] = 0.0f;	val_dir[320*3 + 2] = 0.066519f;
+        val_dir[321*3 + 0] = 0.999329f;	val_dir[321*3 + 1] = 0.016382f;	val_dir[321*3 + 2] = 0.032765f;
+        val_dir[322*3 + 0] = 0.999480f;	val_dir[322*3 + 1] = 0.032241f;	val_dir[322*3 + 2] = 0.0f;
+        val_dir[323*3 + 0] = -0.032765f;	val_dir[323*3 + 1] = -0.999329f;	val_dir[323*3 + 2] = 0.016382f;
+        val_dir[324*3 + 0] = -0.016644f;	val_dir[324*3 + 1] = -0.998614f;	val_dir[324*3 + 2] = 0.049931f;
+        val_dir[325*3 + 0] = 0.0f;	val_dir[325*3 + 1] = -0.996428f;	val_dir[325*3 + 2] = 0.084443f;
+        val_dir[326*3 + 0] = 0.017175f;	val_dir[326*3 + 1] = -0.996158f;	val_dir[326*3 + 2] = 0.085876f;
+        val_dir[327*3 + 0] = 0.034932f;	val_dir[327*3 + 1] = -0.995567f;	val_dir[327*3 + 2] = 0.087330f;
+        val_dir[328*3 + 0] = 0.053283f;	val_dir[328*3 + 1] = -0.994623f;	val_dir[328*3 + 2] = 0.088806f;
+        val_dir[329*3 + 0] = 0.072239f;	val_dir[329*3 + 1] = -0.993291f;	val_dir[329*3 + 2] = 0.090299f;
+        val_dir[330*3 + 0] = 0.091809f;	val_dir[330*3 + 1] = -0.991535f;	val_dir[330*3 + 2] = 0.091809f;
+        val_dir[331*3 + 0] = 0.111998f;	val_dir[331*3 + 1] = -0.989316f;	val_dir[331*3 + 2] = 0.093332f;
+        val_dir[332*3 + 0] = 0.132810f;	val_dir[332*3 + 1] = -0.986591f;	val_dir[332*3 + 2] = 0.094865f;
+        val_dir[333*3 + 0] = 0.154246f;	val_dir[333*3 + 1] = -0.983318f;	val_dir[333*3 + 2] = 0.096404f;
+        val_dir[334*3 + 0] = 0.176301f;	val_dir[334*3 + 1] = -0.979451f;	val_dir[334*3 + 2] = 0.097945f;
+        val_dir[335*3 + 0] = 0.198968f;	val_dir[335*3 + 1] = -0.974943f;	val_dir[335*3 + 2] = 0.099484f;
+        val_dir[336*3 + 0] = 0.222234f;	val_dir[336*3 + 1] = -0.969746f;	val_dir[336*3 + 2] = 0.101015f;
+        val_dir[337*3 + 0] = 0.246079f;	val_dir[337*3 + 1] = -0.963811f;	val_dir[337*3 + 2] = 0.102533f;
+        val_dir[338*3 + 0] = 0.270481f;	val_dir[338*3 + 1] = -0.957088f;	val_dir[338*3 + 2] = 0.104031f;
+        val_dir[339*3 + 0] = 0.295409f;	val_dir[339*3 + 1] = -0.949528f;	val_dir[339*3 + 2] = 0.105503f;
+        val_dir[340*3 + 0] = 0.320824f;	val_dir[340*3 + 1] = -0.941082f;	val_dir[340*3 + 2] = 0.106941f;
+        val_dir[341*3 + 0] = 0.346681f;	val_dir[341*3 + 1] = -0.931705f;	val_dir[341*3 + 2] = 0.108338f;
+        val_dir[342*3 + 0] = 0.372929f;	val_dir[342*3 + 1] = -0.921354f;	val_dir[342*3 + 2] = 0.109685f;
+        val_dir[343*3 + 0] = 0.399507f;	val_dir[343*3 + 1] = -0.909988f;	val_dir[343*3 + 2] = 0.110974f;
+        val_dir[344*3 + 0] = 0.426348f;	val_dir[344*3 + 1] = -0.897574f;	val_dir[344*3 + 2] = 0.112197f;
+        val_dir[345*3 + 0] = 0.453376f;	val_dir[345*3 + 1] = -0.884083f;	val_dir[345*3 + 2] = 0.113344f;
+        val_dir[346*3 + 0] = 0.480510f;	val_dir[346*3 + 1] = -0.869495f;	val_dir[346*3 + 2] = 0.114407f;
+        val_dir[347*3 + 0] = 0.507662f;	val_dir[347*3 + 1] = -0.853796f;	val_dir[347*3 + 2] = 0.115378f;
+        val_dir[348*3 + 0] = 0.534739f;	val_dir[348*3 + 1] = -0.836983f;	val_dir[348*3 + 2] = 0.116248f;
+        val_dir[349*3 + 0] = 0.561644f;	val_dir[349*3 + 1] = -0.819064f;	val_dir[349*3 + 2] = 0.117009f;
+        val_dir[350*3 + 0] = 0.588276f;	val_dir[350*3 + 1] = -0.800055f;	val_dir[350*3 + 2] = 0.117655f;
+        val_dir[351*3 + 0] = 0.614535f;	val_dir[351*3 + 1] = -0.779987f;	val_dir[351*3 + 2] = 0.118180f;
+        val_dir[352*3 + 0] = 0.640321f;	val_dir[352*3 + 1] = -0.758899f;	val_dir[352*3 + 2] = 0.118578f;
+        val_dir[353*3 + 0] = 0.665536f;	val_dir[353*3 + 1] = -0.736843f;	val_dir[353*3 + 2] = 0.118846f;
+        val_dir[354*3 + 0] = 0.690085f;	val_dir[354*3 + 1] = -0.713881f;	val_dir[354*3 + 2] = 0.118980f;
+        val_dir[355*3 + 0] = 0.713881f;	val_dir[355*3 + 1] = -0.690085f;	val_dir[355*3 + 2] = 0.118980f;
+        val_dir[356*3 + 0] = 0.736843f;	val_dir[356*3 + 1] = -0.665536f;	val_dir[356*3 + 2] = 0.118846f;
+        val_dir[357*3 + 0] = 0.758899f;	val_dir[357*3 + 1] = -0.640321f;	val_dir[357*3 + 2] = 0.118578f;
+        val_dir[358*3 + 0] = 0.779987f;	val_dir[358*3 + 1] = -0.614535f;	val_dir[358*3 + 2] = 0.118180f;
+        val_dir[359*3 + 0] = 0.800055f;	val_dir[359*3 + 1] = -0.588276f;	val_dir[359*3 + 2] = 0.117655f;
+        val_dir[360*3 + 0] = 0.819064f;	val_dir[360*3 + 1] = -0.561644f;	val_dir[360*3 + 2] = 0.117009f;
+        val_dir[361*3 + 0] = 0.836983f;	val_dir[361*3 + 1] = -0.534739f;	val_dir[361*3 + 2] = 0.116248f;
+        val_dir[362*3 + 0] = 0.853796f;	val_dir[362*3 + 1] = -0.507662f;	val_dir[362*3 + 2] = 0.115378f;
+        val_dir[363*3 + 0] = 0.869495f;	val_dir[363*3 + 1] = -0.480510f;	val_dir[363*3 + 2] = 0.114407f;
+        val_dir[364*3 + 0] = 0.884083f;	val_dir[364*3 + 1] = -0.453376f;	val_dir[364*3 + 2] = 0.113344f;
+        val_dir[365*3 + 0] = 0.897574f;	val_dir[365*3 + 1] = -0.426348f;	val_dir[365*3 + 2] = 0.112197f;
+        val_dir[366*3 + 0] = 0.909988f;	val_dir[366*3 + 1] = -0.399507f;	val_dir[366*3 + 2] = 0.110974f;
+        val_dir[367*3 + 0] = 0.921354f;	val_dir[367*3 + 1] = -0.372929f;	val_dir[367*3 + 2] = 0.109685f;
+        val_dir[368*3 + 0] = 0.931705f;	val_dir[368*3 + 1] = -0.346681f;	val_dir[368*3 + 2] = 0.108338f;
+        val_dir[369*3 + 0] = 0.941082f;	val_dir[369*3 + 1] = -0.320824f;	val_dir[369*3 + 2] = 0.106941f;
+        val_dir[370*3 + 0] = 0.949528f;	val_dir[370*3 + 1] = -0.295409f;	val_dir[370*3 + 2] = 0.105503f;
+        val_dir[371*3 + 0] = 0.957088f;	val_dir[371*3 + 1] = -0.270481f;	val_dir[371*3 + 2] = 0.104031f;
+        val_dir[372*3 + 0] = 0.963811f;	val_dir[372*3 + 1] = -0.246079f;	val_dir[372*3 + 2] = 0.102533f;
+        val_dir[373*3 + 0] = 0.969746f;	val_dir[373*3 + 1] = -0.222234f;	val_dir[373*3 + 2] = 0.101015f;
+        val_dir[374*3 + 0] = 0.974943f;	val_dir[374*3 + 1] = -0.198968f;	val_dir[374*3 + 2] = 0.099484f;
+        val_dir[375*3 + 0] = 0.979451f;	val_dir[375*3 + 1] = -0.176301f;	val_dir[375*3 + 2] = 0.097945f;
+        val_dir[376*3 + 0] = 0.983318f;	val_dir[376*3 + 1] = -0.154246f;	val_dir[376*3 + 2] = 0.096404f;
+        val_dir[377*3 + 0] = 0.986591f;	val_dir[377*3 + 1] = -0.132810f;	val_dir[377*3 + 2] = 0.094865f;
+        val_dir[378*3 + 0] = 0.989316f;	val_dir[378*3 + 1] = -0.111998f;	val_dir[378*3 + 2] = 0.093332f;
+        val_dir[379*3 + 0] = 0.991535f;	val_dir[379*3 + 1] = -0.091809f;	val_dir[379*3 + 2] = 0.091809f;
+        val_dir[380*3 + 0] = 0.993291f;	val_dir[380*3 + 1] = -0.072239f;	val_dir[380*3 + 2] = 0.090299f;
+        val_dir[381*3 + 0] = 0.994623f;	val_dir[381*3 + 1] = -0.053283f;	val_dir[381*3 + 2] = 0.088806f;
+        val_dir[382*3 + 0] = 0.995567f;	val_dir[382*3 + 1] = -0.034932f;	val_dir[382*3 + 2] = 0.087330f;
+        val_dir[383*3 + 0] = 0.996158f;	val_dir[383*3 + 1] = -0.017175f;	val_dir[383*3 + 2] = 0.085876f;
+        val_dir[384*3 + 0] = 0.996428f;	val_dir[384*3 + 1] = 0.0f;	val_dir[384*3 + 2] = 0.084443f;
+        val_dir[385*3 + 0] = 0.998614f;	val_dir[385*3 + 1] = 0.016644f;	val_dir[385*3 + 2] = 0.049931f;
+        val_dir[386*3 + 0] = 0.999329f;	val_dir[386*3 + 1] = 0.032765f;	val_dir[386*3 + 2] = 0.016382f;
+        val_dir[387*3 + 0] = -0.049121f;	val_dir[387*3 + 1] = -0.998793f;	val_dir[387*3 + 2] = 0.0f;
+        val_dir[388*3 + 0] = -0.033296f;	val_dir[388*3 + 1] = -0.998891f;	val_dir[388*3 + 2] = 0.033296f;
+        val_dir[389*3 + 0] = -0.016908f;	val_dir[389*3 + 1] = -0.997567f;	val_dir[389*3 + 2] = 0.067632f;
+        val_dir[390*3 + 0] = 0.0f;	val_dir[390*3 + 1] = -0.994692f;	val_dir[390*3 + 2] = 0.102899f;
+        val_dir[391*3 + 0] = 0.017445f;	val_dir[391*3 + 1] = -0.994354f;	val_dir[391*3 + 2] = 0.104669f;
+        val_dir[392*3 + 0] = 0.035489f;	val_dir[392*3 + 1] = -0.993683f;	val_dir[392*3 + 2] = 0.106466f;
+        val_dir[393*3 + 0] = 0.054144f;	val_dir[393*3 + 1] = -0.992644f;	val_dir[393*3 + 2] = 0.108288f;
+        val_dir[394*3 + 0] = 0.073422f;	val_dir[394*3 + 1] = -0.991201f;	val_dir[394*3 + 2] = 0.110133f;
+        val_dir[395*3 + 0] = 0.093332f;	val_dir[395*3 + 1] = -0.989316f;	val_dir[395*3 + 2] = 0.111998f;
+        val_dir[396*3 + 0] = 0.113878f;	val_dir[396*3 + 1] = -0.986947f;	val_dir[396*3 + 2] = 0.113878f;
+        val_dir[397*3 + 0] = 0.135066f;	val_dir[397*3 + 1] = -0.984050f;	val_dir[397*3 + 2] = 0.115771f;
+        val_dir[398*3 + 0] = 0.156893f;	val_dir[398*3 + 1] = -0.980581f;	val_dir[398*3 + 2] = 0.117670f;
+        val_dir[399*3 + 0] = 0.179355f;	val_dir[399*3 + 1] = -0.976491f;	val_dir[399*3 + 2] = 0.119570f;
+        val_dir[400*3 + 0] = 0.202444f;	val_dir[400*3 + 1] = -0.971732f;	val_dir[400*3 + 2] = 0.121466f;
+        val_dir[401*3 + 0] = 0.226144f;	val_dir[401*3 + 1] = -0.966252f;	val_dir[401*3 + 2] = 0.123351f;
+        val_dir[402*3 + 0] = 0.250435f;	val_dir[402*3 + 1] = -0.960001f;	val_dir[402*3 + 2] = 0.125218f;
+        val_dir[403*3 + 0] = 0.275290f;	val_dir[403*3 + 1] = -0.952928f;	val_dir[403*3 + 2] = 0.127057f;
+        val_dir[404*3 + 0] = 0.300676f;	val_dir[404*3 + 1] = -0.944981f;	val_dir[404*3 + 2] = 0.128861f;
+        val_dir[405*3 + 0] = 0.326550f;	val_dir[405*3 + 1] = -0.936111f;	val_dir[405*3 + 2] = 0.130620f;
+        val_dir[406*3 + 0] = 0.352865f;	val_dir[406*3 + 1] = -0.926270f;	val_dir[406*3 + 2] = 0.132324f;
+        val_dir[407*3 + 0] = 0.379563f;	val_dir[407*3 + 1] = -0.915416f;	val_dir[407*3 + 2] = 0.133963f;
+        val_dir[408*3 + 0] = 0.406579f;	val_dir[408*3 + 1] = -0.903508f;	val_dir[408*3 + 2] = 0.135526f;
+        val_dir[409*3 + 0] = 0.433840f;	val_dir[409*3 + 1] = -0.890513f;	val_dir[409*3 + 2] = 0.137002f;
+        val_dir[410*3 + 0] = 0.461266f;	val_dir[410*3 + 1] = -0.876405f;	val_dir[410*3 + 2] = 0.138380f;
+        val_dir[411*3 + 0] = 0.488769f;	val_dir[411*3 + 1] = -0.861164f;	val_dir[411*3 + 2] = 0.139648f;
+        val_dir[412*3 + 0] = 0.516256f;	val_dir[412*3 + 1] = -0.844782f;	val_dir[412*3 + 2] = 0.140797f;
+        val_dir[413*3 + 0] = 0.543627f;	val_dir[413*3 + 1] = -0.827259f;	val_dir[413*3 + 2] = 0.141816f;
+        val_dir[414*3 + 0] = 0.570782f;	val_dir[414*3 + 1] = -0.808608f;	val_dir[414*3 + 2] = 0.142695f;
+        val_dir[415*3 + 0] = 0.597614f;	val_dir[415*3 + 1] = -0.788851f;	val_dir[415*3 + 2] = 0.143427f;
+        val_dir[416*3 + 0] = 0.624020f;	val_dir[416*3 + 1] = -0.768025f;	val_dir[416*3 + 2] = 0.144005f;
+        val_dir[417*3 + 0] = 0.649895f;	val_dir[417*3 + 1] = -0.746176f;	val_dir[417*3 + 2] = 0.144421f;
+        val_dir[418*3 + 0] = 0.675140f;	val_dir[418*3 + 1] = -0.723364f;	val_dir[418*3 + 2] = 0.144673f;
+        val_dir[419*3 + 0] = 0.699659f;	val_dir[419*3 + 1] = -0.699659f;	val_dir[419*3 + 2] = 0.144757f;
+        val_dir[420*3 + 0] = 0.723364f;	val_dir[420*3 + 1] = -0.675140f;	val_dir[420*3 + 2] = 0.144673f;
+        val_dir[421*3 + 0] = 0.746176f;	val_dir[421*3 + 1] = -0.649895f;	val_dir[421*3 + 2] = 0.144421f;
+        val_dir[422*3 + 0] = 0.768025f;	val_dir[422*3 + 1] = -0.624020f;	val_dir[422*3 + 2] = 0.144005f;
+        val_dir[423*3 + 0] = 0.788851f;	val_dir[423*3 + 1] = -0.597614f;	val_dir[423*3 + 2] = 0.143427f;
+        val_dir[424*3 + 0] = 0.808608f;	val_dir[424*3 + 1] = -0.570782f;	val_dir[424*3 + 2] = 0.142695f;
+        val_dir[425*3 + 0] = 0.827259f;	val_dir[425*3 + 1] = -0.543627f;	val_dir[425*3 + 2] = 0.141816f;
+        val_dir[426*3 + 0] = 0.844782f;	val_dir[426*3 + 1] = -0.516256f;	val_dir[426*3 + 2] = 0.140797f;
+        val_dir[427*3 + 0] = 0.861164f;	val_dir[427*3 + 1] = -0.488769f;	val_dir[427*3 + 2] = 0.139648f;
+        val_dir[428*3 + 0] = 0.876405f;	val_dir[428*3 + 1] = -0.461266f;	val_dir[428*3 + 2] = 0.138380f;
+        val_dir[429*3 + 0] = 0.890513f;	val_dir[429*3 + 1] = -0.433840f;	val_dir[429*3 + 2] = 0.137002f;
+        val_dir[430*3 + 0] = 0.903508f;	val_dir[430*3 + 1] = -0.406579f;	val_dir[430*3 + 2] = 0.135526f;
+        val_dir[431*3 + 0] = 0.915416f;	val_dir[431*3 + 1] = -0.379563f;	val_dir[431*3 + 2] = 0.133963f;
+        val_dir[432*3 + 0] = 0.926270f;	val_dir[432*3 + 1] = -0.352865f;	val_dir[432*3 + 2] = 0.132324f;
+        val_dir[433*3 + 0] = 0.936111f;	val_dir[433*3 + 1] = -0.326550f;	val_dir[433*3 + 2] = 0.130620f;
+        val_dir[434*3 + 0] = 0.944981f;	val_dir[434*3 + 1] = -0.300676f;	val_dir[434*3 + 2] = 0.128861f;
+        val_dir[435*3 + 0] = 0.952928f;	val_dir[435*3 + 1] = -0.275290f;	val_dir[435*3 + 2] = 0.127057f;
+        val_dir[436*3 + 0] = 0.960001f;	val_dir[436*3 + 1] = -0.250435f;	val_dir[436*3 + 2] = 0.125218f;
+        val_dir[437*3 + 0] = 0.966252f;	val_dir[437*3 + 1] = -0.226144f;	val_dir[437*3 + 2] = 0.123351f;
+        val_dir[438*3 + 0] = 0.971732f;	val_dir[438*3 + 1] = -0.202444f;	val_dir[438*3 + 2] = 0.121466f;
+        val_dir[439*3 + 0] = 0.976491f;	val_dir[439*3 + 1] = -0.179355f;	val_dir[439*3 + 2] = 0.119570f;
+        val_dir[440*3 + 0] = 0.980581f;	val_dir[440*3 + 1] = -0.156893f;	val_dir[440*3 + 2] = 0.117670f;
+        val_dir[441*3 + 0] = 0.984050f;	val_dir[441*3 + 1] = -0.135066f;	val_dir[441*3 + 2] = 0.115771f;
+        val_dir[442*3 + 0] = 0.986947f;	val_dir[442*3 + 1] = -0.113878f;	val_dir[442*3 + 2] = 0.113878f;
+        val_dir[443*3 + 0] = 0.989316f;	val_dir[443*3 + 1] = -0.093332f;	val_dir[443*3 + 2] = 0.111998f;
+        val_dir[444*3 + 0] = 0.991201f;	val_dir[444*3 + 1] = -0.073422f;	val_dir[444*3 + 2] = 0.110133f;
+        val_dir[445*3 + 0] = 0.992644f;	val_dir[445*3 + 1] = -0.054144f;	val_dir[445*3 + 2] = 0.108288f;
+        val_dir[446*3 + 0] = 0.993683f;	val_dir[446*3 + 1] = -0.035489f;	val_dir[446*3 + 2] = 0.106466f;
+        val_dir[447*3 + 0] = 0.994354f;	val_dir[447*3 + 1] = -0.017445f;	val_dir[447*3 + 2] = 0.104669f;
+        val_dir[448*3 + 0] = 0.994692f;	val_dir[448*3 + 1] = 0.0f;	val_dir[448*3 + 2] = 0.102899f;
+        val_dir[449*3 + 0] = 0.997567f;	val_dir[449*3 + 1] = 0.016908f;	val_dir[449*3 + 2] = 0.067632f;
+        val_dir[450*3 + 0] = 0.998891f;	val_dir[450*3 + 1] = 0.033296f;	val_dir[450*3 + 2] = 0.033296f;
+        val_dir[451*3 + 0] = 0.998793f;	val_dir[451*3 + 1] = 0.049121f;	val_dir[451*3 + 2] = 0.0f;
+        val_dir[452*3 + 0] = -0.049931f;	val_dir[452*3 + 1] = -0.998614f;	val_dir[452*3 + 2] = 0.016644f;
+        val_dir[453*3 + 0] = -0.033835f;	val_dir[453*3 + 1] = -0.998138f;	val_dir[453*3 + 2] = 0.050753f;
+        val_dir[454*3 + 0] = -0.017175f;	val_dir[454*3 + 1] = -0.996158f;	val_dir[454*3 + 2] = 0.085876f;
+        val_dir[455*3 + 0] = 0.0f;	val_dir[455*3 + 1] = -0.992543f;	val_dir[455*3 + 2] = 0.121891f;
+        val_dir[456*3 + 0] = 0.017716f;	val_dir[456*3 + 1] = -0.992122f;	val_dir[456*3 + 2] = 0.124015f;
+        val_dir[457*3 + 0] = 0.036049f;	val_dir[457*3 + 1] = -0.991353f;	val_dir[457*3 + 2] = 0.126172f;
+        val_dir[458*3 + 0] = 0.055011f;	val_dir[458*3 + 1] = -0.990201f;	val_dir[458*3 + 2] = 0.128359f;
+        val_dir[459*3 + 0] = 0.074613f;	val_dir[459*3 + 1] = -0.988627f;	val_dir[459*3 + 2] = 0.130573f;
+        val_dir[460*3 + 0] = 0.094865f;	val_dir[460*3 + 1] = -0.986591f;	val_dir[460*3 + 2] = 0.132810f;
+        val_dir[461*3 + 0] = 0.115771f;	val_dir[461*3 + 1] = -0.984050f;	val_dir[461*3 + 2] = 0.135066f;
+        val_dir[462*3 + 0] = 0.137334f;	val_dir[462*3 + 1] = -0.980958f;	val_dir[462*3 + 2] = 0.137334f;
+        val_dir[463*3 + 0] = 0.159554f;	val_dir[463*3 + 1] = -0.977267f;	val_dir[463*3 + 2] = 0.139610f;
+        val_dir[464*3 + 0] = 0.182424f;	val_dir[464*3 + 1] = -0.972929f;	val_dir[464*3 + 2] = 0.141885f;
+        val_dir[465*3 + 0] = 0.205934f;	val_dir[465*3 + 1] = -0.967890f;	val_dir[465*3 + 2] = 0.144154f;
+        val_dir[466*3 + 0] = 0.230067f;	val_dir[466*3 + 1] = -0.962099f;	val_dir[466*3 + 2] = 0.146406f;
+        val_dir[467*3 + 0] = 0.254801f;	val_dir[467*3 + 1] = -0.955502f;	val_dir[467*3 + 2] = 0.148634f;
+        val_dir[468*3 + 0] = 0.280105f;	val_dir[468*3 + 1] = -0.948047f;	val_dir[468*3 + 2] = 0.150826f;
+        val_dir[469*3 + 0] = 0.305942f;	val_dir[469*3 + 1] = -0.939680f;	val_dir[469*3 + 2] = 0.152971f;
+        val_dir[470*3 + 0] = 0.332269f;	val_dir[470*3 + 1] = -0.930352f;	val_dir[470*3 + 2] = 0.155059f;
+        val_dir[471*3 + 0] = 0.359030f;	val_dir[471*3 + 1] = -0.920014f;	val_dir[471*3 + 2] = 0.157075f;
+        val_dir[472*3 + 0] = 0.386164f;	val_dir[472*3 + 1] = -0.908622f;	val_dir[472*3 + 2] = 0.159009f;
+        val_dir[473*3 + 0] = 0.413602f;	val_dir[473*3 + 1] = -0.896137f;	val_dir[473*3 + 2] = 0.160845f;
+        val_dir[474*3 + 0] = 0.441264f;	val_dir[474*3 + 1] = -0.882528f;	val_dir[474*3 + 2] = 0.162571f;
+        val_dir[475*3 + 0] = 0.469065f;	val_dir[475*3 + 1] = -0.867770f;	val_dir[475*3 + 2] = 0.164173f;
+        val_dir[476*3 + 0] = 0.496911f;	val_dir[476*3 + 1] = -0.851847f;	val_dir[476*3 + 2] = 0.165637f;
+        val_dir[477*3 + 0] = 0.524703f;	val_dir[477*3 + 1] = -0.834754f;	val_dir[477*3 + 2] = 0.166951f;
+        val_dir[478*3 + 0] = 0.552336f;	val_dir[478*3 + 1] = -0.816497f;	val_dir[478*3 + 2] = 0.168102f;
+        val_dir[479*3 + 0] = 0.579703f;	val_dir[479*3 + 1] = -0.797092f;	val_dir[479*3 + 2] = 0.169080f;
+        val_dir[480*3 + 0] = 0.606696f;	val_dir[480*3 + 1] = -0.776571f;	val_dir[480*3 + 2] = 0.169875f;
+        val_dir[481*3 + 0] = 0.633205f;	val_dir[481*3 + 1] = -0.754976f;	val_dir[481*3 + 2] = 0.170478f;
+        val_dir[482*3 + 0] = 0.659125f;	val_dir[482*3 + 1] = -0.732361f;	val_dir[482*3 + 2] = 0.170884f;
+        val_dir[483*3 + 0] = 0.684353f;	val_dir[483*3 + 1] = -0.708794f;	val_dir[483*3 + 2] = 0.171088f;
+        val_dir[484*3 + 0] = 0.708794f;	val_dir[484*3 + 1] = -0.684353f;	val_dir[484*3 + 2] = 0.171088f;
+        val_dir[485*3 + 0] = 0.732361f;	val_dir[485*3 + 1] = -0.659125f;	val_dir[485*3 + 2] = 0.170884f;
+        val_dir[486*3 + 0] = 0.754976f;	val_dir[486*3 + 1] = -0.633205f;	val_dir[486*3 + 2] = 0.170478f;
+        val_dir[487*3 + 0] = 0.776571f;	val_dir[487*3 + 1] = -0.606696f;	val_dir[487*3 + 2] = 0.169875f;
+        val_dir[488*3 + 0] = 0.797092f;	val_dir[488*3 + 1] = -0.579703f;	val_dir[488*3 + 2] = 0.169080f;
+        val_dir[489*3 + 0] = 0.816497f;	val_dir[489*3 + 1] = -0.552336f;	val_dir[489*3 + 2] = 0.168102f;
+        val_dir[490*3 + 0] = 0.834754f;	val_dir[490*3 + 1] = -0.524703f;	val_dir[490*3 + 2] = 0.166951f;
+        val_dir[491*3 + 0] = 0.851847f;	val_dir[491*3 + 1] = -0.496911f;	val_dir[491*3 + 2] = 0.165637f;
+        val_dir[492*3 + 0] = 0.867770f;	val_dir[492*3 + 1] = -0.469065f;	val_dir[492*3 + 2] = 0.164173f;
+        val_dir[493*3 + 0] = 0.882528f;	val_dir[493*3 + 1] = -0.441264f;	val_dir[493*3 + 2] = 0.162571f;
+        val_dir[494*3 + 0] = 0.896137f;	val_dir[494*3 + 1] = -0.413602f;	val_dir[494*3 + 2] = 0.160845f;
+        val_dir[495*3 + 0] = 0.908622f;	val_dir[495*3 + 1] = -0.386164f;	val_dir[495*3 + 2] = 0.159009f;
+        val_dir[496*3 + 0] = 0.920014f;	val_dir[496*3 + 1] = -0.359030f;	val_dir[496*3 + 2] = 0.157075f;
+        val_dir[497*3 + 0] = 0.930352f;	val_dir[497*3 + 1] = -0.332269f;	val_dir[497*3 + 2] = 0.155059f;
+        val_dir[498*3 + 0] = 0.939680f;	val_dir[498*3 + 1] = -0.305942f;	val_dir[498*3 + 2] = 0.152971f;
+        val_dir[499*3 + 0] = 0.948047f;	val_dir[499*3 + 1] = -0.280105f;	val_dir[499*3 + 2] = 0.150826f;
+        val_dir[500*3 + 0] = 0.955502f;	val_dir[500*3 + 1] = -0.254801f;	val_dir[500*3 + 2] = 0.148634f;
+        val_dir[501*3 + 0] = 0.962099f;	val_dir[501*3 + 1] = -0.230067f;	val_dir[501*3 + 2] = 0.146406f;
+        val_dir[502*3 + 0] = 0.967890f;	val_dir[502*3 + 1] = -0.205934f;	val_dir[502*3 + 2] = 0.144154f;
+        val_dir[503*3 + 0] = 0.972929f;	val_dir[503*3 + 1] = -0.182424f;	val_dir[503*3 + 2] = 0.141885f;
+        val_dir[504*3 + 0] = 0.977267f;	val_dir[504*3 + 1] = -0.159554f;	val_dir[504*3 + 2] = 0.139610f;
+        val_dir[505*3 + 0] = 0.980958f;	val_dir[505*3 + 1] = -0.137334f;	val_dir[505*3 + 2] = 0.137334f;
+        val_dir[506*3 + 0] = 0.984050f;	val_dir[506*3 + 1] = -0.115771f;	val_dir[506*3 + 2] = 0.135066f;
+        val_dir[507*3 + 0] = 0.986591f;	val_dir[507*3 + 1] = -0.094865f;	val_dir[507*3 + 2] = 0.132810f;
+        val_dir[508*3 + 0] = 0.988627f;	val_dir[508*3 + 1] = -0.074613f;	val_dir[508*3 + 2] = 0.130573f;
+        val_dir[509*3 + 0] = 0.990201f;	val_dir[509*3 + 1] = -0.055011f;	val_dir[509*3 + 2] = 0.128359f;
+        val_dir[510*3 + 0] = 0.991353f;	val_dir[510*3 + 1] = -0.036049f;	val_dir[510*3 + 2] = 0.126172f;
+        val_dir[511*3 + 0] = 0.992122f;	val_dir[511*3 + 1] = -0.017716f;	val_dir[511*3 + 2] = 0.124015f;
+        val_dir[512*3 + 0] = 0.992543f;	val_dir[512*3 + 1] = 0.0f;	val_dir[512*3 + 2] = 0.121891f;
+        val_dir[513*3 + 0] = 0.996158f;	val_dir[513*3 + 1] = 0.017175f;	val_dir[513*3 + 2] = 0.085876f;
+        val_dir[514*3 + 0] = 0.998138f;	val_dir[514*3 + 1] = 0.033835f;	val_dir[514*3 + 2] = 0.050753f;
+        val_dir[515*3 + 0] = 0.998614f;	val_dir[515*3 + 1] = 0.049931f;	val_dir[515*3 + 2] = 0.016644f;
+        val_dir[516*3 + 0] = -0.066519f;	val_dir[516*3 + 1] = -0.997785f;	val_dir[516*3 + 2] = 0.0f;
+        val_dir[517*3 + 0] = -0.050753f;	val_dir[517*3 + 1] = -0.998138f;	val_dir[517*3 + 2] = 0.033835f;
+        val_dir[518*3 + 0] = -0.034381f;	val_dir[518*3 + 1] = -0.997041f;	val_dir[518*3 + 2] = 0.068761f;
+        val_dir[519*3 + 0] = -0.017445f;	val_dir[519*3 + 1] = -0.994354f;	val_dir[519*3 + 2] = 0.104669f;
+        val_dir[520*3 + 0] = 0.0f;	val_dir[520*3 + 1] = -0.989949f;	val_dir[520*3 + 2] = 0.141421f;
+        val_dir[521*3 + 0] = 0.017990f;	val_dir[521*3 + 1] = -0.989426f;	val_dir[521*3 + 2] = 0.143917f;
+        val_dir[522*3 + 0] = 0.036613f;	val_dir[522*3 + 1] = -0.988540f;	val_dir[522*3 + 2] = 0.146450f;
+        val_dir[523*3 + 0] = 0.055882f;	val_dir[523*3 + 1] = -0.987254f;	val_dir[523*3 + 2] = 0.149019f;
+        val_dir[524*3 + 0] = 0.075810f;	val_dir[524*3 + 1] = -0.985527f;	val_dir[524*3 + 2] = 0.151620f;
+        val_dir[525*3 + 0] = 0.096404f;	val_dir[525*3 + 1] = -0.983318f;	val_dir[525*3 + 2] = 0.154246f;
+        val_dir[526*3 + 0] = 0.117670f;	val_dir[526*3 + 1] = -0.980581f;	val_dir[526*3 + 2] = 0.156893f;
+        val_dir[527*3 + 0] = 0.139610f;	val_dir[527*3 + 1] = -0.977267f;	val_dir[527*3 + 2] = 0.159554f;
+        val_dir[528*3 + 0] = 0.162221f;	val_dir[528*3 + 1] = -0.973329f;	val_dir[528*3 + 2] = 0.162221f;
+        val_dir[529*3 + 0] = 0.185498f;	val_dir[529*3 + 1] = -0.968712f;	val_dir[529*3 + 2] = 0.164887f;
+        val_dir[530*3 + 0] = 0.209427f;	val_dir[530*3 + 1] = -0.963364f;	val_dir[530*3 + 2] = 0.167542f;
+        val_dir[531*3 + 0] = 0.233990f;	val_dir[531*3 + 1] = -0.957230f;	val_dir[531*3 + 2] = 0.170174f;
+        val_dir[532*3 + 0] = 0.259161f;	val_dir[532*3 + 1] = -0.950255f;	val_dir[532*3 + 2] = 0.172774f;
+        val_dir[533*3 + 0] = 0.284907f;	val_dir[533*3 + 1] = -0.942384f;	val_dir[533*3 + 2] = 0.175327f;
+        val_dir[534*3 + 0] = 0.311188f;	val_dir[534*3 + 1] = -0.933564f;	val_dir[534*3 + 2] = 0.177822f;
+        val_dir[535*3 + 0] = 0.337954f;	val_dir[535*3 + 1] = -0.923742f;	val_dir[535*3 + 2] = 0.180242f;
+        val_dir[536*3 + 0] = 0.365148f;	val_dir[536*3 + 1] = -0.912871f;	val_dir[536*3 + 2] = 0.182574f;
+        val_dir[537*3 + 0] = 0.392703f;	val_dir[537*3 + 1] = -0.900907f;	val_dir[537*3 + 2] = 0.184801f;
+        val_dir[538*3 + 0] = 0.420542f;	val_dir[538*3 + 1] = -0.887812f;	val_dir[538*3 + 2] = 0.186908f;
+        val_dir[539*3 + 0] = 0.448583f;	val_dir[539*3 + 1] = -0.873555f;	val_dir[539*3 + 2] = 0.188877f;
+        val_dir[540*3 + 0] = 0.476731f;	val_dir[540*3 + 1] = -0.858116f;	val_dir[540*3 + 2] = 0.190693f;
+        val_dir[541*3 + 0] = 0.504889f;	val_dir[541*3 + 1] = -0.841482f;	val_dir[541*3 + 2] = 0.192339f;
+        val_dir[542*3 + 0] = 0.532952f;	val_dir[542*3 + 1] = -0.823653f;	val_dir[542*3 + 2] = 0.193801f;
+        val_dir[543*3 + 0] = 0.560809f;	val_dir[543*3 + 1] = -0.804639f;	val_dir[543*3 + 2] = 0.195064f;
+        val_dir[544*3 + 0] = 0.588348f;	val_dir[544*3 + 1] = -0.784465f;	val_dir[544*3 + 2] = 0.196116f;
+        val_dir[545*3 + 0] = 0.615457f;	val_dir[545*3 + 1] = -0.763167f;	val_dir[545*3 + 2] = 0.196946f;
+        val_dir[546*3 + 0] = 0.642024f;	val_dir[546*3 + 1] = -0.740797f;	val_dir[546*3 + 2] = 0.197546f;
+        val_dir[547*3 + 0] = 0.667940f;	val_dir[547*3 + 1] = -0.717418f;	val_dir[547*3 + 2] = 0.197908f;
+        val_dir[548*3 + 0] = 0.693103f;	val_dir[548*3 + 1] = -0.693103f;	val_dir[548*3 + 2] = 0.198030f;
+        val_dir[549*3 + 0] = 0.717418f;	val_dir[549*3 + 1] = -0.667940f;	val_dir[549*3 + 2] = 0.197908f;
+        val_dir[550*3 + 0] = 0.740797f;	val_dir[550*3 + 1] = -0.642024f;	val_dir[550*3 + 2] = 0.197546f;
+        val_dir[551*3 + 0] = 0.763167f;	val_dir[551*3 + 1] = -0.615457f;	val_dir[551*3 + 2] = 0.196946f;
+        val_dir[552*3 + 0] = 0.784465f;	val_dir[552*3 + 1] = -0.588348f;	val_dir[552*3 + 2] = 0.196116f;
+        val_dir[553*3 + 0] = 0.804639f;	val_dir[553*3 + 1] = -0.560809f;	val_dir[553*3 + 2] = 0.195064f;
+        val_dir[554*3 + 0] = 0.823653f;	val_dir[554*3 + 1] = -0.532952f;	val_dir[554*3 + 2] = 0.193801f;
+        val_dir[555*3 + 0] = 0.841482f;	val_dir[555*3 + 1] = -0.504889f;	val_dir[555*3 + 2] = 0.192339f;
+        val_dir[556*3 + 0] = 0.858116f;	val_dir[556*3 + 1] = -0.476731f;	val_dir[556*3 + 2] = 0.190693f;
+        val_dir[557*3 + 0] = 0.873555f;	val_dir[557*3 + 1] = -0.448583f;	val_dir[557*3 + 2] = 0.188877f;
+        val_dir[558*3 + 0] = 0.887812f;	val_dir[558*3 + 1] = -0.420542f;	val_dir[558*3 + 2] = 0.186908f;
+        val_dir[559*3 + 0] = 0.900907f;	val_dir[559*3 + 1] = -0.392703f;	val_dir[559*3 + 2] = 0.184801f;
+        val_dir[560*3 + 0] = 0.912871f;	val_dir[560*3 + 1] = -0.365148f;	val_dir[560*3 + 2] = 0.182574f;
+        val_dir[561*3 + 0] = 0.923742f;	val_dir[561*3 + 1] = -0.337954f;	val_dir[561*3 + 2] = 0.180242f;
+        val_dir[562*3 + 0] = 0.933564f;	val_dir[562*3 + 1] = -0.311188f;	val_dir[562*3 + 2] = 0.177822f;
+        val_dir[563*3 + 0] = 0.942384f;	val_dir[563*3 + 1] = -0.284907f;	val_dir[563*3 + 2] = 0.175327f;
+        val_dir[564*3 + 0] = 0.950255f;	val_dir[564*3 + 1] = -0.259161f;	val_dir[564*3 + 2] = 0.172774f;
+        val_dir[565*3 + 0] = 0.957230f;	val_dir[565*3 + 1] = -0.233990f;	val_dir[565*3 + 2] = 0.170174f;
+        val_dir[566*3 + 0] = 0.963364f;	val_dir[566*3 + 1] = -0.209427f;	val_dir[566*3 + 2] = 0.167542f;
+        val_dir[567*3 + 0] = 0.968712f;	val_dir[567*3 + 1] = -0.185498f;	val_dir[567*3 + 2] = 0.164887f;
+        val_dir[568*3 + 0] = 0.973329f;	val_dir[568*3 + 1] = -0.162221f;	val_dir[568*3 + 2] = 0.162221f;
+        val_dir[569*3 + 0] = 0.977267f;	val_dir[569*3 + 1] = -0.139610f;	val_dir[569*3 + 2] = 0.159554f;
+        val_dir[570*3 + 0] = 0.980581f;	val_dir[570*3 + 1] = -0.117670f;	val_dir[570*3 + 2] = 0.156893f;
+        val_dir[571*3 + 0] = 0.983318f;	val_dir[571*3 + 1] = -0.096404f;	val_dir[571*3 + 2] = 0.154246f;
+ 	val_dir[572*3 + 0] = 0.985527f;	val_dir[572*3 + 1] = -0.075810f;	val_dir[572*3 + 2] = 0.151620f;
+ 	val_dir[573*3 + 0] = 0.987254f;	val_dir[573*3 + 1] = -0.055882f;	val_dir[573*3 + 2] = 0.149019f;
+ 	val_dir[574*3 + 0] = 0.988540f;	val_dir[574*3 + 1] = -0.036613f;	val_dir[574*3 + 2] = 0.146450f;
+ 	val_dir[575*3 + 0] = 0.989426f;	val_dir[575*3 + 1] = -0.017990f;	val_dir[575*3 + 2] = 0.143917f;
+ 	val_dir[576*3 + 0] = 0.989949f;	val_dir[576*3 + 1] = 0.0f;	val_dir[576*3 + 2] = 0.141421f;
+ 	val_dir[577*3 + 0] = 0.994354f;	val_dir[577*3 + 1] = 0.017445f;	val_dir[577*3 + 2] = 0.104669f;
+ 	val_dir[578*3 + 0] = 0.997041f;	val_dir[578*3 + 1] = 0.034381f;	val_dir[578*3 + 2] = 0.068761f;
+ 	val_dir[579*3 + 0] = 0.998138f;	val_dir[579*3 + 1] = 0.050753f;	val_dir[579*3 + 2] = 0.033835f;
+ 	val_dir[580*3 + 0] = 0.997785f;	val_dir[580*3 + 1] = 0.066519f;	val_dir[580*3 + 2] = 0.0f;
+ 	val_dir[581*3 + 0] = -0.067632f;	val_dir[581*3 + 1] = -0.997567f;	val_dir[581*3 + 2] = 0.016908f;
+ 	val_dir[582*3 + 0] = -0.051586f;	val_dir[582*3 + 1] = -0.997335f;	val_dir[582*3 + 2] = 0.051586f;
+ 	val_dir[583*3 + 0] = -0.034932f;	val_dir[583*3 + 1] = -0.995567f;	val_dir[583*3 + 2] = 0.087330f;
+ 	val_dir[584*3 + 0] = -0.017716f;	val_dir[584*3 + 1] = -0.992122f;	val_dir[584*3 + 2] = 0.124015f;
+ 	val_dir[585*3 + 0] = 0.0f;	val_dir[585*3 + 1] = -0.986875f;	val_dir[585*3 + 2] = 0.161489f;
+ 	val_dir[586*3 + 0] = 0.018264f;	val_dir[586*3 + 1] = -0.986229f;	val_dir[586*3 + 2] = 0.164372f;
+ 	val_dir[587*3 + 0] = 0.037178f;	val_dir[587*3 + 1] = -0.985205f;	val_dir[587*3 + 2] = 0.167299f;
+ 	val_dir[588*3 + 0] = 0.056756f;	val_dir[588*3 + 1] = -0.983762f;	val_dir[588*3 + 2] = 0.170267f;
+ 	val_dir[589*3 + 0] = 0.077009f;	val_dir[589*3 + 1] = -0.981859f;	val_dir[589*3 + 2] = 0.173269f;
+ 	val_dir[590*3 + 0] = 0.097945f;	val_dir[590*3 + 1] = -0.979451f;	val_dir[590*3 + 2] = 0.176301f;
+ 	val_dir[591*3 + 0] = 0.119570f;	val_dir[591*3 + 1] = -0.976491f;	val_dir[591*3 + 2] = 0.179355f;
+ 	val_dir[592*3 + 0] = 0.141885f;	val_dir[592*3 + 1] = -0.972929f;	val_dir[592*3 + 2] = 0.182424f;
+ 	val_dir[593*3 + 0] = 0.164887f;	val_dir[593*3 + 1] = -0.968712f;	val_dir[593*3 + 2] = 0.185498f;
+ 	val_dir[594*3 + 0] = 0.188567f;	val_dir[594*3 + 1] = -0.963787f;	val_dir[594*3 + 2] = 0.188567f;
+ 	val_dir[595*3 + 0] = 0.212911f;	val_dir[595*3 + 1] = -0.958098f;	val_dir[595*3 + 2] = 0.191620f;
+ 	val_dir[596*3 + 0] = 0.237897f;	val_dir[596*3 + 1] = -0.951588f;	val_dir[596*3 + 2] = 0.194643f;
+ 	val_dir[597*3 + 0] = 0.263498f;	val_dir[597*3 + 1] = -0.94420f;	val_dir[597*3 + 2] = 0.197623f;
+ 	val_dir[598*3 + 0] = 0.289677f;	val_dir[598*3 + 1] = -0.935879f;	val_dir[598*3 + 2] = 0.200545f;
+ 	val_dir[599*3 + 0] = 0.316389f;	val_dir[599*3 + 1] = -0.926568f;	val_dir[599*3 + 2] = 0.203393f;
+ 	val_dir[600*3 + 0] = 0.343582f;	val_dir[600*3 + 1] = -0.916217f;	val_dir[600*3 + 2] = 0.206149f;
+ 	val_dir[601*3 + 0] = 0.371191f;	val_dir[601*3 + 1] = -0.904777f;	val_dir[601*3 + 2] = 0.208795f;
+ 	val_dir[602*3 + 0] = 0.399145f;	val_dir[602*3 + 1] = -0.892206f;	val_dir[602*3 + 2] = 0.211312f;
+ 	val_dir[603*3 + 0] = 0.427362f;	val_dir[603*3 + 1] = -0.878466f;	val_dir[603*3 + 2] = 0.213681f;
+ 	val_dir[604*3 + 0] = 0.455752f;	val_dir[604*3 + 1] = -0.863530f;	val_dir[604*3 + 2] = 0.215883f;
+ 	val_dir[605*3 + 0] = 0.484217f;	val_dir[605*3 + 1] = -0.847381f;	val_dir[605*3 + 2] = 0.217898f;
+ 	val_dir[606*3 + 0] = 0.512653f;	val_dir[606*3 + 1] = -0.830009f;	val_dir[606*3 + 2] = 0.219708f;
+ 	val_dir[607*3 + 0] = 0.540947f;	val_dir[607*3 + 1] = -0.811421f;	val_dir[607*3 + 2] = 0.221297f;
+ 	val_dir[608*3 + 0] = 0.568986f;	val_dir[608*3 + 1] = -0.791633f;	val_dir[608*3 + 2] = 0.222647f;
+ 	val_dir[609*3 + 0] = 0.596653f;	val_dir[609*3 + 1] = -0.770677f;	val_dir[609*3 + 2] = 0.223745f;
+ 	val_dir[610*3 + 0] = 0.623831f;	val_dir[610*3 + 1] = -0.748598f;	val_dir[610*3 + 2] = 0.224579f;
+ 	val_dir[611*3 + 0] = 0.650407f;	val_dir[611*3 + 1] = -0.725454f;	val_dir[611*3 + 2] = 0.225141f;
+ 	val_dir[612*3 + 0] = 0.676269f;	val_dir[612*3 + 1] = -0.701316f;	val_dir[612*3 + 2] = 0.225423f;
+ 	val_dir[613*3 + 0] = 0.701316f;	val_dir[613*3 + 1] = -0.676269f;	val_dir[613*3 + 2] = 0.225423f;
+ 	val_dir[614*3 + 0] = 0.725454f;	val_dir[614*3 + 1] = -0.650407f;	val_dir[614*3 + 2] = 0.225141f;
+ 	val_dir[615*3 + 0] = 0.748598f;	val_dir[615*3 + 1] = -0.623831f;	val_dir[615*3 + 2] = 0.224579f;
+ 	val_dir[616*3 + 0] = 0.770677f;	val_dir[616*3 + 1] = -0.596653f;	val_dir[616*3 + 2] = 0.223745f;
+ 	val_dir[617*3 + 0] = 0.791633f;	val_dir[617*3 + 1] = -0.568986f;	val_dir[617*3 + 2] = 0.222647f;
+ 	val_dir[618*3 + 0] = 0.811421f;	val_dir[618*3 + 1] = -0.540947f;	val_dir[618*3 + 2] = 0.221297f;
+ 	val_dir[619*3 + 0] = 0.830009f;	val_dir[619*3 + 1] = -0.512653f;	val_dir[619*3 + 2] = 0.219708f;
+ 	val_dir[620*3 + 0] = 0.847381f;	val_dir[620*3 + 1] = -0.484217f;	val_dir[620*3 + 2] = 0.217898f;
+ 	val_dir[621*3 + 0] = 0.863530f;	val_dir[621*3 + 1] = -0.455752f;	val_dir[621*3 + 2] = 0.215883f;
+ 	val_dir[622*3 + 0] = 0.878466f;	val_dir[622*3 + 1] = -0.427362f;	val_dir[622*3 + 2] = 0.213681f;
+ 	val_dir[623*3 + 0] = 0.892206f;	val_dir[623*3 + 1] = -0.399145f;	val_dir[623*3 + 2] = 0.211312f;
+ 	val_dir[624*3 + 0] = 0.904777f;	val_dir[624*3 + 1] = -0.371191f;	val_dir[624*3 + 2] = 0.208795f;
+ 	val_dir[625*3 + 0] = 0.916217f;	val_dir[625*3 + 1] = -0.343582f;	val_dir[625*3 + 2] = 0.206149f;
+ 	val_dir[626*3 + 0] = 0.926568f;	val_dir[626*3 + 1] = -0.316389f;	val_dir[626*3 + 2] = 0.203393f;
+ 	val_dir[627*3 + 0] = 0.935879f;	val_dir[627*3 + 1] = -0.289677f;	val_dir[627*3 + 2] = 0.200545f;
+ 	val_dir[628*3 + 0] = 0.94420f;	val_dir[628*3 + 1] = -0.263498f;	val_dir[628*3 + 2] = 0.197623f;
+ 	val_dir[629*3 + 0] = 0.951588f;	val_dir[629*3 + 1] = -0.237897f;	val_dir[629*3 + 2] = 0.194643f;
+ 	val_dir[630*3 + 0] = 0.958098f;	val_dir[630*3 + 1] = -0.212911f;	val_dir[630*3 + 2] = 0.191620f;
+ 	val_dir[631*3 + 0] = 0.963787f;	val_dir[631*3 + 1] = -0.188567f;	val_dir[631*3 + 2] = 0.188567f;
+ 	val_dir[632*3 + 0] = 0.968712f;	val_dir[632*3 + 1] = -0.164887f;	val_dir[632*3 + 2] = 0.185498f;
+ 	val_dir[633*3 + 0] = 0.972929f;	val_dir[633*3 + 1] = -0.141885f;	val_dir[633*3 + 2] = 0.182424f;
+ 	val_dir[634*3 + 0] = 0.976491f;	val_dir[634*3 + 1] = -0.119570f;	val_dir[634*3 + 2] = 0.179355f;
+ 	val_dir[635*3 + 0] = 0.979451f;	val_dir[635*3 + 1] = -0.097945f;	val_dir[635*3 + 2] = 0.176301f;
+ 	val_dir[636*3 + 0] = 0.981859f;	val_dir[636*3 + 1] = -0.077009f;	val_dir[636*3 + 2] = 0.173269f;
+ 	val_dir[637*3 + 0] = 0.983762f;	val_dir[637*3 + 1] = -0.056756f;	val_dir[637*3 + 2] = 0.170267f;
+ 	val_dir[638*3 + 0] = 0.985205f;	val_dir[638*3 + 1] = -0.037178f;	val_dir[638*3 + 2] = 0.167299f;
+ 	val_dir[639*3 + 0] = 0.986229f;	val_dir[639*3 + 1] = -0.018264f;	val_dir[639*3 + 2] = 0.164372f;
+ 	val_dir[640*3 + 0] = 0.986875f;	val_dir[640*3 + 1] = 0.0f;	val_dir[640*3 + 2] = 0.161489f;
+ 	val_dir[641*3 + 0] = 0.992122f;	val_dir[641*3 + 1] = 0.017716f;	val_dir[641*3 + 2] = 0.124015f;
+ 	val_dir[642*3 + 0] = 0.995567f;	val_dir[642*3 + 1] = 0.034932f;	val_dir[642*3 + 2] = 0.087330f;
+ 	val_dir[643*3 + 0] = 0.997335f;	val_dir[643*3 + 1] = 0.051586f;	val_dir[643*3 + 2] = 0.051586f;
+ 	val_dir[644*3 + 0] = 0.997567f;	val_dir[644*3 + 1] = 0.067632f;	val_dir[644*3 + 2] = 0.016908f;
+ 	val_dir[645*3 + 0] = -0.084443f;	val_dir[645*3 + 1] = -0.996428f;	val_dir[645*3 + 2] = 0.0f;
+ 	val_dir[646*3 + 0] = -0.068761f;	val_dir[646*3 + 1] = -0.997041f;	val_dir[646*3 + 2] = 0.034381f;
+ 	val_dir[647*3 + 0] = -0.052430f;	val_dir[647*3 + 1] = -0.996175f;	val_dir[647*3 + 2] = 0.069907f;
+ 	val_dir[648*3 + 0] = -0.035489f;	val_dir[648*3 + 1] = -0.993683f;	val_dir[648*3 + 2] = 0.106466f;
+ 	val_dir[649*3 + 0] = -0.017990f;	val_dir[649*3 + 1] = -0.989426f;	val_dir[649*3 + 2] = 0.143917f;
+ 	val_dir[650*3 + 0] = 0.0f;	val_dir[650*3 + 1] = -0.983282f;	val_dir[650*3 + 2] = 0.182089f;
+ 	val_dir[651*3 + 0] = 0.018538f;	val_dir[651*3 + 1] = -0.982493f;	val_dir[651*3 + 2] = 0.185376f;
+ 	val_dir[652*3 + 0] = 0.037743f;	val_dir[652*3 + 1] = -0.981307f;	val_dir[652*3 + 2] = 0.188713f;
+ 	val_dir[653*3 + 0] = 0.057628f;	val_dir[653*3 + 1] = -0.979683f;	val_dir[653*3 + 2] = 0.192095f;
+ 	val_dir[654*3 + 0] = 0.078206f;	val_dir[654*3 + 1] = -0.977577f;	val_dir[654*3 + 2] = 0.195515f;
+ 	val_dir[655*3 + 0] = 0.099484f;	val_dir[655*3 + 1] = -0.974943f;	val_dir[655*3 + 2] = 0.198968f;
+ 	val_dir[656*3 + 0] = 0.121466f;	val_dir[656*3 + 1] = -0.971732f;	val_dir[656*3 + 2] = 0.202444f;
+ 	val_dir[657*3 + 0] = 0.144154f;	val_dir[657*3 + 1] = -0.967890f;	val_dir[657*3 + 2] = 0.205934f;
+ 	val_dir[658*3 + 0] = 0.167542f;	val_dir[658*3 + 1] = -0.963364f;	val_dir[658*3 + 2] = 0.209427f;
+ 	val_dir[659*3 + 0] = 0.191620f;	val_dir[659*3 + 1] = -0.958098f;	val_dir[659*3 + 2] = 0.212911f;
+ 	val_dir[660*3 + 0] = 0.216371f;	val_dir[660*3 + 1] = -0.952033f;	val_dir[660*3 + 2] = 0.216371f;
+ 	val_dir[661*3 + 0] = 0.241773f;	val_dir[661*3 + 1] = -0.945112f;	val_dir[661*3 + 2] = 0.219793f;
+ 	val_dir[662*3 + 0] = 0.267793f;	val_dir[662*3 + 1] = -0.937276f;	val_dir[662*3 + 2] = 0.223161f;
+ 	val_dir[663*3 + 0] = 0.294392f;	val_dir[663*3 + 1] = -0.928467f;	val_dir[663*3 + 2] = 0.226455f;
+ 	val_dir[664*3 + 0] = 0.321521f;	val_dir[664*3 + 1] = -0.918630f;	val_dir[664*3 + 2] = 0.229658f;
+ 	val_dir[665*3 + 0] = 0.349121f;	val_dir[665*3 + 1] = -0.907713f;	val_dir[665*3 + 2] = 0.232747f;
+ 	val_dir[666*3 + 0] = 0.377124f;	val_dir[666*3 + 1] = -0.895669f;	val_dir[666*3 + 2] = 0.235702f;
+ 	val_dir[667*3 + 0] = 0.405452f;	val_dir[667*3 + 1] = -0.882454f;	val_dir[667*3 + 2] = 0.238501f;
+ 	val_dir[668*3 + 0] = 0.434019f;	val_dir[668*3 + 1] = -0.868037f;	val_dir[668*3 + 2] = 0.241121f;
+ 	val_dir[669*3 + 0] = 0.462727f;	val_dir[669*3 + 1] = -0.852392f;	val_dir[669*3 + 2] = 0.243541f;
+ 	val_dir[670*3 + 0] = 0.491473f;	val_dir[670*3 + 1] = -0.835504f;	val_dir[670*3 + 2] = 0.245737f;
+ 	val_dir[671*3 + 0] = 0.520146f;	val_dir[671*3 + 1] = -0.817373f;	val_dir[671*3 + 2] = 0.247689f;
+ 	val_dir[672*3 + 0] = 0.548630f;	val_dir[672*3 + 1] = -0.798007f;	val_dir[672*3 + 2] = 0.249377f;
+ 	val_dir[673*3 + 0] = 0.576805f;	val_dir[673*3 + 1] = -0.777433f;	val_dir[673*3 + 2] = 0.250785f;
+ 	val_dir[674*3 + 0] = 0.604551f;	val_dir[674*3 + 1] = -0.755689f;	val_dir[674*3 + 2] = 0.251896f;
+ 	val_dir[675*3 + 0] = 0.631748f;	val_dir[675*3 + 1] = -0.732828f;	val_dir[675*3 + 2] = 0.252699f;
+ 	val_dir[676*3 + 0] = 0.658281f;	val_dir[676*3 + 1] = -0.708918f;	val_dir[676*3 + 2] = 0.253185f;
+ 	val_dir[677*3 + 0] = 0.684038f;	val_dir[677*3 + 1] = -0.684038f;	val_dir[677*3 + 2] = 0.253347f;
+ 	val_dir[678*3 + 0] = 0.708918f;	val_dir[678*3 + 1] = -0.658281f;	val_dir[678*3 + 2] = 0.253185f;
+ 	val_dir[679*3 + 0] = 0.732828f;	val_dir[679*3 + 1] = -0.631748f;	val_dir[679*3 + 2] = 0.252699f;
+ 	val_dir[680*3 + 0] = 0.755689f;	val_dir[680*3 + 1] = -0.604551f;	val_dir[680*3 + 2] = 0.251896f;
+ 	val_dir[681*3 + 0] = 0.777433f;	val_dir[681*3 + 1] = -0.576805f;	val_dir[681*3 + 2] = 0.250785f;
+ 	val_dir[682*3 + 0] = 0.798007f;	val_dir[682*3 + 1] = -0.548630f;	val_dir[682*3 + 2] = 0.249377f;
+ 	val_dir[683*3 + 0] = 0.817373f;	val_dir[683*3 + 1] = -0.520146f;	val_dir[683*3 + 2] = 0.247689f;
+ 	val_dir[684*3 + 0] = 0.835504f;	val_dir[684*3 + 1] = -0.491473f;	val_dir[684*3 + 2] = 0.245737f;
+ 	val_dir[685*3 + 0] = 0.852392f;	val_dir[685*3 + 1] = -0.462727f;	val_dir[685*3 + 2] = 0.243541f;
+ 	val_dir[686*3 + 0] = 0.868037f;	val_dir[686*3 + 1] = -0.434019f;	val_dir[686*3 + 2] = 0.241121f;
+ 	val_dir[687*3 + 0] = 0.882454f;	val_dir[687*3 + 1] = -0.405452f;	val_dir[687*3 + 2] = 0.238501f;
+ 	val_dir[688*3 + 0] = 0.895669f;	val_dir[688*3 + 1] = -0.377124f;	val_dir[688*3 + 2] = 0.235702f;
+ 	val_dir[689*3 + 0] = 0.907713f;	val_dir[689*3 + 1] = -0.349121f;	val_dir[689*3 + 2] = 0.232747f;
+ 	val_dir[690*3 + 0] = 0.918630f;	val_dir[690*3 + 1] = -0.321521f;	val_dir[690*3 + 2] = 0.229658f;
+ 	val_dir[691*3 + 0] = 0.928467f;	val_dir[691*3 + 1] = -0.294392f;	val_dir[691*3 + 2] = 0.226455f;
+ 	val_dir[692*3 + 0] = 0.937276f;	val_dir[692*3 + 1] = -0.267793f;	val_dir[692*3 + 2] = 0.223161f;
+ 	val_dir[693*3 + 0] = 0.945112f;	val_dir[693*3 + 1] = -0.241773f;	val_dir[693*3 + 2] = 0.219793f;
+ 	val_dir[694*3 + 0] = 0.952033f;	val_dir[694*3 + 1] = -0.216371f;	val_dir[694*3 + 2] = 0.216371f;
+ 	val_dir[695*3 + 0] = 0.958098f;	val_dir[695*3 + 1] = -0.191620f;	val_dir[695*3 + 2] = 0.212911f;
+ 	val_dir[696*3 + 0] = 0.963364f;	val_dir[696*3 + 1] = -0.167542f;	val_dir[696*3 + 2] = 0.209427f;
+ 	val_dir[697*3 + 0] = 0.967890f;	val_dir[697*3 + 1] = -0.144154f;	val_dir[697*3 + 2] = 0.205934f;
+ 	val_dir[698*3 + 0] = 0.971732f;	val_dir[698*3 + 1] = -0.121466f;	val_dir[698*3 + 2] = 0.202444f;
+ 	val_dir[699*3 + 0] = 0.974943f;	val_dir[699*3 + 1] = -0.099484f;	val_dir[699*3 + 2] = 0.198968f;
+ 	val_dir[700*3 + 0] = 0.977577f;	val_dir[700*3 + 1] = -0.078206f;	val_dir[700*3 + 2] = 0.195515f;
+ 	val_dir[701*3 + 0] = 0.979683f;	val_dir[701*3 + 1] = -0.057628f;	val_dir[701*3 + 2] = 0.192095f;
+ 	val_dir[702*3 + 0] = 0.981307f;	val_dir[702*3 + 1] = -0.037743f;	val_dir[702*3 + 2] = 0.188713f;
+ 	val_dir[703*3 + 0] = 0.982493f;	val_dir[703*3 + 1] = -0.018538f;	val_dir[703*3 + 2] = 0.185376f;
+ 	val_dir[704*3 + 0] = 0.983282f;	val_dir[704*3 + 1] = 0.0f;	val_dir[704*3 + 2] = 0.182089f;
+ 	val_dir[705*3 + 0] = 0.989426f;	val_dir[705*3 + 1] = 0.017990f;	val_dir[705*3 + 2] = 0.143917f;
+ 	val_dir[706*3 + 0] = 0.993683f;	val_dir[706*3 + 1] = 0.035489f;	val_dir[706*3 + 2] = 0.106466f;
+ 	val_dir[707*3 + 0] = 0.996175f;	val_dir[707*3 + 1] = 0.052430f;	val_dir[707*3 + 2] = 0.069907f;
+ 	val_dir[708*3 + 0] = 0.997041f;	val_dir[708*3 + 1] = 0.068761f;	val_dir[708*3 + 2] = 0.034381f;
+ 	val_dir[709*3 + 0] = 0.996428f;	val_dir[709*3 + 1] = 0.084443f;	val_dir[709*3 + 2] = 0.0f;
+ 	val_dir[710*3 + 0] = -0.085876f;	val_dir[710*3 + 1] = -0.996158f;	val_dir[710*3 + 2] = 0.017175f;
+ 	val_dir[711*3 + 0] = -0.069907f;	val_dir[711*3 + 1] = -0.996175f;	val_dir[711*3 + 2] = 0.052430f;
+ 	val_dir[712*3 + 0] = -0.053283f;	val_dir[712*3 + 1] = -0.994623f;	val_dir[712*3 + 2] = 0.088806f;
+ 	val_dir[713*3 + 0] = -0.036049f;	val_dir[713*3 + 1] = -0.991353f;	val_dir[713*3 + 2] = 0.126172f;
+ 	val_dir[714*3 + 0] = -0.018264f;	val_dir[714*3 + 1] = -0.986229f;	val_dir[714*3 + 2] = 0.164372f;
+ 	val_dir[715*3 + 0] = 0.0f;	val_dir[715*3 + 1] = -0.979134f;	val_dir[715*3 + 2] = 0.203216f;
+ 	val_dir[716*3 + 0] = 0.018811f;	val_dir[716*3 + 1] = -0.978177f;	val_dir[716*3 + 2] = 0.206922f;
+ 	val_dir[717*3 + 0] = 0.038306f;	val_dir[717*3 + 1] = -0.976804f;	val_dir[717*3 + 2] = 0.210683f;
+ 	val_dir[718*3 + 0] = 0.058498f;	val_dir[718*3 + 1] = -0.974972f;	val_dir[718*3 + 2] = 0.214494f;
+ 	val_dir[719*3 + 0] = 0.079399f;	val_dir[719*3 + 1] = -0.972636f;	val_dir[719*3 + 2] = 0.218347f;
+ 	val_dir[720*3 + 0] = 0.101015f;	val_dir[720*3 + 1] = -0.969746f;	val_dir[720*3 + 2] = 0.222234f;
+ 	val_dir[721*3 + 0] = 0.123351f;	val_dir[721*3 + 1] = -0.966252f;	val_dir[721*3 + 2] = 0.226144f;
+ 	val_dir[722*3 + 0] = 0.146406f;	val_dir[722*3 + 1] = -0.962099f;	val_dir[722*3 + 2] = 0.230067f;
+ 	val_dir[723*3 + 0] = 0.170174f;	val_dir[723*3 + 1] = -0.957230f;	val_dir[723*3 + 2] = 0.233990f;
+ 	val_dir[724*3 + 0] = 0.194643f;	val_dir[724*3 + 1] = -0.951588f;	val_dir[724*3 + 2] = 0.237897f;
+ 	val_dir[725*3 + 0] = 0.219793f;	val_dir[725*3 + 1] = -0.945112f;	val_dir[725*3 + 2] = 0.241773f;
+ 	val_dir[726*3 + 0] = 0.245599f;	val_dir[726*3 + 1] = -0.937743f;	val_dir[726*3 + 2] = 0.245599f;
+ 	val_dir[727*3 + 0] = 0.272026f;	val_dir[727*3 + 1] = -0.929421f;	val_dir[727*3 + 2] = 0.249357f;
+ 	val_dir[728*3 + 0] = 0.299028f;	val_dir[728*3 + 1] = -0.920087f;	val_dir[728*3 + 2] = 0.253024f;
+ 	val_dir[729*3 + 0] = 0.326554f;	val_dir[729*3 + 1] = -0.909687f;	val_dir[729*3 + 2] = 0.256578f;
+ 	val_dir[730*3 + 0] = 0.354540f;	val_dir[730*3 + 1] = -0.898167f;	val_dir[730*3 + 2] = 0.259996f;
+ 	val_dir[731*3 + 0] = 0.382911f;	val_dir[731*3 + 1] = -0.885482f;	val_dir[731*3 + 2] = 0.263251f;
+ 	val_dir[732*3 + 0] = 0.411585f;	val_dir[732*3 + 1] = -0.871592f;	val_dir[732*3 + 2] = 0.266320f;
+ 	val_dir[733*3 + 0] = 0.440468f;	val_dir[733*3 + 1] = -0.856465f;	val_dir[733*3 + 2] = 0.269175f;
+ 	val_dir[734*3 + 0] = 0.469458f;	val_dir[734*3 + 1] = -0.840083f;	val_dir[734*3 + 2] = 0.271791f;
+ 	val_dir[735*3 + 0] = 0.498445f;	val_dir[735*3 + 1] = -0.822434f;	val_dir[735*3 + 2] = 0.274145f;
+ 	val_dir[736*3 + 0] = 0.527312f;	val_dir[736*3 + 1] = -0.803523f;	val_dir[736*3 + 2] = 0.276211f;
+ 	val_dir[737*3 + 0] = 0.555939f;	val_dir[737*3 + 1] = -0.783368f;	val_dir[737*3 + 2] = 0.277969f;
+ 	val_dir[738*3 + 0] = 0.584201f;	val_dir[738*3 + 1] = -0.762001f;	val_dir[738*3 + 2] = 0.27940f;
+ 	val_dir[739*3 + 0] = 0.611974f;	val_dir[739*3 + 1] = -0.739469f;	val_dir[739*3 + 2] = 0.280488f;
+ 	val_dir[740*3 + 0] = 0.639138f;	val_dir[740*3 + 1] = -0.715834f;	val_dir[740*3 + 2] = 0.281220f;
+ 	val_dir[741*3 + 0] = 0.665574f;	val_dir[741*3 + 1] = -0.691173f;	val_dir[741*3 + 2] = 0.281589f;
+ 	val_dir[742*3 + 0] = 0.691173f;	val_dir[742*3 + 1] = -0.665574f;	val_dir[742*3 + 2] = 0.281589f;
+ 	val_dir[743*3 + 0] = 0.715834f;	val_dir[743*3 + 1] = -0.639138f;	val_dir[743*3 + 2] = 0.281220f;
+ 	val_dir[744*3 + 0] = 0.739469f;	val_dir[744*3 + 1] = -0.611974f;	val_dir[744*3 + 2] = 0.280488f;
+ 	val_dir[745*3 + 0] = 0.762001f;	val_dir[745*3 + 1] = -0.584201f;	val_dir[745*3 + 2] = 0.27940f;
+ 	val_dir[746*3 + 0] = 0.783368f;	val_dir[746*3 + 1] = -0.555939f;	val_dir[746*3 + 2] = 0.277969f;
+ 	val_dir[747*3 + 0] = 0.803523f;	val_dir[747*3 + 1] = -0.527312f;	val_dir[747*3 + 2] = 0.276211f;
+ 	val_dir[748*3 + 0] = 0.822434f;	val_dir[748*3 + 1] = -0.498445f;	val_dir[748*3 + 2] = 0.274145f;
+ 	val_dir[749*3 + 0] = 0.840083f;	val_dir[749*3 + 1] = -0.469458f;	val_dir[749*3 + 2] = 0.271791f;
+ 	val_dir[750*3 + 0] = 0.856465f;	val_dir[750*3 + 1] = -0.440468f;	val_dir[750*3 + 2] = 0.269175f;
+ 	val_dir[751*3 + 0] = 0.871592f;	val_dir[751*3 + 1] = -0.411585f;	val_dir[751*3 + 2] = 0.266320f;
+ 	val_dir[752*3 + 0] = 0.885482f;	val_dir[752*3 + 1] = -0.382911f;	val_dir[752*3 + 2] = 0.263251f;
+ 	val_dir[753*3 + 0] = 0.898167f;	val_dir[753*3 + 1] = -0.354540f;	val_dir[753*3 + 2] = 0.259996f;
+ 	val_dir[754*3 + 0] = 0.909687f;	val_dir[754*3 + 1] = -0.326554f;	val_dir[754*3 + 2] = 0.256578f;
+ 	val_dir[755*3 + 0] = 0.920087f;	val_dir[755*3 + 1] = -0.299028f;	val_dir[755*3 + 2] = 0.253024f;
+ 	val_dir[756*3 + 0] = 0.929421f;	val_dir[756*3 + 1] = -0.272026f;	val_dir[756*3 + 2] = 0.249357f;
+ 	val_dir[757*3 + 0] = 0.937743f;	val_dir[757*3 + 1] = -0.245599f;	val_dir[757*3 + 2] = 0.245599f;
+ 	val_dir[758*3 + 0] = 0.945112f;	val_dir[758*3 + 1] = -0.219793f;	val_dir[758*3 + 2] = 0.241773f;
+ 	val_dir[759*3 + 0] = 0.951588f;	val_dir[759*3 + 1] = -0.194643f;	val_dir[759*3 + 2] = 0.237897f;
+ 	val_dir[760*3 + 0] = 0.957230f;	val_dir[760*3 + 1] = -0.170174f;	val_dir[760*3 + 2] = 0.233990f;
+ 	val_dir[761*3 + 0] = 0.962099f;	val_dir[761*3 + 1] = -0.146406f;	val_dir[761*3 + 2] = 0.230067f;
+ 	val_dir[762*3 + 0] = 0.966252f;	val_dir[762*3 + 1] = -0.123351f;	val_dir[762*3 + 2] = 0.226144f;
+ 	val_dir[763*3 + 0] = 0.969746f;	val_dir[763*3 + 1] = -0.101015f;	val_dir[763*3 + 2] = 0.222234f;
+ 	val_dir[764*3 + 0] = 0.972636f;	val_dir[764*3 + 1] = -0.079399f;	val_dir[764*3 + 2] = 0.218347f;
+ 	val_dir[765*3 + 0] = 0.974972f;	val_dir[765*3 + 1] = -0.058498f;	val_dir[765*3 + 2] = 0.214494f;
+ 	val_dir[766*3 + 0] = 0.976804f;	val_dir[766*3 + 1] = -0.038306f;	val_dir[766*3 + 2] = 0.210683f;
+ 	val_dir[767*3 + 0] = 0.978177f;	val_dir[767*3 + 1] = -0.018811f;	val_dir[767*3 + 2] = 0.206922f;
+ 	val_dir[768*3 + 0] = 0.979134f;	val_dir[768*3 + 1] = 0.0f;	val_dir[768*3 + 2] = 0.203216f;
+ 	val_dir[769*3 + 0] = 0.986229f;	val_dir[769*3 + 1] = 0.018264f;	val_dir[769*3 + 2] = 0.164372f;
+ 	val_dir[770*3 + 0] = 0.991353f;	val_dir[770*3 + 1] = 0.036049f;	val_dir[770*3 + 2] = 0.126172f;
+ 	val_dir[771*3 + 0] = 0.994623f;	val_dir[771*3 + 1] = 0.053283f;	val_dir[771*3 + 2] = 0.088806f;
+ 	val_dir[772*3 + 0] = 0.996175f;	val_dir[772*3 + 1] = 0.069907f;	val_dir[772*3 + 2] = 0.052430f;
+ 	val_dir[773*3 + 0] = 0.996158f;	val_dir[773*3 + 1] = 0.085876f;	val_dir[773*3 + 2] = 0.017175f;
+ 	val_dir[774*3 + 0] = -0.102899f;	val_dir[774*3 + 1] = -0.994692f;	val_dir[774*3 + 2] = 0.0f;
+ 	val_dir[775*3 + 0] = -0.087330f;	val_dir[775*3 + 1] = -0.995567f;	val_dir[775*3 + 2] = 0.034932f;
+ 	val_dir[776*3 + 0] = -0.071067f;	val_dir[776*3 + 1] = -0.994937f;	val_dir[776*3 + 2] = 0.071067f;
+ 	val_dir[777*3 + 0] = -0.054144f;	val_dir[777*3 + 1] = -0.992644f;	val_dir[777*3 + 2] = 0.108288f;
+ 	val_dir[778*3 + 0] = -0.036613f;	val_dir[778*3 + 1] = -0.988540f;	val_dir[778*3 + 2] = 0.146450f;
+ 	val_dir[779*3 + 0] = -0.018538f;	val_dir[779*3 + 1] = -0.982493f;	val_dir[779*3 + 2] = 0.185376f;
+ 	val_dir[780*3 + 0] = 0.0f;	val_dir[780*3 + 1] = -0.974391f;	val_dir[780*3 + 2] = 0.224860f;
+ 	val_dir[781*3 + 0] = 0.019083f;	val_dir[781*3 + 1] = -0.973240f;	val_dir[781*3 + 2] = 0.228998f;
+ 	val_dir[782*3 + 0] = 0.038866f;	val_dir[782*3 + 1] = -0.971653f;	val_dir[782*3 + 2] = 0.233197f;
+ 	val_dir[783*3 + 0] = 0.059362f;	val_dir[783*3 + 1] = -0.969584f;	val_dir[783*3 + 2] = 0.237449f;
+ 	val_dir[784*3 + 0] = 0.080582f;	val_dir[784*3 + 1] = -0.966988f;	val_dir[784*3 + 2] = 0.241747f;
+ 	val_dir[785*3 + 0] = 0.102533f;	val_dir[785*3 + 1] = -0.963811f;	val_dir[785*3 + 2] = 0.246079f;
+ 	val_dir[786*3 + 0] = 0.125218f;	val_dir[786*3 + 1] = -0.960001f;	val_dir[786*3 + 2] = 0.250435f;
+ 	val_dir[787*3 + 0] = 0.148634f;	val_dir[787*3 + 1] = -0.955502f;	val_dir[787*3 + 2] = 0.254801f;
+ 	val_dir[788*3 + 0] = 0.172774f;	val_dir[788*3 + 1] = -0.950255f;	val_dir[788*3 + 2] = 0.259161f;
+ 	val_dir[789*3 + 0] = 0.197623f;	val_dir[789*3 + 1] = -0.94420f;	val_dir[789*3 + 2] = 0.263498f;
+ 	val_dir[790*3 + 0] = 0.223161f;	val_dir[790*3 + 1] = -0.937276f;	val_dir[790*3 + 2] = 0.267793f;
+ 	val_dir[791*3 + 0] = 0.249357f;	val_dir[791*3 + 1] = -0.929421f;	val_dir[791*3 + 2] = 0.272026f;
+ 	val_dir[792*3 + 0] = 0.276172f;	val_dir[792*3 + 1] = -0.920575f;	val_dir[792*3 + 2] = 0.276172f;
+ 	val_dir[793*3 + 0] = 0.303559f;	val_dir[793*3 + 1] = -0.910678f;	val_dir[793*3 + 2] = 0.280209f;
+ 	val_dir[794*3 + 0] = 0.331460f;	val_dir[794*3 + 1] = -0.899676f;	val_dir[794*3 + 2] = 0.284108f;
+ 	val_dir[795*3 + 0] = 0.359804f;	val_dir[795*3 + 1] = -0.887517f;	val_dir[795*3 + 2] = 0.287843f;
+ 	val_dir[796*3 + 0] = 0.388514f;	val_dir[796*3 + 1] = -0.874157f;	val_dir[796*3 + 2] = 0.291386f;
+ 	val_dir[797*3 + 0] = 0.41750f;	val_dir[797*3 + 1] = -0.859559f;	val_dir[797*3 + 2] = 0.294706f;
+ 	val_dir[798*3 + 0] = 0.446662f;	val_dir[798*3 + 1] = -0.843696f;	val_dir[798*3 + 2] = 0.297775f;
+ 	val_dir[799*3 + 0] = 0.475893f;	val_dir[799*3 + 1] = -0.826551f;	val_dir[799*3 + 2] = 0.300564f;
+ 	val_dir[800*3 + 0] = 0.505076f;	val_dir[800*3 + 1] = -0.808122f;	val_dir[800*3 + 2] = 0.303046f;
+ 	val_dir[801*3 + 0] = 0.534090f;	val_dir[801*3 + 1] = -0.788419f;	val_dir[801*3 + 2] = 0.305194f;
+ 	val_dir[802*3 + 0] = 0.562809f;	val_dir[802*3 + 1] = -0.767467f;	val_dir[802*3 + 2] = 0.306987f;
+ 	val_dir[803*3 + 0] = 0.591105f;	val_dir[803*3 + 1] = -0.745307f;	val_dir[803*3 + 2] = 0.308403f;
+ 	val_dir[804*3 + 0] = 0.618853f;	val_dir[804*3 + 1] = -0.721995f;	val_dir[804*3 + 2] = 0.309426f;
+ 	val_dir[805*3 + 0] = 0.645928f;	val_dir[805*3 + 1] = -0.697602f;	val_dir[805*3 + 2] = 0.310045f;
+ 	val_dir[806*3 + 0] = 0.672214f;	val_dir[806*3 + 1] = -0.672214f;	val_dir[806*3 + 2] = 0.310253f;
+ 	val_dir[807*3 + 0] = 0.697602f;	val_dir[807*3 + 1] = -0.645928f;	val_dir[807*3 + 2] = 0.310045f;
+ 	val_dir[808*3 + 0] = 0.721995f;	val_dir[808*3 + 1] = -0.618853f;	val_dir[808*3 + 2] = 0.309426f;
+ 	val_dir[809*3 + 0] = 0.745307f;	val_dir[809*3 + 1] = -0.591105f;	val_dir[809*3 + 2] = 0.308403f;
+ 	val_dir[810*3 + 0] = 0.767467f;	val_dir[810*3 + 1] = -0.562809f;	val_dir[810*3 + 2] = 0.306987f;
+ 	val_dir[811*3 + 0] = 0.788419f;	val_dir[811*3 + 1] = -0.534090f;	val_dir[811*3 + 2] = 0.305194f;
+ 	val_dir[812*3 + 0] = 0.808122f;	val_dir[812*3 + 1] = -0.505076f;	val_dir[812*3 + 2] = 0.303046f;
+ 	val_dir[813*3 + 0] = 0.826551f;	val_dir[813*3 + 1] = -0.475893f;	val_dir[813*3 + 2] = 0.300564f;
+ 	val_dir[814*3 + 0] = 0.843696f;	val_dir[814*3 + 1] = -0.446662f;	val_dir[814*3 + 2] = 0.297775f;
+ 	val_dir[815*3 + 0] = 0.859559f;	val_dir[815*3 + 1] = -0.41750f;	val_dir[815*3 + 2] = 0.294706f;
+ 	val_dir[816*3 + 0] = 0.874157f;	val_dir[816*3 + 1] = -0.388514f;	val_dir[816*3 + 2] = 0.291386f;
+ 	val_dir[817*3 + 0] = 0.887517f;	val_dir[817*3 + 1] = -0.359804f;	val_dir[817*3 + 2] = 0.287843f;
+ 	val_dir[818*3 + 0] = 0.899676f;	val_dir[818*3 + 1] = -0.331460f;	val_dir[818*3 + 2] = 0.284108f;
+ 	val_dir[819*3 + 0] = 0.910678f;	val_dir[819*3 + 1] = -0.303559f;	val_dir[819*3 + 2] = 0.280209f;
+ 	val_dir[820*3 + 0] = 0.920575f;	val_dir[820*3 + 1] = -0.276172f;	val_dir[820*3 + 2] = 0.276172f;
+ 	val_dir[821*3 + 0] = 0.929421f;	val_dir[821*3 + 1] = -0.249357f;	val_dir[821*3 + 2] = 0.272026f;
+ 	val_dir[822*3 + 0] = 0.937276f;	val_dir[822*3 + 1] = -0.223161f;	val_dir[822*3 + 2] = 0.267793f;
+ 	val_dir[823*3 + 0] = 0.94420f;	val_dir[823*3 + 1] = -0.197623f;	val_dir[823*3 + 2] = 0.263498f;
+ 	val_dir[824*3 + 0] = 0.950255f;	val_dir[824*3 + 1] = -0.172774f;	val_dir[824*3 + 2] = 0.259161f;
+ 	val_dir[825*3 + 0] = 0.955502f;	val_dir[825*3 + 1] = -0.148634f;	val_dir[825*3 + 2] = 0.254801f;
+ 	val_dir[826*3 + 0] = 0.960001f;	val_dir[826*3 + 1] = -0.125218f;	val_dir[826*3 + 2] = 0.250435f;
+ 	val_dir[827*3 + 0] = 0.963811f;	val_dir[827*3 + 1] = -0.102533f;	val_dir[827*3 + 2] = 0.246079f;
+ 	val_dir[828*3 + 0] = 0.966988f;	val_dir[828*3 + 1] = -0.080582f;	val_dir[828*3 + 2] = 0.241747f;
+ 	val_dir[829*3 + 0] = 0.969584f;	val_dir[829*3 + 1] = -0.059362f;	val_dir[829*3 + 2] = 0.237449f;
+ 	val_dir[830*3 + 0] = 0.971653f;	val_dir[830*3 + 1] = -0.038866f;	val_dir[830*3 + 2] = 0.233197f;
+ 	val_dir[831*3 + 0] = 0.973240f;	val_dir[831*3 + 1] = -0.019083f;	val_dir[831*3 + 2] = 0.228998f;
+ 	val_dir[832*3 + 0] = 0.974391f;	val_dir[832*3 + 1] = 0.0f;	val_dir[832*3 + 2] = 0.224860f;
+ 	val_dir[833*3 + 0] = 0.982493f;	val_dir[833*3 + 1] = 0.018538f;	val_dir[833*3 + 2] = 0.185376f;
+ 	val_dir[834*3 + 0] = 0.988540f;	val_dir[834*3 + 1] = 0.036613f;	val_dir[834*3 + 2] = 0.146450f;
+ 	val_dir[835*3 + 0] = 0.992644f;	val_dir[835*3 + 1] = 0.054144f;	val_dir[835*3 + 2] = 0.108288f;
+ 	val_dir[836*3 + 0] = 0.994937f;	val_dir[836*3 + 1] = 0.071067f;	val_dir[836*3 + 2] = 0.071067f;
+ 	val_dir[837*3 + 0] = 0.995567f;	val_dir[837*3 + 1] = 0.087330f;	val_dir[837*3 + 2] = 0.034932f;
+ 	val_dir[838*3 + 0] = 0.994692f;	val_dir[838*3 + 1] = 0.102899f;	val_dir[838*3 + 2] = 0.0f;
+ 	val_dir[839*3 + 0] = -0.104669f;	val_dir[839*3 + 1] = -0.994354f;	val_dir[839*3 + 2] = 0.017445f;
+ 	val_dir[840*3 + 0] = -0.088806f;	val_dir[840*3 + 1] = -0.994623f;	val_dir[840*3 + 2] = 0.053283f;
+ 	val_dir[841*3 + 0] = -0.072239f;	val_dir[841*3 + 1] = -0.993291f;	val_dir[841*3 + 2] = 0.090299f;
+ 	val_dir[842*3 + 0] = -0.055011f;	val_dir[842*3 + 1] = -0.990201f;	val_dir[842*3 + 2] = 0.128359f;
+ 	val_dir[843*3 + 0] = -0.037178f;	val_dir[843*3 + 1] = -0.985205f;	val_dir[843*3 + 2] = 0.167299f;
+ 	val_dir[844*3 + 0] = -0.018811f;	val_dir[844*3 + 1] = -0.978177f;	val_dir[844*3 + 2] = 0.206922f;
+ 	val_dir[845*3 + 0] = 0.0f;	val_dir[845*3 + 1] = -0.969015f;	val_dir[845*3 + 2] = 0.247004f;
+ 	val_dir[846*3 + 0] = 0.019353f;	val_dir[846*3 + 1] = -0.967641f;	val_dir[846*3 + 2] = 0.251587f;
+ 	val_dir[847*3 + 0] = 0.039421f;	val_dir[847*3 + 1] = -0.965810f;	val_dir[847*3 + 2] = 0.256235f;
+ 	val_dir[848*3 + 0] = 0.060217f;	val_dir[848*3 + 1] = -0.963475f;	val_dir[848*3 + 2] = 0.260941f;
+ 	val_dir[849*3 + 0] = 0.081752f;	val_dir[849*3 + 1] = -0.960585f;	val_dir[849*3 + 2] = 0.265694f;
+ 	val_dir[850*3 + 0] = 0.104031f;	val_dir[850*3 + 1] = -0.957088f;	val_dir[850*3 + 2] = 0.270481f;
+ 	val_dir[851*3 + 0] = 0.127057f;	val_dir[851*3 + 1] = -0.952928f;	val_dir[851*3 + 2] = 0.275290f;
+ 	val_dir[852*3 + 0] = 0.150826f;	val_dir[852*3 + 1] = -0.948047f;	val_dir[852*3 + 2] = 0.280105f;
+ 	val_dir[853*3 + 0] = 0.175327f;	val_dir[853*3 + 1] = -0.942384f;	val_dir[853*3 + 2] = 0.284907f;
+ 	val_dir[854*3 + 0] = 0.200545f;	val_dir[854*3 + 1] = -0.935879f;	val_dir[854*3 + 2] = 0.289677f;
+ 	val_dir[855*3 + 0] = 0.226455f;	val_dir[855*3 + 1] = -0.928467f;	val_dir[855*3 + 2] = 0.294392f;
+ 	val_dir[856*3 + 0] = 0.253024f;	val_dir[856*3 + 1] = -0.920087f;	val_dir[856*3 + 2] = 0.299028f;
+ 	val_dir[857*3 + 0] = 0.280209f;	val_dir[857*3 + 1] = -0.910678f;	val_dir[857*3 + 2] = 0.303559f;
+ 	val_dir[858*3 + 0] = 0.307957f;	val_dir[858*3 + 1] = -0.900181f;	val_dir[858*3 + 2] = 0.307957f;
+ 	val_dir[859*3 + 0] = 0.336204f;	val_dir[859*3 + 1] = -0.888540f;	val_dir[859*3 + 2] = 0.312190f;
+ 	val_dir[860*3 + 0] = 0.364878f;	val_dir[860*3 + 1] = -0.875708f;	val_dir[860*3 + 2] = 0.316228f;
+ 	val_dir[861*3 + 0] = 0.393893f;	val_dir[861*3 + 1] = -0.861640f;	val_dir[861*3 + 2] = 0.320038f;
+ 	val_dir[862*3 + 0] = 0.423153f;	val_dir[862*3 + 1] = -0.846305f;	val_dir[862*3 + 2] = 0.323587f;
+ 	val_dir[863*3 + 0] = 0.452553f;	val_dir[863*3 + 1] = -0.829680f;	val_dir[863*3 + 2] = 0.326844f;
+ 	val_dir[864*3 + 0] = 0.481979f;	val_dir[864*3 + 1] = -0.811754f;	val_dir[864*3 + 2] = 0.329775f;
+ 	val_dir[865*3 + 0] = 0.511310f;	val_dir[865*3 + 1] = -0.792530f;	val_dir[865*3 + 2] = 0.332352f;
+ 	val_dir[866*3 + 0] = 0.540419f;	val_dir[866*3 + 1] = -0.772027f;	val_dir[866*3 + 2] = 0.334545f;
+ 	val_dir[867*3 + 0] = 0.569177f;	val_dir[867*3 + 1] = -0.750279f;	val_dir[867*3 + 2] = 0.336332f;
+ 	val_dir[868*3 + 0] = 0.597453f;	val_dir[868*3 + 1] = -0.727334f;	val_dir[868*3 + 2] = 0.337691f;
+ 	val_dir[869*3 + 0] = 0.625119f;	val_dir[869*3 + 1] = -0.703259f;	val_dir[869*3 + 2] = 0.338606f;
+ 	val_dir[870*3 + 0] = 0.652051f;	val_dir[870*3 + 1] = -0.678133f;	val_dir[870*3 + 2] = 0.339066f;
+ 	val_dir[871*3 + 0] = 0.678133f;	val_dir[871*3 + 1] = -0.652051f;	val_dir[871*3 + 2] = 0.339066f;
+ 	val_dir[872*3 + 0] = 0.703259f;	val_dir[872*3 + 1] = -0.625119f;	val_dir[872*3 + 2] = 0.338606f;
+ 	val_dir[873*3 + 0] = 0.727334f;	val_dir[873*3 + 1] = -0.597453f;	val_dir[873*3 + 2] = 0.337691f;
+ 	val_dir[874*3 + 0] = 0.750279f;	val_dir[874*3 + 1] = -0.569177f;	val_dir[874*3 + 2] = 0.336332f;
+ 	val_dir[875*3 + 0] = 0.772027f;	val_dir[875*3 + 1] = -0.540419f;	val_dir[875*3 + 2] = 0.334545f;
+ 	val_dir[876*3 + 0] = 0.792530f;	val_dir[876*3 + 1] = -0.511310f;	val_dir[876*3 + 2] = 0.332352f;
+ 	val_dir[877*3 + 0] = 0.811754f;	val_dir[877*3 + 1] = -0.481979f;	val_dir[877*3 + 2] = 0.329775f;
+ 	val_dir[878*3 + 0] = 0.829680f;	val_dir[878*3 + 1] = -0.452553f;	val_dir[878*3 + 2] = 0.326844f;
+ 	val_dir[879*3 + 0] = 0.846305f;	val_dir[879*3 + 1] = -0.423153f;	val_dir[879*3 + 2] = 0.323587f;
+ 	val_dir[880*3 + 0] = 0.861640f;	val_dir[880*3 + 1] = -0.393893f;	val_dir[880*3 + 2] = 0.320038f;
+ 	val_dir[881*3 + 0] = 0.875708f;	val_dir[881*3 + 1] = -0.364878f;	val_dir[881*3 + 2] = 0.316228f;
+ 	val_dir[882*3 + 0] = 0.888540f;	val_dir[882*3 + 1] = -0.336204f;	val_dir[882*3 + 2] = 0.312190f;
+ 	val_dir[883*3 + 0] = 0.900181f;	val_dir[883*3 + 1] = -0.307957f;	val_dir[883*3 + 2] = 0.307957f;
+ 	val_dir[884*3 + 0] = 0.910678f;	val_dir[884*3 + 1] = -0.280209f;	val_dir[884*3 + 2] = 0.303559f;
+ 	val_dir[885*3 + 0] = 0.920087f;	val_dir[885*3 + 1] = -0.253024f;	val_dir[885*3 + 2] = 0.299028f;
+ 	val_dir[886*3 + 0] = 0.928467f;	val_dir[886*3 + 1] = -0.226455f;	val_dir[886*3 + 2] = 0.294392f;
+ 	val_dir[887*3 + 0] = 0.935879f;	val_dir[887*3 + 1] = -0.200545f;	val_dir[887*3 + 2] = 0.289677f;
+ 	val_dir[888*3 + 0] = 0.942384f;	val_dir[888*3 + 1] = -0.175327f;	val_dir[888*3 + 2] = 0.284907f;
+ 	val_dir[889*3 + 0] = 0.948047f;	val_dir[889*3 + 1] = -0.150826f;	val_dir[889*3 + 2] = 0.280105f;
+ 	val_dir[890*3 + 0] = 0.952928f;	val_dir[890*3 + 1] = -0.127057f;	val_dir[890*3 + 2] = 0.275290f;
+ 	val_dir[891*3 + 0] = 0.957088f;	val_dir[891*3 + 1] = -0.104031f;	val_dir[891*3 + 2] = 0.270481f;
+ 	val_dir[892*3 + 0] = 0.960585f;	val_dir[892*3 + 1] = -0.081752f;	val_dir[892*3 + 2] = 0.265694f;
+ 	val_dir[893*3 + 0] = 0.963475f;	val_dir[893*3 + 1] = -0.060217f;	val_dir[893*3 + 2] = 0.260941f;
+ 	val_dir[894*3 + 0] = 0.965810f;	val_dir[894*3 + 1] = -0.039421f;	val_dir[894*3 + 2] = 0.256235f;
+ 	val_dir[895*3 + 0] = 0.967641f;	val_dir[895*3 + 1] = -0.019353f;	val_dir[895*3 + 2] = 0.251587f;
+ 	val_dir[896*3 + 0] = 0.969015f;	val_dir[896*3 + 1] = 0.0f;	val_dir[896*3 + 2] = 0.247004f;
+ 	val_dir[897*3 + 0] = 0.978177f;	val_dir[897*3 + 1] = 0.018811f;	val_dir[897*3 + 2] = 0.206922f;
+ 	val_dir[898*3 + 0] = 0.985205f;	val_dir[898*3 + 1] = 0.037178f;	val_dir[898*3 + 2] = 0.167299f;
+ 	val_dir[899*3 + 0] = 0.990201f;	val_dir[899*3 + 1] = 0.055011f;	val_dir[899*3 + 2] = 0.128359f;
+ 	val_dir[900*3 + 0] = 0.993291f;	val_dir[900*3 + 1] = 0.072239f;	val_dir[900*3 + 2] = 0.090299f;
+ 	val_dir[901*3 + 0] = 0.994623f;	val_dir[901*3 + 1] = 0.088806f;	val_dir[901*3 + 2] = 0.053283f;
+ 	val_dir[902*3 + 0] = 0.994354f;	val_dir[902*3 + 1] = 0.104669f;	val_dir[902*3 + 2] = 0.017445f;
+ 	val_dir[903*3 + 0] = -0.121891f;	val_dir[903*3 + 1] = -0.992543f;	val_dir[903*3 + 2] = 0.0f;
+ 	val_dir[904*3 + 0] = -0.106466f;	val_dir[904*3 + 1] = -0.993683f;	val_dir[904*3 + 2] = 0.035489f;
+ 	val_dir[905*3 + 0] = -0.090299f;	val_dir[905*3 + 1] = -0.993291f;	val_dir[905*3 + 2] = 0.072239f;
+ 	val_dir[906*3 + 0] = -0.073422f;	val_dir[906*3 + 1] = -0.991201f;	val_dir[906*3 + 2] = 0.110133f;
+ 	val_dir[907*3 + 0] = -0.055882f;	val_dir[907*3 + 1] = -0.987254f;	val_dir[907*3 + 2] = 0.149019f;
+ 	val_dir[908*3 + 0] = -0.037743f;	val_dir[908*3 + 1] = -0.981307f;	val_dir[908*3 + 2] = 0.188713f;
+ 	val_dir[909*3 + 0] = -0.019083f;	val_dir[909*3 + 1] = -0.973240f;	val_dir[909*3 + 2] = 0.228998f;
+ 	val_dir[910*3 + 0] = 0.0f;	val_dir[910*3 + 1] = -0.962964f;	val_dir[910*3 + 2] = 0.269630f;
+ 	val_dir[911*3 + 0] = 0.019619f;	val_dir[911*3 + 1] = -0.961339f;	val_dir[911*3 + 2] = 0.274668f;
+ 	val_dir[912*3 + 0] = 0.039968f;	val_dir[912*3 + 1] = -0.959233f;	val_dir[912*3 + 2] = 0.279776f;
+ 	val_dir[913*3 + 0] = 0.061059f;	val_dir[913*3 + 1] = -0.956597f;	val_dir[913*3 + 2] = 0.284944f;
+ 	val_dir[914*3 + 0] = 0.082903f;	val_dir[914*3 + 1] = -0.953381f;	val_dir[914*3 + 2] = 0.290159f;
+ 	val_dir[915*3 + 0] = 0.105503f;	val_dir[915*3 + 1] = -0.949528f;	val_dir[915*3 + 2] = 0.295409f;
+ 	val_dir[916*3 + 0] = 0.128861f;	val_dir[916*3 + 1] = -0.944981f;	val_dir[916*3 + 2] = 0.300676f;
+ 	val_dir[917*3 + 0] = 0.152971f;	val_dir[917*3 + 1] = -0.939680f;	val_dir[917*3 + 2] = 0.305942f;
+ 	val_dir[918*3 + 0] = 0.177822f;	val_dir[918*3 + 1] = -0.933564f;	val_dir[918*3 + 2] = 0.311188f;
+ 	val_dir[919*3 + 0] = 0.203393f;	val_dir[919*3 + 1] = -0.926568f;	val_dir[919*3 + 2] = 0.316389f;
+ 	val_dir[920*3 + 0] = 0.229658f;	val_dir[920*3 + 1] = -0.918630f;	val_dir[920*3 + 2] = 0.321521f;
+ 	val_dir[921*3 + 0] = 0.256578f;	val_dir[921*3 + 1] = -0.909687f;	val_dir[921*3 + 2] = 0.326554f;
+ 	val_dir[922*3 + 0] = 0.284108f;	val_dir[922*3 + 1] = -0.899676f;	val_dir[922*3 + 2] = 0.331460f;
+ 	val_dir[923*3 + 0] = 0.312190f;	val_dir[923*3 + 1] = -0.888540f;	val_dir[923*3 + 2] = 0.336204f;
+ 	val_dir[924*3 + 0] = 0.340755f;	val_dir[924*3 + 1] = -0.876226f;	val_dir[924*3 + 2] = 0.340755f;
+ 	val_dir[925*3 + 0] = 0.369723f;	val_dir[925*3 + 1] = -0.862687f;	val_dir[925*3 + 2] = 0.345075f;
+ 	val_dir[926*3 + 0] = 0.399004f;	val_dir[926*3 + 1] = -0.847883f;	val_dir[926*3 + 2] = 0.349128f;
+ 	val_dir[927*3 + 0] = 0.428496f;	val_dir[927*3 + 1] = -0.831786f;	val_dir[927*3 + 2] = 0.352879f;
+ 	val_dir[928*3 + 0] = 0.458088f;	val_dir[928*3 + 1] = -0.814379f;	val_dir[928*3 + 2] = 0.356291f;
+ 	val_dir[929*3 + 0] = 0.487661f;	val_dir[929*3 + 1] = -0.795657f;	val_dir[929*3 + 2] = 0.359329f;
+ 	val_dir[930*3 + 0] = 0.517088f;	val_dir[930*3 + 1] = -0.775632f;	val_dir[930*3 + 2] = 0.361961f;
+ 	val_dir[931*3 + 0] = 0.546238f;	val_dir[931*3 + 1] = -0.754329f;	val_dir[931*3 + 2] = 0.364159f;
+ 	val_dir[932*3 + 0] = 0.574979f;	val_dir[932*3 + 1] = -0.731792f;	val_dir[932*3 + 2] = 0.365896f;
+ 	val_dir[933*3 + 0] = 0.603178f;	val_dir[933*3 + 1] = -0.708079f;	val_dir[933*3 + 2] = 0.367152f;
+ 	val_dir[934*3 + 0] = 0.630706f;	val_dir[934*3 + 1] = -0.683265f;	val_dir[934*3 + 2] = 0.367912f;
+ 	val_dir[935*3 + 0] = 0.657440f;	val_dir[935*3 + 1] = -0.657440f;	val_dir[935*3 + 2] = 0.368166f;
+ 	val_dir[936*3 + 0] = 0.683265f;	val_dir[936*3 + 1] = -0.630706f;	val_dir[936*3 + 2] = 0.367912f;
+ 	val_dir[937*3 + 0] = 0.708079f;	val_dir[937*3 + 1] = -0.603178f;	val_dir[937*3 + 2] = 0.367152f;
+ 	val_dir[938*3 + 0] = 0.731792f;	val_dir[938*3 + 1] = -0.574979f;	val_dir[938*3 + 2] = 0.365896f;
+ 	val_dir[939*3 + 0] = 0.754329f;	val_dir[939*3 + 1] = -0.546238f;	val_dir[939*3 + 2] = 0.364159f;
+ 	val_dir[940*3 + 0] = 0.775632f;	val_dir[940*3 + 1] = -0.517088f;	val_dir[940*3 + 2] = 0.361961f;
+ 	val_dir[941*3 + 0] = 0.795657f;	val_dir[941*3 + 1] = -0.487661f;	val_dir[941*3 + 2] = 0.359329f;
+ 	val_dir[942*3 + 0] = 0.814379f;	val_dir[942*3 + 1] = -0.458088f;	val_dir[942*3 + 2] = 0.356291f;
+ 	val_dir[943*3 + 0] = 0.831786f;	val_dir[943*3 + 1] = -0.428496f;	val_dir[943*3 + 2] = 0.352879f;
+ 	val_dir[944*3 + 0] = 0.847883f;	val_dir[944*3 + 1] = -0.399004f;	val_dir[944*3 + 2] = 0.349128f;
+ 	val_dir[945*3 + 0] = 0.862687f;	val_dir[945*3 + 1] = -0.369723f;	val_dir[945*3 + 2] = 0.345075f;
+ 	val_dir[946*3 + 0] = 0.876226f;	val_dir[946*3 + 1] = -0.340755f;	val_dir[946*3 + 2] = 0.340755f;
+ 	val_dir[947*3 + 0] = 0.888540f;	val_dir[947*3 + 1] = -0.312190f;	val_dir[947*3 + 2] = 0.336204f;
+ 	val_dir[948*3 + 0] = 0.899676f;	val_dir[948*3 + 1] = -0.284108f;	val_dir[948*3 + 2] = 0.331460f;
+ 	val_dir[949*3 + 0] = 0.909687f;	val_dir[949*3 + 1] = -0.256578f;	val_dir[949*3 + 2] = 0.326554f;
+ 	val_dir[950*3 + 0] = 0.918630f;	val_dir[950*3 + 1] = -0.229658f;	val_dir[950*3 + 2] = 0.321521f;
+ 	val_dir[951*3 + 0] = 0.926568f;	val_dir[951*3 + 1] = -0.203393f;	val_dir[951*3 + 2] = 0.316389f;
+ 	val_dir[952*3 + 0] = 0.933564f;	val_dir[952*3 + 1] = -0.177822f;	val_dir[952*3 + 2] = 0.311188f;
+ 	val_dir[953*3 + 0] = 0.939680f;	val_dir[953*3 + 1] = -0.152971f;	val_dir[953*3 + 2] = 0.305942f;
+ 	val_dir[954*3 + 0] = 0.944981f;	val_dir[954*3 + 1] = -0.128861f;	val_dir[954*3 + 2] = 0.300676f;
+ 	val_dir[955*3 + 0] = 0.949528f;	val_dir[955*3 + 1] = -0.105503f;	val_dir[955*3 + 2] = 0.295409f;
+ 	val_dir[956*3 + 0] = 0.953381f;	val_dir[956*3 + 1] = -0.082903f;	val_dir[956*3 + 2] = 0.290159f;
+ 	val_dir[957*3 + 0] = 0.956597f;	val_dir[957*3 + 1] = -0.061059f;	val_dir[957*3 + 2] = 0.284944f;
+ 	val_dir[958*3 + 0] = 0.959233f;	val_dir[958*3 + 1] = -0.039968f;	val_dir[958*3 + 2] = 0.279776f;
+ 	val_dir[959*3 + 0] = 0.961339f;	val_dir[959*3 + 1] = -0.019619f;	val_dir[959*3 + 2] = 0.274668f;
+ 	val_dir[960*3 + 0] = 0.962964f;	val_dir[960*3 + 1] = 0.0f;	val_dir[960*3 + 2] = 0.269630f;
+ 	val_dir[961*3 + 0] = 0.973240f;	val_dir[961*3 + 1] = 0.019083f;	val_dir[961*3 + 2] = 0.228998f;
+ 	val_dir[962*3 + 0] = 0.981307f;	val_dir[962*3 + 1] = 0.037743f;	val_dir[962*3 + 2] = 0.188713f;
+ 	val_dir[963*3 + 0] = 0.987254f;	val_dir[963*3 + 1] = 0.055882f;	val_dir[963*3 + 2] = 0.149019f;
+ 	val_dir[964*3 + 0] = 0.991201f;	val_dir[964*3 + 1] = 0.073422f;	val_dir[964*3 + 2] = 0.110133f;
+ 	val_dir[965*3 + 0] = 0.993291f;	val_dir[965*3 + 1] = 0.090299f;	val_dir[965*3 + 2] = 0.072239f;
+ 	val_dir[966*3 + 0] = 0.993683f;	val_dir[966*3 + 1] = 0.106466f;	val_dir[966*3 + 2] = 0.035489f;
+ 	val_dir[967*3 + 0] = 0.992543f;	val_dir[967*3 + 1] = 0.121891f;	val_dir[967*3 + 2] = 0.0f;
+ 	val_dir[968*3 + 0] = -0.124015f;	val_dir[968*3 + 1] = -0.992122f;	val_dir[968*3 + 2] = 0.017716f;
+ 	val_dir[969*3 + 0] = -0.108288f;	val_dir[969*3 + 1] = -0.992644f;	val_dir[969*3 + 2] = 0.054144f;
+ 	val_dir[970*3 + 0] = -0.091809f;	val_dir[970*3 + 1] = -0.991535f;	val_dir[970*3 + 2] = 0.091809f;
+ 	val_dir[971*3 + 0] = -0.074613f;	val_dir[971*3 + 1] = -0.988627f;	val_dir[971*3 + 2] = 0.130573f;
+ 	val_dir[972*3 + 0] = -0.056756f;	val_dir[972*3 + 1] = -0.983762f;	val_dir[972*3 + 2] = 0.170267f;
+ 	val_dir[973*3 + 0] = -0.038306f;	val_dir[973*3 + 1] = -0.976804f;	val_dir[973*3 + 2] = 0.210683f;
+ 	val_dir[974*3 + 0] = -0.019353f;	val_dir[974*3 + 1] = -0.967641f;	val_dir[974*3 + 2] = 0.251587f;
+ 	val_dir[975*3 + 0] = 0.0f;	val_dir[975*3 + 1] = -0.95620f;	val_dir[975*3 + 2] = 0.292714f;
+ 	val_dir[976*3 + 0] = 0.019881f;	val_dir[976*3 + 1] = -0.954291f;	val_dir[976*3 + 2] = 0.298216f;
+ 	val_dir[977*3 + 0] = 0.040505f;	val_dir[977*3 + 1] = -0.951877f;	val_dir[977*3 + 2] = 0.303791f;
+ 	val_dir[978*3 + 0] = 0.061885f;	val_dir[978*3 + 1] = -0.948908f;	val_dir[978*3 + 2] = 0.309426f;
+ 	val_dir[979*3 + 0] = 0.084029f;	val_dir[979*3 + 1] = -0.945328f;	val_dir[979*3 + 2] = 0.315109f;
+ 	val_dir[980*3 + 0] = 0.106941f;	val_dir[980*3 + 1] = -0.941082f;	val_dir[980*3 + 2] = 0.320824f;
+ 	val_dir[981*3 + 0] = 0.130620f;	val_dir[981*3 + 1] = -0.936111f;	val_dir[981*3 + 2] = 0.326550f;
+ 	val_dir[982*3 + 0] = 0.155059f;	val_dir[982*3 + 1] = -0.930352f;	val_dir[982*3 + 2] = 0.332269f;
+ 	val_dir[983*3 + 0] = 0.180242f;	val_dir[983*3 + 1] = -0.923742f;	val_dir[983*3 + 2] = 0.337954f;
+ 	val_dir[984*3 + 0] = 0.206149f;	val_dir[984*3 + 1] = -0.916217f;	val_dir[984*3 + 2] = 0.343582f;
+ 	val_dir[985*3 + 0] = 0.232747f;	val_dir[985*3 + 1] = -0.907713f;	val_dir[985*3 + 2] = 0.349121f;
+ 	val_dir[986*3 + 0] = 0.259996f;	val_dir[986*3 + 1] = -0.898167f;	val_dir[986*3 + 2] = 0.354540f;
+ 	val_dir[987*3 + 0] = 0.287843f;	val_dir[987*3 + 1] = -0.887517f;	val_dir[987*3 + 2] = 0.359804f;
+ 	val_dir[988*3 + 0] = 0.316228f;	val_dir[988*3 + 1] = -0.875708f;	val_dir[988*3 + 2] = 0.364878f;
+ 	val_dir[989*3 + 0] = 0.345075f;	val_dir[989*3 + 1] = -0.862687f;	val_dir[989*3 + 2] = 0.369723f;
+ 	val_dir[990*3 + 0] = 0.374299f;	val_dir[990*3 + 1] = -0.848411f;	val_dir[990*3 + 2] = 0.374299f;
+ 	val_dir[991*3 + 0] = 0.403804f;	val_dir[991*3 + 1] = -0.832845f;	val_dir[991*3 + 2] = 0.378566f;
+ 	val_dir[992*3 + 0] = 0.433482f;	val_dir[992*3 + 1] = -0.815966f;	val_dir[992*3 + 2] = 0.382484f;
+ 	val_dir[993*3 + 0] = 0.463217f;	val_dir[993*3 + 1] = -0.797762f;	val_dir[993*3 + 2] = 0.386014f;
+ 	val_dir[994*3 + 0] = 0.492883f;	val_dir[994*3 + 1] = -0.778237f;	val_dir[994*3 + 2] = 0.389118f;
+ 	val_dir[995*3 + 0] = 0.522352f;	val_dir[995*3 + 1] = -0.757410f;	val_dir[995*3 + 2] = 0.391764f;
+ 	val_dir[996*3 + 0] = 0.551487f;	val_dir[996*3 + 1] = -0.735316f;	val_dir[996*3 + 2] = 0.393919f;
+ 	val_dir[997*3 + 0] = 0.580154f;	val_dir[997*3 + 1] = -0.712007f;	val_dir[997*3 + 2] = 0.395559f;
+ 	val_dir[998*3 + 0] = 0.608219f;	val_dir[998*3 + 1] = -0.687552f;	val_dir[998*3 + 2] = 0.396664f;
+ 	val_dir[999*3 + 0] = 0.635553f;	val_dir[999*3 + 1] = -0.662034f;	val_dir[999*3 + 2] = 0.397220f;
+ 	val_dir[1000*3 + 0] = 0.662034f;	val_dir[1000*3 + 1] = -0.635553f;	val_dir[1000*3 + 2] = 0.397220f;
+ 	val_dir[1001*3 + 0] = 0.687552f;	val_dir[1001*3 + 1] = -0.608219f;	val_dir[1001*3 + 2] = 0.396664f;
+ 	val_dir[1002*3 + 0] = 0.712007f;	val_dir[1002*3 + 1] = -0.580154f;	val_dir[1002*3 + 2] = 0.395559f;
+ 	val_dir[1003*3 + 0] = 0.735316f;	val_dir[1003*3 + 1] = -0.551487f;	val_dir[1003*3 + 2] = 0.393919f;
+ 	val_dir[1004*3 + 0] = 0.757410f;	val_dir[1004*3 + 1] = -0.522352f;	val_dir[1004*3 + 2] = 0.391764f;
+ 	val_dir[1005*3 + 0] = 0.778237f;	val_dir[1005*3 + 1] = -0.492883f;	val_dir[1005*3 + 2] = 0.389118f;
+ 	val_dir[1006*3 + 0] = 0.797762f;	val_dir[1006*3 + 1] = -0.463217f;	val_dir[1006*3 + 2] = 0.386014f;
+ 	val_dir[1007*3 + 0] = 0.815966f;	val_dir[1007*3 + 1] = -0.433482f;	val_dir[1007*3 + 2] = 0.382484f;
+ 	val_dir[1008*3 + 0] = 0.832845f;	val_dir[1008*3 + 1] = -0.403804f;	val_dir[1008*3 + 2] = 0.378566f;
+ 	val_dir[1009*3 + 0] = 0.848411f;	val_dir[1009*3 + 1] = -0.374299f;	val_dir[1009*3 + 2] = 0.374299f;
+ 	val_dir[1010*3 + 0] = 0.862687f;	val_dir[1010*3 + 1] = -0.345075f;	val_dir[1010*3 + 2] = 0.369723f;
+ 	val_dir[1011*3 + 0] = 0.875708f;	val_dir[1011*3 + 1] = -0.316228f;	val_dir[1011*3 + 2] = 0.364878f;
+ 	val_dir[1012*3 + 0] = 0.887517f;	val_dir[1012*3 + 1] = -0.287843f;	val_dir[1012*3 + 2] = 0.359804f;
+ 	val_dir[1013*3 + 0] = 0.898167f;	val_dir[1013*3 + 1] = -0.259996f;	val_dir[1013*3 + 2] = 0.354540f;
+ 	val_dir[1014*3 + 0] = 0.907713f;	val_dir[1014*3 + 1] = -0.232747f;	val_dir[1014*3 + 2] = 0.349121f;
+ 	val_dir[1015*3 + 0] = 0.916217f;	val_dir[1015*3 + 1] = -0.206149f;	val_dir[1015*3 + 2] = 0.343582f;
+ 	val_dir[1016*3 + 0] = 0.923742f;	val_dir[1016*3 + 1] = -0.180242f;	val_dir[1016*3 + 2] = 0.337954f;
+ 	val_dir[1017*3 + 0] = 0.930352f;	val_dir[1017*3 + 1] = -0.155059f;	val_dir[1017*3 + 2] = 0.332269f;
+ 	val_dir[1018*3 + 0] = 0.936111f;	val_dir[1018*3 + 1] = -0.130620f;	val_dir[1018*3 + 2] = 0.326550f;
+ 	val_dir[1019*3 + 0] = 0.941082f;	val_dir[1019*3 + 1] = -0.106941f;	val_dir[1019*3 + 2] = 0.320824f;
+ 	val_dir[1020*3 + 0] = 0.945328f;	val_dir[1020*3 + 1] = -0.084029f;	val_dir[1020*3 + 2] = 0.315109f;
+ 	val_dir[1021*3 + 0] = 0.948908f;	val_dir[1021*3 + 1] = -0.061885f;	val_dir[1021*3 + 2] = 0.309426f;
+ 	val_dir[1022*3 + 0] = 0.951877f;	val_dir[1022*3 + 1] = -0.040505f;	val_dir[1022*3 + 2] = 0.303791f;
+ 	val_dir[1023*3 + 0] = 0.954291f;	val_dir[1023*3 + 1] = -0.019881f;	val_dir[1023*3 + 2] = 0.298216f;
+ 	val_dir[1024*3 + 0] = 0.95620f;	val_dir[1024*3 + 1] = 0.0f;	val_dir[1024*3 + 2] = 0.292714f;
+ 	val_dir[1025*3 + 0] = 0.967641f;	val_dir[1025*3 + 1] = 0.019353f;	val_dir[1025*3 + 2] = 0.251587f;
+ 	val_dir[1026*3 + 0] = 0.976804f;	val_dir[1026*3 + 1] = 0.038306f;	val_dir[1026*3 + 2] = 0.210683f;
+ 	val_dir[1027*3 + 0] = 0.983762f;	val_dir[1027*3 + 1] = 0.056756f;	val_dir[1027*3 + 2] = 0.170267f;
+ 	val_dir[1028*3 + 0] = 0.988627f;	val_dir[1028*3 + 1] = 0.074613f;	val_dir[1028*3 + 2] = 0.130573f;
+ 	val_dir[1029*3 + 0] = 0.991535f;	val_dir[1029*3 + 1] = 0.091809f;	val_dir[1029*3 + 2] = 0.091809f;
+ 	val_dir[1030*3 + 0] = 0.992644f;	val_dir[1030*3 + 1] = 0.108288f;	val_dir[1030*3 + 2] = 0.054144f;
+ 	val_dir[1031*3 + 0] = 0.992122f;	val_dir[1031*3 + 1] = 0.124015f;	val_dir[1031*3 + 2] = 0.017716f;
+ 	val_dir[1032*3 + 0] = -0.141421f;	val_dir[1032*3 + 1] = -0.989949f;	val_dir[1032*3 + 2] = 0.0f;
+ 	val_dir[1033*3 + 0] = -0.126172f;	val_dir[1033*3 + 1] = -0.991353f;	val_dir[1033*3 + 2] = 0.036049f;
+ 	val_dir[1034*3 + 0] = -0.110133f;	val_dir[1034*3 + 1] = -0.991201f;	val_dir[1034*3 + 2] = 0.073422f;
+ 	val_dir[1035*3 + 0] = -0.093332f;	val_dir[1035*3 + 1] = -0.989316f;	val_dir[1035*3 + 2] = 0.111998f;
+ 	val_dir[1036*3 + 0] = -0.075810f;	val_dir[1036*3 + 1] = -0.985527f;	val_dir[1036*3 + 2] = 0.151620f;
+ 	val_dir[1037*3 + 0] = -0.057628f;	val_dir[1037*3 + 1] = -0.979683f;	val_dir[1037*3 + 2] = 0.192095f;
+ 	val_dir[1038*3 + 0] = -0.038866f;	val_dir[1038*3 + 1] = -0.971653f;	val_dir[1038*3 + 2] = 0.233197f;
+ 	val_dir[1039*3 + 0] = -0.019619f;	val_dir[1039*3 + 1] = -0.961339f;	val_dir[1039*3 + 2] = 0.274668f;
+ 	val_dir[1040*3 + 0] = 0.0f;	val_dir[1040*3 + 1] = -0.948683f;	val_dir[1040*3 + 2] = 0.316228f;
+ 	val_dir[1041*3 + 0] = 0.020137f;	val_dir[1041*3 + 1] = -0.946458f;	val_dir[1041*3 + 2] = 0.322198f;
+ 	val_dir[1042*3 + 0] = 0.041030f;	val_dir[1042*3 + 1] = -0.943701f;	val_dir[1042*3 + 2] = 0.328244f;
+ 	val_dir[1043*3 + 0] = 0.062691f;	val_dir[1043*3 + 1] = -0.940361f;	val_dir[1043*3 + 2] = 0.334351f;
+ 	val_dir[1044*3 + 0] = 0.085126f;	val_dir[1044*3 + 1] = -0.936382f;	val_dir[1044*3 + 2] = 0.340503f;
+ 	val_dir[1045*3 + 0] = 0.108338f;	val_dir[1045*3 + 1] = -0.931705f;	val_dir[1045*3 + 2] = 0.346681f;
+ 	val_dir[1046*3 + 0] = 0.132324f;	val_dir[1046*3 + 1] = -0.926270f;	val_dir[1046*3 + 2] = 0.352865f;
+ 	val_dir[1047*3 + 0] = 0.157075f;	val_dir[1047*3 + 1] = -0.920014f;	val_dir[1047*3 + 2] = 0.359030f;
+ 	val_dir[1048*3 + 0] = 0.182574f;	val_dir[1048*3 + 1] = -0.912871f;	val_dir[1048*3 + 2] = 0.365148f;
+ 	val_dir[1049*3 + 0] = 0.208795f;	val_dir[1049*3 + 1] = -0.904777f;	val_dir[1049*3 + 2] = 0.371191f;
+ 	val_dir[1050*3 + 0] = 0.235702f;	val_dir[1050*3 + 1] = -0.895669f;	val_dir[1050*3 + 2] = 0.377124f;
+ 	val_dir[1051*3 + 0] = 0.263251f;	val_dir[1051*3 + 1] = -0.885482f;	val_dir[1051*3 + 2] = 0.382911f;
+ 	val_dir[1052*3 + 0] = 0.291386f;	val_dir[1052*3 + 1] = -0.874157f;	val_dir[1052*3 + 2] = 0.388514f;
+ 	val_dir[1053*3 + 0] = 0.320038f;	val_dir[1053*3 + 1] = -0.861640f;	val_dir[1053*3 + 2] = 0.393893f;
+ 	val_dir[1054*3 + 0] = 0.349128f;	val_dir[1054*3 + 1] = -0.847883f;	val_dir[1054*3 + 2] = 0.399004f;
+ 	val_dir[1055*3 + 0] = 0.378566f;	val_dir[1055*3 + 1] = -0.832845f;	val_dir[1055*3 + 2] = 0.403804f;
+ 	val_dir[1056*3 + 0] = 0.408248f;	val_dir[1056*3 + 1] = -0.816497f;	val_dir[1056*3 + 2] = 0.408248f;
+ 	val_dir[1057*3 + 0] = 0.438063f;	val_dir[1057*3 + 1] = -0.798820f;	val_dir[1057*3 + 2] = 0.412294f;
+ 	val_dir[1058*3 + 0] = 0.467888f;	val_dir[1058*3 + 1] = -0.779813f;	val_dir[1058*3 + 2] = 0.41590f;
+ 	val_dir[1059*3 + 0] = 0.497594f;	val_dir[1059*3 + 1] = -0.759485f;	val_dir[1059*3 + 2] = 0.419026f;
+ 	val_dir[1060*3 + 0] = 0.527046f;	val_dir[1060*3 + 1] = -0.737865f;	val_dir[1060*3 + 2] = 0.421637f;
+ 	val_dir[1061*3 + 0] = 0.556108f;	val_dir[1061*3 + 1] = -0.714997f;	val_dir[1061*3 + 2] = 0.423702f;
+ 	val_dir[1062*3 + 0] = 0.584643f;	val_dir[1062*3 + 1] = -0.690942f;	val_dir[1062*3 + 2] = 0.425195f;
+ 	val_dir[1063*3 + 0] = 0.612517f;	val_dir[1063*3 + 1] = -0.665780f;	val_dir[1063*3 + 2] = 0.426099f;
+ 	val_dir[1064*3 + 0] = 0.639602f;	val_dir[1064*3 + 1] = -0.639602f;	val_dir[1064*3 + 2] = 0.426401f;
+ 	val_dir[1065*3 + 0] = 0.665780f;	val_dir[1065*3 + 1] = -0.612517f;	val_dir[1065*3 + 2] = 0.426099f;
+ 	val_dir[1066*3 + 0] = 0.690942f;	val_dir[1066*3 + 1] = -0.584643f;	val_dir[1066*3 + 2] = 0.425195f;
+ 	val_dir[1067*3 + 0] = 0.714997f;	val_dir[1067*3 + 1] = -0.556108f;	val_dir[1067*3 + 2] = 0.423702f;
+ 	val_dir[1068*3 + 0] = 0.737865f;	val_dir[1068*3 + 1] = -0.527046f;	val_dir[1068*3 + 2] = 0.421637f;
+ 	val_dir[1069*3 + 0] = 0.759485f;	val_dir[1069*3 + 1] = -0.497594f;	val_dir[1069*3 + 2] = 0.419026f;
+ 	val_dir[1070*3 + 0] = 0.779813f;	val_dir[1070*3 + 1] = -0.467888f;	val_dir[1070*3 + 2] = 0.41590f;
+ 	val_dir[1071*3 + 0] = 0.798820f;	val_dir[1071*3 + 1] = -0.438063f;	val_dir[1071*3 + 2] = 0.412294f;
+ 	val_dir[1072*3 + 0] = 0.816497f;	val_dir[1072*3 + 1] = -0.408248f;	val_dir[1072*3 + 2] = 0.408248f;
+ 	val_dir[1073*3 + 0] = 0.832845f;	val_dir[1073*3 + 1] = -0.378566f;	val_dir[1073*3 + 2] = 0.403804f;
+ 	val_dir[1074*3 + 0] = 0.847883f;	val_dir[1074*3 + 1] = -0.349128f;	val_dir[1074*3 + 2] = 0.399004f;
+ 	val_dir[1075*3 + 0] = 0.861640f;	val_dir[1075*3 + 1] = -0.320038f;	val_dir[1075*3 + 2] = 0.393893f;
+ 	val_dir[1076*3 + 0] = 0.874157f;	val_dir[1076*3 + 1] = -0.291386f;	val_dir[1076*3 + 2] = 0.388514f;
+ 	val_dir[1077*3 + 0] = 0.885482f;	val_dir[1077*3 + 1] = -0.263251f;	val_dir[1077*3 + 2] = 0.382911f;
+ 	val_dir[1078*3 + 0] = 0.895669f;	val_dir[1078*3 + 1] = -0.235702f;	val_dir[1078*3 + 2] = 0.377124f;
+ 	val_dir[1079*3 + 0] = 0.904777f;	val_dir[1079*3 + 1] = -0.208795f;	val_dir[1079*3 + 2] = 0.371191f;
+ 	val_dir[1080*3 + 0] = 0.912871f;	val_dir[1080*3 + 1] = -0.182574f;	val_dir[1080*3 + 2] = 0.365148f;
+ 	val_dir[1081*3 + 0] = 0.920014f;	val_dir[1081*3 + 1] = -0.157075f;	val_dir[1081*3 + 2] = 0.359030f;
+ 	val_dir[1082*3 + 0] = 0.926270f;	val_dir[1082*3 + 1] = -0.132324f;	val_dir[1082*3 + 2] = 0.352865f;
+ 	val_dir[1083*3 + 0] = 0.931705f;	val_dir[1083*3 + 1] = -0.108338f;	val_dir[1083*3 + 2] = 0.346681f;
+ 	val_dir[1084*3 + 0] = 0.936382f;	val_dir[1084*3 + 1] = -0.085126f;	val_dir[1084*3 + 2] = 0.340503f;
+ 	val_dir[1085*3 + 0] = 0.940361f;	val_dir[1085*3 + 1] = -0.062691f;	val_dir[1085*3 + 2] = 0.334351f;
+ 	val_dir[1086*3 + 0] = 0.943701f;	val_dir[1086*3 + 1] = -0.041030f;	val_dir[1086*3 + 2] = 0.328244f;
+ 	val_dir[1087*3 + 0] = 0.946458f;	val_dir[1087*3 + 1] = -0.020137f;	val_dir[1087*3 + 2] = 0.322198f;
+ 	val_dir[1088*3 + 0] = 0.948683f;	val_dir[1088*3 + 1] = 0.0f;	val_dir[1088*3 + 2] = 0.316228f;
+ 	val_dir[1089*3 + 0] = 0.961339f;	val_dir[1089*3 + 1] = 0.019619f;	val_dir[1089*3 + 2] = 0.274668f;
+ 	val_dir[1090*3 + 0] = 0.971653f;	val_dir[1090*3 + 1] = 0.038866f;	val_dir[1090*3 + 2] = 0.233197f;
+ 	val_dir[1091*3 + 0] = 0.979683f;	val_dir[1091*3 + 1] = 0.057628f;	val_dir[1091*3 + 2] = 0.192095f;
+ 	val_dir[1092*3 + 0] = 0.985527f;	val_dir[1092*3 + 1] = 0.075810f;	val_dir[1092*3 + 2] = 0.151620f;
+ 	val_dir[1093*3 + 0] = 0.989316f;	val_dir[1093*3 + 1] = 0.093332f;	val_dir[1093*3 + 2] = 0.111998f;
+ 	val_dir[1094*3 + 0] = 0.991201f;	val_dir[1094*3 + 1] = 0.110133f;	val_dir[1094*3 + 2] = 0.073422f;
+ 	val_dir[1095*3 + 0] = 0.991353f;	val_dir[1095*3 + 1] = 0.126172f;	val_dir[1095*3 + 2] = 0.036049f;
+ 	val_dir[1096*3 + 0] = 0.989949f;	val_dir[1096*3 + 1] = 0.141421f;	val_dir[1096*3 + 2] = 0.0f;
+ 	val_dir[1097*3 + 0] = -0.143917f;	val_dir[1097*3 + 1] = -0.989426f;	val_dir[1097*3 + 2] = 0.017990f;
+ 	val_dir[1098*3 + 0] = -0.128359f;	val_dir[1098*3 + 1] = -0.990201f;	val_dir[1098*3 + 2] = 0.055011f;
+ 	val_dir[1099*3 + 0] = -0.111998f;	val_dir[1099*3 + 1] = -0.989316f;	val_dir[1099*3 + 2] = 0.093332f;
+ 	val_dir[1100*3 + 0] = -0.094865f;	val_dir[1100*3 + 1] = -0.986591f;	val_dir[1100*3 + 2] = 0.132810f;
+ 	val_dir[1101*3 + 0] = -0.077009f;	val_dir[1101*3 + 1] = -0.981859f;	val_dir[1101*3 + 2] = 0.173269f;
+ 	val_dir[1102*3 + 0] = -0.058498f;	val_dir[1102*3 + 1] = -0.974972f;	val_dir[1102*3 + 2] = 0.214494f;
+ 	val_dir[1103*3 + 0] = -0.039421f;	val_dir[1103*3 + 1] = -0.965810f;	val_dir[1103*3 + 2] = 0.256235f;
+ 	val_dir[1104*3 + 0] = -0.019881f;	val_dir[1104*3 + 1] = -0.954291f;	val_dir[1104*3 + 2] = 0.298216f;
+ 	val_dir[1105*3 + 0] = 0.0f;	val_dir[1105*3 + 1] = -0.940376f;	val_dir[1105*3 + 2] = 0.340136f;
+ 	val_dir[1106*3 + 0] = 0.020387f;	val_dir[1106*3 + 1] = -0.93780f;	val_dir[1106*3 + 2] = 0.346578f;
+ 	val_dir[1107*3 + 0] = 0.041541f;	val_dir[1107*3 + 1] = -0.934665f;	val_dir[1107*3 + 2] = 0.353096f;
+ 	val_dir[1108*3 + 0] = 0.063472f;	val_dir[1108*3 + 1] = -0.930917f;	val_dir[1108*3 + 2] = 0.359673f;
+ 	val_dir[1109*3 + 0] = 0.086186f;	val_dir[1109*3 + 1] = -0.92650f;	val_dir[1109*3 + 2] = 0.366291f;
+ 	val_dir[1110*3 + 0] = 0.109685f;	val_dir[1110*3 + 1] = -0.921354f;	val_dir[1110*3 + 2] = 0.372929f;
+ 	val_dir[1111*3 + 0] = 0.133963f;	val_dir[1111*3 + 1] = -0.915416f;	val_dir[1111*3 + 2] = 0.379563f;
+ 	val_dir[1112*3 + 0] = 0.159009f;	val_dir[1112*3 + 1] = -0.908622f;	val_dir[1112*3 + 2] = 0.386164f;
+ 	val_dir[1113*3 + 0] = 0.184801f;	val_dir[1113*3 + 1] = -0.900907f;	val_dir[1113*3 + 2] = 0.392703f;
+ 	val_dir[1114*3 + 0] = 0.211312f;	val_dir[1114*3 + 1] = -0.892206f;	val_dir[1114*3 + 2] = 0.399145f;
+ 	val_dir[1115*3 + 0] = 0.238501f;	val_dir[1115*3 + 1] = -0.882454f;	val_dir[1115*3 + 2] = 0.405452f;
+ 	val_dir[1116*3 + 0] = 0.266320f;	val_dir[1116*3 + 1] = -0.871592f;	val_dir[1116*3 + 2] = 0.411585f;
+ 	val_dir[1117*3 + 0] = 0.294706f;	val_dir[1117*3 + 1] = -0.859559f;	val_dir[1117*3 + 2] = 0.41750f;
+ 	val_dir[1118*3 + 0] = 0.323587f;	val_dir[1118*3 + 1] = -0.846305f;	val_dir[1118*3 + 2] = 0.423153f;
+ 	val_dir[1119*3 + 0] = 0.352879f;	val_dir[1119*3 + 1] = -0.831786f;	val_dir[1119*3 + 2] = 0.428496f;
+ 	val_dir[1120*3 + 0] = 0.382484f;	val_dir[1120*3 + 1] = -0.815966f;	val_dir[1120*3 + 2] = 0.433482f;
+ 	val_dir[1121*3 + 0] = 0.412294f;	val_dir[1121*3 + 1] = -0.798820f;	val_dir[1121*3 + 2] = 0.438063f;
+ 	val_dir[1122*3 + 0] = 0.442193f;	val_dir[1122*3 + 1] = -0.780340f;	val_dir[1122*3 + 2] = 0.442193f;
+ 	val_dir[1123*3 + 0] = 0.472053f;	val_dir[1123*3 + 1] = -0.760529f;	val_dir[1123*3 + 2] = 0.445827f;
+ 	val_dir[1124*3 + 0] = 0.501740f;	val_dir[1124*3 + 1] = -0.739407f;	val_dir[1124*3 + 2] = 0.448926f;
+ 	val_dir[1125*3 + 0] = 0.531119f;	val_dir[1125*3 + 1] = -0.717011f;	val_dir[1125*3 + 2] = 0.451451f;
+ 	val_dir[1126*3 + 0] = 0.560050f;	val_dir[1126*3 + 1] = -0.693395f;	val_dir[1126*3 + 2] = 0.453374f;
+ 	val_dir[1127*3 + 0] = 0.588395f;	val_dir[1127*3 + 1] = -0.668631f;	val_dir[1127*3 + 2] = 0.454669f;
+ 	val_dir[1128*3 + 0] = 0.616022f;	val_dir[1128*3 + 1] = -0.642806f;	val_dir[1128*3 + 2] = 0.455321f;
+ 	val_dir[1129*3 + 0] = 0.642806f;	val_dir[1129*3 + 1] = -0.616022f;	val_dir[1129*3 + 2] = 0.455321f;
+ 	val_dir[1130*3 + 0] = 0.668631f;	val_dir[1130*3 + 1] = -0.588395f;	val_dir[1130*3 + 2] = 0.454669f;
+ 	val_dir[1131*3 + 0] = 0.693395f;	val_dir[1131*3 + 1] = -0.560050f;	val_dir[1131*3 + 2] = 0.453374f;
+ 	val_dir[1132*3 + 0] = 0.717011f;	val_dir[1132*3 + 1] = -0.531119f;	val_dir[1132*3 + 2] = 0.451451f;
+ 	val_dir[1133*3 + 0] = 0.739407f;	val_dir[1133*3 + 1] = -0.501740f;	val_dir[1133*3 + 2] = 0.448926f;
+ 	val_dir[1134*3 + 0] = 0.760529f;	val_dir[1134*3 + 1] = -0.472053f;	val_dir[1134*3 + 2] = 0.445827f;
+ 	val_dir[1135*3 + 0] = 0.780340f;	val_dir[1135*3 + 1] = -0.442193f;	val_dir[1135*3 + 2] = 0.442193f;
+ 	val_dir[1136*3 + 0] = 0.798820f;	val_dir[1136*3 + 1] = -0.412294f;	val_dir[1136*3 + 2] = 0.438063f;
+ 	val_dir[1137*3 + 0] = 0.815966f;	val_dir[1137*3 + 1] = -0.382484f;	val_dir[1137*3 + 2] = 0.433482f;
+ 	val_dir[1138*3 + 0] = 0.831786f;	val_dir[1138*3 + 1] = -0.352879f;	val_dir[1138*3 + 2] = 0.428496f;
+ 	val_dir[1139*3 + 0] = 0.846305f;	val_dir[1139*3 + 1] = -0.323587f;	val_dir[1139*3 + 2] = 0.423153f;
+ 	val_dir[1140*3 + 0] = 0.859559f;	val_dir[1140*3 + 1] = -0.294706f;	val_dir[1140*3 + 2] = 0.41750f;
+ 	val_dir[1141*3 + 0] = 0.871592f;	val_dir[1141*3 + 1] = -0.266320f;	val_dir[1141*3 + 2] = 0.411585f;
+ 	val_dir[1142*3 + 0] = 0.882454f;	val_dir[1142*3 + 1] = -0.238501f;	val_dir[1142*3 + 2] = 0.405452f;
+ 	val_dir[1143*3 + 0] = 0.892206f;	val_dir[1143*3 + 1] = -0.211312f;	val_dir[1143*3 + 2] = 0.399145f;
+ 	val_dir[1144*3 + 0] = 0.900907f;	val_dir[1144*3 + 1] = -0.184801f;	val_dir[1144*3 + 2] = 0.392703f;
+ 	val_dir[1145*3 + 0] = 0.908622f;	val_dir[1145*3 + 1] = -0.159009f;	val_dir[1145*3 + 2] = 0.386164f;
+ 	val_dir[1146*3 + 0] = 0.915416f;	val_dir[1146*3 + 1] = -0.133963f;	val_dir[1146*3 + 2] = 0.379563f;
+ 	val_dir[1147*3 + 0] = 0.921354f;	val_dir[1147*3 + 1] = -0.109685f;	val_dir[1147*3 + 2] = 0.372929f;
+ 	val_dir[1148*3 + 0] = 0.92650f;	val_dir[1148*3 + 1] = -0.086186f;	val_dir[1148*3 + 2] = 0.366291f;
+ 	val_dir[1149*3 + 0] = 0.930917f;	val_dir[1149*3 + 1] = -0.063472f;	val_dir[1149*3 + 2] = 0.359673f;
+ 	val_dir[1150*3 + 0] = 0.934665f;	val_dir[1150*3 + 1] = -0.041541f;	val_dir[1150*3 + 2] = 0.353096f;
+ 	val_dir[1151*3 + 0] = 0.93780f;	val_dir[1151*3 + 1] = -0.020387f;	val_dir[1151*3 + 2] = 0.346578f;
+ 	val_dir[1152*3 + 0] = 0.940376f;	val_dir[1152*3 + 1] = 0.0f;	val_dir[1152*3 + 2] = 0.340136f;
+ 	val_dir[1153*3 + 0] = 0.954291f;	val_dir[1153*3 + 1] = 0.019881f;	val_dir[1153*3 + 2] = 0.298216f;
+ 	val_dir[1154*3 + 0] = 0.965810f;	val_dir[1154*3 + 1] = 0.039421f;	val_dir[1154*3 + 2] = 0.256235f;
+ 	val_dir[1155*3 + 0] = 0.974972f;	val_dir[1155*3 + 1] = 0.058498f;	val_dir[1155*3 + 2] = 0.214494f;
+ 	val_dir[1156*3 + 0] = 0.981859f;	val_dir[1156*3 + 1] = 0.077009f;	val_dir[1156*3 + 2] = 0.173269f;
+ 	val_dir[1157*3 + 0] = 0.986591f;	val_dir[1157*3 + 1] = 0.094865f;	val_dir[1157*3 + 2] = 0.132810f;
+ 	val_dir[1158*3 + 0] = 0.989316f;	val_dir[1158*3 + 1] = 0.111998f;	val_dir[1158*3 + 2] = 0.093332f;
+ 	val_dir[1159*3 + 0] = 0.990201f;	val_dir[1159*3 + 1] = 0.128359f;	val_dir[1159*3 + 2] = 0.055011f;
+ 	val_dir[1160*3 + 0] = 0.989426f;	val_dir[1160*3 + 1] = 0.143917f;	val_dir[1160*3 + 2] = 0.017990f;
+ 	val_dir[1161*3 + 0] = -0.161489f;	val_dir[1161*3 + 1] = -0.986875f;	val_dir[1161*3 + 2] = 0.0f;
+ 	val_dir[1162*3 + 0] = -0.146450f;	val_dir[1162*3 + 1] = -0.988540f;	val_dir[1162*3 + 2] = 0.036613f;
+ 	val_dir[1163*3 + 0] = -0.130573f;	val_dir[1163*3 + 1] = -0.988627f;	val_dir[1163*3 + 2] = 0.074613f;
+ 	val_dir[1164*3 + 0] = -0.113878f;	val_dir[1164*3 + 1] = -0.986947f;	val_dir[1164*3 + 2] = 0.113878f;
+ 	val_dir[1165*3 + 0] = -0.096404f;	val_dir[1165*3 + 1] = -0.983318f;	val_dir[1165*3 + 2] = 0.154246f;
+ 	val_dir[1166*3 + 0] = -0.078206f;	val_dir[1166*3 + 1] = -0.977577f;	val_dir[1166*3 + 2] = 0.195515f;
+ 	val_dir[1167*3 + 0] = -0.059362f;	val_dir[1167*3 + 1] = -0.969584f;	val_dir[1167*3 + 2] = 0.237449f;
+ 	val_dir[1168*3 + 0] = -0.039968f;	val_dir[1168*3 + 1] = -0.959233f;	val_dir[1168*3 + 2] = 0.279776f;
+ 	val_dir[1169*3 + 0] = -0.020137f;	val_dir[1169*3 + 1] = -0.946458f;	val_dir[1169*3 + 2] = 0.322198f;
+ 	val_dir[1170*3 + 0] = 0.0f;	val_dir[1170*3 + 1] = -0.931243f;	val_dir[1170*3 + 2] = 0.364399f;
+ 	val_dir[1171*3 + 0] = 0.020628f;	val_dir[1171*3 + 1] = -0.928279f;	val_dir[1171*3 + 2] = 0.371312f;
+ 	val_dir[1172*3 + 0] = 0.042033f;	val_dir[1172*3 + 1] = -0.924729f;	val_dir[1172*3 + 2] = 0.378298f;
+ 	val_dir[1173*3 + 0] = 0.064223f;	val_dir[1173*3 + 1] = -0.920537f;	val_dir[1173*3 + 2] = 0.385341f;
+ 	val_dir[1174*3 + 0] = 0.087204f;	val_dir[1174*3 + 1] = -0.915644f;	val_dir[1174*3 + 2] = 0.392419f;
+ 	val_dir[1175*3 + 0] = 0.110974f;	val_dir[1175*3 + 1] = -0.909988f;	val_dir[1175*3 + 2] = 0.399507f;
+ 	val_dir[1176*3 + 0] = 0.135526f;	val_dir[1176*3 + 1] = -0.903508f;	val_dir[1176*3 + 2] = 0.406579f;
+ 	val_dir[1177*3 + 0] = 0.160845f;	val_dir[1177*3 + 1] = -0.896137f;	val_dir[1177*3 + 2] = 0.413602f;
+ 	val_dir[1178*3 + 0] = 0.186908f;	val_dir[1178*3 + 1] = -0.887812f;	val_dir[1178*3 + 2] = 0.420542f;
+ 	val_dir[1179*3 + 0] = 0.213681f;	val_dir[1179*3 + 1] = -0.878466f;	val_dir[1179*3 + 2] = 0.427362f;
+ 	val_dir[1180*3 + 0] = 0.241121f;	val_dir[1180*3 + 1] = -0.868037f;	val_dir[1180*3 + 2] = 0.434019f;
+ 	val_dir[1181*3 + 0] = 0.269175f;	val_dir[1181*3 + 1] = -0.856465f;	val_dir[1181*3 + 2] = 0.440468f;
+ 	val_dir[1182*3 + 0] = 0.297775f;	val_dir[1182*3 + 1] = -0.843696f;	val_dir[1182*3 + 2] = 0.446662f;
+ 	val_dir[1183*3 + 0] = 0.326844f;	val_dir[1183*3 + 1] = -0.829680f;	val_dir[1183*3 + 2] = 0.452553f;
+ 	val_dir[1184*3 + 0] = 0.356291f;	val_dir[1184*3 + 1] = -0.814379f;	val_dir[1184*3 + 2] = 0.458088f;
+ 	val_dir[1185*3 + 0] = 0.386014f;	val_dir[1185*3 + 1] = -0.797762f;	val_dir[1185*3 + 2] = 0.463217f;
+ 	val_dir[1186*3 + 0] = 0.41590f;	val_dir[1186*3 + 1] = -0.779813f;	val_dir[1186*3 + 2] = 0.467888f;
+ 	val_dir[1187*3 + 0] = 0.445827f;	val_dir[1187*3 + 1] = -0.760529f;	val_dir[1187*3 + 2] = 0.472053f;
+ 	val_dir[1188*3 + 0] = 0.475665f;	val_dir[1188*3 + 1] = -0.739923f;	val_dir[1188*3 + 2] = 0.475665f;
+ 	val_dir[1189*3 + 0] = 0.505276f;	val_dir[1189*3 + 1] = -0.718024f;	val_dir[1189*3 + 2] = 0.478683f;
+ 	val_dir[1190*3 + 0] = 0.534522f;	val_dir[1190*3 + 1] = -0.694879f;	val_dir[1190*3 + 2] = 0.481070f;
+ 	val_dir[1191*3 + 0] = 0.563264f;	val_dir[1191*3 + 1] = -0.670552f;	val_dir[1191*3 + 2] = 0.482798f;
+ 	val_dir[1192*3 + 0] = 0.591364f;	val_dir[1192*3 + 1] = -0.645124f;	val_dir[1192*3 + 2] = 0.483843f;
+ 	val_dir[1193*3 + 0] = 0.618691f;	val_dir[1193*3 + 1] = -0.618691f;	val_dir[1193*3 + 2] = 0.484193f;
+ 	val_dir[1194*3 + 0] = 0.645124f;	val_dir[1194*3 + 1] = -0.591364f;	val_dir[1194*3 + 2] = 0.483843f;
+ 	val_dir[1195*3 + 0] = 0.670552f;	val_dir[1195*3 + 1] = -0.563264f;	val_dir[1195*3 + 2] = 0.482798f;
+ 	val_dir[1196*3 + 0] = 0.694879f;	val_dir[1196*3 + 1] = -0.534522f;	val_dir[1196*3 + 2] = 0.481070f;
+ 	val_dir[1197*3 + 0] = 0.718024f;	val_dir[1197*3 + 1] = -0.505276f;	val_dir[1197*3 + 2] = 0.478683f;
+ 	val_dir[1198*3 + 0] = 0.739923f;	val_dir[1198*3 + 1] = -0.475665f;	val_dir[1198*3 + 2] = 0.475665f;
+ 	val_dir[1199*3 + 0] = 0.760529f;	val_dir[1199*3 + 1] = -0.445827f;	val_dir[1199*3 + 2] = 0.472053f;
+ 	val_dir[1200*3 + 0] = 0.779813f;	val_dir[1200*3 + 1] = -0.41590f;	val_dir[1200*3 + 2] = 0.467888f;
+ 	val_dir[1201*3 + 0] = 0.797762f;	val_dir[1201*3 + 1] = -0.386014f;	val_dir[1201*3 + 2] = 0.463217f;
+ 	val_dir[1202*3 + 0] = 0.814379f;	val_dir[1202*3 + 1] = -0.356291f;	val_dir[1202*3 + 2] = 0.458088f;
+ 	val_dir[1203*3 + 0] = 0.829680f;	val_dir[1203*3 + 1] = -0.326844f;	val_dir[1203*3 + 2] = 0.452553f;
+ 	val_dir[1204*3 + 0] = 0.843696f;	val_dir[1204*3 + 1] = -0.297775f;	val_dir[1204*3 + 2] = 0.446662f;
+ 	val_dir[1205*3 + 0] = 0.856465f;	val_dir[1205*3 + 1] = -0.269175f;	val_dir[1205*3 + 2] = 0.440468f;
+ 	val_dir[1206*3 + 0] = 0.868037f;	val_dir[1206*3 + 1] = -0.241121f;	val_dir[1206*3 + 2] = 0.434019f;
+ 	val_dir[1207*3 + 0] = 0.878466f;	val_dir[1207*3 + 1] = -0.213681f;	val_dir[1207*3 + 2] = 0.427362f;
+ 	val_dir[1208*3 + 0] = 0.887812f;	val_dir[1208*3 + 1] = -0.186908f;	val_dir[1208*3 + 2] = 0.420542f;
+ 	val_dir[1209*3 + 0] = 0.896137f;	val_dir[1209*3 + 1] = -0.160845f;	val_dir[1209*3 + 2] = 0.413602f;
+ 	val_dir[1210*3 + 0] = 0.903508f;	val_dir[1210*3 + 1] = -0.135526f;	val_dir[1210*3 + 2] = 0.406579f;
+ 	val_dir[1211*3 + 0] = 0.909988f;	val_dir[1211*3 + 1] = -0.110974f;	val_dir[1211*3 + 2] = 0.399507f;
+ 	val_dir[1212*3 + 0] = 0.915644f;	val_dir[1212*3 + 1] = -0.087204f;	val_dir[1212*3 + 2] = 0.392419f;
+ 	val_dir[1213*3 + 0] = 0.920537f;	val_dir[1213*3 + 1] = -0.064223f;	val_dir[1213*3 + 2] = 0.385341f;
+ 	val_dir[1214*3 + 0] = 0.924729f;	val_dir[1214*3 + 1] = -0.042033f;	val_dir[1214*3 + 2] = 0.378298f;
+ 	val_dir[1215*3 + 0] = 0.928279f;	val_dir[1215*3 + 1] = -0.020628f;	val_dir[1215*3 + 2] = 0.371312f;
+ 	val_dir[1216*3 + 0] = 0.931243f;	val_dir[1216*3 + 1] = 0.0f;	val_dir[1216*3 + 2] = 0.364399f;
+ 	val_dir[1217*3 + 0] = 0.946458f;	val_dir[1217*3 + 1] = 0.020137f;	val_dir[1217*3 + 2] = 0.322198f;
+ 	val_dir[1218*3 + 0] = 0.959233f;	val_dir[1218*3 + 1] = 0.039968f;	val_dir[1218*3 + 2] = 0.279776f;
+ 	val_dir[1219*3 + 0] = 0.969584f;	val_dir[1219*3 + 1] = 0.059362f;	val_dir[1219*3 + 2] = 0.237449f;
+ 	val_dir[1220*3 + 0] = 0.977577f;	val_dir[1220*3 + 1] = 0.078206f;	val_dir[1220*3 + 2] = 0.195515f;
+ 	val_dir[1221*3 + 0] = 0.983318f;	val_dir[1221*3 + 1] = 0.096404f;	val_dir[1221*3 + 2] = 0.154246f;
+ 	val_dir[1222*3 + 0] = 0.986947f;	val_dir[1222*3 + 1] = 0.113878f;	val_dir[1222*3 + 2] = 0.113878f;
+ 	val_dir[1223*3 + 0] = 0.988627f;	val_dir[1223*3 + 1] = 0.130573f;	val_dir[1223*3 + 2] = 0.074613f;
+ 	val_dir[1224*3 + 0] = 0.988540f;	val_dir[1224*3 + 1] = 0.146450f;	val_dir[1224*3 + 2] = 0.036613f;
+ 	val_dir[1225*3 + 0] = 0.986875f;	val_dir[1225*3 + 1] = 0.161489f;	val_dir[1225*3 + 2] = 0.0f;
+ 	val_dir[1226*3 + 0] = -0.164372f;	val_dir[1226*3 + 1] = -0.986229f;	val_dir[1226*3 + 2] = 0.018264f;
+ 	val_dir[1227*3 + 0] = -0.149019f;	val_dir[1227*3 + 1] = -0.987254f;	val_dir[1227*3 + 2] = 0.055882f;
+ 	val_dir[1228*3 + 0] = -0.132810f;	val_dir[1228*3 + 1] = -0.986591f;	val_dir[1228*3 + 2] = 0.094865f;
+ 	val_dir[1229*3 + 0] = -0.115771f;	val_dir[1229*3 + 1] = -0.984050f;	val_dir[1229*3 + 2] = 0.135066f;
+ 	val_dir[1230*3 + 0] = -0.097945f;	val_dir[1230*3 + 1] = -0.979451f;	val_dir[1230*3 + 2] = 0.176301f;
+ 	val_dir[1231*3 + 0] = -0.079399f;	val_dir[1231*3 + 1] = -0.972636f;	val_dir[1231*3 + 2] = 0.218347f;
+ 	val_dir[1232*3 + 0] = -0.060217f;	val_dir[1232*3 + 1] = -0.963475f;	val_dir[1232*3 + 2] = 0.260941f;
+ 	val_dir[1233*3 + 0] = -0.040505f;	val_dir[1233*3 + 1] = -0.951877f;	val_dir[1233*3 + 2] = 0.303791f;
+ 	val_dir[1234*3 + 0] = -0.020387f;	val_dir[1234*3 + 1] = -0.93780f;	val_dir[1234*3 + 2] = 0.346578f;
+ 	val_dir[1235*3 + 0] = 0.0f;	val_dir[1235*3 + 1] = -0.921250f;	val_dir[1235*3 + 2] = 0.388972f;
+ 	val_dir[1236*3 + 0] = 0.020861f;	val_dir[1236*3 + 1] = -0.917863f;	val_dir[1236*3 + 2] = 0.396350f;
+ 	val_dir[1237*3 + 0] = 0.042505f;	val_dir[1237*3 + 1] = -0.913860f;	val_dir[1237*3 + 2] = 0.403799f;
+ 	val_dir[1238*3 + 0] = 0.064942f;	val_dir[1238*3 + 1] = -0.909185f;	val_dir[1238*3 + 2] = 0.411298f;
+ 	val_dir[1239*3 + 0] = 0.088173f;	val_dir[1239*3 + 1] = -0.903777f;	val_dir[1239*3 + 2] = 0.418823f;
+ 	val_dir[1240*3 + 0] = 0.112197f;	val_dir[1240*3 + 1] = -0.897574f;	val_dir[1240*3 + 2] = 0.426348f;
+ 	val_dir[1241*3 + 0] = 0.137002f;	val_dir[1241*3 + 1] = -0.890513f;	val_dir[1241*3 + 2] = 0.433840f;
+ 	val_dir[1242*3 + 0] = 0.162571f;	val_dir[1242*3 + 1] = -0.882528f;	val_dir[1242*3 + 2] = 0.441264f;
+ 	val_dir[1243*3 + 0] = 0.188877f;	val_dir[1243*3 + 1] = -0.873555f;	val_dir[1243*3 + 2] = 0.448583f;
+ 	val_dir[1244*3 + 0] = 0.215883f;	val_dir[1244*3 + 1] = -0.863530f;	val_dir[1244*3 + 2] = 0.455752f;
+ 	val_dir[1245*3 + 0] = 0.243541f;	val_dir[1245*3 + 1] = -0.852392f;	val_dir[1245*3 + 2] = 0.462727f;
+ 	val_dir[1246*3 + 0] = 0.271791f;	val_dir[1246*3 + 1] = -0.840083f;	val_dir[1246*3 + 2] = 0.469458f;
+ 	val_dir[1247*3 + 0] = 0.300564f;	val_dir[1247*3 + 1] = -0.826551f;	val_dir[1247*3 + 2] = 0.475893f;
+ 	val_dir[1248*3 + 0] = 0.329775f;	val_dir[1248*3 + 1] = -0.811754f;	val_dir[1248*3 + 2] = 0.481979f;
+ 	val_dir[1249*3 + 0] = 0.359329f;	val_dir[1249*3 + 1] = -0.795657f;	val_dir[1249*3 + 2] = 0.487661f;
+ 	val_dir[1250*3 + 0] = 0.389118f;	val_dir[1250*3 + 1] = -0.778237f;	val_dir[1250*3 + 2] = 0.492883f;
+ 	val_dir[1251*3 + 0] = 0.419026f;	val_dir[1251*3 + 1] = -0.759485f;	val_dir[1251*3 + 2] = 0.497594f;
+ 	val_dir[1252*3 + 0] = 0.448926f;	val_dir[1252*3 + 1] = -0.739407f;	val_dir[1252*3 + 2] = 0.501740f;
+ 	val_dir[1253*3 + 0] = 0.478683f;	val_dir[1253*3 + 1] = -0.718024f;	val_dir[1253*3 + 2] = 0.505276f;
+ 	val_dir[1254*3 + 0] = 0.508159f;	val_dir[1254*3 + 1] = -0.695376f;	val_dir[1254*3 + 2] = 0.508159f;
+ 	val_dir[1255*3 + 0] = 0.537215f;	val_dir[1255*3 + 1] = -0.671519f;	val_dir[1255*3 + 2] = 0.510355f;
+ 	val_dir[1256*3 + 0] = 0.565711f;	val_dir[1256*3 + 1] = -0.646527f;	val_dir[1256*3 + 2] = 0.511834f;
+ 	val_dir[1257*3 + 0] = 0.593512f;	val_dir[1257*3 + 1] = -0.620490f;	val_dir[1257*3 + 2] = 0.512578f;
+ 	val_dir[1258*3 + 0] = 0.620490f;	val_dir[1258*3 + 1] = -0.593512f;	val_dir[1258*3 + 2] = 0.512578f;
+ 	val_dir[1259*3 + 0] = 0.646527f;	val_dir[1259*3 + 1] = -0.565711f;	val_dir[1259*3 + 2] = 0.511834f;
+ 	val_dir[1260*3 + 0] = 0.671519f;	val_dir[1260*3 + 1] = -0.537215f;	val_dir[1260*3 + 2] = 0.510355f;
+ 	val_dir[1261*3 + 0] = 0.695376f;	val_dir[1261*3 + 1] = -0.508159f;	val_dir[1261*3 + 2] = 0.508159f;
+ 	val_dir[1262*3 + 0] = 0.718024f;	val_dir[1262*3 + 1] = -0.478683f;	val_dir[1262*3 + 2] = 0.505276f;
+ 	val_dir[1263*3 + 0] = 0.739407f;	val_dir[1263*3 + 1] = -0.448926f;	val_dir[1263*3 + 2] = 0.501740f;
+ 	val_dir[1264*3 + 0] = 0.759485f;	val_dir[1264*3 + 1] = -0.419026f;	val_dir[1264*3 + 2] = 0.497594f;
+ 	val_dir[1265*3 + 0] = 0.778237f;	val_dir[1265*3 + 1] = -0.389118f;	val_dir[1265*3 + 2] = 0.492883f;
+ 	val_dir[1266*3 + 0] = 0.795657f;	val_dir[1266*3 + 1] = -0.359329f;	val_dir[1266*3 + 2] = 0.487661f;
+ 	val_dir[1267*3 + 0] = 0.811754f;	val_dir[1267*3 + 1] = -0.329775f;	val_dir[1267*3 + 2] = 0.481979f;
+ 	val_dir[1268*3 + 0] = 0.826551f;	val_dir[1268*3 + 1] = -0.300564f;	val_dir[1268*3 + 2] = 0.475893f;
+ 	val_dir[1269*3 + 0] = 0.840083f;	val_dir[1269*3 + 1] = -0.271791f;	val_dir[1269*3 + 2] = 0.469458f;
+ 	val_dir[1270*3 + 0] = 0.852392f;	val_dir[1270*3 + 1] = -0.243541f;	val_dir[1270*3 + 2] = 0.462727f;
+ 	val_dir[1271*3 + 0] = 0.863530f;	val_dir[1271*3 + 1] = -0.215883f;	val_dir[1271*3 + 2] = 0.455752f;
+ 	val_dir[1272*3 + 0] = 0.873555f;	val_dir[1272*3 + 1] = -0.188877f;	val_dir[1272*3 + 2] = 0.448583f;
+ 	val_dir[1273*3 + 0] = 0.882528f;	val_dir[1273*3 + 1] = -0.162571f;	val_dir[1273*3 + 2] = 0.441264f;
+ 	val_dir[1274*3 + 0] = 0.890513f;	val_dir[1274*3 + 1] = -0.137002f;	val_dir[1274*3 + 2] = 0.433840f;
+ 	val_dir[1275*3 + 0] = 0.897574f;	val_dir[1275*3 + 1] = -0.112197f;	val_dir[1275*3 + 2] = 0.426348f;
+ 	val_dir[1276*3 + 0] = 0.903777f;	val_dir[1276*3 + 1] = -0.088173f;	val_dir[1276*3 + 2] = 0.418823f;
+ 	val_dir[1277*3 + 0] = 0.909185f;	val_dir[1277*3 + 1] = -0.064942f;	val_dir[1277*3 + 2] = 0.411298f;
+ 	val_dir[1278*3 + 0] = 0.913860f;	val_dir[1278*3 + 1] = -0.042505f;	val_dir[1278*3 + 2] = 0.403799f;
+ 	val_dir[1279*3 + 0] = 0.917863f;	val_dir[1279*3 + 1] = -0.020861f;	val_dir[1279*3 + 2] = 0.396350f;
+ 	val_dir[1280*3 + 0] = 0.921250f;	val_dir[1280*3 + 1] = 0.0f;	val_dir[1280*3 + 2] = 0.388972f;
+ 	val_dir[1281*3 + 0] = 0.93780f;	val_dir[1281*3 + 1] = 0.020387f;	val_dir[1281*3 + 2] = 0.346578f;
+ 	val_dir[1282*3 + 0] = 0.951877f;	val_dir[1282*3 + 1] = 0.040505f;	val_dir[1282*3 + 2] = 0.303791f;
+ 	val_dir[1283*3 + 0] = 0.963475f;	val_dir[1283*3 + 1] = 0.060217f;	val_dir[1283*3 + 2] = 0.260941f;
+ 	val_dir[1284*3 + 0] = 0.972636f;	val_dir[1284*3 + 1] = 0.079399f;	val_dir[1284*3 + 2] = 0.218347f;
+ 	val_dir[1285*3 + 0] = 0.979451f;	val_dir[1285*3 + 1] = 0.097945f;	val_dir[1285*3 + 2] = 0.176301f;
+ 	val_dir[1286*3 + 0] = 0.984050f;	val_dir[1286*3 + 1] = 0.115771f;	val_dir[1286*3 + 2] = 0.135066f;
+ 	val_dir[1287*3 + 0] = 0.986591f;	val_dir[1287*3 + 1] = 0.132810f;	val_dir[1287*3 + 2] = 0.094865f;
+ 	val_dir[1288*3 + 0] = 0.987254f;	val_dir[1288*3 + 1] = 0.149019f;	val_dir[1288*3 + 2] = 0.055882f;
+ 	val_dir[1289*3 + 0] = 0.986229f;	val_dir[1289*3 + 1] = 0.164372f;	val_dir[1289*3 + 2] = 0.018264f;
+ 	val_dir[1290*3 + 0] = -0.182089f;	val_dir[1290*3 + 1] = -0.983282f;	val_dir[1290*3 + 2] = 0.0f;
+ 	val_dir[1291*3 + 0] = -0.167299f;	val_dir[1291*3 + 1] = -0.985205f;	val_dir[1291*3 + 2] = 0.037178f;
+ 	val_dir[1292*3 + 0] = -0.151620f;	val_dir[1292*3 + 1] = -0.985527f;	val_dir[1292*3 + 2] = 0.075810f;
+ 	val_dir[1293*3 + 0] = -0.135066f;	val_dir[1293*3 + 1] = -0.984050f;	val_dir[1293*3 + 2] = 0.115771f;
+ 	val_dir[1294*3 + 0] = -0.117670f;	val_dir[1294*3 + 1] = -0.980581f;	val_dir[1294*3 + 2] = 0.156893f;
+ 	val_dir[1295*3 + 0] = -0.099484f;	val_dir[1295*3 + 1] = -0.974943f;	val_dir[1295*3 + 2] = 0.198968f;
+ 	val_dir[1296*3 + 0] = -0.080582f;	val_dir[1296*3 + 1] = -0.966988f;	val_dir[1296*3 + 2] = 0.241747f;
+ 	val_dir[1297*3 + 0] = -0.061059f;	val_dir[1297*3 + 1] = -0.956597f;	val_dir[1297*3 + 2] = 0.284944f;
+ 	val_dir[1298*3 + 0] = -0.041030f;	val_dir[1298*3 + 1] = -0.943701f;	val_dir[1298*3 + 2] = 0.328244f;
+ 	val_dir[1299*3 + 0] = -0.020628f;	val_dir[1299*3 + 1] = -0.928279f;	val_dir[1299*3 + 2] = 0.371312f;
+ 	val_dir[1300*3 + 0] = 0.0f;	val_dir[1300*3 + 1] = -0.910366f;	val_dir[1300*3 + 2] = 0.413803f;
+ 	val_dir[1301*3 + 0] = 0.021082f;	val_dir[1301*3 + 1] = -0.906520f;	val_dir[1301*3 + 2] = 0.421637f;
+ 	val_dir[1302*3 + 0] = 0.042954f;	val_dir[1302*3 + 1] = -0.902027f;	val_dir[1302*3 + 2] = 0.429537f;
+ 	val_dir[1303*3 + 0] = 0.065622f;	val_dir[1303*3 + 1] = -0.896831f;	val_dir[1303*3 + 2] = 0.437479f;
+ 	val_dir[1304*3 + 0] = 0.089087f;	val_dir[1304*3 + 1] = -0.890871f;	val_dir[1304*3 + 2] = 0.445435f;
+ 	val_dir[1305*3 + 0] = 0.113344f;	val_dir[1305*3 + 1] = -0.884083f;	val_dir[1305*3 + 2] = 0.453376f;
+ 	val_dir[1306*3 + 0] = 0.138380f;	val_dir[1306*3 + 1] = -0.876405f;	val_dir[1306*3 + 2] = 0.461266f;
+ 	val_dir[1307*3 + 0] = 0.164173f;	val_dir[1307*3 + 1] = -0.867770f;	val_dir[1307*3 + 2] = 0.469065f;
+ 	val_dir[1308*3 + 0] = 0.190693f;	val_dir[1308*3 + 1] = -0.858116f;	val_dir[1308*3 + 2] = 0.476731f;
+ 	val_dir[1309*3 + 0] = 0.217898f;	val_dir[1309*3 + 1] = -0.847381f;	val_dir[1309*3 + 2] = 0.484217f;
+ 	val_dir[1310*3 + 0] = 0.245737f;	val_dir[1310*3 + 1] = -0.835504f;	val_dir[1310*3 + 2] = 0.491473f;
+ 	val_dir[1311*3 + 0] = 0.274145f;	val_dir[1311*3 + 1] = -0.822434f;	val_dir[1311*3 + 2] = 0.498445f;
+ 	val_dir[1312*3 + 0] = 0.303046f;	val_dir[1312*3 + 1] = -0.808122f;	val_dir[1312*3 + 2] = 0.505076f;
+ 	val_dir[1313*3 + 0] = 0.332352f;	val_dir[1313*3 + 1] = -0.792530f;	val_dir[1313*3 + 2] = 0.511310f;
+ 	val_dir[1314*3 + 0] = 0.361961f;	val_dir[1314*3 + 1] = -0.775632f;	val_dir[1314*3 + 2] = 0.517088f;
+ 	val_dir[1315*3 + 0] = 0.391764f;	val_dir[1315*3 + 1] = -0.757410f;	val_dir[1315*3 + 2] = 0.522352f;
+ 	val_dir[1316*3 + 0] = 0.421637f;	val_dir[1316*3 + 1] = -0.737865f;	val_dir[1316*3 + 2] = 0.527046f;
+ 	val_dir[1317*3 + 0] = 0.451451f;	val_dir[1317*3 + 1] = -0.717011f;	val_dir[1317*3 + 2] = 0.531119f;
+ 	val_dir[1318*3 + 0] = 0.481070f;	val_dir[1318*3 + 1] = -0.694879f;	val_dir[1318*3 + 2] = 0.534522f;
+ 	val_dir[1319*3 + 0] = 0.510355f;	val_dir[1319*3 + 1] = -0.671519f;	val_dir[1319*3 + 2] = 0.537215f;
+ 	val_dir[1320*3 + 0] = 0.539164f;	val_dir[1320*3 + 1] = -0.646997f;	val_dir[1320*3 + 2] = 0.539164f;
+ 	val_dir[1321*3 + 0] = 0.567360f;	val_dir[1321*3 + 1] = -0.621395f;	val_dir[1321*3 + 2] = 0.540343f;
+ 	val_dir[1322*3 + 0] = 0.594812f;	val_dir[1322*3 + 1] = -0.594812f;	val_dir[1322*3 + 2] = 0.540738f;
+ 	val_dir[1323*3 + 0] = 0.621395f;	val_dir[1323*3 + 1] = -0.567360f;	val_dir[1323*3 + 2] = 0.540343f;
+ 	val_dir[1324*3 + 0] = 0.646997f;	val_dir[1324*3 + 1] = -0.539164f;	val_dir[1324*3 + 2] = 0.539164f;
+ 	val_dir[1325*3 + 0] = 0.671519f;	val_dir[1325*3 + 1] = -0.510355f;	val_dir[1325*3 + 2] = 0.537215f;
+ 	val_dir[1326*3 + 0] = 0.694879f;	val_dir[1326*3 + 1] = -0.481070f;	val_dir[1326*3 + 2] = 0.534522f;
+ 	val_dir[1327*3 + 0] = 0.717011f;	val_dir[1327*3 + 1] = -0.451451f;	val_dir[1327*3 + 2] = 0.531119f;
+ 	val_dir[1328*3 + 0] = 0.737865f;	val_dir[1328*3 + 1] = -0.421637f;	val_dir[1328*3 + 2] = 0.527046f;
+ 	val_dir[1329*3 + 0] = 0.757410f;	val_dir[1329*3 + 1] = -0.391764f;	val_dir[1329*3 + 2] = 0.522352f;
+ 	val_dir[1330*3 + 0] = 0.775632f;	val_dir[1330*3 + 1] = -0.361961f;	val_dir[1330*3 + 2] = 0.517088f;
+ 	val_dir[1331*3 + 0] = 0.792530f;	val_dir[1331*3 + 1] = -0.332352f;	val_dir[1331*3 + 2] = 0.511310f;
+ 	val_dir[1332*3 + 0] = 0.808122f;	val_dir[1332*3 + 1] = -0.303046f;	val_dir[1332*3 + 2] = 0.505076f;
+ 	val_dir[1333*3 + 0] = 0.822434f;	val_dir[1333*3 + 1] = -0.274145f;	val_dir[1333*3 + 2] = 0.498445f;
+ 	val_dir[1334*3 + 0] = 0.835504f;	val_dir[1334*3 + 1] = -0.245737f;	val_dir[1334*3 + 2] = 0.491473f;
+ 	val_dir[1335*3 + 0] = 0.847381f;	val_dir[1335*3 + 1] = -0.217898f;	val_dir[1335*3 + 2] = 0.484217f;
+ 	val_dir[1336*3 + 0] = 0.858116f;	val_dir[1336*3 + 1] = -0.190693f;	val_dir[1336*3 + 2] = 0.476731f;
+ 	val_dir[1337*3 + 0] = 0.867770f;	val_dir[1337*3 + 1] = -0.164173f;	val_dir[1337*3 + 2] = 0.469065f;
+ 	val_dir[1338*3 + 0] = 0.876405f;	val_dir[1338*3 + 1] = -0.138380f;	val_dir[1338*3 + 2] = 0.461266f;
+ 	val_dir[1339*3 + 0] = 0.884083f;	val_dir[1339*3 + 1] = -0.113344f;	val_dir[1339*3 + 2] = 0.453376f;
+ 	val_dir[1340*3 + 0] = 0.890871f;	val_dir[1340*3 + 1] = -0.089087f;	val_dir[1340*3 + 2] = 0.445435f;
+ 	val_dir[1341*3 + 0] = 0.896831f;	val_dir[1341*3 + 1] = -0.065622f;	val_dir[1341*3 + 2] = 0.437479f;
+ 	val_dir[1342*3 + 0] = 0.902027f;	val_dir[1342*3 + 1] = -0.042954f;	val_dir[1342*3 + 2] = 0.429537f;
+ 	val_dir[1343*3 + 0] = 0.906520f;	val_dir[1343*3 + 1] = -0.021082f;	val_dir[1343*3 + 2] = 0.421637f;
+ 	val_dir[1344*3 + 0] = 0.910366f;	val_dir[1344*3 + 1] = 0.0f;	val_dir[1344*3 + 2] = 0.413803f;
+ 	val_dir[1345*3 + 0] = 0.928279f;	val_dir[1345*3 + 1] = 0.020628f;	val_dir[1345*3 + 2] = 0.371312f;
+ 	val_dir[1346*3 + 0] = 0.943701f;	val_dir[1346*3 + 1] = 0.041030f;	val_dir[1346*3 + 2] = 0.328244f;
+ 	val_dir[1347*3 + 0] = 0.956597f;	val_dir[1347*3 + 1] = 0.061059f;	val_dir[1347*3 + 2] = 0.284944f;
+ 	val_dir[1348*3 + 0] = 0.966988f;	val_dir[1348*3 + 1] = 0.080582f;	val_dir[1348*3 + 2] = 0.241747f;
+ 	val_dir[1349*3 + 0] = 0.974943f;	val_dir[1349*3 + 1] = 0.099484f;	val_dir[1349*3 + 2] = 0.198968f;
+ 	val_dir[1350*3 + 0] = 0.980581f;	val_dir[1350*3 + 1] = 0.117670f;	val_dir[1350*3 + 2] = 0.156893f;
+ 	val_dir[1351*3 + 0] = 0.984050f;	val_dir[1351*3 + 1] = 0.135066f;	val_dir[1351*3 + 2] = 0.115771f;
+ 	val_dir[1352*3 + 0] = 0.985527f;	val_dir[1352*3 + 1] = 0.151620f;	val_dir[1352*3 + 2] = 0.075810f;
+ 	val_dir[1353*3 + 0] = 0.985205f;	val_dir[1353*3 + 1] = 0.167299f;	val_dir[1353*3 + 2] = 0.037178f;
+ 	val_dir[1354*3 + 0] = 0.983282f;	val_dir[1354*3 + 1] = 0.182089f;	val_dir[1354*3 + 2] = 0.0f;
+ 	val_dir[1355*3 + 0] = -0.185376f;	val_dir[1355*3 + 1] = -0.982493f;	val_dir[1355*3 + 2] = 0.018538f;
+ 	val_dir[1356*3 + 0] = -0.170267f;	val_dir[1356*3 + 1] = -0.983762f;	val_dir[1356*3 + 2] = 0.056756f;
+ 	val_dir[1357*3 + 0] = -0.154246f;	val_dir[1357*3 + 1] = -0.983318f;	val_dir[1357*3 + 2] = 0.096404f;
+ 	val_dir[1358*3 + 0] = -0.137334f;	val_dir[1358*3 + 1] = -0.980958f;	val_dir[1358*3 + 2] = 0.137334f;
+ 	val_dir[1359*3 + 0] = -0.119570f;	val_dir[1359*3 + 1] = -0.976491f;	val_dir[1359*3 + 2] = 0.179355f;
+ 	val_dir[1360*3 + 0] = -0.101015f;	val_dir[1360*3 + 1] = -0.969746f;	val_dir[1360*3 + 2] = 0.222234f;
+ 	val_dir[1361*3 + 0] = -0.081752f;	val_dir[1361*3 + 1] = -0.960585f;	val_dir[1361*3 + 2] = 0.265694f;
+ 	val_dir[1362*3 + 0] = -0.061885f;	val_dir[1362*3 + 1] = -0.948908f;	val_dir[1362*3 + 2] = 0.309426f;
+ 	val_dir[1363*3 + 0] = -0.041541f;	val_dir[1363*3 + 1] = -0.934665f;	val_dir[1363*3 + 2] = 0.353096f;
+ 	val_dir[1364*3 + 0] = -0.020861f;	val_dir[1364*3 + 1] = -0.917863f;	val_dir[1364*3 + 2] = 0.396350f;
+ 	val_dir[1365*3 + 0] = 0.0f;	val_dir[1365*3 + 1] = -0.898567f;	val_dir[1365*3 + 2] = 0.438835f;
+ 	val_dir[1366*3 + 0] = 0.021291f;	val_dir[1366*3 + 1] = -0.894224f;	val_dir[1366*3 + 2] = 0.447112f;
+ 	val_dir[1367*3 + 0] = 0.043376f;	val_dir[1367*3 + 1] = -0.889206f;	val_dir[1367*3 + 2] = 0.455447f;
+ 	val_dir[1368*3 + 0] = 0.066259f;	val_dir[1368*3 + 1] = -0.883452f;	val_dir[1368*3 + 2] = 0.463812f;
+ 	val_dir[1369*3 + 0] = 0.089939f;	val_dir[1369*3 + 1] = -0.876903f;	val_dir[1369*3 + 2] = 0.472178f;
+ 	val_dir[1370*3 + 0] = 0.114407f;	val_dir[1370*3 + 1] = -0.869495f;	val_dir[1370*3 + 2] = 0.480510f;
+ 	val_dir[1371*3 + 0] = 0.139648f;	val_dir[1371*3 + 1] = -0.861164f;	val_dir[1371*3 + 2] = 0.488769f;
+ 	val_dir[1372*3 + 0] = 0.165637f;	val_dir[1372*3 + 1] = -0.851847f;	val_dir[1372*3 + 2] = 0.496911f;
+ 	val_dir[1373*3 + 0] = 0.192339f;	val_dir[1373*3 + 1] = -0.841482f;	val_dir[1373*3 + 2] = 0.504889f;
+ 	val_dir[1374*3 + 0] = 0.219708f;	val_dir[1374*3 + 1] = -0.830009f;	val_dir[1374*3 + 2] = 0.512653f;
+ 	val_dir[1375*3 + 0] = 0.247689f;	val_dir[1375*3 + 1] = -0.817373f;	val_dir[1375*3 + 2] = 0.520146f;
+ 	val_dir[1376*3 + 0] = 0.276211f;	val_dir[1376*3 + 1] = -0.803523f;	val_dir[1376*3 + 2] = 0.527312f;
+ 	val_dir[1377*3 + 0] = 0.305194f;	val_dir[1377*3 + 1] = -0.788419f;	val_dir[1377*3 + 2] = 0.534090f;
+ 	val_dir[1378*3 + 0] = 0.334545f;	val_dir[1378*3 + 1] = -0.772027f;	val_dir[1378*3 + 2] = 0.540419f;
+ 	val_dir[1379*3 + 0] = 0.364159f;	val_dir[1379*3 + 1] = -0.754329f;	val_dir[1379*3 + 2] = 0.546238f;
+ 	val_dir[1380*3 + 0] = 0.393919f;	val_dir[1380*3 + 1] = -0.735316f;	val_dir[1380*3 + 2] = 0.551487f;
+ 	val_dir[1381*3 + 0] = 0.423702f;	val_dir[1381*3 + 1] = -0.714997f;	val_dir[1381*3 + 2] = 0.556108f;
+ 	val_dir[1382*3 + 0] = 0.453374f;	val_dir[1382*3 + 1] = -0.693395f;	val_dir[1382*3 + 2] = 0.560050f;
+ 	val_dir[1383*3 + 0] = 0.482798f;	val_dir[1383*3 + 1] = -0.670552f;	val_dir[1383*3 + 2] = 0.563264f;
+ 	val_dir[1384*3 + 0] = 0.511834f;	val_dir[1384*3 + 1] = -0.646527f;	val_dir[1384*3 + 2] = 0.565711f;
+ 	val_dir[1385*3 + 0] = 0.540343f;	val_dir[1385*3 + 1] = -0.621395f;	val_dir[1385*3 + 2] = 0.567360f;
+ 	val_dir[1386*3 + 0] = 0.568190f;	val_dir[1386*3 + 1] = -0.595247f;	val_dir[1386*3 + 2] = 0.568190f;
+ 	val_dir[1387*3 + 0] = 0.595247f;	val_dir[1387*3 + 1] = -0.568190f;	val_dir[1387*3 + 2] = 0.568190f;
+ 	val_dir[1388*3 + 0] = 0.621395f;	val_dir[1388*3 + 1] = -0.540343f;	val_dir[1388*3 + 2] = 0.567360f;
+ 	val_dir[1389*3 + 0] = 0.646527f;	val_dir[1389*3 + 1] = -0.511834f;	val_dir[1389*3 + 2] = 0.565711f;
+ 	val_dir[1390*3 + 0] = 0.670552f;	val_dir[1390*3 + 1] = -0.482798f;	val_dir[1390*3 + 2] = 0.563264f;
+ 	val_dir[1391*3 + 0] = 0.693395f;	val_dir[1391*3 + 1] = -0.453374f;	val_dir[1391*3 + 2] = 0.560050f;
+ 	val_dir[1392*3 + 0] = 0.714997f;	val_dir[1392*3 + 1] = -0.423702f;	val_dir[1392*3 + 2] = 0.556108f;
+ 	val_dir[1393*3 + 0] = 0.735316f;	val_dir[1393*3 + 1] = -0.393919f;	val_dir[1393*3 + 2] = 0.551487f;
+ 	val_dir[1394*3 + 0] = 0.754329f;	val_dir[1394*3 + 1] = -0.364159f;	val_dir[1394*3 + 2] = 0.546238f;
+ 	val_dir[1395*3 + 0] = 0.772027f;	val_dir[1395*3 + 1] = -0.334545f;	val_dir[1395*3 + 2] = 0.540419f;
+ 	val_dir[1396*3 + 0] = 0.788419f;	val_dir[1396*3 + 1] = -0.305194f;	val_dir[1396*3 + 2] = 0.534090f;
+ 	val_dir[1397*3 + 0] = 0.803523f;	val_dir[1397*3 + 1] = -0.276211f;	val_dir[1397*3 + 2] = 0.527312f;
+ 	val_dir[1398*3 + 0] = 0.817373f;	val_dir[1398*3 + 1] = -0.247689f;	val_dir[1398*3 + 2] = 0.520146f;
+ 	val_dir[1399*3 + 0] = 0.830009f;	val_dir[1399*3 + 1] = -0.219708f;	val_dir[1399*3 + 2] = 0.512653f;
+ 	val_dir[1400*3 + 0] = 0.841482f;	val_dir[1400*3 + 1] = -0.192339f;	val_dir[1400*3 + 2] = 0.504889f;
+ 	val_dir[1401*3 + 0] = 0.851847f;	val_dir[1401*3 + 1] = -0.165637f;	val_dir[1401*3 + 2] = 0.496911f;
+ 	val_dir[1402*3 + 0] = 0.861164f;	val_dir[1402*3 + 1] = -0.139648f;	val_dir[1402*3 + 2] = 0.488769f;
+ 	val_dir[1403*3 + 0] = 0.869495f;	val_dir[1403*3 + 1] = -0.114407f;	val_dir[1403*3 + 2] = 0.480510f;
+ 	val_dir[1404*3 + 0] = 0.876903f;	val_dir[1404*3 + 1] = -0.089939f;	val_dir[1404*3 + 2] = 0.472178f;
+ 	val_dir[1405*3 + 0] = 0.883452f;	val_dir[1405*3 + 1] = -0.066259f;	val_dir[1405*3 + 2] = 0.463812f;
+ 	val_dir[1406*3 + 0] = 0.889206f;	val_dir[1406*3 + 1] = -0.043376f;	val_dir[1406*3 + 2] = 0.455447f;
+ 	val_dir[1407*3 + 0] = 0.894224f;	val_dir[1407*3 + 1] = -0.021291f;	val_dir[1407*3 + 2] = 0.447112f;
+ 	val_dir[1408*3 + 0] = 0.898567f;	val_dir[1408*3 + 1] = 0.0f;	val_dir[1408*3 + 2] = 0.438835f;
+ 	val_dir[1409*3 + 0] = 0.917863f;	val_dir[1409*3 + 1] = 0.020861f;	val_dir[1409*3 + 2] = 0.396350f;
+ 	val_dir[1410*3 + 0] = 0.934665f;	val_dir[1410*3 + 1] = 0.041541f;	val_dir[1410*3 + 2] = 0.353096f;
+ 	val_dir[1411*3 + 0] = 0.948908f;	val_dir[1411*3 + 1] = 0.061885f;	val_dir[1411*3 + 2] = 0.309426f;
+ 	val_dir[1412*3 + 0] = 0.960585f;	val_dir[1412*3 + 1] = 0.081752f;	val_dir[1412*3 + 2] = 0.265694f;
+ 	val_dir[1413*3 + 0] = 0.969746f;	val_dir[1413*3 + 1] = 0.101015f;	val_dir[1413*3 + 2] = 0.222234f;
+ 	val_dir[1414*3 + 0] = 0.976491f;	val_dir[1414*3 + 1] = 0.119570f;	val_dir[1414*3 + 2] = 0.179355f;
+ 	val_dir[1415*3 + 0] = 0.980958f;	val_dir[1415*3 + 1] = 0.137334f;	val_dir[1415*3 + 2] = 0.137334f;
+ 	val_dir[1416*3 + 0] = 0.983318f;	val_dir[1416*3 + 1] = 0.154246f;	val_dir[1416*3 + 2] = 0.096404f;
+ 	val_dir[1417*3 + 0] = 0.983762f;	val_dir[1417*3 + 1] = 0.170267f;	val_dir[1417*3 + 2] = 0.056756f;
+ 	val_dir[1418*3 + 0] = 0.982493f;	val_dir[1418*3 + 1] = 0.185376f;	val_dir[1418*3 + 2] = 0.018538f;
+ 	val_dir[1419*3 + 0] = -0.203216f;	val_dir[1419*3 + 1] = -0.979134f;	val_dir[1419*3 + 2] = 0.0f;
+ 	val_dir[1420*3 + 0] = -0.188713f;	val_dir[1420*3 + 1] = -0.981307f;	val_dir[1420*3 + 2] = 0.037743f;
+ 	val_dir[1421*3 + 0] = -0.173269f;	val_dir[1421*3 + 1] = -0.981859f;	val_dir[1421*3 + 2] = 0.077009f;
+ 	val_dir[1422*3 + 0] = -0.156893f;	val_dir[1422*3 + 1] = -0.980581f;	val_dir[1422*3 + 2] = 0.117670f;
+ 	val_dir[1423*3 + 0] = -0.139610f;	val_dir[1423*3 + 1] = -0.977267f;	val_dir[1423*3 + 2] = 0.159554f;
+ 	val_dir[1424*3 + 0] = -0.121466f;	val_dir[1424*3 + 1] = -0.971732f;	val_dir[1424*3 + 2] = 0.202444f;
+ 	val_dir[1425*3 + 0] = -0.102533f;	val_dir[1425*3 + 1] = -0.963811f;	val_dir[1425*3 + 2] = 0.246079f;
+ 	val_dir[1426*3 + 0] = -0.082903f;	val_dir[1426*3 + 1] = -0.953381f;	val_dir[1426*3 + 2] = 0.290159f;
+ 	val_dir[1427*3 + 0] = -0.062691f;	val_dir[1427*3 + 1] = -0.940361f;	val_dir[1427*3 + 2] = 0.334351f;
+ 	val_dir[1428*3 + 0] = -0.042033f;	val_dir[1428*3 + 1] = -0.924729f;	val_dir[1428*3 + 2] = 0.378298f;
+ 	val_dir[1429*3 + 0] = -0.021082f;	val_dir[1429*3 + 1] = -0.906520f;	val_dir[1429*3 + 2] = 0.421637f;
+ 	val_dir[1430*3 + 0] = 0.0f;	val_dir[1430*3 + 1] = -0.885832f;	val_dir[1430*3 + 2] = 0.464007f;
+ 	val_dir[1431*3 + 0] = 0.021487f;	val_dir[1431*3 + 1] = -0.880957f;	val_dir[1431*3 + 2] = 0.472709f;
+ 	val_dir[1432*3 + 0] = 0.043769f;	val_dir[1432*3 + 1] = -0.875376f;	val_dir[1432*3 + 2] = 0.481457f;
+ 	val_dir[1433*3 + 0] = 0.066848f;	val_dir[1433*3 + 1] = -0.869030f;	val_dir[1433*3 + 2] = 0.490222f;
+ 	val_dir[1434*3 + 0] = 0.090722f;	val_dir[1434*3 + 1] = -0.861857f;	val_dir[1434*3 + 2] = 0.498970f;
+ 	val_dir[1435*3 + 0] = 0.115378f;	val_dir[1435*3 + 1] = -0.853796f;	val_dir[1435*3 + 2] = 0.507662f;
+ 	val_dir[1436*3 + 0] = 0.140797f;	val_dir[1436*3 + 1] = -0.844782f;	val_dir[1436*3 + 2] = 0.516256f;
+ 	val_dir[1437*3 + 0] = 0.166951f;	val_dir[1437*3 + 1] = -0.834754f;	val_dir[1437*3 + 2] = 0.524703f;
+ 	val_dir[1438*3 + 0] = 0.193801f;	val_dir[1438*3 + 1] = -0.823653f;	val_dir[1438*3 + 2] = 0.532952f;
+ 	val_dir[1439*3 + 0] = 0.221297f;	val_dir[1439*3 + 1] = -0.811421f;	val_dir[1439*3 + 2] = 0.540947f;
+ 	val_dir[1440*3 + 0] = 0.249377f;	val_dir[1440*3 + 1] = -0.798007f;	val_dir[1440*3 + 2] = 0.548630f;
+ 	val_dir[1441*3 + 0] = 0.277969f;	val_dir[1441*3 + 1] = -0.783368f;	val_dir[1441*3 + 2] = 0.555939f;
+ 	val_dir[1442*3 + 0] = 0.306987f;	val_dir[1442*3 + 1] = -0.767467f;	val_dir[1442*3 + 2] = 0.562809f;
+ 	val_dir[1443*3 + 0] = 0.336332f;	val_dir[1443*3 + 1] = -0.750279f;	val_dir[1443*3 + 2] = 0.569177f;
+ 	val_dir[1444*3 + 0] = 0.365896f;	val_dir[1444*3 + 1] = -0.731792f;	val_dir[1444*3 + 2] = 0.574979f;
+ 	val_dir[1445*3 + 0] = 0.395559f;	val_dir[1445*3 + 1] = -0.712007f;	val_dir[1445*3 + 2] = 0.580154f;
+ 	val_dir[1446*3 + 0] = 0.425195f;	val_dir[1446*3 + 1] = -0.690942f;	val_dir[1446*3 + 2] = 0.584643f;
+ 	val_dir[1447*3 + 0] = 0.454669f;	val_dir[1447*3 + 1] = -0.668631f;	val_dir[1447*3 + 2] = 0.588395f;
+ 	val_dir[1448*3 + 0] = 0.483843f;	val_dir[1448*3 + 1] = -0.645124f;	val_dir[1448*3 + 2] = 0.591364f;
+ 	val_dir[1449*3 + 0] = 0.512578f;	val_dir[1449*3 + 1] = -0.620490f;	val_dir[1449*3 + 2] = 0.593512f;
+ 	val_dir[1450*3 + 0] = 0.540738f;	val_dir[1450*3 + 1] = -0.594812f;	val_dir[1450*3 + 2] = 0.594812f;
+ 	val_dir[1451*3 + 0] = 0.568190f;	val_dir[1451*3 + 1] = -0.568190f;	val_dir[1451*3 + 2] = 0.595247f;
+ 	val_dir[1452*3 + 0] = 0.594812f;	val_dir[1452*3 + 1] = -0.540738f;	val_dir[1452*3 + 2] = 0.594812f;
+ 	val_dir[1453*3 + 0] = 0.620490f;	val_dir[1453*3 + 1] = -0.512578f;	val_dir[1453*3 + 2] = 0.593512f;
+ 	val_dir[1454*3 + 0] = 0.645124f;	val_dir[1454*3 + 1] = -0.483843f;	val_dir[1454*3 + 2] = 0.591364f;
+ 	val_dir[1455*3 + 0] = 0.668631f;	val_dir[1455*3 + 1] = -0.454669f;	val_dir[1455*3 + 2] = 0.588395f;
+ 	val_dir[1456*3 + 0] = 0.690942f;	val_dir[1456*3 + 1] = -0.425195f;	val_dir[1456*3 + 2] = 0.584643f;
+ 	val_dir[1457*3 + 0] = 0.712007f;	val_dir[1457*3 + 1] = -0.395559f;	val_dir[1457*3 + 2] = 0.580154f;
+ 	val_dir[1458*3 + 0] = 0.731792f;	val_dir[1458*3 + 1] = -0.365896f;	val_dir[1458*3 + 2] = 0.574979f;
+ 	val_dir[1459*3 + 0] = 0.750279f;	val_dir[1459*3 + 1] = -0.336332f;	val_dir[1459*3 + 2] = 0.569177f;
+ 	val_dir[1460*3 + 0] = 0.767467f;	val_dir[1460*3 + 1] = -0.306987f;	val_dir[1460*3 + 2] = 0.562809f;
+ 	val_dir[1461*3 + 0] = 0.783368f;	val_dir[1461*3 + 1] = -0.277969f;	val_dir[1461*3 + 2] = 0.555939f;
+ 	val_dir[1462*3 + 0] = 0.798007f;	val_dir[1462*3 + 1] = -0.249377f;	val_dir[1462*3 + 2] = 0.548630f;
+ 	val_dir[1463*3 + 0] = 0.811421f;	val_dir[1463*3 + 1] = -0.221297f;	val_dir[1463*3 + 2] = 0.540947f;
+ 	val_dir[1464*3 + 0] = 0.823653f;	val_dir[1464*3 + 1] = -0.193801f;	val_dir[1464*3 + 2] = 0.532952f;
+ 	val_dir[1465*3 + 0] = 0.834754f;	val_dir[1465*3 + 1] = -0.166951f;	val_dir[1465*3 + 2] = 0.524703f;
+ 	val_dir[1466*3 + 0] = 0.844782f;	val_dir[1466*3 + 1] = -0.140797f;	val_dir[1466*3 + 2] = 0.516256f;
+ 	val_dir[1467*3 + 0] = 0.853796f;	val_dir[1467*3 + 1] = -0.115378f;	val_dir[1467*3 + 2] = 0.507662f;
+ 	val_dir[1468*3 + 0] = 0.861857f;	val_dir[1468*3 + 1] = -0.090722f;	val_dir[1468*3 + 2] = 0.498970f;
+ 	val_dir[1469*3 + 0] = 0.869030f;	val_dir[1469*3 + 1] = -0.066848f;	val_dir[1469*3 + 2] = 0.490222f;
+ 	val_dir[1470*3 + 0] = 0.875376f;	val_dir[1470*3 + 1] = -0.043769f;	val_dir[1470*3 + 2] = 0.481457f;
+ 	val_dir[1471*3 + 0] = 0.880957f;	val_dir[1471*3 + 1] = -0.021487f;	val_dir[1471*3 + 2] = 0.472709f;
+ 	val_dir[1472*3 + 0] = 0.885832f;	val_dir[1472*3 + 1] = 0.0f;	val_dir[1472*3 + 2] = 0.464007f;
+ 	val_dir[1473*3 + 0] = 0.906520f;	val_dir[1473*3 + 1] = 0.021082f;	val_dir[1473*3 + 2] = 0.421637f;
+ 	val_dir[1474*3 + 0] = 0.924729f;	val_dir[1474*3 + 1] = 0.042033f;	val_dir[1474*3 + 2] = 0.378298f;
+ 	val_dir[1475*3 + 0] = 0.940361f;	val_dir[1475*3 + 1] = 0.062691f;	val_dir[1475*3 + 2] = 0.334351f;
+ 	val_dir[1476*3 + 0] = 0.953381f;	val_dir[1476*3 + 1] = 0.082903f;	val_dir[1476*3 + 2] = 0.290159f;
+ 	val_dir[1477*3 + 0] = 0.963811f;	val_dir[1477*3 + 1] = 0.102533f;	val_dir[1477*3 + 2] = 0.246079f;
+ 	val_dir[1478*3 + 0] = 0.971732f;	val_dir[1478*3 + 1] = 0.121466f;	val_dir[1478*3 + 2] = 0.202444f;
+ 	val_dir[1479*3 + 0] = 0.977267f;	val_dir[1479*3 + 1] = 0.139610f;	val_dir[1479*3 + 2] = 0.159554f;
+ 	val_dir[1480*3 + 0] = 0.980581f;	val_dir[1480*3 + 1] = 0.156893f;	val_dir[1480*3 + 2] = 0.117670f;
+ 	val_dir[1481*3 + 0] = 0.981859f;	val_dir[1481*3 + 1] = 0.173269f;	val_dir[1481*3 + 2] = 0.077009f;
+ 	val_dir[1482*3 + 0] = 0.981307f;	val_dir[1482*3 + 1] = 0.188713f;	val_dir[1482*3 + 2] = 0.037743f;
+ 	val_dir[1483*3 + 0] = 0.979134f;	val_dir[1483*3 + 1] = 0.203216f;	val_dir[1483*3 + 2] = 0.0f;
+ 	val_dir[1484*3 + 0] = -0.206922f;	val_dir[1484*3 + 1] = -0.978177f;	val_dir[1484*3 + 2] = 0.018811f;
+ 	val_dir[1485*3 + 0] = -0.192095f;	val_dir[1485*3 + 1] = -0.979683f;	val_dir[1485*3 + 2] = 0.057628f;
+ 	val_dir[1486*3 + 0] = -0.176301f;	val_dir[1486*3 + 1] = -0.979451f;	val_dir[1486*3 + 2] = 0.097945f;
+ 	val_dir[1487*3 + 0] = -0.159554f;	val_dir[1487*3 + 1] = -0.977267f;	val_dir[1487*3 + 2] = 0.139610f;
+ 	val_dir[1488*3 + 0] = -0.141885f;	val_dir[1488*3 + 1] = -0.972929f;	val_dir[1488*3 + 2] = 0.182424f;
+ 	val_dir[1489*3 + 0] = -0.123351f;	val_dir[1489*3 + 1] = -0.966252f;	val_dir[1489*3 + 2] = 0.226144f;
+ 	val_dir[1490*3 + 0] = -0.104031f;	val_dir[1490*3 + 1] = -0.957088f;	val_dir[1490*3 + 2] = 0.270481f;
+ 	val_dir[1491*3 + 0] = -0.084029f;	val_dir[1491*3 + 1] = -0.945328f;	val_dir[1491*3 + 2] = 0.315109f;
+ 	val_dir[1492*3 + 0] = -0.063472f;	val_dir[1492*3 + 1] = -0.930917f;	val_dir[1492*3 + 2] = 0.359673f;
+ 	val_dir[1493*3 + 0] = -0.042505f;	val_dir[1493*3 + 1] = -0.913860f;	val_dir[1493*3 + 2] = 0.403799f;
+ 	val_dir[1494*3 + 0] = -0.021291f;	val_dir[1494*3 + 1] = -0.894224f;	val_dir[1494*3 + 2] = 0.447112f;
+ 	val_dir[1495*3 + 0] = 0.0f;	val_dir[1495*3 + 1] = -0.872143f;	val_dir[1495*3 + 2] = 0.489251f;
+ 	val_dir[1496*3 + 0] = 0.021668f;	val_dir[1496*3 + 1] = -0.866703f;	val_dir[1496*3 + 2] = 0.498354f;
+ 	val_dir[1497*3 + 0] = 0.044130f;	val_dir[1497*3 + 1] = -0.860527f;	val_dir[1497*3 + 2] = 0.507490f;
+ 	val_dir[1498*3 + 0] = 0.067386f;	val_dir[1498*3 + 1] = -0.853556f;	val_dir[1498*3 + 2] = 0.516626f;
+ 	val_dir[1499*3 + 0] = 0.091430f;	val_dir[1499*3 + 1] = -0.845728f;	val_dir[1499*3 + 2] = 0.525723f;
+ 	val_dir[1500*3 + 0] = 0.116248f;	val_dir[1500*3 + 1] = -0.836983f;	val_dir[1500*3 + 2] = 0.534739f;
+ 	val_dir[1501*3 + 0] = 0.141816f;	val_dir[1501*3 + 1] = -0.827259f;	val_dir[1501*3 + 2] = 0.543627f;
+ 	val_dir[1502*3 + 0] = 0.168102f;	val_dir[1502*3 + 1] = -0.816497f;	val_dir[1502*3 + 2] = 0.552336f;
+ 	val_dir[1503*3 + 0] = 0.195064f;	val_dir[1503*3 + 1] = -0.804639f;	val_dir[1503*3 + 2] = 0.560809f;
+ 	val_dir[1504*3 + 0] = 0.222647f;	val_dir[1504*3 + 1] = -0.791633f;	val_dir[1504*3 + 2] = 0.568986f;
+ 	val_dir[1505*3 + 0] = 0.250785f;	val_dir[1505*3 + 1] = -0.777433f;	val_dir[1505*3 + 2] = 0.576805f;
+ 	val_dir[1506*3 + 0] = 0.27940f;	val_dir[1506*3 + 1] = -0.762001f;	val_dir[1506*3 + 2] = 0.584201f;
+ 	val_dir[1507*3 + 0] = 0.308403f;	val_dir[1507*3 + 1] = -0.745307f;	val_dir[1507*3 + 2] = 0.591105f;
+ 	val_dir[1508*3 + 0] = 0.337691f;	val_dir[1508*3 + 1] = -0.727334f;	val_dir[1508*3 + 2] = 0.597453f;
+ 	val_dir[1509*3 + 0] = 0.367152f;	val_dir[1509*3 + 1] = -0.708079f;	val_dir[1509*3 + 2] = 0.603178f;
+ 	val_dir[1510*3 + 0] = 0.396664f;	val_dir[1510*3 + 1] = -0.687552f;	val_dir[1510*3 + 2] = 0.608219f;
+ 	val_dir[1511*3 + 0] = 0.426099f;	val_dir[1511*3 + 1] = -0.665780f;	val_dir[1511*3 + 2] = 0.612517f;
+ 	val_dir[1512*3 + 0] = 0.455321f;	val_dir[1512*3 + 1] = -0.642806f;	val_dir[1512*3 + 2] = 0.616022f;
+ 	val_dir[1513*3 + 0] = 0.484193f;	val_dir[1513*3 + 1] = -0.618691f;	val_dir[1513*3 + 2] = 0.618691f;
+ 	val_dir[1514*3 + 0] = 0.512578f;	val_dir[1514*3 + 1] = -0.593512f;	val_dir[1514*3 + 2] = 0.620490f;
+ 	val_dir[1515*3 + 0] = 0.540343f;	val_dir[1515*3 + 1] = -0.567360f;	val_dir[1515*3 + 2] = 0.621395f;
+ 	val_dir[1516*3 + 0] = 0.567360f;	val_dir[1516*3 + 1] = -0.540343f;	val_dir[1516*3 + 2] = 0.621395f;
+ 	val_dir[1517*3 + 0] = 0.593512f;	val_dir[1517*3 + 1] = -0.512578f;	val_dir[1517*3 + 2] = 0.620490f;
+ 	val_dir[1518*3 + 0] = 0.618691f;	val_dir[1518*3 + 1] = -0.484193f;	val_dir[1518*3 + 2] = 0.618691f;
+ 	val_dir[1519*3 + 0] = 0.642806f;	val_dir[1519*3 + 1] = -0.455321f;	val_dir[1519*3 + 2] = 0.616022f;
+ 	val_dir[1520*3 + 0] = 0.665780f;	val_dir[1520*3 + 1] = -0.426099f;	val_dir[1520*3 + 2] = 0.612517f;
+ 	val_dir[1521*3 + 0] = 0.687552f;	val_dir[1521*3 + 1] = -0.396664f;	val_dir[1521*3 + 2] = 0.608219f;
+ 	val_dir[1522*3 + 0] = 0.708079f;	val_dir[1522*3 + 1] = -0.367152f;	val_dir[1522*3 + 2] = 0.603178f;
+ 	val_dir[1523*3 + 0] = 0.727334f;	val_dir[1523*3 + 1] = -0.337691f;	val_dir[1523*3 + 2] = 0.597453f;
+ 	val_dir[1524*3 + 0] = 0.745307f;	val_dir[1524*3 + 1] = -0.308403f;	val_dir[1524*3 + 2] = 0.591105f;
+ 	val_dir[1525*3 + 0] = 0.762001f;	val_dir[1525*3 + 1] = -0.27940f;	val_dir[1525*3 + 2] = 0.584201f;
+ 	val_dir[1526*3 + 0] = 0.777433f;	val_dir[1526*3 + 1] = -0.250785f;	val_dir[1526*3 + 2] = 0.576805f;
+ 	val_dir[1527*3 + 0] = 0.791633f;	val_dir[1527*3 + 1] = -0.222647f;	val_dir[1527*3 + 2] = 0.568986f;
+ 	val_dir[1528*3 + 0] = 0.804639f;	val_dir[1528*3 + 1] = -0.195064f;	val_dir[1528*3 + 2] = 0.560809f;
+ 	val_dir[1529*3 + 0] = 0.816497f;	val_dir[1529*3 + 1] = -0.168102f;	val_dir[1529*3 + 2] = 0.552336f;
+ 	val_dir[1530*3 + 0] = 0.827259f;	val_dir[1530*3 + 1] = -0.141816f;	val_dir[1530*3 + 2] = 0.543627f;
+ 	val_dir[1531*3 + 0] = 0.836983f;	val_dir[1531*3 + 1] = -0.116248f;	val_dir[1531*3 + 2] = 0.534739f;
+ 	val_dir[1532*3 + 0] = 0.845728f;	val_dir[1532*3 + 1] = -0.091430f;	val_dir[1532*3 + 2] = 0.525723f;
+ 	val_dir[1533*3 + 0] = 0.853556f;	val_dir[1533*3 + 1] = -0.067386f;	val_dir[1533*3 + 2] = 0.516626f;
+ 	val_dir[1534*3 + 0] = 0.860527f;	val_dir[1534*3 + 1] = -0.044130f;	val_dir[1534*3 + 2] = 0.507490f;
+ 	val_dir[1535*3 + 0] = 0.866703f;	val_dir[1535*3 + 1] = -0.021668f;	val_dir[1535*3 + 2] = 0.498354f;
+ 	val_dir[1536*3 + 0] = 0.872143f;	val_dir[1536*3 + 1] = 0.0f;	val_dir[1536*3 + 2] = 0.489251f;
+ 	val_dir[1537*3 + 0] = 0.894224f;	val_dir[1537*3 + 1] = 0.021291f;	val_dir[1537*3 + 2] = 0.447112f;
+ 	val_dir[1538*3 + 0] = 0.913860f;	val_dir[1538*3 + 1] = 0.042505f;	val_dir[1538*3 + 2] = 0.403799f;
+ 	val_dir[1539*3 + 0] = 0.930917f;	val_dir[1539*3 + 1] = 0.063472f;	val_dir[1539*3 + 2] = 0.359673f;
+ 	val_dir[1540*3 + 0] = 0.945328f;	val_dir[1540*3 + 1] = 0.084029f;	val_dir[1540*3 + 2] = 0.315109f;
+ 	val_dir[1541*3 + 0] = 0.957088f;	val_dir[1541*3 + 1] = 0.104031f;	val_dir[1541*3 + 2] = 0.270481f;
+ 	val_dir[1542*3 + 0] = 0.966252f;	val_dir[1542*3 + 1] = 0.123351f;	val_dir[1542*3 + 2] = 0.226144f;
+ 	val_dir[1543*3 + 0] = 0.972929f;	val_dir[1543*3 + 1] = 0.141885f;	val_dir[1543*3 + 2] = 0.182424f;
+ 	val_dir[1544*3 + 0] = 0.977267f;	val_dir[1544*3 + 1] = 0.159554f;	val_dir[1544*3 + 2] = 0.139610f;
+ 	val_dir[1545*3 + 0] = 0.979451f;	val_dir[1545*3 + 1] = 0.176301f;	val_dir[1545*3 + 2] = 0.097945f;
+ 	val_dir[1546*3 + 0] = 0.979683f;	val_dir[1546*3 + 1] = 0.192095f;	val_dir[1546*3 + 2] = 0.057628f;
+ 	val_dir[1547*3 + 0] = 0.978177f;	val_dir[1547*3 + 1] = 0.206922f;	val_dir[1547*3 + 2] = 0.018811f;
+ 	val_dir[1548*3 + 0] = -0.224860f;	val_dir[1548*3 + 1] = -0.974391f;	val_dir[1548*3 + 2] = 0.0f;
+ 	val_dir[1549*3 + 0] = -0.210683f;	val_dir[1549*3 + 1] = -0.976804f;	val_dir[1549*3 + 2] = 0.038306f;
+ 	val_dir[1550*3 + 0] = -0.195515f;	val_dir[1550*3 + 1] = -0.977577f;	val_dir[1550*3 + 2] = 0.078206f;
+ 	val_dir[1551*3 + 0] = -0.179355f;	val_dir[1551*3 + 1] = -0.976491f;	val_dir[1551*3 + 2] = 0.119570f;
+ 	val_dir[1552*3 + 0] = -0.162221f;	val_dir[1552*3 + 1] = -0.973329f;	val_dir[1552*3 + 2] = 0.162221f;
+ 	val_dir[1553*3 + 0] = -0.144154f;	val_dir[1553*3 + 1] = -0.967890f;	val_dir[1553*3 + 2] = 0.205934f;
+ 	val_dir[1554*3 + 0] = -0.125218f;	val_dir[1554*3 + 1] = -0.960001f;	val_dir[1554*3 + 2] = 0.250435f;
+ 	val_dir[1555*3 + 0] = -0.105503f;	val_dir[1555*3 + 1] = -0.949528f;	val_dir[1555*3 + 2] = 0.295409f;
+ 	val_dir[1556*3 + 0] = -0.085126f;	val_dir[1556*3 + 1] = -0.936382f;	val_dir[1556*3 + 2] = 0.340503f;
+ 	val_dir[1557*3 + 0] = -0.064223f;	val_dir[1557*3 + 1] = -0.920537f;	val_dir[1557*3 + 2] = 0.385341f;
+ 	val_dir[1558*3 + 0] = -0.042954f;	val_dir[1558*3 + 1] = -0.902027f;	val_dir[1558*3 + 2] = 0.429537f;
+ 	val_dir[1559*3 + 0] = -0.021487f;	val_dir[1559*3 + 1] = -0.880957f;	val_dir[1559*3 + 2] = 0.472709f;
+ 	val_dir[1560*3 + 0] = 0.0f;	val_dir[1560*3 + 1] = -0.857493f;	val_dir[1560*3 + 2] = 0.514496f;
+ 	val_dir[1561*3 + 0] = 0.021832f;	val_dir[1561*3 + 1] = -0.851455f;	val_dir[1561*3 + 2] = 0.523973f;
+ 	val_dir[1562*3 + 0] = 0.044455f;	val_dir[1562*3 + 1] = -0.844653f;	val_dir[1562*3 + 2] = 0.533465f;
+ 	val_dir[1563*3 + 0] = 0.067867f;	val_dir[1563*3 + 1] = -0.837027f;	val_dir[1563*3 + 2] = 0.542936f;
+ 	val_dir[1564*3 + 0] = 0.092057f;	val_dir[1564*3 + 1] = -0.828517f;	val_dir[1564*3 + 2] = 0.552345f;
+ 	val_dir[1565*3 + 0] = 0.117009f;	val_dir[1565*3 + 1] = -0.819064f;	val_dir[1565*3 + 2] = 0.561644f;
+ 	val_dir[1566*3 + 0] = 0.142695f;	val_dir[1566*3 + 1] = -0.808608f;	val_dir[1566*3 + 2] = 0.570782f;
+ 	val_dir[1567*3 + 0] = 0.169080f;	val_dir[1567*3 + 1] = -0.797092f;	val_dir[1567*3 + 2] = 0.579703f;
+ 	val_dir[1568*3 + 0] = 0.196116f;	val_dir[1568*3 + 1] = -0.784465f;	val_dir[1568*3 + 2] = 0.588348f;
+ 	val_dir[1569*3 + 0] = 0.223745f;	val_dir[1569*3 + 1] = -0.770677f;	val_dir[1569*3 + 2] = 0.596653f;
+ 	val_dir[1570*3 + 0] = 0.251896f;	val_dir[1570*3 + 1] = -0.755689f;	val_dir[1570*3 + 2] = 0.604551f;
+ 	val_dir[1571*3 + 0] = 0.280488f;	val_dir[1571*3 + 1] = -0.739469f;	val_dir[1571*3 + 2] = 0.611974f;
+ 	val_dir[1572*3 + 0] = 0.309426f;	val_dir[1572*3 + 1] = -0.721995f;	val_dir[1572*3 + 2] = 0.618853f;
+ 	val_dir[1573*3 + 0] = 0.338606f;	val_dir[1573*3 + 1] = -0.703259f;	val_dir[1573*3 + 2] = 0.625119f;
+ 	val_dir[1574*3 + 0] = 0.367912f;	val_dir[1574*3 + 1] = -0.683265f;	val_dir[1574*3 + 2] = 0.630706f;
+ 	val_dir[1575*3 + 0] = 0.397220f;	val_dir[1575*3 + 1] = -0.662034f;	val_dir[1575*3 + 2] = 0.635553f;
+ 	val_dir[1576*3 + 0] = 0.426401f;	val_dir[1576*3 + 1] = -0.639602f;	val_dir[1576*3 + 2] = 0.639602f;
+ 	val_dir[1577*3 + 0] = 0.455321f;	val_dir[1577*3 + 1] = -0.616022f;	val_dir[1577*3 + 2] = 0.642806f;
+ 	val_dir[1578*3 + 0] = 0.483843f;	val_dir[1578*3 + 1] = -0.591364f;	val_dir[1578*3 + 2] = 0.645124f;
+ 	val_dir[1579*3 + 0] = 0.511834f;	val_dir[1579*3 + 1] = -0.565711f;	val_dir[1579*3 + 2] = 0.646527f;
+ 	val_dir[1580*3 + 0] = 0.539164f;	val_dir[1580*3 + 1] = -0.539164f;	val_dir[1580*3 + 2] = 0.646997f;
+ 	val_dir[1581*3 + 0] = 0.565711f;	val_dir[1581*3 + 1] = -0.511834f;	val_dir[1581*3 + 2] = 0.646527f;
+ 	val_dir[1582*3 + 0] = 0.591364f;	val_dir[1582*3 + 1] = -0.483843f;	val_dir[1582*3 + 2] = 0.645124f;
+ 	val_dir[1583*3 + 0] = 0.616022f;	val_dir[1583*3 + 1] = -0.455321f;	val_dir[1583*3 + 2] = 0.642806f;
+ 	val_dir[1584*3 + 0] = 0.639602f;	val_dir[1584*3 + 1] = -0.426401f;	val_dir[1584*3 + 2] = 0.639602f;
+ 	val_dir[1585*3 + 0] = 0.662034f;	val_dir[1585*3 + 1] = -0.397220f;	val_dir[1585*3 + 2] = 0.635553f;
+ 	val_dir[1586*3 + 0] = 0.683265f;	val_dir[1586*3 + 1] = -0.367912f;	val_dir[1586*3 + 2] = 0.630706f;
+ 	val_dir[1587*3 + 0] = 0.703259f;	val_dir[1587*3 + 1] = -0.338606f;	val_dir[1587*3 + 2] = 0.625119f;
+ 	val_dir[1588*3 + 0] = 0.721995f;	val_dir[1588*3 + 1] = -0.309426f;	val_dir[1588*3 + 2] = 0.618853f;
+ 	val_dir[1589*3 + 0] = 0.739469f;	val_dir[1589*3 + 1] = -0.280488f;	val_dir[1589*3 + 2] = 0.611974f;
+ 	val_dir[1590*3 + 0] = 0.755689f;	val_dir[1590*3 + 1] = -0.251896f;	val_dir[1590*3 + 2] = 0.604551f;
+ 	val_dir[1591*3 + 0] = 0.770677f;	val_dir[1591*3 + 1] = -0.223745f;	val_dir[1591*3 + 2] = 0.596653f;
+ 	val_dir[1592*3 + 0] = 0.784465f;	val_dir[1592*3 + 1] = -0.196116f;	val_dir[1592*3 + 2] = 0.588348f;
+ 	val_dir[1593*3 + 0] = 0.797092f;	val_dir[1593*3 + 1] = -0.169080f;	val_dir[1593*3 + 2] = 0.579703f;
+ 	val_dir[1594*3 + 0] = 0.808608f;	val_dir[1594*3 + 1] = -0.142695f;	val_dir[1594*3 + 2] = 0.570782f;
+ 	val_dir[1595*3 + 0] = 0.819064f;	val_dir[1595*3 + 1] = -0.117009f;	val_dir[1595*3 + 2] = 0.561644f;
+ 	val_dir[1596*3 + 0] = 0.828517f;	val_dir[1596*3 + 1] = -0.092057f;	val_dir[1596*3 + 2] = 0.552345f;
+ 	val_dir[1597*3 + 0] = 0.837027f;	val_dir[1597*3 + 1] = -0.067867f;	val_dir[1597*3 + 2] = 0.542936f;
+ 	val_dir[1598*3 + 0] = 0.844653f;	val_dir[1598*3 + 1] = -0.044455f;	val_dir[1598*3 + 2] = 0.533465f;
+ 	val_dir[1599*3 + 0] = 0.851455f;	val_dir[1599*3 + 1] = -0.021832f;	val_dir[1599*3 + 2] = 0.523973f;
+ 	val_dir[1600*3 + 0] = 0.857493f;	val_dir[1600*3 + 1] = 0.0f;	val_dir[1600*3 + 2] = 0.514496f;
+ 	val_dir[1601*3 + 0] = 0.880957f;	val_dir[1601*3 + 1] = 0.021487f;	val_dir[1601*3 + 2] = 0.472709f;
+ 	val_dir[1602*3 + 0] = 0.902027f;	val_dir[1602*3 + 1] = 0.042954f;	val_dir[1602*3 + 2] = 0.429537f;
+ 	val_dir[1603*3 + 0] = 0.920537f;	val_dir[1603*3 + 1] = 0.064223f;	val_dir[1603*3 + 2] = 0.385341f;
+ 	val_dir[1604*3 + 0] = 0.936382f;	val_dir[1604*3 + 1] = 0.085126f;	val_dir[1604*3 + 2] = 0.340503f;
+ 	val_dir[1605*3 + 0] = 0.949528f;	val_dir[1605*3 + 1] = 0.105503f;	val_dir[1605*3 + 2] = 0.295409f;
+ 	val_dir[1606*3 + 0] = 0.960001f;	val_dir[1606*3 + 1] = 0.125218f;	val_dir[1606*3 + 2] = 0.250435f;
+ 	val_dir[1607*3 + 0] = 0.967890f;	val_dir[1607*3 + 1] = 0.144154f;	val_dir[1607*3 + 2] = 0.205934f;
+ 	val_dir[1608*3 + 0] = 0.973329f;	val_dir[1608*3 + 1] = 0.162221f;	val_dir[1608*3 + 2] = 0.162221f;
+ 	val_dir[1609*3 + 0] = 0.976491f;	val_dir[1609*3 + 1] = 0.179355f;	val_dir[1609*3 + 2] = 0.119570f;
+ 	val_dir[1610*3 + 0] = 0.977577f;	val_dir[1610*3 + 1] = 0.195515f;	val_dir[1610*3 + 2] = 0.078206f;
+ 	val_dir[1611*3 + 0] = 0.976804f;	val_dir[1611*3 + 1] = 0.210683f;	val_dir[1611*3 + 2] = 0.038306f;
+ 	val_dir[1612*3 + 0] = 0.974391f;	val_dir[1612*3 + 1] = 0.224860f;	val_dir[1612*3 + 2] = 0.0f;
+ 	val_dir[1613*3 + 0] = -0.228998f;	val_dir[1613*3 + 1] = -0.973240f;	val_dir[1613*3 + 2] = 0.019083f;
+ 	val_dir[1614*3 + 0] = -0.214494f;	val_dir[1614*3 + 1] = -0.974972f;	val_dir[1614*3 + 2] = 0.058498f;
+ 	val_dir[1615*3 + 0] = -0.198968f;	val_dir[1615*3 + 1] = -0.974943f;	val_dir[1615*3 + 2] = 0.099484f;
+ 	val_dir[1616*3 + 0] = -0.182424f;	val_dir[1616*3 + 1] = -0.972929f;	val_dir[1616*3 + 2] = 0.141885f;
+ 	val_dir[1617*3 + 0] = -0.164887f;	val_dir[1617*3 + 1] = -0.968712f;	val_dir[1617*3 + 2] = 0.185498f;
+ 	val_dir[1618*3 + 0] = -0.146406f;	val_dir[1618*3 + 1] = -0.962099f;	val_dir[1618*3 + 2] = 0.230067f;
+ 	val_dir[1619*3 + 0] = -0.127057f;	val_dir[1619*3 + 1] = -0.952928f;	val_dir[1619*3 + 2] = 0.275290f;
+ 	val_dir[1620*3 + 0] = -0.106941f;	val_dir[1620*3 + 1] = -0.941082f;	val_dir[1620*3 + 2] = 0.320824f;
+ 	val_dir[1621*3 + 0] = -0.086186f;	val_dir[1621*3 + 1] = -0.92650f;	val_dir[1621*3 + 2] = 0.366291f;
+ 	val_dir[1622*3 + 0] = -0.064942f;	val_dir[1622*3 + 1] = -0.909185f;	val_dir[1622*3 + 2] = 0.411298f;
+ 	val_dir[1623*3 + 0] = -0.043376f;	val_dir[1623*3 + 1] = -0.889206f;	val_dir[1623*3 + 2] = 0.455447f;
+ 	val_dir[1624*3 + 0] = -0.021668f;	val_dir[1624*3 + 1] = -0.866703f;	val_dir[1624*3 + 2] = 0.498354f;
+ 	val_dir[1625*3 + 0] = 0.0f;	val_dir[1625*3 + 1] = -0.841879f;	val_dir[1625*3 + 2] = 0.539666f;
+ 	val_dir[1626*3 + 0] = 0.021979f;	val_dir[1626*3 + 1] = -0.835215f;	val_dir[1626*3 + 2] = 0.549484f;
+ 	val_dir[1627*3 + 0] = 0.044744f;	val_dir[1627*3 + 1] = -0.827759f;	val_dir[1627*3 + 2] = 0.559297f;
+ 	val_dir[1628*3 + 0] = 0.068288f;	val_dir[1628*3 + 1] = -0.819453f;	val_dir[1628*3 + 2] = 0.569064f;
+ 	val_dir[1629*3 + 0] = 0.092599f;	val_dir[1629*3 + 1] = -0.810237f;	val_dir[1629*3 + 2] = 0.578741f;
+ 	val_dir[1630*3 + 0] = 0.117655f;	val_dir[1630*3 + 1] = -0.800055f;	val_dir[1630*3 + 2] = 0.588276f;
+ 	val_dir[1631*3 + 0] = 0.143427f;	val_dir[1631*3 + 1] = -0.788851f;	val_dir[1631*3 + 2] = 0.597614f;
+ 	val_dir[1632*3 + 0] = 0.169875f;	val_dir[1632*3 + 1] = -0.776571f;	val_dir[1632*3 + 2] = 0.606696f;
+ 	val_dir[1633*3 + 0] = 0.196946f;	val_dir[1633*3 + 1] = -0.763167f;	val_dir[1633*3 + 2] = 0.615457f;
+ 	val_dir[1634*3 + 0] = 0.224579f;	val_dir[1634*3 + 1] = -0.748598f;	val_dir[1634*3 + 2] = 0.623831f;
+ 	val_dir[1635*3 + 0] = 0.252699f;	val_dir[1635*3 + 1] = -0.732828f;	val_dir[1635*3 + 2] = 0.631748f;
+ 	val_dir[1636*3 + 0] = 0.281220f;	val_dir[1636*3 + 1] = -0.715834f;	val_dir[1636*3 + 2] = 0.639138f;
+ 	val_dir[1637*3 + 0] = 0.310045f;	val_dir[1637*3 + 1] = -0.697602f;	val_dir[1637*3 + 2] = 0.645928f;
+ 	val_dir[1638*3 + 0] = 0.339066f;	val_dir[1638*3 + 1] = -0.678133f;	val_dir[1638*3 + 2] = 0.652051f;
+ 	val_dir[1639*3 + 0] = 0.368166f;	val_dir[1639*3 + 1] = -0.657440f;	val_dir[1639*3 + 2] = 0.657440f;
+ 	val_dir[1640*3 + 0] = 0.397220f;	val_dir[1640*3 + 1] = -0.635553f;	val_dir[1640*3 + 2] = 0.662034f;
+ 	val_dir[1641*3 + 0] = 0.426099f;	val_dir[1641*3 + 1] = -0.612517f;	val_dir[1641*3 + 2] = 0.665780f;
+ 	val_dir[1642*3 + 0] = 0.454669f;	val_dir[1642*3 + 1] = -0.588395f;	val_dir[1642*3 + 2] = 0.668631f;
+ 	val_dir[1643*3 + 0] = 0.482798f;	val_dir[1643*3 + 1] = -0.563264f;	val_dir[1643*3 + 2] = 0.670552f;
+ 	val_dir[1644*3 + 0] = 0.510355f;	val_dir[1644*3 + 1] = -0.537215f;	val_dir[1644*3 + 2] = 0.671519f;
+ 	val_dir[1645*3 + 0] = 0.537215f;	val_dir[1645*3 + 1] = -0.510355f;	val_dir[1645*3 + 2] = 0.671519f;
+ 	val_dir[1646*3 + 0] = 0.563264f;	val_dir[1646*3 + 1] = -0.482798f;	val_dir[1646*3 + 2] = 0.670552f;
+ 	val_dir[1647*3 + 0] = 0.588395f;	val_dir[1647*3 + 1] = -0.454669f;	val_dir[1647*3 + 2] = 0.668631f;
+ 	val_dir[1648*3 + 0] = 0.612517f;	val_dir[1648*3 + 1] = -0.426099f;	val_dir[1648*3 + 2] = 0.665780f;
+ 	val_dir[1649*3 + 0] = 0.635553f;	val_dir[1649*3 + 1] = -0.397220f;	val_dir[1649*3 + 2] = 0.662034f;
+ 	val_dir[1650*3 + 0] = 0.657440f;	val_dir[1650*3 + 1] = -0.368166f;	val_dir[1650*3 + 2] = 0.657440f;
+ 	val_dir[1651*3 + 0] = 0.678133f;	val_dir[1651*3 + 1] = -0.339066f;	val_dir[1651*3 + 2] = 0.652051f;
+ 	val_dir[1652*3 + 0] = 0.697602f;	val_dir[1652*3 + 1] = -0.310045f;	val_dir[1652*3 + 2] = 0.645928f;
+ 	val_dir[1653*3 + 0] = 0.715834f;	val_dir[1653*3 + 1] = -0.281220f;	val_dir[1653*3 + 2] = 0.639138f;
+ 	val_dir[1654*3 + 0] = 0.732828f;	val_dir[1654*3 + 1] = -0.252699f;	val_dir[1654*3 + 2] = 0.631748f;
+ 	val_dir[1655*3 + 0] = 0.748598f;	val_dir[1655*3 + 1] = -0.224579f;	val_dir[1655*3 + 2] = 0.623831f;
+ 	val_dir[1656*3 + 0] = 0.763167f;	val_dir[1656*3 + 1] = -0.196946f;	val_dir[1656*3 + 2] = 0.615457f;
+ 	val_dir[1657*3 + 0] = 0.776571f;	val_dir[1657*3 + 1] = -0.169875f;	val_dir[1657*3 + 2] = 0.606696f;
+ 	val_dir[1658*3 + 0] = 0.788851f;	val_dir[1658*3 + 1] = -0.143427f;	val_dir[1658*3 + 2] = 0.597614f;
+ 	val_dir[1659*3 + 0] = 0.800055f;	val_dir[1659*3 + 1] = -0.117655f;	val_dir[1659*3 + 2] = 0.588276f;
+ 	val_dir[1660*3 + 0] = 0.810237f;	val_dir[1660*3 + 1] = -0.092599f;	val_dir[1660*3 + 2] = 0.578741f;
+ 	val_dir[1661*3 + 0] = 0.819453f;	val_dir[1661*3 + 1] = -0.068288f;	val_dir[1661*3 + 2] = 0.569064f;
+ 	val_dir[1662*3 + 0] = 0.827759f;	val_dir[1662*3 + 1] = -0.044744f;	val_dir[1662*3 + 2] = 0.559297f;
+ 	val_dir[1663*3 + 0] = 0.835215f;	val_dir[1663*3 + 1] = -0.021979f;	val_dir[1663*3 + 2] = 0.549484f;
+ 	val_dir[1664*3 + 0] = 0.841879f;	val_dir[1664*3 + 1] = 0.0f;	val_dir[1664*3 + 2] = 0.539666f;
+ 	val_dir[1665*3 + 0] = 0.866703f;	val_dir[1665*3 + 1] = 0.021668f;	val_dir[1665*3 + 2] = 0.498354f;
+ 	val_dir[1666*3 + 0] = 0.889206f;	val_dir[1666*3 + 1] = 0.043376f;	val_dir[1666*3 + 2] = 0.455447f;
+ 	val_dir[1667*3 + 0] = 0.909185f;	val_dir[1667*3 + 1] = 0.064942f;	val_dir[1667*3 + 2] = 0.411298f;
+ 	val_dir[1668*3 + 0] = 0.92650f;	val_dir[1668*3 + 1] = 0.086186f;	val_dir[1668*3 + 2] = 0.366291f;
+ 	val_dir[1669*3 + 0] = 0.941082f;	val_dir[1669*3 + 1] = 0.106941f;	val_dir[1669*3 + 2] = 0.320824f;
+ 	val_dir[1670*3 + 0] = 0.952928f;	val_dir[1670*3 + 1] = 0.127057f;	val_dir[1670*3 + 2] = 0.275290f;
+ 	val_dir[1671*3 + 0] = 0.962099f;	val_dir[1671*3 + 1] = 0.146406f;	val_dir[1671*3 + 2] = 0.230067f;
+ 	val_dir[1672*3 + 0] = 0.968712f;	val_dir[1672*3 + 1] = 0.164887f;	val_dir[1672*3 + 2] = 0.185498f;
+ 	val_dir[1673*3 + 0] = 0.972929f;	val_dir[1673*3 + 1] = 0.182424f;	val_dir[1673*3 + 2] = 0.141885f;
+ 	val_dir[1674*3 + 0] = 0.974943f;	val_dir[1674*3 + 1] = 0.198968f;	val_dir[1674*3 + 2] = 0.099484f;
+ 	val_dir[1675*3 + 0] = 0.974972f;	val_dir[1675*3 + 1] = 0.214494f;	val_dir[1675*3 + 2] = 0.058498f;
+ 	val_dir[1676*3 + 0] = 0.973240f;	val_dir[1676*3 + 1] = 0.228998f;	val_dir[1676*3 + 2] = 0.019083f;
+ 	val_dir[1677*3 + 0] = -0.247004f;	val_dir[1677*3 + 1] = -0.969015f;	val_dir[1677*3 + 2] = 0.0f;
+ 	val_dir[1678*3 + 0] = -0.233197f;	val_dir[1678*3 + 1] = -0.971653f;	val_dir[1678*3 + 2] = 0.038866f;
+ 	val_dir[1679*3 + 0] = -0.218347f;	val_dir[1679*3 + 1] = -0.972636f;	val_dir[1679*3 + 2] = 0.079399f;
+ 	val_dir[1680*3 + 0] = -0.202444f;	val_dir[1680*3 + 1] = -0.971732f;	val_dir[1680*3 + 2] = 0.121466f;
+ 	val_dir[1681*3 + 0] = -0.185498f;	val_dir[1681*3 + 1] = -0.968712f;	val_dir[1681*3 + 2] = 0.164887f;
+ 	val_dir[1682*3 + 0] = -0.167542f;	val_dir[1682*3 + 1] = -0.963364f;	val_dir[1682*3 + 2] = 0.209427f;
+ 	val_dir[1683*3 + 0] = -0.148634f;	val_dir[1683*3 + 1] = -0.955502f;	val_dir[1683*3 + 2] = 0.254801f;
+ 	val_dir[1684*3 + 0] = -0.128861f;	val_dir[1684*3 + 1] = -0.944981f;	val_dir[1684*3 + 2] = 0.300676f;
+ 	val_dir[1685*3 + 0] = -0.108338f;	val_dir[1685*3 + 1] = -0.931705f;	val_dir[1685*3 + 2] = 0.346681f;
+ 	val_dir[1686*3 + 0] = -0.087204f;	val_dir[1686*3 + 1] = -0.915644f;	val_dir[1686*3 + 2] = 0.392419f;
+ 	val_dir[1687*3 + 0] = -0.065622f;	val_dir[1687*3 + 1] = -0.896831f;	val_dir[1687*3 + 2] = 0.437479f;
+ 	val_dir[1688*3 + 0] = -0.043769f;	val_dir[1688*3 + 1] = -0.875376f;	val_dir[1688*3 + 2] = 0.481457f;
+ 	val_dir[1689*3 + 0] = -0.021832f;	val_dir[1689*3 + 1] = -0.851455f;	val_dir[1689*3 + 2] = 0.523973f;
+ 	val_dir[1690*3 + 0] = 0.0f;	val_dir[1690*3 + 1] = -0.825307f;	val_dir[1690*3 + 2] = 0.564684f;
+ 	val_dir[1691*3 + 0] = 0.022108f;	val_dir[1691*3 + 1] = -0.817992f;	val_dir[1691*3 + 2] = 0.574805f;
+ 	val_dir[1692*3 + 0] = 0.044992f;	val_dir[1692*3 + 1] = -0.809858f;	val_dir[1692*3 + 2] = 0.584898f;
+ 	val_dir[1693*3 + 0] = 0.068644f;	val_dir[1693*3 + 1] = -0.800850f;	val_dir[1693*3 + 2] = 0.594917f;
+ 	val_dir[1694*3 + 0] = 0.093048f;	val_dir[1694*3 + 1] = -0.790912f;	val_dir[1694*3 + 2] = 0.604815f;
+ 	val_dir[1695*3 + 0] = 0.118180f;	val_dir[1695*3 + 1] = -0.779987f;	val_dir[1695*3 + 2] = 0.614535f;
+ 	val_dir[1696*3 + 0] = 0.144005f;	val_dir[1696*3 + 1] = -0.768025f;	val_dir[1696*3 + 2] = 0.624020f;
+ 	val_dir[1697*3 + 0] = 0.170478f;	val_dir[1697*3 + 1] = -0.754976f;	val_dir[1697*3 + 2] = 0.633205f;
+ 	val_dir[1698*3 + 0] = 0.197546f;	val_dir[1698*3 + 1] = -0.740797f;	val_dir[1698*3 + 2] = 0.642024f;
+ 	val_dir[1699*3 + 0] = 0.225141f;	val_dir[1699*3 + 1] = -0.725454f;	val_dir[1699*3 + 2] = 0.650407f;
+ 	val_dir[1700*3 + 0] = 0.253185f;	val_dir[1700*3 + 1] = -0.708918f;	val_dir[1700*3 + 2] = 0.658281f;
+ 	val_dir[1701*3 + 0] = 0.281589f;	val_dir[1701*3 + 1] = -0.691173f;	val_dir[1701*3 + 2] = 0.665574f;
+ 	val_dir[1702*3 + 0] = 0.310253f;	val_dir[1702*3 + 1] = -0.672214f;	val_dir[1702*3 + 2] = 0.672214f;
+ 	val_dir[1703*3 + 0] = 0.339066f;	val_dir[1703*3 + 1] = -0.652051f;	val_dir[1703*3 + 2] = 0.678133f;
+ 	val_dir[1704*3 + 0] = 0.367912f;	val_dir[1704*3 + 1] = -0.630706f;	val_dir[1704*3 + 2] = 0.683265f;
+ 	val_dir[1705*3 + 0] = 0.396664f;	val_dir[1705*3 + 1] = -0.608219f;	val_dir[1705*3 + 2] = 0.687552f;
+ 	val_dir[1706*3 + 0] = 0.425195f;	val_dir[1706*3 + 1] = -0.584643f;	val_dir[1706*3 + 2] = 0.690942f;
+ 	val_dir[1707*3 + 0] = 0.453374f;	val_dir[1707*3 + 1] = -0.560050f;	val_dir[1707*3 + 2] = 0.693395f;
+ 	val_dir[1708*3 + 0] = 0.481070f;	val_dir[1708*3 + 1] = -0.534522f;	val_dir[1708*3 + 2] = 0.694879f;
+ 	val_dir[1709*3 + 0] = 0.508159f;	val_dir[1709*3 + 1] = -0.508159f;	val_dir[1709*3 + 2] = 0.695376f;
+ 	val_dir[1710*3 + 0] = 0.534522f;	val_dir[1710*3 + 1] = -0.481070f;	val_dir[1710*3 + 2] = 0.694879f;
+ 	val_dir[1711*3 + 0] = 0.560050f;	val_dir[1711*3 + 1] = -0.453374f;	val_dir[1711*3 + 2] = 0.693395f;
+ 	val_dir[1712*3 + 0] = 0.584643f;	val_dir[1712*3 + 1] = -0.425195f;	val_dir[1712*3 + 2] = 0.690942f;
+ 	val_dir[1713*3 + 0] = 0.608219f;	val_dir[1713*3 + 1] = -0.396664f;	val_dir[1713*3 + 2] = 0.687552f;
+ 	val_dir[1714*3 + 0] = 0.630706f;	val_dir[1714*3 + 1] = -0.367912f;	val_dir[1714*3 + 2] = 0.683265f;
+ 	val_dir[1715*3 + 0] = 0.652051f;	val_dir[1715*3 + 1] = -0.339066f;	val_dir[1715*3 + 2] = 0.678133f;
+ 	val_dir[1716*3 + 0] = 0.672214f;	val_dir[1716*3 + 1] = -0.310253f;	val_dir[1716*3 + 2] = 0.672214f;
+ 	val_dir[1717*3 + 0] = 0.691173f;	val_dir[1717*3 + 1] = -0.281589f;	val_dir[1717*3 + 2] = 0.665574f;
+ 	val_dir[1718*3 + 0] = 0.708918f;	val_dir[1718*3 + 1] = -0.253185f;	val_dir[1718*3 + 2] = 0.658281f;
+ 	val_dir[1719*3 + 0] = 0.725454f;	val_dir[1719*3 + 1] = -0.225141f;	val_dir[1719*3 + 2] = 0.650407f;
+ 	val_dir[1720*3 + 0] = 0.740797f;	val_dir[1720*3 + 1] = -0.197546f;	val_dir[1720*3 + 2] = 0.642024f;
+ 	val_dir[1721*3 + 0] = 0.754976f;	val_dir[1721*3 + 1] = -0.170478f;	val_dir[1721*3 + 2] = 0.633205f;
+ 	val_dir[1722*3 + 0] = 0.768025f;	val_dir[1722*3 + 1] = -0.144005f;	val_dir[1722*3 + 2] = 0.624020f;
+ 	val_dir[1723*3 + 0] = 0.779987f;	val_dir[1723*3 + 1] = -0.118180f;	val_dir[1723*3 + 2] = 0.614535f;
+ 	val_dir[1724*3 + 0] = 0.790912f;	val_dir[1724*3 + 1] = -0.093048f;	val_dir[1724*3 + 2] = 0.604815f;
+ 	val_dir[1725*3 + 0] = 0.800850f;	val_dir[1725*3 + 1] = -0.068644f;	val_dir[1725*3 + 2] = 0.594917f;
+ 	val_dir[1726*3 + 0] = 0.809858f;	val_dir[1726*3 + 1] = -0.044992f;	val_dir[1726*3 + 2] = 0.584898f;
+ 	val_dir[1727*3 + 0] = 0.817992f;	val_dir[1727*3 + 1] = -0.022108f;	val_dir[1727*3 + 2] = 0.574805f;
+ 	val_dir[1728*3 + 0] = 0.825307f;	val_dir[1728*3 + 1] = 0.0f;	val_dir[1728*3 + 2] = 0.564684f;
+ 	val_dir[1729*3 + 0] = 0.851455f;	val_dir[1729*3 + 1] = 0.021832f;	val_dir[1729*3 + 2] = 0.523973f;
+ 	val_dir[1730*3 + 0] = 0.875376f;	val_dir[1730*3 + 1] = 0.043769f;	val_dir[1730*3 + 2] = 0.481457f;
+ 	val_dir[1731*3 + 0] = 0.896831f;	val_dir[1731*3 + 1] = 0.065622f;	val_dir[1731*3 + 2] = 0.437479f;
+ 	val_dir[1732*3 + 0] = 0.915644f;	val_dir[1732*3 + 1] = 0.087204f;	val_dir[1732*3 + 2] = 0.392419f;
+ 	val_dir[1733*3 + 0] = 0.931705f;	val_dir[1733*3 + 1] = 0.108338f;	val_dir[1733*3 + 2] = 0.346681f;
+ 	val_dir[1734*3 + 0] = 0.944981f;	val_dir[1734*3 + 1] = 0.128861f;	val_dir[1734*3 + 2] = 0.300676f;
+ 	val_dir[1735*3 + 0] = 0.955502f;	val_dir[1735*3 + 1] = 0.148634f;	val_dir[1735*3 + 2] = 0.254801f;
+ 	val_dir[1736*3 + 0] = 0.963364f;	val_dir[1736*3 + 1] = 0.167542f;	val_dir[1736*3 + 2] = 0.209427f;
+ 	val_dir[1737*3 + 0] = 0.968712f;	val_dir[1737*3 + 1] = 0.185498f;	val_dir[1737*3 + 2] = 0.164887f;
+ 	val_dir[1738*3 + 0] = 0.971732f;	val_dir[1738*3 + 1] = 0.202444f;	val_dir[1738*3 + 2] = 0.121466f;
+ 	val_dir[1739*3 + 0] = 0.972636f;	val_dir[1739*3 + 1] = 0.218347f;	val_dir[1739*3 + 2] = 0.079399f;
+ 	val_dir[1740*3 + 0] = 0.971653f;	val_dir[1740*3 + 1] = 0.233197f;	val_dir[1740*3 + 2] = 0.038866f;
+ 	val_dir[1741*3 + 0] = 0.969015f;	val_dir[1741*3 + 1] = 0.247004f;	val_dir[1741*3 + 2] = 0.0f;
+ 	val_dir[1742*3 + 0] = -0.251587f;	val_dir[1742*3 + 1] = -0.967641f;	val_dir[1742*3 + 2] = 0.019353f;
+ 	val_dir[1743*3 + 0] = -0.237449f;	val_dir[1743*3 + 1] = -0.969584f;	val_dir[1743*3 + 2] = 0.059362f;
+ 	val_dir[1744*3 + 0] = -0.222234f;	val_dir[1744*3 + 1] = -0.969746f;	val_dir[1744*3 + 2] = 0.101015f;
+ 	val_dir[1745*3 + 0] = -0.205934f;	val_dir[1745*3 + 1] = -0.967890f;	val_dir[1745*3 + 2] = 0.144154f;
+ 	val_dir[1746*3 + 0] = -0.188567f;	val_dir[1746*3 + 1] = -0.963787f;	val_dir[1746*3 + 2] = 0.188567f;
+ 	val_dir[1747*3 + 0] = -0.170174f;	val_dir[1747*3 + 1] = -0.957230f;	val_dir[1747*3 + 2] = 0.233990f;
+ 	val_dir[1748*3 + 0] = -0.150826f;	val_dir[1748*3 + 1] = -0.948047f;	val_dir[1748*3 + 2] = 0.280105f;
+ 	val_dir[1749*3 + 0] = -0.130620f;	val_dir[1749*3 + 1] = -0.936111f;	val_dir[1749*3 + 2] = 0.326550f;
+ 	val_dir[1750*3 + 0] = -0.109685f;	val_dir[1750*3 + 1] = -0.921354f;	val_dir[1750*3 + 2] = 0.372929f;
+ 	val_dir[1751*3 + 0] = -0.088173f;	val_dir[1751*3 + 1] = -0.903777f;	val_dir[1751*3 + 2] = 0.418823f;
+ 	val_dir[1752*3 + 0] = -0.066259f;	val_dir[1752*3 + 1] = -0.883452f;	val_dir[1752*3 + 2] = 0.463812f;
+ 	val_dir[1753*3 + 0] = -0.044130f;	val_dir[1753*3 + 1] = -0.860527f;	val_dir[1753*3 + 2] = 0.507490f;
+ 	val_dir[1754*3 + 0] = -0.021979f;	val_dir[1754*3 + 1] = -0.835215f;	val_dir[1754*3 + 2] = 0.549484f;
+ 	val_dir[1755*3 + 0] = 0.0f;	val_dir[1755*3 + 1] = -0.807791f;	val_dir[1755*3 + 2] = 0.589469f;
+ 	val_dir[1756*3 + 0] = 0.022217f;	val_dir[1756*3 + 1] = -0.799803f;	val_dir[1756*3 + 2] = 0.599852f;
+ 	val_dir[1757*3 + 0] = 0.045198f;	val_dir[1757*3 + 1] = -0.790973f;	val_dir[1757*3 + 2] = 0.610179f;
+ 	val_dir[1758*3 + 0] = 0.068934f;	val_dir[1758*3 + 1] = -0.781248f;	val_dir[1758*3 + 2] = 0.620403f;
+ 	val_dir[1759*3 + 0] = 0.093403f;	val_dir[1759*3 + 1] = -0.770574f;	val_dir[1759*3 + 2] = 0.630470f;
+ 	val_dir[1760*3 + 0] = 0.118578f;	val_dir[1760*3 + 1] = -0.758899f;	val_dir[1760*3 + 2] = 0.640321f;
+ 	val_dir[1761*3 + 0] = 0.144421f;	val_dir[1761*3 + 1] = -0.746176f;	val_dir[1761*3 + 2] = 0.649895f;
+ 	val_dir[1762*3 + 0] = 0.170884f;	val_dir[1762*3 + 1] = -0.732361f;	val_dir[1762*3 + 2] = 0.659125f;
+ 	val_dir[1763*3 + 0] = 0.197908f;	val_dir[1763*3 + 1] = -0.717418f;	val_dir[1763*3 + 2] = 0.667940f;
+ 	val_dir[1764*3 + 0] = 0.225423f;	val_dir[1764*3 + 1] = -0.701316f;	val_dir[1764*3 + 2] = 0.676269f;
+ 	val_dir[1765*3 + 0] = 0.253347f;	val_dir[1765*3 + 1] = -0.684038f;	val_dir[1765*3 + 2] = 0.684038f;
+ 	val_dir[1766*3 + 0] = 0.281589f;	val_dir[1766*3 + 1] = -0.665574f;	val_dir[1766*3 + 2] = 0.691173f;
+ 	val_dir[1767*3 + 0] = 0.310045f;	val_dir[1767*3 + 1] = -0.645928f;	val_dir[1767*3 + 2] = 0.697602f;
+ 	val_dir[1768*3 + 0] = 0.338606f;	val_dir[1768*3 + 1] = -0.625119f;	val_dir[1768*3 + 2] = 0.703259f;
+ 	val_dir[1769*3 + 0] = 0.367152f;	val_dir[1769*3 + 1] = -0.603178f;	val_dir[1769*3 + 2] = 0.708079f;
+ 	val_dir[1770*3 + 0] = 0.395559f;	val_dir[1770*3 + 1] = -0.580154f;	val_dir[1770*3 + 2] = 0.712007f;
+ 	val_dir[1771*3 + 0] = 0.423702f;	val_dir[1771*3 + 1] = -0.556108f;	val_dir[1771*3 + 2] = 0.714997f;
+ 	val_dir[1772*3 + 0] = 0.451451f;	val_dir[1772*3 + 1] = -0.531119f;	val_dir[1772*3 + 2] = 0.717011f;
+ 	val_dir[1773*3 + 0] = 0.478683f;	val_dir[1773*3 + 1] = -0.505276f;	val_dir[1773*3 + 2] = 0.718024f;
+ 	val_dir[1774*3 + 0] = 0.505276f;	val_dir[1774*3 + 1] = -0.478683f;	val_dir[1774*3 + 2] = 0.718024f;
+ 	val_dir[1775*3 + 0] = 0.531119f;	val_dir[1775*3 + 1] = -0.451451f;	val_dir[1775*3 + 2] = 0.717011f;
+ 	val_dir[1776*3 + 0] = 0.556108f;	val_dir[1776*3 + 1] = -0.423702f;	val_dir[1776*3 + 2] = 0.714997f;
+ 	val_dir[1777*3 + 0] = 0.580154f;	val_dir[1777*3 + 1] = -0.395559f;	val_dir[1777*3 + 2] = 0.712007f;
+ 	val_dir[1778*3 + 0] = 0.603178f;	val_dir[1778*3 + 1] = -0.367152f;	val_dir[1778*3 + 2] = 0.708079f;
+ 	val_dir[1779*3 + 0] = 0.625119f;	val_dir[1779*3 + 1] = -0.338606f;	val_dir[1779*3 + 2] = 0.703259f;
+ 	val_dir[1780*3 + 0] = 0.645928f;	val_dir[1780*3 + 1] = -0.310045f;	val_dir[1780*3 + 2] = 0.697602f;
+ 	val_dir[1781*3 + 0] = 0.665574f;	val_dir[1781*3 + 1] = -0.281589f;	val_dir[1781*3 + 2] = 0.691173f;
+ 	val_dir[1782*3 + 0] = 0.684038f;	val_dir[1782*3 + 1] = -0.253347f;	val_dir[1782*3 + 2] = 0.684038f;
+ 	val_dir[1783*3 + 0] = 0.701316f;	val_dir[1783*3 + 1] = -0.225423f;	val_dir[1783*3 + 2] = 0.676269f;
+ 	val_dir[1784*3 + 0] = 0.717418f;	val_dir[1784*3 + 1] = -0.197908f;	val_dir[1784*3 + 2] = 0.667940f;
+ 	val_dir[1785*3 + 0] = 0.732361f;	val_dir[1785*3 + 1] = -0.170884f;	val_dir[1785*3 + 2] = 0.659125f;
+ 	val_dir[1786*3 + 0] = 0.746176f;	val_dir[1786*3 + 1] = -0.144421f;	val_dir[1786*3 + 2] = 0.649895f;
+ 	val_dir[1787*3 + 0] = 0.758899f;	val_dir[1787*3 + 1] = -0.118578f;	val_dir[1787*3 + 2] = 0.640321f;
+ 	val_dir[1788*3 + 0] = 0.770574f;	val_dir[1788*3 + 1] = -0.093403f;	val_dir[1788*3 + 2] = 0.630470f;
+ 	val_dir[1789*3 + 0] = 0.781248f;	val_dir[1789*3 + 1] = -0.068934f;	val_dir[1789*3 + 2] = 0.620403f;
+ 	val_dir[1790*3 + 0] = 0.790973f;	val_dir[1790*3 + 1] = -0.045198f;	val_dir[1790*3 + 2] = 0.610179f;
+ 	val_dir[1791*3 + 0] = 0.799803f;	val_dir[1791*3 + 1] = -0.022217f;	val_dir[1791*3 + 2] = 0.599852f;
+ 	val_dir[1792*3 + 0] = 0.807791f;	val_dir[1792*3 + 1] = 0.0f;	val_dir[1792*3 + 2] = 0.589469f;
+ 	val_dir[1793*3 + 0] = 0.835215f;	val_dir[1793*3 + 1] = 0.021979f;	val_dir[1793*3 + 2] = 0.549484f;
+ 	val_dir[1794*3 + 0] = 0.860527f;	val_dir[1794*3 + 1] = 0.044130f;	val_dir[1794*3 + 2] = 0.507490f;
+ 	val_dir[1795*3 + 0] = 0.883452f;	val_dir[1795*3 + 1] = 0.066259f;	val_dir[1795*3 + 2] = 0.463812f;
+ 	val_dir[1796*3 + 0] = 0.903777f;	val_dir[1796*3 + 1] = 0.088173f;	val_dir[1796*3 + 2] = 0.418823f;
+ 	val_dir[1797*3 + 0] = 0.921354f;	val_dir[1797*3 + 1] = 0.109685f;	val_dir[1797*3 + 2] = 0.372929f;
+ 	val_dir[1798*3 + 0] = 0.936111f;	val_dir[1798*3 + 1] = 0.130620f;	val_dir[1798*3 + 2] = 0.326550f;
+ 	val_dir[1799*3 + 0] = 0.948047f;	val_dir[1799*3 + 1] = 0.150826f;	val_dir[1799*3 + 2] = 0.280105f;
+ 	val_dir[1800*3 + 0] = 0.957230f;	val_dir[1800*3 + 1] = 0.170174f;	val_dir[1800*3 + 2] = 0.233990f;
+ 	val_dir[1801*3 + 0] = 0.963787f;	val_dir[1801*3 + 1] = 0.188567f;	val_dir[1801*3 + 2] = 0.188567f;
+ 	val_dir[1802*3 + 0] = 0.967890f;	val_dir[1802*3 + 1] = 0.205934f;	val_dir[1802*3 + 2] = 0.144154f;
+ 	val_dir[1803*3 + 0] = 0.969746f;	val_dir[1803*3 + 1] = 0.222234f;	val_dir[1803*3 + 2] = 0.101015f;
+ 	val_dir[1804*3 + 0] = 0.969584f;	val_dir[1804*3 + 1] = 0.237449f;	val_dir[1804*3 + 2] = 0.059362f;
+ 	val_dir[1805*3 + 0] = 0.967641f;	val_dir[1805*3 + 1] = 0.251587f;	val_dir[1805*3 + 2] = 0.019353f;
+ 	val_dir[1806*3 + 0] = -0.269630f;	val_dir[1806*3 + 1] = -0.962964f;	val_dir[1806*3 + 2] = 0.0f;
+ 	val_dir[1807*3 + 0] = -0.256235f;	val_dir[1807*3 + 1] = -0.965810f;	val_dir[1807*3 + 2] = 0.039421f;
+ 	val_dir[1808*3 + 0] = -0.241747f;	val_dir[1808*3 + 1] = -0.966988f;	val_dir[1808*3 + 2] = 0.080582f;
+ 	val_dir[1809*3 + 0] = -0.226144f;	val_dir[1809*3 + 1] = -0.966252f;	val_dir[1809*3 + 2] = 0.123351f;
+ 	val_dir[1810*3 + 0] = -0.209427f;	val_dir[1810*3 + 1] = -0.963364f;	val_dir[1810*3 + 2] = 0.167542f;
+ 	val_dir[1811*3 + 0] = -0.191620f;	val_dir[1811*3 + 1] = -0.958098f;	val_dir[1811*3 + 2] = 0.212911f;
+ 	val_dir[1812*3 + 0] = -0.172774f;	val_dir[1812*3 + 1] = -0.950255f;	val_dir[1812*3 + 2] = 0.259161f;
+ 	val_dir[1813*3 + 0] = -0.152971f;	val_dir[1813*3 + 1] = -0.939680f;	val_dir[1813*3 + 2] = 0.305942f;
+ 	val_dir[1814*3 + 0] = -0.132324f;	val_dir[1814*3 + 1] = -0.926270f;	val_dir[1814*3 + 2] = 0.352865f;
+ 	val_dir[1815*3 + 0] = -0.110974f;	val_dir[1815*3 + 1] = -0.909988f;	val_dir[1815*3 + 2] = 0.399507f;
+ 	val_dir[1816*3 + 0] = -0.089087f;	val_dir[1816*3 + 1] = -0.890871f;	val_dir[1816*3 + 2] = 0.445435f;
+ 	val_dir[1817*3 + 0] = -0.066848f;	val_dir[1817*3 + 1] = -0.869030f;	val_dir[1817*3 + 2] = 0.490222f;
+ 	val_dir[1818*3 + 0] = -0.044455f;	val_dir[1818*3 + 1] = -0.844653f;	val_dir[1818*3 + 2] = 0.533465f;
+ 	val_dir[1819*3 + 0] = -0.022108f;	val_dir[1819*3 + 1] = -0.817992f;	val_dir[1819*3 + 2] = 0.574805f;
+ 	val_dir[1820*3 + 0] = 0.0f;	val_dir[1820*3 + 1] = -0.789352f;	val_dir[1820*3 + 2] = 0.613941f;
+ 	val_dir[1821*3 + 0] = 0.022305f;	val_dir[1821*3 + 1] = -0.780675f;	val_dir[1821*3 + 2] = 0.624540f;
+ 	val_dir[1822*3 + 0] = 0.045361f;	val_dir[1822*3 + 1] = -0.771136f;	val_dir[1822*3 + 2] = 0.635053f;
+ 	val_dir[1823*3 + 0] = 0.069153f;	val_dir[1823*3 + 1] = -0.760684f;	val_dir[1823*3 + 2] = 0.645429f;
+ 	val_dir[1824*3 + 0] = 0.093659f;	val_dir[1824*3 + 1] = -0.749269f;	val_dir[1824*3 + 2] = 0.655610f;
+ 	val_dir[1825*3 + 0] = 0.118846f;	val_dir[1825*3 + 1] = -0.736843f;	val_dir[1825*3 + 2] = 0.665536f;
+ 	val_dir[1826*3 + 0] = 0.144673f;	val_dir[1826*3 + 1] = -0.723364f;	val_dir[1826*3 + 2] = 0.675140f;
+ 	val_dir[1827*3 + 0] = 0.171088f;	val_dir[1827*3 + 1] = -0.708794f;	val_dir[1827*3 + 2] = 0.684353f;
+ 	val_dir[1828*3 + 0] = 0.198030f;	val_dir[1828*3 + 1] = -0.693103f;	val_dir[1828*3 + 2] = 0.693103f;
+ 	val_dir[1829*3 + 0] = 0.225423f;	val_dir[1829*3 + 1] = -0.676269f;	val_dir[1829*3 + 2] = 0.701316f;
+ 	val_dir[1830*3 + 0] = 0.253185f;	val_dir[1830*3 + 1] = -0.658281f;	val_dir[1830*3 + 2] = 0.708918f;
+ 	val_dir[1831*3 + 0] = 0.281220f;	val_dir[1831*3 + 1] = -0.639138f;	val_dir[1831*3 + 2] = 0.715834f;
+ 	val_dir[1832*3 + 0] = 0.309426f;	val_dir[1832*3 + 1] = -0.618853f;	val_dir[1832*3 + 2] = 0.721995f;
+ 	val_dir[1833*3 + 0] = 0.337691f;	val_dir[1833*3 + 1] = -0.597453f;	val_dir[1833*3 + 2] = 0.727334f;
+ 	val_dir[1834*3 + 0] = 0.365896f;	val_dir[1834*3 + 1] = -0.574979f;	val_dir[1834*3 + 2] = 0.731792f;
+ 	val_dir[1835*3 + 0] = 0.393919f;	val_dir[1835*3 + 1] = -0.551487f;	val_dir[1835*3 + 2] = 0.735316f;
+ 	val_dir[1836*3 + 0] = 0.421637f;	val_dir[1836*3 + 1] = -0.527046f;	val_dir[1836*3 + 2] = 0.737865f;
+ 	val_dir[1837*3 + 0] = 0.448926f;	val_dir[1837*3 + 1] = -0.501740f;	val_dir[1837*3 + 2] = 0.739407f;
+ 	val_dir[1838*3 + 0] = 0.475665f;	val_dir[1838*3 + 1] = -0.475665f;	val_dir[1838*3 + 2] = 0.739923f;
+ 	val_dir[1839*3 + 0] = 0.501740f;	val_dir[1839*3 + 1] = -0.448926f;	val_dir[1839*3 + 2] = 0.739407f;
+ 	val_dir[1840*3 + 0] = 0.527046f;	val_dir[1840*3 + 1] = -0.421637f;	val_dir[1840*3 + 2] = 0.737865f;
+ 	val_dir[1841*3 + 0] = 0.551487f;	val_dir[1841*3 + 1] = -0.393919f;	val_dir[1841*3 + 2] = 0.735316f;
+ 	val_dir[1842*3 + 0] = 0.574979f;	val_dir[1842*3 + 1] = -0.365896f;	val_dir[1842*3 + 2] = 0.731792f;
+ 	val_dir[1843*3 + 0] = 0.597453f;	val_dir[1843*3 + 1] = -0.337691f;	val_dir[1843*3 + 2] = 0.727334f;
+ 	val_dir[1844*3 + 0] = 0.618853f;	val_dir[1844*3 + 1] = -0.309426f;	val_dir[1844*3 + 2] = 0.721995f;
+ 	val_dir[1845*3 + 0] = 0.639138f;	val_dir[1845*3 + 1] = -0.281220f;	val_dir[1845*3 + 2] = 0.715834f;
+ 	val_dir[1846*3 + 0] = 0.658281f;	val_dir[1846*3 + 1] = -0.253185f;	val_dir[1846*3 + 2] = 0.708918f;
+ 	val_dir[1847*3 + 0] = 0.676269f;	val_dir[1847*3 + 1] = -0.225423f;	val_dir[1847*3 + 2] = 0.701316f;
+ 	val_dir[1848*3 + 0] = 0.693103f;	val_dir[1848*3 + 1] = -0.198030f;	val_dir[1848*3 + 2] = 0.693103f;
+ 	val_dir[1849*3 + 0] = 0.708794f;	val_dir[1849*3 + 1] = -0.171088f;	val_dir[1849*3 + 2] = 0.684353f;
+ 	val_dir[1850*3 + 0] = 0.723364f;	val_dir[1850*3 + 1] = -0.144673f;	val_dir[1850*3 + 2] = 0.675140f;
+ 	val_dir[1851*3 + 0] = 0.736843f;	val_dir[1851*3 + 1] = -0.118846f;	val_dir[1851*3 + 2] = 0.665536f;
+ 	val_dir[1852*3 + 0] = 0.749269f;	val_dir[1852*3 + 1] = -0.093659f;	val_dir[1852*3 + 2] = 0.655610f;
+ 	val_dir[1853*3 + 0] = 0.760684f;	val_dir[1853*3 + 1] = -0.069153f;	val_dir[1853*3 + 2] = 0.645429f;
+ 	val_dir[1854*3 + 0] = 0.771136f;	val_dir[1854*3 + 1] = -0.045361f;	val_dir[1854*3 + 2] = 0.635053f;
+ 	val_dir[1855*3 + 0] = 0.780675f;	val_dir[1855*3 + 1] = -0.022305f;	val_dir[1855*3 + 2] = 0.624540f;
+ 	val_dir[1856*3 + 0] = 0.789352f;	val_dir[1856*3 + 1] = 0.0f;	val_dir[1856*3 + 2] = 0.613941f;
+ 	val_dir[1857*3 + 0] = 0.817992f;	val_dir[1857*3 + 1] = 0.022108f;	val_dir[1857*3 + 2] = 0.574805f;
+ 	val_dir[1858*3 + 0] = 0.844653f;	val_dir[1858*3 + 1] = 0.044455f;	val_dir[1858*3 + 2] = 0.533465f;
+ 	val_dir[1859*3 + 0] = 0.869030f;	val_dir[1859*3 + 1] = 0.066848f;	val_dir[1859*3 + 2] = 0.490222f;
+ 	val_dir[1860*3 + 0] = 0.890871f;	val_dir[1860*3 + 1] = 0.089087f;	val_dir[1860*3 + 2] = 0.445435f;
+ 	val_dir[1861*3 + 0] = 0.909988f;	val_dir[1861*3 + 1] = 0.110974f;	val_dir[1861*3 + 2] = 0.399507f;
+ 	val_dir[1862*3 + 0] = 0.926270f;	val_dir[1862*3 + 1] = 0.132324f;	val_dir[1862*3 + 2] = 0.352865f;
+ 	val_dir[1863*3 + 0] = 0.939680f;	val_dir[1863*3 + 1] = 0.152971f;	val_dir[1863*3 + 2] = 0.305942f;
+ 	val_dir[1864*3 + 0] = 0.950255f;	val_dir[1864*3 + 1] = 0.172774f;	val_dir[1864*3 + 2] = 0.259161f;
+ 	val_dir[1865*3 + 0] = 0.958098f;	val_dir[1865*3 + 1] = 0.191620f;	val_dir[1865*3 + 2] = 0.212911f;
+ 	val_dir[1866*3 + 0] = 0.963364f;	val_dir[1866*3 + 1] = 0.209427f;	val_dir[1866*3 + 2] = 0.167542f;
+ 	val_dir[1867*3 + 0] = 0.966252f;	val_dir[1867*3 + 1] = 0.226144f;	val_dir[1867*3 + 2] = 0.123351f;
+ 	val_dir[1868*3 + 0] = 0.966988f;	val_dir[1868*3 + 1] = 0.241747f;	val_dir[1868*3 + 2] = 0.080582f;
+ 	val_dir[1869*3 + 0] = 0.965810f;	val_dir[1869*3 + 1] = 0.256235f;	val_dir[1869*3 + 2] = 0.039421f;
+ 	val_dir[1870*3 + 0] = 0.962964f;	val_dir[1870*3 + 1] = 0.269630f;	val_dir[1870*3 + 2] = 0.0f;
+ 	val_dir[1871*3 + 0] = -0.274668f;	val_dir[1871*3 + 1] = -0.961339f;	val_dir[1871*3 + 2] = 0.019619f;
+ 	val_dir[1872*3 + 0] = -0.260941f;	val_dir[1872*3 + 1] = -0.963475f;	val_dir[1872*3 + 2] = 0.060217f;
+ 	val_dir[1873*3 + 0] = -0.246079f;	val_dir[1873*3 + 1] = -0.963811f;	val_dir[1873*3 + 2] = 0.102533f;
+ 	val_dir[1874*3 + 0] = -0.230067f;	val_dir[1874*3 + 1] = -0.962099f;	val_dir[1874*3 + 2] = 0.146406f;
+ 	val_dir[1875*3 + 0] = -0.212911f;	val_dir[1875*3 + 1] = -0.958098f;	val_dir[1875*3 + 2] = 0.191620f;
+ 	val_dir[1876*3 + 0] = -0.194643f;	val_dir[1876*3 + 1] = -0.951588f;	val_dir[1876*3 + 2] = 0.237897f;
+ 	val_dir[1877*3 + 0] = -0.175327f;	val_dir[1877*3 + 1] = -0.942384f;	val_dir[1877*3 + 2] = 0.284907f;
+ 	val_dir[1878*3 + 0] = -0.155059f;	val_dir[1878*3 + 1] = -0.930352f;	val_dir[1878*3 + 2] = 0.332269f;
+ 	val_dir[1879*3 + 0] = -0.133963f;	val_dir[1879*3 + 1] = -0.915416f;	val_dir[1879*3 + 2] = 0.379563f;
+ 	val_dir[1880*3 + 0] = -0.112197f;	val_dir[1880*3 + 1] = -0.897574f;	val_dir[1880*3 + 2] = 0.426348f;
+ 	val_dir[1881*3 + 0] = -0.089939f;	val_dir[1881*3 + 1] = -0.876903f;	val_dir[1881*3 + 2] = 0.472178f;
+ 	val_dir[1882*3 + 0] = -0.067386f;	val_dir[1882*3 + 1] = -0.853556f;	val_dir[1882*3 + 2] = 0.516626f;
+ 	val_dir[1883*3 + 0] = -0.044744f;	val_dir[1883*3 + 1] = -0.827759f;	val_dir[1883*3 + 2] = 0.559297f;
+ 	val_dir[1884*3 + 0] = -0.022217f;	val_dir[1884*3 + 1] = -0.799803f;	val_dir[1884*3 + 2] = 0.599852f;
+ 	val_dir[1885*3 + 0] = 0.0f;	val_dir[1885*3 + 1] = -0.770022f;	val_dir[1885*3 + 2] = 0.638018f;
+ 	val_dir[1886*3 + 0] = 0.022372f;	val_dir[1886*3 + 1] = -0.760644f;	val_dir[1886*3 + 2] = 0.648784f;
+ 	val_dir[1887*3 + 0] = 0.045478f;	val_dir[1887*3 + 1] = -0.750388f;	val_dir[1887*3 + 2] = 0.659432f;
+ 	val_dir[1888*3 + 0] = 0.069301f;	val_dir[1888*3 + 1] = -0.739205f;	val_dir[1888*3 + 2] = 0.669905f;
+ 	val_dir[1889*3 + 0] = 0.093813f;	val_dir[1889*3 + 1] = -0.727051f;	val_dir[1889*3 + 2] = 0.680144f;
+ 	val_dir[1890*3 + 0] = 0.118980f;	val_dir[1890*3 + 1] = -0.713881f;	val_dir[1890*3 + 2] = 0.690085f;
+ 	val_dir[1891*3 + 0] = 0.144757f;	val_dir[1891*3 + 1] = -0.699659f;	val_dir[1891*3 + 2] = 0.699659f;
+ 	val_dir[1892*3 + 0] = 0.171088f;	val_dir[1892*3 + 1] = -0.684353f;	val_dir[1892*3 + 2] = 0.708794f;
+ 	val_dir[1893*3 + 0] = 0.197908f;	val_dir[1893*3 + 1] = -0.667940f;	val_dir[1893*3 + 2] = 0.717418f;
+ 	val_dir[1894*3 + 0] = 0.225141f;	val_dir[1894*3 + 1] = -0.650407f;	val_dir[1894*3 + 2] = 0.725454f;
+ 	val_dir[1895*3 + 0] = 0.252699f;	val_dir[1895*3 + 1] = -0.631748f;	val_dir[1895*3 + 2] = 0.732828f;
+ 	val_dir[1896*3 + 0] = 0.280488f;	val_dir[1896*3 + 1] = -0.611974f;	val_dir[1896*3 + 2] = 0.739469f;
+ 	val_dir[1897*3 + 0] = 0.308403f;	val_dir[1897*3 + 1] = -0.591105f;	val_dir[1897*3 + 2] = 0.745307f;
+ 	val_dir[1898*3 + 0] = 0.336332f;	val_dir[1898*3 + 1] = -0.569177f;	val_dir[1898*3 + 2] = 0.750279f;
+ 	val_dir[1899*3 + 0] = 0.364159f;	val_dir[1899*3 + 1] = -0.546238f;	val_dir[1899*3 + 2] = 0.754329f;
+ 	val_dir[1900*3 + 0] = 0.391764f;	val_dir[1900*3 + 1] = -0.522352f;	val_dir[1900*3 + 2] = 0.757410f;
+ 	val_dir[1901*3 + 0] = 0.419026f;	val_dir[1901*3 + 1] = -0.497594f;	val_dir[1901*3 + 2] = 0.759485f;
+ 	val_dir[1902*3 + 0] = 0.445827f;	val_dir[1902*3 + 1] = -0.472053f;	val_dir[1902*3 + 2] = 0.760529f;
+ 	val_dir[1903*3 + 0] = 0.472053f;	val_dir[1903*3 + 1] = -0.445827f;	val_dir[1903*3 + 2] = 0.760529f;
+ 	val_dir[1904*3 + 0] = 0.497594f;	val_dir[1904*3 + 1] = -0.419026f;	val_dir[1904*3 + 2] = 0.759485f;
+ 	val_dir[1905*3 + 0] = 0.522352f;	val_dir[1905*3 + 1] = -0.391764f;	val_dir[1905*3 + 2] = 0.757410f;
+ 	val_dir[1906*3 + 0] = 0.546238f;	val_dir[1906*3 + 1] = -0.364159f;	val_dir[1906*3 + 2] = 0.754329f;
+ 	val_dir[1907*3 + 0] = 0.569177f;	val_dir[1907*3 + 1] = -0.336332f;	val_dir[1907*3 + 2] = 0.750279f;
+ 	val_dir[1908*3 + 0] = 0.591105f;	val_dir[1908*3 + 1] = -0.308403f;	val_dir[1908*3 + 2] = 0.745307f;
+ 	val_dir[1909*3 + 0] = 0.611974f;	val_dir[1909*3 + 1] = -0.280488f;	val_dir[1909*3 + 2] = 0.739469f;
+ 	val_dir[1910*3 + 0] = 0.631748f;	val_dir[1910*3 + 1] = -0.252699f;	val_dir[1910*3 + 2] = 0.732828f;
+ 	val_dir[1911*3 + 0] = 0.650407f;	val_dir[1911*3 + 1] = -0.225141f;	val_dir[1911*3 + 2] = 0.725454f;
+ 	val_dir[1912*3 + 0] = 0.667940f;	val_dir[1912*3 + 1] = -0.197908f;	val_dir[1912*3 + 2] = 0.717418f;
+ 	val_dir[1913*3 + 0] = 0.684353f;	val_dir[1913*3 + 1] = -0.171088f;	val_dir[1913*3 + 2] = 0.708794f;
+ 	val_dir[1914*3 + 0] = 0.699659f;	val_dir[1914*3 + 1] = -0.144757f;	val_dir[1914*3 + 2] = 0.699659f;
+ 	val_dir[1915*3 + 0] = 0.713881f;	val_dir[1915*3 + 1] = -0.118980f;	val_dir[1915*3 + 2] = 0.690085f;
+ 	val_dir[1916*3 + 0] = 0.727051f;	val_dir[1916*3 + 1] = -0.093813f;	val_dir[1916*3 + 2] = 0.680144f;
+ 	val_dir[1917*3 + 0] = 0.739205f;	val_dir[1917*3 + 1] = -0.069301f;	val_dir[1917*3 + 2] = 0.669905f;
+ 	val_dir[1918*3 + 0] = 0.750388f;	val_dir[1918*3 + 1] = -0.045478f;	val_dir[1918*3 + 2] = 0.659432f;
+ 	val_dir[1919*3 + 0] = 0.760644f;	val_dir[1919*3 + 1] = -0.022372f;	val_dir[1919*3 + 2] = 0.648784f;
+ 	val_dir[1920*3 + 0] = 0.770022f;	val_dir[1920*3 + 1] = 0.0f;	val_dir[1920*3 + 2] = 0.638018f;
+ 	val_dir[1921*3 + 0] = 0.799803f;	val_dir[1921*3 + 1] = 0.022217f;	val_dir[1921*3 + 2] = 0.599852f;
+ 	val_dir[1922*3 + 0] = 0.827759f;	val_dir[1922*3 + 1] = 0.044744f;	val_dir[1922*3 + 2] = 0.559297f;
+ 	val_dir[1923*3 + 0] = 0.853556f;	val_dir[1923*3 + 1] = 0.067386f;	val_dir[1923*3 + 2] = 0.516626f;
+ 	val_dir[1924*3 + 0] = 0.876903f;	val_dir[1924*3 + 1] = 0.089939f;	val_dir[1924*3 + 2] = 0.472178f;
+ 	val_dir[1925*3 + 0] = 0.897574f;	val_dir[1925*3 + 1] = 0.112197f;	val_dir[1925*3 + 2] = 0.426348f;
+ 	val_dir[1926*3 + 0] = 0.915416f;	val_dir[1926*3 + 1] = 0.133963f;	val_dir[1926*3 + 2] = 0.379563f;
+ 	val_dir[1927*3 + 0] = 0.930352f;	val_dir[1927*3 + 1] = 0.155059f;	val_dir[1927*3 + 2] = 0.332269f;
+ 	val_dir[1928*3 + 0] = 0.942384f;	val_dir[1928*3 + 1] = 0.175327f;	val_dir[1928*3 + 2] = 0.284907f;
+ 	val_dir[1929*3 + 0] = 0.951588f;	val_dir[1929*3 + 1] = 0.194643f;	val_dir[1929*3 + 2] = 0.237897f;
+ 	val_dir[1930*3 + 0] = 0.958098f;	val_dir[1930*3 + 1] = 0.212911f;	val_dir[1930*3 + 2] = 0.191620f;
+ 	val_dir[1931*3 + 0] = 0.962099f;	val_dir[1931*3 + 1] = 0.230067f;	val_dir[1931*3 + 2] = 0.146406f;
+ 	val_dir[1932*3 + 0] = 0.963811f;	val_dir[1932*3 + 1] = 0.246079f;	val_dir[1932*3 + 2] = 0.102533f;
+ 	val_dir[1933*3 + 0] = 0.963475f;	val_dir[1933*3 + 1] = 0.260941f;	val_dir[1933*3 + 2] = 0.060217f;
+ 	val_dir[1934*3 + 0] = 0.961339f;	val_dir[1934*3 + 1] = 0.274668f;	val_dir[1934*3 + 2] = 0.019619f;
+ 	val_dir[1935*3 + 0] = -0.292714f;	val_dir[1935*3 + 1] = -0.95620f;	val_dir[1935*3 + 2] = 0.0f;
+ 	val_dir[1936*3 + 0] = -0.279776f;	val_dir[1936*3 + 1] = -0.959233f;	val_dir[1936*3 + 2] = 0.039968f;
+ 	val_dir[1937*3 + 0] = -0.265694f;	val_dir[1937*3 + 1] = -0.960585f;	val_dir[1937*3 + 2] = 0.081752f;
+ 	val_dir[1938*3 + 0] = -0.250435f;	val_dir[1938*3 + 1] = -0.960001f;	val_dir[1938*3 + 2] = 0.125218f;
+ 	val_dir[1939*3 + 0] = -0.233990f;	val_dir[1939*3 + 1] = -0.957230f;	val_dir[1939*3 + 2] = 0.170174f;
+ 	val_dir[1940*3 + 0] = -0.216371f;	val_dir[1940*3 + 1] = -0.952033f;	val_dir[1940*3 + 2] = 0.216371f;
+ 	val_dir[1941*3 + 0] = -0.197623f;	val_dir[1941*3 + 1] = -0.94420f;	val_dir[1941*3 + 2] = 0.263498f;
+ 	val_dir[1942*3 + 0] = -0.177822f;	val_dir[1942*3 + 1] = -0.933564f;	val_dir[1942*3 + 2] = 0.311188f;
+ 	val_dir[1943*3 + 0] = -0.157075f;	val_dir[1943*3 + 1] = -0.920014f;	val_dir[1943*3 + 2] = 0.359030f;
+ 	val_dir[1944*3 + 0] = -0.135526f;	val_dir[1944*3 + 1] = -0.903508f;	val_dir[1944*3 + 2] = 0.406579f;
+ 	val_dir[1945*3 + 0] = -0.113344f;	val_dir[1945*3 + 1] = -0.884083f;	val_dir[1945*3 + 2] = 0.453376f;
+ 	val_dir[1946*3 + 0] = -0.090722f;	val_dir[1946*3 + 1] = -0.861857f;	val_dir[1946*3 + 2] = 0.498970f;
+ 	val_dir[1947*3 + 0] = -0.067867f;	val_dir[1947*3 + 1] = -0.837027f;	val_dir[1947*3 + 2] = 0.542936f;
+ 	val_dir[1948*3 + 0] = -0.044992f;	val_dir[1948*3 + 1] = -0.809858f;	val_dir[1948*3 + 2] = 0.584898f;
+ 	val_dir[1949*3 + 0] = -0.022305f;	val_dir[1949*3 + 1] = -0.780675f;	val_dir[1949*3 + 2] = 0.624540f;
+ 	val_dir[1950*3 + 0] = 0.0f;	val_dir[1950*3 + 1] = -0.749838f;	val_dir[1950*3 + 2] = 0.661622f;
+ 	val_dir[1951*3 + 0] = 0.022417f;	val_dir[1951*3 + 1] = -0.739754f;	val_dir[1951*3 + 2] = 0.672504f;
+ 	val_dir[1952*3 + 0] = 0.045549f;	val_dir[1952*3 + 1] = -0.728780f;	val_dir[1952*3 + 2] = 0.683231f;
+ 	val_dir[1953*3 + 0] = 0.069375f;	val_dir[1953*3 + 1] = -0.716871f;	val_dir[1953*3 + 2] = 0.693746f;
+ 	val_dir[1954*3 + 0] = 0.093865f;	val_dir[1954*3 + 1] = -0.703985f;	val_dir[1954*3 + 2] = 0.703985f;
+ 	val_dir[1955*3 + 0] = 0.118980f;	val_dir[1955*3 + 1] = -0.690085f;	val_dir[1955*3 + 2] = 0.713881f;
+ 	val_dir[1956*3 + 0] = 0.144673f;	val_dir[1956*3 + 1] = -0.675140f;	val_dir[1956*3 + 2] = 0.723364f;
+ 	val_dir[1957*3 + 0] = 0.170884f;	val_dir[1957*3 + 1] = -0.659125f;	val_dir[1957*3 + 2] = 0.732361f;
+ 	val_dir[1958*3 + 0] = 0.197546f;	val_dir[1958*3 + 1] = -0.642024f;	val_dir[1958*3 + 2] = 0.740797f;
+ 	val_dir[1959*3 + 0] = 0.224579f;	val_dir[1959*3 + 1] = -0.623831f;	val_dir[1959*3 + 2] = 0.748598f;
+ 	val_dir[1960*3 + 0] = 0.251896f;	val_dir[1960*3 + 1] = -0.604551f;	val_dir[1960*3 + 2] = 0.755689f;
+ 	val_dir[1961*3 + 0] = 0.27940f;	val_dir[1961*3 + 1] = -0.584201f;	val_dir[1961*3 + 2] = 0.762001f;
+ 	val_dir[1962*3 + 0] = 0.306987f;	val_dir[1962*3 + 1] = -0.562809f;	val_dir[1962*3 + 2] = 0.767467f;
+ 	val_dir[1963*3 + 0] = 0.334545f;	val_dir[1963*3 + 1] = -0.540419f;	val_dir[1963*3 + 2] = 0.772027f;
+ 	val_dir[1964*3 + 0] = 0.361961f;	val_dir[1964*3 + 1] = -0.517088f;	val_dir[1964*3 + 2] = 0.775632f;
+ 	val_dir[1965*3 + 0] = 0.389118f;	val_dir[1965*3 + 1] = -0.492883f;	val_dir[1965*3 + 2] = 0.778237f;
+ 	val_dir[1966*3 + 0] = 0.41590f;	val_dir[1966*3 + 1] = -0.467888f;	val_dir[1966*3 + 2] = 0.779813f;
+ 	val_dir[1967*3 + 0] = 0.442193f;	val_dir[1967*3 + 1] = -0.442193f;	val_dir[1967*3 + 2] = 0.780340f;
+ 	val_dir[1968*3 + 0] = 0.467888f;	val_dir[1968*3 + 1] = -0.41590f;	val_dir[1968*3 + 2] = 0.779813f;
+ 	val_dir[1969*3 + 0] = 0.492883f;	val_dir[1969*3 + 1] = -0.389118f;	val_dir[1969*3 + 2] = 0.778237f;
+ 	val_dir[1970*3 + 0] = 0.517088f;	val_dir[1970*3 + 1] = -0.361961f;	val_dir[1970*3 + 2] = 0.775632f;
+ 	val_dir[1971*3 + 0] = 0.540419f;	val_dir[1971*3 + 1] = -0.334545f;	val_dir[1971*3 + 2] = 0.772027f;
+ 	val_dir[1972*3 + 0] = 0.562809f;	val_dir[1972*3 + 1] = -0.306987f;	val_dir[1972*3 + 2] = 0.767467f;
+ 	val_dir[1973*3 + 0] = 0.584201f;	val_dir[1973*3 + 1] = -0.27940f;	val_dir[1973*3 + 2] = 0.762001f;
+ 	val_dir[1974*3 + 0] = 0.604551f;	val_dir[1974*3 + 1] = -0.251896f;	val_dir[1974*3 + 2] = 0.755689f;
+ 	val_dir[1975*3 + 0] = 0.623831f;	val_dir[1975*3 + 1] = -0.224579f;	val_dir[1975*3 + 2] = 0.748598f;
+ 	val_dir[1976*3 + 0] = 0.642024f;	val_dir[1976*3 + 1] = -0.197546f;	val_dir[1976*3 + 2] = 0.740797f;
+ 	val_dir[1977*3 + 0] = 0.659125f;	val_dir[1977*3 + 1] = -0.170884f;	val_dir[1977*3 + 2] = 0.732361f;
+ 	val_dir[1978*3 + 0] = 0.675140f;	val_dir[1978*3 + 1] = -0.144673f;	val_dir[1978*3 + 2] = 0.723364f;
+ 	val_dir[1979*3 + 0] = 0.690085f;	val_dir[1979*3 + 1] = -0.118980f;	val_dir[1979*3 + 2] = 0.713881f;
+ 	val_dir[1980*3 + 0] = 0.703985f;	val_dir[1980*3 + 1] = -0.093865f;	val_dir[1980*3 + 2] = 0.703985f;
+ 	val_dir[1981*3 + 0] = 0.716871f;	val_dir[1981*3 + 1] = -0.069375f;	val_dir[1981*3 + 2] = 0.693746f;
+ 	val_dir[1982*3 + 0] = 0.728780f;	val_dir[1982*3 + 1] = -0.045549f;	val_dir[1982*3 + 2] = 0.683231f;
+ 	val_dir[1983*3 + 0] = 0.739754f;	val_dir[1983*3 + 1] = -0.022417f;	val_dir[1983*3 + 2] = 0.672504f;
+ 	val_dir[1984*3 + 0] = 0.749838f;	val_dir[1984*3 + 1] = 0.0f;	val_dir[1984*3 + 2] = 0.661622f;
+ 	val_dir[1985*3 + 0] = 0.780675f;	val_dir[1985*3 + 1] = 0.022305f;	val_dir[1985*3 + 2] = 0.624540f;
+ 	val_dir[1986*3 + 0] = 0.809858f;	val_dir[1986*3 + 1] = 0.044992f;	val_dir[1986*3 + 2] = 0.584898f;
+ 	val_dir[1987*3 + 0] = 0.837027f;	val_dir[1987*3 + 1] = 0.067867f;	val_dir[1987*3 + 2] = 0.542936f;
+ 	val_dir[1988*3 + 0] = 0.861857f;	val_dir[1988*3 + 1] = 0.090722f;	val_dir[1988*3 + 2] = 0.498970f;
+ 	val_dir[1989*3 + 0] = 0.884083f;	val_dir[1989*3 + 1] = 0.113344f;	val_dir[1989*3 + 2] = 0.453376f;
+ 	val_dir[1990*3 + 0] = 0.903508f;	val_dir[1990*3 + 1] = 0.135526f;	val_dir[1990*3 + 2] = 0.406579f;
+ 	val_dir[1991*3 + 0] = 0.920014f;	val_dir[1991*3 + 1] = 0.157075f;	val_dir[1991*3 + 2] = 0.359030f;
+ 	val_dir[1992*3 + 0] = 0.933564f;	val_dir[1992*3 + 1] = 0.177822f;	val_dir[1992*3 + 2] = 0.311188f;
+ 	val_dir[1993*3 + 0] = 0.94420f;	val_dir[1993*3 + 1] = 0.197623f;	val_dir[1993*3 + 2] = 0.263498f;
+ 	val_dir[1994*3 + 0] = 0.952033f;	val_dir[1994*3 + 1] = 0.216371f;	val_dir[1994*3 + 2] = 0.216371f;
+ 	val_dir[1995*3 + 0] = 0.957230f;	val_dir[1995*3 + 1] = 0.233990f;	val_dir[1995*3 + 2] = 0.170174f;
+ 	val_dir[1996*3 + 0] = 0.960001f;	val_dir[1996*3 + 1] = 0.250435f;	val_dir[1996*3 + 2] = 0.125218f;
+ 	val_dir[1997*3 + 0] = 0.960585f;	val_dir[1997*3 + 1] = 0.265694f;	val_dir[1997*3 + 2] = 0.081752f;
+ 	val_dir[1998*3 + 0] = 0.959233f;	val_dir[1998*3 + 1] = 0.279776f;	val_dir[1998*3 + 2] = 0.039968f;
+ 	val_dir[1999*3 + 0] = 0.95620f;	val_dir[1999*3 + 1] = 0.292714f;	val_dir[1999*3 + 2] = 0.0f;
+ 	val_dir[2000*3 + 0] = -0.298216f;	val_dir[2000*3 + 1] = -0.954291f;	val_dir[2000*3 + 2] = 0.019881f;
+ 	val_dir[2001*3 + 0] = -0.284944f;	val_dir[2001*3 + 1] = -0.956597f;	val_dir[2001*3 + 2] = 0.061059f;
+ 	val_dir[2002*3 + 0] = -0.270481f;	val_dir[2002*3 + 1] = -0.957088f;	val_dir[2002*3 + 2] = 0.104031f;
+ 	val_dir[2003*3 + 0] = -0.254801f;	val_dir[2003*3 + 1] = -0.955502f;	val_dir[2003*3 + 2] = 0.148634f;
+ 	val_dir[2004*3 + 0] = -0.237897f;	val_dir[2004*3 + 1] = -0.951588f;	val_dir[2004*3 + 2] = 0.194643f;
+ 	val_dir[2005*3 + 0] = -0.219793f;	val_dir[2005*3 + 1] = -0.945112f;	val_dir[2005*3 + 2] = 0.241773f;
+ 	val_dir[2006*3 + 0] = -0.200545f;	val_dir[2006*3 + 1] = -0.935879f;	val_dir[2006*3 + 2] = 0.289677f;
+ 	val_dir[2007*3 + 0] = -0.180242f;	val_dir[2007*3 + 1] = -0.923742f;	val_dir[2007*3 + 2] = 0.337954f;
+ 	val_dir[2008*3 + 0] = -0.159009f;	val_dir[2008*3 + 1] = -0.908622f;	val_dir[2008*3 + 2] = 0.386164f;
+ 	val_dir[2009*3 + 0] = -0.137002f;	val_dir[2009*3 + 1] = -0.890513f;	val_dir[2009*3 + 2] = 0.433840f;
+ 	val_dir[2010*3 + 0] = -0.114407f;	val_dir[2010*3 + 1] = -0.869495f;	val_dir[2010*3 + 2] = 0.480510f;
+ 	val_dir[2011*3 + 0] = -0.091430f;	val_dir[2011*3 + 1] = -0.845728f;	val_dir[2011*3 + 2] = 0.525723f;
+ 	val_dir[2012*3 + 0] = -0.068288f;	val_dir[2012*3 + 1] = -0.819453f;	val_dir[2012*3 + 2] = 0.569064f;
+ 	val_dir[2013*3 + 0] = -0.045198f;	val_dir[2013*3 + 1] = -0.790973f;	val_dir[2013*3 + 2] = 0.610179f;
+ 	val_dir[2014*3 + 0] = -0.022372f;	val_dir[2014*3 + 1] = -0.760644f;	val_dir[2014*3 + 2] = 0.648784f;
+ 	val_dir[2015*3 + 0] = 0.0f;	val_dir[2015*3 + 1] = -0.728848f;	val_dir[2015*3 + 2] = 0.684675f;
+ 	val_dir[2016*3 + 0] = 0.022439f;	val_dir[2016*3 + 1] = -0.718059f;	val_dir[2016*3 + 2] = 0.695620f;
+ 	val_dir[2017*3 + 0] = 0.045572f;	val_dir[2017*3 + 1] = -0.706372f;	val_dir[2017*3 + 2] = 0.706372f;
+ 	val_dir[2018*3 + 0] = 0.069375f;	val_dir[2018*3 + 1] = -0.693746f;	val_dir[2018*3 + 2] = 0.716871f;
+ 	val_dir[2019*3 + 0] = 0.093813f;	val_dir[2019*3 + 1] = -0.680144f;	val_dir[2019*3 + 2] = 0.727051f;
+ 	val_dir[2020*3 + 0] = 0.118846f;	val_dir[2020*3 + 1] = -0.665536f;	val_dir[2020*3 + 2] = 0.736843f;
+ 	val_dir[2021*3 + 0] = 0.144421f;	val_dir[2021*3 + 1] = -0.649895f;	val_dir[2021*3 + 2] = 0.746176f;
+ 	val_dir[2022*3 + 0] = 0.170478f;	val_dir[2022*3 + 1] = -0.633205f;	val_dir[2022*3 + 2] = 0.754976f;
+ 	val_dir[2023*3 + 0] = 0.196946f;	val_dir[2023*3 + 1] = -0.615457f;	val_dir[2023*3 + 2] = 0.763167f;
+ 	val_dir[2024*3 + 0] = 0.223745f;	val_dir[2024*3 + 1] = -0.596653f;	val_dir[2024*3 + 2] = 0.770677f;
+ 	val_dir[2025*3 + 0] = 0.250785f;	val_dir[2025*3 + 1] = -0.576805f;	val_dir[2025*3 + 2] = 0.777433f;
+ 	val_dir[2026*3 + 0] = 0.277969f;	val_dir[2026*3 + 1] = -0.555939f;	val_dir[2026*3 + 2] = 0.783368f;
+ 	val_dir[2027*3 + 0] = 0.305194f;	val_dir[2027*3 + 1] = -0.534090f;	val_dir[2027*3 + 2] = 0.788419f;
+ 	val_dir[2028*3 + 0] = 0.332352f;	val_dir[2028*3 + 1] = -0.511310f;	val_dir[2028*3 + 2] = 0.792530f;
+ 	val_dir[2029*3 + 0] = 0.359329f;	val_dir[2029*3 + 1] = -0.487661f;	val_dir[2029*3 + 2] = 0.795657f;
+ 	val_dir[2030*3 + 0] = 0.386014f;	val_dir[2030*3 + 1] = -0.463217f;	val_dir[2030*3 + 2] = 0.797762f;
+ 	val_dir[2031*3 + 0] = 0.412294f;	val_dir[2031*3 + 1] = -0.438063f;	val_dir[2031*3 + 2] = 0.798820f;
+ 	val_dir[2032*3 + 0] = 0.438063f;	val_dir[2032*3 + 1] = -0.412294f;	val_dir[2032*3 + 2] = 0.798820f;
+ 	val_dir[2033*3 + 0] = 0.463217f;	val_dir[2033*3 + 1] = -0.386014f;	val_dir[2033*3 + 2] = 0.797762f;
+ 	val_dir[2034*3 + 0] = 0.487661f;	val_dir[2034*3 + 1] = -0.359329f;	val_dir[2034*3 + 2] = 0.795657f;
+ 	val_dir[2035*3 + 0] = 0.511310f;	val_dir[2035*3 + 1] = -0.332352f;	val_dir[2035*3 + 2] = 0.792530f;
+ 	val_dir[2036*3 + 0] = 0.534090f;	val_dir[2036*3 + 1] = -0.305194f;	val_dir[2036*3 + 2] = 0.788419f;
+ 	val_dir[2037*3 + 0] = 0.555939f;	val_dir[2037*3 + 1] = -0.277969f;	val_dir[2037*3 + 2] = 0.783368f;
+ 	val_dir[2038*3 + 0] = 0.576805f;	val_dir[2038*3 + 1] = -0.250785f;	val_dir[2038*3 + 2] = 0.777433f;
+ 	val_dir[2039*3 + 0] = 0.596653f;	val_dir[2039*3 + 1] = -0.223745f;	val_dir[2039*3 + 2] = 0.770677f;
+ 	val_dir[2040*3 + 0] = 0.615457f;	val_dir[2040*3 + 1] = -0.196946f;	val_dir[2040*3 + 2] = 0.763167f;
+ 	val_dir[2041*3 + 0] = 0.633205f;	val_dir[2041*3 + 1] = -0.170478f;	val_dir[2041*3 + 2] = 0.754976f;
+ 	val_dir[2042*3 + 0] = 0.649895f;	val_dir[2042*3 + 1] = -0.144421f;	val_dir[2042*3 + 2] = 0.746176f;
+ 	val_dir[2043*3 + 0] = 0.665536f;	val_dir[2043*3 + 1] = -0.118846f;	val_dir[2043*3 + 2] = 0.736843f;
+ 	val_dir[2044*3 + 0] = 0.680144f;	val_dir[2044*3 + 1] = -0.093813f;	val_dir[2044*3 + 2] = 0.727051f;
+ 	val_dir[2045*3 + 0] = 0.693746f;	val_dir[2045*3 + 1] = -0.069375f;	val_dir[2045*3 + 2] = 0.716871f;
+ 	val_dir[2046*3 + 0] = 0.706372f;	val_dir[2046*3 + 1] = -0.045572f;	val_dir[2046*3 + 2] = 0.706372f;
+ 	val_dir[2047*3 + 0] = 0.718059f;	val_dir[2047*3 + 1] = -0.022439f;	val_dir[2047*3 + 2] = 0.695620f;
+ 	val_dir[2048*3 + 0] = 0.728848f;	val_dir[2048*3 + 1] = 0.0f;	val_dir[2048*3 + 2] = 0.684675f;
+ 	val_dir[2049*3 + 0] = 0.760644f;	val_dir[2049*3 + 1] = 0.022372f;	val_dir[2049*3 + 2] = 0.648784f;
+ 	val_dir[2050*3 + 0] = 0.790973f;	val_dir[2050*3 + 1] = 0.045198f;	val_dir[2050*3 + 2] = 0.610179f;
+ 	val_dir[2051*3 + 0] = 0.819453f;	val_dir[2051*3 + 1] = 0.068288f;	val_dir[2051*3 + 2] = 0.569064f;
+ 	val_dir[2052*3 + 0] = 0.845728f;	val_dir[2052*3 + 1] = 0.091430f;	val_dir[2052*3 + 2] = 0.525723f;
+ 	val_dir[2053*3 + 0] = 0.869495f;	val_dir[2053*3 + 1] = 0.114407f;	val_dir[2053*3 + 2] = 0.480510f;
+ 	val_dir[2054*3 + 0] = 0.890513f;	val_dir[2054*3 + 1] = 0.137002f;	val_dir[2054*3 + 2] = 0.433840f;
+ 	val_dir[2055*3 + 0] = 0.908622f;	val_dir[2055*3 + 1] = 0.159009f;	val_dir[2055*3 + 2] = 0.386164f;
+ 	val_dir[2056*3 + 0] = 0.923742f;	val_dir[2056*3 + 1] = 0.180242f;	val_dir[2056*3 + 2] = 0.337954f;
+ 	val_dir[2057*3 + 0] = 0.935879f;	val_dir[2057*3 + 1] = 0.200545f;	val_dir[2057*3 + 2] = 0.289677f;
+ 	val_dir[2058*3 + 0] = 0.945112f;	val_dir[2058*3 + 1] = 0.219793f;	val_dir[2058*3 + 2] = 0.241773f;
+ 	val_dir[2059*3 + 0] = 0.951588f;	val_dir[2059*3 + 1] = 0.237897f;	val_dir[2059*3 + 2] = 0.194643f;
+ 	val_dir[2060*3 + 0] = 0.955502f;	val_dir[2060*3 + 1] = 0.254801f;	val_dir[2060*3 + 2] = 0.148634f;
+ 	val_dir[2061*3 + 0] = 0.957088f;	val_dir[2061*3 + 1] = 0.270481f;	val_dir[2061*3 + 2] = 0.104031f;
+ 	val_dir[2062*3 + 0] = 0.956597f;	val_dir[2062*3 + 1] = 0.284944f;	val_dir[2062*3 + 2] = 0.061059f;
+ 	val_dir[2063*3 + 0] = 0.954291f;	val_dir[2063*3 + 1] = 0.298216f;	val_dir[2063*3 + 2] = 0.019881f;
+ 	val_dir[2064*3 + 0] = -0.316228f;	val_dir[2064*3 + 1] = -0.948683f;	val_dir[2064*3 + 2] = 0.0f;
+ 	val_dir[2065*3 + 0] = -0.303791f;	val_dir[2065*3 + 1] = -0.951877f;	val_dir[2065*3 + 2] = 0.040505f;
+ 	val_dir[2066*3 + 0] = -0.290159f;	val_dir[2066*3 + 1] = -0.953381f;	val_dir[2066*3 + 2] = 0.082903f;
+ 	val_dir[2067*3 + 0] = -0.275290f;	val_dir[2067*3 + 1] = -0.952928f;	val_dir[2067*3 + 2] = 0.127057f;
+ 	val_dir[2068*3 + 0] = -0.259161f;	val_dir[2068*3 + 1] = -0.950255f;	val_dir[2068*3 + 2] = 0.172774f;
+ 	val_dir[2069*3 + 0] = -0.241773f;	val_dir[2069*3 + 1] = -0.945112f;	val_dir[2069*3 + 2] = 0.219793f;
+ 	val_dir[2070*3 + 0] = -0.223161f;	val_dir[2070*3 + 1] = -0.937276f;	val_dir[2070*3 + 2] = 0.267793f;
+ 	val_dir[2071*3 + 0] = -0.203393f;	val_dir[2071*3 + 1] = -0.926568f;	val_dir[2071*3 + 2] = 0.316389f;
+ 	val_dir[2072*3 + 0] = -0.182574f;	val_dir[2072*3 + 1] = -0.912871f;	val_dir[2072*3 + 2] = 0.365148f;
+ 	val_dir[2073*3 + 0] = -0.160845f;	val_dir[2073*3 + 1] = -0.896137f;	val_dir[2073*3 + 2] = 0.413602f;
+ 	val_dir[2074*3 + 0] = -0.138380f;	val_dir[2074*3 + 1] = -0.876405f;	val_dir[2074*3 + 2] = 0.461266f;
+ 	val_dir[2075*3 + 0] = -0.115378f;	val_dir[2075*3 + 1] = -0.853796f;	val_dir[2075*3 + 2] = 0.507662f;
+ 	val_dir[2076*3 + 0] = -0.092057f;	val_dir[2076*3 + 1] = -0.828517f;	val_dir[2076*3 + 2] = 0.552345f;
+ 	val_dir[2077*3 + 0] = -0.068644f;	val_dir[2077*3 + 1] = -0.800850f;	val_dir[2077*3 + 2] = 0.594917f;
+ 	val_dir[2078*3 + 0] = -0.045361f;	val_dir[2078*3 + 1] = -0.771136f;	val_dir[2078*3 + 2] = 0.635053f;
+ 	val_dir[2079*3 + 0] = -0.022417f;	val_dir[2079*3 + 1] = -0.739754f;	val_dir[2079*3 + 2] = 0.672504f;
+ 	val_dir[2080*3 + 0] = 0.0f;	val_dir[2080*3 + 1] = -0.707107f;	val_dir[2080*3 + 2] = 0.707107f;
+ 	val_dir[2081*3 + 0] = 0.022439f;	val_dir[2081*3 + 1] = -0.695620f;	val_dir[2081*3 + 2] = 0.718059f;
+ 	val_dir[2082*3 + 0] = 0.045549f;	val_dir[2082*3 + 1] = -0.683231f;	val_dir[2082*3 + 2] = 0.728780f;
+ 	val_dir[2083*3 + 0] = 0.069301f;	val_dir[2083*3 + 1] = -0.669905f;	val_dir[2083*3 + 2] = 0.739205f;
+ 	val_dir[2084*3 + 0] = 0.093659f;	val_dir[2084*3 + 1] = -0.655610f;	val_dir[2084*3 + 2] = 0.749269f;
+ 	val_dir[2085*3 + 0] = 0.118578f;	val_dir[2085*3 + 1] = -0.640321f;	val_dir[2085*3 + 2] = 0.758899f;
+ 	val_dir[2086*3 + 0] = 0.144005f;	val_dir[2086*3 + 1] = -0.624020f;	val_dir[2086*3 + 2] = 0.768025f;
+ 	val_dir[2087*3 + 0] = 0.169875f;	val_dir[2087*3 + 1] = -0.606696f;	val_dir[2087*3 + 2] = 0.776571f;
+ 	val_dir[2088*3 + 0] = 0.196116f;	val_dir[2088*3 + 1] = -0.588348f;	val_dir[2088*3 + 2] = 0.784465f;
+ 	val_dir[2089*3 + 0] = 0.222647f;	val_dir[2089*3 + 1] = -0.568986f;	val_dir[2089*3 + 2] = 0.791633f;
+ 	val_dir[2090*3 + 0] = 0.249377f;	val_dir[2090*3 + 1] = -0.548630f;	val_dir[2090*3 + 2] = 0.798007f;
+ 	val_dir[2091*3 + 0] = 0.276211f;	val_dir[2091*3 + 1] = -0.527312f;	val_dir[2091*3 + 2] = 0.803523f;
+ 	val_dir[2092*3 + 0] = 0.303046f;	val_dir[2092*3 + 1] = -0.505076f;	val_dir[2092*3 + 2] = 0.808122f;
+ 	val_dir[2093*3 + 0] = 0.329775f;	val_dir[2093*3 + 1] = -0.481979f;	val_dir[2093*3 + 2] = 0.811754f;
+ 	val_dir[2094*3 + 0] = 0.356291f;	val_dir[2094*3 + 1] = -0.458088f;	val_dir[2094*3 + 2] = 0.814379f;
+ 	val_dir[2095*3 + 0] = 0.382484f;	val_dir[2095*3 + 1] = -0.433482f;	val_dir[2095*3 + 2] = 0.815966f;
+ 	val_dir[2096*3 + 0] = 0.408248f;	val_dir[2096*3 + 1] = -0.408248f;	val_dir[2096*3 + 2] = 0.816497f;
+ 	val_dir[2097*3 + 0] = 0.433482f;	val_dir[2097*3 + 1] = -0.382484f;	val_dir[2097*3 + 2] = 0.815966f;
+ 	val_dir[2098*3 + 0] = 0.458088f;	val_dir[2098*3 + 1] = -0.356291f;	val_dir[2098*3 + 2] = 0.814379f;
+ 	val_dir[2099*3 + 0] = 0.481979f;	val_dir[2099*3 + 1] = -0.329775f;	val_dir[2099*3 + 2] = 0.811754f;
+ 	val_dir[2100*3 + 0] = 0.505076f;	val_dir[2100*3 + 1] = -0.303046f;	val_dir[2100*3 + 2] = 0.808122f;
+ 	val_dir[2101*3 + 0] = 0.527312f;	val_dir[2101*3 + 1] = -0.276211f;	val_dir[2101*3 + 2] = 0.803523f;
+ 	val_dir[2102*3 + 0] = 0.548630f;	val_dir[2102*3 + 1] = -0.249377f;	val_dir[2102*3 + 2] = 0.798007f;
+ 	val_dir[2103*3 + 0] = 0.568986f;	val_dir[2103*3 + 1] = -0.222647f;	val_dir[2103*3 + 2] = 0.791633f;
+ 	val_dir[2104*3 + 0] = 0.588348f;	val_dir[2104*3 + 1] = -0.196116f;	val_dir[2104*3 + 2] = 0.784465f;
+ 	val_dir[2105*3 + 0] = 0.606696f;	val_dir[2105*3 + 1] = -0.169875f;	val_dir[2105*3 + 2] = 0.776571f;
+ 	val_dir[2106*3 + 0] = 0.624020f;	val_dir[2106*3 + 1] = -0.144005f;	val_dir[2106*3 + 2] = 0.768025f;
+ 	val_dir[2107*3 + 0] = 0.640321f;	val_dir[2107*3 + 1] = -0.118578f;	val_dir[2107*3 + 2] = 0.758899f;
+ 	val_dir[2108*3 + 0] = 0.655610f;	val_dir[2108*3 + 1] = -0.093659f;	val_dir[2108*3 + 2] = 0.749269f;
+ 	val_dir[2109*3 + 0] = 0.669905f;	val_dir[2109*3 + 1] = -0.069301f;	val_dir[2109*3 + 2] = 0.739205f;
+ 	val_dir[2110*3 + 0] = 0.683231f;	val_dir[2110*3 + 1] = -0.045549f;	val_dir[2110*3 + 2] = 0.728780f;
+ 	val_dir[2111*3 + 0] = 0.695620f;	val_dir[2111*3 + 1] = -0.022439f;	val_dir[2111*3 + 2] = 0.718059f;
+ 	val_dir[2112*3 + 0] = 0.707107f;	val_dir[2112*3 + 1] = 0.0f;	val_dir[2112*3 + 2] = 0.707107f;
+ 	val_dir[2113*3 + 0] = 0.739754f;	val_dir[2113*3 + 1] = 0.022417f;	val_dir[2113*3 + 2] = 0.672504f;
+ 	val_dir[2114*3 + 0] = 0.771136f;	val_dir[2114*3 + 1] = 0.045361f;	val_dir[2114*3 + 2] = 0.635053f;
+ 	val_dir[2115*3 + 0] = 0.800850f;	val_dir[2115*3 + 1] = 0.068644f;	val_dir[2115*3 + 2] = 0.594917f;
+ 	val_dir[2116*3 + 0] = 0.828517f;	val_dir[2116*3 + 1] = 0.092057f;	val_dir[2116*3 + 2] = 0.552345f;
+ 	val_dir[2117*3 + 0] = 0.853796f;	val_dir[2117*3 + 1] = 0.115378f;	val_dir[2117*3 + 2] = 0.507662f;
+ 	val_dir[2118*3 + 0] = 0.876405f;	val_dir[2118*3 + 1] = 0.138380f;	val_dir[2118*3 + 2] = 0.461266f;
+ 	val_dir[2119*3 + 0] = 0.896137f;	val_dir[2119*3 + 1] = 0.160845f;	val_dir[2119*3 + 2] = 0.413602f;
+ 	val_dir[2120*3 + 0] = 0.912871f;	val_dir[2120*3 + 1] = 0.182574f;	val_dir[2120*3 + 2] = 0.365148f;
+ 	val_dir[2121*3 + 0] = 0.926568f;	val_dir[2121*3 + 1] = 0.203393f;	val_dir[2121*3 + 2] = 0.316389f;
+ 	val_dir[2122*3 + 0] = 0.937276f;	val_dir[2122*3 + 1] = 0.223161f;	val_dir[2122*3 + 2] = 0.267793f;
+ 	val_dir[2123*3 + 0] = 0.945112f;	val_dir[2123*3 + 1] = 0.241773f;	val_dir[2123*3 + 2] = 0.219793f;
+ 	val_dir[2124*3 + 0] = 0.950255f;	val_dir[2124*3 + 1] = 0.259161f;	val_dir[2124*3 + 2] = 0.172774f;
+ 	val_dir[2125*3 + 0] = 0.952928f;	val_dir[2125*3 + 1] = 0.275290f;	val_dir[2125*3 + 2] = 0.127057f;
+ 	val_dir[2126*3 + 0] = 0.953381f;	val_dir[2126*3 + 1] = 0.290159f;	val_dir[2126*3 + 2] = 0.082903f;
+ 	val_dir[2127*3 + 0] = 0.951877f;	val_dir[2127*3 + 1] = 0.303791f;	val_dir[2127*3 + 2] = 0.040505f;
+ 	val_dir[2128*3 + 0] = 0.948683f;	val_dir[2128*3 + 1] = 0.316228f;	val_dir[2128*3 + 2] = 0.0f;
+ 	val_dir[2129*3 + 0] = -0.322198f;	val_dir[2129*3 + 1] = -0.946458f;	val_dir[2129*3 + 2] = 0.020137f;
+ 	val_dir[2130*3 + 0] = -0.309426f;	val_dir[2130*3 + 1] = -0.948908f;	val_dir[2130*3 + 2] = 0.061885f;
+ 	val_dir[2131*3 + 0] = -0.295409f;	val_dir[2131*3 + 1] = -0.949528f;	val_dir[2131*3 + 2] = 0.105503f;
+ 	val_dir[2132*3 + 0] = -0.280105f;	val_dir[2132*3 + 1] = -0.948047f;	val_dir[2132*3 + 2] = 0.150826f;
+ 	val_dir[2133*3 + 0] = -0.263498f;	val_dir[2133*3 + 1] = -0.94420f;	val_dir[2133*3 + 2] = 0.197623f;
+ 	val_dir[2134*3 + 0] = -0.245599f;	val_dir[2134*3 + 1] = -0.937743f;	val_dir[2134*3 + 2] = 0.245599f;
+ 	val_dir[2135*3 + 0] = -0.226455f;	val_dir[2135*3 + 1] = -0.928467f;	val_dir[2135*3 + 2] = 0.294392f;
+ 	val_dir[2136*3 + 0] = -0.206149f;	val_dir[2136*3 + 1] = -0.916217f;	val_dir[2136*3 + 2] = 0.343582f;
+ 	val_dir[2137*3 + 0] = -0.184801f;	val_dir[2137*3 + 1] = -0.900907f;	val_dir[2137*3 + 2] = 0.392703f;
+ 	val_dir[2138*3 + 0] = -0.162571f;	val_dir[2138*3 + 1] = -0.882528f;	val_dir[2138*3 + 2] = 0.441264f;
+ 	val_dir[2139*3 + 0] = -0.139648f;	val_dir[2139*3 + 1] = -0.861164f;	val_dir[2139*3 + 2] = 0.488769f;
+ 	val_dir[2140*3 + 0] = -0.116248f;	val_dir[2140*3 + 1] = -0.836983f;	val_dir[2140*3 + 2] = 0.534739f;
+ 	val_dir[2141*3 + 0] = -0.092599f;	val_dir[2141*3 + 1] = -0.810237f;	val_dir[2141*3 + 2] = 0.578741f;
+ 	val_dir[2142*3 + 0] = -0.068934f;	val_dir[2142*3 + 1] = -0.781248f;	val_dir[2142*3 + 2] = 0.620403f;
+ 	val_dir[2143*3 + 0] = -0.045478f;	val_dir[2143*3 + 1] = -0.750388f;	val_dir[2143*3 + 2] = 0.659432f;
+ 	val_dir[2144*3 + 0] = -0.022439f;	val_dir[2144*3 + 1] = -0.718059f;	val_dir[2144*3 + 2] = 0.695620f;
+ 	val_dir[2145*3 + 0] = 0.0f;	val_dir[2145*3 + 1] = -0.684675f;	val_dir[2145*3 + 2] = 0.728848f;
+ 	val_dir[2146*3 + 0] = 0.022417f;	val_dir[2146*3 + 1] = -0.672504f;	val_dir[2146*3 + 2] = 0.739754f;
+ 	val_dir[2147*3 + 0] = 0.045478f;	val_dir[2147*3 + 1] = -0.659432f;	val_dir[2147*3 + 2] = 0.750388f;
+ 	val_dir[2148*3 + 0] = 0.069153f;	val_dir[2148*3 + 1] = -0.645429f;	val_dir[2148*3 + 2] = 0.760684f;
+ 	val_dir[2149*3 + 0] = 0.093403f;	val_dir[2149*3 + 1] = -0.630470f;	val_dir[2149*3 + 2] = 0.770574f;
+ 	val_dir[2150*3 + 0] = 0.118180f;	val_dir[2150*3 + 1] = -0.614535f;	val_dir[2150*3 + 2] = 0.779987f;
+ 	val_dir[2151*3 + 0] = 0.143427f;	val_dir[2151*3 + 1] = -0.597614f;	val_dir[2151*3 + 2] = 0.788851f;
+ 	val_dir[2152*3 + 0] = 0.169080f;	val_dir[2152*3 + 1] = -0.579703f;	val_dir[2152*3 + 2] = 0.797092f;
+ 	val_dir[2153*3 + 0] = 0.195064f;	val_dir[2153*3 + 1] = -0.560809f;	val_dir[2153*3 + 2] = 0.804639f;
+ 	val_dir[2154*3 + 0] = 0.221297f;	val_dir[2154*3 + 1] = -0.540947f;	val_dir[2154*3 + 2] = 0.811421f;
+ 	val_dir[2155*3 + 0] = 0.247689f;	val_dir[2155*3 + 1] = -0.520146f;	val_dir[2155*3 + 2] = 0.817373f;
+ 	val_dir[2156*3 + 0] = 0.274145f;	val_dir[2156*3 + 1] = -0.498445f;	val_dir[2156*3 + 2] = 0.822434f;
+ 	val_dir[2157*3 + 0] = 0.300564f;	val_dir[2157*3 + 1] = -0.475893f;	val_dir[2157*3 + 2] = 0.826551f;
+ 	val_dir[2158*3 + 0] = 0.326844f;	val_dir[2158*3 + 1] = -0.452553f;	val_dir[2158*3 + 2] = 0.829680f;
+ 	val_dir[2159*3 + 0] = 0.352879f;	val_dir[2159*3 + 1] = -0.428496f;	val_dir[2159*3 + 2] = 0.831786f;
+ 	val_dir[2160*3 + 0] = 0.378566f;	val_dir[2160*3 + 1] = -0.403804f;	val_dir[2160*3 + 2] = 0.832845f;
+ 	val_dir[2161*3 + 0] = 0.403804f;	val_dir[2161*3 + 1] = -0.378566f;	val_dir[2161*3 + 2] = 0.832845f;
+ 	val_dir[2162*3 + 0] = 0.428496f;	val_dir[2162*3 + 1] = -0.352879f;	val_dir[2162*3 + 2] = 0.831786f;
+ 	val_dir[2163*3 + 0] = 0.452553f;	val_dir[2163*3 + 1] = -0.326844f;	val_dir[2163*3 + 2] = 0.829680f;
+ 	val_dir[2164*3 + 0] = 0.475893f;	val_dir[2164*3 + 1] = -0.300564f;	val_dir[2164*3 + 2] = 0.826551f;
+ 	val_dir[2165*3 + 0] = 0.498445f;	val_dir[2165*3 + 1] = -0.274145f;	val_dir[2165*3 + 2] = 0.822434f;
+ 	val_dir[2166*3 + 0] = 0.520146f;	val_dir[2166*3 + 1] = -0.247689f;	val_dir[2166*3 + 2] = 0.817373f;
+ 	val_dir[2167*3 + 0] = 0.540947f;	val_dir[2167*3 + 1] = -0.221297f;	val_dir[2167*3 + 2] = 0.811421f;
+ 	val_dir[2168*3 + 0] = 0.560809f;	val_dir[2168*3 + 1] = -0.195064f;	val_dir[2168*3 + 2] = 0.804639f;
+ 	val_dir[2169*3 + 0] = 0.579703f;	val_dir[2169*3 + 1] = -0.169080f;	val_dir[2169*3 + 2] = 0.797092f;
+ 	val_dir[2170*3 + 0] = 0.597614f;	val_dir[2170*3 + 1] = -0.143427f;	val_dir[2170*3 + 2] = 0.788851f;
+ 	val_dir[2171*3 + 0] = 0.614535f;	val_dir[2171*3 + 1] = -0.118180f;	val_dir[2171*3 + 2] = 0.779987f;
+ 	val_dir[2172*3 + 0] = 0.630470f;	val_dir[2172*3 + 1] = -0.093403f;	val_dir[2172*3 + 2] = 0.770574f;
+ 	val_dir[2173*3 + 0] = 0.645429f;	val_dir[2173*3 + 1] = -0.069153f;	val_dir[2173*3 + 2] = 0.760684f;
+ 	val_dir[2174*3 + 0] = 0.659432f;	val_dir[2174*3 + 1] = -0.045478f;	val_dir[2174*3 + 2] = 0.750388f;
+ 	val_dir[2175*3 + 0] = 0.672504f;	val_dir[2175*3 + 1] = -0.022417f;	val_dir[2175*3 + 2] = 0.739754f;
+ 	val_dir[2176*3 + 0] = 0.684675f;	val_dir[2176*3 + 1] = 0.0f;	val_dir[2176*3 + 2] = 0.728848f;
+ 	val_dir[2177*3 + 0] = 0.718059f;	val_dir[2177*3 + 1] = 0.022439f;	val_dir[2177*3 + 2] = 0.695620f;
+ 	val_dir[2178*3 + 0] = 0.750388f;	val_dir[2178*3 + 1] = 0.045478f;	val_dir[2178*3 + 2] = 0.659432f;
+ 	val_dir[2179*3 + 0] = 0.781248f;	val_dir[2179*3 + 1] = 0.068934f;	val_dir[2179*3 + 2] = 0.620403f;
+ 	val_dir[2180*3 + 0] = 0.810237f;	val_dir[2180*3 + 1] = 0.092599f;	val_dir[2180*3 + 2] = 0.578741f;
+ 	val_dir[2181*3 + 0] = 0.836983f;	val_dir[2181*3 + 1] = 0.116248f;	val_dir[2181*3 + 2] = 0.534739f;
+ 	val_dir[2182*3 + 0] = 0.861164f;	val_dir[2182*3 + 1] = 0.139648f;	val_dir[2182*3 + 2] = 0.488769f;
+ 	val_dir[2183*3 + 0] = 0.882528f;	val_dir[2183*3 + 1] = 0.162571f;	val_dir[2183*3 + 2] = 0.441264f;
+ 	val_dir[2184*3 + 0] = 0.900907f;	val_dir[2184*3 + 1] = 0.184801f;	val_dir[2184*3 + 2] = 0.392703f;
+ 	val_dir[2185*3 + 0] = 0.916217f;	val_dir[2185*3 + 1] = 0.206149f;	val_dir[2185*3 + 2] = 0.343582f;
+ 	val_dir[2186*3 + 0] = 0.928467f;	val_dir[2186*3 + 1] = 0.226455f;	val_dir[2186*3 + 2] = 0.294392f;
+ 	val_dir[2187*3 + 0] = 0.937743f;	val_dir[2187*3 + 1] = 0.245599f;	val_dir[2187*3 + 2] = 0.245599f;
+ 	val_dir[2188*3 + 0] = 0.94420f;	val_dir[2188*3 + 1] = 0.263498f;	val_dir[2188*3 + 2] = 0.197623f;
+ 	val_dir[2189*3 + 0] = 0.948047f;	val_dir[2189*3 + 1] = 0.280105f;	val_dir[2189*3 + 2] = 0.150826f;
+ 	val_dir[2190*3 + 0] = 0.949528f;	val_dir[2190*3 + 1] = 0.295409f;	val_dir[2190*3 + 2] = 0.105503f;
+ 	val_dir[2191*3 + 0] = 0.948908f;	val_dir[2191*3 + 1] = 0.309426f;	val_dir[2191*3 + 2] = 0.061885f;
+ 	val_dir[2192*3 + 0] = 0.946458f;	val_dir[2192*3 + 1] = 0.322198f;	val_dir[2192*3 + 2] = 0.020137f;
+ 	val_dir[2193*3 + 0] = -0.340136f;	val_dir[2193*3 + 1] = -0.940376f;	val_dir[2193*3 + 2] = 0.0f;
+ 	val_dir[2194*3 + 0] = -0.328244f;	val_dir[2194*3 + 1] = -0.943701f;	val_dir[2194*3 + 2] = 0.041030f;
+ 	val_dir[2195*3 + 0] = -0.315109f;	val_dir[2195*3 + 1] = -0.945328f;	val_dir[2195*3 + 2] = 0.084029f;
+ 	val_dir[2196*3 + 0] = -0.300676f;	val_dir[2196*3 + 1] = -0.944981f;	val_dir[2196*3 + 2] = 0.128861f;
+ 	val_dir[2197*3 + 0] = -0.284907f;	val_dir[2197*3 + 1] = -0.942384f;	val_dir[2197*3 + 2] = 0.175327f;
+ 	val_dir[2198*3 + 0] = -0.267793f;	val_dir[2198*3 + 1] = -0.937276f;	val_dir[2198*3 + 2] = 0.223161f;
+ 	val_dir[2199*3 + 0] = -0.249357f;	val_dir[2199*3 + 1] = -0.929421f;	val_dir[2199*3 + 2] = 0.272026f;
+ 	val_dir[2200*3 + 0] = -0.229658f;	val_dir[2200*3 + 1] = -0.918630f;	val_dir[2200*3 + 2] = 0.321521f;
+ 	val_dir[2201*3 + 0] = -0.208795f;	val_dir[2201*3 + 1] = -0.904777f;	val_dir[2201*3 + 2] = 0.371191f;
+ 	val_dir[2202*3 + 0] = -0.186908f;	val_dir[2202*3 + 1] = -0.887812f;	val_dir[2202*3 + 2] = 0.420542f;
+ 	val_dir[2203*3 + 0] = -0.164173f;	val_dir[2203*3 + 1] = -0.867770f;	val_dir[2203*3 + 2] = 0.469065f;
+ 	val_dir[2204*3 + 0] = -0.140797f;	val_dir[2204*3 + 1] = -0.844782f;	val_dir[2204*3 + 2] = 0.516256f;
+ 	val_dir[2205*3 + 0] = -0.117009f;	val_dir[2205*3 + 1] = -0.819064f;	val_dir[2205*3 + 2] = 0.561644f;
+ 	val_dir[2206*3 + 0] = -0.093048f;	val_dir[2206*3 + 1] = -0.790912f;	val_dir[2206*3 + 2] = 0.604815f;
+ 	val_dir[2207*3 + 0] = -0.069153f;	val_dir[2207*3 + 1] = -0.760684f;	val_dir[2207*3 + 2] = 0.645429f;
+ 	val_dir[2208*3 + 0] = -0.045549f;	val_dir[2208*3 + 1] = -0.728780f;	val_dir[2208*3 + 2] = 0.683231f;
+ 	val_dir[2209*3 + 0] = -0.022439f;	val_dir[2209*3 + 1] = -0.695620f;	val_dir[2209*3 + 2] = 0.718059f;
+ 	val_dir[2210*3 + 0] = 0.0f;	val_dir[2210*3 + 1] = -0.661622f;	val_dir[2210*3 + 2] = 0.749838f;
+ 	val_dir[2211*3 + 0] = 0.022372f;	val_dir[2211*3 + 1] = -0.648784f;	val_dir[2211*3 + 2] = 0.760644f;
+ 	val_dir[2212*3 + 0] = 0.045361f;	val_dir[2212*3 + 1] = -0.635053f;	val_dir[2212*3 + 2] = 0.771136f;
+ 	val_dir[2213*3 + 0] = 0.068934f;	val_dir[2213*3 + 1] = -0.620403f;	val_dir[2213*3 + 2] = 0.781248f;
+ 	val_dir[2214*3 + 0] = 0.093048f;	val_dir[2214*3 + 1] = -0.604815f;	val_dir[2214*3 + 2] = 0.790912f;
+ 	val_dir[2215*3 + 0] = 0.117655f;	val_dir[2215*3 + 1] = -0.588276f;	val_dir[2215*3 + 2] = 0.800055f;
+ 	val_dir[2216*3 + 0] = 0.142695f;	val_dir[2216*3 + 1] = -0.570782f;	val_dir[2216*3 + 2] = 0.808608f;
+ 	val_dir[2217*3 + 0] = 0.168102f;	val_dir[2217*3 + 1] = -0.552336f;	val_dir[2217*3 + 2] = 0.816497f;
+ 	val_dir[2218*3 + 0] = 0.193801f;	val_dir[2218*3 + 1] = -0.532952f;	val_dir[2218*3 + 2] = 0.823653f;
+ 	val_dir[2219*3 + 0] = 0.219708f;	val_dir[2219*3 + 1] = -0.512653f;	val_dir[2219*3 + 2] = 0.830009f;
+ 	val_dir[2220*3 + 0] = 0.245737f;	val_dir[2220*3 + 1] = -0.491473f;	val_dir[2220*3 + 2] = 0.835504f;
+ 	val_dir[2221*3 + 0] = 0.271791f;	val_dir[2221*3 + 1] = -0.469458f;	val_dir[2221*3 + 2] = 0.840083f;
+ 	val_dir[2222*3 + 0] = 0.297775f;	val_dir[2222*3 + 1] = -0.446662f;	val_dir[2222*3 + 2] = 0.843696f;
+ 	val_dir[2223*3 + 0] = 0.323587f;	val_dir[2223*3 + 1] = -0.423153f;	val_dir[2223*3 + 2] = 0.846305f;
+ 	val_dir[2224*3 + 0] = 0.349128f;	val_dir[2224*3 + 1] = -0.399004f;	val_dir[2224*3 + 2] = 0.847883f;
+ 	val_dir[2225*3 + 0] = 0.374299f;	val_dir[2225*3 + 1] = -0.374299f;	val_dir[2225*3 + 2] = 0.848411f;
+ 	val_dir[2226*3 + 0] = 0.399004f;	val_dir[2226*3 + 1] = -0.349128f;	val_dir[2226*3 + 2] = 0.847883f;
+ 	val_dir[2227*3 + 0] = 0.423153f;	val_dir[2227*3 + 1] = -0.323587f;	val_dir[2227*3 + 2] = 0.846305f;
+ 	val_dir[2228*3 + 0] = 0.446662f;	val_dir[2228*3 + 1] = -0.297775f;	val_dir[2228*3 + 2] = 0.843696f;
+ 	val_dir[2229*3 + 0] = 0.469458f;	val_dir[2229*3 + 1] = -0.271791f;	val_dir[2229*3 + 2] = 0.840083f;
+ 	val_dir[2230*3 + 0] = 0.491473f;	val_dir[2230*3 + 1] = -0.245737f;	val_dir[2230*3 + 2] = 0.835504f;
+ 	val_dir[2231*3 + 0] = 0.512653f;	val_dir[2231*3 + 1] = -0.219708f;	val_dir[2231*3 + 2] = 0.830009f;
+ 	val_dir[2232*3 + 0] = 0.532952f;	val_dir[2232*3 + 1] = -0.193801f;	val_dir[2232*3 + 2] = 0.823653f;
+ 	val_dir[2233*3 + 0] = 0.552336f;	val_dir[2233*3 + 1] = -0.168102f;	val_dir[2233*3 + 2] = 0.816497f;
+ 	val_dir[2234*3 + 0] = 0.570782f;	val_dir[2234*3 + 1] = -0.142695f;	val_dir[2234*3 + 2] = 0.808608f;
+ 	val_dir[2235*3 + 0] = 0.588276f;	val_dir[2235*3 + 1] = -0.117655f;	val_dir[2235*3 + 2] = 0.800055f;
+ 	val_dir[2236*3 + 0] = 0.604815f;	val_dir[2236*3 + 1] = -0.093048f;	val_dir[2236*3 + 2] = 0.790912f;
+ 	val_dir[2237*3 + 0] = 0.620403f;	val_dir[2237*3 + 1] = -0.068934f;	val_dir[2237*3 + 2] = 0.781248f;
+ 	val_dir[2238*3 + 0] = 0.635053f;	val_dir[2238*3 + 1] = -0.045361f;	val_dir[2238*3 + 2] = 0.771136f;
+ 	val_dir[2239*3 + 0] = 0.648784f;	val_dir[2239*3 + 1] = -0.022372f;	val_dir[2239*3 + 2] = 0.760644f;
+ 	val_dir[2240*3 + 0] = 0.661622f;	val_dir[2240*3 + 1] = 0.0f;	val_dir[2240*3 + 2] = 0.749838f;
+ 	val_dir[2241*3 + 0] = 0.695620f;	val_dir[2241*3 + 1] = 0.022439f;	val_dir[2241*3 + 2] = 0.718059f;
+ 	val_dir[2242*3 + 0] = 0.728780f;	val_dir[2242*3 + 1] = 0.045549f;	val_dir[2242*3 + 2] = 0.683231f;
+ 	val_dir[2243*3 + 0] = 0.760684f;	val_dir[2243*3 + 1] = 0.069153f;	val_dir[2243*3 + 2] = 0.645429f;
+ 	val_dir[2244*3 + 0] = 0.790912f;	val_dir[2244*3 + 1] = 0.093048f;	val_dir[2244*3 + 2] = 0.604815f;
+ 	val_dir[2245*3 + 0] = 0.819064f;	val_dir[2245*3 + 1] = 0.117009f;	val_dir[2245*3 + 2] = 0.561644f;
+ 	val_dir[2246*3 + 0] = 0.844782f;	val_dir[2246*3 + 1] = 0.140797f;	val_dir[2246*3 + 2] = 0.516256f;
+ 	val_dir[2247*3 + 0] = 0.867770f;	val_dir[2247*3 + 1] = 0.164173f;	val_dir[2247*3 + 2] = 0.469065f;
+ 	val_dir[2248*3 + 0] = 0.887812f;	val_dir[2248*3 + 1] = 0.186908f;	val_dir[2248*3 + 2] = 0.420542f;
+ 	val_dir[2249*3 + 0] = 0.904777f;	val_dir[2249*3 + 1] = 0.208795f;	val_dir[2249*3 + 2] = 0.371191f;
+ 	val_dir[2250*3 + 0] = 0.918630f;	val_dir[2250*3 + 1] = 0.229658f;	val_dir[2250*3 + 2] = 0.321521f;
+ 	val_dir[2251*3 + 0] = 0.929421f;	val_dir[2251*3 + 1] = 0.249357f;	val_dir[2251*3 + 2] = 0.272026f;
+ 	val_dir[2252*3 + 0] = 0.937276f;	val_dir[2252*3 + 1] = 0.267793f;	val_dir[2252*3 + 2] = 0.223161f;
+ 	val_dir[2253*3 + 0] = 0.942384f;	val_dir[2253*3 + 1] = 0.284907f;	val_dir[2253*3 + 2] = 0.175327f;
+ 	val_dir[2254*3 + 0] = 0.944981f;	val_dir[2254*3 + 1] = 0.300676f;	val_dir[2254*3 + 2] = 0.128861f;
+ 	val_dir[2255*3 + 0] = 0.945328f;	val_dir[2255*3 + 1] = 0.315109f;	val_dir[2255*3 + 2] = 0.084029f;
+ 	val_dir[2256*3 + 0] = 0.943701f;	val_dir[2256*3 + 1] = 0.328244f;	val_dir[2256*3 + 2] = 0.041030f;
+ 	val_dir[2257*3 + 0] = 0.940376f;	val_dir[2257*3 + 1] = 0.340136f;	val_dir[2257*3 + 2] = 0.0f;
+ 	val_dir[2258*3 + 0] = -0.346578f;	val_dir[2258*3 + 1] = -0.93780f;	val_dir[2258*3 + 2] = 0.020387f;
+ 	val_dir[2259*3 + 0] = -0.334351f;	val_dir[2259*3 + 1] = -0.940361f;	val_dir[2259*3 + 2] = 0.062691f;
+ 	val_dir[2260*3 + 0] = -0.320824f;	val_dir[2260*3 + 1] = -0.941082f;	val_dir[2260*3 + 2] = 0.106941f;
+ 	val_dir[2261*3 + 0] = -0.305942f;	val_dir[2261*3 + 1] = -0.939680f;	val_dir[2261*3 + 2] = 0.152971f;
+ 	val_dir[2262*3 + 0] = -0.289677f;	val_dir[2262*3 + 1] = -0.935879f;	val_dir[2262*3 + 2] = 0.200545f;
+ 	val_dir[2263*3 + 0] = -0.272026f;	val_dir[2263*3 + 1] = -0.929421f;	val_dir[2263*3 + 2] = 0.249357f;
+ 	val_dir[2264*3 + 0] = -0.253024f;	val_dir[2264*3 + 1] = -0.920087f;	val_dir[2264*3 + 2] = 0.299028f;
+ 	val_dir[2265*3 + 0] = -0.232747f;	val_dir[2265*3 + 1] = -0.907713f;	val_dir[2265*3 + 2] = 0.349121f;
+ 	val_dir[2266*3 + 0] = -0.211312f;	val_dir[2266*3 + 1] = -0.892206f;	val_dir[2266*3 + 2] = 0.399145f;
+ 	val_dir[2267*3 + 0] = -0.188877f;	val_dir[2267*3 + 1] = -0.873555f;	val_dir[2267*3 + 2] = 0.448583f;
+ 	val_dir[2268*3 + 0] = -0.165637f;	val_dir[2268*3 + 1] = -0.851847f;	val_dir[2268*3 + 2] = 0.496911f;
+ 	val_dir[2269*3 + 0] = -0.141816f;	val_dir[2269*3 + 1] = -0.827259f;	val_dir[2269*3 + 2] = 0.543627f;
+ 	val_dir[2270*3 + 0] = -0.117655f;	val_dir[2270*3 + 1] = -0.800055f;	val_dir[2270*3 + 2] = 0.588276f;
+ 	val_dir[2271*3 + 0] = -0.093403f;	val_dir[2271*3 + 1] = -0.770574f;	val_dir[2271*3 + 2] = 0.630470f;
+ 	val_dir[2272*3 + 0] = -0.069301f;	val_dir[2272*3 + 1] = -0.739205f;	val_dir[2272*3 + 2] = 0.669905f;
+ 	val_dir[2273*3 + 0] = -0.045572f;	val_dir[2273*3 + 1] = -0.706372f;	val_dir[2273*3 + 2] = 0.706372f;
+ 	val_dir[2274*3 + 0] = -0.022417f;	val_dir[2274*3 + 1] = -0.672504f;	val_dir[2274*3 + 2] = 0.739754f;
+ 	val_dir[2275*3 + 0] = 0.0f;	val_dir[2275*3 + 1] = -0.638018f;	val_dir[2275*3 + 2] = 0.770022f;
+ 	val_dir[2276*3 + 0] = 0.022305f;	val_dir[2276*3 + 1] = -0.624540f;	val_dir[2276*3 + 2] = 0.780675f;
+ 	val_dir[2277*3 + 0] = 0.045198f;	val_dir[2277*3 + 1] = -0.610179f;	val_dir[2277*3 + 2] = 0.790973f;
+ 	val_dir[2278*3 + 0] = 0.068644f;	val_dir[2278*3 + 1] = -0.594917f;	val_dir[2278*3 + 2] = 0.800850f;
+ 	val_dir[2279*3 + 0] = 0.092599f;	val_dir[2279*3 + 1] = -0.578741f;	val_dir[2279*3 + 2] = 0.810237f;
+ 	val_dir[2280*3 + 0] = 0.117009f;	val_dir[2280*3 + 1] = -0.561644f;	val_dir[2280*3 + 2] = 0.819064f;
+ 	val_dir[2281*3 + 0] = 0.141816f;	val_dir[2281*3 + 1] = -0.543627f;	val_dir[2281*3 + 2] = 0.827259f;
+ 	val_dir[2282*3 + 0] = 0.166951f;	val_dir[2282*3 + 1] = -0.524703f;	val_dir[2282*3 + 2] = 0.834754f;
+ 	val_dir[2283*3 + 0] = 0.192339f;	val_dir[2283*3 + 1] = -0.504889f;	val_dir[2283*3 + 2] = 0.841482f;
+ 	val_dir[2284*3 + 0] = 0.217898f;	val_dir[2284*3 + 1] = -0.484217f;	val_dir[2284*3 + 2] = 0.847381f;
+ 	val_dir[2285*3 + 0] = 0.243541f;	val_dir[2285*3 + 1] = -0.462727f;	val_dir[2285*3 + 2] = 0.852392f;
+ 	val_dir[2286*3 + 0] = 0.269175f;	val_dir[2286*3 + 1] = -0.440468f;	val_dir[2286*3 + 2] = 0.856465f;
+ 	val_dir[2287*3 + 0] = 0.294706f;	val_dir[2287*3 + 1] = -0.41750f;	val_dir[2287*3 + 2] = 0.859559f;
+ 	val_dir[2288*3 + 0] = 0.320038f;	val_dir[2288*3 + 1] = -0.393893f;	val_dir[2288*3 + 2] = 0.861640f;
+ 	val_dir[2289*3 + 0] = 0.345075f;	val_dir[2289*3 + 1] = -0.369723f;	val_dir[2289*3 + 2] = 0.862687f;
+ 	val_dir[2290*3 + 0] = 0.369723f;	val_dir[2290*3 + 1] = -0.345075f;	val_dir[2290*3 + 2] = 0.862687f;
+ 	val_dir[2291*3 + 0] = 0.393893f;	val_dir[2291*3 + 1] = -0.320038f;	val_dir[2291*3 + 2] = 0.861640f;
+ 	val_dir[2292*3 + 0] = 0.41750f;	val_dir[2292*3 + 1] = -0.294706f;	val_dir[2292*3 + 2] = 0.859559f;
+ 	val_dir[2293*3 + 0] = 0.440468f;	val_dir[2293*3 + 1] = -0.269175f;	val_dir[2293*3 + 2] = 0.856465f;
+ 	val_dir[2294*3 + 0] = 0.462727f;	val_dir[2294*3 + 1] = -0.243541f;	val_dir[2294*3 + 2] = 0.852392f;
+ 	val_dir[2295*3 + 0] = 0.484217f;	val_dir[2295*3 + 1] = -0.217898f;	val_dir[2295*3 + 2] = 0.847381f;
+ 	val_dir[2296*3 + 0] = 0.504889f;	val_dir[2296*3 + 1] = -0.192339f;	val_dir[2296*3 + 2] = 0.841482f;
+ 	val_dir[2297*3 + 0] = 0.524703f;	val_dir[2297*3 + 1] = -0.166951f;	val_dir[2297*3 + 2] = 0.834754f;
+ 	val_dir[2298*3 + 0] = 0.543627f;	val_dir[2298*3 + 1] = -0.141816f;	val_dir[2298*3 + 2] = 0.827259f;
+ 	val_dir[2299*3 + 0] = 0.561644f;	val_dir[2299*3 + 1] = -0.117009f;	val_dir[2299*3 + 2] = 0.819064f;
+ 	val_dir[2300*3 + 0] = 0.578741f;	val_dir[2300*3 + 1] = -0.092599f;	val_dir[2300*3 + 2] = 0.810237f;
+ 	val_dir[2301*3 + 0] = 0.594917f;	val_dir[2301*3 + 1] = -0.068644f;	val_dir[2301*3 + 2] = 0.800850f;
+ 	val_dir[2302*3 + 0] = 0.610179f;	val_dir[2302*3 + 1] = -0.045198f;	val_dir[2302*3 + 2] = 0.790973f;
+ 	val_dir[2303*3 + 0] = 0.624540f;	val_dir[2303*3 + 1] = -0.022305f;	val_dir[2303*3 + 2] = 0.780675f;
+ 	val_dir[2304*3 + 0] = 0.638018f;	val_dir[2304*3 + 1] = 0.0f;	val_dir[2304*3 + 2] = 0.770022f;
+ 	val_dir[2305*3 + 0] = 0.672504f;	val_dir[2305*3 + 1] = 0.022417f;	val_dir[2305*3 + 2] = 0.739754f;
+ 	val_dir[2306*3 + 0] = 0.706372f;	val_dir[2306*3 + 1] = 0.045572f;	val_dir[2306*3 + 2] = 0.706372f;
+ 	val_dir[2307*3 + 0] = 0.739205f;	val_dir[2307*3 + 1] = 0.069301f;	val_dir[2307*3 + 2] = 0.669905f;
+ 	val_dir[2308*3 + 0] = 0.770574f;	val_dir[2308*3 + 1] = 0.093403f;	val_dir[2308*3 + 2] = 0.630470f;
+ 	val_dir[2309*3 + 0] = 0.800055f;	val_dir[2309*3 + 1] = 0.117655f;	val_dir[2309*3 + 2] = 0.588276f;
+ 	val_dir[2310*3 + 0] = 0.827259f;	val_dir[2310*3 + 1] = 0.141816f;	val_dir[2310*3 + 2] = 0.543627f;
+ 	val_dir[2311*3 + 0] = 0.851847f;	val_dir[2311*3 + 1] = 0.165637f;	val_dir[2311*3 + 2] = 0.496911f;
+ 	val_dir[2312*3 + 0] = 0.873555f;	val_dir[2312*3 + 1] = 0.188877f;	val_dir[2312*3 + 2] = 0.448583f;
+ 	val_dir[2313*3 + 0] = 0.892206f;	val_dir[2313*3 + 1] = 0.211312f;	val_dir[2313*3 + 2] = 0.399145f;
+ 	val_dir[2314*3 + 0] = 0.907713f;	val_dir[2314*3 + 1] = 0.232747f;	val_dir[2314*3 + 2] = 0.349121f;
+ 	val_dir[2315*3 + 0] = 0.920087f;	val_dir[2315*3 + 1] = 0.253024f;	val_dir[2315*3 + 2] = 0.299028f;
+ 	val_dir[2316*3 + 0] = 0.929421f;	val_dir[2316*3 + 1] = 0.272026f;	val_dir[2316*3 + 2] = 0.249357f;
+ 	val_dir[2317*3 + 0] = 0.935879f;	val_dir[2317*3 + 1] = 0.289677f;	val_dir[2317*3 + 2] = 0.200545f;
+ 	val_dir[2318*3 + 0] = 0.939680f;	val_dir[2318*3 + 1] = 0.305942f;	val_dir[2318*3 + 2] = 0.152971f;
+ 	val_dir[2319*3 + 0] = 0.941082f;	val_dir[2319*3 + 1] = 0.320824f;	val_dir[2319*3 + 2] = 0.106941f;
+ 	val_dir[2320*3 + 0] = 0.940361f;	val_dir[2320*3 + 1] = 0.334351f;	val_dir[2320*3 + 2] = 0.062691f;
+ 	val_dir[2321*3 + 0] = 0.93780f;	val_dir[2321*3 + 1] = 0.346578f;	val_dir[2321*3 + 2] = 0.020387f;
+ 	val_dir[2322*3 + 0] = -0.364399f;	val_dir[2322*3 + 1] = -0.931243f;	val_dir[2322*3 + 2] = 0.0f;
+ 	val_dir[2323*3 + 0] = -0.353096f;	val_dir[2323*3 + 1] = -0.934665f;	val_dir[2323*3 + 2] = 0.041541f;
+ 	val_dir[2324*3 + 0] = -0.340503f;	val_dir[2324*3 + 1] = -0.936382f;	val_dir[2324*3 + 2] = 0.085126f;
+ 	val_dir[2325*3 + 0] = -0.326550f;	val_dir[2325*3 + 1] = -0.936111f;	val_dir[2325*3 + 2] = 0.130620f;
+ 	val_dir[2326*3 + 0] = -0.311188f;	val_dir[2326*3 + 1] = -0.933564f;	val_dir[2326*3 + 2] = 0.177822f;
+ 	val_dir[2327*3 + 0] = -0.294392f;	val_dir[2327*3 + 1] = -0.928467f;	val_dir[2327*3 + 2] = 0.226455f;
+ 	val_dir[2328*3 + 0] = -0.276172f;	val_dir[2328*3 + 1] = -0.920575f;	val_dir[2328*3 + 2] = 0.276172f;
+ 	val_dir[2329*3 + 0] = -0.256578f;	val_dir[2329*3 + 1] = -0.909687f;	val_dir[2329*3 + 2] = 0.326554f;
+ 	val_dir[2330*3 + 0] = -0.235702f;	val_dir[2330*3 + 1] = -0.895669f;	val_dir[2330*3 + 2] = 0.377124f;
+ 	val_dir[2331*3 + 0] = -0.213681f;	val_dir[2331*3 + 1] = -0.878466f;	val_dir[2331*3 + 2] = 0.427362f;
+ 	val_dir[2332*3 + 0] = -0.190693f;	val_dir[2332*3 + 1] = -0.858116f;	val_dir[2332*3 + 2] = 0.476731f;
+ 	val_dir[2333*3 + 0] = -0.166951f;	val_dir[2333*3 + 1] = -0.834754f;	val_dir[2333*3 + 2] = 0.524703f;
+ 	val_dir[2334*3 + 0] = -0.142695f;	val_dir[2334*3 + 1] = -0.808608f;	val_dir[2334*3 + 2] = 0.570782f;
+ 	val_dir[2335*3 + 0] = -0.118180f;	val_dir[2335*3 + 1] = -0.779987f;	val_dir[2335*3 + 2] = 0.614535f;
+ 	val_dir[2336*3 + 0] = -0.093659f;	val_dir[2336*3 + 1] = -0.749269f;	val_dir[2336*3 + 2] = 0.655610f;
+ 	val_dir[2337*3 + 0] = -0.069375f;	val_dir[2337*3 + 1] = -0.716871f;	val_dir[2337*3 + 2] = 0.693746f;
+ 	val_dir[2338*3 + 0] = -0.045549f;	val_dir[2338*3 + 1] = -0.683231f;	val_dir[2338*3 + 2] = 0.728780f;
+ 	val_dir[2339*3 + 0] = -0.022372f;	val_dir[2339*3 + 1] = -0.648784f;	val_dir[2339*3 + 2] = 0.760644f;
+ 	val_dir[2340*3 + 0] = 0.0f;	val_dir[2340*3 + 1] = -0.613941f;	val_dir[2340*3 + 2] = 0.789352f;
+ 	val_dir[2341*3 + 0] = 0.022217f;	val_dir[2341*3 + 1] = -0.599852f;	val_dir[2341*3 + 2] = 0.799803f;
+ 	val_dir[2342*3 + 0] = 0.044992f;	val_dir[2342*3 + 1] = -0.584898f;	val_dir[2342*3 + 2] = 0.809858f;
+ 	val_dir[2343*3 + 0] = 0.068288f;	val_dir[2343*3 + 1] = -0.569064f;	val_dir[2343*3 + 2] = 0.819453f;
+ 	val_dir[2344*3 + 0] = 0.092057f;	val_dir[2344*3 + 1] = -0.552345f;	val_dir[2344*3 + 2] = 0.828517f;
+ 	val_dir[2345*3 + 0] = 0.116248f;	val_dir[2345*3 + 1] = -0.534739f;	val_dir[2345*3 + 2] = 0.836983f;
+ 	val_dir[2346*3 + 0] = 0.140797f;	val_dir[2346*3 + 1] = -0.516256f;	val_dir[2346*3 + 2] = 0.844782f;
+ 	val_dir[2347*3 + 0] = 0.165637f;	val_dir[2347*3 + 1] = -0.496911f;	val_dir[2347*3 + 2] = 0.851847f;
+ 	val_dir[2348*3 + 0] = 0.190693f;	val_dir[2348*3 + 1] = -0.476731f;	val_dir[2348*3 + 2] = 0.858116f;
+ 	val_dir[2349*3 + 0] = 0.215883f;	val_dir[2349*3 + 1] = -0.455752f;	val_dir[2349*3 + 2] = 0.863530f;
+ 	val_dir[2350*3 + 0] = 0.241121f;	val_dir[2350*3 + 1] = -0.434019f;	val_dir[2350*3 + 2] = 0.868037f;
+ 	val_dir[2351*3 + 0] = 0.266320f;	val_dir[2351*3 + 1] = -0.411585f;	val_dir[2351*3 + 2] = 0.871592f;
+ 	val_dir[2352*3 + 0] = 0.291386f;	val_dir[2352*3 + 1] = -0.388514f;	val_dir[2352*3 + 2] = 0.874157f;
+ 	val_dir[2353*3 + 0] = 0.316228f;	val_dir[2353*3 + 1] = -0.364878f;	val_dir[2353*3 + 2] = 0.875708f;
+ 	val_dir[2354*3 + 0] = 0.340755f;	val_dir[2354*3 + 1] = -0.340755f;	val_dir[2354*3 + 2] = 0.876226f;
+ 	val_dir[2355*3 + 0] = 0.364878f;	val_dir[2355*3 + 1] = -0.316228f;	val_dir[2355*3 + 2] = 0.875708f;
+ 	val_dir[2356*3 + 0] = 0.388514f;	val_dir[2356*3 + 1] = -0.291386f;	val_dir[2356*3 + 2] = 0.874157f;
+ 	val_dir[2357*3 + 0] = 0.411585f;	val_dir[2357*3 + 1] = -0.266320f;	val_dir[2357*3 + 2] = 0.871592f;
+ 	val_dir[2358*3 + 0] = 0.434019f;	val_dir[2358*3 + 1] = -0.241121f;	val_dir[2358*3 + 2] = 0.868037f;
+ 	val_dir[2359*3 + 0] = 0.455752f;	val_dir[2359*3 + 1] = -0.215883f;	val_dir[2359*3 + 2] = 0.863530f;
+ 	val_dir[2360*3 + 0] = 0.476731f;	val_dir[2360*3 + 1] = -0.190693f;	val_dir[2360*3 + 2] = 0.858116f;
+ 	val_dir[2361*3 + 0] = 0.496911f;	val_dir[2361*3 + 1] = -0.165637f;	val_dir[2361*3 + 2] = 0.851847f;
+ 	val_dir[2362*3 + 0] = 0.516256f;	val_dir[2362*3 + 1] = -0.140797f;	val_dir[2362*3 + 2] = 0.844782f;
+ 	val_dir[2363*3 + 0] = 0.534739f;	val_dir[2363*3 + 1] = -0.116248f;	val_dir[2363*3 + 2] = 0.836983f;
+ 	val_dir[2364*3 + 0] = 0.552345f;	val_dir[2364*3 + 1] = -0.092057f;	val_dir[2364*3 + 2] = 0.828517f;
+ 	val_dir[2365*3 + 0] = 0.569064f;	val_dir[2365*3 + 1] = -0.068288f;	val_dir[2365*3 + 2] = 0.819453f;
+ 	val_dir[2366*3 + 0] = 0.584898f;	val_dir[2366*3 + 1] = -0.044992f;	val_dir[2366*3 + 2] = 0.809858f;
+ 	val_dir[2367*3 + 0] = 0.599852f;	val_dir[2367*3 + 1] = -0.022217f;	val_dir[2367*3 + 2] = 0.799803f;
+ 	val_dir[2368*3 + 0] = 0.613941f;	val_dir[2368*3 + 1] = 0.0f;	val_dir[2368*3 + 2] = 0.789352f;
+ 	val_dir[2369*3 + 0] = 0.648784f;	val_dir[2369*3 + 1] = 0.022372f;	val_dir[2369*3 + 2] = 0.760644f;
+ 	val_dir[2370*3 + 0] = 0.683231f;	val_dir[2370*3 + 1] = 0.045549f;	val_dir[2370*3 + 2] = 0.728780f;
+ 	val_dir[2371*3 + 0] = 0.716871f;	val_dir[2371*3 + 1] = 0.069375f;	val_dir[2371*3 + 2] = 0.693746f;
+ 	val_dir[2372*3 + 0] = 0.749269f;	val_dir[2372*3 + 1] = 0.093659f;	val_dir[2372*3 + 2] = 0.655610f;
+ 	val_dir[2373*3 + 0] = 0.779987f;	val_dir[2373*3 + 1] = 0.118180f;	val_dir[2373*3 + 2] = 0.614535f;
+ 	val_dir[2374*3 + 0] = 0.808608f;	val_dir[2374*3 + 1] = 0.142695f;	val_dir[2374*3 + 2] = 0.570782f;
+ 	val_dir[2375*3 + 0] = 0.834754f;	val_dir[2375*3 + 1] = 0.166951f;	val_dir[2375*3 + 2] = 0.524703f;
+ 	val_dir[2376*3 + 0] = 0.858116f;	val_dir[2376*3 + 1] = 0.190693f;	val_dir[2376*3 + 2] = 0.476731f;
+ 	val_dir[2377*3 + 0] = 0.878466f;	val_dir[2377*3 + 1] = 0.213681f;	val_dir[2377*3 + 2] = 0.427362f;
+ 	val_dir[2378*3 + 0] = 0.895669f;	val_dir[2378*3 + 1] = 0.235702f;	val_dir[2378*3 + 2] = 0.377124f;
+ 	val_dir[2379*3 + 0] = 0.909687f;	val_dir[2379*3 + 1] = 0.256578f;	val_dir[2379*3 + 2] = 0.326554f;
+ 	val_dir[2380*3 + 0] = 0.920575f;	val_dir[2380*3 + 1] = 0.276172f;	val_dir[2380*3 + 2] = 0.276172f;
+ 	val_dir[2381*3 + 0] = 0.928467f;	val_dir[2381*3 + 1] = 0.294392f;	val_dir[2381*3 + 2] = 0.226455f;
+ 	val_dir[2382*3 + 0] = 0.933564f;	val_dir[2382*3 + 1] = 0.311188f;	val_dir[2382*3 + 2] = 0.177822f;
+ 	val_dir[2383*3 + 0] = 0.936111f;	val_dir[2383*3 + 1] = 0.326550f;	val_dir[2383*3 + 2] = 0.130620f;
+ 	val_dir[2384*3 + 0] = 0.936382f;	val_dir[2384*3 + 1] = 0.340503f;	val_dir[2384*3 + 2] = 0.085126f;
+ 	val_dir[2385*3 + 0] = 0.934665f;	val_dir[2385*3 + 1] = 0.353096f;	val_dir[2385*3 + 2] = 0.041541f;
+ 	val_dir[2386*3 + 0] = 0.931243f;	val_dir[2386*3 + 1] = 0.364399f;	val_dir[2386*3 + 2] = 0.0f;
+ 	val_dir[2387*3 + 0] = -0.371312f;	val_dir[2387*3 + 1] = -0.928279f;	val_dir[2387*3 + 2] = 0.020628f;
+ 	val_dir[2388*3 + 0] = -0.359673f;	val_dir[2388*3 + 1] = -0.930917f;	val_dir[2388*3 + 2] = 0.063472f;
+ 	val_dir[2389*3 + 0] = -0.346681f;	val_dir[2389*3 + 1] = -0.931705f;	val_dir[2389*3 + 2] = 0.108338f;
+ 	val_dir[2390*3 + 0] = -0.332269f;	val_dir[2390*3 + 1] = -0.930352f;	val_dir[2390*3 + 2] = 0.155059f;
+ 	val_dir[2391*3 + 0] = -0.316389f;	val_dir[2391*3 + 1] = -0.926568f;	val_dir[2391*3 + 2] = 0.203393f;
+ 	val_dir[2392*3 + 0] = -0.299028f;	val_dir[2392*3 + 1] = -0.920087f;	val_dir[2392*3 + 2] = 0.253024f;
+ 	val_dir[2393*3 + 0] = -0.280209f;	val_dir[2393*3 + 1] = -0.910678f;	val_dir[2393*3 + 2] = 0.303559f;
+ 	val_dir[2394*3 + 0] = -0.259996f;	val_dir[2394*3 + 1] = -0.898167f;	val_dir[2394*3 + 2] = 0.354540f;
+ 	val_dir[2395*3 + 0] = -0.238501f;	val_dir[2395*3 + 1] = -0.882454f;	val_dir[2395*3 + 2] = 0.405452f;
+ 	val_dir[2396*3 + 0] = -0.215883f;	val_dir[2396*3 + 1] = -0.863530f;	val_dir[2396*3 + 2] = 0.455752f;
+ 	val_dir[2397*3 + 0] = -0.192339f;	val_dir[2397*3 + 1] = -0.841482f;	val_dir[2397*3 + 2] = 0.504889f;
+ 	val_dir[2398*3 + 0] = -0.168102f;	val_dir[2398*3 + 1] = -0.816497f;	val_dir[2398*3 + 2] = 0.552336f;
+ 	val_dir[2399*3 + 0] = -0.143427f;	val_dir[2399*3 + 1] = -0.788851f;	val_dir[2399*3 + 2] = 0.597614f;
+ 	val_dir[2400*3 + 0] = -0.118578f;	val_dir[2400*3 + 1] = -0.758899f;	val_dir[2400*3 + 2] = 0.640321f;
+ 	val_dir[2401*3 + 0] = -0.093813f;	val_dir[2401*3 + 1] = -0.727051f;	val_dir[2401*3 + 2] = 0.680144f;
+ 	val_dir[2402*3 + 0] = -0.069375f;	val_dir[2402*3 + 1] = -0.693746f;	val_dir[2402*3 + 2] = 0.716871f;
+ 	val_dir[2403*3 + 0] = -0.045478f;	val_dir[2403*3 + 1] = -0.659432f;	val_dir[2403*3 + 2] = 0.750388f;
+ 	val_dir[2404*3 + 0] = -0.022305f;	val_dir[2404*3 + 1] = -0.624540f;	val_dir[2404*3 + 2] = 0.780675f;
+ 	val_dir[2405*3 + 0] = 0.0f;	val_dir[2405*3 + 1] = -0.589469f;	val_dir[2405*3 + 2] = 0.807791f;
+ 	val_dir[2406*3 + 0] = 0.022108f;	val_dir[2406*3 + 1] = -0.574805f;	val_dir[2406*3 + 2] = 0.817992f;
+ 	val_dir[2407*3 + 0] = 0.044744f;	val_dir[2407*3 + 1] = -0.559297f;	val_dir[2407*3 + 2] = 0.827759f;
+ 	val_dir[2408*3 + 0] = 0.067867f;	val_dir[2408*3 + 1] = -0.542936f;	val_dir[2408*3 + 2] = 0.837027f;
+ 	val_dir[2409*3 + 0] = 0.091430f;	val_dir[2409*3 + 1] = -0.525723f;	val_dir[2409*3 + 2] = 0.845728f;
+ 	val_dir[2410*3 + 0] = 0.115378f;	val_dir[2410*3 + 1] = -0.507662f;	val_dir[2410*3 + 2] = 0.853796f;
+ 	val_dir[2411*3 + 0] = 0.139648f;	val_dir[2411*3 + 1] = -0.488769f;	val_dir[2411*3 + 2] = 0.861164f;
+ 	val_dir[2412*3 + 0] = 0.164173f;	val_dir[2412*3 + 1] = -0.469065f;	val_dir[2412*3 + 2] = 0.867770f;
+ 	val_dir[2413*3 + 0] = 0.188877f;	val_dir[2413*3 + 1] = -0.448583f;	val_dir[2413*3 + 2] = 0.873555f;
+ 	val_dir[2414*3 + 0] = 0.213681f;	val_dir[2414*3 + 1] = -0.427362f;	val_dir[2414*3 + 2] = 0.878466f;
+ 	val_dir[2415*3 + 0] = 0.238501f;	val_dir[2415*3 + 1] = -0.405452f;	val_dir[2415*3 + 2] = 0.882454f;
+ 	val_dir[2416*3 + 0] = 0.263251f;	val_dir[2416*3 + 1] = -0.382911f;	val_dir[2416*3 + 2] = 0.885482f;
+ 	val_dir[2417*3 + 0] = 0.287843f;	val_dir[2417*3 + 1] = -0.359804f;	val_dir[2417*3 + 2] = 0.887517f;
+ 	val_dir[2418*3 + 0] = 0.312190f;	val_dir[2418*3 + 1] = -0.336204f;	val_dir[2418*3 + 2] = 0.888540f;
+ 	val_dir[2419*3 + 0] = 0.336204f;	val_dir[2419*3 + 1] = -0.312190f;	val_dir[2419*3 + 2] = 0.888540f;
+ 	val_dir[2420*3 + 0] = 0.359804f;	val_dir[2420*3 + 1] = -0.287843f;	val_dir[2420*3 + 2] = 0.887517f;
+ 	val_dir[2421*3 + 0] = 0.382911f;	val_dir[2421*3 + 1] = -0.263251f;	val_dir[2421*3 + 2] = 0.885482f;
+ 	val_dir[2422*3 + 0] = 0.405452f;	val_dir[2422*3 + 1] = -0.238501f;	val_dir[2422*3 + 2] = 0.882454f;
+ 	val_dir[2423*3 + 0] = 0.427362f;	val_dir[2423*3 + 1] = -0.213681f;	val_dir[2423*3 + 2] = 0.878466f;
+ 	val_dir[2424*3 + 0] = 0.448583f;	val_dir[2424*3 + 1] = -0.188877f;	val_dir[2424*3 + 2] = 0.873555f;
+ 	val_dir[2425*3 + 0] = 0.469065f;	val_dir[2425*3 + 1] = -0.164173f;	val_dir[2425*3 + 2] = 0.867770f;
+ 	val_dir[2426*3 + 0] = 0.488769f;	val_dir[2426*3 + 1] = -0.139648f;	val_dir[2426*3 + 2] = 0.861164f;
+ 	val_dir[2427*3 + 0] = 0.507662f;	val_dir[2427*3 + 1] = -0.115378f;	val_dir[2427*3 + 2] = 0.853796f;
+ 	val_dir[2428*3 + 0] = 0.525723f;	val_dir[2428*3 + 1] = -0.091430f;	val_dir[2428*3 + 2] = 0.845728f;
+ 	val_dir[2429*3 + 0] = 0.542936f;	val_dir[2429*3 + 1] = -0.067867f;	val_dir[2429*3 + 2] = 0.837027f;
+ 	val_dir[2430*3 + 0] = 0.559297f;	val_dir[2430*3 + 1] = -0.044744f;	val_dir[2430*3 + 2] = 0.827759f;
+ 	val_dir[2431*3 + 0] = 0.574805f;	val_dir[2431*3 + 1] = -0.022108f;	val_dir[2431*3 + 2] = 0.817992f;
+ 	val_dir[2432*3 + 0] = 0.589469f;	val_dir[2432*3 + 1] = 0.0f;	val_dir[2432*3 + 2] = 0.807791f;
+ 	val_dir[2433*3 + 0] = 0.624540f;	val_dir[2433*3 + 1] = 0.022305f;	val_dir[2433*3 + 2] = 0.780675f;
+ 	val_dir[2434*3 + 0] = 0.659432f;	val_dir[2434*3 + 1] = 0.045478f;	val_dir[2434*3 + 2] = 0.750388f;
+ 	val_dir[2435*3 + 0] = 0.693746f;	val_dir[2435*3 + 1] = 0.069375f;	val_dir[2435*3 + 2] = 0.716871f;
+ 	val_dir[2436*3 + 0] = 0.727051f;	val_dir[2436*3 + 1] = 0.093813f;	val_dir[2436*3 + 2] = 0.680144f;
+ 	val_dir[2437*3 + 0] = 0.758899f;	val_dir[2437*3 + 1] = 0.118578f;	val_dir[2437*3 + 2] = 0.640321f;
+ 	val_dir[2438*3 + 0] = 0.788851f;	val_dir[2438*3 + 1] = 0.143427f;	val_dir[2438*3 + 2] = 0.597614f;
+ 	val_dir[2439*3 + 0] = 0.816497f;	val_dir[2439*3 + 1] = 0.168102f;	val_dir[2439*3 + 2] = 0.552336f;
+ 	val_dir[2440*3 + 0] = 0.841482f;	val_dir[2440*3 + 1] = 0.192339f;	val_dir[2440*3 + 2] = 0.504889f;
+ 	val_dir[2441*3 + 0] = 0.863530f;	val_dir[2441*3 + 1] = 0.215883f;	val_dir[2441*3 + 2] = 0.455752f;
+ 	val_dir[2442*3 + 0] = 0.882454f;	val_dir[2442*3 + 1] = 0.238501f;	val_dir[2442*3 + 2] = 0.405452f;
+ 	val_dir[2443*3 + 0] = 0.898167f;	val_dir[2443*3 + 1] = 0.259996f;	val_dir[2443*3 + 2] = 0.354540f;
+ 	val_dir[2444*3 + 0] = 0.910678f;	val_dir[2444*3 + 1] = 0.280209f;	val_dir[2444*3 + 2] = 0.303559f;
+ 	val_dir[2445*3 + 0] = 0.920087f;	val_dir[2445*3 + 1] = 0.299028f;	val_dir[2445*3 + 2] = 0.253024f;
+ 	val_dir[2446*3 + 0] = 0.926568f;	val_dir[2446*3 + 1] = 0.316389f;	val_dir[2446*3 + 2] = 0.203393f;
+ 	val_dir[2447*3 + 0] = 0.930352f;	val_dir[2447*3 + 1] = 0.332269f;	val_dir[2447*3 + 2] = 0.155059f;
+ 	val_dir[2448*3 + 0] = 0.931705f;	val_dir[2448*3 + 1] = 0.346681f;	val_dir[2448*3 + 2] = 0.108338f;
+ 	val_dir[2449*3 + 0] = 0.930917f;	val_dir[2449*3 + 1] = 0.359673f;	val_dir[2449*3 + 2] = 0.063472f;
+ 	val_dir[2450*3 + 0] = 0.928279f;	val_dir[2450*3 + 1] = 0.371312f;	val_dir[2450*3 + 2] = 0.020628f;
+ 	val_dir[2451*3 + 0] = -0.388972f;	val_dir[2451*3 + 1] = -0.921250f;	val_dir[2451*3 + 2] = 0.0f;
+ 	val_dir[2452*3 + 0] = -0.378298f;	val_dir[2452*3 + 1] = -0.924729f;	val_dir[2452*3 + 2] = 0.042033f;
+ 	val_dir[2453*3 + 0] = -0.366291f;	val_dir[2453*3 + 1] = -0.92650f;	val_dir[2453*3 + 2] = 0.086186f;
+ 	val_dir[2454*3 + 0] = -0.352865f;	val_dir[2454*3 + 1] = -0.926270f;	val_dir[2454*3 + 2] = 0.132324f;
+ 	val_dir[2455*3 + 0] = -0.337954f;	val_dir[2455*3 + 1] = -0.923742f;	val_dir[2455*3 + 2] = 0.180242f;
+ 	val_dir[2456*3 + 0] = -0.321521f;	val_dir[2456*3 + 1] = -0.918630f;	val_dir[2456*3 + 2] = 0.229658f;
+ 	val_dir[2457*3 + 0] = -0.303559f;	val_dir[2457*3 + 1] = -0.910678f;	val_dir[2457*3 + 2] = 0.280209f;
+ 	val_dir[2458*3 + 0] = -0.284108f;	val_dir[2458*3 + 1] = -0.899676f;	val_dir[2458*3 + 2] = 0.331460f;
+ 	val_dir[2459*3 + 0] = -0.263251f;	val_dir[2459*3 + 1] = -0.885482f;	val_dir[2459*3 + 2] = 0.382911f;
+ 	val_dir[2460*3 + 0] = -0.241121f;	val_dir[2460*3 + 1] = -0.868037f;	val_dir[2460*3 + 2] = 0.434019f;
+ 	val_dir[2461*3 + 0] = -0.217898f;	val_dir[2461*3 + 1] = -0.847381f;	val_dir[2461*3 + 2] = 0.484217f;
+ 	val_dir[2462*3 + 0] = -0.193801f;	val_dir[2462*3 + 1] = -0.823653f;	val_dir[2462*3 + 2] = 0.532952f;
+ 	val_dir[2463*3 + 0] = -0.169080f;	val_dir[2463*3 + 1] = -0.797092f;	val_dir[2463*3 + 2] = 0.579703f;
+ 	val_dir[2464*3 + 0] = -0.144005f;	val_dir[2464*3 + 1] = -0.768025f;	val_dir[2464*3 + 2] = 0.624020f;
+ 	val_dir[2465*3 + 0] = -0.118846f;	val_dir[2465*3 + 1] = -0.736843f;	val_dir[2465*3 + 2] = 0.665536f;
+ 	val_dir[2466*3 + 0] = -0.093865f;	val_dir[2466*3 + 1] = -0.703985f;	val_dir[2466*3 + 2] = 0.703985f;
+ 	val_dir[2467*3 + 0] = -0.069301f;	val_dir[2467*3 + 1] = -0.669905f;	val_dir[2467*3 + 2] = 0.739205f;
+ 	val_dir[2468*3 + 0] = -0.045361f;	val_dir[2468*3 + 1] = -0.635053f;	val_dir[2468*3 + 2] = 0.771136f;
+ 	val_dir[2469*3 + 0] = -0.022217f;	val_dir[2469*3 + 1] = -0.599852f;	val_dir[2469*3 + 2] = 0.799803f;
+ 	val_dir[2470*3 + 0] = 0.0f;	val_dir[2470*3 + 1] = -0.564684f;	val_dir[2470*3 + 2] = 0.825307f;
+ 	val_dir[2471*3 + 0] = 0.021979f;	val_dir[2471*3 + 1] = -0.549484f;	val_dir[2471*3 + 2] = 0.835215f;
+ 	val_dir[2472*3 + 0] = 0.044455f;	val_dir[2472*3 + 1] = -0.533465f;	val_dir[2472*3 + 2] = 0.844653f;
+ 	val_dir[2473*3 + 0] = 0.067386f;	val_dir[2473*3 + 1] = -0.516626f;	val_dir[2473*3 + 2] = 0.853556f;
+ 	val_dir[2474*3 + 0] = 0.090722f;	val_dir[2474*3 + 1] = -0.498970f;	val_dir[2474*3 + 2] = 0.861857f;
+ 	val_dir[2475*3 + 0] = 0.114407f;	val_dir[2475*3 + 1] = -0.480510f;	val_dir[2475*3 + 2] = 0.869495f;
+ 	val_dir[2476*3 + 0] = 0.138380f;	val_dir[2476*3 + 1] = -0.461266f;	val_dir[2476*3 + 2] = 0.876405f;
+ 	val_dir[2477*3 + 0] = 0.162571f;	val_dir[2477*3 + 1] = -0.441264f;	val_dir[2477*3 + 2] = 0.882528f;
+ 	val_dir[2478*3 + 0] = 0.186908f;	val_dir[2478*3 + 1] = -0.420542f;	val_dir[2478*3 + 2] = 0.887812f;
+ 	val_dir[2479*3 + 0] = 0.211312f;	val_dir[2479*3 + 1] = -0.399145f;	val_dir[2479*3 + 2] = 0.892206f;
+ 	val_dir[2480*3 + 0] = 0.235702f;	val_dir[2480*3 + 1] = -0.377124f;	val_dir[2480*3 + 2] = 0.895669f;
+ 	val_dir[2481*3 + 0] = 0.259996f;	val_dir[2481*3 + 1] = -0.354540f;	val_dir[2481*3 + 2] = 0.898167f;
+ 	val_dir[2482*3 + 0] = 0.284108f;	val_dir[2482*3 + 1] = -0.331460f;	val_dir[2482*3 + 2] = 0.899676f;
+ 	val_dir[2483*3 + 0] = 0.307957f;	val_dir[2483*3 + 1] = -0.307957f;	val_dir[2483*3 + 2] = 0.900181f;
+ 	val_dir[2484*3 + 0] = 0.331460f;	val_dir[2484*3 + 1] = -0.284108f;	val_dir[2484*3 + 2] = 0.899676f;
+ 	val_dir[2485*3 + 0] = 0.354540f;	val_dir[2485*3 + 1] = -0.259996f;	val_dir[2485*3 + 2] = 0.898167f;
+ 	val_dir[2486*3 + 0] = 0.377124f;	val_dir[2486*3 + 1] = -0.235702f;	val_dir[2486*3 + 2] = 0.895669f;
+ 	val_dir[2487*3 + 0] = 0.399145f;	val_dir[2487*3 + 1] = -0.211312f;	val_dir[2487*3 + 2] = 0.892206f;
+ 	val_dir[2488*3 + 0] = 0.420542f;	val_dir[2488*3 + 1] = -0.186908f;	val_dir[2488*3 + 2] = 0.887812f;
+ 	val_dir[2489*3 + 0] = 0.441264f;	val_dir[2489*3 + 1] = -0.162571f;	val_dir[2489*3 + 2] = 0.882528f;
+ 	val_dir[2490*3 + 0] = 0.461266f;	val_dir[2490*3 + 1] = -0.138380f;	val_dir[2490*3 + 2] = 0.876405f;
+ 	val_dir[2491*3 + 0] = 0.480510f;	val_dir[2491*3 + 1] = -0.114407f;	val_dir[2491*3 + 2] = 0.869495f;
+ 	val_dir[2492*3 + 0] = 0.498970f;	val_dir[2492*3 + 1] = -0.090722f;	val_dir[2492*3 + 2] = 0.861857f;
+ 	val_dir[2493*3 + 0] = 0.516626f;	val_dir[2493*3 + 1] = -0.067386f;	val_dir[2493*3 + 2] = 0.853556f;
+ 	val_dir[2494*3 + 0] = 0.533465f;	val_dir[2494*3 + 1] = -0.044455f;	val_dir[2494*3 + 2] = 0.844653f;
+ 	val_dir[2495*3 + 0] = 0.549484f;	val_dir[2495*3 + 1] = -0.021979f;	val_dir[2495*3 + 2] = 0.835215f;
+ 	val_dir[2496*3 + 0] = 0.564684f;	val_dir[2496*3 + 1] = 0.0f;	val_dir[2496*3 + 2] = 0.825307f;
+ 	val_dir[2497*3 + 0] = 0.599852f;	val_dir[2497*3 + 1] = 0.022217f;	val_dir[2497*3 + 2] = 0.799803f;
+ 	val_dir[2498*3 + 0] = 0.635053f;	val_dir[2498*3 + 1] = 0.045361f;	val_dir[2498*3 + 2] = 0.771136f;
+ 	val_dir[2499*3 + 0] = 0.669905f;	val_dir[2499*3 + 1] = 0.069301f;	val_dir[2499*3 + 2] = 0.739205f;
+ 	val_dir[2500*3 + 0] = 0.703985f;	val_dir[2500*3 + 1] = 0.093865f;	val_dir[2500*3 + 2] = 0.703985f;
+ 	val_dir[2501*3 + 0] = 0.736843f;	val_dir[2501*3 + 1] = 0.118846f;	val_dir[2501*3 + 2] = 0.665536f;
+ 	val_dir[2502*3 + 0] = 0.768025f;	val_dir[2502*3 + 1] = 0.144005f;	val_dir[2502*3 + 2] = 0.624020f;
+ 	val_dir[2503*3 + 0] = 0.797092f;	val_dir[2503*3 + 1] = 0.169080f;	val_dir[2503*3 + 2] = 0.579703f;
+ 	val_dir[2504*3 + 0] = 0.823653f;	val_dir[2504*3 + 1] = 0.193801f;	val_dir[2504*3 + 2] = 0.532952f;
+ 	val_dir[2505*3 + 0] = 0.847381f;	val_dir[2505*3 + 1] = 0.217898f;	val_dir[2505*3 + 2] = 0.484217f;
+ 	val_dir[2506*3 + 0] = 0.868037f;	val_dir[2506*3 + 1] = 0.241121f;	val_dir[2506*3 + 2] = 0.434019f;
+ 	val_dir[2507*3 + 0] = 0.885482f;	val_dir[2507*3 + 1] = 0.263251f;	val_dir[2507*3 + 2] = 0.382911f;
+ 	val_dir[2508*3 + 0] = 0.899676f;	val_dir[2508*3 + 1] = 0.284108f;	val_dir[2508*3 + 2] = 0.331460f;
+ 	val_dir[2509*3 + 0] = 0.910678f;	val_dir[2509*3 + 1] = 0.303559f;	val_dir[2509*3 + 2] = 0.280209f;
+ 	val_dir[2510*3 + 0] = 0.918630f;	val_dir[2510*3 + 1] = 0.321521f;	val_dir[2510*3 + 2] = 0.229658f;
+ 	val_dir[2511*3 + 0] = 0.923742f;	val_dir[2511*3 + 1] = 0.337954f;	val_dir[2511*3 + 2] = 0.180242f;
+ 	val_dir[2512*3 + 0] = 0.926270f;	val_dir[2512*3 + 1] = 0.352865f;	val_dir[2512*3 + 2] = 0.132324f;
+ 	val_dir[2513*3 + 0] = 0.92650f;	val_dir[2513*3 + 1] = 0.366291f;	val_dir[2513*3 + 2] = 0.086186f;
+ 	val_dir[2514*3 + 0] = 0.924729f;	val_dir[2514*3 + 1] = 0.378298f;	val_dir[2514*3 + 2] = 0.042033f;
+ 	val_dir[2515*3 + 0] = 0.921250f;	val_dir[2515*3 + 1] = 0.388972f;	val_dir[2515*3 + 2] = 0.0f;
+ 	val_dir[2516*3 + 0] = -0.396350f;	val_dir[2516*3 + 1] = -0.917863f;	val_dir[2516*3 + 2] = 0.020861f;
+ 	val_dir[2517*3 + 0] = -0.385341f;	val_dir[2517*3 + 1] = -0.920537f;	val_dir[2517*3 + 2] = 0.064223f;
+ 	val_dir[2518*3 + 0] = -0.372929f;	val_dir[2518*3 + 1] = -0.921354f;	val_dir[2518*3 + 2] = 0.109685f;
+ 	val_dir[2519*3 + 0] = -0.359030f;	val_dir[2519*3 + 1] = -0.920014f;	val_dir[2519*3 + 2] = 0.157075f;
+ 	val_dir[2520*3 + 0] = -0.343582f;	val_dir[2520*3 + 1] = -0.916217f;	val_dir[2520*3 + 2] = 0.206149f;
+ 	val_dir[2521*3 + 0] = -0.326554f;	val_dir[2521*3 + 1] = -0.909687f;	val_dir[2521*3 + 2] = 0.256578f;
+ 	val_dir[2522*3 + 0] = -0.307957f;	val_dir[2522*3 + 1] = -0.900181f;	val_dir[2522*3 + 2] = 0.307957f;
+ 	val_dir[2523*3 + 0] = -0.287843f;	val_dir[2523*3 + 1] = -0.887517f;	val_dir[2523*3 + 2] = 0.359804f;
+ 	val_dir[2524*3 + 0] = -0.266320f;	val_dir[2524*3 + 1] = -0.871592f;	val_dir[2524*3 + 2] = 0.411585f;
+ 	val_dir[2525*3 + 0] = -0.243541f;	val_dir[2525*3 + 1] = -0.852392f;	val_dir[2525*3 + 2] = 0.462727f;
+ 	val_dir[2526*3 + 0] = -0.219708f;	val_dir[2526*3 + 1] = -0.830009f;	val_dir[2526*3 + 2] = 0.512653f;
+ 	val_dir[2527*3 + 0] = -0.195064f;	val_dir[2527*3 + 1] = -0.804639f;	val_dir[2527*3 + 2] = 0.560809f;
+ 	val_dir[2528*3 + 0] = -0.169875f;	val_dir[2528*3 + 1] = -0.776571f;	val_dir[2528*3 + 2] = 0.606696f;
+ 	val_dir[2529*3 + 0] = -0.144421f;	val_dir[2529*3 + 1] = -0.746176f;	val_dir[2529*3 + 2] = 0.649895f;
+ 	val_dir[2530*3 + 0] = -0.118980f;	val_dir[2530*3 + 1] = -0.713881f;	val_dir[2530*3 + 2] = 0.690085f;
+ 	val_dir[2531*3 + 0] = -0.093813f;	val_dir[2531*3 + 1] = -0.680144f;	val_dir[2531*3 + 2] = 0.727051f;
+ 	val_dir[2532*3 + 0] = -0.069153f;	val_dir[2532*3 + 1] = -0.645429f;	val_dir[2532*3 + 2] = 0.760684f;
+ 	val_dir[2533*3 + 0] = -0.045198f;	val_dir[2533*3 + 1] = -0.610179f;	val_dir[2533*3 + 2] = 0.790973f;
+ 	val_dir[2534*3 + 0] = -0.022108f;	val_dir[2534*3 + 1] = -0.574805f;	val_dir[2534*3 + 2] = 0.817992f;
+ 	val_dir[2535*3 + 0] = 0.0f;	val_dir[2535*3 + 1] = -0.539666f;	val_dir[2535*3 + 2] = 0.841879f;
+ 	val_dir[2536*3 + 0] = 0.021832f;	val_dir[2536*3 + 1] = -0.523973f;	val_dir[2536*3 + 2] = 0.851455f;
+ 	val_dir[2537*3 + 0] = 0.044130f;	val_dir[2537*3 + 1] = -0.507490f;	val_dir[2537*3 + 2] = 0.860527f;
+ 	val_dir[2538*3 + 0] = 0.066848f;	val_dir[2538*3 + 1] = -0.490222f;	val_dir[2538*3 + 2] = 0.869030f;
+ 	val_dir[2539*3 + 0] = 0.089939f;	val_dir[2539*3 + 1] = -0.472178f;	val_dir[2539*3 + 2] = 0.876903f;
+ 	val_dir[2540*3 + 0] = 0.113344f;	val_dir[2540*3 + 1] = -0.453376f;	val_dir[2540*3 + 2] = 0.884083f;
+ 	val_dir[2541*3 + 0] = 0.137002f;	val_dir[2541*3 + 1] = -0.433840f;	val_dir[2541*3 + 2] = 0.890513f;
+ 	val_dir[2542*3 + 0] = 0.160845f;	val_dir[2542*3 + 1] = -0.413602f;	val_dir[2542*3 + 2] = 0.896137f;
+ 	val_dir[2543*3 + 0] = 0.184801f;	val_dir[2543*3 + 1] = -0.392703f;	val_dir[2543*3 + 2] = 0.900907f;
+ 	val_dir[2544*3 + 0] = 0.208795f;	val_dir[2544*3 + 1] = -0.371191f;	val_dir[2544*3 + 2] = 0.904777f;
+ 	val_dir[2545*3 + 0] = 0.232747f;	val_dir[2545*3 + 1] = -0.349121f;	val_dir[2545*3 + 2] = 0.907713f;
+ 	val_dir[2546*3 + 0] = 0.256578f;	val_dir[2546*3 + 1] = -0.326554f;	val_dir[2546*3 + 2] = 0.909687f;
+ 	val_dir[2547*3 + 0] = 0.280209f;	val_dir[2547*3 + 1] = -0.303559f;	val_dir[2547*3 + 2] = 0.910678f;
+ 	val_dir[2548*3 + 0] = 0.303559f;	val_dir[2548*3 + 1] = -0.280209f;	val_dir[2548*3 + 2] = 0.910678f;
+ 	val_dir[2549*3 + 0] = 0.326554f;	val_dir[2549*3 + 1] = -0.256578f;	val_dir[2549*3 + 2] = 0.909687f;
+ 	val_dir[2550*3 + 0] = 0.349121f;	val_dir[2550*3 + 1] = -0.232747f;	val_dir[2550*3 + 2] = 0.907713f;
+ 	val_dir[2551*3 + 0] = 0.371191f;	val_dir[2551*3 + 1] = -0.208795f;	val_dir[2551*3 + 2] = 0.904777f;
+ 	val_dir[2552*3 + 0] = 0.392703f;	val_dir[2552*3 + 1] = -0.184801f;	val_dir[2552*3 + 2] = 0.900907f;
+ 	val_dir[2553*3 + 0] = 0.413602f;	val_dir[2553*3 + 1] = -0.160845f;	val_dir[2553*3 + 2] = 0.896137f;
+ 	val_dir[2554*3 + 0] = 0.433840f;	val_dir[2554*3 + 1] = -0.137002f;	val_dir[2554*3 + 2] = 0.890513f;
+ 	val_dir[2555*3 + 0] = 0.453376f;	val_dir[2555*3 + 1] = -0.113344f;	val_dir[2555*3 + 2] = 0.884083f;
+ 	val_dir[2556*3 + 0] = 0.472178f;	val_dir[2556*3 + 1] = -0.089939f;	val_dir[2556*3 + 2] = 0.876903f;
+ 	val_dir[2557*3 + 0] = 0.490222f;	val_dir[2557*3 + 1] = -0.066848f;	val_dir[2557*3 + 2] = 0.869030f;
+ 	val_dir[2558*3 + 0] = 0.507490f;	val_dir[2558*3 + 1] = -0.044130f;	val_dir[2558*3 + 2] = 0.860527f;
+ 	val_dir[2559*3 + 0] = 0.523973f;	val_dir[2559*3 + 1] = -0.021832f;	val_dir[2559*3 + 2] = 0.851455f;
+ 	val_dir[2560*3 + 0] = 0.539666f;	val_dir[2560*3 + 1] = 0.0f;	val_dir[2560*3 + 2] = 0.841879f;
+ 	val_dir[2561*3 + 0] = 0.574805f;	val_dir[2561*3 + 1] = 0.022108f;	val_dir[2561*3 + 2] = 0.817992f;
+ 	val_dir[2562*3 + 0] = 0.610179f;	val_dir[2562*3 + 1] = 0.045198f;	val_dir[2562*3 + 2] = 0.790973f;
+ 	val_dir[2563*3 + 0] = 0.645429f;	val_dir[2563*3 + 1] = 0.069153f;	val_dir[2563*3 + 2] = 0.760684f;
+ 	val_dir[2564*3 + 0] = 0.680144f;	val_dir[2564*3 + 1] = 0.093813f;	val_dir[2564*3 + 2] = 0.727051f;
+ 	val_dir[2565*3 + 0] = 0.713881f;	val_dir[2565*3 + 1] = 0.118980f;	val_dir[2565*3 + 2] = 0.690085f;
+ 	val_dir[2566*3 + 0] = 0.746176f;	val_dir[2566*3 + 1] = 0.144421f;	val_dir[2566*3 + 2] = 0.649895f;
+ 	val_dir[2567*3 + 0] = 0.776571f;	val_dir[2567*3 + 1] = 0.169875f;	val_dir[2567*3 + 2] = 0.606696f;
+ 	val_dir[2568*3 + 0] = 0.804639f;	val_dir[2568*3 + 1] = 0.195064f;	val_dir[2568*3 + 2] = 0.560809f;
+ 	val_dir[2569*3 + 0] = 0.830009f;	val_dir[2569*3 + 1] = 0.219708f;	val_dir[2569*3 + 2] = 0.512653f;
+ 	val_dir[2570*3 + 0] = 0.852392f;	val_dir[2570*3 + 1] = 0.243541f;	val_dir[2570*3 + 2] = 0.462727f;
+ 	val_dir[2571*3 + 0] = 0.871592f;	val_dir[2571*3 + 1] = 0.266320f;	val_dir[2571*3 + 2] = 0.411585f;
+ 	val_dir[2572*3 + 0] = 0.887517f;	val_dir[2572*3 + 1] = 0.287843f;	val_dir[2572*3 + 2] = 0.359804f;
+ 	val_dir[2573*3 + 0] = 0.900181f;	val_dir[2573*3 + 1] = 0.307957f;	val_dir[2573*3 + 2] = 0.307957f;
+ 	val_dir[2574*3 + 0] = 0.909687f;	val_dir[2574*3 + 1] = 0.326554f;	val_dir[2574*3 + 2] = 0.256578f;
+ 	val_dir[2575*3 + 0] = 0.916217f;	val_dir[2575*3 + 1] = 0.343582f;	val_dir[2575*3 + 2] = 0.206149f;
+ 	val_dir[2576*3 + 0] = 0.920014f;	val_dir[2576*3 + 1] = 0.359030f;	val_dir[2576*3 + 2] = 0.157075f;
+ 	val_dir[2577*3 + 0] = 0.921354f;	val_dir[2577*3 + 1] = 0.372929f;	val_dir[2577*3 + 2] = 0.109685f;
+ 	val_dir[2578*3 + 0] = 0.920537f;	val_dir[2578*3 + 1] = 0.385341f;	val_dir[2578*3 + 2] = 0.064223f;
+ 	val_dir[2579*3 + 0] = 0.917863f;	val_dir[2579*3 + 1] = 0.396350f;	val_dir[2579*3 + 2] = 0.020861f;
+ 	val_dir[2580*3 + 0] = -0.413803f;	val_dir[2580*3 + 1] = -0.910366f;	val_dir[2580*3 + 2] = 0.0f;
+ 	val_dir[2581*3 + 0] = -0.403799f;	val_dir[2581*3 + 1] = -0.913860f;	val_dir[2581*3 + 2] = 0.042505f;
+ 	val_dir[2582*3 + 0] = -0.392419f;	val_dir[2582*3 + 1] = -0.915644f;	val_dir[2582*3 + 2] = 0.087204f;
+ 	val_dir[2583*3 + 0] = -0.379563f;	val_dir[2583*3 + 1] = -0.915416f;	val_dir[2583*3 + 2] = 0.133963f;
+ 	val_dir[2584*3 + 0] = -0.365148f;	val_dir[2584*3 + 1] = -0.912871f;	val_dir[2584*3 + 2] = 0.182574f;
+ 	val_dir[2585*3 + 0] = -0.349121f;	val_dir[2585*3 + 1] = -0.907713f;	val_dir[2585*3 + 2] = 0.232747f;
+ 	val_dir[2586*3 + 0] = -0.331460f;	val_dir[2586*3 + 1] = -0.899676f;	val_dir[2586*3 + 2] = 0.284108f;
+ 	val_dir[2587*3 + 0] = -0.312190f;	val_dir[2587*3 + 1] = -0.888540f;	val_dir[2587*3 + 2] = 0.336204f;
+ 	val_dir[2588*3 + 0] = -0.291386f;	val_dir[2588*3 + 1] = -0.874157f;	val_dir[2588*3 + 2] = 0.388514f;
+ 	val_dir[2589*3 + 0] = -0.269175f;	val_dir[2589*3 + 1] = -0.856465f;	val_dir[2589*3 + 2] = 0.440468f;
+ 	val_dir[2590*3 + 0] = -0.245737f;	val_dir[2590*3 + 1] = -0.835504f;	val_dir[2590*3 + 2] = 0.491473f;
+ 	val_dir[2591*3 + 0] = -0.221297f;	val_dir[2591*3 + 1] = -0.811421f;	val_dir[2591*3 + 2] = 0.540947f;
+ 	val_dir[2592*3 + 0] = -0.196116f;	val_dir[2592*3 + 1] = -0.784465f;	val_dir[2592*3 + 2] = 0.588348f;
+ 	val_dir[2593*3 + 0] = -0.170478f;	val_dir[2593*3 + 1] = -0.754976f;	val_dir[2593*3 + 2] = 0.633205f;
+ 	val_dir[2594*3 + 0] = -0.144673f;	val_dir[2594*3 + 1] = -0.723364f;	val_dir[2594*3 + 2] = 0.675140f;
+ 	val_dir[2595*3 + 0] = -0.118980f;	val_dir[2595*3 + 1] = -0.690085f;	val_dir[2595*3 + 2] = 0.713881f;
+ 	val_dir[2596*3 + 0] = -0.093659f;	val_dir[2596*3 + 1] = -0.655610f;	val_dir[2596*3 + 2] = 0.749269f;
+ 	val_dir[2597*3 + 0] = -0.068934f;	val_dir[2597*3 + 1] = -0.620403f;	val_dir[2597*3 + 2] = 0.781248f;
+ 	val_dir[2598*3 + 0] = -0.044992f;	val_dir[2598*3 + 1] = -0.584898f;	val_dir[2598*3 + 2] = 0.809858f;
+ 	val_dir[2599*3 + 0] = -0.021979f;	val_dir[2599*3 + 1] = -0.549484f;	val_dir[2599*3 + 2] = 0.835215f;
+ 	val_dir[2600*3 + 0] = 0.0f;	val_dir[2600*3 + 1] = -0.514496f;	val_dir[2600*3 + 2] = 0.857493f;
+ 	val_dir[2601*3 + 0] = 0.021668f;	val_dir[2601*3 + 1] = -0.498354f;	val_dir[2601*3 + 2] = 0.866703f;
+ 	val_dir[2602*3 + 0] = 0.043769f;	val_dir[2602*3 + 1] = -0.481457f;	val_dir[2602*3 + 2] = 0.875376f;
+ 	val_dir[2603*3 + 0] = 0.066259f;	val_dir[2603*3 + 1] = -0.463812f;	val_dir[2603*3 + 2] = 0.883452f;
+ 	val_dir[2604*3 + 0] = 0.089087f;	val_dir[2604*3 + 1] = -0.445435f;	val_dir[2604*3 + 2] = 0.890871f;
+ 	val_dir[2605*3 + 0] = 0.112197f;	val_dir[2605*3 + 1] = -0.426348f;	val_dir[2605*3 + 2] = 0.897574f;
+ 	val_dir[2606*3 + 0] = 0.135526f;	val_dir[2606*3 + 1] = -0.406579f;	val_dir[2606*3 + 2] = 0.903508f;
+ 	val_dir[2607*3 + 0] = 0.159009f;	val_dir[2607*3 + 1] = -0.386164f;	val_dir[2607*3 + 2] = 0.908622f;
+ 	val_dir[2608*3 + 0] = 0.182574f;	val_dir[2608*3 + 1] = -0.365148f;	val_dir[2608*3 + 2] = 0.912871f;
+ 	val_dir[2609*3 + 0] = 0.206149f;	val_dir[2609*3 + 1] = -0.343582f;	val_dir[2609*3 + 2] = 0.916217f;
+ 	val_dir[2610*3 + 0] = 0.229658f;	val_dir[2610*3 + 1] = -0.321521f;	val_dir[2610*3 + 2] = 0.918630f;
+ 	val_dir[2611*3 + 0] = 0.253024f;	val_dir[2611*3 + 1] = -0.299028f;	val_dir[2611*3 + 2] = 0.920087f;
+ 	val_dir[2612*3 + 0] = 0.276172f;	val_dir[2612*3 + 1] = -0.276172f;	val_dir[2612*3 + 2] = 0.920575f;
+ 	val_dir[2613*3 + 0] = 0.299028f;	val_dir[2613*3 + 1] = -0.253024f;	val_dir[2613*3 + 2] = 0.920087f;
+ 	val_dir[2614*3 + 0] = 0.321521f;	val_dir[2614*3 + 1] = -0.229658f;	val_dir[2614*3 + 2] = 0.918630f;
+ 	val_dir[2615*3 + 0] = 0.343582f;	val_dir[2615*3 + 1] = -0.206149f;	val_dir[2615*3 + 2] = 0.916217f;
+ 	val_dir[2616*3 + 0] = 0.365148f;	val_dir[2616*3 + 1] = -0.182574f;	val_dir[2616*3 + 2] = 0.912871f;
+ 	val_dir[2617*3 + 0] = 0.386164f;	val_dir[2617*3 + 1] = -0.159009f;	val_dir[2617*3 + 2] = 0.908622f;
+ 	val_dir[2618*3 + 0] = 0.406579f;	val_dir[2618*3 + 1] = -0.135526f;	val_dir[2618*3 + 2] = 0.903508f;
+ 	val_dir[2619*3 + 0] = 0.426348f;	val_dir[2619*3 + 1] = -0.112197f;	val_dir[2619*3 + 2] = 0.897574f;
+ 	val_dir[2620*3 + 0] = 0.445435f;	val_dir[2620*3 + 1] = -0.089087f;	val_dir[2620*3 + 2] = 0.890871f;
+ 	val_dir[2621*3 + 0] = 0.463812f;	val_dir[2621*3 + 1] = -0.066259f;	val_dir[2621*3 + 2] = 0.883452f;
+ 	val_dir[2622*3 + 0] = 0.481457f;	val_dir[2622*3 + 1] = -0.043769f;	val_dir[2622*3 + 2] = 0.875376f;
+ 	val_dir[2623*3 + 0] = 0.498354f;	val_dir[2623*3 + 1] = -0.021668f;	val_dir[2623*3 + 2] = 0.866703f;
+ 	val_dir[2624*3 + 0] = 0.514496f;	val_dir[2624*3 + 1] = 0.0f;	val_dir[2624*3 + 2] = 0.857493f;
+ 	val_dir[2625*3 + 0] = 0.549484f;	val_dir[2625*3 + 1] = 0.021979f;	val_dir[2625*3 + 2] = 0.835215f;
+ 	val_dir[2626*3 + 0] = 0.584898f;	val_dir[2626*3 + 1] = 0.044992f;	val_dir[2626*3 + 2] = 0.809858f;
+ 	val_dir[2627*3 + 0] = 0.620403f;	val_dir[2627*3 + 1] = 0.068934f;	val_dir[2627*3 + 2] = 0.781248f;
+ 	val_dir[2628*3 + 0] = 0.655610f;	val_dir[2628*3 + 1] = 0.093659f;	val_dir[2628*3 + 2] = 0.749269f;
+ 	val_dir[2629*3 + 0] = 0.690085f;	val_dir[2629*3 + 1] = 0.118980f;	val_dir[2629*3 + 2] = 0.713881f;
+ 	val_dir[2630*3 + 0] = 0.723364f;	val_dir[2630*3 + 1] = 0.144673f;	val_dir[2630*3 + 2] = 0.675140f;
+ 	val_dir[2631*3 + 0] = 0.754976f;	val_dir[2631*3 + 1] = 0.170478f;	val_dir[2631*3 + 2] = 0.633205f;
+ 	val_dir[2632*3 + 0] = 0.784465f;	val_dir[2632*3 + 1] = 0.196116f;	val_dir[2632*3 + 2] = 0.588348f;
+ 	val_dir[2633*3 + 0] = 0.811421f;	val_dir[2633*3 + 1] = 0.221297f;	val_dir[2633*3 + 2] = 0.540947f;
+ 	val_dir[2634*3 + 0] = 0.835504f;	val_dir[2634*3 + 1] = 0.245737f;	val_dir[2634*3 + 2] = 0.491473f;
+ 	val_dir[2635*3 + 0] = 0.856465f;	val_dir[2635*3 + 1] = 0.269175f;	val_dir[2635*3 + 2] = 0.440468f;
+ 	val_dir[2636*3 + 0] = 0.874157f;	val_dir[2636*3 + 1] = 0.291386f;	val_dir[2636*3 + 2] = 0.388514f;
+ 	val_dir[2637*3 + 0] = 0.888540f;	val_dir[2637*3 + 1] = 0.312190f;	val_dir[2637*3 + 2] = 0.336204f;
+ 	val_dir[2638*3 + 0] = 0.899676f;	val_dir[2638*3 + 1] = 0.331460f;	val_dir[2638*3 + 2] = 0.284108f;
+ 	val_dir[2639*3 + 0] = 0.907713f;	val_dir[2639*3 + 1] = 0.349121f;	val_dir[2639*3 + 2] = 0.232747f;
+ 	val_dir[2640*3 + 0] = 0.912871f;	val_dir[2640*3 + 1] = 0.365148f;	val_dir[2640*3 + 2] = 0.182574f;
+ 	val_dir[2641*3 + 0] = 0.915416f;	val_dir[2641*3 + 1] = 0.379563f;	val_dir[2641*3 + 2] = 0.133963f;
+ 	val_dir[2642*3 + 0] = 0.915644f;	val_dir[2642*3 + 1] = 0.392419f;	val_dir[2642*3 + 2] = 0.087204f;
+ 	val_dir[2643*3 + 0] = 0.913860f;	val_dir[2643*3 + 1] = 0.403799f;	val_dir[2643*3 + 2] = 0.042505f;
+ 	val_dir[2644*3 + 0] = 0.910366f;	val_dir[2644*3 + 1] = 0.413803f;	val_dir[2644*3 + 2] = 0.0f;
+ 	val_dir[2645*3 + 0] = -0.421637f;	val_dir[2645*3 + 1] = -0.906520f;	val_dir[2645*3 + 2] = 0.021082f;
+ 	val_dir[2646*3 + 0] = -0.411298f;	val_dir[2646*3 + 1] = -0.909185f;	val_dir[2646*3 + 2] = 0.064942f;
+ 	val_dir[2647*3 + 0] = -0.399507f;	val_dir[2647*3 + 1] = -0.909988f;	val_dir[2647*3 + 2] = 0.110974f;
+ 	val_dir[2648*3 + 0] = -0.386164f;	val_dir[2648*3 + 1] = -0.908622f;	val_dir[2648*3 + 2] = 0.159009f;
+ 	val_dir[2649*3 + 0] = -0.371191f;	val_dir[2649*3 + 1] = -0.904777f;	val_dir[2649*3 + 2] = 0.208795f;
+ 	val_dir[2650*3 + 0] = -0.354540f;	val_dir[2650*3 + 1] = -0.898167f;	val_dir[2650*3 + 2] = 0.259996f;
+ 	val_dir[2651*3 + 0] = -0.336204f;	val_dir[2651*3 + 1] = -0.888540f;	val_dir[2651*3 + 2] = 0.312190f;
+ 	val_dir[2652*3 + 0] = -0.316228f;	val_dir[2652*3 + 1] = -0.875708f;	val_dir[2652*3 + 2] = 0.364878f;
+ 	val_dir[2653*3 + 0] = -0.294706f;	val_dir[2653*3 + 1] = -0.859559f;	val_dir[2653*3 + 2] = 0.41750f;
+ 	val_dir[2654*3 + 0] = -0.271791f;	val_dir[2654*3 + 1] = -0.840083f;	val_dir[2654*3 + 2] = 0.469458f;
+ 	val_dir[2655*3 + 0] = -0.247689f;	val_dir[2655*3 + 1] = -0.817373f;	val_dir[2655*3 + 2] = 0.520146f;
+ 	val_dir[2656*3 + 0] = -0.222647f;	val_dir[2656*3 + 1] = -0.791633f;	val_dir[2656*3 + 2] = 0.568986f;
+ 	val_dir[2657*3 + 0] = -0.196946f;	val_dir[2657*3 + 1] = -0.763167f;	val_dir[2657*3 + 2] = 0.615457f;
+ 	val_dir[2658*3 + 0] = -0.170884f;	val_dir[2658*3 + 1] = -0.732361f;	val_dir[2658*3 + 2] = 0.659125f;
+ 	val_dir[2659*3 + 0] = -0.144757f;	val_dir[2659*3 + 1] = -0.699659f;	val_dir[2659*3 + 2] = 0.699659f;
+ 	val_dir[2660*3 + 0] = -0.118846f;	val_dir[2660*3 + 1] = -0.665536f;	val_dir[2660*3 + 2] = 0.736843f;
+ 	val_dir[2661*3 + 0] = -0.093403f;	val_dir[2661*3 + 1] = -0.630470f;	val_dir[2661*3 + 2] = 0.770574f;
+ 	val_dir[2662*3 + 0] = -0.068644f;	val_dir[2662*3 + 1] = -0.594917f;	val_dir[2662*3 + 2] = 0.800850f;
+ 	val_dir[2663*3 + 0] = -0.044744f;	val_dir[2663*3 + 1] = -0.559297f;	val_dir[2663*3 + 2] = 0.827759f;
+ 	val_dir[2664*3 + 0] = -0.021832f;	val_dir[2664*3 + 1] = -0.523973f;	val_dir[2664*3 + 2] = 0.851455f;
+ 	val_dir[2665*3 + 0] = 0.0f;	val_dir[2665*3 + 1] = -0.489251f;	val_dir[2665*3 + 2] = 0.872143f;
+ 	val_dir[2666*3 + 0] = 0.021487f;	val_dir[2666*3 + 1] = -0.472709f;	val_dir[2666*3 + 2] = 0.880957f;
+ 	val_dir[2667*3 + 0] = 0.043376f;	val_dir[2667*3 + 1] = -0.455447f;	val_dir[2667*3 + 2] = 0.889206f;
+ 	val_dir[2668*3 + 0] = 0.065622f;	val_dir[2668*3 + 1] = -0.437479f;	val_dir[2668*3 + 2] = 0.896831f;
+ 	val_dir[2669*3 + 0] = 0.088173f;	val_dir[2669*3 + 1] = -0.418823f;	val_dir[2669*3 + 2] = 0.903777f;
+ 	val_dir[2670*3 + 0] = 0.110974f;	val_dir[2670*3 + 1] = -0.399507f;	val_dir[2670*3 + 2] = 0.909988f;
+ 	val_dir[2671*3 + 0] = 0.133963f;	val_dir[2671*3 + 1] = -0.379563f;	val_dir[2671*3 + 2] = 0.915416f;
+ 	val_dir[2672*3 + 0] = 0.157075f;	val_dir[2672*3 + 1] = -0.359030f;	val_dir[2672*3 + 2] = 0.920014f;
+ 	val_dir[2673*3 + 0] = 0.180242f;	val_dir[2673*3 + 1] = -0.337954f;	val_dir[2673*3 + 2] = 0.923742f;
+ 	val_dir[2674*3 + 0] = 0.203393f;	val_dir[2674*3 + 1] = -0.316389f;	val_dir[2674*3 + 2] = 0.926568f;
+ 	val_dir[2675*3 + 0] = 0.226455f;	val_dir[2675*3 + 1] = -0.294392f;	val_dir[2675*3 + 2] = 0.928467f;
+ 	val_dir[2676*3 + 0] = 0.249357f;	val_dir[2676*3 + 1] = -0.272026f;	val_dir[2676*3 + 2] = 0.929421f;
+ 	val_dir[2677*3 + 0] = 0.272026f;	val_dir[2677*3 + 1] = -0.249357f;	val_dir[2677*3 + 2] = 0.929421f;
+ 	val_dir[2678*3 + 0] = 0.294392f;	val_dir[2678*3 + 1] = -0.226455f;	val_dir[2678*3 + 2] = 0.928467f;
+ 	val_dir[2679*3 + 0] = 0.316389f;	val_dir[2679*3 + 1] = -0.203393f;	val_dir[2679*3 + 2] = 0.926568f;
+ 	val_dir[2680*3 + 0] = 0.337954f;	val_dir[2680*3 + 1] = -0.180242f;	val_dir[2680*3 + 2] = 0.923742f;
+ 	val_dir[2681*3 + 0] = 0.359030f;	val_dir[2681*3 + 1] = -0.157075f;	val_dir[2681*3 + 2] = 0.920014f;
+ 	val_dir[2682*3 + 0] = 0.379563f;	val_dir[2682*3 + 1] = -0.133963f;	val_dir[2682*3 + 2] = 0.915416f;
+ 	val_dir[2683*3 + 0] = 0.399507f;	val_dir[2683*3 + 1] = -0.110974f;	val_dir[2683*3 + 2] = 0.909988f;
+ 	val_dir[2684*3 + 0] = 0.418823f;	val_dir[2684*3 + 1] = -0.088173f;	val_dir[2684*3 + 2] = 0.903777f;
+ 	val_dir[2685*3 + 0] = 0.437479f;	val_dir[2685*3 + 1] = -0.065622f;	val_dir[2685*3 + 2] = 0.896831f;
+ 	val_dir[2686*3 + 0] = 0.455447f;	val_dir[2686*3 + 1] = -0.043376f;	val_dir[2686*3 + 2] = 0.889206f;
+ 	val_dir[2687*3 + 0] = 0.472709f;	val_dir[2687*3 + 1] = -0.021487f;	val_dir[2687*3 + 2] = 0.880957f;
+ 	val_dir[2688*3 + 0] = 0.489251f;	val_dir[2688*3 + 1] = 0.0f;	val_dir[2688*3 + 2] = 0.872143f;
+ 	val_dir[2689*3 + 0] = 0.523973f;	val_dir[2689*3 + 1] = 0.021832f;	val_dir[2689*3 + 2] = 0.851455f;
+ 	val_dir[2690*3 + 0] = 0.559297f;	val_dir[2690*3 + 1] = 0.044744f;	val_dir[2690*3 + 2] = 0.827759f;
+ 	val_dir[2691*3 + 0] = 0.594917f;	val_dir[2691*3 + 1] = 0.068644f;	val_dir[2691*3 + 2] = 0.800850f;
+ 	val_dir[2692*3 + 0] = 0.630470f;	val_dir[2692*3 + 1] = 0.093403f;	val_dir[2692*3 + 2] = 0.770574f;
+ 	val_dir[2693*3 + 0] = 0.665536f;	val_dir[2693*3 + 1] = 0.118846f;	val_dir[2693*3 + 2] = 0.736843f;
+ 	val_dir[2694*3 + 0] = 0.699659f;	val_dir[2694*3 + 1] = 0.144757f;	val_dir[2694*3 + 2] = 0.699659f;
+ 	val_dir[2695*3 + 0] = 0.732361f;	val_dir[2695*3 + 1] = 0.170884f;	val_dir[2695*3 + 2] = 0.659125f;
+ 	val_dir[2696*3 + 0] = 0.763167f;	val_dir[2696*3 + 1] = 0.196946f;	val_dir[2696*3 + 2] = 0.615457f;
+ 	val_dir[2697*3 + 0] = 0.791633f;	val_dir[2697*3 + 1] = 0.222647f;	val_dir[2697*3 + 2] = 0.568986f;
+ 	val_dir[2698*3 + 0] = 0.817373f;	val_dir[2698*3 + 1] = 0.247689f;	val_dir[2698*3 + 2] = 0.520146f;
+ 	val_dir[2699*3 + 0] = 0.840083f;	val_dir[2699*3 + 1] = 0.271791f;	val_dir[2699*3 + 2] = 0.469458f;
+ 	val_dir[2700*3 + 0] = 0.859559f;	val_dir[2700*3 + 1] = 0.294706f;	val_dir[2700*3 + 2] = 0.41750f;
+ 	val_dir[2701*3 + 0] = 0.875708f;	val_dir[2701*3 + 1] = 0.316228f;	val_dir[2701*3 + 2] = 0.364878f;
+ 	val_dir[2702*3 + 0] = 0.888540f;	val_dir[2702*3 + 1] = 0.336204f;	val_dir[2702*3 + 2] = 0.312190f;
+ 	val_dir[2703*3 + 0] = 0.898167f;	val_dir[2703*3 + 1] = 0.354540f;	val_dir[2703*3 + 2] = 0.259996f;
+ 	val_dir[2704*3 + 0] = 0.904777f;	val_dir[2704*3 + 1] = 0.371191f;	val_dir[2704*3 + 2] = 0.208795f;
+ 	val_dir[2705*3 + 0] = 0.908622f;	val_dir[2705*3 + 1] = 0.386164f;	val_dir[2705*3 + 2] = 0.159009f;
+ 	val_dir[2706*3 + 0] = 0.909988f;	val_dir[2706*3 + 1] = 0.399507f;	val_dir[2706*3 + 2] = 0.110974f;
+ 	val_dir[2707*3 + 0] = 0.909185f;	val_dir[2707*3 + 1] = 0.411298f;	val_dir[2707*3 + 2] = 0.064942f;
+ 	val_dir[2708*3 + 0] = 0.906520f;	val_dir[2708*3 + 1] = 0.421637f;	val_dir[2708*3 + 2] = 0.021082f;
+ 	val_dir[2709*3 + 0] = -0.438835f;	val_dir[2709*3 + 1] = -0.898567f;	val_dir[2709*3 + 2] = 0.0f;
+ 	val_dir[2710*3 + 0] = -0.429537f;	val_dir[2710*3 + 1] = -0.902027f;	val_dir[2710*3 + 2] = 0.042954f;
+ 	val_dir[2711*3 + 0] = -0.418823f;	val_dir[2711*3 + 1] = -0.903777f;	val_dir[2711*3 + 2] = 0.088173f;
+ 	val_dir[2712*3 + 0] = -0.406579f;	val_dir[2712*3 + 1] = -0.903508f;	val_dir[2712*3 + 2] = 0.135526f;
+ 	val_dir[2713*3 + 0] = -0.392703f;	val_dir[2713*3 + 1] = -0.900907f;	val_dir[2713*3 + 2] = 0.184801f;
+ 	val_dir[2714*3 + 0] = -0.377124f;	val_dir[2714*3 + 1] = -0.895669f;	val_dir[2714*3 + 2] = 0.235702f;
+ 	val_dir[2715*3 + 0] = -0.359804f;	val_dir[2715*3 + 1] = -0.887517f;	val_dir[2715*3 + 2] = 0.287843f;
+ 	val_dir[2716*3 + 0] = -0.340755f;	val_dir[2716*3 + 1] = -0.876226f;	val_dir[2716*3 + 2] = 0.340755f;
+ 	val_dir[2717*3 + 0] = -0.320038f;	val_dir[2717*3 + 1] = -0.861640f;	val_dir[2717*3 + 2] = 0.393893f;
+ 	val_dir[2718*3 + 0] = -0.297775f;	val_dir[2718*3 + 1] = -0.843696f;	val_dir[2718*3 + 2] = 0.446662f;
+ 	val_dir[2719*3 + 0] = -0.274145f;	val_dir[2719*3 + 1] = -0.822434f;	val_dir[2719*3 + 2] = 0.498445f;
+ 	val_dir[2720*3 + 0] = -0.249377f;	val_dir[2720*3 + 1] = -0.798007f;	val_dir[2720*3 + 2] = 0.548630f;
+ 	val_dir[2721*3 + 0] = -0.223745f;	val_dir[2721*3 + 1] = -0.770677f;	val_dir[2721*3 + 2] = 0.596653f;
+ 	val_dir[2722*3 + 0] = -0.197546f;	val_dir[2722*3 + 1] = -0.740797f;	val_dir[2722*3 + 2] = 0.642024f;
+ 	val_dir[2723*3 + 0] = -0.171088f;	val_dir[2723*3 + 1] = -0.708794f;	val_dir[2723*3 + 2] = 0.684353f;
+ 	val_dir[2724*3 + 0] = -0.144673f;	val_dir[2724*3 + 1] = -0.675140f;	val_dir[2724*3 + 2] = 0.723364f;
+ 	val_dir[2725*3 + 0] = -0.118578f;	val_dir[2725*3 + 1] = -0.640321f;	val_dir[2725*3 + 2] = 0.758899f;
+ 	val_dir[2726*3 + 0] = -0.093048f;	val_dir[2726*3 + 1] = -0.604815f;	val_dir[2726*3 + 2] = 0.790912f;
+ 	val_dir[2727*3 + 0] = -0.068288f;	val_dir[2727*3 + 1] = -0.569064f;	val_dir[2727*3 + 2] = 0.819453f;
+ 	val_dir[2728*3 + 0] = -0.044455f;	val_dir[2728*3 + 1] = -0.533465f;	val_dir[2728*3 + 2] = 0.844653f;
+ 	val_dir[2729*3 + 0] = -0.021668f;	val_dir[2729*3 + 1] = -0.498354f;	val_dir[2729*3 + 2] = 0.866703f;
+ 	val_dir[2730*3 + 0] = 0.0f;	val_dir[2730*3 + 1] = -0.464007f;	val_dir[2730*3 + 2] = 0.885832f;
+ 	val_dir[2731*3 + 0] = 0.021291f;	val_dir[2731*3 + 1] = -0.447112f;	val_dir[2731*3 + 2] = 0.894224f;
+ 	val_dir[2732*3 + 0] = 0.042954f;	val_dir[2732*3 + 1] = -0.429537f;	val_dir[2732*3 + 2] = 0.902027f;
+ 	val_dir[2733*3 + 0] = 0.064942f;	val_dir[2733*3 + 1] = -0.411298f;	val_dir[2733*3 + 2] = 0.909185f;
+ 	val_dir[2734*3 + 0] = 0.087204f;	val_dir[2734*3 + 1] = -0.392419f;	val_dir[2734*3 + 2] = 0.915644f;
+ 	val_dir[2735*3 + 0] = 0.109685f;	val_dir[2735*3 + 1] = -0.372929f;	val_dir[2735*3 + 2] = 0.921354f;
+ 	val_dir[2736*3 + 0] = 0.132324f;	val_dir[2736*3 + 1] = -0.352865f;	val_dir[2736*3 + 2] = 0.926270f;
+ 	val_dir[2737*3 + 0] = 0.155059f;	val_dir[2737*3 + 1] = -0.332269f;	val_dir[2737*3 + 2] = 0.930352f;
+ 	val_dir[2738*3 + 0] = 0.177822f;	val_dir[2738*3 + 1] = -0.311188f;	val_dir[2738*3 + 2] = 0.933564f;
+ 	val_dir[2739*3 + 0] = 0.200545f;	val_dir[2739*3 + 1] = -0.289677f;	val_dir[2739*3 + 2] = 0.935879f;
+ 	val_dir[2740*3 + 0] = 0.223161f;	val_dir[2740*3 + 1] = -0.267793f;	val_dir[2740*3 + 2] = 0.937276f;
+ 	val_dir[2741*3 + 0] = 0.245599f;	val_dir[2741*3 + 1] = -0.245599f;	val_dir[2741*3 + 2] = 0.937743f;
+ 	val_dir[2742*3 + 0] = 0.267793f;	val_dir[2742*3 + 1] = -0.223161f;	val_dir[2742*3 + 2] = 0.937276f;
+ 	val_dir[2743*3 + 0] = 0.289677f;	val_dir[2743*3 + 1] = -0.200545f;	val_dir[2743*3 + 2] = 0.935879f;
+ 	val_dir[2744*3 + 0] = 0.311188f;	val_dir[2744*3 + 1] = -0.177822f;	val_dir[2744*3 + 2] = 0.933564f;
+ 	val_dir[2745*3 + 0] = 0.332269f;	val_dir[2745*3 + 1] = -0.155059f;	val_dir[2745*3 + 2] = 0.930352f;
+ 	val_dir[2746*3 + 0] = 0.352865f;	val_dir[2746*3 + 1] = -0.132324f;	val_dir[2746*3 + 2] = 0.926270f;
+ 	val_dir[2747*3 + 0] = 0.372929f;	val_dir[2747*3 + 1] = -0.109685f;	val_dir[2747*3 + 2] = 0.921354f;
+ 	val_dir[2748*3 + 0] = 0.392419f;	val_dir[2748*3 + 1] = -0.087204f;	val_dir[2748*3 + 2] = 0.915644f;
+ 	val_dir[2749*3 + 0] = 0.411298f;	val_dir[2749*3 + 1] = -0.064942f;	val_dir[2749*3 + 2] = 0.909185f;
+ 	val_dir[2750*3 + 0] = 0.429537f;	val_dir[2750*3 + 1] = -0.042954f;	val_dir[2750*3 + 2] = 0.902027f;
+ 	val_dir[2751*3 + 0] = 0.447112f;	val_dir[2751*3 + 1] = -0.021291f;	val_dir[2751*3 + 2] = 0.894224f;
+ 	val_dir[2752*3 + 0] = 0.464007f;	val_dir[2752*3 + 1] = 0.0f;	val_dir[2752*3 + 2] = 0.885832f;
+ 	val_dir[2753*3 + 0] = 0.498354f;	val_dir[2753*3 + 1] = 0.021668f;	val_dir[2753*3 + 2] = 0.866703f;
+ 	val_dir[2754*3 + 0] = 0.533465f;	val_dir[2754*3 + 1] = 0.044455f;	val_dir[2754*3 + 2] = 0.844653f;
+ 	val_dir[2755*3 + 0] = 0.569064f;	val_dir[2755*3 + 1] = 0.068288f;	val_dir[2755*3 + 2] = 0.819453f;
+ 	val_dir[2756*3 + 0] = 0.604815f;	val_dir[2756*3 + 1] = 0.093048f;	val_dir[2756*3 + 2] = 0.790912f;
+ 	val_dir[2757*3 + 0] = 0.640321f;	val_dir[2757*3 + 1] = 0.118578f;	val_dir[2757*3 + 2] = 0.758899f;
+ 	val_dir[2758*3 + 0] = 0.675140f;	val_dir[2758*3 + 1] = 0.144673f;	val_dir[2758*3 + 2] = 0.723364f;
+ 	val_dir[2759*3 + 0] = 0.708794f;	val_dir[2759*3 + 1] = 0.171088f;	val_dir[2759*3 + 2] = 0.684353f;
+ 	val_dir[2760*3 + 0] = 0.740797f;	val_dir[2760*3 + 1] = 0.197546f;	val_dir[2760*3 + 2] = 0.642024f;
+ 	val_dir[2761*3 + 0] = 0.770677f;	val_dir[2761*3 + 1] = 0.223745f;	val_dir[2761*3 + 2] = 0.596653f;
+ 	val_dir[2762*3 + 0] = 0.798007f;	val_dir[2762*3 + 1] = 0.249377f;	val_dir[2762*3 + 2] = 0.548630f;
+ 	val_dir[2763*3 + 0] = 0.822434f;	val_dir[2763*3 + 1] = 0.274145f;	val_dir[2763*3 + 2] = 0.498445f;
+ 	val_dir[2764*3 + 0] = 0.843696f;	val_dir[2764*3 + 1] = 0.297775f;	val_dir[2764*3 + 2] = 0.446662f;
+ 	val_dir[2765*3 + 0] = 0.861640f;	val_dir[2765*3 + 1] = 0.320038f;	val_dir[2765*3 + 2] = 0.393893f;
+ 	val_dir[2766*3 + 0] = 0.876226f;	val_dir[2766*3 + 1] = 0.340755f;	val_dir[2766*3 + 2] = 0.340755f;
+ 	val_dir[2767*3 + 0] = 0.887517f;	val_dir[2767*3 + 1] = 0.359804f;	val_dir[2767*3 + 2] = 0.287843f;
+ 	val_dir[2768*3 + 0] = 0.895669f;	val_dir[2768*3 + 1] = 0.377124f;	val_dir[2768*3 + 2] = 0.235702f;
+ 	val_dir[2769*3 + 0] = 0.900907f;	val_dir[2769*3 + 1] = 0.392703f;	val_dir[2769*3 + 2] = 0.184801f;
+ 	val_dir[2770*3 + 0] = 0.903508f;	val_dir[2770*3 + 1] = 0.406579f;	val_dir[2770*3 + 2] = 0.135526f;
+ 	val_dir[2771*3 + 0] = 0.903777f;	val_dir[2771*3 + 1] = 0.418823f;	val_dir[2771*3 + 2] = 0.088173f;
+ 	val_dir[2772*3 + 0] = 0.902027f;	val_dir[2772*3 + 1] = 0.429537f;	val_dir[2772*3 + 2] = 0.042954f;
+ 	val_dir[2773*3 + 0] = 0.898567f;	val_dir[2773*3 + 1] = 0.438835f;	val_dir[2773*3 + 2] = 0.0f;
+ 	val_dir[2774*3 + 0] = -0.447112f;	val_dir[2774*3 + 1] = -0.894224f;	val_dir[2774*3 + 2] = 0.021291f;
+ 	val_dir[2775*3 + 0] = -0.437479f;	val_dir[2775*3 + 1] = -0.896831f;	val_dir[2775*3 + 2] = 0.065622f;
+ 	val_dir[2776*3 + 0] = -0.426348f;	val_dir[2776*3 + 1] = -0.897574f;	val_dir[2776*3 + 2] = 0.112197f;
+ 	val_dir[2777*3 + 0] = -0.413602f;	val_dir[2777*3 + 1] = -0.896137f;	val_dir[2777*3 + 2] = 0.160845f;
+ 	val_dir[2778*3 + 0] = -0.399145f;	val_dir[2778*3 + 1] = -0.892206f;	val_dir[2778*3 + 2] = 0.211312f;
+ 	val_dir[2779*3 + 0] = -0.382911f;	val_dir[2779*3 + 1] = -0.885482f;	val_dir[2779*3 + 2] = 0.263251f;
+ 	val_dir[2780*3 + 0] = -0.364878f;	val_dir[2780*3 + 1] = -0.875708f;	val_dir[2780*3 + 2] = 0.316228f;
+ 	val_dir[2781*3 + 0] = -0.345075f;	val_dir[2781*3 + 1] = -0.862687f;	val_dir[2781*3 + 2] = 0.369723f;
+ 	val_dir[2782*3 + 0] = -0.323587f;	val_dir[2782*3 + 1] = -0.846305f;	val_dir[2782*3 + 2] = 0.423153f;
+ 	val_dir[2783*3 + 0] = -0.300564f;	val_dir[2783*3 + 1] = -0.826551f;	val_dir[2783*3 + 2] = 0.475893f;
+ 	val_dir[2784*3 + 0] = -0.276211f;	val_dir[2784*3 + 1] = -0.803523f;	val_dir[2784*3 + 2] = 0.527312f;
+ 	val_dir[2785*3 + 0] = -0.250785f;	val_dir[2785*3 + 1] = -0.777433f;	val_dir[2785*3 + 2] = 0.576805f;
+ 	val_dir[2786*3 + 0] = -0.224579f;	val_dir[2786*3 + 1] = -0.748598f;	val_dir[2786*3 + 2] = 0.623831f;
+ 	val_dir[2787*3 + 0] = -0.197908f;	val_dir[2787*3 + 1] = -0.717418f;	val_dir[2787*3 + 2] = 0.667940f;
+ 	val_dir[2788*3 + 0] = -0.171088f;	val_dir[2788*3 + 1] = -0.684353f;	val_dir[2788*3 + 2] = 0.708794f;
+ 	val_dir[2789*3 + 0] = -0.144421f;	val_dir[2789*3 + 1] = -0.649895f;	val_dir[2789*3 + 2] = 0.746176f;
+ 	val_dir[2790*3 + 0] = -0.118180f;	val_dir[2790*3 + 1] = -0.614535f;	val_dir[2790*3 + 2] = 0.779987f;
+ 	val_dir[2791*3 + 0] = -0.092599f;	val_dir[2791*3 + 1] = -0.578741f;	val_dir[2791*3 + 2] = 0.810237f;
+ 	val_dir[2792*3 + 0] = -0.067867f;	val_dir[2792*3 + 1] = -0.542936f;	val_dir[2792*3 + 2] = 0.837027f;
+ 	val_dir[2793*3 + 0] = -0.044130f;	val_dir[2793*3 + 1] = -0.507490f;	val_dir[2793*3 + 2] = 0.860527f;
+ 	val_dir[2794*3 + 0] = -0.021487f;	val_dir[2794*3 + 1] = -0.472709f;	val_dir[2794*3 + 2] = 0.880957f;
+ 	val_dir[2795*3 + 0] = 0.0f;	val_dir[2795*3 + 1] = -0.438835f;	val_dir[2795*3 + 2] = 0.898567f;
+ 	val_dir[2796*3 + 0] = 0.021082f;	val_dir[2796*3 + 1] = -0.421637f;	val_dir[2796*3 + 2] = 0.906520f;
+ 	val_dir[2797*3 + 0] = 0.042505f;	val_dir[2797*3 + 1] = -0.403799f;	val_dir[2797*3 + 2] = 0.913860f;
+ 	val_dir[2798*3 + 0] = 0.064223f;	val_dir[2798*3 + 1] = -0.385341f;	val_dir[2798*3 + 2] = 0.920537f;
+ 	val_dir[2799*3 + 0] = 0.086186f;	val_dir[2799*3 + 1] = -0.366291f;	val_dir[2799*3 + 2] = 0.92650f;
+ 	val_dir[2800*3 + 0] = 0.108338f;	val_dir[2800*3 + 1] = -0.346681f;	val_dir[2800*3 + 2] = 0.931705f;
+ 	val_dir[2801*3 + 0] = 0.130620f;	val_dir[2801*3 + 1] = -0.326550f;	val_dir[2801*3 + 2] = 0.936111f;
+ 	val_dir[2802*3 + 0] = 0.152971f;	val_dir[2802*3 + 1] = -0.305942f;	val_dir[2802*3 + 2] = 0.939680f;
+ 	val_dir[2803*3 + 0] = 0.175327f;	val_dir[2803*3 + 1] = -0.284907f;	val_dir[2803*3 + 2] = 0.942384f;
+ 	val_dir[2804*3 + 0] = 0.197623f;	val_dir[2804*3 + 1] = -0.263498f;	val_dir[2804*3 + 2] = 0.94420f;
+ 	val_dir[2805*3 + 0] = 0.219793f;	val_dir[2805*3 + 1] = -0.241773f;	val_dir[2805*3 + 2] = 0.945112f;
+ 	val_dir[2806*3 + 0] = 0.241773f;	val_dir[2806*3 + 1] = -0.219793f;	val_dir[2806*3 + 2] = 0.945112f;
+ 	val_dir[2807*3 + 0] = 0.263498f;	val_dir[2807*3 + 1] = -0.197623f;	val_dir[2807*3 + 2] = 0.94420f;
+ 	val_dir[2808*3 + 0] = 0.284907f;	val_dir[2808*3 + 1] = -0.175327f;	val_dir[2808*3 + 2] = 0.942384f;
+ 	val_dir[2809*3 + 0] = 0.305942f;	val_dir[2809*3 + 1] = -0.152971f;	val_dir[2809*3 + 2] = 0.939680f;
+ 	val_dir[2810*3 + 0] = 0.326550f;	val_dir[2810*3 + 1] = -0.130620f;	val_dir[2810*3 + 2] = 0.936111f;
+ 	val_dir[2811*3 + 0] = 0.346681f;	val_dir[2811*3 + 1] = -0.108338f;	val_dir[2811*3 + 2] = 0.931705f;
+ 	val_dir[2812*3 + 0] = 0.366291f;	val_dir[2812*3 + 1] = -0.086186f;	val_dir[2812*3 + 2] = 0.92650f;
+ 	val_dir[2813*3 + 0] = 0.385341f;	val_dir[2813*3 + 1] = -0.064223f;	val_dir[2813*3 + 2] = 0.920537f;
+ 	val_dir[2814*3 + 0] = 0.403799f;	val_dir[2814*3 + 1] = -0.042505f;	val_dir[2814*3 + 2] = 0.913860f;
+ 	val_dir[2815*3 + 0] = 0.421637f;	val_dir[2815*3 + 1] = -0.021082f;	val_dir[2815*3 + 2] = 0.906520f;
+ 	val_dir[2816*3 + 0] = 0.438835f;	val_dir[2816*3 + 1] = 0.0f;	val_dir[2816*3 + 2] = 0.898567f;
+ 	val_dir[2817*3 + 0] = 0.472709f;	val_dir[2817*3 + 1] = 0.021487f;	val_dir[2817*3 + 2] = 0.880957f;
+ 	val_dir[2818*3 + 0] = 0.507490f;	val_dir[2818*3 + 1] = 0.044130f;	val_dir[2818*3 + 2] = 0.860527f;
+ 	val_dir[2819*3 + 0] = 0.542936f;	val_dir[2819*3 + 1] = 0.067867f;	val_dir[2819*3 + 2] = 0.837027f;
+ 	val_dir[2820*3 + 0] = 0.578741f;	val_dir[2820*3 + 1] = 0.092599f;	val_dir[2820*3 + 2] = 0.810237f;
+ 	val_dir[2821*3 + 0] = 0.614535f;	val_dir[2821*3 + 1] = 0.118180f;	val_dir[2821*3 + 2] = 0.779987f;
+ 	val_dir[2822*3 + 0] = 0.649895f;	val_dir[2822*3 + 1] = 0.144421f;	val_dir[2822*3 + 2] = 0.746176f;
+ 	val_dir[2823*3 + 0] = 0.684353f;	val_dir[2823*3 + 1] = 0.171088f;	val_dir[2823*3 + 2] = 0.708794f;
+ 	val_dir[2824*3 + 0] = 0.717418f;	val_dir[2824*3 + 1] = 0.197908f;	val_dir[2824*3 + 2] = 0.667940f;
+ 	val_dir[2825*3 + 0] = 0.748598f;	val_dir[2825*3 + 1] = 0.224579f;	val_dir[2825*3 + 2] = 0.623831f;
+ 	val_dir[2826*3 + 0] = 0.777433f;	val_dir[2826*3 + 1] = 0.250785f;	val_dir[2826*3 + 2] = 0.576805f;
+ 	val_dir[2827*3 + 0] = 0.803523f;	val_dir[2827*3 + 1] = 0.276211f;	val_dir[2827*3 + 2] = 0.527312f;
+ 	val_dir[2828*3 + 0] = 0.826551f;	val_dir[2828*3 + 1] = 0.300564f;	val_dir[2828*3 + 2] = 0.475893f;
+ 	val_dir[2829*3 + 0] = 0.846305f;	val_dir[2829*3 + 1] = 0.323587f;	val_dir[2829*3 + 2] = 0.423153f;
+ 	val_dir[2830*3 + 0] = 0.862687f;	val_dir[2830*3 + 1] = 0.345075f;	val_dir[2830*3 + 2] = 0.369723f;
+ 	val_dir[2831*3 + 0] = 0.875708f;	val_dir[2831*3 + 1] = 0.364878f;	val_dir[2831*3 + 2] = 0.316228f;
+ 	val_dir[2832*3 + 0] = 0.885482f;	val_dir[2832*3 + 1] = 0.382911f;	val_dir[2832*3 + 2] = 0.263251f;
+ 	val_dir[2833*3 + 0] = 0.892206f;	val_dir[2833*3 + 1] = 0.399145f;	val_dir[2833*3 + 2] = 0.211312f;
+ 	val_dir[2834*3 + 0] = 0.896137f;	val_dir[2834*3 + 1] = 0.413602f;	val_dir[2834*3 + 2] = 0.160845f;
+ 	val_dir[2835*3 + 0] = 0.897574f;	val_dir[2835*3 + 1] = 0.426348f;	val_dir[2835*3 + 2] = 0.112197f;
+ 	val_dir[2836*3 + 0] = 0.896831f;	val_dir[2836*3 + 1] = 0.437479f;	val_dir[2836*3 + 2] = 0.065622f;
+ 	val_dir[2837*3 + 0] = 0.894224f;	val_dir[2837*3 + 1] = 0.447112f;	val_dir[2837*3 + 2] = 0.021291f;
+ 	val_dir[2838*3 + 0] = -0.464007f;	val_dir[2838*3 + 1] = -0.885832f;	val_dir[2838*3 + 2] = 0.0f;
+ 	val_dir[2839*3 + 0] = -0.455447f;	val_dir[2839*3 + 1] = -0.889206f;	val_dir[2839*3 + 2] = 0.043376f;
+ 	val_dir[2840*3 + 0] = -0.445435f;	val_dir[2840*3 + 1] = -0.890871f;	val_dir[2840*3 + 2] = 0.089087f;
+ 	val_dir[2841*3 + 0] = -0.433840f;	val_dir[2841*3 + 1] = -0.890513f;	val_dir[2841*3 + 2] = 0.137002f;
+ 	val_dir[2842*3 + 0] = -0.420542f;	val_dir[2842*3 + 1] = -0.887812f;	val_dir[2842*3 + 2] = 0.186908f;
+ 	val_dir[2843*3 + 0] = -0.405452f;	val_dir[2843*3 + 1] = -0.882454f;	val_dir[2843*3 + 2] = 0.238501f;
+ 	val_dir[2844*3 + 0] = -0.388514f;	val_dir[2844*3 + 1] = -0.874157f;	val_dir[2844*3 + 2] = 0.291386f;
+ 	val_dir[2845*3 + 0] = -0.369723f;	val_dir[2845*3 + 1] = -0.862687f;	val_dir[2845*3 + 2] = 0.345075f;
+ 	val_dir[2846*3 + 0] = -0.349128f;	val_dir[2846*3 + 1] = -0.847883f;	val_dir[2846*3 + 2] = 0.399004f;
+ 	val_dir[2847*3 + 0] = -0.326844f;	val_dir[2847*3 + 1] = -0.829680f;	val_dir[2847*3 + 2] = 0.452553f;
+ 	val_dir[2848*3 + 0] = -0.303046f;	val_dir[2848*3 + 1] = -0.808122f;	val_dir[2848*3 + 2] = 0.505076f;
+ 	val_dir[2849*3 + 0] = -0.277969f;	val_dir[2849*3 + 1] = -0.783368f;	val_dir[2849*3 + 2] = 0.555939f;
+ 	val_dir[2850*3 + 0] = -0.251896f;	val_dir[2850*3 + 1] = -0.755689f;	val_dir[2850*3 + 2] = 0.604551f;
+ 	val_dir[2851*3 + 0] = -0.225141f;	val_dir[2851*3 + 1] = -0.725454f;	val_dir[2851*3 + 2] = 0.650407f;
+ 	val_dir[2852*3 + 0] = -0.198030f;	val_dir[2852*3 + 1] = -0.693103f;	val_dir[2852*3 + 2] = 0.693103f;
+ 	val_dir[2853*3 + 0] = -0.170884f;	val_dir[2853*3 + 1] = -0.659125f;	val_dir[2853*3 + 2] = 0.732361f;
+ 	val_dir[2854*3 + 0] = -0.144005f;	val_dir[2854*3 + 1] = -0.624020f;	val_dir[2854*3 + 2] = 0.768025f;
+ 	val_dir[2855*3 + 0] = -0.117655f;	val_dir[2855*3 + 1] = -0.588276f;	val_dir[2855*3 + 2] = 0.800055f;
+ 	val_dir[2856*3 + 0] = -0.092057f;	val_dir[2856*3 + 1] = -0.552345f;	val_dir[2856*3 + 2] = 0.828517f;
+ 	val_dir[2857*3 + 0] = -0.067386f;	val_dir[2857*3 + 1] = -0.516626f;	val_dir[2857*3 + 2] = 0.853556f;
+ 	val_dir[2858*3 + 0] = -0.043769f;	val_dir[2858*3 + 1] = -0.481457f;	val_dir[2858*3 + 2] = 0.875376f;
+ 	val_dir[2859*3 + 0] = -0.021291f;	val_dir[2859*3 + 1] = -0.447112f;	val_dir[2859*3 + 2] = 0.894224f;
+ 	val_dir[2860*3 + 0] = 0.0f;	val_dir[2860*3 + 1] = -0.413803f;	val_dir[2860*3 + 2] = 0.910366f;
+ 	val_dir[2861*3 + 0] = 0.020861f;	val_dir[2861*3 + 1] = -0.396350f;	val_dir[2861*3 + 2] = 0.917863f;
+ 	val_dir[2862*3 + 0] = 0.042033f;	val_dir[2862*3 + 1] = -0.378298f;	val_dir[2862*3 + 2] = 0.924729f;
+ 	val_dir[2863*3 + 0] = 0.063472f;	val_dir[2863*3 + 1] = -0.359673f;	val_dir[2863*3 + 2] = 0.930917f;
+ 	val_dir[2864*3 + 0] = 0.085126f;	val_dir[2864*3 + 1] = -0.340503f;	val_dir[2864*3 + 2] = 0.936382f;
+ 	val_dir[2865*3 + 0] = 0.106941f;	val_dir[2865*3 + 1] = -0.320824f;	val_dir[2865*3 + 2] = 0.941082f;
+ 	val_dir[2866*3 + 0] = 0.128861f;	val_dir[2866*3 + 1] = -0.300676f;	val_dir[2866*3 + 2] = 0.944981f;
+ 	val_dir[2867*3 + 0] = 0.150826f;	val_dir[2867*3 + 1] = -0.280105f;	val_dir[2867*3 + 2] = 0.948047f;
+ 	val_dir[2868*3 + 0] = 0.172774f;	val_dir[2868*3 + 1] = -0.259161f;	val_dir[2868*3 + 2] = 0.950255f;
+ 	val_dir[2869*3 + 0] = 0.194643f;	val_dir[2869*3 + 1] = -0.237897f;	val_dir[2869*3 + 2] = 0.951588f;
+ 	val_dir[2870*3 + 0] = 0.216371f;	val_dir[2870*3 + 1] = -0.216371f;	val_dir[2870*3 + 2] = 0.952033f;
+ 	val_dir[2871*3 + 0] = 0.237897f;	val_dir[2871*3 + 1] = -0.194643f;	val_dir[2871*3 + 2] = 0.951588f;
+ 	val_dir[2872*3 + 0] = 0.259161f;	val_dir[2872*3 + 1] = -0.172774f;	val_dir[2872*3 + 2] = 0.950255f;
+ 	val_dir[2873*3 + 0] = 0.280105f;	val_dir[2873*3 + 1] = -0.150826f;	val_dir[2873*3 + 2] = 0.948047f;
+ 	val_dir[2874*3 + 0] = 0.300676f;	val_dir[2874*3 + 1] = -0.128861f;	val_dir[2874*3 + 2] = 0.944981f;
+ 	val_dir[2875*3 + 0] = 0.320824f;	val_dir[2875*3 + 1] = -0.106941f;	val_dir[2875*3 + 2] = 0.941082f;
+ 	val_dir[2876*3 + 0] = 0.340503f;	val_dir[2876*3 + 1] = -0.085126f;	val_dir[2876*3 + 2] = 0.936382f;
+ 	val_dir[2877*3 + 0] = 0.359673f;	val_dir[2877*3 + 1] = -0.063472f;	val_dir[2877*3 + 2] = 0.930917f;
+ 	val_dir[2878*3 + 0] = 0.378298f;	val_dir[2878*3 + 1] = -0.042033f;	val_dir[2878*3 + 2] = 0.924729f;
+ 	val_dir[2879*3 + 0] = 0.396350f;	val_dir[2879*3 + 1] = -0.020861f;	val_dir[2879*3 + 2] = 0.917863f;
+ 	val_dir[2880*3 + 0] = 0.413803f;	val_dir[2880*3 + 1] = 0.0f;	val_dir[2880*3 + 2] = 0.910366f;
+ 	val_dir[2881*3 + 0] = 0.447112f;	val_dir[2881*3 + 1] = 0.021291f;	val_dir[2881*3 + 2] = 0.894224f;
+ 	val_dir[2882*3 + 0] = 0.481457f;	val_dir[2882*3 + 1] = 0.043769f;	val_dir[2882*3 + 2] = 0.875376f;
+ 	val_dir[2883*3 + 0] = 0.516626f;	val_dir[2883*3 + 1] = 0.067386f;	val_dir[2883*3 + 2] = 0.853556f;
+ 	val_dir[2884*3 + 0] = 0.552345f;	val_dir[2884*3 + 1] = 0.092057f;	val_dir[2884*3 + 2] = 0.828517f;
+ 	val_dir[2885*3 + 0] = 0.588276f;	val_dir[2885*3 + 1] = 0.117655f;	val_dir[2885*3 + 2] = 0.800055f;
+ 	val_dir[2886*3 + 0] = 0.624020f;	val_dir[2886*3 + 1] = 0.144005f;	val_dir[2886*3 + 2] = 0.768025f;
+ 	val_dir[2887*3 + 0] = 0.659125f;	val_dir[2887*3 + 1] = 0.170884f;	val_dir[2887*3 + 2] = 0.732361f;
+ 	val_dir[2888*3 + 0] = 0.693103f;	val_dir[2888*3 + 1] = 0.198030f;	val_dir[2888*3 + 2] = 0.693103f;
+ 	val_dir[2889*3 + 0] = 0.725454f;	val_dir[2889*3 + 1] = 0.225141f;	val_dir[2889*3 + 2] = 0.650407f;
+ 	val_dir[2890*3 + 0] = 0.755689f;	val_dir[2890*3 + 1] = 0.251896f;	val_dir[2890*3 + 2] = 0.604551f;
+ 	val_dir[2891*3 + 0] = 0.783368f;	val_dir[2891*3 + 1] = 0.277969f;	val_dir[2891*3 + 2] = 0.555939f;
+ 	val_dir[2892*3 + 0] = 0.808122f;	val_dir[2892*3 + 1] = 0.303046f;	val_dir[2892*3 + 2] = 0.505076f;
+ 	val_dir[2893*3 + 0] = 0.829680f;	val_dir[2893*3 + 1] = 0.326844f;	val_dir[2893*3 + 2] = 0.452553f;
+ 	val_dir[2894*3 + 0] = 0.847883f;	val_dir[2894*3 + 1] = 0.349128f;	val_dir[2894*3 + 2] = 0.399004f;
+ 	val_dir[2895*3 + 0] = 0.862687f;	val_dir[2895*3 + 1] = 0.369723f;	val_dir[2895*3 + 2] = 0.345075f;
+ 	val_dir[2896*3 + 0] = 0.874157f;	val_dir[2896*3 + 1] = 0.388514f;	val_dir[2896*3 + 2] = 0.291386f;
+ 	val_dir[2897*3 + 0] = 0.882454f;	val_dir[2897*3 + 1] = 0.405452f;	val_dir[2897*3 + 2] = 0.238501f;
+ 	val_dir[2898*3 + 0] = 0.887812f;	val_dir[2898*3 + 1] = 0.420542f;	val_dir[2898*3 + 2] = 0.186908f;
+ 	val_dir[2899*3 + 0] = 0.890513f;	val_dir[2899*3 + 1] = 0.433840f;	val_dir[2899*3 + 2] = 0.137002f;
+ 	val_dir[2900*3 + 0] = 0.890871f;	val_dir[2900*3 + 1] = 0.445435f;	val_dir[2900*3 + 2] = 0.089087f;
+ 	val_dir[2901*3 + 0] = 0.889206f;	val_dir[2901*3 + 1] = 0.455447f;	val_dir[2901*3 + 2] = 0.043376f;
+ 	val_dir[2902*3 + 0] = 0.885832f;	val_dir[2902*3 + 1] = 0.464007f;	val_dir[2902*3 + 2] = 0.0f;
+ 	val_dir[2903*3 + 0] = -0.472709f;	val_dir[2903*3 + 1] = -0.880957f;	val_dir[2903*3 + 2] = 0.021487f;
+ 	val_dir[2904*3 + 0] = -0.463812f;	val_dir[2904*3 + 1] = -0.883452f;	val_dir[2904*3 + 2] = 0.066259f;
+ 	val_dir[2905*3 + 0] = -0.453376f;	val_dir[2905*3 + 1] = -0.884083f;	val_dir[2905*3 + 2] = 0.113344f;
+ 	val_dir[2906*3 + 0] = -0.441264f;	val_dir[2906*3 + 1] = -0.882528f;	val_dir[2906*3 + 2] = 0.162571f;
+ 	val_dir[2907*3 + 0] = -0.427362f;	val_dir[2907*3 + 1] = -0.878466f;	val_dir[2907*3 + 2] = 0.213681f;
+ 	val_dir[2908*3 + 0] = -0.411585f;	val_dir[2908*3 + 1] = -0.871592f;	val_dir[2908*3 + 2] = 0.266320f;
+ 	val_dir[2909*3 + 0] = -0.393893f;	val_dir[2909*3 + 1] = -0.861640f;	val_dir[2909*3 + 2] = 0.320038f;
+ 	val_dir[2910*3 + 0] = -0.374299f;	val_dir[2910*3 + 1] = -0.848411f;	val_dir[2910*3 + 2] = 0.374299f;
+ 	val_dir[2911*3 + 0] = -0.352879f;	val_dir[2911*3 + 1] = -0.831786f;	val_dir[2911*3 + 2] = 0.428496f;
+ 	val_dir[2912*3 + 0] = -0.329775f;	val_dir[2912*3 + 1] = -0.811754f;	val_dir[2912*3 + 2] = 0.481979f;
+ 	val_dir[2913*3 + 0] = -0.305194f;	val_dir[2913*3 + 1] = -0.788419f;	val_dir[2913*3 + 2] = 0.534090f;
+ 	val_dir[2914*3 + 0] = -0.27940f;	val_dir[2914*3 + 1] = -0.762001f;	val_dir[2914*3 + 2] = 0.584201f;
+ 	val_dir[2915*3 + 0] = -0.252699f;	val_dir[2915*3 + 1] = -0.732828f;	val_dir[2915*3 + 2] = 0.631748f;
+ 	val_dir[2916*3 + 0] = -0.225423f;	val_dir[2916*3 + 1] = -0.701316f;	val_dir[2916*3 + 2] = 0.676269f;
+ 	val_dir[2917*3 + 0] = -0.197908f;	val_dir[2917*3 + 1] = -0.667940f;	val_dir[2917*3 + 2] = 0.717418f;
+ 	val_dir[2918*3 + 0] = -0.170478f;	val_dir[2918*3 + 1] = -0.633205f;	val_dir[2918*3 + 2] = 0.754976f;
+ 	val_dir[2919*3 + 0] = -0.143427f;	val_dir[2919*3 + 1] = -0.597614f;	val_dir[2919*3 + 2] = 0.788851f;
+ 	val_dir[2920*3 + 0] = -0.117009f;	val_dir[2920*3 + 1] = -0.561644f;	val_dir[2920*3 + 2] = 0.819064f;
+ 	val_dir[2921*3 + 0] = -0.091430f;	val_dir[2921*3 + 1] = -0.525723f;	val_dir[2921*3 + 2] = 0.845728f;
+ 	val_dir[2922*3 + 0] = -0.066848f;	val_dir[2922*3 + 1] = -0.490222f;	val_dir[2922*3 + 2] = 0.869030f;
+ 	val_dir[2923*3 + 0] = -0.043376f;	val_dir[2923*3 + 1] = -0.455447f;	val_dir[2923*3 + 2] = 0.889206f;
+ 	val_dir[2924*3 + 0] = -0.021082f;	val_dir[2924*3 + 1] = -0.421637f;	val_dir[2924*3 + 2] = 0.906520f;
+ 	val_dir[2925*3 + 0] = 0.0f;	val_dir[2925*3 + 1] = -0.388972f;	val_dir[2925*3 + 2] = 0.921250f;
+ 	val_dir[2926*3 + 0] = 0.020628f;	val_dir[2926*3 + 1] = -0.371312f;	val_dir[2926*3 + 2] = 0.928279f;
+ 	val_dir[2927*3 + 0] = 0.041541f;	val_dir[2927*3 + 1] = -0.353096f;	val_dir[2927*3 + 2] = 0.934665f;
+ 	val_dir[2928*3 + 0] = 0.062691f;	val_dir[2928*3 + 1] = -0.334351f;	val_dir[2928*3 + 2] = 0.940361f;
+ 	val_dir[2929*3 + 0] = 0.084029f;	val_dir[2929*3 + 1] = -0.315109f;	val_dir[2929*3 + 2] = 0.945328f;
+ 	val_dir[2930*3 + 0] = 0.105503f;	val_dir[2930*3 + 1] = -0.295409f;	val_dir[2930*3 + 2] = 0.949528f;
+ 	val_dir[2931*3 + 0] = 0.127057f;	val_dir[2931*3 + 1] = -0.275290f;	val_dir[2931*3 + 2] = 0.952928f;
+ 	val_dir[2932*3 + 0] = 0.148634f;	val_dir[2932*3 + 1] = -0.254801f;	val_dir[2932*3 + 2] = 0.955502f;
+ 	val_dir[2933*3 + 0] = 0.170174f;	val_dir[2933*3 + 1] = -0.233990f;	val_dir[2933*3 + 2] = 0.957230f;
+ 	val_dir[2934*3 + 0] = 0.191620f;	val_dir[2934*3 + 1] = -0.212911f;	val_dir[2934*3 + 2] = 0.958098f;
+ 	val_dir[2935*3 + 0] = 0.212911f;	val_dir[2935*3 + 1] = -0.191620f;	val_dir[2935*3 + 2] = 0.958098f;
+ 	val_dir[2936*3 + 0] = 0.233990f;	val_dir[2936*3 + 1] = -0.170174f;	val_dir[2936*3 + 2] = 0.957230f;
+ 	val_dir[2937*3 + 0] = 0.254801f;	val_dir[2937*3 + 1] = -0.148634f;	val_dir[2937*3 + 2] = 0.955502f;
+ 	val_dir[2938*3 + 0] = 0.275290f;	val_dir[2938*3 + 1] = -0.127057f;	val_dir[2938*3 + 2] = 0.952928f;
+ 	val_dir[2939*3 + 0] = 0.295409f;	val_dir[2939*3 + 1] = -0.105503f;	val_dir[2939*3 + 2] = 0.949528f;
+ 	val_dir[2940*3 + 0] = 0.315109f;	val_dir[2940*3 + 1] = -0.084029f;	val_dir[2940*3 + 2] = 0.945328f;
+ 	val_dir[2941*3 + 0] = 0.334351f;	val_dir[2941*3 + 1] = -0.062691f;	val_dir[2941*3 + 2] = 0.940361f;
+ 	val_dir[2942*3 + 0] = 0.353096f;	val_dir[2942*3 + 1] = -0.041541f;	val_dir[2942*3 + 2] = 0.934665f;
+ 	val_dir[2943*3 + 0] = 0.371312f;	val_dir[2943*3 + 1] = -0.020628f;	val_dir[2943*3 + 2] = 0.928279f;
+ 	val_dir[2944*3 + 0] = 0.388972f;	val_dir[2944*3 + 1] = 0.0f;	val_dir[2944*3 + 2] = 0.921250f;
+ 	val_dir[2945*3 + 0] = 0.421637f;	val_dir[2945*3 + 1] = 0.021082f;	val_dir[2945*3 + 2] = 0.906520f;
+ 	val_dir[2946*3 + 0] = 0.455447f;	val_dir[2946*3 + 1] = 0.043376f;	val_dir[2946*3 + 2] = 0.889206f;
+ 	val_dir[2947*3 + 0] = 0.490222f;	val_dir[2947*3 + 1] = 0.066848f;	val_dir[2947*3 + 2] = 0.869030f;
+ 	val_dir[2948*3 + 0] = 0.525723f;	val_dir[2948*3 + 1] = 0.091430f;	val_dir[2948*3 + 2] = 0.845728f;
+ 	val_dir[2949*3 + 0] = 0.561644f;	val_dir[2949*3 + 1] = 0.117009f;	val_dir[2949*3 + 2] = 0.819064f;
+ 	val_dir[2950*3 + 0] = 0.597614f;	val_dir[2950*3 + 1] = 0.143427f;	val_dir[2950*3 + 2] = 0.788851f;
+ 	val_dir[2951*3 + 0] = 0.633205f;	val_dir[2951*3 + 1] = 0.170478f;	val_dir[2951*3 + 2] = 0.754976f;
+ 	val_dir[2952*3 + 0] = 0.667940f;	val_dir[2952*3 + 1] = 0.197908f;	val_dir[2952*3 + 2] = 0.717418f;
+ 	val_dir[2953*3 + 0] = 0.701316f;	val_dir[2953*3 + 1] = 0.225423f;	val_dir[2953*3 + 2] = 0.676269f;
+ 	val_dir[2954*3 + 0] = 0.732828f;	val_dir[2954*3 + 1] = 0.252699f;	val_dir[2954*3 + 2] = 0.631748f;
+ 	val_dir[2955*3 + 0] = 0.762001f;	val_dir[2955*3 + 1] = 0.27940f;	val_dir[2955*3 + 2] = 0.584201f;
+ 	val_dir[2956*3 + 0] = 0.788419f;	val_dir[2956*3 + 1] = 0.305194f;	val_dir[2956*3 + 2] = 0.534090f;
+ 	val_dir[2957*3 + 0] = 0.811754f;	val_dir[2957*3 + 1] = 0.329775f;	val_dir[2957*3 + 2] = 0.481979f;
+ 	val_dir[2958*3 + 0] = 0.831786f;	val_dir[2958*3 + 1] = 0.352879f;	val_dir[2958*3 + 2] = 0.428496f;
+ 	val_dir[2959*3 + 0] = 0.848411f;	val_dir[2959*3 + 1] = 0.374299f;	val_dir[2959*3 + 2] = 0.374299f;
+ 	val_dir[2960*3 + 0] = 0.861640f;	val_dir[2960*3 + 1] = 0.393893f;	val_dir[2960*3 + 2] = 0.320038f;
+ 	val_dir[2961*3 + 0] = 0.871592f;	val_dir[2961*3 + 1] = 0.411585f;	val_dir[2961*3 + 2] = 0.266320f;
+ 	val_dir[2962*3 + 0] = 0.878466f;	val_dir[2962*3 + 1] = 0.427362f;	val_dir[2962*3 + 2] = 0.213681f;
+ 	val_dir[2963*3 + 0] = 0.882528f;	val_dir[2963*3 + 1] = 0.441264f;	val_dir[2963*3 + 2] = 0.162571f;
+ 	val_dir[2964*3 + 0] = 0.884083f;	val_dir[2964*3 + 1] = 0.453376f;	val_dir[2964*3 + 2] = 0.113344f;
+ 	val_dir[2965*3 + 0] = 0.883452f;	val_dir[2965*3 + 1] = 0.463812f;	val_dir[2965*3 + 2] = 0.066259f;
+ 	val_dir[2966*3 + 0] = 0.880957f;	val_dir[2966*3 + 1] = 0.472709f;	val_dir[2966*3 + 2] = 0.021487f;
+ 	val_dir[2967*3 + 0] = -0.489251f;	val_dir[2967*3 + 1] = -0.872143f;	val_dir[2967*3 + 2] = 0.0f;
+ 	val_dir[2968*3 + 0] = -0.481457f;	val_dir[2968*3 + 1] = -0.875376f;	val_dir[2968*3 + 2] = 0.043769f;
+ 	val_dir[2969*3 + 0] = -0.472178f;	val_dir[2969*3 + 1] = -0.876903f;	val_dir[2969*3 + 2] = 0.089939f;
+ 	val_dir[2970*3 + 0] = -0.461266f;	val_dir[2970*3 + 1] = -0.876405f;	val_dir[2970*3 + 2] = 0.138380f;
+ 	val_dir[2971*3 + 0] = -0.448583f;	val_dir[2971*3 + 1] = -0.873555f;	val_dir[2971*3 + 2] = 0.188877f;
+ 	val_dir[2972*3 + 0] = -0.434019f;	val_dir[2972*3 + 1] = -0.868037f;	val_dir[2972*3 + 2] = 0.241121f;
+ 	val_dir[2973*3 + 0] = -0.41750f;	val_dir[2973*3 + 1] = -0.859559f;	val_dir[2973*3 + 2] = 0.294706f;
+ 	val_dir[2974*3 + 0] = -0.399004f;	val_dir[2974*3 + 1] = -0.847883f;	val_dir[2974*3 + 2] = 0.349128f;
+ 	val_dir[2975*3 + 0] = -0.378566f;	val_dir[2975*3 + 1] = -0.832845f;	val_dir[2975*3 + 2] = 0.403804f;
+ 	val_dir[2976*3 + 0] = -0.356291f;	val_dir[2976*3 + 1] = -0.814379f;	val_dir[2976*3 + 2] = 0.458088f;
+ 	val_dir[2977*3 + 0] = -0.332352f;	val_dir[2977*3 + 1] = -0.792530f;	val_dir[2977*3 + 2] = 0.511310f;
+ 	val_dir[2978*3 + 0] = -0.306987f;	val_dir[2978*3 + 1] = -0.767467f;	val_dir[2978*3 + 2] = 0.562809f;
+ 	val_dir[2979*3 + 0] = -0.280488f;	val_dir[2979*3 + 1] = -0.739469f;	val_dir[2979*3 + 2] = 0.611974f;
+ 	val_dir[2980*3 + 0] = -0.253185f;	val_dir[2980*3 + 1] = -0.708918f;	val_dir[2980*3 + 2] = 0.658281f;
+ 	val_dir[2981*3 + 0] = -0.225423f;	val_dir[2981*3 + 1] = -0.676269f;	val_dir[2981*3 + 2] = 0.701316f;
+ 	val_dir[2982*3 + 0] = -0.197546f;	val_dir[2982*3 + 1] = -0.642024f;	val_dir[2982*3 + 2] = 0.740797f;
+ 	val_dir[2983*3 + 0] = -0.169875f;	val_dir[2983*3 + 1] = -0.606696f;	val_dir[2983*3 + 2] = 0.776571f;
+ 	val_dir[2984*3 + 0] = -0.142695f;	val_dir[2984*3 + 1] = -0.570782f;	val_dir[2984*3 + 2] = 0.808608f;
+ 	val_dir[2985*3 + 0] = -0.116248f;	val_dir[2985*3 + 1] = -0.534739f;	val_dir[2985*3 + 2] = 0.836983f;
+ 	val_dir[2986*3 + 0] = -0.090722f;	val_dir[2986*3 + 1] = -0.498970f;	val_dir[2986*3 + 2] = 0.861857f;
+ 	val_dir[2987*3 + 0] = -0.066259f;	val_dir[2987*3 + 1] = -0.463812f;	val_dir[2987*3 + 2] = 0.883452f;
+ 	val_dir[2988*3 + 0] = -0.042954f;	val_dir[2988*3 + 1] = -0.429537f;	val_dir[2988*3 + 2] = 0.902027f;
+ 	val_dir[2989*3 + 0] = -0.020861f;	val_dir[2989*3 + 1] = -0.396350f;	val_dir[2989*3 + 2] = 0.917863f;
+ 	val_dir[2990*3 + 0] = 0.0f;	val_dir[2990*3 + 1] = -0.364399f;	val_dir[2990*3 + 2] = 0.931243f;
+ 	val_dir[2991*3 + 0] = 0.020387f;	val_dir[2991*3 + 1] = -0.346578f;	val_dir[2991*3 + 2] = 0.93780f;
+ 	val_dir[2992*3 + 0] = 0.041030f;	val_dir[2992*3 + 1] = -0.328244f;	val_dir[2992*3 + 2] = 0.943701f;
+ 	val_dir[2993*3 + 0] = 0.061885f;	val_dir[2993*3 + 1] = -0.309426f;	val_dir[2993*3 + 2] = 0.948908f;
+ 	val_dir[2994*3 + 0] = 0.082903f;	val_dir[2994*3 + 1] = -0.290159f;	val_dir[2994*3 + 2] = 0.953381f;
+ 	val_dir[2995*3 + 0] = 0.104031f;	val_dir[2995*3 + 1] = -0.270481f;	val_dir[2995*3 + 2] = 0.957088f;
+ 	val_dir[2996*3 + 0] = 0.125218f;	val_dir[2996*3 + 1] = -0.250435f;	val_dir[2996*3 + 2] = 0.960001f;
+ 	val_dir[2997*3 + 0] = 0.146406f;	val_dir[2997*3 + 1] = -0.230067f;	val_dir[2997*3 + 2] = 0.962099f;
+ 	val_dir[2998*3 + 0] = 0.167542f;	val_dir[2998*3 + 1] = -0.209427f;	val_dir[2998*3 + 2] = 0.963364f;
+ 	val_dir[2999*3 + 0] = 0.188567f;	val_dir[2999*3 + 1] = -0.188567f;	val_dir[2999*3 + 2] = 0.963787f;
+ 	val_dir[3000*3 + 0] = 0.209427f;	val_dir[3000*3 + 1] = -0.167542f;	val_dir[3000*3 + 2] = 0.963364f;
+ 	val_dir[3001*3 + 0] = 0.230067f;	val_dir[3001*3 + 1] = -0.146406f;	val_dir[3001*3 + 2] = 0.962099f;
+ 	val_dir[3002*3 + 0] = 0.250435f;	val_dir[3002*3 + 1] = -0.125218f;	val_dir[3002*3 + 2] = 0.960001f;
+ 	val_dir[3003*3 + 0] = 0.270481f;	val_dir[3003*3 + 1] = -0.104031f;	val_dir[3003*3 + 2] = 0.957088f;
+ 	val_dir[3004*3 + 0] = 0.290159f;	val_dir[3004*3 + 1] = -0.082903f;	val_dir[3004*3 + 2] = 0.953381f;
+ 	val_dir[3005*3 + 0] = 0.309426f;	val_dir[3005*3 + 1] = -0.061885f;	val_dir[3005*3 + 2] = 0.948908f;
+ 	val_dir[3006*3 + 0] = 0.328244f;	val_dir[3006*3 + 1] = -0.041030f;	val_dir[3006*3 + 2] = 0.943701f;
+ 	val_dir[3007*3 + 0] = 0.346578f;	val_dir[3007*3 + 1] = -0.020387f;	val_dir[3007*3 + 2] = 0.93780f;
+ 	val_dir[3008*3 + 0] = 0.364399f;	val_dir[3008*3 + 1] = 0.0f;	val_dir[3008*3 + 2] = 0.931243f;
+ 	val_dir[3009*3 + 0] = 0.396350f;	val_dir[3009*3 + 1] = 0.020861f;	val_dir[3009*3 + 2] = 0.917863f;
+ 	val_dir[3010*3 + 0] = 0.429537f;	val_dir[3010*3 + 1] = 0.042954f;	val_dir[3010*3 + 2] = 0.902027f;
+ 	val_dir[3011*3 + 0] = 0.463812f;	val_dir[3011*3 + 1] = 0.066259f;	val_dir[3011*3 + 2] = 0.883452f;
+ 	val_dir[3012*3 + 0] = 0.498970f;	val_dir[3012*3 + 1] = 0.090722f;	val_dir[3012*3 + 2] = 0.861857f;
+ 	val_dir[3013*3 + 0] = 0.534739f;	val_dir[3013*3 + 1] = 0.116248f;	val_dir[3013*3 + 2] = 0.836983f;
+ 	val_dir[3014*3 + 0] = 0.570782f;	val_dir[3014*3 + 1] = 0.142695f;	val_dir[3014*3 + 2] = 0.808608f;
+ 	val_dir[3015*3 + 0] = 0.606696f;	val_dir[3015*3 + 1] = 0.169875f;	val_dir[3015*3 + 2] = 0.776571f;
+ 	val_dir[3016*3 + 0] = 0.642024f;	val_dir[3016*3 + 1] = 0.197546f;	val_dir[3016*3 + 2] = 0.740797f;
+ 	val_dir[3017*3 + 0] = 0.676269f;	val_dir[3017*3 + 1] = 0.225423f;	val_dir[3017*3 + 2] = 0.701316f;
+ 	val_dir[3018*3 + 0] = 0.708918f;	val_dir[3018*3 + 1] = 0.253185f;	val_dir[3018*3 + 2] = 0.658281f;
+ 	val_dir[3019*3 + 0] = 0.739469f;	val_dir[3019*3 + 1] = 0.280488f;	val_dir[3019*3 + 2] = 0.611974f;
+ 	val_dir[3020*3 + 0] = 0.767467f;	val_dir[3020*3 + 1] = 0.306987f;	val_dir[3020*3 + 2] = 0.562809f;
+ 	val_dir[3021*3 + 0] = 0.792530f;	val_dir[3021*3 + 1] = 0.332352f;	val_dir[3021*3 + 2] = 0.511310f;
+ 	val_dir[3022*3 + 0] = 0.814379f;	val_dir[3022*3 + 1] = 0.356291f;	val_dir[3022*3 + 2] = 0.458088f;
+ 	val_dir[3023*3 + 0] = 0.832845f;	val_dir[3023*3 + 1] = 0.378566f;	val_dir[3023*3 + 2] = 0.403804f;
+ 	val_dir[3024*3 + 0] = 0.847883f;	val_dir[3024*3 + 1] = 0.399004f;	val_dir[3024*3 + 2] = 0.349128f;
+ 	val_dir[3025*3 + 0] = 0.859559f;	val_dir[3025*3 + 1] = 0.41750f;	val_dir[3025*3 + 2] = 0.294706f;
+ 	val_dir[3026*3 + 0] = 0.868037f;	val_dir[3026*3 + 1] = 0.434019f;	val_dir[3026*3 + 2] = 0.241121f;
+ 	val_dir[3027*3 + 0] = 0.873555f;	val_dir[3027*3 + 1] = 0.448583f;	val_dir[3027*3 + 2] = 0.188877f;
+ 	val_dir[3028*3 + 0] = 0.876405f;	val_dir[3028*3 + 1] = 0.461266f;	val_dir[3028*3 + 2] = 0.138380f;
+ 	val_dir[3029*3 + 0] = 0.876903f;	val_dir[3029*3 + 1] = 0.472178f;	val_dir[3029*3 + 2] = 0.089939f;
+ 	val_dir[3030*3 + 0] = 0.875376f;	val_dir[3030*3 + 1] = 0.481457f;	val_dir[3030*3 + 2] = 0.043769f;
+ 	val_dir[3031*3 + 0] = 0.872143f;	val_dir[3031*3 + 1] = 0.489251f;	val_dir[3031*3 + 2] = 0.0f;
+ 	val_dir[3032*3 + 0] = -0.498354f;	val_dir[3032*3 + 1] = -0.866703f;	val_dir[3032*3 + 2] = 0.021668f;
+ 	val_dir[3033*3 + 0] = -0.490222f;	val_dir[3033*3 + 1] = -0.869030f;	val_dir[3033*3 + 2] = 0.066848f;
+ 	val_dir[3034*3 + 0] = -0.480510f;	val_dir[3034*3 + 1] = -0.869495f;	val_dir[3034*3 + 2] = 0.114407f;
+ 	val_dir[3035*3 + 0] = -0.469065f;	val_dir[3035*3 + 1] = -0.867770f;	val_dir[3035*3 + 2] = 0.164173f;
+ 	val_dir[3036*3 + 0] = -0.455752f;	val_dir[3036*3 + 1] = -0.863530f;	val_dir[3036*3 + 2] = 0.215883f;
+ 	val_dir[3037*3 + 0] = -0.440468f;	val_dir[3037*3 + 1] = -0.856465f;	val_dir[3037*3 + 2] = 0.269175f;
+ 	val_dir[3038*3 + 0] = -0.423153f;	val_dir[3038*3 + 1] = -0.846305f;	val_dir[3038*3 + 2] = 0.323587f;
+ 	val_dir[3039*3 + 0] = -0.403804f;	val_dir[3039*3 + 1] = -0.832845f;	val_dir[3039*3 + 2] = 0.378566f;
+ 	val_dir[3040*3 + 0] = -0.382484f;	val_dir[3040*3 + 1] = -0.815966f;	val_dir[3040*3 + 2] = 0.433482f;
+ 	val_dir[3041*3 + 0] = -0.359329f;	val_dir[3041*3 + 1] = -0.795657f;	val_dir[3041*3 + 2] = 0.487661f;
+ 	val_dir[3042*3 + 0] = -0.334545f;	val_dir[3042*3 + 1] = -0.772027f;	val_dir[3042*3 + 2] = 0.540419f;
+ 	val_dir[3043*3 + 0] = -0.308403f;	val_dir[3043*3 + 1] = -0.745307f;	val_dir[3043*3 + 2] = 0.591105f;
+ 	val_dir[3044*3 + 0] = -0.281220f;	val_dir[3044*3 + 1] = -0.715834f;	val_dir[3044*3 + 2] = 0.639138f;
+ 	val_dir[3045*3 + 0] = -0.253347f;	val_dir[3045*3 + 1] = -0.684038f;	val_dir[3045*3 + 2] = 0.684038f;
+ 	val_dir[3046*3 + 0] = -0.225141f;	val_dir[3046*3 + 1] = -0.650407f;	val_dir[3046*3 + 2] = 0.725454f;
+ 	val_dir[3047*3 + 0] = -0.196946f;	val_dir[3047*3 + 1] = -0.615457f;	val_dir[3047*3 + 2] = 0.763167f;
+ 	val_dir[3048*3 + 0] = -0.169080f;	val_dir[3048*3 + 1] = -0.579703f;	val_dir[3048*3 + 2] = 0.797092f;
+ 	val_dir[3049*3 + 0] = -0.141816f;	val_dir[3049*3 + 1] = -0.543627f;	val_dir[3049*3 + 2] = 0.827259f;
+ 	val_dir[3050*3 + 0] = -0.115378f;	val_dir[3050*3 + 1] = -0.507662f;	val_dir[3050*3 + 2] = 0.853796f;
+ 	val_dir[3051*3 + 0] = -0.089939f;	val_dir[3051*3 + 1] = -0.472178f;	val_dir[3051*3 + 2] = 0.876903f;
+ 	val_dir[3052*3 + 0] = -0.065622f;	val_dir[3052*3 + 1] = -0.437479f;	val_dir[3052*3 + 2] = 0.896831f;
+ 	val_dir[3053*3 + 0] = -0.042505f;	val_dir[3053*3 + 1] = -0.403799f;	val_dir[3053*3 + 2] = 0.913860f;
+ 	val_dir[3054*3 + 0] = -0.020628f;	val_dir[3054*3 + 1] = -0.371312f;	val_dir[3054*3 + 2] = 0.928279f;
+ 	val_dir[3055*3 + 0] = 0.0f;	val_dir[3055*3 + 1] = -0.340136f;	val_dir[3055*3 + 2] = 0.940376f;
+ 	val_dir[3056*3 + 0] = 0.020137f;	val_dir[3056*3 + 1] = -0.322198f;	val_dir[3056*3 + 2] = 0.946458f;
+ 	val_dir[3057*3 + 0] = 0.040505f;	val_dir[3057*3 + 1] = -0.303791f;	val_dir[3057*3 + 2] = 0.951877f;
+ 	val_dir[3058*3 + 0] = 0.061059f;	val_dir[3058*3 + 1] = -0.284944f;	val_dir[3058*3 + 2] = 0.956597f;
+ 	val_dir[3059*3 + 0] = 0.081752f;	val_dir[3059*3 + 1] = -0.265694f;	val_dir[3059*3 + 2] = 0.960585f;
+ 	val_dir[3060*3 + 0] = 0.102533f;	val_dir[3060*3 + 1] = -0.246079f;	val_dir[3060*3 + 2] = 0.963811f;
+ 	val_dir[3061*3 + 0] = 0.123351f;	val_dir[3061*3 + 1] = -0.226144f;	val_dir[3061*3 + 2] = 0.966252f;
+ 	val_dir[3062*3 + 0] = 0.144154f;	val_dir[3062*3 + 1] = -0.205934f;	val_dir[3062*3 + 2] = 0.967890f;
+ 	val_dir[3063*3 + 0] = 0.164887f;	val_dir[3063*3 + 1] = -0.185498f;	val_dir[3063*3 + 2] = 0.968712f;
+ 	val_dir[3064*3 + 0] = 0.185498f;	val_dir[3064*3 + 1] = -0.164887f;	val_dir[3064*3 + 2] = 0.968712f;
+ 	val_dir[3065*3 + 0] = 0.205934f;	val_dir[3065*3 + 1] = -0.144154f;	val_dir[3065*3 + 2] = 0.967890f;
+ 	val_dir[3066*3 + 0] = 0.226144f;	val_dir[3066*3 + 1] = -0.123351f;	val_dir[3066*3 + 2] = 0.966252f;
+ 	val_dir[3067*3 + 0] = 0.246079f;	val_dir[3067*3 + 1] = -0.102533f;	val_dir[3067*3 + 2] = 0.963811f;
+ 	val_dir[3068*3 + 0] = 0.265694f;	val_dir[3068*3 + 1] = -0.081752f;	val_dir[3068*3 + 2] = 0.960585f;
+ 	val_dir[3069*3 + 0] = 0.284944f;	val_dir[3069*3 + 1] = -0.061059f;	val_dir[3069*3 + 2] = 0.956597f;
+ 	val_dir[3070*3 + 0] = 0.303791f;	val_dir[3070*3 + 1] = -0.040505f;	val_dir[3070*3 + 2] = 0.951877f;
+ 	val_dir[3071*3 + 0] = 0.322198f;	val_dir[3071*3 + 1] = -0.020137f;	val_dir[3071*3 + 2] = 0.946458f;
+ 	val_dir[3072*3 + 0] = 0.340136f;	val_dir[3072*3 + 1] = 0.0f;	val_dir[3072*3 + 2] = 0.940376f;
+ 	val_dir[3073*3 + 0] = 0.371312f;	val_dir[3073*3 + 1] = 0.020628f;	val_dir[3073*3 + 2] = 0.928279f;
+ 	val_dir[3074*3 + 0] = 0.403799f;	val_dir[3074*3 + 1] = 0.042505f;	val_dir[3074*3 + 2] = 0.913860f;
+ 	val_dir[3075*3 + 0] = 0.437479f;	val_dir[3075*3 + 1] = 0.065622f;	val_dir[3075*3 + 2] = 0.896831f;
+ 	val_dir[3076*3 + 0] = 0.472178f;	val_dir[3076*3 + 1] = 0.089939f;	val_dir[3076*3 + 2] = 0.876903f;
+ 	val_dir[3077*3 + 0] = 0.507662f;	val_dir[3077*3 + 1] = 0.115378f;	val_dir[3077*3 + 2] = 0.853796f;
+ 	val_dir[3078*3 + 0] = 0.543627f;	val_dir[3078*3 + 1] = 0.141816f;	val_dir[3078*3 + 2] = 0.827259f;
+ 	val_dir[3079*3 + 0] = 0.579703f;	val_dir[3079*3 + 1] = 0.169080f;	val_dir[3079*3 + 2] = 0.797092f;
+ 	val_dir[3080*3 + 0] = 0.615457f;	val_dir[3080*3 + 1] = 0.196946f;	val_dir[3080*3 + 2] = 0.763167f;
+ 	val_dir[3081*3 + 0] = 0.650407f;	val_dir[3081*3 + 1] = 0.225141f;	val_dir[3081*3 + 2] = 0.725454f;
+ 	val_dir[3082*3 + 0] = 0.684038f;	val_dir[3082*3 + 1] = 0.253347f;	val_dir[3082*3 + 2] = 0.684038f;
+ 	val_dir[3083*3 + 0] = 0.715834f;	val_dir[3083*3 + 1] = 0.281220f;	val_dir[3083*3 + 2] = 0.639138f;
+ 	val_dir[3084*3 + 0] = 0.745307f;	val_dir[3084*3 + 1] = 0.308403f;	val_dir[3084*3 + 2] = 0.591105f;
+ 	val_dir[3085*3 + 0] = 0.772027f;	val_dir[3085*3 + 1] = 0.334545f;	val_dir[3085*3 + 2] = 0.540419f;
+ 	val_dir[3086*3 + 0] = 0.795657f;	val_dir[3086*3 + 1] = 0.359329f;	val_dir[3086*3 + 2] = 0.487661f;
+ 	val_dir[3087*3 + 0] = 0.815966f;	val_dir[3087*3 + 1] = 0.382484f;	val_dir[3087*3 + 2] = 0.433482f;
+ 	val_dir[3088*3 + 0] = 0.832845f;	val_dir[3088*3 + 1] = 0.403804f;	val_dir[3088*3 + 2] = 0.378566f;
+ 	val_dir[3089*3 + 0] = 0.846305f;	val_dir[3089*3 + 1] = 0.423153f;	val_dir[3089*3 + 2] = 0.323587f;
+ 	val_dir[3090*3 + 0] = 0.856465f;	val_dir[3090*3 + 1] = 0.440468f;	val_dir[3090*3 + 2] = 0.269175f;
+ 	val_dir[3091*3 + 0] = 0.863530f;	val_dir[3091*3 + 1] = 0.455752f;	val_dir[3091*3 + 2] = 0.215883f;
+ 	val_dir[3092*3 + 0] = 0.867770f;	val_dir[3092*3 + 1] = 0.469065f;	val_dir[3092*3 + 2] = 0.164173f;
+ 	val_dir[3093*3 + 0] = 0.869495f;	val_dir[3093*3 + 1] = 0.480510f;	val_dir[3093*3 + 2] = 0.114407f;
+ 	val_dir[3094*3 + 0] = 0.869030f;	val_dir[3094*3 + 1] = 0.490222f;	val_dir[3094*3 + 2] = 0.066848f;
+ 	val_dir[3095*3 + 0] = 0.866703f;	val_dir[3095*3 + 1] = 0.498354f;	val_dir[3095*3 + 2] = 0.021668f;
+ 	val_dir[3096*3 + 0] = -0.514496f;	val_dir[3096*3 + 1] = -0.857493f;	val_dir[3096*3 + 2] = 0.0f;
+ 	val_dir[3097*3 + 0] = -0.507490f;	val_dir[3097*3 + 1] = -0.860527f;	val_dir[3097*3 + 2] = 0.044130f;
+ 	val_dir[3098*3 + 0] = -0.498970f;	val_dir[3098*3 + 1] = -0.861857f;	val_dir[3098*3 + 2] = 0.090722f;
+ 	val_dir[3099*3 + 0] = -0.488769f;	val_dir[3099*3 + 1] = -0.861164f;	val_dir[3099*3 + 2] = 0.139648f;
+ 	val_dir[3100*3 + 0] = -0.476731f;	val_dir[3100*3 + 1] = -0.858116f;	val_dir[3100*3 + 2] = 0.190693f;
+ 	val_dir[3101*3 + 0] = -0.462727f;	val_dir[3101*3 + 1] = -0.852392f;	val_dir[3101*3 + 2] = 0.243541f;
+ 	val_dir[3102*3 + 0] = -0.446662f;	val_dir[3102*3 + 1] = -0.843696f;	val_dir[3102*3 + 2] = 0.297775f;
+ 	val_dir[3103*3 + 0] = -0.428496f;	val_dir[3103*3 + 1] = -0.831786f;	val_dir[3103*3 + 2] = 0.352879f;
+ 	val_dir[3104*3 + 0] = -0.408248f;	val_dir[3104*3 + 1] = -0.816497f;	val_dir[3104*3 + 2] = 0.408248f;
+ 	val_dir[3105*3 + 0] = -0.386014f;	val_dir[3105*3 + 1] = -0.797762f;	val_dir[3105*3 + 2] = 0.463217f;
+ 	val_dir[3106*3 + 0] = -0.361961f;	val_dir[3106*3 + 1] = -0.775632f;	val_dir[3106*3 + 2] = 0.517088f;
+ 	val_dir[3107*3 + 0] = -0.336332f;	val_dir[3107*3 + 1] = -0.750279f;	val_dir[3107*3 + 2] = 0.569177f;
+ 	val_dir[3108*3 + 0] = -0.309426f;	val_dir[3108*3 + 1] = -0.721995f;	val_dir[3108*3 + 2] = 0.618853f;
+ 	val_dir[3109*3 + 0] = -0.281589f;	val_dir[3109*3 + 1] = -0.691173f;	val_dir[3109*3 + 2] = 0.665574f;
+ 	val_dir[3110*3 + 0] = -0.253185f;	val_dir[3110*3 + 1] = -0.658281f;	val_dir[3110*3 + 2] = 0.708918f;
+ 	val_dir[3111*3 + 0] = -0.224579f;	val_dir[3111*3 + 1] = -0.623831f;	val_dir[3111*3 + 2] = 0.748598f;
+ 	val_dir[3112*3 + 0] = -0.196116f;	val_dir[3112*3 + 1] = -0.588348f;	val_dir[3112*3 + 2] = 0.784465f;
+ 	val_dir[3113*3 + 0] = -0.168102f;	val_dir[3113*3 + 1] = -0.552336f;	val_dir[3113*3 + 2] = 0.816497f;
+ 	val_dir[3114*3 + 0] = -0.140797f;	val_dir[3114*3 + 1] = -0.516256f;	val_dir[3114*3 + 2] = 0.844782f;
+ 	val_dir[3115*3 + 0] = -0.114407f;	val_dir[3115*3 + 1] = -0.480510f;	val_dir[3115*3 + 2] = 0.869495f;
+ 	val_dir[3116*3 + 0] = -0.089087f;	val_dir[3116*3 + 1] = -0.445435f;	val_dir[3116*3 + 2] = 0.890871f;
+ 	val_dir[3117*3 + 0] = -0.064942f;	val_dir[3117*3 + 1] = -0.411298f;	val_dir[3117*3 + 2] = 0.909185f;
+ 	val_dir[3118*3 + 0] = -0.042033f;	val_dir[3118*3 + 1] = -0.378298f;	val_dir[3118*3 + 2] = 0.924729f;
+ 	val_dir[3119*3 + 0] = -0.020387f;	val_dir[3119*3 + 1] = -0.346578f;	val_dir[3119*3 + 2] = 0.93780f;
+ 	val_dir[3120*3 + 0] = 0.0f;	val_dir[3120*3 + 1] = -0.316228f;	val_dir[3120*3 + 2] = 0.948683f;
+ 	val_dir[3121*3 + 0] = 0.019881f;	val_dir[3121*3 + 1] = -0.298216f;	val_dir[3121*3 + 2] = 0.954291f;
+ 	val_dir[3122*3 + 0] = 0.039968f;	val_dir[3122*3 + 1] = -0.279776f;	val_dir[3122*3 + 2] = 0.959233f;
+ 	val_dir[3123*3 + 0] = 0.060217f;	val_dir[3123*3 + 1] = -0.260941f;	val_dir[3123*3 + 2] = 0.963475f;
+ 	val_dir[3124*3 + 0] = 0.080582f;	val_dir[3124*3 + 1] = -0.241747f;	val_dir[3124*3 + 2] = 0.966988f;
+ 	val_dir[3125*3 + 0] = 0.101015f;	val_dir[3125*3 + 1] = -0.222234f;	val_dir[3125*3 + 2] = 0.969746f;
+ 	val_dir[3126*3 + 0] = 0.121466f;	val_dir[3126*3 + 1] = -0.202444f;	val_dir[3126*3 + 2] = 0.971732f;
+ 	val_dir[3127*3 + 0] = 0.141885f;	val_dir[3127*3 + 1] = -0.182424f;	val_dir[3127*3 + 2] = 0.972929f;
+ 	val_dir[3128*3 + 0] = 0.162221f;	val_dir[3128*3 + 1] = -0.162221f;	val_dir[3128*3 + 2] = 0.973329f;
+ 	val_dir[3129*3 + 0] = 0.182424f;	val_dir[3129*3 + 1] = -0.141885f;	val_dir[3129*3 + 2] = 0.972929f;
+ 	val_dir[3130*3 + 0] = 0.202444f;	val_dir[3130*3 + 1] = -0.121466f;	val_dir[3130*3 + 2] = 0.971732f;
+ 	val_dir[3131*3 + 0] = 0.222234f;	val_dir[3131*3 + 1] = -0.101015f;	val_dir[3131*3 + 2] = 0.969746f;
+ 	val_dir[3132*3 + 0] = 0.241747f;	val_dir[3132*3 + 1] = -0.080582f;	val_dir[3132*3 + 2] = 0.966988f;
+ 	val_dir[3133*3 + 0] = 0.260941f;	val_dir[3133*3 + 1] = -0.060217f;	val_dir[3133*3 + 2] = 0.963475f;
+ 	val_dir[3134*3 + 0] = 0.279776f;	val_dir[3134*3 + 1] = -0.039968f;	val_dir[3134*3 + 2] = 0.959233f;
+ 	val_dir[3135*3 + 0] = 0.298216f;	val_dir[3135*3 + 1] = -0.019881f;	val_dir[3135*3 + 2] = 0.954291f;
+ 	val_dir[3136*3 + 0] = 0.316228f;	val_dir[3136*3 + 1] = 0.0f;	val_dir[3136*3 + 2] = 0.948683f;
+ 	val_dir[3137*3 + 0] = 0.346578f;	val_dir[3137*3 + 1] = 0.020387f;	val_dir[3137*3 + 2] = 0.93780f;
+ 	val_dir[3138*3 + 0] = 0.378298f;	val_dir[3138*3 + 1] = 0.042033f;	val_dir[3138*3 + 2] = 0.924729f;
+ 	val_dir[3139*3 + 0] = 0.411298f;	val_dir[3139*3 + 1] = 0.064942f;	val_dir[3139*3 + 2] = 0.909185f;
+ 	val_dir[3140*3 + 0] = 0.445435f;	val_dir[3140*3 + 1] = 0.089087f;	val_dir[3140*3 + 2] = 0.890871f;
+ 	val_dir[3141*3 + 0] = 0.480510f;	val_dir[3141*3 + 1] = 0.114407f;	val_dir[3141*3 + 2] = 0.869495f;
+ 	val_dir[3142*3 + 0] = 0.516256f;	val_dir[3142*3 + 1] = 0.140797f;	val_dir[3142*3 + 2] = 0.844782f;
+ 	val_dir[3143*3 + 0] = 0.552336f;	val_dir[3143*3 + 1] = 0.168102f;	val_dir[3143*3 + 2] = 0.816497f;
+ 	val_dir[3144*3 + 0] = 0.588348f;	val_dir[3144*3 + 1] = 0.196116f;	val_dir[3144*3 + 2] = 0.784465f;
+ 	val_dir[3145*3 + 0] = 0.623831f;	val_dir[3145*3 + 1] = 0.224579f;	val_dir[3145*3 + 2] = 0.748598f;
+ 	val_dir[3146*3 + 0] = 0.658281f;	val_dir[3146*3 + 1] = 0.253185f;	val_dir[3146*3 + 2] = 0.708918f;
+ 	val_dir[3147*3 + 0] = 0.691173f;	val_dir[3147*3 + 1] = 0.281589f;	val_dir[3147*3 + 2] = 0.665574f;
+ 	val_dir[3148*3 + 0] = 0.721995f;	val_dir[3148*3 + 1] = 0.309426f;	val_dir[3148*3 + 2] = 0.618853f;
+ 	val_dir[3149*3 + 0] = 0.750279f;	val_dir[3149*3 + 1] = 0.336332f;	val_dir[3149*3 + 2] = 0.569177f;
+ 	val_dir[3150*3 + 0] = 0.775632f;	val_dir[3150*3 + 1] = 0.361961f;	val_dir[3150*3 + 2] = 0.517088f;
+ 	val_dir[3151*3 + 0] = 0.797762f;	val_dir[3151*3 + 1] = 0.386014f;	val_dir[3151*3 + 2] = 0.463217f;
+ 	val_dir[3152*3 + 0] = 0.816497f;	val_dir[3152*3 + 1] = 0.408248f;	val_dir[3152*3 + 2] = 0.408248f;
+ 	val_dir[3153*3 + 0] = 0.831786f;	val_dir[3153*3 + 1] = 0.428496f;	val_dir[3153*3 + 2] = 0.352879f;
+ 	val_dir[3154*3 + 0] = 0.843696f;	val_dir[3154*3 + 1] = 0.446662f;	val_dir[3154*3 + 2] = 0.297775f;
+ 	val_dir[3155*3 + 0] = 0.852392f;	val_dir[3155*3 + 1] = 0.462727f;	val_dir[3155*3 + 2] = 0.243541f;
+ 	val_dir[3156*3 + 0] = 0.858116f;	val_dir[3156*3 + 1] = 0.476731f;	val_dir[3156*3 + 2] = 0.190693f;
+ 	val_dir[3157*3 + 0] = 0.861164f;	val_dir[3157*3 + 1] = 0.488769f;	val_dir[3157*3 + 2] = 0.139648f;
+ 	val_dir[3158*3 + 0] = 0.861857f;	val_dir[3158*3 + 1] = 0.498970f;	val_dir[3158*3 + 2] = 0.090722f;
+ 	val_dir[3159*3 + 0] = 0.860527f;	val_dir[3159*3 + 1] = 0.507490f;	val_dir[3159*3 + 2] = 0.044130f;
+ 	val_dir[3160*3 + 0] = 0.857493f;	val_dir[3160*3 + 1] = 0.514496f;	val_dir[3160*3 + 2] = 0.0f;
+ 	val_dir[3161*3 + 0] = -0.523973f;	val_dir[3161*3 + 1] = -0.851455f;	val_dir[3161*3 + 2] = 0.021832f;
+ 	val_dir[3162*3 + 0] = -0.516626f;	val_dir[3162*3 + 1] = -0.853556f;	val_dir[3162*3 + 2] = 0.067386f;
+ 	val_dir[3163*3 + 0] = -0.507662f;	val_dir[3163*3 + 1] = -0.853796f;	val_dir[3163*3 + 2] = 0.115378f;
+ 	val_dir[3164*3 + 0] = -0.496911f;	val_dir[3164*3 + 1] = -0.851847f;	val_dir[3164*3 + 2] = 0.165637f;
+ 	val_dir[3165*3 + 0] = -0.484217f;	val_dir[3165*3 + 1] = -0.847381f;	val_dir[3165*3 + 2] = 0.217898f;
+ 	val_dir[3166*3 + 0] = -0.469458f;	val_dir[3166*3 + 1] = -0.840083f;	val_dir[3166*3 + 2] = 0.271791f;
+ 	val_dir[3167*3 + 0] = -0.452553f;	val_dir[3167*3 + 1] = -0.829680f;	val_dir[3167*3 + 2] = 0.326844f;
+ 	val_dir[3168*3 + 0] = -0.433482f;	val_dir[3168*3 + 1] = -0.815966f;	val_dir[3168*3 + 2] = 0.382484f;
+ 	val_dir[3169*3 + 0] = -0.412294f;	val_dir[3169*3 + 1] = -0.798820f;	val_dir[3169*3 + 2] = 0.438063f;
+ 	val_dir[3170*3 + 0] = -0.389118f;	val_dir[3170*3 + 1] = -0.778237f;	val_dir[3170*3 + 2] = 0.492883f;
+ 	val_dir[3171*3 + 0] = -0.364159f;	val_dir[3171*3 + 1] = -0.754329f;	val_dir[3171*3 + 2] = 0.546238f;
+ 	val_dir[3172*3 + 0] = -0.337691f;	val_dir[3172*3 + 1] = -0.727334f;	val_dir[3172*3 + 2] = 0.597453f;
+ 	val_dir[3173*3 + 0] = -0.310045f;	val_dir[3173*3 + 1] = -0.697602f;	val_dir[3173*3 + 2] = 0.645928f;
+ 	val_dir[3174*3 + 0] = -0.281589f;	val_dir[3174*3 + 1] = -0.665574f;	val_dir[3174*3 + 2] = 0.691173f;
+ 	val_dir[3175*3 + 0] = -0.252699f;	val_dir[3175*3 + 1] = -0.631748f;	val_dir[3175*3 + 2] = 0.732828f;
+ 	val_dir[3176*3 + 0] = -0.223745f;	val_dir[3176*3 + 1] = -0.596653f;	val_dir[3176*3 + 2] = 0.770677f;
+ 	val_dir[3177*3 + 0] = -0.195064f;	val_dir[3177*3 + 1] = -0.560809f;	val_dir[3177*3 + 2] = 0.804639f;
+ 	val_dir[3178*3 + 0] = -0.166951f;	val_dir[3178*3 + 1] = -0.524703f;	val_dir[3178*3 + 2] = 0.834754f;
+ 	val_dir[3179*3 + 0] = -0.139648f;	val_dir[3179*3 + 1] = -0.488769f;	val_dir[3179*3 + 2] = 0.861164f;
+ 	val_dir[3180*3 + 0] = -0.113344f;	val_dir[3180*3 + 1] = -0.453376f;	val_dir[3180*3 + 2] = 0.884083f;
+ 	val_dir[3181*3 + 0] = -0.088173f;	val_dir[3181*3 + 1] = -0.418823f;	val_dir[3181*3 + 2] = 0.903777f;
+ 	val_dir[3182*3 + 0] = -0.064223f;	val_dir[3182*3 + 1] = -0.385341f;	val_dir[3182*3 + 2] = 0.920537f;
+ 	val_dir[3183*3 + 0] = -0.041541f;	val_dir[3183*3 + 1] = -0.353096f;	val_dir[3183*3 + 2] = 0.934665f;
+ 	val_dir[3184*3 + 0] = -0.020137f;	val_dir[3184*3 + 1] = -0.322198f;	val_dir[3184*3 + 2] = 0.946458f;
+ 	val_dir[3185*3 + 0] = 0.0f;	val_dir[3185*3 + 1] = -0.292714f;	val_dir[3185*3 + 2] = 0.95620f;
+ 	val_dir[3186*3 + 0] = 0.019619f;	val_dir[3186*3 + 1] = -0.274668f;	val_dir[3186*3 + 2] = 0.961339f;
+ 	val_dir[3187*3 + 0] = 0.039421f;	val_dir[3187*3 + 1] = -0.256235f;	val_dir[3187*3 + 2] = 0.965810f;
+ 	val_dir[3188*3 + 0] = 0.059362f;	val_dir[3188*3 + 1] = -0.237449f;	val_dir[3188*3 + 2] = 0.969584f;
+ 	val_dir[3189*3 + 0] = 0.079399f;	val_dir[3189*3 + 1] = -0.218347f;	val_dir[3189*3 + 2] = 0.972636f;
+ 	val_dir[3190*3 + 0] = 0.099484f;	val_dir[3190*3 + 1] = -0.198968f;	val_dir[3190*3 + 2] = 0.974943f;
+ 	val_dir[3191*3 + 0] = 0.119570f;	val_dir[3191*3 + 1] = -0.179355f;	val_dir[3191*3 + 2] = 0.976491f;
+ 	val_dir[3192*3 + 0] = 0.139610f;	val_dir[3192*3 + 1] = -0.159554f;	val_dir[3192*3 + 2] = 0.977267f;
+ 	val_dir[3193*3 + 0] = 0.159554f;	val_dir[3193*3 + 1] = -0.139610f;	val_dir[3193*3 + 2] = 0.977267f;
+ 	val_dir[3194*3 + 0] = 0.179355f;	val_dir[3194*3 + 1] = -0.119570f;	val_dir[3194*3 + 2] = 0.976491f;
+ 	val_dir[3195*3 + 0] = 0.198968f;	val_dir[3195*3 + 1] = -0.099484f;	val_dir[3195*3 + 2] = 0.974943f;
+ 	val_dir[3196*3 + 0] = 0.218347f;	val_dir[3196*3 + 1] = -0.079399f;	val_dir[3196*3 + 2] = 0.972636f;
+ 	val_dir[3197*3 + 0] = 0.237449f;	val_dir[3197*3 + 1] = -0.059362f;	val_dir[3197*3 + 2] = 0.969584f;
+ 	val_dir[3198*3 + 0] = 0.256235f;	val_dir[3198*3 + 1] = -0.039421f;	val_dir[3198*3 + 2] = 0.965810f;
+ 	val_dir[3199*3 + 0] = 0.274668f;	val_dir[3199*3 + 1] = -0.019619f;	val_dir[3199*3 + 2] = 0.961339f;
+ 	val_dir[3200*3 + 0] = 0.292714f;	val_dir[3200*3 + 1] = 0.0f;	val_dir[3200*3 + 2] = 0.95620f;
+ 	val_dir[3201*3 + 0] = 0.322198f;	val_dir[3201*3 + 1] = 0.020137f;	val_dir[3201*3 + 2] = 0.946458f;
+ 	val_dir[3202*3 + 0] = 0.353096f;	val_dir[3202*3 + 1] = 0.041541f;	val_dir[3202*3 + 2] = 0.934665f;
+ 	val_dir[3203*3 + 0] = 0.385341f;	val_dir[3203*3 + 1] = 0.064223f;	val_dir[3203*3 + 2] = 0.920537f;
+ 	val_dir[3204*3 + 0] = 0.418823f;	val_dir[3204*3 + 1] = 0.088173f;	val_dir[3204*3 + 2] = 0.903777f;
+ 	val_dir[3205*3 + 0] = 0.453376f;	val_dir[3205*3 + 1] = 0.113344f;	val_dir[3205*3 + 2] = 0.884083f;
+ 	val_dir[3206*3 + 0] = 0.488769f;	val_dir[3206*3 + 1] = 0.139648f;	val_dir[3206*3 + 2] = 0.861164f;
+ 	val_dir[3207*3 + 0] = 0.524703f;	val_dir[3207*3 + 1] = 0.166951f;	val_dir[3207*3 + 2] = 0.834754f;
+ 	val_dir[3208*3 + 0] = 0.560809f;	val_dir[3208*3 + 1] = 0.195064f;	val_dir[3208*3 + 2] = 0.804639f;
+ 	val_dir[3209*3 + 0] = 0.596653f;	val_dir[3209*3 + 1] = 0.223745f;	val_dir[3209*3 + 2] = 0.770677f;
+ 	val_dir[3210*3 + 0] = 0.631748f;	val_dir[3210*3 + 1] = 0.252699f;	val_dir[3210*3 + 2] = 0.732828f;
+ 	val_dir[3211*3 + 0] = 0.665574f;	val_dir[3211*3 + 1] = 0.281589f;	val_dir[3211*3 + 2] = 0.691173f;
+ 	val_dir[3212*3 + 0] = 0.697602f;	val_dir[3212*3 + 1] = 0.310045f;	val_dir[3212*3 + 2] = 0.645928f;
+ 	val_dir[3213*3 + 0] = 0.727334f;	val_dir[3213*3 + 1] = 0.337691f;	val_dir[3213*3 + 2] = 0.597453f;
+ 	val_dir[3214*3 + 0] = 0.754329f;	val_dir[3214*3 + 1] = 0.364159f;	val_dir[3214*3 + 2] = 0.546238f;
+ 	val_dir[3215*3 + 0] = 0.778237f;	val_dir[3215*3 + 1] = 0.389118f;	val_dir[3215*3 + 2] = 0.492883f;
+ 	val_dir[3216*3 + 0] = 0.798820f;	val_dir[3216*3 + 1] = 0.412294f;	val_dir[3216*3 + 2] = 0.438063f;
+ 	val_dir[3217*3 + 0] = 0.815966f;	val_dir[3217*3 + 1] = 0.433482f;	val_dir[3217*3 + 2] = 0.382484f;
+ 	val_dir[3218*3 + 0] = 0.829680f;	val_dir[3218*3 + 1] = 0.452553f;	val_dir[3218*3 + 2] = 0.326844f;
+ 	val_dir[3219*3 + 0] = 0.840083f;	val_dir[3219*3 + 1] = 0.469458f;	val_dir[3219*3 + 2] = 0.271791f;
+ 	val_dir[3220*3 + 0] = 0.847381f;	val_dir[3220*3 + 1] = 0.484217f;	val_dir[3220*3 + 2] = 0.217898f;
+ 	val_dir[3221*3 + 0] = 0.851847f;	val_dir[3221*3 + 1] = 0.496911f;	val_dir[3221*3 + 2] = 0.165637f;
+ 	val_dir[3222*3 + 0] = 0.853796f;	val_dir[3222*3 + 1] = 0.507662f;	val_dir[3222*3 + 2] = 0.115378f;
+ 	val_dir[3223*3 + 0] = 0.853556f;	val_dir[3223*3 + 1] = 0.516626f;	val_dir[3223*3 + 2] = 0.067386f;
+ 	val_dir[3224*3 + 0] = 0.851455f;	val_dir[3224*3 + 1] = 0.523973f;	val_dir[3224*3 + 2] = 0.021832f;
+ 	val_dir[3225*3 + 0] = -0.539666f;	val_dir[3225*3 + 1] = -0.841879f;	val_dir[3225*3 + 2] = 0.0f;
+ 	val_dir[3226*3 + 0] = -0.533465f;	val_dir[3226*3 + 1] = -0.844653f;	val_dir[3226*3 + 2] = 0.044455f;
+ 	val_dir[3227*3 + 0] = -0.525723f;	val_dir[3227*3 + 1] = -0.845728f;	val_dir[3227*3 + 2] = 0.091430f;
+ 	val_dir[3228*3 + 0] = -0.516256f;	val_dir[3228*3 + 1] = -0.844782f;	val_dir[3228*3 + 2] = 0.140797f;
+ 	val_dir[3229*3 + 0] = -0.504889f;	val_dir[3229*3 + 1] = -0.841482f;	val_dir[3229*3 + 2] = 0.192339f;
+ 	val_dir[3230*3 + 0] = -0.491473f;	val_dir[3230*3 + 1] = -0.835504f;	val_dir[3230*3 + 2] = 0.245737f;
+ 	val_dir[3231*3 + 0] = -0.475893f;	val_dir[3231*3 + 1] = -0.826551f;	val_dir[3231*3 + 2] = 0.300564f;
+ 	val_dir[3232*3 + 0] = -0.458088f;	val_dir[3232*3 + 1] = -0.814379f;	val_dir[3232*3 + 2] = 0.356291f;
+ 	val_dir[3233*3 + 0] = -0.438063f;	val_dir[3233*3 + 1] = -0.798820f;	val_dir[3233*3 + 2] = 0.412294f;
+ 	val_dir[3234*3 + 0] = -0.41590f;	val_dir[3234*3 + 1] = -0.779813f;	val_dir[3234*3 + 2] = 0.467888f;
+ 	val_dir[3235*3 + 0] = -0.391764f;	val_dir[3235*3 + 1] = -0.757410f;	val_dir[3235*3 + 2] = 0.522352f;
+ 	val_dir[3236*3 + 0] = -0.365896f;	val_dir[3236*3 + 1] = -0.731792f;	val_dir[3236*3 + 2] = 0.574979f;
+ 	val_dir[3237*3 + 0] = -0.338606f;	val_dir[3237*3 + 1] = -0.703259f;	val_dir[3237*3 + 2] = 0.625119f;
+ 	val_dir[3238*3 + 0] = -0.310253f;	val_dir[3238*3 + 1] = -0.672214f;	val_dir[3238*3 + 2] = 0.672214f;
+ 	val_dir[3239*3 + 0] = -0.281220f;	val_dir[3239*3 + 1] = -0.639138f;	val_dir[3239*3 + 2] = 0.715834f;
+ 	val_dir[3240*3 + 0] = -0.251896f;	val_dir[3240*3 + 1] = -0.604551f;	val_dir[3240*3 + 2] = 0.755689f;
+ 	val_dir[3241*3 + 0] = -0.222647f;	val_dir[3241*3 + 1] = -0.568986f;	val_dir[3241*3 + 2] = 0.791633f;
+ 	val_dir[3242*3 + 0] = -0.193801f;	val_dir[3242*3 + 1] = -0.532952f;	val_dir[3242*3 + 2] = 0.823653f;
+ 	val_dir[3243*3 + 0] = -0.165637f;	val_dir[3243*3 + 1] = -0.496911f;	val_dir[3243*3 + 2] = 0.851847f;
+ 	val_dir[3244*3 + 0] = -0.138380f;	val_dir[3244*3 + 1] = -0.461266f;	val_dir[3244*3 + 2] = 0.876405f;
+ 	val_dir[3245*3 + 0] = -0.112197f;	val_dir[3245*3 + 1] = -0.426348f;	val_dir[3245*3 + 2] = 0.897574f;
+ 	val_dir[3246*3 + 0] = -0.087204f;	val_dir[3246*3 + 1] = -0.392419f;	val_dir[3246*3 + 2] = 0.915644f;
+ 	val_dir[3247*3 + 0] = -0.063472f;	val_dir[3247*3 + 1] = -0.359673f;	val_dir[3247*3 + 2] = 0.930917f;
+ 	val_dir[3248*3 + 0] = -0.041030f;	val_dir[3248*3 + 1] = -0.328244f;	val_dir[3248*3 + 2] = 0.943701f;
+ 	val_dir[3249*3 + 0] = -0.019881f;	val_dir[3249*3 + 1] = -0.298216f;	val_dir[3249*3 + 2] = 0.954291f;
+ 	val_dir[3250*3 + 0] = 0.0f;	val_dir[3250*3 + 1] = -0.269630f;	val_dir[3250*3 + 2] = 0.962964f;
+ 	val_dir[3251*3 + 0] = 0.019353f;	val_dir[3251*3 + 1] = -0.251587f;	val_dir[3251*3 + 2] = 0.967641f;
+ 	val_dir[3252*3 + 0] = 0.038866f;	val_dir[3252*3 + 1] = -0.233197f;	val_dir[3252*3 + 2] = 0.971653f;
+ 	val_dir[3253*3 + 0] = 0.058498f;	val_dir[3253*3 + 1] = -0.214494f;	val_dir[3253*3 + 2] = 0.974972f;
+ 	val_dir[3254*3 + 0] = 0.078206f;	val_dir[3254*3 + 1] = -0.195515f;	val_dir[3254*3 + 2] = 0.977577f;
+ 	val_dir[3255*3 + 0] = 0.097945f;	val_dir[3255*3 + 1] = -0.176301f;	val_dir[3255*3 + 2] = 0.979451f;
+ 	val_dir[3256*3 + 0] = 0.117670f;	val_dir[3256*3 + 1] = -0.156893f;	val_dir[3256*3 + 2] = 0.980581f;
+ 	val_dir[3257*3 + 0] = 0.137334f;	val_dir[3257*3 + 1] = -0.137334f;	val_dir[3257*3 + 2] = 0.980958f;
+ 	val_dir[3258*3 + 0] = 0.156893f;	val_dir[3258*3 + 1] = -0.117670f;	val_dir[3258*3 + 2] = 0.980581f;
+ 	val_dir[3259*3 + 0] = 0.176301f;	val_dir[3259*3 + 1] = -0.097945f;	val_dir[3259*3 + 2] = 0.979451f;
+ 	val_dir[3260*3 + 0] = 0.195515f;	val_dir[3260*3 + 1] = -0.078206f;	val_dir[3260*3 + 2] = 0.977577f;
+ 	val_dir[3261*3 + 0] = 0.214494f;	val_dir[3261*3 + 1] = -0.058498f;	val_dir[3261*3 + 2] = 0.974972f;
+ 	val_dir[3262*3 + 0] = 0.233197f;	val_dir[3262*3 + 1] = -0.038866f;	val_dir[3262*3 + 2] = 0.971653f;
+ 	val_dir[3263*3 + 0] = 0.251587f;	val_dir[3263*3 + 1] = -0.019353f;	val_dir[3263*3 + 2] = 0.967641f;
+ 	val_dir[3264*3 + 0] = 0.269630f;	val_dir[3264*3 + 1] = 0.0f;	val_dir[3264*3 + 2] = 0.962964f;
+ 	val_dir[3265*3 + 0] = 0.298216f;	val_dir[3265*3 + 1] = 0.019881f;	val_dir[3265*3 + 2] = 0.954291f;
+ 	val_dir[3266*3 + 0] = 0.328244f;	val_dir[3266*3 + 1] = 0.041030f;	val_dir[3266*3 + 2] = 0.943701f;
+ 	val_dir[3267*3 + 0] = 0.359673f;	val_dir[3267*3 + 1] = 0.063472f;	val_dir[3267*3 + 2] = 0.930917f;
+ 	val_dir[3268*3 + 0] = 0.392419f;	val_dir[3268*3 + 1] = 0.087204f;	val_dir[3268*3 + 2] = 0.915644f;
+ 	val_dir[3269*3 + 0] = 0.426348f;	val_dir[3269*3 + 1] = 0.112197f;	val_dir[3269*3 + 2] = 0.897574f;
+ 	val_dir[3270*3 + 0] = 0.461266f;	val_dir[3270*3 + 1] = 0.138380f;	val_dir[3270*3 + 2] = 0.876405f;
+ 	val_dir[3271*3 + 0] = 0.496911f;	val_dir[3271*3 + 1] = 0.165637f;	val_dir[3271*3 + 2] = 0.851847f;
+ 	val_dir[3272*3 + 0] = 0.532952f;	val_dir[3272*3 + 1] = 0.193801f;	val_dir[3272*3 + 2] = 0.823653f;
+ 	val_dir[3273*3 + 0] = 0.568986f;	val_dir[3273*3 + 1] = 0.222647f;	val_dir[3273*3 + 2] = 0.791633f;
+ 	val_dir[3274*3 + 0] = 0.604551f;	val_dir[3274*3 + 1] = 0.251896f;	val_dir[3274*3 + 2] = 0.755689f;
+ 	val_dir[3275*3 + 0] = 0.639138f;	val_dir[3275*3 + 1] = 0.281220f;	val_dir[3275*3 + 2] = 0.715834f;
+ 	val_dir[3276*3 + 0] = 0.672214f;	val_dir[3276*3 + 1] = 0.310253f;	val_dir[3276*3 + 2] = 0.672214f;
+ 	val_dir[3277*3 + 0] = 0.703259f;	val_dir[3277*3 + 1] = 0.338606f;	val_dir[3277*3 + 2] = 0.625119f;
+ 	val_dir[3278*3 + 0] = 0.731792f;	val_dir[3278*3 + 1] = 0.365896f;	val_dir[3278*3 + 2] = 0.574979f;
+ 	val_dir[3279*3 + 0] = 0.757410f;	val_dir[3279*3 + 1] = 0.391764f;	val_dir[3279*3 + 2] = 0.522352f;
+ 	val_dir[3280*3 + 0] = 0.779813f;	val_dir[3280*3 + 1] = 0.41590f;	val_dir[3280*3 + 2] = 0.467888f;
+ 	val_dir[3281*3 + 0] = 0.798820f;	val_dir[3281*3 + 1] = 0.438063f;	val_dir[3281*3 + 2] = 0.412294f;
+ 	val_dir[3282*3 + 0] = 0.814379f;	val_dir[3282*3 + 1] = 0.458088f;	val_dir[3282*3 + 2] = 0.356291f;
+ 	val_dir[3283*3 + 0] = 0.826551f;	val_dir[3283*3 + 1] = 0.475893f;	val_dir[3283*3 + 2] = 0.300564f;
+ 	val_dir[3284*3 + 0] = 0.835504f;	val_dir[3284*3 + 1] = 0.491473f;	val_dir[3284*3 + 2] = 0.245737f;
+ 	val_dir[3285*3 + 0] = 0.841482f;	val_dir[3285*3 + 1] = 0.504889f;	val_dir[3285*3 + 2] = 0.192339f;
+ 	val_dir[3286*3 + 0] = 0.844782f;	val_dir[3286*3 + 1] = 0.516256f;	val_dir[3286*3 + 2] = 0.140797f;
+ 	val_dir[3287*3 + 0] = 0.845728f;	val_dir[3287*3 + 1] = 0.525723f;	val_dir[3287*3 + 2] = 0.091430f;
+ 	val_dir[3288*3 + 0] = 0.844653f;	val_dir[3288*3 + 1] = 0.533465f;	val_dir[3288*3 + 2] = 0.044455f;
+ 	val_dir[3289*3 + 0] = 0.841879f;	val_dir[3289*3 + 1] = 0.539666f;	val_dir[3289*3 + 2] = 0.0f;
+ 	val_dir[3290*3 + 0] = -0.549484f;	val_dir[3290*3 + 1] = -0.835215f;	val_dir[3290*3 + 2] = 0.021979f;
+ 	val_dir[3291*3 + 0] = -0.542936f;	val_dir[3291*3 + 1] = -0.837027f;	val_dir[3291*3 + 2] = 0.067867f;
+ 	val_dir[3292*3 + 0] = -0.534739f;	val_dir[3292*3 + 1] = -0.836983f;	val_dir[3292*3 + 2] = 0.116248f;
+ 	val_dir[3293*3 + 0] = -0.524703f;	val_dir[3293*3 + 1] = -0.834754f;	val_dir[3293*3 + 2] = 0.166951f;
+ 	val_dir[3294*3 + 0] = -0.512653f;	val_dir[3294*3 + 1] = -0.830009f;	val_dir[3294*3 + 2] = 0.219708f;
+ 	val_dir[3295*3 + 0] = -0.498445f;	val_dir[3295*3 + 1] = -0.822434f;	val_dir[3295*3 + 2] = 0.274145f;
+ 	val_dir[3296*3 + 0] = -0.481979f;	val_dir[3296*3 + 1] = -0.811754f;	val_dir[3296*3 + 2] = 0.329775f;
+ 	val_dir[3297*3 + 0] = -0.463217f;	val_dir[3297*3 + 1] = -0.797762f;	val_dir[3297*3 + 2] = 0.386014f;
+ 	val_dir[3298*3 + 0] = -0.442193f;	val_dir[3298*3 + 1] = -0.780340f;	val_dir[3298*3 + 2] = 0.442193f;
+ 	val_dir[3299*3 + 0] = -0.419026f;	val_dir[3299*3 + 1] = -0.759485f;	val_dir[3299*3 + 2] = 0.497594f;
+ 	val_dir[3300*3 + 0] = -0.393919f;	val_dir[3300*3 + 1] = -0.735316f;	val_dir[3300*3 + 2] = 0.551487f;
+ 	val_dir[3301*3 + 0] = -0.367152f;	val_dir[3301*3 + 1] = -0.708079f;	val_dir[3301*3 + 2] = 0.603178f;
+ 	val_dir[3302*3 + 0] = -0.339066f;	val_dir[3302*3 + 1] = -0.678133f;	val_dir[3302*3 + 2] = 0.652051f;
+ 	val_dir[3303*3 + 0] = -0.310045f;	val_dir[3303*3 + 1] = -0.645928f;	val_dir[3303*3 + 2] = 0.697602f;
+ 	val_dir[3304*3 + 0] = -0.280488f;	val_dir[3304*3 + 1] = -0.611974f;	val_dir[3304*3 + 2] = 0.739469f;
+ 	val_dir[3305*3 + 0] = -0.250785f;	val_dir[3305*3 + 1] = -0.576805f;	val_dir[3305*3 + 2] = 0.777433f;
+ 	val_dir[3306*3 + 0] = -0.221297f;	val_dir[3306*3 + 1] = -0.540947f;	val_dir[3306*3 + 2] = 0.811421f;
+ 	val_dir[3307*3 + 0] = -0.192339f;	val_dir[3307*3 + 1] = -0.504889f;	val_dir[3307*3 + 2] = 0.841482f;
+ 	val_dir[3308*3 + 0] = -0.164173f;	val_dir[3308*3 + 1] = -0.469065f;	val_dir[3308*3 + 2] = 0.867770f;
+ 	val_dir[3309*3 + 0] = -0.137002f;	val_dir[3309*3 + 1] = -0.433840f;	val_dir[3309*3 + 2] = 0.890513f;
+ 	val_dir[3310*3 + 0] = -0.110974f;	val_dir[3310*3 + 1] = -0.399507f;	val_dir[3310*3 + 2] = 0.909988f;
+ 	val_dir[3311*3 + 0] = -0.086186f;	val_dir[3311*3 + 1] = -0.366291f;	val_dir[3311*3 + 2] = 0.92650f;
+ 	val_dir[3312*3 + 0] = -0.062691f;	val_dir[3312*3 + 1] = -0.334351f;	val_dir[3312*3 + 2] = 0.940361f;
+ 	val_dir[3313*3 + 0] = -0.040505f;	val_dir[3313*3 + 1] = -0.303791f;	val_dir[3313*3 + 2] = 0.951877f;
+ 	val_dir[3314*3 + 0] = -0.019619f;	val_dir[3314*3 + 1] = -0.274668f;	val_dir[3314*3 + 2] = 0.961339f;
+ 	val_dir[3315*3 + 0] = 0.0f;	val_dir[3315*3 + 1] = -0.247004f;	val_dir[3315*3 + 2] = 0.969015f;
+ 	val_dir[3316*3 + 0] = 0.019083f;	val_dir[3316*3 + 1] = -0.228998f;	val_dir[3316*3 + 2] = 0.973240f;
+ 	val_dir[3317*3 + 0] = 0.038306f;	val_dir[3317*3 + 1] = -0.210683f;	val_dir[3317*3 + 2] = 0.976804f;
+ 	val_dir[3318*3 + 0] = 0.057628f;	val_dir[3318*3 + 1] = -0.192095f;	val_dir[3318*3 + 2] = 0.979683f;
+ 	val_dir[3319*3 + 0] = 0.077009f;	val_dir[3319*3 + 1] = -0.173269f;	val_dir[3319*3 + 2] = 0.981859f;
+ 	val_dir[3320*3 + 0] = 0.096404f;	val_dir[3320*3 + 1] = -0.154246f;	val_dir[3320*3 + 2] = 0.983318f;
+ 	val_dir[3321*3 + 0] = 0.115771f;	val_dir[3321*3 + 1] = -0.135066f;	val_dir[3321*3 + 2] = 0.984050f;
+ 	val_dir[3322*3 + 0] = 0.135066f;	val_dir[3322*3 + 1] = -0.115771f;	val_dir[3322*3 + 2] = 0.984050f;
+ 	val_dir[3323*3 + 0] = 0.154246f;	val_dir[3323*3 + 1] = -0.096404f;	val_dir[3323*3 + 2] = 0.983318f;
+ 	val_dir[3324*3 + 0] = 0.173269f;	val_dir[3324*3 + 1] = -0.077009f;	val_dir[3324*3 + 2] = 0.981859f;
+ 	val_dir[3325*3 + 0] = 0.192095f;	val_dir[3325*3 + 1] = -0.057628f;	val_dir[3325*3 + 2] = 0.979683f;
+ 	val_dir[3326*3 + 0] = 0.210683f;	val_dir[3326*3 + 1] = -0.038306f;	val_dir[3326*3 + 2] = 0.976804f;
+ 	val_dir[3327*3 + 0] = 0.228998f;	val_dir[3327*3 + 1] = -0.019083f;	val_dir[3327*3 + 2] = 0.973240f;
+ 	val_dir[3328*3 + 0] = 0.247004f;	val_dir[3328*3 + 1] = 0.0f;	val_dir[3328*3 + 2] = 0.969015f;
+ 	val_dir[3329*3 + 0] = 0.274668f;	val_dir[3329*3 + 1] = 0.019619f;	val_dir[3329*3 + 2] = 0.961339f;
+ 	val_dir[3330*3 + 0] = 0.303791f;	val_dir[3330*3 + 1] = 0.040505f;	val_dir[3330*3 + 2] = 0.951877f;
+ 	val_dir[3331*3 + 0] = 0.334351f;	val_dir[3331*3 + 1] = 0.062691f;	val_dir[3331*3 + 2] = 0.940361f;
+ 	val_dir[3332*3 + 0] = 0.366291f;	val_dir[3332*3 + 1] = 0.086186f;	val_dir[3332*3 + 2] = 0.92650f;
+ 	val_dir[3333*3 + 0] = 0.399507f;	val_dir[3333*3 + 1] = 0.110974f;	val_dir[3333*3 + 2] = 0.909988f;
+ 	val_dir[3334*3 + 0] = 0.433840f;	val_dir[3334*3 + 1] = 0.137002f;	val_dir[3334*3 + 2] = 0.890513f;
+ 	val_dir[3335*3 + 0] = 0.469065f;	val_dir[3335*3 + 1] = 0.164173f;	val_dir[3335*3 + 2] = 0.867770f;
+ 	val_dir[3336*3 + 0] = 0.504889f;	val_dir[3336*3 + 1] = 0.192339f;	val_dir[3336*3 + 2] = 0.841482f;
+ 	val_dir[3337*3 + 0] = 0.540947f;	val_dir[3337*3 + 1] = 0.221297f;	val_dir[3337*3 + 2] = 0.811421f;
+ 	val_dir[3338*3 + 0] = 0.576805f;	val_dir[3338*3 + 1] = 0.250785f;	val_dir[3338*3 + 2] = 0.777433f;
+ 	val_dir[3339*3 + 0] = 0.611974f;	val_dir[3339*3 + 1] = 0.280488f;	val_dir[3339*3 + 2] = 0.739469f;
+ 	val_dir[3340*3 + 0] = 0.645928f;	val_dir[3340*3 + 1] = 0.310045f;	val_dir[3340*3 + 2] = 0.697602f;
+ 	val_dir[3341*3 + 0] = 0.678133f;	val_dir[3341*3 + 1] = 0.339066f;	val_dir[3341*3 + 2] = 0.652051f;
+ 	val_dir[3342*3 + 0] = 0.708079f;	val_dir[3342*3 + 1] = 0.367152f;	val_dir[3342*3 + 2] = 0.603178f;
+ 	val_dir[3343*3 + 0] = 0.735316f;	val_dir[3343*3 + 1] = 0.393919f;	val_dir[3343*3 + 2] = 0.551487f;
+ 	val_dir[3344*3 + 0] = 0.759485f;	val_dir[3344*3 + 1] = 0.419026f;	val_dir[3344*3 + 2] = 0.497594f;
+ 	val_dir[3345*3 + 0] = 0.780340f;	val_dir[3345*3 + 1] = 0.442193f;	val_dir[3345*3 + 2] = 0.442193f;
+ 	val_dir[3346*3 + 0] = 0.797762f;	val_dir[3346*3 + 1] = 0.463217f;	val_dir[3346*3 + 2] = 0.386014f;
+ 	val_dir[3347*3 + 0] = 0.811754f;	val_dir[3347*3 + 1] = 0.481979f;	val_dir[3347*3 + 2] = 0.329775f;
+ 	val_dir[3348*3 + 0] = 0.822434f;	val_dir[3348*3 + 1] = 0.498445f;	val_dir[3348*3 + 2] = 0.274145f;
+ 	val_dir[3349*3 + 0] = 0.830009f;	val_dir[3349*3 + 1] = 0.512653f;	val_dir[3349*3 + 2] = 0.219708f;
+ 	val_dir[3350*3 + 0] = 0.834754f;	val_dir[3350*3 + 1] = 0.524703f;	val_dir[3350*3 + 2] = 0.166951f;
+ 	val_dir[3351*3 + 0] = 0.836983f;	val_dir[3351*3 + 1] = 0.534739f;	val_dir[3351*3 + 2] = 0.116248f;
+ 	val_dir[3352*3 + 0] = 0.837027f;	val_dir[3352*3 + 1] = 0.542936f;	val_dir[3352*3 + 2] = 0.067867f;
+ 	val_dir[3353*3 + 0] = 0.835215f;	val_dir[3353*3 + 1] = 0.549484f;	val_dir[3353*3 + 2] = 0.021979f;
+ 	val_dir[3354*3 + 0] = -0.564684f;	val_dir[3354*3 + 1] = -0.825307f;	val_dir[3354*3 + 2] = 0.0f;
+ 	val_dir[3355*3 + 0] = -0.559297f;	val_dir[3355*3 + 1] = -0.827759f;	val_dir[3355*3 + 2] = 0.044744f;
+ 	val_dir[3356*3 + 0] = -0.552345f;	val_dir[3356*3 + 1] = -0.828517f;	val_dir[3356*3 + 2] = 0.092057f;
+ 	val_dir[3357*3 + 0] = -0.543627f;	val_dir[3357*3 + 1] = -0.827259f;	val_dir[3357*3 + 2] = 0.141816f;
+ 	val_dir[3358*3 + 0] = -0.532952f;	val_dir[3358*3 + 1] = -0.823653f;	val_dir[3358*3 + 2] = 0.193801f;
+ 	val_dir[3359*3 + 0] = -0.520146f;	val_dir[3359*3 + 1] = -0.817373f;	val_dir[3359*3 + 2] = 0.247689f;
+ 	val_dir[3360*3 + 0] = -0.505076f;	val_dir[3360*3 + 1] = -0.808122f;	val_dir[3360*3 + 2] = 0.303046f;
+ 	val_dir[3361*3 + 0] = -0.487661f;	val_dir[3361*3 + 1] = -0.795657f;	val_dir[3361*3 + 2] = 0.359329f;
+ 	val_dir[3362*3 + 0] = -0.467888f;	val_dir[3362*3 + 1] = -0.779813f;	val_dir[3362*3 + 2] = 0.41590f;
+ 	val_dir[3363*3 + 0] = -0.445827f;	val_dir[3363*3 + 1] = -0.760529f;	val_dir[3363*3 + 2] = 0.472053f;
+ 	val_dir[3364*3 + 0] = -0.421637f;	val_dir[3364*3 + 1] = -0.737865f;	val_dir[3364*3 + 2] = 0.527046f;
+ 	val_dir[3365*3 + 0] = -0.395559f;	val_dir[3365*3 + 1] = -0.712007f;	val_dir[3365*3 + 2] = 0.580154f;
+ 	val_dir[3366*3 + 0] = -0.367912f;	val_dir[3366*3 + 1] = -0.683265f;	val_dir[3366*3 + 2] = 0.630706f;
+ 	val_dir[3367*3 + 0] = -0.339066f;	val_dir[3367*3 + 1] = -0.652051f;	val_dir[3367*3 + 2] = 0.678133f;
+ 	val_dir[3368*3 + 0] = -0.309426f;	val_dir[3368*3 + 1] = -0.618853f;	val_dir[3368*3 + 2] = 0.721995f;
+ 	val_dir[3369*3 + 0] = -0.27940f;	val_dir[3369*3 + 1] = -0.584201f;	val_dir[3369*3 + 2] = 0.762001f;
+ 	val_dir[3370*3 + 0] = -0.249377f;	val_dir[3370*3 + 1] = -0.548630f;	val_dir[3370*3 + 2] = 0.798007f;
+ 	val_dir[3371*3 + 0] = -0.219708f;	val_dir[3371*3 + 1] = -0.512653f;	val_dir[3371*3 + 2] = 0.830009f;
+ 	val_dir[3372*3 + 0] = -0.190693f;	val_dir[3372*3 + 1] = -0.476731f;	val_dir[3372*3 + 2] = 0.858116f;
+ 	val_dir[3373*3 + 0] = -0.162571f;	val_dir[3373*3 + 1] = -0.441264f;	val_dir[3373*3 + 2] = 0.882528f;
+ 	val_dir[3374*3 + 0] = -0.135526f;	val_dir[3374*3 + 1] = -0.406579f;	val_dir[3374*3 + 2] = 0.903508f;
+ 	val_dir[3375*3 + 0] = -0.109685f;	val_dir[3375*3 + 1] = -0.372929f;	val_dir[3375*3 + 2] = 0.921354f;
+ 	val_dir[3376*3 + 0] = -0.085126f;	val_dir[3376*3 + 1] = -0.340503f;	val_dir[3376*3 + 2] = 0.936382f;
+ 	val_dir[3377*3 + 0] = -0.061885f;	val_dir[3377*3 + 1] = -0.309426f;	val_dir[3377*3 + 2] = 0.948908f;
+ 	val_dir[3378*3 + 0] = -0.039968f;	val_dir[3378*3 + 1] = -0.279776f;	val_dir[3378*3 + 2] = 0.959233f;
+ 	val_dir[3379*3 + 0] = -0.019353f;	val_dir[3379*3 + 1] = -0.251587f;	val_dir[3379*3 + 2] = 0.967641f;
+ 	val_dir[3380*3 + 0] = 0.0f;	val_dir[3380*3 + 1] = -0.224860f;	val_dir[3380*3 + 2] = 0.974391f;
+ 	val_dir[3381*3 + 0] = 0.018811f;	val_dir[3381*3 + 1] = -0.206922f;	val_dir[3381*3 + 2] = 0.978177f;
+ 	val_dir[3382*3 + 0] = 0.037743f;	val_dir[3382*3 + 1] = -0.188713f;	val_dir[3382*3 + 2] = 0.981307f;
+ 	val_dir[3383*3 + 0] = 0.056756f;	val_dir[3383*3 + 1] = -0.170267f;	val_dir[3383*3 + 2] = 0.983762f;
+ 	val_dir[3384*3 + 0] = 0.075810f;	val_dir[3384*3 + 1] = -0.151620f;	val_dir[3384*3 + 2] = 0.985527f;
+ 	val_dir[3385*3 + 0] = 0.094865f;	val_dir[3385*3 + 1] = -0.132810f;	val_dir[3385*3 + 2] = 0.986591f;
+ 	val_dir[3386*3 + 0] = 0.113878f;	val_dir[3386*3 + 1] = -0.113878f;	val_dir[3386*3 + 2] = 0.986947f;
+ 	val_dir[3387*3 + 0] = 0.132810f;	val_dir[3387*3 + 1] = -0.094865f;	val_dir[3387*3 + 2] = 0.986591f;
+ 	val_dir[3388*3 + 0] = 0.151620f;	val_dir[3388*3 + 1] = -0.075810f;	val_dir[3388*3 + 2] = 0.985527f;
+ 	val_dir[3389*3 + 0] = 0.170267f;	val_dir[3389*3 + 1] = -0.056756f;	val_dir[3389*3 + 2] = 0.983762f;
+ 	val_dir[3390*3 + 0] = 0.188713f;	val_dir[3390*3 + 1] = -0.037743f;	val_dir[3390*3 + 2] = 0.981307f;
+ 	val_dir[3391*3 + 0] = 0.206922f;	val_dir[3391*3 + 1] = -0.018811f;	val_dir[3391*3 + 2] = 0.978177f;
+ 	val_dir[3392*3 + 0] = 0.224860f;	val_dir[3392*3 + 1] = 0.0f;	val_dir[3392*3 + 2] = 0.974391f;
+ 	val_dir[3393*3 + 0] = 0.251587f;	val_dir[3393*3 + 1] = 0.019353f;	val_dir[3393*3 + 2] = 0.967641f;
+ 	val_dir[3394*3 + 0] = 0.279776f;	val_dir[3394*3 + 1] = 0.039968f;	val_dir[3394*3 + 2] = 0.959233f;
+ 	val_dir[3395*3 + 0] = 0.309426f;	val_dir[3395*3 + 1] = 0.061885f;	val_dir[3395*3 + 2] = 0.948908f;
+ 	val_dir[3396*3 + 0] = 0.340503f;	val_dir[3396*3 + 1] = 0.085126f;	val_dir[3396*3 + 2] = 0.936382f;
+ 	val_dir[3397*3 + 0] = 0.372929f;	val_dir[3397*3 + 1] = 0.109685f;	val_dir[3397*3 + 2] = 0.921354f;
+ 	val_dir[3398*3 + 0] = 0.406579f;	val_dir[3398*3 + 1] = 0.135526f;	val_dir[3398*3 + 2] = 0.903508f;
+ 	val_dir[3399*3 + 0] = 0.441264f;	val_dir[3399*3 + 1] = 0.162571f;	val_dir[3399*3 + 2] = 0.882528f;
+ 	val_dir[3400*3 + 0] = 0.476731f;	val_dir[3400*3 + 1] = 0.190693f;	val_dir[3400*3 + 2] = 0.858116f;
+ 	val_dir[3401*3 + 0] = 0.512653f;	val_dir[3401*3 + 1] = 0.219708f;	val_dir[3401*3 + 2] = 0.830009f;
+ 	val_dir[3402*3 + 0] = 0.548630f;	val_dir[3402*3 + 1] = 0.249377f;	val_dir[3402*3 + 2] = 0.798007f;
+ 	val_dir[3403*3 + 0] = 0.584201f;	val_dir[3403*3 + 1] = 0.27940f;	val_dir[3403*3 + 2] = 0.762001f;
+ 	val_dir[3404*3 + 0] = 0.618853f;	val_dir[3404*3 + 1] = 0.309426f;	val_dir[3404*3 + 2] = 0.721995f;
+ 	val_dir[3405*3 + 0] = 0.652051f;	val_dir[3405*3 + 1] = 0.339066f;	val_dir[3405*3 + 2] = 0.678133f;
+ 	val_dir[3406*3 + 0] = 0.683265f;	val_dir[3406*3 + 1] = 0.367912f;	val_dir[3406*3 + 2] = 0.630706f;
+ 	val_dir[3407*3 + 0] = 0.712007f;	val_dir[3407*3 + 1] = 0.395559f;	val_dir[3407*3 + 2] = 0.580154f;
+ 	val_dir[3408*3 + 0] = 0.737865f;	val_dir[3408*3 + 1] = 0.421637f;	val_dir[3408*3 + 2] = 0.527046f;
+ 	val_dir[3409*3 + 0] = 0.760529f;	val_dir[3409*3 + 1] = 0.445827f;	val_dir[3409*3 + 2] = 0.472053f;
+ 	val_dir[3410*3 + 0] = 0.779813f;	val_dir[3410*3 + 1] = 0.467888f;	val_dir[3410*3 + 2] = 0.41590f;
+ 	val_dir[3411*3 + 0] = 0.795657f;	val_dir[3411*3 + 1] = 0.487661f;	val_dir[3411*3 + 2] = 0.359329f;
+ 	val_dir[3412*3 + 0] = 0.808122f;	val_dir[3412*3 + 1] = 0.505076f;	val_dir[3412*3 + 2] = 0.303046f;
+ 	val_dir[3413*3 + 0] = 0.817373f;	val_dir[3413*3 + 1] = 0.520146f;	val_dir[3413*3 + 2] = 0.247689f;
+ 	val_dir[3414*3 + 0] = 0.823653f;	val_dir[3414*3 + 1] = 0.532952f;	val_dir[3414*3 + 2] = 0.193801f;
+ 	val_dir[3415*3 + 0] = 0.827259f;	val_dir[3415*3 + 1] = 0.543627f;	val_dir[3415*3 + 2] = 0.141816f;
+ 	val_dir[3416*3 + 0] = 0.828517f;	val_dir[3416*3 + 1] = 0.552345f;	val_dir[3416*3 + 2] = 0.092057f;
+ 	val_dir[3417*3 + 0] = 0.827759f;	val_dir[3417*3 + 1] = 0.559297f;	val_dir[3417*3 + 2] = 0.044744f;
+ 	val_dir[3418*3 + 0] = 0.825307f;	val_dir[3418*3 + 1] = 0.564684f;	val_dir[3418*3 + 2] = 0.0f;
+ 	val_dir[3419*3 + 0] = -0.574805f;	val_dir[3419*3 + 1] = -0.817992f;	val_dir[3419*3 + 2] = 0.022108f;
+ 	val_dir[3420*3 + 0] = -0.569064f;	val_dir[3420*3 + 1] = -0.819453f;	val_dir[3420*3 + 2] = 0.068288f;
+ 	val_dir[3421*3 + 0] = -0.561644f;	val_dir[3421*3 + 1] = -0.819064f;	val_dir[3421*3 + 2] = 0.117009f;
+ 	val_dir[3422*3 + 0] = -0.552336f;	val_dir[3422*3 + 1] = -0.816497f;	val_dir[3422*3 + 2] = 0.168102f;
+ 	val_dir[3423*3 + 0] = -0.540947f;	val_dir[3423*3 + 1] = -0.811421f;	val_dir[3423*3 + 2] = 0.221297f;
+ 	val_dir[3424*3 + 0] = -0.527312f;	val_dir[3424*3 + 1] = -0.803523f;	val_dir[3424*3 + 2] = 0.276211f;
+ 	val_dir[3425*3 + 0] = -0.511310f;	val_dir[3425*3 + 1] = -0.792530f;	val_dir[3425*3 + 2] = 0.332352f;
+ 	val_dir[3426*3 + 0] = -0.492883f;	val_dir[3426*3 + 1] = -0.778237f;	val_dir[3426*3 + 2] = 0.389118f;
+ 	val_dir[3427*3 + 0] = -0.472053f;	val_dir[3427*3 + 1] = -0.760529f;	val_dir[3427*3 + 2] = 0.445827f;
+ 	val_dir[3428*3 + 0] = -0.448926f;	val_dir[3428*3 + 1] = -0.739407f;	val_dir[3428*3 + 2] = 0.501740f;
+ 	val_dir[3429*3 + 0] = -0.423702f;	val_dir[3429*3 + 1] = -0.714997f;	val_dir[3429*3 + 2] = 0.556108f;
+ 	val_dir[3430*3 + 0] = -0.396664f;	val_dir[3430*3 + 1] = -0.687552f;	val_dir[3430*3 + 2] = 0.608219f;
+ 	val_dir[3431*3 + 0] = -0.368166f;	val_dir[3431*3 + 1] = -0.657440f;	val_dir[3431*3 + 2] = 0.657440f;
+ 	val_dir[3432*3 + 0] = -0.338606f;	val_dir[3432*3 + 1] = -0.625119f;	val_dir[3432*3 + 2] = 0.703259f;
+ 	val_dir[3433*3 + 0] = -0.308403f;	val_dir[3433*3 + 1] = -0.591105f;	val_dir[3433*3 + 2] = 0.745307f;
+ 	val_dir[3434*3 + 0] = -0.277969f;	val_dir[3434*3 + 1] = -0.555939f;	val_dir[3434*3 + 2] = 0.783368f;
+ 	val_dir[3435*3 + 0] = -0.247689f;	val_dir[3435*3 + 1] = -0.520146f;	val_dir[3435*3 + 2] = 0.817373f;
+ 	val_dir[3436*3 + 0] = -0.217898f;	val_dir[3436*3 + 1] = -0.484217f;	val_dir[3436*3 + 2] = 0.847381f;
+ 	val_dir[3437*3 + 0] = -0.188877f;	val_dir[3437*3 + 1] = -0.448583f;	val_dir[3437*3 + 2] = 0.873555f;
+ 	val_dir[3438*3 + 0] = -0.160845f;	val_dir[3438*3 + 1] = -0.413602f;	val_dir[3438*3 + 2] = 0.896137f;
+ 	val_dir[3439*3 + 0] = -0.133963f;	val_dir[3439*3 + 1] = -0.379563f;	val_dir[3439*3 + 2] = 0.915416f;
+ 	val_dir[3440*3 + 0] = -0.108338f;	val_dir[3440*3 + 1] = -0.346681f;	val_dir[3440*3 + 2] = 0.931705f;
+ 	val_dir[3441*3 + 0] = -0.084029f;	val_dir[3441*3 + 1] = -0.315109f;	val_dir[3441*3 + 2] = 0.945328f;
+ 	val_dir[3442*3 + 0] = -0.061059f;	val_dir[3442*3 + 1] = -0.284944f;	val_dir[3442*3 + 2] = 0.956597f;
+ 	val_dir[3443*3 + 0] = -0.039421f;	val_dir[3443*3 + 1] = -0.256235f;	val_dir[3443*3 + 2] = 0.965810f;
+ 	val_dir[3444*3 + 0] = -0.019083f;	val_dir[3444*3 + 1] = -0.228998f;	val_dir[3444*3 + 2] = 0.973240f;
+ 	val_dir[3445*3 + 0] = 0.0f;	val_dir[3445*3 + 1] = -0.203216f;	val_dir[3445*3 + 2] = 0.979134f;
+ 	val_dir[3446*3 + 0] = 0.018538f;	val_dir[3446*3 + 1] = -0.185376f;	val_dir[3446*3 + 2] = 0.982493f;
+ 	val_dir[3447*3 + 0] = 0.037178f;	val_dir[3447*3 + 1] = -0.167299f;	val_dir[3447*3 + 2] = 0.985205f;
+ 	val_dir[3448*3 + 0] = 0.055882f;	val_dir[3448*3 + 1] = -0.149019f;	val_dir[3448*3 + 2] = 0.987254f;
+ 	val_dir[3449*3 + 0] = 0.074613f;	val_dir[3449*3 + 1] = -0.130573f;	val_dir[3449*3 + 2] = 0.988627f;
+ 	val_dir[3450*3 + 0] = 0.093332f;	val_dir[3450*3 + 1] = -0.111998f;	val_dir[3450*3 + 2] = 0.989316f;
+ 	val_dir[3451*3 + 0] = 0.111998f;	val_dir[3451*3 + 1] = -0.093332f;	val_dir[3451*3 + 2] = 0.989316f;
+ 	val_dir[3452*3 + 0] = 0.130573f;	val_dir[3452*3 + 1] = -0.074613f;	val_dir[3452*3 + 2] = 0.988627f;
+ 	val_dir[3453*3 + 0] = 0.149019f;	val_dir[3453*3 + 1] = -0.055882f;	val_dir[3453*3 + 2] = 0.987254f;
+ 	val_dir[3454*3 + 0] = 0.167299f;	val_dir[3454*3 + 1] = -0.037178f;	val_dir[3454*3 + 2] = 0.985205f;
+ 	val_dir[3455*3 + 0] = 0.185376f;	val_dir[3455*3 + 1] = -0.018538f;	val_dir[3455*3 + 2] = 0.982493f;
+ 	val_dir[3456*3 + 0] = 0.203216f;	val_dir[3456*3 + 1] = 0.0f;	val_dir[3456*3 + 2] = 0.979134f;
+ 	val_dir[3457*3 + 0] = 0.228998f;	val_dir[3457*3 + 1] = 0.019083f;	val_dir[3457*3 + 2] = 0.973240f;
+ 	val_dir[3458*3 + 0] = 0.256235f;	val_dir[3458*3 + 1] = 0.039421f;	val_dir[3458*3 + 2] = 0.965810f;
+ 	val_dir[3459*3 + 0] = 0.284944f;	val_dir[3459*3 + 1] = 0.061059f;	val_dir[3459*3 + 2] = 0.956597f;
+ 	val_dir[3460*3 + 0] = 0.315109f;	val_dir[3460*3 + 1] = 0.084029f;	val_dir[3460*3 + 2] = 0.945328f;
+ 	val_dir[3461*3 + 0] = 0.346681f;	val_dir[3461*3 + 1] = 0.108338f;	val_dir[3461*3 + 2] = 0.931705f;
+ 	val_dir[3462*3 + 0] = 0.379563f;	val_dir[3462*3 + 1] = 0.133963f;	val_dir[3462*3 + 2] = 0.915416f;
+ 	val_dir[3463*3 + 0] = 0.413602f;	val_dir[3463*3 + 1] = 0.160845f;	val_dir[3463*3 + 2] = 0.896137f;
+ 	val_dir[3464*3 + 0] = 0.448583f;	val_dir[3464*3 + 1] = 0.188877f;	val_dir[3464*3 + 2] = 0.873555f;
+ 	val_dir[3465*3 + 0] = 0.484217f;	val_dir[3465*3 + 1] = 0.217898f;	val_dir[3465*3 + 2] = 0.847381f;
+ 	val_dir[3466*3 + 0] = 0.520146f;	val_dir[3466*3 + 1] = 0.247689f;	val_dir[3466*3 + 2] = 0.817373f;
+ 	val_dir[3467*3 + 0] = 0.555939f;	val_dir[3467*3 + 1] = 0.277969f;	val_dir[3467*3 + 2] = 0.783368f;
+ 	val_dir[3468*3 + 0] = 0.591105f;	val_dir[3468*3 + 1] = 0.308403f;	val_dir[3468*3 + 2] = 0.745307f;
+ 	val_dir[3469*3 + 0] = 0.625119f;	val_dir[3469*3 + 1] = 0.338606f;	val_dir[3469*3 + 2] = 0.703259f;
+ 	val_dir[3470*3 + 0] = 0.657440f;	val_dir[3470*3 + 1] = 0.368166f;	val_dir[3470*3 + 2] = 0.657440f;
+ 	val_dir[3471*3 + 0] = 0.687552f;	val_dir[3471*3 + 1] = 0.396664f;	val_dir[3471*3 + 2] = 0.608219f;
+ 	val_dir[3472*3 + 0] = 0.714997f;	val_dir[3472*3 + 1] = 0.423702f;	val_dir[3472*3 + 2] = 0.556108f;
+ 	val_dir[3473*3 + 0] = 0.739407f;	val_dir[3473*3 + 1] = 0.448926f;	val_dir[3473*3 + 2] = 0.501740f;
+ 	val_dir[3474*3 + 0] = 0.760529f;	val_dir[3474*3 + 1] = 0.472053f;	val_dir[3474*3 + 2] = 0.445827f;
+ 	val_dir[3475*3 + 0] = 0.778237f;	val_dir[3475*3 + 1] = 0.492883f;	val_dir[3475*3 + 2] = 0.389118f;
+ 	val_dir[3476*3 + 0] = 0.792530f;	val_dir[3476*3 + 1] = 0.511310f;	val_dir[3476*3 + 2] = 0.332352f;
+ 	val_dir[3477*3 + 0] = 0.803523f;	val_dir[3477*3 + 1] = 0.527312f;	val_dir[3477*3 + 2] = 0.276211f;
+ 	val_dir[3478*3 + 0] = 0.811421f;	val_dir[3478*3 + 1] = 0.540947f;	val_dir[3478*3 + 2] = 0.221297f;
+ 	val_dir[3479*3 + 0] = 0.816497f;	val_dir[3479*3 + 1] = 0.552336f;	val_dir[3479*3 + 2] = 0.168102f;
+ 	val_dir[3480*3 + 0] = 0.819064f;	val_dir[3480*3 + 1] = 0.561644f;	val_dir[3480*3 + 2] = 0.117009f;
+ 	val_dir[3481*3 + 0] = 0.819453f;	val_dir[3481*3 + 1] = 0.569064f;	val_dir[3481*3 + 2] = 0.068288f;
+ 	val_dir[3482*3 + 0] = 0.817992f;	val_dir[3482*3 + 1] = 0.574805f;	val_dir[3482*3 + 2] = 0.022108f;
+ 	val_dir[3483*3 + 0] = -0.589469f;	val_dir[3483*3 + 1] = -0.807791f;	val_dir[3483*3 + 2] = 0.0f;
+ 	val_dir[3484*3 + 0] = -0.584898f;	val_dir[3484*3 + 1] = -0.809858f;	val_dir[3484*3 + 2] = 0.044992f;
+ 	val_dir[3485*3 + 0] = -0.578741f;	val_dir[3485*3 + 1] = -0.810237f;	val_dir[3485*3 + 2] = 0.092599f;
+ 	val_dir[3486*3 + 0] = -0.570782f;	val_dir[3486*3 + 1] = -0.808608f;	val_dir[3486*3 + 2] = 0.142695f;
+ 	val_dir[3487*3 + 0] = -0.560809f;	val_dir[3487*3 + 1] = -0.804639f;	val_dir[3487*3 + 2] = 0.195064f;
+ 	val_dir[3488*3 + 0] = -0.548630f;	val_dir[3488*3 + 1] = -0.798007f;	val_dir[3488*3 + 2] = 0.249377f;
+ 	val_dir[3489*3 + 0] = -0.534090f;	val_dir[3489*3 + 1] = -0.788419f;	val_dir[3489*3 + 2] = 0.305194f;
+ 	val_dir[3490*3 + 0] = -0.517088f;	val_dir[3490*3 + 1] = -0.775632f;	val_dir[3490*3 + 2] = 0.361961f;
+ 	val_dir[3491*3 + 0] = -0.497594f;	val_dir[3491*3 + 1] = -0.759485f;	val_dir[3491*3 + 2] = 0.419026f;
+ 	val_dir[3492*3 + 0] = -0.475665f;	val_dir[3492*3 + 1] = -0.739923f;	val_dir[3492*3 + 2] = 0.475665f;
+ 	val_dir[3493*3 + 0] = -0.451451f;	val_dir[3493*3 + 1] = -0.717011f;	val_dir[3493*3 + 2] = 0.531119f;
+ 	val_dir[3494*3 + 0] = -0.425195f;	val_dir[3494*3 + 1] = -0.690942f;	val_dir[3494*3 + 2] = 0.584643f;
+ 	val_dir[3495*3 + 0] = -0.397220f;	val_dir[3495*3 + 1] = -0.662034f;	val_dir[3495*3 + 2] = 0.635553f;
+ 	val_dir[3496*3 + 0] = -0.367912f;	val_dir[3496*3 + 1] = -0.630706f;	val_dir[3496*3 + 2] = 0.683265f;
+ 	val_dir[3497*3 + 0] = -0.337691f;	val_dir[3497*3 + 1] = -0.597453f;	val_dir[3497*3 + 2] = 0.727334f;
+ 	val_dir[3498*3 + 0] = -0.306987f;	val_dir[3498*3 + 1] = -0.562809f;	val_dir[3498*3 + 2] = 0.767467f;
+ 	val_dir[3499*3 + 0] = -0.276211f;	val_dir[3499*3 + 1] = -0.527312f;	val_dir[3499*3 + 2] = 0.803523f;
+ 	val_dir[3500*3 + 0] = -0.245737f;	val_dir[3500*3 + 1] = -0.491473f;	val_dir[3500*3 + 2] = 0.835504f;
+ 	val_dir[3501*3 + 0] = -0.215883f;	val_dir[3501*3 + 1] = -0.455752f;	val_dir[3501*3 + 2] = 0.863530f;
+ 	val_dir[3502*3 + 0] = -0.186908f;	val_dir[3502*3 + 1] = -0.420542f;	val_dir[3502*3 + 2] = 0.887812f;
+ 	val_dir[3503*3 + 0] = -0.159009f;	val_dir[3503*3 + 1] = -0.386164f;	val_dir[3503*3 + 2] = 0.908622f;
+ 	val_dir[3504*3 + 0] = -0.132324f;	val_dir[3504*3 + 1] = -0.352865f;	val_dir[3504*3 + 2] = 0.926270f;
+ 	val_dir[3505*3 + 0] = -0.106941f;	val_dir[3505*3 + 1] = -0.320824f;	val_dir[3505*3 + 2] = 0.941082f;
+ 	val_dir[3506*3 + 0] = -0.082903f;	val_dir[3506*3 + 1] = -0.290159f;	val_dir[3506*3 + 2] = 0.953381f;
+ 	val_dir[3507*3 + 0] = -0.060217f;	val_dir[3507*3 + 1] = -0.260941f;	val_dir[3507*3 + 2] = 0.963475f;
+ 	val_dir[3508*3 + 0] = -0.038866f;	val_dir[3508*3 + 1] = -0.233197f;	val_dir[3508*3 + 2] = 0.971653f;
+ 	val_dir[3509*3 + 0] = -0.018811f;	val_dir[3509*3 + 1] = -0.206922f;	val_dir[3509*3 + 2] = 0.978177f;
+ 	val_dir[3510*3 + 0] = 0.0f;	val_dir[3510*3 + 1] = -0.182089f;	val_dir[3510*3 + 2] = 0.983282f;
+ 	val_dir[3511*3 + 0] = 0.018264f;	val_dir[3511*3 + 1] = -0.164372f;	val_dir[3511*3 + 2] = 0.986229f;
+ 	val_dir[3512*3 + 0] = 0.036613f;	val_dir[3512*3 + 1] = -0.146450f;	val_dir[3512*3 + 2] = 0.988540f;
+ 	val_dir[3513*3 + 0] = 0.055011f;	val_dir[3513*3 + 1] = -0.128359f;	val_dir[3513*3 + 2] = 0.990201f;
+ 	val_dir[3514*3 + 0] = 0.073422f;	val_dir[3514*3 + 1] = -0.110133f;	val_dir[3514*3 + 2] = 0.991201f;
+ 	val_dir[3515*3 + 0] = 0.091809f;	val_dir[3515*3 + 1] = -0.091809f;	val_dir[3515*3 + 2] = 0.991535f;
+ 	val_dir[3516*3 + 0] = 0.110133f;	val_dir[3516*3 + 1] = -0.073422f;	val_dir[3516*3 + 2] = 0.991201f;
+ 	val_dir[3517*3 + 0] = 0.128359f;	val_dir[3517*3 + 1] = -0.055011f;	val_dir[3517*3 + 2] = 0.990201f;
+ 	val_dir[3518*3 + 0] = 0.146450f;	val_dir[3518*3 + 1] = -0.036613f;	val_dir[3518*3 + 2] = 0.988540f;
+ 	val_dir[3519*3 + 0] = 0.164372f;	val_dir[3519*3 + 1] = -0.018264f;	val_dir[3519*3 + 2] = 0.986229f;
+ 	val_dir[3520*3 + 0] = 0.182089f;	val_dir[3520*3 + 1] = 0.0f;	val_dir[3520*3 + 2] = 0.983282f;
+ 	val_dir[3521*3 + 0] = 0.206922f;	val_dir[3521*3 + 1] = 0.018811f;	val_dir[3521*3 + 2] = 0.978177f;
+ 	val_dir[3522*3 + 0] = 0.233197f;	val_dir[3522*3 + 1] = 0.038866f;	val_dir[3522*3 + 2] = 0.971653f;
+ 	val_dir[3523*3 + 0] = 0.260941f;	val_dir[3523*3 + 1] = 0.060217f;	val_dir[3523*3 + 2] = 0.963475f;
+ 	val_dir[3524*3 + 0] = 0.290159f;	val_dir[3524*3 + 1] = 0.082903f;	val_dir[3524*3 + 2] = 0.953381f;
+ 	val_dir[3525*3 + 0] = 0.320824f;	val_dir[3525*3 + 1] = 0.106941f;	val_dir[3525*3 + 2] = 0.941082f;
+ 	val_dir[3526*3 + 0] = 0.352865f;	val_dir[3526*3 + 1] = 0.132324f;	val_dir[3526*3 + 2] = 0.926270f;
+ 	val_dir[3527*3 + 0] = 0.386164f;	val_dir[3527*3 + 1] = 0.159009f;	val_dir[3527*3 + 2] = 0.908622f;
+ 	val_dir[3528*3 + 0] = 0.420542f;	val_dir[3528*3 + 1] = 0.186908f;	val_dir[3528*3 + 2] = 0.887812f;
+ 	val_dir[3529*3 + 0] = 0.455752f;	val_dir[3529*3 + 1] = 0.215883f;	val_dir[3529*3 + 2] = 0.863530f;
+ 	val_dir[3530*3 + 0] = 0.491473f;	val_dir[3530*3 + 1] = 0.245737f;	val_dir[3530*3 + 2] = 0.835504f;
+ 	val_dir[3531*3 + 0] = 0.527312f;	val_dir[3531*3 + 1] = 0.276211f;	val_dir[3531*3 + 2] = 0.803523f;
+ 	val_dir[3532*3 + 0] = 0.562809f;	val_dir[3532*3 + 1] = 0.306987f;	val_dir[3532*3 + 2] = 0.767467f;
+ 	val_dir[3533*3 + 0] = 0.597453f;	val_dir[3533*3 + 1] = 0.337691f;	val_dir[3533*3 + 2] = 0.727334f;
+ 	val_dir[3534*3 + 0] = 0.630706f;	val_dir[3534*3 + 1] = 0.367912f;	val_dir[3534*3 + 2] = 0.683265f;
+ 	val_dir[3535*3 + 0] = 0.662034f;	val_dir[3535*3 + 1] = 0.397220f;	val_dir[3535*3 + 2] = 0.635553f;
+ 	val_dir[3536*3 + 0] = 0.690942f;	val_dir[3536*3 + 1] = 0.425195f;	val_dir[3536*3 + 2] = 0.584643f;
+ 	val_dir[3537*3 + 0] = 0.717011f;	val_dir[3537*3 + 1] = 0.451451f;	val_dir[3537*3 + 2] = 0.531119f;
+ 	val_dir[3538*3 + 0] = 0.739923f;	val_dir[3538*3 + 1] = 0.475665f;	val_dir[3538*3 + 2] = 0.475665f;
+ 	val_dir[3539*3 + 0] = 0.759485f;	val_dir[3539*3 + 1] = 0.497594f;	val_dir[3539*3 + 2] = 0.419026f;
+ 	val_dir[3540*3 + 0] = 0.775632f;	val_dir[3540*3 + 1] = 0.517088f;	val_dir[3540*3 + 2] = 0.361961f;
+ 	val_dir[3541*3 + 0] = 0.788419f;	val_dir[3541*3 + 1] = 0.534090f;	val_dir[3541*3 + 2] = 0.305194f;
+ 	val_dir[3542*3 + 0] = 0.798007f;	val_dir[3542*3 + 1] = 0.548630f;	val_dir[3542*3 + 2] = 0.249377f;
+ 	val_dir[3543*3 + 0] = 0.804639f;	val_dir[3543*3 + 1] = 0.560809f;	val_dir[3543*3 + 2] = 0.195064f;
+ 	val_dir[3544*3 + 0] = 0.808608f;	val_dir[3544*3 + 1] = 0.570782f;	val_dir[3544*3 + 2] = 0.142695f;
+ 	val_dir[3545*3 + 0] = 0.810237f;	val_dir[3545*3 + 1] = 0.578741f;	val_dir[3545*3 + 2] = 0.092599f;
+ 	val_dir[3546*3 + 0] = 0.809858f;	val_dir[3546*3 + 1] = 0.584898f;	val_dir[3546*3 + 2] = 0.044992f;
+ 	val_dir[3547*3 + 0] = 0.807791f;	val_dir[3547*3 + 1] = 0.589469f;	val_dir[3547*3 + 2] = 0.0f;
+ 	val_dir[3548*3 + 0] = -0.599852f;	val_dir[3548*3 + 1] = -0.799803f;	val_dir[3548*3 + 2] = 0.022217f;
+ 	val_dir[3549*3 + 0] = -0.594917f;	val_dir[3549*3 + 1] = -0.800850f;	val_dir[3549*3 + 2] = 0.068644f;
+ 	val_dir[3550*3 + 0] = -0.588276f;	val_dir[3550*3 + 1] = -0.800055f;	val_dir[3550*3 + 2] = 0.117655f;
+ 	val_dir[3551*3 + 0] = -0.579703f;	val_dir[3551*3 + 1] = -0.797092f;	val_dir[3551*3 + 2] = 0.169080f;
+ 	val_dir[3552*3 + 0] = -0.568986f;	val_dir[3552*3 + 1] = -0.791633f;	val_dir[3552*3 + 2] = 0.222647f;
+ 	val_dir[3553*3 + 0] = -0.555939f;	val_dir[3553*3 + 1] = -0.783368f;	val_dir[3553*3 + 2] = 0.277969f;
+ 	val_dir[3554*3 + 0] = -0.540419f;	val_dir[3554*3 + 1] = -0.772027f;	val_dir[3554*3 + 2] = 0.334545f;
+ 	val_dir[3555*3 + 0] = -0.522352f;	val_dir[3555*3 + 1] = -0.757410f;	val_dir[3555*3 + 2] = 0.391764f;
+ 	val_dir[3556*3 + 0] = -0.501740f;	val_dir[3556*3 + 1] = -0.739407f;	val_dir[3556*3 + 2] = 0.448926f;
+ 	val_dir[3557*3 + 0] = -0.478683f;	val_dir[3557*3 + 1] = -0.718024f;	val_dir[3557*3 + 2] = 0.505276f;
+ 	val_dir[3558*3 + 0] = -0.453374f;	val_dir[3558*3 + 1] = -0.693395f;	val_dir[3558*3 + 2] = 0.560050f;
+ 	val_dir[3559*3 + 0] = -0.426099f;	val_dir[3559*3 + 1] = -0.665780f;	val_dir[3559*3 + 2] = 0.612517f;
+ 	val_dir[3560*3 + 0] = -0.397220f;	val_dir[3560*3 + 1] = -0.635553f;	val_dir[3560*3 + 2] = 0.662034f;
+ 	val_dir[3561*3 + 0] = -0.367152f;	val_dir[3561*3 + 1] = -0.603178f;	val_dir[3561*3 + 2] = 0.708079f;
+ 	val_dir[3562*3 + 0] = -0.336332f;	val_dir[3562*3 + 1] = -0.569177f;	val_dir[3562*3 + 2] = 0.750279f;
+ 	val_dir[3563*3 + 0] = -0.305194f;	val_dir[3563*3 + 1] = -0.534090f;	val_dir[3563*3 + 2] = 0.788419f;
+ 	val_dir[3564*3 + 0] = -0.274145f;	val_dir[3564*3 + 1] = -0.498445f;	val_dir[3564*3 + 2] = 0.822434f;
+ 	val_dir[3565*3 + 0] = -0.243541f;	val_dir[3565*3 + 1] = -0.462727f;	val_dir[3565*3 + 2] = 0.852392f;
+ 	val_dir[3566*3 + 0] = -0.213681f;	val_dir[3566*3 + 1] = -0.427362f;	val_dir[3566*3 + 2] = 0.878466f;
+ 	val_dir[3567*3 + 0] = -0.184801f;	val_dir[3567*3 + 1] = -0.392703f;	val_dir[3567*3 + 2] = 0.900907f;
+ 	val_dir[3568*3 + 0] = -0.157075f;	val_dir[3568*3 + 1] = -0.359030f;	val_dir[3568*3 + 2] = 0.920014f;
+ 	val_dir[3569*3 + 0] = -0.130620f;	val_dir[3569*3 + 1] = -0.326550f;	val_dir[3569*3 + 2] = 0.936111f;
+ 	val_dir[3570*3 + 0] = -0.105503f;	val_dir[3570*3 + 1] = -0.295409f;	val_dir[3570*3 + 2] = 0.949528f;
+ 	val_dir[3571*3 + 0] = -0.081752f;	val_dir[3571*3 + 1] = -0.265694f;	val_dir[3571*3 + 2] = 0.960585f;
+ 	val_dir[3572*3 + 0] = -0.059362f;	val_dir[3572*3 + 1] = -0.237449f;	val_dir[3572*3 + 2] = 0.969584f;
+ 	val_dir[3573*3 + 0] = -0.038306f;	val_dir[3573*3 + 1] = -0.210683f;	val_dir[3573*3 + 2] = 0.976804f;
+ 	val_dir[3574*3 + 0] = -0.018538f;	val_dir[3574*3 + 1] = -0.185376f;	val_dir[3574*3 + 2] = 0.982493f;
+ 	val_dir[3575*3 + 0] = 0.0f;	val_dir[3575*3 + 1] = -0.161489f;	val_dir[3575*3 + 2] = 0.986875f;
+ 	val_dir[3576*3 + 0] = 0.017990f;	val_dir[3576*3 + 1] = -0.143917f;	val_dir[3576*3 + 2] = 0.989426f;
+ 	val_dir[3577*3 + 0] = 0.036049f;	val_dir[3577*3 + 1] = -0.126172f;	val_dir[3577*3 + 2] = 0.991353f;
+ 	val_dir[3578*3 + 0] = 0.054144f;	val_dir[3578*3 + 1] = -0.108288f;	val_dir[3578*3 + 2] = 0.992644f;
+ 	val_dir[3579*3 + 0] = 0.072239f;	val_dir[3579*3 + 1] = -0.090299f;	val_dir[3579*3 + 2] = 0.993291f;
+ 	val_dir[3580*3 + 0] = 0.090299f;	val_dir[3580*3 + 1] = -0.072239f;	val_dir[3580*3 + 2] = 0.993291f;
+ 	val_dir[3581*3 + 0] = 0.108288f;	val_dir[3581*3 + 1] = -0.054144f;	val_dir[3581*3 + 2] = 0.992644f;
+ 	val_dir[3582*3 + 0] = 0.126172f;	val_dir[3582*3 + 1] = -0.036049f;	val_dir[3582*3 + 2] = 0.991353f;
+ 	val_dir[3583*3 + 0] = 0.143917f;	val_dir[3583*3 + 1] = -0.017990f;	val_dir[3583*3 + 2] = 0.989426f;
+ 	val_dir[3584*3 + 0] = 0.161489f;	val_dir[3584*3 + 1] = 0.0f;	val_dir[3584*3 + 2] = 0.986875f;
+ 	val_dir[3585*3 + 0] = 0.185376f;	val_dir[3585*3 + 1] = 0.018538f;	val_dir[3585*3 + 2] = 0.982493f;
+ 	val_dir[3586*3 + 0] = 0.210683f;	val_dir[3586*3 + 1] = 0.038306f;	val_dir[3586*3 + 2] = 0.976804f;
+ 	val_dir[3587*3 + 0] = 0.237449f;	val_dir[3587*3 + 1] = 0.059362f;	val_dir[3587*3 + 2] = 0.969584f;
+ 	val_dir[3588*3 + 0] = 0.265694f;	val_dir[3588*3 + 1] = 0.081752f;	val_dir[3588*3 + 2] = 0.960585f;
+ 	val_dir[3589*3 + 0] = 0.295409f;	val_dir[3589*3 + 1] = 0.105503f;	val_dir[3589*3 + 2] = 0.949528f;
+ 	val_dir[3590*3 + 0] = 0.326550f;	val_dir[3590*3 + 1] = 0.130620f;	val_dir[3590*3 + 2] = 0.936111f;
+ 	val_dir[3591*3 + 0] = 0.359030f;	val_dir[3591*3 + 1] = 0.157075f;	val_dir[3591*3 + 2] = 0.920014f;
+ 	val_dir[3592*3 + 0] = 0.392703f;	val_dir[3592*3 + 1] = 0.184801f;	val_dir[3592*3 + 2] = 0.900907f;
+ 	val_dir[3593*3 + 0] = 0.427362f;	val_dir[3593*3 + 1] = 0.213681f;	val_dir[3593*3 + 2] = 0.878466f;
+ 	val_dir[3594*3 + 0] = 0.462727f;	val_dir[3594*3 + 1] = 0.243541f;	val_dir[3594*3 + 2] = 0.852392f;
+ 	val_dir[3595*3 + 0] = 0.498445f;	val_dir[3595*3 + 1] = 0.274145f;	val_dir[3595*3 + 2] = 0.822434f;
+ 	val_dir[3596*3 + 0] = 0.534090f;	val_dir[3596*3 + 1] = 0.305194f;	val_dir[3596*3 + 2] = 0.788419f;
+ 	val_dir[3597*3 + 0] = 0.569177f;	val_dir[3597*3 + 1] = 0.336332f;	val_dir[3597*3 + 2] = 0.750279f;
+ 	val_dir[3598*3 + 0] = 0.603178f;	val_dir[3598*3 + 1] = 0.367152f;	val_dir[3598*3 + 2] = 0.708079f;
+ 	val_dir[3599*3 + 0] = 0.635553f;	val_dir[3599*3 + 1] = 0.397220f;	val_dir[3599*3 + 2] = 0.662034f;
+ 	val_dir[3600*3 + 0] = 0.665780f;	val_dir[3600*3 + 1] = 0.426099f;	val_dir[3600*3 + 2] = 0.612517f;
+ 	val_dir[3601*3 + 0] = 0.693395f;	val_dir[3601*3 + 1] = 0.453374f;	val_dir[3601*3 + 2] = 0.560050f;
+ 	val_dir[3602*3 + 0] = 0.718024f;	val_dir[3602*3 + 1] = 0.478683f;	val_dir[3602*3 + 2] = 0.505276f;
+ 	val_dir[3603*3 + 0] = 0.739407f;	val_dir[3603*3 + 1] = 0.501740f;	val_dir[3603*3 + 2] = 0.448926f;
+ 	val_dir[3604*3 + 0] = 0.757410f;	val_dir[3604*3 + 1] = 0.522352f;	val_dir[3604*3 + 2] = 0.391764f;
+ 	val_dir[3605*3 + 0] = 0.772027f;	val_dir[3605*3 + 1] = 0.540419f;	val_dir[3605*3 + 2] = 0.334545f;
+ 	val_dir[3606*3 + 0] = 0.783368f;	val_dir[3606*3 + 1] = 0.555939f;	val_dir[3606*3 + 2] = 0.277969f;
+ 	val_dir[3607*3 + 0] = 0.791633f;	val_dir[3607*3 + 1] = 0.568986f;	val_dir[3607*3 + 2] = 0.222647f;
+ 	val_dir[3608*3 + 0] = 0.797092f;	val_dir[3608*3 + 1] = 0.579703f;	val_dir[3608*3 + 2] = 0.169080f;
+ 	val_dir[3609*3 + 0] = 0.800055f;	val_dir[3609*3 + 1] = 0.588276f;	val_dir[3609*3 + 2] = 0.117655f;
+ 	val_dir[3610*3 + 0] = 0.800850f;	val_dir[3610*3 + 1] = 0.594917f;	val_dir[3610*3 + 2] = 0.068644f;
+ 	val_dir[3611*3 + 0] = 0.799803f;	val_dir[3611*3 + 1] = 0.599852f;	val_dir[3611*3 + 2] = 0.022217f;
+ 	val_dir[3612*3 + 0] = -0.613941f;	val_dir[3612*3 + 1] = -0.789352f;	val_dir[3612*3 + 2] = 0.0f;
+ 	val_dir[3613*3 + 0] = -0.610179f;	val_dir[3613*3 + 1] = -0.790973f;	val_dir[3613*3 + 2] = 0.045198f;
+ 	val_dir[3614*3 + 0] = -0.604815f;	val_dir[3614*3 + 1] = -0.790912f;	val_dir[3614*3 + 2] = 0.093048f;
+ 	val_dir[3615*3 + 0] = -0.597614f;	val_dir[3615*3 + 1] = -0.788851f;	val_dir[3615*3 + 2] = 0.143427f;
+ 	val_dir[3616*3 + 0] = -0.588348f;	val_dir[3616*3 + 1] = -0.784465f;	val_dir[3616*3 + 2] = 0.196116f;
+ 	val_dir[3617*3 + 0] = -0.576805f;	val_dir[3617*3 + 1] = -0.777433f;	val_dir[3617*3 + 2] = 0.250785f;
+ 	val_dir[3618*3 + 0] = -0.562809f;	val_dir[3618*3 + 1] = -0.767467f;	val_dir[3618*3 + 2] = 0.306987f;
+ 	val_dir[3619*3 + 0] = -0.546238f;	val_dir[3619*3 + 1] = -0.754329f;	val_dir[3619*3 + 2] = 0.364159f;
+ 	val_dir[3620*3 + 0] = -0.527046f;	val_dir[3620*3 + 1] = -0.737865f;	val_dir[3620*3 + 2] = 0.421637f;
+ 	val_dir[3621*3 + 0] = -0.505276f;	val_dir[3621*3 + 1] = -0.718024f;	val_dir[3621*3 + 2] = 0.478683f;
+ 	val_dir[3622*3 + 0] = -0.481070f;	val_dir[3622*3 + 1] = -0.694879f;	val_dir[3622*3 + 2] = 0.534522f;
+ 	val_dir[3623*3 + 0] = -0.454669f;	val_dir[3623*3 + 1] = -0.668631f;	val_dir[3623*3 + 2] = 0.588395f;
+ 	val_dir[3624*3 + 0] = -0.426401f;	val_dir[3624*3 + 1] = -0.639602f;	val_dir[3624*3 + 2] = 0.639602f;
+ 	val_dir[3625*3 + 0] = -0.396664f;	val_dir[3625*3 + 1] = -0.608219f;	val_dir[3625*3 + 2] = 0.687552f;
+ 	val_dir[3626*3 + 0] = -0.365896f;	val_dir[3626*3 + 1] = -0.574979f;	val_dir[3626*3 + 2] = 0.731792f;
+ 	val_dir[3627*3 + 0] = -0.334545f;	val_dir[3627*3 + 1] = -0.540419f;	val_dir[3627*3 + 2] = 0.772027f;
+ 	val_dir[3628*3 + 0] = -0.303046f;	val_dir[3628*3 + 1] = -0.505076f;	val_dir[3628*3 + 2] = 0.808122f;
+ 	val_dir[3629*3 + 0] = -0.271791f;	val_dir[3629*3 + 1] = -0.469458f;	val_dir[3629*3 + 2] = 0.840083f;
+ 	val_dir[3630*3 + 0] = -0.241121f;	val_dir[3630*3 + 1] = -0.434019f;	val_dir[3630*3 + 2] = 0.868037f;
+ 	val_dir[3631*3 + 0] = -0.211312f;	val_dir[3631*3 + 1] = -0.399145f;	val_dir[3631*3 + 2] = 0.892206f;
+ 	val_dir[3632*3 + 0] = -0.182574f;	val_dir[3632*3 + 1] = -0.365148f;	val_dir[3632*3 + 2] = 0.912871f;
+ 	val_dir[3633*3 + 0] = -0.155059f;	val_dir[3633*3 + 1] = -0.332269f;	val_dir[3633*3 + 2] = 0.930352f;
+ 	val_dir[3634*3 + 0] = -0.128861f;	val_dir[3634*3 + 1] = -0.300676f;	val_dir[3634*3 + 2] = 0.944981f;
+ 	val_dir[3635*3 + 0] = -0.104031f;	val_dir[3635*3 + 1] = -0.270481f;	val_dir[3635*3 + 2] = 0.957088f;
+ 	val_dir[3636*3 + 0] = -0.080582f;	val_dir[3636*3 + 1] = -0.241747f;	val_dir[3636*3 + 2] = 0.966988f;
+ 	val_dir[3637*3 + 0] = -0.058498f;	val_dir[3637*3 + 1] = -0.214494f;	val_dir[3637*3 + 2] = 0.974972f;
+ 	val_dir[3638*3 + 0] = -0.037743f;	val_dir[3638*3 + 1] = -0.188713f;	val_dir[3638*3 + 2] = 0.981307f;
+ 	val_dir[3639*3 + 0] = -0.018264f;	val_dir[3639*3 + 1] = -0.164372f;	val_dir[3639*3 + 2] = 0.986229f;
+ 	val_dir[3640*3 + 0] = 0.0f;	val_dir[3640*3 + 1] = -0.141421f;	val_dir[3640*3 + 2] = 0.989949f;
+ 	val_dir[3641*3 + 0] = 0.017716f;	val_dir[3641*3 + 1] = -0.124015f;	val_dir[3641*3 + 2] = 0.992122f;
+ 	val_dir[3642*3 + 0] = 0.035489f;	val_dir[3642*3 + 1] = -0.106466f;	val_dir[3642*3 + 2] = 0.993683f;
+ 	val_dir[3643*3 + 0] = 0.053283f;	val_dir[3643*3 + 1] = -0.088806f;	val_dir[3643*3 + 2] = 0.994623f;
+ 	val_dir[3644*3 + 0] = 0.071067f;	val_dir[3644*3 + 1] = -0.071067f;	val_dir[3644*3 + 2] = 0.994937f;
+ 	val_dir[3645*3 + 0] = 0.088806f;	val_dir[3645*3 + 1] = -0.053283f;	val_dir[3645*3 + 2] = 0.994623f;
+ 	val_dir[3646*3 + 0] = 0.106466f;	val_dir[3646*3 + 1] = -0.035489f;	val_dir[3646*3 + 2] = 0.993683f;
+ 	val_dir[3647*3 + 0] = 0.124015f;	val_dir[3647*3 + 1] = -0.017716f;	val_dir[3647*3 + 2] = 0.992122f;
+ 	val_dir[3648*3 + 0] = 0.141421f;	val_dir[3648*3 + 1] = 0.0f;	val_dir[3648*3 + 2] = 0.989949f;
+ 	val_dir[3649*3 + 0] = 0.164372f;	val_dir[3649*3 + 1] = 0.018264f;	val_dir[3649*3 + 2] = 0.986229f;
+ 	val_dir[3650*3 + 0] = 0.188713f;	val_dir[3650*3 + 1] = 0.037743f;	val_dir[3650*3 + 2] = 0.981307f;
+ 	val_dir[3651*3 + 0] = 0.214494f;	val_dir[3651*3 + 1] = 0.058498f;	val_dir[3651*3 + 2] = 0.974972f;
+ 	val_dir[3652*3 + 0] = 0.241747f;	val_dir[3652*3 + 1] = 0.080582f;	val_dir[3652*3 + 2] = 0.966988f;
+ 	val_dir[3653*3 + 0] = 0.270481f;	val_dir[3653*3 + 1] = 0.104031f;	val_dir[3653*3 + 2] = 0.957088f;
+ 	val_dir[3654*3 + 0] = 0.300676f;	val_dir[3654*3 + 1] = 0.128861f;	val_dir[3654*3 + 2] = 0.944981f;
+ 	val_dir[3655*3 + 0] = 0.332269f;	val_dir[3655*3 + 1] = 0.155059f;	val_dir[3655*3 + 2] = 0.930352f;
+ 	val_dir[3656*3 + 0] = 0.365148f;	val_dir[3656*3 + 1] = 0.182574f;	val_dir[3656*3 + 2] = 0.912871f;
+ 	val_dir[3657*3 + 0] = 0.399145f;	val_dir[3657*3 + 1] = 0.211312f;	val_dir[3657*3 + 2] = 0.892206f;
+ 	val_dir[3658*3 + 0] = 0.434019f;	val_dir[3658*3 + 1] = 0.241121f;	val_dir[3658*3 + 2] = 0.868037f;
+ 	val_dir[3659*3 + 0] = 0.469458f;	val_dir[3659*3 + 1] = 0.271791f;	val_dir[3659*3 + 2] = 0.840083f;
+ 	val_dir[3660*3 + 0] = 0.505076f;	val_dir[3660*3 + 1] = 0.303046f;	val_dir[3660*3 + 2] = 0.808122f;
+ 	val_dir[3661*3 + 0] = 0.540419f;	val_dir[3661*3 + 1] = 0.334545f;	val_dir[3661*3 + 2] = 0.772027f;
+ 	val_dir[3662*3 + 0] = 0.574979f;	val_dir[3662*3 + 1] = 0.365896f;	val_dir[3662*3 + 2] = 0.731792f;
+ 	val_dir[3663*3 + 0] = 0.608219f;	val_dir[3663*3 + 1] = 0.396664f;	val_dir[3663*3 + 2] = 0.687552f;
+ 	val_dir[3664*3 + 0] = 0.639602f;	val_dir[3664*3 + 1] = 0.426401f;	val_dir[3664*3 + 2] = 0.639602f;
+ 	val_dir[3665*3 + 0] = 0.668631f;	val_dir[3665*3 + 1] = 0.454669f;	val_dir[3665*3 + 2] = 0.588395f;
+ 	val_dir[3666*3 + 0] = 0.694879f;	val_dir[3666*3 + 1] = 0.481070f;	val_dir[3666*3 + 2] = 0.534522f;
+ 	val_dir[3667*3 + 0] = 0.718024f;	val_dir[3667*3 + 1] = 0.505276f;	val_dir[3667*3 + 2] = 0.478683f;
+ 	val_dir[3668*3 + 0] = 0.737865f;	val_dir[3668*3 + 1] = 0.527046f;	val_dir[3668*3 + 2] = 0.421637f;
+ 	val_dir[3669*3 + 0] = 0.754329f;	val_dir[3669*3 + 1] = 0.546238f;	val_dir[3669*3 + 2] = 0.364159f;
+ 	val_dir[3670*3 + 0] = 0.767467f;	val_dir[3670*3 + 1] = 0.562809f;	val_dir[3670*3 + 2] = 0.306987f;
+ 	val_dir[3671*3 + 0] = 0.777433f;	val_dir[3671*3 + 1] = 0.576805f;	val_dir[3671*3 + 2] = 0.250785f;
+ 	val_dir[3672*3 + 0] = 0.784465f;	val_dir[3672*3 + 1] = 0.588348f;	val_dir[3672*3 + 2] = 0.196116f;
+ 	val_dir[3673*3 + 0] = 0.788851f;	val_dir[3673*3 + 1] = 0.597614f;	val_dir[3673*3 + 2] = 0.143427f;
+ 	val_dir[3674*3 + 0] = 0.790912f;	val_dir[3674*3 + 1] = 0.604815f;	val_dir[3674*3 + 2] = 0.093048f;
+ 	val_dir[3675*3 + 0] = 0.790973f;	val_dir[3675*3 + 1] = 0.610179f;	val_dir[3675*3 + 2] = 0.045198f;
+ 	val_dir[3676*3 + 0] = 0.789352f;	val_dir[3676*3 + 1] = 0.613941f;	val_dir[3676*3 + 2] = 0.0f;
+ 	val_dir[3677*3 + 0] = -0.624540f;	val_dir[3677*3 + 1] = -0.780675f;	val_dir[3677*3 + 2] = 0.022305f;
+ 	val_dir[3678*3 + 0] = -0.620403f;	val_dir[3678*3 + 1] = -0.781248f;	val_dir[3678*3 + 2] = 0.068934f;
+ 	val_dir[3679*3 + 0] = -0.614535f;	val_dir[3679*3 + 1] = -0.779987f;	val_dir[3679*3 + 2] = 0.118180f;
+ 	val_dir[3680*3 + 0] = -0.606696f;	val_dir[3680*3 + 1] = -0.776571f;	val_dir[3680*3 + 2] = 0.169875f;
+ 	val_dir[3681*3 + 0] = -0.596653f;	val_dir[3681*3 + 1] = -0.770677f;	val_dir[3681*3 + 2] = 0.223745f;
+ 	val_dir[3682*3 + 0] = -0.584201f;	val_dir[3682*3 + 1] = -0.762001f;	val_dir[3682*3 + 2] = 0.27940f;
+ 	val_dir[3683*3 + 0] = -0.569177f;	val_dir[3683*3 + 1] = -0.750279f;	val_dir[3683*3 + 2] = 0.336332f;
+ 	val_dir[3684*3 + 0] = -0.551487f;	val_dir[3684*3 + 1] = -0.735316f;	val_dir[3684*3 + 2] = 0.393919f;
+ 	val_dir[3685*3 + 0] = -0.531119f;	val_dir[3685*3 + 1] = -0.717011f;	val_dir[3685*3 + 2] = 0.451451f;
+ 	val_dir[3686*3 + 0] = -0.508159f;	val_dir[3686*3 + 1] = -0.695376f;	val_dir[3686*3 + 2] = 0.508159f;
+ 	val_dir[3687*3 + 0] = -0.482798f;	val_dir[3687*3 + 1] = -0.670552f;	val_dir[3687*3 + 2] = 0.563264f;
+ 	val_dir[3688*3 + 0] = -0.455321f;	val_dir[3688*3 + 1] = -0.642806f;	val_dir[3688*3 + 2] = 0.616022f;
+ 	val_dir[3689*3 + 0] = -0.426099f;	val_dir[3689*3 + 1] = -0.612517f;	val_dir[3689*3 + 2] = 0.665780f;
+ 	val_dir[3690*3 + 0] = -0.395559f;	val_dir[3690*3 + 1] = -0.580154f;	val_dir[3690*3 + 2] = 0.712007f;
+ 	val_dir[3691*3 + 0] = -0.364159f;	val_dir[3691*3 + 1] = -0.546238f;	val_dir[3691*3 + 2] = 0.754329f;
+ 	val_dir[3692*3 + 0] = -0.332352f;	val_dir[3692*3 + 1] = -0.511310f;	val_dir[3692*3 + 2] = 0.792530f;
+ 	val_dir[3693*3 + 0] = -0.300564f;	val_dir[3693*3 + 1] = -0.475893f;	val_dir[3693*3 + 2] = 0.826551f;
+ 	val_dir[3694*3 + 0] = -0.269175f;	val_dir[3694*3 + 1] = -0.440468f;	val_dir[3694*3 + 2] = 0.856465f;
+ 	val_dir[3695*3 + 0] = -0.238501f;	val_dir[3695*3 + 1] = -0.405452f;	val_dir[3695*3 + 2] = 0.882454f;
+ 	val_dir[3696*3 + 0] = -0.208795f;	val_dir[3696*3 + 1] = -0.371191f;	val_dir[3696*3 + 2] = 0.904777f;
+ 	val_dir[3697*3 + 0] = -0.180242f;	val_dir[3697*3 + 1] = -0.337954f;	val_dir[3697*3 + 2] = 0.923742f;
+ 	val_dir[3698*3 + 0] = -0.152971f;	val_dir[3698*3 + 1] = -0.305942f;	val_dir[3698*3 + 2] = 0.939680f;
+ 	val_dir[3699*3 + 0] = -0.127057f;	val_dir[3699*3 + 1] = -0.275290f;	val_dir[3699*3 + 2] = 0.952928f;
+ 	val_dir[3700*3 + 0] = -0.102533f;	val_dir[3700*3 + 1] = -0.246079f;	val_dir[3700*3 + 2] = 0.963811f;
+ 	val_dir[3701*3 + 0] = -0.079399f;	val_dir[3701*3 + 1] = -0.218347f;	val_dir[3701*3 + 2] = 0.972636f;
+ 	val_dir[3702*3 + 0] = -0.057628f;	val_dir[3702*3 + 1] = -0.192095f;	val_dir[3702*3 + 2] = 0.979683f;
+ 	val_dir[3703*3 + 0] = -0.037178f;	val_dir[3703*3 + 1] = -0.167299f;	val_dir[3703*3 + 2] = 0.985205f;
+ 	val_dir[3704*3 + 0] = -0.017990f;	val_dir[3704*3 + 1] = -0.143917f;	val_dir[3704*3 + 2] = 0.989426f;
+ 	val_dir[3705*3 + 0] = 0.0f;	val_dir[3705*3 + 1] = -0.121891f;	val_dir[3705*3 + 2] = 0.992543f;
+ 	val_dir[3706*3 + 0] = 0.017445f;	val_dir[3706*3 + 1] = -0.104669f;	val_dir[3706*3 + 2] = 0.994354f;
+ 	val_dir[3707*3 + 0] = 0.034932f;	val_dir[3707*3 + 1] = -0.087330f;	val_dir[3707*3 + 2] = 0.995567f;
+ 	val_dir[3708*3 + 0] = 0.052430f;	val_dir[3708*3 + 1] = -0.069907f;	val_dir[3708*3 + 2] = 0.996175f;
+ 	val_dir[3709*3 + 0] = 0.069907f;	val_dir[3709*3 + 1] = -0.052430f;	val_dir[3709*3 + 2] = 0.996175f;
+ 	val_dir[3710*3 + 0] = 0.087330f;	val_dir[3710*3 + 1] = -0.034932f;	val_dir[3710*3 + 2] = 0.995567f;
+ 	val_dir[3711*3 + 0] = 0.104669f;	val_dir[3711*3 + 1] = -0.017445f;	val_dir[3711*3 + 2] = 0.994354f;
+ 	val_dir[3712*3 + 0] = 0.121891f;	val_dir[3712*3 + 1] = 0.0f;	val_dir[3712*3 + 2] = 0.992543f;
+ 	val_dir[3713*3 + 0] = 0.143917f;	val_dir[3713*3 + 1] = 0.017990f;	val_dir[3713*3 + 2] = 0.989426f;
+ 	val_dir[3714*3 + 0] = 0.167299f;	val_dir[3714*3 + 1] = 0.037178f;	val_dir[3714*3 + 2] = 0.985205f;
+ 	val_dir[3715*3 + 0] = 0.192095f;	val_dir[3715*3 + 1] = 0.057628f;	val_dir[3715*3 + 2] = 0.979683f;
+ 	val_dir[3716*3 + 0] = 0.218347f;	val_dir[3716*3 + 1] = 0.079399f;	val_dir[3716*3 + 2] = 0.972636f;
+ 	val_dir[3717*3 + 0] = 0.246079f;	val_dir[3717*3 + 1] = 0.102533f;	val_dir[3717*3 + 2] = 0.963811f;
+ 	val_dir[3718*3 + 0] = 0.275290f;	val_dir[3718*3 + 1] = 0.127057f;	val_dir[3718*3 + 2] = 0.952928f;
+ 	val_dir[3719*3 + 0] = 0.305942f;	val_dir[3719*3 + 1] = 0.152971f;	val_dir[3719*3 + 2] = 0.939680f;
+ 	val_dir[3720*3 + 0] = 0.337954f;	val_dir[3720*3 + 1] = 0.180242f;	val_dir[3720*3 + 2] = 0.923742f;
+ 	val_dir[3721*3 + 0] = 0.371191f;	val_dir[3721*3 + 1] = 0.208795f;	val_dir[3721*3 + 2] = 0.904777f;
+ 	val_dir[3722*3 + 0] = 0.405452f;	val_dir[3722*3 + 1] = 0.238501f;	val_dir[3722*3 + 2] = 0.882454f;
+ 	val_dir[3723*3 + 0] = 0.440468f;	val_dir[3723*3 + 1] = 0.269175f;	val_dir[3723*3 + 2] = 0.856465f;
+ 	val_dir[3724*3 + 0] = 0.475893f;	val_dir[3724*3 + 1] = 0.300564f;	val_dir[3724*3 + 2] = 0.826551f;
+ 	val_dir[3725*3 + 0] = 0.511310f;	val_dir[3725*3 + 1] = 0.332352f;	val_dir[3725*3 + 2] = 0.792530f;
+ 	val_dir[3726*3 + 0] = 0.546238f;	val_dir[3726*3 + 1] = 0.364159f;	val_dir[3726*3 + 2] = 0.754329f;
+ 	val_dir[3727*3 + 0] = 0.580154f;	val_dir[3727*3 + 1] = 0.395559f;	val_dir[3727*3 + 2] = 0.712007f;
+ 	val_dir[3728*3 + 0] = 0.612517f;	val_dir[3728*3 + 1] = 0.426099f;	val_dir[3728*3 + 2] = 0.665780f;
+ 	val_dir[3729*3 + 0] = 0.642806f;	val_dir[3729*3 + 1] = 0.455321f;	val_dir[3729*3 + 2] = 0.616022f;
+ 	val_dir[3730*3 + 0] = 0.670552f;	val_dir[3730*3 + 1] = 0.482798f;	val_dir[3730*3 + 2] = 0.563264f;
+ 	val_dir[3731*3 + 0] = 0.695376f;	val_dir[3731*3 + 1] = 0.508159f;	val_dir[3731*3 + 2] = 0.508159f;
+ 	val_dir[3732*3 + 0] = 0.717011f;	val_dir[3732*3 + 1] = 0.531119f;	val_dir[3732*3 + 2] = 0.451451f;
+ 	val_dir[3733*3 + 0] = 0.735316f;	val_dir[3733*3 + 1] = 0.551487f;	val_dir[3733*3 + 2] = 0.393919f;
+ 	val_dir[3734*3 + 0] = 0.750279f;	val_dir[3734*3 + 1] = 0.569177f;	val_dir[3734*3 + 2] = 0.336332f;
+ 	val_dir[3735*3 + 0] = 0.762001f;	val_dir[3735*3 + 1] = 0.584201f;	val_dir[3735*3 + 2] = 0.27940f;
+ 	val_dir[3736*3 + 0] = 0.770677f;	val_dir[3736*3 + 1] = 0.596653f;	val_dir[3736*3 + 2] = 0.223745f;
+ 	val_dir[3737*3 + 0] = 0.776571f;	val_dir[3737*3 + 1] = 0.606696f;	val_dir[3737*3 + 2] = 0.169875f;
+ 	val_dir[3738*3 + 0] = 0.779987f;	val_dir[3738*3 + 1] = 0.614535f;	val_dir[3738*3 + 2] = 0.118180f;
+ 	val_dir[3739*3 + 0] = 0.781248f;	val_dir[3739*3 + 1] = 0.620403f;	val_dir[3739*3 + 2] = 0.068934f;
+ 	val_dir[3740*3 + 0] = 0.780675f;	val_dir[3740*3 + 1] = 0.624540f;	val_dir[3740*3 + 2] = 0.022305f;
+ 	val_dir[3741*3 + 0] = -0.638018f;	val_dir[3741*3 + 1] = -0.770022f;	val_dir[3741*3 + 2] = 0.0f;
+ 	val_dir[3742*3 + 0] = -0.635053f;	val_dir[3742*3 + 1] = -0.771136f;	val_dir[3742*3 + 2] = 0.045361f;
+ 	val_dir[3743*3 + 0] = -0.630470f;	val_dir[3743*3 + 1] = -0.770574f;	val_dir[3743*3 + 2] = 0.093403f;
+ 	val_dir[3744*3 + 0] = -0.624020f;	val_dir[3744*3 + 1] = -0.768025f;	val_dir[3744*3 + 2] = 0.144005f;
+ 	val_dir[3745*3 + 0] = -0.615457f;	val_dir[3745*3 + 1] = -0.763167f;	val_dir[3745*3 + 2] = 0.196946f;
+ 	val_dir[3746*3 + 0] = -0.604551f;	val_dir[3746*3 + 1] = -0.755689f;	val_dir[3746*3 + 2] = 0.251896f;
+ 	val_dir[3747*3 + 0] = -0.591105f;	val_dir[3747*3 + 1] = -0.745307f;	val_dir[3747*3 + 2] = 0.308403f;
+ 	val_dir[3748*3 + 0] = -0.574979f;	val_dir[3748*3 + 1] = -0.731792f;	val_dir[3748*3 + 2] = 0.365896f;
+ 	val_dir[3749*3 + 0] = -0.556108f;	val_dir[3749*3 + 1] = -0.714997f;	val_dir[3749*3 + 2] = 0.423702f;
+ 	val_dir[3750*3 + 0] = -0.534522f;	val_dir[3750*3 + 1] = -0.694879f;	val_dir[3750*3 + 2] = 0.481070f;
+ 	val_dir[3751*3 + 0] = -0.510355f;	val_dir[3751*3 + 1] = -0.671519f;	val_dir[3751*3 + 2] = 0.537215f;
+ 	val_dir[3752*3 + 0] = -0.483843f;	val_dir[3752*3 + 1] = -0.645124f;	val_dir[3752*3 + 2] = 0.591364f;
+ 	val_dir[3753*3 + 0] = -0.455321f;	val_dir[3753*3 + 1] = -0.616022f;	val_dir[3753*3 + 2] = 0.642806f;
+ 	val_dir[3754*3 + 0] = -0.425195f;	val_dir[3754*3 + 1] = -0.584643f;	val_dir[3754*3 + 2] = 0.690942f;
+ 	val_dir[3755*3 + 0] = -0.393919f;	val_dir[3755*3 + 1] = -0.551487f;	val_dir[3755*3 + 2] = 0.735316f;
+ 	val_dir[3756*3 + 0] = -0.361961f;	val_dir[3756*3 + 1] = -0.517088f;	val_dir[3756*3 + 2] = 0.775632f;
+ 	val_dir[3757*3 + 0] = -0.329775f;	val_dir[3757*3 + 1] = -0.481979f;	val_dir[3757*3 + 2] = 0.811754f;
+ 	val_dir[3758*3 + 0] = -0.297775f;	val_dir[3758*3 + 1] = -0.446662f;	val_dir[3758*3 + 2] = 0.843696f;
+ 	val_dir[3759*3 + 0] = -0.266320f;	val_dir[3759*3 + 1] = -0.411585f;	val_dir[3759*3 + 2] = 0.871592f;
+ 	val_dir[3760*3 + 0] = -0.235702f;	val_dir[3760*3 + 1] = -0.377124f;	val_dir[3760*3 + 2] = 0.895669f;
+ 	val_dir[3761*3 + 0] = -0.206149f;	val_dir[3761*3 + 1] = -0.343582f;	val_dir[3761*3 + 2] = 0.916217f;
+ 	val_dir[3762*3 + 0] = -0.177822f;	val_dir[3762*3 + 1] = -0.311188f;	val_dir[3762*3 + 2] = 0.933564f;
+ 	val_dir[3763*3 + 0] = -0.150826f;	val_dir[3763*3 + 1] = -0.280105f;	val_dir[3763*3 + 2] = 0.948047f;
+ 	val_dir[3764*3 + 0] = -0.125218f;	val_dir[3764*3 + 1] = -0.250435f;	val_dir[3764*3 + 2] = 0.960001f;
+ 	val_dir[3765*3 + 0] = -0.101015f;	val_dir[3765*3 + 1] = -0.222234f;	val_dir[3765*3 + 2] = 0.969746f;
+ 	val_dir[3766*3 + 0] = -0.078206f;	val_dir[3766*3 + 1] = -0.195515f;	val_dir[3766*3 + 2] = 0.977577f;
+ 	val_dir[3767*3 + 0] = -0.056756f;	val_dir[3767*3 + 1] = -0.170267f;	val_dir[3767*3 + 2] = 0.983762f;
+ 	val_dir[3768*3 + 0] = -0.036613f;	val_dir[3768*3 + 1] = -0.146450f;	val_dir[3768*3 + 2] = 0.988540f;
+ 	val_dir[3769*3 + 0] = -0.017716f;	val_dir[3769*3 + 1] = -0.124015f;	val_dir[3769*3 + 2] = 0.992122f;
+ 	val_dir[3770*3 + 0] = 0.0f;	val_dir[3770*3 + 1] = -0.102899f;	val_dir[3770*3 + 2] = 0.994692f;
+ 	val_dir[3771*3 + 0] = 0.017175f;	val_dir[3771*3 + 1] = -0.085876f;	val_dir[3771*3 + 2] = 0.996158f;
+ 	val_dir[3772*3 + 0] = 0.034381f;	val_dir[3772*3 + 1] = -0.068761f;	val_dir[3772*3 + 2] = 0.997041f;
+ 	val_dir[3773*3 + 0] = 0.051586f;	val_dir[3773*3 + 1] = -0.051586f;	val_dir[3773*3 + 2] = 0.997335f;
+ 	val_dir[3774*3 + 0] = 0.068761f;	val_dir[3774*3 + 1] = -0.034381f;	val_dir[3774*3 + 2] = 0.997041f;
+ 	val_dir[3775*3 + 0] = 0.085876f;	val_dir[3775*3 + 1] = -0.017175f;	val_dir[3775*3 + 2] = 0.996158f;
+ 	val_dir[3776*3 + 0] = 0.102899f;	val_dir[3776*3 + 1] = 0.0f;	val_dir[3776*3 + 2] = 0.994692f;
+ 	val_dir[3777*3 + 0] = 0.124015f;	val_dir[3777*3 + 1] = 0.017716f;	val_dir[3777*3 + 2] = 0.992122f;
+ 	val_dir[3778*3 + 0] = 0.146450f;	val_dir[3778*3 + 1] = 0.036613f;	val_dir[3778*3 + 2] = 0.988540f;
+ 	val_dir[3779*3 + 0] = 0.170267f;	val_dir[3779*3 + 1] = 0.056756f;	val_dir[3779*3 + 2] = 0.983762f;
+ 	val_dir[3780*3 + 0] = 0.195515f;	val_dir[3780*3 + 1] = 0.078206f;	val_dir[3780*3 + 2] = 0.977577f;
+ 	val_dir[3781*3 + 0] = 0.222234f;	val_dir[3781*3 + 1] = 0.101015f;	val_dir[3781*3 + 2] = 0.969746f;
+ 	val_dir[3782*3 + 0] = 0.250435f;	val_dir[3782*3 + 1] = 0.125218f;	val_dir[3782*3 + 2] = 0.960001f;
+ 	val_dir[3783*3 + 0] = 0.280105f;	val_dir[3783*3 + 1] = 0.150826f;	val_dir[3783*3 + 2] = 0.948047f;
+ 	val_dir[3784*3 + 0] = 0.311188f;	val_dir[3784*3 + 1] = 0.177822f;	val_dir[3784*3 + 2] = 0.933564f;
+ 	val_dir[3785*3 + 0] = 0.343582f;	val_dir[3785*3 + 1] = 0.206149f;	val_dir[3785*3 + 2] = 0.916217f;
+ 	val_dir[3786*3 + 0] = 0.377124f;	val_dir[3786*3 + 1] = 0.235702f;	val_dir[3786*3 + 2] = 0.895669f;
+ 	val_dir[3787*3 + 0] = 0.411585f;	val_dir[3787*3 + 1] = 0.266320f;	val_dir[3787*3 + 2] = 0.871592f;
+ 	val_dir[3788*3 + 0] = 0.446662f;	val_dir[3788*3 + 1] = 0.297775f;	val_dir[3788*3 + 2] = 0.843696f;
+ 	val_dir[3789*3 + 0] = 0.481979f;	val_dir[3789*3 + 1] = 0.329775f;	val_dir[3789*3 + 2] = 0.811754f;
+ 	val_dir[3790*3 + 0] = 0.517088f;	val_dir[3790*3 + 1] = 0.361961f;	val_dir[3790*3 + 2] = 0.775632f;
+ 	val_dir[3791*3 + 0] = 0.551487f;	val_dir[3791*3 + 1] = 0.393919f;	val_dir[3791*3 + 2] = 0.735316f;
+ 	val_dir[3792*3 + 0] = 0.584643f;	val_dir[3792*3 + 1] = 0.425195f;	val_dir[3792*3 + 2] = 0.690942f;
+ 	val_dir[3793*3 + 0] = 0.616022f;	val_dir[3793*3 + 1] = 0.455321f;	val_dir[3793*3 + 2] = 0.642806f;
+ 	val_dir[3794*3 + 0] = 0.645124f;	val_dir[3794*3 + 1] = 0.483843f;	val_dir[3794*3 + 2] = 0.591364f;
+ 	val_dir[3795*3 + 0] = 0.671519f;	val_dir[3795*3 + 1] = 0.510355f;	val_dir[3795*3 + 2] = 0.537215f;
+ 	val_dir[3796*3 + 0] = 0.694879f;	val_dir[3796*3 + 1] = 0.534522f;	val_dir[3796*3 + 2] = 0.481070f;
+ 	val_dir[3797*3 + 0] = 0.714997f;	val_dir[3797*3 + 1] = 0.556108f;	val_dir[3797*3 + 2] = 0.423702f;
+ 	val_dir[3798*3 + 0] = 0.731792f;	val_dir[3798*3 + 1] = 0.574979f;	val_dir[3798*3 + 2] = 0.365896f;
+ 	val_dir[3799*3 + 0] = 0.745307f;	val_dir[3799*3 + 1] = 0.591105f;	val_dir[3799*3 + 2] = 0.308403f;
+ 	val_dir[3800*3 + 0] = 0.755689f;	val_dir[3800*3 + 1] = 0.604551f;	val_dir[3800*3 + 2] = 0.251896f;
+ 	val_dir[3801*3 + 0] = 0.763167f;	val_dir[3801*3 + 1] = 0.615457f;	val_dir[3801*3 + 2] = 0.196946f;
+ 	val_dir[3802*3 + 0] = 0.768025f;	val_dir[3802*3 + 1] = 0.624020f;	val_dir[3802*3 + 2] = 0.144005f;
+ 	val_dir[3803*3 + 0] = 0.770574f;	val_dir[3803*3 + 1] = 0.630470f;	val_dir[3803*3 + 2] = 0.093403f;
+ 	val_dir[3804*3 + 0] = 0.771136f;	val_dir[3804*3 + 1] = 0.635053f;	val_dir[3804*3 + 2] = 0.045361f;
+ 	val_dir[3805*3 + 0] = 0.770022f;	val_dir[3805*3 + 1] = 0.638018f;	val_dir[3805*3 + 2] = 0.0f;
+ 	val_dir[3806*3 + 0] = -0.648784f;	val_dir[3806*3 + 1] = -0.760644f;	val_dir[3806*3 + 2] = 0.022372f;
+ 	val_dir[3807*3 + 0] = -0.645429f;	val_dir[3807*3 + 1] = -0.760684f;	val_dir[3807*3 + 2] = 0.069153f;
+ 	val_dir[3808*3 + 0] = -0.640321f;	val_dir[3808*3 + 1] = -0.758899f;	val_dir[3808*3 + 2] = 0.118578f;
+ 	val_dir[3809*3 + 0] = -0.633205f;	val_dir[3809*3 + 1] = -0.754976f;	val_dir[3809*3 + 2] = 0.170478f;
+ 	val_dir[3810*3 + 0] = -0.623831f;	val_dir[3810*3 + 1] = -0.748598f;	val_dir[3810*3 + 2] = 0.224579f;
+ 	val_dir[3811*3 + 0] = -0.611974f;	val_dir[3811*3 + 1] = -0.739469f;	val_dir[3811*3 + 2] = 0.280488f;
+ 	val_dir[3812*3 + 0] = -0.597453f;	val_dir[3812*3 + 1] = -0.727334f;	val_dir[3812*3 + 2] = 0.337691f;
+ 	val_dir[3813*3 + 0] = -0.580154f;	val_dir[3813*3 + 1] = -0.712007f;	val_dir[3813*3 + 2] = 0.395559f;
+ 	val_dir[3814*3 + 0] = -0.560050f;	val_dir[3814*3 + 1] = -0.693395f;	val_dir[3814*3 + 2] = 0.453374f;
+ 	val_dir[3815*3 + 0] = -0.537215f;	val_dir[3815*3 + 1] = -0.671519f;	val_dir[3815*3 + 2] = 0.510355f;
+ 	val_dir[3816*3 + 0] = -0.511834f;	val_dir[3816*3 + 1] = -0.646527f;	val_dir[3816*3 + 2] = 0.565711f;
+ 	val_dir[3817*3 + 0] = -0.484193f;	val_dir[3817*3 + 1] = -0.618691f;	val_dir[3817*3 + 2] = 0.618691f;
+ 	val_dir[3818*3 + 0] = -0.454669f;	val_dir[3818*3 + 1] = -0.588395f;	val_dir[3818*3 + 2] = 0.668631f;
+ 	val_dir[3819*3 + 0] = -0.423702f;	val_dir[3819*3 + 1] = -0.556108f;	val_dir[3819*3 + 2] = 0.714997f;
+ 	val_dir[3820*3 + 0] = -0.391764f;	val_dir[3820*3 + 1] = -0.522352f;	val_dir[3820*3 + 2] = 0.757410f;
+ 	val_dir[3821*3 + 0] = -0.359329f;	val_dir[3821*3 + 1] = -0.487661f;	val_dir[3821*3 + 2] = 0.795657f;
+ 	val_dir[3822*3 + 0] = -0.326844f;	val_dir[3822*3 + 1] = -0.452553f;	val_dir[3822*3 + 2] = 0.829680f;
+ 	val_dir[3823*3 + 0] = -0.294706f;	val_dir[3823*3 + 1] = -0.41750f;	val_dir[3823*3 + 2] = 0.859559f;
+ 	val_dir[3824*3 + 0] = -0.263251f;	val_dir[3824*3 + 1] = -0.382911f;	val_dir[3824*3 + 2] = 0.885482f;
+ 	val_dir[3825*3 + 0] = -0.232747f;	val_dir[3825*3 + 1] = -0.349121f;	val_dir[3825*3 + 2] = 0.907713f;
+ 	val_dir[3826*3 + 0] = -0.203393f;	val_dir[3826*3 + 1] = -0.316389f;	val_dir[3826*3 + 2] = 0.926568f;
+ 	val_dir[3827*3 + 0] = -0.175327f;	val_dir[3827*3 + 1] = -0.284907f;	val_dir[3827*3 + 2] = 0.942384f;
+ 	val_dir[3828*3 + 0] = -0.148634f;	val_dir[3828*3 + 1] = -0.254801f;	val_dir[3828*3 + 2] = 0.955502f;
+ 	val_dir[3829*3 + 0] = -0.123351f;	val_dir[3829*3 + 1] = -0.226144f;	val_dir[3829*3 + 2] = 0.966252f;
+ 	val_dir[3830*3 + 0] = -0.099484f;	val_dir[3830*3 + 1] = -0.198968f;	val_dir[3830*3 + 2] = 0.974943f;
+ 	val_dir[3831*3 + 0] = -0.077009f;	val_dir[3831*3 + 1] = -0.173269f;	val_dir[3831*3 + 2] = 0.981859f;
+ 	val_dir[3832*3 + 0] = -0.055882f;	val_dir[3832*3 + 1] = -0.149019f;	val_dir[3832*3 + 2] = 0.987254f;
+ 	val_dir[3833*3 + 0] = -0.036049f;	val_dir[3833*3 + 1] = -0.126172f;	val_dir[3833*3 + 2] = 0.991353f;
+ 	val_dir[3834*3 + 0] = -0.017445f;	val_dir[3834*3 + 1] = -0.104669f;	val_dir[3834*3 + 2] = 0.994354f;
+ 	val_dir[3835*3 + 0] = 0.0f;	val_dir[3835*3 + 1] = -0.084443f;	val_dir[3835*3 + 2] = 0.996428f;
+ 	val_dir[3836*3 + 0] = 0.016908f;	val_dir[3836*3 + 1] = -0.067632f;	val_dir[3836*3 + 2] = 0.997567f;
+ 	val_dir[3837*3 + 0] = 0.033835f;	val_dir[3837*3 + 1] = -0.050753f;	val_dir[3837*3 + 2] = 0.998138f;
+ 	val_dir[3838*3 + 0] = 0.050753f;	val_dir[3838*3 + 1] = -0.033835f;	val_dir[3838*3 + 2] = 0.998138f;
+ 	val_dir[3839*3 + 0] = 0.067632f;	val_dir[3839*3 + 1] = -0.016908f;	val_dir[3839*3 + 2] = 0.997567f;
+ 	val_dir[3840*3 + 0] = 0.084443f;	val_dir[3840*3 + 1] = 0.0f;	val_dir[3840*3 + 2] = 0.996428f;
+ 	val_dir[3841*3 + 0] = 0.104669f;	val_dir[3841*3 + 1] = 0.017445f;	val_dir[3841*3 + 2] = 0.994354f;
+ 	val_dir[3842*3 + 0] = 0.126172f;	val_dir[3842*3 + 1] = 0.036049f;	val_dir[3842*3 + 2] = 0.991353f;
+ 	val_dir[3843*3 + 0] = 0.149019f;	val_dir[3843*3 + 1] = 0.055882f;	val_dir[3843*3 + 2] = 0.987254f;
+ 	val_dir[3844*3 + 0] = 0.173269f;	val_dir[3844*3 + 1] = 0.077009f;	val_dir[3844*3 + 2] = 0.981859f;
+ 	val_dir[3845*3 + 0] = 0.198968f;	val_dir[3845*3 + 1] = 0.099484f;	val_dir[3845*3 + 2] = 0.974943f;
+ 	val_dir[3846*3 + 0] = 0.226144f;	val_dir[3846*3 + 1] = 0.123351f;	val_dir[3846*3 + 2] = 0.966252f;
+ 	val_dir[3847*3 + 0] = 0.254801f;	val_dir[3847*3 + 1] = 0.148634f;	val_dir[3847*3 + 2] = 0.955502f;
+ 	val_dir[3848*3 + 0] = 0.284907f;	val_dir[3848*3 + 1] = 0.175327f;	val_dir[3848*3 + 2] = 0.942384f;
+ 	val_dir[3849*3 + 0] = 0.316389f;	val_dir[3849*3 + 1] = 0.203393f;	val_dir[3849*3 + 2] = 0.926568f;
+ 	val_dir[3850*3 + 0] = 0.349121f;	val_dir[3850*3 + 1] = 0.232747f;	val_dir[3850*3 + 2] = 0.907713f;
+ 	val_dir[3851*3 + 0] = 0.382911f;	val_dir[3851*3 + 1] = 0.263251f;	val_dir[3851*3 + 2] = 0.885482f;
+ 	val_dir[3852*3 + 0] = 0.41750f;	val_dir[3852*3 + 1] = 0.294706f;	val_dir[3852*3 + 2] = 0.859559f;
+ 	val_dir[3853*3 + 0] = 0.452553f;	val_dir[3853*3 + 1] = 0.326844f;	val_dir[3853*3 + 2] = 0.829680f;
+ 	val_dir[3854*3 + 0] = 0.487661f;	val_dir[3854*3 + 1] = 0.359329f;	val_dir[3854*3 + 2] = 0.795657f;
+ 	val_dir[3855*3 + 0] = 0.522352f;	val_dir[3855*3 + 1] = 0.391764f;	val_dir[3855*3 + 2] = 0.757410f;
+ 	val_dir[3856*3 + 0] = 0.556108f;	val_dir[3856*3 + 1] = 0.423702f;	val_dir[3856*3 + 2] = 0.714997f;
+ 	val_dir[3857*3 + 0] = 0.588395f;	val_dir[3857*3 + 1] = 0.454669f;	val_dir[3857*3 + 2] = 0.668631f;
+ 	val_dir[3858*3 + 0] = 0.618691f;	val_dir[3858*3 + 1] = 0.484193f;	val_dir[3858*3 + 2] = 0.618691f;
+ 	val_dir[3859*3 + 0] = 0.646527f;	val_dir[3859*3 + 1] = 0.511834f;	val_dir[3859*3 + 2] = 0.565711f;
+ 	val_dir[3860*3 + 0] = 0.671519f;	val_dir[3860*3 + 1] = 0.537215f;	val_dir[3860*3 + 2] = 0.510355f;
+ 	val_dir[3861*3 + 0] = 0.693395f;	val_dir[3861*3 + 1] = 0.560050f;	val_dir[3861*3 + 2] = 0.453374f;
+ 	val_dir[3862*3 + 0] = 0.712007f;	val_dir[3862*3 + 1] = 0.580154f;	val_dir[3862*3 + 2] = 0.395559f;
+ 	val_dir[3863*3 + 0] = 0.727334f;	val_dir[3863*3 + 1] = 0.597453f;	val_dir[3863*3 + 2] = 0.337691f;
+ 	val_dir[3864*3 + 0] = 0.739469f;	val_dir[3864*3 + 1] = 0.611974f;	val_dir[3864*3 + 2] = 0.280488f;
+ 	val_dir[3865*3 + 0] = 0.748598f;	val_dir[3865*3 + 1] = 0.623831f;	val_dir[3865*3 + 2] = 0.224579f;
+ 	val_dir[3866*3 + 0] = 0.754976f;	val_dir[3866*3 + 1] = 0.633205f;	val_dir[3866*3 + 2] = 0.170478f;
+ 	val_dir[3867*3 + 0] = 0.758899f;	val_dir[3867*3 + 1] = 0.640321f;	val_dir[3867*3 + 2] = 0.118578f;
+ 	val_dir[3868*3 + 0] = 0.760684f;	val_dir[3868*3 + 1] = 0.645429f;	val_dir[3868*3 + 2] = 0.069153f;
+ 	val_dir[3869*3 + 0] = 0.760644f;	val_dir[3869*3 + 1] = 0.648784f;	val_dir[3869*3 + 2] = 0.022372f;
+ 	val_dir[3870*3 + 0] = -0.661622f;	val_dir[3870*3 + 1] = -0.749838f;	val_dir[3870*3 + 2] = 0.0f;
+ 	val_dir[3871*3 + 0] = -0.659432f;	val_dir[3871*3 + 1] = -0.750388f;	val_dir[3871*3 + 2] = 0.045478f;
+ 	val_dir[3872*3 + 0] = -0.655610f;	val_dir[3872*3 + 1] = -0.749269f;	val_dir[3872*3 + 2] = 0.093659f;
+ 	val_dir[3873*3 + 0] = -0.649895f;	val_dir[3873*3 + 1] = -0.746176f;	val_dir[3873*3 + 2] = 0.144421f;
+ 	val_dir[3874*3 + 0] = -0.642024f;	val_dir[3874*3 + 1] = -0.740797f;	val_dir[3874*3 + 2] = 0.197546f;
+ 	val_dir[3875*3 + 0] = -0.631748f;	val_dir[3875*3 + 1] = -0.732828f;	val_dir[3875*3 + 2] = 0.252699f;
+ 	val_dir[3876*3 + 0] = -0.618853f;	val_dir[3876*3 + 1] = -0.721995f;	val_dir[3876*3 + 2] = 0.309426f;
+ 	val_dir[3877*3 + 0] = -0.603178f;	val_dir[3877*3 + 1] = -0.708079f;	val_dir[3877*3 + 2] = 0.367152f;
+ 	val_dir[3878*3 + 0] = -0.584643f;	val_dir[3878*3 + 1] = -0.690942f;	val_dir[3878*3 + 2] = 0.425195f;
+ 	val_dir[3879*3 + 0] = -0.563264f;	val_dir[3879*3 + 1] = -0.670552f;	val_dir[3879*3 + 2] = 0.482798f;
+ 	val_dir[3880*3 + 0] = -0.539164f;	val_dir[3880*3 + 1] = -0.646997f;	val_dir[3880*3 + 2] = 0.539164f;
+ 	val_dir[3881*3 + 0] = -0.512578f;	val_dir[3881*3 + 1] = -0.620490f;	val_dir[3881*3 + 2] = 0.593512f;
+ 	val_dir[3882*3 + 0] = -0.483843f;	val_dir[3882*3 + 1] = -0.591364f;	val_dir[3882*3 + 2] = 0.645124f;
+ 	val_dir[3883*3 + 0] = -0.453374f;	val_dir[3883*3 + 1] = -0.560050f;	val_dir[3883*3 + 2] = 0.693395f;
+ 	val_dir[3884*3 + 0] = -0.421637f;	val_dir[3884*3 + 1] = -0.527046f;	val_dir[3884*3 + 2] = 0.737865f;
+ 	val_dir[3885*3 + 0] = -0.389118f;	val_dir[3885*3 + 1] = -0.492883f;	val_dir[3885*3 + 2] = 0.778237f;
+ 	val_dir[3886*3 + 0] = -0.356291f;	val_dir[3886*3 + 1] = -0.458088f;	val_dir[3886*3 + 2] = 0.814379f;
+ 	val_dir[3887*3 + 0] = -0.323587f;	val_dir[3887*3 + 1] = -0.423153f;	val_dir[3887*3 + 2] = 0.846305f;
+ 	val_dir[3888*3 + 0] = -0.291386f;	val_dir[3888*3 + 1] = -0.388514f;	val_dir[3888*3 + 2] = 0.874157f;
+ 	val_dir[3889*3 + 0] = -0.259996f;	val_dir[3889*3 + 1] = -0.354540f;	val_dir[3889*3 + 2] = 0.898167f;
+ 	val_dir[3890*3 + 0] = -0.229658f;	val_dir[3890*3 + 1] = -0.321521f;	val_dir[3890*3 + 2] = 0.918630f;
+ 	val_dir[3891*3 + 0] = -0.200545f;	val_dir[3891*3 + 1] = -0.289677f;	val_dir[3891*3 + 2] = 0.935879f;
+ 	val_dir[3892*3 + 0] = -0.172774f;	val_dir[3892*3 + 1] = -0.259161f;	val_dir[3892*3 + 2] = 0.950255f;
+ 	val_dir[3893*3 + 0] = -0.146406f;	val_dir[3893*3 + 1] = -0.230067f;	val_dir[3893*3 + 2] = 0.962099f;
+ 	val_dir[3894*3 + 0] = -0.121466f;	val_dir[3894*3 + 1] = -0.202444f;	val_dir[3894*3 + 2] = 0.971732f;
+ 	val_dir[3895*3 + 0] = -0.097945f;	val_dir[3895*3 + 1] = -0.176301f;	val_dir[3895*3 + 2] = 0.979451f;
+ 	val_dir[3896*3 + 0] = -0.075810f;	val_dir[3896*3 + 1] = -0.151620f;	val_dir[3896*3 + 2] = 0.985527f;
+ 	val_dir[3897*3 + 0] = -0.055011f;	val_dir[3897*3 + 1] = -0.128359f;	val_dir[3897*3 + 2] = 0.990201f;
+ 	val_dir[3898*3 + 0] = -0.035489f;	val_dir[3898*3 + 1] = -0.106466f;	val_dir[3898*3 + 2] = 0.993683f;
+ 	val_dir[3899*3 + 0] = -0.017175f;	val_dir[3899*3 + 1] = -0.085876f;	val_dir[3899*3 + 2] = 0.996158f;
+ 	val_dir[3900*3 + 0] = 0.0f;	val_dir[3900*3 + 1] = -0.066519f;	val_dir[3900*3 + 2] = 0.997785f;
+ 	val_dir[3901*3 + 0] = 0.016644f;	val_dir[3901*3 + 1] = -0.049931f;	val_dir[3901*3 + 2] = 0.998614f;
+ 	val_dir[3902*3 + 0] = 0.033296f;	val_dir[3902*3 + 1] = -0.033296f;	val_dir[3902*3 + 2] = 0.998891f;
+ 	val_dir[3903*3 + 0] = 0.049931f;	val_dir[3903*3 + 1] = -0.016644f;	val_dir[3903*3 + 2] = 0.998614f;
+ 	val_dir[3904*3 + 0] = 0.066519f;	val_dir[3904*3 + 1] = 0.0f;	val_dir[3904*3 + 2] = 0.997785f;
+ 	val_dir[3905*3 + 0] = 0.085876f;	val_dir[3905*3 + 1] = 0.017175f;	val_dir[3905*3 + 2] = 0.996158f;
+ 	val_dir[3906*3 + 0] = 0.106466f;	val_dir[3906*3 + 1] = 0.035489f;	val_dir[3906*3 + 2] = 0.993683f;
+ 	val_dir[3907*3 + 0] = 0.128359f;	val_dir[3907*3 + 1] = 0.055011f;	val_dir[3907*3 + 2] = 0.990201f;
+ 	val_dir[3908*3 + 0] = 0.151620f;	val_dir[3908*3 + 1] = 0.075810f;	val_dir[3908*3 + 2] = 0.985527f;
+ 	val_dir[3909*3 + 0] = 0.176301f;	val_dir[3909*3 + 1] = 0.097945f;	val_dir[3909*3 + 2] = 0.979451f;
+ 	val_dir[3910*3 + 0] = 0.202444f;	val_dir[3910*3 + 1] = 0.121466f;	val_dir[3910*3 + 2] = 0.971732f;
+ 	val_dir[3911*3 + 0] = 0.230067f;	val_dir[3911*3 + 1] = 0.146406f;	val_dir[3911*3 + 2] = 0.962099f;
+ 	val_dir[3912*3 + 0] = 0.259161f;	val_dir[3912*3 + 1] = 0.172774f;	val_dir[3912*3 + 2] = 0.950255f;
+ 	val_dir[3913*3 + 0] = 0.289677f;	val_dir[3913*3 + 1] = 0.200545f;	val_dir[3913*3 + 2] = 0.935879f;
+ 	val_dir[3914*3 + 0] = 0.321521f;	val_dir[3914*3 + 1] = 0.229658f;	val_dir[3914*3 + 2] = 0.918630f;
+ 	val_dir[3915*3 + 0] = 0.354540f;	val_dir[3915*3 + 1] = 0.259996f;	val_dir[3915*3 + 2] = 0.898167f;
+ 	val_dir[3916*3 + 0] = 0.388514f;	val_dir[3916*3 + 1] = 0.291386f;	val_dir[3916*3 + 2] = 0.874157f;
+ 	val_dir[3917*3 + 0] = 0.423153f;	val_dir[3917*3 + 1] = 0.323587f;	val_dir[3917*3 + 2] = 0.846305f;
+ 	val_dir[3918*3 + 0] = 0.458088f;	val_dir[3918*3 + 1] = 0.356291f;	val_dir[3918*3 + 2] = 0.814379f;
+ 	val_dir[3919*3 + 0] = 0.492883f;	val_dir[3919*3 + 1] = 0.389118f;	val_dir[3919*3 + 2] = 0.778237f;
+ 	val_dir[3920*3 + 0] = 0.527046f;	val_dir[3920*3 + 1] = 0.421637f;	val_dir[3920*3 + 2] = 0.737865f;
+ 	val_dir[3921*3 + 0] = 0.560050f;	val_dir[3921*3 + 1] = 0.453374f;	val_dir[3921*3 + 2] = 0.693395f;
+ 	val_dir[3922*3 + 0] = 0.591364f;	val_dir[3922*3 + 1] = 0.483843f;	val_dir[3922*3 + 2] = 0.645124f;
+ 	val_dir[3923*3 + 0] = 0.620490f;	val_dir[3923*3 + 1] = 0.512578f;	val_dir[3923*3 + 2] = 0.593512f;
+ 	val_dir[3924*3 + 0] = 0.646997f;	val_dir[3924*3 + 1] = 0.539164f;	val_dir[3924*3 + 2] = 0.539164f;
+ 	val_dir[3925*3 + 0] = 0.670552f;	val_dir[3925*3 + 1] = 0.563264f;	val_dir[3925*3 + 2] = 0.482798f;
+ 	val_dir[3926*3 + 0] = 0.690942f;	val_dir[3926*3 + 1] = 0.584643f;	val_dir[3926*3 + 2] = 0.425195f;
+ 	val_dir[3927*3 + 0] = 0.708079f;	val_dir[3927*3 + 1] = 0.603178f;	val_dir[3927*3 + 2] = 0.367152f;
+ 	val_dir[3928*3 + 0] = 0.721995f;	val_dir[3928*3 + 1] = 0.618853f;	val_dir[3928*3 + 2] = 0.309426f;
+ 	val_dir[3929*3 + 0] = 0.732828f;	val_dir[3929*3 + 1] = 0.631748f;	val_dir[3929*3 + 2] = 0.252699f;
+ 	val_dir[3930*3 + 0] = 0.740797f;	val_dir[3930*3 + 1] = 0.642024f;	val_dir[3930*3 + 2] = 0.197546f;
+ 	val_dir[3931*3 + 0] = 0.746176f;	val_dir[3931*3 + 1] = 0.649895f;	val_dir[3931*3 + 2] = 0.144421f;
+ 	val_dir[3932*3 + 0] = 0.749269f;	val_dir[3932*3 + 1] = 0.655610f;	val_dir[3932*3 + 2] = 0.093659f;
+ 	val_dir[3933*3 + 0] = 0.750388f;	val_dir[3933*3 + 1] = 0.659432f;	val_dir[3933*3 + 2] = 0.045478f;
+ 	val_dir[3934*3 + 0] = 0.749838f;	val_dir[3934*3 + 1] = 0.661622f;	val_dir[3934*3 + 2] = 0.0f;
+ 	val_dir[3935*3 + 0] = -0.672504f;	val_dir[3935*3 + 1] = -0.739754f;	val_dir[3935*3 + 2] = 0.022417f;
+ 	val_dir[3936*3 + 0] = -0.669905f;	val_dir[3936*3 + 1] = -0.739205f;	val_dir[3936*3 + 2] = 0.069301f;
+ 	val_dir[3937*3 + 0] = -0.665536f;	val_dir[3937*3 + 1] = -0.736843f;	val_dir[3937*3 + 2] = 0.118846f;
+ 	val_dir[3938*3 + 0] = -0.659125f;	val_dir[3938*3 + 1] = -0.732361f;	val_dir[3938*3 + 2] = 0.170884f;
+ 	val_dir[3939*3 + 0] = -0.650407f;	val_dir[3939*3 + 1] = -0.725454f;	val_dir[3939*3 + 2] = 0.225141f;
+ 	val_dir[3940*3 + 0] = -0.639138f;	val_dir[3940*3 + 1] = -0.715834f;	val_dir[3940*3 + 2] = 0.281220f;
+ 	val_dir[3941*3 + 0] = -0.625119f;	val_dir[3941*3 + 1] = -0.703259f;	val_dir[3941*3 + 2] = 0.338606f;
+ 	val_dir[3942*3 + 0] = -0.608219f;	val_dir[3942*3 + 1] = -0.687552f;	val_dir[3942*3 + 2] = 0.396664f;
+ 	val_dir[3943*3 + 0] = -0.588395f;	val_dir[3943*3 + 1] = -0.668631f;	val_dir[3943*3 + 2] = 0.454669f;
+ 	val_dir[3944*3 + 0] = -0.565711f;	val_dir[3944*3 + 1] = -0.646527f;	val_dir[3944*3 + 2] = 0.511834f;
+ 	val_dir[3945*3 + 0] = -0.540343f;	val_dir[3945*3 + 1] = -0.621395f;	val_dir[3945*3 + 2] = 0.567360f;
+ 	val_dir[3946*3 + 0] = -0.512578f;	val_dir[3946*3 + 1] = -0.593512f;	val_dir[3946*3 + 2] = 0.620490f;
+ 	val_dir[3947*3 + 0] = -0.482798f;	val_dir[3947*3 + 1] = -0.563264f;	val_dir[3947*3 + 2] = 0.670552f;
+ 	val_dir[3948*3 + 0] = -0.451451f;	val_dir[3948*3 + 1] = -0.531119f;	val_dir[3948*3 + 2] = 0.717011f;
+ 	val_dir[3949*3 + 0] = -0.419026f;	val_dir[3949*3 + 1] = -0.497594f;	val_dir[3949*3 + 2] = 0.759485f;
+ 	val_dir[3950*3 + 0] = -0.386014f;	val_dir[3950*3 + 1] = -0.463217f;	val_dir[3950*3 + 2] = 0.797762f;
+ 	val_dir[3951*3 + 0] = -0.352879f;	val_dir[3951*3 + 1] = -0.428496f;	val_dir[3951*3 + 2] = 0.831786f;
+ 	val_dir[3952*3 + 0] = -0.320038f;	val_dir[3952*3 + 1] = -0.393893f;	val_dir[3952*3 + 2] = 0.861640f;
+ 	val_dir[3953*3 + 0] = -0.287843f;	val_dir[3953*3 + 1] = -0.359804f;	val_dir[3953*3 + 2] = 0.887517f;
+ 	val_dir[3954*3 + 0] = -0.256578f;	val_dir[3954*3 + 1] = -0.326554f;	val_dir[3954*3 + 2] = 0.909687f;
+ 	val_dir[3955*3 + 0] = -0.226455f;	val_dir[3955*3 + 1] = -0.294392f;	val_dir[3955*3 + 2] = 0.928467f;
+ 	val_dir[3956*3 + 0] = -0.197623f;	val_dir[3956*3 + 1] = -0.263498f;	val_dir[3956*3 + 2] = 0.94420f;
+ 	val_dir[3957*3 + 0] = -0.170174f;	val_dir[3957*3 + 1] = -0.233990f;	val_dir[3957*3 + 2] = 0.957230f;
+ 	val_dir[3958*3 + 0] = -0.144154f;	val_dir[3958*3 + 1] = -0.205934f;	val_dir[3958*3 + 2] = 0.967890f;
+ 	val_dir[3959*3 + 0] = -0.119570f;	val_dir[3959*3 + 1] = -0.179355f;	val_dir[3959*3 + 2] = 0.976491f;
+ 	val_dir[3960*3 + 0] = -0.096404f;	val_dir[3960*3 + 1] = -0.154246f;	val_dir[3960*3 + 2] = 0.983318f;
+ 	val_dir[3961*3 + 0] = -0.074613f;	val_dir[3961*3 + 1] = -0.130573f;	val_dir[3961*3 + 2] = 0.988627f;
+ 	val_dir[3962*3 + 0] = -0.054144f;	val_dir[3962*3 + 1] = -0.108288f;	val_dir[3962*3 + 2] = 0.992644f;
+ 	val_dir[3963*3 + 0] = -0.034932f;	val_dir[3963*3 + 1] = -0.087330f;	val_dir[3963*3 + 2] = 0.995567f;
+ 	val_dir[3964*3 + 0] = -0.016908f;	val_dir[3964*3 + 1] = -0.067632f;	val_dir[3964*3 + 2] = 0.997567f;
+ 	val_dir[3965*3 + 0] = 0.0f;	val_dir[3965*3 + 1] = -0.049121f;	val_dir[3965*3 + 2] = 0.998793f;
+ 	val_dir[3966*3 + 0] = 0.016382f;	val_dir[3966*3 + 1] = -0.032765f;	val_dir[3966*3 + 2] = 0.999329f;
+ 	val_dir[3967*3 + 0] = 0.032765f;	val_dir[3967*3 + 1] = -0.016382f;	val_dir[3967*3 + 2] = 0.999329f;
+ 	val_dir[3968*3 + 0] = 0.049121f;	val_dir[3968*3 + 1] = 0.0f;	val_dir[3968*3 + 2] = 0.998793f;
+ 	val_dir[3969*3 + 0] = 0.067632f;	val_dir[3969*3 + 1] = 0.016908f;	val_dir[3969*3 + 2] = 0.997567f;
+ 	val_dir[3970*3 + 0] = 0.087330f;	val_dir[3970*3 + 1] = 0.034932f;	val_dir[3970*3 + 2] = 0.995567f;
+ 	val_dir[3971*3 + 0] = 0.108288f;	val_dir[3971*3 + 1] = 0.054144f;	val_dir[3971*3 + 2] = 0.992644f;
+ 	val_dir[3972*3 + 0] = 0.130573f;	val_dir[3972*3 + 1] = 0.074613f;	val_dir[3972*3 + 2] = 0.988627f;
+ 	val_dir[3973*3 + 0] = 0.154246f;	val_dir[3973*3 + 1] = 0.096404f;	val_dir[3973*3 + 2] = 0.983318f;
+ 	val_dir[3974*3 + 0] = 0.179355f;	val_dir[3974*3 + 1] = 0.119570f;	val_dir[3974*3 + 2] = 0.976491f;
+ 	val_dir[3975*3 + 0] = 0.205934f;	val_dir[3975*3 + 1] = 0.144154f;	val_dir[3975*3 + 2] = 0.967890f;
+ 	val_dir[3976*3 + 0] = 0.233990f;	val_dir[3976*3 + 1] = 0.170174f;	val_dir[3976*3 + 2] = 0.957230f;
+ 	val_dir[3977*3 + 0] = 0.263498f;	val_dir[3977*3 + 1] = 0.197623f;	val_dir[3977*3 + 2] = 0.94420f;
+ 	val_dir[3978*3 + 0] = 0.294392f;	val_dir[3978*3 + 1] = 0.226455f;	val_dir[3978*3 + 2] = 0.928467f;
+ 	val_dir[3979*3 + 0] = 0.326554f;	val_dir[3979*3 + 1] = 0.256578f;	val_dir[3979*3 + 2] = 0.909687f;
+ 	val_dir[3980*3 + 0] = 0.359804f;	val_dir[3980*3 + 1] = 0.287843f;	val_dir[3980*3 + 2] = 0.887517f;
+ 	val_dir[3981*3 + 0] = 0.393893f;	val_dir[3981*3 + 1] = 0.320038f;	val_dir[3981*3 + 2] = 0.861640f;
+ 	val_dir[3982*3 + 0] = 0.428496f;	val_dir[3982*3 + 1] = 0.352879f;	val_dir[3982*3 + 2] = 0.831786f;
+ 	val_dir[3983*3 + 0] = 0.463217f;	val_dir[3983*3 + 1] = 0.386014f;	val_dir[3983*3 + 2] = 0.797762f;
+ 	val_dir[3984*3 + 0] = 0.497594f;	val_dir[3984*3 + 1] = 0.419026f;	val_dir[3984*3 + 2] = 0.759485f;
+ 	val_dir[3985*3 + 0] = 0.531119f;	val_dir[3985*3 + 1] = 0.451451f;	val_dir[3985*3 + 2] = 0.717011f;
+ 	val_dir[3986*3 + 0] = 0.563264f;	val_dir[3986*3 + 1] = 0.482798f;	val_dir[3986*3 + 2] = 0.670552f;
+ 	val_dir[3987*3 + 0] = 0.593512f;	val_dir[3987*3 + 1] = 0.512578f;	val_dir[3987*3 + 2] = 0.620490f;
+ 	val_dir[3988*3 + 0] = 0.621395f;	val_dir[3988*3 + 1] = 0.540343f;	val_dir[3988*3 + 2] = 0.567360f;
+ 	val_dir[3989*3 + 0] = 0.646527f;	val_dir[3989*3 + 1] = 0.565711f;	val_dir[3989*3 + 2] = 0.511834f;
+ 	val_dir[3990*3 + 0] = 0.668631f;	val_dir[3990*3 + 1] = 0.588395f;	val_dir[3990*3 + 2] = 0.454669f;
+ 	val_dir[3991*3 + 0] = 0.687552f;	val_dir[3991*3 + 1] = 0.608219f;	val_dir[3991*3 + 2] = 0.396664f;
+ 	val_dir[3992*3 + 0] = 0.703259f;	val_dir[3992*3 + 1] = 0.625119f;	val_dir[3992*3 + 2] = 0.338606f;
+ 	val_dir[3993*3 + 0] = 0.715834f;	val_dir[3993*3 + 1] = 0.639138f;	val_dir[3993*3 + 2] = 0.281220f;
+ 	val_dir[3994*3 + 0] = 0.725454f;	val_dir[3994*3 + 1] = 0.650407f;	val_dir[3994*3 + 2] = 0.225141f;
+ 	val_dir[3995*3 + 0] = 0.732361f;	val_dir[3995*3 + 1] = 0.659125f;	val_dir[3995*3 + 2] = 0.170884f;
+ 	val_dir[3996*3 + 0] = 0.736843f;	val_dir[3996*3 + 1] = 0.665536f;	val_dir[3996*3 + 2] = 0.118846f;
+ 	val_dir[3997*3 + 0] = 0.739205f;	val_dir[3997*3 + 1] = 0.669905f;	val_dir[3997*3 + 2] = 0.069301f;
+ 	val_dir[3998*3 + 0] = 0.739754f;	val_dir[3998*3 + 1] = 0.672504f;	val_dir[3998*3 + 2] = 0.022417f;
+ 	val_dir[3999*3 + 0] = -0.684675f;	val_dir[3999*3 + 1] = -0.728848f;	val_dir[3999*3 + 2] = 0.0f;
+ 	val_dir[4000*3 + 0] = -0.683231f;	val_dir[4000*3 + 1] = -0.728780f;	val_dir[4000*3 + 2] = 0.045549f;
+ 	val_dir[4001*3 + 0] = -0.680144f;	val_dir[4001*3 + 1] = -0.727051f;	val_dir[4001*3 + 2] = 0.093813f;
+ 	val_dir[4002*3 + 0] = -0.675140f;	val_dir[4002*3 + 1] = -0.723364f;	val_dir[4002*3 + 2] = 0.144673f;
+ 	val_dir[4003*3 + 0] = -0.667940f;	val_dir[4003*3 + 1] = -0.717418f;	val_dir[4003*3 + 2] = 0.197908f;
+ 	val_dir[4004*3 + 0] = -0.658281f;	val_dir[4004*3 + 1] = -0.708918f;	val_dir[4004*3 + 2] = 0.253185f;
+ 	val_dir[4005*3 + 0] = -0.645928f;	val_dir[4005*3 + 1] = -0.697602f;	val_dir[4005*3 + 2] = 0.310045f;
+ 	val_dir[4006*3 + 0] = -0.630706f;	val_dir[4006*3 + 1] = -0.683265f;	val_dir[4006*3 + 2] = 0.367912f;
+ 	val_dir[4007*3 + 0] = -0.612517f;	val_dir[4007*3 + 1] = -0.665780f;	val_dir[4007*3 + 2] = 0.426099f;
+ 	val_dir[4008*3 + 0] = -0.591364f;	val_dir[4008*3 + 1] = -0.645124f;	val_dir[4008*3 + 2] = 0.483843f;
+ 	val_dir[4009*3 + 0] = -0.567360f;	val_dir[4009*3 + 1] = -0.621395f;	val_dir[4009*3 + 2] = 0.540343f;
+ 	val_dir[4010*3 + 0] = -0.540738f;	val_dir[4010*3 + 1] = -0.594812f;	val_dir[4010*3 + 2] = 0.594812f;
+ 	val_dir[4011*3 + 0] = -0.511834f;	val_dir[4011*3 + 1] = -0.565711f;	val_dir[4011*3 + 2] = 0.646527f;
+ 	val_dir[4012*3 + 0] = -0.481070f;	val_dir[4012*3 + 1] = -0.534522f;	val_dir[4012*3 + 2] = 0.694879f;
+ 	val_dir[4013*3 + 0] = -0.448926f;	val_dir[4013*3 + 1] = -0.501740f;	val_dir[4013*3 + 2] = 0.739407f;
+ 	val_dir[4014*3 + 0] = -0.41590f;	val_dir[4014*3 + 1] = -0.467888f;	val_dir[4014*3 + 2] = 0.779813f;
+ 	val_dir[4015*3 + 0] = -0.382484f;	val_dir[4015*3 + 1] = -0.433482f;	val_dir[4015*3 + 2] = 0.815966f;
+ 	val_dir[4016*3 + 0] = -0.349128f;	val_dir[4016*3 + 1] = -0.399004f;	val_dir[4016*3 + 2] = 0.847883f;
+ 	val_dir[4017*3 + 0] = -0.316228f;	val_dir[4017*3 + 1] = -0.364878f;	val_dir[4017*3 + 2] = 0.875708f;
+ 	val_dir[4018*3 + 0] = -0.284108f;	val_dir[4018*3 + 1] = -0.331460f;	val_dir[4018*3 + 2] = 0.899676f;
+ 	val_dir[4019*3 + 0] = -0.253024f;	val_dir[4019*3 + 1] = -0.299028f;	val_dir[4019*3 + 2] = 0.920087f;
+ 	val_dir[4020*3 + 0] = -0.223161f;	val_dir[4020*3 + 1] = -0.267793f;	val_dir[4020*3 + 2] = 0.937276f;
+ 	val_dir[4021*3 + 0] = -0.194643f;	val_dir[4021*3 + 1] = -0.237897f;	val_dir[4021*3 + 2] = 0.951588f;
+ 	val_dir[4022*3 + 0] = -0.167542f;	val_dir[4022*3 + 1] = -0.209427f;	val_dir[4022*3 + 2] = 0.963364f;
+ 	val_dir[4023*3 + 0] = -0.141885f;	val_dir[4023*3 + 1] = -0.182424f;	val_dir[4023*3 + 2] = 0.972929f;
+ 	val_dir[4024*3 + 0] = -0.117670f;	val_dir[4024*3 + 1] = -0.156893f;	val_dir[4024*3 + 2] = 0.980581f;
+ 	val_dir[4025*3 + 0] = -0.094865f;	val_dir[4025*3 + 1] = -0.132810f;	val_dir[4025*3 + 2] = 0.986591f;
+ 	val_dir[4026*3 + 0] = -0.073422f;	val_dir[4026*3 + 1] = -0.110133f;	val_dir[4026*3 + 2] = 0.991201f;
+ 	val_dir[4027*3 + 0] = -0.053283f;	val_dir[4027*3 + 1] = -0.088806f;	val_dir[4027*3 + 2] = 0.994623f;
+ 	val_dir[4028*3 + 0] = -0.034381f;	val_dir[4028*3 + 1] = -0.068761f;	val_dir[4028*3 + 2] = 0.997041f;
+ 	val_dir[4029*3 + 0] = -0.016644f;	val_dir[4029*3 + 1] = -0.049931f;	val_dir[4029*3 + 2] = 0.998614f;
+ 	val_dir[4030*3 + 0] = 0.0f;	val_dir[4030*3 + 1] = -0.032241f;	val_dir[4030*3 + 2] = 0.999480f;
+ 	val_dir[4031*3 + 0] = 0.016125f;	val_dir[4031*3 + 1] = -0.016125f;	val_dir[4031*3 + 2] = 0.999740f;
+ 	val_dir[4032*3 + 0] = 0.032241f;	val_dir[4032*3 + 1] = 0.0f;	val_dir[4032*3 + 2] = 0.999480f;
+ 	val_dir[4033*3 + 0] = 0.049931f;	val_dir[4033*3 + 1] = 0.016644f;	val_dir[4033*3 + 2] = 0.998614f;
+ 	val_dir[4034*3 + 0] = 0.068761f;	val_dir[4034*3 + 1] = 0.034381f;	val_dir[4034*3 + 2] = 0.997041f;
+ 	val_dir[4035*3 + 0] = 0.088806f;	val_dir[4035*3 + 1] = 0.053283f;	val_dir[4035*3 + 2] = 0.994623f;
+ 	val_dir[4036*3 + 0] = 0.110133f;	val_dir[4036*3 + 1] = 0.073422f;	val_dir[4036*3 + 2] = 0.991201f;
+ 	val_dir[4037*3 + 0] = 0.132810f;	val_dir[4037*3 + 1] = 0.094865f;	val_dir[4037*3 + 2] = 0.986591f;
+ 	val_dir[4038*3 + 0] = 0.156893f;	val_dir[4038*3 + 1] = 0.117670f;	val_dir[4038*3 + 2] = 0.980581f;
+ 	val_dir[4039*3 + 0] = 0.182424f;	val_dir[4039*3 + 1] = 0.141885f;	val_dir[4039*3 + 2] = 0.972929f;
+ 	val_dir[4040*3 + 0] = 0.209427f;	val_dir[4040*3 + 1] = 0.167542f;	val_dir[4040*3 + 2] = 0.963364f;
+ 	val_dir[4041*3 + 0] = 0.237897f;	val_dir[4041*3 + 1] = 0.194643f;	val_dir[4041*3 + 2] = 0.951588f;
+ 	val_dir[4042*3 + 0] = 0.267793f;	val_dir[4042*3 + 1] = 0.223161f;	val_dir[4042*3 + 2] = 0.937276f;
+ 	val_dir[4043*3 + 0] = 0.299028f;	val_dir[4043*3 + 1] = 0.253024f;	val_dir[4043*3 + 2] = 0.920087f;
+ 	val_dir[4044*3 + 0] = 0.331460f;	val_dir[4044*3 + 1] = 0.284108f;	val_dir[4044*3 + 2] = 0.899676f;
+ 	val_dir[4045*3 + 0] = 0.364878f;	val_dir[4045*3 + 1] = 0.316228f;	val_dir[4045*3 + 2] = 0.875708f;
+ 	val_dir[4046*3 + 0] = 0.399004f;	val_dir[4046*3 + 1] = 0.349128f;	val_dir[4046*3 + 2] = 0.847883f;
+ 	val_dir[4047*3 + 0] = 0.433482f;	val_dir[4047*3 + 1] = 0.382484f;	val_dir[4047*3 + 2] = 0.815966f;
+ 	val_dir[4048*3 + 0] = 0.467888f;	val_dir[4048*3 + 1] = 0.41590f;	val_dir[4048*3 + 2] = 0.779813f;
+ 	val_dir[4049*3 + 0] = 0.501740f;	val_dir[4049*3 + 1] = 0.448926f;	val_dir[4049*3 + 2] = 0.739407f;
+ 	val_dir[4050*3 + 0] = 0.534522f;	val_dir[4050*3 + 1] = 0.481070f;	val_dir[4050*3 + 2] = 0.694879f;
+ 	val_dir[4051*3 + 0] = 0.565711f;	val_dir[4051*3 + 1] = 0.511834f;	val_dir[4051*3 + 2] = 0.646527f;
+ 	val_dir[4052*3 + 0] = 0.594812f;	val_dir[4052*3 + 1] = 0.540738f;	val_dir[4052*3 + 2] = 0.594812f;
+ 	val_dir[4053*3 + 0] = 0.621395f;	val_dir[4053*3 + 1] = 0.567360f;	val_dir[4053*3 + 2] = 0.540343f;
+ 	val_dir[4054*3 + 0] = 0.645124f;	val_dir[4054*3 + 1] = 0.591364f;	val_dir[4054*3 + 2] = 0.483843f;
+ 	val_dir[4055*3 + 0] = 0.665780f;	val_dir[4055*3 + 1] = 0.612517f;	val_dir[4055*3 + 2] = 0.426099f;
+ 	val_dir[4056*3 + 0] = 0.683265f;	val_dir[4056*3 + 1] = 0.630706f;	val_dir[4056*3 + 2] = 0.367912f;
+ 	val_dir[4057*3 + 0] = 0.697602f;	val_dir[4057*3 + 1] = 0.645928f;	val_dir[4057*3 + 2] = 0.310045f;
+ 	val_dir[4058*3 + 0] = 0.708918f;	val_dir[4058*3 + 1] = 0.658281f;	val_dir[4058*3 + 2] = 0.253185f;
+ 	val_dir[4059*3 + 0] = 0.717418f;	val_dir[4059*3 + 1] = 0.667940f;	val_dir[4059*3 + 2] = 0.197908f;
+ 	val_dir[4060*3 + 0] = 0.723364f;	val_dir[4060*3 + 1] = 0.675140f;	val_dir[4060*3 + 2] = 0.144673f;
+ 	val_dir[4061*3 + 0] = 0.727051f;	val_dir[4061*3 + 1] = 0.680144f;	val_dir[4061*3 + 2] = 0.093813f;
+ 	val_dir[4062*3 + 0] = 0.728780f;	val_dir[4062*3 + 1] = 0.683231f;	val_dir[4062*3 + 2] = 0.045549f;
+ 	val_dir[4063*3 + 0] = 0.728848f;	val_dir[4063*3 + 1] = 0.684675f;	val_dir[4063*3 + 2] = 0.0f;
+ 	val_dir[4064*3 + 0] = -0.695620f;	val_dir[4064*3 + 1] = -0.718059f;	val_dir[4064*3 + 2] = 0.022439f;
+ 	val_dir[4065*3 + 0] = -0.693746f;	val_dir[4065*3 + 1] = -0.716871f;	val_dir[4065*3 + 2] = 0.069375f;
+ 	val_dir[4066*3 + 0] = -0.690085f;	val_dir[4066*3 + 1] = -0.713881f;	val_dir[4066*3 + 2] = 0.118980f;
+ 	val_dir[4067*3 + 0] = -0.684353f;	val_dir[4067*3 + 1] = -0.708794f;	val_dir[4067*3 + 2] = 0.171088f;
+ 	val_dir[4068*3 + 0] = -0.676269f;	val_dir[4068*3 + 1] = -0.701316f;	val_dir[4068*3 + 2] = 0.225423f;
+ 	val_dir[4069*3 + 0] = -0.665574f;	val_dir[4069*3 + 1] = -0.691173f;	val_dir[4069*3 + 2] = 0.281589f;
+ 	val_dir[4070*3 + 0] = -0.652051f;	val_dir[4070*3 + 1] = -0.678133f;	val_dir[4070*3 + 2] = 0.339066f;
+ 	val_dir[4071*3 + 0] = -0.635553f;	val_dir[4071*3 + 1] = -0.662034f;	val_dir[4071*3 + 2] = 0.397220f;
+ 	val_dir[4072*3 + 0] = -0.616022f;	val_dir[4072*3 + 1] = -0.642806f;	val_dir[4072*3 + 2] = 0.455321f;
+ 	val_dir[4073*3 + 0] = -0.593512f;	val_dir[4073*3 + 1] = -0.620490f;	val_dir[4073*3 + 2] = 0.512578f;
+ 	val_dir[4074*3 + 0] = -0.568190f;	val_dir[4074*3 + 1] = -0.595247f;	val_dir[4074*3 + 2] = 0.568190f;
+ 	val_dir[4075*3 + 0] = -0.540343f;	val_dir[4075*3 + 1] = -0.567360f;	val_dir[4075*3 + 2] = 0.621395f;
+ 	val_dir[4076*3 + 0] = -0.510355f;	val_dir[4076*3 + 1] = -0.537215f;	val_dir[4076*3 + 2] = 0.671519f;
+ 	val_dir[4077*3 + 0] = -0.478683f;	val_dir[4077*3 + 1] = -0.505276f;	val_dir[4077*3 + 2] = 0.718024f;
+ 	val_dir[4078*3 + 0] = -0.445827f;	val_dir[4078*3 + 1] = -0.472053f;	val_dir[4078*3 + 2] = 0.760529f;
+ 	val_dir[4079*3 + 0] = -0.412294f;	val_dir[4079*3 + 1] = -0.438063f;	val_dir[4079*3 + 2] = 0.798820f;
+ 	val_dir[4080*3 + 0] = -0.378566f;	val_dir[4080*3 + 1] = -0.403804f;	val_dir[4080*3 + 2] = 0.832845f;
+ 	val_dir[4081*3 + 0] = -0.345075f;	val_dir[4081*3 + 1] = -0.369723f;	val_dir[4081*3 + 2] = 0.862687f;
+ 	val_dir[4082*3 + 0] = -0.312190f;	val_dir[4082*3 + 1] = -0.336204f;	val_dir[4082*3 + 2] = 0.888540f;
+ 	val_dir[4083*3 + 0] = -0.280209f;	val_dir[4083*3 + 1] = -0.303559f;	val_dir[4083*3 + 2] = 0.910678f;
+ 	val_dir[4084*3 + 0] = -0.249357f;	val_dir[4084*3 + 1] = -0.272026f;	val_dir[4084*3 + 2] = 0.929421f;
+ 	val_dir[4085*3 + 0] = -0.219793f;	val_dir[4085*3 + 1] = -0.241773f;	val_dir[4085*3 + 2] = 0.945112f;
+ 	val_dir[4086*3 + 0] = -0.191620f;	val_dir[4086*3 + 1] = -0.212911f;	val_dir[4086*3 + 2] = 0.958098f;
+ 	val_dir[4087*3 + 0] = -0.164887f;	val_dir[4087*3 + 1] = -0.185498f;	val_dir[4087*3 + 2] = 0.968712f;
+ 	val_dir[4088*3 + 0] = -0.139610f;	val_dir[4088*3 + 1] = -0.159554f;	val_dir[4088*3 + 2] = 0.977267f;
+ 	val_dir[4089*3 + 0] = -0.115771f;	val_dir[4089*3 + 1] = -0.135066f;	val_dir[4089*3 + 2] = 0.984050f;
+ 	val_dir[4090*3 + 0] = -0.093332f;	val_dir[4090*3 + 1] = -0.111998f;	val_dir[4090*3 + 2] = 0.989316f;
+ 	val_dir[4091*3 + 0] = -0.072239f;	val_dir[4091*3 + 1] = -0.090299f;	val_dir[4091*3 + 2] = 0.993291f;
+ 	val_dir[4092*3 + 0] = -0.052430f;	val_dir[4092*3 + 1] = -0.069907f;	val_dir[4092*3 + 2] = 0.996175f;
+ 	val_dir[4093*3 + 0] = -0.033835f;	val_dir[4093*3 + 1] = -0.050753f;	val_dir[4093*3 + 2] = 0.998138f;
+ 	val_dir[4094*3 + 0] = -0.016382f;	val_dir[4094*3 + 1] = -0.032765f;	val_dir[4094*3 + 2] = 0.999329f;
+ 	val_dir[4095*3 + 0] = 0.0f;	val_dir[4095*3 + 1] = -0.015871f;	val_dir[4095*3 + 2] = 0.999874f;
+ 	val_dir[4096*3 + 0] = 0.015871f;	val_dir[4096*3 + 1] = 0.0f;	val_dir[4096*3 + 2] = 0.999874f;
+ 	val_dir[4097*3 + 0] = 0.032765f;	val_dir[4097*3 + 1] = 0.016382f;	val_dir[4097*3 + 2] = 0.999329f;
+ 	val_dir[4098*3 + 0] = 0.050753f;	val_dir[4098*3 + 1] = 0.033835f;	val_dir[4098*3 + 2] = 0.998138f;
+ 	val_dir[4099*3 + 0] = 0.069907f;	val_dir[4099*3 + 1] = 0.052430f;	val_dir[4099*3 + 2] = 0.996175f;
+ 	val_dir[4100*3 + 0] = 0.090299f;	val_dir[4100*3 + 1] = 0.072239f;	val_dir[4100*3 + 2] = 0.993291f;
+ 	val_dir[4101*3 + 0] = 0.111998f;	val_dir[4101*3 + 1] = 0.093332f;	val_dir[4101*3 + 2] = 0.989316f;
+ 	val_dir[4102*3 + 0] = 0.135066f;	val_dir[4102*3 + 1] = 0.115771f;	val_dir[4102*3 + 2] = 0.984050f;
+ 	val_dir[4103*3 + 0] = 0.159554f;	val_dir[4103*3 + 1] = 0.139610f;	val_dir[4103*3 + 2] = 0.977267f;
+ 	val_dir[4104*3 + 0] = 0.185498f;	val_dir[4104*3 + 1] = 0.164887f;	val_dir[4104*3 + 2] = 0.968712f;
+ 	val_dir[4105*3 + 0] = 0.212911f;	val_dir[4105*3 + 1] = 0.191620f;	val_dir[4105*3 + 2] = 0.958098f;
+ 	val_dir[4106*3 + 0] = 0.241773f;	val_dir[4106*3 + 1] = 0.219793f;	val_dir[4106*3 + 2] = 0.945112f;
+ 	val_dir[4107*3 + 0] = 0.272026f;	val_dir[4107*3 + 1] = 0.249357f;	val_dir[4107*3 + 2] = 0.929421f;
+ 	val_dir[4108*3 + 0] = 0.303559f;	val_dir[4108*3 + 1] = 0.280209f;	val_dir[4108*3 + 2] = 0.910678f;
+ 	val_dir[4109*3 + 0] = 0.336204f;	val_dir[4109*3 + 1] = 0.312190f;	val_dir[4109*3 + 2] = 0.888540f;
+ 	val_dir[4110*3 + 0] = 0.369723f;	val_dir[4110*3 + 1] = 0.345075f;	val_dir[4110*3 + 2] = 0.862687f;
+ 	val_dir[4111*3 + 0] = 0.403804f;	val_dir[4111*3 + 1] = 0.378566f;	val_dir[4111*3 + 2] = 0.832845f;
+ 	val_dir[4112*3 + 0] = 0.438063f;	val_dir[4112*3 + 1] = 0.412294f;	val_dir[4112*3 + 2] = 0.798820f;
+ 	val_dir[4113*3 + 0] = 0.472053f;	val_dir[4113*3 + 1] = 0.445827f;	val_dir[4113*3 + 2] = 0.760529f;
+ 	val_dir[4114*3 + 0] = 0.505276f;	val_dir[4114*3 + 1] = 0.478683f;	val_dir[4114*3 + 2] = 0.718024f;
+ 	val_dir[4115*3 + 0] = 0.537215f;	val_dir[4115*3 + 1] = 0.510355f;	val_dir[4115*3 + 2] = 0.671519f;
+ 	val_dir[4116*3 + 0] = 0.567360f;	val_dir[4116*3 + 1] = 0.540343f;	val_dir[4116*3 + 2] = 0.621395f;
+ 	val_dir[4117*3 + 0] = 0.595247f;	val_dir[4117*3 + 1] = 0.568190f;	val_dir[4117*3 + 2] = 0.568190f;
+ 	val_dir[4118*3 + 0] = 0.620490f;	val_dir[4118*3 + 1] = 0.593512f;	val_dir[4118*3 + 2] = 0.512578f;
+ 	val_dir[4119*3 + 0] = 0.642806f;	val_dir[4119*3 + 1] = 0.616022f;	val_dir[4119*3 + 2] = 0.455321f;
+ 	val_dir[4120*3 + 0] = 0.662034f;	val_dir[4120*3 + 1] = 0.635553f;	val_dir[4120*3 + 2] = 0.397220f;
+ 	val_dir[4121*3 + 0] = 0.678133f;	val_dir[4121*3 + 1] = 0.652051f;	val_dir[4121*3 + 2] = 0.339066f;
+ 	val_dir[4122*3 + 0] = 0.691173f;	val_dir[4122*3 + 1] = 0.665574f;	val_dir[4122*3 + 2] = 0.281589f;
+ 	val_dir[4123*3 + 0] = 0.701316f;	val_dir[4123*3 + 1] = 0.676269f;	val_dir[4123*3 + 2] = 0.225423f;
+ 	val_dir[4124*3 + 0] = 0.708794f;	val_dir[4124*3 + 1] = 0.684353f;	val_dir[4124*3 + 2] = 0.171088f;
+ 	val_dir[4125*3 + 0] = 0.713881f;	val_dir[4125*3 + 1] = 0.690085f;	val_dir[4125*3 + 2] = 0.118980f;
+ 	val_dir[4126*3 + 0] = 0.716871f;	val_dir[4126*3 + 1] = 0.693746f;	val_dir[4126*3 + 2] = 0.069375f;
+ 	val_dir[4127*3 + 0] = 0.718059f;	val_dir[4127*3 + 1] = 0.695620f;	val_dir[4127*3 + 2] = 0.022439f;
+ 	val_dir[4128*3 + 0] = -0.707107f;	val_dir[4128*3 + 1] = -0.707107f;	val_dir[4128*3 + 2] = 0.0f;
+ 	val_dir[4129*3 + 0] = -0.706372f;	val_dir[4129*3 + 1] = -0.706372f;	val_dir[4129*3 + 2] = 0.045572f;
+ 	val_dir[4130*3 + 0] = -0.703985f;	val_dir[4130*3 + 1] = -0.703985f;	val_dir[4130*3 + 2] = 0.093865f;
+ 	val_dir[4131*3 + 0] = -0.699659f;	val_dir[4131*3 + 1] = -0.699659f;	val_dir[4131*3 + 2] = 0.144757f;
+ 	val_dir[4132*3 + 0] = -0.693103f;	val_dir[4132*3 + 1] = -0.693103f;	val_dir[4132*3 + 2] = 0.198030f;
+ 	val_dir[4133*3 + 0] = -0.684038f;	val_dir[4133*3 + 1] = -0.684038f;	val_dir[4133*3 + 2] = 0.253347f;
+ 	val_dir[4134*3 + 0] = -0.672214f;	val_dir[4134*3 + 1] = -0.672214f;	val_dir[4134*3 + 2] = 0.310253f;
+ 	val_dir[4135*3 + 0] = -0.657440f;	val_dir[4135*3 + 1] = -0.657440f;	val_dir[4135*3 + 2] = 0.368166f;
+ 	val_dir[4136*3 + 0] = -0.639602f;	val_dir[4136*3 + 1] = -0.639602f;	val_dir[4136*3 + 2] = 0.426401f;
+ 	val_dir[4137*3 + 0] = -0.618691f;	val_dir[4137*3 + 1] = -0.618691f;	val_dir[4137*3 + 2] = 0.484193f;
+ 	val_dir[4138*3 + 0] = -0.594812f;	val_dir[4138*3 + 1] = -0.594812f;	val_dir[4138*3 + 2] = 0.540738f;
+ 	val_dir[4139*3 + 0] = -0.568190f;	val_dir[4139*3 + 1] = -0.568190f;	val_dir[4139*3 + 2] = 0.595247f;
+ 	val_dir[4140*3 + 0] = -0.539164f;	val_dir[4140*3 + 1] = -0.539164f;	val_dir[4140*3 + 2] = 0.646997f;
+ 	val_dir[4141*3 + 0] = -0.508159f;	val_dir[4141*3 + 1] = -0.508159f;	val_dir[4141*3 + 2] = 0.695376f;
+ 	val_dir[4142*3 + 0] = -0.475665f;	val_dir[4142*3 + 1] = -0.475665f;	val_dir[4142*3 + 2] = 0.739923f;
+ 	val_dir[4143*3 + 0] = -0.442193f;	val_dir[4143*3 + 1] = -0.442193f;	val_dir[4143*3 + 2] = 0.780340f;
+ 	val_dir[4144*3 + 0] = -0.408248f;	val_dir[4144*3 + 1] = -0.408248f;	val_dir[4144*3 + 2] = 0.816497f;
+ 	val_dir[4145*3 + 0] = -0.374299f;	val_dir[4145*3 + 1] = -0.374299f;	val_dir[4145*3 + 2] = 0.848411f;
+ 	val_dir[4146*3 + 0] = -0.340755f;	val_dir[4146*3 + 1] = -0.340755f;	val_dir[4146*3 + 2] = 0.876226f;
+ 	val_dir[4147*3 + 0] = -0.307957f;	val_dir[4147*3 + 1] = -0.307957f;	val_dir[4147*3 + 2] = 0.900181f;
+ 	val_dir[4148*3 + 0] = -0.276172f;	val_dir[4148*3 + 1] = -0.276172f;	val_dir[4148*3 + 2] = 0.920575f;
+ 	val_dir[4149*3 + 0] = -0.245599f;	val_dir[4149*3 + 1] = -0.245599f;	val_dir[4149*3 + 2] = 0.937743f;
+ 	val_dir[4150*3 + 0] = -0.216371f;	val_dir[4150*3 + 1] = -0.216371f;	val_dir[4150*3 + 2] = 0.952033f;
+ 	val_dir[4151*3 + 0] = -0.188567f;	val_dir[4151*3 + 1] = -0.188567f;	val_dir[4151*3 + 2] = 0.963787f;
+ 	val_dir[4152*3 + 0] = -0.162221f;	val_dir[4152*3 + 1] = -0.162221f;	val_dir[4152*3 + 2] = 0.973329f;
+ 	val_dir[4153*3 + 0] = -0.137334f;	val_dir[4153*3 + 1] = -0.137334f;	val_dir[4153*3 + 2] = 0.980958f;
+ 	val_dir[4154*3 + 0] = -0.113878f;	val_dir[4154*3 + 1] = -0.113878f;	val_dir[4154*3 + 2] = 0.986947f;
+ 	val_dir[4155*3 + 0] = -0.091809f;	val_dir[4155*3 + 1] = -0.091809f;	val_dir[4155*3 + 2] = 0.991535f;
+ 	val_dir[4156*3 + 0] = -0.071067f;	val_dir[4156*3 + 1] = -0.071067f;	val_dir[4156*3 + 2] = 0.994937f;
+ 	val_dir[4157*3 + 0] = -0.051586f;	val_dir[4157*3 + 1] = -0.051586f;	val_dir[4157*3 + 2] = 0.997335f;
+ 	val_dir[4158*3 + 0] = -0.033296f;	val_dir[4158*3 + 1] = -0.033296f;	val_dir[4158*3 + 2] = 0.998891f;
+ 	val_dir[4159*3 + 0] = -0.016125f;	val_dir[4159*3 + 1] = -0.016125f;	val_dir[4159*3 + 2] = 0.999740f;
+ 	val_dir[4160*3 + 0] = 0.0f;	val_dir[4160*3 + 1] = 0.0f;	val_dir[4160*3 + 2] = 1.0f;
+ 	val_dir[4161*3 + 0] = 0.016125f;	val_dir[4161*3 + 1] = 0.016125f;	val_dir[4161*3 + 2] = 0.999740f;
+ 	val_dir[4162*3 + 0] = 0.033296f;	val_dir[4162*3 + 1] = 0.033296f;	val_dir[4162*3 + 2] = 0.998891f;
+ 	val_dir[4163*3 + 0] = 0.051586f;	val_dir[4163*3 + 1] = 0.051586f;	val_dir[4163*3 + 2] = 0.997335f;
+ 	val_dir[4164*3 + 0] = 0.071067f;	val_dir[4164*3 + 1] = 0.071067f;	val_dir[4164*3 + 2] = 0.994937f;
+ 	val_dir[4165*3 + 0] = 0.091809f;	val_dir[4165*3 + 1] = 0.091809f;	val_dir[4165*3 + 2] = 0.991535f;
+ 	val_dir[4166*3 + 0] = 0.113878f;	val_dir[4166*3 + 1] = 0.113878f;	val_dir[4166*3 + 2] = 0.986947f;
+ 	val_dir[4167*3 + 0] = 0.137334f;	val_dir[4167*3 + 1] = 0.137334f;	val_dir[4167*3 + 2] = 0.980958f;
+ 	val_dir[4168*3 + 0] = 0.162221f;	val_dir[4168*3 + 1] = 0.162221f;	val_dir[4168*3 + 2] = 0.973329f;
+ 	val_dir[4169*3 + 0] = 0.188567f;	val_dir[4169*3 + 1] = 0.188567f;	val_dir[4169*3 + 2] = 0.963787f;
+ 	val_dir[4170*3 + 0] = 0.216371f;	val_dir[4170*3 + 1] = 0.216371f;	val_dir[4170*3 + 2] = 0.952033f;
+ 	val_dir[4171*3 + 0] = 0.245599f;	val_dir[4171*3 + 1] = 0.245599f;	val_dir[4171*3 + 2] = 0.937743f;
+ 	val_dir[4172*3 + 0] = 0.276172f;	val_dir[4172*3 + 1] = 0.276172f;	val_dir[4172*3 + 2] = 0.920575f;
+ 	val_dir[4173*3 + 0] = 0.307957f;	val_dir[4173*3 + 1] = 0.307957f;	val_dir[4173*3 + 2] = 0.900181f;
+ 	val_dir[4174*3 + 0] = 0.340755f;	val_dir[4174*3 + 1] = 0.340755f;	val_dir[4174*3 + 2] = 0.876226f;
+ 	val_dir[4175*3 + 0] = 0.374299f;	val_dir[4175*3 + 1] = 0.374299f;	val_dir[4175*3 + 2] = 0.848411f;
+ 	val_dir[4176*3 + 0] = 0.408248f;	val_dir[4176*3 + 1] = 0.408248f;	val_dir[4176*3 + 2] = 0.816497f;
+ 	val_dir[4177*3 + 0] = 0.442193f;	val_dir[4177*3 + 1] = 0.442193f;	val_dir[4177*3 + 2] = 0.780340f;
+ 	val_dir[4178*3 + 0] = 0.475665f;	val_dir[4178*3 + 1] = 0.475665f;	val_dir[4178*3 + 2] = 0.739923f;
+ 	val_dir[4179*3 + 0] = 0.508159f;	val_dir[4179*3 + 1] = 0.508159f;	val_dir[4179*3 + 2] = 0.695376f;
+ 	val_dir[4180*3 + 0] = 0.539164f;	val_dir[4180*3 + 1] = 0.539164f;	val_dir[4180*3 + 2] = 0.646997f;
+ 	val_dir[4181*3 + 0] = 0.568190f;	val_dir[4181*3 + 1] = 0.568190f;	val_dir[4181*3 + 2] = 0.595247f;
+ 	val_dir[4182*3 + 0] = 0.594812f;	val_dir[4182*3 + 1] = 0.594812f;	val_dir[4182*3 + 2] = 0.540738f;
+ 	val_dir[4183*3 + 0] = 0.618691f;	val_dir[4183*3 + 1] = 0.618691f;	val_dir[4183*3 + 2] = 0.484193f;
+ 	val_dir[4184*3 + 0] = 0.639602f;	val_dir[4184*3 + 1] = 0.639602f;	val_dir[4184*3 + 2] = 0.426401f;
+ 	val_dir[4185*3 + 0] = 0.657440f;	val_dir[4185*3 + 1] = 0.657440f;	val_dir[4185*3 + 2] = 0.368166f;
+ 	val_dir[4186*3 + 0] = 0.672214f;	val_dir[4186*3 + 1] = 0.672214f;	val_dir[4186*3 + 2] = 0.310253f;
+ 	val_dir[4187*3 + 0] = 0.684038f;	val_dir[4187*3 + 1] = 0.684038f;	val_dir[4187*3 + 2] = 0.253347f;
+ 	val_dir[4188*3 + 0] = 0.693103f;	val_dir[4188*3 + 1] = 0.693103f;	val_dir[4188*3 + 2] = 0.198030f;
+ 	val_dir[4189*3 + 0] = 0.699659f;	val_dir[4189*3 + 1] = 0.699659f;	val_dir[4189*3 + 2] = 0.144757f;
+ 	val_dir[4190*3 + 0] = 0.703985f;	val_dir[4190*3 + 1] = 0.703985f;	val_dir[4190*3 + 2] = 0.093865f;
+ 	val_dir[4191*3 + 0] = 0.706372f;	val_dir[4191*3 + 1] = 0.706372f;	val_dir[4191*3 + 2] = 0.045572f;
+ 	val_dir[4192*3 + 0] = 0.707107f;	val_dir[4192*3 + 1] = 0.707107f;	val_dir[4192*3 + 2] = 0.0f;
+ 	val_dir[4193*3 + 0] = -0.718059f;	val_dir[4193*3 + 1] = -0.695620f;	val_dir[4193*3 + 2] = 0.022439f;
+ 	val_dir[4194*3 + 0] = -0.716871f;	val_dir[4194*3 + 1] = -0.693746f;	val_dir[4194*3 + 2] = 0.069375f;
+ 	val_dir[4195*3 + 0] = -0.713881f;	val_dir[4195*3 + 1] = -0.690085f;	val_dir[4195*3 + 2] = 0.118980f;
+ 	val_dir[4196*3 + 0] = -0.708794f;	val_dir[4196*3 + 1] = -0.684353f;	val_dir[4196*3 + 2] = 0.171088f;
+ 	val_dir[4197*3 + 0] = -0.701316f;	val_dir[4197*3 + 1] = -0.676269f;	val_dir[4197*3 + 2] = 0.225423f;
+ 	val_dir[4198*3 + 0] = -0.691173f;	val_dir[4198*3 + 1] = -0.665574f;	val_dir[4198*3 + 2] = 0.281589f;
+ 	val_dir[4199*3 + 0] = -0.678133f;	val_dir[4199*3 + 1] = -0.652051f;	val_dir[4199*3 + 2] = 0.339066f;
+ 	val_dir[4200*3 + 0] = -0.662034f;	val_dir[4200*3 + 1] = -0.635553f;	val_dir[4200*3 + 2] = 0.397220f;
+ 	val_dir[4201*3 + 0] = -0.642806f;	val_dir[4201*3 + 1] = -0.616022f;	val_dir[4201*3 + 2] = 0.455321f;
+ 	val_dir[4202*3 + 0] = -0.620490f;	val_dir[4202*3 + 1] = -0.593512f;	val_dir[4202*3 + 2] = 0.512578f;
+ 	val_dir[4203*3 + 0] = -0.595247f;	val_dir[4203*3 + 1] = -0.568190f;	val_dir[4203*3 + 2] = 0.568190f;
+ 	val_dir[4204*3 + 0] = -0.567360f;	val_dir[4204*3 + 1] = -0.540343f;	val_dir[4204*3 + 2] = 0.621395f;
+ 	val_dir[4205*3 + 0] = -0.537215f;	val_dir[4205*3 + 1] = -0.510355f;	val_dir[4205*3 + 2] = 0.671519f;
+ 	val_dir[4206*3 + 0] = -0.505276f;	val_dir[4206*3 + 1] = -0.478683f;	val_dir[4206*3 + 2] = 0.718024f;
+ 	val_dir[4207*3 + 0] = -0.472053f;	val_dir[4207*3 + 1] = -0.445827f;	val_dir[4207*3 + 2] = 0.760529f;
+ 	val_dir[4208*3 + 0] = -0.438063f;	val_dir[4208*3 + 1] = -0.412294f;	val_dir[4208*3 + 2] = 0.798820f;
+ 	val_dir[4209*3 + 0] = -0.403804f;	val_dir[4209*3 + 1] = -0.378566f;	val_dir[4209*3 + 2] = 0.832845f;
+ 	val_dir[4210*3 + 0] = -0.369723f;	val_dir[4210*3 + 1] = -0.345075f;	val_dir[4210*3 + 2] = 0.862687f;
+ 	val_dir[4211*3 + 0] = -0.336204f;	val_dir[4211*3 + 1] = -0.312190f;	val_dir[4211*3 + 2] = 0.888540f;
+ 	val_dir[4212*3 + 0] = -0.303559f;	val_dir[4212*3 + 1] = -0.280209f;	val_dir[4212*3 + 2] = 0.910678f;
+ 	val_dir[4213*3 + 0] = -0.272026f;	val_dir[4213*3 + 1] = -0.249357f;	val_dir[4213*3 + 2] = 0.929421f;
+ 	val_dir[4214*3 + 0] = -0.241773f;	val_dir[4214*3 + 1] = -0.219793f;	val_dir[4214*3 + 2] = 0.945112f;
+ 	val_dir[4215*3 + 0] = -0.212911f;	val_dir[4215*3 + 1] = -0.191620f;	val_dir[4215*3 + 2] = 0.958098f;
+ 	val_dir[4216*3 + 0] = -0.185498f;	val_dir[4216*3 + 1] = -0.164887f;	val_dir[4216*3 + 2] = 0.968712f;
+ 	val_dir[4217*3 + 0] = -0.159554f;	val_dir[4217*3 + 1] = -0.139610f;	val_dir[4217*3 + 2] = 0.977267f;
+ 	val_dir[4218*3 + 0] = -0.135066f;	val_dir[4218*3 + 1] = -0.115771f;	val_dir[4218*3 + 2] = 0.984050f;
+ 	val_dir[4219*3 + 0] = -0.111998f;	val_dir[4219*3 + 1] = -0.093332f;	val_dir[4219*3 + 2] = 0.989316f;
+ 	val_dir[4220*3 + 0] = -0.090299f;	val_dir[4220*3 + 1] = -0.072239f;	val_dir[4220*3 + 2] = 0.993291f;
+ 	val_dir[4221*3 + 0] = -0.069907f;	val_dir[4221*3 + 1] = -0.052430f;	val_dir[4221*3 + 2] = 0.996175f;
+ 	val_dir[4222*3 + 0] = -0.050753f;	val_dir[4222*3 + 1] = -0.033835f;	val_dir[4222*3 + 2] = 0.998138f;
+ 	val_dir[4223*3 + 0] = -0.032765f;	val_dir[4223*3 + 1] = -0.016382f;	val_dir[4223*3 + 2] = 0.999329f;
+ 	val_dir[4224*3 + 0] = -0.015871f;	val_dir[4224*3 + 1] = 0.0f;	val_dir[4224*3 + 2] = 0.999874f;
+ 	val_dir[4225*3 + 0] = 0.0f;	val_dir[4225*3 + 1] = 0.015871f;	val_dir[4225*3 + 2] = 0.999874f;
+ 	val_dir[4226*3 + 0] = 0.016382f;	val_dir[4226*3 + 1] = 0.032765f;	val_dir[4226*3 + 2] = 0.999329f;
+ 	val_dir[4227*3 + 0] = 0.033835f;	val_dir[4227*3 + 1] = 0.050753f;	val_dir[4227*3 + 2] = 0.998138f;
+ 	val_dir[4228*3 + 0] = 0.052430f;	val_dir[4228*3 + 1] = 0.069907f;	val_dir[4228*3 + 2] = 0.996175f;
+ 	val_dir[4229*3 + 0] = 0.072239f;	val_dir[4229*3 + 1] = 0.090299f;	val_dir[4229*3 + 2] = 0.993291f;
+ 	val_dir[4230*3 + 0] = 0.093332f;	val_dir[4230*3 + 1] = 0.111998f;	val_dir[4230*3 + 2] = 0.989316f;
+ 	val_dir[4231*3 + 0] = 0.115771f;	val_dir[4231*3 + 1] = 0.135066f;	val_dir[4231*3 + 2] = 0.984050f;
+ 	val_dir[4232*3 + 0] = 0.139610f;	val_dir[4232*3 + 1] = 0.159554f;	val_dir[4232*3 + 2] = 0.977267f;
+ 	val_dir[4233*3 + 0] = 0.164887f;	val_dir[4233*3 + 1] = 0.185498f;	val_dir[4233*3 + 2] = 0.968712f;
+ 	val_dir[4234*3 + 0] = 0.191620f;	val_dir[4234*3 + 1] = 0.212911f;	val_dir[4234*3 + 2] = 0.958098f;
+ 	val_dir[4235*3 + 0] = 0.219793f;	val_dir[4235*3 + 1] = 0.241773f;	val_dir[4235*3 + 2] = 0.945112f;
+ 	val_dir[4236*3 + 0] = 0.249357f;	val_dir[4236*3 + 1] = 0.272026f;	val_dir[4236*3 + 2] = 0.929421f;
+ 	val_dir[4237*3 + 0] = 0.280209f;	val_dir[4237*3 + 1] = 0.303559f;	val_dir[4237*3 + 2] = 0.910678f;
+ 	val_dir[4238*3 + 0] = 0.312190f;	val_dir[4238*3 + 1] = 0.336204f;	val_dir[4238*3 + 2] = 0.888540f;
+ 	val_dir[4239*3 + 0] = 0.345075f;	val_dir[4239*3 + 1] = 0.369723f;	val_dir[4239*3 + 2] = 0.862687f;
+ 	val_dir[4240*3 + 0] = 0.378566f;	val_dir[4240*3 + 1] = 0.403804f;	val_dir[4240*3 + 2] = 0.832845f;
+ 	val_dir[4241*3 + 0] = 0.412294f;	val_dir[4241*3 + 1] = 0.438063f;	val_dir[4241*3 + 2] = 0.798820f;
+ 	val_dir[4242*3 + 0] = 0.445827f;	val_dir[4242*3 + 1] = 0.472053f;	val_dir[4242*3 + 2] = 0.760529f;
+ 	val_dir[4243*3 + 0] = 0.478683f;	val_dir[4243*3 + 1] = 0.505276f;	val_dir[4243*3 + 2] = 0.718024f;
+ 	val_dir[4244*3 + 0] = 0.510355f;	val_dir[4244*3 + 1] = 0.537215f;	val_dir[4244*3 + 2] = 0.671519f;
+ 	val_dir[4245*3 + 0] = 0.540343f;	val_dir[4245*3 + 1] = 0.567360f;	val_dir[4245*3 + 2] = 0.621395f;
+ 	val_dir[4246*3 + 0] = 0.568190f;	val_dir[4246*3 + 1] = 0.595247f;	val_dir[4246*3 + 2] = 0.568190f;
+ 	val_dir[4247*3 + 0] = 0.593512f;	val_dir[4247*3 + 1] = 0.620490f;	val_dir[4247*3 + 2] = 0.512578f;
+ 	val_dir[4248*3 + 0] = 0.616022f;	val_dir[4248*3 + 1] = 0.642806f;	val_dir[4248*3 + 2] = 0.455321f;
+ 	val_dir[4249*3 + 0] = 0.635553f;	val_dir[4249*3 + 1] = 0.662034f;	val_dir[4249*3 + 2] = 0.397220f;
+ 	val_dir[4250*3 + 0] = 0.652051f;	val_dir[4250*3 + 1] = 0.678133f;	val_dir[4250*3 + 2] = 0.339066f;
+ 	val_dir[4251*3 + 0] = 0.665574f;	val_dir[4251*3 + 1] = 0.691173f;	val_dir[4251*3 + 2] = 0.281589f;
+ 	val_dir[4252*3 + 0] = 0.676269f;	val_dir[4252*3 + 1] = 0.701316f;	val_dir[4252*3 + 2] = 0.225423f;
+ 	val_dir[4253*3 + 0] = 0.684353f;	val_dir[4253*3 + 1] = 0.708794f;	val_dir[4253*3 + 2] = 0.171088f;
+ 	val_dir[4254*3 + 0] = 0.690085f;	val_dir[4254*3 + 1] = 0.713881f;	val_dir[4254*3 + 2] = 0.118980f;
+ 	val_dir[4255*3 + 0] = 0.693746f;	val_dir[4255*3 + 1] = 0.716871f;	val_dir[4255*3 + 2] = 0.069375f;
+ 	val_dir[4256*3 + 0] = 0.695620f;	val_dir[4256*3 + 1] = 0.718059f;	val_dir[4256*3 + 2] = 0.022439f;
+ 	val_dir[4257*3 + 0] = -0.728848f;	val_dir[4257*3 + 1] = -0.684675f;	val_dir[4257*3 + 2] = 0.0f;
+ 	val_dir[4258*3 + 0] = -0.728780f;	val_dir[4258*3 + 1] = -0.683231f;	val_dir[4258*3 + 2] = 0.045549f;
+ 	val_dir[4259*3 + 0] = -0.727051f;	val_dir[4259*3 + 1] = -0.680144f;	val_dir[4259*3 + 2] = 0.093813f;
+ 	val_dir[4260*3 + 0] = -0.723364f;	val_dir[4260*3 + 1] = -0.675140f;	val_dir[4260*3 + 2] = 0.144673f;
+ 	val_dir[4261*3 + 0] = -0.717418f;	val_dir[4261*3 + 1] = -0.667940f;	val_dir[4261*3 + 2] = 0.197908f;
+ 	val_dir[4262*3 + 0] = -0.708918f;	val_dir[4262*3 + 1] = -0.658281f;	val_dir[4262*3 + 2] = 0.253185f;
+ 	val_dir[4263*3 + 0] = -0.697602f;	val_dir[4263*3 + 1] = -0.645928f;	val_dir[4263*3 + 2] = 0.310045f;
+ 	val_dir[4264*3 + 0] = -0.683265f;	val_dir[4264*3 + 1] = -0.630706f;	val_dir[4264*3 + 2] = 0.367912f;
+ 	val_dir[4265*3 + 0] = -0.665780f;	val_dir[4265*3 + 1] = -0.612517f;	val_dir[4265*3 + 2] = 0.426099f;
+ 	val_dir[4266*3 + 0] = -0.645124f;	val_dir[4266*3 + 1] = -0.591364f;	val_dir[4266*3 + 2] = 0.483843f;
+ 	val_dir[4267*3 + 0] = -0.621395f;	val_dir[4267*3 + 1] = -0.567360f;	val_dir[4267*3 + 2] = 0.540343f;
+ 	val_dir[4268*3 + 0] = -0.594812f;	val_dir[4268*3 + 1] = -0.540738f;	val_dir[4268*3 + 2] = 0.594812f;
+ 	val_dir[4269*3 + 0] = -0.565711f;	val_dir[4269*3 + 1] = -0.511834f;	val_dir[4269*3 + 2] = 0.646527f;
+ 	val_dir[4270*3 + 0] = -0.534522f;	val_dir[4270*3 + 1] = -0.481070f;	val_dir[4270*3 + 2] = 0.694879f;
+ 	val_dir[4271*3 + 0] = -0.501740f;	val_dir[4271*3 + 1] = -0.448926f;	val_dir[4271*3 + 2] = 0.739407f;
+ 	val_dir[4272*3 + 0] = -0.467888f;	val_dir[4272*3 + 1] = -0.41590f;	val_dir[4272*3 + 2] = 0.779813f;
+ 	val_dir[4273*3 + 0] = -0.433482f;	val_dir[4273*3 + 1] = -0.382484f;	val_dir[4273*3 + 2] = 0.815966f;
+ 	val_dir[4274*3 + 0] = -0.399004f;	val_dir[4274*3 + 1] = -0.349128f;	val_dir[4274*3 + 2] = 0.847883f;
+ 	val_dir[4275*3 + 0] = -0.364878f;	val_dir[4275*3 + 1] = -0.316228f;	val_dir[4275*3 + 2] = 0.875708f;
+ 	val_dir[4276*3 + 0] = -0.331460f;	val_dir[4276*3 + 1] = -0.284108f;	val_dir[4276*3 + 2] = 0.899676f;
+ 	val_dir[4277*3 + 0] = -0.299028f;	val_dir[4277*3 + 1] = -0.253024f;	val_dir[4277*3 + 2] = 0.920087f;
+ 	val_dir[4278*3 + 0] = -0.267793f;	val_dir[4278*3 + 1] = -0.223161f;	val_dir[4278*3 + 2] = 0.937276f;
+ 	val_dir[4279*3 + 0] = -0.237897f;	val_dir[4279*3 + 1] = -0.194643f;	val_dir[4279*3 + 2] = 0.951588f;
+ 	val_dir[4280*3 + 0] = -0.209427f;	val_dir[4280*3 + 1] = -0.167542f;	val_dir[4280*3 + 2] = 0.963364f;
+ 	val_dir[4281*3 + 0] = -0.182424f;	val_dir[4281*3 + 1] = -0.141885f;	val_dir[4281*3 + 2] = 0.972929f;
+ 	val_dir[4282*3 + 0] = -0.156893f;	val_dir[4282*3 + 1] = -0.117670f;	val_dir[4282*3 + 2] = 0.980581f;
+ 	val_dir[4283*3 + 0] = -0.132810f;	val_dir[4283*3 + 1] = -0.094865f;	val_dir[4283*3 + 2] = 0.986591f;
+ 	val_dir[4284*3 + 0] = -0.110133f;	val_dir[4284*3 + 1] = -0.073422f;	val_dir[4284*3 + 2] = 0.991201f;
+ 	val_dir[4285*3 + 0] = -0.088806f;	val_dir[4285*3 + 1] = -0.053283f;	val_dir[4285*3 + 2] = 0.994623f;
+ 	val_dir[4286*3 + 0] = -0.068761f;	val_dir[4286*3 + 1] = -0.034381f;	val_dir[4286*3 + 2] = 0.997041f;
+ 	val_dir[4287*3 + 0] = -0.049931f;	val_dir[4287*3 + 1] = -0.016644f;	val_dir[4287*3 + 2] = 0.998614f;
+ 	val_dir[4288*3 + 0] = -0.032241f;	val_dir[4288*3 + 1] = 0.0f;	val_dir[4288*3 + 2] = 0.999480f;
+ 	val_dir[4289*3 + 0] = -0.016125f;	val_dir[4289*3 + 1] = 0.016125f;	val_dir[4289*3 + 2] = 0.999740f;
+ 	val_dir[4290*3 + 0] = 0.0f;	val_dir[4290*3 + 1] = 0.032241f;	val_dir[4290*3 + 2] = 0.999480f;
+ 	val_dir[4291*3 + 0] = 0.016644f;	val_dir[4291*3 + 1] = 0.049931f;	val_dir[4291*3 + 2] = 0.998614f;
+ 	val_dir[4292*3 + 0] = 0.034381f;	val_dir[4292*3 + 1] = 0.068761f;	val_dir[4292*3 + 2] = 0.997041f;
+ 	val_dir[4293*3 + 0] = 0.053283f;	val_dir[4293*3 + 1] = 0.088806f;	val_dir[4293*3 + 2] = 0.994623f;
+ 	val_dir[4294*3 + 0] = 0.073422f;	val_dir[4294*3 + 1] = 0.110133f;	val_dir[4294*3 + 2] = 0.991201f;
+ 	val_dir[4295*3 + 0] = 0.094865f;	val_dir[4295*3 + 1] = 0.132810f;	val_dir[4295*3 + 2] = 0.986591f;
+ 	val_dir[4296*3 + 0] = 0.117670f;	val_dir[4296*3 + 1] = 0.156893f;	val_dir[4296*3 + 2] = 0.980581f;
+ 	val_dir[4297*3 + 0] = 0.141885f;	val_dir[4297*3 + 1] = 0.182424f;	val_dir[4297*3 + 2] = 0.972929f;
+ 	val_dir[4298*3 + 0] = 0.167542f;	val_dir[4298*3 + 1] = 0.209427f;	val_dir[4298*3 + 2] = 0.963364f;
+ 	val_dir[4299*3 + 0] = 0.194643f;	val_dir[4299*3 + 1] = 0.237897f;	val_dir[4299*3 + 2] = 0.951588f;
+ 	val_dir[4300*3 + 0] = 0.223161f;	val_dir[4300*3 + 1] = 0.267793f;	val_dir[4300*3 + 2] = 0.937276f;
+ 	val_dir[4301*3 + 0] = 0.253024f;	val_dir[4301*3 + 1] = 0.299028f;	val_dir[4301*3 + 2] = 0.920087f;
+ 	val_dir[4302*3 + 0] = 0.284108f;	val_dir[4302*3 + 1] = 0.331460f;	val_dir[4302*3 + 2] = 0.899676f;
+ 	val_dir[4303*3 + 0] = 0.316228f;	val_dir[4303*3 + 1] = 0.364878f;	val_dir[4303*3 + 2] = 0.875708f;
+ 	val_dir[4304*3 + 0] = 0.349128f;	val_dir[4304*3 + 1] = 0.399004f;	val_dir[4304*3 + 2] = 0.847883f;
+ 	val_dir[4305*3 + 0] = 0.382484f;	val_dir[4305*3 + 1] = 0.433482f;	val_dir[4305*3 + 2] = 0.815966f;
+ 	val_dir[4306*3 + 0] = 0.41590f;	val_dir[4306*3 + 1] = 0.467888f;	val_dir[4306*3 + 2] = 0.779813f;
+ 	val_dir[4307*3 + 0] = 0.448926f;	val_dir[4307*3 + 1] = 0.501740f;	val_dir[4307*3 + 2] = 0.739407f;
+ 	val_dir[4308*3 + 0] = 0.481070f;	val_dir[4308*3 + 1] = 0.534522f;	val_dir[4308*3 + 2] = 0.694879f;
+ 	val_dir[4309*3 + 0] = 0.511834f;	val_dir[4309*3 + 1] = 0.565711f;	val_dir[4309*3 + 2] = 0.646527f;
+ 	val_dir[4310*3 + 0] = 0.540738f;	val_dir[4310*3 + 1] = 0.594812f;	val_dir[4310*3 + 2] = 0.594812f;
+ 	val_dir[4311*3 + 0] = 0.567360f;	val_dir[4311*3 + 1] = 0.621395f;	val_dir[4311*3 + 2] = 0.540343f;
+ 	val_dir[4312*3 + 0] = 0.591364f;	val_dir[4312*3 + 1] = 0.645124f;	val_dir[4312*3 + 2] = 0.483843f;
+ 	val_dir[4313*3 + 0] = 0.612517f;	val_dir[4313*3 + 1] = 0.665780f;	val_dir[4313*3 + 2] = 0.426099f;
+ 	val_dir[4314*3 + 0] = 0.630706f;	val_dir[4314*3 + 1] = 0.683265f;	val_dir[4314*3 + 2] = 0.367912f;
+ 	val_dir[4315*3 + 0] = 0.645928f;	val_dir[4315*3 + 1] = 0.697602f;	val_dir[4315*3 + 2] = 0.310045f;
+ 	val_dir[4316*3 + 0] = 0.658281f;	val_dir[4316*3 + 1] = 0.708918f;	val_dir[4316*3 + 2] = 0.253185f;
+ 	val_dir[4317*3 + 0] = 0.667940f;	val_dir[4317*3 + 1] = 0.717418f;	val_dir[4317*3 + 2] = 0.197908f;
+ 	val_dir[4318*3 + 0] = 0.675140f;	val_dir[4318*3 + 1] = 0.723364f;	val_dir[4318*3 + 2] = 0.144673f;
+ 	val_dir[4319*3 + 0] = 0.680144f;	val_dir[4319*3 + 1] = 0.727051f;	val_dir[4319*3 + 2] = 0.093813f;
+ 	val_dir[4320*3 + 0] = 0.683231f;	val_dir[4320*3 + 1] = 0.728780f;	val_dir[4320*3 + 2] = 0.045549f;
+ 	val_dir[4321*3 + 0] = 0.684675f;	val_dir[4321*3 + 1] = 0.728848f;	val_dir[4321*3 + 2] = 0.0f;
+ 	val_dir[4322*3 + 0] = -0.739754f;	val_dir[4322*3 + 1] = -0.672504f;	val_dir[4322*3 + 2] = 0.022417f;
+ 	val_dir[4323*3 + 0] = -0.739205f;	val_dir[4323*3 + 1] = -0.669905f;	val_dir[4323*3 + 2] = 0.069301f;
+ 	val_dir[4324*3 + 0] = -0.736843f;	val_dir[4324*3 + 1] = -0.665536f;	val_dir[4324*3 + 2] = 0.118846f;
+ 	val_dir[4325*3 + 0] = -0.732361f;	val_dir[4325*3 + 1] = -0.659125f;	val_dir[4325*3 + 2] = 0.170884f;
+ 	val_dir[4326*3 + 0] = -0.725454f;	val_dir[4326*3 + 1] = -0.650407f;	val_dir[4326*3 + 2] = 0.225141f;
+ 	val_dir[4327*3 + 0] = -0.715834f;	val_dir[4327*3 + 1] = -0.639138f;	val_dir[4327*3 + 2] = 0.281220f;
+ 	val_dir[4328*3 + 0] = -0.703259f;	val_dir[4328*3 + 1] = -0.625119f;	val_dir[4328*3 + 2] = 0.338606f;
+ 	val_dir[4329*3 + 0] = -0.687552f;	val_dir[4329*3 + 1] = -0.608219f;	val_dir[4329*3 + 2] = 0.396664f;
+ 	val_dir[4330*3 + 0] = -0.668631f;	val_dir[4330*3 + 1] = -0.588395f;	val_dir[4330*3 + 2] = 0.454669f;
+ 	val_dir[4331*3 + 0] = -0.646527f;	val_dir[4331*3 + 1] = -0.565711f;	val_dir[4331*3 + 2] = 0.511834f;
+ 	val_dir[4332*3 + 0] = -0.621395f;	val_dir[4332*3 + 1] = -0.540343f;	val_dir[4332*3 + 2] = 0.567360f;
+ 	val_dir[4333*3 + 0] = -0.593512f;	val_dir[4333*3 + 1] = -0.512578f;	val_dir[4333*3 + 2] = 0.620490f;
+ 	val_dir[4334*3 + 0] = -0.563264f;	val_dir[4334*3 + 1] = -0.482798f;	val_dir[4334*3 + 2] = 0.670552f;
+ 	val_dir[4335*3 + 0] = -0.531119f;	val_dir[4335*3 + 1] = -0.451451f;	val_dir[4335*3 + 2] = 0.717011f;
+ 	val_dir[4336*3 + 0] = -0.497594f;	val_dir[4336*3 + 1] = -0.419026f;	val_dir[4336*3 + 2] = 0.759485f;
+ 	val_dir[4337*3 + 0] = -0.463217f;	val_dir[4337*3 + 1] = -0.386014f;	val_dir[4337*3 + 2] = 0.797762f;
+ 	val_dir[4338*3 + 0] = -0.428496f;	val_dir[4338*3 + 1] = -0.352879f;	val_dir[4338*3 + 2] = 0.831786f;
+ 	val_dir[4339*3 + 0] = -0.393893f;	val_dir[4339*3 + 1] = -0.320038f;	val_dir[4339*3 + 2] = 0.861640f;
+ 	val_dir[4340*3 + 0] = -0.359804f;	val_dir[4340*3 + 1] = -0.287843f;	val_dir[4340*3 + 2] = 0.887517f;
+ 	val_dir[4341*3 + 0] = -0.326554f;	val_dir[4341*3 + 1] = -0.256578f;	val_dir[4341*3 + 2] = 0.909687f;
+ 	val_dir[4342*3 + 0] = -0.294392f;	val_dir[4342*3 + 1] = -0.226455f;	val_dir[4342*3 + 2] = 0.928467f;
+ 	val_dir[4343*3 + 0] = -0.263498f;	val_dir[4343*3 + 1] = -0.197623f;	val_dir[4343*3 + 2] = 0.94420f;
+ 	val_dir[4344*3 + 0] = -0.233990f;	val_dir[4344*3 + 1] = -0.170174f;	val_dir[4344*3 + 2] = 0.957230f;
+ 	val_dir[4345*3 + 0] = -0.205934f;	val_dir[4345*3 + 1] = -0.144154f;	val_dir[4345*3 + 2] = 0.967890f;
+ 	val_dir[4346*3 + 0] = -0.179355f;	val_dir[4346*3 + 1] = -0.119570f;	val_dir[4346*3 + 2] = 0.976491f;
+ 	val_dir[4347*3 + 0] = -0.154246f;	val_dir[4347*3 + 1] = -0.096404f;	val_dir[4347*3 + 2] = 0.983318f;
+ 	val_dir[4348*3 + 0] = -0.130573f;	val_dir[4348*3 + 1] = -0.074613f;	val_dir[4348*3 + 2] = 0.988627f;
+ 	val_dir[4349*3 + 0] = -0.108288f;	val_dir[4349*3 + 1] = -0.054144f;	val_dir[4349*3 + 2] = 0.992644f;
+ 	val_dir[4350*3 + 0] = -0.087330f;	val_dir[4350*3 + 1] = -0.034932f;	val_dir[4350*3 + 2] = 0.995567f;
+ 	val_dir[4351*3 + 0] = -0.067632f;	val_dir[4351*3 + 1] = -0.016908f;	val_dir[4351*3 + 2] = 0.997567f;
+ 	val_dir[4352*3 + 0] = -0.049121f;	val_dir[4352*3 + 1] = 0.0f;	val_dir[4352*3 + 2] = 0.998793f;
+ 	val_dir[4353*3 + 0] = -0.032765f;	val_dir[4353*3 + 1] = 0.016382f;	val_dir[4353*3 + 2] = 0.999329f;
+ 	val_dir[4354*3 + 0] = -0.016382f;	val_dir[4354*3 + 1] = 0.032765f;	val_dir[4354*3 + 2] = 0.999329f;
+ 	val_dir[4355*3 + 0] = 0.0f;	val_dir[4355*3 + 1] = 0.049121f;	val_dir[4355*3 + 2] = 0.998793f;
+ 	val_dir[4356*3 + 0] = 0.016908f;	val_dir[4356*3 + 1] = 0.067632f;	val_dir[4356*3 + 2] = 0.997567f;
+ 	val_dir[4357*3 + 0] = 0.034932f;	val_dir[4357*3 + 1] = 0.087330f;	val_dir[4357*3 + 2] = 0.995567f;
+ 	val_dir[4358*3 + 0] = 0.054144f;	val_dir[4358*3 + 1] = 0.108288f;	val_dir[4358*3 + 2] = 0.992644f;
+ 	val_dir[4359*3 + 0] = 0.074613f;	val_dir[4359*3 + 1] = 0.130573f;	val_dir[4359*3 + 2] = 0.988627f;
+ 	val_dir[4360*3 + 0] = 0.096404f;	val_dir[4360*3 + 1] = 0.154246f;	val_dir[4360*3 + 2] = 0.983318f;
+ 	val_dir[4361*3 + 0] = 0.119570f;	val_dir[4361*3 + 1] = 0.179355f;	val_dir[4361*3 + 2] = 0.976491f;
+ 	val_dir[4362*3 + 0] = 0.144154f;	val_dir[4362*3 + 1] = 0.205934f;	val_dir[4362*3 + 2] = 0.967890f;
+ 	val_dir[4363*3 + 0] = 0.170174f;	val_dir[4363*3 + 1] = 0.233990f;	val_dir[4363*3 + 2] = 0.957230f;
+ 	val_dir[4364*3 + 0] = 0.197623f;	val_dir[4364*3 + 1] = 0.263498f;	val_dir[4364*3 + 2] = 0.94420f;
+ 	val_dir[4365*3 + 0] = 0.226455f;	val_dir[4365*3 + 1] = 0.294392f;	val_dir[4365*3 + 2] = 0.928467f;
+ 	val_dir[4366*3 + 0] = 0.256578f;	val_dir[4366*3 + 1] = 0.326554f;	val_dir[4366*3 + 2] = 0.909687f;
+ 	val_dir[4367*3 + 0] = 0.287843f;	val_dir[4367*3 + 1] = 0.359804f;	val_dir[4367*3 + 2] = 0.887517f;
+ 	val_dir[4368*3 + 0] = 0.320038f;	val_dir[4368*3 + 1] = 0.393893f;	val_dir[4368*3 + 2] = 0.861640f;
+ 	val_dir[4369*3 + 0] = 0.352879f;	val_dir[4369*3 + 1] = 0.428496f;	val_dir[4369*3 + 2] = 0.831786f;
+ 	val_dir[4370*3 + 0] = 0.386014f;	val_dir[4370*3 + 1] = 0.463217f;	val_dir[4370*3 + 2] = 0.797762f;
+ 	val_dir[4371*3 + 0] = 0.419026f;	val_dir[4371*3 + 1] = 0.497594f;	val_dir[4371*3 + 2] = 0.759485f;
+ 	val_dir[4372*3 + 0] = 0.451451f;	val_dir[4372*3 + 1] = 0.531119f;	val_dir[4372*3 + 2] = 0.717011f;
+ 	val_dir[4373*3 + 0] = 0.482798f;	val_dir[4373*3 + 1] = 0.563264f;	val_dir[4373*3 + 2] = 0.670552f;
+ 	val_dir[4374*3 + 0] = 0.512578f;	val_dir[4374*3 + 1] = 0.593512f;	val_dir[4374*3 + 2] = 0.620490f;
+ 	val_dir[4375*3 + 0] = 0.540343f;	val_dir[4375*3 + 1] = 0.621395f;	val_dir[4375*3 + 2] = 0.567360f;
+ 	val_dir[4376*3 + 0] = 0.565711f;	val_dir[4376*3 + 1] = 0.646527f;	val_dir[4376*3 + 2] = 0.511834f;
+ 	val_dir[4377*3 + 0] = 0.588395f;	val_dir[4377*3 + 1] = 0.668631f;	val_dir[4377*3 + 2] = 0.454669f;
+ 	val_dir[4378*3 + 0] = 0.608219f;	val_dir[4378*3 + 1] = 0.687552f;	val_dir[4378*3 + 2] = 0.396664f;
+ 	val_dir[4379*3 + 0] = 0.625119f;	val_dir[4379*3 + 1] = 0.703259f;	val_dir[4379*3 + 2] = 0.338606f;
+ 	val_dir[4380*3 + 0] = 0.639138f;	val_dir[4380*3 + 1] = 0.715834f;	val_dir[4380*3 + 2] = 0.281220f;
+ 	val_dir[4381*3 + 0] = 0.650407f;	val_dir[4381*3 + 1] = 0.725454f;	val_dir[4381*3 + 2] = 0.225141f;
+ 	val_dir[4382*3 + 0] = 0.659125f;	val_dir[4382*3 + 1] = 0.732361f;	val_dir[4382*3 + 2] = 0.170884f;
+ 	val_dir[4383*3 + 0] = 0.665536f;	val_dir[4383*3 + 1] = 0.736843f;	val_dir[4383*3 + 2] = 0.118846f;
+ 	val_dir[4384*3 + 0] = 0.669905f;	val_dir[4384*3 + 1] = 0.739205f;	val_dir[4384*3 + 2] = 0.069301f;
+ 	val_dir[4385*3 + 0] = 0.672504f;	val_dir[4385*3 + 1] = 0.739754f;	val_dir[4385*3 + 2] = 0.022417f;
+ 	val_dir[4386*3 + 0] = -0.749838f;	val_dir[4386*3 + 1] = -0.661622f;	val_dir[4386*3 + 2] = 0.0f;
+ 	val_dir[4387*3 + 0] = -0.750388f;	val_dir[4387*3 + 1] = -0.659432f;	val_dir[4387*3 + 2] = 0.045478f;
+ 	val_dir[4388*3 + 0] = -0.749269f;	val_dir[4388*3 + 1] = -0.655610f;	val_dir[4388*3 + 2] = 0.093659f;
+ 	val_dir[4389*3 + 0] = -0.746176f;	val_dir[4389*3 + 1] = -0.649895f;	val_dir[4389*3 + 2] = 0.144421f;
+ 	val_dir[4390*3 + 0] = -0.740797f;	val_dir[4390*3 + 1] = -0.642024f;	val_dir[4390*3 + 2] = 0.197546f;
+ 	val_dir[4391*3 + 0] = -0.732828f;	val_dir[4391*3 + 1] = -0.631748f;	val_dir[4391*3 + 2] = 0.252699f;
+ 	val_dir[4392*3 + 0] = -0.721995f;	val_dir[4392*3 + 1] = -0.618853f;	val_dir[4392*3 + 2] = 0.309426f;
+ 	val_dir[4393*3 + 0] = -0.708079f;	val_dir[4393*3 + 1] = -0.603178f;	val_dir[4393*3 + 2] = 0.367152f;
+ 	val_dir[4394*3 + 0] = -0.690942f;	val_dir[4394*3 + 1] = -0.584643f;	val_dir[4394*3 + 2] = 0.425195f;
+ 	val_dir[4395*3 + 0] = -0.670552f;	val_dir[4395*3 + 1] = -0.563264f;	val_dir[4395*3 + 2] = 0.482798f;
+ 	val_dir[4396*3 + 0] = -0.646997f;	val_dir[4396*3 + 1] = -0.539164f;	val_dir[4396*3 + 2] = 0.539164f;
+ 	val_dir[4397*3 + 0] = -0.620490f;	val_dir[4397*3 + 1] = -0.512578f;	val_dir[4397*3 + 2] = 0.593512f;
+ 	val_dir[4398*3 + 0] = -0.591364f;	val_dir[4398*3 + 1] = -0.483843f;	val_dir[4398*3 + 2] = 0.645124f;
+ 	val_dir[4399*3 + 0] = -0.560050f;	val_dir[4399*3 + 1] = -0.453374f;	val_dir[4399*3 + 2] = 0.693395f;
+ 	val_dir[4400*3 + 0] = -0.527046f;	val_dir[4400*3 + 1] = -0.421637f;	val_dir[4400*3 + 2] = 0.737865f;
+ 	val_dir[4401*3 + 0] = -0.492883f;	val_dir[4401*3 + 1] = -0.389118f;	val_dir[4401*3 + 2] = 0.778237f;
+ 	val_dir[4402*3 + 0] = -0.458088f;	val_dir[4402*3 + 1] = -0.356291f;	val_dir[4402*3 + 2] = 0.814379f;
+ 	val_dir[4403*3 + 0] = -0.423153f;	val_dir[4403*3 + 1] = -0.323587f;	val_dir[4403*3 + 2] = 0.846305f;
+ 	val_dir[4404*3 + 0] = -0.388514f;	val_dir[4404*3 + 1] = -0.291386f;	val_dir[4404*3 + 2] = 0.874157f;
+ 	val_dir[4405*3 + 0] = -0.354540f;	val_dir[4405*3 + 1] = -0.259996f;	val_dir[4405*3 + 2] = 0.898167f;
+ 	val_dir[4406*3 + 0] = -0.321521f;	val_dir[4406*3 + 1] = -0.229658f;	val_dir[4406*3 + 2] = 0.918630f;
+ 	val_dir[4407*3 + 0] = -0.289677f;	val_dir[4407*3 + 1] = -0.200545f;	val_dir[4407*3 + 2] = 0.935879f;
+ 	val_dir[4408*3 + 0] = -0.259161f;	val_dir[4408*3 + 1] = -0.172774f;	val_dir[4408*3 + 2] = 0.950255f;
+ 	val_dir[4409*3 + 0] = -0.230067f;	val_dir[4409*3 + 1] = -0.146406f;	val_dir[4409*3 + 2] = 0.962099f;
+ 	val_dir[4410*3 + 0] = -0.202444f;	val_dir[4410*3 + 1] = -0.121466f;	val_dir[4410*3 + 2] = 0.971732f;
+ 	val_dir[4411*3 + 0] = -0.176301f;	val_dir[4411*3 + 1] = -0.097945f;	val_dir[4411*3 + 2] = 0.979451f;
+ 	val_dir[4412*3 + 0] = -0.151620f;	val_dir[4412*3 + 1] = -0.075810f;	val_dir[4412*3 + 2] = 0.985527f;
+ 	val_dir[4413*3 + 0] = -0.128359f;	val_dir[4413*3 + 1] = -0.055011f;	val_dir[4413*3 + 2] = 0.990201f;
+ 	val_dir[4414*3 + 0] = -0.106466f;	val_dir[4414*3 + 1] = -0.035489f;	val_dir[4414*3 + 2] = 0.993683f;
+ 	val_dir[4415*3 + 0] = -0.085876f;	val_dir[4415*3 + 1] = -0.017175f;	val_dir[4415*3 + 2] = 0.996158f;
+ 	val_dir[4416*3 + 0] = -0.066519f;	val_dir[4416*3 + 1] = 0.0f;	val_dir[4416*3 + 2] = 0.997785f;
+ 	val_dir[4417*3 + 0] = -0.049931f;	val_dir[4417*3 + 1] = 0.016644f;	val_dir[4417*3 + 2] = 0.998614f;
+ 	val_dir[4418*3 + 0] = -0.033296f;	val_dir[4418*3 + 1] = 0.033296f;	val_dir[4418*3 + 2] = 0.998891f;
+ 	val_dir[4419*3 + 0] = -0.016644f;	val_dir[4419*3 + 1] = 0.049931f;	val_dir[4419*3 + 2] = 0.998614f;
+ 	val_dir[4420*3 + 0] = 0.0f;	val_dir[4420*3 + 1] = 0.066519f;	val_dir[4420*3 + 2] = 0.997785f;
+ 	val_dir[4421*3 + 0] = 0.017175f;	val_dir[4421*3 + 1] = 0.085876f;	val_dir[4421*3 + 2] = 0.996158f;
+ 	val_dir[4422*3 + 0] = 0.035489f;	val_dir[4422*3 + 1] = 0.106466f;	val_dir[4422*3 + 2] = 0.993683f;
+ 	val_dir[4423*3 + 0] = 0.055011f;	val_dir[4423*3 + 1] = 0.128359f;	val_dir[4423*3 + 2] = 0.990201f;
+ 	val_dir[4424*3 + 0] = 0.075810f;	val_dir[4424*3 + 1] = 0.151620f;	val_dir[4424*3 + 2] = 0.985527f;
+ 	val_dir[4425*3 + 0] = 0.097945f;	val_dir[4425*3 + 1] = 0.176301f;	val_dir[4425*3 + 2] = 0.979451f;
+ 	val_dir[4426*3 + 0] = 0.121466f;	val_dir[4426*3 + 1] = 0.202444f;	val_dir[4426*3 + 2] = 0.971732f;
+ 	val_dir[4427*3 + 0] = 0.146406f;	val_dir[4427*3 + 1] = 0.230067f;	val_dir[4427*3 + 2] = 0.962099f;
+ 	val_dir[4428*3 + 0] = 0.172774f;	val_dir[4428*3 + 1] = 0.259161f;	val_dir[4428*3 + 2] = 0.950255f;
+ 	val_dir[4429*3 + 0] = 0.200545f;	val_dir[4429*3 + 1] = 0.289677f;	val_dir[4429*3 + 2] = 0.935879f;
+ 	val_dir[4430*3 + 0] = 0.229658f;	val_dir[4430*3 + 1] = 0.321521f;	val_dir[4430*3 + 2] = 0.918630f;
+ 	val_dir[4431*3 + 0] = 0.259996f;	val_dir[4431*3 + 1] = 0.354540f;	val_dir[4431*3 + 2] = 0.898167f;
+ 	val_dir[4432*3 + 0] = 0.291386f;	val_dir[4432*3 + 1] = 0.388514f;	val_dir[4432*3 + 2] = 0.874157f;
+ 	val_dir[4433*3 + 0] = 0.323587f;	val_dir[4433*3 + 1] = 0.423153f;	val_dir[4433*3 + 2] = 0.846305f;
+ 	val_dir[4434*3 + 0] = 0.356291f;	val_dir[4434*3 + 1] = 0.458088f;	val_dir[4434*3 + 2] = 0.814379f;
+ 	val_dir[4435*3 + 0] = 0.389118f;	val_dir[4435*3 + 1] = 0.492883f;	val_dir[4435*3 + 2] = 0.778237f;
+ 	val_dir[4436*3 + 0] = 0.421637f;	val_dir[4436*3 + 1] = 0.527046f;	val_dir[4436*3 + 2] = 0.737865f;
+ 	val_dir[4437*3 + 0] = 0.453374f;	val_dir[4437*3 + 1] = 0.560050f;	val_dir[4437*3 + 2] = 0.693395f;
+ 	val_dir[4438*3 + 0] = 0.483843f;	val_dir[4438*3 + 1] = 0.591364f;	val_dir[4438*3 + 2] = 0.645124f;
+ 	val_dir[4439*3 + 0] = 0.512578f;	val_dir[4439*3 + 1] = 0.620490f;	val_dir[4439*3 + 2] = 0.593512f;
+ 	val_dir[4440*3 + 0] = 0.539164f;	val_dir[4440*3 + 1] = 0.646997f;	val_dir[4440*3 + 2] = 0.539164f;
+ 	val_dir[4441*3 + 0] = 0.563264f;	val_dir[4441*3 + 1] = 0.670552f;	val_dir[4441*3 + 2] = 0.482798f;
+ 	val_dir[4442*3 + 0] = 0.584643f;	val_dir[4442*3 + 1] = 0.690942f;	val_dir[4442*3 + 2] = 0.425195f;
+ 	val_dir[4443*3 + 0] = 0.603178f;	val_dir[4443*3 + 1] = 0.708079f;	val_dir[4443*3 + 2] = 0.367152f;
+ 	val_dir[4444*3 + 0] = 0.618853f;	val_dir[4444*3 + 1] = 0.721995f;	val_dir[4444*3 + 2] = 0.309426f;
+ 	val_dir[4445*3 + 0] = 0.631748f;	val_dir[4445*3 + 1] = 0.732828f;	val_dir[4445*3 + 2] = 0.252699f;
+ 	val_dir[4446*3 + 0] = 0.642024f;	val_dir[4446*3 + 1] = 0.740797f;	val_dir[4446*3 + 2] = 0.197546f;
+ 	val_dir[4447*3 + 0] = 0.649895f;	val_dir[4447*3 + 1] = 0.746176f;	val_dir[4447*3 + 2] = 0.144421f;
+ 	val_dir[4448*3 + 0] = 0.655610f;	val_dir[4448*3 + 1] = 0.749269f;	val_dir[4448*3 + 2] = 0.093659f;
+ 	val_dir[4449*3 + 0] = 0.659432f;	val_dir[4449*3 + 1] = 0.750388f;	val_dir[4449*3 + 2] = 0.045478f;
+ 	val_dir[4450*3 + 0] = 0.661622f;	val_dir[4450*3 + 1] = 0.749838f;	val_dir[4450*3 + 2] = 0.0f;
+ 	val_dir[4451*3 + 0] = -0.760644f;	val_dir[4451*3 + 1] = -0.648784f;	val_dir[4451*3 + 2] = 0.022372f;
+ 	val_dir[4452*3 + 0] = -0.760684f;	val_dir[4452*3 + 1] = -0.645429f;	val_dir[4452*3 + 2] = 0.069153f;
+ 	val_dir[4453*3 + 0] = -0.758899f;	val_dir[4453*3 + 1] = -0.640321f;	val_dir[4453*3 + 2] = 0.118578f;
+ 	val_dir[4454*3 + 0] = -0.754976f;	val_dir[4454*3 + 1] = -0.633205f;	val_dir[4454*3 + 2] = 0.170478f;
+ 	val_dir[4455*3 + 0] = -0.748598f;	val_dir[4455*3 + 1] = -0.623831f;	val_dir[4455*3 + 2] = 0.224579f;
+ 	val_dir[4456*3 + 0] = -0.739469f;	val_dir[4456*3 + 1] = -0.611974f;	val_dir[4456*3 + 2] = 0.280488f;
+ 	val_dir[4457*3 + 0] = -0.727334f;	val_dir[4457*3 + 1] = -0.597453f;	val_dir[4457*3 + 2] = 0.337691f;
+ 	val_dir[4458*3 + 0] = -0.712007f;	val_dir[4458*3 + 1] = -0.580154f;	val_dir[4458*3 + 2] = 0.395559f;
+ 	val_dir[4459*3 + 0] = -0.693395f;	val_dir[4459*3 + 1] = -0.560050f;	val_dir[4459*3 + 2] = 0.453374f;
+ 	val_dir[4460*3 + 0] = -0.671519f;	val_dir[4460*3 + 1] = -0.537215f;	val_dir[4460*3 + 2] = 0.510355f;
+ 	val_dir[4461*3 + 0] = -0.646527f;	val_dir[4461*3 + 1] = -0.511834f;	val_dir[4461*3 + 2] = 0.565711f;
+ 	val_dir[4462*3 + 0] = -0.618691f;	val_dir[4462*3 + 1] = -0.484193f;	val_dir[4462*3 + 2] = 0.618691f;
+ 	val_dir[4463*3 + 0] = -0.588395f;	val_dir[4463*3 + 1] = -0.454669f;	val_dir[4463*3 + 2] = 0.668631f;
+ 	val_dir[4464*3 + 0] = -0.556108f;	val_dir[4464*3 + 1] = -0.423702f;	val_dir[4464*3 + 2] = 0.714997f;
+ 	val_dir[4465*3 + 0] = -0.522352f;	val_dir[4465*3 + 1] = -0.391764f;	val_dir[4465*3 + 2] = 0.757410f;
+ 	val_dir[4466*3 + 0] = -0.487661f;	val_dir[4466*3 + 1] = -0.359329f;	val_dir[4466*3 + 2] = 0.795657f;
+ 	val_dir[4467*3 + 0] = -0.452553f;	val_dir[4467*3 + 1] = -0.326844f;	val_dir[4467*3 + 2] = 0.829680f;
+ 	val_dir[4468*3 + 0] = -0.41750f;	val_dir[4468*3 + 1] = -0.294706f;	val_dir[4468*3 + 2] = 0.859559f;
+ 	val_dir[4469*3 + 0] = -0.382911f;	val_dir[4469*3 + 1] = -0.263251f;	val_dir[4469*3 + 2] = 0.885482f;
+ 	val_dir[4470*3 + 0] = -0.349121f;	val_dir[4470*3 + 1] = -0.232747f;	val_dir[4470*3 + 2] = 0.907713f;
+ 	val_dir[4471*3 + 0] = -0.316389f;	val_dir[4471*3 + 1] = -0.203393f;	val_dir[4471*3 + 2] = 0.926568f;
+ 	val_dir[4472*3 + 0] = -0.284907f;	val_dir[4472*3 + 1] = -0.175327f;	val_dir[4472*3 + 2] = 0.942384f;
+ 	val_dir[4473*3 + 0] = -0.254801f;	val_dir[4473*3 + 1] = -0.148634f;	val_dir[4473*3 + 2] = 0.955502f;
+ 	val_dir[4474*3 + 0] = -0.226144f;	val_dir[4474*3 + 1] = -0.123351f;	val_dir[4474*3 + 2] = 0.966252f;
+ 	val_dir[4475*3 + 0] = -0.198968f;	val_dir[4475*3 + 1] = -0.099484f;	val_dir[4475*3 + 2] = 0.974943f;
+ 	val_dir[4476*3 + 0] = -0.173269f;	val_dir[4476*3 + 1] = -0.077009f;	val_dir[4476*3 + 2] = 0.981859f;
+ 	val_dir[4477*3 + 0] = -0.149019f;	val_dir[4477*3 + 1] = -0.055882f;	val_dir[4477*3 + 2] = 0.987254f;
+ 	val_dir[4478*3 + 0] = -0.126172f;	val_dir[4478*3 + 1] = -0.036049f;	val_dir[4478*3 + 2] = 0.991353f;
+ 	val_dir[4479*3 + 0] = -0.104669f;	val_dir[4479*3 + 1] = -0.017445f;	val_dir[4479*3 + 2] = 0.994354f;
+ 	val_dir[4480*3 + 0] = -0.084443f;	val_dir[4480*3 + 1] = 0.0f;	val_dir[4480*3 + 2] = 0.996428f;
+ 	val_dir[4481*3 + 0] = -0.067632f;	val_dir[4481*3 + 1] = 0.016908f;	val_dir[4481*3 + 2] = 0.997567f;
+ 	val_dir[4482*3 + 0] = -0.050753f;	val_dir[4482*3 + 1] = 0.033835f;	val_dir[4482*3 + 2] = 0.998138f;
+ 	val_dir[4483*3 + 0] = -0.033835f;	val_dir[4483*3 + 1] = 0.050753f;	val_dir[4483*3 + 2] = 0.998138f;
+ 	val_dir[4484*3 + 0] = -0.016908f;	val_dir[4484*3 + 1] = 0.067632f;	val_dir[4484*3 + 2] = 0.997567f;
+ 	val_dir[4485*3 + 0] = 0.0f;	val_dir[4485*3 + 1] = 0.084443f;	val_dir[4485*3 + 2] = 0.996428f;
+ 	val_dir[4486*3 + 0] = 0.017445f;	val_dir[4486*3 + 1] = 0.104669f;	val_dir[4486*3 + 2] = 0.994354f;
+ 	val_dir[4487*3 + 0] = 0.036049f;	val_dir[4487*3 + 1] = 0.126172f;	val_dir[4487*3 + 2] = 0.991353f;
+ 	val_dir[4488*3 + 0] = 0.055882f;	val_dir[4488*3 + 1] = 0.149019f;	val_dir[4488*3 + 2] = 0.987254f;
+ 	val_dir[4489*3 + 0] = 0.077009f;	val_dir[4489*3 + 1] = 0.173269f;	val_dir[4489*3 + 2] = 0.981859f;
+ 	val_dir[4490*3 + 0] = 0.099484f;	val_dir[4490*3 + 1] = 0.198968f;	val_dir[4490*3 + 2] = 0.974943f;
+ 	val_dir[4491*3 + 0] = 0.123351f;	val_dir[4491*3 + 1] = 0.226144f;	val_dir[4491*3 + 2] = 0.966252f;
+ 	val_dir[4492*3 + 0] = 0.148634f;	val_dir[4492*3 + 1] = 0.254801f;	val_dir[4492*3 + 2] = 0.955502f;
+ 	val_dir[4493*3 + 0] = 0.175327f;	val_dir[4493*3 + 1] = 0.284907f;	val_dir[4493*3 + 2] = 0.942384f;
+ 	val_dir[4494*3 + 0] = 0.203393f;	val_dir[4494*3 + 1] = 0.316389f;	val_dir[4494*3 + 2] = 0.926568f;
+ 	val_dir[4495*3 + 0] = 0.232747f;	val_dir[4495*3 + 1] = 0.349121f;	val_dir[4495*3 + 2] = 0.907713f;
+ 	val_dir[4496*3 + 0] = 0.263251f;	val_dir[4496*3 + 1] = 0.382911f;	val_dir[4496*3 + 2] = 0.885482f;
+ 	val_dir[4497*3 + 0] = 0.294706f;	val_dir[4497*3 + 1] = 0.41750f;	val_dir[4497*3 + 2] = 0.859559f;
+ 	val_dir[4498*3 + 0] = 0.326844f;	val_dir[4498*3 + 1] = 0.452553f;	val_dir[4498*3 + 2] = 0.829680f;
+ 	val_dir[4499*3 + 0] = 0.359329f;	val_dir[4499*3 + 1] = 0.487661f;	val_dir[4499*3 + 2] = 0.795657f;
+ 	val_dir[4500*3 + 0] = 0.391764f;	val_dir[4500*3 + 1] = 0.522352f;	val_dir[4500*3 + 2] = 0.757410f;
+ 	val_dir[4501*3 + 0] = 0.423702f;	val_dir[4501*3 + 1] = 0.556108f;	val_dir[4501*3 + 2] = 0.714997f;
+ 	val_dir[4502*3 + 0] = 0.454669f;	val_dir[4502*3 + 1] = 0.588395f;	val_dir[4502*3 + 2] = 0.668631f;
+ 	val_dir[4503*3 + 0] = 0.484193f;	val_dir[4503*3 + 1] = 0.618691f;	val_dir[4503*3 + 2] = 0.618691f;
+ 	val_dir[4504*3 + 0] = 0.511834f;	val_dir[4504*3 + 1] = 0.646527f;	val_dir[4504*3 + 2] = 0.565711f;
+ 	val_dir[4505*3 + 0] = 0.537215f;	val_dir[4505*3 + 1] = 0.671519f;	val_dir[4505*3 + 2] = 0.510355f;
+ 	val_dir[4506*3 + 0] = 0.560050f;	val_dir[4506*3 + 1] = 0.693395f;	val_dir[4506*3 + 2] = 0.453374f;
+ 	val_dir[4507*3 + 0] = 0.580154f;	val_dir[4507*3 + 1] = 0.712007f;	val_dir[4507*3 + 2] = 0.395559f;
+ 	val_dir[4508*3 + 0] = 0.597453f;	val_dir[4508*3 + 1] = 0.727334f;	val_dir[4508*3 + 2] = 0.337691f;
+ 	val_dir[4509*3 + 0] = 0.611974f;	val_dir[4509*3 + 1] = 0.739469f;	val_dir[4509*3 + 2] = 0.280488f;
+ 	val_dir[4510*3 + 0] = 0.623831f;	val_dir[4510*3 + 1] = 0.748598f;	val_dir[4510*3 + 2] = 0.224579f;
+ 	val_dir[4511*3 + 0] = 0.633205f;	val_dir[4511*3 + 1] = 0.754976f;	val_dir[4511*3 + 2] = 0.170478f;
+ 	val_dir[4512*3 + 0] = 0.640321f;	val_dir[4512*3 + 1] = 0.758899f;	val_dir[4512*3 + 2] = 0.118578f;
+ 	val_dir[4513*3 + 0] = 0.645429f;	val_dir[4513*3 + 1] = 0.760684f;	val_dir[4513*3 + 2] = 0.069153f;
+ 	val_dir[4514*3 + 0] = 0.648784f;	val_dir[4514*3 + 1] = 0.760644f;	val_dir[4514*3 + 2] = 0.022372f;
+ 	val_dir[4515*3 + 0] = -0.770022f;	val_dir[4515*3 + 1] = -0.638018f;	val_dir[4515*3 + 2] = 0.0f;
+ 	val_dir[4516*3 + 0] = -0.771136f;	val_dir[4516*3 + 1] = -0.635053f;	val_dir[4516*3 + 2] = 0.045361f;
+ 	val_dir[4517*3 + 0] = -0.770574f;	val_dir[4517*3 + 1] = -0.630470f;	val_dir[4517*3 + 2] = 0.093403f;
+ 	val_dir[4518*3 + 0] = -0.768025f;	val_dir[4518*3 + 1] = -0.624020f;	val_dir[4518*3 + 2] = 0.144005f;
+ 	val_dir[4519*3 + 0] = -0.763167f;	val_dir[4519*3 + 1] = -0.615457f;	val_dir[4519*3 + 2] = 0.196946f;
+ 	val_dir[4520*3 + 0] = -0.755689f;	val_dir[4520*3 + 1] = -0.604551f;	val_dir[4520*3 + 2] = 0.251896f;
+ 	val_dir[4521*3 + 0] = -0.745307f;	val_dir[4521*3 + 1] = -0.591105f;	val_dir[4521*3 + 2] = 0.308403f;
+ 	val_dir[4522*3 + 0] = -0.731792f;	val_dir[4522*3 + 1] = -0.574979f;	val_dir[4522*3 + 2] = 0.365896f;
+ 	val_dir[4523*3 + 0] = -0.714997f;	val_dir[4523*3 + 1] = -0.556108f;	val_dir[4523*3 + 2] = 0.423702f;
+ 	val_dir[4524*3 + 0] = -0.694879f;	val_dir[4524*3 + 1] = -0.534522f;	val_dir[4524*3 + 2] = 0.481070f;
+ 	val_dir[4525*3 + 0] = -0.671519f;	val_dir[4525*3 + 1] = -0.510355f;	val_dir[4525*3 + 2] = 0.537215f;
+ 	val_dir[4526*3 + 0] = -0.645124f;	val_dir[4526*3 + 1] = -0.483843f;	val_dir[4526*3 + 2] = 0.591364f;
+ 	val_dir[4527*3 + 0] = -0.616022f;	val_dir[4527*3 + 1] = -0.455321f;	val_dir[4527*3 + 2] = 0.642806f;
+ 	val_dir[4528*3 + 0] = -0.584643f;	val_dir[4528*3 + 1] = -0.425195f;	val_dir[4528*3 + 2] = 0.690942f;
+ 	val_dir[4529*3 + 0] = -0.551487f;	val_dir[4529*3 + 1] = -0.393919f;	val_dir[4529*3 + 2] = 0.735316f;
+ 	val_dir[4530*3 + 0] = -0.517088f;	val_dir[4530*3 + 1] = -0.361961f;	val_dir[4530*3 + 2] = 0.775632f;
+ 	val_dir[4531*3 + 0] = -0.481979f;	val_dir[4531*3 + 1] = -0.329775f;	val_dir[4531*3 + 2] = 0.811754f;
+ 	val_dir[4532*3 + 0] = -0.446662f;	val_dir[4532*3 + 1] = -0.297775f;	val_dir[4532*3 + 2] = 0.843696f;
+ 	val_dir[4533*3 + 0] = -0.411585f;	val_dir[4533*3 + 1] = -0.266320f;	val_dir[4533*3 + 2] = 0.871592f;
+ 	val_dir[4534*3 + 0] = -0.377124f;	val_dir[4534*3 + 1] = -0.235702f;	val_dir[4534*3 + 2] = 0.895669f;
+ 	val_dir[4535*3 + 0] = -0.343582f;	val_dir[4535*3 + 1] = -0.206149f;	val_dir[4535*3 + 2] = 0.916217f;
+ 	val_dir[4536*3 + 0] = -0.311188f;	val_dir[4536*3 + 1] = -0.177822f;	val_dir[4536*3 + 2] = 0.933564f;
+ 	val_dir[4537*3 + 0] = -0.280105f;	val_dir[4537*3 + 1] = -0.150826f;	val_dir[4537*3 + 2] = 0.948047f;
+ 	val_dir[4538*3 + 0] = -0.250435f;	val_dir[4538*3 + 1] = -0.125218f;	val_dir[4538*3 + 2] = 0.960001f;
+ 	val_dir[4539*3 + 0] = -0.222234f;	val_dir[4539*3 + 1] = -0.101015f;	val_dir[4539*3 + 2] = 0.969746f;
+ 	val_dir[4540*3 + 0] = -0.195515f;	val_dir[4540*3 + 1] = -0.078206f;	val_dir[4540*3 + 2] = 0.977577f;
+ 	val_dir[4541*3 + 0] = -0.170267f;	val_dir[4541*3 + 1] = -0.056756f;	val_dir[4541*3 + 2] = 0.983762f;
+ 	val_dir[4542*3 + 0] = -0.146450f;	val_dir[4542*3 + 1] = -0.036613f;	val_dir[4542*3 + 2] = 0.988540f;
+ 	val_dir[4543*3 + 0] = -0.124015f;	val_dir[4543*3 + 1] = -0.017716f;	val_dir[4543*3 + 2] = 0.992122f;
+ 	val_dir[4544*3 + 0] = -0.102899f;	val_dir[4544*3 + 1] = 0.0f;	val_dir[4544*3 + 2] = 0.994692f;
+ 	val_dir[4545*3 + 0] = -0.085876f;	val_dir[4545*3 + 1] = 0.017175f;	val_dir[4545*3 + 2] = 0.996158f;
+ 	val_dir[4546*3 + 0] = -0.068761f;	val_dir[4546*3 + 1] = 0.034381f;	val_dir[4546*3 + 2] = 0.997041f;
+ 	val_dir[4547*3 + 0] = -0.051586f;	val_dir[4547*3 + 1] = 0.051586f;	val_dir[4547*3 + 2] = 0.997335f;
+ 	val_dir[4548*3 + 0] = -0.034381f;	val_dir[4548*3 + 1] = 0.068761f;	val_dir[4548*3 + 2] = 0.997041f;
+ 	val_dir[4549*3 + 0] = -0.017175f;	val_dir[4549*3 + 1] = 0.085876f;	val_dir[4549*3 + 2] = 0.996158f;
+ 	val_dir[4550*3 + 0] = 0.0f;	val_dir[4550*3 + 1] = 0.102899f;	val_dir[4550*3 + 2] = 0.994692f;
+ 	val_dir[4551*3 + 0] = 0.017716f;	val_dir[4551*3 + 1] = 0.124015f;	val_dir[4551*3 + 2] = 0.992122f;
+ 	val_dir[4552*3 + 0] = 0.036613f;	val_dir[4552*3 + 1] = 0.146450f;	val_dir[4552*3 + 2] = 0.988540f;
+ 	val_dir[4553*3 + 0] = 0.056756f;	val_dir[4553*3 + 1] = 0.170267f;	val_dir[4553*3 + 2] = 0.983762f;
+ 	val_dir[4554*3 + 0] = 0.078206f;	val_dir[4554*3 + 1] = 0.195515f;	val_dir[4554*3 + 2] = 0.977577f;
+ 	val_dir[4555*3 + 0] = 0.101015f;	val_dir[4555*3 + 1] = 0.222234f;	val_dir[4555*3 + 2] = 0.969746f;
+ 	val_dir[4556*3 + 0] = 0.125218f;	val_dir[4556*3 + 1] = 0.250435f;	val_dir[4556*3 + 2] = 0.960001f;
+ 	val_dir[4557*3 + 0] = 0.150826f;	val_dir[4557*3 + 1] = 0.280105f;	val_dir[4557*3 + 2] = 0.948047f;
+ 	val_dir[4558*3 + 0] = 0.177822f;	val_dir[4558*3 + 1] = 0.311188f;	val_dir[4558*3 + 2] = 0.933564f;
+ 	val_dir[4559*3 + 0] = 0.206149f;	val_dir[4559*3 + 1] = 0.343582f;	val_dir[4559*3 + 2] = 0.916217f;
+ 	val_dir[4560*3 + 0] = 0.235702f;	val_dir[4560*3 + 1] = 0.377124f;	val_dir[4560*3 + 2] = 0.895669f;
+ 	val_dir[4561*3 + 0] = 0.266320f;	val_dir[4561*3 + 1] = 0.411585f;	val_dir[4561*3 + 2] = 0.871592f;
+ 	val_dir[4562*3 + 0] = 0.297775f;	val_dir[4562*3 + 1] = 0.446662f;	val_dir[4562*3 + 2] = 0.843696f;
+ 	val_dir[4563*3 + 0] = 0.329775f;	val_dir[4563*3 + 1] = 0.481979f;	val_dir[4563*3 + 2] = 0.811754f;
+ 	val_dir[4564*3 + 0] = 0.361961f;	val_dir[4564*3 + 1] = 0.517088f;	val_dir[4564*3 + 2] = 0.775632f;
+ 	val_dir[4565*3 + 0] = 0.393919f;	val_dir[4565*3 + 1] = 0.551487f;	val_dir[4565*3 + 2] = 0.735316f;
+ 	val_dir[4566*3 + 0] = 0.425195f;	val_dir[4566*3 + 1] = 0.584643f;	val_dir[4566*3 + 2] = 0.690942f;
+ 	val_dir[4567*3 + 0] = 0.455321f;	val_dir[4567*3 + 1] = 0.616022f;	val_dir[4567*3 + 2] = 0.642806f;
+ 	val_dir[4568*3 + 0] = 0.483843f;	val_dir[4568*3 + 1] = 0.645124f;	val_dir[4568*3 + 2] = 0.591364f;
+ 	val_dir[4569*3 + 0] = 0.510355f;	val_dir[4569*3 + 1] = 0.671519f;	val_dir[4569*3 + 2] = 0.537215f;
+ 	val_dir[4570*3 + 0] = 0.534522f;	val_dir[4570*3 + 1] = 0.694879f;	val_dir[4570*3 + 2] = 0.481070f;
+ 	val_dir[4571*3 + 0] = 0.556108f;	val_dir[4571*3 + 1] = 0.714997f;	val_dir[4571*3 + 2] = 0.423702f;
+ 	val_dir[4572*3 + 0] = 0.574979f;	val_dir[4572*3 + 1] = 0.731792f;	val_dir[4572*3 + 2] = 0.365896f;
+ 	val_dir[4573*3 + 0] = 0.591105f;	val_dir[4573*3 + 1] = 0.745307f;	val_dir[4573*3 + 2] = 0.308403f;
+ 	val_dir[4574*3 + 0] = 0.604551f;	val_dir[4574*3 + 1] = 0.755689f;	val_dir[4574*3 + 2] = 0.251896f;
+ 	val_dir[4575*3 + 0] = 0.615457f;	val_dir[4575*3 + 1] = 0.763167f;	val_dir[4575*3 + 2] = 0.196946f;
+ 	val_dir[4576*3 + 0] = 0.624020f;	val_dir[4576*3 + 1] = 0.768025f;	val_dir[4576*3 + 2] = 0.144005f;
+ 	val_dir[4577*3 + 0] = 0.630470f;	val_dir[4577*3 + 1] = 0.770574f;	val_dir[4577*3 + 2] = 0.093403f;
+ 	val_dir[4578*3 + 0] = 0.635053f;	val_dir[4578*3 + 1] = 0.771136f;	val_dir[4578*3 + 2] = 0.045361f;
+ 	val_dir[4579*3 + 0] = 0.638018f;	val_dir[4579*3 + 1] = 0.770022f;	val_dir[4579*3 + 2] = 0.0f;
+ 	val_dir[4580*3 + 0] = -0.780675f;	val_dir[4580*3 + 1] = -0.624540f;	val_dir[4580*3 + 2] = 0.022305f;
+ 	val_dir[4581*3 + 0] = -0.781248f;	val_dir[4581*3 + 1] = -0.620403f;	val_dir[4581*3 + 2] = 0.068934f;
+ 	val_dir[4582*3 + 0] = -0.779987f;	val_dir[4582*3 + 1] = -0.614535f;	val_dir[4582*3 + 2] = 0.118180f;
+ 	val_dir[4583*3 + 0] = -0.776571f;	val_dir[4583*3 + 1] = -0.606696f;	val_dir[4583*3 + 2] = 0.169875f;
+ 	val_dir[4584*3 + 0] = -0.770677f;	val_dir[4584*3 + 1] = -0.596653f;	val_dir[4584*3 + 2] = 0.223745f;
+ 	val_dir[4585*3 + 0] = -0.762001f;	val_dir[4585*3 + 1] = -0.584201f;	val_dir[4585*3 + 2] = 0.27940f;
+ 	val_dir[4586*3 + 0] = -0.750279f;	val_dir[4586*3 + 1] = -0.569177f;	val_dir[4586*3 + 2] = 0.336332f;
+ 	val_dir[4587*3 + 0] = -0.735316f;	val_dir[4587*3 + 1] = -0.551487f;	val_dir[4587*3 + 2] = 0.393919f;
+ 	val_dir[4588*3 + 0] = -0.717011f;	val_dir[4588*3 + 1] = -0.531119f;	val_dir[4588*3 + 2] = 0.451451f;
+ 	val_dir[4589*3 + 0] = -0.695376f;	val_dir[4589*3 + 1] = -0.508159f;	val_dir[4589*3 + 2] = 0.508159f;
+ 	val_dir[4590*3 + 0] = -0.670552f;	val_dir[4590*3 + 1] = -0.482798f;	val_dir[4590*3 + 2] = 0.563264f;
+ 	val_dir[4591*3 + 0] = -0.642806f;	val_dir[4591*3 + 1] = -0.455321f;	val_dir[4591*3 + 2] = 0.616022f;
+ 	val_dir[4592*3 + 0] = -0.612517f;	val_dir[4592*3 + 1] = -0.426099f;	val_dir[4592*3 + 2] = 0.665780f;
+ 	val_dir[4593*3 + 0] = -0.580154f;	val_dir[4593*3 + 1] = -0.395559f;	val_dir[4593*3 + 2] = 0.712007f;
+ 	val_dir[4594*3 + 0] = -0.546238f;	val_dir[4594*3 + 1] = -0.364159f;	val_dir[4594*3 + 2] = 0.754329f;
+ 	val_dir[4595*3 + 0] = -0.511310f;	val_dir[4595*3 + 1] = -0.332352f;	val_dir[4595*3 + 2] = 0.792530f;
+ 	val_dir[4596*3 + 0] = -0.475893f;	val_dir[4596*3 + 1] = -0.300564f;	val_dir[4596*3 + 2] = 0.826551f;
+ 	val_dir[4597*3 + 0] = -0.440468f;	val_dir[4597*3 + 1] = -0.269175f;	val_dir[4597*3 + 2] = 0.856465f;
+ 	val_dir[4598*3 + 0] = -0.405452f;	val_dir[4598*3 + 1] = -0.238501f;	val_dir[4598*3 + 2] = 0.882454f;
+ 	val_dir[4599*3 + 0] = -0.371191f;	val_dir[4599*3 + 1] = -0.208795f;	val_dir[4599*3 + 2] = 0.904777f;
+ 	val_dir[4600*3 + 0] = -0.337954f;	val_dir[4600*3 + 1] = -0.180242f;	val_dir[4600*3 + 2] = 0.923742f;
+ 	val_dir[4601*3 + 0] = -0.305942f;	val_dir[4601*3 + 1] = -0.152971f;	val_dir[4601*3 + 2] = 0.939680f;
+ 	val_dir[4602*3 + 0] = -0.275290f;	val_dir[4602*3 + 1] = -0.127057f;	val_dir[4602*3 + 2] = 0.952928f;
+ 	val_dir[4603*3 + 0] = -0.246079f;	val_dir[4603*3 + 1] = -0.102533f;	val_dir[4603*3 + 2] = 0.963811f;
+ 	val_dir[4604*3 + 0] = -0.218347f;	val_dir[4604*3 + 1] = -0.079399f;	val_dir[4604*3 + 2] = 0.972636f;
+ 	val_dir[4605*3 + 0] = -0.192095f;	val_dir[4605*3 + 1] = -0.057628f;	val_dir[4605*3 + 2] = 0.979683f;
+ 	val_dir[4606*3 + 0] = -0.167299f;	val_dir[4606*3 + 1] = -0.037178f;	val_dir[4606*3 + 2] = 0.985205f;
+ 	val_dir[4607*3 + 0] = -0.143917f;	val_dir[4607*3 + 1] = -0.017990f;	val_dir[4607*3 + 2] = 0.989426f;
+ 	val_dir[4608*3 + 0] = -0.121891f;	val_dir[4608*3 + 1] = 0.0f;	val_dir[4608*3 + 2] = 0.992543f;
+ 	val_dir[4609*3 + 0] = -0.104669f;	val_dir[4609*3 + 1] = 0.017445f;	val_dir[4609*3 + 2] = 0.994354f;
+ 	val_dir[4610*3 + 0] = -0.087330f;	val_dir[4610*3 + 1] = 0.034932f;	val_dir[4610*3 + 2] = 0.995567f;
+ 	val_dir[4611*3 + 0] = -0.069907f;	val_dir[4611*3 + 1] = 0.052430f;	val_dir[4611*3 + 2] = 0.996175f;
+ 	val_dir[4612*3 + 0] = -0.052430f;	val_dir[4612*3 + 1] = 0.069907f;	val_dir[4612*3 + 2] = 0.996175f;
+ 	val_dir[4613*3 + 0] = -0.034932f;	val_dir[4613*3 + 1] = 0.087330f;	val_dir[4613*3 + 2] = 0.995567f;
+ 	val_dir[4614*3 + 0] = -0.017445f;	val_dir[4614*3 + 1] = 0.104669f;	val_dir[4614*3 + 2] = 0.994354f;
+ 	val_dir[4615*3 + 0] = 0.0f;	val_dir[4615*3 + 1] = 0.121891f;	val_dir[4615*3 + 2] = 0.992543f;
+ 	val_dir[4616*3 + 0] = 0.017990f;	val_dir[4616*3 + 1] = 0.143917f;	val_dir[4616*3 + 2] = 0.989426f;
+ 	val_dir[4617*3 + 0] = 0.037178f;	val_dir[4617*3 + 1] = 0.167299f;	val_dir[4617*3 + 2] = 0.985205f;
+ 	val_dir[4618*3 + 0] = 0.057628f;	val_dir[4618*3 + 1] = 0.192095f;	val_dir[4618*3 + 2] = 0.979683f;
+ 	val_dir[4619*3 + 0] = 0.079399f;	val_dir[4619*3 + 1] = 0.218347f;	val_dir[4619*3 + 2] = 0.972636f;
+ 	val_dir[4620*3 + 0] = 0.102533f;	val_dir[4620*3 + 1] = 0.246079f;	val_dir[4620*3 + 2] = 0.963811f;
+ 	val_dir[4621*3 + 0] = 0.127057f;	val_dir[4621*3 + 1] = 0.275290f;	val_dir[4621*3 + 2] = 0.952928f;
+ 	val_dir[4622*3 + 0] = 0.152971f;	val_dir[4622*3 + 1] = 0.305942f;	val_dir[4622*3 + 2] = 0.939680f;
+ 	val_dir[4623*3 + 0] = 0.180242f;	val_dir[4623*3 + 1] = 0.337954f;	val_dir[4623*3 + 2] = 0.923742f;
+ 	val_dir[4624*3 + 0] = 0.208795f;	val_dir[4624*3 + 1] = 0.371191f;	val_dir[4624*3 + 2] = 0.904777f;
+ 	val_dir[4625*3 + 0] = 0.238501f;	val_dir[4625*3 + 1] = 0.405452f;	val_dir[4625*3 + 2] = 0.882454f;
+ 	val_dir[4626*3 + 0] = 0.269175f;	val_dir[4626*3 + 1] = 0.440468f;	val_dir[4626*3 + 2] = 0.856465f;
+ 	val_dir[4627*3 + 0] = 0.300564f;	val_dir[4627*3 + 1] = 0.475893f;	val_dir[4627*3 + 2] = 0.826551f;
+ 	val_dir[4628*3 + 0] = 0.332352f;	val_dir[4628*3 + 1] = 0.511310f;	val_dir[4628*3 + 2] = 0.792530f;
+ 	val_dir[4629*3 + 0] = 0.364159f;	val_dir[4629*3 + 1] = 0.546238f;	val_dir[4629*3 + 2] = 0.754329f;
+ 	val_dir[4630*3 + 0] = 0.395559f;	val_dir[4630*3 + 1] = 0.580154f;	val_dir[4630*3 + 2] = 0.712007f;
+ 	val_dir[4631*3 + 0] = 0.426099f;	val_dir[4631*3 + 1] = 0.612517f;	val_dir[4631*3 + 2] = 0.665780f;
+ 	val_dir[4632*3 + 0] = 0.455321f;	val_dir[4632*3 + 1] = 0.642806f;	val_dir[4632*3 + 2] = 0.616022f;
+ 	val_dir[4633*3 + 0] = 0.482798f;	val_dir[4633*3 + 1] = 0.670552f;	val_dir[4633*3 + 2] = 0.563264f;
+ 	val_dir[4634*3 + 0] = 0.508159f;	val_dir[4634*3 + 1] = 0.695376f;	val_dir[4634*3 + 2] = 0.508159f;
+ 	val_dir[4635*3 + 0] = 0.531119f;	val_dir[4635*3 + 1] = 0.717011f;	val_dir[4635*3 + 2] = 0.451451f;
+ 	val_dir[4636*3 + 0] = 0.551487f;	val_dir[4636*3 + 1] = 0.735316f;	val_dir[4636*3 + 2] = 0.393919f;
+ 	val_dir[4637*3 + 0] = 0.569177f;	val_dir[4637*3 + 1] = 0.750279f;	val_dir[4637*3 + 2] = 0.336332f;
+ 	val_dir[4638*3 + 0] = 0.584201f;	val_dir[4638*3 + 1] = 0.762001f;	val_dir[4638*3 + 2] = 0.27940f;
+ 	val_dir[4639*3 + 0] = 0.596653f;	val_dir[4639*3 + 1] = 0.770677f;	val_dir[4639*3 + 2] = 0.223745f;
+ 	val_dir[4640*3 + 0] = 0.606696f;	val_dir[4640*3 + 1] = 0.776571f;	val_dir[4640*3 + 2] = 0.169875f;
+ 	val_dir[4641*3 + 0] = 0.614535f;	val_dir[4641*3 + 1] = 0.779987f;	val_dir[4641*3 + 2] = 0.118180f;
+ 	val_dir[4642*3 + 0] = 0.620403f;	val_dir[4642*3 + 1] = 0.781248f;	val_dir[4642*3 + 2] = 0.068934f;
+ 	val_dir[4643*3 + 0] = 0.624540f;	val_dir[4643*3 + 1] = 0.780675f;	val_dir[4643*3 + 2] = 0.022305f;
+ 	val_dir[4644*3 + 0] = -0.789352f;	val_dir[4644*3 + 1] = -0.613941f;	val_dir[4644*3 + 2] = 0.0f;
+ 	val_dir[4645*3 + 0] = -0.790973f;	val_dir[4645*3 + 1] = -0.610179f;	val_dir[4645*3 + 2] = 0.045198f;
+ 	val_dir[4646*3 + 0] = -0.790912f;	val_dir[4646*3 + 1] = -0.604815f;	val_dir[4646*3 + 2] = 0.093048f;
+ 	val_dir[4647*3 + 0] = -0.788851f;	val_dir[4647*3 + 1] = -0.597614f;	val_dir[4647*3 + 2] = 0.143427f;
+ 	val_dir[4648*3 + 0] = -0.784465f;	val_dir[4648*3 + 1] = -0.588348f;	val_dir[4648*3 + 2] = 0.196116f;
+ 	val_dir[4649*3 + 0] = -0.777433f;	val_dir[4649*3 + 1] = -0.576805f;	val_dir[4649*3 + 2] = 0.250785f;
+ 	val_dir[4650*3 + 0] = -0.767467f;	val_dir[4650*3 + 1] = -0.562809f;	val_dir[4650*3 + 2] = 0.306987f;
+ 	val_dir[4651*3 + 0] = -0.754329f;	val_dir[4651*3 + 1] = -0.546238f;	val_dir[4651*3 + 2] = 0.364159f;
+ 	val_dir[4652*3 + 0] = -0.737865f;	val_dir[4652*3 + 1] = -0.527046f;	val_dir[4652*3 + 2] = 0.421637f;
+ 	val_dir[4653*3 + 0] = -0.718024f;	val_dir[4653*3 + 1] = -0.505276f;	val_dir[4653*3 + 2] = 0.478683f;
+ 	val_dir[4654*3 + 0] = -0.694879f;	val_dir[4654*3 + 1] = -0.481070f;	val_dir[4654*3 + 2] = 0.534522f;
+ 	val_dir[4655*3 + 0] = -0.668631f;	val_dir[4655*3 + 1] = -0.454669f;	val_dir[4655*3 + 2] = 0.588395f;
+ 	val_dir[4656*3 + 0] = -0.639602f;	val_dir[4656*3 + 1] = -0.426401f;	val_dir[4656*3 + 2] = 0.639602f;
+ 	val_dir[4657*3 + 0] = -0.608219f;	val_dir[4657*3 + 1] = -0.396664f;	val_dir[4657*3 + 2] = 0.687552f;
+ 	val_dir[4658*3 + 0] = -0.574979f;	val_dir[4658*3 + 1] = -0.365896f;	val_dir[4658*3 + 2] = 0.731792f;
+ 	val_dir[4659*3 + 0] = -0.540419f;	val_dir[4659*3 + 1] = -0.334545f;	val_dir[4659*3 + 2] = 0.772027f;
+ 	val_dir[4660*3 + 0] = -0.505076f;	val_dir[4660*3 + 1] = -0.303046f;	val_dir[4660*3 + 2] = 0.808122f;
+ 	val_dir[4661*3 + 0] = -0.469458f;	val_dir[4661*3 + 1] = -0.271791f;	val_dir[4661*3 + 2] = 0.840083f;
+ 	val_dir[4662*3 + 0] = -0.434019f;	val_dir[4662*3 + 1] = -0.241121f;	val_dir[4662*3 + 2] = 0.868037f;
+ 	val_dir[4663*3 + 0] = -0.399145f;	val_dir[4663*3 + 1] = -0.211312f;	val_dir[4663*3 + 2] = 0.892206f;
+ 	val_dir[4664*3 + 0] = -0.365148f;	val_dir[4664*3 + 1] = -0.182574f;	val_dir[4664*3 + 2] = 0.912871f;
+ 	val_dir[4665*3 + 0] = -0.332269f;	val_dir[4665*3 + 1] = -0.155059f;	val_dir[4665*3 + 2] = 0.930352f;
+ 	val_dir[4666*3 + 0] = -0.300676f;	val_dir[4666*3 + 1] = -0.128861f;	val_dir[4666*3 + 2] = 0.944981f;
+ 	val_dir[4667*3 + 0] = -0.270481f;	val_dir[4667*3 + 1] = -0.104031f;	val_dir[4667*3 + 2] = 0.957088f;
+ 	val_dir[4668*3 + 0] = -0.241747f;	val_dir[4668*3 + 1] = -0.080582f;	val_dir[4668*3 + 2] = 0.966988f;
+ 	val_dir[4669*3 + 0] = -0.214494f;	val_dir[4669*3 + 1] = -0.058498f;	val_dir[4669*3 + 2] = 0.974972f;
+ 	val_dir[4670*3 + 0] = -0.188713f;	val_dir[4670*3 + 1] = -0.037743f;	val_dir[4670*3 + 2] = 0.981307f;
+ 	val_dir[4671*3 + 0] = -0.164372f;	val_dir[4671*3 + 1] = -0.018264f;	val_dir[4671*3 + 2] = 0.986229f;
+ 	val_dir[4672*3 + 0] = -0.141421f;	val_dir[4672*3 + 1] = 0.0f;	val_dir[4672*3 + 2] = 0.989949f;
+ 	val_dir[4673*3 + 0] = -0.124015f;	val_dir[4673*3 + 1] = 0.017716f;	val_dir[4673*3 + 2] = 0.992122f;
+ 	val_dir[4674*3 + 0] = -0.106466f;	val_dir[4674*3 + 1] = 0.035489f;	val_dir[4674*3 + 2] = 0.993683f;
+ 	val_dir[4675*3 + 0] = -0.088806f;	val_dir[4675*3 + 1] = 0.053283f;	val_dir[4675*3 + 2] = 0.994623f;
+ 	val_dir[4676*3 + 0] = -0.071067f;	val_dir[4676*3 + 1] = 0.071067f;	val_dir[4676*3 + 2] = 0.994937f;
+ 	val_dir[4677*3 + 0] = -0.053283f;	val_dir[4677*3 + 1] = 0.088806f;	val_dir[4677*3 + 2] = 0.994623f;
+ 	val_dir[4678*3 + 0] = -0.035489f;	val_dir[4678*3 + 1] = 0.106466f;	val_dir[4678*3 + 2] = 0.993683f;
+ 	val_dir[4679*3 + 0] = -0.017716f;	val_dir[4679*3 + 1] = 0.124015f;	val_dir[4679*3 + 2] = 0.992122f;
+ 	val_dir[4680*3 + 0] = 0.0f;	val_dir[4680*3 + 1] = 0.141421f;	val_dir[4680*3 + 2] = 0.989949f;
+ 	val_dir[4681*3 + 0] = 0.018264f;	val_dir[4681*3 + 1] = 0.164372f;	val_dir[4681*3 + 2] = 0.986229f;
+ 	val_dir[4682*3 + 0] = 0.037743f;	val_dir[4682*3 + 1] = 0.188713f;	val_dir[4682*3 + 2] = 0.981307f;
+ 	val_dir[4683*3 + 0] = 0.058498f;	val_dir[4683*3 + 1] = 0.214494f;	val_dir[4683*3 + 2] = 0.974972f;
+ 	val_dir[4684*3 + 0] = 0.080582f;	val_dir[4684*3 + 1] = 0.241747f;	val_dir[4684*3 + 2] = 0.966988f;
+ 	val_dir[4685*3 + 0] = 0.104031f;	val_dir[4685*3 + 1] = 0.270481f;	val_dir[4685*3 + 2] = 0.957088f;
+ 	val_dir[4686*3 + 0] = 0.128861f;	val_dir[4686*3 + 1] = 0.300676f;	val_dir[4686*3 + 2] = 0.944981f;
+ 	val_dir[4687*3 + 0] = 0.155059f;	val_dir[4687*3 + 1] = 0.332269f;	val_dir[4687*3 + 2] = 0.930352f;
+ 	val_dir[4688*3 + 0] = 0.182574f;	val_dir[4688*3 + 1] = 0.365148f;	val_dir[4688*3 + 2] = 0.912871f;
+ 	val_dir[4689*3 + 0] = 0.211312f;	val_dir[4689*3 + 1] = 0.399145f;	val_dir[4689*3 + 2] = 0.892206f;
+ 	val_dir[4690*3 + 0] = 0.241121f;	val_dir[4690*3 + 1] = 0.434019f;	val_dir[4690*3 + 2] = 0.868037f;
+ 	val_dir[4691*3 + 0] = 0.271791f;	val_dir[4691*3 + 1] = 0.469458f;	val_dir[4691*3 + 2] = 0.840083f;
+ 	val_dir[4692*3 + 0] = 0.303046f;	val_dir[4692*3 + 1] = 0.505076f;	val_dir[4692*3 + 2] = 0.808122f;
+ 	val_dir[4693*3 + 0] = 0.334545f;	val_dir[4693*3 + 1] = 0.540419f;	val_dir[4693*3 + 2] = 0.772027f;
+ 	val_dir[4694*3 + 0] = 0.365896f;	val_dir[4694*3 + 1] = 0.574979f;	val_dir[4694*3 + 2] = 0.731792f;
+ 	val_dir[4695*3 + 0] = 0.396664f;	val_dir[4695*3 + 1] = 0.608219f;	val_dir[4695*3 + 2] = 0.687552f;
+ 	val_dir[4696*3 + 0] = 0.426401f;	val_dir[4696*3 + 1] = 0.639602f;	val_dir[4696*3 + 2] = 0.639602f;
+ 	val_dir[4697*3 + 0] = 0.454669f;	val_dir[4697*3 + 1] = 0.668631f;	val_dir[4697*3 + 2] = 0.588395f;
+ 	val_dir[4698*3 + 0] = 0.481070f;	val_dir[4698*3 + 1] = 0.694879f;	val_dir[4698*3 + 2] = 0.534522f;
+ 	val_dir[4699*3 + 0] = 0.505276f;	val_dir[4699*3 + 1] = 0.718024f;	val_dir[4699*3 + 2] = 0.478683f;
+ 	val_dir[4700*3 + 0] = 0.527046f;	val_dir[4700*3 + 1] = 0.737865f;	val_dir[4700*3 + 2] = 0.421637f;
+ 	val_dir[4701*3 + 0] = 0.546238f;	val_dir[4701*3 + 1] = 0.754329f;	val_dir[4701*3 + 2] = 0.364159f;
+ 	val_dir[4702*3 + 0] = 0.562809f;	val_dir[4702*3 + 1] = 0.767467f;	val_dir[4702*3 + 2] = 0.306987f;
+ 	val_dir[4703*3 + 0] = 0.576805f;	val_dir[4703*3 + 1] = 0.777433f;	val_dir[4703*3 + 2] = 0.250785f;
+ 	val_dir[4704*3 + 0] = 0.588348f;	val_dir[4704*3 + 1] = 0.784465f;	val_dir[4704*3 + 2] = 0.196116f;
+ 	val_dir[4705*3 + 0] = 0.597614f;	val_dir[4705*3 + 1] = 0.788851f;	val_dir[4705*3 + 2] = 0.143427f;
+ 	val_dir[4706*3 + 0] = 0.604815f;	val_dir[4706*3 + 1] = 0.790912f;	val_dir[4706*3 + 2] = 0.093048f;
+ 	val_dir[4707*3 + 0] = 0.610179f;	val_dir[4707*3 + 1] = 0.790973f;	val_dir[4707*3 + 2] = 0.045198f;
+ 	val_dir[4708*3 + 0] = 0.613941f;	val_dir[4708*3 + 1] = 0.789352f;	val_dir[4708*3 + 2] = 0.0f;
+ 	val_dir[4709*3 + 0] = -0.799803f;	val_dir[4709*3 + 1] = -0.599852f;	val_dir[4709*3 + 2] = 0.022217f;
+ 	val_dir[4710*3 + 0] = -0.800850f;	val_dir[4710*3 + 1] = -0.594917f;	val_dir[4710*3 + 2] = 0.068644f;
+ 	val_dir[4711*3 + 0] = -0.800055f;	val_dir[4711*3 + 1] = -0.588276f;	val_dir[4711*3 + 2] = 0.117655f;
+ 	val_dir[4712*3 + 0] = -0.797092f;	val_dir[4712*3 + 1] = -0.579703f;	val_dir[4712*3 + 2] = 0.169080f;
+ 	val_dir[4713*3 + 0] = -0.791633f;	val_dir[4713*3 + 1] = -0.568986f;	val_dir[4713*3 + 2] = 0.222647f;
+ 	val_dir[4714*3 + 0] = -0.783368f;	val_dir[4714*3 + 1] = -0.555939f;	val_dir[4714*3 + 2] = 0.277969f;
+ 	val_dir[4715*3 + 0] = -0.772027f;	val_dir[4715*3 + 1] = -0.540419f;	val_dir[4715*3 + 2] = 0.334545f;
+ 	val_dir[4716*3 + 0] = -0.757410f;	val_dir[4716*3 + 1] = -0.522352f;	val_dir[4716*3 + 2] = 0.391764f;
+ 	val_dir[4717*3 + 0] = -0.739407f;	val_dir[4717*3 + 1] = -0.501740f;	val_dir[4717*3 + 2] = 0.448926f;
+ 	val_dir[4718*3 + 0] = -0.718024f;	val_dir[4718*3 + 1] = -0.478683f;	val_dir[4718*3 + 2] = 0.505276f;
+ 	val_dir[4719*3 + 0] = -0.693395f;	val_dir[4719*3 + 1] = -0.453374f;	val_dir[4719*3 + 2] = 0.560050f;
+ 	val_dir[4720*3 + 0] = -0.665780f;	val_dir[4720*3 + 1] = -0.426099f;	val_dir[4720*3 + 2] = 0.612517f;
+ 	val_dir[4721*3 + 0] = -0.635553f;	val_dir[4721*3 + 1] = -0.397220f;	val_dir[4721*3 + 2] = 0.662034f;
+ 	val_dir[4722*3 + 0] = -0.603178f;	val_dir[4722*3 + 1] = -0.367152f;	val_dir[4722*3 + 2] = 0.708079f;
+ 	val_dir[4723*3 + 0] = -0.569177f;	val_dir[4723*3 + 1] = -0.336332f;	val_dir[4723*3 + 2] = 0.750279f;
+ 	val_dir[4724*3 + 0] = -0.534090f;	val_dir[4724*3 + 1] = -0.305194f;	val_dir[4724*3 + 2] = 0.788419f;
+ 	val_dir[4725*3 + 0] = -0.498445f;	val_dir[4725*3 + 1] = -0.274145f;	val_dir[4725*3 + 2] = 0.822434f;
+ 	val_dir[4726*3 + 0] = -0.462727f;	val_dir[4726*3 + 1] = -0.243541f;	val_dir[4726*3 + 2] = 0.852392f;
+ 	val_dir[4727*3 + 0] = -0.427362f;	val_dir[4727*3 + 1] = -0.213681f;	val_dir[4727*3 + 2] = 0.878466f;
+ 	val_dir[4728*3 + 0] = -0.392703f;	val_dir[4728*3 + 1] = -0.184801f;	val_dir[4728*3 + 2] = 0.900907f;
+ 	val_dir[4729*3 + 0] = -0.359030f;	val_dir[4729*3 + 1] = -0.157075f;	val_dir[4729*3 + 2] = 0.920014f;
+ 	val_dir[4730*3 + 0] = -0.326550f;	val_dir[4730*3 + 1] = -0.130620f;	val_dir[4730*3 + 2] = 0.936111f;
+ 	val_dir[4731*3 + 0] = -0.295409f;	val_dir[4731*3 + 1] = -0.105503f;	val_dir[4731*3 + 2] = 0.949528f;
+ 	val_dir[4732*3 + 0] = -0.265694f;	val_dir[4732*3 + 1] = -0.081752f;	val_dir[4732*3 + 2] = 0.960585f;
+ 	val_dir[4733*3 + 0] = -0.237449f;	val_dir[4733*3 + 1] = -0.059362f;	val_dir[4733*3 + 2] = 0.969584f;
+ 	val_dir[4734*3 + 0] = -0.210683f;	val_dir[4734*3 + 1] = -0.038306f;	val_dir[4734*3 + 2] = 0.976804f;
+ 	val_dir[4735*3 + 0] = -0.185376f;	val_dir[4735*3 + 1] = -0.018538f;	val_dir[4735*3 + 2] = 0.982493f;
+ 	val_dir[4736*3 + 0] = -0.161489f;	val_dir[4736*3 + 1] = 0.0f;	val_dir[4736*3 + 2] = 0.986875f;
+ 	val_dir[4737*3 + 0] = -0.143917f;	val_dir[4737*3 + 1] = 0.017990f;	val_dir[4737*3 + 2] = 0.989426f;
+ 	val_dir[4738*3 + 0] = -0.126172f;	val_dir[4738*3 + 1] = 0.036049f;	val_dir[4738*3 + 2] = 0.991353f;
+ 	val_dir[4739*3 + 0] = -0.108288f;	val_dir[4739*3 + 1] = 0.054144f;	val_dir[4739*3 + 2] = 0.992644f;
+ 	val_dir[4740*3 + 0] = -0.090299f;	val_dir[4740*3 + 1] = 0.072239f;	val_dir[4740*3 + 2] = 0.993291f;
+ 	val_dir[4741*3 + 0] = -0.072239f;	val_dir[4741*3 + 1] = 0.090299f;	val_dir[4741*3 + 2] = 0.993291f;
+ 	val_dir[4742*3 + 0] = -0.054144f;	val_dir[4742*3 + 1] = 0.108288f;	val_dir[4742*3 + 2] = 0.992644f;
+ 	val_dir[4743*3 + 0] = -0.036049f;	val_dir[4743*3 + 1] = 0.126172f;	val_dir[4743*3 + 2] = 0.991353f;
+ 	val_dir[4744*3 + 0] = -0.017990f;	val_dir[4744*3 + 1] = 0.143917f;	val_dir[4744*3 + 2] = 0.989426f;
+ 	val_dir[4745*3 + 0] = 0.0f;	val_dir[4745*3 + 1] = 0.161489f;	val_dir[4745*3 + 2] = 0.986875f;
+ 	val_dir[4746*3 + 0] = 0.018538f;	val_dir[4746*3 + 1] = 0.185376f;	val_dir[4746*3 + 2] = 0.982493f;
+ 	val_dir[4747*3 + 0] = 0.038306f;	val_dir[4747*3 + 1] = 0.210683f;	val_dir[4747*3 + 2] = 0.976804f;
+ 	val_dir[4748*3 + 0] = 0.059362f;	val_dir[4748*3 + 1] = 0.237449f;	val_dir[4748*3 + 2] = 0.969584f;
+ 	val_dir[4749*3 + 0] = 0.081752f;	val_dir[4749*3 + 1] = 0.265694f;	val_dir[4749*3 + 2] = 0.960585f;
+ 	val_dir[4750*3 + 0] = 0.105503f;	val_dir[4750*3 + 1] = 0.295409f;	val_dir[4750*3 + 2] = 0.949528f;
+ 	val_dir[4751*3 + 0] = 0.130620f;	val_dir[4751*3 + 1] = 0.326550f;	val_dir[4751*3 + 2] = 0.936111f;
+ 	val_dir[4752*3 + 0] = 0.157075f;	val_dir[4752*3 + 1] = 0.359030f;	val_dir[4752*3 + 2] = 0.920014f;
+ 	val_dir[4753*3 + 0] = 0.184801f;	val_dir[4753*3 + 1] = 0.392703f;	val_dir[4753*3 + 2] = 0.900907f;
+ 	val_dir[4754*3 + 0] = 0.213681f;	val_dir[4754*3 + 1] = 0.427362f;	val_dir[4754*3 + 2] = 0.878466f;
+ 	val_dir[4755*3 + 0] = 0.243541f;	val_dir[4755*3 + 1] = 0.462727f;	val_dir[4755*3 + 2] = 0.852392f;
+ 	val_dir[4756*3 + 0] = 0.274145f;	val_dir[4756*3 + 1] = 0.498445f;	val_dir[4756*3 + 2] = 0.822434f;
+ 	val_dir[4757*3 + 0] = 0.305194f;	val_dir[4757*3 + 1] = 0.534090f;	val_dir[4757*3 + 2] = 0.788419f;
+ 	val_dir[4758*3 + 0] = 0.336332f;	val_dir[4758*3 + 1] = 0.569177f;	val_dir[4758*3 + 2] = 0.750279f;
+ 	val_dir[4759*3 + 0] = 0.367152f;	val_dir[4759*3 + 1] = 0.603178f;	val_dir[4759*3 + 2] = 0.708079f;
+ 	val_dir[4760*3 + 0] = 0.397220f;	val_dir[4760*3 + 1] = 0.635553f;	val_dir[4760*3 + 2] = 0.662034f;
+ 	val_dir[4761*3 + 0] = 0.426099f;	val_dir[4761*3 + 1] = 0.665780f;	val_dir[4761*3 + 2] = 0.612517f;
+ 	val_dir[4762*3 + 0] = 0.453374f;	val_dir[4762*3 + 1] = 0.693395f;	val_dir[4762*3 + 2] = 0.560050f;
+ 	val_dir[4763*3 + 0] = 0.478683f;	val_dir[4763*3 + 1] = 0.718024f;	val_dir[4763*3 + 2] = 0.505276f;
+ 	val_dir[4764*3 + 0] = 0.501740f;	val_dir[4764*3 + 1] = 0.739407f;	val_dir[4764*3 + 2] = 0.448926f;
+ 	val_dir[4765*3 + 0] = 0.522352f;	val_dir[4765*3 + 1] = 0.757410f;	val_dir[4765*3 + 2] = 0.391764f;
+ 	val_dir[4766*3 + 0] = 0.540419f;	val_dir[4766*3 + 1] = 0.772027f;	val_dir[4766*3 + 2] = 0.334545f;
+ 	val_dir[4767*3 + 0] = 0.555939f;	val_dir[4767*3 + 1] = 0.783368f;	val_dir[4767*3 + 2] = 0.277969f;
+ 	val_dir[4768*3 + 0] = 0.568986f;	val_dir[4768*3 + 1] = 0.791633f;	val_dir[4768*3 + 2] = 0.222647f;
+ 	val_dir[4769*3 + 0] = 0.579703f;	val_dir[4769*3 + 1] = 0.797092f;	val_dir[4769*3 + 2] = 0.169080f;
+ 	val_dir[4770*3 + 0] = 0.588276f;	val_dir[4770*3 + 1] = 0.800055f;	val_dir[4770*3 + 2] = 0.117655f;
+ 	val_dir[4771*3 + 0] = 0.594917f;	val_dir[4771*3 + 1] = 0.800850f;	val_dir[4771*3 + 2] = 0.068644f;
+ 	val_dir[4772*3 + 0] = 0.599852f;	val_dir[4772*3 + 1] = 0.799803f;	val_dir[4772*3 + 2] = 0.022217f;
+ 	val_dir[4773*3 + 0] = -0.807791f;	val_dir[4773*3 + 1] = -0.589469f;	val_dir[4773*3 + 2] = 0.0f;
+ 	val_dir[4774*3 + 0] = -0.809858f;	val_dir[4774*3 + 1] = -0.584898f;	val_dir[4774*3 + 2] = 0.044992f;
+ 	val_dir[4775*3 + 0] = -0.810237f;	val_dir[4775*3 + 1] = -0.578741f;	val_dir[4775*3 + 2] = 0.092599f;
+ 	val_dir[4776*3 + 0] = -0.808608f;	val_dir[4776*3 + 1] = -0.570782f;	val_dir[4776*3 + 2] = 0.142695f;
+ 	val_dir[4777*3 + 0] = -0.804639f;	val_dir[4777*3 + 1] = -0.560809f;	val_dir[4777*3 + 2] = 0.195064f;
+ 	val_dir[4778*3 + 0] = -0.798007f;	val_dir[4778*3 + 1] = -0.548630f;	val_dir[4778*3 + 2] = 0.249377f;
+ 	val_dir[4779*3 + 0] = -0.788419f;	val_dir[4779*3 + 1] = -0.534090f;	val_dir[4779*3 + 2] = 0.305194f;
+ 	val_dir[4780*3 + 0] = -0.775632f;	val_dir[4780*3 + 1] = -0.517088f;	val_dir[4780*3 + 2] = 0.361961f;
+ 	val_dir[4781*3 + 0] = -0.759485f;	val_dir[4781*3 + 1] = -0.497594f;	val_dir[4781*3 + 2] = 0.419026f;
+ 	val_dir[4782*3 + 0] = -0.739923f;	val_dir[4782*3 + 1] = -0.475665f;	val_dir[4782*3 + 2] = 0.475665f;
+ 	val_dir[4783*3 + 0] = -0.717011f;	val_dir[4783*3 + 1] = -0.451451f;	val_dir[4783*3 + 2] = 0.531119f;
+ 	val_dir[4784*3 + 0] = -0.690942f;	val_dir[4784*3 + 1] = -0.425195f;	val_dir[4784*3 + 2] = 0.584643f;
+ 	val_dir[4785*3 + 0] = -0.662034f;	val_dir[4785*3 + 1] = -0.397220f;	val_dir[4785*3 + 2] = 0.635553f;
+ 	val_dir[4786*3 + 0] = -0.630706f;	val_dir[4786*3 + 1] = -0.367912f;	val_dir[4786*3 + 2] = 0.683265f;
+ 	val_dir[4787*3 + 0] = -0.597453f;	val_dir[4787*3 + 1] = -0.337691f;	val_dir[4787*3 + 2] = 0.727334f;
+ 	val_dir[4788*3 + 0] = -0.562809f;	val_dir[4788*3 + 1] = -0.306987f;	val_dir[4788*3 + 2] = 0.767467f;
+ 	val_dir[4789*3 + 0] = -0.527312f;	val_dir[4789*3 + 1] = -0.276211f;	val_dir[4789*3 + 2] = 0.803523f;
+ 	val_dir[4790*3 + 0] = -0.491473f;	val_dir[4790*3 + 1] = -0.245737f;	val_dir[4790*3 + 2] = 0.835504f;
+ 	val_dir[4791*3 + 0] = -0.455752f;	val_dir[4791*3 + 1] = -0.215883f;	val_dir[4791*3 + 2] = 0.863530f;
+ 	val_dir[4792*3 + 0] = -0.420542f;	val_dir[4792*3 + 1] = -0.186908f;	val_dir[4792*3 + 2] = 0.887812f;
+ 	val_dir[4793*3 + 0] = -0.386164f;	val_dir[4793*3 + 1] = -0.159009f;	val_dir[4793*3 + 2] = 0.908622f;
+ 	val_dir[4794*3 + 0] = -0.352865f;	val_dir[4794*3 + 1] = -0.132324f;	val_dir[4794*3 + 2] = 0.926270f;
+ 	val_dir[4795*3 + 0] = -0.320824f;	val_dir[4795*3 + 1] = -0.106941f;	val_dir[4795*3 + 2] = 0.941082f;
+ 	val_dir[4796*3 + 0] = -0.290159f;	val_dir[4796*3 + 1] = -0.082903f;	val_dir[4796*3 + 2] = 0.953381f;
+ 	val_dir[4797*3 + 0] = -0.260941f;	val_dir[4797*3 + 1] = -0.060217f;	val_dir[4797*3 + 2] = 0.963475f;
+ 	val_dir[4798*3 + 0] = -0.233197f;	val_dir[4798*3 + 1] = -0.038866f;	val_dir[4798*3 + 2] = 0.971653f;
+ 	val_dir[4799*3 + 0] = -0.206922f;	val_dir[4799*3 + 1] = -0.018811f;	val_dir[4799*3 + 2] = 0.978177f;
+ 	val_dir[4800*3 + 0] = -0.182089f;	val_dir[4800*3 + 1] = 0.0f;	val_dir[4800*3 + 2] = 0.983282f;
+ 	val_dir[4801*3 + 0] = -0.164372f;	val_dir[4801*3 + 1] = 0.018264f;	val_dir[4801*3 + 2] = 0.986229f;
+ 	val_dir[4802*3 + 0] = -0.146450f;	val_dir[4802*3 + 1] = 0.036613f;	val_dir[4802*3 + 2] = 0.988540f;
+ 	val_dir[4803*3 + 0] = -0.128359f;	val_dir[4803*3 + 1] = 0.055011f;	val_dir[4803*3 + 2] = 0.990201f;
+ 	val_dir[4804*3 + 0] = -0.110133f;	val_dir[4804*3 + 1] = 0.073422f;	val_dir[4804*3 + 2] = 0.991201f;
+ 	val_dir[4805*3 + 0] = -0.091809f;	val_dir[4805*3 + 1] = 0.091809f;	val_dir[4805*3 + 2] = 0.991535f;
+ 	val_dir[4806*3 + 0] = -0.073422f;	val_dir[4806*3 + 1] = 0.110133f;	val_dir[4806*3 + 2] = 0.991201f;
+ 	val_dir[4807*3 + 0] = -0.055011f;	val_dir[4807*3 + 1] = 0.128359f;	val_dir[4807*3 + 2] = 0.990201f;
+ 	val_dir[4808*3 + 0] = -0.036613f;	val_dir[4808*3 + 1] = 0.146450f;	val_dir[4808*3 + 2] = 0.988540f;
+ 	val_dir[4809*3 + 0] = -0.018264f;	val_dir[4809*3 + 1] = 0.164372f;	val_dir[4809*3 + 2] = 0.986229f;
+ 	val_dir[4810*3 + 0] = 0.0f;	val_dir[4810*3 + 1] = 0.182089f;	val_dir[4810*3 + 2] = 0.983282f;
+ 	val_dir[4811*3 + 0] = 0.018811f;	val_dir[4811*3 + 1] = 0.206922f;	val_dir[4811*3 + 2] = 0.978177f;
+ 	val_dir[4812*3 + 0] = 0.038866f;	val_dir[4812*3 + 1] = 0.233197f;	val_dir[4812*3 + 2] = 0.971653f;
+ 	val_dir[4813*3 + 0] = 0.060217f;	val_dir[4813*3 + 1] = 0.260941f;	val_dir[4813*3 + 2] = 0.963475f;
+ 	val_dir[4814*3 + 0] = 0.082903f;	val_dir[4814*3 + 1] = 0.290159f;	val_dir[4814*3 + 2] = 0.953381f;
+ 	val_dir[4815*3 + 0] = 0.106941f;	val_dir[4815*3 + 1] = 0.320824f;	val_dir[4815*3 + 2] = 0.941082f;
+ 	val_dir[4816*3 + 0] = 0.132324f;	val_dir[4816*3 + 1] = 0.352865f;	val_dir[4816*3 + 2] = 0.926270f;
+ 	val_dir[4817*3 + 0] = 0.159009f;	val_dir[4817*3 + 1] = 0.386164f;	val_dir[4817*3 + 2] = 0.908622f;
+ 	val_dir[4818*3 + 0] = 0.186908f;	val_dir[4818*3 + 1] = 0.420542f;	val_dir[4818*3 + 2] = 0.887812f;
+ 	val_dir[4819*3 + 0] = 0.215883f;	val_dir[4819*3 + 1] = 0.455752f;	val_dir[4819*3 + 2] = 0.863530f;
+ 	val_dir[4820*3 + 0] = 0.245737f;	val_dir[4820*3 + 1] = 0.491473f;	val_dir[4820*3 + 2] = 0.835504f;
+ 	val_dir[4821*3 + 0] = 0.276211f;	val_dir[4821*3 + 1] = 0.527312f;	val_dir[4821*3 + 2] = 0.803523f;
+ 	val_dir[4822*3 + 0] = 0.306987f;	val_dir[4822*3 + 1] = 0.562809f;	val_dir[4822*3 + 2] = 0.767467f;
+ 	val_dir[4823*3 + 0] = 0.337691f;	val_dir[4823*3 + 1] = 0.597453f;	val_dir[4823*3 + 2] = 0.727334f;
+ 	val_dir[4824*3 + 0] = 0.367912f;	val_dir[4824*3 + 1] = 0.630706f;	val_dir[4824*3 + 2] = 0.683265f;
+ 	val_dir[4825*3 + 0] = 0.397220f;	val_dir[4825*3 + 1] = 0.662034f;	val_dir[4825*3 + 2] = 0.635553f;
+ 	val_dir[4826*3 + 0] = 0.425195f;	val_dir[4826*3 + 1] = 0.690942f;	val_dir[4826*3 + 2] = 0.584643f;
+ 	val_dir[4827*3 + 0] = 0.451451f;	val_dir[4827*3 + 1] = 0.717011f;	val_dir[4827*3 + 2] = 0.531119f;
+ 	val_dir[4828*3 + 0] = 0.475665f;	val_dir[4828*3 + 1] = 0.739923f;	val_dir[4828*3 + 2] = 0.475665f;
+ 	val_dir[4829*3 + 0] = 0.497594f;	val_dir[4829*3 + 1] = 0.759485f;	val_dir[4829*3 + 2] = 0.419026f;
+ 	val_dir[4830*3 + 0] = 0.517088f;	val_dir[4830*3 + 1] = 0.775632f;	val_dir[4830*3 + 2] = 0.361961f;
+ 	val_dir[4831*3 + 0] = 0.534090f;	val_dir[4831*3 + 1] = 0.788419f;	val_dir[4831*3 + 2] = 0.305194f;
+ 	val_dir[4832*3 + 0] = 0.548630f;	val_dir[4832*3 + 1] = 0.798007f;	val_dir[4832*3 + 2] = 0.249377f;
+ 	val_dir[4833*3 + 0] = 0.560809f;	val_dir[4833*3 + 1] = 0.804639f;	val_dir[4833*3 + 2] = 0.195064f;
+ 	val_dir[4834*3 + 0] = 0.570782f;	val_dir[4834*3 + 1] = 0.808608f;	val_dir[4834*3 + 2] = 0.142695f;
+ 	val_dir[4835*3 + 0] = 0.578741f;	val_dir[4835*3 + 1] = 0.810237f;	val_dir[4835*3 + 2] = 0.092599f;
+ 	val_dir[4836*3 + 0] = 0.584898f;	val_dir[4836*3 + 1] = 0.809858f;	val_dir[4836*3 + 2] = 0.044992f;
+ 	val_dir[4837*3 + 0] = 0.589469f;	val_dir[4837*3 + 1] = 0.807791f;	val_dir[4837*3 + 2] = 0.0f;
+ 	val_dir[4838*3 + 0] = -0.817992f;	val_dir[4838*3 + 1] = -0.574805f;	val_dir[4838*3 + 2] = 0.022108f;
+ 	val_dir[4839*3 + 0] = -0.819453f;	val_dir[4839*3 + 1] = -0.569064f;	val_dir[4839*3 + 2] = 0.068288f;
+ 	val_dir[4840*3 + 0] = -0.819064f;	val_dir[4840*3 + 1] = -0.561644f;	val_dir[4840*3 + 2] = 0.117009f;
+ 	val_dir[4841*3 + 0] = -0.816497f;	val_dir[4841*3 + 1] = -0.552336f;	val_dir[4841*3 + 2] = 0.168102f;
+ 	val_dir[4842*3 + 0] = -0.811421f;	val_dir[4842*3 + 1] = -0.540947f;	val_dir[4842*3 + 2] = 0.221297f;
+ 	val_dir[4843*3 + 0] = -0.803523f;	val_dir[4843*3 + 1] = -0.527312f;	val_dir[4843*3 + 2] = 0.276211f;
+ 	val_dir[4844*3 + 0] = -0.792530f;	val_dir[4844*3 + 1] = -0.511310f;	val_dir[4844*3 + 2] = 0.332352f;
+ 	val_dir[4845*3 + 0] = -0.778237f;	val_dir[4845*3 + 1] = -0.492883f;	val_dir[4845*3 + 2] = 0.389118f;
+ 	val_dir[4846*3 + 0] = -0.760529f;	val_dir[4846*3 + 1] = -0.472053f;	val_dir[4846*3 + 2] = 0.445827f;
+ 	val_dir[4847*3 + 0] = -0.739407f;	val_dir[4847*3 + 1] = -0.448926f;	val_dir[4847*3 + 2] = 0.501740f;
+ 	val_dir[4848*3 + 0] = -0.714997f;	val_dir[4848*3 + 1] = -0.423702f;	val_dir[4848*3 + 2] = 0.556108f;
+ 	val_dir[4849*3 + 0] = -0.687552f;	val_dir[4849*3 + 1] = -0.396664f;	val_dir[4849*3 + 2] = 0.608219f;
+ 	val_dir[4850*3 + 0] = -0.657440f;	val_dir[4850*3 + 1] = -0.368166f;	val_dir[4850*3 + 2] = 0.657440f;
+ 	val_dir[4851*3 + 0] = -0.625119f;	val_dir[4851*3 + 1] = -0.338606f;	val_dir[4851*3 + 2] = 0.703259f;
+ 	val_dir[4852*3 + 0] = -0.591105f;	val_dir[4852*3 + 1] = -0.308403f;	val_dir[4852*3 + 2] = 0.745307f;
+ 	val_dir[4853*3 + 0] = -0.555939f;	val_dir[4853*3 + 1] = -0.277969f;	val_dir[4853*3 + 2] = 0.783368f;
+ 	val_dir[4854*3 + 0] = -0.520146f;	val_dir[4854*3 + 1] = -0.247689f;	val_dir[4854*3 + 2] = 0.817373f;
+ 	val_dir[4855*3 + 0] = -0.484217f;	val_dir[4855*3 + 1] = -0.217898f;	val_dir[4855*3 + 2] = 0.847381f;
+ 	val_dir[4856*3 + 0] = -0.448583f;	val_dir[4856*3 + 1] = -0.188877f;	val_dir[4856*3 + 2] = 0.873555f;
+ 	val_dir[4857*3 + 0] = -0.413602f;	val_dir[4857*3 + 1] = -0.160845f;	val_dir[4857*3 + 2] = 0.896137f;
+ 	val_dir[4858*3 + 0] = -0.379563f;	val_dir[4858*3 + 1] = -0.133963f;	val_dir[4858*3 + 2] = 0.915416f;
+ 	val_dir[4859*3 + 0] = -0.346681f;	val_dir[4859*3 + 1] = -0.108338f;	val_dir[4859*3 + 2] = 0.931705f;
+ 	val_dir[4860*3 + 0] = -0.315109f;	val_dir[4860*3 + 1] = -0.084029f;	val_dir[4860*3 + 2] = 0.945328f;
+ 	val_dir[4861*3 + 0] = -0.284944f;	val_dir[4861*3 + 1] = -0.061059f;	val_dir[4861*3 + 2] = 0.956597f;
+ 	val_dir[4862*3 + 0] = -0.256235f;	val_dir[4862*3 + 1] = -0.039421f;	val_dir[4862*3 + 2] = 0.965810f;
+ 	val_dir[4863*3 + 0] = -0.228998f;	val_dir[4863*3 + 1] = -0.019083f;	val_dir[4863*3 + 2] = 0.973240f;
+ 	val_dir[4864*3 + 0] = -0.203216f;	val_dir[4864*3 + 1] = 0.0f;	val_dir[4864*3 + 2] = 0.979134f;
+ 	val_dir[4865*3 + 0] = -0.185376f;	val_dir[4865*3 + 1] = 0.018538f;	val_dir[4865*3 + 2] = 0.982493f;
+ 	val_dir[4866*3 + 0] = -0.167299f;	val_dir[4866*3 + 1] = 0.037178f;	val_dir[4866*3 + 2] = 0.985205f;
+ 	val_dir[4867*3 + 0] = -0.149019f;	val_dir[4867*3 + 1] = 0.055882f;	val_dir[4867*3 + 2] = 0.987254f;
+ 	val_dir[4868*3 + 0] = -0.130573f;	val_dir[4868*3 + 1] = 0.074613f;	val_dir[4868*3 + 2] = 0.988627f;
+ 	val_dir[4869*3 + 0] = -0.111998f;	val_dir[4869*3 + 1] = 0.093332f;	val_dir[4869*3 + 2] = 0.989316f;
+ 	val_dir[4870*3 + 0] = -0.093332f;	val_dir[4870*3 + 1] = 0.111998f;	val_dir[4870*3 + 2] = 0.989316f;
+ 	val_dir[4871*3 + 0] = -0.074613f;	val_dir[4871*3 + 1] = 0.130573f;	val_dir[4871*3 + 2] = 0.988627f;
+ 	val_dir[4872*3 + 0] = -0.055882f;	val_dir[4872*3 + 1] = 0.149019f;	val_dir[4872*3 + 2] = 0.987254f;
+ 	val_dir[4873*3 + 0] = -0.037178f;	val_dir[4873*3 + 1] = 0.167299f;	val_dir[4873*3 + 2] = 0.985205f;
+ 	val_dir[4874*3 + 0] = -0.018538f;	val_dir[4874*3 + 1] = 0.185376f;	val_dir[4874*3 + 2] = 0.982493f;
+ 	val_dir[4875*3 + 0] = 0.0f;	val_dir[4875*3 + 1] = 0.203216f;	val_dir[4875*3 + 2] = 0.979134f;
+ 	val_dir[4876*3 + 0] = 0.019083f;	val_dir[4876*3 + 1] = 0.228998f;	val_dir[4876*3 + 2] = 0.973240f;
+ 	val_dir[4877*3 + 0] = 0.039421f;	val_dir[4877*3 + 1] = 0.256235f;	val_dir[4877*3 + 2] = 0.965810f;
+ 	val_dir[4878*3 + 0] = 0.061059f;	val_dir[4878*3 + 1] = 0.284944f;	val_dir[4878*3 + 2] = 0.956597f;
+ 	val_dir[4879*3 + 0] = 0.084029f;	val_dir[4879*3 + 1] = 0.315109f;	val_dir[4879*3 + 2] = 0.945328f;
+ 	val_dir[4880*3 + 0] = 0.108338f;	val_dir[4880*3 + 1] = 0.346681f;	val_dir[4880*3 + 2] = 0.931705f;
+ 	val_dir[4881*3 + 0] = 0.133963f;	val_dir[4881*3 + 1] = 0.379563f;	val_dir[4881*3 + 2] = 0.915416f;
+ 	val_dir[4882*3 + 0] = 0.160845f;	val_dir[4882*3 + 1] = 0.413602f;	val_dir[4882*3 + 2] = 0.896137f;
+ 	val_dir[4883*3 + 0] = 0.188877f;	val_dir[4883*3 + 1] = 0.448583f;	val_dir[4883*3 + 2] = 0.873555f;
+ 	val_dir[4884*3 + 0] = 0.217898f;	val_dir[4884*3 + 1] = 0.484217f;	val_dir[4884*3 + 2] = 0.847381f;
+ 	val_dir[4885*3 + 0] = 0.247689f;	val_dir[4885*3 + 1] = 0.520146f;	val_dir[4885*3 + 2] = 0.817373f;
+ 	val_dir[4886*3 + 0] = 0.277969f;	val_dir[4886*3 + 1] = 0.555939f;	val_dir[4886*3 + 2] = 0.783368f;
+ 	val_dir[4887*3 + 0] = 0.308403f;	val_dir[4887*3 + 1] = 0.591105f;	val_dir[4887*3 + 2] = 0.745307f;
+ 	val_dir[4888*3 + 0] = 0.338606f;	val_dir[4888*3 + 1] = 0.625119f;	val_dir[4888*3 + 2] = 0.703259f;
+ 	val_dir[4889*3 + 0] = 0.368166f;	val_dir[4889*3 + 1] = 0.657440f;	val_dir[4889*3 + 2] = 0.657440f;
+ 	val_dir[4890*3 + 0] = 0.396664f;	val_dir[4890*3 + 1] = 0.687552f;	val_dir[4890*3 + 2] = 0.608219f;
+ 	val_dir[4891*3 + 0] = 0.423702f;	val_dir[4891*3 + 1] = 0.714997f;	val_dir[4891*3 + 2] = 0.556108f;
+ 	val_dir[4892*3 + 0] = 0.448926f;	val_dir[4892*3 + 1] = 0.739407f;	val_dir[4892*3 + 2] = 0.501740f;
+ 	val_dir[4893*3 + 0] = 0.472053f;	val_dir[4893*3 + 1] = 0.760529f;	val_dir[4893*3 + 2] = 0.445827f;
+ 	val_dir[4894*3 + 0] = 0.492883f;	val_dir[4894*3 + 1] = 0.778237f;	val_dir[4894*3 + 2] = 0.389118f;
+ 	val_dir[4895*3 + 0] = 0.511310f;	val_dir[4895*3 + 1] = 0.792530f;	val_dir[4895*3 + 2] = 0.332352f;
+ 	val_dir[4896*3 + 0] = 0.527312f;	val_dir[4896*3 + 1] = 0.803523f;	val_dir[4896*3 + 2] = 0.276211f;
+ 	val_dir[4897*3 + 0] = 0.540947f;	val_dir[4897*3 + 1] = 0.811421f;	val_dir[4897*3 + 2] = 0.221297f;
+ 	val_dir[4898*3 + 0] = 0.552336f;	val_dir[4898*3 + 1] = 0.816497f;	val_dir[4898*3 + 2] = 0.168102f;
+ 	val_dir[4899*3 + 0] = 0.561644f;	val_dir[4899*3 + 1] = 0.819064f;	val_dir[4899*3 + 2] = 0.117009f;
+ 	val_dir[4900*3 + 0] = 0.569064f;	val_dir[4900*3 + 1] = 0.819453f;	val_dir[4900*3 + 2] = 0.068288f;
+ 	val_dir[4901*3 + 0] = 0.574805f;	val_dir[4901*3 + 1] = 0.817992f;	val_dir[4901*3 + 2] = 0.022108f;
+ 	val_dir[4902*3 + 0] = -0.825307f;	val_dir[4902*3 + 1] = -0.564684f;	val_dir[4902*3 + 2] = 0.0f;
+ 	val_dir[4903*3 + 0] = -0.827759f;	val_dir[4903*3 + 1] = -0.559297f;	val_dir[4903*3 + 2] = 0.044744f;
+ 	val_dir[4904*3 + 0] = -0.828517f;	val_dir[4904*3 + 1] = -0.552345f;	val_dir[4904*3 + 2] = 0.092057f;
+ 	val_dir[4905*3 + 0] = -0.827259f;	val_dir[4905*3 + 1] = -0.543627f;	val_dir[4905*3 + 2] = 0.141816f;
+ 	val_dir[4906*3 + 0] = -0.823653f;	val_dir[4906*3 + 1] = -0.532952f;	val_dir[4906*3 + 2] = 0.193801f;
+ 	val_dir[4907*3 + 0] = -0.817373f;	val_dir[4907*3 + 1] = -0.520146f;	val_dir[4907*3 + 2] = 0.247689f;
+ 	val_dir[4908*3 + 0] = -0.808122f;	val_dir[4908*3 + 1] = -0.505076f;	val_dir[4908*3 + 2] = 0.303046f;
+ 	val_dir[4909*3 + 0] = -0.795657f;	val_dir[4909*3 + 1] = -0.487661f;	val_dir[4909*3 + 2] = 0.359329f;
+ 	val_dir[4910*3 + 0] = -0.779813f;	val_dir[4910*3 + 1] = -0.467888f;	val_dir[4910*3 + 2] = 0.41590f;
+ 	val_dir[4911*3 + 0] = -0.760529f;	val_dir[4911*3 + 1] = -0.445827f;	val_dir[4911*3 + 2] = 0.472053f;
+ 	val_dir[4912*3 + 0] = -0.737865f;	val_dir[4912*3 + 1] = -0.421637f;	val_dir[4912*3 + 2] = 0.527046f;
+ 	val_dir[4913*3 + 0] = -0.712007f;	val_dir[4913*3 + 1] = -0.395559f;	val_dir[4913*3 + 2] = 0.580154f;
+ 	val_dir[4914*3 + 0] = -0.683265f;	val_dir[4914*3 + 1] = -0.367912f;	val_dir[4914*3 + 2] = 0.630706f;
+ 	val_dir[4915*3 + 0] = -0.652051f;	val_dir[4915*3 + 1] = -0.339066f;	val_dir[4915*3 + 2] = 0.678133f;
+ 	val_dir[4916*3 + 0] = -0.618853f;	val_dir[4916*3 + 1] = -0.309426f;	val_dir[4916*3 + 2] = 0.721995f;
+ 	val_dir[4917*3 + 0] = -0.584201f;	val_dir[4917*3 + 1] = -0.27940f;	val_dir[4917*3 + 2] = 0.762001f;
+ 	val_dir[4918*3 + 0] = -0.548630f;	val_dir[4918*3 + 1] = -0.249377f;	val_dir[4918*3 + 2] = 0.798007f;
+ 	val_dir[4919*3 + 0] = -0.512653f;	val_dir[4919*3 + 1] = -0.219708f;	val_dir[4919*3 + 2] = 0.830009f;
+ 	val_dir[4920*3 + 0] = -0.476731f;	val_dir[4920*3 + 1] = -0.190693f;	val_dir[4920*3 + 2] = 0.858116f;
+ 	val_dir[4921*3 + 0] = -0.441264f;	val_dir[4921*3 + 1] = -0.162571f;	val_dir[4921*3 + 2] = 0.882528f;
+ 	val_dir[4922*3 + 0] = -0.406579f;	val_dir[4922*3 + 1] = -0.135526f;	val_dir[4922*3 + 2] = 0.903508f;
+ 	val_dir[4923*3 + 0] = -0.372929f;	val_dir[4923*3 + 1] = -0.109685f;	val_dir[4923*3 + 2] = 0.921354f;
+ 	val_dir[4924*3 + 0] = -0.340503f;	val_dir[4924*3 + 1] = -0.085126f;	val_dir[4924*3 + 2] = 0.936382f;
+ 	val_dir[4925*3 + 0] = -0.309426f;	val_dir[4925*3 + 1] = -0.061885f;	val_dir[4925*3 + 2] = 0.948908f;
+ 	val_dir[4926*3 + 0] = -0.279776f;	val_dir[4926*3 + 1] = -0.039968f;	val_dir[4926*3 + 2] = 0.959233f;
+ 	val_dir[4927*3 + 0] = -0.251587f;	val_dir[4927*3 + 1] = -0.019353f;	val_dir[4927*3 + 2] = 0.967641f;
+ 	val_dir[4928*3 + 0] = -0.224860f;	val_dir[4928*3 + 1] = 0.0f;	val_dir[4928*3 + 2] = 0.974391f;
+ 	val_dir[4929*3 + 0] = -0.206922f;	val_dir[4929*3 + 1] = 0.018811f;	val_dir[4929*3 + 2] = 0.978177f;
+ 	val_dir[4930*3 + 0] = -0.188713f;	val_dir[4930*3 + 1] = 0.037743f;	val_dir[4930*3 + 2] = 0.981307f;
+ 	val_dir[4931*3 + 0] = -0.170267f;	val_dir[4931*3 + 1] = 0.056756f;	val_dir[4931*3 + 2] = 0.983762f;
+ 	val_dir[4932*3 + 0] = -0.151620f;	val_dir[4932*3 + 1] = 0.075810f;	val_dir[4932*3 + 2] = 0.985527f;
+ 	val_dir[4933*3 + 0] = -0.132810f;	val_dir[4933*3 + 1] = 0.094865f;	val_dir[4933*3 + 2] = 0.986591f;
+ 	val_dir[4934*3 + 0] = -0.113878f;	val_dir[4934*3 + 1] = 0.113878f;	val_dir[4934*3 + 2] = 0.986947f;
+ 	val_dir[4935*3 + 0] = -0.094865f;	val_dir[4935*3 + 1] = 0.132810f;	val_dir[4935*3 + 2] = 0.986591f;
+ 	val_dir[4936*3 + 0] = -0.075810f;	val_dir[4936*3 + 1] = 0.151620f;	val_dir[4936*3 + 2] = 0.985527f;
+ 	val_dir[4937*3 + 0] = -0.056756f;	val_dir[4937*3 + 1] = 0.170267f;	val_dir[4937*3 + 2] = 0.983762f;
+ 	val_dir[4938*3 + 0] = -0.037743f;	val_dir[4938*3 + 1] = 0.188713f;	val_dir[4938*3 + 2] = 0.981307f;
+ 	val_dir[4939*3 + 0] = -0.018811f;	val_dir[4939*3 + 1] = 0.206922f;	val_dir[4939*3 + 2] = 0.978177f;
+ 	val_dir[4940*3 + 0] = 0.0f;	val_dir[4940*3 + 1] = 0.224860f;	val_dir[4940*3 + 2] = 0.974391f;
+ 	val_dir[4941*3 + 0] = 0.019353f;	val_dir[4941*3 + 1] = 0.251587f;	val_dir[4941*3 + 2] = 0.967641f;
+ 	val_dir[4942*3 + 0] = 0.039968f;	val_dir[4942*3 + 1] = 0.279776f;	val_dir[4942*3 + 2] = 0.959233f;
+ 	val_dir[4943*3 + 0] = 0.061885f;	val_dir[4943*3 + 1] = 0.309426f;	val_dir[4943*3 + 2] = 0.948908f;
+ 	val_dir[4944*3 + 0] = 0.085126f;	val_dir[4944*3 + 1] = 0.340503f;	val_dir[4944*3 + 2] = 0.936382f;
+ 	val_dir[4945*3 + 0] = 0.109685f;	val_dir[4945*3 + 1] = 0.372929f;	val_dir[4945*3 + 2] = 0.921354f;
+ 	val_dir[4946*3 + 0] = 0.135526f;	val_dir[4946*3 + 1] = 0.406579f;	val_dir[4946*3 + 2] = 0.903508f;
+ 	val_dir[4947*3 + 0] = 0.162571f;	val_dir[4947*3 + 1] = 0.441264f;	val_dir[4947*3 + 2] = 0.882528f;
+ 	val_dir[4948*3 + 0] = 0.190693f;	val_dir[4948*3 + 1] = 0.476731f;	val_dir[4948*3 + 2] = 0.858116f;
+ 	val_dir[4949*3 + 0] = 0.219708f;	val_dir[4949*3 + 1] = 0.512653f;	val_dir[4949*3 + 2] = 0.830009f;
+ 	val_dir[4950*3 + 0] = 0.249377f;	val_dir[4950*3 + 1] = 0.548630f;	val_dir[4950*3 + 2] = 0.798007f;
+ 	val_dir[4951*3 + 0] = 0.27940f;	val_dir[4951*3 + 1] = 0.584201f;	val_dir[4951*3 + 2] = 0.762001f;
+ 	val_dir[4952*3 + 0] = 0.309426f;	val_dir[4952*3 + 1] = 0.618853f;	val_dir[4952*3 + 2] = 0.721995f;
+ 	val_dir[4953*3 + 0] = 0.339066f;	val_dir[4953*3 + 1] = 0.652051f;	val_dir[4953*3 + 2] = 0.678133f;
+ 	val_dir[4954*3 + 0] = 0.367912f;	val_dir[4954*3 + 1] = 0.683265f;	val_dir[4954*3 + 2] = 0.630706f;
+ 	val_dir[4955*3 + 0] = 0.395559f;	val_dir[4955*3 + 1] = 0.712007f;	val_dir[4955*3 + 2] = 0.580154f;
+ 	val_dir[4956*3 + 0] = 0.421637f;	val_dir[4956*3 + 1] = 0.737865f;	val_dir[4956*3 + 2] = 0.527046f;
+ 	val_dir[4957*3 + 0] = 0.445827f;	val_dir[4957*3 + 1] = 0.760529f;	val_dir[4957*3 + 2] = 0.472053f;
+ 	val_dir[4958*3 + 0] = 0.467888f;	val_dir[4958*3 + 1] = 0.779813f;	val_dir[4958*3 + 2] = 0.41590f;
+ 	val_dir[4959*3 + 0] = 0.487661f;	val_dir[4959*3 + 1] = 0.795657f;	val_dir[4959*3 + 2] = 0.359329f;
+ 	val_dir[4960*3 + 0] = 0.505076f;	val_dir[4960*3 + 1] = 0.808122f;	val_dir[4960*3 + 2] = 0.303046f;
+ 	val_dir[4961*3 + 0] = 0.520146f;	val_dir[4961*3 + 1] = 0.817373f;	val_dir[4961*3 + 2] = 0.247689f;
+ 	val_dir[4962*3 + 0] = 0.532952f;	val_dir[4962*3 + 1] = 0.823653f;	val_dir[4962*3 + 2] = 0.193801f;
+ 	val_dir[4963*3 + 0] = 0.543627f;	val_dir[4963*3 + 1] = 0.827259f;	val_dir[4963*3 + 2] = 0.141816f;
+ 	val_dir[4964*3 + 0] = 0.552345f;	val_dir[4964*3 + 1] = 0.828517f;	val_dir[4964*3 + 2] = 0.092057f;
+ 	val_dir[4965*3 + 0] = 0.559297f;	val_dir[4965*3 + 1] = 0.827759f;	val_dir[4965*3 + 2] = 0.044744f;
+ 	val_dir[4966*3 + 0] = 0.564684f;	val_dir[4966*3 + 1] = 0.825307f;	val_dir[4966*3 + 2] = 0.0f;
+ 	val_dir[4967*3 + 0] = -0.835215f;	val_dir[4967*3 + 1] = -0.549484f;	val_dir[4967*3 + 2] = 0.021979f;
+ 	val_dir[4968*3 + 0] = -0.837027f;	val_dir[4968*3 + 1] = -0.542936f;	val_dir[4968*3 + 2] = 0.067867f;
+ 	val_dir[4969*3 + 0] = -0.836983f;	val_dir[4969*3 + 1] = -0.534739f;	val_dir[4969*3 + 2] = 0.116248f;
+ 	val_dir[4970*3 + 0] = -0.834754f;	val_dir[4970*3 + 1] = -0.524703f;	val_dir[4970*3 + 2] = 0.166951f;
+ 	val_dir[4971*3 + 0] = -0.830009f;	val_dir[4971*3 + 1] = -0.512653f;	val_dir[4971*3 + 2] = 0.219708f;
+ 	val_dir[4972*3 + 0] = -0.822434f;	val_dir[4972*3 + 1] = -0.498445f;	val_dir[4972*3 + 2] = 0.274145f;
+ 	val_dir[4973*3 + 0] = -0.811754f;	val_dir[4973*3 + 1] = -0.481979f;	val_dir[4973*3 + 2] = 0.329775f;
+ 	val_dir[4974*3 + 0] = -0.797762f;	val_dir[4974*3 + 1] = -0.463217f;	val_dir[4974*3 + 2] = 0.386014f;
+ 	val_dir[4975*3 + 0] = -0.780340f;	val_dir[4975*3 + 1] = -0.442193f;	val_dir[4975*3 + 2] = 0.442193f;
+ 	val_dir[4976*3 + 0] = -0.759485f;	val_dir[4976*3 + 1] = -0.419026f;	val_dir[4976*3 + 2] = 0.497594f;
+ 	val_dir[4977*3 + 0] = -0.735316f;	val_dir[4977*3 + 1] = -0.393919f;	val_dir[4977*3 + 2] = 0.551487f;
+ 	val_dir[4978*3 + 0] = -0.708079f;	val_dir[4978*3 + 1] = -0.367152f;	val_dir[4978*3 + 2] = 0.603178f;
+ 	val_dir[4979*3 + 0] = -0.678133f;	val_dir[4979*3 + 1] = -0.339066f;	val_dir[4979*3 + 2] = 0.652051f;
+ 	val_dir[4980*3 + 0] = -0.645928f;	val_dir[4980*3 + 1] = -0.310045f;	val_dir[4980*3 + 2] = 0.697602f;
+ 	val_dir[4981*3 + 0] = -0.611974f;	val_dir[4981*3 + 1] = -0.280488f;	val_dir[4981*3 + 2] = 0.739469f;
+ 	val_dir[4982*3 + 0] = -0.576805f;	val_dir[4982*3 + 1] = -0.250785f;	val_dir[4982*3 + 2] = 0.777433f;
+ 	val_dir[4983*3 + 0] = -0.540947f;	val_dir[4983*3 + 1] = -0.221297f;	val_dir[4983*3 + 2] = 0.811421f;
+ 	val_dir[4984*3 + 0] = -0.504889f;	val_dir[4984*3 + 1] = -0.192339f;	val_dir[4984*3 + 2] = 0.841482f;
+ 	val_dir[4985*3 + 0] = -0.469065f;	val_dir[4985*3 + 1] = -0.164173f;	val_dir[4985*3 + 2] = 0.867770f;
+ 	val_dir[4986*3 + 0] = -0.433840f;	val_dir[4986*3 + 1] = -0.137002f;	val_dir[4986*3 + 2] = 0.890513f;
+ 	val_dir[4987*3 + 0] = -0.399507f;	val_dir[4987*3 + 1] = -0.110974f;	val_dir[4987*3 + 2] = 0.909988f;
+ 	val_dir[4988*3 + 0] = -0.366291f;	val_dir[4988*3 + 1] = -0.086186f;	val_dir[4988*3 + 2] = 0.92650f;
+ 	val_dir[4989*3 + 0] = -0.334351f;	val_dir[4989*3 + 1] = -0.062691f;	val_dir[4989*3 + 2] = 0.940361f;
+ 	val_dir[4990*3 + 0] = -0.303791f;	val_dir[4990*3 + 1] = -0.040505f;	val_dir[4990*3 + 2] = 0.951877f;
+ 	val_dir[4991*3 + 0] = -0.274668f;	val_dir[4991*3 + 1] = -0.019619f;	val_dir[4991*3 + 2] = 0.961339f;
+ 	val_dir[4992*3 + 0] = -0.247004f;	val_dir[4992*3 + 1] = 0.0f;	val_dir[4992*3 + 2] = 0.969015f;
+ 	val_dir[4993*3 + 0] = -0.228998f;	val_dir[4993*3 + 1] = 0.019083f;	val_dir[4993*3 + 2] = 0.973240f;
+ 	val_dir[4994*3 + 0] = -0.210683f;	val_dir[4994*3 + 1] = 0.038306f;	val_dir[4994*3 + 2] = 0.976804f;
+ 	val_dir[4995*3 + 0] = -0.192095f;	val_dir[4995*3 + 1] = 0.057628f;	val_dir[4995*3 + 2] = 0.979683f;
+ 	val_dir[4996*3 + 0] = -0.173269f;	val_dir[4996*3 + 1] = 0.077009f;	val_dir[4996*3 + 2] = 0.981859f;
+ 	val_dir[4997*3 + 0] = -0.154246f;	val_dir[4997*3 + 1] = 0.096404f;	val_dir[4997*3 + 2] = 0.983318f;
+ 	val_dir[4998*3 + 0] = -0.135066f;	val_dir[4998*3 + 1] = 0.115771f;	val_dir[4998*3 + 2] = 0.984050f;
+ 	val_dir[4999*3 + 0] = -0.115771f;	val_dir[4999*3 + 1] = 0.135066f;	val_dir[4999*3 + 2] = 0.984050f;
+ 	val_dir[5000*3 + 0] = -0.096404f;	val_dir[5000*3 + 1] = 0.154246f;	val_dir[5000*3 + 2] = 0.983318f;
+ 	val_dir[5001*3 + 0] = -0.077009f;	val_dir[5001*3 + 1] = 0.173269f;	val_dir[5001*3 + 2] = 0.981859f;
+ 	val_dir[5002*3 + 0] = -0.057628f;	val_dir[5002*3 + 1] = 0.192095f;	val_dir[5002*3 + 2] = 0.979683f;
+ 	val_dir[5003*3 + 0] = -0.038306f;	val_dir[5003*3 + 1] = 0.210683f;	val_dir[5003*3 + 2] = 0.976804f;
+ 	val_dir[5004*3 + 0] = -0.019083f;	val_dir[5004*3 + 1] = 0.228998f;	val_dir[5004*3 + 2] = 0.973240f;
+ 	val_dir[5005*3 + 0] = 0.0f;	val_dir[5005*3 + 1] = 0.247004f;	val_dir[5005*3 + 2] = 0.969015f;
+ 	val_dir[5006*3 + 0] = 0.019619f;	val_dir[5006*3 + 1] = 0.274668f;	val_dir[5006*3 + 2] = 0.961339f;
+ 	val_dir[5007*3 + 0] = 0.040505f;	val_dir[5007*3 + 1] = 0.303791f;	val_dir[5007*3 + 2] = 0.951877f;
+ 	val_dir[5008*3 + 0] = 0.062691f;	val_dir[5008*3 + 1] = 0.334351f;	val_dir[5008*3 + 2] = 0.940361f;
+ 	val_dir[5009*3 + 0] = 0.086186f;	val_dir[5009*3 + 1] = 0.366291f;	val_dir[5009*3 + 2] = 0.92650f;
+ 	val_dir[5010*3 + 0] = 0.110974f;	val_dir[5010*3 + 1] = 0.399507f;	val_dir[5010*3 + 2] = 0.909988f;
+ 	val_dir[5011*3 + 0] = 0.137002f;	val_dir[5011*3 + 1] = 0.433840f;	val_dir[5011*3 + 2] = 0.890513f;
+ 	val_dir[5012*3 + 0] = 0.164173f;	val_dir[5012*3 + 1] = 0.469065f;	val_dir[5012*3 + 2] = 0.867770f;
+ 	val_dir[5013*3 + 0] = 0.192339f;	val_dir[5013*3 + 1] = 0.504889f;	val_dir[5013*3 + 2] = 0.841482f;
+ 	val_dir[5014*3 + 0] = 0.221297f;	val_dir[5014*3 + 1] = 0.540947f;	val_dir[5014*3 + 2] = 0.811421f;
+ 	val_dir[5015*3 + 0] = 0.250785f;	val_dir[5015*3 + 1] = 0.576805f;	val_dir[5015*3 + 2] = 0.777433f;
+ 	val_dir[5016*3 + 0] = 0.280488f;	val_dir[5016*3 + 1] = 0.611974f;	val_dir[5016*3 + 2] = 0.739469f;
+ 	val_dir[5017*3 + 0] = 0.310045f;	val_dir[5017*3 + 1] = 0.645928f;	val_dir[5017*3 + 2] = 0.697602f;
+ 	val_dir[5018*3 + 0] = 0.339066f;	val_dir[5018*3 + 1] = 0.678133f;	val_dir[5018*3 + 2] = 0.652051f;
+ 	val_dir[5019*3 + 0] = 0.367152f;	val_dir[5019*3 + 1] = 0.708079f;	val_dir[5019*3 + 2] = 0.603178f;
+ 	val_dir[5020*3 + 0] = 0.393919f;	val_dir[5020*3 + 1] = 0.735316f;	val_dir[5020*3 + 2] = 0.551487f;
+ 	val_dir[5021*3 + 0] = 0.419026f;	val_dir[5021*3 + 1] = 0.759485f;	val_dir[5021*3 + 2] = 0.497594f;
+ 	val_dir[5022*3 + 0] = 0.442193f;	val_dir[5022*3 + 1] = 0.780340f;	val_dir[5022*3 + 2] = 0.442193f;
+ 	val_dir[5023*3 + 0] = 0.463217f;	val_dir[5023*3 + 1] = 0.797762f;	val_dir[5023*3 + 2] = 0.386014f;
+ 	val_dir[5024*3 + 0] = 0.481979f;	val_dir[5024*3 + 1] = 0.811754f;	val_dir[5024*3 + 2] = 0.329775f;
+ 	val_dir[5025*3 + 0] = 0.498445f;	val_dir[5025*3 + 1] = 0.822434f;	val_dir[5025*3 + 2] = 0.274145f;
+ 	val_dir[5026*3 + 0] = 0.512653f;	val_dir[5026*3 + 1] = 0.830009f;	val_dir[5026*3 + 2] = 0.219708f;
+ 	val_dir[5027*3 + 0] = 0.524703f;	val_dir[5027*3 + 1] = 0.834754f;	val_dir[5027*3 + 2] = 0.166951f;
+ 	val_dir[5028*3 + 0] = 0.534739f;	val_dir[5028*3 + 1] = 0.836983f;	val_dir[5028*3 + 2] = 0.116248f;
+ 	val_dir[5029*3 + 0] = 0.542936f;	val_dir[5029*3 + 1] = 0.837027f;	val_dir[5029*3 + 2] = 0.067867f;
+ 	val_dir[5030*3 + 0] = 0.549484f;	val_dir[5030*3 + 1] = 0.835215f;	val_dir[5030*3 + 2] = 0.021979f;
+ 	val_dir[5031*3 + 0] = -0.841879f;	val_dir[5031*3 + 1] = -0.539666f;	val_dir[5031*3 + 2] = 0.0f;
+ 	val_dir[5032*3 + 0] = -0.844653f;	val_dir[5032*3 + 1] = -0.533465f;	val_dir[5032*3 + 2] = 0.044455f;
+ 	val_dir[5033*3 + 0] = -0.845728f;	val_dir[5033*3 + 1] = -0.525723f;	val_dir[5033*3 + 2] = 0.091430f;
+ 	val_dir[5034*3 + 0] = -0.844782f;	val_dir[5034*3 + 1] = -0.516256f;	val_dir[5034*3 + 2] = 0.140797f;
+ 	val_dir[5035*3 + 0] = -0.841482f;	val_dir[5035*3 + 1] = -0.504889f;	val_dir[5035*3 + 2] = 0.192339f;
+ 	val_dir[5036*3 + 0] = -0.835504f;	val_dir[5036*3 + 1] = -0.491473f;	val_dir[5036*3 + 2] = 0.245737f;
+ 	val_dir[5037*3 + 0] = -0.826551f;	val_dir[5037*3 + 1] = -0.475893f;	val_dir[5037*3 + 2] = 0.300564f;
+ 	val_dir[5038*3 + 0] = -0.814379f;	val_dir[5038*3 + 1] = -0.458088f;	val_dir[5038*3 + 2] = 0.356291f;
+ 	val_dir[5039*3 + 0] = -0.798820f;	val_dir[5039*3 + 1] = -0.438063f;	val_dir[5039*3 + 2] = 0.412294f;
+ 	val_dir[5040*3 + 0] = -0.779813f;	val_dir[5040*3 + 1] = -0.41590f;	val_dir[5040*3 + 2] = 0.467888f;
+ 	val_dir[5041*3 + 0] = -0.757410f;	val_dir[5041*3 + 1] = -0.391764f;	val_dir[5041*3 + 2] = 0.522352f;
+ 	val_dir[5042*3 + 0] = -0.731792f;	val_dir[5042*3 + 1] = -0.365896f;	val_dir[5042*3 + 2] = 0.574979f;
+ 	val_dir[5043*3 + 0] = -0.703259f;	val_dir[5043*3 + 1] = -0.338606f;	val_dir[5043*3 + 2] = 0.625119f;
+ 	val_dir[5044*3 + 0] = -0.672214f;	val_dir[5044*3 + 1] = -0.310253f;	val_dir[5044*3 + 2] = 0.672214f;
+ 	val_dir[5045*3 + 0] = -0.639138f;	val_dir[5045*3 + 1] = -0.281220f;	val_dir[5045*3 + 2] = 0.715834f;
+ 	val_dir[5046*3 + 0] = -0.604551f;	val_dir[5046*3 + 1] = -0.251896f;	val_dir[5046*3 + 2] = 0.755689f;
+ 	val_dir[5047*3 + 0] = -0.568986f;	val_dir[5047*3 + 1] = -0.222647f;	val_dir[5047*3 + 2] = 0.791633f;
+ 	val_dir[5048*3 + 0] = -0.532952f;	val_dir[5048*3 + 1] = -0.193801f;	val_dir[5048*3 + 2] = 0.823653f;
+ 	val_dir[5049*3 + 0] = -0.496911f;	val_dir[5049*3 + 1] = -0.165637f;	val_dir[5049*3 + 2] = 0.851847f;
+ 	val_dir[5050*3 + 0] = -0.461266f;	val_dir[5050*3 + 1] = -0.138380f;	val_dir[5050*3 + 2] = 0.876405f;
+ 	val_dir[5051*3 + 0] = -0.426348f;	val_dir[5051*3 + 1] = -0.112197f;	val_dir[5051*3 + 2] = 0.897574f;
+ 	val_dir[5052*3 + 0] = -0.392419f;	val_dir[5052*3 + 1] = -0.087204f;	val_dir[5052*3 + 2] = 0.915644f;
+ 	val_dir[5053*3 + 0] = -0.359673f;	val_dir[5053*3 + 1] = -0.063472f;	val_dir[5053*3 + 2] = 0.930917f;
+ 	val_dir[5054*3 + 0] = -0.328244f;	val_dir[5054*3 + 1] = -0.041030f;	val_dir[5054*3 + 2] = 0.943701f;
+ 	val_dir[5055*3 + 0] = -0.298216f;	val_dir[5055*3 + 1] = -0.019881f;	val_dir[5055*3 + 2] = 0.954291f;
+ 	val_dir[5056*3 + 0] = -0.269630f;	val_dir[5056*3 + 1] = 0.0f;	val_dir[5056*3 + 2] = 0.962964f;
+ 	val_dir[5057*3 + 0] = -0.251587f;	val_dir[5057*3 + 1] = 0.019353f;	val_dir[5057*3 + 2] = 0.967641f;
+ 	val_dir[5058*3 + 0] = -0.233197f;	val_dir[5058*3 + 1] = 0.038866f;	val_dir[5058*3 + 2] = 0.971653f;
+ 	val_dir[5059*3 + 0] = -0.214494f;	val_dir[5059*3 + 1] = 0.058498f;	val_dir[5059*3 + 2] = 0.974972f;
+ 	val_dir[5060*3 + 0] = -0.195515f;	val_dir[5060*3 + 1] = 0.078206f;	val_dir[5060*3 + 2] = 0.977577f;
+ 	val_dir[5061*3 + 0] = -0.176301f;	val_dir[5061*3 + 1] = 0.097945f;	val_dir[5061*3 + 2] = 0.979451f;
+ 	val_dir[5062*3 + 0] = -0.156893f;	val_dir[5062*3 + 1] = 0.117670f;	val_dir[5062*3 + 2] = 0.980581f;
+ 	val_dir[5063*3 + 0] = -0.137334f;	val_dir[5063*3 + 1] = 0.137334f;	val_dir[5063*3 + 2] = 0.980958f;
+ 	val_dir[5064*3 + 0] = -0.117670f;	val_dir[5064*3 + 1] = 0.156893f;	val_dir[5064*3 + 2] = 0.980581f;
+ 	val_dir[5065*3 + 0] = -0.097945f;	val_dir[5065*3 + 1] = 0.176301f;	val_dir[5065*3 + 2] = 0.979451f;
+ 	val_dir[5066*3 + 0] = -0.078206f;	val_dir[5066*3 + 1] = 0.195515f;	val_dir[5066*3 + 2] = 0.977577f;
+ 	val_dir[5067*3 + 0] = -0.058498f;	val_dir[5067*3 + 1] = 0.214494f;	val_dir[5067*3 + 2] = 0.974972f;
+ 	val_dir[5068*3 + 0] = -0.038866f;	val_dir[5068*3 + 1] = 0.233197f;	val_dir[5068*3 + 2] = 0.971653f;
+ 	val_dir[5069*3 + 0] = -0.019353f;	val_dir[5069*3 + 1] = 0.251587f;	val_dir[5069*3 + 2] = 0.967641f;
+ 	val_dir[5070*3 + 0] = 0.0f;	val_dir[5070*3 + 1] = 0.269630f;	val_dir[5070*3 + 2] = 0.962964f;
+ 	val_dir[5071*3 + 0] = 0.019881f;	val_dir[5071*3 + 1] = 0.298216f;	val_dir[5071*3 + 2] = 0.954291f;
+ 	val_dir[5072*3 + 0] = 0.041030f;	val_dir[5072*3 + 1] = 0.328244f;	val_dir[5072*3 + 2] = 0.943701f;
+ 	val_dir[5073*3 + 0] = 0.063472f;	val_dir[5073*3 + 1] = 0.359673f;	val_dir[5073*3 + 2] = 0.930917f;
+ 	val_dir[5074*3 + 0] = 0.087204f;	val_dir[5074*3 + 1] = 0.392419f;	val_dir[5074*3 + 2] = 0.915644f;
+ 	val_dir[5075*3 + 0] = 0.112197f;	val_dir[5075*3 + 1] = 0.426348f;	val_dir[5075*3 + 2] = 0.897574f;
+ 	val_dir[5076*3 + 0] = 0.138380f;	val_dir[5076*3 + 1] = 0.461266f;	val_dir[5076*3 + 2] = 0.876405f;
+ 	val_dir[5077*3 + 0] = 0.165637f;	val_dir[5077*3 + 1] = 0.496911f;	val_dir[5077*3 + 2] = 0.851847f;
+ 	val_dir[5078*3 + 0] = 0.193801f;	val_dir[5078*3 + 1] = 0.532952f;	val_dir[5078*3 + 2] = 0.823653f;
+ 	val_dir[5079*3 + 0] = 0.222647f;	val_dir[5079*3 + 1] = 0.568986f;	val_dir[5079*3 + 2] = 0.791633f;
+ 	val_dir[5080*3 + 0] = 0.251896f;	val_dir[5080*3 + 1] = 0.604551f;	val_dir[5080*3 + 2] = 0.755689f;
+ 	val_dir[5081*3 + 0] = 0.281220f;	val_dir[5081*3 + 1] = 0.639138f;	val_dir[5081*3 + 2] = 0.715834f;
+ 	val_dir[5082*3 + 0] = 0.310253f;	val_dir[5082*3 + 1] = 0.672214f;	val_dir[5082*3 + 2] = 0.672214f;
+ 	val_dir[5083*3 + 0] = 0.338606f;	val_dir[5083*3 + 1] = 0.703259f;	val_dir[5083*3 + 2] = 0.625119f;
+ 	val_dir[5084*3 + 0] = 0.365896f;	val_dir[5084*3 + 1] = 0.731792f;	val_dir[5084*3 + 2] = 0.574979f;
+ 	val_dir[5085*3 + 0] = 0.391764f;	val_dir[5085*3 + 1] = 0.757410f;	val_dir[5085*3 + 2] = 0.522352f;
+ 	val_dir[5086*3 + 0] = 0.41590f;	val_dir[5086*3 + 1] = 0.779813f;	val_dir[5086*3 + 2] = 0.467888f;
+ 	val_dir[5087*3 + 0] = 0.438063f;	val_dir[5087*3 + 1] = 0.798820f;	val_dir[5087*3 + 2] = 0.412294f;
+ 	val_dir[5088*3 + 0] = 0.458088f;	val_dir[5088*3 + 1] = 0.814379f;	val_dir[5088*3 + 2] = 0.356291f;
+ 	val_dir[5089*3 + 0] = 0.475893f;	val_dir[5089*3 + 1] = 0.826551f;	val_dir[5089*3 + 2] = 0.300564f;
+ 	val_dir[5090*3 + 0] = 0.491473f;	val_dir[5090*3 + 1] = 0.835504f;	val_dir[5090*3 + 2] = 0.245737f;
+ 	val_dir[5091*3 + 0] = 0.504889f;	val_dir[5091*3 + 1] = 0.841482f;	val_dir[5091*3 + 2] = 0.192339f;
+ 	val_dir[5092*3 + 0] = 0.516256f;	val_dir[5092*3 + 1] = 0.844782f;	val_dir[5092*3 + 2] = 0.140797f;
+ 	val_dir[5093*3 + 0] = 0.525723f;	val_dir[5093*3 + 1] = 0.845728f;	val_dir[5093*3 + 2] = 0.091430f;
+ 	val_dir[5094*3 + 0] = 0.533465f;	val_dir[5094*3 + 1] = 0.844653f;	val_dir[5094*3 + 2] = 0.044455f;
+ 	val_dir[5095*3 + 0] = 0.539666f;	val_dir[5095*3 + 1] = 0.841879f;	val_dir[5095*3 + 2] = 0.0f;
+ 	val_dir[5096*3 + 0] = -0.851455f;	val_dir[5096*3 + 1] = -0.523973f;	val_dir[5096*3 + 2] = 0.021832f;
+ 	val_dir[5097*3 + 0] = -0.853556f;	val_dir[5097*3 + 1] = -0.516626f;	val_dir[5097*3 + 2] = 0.067386f;
+ 	val_dir[5098*3 + 0] = -0.853796f;	val_dir[5098*3 + 1] = -0.507662f;	val_dir[5098*3 + 2] = 0.115378f;
+ 	val_dir[5099*3 + 0] = -0.851847f;	val_dir[5099*3 + 1] = -0.496911f;	val_dir[5099*3 + 2] = 0.165637f;
+ 	val_dir[5100*3 + 0] = -0.847381f;	val_dir[5100*3 + 1] = -0.484217f;	val_dir[5100*3 + 2] = 0.217898f;
+ 	val_dir[5101*3 + 0] = -0.840083f;	val_dir[5101*3 + 1] = -0.469458f;	val_dir[5101*3 + 2] = 0.271791f;
+ 	val_dir[5102*3 + 0] = -0.829680f;	val_dir[5102*3 + 1] = -0.452553f;	val_dir[5102*3 + 2] = 0.326844f;
+ 	val_dir[5103*3 + 0] = -0.815966f;	val_dir[5103*3 + 1] = -0.433482f;	val_dir[5103*3 + 2] = 0.382484f;
+ 	val_dir[5104*3 + 0] = -0.798820f;	val_dir[5104*3 + 1] = -0.412294f;	val_dir[5104*3 + 2] = 0.438063f;
+ 	val_dir[5105*3 + 0] = -0.778237f;	val_dir[5105*3 + 1] = -0.389118f;	val_dir[5105*3 + 2] = 0.492883f;
+ 	val_dir[5106*3 + 0] = -0.754329f;	val_dir[5106*3 + 1] = -0.364159f;	val_dir[5106*3 + 2] = 0.546238f;
+ 	val_dir[5107*3 + 0] = -0.727334f;	val_dir[5107*3 + 1] = -0.337691f;	val_dir[5107*3 + 2] = 0.597453f;
+ 	val_dir[5108*3 + 0] = -0.697602f;	val_dir[5108*3 + 1] = -0.310045f;	val_dir[5108*3 + 2] = 0.645928f;
+ 	val_dir[5109*3 + 0] = -0.665574f;	val_dir[5109*3 + 1] = -0.281589f;	val_dir[5109*3 + 2] = 0.691173f;
+ 	val_dir[5110*3 + 0] = -0.631748f;	val_dir[5110*3 + 1] = -0.252699f;	val_dir[5110*3 + 2] = 0.732828f;
+ 	val_dir[5111*3 + 0] = -0.596653f;	val_dir[5111*3 + 1] = -0.223745f;	val_dir[5111*3 + 2] = 0.770677f;
+ 	val_dir[5112*3 + 0] = -0.560809f;	val_dir[5112*3 + 1] = -0.195064f;	val_dir[5112*3 + 2] = 0.804639f;
+ 	val_dir[5113*3 + 0] = -0.524703f;	val_dir[5113*3 + 1] = -0.166951f;	val_dir[5113*3 + 2] = 0.834754f;
+ 	val_dir[5114*3 + 0] = -0.488769f;	val_dir[5114*3 + 1] = -0.139648f;	val_dir[5114*3 + 2] = 0.861164f;
+ 	val_dir[5115*3 + 0] = -0.453376f;	val_dir[5115*3 + 1] = -0.113344f;	val_dir[5115*3 + 2] = 0.884083f;
+ 	val_dir[5116*3 + 0] = -0.418823f;	val_dir[5116*3 + 1] = -0.088173f;	val_dir[5116*3 + 2] = 0.903777f;
+ 	val_dir[5117*3 + 0] = -0.385341f;	val_dir[5117*3 + 1] = -0.064223f;	val_dir[5117*3 + 2] = 0.920537f;
+ 	val_dir[5118*3 + 0] = -0.353096f;	val_dir[5118*3 + 1] = -0.041541f;	val_dir[5118*3 + 2] = 0.934665f;
+ 	val_dir[5119*3 + 0] = -0.322198f;	val_dir[5119*3 + 1] = -0.020137f;	val_dir[5119*3 + 2] = 0.946458f;
+ 	val_dir[5120*3 + 0] = -0.292714f;	val_dir[5120*3 + 1] = 0.0f;	val_dir[5120*3 + 2] = 0.95620f;
+ 	val_dir[5121*3 + 0] = -0.274668f;	val_dir[5121*3 + 1] = 0.019619f;	val_dir[5121*3 + 2] = 0.961339f;
+ 	val_dir[5122*3 + 0] = -0.256235f;	val_dir[5122*3 + 1] = 0.039421f;	val_dir[5122*3 + 2] = 0.965810f;
+ 	val_dir[5123*3 + 0] = -0.237449f;	val_dir[5123*3 + 1] = 0.059362f;	val_dir[5123*3 + 2] = 0.969584f;
+ 	val_dir[5124*3 + 0] = -0.218347f;	val_dir[5124*3 + 1] = 0.079399f;	val_dir[5124*3 + 2] = 0.972636f;
+ 	val_dir[5125*3 + 0] = -0.198968f;	val_dir[5125*3 + 1] = 0.099484f;	val_dir[5125*3 + 2] = 0.974943f;
+ 	val_dir[5126*3 + 0] = -0.179355f;	val_dir[5126*3 + 1] = 0.119570f;	val_dir[5126*3 + 2] = 0.976491f;
+ 	val_dir[5127*3 + 0] = -0.159554f;	val_dir[5127*3 + 1] = 0.139610f;	val_dir[5127*3 + 2] = 0.977267f;
+ 	val_dir[5128*3 + 0] = -0.139610f;	val_dir[5128*3 + 1] = 0.159554f;	val_dir[5128*3 + 2] = 0.977267f;
+ 	val_dir[5129*3 + 0] = -0.119570f;	val_dir[5129*3 + 1] = 0.179355f;	val_dir[5129*3 + 2] = 0.976491f;
+ 	val_dir[5130*3 + 0] = -0.099484f;	val_dir[5130*3 + 1] = 0.198968f;	val_dir[5130*3 + 2] = 0.974943f;
+ 	val_dir[5131*3 + 0] = -0.079399f;	val_dir[5131*3 + 1] = 0.218347f;	val_dir[5131*3 + 2] = 0.972636f;
+ 	val_dir[5132*3 + 0] = -0.059362f;	val_dir[5132*3 + 1] = 0.237449f;	val_dir[5132*3 + 2] = 0.969584f;
+ 	val_dir[5133*3 + 0] = -0.039421f;	val_dir[5133*3 + 1] = 0.256235f;	val_dir[5133*3 + 2] = 0.965810f;
+ 	val_dir[5134*3 + 0] = -0.019619f;	val_dir[5134*3 + 1] = 0.274668f;	val_dir[5134*3 + 2] = 0.961339f;
+ 	val_dir[5135*3 + 0] = 0.0f;	val_dir[5135*3 + 1] = 0.292714f;	val_dir[5135*3 + 2] = 0.95620f;
+ 	val_dir[5136*3 + 0] = 0.020137f;	val_dir[5136*3 + 1] = 0.322198f;	val_dir[5136*3 + 2] = 0.946458f;
+ 	val_dir[5137*3 + 0] = 0.041541f;	val_dir[5137*3 + 1] = 0.353096f;	val_dir[5137*3 + 2] = 0.934665f;
+ 	val_dir[5138*3 + 0] = 0.064223f;	val_dir[5138*3 + 1] = 0.385341f;	val_dir[5138*3 + 2] = 0.920537f;
+ 	val_dir[5139*3 + 0] = 0.088173f;	val_dir[5139*3 + 1] = 0.418823f;	val_dir[5139*3 + 2] = 0.903777f;
+ 	val_dir[5140*3 + 0] = 0.113344f;	val_dir[5140*3 + 1] = 0.453376f;	val_dir[5140*3 + 2] = 0.884083f;
+ 	val_dir[5141*3 + 0] = 0.139648f;	val_dir[5141*3 + 1] = 0.488769f;	val_dir[5141*3 + 2] = 0.861164f;
+ 	val_dir[5142*3 + 0] = 0.166951f;	val_dir[5142*3 + 1] = 0.524703f;	val_dir[5142*3 + 2] = 0.834754f;
+ 	val_dir[5143*3 + 0] = 0.195064f;	val_dir[5143*3 + 1] = 0.560809f;	val_dir[5143*3 + 2] = 0.804639f;
+ 	val_dir[5144*3 + 0] = 0.223745f;	val_dir[5144*3 + 1] = 0.596653f;	val_dir[5144*3 + 2] = 0.770677f;
+ 	val_dir[5145*3 + 0] = 0.252699f;	val_dir[5145*3 + 1] = 0.631748f;	val_dir[5145*3 + 2] = 0.732828f;
+ 	val_dir[5146*3 + 0] = 0.281589f;	val_dir[5146*3 + 1] = 0.665574f;	val_dir[5146*3 + 2] = 0.691173f;
+ 	val_dir[5147*3 + 0] = 0.310045f;	val_dir[5147*3 + 1] = 0.697602f;	val_dir[5147*3 + 2] = 0.645928f;
+ 	val_dir[5148*3 + 0] = 0.337691f;	val_dir[5148*3 + 1] = 0.727334f;	val_dir[5148*3 + 2] = 0.597453f;
+ 	val_dir[5149*3 + 0] = 0.364159f;	val_dir[5149*3 + 1] = 0.754329f;	val_dir[5149*3 + 2] = 0.546238f;
+ 	val_dir[5150*3 + 0] = 0.389118f;	val_dir[5150*3 + 1] = 0.778237f;	val_dir[5150*3 + 2] = 0.492883f;
+ 	val_dir[5151*3 + 0] = 0.412294f;	val_dir[5151*3 + 1] = 0.798820f;	val_dir[5151*3 + 2] = 0.438063f;
+ 	val_dir[5152*3 + 0] = 0.433482f;	val_dir[5152*3 + 1] = 0.815966f;	val_dir[5152*3 + 2] = 0.382484f;
+ 	val_dir[5153*3 + 0] = 0.452553f;	val_dir[5153*3 + 1] = 0.829680f;	val_dir[5153*3 + 2] = 0.326844f;
+ 	val_dir[5154*3 + 0] = 0.469458f;	val_dir[5154*3 + 1] = 0.840083f;	val_dir[5154*3 + 2] = 0.271791f;
+ 	val_dir[5155*3 + 0] = 0.484217f;	val_dir[5155*3 + 1] = 0.847381f;	val_dir[5155*3 + 2] = 0.217898f;
+ 	val_dir[5156*3 + 0] = 0.496911f;	val_dir[5156*3 + 1] = 0.851847f;	val_dir[5156*3 + 2] = 0.165637f;
+ 	val_dir[5157*3 + 0] = 0.507662f;	val_dir[5157*3 + 1] = 0.853796f;	val_dir[5157*3 + 2] = 0.115378f;
+ 	val_dir[5158*3 + 0] = 0.516626f;	val_dir[5158*3 + 1] = 0.853556f;	val_dir[5158*3 + 2] = 0.067386f;
+ 	val_dir[5159*3 + 0] = 0.523973f;	val_dir[5159*3 + 1] = 0.851455f;	val_dir[5159*3 + 2] = 0.021832f;
+ 	val_dir[5160*3 + 0] = -0.857493f;	val_dir[5160*3 + 1] = -0.514496f;	val_dir[5160*3 + 2] = 0.0f;
+ 	val_dir[5161*3 + 0] = -0.860527f;	val_dir[5161*3 + 1] = -0.507490f;	val_dir[5161*3 + 2] = 0.044130f;
+ 	val_dir[5162*3 + 0] = -0.861857f;	val_dir[5162*3 + 1] = -0.498970f;	val_dir[5162*3 + 2] = 0.090722f;
+ 	val_dir[5163*3 + 0] = -0.861164f;	val_dir[5163*3 + 1] = -0.488769f;	val_dir[5163*3 + 2] = 0.139648f;
+ 	val_dir[5164*3 + 0] = -0.858116f;	val_dir[5164*3 + 1] = -0.476731f;	val_dir[5164*3 + 2] = 0.190693f;
+ 	val_dir[5165*3 + 0] = -0.852392f;	val_dir[5165*3 + 1] = -0.462727f;	val_dir[5165*3 + 2] = 0.243541f;
+ 	val_dir[5166*3 + 0] = -0.843696f;	val_dir[5166*3 + 1] = -0.446662f;	val_dir[5166*3 + 2] = 0.297775f;
+ 	val_dir[5167*3 + 0] = -0.831786f;	val_dir[5167*3 + 1] = -0.428496f;	val_dir[5167*3 + 2] = 0.352879f;
+ 	val_dir[5168*3 + 0] = -0.816497f;	val_dir[5168*3 + 1] = -0.408248f;	val_dir[5168*3 + 2] = 0.408248f;
+ 	val_dir[5169*3 + 0] = -0.797762f;	val_dir[5169*3 + 1] = -0.386014f;	val_dir[5169*3 + 2] = 0.463217f;
+ 	val_dir[5170*3 + 0] = -0.775632f;	val_dir[5170*3 + 1] = -0.361961f;	val_dir[5170*3 + 2] = 0.517088f;
+ 	val_dir[5171*3 + 0] = -0.750279f;	val_dir[5171*3 + 1] = -0.336332f;	val_dir[5171*3 + 2] = 0.569177f;
+ 	val_dir[5172*3 + 0] = -0.721995f;	val_dir[5172*3 + 1] = -0.309426f;	val_dir[5172*3 + 2] = 0.618853f;
+ 	val_dir[5173*3 + 0] = -0.691173f;	val_dir[5173*3 + 1] = -0.281589f;	val_dir[5173*3 + 2] = 0.665574f;
+ 	val_dir[5174*3 + 0] = -0.658281f;	val_dir[5174*3 + 1] = -0.253185f;	val_dir[5174*3 + 2] = 0.708918f;
+ 	val_dir[5175*3 + 0] = -0.623831f;	val_dir[5175*3 + 1] = -0.224579f;	val_dir[5175*3 + 2] = 0.748598f;
+ 	val_dir[5176*3 + 0] = -0.588348f;	val_dir[5176*3 + 1] = -0.196116f;	val_dir[5176*3 + 2] = 0.784465f;
+ 	val_dir[5177*3 + 0] = -0.552336f;	val_dir[5177*3 + 1] = -0.168102f;	val_dir[5177*3 + 2] = 0.816497f;
+ 	val_dir[5178*3 + 0] = -0.516256f;	val_dir[5178*3 + 1] = -0.140797f;	val_dir[5178*3 + 2] = 0.844782f;
+ 	val_dir[5179*3 + 0] = -0.480510f;	val_dir[5179*3 + 1] = -0.114407f;	val_dir[5179*3 + 2] = 0.869495f;
+ 	val_dir[5180*3 + 0] = -0.445435f;	val_dir[5180*3 + 1] = -0.089087f;	val_dir[5180*3 + 2] = 0.890871f;
+ 	val_dir[5181*3 + 0] = -0.411298f;	val_dir[5181*3 + 1] = -0.064942f;	val_dir[5181*3 + 2] = 0.909185f;
+ 	val_dir[5182*3 + 0] = -0.378298f;	val_dir[5182*3 + 1] = -0.042033f;	val_dir[5182*3 + 2] = 0.924729f;
+ 	val_dir[5183*3 + 0] = -0.346578f;	val_dir[5183*3 + 1] = -0.020387f;	val_dir[5183*3 + 2] = 0.93780f;
+ 	val_dir[5184*3 + 0] = -0.316228f;	val_dir[5184*3 + 1] = 0.0f;	val_dir[5184*3 + 2] = 0.948683f;
+ 	val_dir[5185*3 + 0] = -0.298216f;	val_dir[5185*3 + 1] = 0.019881f;	val_dir[5185*3 + 2] = 0.954291f;
+ 	val_dir[5186*3 + 0] = -0.279776f;	val_dir[5186*3 + 1] = 0.039968f;	val_dir[5186*3 + 2] = 0.959233f;
+ 	val_dir[5187*3 + 0] = -0.260941f;	val_dir[5187*3 + 1] = 0.060217f;	val_dir[5187*3 + 2] = 0.963475f;
+ 	val_dir[5188*3 + 0] = -0.241747f;	val_dir[5188*3 + 1] = 0.080582f;	val_dir[5188*3 + 2] = 0.966988f;
+ 	val_dir[5189*3 + 0] = -0.222234f;	val_dir[5189*3 + 1] = 0.101015f;	val_dir[5189*3 + 2] = 0.969746f;
+ 	val_dir[5190*3 + 0] = -0.202444f;	val_dir[5190*3 + 1] = 0.121466f;	val_dir[5190*3 + 2] = 0.971732f;
+ 	val_dir[5191*3 + 0] = -0.182424f;	val_dir[5191*3 + 1] = 0.141885f;	val_dir[5191*3 + 2] = 0.972929f;
+ 	val_dir[5192*3 + 0] = -0.162221f;	val_dir[5192*3 + 1] = 0.162221f;	val_dir[5192*3 + 2] = 0.973329f;
+ 	val_dir[5193*3 + 0] = -0.141885f;	val_dir[5193*3 + 1] = 0.182424f;	val_dir[5193*3 + 2] = 0.972929f;
+ 	val_dir[5194*3 + 0] = -0.121466f;	val_dir[5194*3 + 1] = 0.202444f;	val_dir[5194*3 + 2] = 0.971732f;
+ 	val_dir[5195*3 + 0] = -0.101015f;	val_dir[5195*3 + 1] = 0.222234f;	val_dir[5195*3 + 2] = 0.969746f;
+ 	val_dir[5196*3 + 0] = -0.080582f;	val_dir[5196*3 + 1] = 0.241747f;	val_dir[5196*3 + 2] = 0.966988f;
+ 	val_dir[5197*3 + 0] = -0.060217f;	val_dir[5197*3 + 1] = 0.260941f;	val_dir[5197*3 + 2] = 0.963475f;
+ 	val_dir[5198*3 + 0] = -0.039968f;	val_dir[5198*3 + 1] = 0.279776f;	val_dir[5198*3 + 2] = 0.959233f;
+ 	val_dir[5199*3 + 0] = -0.019881f;	val_dir[5199*3 + 1] = 0.298216f;	val_dir[5199*3 + 2] = 0.954291f;
+ 	val_dir[5200*3 + 0] = 0.0f;	val_dir[5200*3 + 1] = 0.316228f;	val_dir[5200*3 + 2] = 0.948683f;
+ 	val_dir[5201*3 + 0] = 0.020387f;	val_dir[5201*3 + 1] = 0.346578f;	val_dir[5201*3 + 2] = 0.93780f;
+ 	val_dir[5202*3 + 0] = 0.042033f;	val_dir[5202*3 + 1] = 0.378298f;	val_dir[5202*3 + 2] = 0.924729f;
+ 	val_dir[5203*3 + 0] = 0.064942f;	val_dir[5203*3 + 1] = 0.411298f;	val_dir[5203*3 + 2] = 0.909185f;
+ 	val_dir[5204*3 + 0] = 0.089087f;	val_dir[5204*3 + 1] = 0.445435f;	val_dir[5204*3 + 2] = 0.890871f;
+ 	val_dir[5205*3 + 0] = 0.114407f;	val_dir[5205*3 + 1] = 0.480510f;	val_dir[5205*3 + 2] = 0.869495f;
+ 	val_dir[5206*3 + 0] = 0.140797f;	val_dir[5206*3 + 1] = 0.516256f;	val_dir[5206*3 + 2] = 0.844782f;
+ 	val_dir[5207*3 + 0] = 0.168102f;	val_dir[5207*3 + 1] = 0.552336f;	val_dir[5207*3 + 2] = 0.816497f;
+ 	val_dir[5208*3 + 0] = 0.196116f;	val_dir[5208*3 + 1] = 0.588348f;	val_dir[5208*3 + 2] = 0.784465f;
+ 	val_dir[5209*3 + 0] = 0.224579f;	val_dir[5209*3 + 1] = 0.623831f;	val_dir[5209*3 + 2] = 0.748598f;
+ 	val_dir[5210*3 + 0] = 0.253185f;	val_dir[5210*3 + 1] = 0.658281f;	val_dir[5210*3 + 2] = 0.708918f;
+ 	val_dir[5211*3 + 0] = 0.281589f;	val_dir[5211*3 + 1] = 0.691173f;	val_dir[5211*3 + 2] = 0.665574f;
+ 	val_dir[5212*3 + 0] = 0.309426f;	val_dir[5212*3 + 1] = 0.721995f;	val_dir[5212*3 + 2] = 0.618853f;
+ 	val_dir[5213*3 + 0] = 0.336332f;	val_dir[5213*3 + 1] = 0.750279f;	val_dir[5213*3 + 2] = 0.569177f;
+ 	val_dir[5214*3 + 0] = 0.361961f;	val_dir[5214*3 + 1] = 0.775632f;	val_dir[5214*3 + 2] = 0.517088f;
+ 	val_dir[5215*3 + 0] = 0.386014f;	val_dir[5215*3 + 1] = 0.797762f;	val_dir[5215*3 + 2] = 0.463217f;
+ 	val_dir[5216*3 + 0] = 0.408248f;	val_dir[5216*3 + 1] = 0.816497f;	val_dir[5216*3 + 2] = 0.408248f;
+ 	val_dir[5217*3 + 0] = 0.428496f;	val_dir[5217*3 + 1] = 0.831786f;	val_dir[5217*3 + 2] = 0.352879f;
+ 	val_dir[5218*3 + 0] = 0.446662f;	val_dir[5218*3 + 1] = 0.843696f;	val_dir[5218*3 + 2] = 0.297775f;
+ 	val_dir[5219*3 + 0] = 0.462727f;	val_dir[5219*3 + 1] = 0.852392f;	val_dir[5219*3 + 2] = 0.243541f;
+ 	val_dir[5220*3 + 0] = 0.476731f;	val_dir[5220*3 + 1] = 0.858116f;	val_dir[5220*3 + 2] = 0.190693f;
+ 	val_dir[5221*3 + 0] = 0.488769f;	val_dir[5221*3 + 1] = 0.861164f;	val_dir[5221*3 + 2] = 0.139648f;
+ 	val_dir[5222*3 + 0] = 0.498970f;	val_dir[5222*3 + 1] = 0.861857f;	val_dir[5222*3 + 2] = 0.090722f;
+ 	val_dir[5223*3 + 0] = 0.507490f;	val_dir[5223*3 + 1] = 0.860527f;	val_dir[5223*3 + 2] = 0.044130f;
+ 	val_dir[5224*3 + 0] = 0.514496f;	val_dir[5224*3 + 1] = 0.857493f;	val_dir[5224*3 + 2] = 0.0f;
+ 	val_dir[5225*3 + 0] = -0.866703f;	val_dir[5225*3 + 1] = -0.498354f;	val_dir[5225*3 + 2] = 0.021668f;
+ 	val_dir[5226*3 + 0] = -0.869030f;	val_dir[5226*3 + 1] = -0.490222f;	val_dir[5226*3 + 2] = 0.066848f;
+ 	val_dir[5227*3 + 0] = -0.869495f;	val_dir[5227*3 + 1] = -0.480510f;	val_dir[5227*3 + 2] = 0.114407f;
+ 	val_dir[5228*3 + 0] = -0.867770f;	val_dir[5228*3 + 1] = -0.469065f;	val_dir[5228*3 + 2] = 0.164173f;
+ 	val_dir[5229*3 + 0] = -0.863530f;	val_dir[5229*3 + 1] = -0.455752f;	val_dir[5229*3 + 2] = 0.215883f;
+ 	val_dir[5230*3 + 0] = -0.856465f;	val_dir[5230*3 + 1] = -0.440468f;	val_dir[5230*3 + 2] = 0.269175f;
+ 	val_dir[5231*3 + 0] = -0.846305f;	val_dir[5231*3 + 1] = -0.423153f;	val_dir[5231*3 + 2] = 0.323587f;
+ 	val_dir[5232*3 + 0] = -0.832845f;	val_dir[5232*3 + 1] = -0.403804f;	val_dir[5232*3 + 2] = 0.378566f;
+ 	val_dir[5233*3 + 0] = -0.815966f;	val_dir[5233*3 + 1] = -0.382484f;	val_dir[5233*3 + 2] = 0.433482f;
+ 	val_dir[5234*3 + 0] = -0.795657f;	val_dir[5234*3 + 1] = -0.359329f;	val_dir[5234*3 + 2] = 0.487661f;
+ 	val_dir[5235*3 + 0] = -0.772027f;	val_dir[5235*3 + 1] = -0.334545f;	val_dir[5235*3 + 2] = 0.540419f;
+ 	val_dir[5236*3 + 0] = -0.745307f;	val_dir[5236*3 + 1] = -0.308403f;	val_dir[5236*3 + 2] = 0.591105f;
+ 	val_dir[5237*3 + 0] = -0.715834f;	val_dir[5237*3 + 1] = -0.281220f;	val_dir[5237*3 + 2] = 0.639138f;
+ 	val_dir[5238*3 + 0] = -0.684038f;	val_dir[5238*3 + 1] = -0.253347f;	val_dir[5238*3 + 2] = 0.684038f;
+ 	val_dir[5239*3 + 0] = -0.650407f;	val_dir[5239*3 + 1] = -0.225141f;	val_dir[5239*3 + 2] = 0.725454f;
+ 	val_dir[5240*3 + 0] = -0.615457f;	val_dir[5240*3 + 1] = -0.196946f;	val_dir[5240*3 + 2] = 0.763167f;
+ 	val_dir[5241*3 + 0] = -0.579703f;	val_dir[5241*3 + 1] = -0.169080f;	val_dir[5241*3 + 2] = 0.797092f;
+ 	val_dir[5242*3 + 0] = -0.543627f;	val_dir[5242*3 + 1] = -0.141816f;	val_dir[5242*3 + 2] = 0.827259f;
+ 	val_dir[5243*3 + 0] = -0.507662f;	val_dir[5243*3 + 1] = -0.115378f;	val_dir[5243*3 + 2] = 0.853796f;
+ 	val_dir[5244*3 + 0] = -0.472178f;	val_dir[5244*3 + 1] = -0.089939f;	val_dir[5244*3 + 2] = 0.876903f;
+ 	val_dir[5245*3 + 0] = -0.437479f;	val_dir[5245*3 + 1] = -0.065622f;	val_dir[5245*3 + 2] = 0.896831f;
+ 	val_dir[5246*3 + 0] = -0.403799f;	val_dir[5246*3 + 1] = -0.042505f;	val_dir[5246*3 + 2] = 0.913860f;
+ 	val_dir[5247*3 + 0] = -0.371312f;	val_dir[5247*3 + 1] = -0.020628f;	val_dir[5247*3 + 2] = 0.928279f;
+ 	val_dir[5248*3 + 0] = -0.340136f;	val_dir[5248*3 + 1] = 0.0f;	val_dir[5248*3 + 2] = 0.940376f;
+ 	val_dir[5249*3 + 0] = -0.322198f;	val_dir[5249*3 + 1] = 0.020137f;	val_dir[5249*3 + 2] = 0.946458f;
+ 	val_dir[5250*3 + 0] = -0.303791f;	val_dir[5250*3 + 1] = 0.040505f;	val_dir[5250*3 + 2] = 0.951877f;
+ 	val_dir[5251*3 + 0] = -0.284944f;	val_dir[5251*3 + 1] = 0.061059f;	val_dir[5251*3 + 2] = 0.956597f;
+ 	val_dir[5252*3 + 0] = -0.265694f;	val_dir[5252*3 + 1] = 0.081752f;	val_dir[5252*3 + 2] = 0.960585f;
+ 	val_dir[5253*3 + 0] = -0.246079f;	val_dir[5253*3 + 1] = 0.102533f;	val_dir[5253*3 + 2] = 0.963811f;
+ 	val_dir[5254*3 + 0] = -0.226144f;	val_dir[5254*3 + 1] = 0.123351f;	val_dir[5254*3 + 2] = 0.966252f;
+ 	val_dir[5255*3 + 0] = -0.205934f;	val_dir[5255*3 + 1] = 0.144154f;	val_dir[5255*3 + 2] = 0.967890f;
+ 	val_dir[5256*3 + 0] = -0.185498f;	val_dir[5256*3 + 1] = 0.164887f;	val_dir[5256*3 + 2] = 0.968712f;
+ 	val_dir[5257*3 + 0] = -0.164887f;	val_dir[5257*3 + 1] = 0.185498f;	val_dir[5257*3 + 2] = 0.968712f;
+ 	val_dir[5258*3 + 0] = -0.144154f;	val_dir[5258*3 + 1] = 0.205934f;	val_dir[5258*3 + 2] = 0.967890f;
+ 	val_dir[5259*3 + 0] = -0.123351f;	val_dir[5259*3 + 1] = 0.226144f;	val_dir[5259*3 + 2] = 0.966252f;
+ 	val_dir[5260*3 + 0] = -0.102533f;	val_dir[5260*3 + 1] = 0.246079f;	val_dir[5260*3 + 2] = 0.963811f;
+ 	val_dir[5261*3 + 0] = -0.081752f;	val_dir[5261*3 + 1] = 0.265694f;	val_dir[5261*3 + 2] = 0.960585f;
+ 	val_dir[5262*3 + 0] = -0.061059f;	val_dir[5262*3 + 1] = 0.284944f;	val_dir[5262*3 + 2] = 0.956597f;
+ 	val_dir[5263*3 + 0] = -0.040505f;	val_dir[5263*3 + 1] = 0.303791f;	val_dir[5263*3 + 2] = 0.951877f;
+ 	val_dir[5264*3 + 0] = -0.020137f;	val_dir[5264*3 + 1] = 0.322198f;	val_dir[5264*3 + 2] = 0.946458f;
+ 	val_dir[5265*3 + 0] = 0.0f;	val_dir[5265*3 + 1] = 0.340136f;	val_dir[5265*3 + 2] = 0.940376f;
+ 	val_dir[5266*3 + 0] = 0.020628f;	val_dir[5266*3 + 1] = 0.371312f;	val_dir[5266*3 + 2] = 0.928279f;
+ 	val_dir[5267*3 + 0] = 0.042505f;	val_dir[5267*3 + 1] = 0.403799f;	val_dir[5267*3 + 2] = 0.913860f;
+ 	val_dir[5268*3 + 0] = 0.065622f;	val_dir[5268*3 + 1] = 0.437479f;	val_dir[5268*3 + 2] = 0.896831f;
+ 	val_dir[5269*3 + 0] = 0.089939f;	val_dir[5269*3 + 1] = 0.472178f;	val_dir[5269*3 + 2] = 0.876903f;
+ 	val_dir[5270*3 + 0] = 0.115378f;	val_dir[5270*3 + 1] = 0.507662f;	val_dir[5270*3 + 2] = 0.853796f;
+ 	val_dir[5271*3 + 0] = 0.141816f;	val_dir[5271*3 + 1] = 0.543627f;	val_dir[5271*3 + 2] = 0.827259f;
+ 	val_dir[5272*3 + 0] = 0.169080f;	val_dir[5272*3 + 1] = 0.579703f;	val_dir[5272*3 + 2] = 0.797092f;
+ 	val_dir[5273*3 + 0] = 0.196946f;	val_dir[5273*3 + 1] = 0.615457f;	val_dir[5273*3 + 2] = 0.763167f;
+ 	val_dir[5274*3 + 0] = 0.225141f;	val_dir[5274*3 + 1] = 0.650407f;	val_dir[5274*3 + 2] = 0.725454f;
+ 	val_dir[5275*3 + 0] = 0.253347f;	val_dir[5275*3 + 1] = 0.684038f;	val_dir[5275*3 + 2] = 0.684038f;
+ 	val_dir[5276*3 + 0] = 0.281220f;	val_dir[5276*3 + 1] = 0.715834f;	val_dir[5276*3 + 2] = 0.639138f;
+ 	val_dir[5277*3 + 0] = 0.308403f;	val_dir[5277*3 + 1] = 0.745307f;	val_dir[5277*3 + 2] = 0.591105f;
+ 	val_dir[5278*3 + 0] = 0.334545f;	val_dir[5278*3 + 1] = 0.772027f;	val_dir[5278*3 + 2] = 0.540419f;
+ 	val_dir[5279*3 + 0] = 0.359329f;	val_dir[5279*3 + 1] = 0.795657f;	val_dir[5279*3 + 2] = 0.487661f;
+ 	val_dir[5280*3 + 0] = 0.382484f;	val_dir[5280*3 + 1] = 0.815966f;	val_dir[5280*3 + 2] = 0.433482f;
+ 	val_dir[5281*3 + 0] = 0.403804f;	val_dir[5281*3 + 1] = 0.832845f;	val_dir[5281*3 + 2] = 0.378566f;
+ 	val_dir[5282*3 + 0] = 0.423153f;	val_dir[5282*3 + 1] = 0.846305f;	val_dir[5282*3 + 2] = 0.323587f;
+ 	val_dir[5283*3 + 0] = 0.440468f;	val_dir[5283*3 + 1] = 0.856465f;	val_dir[5283*3 + 2] = 0.269175f;
+ 	val_dir[5284*3 + 0] = 0.455752f;	val_dir[5284*3 + 1] = 0.863530f;	val_dir[5284*3 + 2] = 0.215883f;
+ 	val_dir[5285*3 + 0] = 0.469065f;	val_dir[5285*3 + 1] = 0.867770f;	val_dir[5285*3 + 2] = 0.164173f;
+ 	val_dir[5286*3 + 0] = 0.480510f;	val_dir[5286*3 + 1] = 0.869495f;	val_dir[5286*3 + 2] = 0.114407f;
+ 	val_dir[5287*3 + 0] = 0.490222f;	val_dir[5287*3 + 1] = 0.869030f;	val_dir[5287*3 + 2] = 0.066848f;
+ 	val_dir[5288*3 + 0] = 0.498354f;	val_dir[5288*3 + 1] = 0.866703f;	val_dir[5288*3 + 2] = 0.021668f;
+ 	val_dir[5289*3 + 0] = -0.872143f;	val_dir[5289*3 + 1] = -0.489251f;	val_dir[5289*3 + 2] = 0.0f;
+ 	val_dir[5290*3 + 0] = -0.875376f;	val_dir[5290*3 + 1] = -0.481457f;	val_dir[5290*3 + 2] = 0.043769f;
+ 	val_dir[5291*3 + 0] = -0.876903f;	val_dir[5291*3 + 1] = -0.472178f;	val_dir[5291*3 + 2] = 0.089939f;
+ 	val_dir[5292*3 + 0] = -0.876405f;	val_dir[5292*3 + 1] = -0.461266f;	val_dir[5292*3 + 2] = 0.138380f;
+ 	val_dir[5293*3 + 0] = -0.873555f;	val_dir[5293*3 + 1] = -0.448583f;	val_dir[5293*3 + 2] = 0.188877f;
+ 	val_dir[5294*3 + 0] = -0.868037f;	val_dir[5294*3 + 1] = -0.434019f;	val_dir[5294*3 + 2] = 0.241121f;
+ 	val_dir[5295*3 + 0] = -0.859559f;	val_dir[5295*3 + 1] = -0.41750f;	val_dir[5295*3 + 2] = 0.294706f;
+ 	val_dir[5296*3 + 0] = -0.847883f;	val_dir[5296*3 + 1] = -0.399004f;	val_dir[5296*3 + 2] = 0.349128f;
+ 	val_dir[5297*3 + 0] = -0.832845f;	val_dir[5297*3 + 1] = -0.378566f;	val_dir[5297*3 + 2] = 0.403804f;
+ 	val_dir[5298*3 + 0] = -0.814379f;	val_dir[5298*3 + 1] = -0.356291f;	val_dir[5298*3 + 2] = 0.458088f;
+ 	val_dir[5299*3 + 0] = -0.792530f;	val_dir[5299*3 + 1] = -0.332352f;	val_dir[5299*3 + 2] = 0.511310f;
+ 	val_dir[5300*3 + 0] = -0.767467f;	val_dir[5300*3 + 1] = -0.306987f;	val_dir[5300*3 + 2] = 0.562809f;
+ 	val_dir[5301*3 + 0] = -0.739469f;	val_dir[5301*3 + 1] = -0.280488f;	val_dir[5301*3 + 2] = 0.611974f;
+ 	val_dir[5302*3 + 0] = -0.708918f;	val_dir[5302*3 + 1] = -0.253185f;	val_dir[5302*3 + 2] = 0.658281f;
+ 	val_dir[5303*3 + 0] = -0.676269f;	val_dir[5303*3 + 1] = -0.225423f;	val_dir[5303*3 + 2] = 0.701316f;
+ 	val_dir[5304*3 + 0] = -0.642024f;	val_dir[5304*3 + 1] = -0.197546f;	val_dir[5304*3 + 2] = 0.740797f;
+ 	val_dir[5305*3 + 0] = -0.606696f;	val_dir[5305*3 + 1] = -0.169875f;	val_dir[5305*3 + 2] = 0.776571f;
+ 	val_dir[5306*3 + 0] = -0.570782f;	val_dir[5306*3 + 1] = -0.142695f;	val_dir[5306*3 + 2] = 0.808608f;
+ 	val_dir[5307*3 + 0] = -0.534739f;	val_dir[5307*3 + 1] = -0.116248f;	val_dir[5307*3 + 2] = 0.836983f;
+ 	val_dir[5308*3 + 0] = -0.498970f;	val_dir[5308*3 + 1] = -0.090722f;	val_dir[5308*3 + 2] = 0.861857f;
+ 	val_dir[5309*3 + 0] = -0.463812f;	val_dir[5309*3 + 1] = -0.066259f;	val_dir[5309*3 + 2] = 0.883452f;
+ 	val_dir[5310*3 + 0] = -0.429537f;	val_dir[5310*3 + 1] = -0.042954f;	val_dir[5310*3 + 2] = 0.902027f;
+ 	val_dir[5311*3 + 0] = -0.396350f;	val_dir[5311*3 + 1] = -0.020861f;	val_dir[5311*3 + 2] = 0.917863f;
+ 	val_dir[5312*3 + 0] = -0.364399f;	val_dir[5312*3 + 1] = 0.0f;	val_dir[5312*3 + 2] = 0.931243f;
+ 	val_dir[5313*3 + 0] = -0.346578f;	val_dir[5313*3 + 1] = 0.020387f;	val_dir[5313*3 + 2] = 0.93780f;
+ 	val_dir[5314*3 + 0] = -0.328244f;	val_dir[5314*3 + 1] = 0.041030f;	val_dir[5314*3 + 2] = 0.943701f;
+ 	val_dir[5315*3 + 0] = -0.309426f;	val_dir[5315*3 + 1] = 0.061885f;	val_dir[5315*3 + 2] = 0.948908f;
+ 	val_dir[5316*3 + 0] = -0.290159f;	val_dir[5316*3 + 1] = 0.082903f;	val_dir[5316*3 + 2] = 0.953381f;
+ 	val_dir[5317*3 + 0] = -0.270481f;	val_dir[5317*3 + 1] = 0.104031f;	val_dir[5317*3 + 2] = 0.957088f;
+ 	val_dir[5318*3 + 0] = -0.250435f;	val_dir[5318*3 + 1] = 0.125218f;	val_dir[5318*3 + 2] = 0.960001f;
+ 	val_dir[5319*3 + 0] = -0.230067f;	val_dir[5319*3 + 1] = 0.146406f;	val_dir[5319*3 + 2] = 0.962099f;
+ 	val_dir[5320*3 + 0] = -0.209427f;	val_dir[5320*3 + 1] = 0.167542f;	val_dir[5320*3 + 2] = 0.963364f;
+ 	val_dir[5321*3 + 0] = -0.188567f;	val_dir[5321*3 + 1] = 0.188567f;	val_dir[5321*3 + 2] = 0.963787f;
+ 	val_dir[5322*3 + 0] = -0.167542f;	val_dir[5322*3 + 1] = 0.209427f;	val_dir[5322*3 + 2] = 0.963364f;
+ 	val_dir[5323*3 + 0] = -0.146406f;	val_dir[5323*3 + 1] = 0.230067f;	val_dir[5323*3 + 2] = 0.962099f;
+ 	val_dir[5324*3 + 0] = -0.125218f;	val_dir[5324*3 + 1] = 0.250435f;	val_dir[5324*3 + 2] = 0.960001f;
+ 	val_dir[5325*3 + 0] = -0.104031f;	val_dir[5325*3 + 1] = 0.270481f;	val_dir[5325*3 + 2] = 0.957088f;
+ 	val_dir[5326*3 + 0] = -0.082903f;	val_dir[5326*3 + 1] = 0.290159f;	val_dir[5326*3 + 2] = 0.953381f;
+ 	val_dir[5327*3 + 0] = -0.061885f;	val_dir[5327*3 + 1] = 0.309426f;	val_dir[5327*3 + 2] = 0.948908f;
+ 	val_dir[5328*3 + 0] = -0.041030f;	val_dir[5328*3 + 1] = 0.328244f;	val_dir[5328*3 + 2] = 0.943701f;
+ 	val_dir[5329*3 + 0] = -0.020387f;	val_dir[5329*3 + 1] = 0.346578f;	val_dir[5329*3 + 2] = 0.93780f;
+ 	val_dir[5330*3 + 0] = 0.0f;	val_dir[5330*3 + 1] = 0.364399f;	val_dir[5330*3 + 2] = 0.931243f;
+ 	val_dir[5331*3 + 0] = 0.020861f;	val_dir[5331*3 + 1] = 0.396350f;	val_dir[5331*3 + 2] = 0.917863f;
+ 	val_dir[5332*3 + 0] = 0.042954f;	val_dir[5332*3 + 1] = 0.429537f;	val_dir[5332*3 + 2] = 0.902027f;
+ 	val_dir[5333*3 + 0] = 0.066259f;	val_dir[5333*3 + 1] = 0.463812f;	val_dir[5333*3 + 2] = 0.883452f;
+ 	val_dir[5334*3 + 0] = 0.090722f;	val_dir[5334*3 + 1] = 0.498970f;	val_dir[5334*3 + 2] = 0.861857f;
+ 	val_dir[5335*3 + 0] = 0.116248f;	val_dir[5335*3 + 1] = 0.534739f;	val_dir[5335*3 + 2] = 0.836983f;
+ 	val_dir[5336*3 + 0] = 0.142695f;	val_dir[5336*3 + 1] = 0.570782f;	val_dir[5336*3 + 2] = 0.808608f;
+ 	val_dir[5337*3 + 0] = 0.169875f;	val_dir[5337*3 + 1] = 0.606696f;	val_dir[5337*3 + 2] = 0.776571f;
+ 	val_dir[5338*3 + 0] = 0.197546f;	val_dir[5338*3 + 1] = 0.642024f;	val_dir[5338*3 + 2] = 0.740797f;
+ 	val_dir[5339*3 + 0] = 0.225423f;	val_dir[5339*3 + 1] = 0.676269f;	val_dir[5339*3 + 2] = 0.701316f;
+ 	val_dir[5340*3 + 0] = 0.253185f;	val_dir[5340*3 + 1] = 0.708918f;	val_dir[5340*3 + 2] = 0.658281f;
+ 	val_dir[5341*3 + 0] = 0.280488f;	val_dir[5341*3 + 1] = 0.739469f;	val_dir[5341*3 + 2] = 0.611974f;
+ 	val_dir[5342*3 + 0] = 0.306987f;	val_dir[5342*3 + 1] = 0.767467f;	val_dir[5342*3 + 2] = 0.562809f;
+ 	val_dir[5343*3 + 0] = 0.332352f;	val_dir[5343*3 + 1] = 0.792530f;	val_dir[5343*3 + 2] = 0.511310f;
+ 	val_dir[5344*3 + 0] = 0.356291f;	val_dir[5344*3 + 1] = 0.814379f;	val_dir[5344*3 + 2] = 0.458088f;
+ 	val_dir[5345*3 + 0] = 0.378566f;	val_dir[5345*3 + 1] = 0.832845f;	val_dir[5345*3 + 2] = 0.403804f;
+ 	val_dir[5346*3 + 0] = 0.399004f;	val_dir[5346*3 + 1] = 0.847883f;	val_dir[5346*3 + 2] = 0.349128f;
+ 	val_dir[5347*3 + 0] = 0.41750f;	val_dir[5347*3 + 1] = 0.859559f;	val_dir[5347*3 + 2] = 0.294706f;
+ 	val_dir[5348*3 + 0] = 0.434019f;	val_dir[5348*3 + 1] = 0.868037f;	val_dir[5348*3 + 2] = 0.241121f;
+ 	val_dir[5349*3 + 0] = 0.448583f;	val_dir[5349*3 + 1] = 0.873555f;	val_dir[5349*3 + 2] = 0.188877f;
+ 	val_dir[5350*3 + 0] = 0.461266f;	val_dir[5350*3 + 1] = 0.876405f;	val_dir[5350*3 + 2] = 0.138380f;
+ 	val_dir[5351*3 + 0] = 0.472178f;	val_dir[5351*3 + 1] = 0.876903f;	val_dir[5351*3 + 2] = 0.089939f;
+ 	val_dir[5352*3 + 0] = 0.481457f;	val_dir[5352*3 + 1] = 0.875376f;	val_dir[5352*3 + 2] = 0.043769f;
+ 	val_dir[5353*3 + 0] = 0.489251f;	val_dir[5353*3 + 1] = 0.872143f;	val_dir[5353*3 + 2] = 0.0f;
+ 	val_dir[5354*3 + 0] = -0.880957f;	val_dir[5354*3 + 1] = -0.472709f;	val_dir[5354*3 + 2] = 0.021487f;
+ 	val_dir[5355*3 + 0] = -0.883452f;	val_dir[5355*3 + 1] = -0.463812f;	val_dir[5355*3 + 2] = 0.066259f;
+ 	val_dir[5356*3 + 0] = -0.884083f;	val_dir[5356*3 + 1] = -0.453376f;	val_dir[5356*3 + 2] = 0.113344f;
+ 	val_dir[5357*3 + 0] = -0.882528f;	val_dir[5357*3 + 1] = -0.441264f;	val_dir[5357*3 + 2] = 0.162571f;
+ 	val_dir[5358*3 + 0] = -0.878466f;	val_dir[5358*3 + 1] = -0.427362f;	val_dir[5358*3 + 2] = 0.213681f;
+ 	val_dir[5359*3 + 0] = -0.871592f;	val_dir[5359*3 + 1] = -0.411585f;	val_dir[5359*3 + 2] = 0.266320f;
+ 	val_dir[5360*3 + 0] = -0.861640f;	val_dir[5360*3 + 1] = -0.393893f;	val_dir[5360*3 + 2] = 0.320038f;
+ 	val_dir[5361*3 + 0] = -0.848411f;	val_dir[5361*3 + 1] = -0.374299f;	val_dir[5361*3 + 2] = 0.374299f;
+ 	val_dir[5362*3 + 0] = -0.831786f;	val_dir[5362*3 + 1] = -0.352879f;	val_dir[5362*3 + 2] = 0.428496f;
+ 	val_dir[5363*3 + 0] = -0.811754f;	val_dir[5363*3 + 1] = -0.329775f;	val_dir[5363*3 + 2] = 0.481979f;
+ 	val_dir[5364*3 + 0] = -0.788419f;	val_dir[5364*3 + 1] = -0.305194f;	val_dir[5364*3 + 2] = 0.534090f;
+ 	val_dir[5365*3 + 0] = -0.762001f;	val_dir[5365*3 + 1] = -0.27940f;	val_dir[5365*3 + 2] = 0.584201f;
+ 	val_dir[5366*3 + 0] = -0.732828f;	val_dir[5366*3 + 1] = -0.252699f;	val_dir[5366*3 + 2] = 0.631748f;
+ 	val_dir[5367*3 + 0] = -0.701316f;	val_dir[5367*3 + 1] = -0.225423f;	val_dir[5367*3 + 2] = 0.676269f;
+ 	val_dir[5368*3 + 0] = -0.667940f;	val_dir[5368*3 + 1] = -0.197908f;	val_dir[5368*3 + 2] = 0.717418f;
+ 	val_dir[5369*3 + 0] = -0.633205f;	val_dir[5369*3 + 1] = -0.170478f;	val_dir[5369*3 + 2] = 0.754976f;
+ 	val_dir[5370*3 + 0] = -0.597614f;	val_dir[5370*3 + 1] = -0.143427f;	val_dir[5370*3 + 2] = 0.788851f;
+ 	val_dir[5371*3 + 0] = -0.561644f;	val_dir[5371*3 + 1] = -0.117009f;	val_dir[5371*3 + 2] = 0.819064f;
+ 	val_dir[5372*3 + 0] = -0.525723f;	val_dir[5372*3 + 1] = -0.091430f;	val_dir[5372*3 + 2] = 0.845728f;
+ 	val_dir[5373*3 + 0] = -0.490222f;	val_dir[5373*3 + 1] = -0.066848f;	val_dir[5373*3 + 2] = 0.869030f;
+ 	val_dir[5374*3 + 0] = -0.455447f;	val_dir[5374*3 + 1] = -0.043376f;	val_dir[5374*3 + 2] = 0.889206f;
+ 	val_dir[5375*3 + 0] = -0.421637f;	val_dir[5375*3 + 1] = -0.021082f;	val_dir[5375*3 + 2] = 0.906520f;
+ 	val_dir[5376*3 + 0] = -0.388972f;	val_dir[5376*3 + 1] = 0.0f;	val_dir[5376*3 + 2] = 0.921250f;
+ 	val_dir[5377*3 + 0] = -0.371312f;	val_dir[5377*3 + 1] = 0.020628f;	val_dir[5377*3 + 2] = 0.928279f;
+ 	val_dir[5378*3 + 0] = -0.353096f;	val_dir[5378*3 + 1] = 0.041541f;	val_dir[5378*3 + 2] = 0.934665f;
+ 	val_dir[5379*3 + 0] = -0.334351f;	val_dir[5379*3 + 1] = 0.062691f;	val_dir[5379*3 + 2] = 0.940361f;
+ 	val_dir[5380*3 + 0] = -0.315109f;	val_dir[5380*3 + 1] = 0.084029f;	val_dir[5380*3 + 2] = 0.945328f;
+ 	val_dir[5381*3 + 0] = -0.295409f;	val_dir[5381*3 + 1] = 0.105503f;	val_dir[5381*3 + 2] = 0.949528f;
+ 	val_dir[5382*3 + 0] = -0.275290f;	val_dir[5382*3 + 1] = 0.127057f;	val_dir[5382*3 + 2] = 0.952928f;
+ 	val_dir[5383*3 + 0] = -0.254801f;	val_dir[5383*3 + 1] = 0.148634f;	val_dir[5383*3 + 2] = 0.955502f;
+ 	val_dir[5384*3 + 0] = -0.233990f;	val_dir[5384*3 + 1] = 0.170174f;	val_dir[5384*3 + 2] = 0.957230f;
+ 	val_dir[5385*3 + 0] = -0.212911f;	val_dir[5385*3 + 1] = 0.191620f;	val_dir[5385*3 + 2] = 0.958098f;
+ 	val_dir[5386*3 + 0] = -0.191620f;	val_dir[5386*3 + 1] = 0.212911f;	val_dir[5386*3 + 2] = 0.958098f;
+ 	val_dir[5387*3 + 0] = -0.170174f;	val_dir[5387*3 + 1] = 0.233990f;	val_dir[5387*3 + 2] = 0.957230f;
+ 	val_dir[5388*3 + 0] = -0.148634f;	val_dir[5388*3 + 1] = 0.254801f;	val_dir[5388*3 + 2] = 0.955502f;
+ 	val_dir[5389*3 + 0] = -0.127057f;	val_dir[5389*3 + 1] = 0.275290f;	val_dir[5389*3 + 2] = 0.952928f;
+ 	val_dir[5390*3 + 0] = -0.105503f;	val_dir[5390*3 + 1] = 0.295409f;	val_dir[5390*3 + 2] = 0.949528f;
+ 	val_dir[5391*3 + 0] = -0.084029f;	val_dir[5391*3 + 1] = 0.315109f;	val_dir[5391*3 + 2] = 0.945328f;
+ 	val_dir[5392*3 + 0] = -0.062691f;	val_dir[5392*3 + 1] = 0.334351f;	val_dir[5392*3 + 2] = 0.940361f;
+ 	val_dir[5393*3 + 0] = -0.041541f;	val_dir[5393*3 + 1] = 0.353096f;	val_dir[5393*3 + 2] = 0.934665f;
+ 	val_dir[5394*3 + 0] = -0.020628f;	val_dir[5394*3 + 1] = 0.371312f;	val_dir[5394*3 + 2] = 0.928279f;
+ 	val_dir[5395*3 + 0] = 0.0f;	val_dir[5395*3 + 1] = 0.388972f;	val_dir[5395*3 + 2] = 0.921250f;
+ 	val_dir[5396*3 + 0] = 0.021082f;	val_dir[5396*3 + 1] = 0.421637f;	val_dir[5396*3 + 2] = 0.906520f;
+ 	val_dir[5397*3 + 0] = 0.043376f;	val_dir[5397*3 + 1] = 0.455447f;	val_dir[5397*3 + 2] = 0.889206f;
+ 	val_dir[5398*3 + 0] = 0.066848f;	val_dir[5398*3 + 1] = 0.490222f;	val_dir[5398*3 + 2] = 0.869030f;
+ 	val_dir[5399*3 + 0] = 0.091430f;	val_dir[5399*3 + 1] = 0.525723f;	val_dir[5399*3 + 2] = 0.845728f;
+ 	val_dir[5400*3 + 0] = 0.117009f;	val_dir[5400*3 + 1] = 0.561644f;	val_dir[5400*3 + 2] = 0.819064f;
+ 	val_dir[5401*3 + 0] = 0.143427f;	val_dir[5401*3 + 1] = 0.597614f;	val_dir[5401*3 + 2] = 0.788851f;
+ 	val_dir[5402*3 + 0] = 0.170478f;	val_dir[5402*3 + 1] = 0.633205f;	val_dir[5402*3 + 2] = 0.754976f;
+ 	val_dir[5403*3 + 0] = 0.197908f;	val_dir[5403*3 + 1] = 0.667940f;	val_dir[5403*3 + 2] = 0.717418f;
+ 	val_dir[5404*3 + 0] = 0.225423f;	val_dir[5404*3 + 1] = 0.701316f;	val_dir[5404*3 + 2] = 0.676269f;
+ 	val_dir[5405*3 + 0] = 0.252699f;	val_dir[5405*3 + 1] = 0.732828f;	val_dir[5405*3 + 2] = 0.631748f;
+ 	val_dir[5406*3 + 0] = 0.27940f;	val_dir[5406*3 + 1] = 0.762001f;	val_dir[5406*3 + 2] = 0.584201f;
+ 	val_dir[5407*3 + 0] = 0.305194f;	val_dir[5407*3 + 1] = 0.788419f;	val_dir[5407*3 + 2] = 0.534090f;
+ 	val_dir[5408*3 + 0] = 0.329775f;	val_dir[5408*3 + 1] = 0.811754f;	val_dir[5408*3 + 2] = 0.481979f;
+ 	val_dir[5409*3 + 0] = 0.352879f;	val_dir[5409*3 + 1] = 0.831786f;	val_dir[5409*3 + 2] = 0.428496f;
+ 	val_dir[5410*3 + 0] = 0.374299f;	val_dir[5410*3 + 1] = 0.848411f;	val_dir[5410*3 + 2] = 0.374299f;
+ 	val_dir[5411*3 + 0] = 0.393893f;	val_dir[5411*3 + 1] = 0.861640f;	val_dir[5411*3 + 2] = 0.320038f;
+ 	val_dir[5412*3 + 0] = 0.411585f;	val_dir[5412*3 + 1] = 0.871592f;	val_dir[5412*3 + 2] = 0.266320f;
+ 	val_dir[5413*3 + 0] = 0.427362f;	val_dir[5413*3 + 1] = 0.878466f;	val_dir[5413*3 + 2] = 0.213681f;
+ 	val_dir[5414*3 + 0] = 0.441264f;	val_dir[5414*3 + 1] = 0.882528f;	val_dir[5414*3 + 2] = 0.162571f;
+ 	val_dir[5415*3 + 0] = 0.453376f;	val_dir[5415*3 + 1] = 0.884083f;	val_dir[5415*3 + 2] = 0.113344f;
+ 	val_dir[5416*3 + 0] = 0.463812f;	val_dir[5416*3 + 1] = 0.883452f;	val_dir[5416*3 + 2] = 0.066259f;
+ 	val_dir[5417*3 + 0] = 0.472709f;	val_dir[5417*3 + 1] = 0.880957f;	val_dir[5417*3 + 2] = 0.021487f;
+ 	val_dir[5418*3 + 0] = -0.885832f;	val_dir[5418*3 + 1] = -0.464007f;	val_dir[5418*3 + 2] = 0.0f;
+ 	val_dir[5419*3 + 0] = -0.889206f;	val_dir[5419*3 + 1] = -0.455447f;	val_dir[5419*3 + 2] = 0.043376f;
+ 	val_dir[5420*3 + 0] = -0.890871f;	val_dir[5420*3 + 1] = -0.445435f;	val_dir[5420*3 + 2] = 0.089087f;
+ 	val_dir[5421*3 + 0] = -0.890513f;	val_dir[5421*3 + 1] = -0.433840f;	val_dir[5421*3 + 2] = 0.137002f;
+ 	val_dir[5422*3 + 0] = -0.887812f;	val_dir[5422*3 + 1] = -0.420542f;	val_dir[5422*3 + 2] = 0.186908f;
+ 	val_dir[5423*3 + 0] = -0.882454f;	val_dir[5423*3 + 1] = -0.405452f;	val_dir[5423*3 + 2] = 0.238501f;
+ 	val_dir[5424*3 + 0] = -0.874157f;	val_dir[5424*3 + 1] = -0.388514f;	val_dir[5424*3 + 2] = 0.291386f;
+ 	val_dir[5425*3 + 0] = -0.862687f;	val_dir[5425*3 + 1] = -0.369723f;	val_dir[5425*3 + 2] = 0.345075f;
+ 	val_dir[5426*3 + 0] = -0.847883f;	val_dir[5426*3 + 1] = -0.349128f;	val_dir[5426*3 + 2] = 0.399004f;
+ 	val_dir[5427*3 + 0] = -0.829680f;	val_dir[5427*3 + 1] = -0.326844f;	val_dir[5427*3 + 2] = 0.452553f;
+ 	val_dir[5428*3 + 0] = -0.808122f;	val_dir[5428*3 + 1] = -0.303046f;	val_dir[5428*3 + 2] = 0.505076f;
+ 	val_dir[5429*3 + 0] = -0.783368f;	val_dir[5429*3 + 1] = -0.277969f;	val_dir[5429*3 + 2] = 0.555939f;
+ 	val_dir[5430*3 + 0] = -0.755689f;	val_dir[5430*3 + 1] = -0.251896f;	val_dir[5430*3 + 2] = 0.604551f;
+ 	val_dir[5431*3 + 0] = -0.725454f;	val_dir[5431*3 + 1] = -0.225141f;	val_dir[5431*3 + 2] = 0.650407f;
+ 	val_dir[5432*3 + 0] = -0.693103f;	val_dir[5432*3 + 1] = -0.198030f;	val_dir[5432*3 + 2] = 0.693103f;
+ 	val_dir[5433*3 + 0] = -0.659125f;	val_dir[5433*3 + 1] = -0.170884f;	val_dir[5433*3 + 2] = 0.732361f;
+ 	val_dir[5434*3 + 0] = -0.624020f;	val_dir[5434*3 + 1] = -0.144005f;	val_dir[5434*3 + 2] = 0.768025f;
+ 	val_dir[5435*3 + 0] = -0.588276f;	val_dir[5435*3 + 1] = -0.117655f;	val_dir[5435*3 + 2] = 0.800055f;
+ 	val_dir[5436*3 + 0] = -0.552345f;	val_dir[5436*3 + 1] = -0.092057f;	val_dir[5436*3 + 2] = 0.828517f;
+ 	val_dir[5437*3 + 0] = -0.516626f;	val_dir[5437*3 + 1] = -0.067386f;	val_dir[5437*3 + 2] = 0.853556f;
+ 	val_dir[5438*3 + 0] = -0.481457f;	val_dir[5438*3 + 1] = -0.043769f;	val_dir[5438*3 + 2] = 0.875376f;
+ 	val_dir[5439*3 + 0] = -0.447112f;	val_dir[5439*3 + 1] = -0.021291f;	val_dir[5439*3 + 2] = 0.894224f;
+ 	val_dir[5440*3 + 0] = -0.413803f;	val_dir[5440*3 + 1] = 0.0f;	val_dir[5440*3 + 2] = 0.910366f;
+ 	val_dir[5441*3 + 0] = -0.396350f;	val_dir[5441*3 + 1] = 0.020861f;	val_dir[5441*3 + 2] = 0.917863f;
+ 	val_dir[5442*3 + 0] = -0.378298f;	val_dir[5442*3 + 1] = 0.042033f;	val_dir[5442*3 + 2] = 0.924729f;
+ 	val_dir[5443*3 + 0] = -0.359673f;	val_dir[5443*3 + 1] = 0.063472f;	val_dir[5443*3 + 2] = 0.930917f;
+ 	val_dir[5444*3 + 0] = -0.340503f;	val_dir[5444*3 + 1] = 0.085126f;	val_dir[5444*3 + 2] = 0.936382f;
+ 	val_dir[5445*3 + 0] = -0.320824f;	val_dir[5445*3 + 1] = 0.106941f;	val_dir[5445*3 + 2] = 0.941082f;
+ 	val_dir[5446*3 + 0] = -0.300676f;	val_dir[5446*3 + 1] = 0.128861f;	val_dir[5446*3 + 2] = 0.944981f;
+ 	val_dir[5447*3 + 0] = -0.280105f;	val_dir[5447*3 + 1] = 0.150826f;	val_dir[5447*3 + 2] = 0.948047f;
+ 	val_dir[5448*3 + 0] = -0.259161f;	val_dir[5448*3 + 1] = 0.172774f;	val_dir[5448*3 + 2] = 0.950255f;
+ 	val_dir[5449*3 + 0] = -0.237897f;	val_dir[5449*3 + 1] = 0.194643f;	val_dir[5449*3 + 2] = 0.951588f;
+ 	val_dir[5450*3 + 0] = -0.216371f;	val_dir[5450*3 + 1] = 0.216371f;	val_dir[5450*3 + 2] = 0.952033f;
+ 	val_dir[5451*3 + 0] = -0.194643f;	val_dir[5451*3 + 1] = 0.237897f;	val_dir[5451*3 + 2] = 0.951588f;
+ 	val_dir[5452*3 + 0] = -0.172774f;	val_dir[5452*3 + 1] = 0.259161f;	val_dir[5452*3 + 2] = 0.950255f;
+ 	val_dir[5453*3 + 0] = -0.150826f;	val_dir[5453*3 + 1] = 0.280105f;	val_dir[5453*3 + 2] = 0.948047f;
+ 	val_dir[5454*3 + 0] = -0.128861f;	val_dir[5454*3 + 1] = 0.300676f;	val_dir[5454*3 + 2] = 0.944981f;
+ 	val_dir[5455*3 + 0] = -0.106941f;	val_dir[5455*3 + 1] = 0.320824f;	val_dir[5455*3 + 2] = 0.941082f;
+ 	val_dir[5456*3 + 0] = -0.085126f;	val_dir[5456*3 + 1] = 0.340503f;	val_dir[5456*3 + 2] = 0.936382f;
+ 	val_dir[5457*3 + 0] = -0.063472f;	val_dir[5457*3 + 1] = 0.359673f;	val_dir[5457*3 + 2] = 0.930917f;
+ 	val_dir[5458*3 + 0] = -0.042033f;	val_dir[5458*3 + 1] = 0.378298f;	val_dir[5458*3 + 2] = 0.924729f;
+ 	val_dir[5459*3 + 0] = -0.020861f;	val_dir[5459*3 + 1] = 0.396350f;	val_dir[5459*3 + 2] = 0.917863f;
+ 	val_dir[5460*3 + 0] = 0.0f;	val_dir[5460*3 + 1] = 0.413803f;	val_dir[5460*3 + 2] = 0.910366f;
+ 	val_dir[5461*3 + 0] = 0.021291f;	val_dir[5461*3 + 1] = 0.447112f;	val_dir[5461*3 + 2] = 0.894224f;
+ 	val_dir[5462*3 + 0] = 0.043769f;	val_dir[5462*3 + 1] = 0.481457f;	val_dir[5462*3 + 2] = 0.875376f;
+ 	val_dir[5463*3 + 0] = 0.067386f;	val_dir[5463*3 + 1] = 0.516626f;	val_dir[5463*3 + 2] = 0.853556f;
+ 	val_dir[5464*3 + 0] = 0.092057f;	val_dir[5464*3 + 1] = 0.552345f;	val_dir[5464*3 + 2] = 0.828517f;
+ 	val_dir[5465*3 + 0] = 0.117655f;	val_dir[5465*3 + 1] = 0.588276f;	val_dir[5465*3 + 2] = 0.800055f;
+ 	val_dir[5466*3 + 0] = 0.144005f;	val_dir[5466*3 + 1] = 0.624020f;	val_dir[5466*3 + 2] = 0.768025f;
+ 	val_dir[5467*3 + 0] = 0.170884f;	val_dir[5467*3 + 1] = 0.659125f;	val_dir[5467*3 + 2] = 0.732361f;
+ 	val_dir[5468*3 + 0] = 0.198030f;	val_dir[5468*3 + 1] = 0.693103f;	val_dir[5468*3 + 2] = 0.693103f;
+ 	val_dir[5469*3 + 0] = 0.225141f;	val_dir[5469*3 + 1] = 0.725454f;	val_dir[5469*3 + 2] = 0.650407f;
+ 	val_dir[5470*3 + 0] = 0.251896f;	val_dir[5470*3 + 1] = 0.755689f;	val_dir[5470*3 + 2] = 0.604551f;
+ 	val_dir[5471*3 + 0] = 0.277969f;	val_dir[5471*3 + 1] = 0.783368f;	val_dir[5471*3 + 2] = 0.555939f;
+ 	val_dir[5472*3 + 0] = 0.303046f;	val_dir[5472*3 + 1] = 0.808122f;	val_dir[5472*3 + 2] = 0.505076f;
+ 	val_dir[5473*3 + 0] = 0.326844f;	val_dir[5473*3 + 1] = 0.829680f;	val_dir[5473*3 + 2] = 0.452553f;
+ 	val_dir[5474*3 + 0] = 0.349128f;	val_dir[5474*3 + 1] = 0.847883f;	val_dir[5474*3 + 2] = 0.399004f;
+ 	val_dir[5475*3 + 0] = 0.369723f;	val_dir[5475*3 + 1] = 0.862687f;	val_dir[5475*3 + 2] = 0.345075f;
+ 	val_dir[5476*3 + 0] = 0.388514f;	val_dir[5476*3 + 1] = 0.874157f;	val_dir[5476*3 + 2] = 0.291386f;
+ 	val_dir[5477*3 + 0] = 0.405452f;	val_dir[5477*3 + 1] = 0.882454f;	val_dir[5477*3 + 2] = 0.238501f;
+ 	val_dir[5478*3 + 0] = 0.420542f;	val_dir[5478*3 + 1] = 0.887812f;	val_dir[5478*3 + 2] = 0.186908f;
+ 	val_dir[5479*3 + 0] = 0.433840f;	val_dir[5479*3 + 1] = 0.890513f;	val_dir[5479*3 + 2] = 0.137002f;
+ 	val_dir[5480*3 + 0] = 0.445435f;	val_dir[5480*3 + 1] = 0.890871f;	val_dir[5480*3 + 2] = 0.089087f;
+ 	val_dir[5481*3 + 0] = 0.455447f;	val_dir[5481*3 + 1] = 0.889206f;	val_dir[5481*3 + 2] = 0.043376f;
+ 	val_dir[5482*3 + 0] = 0.464007f;	val_dir[5482*3 + 1] = 0.885832f;	val_dir[5482*3 + 2] = 0.0f;
+ 	val_dir[5483*3 + 0] = -0.894224f;	val_dir[5483*3 + 1] = -0.447112f;	val_dir[5483*3 + 2] = 0.021291f;
+ 	val_dir[5484*3 + 0] = -0.896831f;	val_dir[5484*3 + 1] = -0.437479f;	val_dir[5484*3 + 2] = 0.065622f;
+ 	val_dir[5485*3 + 0] = -0.897574f;	val_dir[5485*3 + 1] = -0.426348f;	val_dir[5485*3 + 2] = 0.112197f;
+ 	val_dir[5486*3 + 0] = -0.896137f;	val_dir[5486*3 + 1] = -0.413602f;	val_dir[5486*3 + 2] = 0.160845f;
+ 	val_dir[5487*3 + 0] = -0.892206f;	val_dir[5487*3 + 1] = -0.399145f;	val_dir[5487*3 + 2] = 0.211312f;
+ 	val_dir[5488*3 + 0] = -0.885482f;	val_dir[5488*3 + 1] = -0.382911f;	val_dir[5488*3 + 2] = 0.263251f;
+ 	val_dir[5489*3 + 0] = -0.875708f;	val_dir[5489*3 + 1] = -0.364878f;	val_dir[5489*3 + 2] = 0.316228f;
+ 	val_dir[5490*3 + 0] = -0.862687f;	val_dir[5490*3 + 1] = -0.345075f;	val_dir[5490*3 + 2] = 0.369723f;
+ 	val_dir[5491*3 + 0] = -0.846305f;	val_dir[5491*3 + 1] = -0.323587f;	val_dir[5491*3 + 2] = 0.423153f;
+ 	val_dir[5492*3 + 0] = -0.826551f;	val_dir[5492*3 + 1] = -0.300564f;	val_dir[5492*3 + 2] = 0.475893f;
+ 	val_dir[5493*3 + 0] = -0.803523f;	val_dir[5493*3 + 1] = -0.276211f;	val_dir[5493*3 + 2] = 0.527312f;
+ 	val_dir[5494*3 + 0] = -0.777433f;	val_dir[5494*3 + 1] = -0.250785f;	val_dir[5494*3 + 2] = 0.576805f;
+ 	val_dir[5495*3 + 0] = -0.748598f;	val_dir[5495*3 + 1] = -0.224579f;	val_dir[5495*3 + 2] = 0.623831f;
+ 	val_dir[5496*3 + 0] = -0.717418f;	val_dir[5496*3 + 1] = -0.197908f;	val_dir[5496*3 + 2] = 0.667940f;
+ 	val_dir[5497*3 + 0] = -0.684353f;	val_dir[5497*3 + 1] = -0.171088f;	val_dir[5497*3 + 2] = 0.708794f;
+ 	val_dir[5498*3 + 0] = -0.649895f;	val_dir[5498*3 + 1] = -0.144421f;	val_dir[5498*3 + 2] = 0.746176f;
+ 	val_dir[5499*3 + 0] = -0.614535f;	val_dir[5499*3 + 1] = -0.118180f;	val_dir[5499*3 + 2] = 0.779987f;
+ 	val_dir[5500*3 + 0] = -0.578741f;	val_dir[5500*3 + 1] = -0.092599f;	val_dir[5500*3 + 2] = 0.810237f;
+ 	val_dir[5501*3 + 0] = -0.542936f;	val_dir[5501*3 + 1] = -0.067867f;	val_dir[5501*3 + 2] = 0.837027f;
+ 	val_dir[5502*3 + 0] = -0.507490f;	val_dir[5502*3 + 1] = -0.044130f;	val_dir[5502*3 + 2] = 0.860527f;
+ 	val_dir[5503*3 + 0] = -0.472709f;	val_dir[5503*3 + 1] = -0.021487f;	val_dir[5503*3 + 2] = 0.880957f;
+ 	val_dir[5504*3 + 0] = -0.438835f;	val_dir[5504*3 + 1] = 0.0f;	val_dir[5504*3 + 2] = 0.898567f;
+ 	val_dir[5505*3 + 0] = -0.421637f;	val_dir[5505*3 + 1] = 0.021082f;	val_dir[5505*3 + 2] = 0.906520f;
+ 	val_dir[5506*3 + 0] = -0.403799f;	val_dir[5506*3 + 1] = 0.042505f;	val_dir[5506*3 + 2] = 0.913860f;
+ 	val_dir[5507*3 + 0] = -0.385341f;	val_dir[5507*3 + 1] = 0.064223f;	val_dir[5507*3 + 2] = 0.920537f;
+ 	val_dir[5508*3 + 0] = -0.366291f;	val_dir[5508*3 + 1] = 0.086186f;	val_dir[5508*3 + 2] = 0.92650f;
+ 	val_dir[5509*3 + 0] = -0.346681f;	val_dir[5509*3 + 1] = 0.108338f;	val_dir[5509*3 + 2] = 0.931705f;
+ 	val_dir[5510*3 + 0] = -0.326550f;	val_dir[5510*3 + 1] = 0.130620f;	val_dir[5510*3 + 2] = 0.936111f;
+ 	val_dir[5511*3 + 0] = -0.305942f;	val_dir[5511*3 + 1] = 0.152971f;	val_dir[5511*3 + 2] = 0.939680f;
+ 	val_dir[5512*3 + 0] = -0.284907f;	val_dir[5512*3 + 1] = 0.175327f;	val_dir[5512*3 + 2] = 0.942384f;
+ 	val_dir[5513*3 + 0] = -0.263498f;	val_dir[5513*3 + 1] = 0.197623f;	val_dir[5513*3 + 2] = 0.94420f;
+ 	val_dir[5514*3 + 0] = -0.241773f;	val_dir[5514*3 + 1] = 0.219793f;	val_dir[5514*3 + 2] = 0.945112f;
+ 	val_dir[5515*3 + 0] = -0.219793f;	val_dir[5515*3 + 1] = 0.241773f;	val_dir[5515*3 + 2] = 0.945112f;
+ 	val_dir[5516*3 + 0] = -0.197623f;	val_dir[5516*3 + 1] = 0.263498f;	val_dir[5516*3 + 2] = 0.94420f;
+ 	val_dir[5517*3 + 0] = -0.175327f;	val_dir[5517*3 + 1] = 0.284907f;	val_dir[5517*3 + 2] = 0.942384f;
+ 	val_dir[5518*3 + 0] = -0.152971f;	val_dir[5518*3 + 1] = 0.305942f;	val_dir[5518*3 + 2] = 0.939680f;
+ 	val_dir[5519*3 + 0] = -0.130620f;	val_dir[5519*3 + 1] = 0.326550f;	val_dir[5519*3 + 2] = 0.936111f;
+ 	val_dir[5520*3 + 0] = -0.108338f;	val_dir[5520*3 + 1] = 0.346681f;	val_dir[5520*3 + 2] = 0.931705f;
+ 	val_dir[5521*3 + 0] = -0.086186f;	val_dir[5521*3 + 1] = 0.366291f;	val_dir[5521*3 + 2] = 0.92650f;
+ 	val_dir[5522*3 + 0] = -0.064223f;	val_dir[5522*3 + 1] = 0.385341f;	val_dir[5522*3 + 2] = 0.920537f;
+ 	val_dir[5523*3 + 0] = -0.042505f;	val_dir[5523*3 + 1] = 0.403799f;	val_dir[5523*3 + 2] = 0.913860f;
+ 	val_dir[5524*3 + 0] = -0.021082f;	val_dir[5524*3 + 1] = 0.421637f;	val_dir[5524*3 + 2] = 0.906520f;
+ 	val_dir[5525*3 + 0] = 0.0f;	val_dir[5525*3 + 1] = 0.438835f;	val_dir[5525*3 + 2] = 0.898567f;
+ 	val_dir[5526*3 + 0] = 0.021487f;	val_dir[5526*3 + 1] = 0.472709f;	val_dir[5526*3 + 2] = 0.880957f;
+ 	val_dir[5527*3 + 0] = 0.044130f;	val_dir[5527*3 + 1] = 0.507490f;	val_dir[5527*3 + 2] = 0.860527f;
+ 	val_dir[5528*3 + 0] = 0.067867f;	val_dir[5528*3 + 1] = 0.542936f;	val_dir[5528*3 + 2] = 0.837027f;
+ 	val_dir[5529*3 + 0] = 0.092599f;	val_dir[5529*3 + 1] = 0.578741f;	val_dir[5529*3 + 2] = 0.810237f;
+ 	val_dir[5530*3 + 0] = 0.118180f;	val_dir[5530*3 + 1] = 0.614535f;	val_dir[5530*3 + 2] = 0.779987f;
+ 	val_dir[5531*3 + 0] = 0.144421f;	val_dir[5531*3 + 1] = 0.649895f;	val_dir[5531*3 + 2] = 0.746176f;
+ 	val_dir[5532*3 + 0] = 0.171088f;	val_dir[5532*3 + 1] = 0.684353f;	val_dir[5532*3 + 2] = 0.708794f;
+ 	val_dir[5533*3 + 0] = 0.197908f;	val_dir[5533*3 + 1] = 0.717418f;	val_dir[5533*3 + 2] = 0.667940f;
+ 	val_dir[5534*3 + 0] = 0.224579f;	val_dir[5534*3 + 1] = 0.748598f;	val_dir[5534*3 + 2] = 0.623831f;
+ 	val_dir[5535*3 + 0] = 0.250785f;	val_dir[5535*3 + 1] = 0.777433f;	val_dir[5535*3 + 2] = 0.576805f;
+ 	val_dir[5536*3 + 0] = 0.276211f;	val_dir[5536*3 + 1] = 0.803523f;	val_dir[5536*3 + 2] = 0.527312f;
+ 	val_dir[5537*3 + 0] = 0.300564f;	val_dir[5537*3 + 1] = 0.826551f;	val_dir[5537*3 + 2] = 0.475893f;
+ 	val_dir[5538*3 + 0] = 0.323587f;	val_dir[5538*3 + 1] = 0.846305f;	val_dir[5538*3 + 2] = 0.423153f;
+ 	val_dir[5539*3 + 0] = 0.345075f;	val_dir[5539*3 + 1] = 0.862687f;	val_dir[5539*3 + 2] = 0.369723f;
+ 	val_dir[5540*3 + 0] = 0.364878f;	val_dir[5540*3 + 1] = 0.875708f;	val_dir[5540*3 + 2] = 0.316228f;
+ 	val_dir[5541*3 + 0] = 0.382911f;	val_dir[5541*3 + 1] = 0.885482f;	val_dir[5541*3 + 2] = 0.263251f;
+ 	val_dir[5542*3 + 0] = 0.399145f;	val_dir[5542*3 + 1] = 0.892206f;	val_dir[5542*3 + 2] = 0.211312f;
+ 	val_dir[5543*3 + 0] = 0.413602f;	val_dir[5543*3 + 1] = 0.896137f;	val_dir[5543*3 + 2] = 0.160845f;
+ 	val_dir[5544*3 + 0] = 0.426348f;	val_dir[5544*3 + 1] = 0.897574f;	val_dir[5544*3 + 2] = 0.112197f;
+ 	val_dir[5545*3 + 0] = 0.437479f;	val_dir[5545*3 + 1] = 0.896831f;	val_dir[5545*3 + 2] = 0.065622f;
+ 	val_dir[5546*3 + 0] = 0.447112f;	val_dir[5546*3 + 1] = 0.894224f;	val_dir[5546*3 + 2] = 0.021291f;
+ 	val_dir[5547*3 + 0] = -0.898567f;	val_dir[5547*3 + 1] = -0.438835f;	val_dir[5547*3 + 2] = 0.0f;
+ 	val_dir[5548*3 + 0] = -0.902027f;	val_dir[5548*3 + 1] = -0.429537f;	val_dir[5548*3 + 2] = 0.042954f;
+ 	val_dir[5549*3 + 0] = -0.903777f;	val_dir[5549*3 + 1] = -0.418823f;	val_dir[5549*3 + 2] = 0.088173f;
+ 	val_dir[5550*3 + 0] = -0.903508f;	val_dir[5550*3 + 1] = -0.406579f;	val_dir[5550*3 + 2] = 0.135526f;
+ 	val_dir[5551*3 + 0] = -0.900907f;	val_dir[5551*3 + 1] = -0.392703f;	val_dir[5551*3 + 2] = 0.184801f;
+ 	val_dir[5552*3 + 0] = -0.895669f;	val_dir[5552*3 + 1] = -0.377124f;	val_dir[5552*3 + 2] = 0.235702f;
+ 	val_dir[5553*3 + 0] = -0.887517f;	val_dir[5553*3 + 1] = -0.359804f;	val_dir[5553*3 + 2] = 0.287843f;
+ 	val_dir[5554*3 + 0] = -0.876226f;	val_dir[5554*3 + 1] = -0.340755f;	val_dir[5554*3 + 2] = 0.340755f;
+ 	val_dir[5555*3 + 0] = -0.861640f;	val_dir[5555*3 + 1] = -0.320038f;	val_dir[5555*3 + 2] = 0.393893f;
+ 	val_dir[5556*3 + 0] = -0.843696f;	val_dir[5556*3 + 1] = -0.297775f;	val_dir[5556*3 + 2] = 0.446662f;
+ 	val_dir[5557*3 + 0] = -0.822434f;	val_dir[5557*3 + 1] = -0.274145f;	val_dir[5557*3 + 2] = 0.498445f;
+ 	val_dir[5558*3 + 0] = -0.798007f;	val_dir[5558*3 + 1] = -0.249377f;	val_dir[5558*3 + 2] = 0.548630f;
+ 	val_dir[5559*3 + 0] = -0.770677f;	val_dir[5559*3 + 1] = -0.223745f;	val_dir[5559*3 + 2] = 0.596653f;
+ 	val_dir[5560*3 + 0] = -0.740797f;	val_dir[5560*3 + 1] = -0.197546f;	val_dir[5560*3 + 2] = 0.642024f;
+ 	val_dir[5561*3 + 0] = -0.708794f;	val_dir[5561*3 + 1] = -0.171088f;	val_dir[5561*3 + 2] = 0.684353f;
+ 	val_dir[5562*3 + 0] = -0.675140f;	val_dir[5562*3 + 1] = -0.144673f;	val_dir[5562*3 + 2] = 0.723364f;
+ 	val_dir[5563*3 + 0] = -0.640321f;	val_dir[5563*3 + 1] = -0.118578f;	val_dir[5563*3 + 2] = 0.758899f;
+ 	val_dir[5564*3 + 0] = -0.604815f;	val_dir[5564*3 + 1] = -0.093048f;	val_dir[5564*3 + 2] = 0.790912f;
+ 	val_dir[5565*3 + 0] = -0.569064f;	val_dir[5565*3 + 1] = -0.068288f;	val_dir[5565*3 + 2] = 0.819453f;
+ 	val_dir[5566*3 + 0] = -0.533465f;	val_dir[5566*3 + 1] = -0.044455f;	val_dir[5566*3 + 2] = 0.844653f;
+ 	val_dir[5567*3 + 0] = -0.498354f;	val_dir[5567*3 + 1] = -0.021668f;	val_dir[5567*3 + 2] = 0.866703f;
+ 	val_dir[5568*3 + 0] = -0.464007f;	val_dir[5568*3 + 1] = 0.0f;	val_dir[5568*3 + 2] = 0.885832f;
+ 	val_dir[5569*3 + 0] = -0.447112f;	val_dir[5569*3 + 1] = 0.021291f;	val_dir[5569*3 + 2] = 0.894224f;
+ 	val_dir[5570*3 + 0] = -0.429537f;	val_dir[5570*3 + 1] = 0.042954f;	val_dir[5570*3 + 2] = 0.902027f;
+ 	val_dir[5571*3 + 0] = -0.411298f;	val_dir[5571*3 + 1] = 0.064942f;	val_dir[5571*3 + 2] = 0.909185f;
+ 	val_dir[5572*3 + 0] = -0.392419f;	val_dir[5572*3 + 1] = 0.087204f;	val_dir[5572*3 + 2] = 0.915644f;
+ 	val_dir[5573*3 + 0] = -0.372929f;	val_dir[5573*3 + 1] = 0.109685f;	val_dir[5573*3 + 2] = 0.921354f;
+ 	val_dir[5574*3 + 0] = -0.352865f;	val_dir[5574*3 + 1] = 0.132324f;	val_dir[5574*3 + 2] = 0.926270f;
+ 	val_dir[5575*3 + 0] = -0.332269f;	val_dir[5575*3 + 1] = 0.155059f;	val_dir[5575*3 + 2] = 0.930352f;
+ 	val_dir[5576*3 + 0] = -0.311188f;	val_dir[5576*3 + 1] = 0.177822f;	val_dir[5576*3 + 2] = 0.933564f;
+ 	val_dir[5577*3 + 0] = -0.289677f;	val_dir[5577*3 + 1] = 0.200545f;	val_dir[5577*3 + 2] = 0.935879f;
+ 	val_dir[5578*3 + 0] = -0.267793f;	val_dir[5578*3 + 1] = 0.223161f;	val_dir[5578*3 + 2] = 0.937276f;
+ 	val_dir[5579*3 + 0] = -0.245599f;	val_dir[5579*3 + 1] = 0.245599f;	val_dir[5579*3 + 2] = 0.937743f;
+ 	val_dir[5580*3 + 0] = -0.223161f;	val_dir[5580*3 + 1] = 0.267793f;	val_dir[5580*3 + 2] = 0.937276f;
+ 	val_dir[5581*3 + 0] = -0.200545f;	val_dir[5581*3 + 1] = 0.289677f;	val_dir[5581*3 + 2] = 0.935879f;
+ 	val_dir[5582*3 + 0] = -0.177822f;	val_dir[5582*3 + 1] = 0.311188f;	val_dir[5582*3 + 2] = 0.933564f;
+ 	val_dir[5583*3 + 0] = -0.155059f;	val_dir[5583*3 + 1] = 0.332269f;	val_dir[5583*3 + 2] = 0.930352f;
+ 	val_dir[5584*3 + 0] = -0.132324f;	val_dir[5584*3 + 1] = 0.352865f;	val_dir[5584*3 + 2] = 0.926270f;
+ 	val_dir[5585*3 + 0] = -0.109685f;	val_dir[5585*3 + 1] = 0.372929f;	val_dir[5585*3 + 2] = 0.921354f;
+ 	val_dir[5586*3 + 0] = -0.087204f;	val_dir[5586*3 + 1] = 0.392419f;	val_dir[5586*3 + 2] = 0.915644f;
+ 	val_dir[5587*3 + 0] = -0.064942f;	val_dir[5587*3 + 1] = 0.411298f;	val_dir[5587*3 + 2] = 0.909185f;
+ 	val_dir[5588*3 + 0] = -0.042954f;	val_dir[5588*3 + 1] = 0.429537f;	val_dir[5588*3 + 2] = 0.902027f;
+ 	val_dir[5589*3 + 0] = -0.021291f;	val_dir[5589*3 + 1] = 0.447112f;	val_dir[5589*3 + 2] = 0.894224f;
+ 	val_dir[5590*3 + 0] = 0.0f;	val_dir[5590*3 + 1] = 0.464007f;	val_dir[5590*3 + 2] = 0.885832f;
+ 	val_dir[5591*3 + 0] = 0.021668f;	val_dir[5591*3 + 1] = 0.498354f;	val_dir[5591*3 + 2] = 0.866703f;
+ 	val_dir[5592*3 + 0] = 0.044455f;	val_dir[5592*3 + 1] = 0.533465f;	val_dir[5592*3 + 2] = 0.844653f;
+ 	val_dir[5593*3 + 0] = 0.068288f;	val_dir[5593*3 + 1] = 0.569064f;	val_dir[5593*3 + 2] = 0.819453f;
+ 	val_dir[5594*3 + 0] = 0.093048f;	val_dir[5594*3 + 1] = 0.604815f;	val_dir[5594*3 + 2] = 0.790912f;
+ 	val_dir[5595*3 + 0] = 0.118578f;	val_dir[5595*3 + 1] = 0.640321f;	val_dir[5595*3 + 2] = 0.758899f;
+ 	val_dir[5596*3 + 0] = 0.144673f;	val_dir[5596*3 + 1] = 0.675140f;	val_dir[5596*3 + 2] = 0.723364f;
+ 	val_dir[5597*3 + 0] = 0.171088f;	val_dir[5597*3 + 1] = 0.708794f;	val_dir[5597*3 + 2] = 0.684353f;
+ 	val_dir[5598*3 + 0] = 0.197546f;	val_dir[5598*3 + 1] = 0.740797f;	val_dir[5598*3 + 2] = 0.642024f;
+ 	val_dir[5599*3 + 0] = 0.223745f;	val_dir[5599*3 + 1] = 0.770677f;	val_dir[5599*3 + 2] = 0.596653f;
+ 	val_dir[5600*3 + 0] = 0.249377f;	val_dir[5600*3 + 1] = 0.798007f;	val_dir[5600*3 + 2] = 0.548630f;
+ 	val_dir[5601*3 + 0] = 0.274145f;	val_dir[5601*3 + 1] = 0.822434f;	val_dir[5601*3 + 2] = 0.498445f;
+ 	val_dir[5602*3 + 0] = 0.297775f;	val_dir[5602*3 + 1] = 0.843696f;	val_dir[5602*3 + 2] = 0.446662f;
+ 	val_dir[5603*3 + 0] = 0.320038f;	val_dir[5603*3 + 1] = 0.861640f;	val_dir[5603*3 + 2] = 0.393893f;
+ 	val_dir[5604*3 + 0] = 0.340755f;	val_dir[5604*3 + 1] = 0.876226f;	val_dir[5604*3 + 2] = 0.340755f;
+ 	val_dir[5605*3 + 0] = 0.359804f;	val_dir[5605*3 + 1] = 0.887517f;	val_dir[5605*3 + 2] = 0.287843f;
+ 	val_dir[5606*3 + 0] = 0.377124f;	val_dir[5606*3 + 1] = 0.895669f;	val_dir[5606*3 + 2] = 0.235702f;
+ 	val_dir[5607*3 + 0] = 0.392703f;	val_dir[5607*3 + 1] = 0.900907f;	val_dir[5607*3 + 2] = 0.184801f;
+ 	val_dir[5608*3 + 0] = 0.406579f;	val_dir[5608*3 + 1] = 0.903508f;	val_dir[5608*3 + 2] = 0.135526f;
+ 	val_dir[5609*3 + 0] = 0.418823f;	val_dir[5609*3 + 1] = 0.903777f;	val_dir[5609*3 + 2] = 0.088173f;
+ 	val_dir[5610*3 + 0] = 0.429537f;	val_dir[5610*3 + 1] = 0.902027f;	val_dir[5610*3 + 2] = 0.042954f;
+ 	val_dir[5611*3 + 0] = 0.438835f;	val_dir[5611*3 + 1] = 0.898567f;	val_dir[5611*3 + 2] = 0.0f;
+ 	val_dir[5612*3 + 0] = -0.906520f;	val_dir[5612*3 + 1] = -0.421637f;	val_dir[5612*3 + 2] = 0.021082f;
+ 	val_dir[5613*3 + 0] = -0.909185f;	val_dir[5613*3 + 1] = -0.411298f;	val_dir[5613*3 + 2] = 0.064942f;
+ 	val_dir[5614*3 + 0] = -0.909988f;	val_dir[5614*3 + 1] = -0.399507f;	val_dir[5614*3 + 2] = 0.110974f;
+ 	val_dir[5615*3 + 0] = -0.908622f;	val_dir[5615*3 + 1] = -0.386164f;	val_dir[5615*3 + 2] = 0.159009f;
+ 	val_dir[5616*3 + 0] = -0.904777f;	val_dir[5616*3 + 1] = -0.371191f;	val_dir[5616*3 + 2] = 0.208795f;
+ 	val_dir[5617*3 + 0] = -0.898167f;	val_dir[5617*3 + 1] = -0.354540f;	val_dir[5617*3 + 2] = 0.259996f;
+ 	val_dir[5618*3 + 0] = -0.888540f;	val_dir[5618*3 + 1] = -0.336204f;	val_dir[5618*3 + 2] = 0.312190f;
+ 	val_dir[5619*3 + 0] = -0.875708f;	val_dir[5619*3 + 1] = -0.316228f;	val_dir[5619*3 + 2] = 0.364878f;
+ 	val_dir[5620*3 + 0] = -0.859559f;	val_dir[5620*3 + 1] = -0.294706f;	val_dir[5620*3 + 2] = 0.41750f;
+ 	val_dir[5621*3 + 0] = -0.840083f;	val_dir[5621*3 + 1] = -0.271791f;	val_dir[5621*3 + 2] = 0.469458f;
+ 	val_dir[5622*3 + 0] = -0.817373f;	val_dir[5622*3 + 1] = -0.247689f;	val_dir[5622*3 + 2] = 0.520146f;
+ 	val_dir[5623*3 + 0] = -0.791633f;	val_dir[5623*3 + 1] = -0.222647f;	val_dir[5623*3 + 2] = 0.568986f;
+ 	val_dir[5624*3 + 0] = -0.763167f;	val_dir[5624*3 + 1] = -0.196946f;	val_dir[5624*3 + 2] = 0.615457f;
+ 	val_dir[5625*3 + 0] = -0.732361f;	val_dir[5625*3 + 1] = -0.170884f;	val_dir[5625*3 + 2] = 0.659125f;
+ 	val_dir[5626*3 + 0] = -0.699659f;	val_dir[5626*3 + 1] = -0.144757f;	val_dir[5626*3 + 2] = 0.699659f;
+ 	val_dir[5627*3 + 0] = -0.665536f;	val_dir[5627*3 + 1] = -0.118846f;	val_dir[5627*3 + 2] = 0.736843f;
+ 	val_dir[5628*3 + 0] = -0.630470f;	val_dir[5628*3 + 1] = -0.093403f;	val_dir[5628*3 + 2] = 0.770574f;
+ 	val_dir[5629*3 + 0] = -0.594917f;	val_dir[5629*3 + 1] = -0.068644f;	val_dir[5629*3 + 2] = 0.800850f;
+ 	val_dir[5630*3 + 0] = -0.559297f;	val_dir[5630*3 + 1] = -0.044744f;	val_dir[5630*3 + 2] = 0.827759f;
+ 	val_dir[5631*3 + 0] = -0.523973f;	val_dir[5631*3 + 1] = -0.021832f;	val_dir[5631*3 + 2] = 0.851455f;
+ 	val_dir[5632*3 + 0] = -0.489251f;	val_dir[5632*3 + 1] = 0.0f;	val_dir[5632*3 + 2] = 0.872143f;
+ 	val_dir[5633*3 + 0] = -0.472709f;	val_dir[5633*3 + 1] = 0.021487f;	val_dir[5633*3 + 2] = 0.880957f;
+ 	val_dir[5634*3 + 0] = -0.455447f;	val_dir[5634*3 + 1] = 0.043376f;	val_dir[5634*3 + 2] = 0.889206f;
+ 	val_dir[5635*3 + 0] = -0.437479f;	val_dir[5635*3 + 1] = 0.065622f;	val_dir[5635*3 + 2] = 0.896831f;
+ 	val_dir[5636*3 + 0] = -0.418823f;	val_dir[5636*3 + 1] = 0.088173f;	val_dir[5636*3 + 2] = 0.903777f;
+ 	val_dir[5637*3 + 0] = -0.399507f;	val_dir[5637*3 + 1] = 0.110974f;	val_dir[5637*3 + 2] = 0.909988f;
+ 	val_dir[5638*3 + 0] = -0.379563f;	val_dir[5638*3 + 1] = 0.133963f;	val_dir[5638*3 + 2] = 0.915416f;
+ 	val_dir[5639*3 + 0] = -0.359030f;	val_dir[5639*3 + 1] = 0.157075f;	val_dir[5639*3 + 2] = 0.920014f;
+ 	val_dir[5640*3 + 0] = -0.337954f;	val_dir[5640*3 + 1] = 0.180242f;	val_dir[5640*3 + 2] = 0.923742f;
+ 	val_dir[5641*3 + 0] = -0.316389f;	val_dir[5641*3 + 1] = 0.203393f;	val_dir[5641*3 + 2] = 0.926568f;
+ 	val_dir[5642*3 + 0] = -0.294392f;	val_dir[5642*3 + 1] = 0.226455f;	val_dir[5642*3 + 2] = 0.928467f;
+ 	val_dir[5643*3 + 0] = -0.272026f;	val_dir[5643*3 + 1] = 0.249357f;	val_dir[5643*3 + 2] = 0.929421f;
+ 	val_dir[5644*3 + 0] = -0.249357f;	val_dir[5644*3 + 1] = 0.272026f;	val_dir[5644*3 + 2] = 0.929421f;
+ 	val_dir[5645*3 + 0] = -0.226455f;	val_dir[5645*3 + 1] = 0.294392f;	val_dir[5645*3 + 2] = 0.928467f;
+ 	val_dir[5646*3 + 0] = -0.203393f;	val_dir[5646*3 + 1] = 0.316389f;	val_dir[5646*3 + 2] = 0.926568f;
+ 	val_dir[5647*3 + 0] = -0.180242f;	val_dir[5647*3 + 1] = 0.337954f;	val_dir[5647*3 + 2] = 0.923742f;
+ 	val_dir[5648*3 + 0] = -0.157075f;	val_dir[5648*3 + 1] = 0.359030f;	val_dir[5648*3 + 2] = 0.920014f;
+ 	val_dir[5649*3 + 0] = -0.133963f;	val_dir[5649*3 + 1] = 0.379563f;	val_dir[5649*3 + 2] = 0.915416f;
+ 	val_dir[5650*3 + 0] = -0.110974f;	val_dir[5650*3 + 1] = 0.399507f;	val_dir[5650*3 + 2] = 0.909988f;
+ 	val_dir[5651*3 + 0] = -0.088173f;	val_dir[5651*3 + 1] = 0.418823f;	val_dir[5651*3 + 2] = 0.903777f;
+ 	val_dir[5652*3 + 0] = -0.065622f;	val_dir[5652*3 + 1] = 0.437479f;	val_dir[5652*3 + 2] = 0.896831f;
+ 	val_dir[5653*3 + 0] = -0.043376f;	val_dir[5653*3 + 1] = 0.455447f;	val_dir[5653*3 + 2] = 0.889206f;
+ 	val_dir[5654*3 + 0] = -0.021487f;	val_dir[5654*3 + 1] = 0.472709f;	val_dir[5654*3 + 2] = 0.880957f;
+ 	val_dir[5655*3 + 0] = 0.0f;	val_dir[5655*3 + 1] = 0.489251f;	val_dir[5655*3 + 2] = 0.872143f;
+ 	val_dir[5656*3 + 0] = 0.021832f;	val_dir[5656*3 + 1] = 0.523973f;	val_dir[5656*3 + 2] = 0.851455f;
+ 	val_dir[5657*3 + 0] = 0.044744f;	val_dir[5657*3 + 1] = 0.559297f;	val_dir[5657*3 + 2] = 0.827759f;
+ 	val_dir[5658*3 + 0] = 0.068644f;	val_dir[5658*3 + 1] = 0.594917f;	val_dir[5658*3 + 2] = 0.800850f;
+ 	val_dir[5659*3 + 0] = 0.093403f;	val_dir[5659*3 + 1] = 0.630470f;	val_dir[5659*3 + 2] = 0.770574f;
+ 	val_dir[5660*3 + 0] = 0.118846f;	val_dir[5660*3 + 1] = 0.665536f;	val_dir[5660*3 + 2] = 0.736843f;
+ 	val_dir[5661*3 + 0] = 0.144757f;	val_dir[5661*3 + 1] = 0.699659f;	val_dir[5661*3 + 2] = 0.699659f;
+ 	val_dir[5662*3 + 0] = 0.170884f;	val_dir[5662*3 + 1] = 0.732361f;	val_dir[5662*3 + 2] = 0.659125f;
+ 	val_dir[5663*3 + 0] = 0.196946f;	val_dir[5663*3 + 1] = 0.763167f;	val_dir[5663*3 + 2] = 0.615457f;
+ 	val_dir[5664*3 + 0] = 0.222647f;	val_dir[5664*3 + 1] = 0.791633f;	val_dir[5664*3 + 2] = 0.568986f;
+ 	val_dir[5665*3 + 0] = 0.247689f;	val_dir[5665*3 + 1] = 0.817373f;	val_dir[5665*3 + 2] = 0.520146f;
+ 	val_dir[5666*3 + 0] = 0.271791f;	val_dir[5666*3 + 1] = 0.840083f;	val_dir[5666*3 + 2] = 0.469458f;
+ 	val_dir[5667*3 + 0] = 0.294706f;	val_dir[5667*3 + 1] = 0.859559f;	val_dir[5667*3 + 2] = 0.41750f;
+ 	val_dir[5668*3 + 0] = 0.316228f;	val_dir[5668*3 + 1] = 0.875708f;	val_dir[5668*3 + 2] = 0.364878f;
+ 	val_dir[5669*3 + 0] = 0.336204f;	val_dir[5669*3 + 1] = 0.888540f;	val_dir[5669*3 + 2] = 0.312190f;
+ 	val_dir[5670*3 + 0] = 0.354540f;	val_dir[5670*3 + 1] = 0.898167f;	val_dir[5670*3 + 2] = 0.259996f;
+ 	val_dir[5671*3 + 0] = 0.371191f;	val_dir[5671*3 + 1] = 0.904777f;	val_dir[5671*3 + 2] = 0.208795f;
+ 	val_dir[5672*3 + 0] = 0.386164f;	val_dir[5672*3 + 1] = 0.908622f;	val_dir[5672*3 + 2] = 0.159009f;
+ 	val_dir[5673*3 + 0] = 0.399507f;	val_dir[5673*3 + 1] = 0.909988f;	val_dir[5673*3 + 2] = 0.110974f;
+ 	val_dir[5674*3 + 0] = 0.411298f;	val_dir[5674*3 + 1] = 0.909185f;	val_dir[5674*3 + 2] = 0.064942f;
+ 	val_dir[5675*3 + 0] = 0.421637f;	val_dir[5675*3 + 1] = 0.906520f;	val_dir[5675*3 + 2] = 0.021082f;
+ 	val_dir[5676*3 + 0] = -0.910366f;	val_dir[5676*3 + 1] = -0.413803f;	val_dir[5676*3 + 2] = 0.0f;
+ 	val_dir[5677*3 + 0] = -0.913860f;	val_dir[5677*3 + 1] = -0.403799f;	val_dir[5677*3 + 2] = 0.042505f;
+ 	val_dir[5678*3 + 0] = -0.915644f;	val_dir[5678*3 + 1] = -0.392419f;	val_dir[5678*3 + 2] = 0.087204f;
+ 	val_dir[5679*3 + 0] = -0.915416f;	val_dir[5679*3 + 1] = -0.379563f;	val_dir[5679*3 + 2] = 0.133963f;
+ 	val_dir[5680*3 + 0] = -0.912871f;	val_dir[5680*3 + 1] = -0.365148f;	val_dir[5680*3 + 2] = 0.182574f;
+ 	val_dir[5681*3 + 0] = -0.907713f;	val_dir[5681*3 + 1] = -0.349121f;	val_dir[5681*3 + 2] = 0.232747f;
+ 	val_dir[5682*3 + 0] = -0.899676f;	val_dir[5682*3 + 1] = -0.331460f;	val_dir[5682*3 + 2] = 0.284108f;
+ 	val_dir[5683*3 + 0] = -0.888540f;	val_dir[5683*3 + 1] = -0.312190f;	val_dir[5683*3 + 2] = 0.336204f;
+ 	val_dir[5684*3 + 0] = -0.874157f;	val_dir[5684*3 + 1] = -0.291386f;	val_dir[5684*3 + 2] = 0.388514f;
+ 	val_dir[5685*3 + 0] = -0.856465f;	val_dir[5685*3 + 1] = -0.269175f;	val_dir[5685*3 + 2] = 0.440468f;
+ 	val_dir[5686*3 + 0] = -0.835504f;	val_dir[5686*3 + 1] = -0.245737f;	val_dir[5686*3 + 2] = 0.491473f;
+ 	val_dir[5687*3 + 0] = -0.811421f;	val_dir[5687*3 + 1] = -0.221297f;	val_dir[5687*3 + 2] = 0.540947f;
+ 	val_dir[5688*3 + 0] = -0.784465f;	val_dir[5688*3 + 1] = -0.196116f;	val_dir[5688*3 + 2] = 0.588348f;
+ 	val_dir[5689*3 + 0] = -0.754976f;	val_dir[5689*3 + 1] = -0.170478f;	val_dir[5689*3 + 2] = 0.633205f;
+ 	val_dir[5690*3 + 0] = -0.723364f;	val_dir[5690*3 + 1] = -0.144673f;	val_dir[5690*3 + 2] = 0.675140f;
+ 	val_dir[5691*3 + 0] = -0.690085f;	val_dir[5691*3 + 1] = -0.118980f;	val_dir[5691*3 + 2] = 0.713881f;
+ 	val_dir[5692*3 + 0] = -0.655610f;	val_dir[5692*3 + 1] = -0.093659f;	val_dir[5692*3 + 2] = 0.749269f;
+ 	val_dir[5693*3 + 0] = -0.620403f;	val_dir[5693*3 + 1] = -0.068934f;	val_dir[5693*3 + 2] = 0.781248f;
+ 	val_dir[5694*3 + 0] = -0.584898f;	val_dir[5694*3 + 1] = -0.044992f;	val_dir[5694*3 + 2] = 0.809858f;
+ 	val_dir[5695*3 + 0] = -0.549484f;	val_dir[5695*3 + 1] = -0.021979f;	val_dir[5695*3 + 2] = 0.835215f;
+ 	val_dir[5696*3 + 0] = -0.514496f;	val_dir[5696*3 + 1] = 0.0f;	val_dir[5696*3 + 2] = 0.857493f;
+ 	val_dir[5697*3 + 0] = -0.498354f;	val_dir[5697*3 + 1] = 0.021668f;	val_dir[5697*3 + 2] = 0.866703f;
+ 	val_dir[5698*3 + 0] = -0.481457f;	val_dir[5698*3 + 1] = 0.043769f;	val_dir[5698*3 + 2] = 0.875376f;
+ 	val_dir[5699*3 + 0] = -0.463812f;	val_dir[5699*3 + 1] = 0.066259f;	val_dir[5699*3 + 2] = 0.883452f;
+ 	val_dir[5700*3 + 0] = -0.445435f;	val_dir[5700*3 + 1] = 0.089087f;	val_dir[5700*3 + 2] = 0.890871f;
+ 	val_dir[5701*3 + 0] = -0.426348f;	val_dir[5701*3 + 1] = 0.112197f;	val_dir[5701*3 + 2] = 0.897574f;
+ 	val_dir[5702*3 + 0] = -0.406579f;	val_dir[5702*3 + 1] = 0.135526f;	val_dir[5702*3 + 2] = 0.903508f;
+ 	val_dir[5703*3 + 0] = -0.386164f;	val_dir[5703*3 + 1] = 0.159009f;	val_dir[5703*3 + 2] = 0.908622f;
+ 	val_dir[5704*3 + 0] = -0.365148f;	val_dir[5704*3 + 1] = 0.182574f;	val_dir[5704*3 + 2] = 0.912871f;
+ 	val_dir[5705*3 + 0] = -0.343582f;	val_dir[5705*3 + 1] = 0.206149f;	val_dir[5705*3 + 2] = 0.916217f;
+ 	val_dir[5706*3 + 0] = -0.321521f;	val_dir[5706*3 + 1] = 0.229658f;	val_dir[5706*3 + 2] = 0.918630f;
+ 	val_dir[5707*3 + 0] = -0.299028f;	val_dir[5707*3 + 1] = 0.253024f;	val_dir[5707*3 + 2] = 0.920087f;
+ 	val_dir[5708*3 + 0] = -0.276172f;	val_dir[5708*3 + 1] = 0.276172f;	val_dir[5708*3 + 2] = 0.920575f;
+ 	val_dir[5709*3 + 0] = -0.253024f;	val_dir[5709*3 + 1] = 0.299028f;	val_dir[5709*3 + 2] = 0.920087f;
+ 	val_dir[5710*3 + 0] = -0.229658f;	val_dir[5710*3 + 1] = 0.321521f;	val_dir[5710*3 + 2] = 0.918630f;
+ 	val_dir[5711*3 + 0] = -0.206149f;	val_dir[5711*3 + 1] = 0.343582f;	val_dir[5711*3 + 2] = 0.916217f;
+ 	val_dir[5712*3 + 0] = -0.182574f;	val_dir[5712*3 + 1] = 0.365148f;	val_dir[5712*3 + 2] = 0.912871f;
+ 	val_dir[5713*3 + 0] = -0.159009f;	val_dir[5713*3 + 1] = 0.386164f;	val_dir[5713*3 + 2] = 0.908622f;
+ 	val_dir[5714*3 + 0] = -0.135526f;	val_dir[5714*3 + 1] = 0.406579f;	val_dir[5714*3 + 2] = 0.903508f;
+ 	val_dir[5715*3 + 0] = -0.112197f;	val_dir[5715*3 + 1] = 0.426348f;	val_dir[5715*3 + 2] = 0.897574f;
+ 	val_dir[5716*3 + 0] = -0.089087f;	val_dir[5716*3 + 1] = 0.445435f;	val_dir[5716*3 + 2] = 0.890871f;
+ 	val_dir[5717*3 + 0] = -0.066259f;	val_dir[5717*3 + 1] = 0.463812f;	val_dir[5717*3 + 2] = 0.883452f;
+ 	val_dir[5718*3 + 0] = -0.043769f;	val_dir[5718*3 + 1] = 0.481457f;	val_dir[5718*3 + 2] = 0.875376f;
+ 	val_dir[5719*3 + 0] = -0.021668f;	val_dir[5719*3 + 1] = 0.498354f;	val_dir[5719*3 + 2] = 0.866703f;
+ 	val_dir[5720*3 + 0] = 0.0f;	val_dir[5720*3 + 1] = 0.514496f;	val_dir[5720*3 + 2] = 0.857493f;
+ 	val_dir[5721*3 + 0] = 0.021979f;	val_dir[5721*3 + 1] = 0.549484f;	val_dir[5721*3 + 2] = 0.835215f;
+ 	val_dir[5722*3 + 0] = 0.044992f;	val_dir[5722*3 + 1] = 0.584898f;	val_dir[5722*3 + 2] = 0.809858f;
+ 	val_dir[5723*3 + 0] = 0.068934f;	val_dir[5723*3 + 1] = 0.620403f;	val_dir[5723*3 + 2] = 0.781248f;
+ 	val_dir[5724*3 + 0] = 0.093659f;	val_dir[5724*3 + 1] = 0.655610f;	val_dir[5724*3 + 2] = 0.749269f;
+ 	val_dir[5725*3 + 0] = 0.118980f;	val_dir[5725*3 + 1] = 0.690085f;	val_dir[5725*3 + 2] = 0.713881f;
+ 	val_dir[5726*3 + 0] = 0.144673f;	val_dir[5726*3 + 1] = 0.723364f;	val_dir[5726*3 + 2] = 0.675140f;
+ 	val_dir[5727*3 + 0] = 0.170478f;	val_dir[5727*3 + 1] = 0.754976f;	val_dir[5727*3 + 2] = 0.633205f;
+ 	val_dir[5728*3 + 0] = 0.196116f;	val_dir[5728*3 + 1] = 0.784465f;	val_dir[5728*3 + 2] = 0.588348f;
+ 	val_dir[5729*3 + 0] = 0.221297f;	val_dir[5729*3 + 1] = 0.811421f;	val_dir[5729*3 + 2] = 0.540947f;
+ 	val_dir[5730*3 + 0] = 0.245737f;	val_dir[5730*3 + 1] = 0.835504f;	val_dir[5730*3 + 2] = 0.491473f;
+ 	val_dir[5731*3 + 0] = 0.269175f;	val_dir[5731*3 + 1] = 0.856465f;	val_dir[5731*3 + 2] = 0.440468f;
+ 	val_dir[5732*3 + 0] = 0.291386f;	val_dir[5732*3 + 1] = 0.874157f;	val_dir[5732*3 + 2] = 0.388514f;
+ 	val_dir[5733*3 + 0] = 0.312190f;	val_dir[5733*3 + 1] = 0.888540f;	val_dir[5733*3 + 2] = 0.336204f;
+ 	val_dir[5734*3 + 0] = 0.331460f;	val_dir[5734*3 + 1] = 0.899676f;	val_dir[5734*3 + 2] = 0.284108f;
+ 	val_dir[5735*3 + 0] = 0.349121f;	val_dir[5735*3 + 1] = 0.907713f;	val_dir[5735*3 + 2] = 0.232747f;
+ 	val_dir[5736*3 + 0] = 0.365148f;	val_dir[5736*3 + 1] = 0.912871f;	val_dir[5736*3 + 2] = 0.182574f;
+ 	val_dir[5737*3 + 0] = 0.379563f;	val_dir[5737*3 + 1] = 0.915416f;	val_dir[5737*3 + 2] = 0.133963f;
+ 	val_dir[5738*3 + 0] = 0.392419f;	val_dir[5738*3 + 1] = 0.915644f;	val_dir[5738*3 + 2] = 0.087204f;
+ 	val_dir[5739*3 + 0] = 0.403799f;	val_dir[5739*3 + 1] = 0.913860f;	val_dir[5739*3 + 2] = 0.042505f;
+ 	val_dir[5740*3 + 0] = 0.413803f;	val_dir[5740*3 + 1] = 0.910366f;	val_dir[5740*3 + 2] = 0.0f;
+ 	val_dir[5741*3 + 0] = -0.917863f;	val_dir[5741*3 + 1] = -0.396350f;	val_dir[5741*3 + 2] = 0.020861f;
+ 	val_dir[5742*3 + 0] = -0.920537f;	val_dir[5742*3 + 1] = -0.385341f;	val_dir[5742*3 + 2] = 0.064223f;
+ 	val_dir[5743*3 + 0] = -0.921354f;	val_dir[5743*3 + 1] = -0.372929f;	val_dir[5743*3 + 2] = 0.109685f;
+ 	val_dir[5744*3 + 0] = -0.920014f;	val_dir[5744*3 + 1] = -0.359030f;	val_dir[5744*3 + 2] = 0.157075f;
+ 	val_dir[5745*3 + 0] = -0.916217f;	val_dir[5745*3 + 1] = -0.343582f;	val_dir[5745*3 + 2] = 0.206149f;
+ 	val_dir[5746*3 + 0] = -0.909687f;	val_dir[5746*3 + 1] = -0.326554f;	val_dir[5746*3 + 2] = 0.256578f;
+ 	val_dir[5747*3 + 0] = -0.900181f;	val_dir[5747*3 + 1] = -0.307957f;	val_dir[5747*3 + 2] = 0.307957f;
+ 	val_dir[5748*3 + 0] = -0.887517f;	val_dir[5748*3 + 1] = -0.287843f;	val_dir[5748*3 + 2] = 0.359804f;
+ 	val_dir[5749*3 + 0] = -0.871592f;	val_dir[5749*3 + 1] = -0.266320f;	val_dir[5749*3 + 2] = 0.411585f;
+ 	val_dir[5750*3 + 0] = -0.852392f;	val_dir[5750*3 + 1] = -0.243541f;	val_dir[5750*3 + 2] = 0.462727f;
+ 	val_dir[5751*3 + 0] = -0.830009f;	val_dir[5751*3 + 1] = -0.219708f;	val_dir[5751*3 + 2] = 0.512653f;
+ 	val_dir[5752*3 + 0] = -0.804639f;	val_dir[5752*3 + 1] = -0.195064f;	val_dir[5752*3 + 2] = 0.560809f;
+ 	val_dir[5753*3 + 0] = -0.776571f;	val_dir[5753*3 + 1] = -0.169875f;	val_dir[5753*3 + 2] = 0.606696f;
+ 	val_dir[5754*3 + 0] = -0.746176f;	val_dir[5754*3 + 1] = -0.144421f;	val_dir[5754*3 + 2] = 0.649895f;
+ 	val_dir[5755*3 + 0] = -0.713881f;	val_dir[5755*3 + 1] = -0.118980f;	val_dir[5755*3 + 2] = 0.690085f;
+ 	val_dir[5756*3 + 0] = -0.680144f;	val_dir[5756*3 + 1] = -0.093813f;	val_dir[5756*3 + 2] = 0.727051f;
+ 	val_dir[5757*3 + 0] = -0.645429f;	val_dir[5757*3 + 1] = -0.069153f;	val_dir[5757*3 + 2] = 0.760684f;
+ 	val_dir[5758*3 + 0] = -0.610179f;	val_dir[5758*3 + 1] = -0.045198f;	val_dir[5758*3 + 2] = 0.790973f;
+ 	val_dir[5759*3 + 0] = -0.574805f;	val_dir[5759*3 + 1] = -0.022108f;	val_dir[5759*3 + 2] = 0.817992f;
+ 	val_dir[5760*3 + 0] = -0.539666f;	val_dir[5760*3 + 1] = 0.0f;	val_dir[5760*3 + 2] = 0.841879f;
+ 	val_dir[5761*3 + 0] = -0.523973f;	val_dir[5761*3 + 1] = 0.021832f;	val_dir[5761*3 + 2] = 0.851455f;
+ 	val_dir[5762*3 + 0] = -0.507490f;	val_dir[5762*3 + 1] = 0.044130f;	val_dir[5762*3 + 2] = 0.860527f;
+ 	val_dir[5763*3 + 0] = -0.490222f;	val_dir[5763*3 + 1] = 0.066848f;	val_dir[5763*3 + 2] = 0.869030f;
+ 	val_dir[5764*3 + 0] = -0.472178f;	val_dir[5764*3 + 1] = 0.089939f;	val_dir[5764*3 + 2] = 0.876903f;
+ 	val_dir[5765*3 + 0] = -0.453376f;	val_dir[5765*3 + 1] = 0.113344f;	val_dir[5765*3 + 2] = 0.884083f;
+ 	val_dir[5766*3 + 0] = -0.433840f;	val_dir[5766*3 + 1] = 0.137002f;	val_dir[5766*3 + 2] = 0.890513f;
+ 	val_dir[5767*3 + 0] = -0.413602f;	val_dir[5767*3 + 1] = 0.160845f;	val_dir[5767*3 + 2] = 0.896137f;
+ 	val_dir[5768*3 + 0] = -0.392703f;	val_dir[5768*3 + 1] = 0.184801f;	val_dir[5768*3 + 2] = 0.900907f;
+ 	val_dir[5769*3 + 0] = -0.371191f;	val_dir[5769*3 + 1] = 0.208795f;	val_dir[5769*3 + 2] = 0.904777f;
+ 	val_dir[5770*3 + 0] = -0.349121f;	val_dir[5770*3 + 1] = 0.232747f;	val_dir[5770*3 + 2] = 0.907713f;
+ 	val_dir[5771*3 + 0] = -0.326554f;	val_dir[5771*3 + 1] = 0.256578f;	val_dir[5771*3 + 2] = 0.909687f;
+ 	val_dir[5772*3 + 0] = -0.303559f;	val_dir[5772*3 + 1] = 0.280209f;	val_dir[5772*3 + 2] = 0.910678f;
+ 	val_dir[5773*3 + 0] = -0.280209f;	val_dir[5773*3 + 1] = 0.303559f;	val_dir[5773*3 + 2] = 0.910678f;
+ 	val_dir[5774*3 + 0] = -0.256578f;	val_dir[5774*3 + 1] = 0.326554f;	val_dir[5774*3 + 2] = 0.909687f;
+ 	val_dir[5775*3 + 0] = -0.232747f;	val_dir[5775*3 + 1] = 0.349121f;	val_dir[5775*3 + 2] = 0.907713f;
+ 	val_dir[5776*3 + 0] = -0.208795f;	val_dir[5776*3 + 1] = 0.371191f;	val_dir[5776*3 + 2] = 0.904777f;
+ 	val_dir[5777*3 + 0] = -0.184801f;	val_dir[5777*3 + 1] = 0.392703f;	val_dir[5777*3 + 2] = 0.900907f;
+ 	val_dir[5778*3 + 0] = -0.160845f;	val_dir[5778*3 + 1] = 0.413602f;	val_dir[5778*3 + 2] = 0.896137f;
+ 	val_dir[5779*3 + 0] = -0.137002f;	val_dir[5779*3 + 1] = 0.433840f;	val_dir[5779*3 + 2] = 0.890513f;
+ 	val_dir[5780*3 + 0] = -0.113344f;	val_dir[5780*3 + 1] = 0.453376f;	val_dir[5780*3 + 2] = 0.884083f;
+ 	val_dir[5781*3 + 0] = -0.089939f;	val_dir[5781*3 + 1] = 0.472178f;	val_dir[5781*3 + 2] = 0.876903f;
+ 	val_dir[5782*3 + 0] = -0.066848f;	val_dir[5782*3 + 1] = 0.490222f;	val_dir[5782*3 + 2] = 0.869030f;
+ 	val_dir[5783*3 + 0] = -0.044130f;	val_dir[5783*3 + 1] = 0.507490f;	val_dir[5783*3 + 2] = 0.860527f;
+ 	val_dir[5784*3 + 0] = -0.021832f;	val_dir[5784*3 + 1] = 0.523973f;	val_dir[5784*3 + 2] = 0.851455f;
+ 	val_dir[5785*3 + 0] = 0.0f;	val_dir[5785*3 + 1] = 0.539666f;	val_dir[5785*3 + 2] = 0.841879f;
+ 	val_dir[5786*3 + 0] = 0.022108f;	val_dir[5786*3 + 1] = 0.574805f;	val_dir[5786*3 + 2] = 0.817992f;
+ 	val_dir[5787*3 + 0] = 0.045198f;	val_dir[5787*3 + 1] = 0.610179f;	val_dir[5787*3 + 2] = 0.790973f;
+ 	val_dir[5788*3 + 0] = 0.069153f;	val_dir[5788*3 + 1] = 0.645429f;	val_dir[5788*3 + 2] = 0.760684f;
+ 	val_dir[5789*3 + 0] = 0.093813f;	val_dir[5789*3 + 1] = 0.680144f;	val_dir[5789*3 + 2] = 0.727051f;
+ 	val_dir[5790*3 + 0] = 0.118980f;	val_dir[5790*3 + 1] = 0.713881f;	val_dir[5790*3 + 2] = 0.690085f;
+ 	val_dir[5791*3 + 0] = 0.144421f;	val_dir[5791*3 + 1] = 0.746176f;	val_dir[5791*3 + 2] = 0.649895f;
+ 	val_dir[5792*3 + 0] = 0.169875f;	val_dir[5792*3 + 1] = 0.776571f;	val_dir[5792*3 + 2] = 0.606696f;
+ 	val_dir[5793*3 + 0] = 0.195064f;	val_dir[5793*3 + 1] = 0.804639f;	val_dir[5793*3 + 2] = 0.560809f;
+ 	val_dir[5794*3 + 0] = 0.219708f;	val_dir[5794*3 + 1] = 0.830009f;	val_dir[5794*3 + 2] = 0.512653f;
+ 	val_dir[5795*3 + 0] = 0.243541f;	val_dir[5795*3 + 1] = 0.852392f;	val_dir[5795*3 + 2] = 0.462727f;
+ 	val_dir[5796*3 + 0] = 0.266320f;	val_dir[5796*3 + 1] = 0.871592f;	val_dir[5796*3 + 2] = 0.411585f;
+ 	val_dir[5797*3 + 0] = 0.287843f;	val_dir[5797*3 + 1] = 0.887517f;	val_dir[5797*3 + 2] = 0.359804f;
+ 	val_dir[5798*3 + 0] = 0.307957f;	val_dir[5798*3 + 1] = 0.900181f;	val_dir[5798*3 + 2] = 0.307957f;
+ 	val_dir[5799*3 + 0] = 0.326554f;	val_dir[5799*3 + 1] = 0.909687f;	val_dir[5799*3 + 2] = 0.256578f;
+ 	val_dir[5800*3 + 0] = 0.343582f;	val_dir[5800*3 + 1] = 0.916217f;	val_dir[5800*3 + 2] = 0.206149f;
+ 	val_dir[5801*3 + 0] = 0.359030f;	val_dir[5801*3 + 1] = 0.920014f;	val_dir[5801*3 + 2] = 0.157075f;
+ 	val_dir[5802*3 + 0] = 0.372929f;	val_dir[5802*3 + 1] = 0.921354f;	val_dir[5802*3 + 2] = 0.109685f;
+ 	val_dir[5803*3 + 0] = 0.385341f;	val_dir[5803*3 + 1] = 0.920537f;	val_dir[5803*3 + 2] = 0.064223f;
+ 	val_dir[5804*3 + 0] = 0.396350f;	val_dir[5804*3 + 1] = 0.917863f;	val_dir[5804*3 + 2] = 0.020861f;
+ 	val_dir[5805*3 + 0] = -0.921250f;	val_dir[5805*3 + 1] = -0.388972f;	val_dir[5805*3 + 2] = 0.0f;
+ 	val_dir[5806*3 + 0] = -0.924729f;	val_dir[5806*3 + 1] = -0.378298f;	val_dir[5806*3 + 2] = 0.042033f;
+ 	val_dir[5807*3 + 0] = -0.92650f;	val_dir[5807*3 + 1] = -0.366291f;	val_dir[5807*3 + 2] = 0.086186f;
+ 	val_dir[5808*3 + 0] = -0.926270f;	val_dir[5808*3 + 1] = -0.352865f;	val_dir[5808*3 + 2] = 0.132324f;
+ 	val_dir[5809*3 + 0] = -0.923742f;	val_dir[5809*3 + 1] = -0.337954f;	val_dir[5809*3 + 2] = 0.180242f;
+ 	val_dir[5810*3 + 0] = -0.918630f;	val_dir[5810*3 + 1] = -0.321521f;	val_dir[5810*3 + 2] = 0.229658f;
+ 	val_dir[5811*3 + 0] = -0.910678f;	val_dir[5811*3 + 1] = -0.303559f;	val_dir[5811*3 + 2] = 0.280209f;
+ 	val_dir[5812*3 + 0] = -0.899676f;	val_dir[5812*3 + 1] = -0.284108f;	val_dir[5812*3 + 2] = 0.331460f;
+ 	val_dir[5813*3 + 0] = -0.885482f;	val_dir[5813*3 + 1] = -0.263251f;	val_dir[5813*3 + 2] = 0.382911f;
+ 	val_dir[5814*3 + 0] = -0.868037f;	val_dir[5814*3 + 1] = -0.241121f;	val_dir[5814*3 + 2] = 0.434019f;
+ 	val_dir[5815*3 + 0] = -0.847381f;	val_dir[5815*3 + 1] = -0.217898f;	val_dir[5815*3 + 2] = 0.484217f;
+ 	val_dir[5816*3 + 0] = -0.823653f;	val_dir[5816*3 + 1] = -0.193801f;	val_dir[5816*3 + 2] = 0.532952f;
+ 	val_dir[5817*3 + 0] = -0.797092f;	val_dir[5817*3 + 1] = -0.169080f;	val_dir[5817*3 + 2] = 0.579703f;
+ 	val_dir[5818*3 + 0] = -0.768025f;	val_dir[5818*3 + 1] = -0.144005f;	val_dir[5818*3 + 2] = 0.624020f;
+ 	val_dir[5819*3 + 0] = -0.736843f;	val_dir[5819*3 + 1] = -0.118846f;	val_dir[5819*3 + 2] = 0.665536f;
+ 	val_dir[5820*3 + 0] = -0.703985f;	val_dir[5820*3 + 1] = -0.093865f;	val_dir[5820*3 + 2] = 0.703985f;
+ 	val_dir[5821*3 + 0] = -0.669905f;	val_dir[5821*3 + 1] = -0.069301f;	val_dir[5821*3 + 2] = 0.739205f;
+ 	val_dir[5822*3 + 0] = -0.635053f;	val_dir[5822*3 + 1] = -0.045361f;	val_dir[5822*3 + 2] = 0.771136f;
+ 	val_dir[5823*3 + 0] = -0.599852f;	val_dir[5823*3 + 1] = -0.022217f;	val_dir[5823*3 + 2] = 0.799803f;
+ 	val_dir[5824*3 + 0] = -0.564684f;	val_dir[5824*3 + 1] = 0.0f;	val_dir[5824*3 + 2] = 0.825307f;
+ 	val_dir[5825*3 + 0] = -0.549484f;	val_dir[5825*3 + 1] = 0.021979f;	val_dir[5825*3 + 2] = 0.835215f;
+ 	val_dir[5826*3 + 0] = -0.533465f;	val_dir[5826*3 + 1] = 0.044455f;	val_dir[5826*3 + 2] = 0.844653f;
+ 	val_dir[5827*3 + 0] = -0.516626f;	val_dir[5827*3 + 1] = 0.067386f;	val_dir[5827*3 + 2] = 0.853556f;
+ 	val_dir[5828*3 + 0] = -0.498970f;	val_dir[5828*3 + 1] = 0.090722f;	val_dir[5828*3 + 2] = 0.861857f;
+ 	val_dir[5829*3 + 0] = -0.480510f;	val_dir[5829*3 + 1] = 0.114407f;	val_dir[5829*3 + 2] = 0.869495f;
+ 	val_dir[5830*3 + 0] = -0.461266f;	val_dir[5830*3 + 1] = 0.138380f;	val_dir[5830*3 + 2] = 0.876405f;
+ 	val_dir[5831*3 + 0] = -0.441264f;	val_dir[5831*3 + 1] = 0.162571f;	val_dir[5831*3 + 2] = 0.882528f;
+ 	val_dir[5832*3 + 0] = -0.420542f;	val_dir[5832*3 + 1] = 0.186908f;	val_dir[5832*3 + 2] = 0.887812f;
+ 	val_dir[5833*3 + 0] = -0.399145f;	val_dir[5833*3 + 1] = 0.211312f;	val_dir[5833*3 + 2] = 0.892206f;
+ 	val_dir[5834*3 + 0] = -0.377124f;	val_dir[5834*3 + 1] = 0.235702f;	val_dir[5834*3 + 2] = 0.895669f;
+ 	val_dir[5835*3 + 0] = -0.354540f;	val_dir[5835*3 + 1] = 0.259996f;	val_dir[5835*3 + 2] = 0.898167f;
+ 	val_dir[5836*3 + 0] = -0.331460f;	val_dir[5836*3 + 1] = 0.284108f;	val_dir[5836*3 + 2] = 0.899676f;
+ 	val_dir[5837*3 + 0] = -0.307957f;	val_dir[5837*3 + 1] = 0.307957f;	val_dir[5837*3 + 2] = 0.900181f;
+ 	val_dir[5838*3 + 0] = -0.284108f;	val_dir[5838*3 + 1] = 0.331460f;	val_dir[5838*3 + 2] = 0.899676f;
+ 	val_dir[5839*3 + 0] = -0.259996f;	val_dir[5839*3 + 1] = 0.354540f;	val_dir[5839*3 + 2] = 0.898167f;
+ 	val_dir[5840*3 + 0] = -0.235702f;	val_dir[5840*3 + 1] = 0.377124f;	val_dir[5840*3 + 2] = 0.895669f;
+ 	val_dir[5841*3 + 0] = -0.211312f;	val_dir[5841*3 + 1] = 0.399145f;	val_dir[5841*3 + 2] = 0.892206f;
+ 	val_dir[5842*3 + 0] = -0.186908f;	val_dir[5842*3 + 1] = 0.420542f;	val_dir[5842*3 + 2] = 0.887812f;
+ 	val_dir[5843*3 + 0] = -0.162571f;	val_dir[5843*3 + 1] = 0.441264f;	val_dir[5843*3 + 2] = 0.882528f;
+ 	val_dir[5844*3 + 0] = -0.138380f;	val_dir[5844*3 + 1] = 0.461266f;	val_dir[5844*3 + 2] = 0.876405f;
+ 	val_dir[5845*3 + 0] = -0.114407f;	val_dir[5845*3 + 1] = 0.480510f;	val_dir[5845*3 + 2] = 0.869495f;
+ 	val_dir[5846*3 + 0] = -0.090722f;	val_dir[5846*3 + 1] = 0.498970f;	val_dir[5846*3 + 2] = 0.861857f;
+ 	val_dir[5847*3 + 0] = -0.067386f;	val_dir[5847*3 + 1] = 0.516626f;	val_dir[5847*3 + 2] = 0.853556f;
+ 	val_dir[5848*3 + 0] = -0.044455f;	val_dir[5848*3 + 1] = 0.533465f;	val_dir[5848*3 + 2] = 0.844653f;
+ 	val_dir[5849*3 + 0] = -0.021979f;	val_dir[5849*3 + 1] = 0.549484f;	val_dir[5849*3 + 2] = 0.835215f;
+ 	val_dir[5850*3 + 0] = 0.0f;	val_dir[5850*3 + 1] = 0.564684f;	val_dir[5850*3 + 2] = 0.825307f;
+ 	val_dir[5851*3 + 0] = 0.022217f;	val_dir[5851*3 + 1] = 0.599852f;	val_dir[5851*3 + 2] = 0.799803f;
+ 	val_dir[5852*3 + 0] = 0.045361f;	val_dir[5852*3 + 1] = 0.635053f;	val_dir[5852*3 + 2] = 0.771136f;
+ 	val_dir[5853*3 + 0] = 0.069301f;	val_dir[5853*3 + 1] = 0.669905f;	val_dir[5853*3 + 2] = 0.739205f;
+ 	val_dir[5854*3 + 0] = 0.093865f;	val_dir[5854*3 + 1] = 0.703985f;	val_dir[5854*3 + 2] = 0.703985f;
+ 	val_dir[5855*3 + 0] = 0.118846f;	val_dir[5855*3 + 1] = 0.736843f;	val_dir[5855*3 + 2] = 0.665536f;
+ 	val_dir[5856*3 + 0] = 0.144005f;	val_dir[5856*3 + 1] = 0.768025f;	val_dir[5856*3 + 2] = 0.624020f;
+ 	val_dir[5857*3 + 0] = 0.169080f;	val_dir[5857*3 + 1] = 0.797092f;	val_dir[5857*3 + 2] = 0.579703f;
+ 	val_dir[5858*3 + 0] = 0.193801f;	val_dir[5858*3 + 1] = 0.823653f;	val_dir[5858*3 + 2] = 0.532952f;
+ 	val_dir[5859*3 + 0] = 0.217898f;	val_dir[5859*3 + 1] = 0.847381f;	val_dir[5859*3 + 2] = 0.484217f;
+ 	val_dir[5860*3 + 0] = 0.241121f;	val_dir[5860*3 + 1] = 0.868037f;	val_dir[5860*3 + 2] = 0.434019f;
+ 	val_dir[5861*3 + 0] = 0.263251f;	val_dir[5861*3 + 1] = 0.885482f;	val_dir[5861*3 + 2] = 0.382911f;
+ 	val_dir[5862*3 + 0] = 0.284108f;	val_dir[5862*3 + 1] = 0.899676f;	val_dir[5862*3 + 2] = 0.331460f;
+ 	val_dir[5863*3 + 0] = 0.303559f;	val_dir[5863*3 + 1] = 0.910678f;	val_dir[5863*3 + 2] = 0.280209f;
+ 	val_dir[5864*3 + 0] = 0.321521f;	val_dir[5864*3 + 1] = 0.918630f;	val_dir[5864*3 + 2] = 0.229658f;
+ 	val_dir[5865*3 + 0] = 0.337954f;	val_dir[5865*3 + 1] = 0.923742f;	val_dir[5865*3 + 2] = 0.180242f;
+ 	val_dir[5866*3 + 0] = 0.352865f;	val_dir[5866*3 + 1] = 0.926270f;	val_dir[5866*3 + 2] = 0.132324f;
+ 	val_dir[5867*3 + 0] = 0.366291f;	val_dir[5867*3 + 1] = 0.92650f;	val_dir[5867*3 + 2] = 0.086186f;
+ 	val_dir[5868*3 + 0] = 0.378298f;	val_dir[5868*3 + 1] = 0.924729f;	val_dir[5868*3 + 2] = 0.042033f;
+ 	val_dir[5869*3 + 0] = 0.388972f;	val_dir[5869*3 + 1] = 0.921250f;	val_dir[5869*3 + 2] = 0.0f;
+ 	val_dir[5870*3 + 0] = -0.928279f;	val_dir[5870*3 + 1] = -0.371312f;	val_dir[5870*3 + 2] = 0.020628f;
+ 	val_dir[5871*3 + 0] = -0.930917f;	val_dir[5871*3 + 1] = -0.359673f;	val_dir[5871*3 + 2] = 0.063472f;
+ 	val_dir[5872*3 + 0] = -0.931705f;	val_dir[5872*3 + 1] = -0.346681f;	val_dir[5872*3 + 2] = 0.108338f;
+ 	val_dir[5873*3 + 0] = -0.930352f;	val_dir[5873*3 + 1] = -0.332269f;	val_dir[5873*3 + 2] = 0.155059f;
+ 	val_dir[5874*3 + 0] = -0.926568f;	val_dir[5874*3 + 1] = -0.316389f;	val_dir[5874*3 + 2] = 0.203393f;
+ 	val_dir[5875*3 + 0] = -0.920087f;	val_dir[5875*3 + 1] = -0.299028f;	val_dir[5875*3 + 2] = 0.253024f;
+ 	val_dir[5876*3 + 0] = -0.910678f;	val_dir[5876*3 + 1] = -0.280209f;	val_dir[5876*3 + 2] = 0.303559f;
+ 	val_dir[5877*3 + 0] = -0.898167f;	val_dir[5877*3 + 1] = -0.259996f;	val_dir[5877*3 + 2] = 0.354540f;
+ 	val_dir[5878*3 + 0] = -0.882454f;	val_dir[5878*3 + 1] = -0.238501f;	val_dir[5878*3 + 2] = 0.405452f;
+ 	val_dir[5879*3 + 0] = -0.863530f;	val_dir[5879*3 + 1] = -0.215883f;	val_dir[5879*3 + 2] = 0.455752f;
+ 	val_dir[5880*3 + 0] = -0.841482f;	val_dir[5880*3 + 1] = -0.192339f;	val_dir[5880*3 + 2] = 0.504889f;
+ 	val_dir[5881*3 + 0] = -0.816497f;	val_dir[5881*3 + 1] = -0.168102f;	val_dir[5881*3 + 2] = 0.552336f;
+ 	val_dir[5882*3 + 0] = -0.788851f;	val_dir[5882*3 + 1] = -0.143427f;	val_dir[5882*3 + 2] = 0.597614f;
+ 	val_dir[5883*3 + 0] = -0.758899f;	val_dir[5883*3 + 1] = -0.118578f;	val_dir[5883*3 + 2] = 0.640321f;
+ 	val_dir[5884*3 + 0] = -0.727051f;	val_dir[5884*3 + 1] = -0.093813f;	val_dir[5884*3 + 2] = 0.680144f;
+ 	val_dir[5885*3 + 0] = -0.693746f;	val_dir[5885*3 + 1] = -0.069375f;	val_dir[5885*3 + 2] = 0.716871f;
+ 	val_dir[5886*3 + 0] = -0.659432f;	val_dir[5886*3 + 1] = -0.045478f;	val_dir[5886*3 + 2] = 0.750388f;
+ 	val_dir[5887*3 + 0] = -0.624540f;	val_dir[5887*3 + 1] = -0.022305f;	val_dir[5887*3 + 2] = 0.780675f;
+ 	val_dir[5888*3 + 0] = -0.589469f;	val_dir[5888*3 + 1] = 0.0f;	val_dir[5888*3 + 2] = 0.807791f;
+ 	val_dir[5889*3 + 0] = -0.574805f;	val_dir[5889*3 + 1] = 0.022108f;	val_dir[5889*3 + 2] = 0.817992f;
+ 	val_dir[5890*3 + 0] = -0.559297f;	val_dir[5890*3 + 1] = 0.044744f;	val_dir[5890*3 + 2] = 0.827759f;
+ 	val_dir[5891*3 + 0] = -0.542936f;	val_dir[5891*3 + 1] = 0.067867f;	val_dir[5891*3 + 2] = 0.837027f;
+ 	val_dir[5892*3 + 0] = -0.525723f;	val_dir[5892*3 + 1] = 0.091430f;	val_dir[5892*3 + 2] = 0.845728f;
+ 	val_dir[5893*3 + 0] = -0.507662f;	val_dir[5893*3 + 1] = 0.115378f;	val_dir[5893*3 + 2] = 0.853796f;
+ 	val_dir[5894*3 + 0] = -0.488769f;	val_dir[5894*3 + 1] = 0.139648f;	val_dir[5894*3 + 2] = 0.861164f;
+ 	val_dir[5895*3 + 0] = -0.469065f;	val_dir[5895*3 + 1] = 0.164173f;	val_dir[5895*3 + 2] = 0.867770f;
+ 	val_dir[5896*3 + 0] = -0.448583f;	val_dir[5896*3 + 1] = 0.188877f;	val_dir[5896*3 + 2] = 0.873555f;
+ 	val_dir[5897*3 + 0] = -0.427362f;	val_dir[5897*3 + 1] = 0.213681f;	val_dir[5897*3 + 2] = 0.878466f;
+ 	val_dir[5898*3 + 0] = -0.405452f;	val_dir[5898*3 + 1] = 0.238501f;	val_dir[5898*3 + 2] = 0.882454f;
+ 	val_dir[5899*3 + 0] = -0.382911f;	val_dir[5899*3 + 1] = 0.263251f;	val_dir[5899*3 + 2] = 0.885482f;
+ 	val_dir[5900*3 + 0] = -0.359804f;	val_dir[5900*3 + 1] = 0.287843f;	val_dir[5900*3 + 2] = 0.887517f;
+ 	val_dir[5901*3 + 0] = -0.336204f;	val_dir[5901*3 + 1] = 0.312190f;	val_dir[5901*3 + 2] = 0.888540f;
+ 	val_dir[5902*3 + 0] = -0.312190f;	val_dir[5902*3 + 1] = 0.336204f;	val_dir[5902*3 + 2] = 0.888540f;
+ 	val_dir[5903*3 + 0] = -0.287843f;	val_dir[5903*3 + 1] = 0.359804f;	val_dir[5903*3 + 2] = 0.887517f;
+ 	val_dir[5904*3 + 0] = -0.263251f;	val_dir[5904*3 + 1] = 0.382911f;	val_dir[5904*3 + 2] = 0.885482f;
+ 	val_dir[5905*3 + 0] = -0.238501f;	val_dir[5905*3 + 1] = 0.405452f;	val_dir[5905*3 + 2] = 0.882454f;
+ 	val_dir[5906*3 + 0] = -0.213681f;	val_dir[5906*3 + 1] = 0.427362f;	val_dir[5906*3 + 2] = 0.878466f;
+ 	val_dir[5907*3 + 0] = -0.188877f;	val_dir[5907*3 + 1] = 0.448583f;	val_dir[5907*3 + 2] = 0.873555f;
+ 	val_dir[5908*3 + 0] = -0.164173f;	val_dir[5908*3 + 1] = 0.469065f;	val_dir[5908*3 + 2] = 0.867770f;
+ 	val_dir[5909*3 + 0] = -0.139648f;	val_dir[5909*3 + 1] = 0.488769f;	val_dir[5909*3 + 2] = 0.861164f;
+ 	val_dir[5910*3 + 0] = -0.115378f;	val_dir[5910*3 + 1] = 0.507662f;	val_dir[5910*3 + 2] = 0.853796f;
+ 	val_dir[5911*3 + 0] = -0.091430f;	val_dir[5911*3 + 1] = 0.525723f;	val_dir[5911*3 + 2] = 0.845728f;
+ 	val_dir[5912*3 + 0] = -0.067867f;	val_dir[5912*3 + 1] = 0.542936f;	val_dir[5912*3 + 2] = 0.837027f;
+ 	val_dir[5913*3 + 0] = -0.044744f;	val_dir[5913*3 + 1] = 0.559297f;	val_dir[5913*3 + 2] = 0.827759f;
+ 	val_dir[5914*3 + 0] = -0.022108f;	val_dir[5914*3 + 1] = 0.574805f;	val_dir[5914*3 + 2] = 0.817992f;
+ 	val_dir[5915*3 + 0] = 0.0f;	val_dir[5915*3 + 1] = 0.589469f;	val_dir[5915*3 + 2] = 0.807791f;
+ 	val_dir[5916*3 + 0] = 0.022305f;	val_dir[5916*3 + 1] = 0.624540f;	val_dir[5916*3 + 2] = 0.780675f;
+ 	val_dir[5917*3 + 0] = 0.045478f;	val_dir[5917*3 + 1] = 0.659432f;	val_dir[5917*3 + 2] = 0.750388f;
+ 	val_dir[5918*3 + 0] = 0.069375f;	val_dir[5918*3 + 1] = 0.693746f;	val_dir[5918*3 + 2] = 0.716871f;
+ 	val_dir[5919*3 + 0] = 0.093813f;	val_dir[5919*3 + 1] = 0.727051f;	val_dir[5919*3 + 2] = 0.680144f;
+ 	val_dir[5920*3 + 0] = 0.118578f;	val_dir[5920*3 + 1] = 0.758899f;	val_dir[5920*3 + 2] = 0.640321f;
+ 	val_dir[5921*3 + 0] = 0.143427f;	val_dir[5921*3 + 1] = 0.788851f;	val_dir[5921*3 + 2] = 0.597614f;
+ 	val_dir[5922*3 + 0] = 0.168102f;	val_dir[5922*3 + 1] = 0.816497f;	val_dir[5922*3 + 2] = 0.552336f;
+ 	val_dir[5923*3 + 0] = 0.192339f;	val_dir[5923*3 + 1] = 0.841482f;	val_dir[5923*3 + 2] = 0.504889f;
+ 	val_dir[5924*3 + 0] = 0.215883f;	val_dir[5924*3 + 1] = 0.863530f;	val_dir[5924*3 + 2] = 0.455752f;
+ 	val_dir[5925*3 + 0] = 0.238501f;	val_dir[5925*3 + 1] = 0.882454f;	val_dir[5925*3 + 2] = 0.405452f;
+ 	val_dir[5926*3 + 0] = 0.259996f;	val_dir[5926*3 + 1] = 0.898167f;	val_dir[5926*3 + 2] = 0.354540f;
+ 	val_dir[5927*3 + 0] = 0.280209f;	val_dir[5927*3 + 1] = 0.910678f;	val_dir[5927*3 + 2] = 0.303559f;
+ 	val_dir[5928*3 + 0] = 0.299028f;	val_dir[5928*3 + 1] = 0.920087f;	val_dir[5928*3 + 2] = 0.253024f;
+ 	val_dir[5929*3 + 0] = 0.316389f;	val_dir[5929*3 + 1] = 0.926568f;	val_dir[5929*3 + 2] = 0.203393f;
+ 	val_dir[5930*3 + 0] = 0.332269f;	val_dir[5930*3 + 1] = 0.930352f;	val_dir[5930*3 + 2] = 0.155059f;
+ 	val_dir[5931*3 + 0] = 0.346681f;	val_dir[5931*3 + 1] = 0.931705f;	val_dir[5931*3 + 2] = 0.108338f;
+ 	val_dir[5932*3 + 0] = 0.359673f;	val_dir[5932*3 + 1] = 0.930917f;	val_dir[5932*3 + 2] = 0.063472f;
+ 	val_dir[5933*3 + 0] = 0.371312f;	val_dir[5933*3 + 1] = 0.928279f;	val_dir[5933*3 + 2] = 0.020628f;
+ 	val_dir[5934*3 + 0] = -0.931243f;	val_dir[5934*3 + 1] = -0.364399f;	val_dir[5934*3 + 2] = 0.0f;
+ 	val_dir[5935*3 + 0] = -0.934665f;	val_dir[5935*3 + 1] = -0.353096f;	val_dir[5935*3 + 2] = 0.041541f;
+ 	val_dir[5936*3 + 0] = -0.936382f;	val_dir[5936*3 + 1] = -0.340503f;	val_dir[5936*3 + 2] = 0.085126f;
+ 	val_dir[5937*3 + 0] = -0.936111f;	val_dir[5937*3 + 1] = -0.326550f;	val_dir[5937*3 + 2] = 0.130620f;
+ 	val_dir[5938*3 + 0] = -0.933564f;	val_dir[5938*3 + 1] = -0.311188f;	val_dir[5938*3 + 2] = 0.177822f;
+ 	val_dir[5939*3 + 0] = -0.928467f;	val_dir[5939*3 + 1] = -0.294392f;	val_dir[5939*3 + 2] = 0.226455f;
+ 	val_dir[5940*3 + 0] = -0.920575f;	val_dir[5940*3 + 1] = -0.276172f;	val_dir[5940*3 + 2] = 0.276172f;
+ 	val_dir[5941*3 + 0] = -0.909687f;	val_dir[5941*3 + 1] = -0.256578f;	val_dir[5941*3 + 2] = 0.326554f;
+ 	val_dir[5942*3 + 0] = -0.895669f;	val_dir[5942*3 + 1] = -0.235702f;	val_dir[5942*3 + 2] = 0.377124f;
+ 	val_dir[5943*3 + 0] = -0.878466f;	val_dir[5943*3 + 1] = -0.213681f;	val_dir[5943*3 + 2] = 0.427362f;
+ 	val_dir[5944*3 + 0] = -0.858116f;	val_dir[5944*3 + 1] = -0.190693f;	val_dir[5944*3 + 2] = 0.476731f;
+ 	val_dir[5945*3 + 0] = -0.834754f;	val_dir[5945*3 + 1] = -0.166951f;	val_dir[5945*3 + 2] = 0.524703f;
+ 	val_dir[5946*3 + 0] = -0.808608f;	val_dir[5946*3 + 1] = -0.142695f;	val_dir[5946*3 + 2] = 0.570782f;
+ 	val_dir[5947*3 + 0] = -0.779987f;	val_dir[5947*3 + 1] = -0.118180f;	val_dir[5947*3 + 2] = 0.614535f;
+ 	val_dir[5948*3 + 0] = -0.749269f;	val_dir[5948*3 + 1] = -0.093659f;	val_dir[5948*3 + 2] = 0.655610f;
+ 	val_dir[5949*3 + 0] = -0.716871f;	val_dir[5949*3 + 1] = -0.069375f;	val_dir[5949*3 + 2] = 0.693746f;
+ 	val_dir[5950*3 + 0] = -0.683231f;	val_dir[5950*3 + 1] = -0.045549f;	val_dir[5950*3 + 2] = 0.728780f;
+ 	val_dir[5951*3 + 0] = -0.648784f;	val_dir[5951*3 + 1] = -0.022372f;	val_dir[5951*3 + 2] = 0.760644f;
+ 	val_dir[5952*3 + 0] = -0.613941f;	val_dir[5952*3 + 1] = 0.0f;	val_dir[5952*3 + 2] = 0.789352f;
+ 	val_dir[5953*3 + 0] = -0.599852f;	val_dir[5953*3 + 1] = 0.022217f;	val_dir[5953*3 + 2] = 0.799803f;
+ 	val_dir[5954*3 + 0] = -0.584898f;	val_dir[5954*3 + 1] = 0.044992f;	val_dir[5954*3 + 2] = 0.809858f;
+ 	val_dir[5955*3 + 0] = -0.569064f;	val_dir[5955*3 + 1] = 0.068288f;	val_dir[5955*3 + 2] = 0.819453f;
+ 	val_dir[5956*3 + 0] = -0.552345f;	val_dir[5956*3 + 1] = 0.092057f;	val_dir[5956*3 + 2] = 0.828517f;
+ 	val_dir[5957*3 + 0] = -0.534739f;	val_dir[5957*3 + 1] = 0.116248f;	val_dir[5957*3 + 2] = 0.836983f;
+ 	val_dir[5958*3 + 0] = -0.516256f;	val_dir[5958*3 + 1] = 0.140797f;	val_dir[5958*3 + 2] = 0.844782f;
+ 	val_dir[5959*3 + 0] = -0.496911f;	val_dir[5959*3 + 1] = 0.165637f;	val_dir[5959*3 + 2] = 0.851847f;
+ 	val_dir[5960*3 + 0] = -0.476731f;	val_dir[5960*3 + 1] = 0.190693f;	val_dir[5960*3 + 2] = 0.858116f;
+ 	val_dir[5961*3 + 0] = -0.455752f;	val_dir[5961*3 + 1] = 0.215883f;	val_dir[5961*3 + 2] = 0.863530f;
+ 	val_dir[5962*3 + 0] = -0.434019f;	val_dir[5962*3 + 1] = 0.241121f;	val_dir[5962*3 + 2] = 0.868037f;
+ 	val_dir[5963*3 + 0] = -0.411585f;	val_dir[5963*3 + 1] = 0.266320f;	val_dir[5963*3 + 2] = 0.871592f;
+ 	val_dir[5964*3 + 0] = -0.388514f;	val_dir[5964*3 + 1] = 0.291386f;	val_dir[5964*3 + 2] = 0.874157f;
+ 	val_dir[5965*3 + 0] = -0.364878f;	val_dir[5965*3 + 1] = 0.316228f;	val_dir[5965*3 + 2] = 0.875708f;
+ 	val_dir[5966*3 + 0] = -0.340755f;	val_dir[5966*3 + 1] = 0.340755f;	val_dir[5966*3 + 2] = 0.876226f;
+ 	val_dir[5967*3 + 0] = -0.316228f;	val_dir[5967*3 + 1] = 0.364878f;	val_dir[5967*3 + 2] = 0.875708f;
+ 	val_dir[5968*3 + 0] = -0.291386f;	val_dir[5968*3 + 1] = 0.388514f;	val_dir[5968*3 + 2] = 0.874157f;
+ 	val_dir[5969*3 + 0] = -0.266320f;	val_dir[5969*3 + 1] = 0.411585f;	val_dir[5969*3 + 2] = 0.871592f;
+ 	val_dir[5970*3 + 0] = -0.241121f;	val_dir[5970*3 + 1] = 0.434019f;	val_dir[5970*3 + 2] = 0.868037f;
+ 	val_dir[5971*3 + 0] = -0.215883f;	val_dir[5971*3 + 1] = 0.455752f;	val_dir[5971*3 + 2] = 0.863530f;
+ 	val_dir[5972*3 + 0] = -0.190693f;	val_dir[5972*3 + 1] = 0.476731f;	val_dir[5972*3 + 2] = 0.858116f;
+ 	val_dir[5973*3 + 0] = -0.165637f;	val_dir[5973*3 + 1] = 0.496911f;	val_dir[5973*3 + 2] = 0.851847f;
+ 	val_dir[5974*3 + 0] = -0.140797f;	val_dir[5974*3 + 1] = 0.516256f;	val_dir[5974*3 + 2] = 0.844782f;
+ 	val_dir[5975*3 + 0] = -0.116248f;	val_dir[5975*3 + 1] = 0.534739f;	val_dir[5975*3 + 2] = 0.836983f;
+ 	val_dir[5976*3 + 0] = -0.092057f;	val_dir[5976*3 + 1] = 0.552345f;	val_dir[5976*3 + 2] = 0.828517f;
+ 	val_dir[5977*3 + 0] = -0.068288f;	val_dir[5977*3 + 1] = 0.569064f;	val_dir[5977*3 + 2] = 0.819453f;
+ 	val_dir[5978*3 + 0] = -0.044992f;	val_dir[5978*3 + 1] = 0.584898f;	val_dir[5978*3 + 2] = 0.809858f;
+ 	val_dir[5979*3 + 0] = -0.022217f;	val_dir[5979*3 + 1] = 0.599852f;	val_dir[5979*3 + 2] = 0.799803f;
+ 	val_dir[5980*3 + 0] = 0.0f;	val_dir[5980*3 + 1] = 0.613941f;	val_dir[5980*3 + 2] = 0.789352f;
+ 	val_dir[5981*3 + 0] = 0.022372f;	val_dir[5981*3 + 1] = 0.648784f;	val_dir[5981*3 + 2] = 0.760644f;
+ 	val_dir[5982*3 + 0] = 0.045549f;	val_dir[5982*3 + 1] = 0.683231f;	val_dir[5982*3 + 2] = 0.728780f;
+ 	val_dir[5983*3 + 0] = 0.069375f;	val_dir[5983*3 + 1] = 0.716871f;	val_dir[5983*3 + 2] = 0.693746f;
+ 	val_dir[5984*3 + 0] = 0.093659f;	val_dir[5984*3 + 1] = 0.749269f;	val_dir[5984*3 + 2] = 0.655610f;
+ 	val_dir[5985*3 + 0] = 0.118180f;	val_dir[5985*3 + 1] = 0.779987f;	val_dir[5985*3 + 2] = 0.614535f;
+ 	val_dir[5986*3 + 0] = 0.142695f;	val_dir[5986*3 + 1] = 0.808608f;	val_dir[5986*3 + 2] = 0.570782f;
+ 	val_dir[5987*3 + 0] = 0.166951f;	val_dir[5987*3 + 1] = 0.834754f;	val_dir[5987*3 + 2] = 0.524703f;
+ 	val_dir[5988*3 + 0] = 0.190693f;	val_dir[5988*3 + 1] = 0.858116f;	val_dir[5988*3 + 2] = 0.476731f;
+ 	val_dir[5989*3 + 0] = 0.213681f;	val_dir[5989*3 + 1] = 0.878466f;	val_dir[5989*3 + 2] = 0.427362f;
+ 	val_dir[5990*3 + 0] = 0.235702f;	val_dir[5990*3 + 1] = 0.895669f;	val_dir[5990*3 + 2] = 0.377124f;
+ 	val_dir[5991*3 + 0] = 0.256578f;	val_dir[5991*3 + 1] = 0.909687f;	val_dir[5991*3 + 2] = 0.326554f;
+ 	val_dir[5992*3 + 0] = 0.276172f;	val_dir[5992*3 + 1] = 0.920575f;	val_dir[5992*3 + 2] = 0.276172f;
+ 	val_dir[5993*3 + 0] = 0.294392f;	val_dir[5993*3 + 1] = 0.928467f;	val_dir[5993*3 + 2] = 0.226455f;
+ 	val_dir[5994*3 + 0] = 0.311188f;	val_dir[5994*3 + 1] = 0.933564f;	val_dir[5994*3 + 2] = 0.177822f;
+ 	val_dir[5995*3 + 0] = 0.326550f;	val_dir[5995*3 + 1] = 0.936111f;	val_dir[5995*3 + 2] = 0.130620f;
+ 	val_dir[5996*3 + 0] = 0.340503f;	val_dir[5996*3 + 1] = 0.936382f;	val_dir[5996*3 + 2] = 0.085126f;
+ 	val_dir[5997*3 + 0] = 0.353096f;	val_dir[5997*3 + 1] = 0.934665f;	val_dir[5997*3 + 2] = 0.041541f;
+ 	val_dir[5998*3 + 0] = 0.364399f;	val_dir[5998*3 + 1] = 0.931243f;	val_dir[5998*3 + 2] = 0.0f;
+ 	val_dir[5999*3 + 0] = -0.93780f;	val_dir[5999*3 + 1] = -0.346578f;	val_dir[5999*3 + 2] = 0.020387f;
+ 	val_dir[6000*3 + 0] = -0.940361f;	val_dir[6000*3 + 1] = -0.334351f;	val_dir[6000*3 + 2] = 0.062691f;
+ 	val_dir[6001*3 + 0] = -0.941082f;	val_dir[6001*3 + 1] = -0.320824f;	val_dir[6001*3 + 2] = 0.106941f;
+ 	val_dir[6002*3 + 0] = -0.939680f;	val_dir[6002*3 + 1] = -0.305942f;	val_dir[6002*3 + 2] = 0.152971f;
+ 	val_dir[6003*3 + 0] = -0.935879f;	val_dir[6003*3 + 1] = -0.289677f;	val_dir[6003*3 + 2] = 0.200545f;
+ 	val_dir[6004*3 + 0] = -0.929421f;	val_dir[6004*3 + 1] = -0.272026f;	val_dir[6004*3 + 2] = 0.249357f;
+ 	val_dir[6005*3 + 0] = -0.920087f;	val_dir[6005*3 + 1] = -0.253024f;	val_dir[6005*3 + 2] = 0.299028f;
+ 	val_dir[6006*3 + 0] = -0.907713f;	val_dir[6006*3 + 1] = -0.232747f;	val_dir[6006*3 + 2] = 0.349121f;
+ 	val_dir[6007*3 + 0] = -0.892206f;	val_dir[6007*3 + 1] = -0.211312f;	val_dir[6007*3 + 2] = 0.399145f;
+ 	val_dir[6008*3 + 0] = -0.873555f;	val_dir[6008*3 + 1] = -0.188877f;	val_dir[6008*3 + 2] = 0.448583f;
+ 	val_dir[6009*3 + 0] = -0.851847f;	val_dir[6009*3 + 1] = -0.165637f;	val_dir[6009*3 + 2] = 0.496911f;
+ 	val_dir[6010*3 + 0] = -0.827259f;	val_dir[6010*3 + 1] = -0.141816f;	val_dir[6010*3 + 2] = 0.543627f;
+ 	val_dir[6011*3 + 0] = -0.800055f;	val_dir[6011*3 + 1] = -0.117655f;	val_dir[6011*3 + 2] = 0.588276f;
+ 	val_dir[6012*3 + 0] = -0.770574f;	val_dir[6012*3 + 1] = -0.093403f;	val_dir[6012*3 + 2] = 0.630470f;
+ 	val_dir[6013*3 + 0] = -0.739205f;	val_dir[6013*3 + 1] = -0.069301f;	val_dir[6013*3 + 2] = 0.669905f;
+ 	val_dir[6014*3 + 0] = -0.706372f;	val_dir[6014*3 + 1] = -0.045572f;	val_dir[6014*3 + 2] = 0.706372f;
+ 	val_dir[6015*3 + 0] = -0.672504f;	val_dir[6015*3 + 1] = -0.022417f;	val_dir[6015*3 + 2] = 0.739754f;
+ 	val_dir[6016*3 + 0] = -0.638018f;	val_dir[6016*3 + 1] = 0.0f;	val_dir[6016*3 + 2] = 0.770022f;
+ 	val_dir[6017*3 + 0] = -0.624540f;	val_dir[6017*3 + 1] = 0.022305f;	val_dir[6017*3 + 2] = 0.780675f;
+ 	val_dir[6018*3 + 0] = -0.610179f;	val_dir[6018*3 + 1] = 0.045198f;	val_dir[6018*3 + 2] = 0.790973f;
+ 	val_dir[6019*3 + 0] = -0.594917f;	val_dir[6019*3 + 1] = 0.068644f;	val_dir[6019*3 + 2] = 0.800850f;
+ 	val_dir[6020*3 + 0] = -0.578741f;	val_dir[6020*3 + 1] = 0.092599f;	val_dir[6020*3 + 2] = 0.810237f;
+ 	val_dir[6021*3 + 0] = -0.561644f;	val_dir[6021*3 + 1] = 0.117009f;	val_dir[6021*3 + 2] = 0.819064f;
+ 	val_dir[6022*3 + 0] = -0.543627f;	val_dir[6022*3 + 1] = 0.141816f;	val_dir[6022*3 + 2] = 0.827259f;
+ 	val_dir[6023*3 + 0] = -0.524703f;	val_dir[6023*3 + 1] = 0.166951f;	val_dir[6023*3 + 2] = 0.834754f;
+ 	val_dir[6024*3 + 0] = -0.504889f;	val_dir[6024*3 + 1] = 0.192339f;	val_dir[6024*3 + 2] = 0.841482f;
+ 	val_dir[6025*3 + 0] = -0.484217f;	val_dir[6025*3 + 1] = 0.217898f;	val_dir[6025*3 + 2] = 0.847381f;
+ 	val_dir[6026*3 + 0] = -0.462727f;	val_dir[6026*3 + 1] = 0.243541f;	val_dir[6026*3 + 2] = 0.852392f;
+ 	val_dir[6027*3 + 0] = -0.440468f;	val_dir[6027*3 + 1] = 0.269175f;	val_dir[6027*3 + 2] = 0.856465f;
+ 	val_dir[6028*3 + 0] = -0.41750f;	val_dir[6028*3 + 1] = 0.294706f;	val_dir[6028*3 + 2] = 0.859559f;
+ 	val_dir[6029*3 + 0] = -0.393893f;	val_dir[6029*3 + 1] = 0.320038f;	val_dir[6029*3 + 2] = 0.861640f;
+ 	val_dir[6030*3 + 0] = -0.369723f;	val_dir[6030*3 + 1] = 0.345075f;	val_dir[6030*3 + 2] = 0.862687f;
+ 	val_dir[6031*3 + 0] = -0.345075f;	val_dir[6031*3 + 1] = 0.369723f;	val_dir[6031*3 + 2] = 0.862687f;
+ 	val_dir[6032*3 + 0] = -0.320038f;	val_dir[6032*3 + 1] = 0.393893f;	val_dir[6032*3 + 2] = 0.861640f;
+ 	val_dir[6033*3 + 0] = -0.294706f;	val_dir[6033*3 + 1] = 0.41750f;	val_dir[6033*3 + 2] = 0.859559f;
+ 	val_dir[6034*3 + 0] = -0.269175f;	val_dir[6034*3 + 1] = 0.440468f;	val_dir[6034*3 + 2] = 0.856465f;
+ 	val_dir[6035*3 + 0] = -0.243541f;	val_dir[6035*3 + 1] = 0.462727f;	val_dir[6035*3 + 2] = 0.852392f;
+ 	val_dir[6036*3 + 0] = -0.217898f;	val_dir[6036*3 + 1] = 0.484217f;	val_dir[6036*3 + 2] = 0.847381f;
+ 	val_dir[6037*3 + 0] = -0.192339f;	val_dir[6037*3 + 1] = 0.504889f;	val_dir[6037*3 + 2] = 0.841482f;
+ 	val_dir[6038*3 + 0] = -0.166951f;	val_dir[6038*3 + 1] = 0.524703f;	val_dir[6038*3 + 2] = 0.834754f;
+ 	val_dir[6039*3 + 0] = -0.141816f;	val_dir[6039*3 + 1] = 0.543627f;	val_dir[6039*3 + 2] = 0.827259f;
+ 	val_dir[6040*3 + 0] = -0.117009f;	val_dir[6040*3 + 1] = 0.561644f;	val_dir[6040*3 + 2] = 0.819064f;
+ 	val_dir[6041*3 + 0] = -0.092599f;	val_dir[6041*3 + 1] = 0.578741f;	val_dir[6041*3 + 2] = 0.810237f;
+ 	val_dir[6042*3 + 0] = -0.068644f;	val_dir[6042*3 + 1] = 0.594917f;	val_dir[6042*3 + 2] = 0.800850f;
+ 	val_dir[6043*3 + 0] = -0.045198f;	val_dir[6043*3 + 1] = 0.610179f;	val_dir[6043*3 + 2] = 0.790973f;
+ 	val_dir[6044*3 + 0] = -0.022305f;	val_dir[6044*3 + 1] = 0.624540f;	val_dir[6044*3 + 2] = 0.780675f;
+ 	val_dir[6045*3 + 0] = 0.0f;	val_dir[6045*3 + 1] = 0.638018f;	val_dir[6045*3 + 2] = 0.770022f;
+ 	val_dir[6046*3 + 0] = 0.022417f;	val_dir[6046*3 + 1] = 0.672504f;	val_dir[6046*3 + 2] = 0.739754f;
+ 	val_dir[6047*3 + 0] = 0.045572f;	val_dir[6047*3 + 1] = 0.706372f;	val_dir[6047*3 + 2] = 0.706372f;
+ 	val_dir[6048*3 + 0] = 0.069301f;	val_dir[6048*3 + 1] = 0.739205f;	val_dir[6048*3 + 2] = 0.669905f;
+ 	val_dir[6049*3 + 0] = 0.093403f;	val_dir[6049*3 + 1] = 0.770574f;	val_dir[6049*3 + 2] = 0.630470f;
+ 	val_dir[6050*3 + 0] = 0.117655f;	val_dir[6050*3 + 1] = 0.800055f;	val_dir[6050*3 + 2] = 0.588276f;
+ 	val_dir[6051*3 + 0] = 0.141816f;	val_dir[6051*3 + 1] = 0.827259f;	val_dir[6051*3 + 2] = 0.543627f;
+ 	val_dir[6052*3 + 0] = 0.165637f;	val_dir[6052*3 + 1] = 0.851847f;	val_dir[6052*3 + 2] = 0.496911f;
+ 	val_dir[6053*3 + 0] = 0.188877f;	val_dir[6053*3 + 1] = 0.873555f;	val_dir[6053*3 + 2] = 0.448583f;
+ 	val_dir[6054*3 + 0] = 0.211312f;	val_dir[6054*3 + 1] = 0.892206f;	val_dir[6054*3 + 2] = 0.399145f;
+ 	val_dir[6055*3 + 0] = 0.232747f;	val_dir[6055*3 + 1] = 0.907713f;	val_dir[6055*3 + 2] = 0.349121f;
+ 	val_dir[6056*3 + 0] = 0.253024f;	val_dir[6056*3 + 1] = 0.920087f;	val_dir[6056*3 + 2] = 0.299028f;
+ 	val_dir[6057*3 + 0] = 0.272026f;	val_dir[6057*3 + 1] = 0.929421f;	val_dir[6057*3 + 2] = 0.249357f;
+ 	val_dir[6058*3 + 0] = 0.289677f;	val_dir[6058*3 + 1] = 0.935879f;	val_dir[6058*3 + 2] = 0.200545f;
+ 	val_dir[6059*3 + 0] = 0.305942f;	val_dir[6059*3 + 1] = 0.939680f;	val_dir[6059*3 + 2] = 0.152971f;
+ 	val_dir[6060*3 + 0] = 0.320824f;	val_dir[6060*3 + 1] = 0.941082f;	val_dir[6060*3 + 2] = 0.106941f;
+ 	val_dir[6061*3 + 0] = 0.334351f;	val_dir[6061*3 + 1] = 0.940361f;	val_dir[6061*3 + 2] = 0.062691f;
+ 	val_dir[6062*3 + 0] = 0.346578f;	val_dir[6062*3 + 1] = 0.93780f;	val_dir[6062*3 + 2] = 0.020387f;
+ 	val_dir[6063*3 + 0] = -0.940376f;	val_dir[6063*3 + 1] = -0.340136f;	val_dir[6063*3 + 2] = 0.0f;
+ 	val_dir[6064*3 + 0] = -0.943701f;	val_dir[6064*3 + 1] = -0.328244f;	val_dir[6064*3 + 2] = 0.041030f;
+ 	val_dir[6065*3 + 0] = -0.945328f;	val_dir[6065*3 + 1] = -0.315109f;	val_dir[6065*3 + 2] = 0.084029f;
+ 	val_dir[6066*3 + 0] = -0.944981f;	val_dir[6066*3 + 1] = -0.300676f;	val_dir[6066*3 + 2] = 0.128861f;
+ 	val_dir[6067*3 + 0] = -0.942384f;	val_dir[6067*3 + 1] = -0.284907f;	val_dir[6067*3 + 2] = 0.175327f;
+ 	val_dir[6068*3 + 0] = -0.937276f;	val_dir[6068*3 + 1] = -0.267793f;	val_dir[6068*3 + 2] = 0.223161f;
+ 	val_dir[6069*3 + 0] = -0.929421f;	val_dir[6069*3 + 1] = -0.249357f;	val_dir[6069*3 + 2] = 0.272026f;
+ 	val_dir[6070*3 + 0] = -0.918630f;	val_dir[6070*3 + 1] = -0.229658f;	val_dir[6070*3 + 2] = 0.321521f;
+ 	val_dir[6071*3 + 0] = -0.904777f;	val_dir[6071*3 + 1] = -0.208795f;	val_dir[6071*3 + 2] = 0.371191f;
+ 	val_dir[6072*3 + 0] = -0.887812f;	val_dir[6072*3 + 1] = -0.186908f;	val_dir[6072*3 + 2] = 0.420542f;
+ 	val_dir[6073*3 + 0] = -0.867770f;	val_dir[6073*3 + 1] = -0.164173f;	val_dir[6073*3 + 2] = 0.469065f;
+ 	val_dir[6074*3 + 0] = -0.844782f;	val_dir[6074*3 + 1] = -0.140797f;	val_dir[6074*3 + 2] = 0.516256f;
+ 	val_dir[6075*3 + 0] = -0.819064f;	val_dir[6075*3 + 1] = -0.117009f;	val_dir[6075*3 + 2] = 0.561644f;
+ 	val_dir[6076*3 + 0] = -0.790912f;	val_dir[6076*3 + 1] = -0.093048f;	val_dir[6076*3 + 2] = 0.604815f;
+ 	val_dir[6077*3 + 0] = -0.760684f;	val_dir[6077*3 + 1] = -0.069153f;	val_dir[6077*3 + 2] = 0.645429f;
+ 	val_dir[6078*3 + 0] = -0.728780f;	val_dir[6078*3 + 1] = -0.045549f;	val_dir[6078*3 + 2] = 0.683231f;
+ 	val_dir[6079*3 + 0] = -0.695620f;	val_dir[6079*3 + 1] = -0.022439f;	val_dir[6079*3 + 2] = 0.718059f;
+ 	val_dir[6080*3 + 0] = -0.661622f;	val_dir[6080*3 + 1] = 0.0f;	val_dir[6080*3 + 2] = 0.749838f;
+ 	val_dir[6081*3 + 0] = -0.648784f;	val_dir[6081*3 + 1] = 0.022372f;	val_dir[6081*3 + 2] = 0.760644f;
+ 	val_dir[6082*3 + 0] = -0.635053f;	val_dir[6082*3 + 1] = 0.045361f;	val_dir[6082*3 + 2] = 0.771136f;
+ 	val_dir[6083*3 + 0] = -0.620403f;	val_dir[6083*3 + 1] = 0.068934f;	val_dir[6083*3 + 2] = 0.781248f;
+ 	val_dir[6084*3 + 0] = -0.604815f;	val_dir[6084*3 + 1] = 0.093048f;	val_dir[6084*3 + 2] = 0.790912f;
+ 	val_dir[6085*3 + 0] = -0.588276f;	val_dir[6085*3 + 1] = 0.117655f;	val_dir[6085*3 + 2] = 0.800055f;
+ 	val_dir[6086*3 + 0] = -0.570782f;	val_dir[6086*3 + 1] = 0.142695f;	val_dir[6086*3 + 2] = 0.808608f;
+ 	val_dir[6087*3 + 0] = -0.552336f;	val_dir[6087*3 + 1] = 0.168102f;	val_dir[6087*3 + 2] = 0.816497f;
+ 	val_dir[6088*3 + 0] = -0.532952f;	val_dir[6088*3 + 1] = 0.193801f;	val_dir[6088*3 + 2] = 0.823653f;
+ 	val_dir[6089*3 + 0] = -0.512653f;	val_dir[6089*3 + 1] = 0.219708f;	val_dir[6089*3 + 2] = 0.830009f;
+ 	val_dir[6090*3 + 0] = -0.491473f;	val_dir[6090*3 + 1] = 0.245737f;	val_dir[6090*3 + 2] = 0.835504f;
+ 	val_dir[6091*3 + 0] = -0.469458f;	val_dir[6091*3 + 1] = 0.271791f;	val_dir[6091*3 + 2] = 0.840083f;
+ 	val_dir[6092*3 + 0] = -0.446662f;	val_dir[6092*3 + 1] = 0.297775f;	val_dir[6092*3 + 2] = 0.843696f;
+ 	val_dir[6093*3 + 0] = -0.423153f;	val_dir[6093*3 + 1] = 0.323587f;	val_dir[6093*3 + 2] = 0.846305f;
+ 	val_dir[6094*3 + 0] = -0.399004f;	val_dir[6094*3 + 1] = 0.349128f;	val_dir[6094*3 + 2] = 0.847883f;
+ 	val_dir[6095*3 + 0] = -0.374299f;	val_dir[6095*3 + 1] = 0.374299f;	val_dir[6095*3 + 2] = 0.848411f;
+ 	val_dir[6096*3 + 0] = -0.349128f;	val_dir[6096*3 + 1] = 0.399004f;	val_dir[6096*3 + 2] = 0.847883f;
+ 	val_dir[6097*3 + 0] = -0.323587f;	val_dir[6097*3 + 1] = 0.423153f;	val_dir[6097*3 + 2] = 0.846305f;
+ 	val_dir[6098*3 + 0] = -0.297775f;	val_dir[6098*3 + 1] = 0.446662f;	val_dir[6098*3 + 2] = 0.843696f;
+ 	val_dir[6099*3 + 0] = -0.271791f;	val_dir[6099*3 + 1] = 0.469458f;	val_dir[6099*3 + 2] = 0.840083f;
+ 	val_dir[6100*3 + 0] = -0.245737f;	val_dir[6100*3 + 1] = 0.491473f;	val_dir[6100*3 + 2] = 0.835504f;
+ 	val_dir[6101*3 + 0] = -0.219708f;	val_dir[6101*3 + 1] = 0.512653f;	val_dir[6101*3 + 2] = 0.830009f;
+ 	val_dir[6102*3 + 0] = -0.193801f;	val_dir[6102*3 + 1] = 0.532952f;	val_dir[6102*3 + 2] = 0.823653f;
+ 	val_dir[6103*3 + 0] = -0.168102f;	val_dir[6103*3 + 1] = 0.552336f;	val_dir[6103*3 + 2] = 0.816497f;
+ 	val_dir[6104*3 + 0] = -0.142695f;	val_dir[6104*3 + 1] = 0.570782f;	val_dir[6104*3 + 2] = 0.808608f;
+ 	val_dir[6105*3 + 0] = -0.117655f;	val_dir[6105*3 + 1] = 0.588276f;	val_dir[6105*3 + 2] = 0.800055f;
+ 	val_dir[6106*3 + 0] = -0.093048f;	val_dir[6106*3 + 1] = 0.604815f;	val_dir[6106*3 + 2] = 0.790912f;
+ 	val_dir[6107*3 + 0] = -0.068934f;	val_dir[6107*3 + 1] = 0.620403f;	val_dir[6107*3 + 2] = 0.781248f;
+ 	val_dir[6108*3 + 0] = -0.045361f;	val_dir[6108*3 + 1] = 0.635053f;	val_dir[6108*3 + 2] = 0.771136f;
+ 	val_dir[6109*3 + 0] = -0.022372f;	val_dir[6109*3 + 1] = 0.648784f;	val_dir[6109*3 + 2] = 0.760644f;
+ 	val_dir[6110*3 + 0] = 0.0f;	val_dir[6110*3 + 1] = 0.661622f;	val_dir[6110*3 + 2] = 0.749838f;
+ 	val_dir[6111*3 + 0] = 0.022439f;	val_dir[6111*3 + 1] = 0.695620f;	val_dir[6111*3 + 2] = 0.718059f;
+ 	val_dir[6112*3 + 0] = 0.045549f;	val_dir[6112*3 + 1] = 0.728780f;	val_dir[6112*3 + 2] = 0.683231f;
+ 	val_dir[6113*3 + 0] = 0.069153f;	val_dir[6113*3 + 1] = 0.760684f;	val_dir[6113*3 + 2] = 0.645429f;
+ 	val_dir[6114*3 + 0] = 0.093048f;	val_dir[6114*3 + 1] = 0.790912f;	val_dir[6114*3 + 2] = 0.604815f;
+ 	val_dir[6115*3 + 0] = 0.117009f;	val_dir[6115*3 + 1] = 0.819064f;	val_dir[6115*3 + 2] = 0.561644f;
+ 	val_dir[6116*3 + 0] = 0.140797f;	val_dir[6116*3 + 1] = 0.844782f;	val_dir[6116*3 + 2] = 0.516256f;
+ 	val_dir[6117*3 + 0] = 0.164173f;	val_dir[6117*3 + 1] = 0.867770f;	val_dir[6117*3 + 2] = 0.469065f;
+ 	val_dir[6118*3 + 0] = 0.186908f;	val_dir[6118*3 + 1] = 0.887812f;	val_dir[6118*3 + 2] = 0.420542f;
+ 	val_dir[6119*3 + 0] = 0.208795f;	val_dir[6119*3 + 1] = 0.904777f;	val_dir[6119*3 + 2] = 0.371191f;
+ 	val_dir[6120*3 + 0] = 0.229658f;	val_dir[6120*3 + 1] = 0.918630f;	val_dir[6120*3 + 2] = 0.321521f;
+ 	val_dir[6121*3 + 0] = 0.249357f;	val_dir[6121*3 + 1] = 0.929421f;	val_dir[6121*3 + 2] = 0.272026f;
+ 	val_dir[6122*3 + 0] = 0.267793f;	val_dir[6122*3 + 1] = 0.937276f;	val_dir[6122*3 + 2] = 0.223161f;
+ 	val_dir[6123*3 + 0] = 0.284907f;	val_dir[6123*3 + 1] = 0.942384f;	val_dir[6123*3 + 2] = 0.175327f;
+ 	val_dir[6124*3 + 0] = 0.300676f;	val_dir[6124*3 + 1] = 0.944981f;	val_dir[6124*3 + 2] = 0.128861f;
+ 	val_dir[6125*3 + 0] = 0.315109f;	val_dir[6125*3 + 1] = 0.945328f;	val_dir[6125*3 + 2] = 0.084029f;
+ 	val_dir[6126*3 + 0] = 0.328244f;	val_dir[6126*3 + 1] = 0.943701f;	val_dir[6126*3 + 2] = 0.041030f;
+ 	val_dir[6127*3 + 0] = 0.340136f;	val_dir[6127*3 + 1] = 0.940376f;	val_dir[6127*3 + 2] = 0.0f;
+ 	val_dir[6128*3 + 0] = -0.946458f;	val_dir[6128*3 + 1] = -0.322198f;	val_dir[6128*3 + 2] = 0.020137f;
+ 	val_dir[6129*3 + 0] = -0.948908f;	val_dir[6129*3 + 1] = -0.309426f;	val_dir[6129*3 + 2] = 0.061885f;
+ 	val_dir[6130*3 + 0] = -0.949528f;	val_dir[6130*3 + 1] = -0.295409f;	val_dir[6130*3 + 2] = 0.105503f;
+ 	val_dir[6131*3 + 0] = -0.948047f;	val_dir[6131*3 + 1] = -0.280105f;	val_dir[6131*3 + 2] = 0.150826f;
+ 	val_dir[6132*3 + 0] = -0.94420f;	val_dir[6132*3 + 1] = -0.263498f;	val_dir[6132*3 + 2] = 0.197623f;
+ 	val_dir[6133*3 + 0] = -0.937743f;	val_dir[6133*3 + 1] = -0.245599f;	val_dir[6133*3 + 2] = 0.245599f;
+ 	val_dir[6134*3 + 0] = -0.928467f;	val_dir[6134*3 + 1] = -0.226455f;	val_dir[6134*3 + 2] = 0.294392f;
+ 	val_dir[6135*3 + 0] = -0.916217f;	val_dir[6135*3 + 1] = -0.206149f;	val_dir[6135*3 + 2] = 0.343582f;
+ 	val_dir[6136*3 + 0] = -0.900907f;	val_dir[6136*3 + 1] = -0.184801f;	val_dir[6136*3 + 2] = 0.392703f;
+ 	val_dir[6137*3 + 0] = -0.882528f;	val_dir[6137*3 + 1] = -0.162571f;	val_dir[6137*3 + 2] = 0.441264f;
+ 	val_dir[6138*3 + 0] = -0.861164f;	val_dir[6138*3 + 1] = -0.139648f;	val_dir[6138*3 + 2] = 0.488769f;
+ 	val_dir[6139*3 + 0] = -0.836983f;	val_dir[6139*3 + 1] = -0.116248f;	val_dir[6139*3 + 2] = 0.534739f;
+ 	val_dir[6140*3 + 0] = -0.810237f;	val_dir[6140*3 + 1] = -0.092599f;	val_dir[6140*3 + 2] = 0.578741f;
+ 	val_dir[6141*3 + 0] = -0.781248f;	val_dir[6141*3 + 1] = -0.068934f;	val_dir[6141*3 + 2] = 0.620403f;
+ 	val_dir[6142*3 + 0] = -0.750388f;	val_dir[6142*3 + 1] = -0.045478f;	val_dir[6142*3 + 2] = 0.659432f;
+ 	val_dir[6143*3 + 0] = -0.718059f;	val_dir[6143*3 + 1] = -0.022439f;	val_dir[6143*3 + 2] = 0.695620f;
+ 	val_dir[6144*3 + 0] = -0.684675f;	val_dir[6144*3 + 1] = 0.0f;	val_dir[6144*3 + 2] = 0.728848f;
+ 	val_dir[6145*3 + 0] = -0.672504f;	val_dir[6145*3 + 1] = 0.022417f;	val_dir[6145*3 + 2] = 0.739754f;
+ 	val_dir[6146*3 + 0] = -0.659432f;	val_dir[6146*3 + 1] = 0.045478f;	val_dir[6146*3 + 2] = 0.750388f;
+ 	val_dir[6147*3 + 0] = -0.645429f;	val_dir[6147*3 + 1] = 0.069153f;	val_dir[6147*3 + 2] = 0.760684f;
+ 	val_dir[6148*3 + 0] = -0.630470f;	val_dir[6148*3 + 1] = 0.093403f;	val_dir[6148*3 + 2] = 0.770574f;
+ 	val_dir[6149*3 + 0] = -0.614535f;	val_dir[6149*3 + 1] = 0.118180f;	val_dir[6149*3 + 2] = 0.779987f;
+ 	val_dir[6150*3 + 0] = -0.597614f;	val_dir[6150*3 + 1] = 0.143427f;	val_dir[6150*3 + 2] = 0.788851f;
+ 	val_dir[6151*3 + 0] = -0.579703f;	val_dir[6151*3 + 1] = 0.169080f;	val_dir[6151*3 + 2] = 0.797092f;
+ 	val_dir[6152*3 + 0] = -0.560809f;	val_dir[6152*3 + 1] = 0.195064f;	val_dir[6152*3 + 2] = 0.804639f;
+ 	val_dir[6153*3 + 0] = -0.540947f;	val_dir[6153*3 + 1] = 0.221297f;	val_dir[6153*3 + 2] = 0.811421f;
+ 	val_dir[6154*3 + 0] = -0.520146f;	val_dir[6154*3 + 1] = 0.247689f;	val_dir[6154*3 + 2] = 0.817373f;
+ 	val_dir[6155*3 + 0] = -0.498445f;	val_dir[6155*3 + 1] = 0.274145f;	val_dir[6155*3 + 2] = 0.822434f;
+ 	val_dir[6156*3 + 0] = -0.475893f;	val_dir[6156*3 + 1] = 0.300564f;	val_dir[6156*3 + 2] = 0.826551f;
+ 	val_dir[6157*3 + 0] = -0.452553f;	val_dir[6157*3 + 1] = 0.326844f;	val_dir[6157*3 + 2] = 0.829680f;
+ 	val_dir[6158*3 + 0] = -0.428496f;	val_dir[6158*3 + 1] = 0.352879f;	val_dir[6158*3 + 2] = 0.831786f;
+ 	val_dir[6159*3 + 0] = -0.403804f;	val_dir[6159*3 + 1] = 0.378566f;	val_dir[6159*3 + 2] = 0.832845f;
+ 	val_dir[6160*3 + 0] = -0.378566f;	val_dir[6160*3 + 1] = 0.403804f;	val_dir[6160*3 + 2] = 0.832845f;
+ 	val_dir[6161*3 + 0] = -0.352879f;	val_dir[6161*3 + 1] = 0.428496f;	val_dir[6161*3 + 2] = 0.831786f;
+ 	val_dir[6162*3 + 0] = -0.326844f;	val_dir[6162*3 + 1] = 0.452553f;	val_dir[6162*3 + 2] = 0.829680f;
+ 	val_dir[6163*3 + 0] = -0.300564f;	val_dir[6163*3 + 1] = 0.475893f;	val_dir[6163*3 + 2] = 0.826551f;
+ 	val_dir[6164*3 + 0] = -0.274145f;	val_dir[6164*3 + 1] = 0.498445f;	val_dir[6164*3 + 2] = 0.822434f;
+ 	val_dir[6165*3 + 0] = -0.247689f;	val_dir[6165*3 + 1] = 0.520146f;	val_dir[6165*3 + 2] = 0.817373f;
+ 	val_dir[6166*3 + 0] = -0.221297f;	val_dir[6166*3 + 1] = 0.540947f;	val_dir[6166*3 + 2] = 0.811421f;
+ 	val_dir[6167*3 + 0] = -0.195064f;	val_dir[6167*3 + 1] = 0.560809f;	val_dir[6167*3 + 2] = 0.804639f;
+ 	val_dir[6168*3 + 0] = -0.169080f;	val_dir[6168*3 + 1] = 0.579703f;	val_dir[6168*3 + 2] = 0.797092f;
+ 	val_dir[6169*3 + 0] = -0.143427f;	val_dir[6169*3 + 1] = 0.597614f;	val_dir[6169*3 + 2] = 0.788851f;
+ 	val_dir[6170*3 + 0] = -0.118180f;	val_dir[6170*3 + 1] = 0.614535f;	val_dir[6170*3 + 2] = 0.779987f;
+ 	val_dir[6171*3 + 0] = -0.093403f;	val_dir[6171*3 + 1] = 0.630470f;	val_dir[6171*3 + 2] = 0.770574f;
+ 	val_dir[6172*3 + 0] = -0.069153f;	val_dir[6172*3 + 1] = 0.645429f;	val_dir[6172*3 + 2] = 0.760684f;
+ 	val_dir[6173*3 + 0] = -0.045478f;	val_dir[6173*3 + 1] = 0.659432f;	val_dir[6173*3 + 2] = 0.750388f;
+ 	val_dir[6174*3 + 0] = -0.022417f;	val_dir[6174*3 + 1] = 0.672504f;	val_dir[6174*3 + 2] = 0.739754f;
+ 	val_dir[6175*3 + 0] = 0.0f;	val_dir[6175*3 + 1] = 0.684675f;	val_dir[6175*3 + 2] = 0.728848f;
+ 	val_dir[6176*3 + 0] = 0.022439f;	val_dir[6176*3 + 1] = 0.718059f;	val_dir[6176*3 + 2] = 0.695620f;
+ 	val_dir[6177*3 + 0] = 0.045478f;	val_dir[6177*3 + 1] = 0.750388f;	val_dir[6177*3 + 2] = 0.659432f;
+ 	val_dir[6178*3 + 0] = 0.068934f;	val_dir[6178*3 + 1] = 0.781248f;	val_dir[6178*3 + 2] = 0.620403f;
+ 	val_dir[6179*3 + 0] = 0.092599f;	val_dir[6179*3 + 1] = 0.810237f;	val_dir[6179*3 + 2] = 0.578741f;
+ 	val_dir[6180*3 + 0] = 0.116248f;	val_dir[6180*3 + 1] = 0.836983f;	val_dir[6180*3 + 2] = 0.534739f;
+ 	val_dir[6181*3 + 0] = 0.139648f;	val_dir[6181*3 + 1] = 0.861164f;	val_dir[6181*3 + 2] = 0.488769f;
+ 	val_dir[6182*3 + 0] = 0.162571f;	val_dir[6182*3 + 1] = 0.882528f;	val_dir[6182*3 + 2] = 0.441264f;
+ 	val_dir[6183*3 + 0] = 0.184801f;	val_dir[6183*3 + 1] = 0.900907f;	val_dir[6183*3 + 2] = 0.392703f;
+ 	val_dir[6184*3 + 0] = 0.206149f;	val_dir[6184*3 + 1] = 0.916217f;	val_dir[6184*3 + 2] = 0.343582f;
+ 	val_dir[6185*3 + 0] = 0.226455f;	val_dir[6185*3 + 1] = 0.928467f;	val_dir[6185*3 + 2] = 0.294392f;
+ 	val_dir[6186*3 + 0] = 0.245599f;	val_dir[6186*3 + 1] = 0.937743f;	val_dir[6186*3 + 2] = 0.245599f;
+ 	val_dir[6187*3 + 0] = 0.263498f;	val_dir[6187*3 + 1] = 0.94420f;	val_dir[6187*3 + 2] = 0.197623f;
+ 	val_dir[6188*3 + 0] = 0.280105f;	val_dir[6188*3 + 1] = 0.948047f;	val_dir[6188*3 + 2] = 0.150826f;
+ 	val_dir[6189*3 + 0] = 0.295409f;	val_dir[6189*3 + 1] = 0.949528f;	val_dir[6189*3 + 2] = 0.105503f;
+ 	val_dir[6190*3 + 0] = 0.309426f;	val_dir[6190*3 + 1] = 0.948908f;	val_dir[6190*3 + 2] = 0.061885f;
+ 	val_dir[6191*3 + 0] = 0.322198f;	val_dir[6191*3 + 1] = 0.946458f;	val_dir[6191*3 + 2] = 0.020137f;
+ 	val_dir[6192*3 + 0] = -0.948683f;	val_dir[6192*3 + 1] = -0.316228f;	val_dir[6192*3 + 2] = 0.0f;
+ 	val_dir[6193*3 + 0] = -0.951877f;	val_dir[6193*3 + 1] = -0.303791f;	val_dir[6193*3 + 2] = 0.040505f;
+ 	val_dir[6194*3 + 0] = -0.953381f;	val_dir[6194*3 + 1] = -0.290159f;	val_dir[6194*3 + 2] = 0.082903f;
+ 	val_dir[6195*3 + 0] = -0.952928f;	val_dir[6195*3 + 1] = -0.275290f;	val_dir[6195*3 + 2] = 0.127057f;
+ 	val_dir[6196*3 + 0] = -0.950255f;	val_dir[6196*3 + 1] = -0.259161f;	val_dir[6196*3 + 2] = 0.172774f;
+ 	val_dir[6197*3 + 0] = -0.945112f;	val_dir[6197*3 + 1] = -0.241773f;	val_dir[6197*3 + 2] = 0.219793f;
+ 	val_dir[6198*3 + 0] = -0.937276f;	val_dir[6198*3 + 1] = -0.223161f;	val_dir[6198*3 + 2] = 0.267793f;
+ 	val_dir[6199*3 + 0] = -0.926568f;	val_dir[6199*3 + 1] = -0.203393f;	val_dir[6199*3 + 2] = 0.316389f;
+ 	val_dir[6200*3 + 0] = -0.912871f;	val_dir[6200*3 + 1] = -0.182574f;	val_dir[6200*3 + 2] = 0.365148f;
+ 	val_dir[6201*3 + 0] = -0.896137f;	val_dir[6201*3 + 1] = -0.160845f;	val_dir[6201*3 + 2] = 0.413602f;
+ 	val_dir[6202*3 + 0] = -0.876405f;	val_dir[6202*3 + 1] = -0.138380f;	val_dir[6202*3 + 2] = 0.461266f;
+ 	val_dir[6203*3 + 0] = -0.853796f;	val_dir[6203*3 + 1] = -0.115378f;	val_dir[6203*3 + 2] = 0.507662f;
+ 	val_dir[6204*3 + 0] = -0.828517f;	val_dir[6204*3 + 1] = -0.092057f;	val_dir[6204*3 + 2] = 0.552345f;
+ 	val_dir[6205*3 + 0] = -0.800850f;	val_dir[6205*3 + 1] = -0.068644f;	val_dir[6205*3 + 2] = 0.594917f;
+ 	val_dir[6206*3 + 0] = -0.771136f;	val_dir[6206*3 + 1] = -0.045361f;	val_dir[6206*3 + 2] = 0.635053f;
+ 	val_dir[6207*3 + 0] = -0.739754f;	val_dir[6207*3 + 1] = -0.022417f;	val_dir[6207*3 + 2] = 0.672504f;
+ 	val_dir[6208*3 + 0] = -0.707107f;	val_dir[6208*3 + 1] = 0.0f;	val_dir[6208*3 + 2] = 0.707107f;
+ 	val_dir[6209*3 + 0] = -0.695620f;	val_dir[6209*3 + 1] = 0.022439f;	val_dir[6209*3 + 2] = 0.718059f;
+ 	val_dir[6210*3 + 0] = -0.683231f;	val_dir[6210*3 + 1] = 0.045549f;	val_dir[6210*3 + 2] = 0.728780f;
+ 	val_dir[6211*3 + 0] = -0.669905f;	val_dir[6211*3 + 1] = 0.069301f;	val_dir[6211*3 + 2] = 0.739205f;
+ 	val_dir[6212*3 + 0] = -0.655610f;	val_dir[6212*3 + 1] = 0.093659f;	val_dir[6212*3 + 2] = 0.749269f;
+ 	val_dir[6213*3 + 0] = -0.640321f;	val_dir[6213*3 + 1] = 0.118578f;	val_dir[6213*3 + 2] = 0.758899f;
+ 	val_dir[6214*3 + 0] = -0.624020f;	val_dir[6214*3 + 1] = 0.144005f;	val_dir[6214*3 + 2] = 0.768025f;
+ 	val_dir[6215*3 + 0] = -0.606696f;	val_dir[6215*3 + 1] = 0.169875f;	val_dir[6215*3 + 2] = 0.776571f;
+ 	val_dir[6216*3 + 0] = -0.588348f;	val_dir[6216*3 + 1] = 0.196116f;	val_dir[6216*3 + 2] = 0.784465f;
+ 	val_dir[6217*3 + 0] = -0.568986f;	val_dir[6217*3 + 1] = 0.222647f;	val_dir[6217*3 + 2] = 0.791633f;
+ 	val_dir[6218*3 + 0] = -0.548630f;	val_dir[6218*3 + 1] = 0.249377f;	val_dir[6218*3 + 2] = 0.798007f;
+ 	val_dir[6219*3 + 0] = -0.527312f;	val_dir[6219*3 + 1] = 0.276211f;	val_dir[6219*3 + 2] = 0.803523f;
+ 	val_dir[6220*3 + 0] = -0.505076f;	val_dir[6220*3 + 1] = 0.303046f;	val_dir[6220*3 + 2] = 0.808122f;
+ 	val_dir[6221*3 + 0] = -0.481979f;	val_dir[6221*3 + 1] = 0.329775f;	val_dir[6221*3 + 2] = 0.811754f;
+ 	val_dir[6222*3 + 0] = -0.458088f;	val_dir[6222*3 + 1] = 0.356291f;	val_dir[6222*3 + 2] = 0.814379f;
+ 	val_dir[6223*3 + 0] = -0.433482f;	val_dir[6223*3 + 1] = 0.382484f;	val_dir[6223*3 + 2] = 0.815966f;
+ 	val_dir[6224*3 + 0] = -0.408248f;	val_dir[6224*3 + 1] = 0.408248f;	val_dir[6224*3 + 2] = 0.816497f;
+ 	val_dir[6225*3 + 0] = -0.382484f;	val_dir[6225*3 + 1] = 0.433482f;	val_dir[6225*3 + 2] = 0.815966f;
+ 	val_dir[6226*3 + 0] = -0.356291f;	val_dir[6226*3 + 1] = 0.458088f;	val_dir[6226*3 + 2] = 0.814379f;
+ 	val_dir[6227*3 + 0] = -0.329775f;	val_dir[6227*3 + 1] = 0.481979f;	val_dir[6227*3 + 2] = 0.811754f;
+ 	val_dir[6228*3 + 0] = -0.303046f;	val_dir[6228*3 + 1] = 0.505076f;	val_dir[6228*3 + 2] = 0.808122f;
+ 	val_dir[6229*3 + 0] = -0.276211f;	val_dir[6229*3 + 1] = 0.527312f;	val_dir[6229*3 + 2] = 0.803523f;
+ 	val_dir[6230*3 + 0] = -0.249377f;	val_dir[6230*3 + 1] = 0.548630f;	val_dir[6230*3 + 2] = 0.798007f;
+ 	val_dir[6231*3 + 0] = -0.222647f;	val_dir[6231*3 + 1] = 0.568986f;	val_dir[6231*3 + 2] = 0.791633f;
+ 	val_dir[6232*3 + 0] = -0.196116f;	val_dir[6232*3 + 1] = 0.588348f;	val_dir[6232*3 + 2] = 0.784465f;
+ 	val_dir[6233*3 + 0] = -0.169875f;	val_dir[6233*3 + 1] = 0.606696f;	val_dir[6233*3 + 2] = 0.776571f;
+ 	val_dir[6234*3 + 0] = -0.144005f;	val_dir[6234*3 + 1] = 0.624020f;	val_dir[6234*3 + 2] = 0.768025f;
+ 	val_dir[6235*3 + 0] = -0.118578f;	val_dir[6235*3 + 1] = 0.640321f;	val_dir[6235*3 + 2] = 0.758899f;
+ 	val_dir[6236*3 + 0] = -0.093659f;	val_dir[6236*3 + 1] = 0.655610f;	val_dir[6236*3 + 2] = 0.749269f;
+ 	val_dir[6237*3 + 0] = -0.069301f;	val_dir[6237*3 + 1] = 0.669905f;	val_dir[6237*3 + 2] = 0.739205f;
+ 	val_dir[6238*3 + 0] = -0.045549f;	val_dir[6238*3 + 1] = 0.683231f;	val_dir[6238*3 + 2] = 0.728780f;
+ 	val_dir[6239*3 + 0] = -0.022439f;	val_dir[6239*3 + 1] = 0.695620f;	val_dir[6239*3 + 2] = 0.718059f;
+ 	val_dir[6240*3 + 0] = 0.0f;	val_dir[6240*3 + 1] = 0.707107f;	val_dir[6240*3 + 2] = 0.707107f;
+ 	val_dir[6241*3 + 0] = 0.022417f;	val_dir[6241*3 + 1] = 0.739754f;	val_dir[6241*3 + 2] = 0.672504f;
+ 	val_dir[6242*3 + 0] = 0.045361f;	val_dir[6242*3 + 1] = 0.771136f;	val_dir[6242*3 + 2] = 0.635053f;
+ 	val_dir[6243*3 + 0] = 0.068644f;	val_dir[6243*3 + 1] = 0.800850f;	val_dir[6243*3 + 2] = 0.594917f;
+ 	val_dir[6244*3 + 0] = 0.092057f;	val_dir[6244*3 + 1] = 0.828517f;	val_dir[6244*3 + 2] = 0.552345f;
+ 	val_dir[6245*3 + 0] = 0.115378f;	val_dir[6245*3 + 1] = 0.853796f;	val_dir[6245*3 + 2] = 0.507662f;
+ 	val_dir[6246*3 + 0] = 0.138380f;	val_dir[6246*3 + 1] = 0.876405f;	val_dir[6246*3 + 2] = 0.461266f;
+ 	val_dir[6247*3 + 0] = 0.160845f;	val_dir[6247*3 + 1] = 0.896137f;	val_dir[6247*3 + 2] = 0.413602f;
+ 	val_dir[6248*3 + 0] = 0.182574f;	val_dir[6248*3 + 1] = 0.912871f;	val_dir[6248*3 + 2] = 0.365148f;
+ 	val_dir[6249*3 + 0] = 0.203393f;	val_dir[6249*3 + 1] = 0.926568f;	val_dir[6249*3 + 2] = 0.316389f;
+ 	val_dir[6250*3 + 0] = 0.223161f;	val_dir[6250*3 + 1] = 0.937276f;	val_dir[6250*3 + 2] = 0.267793f;
+ 	val_dir[6251*3 + 0] = 0.241773f;	val_dir[6251*3 + 1] = 0.945112f;	val_dir[6251*3 + 2] = 0.219793f;
+ 	val_dir[6252*3 + 0] = 0.259161f;	val_dir[6252*3 + 1] = 0.950255f;	val_dir[6252*3 + 2] = 0.172774f;
+ 	val_dir[6253*3 + 0] = 0.275290f;	val_dir[6253*3 + 1] = 0.952928f;	val_dir[6253*3 + 2] = 0.127057f;
+ 	val_dir[6254*3 + 0] = 0.290159f;	val_dir[6254*3 + 1] = 0.953381f;	val_dir[6254*3 + 2] = 0.082903f;
+ 	val_dir[6255*3 + 0] = 0.303791f;	val_dir[6255*3 + 1] = 0.951877f;	val_dir[6255*3 + 2] = 0.040505f;
+ 	val_dir[6256*3 + 0] = 0.316228f;	val_dir[6256*3 + 1] = 0.948683f;	val_dir[6256*3 + 2] = 0.0f;
+ 	val_dir[6257*3 + 0] = -0.954291f;	val_dir[6257*3 + 1] = -0.298216f;	val_dir[6257*3 + 2] = 0.019881f;
+ 	val_dir[6258*3 + 0] = -0.956597f;	val_dir[6258*3 + 1] = -0.284944f;	val_dir[6258*3 + 2] = 0.061059f;
+ 	val_dir[6259*3 + 0] = -0.957088f;	val_dir[6259*3 + 1] = -0.270481f;	val_dir[6259*3 + 2] = 0.104031f;
+ 	val_dir[6260*3 + 0] = -0.955502f;	val_dir[6260*3 + 1] = -0.254801f;	val_dir[6260*3 + 2] = 0.148634f;
+ 	val_dir[6261*3 + 0] = -0.951588f;	val_dir[6261*3 + 1] = -0.237897f;	val_dir[6261*3 + 2] = 0.194643f;
+ 	val_dir[6262*3 + 0] = -0.945112f;	val_dir[6262*3 + 1] = -0.219793f;	val_dir[6262*3 + 2] = 0.241773f;
+ 	val_dir[6263*3 + 0] = -0.935879f;	val_dir[6263*3 + 1] = -0.200545f;	val_dir[6263*3 + 2] = 0.289677f;
+ 	val_dir[6264*3 + 0] = -0.923742f;	val_dir[6264*3 + 1] = -0.180242f;	val_dir[6264*3 + 2] = 0.337954f;
+ 	val_dir[6265*3 + 0] = -0.908622f;	val_dir[6265*3 + 1] = -0.159009f;	val_dir[6265*3 + 2] = 0.386164f;
+ 	val_dir[6266*3 + 0] = -0.890513f;	val_dir[6266*3 + 1] = -0.137002f;	val_dir[6266*3 + 2] = 0.433840f;
+ 	val_dir[6267*3 + 0] = -0.869495f;	val_dir[6267*3 + 1] = -0.114407f;	val_dir[6267*3 + 2] = 0.480510f;
+ 	val_dir[6268*3 + 0] = -0.845728f;	val_dir[6268*3 + 1] = -0.091430f;	val_dir[6268*3 + 2] = 0.525723f;
+ 	val_dir[6269*3 + 0] = -0.819453f;	val_dir[6269*3 + 1] = -0.068288f;	val_dir[6269*3 + 2] = 0.569064f;
+ 	val_dir[6270*3 + 0] = -0.790973f;	val_dir[6270*3 + 1] = -0.045198f;	val_dir[6270*3 + 2] = 0.610179f;
+ 	val_dir[6271*3 + 0] = -0.760644f;	val_dir[6271*3 + 1] = -0.022372f;	val_dir[6271*3 + 2] = 0.648784f;
+ 	val_dir[6272*3 + 0] = -0.728848f;	val_dir[6272*3 + 1] = 0.0f;	val_dir[6272*3 + 2] = 0.684675f;
+ 	val_dir[6273*3 + 0] = -0.718059f;	val_dir[6273*3 + 1] = 0.022439f;	val_dir[6273*3 + 2] = 0.695620f;
+ 	val_dir[6274*3 + 0] = -0.706372f;	val_dir[6274*3 + 1] = 0.045572f;	val_dir[6274*3 + 2] = 0.706372f;
+ 	val_dir[6275*3 + 0] = -0.693746f;	val_dir[6275*3 + 1] = 0.069375f;	val_dir[6275*3 + 2] = 0.716871f;
+ 	val_dir[6276*3 + 0] = -0.680144f;	val_dir[6276*3 + 1] = 0.093813f;	val_dir[6276*3 + 2] = 0.727051f;
+ 	val_dir[6277*3 + 0] = -0.665536f;	val_dir[6277*3 + 1] = 0.118846f;	val_dir[6277*3 + 2] = 0.736843f;
+ 	val_dir[6278*3 + 0] = -0.649895f;	val_dir[6278*3 + 1] = 0.144421f;	val_dir[6278*3 + 2] = 0.746176f;
+ 	val_dir[6279*3 + 0] = -0.633205f;	val_dir[6279*3 + 1] = 0.170478f;	val_dir[6279*3 + 2] = 0.754976f;
+ 	val_dir[6280*3 + 0] = -0.615457f;	val_dir[6280*3 + 1] = 0.196946f;	val_dir[6280*3 + 2] = 0.763167f;
+ 	val_dir[6281*3 + 0] = -0.596653f;	val_dir[6281*3 + 1] = 0.223745f;	val_dir[6281*3 + 2] = 0.770677f;
+ 	val_dir[6282*3 + 0] = -0.576805f;	val_dir[6282*3 + 1] = 0.250785f;	val_dir[6282*3 + 2] = 0.777433f;
+ 	val_dir[6283*3 + 0] = -0.555939f;	val_dir[6283*3 + 1] = 0.277969f;	val_dir[6283*3 + 2] = 0.783368f;
+ 	val_dir[6284*3 + 0] = -0.534090f;	val_dir[6284*3 + 1] = 0.305194f;	val_dir[6284*3 + 2] = 0.788419f;
+ 	val_dir[6285*3 + 0] = -0.511310f;	val_dir[6285*3 + 1] = 0.332352f;	val_dir[6285*3 + 2] = 0.792530f;
+ 	val_dir[6286*3 + 0] = -0.487661f;	val_dir[6286*3 + 1] = 0.359329f;	val_dir[6286*3 + 2] = 0.795657f;
+ 	val_dir[6287*3 + 0] = -0.463217f;	val_dir[6287*3 + 1] = 0.386014f;	val_dir[6287*3 + 2] = 0.797762f;
+ 	val_dir[6288*3 + 0] = -0.438063f;	val_dir[6288*3 + 1] = 0.412294f;	val_dir[6288*3 + 2] = 0.798820f;
+ 	val_dir[6289*3 + 0] = -0.412294f;	val_dir[6289*3 + 1] = 0.438063f;	val_dir[6289*3 + 2] = 0.798820f;
+ 	val_dir[6290*3 + 0] = -0.386014f;	val_dir[6290*3 + 1] = 0.463217f;	val_dir[6290*3 + 2] = 0.797762f;
+ 	val_dir[6291*3 + 0] = -0.359329f;	val_dir[6291*3 + 1] = 0.487661f;	val_dir[6291*3 + 2] = 0.795657f;
+ 	val_dir[6292*3 + 0] = -0.332352f;	val_dir[6292*3 + 1] = 0.511310f;	val_dir[6292*3 + 2] = 0.792530f;
+ 	val_dir[6293*3 + 0] = -0.305194f;	val_dir[6293*3 + 1] = 0.534090f;	val_dir[6293*3 + 2] = 0.788419f;
+ 	val_dir[6294*3 + 0] = -0.277969f;	val_dir[6294*3 + 1] = 0.555939f;	val_dir[6294*3 + 2] = 0.783368f;
+ 	val_dir[6295*3 + 0] = -0.250785f;	val_dir[6295*3 + 1] = 0.576805f;	val_dir[6295*3 + 2] = 0.777433f;
+ 	val_dir[6296*3 + 0] = -0.223745f;	val_dir[6296*3 + 1] = 0.596653f;	val_dir[6296*3 + 2] = 0.770677f;
+ 	val_dir[6297*3 + 0] = -0.196946f;	val_dir[6297*3 + 1] = 0.615457f;	val_dir[6297*3 + 2] = 0.763167f;
+ 	val_dir[6298*3 + 0] = -0.170478f;	val_dir[6298*3 + 1] = 0.633205f;	val_dir[6298*3 + 2] = 0.754976f;
+ 	val_dir[6299*3 + 0] = -0.144421f;	val_dir[6299*3 + 1] = 0.649895f;	val_dir[6299*3 + 2] = 0.746176f;
+ 	val_dir[6300*3 + 0] = -0.118846f;	val_dir[6300*3 + 1] = 0.665536f;	val_dir[6300*3 + 2] = 0.736843f;
+ 	val_dir[6301*3 + 0] = -0.093813f;	val_dir[6301*3 + 1] = 0.680144f;	val_dir[6301*3 + 2] = 0.727051f;
+ 	val_dir[6302*3 + 0] = -0.069375f;	val_dir[6302*3 + 1] = 0.693746f;	val_dir[6302*3 + 2] = 0.716871f;
+ 	val_dir[6303*3 + 0] = -0.045572f;	val_dir[6303*3 + 1] = 0.706372f;	val_dir[6303*3 + 2] = 0.706372f;
+ 	val_dir[6304*3 + 0] = -0.022439f;	val_dir[6304*3 + 1] = 0.718059f;	val_dir[6304*3 + 2] = 0.695620f;
+ 	val_dir[6305*3 + 0] = 0.0f;	val_dir[6305*3 + 1] = 0.728848f;	val_dir[6305*3 + 2] = 0.684675f;
+ 	val_dir[6306*3 + 0] = 0.022372f;	val_dir[6306*3 + 1] = 0.760644f;	val_dir[6306*3 + 2] = 0.648784f;
+ 	val_dir[6307*3 + 0] = 0.045198f;	val_dir[6307*3 + 1] = 0.790973f;	val_dir[6307*3 + 2] = 0.610179f;
+ 	val_dir[6308*3 + 0] = 0.068288f;	val_dir[6308*3 + 1] = 0.819453f;	val_dir[6308*3 + 2] = 0.569064f;
+ 	val_dir[6309*3 + 0] = 0.091430f;	val_dir[6309*3 + 1] = 0.845728f;	val_dir[6309*3 + 2] = 0.525723f;
+ 	val_dir[6310*3 + 0] = 0.114407f;	val_dir[6310*3 + 1] = 0.869495f;	val_dir[6310*3 + 2] = 0.480510f;
+ 	val_dir[6311*3 + 0] = 0.137002f;	val_dir[6311*3 + 1] = 0.890513f;	val_dir[6311*3 + 2] = 0.433840f;
+ 	val_dir[6312*3 + 0] = 0.159009f;	val_dir[6312*3 + 1] = 0.908622f;	val_dir[6312*3 + 2] = 0.386164f;
+ 	val_dir[6313*3 + 0] = 0.180242f;	val_dir[6313*3 + 1] = 0.923742f;	val_dir[6313*3 + 2] = 0.337954f;
+ 	val_dir[6314*3 + 0] = 0.200545f;	val_dir[6314*3 + 1] = 0.935879f;	val_dir[6314*3 + 2] = 0.289677f;
+ 	val_dir[6315*3 + 0] = 0.219793f;	val_dir[6315*3 + 1] = 0.945112f;	val_dir[6315*3 + 2] = 0.241773f;
+ 	val_dir[6316*3 + 0] = 0.237897f;	val_dir[6316*3 + 1] = 0.951588f;	val_dir[6316*3 + 2] = 0.194643f;
+ 	val_dir[6317*3 + 0] = 0.254801f;	val_dir[6317*3 + 1] = 0.955502f;	val_dir[6317*3 + 2] = 0.148634f;
+ 	val_dir[6318*3 + 0] = 0.270481f;	val_dir[6318*3 + 1] = 0.957088f;	val_dir[6318*3 + 2] = 0.104031f;
+ 	val_dir[6319*3 + 0] = 0.284944f;	val_dir[6319*3 + 1] = 0.956597f;	val_dir[6319*3 + 2] = 0.061059f;
+ 	val_dir[6320*3 + 0] = 0.298216f;	val_dir[6320*3 + 1] = 0.954291f;	val_dir[6320*3 + 2] = 0.019881f;
+ 	val_dir[6321*3 + 0] = -0.95620f;	val_dir[6321*3 + 1] = -0.292714f;	val_dir[6321*3 + 2] = 0.0f;
+ 	val_dir[6322*3 + 0] = -0.959233f;	val_dir[6322*3 + 1] = -0.279776f;	val_dir[6322*3 + 2] = 0.039968f;
+ 	val_dir[6323*3 + 0] = -0.960585f;	val_dir[6323*3 + 1] = -0.265694f;	val_dir[6323*3 + 2] = 0.081752f;
+ 	val_dir[6324*3 + 0] = -0.960001f;	val_dir[6324*3 + 1] = -0.250435f;	val_dir[6324*3 + 2] = 0.125218f;
+ 	val_dir[6325*3 + 0] = -0.957230f;	val_dir[6325*3 + 1] = -0.233990f;	val_dir[6325*3 + 2] = 0.170174f;
+ 	val_dir[6326*3 + 0] = -0.952033f;	val_dir[6326*3 + 1] = -0.216371f;	val_dir[6326*3 + 2] = 0.216371f;
+ 	val_dir[6327*3 + 0] = -0.94420f;	val_dir[6327*3 + 1] = -0.197623f;	val_dir[6327*3 + 2] = 0.263498f;
+ 	val_dir[6328*3 + 0] = -0.933564f;	val_dir[6328*3 + 1] = -0.177822f;	val_dir[6328*3 + 2] = 0.311188f;
+ 	val_dir[6329*3 + 0] = -0.920014f;	val_dir[6329*3 + 1] = -0.157075f;	val_dir[6329*3 + 2] = 0.359030f;
+ 	val_dir[6330*3 + 0] = -0.903508f;	val_dir[6330*3 + 1] = -0.135526f;	val_dir[6330*3 + 2] = 0.406579f;
+ 	val_dir[6331*3 + 0] = -0.884083f;	val_dir[6331*3 + 1] = -0.113344f;	val_dir[6331*3 + 2] = 0.453376f;
+ 	val_dir[6332*3 + 0] = -0.861857f;	val_dir[6332*3 + 1] = -0.090722f;	val_dir[6332*3 + 2] = 0.498970f;
+ 	val_dir[6333*3 + 0] = -0.837027f;	val_dir[6333*3 + 1] = -0.067867f;	val_dir[6333*3 + 2] = 0.542936f;
+ 	val_dir[6334*3 + 0] = -0.809858f;	val_dir[6334*3 + 1] = -0.044992f;	val_dir[6334*3 + 2] = 0.584898f;
+ 	val_dir[6335*3 + 0] = -0.780675f;	val_dir[6335*3 + 1] = -0.022305f;	val_dir[6335*3 + 2] = 0.624540f;
+ 	val_dir[6336*3 + 0] = -0.749838f;	val_dir[6336*3 + 1] = 0.0f;	val_dir[6336*3 + 2] = 0.661622f;
+ 	val_dir[6337*3 + 0] = -0.739754f;	val_dir[6337*3 + 1] = 0.022417f;	val_dir[6337*3 + 2] = 0.672504f;
+ 	val_dir[6338*3 + 0] = -0.728780f;	val_dir[6338*3 + 1] = 0.045549f;	val_dir[6338*3 + 2] = 0.683231f;
+ 	val_dir[6339*3 + 0] = -0.716871f;	val_dir[6339*3 + 1] = 0.069375f;	val_dir[6339*3 + 2] = 0.693746f;
+ 	val_dir[6340*3 + 0] = -0.703985f;	val_dir[6340*3 + 1] = 0.093865f;	val_dir[6340*3 + 2] = 0.703985f;
+ 	val_dir[6341*3 + 0] = -0.690085f;	val_dir[6341*3 + 1] = 0.118980f;	val_dir[6341*3 + 2] = 0.713881f;
+ 	val_dir[6342*3 + 0] = -0.675140f;	val_dir[6342*3 + 1] = 0.144673f;	val_dir[6342*3 + 2] = 0.723364f;
+ 	val_dir[6343*3 + 0] = -0.659125f;	val_dir[6343*3 + 1] = 0.170884f;	val_dir[6343*3 + 2] = 0.732361f;
+ 	val_dir[6344*3 + 0] = -0.642024f;	val_dir[6344*3 + 1] = 0.197546f;	val_dir[6344*3 + 2] = 0.740797f;
+ 	val_dir[6345*3 + 0] = -0.623831f;	val_dir[6345*3 + 1] = 0.224579f;	val_dir[6345*3 + 2] = 0.748598f;
+ 	val_dir[6346*3 + 0] = -0.604551f;	val_dir[6346*3 + 1] = 0.251896f;	val_dir[6346*3 + 2] = 0.755689f;
+ 	val_dir[6347*3 + 0] = -0.584201f;	val_dir[6347*3 + 1] = 0.27940f;	val_dir[6347*3 + 2] = 0.762001f;
+ 	val_dir[6348*3 + 0] = -0.562809f;	val_dir[6348*3 + 1] = 0.306987f;	val_dir[6348*3 + 2] = 0.767467f;
+ 	val_dir[6349*3 + 0] = -0.540419f;	val_dir[6349*3 + 1] = 0.334545f;	val_dir[6349*3 + 2] = 0.772027f;
+ 	val_dir[6350*3 + 0] = -0.517088f;	val_dir[6350*3 + 1] = 0.361961f;	val_dir[6350*3 + 2] = 0.775632f;
+ 	val_dir[6351*3 + 0] = -0.492883f;	val_dir[6351*3 + 1] = 0.389118f;	val_dir[6351*3 + 2] = 0.778237f;
+ 	val_dir[6352*3 + 0] = -0.467888f;	val_dir[6352*3 + 1] = 0.41590f;	val_dir[6352*3 + 2] = 0.779813f;
+ 	val_dir[6353*3 + 0] = -0.442193f;	val_dir[6353*3 + 1] = 0.442193f;	val_dir[6353*3 + 2] = 0.780340f;
+ 	val_dir[6354*3 + 0] = -0.41590f;	val_dir[6354*3 + 1] = 0.467888f;	val_dir[6354*3 + 2] = 0.779813f;
+ 	val_dir[6355*3 + 0] = -0.389118f;	val_dir[6355*3 + 1] = 0.492883f;	val_dir[6355*3 + 2] = 0.778237f;
+ 	val_dir[6356*3 + 0] = -0.361961f;	val_dir[6356*3 + 1] = 0.517088f;	val_dir[6356*3 + 2] = 0.775632f;
+ 	val_dir[6357*3 + 0] = -0.334545f;	val_dir[6357*3 + 1] = 0.540419f;	val_dir[6357*3 + 2] = 0.772027f;
+ 	val_dir[6358*3 + 0] = -0.306987f;	val_dir[6358*3 + 1] = 0.562809f;	val_dir[6358*3 + 2] = 0.767467f;
+ 	val_dir[6359*3 + 0] = -0.27940f;	val_dir[6359*3 + 1] = 0.584201f;	val_dir[6359*3 + 2] = 0.762001f;
+ 	val_dir[6360*3 + 0] = -0.251896f;	val_dir[6360*3 + 1] = 0.604551f;	val_dir[6360*3 + 2] = 0.755689f;
+ 	val_dir[6361*3 + 0] = -0.224579f;	val_dir[6361*3 + 1] = 0.623831f;	val_dir[6361*3 + 2] = 0.748598f;
+ 	val_dir[6362*3 + 0] = -0.197546f;	val_dir[6362*3 + 1] = 0.642024f;	val_dir[6362*3 + 2] = 0.740797f;
+ 	val_dir[6363*3 + 0] = -0.170884f;	val_dir[6363*3 + 1] = 0.659125f;	val_dir[6363*3 + 2] = 0.732361f;
+ 	val_dir[6364*3 + 0] = -0.144673f;	val_dir[6364*3 + 1] = 0.675140f;	val_dir[6364*3 + 2] = 0.723364f;
+ 	val_dir[6365*3 + 0] = -0.118980f;	val_dir[6365*3 + 1] = 0.690085f;	val_dir[6365*3 + 2] = 0.713881f;
+ 	val_dir[6366*3 + 0] = -0.093865f;	val_dir[6366*3 + 1] = 0.703985f;	val_dir[6366*3 + 2] = 0.703985f;
+ 	val_dir[6367*3 + 0] = -0.069375f;	val_dir[6367*3 + 1] = 0.716871f;	val_dir[6367*3 + 2] = 0.693746f;
+ 	val_dir[6368*3 + 0] = -0.045549f;	val_dir[6368*3 + 1] = 0.728780f;	val_dir[6368*3 + 2] = 0.683231f;
+ 	val_dir[6369*3 + 0] = -0.022417f;	val_dir[6369*3 + 1] = 0.739754f;	val_dir[6369*3 + 2] = 0.672504f;
+ 	val_dir[6370*3 + 0] = 0.0f;	val_dir[6370*3 + 1] = 0.749838f;	val_dir[6370*3 + 2] = 0.661622f;
+ 	val_dir[6371*3 + 0] = 0.022305f;	val_dir[6371*3 + 1] = 0.780675f;	val_dir[6371*3 + 2] = 0.624540f;
+ 	val_dir[6372*3 + 0] = 0.044992f;	val_dir[6372*3 + 1] = 0.809858f;	val_dir[6372*3 + 2] = 0.584898f;
+ 	val_dir[6373*3 + 0] = 0.067867f;	val_dir[6373*3 + 1] = 0.837027f;	val_dir[6373*3 + 2] = 0.542936f;
+ 	val_dir[6374*3 + 0] = 0.090722f;	val_dir[6374*3 + 1] = 0.861857f;	val_dir[6374*3 + 2] = 0.498970f;
+ 	val_dir[6375*3 + 0] = 0.113344f;	val_dir[6375*3 + 1] = 0.884083f;	val_dir[6375*3 + 2] = 0.453376f;
+ 	val_dir[6376*3 + 0] = 0.135526f;	val_dir[6376*3 + 1] = 0.903508f;	val_dir[6376*3 + 2] = 0.406579f;
+ 	val_dir[6377*3 + 0] = 0.157075f;	val_dir[6377*3 + 1] = 0.920014f;	val_dir[6377*3 + 2] = 0.359030f;
+ 	val_dir[6378*3 + 0] = 0.177822f;	val_dir[6378*3 + 1] = 0.933564f;	val_dir[6378*3 + 2] = 0.311188f;
+ 	val_dir[6379*3 + 0] = 0.197623f;	val_dir[6379*3 + 1] = 0.94420f;	val_dir[6379*3 + 2] = 0.263498f;
+ 	val_dir[6380*3 + 0] = 0.216371f;	val_dir[6380*3 + 1] = 0.952033f;	val_dir[6380*3 + 2] = 0.216371f;
+ 	val_dir[6381*3 + 0] = 0.233990f;	val_dir[6381*3 + 1] = 0.957230f;	val_dir[6381*3 + 2] = 0.170174f;
+ 	val_dir[6382*3 + 0] = 0.250435f;	val_dir[6382*3 + 1] = 0.960001f;	val_dir[6382*3 + 2] = 0.125218f;
+ 	val_dir[6383*3 + 0] = 0.265694f;	val_dir[6383*3 + 1] = 0.960585f;	val_dir[6383*3 + 2] = 0.081752f;
+ 	val_dir[6384*3 + 0] = 0.279776f;	val_dir[6384*3 + 1] = 0.959233f;	val_dir[6384*3 + 2] = 0.039968f;
+ 	val_dir[6385*3 + 0] = 0.292714f;	val_dir[6385*3 + 1] = 0.95620f;	val_dir[6385*3 + 2] = 0.0f;
+ 	val_dir[6386*3 + 0] = -0.961339f;	val_dir[6386*3 + 1] = -0.274668f;	val_dir[6386*3 + 2] = 0.019619f;
+ 	val_dir[6387*3 + 0] = -0.963475f;	val_dir[6387*3 + 1] = -0.260941f;	val_dir[6387*3 + 2] = 0.060217f;
+ 	val_dir[6388*3 + 0] = -0.963811f;	val_dir[6388*3 + 1] = -0.246079f;	val_dir[6388*3 + 2] = 0.102533f;
+ 	val_dir[6389*3 + 0] = -0.962099f;	val_dir[6389*3 + 1] = -0.230067f;	val_dir[6389*3 + 2] = 0.146406f;
+ 	val_dir[6390*3 + 0] = -0.958098f;	val_dir[6390*3 + 1] = -0.212911f;	val_dir[6390*3 + 2] = 0.191620f;
+ 	val_dir[6391*3 + 0] = -0.951588f;	val_dir[6391*3 + 1] = -0.194643f;	val_dir[6391*3 + 2] = 0.237897f;
+ 	val_dir[6392*3 + 0] = -0.942384f;	val_dir[6392*3 + 1] = -0.175327f;	val_dir[6392*3 + 2] = 0.284907f;
+ 	val_dir[6393*3 + 0] = -0.930352f;	val_dir[6393*3 + 1] = -0.155059f;	val_dir[6393*3 + 2] = 0.332269f;
+ 	val_dir[6394*3 + 0] = -0.915416f;	val_dir[6394*3 + 1] = -0.133963f;	val_dir[6394*3 + 2] = 0.379563f;
+ 	val_dir[6395*3 + 0] = -0.897574f;	val_dir[6395*3 + 1] = -0.112197f;	val_dir[6395*3 + 2] = 0.426348f;
+ 	val_dir[6396*3 + 0] = -0.876903f;	val_dir[6396*3 + 1] = -0.089939f;	val_dir[6396*3 + 2] = 0.472178f;
+ 	val_dir[6397*3 + 0] = -0.853556f;	val_dir[6397*3 + 1] = -0.067386f;	val_dir[6397*3 + 2] = 0.516626f;
+ 	val_dir[6398*3 + 0] = -0.827759f;	val_dir[6398*3 + 1] = -0.044744f;	val_dir[6398*3 + 2] = 0.559297f;
+ 	val_dir[6399*3 + 0] = -0.799803f;	val_dir[6399*3 + 1] = -0.022217f;	val_dir[6399*3 + 2] = 0.599852f;
+ 	val_dir[6400*3 + 0] = -0.770022f;	val_dir[6400*3 + 1] = 0.0f;	val_dir[6400*3 + 2] = 0.638018f;
+ 	val_dir[6401*3 + 0] = -0.760644f;	val_dir[6401*3 + 1] = 0.022372f;	val_dir[6401*3 + 2] = 0.648784f;
+ 	val_dir[6402*3 + 0] = -0.750388f;	val_dir[6402*3 + 1] = 0.045478f;	val_dir[6402*3 + 2] = 0.659432f;
+ 	val_dir[6403*3 + 0] = -0.739205f;	val_dir[6403*3 + 1] = 0.069301f;	val_dir[6403*3 + 2] = 0.669905f;
+ 	val_dir[6404*3 + 0] = -0.727051f;	val_dir[6404*3 + 1] = 0.093813f;	val_dir[6404*3 + 2] = 0.680144f;
+ 	val_dir[6405*3 + 0] = -0.713881f;	val_dir[6405*3 + 1] = 0.118980f;	val_dir[6405*3 + 2] = 0.690085f;
+ 	val_dir[6406*3 + 0] = -0.699659f;	val_dir[6406*3 + 1] = 0.144757f;	val_dir[6406*3 + 2] = 0.699659f;
+ 	val_dir[6407*3 + 0] = -0.684353f;	val_dir[6407*3 + 1] = 0.171088f;	val_dir[6407*3 + 2] = 0.708794f;
+ 	val_dir[6408*3 + 0] = -0.667940f;	val_dir[6408*3 + 1] = 0.197908f;	val_dir[6408*3 + 2] = 0.717418f;
+ 	val_dir[6409*3 + 0] = -0.650407f;	val_dir[6409*3 + 1] = 0.225141f;	val_dir[6409*3 + 2] = 0.725454f;
+ 	val_dir[6410*3 + 0] = -0.631748f;	val_dir[6410*3 + 1] = 0.252699f;	val_dir[6410*3 + 2] = 0.732828f;
+ 	val_dir[6411*3 + 0] = -0.611974f;	val_dir[6411*3 + 1] = 0.280488f;	val_dir[6411*3 + 2] = 0.739469f;
+ 	val_dir[6412*3 + 0] = -0.591105f;	val_dir[6412*3 + 1] = 0.308403f;	val_dir[6412*3 + 2] = 0.745307f;
+ 	val_dir[6413*3 + 0] = -0.569177f;	val_dir[6413*3 + 1] = 0.336332f;	val_dir[6413*3 + 2] = 0.750279f;
+ 	val_dir[6414*3 + 0] = -0.546238f;	val_dir[6414*3 + 1] = 0.364159f;	val_dir[6414*3 + 2] = 0.754329f;
+ 	val_dir[6415*3 + 0] = -0.522352f;	val_dir[6415*3 + 1] = 0.391764f;	val_dir[6415*3 + 2] = 0.757410f;
+ 	val_dir[6416*3 + 0] = -0.497594f;	val_dir[6416*3 + 1] = 0.419026f;	val_dir[6416*3 + 2] = 0.759485f;
+ 	val_dir[6417*3 + 0] = -0.472053f;	val_dir[6417*3 + 1] = 0.445827f;	val_dir[6417*3 + 2] = 0.760529f;
+ 	val_dir[6418*3 + 0] = -0.445827f;	val_dir[6418*3 + 1] = 0.472053f;	val_dir[6418*3 + 2] = 0.760529f;
+ 	val_dir[6419*3 + 0] = -0.419026f;	val_dir[6419*3 + 1] = 0.497594f;	val_dir[6419*3 + 2] = 0.759485f;
+ 	val_dir[6420*3 + 0] = -0.391764f;	val_dir[6420*3 + 1] = 0.522352f;	val_dir[6420*3 + 2] = 0.757410f;
+ 	val_dir[6421*3 + 0] = -0.364159f;	val_dir[6421*3 + 1] = 0.546238f;	val_dir[6421*3 + 2] = 0.754329f;
+ 	val_dir[6422*3 + 0] = -0.336332f;	val_dir[6422*3 + 1] = 0.569177f;	val_dir[6422*3 + 2] = 0.750279f;
+ 	val_dir[6423*3 + 0] = -0.308403f;	val_dir[6423*3 + 1] = 0.591105f;	val_dir[6423*3 + 2] = 0.745307f;
+ 	val_dir[6424*3 + 0] = -0.280488f;	val_dir[6424*3 + 1] = 0.611974f;	val_dir[6424*3 + 2] = 0.739469f;
+ 	val_dir[6425*3 + 0] = -0.252699f;	val_dir[6425*3 + 1] = 0.631748f;	val_dir[6425*3 + 2] = 0.732828f;
+ 	val_dir[6426*3 + 0] = -0.225141f;	val_dir[6426*3 + 1] = 0.650407f;	val_dir[6426*3 + 2] = 0.725454f;
+ 	val_dir[6427*3 + 0] = -0.197908f;	val_dir[6427*3 + 1] = 0.667940f;	val_dir[6427*3 + 2] = 0.717418f;
+ 	val_dir[6428*3 + 0] = -0.171088f;	val_dir[6428*3 + 1] = 0.684353f;	val_dir[6428*3 + 2] = 0.708794f;
+ 	val_dir[6429*3 + 0] = -0.144757f;	val_dir[6429*3 + 1] = 0.699659f;	val_dir[6429*3 + 2] = 0.699659f;
+ 	val_dir[6430*3 + 0] = -0.118980f;	val_dir[6430*3 + 1] = 0.713881f;	val_dir[6430*3 + 2] = 0.690085f;
+ 	val_dir[6431*3 + 0] = -0.093813f;	val_dir[6431*3 + 1] = 0.727051f;	val_dir[6431*3 + 2] = 0.680144f;
+ 	val_dir[6432*3 + 0] = -0.069301f;	val_dir[6432*3 + 1] = 0.739205f;	val_dir[6432*3 + 2] = 0.669905f;
+ 	val_dir[6433*3 + 0] = -0.045478f;	val_dir[6433*3 + 1] = 0.750388f;	val_dir[6433*3 + 2] = 0.659432f;
+ 	val_dir[6434*3 + 0] = -0.022372f;	val_dir[6434*3 + 1] = 0.760644f;	val_dir[6434*3 + 2] = 0.648784f;
+ 	val_dir[6435*3 + 0] = 0.0f;	val_dir[6435*3 + 1] = 0.770022f;	val_dir[6435*3 + 2] = 0.638018f;
+ 	val_dir[6436*3 + 0] = 0.022217f;	val_dir[6436*3 + 1] = 0.799803f;	val_dir[6436*3 + 2] = 0.599852f;
+ 	val_dir[6437*3 + 0] = 0.044744f;	val_dir[6437*3 + 1] = 0.827759f;	val_dir[6437*3 + 2] = 0.559297f;
+ 	val_dir[6438*3 + 0] = 0.067386f;	val_dir[6438*3 + 1] = 0.853556f;	val_dir[6438*3 + 2] = 0.516626f;
+ 	val_dir[6439*3 + 0] = 0.089939f;	val_dir[6439*3 + 1] = 0.876903f;	val_dir[6439*3 + 2] = 0.472178f;
+ 	val_dir[6440*3 + 0] = 0.112197f;	val_dir[6440*3 + 1] = 0.897574f;	val_dir[6440*3 + 2] = 0.426348f;
+ 	val_dir[6441*3 + 0] = 0.133963f;	val_dir[6441*3 + 1] = 0.915416f;	val_dir[6441*3 + 2] = 0.379563f;
+ 	val_dir[6442*3 + 0] = 0.155059f;	val_dir[6442*3 + 1] = 0.930352f;	val_dir[6442*3 + 2] = 0.332269f;
+ 	val_dir[6443*3 + 0] = 0.175327f;	val_dir[6443*3 + 1] = 0.942384f;	val_dir[6443*3 + 2] = 0.284907f;
+ 	val_dir[6444*3 + 0] = 0.194643f;	val_dir[6444*3 + 1] = 0.951588f;	val_dir[6444*3 + 2] = 0.237897f;
+ 	val_dir[6445*3 + 0] = 0.212911f;	val_dir[6445*3 + 1] = 0.958098f;	val_dir[6445*3 + 2] = 0.191620f;
+ 	val_dir[6446*3 + 0] = 0.230067f;	val_dir[6446*3 + 1] = 0.962099f;	val_dir[6446*3 + 2] = 0.146406f;
+ 	val_dir[6447*3 + 0] = 0.246079f;	val_dir[6447*3 + 1] = 0.963811f;	val_dir[6447*3 + 2] = 0.102533f;
+ 	val_dir[6448*3 + 0] = 0.260941f;	val_dir[6448*3 + 1] = 0.963475f;	val_dir[6448*3 + 2] = 0.060217f;
+ 	val_dir[6449*3 + 0] = 0.274668f;	val_dir[6449*3 + 1] = 0.961339f;	val_dir[6449*3 + 2] = 0.019619f;
+ 	val_dir[6450*3 + 0] = -0.962964f;	val_dir[6450*3 + 1] = -0.269630f;	val_dir[6450*3 + 2] = 0.0f;
+ 	val_dir[6451*3 + 0] = -0.965810f;	val_dir[6451*3 + 1] = -0.256235f;	val_dir[6451*3 + 2] = 0.039421f;
+ 	val_dir[6452*3 + 0] = -0.966988f;	val_dir[6452*3 + 1] = -0.241747f;	val_dir[6452*3 + 2] = 0.080582f;
+ 	val_dir[6453*3 + 0] = -0.966252f;	val_dir[6453*3 + 1] = -0.226144f;	val_dir[6453*3 + 2] = 0.123351f;
+ 	val_dir[6454*3 + 0] = -0.963364f;	val_dir[6454*3 + 1] = -0.209427f;	val_dir[6454*3 + 2] = 0.167542f;
+ 	val_dir[6455*3 + 0] = -0.958098f;	val_dir[6455*3 + 1] = -0.191620f;	val_dir[6455*3 + 2] = 0.212911f;
+ 	val_dir[6456*3 + 0] = -0.950255f;	val_dir[6456*3 + 1] = -0.172774f;	val_dir[6456*3 + 2] = 0.259161f;
+ 	val_dir[6457*3 + 0] = -0.939680f;	val_dir[6457*3 + 1] = -0.152971f;	val_dir[6457*3 + 2] = 0.305942f;
+ 	val_dir[6458*3 + 0] = -0.926270f;	val_dir[6458*3 + 1] = -0.132324f;	val_dir[6458*3 + 2] = 0.352865f;
+ 	val_dir[6459*3 + 0] = -0.909988f;	val_dir[6459*3 + 1] = -0.110974f;	val_dir[6459*3 + 2] = 0.399507f;
+ 	val_dir[6460*3 + 0] = -0.890871f;	val_dir[6460*3 + 1] = -0.089087f;	val_dir[6460*3 + 2] = 0.445435f;
+ 	val_dir[6461*3 + 0] = -0.869030f;	val_dir[6461*3 + 1] = -0.066848f;	val_dir[6461*3 + 2] = 0.490222f;
+ 	val_dir[6462*3 + 0] = -0.844653f;	val_dir[6462*3 + 1] = -0.044455f;	val_dir[6462*3 + 2] = 0.533465f;
+ 	val_dir[6463*3 + 0] = -0.817992f;	val_dir[6463*3 + 1] = -0.022108f;	val_dir[6463*3 + 2] = 0.574805f;
+ 	val_dir[6464*3 + 0] = -0.789352f;	val_dir[6464*3 + 1] = 0.0f;	val_dir[6464*3 + 2] = 0.613941f;
+ 	val_dir[6465*3 + 0] = -0.780675f;	val_dir[6465*3 + 1] = 0.022305f;	val_dir[6465*3 + 2] = 0.624540f;
+ 	val_dir[6466*3 + 0] = -0.771136f;	val_dir[6466*3 + 1] = 0.045361f;	val_dir[6466*3 + 2] = 0.635053f;
+ 	val_dir[6467*3 + 0] = -0.760684f;	val_dir[6467*3 + 1] = 0.069153f;	val_dir[6467*3 + 2] = 0.645429f;
+ 	val_dir[6468*3 + 0] = -0.749269f;	val_dir[6468*3 + 1] = 0.093659f;	val_dir[6468*3 + 2] = 0.655610f;
+ 	val_dir[6469*3 + 0] = -0.736843f;	val_dir[6469*3 + 1] = 0.118846f;	val_dir[6469*3 + 2] = 0.665536f;
+ 	val_dir[6470*3 + 0] = -0.723364f;	val_dir[6470*3 + 1] = 0.144673f;	val_dir[6470*3 + 2] = 0.675140f;
+ 	val_dir[6471*3 + 0] = -0.708794f;	val_dir[6471*3 + 1] = 0.171088f;	val_dir[6471*3 + 2] = 0.684353f;
+ 	val_dir[6472*3 + 0] = -0.693103f;	val_dir[6472*3 + 1] = 0.198030f;	val_dir[6472*3 + 2] = 0.693103f;
+ 	val_dir[6473*3 + 0] = -0.676269f;	val_dir[6473*3 + 1] = 0.225423f;	val_dir[6473*3 + 2] = 0.701316f;
+ 	val_dir[6474*3 + 0] = -0.658281f;	val_dir[6474*3 + 1] = 0.253185f;	val_dir[6474*3 + 2] = 0.708918f;
+ 	val_dir[6475*3 + 0] = -0.639138f;	val_dir[6475*3 + 1] = 0.281220f;	val_dir[6475*3 + 2] = 0.715834f;
+ 	val_dir[6476*3 + 0] = -0.618853f;	val_dir[6476*3 + 1] = 0.309426f;	val_dir[6476*3 + 2] = 0.721995f;
+ 	val_dir[6477*3 + 0] = -0.597453f;	val_dir[6477*3 + 1] = 0.337691f;	val_dir[6477*3 + 2] = 0.727334f;
+ 	val_dir[6478*3 + 0] = -0.574979f;	val_dir[6478*3 + 1] = 0.365896f;	val_dir[6478*3 + 2] = 0.731792f;
+ 	val_dir[6479*3 + 0] = -0.551487f;	val_dir[6479*3 + 1] = 0.393919f;	val_dir[6479*3 + 2] = 0.735316f;
+ 	val_dir[6480*3 + 0] = -0.527046f;	val_dir[6480*3 + 1] = 0.421637f;	val_dir[6480*3 + 2] = 0.737865f;
+ 	val_dir[6481*3 + 0] = -0.501740f;	val_dir[6481*3 + 1] = 0.448926f;	val_dir[6481*3 + 2] = 0.739407f;
+ 	val_dir[6482*3 + 0] = -0.475665f;	val_dir[6482*3 + 1] = 0.475665f;	val_dir[6482*3 + 2] = 0.739923f;
+ 	val_dir[6483*3 + 0] = -0.448926f;	val_dir[6483*3 + 1] = 0.501740f;	val_dir[6483*3 + 2] = 0.739407f;
+ 	val_dir[6484*3 + 0] = -0.421637f;	val_dir[6484*3 + 1] = 0.527046f;	val_dir[6484*3 + 2] = 0.737865f;
+ 	val_dir[6485*3 + 0] = -0.393919f;	val_dir[6485*3 + 1] = 0.551487f;	val_dir[6485*3 + 2] = 0.735316f;
+ 	val_dir[6486*3 + 0] = -0.365896f;	val_dir[6486*3 + 1] = 0.574979f;	val_dir[6486*3 + 2] = 0.731792f;
+ 	val_dir[6487*3 + 0] = -0.337691f;	val_dir[6487*3 + 1] = 0.597453f;	val_dir[6487*3 + 2] = 0.727334f;
+ 	val_dir[6488*3 + 0] = -0.309426f;	val_dir[6488*3 + 1] = 0.618853f;	val_dir[6488*3 + 2] = 0.721995f;
+ 	val_dir[6489*3 + 0] = -0.281220f;	val_dir[6489*3 + 1] = 0.639138f;	val_dir[6489*3 + 2] = 0.715834f;
+ 	val_dir[6490*3 + 0] = -0.253185f;	val_dir[6490*3 + 1] = 0.658281f;	val_dir[6490*3 + 2] = 0.708918f;
+ 	val_dir[6491*3 + 0] = -0.225423f;	val_dir[6491*3 + 1] = 0.676269f;	val_dir[6491*3 + 2] = 0.701316f;
+ 	val_dir[6492*3 + 0] = -0.198030f;	val_dir[6492*3 + 1] = 0.693103f;	val_dir[6492*3 + 2] = 0.693103f;
+ 	val_dir[6493*3 + 0] = -0.171088f;	val_dir[6493*3 + 1] = 0.708794f;	val_dir[6493*3 + 2] = 0.684353f;
+ 	val_dir[6494*3 + 0] = -0.144673f;	val_dir[6494*3 + 1] = 0.723364f;	val_dir[6494*3 + 2] = 0.675140f;
+ 	val_dir[6495*3 + 0] = -0.118846f;	val_dir[6495*3 + 1] = 0.736843f;	val_dir[6495*3 + 2] = 0.665536f;
+ 	val_dir[6496*3 + 0] = -0.093659f;	val_dir[6496*3 + 1] = 0.749269f;	val_dir[6496*3 + 2] = 0.655610f;
+ 	val_dir[6497*3 + 0] = -0.069153f;	val_dir[6497*3 + 1] = 0.760684f;	val_dir[6497*3 + 2] = 0.645429f;
+ 	val_dir[6498*3 + 0] = -0.045361f;	val_dir[6498*3 + 1] = 0.771136f;	val_dir[6498*3 + 2] = 0.635053f;
+ 	val_dir[6499*3 + 0] = -0.022305f;	val_dir[6499*3 + 1] = 0.780675f;	val_dir[6499*3 + 2] = 0.624540f;
+ 	val_dir[6500*3 + 0] = 0.0f;	val_dir[6500*3 + 1] = 0.789352f;	val_dir[6500*3 + 2] = 0.613941f;
+ 	val_dir[6501*3 + 0] = 0.022108f;	val_dir[6501*3 + 1] = 0.817992f;	val_dir[6501*3 + 2] = 0.574805f;
+ 	val_dir[6502*3 + 0] = 0.044455f;	val_dir[6502*3 + 1] = 0.844653f;	val_dir[6502*3 + 2] = 0.533465f;
+ 	val_dir[6503*3 + 0] = 0.066848f;	val_dir[6503*3 + 1] = 0.869030f;	val_dir[6503*3 + 2] = 0.490222f;
+ 	val_dir[6504*3 + 0] = 0.089087f;	val_dir[6504*3 + 1] = 0.890871f;	val_dir[6504*3 + 2] = 0.445435f;
+ 	val_dir[6505*3 + 0] = 0.110974f;	val_dir[6505*3 + 1] = 0.909988f;	val_dir[6505*3 + 2] = 0.399507f;
+ 	val_dir[6506*3 + 0] = 0.132324f;	val_dir[6506*3 + 1] = 0.926270f;	val_dir[6506*3 + 2] = 0.352865f;
+ 	val_dir[6507*3 + 0] = 0.152971f;	val_dir[6507*3 + 1] = 0.939680f;	val_dir[6507*3 + 2] = 0.305942f;
+ 	val_dir[6508*3 + 0] = 0.172774f;	val_dir[6508*3 + 1] = 0.950255f;	val_dir[6508*3 + 2] = 0.259161f;
+ 	val_dir[6509*3 + 0] = 0.191620f;	val_dir[6509*3 + 1] = 0.958098f;	val_dir[6509*3 + 2] = 0.212911f;
+ 	val_dir[6510*3 + 0] = 0.209427f;	val_dir[6510*3 + 1] = 0.963364f;	val_dir[6510*3 + 2] = 0.167542f;
+ 	val_dir[6511*3 + 0] = 0.226144f;	val_dir[6511*3 + 1] = 0.966252f;	val_dir[6511*3 + 2] = 0.123351f;
+ 	val_dir[6512*3 + 0] = 0.241747f;	val_dir[6512*3 + 1] = 0.966988f;	val_dir[6512*3 + 2] = 0.080582f;
+ 	val_dir[6513*3 + 0] = 0.256235f;	val_dir[6513*3 + 1] = 0.965810f;	val_dir[6513*3 + 2] = 0.039421f;
+ 	val_dir[6514*3 + 0] = 0.269630f;	val_dir[6514*3 + 1] = 0.962964f;	val_dir[6514*3 + 2] = 0.0f;
+ 	val_dir[6515*3 + 0] = -0.967641f;	val_dir[6515*3 + 1] = -0.251587f;	val_dir[6515*3 + 2] = 0.019353f;
+ 	val_dir[6516*3 + 0] = -0.969584f;	val_dir[6516*3 + 1] = -0.237449f;	val_dir[6516*3 + 2] = 0.059362f;
+ 	val_dir[6517*3 + 0] = -0.969746f;	val_dir[6517*3 + 1] = -0.222234f;	val_dir[6517*3 + 2] = 0.101015f;
+ 	val_dir[6518*3 + 0] = -0.967890f;	val_dir[6518*3 + 1] = -0.205934f;	val_dir[6518*3 + 2] = 0.144154f;
+ 	val_dir[6519*3 + 0] = -0.963787f;	val_dir[6519*3 + 1] = -0.188567f;	val_dir[6519*3 + 2] = 0.188567f;
+ 	val_dir[6520*3 + 0] = -0.957230f;	val_dir[6520*3 + 1] = -0.170174f;	val_dir[6520*3 + 2] = 0.233990f;
+ 	val_dir[6521*3 + 0] = -0.948047f;	val_dir[6521*3 + 1] = -0.150826f;	val_dir[6521*3 + 2] = 0.280105f;
+ 	val_dir[6522*3 + 0] = -0.936111f;	val_dir[6522*3 + 1] = -0.130620f;	val_dir[6522*3 + 2] = 0.326550f;
+ 	val_dir[6523*3 + 0] = -0.921354f;	val_dir[6523*3 + 1] = -0.109685f;	val_dir[6523*3 + 2] = 0.372929f;
+ 	val_dir[6524*3 + 0] = -0.903777f;	val_dir[6524*3 + 1] = -0.088173f;	val_dir[6524*3 + 2] = 0.418823f;
+ 	val_dir[6525*3 + 0] = -0.883452f;	val_dir[6525*3 + 1] = -0.066259f;	val_dir[6525*3 + 2] = 0.463812f;
+ 	val_dir[6526*3 + 0] = -0.860527f;	val_dir[6526*3 + 1] = -0.044130f;	val_dir[6526*3 + 2] = 0.507490f;
+ 	val_dir[6527*3 + 0] = -0.835215f;	val_dir[6527*3 + 1] = -0.021979f;	val_dir[6527*3 + 2] = 0.549484f;
+ 	val_dir[6528*3 + 0] = -0.807791f;	val_dir[6528*3 + 1] = 0.0f;	val_dir[6528*3 + 2] = 0.589469f;
+ 	val_dir[6529*3 + 0] = -0.799803f;	val_dir[6529*3 + 1] = 0.022217f;	val_dir[6529*3 + 2] = 0.599852f;
+ 	val_dir[6530*3 + 0] = -0.790973f;	val_dir[6530*3 + 1] = 0.045198f;	val_dir[6530*3 + 2] = 0.610179f;
+ 	val_dir[6531*3 + 0] = -0.781248f;	val_dir[6531*3 + 1] = 0.068934f;	val_dir[6531*3 + 2] = 0.620403f;
+ 	val_dir[6532*3 + 0] = -0.770574f;	val_dir[6532*3 + 1] = 0.093403f;	val_dir[6532*3 + 2] = 0.630470f;
+ 	val_dir[6533*3 + 0] = -0.758899f;	val_dir[6533*3 + 1] = 0.118578f;	val_dir[6533*3 + 2] = 0.640321f;
+ 	val_dir[6534*3 + 0] = -0.746176f;	val_dir[6534*3 + 1] = 0.144421f;	val_dir[6534*3 + 2] = 0.649895f;
+ 	val_dir[6535*3 + 0] = -0.732361f;	val_dir[6535*3 + 1] = 0.170884f;	val_dir[6535*3 + 2] = 0.659125f;
+ 	val_dir[6536*3 + 0] = -0.717418f;	val_dir[6536*3 + 1] = 0.197908f;	val_dir[6536*3 + 2] = 0.667940f;
+ 	val_dir[6537*3 + 0] = -0.701316f;	val_dir[6537*3 + 1] = 0.225423f;	val_dir[6537*3 + 2] = 0.676269f;
+ 	val_dir[6538*3 + 0] = -0.684038f;	val_dir[6538*3 + 1] = 0.253347f;	val_dir[6538*3 + 2] = 0.684038f;
+ 	val_dir[6539*3 + 0] = -0.665574f;	val_dir[6539*3 + 1] = 0.281589f;	val_dir[6539*3 + 2] = 0.691173f;
+ 	val_dir[6540*3 + 0] = -0.645928f;	val_dir[6540*3 + 1] = 0.310045f;	val_dir[6540*3 + 2] = 0.697602f;
+ 	val_dir[6541*3 + 0] = -0.625119f;	val_dir[6541*3 + 1] = 0.338606f;	val_dir[6541*3 + 2] = 0.703259f;
+ 	val_dir[6542*3 + 0] = -0.603178f;	val_dir[6542*3 + 1] = 0.367152f;	val_dir[6542*3 + 2] = 0.708079f;
+ 	val_dir[6543*3 + 0] = -0.580154f;	val_dir[6543*3 + 1] = 0.395559f;	val_dir[6543*3 + 2] = 0.712007f;
+ 	val_dir[6544*3 + 0] = -0.556108f;	val_dir[6544*3 + 1] = 0.423702f;	val_dir[6544*3 + 2] = 0.714997f;
+ 	val_dir[6545*3 + 0] = -0.531119f;	val_dir[6545*3 + 1] = 0.451451f;	val_dir[6545*3 + 2] = 0.717011f;
+ 	val_dir[6546*3 + 0] = -0.505276f;	val_dir[6546*3 + 1] = 0.478683f;	val_dir[6546*3 + 2] = 0.718024f;
+ 	val_dir[6547*3 + 0] = -0.478683f;	val_dir[6547*3 + 1] = 0.505276f;	val_dir[6547*3 + 2] = 0.718024f;
+ 	val_dir[6548*3 + 0] = -0.451451f;	val_dir[6548*3 + 1] = 0.531119f;	val_dir[6548*3 + 2] = 0.717011f;
+ 	val_dir[6549*3 + 0] = -0.423702f;	val_dir[6549*3 + 1] = 0.556108f;	val_dir[6549*3 + 2] = 0.714997f;
+ 	val_dir[6550*3 + 0] = -0.395559f;	val_dir[6550*3 + 1] = 0.580154f;	val_dir[6550*3 + 2] = 0.712007f;
+ 	val_dir[6551*3 + 0] = -0.367152f;	val_dir[6551*3 + 1] = 0.603178f;	val_dir[6551*3 + 2] = 0.708079f;
+ 	val_dir[6552*3 + 0] = -0.338606f;	val_dir[6552*3 + 1] = 0.625119f;	val_dir[6552*3 + 2] = 0.703259f;
+ 	val_dir[6553*3 + 0] = -0.310045f;	val_dir[6553*3 + 1] = 0.645928f;	val_dir[6553*3 + 2] = 0.697602f;
+ 	val_dir[6554*3 + 0] = -0.281589f;	val_dir[6554*3 + 1] = 0.665574f;	val_dir[6554*3 + 2] = 0.691173f;
+ 	val_dir[6555*3 + 0] = -0.253347f;	val_dir[6555*3 + 1] = 0.684038f;	val_dir[6555*3 + 2] = 0.684038f;
+ 	val_dir[6556*3 + 0] = -0.225423f;	val_dir[6556*3 + 1] = 0.701316f;	val_dir[6556*3 + 2] = 0.676269f;
+ 	val_dir[6557*3 + 0] = -0.197908f;	val_dir[6557*3 + 1] = 0.717418f;	val_dir[6557*3 + 2] = 0.667940f;
+ 	val_dir[6558*3 + 0] = -0.170884f;	val_dir[6558*3 + 1] = 0.732361f;	val_dir[6558*3 + 2] = 0.659125f;
+ 	val_dir[6559*3 + 0] = -0.144421f;	val_dir[6559*3 + 1] = 0.746176f;	val_dir[6559*3 + 2] = 0.649895f;
+ 	val_dir[6560*3 + 0] = -0.118578f;	val_dir[6560*3 + 1] = 0.758899f;	val_dir[6560*3 + 2] = 0.640321f;
+ 	val_dir[6561*3 + 0] = -0.093403f;	val_dir[6561*3 + 1] = 0.770574f;	val_dir[6561*3 + 2] = 0.630470f;
+ 	val_dir[6562*3 + 0] = -0.068934f;	val_dir[6562*3 + 1] = 0.781248f;	val_dir[6562*3 + 2] = 0.620403f;
+ 	val_dir[6563*3 + 0] = -0.045198f;	val_dir[6563*3 + 1] = 0.790973f;	val_dir[6563*3 + 2] = 0.610179f;
+ 	val_dir[6564*3 + 0] = -0.022217f;	val_dir[6564*3 + 1] = 0.799803f;	val_dir[6564*3 + 2] = 0.599852f;
+ 	val_dir[6565*3 + 0] = 0.0f;	val_dir[6565*3 + 1] = 0.807791f;	val_dir[6565*3 + 2] = 0.589469f;
+ 	val_dir[6566*3 + 0] = 0.021979f;	val_dir[6566*3 + 1] = 0.835215f;	val_dir[6566*3 + 2] = 0.549484f;
+ 	val_dir[6567*3 + 0] = 0.044130f;	val_dir[6567*3 + 1] = 0.860527f;	val_dir[6567*3 + 2] = 0.507490f;
+ 	val_dir[6568*3 + 0] = 0.066259f;	val_dir[6568*3 + 1] = 0.883452f;	val_dir[6568*3 + 2] = 0.463812f;
+ 	val_dir[6569*3 + 0] = 0.088173f;	val_dir[6569*3 + 1] = 0.903777f;	val_dir[6569*3 + 2] = 0.418823f;
+ 	val_dir[6570*3 + 0] = 0.109685f;	val_dir[6570*3 + 1] = 0.921354f;	val_dir[6570*3 + 2] = 0.372929f;
+ 	val_dir[6571*3 + 0] = 0.130620f;	val_dir[6571*3 + 1] = 0.936111f;	val_dir[6571*3 + 2] = 0.326550f;
+ 	val_dir[6572*3 + 0] = 0.150826f;	val_dir[6572*3 + 1] = 0.948047f;	val_dir[6572*3 + 2] = 0.280105f;
+ 	val_dir[6573*3 + 0] = 0.170174f;	val_dir[6573*3 + 1] = 0.957230f;	val_dir[6573*3 + 2] = 0.233990f;
+ 	val_dir[6574*3 + 0] = 0.188567f;	val_dir[6574*3 + 1] = 0.963787f;	val_dir[6574*3 + 2] = 0.188567f;
+ 	val_dir[6575*3 + 0] = 0.205934f;	val_dir[6575*3 + 1] = 0.967890f;	val_dir[6575*3 + 2] = 0.144154f;
+ 	val_dir[6576*3 + 0] = 0.222234f;	val_dir[6576*3 + 1] = 0.969746f;	val_dir[6576*3 + 2] = 0.101015f;
+ 	val_dir[6577*3 + 0] = 0.237449f;	val_dir[6577*3 + 1] = 0.969584f;	val_dir[6577*3 + 2] = 0.059362f;
+ 	val_dir[6578*3 + 0] = 0.251587f;	val_dir[6578*3 + 1] = 0.967641f;	val_dir[6578*3 + 2] = 0.019353f;
+ 	val_dir[6579*3 + 0] = -0.969015f;	val_dir[6579*3 + 1] = -0.247004f;	val_dir[6579*3 + 2] = 0.0f;
+ 	val_dir[6580*3 + 0] = -0.971653f;	val_dir[6580*3 + 1] = -0.233197f;	val_dir[6580*3 + 2] = 0.038866f;
+ 	val_dir[6581*3 + 0] = -0.972636f;	val_dir[6581*3 + 1] = -0.218347f;	val_dir[6581*3 + 2] = 0.079399f;
+ 	val_dir[6582*3 + 0] = -0.971732f;	val_dir[6582*3 + 1] = -0.202444f;	val_dir[6582*3 + 2] = 0.121466f;
+ 	val_dir[6583*3 + 0] = -0.968712f;	val_dir[6583*3 + 1] = -0.185498f;	val_dir[6583*3 + 2] = 0.164887f;
+ 	val_dir[6584*3 + 0] = -0.963364f;	val_dir[6584*3 + 1] = -0.167542f;	val_dir[6584*3 + 2] = 0.209427f;
+ 	val_dir[6585*3 + 0] = -0.955502f;	val_dir[6585*3 + 1] = -0.148634f;	val_dir[6585*3 + 2] = 0.254801f;
+ 	val_dir[6586*3 + 0] = -0.944981f;	val_dir[6586*3 + 1] = -0.128861f;	val_dir[6586*3 + 2] = 0.300676f;
+ 	val_dir[6587*3 + 0] = -0.931705f;	val_dir[6587*3 + 1] = -0.108338f;	val_dir[6587*3 + 2] = 0.346681f;
+ 	val_dir[6588*3 + 0] = -0.915644f;	val_dir[6588*3 + 1] = -0.087204f;	val_dir[6588*3 + 2] = 0.392419f;
+ 	val_dir[6589*3 + 0] = -0.896831f;	val_dir[6589*3 + 1] = -0.065622f;	val_dir[6589*3 + 2] = 0.437479f;
+ 	val_dir[6590*3 + 0] = -0.875376f;	val_dir[6590*3 + 1] = -0.043769f;	val_dir[6590*3 + 2] = 0.481457f;
+ 	val_dir[6591*3 + 0] = -0.851455f;	val_dir[6591*3 + 1] = -0.021832f;	val_dir[6591*3 + 2] = 0.523973f;
+ 	val_dir[6592*3 + 0] = -0.825307f;	val_dir[6592*3 + 1] = 0.0f;	val_dir[6592*3 + 2] = 0.564684f;
+ 	val_dir[6593*3 + 0] = -0.817992f;	val_dir[6593*3 + 1] = 0.022108f;	val_dir[6593*3 + 2] = 0.574805f;
+ 	val_dir[6594*3 + 0] = -0.809858f;	val_dir[6594*3 + 1] = 0.044992f;	val_dir[6594*3 + 2] = 0.584898f;
+ 	val_dir[6595*3 + 0] = -0.800850f;	val_dir[6595*3 + 1] = 0.068644f;	val_dir[6595*3 + 2] = 0.594917f;
+ 	val_dir[6596*3 + 0] = -0.790912f;	val_dir[6596*3 + 1] = 0.093048f;	val_dir[6596*3 + 2] = 0.604815f;
+ 	val_dir[6597*3 + 0] = -0.779987f;	val_dir[6597*3 + 1] = 0.118180f;	val_dir[6597*3 + 2] = 0.614535f;
+ 	val_dir[6598*3 + 0] = -0.768025f;	val_dir[6598*3 + 1] = 0.144005f;	val_dir[6598*3 + 2] = 0.624020f;
+ 	val_dir[6599*3 + 0] = -0.754976f;	val_dir[6599*3 + 1] = 0.170478f;	val_dir[6599*3 + 2] = 0.633205f;
+ 	val_dir[6600*3 + 0] = -0.740797f;	val_dir[6600*3 + 1] = 0.197546f;	val_dir[6600*3 + 2] = 0.642024f;
+ 	val_dir[6601*3 + 0] = -0.725454f;	val_dir[6601*3 + 1] = 0.225141f;	val_dir[6601*3 + 2] = 0.650407f;
+ 	val_dir[6602*3 + 0] = -0.708918f;	val_dir[6602*3 + 1] = 0.253185f;	val_dir[6602*3 + 2] = 0.658281f;
+ 	val_dir[6603*3 + 0] = -0.691173f;	val_dir[6603*3 + 1] = 0.281589f;	val_dir[6603*3 + 2] = 0.665574f;
+ 	val_dir[6604*3 + 0] = -0.672214f;	val_dir[6604*3 + 1] = 0.310253f;	val_dir[6604*3 + 2] = 0.672214f;
+ 	val_dir[6605*3 + 0] = -0.652051f;	val_dir[6605*3 + 1] = 0.339066f;	val_dir[6605*3 + 2] = 0.678133f;
+ 	val_dir[6606*3 + 0] = -0.630706f;	val_dir[6606*3 + 1] = 0.367912f;	val_dir[6606*3 + 2] = 0.683265f;
+ 	val_dir[6607*3 + 0] = -0.608219f;	val_dir[6607*3 + 1] = 0.396664f;	val_dir[6607*3 + 2] = 0.687552f;
+ 	val_dir[6608*3 + 0] = -0.584643f;	val_dir[6608*3 + 1] = 0.425195f;	val_dir[6608*3 + 2] = 0.690942f;
+ 	val_dir[6609*3 + 0] = -0.560050f;	val_dir[6609*3 + 1] = 0.453374f;	val_dir[6609*3 + 2] = 0.693395f;
+ 	val_dir[6610*3 + 0] = -0.534522f;	val_dir[6610*3 + 1] = 0.481070f;	val_dir[6610*3 + 2] = 0.694879f;
+ 	val_dir[6611*3 + 0] = -0.508159f;	val_dir[6611*3 + 1] = 0.508159f;	val_dir[6611*3 + 2] = 0.695376f;
+ 	val_dir[6612*3 + 0] = -0.481070f;	val_dir[6612*3 + 1] = 0.534522f;	val_dir[6612*3 + 2] = 0.694879f;
+ 	val_dir[6613*3 + 0] = -0.453374f;	val_dir[6613*3 + 1] = 0.560050f;	val_dir[6613*3 + 2] = 0.693395f;
+ 	val_dir[6614*3 + 0] = -0.425195f;	val_dir[6614*3 + 1] = 0.584643f;	val_dir[6614*3 + 2] = 0.690942f;
+ 	val_dir[6615*3 + 0] = -0.396664f;	val_dir[6615*3 + 1] = 0.608219f;	val_dir[6615*3 + 2] = 0.687552f;
+ 	val_dir[6616*3 + 0] = -0.367912f;	val_dir[6616*3 + 1] = 0.630706f;	val_dir[6616*3 + 2] = 0.683265f;
+ 	val_dir[6617*3 + 0] = -0.339066f;	val_dir[6617*3 + 1] = 0.652051f;	val_dir[6617*3 + 2] = 0.678133f;
+ 	val_dir[6618*3 + 0] = -0.310253f;	val_dir[6618*3 + 1] = 0.672214f;	val_dir[6618*3 + 2] = 0.672214f;
+ 	val_dir[6619*3 + 0] = -0.281589f;	val_dir[6619*3 + 1] = 0.691173f;	val_dir[6619*3 + 2] = 0.665574f;
+ 	val_dir[6620*3 + 0] = -0.253185f;	val_dir[6620*3 + 1] = 0.708918f;	val_dir[6620*3 + 2] = 0.658281f;
+ 	val_dir[6621*3 + 0] = -0.225141f;	val_dir[6621*3 + 1] = 0.725454f;	val_dir[6621*3 + 2] = 0.650407f;
+ 	val_dir[6622*3 + 0] = -0.197546f;	val_dir[6622*3 + 1] = 0.740797f;	val_dir[6622*3 + 2] = 0.642024f;
+ 	val_dir[6623*3 + 0] = -0.170478f;	val_dir[6623*3 + 1] = 0.754976f;	val_dir[6623*3 + 2] = 0.633205f;
+ 	val_dir[6624*3 + 0] = -0.144005f;	val_dir[6624*3 + 1] = 0.768025f;	val_dir[6624*3 + 2] = 0.624020f;
+ 	val_dir[6625*3 + 0] = -0.118180f;	val_dir[6625*3 + 1] = 0.779987f;	val_dir[6625*3 + 2] = 0.614535f;
+ 	val_dir[6626*3 + 0] = -0.093048f;	val_dir[6626*3 + 1] = 0.790912f;	val_dir[6626*3 + 2] = 0.604815f;
+ 	val_dir[6627*3 + 0] = -0.068644f;	val_dir[6627*3 + 1] = 0.800850f;	val_dir[6627*3 + 2] = 0.594917f;
+ 	val_dir[6628*3 + 0] = -0.044992f;	val_dir[6628*3 + 1] = 0.809858f;	val_dir[6628*3 + 2] = 0.584898f;
+ 	val_dir[6629*3 + 0] = -0.022108f;	val_dir[6629*3 + 1] = 0.817992f;	val_dir[6629*3 + 2] = 0.574805f;
+ 	val_dir[6630*3 + 0] = 0.0f;	val_dir[6630*3 + 1] = 0.825307f;	val_dir[6630*3 + 2] = 0.564684f;
+ 	val_dir[6631*3 + 0] = 0.021832f;	val_dir[6631*3 + 1] = 0.851455f;	val_dir[6631*3 + 2] = 0.523973f;
+ 	val_dir[6632*3 + 0] = 0.043769f;	val_dir[6632*3 + 1] = 0.875376f;	val_dir[6632*3 + 2] = 0.481457f;
+ 	val_dir[6633*3 + 0] = 0.065622f;	val_dir[6633*3 + 1] = 0.896831f;	val_dir[6633*3 + 2] = 0.437479f;
+ 	val_dir[6634*3 + 0] = 0.087204f;	val_dir[6634*3 + 1] = 0.915644f;	val_dir[6634*3 + 2] = 0.392419f;
+ 	val_dir[6635*3 + 0] = 0.108338f;	val_dir[6635*3 + 1] = 0.931705f;	val_dir[6635*3 + 2] = 0.346681f;
+ 	val_dir[6636*3 + 0] = 0.128861f;	val_dir[6636*3 + 1] = 0.944981f;	val_dir[6636*3 + 2] = 0.300676f;
+ 	val_dir[6637*3 + 0] = 0.148634f;	val_dir[6637*3 + 1] = 0.955502f;	val_dir[6637*3 + 2] = 0.254801f;
+ 	val_dir[6638*3 + 0] = 0.167542f;	val_dir[6638*3 + 1] = 0.963364f;	val_dir[6638*3 + 2] = 0.209427f;
+ 	val_dir[6639*3 + 0] = 0.185498f;	val_dir[6639*3 + 1] = 0.968712f;	val_dir[6639*3 + 2] = 0.164887f;
+ 	val_dir[6640*3 + 0] = 0.202444f;	val_dir[6640*3 + 1] = 0.971732f;	val_dir[6640*3 + 2] = 0.121466f;
+ 	val_dir[6641*3 + 0] = 0.218347f;	val_dir[6641*3 + 1] = 0.972636f;	val_dir[6641*3 + 2] = 0.079399f;
+ 	val_dir[6642*3 + 0] = 0.233197f;	val_dir[6642*3 + 1] = 0.971653f;	val_dir[6642*3 + 2] = 0.038866f;
+ 	val_dir[6643*3 + 0] = 0.247004f;	val_dir[6643*3 + 1] = 0.969015f;	val_dir[6643*3 + 2] = 0.0f;
+ 	val_dir[6644*3 + 0] = -0.973240f;	val_dir[6644*3 + 1] = -0.228998f;	val_dir[6644*3 + 2] = 0.019083f;
+ 	val_dir[6645*3 + 0] = -0.974972f;	val_dir[6645*3 + 1] = -0.214494f;	val_dir[6645*3 + 2] = 0.058498f;
+ 	val_dir[6646*3 + 0] = -0.974943f;	val_dir[6646*3 + 1] = -0.198968f;	val_dir[6646*3 + 2] = 0.099484f;
+ 	val_dir[6647*3 + 0] = -0.972929f;	val_dir[6647*3 + 1] = -0.182424f;	val_dir[6647*3 + 2] = 0.141885f;
+ 	val_dir[6648*3 + 0] = -0.968712f;	val_dir[6648*3 + 1] = -0.164887f;	val_dir[6648*3 + 2] = 0.185498f;
+ 	val_dir[6649*3 + 0] = -0.962099f;	val_dir[6649*3 + 1] = -0.146406f;	val_dir[6649*3 + 2] = 0.230067f;
+ 	val_dir[6650*3 + 0] = -0.952928f;	val_dir[6650*3 + 1] = -0.127057f;	val_dir[6650*3 + 2] = 0.275290f;
+ 	val_dir[6651*3 + 0] = -0.941082f;	val_dir[6651*3 + 1] = -0.106941f;	val_dir[6651*3 + 2] = 0.320824f;
+ 	val_dir[6652*3 + 0] = -0.92650f;	val_dir[6652*3 + 1] = -0.086186f;	val_dir[6652*3 + 2] = 0.366291f;
+ 	val_dir[6653*3 + 0] = -0.909185f;	val_dir[6653*3 + 1] = -0.064942f;	val_dir[6653*3 + 2] = 0.411298f;
+ 	val_dir[6654*3 + 0] = -0.889206f;	val_dir[6654*3 + 1] = -0.043376f;	val_dir[6654*3 + 2] = 0.455447f;
+ 	val_dir[6655*3 + 0] = -0.866703f;	val_dir[6655*3 + 1] = -0.021668f;	val_dir[6655*3 + 2] = 0.498354f;
+ 	val_dir[6656*3 + 0] = -0.841879f;	val_dir[6656*3 + 1] = 0.0f;	val_dir[6656*3 + 2] = 0.539666f;
+ 	val_dir[6657*3 + 0] = -0.835215f;	val_dir[6657*3 + 1] = 0.021979f;	val_dir[6657*3 + 2] = 0.549484f;
+ 	val_dir[6658*3 + 0] = -0.827759f;	val_dir[6658*3 + 1] = 0.044744f;	val_dir[6658*3 + 2] = 0.559297f;
+ 	val_dir[6659*3 + 0] = -0.819453f;	val_dir[6659*3 + 1] = 0.068288f;	val_dir[6659*3 + 2] = 0.569064f;
+ 	val_dir[6660*3 + 0] = -0.810237f;	val_dir[6660*3 + 1] = 0.092599f;	val_dir[6660*3 + 2] = 0.578741f;
+ 	val_dir[6661*3 + 0] = -0.800055f;	val_dir[6661*3 + 1] = 0.117655f;	val_dir[6661*3 + 2] = 0.588276f;
+ 	val_dir[6662*3 + 0] = -0.788851f;	val_dir[6662*3 + 1] = 0.143427f;	val_dir[6662*3 + 2] = 0.597614f;
+ 	val_dir[6663*3 + 0] = -0.776571f;	val_dir[6663*3 + 1] = 0.169875f;	val_dir[6663*3 + 2] = 0.606696f;
+ 	val_dir[6664*3 + 0] = -0.763167f;	val_dir[6664*3 + 1] = 0.196946f;	val_dir[6664*3 + 2] = 0.615457f;
+ 	val_dir[6665*3 + 0] = -0.748598f;	val_dir[6665*3 + 1] = 0.224579f;	val_dir[6665*3 + 2] = 0.623831f;
+ 	val_dir[6666*3 + 0] = -0.732828f;	val_dir[6666*3 + 1] = 0.252699f;	val_dir[6666*3 + 2] = 0.631748f;
+ 	val_dir[6667*3 + 0] = -0.715834f;	val_dir[6667*3 + 1] = 0.281220f;	val_dir[6667*3 + 2] = 0.639138f;
+ 	val_dir[6668*3 + 0] = -0.697602f;	val_dir[6668*3 + 1] = 0.310045f;	val_dir[6668*3 + 2] = 0.645928f;
+ 	val_dir[6669*3 + 0] = -0.678133f;	val_dir[6669*3 + 1] = 0.339066f;	val_dir[6669*3 + 2] = 0.652051f;
+ 	val_dir[6670*3 + 0] = -0.657440f;	val_dir[6670*3 + 1] = 0.368166f;	val_dir[6670*3 + 2] = 0.657440f;
+ 	val_dir[6671*3 + 0] = -0.635553f;	val_dir[6671*3 + 1] = 0.397220f;	val_dir[6671*3 + 2] = 0.662034f;
+ 	val_dir[6672*3 + 0] = -0.612517f;	val_dir[6672*3 + 1] = 0.426099f;	val_dir[6672*3 + 2] = 0.665780f;
+ 	val_dir[6673*3 + 0] = -0.588395f;	val_dir[6673*3 + 1] = 0.454669f;	val_dir[6673*3 + 2] = 0.668631f;
+ 	val_dir[6674*3 + 0] = -0.563264f;	val_dir[6674*3 + 1] = 0.482798f;	val_dir[6674*3 + 2] = 0.670552f;
+ 	val_dir[6675*3 + 0] = -0.537215f;	val_dir[6675*3 + 1] = 0.510355f;	val_dir[6675*3 + 2] = 0.671519f;
+ 	val_dir[6676*3 + 0] = -0.510355f;	val_dir[6676*3 + 1] = 0.537215f;	val_dir[6676*3 + 2] = 0.671519f;
+ 	val_dir[6677*3 + 0] = -0.482798f;	val_dir[6677*3 + 1] = 0.563264f;	val_dir[6677*3 + 2] = 0.670552f;
+ 	val_dir[6678*3 + 0] = -0.454669f;	val_dir[6678*3 + 1] = 0.588395f;	val_dir[6678*3 + 2] = 0.668631f;
+ 	val_dir[6679*3 + 0] = -0.426099f;	val_dir[6679*3 + 1] = 0.612517f;	val_dir[6679*3 + 2] = 0.665780f;
+ 	val_dir[6680*3 + 0] = -0.397220f;	val_dir[6680*3 + 1] = 0.635553f;	val_dir[6680*3 + 2] = 0.662034f;
+ 	val_dir[6681*3 + 0] = -0.368166f;	val_dir[6681*3 + 1] = 0.657440f;	val_dir[6681*3 + 2] = 0.657440f;
+ 	val_dir[6682*3 + 0] = -0.339066f;	val_dir[6682*3 + 1] = 0.678133f;	val_dir[6682*3 + 2] = 0.652051f;
+ 	val_dir[6683*3 + 0] = -0.310045f;	val_dir[6683*3 + 1] = 0.697602f;	val_dir[6683*3 + 2] = 0.645928f;
+ 	val_dir[6684*3 + 0] = -0.281220f;	val_dir[6684*3 + 1] = 0.715834f;	val_dir[6684*3 + 2] = 0.639138f;
+ 	val_dir[6685*3 + 0] = -0.252699f;	val_dir[6685*3 + 1] = 0.732828f;	val_dir[6685*3 + 2] = 0.631748f;
+ 	val_dir[6686*3 + 0] = -0.224579f;	val_dir[6686*3 + 1] = 0.748598f;	val_dir[6686*3 + 2] = 0.623831f;
+ 	val_dir[6687*3 + 0] = -0.196946f;	val_dir[6687*3 + 1] = 0.763167f;	val_dir[6687*3 + 2] = 0.615457f;
+ 	val_dir[6688*3 + 0] = -0.169875f;	val_dir[6688*3 + 1] = 0.776571f;	val_dir[6688*3 + 2] = 0.606696f;
+ 	val_dir[6689*3 + 0] = -0.143427f;	val_dir[6689*3 + 1] = 0.788851f;	val_dir[6689*3 + 2] = 0.597614f;
+ 	val_dir[6690*3 + 0] = -0.117655f;	val_dir[6690*3 + 1] = 0.800055f;	val_dir[6690*3 + 2] = 0.588276f;
+ 	val_dir[6691*3 + 0] = -0.092599f;	val_dir[6691*3 + 1] = 0.810237f;	val_dir[6691*3 + 2] = 0.578741f;
+ 	val_dir[6692*3 + 0] = -0.068288f;	val_dir[6692*3 + 1] = 0.819453f;	val_dir[6692*3 + 2] = 0.569064f;
+ 	val_dir[6693*3 + 0] = -0.044744f;	val_dir[6693*3 + 1] = 0.827759f;	val_dir[6693*3 + 2] = 0.559297f;
+ 	val_dir[6694*3 + 0] = -0.021979f;	val_dir[6694*3 + 1] = 0.835215f;	val_dir[6694*3 + 2] = 0.549484f;
+ 	val_dir[6695*3 + 0] = 0.0f;	val_dir[6695*3 + 1] = 0.841879f;	val_dir[6695*3 + 2] = 0.539666f;
+ 	val_dir[6696*3 + 0] = 0.021668f;	val_dir[6696*3 + 1] = 0.866703f;	val_dir[6696*3 + 2] = 0.498354f;
+ 	val_dir[6697*3 + 0] = 0.043376f;	val_dir[6697*3 + 1] = 0.889206f;	val_dir[6697*3 + 2] = 0.455447f;
+ 	val_dir[6698*3 + 0] = 0.064942f;	val_dir[6698*3 + 1] = 0.909185f;	val_dir[6698*3 + 2] = 0.411298f;
+ 	val_dir[6699*3 + 0] = 0.086186f;	val_dir[6699*3 + 1] = 0.92650f;	val_dir[6699*3 + 2] = 0.366291f;
+ 	val_dir[6700*3 + 0] = 0.106941f;	val_dir[6700*3 + 1] = 0.941082f;	val_dir[6700*3 + 2] = 0.320824f;
+ 	val_dir[6701*3 + 0] = 0.127057f;	val_dir[6701*3 + 1] = 0.952928f;	val_dir[6701*3 + 2] = 0.275290f;
+ 	val_dir[6702*3 + 0] = 0.146406f;	val_dir[6702*3 + 1] = 0.962099f;	val_dir[6702*3 + 2] = 0.230067f;
+ 	val_dir[6703*3 + 0] = 0.164887f;	val_dir[6703*3 + 1] = 0.968712f;	val_dir[6703*3 + 2] = 0.185498f;
+ 	val_dir[6704*3 + 0] = 0.182424f;	val_dir[6704*3 + 1] = 0.972929f;	val_dir[6704*3 + 2] = 0.141885f;
+ 	val_dir[6705*3 + 0] = 0.198968f;	val_dir[6705*3 + 1] = 0.974943f;	val_dir[6705*3 + 2] = 0.099484f;
+ 	val_dir[6706*3 + 0] = 0.214494f;	val_dir[6706*3 + 1] = 0.974972f;	val_dir[6706*3 + 2] = 0.058498f;
+ 	val_dir[6707*3 + 0] = 0.228998f;	val_dir[6707*3 + 1] = 0.973240f;	val_dir[6707*3 + 2] = 0.019083f;
+ 	val_dir[6708*3 + 0] = -0.974391f;	val_dir[6708*3 + 1] = -0.224860f;	val_dir[6708*3 + 2] = 0.0f;
+ 	val_dir[6709*3 + 0] = -0.976804f;	val_dir[6709*3 + 1] = -0.210683f;	val_dir[6709*3 + 2] = 0.038306f;
+ 	val_dir[6710*3 + 0] = -0.977577f;	val_dir[6710*3 + 1] = -0.195515f;	val_dir[6710*3 + 2] = 0.078206f;
+ 	val_dir[6711*3 + 0] = -0.976491f;	val_dir[6711*3 + 1] = -0.179355f;	val_dir[6711*3 + 2] = 0.119570f;
+ 	val_dir[6712*3 + 0] = -0.973329f;	val_dir[6712*3 + 1] = -0.162221f;	val_dir[6712*3 + 2] = 0.162221f;
+ 	val_dir[6713*3 + 0] = -0.967890f;	val_dir[6713*3 + 1] = -0.144154f;	val_dir[6713*3 + 2] = 0.205934f;
+ 	val_dir[6714*3 + 0] = -0.960001f;	val_dir[6714*3 + 1] = -0.125218f;	val_dir[6714*3 + 2] = 0.250435f;
+ 	val_dir[6715*3 + 0] = -0.949528f;	val_dir[6715*3 + 1] = -0.105503f;	val_dir[6715*3 + 2] = 0.295409f;
+ 	val_dir[6716*3 + 0] = -0.936382f;	val_dir[6716*3 + 1] = -0.085126f;	val_dir[6716*3 + 2] = 0.340503f;
+ 	val_dir[6717*3 + 0] = -0.920537f;	val_dir[6717*3 + 1] = -0.064223f;	val_dir[6717*3 + 2] = 0.385341f;
+ 	val_dir[6718*3 + 0] = -0.902027f;	val_dir[6718*3 + 1] = -0.042954f;	val_dir[6718*3 + 2] = 0.429537f;
+ 	val_dir[6719*3 + 0] = -0.880957f;	val_dir[6719*3 + 1] = -0.021487f;	val_dir[6719*3 + 2] = 0.472709f;
+ 	val_dir[6720*3 + 0] = -0.857493f;	val_dir[6720*3 + 1] = 0.0f;	val_dir[6720*3 + 2] = 0.514496f;
+ 	val_dir[6721*3 + 0] = -0.851455f;	val_dir[6721*3 + 1] = 0.021832f;	val_dir[6721*3 + 2] = 0.523973f;
+ 	val_dir[6722*3 + 0] = -0.844653f;	val_dir[6722*3 + 1] = 0.044455f;	val_dir[6722*3 + 2] = 0.533465f;
+ 	val_dir[6723*3 + 0] = -0.837027f;	val_dir[6723*3 + 1] = 0.067867f;	val_dir[6723*3 + 2] = 0.542936f;
+ 	val_dir[6724*3 + 0] = -0.828517f;	val_dir[6724*3 + 1] = 0.092057f;	val_dir[6724*3 + 2] = 0.552345f;
+ 	val_dir[6725*3 + 0] = -0.819064f;	val_dir[6725*3 + 1] = 0.117009f;	val_dir[6725*3 + 2] = 0.561644f;
+ 	val_dir[6726*3 + 0] = -0.808608f;	val_dir[6726*3 + 1] = 0.142695f;	val_dir[6726*3 + 2] = 0.570782f;
+ 	val_dir[6727*3 + 0] = -0.797092f;	val_dir[6727*3 + 1] = 0.169080f;	val_dir[6727*3 + 2] = 0.579703f;
+ 	val_dir[6728*3 + 0] = -0.784465f;	val_dir[6728*3 + 1] = 0.196116f;	val_dir[6728*3 + 2] = 0.588348f;
+ 	val_dir[6729*3 + 0] = -0.770677f;	val_dir[6729*3 + 1] = 0.223745f;	val_dir[6729*3 + 2] = 0.596653f;
+ 	val_dir[6730*3 + 0] = -0.755689f;	val_dir[6730*3 + 1] = 0.251896f;	val_dir[6730*3 + 2] = 0.604551f;
+ 	val_dir[6731*3 + 0] = -0.739469f;	val_dir[6731*3 + 1] = 0.280488f;	val_dir[6731*3 + 2] = 0.611974f;
+ 	val_dir[6732*3 + 0] = -0.721995f;	val_dir[6732*3 + 1] = 0.309426f;	val_dir[6732*3 + 2] = 0.618853f;
+ 	val_dir[6733*3 + 0] = -0.703259f;	val_dir[6733*3 + 1] = 0.338606f;	val_dir[6733*3 + 2] = 0.625119f;
+ 	val_dir[6734*3 + 0] = -0.683265f;	val_dir[6734*3 + 1] = 0.367912f;	val_dir[6734*3 + 2] = 0.630706f;
+ 	val_dir[6735*3 + 0] = -0.662034f;	val_dir[6735*3 + 1] = 0.397220f;	val_dir[6735*3 + 2] = 0.635553f;
+ 	val_dir[6736*3 + 0] = -0.639602f;	val_dir[6736*3 + 1] = 0.426401f;	val_dir[6736*3 + 2] = 0.639602f;
+ 	val_dir[6737*3 + 0] = -0.616022f;	val_dir[6737*3 + 1] = 0.455321f;	val_dir[6737*3 + 2] = 0.642806f;
+ 	val_dir[6738*3 + 0] = -0.591364f;	val_dir[6738*3 + 1] = 0.483843f;	val_dir[6738*3 + 2] = 0.645124f;
+ 	val_dir[6739*3 + 0] = -0.565711f;	val_dir[6739*3 + 1] = 0.511834f;	val_dir[6739*3 + 2] = 0.646527f;
+ 	val_dir[6740*3 + 0] = -0.539164f;	val_dir[6740*3 + 1] = 0.539164f;	val_dir[6740*3 + 2] = 0.646997f;
+ 	val_dir[6741*3 + 0] = -0.511834f;	val_dir[6741*3 + 1] = 0.565711f;	val_dir[6741*3 + 2] = 0.646527f;
+ 	val_dir[6742*3 + 0] = -0.483843f;	val_dir[6742*3 + 1] = 0.591364f;	val_dir[6742*3 + 2] = 0.645124f;
+ 	val_dir[6743*3 + 0] = -0.455321f;	val_dir[6743*3 + 1] = 0.616022f;	val_dir[6743*3 + 2] = 0.642806f;
+ 	val_dir[6744*3 + 0] = -0.426401f;	val_dir[6744*3 + 1] = 0.639602f;	val_dir[6744*3 + 2] = 0.639602f;
+ 	val_dir[6745*3 + 0] = -0.397220f;	val_dir[6745*3 + 1] = 0.662034f;	val_dir[6745*3 + 2] = 0.635553f;
+ 	val_dir[6746*3 + 0] = -0.367912f;	val_dir[6746*3 + 1] = 0.683265f;	val_dir[6746*3 + 2] = 0.630706f;
+ 	val_dir[6747*3 + 0] = -0.338606f;	val_dir[6747*3 + 1] = 0.703259f;	val_dir[6747*3 + 2] = 0.625119f;
+ 	val_dir[6748*3 + 0] = -0.309426f;	val_dir[6748*3 + 1] = 0.721995f;	val_dir[6748*3 + 2] = 0.618853f;
+ 	val_dir[6749*3 + 0] = -0.280488f;	val_dir[6749*3 + 1] = 0.739469f;	val_dir[6749*3 + 2] = 0.611974f;
+ 	val_dir[6750*3 + 0] = -0.251896f;	val_dir[6750*3 + 1] = 0.755689f;	val_dir[6750*3 + 2] = 0.604551f;
+ 	val_dir[6751*3 + 0] = -0.223745f;	val_dir[6751*3 + 1] = 0.770677f;	val_dir[6751*3 + 2] = 0.596653f;
+ 	val_dir[6752*3 + 0] = -0.196116f;	val_dir[6752*3 + 1] = 0.784465f;	val_dir[6752*3 + 2] = 0.588348f;
+ 	val_dir[6753*3 + 0] = -0.169080f;	val_dir[6753*3 + 1] = 0.797092f;	val_dir[6753*3 + 2] = 0.579703f;
+ 	val_dir[6754*3 + 0] = -0.142695f;	val_dir[6754*3 + 1] = 0.808608f;	val_dir[6754*3 + 2] = 0.570782f;
+ 	val_dir[6755*3 + 0] = -0.117009f;	val_dir[6755*3 + 1] = 0.819064f;	val_dir[6755*3 + 2] = 0.561644f;
+ 	val_dir[6756*3 + 0] = -0.092057f;	val_dir[6756*3 + 1] = 0.828517f;	val_dir[6756*3 + 2] = 0.552345f;
+ 	val_dir[6757*3 + 0] = -0.067867f;	val_dir[6757*3 + 1] = 0.837027f;	val_dir[6757*3 + 2] = 0.542936f;
+ 	val_dir[6758*3 + 0] = -0.044455f;	val_dir[6758*3 + 1] = 0.844653f;	val_dir[6758*3 + 2] = 0.533465f;
+ 	val_dir[6759*3 + 0] = -0.021832f;	val_dir[6759*3 + 1] = 0.851455f;	val_dir[6759*3 + 2] = 0.523973f;
+ 	val_dir[6760*3 + 0] = 0.0f;	val_dir[6760*3 + 1] = 0.857493f;	val_dir[6760*3 + 2] = 0.514496f;
+ 	val_dir[6761*3 + 0] = 0.021487f;	val_dir[6761*3 + 1] = 0.880957f;	val_dir[6761*3 + 2] = 0.472709f;
+ 	val_dir[6762*3 + 0] = 0.042954f;	val_dir[6762*3 + 1] = 0.902027f;	val_dir[6762*3 + 2] = 0.429537f;
+ 	val_dir[6763*3 + 0] = 0.064223f;	val_dir[6763*3 + 1] = 0.920537f;	val_dir[6763*3 + 2] = 0.385341f;
+ 	val_dir[6764*3 + 0] = 0.085126f;	val_dir[6764*3 + 1] = 0.936382f;	val_dir[6764*3 + 2] = 0.340503f;
+ 	val_dir[6765*3 + 0] = 0.105503f;	val_dir[6765*3 + 1] = 0.949528f;	val_dir[6765*3 + 2] = 0.295409f;
+ 	val_dir[6766*3 + 0] = 0.125218f;	val_dir[6766*3 + 1] = 0.960001f;	val_dir[6766*3 + 2] = 0.250435f;
+ 	val_dir[6767*3 + 0] = 0.144154f;	val_dir[6767*3 + 1] = 0.967890f;	val_dir[6767*3 + 2] = 0.205934f;
+ 	val_dir[6768*3 + 0] = 0.162221f;	val_dir[6768*3 + 1] = 0.973329f;	val_dir[6768*3 + 2] = 0.162221f;
+ 	val_dir[6769*3 + 0] = 0.179355f;	val_dir[6769*3 + 1] = 0.976491f;	val_dir[6769*3 + 2] = 0.119570f;
+ 	val_dir[6770*3 + 0] = 0.195515f;	val_dir[6770*3 + 1] = 0.977577f;	val_dir[6770*3 + 2] = 0.078206f;
+ 	val_dir[6771*3 + 0] = 0.210683f;	val_dir[6771*3 + 1] = 0.976804f;	val_dir[6771*3 + 2] = 0.038306f;
+ 	val_dir[6772*3 + 0] = 0.224860f;	val_dir[6772*3 + 1] = 0.974391f;	val_dir[6772*3 + 2] = 0.0f;
+ 	val_dir[6773*3 + 0] = -0.978177f;	val_dir[6773*3 + 1] = -0.206922f;	val_dir[6773*3 + 2] = 0.018811f;
+ 	val_dir[6774*3 + 0] = -0.979683f;	val_dir[6774*3 + 1] = -0.192095f;	val_dir[6774*3 + 2] = 0.057628f;
+ 	val_dir[6775*3 + 0] = -0.979451f;	val_dir[6775*3 + 1] = -0.176301f;	val_dir[6775*3 + 2] = 0.097945f;
+ 	val_dir[6776*3 + 0] = -0.977267f;	val_dir[6776*3 + 1] = -0.159554f;	val_dir[6776*3 + 2] = 0.139610f;
+ 	val_dir[6777*3 + 0] = -0.972929f;	val_dir[6777*3 + 1] = -0.141885f;	val_dir[6777*3 + 2] = 0.182424f;
+ 	val_dir[6778*3 + 0] = -0.966252f;	val_dir[6778*3 + 1] = -0.123351f;	val_dir[6778*3 + 2] = 0.226144f;
+ 	val_dir[6779*3 + 0] = -0.957088f;	val_dir[6779*3 + 1] = -0.104031f;	val_dir[6779*3 + 2] = 0.270481f;
+ 	val_dir[6780*3 + 0] = -0.945328f;	val_dir[6780*3 + 1] = -0.084029f;	val_dir[6780*3 + 2] = 0.315109f;
+ 	val_dir[6781*3 + 0] = -0.930917f;	val_dir[6781*3 + 1] = -0.063472f;	val_dir[6781*3 + 2] = 0.359673f;
+ 	val_dir[6782*3 + 0] = -0.913860f;	val_dir[6782*3 + 1] = -0.042505f;	val_dir[6782*3 + 2] = 0.403799f;
+ 	val_dir[6783*3 + 0] = -0.894224f;	val_dir[6783*3 + 1] = -0.021291f;	val_dir[6783*3 + 2] = 0.447112f;
+ 	val_dir[6784*3 + 0] = -0.872143f;	val_dir[6784*3 + 1] = 0.0f;	val_dir[6784*3 + 2] = 0.489251f;
+ 	val_dir[6785*3 + 0] = -0.866703f;	val_dir[6785*3 + 1] = 0.021668f;	val_dir[6785*3 + 2] = 0.498354f;
+ 	val_dir[6786*3 + 0] = -0.860527f;	val_dir[6786*3 + 1] = 0.044130f;	val_dir[6786*3 + 2] = 0.507490f;
+ 	val_dir[6787*3 + 0] = -0.853556f;	val_dir[6787*3 + 1] = 0.067386f;	val_dir[6787*3 + 2] = 0.516626f;
+ 	val_dir[6788*3 + 0] = -0.845728f;	val_dir[6788*3 + 1] = 0.091430f;	val_dir[6788*3 + 2] = 0.525723f;
+ 	val_dir[6789*3 + 0] = -0.836983f;	val_dir[6789*3 + 1] = 0.116248f;	val_dir[6789*3 + 2] = 0.534739f;
+ 	val_dir[6790*3 + 0] = -0.827259f;	val_dir[6790*3 + 1] = 0.141816f;	val_dir[6790*3 + 2] = 0.543627f;
+ 	val_dir[6791*3 + 0] = -0.816497f;	val_dir[6791*3 + 1] = 0.168102f;	val_dir[6791*3 + 2] = 0.552336f;
+ 	val_dir[6792*3 + 0] = -0.804639f;	val_dir[6792*3 + 1] = 0.195064f;	val_dir[6792*3 + 2] = 0.560809f;
+ 	val_dir[6793*3 + 0] = -0.791633f;	val_dir[6793*3 + 1] = 0.222647f;	val_dir[6793*3 + 2] = 0.568986f;
+ 	val_dir[6794*3 + 0] = -0.777433f;	val_dir[6794*3 + 1] = 0.250785f;	val_dir[6794*3 + 2] = 0.576805f;
+ 	val_dir[6795*3 + 0] = -0.762001f;	val_dir[6795*3 + 1] = 0.27940f;	val_dir[6795*3 + 2] = 0.584201f;
+ 	val_dir[6796*3 + 0] = -0.745307f;	val_dir[6796*3 + 1] = 0.308403f;	val_dir[6796*3 + 2] = 0.591105f;
+ 	val_dir[6797*3 + 0] = -0.727334f;	val_dir[6797*3 + 1] = 0.337691f;	val_dir[6797*3 + 2] = 0.597453f;
+ 	val_dir[6798*3 + 0] = -0.708079f;	val_dir[6798*3 + 1] = 0.367152f;	val_dir[6798*3 + 2] = 0.603178f;
+ 	val_dir[6799*3 + 0] = -0.687552f;	val_dir[6799*3 + 1] = 0.396664f;	val_dir[6799*3 + 2] = 0.608219f;
+ 	val_dir[6800*3 + 0] = -0.665780f;	val_dir[6800*3 + 1] = 0.426099f;	val_dir[6800*3 + 2] = 0.612517f;
+ 	val_dir[6801*3 + 0] = -0.642806f;	val_dir[6801*3 + 1] = 0.455321f;	val_dir[6801*3 + 2] = 0.616022f;
+ 	val_dir[6802*3 + 0] = -0.618691f;	val_dir[6802*3 + 1] = 0.484193f;	val_dir[6802*3 + 2] = 0.618691f;
+ 	val_dir[6803*3 + 0] = -0.593512f;	val_dir[6803*3 + 1] = 0.512578f;	val_dir[6803*3 + 2] = 0.620490f;
+ 	val_dir[6804*3 + 0] = -0.567360f;	val_dir[6804*3 + 1] = 0.540343f;	val_dir[6804*3 + 2] = 0.621395f;
+ 	val_dir[6805*3 + 0] = -0.540343f;	val_dir[6805*3 + 1] = 0.567360f;	val_dir[6805*3 + 2] = 0.621395f;
+ 	val_dir[6806*3 + 0] = -0.512578f;	val_dir[6806*3 + 1] = 0.593512f;	val_dir[6806*3 + 2] = 0.620490f;
+ 	val_dir[6807*3 + 0] = -0.484193f;	val_dir[6807*3 + 1] = 0.618691f;	val_dir[6807*3 + 2] = 0.618691f;
+ 	val_dir[6808*3 + 0] = -0.455321f;	val_dir[6808*3 + 1] = 0.642806f;	val_dir[6808*3 + 2] = 0.616022f;
+ 	val_dir[6809*3 + 0] = -0.426099f;	val_dir[6809*3 + 1] = 0.665780f;	val_dir[6809*3 + 2] = 0.612517f;
+ 	val_dir[6810*3 + 0] = -0.396664f;	val_dir[6810*3 + 1] = 0.687552f;	val_dir[6810*3 + 2] = 0.608219f;
+ 	val_dir[6811*3 + 0] = -0.367152f;	val_dir[6811*3 + 1] = 0.708079f;	val_dir[6811*3 + 2] = 0.603178f;
+ 	val_dir[6812*3 + 0] = -0.337691f;	val_dir[6812*3 + 1] = 0.727334f;	val_dir[6812*3 + 2] = 0.597453f;
+ 	val_dir[6813*3 + 0] = -0.308403f;	val_dir[6813*3 + 1] = 0.745307f;	val_dir[6813*3 + 2] = 0.591105f;
+ 	val_dir[6814*3 + 0] = -0.27940f;	val_dir[6814*3 + 1] = 0.762001f;	val_dir[6814*3 + 2] = 0.584201f;
+ 	val_dir[6815*3 + 0] = -0.250785f;	val_dir[6815*3 + 1] = 0.777433f;	val_dir[6815*3 + 2] = 0.576805f;
+ 	val_dir[6816*3 + 0] = -0.222647f;	val_dir[6816*3 + 1] = 0.791633f;	val_dir[6816*3 + 2] = 0.568986f;
+ 	val_dir[6817*3 + 0] = -0.195064f;	val_dir[6817*3 + 1] = 0.804639f;	val_dir[6817*3 + 2] = 0.560809f;
+ 	val_dir[6818*3 + 0] = -0.168102f;	val_dir[6818*3 + 1] = 0.816497f;	val_dir[6818*3 + 2] = 0.552336f;
+ 	val_dir[6819*3 + 0] = -0.141816f;	val_dir[6819*3 + 1] = 0.827259f;	val_dir[6819*3 + 2] = 0.543627f;
+ 	val_dir[6820*3 + 0] = -0.116248f;	val_dir[6820*3 + 1] = 0.836983f;	val_dir[6820*3 + 2] = 0.534739f;
+ 	val_dir[6821*3 + 0] = -0.091430f;	val_dir[6821*3 + 1] = 0.845728f;	val_dir[6821*3 + 2] = 0.525723f;
+ 	val_dir[6822*3 + 0] = -0.067386f;	val_dir[6822*3 + 1] = 0.853556f;	val_dir[6822*3 + 2] = 0.516626f;
+ 	val_dir[6823*3 + 0] = -0.044130f;	val_dir[6823*3 + 1] = 0.860527f;	val_dir[6823*3 + 2] = 0.507490f;
+ 	val_dir[6824*3 + 0] = -0.021668f;	val_dir[6824*3 + 1] = 0.866703f;	val_dir[6824*3 + 2] = 0.498354f;
+ 	val_dir[6825*3 + 0] = 0.0f;	val_dir[6825*3 + 1] = 0.872143f;	val_dir[6825*3 + 2] = 0.489251f;
+ 	val_dir[6826*3 + 0] = 0.021291f;	val_dir[6826*3 + 1] = 0.894224f;	val_dir[6826*3 + 2] = 0.447112f;
+ 	val_dir[6827*3 + 0] = 0.042505f;	val_dir[6827*3 + 1] = 0.913860f;	val_dir[6827*3 + 2] = 0.403799f;
+ 	val_dir[6828*3 + 0] = 0.063472f;	val_dir[6828*3 + 1] = 0.930917f;	val_dir[6828*3 + 2] = 0.359673f;
+ 	val_dir[6829*3 + 0] = 0.084029f;	val_dir[6829*3 + 1] = 0.945328f;	val_dir[6829*3 + 2] = 0.315109f;
+ 	val_dir[6830*3 + 0] = 0.104031f;	val_dir[6830*3 + 1] = 0.957088f;	val_dir[6830*3 + 2] = 0.270481f;
+ 	val_dir[6831*3 + 0] = 0.123351f;	val_dir[6831*3 + 1] = 0.966252f;	val_dir[6831*3 + 2] = 0.226144f;
+ 	val_dir[6832*3 + 0] = 0.141885f;	val_dir[6832*3 + 1] = 0.972929f;	val_dir[6832*3 + 2] = 0.182424f;
+ 	val_dir[6833*3 + 0] = 0.159554f;	val_dir[6833*3 + 1] = 0.977267f;	val_dir[6833*3 + 2] = 0.139610f;
+ 	val_dir[6834*3 + 0] = 0.176301f;	val_dir[6834*3 + 1] = 0.979451f;	val_dir[6834*3 + 2] = 0.097945f;
+ 	val_dir[6835*3 + 0] = 0.192095f;	val_dir[6835*3 + 1] = 0.979683f;	val_dir[6835*3 + 2] = 0.057628f;
+ 	val_dir[6836*3 + 0] = 0.206922f;	val_dir[6836*3 + 1] = 0.978177f;	val_dir[6836*3 + 2] = 0.018811f;
+ 	val_dir[6837*3 + 0] = -0.979134f;	val_dir[6837*3 + 1] = -0.203216f;	val_dir[6837*3 + 2] = 0.0f;
+ 	val_dir[6838*3 + 0] = -0.981307f;	val_dir[6838*3 + 1] = -0.188713f;	val_dir[6838*3 + 2] = 0.037743f;
+ 	val_dir[6839*3 + 0] = -0.981859f;	val_dir[6839*3 + 1] = -0.173269f;	val_dir[6839*3 + 2] = 0.077009f;
+ 	val_dir[6840*3 + 0] = -0.980581f;	val_dir[6840*3 + 1] = -0.156893f;	val_dir[6840*3 + 2] = 0.117670f;
+ 	val_dir[6841*3 + 0] = -0.977267f;	val_dir[6841*3 + 1] = -0.139610f;	val_dir[6841*3 + 2] = 0.159554f;
+ 	val_dir[6842*3 + 0] = -0.971732f;	val_dir[6842*3 + 1] = -0.121466f;	val_dir[6842*3 + 2] = 0.202444f;
+ 	val_dir[6843*3 + 0] = -0.963811f;	val_dir[6843*3 + 1] = -0.102533f;	val_dir[6843*3 + 2] = 0.246079f;
+ 	val_dir[6844*3 + 0] = -0.953381f;	val_dir[6844*3 + 1] = -0.082903f;	val_dir[6844*3 + 2] = 0.290159f;
+ 	val_dir[6845*3 + 0] = -0.940361f;	val_dir[6845*3 + 1] = -0.062691f;	val_dir[6845*3 + 2] = 0.334351f;
+ 	val_dir[6846*3 + 0] = -0.924729f;	val_dir[6846*3 + 1] = -0.042033f;	val_dir[6846*3 + 2] = 0.378298f;
+ 	val_dir[6847*3 + 0] = -0.906520f;	val_dir[6847*3 + 1] = -0.021082f;	val_dir[6847*3 + 2] = 0.421637f;
+ 	val_dir[6848*3 + 0] = -0.885832f;	val_dir[6848*3 + 1] = 0.0f;	val_dir[6848*3 + 2] = 0.464007f;
+ 	val_dir[6849*3 + 0] = -0.880957f;	val_dir[6849*3 + 1] = 0.021487f;	val_dir[6849*3 + 2] = 0.472709f;
+ 	val_dir[6850*3 + 0] = -0.875376f;	val_dir[6850*3 + 1] = 0.043769f;	val_dir[6850*3 + 2] = 0.481457f;
+ 	val_dir[6851*3 + 0] = -0.869030f;	val_dir[6851*3 + 1] = 0.066848f;	val_dir[6851*3 + 2] = 0.490222f;
+ 	val_dir[6852*3 + 0] = -0.861857f;	val_dir[6852*3 + 1] = 0.090722f;	val_dir[6852*3 + 2] = 0.498970f;
+ 	val_dir[6853*3 + 0] = -0.853796f;	val_dir[6853*3 + 1] = 0.115378f;	val_dir[6853*3 + 2] = 0.507662f;
+ 	val_dir[6854*3 + 0] = -0.844782f;	val_dir[6854*3 + 1] = 0.140797f;	val_dir[6854*3 + 2] = 0.516256f;
+ 	val_dir[6855*3 + 0] = -0.834754f;	val_dir[6855*3 + 1] = 0.166951f;	val_dir[6855*3 + 2] = 0.524703f;
+ 	val_dir[6856*3 + 0] = -0.823653f;	val_dir[6856*3 + 1] = 0.193801f;	val_dir[6856*3 + 2] = 0.532952f;
+ 	val_dir[6857*3 + 0] = -0.811421f;	val_dir[6857*3 + 1] = 0.221297f;	val_dir[6857*3 + 2] = 0.540947f;
+ 	val_dir[6858*3 + 0] = -0.798007f;	val_dir[6858*3 + 1] = 0.249377f;	val_dir[6858*3 + 2] = 0.548630f;
+ 	val_dir[6859*3 + 0] = -0.783368f;	val_dir[6859*3 + 1] = 0.277969f;	val_dir[6859*3 + 2] = 0.555939f;
+ 	val_dir[6860*3 + 0] = -0.767467f;	val_dir[6860*3 + 1] = 0.306987f;	val_dir[6860*3 + 2] = 0.562809f;
+ 	val_dir[6861*3 + 0] = -0.750279f;	val_dir[6861*3 + 1] = 0.336332f;	val_dir[6861*3 + 2] = 0.569177f;
+ 	val_dir[6862*3 + 0] = -0.731792f;	val_dir[6862*3 + 1] = 0.365896f;	val_dir[6862*3 + 2] = 0.574979f;
+ 	val_dir[6863*3 + 0] = -0.712007f;	val_dir[6863*3 + 1] = 0.395559f;	val_dir[6863*3 + 2] = 0.580154f;
+ 	val_dir[6864*3 + 0] = -0.690942f;	val_dir[6864*3 + 1] = 0.425195f;	val_dir[6864*3 + 2] = 0.584643f;
+ 	val_dir[6865*3 + 0] = -0.668631f;	val_dir[6865*3 + 1] = 0.454669f;	val_dir[6865*3 + 2] = 0.588395f;
+ 	val_dir[6866*3 + 0] = -0.645124f;	val_dir[6866*3 + 1] = 0.483843f;	val_dir[6866*3 + 2] = 0.591364f;
+ 	val_dir[6867*3 + 0] = -0.620490f;	val_dir[6867*3 + 1] = 0.512578f;	val_dir[6867*3 + 2] = 0.593512f;
+ 	val_dir[6868*3 + 0] = -0.594812f;	val_dir[6868*3 + 1] = 0.540738f;	val_dir[6868*3 + 2] = 0.594812f;
+ 	val_dir[6869*3 + 0] = -0.568190f;	val_dir[6869*3 + 1] = 0.568190f;	val_dir[6869*3 + 2] = 0.595247f;
+ 	val_dir[6870*3 + 0] = -0.540738f;	val_dir[6870*3 + 1] = 0.594812f;	val_dir[6870*3 + 2] = 0.594812f;
+ 	val_dir[6871*3 + 0] = -0.512578f;	val_dir[6871*3 + 1] = 0.620490f;	val_dir[6871*3 + 2] = 0.593512f;
+ 	val_dir[6872*3 + 0] = -0.483843f;	val_dir[6872*3 + 1] = 0.645124f;	val_dir[6872*3 + 2] = 0.591364f;
+ 	val_dir[6873*3 + 0] = -0.454669f;	val_dir[6873*3 + 1] = 0.668631f;	val_dir[6873*3 + 2] = 0.588395f;
+ 	val_dir[6874*3 + 0] = -0.425195f;	val_dir[6874*3 + 1] = 0.690942f;	val_dir[6874*3 + 2] = 0.584643f;
+ 	val_dir[6875*3 + 0] = -0.395559f;	val_dir[6875*3 + 1] = 0.712007f;	val_dir[6875*3 + 2] = 0.580154f;
+ 	val_dir[6876*3 + 0] = -0.365896f;	val_dir[6876*3 + 1] = 0.731792f;	val_dir[6876*3 + 2] = 0.574979f;
+ 	val_dir[6877*3 + 0] = -0.336332f;	val_dir[6877*3 + 1] = 0.750279f;	val_dir[6877*3 + 2] = 0.569177f;
+ 	val_dir[6878*3 + 0] = -0.306987f;	val_dir[6878*3 + 1] = 0.767467f;	val_dir[6878*3 + 2] = 0.562809f;
+ 	val_dir[6879*3 + 0] = -0.277969f;	val_dir[6879*3 + 1] = 0.783368f;	val_dir[6879*3 + 2] = 0.555939f;
+ 	val_dir[6880*3 + 0] = -0.249377f;	val_dir[6880*3 + 1] = 0.798007f;	val_dir[6880*3 + 2] = 0.548630f;
+ 	val_dir[6881*3 + 0] = -0.221297f;	val_dir[6881*3 + 1] = 0.811421f;	val_dir[6881*3 + 2] = 0.540947f;
+ 	val_dir[6882*3 + 0] = -0.193801f;	val_dir[6882*3 + 1] = 0.823653f;	val_dir[6882*3 + 2] = 0.532952f;
+ 	val_dir[6883*3 + 0] = -0.166951f;	val_dir[6883*3 + 1] = 0.834754f;	val_dir[6883*3 + 2] = 0.524703f;
+ 	val_dir[6884*3 + 0] = -0.140797f;	val_dir[6884*3 + 1] = 0.844782f;	val_dir[6884*3 + 2] = 0.516256f;
+ 	val_dir[6885*3 + 0] = -0.115378f;	val_dir[6885*3 + 1] = 0.853796f;	val_dir[6885*3 + 2] = 0.507662f;
+ 	val_dir[6886*3 + 0] = -0.090722f;	val_dir[6886*3 + 1] = 0.861857f;	val_dir[6886*3 + 2] = 0.498970f;
+ 	val_dir[6887*3 + 0] = -0.066848f;	val_dir[6887*3 + 1] = 0.869030f;	val_dir[6887*3 + 2] = 0.490222f;
+ 	val_dir[6888*3 + 0] = -0.043769f;	val_dir[6888*3 + 1] = 0.875376f;	val_dir[6888*3 + 2] = 0.481457f;
+ 	val_dir[6889*3 + 0] = -0.021487f;	val_dir[6889*3 + 1] = 0.880957f;	val_dir[6889*3 + 2] = 0.472709f;
+ 	val_dir[6890*3 + 0] = 0.0f;	val_dir[6890*3 + 1] = 0.885832f;	val_dir[6890*3 + 2] = 0.464007f;
+ 	val_dir[6891*3 + 0] = 0.021082f;	val_dir[6891*3 + 1] = 0.906520f;	val_dir[6891*3 + 2] = 0.421637f;
+ 	val_dir[6892*3 + 0] = 0.042033f;	val_dir[6892*3 + 1] = 0.924729f;	val_dir[6892*3 + 2] = 0.378298f;
+ 	val_dir[6893*3 + 0] = 0.062691f;	val_dir[6893*3 + 1] = 0.940361f;	val_dir[6893*3 + 2] = 0.334351f;
+ 	val_dir[6894*3 + 0] = 0.082903f;	val_dir[6894*3 + 1] = 0.953381f;	val_dir[6894*3 + 2] = 0.290159f;
+ 	val_dir[6895*3 + 0] = 0.102533f;	val_dir[6895*3 + 1] = 0.963811f;	val_dir[6895*3 + 2] = 0.246079f;
+ 	val_dir[6896*3 + 0] = 0.121466f;	val_dir[6896*3 + 1] = 0.971732f;	val_dir[6896*3 + 2] = 0.202444f;
+ 	val_dir[6897*3 + 0] = 0.139610f;	val_dir[6897*3 + 1] = 0.977267f;	val_dir[6897*3 + 2] = 0.159554f;
+ 	val_dir[6898*3 + 0] = 0.156893f;	val_dir[6898*3 + 1] = 0.980581f;	val_dir[6898*3 + 2] = 0.117670f;
+ 	val_dir[6899*3 + 0] = 0.173269f;	val_dir[6899*3 + 1] = 0.981859f;	val_dir[6899*3 + 2] = 0.077009f;
+ 	val_dir[6900*3 + 0] = 0.188713f;	val_dir[6900*3 + 1] = 0.981307f;	val_dir[6900*3 + 2] = 0.037743f;
+ 	val_dir[6901*3 + 0] = 0.203216f;	val_dir[6901*3 + 1] = 0.979134f;	val_dir[6901*3 + 2] = 0.0f;
+ 	val_dir[6902*3 + 0] = -0.982493f;	val_dir[6902*3 + 1] = -0.185376f;	val_dir[6902*3 + 2] = 0.018538f;
+ 	val_dir[6903*3 + 0] = -0.983762f;	val_dir[6903*3 + 1] = -0.170267f;	val_dir[6903*3 + 2] = 0.056756f;
+ 	val_dir[6904*3 + 0] = -0.983318f;	val_dir[6904*3 + 1] = -0.154246f;	val_dir[6904*3 + 2] = 0.096404f;
+ 	val_dir[6905*3 + 0] = -0.980958f;	val_dir[6905*3 + 1] = -0.137334f;	val_dir[6905*3 + 2] = 0.137334f;
+ 	val_dir[6906*3 + 0] = -0.976491f;	val_dir[6906*3 + 1] = -0.119570f;	val_dir[6906*3 + 2] = 0.179355f;
+ 	val_dir[6907*3 + 0] = -0.969746f;	val_dir[6907*3 + 1] = -0.101015f;	val_dir[6907*3 + 2] = 0.222234f;
+ 	val_dir[6908*3 + 0] = -0.960585f;	val_dir[6908*3 + 1] = -0.081752f;	val_dir[6908*3 + 2] = 0.265694f;
+ 	val_dir[6909*3 + 0] = -0.948908f;	val_dir[6909*3 + 1] = -0.061885f;	val_dir[6909*3 + 2] = 0.309426f;
+ 	val_dir[6910*3 + 0] = -0.934665f;	val_dir[6910*3 + 1] = -0.041541f;	val_dir[6910*3 + 2] = 0.353096f;
+ 	val_dir[6911*3 + 0] = -0.917863f;	val_dir[6911*3 + 1] = -0.020861f;	val_dir[6911*3 + 2] = 0.396350f;
+ 	val_dir[6912*3 + 0] = -0.898567f;	val_dir[6912*3 + 1] = 0.0f;	val_dir[6912*3 + 2] = 0.438835f;
+ 	val_dir[6913*3 + 0] = -0.894224f;	val_dir[6913*3 + 1] = 0.021291f;	val_dir[6913*3 + 2] = 0.447112f;
+ 	val_dir[6914*3 + 0] = -0.889206f;	val_dir[6914*3 + 1] = 0.043376f;	val_dir[6914*3 + 2] = 0.455447f;
+ 	val_dir[6915*3 + 0] = -0.883452f;	val_dir[6915*3 + 1] = 0.066259f;	val_dir[6915*3 + 2] = 0.463812f;
+ 	val_dir[6916*3 + 0] = -0.876903f;	val_dir[6916*3 + 1] = 0.089939f;	val_dir[6916*3 + 2] = 0.472178f;
+ 	val_dir[6917*3 + 0] = -0.869495f;	val_dir[6917*3 + 1] = 0.114407f;	val_dir[6917*3 + 2] = 0.480510f;
+ 	val_dir[6918*3 + 0] = -0.861164f;	val_dir[6918*3 + 1] = 0.139648f;	val_dir[6918*3 + 2] = 0.488769f;
+ 	val_dir[6919*3 + 0] = -0.851847f;	val_dir[6919*3 + 1] = 0.165637f;	val_dir[6919*3 + 2] = 0.496911f;
+ 	val_dir[6920*3 + 0] = -0.841482f;	val_dir[6920*3 + 1] = 0.192339f;	val_dir[6920*3 + 2] = 0.504889f;
+ 	val_dir[6921*3 + 0] = -0.830009f;	val_dir[6921*3 + 1] = 0.219708f;	val_dir[6921*3 + 2] = 0.512653f;
+ 	val_dir[6922*3 + 0] = -0.817373f;	val_dir[6922*3 + 1] = 0.247689f;	val_dir[6922*3 + 2] = 0.520146f;
+ 	val_dir[6923*3 + 0] = -0.803523f;	val_dir[6923*3 + 1] = 0.276211f;	val_dir[6923*3 + 2] = 0.527312f;
+ 	val_dir[6924*3 + 0] = -0.788419f;	val_dir[6924*3 + 1] = 0.305194f;	val_dir[6924*3 + 2] = 0.534090f;
+ 	val_dir[6925*3 + 0] = -0.772027f;	val_dir[6925*3 + 1] = 0.334545f;	val_dir[6925*3 + 2] = 0.540419f;
+ 	val_dir[6926*3 + 0] = -0.754329f;	val_dir[6926*3 + 1] = 0.364159f;	val_dir[6926*3 + 2] = 0.546238f;
+ 	val_dir[6927*3 + 0] = -0.735316f;	val_dir[6927*3 + 1] = 0.393919f;	val_dir[6927*3 + 2] = 0.551487f;
+ 	val_dir[6928*3 + 0] = -0.714997f;	val_dir[6928*3 + 1] = 0.423702f;	val_dir[6928*3 + 2] = 0.556108f;
+ 	val_dir[6929*3 + 0] = -0.693395f;	val_dir[6929*3 + 1] = 0.453374f;	val_dir[6929*3 + 2] = 0.560050f;
+ 	val_dir[6930*3 + 0] = -0.670552f;	val_dir[6930*3 + 1] = 0.482798f;	val_dir[6930*3 + 2] = 0.563264f;
+ 	val_dir[6931*3 + 0] = -0.646527f;	val_dir[6931*3 + 1] = 0.511834f;	val_dir[6931*3 + 2] = 0.565711f;
+ 	val_dir[6932*3 + 0] = -0.621395f;	val_dir[6932*3 + 1] = 0.540343f;	val_dir[6932*3 + 2] = 0.567360f;
+ 	val_dir[6933*3 + 0] = -0.595247f;	val_dir[6933*3 + 1] = 0.568190f;	val_dir[6933*3 + 2] = 0.568190f;
+ 	val_dir[6934*3 + 0] = -0.568190f;	val_dir[6934*3 + 1] = 0.595247f;	val_dir[6934*3 + 2] = 0.568190f;
+ 	val_dir[6935*3 + 0] = -0.540343f;	val_dir[6935*3 + 1] = 0.621395f;	val_dir[6935*3 + 2] = 0.567360f;
+ 	val_dir[6936*3 + 0] = -0.511834f;	val_dir[6936*3 + 1] = 0.646527f;	val_dir[6936*3 + 2] = 0.565711f;
+ 	val_dir[6937*3 + 0] = -0.482798f;	val_dir[6937*3 + 1] = 0.670552f;	val_dir[6937*3 + 2] = 0.563264f;
+ 	val_dir[6938*3 + 0] = -0.453374f;	val_dir[6938*3 + 1] = 0.693395f;	val_dir[6938*3 + 2] = 0.560050f;
+ 	val_dir[6939*3 + 0] = -0.423702f;	val_dir[6939*3 + 1] = 0.714997f;	val_dir[6939*3 + 2] = 0.556108f;
+ 	val_dir[6940*3 + 0] = -0.393919f;	val_dir[6940*3 + 1] = 0.735316f;	val_dir[6940*3 + 2] = 0.551487f;
+ 	val_dir[6941*3 + 0] = -0.364159f;	val_dir[6941*3 + 1] = 0.754329f;	val_dir[6941*3 + 2] = 0.546238f;
+ 	val_dir[6942*3 + 0] = -0.334545f;	val_dir[6942*3 + 1] = 0.772027f;	val_dir[6942*3 + 2] = 0.540419f;
+ 	val_dir[6943*3 + 0] = -0.305194f;	val_dir[6943*3 + 1] = 0.788419f;	val_dir[6943*3 + 2] = 0.534090f;
+ 	val_dir[6944*3 + 0] = -0.276211f;	val_dir[6944*3 + 1] = 0.803523f;	val_dir[6944*3 + 2] = 0.527312f;
+ 	val_dir[6945*3 + 0] = -0.247689f;	val_dir[6945*3 + 1] = 0.817373f;	val_dir[6945*3 + 2] = 0.520146f;
+ 	val_dir[6946*3 + 0] = -0.219708f;	val_dir[6946*3 + 1] = 0.830009f;	val_dir[6946*3 + 2] = 0.512653f;
+ 	val_dir[6947*3 + 0] = -0.192339f;	val_dir[6947*3 + 1] = 0.841482f;	val_dir[6947*3 + 2] = 0.504889f;
+ 	val_dir[6948*3 + 0] = -0.165637f;	val_dir[6948*3 + 1] = 0.851847f;	val_dir[6948*3 + 2] = 0.496911f;
+ 	val_dir[6949*3 + 0] = -0.139648f;	val_dir[6949*3 + 1] = 0.861164f;	val_dir[6949*3 + 2] = 0.488769f;
+ 	val_dir[6950*3 + 0] = -0.114407f;	val_dir[6950*3 + 1] = 0.869495f;	val_dir[6950*3 + 2] = 0.480510f;
+ 	val_dir[6951*3 + 0] = -0.089939f;	val_dir[6951*3 + 1] = 0.876903f;	val_dir[6951*3 + 2] = 0.472178f;
+ 	val_dir[6952*3 + 0] = -0.066259f;	val_dir[6952*3 + 1] = 0.883452f;	val_dir[6952*3 + 2] = 0.463812f;
+ 	val_dir[6953*3 + 0] = -0.043376f;	val_dir[6953*3 + 1] = 0.889206f;	val_dir[6953*3 + 2] = 0.455447f;
+ 	val_dir[6954*3 + 0] = -0.021291f;	val_dir[6954*3 + 1] = 0.894224f;	val_dir[6954*3 + 2] = 0.447112f;
+ 	val_dir[6955*3 + 0] = 0.0f;	val_dir[6955*3 + 1] = 0.898567f;	val_dir[6955*3 + 2] = 0.438835f;
+ 	val_dir[6956*3 + 0] = 0.020861f;	val_dir[6956*3 + 1] = 0.917863f;	val_dir[6956*3 + 2] = 0.396350f;
+ 	val_dir[6957*3 + 0] = 0.041541f;	val_dir[6957*3 + 1] = 0.934665f;	val_dir[6957*3 + 2] = 0.353096f;
+ 	val_dir[6958*3 + 0] = 0.061885f;	val_dir[6958*3 + 1] = 0.948908f;	val_dir[6958*3 + 2] = 0.309426f;
+ 	val_dir[6959*3 + 0] = 0.081752f;	val_dir[6959*3 + 1] = 0.960585f;	val_dir[6959*3 + 2] = 0.265694f;
+ 	val_dir[6960*3 + 0] = 0.101015f;	val_dir[6960*3 + 1] = 0.969746f;	val_dir[6960*3 + 2] = 0.222234f;
+ 	val_dir[6961*3 + 0] = 0.119570f;	val_dir[6961*3 + 1] = 0.976491f;	val_dir[6961*3 + 2] = 0.179355f;
+ 	val_dir[6962*3 + 0] = 0.137334f;	val_dir[6962*3 + 1] = 0.980958f;	val_dir[6962*3 + 2] = 0.137334f;
+ 	val_dir[6963*3 + 0] = 0.154246f;	val_dir[6963*3 + 1] = 0.983318f;	val_dir[6963*3 + 2] = 0.096404f;
+ 	val_dir[6964*3 + 0] = 0.170267f;	val_dir[6964*3 + 1] = 0.983762f;	val_dir[6964*3 + 2] = 0.056756f;
+ 	val_dir[6965*3 + 0] = 0.185376f;	val_dir[6965*3 + 1] = 0.982493f;	val_dir[6965*3 + 2] = 0.018538f;
+ 	val_dir[6966*3 + 0] = -0.983282f;	val_dir[6966*3 + 1] = -0.182089f;	val_dir[6966*3 + 2] = 0.0f;
+ 	val_dir[6967*3 + 0] = -0.985205f;	val_dir[6967*3 + 1] = -0.167299f;	val_dir[6967*3 + 2] = 0.037178f;
+ 	val_dir[6968*3 + 0] = -0.985527f;	val_dir[6968*3 + 1] = -0.151620f;	val_dir[6968*3 + 2] = 0.075810f;
+ 	val_dir[6969*3 + 0] = -0.984050f;	val_dir[6969*3 + 1] = -0.135066f;	val_dir[6969*3 + 2] = 0.115771f;
+ 	val_dir[6970*3 + 0] = -0.980581f;	val_dir[6970*3 + 1] = -0.117670f;	val_dir[6970*3 + 2] = 0.156893f;
+ 	val_dir[6971*3 + 0] = -0.974943f;	val_dir[6971*3 + 1] = -0.099484f;	val_dir[6971*3 + 2] = 0.198968f;
+ 	val_dir[6972*3 + 0] = -0.966988f;	val_dir[6972*3 + 1] = -0.080582f;	val_dir[6972*3 + 2] = 0.241747f;
+ 	val_dir[6973*3 + 0] = -0.956597f;	val_dir[6973*3 + 1] = -0.061059f;	val_dir[6973*3 + 2] = 0.284944f;
+ 	val_dir[6974*3 + 0] = -0.943701f;	val_dir[6974*3 + 1] = -0.041030f;	val_dir[6974*3 + 2] = 0.328244f;
+ 	val_dir[6975*3 + 0] = -0.928279f;	val_dir[6975*3 + 1] = -0.020628f;	val_dir[6975*3 + 2] = 0.371312f;
+ 	val_dir[6976*3 + 0] = -0.910366f;	val_dir[6976*3 + 1] = 0.0f;	val_dir[6976*3 + 2] = 0.413803f;
+ 	val_dir[6977*3 + 0] = -0.906520f;	val_dir[6977*3 + 1] = 0.021082f;	val_dir[6977*3 + 2] = 0.421637f;
+ 	val_dir[6978*3 + 0] = -0.902027f;	val_dir[6978*3 + 1] = 0.042954f;	val_dir[6978*3 + 2] = 0.429537f;
+ 	val_dir[6979*3 + 0] = -0.896831f;	val_dir[6979*3 + 1] = 0.065622f;	val_dir[6979*3 + 2] = 0.437479f;
+ 	val_dir[6980*3 + 0] = -0.890871f;	val_dir[6980*3 + 1] = 0.089087f;	val_dir[6980*3 + 2] = 0.445435f;
+ 	val_dir[6981*3 + 0] = -0.884083f;	val_dir[6981*3 + 1] = 0.113344f;	val_dir[6981*3 + 2] = 0.453376f;
+ 	val_dir[6982*3 + 0] = -0.876405f;	val_dir[6982*3 + 1] = 0.138380f;	val_dir[6982*3 + 2] = 0.461266f;
+ 	val_dir[6983*3 + 0] = -0.867770f;	val_dir[6983*3 + 1] = 0.164173f;	val_dir[6983*3 + 2] = 0.469065f;
+ 	val_dir[6984*3 + 0] = -0.858116f;	val_dir[6984*3 + 1] = 0.190693f;	val_dir[6984*3 + 2] = 0.476731f;
+ 	val_dir[6985*3 + 0] = -0.847381f;	val_dir[6985*3 + 1] = 0.217898f;	val_dir[6985*3 + 2] = 0.484217f;
+ 	val_dir[6986*3 + 0] = -0.835504f;	val_dir[6986*3 + 1] = 0.245737f;	val_dir[6986*3 + 2] = 0.491473f;
+ 	val_dir[6987*3 + 0] = -0.822434f;	val_dir[6987*3 + 1] = 0.274145f;	val_dir[6987*3 + 2] = 0.498445f;
+ 	val_dir[6988*3 + 0] = -0.808122f;	val_dir[6988*3 + 1] = 0.303046f;	val_dir[6988*3 + 2] = 0.505076f;
+ 	val_dir[6989*3 + 0] = -0.792530f;	val_dir[6989*3 + 1] = 0.332352f;	val_dir[6989*3 + 2] = 0.511310f;
+ 	val_dir[6990*3 + 0] = -0.775632f;	val_dir[6990*3 + 1] = 0.361961f;	val_dir[6990*3 + 2] = 0.517088f;
+ 	val_dir[6991*3 + 0] = -0.757410f;	val_dir[6991*3 + 1] = 0.391764f;	val_dir[6991*3 + 2] = 0.522352f;
+ 	val_dir[6992*3 + 0] = -0.737865f;	val_dir[6992*3 + 1] = 0.421637f;	val_dir[6992*3 + 2] = 0.527046f;
+ 	val_dir[6993*3 + 0] = -0.717011f;	val_dir[6993*3 + 1] = 0.451451f;	val_dir[6993*3 + 2] = 0.531119f;
+ 	val_dir[6994*3 + 0] = -0.694879f;	val_dir[6994*3 + 1] = 0.481070f;	val_dir[6994*3 + 2] = 0.534522f;
+ 	val_dir[6995*3 + 0] = -0.671519f;	val_dir[6995*3 + 1] = 0.510355f;	val_dir[6995*3 + 2] = 0.537215f;
+ 	val_dir[6996*3 + 0] = -0.646997f;	val_dir[6996*3 + 1] = 0.539164f;	val_dir[6996*3 + 2] = 0.539164f;
+ 	val_dir[6997*3 + 0] = -0.621395f;	val_dir[6997*3 + 1] = 0.567360f;	val_dir[6997*3 + 2] = 0.540343f;
+ 	val_dir[6998*3 + 0] = -0.594812f;	val_dir[6998*3 + 1] = 0.594812f;	val_dir[6998*3 + 2] = 0.540738f;
+ 	val_dir[6999*3 + 0] = -0.567360f;	val_dir[6999*3 + 1] = 0.621395f;	val_dir[6999*3 + 2] = 0.540343f;
+ 	val_dir[7000*3 + 0] = -0.539164f;	val_dir[7000*3 + 1] = 0.646997f;	val_dir[7000*3 + 2] = 0.539164f;
+ 	val_dir[7001*3 + 0] = -0.510355f;	val_dir[7001*3 + 1] = 0.671519f;	val_dir[7001*3 + 2] = 0.537215f;
+ 	val_dir[7002*3 + 0] = -0.481070f;	val_dir[7002*3 + 1] = 0.694879f;	val_dir[7002*3 + 2] = 0.534522f;
+ 	val_dir[7003*3 + 0] = -0.451451f;	val_dir[7003*3 + 1] = 0.717011f;	val_dir[7003*3 + 2] = 0.531119f;
+ 	val_dir[7004*3 + 0] = -0.421637f;	val_dir[7004*3 + 1] = 0.737865f;	val_dir[7004*3 + 2] = 0.527046f;
+ 	val_dir[7005*3 + 0] = -0.391764f;	val_dir[7005*3 + 1] = 0.757410f;	val_dir[7005*3 + 2] = 0.522352f;
+ 	val_dir[7006*3 + 0] = -0.361961f;	val_dir[7006*3 + 1] = 0.775632f;	val_dir[7006*3 + 2] = 0.517088f;
+ 	val_dir[7007*3 + 0] = -0.332352f;	val_dir[7007*3 + 1] = 0.792530f;	val_dir[7007*3 + 2] = 0.511310f;
+ 	val_dir[7008*3 + 0] = -0.303046f;	val_dir[7008*3 + 1] = 0.808122f;	val_dir[7008*3 + 2] = 0.505076f;
+ 	val_dir[7009*3 + 0] = -0.274145f;	val_dir[7009*3 + 1] = 0.822434f;	val_dir[7009*3 + 2] = 0.498445f;
+ 	val_dir[7010*3 + 0] = -0.245737f;	val_dir[7010*3 + 1] = 0.835504f;	val_dir[7010*3 + 2] = 0.491473f;
+ 	val_dir[7011*3 + 0] = -0.217898f;	val_dir[7011*3 + 1] = 0.847381f;	val_dir[7011*3 + 2] = 0.484217f;
+ 	val_dir[7012*3 + 0] = -0.190693f;	val_dir[7012*3 + 1] = 0.858116f;	val_dir[7012*3 + 2] = 0.476731f;
+ 	val_dir[7013*3 + 0] = -0.164173f;	val_dir[7013*3 + 1] = 0.867770f;	val_dir[7013*3 + 2] = 0.469065f;
+ 	val_dir[7014*3 + 0] = -0.138380f;	val_dir[7014*3 + 1] = 0.876405f;	val_dir[7014*3 + 2] = 0.461266f;
+ 	val_dir[7015*3 + 0] = -0.113344f;	val_dir[7015*3 + 1] = 0.884083f;	val_dir[7015*3 + 2] = 0.453376f;
+ 	val_dir[7016*3 + 0] = -0.089087f;	val_dir[7016*3 + 1] = 0.890871f;	val_dir[7016*3 + 2] = 0.445435f;
+ 	val_dir[7017*3 + 0] = -0.065622f;	val_dir[7017*3 + 1] = 0.896831f;	val_dir[7017*3 + 2] = 0.437479f;
+ 	val_dir[7018*3 + 0] = -0.042954f;	val_dir[7018*3 + 1] = 0.902027f;	val_dir[7018*3 + 2] = 0.429537f;
+ 	val_dir[7019*3 + 0] = -0.021082f;	val_dir[7019*3 + 1] = 0.906520f;	val_dir[7019*3 + 2] = 0.421637f;
+ 	val_dir[7020*3 + 0] = 0.0f;	val_dir[7020*3 + 1] = 0.910366f;	val_dir[7020*3 + 2] = 0.413803f;
+ 	val_dir[7021*3 + 0] = 0.020628f;	val_dir[7021*3 + 1] = 0.928279f;	val_dir[7021*3 + 2] = 0.371312f;
+ 	val_dir[7022*3 + 0] = 0.041030f;	val_dir[7022*3 + 1] = 0.943701f;	val_dir[7022*3 + 2] = 0.328244f;
+ 	val_dir[7023*3 + 0] = 0.061059f;	val_dir[7023*3 + 1] = 0.956597f;	val_dir[7023*3 + 2] = 0.284944f;
+ 	val_dir[7024*3 + 0] = 0.080582f;	val_dir[7024*3 + 1] = 0.966988f;	val_dir[7024*3 + 2] = 0.241747f;
+ 	val_dir[7025*3 + 0] = 0.099484f;	val_dir[7025*3 + 1] = 0.974943f;	val_dir[7025*3 + 2] = 0.198968f;
+ 	val_dir[7026*3 + 0] = 0.117670f;	val_dir[7026*3 + 1] = 0.980581f;	val_dir[7026*3 + 2] = 0.156893f;
+ 	val_dir[7027*3 + 0] = 0.135066f;	val_dir[7027*3 + 1] = 0.984050f;	val_dir[7027*3 + 2] = 0.115771f;
+ 	val_dir[7028*3 + 0] = 0.151620f;	val_dir[7028*3 + 1] = 0.985527f;	val_dir[7028*3 + 2] = 0.075810f;
+ 	val_dir[7029*3 + 0] = 0.167299f;	val_dir[7029*3 + 1] = 0.985205f;	val_dir[7029*3 + 2] = 0.037178f;
+ 	val_dir[7030*3 + 0] = 0.182089f;	val_dir[7030*3 + 1] = 0.983282f;	val_dir[7030*3 + 2] = 0.0f;
+ 	val_dir[7031*3 + 0] = -0.986229f;	val_dir[7031*3 + 1] = -0.164372f;	val_dir[7031*3 + 2] = 0.018264f;
+ 	val_dir[7032*3 + 0] = -0.987254f;	val_dir[7032*3 + 1] = -0.149019f;	val_dir[7032*3 + 2] = 0.055882f;
+ 	val_dir[7033*3 + 0] = -0.986591f;	val_dir[7033*3 + 1] = -0.132810f;	val_dir[7033*3 + 2] = 0.094865f;
+ 	val_dir[7034*3 + 0] = -0.984050f;	val_dir[7034*3 + 1] = -0.115771f;	val_dir[7034*3 + 2] = 0.135066f;
+ 	val_dir[7035*3 + 0] = -0.979451f;	val_dir[7035*3 + 1] = -0.097945f;	val_dir[7035*3 + 2] = 0.176301f;
+ 	val_dir[7036*3 + 0] = -0.972636f;	val_dir[7036*3 + 1] = -0.079399f;	val_dir[7036*3 + 2] = 0.218347f;
+ 	val_dir[7037*3 + 0] = -0.963475f;	val_dir[7037*3 + 1] = -0.060217f;	val_dir[7037*3 + 2] = 0.260941f;
+ 	val_dir[7038*3 + 0] = -0.951877f;	val_dir[7038*3 + 1] = -0.040505f;	val_dir[7038*3 + 2] = 0.303791f;
+ 	val_dir[7039*3 + 0] = -0.93780f;	val_dir[7039*3 + 1] = -0.020387f;	val_dir[7039*3 + 2] = 0.346578f;
+ 	val_dir[7040*3 + 0] = -0.921250f;	val_dir[7040*3 + 1] = 0.0f;	val_dir[7040*3 + 2] = 0.388972f;
+ 	val_dir[7041*3 + 0] = -0.917863f;	val_dir[7041*3 + 1] = 0.020861f;	val_dir[7041*3 + 2] = 0.396350f;
+ 	val_dir[7042*3 + 0] = -0.913860f;	val_dir[7042*3 + 1] = 0.042505f;	val_dir[7042*3 + 2] = 0.403799f;
+ 	val_dir[7043*3 + 0] = -0.909185f;	val_dir[7043*3 + 1] = 0.064942f;	val_dir[7043*3 + 2] = 0.411298f;
+ 	val_dir[7044*3 + 0] = -0.903777f;	val_dir[7044*3 + 1] = 0.088173f;	val_dir[7044*3 + 2] = 0.418823f;
+ 	val_dir[7045*3 + 0] = -0.897574f;	val_dir[7045*3 + 1] = 0.112197f;	val_dir[7045*3 + 2] = 0.426348f;
+ 	val_dir[7046*3 + 0] = -0.890513f;	val_dir[7046*3 + 1] = 0.137002f;	val_dir[7046*3 + 2] = 0.433840f;
+ 	val_dir[7047*3 + 0] = -0.882528f;	val_dir[7047*3 + 1] = 0.162571f;	val_dir[7047*3 + 2] = 0.441264f;
+ 	val_dir[7048*3 + 0] = -0.873555f;	val_dir[7048*3 + 1] = 0.188877f;	val_dir[7048*3 + 2] = 0.448583f;
+ 	val_dir[7049*3 + 0] = -0.863530f;	val_dir[7049*3 + 1] = 0.215883f;	val_dir[7049*3 + 2] = 0.455752f;
+ 	val_dir[7050*3 + 0] = -0.852392f;	val_dir[7050*3 + 1] = 0.243541f;	val_dir[7050*3 + 2] = 0.462727f;
+ 	val_dir[7051*3 + 0] = -0.840083f;	val_dir[7051*3 + 1] = 0.271791f;	val_dir[7051*3 + 2] = 0.469458f;
+ 	val_dir[7052*3 + 0] = -0.826551f;	val_dir[7052*3 + 1] = 0.300564f;	val_dir[7052*3 + 2] = 0.475893f;
+ 	val_dir[7053*3 + 0] = -0.811754f;	val_dir[7053*3 + 1] = 0.329775f;	val_dir[7053*3 + 2] = 0.481979f;
+ 	val_dir[7054*3 + 0] = -0.795657f;	val_dir[7054*3 + 1] = 0.359329f;	val_dir[7054*3 + 2] = 0.487661f;
+ 	val_dir[7055*3 + 0] = -0.778237f;	val_dir[7055*3 + 1] = 0.389118f;	val_dir[7055*3 + 2] = 0.492883f;
+ 	val_dir[7056*3 + 0] = -0.759485f;	val_dir[7056*3 + 1] = 0.419026f;	val_dir[7056*3 + 2] = 0.497594f;
+ 	val_dir[7057*3 + 0] = -0.739407f;	val_dir[7057*3 + 1] = 0.448926f;	val_dir[7057*3 + 2] = 0.501740f;
+ 	val_dir[7058*3 + 0] = -0.718024f;	val_dir[7058*3 + 1] = 0.478683f;	val_dir[7058*3 + 2] = 0.505276f;
+ 	val_dir[7059*3 + 0] = -0.695376f;	val_dir[7059*3 + 1] = 0.508159f;	val_dir[7059*3 + 2] = 0.508159f;
+ 	val_dir[7060*3 + 0] = -0.671519f;	val_dir[7060*3 + 1] = 0.537215f;	val_dir[7060*3 + 2] = 0.510355f;
+ 	val_dir[7061*3 + 0] = -0.646527f;	val_dir[7061*3 + 1] = 0.565711f;	val_dir[7061*3 + 2] = 0.511834f;
+ 	val_dir[7062*3 + 0] = -0.620490f;	val_dir[7062*3 + 1] = 0.593512f;	val_dir[7062*3 + 2] = 0.512578f;
+ 	val_dir[7063*3 + 0] = -0.593512f;	val_dir[7063*3 + 1] = 0.620490f;	val_dir[7063*3 + 2] = 0.512578f;
+ 	val_dir[7064*3 + 0] = -0.565711f;	val_dir[7064*3 + 1] = 0.646527f;	val_dir[7064*3 + 2] = 0.511834f;
+ 	val_dir[7065*3 + 0] = -0.537215f;	val_dir[7065*3 + 1] = 0.671519f;	val_dir[7065*3 + 2] = 0.510355f;
+ 	val_dir[7066*3 + 0] = -0.508159f;	val_dir[7066*3 + 1] = 0.695376f;	val_dir[7066*3 + 2] = 0.508159f;
+ 	val_dir[7067*3 + 0] = -0.478683f;	val_dir[7067*3 + 1] = 0.718024f;	val_dir[7067*3 + 2] = 0.505276f;
+ 	val_dir[7068*3 + 0] = -0.448926f;	val_dir[7068*3 + 1] = 0.739407f;	val_dir[7068*3 + 2] = 0.501740f;
+ 	val_dir[7069*3 + 0] = -0.419026f;	val_dir[7069*3 + 1] = 0.759485f;	val_dir[7069*3 + 2] = 0.497594f;
+ 	val_dir[7070*3 + 0] = -0.389118f;	val_dir[7070*3 + 1] = 0.778237f;	val_dir[7070*3 + 2] = 0.492883f;
+ 	val_dir[7071*3 + 0] = -0.359329f;	val_dir[7071*3 + 1] = 0.795657f;	val_dir[7071*3 + 2] = 0.487661f;
+ 	val_dir[7072*3 + 0] = -0.329775f;	val_dir[7072*3 + 1] = 0.811754f;	val_dir[7072*3 + 2] = 0.481979f;
+ 	val_dir[7073*3 + 0] = -0.300564f;	val_dir[7073*3 + 1] = 0.826551f;	val_dir[7073*3 + 2] = 0.475893f;
+ 	val_dir[7074*3 + 0] = -0.271791f;	val_dir[7074*3 + 1] = 0.840083f;	val_dir[7074*3 + 2] = 0.469458f;
+ 	val_dir[7075*3 + 0] = -0.243541f;	val_dir[7075*3 + 1] = 0.852392f;	val_dir[7075*3 + 2] = 0.462727f;
+ 	val_dir[7076*3 + 0] = -0.215883f;	val_dir[7076*3 + 1] = 0.863530f;	val_dir[7076*3 + 2] = 0.455752f;
+ 	val_dir[7077*3 + 0] = -0.188877f;	val_dir[7077*3 + 1] = 0.873555f;	val_dir[7077*3 + 2] = 0.448583f;
+ 	val_dir[7078*3 + 0] = -0.162571f;	val_dir[7078*3 + 1] = 0.882528f;	val_dir[7078*3 + 2] = 0.441264f;
+ 	val_dir[7079*3 + 0] = -0.137002f;	val_dir[7079*3 + 1] = 0.890513f;	val_dir[7079*3 + 2] = 0.433840f;
+ 	val_dir[7080*3 + 0] = -0.112197f;	val_dir[7080*3 + 1] = 0.897574f;	val_dir[7080*3 + 2] = 0.426348f;
+ 	val_dir[7081*3 + 0] = -0.088173f;	val_dir[7081*3 + 1] = 0.903777f;	val_dir[7081*3 + 2] = 0.418823f;
+ 	val_dir[7082*3 + 0] = -0.064942f;	val_dir[7082*3 + 1] = 0.909185f;	val_dir[7082*3 + 2] = 0.411298f;
+ 	val_dir[7083*3 + 0] = -0.042505f;	val_dir[7083*3 + 1] = 0.913860f;	val_dir[7083*3 + 2] = 0.403799f;
+ 	val_dir[7084*3 + 0] = -0.020861f;	val_dir[7084*3 + 1] = 0.917863f;	val_dir[7084*3 + 2] = 0.396350f;
+ 	val_dir[7085*3 + 0] = 0.0f;	val_dir[7085*3 + 1] = 0.921250f;	val_dir[7085*3 + 2] = 0.388972f;
+ 	val_dir[7086*3 + 0] = 0.020387f;	val_dir[7086*3 + 1] = 0.93780f;	val_dir[7086*3 + 2] = 0.346578f;
+ 	val_dir[7087*3 + 0] = 0.040505f;	val_dir[7087*3 + 1] = 0.951877f;	val_dir[7087*3 + 2] = 0.303791f;
+ 	val_dir[7088*3 + 0] = 0.060217f;	val_dir[7088*3 + 1] = 0.963475f;	val_dir[7088*3 + 2] = 0.260941f;
+ 	val_dir[7089*3 + 0] = 0.079399f;	val_dir[7089*3 + 1] = 0.972636f;	val_dir[7089*3 + 2] = 0.218347f;
+ 	val_dir[7090*3 + 0] = 0.097945f;	val_dir[7090*3 + 1] = 0.979451f;	val_dir[7090*3 + 2] = 0.176301f;
+ 	val_dir[7091*3 + 0] = 0.115771f;	val_dir[7091*3 + 1] = 0.984050f;	val_dir[7091*3 + 2] = 0.135066f;
+ 	val_dir[7092*3 + 0] = 0.132810f;	val_dir[7092*3 + 1] = 0.986591f;	val_dir[7092*3 + 2] = 0.094865f;
+ 	val_dir[7093*3 + 0] = 0.149019f;	val_dir[7093*3 + 1] = 0.987254f;	val_dir[7093*3 + 2] = 0.055882f;
+ 	val_dir[7094*3 + 0] = 0.164372f;	val_dir[7094*3 + 1] = 0.986229f;	val_dir[7094*3 + 2] = 0.018264f;
+ 	val_dir[7095*3 + 0] = -0.986875f;	val_dir[7095*3 + 1] = -0.161489f;	val_dir[7095*3 + 2] = 0.0f;
+ 	val_dir[7096*3 + 0] = -0.988540f;	val_dir[7096*3 + 1] = -0.146450f;	val_dir[7096*3 + 2] = 0.036613f;
+ 	val_dir[7097*3 + 0] = -0.988627f;	val_dir[7097*3 + 1] = -0.130573f;	val_dir[7097*3 + 2] = 0.074613f;
+ 	val_dir[7098*3 + 0] = -0.986947f;	val_dir[7098*3 + 1] = -0.113878f;	val_dir[7098*3 + 2] = 0.113878f;
+ 	val_dir[7099*3 + 0] = -0.983318f;	val_dir[7099*3 + 1] = -0.096404f;	val_dir[7099*3 + 2] = 0.154246f;
+ 	val_dir[7100*3 + 0] = -0.977577f;	val_dir[7100*3 + 1] = -0.078206f;	val_dir[7100*3 + 2] = 0.195515f;
+ 	val_dir[7101*3 + 0] = -0.969584f;	val_dir[7101*3 + 1] = -0.059362f;	val_dir[7101*3 + 2] = 0.237449f;
+ 	val_dir[7102*3 + 0] = -0.959233f;	val_dir[7102*3 + 1] = -0.039968f;	val_dir[7102*3 + 2] = 0.279776f;
+ 	val_dir[7103*3 + 0] = -0.946458f;	val_dir[7103*3 + 1] = -0.020137f;	val_dir[7103*3 + 2] = 0.322198f;
+ 	val_dir[7104*3 + 0] = -0.931243f;	val_dir[7104*3 + 1] = 0.0f;	val_dir[7104*3 + 2] = 0.364399f;
+ 	val_dir[7105*3 + 0] = -0.928279f;	val_dir[7105*3 + 1] = 0.020628f;	val_dir[7105*3 + 2] = 0.371312f;
+ 	val_dir[7106*3 + 0] = -0.924729f;	val_dir[7106*3 + 1] = 0.042033f;	val_dir[7106*3 + 2] = 0.378298f;
+ 	val_dir[7107*3 + 0] = -0.920537f;	val_dir[7107*3 + 1] = 0.064223f;	val_dir[7107*3 + 2] = 0.385341f;
+ 	val_dir[7108*3 + 0] = -0.915644f;	val_dir[7108*3 + 1] = 0.087204f;	val_dir[7108*3 + 2] = 0.392419f;
+ 	val_dir[7109*3 + 0] = -0.909988f;	val_dir[7109*3 + 1] = 0.110974f;	val_dir[7109*3 + 2] = 0.399507f;
+ 	val_dir[7110*3 + 0] = -0.903508f;	val_dir[7110*3 + 1] = 0.135526f;	val_dir[7110*3 + 2] = 0.406579f;
+ 	val_dir[7111*3 + 0] = -0.896137f;	val_dir[7111*3 + 1] = 0.160845f;	val_dir[7111*3 + 2] = 0.413602f;
+ 	val_dir[7112*3 + 0] = -0.887812f;	val_dir[7112*3 + 1] = 0.186908f;	val_dir[7112*3 + 2] = 0.420542f;
+ 	val_dir[7113*3 + 0] = -0.878466f;	val_dir[7113*3 + 1] = 0.213681f;	val_dir[7113*3 + 2] = 0.427362f;
+ 	val_dir[7114*3 + 0] = -0.868037f;	val_dir[7114*3 + 1] = 0.241121f;	val_dir[7114*3 + 2] = 0.434019f;
+ 	val_dir[7115*3 + 0] = -0.856465f;	val_dir[7115*3 + 1] = 0.269175f;	val_dir[7115*3 + 2] = 0.440468f;
+ 	val_dir[7116*3 + 0] = -0.843696f;	val_dir[7116*3 + 1] = 0.297775f;	val_dir[7116*3 + 2] = 0.446662f;
+ 	val_dir[7117*3 + 0] = -0.829680f;	val_dir[7117*3 + 1] = 0.326844f;	val_dir[7117*3 + 2] = 0.452553f;
+ 	val_dir[7118*3 + 0] = -0.814379f;	val_dir[7118*3 + 1] = 0.356291f;	val_dir[7118*3 + 2] = 0.458088f;
+ 	val_dir[7119*3 + 0] = -0.797762f;	val_dir[7119*3 + 1] = 0.386014f;	val_dir[7119*3 + 2] = 0.463217f;
+ 	val_dir[7120*3 + 0] = -0.779813f;	val_dir[7120*3 + 1] = 0.41590f;	val_dir[7120*3 + 2] = 0.467888f;
+ 	val_dir[7121*3 + 0] = -0.760529f;	val_dir[7121*3 + 1] = 0.445827f;	val_dir[7121*3 + 2] = 0.472053f;
+ 	val_dir[7122*3 + 0] = -0.739923f;	val_dir[7122*3 + 1] = 0.475665f;	val_dir[7122*3 + 2] = 0.475665f;
+ 	val_dir[7123*3 + 0] = -0.718024f;	val_dir[7123*3 + 1] = 0.505276f;	val_dir[7123*3 + 2] = 0.478683f;
+ 	val_dir[7124*3 + 0] = -0.694879f;	val_dir[7124*3 + 1] = 0.534522f;	val_dir[7124*3 + 2] = 0.481070f;
+ 	val_dir[7125*3 + 0] = -0.670552f;	val_dir[7125*3 + 1] = 0.563264f;	val_dir[7125*3 + 2] = 0.482798f;
+ 	val_dir[7126*3 + 0] = -0.645124f;	val_dir[7126*3 + 1] = 0.591364f;	val_dir[7126*3 + 2] = 0.483843f;
+ 	val_dir[7127*3 + 0] = -0.618691f;	val_dir[7127*3 + 1] = 0.618691f;	val_dir[7127*3 + 2] = 0.484193f;
+ 	val_dir[7128*3 + 0] = -0.591364f;	val_dir[7128*3 + 1] = 0.645124f;	val_dir[7128*3 + 2] = 0.483843f;
+ 	val_dir[7129*3 + 0] = -0.563264f;	val_dir[7129*3 + 1] = 0.670552f;	val_dir[7129*3 + 2] = 0.482798f;
+ 	val_dir[7130*3 + 0] = -0.534522f;	val_dir[7130*3 + 1] = 0.694879f;	val_dir[7130*3 + 2] = 0.481070f;
+ 	val_dir[7131*3 + 0] = -0.505276f;	val_dir[7131*3 + 1] = 0.718024f;	val_dir[7131*3 + 2] = 0.478683f;
+ 	val_dir[7132*3 + 0] = -0.475665f;	val_dir[7132*3 + 1] = 0.739923f;	val_dir[7132*3 + 2] = 0.475665f;
+ 	val_dir[7133*3 + 0] = -0.445827f;	val_dir[7133*3 + 1] = 0.760529f;	val_dir[7133*3 + 2] = 0.472053f;
+ 	val_dir[7134*3 + 0] = -0.41590f;	val_dir[7134*3 + 1] = 0.779813f;	val_dir[7134*3 + 2] = 0.467888f;
+ 	val_dir[7135*3 + 0] = -0.386014f;	val_dir[7135*3 + 1] = 0.797762f;	val_dir[7135*3 + 2] = 0.463217f;
+ 	val_dir[7136*3 + 0] = -0.356291f;	val_dir[7136*3 + 1] = 0.814379f;	val_dir[7136*3 + 2] = 0.458088f;
+ 	val_dir[7137*3 + 0] = -0.326844f;	val_dir[7137*3 + 1] = 0.829680f;	val_dir[7137*3 + 2] = 0.452553f;
+ 	val_dir[7138*3 + 0] = -0.297775f;	val_dir[7138*3 + 1] = 0.843696f;	val_dir[7138*3 + 2] = 0.446662f;
+ 	val_dir[7139*3 + 0] = -0.269175f;	val_dir[7139*3 + 1] = 0.856465f;	val_dir[7139*3 + 2] = 0.440468f;
+ 	val_dir[7140*3 + 0] = -0.241121f;	val_dir[7140*3 + 1] = 0.868037f;	val_dir[7140*3 + 2] = 0.434019f;
+ 	val_dir[7141*3 + 0] = -0.213681f;	val_dir[7141*3 + 1] = 0.878466f;	val_dir[7141*3 + 2] = 0.427362f;
+ 	val_dir[7142*3 + 0] = -0.186908f;	val_dir[7142*3 + 1] = 0.887812f;	val_dir[7142*3 + 2] = 0.420542f;
+ 	val_dir[7143*3 + 0] = -0.160845f;	val_dir[7143*3 + 1] = 0.896137f;	val_dir[7143*3 + 2] = 0.413602f;
+ 	val_dir[7144*3 + 0] = -0.135526f;	val_dir[7144*3 + 1] = 0.903508f;	val_dir[7144*3 + 2] = 0.406579f;
+ 	val_dir[7145*3 + 0] = -0.110974f;	val_dir[7145*3 + 1] = 0.909988f;	val_dir[7145*3 + 2] = 0.399507f;
+ 	val_dir[7146*3 + 0] = -0.087204f;	val_dir[7146*3 + 1] = 0.915644f;	val_dir[7146*3 + 2] = 0.392419f;
+ 	val_dir[7147*3 + 0] = -0.064223f;	val_dir[7147*3 + 1] = 0.920537f;	val_dir[7147*3 + 2] = 0.385341f;
+ 	val_dir[7148*3 + 0] = -0.042033f;	val_dir[7148*3 + 1] = 0.924729f;	val_dir[7148*3 + 2] = 0.378298f;
+ 	val_dir[7149*3 + 0] = -0.020628f;	val_dir[7149*3 + 1] = 0.928279f;	val_dir[7149*3 + 2] = 0.371312f;
+ 	val_dir[7150*3 + 0] = 0.0f;	val_dir[7150*3 + 1] = 0.931243f;	val_dir[7150*3 + 2] = 0.364399f;
+ 	val_dir[7151*3 + 0] = 0.020137f;	val_dir[7151*3 + 1] = 0.946458f;	val_dir[7151*3 + 2] = 0.322198f;
+ 	val_dir[7152*3 + 0] = 0.039968f;	val_dir[7152*3 + 1] = 0.959233f;	val_dir[7152*3 + 2] = 0.279776f;
+ 	val_dir[7153*3 + 0] = 0.059362f;	val_dir[7153*3 + 1] = 0.969584f;	val_dir[7153*3 + 2] = 0.237449f;
+ 	val_dir[7154*3 + 0] = 0.078206f;	val_dir[7154*3 + 1] = 0.977577f;	val_dir[7154*3 + 2] = 0.195515f;
+ 	val_dir[7155*3 + 0] = 0.096404f;	val_dir[7155*3 + 1] = 0.983318f;	val_dir[7155*3 + 2] = 0.154246f;
+ 	val_dir[7156*3 + 0] = 0.113878f;	val_dir[7156*3 + 1] = 0.986947f;	val_dir[7156*3 + 2] = 0.113878f;
+ 	val_dir[7157*3 + 0] = 0.130573f;	val_dir[7157*3 + 1] = 0.988627f;	val_dir[7157*3 + 2] = 0.074613f;
+ 	val_dir[7158*3 + 0] = 0.146450f;	val_dir[7158*3 + 1] = 0.988540f;	val_dir[7158*3 + 2] = 0.036613f;
+ 	val_dir[7159*3 + 0] = 0.161489f;	val_dir[7159*3 + 1] = 0.986875f;	val_dir[7159*3 + 2] = 0.0f;
+ 	val_dir[7160*3 + 0] = -0.989426f;	val_dir[7160*3 + 1] = -0.143917f;	val_dir[7160*3 + 2] = 0.017990f;
+ 	val_dir[7161*3 + 0] = -0.990201f;	val_dir[7161*3 + 1] = -0.128359f;	val_dir[7161*3 + 2] = 0.055011f;
+ 	val_dir[7162*3 + 0] = -0.989316f;	val_dir[7162*3 + 1] = -0.111998f;	val_dir[7162*3 + 2] = 0.093332f;
+ 	val_dir[7163*3 + 0] = -0.986591f;	val_dir[7163*3 + 1] = -0.094865f;	val_dir[7163*3 + 2] = 0.132810f;
+ 	val_dir[7164*3 + 0] = -0.981859f;	val_dir[7164*3 + 1] = -0.077009f;	val_dir[7164*3 + 2] = 0.173269f;
+ 	val_dir[7165*3 + 0] = -0.974972f;	val_dir[7165*3 + 1] = -0.058498f;	val_dir[7165*3 + 2] = 0.214494f;
+ 	val_dir[7166*3 + 0] = -0.965810f;	val_dir[7166*3 + 1] = -0.039421f;	val_dir[7166*3 + 2] = 0.256235f;
+ 	val_dir[7167*3 + 0] = -0.954291f;	val_dir[7167*3 + 1] = -0.019881f;	val_dir[7167*3 + 2] = 0.298216f;
+ 	val_dir[7168*3 + 0] = -0.940376f;	val_dir[7168*3 + 1] = 0.0f;	val_dir[7168*3 + 2] = 0.340136f;
+ 	val_dir[7169*3 + 0] = -0.93780f;	val_dir[7169*3 + 1] = 0.020387f;	val_dir[7169*3 + 2] = 0.346578f;
+ 	val_dir[7170*3 + 0] = -0.934665f;	val_dir[7170*3 + 1] = 0.041541f;	val_dir[7170*3 + 2] = 0.353096f;
+ 	val_dir[7171*3 + 0] = -0.930917f;	val_dir[7171*3 + 1] = 0.063472f;	val_dir[7171*3 + 2] = 0.359673f;
+ 	val_dir[7172*3 + 0] = -0.92650f;	val_dir[7172*3 + 1] = 0.086186f;	val_dir[7172*3 + 2] = 0.366291f;
+ 	val_dir[7173*3 + 0] = -0.921354f;	val_dir[7173*3 + 1] = 0.109685f;	val_dir[7173*3 + 2] = 0.372929f;
+ 	val_dir[7174*3 + 0] = -0.915416f;	val_dir[7174*3 + 1] = 0.133963f;	val_dir[7174*3 + 2] = 0.379563f;
+ 	val_dir[7175*3 + 0] = -0.908622f;	val_dir[7175*3 + 1] = 0.159009f;	val_dir[7175*3 + 2] = 0.386164f;
+ 	val_dir[7176*3 + 0] = -0.900907f;	val_dir[7176*3 + 1] = 0.184801f;	val_dir[7176*3 + 2] = 0.392703f;
+ 	val_dir[7177*3 + 0] = -0.892206f;	val_dir[7177*3 + 1] = 0.211312f;	val_dir[7177*3 + 2] = 0.399145f;
+ 	val_dir[7178*3 + 0] = -0.882454f;	val_dir[7178*3 + 1] = 0.238501f;	val_dir[7178*3 + 2] = 0.405452f;
+ 	val_dir[7179*3 + 0] = -0.871592f;	val_dir[7179*3 + 1] = 0.266320f;	val_dir[7179*3 + 2] = 0.411585f;
+ 	val_dir[7180*3 + 0] = -0.859559f;	val_dir[7180*3 + 1] = 0.294706f;	val_dir[7180*3 + 2] = 0.41750f;
+ 	val_dir[7181*3 + 0] = -0.846305f;	val_dir[7181*3 + 1] = 0.323587f;	val_dir[7181*3 + 2] = 0.423153f;
+ 	val_dir[7182*3 + 0] = -0.831786f;	val_dir[7182*3 + 1] = 0.352879f;	val_dir[7182*3 + 2] = 0.428496f;
+ 	val_dir[7183*3 + 0] = -0.815966f;	val_dir[7183*3 + 1] = 0.382484f;	val_dir[7183*3 + 2] = 0.433482f;
+ 	val_dir[7184*3 + 0] = -0.798820f;	val_dir[7184*3 + 1] = 0.412294f;	val_dir[7184*3 + 2] = 0.438063f;
+ 	val_dir[7185*3 + 0] = -0.780340f;	val_dir[7185*3 + 1] = 0.442193f;	val_dir[7185*3 + 2] = 0.442193f;
+ 	val_dir[7186*3 + 0] = -0.760529f;	val_dir[7186*3 + 1] = 0.472053f;	val_dir[7186*3 + 2] = 0.445827f;
+ 	val_dir[7187*3 + 0] = -0.739407f;	val_dir[7187*3 + 1] = 0.501740f;	val_dir[7187*3 + 2] = 0.448926f;
+ 	val_dir[7188*3 + 0] = -0.717011f;	val_dir[7188*3 + 1] = 0.531119f;	val_dir[7188*3 + 2] = 0.451451f;
+ 	val_dir[7189*3 + 0] = -0.693395f;	val_dir[7189*3 + 1] = 0.560050f;	val_dir[7189*3 + 2] = 0.453374f;
+ 	val_dir[7190*3 + 0] = -0.668631f;	val_dir[7190*3 + 1] = 0.588395f;	val_dir[7190*3 + 2] = 0.454669f;
+ 	val_dir[7191*3 + 0] = -0.642806f;	val_dir[7191*3 + 1] = 0.616022f;	val_dir[7191*3 + 2] = 0.455321f;
+ 	val_dir[7192*3 + 0] = -0.616022f;	val_dir[7192*3 + 1] = 0.642806f;	val_dir[7192*3 + 2] = 0.455321f;
+ 	val_dir[7193*3 + 0] = -0.588395f;	val_dir[7193*3 + 1] = 0.668631f;	val_dir[7193*3 + 2] = 0.454669f;
+ 	val_dir[7194*3 + 0] = -0.560050f;	val_dir[7194*3 + 1] = 0.693395f;	val_dir[7194*3 + 2] = 0.453374f;
+ 	val_dir[7195*3 + 0] = -0.531119f;	val_dir[7195*3 + 1] = 0.717011f;	val_dir[7195*3 + 2] = 0.451451f;
+ 	val_dir[7196*3 + 0] = -0.501740f;	val_dir[7196*3 + 1] = 0.739407f;	val_dir[7196*3 + 2] = 0.448926f;
+ 	val_dir[7197*3 + 0] = -0.472053f;	val_dir[7197*3 + 1] = 0.760529f;	val_dir[7197*3 + 2] = 0.445827f;
+ 	val_dir[7198*3 + 0] = -0.442193f;	val_dir[7198*3 + 1] = 0.780340f;	val_dir[7198*3 + 2] = 0.442193f;
+ 	val_dir[7199*3 + 0] = -0.412294f;	val_dir[7199*3 + 1] = 0.798820f;	val_dir[7199*3 + 2] = 0.438063f;
+ 	val_dir[7200*3 + 0] = -0.382484f;	val_dir[7200*3 + 1] = 0.815966f;	val_dir[7200*3 + 2] = 0.433482f;
+ 	val_dir[7201*3 + 0] = -0.352879f;	val_dir[7201*3 + 1] = 0.831786f;	val_dir[7201*3 + 2] = 0.428496f;
+ 	val_dir[7202*3 + 0] = -0.323587f;	val_dir[7202*3 + 1] = 0.846305f;	val_dir[7202*3 + 2] = 0.423153f;
+ 	val_dir[7203*3 + 0] = -0.294706f;	val_dir[7203*3 + 1] = 0.859559f;	val_dir[7203*3 + 2] = 0.41750f;
+ 	val_dir[7204*3 + 0] = -0.266320f;	val_dir[7204*3 + 1] = 0.871592f;	val_dir[7204*3 + 2] = 0.411585f;
+ 	val_dir[7205*3 + 0] = -0.238501f;	val_dir[7205*3 + 1] = 0.882454f;	val_dir[7205*3 + 2] = 0.405452f;
+ 	val_dir[7206*3 + 0] = -0.211312f;	val_dir[7206*3 + 1] = 0.892206f;	val_dir[7206*3 + 2] = 0.399145f;
+ 	val_dir[7207*3 + 0] = -0.184801f;	val_dir[7207*3 + 1] = 0.900907f;	val_dir[7207*3 + 2] = 0.392703f;
+ 	val_dir[7208*3 + 0] = -0.159009f;	val_dir[7208*3 + 1] = 0.908622f;	val_dir[7208*3 + 2] = 0.386164f;
+ 	val_dir[7209*3 + 0] = -0.133963f;	val_dir[7209*3 + 1] = 0.915416f;	val_dir[7209*3 + 2] = 0.379563f;
+ 	val_dir[7210*3 + 0] = -0.109685f;	val_dir[7210*3 + 1] = 0.921354f;	val_dir[7210*3 + 2] = 0.372929f;
+ 	val_dir[7211*3 + 0] = -0.086186f;	val_dir[7211*3 + 1] = 0.92650f;	val_dir[7211*3 + 2] = 0.366291f;
+ 	val_dir[7212*3 + 0] = -0.063472f;	val_dir[7212*3 + 1] = 0.930917f;	val_dir[7212*3 + 2] = 0.359673f;
+ 	val_dir[7213*3 + 0] = -0.041541f;	val_dir[7213*3 + 1] = 0.934665f;	val_dir[7213*3 + 2] = 0.353096f;
+ 	val_dir[7214*3 + 0] = -0.020387f;	val_dir[7214*3 + 1] = 0.93780f;	val_dir[7214*3 + 2] = 0.346578f;
+ 	val_dir[7215*3 + 0] = 0.0f;	val_dir[7215*3 + 1] = 0.940376f;	val_dir[7215*3 + 2] = 0.340136f;
+ 	val_dir[7216*3 + 0] = 0.019881f;	val_dir[7216*3 + 1] = 0.954291f;	val_dir[7216*3 + 2] = 0.298216f;
+ 	val_dir[7217*3 + 0] = 0.039421f;	val_dir[7217*3 + 1] = 0.965810f;	val_dir[7217*3 + 2] = 0.256235f;
+ 	val_dir[7218*3 + 0] = 0.058498f;	val_dir[7218*3 + 1] = 0.974972f;	val_dir[7218*3 + 2] = 0.214494f;
+ 	val_dir[7219*3 + 0] = 0.077009f;	val_dir[7219*3 + 1] = 0.981859f;	val_dir[7219*3 + 2] = 0.173269f;
+ 	val_dir[7220*3 + 0] = 0.094865f;	val_dir[7220*3 + 1] = 0.986591f;	val_dir[7220*3 + 2] = 0.132810f;
+ 	val_dir[7221*3 + 0] = 0.111998f;	val_dir[7221*3 + 1] = 0.989316f;	val_dir[7221*3 + 2] = 0.093332f;
+ 	val_dir[7222*3 + 0] = 0.128359f;	val_dir[7222*3 + 1] = 0.990201f;	val_dir[7222*3 + 2] = 0.055011f;
+ 	val_dir[7223*3 + 0] = 0.143917f;	val_dir[7223*3 + 1] = 0.989426f;	val_dir[7223*3 + 2] = 0.017990f;
+ 	val_dir[7224*3 + 0] = -0.989949f;	val_dir[7224*3 + 1] = -0.141421f;	val_dir[7224*3 + 2] = 0.0f;
+ 	val_dir[7225*3 + 0] = -0.991353f;	val_dir[7225*3 + 1] = -0.126172f;	val_dir[7225*3 + 2] = 0.036049f;
+ 	val_dir[7226*3 + 0] = -0.991201f;	val_dir[7226*3 + 1] = -0.110133f;	val_dir[7226*3 + 2] = 0.073422f;
+ 	val_dir[7227*3 + 0] = -0.989316f;	val_dir[7227*3 + 1] = -0.093332f;	val_dir[7227*3 + 2] = 0.111998f;
+ 	val_dir[7228*3 + 0] = -0.985527f;	val_dir[7228*3 + 1] = -0.075810f;	val_dir[7228*3 + 2] = 0.151620f;
+ 	val_dir[7229*3 + 0] = -0.979683f;	val_dir[7229*3 + 1] = -0.057628f;	val_dir[7229*3 + 2] = 0.192095f;
+ 	val_dir[7230*3 + 0] = -0.971653f;	val_dir[7230*3 + 1] = -0.038866f;	val_dir[7230*3 + 2] = 0.233197f;
+ 	val_dir[7231*3 + 0] = -0.961339f;	val_dir[7231*3 + 1] = -0.019619f;	val_dir[7231*3 + 2] = 0.274668f;
+ 	val_dir[7232*3 + 0] = -0.948683f;	val_dir[7232*3 + 1] = 0.0f;	val_dir[7232*3 + 2] = 0.316228f;
+ 	val_dir[7233*3 + 0] = -0.946458f;	val_dir[7233*3 + 1] = 0.020137f;	val_dir[7233*3 + 2] = 0.322198f;
+ 	val_dir[7234*3 + 0] = -0.943701f;	val_dir[7234*3 + 1] = 0.041030f;	val_dir[7234*3 + 2] = 0.328244f;
+ 	val_dir[7235*3 + 0] = -0.940361f;	val_dir[7235*3 + 1] = 0.062691f;	val_dir[7235*3 + 2] = 0.334351f;
+ 	val_dir[7236*3 + 0] = -0.936382f;	val_dir[7236*3 + 1] = 0.085126f;	val_dir[7236*3 + 2] = 0.340503f;
+ 	val_dir[7237*3 + 0] = -0.931705f;	val_dir[7237*3 + 1] = 0.108338f;	val_dir[7237*3 + 2] = 0.346681f;
+ 	val_dir[7238*3 + 0] = -0.926270f;	val_dir[7238*3 + 1] = 0.132324f;	val_dir[7238*3 + 2] = 0.352865f;
+ 	val_dir[7239*3 + 0] = -0.920014f;	val_dir[7239*3 + 1] = 0.157075f;	val_dir[7239*3 + 2] = 0.359030f;
+ 	val_dir[7240*3 + 0] = -0.912871f;	val_dir[7240*3 + 1] = 0.182574f;	val_dir[7240*3 + 2] = 0.365148f;
+ 	val_dir[7241*3 + 0] = -0.904777f;	val_dir[7241*3 + 1] = 0.208795f;	val_dir[7241*3 + 2] = 0.371191f;
+ 	val_dir[7242*3 + 0] = -0.895669f;	val_dir[7242*3 + 1] = 0.235702f;	val_dir[7242*3 + 2] = 0.377124f;
+ 	val_dir[7243*3 + 0] = -0.885482f;	val_dir[7243*3 + 1] = 0.263251f;	val_dir[7243*3 + 2] = 0.382911f;
+ 	val_dir[7244*3 + 0] = -0.874157f;	val_dir[7244*3 + 1] = 0.291386f;	val_dir[7244*3 + 2] = 0.388514f;
+ 	val_dir[7245*3 + 0] = -0.861640f;	val_dir[7245*3 + 1] = 0.320038f;	val_dir[7245*3 + 2] = 0.393893f;
+ 	val_dir[7246*3 + 0] = -0.847883f;	val_dir[7246*3 + 1] = 0.349128f;	val_dir[7246*3 + 2] = 0.399004f;
+ 	val_dir[7247*3 + 0] = -0.832845f;	val_dir[7247*3 + 1] = 0.378566f;	val_dir[7247*3 + 2] = 0.403804f;
+ 	val_dir[7248*3 + 0] = -0.816497f;	val_dir[7248*3 + 1] = 0.408248f;	val_dir[7248*3 + 2] = 0.408248f;
+ 	val_dir[7249*3 + 0] = -0.798820f;	val_dir[7249*3 + 1] = 0.438063f;	val_dir[7249*3 + 2] = 0.412294f;
+ 	val_dir[7250*3 + 0] = -0.779813f;	val_dir[7250*3 + 1] = 0.467888f;	val_dir[7250*3 + 2] = 0.41590f;
+ 	val_dir[7251*3 + 0] = -0.759485f;	val_dir[7251*3 + 1] = 0.497594f;	val_dir[7251*3 + 2] = 0.419026f;
+ 	val_dir[7252*3 + 0] = -0.737865f;	val_dir[7252*3 + 1] = 0.527046f;	val_dir[7252*3 + 2] = 0.421637f;
+ 	val_dir[7253*3 + 0] = -0.714997f;	val_dir[7253*3 + 1] = 0.556108f;	val_dir[7253*3 + 2] = 0.423702f;
+ 	val_dir[7254*3 + 0] = -0.690942f;	val_dir[7254*3 + 1] = 0.584643f;	val_dir[7254*3 + 2] = 0.425195f;
+ 	val_dir[7255*3 + 0] = -0.665780f;	val_dir[7255*3 + 1] = 0.612517f;	val_dir[7255*3 + 2] = 0.426099f;
+ 	val_dir[7256*3 + 0] = -0.639602f;	val_dir[7256*3 + 1] = 0.639602f;	val_dir[7256*3 + 2] = 0.426401f;
+ 	val_dir[7257*3 + 0] = -0.612517f;	val_dir[7257*3 + 1] = 0.665780f;	val_dir[7257*3 + 2] = 0.426099f;
+ 	val_dir[7258*3 + 0] = -0.584643f;	val_dir[7258*3 + 1] = 0.690942f;	val_dir[7258*3 + 2] = 0.425195f;
+ 	val_dir[7259*3 + 0] = -0.556108f;	val_dir[7259*3 + 1] = 0.714997f;	val_dir[7259*3 + 2] = 0.423702f;
+ 	val_dir[7260*3 + 0] = -0.527046f;	val_dir[7260*3 + 1] = 0.737865f;	val_dir[7260*3 + 2] = 0.421637f;
+ 	val_dir[7261*3 + 0] = -0.497594f;	val_dir[7261*3 + 1] = 0.759485f;	val_dir[7261*3 + 2] = 0.419026f;
+ 	val_dir[7262*3 + 0] = -0.467888f;	val_dir[7262*3 + 1] = 0.779813f;	val_dir[7262*3 + 2] = 0.41590f;
+ 	val_dir[7263*3 + 0] = -0.438063f;	val_dir[7263*3 + 1] = 0.798820f;	val_dir[7263*3 + 2] = 0.412294f;
+ 	val_dir[7264*3 + 0] = -0.408248f;	val_dir[7264*3 + 1] = 0.816497f;	val_dir[7264*3 + 2] = 0.408248f;
+ 	val_dir[7265*3 + 0] = -0.378566f;	val_dir[7265*3 + 1] = 0.832845f;	val_dir[7265*3 + 2] = 0.403804f;
+ 	val_dir[7266*3 + 0] = -0.349128f;	val_dir[7266*3 + 1] = 0.847883f;	val_dir[7266*3 + 2] = 0.399004f;
+ 	val_dir[7267*3 + 0] = -0.320038f;	val_dir[7267*3 + 1] = 0.861640f;	val_dir[7267*3 + 2] = 0.393893f;
+ 	val_dir[7268*3 + 0] = -0.291386f;	val_dir[7268*3 + 1] = 0.874157f;	val_dir[7268*3 + 2] = 0.388514f;
+ 	val_dir[7269*3 + 0] = -0.263251f;	val_dir[7269*3 + 1] = 0.885482f;	val_dir[7269*3 + 2] = 0.382911f;
+ 	val_dir[7270*3 + 0] = -0.235702f;	val_dir[7270*3 + 1] = 0.895669f;	val_dir[7270*3 + 2] = 0.377124f;
+ 	val_dir[7271*3 + 0] = -0.208795f;	val_dir[7271*3 + 1] = 0.904777f;	val_dir[7271*3 + 2] = 0.371191f;
+ 	val_dir[7272*3 + 0] = -0.182574f;	val_dir[7272*3 + 1] = 0.912871f;	val_dir[7272*3 + 2] = 0.365148f;
+ 	val_dir[7273*3 + 0] = -0.157075f;	val_dir[7273*3 + 1] = 0.920014f;	val_dir[7273*3 + 2] = 0.359030f;
+ 	val_dir[7274*3 + 0] = -0.132324f;	val_dir[7274*3 + 1] = 0.926270f;	val_dir[7274*3 + 2] = 0.352865f;
+ 	val_dir[7275*3 + 0] = -0.108338f;	val_dir[7275*3 + 1] = 0.931705f;	val_dir[7275*3 + 2] = 0.346681f;
+ 	val_dir[7276*3 + 0] = -0.085126f;	val_dir[7276*3 + 1] = 0.936382f;	val_dir[7276*3 + 2] = 0.340503f;
+ 	val_dir[7277*3 + 0] = -0.062691f;	val_dir[7277*3 + 1] = 0.940361f;	val_dir[7277*3 + 2] = 0.334351f;
+ 	val_dir[7278*3 + 0] = -0.041030f;	val_dir[7278*3 + 1] = 0.943701f;	val_dir[7278*3 + 2] = 0.328244f;
+ 	val_dir[7279*3 + 0] = -0.020137f;	val_dir[7279*3 + 1] = 0.946458f;	val_dir[7279*3 + 2] = 0.322198f;
+ 	val_dir[7280*3 + 0] = 0.0f;	val_dir[7280*3 + 1] = 0.948683f;	val_dir[7280*3 + 2] = 0.316228f;
+ 	val_dir[7281*3 + 0] = 0.019619f;	val_dir[7281*3 + 1] = 0.961339f;	val_dir[7281*3 + 2] = 0.274668f;
+ 	val_dir[7282*3 + 0] = 0.038866f;	val_dir[7282*3 + 1] = 0.971653f;	val_dir[7282*3 + 2] = 0.233197f;
+ 	val_dir[7283*3 + 0] = 0.057628f;	val_dir[7283*3 + 1] = 0.979683f;	val_dir[7283*3 + 2] = 0.192095f;
+ 	val_dir[7284*3 + 0] = 0.075810f;	val_dir[7284*3 + 1] = 0.985527f;	val_dir[7284*3 + 2] = 0.151620f;
+ 	val_dir[7285*3 + 0] = 0.093332f;	val_dir[7285*3 + 1] = 0.989316f;	val_dir[7285*3 + 2] = 0.111998f;
+ 	val_dir[7286*3 + 0] = 0.110133f;	val_dir[7286*3 + 1] = 0.991201f;	val_dir[7286*3 + 2] = 0.073422f;
+ 	val_dir[7287*3 + 0] = 0.126172f;	val_dir[7287*3 + 1] = 0.991353f;	val_dir[7287*3 + 2] = 0.036049f;
+ 	val_dir[7288*3 + 0] = 0.141421f;	val_dir[7288*3 + 1] = 0.989949f;	val_dir[7288*3 + 2] = 0.0f;
+ 	val_dir[7289*3 + 0] = -0.992122f;	val_dir[7289*3 + 1] = -0.124015f;	val_dir[7289*3 + 2] = 0.017716f;
+ 	val_dir[7290*3 + 0] = -0.992644f;	val_dir[7290*3 + 1] = -0.108288f;	val_dir[7290*3 + 2] = 0.054144f;
+ 	val_dir[7291*3 + 0] = -0.991535f;	val_dir[7291*3 + 1] = -0.091809f;	val_dir[7291*3 + 2] = 0.091809f;
+ 	val_dir[7292*3 + 0] = -0.988627f;	val_dir[7292*3 + 1] = -0.074613f;	val_dir[7292*3 + 2] = 0.130573f;
+ 	val_dir[7293*3 + 0] = -0.983762f;	val_dir[7293*3 + 1] = -0.056756f;	val_dir[7293*3 + 2] = 0.170267f;
+ 	val_dir[7294*3 + 0] = -0.976804f;	val_dir[7294*3 + 1] = -0.038306f;	val_dir[7294*3 + 2] = 0.210683f;
+ 	val_dir[7295*3 + 0] = -0.967641f;	val_dir[7295*3 + 1] = -0.019353f;	val_dir[7295*3 + 2] = 0.251587f;
+ 	val_dir[7296*3 + 0] = -0.95620f;	val_dir[7296*3 + 1] = 0.0f;	val_dir[7296*3 + 2] = 0.292714f;
+ 	val_dir[7297*3 + 0] = -0.954291f;	val_dir[7297*3 + 1] = 0.019881f;	val_dir[7297*3 + 2] = 0.298216f;
+ 	val_dir[7298*3 + 0] = -0.951877f;	val_dir[7298*3 + 1] = 0.040505f;	val_dir[7298*3 + 2] = 0.303791f;
+ 	val_dir[7299*3 + 0] = -0.948908f;	val_dir[7299*3 + 1] = 0.061885f;	val_dir[7299*3 + 2] = 0.309426f;
+ 	val_dir[7300*3 + 0] = -0.945328f;	val_dir[7300*3 + 1] = 0.084029f;	val_dir[7300*3 + 2] = 0.315109f;
+ 	val_dir[7301*3 + 0] = -0.941082f;	val_dir[7301*3 + 1] = 0.106941f;	val_dir[7301*3 + 2] = 0.320824f;
+ 	val_dir[7302*3 + 0] = -0.936111f;	val_dir[7302*3 + 1] = 0.130620f;	val_dir[7302*3 + 2] = 0.326550f;
+ 	val_dir[7303*3 + 0] = -0.930352f;	val_dir[7303*3 + 1] = 0.155059f;	val_dir[7303*3 + 2] = 0.332269f;
+ 	val_dir[7304*3 + 0] = -0.923742f;	val_dir[7304*3 + 1] = 0.180242f;	val_dir[7304*3 + 2] = 0.337954f;
+ 	val_dir[7305*3 + 0] = -0.916217f;	val_dir[7305*3 + 1] = 0.206149f;	val_dir[7305*3 + 2] = 0.343582f;
+ 	val_dir[7306*3 + 0] = -0.907713f;	val_dir[7306*3 + 1] = 0.232747f;	val_dir[7306*3 + 2] = 0.349121f;
+ 	val_dir[7307*3 + 0] = -0.898167f;	val_dir[7307*3 + 1] = 0.259996f;	val_dir[7307*3 + 2] = 0.354540f;
+ 	val_dir[7308*3 + 0] = -0.887517f;	val_dir[7308*3 + 1] = 0.287843f;	val_dir[7308*3 + 2] = 0.359804f;
+ 	val_dir[7309*3 + 0] = -0.875708f;	val_dir[7309*3 + 1] = 0.316228f;	val_dir[7309*3 + 2] = 0.364878f;
+ 	val_dir[7310*3 + 0] = -0.862687f;	val_dir[7310*3 + 1] = 0.345075f;	val_dir[7310*3 + 2] = 0.369723f;
+ 	val_dir[7311*3 + 0] = -0.848411f;	val_dir[7311*3 + 1] = 0.374299f;	val_dir[7311*3 + 2] = 0.374299f;
+ 	val_dir[7312*3 + 0] = -0.832845f;	val_dir[7312*3 + 1] = 0.403804f;	val_dir[7312*3 + 2] = 0.378566f;
+ 	val_dir[7313*3 + 0] = -0.815966f;	val_dir[7313*3 + 1] = 0.433482f;	val_dir[7313*3 + 2] = 0.382484f;
+ 	val_dir[7314*3 + 0] = -0.797762f;	val_dir[7314*3 + 1] = 0.463217f;	val_dir[7314*3 + 2] = 0.386014f;
+ 	val_dir[7315*3 + 0] = -0.778237f;	val_dir[7315*3 + 1] = 0.492883f;	val_dir[7315*3 + 2] = 0.389118f;
+ 	val_dir[7316*3 + 0] = -0.757410f;	val_dir[7316*3 + 1] = 0.522352f;	val_dir[7316*3 + 2] = 0.391764f;
+ 	val_dir[7317*3 + 0] = -0.735316f;	val_dir[7317*3 + 1] = 0.551487f;	val_dir[7317*3 + 2] = 0.393919f;
+ 	val_dir[7318*3 + 0] = -0.712007f;	val_dir[7318*3 + 1] = 0.580154f;	val_dir[7318*3 + 2] = 0.395559f;
+ 	val_dir[7319*3 + 0] = -0.687552f;	val_dir[7319*3 + 1] = 0.608219f;	val_dir[7319*3 + 2] = 0.396664f;
+ 	val_dir[7320*3 + 0] = -0.662034f;	val_dir[7320*3 + 1] = 0.635553f;	val_dir[7320*3 + 2] = 0.397220f;
+ 	val_dir[7321*3 + 0] = -0.635553f;	val_dir[7321*3 + 1] = 0.662034f;	val_dir[7321*3 + 2] = 0.397220f;
+ 	val_dir[7322*3 + 0] = -0.608219f;	val_dir[7322*3 + 1] = 0.687552f;	val_dir[7322*3 + 2] = 0.396664f;
+ 	val_dir[7323*3 + 0] = -0.580154f;	val_dir[7323*3 + 1] = 0.712007f;	val_dir[7323*3 + 2] = 0.395559f;
+ 	val_dir[7324*3 + 0] = -0.551487f;	val_dir[7324*3 + 1] = 0.735316f;	val_dir[7324*3 + 2] = 0.393919f;
+ 	val_dir[7325*3 + 0] = -0.522352f;	val_dir[7325*3 + 1] = 0.757410f;	val_dir[7325*3 + 2] = 0.391764f;
+ 	val_dir[7326*3 + 0] = -0.492883f;	val_dir[7326*3 + 1] = 0.778237f;	val_dir[7326*3 + 2] = 0.389118f;
+ 	val_dir[7327*3 + 0] = -0.463217f;	val_dir[7327*3 + 1] = 0.797762f;	val_dir[7327*3 + 2] = 0.386014f;
+ 	val_dir[7328*3 + 0] = -0.433482f;	val_dir[7328*3 + 1] = 0.815966f;	val_dir[7328*3 + 2] = 0.382484f;
+ 	val_dir[7329*3 + 0] = -0.403804f;	val_dir[7329*3 + 1] = 0.832845f;	val_dir[7329*3 + 2] = 0.378566f;
+ 	val_dir[7330*3 + 0] = -0.374299f;	val_dir[7330*3 + 1] = 0.848411f;	val_dir[7330*3 + 2] = 0.374299f;
+ 	val_dir[7331*3 + 0] = -0.345075f;	val_dir[7331*3 + 1] = 0.862687f;	val_dir[7331*3 + 2] = 0.369723f;
+ 	val_dir[7332*3 + 0] = -0.316228f;	val_dir[7332*3 + 1] = 0.875708f;	val_dir[7332*3 + 2] = 0.364878f;
+ 	val_dir[7333*3 + 0] = -0.287843f;	val_dir[7333*3 + 1] = 0.887517f;	val_dir[7333*3 + 2] = 0.359804f;
+ 	val_dir[7334*3 + 0] = -0.259996f;	val_dir[7334*3 + 1] = 0.898167f;	val_dir[7334*3 + 2] = 0.354540f;
+ 	val_dir[7335*3 + 0] = -0.232747f;	val_dir[7335*3 + 1] = 0.907713f;	val_dir[7335*3 + 2] = 0.349121f;
+ 	val_dir[7336*3 + 0] = -0.206149f;	val_dir[7336*3 + 1] = 0.916217f;	val_dir[7336*3 + 2] = 0.343582f;
+ 	val_dir[7337*3 + 0] = -0.180242f;	val_dir[7337*3 + 1] = 0.923742f;	val_dir[7337*3 + 2] = 0.337954f;
+ 	val_dir[7338*3 + 0] = -0.155059f;	val_dir[7338*3 + 1] = 0.930352f;	val_dir[7338*3 + 2] = 0.332269f;
+ 	val_dir[7339*3 + 0] = -0.130620f;	val_dir[7339*3 + 1] = 0.936111f;	val_dir[7339*3 + 2] = 0.326550f;
+ 	val_dir[7340*3 + 0] = -0.106941f;	val_dir[7340*3 + 1] = 0.941082f;	val_dir[7340*3 + 2] = 0.320824f;
+ 	val_dir[7341*3 + 0] = -0.084029f;	val_dir[7341*3 + 1] = 0.945328f;	val_dir[7341*3 + 2] = 0.315109f;
+ 	val_dir[7342*3 + 0] = -0.061885f;	val_dir[7342*3 + 1] = 0.948908f;	val_dir[7342*3 + 2] = 0.309426f;
+ 	val_dir[7343*3 + 0] = -0.040505f;	val_dir[7343*3 + 1] = 0.951877f;	val_dir[7343*3 + 2] = 0.303791f;
+ 	val_dir[7344*3 + 0] = -0.019881f;	val_dir[7344*3 + 1] = 0.954291f;	val_dir[7344*3 + 2] = 0.298216f;
+ 	val_dir[7345*3 + 0] = 0.0f;	val_dir[7345*3 + 1] = 0.95620f;	val_dir[7345*3 + 2] = 0.292714f;
+ 	val_dir[7346*3 + 0] = 0.019353f;	val_dir[7346*3 + 1] = 0.967641f;	val_dir[7346*3 + 2] = 0.251587f;
+ 	val_dir[7347*3 + 0] = 0.038306f;	val_dir[7347*3 + 1] = 0.976804f;	val_dir[7347*3 + 2] = 0.210683f;
+ 	val_dir[7348*3 + 0] = 0.056756f;	val_dir[7348*3 + 1] = 0.983762f;	val_dir[7348*3 + 2] = 0.170267f;
+ 	val_dir[7349*3 + 0] = 0.074613f;	val_dir[7349*3 + 1] = 0.988627f;	val_dir[7349*3 + 2] = 0.130573f;
+ 	val_dir[7350*3 + 0] = 0.091809f;	val_dir[7350*3 + 1] = 0.991535f;	val_dir[7350*3 + 2] = 0.091809f;
+ 	val_dir[7351*3 + 0] = 0.108288f;	val_dir[7351*3 + 1] = 0.992644f;	val_dir[7351*3 + 2] = 0.054144f;
+ 	val_dir[7352*3 + 0] = 0.124015f;	val_dir[7352*3 + 1] = 0.992122f;	val_dir[7352*3 + 2] = 0.017716f;
+ 	val_dir[7353*3 + 0] = -0.992543f;	val_dir[7353*3 + 1] = -0.121891f;	val_dir[7353*3 + 2] = 0.0f;
+ 	val_dir[7354*3 + 0] = -0.993683f;	val_dir[7354*3 + 1] = -0.106466f;	val_dir[7354*3 + 2] = 0.035489f;
+ 	val_dir[7355*3 + 0] = -0.993291f;	val_dir[7355*3 + 1] = -0.090299f;	val_dir[7355*3 + 2] = 0.072239f;
+ 	val_dir[7356*3 + 0] = -0.991201f;	val_dir[7356*3 + 1] = -0.073422f;	val_dir[7356*3 + 2] = 0.110133f;
+ 	val_dir[7357*3 + 0] = -0.987254f;	val_dir[7357*3 + 1] = -0.055882f;	val_dir[7357*3 + 2] = 0.149019f;
+ 	val_dir[7358*3 + 0] = -0.981307f;	val_dir[7358*3 + 1] = -0.037743f;	val_dir[7358*3 + 2] = 0.188713f;
+ 	val_dir[7359*3 + 0] = -0.973240f;	val_dir[7359*3 + 1] = -0.019083f;	val_dir[7359*3 + 2] = 0.228998f;
+ 	val_dir[7360*3 + 0] = -0.962964f;	val_dir[7360*3 + 1] = 0.0f;	val_dir[7360*3 + 2] = 0.269630f;
+ 	val_dir[7361*3 + 0] = -0.961339f;	val_dir[7361*3 + 1] = 0.019619f;	val_dir[7361*3 + 2] = 0.274668f;
+ 	val_dir[7362*3 + 0] = -0.959233f;	val_dir[7362*3 + 1] = 0.039968f;	val_dir[7362*3 + 2] = 0.279776f;
+ 	val_dir[7363*3 + 0] = -0.956597f;	val_dir[7363*3 + 1] = 0.061059f;	val_dir[7363*3 + 2] = 0.284944f;
+ 	val_dir[7364*3 + 0] = -0.953381f;	val_dir[7364*3 + 1] = 0.082903f;	val_dir[7364*3 + 2] = 0.290159f;
+ 	val_dir[7365*3 + 0] = -0.949528f;	val_dir[7365*3 + 1] = 0.105503f;	val_dir[7365*3 + 2] = 0.295409f;
+ 	val_dir[7366*3 + 0] = -0.944981f;	val_dir[7366*3 + 1] = 0.128861f;	val_dir[7366*3 + 2] = 0.300676f;
+ 	val_dir[7367*3 + 0] = -0.939680f;	val_dir[7367*3 + 1] = 0.152971f;	val_dir[7367*3 + 2] = 0.305942f;
+ 	val_dir[7368*3 + 0] = -0.933564f;	val_dir[7368*3 + 1] = 0.177822f;	val_dir[7368*3 + 2] = 0.311188f;
+ 	val_dir[7369*3 + 0] = -0.926568f;	val_dir[7369*3 + 1] = 0.203393f;	val_dir[7369*3 + 2] = 0.316389f;
+ 	val_dir[7370*3 + 0] = -0.918630f;	val_dir[7370*3 + 1] = 0.229658f;	val_dir[7370*3 + 2] = 0.321521f;
+ 	val_dir[7371*3 + 0] = -0.909687f;	val_dir[7371*3 + 1] = 0.256578f;	val_dir[7371*3 + 2] = 0.326554f;
+ 	val_dir[7372*3 + 0] = -0.899676f;	val_dir[7372*3 + 1] = 0.284108f;	val_dir[7372*3 + 2] = 0.331460f;
+ 	val_dir[7373*3 + 0] = -0.888540f;	val_dir[7373*3 + 1] = 0.312190f;	val_dir[7373*3 + 2] = 0.336204f;
+ 	val_dir[7374*3 + 0] = -0.876226f;	val_dir[7374*3 + 1] = 0.340755f;	val_dir[7374*3 + 2] = 0.340755f;
+ 	val_dir[7375*3 + 0] = -0.862687f;	val_dir[7375*3 + 1] = 0.369723f;	val_dir[7375*3 + 2] = 0.345075f;
+ 	val_dir[7376*3 + 0] = -0.847883f;	val_dir[7376*3 + 1] = 0.399004f;	val_dir[7376*3 + 2] = 0.349128f;
+ 	val_dir[7377*3 + 0] = -0.831786f;	val_dir[7377*3 + 1] = 0.428496f;	val_dir[7377*3 + 2] = 0.352879f;
+ 	val_dir[7378*3 + 0] = -0.814379f;	val_dir[7378*3 + 1] = 0.458088f;	val_dir[7378*3 + 2] = 0.356291f;
+ 	val_dir[7379*3 + 0] = -0.795657f;	val_dir[7379*3 + 1] = 0.487661f;	val_dir[7379*3 + 2] = 0.359329f;
+ 	val_dir[7380*3 + 0] = -0.775632f;	val_dir[7380*3 + 1] = 0.517088f;	val_dir[7380*3 + 2] = 0.361961f;
+ 	val_dir[7381*3 + 0] = -0.754329f;	val_dir[7381*3 + 1] = 0.546238f;	val_dir[7381*3 + 2] = 0.364159f;
+ 	val_dir[7382*3 + 0] = -0.731792f;	val_dir[7382*3 + 1] = 0.574979f;	val_dir[7382*3 + 2] = 0.365896f;
+ 	val_dir[7383*3 + 0] = -0.708079f;	val_dir[7383*3 + 1] = 0.603178f;	val_dir[7383*3 + 2] = 0.367152f;
+ 	val_dir[7384*3 + 0] = -0.683265f;	val_dir[7384*3 + 1] = 0.630706f;	val_dir[7384*3 + 2] = 0.367912f;
+ 	val_dir[7385*3 + 0] = -0.657440f;	val_dir[7385*3 + 1] = 0.657440f;	val_dir[7385*3 + 2] = 0.368166f;
+ 	val_dir[7386*3 + 0] = -0.630706f;	val_dir[7386*3 + 1] = 0.683265f;	val_dir[7386*3 + 2] = 0.367912f;
+ 	val_dir[7387*3 + 0] = -0.603178f;	val_dir[7387*3 + 1] = 0.708079f;	val_dir[7387*3 + 2] = 0.367152f;
+ 	val_dir[7388*3 + 0] = -0.574979f;	val_dir[7388*3 + 1] = 0.731792f;	val_dir[7388*3 + 2] = 0.365896f;
+ 	val_dir[7389*3 + 0] = -0.546238f;	val_dir[7389*3 + 1] = 0.754329f;	val_dir[7389*3 + 2] = 0.364159f;
+ 	val_dir[7390*3 + 0] = -0.517088f;	val_dir[7390*3 + 1] = 0.775632f;	val_dir[7390*3 + 2] = 0.361961f;
+ 	val_dir[7391*3 + 0] = -0.487661f;	val_dir[7391*3 + 1] = 0.795657f;	val_dir[7391*3 + 2] = 0.359329f;
+ 	val_dir[7392*3 + 0] = -0.458088f;	val_dir[7392*3 + 1] = 0.814379f;	val_dir[7392*3 + 2] = 0.356291f;
+ 	val_dir[7393*3 + 0] = -0.428496f;	val_dir[7393*3 + 1] = 0.831786f;	val_dir[7393*3 + 2] = 0.352879f;
+ 	val_dir[7394*3 + 0] = -0.399004f;	val_dir[7394*3 + 1] = 0.847883f;	val_dir[7394*3 + 2] = 0.349128f;
+ 	val_dir[7395*3 + 0] = -0.369723f;	val_dir[7395*3 + 1] = 0.862687f;	val_dir[7395*3 + 2] = 0.345075f;
+ 	val_dir[7396*3 + 0] = -0.340755f;	val_dir[7396*3 + 1] = 0.876226f;	val_dir[7396*3 + 2] = 0.340755f;
+ 	val_dir[7397*3 + 0] = -0.312190f;	val_dir[7397*3 + 1] = 0.888540f;	val_dir[7397*3 + 2] = 0.336204f;
+ 	val_dir[7398*3 + 0] = -0.284108f;	val_dir[7398*3 + 1] = 0.899676f;	val_dir[7398*3 + 2] = 0.331460f;
+ 	val_dir[7399*3 + 0] = -0.256578f;	val_dir[7399*3 + 1] = 0.909687f;	val_dir[7399*3 + 2] = 0.326554f;
+ 	val_dir[7400*3 + 0] = -0.229658f;	val_dir[7400*3 + 1] = 0.918630f;	val_dir[7400*3 + 2] = 0.321521f;
+ 	val_dir[7401*3 + 0] = -0.203393f;	val_dir[7401*3 + 1] = 0.926568f;	val_dir[7401*3 + 2] = 0.316389f;
+ 	val_dir[7402*3 + 0] = -0.177822f;	val_dir[7402*3 + 1] = 0.933564f;	val_dir[7402*3 + 2] = 0.311188f;
+ 	val_dir[7403*3 + 0] = -0.152971f;	val_dir[7403*3 + 1] = 0.939680f;	val_dir[7403*3 + 2] = 0.305942f;
+ 	val_dir[7404*3 + 0] = -0.128861f;	val_dir[7404*3 + 1] = 0.944981f;	val_dir[7404*3 + 2] = 0.300676f;
+ 	val_dir[7405*3 + 0] = -0.105503f;	val_dir[7405*3 + 1] = 0.949528f;	val_dir[7405*3 + 2] = 0.295409f;
+ 	val_dir[7406*3 + 0] = -0.082903f;	val_dir[7406*3 + 1] = 0.953381f;	val_dir[7406*3 + 2] = 0.290159f;
+ 	val_dir[7407*3 + 0] = -0.061059f;	val_dir[7407*3 + 1] = 0.956597f;	val_dir[7407*3 + 2] = 0.284944f;
+ 	val_dir[7408*3 + 0] = -0.039968f;	val_dir[7408*3 + 1] = 0.959233f;	val_dir[7408*3 + 2] = 0.279776f;
+ 	val_dir[7409*3 + 0] = -0.019619f;	val_dir[7409*3 + 1] = 0.961339f;	val_dir[7409*3 + 2] = 0.274668f;
+ 	val_dir[7410*3 + 0] = 0.0f;	val_dir[7410*3 + 1] = 0.962964f;	val_dir[7410*3 + 2] = 0.269630f;
+ 	val_dir[7411*3 + 0] = 0.019083f;	val_dir[7411*3 + 1] = 0.973240f;	val_dir[7411*3 + 2] = 0.228998f;
+ 	val_dir[7412*3 + 0] = 0.037743f;	val_dir[7412*3 + 1] = 0.981307f;	val_dir[7412*3 + 2] = 0.188713f;
+ 	val_dir[7413*3 + 0] = 0.055882f;	val_dir[7413*3 + 1] = 0.987254f;	val_dir[7413*3 + 2] = 0.149019f;
+ 	val_dir[7414*3 + 0] = 0.073422f;	val_dir[7414*3 + 1] = 0.991201f;	val_dir[7414*3 + 2] = 0.110133f;
+ 	val_dir[7415*3 + 0] = 0.090299f;	val_dir[7415*3 + 1] = 0.993291f;	val_dir[7415*3 + 2] = 0.072239f;
+ 	val_dir[7416*3 + 0] = 0.106466f;	val_dir[7416*3 + 1] = 0.993683f;	val_dir[7416*3 + 2] = 0.035489f;
+ 	val_dir[7417*3 + 0] = 0.121891f;	val_dir[7417*3 + 1] = 0.992543f;	val_dir[7417*3 + 2] = 0.0f;
+ 	val_dir[7418*3 + 0] = -0.994354f;	val_dir[7418*3 + 1] = -0.104669f;	val_dir[7418*3 + 2] = 0.017445f;
+ 	val_dir[7419*3 + 0] = -0.994623f;	val_dir[7419*3 + 1] = -0.088806f;	val_dir[7419*3 + 2] = 0.053283f;
+ 	val_dir[7420*3 + 0] = -0.993291f;	val_dir[7420*3 + 1] = -0.072239f;	val_dir[7420*3 + 2] = 0.090299f;
+ 	val_dir[7421*3 + 0] = -0.990201f;	val_dir[7421*3 + 1] = -0.055011f;	val_dir[7421*3 + 2] = 0.128359f;
+ 	val_dir[7422*3 + 0] = -0.985205f;	val_dir[7422*3 + 1] = -0.037178f;	val_dir[7422*3 + 2] = 0.167299f;
+ 	val_dir[7423*3 + 0] = -0.978177f;	val_dir[7423*3 + 1] = -0.018811f;	val_dir[7423*3 + 2] = 0.206922f;
+ 	val_dir[7424*3 + 0] = -0.969015f;	val_dir[7424*3 + 1] = 0.0f;	val_dir[7424*3 + 2] = 0.247004f;
+ 	val_dir[7425*3 + 0] = -0.967641f;	val_dir[7425*3 + 1] = 0.019353f;	val_dir[7425*3 + 2] = 0.251587f;
+ 	val_dir[7426*3 + 0] = -0.965810f;	val_dir[7426*3 + 1] = 0.039421f;	val_dir[7426*3 + 2] = 0.256235f;
+ 	val_dir[7427*3 + 0] = -0.963475f;	val_dir[7427*3 + 1] = 0.060217f;	val_dir[7427*3 + 2] = 0.260941f;
+ 	val_dir[7428*3 + 0] = -0.960585f;	val_dir[7428*3 + 1] = 0.081752f;	val_dir[7428*3 + 2] = 0.265694f;
+ 	val_dir[7429*3 + 0] = -0.957088f;	val_dir[7429*3 + 1] = 0.104031f;	val_dir[7429*3 + 2] = 0.270481f;
+ 	val_dir[7430*3 + 0] = -0.952928f;	val_dir[7430*3 + 1] = 0.127057f;	val_dir[7430*3 + 2] = 0.275290f;
+ 	val_dir[7431*3 + 0] = -0.948047f;	val_dir[7431*3 + 1] = 0.150826f;	val_dir[7431*3 + 2] = 0.280105f;
+ 	val_dir[7432*3 + 0] = -0.942384f;	val_dir[7432*3 + 1] = 0.175327f;	val_dir[7432*3 + 2] = 0.284907f;
+ 	val_dir[7433*3 + 0] = -0.935879f;	val_dir[7433*3 + 1] = 0.200545f;	val_dir[7433*3 + 2] = 0.289677f;
+ 	val_dir[7434*3 + 0] = -0.928467f;	val_dir[7434*3 + 1] = 0.226455f;	val_dir[7434*3 + 2] = 0.294392f;
+ 	val_dir[7435*3 + 0] = -0.920087f;	val_dir[7435*3 + 1] = 0.253024f;	val_dir[7435*3 + 2] = 0.299028f;
+ 	val_dir[7436*3 + 0] = -0.910678f;	val_dir[7436*3 + 1] = 0.280209f;	val_dir[7436*3 + 2] = 0.303559f;
+ 	val_dir[7437*3 + 0] = -0.900181f;	val_dir[7437*3 + 1] = 0.307957f;	val_dir[7437*3 + 2] = 0.307957f;
+ 	val_dir[7438*3 + 0] = -0.888540f;	val_dir[7438*3 + 1] = 0.336204f;	val_dir[7438*3 + 2] = 0.312190f;
+ 	val_dir[7439*3 + 0] = -0.875708f;	val_dir[7439*3 + 1] = 0.364878f;	val_dir[7439*3 + 2] = 0.316228f;
+ 	val_dir[7440*3 + 0] = -0.861640f;	val_dir[7440*3 + 1] = 0.393893f;	val_dir[7440*3 + 2] = 0.320038f;
+ 	val_dir[7441*3 + 0] = -0.846305f;	val_dir[7441*3 + 1] = 0.423153f;	val_dir[7441*3 + 2] = 0.323587f;
+ 	val_dir[7442*3 + 0] = -0.829680f;	val_dir[7442*3 + 1] = 0.452553f;	val_dir[7442*3 + 2] = 0.326844f;
+ 	val_dir[7443*3 + 0] = -0.811754f;	val_dir[7443*3 + 1] = 0.481979f;	val_dir[7443*3 + 2] = 0.329775f;
+ 	val_dir[7444*3 + 0] = -0.792530f;	val_dir[7444*3 + 1] = 0.511310f;	val_dir[7444*3 + 2] = 0.332352f;
+ 	val_dir[7445*3 + 0] = -0.772027f;	val_dir[7445*3 + 1] = 0.540419f;	val_dir[7445*3 + 2] = 0.334545f;
+ 	val_dir[7446*3 + 0] = -0.750279f;	val_dir[7446*3 + 1] = 0.569177f;	val_dir[7446*3 + 2] = 0.336332f;
+ 	val_dir[7447*3 + 0] = -0.727334f;	val_dir[7447*3 + 1] = 0.597453f;	val_dir[7447*3 + 2] = 0.337691f;
+ 	val_dir[7448*3 + 0] = -0.703259f;	val_dir[7448*3 + 1] = 0.625119f;	val_dir[7448*3 + 2] = 0.338606f;
+ 	val_dir[7449*3 + 0] = -0.678133f;	val_dir[7449*3 + 1] = 0.652051f;	val_dir[7449*3 + 2] = 0.339066f;
+ 	val_dir[7450*3 + 0] = -0.652051f;	val_dir[7450*3 + 1] = 0.678133f;	val_dir[7450*3 + 2] = 0.339066f;
+ 	val_dir[7451*3 + 0] = -0.625119f;	val_dir[7451*3 + 1] = 0.703259f;	val_dir[7451*3 + 2] = 0.338606f;
+ 	val_dir[7452*3 + 0] = -0.597453f;	val_dir[7452*3 + 1] = 0.727334f;	val_dir[7452*3 + 2] = 0.337691f;
+ 	val_dir[7453*3 + 0] = -0.569177f;	val_dir[7453*3 + 1] = 0.750279f;	val_dir[7453*3 + 2] = 0.336332f;
+ 	val_dir[7454*3 + 0] = -0.540419f;	val_dir[7454*3 + 1] = 0.772027f;	val_dir[7454*3 + 2] = 0.334545f;
+ 	val_dir[7455*3 + 0] = -0.511310f;	val_dir[7455*3 + 1] = 0.792530f;	val_dir[7455*3 + 2] = 0.332352f;
+ 	val_dir[7456*3 + 0] = -0.481979f;	val_dir[7456*3 + 1] = 0.811754f;	val_dir[7456*3 + 2] = 0.329775f;
+ 	val_dir[7457*3 + 0] = -0.452553f;	val_dir[7457*3 + 1] = 0.829680f;	val_dir[7457*3 + 2] = 0.326844f;
+ 	val_dir[7458*3 + 0] = -0.423153f;	val_dir[7458*3 + 1] = 0.846305f;	val_dir[7458*3 + 2] = 0.323587f;
+ 	val_dir[7459*3 + 0] = -0.393893f;	val_dir[7459*3 + 1] = 0.861640f;	val_dir[7459*3 + 2] = 0.320038f;
+ 	val_dir[7460*3 + 0] = -0.364878f;	val_dir[7460*3 + 1] = 0.875708f;	val_dir[7460*3 + 2] = 0.316228f;
+ 	val_dir[7461*3 + 0] = -0.336204f;	val_dir[7461*3 + 1] = 0.888540f;	val_dir[7461*3 + 2] = 0.312190f;
+ 	val_dir[7462*3 + 0] = -0.307957f;	val_dir[7462*3 + 1] = 0.900181f;	val_dir[7462*3 + 2] = 0.307957f;
+ 	val_dir[7463*3 + 0] = -0.280209f;	val_dir[7463*3 + 1] = 0.910678f;	val_dir[7463*3 + 2] = 0.303559f;
+ 	val_dir[7464*3 + 0] = -0.253024f;	val_dir[7464*3 + 1] = 0.920087f;	val_dir[7464*3 + 2] = 0.299028f;
+ 	val_dir[7465*3 + 0] = -0.226455f;	val_dir[7465*3 + 1] = 0.928467f;	val_dir[7465*3 + 2] = 0.294392f;
+ 	val_dir[7466*3 + 0] = -0.200545f;	val_dir[7466*3 + 1] = 0.935879f;	val_dir[7466*3 + 2] = 0.289677f;
+ 	val_dir[7467*3 + 0] = -0.175327f;	val_dir[7467*3 + 1] = 0.942384f;	val_dir[7467*3 + 2] = 0.284907f;
+ 	val_dir[7468*3 + 0] = -0.150826f;	val_dir[7468*3 + 1] = 0.948047f;	val_dir[7468*3 + 2] = 0.280105f;
+ 	val_dir[7469*3 + 0] = -0.127057f;	val_dir[7469*3 + 1] = 0.952928f;	val_dir[7469*3 + 2] = 0.275290f;
+ 	val_dir[7470*3 + 0] = -0.104031f;	val_dir[7470*3 + 1] = 0.957088f;	val_dir[7470*3 + 2] = 0.270481f;
+ 	val_dir[7471*3 + 0] = -0.081752f;	val_dir[7471*3 + 1] = 0.960585f;	val_dir[7471*3 + 2] = 0.265694f;
+ 	val_dir[7472*3 + 0] = -0.060217f;	val_dir[7472*3 + 1] = 0.963475f;	val_dir[7472*3 + 2] = 0.260941f;
+ 	val_dir[7473*3 + 0] = -0.039421f;	val_dir[7473*3 + 1] = 0.965810f;	val_dir[7473*3 + 2] = 0.256235f;
+ 	val_dir[7474*3 + 0] = -0.019353f;	val_dir[7474*3 + 1] = 0.967641f;	val_dir[7474*3 + 2] = 0.251587f;
+ 	val_dir[7475*3 + 0] = 0.0f;	val_dir[7475*3 + 1] = 0.969015f;	val_dir[7475*3 + 2] = 0.247004f;
+ 	val_dir[7476*3 + 0] = 0.018811f;	val_dir[7476*3 + 1] = 0.978177f;	val_dir[7476*3 + 2] = 0.206922f;
+ 	val_dir[7477*3 + 0] = 0.037178f;	val_dir[7477*3 + 1] = 0.985205f;	val_dir[7477*3 + 2] = 0.167299f;
+ 	val_dir[7478*3 + 0] = 0.055011f;	val_dir[7478*3 + 1] = 0.990201f;	val_dir[7478*3 + 2] = 0.128359f;
+ 	val_dir[7479*3 + 0] = 0.072239f;	val_dir[7479*3 + 1] = 0.993291f;	val_dir[7479*3 + 2] = 0.090299f;
+ 	val_dir[7480*3 + 0] = 0.088806f;	val_dir[7480*3 + 1] = 0.994623f;	val_dir[7480*3 + 2] = 0.053283f;
+ 	val_dir[7481*3 + 0] = 0.104669f;	val_dir[7481*3 + 1] = 0.994354f;	val_dir[7481*3 + 2] = 0.017445f;
+ 	val_dir[7482*3 + 0] = -0.994692f;	val_dir[7482*3 + 1] = -0.102899f;	val_dir[7482*3 + 2] = 0.0f;
+ 	val_dir[7483*3 + 0] = -0.995567f;	val_dir[7483*3 + 1] = -0.087330f;	val_dir[7483*3 + 2] = 0.034932f;
+ 	val_dir[7484*3 + 0] = -0.994937f;	val_dir[7484*3 + 1] = -0.071067f;	val_dir[7484*3 + 2] = 0.071067f;
+ 	val_dir[7485*3 + 0] = -0.992644f;	val_dir[7485*3 + 1] = -0.054144f;	val_dir[7485*3 + 2] = 0.108288f;
+ 	val_dir[7486*3 + 0] = -0.988540f;	val_dir[7486*3 + 1] = -0.036613f;	val_dir[7486*3 + 2] = 0.146450f;
+ 	val_dir[7487*3 + 0] = -0.982493f;	val_dir[7487*3 + 1] = -0.018538f;	val_dir[7487*3 + 2] = 0.185376f;
+ 	val_dir[7488*3 + 0] = -0.974391f;	val_dir[7488*3 + 1] = 0.0f;	val_dir[7488*3 + 2] = 0.224860f;
+ 	val_dir[7489*3 + 0] = -0.973240f;	val_dir[7489*3 + 1] = 0.019083f;	val_dir[7489*3 + 2] = 0.228998f;
+ 	val_dir[7490*3 + 0] = -0.971653f;	val_dir[7490*3 + 1] = 0.038866f;	val_dir[7490*3 + 2] = 0.233197f;
+ 	val_dir[7491*3 + 0] = -0.969584f;	val_dir[7491*3 + 1] = 0.059362f;	val_dir[7491*3 + 2] = 0.237449f;
+ 	val_dir[7492*3 + 0] = -0.966988f;	val_dir[7492*3 + 1] = 0.080582f;	val_dir[7492*3 + 2] = 0.241747f;
+ 	val_dir[7493*3 + 0] = -0.963811f;	val_dir[7493*3 + 1] = 0.102533f;	val_dir[7493*3 + 2] = 0.246079f;
+ 	val_dir[7494*3 + 0] = -0.960001f;	val_dir[7494*3 + 1] = 0.125218f;	val_dir[7494*3 + 2] = 0.250435f;
+ 	val_dir[7495*3 + 0] = -0.955502f;	val_dir[7495*3 + 1] = 0.148634f;	val_dir[7495*3 + 2] = 0.254801f;
+ 	val_dir[7496*3 + 0] = -0.950255f;	val_dir[7496*3 + 1] = 0.172774f;	val_dir[7496*3 + 2] = 0.259161f;
+ 	val_dir[7497*3 + 0] = -0.94420f;	val_dir[7497*3 + 1] = 0.197623f;	val_dir[7497*3 + 2] = 0.263498f;
+ 	val_dir[7498*3 + 0] = -0.937276f;	val_dir[7498*3 + 1] = 0.223161f;	val_dir[7498*3 + 2] = 0.267793f;
+ 	val_dir[7499*3 + 0] = -0.929421f;	val_dir[7499*3 + 1] = 0.249357f;	val_dir[7499*3 + 2] = 0.272026f;
+ 	val_dir[7500*3 + 0] = -0.920575f;	val_dir[7500*3 + 1] = 0.276172f;	val_dir[7500*3 + 2] = 0.276172f;
+ 	val_dir[7501*3 + 0] = -0.910678f;	val_dir[7501*3 + 1] = 0.303559f;	val_dir[7501*3 + 2] = 0.280209f;
+ 	val_dir[7502*3 + 0] = -0.899676f;	val_dir[7502*3 + 1] = 0.331460f;	val_dir[7502*3 + 2] = 0.284108f;
+ 	val_dir[7503*3 + 0] = -0.887517f;	val_dir[7503*3 + 1] = 0.359804f;	val_dir[7503*3 + 2] = 0.287843f;
+ 	val_dir[7504*3 + 0] = -0.874157f;	val_dir[7504*3 + 1] = 0.388514f;	val_dir[7504*3 + 2] = 0.291386f;
+ 	val_dir[7505*3 + 0] = -0.859559f;	val_dir[7505*3 + 1] = 0.41750f;	val_dir[7505*3 + 2] = 0.294706f;
+ 	val_dir[7506*3 + 0] = -0.843696f;	val_dir[7506*3 + 1] = 0.446662f;	val_dir[7506*3 + 2] = 0.297775f;
+ 	val_dir[7507*3 + 0] = -0.826551f;	val_dir[7507*3 + 1] = 0.475893f;	val_dir[7507*3 + 2] = 0.300564f;
+ 	val_dir[7508*3 + 0] = -0.808122f;	val_dir[7508*3 + 1] = 0.505076f;	val_dir[7508*3 + 2] = 0.303046f;
+ 	val_dir[7509*3 + 0] = -0.788419f;	val_dir[7509*3 + 1] = 0.534090f;	val_dir[7509*3 + 2] = 0.305194f;
+ 	val_dir[7510*3 + 0] = -0.767467f;	val_dir[7510*3 + 1] = 0.562809f;	val_dir[7510*3 + 2] = 0.306987f;
+ 	val_dir[7511*3 + 0] = -0.745307f;	val_dir[7511*3 + 1] = 0.591105f;	val_dir[7511*3 + 2] = 0.308403f;
+ 	val_dir[7512*3 + 0] = -0.721995f;	val_dir[7512*3 + 1] = 0.618853f;	val_dir[7512*3 + 2] = 0.309426f;
+ 	val_dir[7513*3 + 0] = -0.697602f;	val_dir[7513*3 + 1] = 0.645928f;	val_dir[7513*3 + 2] = 0.310045f;
+ 	val_dir[7514*3 + 0] = -0.672214f;	val_dir[7514*3 + 1] = 0.672214f;	val_dir[7514*3 + 2] = 0.310253f;
+ 	val_dir[7515*3 + 0] = -0.645928f;	val_dir[7515*3 + 1] = 0.697602f;	val_dir[7515*3 + 2] = 0.310045f;
+ 	val_dir[7516*3 + 0] = -0.618853f;	val_dir[7516*3 + 1] = 0.721995f;	val_dir[7516*3 + 2] = 0.309426f;
+ 	val_dir[7517*3 + 0] = -0.591105f;	val_dir[7517*3 + 1] = 0.745307f;	val_dir[7517*3 + 2] = 0.308403f;
+ 	val_dir[7518*3 + 0] = -0.562809f;	val_dir[7518*3 + 1] = 0.767467f;	val_dir[7518*3 + 2] = 0.306987f;
+ 	val_dir[7519*3 + 0] = -0.534090f;	val_dir[7519*3 + 1] = 0.788419f;	val_dir[7519*3 + 2] = 0.305194f;
+ 	val_dir[7520*3 + 0] = -0.505076f;	val_dir[7520*3 + 1] = 0.808122f;	val_dir[7520*3 + 2] = 0.303046f;
+ 	val_dir[7521*3 + 0] = -0.475893f;	val_dir[7521*3 + 1] = 0.826551f;	val_dir[7521*3 + 2] = 0.300564f;
+ 	val_dir[7522*3 + 0] = -0.446662f;	val_dir[7522*3 + 1] = 0.843696f;	val_dir[7522*3 + 2] = 0.297775f;
+ 	val_dir[7523*3 + 0] = -0.41750f;	val_dir[7523*3 + 1] = 0.859559f;	val_dir[7523*3 + 2] = 0.294706f;
+ 	val_dir[7524*3 + 0] = -0.388514f;	val_dir[7524*3 + 1] = 0.874157f;	val_dir[7524*3 + 2] = 0.291386f;
+ 	val_dir[7525*3 + 0] = -0.359804f;	val_dir[7525*3 + 1] = 0.887517f;	val_dir[7525*3 + 2] = 0.287843f;
+ 	val_dir[7526*3 + 0] = -0.331460f;	val_dir[7526*3 + 1] = 0.899676f;	val_dir[7526*3 + 2] = 0.284108f;
+ 	val_dir[7527*3 + 0] = -0.303559f;	val_dir[7527*3 + 1] = 0.910678f;	val_dir[7527*3 + 2] = 0.280209f;
+ 	val_dir[7528*3 + 0] = -0.276172f;	val_dir[7528*3 + 1] = 0.920575f;	val_dir[7528*3 + 2] = 0.276172f;
+ 	val_dir[7529*3 + 0] = -0.249357f;	val_dir[7529*3 + 1] = 0.929421f;	val_dir[7529*3 + 2] = 0.272026f;
+ 	val_dir[7530*3 + 0] = -0.223161f;	val_dir[7530*3 + 1] = 0.937276f;	val_dir[7530*3 + 2] = 0.267793f;
+ 	val_dir[7531*3 + 0] = -0.197623f;	val_dir[7531*3 + 1] = 0.94420f;	val_dir[7531*3 + 2] = 0.263498f;
+ 	val_dir[7532*3 + 0] = -0.172774f;	val_dir[7532*3 + 1] = 0.950255f;	val_dir[7532*3 + 2] = 0.259161f;
+ 	val_dir[7533*3 + 0] = -0.148634f;	val_dir[7533*3 + 1] = 0.955502f;	val_dir[7533*3 + 2] = 0.254801f;
+ 	val_dir[7534*3 + 0] = -0.125218f;	val_dir[7534*3 + 1] = 0.960001f;	val_dir[7534*3 + 2] = 0.250435f;
+ 	val_dir[7535*3 + 0] = -0.102533f;	val_dir[7535*3 + 1] = 0.963811f;	val_dir[7535*3 + 2] = 0.246079f;
+ 	val_dir[7536*3 + 0] = -0.080582f;	val_dir[7536*3 + 1] = 0.966988f;	val_dir[7536*3 + 2] = 0.241747f;
+ 	val_dir[7537*3 + 0] = -0.059362f;	val_dir[7537*3 + 1] = 0.969584f;	val_dir[7537*3 + 2] = 0.237449f;
+ 	val_dir[7538*3 + 0] = -0.038866f;	val_dir[7538*3 + 1] = 0.971653f;	val_dir[7538*3 + 2] = 0.233197f;
+ 	val_dir[7539*3 + 0] = -0.019083f;	val_dir[7539*3 + 1] = 0.973240f;	val_dir[7539*3 + 2] = 0.228998f;
+ 	val_dir[7540*3 + 0] = 0.0f;	val_dir[7540*3 + 1] = 0.974391f;	val_dir[7540*3 + 2] = 0.224860f;
+ 	val_dir[7541*3 + 0] = 0.018538f;	val_dir[7541*3 + 1] = 0.982493f;	val_dir[7541*3 + 2] = 0.185376f;
+ 	val_dir[7542*3 + 0] = 0.036613f;	val_dir[7542*3 + 1] = 0.988540f;	val_dir[7542*3 + 2] = 0.146450f;
+ 	val_dir[7543*3 + 0] = 0.054144f;	val_dir[7543*3 + 1] = 0.992644f;	val_dir[7543*3 + 2] = 0.108288f;
+ 	val_dir[7544*3 + 0] = 0.071067f;	val_dir[7544*3 + 1] = 0.994937f;	val_dir[7544*3 + 2] = 0.071067f;
+ 	val_dir[7545*3 + 0] = 0.087330f;	val_dir[7545*3 + 1] = 0.995567f;	val_dir[7545*3 + 2] = 0.034932f;
+ 	val_dir[7546*3 + 0] = 0.102899f;	val_dir[7546*3 + 1] = 0.994692f;	val_dir[7546*3 + 2] = 0.0f;
+ 	val_dir[7547*3 + 0] = -0.996158f;	val_dir[7547*3 + 1] = -0.085876f;	val_dir[7547*3 + 2] = 0.017175f;
+ 	val_dir[7548*3 + 0] = -0.996175f;	val_dir[7548*3 + 1] = -0.069907f;	val_dir[7548*3 + 2] = 0.052430f;
+ 	val_dir[7549*3 + 0] = -0.994623f;	val_dir[7549*3 + 1] = -0.053283f;	val_dir[7549*3 + 2] = 0.088806f;
+ 	val_dir[7550*3 + 0] = -0.991353f;	val_dir[7550*3 + 1] = -0.036049f;	val_dir[7550*3 + 2] = 0.126172f;
+ 	val_dir[7551*3 + 0] = -0.986229f;	val_dir[7551*3 + 1] = -0.018264f;	val_dir[7551*3 + 2] = 0.164372f;
+ 	val_dir[7552*3 + 0] = -0.979134f;	val_dir[7552*3 + 1] = 0.0f;	val_dir[7552*3 + 2] = 0.203216f;
+ 	val_dir[7553*3 + 0] = -0.978177f;	val_dir[7553*3 + 1] = 0.018811f;	val_dir[7553*3 + 2] = 0.206922f;
+ 	val_dir[7554*3 + 0] = -0.976804f;	val_dir[7554*3 + 1] = 0.038306f;	val_dir[7554*3 + 2] = 0.210683f;
+ 	val_dir[7555*3 + 0] = -0.974972f;	val_dir[7555*3 + 1] = 0.058498f;	val_dir[7555*3 + 2] = 0.214494f;
+ 	val_dir[7556*3 + 0] = -0.972636f;	val_dir[7556*3 + 1] = 0.079399f;	val_dir[7556*3 + 2] = 0.218347f;
+ 	val_dir[7557*3 + 0] = -0.969746f;	val_dir[7557*3 + 1] = 0.101015f;	val_dir[7557*3 + 2] = 0.222234f;
+ 	val_dir[7558*3 + 0] = -0.966252f;	val_dir[7558*3 + 1] = 0.123351f;	val_dir[7558*3 + 2] = 0.226144f;
+ 	val_dir[7559*3 + 0] = -0.962099f;	val_dir[7559*3 + 1] = 0.146406f;	val_dir[7559*3 + 2] = 0.230067f;
+ 	val_dir[7560*3 + 0] = -0.957230f;	val_dir[7560*3 + 1] = 0.170174f;	val_dir[7560*3 + 2] = 0.233990f;
+ 	val_dir[7561*3 + 0] = -0.951588f;	val_dir[7561*3 + 1] = 0.194643f;	val_dir[7561*3 + 2] = 0.237897f;
+ 	val_dir[7562*3 + 0] = -0.945112f;	val_dir[7562*3 + 1] = 0.219793f;	val_dir[7562*3 + 2] = 0.241773f;
+ 	val_dir[7563*3 + 0] = -0.937743f;	val_dir[7563*3 + 1] = 0.245599f;	val_dir[7563*3 + 2] = 0.245599f;
+ 	val_dir[7564*3 + 0] = -0.929421f;	val_dir[7564*3 + 1] = 0.272026f;	val_dir[7564*3 + 2] = 0.249357f;
+ 	val_dir[7565*3 + 0] = -0.920087f;	val_dir[7565*3 + 1] = 0.299028f;	val_dir[7565*3 + 2] = 0.253024f;
+ 	val_dir[7566*3 + 0] = -0.909687f;	val_dir[7566*3 + 1] = 0.326554f;	val_dir[7566*3 + 2] = 0.256578f;
+ 	val_dir[7567*3 + 0] = -0.898167f;	val_dir[7567*3 + 1] = 0.354540f;	val_dir[7567*3 + 2] = 0.259996f;
+ 	val_dir[7568*3 + 0] = -0.885482f;	val_dir[7568*3 + 1] = 0.382911f;	val_dir[7568*3 + 2] = 0.263251f;
+ 	val_dir[7569*3 + 0] = -0.871592f;	val_dir[7569*3 + 1] = 0.411585f;	val_dir[7569*3 + 2] = 0.266320f;
+ 	val_dir[7570*3 + 0] = -0.856465f;	val_dir[7570*3 + 1] = 0.440468f;	val_dir[7570*3 + 2] = 0.269175f;
+ 	val_dir[7571*3 + 0] = -0.840083f;	val_dir[7571*3 + 1] = 0.469458f;	val_dir[7571*3 + 2] = 0.271791f;
+ 	val_dir[7572*3 + 0] = -0.822434f;	val_dir[7572*3 + 1] = 0.498445f;	val_dir[7572*3 + 2] = 0.274145f;
+ 	val_dir[7573*3 + 0] = -0.803523f;	val_dir[7573*3 + 1] = 0.527312f;	val_dir[7573*3 + 2] = 0.276211f;
+ 	val_dir[7574*3 + 0] = -0.783368f;	val_dir[7574*3 + 1] = 0.555939f;	val_dir[7574*3 + 2] = 0.277969f;
+ 	val_dir[7575*3 + 0] = -0.762001f;	val_dir[7575*3 + 1] = 0.584201f;	val_dir[7575*3 + 2] = 0.27940f;
+ 	val_dir[7576*3 + 0] = -0.739469f;	val_dir[7576*3 + 1] = 0.611974f;	val_dir[7576*3 + 2] = 0.280488f;
+ 	val_dir[7577*3 + 0] = -0.715834f;	val_dir[7577*3 + 1] = 0.639138f;	val_dir[7577*3 + 2] = 0.281220f;
+ 	val_dir[7578*3 + 0] = -0.691173f;	val_dir[7578*3 + 1] = 0.665574f;	val_dir[7578*3 + 2] = 0.281589f;
+ 	val_dir[7579*3 + 0] = -0.665574f;	val_dir[7579*3 + 1] = 0.691173f;	val_dir[7579*3 + 2] = 0.281589f;
+ 	val_dir[7580*3 + 0] = -0.639138f;	val_dir[7580*3 + 1] = 0.715834f;	val_dir[7580*3 + 2] = 0.281220f;
+ 	val_dir[7581*3 + 0] = -0.611974f;	val_dir[7581*3 + 1] = 0.739469f;	val_dir[7581*3 + 2] = 0.280488f;
+ 	val_dir[7582*3 + 0] = -0.584201f;	val_dir[7582*3 + 1] = 0.762001f;	val_dir[7582*3 + 2] = 0.27940f;
+ 	val_dir[7583*3 + 0] = -0.555939f;	val_dir[7583*3 + 1] = 0.783368f;	val_dir[7583*3 + 2] = 0.277969f;
+ 	val_dir[7584*3 + 0] = -0.527312f;	val_dir[7584*3 + 1] = 0.803523f;	val_dir[7584*3 + 2] = 0.276211f;
+ 	val_dir[7585*3 + 0] = -0.498445f;	val_dir[7585*3 + 1] = 0.822434f;	val_dir[7585*3 + 2] = 0.274145f;
+ 	val_dir[7586*3 + 0] = -0.469458f;	val_dir[7586*3 + 1] = 0.840083f;	val_dir[7586*3 + 2] = 0.271791f;
+ 	val_dir[7587*3 + 0] = -0.440468f;	val_dir[7587*3 + 1] = 0.856465f;	val_dir[7587*3 + 2] = 0.269175f;
+ 	val_dir[7588*3 + 0] = -0.411585f;	val_dir[7588*3 + 1] = 0.871592f;	val_dir[7588*3 + 2] = 0.266320f;
+ 	val_dir[7589*3 + 0] = -0.382911f;	val_dir[7589*3 + 1] = 0.885482f;	val_dir[7589*3 + 2] = 0.263251f;
+ 	val_dir[7590*3 + 0] = -0.354540f;	val_dir[7590*3 + 1] = 0.898167f;	val_dir[7590*3 + 2] = 0.259996f;
+ 	val_dir[7591*3 + 0] = -0.326554f;	val_dir[7591*3 + 1] = 0.909687f;	val_dir[7591*3 + 2] = 0.256578f;
+ 	val_dir[7592*3 + 0] = -0.299028f;	val_dir[7592*3 + 1] = 0.920087f;	val_dir[7592*3 + 2] = 0.253024f;
+ 	val_dir[7593*3 + 0] = -0.272026f;	val_dir[7593*3 + 1] = 0.929421f;	val_dir[7593*3 + 2] = 0.249357f;
+ 	val_dir[7594*3 + 0] = -0.245599f;	val_dir[7594*3 + 1] = 0.937743f;	val_dir[7594*3 + 2] = 0.245599f;
+ 	val_dir[7595*3 + 0] = -0.219793f;	val_dir[7595*3 + 1] = 0.945112f;	val_dir[7595*3 + 2] = 0.241773f;
+ 	val_dir[7596*3 + 0] = -0.194643f;	val_dir[7596*3 + 1] = 0.951588f;	val_dir[7596*3 + 2] = 0.237897f;
+ 	val_dir[7597*3 + 0] = -0.170174f;	val_dir[7597*3 + 1] = 0.957230f;	val_dir[7597*3 + 2] = 0.233990f;
+ 	val_dir[7598*3 + 0] = -0.146406f;	val_dir[7598*3 + 1] = 0.962099f;	val_dir[7598*3 + 2] = 0.230067f;
+ 	val_dir[7599*3 + 0] = -0.123351f;	val_dir[7599*3 + 1] = 0.966252f;	val_dir[7599*3 + 2] = 0.226144f;
+ 	val_dir[7600*3 + 0] = -0.101015f;	val_dir[7600*3 + 1] = 0.969746f;	val_dir[7600*3 + 2] = 0.222234f;
+ 	val_dir[7601*3 + 0] = -0.079399f;	val_dir[7601*3 + 1] = 0.972636f;	val_dir[7601*3 + 2] = 0.218347f;
+ 	val_dir[7602*3 + 0] = -0.058498f;	val_dir[7602*3 + 1] = 0.974972f;	val_dir[7602*3 + 2] = 0.214494f;
+ 	val_dir[7603*3 + 0] = -0.038306f;	val_dir[7603*3 + 1] = 0.976804f;	val_dir[7603*3 + 2] = 0.210683f;
+ 	val_dir[7604*3 + 0] = -0.018811f;	val_dir[7604*3 + 1] = 0.978177f;	val_dir[7604*3 + 2] = 0.206922f;
+ 	val_dir[7605*3 + 0] = 0.0f;	val_dir[7605*3 + 1] = 0.979134f;	val_dir[7605*3 + 2] = 0.203216f;
+ 	val_dir[7606*3 + 0] = 0.018264f;	val_dir[7606*3 + 1] = 0.986229f;	val_dir[7606*3 + 2] = 0.164372f;
+ 	val_dir[7607*3 + 0] = 0.036049f;	val_dir[7607*3 + 1] = 0.991353f;	val_dir[7607*3 + 2] = 0.126172f;
+ 	val_dir[7608*3 + 0] = 0.053283f;	val_dir[7608*3 + 1] = 0.994623f;	val_dir[7608*3 + 2] = 0.088806f;
+ 	val_dir[7609*3 + 0] = 0.069907f;	val_dir[7609*3 + 1] = 0.996175f;	val_dir[7609*3 + 2] = 0.052430f;
+ 	val_dir[7610*3 + 0] = 0.085876f;	val_dir[7610*3 + 1] = 0.996158f;	val_dir[7610*3 + 2] = 0.017175f;
+ 	val_dir[7611*3 + 0] = -0.996428f;	val_dir[7611*3 + 1] = -0.084443f;	val_dir[7611*3 + 2] = 0.0f;
+ 	val_dir[7612*3 + 0] = -0.997041f;	val_dir[7612*3 + 1] = -0.068761f;	val_dir[7612*3 + 2] = 0.034381f;
+ 	val_dir[7613*3 + 0] = -0.996175f;	val_dir[7613*3 + 1] = -0.052430f;	val_dir[7613*3 + 2] = 0.069907f;
+ 	val_dir[7614*3 + 0] = -0.993683f;	val_dir[7614*3 + 1] = -0.035489f;	val_dir[7614*3 + 2] = 0.106466f;
+ 	val_dir[7615*3 + 0] = -0.989426f;	val_dir[7615*3 + 1] = -0.017990f;	val_dir[7615*3 + 2] = 0.143917f;
+ 	val_dir[7616*3 + 0] = -0.983282f;	val_dir[7616*3 + 1] = 0.0f;	val_dir[7616*3 + 2] = 0.182089f;
+ 	val_dir[7617*3 + 0] = -0.982493f;	val_dir[7617*3 + 1] = 0.018538f;	val_dir[7617*3 + 2] = 0.185376f;
+ 	val_dir[7618*3 + 0] = -0.981307f;	val_dir[7618*3 + 1] = 0.037743f;	val_dir[7618*3 + 2] = 0.188713f;
+ 	val_dir[7619*3 + 0] = -0.979683f;	val_dir[7619*3 + 1] = 0.057628f;	val_dir[7619*3 + 2] = 0.192095f;
+ 	val_dir[7620*3 + 0] = -0.977577f;	val_dir[7620*3 + 1] = 0.078206f;	val_dir[7620*3 + 2] = 0.195515f;
+ 	val_dir[7621*3 + 0] = -0.974943f;	val_dir[7621*3 + 1] = 0.099484f;	val_dir[7621*3 + 2] = 0.198968f;
+ 	val_dir[7622*3 + 0] = -0.971732f;	val_dir[7622*3 + 1] = 0.121466f;	val_dir[7622*3 + 2] = 0.202444f;
+ 	val_dir[7623*3 + 0] = -0.967890f;	val_dir[7623*3 + 1] = 0.144154f;	val_dir[7623*3 + 2] = 0.205934f;
+ 	val_dir[7624*3 + 0] = -0.963364f;	val_dir[7624*3 + 1] = 0.167542f;	val_dir[7624*3 + 2] = 0.209427f;
+ 	val_dir[7625*3 + 0] = -0.958098f;	val_dir[7625*3 + 1] = 0.191620f;	val_dir[7625*3 + 2] = 0.212911f;
+ 	val_dir[7626*3 + 0] = -0.952033f;	val_dir[7626*3 + 1] = 0.216371f;	val_dir[7626*3 + 2] = 0.216371f;
+ 	val_dir[7627*3 + 0] = -0.945112f;	val_dir[7627*3 + 1] = 0.241773f;	val_dir[7627*3 + 2] = 0.219793f;
+ 	val_dir[7628*3 + 0] = -0.937276f;	val_dir[7628*3 + 1] = 0.267793f;	val_dir[7628*3 + 2] = 0.223161f;
+ 	val_dir[7629*3 + 0] = -0.928467f;	val_dir[7629*3 + 1] = 0.294392f;	val_dir[7629*3 + 2] = 0.226455f;
+ 	val_dir[7630*3 + 0] = -0.918630f;	val_dir[7630*3 + 1] = 0.321521f;	val_dir[7630*3 + 2] = 0.229658f;
+ 	val_dir[7631*3 + 0] = -0.907713f;	val_dir[7631*3 + 1] = 0.349121f;	val_dir[7631*3 + 2] = 0.232747f;
+ 	val_dir[7632*3 + 0] = -0.895669f;	val_dir[7632*3 + 1] = 0.377124f;	val_dir[7632*3 + 2] = 0.235702f;
+ 	val_dir[7633*3 + 0] = -0.882454f;	val_dir[7633*3 + 1] = 0.405452f;	val_dir[7633*3 + 2] = 0.238501f;
+ 	val_dir[7634*3 + 0] = -0.868037f;	val_dir[7634*3 + 1] = 0.434019f;	val_dir[7634*3 + 2] = 0.241121f;
+ 	val_dir[7635*3 + 0] = -0.852392f;	val_dir[7635*3 + 1] = 0.462727f;	val_dir[7635*3 + 2] = 0.243541f;
+ 	val_dir[7636*3 + 0] = -0.835504f;	val_dir[7636*3 + 1] = 0.491473f;	val_dir[7636*3 + 2] = 0.245737f;
+ 	val_dir[7637*3 + 0] = -0.817373f;	val_dir[7637*3 + 1] = 0.520146f;	val_dir[7637*3 + 2] = 0.247689f;
+ 	val_dir[7638*3 + 0] = -0.798007f;	val_dir[7638*3 + 1] = 0.548630f;	val_dir[7638*3 + 2] = 0.249377f;
+ 	val_dir[7639*3 + 0] = -0.777433f;	val_dir[7639*3 + 1] = 0.576805f;	val_dir[7639*3 + 2] = 0.250785f;
+ 	val_dir[7640*3 + 0] = -0.755689f;	val_dir[7640*3 + 1] = 0.604551f;	val_dir[7640*3 + 2] = 0.251896f;
+ 	val_dir[7641*3 + 0] = -0.732828f;	val_dir[7641*3 + 1] = 0.631748f;	val_dir[7641*3 + 2] = 0.252699f;
+ 	val_dir[7642*3 + 0] = -0.708918f;	val_dir[7642*3 + 1] = 0.658281f;	val_dir[7642*3 + 2] = 0.253185f;
+ 	val_dir[7643*3 + 0] = -0.684038f;	val_dir[7643*3 + 1] = 0.684038f;	val_dir[7643*3 + 2] = 0.253347f;
+ 	val_dir[7644*3 + 0] = -0.658281f;	val_dir[7644*3 + 1] = 0.708918f;	val_dir[7644*3 + 2] = 0.253185f;
+ 	val_dir[7645*3 + 0] = -0.631748f;	val_dir[7645*3 + 1] = 0.732828f;	val_dir[7645*3 + 2] = 0.252699f;
+ 	val_dir[7646*3 + 0] = -0.604551f;	val_dir[7646*3 + 1] = 0.755689f;	val_dir[7646*3 + 2] = 0.251896f;
+ 	val_dir[7647*3 + 0] = -0.576805f;	val_dir[7647*3 + 1] = 0.777433f;	val_dir[7647*3 + 2] = 0.250785f;
+ 	val_dir[7648*3 + 0] = -0.548630f;	val_dir[7648*3 + 1] = 0.798007f;	val_dir[7648*3 + 2] = 0.249377f;
+ 	val_dir[7649*3 + 0] = -0.520146f;	val_dir[7649*3 + 1] = 0.817373f;	val_dir[7649*3 + 2] = 0.247689f;
+ 	val_dir[7650*3 + 0] = -0.491473f;	val_dir[7650*3 + 1] = 0.835504f;	val_dir[7650*3 + 2] = 0.245737f;
+ 	val_dir[7651*3 + 0] = -0.462727f;	val_dir[7651*3 + 1] = 0.852392f;	val_dir[7651*3 + 2] = 0.243541f;
+ 	val_dir[7652*3 + 0] = -0.434019f;	val_dir[7652*3 + 1] = 0.868037f;	val_dir[7652*3 + 2] = 0.241121f;
+ 	val_dir[7653*3 + 0] = -0.405452f;	val_dir[7653*3 + 1] = 0.882454f;	val_dir[7653*3 + 2] = 0.238501f;
+ 	val_dir[7654*3 + 0] = -0.377124f;	val_dir[7654*3 + 1] = 0.895669f;	val_dir[7654*3 + 2] = 0.235702f;
+ 	val_dir[7655*3 + 0] = -0.349121f;	val_dir[7655*3 + 1] = 0.907713f;	val_dir[7655*3 + 2] = 0.232747f;
+ 	val_dir[7656*3 + 0] = -0.321521f;	val_dir[7656*3 + 1] = 0.918630f;	val_dir[7656*3 + 2] = 0.229658f;
+ 	val_dir[7657*3 + 0] = -0.294392f;	val_dir[7657*3 + 1] = 0.928467f;	val_dir[7657*3 + 2] = 0.226455f;
+ 	val_dir[7658*3 + 0] = -0.267793f;	val_dir[7658*3 + 1] = 0.937276f;	val_dir[7658*3 + 2] = 0.223161f;
+ 	val_dir[7659*3 + 0] = -0.241773f;	val_dir[7659*3 + 1] = 0.945112f;	val_dir[7659*3 + 2] = 0.219793f;
+ 	val_dir[7660*3 + 0] = -0.216371f;	val_dir[7660*3 + 1] = 0.952033f;	val_dir[7660*3 + 2] = 0.216371f;
+ 	val_dir[7661*3 + 0] = -0.191620f;	val_dir[7661*3 + 1] = 0.958098f;	val_dir[7661*3 + 2] = 0.212911f;
+ 	val_dir[7662*3 + 0] = -0.167542f;	val_dir[7662*3 + 1] = 0.963364f;	val_dir[7662*3 + 2] = 0.209427f;
+ 	val_dir[7663*3 + 0] = -0.144154f;	val_dir[7663*3 + 1] = 0.967890f;	val_dir[7663*3 + 2] = 0.205934f;
+ 	val_dir[7664*3 + 0] = -0.121466f;	val_dir[7664*3 + 1] = 0.971732f;	val_dir[7664*3 + 2] = 0.202444f;
+ 	val_dir[7665*3 + 0] = -0.099484f;	val_dir[7665*3 + 1] = 0.974943f;	val_dir[7665*3 + 2] = 0.198968f;
+ 	val_dir[7666*3 + 0] = -0.078206f;	val_dir[7666*3 + 1] = 0.977577f;	val_dir[7666*3 + 2] = 0.195515f;
+ 	val_dir[7667*3 + 0] = -0.057628f;	val_dir[7667*3 + 1] = 0.979683f;	val_dir[7667*3 + 2] = 0.192095f;
+ 	val_dir[7668*3 + 0] = -0.037743f;	val_dir[7668*3 + 1] = 0.981307f;	val_dir[7668*3 + 2] = 0.188713f;
+ 	val_dir[7669*3 + 0] = -0.018538f;	val_dir[7669*3 + 1] = 0.982493f;	val_dir[7669*3 + 2] = 0.185376f;
+ 	val_dir[7670*3 + 0] = 0.0f;	val_dir[7670*3 + 1] = 0.983282f;	val_dir[7670*3 + 2] = 0.182089f;
+ 	val_dir[7671*3 + 0] = 0.017990f;	val_dir[7671*3 + 1] = 0.989426f;	val_dir[7671*3 + 2] = 0.143917f;
+ 	val_dir[7672*3 + 0] = 0.035489f;	val_dir[7672*3 + 1] = 0.993683f;	val_dir[7672*3 + 2] = 0.106466f;
+ 	val_dir[7673*3 + 0] = 0.052430f;	val_dir[7673*3 + 1] = 0.996175f;	val_dir[7673*3 + 2] = 0.069907f;
+ 	val_dir[7674*3 + 0] = 0.068761f;	val_dir[7674*3 + 1] = 0.997041f;	val_dir[7674*3 + 2] = 0.034381f;
+ 	val_dir[7675*3 + 0] = 0.084443f;	val_dir[7675*3 + 1] = 0.996428f;	val_dir[7675*3 + 2] = 0.0f;
+ 	val_dir[7676*3 + 0] = -0.997567f;	val_dir[7676*3 + 1] = -0.067632f;	val_dir[7676*3 + 2] = 0.016908f;
+ 	val_dir[7677*3 + 0] = -0.997335f;	val_dir[7677*3 + 1] = -0.051586f;	val_dir[7677*3 + 2] = 0.051586f;
+ 	val_dir[7678*3 + 0] = -0.995567f;	val_dir[7678*3 + 1] = -0.034932f;	val_dir[7678*3 + 2] = 0.087330f;
+ 	val_dir[7679*3 + 0] = -0.992122f;	val_dir[7679*3 + 1] = -0.017716f;	val_dir[7679*3 + 2] = 0.124015f;
+ 	val_dir[7680*3 + 0] = -0.986875f;	val_dir[7680*3 + 1] = 0.0f;	val_dir[7680*3 + 2] = 0.161489f;
+ 	val_dir[7681*3 + 0] = -0.986229f;	val_dir[7681*3 + 1] = 0.018264f;	val_dir[7681*3 + 2] = 0.164372f;
+ 	val_dir[7682*3 + 0] = -0.985205f;	val_dir[7682*3 + 1] = 0.037178f;	val_dir[7682*3 + 2] = 0.167299f;
+ 	val_dir[7683*3 + 0] = -0.983762f;	val_dir[7683*3 + 1] = 0.056756f;	val_dir[7683*3 + 2] = 0.170267f;
+ 	val_dir[7684*3 + 0] = -0.981859f;	val_dir[7684*3 + 1] = 0.077009f;	val_dir[7684*3 + 2] = 0.173269f;
+ 	val_dir[7685*3 + 0] = -0.979451f;	val_dir[7685*3 + 1] = 0.097945f;	val_dir[7685*3 + 2] = 0.176301f;
+ 	val_dir[7686*3 + 0] = -0.976491f;	val_dir[7686*3 + 1] = 0.119570f;	val_dir[7686*3 + 2] = 0.179355f;
+ 	val_dir[7687*3 + 0] = -0.972929f;	val_dir[7687*3 + 1] = 0.141885f;	val_dir[7687*3 + 2] = 0.182424f;
+ 	val_dir[7688*3 + 0] = -0.968712f;	val_dir[7688*3 + 1] = 0.164887f;	val_dir[7688*3 + 2] = 0.185498f;
+ 	val_dir[7689*3 + 0] = -0.963787f;	val_dir[7689*3 + 1] = 0.188567f;	val_dir[7689*3 + 2] = 0.188567f;
+ 	val_dir[7690*3 + 0] = -0.958098f;	val_dir[7690*3 + 1] = 0.212911f;	val_dir[7690*3 + 2] = 0.191620f;
+ 	val_dir[7691*3 + 0] = -0.951588f;	val_dir[7691*3 + 1] = 0.237897f;	val_dir[7691*3 + 2] = 0.194643f;
+ 	val_dir[7692*3 + 0] = -0.94420f;	val_dir[7692*3 + 1] = 0.263498f;	val_dir[7692*3 + 2] = 0.197623f;
+ 	val_dir[7693*3 + 0] = -0.935879f;	val_dir[7693*3 + 1] = 0.289677f;	val_dir[7693*3 + 2] = 0.200545f;
+ 	val_dir[7694*3 + 0] = -0.926568f;	val_dir[7694*3 + 1] = 0.316389f;	val_dir[7694*3 + 2] = 0.203393f;
+ 	val_dir[7695*3 + 0] = -0.916217f;	val_dir[7695*3 + 1] = 0.343582f;	val_dir[7695*3 + 2] = 0.206149f;
+ 	val_dir[7696*3 + 0] = -0.904777f;	val_dir[7696*3 + 1] = 0.371191f;	val_dir[7696*3 + 2] = 0.208795f;
+ 	val_dir[7697*3 + 0] = -0.892206f;	val_dir[7697*3 + 1] = 0.399145f;	val_dir[7697*3 + 2] = 0.211312f;
+ 	val_dir[7698*3 + 0] = -0.878466f;	val_dir[7698*3 + 1] = 0.427362f;	val_dir[7698*3 + 2] = 0.213681f;
+ 	val_dir[7699*3 + 0] = -0.863530f;	val_dir[7699*3 + 1] = 0.455752f;	val_dir[7699*3 + 2] = 0.215883f;
+ 	val_dir[7700*3 + 0] = -0.847381f;	val_dir[7700*3 + 1] = 0.484217f;	val_dir[7700*3 + 2] = 0.217898f;
+ 	val_dir[7701*3 + 0] = -0.830009f;	val_dir[7701*3 + 1] = 0.512653f;	val_dir[7701*3 + 2] = 0.219708f;
+ 	val_dir[7702*3 + 0] = -0.811421f;	val_dir[7702*3 + 1] = 0.540947f;	val_dir[7702*3 + 2] = 0.221297f;
+ 	val_dir[7703*3 + 0] = -0.791633f;	val_dir[7703*3 + 1] = 0.568986f;	val_dir[7703*3 + 2] = 0.222647f;
+ 	val_dir[7704*3 + 0] = -0.770677f;	val_dir[7704*3 + 1] = 0.596653f;	val_dir[7704*3 + 2] = 0.223745f;
+ 	val_dir[7705*3 + 0] = -0.748598f;	val_dir[7705*3 + 1] = 0.623831f;	val_dir[7705*3 + 2] = 0.224579f;
+ 	val_dir[7706*3 + 0] = -0.725454f;	val_dir[7706*3 + 1] = 0.650407f;	val_dir[7706*3 + 2] = 0.225141f;
+ 	val_dir[7707*3 + 0] = -0.701316f;	val_dir[7707*3 + 1] = 0.676269f;	val_dir[7707*3 + 2] = 0.225423f;
+ 	val_dir[7708*3 + 0] = -0.676269f;	val_dir[7708*3 + 1] = 0.701316f;	val_dir[7708*3 + 2] = 0.225423f;
+ 	val_dir[7709*3 + 0] = -0.650407f;	val_dir[7709*3 + 1] = 0.725454f;	val_dir[7709*3 + 2] = 0.225141f;
+ 	val_dir[7710*3 + 0] = -0.623831f;	val_dir[7710*3 + 1] = 0.748598f;	val_dir[7710*3 + 2] = 0.224579f;
+ 	val_dir[7711*3 + 0] = -0.596653f;	val_dir[7711*3 + 1] = 0.770677f;	val_dir[7711*3 + 2] = 0.223745f;
+ 	val_dir[7712*3 + 0] = -0.568986f;	val_dir[7712*3 + 1] = 0.791633f;	val_dir[7712*3 + 2] = 0.222647f;
+ 	val_dir[7713*3 + 0] = -0.540947f;	val_dir[7713*3 + 1] = 0.811421f;	val_dir[7713*3 + 2] = 0.221297f;
+ 	val_dir[7714*3 + 0] = -0.512653f;	val_dir[7714*3 + 1] = 0.830009f;	val_dir[7714*3 + 2] = 0.219708f;
+ 	val_dir[7715*3 + 0] = -0.484217f;	val_dir[7715*3 + 1] = 0.847381f;	val_dir[7715*3 + 2] = 0.217898f;
+ 	val_dir[7716*3 + 0] = -0.455752f;	val_dir[7716*3 + 1] = 0.863530f;	val_dir[7716*3 + 2] = 0.215883f;
+ 	val_dir[7717*3 + 0] = -0.427362f;	val_dir[7717*3 + 1] = 0.878466f;	val_dir[7717*3 + 2] = 0.213681f;
+ 	val_dir[7718*3 + 0] = -0.399145f;	val_dir[7718*3 + 1] = 0.892206f;	val_dir[7718*3 + 2] = 0.211312f;
+ 	val_dir[7719*3 + 0] = -0.371191f;	val_dir[7719*3 + 1] = 0.904777f;	val_dir[7719*3 + 2] = 0.208795f;
+ 	val_dir[7720*3 + 0] = -0.343582f;	val_dir[7720*3 + 1] = 0.916217f;	val_dir[7720*3 + 2] = 0.206149f;
+ 	val_dir[7721*3 + 0] = -0.316389f;	val_dir[7721*3 + 1] = 0.926568f;	val_dir[7721*3 + 2] = 0.203393f;
+ 	val_dir[7722*3 + 0] = -0.289677f;	val_dir[7722*3 + 1] = 0.935879f;	val_dir[7722*3 + 2] = 0.200545f;
+ 	val_dir[7723*3 + 0] = -0.263498f;	val_dir[7723*3 + 1] = 0.94420f;	val_dir[7723*3 + 2] = 0.197623f;
+ 	val_dir[7724*3 + 0] = -0.237897f;	val_dir[7724*3 + 1] = 0.951588f;	val_dir[7724*3 + 2] = 0.194643f;
+ 	val_dir[7725*3 + 0] = -0.212911f;	val_dir[7725*3 + 1] = 0.958098f;	val_dir[7725*3 + 2] = 0.191620f;
+ 	val_dir[7726*3 + 0] = -0.188567f;	val_dir[7726*3 + 1] = 0.963787f;	val_dir[7726*3 + 2] = 0.188567f;
+ 	val_dir[7727*3 + 0] = -0.164887f;	val_dir[7727*3 + 1] = 0.968712f;	val_dir[7727*3 + 2] = 0.185498f;
+ 	val_dir[7728*3 + 0] = -0.141885f;	val_dir[7728*3 + 1] = 0.972929f;	val_dir[7728*3 + 2] = 0.182424f;
+ 	val_dir[7729*3 + 0] = -0.119570f;	val_dir[7729*3 + 1] = 0.976491f;	val_dir[7729*3 + 2] = 0.179355f;
+ 	val_dir[7730*3 + 0] = -0.097945f;	val_dir[7730*3 + 1] = 0.979451f;	val_dir[7730*3 + 2] = 0.176301f;
+ 	val_dir[7731*3 + 0] = -0.077009f;	val_dir[7731*3 + 1] = 0.981859f;	val_dir[7731*3 + 2] = 0.173269f;
+ 	val_dir[7732*3 + 0] = -0.056756f;	val_dir[7732*3 + 1] = 0.983762f;	val_dir[7732*3 + 2] = 0.170267f;
+ 	val_dir[7733*3 + 0] = -0.037178f;	val_dir[7733*3 + 1] = 0.985205f;	val_dir[7733*3 + 2] = 0.167299f;
+ 	val_dir[7734*3 + 0] = -0.018264f;	val_dir[7734*3 + 1] = 0.986229f;	val_dir[7734*3 + 2] = 0.164372f;
+ 	val_dir[7735*3 + 0] = 0.0f;	val_dir[7735*3 + 1] = 0.986875f;	val_dir[7735*3 + 2] = 0.161489f;
+ 	val_dir[7736*3 + 0] = 0.017716f;	val_dir[7736*3 + 1] = 0.992122f;	val_dir[7736*3 + 2] = 0.124015f;
+ 	val_dir[7737*3 + 0] = 0.034932f;	val_dir[7737*3 + 1] = 0.995567f;	val_dir[7737*3 + 2] = 0.087330f;
+ 	val_dir[7738*3 + 0] = 0.051586f;	val_dir[7738*3 + 1] = 0.997335f;	val_dir[7738*3 + 2] = 0.051586f;
+ 	val_dir[7739*3 + 0] = 0.067632f;	val_dir[7739*3 + 1] = 0.997567f;	val_dir[7739*3 + 2] = 0.016908f;
+ 	val_dir[7740*3 + 0] = -0.997785f;	val_dir[7740*3 + 1] = -0.066519f;	val_dir[7740*3 + 2] = 0.0f;
+ 	val_dir[7741*3 + 0] = -0.998138f;	val_dir[7741*3 + 1] = -0.050753f;	val_dir[7741*3 + 2] = 0.033835f;
+ 	val_dir[7742*3 + 0] = -0.997041f;	val_dir[7742*3 + 1] = -0.034381f;	val_dir[7742*3 + 2] = 0.068761f;
+ 	val_dir[7743*3 + 0] = -0.994354f;	val_dir[7743*3 + 1] = -0.017445f;	val_dir[7743*3 + 2] = 0.104669f;
+ 	val_dir[7744*3 + 0] = -0.989949f;	val_dir[7744*3 + 1] = 0.0f;	val_dir[7744*3 + 2] = 0.141421f;
+ 	val_dir[7745*3 + 0] = -0.989426f;	val_dir[7745*3 + 1] = 0.017990f;	val_dir[7745*3 + 2] = 0.143917f;
+ 	val_dir[7746*3 + 0] = -0.988540f;	val_dir[7746*3 + 1] = 0.036613f;	val_dir[7746*3 + 2] = 0.146450f;
+ 	val_dir[7747*3 + 0] = -0.987254f;	val_dir[7747*3 + 1] = 0.055882f;	val_dir[7747*3 + 2] = 0.149019f;
+ 	val_dir[7748*3 + 0] = -0.985527f;	val_dir[7748*3 + 1] = 0.075810f;	val_dir[7748*3 + 2] = 0.151620f;
+ 	val_dir[7749*3 + 0] = -0.983318f;	val_dir[7749*3 + 1] = 0.096404f;	val_dir[7749*3 + 2] = 0.154246f;
+ 	val_dir[7750*3 + 0] = -0.980581f;	val_dir[7750*3 + 1] = 0.117670f;	val_dir[7750*3 + 2] = 0.156893f;
+ 	val_dir[7751*3 + 0] = -0.977267f;	val_dir[7751*3 + 1] = 0.139610f;	val_dir[7751*3 + 2] = 0.159554f;
+ 	val_dir[7752*3 + 0] = -0.973329f;	val_dir[7752*3 + 1] = 0.162221f;	val_dir[7752*3 + 2] = 0.162221f;
+ 	val_dir[7753*3 + 0] = -0.968712f;	val_dir[7753*3 + 1] = 0.185498f;	val_dir[7753*3 + 2] = 0.164887f;
+ 	val_dir[7754*3 + 0] = -0.963364f;	val_dir[7754*3 + 1] = 0.209427f;	val_dir[7754*3 + 2] = 0.167542f;
+ 	val_dir[7755*3 + 0] = -0.957230f;	val_dir[7755*3 + 1] = 0.233990f;	val_dir[7755*3 + 2] = 0.170174f;
+ 	val_dir[7756*3 + 0] = -0.950255f;	val_dir[7756*3 + 1] = 0.259161f;	val_dir[7756*3 + 2] = 0.172774f;
+ 	val_dir[7757*3 + 0] = -0.942384f;	val_dir[7757*3 + 1] = 0.284907f;	val_dir[7757*3 + 2] = 0.175327f;
+ 	val_dir[7758*3 + 0] = -0.933564f;	val_dir[7758*3 + 1] = 0.311188f;	val_dir[7758*3 + 2] = 0.177822f;
+ 	val_dir[7759*3 + 0] = -0.923742f;	val_dir[7759*3 + 1] = 0.337954f;	val_dir[7759*3 + 2] = 0.180242f;
+ 	val_dir[7760*3 + 0] = -0.912871f;	val_dir[7760*3 + 1] = 0.365148f;	val_dir[7760*3 + 2] = 0.182574f;
+ 	val_dir[7761*3 + 0] = -0.900907f;	val_dir[7761*3 + 1] = 0.392703f;	val_dir[7761*3 + 2] = 0.184801f;
+ 	val_dir[7762*3 + 0] = -0.887812f;	val_dir[7762*3 + 1] = 0.420542f;	val_dir[7762*3 + 2] = 0.186908f;
+ 	val_dir[7763*3 + 0] = -0.873555f;	val_dir[7763*3 + 1] = 0.448583f;	val_dir[7763*3 + 2] = 0.188877f;
+ 	val_dir[7764*3 + 0] = -0.858116f;	val_dir[7764*3 + 1] = 0.476731f;	val_dir[7764*3 + 2] = 0.190693f;
+ 	val_dir[7765*3 + 0] = -0.841482f;	val_dir[7765*3 + 1] = 0.504889f;	val_dir[7765*3 + 2] = 0.192339f;
+ 	val_dir[7766*3 + 0] = -0.823653f;	val_dir[7766*3 + 1] = 0.532952f;	val_dir[7766*3 + 2] = 0.193801f;
+ 	val_dir[7767*3 + 0] = -0.804639f;	val_dir[7767*3 + 1] = 0.560809f;	val_dir[7767*3 + 2] = 0.195064f;
+ 	val_dir[7768*3 + 0] = -0.784465f;	val_dir[7768*3 + 1] = 0.588348f;	val_dir[7768*3 + 2] = 0.196116f;
+ 	val_dir[7769*3 + 0] = -0.763167f;	val_dir[7769*3 + 1] = 0.615457f;	val_dir[7769*3 + 2] = 0.196946f;
+ 	val_dir[7770*3 + 0] = -0.740797f;	val_dir[7770*3 + 1] = 0.642024f;	val_dir[7770*3 + 2] = 0.197546f;
+ 	val_dir[7771*3 + 0] = -0.717418f;	val_dir[7771*3 + 1] = 0.667940f;	val_dir[7771*3 + 2] = 0.197908f;
+ 	val_dir[7772*3 + 0] = -0.693103f;	val_dir[7772*3 + 1] = 0.693103f;	val_dir[7772*3 + 2] = 0.198030f;
+ 	val_dir[7773*3 + 0] = -0.667940f;	val_dir[7773*3 + 1] = 0.717418f;	val_dir[7773*3 + 2] = 0.197908f;
+ 	val_dir[7774*3 + 0] = -0.642024f;	val_dir[7774*3 + 1] = 0.740797f;	val_dir[7774*3 + 2] = 0.197546f;
+ 	val_dir[7775*3 + 0] = -0.615457f;	val_dir[7775*3 + 1] = 0.763167f;	val_dir[7775*3 + 2] = 0.196946f;
+ 	val_dir[7776*3 + 0] = -0.588348f;	val_dir[7776*3 + 1] = 0.784465f;	val_dir[7776*3 + 2] = 0.196116f;
+ 	val_dir[7777*3 + 0] = -0.560809f;	val_dir[7777*3 + 1] = 0.804639f;	val_dir[7777*3 + 2] = 0.195064f;
+ 	val_dir[7778*3 + 0] = -0.532952f;	val_dir[7778*3 + 1] = 0.823653f;	val_dir[7778*3 + 2] = 0.193801f;
+ 	val_dir[7779*3 + 0] = -0.504889f;	val_dir[7779*3 + 1] = 0.841482f;	val_dir[7779*3 + 2] = 0.192339f;
+ 	val_dir[7780*3 + 0] = -0.476731f;	val_dir[7780*3 + 1] = 0.858116f;	val_dir[7780*3 + 2] = 0.190693f;
+ 	val_dir[7781*3 + 0] = -0.448583f;	val_dir[7781*3 + 1] = 0.873555f;	val_dir[7781*3 + 2] = 0.188877f;
+ 	val_dir[7782*3 + 0] = -0.420542f;	val_dir[7782*3 + 1] = 0.887812f;	val_dir[7782*3 + 2] = 0.186908f;
+ 	val_dir[7783*3 + 0] = -0.392703f;	val_dir[7783*3 + 1] = 0.900907f;	val_dir[7783*3 + 2] = 0.184801f;
+ 	val_dir[7784*3 + 0] = -0.365148f;	val_dir[7784*3 + 1] = 0.912871f;	val_dir[7784*3 + 2] = 0.182574f;
+ 	val_dir[7785*3 + 0] = -0.337954f;	val_dir[7785*3 + 1] = 0.923742f;	val_dir[7785*3 + 2] = 0.180242f;
+ 	val_dir[7786*3 + 0] = -0.311188f;	val_dir[7786*3 + 1] = 0.933564f;	val_dir[7786*3 + 2] = 0.177822f;
+ 	val_dir[7787*3 + 0] = -0.284907f;	val_dir[7787*3 + 1] = 0.942384f;	val_dir[7787*3 + 2] = 0.175327f;
+ 	val_dir[7788*3 + 0] = -0.259161f;	val_dir[7788*3 + 1] = 0.950255f;	val_dir[7788*3 + 2] = 0.172774f;
+ 	val_dir[7789*3 + 0] = -0.233990f;	val_dir[7789*3 + 1] = 0.957230f;	val_dir[7789*3 + 2] = 0.170174f;
+ 	val_dir[7790*3 + 0] = -0.209427f;	val_dir[7790*3 + 1] = 0.963364f;	val_dir[7790*3 + 2] = 0.167542f;
+ 	val_dir[7791*3 + 0] = -0.185498f;	val_dir[7791*3 + 1] = 0.968712f;	val_dir[7791*3 + 2] = 0.164887f;
+ 	val_dir[7792*3 + 0] = -0.162221f;	val_dir[7792*3 + 1] = 0.973329f;	val_dir[7792*3 + 2] = 0.162221f;
+ 	val_dir[7793*3 + 0] = -0.139610f;	val_dir[7793*3 + 1] = 0.977267f;	val_dir[7793*3 + 2] = 0.159554f;
+ 	val_dir[7794*3 + 0] = -0.117670f;	val_dir[7794*3 + 1] = 0.980581f;	val_dir[7794*3 + 2] = 0.156893f;
+ 	val_dir[7795*3 + 0] = -0.096404f;	val_dir[7795*3 + 1] = 0.983318f;	val_dir[7795*3 + 2] = 0.154246f;
+ 	val_dir[7796*3 + 0] = -0.075810f;	val_dir[7796*3 + 1] = 0.985527f;	val_dir[7796*3 + 2] = 0.151620f;
+ 	val_dir[7797*3 + 0] = -0.055882f;	val_dir[7797*3 + 1] = 0.987254f;	val_dir[7797*3 + 2] = 0.149019f;
+ 	val_dir[7798*3 + 0] = -0.036613f;	val_dir[7798*3 + 1] = 0.988540f;	val_dir[7798*3 + 2] = 0.146450f;
+ 	val_dir[7799*3 + 0] = -0.017990f;	val_dir[7799*3 + 1] = 0.989426f;	val_dir[7799*3 + 2] = 0.143917f;
+ 	val_dir[7800*3 + 0] = 0.0f;	val_dir[7800*3 + 1] = 0.989949f;	val_dir[7800*3 + 2] = 0.141421f;
+ 	val_dir[7801*3 + 0] = 0.017445f;	val_dir[7801*3 + 1] = 0.994354f;	val_dir[7801*3 + 2] = 0.104669f;
+ 	val_dir[7802*3 + 0] = 0.034381f;	val_dir[7802*3 + 1] = 0.997041f;	val_dir[7802*3 + 2] = 0.068761f;
+ 	val_dir[7803*3 + 0] = 0.050753f;	val_dir[7803*3 + 1] = 0.998138f;	val_dir[7803*3 + 2] = 0.033835f;
+ 	val_dir[7804*3 + 0] = 0.066519f;	val_dir[7804*3 + 1] = 0.997785f;	val_dir[7804*3 + 2] = 0.0f;
+ 	val_dir[7805*3 + 0] = -0.998614f;	val_dir[7805*3 + 1] = -0.049931f;	val_dir[7805*3 + 2] = 0.016644f;
+ 	val_dir[7806*3 + 0] = -0.998138f;	val_dir[7806*3 + 1] = -0.033835f;	val_dir[7806*3 + 2] = 0.050753f;
+ 	val_dir[7807*3 + 0] = -0.996158f;	val_dir[7807*3 + 1] = -0.017175f;	val_dir[7807*3 + 2] = 0.085876f;
+ 	val_dir[7808*3 + 0] = -0.992543f;	val_dir[7808*3 + 1] = 0.0f;	val_dir[7808*3 + 2] = 0.121891f;
+ 	val_dir[7809*3 + 0] = -0.992122f;	val_dir[7809*3 + 1] = 0.017716f;	val_dir[7809*3 + 2] = 0.124015f;
+ 	val_dir[7810*3 + 0] = -0.991353f;	val_dir[7810*3 + 1] = 0.036049f;	val_dir[7810*3 + 2] = 0.126172f;
+ 	val_dir[7811*3 + 0] = -0.990201f;	val_dir[7811*3 + 1] = 0.055011f;	val_dir[7811*3 + 2] = 0.128359f;
+ 	val_dir[7812*3 + 0] = -0.988627f;	val_dir[7812*3 + 1] = 0.074613f;	val_dir[7812*3 + 2] = 0.130573f;
+ 	val_dir[7813*3 + 0] = -0.986591f;	val_dir[7813*3 + 1] = 0.094865f;	val_dir[7813*3 + 2] = 0.132810f;
+ 	val_dir[7814*3 + 0] = -0.984050f;	val_dir[7814*3 + 1] = 0.115771f;	val_dir[7814*3 + 2] = 0.135066f;
+ 	val_dir[7815*3 + 0] = -0.980958f;	val_dir[7815*3 + 1] = 0.137334f;	val_dir[7815*3 + 2] = 0.137334f;
+ 	val_dir[7816*3 + 0] = -0.977267f;	val_dir[7816*3 + 1] = 0.159554f;	val_dir[7816*3 + 2] = 0.139610f;
+ 	val_dir[7817*3 + 0] = -0.972929f;	val_dir[7817*3 + 1] = 0.182424f;	val_dir[7817*3 + 2] = 0.141885f;
+ 	val_dir[7818*3 + 0] = -0.967890f;	val_dir[7818*3 + 1] = 0.205934f;	val_dir[7818*3 + 2] = 0.144154f;
+ 	val_dir[7819*3 + 0] = -0.962099f;	val_dir[7819*3 + 1] = 0.230067f;	val_dir[7819*3 + 2] = 0.146406f;
+ 	val_dir[7820*3 + 0] = -0.955502f;	val_dir[7820*3 + 1] = 0.254801f;	val_dir[7820*3 + 2] = 0.148634f;
+ 	val_dir[7821*3 + 0] = -0.948047f;	val_dir[7821*3 + 1] = 0.280105f;	val_dir[7821*3 + 2] = 0.150826f;
+ 	val_dir[7822*3 + 0] = -0.939680f;	val_dir[7822*3 + 1] = 0.305942f;	val_dir[7822*3 + 2] = 0.152971f;
+ 	val_dir[7823*3 + 0] = -0.930352f;	val_dir[7823*3 + 1] = 0.332269f;	val_dir[7823*3 + 2] = 0.155059f;
+ 	val_dir[7824*3 + 0] = -0.920014f;	val_dir[7824*3 + 1] = 0.359030f;	val_dir[7824*3 + 2] = 0.157075f;
+ 	val_dir[7825*3 + 0] = -0.908622f;	val_dir[7825*3 + 1] = 0.386164f;	val_dir[7825*3 + 2] = 0.159009f;
+ 	val_dir[7826*3 + 0] = -0.896137f;	val_dir[7826*3 + 1] = 0.413602f;	val_dir[7826*3 + 2] = 0.160845f;
+ 	val_dir[7827*3 + 0] = -0.882528f;	val_dir[7827*3 + 1] = 0.441264f;	val_dir[7827*3 + 2] = 0.162571f;
+ 	val_dir[7828*3 + 0] = -0.867770f;	val_dir[7828*3 + 1] = 0.469065f;	val_dir[7828*3 + 2] = 0.164173f;
+ 	val_dir[7829*3 + 0] = -0.851847f;	val_dir[7829*3 + 1] = 0.496911f;	val_dir[7829*3 + 2] = 0.165637f;
+ 	val_dir[7830*3 + 0] = -0.834754f;	val_dir[7830*3 + 1] = 0.524703f;	val_dir[7830*3 + 2] = 0.166951f;
+ 	val_dir[7831*3 + 0] = -0.816497f;	val_dir[7831*3 + 1] = 0.552336f;	val_dir[7831*3 + 2] = 0.168102f;
+ 	val_dir[7832*3 + 0] = -0.797092f;	val_dir[7832*3 + 1] = 0.579703f;	val_dir[7832*3 + 2] = 0.169080f;
+ 	val_dir[7833*3 + 0] = -0.776571f;	val_dir[7833*3 + 1] = 0.606696f;	val_dir[7833*3 + 2] = 0.169875f;
+ 	val_dir[7834*3 + 0] = -0.754976f;	val_dir[7834*3 + 1] = 0.633205f;	val_dir[7834*3 + 2] = 0.170478f;
+ 	val_dir[7835*3 + 0] = -0.732361f;	val_dir[7835*3 + 1] = 0.659125f;	val_dir[7835*3 + 2] = 0.170884f;
+ 	val_dir[7836*3 + 0] = -0.708794f;	val_dir[7836*3 + 1] = 0.684353f;	val_dir[7836*3 + 2] = 0.171088f;
+ 	val_dir[7837*3 + 0] = -0.684353f;	val_dir[7837*3 + 1] = 0.708794f;	val_dir[7837*3 + 2] = 0.171088f;
+ 	val_dir[7838*3 + 0] = -0.659125f;	val_dir[7838*3 + 1] = 0.732361f;	val_dir[7838*3 + 2] = 0.170884f;
+ 	val_dir[7839*3 + 0] = -0.633205f;	val_dir[7839*3 + 1] = 0.754976f;	val_dir[7839*3 + 2] = 0.170478f;
+ 	val_dir[7840*3 + 0] = -0.606696f;	val_dir[7840*3 + 1] = 0.776571f;	val_dir[7840*3 + 2] = 0.169875f;
+ 	val_dir[7841*3 + 0] = -0.579703f;	val_dir[7841*3 + 1] = 0.797092f;	val_dir[7841*3 + 2] = 0.169080f;
+ 	val_dir[7842*3 + 0] = -0.552336f;	val_dir[7842*3 + 1] = 0.816497f;	val_dir[7842*3 + 2] = 0.168102f;
+ 	val_dir[7843*3 + 0] = -0.524703f;	val_dir[7843*3 + 1] = 0.834754f;	val_dir[7843*3 + 2] = 0.166951f;
+ 	val_dir[7844*3 + 0] = -0.496911f;	val_dir[7844*3 + 1] = 0.851847f;	val_dir[7844*3 + 2] = 0.165637f;
+ 	val_dir[7845*3 + 0] = -0.469065f;	val_dir[7845*3 + 1] = 0.867770f;	val_dir[7845*3 + 2] = 0.164173f;
+ 	val_dir[7846*3 + 0] = -0.441264f;	val_dir[7846*3 + 1] = 0.882528f;	val_dir[7846*3 + 2] = 0.162571f;
+ 	val_dir[7847*3 + 0] = -0.413602f;	val_dir[7847*3 + 1] = 0.896137f;	val_dir[7847*3 + 2] = 0.160845f;
+ 	val_dir[7848*3 + 0] = -0.386164f;	val_dir[7848*3 + 1] = 0.908622f;	val_dir[7848*3 + 2] = 0.159009f;
+ 	val_dir[7849*3 + 0] = -0.359030f;	val_dir[7849*3 + 1] = 0.920014f;	val_dir[7849*3 + 2] = 0.157075f;
+ 	val_dir[7850*3 + 0] = -0.332269f;	val_dir[7850*3 + 1] = 0.930352f;	val_dir[7850*3 + 2] = 0.155059f;
+ 	val_dir[7851*3 + 0] = -0.305942f;	val_dir[7851*3 + 1] = 0.939680f;	val_dir[7851*3 + 2] = 0.152971f;
+ 	val_dir[7852*3 + 0] = -0.280105f;	val_dir[7852*3 + 1] = 0.948047f;	val_dir[7852*3 + 2] = 0.150826f;
+ 	val_dir[7853*3 + 0] = -0.254801f;	val_dir[7853*3 + 1] = 0.955502f;	val_dir[7853*3 + 2] = 0.148634f;
+ 	val_dir[7854*3 + 0] = -0.230067f;	val_dir[7854*3 + 1] = 0.962099f;	val_dir[7854*3 + 2] = 0.146406f;
+ 	val_dir[7855*3 + 0] = -0.205934f;	val_dir[7855*3 + 1] = 0.967890f;	val_dir[7855*3 + 2] = 0.144154f;
+ 	val_dir[7856*3 + 0] = -0.182424f;	val_dir[7856*3 + 1] = 0.972929f;	val_dir[7856*3 + 2] = 0.141885f;
+ 	val_dir[7857*3 + 0] = -0.159554f;	val_dir[7857*3 + 1] = 0.977267f;	val_dir[7857*3 + 2] = 0.139610f;
+ 	val_dir[7858*3 + 0] = -0.137334f;	val_dir[7858*3 + 1] = 0.980958f;	val_dir[7858*3 + 2] = 0.137334f;
+ 	val_dir[7859*3 + 0] = -0.115771f;	val_dir[7859*3 + 1] = 0.984050f;	val_dir[7859*3 + 2] = 0.135066f;
+ 	val_dir[7860*3 + 0] = -0.094865f;	val_dir[7860*3 + 1] = 0.986591f;	val_dir[7860*3 + 2] = 0.132810f;
+ 	val_dir[7861*3 + 0] = -0.074613f;	val_dir[7861*3 + 1] = 0.988627f;	val_dir[7861*3 + 2] = 0.130573f;
+ 	val_dir[7862*3 + 0] = -0.055011f;	val_dir[7862*3 + 1] = 0.990201f;	val_dir[7862*3 + 2] = 0.128359f;
+ 	val_dir[7863*3 + 0] = -0.036049f;	val_dir[7863*3 + 1] = 0.991353f;	val_dir[7863*3 + 2] = 0.126172f;
+ 	val_dir[7864*3 + 0] = -0.017716f;	val_dir[7864*3 + 1] = 0.992122f;	val_dir[7864*3 + 2] = 0.124015f;
+ 	val_dir[7865*3 + 0] = 0.0f;	val_dir[7865*3 + 1] = 0.992543f;	val_dir[7865*3 + 2] = 0.121891f;
+ 	val_dir[7866*3 + 0] = 0.017175f;	val_dir[7866*3 + 1] = 0.996158f;	val_dir[7866*3 + 2] = 0.085876f;
+ 	val_dir[7867*3 + 0] = 0.033835f;	val_dir[7867*3 + 1] = 0.998138f;	val_dir[7867*3 + 2] = 0.050753f;
+ 	val_dir[7868*3 + 0] = 0.049931f;	val_dir[7868*3 + 1] = 0.998614f;	val_dir[7868*3 + 2] = 0.016644f;
+ 	val_dir[7869*3 + 0] = -0.998793f;	val_dir[7869*3 + 1] = -0.049121f;	val_dir[7869*3 + 2] = 0.0f;
+ 	val_dir[7870*3 + 0] = -0.998891f;	val_dir[7870*3 + 1] = -0.033296f;	val_dir[7870*3 + 2] = 0.033296f;
+ 	val_dir[7871*3 + 0] = -0.997567f;	val_dir[7871*3 + 1] = -0.016908f;	val_dir[7871*3 + 2] = 0.067632f;
+ 	val_dir[7872*3 + 0] = -0.994692f;	val_dir[7872*3 + 1] = 0.0f;	val_dir[7872*3 + 2] = 0.102899f;
+ 	val_dir[7873*3 + 0] = -0.994354f;	val_dir[7873*3 + 1] = 0.017445f;	val_dir[7873*3 + 2] = 0.104669f;
+ 	val_dir[7874*3 + 0] = -0.993683f;	val_dir[7874*3 + 1] = 0.035489f;	val_dir[7874*3 + 2] = 0.106466f;
+ 	val_dir[7875*3 + 0] = -0.992644f;	val_dir[7875*3 + 1] = 0.054144f;	val_dir[7875*3 + 2] = 0.108288f;
+ 	val_dir[7876*3 + 0] = -0.991201f;	val_dir[7876*3 + 1] = 0.073422f;	val_dir[7876*3 + 2] = 0.110133f;
+ 	val_dir[7877*3 + 0] = -0.989316f;	val_dir[7877*3 + 1] = 0.093332f;	val_dir[7877*3 + 2] = 0.111998f;
+ 	val_dir[7878*3 + 0] = -0.986947f;	val_dir[7878*3 + 1] = 0.113878f;	val_dir[7878*3 + 2] = 0.113878f;
+ 	val_dir[7879*3 + 0] = -0.984050f;	val_dir[7879*3 + 1] = 0.135066f;	val_dir[7879*3 + 2] = 0.115771f;
+ 	val_dir[7880*3 + 0] = -0.980581f;	val_dir[7880*3 + 1] = 0.156893f;	val_dir[7880*3 + 2] = 0.117670f;
+ 	val_dir[7881*3 + 0] = -0.976491f;	val_dir[7881*3 + 1] = 0.179355f;	val_dir[7881*3 + 2] = 0.119570f;
+ 	val_dir[7882*3 + 0] = -0.971732f;	val_dir[7882*3 + 1] = 0.202444f;	val_dir[7882*3 + 2] = 0.121466f;
+ 	val_dir[7883*3 + 0] = -0.966252f;	val_dir[7883*3 + 1] = 0.226144f;	val_dir[7883*3 + 2] = 0.123351f;
+ 	val_dir[7884*3 + 0] = -0.960001f;	val_dir[7884*3 + 1] = 0.250435f;	val_dir[7884*3 + 2] = 0.125218f;
+ 	val_dir[7885*3 + 0] = -0.952928f;	val_dir[7885*3 + 1] = 0.275290f;	val_dir[7885*3 + 2] = 0.127057f;
+ 	val_dir[7886*3 + 0] = -0.944981f;	val_dir[7886*3 + 1] = 0.300676f;	val_dir[7886*3 + 2] = 0.128861f;
+ 	val_dir[7887*3 + 0] = -0.936111f;	val_dir[7887*3 + 1] = 0.326550f;	val_dir[7887*3 + 2] = 0.130620f;
+ 	val_dir[7888*3 + 0] = -0.926270f;	val_dir[7888*3 + 1] = 0.352865f;	val_dir[7888*3 + 2] = 0.132324f;
+ 	val_dir[7889*3 + 0] = -0.915416f;	val_dir[7889*3 + 1] = 0.379563f;	val_dir[7889*3 + 2] = 0.133963f;
+ 	val_dir[7890*3 + 0] = -0.903508f;	val_dir[7890*3 + 1] = 0.406579f;	val_dir[7890*3 + 2] = 0.135526f;
+ 	val_dir[7891*3 + 0] = -0.890513f;	val_dir[7891*3 + 1] = 0.433840f;	val_dir[7891*3 + 2] = 0.137002f;
+ 	val_dir[7892*3 + 0] = -0.876405f;	val_dir[7892*3 + 1] = 0.461266f;	val_dir[7892*3 + 2] = 0.138380f;
+ 	val_dir[7893*3 + 0] = -0.861164f;	val_dir[7893*3 + 1] = 0.488769f;	val_dir[7893*3 + 2] = 0.139648f;
+ 	val_dir[7894*3 + 0] = -0.844782f;	val_dir[7894*3 + 1] = 0.516256f;	val_dir[7894*3 + 2] = 0.140797f;
+ 	val_dir[7895*3 + 0] = -0.827259f;	val_dir[7895*3 + 1] = 0.543627f;	val_dir[7895*3 + 2] = 0.141816f;
+ 	val_dir[7896*3 + 0] = -0.808608f;	val_dir[7896*3 + 1] = 0.570782f;	val_dir[7896*3 + 2] = 0.142695f;
+ 	val_dir[7897*3 + 0] = -0.788851f;	val_dir[7897*3 + 1] = 0.597614f;	val_dir[7897*3 + 2] = 0.143427f;
+ 	val_dir[7898*3 + 0] = -0.768025f;	val_dir[7898*3 + 1] = 0.624020f;	val_dir[7898*3 + 2] = 0.144005f;
+ 	val_dir[7899*3 + 0] = -0.746176f;	val_dir[7899*3 + 1] = 0.649895f;	val_dir[7899*3 + 2] = 0.144421f;
+ 	val_dir[7900*3 + 0] = -0.723364f;	val_dir[7900*3 + 1] = 0.675140f;	val_dir[7900*3 + 2] = 0.144673f;
+ 	val_dir[7901*3 + 0] = -0.699659f;	val_dir[7901*3 + 1] = 0.699659f;	val_dir[7901*3 + 2] = 0.144757f;
+ 	val_dir[7902*3 + 0] = -0.675140f;	val_dir[7902*3 + 1] = 0.723364f;	val_dir[7902*3 + 2] = 0.144673f;
+ 	val_dir[7903*3 + 0] = -0.649895f;	val_dir[7903*3 + 1] = 0.746176f;	val_dir[7903*3 + 2] = 0.144421f;
+ 	val_dir[7904*3 + 0] = -0.624020f;	val_dir[7904*3 + 1] = 0.768025f;	val_dir[7904*3 + 2] = 0.144005f;
+ 	val_dir[7905*3 + 0] = -0.597614f;	val_dir[7905*3 + 1] = 0.788851f;	val_dir[7905*3 + 2] = 0.143427f;
+ 	val_dir[7906*3 + 0] = -0.570782f;	val_dir[7906*3 + 1] = 0.808608f;	val_dir[7906*3 + 2] = 0.142695f;
+ 	val_dir[7907*3 + 0] = -0.543627f;	val_dir[7907*3 + 1] = 0.827259f;	val_dir[7907*3 + 2] = 0.141816f;
+ 	val_dir[7908*3 + 0] = -0.516256f;	val_dir[7908*3 + 1] = 0.844782f;	val_dir[7908*3 + 2] = 0.140797f;
+ 	val_dir[7909*3 + 0] = -0.488769f;	val_dir[7909*3 + 1] = 0.861164f;	val_dir[7909*3 + 2] = 0.139648f;
+ 	val_dir[7910*3 + 0] = -0.461266f;	val_dir[7910*3 + 1] = 0.876405f;	val_dir[7910*3 + 2] = 0.138380f;
+ 	val_dir[7911*3 + 0] = -0.433840f;	val_dir[7911*3 + 1] = 0.890513f;	val_dir[7911*3 + 2] = 0.137002f;
+ 	val_dir[7912*3 + 0] = -0.406579f;	val_dir[7912*3 + 1] = 0.903508f;	val_dir[7912*3 + 2] = 0.135526f;
+ 	val_dir[7913*3 + 0] = -0.379563f;	val_dir[7913*3 + 1] = 0.915416f;	val_dir[7913*3 + 2] = 0.133963f;
+ 	val_dir[7914*3 + 0] = -0.352865f;	val_dir[7914*3 + 1] = 0.926270f;	val_dir[7914*3 + 2] = 0.132324f;
+ 	val_dir[7915*3 + 0] = -0.326550f;	val_dir[7915*3 + 1] = 0.936111f;	val_dir[7915*3 + 2] = 0.130620f;
+ 	val_dir[7916*3 + 0] = -0.300676f;	val_dir[7916*3 + 1] = 0.944981f;	val_dir[7916*3 + 2] = 0.128861f;
+ 	val_dir[7917*3 + 0] = -0.275290f;	val_dir[7917*3 + 1] = 0.952928f;	val_dir[7917*3 + 2] = 0.127057f;
+ 	val_dir[7918*3 + 0] = -0.250435f;	val_dir[7918*3 + 1] = 0.960001f;	val_dir[7918*3 + 2] = 0.125218f;
+ 	val_dir[7919*3 + 0] = -0.226144f;	val_dir[7919*3 + 1] = 0.966252f;	val_dir[7919*3 + 2] = 0.123351f;
+ 	val_dir[7920*3 + 0] = -0.202444f;	val_dir[7920*3 + 1] = 0.971732f;	val_dir[7920*3 + 2] = 0.121466f;
+ 	val_dir[7921*3 + 0] = -0.179355f;	val_dir[7921*3 + 1] = 0.976491f;	val_dir[7921*3 + 2] = 0.119570f;
+ 	val_dir[7922*3 + 0] = -0.156893f;	val_dir[7922*3 + 1] = 0.980581f;	val_dir[7922*3 + 2] = 0.117670f;
+ 	val_dir[7923*3 + 0] = -0.135066f;	val_dir[7923*3 + 1] = 0.984050f;	val_dir[7923*3 + 2] = 0.115771f;
+ 	val_dir[7924*3 + 0] = -0.113878f;	val_dir[7924*3 + 1] = 0.986947f;	val_dir[7924*3 + 2] = 0.113878f;
+ 	val_dir[7925*3 + 0] = -0.093332f;	val_dir[7925*3 + 1] = 0.989316f;	val_dir[7925*3 + 2] = 0.111998f;
+ 	val_dir[7926*3 + 0] = -0.073422f;	val_dir[7926*3 + 1] = 0.991201f;	val_dir[7926*3 + 2] = 0.110133f;
+ 	val_dir[7927*3 + 0] = -0.054144f;	val_dir[7927*3 + 1] = 0.992644f;	val_dir[7927*3 + 2] = 0.108288f;
+ 	val_dir[7928*3 + 0] = -0.035489f;	val_dir[7928*3 + 1] = 0.993683f;	val_dir[7928*3 + 2] = 0.106466f;
+ 	val_dir[7929*3 + 0] = -0.017445f;	val_dir[7929*3 + 1] = 0.994354f;	val_dir[7929*3 + 2] = 0.104669f;
+ 	val_dir[7930*3 + 0] = 0.0f;	val_dir[7930*3 + 1] = 0.994692f;	val_dir[7930*3 + 2] = 0.102899f;
+ 	val_dir[7931*3 + 0] = 0.016908f;	val_dir[7931*3 + 1] = 0.997567f;	val_dir[7931*3 + 2] = 0.067632f;
+ 	val_dir[7932*3 + 0] = 0.033296f;	val_dir[7932*3 + 1] = 0.998891f;	val_dir[7932*3 + 2] = 0.033296f;
+ 	val_dir[7933*3 + 0] = 0.049121f;	val_dir[7933*3 + 1] = 0.998793f;	val_dir[7933*3 + 2] = 0.0f;
+ 	val_dir[7934*3 + 0] = -0.999329f;	val_dir[7934*3 + 1] = -0.032765f;	val_dir[7934*3 + 2] = 0.016382f;
+ 	val_dir[7935*3 + 0] = -0.998614f;	val_dir[7935*3 + 1] = -0.016644f;	val_dir[7935*3 + 2] = 0.049931f;
+ 	val_dir[7936*3 + 0] = -0.996428f;	val_dir[7936*3 + 1] = 0.0f;	val_dir[7936*3 + 2] = 0.084443f;
+ 	val_dir[7937*3 + 0] = -0.996158f;	val_dir[7937*3 + 1] = 0.017175f;	val_dir[7937*3 + 2] = 0.085876f;
+ 	val_dir[7938*3 + 0] = -0.995567f;	val_dir[7938*3 + 1] = 0.034932f;	val_dir[7938*3 + 2] = 0.087330f;
+ 	val_dir[7939*3 + 0] = -0.994623f;	val_dir[7939*3 + 1] = 0.053283f;	val_dir[7939*3 + 2] = 0.088806f;
+ 	val_dir[7940*3 + 0] = -0.993291f;	val_dir[7940*3 + 1] = 0.072239f;	val_dir[7940*3 + 2] = 0.090299f;
+ 	val_dir[7941*3 + 0] = -0.991535f;	val_dir[7941*3 + 1] = 0.091809f;	val_dir[7941*3 + 2] = 0.091809f;
+ 	val_dir[7942*3 + 0] = -0.989316f;	val_dir[7942*3 + 1] = 0.111998f;	val_dir[7942*3 + 2] = 0.093332f;
+ 	val_dir[7943*3 + 0] = -0.986591f;	val_dir[7943*3 + 1] = 0.132810f;	val_dir[7943*3 + 2] = 0.094865f;
+ 	val_dir[7944*3 + 0] = -0.983318f;	val_dir[7944*3 + 1] = 0.154246f;	val_dir[7944*3 + 2] = 0.096404f;
+ 	val_dir[7945*3 + 0] = -0.979451f;	val_dir[7945*3 + 1] = 0.176301f;	val_dir[7945*3 + 2] = 0.097945f;
+ 	val_dir[7946*3 + 0] = -0.974943f;	val_dir[7946*3 + 1] = 0.198968f;	val_dir[7946*3 + 2] = 0.099484f;
+ 	val_dir[7947*3 + 0] = -0.969746f;	val_dir[7947*3 + 1] = 0.222234f;	val_dir[7947*3 + 2] = 0.101015f;
+ 	val_dir[7948*3 + 0] = -0.963811f;	val_dir[7948*3 + 1] = 0.246079f;	val_dir[7948*3 + 2] = 0.102533f;
+ 	val_dir[7949*3 + 0] = -0.957088f;	val_dir[7949*3 + 1] = 0.270481f;	val_dir[7949*3 + 2] = 0.104031f;
+ 	val_dir[7950*3 + 0] = -0.949528f;	val_dir[7950*3 + 1] = 0.295409f;	val_dir[7950*3 + 2] = 0.105503f;
+ 	val_dir[7951*3 + 0] = -0.941082f;	val_dir[7951*3 + 1] = 0.320824f;	val_dir[7951*3 + 2] = 0.106941f;
+ 	val_dir[7952*3 + 0] = -0.931705f;	val_dir[7952*3 + 1] = 0.346681f;	val_dir[7952*3 + 2] = 0.108338f;
+ 	val_dir[7953*3 + 0] = -0.921354f;	val_dir[7953*3 + 1] = 0.372929f;	val_dir[7953*3 + 2] = 0.109685f;
+ 	val_dir[7954*3 + 0] = -0.909988f;	val_dir[7954*3 + 1] = 0.399507f;	val_dir[7954*3 + 2] = 0.110974f;
+ 	val_dir[7955*3 + 0] = -0.897574f;	val_dir[7955*3 + 1] = 0.426348f;	val_dir[7955*3 + 2] = 0.112197f;
+ 	val_dir[7956*3 + 0] = -0.884083f;	val_dir[7956*3 + 1] = 0.453376f;	val_dir[7956*3 + 2] = 0.113344f;
+ 	val_dir[7957*3 + 0] = -0.869495f;	val_dir[7957*3 + 1] = 0.480510f;	val_dir[7957*3 + 2] = 0.114407f;
+ 	val_dir[7958*3 + 0] = -0.853796f;	val_dir[7958*3 + 1] = 0.507662f;	val_dir[7958*3 + 2] = 0.115378f;
+ 	val_dir[7959*3 + 0] = -0.836983f;	val_dir[7959*3 + 1] = 0.534739f;	val_dir[7959*3 + 2] = 0.116248f;
+ 	val_dir[7960*3 + 0] = -0.819064f;	val_dir[7960*3 + 1] = 0.561644f;	val_dir[7960*3 + 2] = 0.117009f;
+ 	val_dir[7961*3 + 0] = -0.800055f;	val_dir[7961*3 + 1] = 0.588276f;	val_dir[7961*3 + 2] = 0.117655f;
+ 	val_dir[7962*3 + 0] = -0.779987f;	val_dir[7962*3 + 1] = 0.614535f;	val_dir[7962*3 + 2] = 0.118180f;
+ 	val_dir[7963*3 + 0] = -0.758899f;	val_dir[7963*3 + 1] = 0.640321f;	val_dir[7963*3 + 2] = 0.118578f;
+ 	val_dir[7964*3 + 0] = -0.736843f;	val_dir[7964*3 + 1] = 0.665536f;	val_dir[7964*3 + 2] = 0.118846f;
+ 	val_dir[7965*3 + 0] = -0.713881f;	val_dir[7965*3 + 1] = 0.690085f;	val_dir[7965*3 + 2] = 0.118980f;
+ 	val_dir[7966*3 + 0] = -0.690085f;	val_dir[7966*3 + 1] = 0.713881f;	val_dir[7966*3 + 2] = 0.118980f;
+ 	val_dir[7967*3 + 0] = -0.665536f;	val_dir[7967*3 + 1] = 0.736843f;	val_dir[7967*3 + 2] = 0.118846f;
+ 	val_dir[7968*3 + 0] = -0.640321f;	val_dir[7968*3 + 1] = 0.758899f;	val_dir[7968*3 + 2] = 0.118578f;
+ 	val_dir[7969*3 + 0] = -0.614535f;	val_dir[7969*3 + 1] = 0.779987f;	val_dir[7969*3 + 2] = 0.118180f;
+ 	val_dir[7970*3 + 0] = -0.588276f;	val_dir[7970*3 + 1] = 0.800055f;	val_dir[7970*3 + 2] = 0.117655f;
+ 	val_dir[7971*3 + 0] = -0.561644f;	val_dir[7971*3 + 1] = 0.819064f;	val_dir[7971*3 + 2] = 0.117009f;
+ 	val_dir[7972*3 + 0] = -0.534739f;	val_dir[7972*3 + 1] = 0.836983f;	val_dir[7972*3 + 2] = 0.116248f;
+ 	val_dir[7973*3 + 0] = -0.507662f;	val_dir[7973*3 + 1] = 0.853796f;	val_dir[7973*3 + 2] = 0.115378f;
+ 	val_dir[7974*3 + 0] = -0.480510f;	val_dir[7974*3 + 1] = 0.869495f;	val_dir[7974*3 + 2] = 0.114407f;
+ 	val_dir[7975*3 + 0] = -0.453376f;	val_dir[7975*3 + 1] = 0.884083f;	val_dir[7975*3 + 2] = 0.113344f;
+ 	val_dir[7976*3 + 0] = -0.426348f;	val_dir[7976*3 + 1] = 0.897574f;	val_dir[7976*3 + 2] = 0.112197f;
+ 	val_dir[7977*3 + 0] = -0.399507f;	val_dir[7977*3 + 1] = 0.909988f;	val_dir[7977*3 + 2] = 0.110974f;
+ 	val_dir[7978*3 + 0] = -0.372929f;	val_dir[7978*3 + 1] = 0.921354f;	val_dir[7978*3 + 2] = 0.109685f;
+ 	val_dir[7979*3 + 0] = -0.346681f;	val_dir[7979*3 + 1] = 0.931705f;	val_dir[7979*3 + 2] = 0.108338f;
+ 	val_dir[7980*3 + 0] = -0.320824f;	val_dir[7980*3 + 1] = 0.941082f;	val_dir[7980*3 + 2] = 0.106941f;
+ 	val_dir[7981*3 + 0] = -0.295409f;	val_dir[7981*3 + 1] = 0.949528f;	val_dir[7981*3 + 2] = 0.105503f;
+ 	val_dir[7982*3 + 0] = -0.270481f;	val_dir[7982*3 + 1] = 0.957088f;	val_dir[7982*3 + 2] = 0.104031f;
+ 	val_dir[7983*3 + 0] = -0.246079f;	val_dir[7983*3 + 1] = 0.963811f;	val_dir[7983*3 + 2] = 0.102533f;
+ 	val_dir[7984*3 + 0] = -0.222234f;	val_dir[7984*3 + 1] = 0.969746f;	val_dir[7984*3 + 2] = 0.101015f;
+ 	val_dir[7985*3 + 0] = -0.198968f;	val_dir[7985*3 + 1] = 0.974943f;	val_dir[7985*3 + 2] = 0.099484f;
+ 	val_dir[7986*3 + 0] = -0.176301f;	val_dir[7986*3 + 1] = 0.979451f;	val_dir[7986*3 + 2] = 0.097945f;
+ 	val_dir[7987*3 + 0] = -0.154246f;	val_dir[7987*3 + 1] = 0.983318f;	val_dir[7987*3 + 2] = 0.096404f;
+ 	val_dir[7988*3 + 0] = -0.132810f;	val_dir[7988*3 + 1] = 0.986591f;	val_dir[7988*3 + 2] = 0.094865f;
+ 	val_dir[7989*3 + 0] = -0.111998f;	val_dir[7989*3 + 1] = 0.989316f;	val_dir[7989*3 + 2] = 0.093332f;
+ 	val_dir[7990*3 + 0] = -0.091809f;	val_dir[7990*3 + 1] = 0.991535f;	val_dir[7990*3 + 2] = 0.091809f;
+ 	val_dir[7991*3 + 0] = -0.072239f;	val_dir[7991*3 + 1] = 0.993291f;	val_dir[7991*3 + 2] = 0.090299f;
+ 	val_dir[7992*3 + 0] = -0.053283f;	val_dir[7992*3 + 1] = 0.994623f;	val_dir[7992*3 + 2] = 0.088806f;
+ 	val_dir[7993*3 + 0] = -0.034932f;	val_dir[7993*3 + 1] = 0.995567f;	val_dir[7993*3 + 2] = 0.087330f;
+ 	val_dir[7994*3 + 0] = -0.017175f;	val_dir[7994*3 + 1] = 0.996158f;	val_dir[7994*3 + 2] = 0.085876f;
+ 	val_dir[7995*3 + 0] = 0.0f;	val_dir[7995*3 + 1] = 0.996428f;	val_dir[7995*3 + 2] = 0.084443f;
+ 	val_dir[7996*3 + 0] = 0.016644f;	val_dir[7996*3 + 1] = 0.998614f;	val_dir[7996*3 + 2] = 0.049931f;
+ 	val_dir[7997*3 + 0] = 0.032765f;	val_dir[7997*3 + 1] = 0.999329f;	val_dir[7997*3 + 2] = 0.016382f;
+ 	val_dir[7998*3 + 0] = -0.999480f;	val_dir[7998*3 + 1] = -0.032241f;	val_dir[7998*3 + 2] = 0.0f;
+ 	val_dir[7999*3 + 0] = -0.999329f;	val_dir[7999*3 + 1] = -0.016382f;	val_dir[7999*3 + 2] = 0.032765f;
+ 	val_dir[8000*3 + 0] = -0.997785f;	val_dir[8000*3 + 1] = 0.0f;	val_dir[8000*3 + 2] = 0.066519f;
+ 	val_dir[8001*3 + 0] = -0.997567f;	val_dir[8001*3 + 1] = 0.016908f;	val_dir[8001*3 + 2] = 0.067632f;
+ 	val_dir[8002*3 + 0] = -0.997041f;	val_dir[8002*3 + 1] = 0.034381f;	val_dir[8002*3 + 2] = 0.068761f;
+ 	val_dir[8003*3 + 0] = -0.996175f;	val_dir[8003*3 + 1] = 0.052430f;	val_dir[8003*3 + 2] = 0.069907f;
+ 	val_dir[8004*3 + 0] = -0.994937f;	val_dir[8004*3 + 1] = 0.071067f;	val_dir[8004*3 + 2] = 0.071067f;
+ 	val_dir[8005*3 + 0] = -0.993291f;	val_dir[8005*3 + 1] = 0.090299f;	val_dir[8005*3 + 2] = 0.072239f;
+ 	val_dir[8006*3 + 0] = -0.991201f;	val_dir[8006*3 + 1] = 0.110133f;	val_dir[8006*3 + 2] = 0.073422f;
+ 	val_dir[8007*3 + 0] = -0.988627f;	val_dir[8007*3 + 1] = 0.130573f;	val_dir[8007*3 + 2] = 0.074613f;
+ 	val_dir[8008*3 + 0] = -0.985527f;	val_dir[8008*3 + 1] = 0.151620f;	val_dir[8008*3 + 2] = 0.075810f;
+ 	val_dir[8009*3 + 0] = -0.981859f;	val_dir[8009*3 + 1] = 0.173269f;	val_dir[8009*3 + 2] = 0.077009f;
+ 	val_dir[8010*3 + 0] = -0.977577f;	val_dir[8010*3 + 1] = 0.195515f;	val_dir[8010*3 + 2] = 0.078206f;
+ 	val_dir[8011*3 + 0] = -0.972636f;	val_dir[8011*3 + 1] = 0.218347f;	val_dir[8011*3 + 2] = 0.079399f;
+ 	val_dir[8012*3 + 0] = -0.966988f;	val_dir[8012*3 + 1] = 0.241747f;	val_dir[8012*3 + 2] = 0.080582f;
+ 	val_dir[8013*3 + 0] = -0.960585f;	val_dir[8013*3 + 1] = 0.265694f;	val_dir[8013*3 + 2] = 0.081752f;
+ 	val_dir[8014*3 + 0] = -0.953381f;	val_dir[8014*3 + 1] = 0.290159f;	val_dir[8014*3 + 2] = 0.082903f;
+ 	val_dir[8015*3 + 0] = -0.945328f;	val_dir[8015*3 + 1] = 0.315109f;	val_dir[8015*3 + 2] = 0.084029f;
+ 	val_dir[8016*3 + 0] = -0.936382f;	val_dir[8016*3 + 1] = 0.340503f;	val_dir[8016*3 + 2] = 0.085126f;
+ 	val_dir[8017*3 + 0] = -0.92650f;	val_dir[8017*3 + 1] = 0.366291f;	val_dir[8017*3 + 2] = 0.086186f;
+ 	val_dir[8018*3 + 0] = -0.915644f;	val_dir[8018*3 + 1] = 0.392419f;	val_dir[8018*3 + 2] = 0.087204f;
+ 	val_dir[8019*3 + 0] = -0.903777f;	val_dir[8019*3 + 1] = 0.418823f;	val_dir[8019*3 + 2] = 0.088173f;
+ 	val_dir[8020*3 + 0] = -0.890871f;	val_dir[8020*3 + 1] = 0.445435f;	val_dir[8020*3 + 2] = 0.089087f;
+ 	val_dir[8021*3 + 0] = -0.876903f;	val_dir[8021*3 + 1] = 0.472178f;	val_dir[8021*3 + 2] = 0.089939f;
+ 	val_dir[8022*3 + 0] = -0.861857f;	val_dir[8022*3 + 1] = 0.498970f;	val_dir[8022*3 + 2] = 0.090722f;
+ 	val_dir[8023*3 + 0] = -0.845728f;	val_dir[8023*3 + 1] = 0.525723f;	val_dir[8023*3 + 2] = 0.091430f;
+ 	val_dir[8024*3 + 0] = -0.828517f;	val_dir[8024*3 + 1] = 0.552345f;	val_dir[8024*3 + 2] = 0.092057f;
+ 	val_dir[8025*3 + 0] = -0.810237f;	val_dir[8025*3 + 1] = 0.578741f;	val_dir[8025*3 + 2] = 0.092599f;
+ 	val_dir[8026*3 + 0] = -0.790912f;	val_dir[8026*3 + 1] = 0.604815f;	val_dir[8026*3 + 2] = 0.093048f;
+ 	val_dir[8027*3 + 0] = -0.770574f;	val_dir[8027*3 + 1] = 0.630470f;	val_dir[8027*3 + 2] = 0.093403f;
+ 	val_dir[8028*3 + 0] = -0.749269f;	val_dir[8028*3 + 1] = 0.655610f;	val_dir[8028*3 + 2] = 0.093659f;
+ 	val_dir[8029*3 + 0] = -0.727051f;	val_dir[8029*3 + 1] = 0.680144f;	val_dir[8029*3 + 2] = 0.093813f;
+ 	val_dir[8030*3 + 0] = -0.703985f;	val_dir[8030*3 + 1] = 0.703985f;	val_dir[8030*3 + 2] = 0.093865f;
+ 	val_dir[8031*3 + 0] = -0.680144f;	val_dir[8031*3 + 1] = 0.727051f;	val_dir[8031*3 + 2] = 0.093813f;
+ 	val_dir[8032*3 + 0] = -0.655610f;	val_dir[8032*3 + 1] = 0.749269f;	val_dir[8032*3 + 2] = 0.093659f;
+ 	val_dir[8033*3 + 0] = -0.630470f;	val_dir[8033*3 + 1] = 0.770574f;	val_dir[8033*3 + 2] = 0.093403f;
+ 	val_dir[8034*3 + 0] = -0.604815f;	val_dir[8034*3 + 1] = 0.790912f;	val_dir[8034*3 + 2] = 0.093048f;
+ 	val_dir[8035*3 + 0] = -0.578741f;	val_dir[8035*3 + 1] = 0.810237f;	val_dir[8035*3 + 2] = 0.092599f;
+ 	val_dir[8036*3 + 0] = -0.552345f;	val_dir[8036*3 + 1] = 0.828517f;	val_dir[8036*3 + 2] = 0.092057f;
+ 	val_dir[8037*3 + 0] = -0.525723f;	val_dir[8037*3 + 1] = 0.845728f;	val_dir[8037*3 + 2] = 0.091430f;
+ 	val_dir[8038*3 + 0] = -0.498970f;	val_dir[8038*3 + 1] = 0.861857f;	val_dir[8038*3 + 2] = 0.090722f;
+ 	val_dir[8039*3 + 0] = -0.472178f;	val_dir[8039*3 + 1] = 0.876903f;	val_dir[8039*3 + 2] = 0.089939f;
+ 	val_dir[8040*3 + 0] = -0.445435f;	val_dir[8040*3 + 1] = 0.890871f;	val_dir[8040*3 + 2] = 0.089087f;
+ 	val_dir[8041*3 + 0] = -0.418823f;	val_dir[8041*3 + 1] = 0.903777f;	val_dir[8041*3 + 2] = 0.088173f;
+ 	val_dir[8042*3 + 0] = -0.392419f;	val_dir[8042*3 + 1] = 0.915644f;	val_dir[8042*3 + 2] = 0.087204f;
+ 	val_dir[8043*3 + 0] = -0.366291f;	val_dir[8043*3 + 1] = 0.92650f;	val_dir[8043*3 + 2] = 0.086186f;
+ 	val_dir[8044*3 + 0] = -0.340503f;	val_dir[8044*3 + 1] = 0.936382f;	val_dir[8044*3 + 2] = 0.085126f;
+ 	val_dir[8045*3 + 0] = -0.315109f;	val_dir[8045*3 + 1] = 0.945328f;	val_dir[8045*3 + 2] = 0.084029f;
+ 	val_dir[8046*3 + 0] = -0.290159f;	val_dir[8046*3 + 1] = 0.953381f;	val_dir[8046*3 + 2] = 0.082903f;
+ 	val_dir[8047*3 + 0] = -0.265694f;	val_dir[8047*3 + 1] = 0.960585f;	val_dir[8047*3 + 2] = 0.081752f;
+ 	val_dir[8048*3 + 0] = -0.241747f;	val_dir[8048*3 + 1] = 0.966988f;	val_dir[8048*3 + 2] = 0.080582f;
+ 	val_dir[8049*3 + 0] = -0.218347f;	val_dir[8049*3 + 1] = 0.972636f;	val_dir[8049*3 + 2] = 0.079399f;
+ 	val_dir[8050*3 + 0] = -0.195515f;	val_dir[8050*3 + 1] = 0.977577f;	val_dir[8050*3 + 2] = 0.078206f;
+ 	val_dir[8051*3 + 0] = -0.173269f;	val_dir[8051*3 + 1] = 0.981859f;	val_dir[8051*3 + 2] = 0.077009f;
+ 	val_dir[8052*3 + 0] = -0.151620f;	val_dir[8052*3 + 1] = 0.985527f;	val_dir[8052*3 + 2] = 0.075810f;
+ 	val_dir[8053*3 + 0] = -0.130573f;	val_dir[8053*3 + 1] = 0.988627f;	val_dir[8053*3 + 2] = 0.074613f;
+ 	val_dir[8054*3 + 0] = -0.110133f;	val_dir[8054*3 + 1] = 0.991201f;	val_dir[8054*3 + 2] = 0.073422f;
+ 	val_dir[8055*3 + 0] = -0.090299f;	val_dir[8055*3 + 1] = 0.993291f;	val_dir[8055*3 + 2] = 0.072239f;
+ 	val_dir[8056*3 + 0] = -0.071067f;	val_dir[8056*3 + 1] = 0.994937f;	val_dir[8056*3 + 2] = 0.071067f;
+ 	val_dir[8057*3 + 0] = -0.052430f;	val_dir[8057*3 + 1] = 0.996175f;	val_dir[8057*3 + 2] = 0.069907f;
+ 	val_dir[8058*3 + 0] = -0.034381f;	val_dir[8058*3 + 1] = 0.997041f;	val_dir[8058*3 + 2] = 0.068761f;
+ 	val_dir[8059*3 + 0] = -0.016908f;	val_dir[8059*3 + 1] = 0.997567f;	val_dir[8059*3 + 2] = 0.067632f;
+ 	val_dir[8060*3 + 0] = 0.0f;	val_dir[8060*3 + 1] = 0.997785f;	val_dir[8060*3 + 2] = 0.066519f;
+ 	val_dir[8061*3 + 0] = 0.016382f;	val_dir[8061*3 + 1] = 0.999329f;	val_dir[8061*3 + 2] = 0.032765f;
+ 	val_dir[8062*3 + 0] = 0.032241f;	val_dir[8062*3 + 1] = 0.999480f;	val_dir[8062*3 + 2] = 0.0f;
+ 	val_dir[8063*3 + 0] = -0.999740f;	val_dir[8063*3 + 1] = -0.016125f;	val_dir[8063*3 + 2] = 0.016125f;
+ 	val_dir[8064*3 + 0] = -0.998793f;	val_dir[8064*3 + 1] = 0.0f;	val_dir[8064*3 + 2] = 0.049121f;
+ 	val_dir[8065*3 + 0] = -0.998614f;	val_dir[8065*3 + 1] = 0.016644f;	val_dir[8065*3 + 2] = 0.049931f;
+ 	val_dir[8066*3 + 0] = -0.998138f;	val_dir[8066*3 + 1] = 0.033835f;	val_dir[8066*3 + 2] = 0.050753f;
+ 	val_dir[8067*3 + 0] = -0.997335f;	val_dir[8067*3 + 1] = 0.051586f;	val_dir[8067*3 + 2] = 0.051586f;
+ 	val_dir[8068*3 + 0] = -0.996175f;	val_dir[8068*3 + 1] = 0.069907f;	val_dir[8068*3 + 2] = 0.052430f;
+ 	val_dir[8069*3 + 0] = -0.994623f;	val_dir[8069*3 + 1] = 0.088806f;	val_dir[8069*3 + 2] = 0.053283f;
+ 	val_dir[8070*3 + 0] = -0.992644f;	val_dir[8070*3 + 1] = 0.108288f;	val_dir[8070*3 + 2] = 0.054144f;
+ 	val_dir[8071*3 + 0] = -0.990201f;	val_dir[8071*3 + 1] = 0.128359f;	val_dir[8071*3 + 2] = 0.055011f;
+ 	val_dir[8072*3 + 0] = -0.987254f;	val_dir[8072*3 + 1] = 0.149019f;	val_dir[8072*3 + 2] = 0.055882f;
+ 	val_dir[8073*3 + 0] = -0.983762f;	val_dir[8073*3 + 1] = 0.170267f;	val_dir[8073*3 + 2] = 0.056756f;
+ 	val_dir[8074*3 + 0] = -0.979683f;	val_dir[8074*3 + 1] = 0.192095f;	val_dir[8074*3 + 2] = 0.057628f;
+ 	val_dir[8075*3 + 0] = -0.974972f;	val_dir[8075*3 + 1] = 0.214494f;	val_dir[8075*3 + 2] = 0.058498f;
+ 	val_dir[8076*3 + 0] = -0.969584f;	val_dir[8076*3 + 1] = 0.237449f;	val_dir[8076*3 + 2] = 0.059362f;
+ 	val_dir[8077*3 + 0] = -0.963475f;	val_dir[8077*3 + 1] = 0.260941f;	val_dir[8077*3 + 2] = 0.060217f;
+ 	val_dir[8078*3 + 0] = -0.956597f;	val_dir[8078*3 + 1] = 0.284944f;	val_dir[8078*3 + 2] = 0.061059f;
+ 	val_dir[8079*3 + 0] = -0.948908f;	val_dir[8079*3 + 1] = 0.309426f;	val_dir[8079*3 + 2] = 0.061885f;
+ 	val_dir[8080*3 + 0] = -0.940361f;	val_dir[8080*3 + 1] = 0.334351f;	val_dir[8080*3 + 2] = 0.062691f;
+ 	val_dir[8081*3 + 0] = -0.930917f;	val_dir[8081*3 + 1] = 0.359673f;	val_dir[8081*3 + 2] = 0.063472f;
+ 	val_dir[8082*3 + 0] = -0.920537f;	val_dir[8082*3 + 1] = 0.385341f;	val_dir[8082*3 + 2] = 0.064223f;
+ 	val_dir[8083*3 + 0] = -0.909185f;	val_dir[8083*3 + 1] = 0.411298f;	val_dir[8083*3 + 2] = 0.064942f;
+ 	val_dir[8084*3 + 0] = -0.896831f;	val_dir[8084*3 + 1] = 0.437479f;	val_dir[8084*3 + 2] = 0.065622f;
+ 	val_dir[8085*3 + 0] = -0.883452f;	val_dir[8085*3 + 1] = 0.463812f;	val_dir[8085*3 + 2] = 0.066259f;
+ 	val_dir[8086*3 + 0] = -0.869030f;	val_dir[8086*3 + 1] = 0.490222f;	val_dir[8086*3 + 2] = 0.066848f;
+ 	val_dir[8087*3 + 0] = -0.853556f;	val_dir[8087*3 + 1] = 0.516626f;	val_dir[8087*3 + 2] = 0.067386f;
+ 	val_dir[8088*3 + 0] = -0.837027f;	val_dir[8088*3 + 1] = 0.542936f;	val_dir[8088*3 + 2] = 0.067867f;
+ 	val_dir[8089*3 + 0] = -0.819453f;	val_dir[8089*3 + 1] = 0.569064f;	val_dir[8089*3 + 2] = 0.068288f;
+ 	val_dir[8090*3 + 0] = -0.800850f;	val_dir[8090*3 + 1] = 0.594917f;	val_dir[8090*3 + 2] = 0.068644f;
+ 	val_dir[8091*3 + 0] = -0.781248f;	val_dir[8091*3 + 1] = 0.620403f;	val_dir[8091*3 + 2] = 0.068934f;
+ 	val_dir[8092*3 + 0] = -0.760684f;	val_dir[8092*3 + 1] = 0.645429f;	val_dir[8092*3 + 2] = 0.069153f;
+ 	val_dir[8093*3 + 0] = -0.739205f;	val_dir[8093*3 + 1] = 0.669905f;	val_dir[8093*3 + 2] = 0.069301f;
+ 	val_dir[8094*3 + 0] = -0.716871f;	val_dir[8094*3 + 1] = 0.693746f;	val_dir[8094*3 + 2] = 0.069375f;
+ 	val_dir[8095*3 + 0] = -0.693746f;	val_dir[8095*3 + 1] = 0.716871f;	val_dir[8095*3 + 2] = 0.069375f;
+ 	val_dir[8096*3 + 0] = -0.669905f;	val_dir[8096*3 + 1] = 0.739205f;	val_dir[8096*3 + 2] = 0.069301f;
+ 	val_dir[8097*3 + 0] = -0.645429f;	val_dir[8097*3 + 1] = 0.760684f;	val_dir[8097*3 + 2] = 0.069153f;
+ 	val_dir[8098*3 + 0] = -0.620403f;	val_dir[8098*3 + 1] = 0.781248f;	val_dir[8098*3 + 2] = 0.068934f;
+ 	val_dir[8099*3 + 0] = -0.594917f;	val_dir[8099*3 + 1] = 0.800850f;	val_dir[8099*3 + 2] = 0.068644f;
+ 	val_dir[8100*3 + 0] = -0.569064f;	val_dir[8100*3 + 1] = 0.819453f;	val_dir[8100*3 + 2] = 0.068288f;
+ 	val_dir[8101*3 + 0] = -0.542936f;	val_dir[8101*3 + 1] = 0.837027f;	val_dir[8101*3 + 2] = 0.067867f;
+ 	val_dir[8102*3 + 0] = -0.516626f;	val_dir[8102*3 + 1] = 0.853556f;	val_dir[8102*3 + 2] = 0.067386f;
+ 	val_dir[8103*3 + 0] = -0.490222f;	val_dir[8103*3 + 1] = 0.869030f;	val_dir[8103*3 + 2] = 0.066848f;
+ 	val_dir[8104*3 + 0] = -0.463812f;	val_dir[8104*3 + 1] = 0.883452f;	val_dir[8104*3 + 2] = 0.066259f;
+ 	val_dir[8105*3 + 0] = -0.437479f;	val_dir[8105*3 + 1] = 0.896831f;	val_dir[8105*3 + 2] = 0.065622f;
+ 	val_dir[8106*3 + 0] = -0.411298f;	val_dir[8106*3 + 1] = 0.909185f;	val_dir[8106*3 + 2] = 0.064942f;
+ 	val_dir[8107*3 + 0] = -0.385341f;	val_dir[8107*3 + 1] = 0.920537f;	val_dir[8107*3 + 2] = 0.064223f;
+ 	val_dir[8108*3 + 0] = -0.359673f;	val_dir[8108*3 + 1] = 0.930917f;	val_dir[8108*3 + 2] = 0.063472f;
+ 	val_dir[8109*3 + 0] = -0.334351f;	val_dir[8109*3 + 1] = 0.940361f;	val_dir[8109*3 + 2] = 0.062691f;
+ 	val_dir[8110*3 + 0] = -0.309426f;	val_dir[8110*3 + 1] = 0.948908f;	val_dir[8110*3 + 2] = 0.061885f;
+ 	val_dir[8111*3 + 0] = -0.284944f;	val_dir[8111*3 + 1] = 0.956597f;	val_dir[8111*3 + 2] = 0.061059f;
+ 	val_dir[8112*3 + 0] = -0.260941f;	val_dir[8112*3 + 1] = 0.963475f;	val_dir[8112*3 + 2] = 0.060217f;
+ 	val_dir[8113*3 + 0] = -0.237449f;	val_dir[8113*3 + 1] = 0.969584f;	val_dir[8113*3 + 2] = 0.059362f;
+ 	val_dir[8114*3 + 0] = -0.214494f;	val_dir[8114*3 + 1] = 0.974972f;	val_dir[8114*3 + 2] = 0.058498f;
+ 	val_dir[8115*3 + 0] = -0.192095f;	val_dir[8115*3 + 1] = 0.979683f;	val_dir[8115*3 + 2] = 0.057628f;
+ 	val_dir[8116*3 + 0] = -0.170267f;	val_dir[8116*3 + 1] = 0.983762f;	val_dir[8116*3 + 2] = 0.056756f;
+ 	val_dir[8117*3 + 0] = -0.149019f;	val_dir[8117*3 + 1] = 0.987254f;	val_dir[8117*3 + 2] = 0.055882f;
+ 	val_dir[8118*3 + 0] = -0.128359f;	val_dir[8118*3 + 1] = 0.990201f;	val_dir[8118*3 + 2] = 0.055011f;
+ 	val_dir[8119*3 + 0] = -0.108288f;	val_dir[8119*3 + 1] = 0.992644f;	val_dir[8119*3 + 2] = 0.054144f;
+ 	val_dir[8120*3 + 0] = -0.088806f;	val_dir[8120*3 + 1] = 0.994623f;	val_dir[8120*3 + 2] = 0.053283f;
+ 	val_dir[8121*3 + 0] = -0.069907f;	val_dir[8121*3 + 1] = 0.996175f;	val_dir[8121*3 + 2] = 0.052430f;
+ 	val_dir[8122*3 + 0] = -0.051586f;	val_dir[8122*3 + 1] = 0.997335f;	val_dir[8122*3 + 2] = 0.051586f;
+ 	val_dir[8123*3 + 0] = -0.033835f;	val_dir[8123*3 + 1] = 0.998138f;	val_dir[8123*3 + 2] = 0.050753f;
+ 	val_dir[8124*3 + 0] = -0.016644f;	val_dir[8124*3 + 1] = 0.998614f;	val_dir[8124*3 + 2] = 0.049931f;
+ 	val_dir[8125*3 + 0] = 0.0f;	val_dir[8125*3 + 1] = 0.998793f;	val_dir[8125*3 + 2] = 0.049121f;
+ 	val_dir[8126*3 + 0] = 0.016125f;	val_dir[8126*3 + 1] = 0.999740f;	val_dir[8126*3 + 2] = 0.016125f;
+ 	val_dir[8127*3 + 0] = -0.999874f;	val_dir[8127*3 + 1] = -0.015871f;	val_dir[8127*3 + 2] = 0.0f;
+ 	val_dir[8128*3 + 0] = -0.999480f;	val_dir[8128*3 + 1] = 0.0f;	val_dir[8128*3 + 2] = 0.032241f;
+ 	val_dir[8129*3 + 0] = -0.999329f;	val_dir[8129*3 + 1] = 0.016382f;	val_dir[8129*3 + 2] = 0.032765f;
+ 	val_dir[8130*3 + 0] = -0.998891f;	val_dir[8130*3 + 1] = 0.033296f;	val_dir[8130*3 + 2] = 0.033296f;
+ 	val_dir[8131*3 + 0] = -0.998138f;	val_dir[8131*3 + 1] = 0.050753f;	val_dir[8131*3 + 2] = 0.033835f;
+ 	val_dir[8132*3 + 0] = -0.997041f;	val_dir[8132*3 + 1] = 0.068761f;	val_dir[8132*3 + 2] = 0.034381f;
+ 	val_dir[8133*3 + 0] = -0.995567f;	val_dir[8133*3 + 1] = 0.087330f;	val_dir[8133*3 + 2] = 0.034932f;
+ 	val_dir[8134*3 + 0] = -0.993683f;	val_dir[8134*3 + 1] = 0.106466f;	val_dir[8134*3 + 2] = 0.035489f;
+ 	val_dir[8135*3 + 0] = -0.991353f;	val_dir[8135*3 + 1] = 0.126172f;	val_dir[8135*3 + 2] = 0.036049f;
+ 	val_dir[8136*3 + 0] = -0.988540f;	val_dir[8136*3 + 1] = 0.146450f;	val_dir[8136*3 + 2] = 0.036613f;
+ 	val_dir[8137*3 + 0] = -0.985205f;	val_dir[8137*3 + 1] = 0.167299f;	val_dir[8137*3 + 2] = 0.037178f;
+ 	val_dir[8138*3 + 0] = -0.981307f;	val_dir[8138*3 + 1] = 0.188713f;	val_dir[8138*3 + 2] = 0.037743f;
+ 	val_dir[8139*3 + 0] = -0.976804f;	val_dir[8139*3 + 1] = 0.210683f;	val_dir[8139*3 + 2] = 0.038306f;
+ 	val_dir[8140*3 + 0] = -0.971653f;	val_dir[8140*3 + 1] = 0.233197f;	val_dir[8140*3 + 2] = 0.038866f;
+ 	val_dir[8141*3 + 0] = -0.965810f;	val_dir[8141*3 + 1] = 0.256235f;	val_dir[8141*3 + 2] = 0.039421f;
+ 	val_dir[8142*3 + 0] = -0.959233f;	val_dir[8142*3 + 1] = 0.279776f;	val_dir[8142*3 + 2] = 0.039968f;
+ 	val_dir[8143*3 + 0] = -0.951877f;	val_dir[8143*3 + 1] = 0.303791f;	val_dir[8143*3 + 2] = 0.040505f;
+ 	val_dir[8144*3 + 0] = -0.943701f;	val_dir[8144*3 + 1] = 0.328244f;	val_dir[8144*3 + 2] = 0.041030f;
+ 	val_dir[8145*3 + 0] = -0.934665f;	val_dir[8145*3 + 1] = 0.353096f;	val_dir[8145*3 + 2] = 0.041541f;
+ 	val_dir[8146*3 + 0] = -0.924729f;	val_dir[8146*3 + 1] = 0.378298f;	val_dir[8146*3 + 2] = 0.042033f;
+ 	val_dir[8147*3 + 0] = -0.913860f;	val_dir[8147*3 + 1] = 0.403799f;	val_dir[8147*3 + 2] = 0.042505f;
+ 	val_dir[8148*3 + 0] = -0.902027f;	val_dir[8148*3 + 1] = 0.429537f;	val_dir[8148*3 + 2] = 0.042954f;
+ 	val_dir[8149*3 + 0] = -0.889206f;	val_dir[8149*3 + 1] = 0.455447f;	val_dir[8149*3 + 2] = 0.043376f;
+ 	val_dir[8150*3 + 0] = -0.875376f;	val_dir[8150*3 + 1] = 0.481457f;	val_dir[8150*3 + 2] = 0.043769f;
+ 	val_dir[8151*3 + 0] = -0.860527f;	val_dir[8151*3 + 1] = 0.507490f;	val_dir[8151*3 + 2] = 0.044130f;
+ 	val_dir[8152*3 + 0] = -0.844653f;	val_dir[8152*3 + 1] = 0.533465f;	val_dir[8152*3 + 2] = 0.044455f;
+ 	val_dir[8153*3 + 0] = -0.827759f;	val_dir[8153*3 + 1] = 0.559297f;	val_dir[8153*3 + 2] = 0.044744f;
+ 	val_dir[8154*3 + 0] = -0.809858f;	val_dir[8154*3 + 1] = 0.584898f;	val_dir[8154*3 + 2] = 0.044992f;
+ 	val_dir[8155*3 + 0] = -0.790973f;	val_dir[8155*3 + 1] = 0.610179f;	val_dir[8155*3 + 2] = 0.045198f;
+ 	val_dir[8156*3 + 0] = -0.771136f;	val_dir[8156*3 + 1] = 0.635053f;	val_dir[8156*3 + 2] = 0.045361f;
+ 	val_dir[8157*3 + 0] = -0.750388f;	val_dir[8157*3 + 1] = 0.659432f;	val_dir[8157*3 + 2] = 0.045478f;
+ 	val_dir[8158*3 + 0] = -0.728780f;	val_dir[8158*3 + 1] = 0.683231f;	val_dir[8158*3 + 2] = 0.045549f;
+ 	val_dir[8159*3 + 0] = -0.706372f;	val_dir[8159*3 + 1] = 0.706372f;	val_dir[8159*3 + 2] = 0.045572f;
+ 	val_dir[8160*3 + 0] = -0.683231f;	val_dir[8160*3 + 1] = 0.728780f;	val_dir[8160*3 + 2] = 0.045549f;
+ 	val_dir[8161*3 + 0] = -0.659432f;	val_dir[8161*3 + 1] = 0.750388f;	val_dir[8161*3 + 2] = 0.045478f;
+ 	val_dir[8162*3 + 0] = -0.635053f;	val_dir[8162*3 + 1] = 0.771136f;	val_dir[8162*3 + 2] = 0.045361f;
+ 	val_dir[8163*3 + 0] = -0.610179f;	val_dir[8163*3 + 1] = 0.790973f;	val_dir[8163*3 + 2] = 0.045198f;
+ 	val_dir[8164*3 + 0] = -0.584898f;	val_dir[8164*3 + 1] = 0.809858f;	val_dir[8164*3 + 2] = 0.044992f;
+ 	val_dir[8165*3 + 0] = -0.559297f;	val_dir[8165*3 + 1] = 0.827759f;	val_dir[8165*3 + 2] = 0.044744f;
+ 	val_dir[8166*3 + 0] = -0.533465f;	val_dir[8166*3 + 1] = 0.844653f;	val_dir[8166*3 + 2] = 0.044455f;
+ 	val_dir[8167*3 + 0] = -0.507490f;	val_dir[8167*3 + 1] = 0.860527f;	val_dir[8167*3 + 2] = 0.044130f;
+ 	val_dir[8168*3 + 0] = -0.481457f;	val_dir[8168*3 + 1] = 0.875376f;	val_dir[8168*3 + 2] = 0.043769f;
+ 	val_dir[8169*3 + 0] = -0.455447f;	val_dir[8169*3 + 1] = 0.889206f;	val_dir[8169*3 + 2] = 0.043376f;
+ 	val_dir[8170*3 + 0] = -0.429537f;	val_dir[8170*3 + 1] = 0.902027f;	val_dir[8170*3 + 2] = 0.042954f;
+ 	val_dir[8171*3 + 0] = -0.403799f;	val_dir[8171*3 + 1] = 0.913860f;	val_dir[8171*3 + 2] = 0.042505f;
+ 	val_dir[8172*3 + 0] = -0.378298f;	val_dir[8172*3 + 1] = 0.924729f;	val_dir[8172*3 + 2] = 0.042033f;
+ 	val_dir[8173*3 + 0] = -0.353096f;	val_dir[8173*3 + 1] = 0.934665f;	val_dir[8173*3 + 2] = 0.041541f;
+ 	val_dir[8174*3 + 0] = -0.328244f;	val_dir[8174*3 + 1] = 0.943701f;	val_dir[8174*3 + 2] = 0.041030f;
+ 	val_dir[8175*3 + 0] = -0.303791f;	val_dir[8175*3 + 1] = 0.951877f;	val_dir[8175*3 + 2] = 0.040505f;
+ 	val_dir[8176*3 + 0] = -0.279776f;	val_dir[8176*3 + 1] = 0.959233f;	val_dir[8176*3 + 2] = 0.039968f;
+ 	val_dir[8177*3 + 0] = -0.256235f;	val_dir[8177*3 + 1] = 0.965810f;	val_dir[8177*3 + 2] = 0.039421f;
+ 	val_dir[8178*3 + 0] = -0.233197f;	val_dir[8178*3 + 1] = 0.971653f;	val_dir[8178*3 + 2] = 0.038866f;
+ 	val_dir[8179*3 + 0] = -0.210683f;	val_dir[8179*3 + 1] = 0.976804f;	val_dir[8179*3 + 2] = 0.038306f;
+ 	val_dir[8180*3 + 0] = -0.188713f;	val_dir[8180*3 + 1] = 0.981307f;	val_dir[8180*3 + 2] = 0.037743f;
+ 	val_dir[8181*3 + 0] = -0.167299f;	val_dir[8181*3 + 1] = 0.985205f;	val_dir[8181*3 + 2] = 0.037178f;
+ 	val_dir[8182*3 + 0] = -0.146450f;	val_dir[8182*3 + 1] = 0.988540f;	val_dir[8182*3 + 2] = 0.036613f;
+ 	val_dir[8183*3 + 0] = -0.126172f;	val_dir[8183*3 + 1] = 0.991353f;	val_dir[8183*3 + 2] = 0.036049f;
+ 	val_dir[8184*3 + 0] = -0.106466f;	val_dir[8184*3 + 1] = 0.993683f;	val_dir[8184*3 + 2] = 0.035489f;
+ 	val_dir[8185*3 + 0] = -0.087330f;	val_dir[8185*3 + 1] = 0.995567f;	val_dir[8185*3 + 2] = 0.034932f;
+ 	val_dir[8186*3 + 0] = -0.068761f;	val_dir[8186*3 + 1] = 0.997041f;	val_dir[8186*3 + 2] = 0.034381f;
+ 	val_dir[8187*3 + 0] = -0.050753f;	val_dir[8187*3 + 1] = 0.998138f;	val_dir[8187*3 + 2] = 0.033835f;
+ 	val_dir[8188*3 + 0] = -0.033296f;	val_dir[8188*3 + 1] = 0.998891f;	val_dir[8188*3 + 2] = 0.033296f;
+ 	val_dir[8189*3 + 0] = -0.016382f;	val_dir[8189*3 + 1] = 0.999329f;	val_dir[8189*3 + 2] = 0.032765f;
+ 	val_dir[8190*3 + 0] = 0.0f;	val_dir[8190*3 + 1] = 0.999480f;	val_dir[8190*3 + 2] = 0.032241f;
+ 	val_dir[8191*3 + 0] = 0.015871f;	val_dir[8191*3 + 1] = 0.999874f;	val_dir[8191*3 + 2] = 0.0f;
+ 	val_dir[8192*3 + 0] = -0.999874f;	val_dir[8192*3 + 1] = 0.0f;	val_dir[8192*3 + 2] = 0.015871f;
+ 	val_dir[8193*3 + 0] = -0.999740f;	val_dir[8193*3 + 1] = 0.016125f;	val_dir[8193*3 + 2] = 0.016125f;
+ 	val_dir[8194*3 + 0] = -0.999329f;	val_dir[8194*3 + 1] = 0.032765f;	val_dir[8194*3 + 2] = 0.016382f;
+ 	val_dir[8195*3 + 0] = -0.998614f;	val_dir[8195*3 + 1] = 0.049931f;	val_dir[8195*3 + 2] = 0.016644f;
+ 	val_dir[8196*3 + 0] = -0.997567f;	val_dir[8196*3 + 1] = 0.067632f;	val_dir[8196*3 + 2] = 0.016908f;
+ 	val_dir[8197*3 + 0] = -0.996158f;	val_dir[8197*3 + 1] = 0.085876f;	val_dir[8197*3 + 2] = 0.017175f;
+ 	val_dir[8198*3 + 0] = -0.994354f;	val_dir[8198*3 + 1] = 0.104669f;	val_dir[8198*3 + 2] = 0.017445f;
+ 	val_dir[8199*3 + 0] = -0.992122f;	val_dir[8199*3 + 1] = 0.124015f;	val_dir[8199*3 + 2] = 0.017716f;
+ 	val_dir[8200*3 + 0] = -0.989426f;	val_dir[8200*3 + 1] = 0.143917f;	val_dir[8200*3 + 2] = 0.017990f;
+ 	val_dir[8201*3 + 0] = -0.986229f;	val_dir[8201*3 + 1] = 0.164372f;	val_dir[8201*3 + 2] = 0.018264f;
+ 	val_dir[8202*3 + 0] = -0.982493f;	val_dir[8202*3 + 1] = 0.185376f;	val_dir[8202*3 + 2] = 0.018538f;
+ 	val_dir[8203*3 + 0] = -0.978177f;	val_dir[8203*3 + 1] = 0.206922f;	val_dir[8203*3 + 2] = 0.018811f;
+ 	val_dir[8204*3 + 0] = -0.973240f;	val_dir[8204*3 + 1] = 0.228998f;	val_dir[8204*3 + 2] = 0.019083f;
+ 	val_dir[8205*3 + 0] = -0.967641f;	val_dir[8205*3 + 1] = 0.251587f;	val_dir[8205*3 + 2] = 0.019353f;
+ 	val_dir[8206*3 + 0] = -0.961339f;	val_dir[8206*3 + 1] = 0.274668f;	val_dir[8206*3 + 2] = 0.019619f;
+ 	val_dir[8207*3 + 0] = -0.954291f;	val_dir[8207*3 + 1] = 0.298216f;	val_dir[8207*3 + 2] = 0.019881f;
+ 	val_dir[8208*3 + 0] = -0.946458f;	val_dir[8208*3 + 1] = 0.322198f;	val_dir[8208*3 + 2] = 0.020137f;
+ 	val_dir[8209*3 + 0] = -0.93780f;	val_dir[8209*3 + 1] = 0.346578f;	val_dir[8209*3 + 2] = 0.020387f;
+ 	val_dir[8210*3 + 0] = -0.928279f;	val_dir[8210*3 + 1] = 0.371312f;	val_dir[8210*3 + 2] = 0.020628f;
+ 	val_dir[8211*3 + 0] = -0.917863f;	val_dir[8211*3 + 1] = 0.396350f;	val_dir[8211*3 + 2] = 0.020861f;
+ 	val_dir[8212*3 + 0] = -0.906520f;	val_dir[8212*3 + 1] = 0.421637f;	val_dir[8212*3 + 2] = 0.021082f;
+ 	val_dir[8213*3 + 0] = -0.894224f;	val_dir[8213*3 + 1] = 0.447112f;	val_dir[8213*3 + 2] = 0.021291f;
+ 	val_dir[8214*3 + 0] = -0.880957f;	val_dir[8214*3 + 1] = 0.472709f;	val_dir[8214*3 + 2] = 0.021487f;
+ 	val_dir[8215*3 + 0] = -0.866703f;	val_dir[8215*3 + 1] = 0.498354f;	val_dir[8215*3 + 2] = 0.021668f;
+ 	val_dir[8216*3 + 0] = -0.851455f;	val_dir[8216*3 + 1] = 0.523973f;	val_dir[8216*3 + 2] = 0.021832f;
+ 	val_dir[8217*3 + 0] = -0.835215f;	val_dir[8217*3 + 1] = 0.549484f;	val_dir[8217*3 + 2] = 0.021979f;
+ 	val_dir[8218*3 + 0] = -0.817992f;	val_dir[8218*3 + 1] = 0.574805f;	val_dir[8218*3 + 2] = 0.022108f;
+ 	val_dir[8219*3 + 0] = -0.799803f;	val_dir[8219*3 + 1] = 0.599852f;	val_dir[8219*3 + 2] = 0.022217f;
+ 	val_dir[8220*3 + 0] = -0.780675f;	val_dir[8220*3 + 1] = 0.624540f;	val_dir[8220*3 + 2] = 0.022305f;
+ 	val_dir[8221*3 + 0] = -0.760644f;	val_dir[8221*3 + 1] = 0.648784f;	val_dir[8221*3 + 2] = 0.022372f;
+ 	val_dir[8222*3 + 0] = -0.739754f;	val_dir[8222*3 + 1] = 0.672504f;	val_dir[8222*3 + 2] = 0.022417f;
+ 	val_dir[8223*3 + 0] = -0.718059f;	val_dir[8223*3 + 1] = 0.695620f;	val_dir[8223*3 + 2] = 0.022439f;
+ 	val_dir[8224*3 + 0] = -0.695620f;	val_dir[8224*3 + 1] = 0.718059f;	val_dir[8224*3 + 2] = 0.022439f;
+ 	val_dir[8225*3 + 0] = -0.672504f;	val_dir[8225*3 + 1] = 0.739754f;	val_dir[8225*3 + 2] = 0.022417f;
+ 	val_dir[8226*3 + 0] = -0.648784f;	val_dir[8226*3 + 1] = 0.760644f;	val_dir[8226*3 + 2] = 0.022372f;
+ 	val_dir[8227*3 + 0] = -0.624540f;	val_dir[8227*3 + 1] = 0.780675f;	val_dir[8227*3 + 2] = 0.022305f;
+ 	val_dir[8228*3 + 0] = -0.599852f;	val_dir[8228*3 + 1] = 0.799803f;	val_dir[8228*3 + 2] = 0.022217f;
+ 	val_dir[8229*3 + 0] = -0.574805f;	val_dir[8229*3 + 1] = 0.817992f;	val_dir[8229*3 + 2] = 0.022108f;
+ 	val_dir[8230*3 + 0] = -0.549484f;	val_dir[8230*3 + 1] = 0.835215f;	val_dir[8230*3 + 2] = 0.021979f;
+ 	val_dir[8231*3 + 0] = -0.523973f;	val_dir[8231*3 + 1] = 0.851455f;	val_dir[8231*3 + 2] = 0.021832f;
+ 	val_dir[8232*3 + 0] = -0.498354f;	val_dir[8232*3 + 1] = 0.866703f;	val_dir[8232*3 + 2] = 0.021668f;
+ 	val_dir[8233*3 + 0] = -0.472709f;	val_dir[8233*3 + 1] = 0.880957f;	val_dir[8233*3 + 2] = 0.021487f;
+ 	val_dir[8234*3 + 0] = -0.447112f;	val_dir[8234*3 + 1] = 0.894224f;	val_dir[8234*3 + 2] = 0.021291f;
+ 	val_dir[8235*3 + 0] = -0.421637f;	val_dir[8235*3 + 1] = 0.906520f;	val_dir[8235*3 + 2] = 0.021082f;
+ 	val_dir[8236*3 + 0] = -0.396350f;	val_dir[8236*3 + 1] = 0.917863f;	val_dir[8236*3 + 2] = 0.020861f;
+ 	val_dir[8237*3 + 0] = -0.371312f;	val_dir[8237*3 + 1] = 0.928279f;	val_dir[8237*3 + 2] = 0.020628f;
+ 	val_dir[8238*3 + 0] = -0.346578f;	val_dir[8238*3 + 1] = 0.93780f;	val_dir[8238*3 + 2] = 0.020387f;
+ 	val_dir[8239*3 + 0] = -0.322198f;	val_dir[8239*3 + 1] = 0.946458f;	val_dir[8239*3 + 2] = 0.020137f;
+ 	val_dir[8240*3 + 0] = -0.298216f;	val_dir[8240*3 + 1] = 0.954291f;	val_dir[8240*3 + 2] = 0.019881f;
+ 	val_dir[8241*3 + 0] = -0.274668f;	val_dir[8241*3 + 1] = 0.961339f;	val_dir[8241*3 + 2] = 0.019619f;
+ 	val_dir[8242*3 + 0] = -0.251587f;	val_dir[8242*3 + 1] = 0.967641f;	val_dir[8242*3 + 2] = 0.019353f;
+ 	val_dir[8243*3 + 0] = -0.228998f;	val_dir[8243*3 + 1] = 0.973240f;	val_dir[8243*3 + 2] = 0.019083f;
+ 	val_dir[8244*3 + 0] = -0.206922f;	val_dir[8244*3 + 1] = 0.978177f;	val_dir[8244*3 + 2] = 0.018811f;
+ 	val_dir[8245*3 + 0] = -0.185376f;	val_dir[8245*3 + 1] = 0.982493f;	val_dir[8245*3 + 2] = 0.018538f;
+ 	val_dir[8246*3 + 0] = -0.164372f;	val_dir[8246*3 + 1] = 0.986229f;	val_dir[8246*3 + 2] = 0.018264f;
+ 	val_dir[8247*3 + 0] = -0.143917f;	val_dir[8247*3 + 1] = 0.989426f;	val_dir[8247*3 + 2] = 0.017990f;
+ 	val_dir[8248*3 + 0] = -0.124015f;	val_dir[8248*3 + 1] = 0.992122f;	val_dir[8248*3 + 2] = 0.017716f;
+ 	val_dir[8249*3 + 0] = -0.104669f;	val_dir[8249*3 + 1] = 0.994354f;	val_dir[8249*3 + 2] = 0.017445f;
+ 	val_dir[8250*3 + 0] = -0.085876f;	val_dir[8250*3 + 1] = 0.996158f;	val_dir[8250*3 + 2] = 0.017175f;
+ 	val_dir[8251*3 + 0] = -0.067632f;	val_dir[8251*3 + 1] = 0.997567f;	val_dir[8251*3 + 2] = 0.016908f;
+ 	val_dir[8252*3 + 0] = -0.049931f;	val_dir[8252*3 + 1] = 0.998614f;	val_dir[8252*3 + 2] = 0.016644f;
+ 	val_dir[8253*3 + 0] = -0.032765f;	val_dir[8253*3 + 1] = 0.999329f;	val_dir[8253*3 + 2] = 0.016382f;
+ 	val_dir[8254*3 + 0] = -0.016125f;	val_dir[8254*3 + 1] = 0.999740f;	val_dir[8254*3 + 2] = 0.016125f;
+ 	val_dir[8255*3 + 0] = 0.0f;	val_dir[8255*3 + 1] = 0.999874f;	val_dir[8255*3 + 2] = 0.015871f;
+ 	val_dir[8256*3 + 0] = -1.0f;	val_dir[8256*3 + 1] = 0.0f;	val_dir[8256*3 + 2] = 0.0f;
+ 	val_dir[8257*3 + 0] = -0.999874f;	val_dir[8257*3 + 1] = 0.015871f;	val_dir[8257*3 + 2] = 0.0f;
+ 	val_dir[8258*3 + 0] = -0.999480f;	val_dir[8258*3 + 1] = 0.032241f;	val_dir[8258*3 + 2] = 0.0f;
+ 	val_dir[8259*3 + 0] = -0.998793f;	val_dir[8259*3 + 1] = 0.049121f;	val_dir[8259*3 + 2] = 0.0f;
+ 	val_dir[8260*3 + 0] = -0.997785f;	val_dir[8260*3 + 1] = 0.066519f;	val_dir[8260*3 + 2] = 0.0f;
+ 	val_dir[8261*3 + 0] = -0.996428f;	val_dir[8261*3 + 1] = 0.084443f;	val_dir[8261*3 + 2] = 0.0f;
+ 	val_dir[8262*3 + 0] = -0.994692f;	val_dir[8262*3 + 1] = 0.102899f;	val_dir[8262*3 + 2] = 0.0f;
+ 	val_dir[8263*3 + 0] = -0.992543f;	val_dir[8263*3 + 1] = 0.121891f;	val_dir[8263*3 + 2] = 0.0f;
+ 	val_dir[8264*3 + 0] = -0.989949f;	val_dir[8264*3 + 1] = 0.141421f;	val_dir[8264*3 + 2] = 0.0f;
+ 	val_dir[8265*3 + 0] = -0.986875f;	val_dir[8265*3 + 1] = 0.161489f;	val_dir[8265*3 + 2] = 0.0f;
+ 	val_dir[8266*3 + 0] = -0.983282f;	val_dir[8266*3 + 1] = 0.182089f;	val_dir[8266*3 + 2] = 0.0f;
+ 	val_dir[8267*3 + 0] = -0.979134f;	val_dir[8267*3 + 1] = 0.203216f;	val_dir[8267*3 + 2] = 0.0f;
+ 	val_dir[8268*3 + 0] = -0.974391f;	val_dir[8268*3 + 1] = 0.224860f;	val_dir[8268*3 + 2] = 0.0f;
+ 	val_dir[8269*3 + 0] = -0.969015f;	val_dir[8269*3 + 1] = 0.247004f;	val_dir[8269*3 + 2] = 0.0f;
+ 	val_dir[8270*3 + 0] = -0.962964f;	val_dir[8270*3 + 1] = 0.269630f;	val_dir[8270*3 + 2] = 0.0f;
+ 	val_dir[8271*3 + 0] = -0.95620f;	val_dir[8271*3 + 1] = 0.292714f;	val_dir[8271*3 + 2] = 0.0f;
+ 	val_dir[8272*3 + 0] = -0.948683f;	val_dir[8272*3 + 1] = 0.316228f;	val_dir[8272*3 + 2] = 0.0f;
+ 	val_dir[8273*3 + 0] = -0.940376f;	val_dir[8273*3 + 1] = 0.340136f;	val_dir[8273*3 + 2] = 0.0f;
+ 	val_dir[8274*3 + 0] = -0.931243f;	val_dir[8274*3 + 1] = 0.364399f;	val_dir[8274*3 + 2] = 0.0f;
+ 	val_dir[8275*3 + 0] = -0.921250f;	val_dir[8275*3 + 1] = 0.388972f;	val_dir[8275*3 + 2] = 0.0f;
+ 	val_dir[8276*3 + 0] = -0.910366f;	val_dir[8276*3 + 1] = 0.413803f;	val_dir[8276*3 + 2] = 0.0f;
+ 	val_dir[8277*3 + 0] = -0.898567f;	val_dir[8277*3 + 1] = 0.438835f;	val_dir[8277*3 + 2] = 0.0f;
+ 	val_dir[8278*3 + 0] = -0.885832f;	val_dir[8278*3 + 1] = 0.464007f;	val_dir[8278*3 + 2] = 0.0f;
+ 	val_dir[8279*3 + 0] = -0.872143f;	val_dir[8279*3 + 1] = 0.489251f;	val_dir[8279*3 + 2] = 0.0f;
+ 	val_dir[8280*3 + 0] = -0.857493f;	val_dir[8280*3 + 1] = 0.514496f;	val_dir[8280*3 + 2] = 0.0f;
+ 	val_dir[8281*3 + 0] = -0.841879f;	val_dir[8281*3 + 1] = 0.539666f;	val_dir[8281*3 + 2] = 0.0f;
+ 	val_dir[8282*3 + 0] = -0.825307f;	val_dir[8282*3 + 1] = 0.564684f;	val_dir[8282*3 + 2] = 0.0f;
+ 	val_dir[8283*3 + 0] = -0.807791f;	val_dir[8283*3 + 1] = 0.589469f;	val_dir[8283*3 + 2] = 0.0f;
+ 	val_dir[8284*3 + 0] = -0.789352f;	val_dir[8284*3 + 1] = 0.613941f;	val_dir[8284*3 + 2] = 0.0f;
+ 	val_dir[8285*3 + 0] = -0.770022f;	val_dir[8285*3 + 1] = 0.638018f;	val_dir[8285*3 + 2] = 0.0f;
+ 	val_dir[8286*3 + 0] = -0.749838f;	val_dir[8286*3 + 1] = 0.661622f;	val_dir[8286*3 + 2] = 0.0f;
+ 	val_dir[8287*3 + 0] = -0.728848f;	val_dir[8287*3 + 1] = 0.684675f;	val_dir[8287*3 + 2] = 0.0f;
+ 	val_dir[8288*3 + 0] = -0.707107f;	val_dir[8288*3 + 1] = 0.707107f;	val_dir[8288*3 + 2] = 0.0f;
+ 	val_dir[8289*3 + 0] = -0.684675f;	val_dir[8289*3 + 1] = 0.728848f;	val_dir[8289*3 + 2] = 0.0f;
+ 	val_dir[8290*3 + 0] = -0.661622f;	val_dir[8290*3 + 1] = 0.749838f;	val_dir[8290*3 + 2] = 0.0f;
+ 	val_dir[8291*3 + 0] = -0.638018f;	val_dir[8291*3 + 1] = 0.770022f;	val_dir[8291*3 + 2] = 0.0f;
+ 	val_dir[8292*3 + 0] = -0.613941f;	val_dir[8292*3 + 1] = 0.789352f;	val_dir[8292*3 + 2] = 0.0f;
+ 	val_dir[8293*3 + 0] = -0.589469f;	val_dir[8293*3 + 1] = 0.807791f;	val_dir[8293*3 + 2] = 0.0f;
+ 	val_dir[8294*3 + 0] = -0.564684f;	val_dir[8294*3 + 1] = 0.825307f;	val_dir[8294*3 + 2] = 0.0f;
+ 	val_dir[8295*3 + 0] = -0.539666f;	val_dir[8295*3 + 1] = 0.841879f;	val_dir[8295*3 + 2] = 0.0f;
+ 	val_dir[8296*3 + 0] = -0.514496f;	val_dir[8296*3 + 1] = 0.857493f;	val_dir[8296*3 + 2] = 0.0f;
+ 	val_dir[8297*3 + 0] = -0.489251f;	val_dir[8297*3 + 1] = 0.872143f;	val_dir[8297*3 + 2] = 0.0f;
+ 	val_dir[8298*3 + 0] = -0.464007f;	val_dir[8298*3 + 1] = 0.885832f;	val_dir[8298*3 + 2] = 0.0f;
+ 	val_dir[8299*3 + 0] = -0.438835f;	val_dir[8299*3 + 1] = 0.898567f;	val_dir[8299*3 + 2] = 0.0f;
+ 	val_dir[8300*3 + 0] = -0.413803f;	val_dir[8300*3 + 1] = 0.910366f;	val_dir[8300*3 + 2] = 0.0f;
+ 	val_dir[8301*3 + 0] = -0.388972f;	val_dir[8301*3 + 1] = 0.921250f;	val_dir[8301*3 + 2] = 0.0f;
+ 	val_dir[8302*3 + 0] = -0.364399f;	val_dir[8302*3 + 1] = 0.931243f;	val_dir[8302*3 + 2] = 0.0f;
+ 	val_dir[8303*3 + 0] = -0.340136f;	val_dir[8303*3 + 1] = 0.940376f;	val_dir[8303*3 + 2] = 0.0f;
+ 	val_dir[8304*3 + 0] = -0.316228f;	val_dir[8304*3 + 1] = 0.948683f;	val_dir[8304*3 + 2] = 0.0f;
+ 	val_dir[8305*3 + 0] = -0.292714f;	val_dir[8305*3 + 1] = 0.95620f;	val_dir[8305*3 + 2] = 0.0f;
+ 	val_dir[8306*3 + 0] = -0.269630f;	val_dir[8306*3 + 1] = 0.962964f;	val_dir[8306*3 + 2] = 0.0f;
+ 	val_dir[8307*3 + 0] = -0.247004f;	val_dir[8307*3 + 1] = 0.969015f;	val_dir[8307*3 + 2] = 0.0f;
+ 	val_dir[8308*3 + 0] = -0.224860f;	val_dir[8308*3 + 1] = 0.974391f;	val_dir[8308*3 + 2] = 0.0f;
+ 	val_dir[8309*3 + 0] = -0.203216f;	val_dir[8309*3 + 1] = 0.979134f;	val_dir[8309*3 + 2] = 0.0f;
+ 	val_dir[8310*3 + 0] = -0.182089f;	val_dir[8310*3 + 1] = 0.983282f;	val_dir[8310*3 + 2] = 0.0f;
+ 	val_dir[8311*3 + 0] = -0.161489f;	val_dir[8311*3 + 1] = 0.986875f;	val_dir[8311*3 + 2] = 0.0f;
+ 	val_dir[8312*3 + 0] = -0.141421f;	val_dir[8312*3 + 1] = 0.989949f;	val_dir[8312*3 + 2] = 0.0f;
+ 	val_dir[8313*3 + 0] = -0.121891f;	val_dir[8313*3 + 1] = 0.992543f;	val_dir[8313*3 + 2] = 0.0f;
+ 	val_dir[8314*3 + 0] = -0.102899f;	val_dir[8314*3 + 1] = 0.994692f;	val_dir[8314*3 + 2] = 0.0f;
+ 	val_dir[8315*3 + 0] = -0.084443f;	val_dir[8315*3 + 1] = 0.996428f;	val_dir[8315*3 + 2] = 0.0f;
+ 	val_dir[8316*3 + 0] = -0.066519f;	val_dir[8316*3 + 1] = 0.997785f;	val_dir[8316*3 + 2] = 0.0f;
+ 	val_dir[8317*3 + 0] = -0.049121f;	val_dir[8317*3 + 1] = 0.998793f;	val_dir[8317*3 + 2] = 0.0f;
+ 	val_dir[8318*3 + 0] = -0.032241f;	val_dir[8318*3 + 1] = 0.999480f;	val_dir[8318*3 + 2] = 0.0f;
+ 	val_dir[8319*3 + 0] = -0.015871f;	val_dir[8319*3 + 1] = 0.999874f;	val_dir[8319*3 + 2] = 0.0f;
+ 	val_dir[8320*3 + 0] = 0.0f;	val_dir[8320*3 + 1] = 1.0f;	val_dir[8320*3 + 2] = 0.0f;
+ 	val_dir[8321*3 + 0] = 0.0f;	val_dir[8321*3 + 1] = -1.0f;	val_dir[8321*3 + 2] = 0.0f;
+ 	val_dir[8322*3 + 0] = 0.015871f;	val_dir[8322*3 + 1] = -0.999874f;	val_dir[8322*3 + 2] = 0.0f;
+ 	val_dir[8323*3 + 0] = 0.032241f;	val_dir[8323*3 + 1] = -0.999480f;	val_dir[8323*3 + 2] = 0.0f;
+ 	val_dir[8324*3 + 0] = 0.049121f;	val_dir[8324*3 + 1] = -0.998793f;	val_dir[8324*3 + 2] = 0.0f;
+ 	val_dir[8325*3 + 0] = 0.066519f;	val_dir[8325*3 + 1] = -0.997785f;	val_dir[8325*3 + 2] = 0.0f;
+ 	val_dir[8326*3 + 0] = 0.084443f;	val_dir[8326*3 + 1] = -0.996428f;	val_dir[8326*3 + 2] = 0.0f;
+ 	val_dir[8327*3 + 0] = 0.102899f;	val_dir[8327*3 + 1] = -0.994692f;	val_dir[8327*3 + 2] = 0.0f;
+ 	val_dir[8328*3 + 0] = 0.121891f;	val_dir[8328*3 + 1] = -0.992543f;	val_dir[8328*3 + 2] = 0.0f;
+ 	val_dir[8329*3 + 0] = 0.141421f;	val_dir[8329*3 + 1] = -0.989949f;	val_dir[8329*3 + 2] = 0.0f;
+ 	val_dir[8330*3 + 0] = 0.161489f;	val_dir[8330*3 + 1] = -0.986875f;	val_dir[8330*3 + 2] = 0.0f;
+ 	val_dir[8331*3 + 0] = 0.182089f;	val_dir[8331*3 + 1] = -0.983282f;	val_dir[8331*3 + 2] = 0.0f;
+ 	val_dir[8332*3 + 0] = 0.203216f;	val_dir[8332*3 + 1] = -0.979134f;	val_dir[8332*3 + 2] = 0.0f;
+ 	val_dir[8333*3 + 0] = 0.224860f;	val_dir[8333*3 + 1] = -0.974391f;	val_dir[8333*3 + 2] = 0.0f;
+ 	val_dir[8334*3 + 0] = 0.247004f;	val_dir[8334*3 + 1] = -0.969015f;	val_dir[8334*3 + 2] = 0.0f;
+ 	val_dir[8335*3 + 0] = 0.269630f;	val_dir[8335*3 + 1] = -0.962964f;	val_dir[8335*3 + 2] = 0.0f;
+ 	val_dir[8336*3 + 0] = 0.292714f;	val_dir[8336*3 + 1] = -0.95620f;	val_dir[8336*3 + 2] = 0.0f;
+ 	val_dir[8337*3 + 0] = 0.316228f;	val_dir[8337*3 + 1] = -0.948683f;	val_dir[8337*3 + 2] = 0.0f;
+ 	val_dir[8338*3 + 0] = 0.340136f;	val_dir[8338*3 + 1] = -0.940376f;	val_dir[8338*3 + 2] = 0.0f;
+ 	val_dir[8339*3 + 0] = 0.364399f;	val_dir[8339*3 + 1] = -0.931243f;	val_dir[8339*3 + 2] = 0.0f;
+ 	val_dir[8340*3 + 0] = 0.388972f;	val_dir[8340*3 + 1] = -0.921250f;	val_dir[8340*3 + 2] = 0.0f;
+ 	val_dir[8341*3 + 0] = 0.413803f;	val_dir[8341*3 + 1] = -0.910366f;	val_dir[8341*3 + 2] = 0.0f;
+ 	val_dir[8342*3 + 0] = 0.438835f;	val_dir[8342*3 + 1] = -0.898567f;	val_dir[8342*3 + 2] = 0.0f;
+ 	val_dir[8343*3 + 0] = 0.464007f;	val_dir[8343*3 + 1] = -0.885832f;	val_dir[8343*3 + 2] = 0.0f;
+ 	val_dir[8344*3 + 0] = 0.489251f;	val_dir[8344*3 + 1] = -0.872143f;	val_dir[8344*3 + 2] = 0.0f;
+ 	val_dir[8345*3 + 0] = 0.514496f;	val_dir[8345*3 + 1] = -0.857493f;	val_dir[8345*3 + 2] = 0.0f;
+ 	val_dir[8346*3 + 0] = 0.539666f;	val_dir[8346*3 + 1] = -0.841879f;	val_dir[8346*3 + 2] = 0.0f;
+ 	val_dir[8347*3 + 0] = 0.564684f;	val_dir[8347*3 + 1] = -0.825307f;	val_dir[8347*3 + 2] = 0.0f;
+ 	val_dir[8348*3 + 0] = 0.589469f;	val_dir[8348*3 + 1] = -0.807791f;	val_dir[8348*3 + 2] = 0.0f;
+ 	val_dir[8349*3 + 0] = 0.613941f;	val_dir[8349*3 + 1] = -0.789352f;	val_dir[8349*3 + 2] = 0.0f;
+ 	val_dir[8350*3 + 0] = 0.638018f;	val_dir[8350*3 + 1] = -0.770022f;	val_dir[8350*3 + 2] = 0.0f;
+ 	val_dir[8351*3 + 0] = 0.661622f;	val_dir[8351*3 + 1] = -0.749838f;	val_dir[8351*3 + 2] = 0.0f;
+ 	val_dir[8352*3 + 0] = 0.684675f;	val_dir[8352*3 + 1] = -0.728848f;	val_dir[8352*3 + 2] = 0.0f;
+ 	val_dir[8353*3 + 0] = 0.707107f;	val_dir[8353*3 + 1] = -0.707107f;	val_dir[8353*3 + 2] = 0.0f;
+ 	val_dir[8354*3 + 0] = 0.728848f;	val_dir[8354*3 + 1] = -0.684675f;	val_dir[8354*3 + 2] = 0.0f;
+ 	val_dir[8355*3 + 0] = 0.749838f;	val_dir[8355*3 + 1] = -0.661622f;	val_dir[8355*3 + 2] = 0.0f;
+ 	val_dir[8356*3 + 0] = 0.770022f;	val_dir[8356*3 + 1] = -0.638018f;	val_dir[8356*3 + 2] = 0.0f;
+ 	val_dir[8357*3 + 0] = 0.789352f;	val_dir[8357*3 + 1] = -0.613941f;	val_dir[8357*3 + 2] = 0.0f;
+ 	val_dir[8358*3 + 0] = 0.807791f;	val_dir[8358*3 + 1] = -0.589469f;	val_dir[8358*3 + 2] = 0.0f;
+ 	val_dir[8359*3 + 0] = 0.825307f;	val_dir[8359*3 + 1] = -0.564684f;	val_dir[8359*3 + 2] = 0.0f;
+ 	val_dir[8360*3 + 0] = 0.841879f;	val_dir[8360*3 + 1] = -0.539666f;	val_dir[8360*3 + 2] = 0.0f;
+ 	val_dir[8361*3 + 0] = 0.857493f;	val_dir[8361*3 + 1] = -0.514496f;	val_dir[8361*3 + 2] = 0.0f;
+ 	val_dir[8362*3 + 0] = 0.872143f;	val_dir[8362*3 + 1] = -0.489251f;	val_dir[8362*3 + 2] = 0.0f;
+ 	val_dir[8363*3 + 0] = 0.885832f;	val_dir[8363*3 + 1] = -0.464007f;	val_dir[8363*3 + 2] = 0.0f;
+ 	val_dir[8364*3 + 0] = 0.898567f;	val_dir[8364*3 + 1] = -0.438835f;	val_dir[8364*3 + 2] = 0.0f;
+ 	val_dir[8365*3 + 0] = 0.910366f;	val_dir[8365*3 + 1] = -0.413803f;	val_dir[8365*3 + 2] = 0.0f;
+ 	val_dir[8366*3 + 0] = 0.921250f;	val_dir[8366*3 + 1] = -0.388972f;	val_dir[8366*3 + 2] = 0.0f;
+ 	val_dir[8367*3 + 0] = 0.931243f;	val_dir[8367*3 + 1] = -0.364399f;	val_dir[8367*3 + 2] = 0.0f;
+ 	val_dir[8368*3 + 0] = 0.940376f;	val_dir[8368*3 + 1] = -0.340136f;	val_dir[8368*3 + 2] = 0.0f;
+ 	val_dir[8369*3 + 0] = 0.948683f;	val_dir[8369*3 + 1] = -0.316228f;	val_dir[8369*3 + 2] = 0.0f;
+ 	val_dir[8370*3 + 0] = 0.95620f;	val_dir[8370*3 + 1] = -0.292714f;	val_dir[8370*3 + 2] = 0.0f;
+ 	val_dir[8371*3 + 0] = 0.962964f;	val_dir[8371*3 + 1] = -0.269630f;	val_dir[8371*3 + 2] = 0.0f;
+ 	val_dir[8372*3 + 0] = 0.969015f;	val_dir[8372*3 + 1] = -0.247004f;	val_dir[8372*3 + 2] = 0.0f;
+ 	val_dir[8373*3 + 0] = 0.974391f;	val_dir[8373*3 + 1] = -0.224860f;	val_dir[8373*3 + 2] = 0.0f;
+ 	val_dir[8374*3 + 0] = 0.979134f;	val_dir[8374*3 + 1] = -0.203216f;	val_dir[8374*3 + 2] = 0.0f;
+ 	val_dir[8375*3 + 0] = 0.983282f;	val_dir[8375*3 + 1] = -0.182089f;	val_dir[8375*3 + 2] = 0.0f;
+ 	val_dir[8376*3 + 0] = 0.986875f;	val_dir[8376*3 + 1] = -0.161489f;	val_dir[8376*3 + 2] = 0.0f;
+ 	val_dir[8377*3 + 0] = 0.989949f;	val_dir[8377*3 + 1] = -0.141421f;	val_dir[8377*3 + 2] = 0.0f;
+ 	val_dir[8378*3 + 0] = 0.992543f;	val_dir[8378*3 + 1] = -0.121891f;	val_dir[8378*3 + 2] = 0.0f;
+ 	val_dir[8379*3 + 0] = 0.994692f;	val_dir[8379*3 + 1] = -0.102899f;	val_dir[8379*3 + 2] = 0.0f;
+ 	val_dir[8380*3 + 0] = 0.996428f;	val_dir[8380*3 + 1] = -0.084443f;	val_dir[8380*3 + 2] = 0.0f;
+ 	val_dir[8381*3 + 0] = 0.997785f;	val_dir[8381*3 + 1] = -0.066519f;	val_dir[8381*3 + 2] = 0.0f;
+ 	val_dir[8382*3 + 0] = 0.998793f;	val_dir[8382*3 + 1] = -0.049121f;	val_dir[8382*3 + 2] = 0.0f;
+ 	val_dir[8383*3 + 0] = 0.999480f;	val_dir[8383*3 + 1] = -0.032241f;	val_dir[8383*3 + 2] = 0.0f;
+ 	val_dir[8384*3 + 0] = 0.999874f;	val_dir[8384*3 + 1] = -0.015871f;	val_dir[8384*3 + 2] = 0.0f;
+ 	val_dir[8385*3 + 0] = 1.0f;	val_dir[8385*3 + 1] = 0.0f;	val_dir[8385*3 + 2] = 0.0f;
+ 	val_dir[8386*3 + 0] = 0.0f;	val_dir[8386*3 + 1] = -0.999874f;	val_dir[8386*3 + 2] = -0.015871f;
+ 	val_dir[8387*3 + 0] = 0.016125f;	val_dir[8387*3 + 1] = -0.999740f;	val_dir[8387*3 + 2] = -0.016125f;
+ 	val_dir[8388*3 + 0] = 0.032765f;	val_dir[8388*3 + 1] = -0.999329f;	val_dir[8388*3 + 2] = -0.016382f;
+ 	val_dir[8389*3 + 0] = 0.049931f;	val_dir[8389*3 + 1] = -0.998614f;	val_dir[8389*3 + 2] = -0.016644f;
+ 	val_dir[8390*3 + 0] = 0.067632f;	val_dir[8390*3 + 1] = -0.997567f;	val_dir[8390*3 + 2] = -0.016908f;
+ 	val_dir[8391*3 + 0] = 0.085876f;	val_dir[8391*3 + 1] = -0.996158f;	val_dir[8391*3 + 2] = -0.017175f;
+ 	val_dir[8392*3 + 0] = 0.104669f;	val_dir[8392*3 + 1] = -0.994354f;	val_dir[8392*3 + 2] = -0.017445f;
+ 	val_dir[8393*3 + 0] = 0.124015f;	val_dir[8393*3 + 1] = -0.992122f;	val_dir[8393*3 + 2] = -0.017716f;
+ 	val_dir[8394*3 + 0] = 0.143917f;	val_dir[8394*3 + 1] = -0.989426f;	val_dir[8394*3 + 2] = -0.017990f;
+ 	val_dir[8395*3 + 0] = 0.164372f;	val_dir[8395*3 + 1] = -0.986229f;	val_dir[8395*3 + 2] = -0.018264f;
+ 	val_dir[8396*3 + 0] = 0.185376f;	val_dir[8396*3 + 1] = -0.982493f;	val_dir[8396*3 + 2] = -0.018538f;
+ 	val_dir[8397*3 + 0] = 0.206922f;	val_dir[8397*3 + 1] = -0.978177f;	val_dir[8397*3 + 2] = -0.018811f;
+ 	val_dir[8398*3 + 0] = 0.228998f;	val_dir[8398*3 + 1] = -0.973240f;	val_dir[8398*3 + 2] = -0.019083f;
+ 	val_dir[8399*3 + 0] = 0.251587f;	val_dir[8399*3 + 1] = -0.967641f;	val_dir[8399*3 + 2] = -0.019353f;
+ 	val_dir[8400*3 + 0] = 0.274668f;	val_dir[8400*3 + 1] = -0.961339f;	val_dir[8400*3 + 2] = -0.019619f;
+ 	val_dir[8401*3 + 0] = 0.298216f;	val_dir[8401*3 + 1] = -0.954291f;	val_dir[8401*3 + 2] = -0.019881f;
+ 	val_dir[8402*3 + 0] = 0.322198f;	val_dir[8402*3 + 1] = -0.946458f;	val_dir[8402*3 + 2] = -0.020137f;
+ 	val_dir[8403*3 + 0] = 0.346578f;	val_dir[8403*3 + 1] = -0.93780f;	val_dir[8403*3 + 2] = -0.020387f;
+ 	val_dir[8404*3 + 0] = 0.371312f;	val_dir[8404*3 + 1] = -0.928279f;	val_dir[8404*3 + 2] = -0.020628f;
+ 	val_dir[8405*3 + 0] = 0.396350f;	val_dir[8405*3 + 1] = -0.917863f;	val_dir[8405*3 + 2] = -0.020861f;
+ 	val_dir[8406*3 + 0] = 0.421637f;	val_dir[8406*3 + 1] = -0.906520f;	val_dir[8406*3 + 2] = -0.021082f;
+ 	val_dir[8407*3 + 0] = 0.447112f;	val_dir[8407*3 + 1] = -0.894224f;	val_dir[8407*3 + 2] = -0.021291f;
+ 	val_dir[8408*3 + 0] = 0.472709f;	val_dir[8408*3 + 1] = -0.880957f;	val_dir[8408*3 + 2] = -0.021487f;
+ 	val_dir[8409*3 + 0] = 0.498354f;	val_dir[8409*3 + 1] = -0.866703f;	val_dir[8409*3 + 2] = -0.021668f;
+ 	val_dir[8410*3 + 0] = 0.523973f;	val_dir[8410*3 + 1] = -0.851455f;	val_dir[8410*3 + 2] = -0.021832f;
+ 	val_dir[8411*3 + 0] = 0.549484f;	val_dir[8411*3 + 1] = -0.835215f;	val_dir[8411*3 + 2] = -0.021979f;
+ 	val_dir[8412*3 + 0] = 0.574805f;	val_dir[8412*3 + 1] = -0.817992f;	val_dir[8412*3 + 2] = -0.022108f;
+ 	val_dir[8413*3 + 0] = 0.599852f;	val_dir[8413*3 + 1] = -0.799803f;	val_dir[8413*3 + 2] = -0.022217f;
+ 	val_dir[8414*3 + 0] = 0.624540f;	val_dir[8414*3 + 1] = -0.780675f;	val_dir[8414*3 + 2] = -0.022305f;
+ 	val_dir[8415*3 + 0] = 0.648784f;	val_dir[8415*3 + 1] = -0.760644f;	val_dir[8415*3 + 2] = -0.022372f;
+ 	val_dir[8416*3 + 0] = 0.672504f;	val_dir[8416*3 + 1] = -0.739754f;	val_dir[8416*3 + 2] = -0.022417f;
+ 	val_dir[8417*3 + 0] = 0.695620f;	val_dir[8417*3 + 1] = -0.718059f;	val_dir[8417*3 + 2] = -0.022439f;
+ 	val_dir[8418*3 + 0] = 0.718059f;	val_dir[8418*3 + 1] = -0.695620f;	val_dir[8418*3 + 2] = -0.022439f;
+ 	val_dir[8419*3 + 0] = 0.739754f;	val_dir[8419*3 + 1] = -0.672504f;	val_dir[8419*3 + 2] = -0.022417f;
+ 	val_dir[8420*3 + 0] = 0.760644f;	val_dir[8420*3 + 1] = -0.648784f;	val_dir[8420*3 + 2] = -0.022372f;
+ 	val_dir[8421*3 + 0] = 0.780675f;	val_dir[8421*3 + 1] = -0.624540f;	val_dir[8421*3 + 2] = -0.022305f;
+ 	val_dir[8422*3 + 0] = 0.799803f;	val_dir[8422*3 + 1] = -0.599852f;	val_dir[8422*3 + 2] = -0.022217f;
+ 	val_dir[8423*3 + 0] = 0.817992f;	val_dir[8423*3 + 1] = -0.574805f;	val_dir[8423*3 + 2] = -0.022108f;
+ 	val_dir[8424*3 + 0] = 0.835215f;	val_dir[8424*3 + 1] = -0.549484f;	val_dir[8424*3 + 2] = -0.021979f;
+ 	val_dir[8425*3 + 0] = 0.851455f;	val_dir[8425*3 + 1] = -0.523973f;	val_dir[8425*3 + 2] = -0.021832f;
+ 	val_dir[8426*3 + 0] = 0.866703f;	val_dir[8426*3 + 1] = -0.498354f;	val_dir[8426*3 + 2] = -0.021668f;
+ 	val_dir[8427*3 + 0] = 0.880957f;	val_dir[8427*3 + 1] = -0.472709f;	val_dir[8427*3 + 2] = -0.021487f;
+ 	val_dir[8428*3 + 0] = 0.894224f;	val_dir[8428*3 + 1] = -0.447112f;	val_dir[8428*3 + 2] = -0.021291f;
+ 	val_dir[8429*3 + 0] = 0.906520f;	val_dir[8429*3 + 1] = -0.421637f;	val_dir[8429*3 + 2] = -0.021082f;
+ 	val_dir[8430*3 + 0] = 0.917863f;	val_dir[8430*3 + 1] = -0.396350f;	val_dir[8430*3 + 2] = -0.020861f;
+ 	val_dir[8431*3 + 0] = 0.928279f;	val_dir[8431*3 + 1] = -0.371312f;	val_dir[8431*3 + 2] = -0.020628f;
+ 	val_dir[8432*3 + 0] = 0.93780f;	val_dir[8432*3 + 1] = -0.346578f;	val_dir[8432*3 + 2] = -0.020387f;
+ 	val_dir[8433*3 + 0] = 0.946458f;	val_dir[8433*3 + 1] = -0.322198f;	val_dir[8433*3 + 2] = -0.020137f;
+ 	val_dir[8434*3 + 0] = 0.954291f;	val_dir[8434*3 + 1] = -0.298216f;	val_dir[8434*3 + 2] = -0.019881f;
+ 	val_dir[8435*3 + 0] = 0.961339f;	val_dir[8435*3 + 1] = -0.274668f;	val_dir[8435*3 + 2] = -0.019619f;
+ 	val_dir[8436*3 + 0] = 0.967641f;	val_dir[8436*3 + 1] = -0.251587f;	val_dir[8436*3 + 2] = -0.019353f;
+ 	val_dir[8437*3 + 0] = 0.973240f;	val_dir[8437*3 + 1] = -0.228998f;	val_dir[8437*3 + 2] = -0.019083f;
+ 	val_dir[8438*3 + 0] = 0.978177f;	val_dir[8438*3 + 1] = -0.206922f;	val_dir[8438*3 + 2] = -0.018811f;
+ 	val_dir[8439*3 + 0] = 0.982493f;	val_dir[8439*3 + 1] = -0.185376f;	val_dir[8439*3 + 2] = -0.018538f;
+ 	val_dir[8440*3 + 0] = 0.986229f;	val_dir[8440*3 + 1] = -0.164372f;	val_dir[8440*3 + 2] = -0.018264f;
+ 	val_dir[8441*3 + 0] = 0.989426f;	val_dir[8441*3 + 1] = -0.143917f;	val_dir[8441*3 + 2] = -0.017990f;
+ 	val_dir[8442*3 + 0] = 0.992122f;	val_dir[8442*3 + 1] = -0.124015f;	val_dir[8442*3 + 2] = -0.017716f;
+ 	val_dir[8443*3 + 0] = 0.994354f;	val_dir[8443*3 + 1] = -0.104669f;	val_dir[8443*3 + 2] = -0.017445f;
+ 	val_dir[8444*3 + 0] = 0.996158f;	val_dir[8444*3 + 1] = -0.085876f;	val_dir[8444*3 + 2] = -0.017175f;
+ 	val_dir[8445*3 + 0] = 0.997567f;	val_dir[8445*3 + 1] = -0.067632f;	val_dir[8445*3 + 2] = -0.016908f;
+ 	val_dir[8446*3 + 0] = 0.998614f;	val_dir[8446*3 + 1] = -0.049931f;	val_dir[8446*3 + 2] = -0.016644f;
+ 	val_dir[8447*3 + 0] = 0.999329f;	val_dir[8447*3 + 1] = -0.032765f;	val_dir[8447*3 + 2] = -0.016382f;
+ 	val_dir[8448*3 + 0] = 0.999740f;	val_dir[8448*3 + 1] = -0.016125f;	val_dir[8448*3 + 2] = -0.016125f;
+ 	val_dir[8449*3 + 0] = 0.999874f;	val_dir[8449*3 + 1] = 0.0f;	val_dir[8449*3 + 2] = -0.015871f;
+ 	val_dir[8450*3 + 0] = -0.015871f;	val_dir[8450*3 + 1] = -0.999874f;	val_dir[8450*3 + 2] = 0.0f;
+ 	val_dir[8451*3 + 0] = 0.0f;	val_dir[8451*3 + 1] = -0.999480f;	val_dir[8451*3 + 2] = -0.032241f;
+ 	val_dir[8452*3 + 0] = 0.016382f;	val_dir[8452*3 + 1] = -0.999329f;	val_dir[8452*3 + 2] = -0.032765f;
+ 	val_dir[8453*3 + 0] = 0.033296f;	val_dir[8453*3 + 1] = -0.998891f;	val_dir[8453*3 + 2] = -0.033296f;
+ 	val_dir[8454*3 + 0] = 0.050753f;	val_dir[8454*3 + 1] = -0.998138f;	val_dir[8454*3 + 2] = -0.033835f;
+ 	val_dir[8455*3 + 0] = 0.068761f;	val_dir[8455*3 + 1] = -0.997041f;	val_dir[8455*3 + 2] = -0.034381f;
+ 	val_dir[8456*3 + 0] = 0.087330f;	val_dir[8456*3 + 1] = -0.995567f;	val_dir[8456*3 + 2] = -0.034932f;
+ 	val_dir[8457*3 + 0] = 0.106466f;	val_dir[8457*3 + 1] = -0.993683f;	val_dir[8457*3 + 2] = -0.035489f;
+ 	val_dir[8458*3 + 0] = 0.126172f;	val_dir[8458*3 + 1] = -0.991353f;	val_dir[8458*3 + 2] = -0.036049f;
+ 	val_dir[8459*3 + 0] = 0.146450f;	val_dir[8459*3 + 1] = -0.988540f;	val_dir[8459*3 + 2] = -0.036613f;
+ 	val_dir[8460*3 + 0] = 0.167299f;	val_dir[8460*3 + 1] = -0.985205f;	val_dir[8460*3 + 2] = -0.037178f;
+ 	val_dir[8461*3 + 0] = 0.188713f;	val_dir[8461*3 + 1] = -0.981307f;	val_dir[8461*3 + 2] = -0.037743f;
+ 	val_dir[8462*3 + 0] = 0.210683f;	val_dir[8462*3 + 1] = -0.976804f;	val_dir[8462*3 + 2] = -0.038306f;
+ 	val_dir[8463*3 + 0] = 0.233197f;	val_dir[8463*3 + 1] = -0.971653f;	val_dir[8463*3 + 2] = -0.038866f;
+ 	val_dir[8464*3 + 0] = 0.256235f;	val_dir[8464*3 + 1] = -0.965810f;	val_dir[8464*3 + 2] = -0.039421f;
+ 	val_dir[8465*3 + 0] = 0.279776f;	val_dir[8465*3 + 1] = -0.959233f;	val_dir[8465*3 + 2] = -0.039968f;
+ 	val_dir[8466*3 + 0] = 0.303791f;	val_dir[8466*3 + 1] = -0.951877f;	val_dir[8466*3 + 2] = -0.040505f;
+ 	val_dir[8467*3 + 0] = 0.328244f;	val_dir[8467*3 + 1] = -0.943701f;	val_dir[8467*3 + 2] = -0.041030f;
+ 	val_dir[8468*3 + 0] = 0.353096f;	val_dir[8468*3 + 1] = -0.934665f;	val_dir[8468*3 + 2] = -0.041541f;
+ 	val_dir[8469*3 + 0] = 0.378298f;	val_dir[8469*3 + 1] = -0.924729f;	val_dir[8469*3 + 2] = -0.042033f;
+ 	val_dir[8470*3 + 0] = 0.403799f;	val_dir[8470*3 + 1] = -0.913860f;	val_dir[8470*3 + 2] = -0.042505f;
+ 	val_dir[8471*3 + 0] = 0.429537f;	val_dir[8471*3 + 1] = -0.902027f;	val_dir[8471*3 + 2] = -0.042954f;
+ 	val_dir[8472*3 + 0] = 0.455447f;	val_dir[8472*3 + 1] = -0.889206f;	val_dir[8472*3 + 2] = -0.043376f;
+ 	val_dir[8473*3 + 0] = 0.481457f;	val_dir[8473*3 + 1] = -0.875376f;	val_dir[8473*3 + 2] = -0.043769f;
+ 	val_dir[8474*3 + 0] = 0.507490f;	val_dir[8474*3 + 1] = -0.860527f;	val_dir[8474*3 + 2] = -0.044130f;
+ 	val_dir[8475*3 + 0] = 0.533465f;	val_dir[8475*3 + 1] = -0.844653f;	val_dir[8475*3 + 2] = -0.044455f;
+ 	val_dir[8476*3 + 0] = 0.559297f;	val_dir[8476*3 + 1] = -0.827759f;	val_dir[8476*3 + 2] = -0.044744f;
+ 	val_dir[8477*3 + 0] = 0.584898f;	val_dir[8477*3 + 1] = -0.809858f;	val_dir[8477*3 + 2] = -0.044992f;
+ 	val_dir[8478*3 + 0] = 0.610179f;	val_dir[8478*3 + 1] = -0.790973f;	val_dir[8478*3 + 2] = -0.045198f;
+ 	val_dir[8479*3 + 0] = 0.635053f;	val_dir[8479*3 + 1] = -0.771136f;	val_dir[8479*3 + 2] = -0.045361f;
+ 	val_dir[8480*3 + 0] = 0.659432f;	val_dir[8480*3 + 1] = -0.750388f;	val_dir[8480*3 + 2] = -0.045478f;
+ 	val_dir[8481*3 + 0] = 0.683231f;	val_dir[8481*3 + 1] = -0.728780f;	val_dir[8481*3 + 2] = -0.045549f;
+ 	val_dir[8482*3 + 0] = 0.706372f;	val_dir[8482*3 + 1] = -0.706372f;	val_dir[8482*3 + 2] = -0.045572f;
+ 	val_dir[8483*3 + 0] = 0.728780f;	val_dir[8483*3 + 1] = -0.683231f;	val_dir[8483*3 + 2] = -0.045549f;
+ 	val_dir[8484*3 + 0] = 0.750388f;	val_dir[8484*3 + 1] = -0.659432f;	val_dir[8484*3 + 2] = -0.045478f;
+ 	val_dir[8485*3 + 0] = 0.771136f;	val_dir[8485*3 + 1] = -0.635053f;	val_dir[8485*3 + 2] = -0.045361f;
+ 	val_dir[8486*3 + 0] = 0.790973f;	val_dir[8486*3 + 1] = -0.610179f;	val_dir[8486*3 + 2] = -0.045198f;
+ 	val_dir[8487*3 + 0] = 0.809858f;	val_dir[8487*3 + 1] = -0.584898f;	val_dir[8487*3 + 2] = -0.044992f;
+ 	val_dir[8488*3 + 0] = 0.827759f;	val_dir[8488*3 + 1] = -0.559297f;	val_dir[8488*3 + 2] = -0.044744f;
+ 	val_dir[8489*3 + 0] = 0.844653f;	val_dir[8489*3 + 1] = -0.533465f;	val_dir[8489*3 + 2] = -0.044455f;
+ 	val_dir[8490*3 + 0] = 0.860527f;	val_dir[8490*3 + 1] = -0.507490f;	val_dir[8490*3 + 2] = -0.044130f;
+ 	val_dir[8491*3 + 0] = 0.875376f;	val_dir[8491*3 + 1] = -0.481457f;	val_dir[8491*3 + 2] = -0.043769f;
+ 	val_dir[8492*3 + 0] = 0.889206f;	val_dir[8492*3 + 1] = -0.455447f;	val_dir[8492*3 + 2] = -0.043376f;
+ 	val_dir[8493*3 + 0] = 0.902027f;	val_dir[8493*3 + 1] = -0.429537f;	val_dir[8493*3 + 2] = -0.042954f;
+ 	val_dir[8494*3 + 0] = 0.913860f;	val_dir[8494*3 + 1] = -0.403799f;	val_dir[8494*3 + 2] = -0.042505f;
+ 	val_dir[8495*3 + 0] = 0.924729f;	val_dir[8495*3 + 1] = -0.378298f;	val_dir[8495*3 + 2] = -0.042033f;
+ 	val_dir[8496*3 + 0] = 0.934665f;	val_dir[8496*3 + 1] = -0.353096f;	val_dir[8496*3 + 2] = -0.041541f;
+ 	val_dir[8497*3 + 0] = 0.943701f;	val_dir[8497*3 + 1] = -0.328244f;	val_dir[8497*3 + 2] = -0.041030f;
+ 	val_dir[8498*3 + 0] = 0.951877f;	val_dir[8498*3 + 1] = -0.303791f;	val_dir[8498*3 + 2] = -0.040505f;
+ 	val_dir[8499*3 + 0] = 0.959233f;	val_dir[8499*3 + 1] = -0.279776f;	val_dir[8499*3 + 2] = -0.039968f;
+ 	val_dir[8500*3 + 0] = 0.965810f;	val_dir[8500*3 + 1] = -0.256235f;	val_dir[8500*3 + 2] = -0.039421f;
+ 	val_dir[8501*3 + 0] = 0.971653f;	val_dir[8501*3 + 1] = -0.233197f;	val_dir[8501*3 + 2] = -0.038866f;
+ 	val_dir[8502*3 + 0] = 0.976804f;	val_dir[8502*3 + 1] = -0.210683f;	val_dir[8502*3 + 2] = -0.038306f;
+ 	val_dir[8503*3 + 0] = 0.981307f;	val_dir[8503*3 + 1] = -0.188713f;	val_dir[8503*3 + 2] = -0.037743f;
+ 	val_dir[8504*3 + 0] = 0.985205f;	val_dir[8504*3 + 1] = -0.167299f;	val_dir[8504*3 + 2] = -0.037178f;
+ 	val_dir[8505*3 + 0] = 0.988540f;	val_dir[8505*3 + 1] = -0.146450f;	val_dir[8505*3 + 2] = -0.036613f;
+ 	val_dir[8506*3 + 0] = 0.991353f;	val_dir[8506*3 + 1] = -0.126172f;	val_dir[8506*3 + 2] = -0.036049f;
+ 	val_dir[8507*3 + 0] = 0.993683f;	val_dir[8507*3 + 1] = -0.106466f;	val_dir[8507*3 + 2] = -0.035489f;
+ 	val_dir[8508*3 + 0] = 0.995567f;	val_dir[8508*3 + 1] = -0.087330f;	val_dir[8508*3 + 2] = -0.034932f;
+ 	val_dir[8509*3 + 0] = 0.997041f;	val_dir[8509*3 + 1] = -0.068761f;	val_dir[8509*3 + 2] = -0.034381f;
+ 	val_dir[8510*3 + 0] = 0.998138f;	val_dir[8510*3 + 1] = -0.050753f;	val_dir[8510*3 + 2] = -0.033835f;
+ 	val_dir[8511*3 + 0] = 0.998891f;	val_dir[8511*3 + 1] = -0.033296f;	val_dir[8511*3 + 2] = -0.033296f;
+ 	val_dir[8512*3 + 0] = 0.999329f;	val_dir[8512*3 + 1] = -0.016382f;	val_dir[8512*3 + 2] = -0.032765f;
+ 	val_dir[8513*3 + 0] = 0.999480f;	val_dir[8513*3 + 1] = 0.0f;	val_dir[8513*3 + 2] = -0.032241f;
+ 	val_dir[8514*3 + 0] = 0.999874f;	val_dir[8514*3 + 1] = 0.015871f;	val_dir[8514*3 + 2] = 0.0f;
+ 	val_dir[8515*3 + 0] = -0.016125f;	val_dir[8515*3 + 1] = -0.999740f;	val_dir[8515*3 + 2] = -0.016125f;
+ 	val_dir[8516*3 + 0] = 0.0f;	val_dir[8516*3 + 1] = -0.998793f;	val_dir[8516*3 + 2] = -0.049121f;
+ 	val_dir[8517*3 + 0] = 0.016644f;	val_dir[8517*3 + 1] = -0.998614f;	val_dir[8517*3 + 2] = -0.049931f;
+ 	val_dir[8518*3 + 0] = 0.033835f;	val_dir[8518*3 + 1] = -0.998138f;	val_dir[8518*3 + 2] = -0.050753f;
+ 	val_dir[8519*3 + 0] = 0.051586f;	val_dir[8519*3 + 1] = -0.997335f;	val_dir[8519*3 + 2] = -0.051586f;
+ 	val_dir[8520*3 + 0] = 0.069907f;	val_dir[8520*3 + 1] = -0.996175f;	val_dir[8520*3 + 2] = -0.052430f;
+ 	val_dir[8521*3 + 0] = 0.088806f;	val_dir[8521*3 + 1] = -0.994623f;	val_dir[8521*3 + 2] = -0.053283f;
+ 	val_dir[8522*3 + 0] = 0.108288f;	val_dir[8522*3 + 1] = -0.992644f;	val_dir[8522*3 + 2] = -0.054144f;
+ 	val_dir[8523*3 + 0] = 0.128359f;	val_dir[8523*3 + 1] = -0.990201f;	val_dir[8523*3 + 2] = -0.055011f;
+ 	val_dir[8524*3 + 0] = 0.149019f;	val_dir[8524*3 + 1] = -0.987254f;	val_dir[8524*3 + 2] = -0.055882f;
+ 	val_dir[8525*3 + 0] = 0.170267f;	val_dir[8525*3 + 1] = -0.983762f;	val_dir[8525*3 + 2] = -0.056756f;
+ 	val_dir[8526*3 + 0] = 0.192095f;	val_dir[8526*3 + 1] = -0.979683f;	val_dir[8526*3 + 2] = -0.057628f;
+ 	val_dir[8527*3 + 0] = 0.214494f;	val_dir[8527*3 + 1] = -0.974972f;	val_dir[8527*3 + 2] = -0.058498f;
+ 	val_dir[8528*3 + 0] = 0.237449f;	val_dir[8528*3 + 1] = -0.969584f;	val_dir[8528*3 + 2] = -0.059362f;
+ 	val_dir[8529*3 + 0] = 0.260941f;	val_dir[8529*3 + 1] = -0.963475f;	val_dir[8529*3 + 2] = -0.060217f;
+ 	val_dir[8530*3 + 0] = 0.284944f;	val_dir[8530*3 + 1] = -0.956597f;	val_dir[8530*3 + 2] = -0.061059f;
+ 	val_dir[8531*3 + 0] = 0.309426f;	val_dir[8531*3 + 1] = -0.948908f;	val_dir[8531*3 + 2] = -0.061885f;
+ 	val_dir[8532*3 + 0] = 0.334351f;	val_dir[8532*3 + 1] = -0.940361f;	val_dir[8532*3 + 2] = -0.062691f;
+ 	val_dir[8533*3 + 0] = 0.359673f;	val_dir[8533*3 + 1] = -0.930917f;	val_dir[8533*3 + 2] = -0.063472f;
+ 	val_dir[8534*3 + 0] = 0.385341f;	val_dir[8534*3 + 1] = -0.920537f;	val_dir[8534*3 + 2] = -0.064223f;
+ 	val_dir[8535*3 + 0] = 0.411298f;	val_dir[8535*3 + 1] = -0.909185f;	val_dir[8535*3 + 2] = -0.064942f;
+ 	val_dir[8536*3 + 0] = 0.437479f;	val_dir[8536*3 + 1] = -0.896831f;	val_dir[8536*3 + 2] = -0.065622f;
+ 	val_dir[8537*3 + 0] = 0.463812f;	val_dir[8537*3 + 1] = -0.883452f;	val_dir[8537*3 + 2] = -0.066259f;
+ 	val_dir[8538*3 + 0] = 0.490222f;	val_dir[8538*3 + 1] = -0.869030f;	val_dir[8538*3 + 2] = -0.066848f;
+ 	val_dir[8539*3 + 0] = 0.516626f;	val_dir[8539*3 + 1] = -0.853556f;	val_dir[8539*3 + 2] = -0.067386f;
+ 	val_dir[8540*3 + 0] = 0.542936f;	val_dir[8540*3 + 1] = -0.837027f;	val_dir[8540*3 + 2] = -0.067867f;
+ 	val_dir[8541*3 + 0] = 0.569064f;	val_dir[8541*3 + 1] = -0.819453f;	val_dir[8541*3 + 2] = -0.068288f;
+ 	val_dir[8542*3 + 0] = 0.594917f;	val_dir[8542*3 + 1] = -0.800850f;	val_dir[8542*3 + 2] = -0.068644f;
+ 	val_dir[8543*3 + 0] = 0.620403f;	val_dir[8543*3 + 1] = -0.781248f;	val_dir[8543*3 + 2] = -0.068934f;
+ 	val_dir[8544*3 + 0] = 0.645429f;	val_dir[8544*3 + 1] = -0.760684f;	val_dir[8544*3 + 2] = -0.069153f;
+ 	val_dir[8545*3 + 0] = 0.669905f;	val_dir[8545*3 + 1] = -0.739205f;	val_dir[8545*3 + 2] = -0.069301f;
+ 	val_dir[8546*3 + 0] = 0.693746f;	val_dir[8546*3 + 1] = -0.716871f;	val_dir[8546*3 + 2] = -0.069375f;
+ 	val_dir[8547*3 + 0] = 0.716871f;	val_dir[8547*3 + 1] = -0.693746f;	val_dir[8547*3 + 2] = -0.069375f;
+ 	val_dir[8548*3 + 0] = 0.739205f;	val_dir[8548*3 + 1] = -0.669905f;	val_dir[8548*3 + 2] = -0.069301f;
+ 	val_dir[8549*3 + 0] = 0.760684f;	val_dir[8549*3 + 1] = -0.645429f;	val_dir[8549*3 + 2] = -0.069153f;
+ 	val_dir[8550*3 + 0] = 0.781248f;	val_dir[8550*3 + 1] = -0.620403f;	val_dir[8550*3 + 2] = -0.068934f;
+ 	val_dir[8551*3 + 0] = 0.800850f;	val_dir[8551*3 + 1] = -0.594917f;	val_dir[8551*3 + 2] = -0.068644f;
+ 	val_dir[8552*3 + 0] = 0.819453f;	val_dir[8552*3 + 1] = -0.569064f;	val_dir[8552*3 + 2] = -0.068288f;
+ 	val_dir[8553*3 + 0] = 0.837027f;	val_dir[8553*3 + 1] = -0.542936f;	val_dir[8553*3 + 2] = -0.067867f;
+ 	val_dir[8554*3 + 0] = 0.853556f;	val_dir[8554*3 + 1] = -0.516626f;	val_dir[8554*3 + 2] = -0.067386f;
+ 	val_dir[8555*3 + 0] = 0.869030f;	val_dir[8555*3 + 1] = -0.490222f;	val_dir[8555*3 + 2] = -0.066848f;
+ 	val_dir[8556*3 + 0] = 0.883452f;	val_dir[8556*3 + 1] = -0.463812f;	val_dir[8556*3 + 2] = -0.066259f;
+ 	val_dir[8557*3 + 0] = 0.896831f;	val_dir[8557*3 + 1] = -0.437479f;	val_dir[8557*3 + 2] = -0.065622f;
+ 	val_dir[8558*3 + 0] = 0.909185f;	val_dir[8558*3 + 1] = -0.411298f;	val_dir[8558*3 + 2] = -0.064942f;
+ 	val_dir[8559*3 + 0] = 0.920537f;	val_dir[8559*3 + 1] = -0.385341f;	val_dir[8559*3 + 2] = -0.064223f;
+ 	val_dir[8560*3 + 0] = 0.930917f;	val_dir[8560*3 + 1] = -0.359673f;	val_dir[8560*3 + 2] = -0.063472f;
+ 	val_dir[8561*3 + 0] = 0.940361f;	val_dir[8561*3 + 1] = -0.334351f;	val_dir[8561*3 + 2] = -0.062691f;
+ 	val_dir[8562*3 + 0] = 0.948908f;	val_dir[8562*3 + 1] = -0.309426f;	val_dir[8562*3 + 2] = -0.061885f;
+ 	val_dir[8563*3 + 0] = 0.956597f;	val_dir[8563*3 + 1] = -0.284944f;	val_dir[8563*3 + 2] = -0.061059f;
+ 	val_dir[8564*3 + 0] = 0.963475f;	val_dir[8564*3 + 1] = -0.260941f;	val_dir[8564*3 + 2] = -0.060217f;
+ 	val_dir[8565*3 + 0] = 0.969584f;	val_dir[8565*3 + 1] = -0.237449f;	val_dir[8565*3 + 2] = -0.059362f;
+ 	val_dir[8566*3 + 0] = 0.974972f;	val_dir[8566*3 + 1] = -0.214494f;	val_dir[8566*3 + 2] = -0.058498f;
+ 	val_dir[8567*3 + 0] = 0.979683f;	val_dir[8567*3 + 1] = -0.192095f;	val_dir[8567*3 + 2] = -0.057628f;
+ 	val_dir[8568*3 + 0] = 0.983762f;	val_dir[8568*3 + 1] = -0.170267f;	val_dir[8568*3 + 2] = -0.056756f;
+ 	val_dir[8569*3 + 0] = 0.987254f;	val_dir[8569*3 + 1] = -0.149019f;	val_dir[8569*3 + 2] = -0.055882f;
+ 	val_dir[8570*3 + 0] = 0.990201f;	val_dir[8570*3 + 1] = -0.128359f;	val_dir[8570*3 + 2] = -0.055011f;
+ 	val_dir[8571*3 + 0] = 0.992644f;	val_dir[8571*3 + 1] = -0.108288f;	val_dir[8571*3 + 2] = -0.054144f;
+ 	val_dir[8572*3 + 0] = 0.994623f;	val_dir[8572*3 + 1] = -0.088806f;	val_dir[8572*3 + 2] = -0.053283f;
+ 	val_dir[8573*3 + 0] = 0.996175f;	val_dir[8573*3 + 1] = -0.069907f;	val_dir[8573*3 + 2] = -0.052430f;
+ 	val_dir[8574*3 + 0] = 0.997335f;	val_dir[8574*3 + 1] = -0.051586f;	val_dir[8574*3 + 2] = -0.051586f;
+ 	val_dir[8575*3 + 0] = 0.998138f;	val_dir[8575*3 + 1] = -0.033835f;	val_dir[8575*3 + 2] = -0.050753f;
+ 	val_dir[8576*3 + 0] = 0.998614f;	val_dir[8576*3 + 1] = -0.016644f;	val_dir[8576*3 + 2] = -0.049931f;
+ 	val_dir[8577*3 + 0] = 0.998793f;	val_dir[8577*3 + 1] = 0.0f;	val_dir[8577*3 + 2] = -0.049121f;
+ 	val_dir[8578*3 + 0] = 0.999740f;	val_dir[8578*3 + 1] = 0.016125f;	val_dir[8578*3 + 2] = -0.016125f;
+ 	val_dir[8579*3 + 0] = -0.032241f;	val_dir[8579*3 + 1] = -0.999480f;	val_dir[8579*3 + 2] = 0.0f;
+ 	val_dir[8580*3 + 0] = -0.016382f;	val_dir[8580*3 + 1] = -0.999329f;	val_dir[8580*3 + 2] = -0.032765f;
+ 	val_dir[8581*3 + 0] = 0.0f;	val_dir[8581*3 + 1] = -0.997785f;	val_dir[8581*3 + 2] = -0.066519f;
+ 	val_dir[8582*3 + 0] = 0.016908f;	val_dir[8582*3 + 1] = -0.997567f;	val_dir[8582*3 + 2] = -0.067632f;
+ 	val_dir[8583*3 + 0] = 0.034381f;	val_dir[8583*3 + 1] = -0.997041f;	val_dir[8583*3 + 2] = -0.068761f;
+ 	val_dir[8584*3 + 0] = 0.052430f;	val_dir[8584*3 + 1] = -0.996175f;	val_dir[8584*3 + 2] = -0.069907f;
+ 	val_dir[8585*3 + 0] = 0.071067f;	val_dir[8585*3 + 1] = -0.994937f;	val_dir[8585*3 + 2] = -0.071067f;
+ 	val_dir[8586*3 + 0] = 0.090299f;	val_dir[8586*3 + 1] = -0.993291f;	val_dir[8586*3 + 2] = -0.072239f;
+ 	val_dir[8587*3 + 0] = 0.110133f;	val_dir[8587*3 + 1] = -0.991201f;	val_dir[8587*3 + 2] = -0.073422f;
+ 	val_dir[8588*3 + 0] = 0.130573f;	val_dir[8588*3 + 1] = -0.988627f;	val_dir[8588*3 + 2] = -0.074613f;
+ 	val_dir[8589*3 + 0] = 0.151620f;	val_dir[8589*3 + 1] = -0.985527f;	val_dir[8589*3 + 2] = -0.075810f;
+ 	val_dir[8590*3 + 0] = 0.173269f;	val_dir[8590*3 + 1] = -0.981859f;	val_dir[8590*3 + 2] = -0.077009f;
+ 	val_dir[8591*3 + 0] = 0.195515f;	val_dir[8591*3 + 1] = -0.977577f;	val_dir[8591*3 + 2] = -0.078206f;
+ 	val_dir[8592*3 + 0] = 0.218347f;	val_dir[8592*3 + 1] = -0.972636f;	val_dir[8592*3 + 2] = -0.079399f;
+ 	val_dir[8593*3 + 0] = 0.241747f;	val_dir[8593*3 + 1] = -0.966988f;	val_dir[8593*3 + 2] = -0.080582f;
+ 	val_dir[8594*3 + 0] = 0.265694f;	val_dir[8594*3 + 1] = -0.960585f;	val_dir[8594*3 + 2] = -0.081752f;
+ 	val_dir[8595*3 + 0] = 0.290159f;	val_dir[8595*3 + 1] = -0.953381f;	val_dir[8595*3 + 2] = -0.082903f;
+ 	val_dir[8596*3 + 0] = 0.315109f;	val_dir[8596*3 + 1] = -0.945328f;	val_dir[8596*3 + 2] = -0.084029f;
+ 	val_dir[8597*3 + 0] = 0.340503f;	val_dir[8597*3 + 1] = -0.936382f;	val_dir[8597*3 + 2] = -0.085126f;
+ 	val_dir[8598*3 + 0] = 0.366291f;	val_dir[8598*3 + 1] = -0.92650f;	val_dir[8598*3 + 2] = -0.086186f;
+ 	val_dir[8599*3 + 0] = 0.392419f;	val_dir[8599*3 + 1] = -0.915644f;	val_dir[8599*3 + 2] = -0.087204f;
+ 	val_dir[8600*3 + 0] = 0.418823f;	val_dir[8600*3 + 1] = -0.903777f;	val_dir[8600*3 + 2] = -0.088173f;
+ 	val_dir[8601*3 + 0] = 0.445435f;	val_dir[8601*3 + 1] = -0.890871f;	val_dir[8601*3 + 2] = -0.089087f;
+ 	val_dir[8602*3 + 0] = 0.472178f;	val_dir[8602*3 + 1] = -0.876903f;	val_dir[8602*3 + 2] = -0.089939f;
+ 	val_dir[8603*3 + 0] = 0.498970f;	val_dir[8603*3 + 1] = -0.861857f;	val_dir[8603*3 + 2] = -0.090722f;
+ 	val_dir[8604*3 + 0] = 0.525723f;	val_dir[8604*3 + 1] = -0.845728f;	val_dir[8604*3 + 2] = -0.091430f;
+ 	val_dir[8605*3 + 0] = 0.552345f;	val_dir[8605*3 + 1] = -0.828517f;	val_dir[8605*3 + 2] = -0.092057f;
+ 	val_dir[8606*3 + 0] = 0.578741f;	val_dir[8606*3 + 1] = -0.810237f;	val_dir[8606*3 + 2] = -0.092599f;
+ 	val_dir[8607*3 + 0] = 0.604815f;	val_dir[8607*3 + 1] = -0.790912f;	val_dir[8607*3 + 2] = -0.093048f;
+ 	val_dir[8608*3 + 0] = 0.630470f;	val_dir[8608*3 + 1] = -0.770574f;	val_dir[8608*3 + 2] = -0.093403f;
+ 	val_dir[8609*3 + 0] = 0.655610f;	val_dir[8609*3 + 1] = -0.749269f;	val_dir[8609*3 + 2] = -0.093659f;
+ 	val_dir[8610*3 + 0] = 0.680144f;	val_dir[8610*3 + 1] = -0.727051f;	val_dir[8610*3 + 2] = -0.093813f;
+ 	val_dir[8611*3 + 0] = 0.703985f;	val_dir[8611*3 + 1] = -0.703985f;	val_dir[8611*3 + 2] = -0.093865f;
+ 	val_dir[8612*3 + 0] = 0.727051f;	val_dir[8612*3 + 1] = -0.680144f;	val_dir[8612*3 + 2] = -0.093813f;
+ 	val_dir[8613*3 + 0] = 0.749269f;	val_dir[8613*3 + 1] = -0.655610f;	val_dir[8613*3 + 2] = -0.093659f;
+ 	val_dir[8614*3 + 0] = 0.770574f;	val_dir[8614*3 + 1] = -0.630470f;	val_dir[8614*3 + 2] = -0.093403f;
+ 	val_dir[8615*3 + 0] = 0.790912f;	val_dir[8615*3 + 1] = -0.604815f;	val_dir[8615*3 + 2] = -0.093048f;
+ 	val_dir[8616*3 + 0] = 0.810237f;	val_dir[8616*3 + 1] = -0.578741f;	val_dir[8616*3 + 2] = -0.092599f;
+ 	val_dir[8617*3 + 0] = 0.828517f;	val_dir[8617*3 + 1] = -0.552345f;	val_dir[8617*3 + 2] = -0.092057f;
+ 	val_dir[8618*3 + 0] = 0.845728f;	val_dir[8618*3 + 1] = -0.525723f;	val_dir[8618*3 + 2] = -0.091430f;
+ 	val_dir[8619*3 + 0] = 0.861857f;	val_dir[8619*3 + 1] = -0.498970f;	val_dir[8619*3 + 2] = -0.090722f;
+ 	val_dir[8620*3 + 0] = 0.876903f;	val_dir[8620*3 + 1] = -0.472178f;	val_dir[8620*3 + 2] = -0.089939f;
+ 	val_dir[8621*3 + 0] = 0.890871f;	val_dir[8621*3 + 1] = -0.445435f;	val_dir[8621*3 + 2] = -0.089087f;
+ 	val_dir[8622*3 + 0] = 0.903777f;	val_dir[8622*3 + 1] = -0.418823f;	val_dir[8622*3 + 2] = -0.088173f;
+ 	val_dir[8623*3 + 0] = 0.915644f;	val_dir[8623*3 + 1] = -0.392419f;	val_dir[8623*3 + 2] = -0.087204f;
+ 	val_dir[8624*3 + 0] = 0.92650f;	val_dir[8624*3 + 1] = -0.366291f;	val_dir[8624*3 + 2] = -0.086186f;
+ 	val_dir[8625*3 + 0] = 0.936382f;	val_dir[8625*3 + 1] = -0.340503f;	val_dir[8625*3 + 2] = -0.085126f;
+ 	val_dir[8626*3 + 0] = 0.945328f;	val_dir[8626*3 + 1] = -0.315109f;	val_dir[8626*3 + 2] = -0.084029f;
+ 	val_dir[8627*3 + 0] = 0.953381f;	val_dir[8627*3 + 1] = -0.290159f;	val_dir[8627*3 + 2] = -0.082903f;
+ 	val_dir[8628*3 + 0] = 0.960585f;	val_dir[8628*3 + 1] = -0.265694f;	val_dir[8628*3 + 2] = -0.081752f;
+ 	val_dir[8629*3 + 0] = 0.966988f;	val_dir[8629*3 + 1] = -0.241747f;	val_dir[8629*3 + 2] = -0.080582f;
+ 	val_dir[8630*3 + 0] = 0.972636f;	val_dir[8630*3 + 1] = -0.218347f;	val_dir[8630*3 + 2] = -0.079399f;
+ 	val_dir[8631*3 + 0] = 0.977577f;	val_dir[8631*3 + 1] = -0.195515f;	val_dir[8631*3 + 2] = -0.078206f;
+ 	val_dir[8632*3 + 0] = 0.981859f;	val_dir[8632*3 + 1] = -0.173269f;	val_dir[8632*3 + 2] = -0.077009f;
+ 	val_dir[8633*3 + 0] = 0.985527f;	val_dir[8633*3 + 1] = -0.151620f;	val_dir[8633*3 + 2] = -0.075810f;
+ 	val_dir[8634*3 + 0] = 0.988627f;	val_dir[8634*3 + 1] = -0.130573f;	val_dir[8634*3 + 2] = -0.074613f;
+ 	val_dir[8635*3 + 0] = 0.991201f;	val_dir[8635*3 + 1] = -0.110133f;	val_dir[8635*3 + 2] = -0.073422f;
+ 	val_dir[8636*3 + 0] = 0.993291f;	val_dir[8636*3 + 1] = -0.090299f;	val_dir[8636*3 + 2] = -0.072239f;
+ 	val_dir[8637*3 + 0] = 0.994937f;	val_dir[8637*3 + 1] = -0.071067f;	val_dir[8637*3 + 2] = -0.071067f;
+ 	val_dir[8638*3 + 0] = 0.996175f;	val_dir[8638*3 + 1] = -0.052430f;	val_dir[8638*3 + 2] = -0.069907f;
+ 	val_dir[8639*3 + 0] = 0.997041f;	val_dir[8639*3 + 1] = -0.034381f;	val_dir[8639*3 + 2] = -0.068761f;
+ 	val_dir[8640*3 + 0] = 0.997567f;	val_dir[8640*3 + 1] = -0.016908f;	val_dir[8640*3 + 2] = -0.067632f;
+ 	val_dir[8641*3 + 0] = 0.997785f;	val_dir[8641*3 + 1] = 0.0f;	val_dir[8641*3 + 2] = -0.066519f;
+ 	val_dir[8642*3 + 0] = 0.999329f;	val_dir[8642*3 + 1] = 0.016382f;	val_dir[8642*3 + 2] = -0.032765f;
+ 	val_dir[8643*3 + 0] = 0.999480f;	val_dir[8643*3 + 1] = 0.032241f;	val_dir[8643*3 + 2] = 0.0f;
+ 	val_dir[8644*3 + 0] = -0.032765f;	val_dir[8644*3 + 1] = -0.999329f;	val_dir[8644*3 + 2] = -0.016382f;
+ 	val_dir[8645*3 + 0] = -0.016644f;	val_dir[8645*3 + 1] = -0.998614f;	val_dir[8645*3 + 2] = -0.049931f;
+ 	val_dir[8646*3 + 0] = 0.0f;	val_dir[8646*3 + 1] = -0.996428f;	val_dir[8646*3 + 2] = -0.084443f;
+ 	val_dir[8647*3 + 0] = 0.017175f;	val_dir[8647*3 + 1] = -0.996158f;	val_dir[8647*3 + 2] = -0.085876f;
+ 	val_dir[8648*3 + 0] = 0.034932f;	val_dir[8648*3 + 1] = -0.995567f;	val_dir[8648*3 + 2] = -0.087330f;
+ 	val_dir[8649*3 + 0] = 0.053283f;	val_dir[8649*3 + 1] = -0.994623f;	val_dir[8649*3 + 2] = -0.088806f;
+ 	val_dir[8650*3 + 0] = 0.072239f;	val_dir[8650*3 + 1] = -0.993291f;	val_dir[8650*3 + 2] = -0.090299f;
+ 	val_dir[8651*3 + 0] = 0.091809f;	val_dir[8651*3 + 1] = -0.991535f;	val_dir[8651*3 + 2] = -0.091809f;
+ 	val_dir[8652*3 + 0] = 0.111998f;	val_dir[8652*3 + 1] = -0.989316f;	val_dir[8652*3 + 2] = -0.093332f;
+ 	val_dir[8653*3 + 0] = 0.132810f;	val_dir[8653*3 + 1] = -0.986591f;	val_dir[8653*3 + 2] = -0.094865f;
+ 	val_dir[8654*3 + 0] = 0.154246f;	val_dir[8654*3 + 1] = -0.983318f;	val_dir[8654*3 + 2] = -0.096404f;
+ 	val_dir[8655*3 + 0] = 0.176301f;	val_dir[8655*3 + 1] = -0.979451f;	val_dir[8655*3 + 2] = -0.097945f;
+ 	val_dir[8656*3 + 0] = 0.198968f;	val_dir[8656*3 + 1] = -0.974943f;	val_dir[8656*3 + 2] = -0.099484f;
+ 	val_dir[8657*3 + 0] = 0.222234f;	val_dir[8657*3 + 1] = -0.969746f;	val_dir[8657*3 + 2] = -0.101015f;
+ 	val_dir[8658*3 + 0] = 0.246079f;	val_dir[8658*3 + 1] = -0.963811f;	val_dir[8658*3 + 2] = -0.102533f;
+ 	val_dir[8659*3 + 0] = 0.270481f;	val_dir[8659*3 + 1] = -0.957088f;	val_dir[8659*3 + 2] = -0.104031f;
+ 	val_dir[8660*3 + 0] = 0.295409f;	val_dir[8660*3 + 1] = -0.949528f;	val_dir[8660*3 + 2] = -0.105503f;
+ 	val_dir[8661*3 + 0] = 0.320824f;	val_dir[8661*3 + 1] = -0.941082f;	val_dir[8661*3 + 2] = -0.106941f;
+ 	val_dir[8662*3 + 0] = 0.346681f;	val_dir[8662*3 + 1] = -0.931705f;	val_dir[8662*3 + 2] = -0.108338f;
+ 	val_dir[8663*3 + 0] = 0.372929f;	val_dir[8663*3 + 1] = -0.921354f;	val_dir[8663*3 + 2] = -0.109685f;
+ 	val_dir[8664*3 + 0] = 0.399507f;	val_dir[8664*3 + 1] = -0.909988f;	val_dir[8664*3 + 2] = -0.110974f;
+ 	val_dir[8665*3 + 0] = 0.426348f;	val_dir[8665*3 + 1] = -0.897574f;	val_dir[8665*3 + 2] = -0.112197f;
+ 	val_dir[8666*3 + 0] = 0.453376f;	val_dir[8666*3 + 1] = -0.884083f;	val_dir[8666*3 + 2] = -0.113344f;
+ 	val_dir[8667*3 + 0] = 0.480510f;	val_dir[8667*3 + 1] = -0.869495f;	val_dir[8667*3 + 2] = -0.114407f;
+ 	val_dir[8668*3 + 0] = 0.507662f;	val_dir[8668*3 + 1] = -0.853796f;	val_dir[8668*3 + 2] = -0.115378f;
+ 	val_dir[8669*3 + 0] = 0.534739f;	val_dir[8669*3 + 1] = -0.836983f;	val_dir[8669*3 + 2] = -0.116248f;
+ 	val_dir[8670*3 + 0] = 0.561644f;	val_dir[8670*3 + 1] = -0.819064f;	val_dir[8670*3 + 2] = -0.117009f;
+ 	val_dir[8671*3 + 0] = 0.588276f;	val_dir[8671*3 + 1] = -0.800055f;	val_dir[8671*3 + 2] = -0.117655f;
+ 	val_dir[8672*3 + 0] = 0.614535f;	val_dir[8672*3 + 1] = -0.779987f;	val_dir[8672*3 + 2] = -0.118180f;
+ 	val_dir[8673*3 + 0] = 0.640321f;	val_dir[8673*3 + 1] = -0.758899f;	val_dir[8673*3 + 2] = -0.118578f;
+ 	val_dir[8674*3 + 0] = 0.665536f;	val_dir[8674*3 + 1] = -0.736843f;	val_dir[8674*3 + 2] = -0.118846f;
+ 	val_dir[8675*3 + 0] = 0.690085f;	val_dir[8675*3 + 1] = -0.713881f;	val_dir[8675*3 + 2] = -0.118980f;
+ 	val_dir[8676*3 + 0] = 0.713881f;	val_dir[8676*3 + 1] = -0.690085f;	val_dir[8676*3 + 2] = -0.118980f;
+ 	val_dir[8677*3 + 0] = 0.736843f;	val_dir[8677*3 + 1] = -0.665536f;	val_dir[8677*3 + 2] = -0.118846f;
+ 	val_dir[8678*3 + 0] = 0.758899f;	val_dir[8678*3 + 1] = -0.640321f;	val_dir[8678*3 + 2] = -0.118578f;
+ 	val_dir[8679*3 + 0] = 0.779987f;	val_dir[8679*3 + 1] = -0.614535f;	val_dir[8679*3 + 2] = -0.118180f;
+ 	val_dir[8680*3 + 0] = 0.800055f;	val_dir[8680*3 + 1] = -0.588276f;	val_dir[8680*3 + 2] = -0.117655f;
+ 	val_dir[8681*3 + 0] = 0.819064f;	val_dir[8681*3 + 1] = -0.561644f;	val_dir[8681*3 + 2] = -0.117009f;
+ 	val_dir[8682*3 + 0] = 0.836983f;	val_dir[8682*3 + 1] = -0.534739f;	val_dir[8682*3 + 2] = -0.116248f;
+ 	val_dir[8683*3 + 0] = 0.853796f;	val_dir[8683*3 + 1] = -0.507662f;	val_dir[8683*3 + 2] = -0.115378f;
+ 	val_dir[8684*3 + 0] = 0.869495f;	val_dir[8684*3 + 1] = -0.480510f;	val_dir[8684*3 + 2] = -0.114407f;
+ 	val_dir[8685*3 + 0] = 0.884083f;	val_dir[8685*3 + 1] = -0.453376f;	val_dir[8685*3 + 2] = -0.113344f;
+ 	val_dir[8686*3 + 0] = 0.897574f;	val_dir[8686*3 + 1] = -0.426348f;	val_dir[8686*3 + 2] = -0.112197f;
+ 	val_dir[8687*3 + 0] = 0.909988f;	val_dir[8687*3 + 1] = -0.399507f;	val_dir[8687*3 + 2] = -0.110974f;
+ 	val_dir[8688*3 + 0] = 0.921354f;	val_dir[8688*3 + 1] = -0.372929f;	val_dir[8688*3 + 2] = -0.109685f;
+ 	val_dir[8689*3 + 0] = 0.931705f;	val_dir[8689*3 + 1] = -0.346681f;	val_dir[8689*3 + 2] = -0.108338f;
+ 	val_dir[8690*3 + 0] = 0.941082f;	val_dir[8690*3 + 1] = -0.320824f;	val_dir[8690*3 + 2] = -0.106941f;
+ 	val_dir[8691*3 + 0] = 0.949528f;	val_dir[8691*3 + 1] = -0.295409f;	val_dir[8691*3 + 2] = -0.105503f;
+ 	val_dir[8692*3 + 0] = 0.957088f;	val_dir[8692*3 + 1] = -0.270481f;	val_dir[8692*3 + 2] = -0.104031f;
+ 	val_dir[8693*3 + 0] = 0.963811f;	val_dir[8693*3 + 1] = -0.246079f;	val_dir[8693*3 + 2] = -0.102533f;
+ 	val_dir[8694*3 + 0] = 0.969746f;	val_dir[8694*3 + 1] = -0.222234f;	val_dir[8694*3 + 2] = -0.101015f;
+ 	val_dir[8695*3 + 0] = 0.974943f;	val_dir[8695*3 + 1] = -0.198968f;	val_dir[8695*3 + 2] = -0.099484f;
+ 	val_dir[8696*3 + 0] = 0.979451f;	val_dir[8696*3 + 1] = -0.176301f;	val_dir[8696*3 + 2] = -0.097945f;
+ 	val_dir[8697*3 + 0] = 0.983318f;	val_dir[8697*3 + 1] = -0.154246f;	val_dir[8697*3 + 2] = -0.096404f;
+ 	val_dir[8698*3 + 0] = 0.986591f;	val_dir[8698*3 + 1] = -0.132810f;	val_dir[8698*3 + 2] = -0.094865f;
+ 	val_dir[8699*3 + 0] = 0.989316f;	val_dir[8699*3 + 1] = -0.111998f;	val_dir[8699*3 + 2] = -0.093332f;
+ 	val_dir[8700*3 + 0] = 0.991535f;	val_dir[8700*3 + 1] = -0.091809f;	val_dir[8700*3 + 2] = -0.091809f;
+ 	val_dir[8701*3 + 0] = 0.993291f;	val_dir[8701*3 + 1] = -0.072239f;	val_dir[8701*3 + 2] = -0.090299f;
+ 	val_dir[8702*3 + 0] = 0.994623f;	val_dir[8702*3 + 1] = -0.053283f;	val_dir[8702*3 + 2] = -0.088806f;
+ 	val_dir[8703*3 + 0] = 0.995567f;	val_dir[8703*3 + 1] = -0.034932f;	val_dir[8703*3 + 2] = -0.087330f;
+ 	val_dir[8704*3 + 0] = 0.996158f;	val_dir[8704*3 + 1] = -0.017175f;	val_dir[8704*3 + 2] = -0.085876f;
+ 	val_dir[8705*3 + 0] = 0.996428f;	val_dir[8705*3 + 1] = 0.0f;	val_dir[8705*3 + 2] = -0.084443f;
+ 	val_dir[8706*3 + 0] = 0.998614f;	val_dir[8706*3 + 1] = 0.016644f;	val_dir[8706*3 + 2] = -0.049931f;
+ 	val_dir[8707*3 + 0] = 0.999329f;	val_dir[8707*3 + 1] = 0.032765f;	val_dir[8707*3 + 2] = -0.016382f;
+ 	val_dir[8708*3 + 0] = -0.049121f;	val_dir[8708*3 + 1] = -0.998793f;	val_dir[8708*3 + 2] = 0.0f;
+ 	val_dir[8709*3 + 0] = -0.033296f;	val_dir[8709*3 + 1] = -0.998891f;	val_dir[8709*3 + 2] = -0.033296f;
+ 	val_dir[8710*3 + 0] = -0.016908f;	val_dir[8710*3 + 1] = -0.997567f;	val_dir[8710*3 + 2] = -0.067632f;
+ 	val_dir[8711*3 + 0] = 0.0f;	val_dir[8711*3 + 1] = -0.994692f;	val_dir[8711*3 + 2] = -0.102899f;
+ 	val_dir[8712*3 + 0] = 0.017445f;	val_dir[8712*3 + 1] = -0.994354f;	val_dir[8712*3 + 2] = -0.104669f;
+ 	val_dir[8713*3 + 0] = 0.035489f;	val_dir[8713*3 + 1] = -0.993683f;	val_dir[8713*3 + 2] = -0.106466f;
+ 	val_dir[8714*3 + 0] = 0.054144f;	val_dir[8714*3 + 1] = -0.992644f;	val_dir[8714*3 + 2] = -0.108288f;
+ 	val_dir[8715*3 + 0] = 0.073422f;	val_dir[8715*3 + 1] = -0.991201f;	val_dir[8715*3 + 2] = -0.110133f;
+ 	val_dir[8716*3 + 0] = 0.093332f;	val_dir[8716*3 + 1] = -0.989316f;	val_dir[8716*3 + 2] = -0.111998f;
+ 	val_dir[8717*3 + 0] = 0.113878f;	val_dir[8717*3 + 1] = -0.986947f;	val_dir[8717*3 + 2] = -0.113878f;
+ 	val_dir[8718*3 + 0] = 0.135066f;	val_dir[8718*3 + 1] = -0.984050f;	val_dir[8718*3 + 2] = -0.115771f;
+ 	val_dir[8719*3 + 0] = 0.156893f;	val_dir[8719*3 + 1] = -0.980581f;	val_dir[8719*3 + 2] = -0.117670f;
+ 	val_dir[8720*3 + 0] = 0.179355f;	val_dir[8720*3 + 1] = -0.976491f;	val_dir[8720*3 + 2] = -0.119570f;
+ 	val_dir[8721*3 + 0] = 0.202444f;	val_dir[8721*3 + 1] = -0.971732f;	val_dir[8721*3 + 2] = -0.121466f;
+ 	val_dir[8722*3 + 0] = 0.226144f;	val_dir[8722*3 + 1] = -0.966252f;	val_dir[8722*3 + 2] = -0.123351f;
+ 	val_dir[8723*3 + 0] = 0.250435f;	val_dir[8723*3 + 1] = -0.960001f;	val_dir[8723*3 + 2] = -0.125218f;
+ 	val_dir[8724*3 + 0] = 0.275290f;	val_dir[8724*3 + 1] = -0.952928f;	val_dir[8724*3 + 2] = -0.127057f;
+ 	val_dir[8725*3 + 0] = 0.300676f;	val_dir[8725*3 + 1] = -0.944981f;	val_dir[8725*3 + 2] = -0.128861f;
+ 	val_dir[8726*3 + 0] = 0.326550f;	val_dir[8726*3 + 1] = -0.936111f;	val_dir[8726*3 + 2] = -0.130620f;
+ 	val_dir[8727*3 + 0] = 0.352865f;	val_dir[8727*3 + 1] = -0.926270f;	val_dir[8727*3 + 2] = -0.132324f;
+ 	val_dir[8728*3 + 0] = 0.379563f;	val_dir[8728*3 + 1] = -0.915416f;	val_dir[8728*3 + 2] = -0.133963f;
+ 	val_dir[8729*3 + 0] = 0.406579f;	val_dir[8729*3 + 1] = -0.903508f;	val_dir[8729*3 + 2] = -0.135526f;
+ 	val_dir[8730*3 + 0] = 0.433840f;	val_dir[8730*3 + 1] = -0.890513f;	val_dir[8730*3 + 2] = -0.137002f;
+ 	val_dir[8731*3 + 0] = 0.461266f;	val_dir[8731*3 + 1] = -0.876405f;	val_dir[8731*3 + 2] = -0.138380f;
+ 	val_dir[8732*3 + 0] = 0.488769f;	val_dir[8732*3 + 1] = -0.861164f;	val_dir[8732*3 + 2] = -0.139648f;
+ 	val_dir[8733*3 + 0] = 0.516256f;	val_dir[8733*3 + 1] = -0.844782f;	val_dir[8733*3 + 2] = -0.140797f;
+ 	val_dir[8734*3 + 0] = 0.543627f;	val_dir[8734*3 + 1] = -0.827259f;	val_dir[8734*3 + 2] = -0.141816f;
+ 	val_dir[8735*3 + 0] = 0.570782f;	val_dir[8735*3 + 1] = -0.808608f;	val_dir[8735*3 + 2] = -0.142695f;
+ 	val_dir[8736*3 + 0] = 0.597614f;	val_dir[8736*3 + 1] = -0.788851f;	val_dir[8736*3 + 2] = -0.143427f;
+ 	val_dir[8737*3 + 0] = 0.624020f;	val_dir[8737*3 + 1] = -0.768025f;	val_dir[8737*3 + 2] = -0.144005f;
+ 	val_dir[8738*3 + 0] = 0.649895f;	val_dir[8738*3 + 1] = -0.746176f;	val_dir[8738*3 + 2] = -0.144421f;
+ 	val_dir[8739*3 + 0] = 0.675140f;	val_dir[8739*3 + 1] = -0.723364f;	val_dir[8739*3 + 2] = -0.144673f;
+ 	val_dir[8740*3 + 0] = 0.699659f;	val_dir[8740*3 + 1] = -0.699659f;	val_dir[8740*3 + 2] = -0.144757f;
+ 	val_dir[8741*3 + 0] = 0.723364f;	val_dir[8741*3 + 1] = -0.675140f;	val_dir[8741*3 + 2] = -0.144673f;
+ 	val_dir[8742*3 + 0] = 0.746176f;	val_dir[8742*3 + 1] = -0.649895f;	val_dir[8742*3 + 2] = -0.144421f;
+ 	val_dir[8743*3 + 0] = 0.768025f;	val_dir[8743*3 + 1] = -0.624020f;	val_dir[8743*3 + 2] = -0.144005f;
+ 	val_dir[8744*3 + 0] = 0.788851f;	val_dir[8744*3 + 1] = -0.597614f;	val_dir[8744*3 + 2] = -0.143427f;
+ 	val_dir[8745*3 + 0] = 0.808608f;	val_dir[8745*3 + 1] = -0.570782f;	val_dir[8745*3 + 2] = -0.142695f;
+ 	val_dir[8746*3 + 0] = 0.827259f;	val_dir[8746*3 + 1] = -0.543627f;	val_dir[8746*3 + 2] = -0.141816f;
+ 	val_dir[8747*3 + 0] = 0.844782f;	val_dir[8747*3 + 1] = -0.516256f;	val_dir[8747*3 + 2] = -0.140797f;
+ 	val_dir[8748*3 + 0] = 0.861164f;	val_dir[8748*3 + 1] = -0.488769f;	val_dir[8748*3 + 2] = -0.139648f;
+ 	val_dir[8749*3 + 0] = 0.876405f;	val_dir[8749*3 + 1] = -0.461266f;	val_dir[8749*3 + 2] = -0.138380f;
+ 	val_dir[8750*3 + 0] = 0.890513f;	val_dir[8750*3 + 1] = -0.433840f;	val_dir[8750*3 + 2] = -0.137002f;
+ 	val_dir[8751*3 + 0] = 0.903508f;	val_dir[8751*3 + 1] = -0.406579f;	val_dir[8751*3 + 2] = -0.135526f;
+ 	val_dir[8752*3 + 0] = 0.915416f;	val_dir[8752*3 + 1] = -0.379563f;	val_dir[8752*3 + 2] = -0.133963f;
+ 	val_dir[8753*3 + 0] = 0.926270f;	val_dir[8753*3 + 1] = -0.352865f;	val_dir[8753*3 + 2] = -0.132324f;
+ 	val_dir[8754*3 + 0] = 0.936111f;	val_dir[8754*3 + 1] = -0.326550f;	val_dir[8754*3 + 2] = -0.130620f;
+ 	val_dir[8755*3 + 0] = 0.944981f;	val_dir[8755*3 + 1] = -0.300676f;	val_dir[8755*3 + 2] = -0.128861f;
+ 	val_dir[8756*3 + 0] = 0.952928f;	val_dir[8756*3 + 1] = -0.275290f;	val_dir[8756*3 + 2] = -0.127057f;
+ 	val_dir[8757*3 + 0] = 0.960001f;	val_dir[8757*3 + 1] = -0.250435f;	val_dir[8757*3 + 2] = -0.125218f;
+ 	val_dir[8758*3 + 0] = 0.966252f;	val_dir[8758*3 + 1] = -0.226144f;	val_dir[8758*3 + 2] = -0.123351f;
+ 	val_dir[8759*3 + 0] = 0.971732f;	val_dir[8759*3 + 1] = -0.202444f;	val_dir[8759*3 + 2] = -0.121466f;
+ 	val_dir[8760*3 + 0] = 0.976491f;	val_dir[8760*3 + 1] = -0.179355f;	val_dir[8760*3 + 2] = -0.119570f;
+ 	val_dir[8761*3 + 0] = 0.980581f;	val_dir[8761*3 + 1] = -0.156893f;	val_dir[8761*3 + 2] = -0.117670f;
+ 	val_dir[8762*3 + 0] = 0.984050f;	val_dir[8762*3 + 1] = -0.135066f;	val_dir[8762*3 + 2] = -0.115771f;
+ 	val_dir[8763*3 + 0] = 0.986947f;	val_dir[8763*3 + 1] = -0.113878f;	val_dir[8763*3 + 2] = -0.113878f;
+ 	val_dir[8764*3 + 0] = 0.989316f;	val_dir[8764*3 + 1] = -0.093332f;	val_dir[8764*3 + 2] = -0.111998f;
+ 	val_dir[8765*3 + 0] = 0.991201f;	val_dir[8765*3 + 1] = -0.073422f;	val_dir[8765*3 + 2] = -0.110133f;
+ 	val_dir[8766*3 + 0] = 0.992644f;	val_dir[8766*3 + 1] = -0.054144f;	val_dir[8766*3 + 2] = -0.108288f;
+ 	val_dir[8767*3 + 0] = 0.993683f;	val_dir[8767*3 + 1] = -0.035489f;	val_dir[8767*3 + 2] = -0.106466f;
+ 	val_dir[8768*3 + 0] = 0.994354f;	val_dir[8768*3 + 1] = -0.017445f;	val_dir[8768*3 + 2] = -0.104669f;
+ 	val_dir[8769*3 + 0] = 0.994692f;	val_dir[8769*3 + 1] = 0.0f;	val_dir[8769*3 + 2] = -0.102899f;
+ 	val_dir[8770*3 + 0] = 0.997567f;	val_dir[8770*3 + 1] = 0.016908f;	val_dir[8770*3 + 2] = -0.067632f;
+ 	val_dir[8771*3 + 0] = 0.998891f;	val_dir[8771*3 + 1] = 0.033296f;	val_dir[8771*3 + 2] = -0.033296f;
+ 	val_dir[8772*3 + 0] = 0.998793f;	val_dir[8772*3 + 1] = 0.049121f;	val_dir[8772*3 + 2] = 0.0f;
+ 	val_dir[8773*3 + 0] = -0.049931f;	val_dir[8773*3 + 1] = -0.998614f;	val_dir[8773*3 + 2] = -0.016644f;
+ 	val_dir[8774*3 + 0] = -0.033835f;	val_dir[8774*3 + 1] = -0.998138f;	val_dir[8774*3 + 2] = -0.050753f;
+ 	val_dir[8775*3 + 0] = -0.017175f;	val_dir[8775*3 + 1] = -0.996158f;	val_dir[8775*3 + 2] = -0.085876f;
+ 	val_dir[8776*3 + 0] = 0.0f;	val_dir[8776*3 + 1] = -0.992543f;	val_dir[8776*3 + 2] = -0.121891f;
+ 	val_dir[8777*3 + 0] = 0.017716f;	val_dir[8777*3 + 1] = -0.992122f;	val_dir[8777*3 + 2] = -0.124015f;
+ 	val_dir[8778*3 + 0] = 0.036049f;	val_dir[8778*3 + 1] = -0.991353f;	val_dir[8778*3 + 2] = -0.126172f;
+ 	val_dir[8779*3 + 0] = 0.055011f;	val_dir[8779*3 + 1] = -0.990201f;	val_dir[8779*3 + 2] = -0.128359f;
+ 	val_dir[8780*3 + 0] = 0.074613f;	val_dir[8780*3 + 1] = -0.988627f;	val_dir[8780*3 + 2] = -0.130573f;
+ 	val_dir[8781*3 + 0] = 0.094865f;	val_dir[8781*3 + 1] = -0.986591f;	val_dir[8781*3 + 2] = -0.132810f;
+ 	val_dir[8782*3 + 0] = 0.115771f;	val_dir[8782*3 + 1] = -0.984050f;	val_dir[8782*3 + 2] = -0.135066f;
+ 	val_dir[8783*3 + 0] = 0.137334f;	val_dir[8783*3 + 1] = -0.980958f;	val_dir[8783*3 + 2] = -0.137334f;
+ 	val_dir[8784*3 + 0] = 0.159554f;	val_dir[8784*3 + 1] = -0.977267f;	val_dir[8784*3 + 2] = -0.139610f;
+ 	val_dir[8785*3 + 0] = 0.182424f;	val_dir[8785*3 + 1] = -0.972929f;	val_dir[8785*3 + 2] = -0.141885f;
+ 	val_dir[8786*3 + 0] = 0.205934f;	val_dir[8786*3 + 1] = -0.967890f;	val_dir[8786*3 + 2] = -0.144154f;
+ 	val_dir[8787*3 + 0] = 0.230067f;	val_dir[8787*3 + 1] = -0.962099f;	val_dir[8787*3 + 2] = -0.146406f;
+ 	val_dir[8788*3 + 0] = 0.254801f;	val_dir[8788*3 + 1] = -0.955502f;	val_dir[8788*3 + 2] = -0.148634f;
+ 	val_dir[8789*3 + 0] = 0.280105f;	val_dir[8789*3 + 1] = -0.948047f;	val_dir[8789*3 + 2] = -0.150826f;
+ 	val_dir[8790*3 + 0] = 0.305942f;	val_dir[8790*3 + 1] = -0.939680f;	val_dir[8790*3 + 2] = -0.152971f;
+ 	val_dir[8791*3 + 0] = 0.332269f;	val_dir[8791*3 + 1] = -0.930352f;	val_dir[8791*3 + 2] = -0.155059f;
+ 	val_dir[8792*3 + 0] = 0.359030f;	val_dir[8792*3 + 1] = -0.920014f;	val_dir[8792*3 + 2] = -0.157075f;
+ 	val_dir[8793*3 + 0] = 0.386164f;	val_dir[8793*3 + 1] = -0.908622f;	val_dir[8793*3 + 2] = -0.159009f;
+ 	val_dir[8794*3 + 0] = 0.413602f;	val_dir[8794*3 + 1] = -0.896137f;	val_dir[8794*3 + 2] = -0.160845f;
+ 	val_dir[8795*3 + 0] = 0.441264f;	val_dir[8795*3 + 1] = -0.882528f;	val_dir[8795*3 + 2] = -0.162571f;
+ 	val_dir[8796*3 + 0] = 0.469065f;	val_dir[8796*3 + 1] = -0.867770f;	val_dir[8796*3 + 2] = -0.164173f;
+ 	val_dir[8797*3 + 0] = 0.496911f;	val_dir[8797*3 + 1] = -0.851847f;	val_dir[8797*3 + 2] = -0.165637f;
+ 	val_dir[8798*3 + 0] = 0.524703f;	val_dir[8798*3 + 1] = -0.834754f;	val_dir[8798*3 + 2] = -0.166951f;
+ 	val_dir[8799*3 + 0] = 0.552336f;	val_dir[8799*3 + 1] = -0.816497f;	val_dir[8799*3 + 2] = -0.168102f;
+ 	val_dir[8800*3 + 0] = 0.579703f;	val_dir[8800*3 + 1] = -0.797092f;	val_dir[8800*3 + 2] = -0.169080f;
+ 	val_dir[8801*3 + 0] = 0.606696f;	val_dir[8801*3 + 1] = -0.776571f;	val_dir[8801*3 + 2] = -0.169875f;
+ 	val_dir[8802*3 + 0] = 0.633205f;	val_dir[8802*3 + 1] = -0.754976f;	val_dir[8802*3 + 2] = -0.170478f;
+ 	val_dir[8803*3 + 0] = 0.659125f;	val_dir[8803*3 + 1] = -0.732361f;	val_dir[8803*3 + 2] = -0.170884f;
+ 	val_dir[8804*3 + 0] = 0.684353f;	val_dir[8804*3 + 1] = -0.708794f;	val_dir[8804*3 + 2] = -0.171088f;
+ 	val_dir[8805*3 + 0] = 0.708794f;	val_dir[8805*3 + 1] = -0.684353f;	val_dir[8805*3 + 2] = -0.171088f;
+ 	val_dir[8806*3 + 0] = 0.732361f;	val_dir[8806*3 + 1] = -0.659125f;	val_dir[8806*3 + 2] = -0.170884f;
+ 	val_dir[8807*3 + 0] = 0.754976f;	val_dir[8807*3 + 1] = -0.633205f;	val_dir[8807*3 + 2] = -0.170478f;
+ 	val_dir[8808*3 + 0] = 0.776571f;	val_dir[8808*3 + 1] = -0.606696f;	val_dir[8808*3 + 2] = -0.169875f;
+ 	val_dir[8809*3 + 0] = 0.797092f;	val_dir[8809*3 + 1] = -0.579703f;	val_dir[8809*3 + 2] = -0.169080f;
+ 	val_dir[8810*3 + 0] = 0.816497f;	val_dir[8810*3 + 1] = -0.552336f;	val_dir[8810*3 + 2] = -0.168102f;
+ 	val_dir[8811*3 + 0] = 0.834754f;	val_dir[8811*3 + 1] = -0.524703f;	val_dir[8811*3 + 2] = -0.166951f;
+ 	val_dir[8812*3 + 0] = 0.851847f;	val_dir[8812*3 + 1] = -0.496911f;	val_dir[8812*3 + 2] = -0.165637f;
+ 	val_dir[8813*3 + 0] = 0.867770f;	val_dir[8813*3 + 1] = -0.469065f;	val_dir[8813*3 + 2] = -0.164173f;
+ 	val_dir[8814*3 + 0] = 0.882528f;	val_dir[8814*3 + 1] = -0.441264f;	val_dir[8814*3 + 2] = -0.162571f;
+ 	val_dir[8815*3 + 0] = 0.896137f;	val_dir[8815*3 + 1] = -0.413602f;	val_dir[8815*3 + 2] = -0.160845f;
+ 	val_dir[8816*3 + 0] = 0.908622f;	val_dir[8816*3 + 1] = -0.386164f;	val_dir[8816*3 + 2] = -0.159009f;
+ 	val_dir[8817*3 + 0] = 0.920014f;	val_dir[8817*3 + 1] = -0.359030f;	val_dir[8817*3 + 2] = -0.157075f;
+ 	val_dir[8818*3 + 0] = 0.930352f;	val_dir[8818*3 + 1] = -0.332269f;	val_dir[8818*3 + 2] = -0.155059f;
+ 	val_dir[8819*3 + 0] = 0.939680f;	val_dir[8819*3 + 1] = -0.305942f;	val_dir[8819*3 + 2] = -0.152971f;
+ 	val_dir[8820*3 + 0] = 0.948047f;	val_dir[8820*3 + 1] = -0.280105f;	val_dir[8820*3 + 2] = -0.150826f;
+ 	val_dir[8821*3 + 0] = 0.955502f;	val_dir[8821*3 + 1] = -0.254801f;	val_dir[8821*3 + 2] = -0.148634f;
+ 	val_dir[8822*3 + 0] = 0.962099f;	val_dir[8822*3 + 1] = -0.230067f;	val_dir[8822*3 + 2] = -0.146406f;
+ 	val_dir[8823*3 + 0] = 0.967890f;	val_dir[8823*3 + 1] = -0.205934f;	val_dir[8823*3 + 2] = -0.144154f;
+ 	val_dir[8824*3 + 0] = 0.972929f;	val_dir[8824*3 + 1] = -0.182424f;	val_dir[8824*3 + 2] = -0.141885f;
+ 	val_dir[8825*3 + 0] = 0.977267f;	val_dir[8825*3 + 1] = -0.159554f;	val_dir[8825*3 + 2] = -0.139610f;
+ 	val_dir[8826*3 + 0] = 0.980958f;	val_dir[8826*3 + 1] = -0.137334f;	val_dir[8826*3 + 2] = -0.137334f;
+ 	val_dir[8827*3 + 0] = 0.984050f;	val_dir[8827*3 + 1] = -0.115771f;	val_dir[8827*3 + 2] = -0.135066f;
+ 	val_dir[8828*3 + 0] = 0.986591f;	val_dir[8828*3 + 1] = -0.094865f;	val_dir[8828*3 + 2] = -0.132810f;
+ 	val_dir[8829*3 + 0] = 0.988627f;	val_dir[8829*3 + 1] = -0.074613f;	val_dir[8829*3 + 2] = -0.130573f;
+ 	val_dir[8830*3 + 0] = 0.990201f;	val_dir[8830*3 + 1] = -0.055011f;	val_dir[8830*3 + 2] = -0.128359f;
+ 	val_dir[8831*3 + 0] = 0.991353f;	val_dir[8831*3 + 1] = -0.036049f;	val_dir[8831*3 + 2] = -0.126172f;
+ 	val_dir[8832*3 + 0] = 0.992122f;	val_dir[8832*3 + 1] = -0.017716f;	val_dir[8832*3 + 2] = -0.124015f;
+ 	val_dir[8833*3 + 0] = 0.992543f;	val_dir[8833*3 + 1] = 0.0f;	val_dir[8833*3 + 2] = -0.121891f;
+ 	val_dir[8834*3 + 0] = 0.996158f;	val_dir[8834*3 + 1] = 0.017175f;	val_dir[8834*3 + 2] = -0.085876f;
+ 	val_dir[8835*3 + 0] = 0.998138f;	val_dir[8835*3 + 1] = 0.033835f;	val_dir[8835*3 + 2] = -0.050753f;
+ 	val_dir[8836*3 + 0] = 0.998614f;	val_dir[8836*3 + 1] = 0.049931f;	val_dir[8836*3 + 2] = -0.016644f;
+ 	val_dir[8837*3 + 0] = -0.066519f;	val_dir[8837*3 + 1] = -0.997785f;	val_dir[8837*3 + 2] = 0.0f;
+ 	val_dir[8838*3 + 0] = -0.050753f;	val_dir[8838*3 + 1] = -0.998138f;	val_dir[8838*3 + 2] = -0.033835f;
+ 	val_dir[8839*3 + 0] = -0.034381f;	val_dir[8839*3 + 1] = -0.997041f;	val_dir[8839*3 + 2] = -0.068761f;
+ 	val_dir[8840*3 + 0] = -0.017445f;	val_dir[8840*3 + 1] = -0.994354f;	val_dir[8840*3 + 2] = -0.104669f;
+ 	val_dir[8841*3 + 0] = 0.0f;	val_dir[8841*3 + 1] = -0.989949f;	val_dir[8841*3 + 2] = -0.141421f;
+ 	val_dir[8842*3 + 0] = 0.017990f;	val_dir[8842*3 + 1] = -0.989426f;	val_dir[8842*3 + 2] = -0.143917f;
+ 	val_dir[8843*3 + 0] = 0.036613f;	val_dir[8843*3 + 1] = -0.988540f;	val_dir[8843*3 + 2] = -0.146450f;
+ 	val_dir[8844*3 + 0] = 0.055882f;	val_dir[8844*3 + 1] = -0.987254f;	val_dir[8844*3 + 2] = -0.149019f;
+ 	val_dir[8845*3 + 0] = 0.075810f;	val_dir[8845*3 + 1] = -0.985527f;	val_dir[8845*3 + 2] = -0.151620f;
+ 	val_dir[8846*3 + 0] = 0.096404f;	val_dir[8846*3 + 1] = -0.983318f;	val_dir[8846*3 + 2] = -0.154246f;
+ 	val_dir[8847*3 + 0] = 0.117670f;	val_dir[8847*3 + 1] = -0.980581f;	val_dir[8847*3 + 2] = -0.156893f;
+ 	val_dir[8848*3 + 0] = 0.139610f;	val_dir[8848*3 + 1] = -0.977267f;	val_dir[8848*3 + 2] = -0.159554f;
+ 	val_dir[8849*3 + 0] = 0.162221f;	val_dir[8849*3 + 1] = -0.973329f;	val_dir[8849*3 + 2] = -0.162221f;
+ 	val_dir[8850*3 + 0] = 0.185498f;	val_dir[8850*3 + 1] = -0.968712f;	val_dir[8850*3 + 2] = -0.164887f;
+ 	val_dir[8851*3 + 0] = 0.209427f;	val_dir[8851*3 + 1] = -0.963364f;	val_dir[8851*3 + 2] = -0.167542f;
+ 	val_dir[8852*3 + 0] = 0.233990f;	val_dir[8852*3 + 1] = -0.957230f;	val_dir[8852*3 + 2] = -0.170174f;
+ 	val_dir[8853*3 + 0] = 0.259161f;	val_dir[8853*3 + 1] = -0.950255f;	val_dir[8853*3 + 2] = -0.172774f;
+ 	val_dir[8854*3 + 0] = 0.284907f;	val_dir[8854*3 + 1] = -0.942384f;	val_dir[8854*3 + 2] = -0.175327f;
+ 	val_dir[8855*3 + 0] = 0.311188f;	val_dir[8855*3 + 1] = -0.933564f;	val_dir[8855*3 + 2] = -0.177822f;
+ 	val_dir[8856*3 + 0] = 0.337954f;	val_dir[8856*3 + 1] = -0.923742f;	val_dir[8856*3 + 2] = -0.180242f;
+ 	val_dir[8857*3 + 0] = 0.365148f;	val_dir[8857*3 + 1] = -0.912871f;	val_dir[8857*3 + 2] = -0.182574f;
+ 	val_dir[8858*3 + 0] = 0.392703f;	val_dir[8858*3 + 1] = -0.900907f;	val_dir[8858*3 + 2] = -0.184801f;
+ 	val_dir[8859*3 + 0] = 0.420542f;	val_dir[8859*3 + 1] = -0.887812f;	val_dir[8859*3 + 2] = -0.186908f;
+ 	val_dir[8860*3 + 0] = 0.448583f;	val_dir[8860*3 + 1] = -0.873555f;	val_dir[8860*3 + 2] = -0.188877f;
+ 	val_dir[8861*3 + 0] = 0.476731f;	val_dir[8861*3 + 1] = -0.858116f;	val_dir[8861*3 + 2] = -0.190693f;
+ 	val_dir[8862*3 + 0] = 0.504889f;	val_dir[8862*3 + 1] = -0.841482f;	val_dir[8862*3 + 2] = -0.192339f;
+ 	val_dir[8863*3 + 0] = 0.532952f;	val_dir[8863*3 + 1] = -0.823653f;	val_dir[8863*3 + 2] = -0.193801f;
+ 	val_dir[8864*3 + 0] = 0.560809f;	val_dir[8864*3 + 1] = -0.804639f;	val_dir[8864*3 + 2] = -0.195064f;
+ 	val_dir[8865*3 + 0] = 0.588348f;	val_dir[8865*3 + 1] = -0.784465f;	val_dir[8865*3 + 2] = -0.196116f;
+ 	val_dir[8866*3 + 0] = 0.615457f;	val_dir[8866*3 + 1] = -0.763167f;	val_dir[8866*3 + 2] = -0.196946f;
+ 	val_dir[8867*3 + 0] = 0.642024f;	val_dir[8867*3 + 1] = -0.740797f;	val_dir[8867*3 + 2] = -0.197546f;
+ 	val_dir[8868*3 + 0] = 0.667940f;	val_dir[8868*3 + 1] = -0.717418f;	val_dir[8868*3 + 2] = -0.197908f;
+ 	val_dir[8869*3 + 0] = 0.693103f;	val_dir[8869*3 + 1] = -0.693103f;	val_dir[8869*3 + 2] = -0.198030f;
+ 	val_dir[8870*3 + 0] = 0.717418f;	val_dir[8870*3 + 1] = -0.667940f;	val_dir[8870*3 + 2] = -0.197908f;
+ 	val_dir[8871*3 + 0] = 0.740797f;	val_dir[8871*3 + 1] = -0.642024f;	val_dir[8871*3 + 2] = -0.197546f;
+ 	val_dir[8872*3 + 0] = 0.763167f;	val_dir[8872*3 + 1] = -0.615457f;	val_dir[8872*3 + 2] = -0.196946f;
+ 	val_dir[8873*3 + 0] = 0.784465f;	val_dir[8873*3 + 1] = -0.588348f;	val_dir[8873*3 + 2] = -0.196116f;
+ 	val_dir[8874*3 + 0] = 0.804639f;	val_dir[8874*3 + 1] = -0.560809f;	val_dir[8874*3 + 2] = -0.195064f;
+ 	val_dir[8875*3 + 0] = 0.823653f;	val_dir[8875*3 + 1] = -0.532952f;	val_dir[8875*3 + 2] = -0.193801f;
+ 	val_dir[8876*3 + 0] = 0.841482f;	val_dir[8876*3 + 1] = -0.504889f;	val_dir[8876*3 + 2] = -0.192339f;
+ 	val_dir[8877*3 + 0] = 0.858116f;	val_dir[8877*3 + 1] = -0.476731f;	val_dir[8877*3 + 2] = -0.190693f;
+ 	val_dir[8878*3 + 0] = 0.873555f;	val_dir[8878*3 + 1] = -0.448583f;	val_dir[8878*3 + 2] = -0.188877f;
+ 	val_dir[8879*3 + 0] = 0.887812f;	val_dir[8879*3 + 1] = -0.420542f;	val_dir[8879*3 + 2] = -0.186908f;
+ 	val_dir[8880*3 + 0] = 0.900907f;	val_dir[8880*3 + 1] = -0.392703f;	val_dir[8880*3 + 2] = -0.184801f;
+ 	val_dir[8881*3 + 0] = 0.912871f;	val_dir[8881*3 + 1] = -0.365148f;	val_dir[8881*3 + 2] = -0.182574f;
+ 	val_dir[8882*3 + 0] = 0.923742f;	val_dir[8882*3 + 1] = -0.337954f;	val_dir[8882*3 + 2] = -0.180242f;
+ 	val_dir[8883*3 + 0] = 0.933564f;	val_dir[8883*3 + 1] = -0.311188f;	val_dir[8883*3 + 2] = -0.177822f;
+ 	val_dir[8884*3 + 0] = 0.942384f;	val_dir[8884*3 + 1] = -0.284907f;	val_dir[8884*3 + 2] = -0.175327f;
+ 	val_dir[8885*3 + 0] = 0.950255f;	val_dir[8885*3 + 1] = -0.259161f;	val_dir[8885*3 + 2] = -0.172774f;
+ 	val_dir[8886*3 + 0] = 0.957230f;	val_dir[8886*3 + 1] = -0.233990f;	val_dir[8886*3 + 2] = -0.170174f;
+ 	val_dir[8887*3 + 0] = 0.963364f;	val_dir[8887*3 + 1] = -0.209427f;	val_dir[8887*3 + 2] = -0.167542f;
+ 	val_dir[8888*3 + 0] = 0.968712f;	val_dir[8888*3 + 1] = -0.185498f;	val_dir[8888*3 + 2] = -0.164887f;
+ 	val_dir[8889*3 + 0] = 0.973329f;	val_dir[8889*3 + 1] = -0.162221f;	val_dir[8889*3 + 2] = -0.162221f;
+ 	val_dir[8890*3 + 0] = 0.977267f;	val_dir[8890*3 + 1] = -0.139610f;	val_dir[8890*3 + 2] = -0.159554f;
+ 	val_dir[8891*3 + 0] = 0.980581f;	val_dir[8891*3 + 1] = -0.117670f;	val_dir[8891*3 + 2] = -0.156893f;
+ 	val_dir[8892*3 + 0] = 0.983318f;	val_dir[8892*3 + 1] = -0.096404f;	val_dir[8892*3 + 2] = -0.154246f;
+ 	val_dir[8893*3 + 0] = 0.985527f;	val_dir[8893*3 + 1] = -0.075810f;	val_dir[8893*3 + 2] = -0.151620f;
+ 	val_dir[8894*3 + 0] = 0.987254f;	val_dir[8894*3 + 1] = -0.055882f;	val_dir[8894*3 + 2] = -0.149019f;
+ 	val_dir[8895*3 + 0] = 0.988540f;	val_dir[8895*3 + 1] = -0.036613f;	val_dir[8895*3 + 2] = -0.146450f;
+ 	val_dir[8896*3 + 0] = 0.989426f;	val_dir[8896*3 + 1] = -0.017990f;	val_dir[8896*3 + 2] = -0.143917f;
+ 	val_dir[8897*3 + 0] = 0.989949f;	val_dir[8897*3 + 1] = 0.0f;	val_dir[8897*3 + 2] = -0.141421f;
+ 	val_dir[8898*3 + 0] = 0.994354f;	val_dir[8898*3 + 1] = 0.017445f;	val_dir[8898*3 + 2] = -0.104669f;
+ 	val_dir[8899*3 + 0] = 0.997041f;	val_dir[8899*3 + 1] = 0.034381f;	val_dir[8899*3 + 2] = -0.068761f;
+ 	val_dir[8900*3 + 0] = 0.998138f;	val_dir[8900*3 + 1] = 0.050753f;	val_dir[8900*3 + 2] = -0.033835f;
+ 	val_dir[8901*3 + 0] = 0.997785f;	val_dir[8901*3 + 1] = 0.066519f;	val_dir[8901*3 + 2] = 0.0f;
+ 	val_dir[8902*3 + 0] = -0.067632f;	val_dir[8902*3 + 1] = -0.997567f;	val_dir[8902*3 + 2] = -0.016908f;
+ 	val_dir[8903*3 + 0] = -0.051586f;	val_dir[8903*3 + 1] = -0.997335f;	val_dir[8903*3 + 2] = -0.051586f;
+ 	val_dir[8904*3 + 0] = -0.034932f;	val_dir[8904*3 + 1] = -0.995567f;	val_dir[8904*3 + 2] = -0.087330f;
+ 	val_dir[8905*3 + 0] = -0.017716f;	val_dir[8905*3 + 1] = -0.992122f;	val_dir[8905*3 + 2] = -0.124015f;
+ 	val_dir[8906*3 + 0] = 0.0f;	val_dir[8906*3 + 1] = -0.986875f;	val_dir[8906*3 + 2] = -0.161489f;
+ 	val_dir[8907*3 + 0] = 0.018264f;	val_dir[8907*3 + 1] = -0.986229f;	val_dir[8907*3 + 2] = -0.164372f;
+ 	val_dir[8908*3 + 0] = 0.037178f;	val_dir[8908*3 + 1] = -0.985205f;	val_dir[8908*3 + 2] = -0.167299f;
+ 	val_dir[8909*3 + 0] = 0.056756f;	val_dir[8909*3 + 1] = -0.983762f;	val_dir[8909*3 + 2] = -0.170267f;
+ 	val_dir[8910*3 + 0] = 0.077009f;	val_dir[8910*3 + 1] = -0.981859f;	val_dir[8910*3 + 2] = -0.173269f;
+ 	val_dir[8911*3 + 0] = 0.097945f;	val_dir[8911*3 + 1] = -0.979451f;	val_dir[8911*3 + 2] = -0.176301f;
+ 	val_dir[8912*3 + 0] = 0.119570f;	val_dir[8912*3 + 1] = -0.976491f;	val_dir[8912*3 + 2] = -0.179355f;
+ 	val_dir[8913*3 + 0] = 0.141885f;	val_dir[8913*3 + 1] = -0.972929f;	val_dir[8913*3 + 2] = -0.182424f;
+ 	val_dir[8914*3 + 0] = 0.164887f;	val_dir[8914*3 + 1] = -0.968712f;	val_dir[8914*3 + 2] = -0.185498f;
+ 	val_dir[8915*3 + 0] = 0.188567f;	val_dir[8915*3 + 1] = -0.963787f;	val_dir[8915*3 + 2] = -0.188567f;
+ 	val_dir[8916*3 + 0] = 0.212911f;	val_dir[8916*3 + 1] = -0.958098f;	val_dir[8916*3 + 2] = -0.191620f;
+ 	val_dir[8917*3 + 0] = 0.237897f;	val_dir[8917*3 + 1] = -0.951588f;	val_dir[8917*3 + 2] = -0.194643f;
+ 	val_dir[8918*3 + 0] = 0.263498f;	val_dir[8918*3 + 1] = -0.94420f;	val_dir[8918*3 + 2] = -0.197623f;
+ 	val_dir[8919*3 + 0] = 0.289677f;	val_dir[8919*3 + 1] = -0.935879f;	val_dir[8919*3 + 2] = -0.200545f;
+ 	val_dir[8920*3 + 0] = 0.316389f;	val_dir[8920*3 + 1] = -0.926568f;	val_dir[8920*3 + 2] = -0.203393f;
+ 	val_dir[8921*3 + 0] = 0.343582f;	val_dir[8921*3 + 1] = -0.916217f;	val_dir[8921*3 + 2] = -0.206149f;
+ 	val_dir[8922*3 + 0] = 0.371191f;	val_dir[8922*3 + 1] = -0.904777f;	val_dir[8922*3 + 2] = -0.208795f;
+ 	val_dir[8923*3 + 0] = 0.399145f;	val_dir[8923*3 + 1] = -0.892206f;	val_dir[8923*3 + 2] = -0.211312f;
+ 	val_dir[8924*3 + 0] = 0.427362f;	val_dir[8924*3 + 1] = -0.878466f;	val_dir[8924*3 + 2] = -0.213681f;
+ 	val_dir[8925*3 + 0] = 0.455752f;	val_dir[8925*3 + 1] = -0.863530f;	val_dir[8925*3 + 2] = -0.215883f;
+ 	val_dir[8926*3 + 0] = 0.484217f;	val_dir[8926*3 + 1] = -0.847381f;	val_dir[8926*3 + 2] = -0.217898f;
+ 	val_dir[8927*3 + 0] = 0.512653f;	val_dir[8927*3 + 1] = -0.830009f;	val_dir[8927*3 + 2] = -0.219708f;
+ 	val_dir[8928*3 + 0] = 0.540947f;	val_dir[8928*3 + 1] = -0.811421f;	val_dir[8928*3 + 2] = -0.221297f;
+ 	val_dir[8929*3 + 0] = 0.568986f;	val_dir[8929*3 + 1] = -0.791633f;	val_dir[8929*3 + 2] = -0.222647f;
+ 	val_dir[8930*3 + 0] = 0.596653f;	val_dir[8930*3 + 1] = -0.770677f;	val_dir[8930*3 + 2] = -0.223745f;
+ 	val_dir[8931*3 + 0] = 0.623831f;	val_dir[8931*3 + 1] = -0.748598f;	val_dir[8931*3 + 2] = -0.224579f;
+ 	val_dir[8932*3 + 0] = 0.650407f;	val_dir[8932*3 + 1] = -0.725454f;	val_dir[8932*3 + 2] = -0.225141f;
+ 	val_dir[8933*3 + 0] = 0.676269f;	val_dir[8933*3 + 1] = -0.701316f;	val_dir[8933*3 + 2] = -0.225423f;
+ 	val_dir[8934*3 + 0] = 0.701316f;	val_dir[8934*3 + 1] = -0.676269f;	val_dir[8934*3 + 2] = -0.225423f;
+ 	val_dir[8935*3 + 0] = 0.725454f;	val_dir[8935*3 + 1] = -0.650407f;	val_dir[8935*3 + 2] = -0.225141f;
+ 	val_dir[8936*3 + 0] = 0.748598f;	val_dir[8936*3 + 1] = -0.623831f;	val_dir[8936*3 + 2] = -0.224579f;
+ 	val_dir[8937*3 + 0] = 0.770677f;	val_dir[8937*3 + 1] = -0.596653f;	val_dir[8937*3 + 2] = -0.223745f;
+ 	val_dir[8938*3 + 0] = 0.791633f;	val_dir[8938*3 + 1] = -0.568986f;	val_dir[8938*3 + 2] = -0.222647f;
+ 	val_dir[8939*3 + 0] = 0.811421f;	val_dir[8939*3 + 1] = -0.540947f;	val_dir[8939*3 + 2] = -0.221297f;
+ 	val_dir[8940*3 + 0] = 0.830009f;	val_dir[8940*3 + 1] = -0.512653f;	val_dir[8940*3 + 2] = -0.219708f;
+ 	val_dir[8941*3 + 0] = 0.847381f;	val_dir[8941*3 + 1] = -0.484217f;	val_dir[8941*3 + 2] = -0.217898f;
+ 	val_dir[8942*3 + 0] = 0.863530f;	val_dir[8942*3 + 1] = -0.455752f;	val_dir[8942*3 + 2] = -0.215883f;
+ 	val_dir[8943*3 + 0] = 0.878466f;	val_dir[8943*3 + 1] = -0.427362f;	val_dir[8943*3 + 2] = -0.213681f;
+ 	val_dir[8944*3 + 0] = 0.892206f;	val_dir[8944*3 + 1] = -0.399145f;	val_dir[8944*3 + 2] = -0.211312f;
+ 	val_dir[8945*3 + 0] = 0.904777f;	val_dir[8945*3 + 1] = -0.371191f;	val_dir[8945*3 + 2] = -0.208795f;
+ 	val_dir[8946*3 + 0] = 0.916217f;	val_dir[8946*3 + 1] = -0.343582f;	val_dir[8946*3 + 2] = -0.206149f;
+ 	val_dir[8947*3 + 0] = 0.926568f;	val_dir[8947*3 + 1] = -0.316389f;	val_dir[8947*3 + 2] = -0.203393f;
+ 	val_dir[8948*3 + 0] = 0.935879f;	val_dir[8948*3 + 1] = -0.289677f;	val_dir[8948*3 + 2] = -0.200545f;
+ 	val_dir[8949*3 + 0] = 0.94420f;	val_dir[8949*3 + 1] = -0.263498f;	val_dir[8949*3 + 2] = -0.197623f;
+ 	val_dir[8950*3 + 0] = 0.951588f;	val_dir[8950*3 + 1] = -0.237897f;	val_dir[8950*3 + 2] = -0.194643f;
+ 	val_dir[8951*3 + 0] = 0.958098f;	val_dir[8951*3 + 1] = -0.212911f;	val_dir[8951*3 + 2] = -0.191620f;
+ 	val_dir[8952*3 + 0] = 0.963787f;	val_dir[8952*3 + 1] = -0.188567f;	val_dir[8952*3 + 2] = -0.188567f;
+ 	val_dir[8953*3 + 0] = 0.968712f;	val_dir[8953*3 + 1] = -0.164887f;	val_dir[8953*3 + 2] = -0.185498f;
+ 	val_dir[8954*3 + 0] = 0.972929f;	val_dir[8954*3 + 1] = -0.141885f;	val_dir[8954*3 + 2] = -0.182424f;
+ 	val_dir[8955*3 + 0] = 0.976491f;	val_dir[8955*3 + 1] = -0.119570f;	val_dir[8955*3 + 2] = -0.179355f;
+ 	val_dir[8956*3 + 0] = 0.979451f;	val_dir[8956*3 + 1] = -0.097945f;	val_dir[8956*3 + 2] = -0.176301f;
+ 	val_dir[8957*3 + 0] = 0.981859f;	val_dir[8957*3 + 1] = -0.077009f;	val_dir[8957*3 + 2] = -0.173269f;
+ 	val_dir[8958*3 + 0] = 0.983762f;	val_dir[8958*3 + 1] = -0.056756f;	val_dir[8958*3 + 2] = -0.170267f;
+ 	val_dir[8959*3 + 0] = 0.985205f;	val_dir[8959*3 + 1] = -0.037178f;	val_dir[8959*3 + 2] = -0.167299f;
+ 	val_dir[8960*3 + 0] = 0.986229f;	val_dir[8960*3 + 1] = -0.018264f;	val_dir[8960*3 + 2] = -0.164372f;
+ 	val_dir[8961*3 + 0] = 0.986875f;	val_dir[8961*3 + 1] = 0.0f;	val_dir[8961*3 + 2] = -0.161489f;
+ 	val_dir[8962*3 + 0] = 0.992122f;	val_dir[8962*3 + 1] = 0.017716f;	val_dir[8962*3 + 2] = -0.124015f;
+ 	val_dir[8963*3 + 0] = 0.995567f;	val_dir[8963*3 + 1] = 0.034932f;	val_dir[8963*3 + 2] = -0.087330f;
+ 	val_dir[8964*3 + 0] = 0.997335f;	val_dir[8964*3 + 1] = 0.051586f;	val_dir[8964*3 + 2] = -0.051586f;
+ 	val_dir[8965*3 + 0] = 0.997567f;	val_dir[8965*3 + 1] = 0.067632f;	val_dir[8965*3 + 2] = -0.016908f;
+ 	val_dir[8966*3 + 0] = -0.084443f;	val_dir[8966*3 + 1] = -0.996428f;	val_dir[8966*3 + 2] = 0.0f;
+ 	val_dir[8967*3 + 0] = -0.068761f;	val_dir[8967*3 + 1] = -0.997041f;	val_dir[8967*3 + 2] = -0.034381f;
+ 	val_dir[8968*3 + 0] = -0.052430f;	val_dir[8968*3 + 1] = -0.996175f;	val_dir[8968*3 + 2] = -0.069907f;
+ 	val_dir[8969*3 + 0] = -0.035489f;	val_dir[8969*3 + 1] = -0.993683f;	val_dir[8969*3 + 2] = -0.106466f;
+ 	val_dir[8970*3 + 0] = -0.017990f;	val_dir[8970*3 + 1] = -0.989426f;	val_dir[8970*3 + 2] = -0.143917f;
+ 	val_dir[8971*3 + 0] = 0.0f;	val_dir[8971*3 + 1] = -0.983282f;	val_dir[8971*3 + 2] = -0.182089f;
+ 	val_dir[8972*3 + 0] = 0.018538f;	val_dir[8972*3 + 1] = -0.982493f;	val_dir[8972*3 + 2] = -0.185376f;
+ 	val_dir[8973*3 + 0] = 0.037743f;	val_dir[8973*3 + 1] = -0.981307f;	val_dir[8973*3 + 2] = -0.188713f;
+ 	val_dir[8974*3 + 0] = 0.057628f;	val_dir[8974*3 + 1] = -0.979683f;	val_dir[8974*3 + 2] = -0.192095f;
+ 	val_dir[8975*3 + 0] = 0.078206f;	val_dir[8975*3 + 1] = -0.977577f;	val_dir[8975*3 + 2] = -0.195515f;
+ 	val_dir[8976*3 + 0] = 0.099484f;	val_dir[8976*3 + 1] = -0.974943f;	val_dir[8976*3 + 2] = -0.198968f;
+ 	val_dir[8977*3 + 0] = 0.121466f;	val_dir[8977*3 + 1] = -0.971732f;	val_dir[8977*3 + 2] = -0.202444f;
+ 	val_dir[8978*3 + 0] = 0.144154f;	val_dir[8978*3 + 1] = -0.967890f;	val_dir[8978*3 + 2] = -0.205934f;
+ 	val_dir[8979*3 + 0] = 0.167542f;	val_dir[8979*3 + 1] = -0.963364f;	val_dir[8979*3 + 2] = -0.209427f;
+ 	val_dir[8980*3 + 0] = 0.191620f;	val_dir[8980*3 + 1] = -0.958098f;	val_dir[8980*3 + 2] = -0.212911f;
+ 	val_dir[8981*3 + 0] = 0.216371f;	val_dir[8981*3 + 1] = -0.952033f;	val_dir[8981*3 + 2] = -0.216371f;
+ 	val_dir[8982*3 + 0] = 0.241773f;	val_dir[8982*3 + 1] = -0.945112f;	val_dir[8982*3 + 2] = -0.219793f;
+ 	val_dir[8983*3 + 0] = 0.267793f;	val_dir[8983*3 + 1] = -0.937276f;	val_dir[8983*3 + 2] = -0.223161f;
+ 	val_dir[8984*3 + 0] = 0.294392f;	val_dir[8984*3 + 1] = -0.928467f;	val_dir[8984*3 + 2] = -0.226455f;
+ 	val_dir[8985*3 + 0] = 0.321521f;	val_dir[8985*3 + 1] = -0.918630f;	val_dir[8985*3 + 2] = -0.229658f;
+ 	val_dir[8986*3 + 0] = 0.349121f;	val_dir[8986*3 + 1] = -0.907713f;	val_dir[8986*3 + 2] = -0.232747f;
+ 	val_dir[8987*3 + 0] = 0.377124f;	val_dir[8987*3 + 1] = -0.895669f;	val_dir[8987*3 + 2] = -0.235702f;
+ 	val_dir[8988*3 + 0] = 0.405452f;	val_dir[8988*3 + 1] = -0.882454f;	val_dir[8988*3 + 2] = -0.238501f;
+ 	val_dir[8989*3 + 0] = 0.434019f;	val_dir[8989*3 + 1] = -0.868037f;	val_dir[8989*3 + 2] = -0.241121f;
+ 	val_dir[8990*3 + 0] = 0.462727f;	val_dir[8990*3 + 1] = -0.852392f;	val_dir[8990*3 + 2] = -0.243541f;
+ 	val_dir[8991*3 + 0] = 0.491473f;	val_dir[8991*3 + 1] = -0.835504f;	val_dir[8991*3 + 2] = -0.245737f;
+ 	val_dir[8992*3 + 0] = 0.520146f;	val_dir[8992*3 + 1] = -0.817373f;	val_dir[8992*3 + 2] = -0.247689f;
+ 	val_dir[8993*3 + 0] = 0.548630f;	val_dir[8993*3 + 1] = -0.798007f;	val_dir[8993*3 + 2] = -0.249377f;
+ 	val_dir[8994*3 + 0] = 0.576805f;	val_dir[8994*3 + 1] = -0.777433f;	val_dir[8994*3 + 2] = -0.250785f;
+ 	val_dir[8995*3 + 0] = 0.604551f;	val_dir[8995*3 + 1] = -0.755689f;	val_dir[8995*3 + 2] = -0.251896f;
+ 	val_dir[8996*3 + 0] = 0.631748f;	val_dir[8996*3 + 1] = -0.732828f;	val_dir[8996*3 + 2] = -0.252699f;
+ 	val_dir[8997*3 + 0] = 0.658281f;	val_dir[8997*3 + 1] = -0.708918f;	val_dir[8997*3 + 2] = -0.253185f;
+ 	val_dir[8998*3 + 0] = 0.684038f;	val_dir[8998*3 + 1] = -0.684038f;	val_dir[8998*3 + 2] = -0.253347f;
+ 	val_dir[8999*3 + 0] = 0.708918f;	val_dir[8999*3 + 1] = -0.658281f;	val_dir[8999*3 + 2] = -0.253185f;
+ 	val_dir[9000*3 + 0] = 0.732828f;	val_dir[9000*3 + 1] = -0.631748f;	val_dir[9000*3 + 2] = -0.252699f;
+ 	val_dir[9001*3 + 0] = 0.755689f;	val_dir[9001*3 + 1] = -0.604551f;	val_dir[9001*3 + 2] = -0.251896f;
+ 	val_dir[9002*3 + 0] = 0.777433f;	val_dir[9002*3 + 1] = -0.576805f;	val_dir[9002*3 + 2] = -0.250785f;
+ 	val_dir[9003*3 + 0] = 0.798007f;	val_dir[9003*3 + 1] = -0.548630f;	val_dir[9003*3 + 2] = -0.249377f;
+ 	val_dir[9004*3 + 0] = 0.817373f;	val_dir[9004*3 + 1] = -0.520146f;	val_dir[9004*3 + 2] = -0.247689f;
+ 	val_dir[9005*3 + 0] = 0.835504f;	val_dir[9005*3 + 1] = -0.491473f;	val_dir[9005*3 + 2] = -0.245737f;
+ 	val_dir[9006*3 + 0] = 0.852392f;	val_dir[9006*3 + 1] = -0.462727f;	val_dir[9006*3 + 2] = -0.243541f;
+ 	val_dir[9007*3 + 0] = 0.868037f;	val_dir[9007*3 + 1] = -0.434019f;	val_dir[9007*3 + 2] = -0.241121f;
+ 	val_dir[9008*3 + 0] = 0.882454f;	val_dir[9008*3 + 1] = -0.405452f;	val_dir[9008*3 + 2] = -0.238501f;
+ 	val_dir[9009*3 + 0] = 0.895669f;	val_dir[9009*3 + 1] = -0.377124f;	val_dir[9009*3 + 2] = -0.235702f;
+ 	val_dir[9010*3 + 0] = 0.907713f;	val_dir[9010*3 + 1] = -0.349121f;	val_dir[9010*3 + 2] = -0.232747f;
+ 	val_dir[9011*3 + 0] = 0.918630f;	val_dir[9011*3 + 1] = -0.321521f;	val_dir[9011*3 + 2] = -0.229658f;
+ 	val_dir[9012*3 + 0] = 0.928467f;	val_dir[9012*3 + 1] = -0.294392f;	val_dir[9012*3 + 2] = -0.226455f;
+ 	val_dir[9013*3 + 0] = 0.937276f;	val_dir[9013*3 + 1] = -0.267793f;	val_dir[9013*3 + 2] = -0.223161f;
+ 	val_dir[9014*3 + 0] = 0.945112f;	val_dir[9014*3 + 1] = -0.241773f;	val_dir[9014*3 + 2] = -0.219793f;
+ 	val_dir[9015*3 + 0] = 0.952033f;	val_dir[9015*3 + 1] = -0.216371f;	val_dir[9015*3 + 2] = -0.216371f;
+ 	val_dir[9016*3 + 0] = 0.958098f;	val_dir[9016*3 + 1] = -0.191620f;	val_dir[9016*3 + 2] = -0.212911f;
+ 	val_dir[9017*3 + 0] = 0.963364f;	val_dir[9017*3 + 1] = -0.167542f;	val_dir[9017*3 + 2] = -0.209427f;
+ 	val_dir[9018*3 + 0] = 0.967890f;	val_dir[9018*3 + 1] = -0.144154f;	val_dir[9018*3 + 2] = -0.205934f;
+ 	val_dir[9019*3 + 0] = 0.971732f;	val_dir[9019*3 + 1] = -0.121466f;	val_dir[9019*3 + 2] = -0.202444f;
+ 	val_dir[9020*3 + 0] = 0.974943f;	val_dir[9020*3 + 1] = -0.099484f;	val_dir[9020*3 + 2] = -0.198968f;
+ 	val_dir[9021*3 + 0] = 0.977577f;	val_dir[9021*3 + 1] = -0.078206f;	val_dir[9021*3 + 2] = -0.195515f;
+ 	val_dir[9022*3 + 0] = 0.979683f;	val_dir[9022*3 + 1] = -0.057628f;	val_dir[9022*3 + 2] = -0.192095f;
+ 	val_dir[9023*3 + 0] = 0.981307f;	val_dir[9023*3 + 1] = -0.037743f;	val_dir[9023*3 + 2] = -0.188713f;
+ 	val_dir[9024*3 + 0] = 0.982493f;	val_dir[9024*3 + 1] = -0.018538f;	val_dir[9024*3 + 2] = -0.185376f;
+ 	val_dir[9025*3 + 0] = 0.983282f;	val_dir[9025*3 + 1] = 0.0f;	val_dir[9025*3 + 2] = -0.182089f;
+ 	val_dir[9026*3 + 0] = 0.989426f;	val_dir[9026*3 + 1] = 0.017990f;	val_dir[9026*3 + 2] = -0.143917f;
+ 	val_dir[9027*3 + 0] = 0.993683f;	val_dir[9027*3 + 1] = 0.035489f;	val_dir[9027*3 + 2] = -0.106466f;
+ 	val_dir[9028*3 + 0] = 0.996175f;	val_dir[9028*3 + 1] = 0.052430f;	val_dir[9028*3 + 2] = -0.069907f;
+ 	val_dir[9029*3 + 0] = 0.997041f;	val_dir[9029*3 + 1] = 0.068761f;	val_dir[9029*3 + 2] = -0.034381f;
+ 	val_dir[9030*3 + 0] = 0.996428f;	val_dir[9030*3 + 1] = 0.084443f;	val_dir[9030*3 + 2] = 0.0f;
+ 	val_dir[9031*3 + 0] = -0.085876f;	val_dir[9031*3 + 1] = -0.996158f;	val_dir[9031*3 + 2] = -0.017175f;
+ 	val_dir[9032*3 + 0] = -0.069907f;	val_dir[9032*3 + 1] = -0.996175f;	val_dir[9032*3 + 2] = -0.052430f;
+ 	val_dir[9033*3 + 0] = -0.053283f;	val_dir[9033*3 + 1] = -0.994623f;	val_dir[9033*3 + 2] = -0.088806f;
+ 	val_dir[9034*3 + 0] = -0.036049f;	val_dir[9034*3 + 1] = -0.991353f;	val_dir[9034*3 + 2] = -0.126172f;
+ 	val_dir[9035*3 + 0] = -0.018264f;	val_dir[9035*3 + 1] = -0.986229f;	val_dir[9035*3 + 2] = -0.164372f;
+ 	val_dir[9036*3 + 0] = 0.0f;	val_dir[9036*3 + 1] = -0.979134f;	val_dir[9036*3 + 2] = -0.203216f;
+ 	val_dir[9037*3 + 0] = 0.018811f;	val_dir[9037*3 + 1] = -0.978177f;	val_dir[9037*3 + 2] = -0.206922f;
+ 	val_dir[9038*3 + 0] = 0.038306f;	val_dir[9038*3 + 1] = -0.976804f;	val_dir[9038*3 + 2] = -0.210683f;
+ 	val_dir[9039*3 + 0] = 0.058498f;	val_dir[9039*3 + 1] = -0.974972f;	val_dir[9039*3 + 2] = -0.214494f;
+ 	val_dir[9040*3 + 0] = 0.079399f;	val_dir[9040*3 + 1] = -0.972636f;	val_dir[9040*3 + 2] = -0.218347f;
+ 	val_dir[9041*3 + 0] = 0.101015f;	val_dir[9041*3 + 1] = -0.969746f;	val_dir[9041*3 + 2] = -0.222234f;
+ 	val_dir[9042*3 + 0] = 0.123351f;	val_dir[9042*3 + 1] = -0.966252f;	val_dir[9042*3 + 2] = -0.226144f;
+ 	val_dir[9043*3 + 0] = 0.146406f;	val_dir[9043*3 + 1] = -0.962099f;	val_dir[9043*3 + 2] = -0.230067f;
+ 	val_dir[9044*3 + 0] = 0.170174f;	val_dir[9044*3 + 1] = -0.957230f;	val_dir[9044*3 + 2] = -0.233990f;
+ 	val_dir[9045*3 + 0] = 0.194643f;	val_dir[9045*3 + 1] = -0.951588f;	val_dir[9045*3 + 2] = -0.237897f;
+ 	val_dir[9046*3 + 0] = 0.219793f;	val_dir[9046*3 + 1] = -0.945112f;	val_dir[9046*3 + 2] = -0.241773f;
+ 	val_dir[9047*3 + 0] = 0.245599f;	val_dir[9047*3 + 1] = -0.937743f;	val_dir[9047*3 + 2] = -0.245599f;
+ 	val_dir[9048*3 + 0] = 0.272026f;	val_dir[9048*3 + 1] = -0.929421f;	val_dir[9048*3 + 2] = -0.249357f;
+ 	val_dir[9049*3 + 0] = 0.299028f;	val_dir[9049*3 + 1] = -0.920087f;	val_dir[9049*3 + 2] = -0.253024f;
+ 	val_dir[9050*3 + 0] = 0.326554f;	val_dir[9050*3 + 1] = -0.909687f;	val_dir[9050*3 + 2] = -0.256578f;
+ 	val_dir[9051*3 + 0] = 0.354540f;	val_dir[9051*3 + 1] = -0.898167f;	val_dir[9051*3 + 2] = -0.259996f;
+ 	val_dir[9052*3 + 0] = 0.382911f;	val_dir[9052*3 + 1] = -0.885482f;	val_dir[9052*3 + 2] = -0.263251f;
+ 	val_dir[9053*3 + 0] = 0.411585f;	val_dir[9053*3 + 1] = -0.871592f;	val_dir[9053*3 + 2] = -0.266320f;
+ 	val_dir[9054*3 + 0] = 0.440468f;	val_dir[9054*3 + 1] = -0.856465f;	val_dir[9054*3 + 2] = -0.269175f;
+ 	val_dir[9055*3 + 0] = 0.469458f;	val_dir[9055*3 + 1] = -0.840083f;	val_dir[9055*3 + 2] = -0.271791f;
+ 	val_dir[9056*3 + 0] = 0.498445f;	val_dir[9056*3 + 1] = -0.822434f;	val_dir[9056*3 + 2] = -0.274145f;
+ 	val_dir[9057*3 + 0] = 0.527312f;	val_dir[9057*3 + 1] = -0.803523f;	val_dir[9057*3 + 2] = -0.276211f;
+ 	val_dir[9058*3 + 0] = 0.555939f;	val_dir[9058*3 + 1] = -0.783368f;	val_dir[9058*3 + 2] = -0.277969f;
+ 	val_dir[9059*3 + 0] = 0.584201f;	val_dir[9059*3 + 1] = -0.762001f;	val_dir[9059*3 + 2] = -0.27940f;
+ 	val_dir[9060*3 + 0] = 0.611974f;	val_dir[9060*3 + 1] = -0.739469f;	val_dir[9060*3 + 2] = -0.280488f;
+ 	val_dir[9061*3 + 0] = 0.639138f;	val_dir[9061*3 + 1] = -0.715834f;	val_dir[9061*3 + 2] = -0.281220f;
+ 	val_dir[9062*3 + 0] = 0.665574f;	val_dir[9062*3 + 1] = -0.691173f;	val_dir[9062*3 + 2] = -0.281589f;
+ 	val_dir[9063*3 + 0] = 0.691173f;	val_dir[9063*3 + 1] = -0.665574f;	val_dir[9063*3 + 2] = -0.281589f;
+ 	val_dir[9064*3 + 0] = 0.715834f;	val_dir[9064*3 + 1] = -0.639138f;	val_dir[9064*3 + 2] = -0.281220f;
+ 	val_dir[9065*3 + 0] = 0.739469f;	val_dir[9065*3 + 1] = -0.611974f;	val_dir[9065*3 + 2] = -0.280488f;
+ 	val_dir[9066*3 + 0] = 0.762001f;	val_dir[9066*3 + 1] = -0.584201f;	val_dir[9066*3 + 2] = -0.27940f;
+ 	val_dir[9067*3 + 0] = 0.783368f;	val_dir[9067*3 + 1] = -0.555939f;	val_dir[9067*3 + 2] = -0.277969f;
+ 	val_dir[9068*3 + 0] = 0.803523f;	val_dir[9068*3 + 1] = -0.527312f;	val_dir[9068*3 + 2] = -0.276211f;
+ 	val_dir[9069*3 + 0] = 0.822434f;	val_dir[9069*3 + 1] = -0.498445f;	val_dir[9069*3 + 2] = -0.274145f;
+ 	val_dir[9070*3 + 0] = 0.840083f;	val_dir[9070*3 + 1] = -0.469458f;	val_dir[9070*3 + 2] = -0.271791f;
+ 	val_dir[9071*3 + 0] = 0.856465f;	val_dir[9071*3 + 1] = -0.440468f;	val_dir[9071*3 + 2] = -0.269175f;
+ 	val_dir[9072*3 + 0] = 0.871592f;	val_dir[9072*3 + 1] = -0.411585f;	val_dir[9072*3 + 2] = -0.266320f;
+ 	val_dir[9073*3 + 0] = 0.885482f;	val_dir[9073*3 + 1] = -0.382911f;	val_dir[9073*3 + 2] = -0.263251f;
+ 	val_dir[9074*3 + 0] = 0.898167f;	val_dir[9074*3 + 1] = -0.354540f;	val_dir[9074*3 + 2] = -0.259996f;
+ 	val_dir[9075*3 + 0] = 0.909687f;	val_dir[9075*3 + 1] = -0.326554f;	val_dir[9075*3 + 2] = -0.256578f;
+ 	val_dir[9076*3 + 0] = 0.920087f;	val_dir[9076*3 + 1] = -0.299028f;	val_dir[9076*3 + 2] = -0.253024f;
+ 	val_dir[9077*3 + 0] = 0.929421f;	val_dir[9077*3 + 1] = -0.272026f;	val_dir[9077*3 + 2] = -0.249357f;
+ 	val_dir[9078*3 + 0] = 0.937743f;	val_dir[9078*3 + 1] = -0.245599f;	val_dir[9078*3 + 2] = -0.245599f;
+ 	val_dir[9079*3 + 0] = 0.945112f;	val_dir[9079*3 + 1] = -0.219793f;	val_dir[9079*3 + 2] = -0.241773f;
+ 	val_dir[9080*3 + 0] = 0.951588f;	val_dir[9080*3 + 1] = -0.194643f;	val_dir[9080*3 + 2] = -0.237897f;
+ 	val_dir[9081*3 + 0] = 0.957230f;	val_dir[9081*3 + 1] = -0.170174f;	val_dir[9081*3 + 2] = -0.233990f;
+ 	val_dir[9082*3 + 0] = 0.962099f;	val_dir[9082*3 + 1] = -0.146406f;	val_dir[9082*3 + 2] = -0.230067f;
+ 	val_dir[9083*3 + 0] = 0.966252f;	val_dir[9083*3 + 1] = -0.123351f;	val_dir[9083*3 + 2] = -0.226144f;
+ 	val_dir[9084*3 + 0] = 0.969746f;	val_dir[9084*3 + 1] = -0.101015f;	val_dir[9084*3 + 2] = -0.222234f;
+ 	val_dir[9085*3 + 0] = 0.972636f;	val_dir[9085*3 + 1] = -0.079399f;	val_dir[9085*3 + 2] = -0.218347f;
+ 	val_dir[9086*3 + 0] = 0.974972f;	val_dir[9086*3 + 1] = -0.058498f;	val_dir[9086*3 + 2] = -0.214494f;
+ 	val_dir[9087*3 + 0] = 0.976804f;	val_dir[9087*3 + 1] = -0.038306f;	val_dir[9087*3 + 2] = -0.210683f;
+ 	val_dir[9088*3 + 0] = 0.978177f;	val_dir[9088*3 + 1] = -0.018811f;	val_dir[9088*3 + 2] = -0.206922f;
+ 	val_dir[9089*3 + 0] = 0.979134f;	val_dir[9089*3 + 1] = 0.0f;	val_dir[9089*3 + 2] = -0.203216f;
+ 	val_dir[9090*3 + 0] = 0.986229f;	val_dir[9090*3 + 1] = 0.018264f;	val_dir[9090*3 + 2] = -0.164372f;
+ 	val_dir[9091*3 + 0] = 0.991353f;	val_dir[9091*3 + 1] = 0.036049f;	val_dir[9091*3 + 2] = -0.126172f;
+ 	val_dir[9092*3 + 0] = 0.994623f;	val_dir[9092*3 + 1] = 0.053283f;	val_dir[9092*3 + 2] = -0.088806f;
+ 	val_dir[9093*3 + 0] = 0.996175f;	val_dir[9093*3 + 1] = 0.069907f;	val_dir[9093*3 + 2] = -0.052430f;
+ 	val_dir[9094*3 + 0] = 0.996158f;	val_dir[9094*3 + 1] = 0.085876f;	val_dir[9094*3 + 2] = -0.017175f;
+ 	val_dir[9095*3 + 0] = -0.102899f;	val_dir[9095*3 + 1] = -0.994692f;	val_dir[9095*3 + 2] = 0.0f;
+ 	val_dir[9096*3 + 0] = -0.087330f;	val_dir[9096*3 + 1] = -0.995567f;	val_dir[9096*3 + 2] = -0.034932f;
+ 	val_dir[9097*3 + 0] = -0.071067f;	val_dir[9097*3 + 1] = -0.994937f;	val_dir[9097*3 + 2] = -0.071067f;
+ 	val_dir[9098*3 + 0] = -0.054144f;	val_dir[9098*3 + 1] = -0.992644f;	val_dir[9098*3 + 2] = -0.108288f;
+ 	val_dir[9099*3 + 0] = -0.036613f;	val_dir[9099*3 + 1] = -0.988540f;	val_dir[9099*3 + 2] = -0.146450f;
+ 	val_dir[9100*3 + 0] = -0.018538f;	val_dir[9100*3 + 1] = -0.982493f;	val_dir[9100*3 + 2] = -0.185376f;
+ 	val_dir[9101*3 + 0] = 0.0f;	val_dir[9101*3 + 1] = -0.974391f;	val_dir[9101*3 + 2] = -0.224860f;
+ 	val_dir[9102*3 + 0] = 0.019083f;	val_dir[9102*3 + 1] = -0.973240f;	val_dir[9102*3 + 2] = -0.228998f;
+ 	val_dir[9103*3 + 0] = 0.038866f;	val_dir[9103*3 + 1] = -0.971653f;	val_dir[9103*3 + 2] = -0.233197f;
+ 	val_dir[9104*3 + 0] = 0.059362f;	val_dir[9104*3 + 1] = -0.969584f;	val_dir[9104*3 + 2] = -0.237449f;
+ 	val_dir[9105*3 + 0] = 0.080582f;	val_dir[9105*3 + 1] = -0.966988f;	val_dir[9105*3 + 2] = -0.241747f;
+ 	val_dir[9106*3 + 0] = 0.102533f;	val_dir[9106*3 + 1] = -0.963811f;	val_dir[9106*3 + 2] = -0.246079f;
+ 	val_dir[9107*3 + 0] = 0.125218f;	val_dir[9107*3 + 1] = -0.960001f;	val_dir[9107*3 + 2] = -0.250435f;
+ 	val_dir[9108*3 + 0] = 0.148634f;	val_dir[9108*3 + 1] = -0.955502f;	val_dir[9108*3 + 2] = -0.254801f;
+ 	val_dir[9109*3 + 0] = 0.172774f;	val_dir[9109*3 + 1] = -0.950255f;	val_dir[9109*3 + 2] = -0.259161f;
+ 	val_dir[9110*3 + 0] = 0.197623f;	val_dir[9110*3 + 1] = -0.94420f;	val_dir[9110*3 + 2] = -0.263498f;
+ 	val_dir[9111*3 + 0] = 0.223161f;	val_dir[9111*3 + 1] = -0.937276f;	val_dir[9111*3 + 2] = -0.267793f;
+ 	val_dir[9112*3 + 0] = 0.249357f;	val_dir[9112*3 + 1] = -0.929421f;	val_dir[9112*3 + 2] = -0.272026f;
+ 	val_dir[9113*3 + 0] = 0.276172f;	val_dir[9113*3 + 1] = -0.920575f;	val_dir[9113*3 + 2] = -0.276172f;
+ 	val_dir[9114*3 + 0] = 0.303559f;	val_dir[9114*3 + 1] = -0.910678f;	val_dir[9114*3 + 2] = -0.280209f;
+ 	val_dir[9115*3 + 0] = 0.331460f;	val_dir[9115*3 + 1] = -0.899676f;	val_dir[9115*3 + 2] = -0.284108f;
+ 	val_dir[9116*3 + 0] = 0.359804f;	val_dir[9116*3 + 1] = -0.887517f;	val_dir[9116*3 + 2] = -0.287843f;
+ 	val_dir[9117*3 + 0] = 0.388514f;	val_dir[9117*3 + 1] = -0.874157f;	val_dir[9117*3 + 2] = -0.291386f;
+ 	val_dir[9118*3 + 0] = 0.41750f;	val_dir[9118*3 + 1] = -0.859559f;	val_dir[9118*3 + 2] = -0.294706f;
+ 	val_dir[9119*3 + 0] = 0.446662f;	val_dir[9119*3 + 1] = -0.843696f;	val_dir[9119*3 + 2] = -0.297775f;
+ 	val_dir[9120*3 + 0] = 0.475893f;	val_dir[9120*3 + 1] = -0.826551f;	val_dir[9120*3 + 2] = -0.300564f;
+ 	val_dir[9121*3 + 0] = 0.505076f;	val_dir[9121*3 + 1] = -0.808122f;	val_dir[9121*3 + 2] = -0.303046f;
+ 	val_dir[9122*3 + 0] = 0.534090f;	val_dir[9122*3 + 1] = -0.788419f;	val_dir[9122*3 + 2] = -0.305194f;
+ 	val_dir[9123*3 + 0] = 0.562809f;	val_dir[9123*3 + 1] = -0.767467f;	val_dir[9123*3 + 2] = -0.306987f;
+ 	val_dir[9124*3 + 0] = 0.591105f;	val_dir[9124*3 + 1] = -0.745307f;	val_dir[9124*3 + 2] = -0.308403f;
+ 	val_dir[9125*3 + 0] = 0.618853f;	val_dir[9125*3 + 1] = -0.721995f;	val_dir[9125*3 + 2] = -0.309426f;
+ 	val_dir[9126*3 + 0] = 0.645928f;	val_dir[9126*3 + 1] = -0.697602f;	val_dir[9126*3 + 2] = -0.310045f;
+ 	val_dir[9127*3 + 0] = 0.672214f;	val_dir[9127*3 + 1] = -0.672214f;	val_dir[9127*3 + 2] = -0.310253f;
+ 	val_dir[9128*3 + 0] = 0.697602f;	val_dir[9128*3 + 1] = -0.645928f;	val_dir[9128*3 + 2] = -0.310045f;
+ 	val_dir[9129*3 + 0] = 0.721995f;	val_dir[9129*3 + 1] = -0.618853f;	val_dir[9129*3 + 2] = -0.309426f;
+ 	val_dir[9130*3 + 0] = 0.745307f;	val_dir[9130*3 + 1] = -0.591105f;	val_dir[9130*3 + 2] = -0.308403f;
+ 	val_dir[9131*3 + 0] = 0.767467f;	val_dir[9131*3 + 1] = -0.562809f;	val_dir[9131*3 + 2] = -0.306987f;
+ 	val_dir[9132*3 + 0] = 0.788419f;	val_dir[9132*3 + 1] = -0.534090f;	val_dir[9132*3 + 2] = -0.305194f;
+ 	val_dir[9133*3 + 0] = 0.808122f;	val_dir[9133*3 + 1] = -0.505076f;	val_dir[9133*3 + 2] = -0.303046f;
+ 	val_dir[9134*3 + 0] = 0.826551f;	val_dir[9134*3 + 1] = -0.475893f;	val_dir[9134*3 + 2] = -0.300564f;
+ 	val_dir[9135*3 + 0] = 0.843696f;	val_dir[9135*3 + 1] = -0.446662f;	val_dir[9135*3 + 2] = -0.297775f;
+ 	val_dir[9136*3 + 0] = 0.859559f;	val_dir[9136*3 + 1] = -0.41750f;	val_dir[9136*3 + 2] = -0.294706f;
+ 	val_dir[9137*3 + 0] = 0.874157f;	val_dir[9137*3 + 1] = -0.388514f;	val_dir[9137*3 + 2] = -0.291386f;
+ 	val_dir[9138*3 + 0] = 0.887517f;	val_dir[9138*3 + 1] = -0.359804f;	val_dir[9138*3 + 2] = -0.287843f;
+ 	val_dir[9139*3 + 0] = 0.899676f;	val_dir[9139*3 + 1] = -0.331460f;	val_dir[9139*3 + 2] = -0.284108f;
+ 	val_dir[9140*3 + 0] = 0.910678f;	val_dir[9140*3 + 1] = -0.303559f;	val_dir[9140*3 + 2] = -0.280209f;
+ 	val_dir[9141*3 + 0] = 0.920575f;	val_dir[9141*3 + 1] = -0.276172f;	val_dir[9141*3 + 2] = -0.276172f;
+ 	val_dir[9142*3 + 0] = 0.929421f;	val_dir[9142*3 + 1] = -0.249357f;	val_dir[9142*3 + 2] = -0.272026f;
+ 	val_dir[9143*3 + 0] = 0.937276f;	val_dir[9143*3 + 1] = -0.223161f;	val_dir[9143*3 + 2] = -0.267793f;
+ 	val_dir[9144*3 + 0] = 0.94420f;	val_dir[9144*3 + 1] = -0.197623f;	val_dir[9144*3 + 2] = -0.263498f;
+ 	val_dir[9145*3 + 0] = 0.950255f;	val_dir[9145*3 + 1] = -0.172774f;	val_dir[9145*3 + 2] = -0.259161f;
+ 	val_dir[9146*3 + 0] = 0.955502f;	val_dir[9146*3 + 1] = -0.148634f;	val_dir[9146*3 + 2] = -0.254801f;
+ 	val_dir[9147*3 + 0] = 0.960001f;	val_dir[9147*3 + 1] = -0.125218f;	val_dir[9147*3 + 2] = -0.250435f;
+ 	val_dir[9148*3 + 0] = 0.963811f;	val_dir[9148*3 + 1] = -0.102533f;	val_dir[9148*3 + 2] = -0.246079f;
+ 	val_dir[9149*3 + 0] = 0.966988f;	val_dir[9149*3 + 1] = -0.080582f;	val_dir[9149*3 + 2] = -0.241747f;
+ 	val_dir[9150*3 + 0] = 0.969584f;	val_dir[9150*3 + 1] = -0.059362f;	val_dir[9150*3 + 2] = -0.237449f;
+ 	val_dir[9151*3 + 0] = 0.971653f;	val_dir[9151*3 + 1] = -0.038866f;	val_dir[9151*3 + 2] = -0.233197f;
+ 	val_dir[9152*3 + 0] = 0.973240f;	val_dir[9152*3 + 1] = -0.019083f;	val_dir[9152*3 + 2] = -0.228998f;
+ 	val_dir[9153*3 + 0] = 0.974391f;	val_dir[9153*3 + 1] = 0.0f;	val_dir[9153*3 + 2] = -0.224860f;
+ 	val_dir[9154*3 + 0] = 0.982493f;	val_dir[9154*3 + 1] = 0.018538f;	val_dir[9154*3 + 2] = -0.185376f;
+ 	val_dir[9155*3 + 0] = 0.988540f;	val_dir[9155*3 + 1] = 0.036613f;	val_dir[9155*3 + 2] = -0.146450f;
+ 	val_dir[9156*3 + 0] = 0.992644f;	val_dir[9156*3 + 1] = 0.054144f;	val_dir[9156*3 + 2] = -0.108288f;
+ 	val_dir[9157*3 + 0] = 0.994937f;	val_dir[9157*3 + 1] = 0.071067f;	val_dir[9157*3 + 2] = -0.071067f;
+ 	val_dir[9158*3 + 0] = 0.995567f;	val_dir[9158*3 + 1] = 0.087330f;	val_dir[9158*3 + 2] = -0.034932f;
+ 	val_dir[9159*3 + 0] = 0.994692f;	val_dir[9159*3 + 1] = 0.102899f;	val_dir[9159*3 + 2] = 0.0f;
+ 	val_dir[9160*3 + 0] = -0.104669f;	val_dir[9160*3 + 1] = -0.994354f;	val_dir[9160*3 + 2] = -0.017445f;
+ 	val_dir[9161*3 + 0] = -0.088806f;	val_dir[9161*3 + 1] = -0.994623f;	val_dir[9161*3 + 2] = -0.053283f;
+ 	val_dir[9162*3 + 0] = -0.072239f;	val_dir[9162*3 + 1] = -0.993291f;	val_dir[9162*3 + 2] = -0.090299f;
+ 	val_dir[9163*3 + 0] = -0.055011f;	val_dir[9163*3 + 1] = -0.990201f;	val_dir[9163*3 + 2] = -0.128359f;
+ 	val_dir[9164*3 + 0] = -0.037178f;	val_dir[9164*3 + 1] = -0.985205f;	val_dir[9164*3 + 2] = -0.167299f;
+ 	val_dir[9165*3 + 0] = -0.018811f;	val_dir[9165*3 + 1] = -0.978177f;	val_dir[9165*3 + 2] = -0.206922f;
+ 	val_dir[9166*3 + 0] = 0.0f;	val_dir[9166*3 + 1] = -0.969015f;	val_dir[9166*3 + 2] = -0.247004f;
+ 	val_dir[9167*3 + 0] = 0.019353f;	val_dir[9167*3 + 1] = -0.967641f;	val_dir[9167*3 + 2] = -0.251587f;
+ 	val_dir[9168*3 + 0] = 0.039421f;	val_dir[9168*3 + 1] = -0.965810f;	val_dir[9168*3 + 2] = -0.256235f;
+ 	val_dir[9169*3 + 0] = 0.060217f;	val_dir[9169*3 + 1] = -0.963475f;	val_dir[9169*3 + 2] = -0.260941f;
+ 	val_dir[9170*3 + 0] = 0.081752f;	val_dir[9170*3 + 1] = -0.960585f;	val_dir[9170*3 + 2] = -0.265694f;
+ 	val_dir[9171*3 + 0] = 0.104031f;	val_dir[9171*3 + 1] = -0.957088f;	val_dir[9171*3 + 2] = -0.270481f;
+ 	val_dir[9172*3 + 0] = 0.127057f;	val_dir[9172*3 + 1] = -0.952928f;	val_dir[9172*3 + 2] = -0.275290f;
+ 	val_dir[9173*3 + 0] = 0.150826f;	val_dir[9173*3 + 1] = -0.948047f;	val_dir[9173*3 + 2] = -0.280105f;
+ 	val_dir[9174*3 + 0] = 0.175327f;	val_dir[9174*3 + 1] = -0.942384f;	val_dir[9174*3 + 2] = -0.284907f;
+ 	val_dir[9175*3 + 0] = 0.200545f;	val_dir[9175*3 + 1] = -0.935879f;	val_dir[9175*3 + 2] = -0.289677f;
+ 	val_dir[9176*3 + 0] = 0.226455f;	val_dir[9176*3 + 1] = -0.928467f;	val_dir[9176*3 + 2] = -0.294392f;
+ 	val_dir[9177*3 + 0] = 0.253024f;	val_dir[9177*3 + 1] = -0.920087f;	val_dir[9177*3 + 2] = -0.299028f;
+ 	val_dir[9178*3 + 0] = 0.280209f;	val_dir[9178*3 + 1] = -0.910678f;	val_dir[9178*3 + 2] = -0.303559f;
+ 	val_dir[9179*3 + 0] = 0.307957f;	val_dir[9179*3 + 1] = -0.900181f;	val_dir[9179*3 + 2] = -0.307957f;
+ 	val_dir[9180*3 + 0] = 0.336204f;	val_dir[9180*3 + 1] = -0.888540f;	val_dir[9180*3 + 2] = -0.312190f;
+ 	val_dir[9181*3 + 0] = 0.364878f;	val_dir[9181*3 + 1] = -0.875708f;	val_dir[9181*3 + 2] = -0.316228f;
+ 	val_dir[9182*3 + 0] = 0.393893f;	val_dir[9182*3 + 1] = -0.861640f;	val_dir[9182*3 + 2] = -0.320038f;
+ 	val_dir[9183*3 + 0] = 0.423153f;	val_dir[9183*3 + 1] = -0.846305f;	val_dir[9183*3 + 2] = -0.323587f;
+ 	val_dir[9184*3 + 0] = 0.452553f;	val_dir[9184*3 + 1] = -0.829680f;	val_dir[9184*3 + 2] = -0.326844f;
+ 	val_dir[9185*3 + 0] = 0.481979f;	val_dir[9185*3 + 1] = -0.811754f;	val_dir[9185*3 + 2] = -0.329775f;
+ 	val_dir[9186*3 + 0] = 0.511310f;	val_dir[9186*3 + 1] = -0.792530f;	val_dir[9186*3 + 2] = -0.332352f;
+ 	val_dir[9187*3 + 0] = 0.540419f;	val_dir[9187*3 + 1] = -0.772027f;	val_dir[9187*3 + 2] = -0.334545f;
+ 	val_dir[9188*3 + 0] = 0.569177f;	val_dir[9188*3 + 1] = -0.750279f;	val_dir[9188*3 + 2] = -0.336332f;
+ 	val_dir[9189*3 + 0] = 0.597453f;	val_dir[9189*3 + 1] = -0.727334f;	val_dir[9189*3 + 2] = -0.337691f;
+ 	val_dir[9190*3 + 0] = 0.625119f;	val_dir[9190*3 + 1] = -0.703259f;	val_dir[9190*3 + 2] = -0.338606f;
+ 	val_dir[9191*3 + 0] = 0.652051f;	val_dir[9191*3 + 1] = -0.678133f;	val_dir[9191*3 + 2] = -0.339066f;
+ 	val_dir[9192*3 + 0] = 0.678133f;	val_dir[9192*3 + 1] = -0.652051f;	val_dir[9192*3 + 2] = -0.339066f;
+ 	val_dir[9193*3 + 0] = 0.703259f;	val_dir[9193*3 + 1] = -0.625119f;	val_dir[9193*3 + 2] = -0.338606f;
+ 	val_dir[9194*3 + 0] = 0.727334f;	val_dir[9194*3 + 1] = -0.597453f;	val_dir[9194*3 + 2] = -0.337691f;
+ 	val_dir[9195*3 + 0] = 0.750279f;	val_dir[9195*3 + 1] = -0.569177f;	val_dir[9195*3 + 2] = -0.336332f;
+ 	val_dir[9196*3 + 0] = 0.772027f;	val_dir[9196*3 + 1] = -0.540419f;	val_dir[9196*3 + 2] = -0.334545f;
+ 	val_dir[9197*3 + 0] = 0.792530f;	val_dir[9197*3 + 1] = -0.511310f;	val_dir[9197*3 + 2] = -0.332352f;
+ 	val_dir[9198*3 + 0] = 0.811754f;	val_dir[9198*3 + 1] = -0.481979f;	val_dir[9198*3 + 2] = -0.329775f;
+ 	val_dir[9199*3 + 0] = 0.829680f;	val_dir[9199*3 + 1] = -0.452553f;	val_dir[9199*3 + 2] = -0.326844f;
+ 	val_dir[9200*3 + 0] = 0.846305f;	val_dir[9200*3 + 1] = -0.423153f;	val_dir[9200*3 + 2] = -0.323587f;
+ 	val_dir[9201*3 + 0] = 0.861640f;	val_dir[9201*3 + 1] = -0.393893f;	val_dir[9201*3 + 2] = -0.320038f;
+ 	val_dir[9202*3 + 0] = 0.875708f;	val_dir[9202*3 + 1] = -0.364878f;	val_dir[9202*3 + 2] = -0.316228f;
+ 	val_dir[9203*3 + 0] = 0.888540f;	val_dir[9203*3 + 1] = -0.336204f;	val_dir[9203*3 + 2] = -0.312190f;
+ 	val_dir[9204*3 + 0] = 0.900181f;	val_dir[9204*3 + 1] = -0.307957f;	val_dir[9204*3 + 2] = -0.307957f;
+ 	val_dir[9205*3 + 0] = 0.910678f;	val_dir[9205*3 + 1] = -0.280209f;	val_dir[9205*3 + 2] = -0.303559f;
+ 	val_dir[9206*3 + 0] = 0.920087f;	val_dir[9206*3 + 1] = -0.253024f;	val_dir[9206*3 + 2] = -0.299028f;
+ 	val_dir[9207*3 + 0] = 0.928467f;	val_dir[9207*3 + 1] = -0.226455f;	val_dir[9207*3 + 2] = -0.294392f;
+ 	val_dir[9208*3 + 0] = 0.935879f;	val_dir[9208*3 + 1] = -0.200545f;	val_dir[9208*3 + 2] = -0.289677f;
+ 	val_dir[9209*3 + 0] = 0.942384f;	val_dir[9209*3 + 1] = -0.175327f;	val_dir[9209*3 + 2] = -0.284907f;
+ 	val_dir[9210*3 + 0] = 0.948047f;	val_dir[9210*3 + 1] = -0.150826f;	val_dir[9210*3 + 2] = -0.280105f;
+ 	val_dir[9211*3 + 0] = 0.952928f;	val_dir[9211*3 + 1] = -0.127057f;	val_dir[9211*3 + 2] = -0.275290f;
+ 	val_dir[9212*3 + 0] = 0.957088f;	val_dir[9212*3 + 1] = -0.104031f;	val_dir[9212*3 + 2] = -0.270481f;
+ 	val_dir[9213*3 + 0] = 0.960585f;	val_dir[9213*3 + 1] = -0.081752f;	val_dir[9213*3 + 2] = -0.265694f;
+ 	val_dir[9214*3 + 0] = 0.963475f;	val_dir[9214*3 + 1] = -0.060217f;	val_dir[9214*3 + 2] = -0.260941f;
+ 	val_dir[9215*3 + 0] = 0.965810f;	val_dir[9215*3 + 1] = -0.039421f;	val_dir[9215*3 + 2] = -0.256235f;
+ 	val_dir[9216*3 + 0] = 0.967641f;	val_dir[9216*3 + 1] = -0.019353f;	val_dir[9216*3 + 2] = -0.251587f;
+ 	val_dir[9217*3 + 0] = 0.969015f;	val_dir[9217*3 + 1] = 0.0f;	val_dir[9217*3 + 2] = -0.247004f;
+ 	val_dir[9218*3 + 0] = 0.978177f;	val_dir[9218*3 + 1] = 0.018811f;	val_dir[9218*3 + 2] = -0.206922f;
+ 	val_dir[9219*3 + 0] = 0.985205f;	val_dir[9219*3 + 1] = 0.037178f;	val_dir[9219*3 + 2] = -0.167299f;
+ 	val_dir[9220*3 + 0] = 0.990201f;	val_dir[9220*3 + 1] = 0.055011f;	val_dir[9220*3 + 2] = -0.128359f;
+ 	val_dir[9221*3 + 0] = 0.993291f;	val_dir[9221*3 + 1] = 0.072239f;	val_dir[9221*3 + 2] = -0.090299f;
+ 	val_dir[9222*3 + 0] = 0.994623f;	val_dir[9222*3 + 1] = 0.088806f;	val_dir[9222*3 + 2] = -0.053283f;
+ 	val_dir[9223*3 + 0] = 0.994354f;	val_dir[9223*3 + 1] = 0.104669f;	val_dir[9223*3 + 2] = -0.017445f;
+ 	val_dir[9224*3 + 0] = -0.121891f;	val_dir[9224*3 + 1] = -0.992543f;	val_dir[9224*3 + 2] = 0.0f;
+ 	val_dir[9225*3 + 0] = -0.106466f;	val_dir[9225*3 + 1] = -0.993683f;	val_dir[9225*3 + 2] = -0.035489f;
+ 	val_dir[9226*3 + 0] = -0.090299f;	val_dir[9226*3 + 1] = -0.993291f;	val_dir[9226*3 + 2] = -0.072239f;
+ 	val_dir[9227*3 + 0] = -0.073422f;	val_dir[9227*3 + 1] = -0.991201f;	val_dir[9227*3 + 2] = -0.110133f;
+ 	val_dir[9228*3 + 0] = -0.055882f;	val_dir[9228*3 + 1] = -0.987254f;	val_dir[9228*3 + 2] = -0.149019f;
+ 	val_dir[9229*3 + 0] = -0.037743f;	val_dir[9229*3 + 1] = -0.981307f;	val_dir[9229*3 + 2] = -0.188713f;
+ 	val_dir[9230*3 + 0] = -0.019083f;	val_dir[9230*3 + 1] = -0.973240f;	val_dir[9230*3 + 2] = -0.228998f;
+ 	val_dir[9231*3 + 0] = 0.0f;	val_dir[9231*3 + 1] = -0.962964f;	val_dir[9231*3 + 2] = -0.269630f;
+ 	val_dir[9232*3 + 0] = 0.019619f;	val_dir[9232*3 + 1] = -0.961339f;	val_dir[9232*3 + 2] = -0.274668f;
+ 	val_dir[9233*3 + 0] = 0.039968f;	val_dir[9233*3 + 1] = -0.959233f;	val_dir[9233*3 + 2] = -0.279776f;
+ 	val_dir[9234*3 + 0] = 0.061059f;	val_dir[9234*3 + 1] = -0.956597f;	val_dir[9234*3 + 2] = -0.284944f;
+ 	val_dir[9235*3 + 0] = 0.082903f;	val_dir[9235*3 + 1] = -0.953381f;	val_dir[9235*3 + 2] = -0.290159f;
+ 	val_dir[9236*3 + 0] = 0.105503f;	val_dir[9236*3 + 1] = -0.949528f;	val_dir[9236*3 + 2] = -0.295409f;
+ 	val_dir[9237*3 + 0] = 0.128861f;	val_dir[9237*3 + 1] = -0.944981f;	val_dir[9237*3 + 2] = -0.300676f;
+ 	val_dir[9238*3 + 0] = 0.152971f;	val_dir[9238*3 + 1] = -0.939680f;	val_dir[9238*3 + 2] = -0.305942f;
+ 	val_dir[9239*3 + 0] = 0.177822f;	val_dir[9239*3 + 1] = -0.933564f;	val_dir[9239*3 + 2] = -0.311188f;
+ 	val_dir[9240*3 + 0] = 0.203393f;	val_dir[9240*3 + 1] = -0.926568f;	val_dir[9240*3 + 2] = -0.316389f;
+ 	val_dir[9241*3 + 0] = 0.229658f;	val_dir[9241*3 + 1] = -0.918630f;	val_dir[9241*3 + 2] = -0.321521f;
+ 	val_dir[9242*3 + 0] = 0.256578f;	val_dir[9242*3 + 1] = -0.909687f;	val_dir[9242*3 + 2] = -0.326554f;
+ 	val_dir[9243*3 + 0] = 0.284108f;	val_dir[9243*3 + 1] = -0.899676f;	val_dir[9243*3 + 2] = -0.331460f;
+ 	val_dir[9244*3 + 0] = 0.312190f;	val_dir[9244*3 + 1] = -0.888540f;	val_dir[9244*3 + 2] = -0.336204f;
+ 	val_dir[9245*3 + 0] = 0.340755f;	val_dir[9245*3 + 1] = -0.876226f;	val_dir[9245*3 + 2] = -0.340755f;
+ 	val_dir[9246*3 + 0] = 0.369723f;	val_dir[9246*3 + 1] = -0.862687f;	val_dir[9246*3 + 2] = -0.345075f;
+ 	val_dir[9247*3 + 0] = 0.399004f;	val_dir[9247*3 + 1] = -0.847883f;	val_dir[9247*3 + 2] = -0.349128f;
+ 	val_dir[9248*3 + 0] = 0.428496f;	val_dir[9248*3 + 1] = -0.831786f;	val_dir[9248*3 + 2] = -0.352879f;
+ 	val_dir[9249*3 + 0] = 0.458088f;	val_dir[9249*3 + 1] = -0.814379f;	val_dir[9249*3 + 2] = -0.356291f;
+ 	val_dir[9250*3 + 0] = 0.487661f;	val_dir[9250*3 + 1] = -0.795657f;	val_dir[9250*3 + 2] = -0.359329f;
+ 	val_dir[9251*3 + 0] = 0.517088f;	val_dir[9251*3 + 1] = -0.775632f;	val_dir[9251*3 + 2] = -0.361961f;
+ 	val_dir[9252*3 + 0] = 0.546238f;	val_dir[9252*3 + 1] = -0.754329f;	val_dir[9252*3 + 2] = -0.364159f;
+ 	val_dir[9253*3 + 0] = 0.574979f;	val_dir[9253*3 + 1] = -0.731792f;	val_dir[9253*3 + 2] = -0.365896f;
+ 	val_dir[9254*3 + 0] = 0.603178f;	val_dir[9254*3 + 1] = -0.708079f;	val_dir[9254*3 + 2] = -0.367152f;
+ 	val_dir[9255*3 + 0] = 0.630706f;	val_dir[9255*3 + 1] = -0.683265f;	val_dir[9255*3 + 2] = -0.367912f;
+ 	val_dir[9256*3 + 0] = 0.657440f;	val_dir[9256*3 + 1] = -0.657440f;	val_dir[9256*3 + 2] = -0.368166f;
+ 	val_dir[9257*3 + 0] = 0.683265f;	val_dir[9257*3 + 1] = -0.630706f;	val_dir[9257*3 + 2] = -0.367912f;
+ 	val_dir[9258*3 + 0] = 0.708079f;	val_dir[9258*3 + 1] = -0.603178f;	val_dir[9258*3 + 2] = -0.367152f;
+ 	val_dir[9259*3 + 0] = 0.731792f;	val_dir[9259*3 + 1] = -0.574979f;	val_dir[9259*3 + 2] = -0.365896f;
+ 	val_dir[9260*3 + 0] = 0.754329f;	val_dir[9260*3 + 1] = -0.546238f;	val_dir[9260*3 + 2] = -0.364159f;
+ 	val_dir[9261*3 + 0] = 0.775632f;	val_dir[9261*3 + 1] = -0.517088f;	val_dir[9261*3 + 2] = -0.361961f;
+ 	val_dir[9262*3 + 0] = 0.795657f;	val_dir[9262*3 + 1] = -0.487661f;	val_dir[9262*3 + 2] = -0.359329f;
+ 	val_dir[9263*3 + 0] = 0.814379f;	val_dir[9263*3 + 1] = -0.458088f;	val_dir[9263*3 + 2] = -0.356291f;
+ 	val_dir[9264*3 + 0] = 0.831786f;	val_dir[9264*3 + 1] = -0.428496f;	val_dir[9264*3 + 2] = -0.352879f;
+ 	val_dir[9265*3 + 0] = 0.847883f;	val_dir[9265*3 + 1] = -0.399004f;	val_dir[9265*3 + 2] = -0.349128f;
+ 	val_dir[9266*3 + 0] = 0.862687f;	val_dir[9266*3 + 1] = -0.369723f;	val_dir[9266*3 + 2] = -0.345075f;
+ 	val_dir[9267*3 + 0] = 0.876226f;	val_dir[9267*3 + 1] = -0.340755f;	val_dir[9267*3 + 2] = -0.340755f;
+ 	val_dir[9268*3 + 0] = 0.888540f;	val_dir[9268*3 + 1] = -0.312190f;	val_dir[9268*3 + 2] = -0.336204f;
+ 	val_dir[9269*3 + 0] = 0.899676f;	val_dir[9269*3 + 1] = -0.284108f;	val_dir[9269*3 + 2] = -0.331460f;
+ 	val_dir[9270*3 + 0] = 0.909687f;	val_dir[9270*3 + 1] = -0.256578f;	val_dir[9270*3 + 2] = -0.326554f;
+ 	val_dir[9271*3 + 0] = 0.918630f;	val_dir[9271*3 + 1] = -0.229658f;	val_dir[9271*3 + 2] = -0.321521f;
+ 	val_dir[9272*3 + 0] = 0.926568f;	val_dir[9272*3 + 1] = -0.203393f;	val_dir[9272*3 + 2] = -0.316389f;
+ 	val_dir[9273*3 + 0] = 0.933564f;	val_dir[9273*3 + 1] = -0.177822f;	val_dir[9273*3 + 2] = -0.311188f;
+ 	val_dir[9274*3 + 0] = 0.939680f;	val_dir[9274*3 + 1] = -0.152971f;	val_dir[9274*3 + 2] = -0.305942f;
+ 	val_dir[9275*3 + 0] = 0.944981f;	val_dir[9275*3 + 1] = -0.128861f;	val_dir[9275*3 + 2] = -0.300676f;
+ 	val_dir[9276*3 + 0] = 0.949528f;	val_dir[9276*3 + 1] = -0.105503f;	val_dir[9276*3 + 2] = -0.295409f;
+ 	val_dir[9277*3 + 0] = 0.953381f;	val_dir[9277*3 + 1] = -0.082903f;	val_dir[9277*3 + 2] = -0.290159f;
+ 	val_dir[9278*3 + 0] = 0.956597f;	val_dir[9278*3 + 1] = -0.061059f;	val_dir[9278*3 + 2] = -0.284944f;
+ 	val_dir[9279*3 + 0] = 0.959233f;	val_dir[9279*3 + 1] = -0.039968f;	val_dir[9279*3 + 2] = -0.279776f;
+ 	val_dir[9280*3 + 0] = 0.961339f;	val_dir[9280*3 + 1] = -0.019619f;	val_dir[9280*3 + 2] = -0.274668f;
+ 	val_dir[9281*3 + 0] = 0.962964f;	val_dir[9281*3 + 1] = 0.0f;	val_dir[9281*3 + 2] = -0.269630f;
+ 	val_dir[9282*3 + 0] = 0.973240f;	val_dir[9282*3 + 1] = 0.019083f;	val_dir[9282*3 + 2] = -0.228998f;
+ 	val_dir[9283*3 + 0] = 0.981307f;	val_dir[9283*3 + 1] = 0.037743f;	val_dir[9283*3 + 2] = -0.188713f;
+ 	val_dir[9284*3 + 0] = 0.987254f;	val_dir[9284*3 + 1] = 0.055882f;	val_dir[9284*3 + 2] = -0.149019f;
+ 	val_dir[9285*3 + 0] = 0.991201f;	val_dir[9285*3 + 1] = 0.073422f;	val_dir[9285*3 + 2] = -0.110133f;
+ 	val_dir[9286*3 + 0] = 0.993291f;	val_dir[9286*3 + 1] = 0.090299f;	val_dir[9286*3 + 2] = -0.072239f;
+ 	val_dir[9287*3 + 0] = 0.993683f;	val_dir[9287*3 + 1] = 0.106466f;	val_dir[9287*3 + 2] = -0.035489f;
+ 	val_dir[9288*3 + 0] = 0.992543f;	val_dir[9288*3 + 1] = 0.121891f;	val_dir[9288*3 + 2] = 0.0f;
+ 	val_dir[9289*3 + 0] = -0.124015f;	val_dir[9289*3 + 1] = -0.992122f;	val_dir[9289*3 + 2] = -0.017716f;
+ 	val_dir[9290*3 + 0] = -0.108288f;	val_dir[9290*3 + 1] = -0.992644f;	val_dir[9290*3 + 2] = -0.054144f;
+ 	val_dir[9291*3 + 0] = -0.091809f;	val_dir[9291*3 + 1] = -0.991535f;	val_dir[9291*3 + 2] = -0.091809f;
+ 	val_dir[9292*3 + 0] = -0.074613f;	val_dir[9292*3 + 1] = -0.988627f;	val_dir[9292*3 + 2] = -0.130573f;
+ 	val_dir[9293*3 + 0] = -0.056756f;	val_dir[9293*3 + 1] = -0.983762f;	val_dir[9293*3 + 2] = -0.170267f;
+ 	val_dir[9294*3 + 0] = -0.038306f;	val_dir[9294*3 + 1] = -0.976804f;	val_dir[9294*3 + 2] = -0.210683f;
+ 	val_dir[9295*3 + 0] = -0.019353f;	val_dir[9295*3 + 1] = -0.967641f;	val_dir[9295*3 + 2] = -0.251587f;
+ 	val_dir[9296*3 + 0] = 0.0f;	val_dir[9296*3 + 1] = -0.95620f;	val_dir[9296*3 + 2] = -0.292714f;
+ 	val_dir[9297*3 + 0] = 0.019881f;	val_dir[9297*3 + 1] = -0.954291f;	val_dir[9297*3 + 2] = -0.298216f;
+ 	val_dir[9298*3 + 0] = 0.040505f;	val_dir[9298*3 + 1] = -0.951877f;	val_dir[9298*3 + 2] = -0.303791f;
+ 	val_dir[9299*3 + 0] = 0.061885f;	val_dir[9299*3 + 1] = -0.948908f;	val_dir[9299*3 + 2] = -0.309426f;
+ 	val_dir[9300*3 + 0] = 0.084029f;	val_dir[9300*3 + 1] = -0.945328f;	val_dir[9300*3 + 2] = -0.315109f;
+ 	val_dir[9301*3 + 0] = 0.106941f;	val_dir[9301*3 + 1] = -0.941082f;	val_dir[9301*3 + 2] = -0.320824f;
+ 	val_dir[9302*3 + 0] = 0.130620f;	val_dir[9302*3 + 1] = -0.936111f;	val_dir[9302*3 + 2] = -0.326550f;
+ 	val_dir[9303*3 + 0] = 0.155059f;	val_dir[9303*3 + 1] = -0.930352f;	val_dir[9303*3 + 2] = -0.332269f;
+ 	val_dir[9304*3 + 0] = 0.180242f;	val_dir[9304*3 + 1] = -0.923742f;	val_dir[9304*3 + 2] = -0.337954f;
+ 	val_dir[9305*3 + 0] = 0.206149f;	val_dir[9305*3 + 1] = -0.916217f;	val_dir[9305*3 + 2] = -0.343582f;
+ 	val_dir[9306*3 + 0] = 0.232747f;	val_dir[9306*3 + 1] = -0.907713f;	val_dir[9306*3 + 2] = -0.349121f;
+ 	val_dir[9307*3 + 0] = 0.259996f;	val_dir[9307*3 + 1] = -0.898167f;	val_dir[9307*3 + 2] = -0.354540f;
+ 	val_dir[9308*3 + 0] = 0.287843f;	val_dir[9308*3 + 1] = -0.887517f;	val_dir[9308*3 + 2] = -0.359804f;
+ 	val_dir[9309*3 + 0] = 0.316228f;	val_dir[9309*3 + 1] = -0.875708f;	val_dir[9309*3 + 2] = -0.364878f;
+ 	val_dir[9310*3 + 0] = 0.345075f;	val_dir[9310*3 + 1] = -0.862687f;	val_dir[9310*3 + 2] = -0.369723f;
+ 	val_dir[9311*3 + 0] = 0.374299f;	val_dir[9311*3 + 1] = -0.848411f;	val_dir[9311*3 + 2] = -0.374299f;
+ 	val_dir[9312*3 + 0] = 0.403804f;	val_dir[9312*3 + 1] = -0.832845f;	val_dir[9312*3 + 2] = -0.378566f;
+ 	val_dir[9313*3 + 0] = 0.433482f;	val_dir[9313*3 + 1] = -0.815966f;	val_dir[9313*3 + 2] = -0.382484f;
+ 	val_dir[9314*3 + 0] = 0.463217f;	val_dir[9314*3 + 1] = -0.797762f;	val_dir[9314*3 + 2] = -0.386014f;
+ 	val_dir[9315*3 + 0] = 0.492883f;	val_dir[9315*3 + 1] = -0.778237f;	val_dir[9315*3 + 2] = -0.389118f;
+ 	val_dir[9316*3 + 0] = 0.522352f;	val_dir[9316*3 + 1] = -0.757410f;	val_dir[9316*3 + 2] = -0.391764f;
+ 	val_dir[9317*3 + 0] = 0.551487f;	val_dir[9317*3 + 1] = -0.735316f;	val_dir[9317*3 + 2] = -0.393919f;
+ 	val_dir[9318*3 + 0] = 0.580154f;	val_dir[9318*3 + 1] = -0.712007f;	val_dir[9318*3 + 2] = -0.395559f;
+ 	val_dir[9319*3 + 0] = 0.608219f;	val_dir[9319*3 + 1] = -0.687552f;	val_dir[9319*3 + 2] = -0.396664f;
+ 	val_dir[9320*3 + 0] = 0.635553f;	val_dir[9320*3 + 1] = -0.662034f;	val_dir[9320*3 + 2] = -0.397220f;
+ 	val_dir[9321*3 + 0] = 0.662034f;	val_dir[9321*3 + 1] = -0.635553f;	val_dir[9321*3 + 2] = -0.397220f;
+ 	val_dir[9322*3 + 0] = 0.687552f;	val_dir[9322*3 + 1] = -0.608219f;	val_dir[9322*3 + 2] = -0.396664f;
+ 	val_dir[9323*3 + 0] = 0.712007f;	val_dir[9323*3 + 1] = -0.580154f;	val_dir[9323*3 + 2] = -0.395559f;
+ 	val_dir[9324*3 + 0] = 0.735316f;	val_dir[9324*3 + 1] = -0.551487f;	val_dir[9324*3 + 2] = -0.393919f;
+ 	val_dir[9325*3 + 0] = 0.757410f;	val_dir[9325*3 + 1] = -0.522352f;	val_dir[9325*3 + 2] = -0.391764f;
+ 	val_dir[9326*3 + 0] = 0.778237f;	val_dir[9326*3 + 1] = -0.492883f;	val_dir[9326*3 + 2] = -0.389118f;
+ 	val_dir[9327*3 + 0] = 0.797762f;	val_dir[9327*3 + 1] = -0.463217f;	val_dir[9327*3 + 2] = -0.386014f;
+ 	val_dir[9328*3 + 0] = 0.815966f;	val_dir[9328*3 + 1] = -0.433482f;	val_dir[9328*3 + 2] = -0.382484f;
+ 	val_dir[9329*3 + 0] = 0.832845f;	val_dir[9329*3 + 1] = -0.403804f;	val_dir[9329*3 + 2] = -0.378566f;
+ 	val_dir[9330*3 + 0] = 0.848411f;	val_dir[9330*3 + 1] = -0.374299f;	val_dir[9330*3 + 2] = -0.374299f;
+ 	val_dir[9331*3 + 0] = 0.862687f;	val_dir[9331*3 + 1] = -0.345075f;	val_dir[9331*3 + 2] = -0.369723f;
+ 	val_dir[9332*3 + 0] = 0.875708f;	val_dir[9332*3 + 1] = -0.316228f;	val_dir[9332*3 + 2] = -0.364878f;
+ 	val_dir[9333*3 + 0] = 0.887517f;	val_dir[9333*3 + 1] = -0.287843f;	val_dir[9333*3 + 2] = -0.359804f;
+ 	val_dir[9334*3 + 0] = 0.898167f;	val_dir[9334*3 + 1] = -0.259996f;	val_dir[9334*3 + 2] = -0.354540f;
+ 	val_dir[9335*3 + 0] = 0.907713f;	val_dir[9335*3 + 1] = -0.232747f;	val_dir[9335*3 + 2] = -0.349121f;
+ 	val_dir[9336*3 + 0] = 0.916217f;	val_dir[9336*3 + 1] = -0.206149f;	val_dir[9336*3 + 2] = -0.343582f;
+ 	val_dir[9337*3 + 0] = 0.923742f;	val_dir[9337*3 + 1] = -0.180242f;	val_dir[9337*3 + 2] = -0.337954f;
+ 	val_dir[9338*3 + 0] = 0.930352f;	val_dir[9338*3 + 1] = -0.155059f;	val_dir[9338*3 + 2] = -0.332269f;
+ 	val_dir[9339*3 + 0] = 0.936111f;	val_dir[9339*3 + 1] = -0.130620f;	val_dir[9339*3 + 2] = -0.326550f;
+ 	val_dir[9340*3 + 0] = 0.941082f;	val_dir[9340*3 + 1] = -0.106941f;	val_dir[9340*3 + 2] = -0.320824f;
+ 	val_dir[9341*3 + 0] = 0.945328f;	val_dir[9341*3 + 1] = -0.084029f;	val_dir[9341*3 + 2] = -0.315109f;
+ 	val_dir[9342*3 + 0] = 0.948908f;	val_dir[9342*3 + 1] = -0.061885f;	val_dir[9342*3 + 2] = -0.309426f;
+ 	val_dir[9343*3 + 0] = 0.951877f;	val_dir[9343*3 + 1] = -0.040505f;	val_dir[9343*3 + 2] = -0.303791f;
+ 	val_dir[9344*3 + 0] = 0.954291f;	val_dir[9344*3 + 1] = -0.019881f;	val_dir[9344*3 + 2] = -0.298216f;
+ 	val_dir[9345*3 + 0] = 0.95620f;	val_dir[9345*3 + 1] = 0.0f;	val_dir[9345*3 + 2] = -0.292714f;
+ 	val_dir[9346*3 + 0] = 0.967641f;	val_dir[9346*3 + 1] = 0.019353f;	val_dir[9346*3 + 2] = -0.251587f;
+ 	val_dir[9347*3 + 0] = 0.976804f;	val_dir[9347*3 + 1] = 0.038306f;	val_dir[9347*3 + 2] = -0.210683f;
+ 	val_dir[9348*3 + 0] = 0.983762f;	val_dir[9348*3 + 1] = 0.056756f;	val_dir[9348*3 + 2] = -0.170267f;
+ 	val_dir[9349*3 + 0] = 0.988627f;	val_dir[9349*3 + 1] = 0.074613f;	val_dir[9349*3 + 2] = -0.130573f;
+ 	val_dir[9350*3 + 0] = 0.991535f;	val_dir[9350*3 + 1] = 0.091809f;	val_dir[9350*3 + 2] = -0.091809f;
+ 	val_dir[9351*3 + 0] = 0.992644f;	val_dir[9351*3 + 1] = 0.108288f;	val_dir[9351*3 + 2] = -0.054144f;
+ 	val_dir[9352*3 + 0] = 0.992122f;	val_dir[9352*3 + 1] = 0.124015f;	val_dir[9352*3 + 2] = -0.017716f;
+ 	val_dir[9353*3 + 0] = -0.141421f;	val_dir[9353*3 + 1] = -0.989949f;	val_dir[9353*3 + 2] = 0.0f;
+ 	val_dir[9354*3 + 0] = -0.126172f;	val_dir[9354*3 + 1] = -0.991353f;	val_dir[9354*3 + 2] = -0.036049f;
+ 	val_dir[9355*3 + 0] = -0.110133f;	val_dir[9355*3 + 1] = -0.991201f;	val_dir[9355*3 + 2] = -0.073422f;
+ 	val_dir[9356*3 + 0] = -0.093332f;	val_dir[9356*3 + 1] = -0.989316f;	val_dir[9356*3 + 2] = -0.111998f;
+ 	val_dir[9357*3 + 0] = -0.075810f;	val_dir[9357*3 + 1] = -0.985527f;	val_dir[9357*3 + 2] = -0.151620f;
+ 	val_dir[9358*3 + 0] = -0.057628f;	val_dir[9358*3 + 1] = -0.979683f;	val_dir[9358*3 + 2] = -0.192095f;
+ 	val_dir[9359*3 + 0] = -0.038866f;	val_dir[9359*3 + 1] = -0.971653f;	val_dir[9359*3 + 2] = -0.233197f;
+ 	val_dir[9360*3 + 0] = -0.019619f;	val_dir[9360*3 + 1] = -0.961339f;	val_dir[9360*3 + 2] = -0.274668f;
+ 	val_dir[9361*3 + 0] = 0.0f;	val_dir[9361*3 + 1] = -0.948683f;	val_dir[9361*3 + 2] = -0.316228f;
+ 	val_dir[9362*3 + 0] = 0.020137f;	val_dir[9362*3 + 1] = -0.946458f;	val_dir[9362*3 + 2] = -0.322198f;
+ 	val_dir[9363*3 + 0] = 0.041030f;	val_dir[9363*3 + 1] = -0.943701f;	val_dir[9363*3 + 2] = -0.328244f;
+ 	val_dir[9364*3 + 0] = 0.062691f;	val_dir[9364*3 + 1] = -0.940361f;	val_dir[9364*3 + 2] = -0.334351f;
+ 	val_dir[9365*3 + 0] = 0.085126f;	val_dir[9365*3 + 1] = -0.936382f;	val_dir[9365*3 + 2] = -0.340503f;
+ 	val_dir[9366*3 + 0] = 0.108338f;	val_dir[9366*3 + 1] = -0.931705f;	val_dir[9366*3 + 2] = -0.346681f;
+ 	val_dir[9367*3 + 0] = 0.132324f;	val_dir[9367*3 + 1] = -0.926270f;	val_dir[9367*3 + 2] = -0.352865f;
+ 	val_dir[9368*3 + 0] = 0.157075f;	val_dir[9368*3 + 1] = -0.920014f;	val_dir[9368*3 + 2] = -0.359030f;
+ 	val_dir[9369*3 + 0] = 0.182574f;	val_dir[9369*3 + 1] = -0.912871f;	val_dir[9369*3 + 2] = -0.365148f;
+ 	val_dir[9370*3 + 0] = 0.208795f;	val_dir[9370*3 + 1] = -0.904777f;	val_dir[9370*3 + 2] = -0.371191f;
+ 	val_dir[9371*3 + 0] = 0.235702f;	val_dir[9371*3 + 1] = -0.895669f;	val_dir[9371*3 + 2] = -0.377124f;
+ 	val_dir[9372*3 + 0] = 0.263251f;	val_dir[9372*3 + 1] = -0.885482f;	val_dir[9372*3 + 2] = -0.382911f;
+ 	val_dir[9373*3 + 0] = 0.291386f;	val_dir[9373*3 + 1] = -0.874157f;	val_dir[9373*3 + 2] = -0.388514f;
+ 	val_dir[9374*3 + 0] = 0.320038f;	val_dir[9374*3 + 1] = -0.861640f;	val_dir[9374*3 + 2] = -0.393893f;
+ 	val_dir[9375*3 + 0] = 0.349128f;	val_dir[9375*3 + 1] = -0.847883f;	val_dir[9375*3 + 2] = -0.399004f;
+ 	val_dir[9376*3 + 0] = 0.378566f;	val_dir[9376*3 + 1] = -0.832845f;	val_dir[9376*3 + 2] = -0.403804f;
+ 	val_dir[9377*3 + 0] = 0.408248f;	val_dir[9377*3 + 1] = -0.816497f;	val_dir[9377*3 + 2] = -0.408248f;
+ 	val_dir[9378*3 + 0] = 0.438063f;	val_dir[9378*3 + 1] = -0.798820f;	val_dir[9378*3 + 2] = -0.412294f;
+ 	val_dir[9379*3 + 0] = 0.467888f;	val_dir[9379*3 + 1] = -0.779813f;	val_dir[9379*3 + 2] = -0.41590f;
+ 	val_dir[9380*3 + 0] = 0.497594f;	val_dir[9380*3 + 1] = -0.759485f;	val_dir[9380*3 + 2] = -0.419026f;
+ 	val_dir[9381*3 + 0] = 0.527046f;	val_dir[9381*3 + 1] = -0.737865f;	val_dir[9381*3 + 2] = -0.421637f;
+ 	val_dir[9382*3 + 0] = 0.556108f;	val_dir[9382*3 + 1] = -0.714997f;	val_dir[9382*3 + 2] = -0.423702f;
+ 	val_dir[9383*3 + 0] = 0.584643f;	val_dir[9383*3 + 1] = -0.690942f;	val_dir[9383*3 + 2] = -0.425195f;
+ 	val_dir[9384*3 + 0] = 0.612517f;	val_dir[9384*3 + 1] = -0.665780f;	val_dir[9384*3 + 2] = -0.426099f;
+ 	val_dir[9385*3 + 0] = 0.639602f;	val_dir[9385*3 + 1] = -0.639602f;	val_dir[9385*3 + 2] = -0.426401f;
+ 	val_dir[9386*3 + 0] = 0.665780f;	val_dir[9386*3 + 1] = -0.612517f;	val_dir[9386*3 + 2] = -0.426099f;
+ 	val_dir[9387*3 + 0] = 0.690942f;	val_dir[9387*3 + 1] = -0.584643f;	val_dir[9387*3 + 2] = -0.425195f;
+ 	val_dir[9388*3 + 0] = 0.714997f;	val_dir[9388*3 + 1] = -0.556108f;	val_dir[9388*3 + 2] = -0.423702f;
+ 	val_dir[9389*3 + 0] = 0.737865f;	val_dir[9389*3 + 1] = -0.527046f;	val_dir[9389*3 + 2] = -0.421637f;
+ 	val_dir[9390*3 + 0] = 0.759485f;	val_dir[9390*3 + 1] = -0.497594f;	val_dir[9390*3 + 2] = -0.419026f;
+ 	val_dir[9391*3 + 0] = 0.779813f;	val_dir[9391*3 + 1] = -0.467888f;	val_dir[9391*3 + 2] = -0.41590f;
+ 	val_dir[9392*3 + 0] = 0.798820f;	val_dir[9392*3 + 1] = -0.438063f;	val_dir[9392*3 + 2] = -0.412294f;
+ 	val_dir[9393*3 + 0] = 0.816497f;	val_dir[9393*3 + 1] = -0.408248f;	val_dir[9393*3 + 2] = -0.408248f;
+ 	val_dir[9394*3 + 0] = 0.832845f;	val_dir[9394*3 + 1] = -0.378566f;	val_dir[9394*3 + 2] = -0.403804f;
+ 	val_dir[9395*3 + 0] = 0.847883f;	val_dir[9395*3 + 1] = -0.349128f;	val_dir[9395*3 + 2] = -0.399004f;
+ 	val_dir[9396*3 + 0] = 0.861640f;	val_dir[9396*3 + 1] = -0.320038f;	val_dir[9396*3 + 2] = -0.393893f;
+ 	val_dir[9397*3 + 0] = 0.874157f;	val_dir[9397*3 + 1] = -0.291386f;	val_dir[9397*3 + 2] = -0.388514f;
+ 	val_dir[9398*3 + 0] = 0.885482f;	val_dir[9398*3 + 1] = -0.263251f;	val_dir[9398*3 + 2] = -0.382911f;
+ 	val_dir[9399*3 + 0] = 0.895669f;	val_dir[9399*3 + 1] = -0.235702f;	val_dir[9399*3 + 2] = -0.377124f;
+ 	val_dir[9400*3 + 0] = 0.904777f;	val_dir[9400*3 + 1] = -0.208795f;	val_dir[9400*3 + 2] = -0.371191f;
+ 	val_dir[9401*3 + 0] = 0.912871f;	val_dir[9401*3 + 1] = -0.182574f;	val_dir[9401*3 + 2] = -0.365148f;
+ 	val_dir[9402*3 + 0] = 0.920014f;	val_dir[9402*3 + 1] = -0.157075f;	val_dir[9402*3 + 2] = -0.359030f;
+ 	val_dir[9403*3 + 0] = 0.926270f;	val_dir[9403*3 + 1] = -0.132324f;	val_dir[9403*3 + 2] = -0.352865f;
+ 	val_dir[9404*3 + 0] = 0.931705f;	val_dir[9404*3 + 1] = -0.108338f;	val_dir[9404*3 + 2] = -0.346681f;
+ 	val_dir[9405*3 + 0] = 0.936382f;	val_dir[9405*3 + 1] = -0.085126f;	val_dir[9405*3 + 2] = -0.340503f;
+ 	val_dir[9406*3 + 0] = 0.940361f;	val_dir[9406*3 + 1] = -0.062691f;	val_dir[9406*3 + 2] = -0.334351f;
+ 	val_dir[9407*3 + 0] = 0.943701f;	val_dir[9407*3 + 1] = -0.041030f;	val_dir[9407*3 + 2] = -0.328244f;
+ 	val_dir[9408*3 + 0] = 0.946458f;	val_dir[9408*3 + 1] = -0.020137f;	val_dir[9408*3 + 2] = -0.322198f;
+ 	val_dir[9409*3 + 0] = 0.948683f;	val_dir[9409*3 + 1] = 0.0f;	val_dir[9409*3 + 2] = -0.316228f;
+ 	val_dir[9410*3 + 0] = 0.961339f;	val_dir[9410*3 + 1] = 0.019619f;	val_dir[9410*3 + 2] = -0.274668f;
+ 	val_dir[9411*3 + 0] = 0.971653f;	val_dir[9411*3 + 1] = 0.038866f;	val_dir[9411*3 + 2] = -0.233197f;
+ 	val_dir[9412*3 + 0] = 0.979683f;	val_dir[9412*3 + 1] = 0.057628f;	val_dir[9412*3 + 2] = -0.192095f;
+ 	val_dir[9413*3 + 0] = 0.985527f;	val_dir[9413*3 + 1] = 0.075810f;	val_dir[9413*3 + 2] = -0.151620f;
+ 	val_dir[9414*3 + 0] = 0.989316f;	val_dir[9414*3 + 1] = 0.093332f;	val_dir[9414*3 + 2] = -0.111998f;
+ 	val_dir[9415*3 + 0] = 0.991201f;	val_dir[9415*3 + 1] = 0.110133f;	val_dir[9415*3 + 2] = -0.073422f;
+ 	val_dir[9416*3 + 0] = 0.991353f;	val_dir[9416*3 + 1] = 0.126172f;	val_dir[9416*3 + 2] = -0.036049f;
+ 	val_dir[9417*3 + 0] = 0.989949f;	val_dir[9417*3 + 1] = 0.141421f;	val_dir[9417*3 + 2] = 0.0f;
+ 	val_dir[9418*3 + 0] = -0.143917f;	val_dir[9418*3 + 1] = -0.989426f;	val_dir[9418*3 + 2] = -0.017990f;
+ 	val_dir[9419*3 + 0] = -0.128359f;	val_dir[9419*3 + 1] = -0.990201f;	val_dir[9419*3 + 2] = -0.055011f;
+ 	val_dir[9420*3 + 0] = -0.111998f;	val_dir[9420*3 + 1] = -0.989316f;	val_dir[9420*3 + 2] = -0.093332f;
+ 	val_dir[9421*3 + 0] = -0.094865f;	val_dir[9421*3 + 1] = -0.986591f;	val_dir[9421*3 + 2] = -0.132810f;
+ 	val_dir[9422*3 + 0] = -0.077009f;	val_dir[9422*3 + 1] = -0.981859f;	val_dir[9422*3 + 2] = -0.173269f;
+ 	val_dir[9423*3 + 0] = -0.058498f;	val_dir[9423*3 + 1] = -0.974972f;	val_dir[9423*3 + 2] = -0.214494f;
+ 	val_dir[9424*3 + 0] = -0.039421f;	val_dir[9424*3 + 1] = -0.965810f;	val_dir[9424*3 + 2] = -0.256235f;
+ 	val_dir[9425*3 + 0] = -0.019881f;	val_dir[9425*3 + 1] = -0.954291f;	val_dir[9425*3 + 2] = -0.298216f;
+ 	val_dir[9426*3 + 0] = 0.0f;	val_dir[9426*3 + 1] = -0.940376f;	val_dir[9426*3 + 2] = -0.340136f;
+ 	val_dir[9427*3 + 0] = 0.020387f;	val_dir[9427*3 + 1] = -0.93780f;	val_dir[9427*3 + 2] = -0.346578f;
+ 	val_dir[9428*3 + 0] = 0.041541f;	val_dir[9428*3 + 1] = -0.934665f;	val_dir[9428*3 + 2] = -0.353096f;
+ 	val_dir[9429*3 + 0] = 0.063472f;	val_dir[9429*3 + 1] = -0.930917f;	val_dir[9429*3 + 2] = -0.359673f;
+ 	val_dir[9430*3 + 0] = 0.086186f;	val_dir[9430*3 + 1] = -0.92650f;	val_dir[9430*3 + 2] = -0.366291f;
+ 	val_dir[9431*3 + 0] = 0.109685f;	val_dir[9431*3 + 1] = -0.921354f;	val_dir[9431*3 + 2] = -0.372929f;
+ 	val_dir[9432*3 + 0] = 0.133963f;	val_dir[9432*3 + 1] = -0.915416f;	val_dir[9432*3 + 2] = -0.379563f;
+ 	val_dir[9433*3 + 0] = 0.159009f;	val_dir[9433*3 + 1] = -0.908622f;	val_dir[9433*3 + 2] = -0.386164f;
+ 	val_dir[9434*3 + 0] = 0.184801f;	val_dir[9434*3 + 1] = -0.900907f;	val_dir[9434*3 + 2] = -0.392703f;
+ 	val_dir[9435*3 + 0] = 0.211312f;	val_dir[9435*3 + 1] = -0.892206f;	val_dir[9435*3 + 2] = -0.399145f;
+ 	val_dir[9436*3 + 0] = 0.238501f;	val_dir[9436*3 + 1] = -0.882454f;	val_dir[9436*3 + 2] = -0.405452f;
+ 	val_dir[9437*3 + 0] = 0.266320f;	val_dir[9437*3 + 1] = -0.871592f;	val_dir[9437*3 + 2] = -0.411585f;
+ 	val_dir[9438*3 + 0] = 0.294706f;	val_dir[9438*3 + 1] = -0.859559f;	val_dir[9438*3 + 2] = -0.41750f;
+ 	val_dir[9439*3 + 0] = 0.323587f;	val_dir[9439*3 + 1] = -0.846305f;	val_dir[9439*3 + 2] = -0.423153f;
+ 	val_dir[9440*3 + 0] = 0.352879f;	val_dir[9440*3 + 1] = -0.831786f;	val_dir[9440*3 + 2] = -0.428496f;
+ 	val_dir[9441*3 + 0] = 0.382484f;	val_dir[9441*3 + 1] = -0.815966f;	val_dir[9441*3 + 2] = -0.433482f;
+ 	val_dir[9442*3 + 0] = 0.412294f;	val_dir[9442*3 + 1] = -0.798820f;	val_dir[9442*3 + 2] = -0.438063f;
+ 	val_dir[9443*3 + 0] = 0.442193f;	val_dir[9443*3 + 1] = -0.780340f;	val_dir[9443*3 + 2] = -0.442193f;
+ 	val_dir[9444*3 + 0] = 0.472053f;	val_dir[9444*3 + 1] = -0.760529f;	val_dir[9444*3 + 2] = -0.445827f;
+ 	val_dir[9445*3 + 0] = 0.501740f;	val_dir[9445*3 + 1] = -0.739407f;	val_dir[9445*3 + 2] = -0.448926f;
+ 	val_dir[9446*3 + 0] = 0.531119f;	val_dir[9446*3 + 1] = -0.717011f;	val_dir[9446*3 + 2] = -0.451451f;
+ 	val_dir[9447*3 + 0] = 0.560050f;	val_dir[9447*3 + 1] = -0.693395f;	val_dir[9447*3 + 2] = -0.453374f;
+ 	val_dir[9448*3 + 0] = 0.588395f;	val_dir[9448*3 + 1] = -0.668631f;	val_dir[9448*3 + 2] = -0.454669f;
+ 	val_dir[9449*3 + 0] = 0.616022f;	val_dir[9449*3 + 1] = -0.642806f;	val_dir[9449*3 + 2] = -0.455321f;
+ 	val_dir[9450*3 + 0] = 0.642806f;	val_dir[9450*3 + 1] = -0.616022f;	val_dir[9450*3 + 2] = -0.455321f;
+ 	val_dir[9451*3 + 0] = 0.668631f;	val_dir[9451*3 + 1] = -0.588395f;	val_dir[9451*3 + 2] = -0.454669f;
+ 	val_dir[9452*3 + 0] = 0.693395f;	val_dir[9452*3 + 1] = -0.560050f;	val_dir[9452*3 + 2] = -0.453374f;
+ 	val_dir[9453*3 + 0] = 0.717011f;	val_dir[9453*3 + 1] = -0.531119f;	val_dir[9453*3 + 2] = -0.451451f;
+ 	val_dir[9454*3 + 0] = 0.739407f;	val_dir[9454*3 + 1] = -0.501740f;	val_dir[9454*3 + 2] = -0.448926f;
+ 	val_dir[9455*3 + 0] = 0.760529f;	val_dir[9455*3 + 1] = -0.472053f;	val_dir[9455*3 + 2] = -0.445827f;
+ 	val_dir[9456*3 + 0] = 0.780340f;	val_dir[9456*3 + 1] = -0.442193f;	val_dir[9456*3 + 2] = -0.442193f;
+ 	val_dir[9457*3 + 0] = 0.798820f;	val_dir[9457*3 + 1] = -0.412294f;	val_dir[9457*3 + 2] = -0.438063f;
+ 	val_dir[9458*3 + 0] = 0.815966f;	val_dir[9458*3 + 1] = -0.382484f;	val_dir[9458*3 + 2] = -0.433482f;
+ 	val_dir[9459*3 + 0] = 0.831786f;	val_dir[9459*3 + 1] = -0.352879f;	val_dir[9459*3 + 2] = -0.428496f;
+ 	val_dir[9460*3 + 0] = 0.846305f;	val_dir[9460*3 + 1] = -0.323587f;	val_dir[9460*3 + 2] = -0.423153f;
+ 	val_dir[9461*3 + 0] = 0.859559f;	val_dir[9461*3 + 1] = -0.294706f;	val_dir[9461*3 + 2] = -0.41750f;
+ 	val_dir[9462*3 + 0] = 0.871592f;	val_dir[9462*3 + 1] = -0.266320f;	val_dir[9462*3 + 2] = -0.411585f;
+ 	val_dir[9463*3 + 0] = 0.882454f;	val_dir[9463*3 + 1] = -0.238501f;	val_dir[9463*3 + 2] = -0.405452f;
+ 	val_dir[9464*3 + 0] = 0.892206f;	val_dir[9464*3 + 1] = -0.211312f;	val_dir[9464*3 + 2] = -0.399145f;
+ 	val_dir[9465*3 + 0] = 0.900907f;	val_dir[9465*3 + 1] = -0.184801f;	val_dir[9465*3 + 2] = -0.392703f;
+ 	val_dir[9466*3 + 0] = 0.908622f;	val_dir[9466*3 + 1] = -0.159009f;	val_dir[9466*3 + 2] = -0.386164f;
+ 	val_dir[9467*3 + 0] = 0.915416f;	val_dir[9467*3 + 1] = -0.133963f;	val_dir[9467*3 + 2] = -0.379563f;
+ 	val_dir[9468*3 + 0] = 0.921354f;	val_dir[9468*3 + 1] = -0.109685f;	val_dir[9468*3 + 2] = -0.372929f;
+ 	val_dir[9469*3 + 0] = 0.92650f;	val_dir[9469*3 + 1] = -0.086186f;	val_dir[9469*3 + 2] = -0.366291f;
+ 	val_dir[9470*3 + 0] = 0.930917f;	val_dir[9470*3 + 1] = -0.063472f;	val_dir[9470*3 + 2] = -0.359673f;
+ 	val_dir[9471*3 + 0] = 0.934665f;	val_dir[9471*3 + 1] = -0.041541f;	val_dir[9471*3 + 2] = -0.353096f;
+ 	val_dir[9472*3 + 0] = 0.93780f;	val_dir[9472*3 + 1] = -0.020387f;	val_dir[9472*3 + 2] = -0.346578f;
+ 	val_dir[9473*3 + 0] = 0.940376f;	val_dir[9473*3 + 1] = 0.0f;	val_dir[9473*3 + 2] = -0.340136f;
+ 	val_dir[9474*3 + 0] = 0.954291f;	val_dir[9474*3 + 1] = 0.019881f;	val_dir[9474*3 + 2] = -0.298216f;
+ 	val_dir[9475*3 + 0] = 0.965810f;	val_dir[9475*3 + 1] = 0.039421f;	val_dir[9475*3 + 2] = -0.256235f;
+ 	val_dir[9476*3 + 0] = 0.974972f;	val_dir[9476*3 + 1] = 0.058498f;	val_dir[9476*3 + 2] = -0.214494f;
+ 	val_dir[9477*3 + 0] = 0.981859f;	val_dir[9477*3 + 1] = 0.077009f;	val_dir[9477*3 + 2] = -0.173269f;
+ 	val_dir[9478*3 + 0] = 0.986591f;	val_dir[9478*3 + 1] = 0.094865f;	val_dir[9478*3 + 2] = -0.132810f;
+ 	val_dir[9479*3 + 0] = 0.989316f;	val_dir[9479*3 + 1] = 0.111998f;	val_dir[9479*3 + 2] = -0.093332f;
+ 	val_dir[9480*3 + 0] = 0.990201f;	val_dir[9480*3 + 1] = 0.128359f;	val_dir[9480*3 + 2] = -0.055011f;
+ 	val_dir[9481*3 + 0] = 0.989426f;	val_dir[9481*3 + 1] = 0.143917f;	val_dir[9481*3 + 2] = -0.017990f;
+ 	val_dir[9482*3 + 0] = -0.161489f;	val_dir[9482*3 + 1] = -0.986875f;	val_dir[9482*3 + 2] = 0.0f;
+ 	val_dir[9483*3 + 0] = -0.146450f;	val_dir[9483*3 + 1] = -0.988540f;	val_dir[9483*3 + 2] = -0.036613f;
+ 	val_dir[9484*3 + 0] = -0.130573f;	val_dir[9484*3 + 1] = -0.988627f;	val_dir[9484*3 + 2] = -0.074613f;
+ 	val_dir[9485*3 + 0] = -0.113878f;	val_dir[9485*3 + 1] = -0.986947f;	val_dir[9485*3 + 2] = -0.113878f;
+ 	val_dir[9486*3 + 0] = -0.096404f;	val_dir[9486*3 + 1] = -0.983318f;	val_dir[9486*3 + 2] = -0.154246f;
+ 	val_dir[9487*3 + 0] = -0.078206f;	val_dir[9487*3 + 1] = -0.977577f;	val_dir[9487*3 + 2] = -0.195515f;
+ 	val_dir[9488*3 + 0] = -0.059362f;	val_dir[9488*3 + 1] = -0.969584f;	val_dir[9488*3 + 2] = -0.237449f;
+ 	val_dir[9489*3 + 0] = -0.039968f;	val_dir[9489*3 + 1] = -0.959233f;	val_dir[9489*3 + 2] = -0.279776f;
+ 	val_dir[9490*3 + 0] = -0.020137f;	val_dir[9490*3 + 1] = -0.946458f;	val_dir[9490*3 + 2] = -0.322198f;
+ 	val_dir[9491*3 + 0] = 0.0f;	val_dir[9491*3 + 1] = -0.931243f;	val_dir[9491*3 + 2] = -0.364399f;
+ 	val_dir[9492*3 + 0] = 0.020628f;	val_dir[9492*3 + 1] = -0.928279f;	val_dir[9492*3 + 2] = -0.371312f;
+ 	val_dir[9493*3 + 0] = 0.042033f;	val_dir[9493*3 + 1] = -0.924729f;	val_dir[9493*3 + 2] = -0.378298f;
+ 	val_dir[9494*3 + 0] = 0.064223f;	val_dir[9494*3 + 1] = -0.920537f;	val_dir[9494*3 + 2] = -0.385341f;
+ 	val_dir[9495*3 + 0] = 0.087204f;	val_dir[9495*3 + 1] = -0.915644f;	val_dir[9495*3 + 2] = -0.392419f;
+ 	val_dir[9496*3 + 0] = 0.110974f;	val_dir[9496*3 + 1] = -0.909988f;	val_dir[9496*3 + 2] = -0.399507f;
+ 	val_dir[9497*3 + 0] = 0.135526f;	val_dir[9497*3 + 1] = -0.903508f;	val_dir[9497*3 + 2] = -0.406579f;
+ 	val_dir[9498*3 + 0] = 0.160845f;	val_dir[9498*3 + 1] = -0.896137f;	val_dir[9498*3 + 2] = -0.413602f;
+ 	val_dir[9499*3 + 0] = 0.186908f;	val_dir[9499*3 + 1] = -0.887812f;	val_dir[9499*3 + 2] = -0.420542f;
+ 	val_dir[9500*3 + 0] = 0.213681f;	val_dir[9500*3 + 1] = -0.878466f;	val_dir[9500*3 + 2] = -0.427362f;
+ 	val_dir[9501*3 + 0] = 0.241121f;	val_dir[9501*3 + 1] = -0.868037f;	val_dir[9501*3 + 2] = -0.434019f;
+ 	val_dir[9502*3 + 0] = 0.269175f;	val_dir[9502*3 + 1] = -0.856465f;	val_dir[9502*3 + 2] = -0.440468f;
+ 	val_dir[9503*3 + 0] = 0.297775f;	val_dir[9503*3 + 1] = -0.843696f;	val_dir[9503*3 + 2] = -0.446662f;
+ 	val_dir[9504*3 + 0] = 0.326844f;	val_dir[9504*3 + 1] = -0.829680f;	val_dir[9504*3 + 2] = -0.452553f;
+ 	val_dir[9505*3 + 0] = 0.356291f;	val_dir[9505*3 + 1] = -0.814379f;	val_dir[9505*3 + 2] = -0.458088f;
+ 	val_dir[9506*3 + 0] = 0.386014f;	val_dir[9506*3 + 1] = -0.797762f;	val_dir[9506*3 + 2] = -0.463217f;
+ 	val_dir[9507*3 + 0] = 0.41590f;	val_dir[9507*3 + 1] = -0.779813f;	val_dir[9507*3 + 2] = -0.467888f;
+ 	val_dir[9508*3 + 0] = 0.445827f;	val_dir[9508*3 + 1] = -0.760529f;	val_dir[9508*3 + 2] = -0.472053f;
+ 	val_dir[9509*3 + 0] = 0.475665f;	val_dir[9509*3 + 1] = -0.739923f;	val_dir[9509*3 + 2] = -0.475665f;
+ 	val_dir[9510*3 + 0] = 0.505276f;	val_dir[9510*3 + 1] = -0.718024f;	val_dir[9510*3 + 2] = -0.478683f;
+ 	val_dir[9511*3 + 0] = 0.534522f;	val_dir[9511*3 + 1] = -0.694879f;	val_dir[9511*3 + 2] = -0.481070f;
+ 	val_dir[9512*3 + 0] = 0.563264f;	val_dir[9512*3 + 1] = -0.670552f;	val_dir[9512*3 + 2] = -0.482798f;
+ 	val_dir[9513*3 + 0] = 0.591364f;	val_dir[9513*3 + 1] = -0.645124f;	val_dir[9513*3 + 2] = -0.483843f;
+ 	val_dir[9514*3 + 0] = 0.618691f;	val_dir[9514*3 + 1] = -0.618691f;	val_dir[9514*3 + 2] = -0.484193f;
+ 	val_dir[9515*3 + 0] = 0.645124f;	val_dir[9515*3 + 1] = -0.591364f;	val_dir[9515*3 + 2] = -0.483843f;
+ 	val_dir[9516*3 + 0] = 0.670552f;	val_dir[9516*3 + 1] = -0.563264f;	val_dir[9516*3 + 2] = -0.482798f;
+ 	val_dir[9517*3 + 0] = 0.694879f;	val_dir[9517*3 + 1] = -0.534522f;	val_dir[9517*3 + 2] = -0.481070f;
+ 	val_dir[9518*3 + 0] = 0.718024f;	val_dir[9518*3 + 1] = -0.505276f;	val_dir[9518*3 + 2] = -0.478683f;
+ 	val_dir[9519*3 + 0] = 0.739923f;	val_dir[9519*3 + 1] = -0.475665f;	val_dir[9519*3 + 2] = -0.475665f;
+ 	val_dir[9520*3 + 0] = 0.760529f;	val_dir[9520*3 + 1] = -0.445827f;	val_dir[9520*3 + 2] = -0.472053f;
+ 	val_dir[9521*3 + 0] = 0.779813f;	val_dir[9521*3 + 1] = -0.41590f;	val_dir[9521*3 + 2] = -0.467888f;
+ 	val_dir[9522*3 + 0] = 0.797762f;	val_dir[9522*3 + 1] = -0.386014f;	val_dir[9522*3 + 2] = -0.463217f;
+ 	val_dir[9523*3 + 0] = 0.814379f;	val_dir[9523*3 + 1] = -0.356291f;	val_dir[9523*3 + 2] = -0.458088f;
+ 	val_dir[9524*3 + 0] = 0.829680f;	val_dir[9524*3 + 1] = -0.326844f;	val_dir[9524*3 + 2] = -0.452553f;
+ 	val_dir[9525*3 + 0] = 0.843696f;	val_dir[9525*3 + 1] = -0.297775f;	val_dir[9525*3 + 2] = -0.446662f;
+ 	val_dir[9526*3 + 0] = 0.856465f;	val_dir[9526*3 + 1] = -0.269175f;	val_dir[9526*3 + 2] = -0.440468f;
+ 	val_dir[9527*3 + 0] = 0.868037f;	val_dir[9527*3 + 1] = -0.241121f;	val_dir[9527*3 + 2] = -0.434019f;
+ 	val_dir[9528*3 + 0] = 0.878466f;	val_dir[9528*3 + 1] = -0.213681f;	val_dir[9528*3 + 2] = -0.427362f;
+ 	val_dir[9529*3 + 0] = 0.887812f;	val_dir[9529*3 + 1] = -0.186908f;	val_dir[9529*3 + 2] = -0.420542f;
+ 	val_dir[9530*3 + 0] = 0.896137f;	val_dir[9530*3 + 1] = -0.160845f;	val_dir[9530*3 + 2] = -0.413602f;
+ 	val_dir[9531*3 + 0] = 0.903508f;	val_dir[9531*3 + 1] = -0.135526f;	val_dir[9531*3 + 2] = -0.406579f;
+ 	val_dir[9532*3 + 0] = 0.909988f;	val_dir[9532*3 + 1] = -0.110974f;	val_dir[9532*3 + 2] = -0.399507f;
+ 	val_dir[9533*3 + 0] = 0.915644f;	val_dir[9533*3 + 1] = -0.087204f;	val_dir[9533*3 + 2] = -0.392419f;
+ 	val_dir[9534*3 + 0] = 0.920537f;	val_dir[9534*3 + 1] = -0.064223f;	val_dir[9534*3 + 2] = -0.385341f;
+ 	val_dir[9535*3 + 0] = 0.924729f;	val_dir[9535*3 + 1] = -0.042033f;	val_dir[9535*3 + 2] = -0.378298f;
+ 	val_dir[9536*3 + 0] = 0.928279f;	val_dir[9536*3 + 1] = -0.020628f;	val_dir[9536*3 + 2] = -0.371312f;
+ 	val_dir[9537*3 + 0] = 0.931243f;	val_dir[9537*3 + 1] = 0.0f;	val_dir[9537*3 + 2] = -0.364399f;
+ 	val_dir[9538*3 + 0] = 0.946458f;	val_dir[9538*3 + 1] = 0.020137f;	val_dir[9538*3 + 2] = -0.322198f;
+ 	val_dir[9539*3 + 0] = 0.959233f;	val_dir[9539*3 + 1] = 0.039968f;	val_dir[9539*3 + 2] = -0.279776f;
+ 	val_dir[9540*3 + 0] = 0.969584f;	val_dir[9540*3 + 1] = 0.059362f;	val_dir[9540*3 + 2] = -0.237449f;
+ 	val_dir[9541*3 + 0] = 0.977577f;	val_dir[9541*3 + 1] = 0.078206f;	val_dir[9541*3 + 2] = -0.195515f;
+ 	val_dir[9542*3 + 0] = 0.983318f;	val_dir[9542*3 + 1] = 0.096404f;	val_dir[9542*3 + 2] = -0.154246f;
+ 	val_dir[9543*3 + 0] = 0.986947f;	val_dir[9543*3 + 1] = 0.113878f;	val_dir[9543*3 + 2] = -0.113878f;
+ 	val_dir[9544*3 + 0] = 0.988627f;	val_dir[9544*3 + 1] = 0.130573f;	val_dir[9544*3 + 2] = -0.074613f;
+ 	val_dir[9545*3 + 0] = 0.988540f;	val_dir[9545*3 + 1] = 0.146450f;	val_dir[9545*3 + 2] = -0.036613f;
+ 	val_dir[9546*3 + 0] = 0.986875f;	val_dir[9546*3 + 1] = 0.161489f;	val_dir[9546*3 + 2] = 0.0f;
+ 	val_dir[9547*3 + 0] = -0.164372f;	val_dir[9547*3 + 1] = -0.986229f;	val_dir[9547*3 + 2] = -0.018264f;
+ 	val_dir[9548*3 + 0] = -0.149019f;	val_dir[9548*3 + 1] = -0.987254f;	val_dir[9548*3 + 2] = -0.055882f;
+ 	val_dir[9549*3 + 0] = -0.132810f;	val_dir[9549*3 + 1] = -0.986591f;	val_dir[9549*3 + 2] = -0.094865f;
+ 	val_dir[9550*3 + 0] = -0.115771f;	val_dir[9550*3 + 1] = -0.984050f;	val_dir[9550*3 + 2] = -0.135066f;
+ 	val_dir[9551*3 + 0] = -0.097945f;	val_dir[9551*3 + 1] = -0.979451f;	val_dir[9551*3 + 2] = -0.176301f;
+ 	val_dir[9552*3 + 0] = -0.079399f;	val_dir[9552*3 + 1] = -0.972636f;	val_dir[9552*3 + 2] = -0.218347f;
+ 	val_dir[9553*3 + 0] = -0.060217f;	val_dir[9553*3 + 1] = -0.963475f;	val_dir[9553*3 + 2] = -0.260941f;
+ 	val_dir[9554*3 + 0] = -0.040505f;	val_dir[9554*3 + 1] = -0.951877f;	val_dir[9554*3 + 2] = -0.303791f;
+ 	val_dir[9555*3 + 0] = -0.020387f;	val_dir[9555*3 + 1] = -0.93780f;	val_dir[9555*3 + 2] = -0.346578f;
+ 	val_dir[9556*3 + 0] = 0.0f;	val_dir[9556*3 + 1] = -0.921250f;	val_dir[9556*3 + 2] = -0.388972f;
+ 	val_dir[9557*3 + 0] = 0.020861f;	val_dir[9557*3 + 1] = -0.917863f;	val_dir[9557*3 + 2] = -0.396350f;
+ 	val_dir[9558*3 + 0] = 0.042505f;	val_dir[9558*3 + 1] = -0.913860f;	val_dir[9558*3 + 2] = -0.403799f;
+ 	val_dir[9559*3 + 0] = 0.064942f;	val_dir[9559*3 + 1] = -0.909185f;	val_dir[9559*3 + 2] = -0.411298f;
+ 	val_dir[9560*3 + 0] = 0.088173f;	val_dir[9560*3 + 1] = -0.903777f;	val_dir[9560*3 + 2] = -0.418823f;
+ 	val_dir[9561*3 + 0] = 0.112197f;	val_dir[9561*3 + 1] = -0.897574f;	val_dir[9561*3 + 2] = -0.426348f;
+ 	val_dir[9562*3 + 0] = 0.137002f;	val_dir[9562*3 + 1] = -0.890513f;	val_dir[9562*3 + 2] = -0.433840f;
+ 	val_dir[9563*3 + 0] = 0.162571f;	val_dir[9563*3 + 1] = -0.882528f;	val_dir[9563*3 + 2] = -0.441264f;
+ 	val_dir[9564*3 + 0] = 0.188877f;	val_dir[9564*3 + 1] = -0.873555f;	val_dir[9564*3 + 2] = -0.448583f;
+ 	val_dir[9565*3 + 0] = 0.215883f;	val_dir[9565*3 + 1] = -0.863530f;	val_dir[9565*3 + 2] = -0.455752f;
+ 	val_dir[9566*3 + 0] = 0.243541f;	val_dir[9566*3 + 1] = -0.852392f;	val_dir[9566*3 + 2] = -0.462727f;
+ 	val_dir[9567*3 + 0] = 0.271791f;	val_dir[9567*3 + 1] = -0.840083f;	val_dir[9567*3 + 2] = -0.469458f;
+ 	val_dir[9568*3 + 0] = 0.300564f;	val_dir[9568*3 + 1] = -0.826551f;	val_dir[9568*3 + 2] = -0.475893f;
+ 	val_dir[9569*3 + 0] = 0.329775f;	val_dir[9569*3 + 1] = -0.811754f;	val_dir[9569*3 + 2] = -0.481979f;
+ 	val_dir[9570*3 + 0] = 0.359329f;	val_dir[9570*3 + 1] = -0.795657f;	val_dir[9570*3 + 2] = -0.487661f;
+ 	val_dir[9571*3 + 0] = 0.389118f;	val_dir[9571*3 + 1] = -0.778237f;	val_dir[9571*3 + 2] = -0.492883f;
+ 	val_dir[9572*3 + 0] = 0.419026f;	val_dir[9572*3 + 1] = -0.759485f;	val_dir[9572*3 + 2] = -0.497594f;
+ 	val_dir[9573*3 + 0] = 0.448926f;	val_dir[9573*3 + 1] = -0.739407f;	val_dir[9573*3 + 2] = -0.501740f;
+ 	val_dir[9574*3 + 0] = 0.478683f;	val_dir[9574*3 + 1] = -0.718024f;	val_dir[9574*3 + 2] = -0.505276f;
+ 	val_dir[9575*3 + 0] = 0.508159f;	val_dir[9575*3 + 1] = -0.695376f;	val_dir[9575*3 + 2] = -0.508159f;
+ 	val_dir[9576*3 + 0] = 0.537215f;	val_dir[9576*3 + 1] = -0.671519f;	val_dir[9576*3 + 2] = -0.510355f;
+ 	val_dir[9577*3 + 0] = 0.565711f;	val_dir[9577*3 + 1] = -0.646527f;	val_dir[9577*3 + 2] = -0.511834f;
+ 	val_dir[9578*3 + 0] = 0.593512f;	val_dir[9578*3 + 1] = -0.620490f;	val_dir[9578*3 + 2] = -0.512578f;
+ 	val_dir[9579*3 + 0] = 0.620490f;	val_dir[9579*3 + 1] = -0.593512f;	val_dir[9579*3 + 2] = -0.512578f;
+ 	val_dir[9580*3 + 0] = 0.646527f;	val_dir[9580*3 + 1] = -0.565711f;	val_dir[9580*3 + 2] = -0.511834f;
+ 	val_dir[9581*3 + 0] = 0.671519f;	val_dir[9581*3 + 1] = -0.537215f;	val_dir[9581*3 + 2] = -0.510355f;
+ 	val_dir[9582*3 + 0] = 0.695376f;	val_dir[9582*3 + 1] = -0.508159f;	val_dir[9582*3 + 2] = -0.508159f;
+ 	val_dir[9583*3 + 0] = 0.718024f;	val_dir[9583*3 + 1] = -0.478683f;	val_dir[9583*3 + 2] = -0.505276f;
+ 	val_dir[9584*3 + 0] = 0.739407f;	val_dir[9584*3 + 1] = -0.448926f;	val_dir[9584*3 + 2] = -0.501740f;
+ 	val_dir[9585*3 + 0] = 0.759485f;	val_dir[9585*3 + 1] = -0.419026f;	val_dir[9585*3 + 2] = -0.497594f;
+ 	val_dir[9586*3 + 0] = 0.778237f;	val_dir[9586*3 + 1] = -0.389118f;	val_dir[9586*3 + 2] = -0.492883f;
+ 	val_dir[9587*3 + 0] = 0.795657f;	val_dir[9587*3 + 1] = -0.359329f;	val_dir[9587*3 + 2] = -0.487661f;
+ 	val_dir[9588*3 + 0] = 0.811754f;	val_dir[9588*3 + 1] = -0.329775f;	val_dir[9588*3 + 2] = -0.481979f;
+ 	val_dir[9589*3 + 0] = 0.826551f;	val_dir[9589*3 + 1] = -0.300564f;	val_dir[9589*3 + 2] = -0.475893f;
+ 	val_dir[9590*3 + 0] = 0.840083f;	val_dir[9590*3 + 1] = -0.271791f;	val_dir[9590*3 + 2] = -0.469458f;
+ 	val_dir[9591*3 + 0] = 0.852392f;	val_dir[9591*3 + 1] = -0.243541f;	val_dir[9591*3 + 2] = -0.462727f;
+ 	val_dir[9592*3 + 0] = 0.863530f;	val_dir[9592*3 + 1] = -0.215883f;	val_dir[9592*3 + 2] = -0.455752f;
+ 	val_dir[9593*3 + 0] = 0.873555f;	val_dir[9593*3 + 1] = -0.188877f;	val_dir[9593*3 + 2] = -0.448583f;
+ 	val_dir[9594*3 + 0] = 0.882528f;	val_dir[9594*3 + 1] = -0.162571f;	val_dir[9594*3 + 2] = -0.441264f;
+ 	val_dir[9595*3 + 0] = 0.890513f;	val_dir[9595*3 + 1] = -0.137002f;	val_dir[9595*3 + 2] = -0.433840f;
+ 	val_dir[9596*3 + 0] = 0.897574f;	val_dir[9596*3 + 1] = -0.112197f;	val_dir[9596*3 + 2] = -0.426348f;
+ 	val_dir[9597*3 + 0] = 0.903777f;	val_dir[9597*3 + 1] = -0.088173f;	val_dir[9597*3 + 2] = -0.418823f;
+ 	val_dir[9598*3 + 0] = 0.909185f;	val_dir[9598*3 + 1] = -0.064942f;	val_dir[9598*3 + 2] = -0.411298f;
+ 	val_dir[9599*3 + 0] = 0.913860f;	val_dir[9599*3 + 1] = -0.042505f;	val_dir[9599*3 + 2] = -0.403799f;
+ 	val_dir[9600*3 + 0] = 0.917863f;	val_dir[9600*3 + 1] = -0.020861f;	val_dir[9600*3 + 2] = -0.396350f;
+ 	val_dir[9601*3 + 0] = 0.921250f;	val_dir[9601*3 + 1] = 0.0f;	val_dir[9601*3 + 2] = -0.388972f;
+ 	val_dir[9602*3 + 0] = 0.93780f;	val_dir[9602*3 + 1] = 0.020387f;	val_dir[9602*3 + 2] = -0.346578f;
+ 	val_dir[9603*3 + 0] = 0.951877f;	val_dir[9603*3 + 1] = 0.040505f;	val_dir[9603*3 + 2] = -0.303791f;
+ 	val_dir[9604*3 + 0] = 0.963475f;	val_dir[9604*3 + 1] = 0.060217f;	val_dir[9604*3 + 2] = -0.260941f;
+ 	val_dir[9605*3 + 0] = 0.972636f;	val_dir[9605*3 + 1] = 0.079399f;	val_dir[9605*3 + 2] = -0.218347f;
+ 	val_dir[9606*3 + 0] = 0.979451f;	val_dir[9606*3 + 1] = 0.097945f;	val_dir[9606*3 + 2] = -0.176301f;
+ 	val_dir[9607*3 + 0] = 0.984050f;	val_dir[9607*3 + 1] = 0.115771f;	val_dir[9607*3 + 2] = -0.135066f;
+ 	val_dir[9608*3 + 0] = 0.986591f;	val_dir[9608*3 + 1] = 0.132810f;	val_dir[9608*3 + 2] = -0.094865f;
+ 	val_dir[9609*3 + 0] = 0.987254f;	val_dir[9609*3 + 1] = 0.149019f;	val_dir[9609*3 + 2] = -0.055882f;
+ 	val_dir[9610*3 + 0] = 0.986229f;	val_dir[9610*3 + 1] = 0.164372f;	val_dir[9610*3 + 2] = -0.018264f;
+ 	val_dir[9611*3 + 0] = -0.182089f;	val_dir[9611*3 + 1] = -0.983282f;	val_dir[9611*3 + 2] = 0.0f;
+ 	val_dir[9612*3 + 0] = -0.167299f;	val_dir[9612*3 + 1] = -0.985205f;	val_dir[9612*3 + 2] = -0.037178f;
+ 	val_dir[9613*3 + 0] = -0.151620f;	val_dir[9613*3 + 1] = -0.985527f;	val_dir[9613*3 + 2] = -0.075810f;
+ 	val_dir[9614*3 + 0] = -0.135066f;	val_dir[9614*3 + 1] = -0.984050f;	val_dir[9614*3 + 2] = -0.115771f;
+ 	val_dir[9615*3 + 0] = -0.117670f;	val_dir[9615*3 + 1] = -0.980581f;	val_dir[9615*3 + 2] = -0.156893f;
+ 	val_dir[9616*3 + 0] = -0.099484f;	val_dir[9616*3 + 1] = -0.974943f;	val_dir[9616*3 + 2] = -0.198968f;
+ 	val_dir[9617*3 + 0] = -0.080582f;	val_dir[9617*3 + 1] = -0.966988f;	val_dir[9617*3 + 2] = -0.241747f;
+ 	val_dir[9618*3 + 0] = -0.061059f;	val_dir[9618*3 + 1] = -0.956597f;	val_dir[9618*3 + 2] = -0.284944f;
+ 	val_dir[9619*3 + 0] = -0.041030f;	val_dir[9619*3 + 1] = -0.943701f;	val_dir[9619*3 + 2] = -0.328244f;
+ 	val_dir[9620*3 + 0] = -0.020628f;	val_dir[9620*3 + 1] = -0.928279f;	val_dir[9620*3 + 2] = -0.371312f;
+ 	val_dir[9621*3 + 0] = 0.0f;	val_dir[9621*3 + 1] = -0.910366f;	val_dir[9621*3 + 2] = -0.413803f;
+ 	val_dir[9622*3 + 0] = 0.021082f;	val_dir[9622*3 + 1] = -0.906520f;	val_dir[9622*3 + 2] = -0.421637f;
+ 	val_dir[9623*3 + 0] = 0.042954f;	val_dir[9623*3 + 1] = -0.902027f;	val_dir[9623*3 + 2] = -0.429537f;
+ 	val_dir[9624*3 + 0] = 0.065622f;	val_dir[9624*3 + 1] = -0.896831f;	val_dir[9624*3 + 2] = -0.437479f;
+ 	val_dir[9625*3 + 0] = 0.089087f;	val_dir[9625*3 + 1] = -0.890871f;	val_dir[9625*3 + 2] = -0.445435f;
+ 	val_dir[9626*3 + 0] = 0.113344f;	val_dir[9626*3 + 1] = -0.884083f;	val_dir[9626*3 + 2] = -0.453376f;
+ 	val_dir[9627*3 + 0] = 0.138380f;	val_dir[9627*3 + 1] = -0.876405f;	val_dir[9627*3 + 2] = -0.461266f;
+ 	val_dir[9628*3 + 0] = 0.164173f;	val_dir[9628*3 + 1] = -0.867770f;	val_dir[9628*3 + 2] = -0.469065f;
+ 	val_dir[9629*3 + 0] = 0.190693f;	val_dir[9629*3 + 1] = -0.858116f;	val_dir[9629*3 + 2] = -0.476731f;
+ 	val_dir[9630*3 + 0] = 0.217898f;	val_dir[9630*3 + 1] = -0.847381f;	val_dir[9630*3 + 2] = -0.484217f;
+ 	val_dir[9631*3 + 0] = 0.245737f;	val_dir[9631*3 + 1] = -0.835504f;	val_dir[9631*3 + 2] = -0.491473f;
+ 	val_dir[9632*3 + 0] = 0.274145f;	val_dir[9632*3 + 1] = -0.822434f;	val_dir[9632*3 + 2] = -0.498445f;
+ 	val_dir[9633*3 + 0] = 0.303046f;	val_dir[9633*3 + 1] = -0.808122f;	val_dir[9633*3 + 2] = -0.505076f;
+ 	val_dir[9634*3 + 0] = 0.332352f;	val_dir[9634*3 + 1] = -0.792530f;	val_dir[9634*3 + 2] = -0.511310f;
+ 	val_dir[9635*3 + 0] = 0.361961f;	val_dir[9635*3 + 1] = -0.775632f;	val_dir[9635*3 + 2] = -0.517088f;
+ 	val_dir[9636*3 + 0] = 0.391764f;	val_dir[9636*3 + 1] = -0.757410f;	val_dir[9636*3 + 2] = -0.522352f;
+ 	val_dir[9637*3 + 0] = 0.421637f;	val_dir[9637*3 + 1] = -0.737865f;	val_dir[9637*3 + 2] = -0.527046f;
+ 	val_dir[9638*3 + 0] = 0.451451f;	val_dir[9638*3 + 1] = -0.717011f;	val_dir[9638*3 + 2] = -0.531119f;
+ 	val_dir[9639*3 + 0] = 0.481070f;	val_dir[9639*3 + 1] = -0.694879f;	val_dir[9639*3 + 2] = -0.534522f;
+ 	val_dir[9640*3 + 0] = 0.510355f;	val_dir[9640*3 + 1] = -0.671519f;	val_dir[9640*3 + 2] = -0.537215f;
+ 	val_dir[9641*3 + 0] = 0.539164f;	val_dir[9641*3 + 1] = -0.646997f;	val_dir[9641*3 + 2] = -0.539164f;
+ 	val_dir[9642*3 + 0] = 0.567360f;	val_dir[9642*3 + 1] = -0.621395f;	val_dir[9642*3 + 2] = -0.540343f;
+ 	val_dir[9643*3 + 0] = 0.594812f;	val_dir[9643*3 + 1] = -0.594812f;	val_dir[9643*3 + 2] = -0.540738f;
+ 	val_dir[9644*3 + 0] = 0.621395f;	val_dir[9644*3 + 1] = -0.567360f;	val_dir[9644*3 + 2] = -0.540343f;
+ 	val_dir[9645*3 + 0] = 0.646997f;	val_dir[9645*3 + 1] = -0.539164f;	val_dir[9645*3 + 2] = -0.539164f;
+ 	val_dir[9646*3 + 0] = 0.671519f;	val_dir[9646*3 + 1] = -0.510355f;	val_dir[9646*3 + 2] = -0.537215f;
+ 	val_dir[9647*3 + 0] = 0.694879f;	val_dir[9647*3 + 1] = -0.481070f;	val_dir[9647*3 + 2] = -0.534522f;
+ 	val_dir[9648*3 + 0] = 0.717011f;	val_dir[9648*3 + 1] = -0.451451f;	val_dir[9648*3 + 2] = -0.531119f;
+ 	val_dir[9649*3 + 0] = 0.737865f;	val_dir[9649*3 + 1] = -0.421637f;	val_dir[9649*3 + 2] = -0.527046f;
+ 	val_dir[9650*3 + 0] = 0.757410f;	val_dir[9650*3 + 1] = -0.391764f;	val_dir[9650*3 + 2] = -0.522352f;
+ 	val_dir[9651*3 + 0] = 0.775632f;	val_dir[9651*3 + 1] = -0.361961f;	val_dir[9651*3 + 2] = -0.517088f;
+ 	val_dir[9652*3 + 0] = 0.792530f;	val_dir[9652*3 + 1] = -0.332352f;	val_dir[9652*3 + 2] = -0.511310f;
+ 	val_dir[9653*3 + 0] = 0.808122f;	val_dir[9653*3 + 1] = -0.303046f;	val_dir[9653*3 + 2] = -0.505076f;
+ 	val_dir[9654*3 + 0] = 0.822434f;	val_dir[9654*3 + 1] = -0.274145f;	val_dir[9654*3 + 2] = -0.498445f;
+ 	val_dir[9655*3 + 0] = 0.835504f;	val_dir[9655*3 + 1] = -0.245737f;	val_dir[9655*3 + 2] = -0.491473f;
+ 	val_dir[9656*3 + 0] = 0.847381f;	val_dir[9656*3 + 1] = -0.217898f;	val_dir[9656*3 + 2] = -0.484217f;
+ 	val_dir[9657*3 + 0] = 0.858116f;	val_dir[9657*3 + 1] = -0.190693f;	val_dir[9657*3 + 2] = -0.476731f;
+ 	val_dir[9658*3 + 0] = 0.867770f;	val_dir[9658*3 + 1] = -0.164173f;	val_dir[9658*3 + 2] = -0.469065f;
+ 	val_dir[9659*3 + 0] = 0.876405f;	val_dir[9659*3 + 1] = -0.138380f;	val_dir[9659*3 + 2] = -0.461266f;
+ 	val_dir[9660*3 + 0] = 0.884083f;	val_dir[9660*3 + 1] = -0.113344f;	val_dir[9660*3 + 2] = -0.453376f;
+ 	val_dir[9661*3 + 0] = 0.890871f;	val_dir[9661*3 + 1] = -0.089087f;	val_dir[9661*3 + 2] = -0.445435f;
+ 	val_dir[9662*3 + 0] = 0.896831f;	val_dir[9662*3 + 1] = -0.065622f;	val_dir[9662*3 + 2] = -0.437479f;
+ 	val_dir[9663*3 + 0] = 0.902027f;	val_dir[9663*3 + 1] = -0.042954f;	val_dir[9663*3 + 2] = -0.429537f;
+ 	val_dir[9664*3 + 0] = 0.906520f;	val_dir[9664*3 + 1] = -0.021082f;	val_dir[9664*3 + 2] = -0.421637f;
+ 	val_dir[9665*3 + 0] = 0.910366f;	val_dir[9665*3 + 1] = 0.0f;	val_dir[9665*3 + 2] = -0.413803f;
+ 	val_dir[9666*3 + 0] = 0.928279f;	val_dir[9666*3 + 1] = 0.020628f;	val_dir[9666*3 + 2] = -0.371312f;
+ 	val_dir[9667*3 + 0] = 0.943701f;	val_dir[9667*3 + 1] = 0.041030f;	val_dir[9667*3 + 2] = -0.328244f;
+ 	val_dir[9668*3 + 0] = 0.956597f;	val_dir[9668*3 + 1] = 0.061059f;	val_dir[9668*3 + 2] = -0.284944f;
+ 	val_dir[9669*3 + 0] = 0.966988f;	val_dir[9669*3 + 1] = 0.080582f;	val_dir[9669*3 + 2] = -0.241747f;
+ 	val_dir[9670*3 + 0] = 0.974943f;	val_dir[9670*3 + 1] = 0.099484f;	val_dir[9670*3 + 2] = -0.198968f;
+ 	val_dir[9671*3 + 0] = 0.980581f;	val_dir[9671*3 + 1] = 0.117670f;	val_dir[9671*3 + 2] = -0.156893f;
+ 	val_dir[9672*3 + 0] = 0.984050f;	val_dir[9672*3 + 1] = 0.135066f;	val_dir[9672*3 + 2] = -0.115771f;
+ 	val_dir[9673*3 + 0] = 0.985527f;	val_dir[9673*3 + 1] = 0.151620f;	val_dir[9673*3 + 2] = -0.075810f;
+ 	val_dir[9674*3 + 0] = 0.985205f;	val_dir[9674*3 + 1] = 0.167299f;	val_dir[9674*3 + 2] = -0.037178f;
+ 	val_dir[9675*3 + 0] = 0.983282f;	val_dir[9675*3 + 1] = 0.182089f;	val_dir[9675*3 + 2] = 0.0f;
+ 	val_dir[9676*3 + 0] = -0.185376f;	val_dir[9676*3 + 1] = -0.982493f;	val_dir[9676*3 + 2] = -0.018538f;
+ 	val_dir[9677*3 + 0] = -0.170267f;	val_dir[9677*3 + 1] = -0.983762f;	val_dir[9677*3 + 2] = -0.056756f;
+ 	val_dir[9678*3 + 0] = -0.154246f;	val_dir[9678*3 + 1] = -0.983318f;	val_dir[9678*3 + 2] = -0.096404f;
+ 	val_dir[9679*3 + 0] = -0.137334f;	val_dir[9679*3 + 1] = -0.980958f;	val_dir[9679*3 + 2] = -0.137334f;
+ 	val_dir[9680*3 + 0] = -0.119570f;	val_dir[9680*3 + 1] = -0.976491f;	val_dir[9680*3 + 2] = -0.179355f;
+ 	val_dir[9681*3 + 0] = -0.101015f;	val_dir[9681*3 + 1] = -0.969746f;	val_dir[9681*3 + 2] = -0.222234f;
+ 	val_dir[9682*3 + 0] = -0.081752f;	val_dir[9682*3 + 1] = -0.960585f;	val_dir[9682*3 + 2] = -0.265694f;
+ 	val_dir[9683*3 + 0] = -0.061885f;	val_dir[9683*3 + 1] = -0.948908f;	val_dir[9683*3 + 2] = -0.309426f;
+ 	val_dir[9684*3 + 0] = -0.041541f;	val_dir[9684*3 + 1] = -0.934665f;	val_dir[9684*3 + 2] = -0.353096f;
+ 	val_dir[9685*3 + 0] = -0.020861f;	val_dir[9685*3 + 1] = -0.917863f;	val_dir[9685*3 + 2] = -0.396350f;
+ 	val_dir[9686*3 + 0] = 0.0f;	val_dir[9686*3 + 1] = -0.898567f;	val_dir[9686*3 + 2] = -0.438835f;
+ 	val_dir[9687*3 + 0] = 0.021291f;	val_dir[9687*3 + 1] = -0.894224f;	val_dir[9687*3 + 2] = -0.447112f;
+ 	val_dir[9688*3 + 0] = 0.043376f;	val_dir[9688*3 + 1] = -0.889206f;	val_dir[9688*3 + 2] = -0.455447f;
+ 	val_dir[9689*3 + 0] = 0.066259f;	val_dir[9689*3 + 1] = -0.883452f;	val_dir[9689*3 + 2] = -0.463812f;
+ 	val_dir[9690*3 + 0] = 0.089939f;	val_dir[9690*3 + 1] = -0.876903f;	val_dir[9690*3 + 2] = -0.472178f;
+ 	val_dir[9691*3 + 0] = 0.114407f;	val_dir[9691*3 + 1] = -0.869495f;	val_dir[9691*3 + 2] = -0.480510f;
+ 	val_dir[9692*3 + 0] = 0.139648f;	val_dir[9692*3 + 1] = -0.861164f;	val_dir[9692*3 + 2] = -0.488769f;
+ 	val_dir[9693*3 + 0] = 0.165637f;	val_dir[9693*3 + 1] = -0.851847f;	val_dir[9693*3 + 2] = -0.496911f;
+ 	val_dir[9694*3 + 0] = 0.192339f;	val_dir[9694*3 + 1] = -0.841482f;	val_dir[9694*3 + 2] = -0.504889f;
+ 	val_dir[9695*3 + 0] = 0.219708f;	val_dir[9695*3 + 1] = -0.830009f;	val_dir[9695*3 + 2] = -0.512653f;
+ 	val_dir[9696*3 + 0] = 0.247689f;	val_dir[9696*3 + 1] = -0.817373f;	val_dir[9696*3 + 2] = -0.520146f;
+ 	val_dir[9697*3 + 0] = 0.276211f;	val_dir[9697*3 + 1] = -0.803523f;	val_dir[9697*3 + 2] = -0.527312f;
+ 	val_dir[9698*3 + 0] = 0.305194f;	val_dir[9698*3 + 1] = -0.788419f;	val_dir[9698*3 + 2] = -0.534090f;
+ 	val_dir[9699*3 + 0] = 0.334545f;	val_dir[9699*3 + 1] = -0.772027f;	val_dir[9699*3 + 2] = -0.540419f;
+ 	val_dir[9700*3 + 0] = 0.364159f;	val_dir[9700*3 + 1] = -0.754329f;	val_dir[9700*3 + 2] = -0.546238f;
+ 	val_dir[9701*3 + 0] = 0.393919f;	val_dir[9701*3 + 1] = -0.735316f;	val_dir[9701*3 + 2] = -0.551487f;
+ 	val_dir[9702*3 + 0] = 0.423702f;	val_dir[9702*3 + 1] = -0.714997f;	val_dir[9702*3 + 2] = -0.556108f;
+ 	val_dir[9703*3 + 0] = 0.453374f;	val_dir[9703*3 + 1] = -0.693395f;	val_dir[9703*3 + 2] = -0.560050f;
+ 	val_dir[9704*3 + 0] = 0.482798f;	val_dir[9704*3 + 1] = -0.670552f;	val_dir[9704*3 + 2] = -0.563264f;
+ 	val_dir[9705*3 + 0] = 0.511834f;	val_dir[9705*3 + 1] = -0.646527f;	val_dir[9705*3 + 2] = -0.565711f;
+ 	val_dir[9706*3 + 0] = 0.540343f;	val_dir[9706*3 + 1] = -0.621395f;	val_dir[9706*3 + 2] = -0.567360f;
+ 	val_dir[9707*3 + 0] = 0.568190f;	val_dir[9707*3 + 1] = -0.595247f;	val_dir[9707*3 + 2] = -0.568190f;
+ 	val_dir[9708*3 + 0] = 0.595247f;	val_dir[9708*3 + 1] = -0.568190f;	val_dir[9708*3 + 2] = -0.568190f;
+ 	val_dir[9709*3 + 0] = 0.621395f;	val_dir[9709*3 + 1] = -0.540343f;	val_dir[9709*3 + 2] = -0.567360f;
+ 	val_dir[9710*3 + 0] = 0.646527f;	val_dir[9710*3 + 1] = -0.511834f;	val_dir[9710*3 + 2] = -0.565711f;
+ 	val_dir[9711*3 + 0] = 0.670552f;	val_dir[9711*3 + 1] = -0.482798f;	val_dir[9711*3 + 2] = -0.563264f;
+ 	val_dir[9712*3 + 0] = 0.693395f;	val_dir[9712*3 + 1] = -0.453374f;	val_dir[9712*3 + 2] = -0.560050f;
+ 	val_dir[9713*3 + 0] = 0.714997f;	val_dir[9713*3 + 1] = -0.423702f;	val_dir[9713*3 + 2] = -0.556108f;
+ 	val_dir[9714*3 + 0] = 0.735316f;	val_dir[9714*3 + 1] = -0.393919f;	val_dir[9714*3 + 2] = -0.551487f;
+ 	val_dir[9715*3 + 0] = 0.754329f;	val_dir[9715*3 + 1] = -0.364159f;	val_dir[9715*3 + 2] = -0.546238f;
+ 	val_dir[9716*3 + 0] = 0.772027f;	val_dir[9716*3 + 1] = -0.334545f;	val_dir[9716*3 + 2] = -0.540419f;
+ 	val_dir[9717*3 + 0] = 0.788419f;	val_dir[9717*3 + 1] = -0.305194f;	val_dir[9717*3 + 2] = -0.534090f;
+ 	val_dir[9718*3 + 0] = 0.803523f;	val_dir[9718*3 + 1] = -0.276211f;	val_dir[9718*3 + 2] = -0.527312f;
+ 	val_dir[9719*3 + 0] = 0.817373f;	val_dir[9719*3 + 1] = -0.247689f;	val_dir[9719*3 + 2] = -0.520146f;
+ 	val_dir[9720*3 + 0] = 0.830009f;	val_dir[9720*3 + 1] = -0.219708f;	val_dir[9720*3 + 2] = -0.512653f;
+ 	val_dir[9721*3 + 0] = 0.841482f;	val_dir[9721*3 + 1] = -0.192339f;	val_dir[9721*3 + 2] = -0.504889f;
+ 	val_dir[9722*3 + 0] = 0.851847f;	val_dir[9722*3 + 1] = -0.165637f;	val_dir[9722*3 + 2] = -0.496911f;
+ 	val_dir[9723*3 + 0] = 0.861164f;	val_dir[9723*3 + 1] = -0.139648f;	val_dir[9723*3 + 2] = -0.488769f;
+ 	val_dir[9724*3 + 0] = 0.869495f;	val_dir[9724*3 + 1] = -0.114407f;	val_dir[9724*3 + 2] = -0.480510f;
+ 	val_dir[9725*3 + 0] = 0.876903f;	val_dir[9725*3 + 1] = -0.089939f;	val_dir[9725*3 + 2] = -0.472178f;
+ 	val_dir[9726*3 + 0] = 0.883452f;	val_dir[9726*3 + 1] = -0.066259f;	val_dir[9726*3 + 2] = -0.463812f;
+ 	val_dir[9727*3 + 0] = 0.889206f;	val_dir[9727*3 + 1] = -0.043376f;	val_dir[9727*3 + 2] = -0.455447f;
+ 	val_dir[9728*3 + 0] = 0.894224f;	val_dir[9728*3 + 1] = -0.021291f;	val_dir[9728*3 + 2] = -0.447112f;
+ 	val_dir[9729*3 + 0] = 0.898567f;	val_dir[9729*3 + 1] = 0.0f;	val_dir[9729*3 + 2] = -0.438835f;
+ 	val_dir[9730*3 + 0] = 0.917863f;	val_dir[9730*3 + 1] = 0.020861f;	val_dir[9730*3 + 2] = -0.396350f;
+ 	val_dir[9731*3 + 0] = 0.934665f;	val_dir[9731*3 + 1] = 0.041541f;	val_dir[9731*3 + 2] = -0.353096f;
+ 	val_dir[9732*3 + 0] = 0.948908f;	val_dir[9732*3 + 1] = 0.061885f;	val_dir[9732*3 + 2] = -0.309426f;
+ 	val_dir[9733*3 + 0] = 0.960585f;	val_dir[9733*3 + 1] = 0.081752f;	val_dir[9733*3 + 2] = -0.265694f;
+ 	val_dir[9734*3 + 0] = 0.969746f;	val_dir[9734*3 + 1] = 0.101015f;	val_dir[9734*3 + 2] = -0.222234f;
+ 	val_dir[9735*3 + 0] = 0.976491f;	val_dir[9735*3 + 1] = 0.119570f;	val_dir[9735*3 + 2] = -0.179355f;
+ 	val_dir[9736*3 + 0] = 0.980958f;	val_dir[9736*3 + 1] = 0.137334f;	val_dir[9736*3 + 2] = -0.137334f;
+ 	val_dir[9737*3 + 0] = 0.983318f;	val_dir[9737*3 + 1] = 0.154246f;	val_dir[9737*3 + 2] = -0.096404f;
+ 	val_dir[9738*3 + 0] = 0.983762f;	val_dir[9738*3 + 1] = 0.170267f;	val_dir[9738*3 + 2] = -0.056756f;
+ 	val_dir[9739*3 + 0] = 0.982493f;	val_dir[9739*3 + 1] = 0.185376f;	val_dir[9739*3 + 2] = -0.018538f;
+ 	val_dir[9740*3 + 0] = -0.203216f;	val_dir[9740*3 + 1] = -0.979134f;	val_dir[9740*3 + 2] = 0.0f;
+ 	val_dir[9741*3 + 0] = -0.188713f;	val_dir[9741*3 + 1] = -0.981307f;	val_dir[9741*3 + 2] = -0.037743f;
+ 	val_dir[9742*3 + 0] = -0.173269f;	val_dir[9742*3 + 1] = -0.981859f;	val_dir[9742*3 + 2] = -0.077009f;
+ 	val_dir[9743*3 + 0] = -0.156893f;	val_dir[9743*3 + 1] = -0.980581f;	val_dir[9743*3 + 2] = -0.117670f;
+ 	val_dir[9744*3 + 0] = -0.139610f;	val_dir[9744*3 + 1] = -0.977267f;	val_dir[9744*3 + 2] = -0.159554f;
+ 	val_dir[9745*3 + 0] = -0.121466f;	val_dir[9745*3 + 1] = -0.971732f;	val_dir[9745*3 + 2] = -0.202444f;
+ 	val_dir[9746*3 + 0] = -0.102533f;	val_dir[9746*3 + 1] = -0.963811f;	val_dir[9746*3 + 2] = -0.246079f;
+ 	val_dir[9747*3 + 0] = -0.082903f;	val_dir[9747*3 + 1] = -0.953381f;	val_dir[9747*3 + 2] = -0.290159f;
+ 	val_dir[9748*3 + 0] = -0.062691f;	val_dir[9748*3 + 1] = -0.940361f;	val_dir[9748*3 + 2] = -0.334351f;
+ 	val_dir[9749*3 + 0] = -0.042033f;	val_dir[9749*3 + 1] = -0.924729f;	val_dir[9749*3 + 2] = -0.378298f;
+ 	val_dir[9750*3 + 0] = -0.021082f;	val_dir[9750*3 + 1] = -0.906520f;	val_dir[9750*3 + 2] = -0.421637f;
+ 	val_dir[9751*3 + 0] = 0.0f;	val_dir[9751*3 + 1] = -0.885832f;	val_dir[9751*3 + 2] = -0.464007f;
+ 	val_dir[9752*3 + 0] = 0.021487f;	val_dir[9752*3 + 1] = -0.880957f;	val_dir[9752*3 + 2] = -0.472709f;
+ 	val_dir[9753*3 + 0] = 0.043769f;	val_dir[9753*3 + 1] = -0.875376f;	val_dir[9753*3 + 2] = -0.481457f;
+ 	val_dir[9754*3 + 0] = 0.066848f;	val_dir[9754*3 + 1] = -0.869030f;	val_dir[9754*3 + 2] = -0.490222f;
+ 	val_dir[9755*3 + 0] = 0.090722f;	val_dir[9755*3 + 1] = -0.861857f;	val_dir[9755*3 + 2] = -0.498970f;
+ 	val_dir[9756*3 + 0] = 0.115378f;	val_dir[9756*3 + 1] = -0.853796f;	val_dir[9756*3 + 2] = -0.507662f;
+ 	val_dir[9757*3 + 0] = 0.140797f;	val_dir[9757*3 + 1] = -0.844782f;	val_dir[9757*3 + 2] = -0.516256f;
+ 	val_dir[9758*3 + 0] = 0.166951f;	val_dir[9758*3 + 1] = -0.834754f;	val_dir[9758*3 + 2] = -0.524703f;
+ 	val_dir[9759*3 + 0] = 0.193801f;	val_dir[9759*3 + 1] = -0.823653f;	val_dir[9759*3 + 2] = -0.532952f;
+ 	val_dir[9760*3 + 0] = 0.221297f;	val_dir[9760*3 + 1] = -0.811421f;	val_dir[9760*3 + 2] = -0.540947f;
+ 	val_dir[9761*3 + 0] = 0.249377f;	val_dir[9761*3 + 1] = -0.798007f;	val_dir[9761*3 + 2] = -0.548630f;
+ 	val_dir[9762*3 + 0] = 0.277969f;	val_dir[9762*3 + 1] = -0.783368f;	val_dir[9762*3 + 2] = -0.555939f;
+ 	val_dir[9763*3 + 0] = 0.306987f;	val_dir[9763*3 + 1] = -0.767467f;	val_dir[9763*3 + 2] = -0.562809f;
+ 	val_dir[9764*3 + 0] = 0.336332f;	val_dir[9764*3 + 1] = -0.750279f;	val_dir[9764*3 + 2] = -0.569177f;
+ 	val_dir[9765*3 + 0] = 0.365896f;	val_dir[9765*3 + 1] = -0.731792f;	val_dir[9765*3 + 2] = -0.574979f;
+ 	val_dir[9766*3 + 0] = 0.395559f;	val_dir[9766*3 + 1] = -0.712007f;	val_dir[9766*3 + 2] = -0.580154f;
+ 	val_dir[9767*3 + 0] = 0.425195f;	val_dir[9767*3 + 1] = -0.690942f;	val_dir[9767*3 + 2] = -0.584643f;
+ 	val_dir[9768*3 + 0] = 0.454669f;	val_dir[9768*3 + 1] = -0.668631f;	val_dir[9768*3 + 2] = -0.588395f;
+ 	val_dir[9769*3 + 0] = 0.483843f;	val_dir[9769*3 + 1] = -0.645124f;	val_dir[9769*3 + 2] = -0.591364f;
+ 	val_dir[9770*3 + 0] = 0.512578f;	val_dir[9770*3 + 1] = -0.620490f;	val_dir[9770*3 + 2] = -0.593512f;
+ 	val_dir[9771*3 + 0] = 0.540738f;	val_dir[9771*3 + 1] = -0.594812f;	val_dir[9771*3 + 2] = -0.594812f;
+ 	val_dir[9772*3 + 0] = 0.568190f;	val_dir[9772*3 + 1] = -0.568190f;	val_dir[9772*3 + 2] = -0.595247f;
+ 	val_dir[9773*3 + 0] = 0.594812f;	val_dir[9773*3 + 1] = -0.540738f;	val_dir[9773*3 + 2] = -0.594812f;
+ 	val_dir[9774*3 + 0] = 0.620490f;	val_dir[9774*3 + 1] = -0.512578f;	val_dir[9774*3 + 2] = -0.593512f;
+ 	val_dir[9775*3 + 0] = 0.645124f;	val_dir[9775*3 + 1] = -0.483843f;	val_dir[9775*3 + 2] = -0.591364f;
+ 	val_dir[9776*3 + 0] = 0.668631f;	val_dir[9776*3 + 1] = -0.454669f;	val_dir[9776*3 + 2] = -0.588395f;
+ 	val_dir[9777*3 + 0] = 0.690942f;	val_dir[9777*3 + 1] = -0.425195f;	val_dir[9777*3 + 2] = -0.584643f;
+ 	val_dir[9778*3 + 0] = 0.712007f;	val_dir[9778*3 + 1] = -0.395559f;	val_dir[9778*3 + 2] = -0.580154f;
+ 	val_dir[9779*3 + 0] = 0.731792f;	val_dir[9779*3 + 1] = -0.365896f;	val_dir[9779*3 + 2] = -0.574979f;
+ 	val_dir[9780*3 + 0] = 0.750279f;	val_dir[9780*3 + 1] = -0.336332f;	val_dir[9780*3 + 2] = -0.569177f;
+ 	val_dir[9781*3 + 0] = 0.767467f;	val_dir[9781*3 + 1] = -0.306987f;	val_dir[9781*3 + 2] = -0.562809f;
+ 	val_dir[9782*3 + 0] = 0.783368f;	val_dir[9782*3 + 1] = -0.277969f;	val_dir[9782*3 + 2] = -0.555939f;
+ 	val_dir[9783*3 + 0] = 0.798007f;	val_dir[9783*3 + 1] = -0.249377f;	val_dir[9783*3 + 2] = -0.548630f;
+ 	val_dir[9784*3 + 0] = 0.811421f;	val_dir[9784*3 + 1] = -0.221297f;	val_dir[9784*3 + 2] = -0.540947f;
+ 	val_dir[9785*3 + 0] = 0.823653f;	val_dir[9785*3 + 1] = -0.193801f;	val_dir[9785*3 + 2] = -0.532952f;
+ 	val_dir[9786*3 + 0] = 0.834754f;	val_dir[9786*3 + 1] = -0.166951f;	val_dir[9786*3 + 2] = -0.524703f;
+ 	val_dir[9787*3 + 0] = 0.844782f;	val_dir[9787*3 + 1] = -0.140797f;	val_dir[9787*3 + 2] = -0.516256f;
+ 	val_dir[9788*3 + 0] = 0.853796f;	val_dir[9788*3 + 1] = -0.115378f;	val_dir[9788*3 + 2] = -0.507662f;
+ 	val_dir[9789*3 + 0] = 0.861857f;	val_dir[9789*3 + 1] = -0.090722f;	val_dir[9789*3 + 2] = -0.498970f;
+ 	val_dir[9790*3 + 0] = 0.869030f;	val_dir[9790*3 + 1] = -0.066848f;	val_dir[9790*3 + 2] = -0.490222f;
+ 	val_dir[9791*3 + 0] = 0.875376f;	val_dir[9791*3 + 1] = -0.043769f;	val_dir[9791*3 + 2] = -0.481457f;
+ 	val_dir[9792*3 + 0] = 0.880957f;	val_dir[9792*3 + 1] = -0.021487f;	val_dir[9792*3 + 2] = -0.472709f;
+ 	val_dir[9793*3 + 0] = 0.885832f;	val_dir[9793*3 + 1] = 0.0f;	val_dir[9793*3 + 2] = -0.464007f;
+ 	val_dir[9794*3 + 0] = 0.906520f;	val_dir[9794*3 + 1] = 0.021082f;	val_dir[9794*3 + 2] = -0.421637f;
+ 	val_dir[9795*3 + 0] = 0.924729f;	val_dir[9795*3 + 1] = 0.042033f;	val_dir[9795*3 + 2] = -0.378298f;
+ 	val_dir[9796*3 + 0] = 0.940361f;	val_dir[9796*3 + 1] = 0.062691f;	val_dir[9796*3 + 2] = -0.334351f;
+ 	val_dir[9797*3 + 0] = 0.953381f;	val_dir[9797*3 + 1] = 0.082903f;	val_dir[9797*3 + 2] = -0.290159f;
+ 	val_dir[9798*3 + 0] = 0.963811f;	val_dir[9798*3 + 1] = 0.102533f;	val_dir[9798*3 + 2] = -0.246079f;
+ 	val_dir[9799*3 + 0] = 0.971732f;	val_dir[9799*3 + 1] = 0.121466f;	val_dir[9799*3 + 2] = -0.202444f;
+ 	val_dir[9800*3 + 0] = 0.977267f;	val_dir[9800*3 + 1] = 0.139610f;	val_dir[9800*3 + 2] = -0.159554f;
+ 	val_dir[9801*3 + 0] = 0.980581f;	val_dir[9801*3 + 1] = 0.156893f;	val_dir[9801*3 + 2] = -0.117670f;
+ 	val_dir[9802*3 + 0] = 0.981859f;	val_dir[9802*3 + 1] = 0.173269f;	val_dir[9802*3 + 2] = -0.077009f;
+ 	val_dir[9803*3 + 0] = 0.981307f;	val_dir[9803*3 + 1] = 0.188713f;	val_dir[9803*3 + 2] = -0.037743f;
+ 	val_dir[9804*3 + 0] = 0.979134f;	val_dir[9804*3 + 1] = 0.203216f;	val_dir[9804*3 + 2] = 0.0f;
+ 	val_dir[9805*3 + 0] = -0.206922f;	val_dir[9805*3 + 1] = -0.978177f;	val_dir[9805*3 + 2] = -0.018811f;
+ 	val_dir[9806*3 + 0] = -0.192095f;	val_dir[9806*3 + 1] = -0.979683f;	val_dir[9806*3 + 2] = -0.057628f;
+ 	val_dir[9807*3 + 0] = -0.176301f;	val_dir[9807*3 + 1] = -0.979451f;	val_dir[9807*3 + 2] = -0.097945f;
+ 	val_dir[9808*3 + 0] = -0.159554f;	val_dir[9808*3 + 1] = -0.977267f;	val_dir[9808*3 + 2] = -0.139610f;
+ 	val_dir[9809*3 + 0] = -0.141885f;	val_dir[9809*3 + 1] = -0.972929f;	val_dir[9809*3 + 2] = -0.182424f;
+ 	val_dir[9810*3 + 0] = -0.123351f;	val_dir[9810*3 + 1] = -0.966252f;	val_dir[9810*3 + 2] = -0.226144f;
+ 	val_dir[9811*3 + 0] = -0.104031f;	val_dir[9811*3 + 1] = -0.957088f;	val_dir[9811*3 + 2] = -0.270481f;
+ 	val_dir[9812*3 + 0] = -0.084029f;	val_dir[9812*3 + 1] = -0.945328f;	val_dir[9812*3 + 2] = -0.315109f;
+ 	val_dir[9813*3 + 0] = -0.063472f;	val_dir[9813*3 + 1] = -0.930917f;	val_dir[9813*3 + 2] = -0.359673f;
+ 	val_dir[9814*3 + 0] = -0.042505f;	val_dir[9814*3 + 1] = -0.913860f;	val_dir[9814*3 + 2] = -0.403799f;
+ 	val_dir[9815*3 + 0] = -0.021291f;	val_dir[9815*3 + 1] = -0.894224f;	val_dir[9815*3 + 2] = -0.447112f;
+ 	val_dir[9816*3 + 0] = 0.0f;	val_dir[9816*3 + 1] = -0.872143f;	val_dir[9816*3 + 2] = -0.489251f;
+ 	val_dir[9817*3 + 0] = 0.021668f;	val_dir[9817*3 + 1] = -0.866703f;	val_dir[9817*3 + 2] = -0.498354f;
+ 	val_dir[9818*3 + 0] = 0.044130f;	val_dir[9818*3 + 1] = -0.860527f;	val_dir[9818*3 + 2] = -0.507490f;
+ 	val_dir[9819*3 + 0] = 0.067386f;	val_dir[9819*3 + 1] = -0.853556f;	val_dir[9819*3 + 2] = -0.516626f;
+ 	val_dir[9820*3 + 0] = 0.091430f;	val_dir[9820*3 + 1] = -0.845728f;	val_dir[9820*3 + 2] = -0.525723f;
+ 	val_dir[9821*3 + 0] = 0.116248f;	val_dir[9821*3 + 1] = -0.836983f;	val_dir[9821*3 + 2] = -0.534739f;
+ 	val_dir[9822*3 + 0] = 0.141816f;	val_dir[9822*3 + 1] = -0.827259f;	val_dir[9822*3 + 2] = -0.543627f;
+ 	val_dir[9823*3 + 0] = 0.168102f;	val_dir[9823*3 + 1] = -0.816497f;	val_dir[9823*3 + 2] = -0.552336f;
+ 	val_dir[9824*3 + 0] = 0.195064f;	val_dir[9824*3 + 1] = -0.804639f;	val_dir[9824*3 + 2] = -0.560809f;
+ 	val_dir[9825*3 + 0] = 0.222647f;	val_dir[9825*3 + 1] = -0.791633f;	val_dir[9825*3 + 2] = -0.568986f;
+ 	val_dir[9826*3 + 0] = 0.250785f;	val_dir[9826*3 + 1] = -0.777433f;	val_dir[9826*3 + 2] = -0.576805f;
+ 	val_dir[9827*3 + 0] = 0.27940f;	val_dir[9827*3 + 1] = -0.762001f;	val_dir[9827*3 + 2] = -0.584201f;
+ 	val_dir[9828*3 + 0] = 0.308403f;	val_dir[9828*3 + 1] = -0.745307f;	val_dir[9828*3 + 2] = -0.591105f;
+ 	val_dir[9829*3 + 0] = 0.337691f;	val_dir[9829*3 + 1] = -0.727334f;	val_dir[9829*3 + 2] = -0.597453f;
+ 	val_dir[9830*3 + 0] = 0.367152f;	val_dir[9830*3 + 1] = -0.708079f;	val_dir[9830*3 + 2] = -0.603178f;
+ 	val_dir[9831*3 + 0] = 0.396664f;	val_dir[9831*3 + 1] = -0.687552f;	val_dir[9831*3 + 2] = -0.608219f;
+ 	val_dir[9832*3 + 0] = 0.426099f;	val_dir[9832*3 + 1] = -0.665780f;	val_dir[9832*3 + 2] = -0.612517f;
+ 	val_dir[9833*3 + 0] = 0.455321f;	val_dir[9833*3 + 1] = -0.642806f;	val_dir[9833*3 + 2] = -0.616022f;
+ 	val_dir[9834*3 + 0] = 0.484193f;	val_dir[9834*3 + 1] = -0.618691f;	val_dir[9834*3 + 2] = -0.618691f;
+ 	val_dir[9835*3 + 0] = 0.512578f;	val_dir[9835*3 + 1] = -0.593512f;	val_dir[9835*3 + 2] = -0.620490f;
+ 	val_dir[9836*3 + 0] = 0.540343f;	val_dir[9836*3 + 1] = -0.567360f;	val_dir[9836*3 + 2] = -0.621395f;
+ 	val_dir[9837*3 + 0] = 0.567360f;	val_dir[9837*3 + 1] = -0.540343f;	val_dir[9837*3 + 2] = -0.621395f;
+ 	val_dir[9838*3 + 0] = 0.593512f;	val_dir[9838*3 + 1] = -0.512578f;	val_dir[9838*3 + 2] = -0.620490f;
+ 	val_dir[9839*3 + 0] = 0.618691f;	val_dir[9839*3 + 1] = -0.484193f;	val_dir[9839*3 + 2] = -0.618691f;
+ 	val_dir[9840*3 + 0] = 0.642806f;	val_dir[9840*3 + 1] = -0.455321f;	val_dir[9840*3 + 2] = -0.616022f;
+ 	val_dir[9841*3 + 0] = 0.665780f;	val_dir[9841*3 + 1] = -0.426099f;	val_dir[9841*3 + 2] = -0.612517f;
+ 	val_dir[9842*3 + 0] = 0.687552f;	val_dir[9842*3 + 1] = -0.396664f;	val_dir[9842*3 + 2] = -0.608219f;
+ 	val_dir[9843*3 + 0] = 0.708079f;	val_dir[9843*3 + 1] = -0.367152f;	val_dir[9843*3 + 2] = -0.603178f;
+ 	val_dir[9844*3 + 0] = 0.727334f;	val_dir[9844*3 + 1] = -0.337691f;	val_dir[9844*3 + 2] = -0.597453f;
+ 	val_dir[9845*3 + 0] = 0.745307f;	val_dir[9845*3 + 1] = -0.308403f;	val_dir[9845*3 + 2] = -0.591105f;
+ 	val_dir[9846*3 + 0] = 0.762001f;	val_dir[9846*3 + 1] = -0.27940f;	val_dir[9846*3 + 2] = -0.584201f;
+ 	val_dir[9847*3 + 0] = 0.777433f;	val_dir[9847*3 + 1] = -0.250785f;	val_dir[9847*3 + 2] = -0.576805f;
+ 	val_dir[9848*3 + 0] = 0.791633f;	val_dir[9848*3 + 1] = -0.222647f;	val_dir[9848*3 + 2] = -0.568986f;
+ 	val_dir[9849*3 + 0] = 0.804639f;	val_dir[9849*3 + 1] = -0.195064f;	val_dir[9849*3 + 2] = -0.560809f;
+ 	val_dir[9850*3 + 0] = 0.816497f;	val_dir[9850*3 + 1] = -0.168102f;	val_dir[9850*3 + 2] = -0.552336f;
+ 	val_dir[9851*3 + 0] = 0.827259f;	val_dir[9851*3 + 1] = -0.141816f;	val_dir[9851*3 + 2] = -0.543627f;
+ 	val_dir[9852*3 + 0] = 0.836983f;	val_dir[9852*3 + 1] = -0.116248f;	val_dir[9852*3 + 2] = -0.534739f;
+ 	val_dir[9853*3 + 0] = 0.845728f;	val_dir[9853*3 + 1] = -0.091430f;	val_dir[9853*3 + 2] = -0.525723f;
+ 	val_dir[9854*3 + 0] = 0.853556f;	val_dir[9854*3 + 1] = -0.067386f;	val_dir[9854*3 + 2] = -0.516626f;
+ 	val_dir[9855*3 + 0] = 0.860527f;	val_dir[9855*3 + 1] = -0.044130f;	val_dir[9855*3 + 2] = -0.507490f;
+ 	val_dir[9856*3 + 0] = 0.866703f;	val_dir[9856*3 + 1] = -0.021668f;	val_dir[9856*3 + 2] = -0.498354f;
+ 	val_dir[9857*3 + 0] = 0.872143f;	val_dir[9857*3 + 1] = 0.0f;	val_dir[9857*3 + 2] = -0.489251f;
+ 	val_dir[9858*3 + 0] = 0.894224f;	val_dir[9858*3 + 1] = 0.021291f;	val_dir[9858*3 + 2] = -0.447112f;
+ 	val_dir[9859*3 + 0] = 0.913860f;	val_dir[9859*3 + 1] = 0.042505f;	val_dir[9859*3 + 2] = -0.403799f;
+ 	val_dir[9860*3 + 0] = 0.930917f;	val_dir[9860*3 + 1] = 0.063472f;	val_dir[9860*3 + 2] = -0.359673f;
+ 	val_dir[9861*3 + 0] = 0.945328f;	val_dir[9861*3 + 1] = 0.084029f;	val_dir[9861*3 + 2] = -0.315109f;
+ 	val_dir[9862*3 + 0] = 0.957088f;	val_dir[9862*3 + 1] = 0.104031f;	val_dir[9862*3 + 2] = -0.270481f;
+ 	val_dir[9863*3 + 0] = 0.966252f;	val_dir[9863*3 + 1] = 0.123351f;	val_dir[9863*3 + 2] = -0.226144f;
+ 	val_dir[9864*3 + 0] = 0.972929f;	val_dir[9864*3 + 1] = 0.141885f;	val_dir[9864*3 + 2] = -0.182424f;
+ 	val_dir[9865*3 + 0] = 0.977267f;	val_dir[9865*3 + 1] = 0.159554f;	val_dir[9865*3 + 2] = -0.139610f;
+ 	val_dir[9866*3 + 0] = 0.979451f;	val_dir[9866*3 + 1] = 0.176301f;	val_dir[9866*3 + 2] = -0.097945f;
+ 	val_dir[9867*3 + 0] = 0.979683f;	val_dir[9867*3 + 1] = 0.192095f;	val_dir[9867*3 + 2] = -0.057628f;
+ 	val_dir[9868*3 + 0] = 0.978177f;	val_dir[9868*3 + 1] = 0.206922f;	val_dir[9868*3 + 2] = -0.018811f;
+ 	val_dir[9869*3 + 0] = -0.224860f;	val_dir[9869*3 + 1] = -0.974391f;	val_dir[9869*3 + 2] = 0.0f;
+ 	val_dir[9870*3 + 0] = -0.210683f;	val_dir[9870*3 + 1] = -0.976804f;	val_dir[9870*3 + 2] = -0.038306f;
+ 	val_dir[9871*3 + 0] = -0.195515f;	val_dir[9871*3 + 1] = -0.977577f;	val_dir[9871*3 + 2] = -0.078206f;
+ 	val_dir[9872*3 + 0] = -0.179355f;	val_dir[9872*3 + 1] = -0.976491f;	val_dir[9872*3 + 2] = -0.119570f;
+ 	val_dir[9873*3 + 0] = -0.162221f;	val_dir[9873*3 + 1] = -0.973329f;	val_dir[9873*3 + 2] = -0.162221f;
+ 	val_dir[9874*3 + 0] = -0.144154f;	val_dir[9874*3 + 1] = -0.967890f;	val_dir[9874*3 + 2] = -0.205934f;
+ 	val_dir[9875*3 + 0] = -0.125218f;	val_dir[9875*3 + 1] = -0.960001f;	val_dir[9875*3 + 2] = -0.250435f;
+ 	val_dir[9876*3 + 0] = -0.105503f;	val_dir[9876*3 + 1] = -0.949528f;	val_dir[9876*3 + 2] = -0.295409f;
+ 	val_dir[9877*3 + 0] = -0.085126f;	val_dir[9877*3 + 1] = -0.936382f;	val_dir[9877*3 + 2] = -0.340503f;
+ 	val_dir[9878*3 + 0] = -0.064223f;	val_dir[9878*3 + 1] = -0.920537f;	val_dir[9878*3 + 2] = -0.385341f;
+ 	val_dir[9879*3 + 0] = -0.042954f;	val_dir[9879*3 + 1] = -0.902027f;	val_dir[9879*3 + 2] = -0.429537f;
+ 	val_dir[9880*3 + 0] = -0.021487f;	val_dir[9880*3 + 1] = -0.880957f;	val_dir[9880*3 + 2] = -0.472709f;
+ 	val_dir[9881*3 + 0] = 0.0f;	val_dir[9881*3 + 1] = -0.857493f;	val_dir[9881*3 + 2] = -0.514496f;
+ 	val_dir[9882*3 + 0] = 0.021832f;	val_dir[9882*3 + 1] = -0.851455f;	val_dir[9882*3 + 2] = -0.523973f;
+ 	val_dir[9883*3 + 0] = 0.044455f;	val_dir[9883*3 + 1] = -0.844653f;	val_dir[9883*3 + 2] = -0.533465f;
+ 	val_dir[9884*3 + 0] = 0.067867f;	val_dir[9884*3 + 1] = -0.837027f;	val_dir[9884*3 + 2] = -0.542936f;
+ 	val_dir[9885*3 + 0] = 0.092057f;	val_dir[9885*3 + 1] = -0.828517f;	val_dir[9885*3 + 2] = -0.552345f;
+ 	val_dir[9886*3 + 0] = 0.117009f;	val_dir[9886*3 + 1] = -0.819064f;	val_dir[9886*3 + 2] = -0.561644f;
+ 	val_dir[9887*3 + 0] = 0.142695f;	val_dir[9887*3 + 1] = -0.808608f;	val_dir[9887*3 + 2] = -0.570782f;
+ 	val_dir[9888*3 + 0] = 0.169080f;	val_dir[9888*3 + 1] = -0.797092f;	val_dir[9888*3 + 2] = -0.579703f;
+ 	val_dir[9889*3 + 0] = 0.196116f;	val_dir[9889*3 + 1] = -0.784465f;	val_dir[9889*3 + 2] = -0.588348f;
+ 	val_dir[9890*3 + 0] = 0.223745f;	val_dir[9890*3 + 1] = -0.770677f;	val_dir[9890*3 + 2] = -0.596653f;
+ 	val_dir[9891*3 + 0] = 0.251896f;	val_dir[9891*3 + 1] = -0.755689f;	val_dir[9891*3 + 2] = -0.604551f;
+ 	val_dir[9892*3 + 0] = 0.280488f;	val_dir[9892*3 + 1] = -0.739469f;	val_dir[9892*3 + 2] = -0.611974f;
+ 	val_dir[9893*3 + 0] = 0.309426f;	val_dir[9893*3 + 1] = -0.721995f;	val_dir[9893*3 + 2] = -0.618853f;
+ 	val_dir[9894*3 + 0] = 0.338606f;	val_dir[9894*3 + 1] = -0.703259f;	val_dir[9894*3 + 2] = -0.625119f;
+ 	val_dir[9895*3 + 0] = 0.367912f;	val_dir[9895*3 + 1] = -0.683265f;	val_dir[9895*3 + 2] = -0.630706f;
+ 	val_dir[9896*3 + 0] = 0.397220f;	val_dir[9896*3 + 1] = -0.662034f;	val_dir[9896*3 + 2] = -0.635553f;
+ 	val_dir[9897*3 + 0] = 0.426401f;	val_dir[9897*3 + 1] = -0.639602f;	val_dir[9897*3 + 2] = -0.639602f;
+ 	val_dir[9898*3 + 0] = 0.455321f;	val_dir[9898*3 + 1] = -0.616022f;	val_dir[9898*3 + 2] = -0.642806f;
+ 	val_dir[9899*3 + 0] = 0.483843f;	val_dir[9899*3 + 1] = -0.591364f;	val_dir[9899*3 + 2] = -0.645124f;
+ 	val_dir[9900*3 + 0] = 0.511834f;	val_dir[9900*3 + 1] = -0.565711f;	val_dir[9900*3 + 2] = -0.646527f;
+ 	val_dir[9901*3 + 0] = 0.539164f;	val_dir[9901*3 + 1] = -0.539164f;	val_dir[9901*3 + 2] = -0.646997f;
+ 	val_dir[9902*3 + 0] = 0.565711f;	val_dir[9902*3 + 1] = -0.511834f;	val_dir[9902*3 + 2] = -0.646527f;
+ 	val_dir[9903*3 + 0] = 0.591364f;	val_dir[9903*3 + 1] = -0.483843f;	val_dir[9903*3 + 2] = -0.645124f;
+ 	val_dir[9904*3 + 0] = 0.616022f;	val_dir[9904*3 + 1] = -0.455321f;	val_dir[9904*3 + 2] = -0.642806f;
+ 	val_dir[9905*3 + 0] = 0.639602f;	val_dir[9905*3 + 1] = -0.426401f;	val_dir[9905*3 + 2] = -0.639602f;
+ 	val_dir[9906*3 + 0] = 0.662034f;	val_dir[9906*3 + 1] = -0.397220f;	val_dir[9906*3 + 2] = -0.635553f;
+ 	val_dir[9907*3 + 0] = 0.683265f;	val_dir[9907*3 + 1] = -0.367912f;	val_dir[9907*3 + 2] = -0.630706f;
+ 	val_dir[9908*3 + 0] = 0.703259f;	val_dir[9908*3 + 1] = -0.338606f;	val_dir[9908*3 + 2] = -0.625119f;
+ 	val_dir[9909*3 + 0] = 0.721995f;	val_dir[9909*3 + 1] = -0.309426f;	val_dir[9909*3 + 2] = -0.618853f;
+ 	val_dir[9910*3 + 0] = 0.739469f;	val_dir[9910*3 + 1] = -0.280488f;	val_dir[9910*3 + 2] = -0.611974f;
+ 	val_dir[9911*3 + 0] = 0.755689f;	val_dir[9911*3 + 1] = -0.251896f;	val_dir[9911*3 + 2] = -0.604551f;
+ 	val_dir[9912*3 + 0] = 0.770677f;	val_dir[9912*3 + 1] = -0.223745f;	val_dir[9912*3 + 2] = -0.596653f;
+ 	val_dir[9913*3 + 0] = 0.784465f;	val_dir[9913*3 + 1] = -0.196116f;	val_dir[9913*3 + 2] = -0.588348f;
+ 	val_dir[9914*3 + 0] = 0.797092f;	val_dir[9914*3 + 1] = -0.169080f;	val_dir[9914*3 + 2] = -0.579703f;
+ 	val_dir[9915*3 + 0] = 0.808608f;	val_dir[9915*3 + 1] = -0.142695f;	val_dir[9915*3 + 2] = -0.570782f;
+ 	val_dir[9916*3 + 0] = 0.819064f;	val_dir[9916*3 + 1] = -0.117009f;	val_dir[9916*3 + 2] = -0.561644f;
+ 	val_dir[9917*3 + 0] = 0.828517f;	val_dir[9917*3 + 1] = -0.092057f;	val_dir[9917*3 + 2] = -0.552345f;
+ 	val_dir[9918*3 + 0] = 0.837027f;	val_dir[9918*3 + 1] = -0.067867f;	val_dir[9918*3 + 2] = -0.542936f;
+ 	val_dir[9919*3 + 0] = 0.844653f;	val_dir[9919*3 + 1] = -0.044455f;	val_dir[9919*3 + 2] = -0.533465f;
+ 	val_dir[9920*3 + 0] = 0.851455f;	val_dir[9920*3 + 1] = -0.021832f;	val_dir[9920*3 + 2] = -0.523973f;
+ 	val_dir[9921*3 + 0] = 0.857493f;	val_dir[9921*3 + 1] = 0.0f;	val_dir[9921*3 + 2] = -0.514496f;
+ 	val_dir[9922*3 + 0] = 0.880957f;	val_dir[9922*3 + 1] = 0.021487f;	val_dir[9922*3 + 2] = -0.472709f;
+ 	val_dir[9923*3 + 0] = 0.902027f;	val_dir[9923*3 + 1] = 0.042954f;	val_dir[9923*3 + 2] = -0.429537f;
+ 	val_dir[9924*3 + 0] = 0.920537f;	val_dir[9924*3 + 1] = 0.064223f;	val_dir[9924*3 + 2] = -0.385341f;
+ 	val_dir[9925*3 + 0] = 0.936382f;	val_dir[9925*3 + 1] = 0.085126f;	val_dir[9925*3 + 2] = -0.340503f;
+ 	val_dir[9926*3 + 0] = 0.949528f;	val_dir[9926*3 + 1] = 0.105503f;	val_dir[9926*3 + 2] = -0.295409f;
+ 	val_dir[9927*3 + 0] = 0.960001f;	val_dir[9927*3 + 1] = 0.125218f;	val_dir[9927*3 + 2] = -0.250435f;
+ 	val_dir[9928*3 + 0] = 0.967890f;	val_dir[9928*3 + 1] = 0.144154f;	val_dir[9928*3 + 2] = -0.205934f;
+ 	val_dir[9929*3 + 0] = 0.973329f;	val_dir[9929*3 + 1] = 0.162221f;	val_dir[9929*3 + 2] = -0.162221f;
+ 	val_dir[9930*3 + 0] = 0.976491f;	val_dir[9930*3 + 1] = 0.179355f;	val_dir[9930*3 + 2] = -0.119570f;
+ 	val_dir[9931*3 + 0] = 0.977577f;	val_dir[9931*3 + 1] = 0.195515f;	val_dir[9931*3 + 2] = -0.078206f;
+ 	val_dir[9932*3 + 0] = 0.976804f;	val_dir[9932*3 + 1] = 0.210683f;	val_dir[9932*3 + 2] = -0.038306f;
+ 	val_dir[9933*3 + 0] = 0.974391f;	val_dir[9933*3 + 1] = 0.224860f;	val_dir[9933*3 + 2] = 0.0f;
+ 	val_dir[9934*3 + 0] = -0.228998f;	val_dir[9934*3 + 1] = -0.973240f;	val_dir[9934*3 + 2] = -0.019083f;
+ 	val_dir[9935*3 + 0] = -0.214494f;	val_dir[9935*3 + 1] = -0.974972f;	val_dir[9935*3 + 2] = -0.058498f;
+ 	val_dir[9936*3 + 0] = -0.198968f;	val_dir[9936*3 + 1] = -0.974943f;	val_dir[9936*3 + 2] = -0.099484f;
+ 	val_dir[9937*3 + 0] = -0.182424f;	val_dir[9937*3 + 1] = -0.972929f;	val_dir[9937*3 + 2] = -0.141885f;
+ 	val_dir[9938*3 + 0] = -0.164887f;	val_dir[9938*3 + 1] = -0.968712f;	val_dir[9938*3 + 2] = -0.185498f;
+ 	val_dir[9939*3 + 0] = -0.146406f;	val_dir[9939*3 + 1] = -0.962099f;	val_dir[9939*3 + 2] = -0.230067f;
+ 	val_dir[9940*3 + 0] = -0.127057f;	val_dir[9940*3 + 1] = -0.952928f;	val_dir[9940*3 + 2] = -0.275290f;
+ 	val_dir[9941*3 + 0] = -0.106941f;	val_dir[9941*3 + 1] = -0.941082f;	val_dir[9941*3 + 2] = -0.320824f;
+ 	val_dir[9942*3 + 0] = -0.086186f;	val_dir[9942*3 + 1] = -0.92650f;	val_dir[9942*3 + 2] = -0.366291f;
+ 	val_dir[9943*3 + 0] = -0.064942f;	val_dir[9943*3 + 1] = -0.909185f;	val_dir[9943*3 + 2] = -0.411298f;
+ 	val_dir[9944*3 + 0] = -0.043376f;	val_dir[9944*3 + 1] = -0.889206f;	val_dir[9944*3 + 2] = -0.455447f;
+ 	val_dir[9945*3 + 0] = -0.021668f;	val_dir[9945*3 + 1] = -0.866703f;	val_dir[9945*3 + 2] = -0.498354f;
+ 	val_dir[9946*3 + 0] = 0.0f;	val_dir[9946*3 + 1] = -0.841879f;	val_dir[9946*3 + 2] = -0.539666f;
+ 	val_dir[9947*3 + 0] = 0.021979f;	val_dir[9947*3 + 1] = -0.835215f;	val_dir[9947*3 + 2] = -0.549484f;
+ 	val_dir[9948*3 + 0] = 0.044744f;	val_dir[9948*3 + 1] = -0.827759f;	val_dir[9948*3 + 2] = -0.559297f;
+ 	val_dir[9949*3 + 0] = 0.068288f;	val_dir[9949*3 + 1] = -0.819453f;	val_dir[9949*3 + 2] = -0.569064f;
+ 	val_dir[9950*3 + 0] = 0.092599f;	val_dir[9950*3 + 1] = -0.810237f;	val_dir[9950*3 + 2] = -0.578741f;
+ 	val_dir[9951*3 + 0] = 0.117655f;	val_dir[9951*3 + 1] = -0.800055f;	val_dir[9951*3 + 2] = -0.588276f;
+ 	val_dir[9952*3 + 0] = 0.143427f;	val_dir[9952*3 + 1] = -0.788851f;	val_dir[9952*3 + 2] = -0.597614f;
+ 	val_dir[9953*3 + 0] = 0.169875f;	val_dir[9953*3 + 1] = -0.776571f;	val_dir[9953*3 + 2] = -0.606696f;
+ 	val_dir[9954*3 + 0] = 0.196946f;	val_dir[9954*3 + 1] = -0.763167f;	val_dir[9954*3 + 2] = -0.615457f;
+ 	val_dir[9955*3 + 0] = 0.224579f;	val_dir[9955*3 + 1] = -0.748598f;	val_dir[9955*3 + 2] = -0.623831f;
+ 	val_dir[9956*3 + 0] = 0.252699f;	val_dir[9956*3 + 1] = -0.732828f;	val_dir[9956*3 + 2] = -0.631748f;
+ 	val_dir[9957*3 + 0] = 0.281220f;	val_dir[9957*3 + 1] = -0.715834f;	val_dir[9957*3 + 2] = -0.639138f;
+ 	val_dir[9958*3 + 0] = 0.310045f;	val_dir[9958*3 + 1] = -0.697602f;	val_dir[9958*3 + 2] = -0.645928f;
+ 	val_dir[9959*3 + 0] = 0.339066f;	val_dir[9959*3 + 1] = -0.678133f;	val_dir[9959*3 + 2] = -0.652051f;
+ 	val_dir[9960*3 + 0] = 0.368166f;	val_dir[9960*3 + 1] = -0.657440f;	val_dir[9960*3 + 2] = -0.657440f;
+ 	val_dir[9961*3 + 0] = 0.397220f;	val_dir[9961*3 + 1] = -0.635553f;	val_dir[9961*3 + 2] = -0.662034f;
+ 	val_dir[9962*3 + 0] = 0.426099f;	val_dir[9962*3 + 1] = -0.612517f;	val_dir[9962*3 + 2] = -0.665780f;
+ 	val_dir[9963*3 + 0] = 0.454669f;	val_dir[9963*3 + 1] = -0.588395f;	val_dir[9963*3 + 2] = -0.668631f;
+ 	val_dir[9964*3 + 0] = 0.482798f;	val_dir[9964*3 + 1] = -0.563264f;	val_dir[9964*3 + 2] = -0.670552f;
+ 	val_dir[9965*3 + 0] = 0.510355f;	val_dir[9965*3 + 1] = -0.537215f;	val_dir[9965*3 + 2] = -0.671519f;
+ 	val_dir[9966*3 + 0] = 0.537215f;	val_dir[9966*3 + 1] = -0.510355f;	val_dir[9966*3 + 2] = -0.671519f;
+ 	val_dir[9967*3 + 0] = 0.563264f;	val_dir[9967*3 + 1] = -0.482798f;	val_dir[9967*3 + 2] = -0.670552f;
+ 	val_dir[9968*3 + 0] = 0.588395f;	val_dir[9968*3 + 1] = -0.454669f;	val_dir[9968*3 + 2] = -0.668631f;
+ 	val_dir[9969*3 + 0] = 0.612517f;	val_dir[9969*3 + 1] = -0.426099f;	val_dir[9969*3 + 2] = -0.665780f;
+ 	val_dir[9970*3 + 0] = 0.635553f;	val_dir[9970*3 + 1] = -0.397220f;	val_dir[9970*3 + 2] = -0.662034f;
+ 	val_dir[9971*3 + 0] = 0.657440f;	val_dir[9971*3 + 1] = -0.368166f;	val_dir[9971*3 + 2] = -0.657440f;
+ 	val_dir[9972*3 + 0] = 0.678133f;	val_dir[9972*3 + 1] = -0.339066f;	val_dir[9972*3 + 2] = -0.652051f;
+ 	val_dir[9973*3 + 0] = 0.697602f;	val_dir[9973*3 + 1] = -0.310045f;	val_dir[9973*3 + 2] = -0.645928f;
+ 	val_dir[9974*3 + 0] = 0.715834f;	val_dir[9974*3 + 1] = -0.281220f;	val_dir[9974*3 + 2] = -0.639138f;
+ 	val_dir[9975*3 + 0] = 0.732828f;	val_dir[9975*3 + 1] = -0.252699f;	val_dir[9975*3 + 2] = -0.631748f;
+ 	val_dir[9976*3 + 0] = 0.748598f;	val_dir[9976*3 + 1] = -0.224579f;	val_dir[9976*3 + 2] = -0.623831f;
+ 	val_dir[9977*3 + 0] = 0.763167f;	val_dir[9977*3 + 1] = -0.196946f;	val_dir[9977*3 + 2] = -0.615457f;
+ 	val_dir[9978*3 + 0] = 0.776571f;	val_dir[9978*3 + 1] = -0.169875f;	val_dir[9978*3 + 2] = -0.606696f;
+ 	val_dir[9979*3 + 0] = 0.788851f;	val_dir[9979*3 + 1] = -0.143427f;	val_dir[9979*3 + 2] = -0.597614f;
+ 	val_dir[9980*3 + 0] = 0.800055f;	val_dir[9980*3 + 1] = -0.117655f;	val_dir[9980*3 + 2] = -0.588276f;
+ 	val_dir[9981*3 + 0] = 0.810237f;	val_dir[9981*3 + 1] = -0.092599f;	val_dir[9981*3 + 2] = -0.578741f;
+ 	val_dir[9982*3 + 0] = 0.819453f;	val_dir[9982*3 + 1] = -0.068288f;	val_dir[9982*3 + 2] = -0.569064f;
+ 	val_dir[9983*3 + 0] = 0.827759f;	val_dir[9983*3 + 1] = -0.044744f;	val_dir[9983*3 + 2] = -0.559297f;
+ 	val_dir[9984*3 + 0] = 0.835215f;	val_dir[9984*3 + 1] = -0.021979f;	val_dir[9984*3 + 2] = -0.549484f;
+ 	val_dir[9985*3 + 0] = 0.841879f;	val_dir[9985*3 + 1] = 0.0f;	val_dir[9985*3 + 2] = -0.539666f;
+ 	val_dir[9986*3 + 0] = 0.866703f;	val_dir[9986*3 + 1] = 0.021668f;	val_dir[9986*3 + 2] = -0.498354f;
+ 	val_dir[9987*3 + 0] = 0.889206f;	val_dir[9987*3 + 1] = 0.043376f;	val_dir[9987*3 + 2] = -0.455447f;
+ 	val_dir[9988*3 + 0] = 0.909185f;	val_dir[9988*3 + 1] = 0.064942f;	val_dir[9988*3 + 2] = -0.411298f;
+ 	val_dir[9989*3 + 0] = 0.92650f;	val_dir[9989*3 + 1] = 0.086186f;	val_dir[9989*3 + 2] = -0.366291f;
+ 	val_dir[9990*3 + 0] = 0.941082f;	val_dir[9990*3 + 1] = 0.106941f;	val_dir[9990*3 + 2] = -0.320824f;
+ 	val_dir[9991*3 + 0] = 0.952928f;	val_dir[9991*3 + 1] = 0.127057f;	val_dir[9991*3 + 2] = -0.275290f;
+ 	val_dir[9992*3 + 0] = 0.962099f;	val_dir[9992*3 + 1] = 0.146406f;	val_dir[9992*3 + 2] = -0.230067f;
+ 	val_dir[9993*3 + 0] = 0.968712f;	val_dir[9993*3 + 1] = 0.164887f;	val_dir[9993*3 + 2] = -0.185498f;
+ 	val_dir[9994*3 + 0] = 0.972929f;	val_dir[9994*3 + 1] = 0.182424f;	val_dir[9994*3 + 2] = -0.141885f;
+ 	val_dir[9995*3 + 0] = 0.974943f;	val_dir[9995*3 + 1] = 0.198968f;	val_dir[9995*3 + 2] = -0.099484f;
+ 	val_dir[9996*3 + 0] = 0.974972f;	val_dir[9996*3 + 1] = 0.214494f;	val_dir[9996*3 + 2] = -0.058498f;
+ 	val_dir[9997*3 + 0] = 0.973240f;	val_dir[9997*3 + 1] = 0.228998f;	val_dir[9997*3 + 2] = -0.019083f;
+ 	val_dir[9998*3 + 0] = -0.247004f;	val_dir[9998*3 + 1] = -0.969015f;	val_dir[9998*3 + 2] = 0.0f;
+ 	val_dir[9999*3 + 0] = -0.233197f;	val_dir[9999*3 + 1] = -0.971653f;	val_dir[9999*3 + 2] = -0.038866f;
+ 	val_dir[10000*3 + 0] = -0.218347f;	val_dir[10000*3 + 1] = -0.972636f;	val_dir[10000*3 + 2] = -0.079399f;
+ 	val_dir[10001*3 + 0] = -0.202444f;	val_dir[10001*3 + 1] = -0.971732f;	val_dir[10001*3 + 2] = -0.121466f;
+ 	val_dir[10002*3 + 0] = -0.185498f;	val_dir[10002*3 + 1] = -0.968712f;	val_dir[10002*3 + 2] = -0.164887f;
+ 	val_dir[10003*3 + 0] = -0.167542f;	val_dir[10003*3 + 1] = -0.963364f;	val_dir[10003*3 + 2] = -0.209427f;
+ 	val_dir[10004*3 + 0] = -0.148634f;	val_dir[10004*3 + 1] = -0.955502f;	val_dir[10004*3 + 2] = -0.254801f;
+ 	val_dir[10005*3 + 0] = -0.128861f;	val_dir[10005*3 + 1] = -0.944981f;	val_dir[10005*3 + 2] = -0.300676f;
+ 	val_dir[10006*3 + 0] = -0.108338f;	val_dir[10006*3 + 1] = -0.931705f;	val_dir[10006*3 + 2] = -0.346681f;
+ 	val_dir[10007*3 + 0] = -0.087204f;	val_dir[10007*3 + 1] = -0.915644f;	val_dir[10007*3 + 2] = -0.392419f;
+ 	val_dir[10008*3 + 0] = -0.065622f;	val_dir[10008*3 + 1] = -0.896831f;	val_dir[10008*3 + 2] = -0.437479f;
+ 	val_dir[10009*3 + 0] = -0.043769f;	val_dir[10009*3 + 1] = -0.875376f;	val_dir[10009*3 + 2] = -0.481457f;
+ 	val_dir[10010*3 + 0] = -0.021832f;	val_dir[10010*3 + 1] = -0.851455f;	val_dir[10010*3 + 2] = -0.523973f;
+ 	val_dir[10011*3 + 0] = 0.0f;	val_dir[10011*3 + 1] = -0.825307f;	val_dir[10011*3 + 2] = -0.564684f;
+ 	val_dir[10012*3 + 0] = 0.022108f;	val_dir[10012*3 + 1] = -0.817992f;	val_dir[10012*3 + 2] = -0.574805f;
+ 	val_dir[10013*3 + 0] = 0.044992f;	val_dir[10013*3 + 1] = -0.809858f;	val_dir[10013*3 + 2] = -0.584898f;
+ 	val_dir[10014*3 + 0] = 0.068644f;	val_dir[10014*3 + 1] = -0.800850f;	val_dir[10014*3 + 2] = -0.594917f;
+ 	val_dir[10015*3 + 0] = 0.093048f;	val_dir[10015*3 + 1] = -0.790912f;	val_dir[10015*3 + 2] = -0.604815f;
+ 	val_dir[10016*3 + 0] = 0.118180f;	val_dir[10016*3 + 1] = -0.779987f;	val_dir[10016*3 + 2] = -0.614535f;
+ 	val_dir[10017*3 + 0] = 0.144005f;	val_dir[10017*3 + 1] = -0.768025f;	val_dir[10017*3 + 2] = -0.624020f;
+ 	val_dir[10018*3 + 0] = 0.170478f;	val_dir[10018*3 + 1] = -0.754976f;	val_dir[10018*3 + 2] = -0.633205f;
+ 	val_dir[10019*3 + 0] = 0.197546f;	val_dir[10019*3 + 1] = -0.740797f;	val_dir[10019*3 + 2] = -0.642024f;
+ 	val_dir[10020*3 + 0] = 0.225141f;	val_dir[10020*3 + 1] = -0.725454f;	val_dir[10020*3 + 2] = -0.650407f;
+ 	val_dir[10021*3 + 0] = 0.253185f;	val_dir[10021*3 + 1] = -0.708918f;	val_dir[10021*3 + 2] = -0.658281f;
+ 	val_dir[10022*3 + 0] = 0.281589f;	val_dir[10022*3 + 1] = -0.691173f;	val_dir[10022*3 + 2] = -0.665574f;
+ 	val_dir[10023*3 + 0] = 0.310253f;	val_dir[10023*3 + 1] = -0.672214f;	val_dir[10023*3 + 2] = -0.672214f;
+ 	val_dir[10024*3 + 0] = 0.339066f;	val_dir[10024*3 + 1] = -0.652051f;	val_dir[10024*3 + 2] = -0.678133f;
+ 	val_dir[10025*3 + 0] = 0.367912f;	val_dir[10025*3 + 1] = -0.630706f;	val_dir[10025*3 + 2] = -0.683265f;
+ 	val_dir[10026*3 + 0] = 0.396664f;	val_dir[10026*3 + 1] = -0.608219f;	val_dir[10026*3 + 2] = -0.687552f;
+ 	val_dir[10027*3 + 0] = 0.425195f;	val_dir[10027*3 + 1] = -0.584643f;	val_dir[10027*3 + 2] = -0.690942f;
+ 	val_dir[10028*3 + 0] = 0.453374f;	val_dir[10028*3 + 1] = -0.560050f;	val_dir[10028*3 + 2] = -0.693395f;
+ 	val_dir[10029*3 + 0] = 0.481070f;	val_dir[10029*3 + 1] = -0.534522f;	val_dir[10029*3 + 2] = -0.694879f;
+ 	val_dir[10030*3 + 0] = 0.508159f;	val_dir[10030*3 + 1] = -0.508159f;	val_dir[10030*3 + 2] = -0.695376f;
+ 	val_dir[10031*3 + 0] = 0.534522f;	val_dir[10031*3 + 1] = -0.481070f;	val_dir[10031*3 + 2] = -0.694879f;
+ 	val_dir[10032*3 + 0] = 0.560050f;	val_dir[10032*3 + 1] = -0.453374f;	val_dir[10032*3 + 2] = -0.693395f;
+ 	val_dir[10033*3 + 0] = 0.584643f;	val_dir[10033*3 + 1] = -0.425195f;	val_dir[10033*3 + 2] = -0.690942f;
+ 	val_dir[10034*3 + 0] = 0.608219f;	val_dir[10034*3 + 1] = -0.396664f;	val_dir[10034*3 + 2] = -0.687552f;
+ 	val_dir[10035*3 + 0] = 0.630706f;	val_dir[10035*3 + 1] = -0.367912f;	val_dir[10035*3 + 2] = -0.683265f;
+ 	val_dir[10036*3 + 0] = 0.652051f;	val_dir[10036*3 + 1] = -0.339066f;	val_dir[10036*3 + 2] = -0.678133f;
+ 	val_dir[10037*3 + 0] = 0.672214f;	val_dir[10037*3 + 1] = -0.310253f;	val_dir[10037*3 + 2] = -0.672214f;
+ 	val_dir[10038*3 + 0] = 0.691173f;	val_dir[10038*3 + 1] = -0.281589f;	val_dir[10038*3 + 2] = -0.665574f;
+ 	val_dir[10039*3 + 0] = 0.708918f;	val_dir[10039*3 + 1] = -0.253185f;	val_dir[10039*3 + 2] = -0.658281f;
+ 	val_dir[10040*3 + 0] = 0.725454f;	val_dir[10040*3 + 1] = -0.225141f;	val_dir[10040*3 + 2] = -0.650407f;
+ 	val_dir[10041*3 + 0] = 0.740797f;	val_dir[10041*3 + 1] = -0.197546f;	val_dir[10041*3 + 2] = -0.642024f;
+ 	val_dir[10042*3 + 0] = 0.754976f;	val_dir[10042*3 + 1] = -0.170478f;	val_dir[10042*3 + 2] = -0.633205f;
+ 	val_dir[10043*3 + 0] = 0.768025f;	val_dir[10043*3 + 1] = -0.144005f;	val_dir[10043*3 + 2] = -0.624020f;
+ 	val_dir[10044*3 + 0] = 0.779987f;	val_dir[10044*3 + 1] = -0.118180f;	val_dir[10044*3 + 2] = -0.614535f;
+ 	val_dir[10045*3 + 0] = 0.790912f;	val_dir[10045*3 + 1] = -0.093048f;	val_dir[10045*3 + 2] = -0.604815f;
+ 	val_dir[10046*3 + 0] = 0.800850f;	val_dir[10046*3 + 1] = -0.068644f;	val_dir[10046*3 + 2] = -0.594917f;
+ 	val_dir[10047*3 + 0] = 0.809858f;	val_dir[10047*3 + 1] = -0.044992f;	val_dir[10047*3 + 2] = -0.584898f;
+ 	val_dir[10048*3 + 0] = 0.817992f;	val_dir[10048*3 + 1] = -0.022108f;	val_dir[10048*3 + 2] = -0.574805f;
+ 	val_dir[10049*3 + 0] = 0.825307f;	val_dir[10049*3 + 1] = 0.0f;	val_dir[10049*3 + 2] = -0.564684f;
+ 	val_dir[10050*3 + 0] = 0.851455f;	val_dir[10050*3 + 1] = 0.021832f;	val_dir[10050*3 + 2] = -0.523973f;
+ 	val_dir[10051*3 + 0] = 0.875376f;	val_dir[10051*3 + 1] = 0.043769f;	val_dir[10051*3 + 2] = -0.481457f;
+ 	val_dir[10052*3 + 0] = 0.896831f;	val_dir[10052*3 + 1] = 0.065622f;	val_dir[10052*3 + 2] = -0.437479f;
+ 	val_dir[10053*3 + 0] = 0.915644f;	val_dir[10053*3 + 1] = 0.087204f;	val_dir[10053*3 + 2] = -0.392419f;
+ 	val_dir[10054*3 + 0] = 0.931705f;	val_dir[10054*3 + 1] = 0.108338f;	val_dir[10054*3 + 2] = -0.346681f;
+ 	val_dir[10055*3 + 0] = 0.944981f;	val_dir[10055*3 + 1] = 0.128861f;	val_dir[10055*3 + 2] = -0.300676f;
+ 	val_dir[10056*3 + 0] = 0.955502f;	val_dir[10056*3 + 1] = 0.148634f;	val_dir[10056*3 + 2] = -0.254801f;
+ 	val_dir[10057*3 + 0] = 0.963364f;	val_dir[10057*3 + 1] = 0.167542f;	val_dir[10057*3 + 2] = -0.209427f;
+ 	val_dir[10058*3 + 0] = 0.968712f;	val_dir[10058*3 + 1] = 0.185498f;	val_dir[10058*3 + 2] = -0.164887f;
+ 	val_dir[10059*3 + 0] = 0.971732f;	val_dir[10059*3 + 1] = 0.202444f;	val_dir[10059*3 + 2] = -0.121466f;
+ 	val_dir[10060*3 + 0] = 0.972636f;	val_dir[10060*3 + 1] = 0.218347f;	val_dir[10060*3 + 2] = -0.079399f;
+ 	val_dir[10061*3 + 0] = 0.971653f;	val_dir[10061*3 + 1] = 0.233197f;	val_dir[10061*3 + 2] = -0.038866f;
+ 	val_dir[10062*3 + 0] = 0.969015f;	val_dir[10062*3 + 1] = 0.247004f;	val_dir[10062*3 + 2] = 0.0f;
+ 	val_dir[10063*3 + 0] = -0.251587f;	val_dir[10063*3 + 1] = -0.967641f;	val_dir[10063*3 + 2] = -0.019353f;
+ 	val_dir[10064*3 + 0] = -0.237449f;	val_dir[10064*3 + 1] = -0.969584f;	val_dir[10064*3 + 2] = -0.059362f;
+ 	val_dir[10065*3 + 0] = -0.222234f;	val_dir[10065*3 + 1] = -0.969746f;	val_dir[10065*3 + 2] = -0.101015f;
+ 	val_dir[10066*3 + 0] = -0.205934f;	val_dir[10066*3 + 1] = -0.967890f;	val_dir[10066*3 + 2] = -0.144154f;
+ 	val_dir[10067*3 + 0] = -0.188567f;	val_dir[10067*3 + 1] = -0.963787f;	val_dir[10067*3 + 2] = -0.188567f;
+ 	val_dir[10068*3 + 0] = -0.170174f;	val_dir[10068*3 + 1] = -0.957230f;	val_dir[10068*3 + 2] = -0.233990f;
+ 	val_dir[10069*3 + 0] = -0.150826f;	val_dir[10069*3 + 1] = -0.948047f;	val_dir[10069*3 + 2] = -0.280105f;
+ 	val_dir[10070*3 + 0] = -0.130620f;	val_dir[10070*3 + 1] = -0.936111f;	val_dir[10070*3 + 2] = -0.326550f;
+ 	val_dir[10071*3 + 0] = -0.109685f;	val_dir[10071*3 + 1] = -0.921354f;	val_dir[10071*3 + 2] = -0.372929f;
+ 	val_dir[10072*3 + 0] = -0.088173f;	val_dir[10072*3 + 1] = -0.903777f;	val_dir[10072*3 + 2] = -0.418823f;
+ 	val_dir[10073*3 + 0] = -0.066259f;	val_dir[10073*3 + 1] = -0.883452f;	val_dir[10073*3 + 2] = -0.463812f;
+ 	val_dir[10074*3 + 0] = -0.044130f;	val_dir[10074*3 + 1] = -0.860527f;	val_dir[10074*3 + 2] = -0.507490f;
+ 	val_dir[10075*3 + 0] = -0.021979f;	val_dir[10075*3 + 1] = -0.835215f;	val_dir[10075*3 + 2] = -0.549484f;
+ 	val_dir[10076*3 + 0] = 0.0f;	val_dir[10076*3 + 1] = -0.807791f;	val_dir[10076*3 + 2] = -0.589469f;
+ 	val_dir[10077*3 + 0] = 0.022217f;	val_dir[10077*3 + 1] = -0.799803f;	val_dir[10077*3 + 2] = -0.599852f;
+ 	val_dir[10078*3 + 0] = 0.045198f;	val_dir[10078*3 + 1] = -0.790973f;	val_dir[10078*3 + 2] = -0.610179f;
+ 	val_dir[10079*3 + 0] = 0.068934f;	val_dir[10079*3 + 1] = -0.781248f;	val_dir[10079*3 + 2] = -0.620403f;
+ 	val_dir[10080*3 + 0] = 0.093403f;	val_dir[10080*3 + 1] = -0.770574f;	val_dir[10080*3 + 2] = -0.630470f;
+ 	val_dir[10081*3 + 0] = 0.118578f;	val_dir[10081*3 + 1] = -0.758899f;	val_dir[10081*3 + 2] = -0.640321f;
+ 	val_dir[10082*3 + 0] = 0.144421f;	val_dir[10082*3 + 1] = -0.746176f;	val_dir[10082*3 + 2] = -0.649895f;
+ 	val_dir[10083*3 + 0] = 0.170884f;	val_dir[10083*3 + 1] = -0.732361f;	val_dir[10083*3 + 2] = -0.659125f;
+ 	val_dir[10084*3 + 0] = 0.197908f;	val_dir[10084*3 + 1] = -0.717418f;	val_dir[10084*3 + 2] = -0.667940f;
+ 	val_dir[10085*3 + 0] = 0.225423f;	val_dir[10085*3 + 1] = -0.701316f;	val_dir[10085*3 + 2] = -0.676269f;
+ 	val_dir[10086*3 + 0] = 0.253347f;	val_dir[10086*3 + 1] = -0.684038f;	val_dir[10086*3 + 2] = -0.684038f;
+ 	val_dir[10087*3 + 0] = 0.281589f;	val_dir[10087*3 + 1] = -0.665574f;	val_dir[10087*3 + 2] = -0.691173f;
+ 	val_dir[10088*3 + 0] = 0.310045f;	val_dir[10088*3 + 1] = -0.645928f;	val_dir[10088*3 + 2] = -0.697602f;
+ 	val_dir[10089*3 + 0] = 0.338606f;	val_dir[10089*3 + 1] = -0.625119f;	val_dir[10089*3 + 2] = -0.703259f;
+ 	val_dir[10090*3 + 0] = 0.367152f;	val_dir[10090*3 + 1] = -0.603178f;	val_dir[10090*3 + 2] = -0.708079f;
+ 	val_dir[10091*3 + 0] = 0.395559f;	val_dir[10091*3 + 1] = -0.580154f;	val_dir[10091*3 + 2] = -0.712007f;
+ 	val_dir[10092*3 + 0] = 0.423702f;	val_dir[10092*3 + 1] = -0.556108f;	val_dir[10092*3 + 2] = -0.714997f;
+ 	val_dir[10093*3 + 0] = 0.451451f;	val_dir[10093*3 + 1] = -0.531119f;	val_dir[10093*3 + 2] = -0.717011f;
+ 	val_dir[10094*3 + 0] = 0.478683f;	val_dir[10094*3 + 1] = -0.505276f;	val_dir[10094*3 + 2] = -0.718024f;
+ 	val_dir[10095*3 + 0] = 0.505276f;	val_dir[10095*3 + 1] = -0.478683f;	val_dir[10095*3 + 2] = -0.718024f;
+ 	val_dir[10096*3 + 0] = 0.531119f;	val_dir[10096*3 + 1] = -0.451451f;	val_dir[10096*3 + 2] = -0.717011f;
+ 	val_dir[10097*3 + 0] = 0.556108f;	val_dir[10097*3 + 1] = -0.423702f;	val_dir[10097*3 + 2] = -0.714997f;
+ 	val_dir[10098*3 + 0] = 0.580154f;	val_dir[10098*3 + 1] = -0.395559f;	val_dir[10098*3 + 2] = -0.712007f;
+ 	val_dir[10099*3 + 0] = 0.603178f;	val_dir[10099*3 + 1] = -0.367152f;	val_dir[10099*3 + 2] = -0.708079f;
+ 	val_dir[10100*3 + 0] = 0.625119f;	val_dir[10100*3 + 1] = -0.338606f;	val_dir[10100*3 + 2] = -0.703259f;
+ 	val_dir[10101*3 + 0] = 0.645928f;	val_dir[10101*3 + 1] = -0.310045f;	val_dir[10101*3 + 2] = -0.697602f;
+ 	val_dir[10102*3 + 0] = 0.665574f;	val_dir[10102*3 + 1] = -0.281589f;	val_dir[10102*3 + 2] = -0.691173f;
+ 	val_dir[10103*3 + 0] = 0.684038f;	val_dir[10103*3 + 1] = -0.253347f;	val_dir[10103*3 + 2] = -0.684038f;
+ 	val_dir[10104*3 + 0] = 0.701316f;	val_dir[10104*3 + 1] = -0.225423f;	val_dir[10104*3 + 2] = -0.676269f;
+ 	val_dir[10105*3 + 0] = 0.717418f;	val_dir[10105*3 + 1] = -0.197908f;	val_dir[10105*3 + 2] = -0.667940f;
+ 	val_dir[10106*3 + 0] = 0.732361f;	val_dir[10106*3 + 1] = -0.170884f;	val_dir[10106*3 + 2] = -0.659125f;
+ 	val_dir[10107*3 + 0] = 0.746176f;	val_dir[10107*3 + 1] = -0.144421f;	val_dir[10107*3 + 2] = -0.649895f;
+ 	val_dir[10108*3 + 0] = 0.758899f;	val_dir[10108*3 + 1] = -0.118578f;	val_dir[10108*3 + 2] = -0.640321f;
+ 	val_dir[10109*3 + 0] = 0.770574f;	val_dir[10109*3 + 1] = -0.093403f;	val_dir[10109*3 + 2] = -0.630470f;
+ 	val_dir[10110*3 + 0] = 0.781248f;	val_dir[10110*3 + 1] = -0.068934f;	val_dir[10110*3 + 2] = -0.620403f;
+ 	val_dir[10111*3 + 0] = 0.790973f;	val_dir[10111*3 + 1] = -0.045198f;	val_dir[10111*3 + 2] = -0.610179f;
+ 	val_dir[10112*3 + 0] = 0.799803f;	val_dir[10112*3 + 1] = -0.022217f;	val_dir[10112*3 + 2] = -0.599852f;
+ 	val_dir[10113*3 + 0] = 0.807791f;	val_dir[10113*3 + 1] = 0.0f;	val_dir[10113*3 + 2] = -0.589469f;
+ 	val_dir[10114*3 + 0] = 0.835215f;	val_dir[10114*3 + 1] = 0.021979f;	val_dir[10114*3 + 2] = -0.549484f;
+ 	val_dir[10115*3 + 0] = 0.860527f;	val_dir[10115*3 + 1] = 0.044130f;	val_dir[10115*3 + 2] = -0.507490f;
+ 	val_dir[10116*3 + 0] = 0.883452f;	val_dir[10116*3 + 1] = 0.066259f;	val_dir[10116*3 + 2] = -0.463812f;
+ 	val_dir[10117*3 + 0] = 0.903777f;	val_dir[10117*3 + 1] = 0.088173f;	val_dir[10117*3 + 2] = -0.418823f;
+ 	val_dir[10118*3 + 0] = 0.921354f;	val_dir[10118*3 + 1] = 0.109685f;	val_dir[10118*3 + 2] = -0.372929f;
+ 	val_dir[10119*3 + 0] = 0.936111f;	val_dir[10119*3 + 1] = 0.130620f;	val_dir[10119*3 + 2] = -0.326550f;
+ 	val_dir[10120*3 + 0] = 0.948047f;	val_dir[10120*3 + 1] = 0.150826f;	val_dir[10120*3 + 2] = -0.280105f;
+ 	val_dir[10121*3 + 0] = 0.957230f;	val_dir[10121*3 + 1] = 0.170174f;	val_dir[10121*3 + 2] = -0.233990f;
+ 	val_dir[10122*3 + 0] = 0.963787f;	val_dir[10122*3 + 1] = 0.188567f;	val_dir[10122*3 + 2] = -0.188567f;
+ 	val_dir[10123*3 + 0] = 0.967890f;	val_dir[10123*3 + 1] = 0.205934f;	val_dir[10123*3 + 2] = -0.144154f;
+ 	val_dir[10124*3 + 0] = 0.969746f;	val_dir[10124*3 + 1] = 0.222234f;	val_dir[10124*3 + 2] = -0.101015f;
+ 	val_dir[10125*3 + 0] = 0.969584f;	val_dir[10125*3 + 1] = 0.237449f;	val_dir[10125*3 + 2] = -0.059362f;
+ 	val_dir[10126*3 + 0] = 0.967641f;	val_dir[10126*3 + 1] = 0.251587f;	val_dir[10126*3 + 2] = -0.019353f;
+ 	val_dir[10127*3 + 0] = -0.269630f;	val_dir[10127*3 + 1] = -0.962964f;	val_dir[10127*3 + 2] = 0.0f;
+ 	val_dir[10128*3 + 0] = -0.256235f;	val_dir[10128*3 + 1] = -0.965810f;	val_dir[10128*3 + 2] = -0.039421f;
+ 	val_dir[10129*3 + 0] = -0.241747f;	val_dir[10129*3 + 1] = -0.966988f;	val_dir[10129*3 + 2] = -0.080582f;
+ 	val_dir[10130*3 + 0] = -0.226144f;	val_dir[10130*3 + 1] = -0.966252f;	val_dir[10130*3 + 2] = -0.123351f;
+ 	val_dir[10131*3 + 0] = -0.209427f;	val_dir[10131*3 + 1] = -0.963364f;	val_dir[10131*3 + 2] = -0.167542f;
+ 	val_dir[10132*3 + 0] = -0.191620f;	val_dir[10132*3 + 1] = -0.958098f;	val_dir[10132*3 + 2] = -0.212911f;
+ 	val_dir[10133*3 + 0] = -0.172774f;	val_dir[10133*3 + 1] = -0.950255f;	val_dir[10133*3 + 2] = -0.259161f;
+ 	val_dir[10134*3 + 0] = -0.152971f;	val_dir[10134*3 + 1] = -0.939680f;	val_dir[10134*3 + 2] = -0.305942f;
+ 	val_dir[10135*3 + 0] = -0.132324f;	val_dir[10135*3 + 1] = -0.926270f;	val_dir[10135*3 + 2] = -0.352865f;
+ 	val_dir[10136*3 + 0] = -0.110974f;	val_dir[10136*3 + 1] = -0.909988f;	val_dir[10136*3 + 2] = -0.399507f;
+ 	val_dir[10137*3 + 0] = -0.089087f;	val_dir[10137*3 + 1] = -0.890871f;	val_dir[10137*3 + 2] = -0.445435f;
+ 	val_dir[10138*3 + 0] = -0.066848f;	val_dir[10138*3 + 1] = -0.869030f;	val_dir[10138*3 + 2] = -0.490222f;
+ 	val_dir[10139*3 + 0] = -0.044455f;	val_dir[10139*3 + 1] = -0.844653f;	val_dir[10139*3 + 2] = -0.533465f;
+ 	val_dir[10140*3 + 0] = -0.022108f;	val_dir[10140*3 + 1] = -0.817992f;	val_dir[10140*3 + 2] = -0.574805f;
+ 	val_dir[10141*3 + 0] = 0.0f;	val_dir[10141*3 + 1] = -0.789352f;	val_dir[10141*3 + 2] = -0.613941f;
+ 	val_dir[10142*3 + 0] = 0.022305f;	val_dir[10142*3 + 1] = -0.780675f;	val_dir[10142*3 + 2] = -0.624540f;
+ 	val_dir[10143*3 + 0] = 0.045361f;	val_dir[10143*3 + 1] = -0.771136f;	val_dir[10143*3 + 2] = -0.635053f;
+ 	val_dir[10144*3 + 0] = 0.069153f;	val_dir[10144*3 + 1] = -0.760684f;	val_dir[10144*3 + 2] = -0.645429f;
+ 	val_dir[10145*3 + 0] = 0.093659f;	val_dir[10145*3 + 1] = -0.749269f;	val_dir[10145*3 + 2] = -0.655610f;
+ 	val_dir[10146*3 + 0] = 0.118846f;	val_dir[10146*3 + 1] = -0.736843f;	val_dir[10146*3 + 2] = -0.665536f;
+ 	val_dir[10147*3 + 0] = 0.144673f;	val_dir[10147*3 + 1] = -0.723364f;	val_dir[10147*3 + 2] = -0.675140f;
+ 	val_dir[10148*3 + 0] = 0.171088f;	val_dir[10148*3 + 1] = -0.708794f;	val_dir[10148*3 + 2] = -0.684353f;
+ 	val_dir[10149*3 + 0] = 0.198030f;	val_dir[10149*3 + 1] = -0.693103f;	val_dir[10149*3 + 2] = -0.693103f;
+ 	val_dir[10150*3 + 0] = 0.225423f;	val_dir[10150*3 + 1] = -0.676269f;	val_dir[10150*3 + 2] = -0.701316f;
+ 	val_dir[10151*3 + 0] = 0.253185f;	val_dir[10151*3 + 1] = -0.658281f;	val_dir[10151*3 + 2] = -0.708918f;
+ 	val_dir[10152*3 + 0] = 0.281220f;	val_dir[10152*3 + 1] = -0.639138f;	val_dir[10152*3 + 2] = -0.715834f;
+ 	val_dir[10153*3 + 0] = 0.309426f;	val_dir[10153*3 + 1] = -0.618853f;	val_dir[10153*3 + 2] = -0.721995f;
+ 	val_dir[10154*3 + 0] = 0.337691f;	val_dir[10154*3 + 1] = -0.597453f;	val_dir[10154*3 + 2] = -0.727334f;
+ 	val_dir[10155*3 + 0] = 0.365896f;	val_dir[10155*3 + 1] = -0.574979f;	val_dir[10155*3 + 2] = -0.731792f;
+ 	val_dir[10156*3 + 0] = 0.393919f;	val_dir[10156*3 + 1] = -0.551487f;	val_dir[10156*3 + 2] = -0.735316f;
+ 	val_dir[10157*3 + 0] = 0.421637f;	val_dir[10157*3 + 1] = -0.527046f;	val_dir[10157*3 + 2] = -0.737865f;
+ 	val_dir[10158*3 + 0] = 0.448926f;	val_dir[10158*3 + 1] = -0.501740f;	val_dir[10158*3 + 2] = -0.739407f;
+ 	val_dir[10159*3 + 0] = 0.475665f;	val_dir[10159*3 + 1] = -0.475665f;	val_dir[10159*3 + 2] = -0.739923f;
+ 	val_dir[10160*3 + 0] = 0.501740f;	val_dir[10160*3 + 1] = -0.448926f;	val_dir[10160*3 + 2] = -0.739407f;
+ 	val_dir[10161*3 + 0] = 0.527046f;	val_dir[10161*3 + 1] = -0.421637f;	val_dir[10161*3 + 2] = -0.737865f;
+ 	val_dir[10162*3 + 0] = 0.551487f;	val_dir[10162*3 + 1] = -0.393919f;	val_dir[10162*3 + 2] = -0.735316f;
+ 	val_dir[10163*3 + 0] = 0.574979f;	val_dir[10163*3 + 1] = -0.365896f;	val_dir[10163*3 + 2] = -0.731792f;
+ 	val_dir[10164*3 + 0] = 0.597453f;	val_dir[10164*3 + 1] = -0.337691f;	val_dir[10164*3 + 2] = -0.727334f;
+ 	val_dir[10165*3 + 0] = 0.618853f;	val_dir[10165*3 + 1] = -0.309426f;	val_dir[10165*3 + 2] = -0.721995f;
+ 	val_dir[10166*3 + 0] = 0.639138f;	val_dir[10166*3 + 1] = -0.281220f;	val_dir[10166*3 + 2] = -0.715834f;
+ 	val_dir[10167*3 + 0] = 0.658281f;	val_dir[10167*3 + 1] = -0.253185f;	val_dir[10167*3 + 2] = -0.708918f;
+ 	val_dir[10168*3 + 0] = 0.676269f;	val_dir[10168*3 + 1] = -0.225423f;	val_dir[10168*3 + 2] = -0.701316f;
+ 	val_dir[10169*3 + 0] = 0.693103f;	val_dir[10169*3 + 1] = -0.198030f;	val_dir[10169*3 + 2] = -0.693103f;
+ 	val_dir[10170*3 + 0] = 0.708794f;	val_dir[10170*3 + 1] = -0.171088f;	val_dir[10170*3 + 2] = -0.684353f;
+ 	val_dir[10171*3 + 0] = 0.723364f;	val_dir[10171*3 + 1] = -0.144673f;	val_dir[10171*3 + 2] = -0.675140f;
+ 	val_dir[10172*3 + 0] = 0.736843f;	val_dir[10172*3 + 1] = -0.118846f;	val_dir[10172*3 + 2] = -0.665536f;
+ 	val_dir[10173*3 + 0] = 0.749269f;	val_dir[10173*3 + 1] = -0.093659f;	val_dir[10173*3 + 2] = -0.655610f;
+ 	val_dir[10174*3 + 0] = 0.760684f;	val_dir[10174*3 + 1] = -0.069153f;	val_dir[10174*3 + 2] = -0.645429f;
+ 	val_dir[10175*3 + 0] = 0.771136f;	val_dir[10175*3 + 1] = -0.045361f;	val_dir[10175*3 + 2] = -0.635053f;
+ 	val_dir[10176*3 + 0] = 0.780675f;	val_dir[10176*3 + 1] = -0.022305f;	val_dir[10176*3 + 2] = -0.624540f;
+ 	val_dir[10177*3 + 0] = 0.789352f;	val_dir[10177*3 + 1] = 0.0f;	val_dir[10177*3 + 2] = -0.613941f;
+ 	val_dir[10178*3 + 0] = 0.817992f;	val_dir[10178*3 + 1] = 0.022108f;	val_dir[10178*3 + 2] = -0.574805f;
+ 	val_dir[10179*3 + 0] = 0.844653f;	val_dir[10179*3 + 1] = 0.044455f;	val_dir[10179*3 + 2] = -0.533465f;
+ 	val_dir[10180*3 + 0] = 0.869030f;	val_dir[10180*3 + 1] = 0.066848f;	val_dir[10180*3 + 2] = -0.490222f;
+ 	val_dir[10181*3 + 0] = 0.890871f;	val_dir[10181*3 + 1] = 0.089087f;	val_dir[10181*3 + 2] = -0.445435f;
+ 	val_dir[10182*3 + 0] = 0.909988f;	val_dir[10182*3 + 1] = 0.110974f;	val_dir[10182*3 + 2] = -0.399507f;
+ 	val_dir[10183*3 + 0] = 0.926270f;	val_dir[10183*3 + 1] = 0.132324f;	val_dir[10183*3 + 2] = -0.352865f;
+ 	val_dir[10184*3 + 0] = 0.939680f;	val_dir[10184*3 + 1] = 0.152971f;	val_dir[10184*3 + 2] = -0.305942f;
+ 	val_dir[10185*3 + 0] = 0.950255f;	val_dir[10185*3 + 1] = 0.172774f;	val_dir[10185*3 + 2] = -0.259161f;
+ 	val_dir[10186*3 + 0] = 0.958098f;	val_dir[10186*3 + 1] = 0.191620f;	val_dir[10186*3 + 2] = -0.212911f;
+ 	val_dir[10187*3 + 0] = 0.963364f;	val_dir[10187*3 + 1] = 0.209427f;	val_dir[10187*3 + 2] = -0.167542f;
+ 	val_dir[10188*3 + 0] = 0.966252f;	val_dir[10188*3 + 1] = 0.226144f;	val_dir[10188*3 + 2] = -0.123351f;
+ 	val_dir[10189*3 + 0] = 0.966988f;	val_dir[10189*3 + 1] = 0.241747f;	val_dir[10189*3 + 2] = -0.080582f;
+ 	val_dir[10190*3 + 0] = 0.965810f;	val_dir[10190*3 + 1] = 0.256235f;	val_dir[10190*3 + 2] = -0.039421f;
+ 	val_dir[10191*3 + 0] = 0.962964f;	val_dir[10191*3 + 1] = 0.269630f;	val_dir[10191*3 + 2] = 0.0f;
+ 	val_dir[10192*3 + 0] = -0.274668f;	val_dir[10192*3 + 1] = -0.961339f;	val_dir[10192*3 + 2] = -0.019619f;
+ 	val_dir[10193*3 + 0] = -0.260941f;	val_dir[10193*3 + 1] = -0.963475f;	val_dir[10193*3 + 2] = -0.060217f;
+ 	val_dir[10194*3 + 0] = -0.246079f;	val_dir[10194*3 + 1] = -0.963811f;	val_dir[10194*3 + 2] = -0.102533f;
+ 	val_dir[10195*3 + 0] = -0.230067f;	val_dir[10195*3 + 1] = -0.962099f;	val_dir[10195*3 + 2] = -0.146406f;
+ 	val_dir[10196*3 + 0] = -0.212911f;	val_dir[10196*3 + 1] = -0.958098f;	val_dir[10196*3 + 2] = -0.191620f;
+ 	val_dir[10197*3 + 0] = -0.194643f;	val_dir[10197*3 + 1] = -0.951588f;	val_dir[10197*3 + 2] = -0.237897f;
+ 	val_dir[10198*3 + 0] = -0.175327f;	val_dir[10198*3 + 1] = -0.942384f;	val_dir[10198*3 + 2] = -0.284907f;
+ 	val_dir[10199*3 + 0] = -0.155059f;	val_dir[10199*3 + 1] = -0.930352f;	val_dir[10199*3 + 2] = -0.332269f;
+ 	val_dir[10200*3 + 0] = -0.133963f;	val_dir[10200*3 + 1] = -0.915416f;	val_dir[10200*3 + 2] = -0.379563f;
+ 	val_dir[10201*3 + 0] = -0.112197f;	val_dir[10201*3 + 1] = -0.897574f;	val_dir[10201*3 + 2] = -0.426348f;
+ 	val_dir[10202*3 + 0] = -0.089939f;	val_dir[10202*3 + 1] = -0.876903f;	val_dir[10202*3 + 2] = -0.472178f;
+ 	val_dir[10203*3 + 0] = -0.067386f;	val_dir[10203*3 + 1] = -0.853556f;	val_dir[10203*3 + 2] = -0.516626f;
+ 	val_dir[10204*3 + 0] = -0.044744f;	val_dir[10204*3 + 1] = -0.827759f;	val_dir[10204*3 + 2] = -0.559297f;
+ 	val_dir[10205*3 + 0] = -0.022217f;	val_dir[10205*3 + 1] = -0.799803f;	val_dir[10205*3 + 2] = -0.599852f;
+ 	val_dir[10206*3 + 0] = 0.0f;	val_dir[10206*3 + 1] = -0.770022f;	val_dir[10206*3 + 2] = -0.638018f;
+ 	val_dir[10207*3 + 0] = 0.022372f;	val_dir[10207*3 + 1] = -0.760644f;	val_dir[10207*3 + 2] = -0.648784f;
+ 	val_dir[10208*3 + 0] = 0.045478f;	val_dir[10208*3 + 1] = -0.750388f;	val_dir[10208*3 + 2] = -0.659432f;
+ 	val_dir[10209*3 + 0] = 0.069301f;	val_dir[10209*3 + 1] = -0.739205f;	val_dir[10209*3 + 2] = -0.669905f;
+ 	val_dir[10210*3 + 0] = 0.093813f;	val_dir[10210*3 + 1] = -0.727051f;	val_dir[10210*3 + 2] = -0.680144f;
+ 	val_dir[10211*3 + 0] = 0.118980f;	val_dir[10211*3 + 1] = -0.713881f;	val_dir[10211*3 + 2] = -0.690085f;
+ 	val_dir[10212*3 + 0] = 0.144757f;	val_dir[10212*3 + 1] = -0.699659f;	val_dir[10212*3 + 2] = -0.699659f;
+ 	val_dir[10213*3 + 0] = 0.171088f;	val_dir[10213*3 + 1] = -0.684353f;	val_dir[10213*3 + 2] = -0.708794f;
+ 	val_dir[10214*3 + 0] = 0.197908f;	val_dir[10214*3 + 1] = -0.667940f;	val_dir[10214*3 + 2] = -0.717418f;
+ 	val_dir[10215*3 + 0] = 0.225141f;	val_dir[10215*3 + 1] = -0.650407f;	val_dir[10215*3 + 2] = -0.725454f;
+ 	val_dir[10216*3 + 0] = 0.252699f;	val_dir[10216*3 + 1] = -0.631748f;	val_dir[10216*3 + 2] = -0.732828f;
+ 	val_dir[10217*3 + 0] = 0.280488f;	val_dir[10217*3 + 1] = -0.611974f;	val_dir[10217*3 + 2] = -0.739469f;
+ 	val_dir[10218*3 + 0] = 0.308403f;	val_dir[10218*3 + 1] = -0.591105f;	val_dir[10218*3 + 2] = -0.745307f;
+ 	val_dir[10219*3 + 0] = 0.336332f;	val_dir[10219*3 + 1] = -0.569177f;	val_dir[10219*3 + 2] = -0.750279f;
+ 	val_dir[10220*3 + 0] = 0.364159f;	val_dir[10220*3 + 1] = -0.546238f;	val_dir[10220*3 + 2] = -0.754329f;
+ 	val_dir[10221*3 + 0] = 0.391764f;	val_dir[10221*3 + 1] = -0.522352f;	val_dir[10221*3 + 2] = -0.757410f;
+ 	val_dir[10222*3 + 0] = 0.419026f;	val_dir[10222*3 + 1] = -0.497594f;	val_dir[10222*3 + 2] = -0.759485f;
+ 	val_dir[10223*3 + 0] = 0.445827f;	val_dir[10223*3 + 1] = -0.472053f;	val_dir[10223*3 + 2] = -0.760529f;
+ 	val_dir[10224*3 + 0] = 0.472053f;	val_dir[10224*3 + 1] = -0.445827f;	val_dir[10224*3 + 2] = -0.760529f;
+ 	val_dir[10225*3 + 0] = 0.497594f;	val_dir[10225*3 + 1] = -0.419026f;	val_dir[10225*3 + 2] = -0.759485f;
+ 	val_dir[10226*3 + 0] = 0.522352f;	val_dir[10226*3 + 1] = -0.391764f;	val_dir[10226*3 + 2] = -0.757410f;
+ 	val_dir[10227*3 + 0] = 0.546238f;	val_dir[10227*3 + 1] = -0.364159f;	val_dir[10227*3 + 2] = -0.754329f;
+ 	val_dir[10228*3 + 0] = 0.569177f;	val_dir[10228*3 + 1] = -0.336332f;	val_dir[10228*3 + 2] = -0.750279f;
+ 	val_dir[10229*3 + 0] = 0.591105f;	val_dir[10229*3 + 1] = -0.308403f;	val_dir[10229*3 + 2] = -0.745307f;
+ 	val_dir[10230*3 + 0] = 0.611974f;	val_dir[10230*3 + 1] = -0.280488f;	val_dir[10230*3 + 2] = -0.739469f;
+ 	val_dir[10231*3 + 0] = 0.631748f;	val_dir[10231*3 + 1] = -0.252699f;	val_dir[10231*3 + 2] = -0.732828f;
+ 	val_dir[10232*3 + 0] = 0.650407f;	val_dir[10232*3 + 1] = -0.225141f;	val_dir[10232*3 + 2] = -0.725454f;
+ 	val_dir[10233*3 + 0] = 0.667940f;	val_dir[10233*3 + 1] = -0.197908f;	val_dir[10233*3 + 2] = -0.717418f;
+ 	val_dir[10234*3 + 0] = 0.684353f;	val_dir[10234*3 + 1] = -0.171088f;	val_dir[10234*3 + 2] = -0.708794f;
+ 	val_dir[10235*3 + 0] = 0.699659f;	val_dir[10235*3 + 1] = -0.144757f;	val_dir[10235*3 + 2] = -0.699659f;
+ 	val_dir[10236*3 + 0] = 0.713881f;	val_dir[10236*3 + 1] = -0.118980f;	val_dir[10236*3 + 2] = -0.690085f;
+ 	val_dir[10237*3 + 0] = 0.727051f;	val_dir[10237*3 + 1] = -0.093813f;	val_dir[10237*3 + 2] = -0.680144f;
+ 	val_dir[10238*3 + 0] = 0.739205f;	val_dir[10238*3 + 1] = -0.069301f;	val_dir[10238*3 + 2] = -0.669905f;
+ 	val_dir[10239*3 + 0] = 0.750388f;	val_dir[10239*3 + 1] = -0.045478f;	val_dir[10239*3 + 2] = -0.659432f;
+ 	val_dir[10240*3 + 0] = 0.760644f;	val_dir[10240*3 + 1] = -0.022372f;	val_dir[10240*3 + 2] = -0.648784f;
+ 	val_dir[10241*3 + 0] = 0.770022f;	val_dir[10241*3 + 1] = 0.0f;	val_dir[10241*3 + 2] = -0.638018f;
+ 	val_dir[10242*3 + 0] = 0.799803f;	val_dir[10242*3 + 1] = 0.022217f;	val_dir[10242*3 + 2] = -0.599852f;
+ 	val_dir[10243*3 + 0] = 0.827759f;	val_dir[10243*3 + 1] = 0.044744f;	val_dir[10243*3 + 2] = -0.559297f;
+ 	val_dir[10244*3 + 0] = 0.853556f;	val_dir[10244*3 + 1] = 0.067386f;	val_dir[10244*3 + 2] = -0.516626f;
+ 	val_dir[10245*3 + 0] = 0.876903f;	val_dir[10245*3 + 1] = 0.089939f;	val_dir[10245*3 + 2] = -0.472178f;
+ 	val_dir[10246*3 + 0] = 0.897574f;	val_dir[10246*3 + 1] = 0.112197f;	val_dir[10246*3 + 2] = -0.426348f;
+ 	val_dir[10247*3 + 0] = 0.915416f;	val_dir[10247*3 + 1] = 0.133963f;	val_dir[10247*3 + 2] = -0.379563f;
+ 	val_dir[10248*3 + 0] = 0.930352f;	val_dir[10248*3 + 1] = 0.155059f;	val_dir[10248*3 + 2] = -0.332269f;
+ 	val_dir[10249*3 + 0] = 0.942384f;	val_dir[10249*3 + 1] = 0.175327f;	val_dir[10249*3 + 2] = -0.284907f;
+ 	val_dir[10250*3 + 0] = 0.951588f;	val_dir[10250*3 + 1] = 0.194643f;	val_dir[10250*3 + 2] = -0.237897f;
+ 	val_dir[10251*3 + 0] = 0.958098f;	val_dir[10251*3 + 1] = 0.212911f;	val_dir[10251*3 + 2] = -0.191620f;
+ 	val_dir[10252*3 + 0] = 0.962099f;	val_dir[10252*3 + 1] = 0.230067f;	val_dir[10252*3 + 2] = -0.146406f;
+ 	val_dir[10253*3 + 0] = 0.963811f;	val_dir[10253*3 + 1] = 0.246079f;	val_dir[10253*3 + 2] = -0.102533f;
+ 	val_dir[10254*3 + 0] = 0.963475f;	val_dir[10254*3 + 1] = 0.260941f;	val_dir[10254*3 + 2] = -0.060217f;
+ 	val_dir[10255*3 + 0] = 0.961339f;	val_dir[10255*3 + 1] = 0.274668f;	val_dir[10255*3 + 2] = -0.019619f;
+ 	val_dir[10256*3 + 0] = -0.292714f;	val_dir[10256*3 + 1] = -0.95620f;	val_dir[10256*3 + 2] = 0.0f;
+ 	val_dir[10257*3 + 0] = -0.279776f;	val_dir[10257*3 + 1] = -0.959233f;	val_dir[10257*3 + 2] = -0.039968f;
+ 	val_dir[10258*3 + 0] = -0.265694f;	val_dir[10258*3 + 1] = -0.960585f;	val_dir[10258*3 + 2] = -0.081752f;
+ 	val_dir[10259*3 + 0] = -0.250435f;	val_dir[10259*3 + 1] = -0.960001f;	val_dir[10259*3 + 2] = -0.125218f;
+ 	val_dir[10260*3 + 0] = -0.233990f;	val_dir[10260*3 + 1] = -0.957230f;	val_dir[10260*3 + 2] = -0.170174f;
+ 	val_dir[10261*3 + 0] = -0.216371f;	val_dir[10261*3 + 1] = -0.952033f;	val_dir[10261*3 + 2] = -0.216371f;
+ 	val_dir[10262*3 + 0] = -0.197623f;	val_dir[10262*3 + 1] = -0.94420f;	val_dir[10262*3 + 2] = -0.263498f;
+ 	val_dir[10263*3 + 0] = -0.177822f;	val_dir[10263*3 + 1] = -0.933564f;	val_dir[10263*3 + 2] = -0.311188f;
+ 	val_dir[10264*3 + 0] = -0.157075f;	val_dir[10264*3 + 1] = -0.920014f;	val_dir[10264*3 + 2] = -0.359030f;
+ 	val_dir[10265*3 + 0] = -0.135526f;	val_dir[10265*3 + 1] = -0.903508f;	val_dir[10265*3 + 2] = -0.406579f;
+ 	val_dir[10266*3 + 0] = -0.113344f;	val_dir[10266*3 + 1] = -0.884083f;	val_dir[10266*3 + 2] = -0.453376f;
+ 	val_dir[10267*3 + 0] = -0.090722f;	val_dir[10267*3 + 1] = -0.861857f;	val_dir[10267*3 + 2] = -0.498970f;
+ 	val_dir[10268*3 + 0] = -0.067867f;	val_dir[10268*3 + 1] = -0.837027f;	val_dir[10268*3 + 2] = -0.542936f;
+ 	val_dir[10269*3 + 0] = -0.044992f;	val_dir[10269*3 + 1] = -0.809858f;	val_dir[10269*3 + 2] = -0.584898f;
+ 	val_dir[10270*3 + 0] = -0.022305f;	val_dir[10270*3 + 1] = -0.780675f;	val_dir[10270*3 + 2] = -0.624540f;
+ 	val_dir[10271*3 + 0] = 0.0f;	val_dir[10271*3 + 1] = -0.749838f;	val_dir[10271*3 + 2] = -0.661622f;
+ 	val_dir[10272*3 + 0] = 0.022417f;	val_dir[10272*3 + 1] = -0.739754f;	val_dir[10272*3 + 2] = -0.672504f;
+ 	val_dir[10273*3 + 0] = 0.045549f;	val_dir[10273*3 + 1] = -0.728780f;	val_dir[10273*3 + 2] = -0.683231f;
+ 	val_dir[10274*3 + 0] = 0.069375f;	val_dir[10274*3 + 1] = -0.716871f;	val_dir[10274*3 + 2] = -0.693746f;
+ 	val_dir[10275*3 + 0] = 0.093865f;	val_dir[10275*3 + 1] = -0.703985f;	val_dir[10275*3 + 2] = -0.703985f;
+ 	val_dir[10276*3 + 0] = 0.118980f;	val_dir[10276*3 + 1] = -0.690085f;	val_dir[10276*3 + 2] = -0.713881f;
+ 	val_dir[10277*3 + 0] = 0.144673f;	val_dir[10277*3 + 1] = -0.675140f;	val_dir[10277*3 + 2] = -0.723364f;
+ 	val_dir[10278*3 + 0] = 0.170884f;	val_dir[10278*3 + 1] = -0.659125f;	val_dir[10278*3 + 2] = -0.732361f;
+ 	val_dir[10279*3 + 0] = 0.197546f;	val_dir[10279*3 + 1] = -0.642024f;	val_dir[10279*3 + 2] = -0.740797f;
+ 	val_dir[10280*3 + 0] = 0.224579f;	val_dir[10280*3 + 1] = -0.623831f;	val_dir[10280*3 + 2] = -0.748598f;
+ 	val_dir[10281*3 + 0] = 0.251896f;	val_dir[10281*3 + 1] = -0.604551f;	val_dir[10281*3 + 2] = -0.755689f;
+ 	val_dir[10282*3 + 0] = 0.27940f;	val_dir[10282*3 + 1] = -0.584201f;	val_dir[10282*3 + 2] = -0.762001f;
+ 	val_dir[10283*3 + 0] = 0.306987f;	val_dir[10283*3 + 1] = -0.562809f;	val_dir[10283*3 + 2] = -0.767467f;
+ 	val_dir[10284*3 + 0] = 0.334545f;	val_dir[10284*3 + 1] = -0.540419f;	val_dir[10284*3 + 2] = -0.772027f;
+ 	val_dir[10285*3 + 0] = 0.361961f;	val_dir[10285*3 + 1] = -0.517088f;	val_dir[10285*3 + 2] = -0.775632f;
+ 	val_dir[10286*3 + 0] = 0.389118f;	val_dir[10286*3 + 1] = -0.492883f;	val_dir[10286*3 + 2] = -0.778237f;
+ 	val_dir[10287*3 + 0] = 0.41590f;	val_dir[10287*3 + 1] = -0.467888f;	val_dir[10287*3 + 2] = -0.779813f;
+ 	val_dir[10288*3 + 0] = 0.442193f;	val_dir[10288*3 + 1] = -0.442193f;	val_dir[10288*3 + 2] = -0.780340f;
+ 	val_dir[10289*3 + 0] = 0.467888f;	val_dir[10289*3 + 1] = -0.41590f;	val_dir[10289*3 + 2] = -0.779813f;
+ 	val_dir[10290*3 + 0] = 0.492883f;	val_dir[10290*3 + 1] = -0.389118f;	val_dir[10290*3 + 2] = -0.778237f;
+ 	val_dir[10291*3 + 0] = 0.517088f;	val_dir[10291*3 + 1] = -0.361961f;	val_dir[10291*3 + 2] = -0.775632f;
+ 	val_dir[10292*3 + 0] = 0.540419f;	val_dir[10292*3 + 1] = -0.334545f;	val_dir[10292*3 + 2] = -0.772027f;
+ 	val_dir[10293*3 + 0] = 0.562809f;	val_dir[10293*3 + 1] = -0.306987f;	val_dir[10293*3 + 2] = -0.767467f;
+ 	val_dir[10294*3 + 0] = 0.584201f;	val_dir[10294*3 + 1] = -0.27940f;	val_dir[10294*3 + 2] = -0.762001f;
+ 	val_dir[10295*3 + 0] = 0.604551f;	val_dir[10295*3 + 1] = -0.251896f;	val_dir[10295*3 + 2] = -0.755689f;
+ 	val_dir[10296*3 + 0] = 0.623831f;	val_dir[10296*3 + 1] = -0.224579f;	val_dir[10296*3 + 2] = -0.748598f;
+ 	val_dir[10297*3 + 0] = 0.642024f;	val_dir[10297*3 + 1] = -0.197546f;	val_dir[10297*3 + 2] = -0.740797f;
+ 	val_dir[10298*3 + 0] = 0.659125f;	val_dir[10298*3 + 1] = -0.170884f;	val_dir[10298*3 + 2] = -0.732361f;
+ 	val_dir[10299*3 + 0] = 0.675140f;	val_dir[10299*3 + 1] = -0.144673f;	val_dir[10299*3 + 2] = -0.723364f;
+ 	val_dir[10300*3 + 0] = 0.690085f;	val_dir[10300*3 + 1] = -0.118980f;	val_dir[10300*3 + 2] = -0.713881f;
+ 	val_dir[10301*3 + 0] = 0.703985f;	val_dir[10301*3 + 1] = -0.093865f;	val_dir[10301*3 + 2] = -0.703985f;
+ 	val_dir[10302*3 + 0] = 0.716871f;	val_dir[10302*3 + 1] = -0.069375f;	val_dir[10302*3 + 2] = -0.693746f;
+ 	val_dir[10303*3 + 0] = 0.728780f;	val_dir[10303*3 + 1] = -0.045549f;	val_dir[10303*3 + 2] = -0.683231f;
+ 	val_dir[10304*3 + 0] = 0.739754f;	val_dir[10304*3 + 1] = -0.022417f;	val_dir[10304*3 + 2] = -0.672504f;
+ 	val_dir[10305*3 + 0] = 0.749838f;	val_dir[10305*3 + 1] = 0.0f;	val_dir[10305*3 + 2] = -0.661622f;
+ 	val_dir[10306*3 + 0] = 0.780675f;	val_dir[10306*3 + 1] = 0.022305f;	val_dir[10306*3 + 2] = -0.624540f;
+ 	val_dir[10307*3 + 0] = 0.809858f;	val_dir[10307*3 + 1] = 0.044992f;	val_dir[10307*3 + 2] = -0.584898f;
+ 	val_dir[10308*3 + 0] = 0.837027f;	val_dir[10308*3 + 1] = 0.067867f;	val_dir[10308*3 + 2] = -0.542936f;
+ 	val_dir[10309*3 + 0] = 0.861857f;	val_dir[10309*3 + 1] = 0.090722f;	val_dir[10309*3 + 2] = -0.498970f;
+ 	val_dir[10310*3 + 0] = 0.884083f;	val_dir[10310*3 + 1] = 0.113344f;	val_dir[10310*3 + 2] = -0.453376f;
+ 	val_dir[10311*3 + 0] = 0.903508f;	val_dir[10311*3 + 1] = 0.135526f;	val_dir[10311*3 + 2] = -0.406579f;
+ 	val_dir[10312*3 + 0] = 0.920014f;	val_dir[10312*3 + 1] = 0.157075f;	val_dir[10312*3 + 2] = -0.359030f;
+ 	val_dir[10313*3 + 0] = 0.933564f;	val_dir[10313*3 + 1] = 0.177822f;	val_dir[10313*3 + 2] = -0.311188f;
+ 	val_dir[10314*3 + 0] = 0.94420f;	val_dir[10314*3 + 1] = 0.197623f;	val_dir[10314*3 + 2] = -0.263498f;
+ 	val_dir[10315*3 + 0] = 0.952033f;	val_dir[10315*3 + 1] = 0.216371f;	val_dir[10315*3 + 2] = -0.216371f;
+ 	val_dir[10316*3 + 0] = 0.957230f;	val_dir[10316*3 + 1] = 0.233990f;	val_dir[10316*3 + 2] = -0.170174f;
+ 	val_dir[10317*3 + 0] = 0.960001f;	val_dir[10317*3 + 1] = 0.250435f;	val_dir[10317*3 + 2] = -0.125218f;
+ 	val_dir[10318*3 + 0] = 0.960585f;	val_dir[10318*3 + 1] = 0.265694f;	val_dir[10318*3 + 2] = -0.081752f;
+ 	val_dir[10319*3 + 0] = 0.959233f;	val_dir[10319*3 + 1] = 0.279776f;	val_dir[10319*3 + 2] = -0.039968f;
+ 	val_dir[10320*3 + 0] = 0.95620f;	val_dir[10320*3 + 1] = 0.292714f;	val_dir[10320*3 + 2] = 0.0f;
+ 	val_dir[10321*3 + 0] = -0.298216f;	val_dir[10321*3 + 1] = -0.954291f;	val_dir[10321*3 + 2] = -0.019881f;
+ 	val_dir[10322*3 + 0] = -0.284944f;	val_dir[10322*3 + 1] = -0.956597f;	val_dir[10322*3 + 2] = -0.061059f;
+ 	val_dir[10323*3 + 0] = -0.270481f;	val_dir[10323*3 + 1] = -0.957088f;	val_dir[10323*3 + 2] = -0.104031f;
+ 	val_dir[10324*3 + 0] = -0.254801f;	val_dir[10324*3 + 1] = -0.955502f;	val_dir[10324*3 + 2] = -0.148634f;
+ 	val_dir[10325*3 + 0] = -0.237897f;	val_dir[10325*3 + 1] = -0.951588f;	val_dir[10325*3 + 2] = -0.194643f;
+ 	val_dir[10326*3 + 0] = -0.219793f;	val_dir[10326*3 + 1] = -0.945112f;	val_dir[10326*3 + 2] = -0.241773f;
+ 	val_dir[10327*3 + 0] = -0.200545f;	val_dir[10327*3 + 1] = -0.935879f;	val_dir[10327*3 + 2] = -0.289677f;
+ 	val_dir[10328*3 + 0] = -0.180242f;	val_dir[10328*3 + 1] = -0.923742f;	val_dir[10328*3 + 2] = -0.337954f;
+ 	val_dir[10329*3 + 0] = -0.159009f;	val_dir[10329*3 + 1] = -0.908622f;	val_dir[10329*3 + 2] = -0.386164f;
+ 	val_dir[10330*3 + 0] = -0.137002f;	val_dir[10330*3 + 1] = -0.890513f;	val_dir[10330*3 + 2] = -0.433840f;
+ 	val_dir[10331*3 + 0] = -0.114407f;	val_dir[10331*3 + 1] = -0.869495f;	val_dir[10331*3 + 2] = -0.480510f;
+ 	val_dir[10332*3 + 0] = -0.091430f;	val_dir[10332*3 + 1] = -0.845728f;	val_dir[10332*3 + 2] = -0.525723f;
+ 	val_dir[10333*3 + 0] = -0.068288f;	val_dir[10333*3 + 1] = -0.819453f;	val_dir[10333*3 + 2] = -0.569064f;
+ 	val_dir[10334*3 + 0] = -0.045198f;	val_dir[10334*3 + 1] = -0.790973f;	val_dir[10334*3 + 2] = -0.610179f;
+ 	val_dir[10335*3 + 0] = -0.022372f;	val_dir[10335*3 + 1] = -0.760644f;	val_dir[10335*3 + 2] = -0.648784f;
+ 	val_dir[10336*3 + 0] = 0.0f;	val_dir[10336*3 + 1] = -0.728848f;	val_dir[10336*3 + 2] = -0.684675f;
+ 	val_dir[10337*3 + 0] = 0.022439f;	val_dir[10337*3 + 1] = -0.718059f;	val_dir[10337*3 + 2] = -0.695620f;
+ 	val_dir[10338*3 + 0] = 0.045572f;	val_dir[10338*3 + 1] = -0.706372f;	val_dir[10338*3 + 2] = -0.706372f;
+ 	val_dir[10339*3 + 0] = 0.069375f;	val_dir[10339*3 + 1] = -0.693746f;	val_dir[10339*3 + 2] = -0.716871f;
+ 	val_dir[10340*3 + 0] = 0.093813f;	val_dir[10340*3 + 1] = -0.680144f;	val_dir[10340*3 + 2] = -0.727051f;
+ 	val_dir[10341*3 + 0] = 0.118846f;	val_dir[10341*3 + 1] = -0.665536f;	val_dir[10341*3 + 2] = -0.736843f;
+ 	val_dir[10342*3 + 0] = 0.144421f;	val_dir[10342*3 + 1] = -0.649895f;	val_dir[10342*3 + 2] = -0.746176f;
+ 	val_dir[10343*3 + 0] = 0.170478f;	val_dir[10343*3 + 1] = -0.633205f;	val_dir[10343*3 + 2] = -0.754976f;
+ 	val_dir[10344*3 + 0] = 0.196946f;	val_dir[10344*3 + 1] = -0.615457f;	val_dir[10344*3 + 2] = -0.763167f;
+ 	val_dir[10345*3 + 0] = 0.223745f;	val_dir[10345*3 + 1] = -0.596653f;	val_dir[10345*3 + 2] = -0.770677f;
+ 	val_dir[10346*3 + 0] = 0.250785f;	val_dir[10346*3 + 1] = -0.576805f;	val_dir[10346*3 + 2] = -0.777433f;
+ 	val_dir[10347*3 + 0] = 0.277969f;	val_dir[10347*3 + 1] = -0.555939f;	val_dir[10347*3 + 2] = -0.783368f;
+ 	val_dir[10348*3 + 0] = 0.305194f;	val_dir[10348*3 + 1] = -0.534090f;	val_dir[10348*3 + 2] = -0.788419f;
+ 	val_dir[10349*3 + 0] = 0.332352f;	val_dir[10349*3 + 1] = -0.511310f;	val_dir[10349*3 + 2] = -0.792530f;
+ 	val_dir[10350*3 + 0] = 0.359329f;	val_dir[10350*3 + 1] = -0.487661f;	val_dir[10350*3 + 2] = -0.795657f;
+ 	val_dir[10351*3 + 0] = 0.386014f;	val_dir[10351*3 + 1] = -0.463217f;	val_dir[10351*3 + 2] = -0.797762f;
+ 	val_dir[10352*3 + 0] = 0.412294f;	val_dir[10352*3 + 1] = -0.438063f;	val_dir[10352*3 + 2] = -0.798820f;
+ 	val_dir[10353*3 + 0] = 0.438063f;	val_dir[10353*3 + 1] = -0.412294f;	val_dir[10353*3 + 2] = -0.798820f;
+ 	val_dir[10354*3 + 0] = 0.463217f;	val_dir[10354*3 + 1] = -0.386014f;	val_dir[10354*3 + 2] = -0.797762f;
+ 	val_dir[10355*3 + 0] = 0.487661f;	val_dir[10355*3 + 1] = -0.359329f;	val_dir[10355*3 + 2] = -0.795657f;
+ 	val_dir[10356*3 + 0] = 0.511310f;	val_dir[10356*3 + 1] = -0.332352f;	val_dir[10356*3 + 2] = -0.792530f;
+ 	val_dir[10357*3 + 0] = 0.534090f;	val_dir[10357*3 + 1] = -0.305194f;	val_dir[10357*3 + 2] = -0.788419f;
+ 	val_dir[10358*3 + 0] = 0.555939f;	val_dir[10358*3 + 1] = -0.277969f;	val_dir[10358*3 + 2] = -0.783368f;
+ 	val_dir[10359*3 + 0] = 0.576805f;	val_dir[10359*3 + 1] = -0.250785f;	val_dir[10359*3 + 2] = -0.777433f;
+ 	val_dir[10360*3 + 0] = 0.596653f;	val_dir[10360*3 + 1] = -0.223745f;	val_dir[10360*3 + 2] = -0.770677f;
+ 	val_dir[10361*3 + 0] = 0.615457f;	val_dir[10361*3 + 1] = -0.196946f;	val_dir[10361*3 + 2] = -0.763167f;
+ 	val_dir[10362*3 + 0] = 0.633205f;	val_dir[10362*3 + 1] = -0.170478f;	val_dir[10362*3 + 2] = -0.754976f;
+ 	val_dir[10363*3 + 0] = 0.649895f;	val_dir[10363*3 + 1] = -0.144421f;	val_dir[10363*3 + 2] = -0.746176f;
+ 	val_dir[10364*3 + 0] = 0.665536f;	val_dir[10364*3 + 1] = -0.118846f;	val_dir[10364*3 + 2] = -0.736843f;
+ 	val_dir[10365*3 + 0] = 0.680144f;	val_dir[10365*3 + 1] = -0.093813f;	val_dir[10365*3 + 2] = -0.727051f;
+ 	val_dir[10366*3 + 0] = 0.693746f;	val_dir[10366*3 + 1] = -0.069375f;	val_dir[10366*3 + 2] = -0.716871f;
+ 	val_dir[10367*3 + 0] = 0.706372f;	val_dir[10367*3 + 1] = -0.045572f;	val_dir[10367*3 + 2] = -0.706372f;
+ 	val_dir[10368*3 + 0] = 0.718059f;	val_dir[10368*3 + 1] = -0.022439f;	val_dir[10368*3 + 2] = -0.695620f;
+ 	val_dir[10369*3 + 0] = 0.728848f;	val_dir[10369*3 + 1] = 0.0f;	val_dir[10369*3 + 2] = -0.684675f;
+ 	val_dir[10370*3 + 0] = 0.760644f;	val_dir[10370*3 + 1] = 0.022372f;	val_dir[10370*3 + 2] = -0.648784f;
+ 	val_dir[10371*3 + 0] = 0.790973f;	val_dir[10371*3 + 1] = 0.045198f;	val_dir[10371*3 + 2] = -0.610179f;
+ 	val_dir[10372*3 + 0] = 0.819453f;	val_dir[10372*3 + 1] = 0.068288f;	val_dir[10372*3 + 2] = -0.569064f;
+ 	val_dir[10373*3 + 0] = 0.845728f;	val_dir[10373*3 + 1] = 0.091430f;	val_dir[10373*3 + 2] = -0.525723f;
+ 	val_dir[10374*3 + 0] = 0.869495f;	val_dir[10374*3 + 1] = 0.114407f;	val_dir[10374*3 + 2] = -0.480510f;
+ 	val_dir[10375*3 + 0] = 0.890513f;	val_dir[10375*3 + 1] = 0.137002f;	val_dir[10375*3 + 2] = -0.433840f;
+ 	val_dir[10376*3 + 0] = 0.908622f;	val_dir[10376*3 + 1] = 0.159009f;	val_dir[10376*3 + 2] = -0.386164f;
+ 	val_dir[10377*3 + 0] = 0.923742f;	val_dir[10377*3 + 1] = 0.180242f;	val_dir[10377*3 + 2] = -0.337954f;
+ 	val_dir[10378*3 + 0] = 0.935879f;	val_dir[10378*3 + 1] = 0.200545f;	val_dir[10378*3 + 2] = -0.289677f;
+ 	val_dir[10379*3 + 0] = 0.945112f;	val_dir[10379*3 + 1] = 0.219793f;	val_dir[10379*3 + 2] = -0.241773f;
+ 	val_dir[10380*3 + 0] = 0.951588f;	val_dir[10380*3 + 1] = 0.237897f;	val_dir[10380*3 + 2] = -0.194643f;
+ 	val_dir[10381*3 + 0] = 0.955502f;	val_dir[10381*3 + 1] = 0.254801f;	val_dir[10381*3 + 2] = -0.148634f;
+ 	val_dir[10382*3 + 0] = 0.957088f;	val_dir[10382*3 + 1] = 0.270481f;	val_dir[10382*3 + 2] = -0.104031f;
+ 	val_dir[10383*3 + 0] = 0.956597f;	val_dir[10383*3 + 1] = 0.284944f;	val_dir[10383*3 + 2] = -0.061059f;
+ 	val_dir[10384*3 + 0] = 0.954291f;	val_dir[10384*3 + 1] = 0.298216f;	val_dir[10384*3 + 2] = -0.019881f;
+ 	val_dir[10385*3 + 0] = -0.316228f;	val_dir[10385*3 + 1] = -0.948683f;	val_dir[10385*3 + 2] = 0.0f;
+ 	val_dir[10386*3 + 0] = -0.303791f;	val_dir[10386*3 + 1] = -0.951877f;	val_dir[10386*3 + 2] = -0.040505f;
+ 	val_dir[10387*3 + 0] = -0.290159f;	val_dir[10387*3 + 1] = -0.953381f;	val_dir[10387*3 + 2] = -0.082903f;
+ 	val_dir[10388*3 + 0] = -0.275290f;	val_dir[10388*3 + 1] = -0.952928f;	val_dir[10388*3 + 2] = -0.127057f;
+ 	val_dir[10389*3 + 0] = -0.259161f;	val_dir[10389*3 + 1] = -0.950255f;	val_dir[10389*3 + 2] = -0.172774f;
+ 	val_dir[10390*3 + 0] = -0.241773f;	val_dir[10390*3 + 1] = -0.945112f;	val_dir[10390*3 + 2] = -0.219793f;
+ 	val_dir[10391*3 + 0] = -0.223161f;	val_dir[10391*3 + 1] = -0.937276f;	val_dir[10391*3 + 2] = -0.267793f;
+ 	val_dir[10392*3 + 0] = -0.203393f;	val_dir[10392*3 + 1] = -0.926568f;	val_dir[10392*3 + 2] = -0.316389f;
+ 	val_dir[10393*3 + 0] = -0.182574f;	val_dir[10393*3 + 1] = -0.912871f;	val_dir[10393*3 + 2] = -0.365148f;
+ 	val_dir[10394*3 + 0] = -0.160845f;	val_dir[10394*3 + 1] = -0.896137f;	val_dir[10394*3 + 2] = -0.413602f;
+ 	val_dir[10395*3 + 0] = -0.138380f;	val_dir[10395*3 + 1] = -0.876405f;	val_dir[10395*3 + 2] = -0.461266f;
+ 	val_dir[10396*3 + 0] = -0.115378f;	val_dir[10396*3 + 1] = -0.853796f;	val_dir[10396*3 + 2] = -0.507662f;
+ 	val_dir[10397*3 + 0] = -0.092057f;	val_dir[10397*3 + 1] = -0.828517f;	val_dir[10397*3 + 2] = -0.552345f;
+ 	val_dir[10398*3 + 0] = -0.068644f;	val_dir[10398*3 + 1] = -0.800850f;	val_dir[10398*3 + 2] = -0.594917f;
+ 	val_dir[10399*3 + 0] = -0.045361f;	val_dir[10399*3 + 1] = -0.771136f;	val_dir[10399*3 + 2] = -0.635053f;
+ 	val_dir[10400*3 + 0] = -0.022417f;	val_dir[10400*3 + 1] = -0.739754f;	val_dir[10400*3 + 2] = -0.672504f;
+ 	val_dir[10401*3 + 0] = 0.0f;	val_dir[10401*3 + 1] = -0.707107f;	val_dir[10401*3 + 2] = -0.707107f;
+ 	val_dir[10402*3 + 0] = 0.022439f;	val_dir[10402*3 + 1] = -0.695620f;	val_dir[10402*3 + 2] = -0.718059f;
+ 	val_dir[10403*3 + 0] = 0.045549f;	val_dir[10403*3 + 1] = -0.683231f;	val_dir[10403*3 + 2] = -0.728780f;
+ 	val_dir[10404*3 + 0] = 0.069301f;	val_dir[10404*3 + 1] = -0.669905f;	val_dir[10404*3 + 2] = -0.739205f;
+ 	val_dir[10405*3 + 0] = 0.093659f;	val_dir[10405*3 + 1] = -0.655610f;	val_dir[10405*3 + 2] = -0.749269f;
+ 	val_dir[10406*3 + 0] = 0.118578f;	val_dir[10406*3 + 1] = -0.640321f;	val_dir[10406*3 + 2] = -0.758899f;
+ 	val_dir[10407*3 + 0] = 0.144005f;	val_dir[10407*3 + 1] = -0.624020f;	val_dir[10407*3 + 2] = -0.768025f;
+ 	val_dir[10408*3 + 0] = 0.169875f;	val_dir[10408*3 + 1] = -0.606696f;	val_dir[10408*3 + 2] = -0.776571f;
+ 	val_dir[10409*3 + 0] = 0.196116f;	val_dir[10409*3 + 1] = -0.588348f;	val_dir[10409*3 + 2] = -0.784465f;
+ 	val_dir[10410*3 + 0] = 0.222647f;	val_dir[10410*3 + 1] = -0.568986f;	val_dir[10410*3 + 2] = -0.791633f;
+ 	val_dir[10411*3 + 0] = 0.249377f;	val_dir[10411*3 + 1] = -0.548630f;	val_dir[10411*3 + 2] = -0.798007f;
+ 	val_dir[10412*3 + 0] = 0.276211f;	val_dir[10412*3 + 1] = -0.527312f;	val_dir[10412*3 + 2] = -0.803523f;
+ 	val_dir[10413*3 + 0] = 0.303046f;	val_dir[10413*3 + 1] = -0.505076f;	val_dir[10413*3 + 2] = -0.808122f;
+ 	val_dir[10414*3 + 0] = 0.329775f;	val_dir[10414*3 + 1] = -0.481979f;	val_dir[10414*3 + 2] = -0.811754f;
+ 	val_dir[10415*3 + 0] = 0.356291f;	val_dir[10415*3 + 1] = -0.458088f;	val_dir[10415*3 + 2] = -0.814379f;
+ 	val_dir[10416*3 + 0] = 0.382484f;	val_dir[10416*3 + 1] = -0.433482f;	val_dir[10416*3 + 2] = -0.815966f;
+ 	val_dir[10417*3 + 0] = 0.408248f;	val_dir[10417*3 + 1] = -0.408248f;	val_dir[10417*3 + 2] = -0.816497f;
+ 	val_dir[10418*3 + 0] = 0.433482f;	val_dir[10418*3 + 1] = -0.382484f;	val_dir[10418*3 + 2] = -0.815966f;
+ 	val_dir[10419*3 + 0] = 0.458088f;	val_dir[10419*3 + 1] = -0.356291f;	val_dir[10419*3 + 2] = -0.814379f;
+ 	val_dir[10420*3 + 0] = 0.481979f;	val_dir[10420*3 + 1] = -0.329775f;	val_dir[10420*3 + 2] = -0.811754f;
+ 	val_dir[10421*3 + 0] = 0.505076f;	val_dir[10421*3 + 1] = -0.303046f;	val_dir[10421*3 + 2] = -0.808122f;
+ 	val_dir[10422*3 + 0] = 0.527312f;	val_dir[10422*3 + 1] = -0.276211f;	val_dir[10422*3 + 2] = -0.803523f;
+ 	val_dir[10423*3 + 0] = 0.548630f;	val_dir[10423*3 + 1] = -0.249377f;	val_dir[10423*3 + 2] = -0.798007f;
+ 	val_dir[10424*3 + 0] = 0.568986f;	val_dir[10424*3 + 1] = -0.222647f;	val_dir[10424*3 + 2] = -0.791633f;
+ 	val_dir[10425*3 + 0] = 0.588348f;	val_dir[10425*3 + 1] = -0.196116f;	val_dir[10425*3 + 2] = -0.784465f;
+ 	val_dir[10426*3 + 0] = 0.606696f;	val_dir[10426*3 + 1] = -0.169875f;	val_dir[10426*3 + 2] = -0.776571f;
+ 	val_dir[10427*3 + 0] = 0.624020f;	val_dir[10427*3 + 1] = -0.144005f;	val_dir[10427*3 + 2] = -0.768025f;
+ 	val_dir[10428*3 + 0] = 0.640321f;	val_dir[10428*3 + 1] = -0.118578f;	val_dir[10428*3 + 2] = -0.758899f;
+ 	val_dir[10429*3 + 0] = 0.655610f;	val_dir[10429*3 + 1] = -0.093659f;	val_dir[10429*3 + 2] = -0.749269f;
+ 	val_dir[10430*3 + 0] = 0.669905f;	val_dir[10430*3 + 1] = -0.069301f;	val_dir[10430*3 + 2] = -0.739205f;
+ 	val_dir[10431*3 + 0] = 0.683231f;	val_dir[10431*3 + 1] = -0.045549f;	val_dir[10431*3 + 2] = -0.728780f;
+ 	val_dir[10432*3 + 0] = 0.695620f;	val_dir[10432*3 + 1] = -0.022439f;	val_dir[10432*3 + 2] = -0.718059f;
+ 	val_dir[10433*3 + 0] = 0.707107f;	val_dir[10433*3 + 1] = 0.0f;	val_dir[10433*3 + 2] = -0.707107f;
+ 	val_dir[10434*3 + 0] = 0.739754f;	val_dir[10434*3 + 1] = 0.022417f;	val_dir[10434*3 + 2] = -0.672504f;
+ 	val_dir[10435*3 + 0] = 0.771136f;	val_dir[10435*3 + 1] = 0.045361f;	val_dir[10435*3 + 2] = -0.635053f;
+ 	val_dir[10436*3 + 0] = 0.800850f;	val_dir[10436*3 + 1] = 0.068644f;	val_dir[10436*3 + 2] = -0.594917f;
+ 	val_dir[10437*3 + 0] = 0.828517f;	val_dir[10437*3 + 1] = 0.092057f;	val_dir[10437*3 + 2] = -0.552345f;
+ 	val_dir[10438*3 + 0] = 0.853796f;	val_dir[10438*3 + 1] = 0.115378f;	val_dir[10438*3 + 2] = -0.507662f;
+ 	val_dir[10439*3 + 0] = 0.876405f;	val_dir[10439*3 + 1] = 0.138380f;	val_dir[10439*3 + 2] = -0.461266f;
+ 	val_dir[10440*3 + 0] = 0.896137f;	val_dir[10440*3 + 1] = 0.160845f;	val_dir[10440*3 + 2] = -0.413602f;
+ 	val_dir[10441*3 + 0] = 0.912871f;	val_dir[10441*3 + 1] = 0.182574f;	val_dir[10441*3 + 2] = -0.365148f;
+ 	val_dir[10442*3 + 0] = 0.926568f;	val_dir[10442*3 + 1] = 0.203393f;	val_dir[10442*3 + 2] = -0.316389f;
+ 	val_dir[10443*3 + 0] = 0.937276f;	val_dir[10443*3 + 1] = 0.223161f;	val_dir[10443*3 + 2] = -0.267793f;
+ 	val_dir[10444*3 + 0] = 0.945112f;	val_dir[10444*3 + 1] = 0.241773f;	val_dir[10444*3 + 2] = -0.219793f;
+ 	val_dir[10445*3 + 0] = 0.950255f;	val_dir[10445*3 + 1] = 0.259161f;	val_dir[10445*3 + 2] = -0.172774f;
+ 	val_dir[10446*3 + 0] = 0.952928f;	val_dir[10446*3 + 1] = 0.275290f;	val_dir[10446*3 + 2] = -0.127057f;
+ 	val_dir[10447*3 + 0] = 0.953381f;	val_dir[10447*3 + 1] = 0.290159f;	val_dir[10447*3 + 2] = -0.082903f;
+ 	val_dir[10448*3 + 0] = 0.951877f;	val_dir[10448*3 + 1] = 0.303791f;	val_dir[10448*3 + 2] = -0.040505f;
+ 	val_dir[10449*3 + 0] = 0.948683f;	val_dir[10449*3 + 1] = 0.316228f;	val_dir[10449*3 + 2] = 0.0f;
+ 	val_dir[10450*3 + 0] = -0.322198f;	val_dir[10450*3 + 1] = -0.946458f;	val_dir[10450*3 + 2] = -0.020137f;
+ 	val_dir[10451*3 + 0] = -0.309426f;	val_dir[10451*3 + 1] = -0.948908f;	val_dir[10451*3 + 2] = -0.061885f;
+ 	val_dir[10452*3 + 0] = -0.295409f;	val_dir[10452*3 + 1] = -0.949528f;	val_dir[10452*3 + 2] = -0.105503f;
+ 	val_dir[10453*3 + 0] = -0.280105f;	val_dir[10453*3 + 1] = -0.948047f;	val_dir[10453*3 + 2] = -0.150826f;
+ 	val_dir[10454*3 + 0] = -0.263498f;	val_dir[10454*3 + 1] = -0.94420f;	val_dir[10454*3 + 2] = -0.197623f;
+ 	val_dir[10455*3 + 0] = -0.245599f;	val_dir[10455*3 + 1] = -0.937743f;	val_dir[10455*3 + 2] = -0.245599f;
+ 	val_dir[10456*3 + 0] = -0.226455f;	val_dir[10456*3 + 1] = -0.928467f;	val_dir[10456*3 + 2] = -0.294392f;
+ 	val_dir[10457*3 + 0] = -0.206149f;	val_dir[10457*3 + 1] = -0.916217f;	val_dir[10457*3 + 2] = -0.343582f;
+ 	val_dir[10458*3 + 0] = -0.184801f;	val_dir[10458*3 + 1] = -0.900907f;	val_dir[10458*3 + 2] = -0.392703f;
+ 	val_dir[10459*3 + 0] = -0.162571f;	val_dir[10459*3 + 1] = -0.882528f;	val_dir[10459*3 + 2] = -0.441264f;
+ 	val_dir[10460*3 + 0] = -0.139648f;	val_dir[10460*3 + 1] = -0.861164f;	val_dir[10460*3 + 2] = -0.488769f;
+ 	val_dir[10461*3 + 0] = -0.116248f;	val_dir[10461*3 + 1] = -0.836983f;	val_dir[10461*3 + 2] = -0.534739f;
+ 	val_dir[10462*3 + 0] = -0.092599f;	val_dir[10462*3 + 1] = -0.810237f;	val_dir[10462*3 + 2] = -0.578741f;
+ 	val_dir[10463*3 + 0] = -0.068934f;	val_dir[10463*3 + 1] = -0.781248f;	val_dir[10463*3 + 2] = -0.620403f;
+ 	val_dir[10464*3 + 0] = -0.045478f;	val_dir[10464*3 + 1] = -0.750388f;	val_dir[10464*3 + 2] = -0.659432f;
+ 	val_dir[10465*3 + 0] = -0.022439f;	val_dir[10465*3 + 1] = -0.718059f;	val_dir[10465*3 + 2] = -0.695620f;
+ 	val_dir[10466*3 + 0] = 0.0f;	val_dir[10466*3 + 1] = -0.684675f;	val_dir[10466*3 + 2] = -0.728848f;
+ 	val_dir[10467*3 + 0] = 0.022417f;	val_dir[10467*3 + 1] = -0.672504f;	val_dir[10467*3 + 2] = -0.739754f;
+ 	val_dir[10468*3 + 0] = 0.045478f;	val_dir[10468*3 + 1] = -0.659432f;	val_dir[10468*3 + 2] = -0.750388f;
+ 	val_dir[10469*3 + 0] = 0.069153f;	val_dir[10469*3 + 1] = -0.645429f;	val_dir[10469*3 + 2] = -0.760684f;
+ 	val_dir[10470*3 + 0] = 0.093403f;	val_dir[10470*3 + 1] = -0.630470f;	val_dir[10470*3 + 2] = -0.770574f;
+ 	val_dir[10471*3 + 0] = 0.118180f;	val_dir[10471*3 + 1] = -0.614535f;	val_dir[10471*3 + 2] = -0.779987f;
+ 	val_dir[10472*3 + 0] = 0.143427f;	val_dir[10472*3 + 1] = -0.597614f;	val_dir[10472*3 + 2] = -0.788851f;
+ 	val_dir[10473*3 + 0] = 0.169080f;	val_dir[10473*3 + 1] = -0.579703f;	val_dir[10473*3 + 2] = -0.797092f;
+ 	val_dir[10474*3 + 0] = 0.195064f;	val_dir[10474*3 + 1] = -0.560809f;	val_dir[10474*3 + 2] = -0.804639f;
+ 	val_dir[10475*3 + 0] = 0.221297f;	val_dir[10475*3 + 1] = -0.540947f;	val_dir[10475*3 + 2] = -0.811421f;
+ 	val_dir[10476*3 + 0] = 0.247689f;	val_dir[10476*3 + 1] = -0.520146f;	val_dir[10476*3 + 2] = -0.817373f;
+ 	val_dir[10477*3 + 0] = 0.274145f;	val_dir[10477*3 + 1] = -0.498445f;	val_dir[10477*3 + 2] = -0.822434f;
+ 	val_dir[10478*3 + 0] = 0.300564f;	val_dir[10478*3 + 1] = -0.475893f;	val_dir[10478*3 + 2] = -0.826551f;
+ 	val_dir[10479*3 + 0] = 0.326844f;	val_dir[10479*3 + 1] = -0.452553f;	val_dir[10479*3 + 2] = -0.829680f;
+ 	val_dir[10480*3 + 0] = 0.352879f;	val_dir[10480*3 + 1] = -0.428496f;	val_dir[10480*3 + 2] = -0.831786f;
+ 	val_dir[10481*3 + 0] = 0.378566f;	val_dir[10481*3 + 1] = -0.403804f;	val_dir[10481*3 + 2] = -0.832845f;
+ 	val_dir[10482*3 + 0] = 0.403804f;	val_dir[10482*3 + 1] = -0.378566f;	val_dir[10482*3 + 2] = -0.832845f;
+ 	val_dir[10483*3 + 0] = 0.428496f;	val_dir[10483*3 + 1] = -0.352879f;	val_dir[10483*3 + 2] = -0.831786f;
+ 	val_dir[10484*3 + 0] = 0.452553f;	val_dir[10484*3 + 1] = -0.326844f;	val_dir[10484*3 + 2] = -0.829680f;
+ 	val_dir[10485*3 + 0] = 0.475893f;	val_dir[10485*3 + 1] = -0.300564f;	val_dir[10485*3 + 2] = -0.826551f;
+ 	val_dir[10486*3 + 0] = 0.498445f;	val_dir[10486*3 + 1] = -0.274145f;	val_dir[10486*3 + 2] = -0.822434f;
+ 	val_dir[10487*3 + 0] = 0.520146f;	val_dir[10487*3 + 1] = -0.247689f;	val_dir[10487*3 + 2] = -0.817373f;
+ 	val_dir[10488*3 + 0] = 0.540947f;	val_dir[10488*3 + 1] = -0.221297f;	val_dir[10488*3 + 2] = -0.811421f;
+ 	val_dir[10489*3 + 0] = 0.560809f;	val_dir[10489*3 + 1] = -0.195064f;	val_dir[10489*3 + 2] = -0.804639f;
+ 	val_dir[10490*3 + 0] = 0.579703f;	val_dir[10490*3 + 1] = -0.169080f;	val_dir[10490*3 + 2] = -0.797092f;
+ 	val_dir[10491*3 + 0] = 0.597614f;	val_dir[10491*3 + 1] = -0.143427f;	val_dir[10491*3 + 2] = -0.788851f;
+ 	val_dir[10492*3 + 0] = 0.614535f;	val_dir[10492*3 + 1] = -0.118180f;	val_dir[10492*3 + 2] = -0.779987f;
+ 	val_dir[10493*3 + 0] = 0.630470f;	val_dir[10493*3 + 1] = -0.093403f;	val_dir[10493*3 + 2] = -0.770574f;
+ 	val_dir[10494*3 + 0] = 0.645429f;	val_dir[10494*3 + 1] = -0.069153f;	val_dir[10494*3 + 2] = -0.760684f;
+ 	val_dir[10495*3 + 0] = 0.659432f;	val_dir[10495*3 + 1] = -0.045478f;	val_dir[10495*3 + 2] = -0.750388f;
+ 	val_dir[10496*3 + 0] = 0.672504f;	val_dir[10496*3 + 1] = -0.022417f;	val_dir[10496*3 + 2] = -0.739754f;
+ 	val_dir[10497*3 + 0] = 0.684675f;	val_dir[10497*3 + 1] = 0.0f;	val_dir[10497*3 + 2] = -0.728848f;
+ 	val_dir[10498*3 + 0] = 0.718059f;	val_dir[10498*3 + 1] = 0.022439f;	val_dir[10498*3 + 2] = -0.695620f;
+ 	val_dir[10499*3 + 0] = 0.750388f;	val_dir[10499*3 + 1] = 0.045478f;	val_dir[10499*3 + 2] = -0.659432f;
+ 	val_dir[10500*3 + 0] = 0.781248f;	val_dir[10500*3 + 1] = 0.068934f;	val_dir[10500*3 + 2] = -0.620403f;
+ 	val_dir[10501*3 + 0] = 0.810237f;	val_dir[10501*3 + 1] = 0.092599f;	val_dir[10501*3 + 2] = -0.578741f;
+ 	val_dir[10502*3 + 0] = 0.836983f;	val_dir[10502*3 + 1] = 0.116248f;	val_dir[10502*3 + 2] = -0.534739f;
+ 	val_dir[10503*3 + 0] = 0.861164f;	val_dir[10503*3 + 1] = 0.139648f;	val_dir[10503*3 + 2] = -0.488769f;
+ 	val_dir[10504*3 + 0] = 0.882528f;	val_dir[10504*3 + 1] = 0.162571f;	val_dir[10504*3 + 2] = -0.441264f;
+ 	val_dir[10505*3 + 0] = 0.900907f;	val_dir[10505*3 + 1] = 0.184801f;	val_dir[10505*3 + 2] = -0.392703f;
+ 	val_dir[10506*3 + 0] = 0.916217f;	val_dir[10506*3 + 1] = 0.206149f;	val_dir[10506*3 + 2] = -0.343582f;
+ 	val_dir[10507*3 + 0] = 0.928467f;	val_dir[10507*3 + 1] = 0.226455f;	val_dir[10507*3 + 2] = -0.294392f;
+ 	val_dir[10508*3 + 0] = 0.937743f;	val_dir[10508*3 + 1] = 0.245599f;	val_dir[10508*3 + 2] = -0.245599f;
+ 	val_dir[10509*3 + 0] = 0.94420f;	val_dir[10509*3 + 1] = 0.263498f;	val_dir[10509*3 + 2] = -0.197623f;
+ 	val_dir[10510*3 + 0] = 0.948047f;	val_dir[10510*3 + 1] = 0.280105f;	val_dir[10510*3 + 2] = -0.150826f;
+ 	val_dir[10511*3 + 0] = 0.949528f;	val_dir[10511*3 + 1] = 0.295409f;	val_dir[10511*3 + 2] = -0.105503f;
+ 	val_dir[10512*3 + 0] = 0.948908f;	val_dir[10512*3 + 1] = 0.309426f;	val_dir[10512*3 + 2] = -0.061885f;
+ 	val_dir[10513*3 + 0] = 0.946458f;	val_dir[10513*3 + 1] = 0.322198f;	val_dir[10513*3 + 2] = -0.020137f;
+ 	val_dir[10514*3 + 0] = -0.340136f;	val_dir[10514*3 + 1] = -0.940376f;	val_dir[10514*3 + 2] = 0.0f;
+ 	val_dir[10515*3 + 0] = -0.328244f;	val_dir[10515*3 + 1] = -0.943701f;	val_dir[10515*3 + 2] = -0.041030f;
+ 	val_dir[10516*3 + 0] = -0.315109f;	val_dir[10516*3 + 1] = -0.945328f;	val_dir[10516*3 + 2] = -0.084029f;
+ 	val_dir[10517*3 + 0] = -0.300676f;	val_dir[10517*3 + 1] = -0.944981f;	val_dir[10517*3 + 2] = -0.128861f;
+ 	val_dir[10518*3 + 0] = -0.284907f;	val_dir[10518*3 + 1] = -0.942384f;	val_dir[10518*3 + 2] = -0.175327f;
+ 	val_dir[10519*3 + 0] = -0.267793f;	val_dir[10519*3 + 1] = -0.937276f;	val_dir[10519*3 + 2] = -0.223161f;
+ 	val_dir[10520*3 + 0] = -0.249357f;	val_dir[10520*3 + 1] = -0.929421f;	val_dir[10520*3 + 2] = -0.272026f;
+ 	val_dir[10521*3 + 0] = -0.229658f;	val_dir[10521*3 + 1] = -0.918630f;	val_dir[10521*3 + 2] = -0.321521f;
+ 	val_dir[10522*3 + 0] = -0.208795f;	val_dir[10522*3 + 1] = -0.904777f;	val_dir[10522*3 + 2] = -0.371191f;
+ 	val_dir[10523*3 + 0] = -0.186908f;	val_dir[10523*3 + 1] = -0.887812f;	val_dir[10523*3 + 2] = -0.420542f;
+ 	val_dir[10524*3 + 0] = -0.164173f;	val_dir[10524*3 + 1] = -0.867770f;	val_dir[10524*3 + 2] = -0.469065f;
+ 	val_dir[10525*3 + 0] = -0.140797f;	val_dir[10525*3 + 1] = -0.844782f;	val_dir[10525*3 + 2] = -0.516256f;
+ 	val_dir[10526*3 + 0] = -0.117009f;	val_dir[10526*3 + 1] = -0.819064f;	val_dir[10526*3 + 2] = -0.561644f;
+ 	val_dir[10527*3 + 0] = -0.093048f;	val_dir[10527*3 + 1] = -0.790912f;	val_dir[10527*3 + 2] = -0.604815f;
+ 	val_dir[10528*3 + 0] = -0.069153f;	val_dir[10528*3 + 1] = -0.760684f;	val_dir[10528*3 + 2] = -0.645429f;
+ 	val_dir[10529*3 + 0] = -0.045549f;	val_dir[10529*3 + 1] = -0.728780f;	val_dir[10529*3 + 2] = -0.683231f;
+ 	val_dir[10530*3 + 0] = -0.022439f;	val_dir[10530*3 + 1] = -0.695620f;	val_dir[10530*3 + 2] = -0.718059f;
+ 	val_dir[10531*3 + 0] = 0.0f;	val_dir[10531*3 + 1] = -0.661622f;	val_dir[10531*3 + 2] = -0.749838f;
+ 	val_dir[10532*3 + 0] = 0.022372f;	val_dir[10532*3 + 1] = -0.648784f;	val_dir[10532*3 + 2] = -0.760644f;
+ 	val_dir[10533*3 + 0] = 0.045361f;	val_dir[10533*3 + 1] = -0.635053f;	val_dir[10533*3 + 2] = -0.771136f;
+ 	val_dir[10534*3 + 0] = 0.068934f;	val_dir[10534*3 + 1] = -0.620403f;	val_dir[10534*3 + 2] = -0.781248f;
+ 	val_dir[10535*3 + 0] = 0.093048f;	val_dir[10535*3 + 1] = -0.604815f;	val_dir[10535*3 + 2] = -0.790912f;
+ 	val_dir[10536*3 + 0] = 0.117655f;	val_dir[10536*3 + 1] = -0.588276f;	val_dir[10536*3 + 2] = -0.800055f;
+ 	val_dir[10537*3 + 0] = 0.142695f;	val_dir[10537*3 + 1] = -0.570782f;	val_dir[10537*3 + 2] = -0.808608f;
+ 	val_dir[10538*3 + 0] = 0.168102f;	val_dir[10538*3 + 1] = -0.552336f;	val_dir[10538*3 + 2] = -0.816497f;
+ 	val_dir[10539*3 + 0] = 0.193801f;	val_dir[10539*3 + 1] = -0.532952f;	val_dir[10539*3 + 2] = -0.823653f;
+ 	val_dir[10540*3 + 0] = 0.219708f;	val_dir[10540*3 + 1] = -0.512653f;	val_dir[10540*3 + 2] = -0.830009f;
+ 	val_dir[10541*3 + 0] = 0.245737f;	val_dir[10541*3 + 1] = -0.491473f;	val_dir[10541*3 + 2] = -0.835504f;
+ 	val_dir[10542*3 + 0] = 0.271791f;	val_dir[10542*3 + 1] = -0.469458f;	val_dir[10542*3 + 2] = -0.840083f;
+ 	val_dir[10543*3 + 0] = 0.297775f;	val_dir[10543*3 + 1] = -0.446662f;	val_dir[10543*3 + 2] = -0.843696f;
+ 	val_dir[10544*3 + 0] = 0.323587f;	val_dir[10544*3 + 1] = -0.423153f;	val_dir[10544*3 + 2] = -0.846305f;
+ 	val_dir[10545*3 + 0] = 0.349128f;	val_dir[10545*3 + 1] = -0.399004f;	val_dir[10545*3 + 2] = -0.847883f;
+ 	val_dir[10546*3 + 0] = 0.374299f;	val_dir[10546*3 + 1] = -0.374299f;	val_dir[10546*3 + 2] = -0.848411f;
+ 	val_dir[10547*3 + 0] = 0.399004f;	val_dir[10547*3 + 1] = -0.349128f;	val_dir[10547*3 + 2] = -0.847883f;
+ 	val_dir[10548*3 + 0] = 0.423153f;	val_dir[10548*3 + 1] = -0.323587f;	val_dir[10548*3 + 2] = -0.846305f;
+ 	val_dir[10549*3 + 0] = 0.446662f;	val_dir[10549*3 + 1] = -0.297775f;	val_dir[10549*3 + 2] = -0.843696f;
+ 	val_dir[10550*3 + 0] = 0.469458f;	val_dir[10550*3 + 1] = -0.271791f;	val_dir[10550*3 + 2] = -0.840083f;
+ 	val_dir[10551*3 + 0] = 0.491473f;	val_dir[10551*3 + 1] = -0.245737f;	val_dir[10551*3 + 2] = -0.835504f;
+ 	val_dir[10552*3 + 0] = 0.512653f;	val_dir[10552*3 + 1] = -0.219708f;	val_dir[10552*3 + 2] = -0.830009f;
+ 	val_dir[10553*3 + 0] = 0.532952f;	val_dir[10553*3 + 1] = -0.193801f;	val_dir[10553*3 + 2] = -0.823653f;
+ 	val_dir[10554*3 + 0] = 0.552336f;	val_dir[10554*3 + 1] = -0.168102f;	val_dir[10554*3 + 2] = -0.816497f;
+ 	val_dir[10555*3 + 0] = 0.570782f;	val_dir[10555*3 + 1] = -0.142695f;	val_dir[10555*3 + 2] = -0.808608f;
+ 	val_dir[10556*3 + 0] = 0.588276f;	val_dir[10556*3 + 1] = -0.117655f;	val_dir[10556*3 + 2] = -0.800055f;
+ 	val_dir[10557*3 + 0] = 0.604815f;	val_dir[10557*3 + 1] = -0.093048f;	val_dir[10557*3 + 2] = -0.790912f;
+ 	val_dir[10558*3 + 0] = 0.620403f;	val_dir[10558*3 + 1] = -0.068934f;	val_dir[10558*3 + 2] = -0.781248f;
+ 	val_dir[10559*3 + 0] = 0.635053f;	val_dir[10559*3 + 1] = -0.045361f;	val_dir[10559*3 + 2] = -0.771136f;
+ 	val_dir[10560*3 + 0] = 0.648784f;	val_dir[10560*3 + 1] = -0.022372f;	val_dir[10560*3 + 2] = -0.760644f;
+ 	val_dir[10561*3 + 0] = 0.661622f;	val_dir[10561*3 + 1] = 0.0f;	val_dir[10561*3 + 2] = -0.749838f;
+ 	val_dir[10562*3 + 0] = 0.695620f;	val_dir[10562*3 + 1] = 0.022439f;	val_dir[10562*3 + 2] = -0.718059f;
+ 	val_dir[10563*3 + 0] = 0.728780f;	val_dir[10563*3 + 1] = 0.045549f;	val_dir[10563*3 + 2] = -0.683231f;
+ 	val_dir[10564*3 + 0] = 0.760684f;	val_dir[10564*3 + 1] = 0.069153f;	val_dir[10564*3 + 2] = -0.645429f;
+ 	val_dir[10565*3 + 0] = 0.790912f;	val_dir[10565*3 + 1] = 0.093048f;	val_dir[10565*3 + 2] = -0.604815f;
+ 	val_dir[10566*3 + 0] = 0.819064f;	val_dir[10566*3 + 1] = 0.117009f;	val_dir[10566*3 + 2] = -0.561644f;
+ 	val_dir[10567*3 + 0] = 0.844782f;	val_dir[10567*3 + 1] = 0.140797f;	val_dir[10567*3 + 2] = -0.516256f;
+ 	val_dir[10568*3 + 0] = 0.867770f;	val_dir[10568*3 + 1] = 0.164173f;	val_dir[10568*3 + 2] = -0.469065f;
+ 	val_dir[10569*3 + 0] = 0.887812f;	val_dir[10569*3 + 1] = 0.186908f;	val_dir[10569*3 + 2] = -0.420542f;
+ 	val_dir[10570*3 + 0] = 0.904777f;	val_dir[10570*3 + 1] = 0.208795f;	val_dir[10570*3 + 2] = -0.371191f;
+ 	val_dir[10571*3 + 0] = 0.918630f;	val_dir[10571*3 + 1] = 0.229658f;	val_dir[10571*3 + 2] = -0.321521f;
+ 	val_dir[10572*3 + 0] = 0.929421f;	val_dir[10572*3 + 1] = 0.249357f;	val_dir[10572*3 + 2] = -0.272026f;
+ 	val_dir[10573*3 + 0] = 0.937276f;	val_dir[10573*3 + 1] = 0.267793f;	val_dir[10573*3 + 2] = -0.223161f;
+ 	val_dir[10574*3 + 0] = 0.942384f;	val_dir[10574*3 + 1] = 0.284907f;	val_dir[10574*3 + 2] = -0.175327f;
+ 	val_dir[10575*3 + 0] = 0.944981f;	val_dir[10575*3 + 1] = 0.300676f;	val_dir[10575*3 + 2] = -0.128861f;
+ 	val_dir[10576*3 + 0] = 0.945328f;	val_dir[10576*3 + 1] = 0.315109f;	val_dir[10576*3 + 2] = -0.084029f;
+ 	val_dir[10577*3 + 0] = 0.943701f;	val_dir[10577*3 + 1] = 0.328244f;	val_dir[10577*3 + 2] = -0.041030f;
+ 	val_dir[10578*3 + 0] = 0.940376f;	val_dir[10578*3 + 1] = 0.340136f;	val_dir[10578*3 + 2] = 0.0f;
+ 	val_dir[10579*3 + 0] = -0.346578f;	val_dir[10579*3 + 1] = -0.93780f;	val_dir[10579*3 + 2] = -0.020387f;
+ 	val_dir[10580*3 + 0] = -0.334351f;	val_dir[10580*3 + 1] = -0.940361f;	val_dir[10580*3 + 2] = -0.062691f;
+ 	val_dir[10581*3 + 0] = -0.320824f;	val_dir[10581*3 + 1] = -0.941082f;	val_dir[10581*3 + 2] = -0.106941f;
+ 	val_dir[10582*3 + 0] = -0.305942f;	val_dir[10582*3 + 1] = -0.939680f;	val_dir[10582*3 + 2] = -0.152971f;
+ 	val_dir[10583*3 + 0] = -0.289677f;	val_dir[10583*3 + 1] = -0.935879f;	val_dir[10583*3 + 2] = -0.200545f;
+ 	val_dir[10584*3 + 0] = -0.272026f;	val_dir[10584*3 + 1] = -0.929421f;	val_dir[10584*3 + 2] = -0.249357f;
+ 	val_dir[10585*3 + 0] = -0.253024f;	val_dir[10585*3 + 1] = -0.920087f;	val_dir[10585*3 + 2] = -0.299028f;
+ 	val_dir[10586*3 + 0] = -0.232747f;	val_dir[10586*3 + 1] = -0.907713f;	val_dir[10586*3 + 2] = -0.349121f;
+ 	val_dir[10587*3 + 0] = -0.211312f;	val_dir[10587*3 + 1] = -0.892206f;	val_dir[10587*3 + 2] = -0.399145f;
+ 	val_dir[10588*3 + 0] = -0.188877f;	val_dir[10588*3 + 1] = -0.873555f;	val_dir[10588*3 + 2] = -0.448583f;
+ 	val_dir[10589*3 + 0] = -0.165637f;	val_dir[10589*3 + 1] = -0.851847f;	val_dir[10589*3 + 2] = -0.496911f;
+ 	val_dir[10590*3 + 0] = -0.141816f;	val_dir[10590*3 + 1] = -0.827259f;	val_dir[10590*3 + 2] = -0.543627f;
+ 	val_dir[10591*3 + 0] = -0.117655f;	val_dir[10591*3 + 1] = -0.800055f;	val_dir[10591*3 + 2] = -0.588276f;
+ 	val_dir[10592*3 + 0] = -0.093403f;	val_dir[10592*3 + 1] = -0.770574f;	val_dir[10592*3 + 2] = -0.630470f;
+ 	val_dir[10593*3 + 0] = -0.069301f;	val_dir[10593*3 + 1] = -0.739205f;	val_dir[10593*3 + 2] = -0.669905f;
+ 	val_dir[10594*3 + 0] = -0.045572f;	val_dir[10594*3 + 1] = -0.706372f;	val_dir[10594*3 + 2] = -0.706372f;
+ 	val_dir[10595*3 + 0] = -0.022417f;	val_dir[10595*3 + 1] = -0.672504f;	val_dir[10595*3 + 2] = -0.739754f;
+ 	val_dir[10596*3 + 0] = 0.0f;	val_dir[10596*3 + 1] = -0.638018f;	val_dir[10596*3 + 2] = -0.770022f;
+ 	val_dir[10597*3 + 0] = 0.022305f;	val_dir[10597*3 + 1] = -0.624540f;	val_dir[10597*3 + 2] = -0.780675f;
+ 	val_dir[10598*3 + 0] = 0.045198f;	val_dir[10598*3 + 1] = -0.610179f;	val_dir[10598*3 + 2] = -0.790973f;
+ 	val_dir[10599*3 + 0] = 0.068644f;	val_dir[10599*3 + 1] = -0.594917f;	val_dir[10599*3 + 2] = -0.800850f;
+ 	val_dir[10600*3 + 0] = 0.092599f;	val_dir[10600*3 + 1] = -0.578741f;	val_dir[10600*3 + 2] = -0.810237f;
+ 	val_dir[10601*3 + 0] = 0.117009f;	val_dir[10601*3 + 1] = -0.561644f;	val_dir[10601*3 + 2] = -0.819064f;
+ 	val_dir[10602*3 + 0] = 0.141816f;	val_dir[10602*3 + 1] = -0.543627f;	val_dir[10602*3 + 2] = -0.827259f;
+ 	val_dir[10603*3 + 0] = 0.166951f;	val_dir[10603*3 + 1] = -0.524703f;	val_dir[10603*3 + 2] = -0.834754f;
+ 	val_dir[10604*3 + 0] = 0.192339f;	val_dir[10604*3 + 1] = -0.504889f;	val_dir[10604*3 + 2] = -0.841482f;
+ 	val_dir[10605*3 + 0] = 0.217898f;	val_dir[10605*3 + 1] = -0.484217f;	val_dir[10605*3 + 2] = -0.847381f;
+ 	val_dir[10606*3 + 0] = 0.243541f;	val_dir[10606*3 + 1] = -0.462727f;	val_dir[10606*3 + 2] = -0.852392f;
+ 	val_dir[10607*3 + 0] = 0.269175f;	val_dir[10607*3 + 1] = -0.440468f;	val_dir[10607*3 + 2] = -0.856465f;
+ 	val_dir[10608*3 + 0] = 0.294706f;	val_dir[10608*3 + 1] = -0.41750f;	val_dir[10608*3 + 2] = -0.859559f;
+ 	val_dir[10609*3 + 0] = 0.320038f;	val_dir[10609*3 + 1] = -0.393893f;	val_dir[10609*3 + 2] = -0.861640f;
+ 	val_dir[10610*3 + 0] = 0.345075f;	val_dir[10610*3 + 1] = -0.369723f;	val_dir[10610*3 + 2] = -0.862687f;
+ 	val_dir[10611*3 + 0] = 0.369723f;	val_dir[10611*3 + 1] = -0.345075f;	val_dir[10611*3 + 2] = -0.862687f;
+ 	val_dir[10612*3 + 0] = 0.393893f;	val_dir[10612*3 + 1] = -0.320038f;	val_dir[10612*3 + 2] = -0.861640f;
+ 	val_dir[10613*3 + 0] = 0.41750f;	val_dir[10613*3 + 1] = -0.294706f;	val_dir[10613*3 + 2] = -0.859559f;
+ 	val_dir[10614*3 + 0] = 0.440468f;	val_dir[10614*3 + 1] = -0.269175f;	val_dir[10614*3 + 2] = -0.856465f;
+ 	val_dir[10615*3 + 0] = 0.462727f;	val_dir[10615*3 + 1] = -0.243541f;	val_dir[10615*3 + 2] = -0.852392f;
+ 	val_dir[10616*3 + 0] = 0.484217f;	val_dir[10616*3 + 1] = -0.217898f;	val_dir[10616*3 + 2] = -0.847381f;
+ 	val_dir[10617*3 + 0] = 0.504889f;	val_dir[10617*3 + 1] = -0.192339f;	val_dir[10617*3 + 2] = -0.841482f;
+ 	val_dir[10618*3 + 0] = 0.524703f;	val_dir[10618*3 + 1] = -0.166951f;	val_dir[10618*3 + 2] = -0.834754f;
+ 	val_dir[10619*3 + 0] = 0.543627f;	val_dir[10619*3 + 1] = -0.141816f;	val_dir[10619*3 + 2] = -0.827259f;
+ 	val_dir[10620*3 + 0] = 0.561644f;	val_dir[10620*3 + 1] = -0.117009f;	val_dir[10620*3 + 2] = -0.819064f;
+ 	val_dir[10621*3 + 0] = 0.578741f;	val_dir[10621*3 + 1] = -0.092599f;	val_dir[10621*3 + 2] = -0.810237f;
+ 	val_dir[10622*3 + 0] = 0.594917f;	val_dir[10622*3 + 1] = -0.068644f;	val_dir[10622*3 + 2] = -0.800850f;
+ 	val_dir[10623*3 + 0] = 0.610179f;	val_dir[10623*3 + 1] = -0.045198f;	val_dir[10623*3 + 2] = -0.790973f;
+ 	val_dir[10624*3 + 0] = 0.624540f;	val_dir[10624*3 + 1] = -0.022305f;	val_dir[10624*3 + 2] = -0.780675f;
+ 	val_dir[10625*3 + 0] = 0.638018f;	val_dir[10625*3 + 1] = 0.0f;	val_dir[10625*3 + 2] = -0.770022f;
+ 	val_dir[10626*3 + 0] = 0.672504f;	val_dir[10626*3 + 1] = 0.022417f;	val_dir[10626*3 + 2] = -0.739754f;
+ 	val_dir[10627*3 + 0] = 0.706372f;	val_dir[10627*3 + 1] = 0.045572f;	val_dir[10627*3 + 2] = -0.706372f;
+ 	val_dir[10628*3 + 0] = 0.739205f;	val_dir[10628*3 + 1] = 0.069301f;	val_dir[10628*3 + 2] = -0.669905f;
+ 	val_dir[10629*3 + 0] = 0.770574f;	val_dir[10629*3 + 1] = 0.093403f;	val_dir[10629*3 + 2] = -0.630470f;
+ 	val_dir[10630*3 + 0] = 0.800055f;	val_dir[10630*3 + 1] = 0.117655f;	val_dir[10630*3 + 2] = -0.588276f;
+ 	val_dir[10631*3 + 0] = 0.827259f;	val_dir[10631*3 + 1] = 0.141816f;	val_dir[10631*3 + 2] = -0.543627f;
+ 	val_dir[10632*3 + 0] = 0.851847f;	val_dir[10632*3 + 1] = 0.165637f;	val_dir[10632*3 + 2] = -0.496911f;
+ 	val_dir[10633*3 + 0] = 0.873555f;	val_dir[10633*3 + 1] = 0.188877f;	val_dir[10633*3 + 2] = -0.448583f;
+ 	val_dir[10634*3 + 0] = 0.892206f;	val_dir[10634*3 + 1] = 0.211312f;	val_dir[10634*3 + 2] = -0.399145f;
+ 	val_dir[10635*3 + 0] = 0.907713f;	val_dir[10635*3 + 1] = 0.232747f;	val_dir[10635*3 + 2] = -0.349121f;
+ 	val_dir[10636*3 + 0] = 0.920087f;	val_dir[10636*3 + 1] = 0.253024f;	val_dir[10636*3 + 2] = -0.299028f;
+ 	val_dir[10637*3 + 0] = 0.929421f;	val_dir[10637*3 + 1] = 0.272026f;	val_dir[10637*3 + 2] = -0.249357f;
+ 	val_dir[10638*3 + 0] = 0.935879f;	val_dir[10638*3 + 1] = 0.289677f;	val_dir[10638*3 + 2] = -0.200545f;
+ 	val_dir[10639*3 + 0] = 0.939680f;	val_dir[10639*3 + 1] = 0.305942f;	val_dir[10639*3 + 2] = -0.152971f;
+ 	val_dir[10640*3 + 0] = 0.941082f;	val_dir[10640*3 + 1] = 0.320824f;	val_dir[10640*3 + 2] = -0.106941f;
+ 	val_dir[10641*3 + 0] = 0.940361f;	val_dir[10641*3 + 1] = 0.334351f;	val_dir[10641*3 + 2] = -0.062691f;
+ 	val_dir[10642*3 + 0] = 0.93780f;	val_dir[10642*3 + 1] = 0.346578f;	val_dir[10642*3 + 2] = -0.020387f;
+ 	val_dir[10643*3 + 0] = -0.364399f;	val_dir[10643*3 + 1] = -0.931243f;	val_dir[10643*3 + 2] = 0.0f;
+ 	val_dir[10644*3 + 0] = -0.353096f;	val_dir[10644*3 + 1] = -0.934665f;	val_dir[10644*3 + 2] = -0.041541f;
+ 	val_dir[10645*3 + 0] = -0.340503f;	val_dir[10645*3 + 1] = -0.936382f;	val_dir[10645*3 + 2] = -0.085126f;
+ 	val_dir[10646*3 + 0] = -0.326550f;	val_dir[10646*3 + 1] = -0.936111f;	val_dir[10646*3 + 2] = -0.130620f;
+ 	val_dir[10647*3 + 0] = -0.311188f;	val_dir[10647*3 + 1] = -0.933564f;	val_dir[10647*3 + 2] = -0.177822f;
+ 	val_dir[10648*3 + 0] = -0.294392f;	val_dir[10648*3 + 1] = -0.928467f;	val_dir[10648*3 + 2] = -0.226455f;
+ 	val_dir[10649*3 + 0] = -0.276172f;	val_dir[10649*3 + 1] = -0.920575f;	val_dir[10649*3 + 2] = -0.276172f;
+ 	val_dir[10650*3 + 0] = -0.256578f;	val_dir[10650*3 + 1] = -0.909687f;	val_dir[10650*3 + 2] = -0.326554f;
+ 	val_dir[10651*3 + 0] = -0.235702f;	val_dir[10651*3 + 1] = -0.895669f;	val_dir[10651*3 + 2] = -0.377124f;
+ 	val_dir[10652*3 + 0] = -0.213681f;	val_dir[10652*3 + 1] = -0.878466f;	val_dir[10652*3 + 2] = -0.427362f;
+ 	val_dir[10653*3 + 0] = -0.190693f;	val_dir[10653*3 + 1] = -0.858116f;	val_dir[10653*3 + 2] = -0.476731f;
+ 	val_dir[10654*3 + 0] = -0.166951f;	val_dir[10654*3 + 1] = -0.834754f;	val_dir[10654*3 + 2] = -0.524703f;
+ 	val_dir[10655*3 + 0] = -0.142695f;	val_dir[10655*3 + 1] = -0.808608f;	val_dir[10655*3 + 2] = -0.570782f;
+ 	val_dir[10656*3 + 0] = -0.118180f;	val_dir[10656*3 + 1] = -0.779987f;	val_dir[10656*3 + 2] = -0.614535f;
+ 	val_dir[10657*3 + 0] = -0.093659f;	val_dir[10657*3 + 1] = -0.749269f;	val_dir[10657*3 + 2] = -0.655610f;
+ 	val_dir[10658*3 + 0] = -0.069375f;	val_dir[10658*3 + 1] = -0.716871f;	val_dir[10658*3 + 2] = -0.693746f;
+ 	val_dir[10659*3 + 0] = -0.045549f;	val_dir[10659*3 + 1] = -0.683231f;	val_dir[10659*3 + 2] = -0.728780f;
+ 	val_dir[10660*3 + 0] = -0.022372f;	val_dir[10660*3 + 1] = -0.648784f;	val_dir[10660*3 + 2] = -0.760644f;
+ 	val_dir[10661*3 + 0] = 0.0f;	val_dir[10661*3 + 1] = -0.613941f;	val_dir[10661*3 + 2] = -0.789352f;
+ 	val_dir[10662*3 + 0] = 0.022217f;	val_dir[10662*3 + 1] = -0.599852f;	val_dir[10662*3 + 2] = -0.799803f;
+ 	val_dir[10663*3 + 0] = 0.044992f;	val_dir[10663*3 + 1] = -0.584898f;	val_dir[10663*3 + 2] = -0.809858f;
+ 	val_dir[10664*3 + 0] = 0.068288f;	val_dir[10664*3 + 1] = -0.569064f;	val_dir[10664*3 + 2] = -0.819453f;
+ 	val_dir[10665*3 + 0] = 0.092057f;	val_dir[10665*3 + 1] = -0.552345f;	val_dir[10665*3 + 2] = -0.828517f;
+ 	val_dir[10666*3 + 0] = 0.116248f;	val_dir[10666*3 + 1] = -0.534739f;	val_dir[10666*3 + 2] = -0.836983f;
+ 	val_dir[10667*3 + 0] = 0.140797f;	val_dir[10667*3 + 1] = -0.516256f;	val_dir[10667*3 + 2] = -0.844782f;
+ 	val_dir[10668*3 + 0] = 0.165637f;	val_dir[10668*3 + 1] = -0.496911f;	val_dir[10668*3 + 2] = -0.851847f;
+ 	val_dir[10669*3 + 0] = 0.190693f;	val_dir[10669*3 + 1] = -0.476731f;	val_dir[10669*3 + 2] = -0.858116f;
+ 	val_dir[10670*3 + 0] = 0.215883f;	val_dir[10670*3 + 1] = -0.455752f;	val_dir[10670*3 + 2] = -0.863530f;
+ 	val_dir[10671*3 + 0] = 0.241121f;	val_dir[10671*3 + 1] = -0.434019f;	val_dir[10671*3 + 2] = -0.868037f;
+ 	val_dir[10672*3 + 0] = 0.266320f;	val_dir[10672*3 + 1] = -0.411585f;	val_dir[10672*3 + 2] = -0.871592f;
+ 	val_dir[10673*3 + 0] = 0.291386f;	val_dir[10673*3 + 1] = -0.388514f;	val_dir[10673*3 + 2] = -0.874157f;
+ 	val_dir[10674*3 + 0] = 0.316228f;	val_dir[10674*3 + 1] = -0.364878f;	val_dir[10674*3 + 2] = -0.875708f;
+ 	val_dir[10675*3 + 0] = 0.340755f;	val_dir[10675*3 + 1] = -0.340755f;	val_dir[10675*3 + 2] = -0.876226f;
+ 	val_dir[10676*3 + 0] = 0.364878f;	val_dir[10676*3 + 1] = -0.316228f;	val_dir[10676*3 + 2] = -0.875708f;
+ 	val_dir[10677*3 + 0] = 0.388514f;	val_dir[10677*3 + 1] = -0.291386f;	val_dir[10677*3 + 2] = -0.874157f;
+ 	val_dir[10678*3 + 0] = 0.411585f;	val_dir[10678*3 + 1] = -0.266320f;	val_dir[10678*3 + 2] = -0.871592f;
+ 	val_dir[10679*3 + 0] = 0.434019f;	val_dir[10679*3 + 1] = -0.241121f;	val_dir[10679*3 + 2] = -0.868037f;
+ 	val_dir[10680*3 + 0] = 0.455752f;	val_dir[10680*3 + 1] = -0.215883f;	val_dir[10680*3 + 2] = -0.863530f;
+ 	val_dir[10681*3 + 0] = 0.476731f;	val_dir[10681*3 + 1] = -0.190693f;	val_dir[10681*3 + 2] = -0.858116f;
+ 	val_dir[10682*3 + 0] = 0.496911f;	val_dir[10682*3 + 1] = -0.165637f;	val_dir[10682*3 + 2] = -0.851847f;
+ 	val_dir[10683*3 + 0] = 0.516256f;	val_dir[10683*3 + 1] = -0.140797f;	val_dir[10683*3 + 2] = -0.844782f;
+ 	val_dir[10684*3 + 0] = 0.534739f;	val_dir[10684*3 + 1] = -0.116248f;	val_dir[10684*3 + 2] = -0.836983f;
+ 	val_dir[10685*3 + 0] = 0.552345f;	val_dir[10685*3 + 1] = -0.092057f;	val_dir[10685*3 + 2] = -0.828517f;
+ 	val_dir[10686*3 + 0] = 0.569064f;	val_dir[10686*3 + 1] = -0.068288f;	val_dir[10686*3 + 2] = -0.819453f;
+ 	val_dir[10687*3 + 0] = 0.584898f;	val_dir[10687*3 + 1] = -0.044992f;	val_dir[10687*3 + 2] = -0.809858f;
+ 	val_dir[10688*3 + 0] = 0.599852f;	val_dir[10688*3 + 1] = -0.022217f;	val_dir[10688*3 + 2] = -0.799803f;
+ 	val_dir[10689*3 + 0] = 0.613941f;	val_dir[10689*3 + 1] = 0.0f;	val_dir[10689*3 + 2] = -0.789352f;
+ 	val_dir[10690*3 + 0] = 0.648784f;	val_dir[10690*3 + 1] = 0.022372f;	val_dir[10690*3 + 2] = -0.760644f;
+ 	val_dir[10691*3 + 0] = 0.683231f;	val_dir[10691*3 + 1] = 0.045549f;	val_dir[10691*3 + 2] = -0.728780f;
+ 	val_dir[10692*3 + 0] = 0.716871f;	val_dir[10692*3 + 1] = 0.069375f;	val_dir[10692*3 + 2] = -0.693746f;
+ 	val_dir[10693*3 + 0] = 0.749269f;	val_dir[10693*3 + 1] = 0.093659f;	val_dir[10693*3 + 2] = -0.655610f;
+ 	val_dir[10694*3 + 0] = 0.779987f;	val_dir[10694*3 + 1] = 0.118180f;	val_dir[10694*3 + 2] = -0.614535f;
+ 	val_dir[10695*3 + 0] = 0.808608f;	val_dir[10695*3 + 1] = 0.142695f;	val_dir[10695*3 + 2] = -0.570782f;
+ 	val_dir[10696*3 + 0] = 0.834754f;	val_dir[10696*3 + 1] = 0.166951f;	val_dir[10696*3 + 2] = -0.524703f;
+ 	val_dir[10697*3 + 0] = 0.858116f;	val_dir[10697*3 + 1] = 0.190693f;	val_dir[10697*3 + 2] = -0.476731f;
+ 	val_dir[10698*3 + 0] = 0.878466f;	val_dir[10698*3 + 1] = 0.213681f;	val_dir[10698*3 + 2] = -0.427362f;
+ 	val_dir[10699*3 + 0] = 0.895669f;	val_dir[10699*3 + 1] = 0.235702f;	val_dir[10699*3 + 2] = -0.377124f;
+ 	val_dir[10700*3 + 0] = 0.909687f;	val_dir[10700*3 + 1] = 0.256578f;	val_dir[10700*3 + 2] = -0.326554f;
+ 	val_dir[10701*3 + 0] = 0.920575f;	val_dir[10701*3 + 1] = 0.276172f;	val_dir[10701*3 + 2] = -0.276172f;
+ 	val_dir[10702*3 + 0] = 0.928467f;	val_dir[10702*3 + 1] = 0.294392f;	val_dir[10702*3 + 2] = -0.226455f;
+ 	val_dir[10703*3 + 0] = 0.933564f;	val_dir[10703*3 + 1] = 0.311188f;	val_dir[10703*3 + 2] = -0.177822f;
+ 	val_dir[10704*3 + 0] = 0.936111f;	val_dir[10704*3 + 1] = 0.326550f;	val_dir[10704*3 + 2] = -0.130620f;
+ 	val_dir[10705*3 + 0] = 0.936382f;	val_dir[10705*3 + 1] = 0.340503f;	val_dir[10705*3 + 2] = -0.085126f;
+ 	val_dir[10706*3 + 0] = 0.934665f;	val_dir[10706*3 + 1] = 0.353096f;	val_dir[10706*3 + 2] = -0.041541f;
+ 	val_dir[10707*3 + 0] = 0.931243f;	val_dir[10707*3 + 1] = 0.364399f;	val_dir[10707*3 + 2] = 0.0f;
+ 	val_dir[10708*3 + 0] = -0.371312f;	val_dir[10708*3 + 1] = -0.928279f;	val_dir[10708*3 + 2] = -0.020628f;
+ 	val_dir[10709*3 + 0] = -0.359673f;	val_dir[10709*3 + 1] = -0.930917f;	val_dir[10709*3 + 2] = -0.063472f;
+ 	val_dir[10710*3 + 0] = -0.346681f;	val_dir[10710*3 + 1] = -0.931705f;	val_dir[10710*3 + 2] = -0.108338f;
+ 	val_dir[10711*3 + 0] = -0.332269f;	val_dir[10711*3 + 1] = -0.930352f;	val_dir[10711*3 + 2] = -0.155059f;
+ 	val_dir[10712*3 + 0] = -0.316389f;	val_dir[10712*3 + 1] = -0.926568f;	val_dir[10712*3 + 2] = -0.203393f;
+ 	val_dir[10713*3 + 0] = -0.299028f;	val_dir[10713*3 + 1] = -0.920087f;	val_dir[10713*3 + 2] = -0.253024f;
+ 	val_dir[10714*3 + 0] = -0.280209f;	val_dir[10714*3 + 1] = -0.910678f;	val_dir[10714*3 + 2] = -0.303559f;
+ 	val_dir[10715*3 + 0] = -0.259996f;	val_dir[10715*3 + 1] = -0.898167f;	val_dir[10715*3 + 2] = -0.354540f;
+ 	val_dir[10716*3 + 0] = -0.238501f;	val_dir[10716*3 + 1] = -0.882454f;	val_dir[10716*3 + 2] = -0.405452f;
+ 	val_dir[10717*3 + 0] = -0.215883f;	val_dir[10717*3 + 1] = -0.863530f;	val_dir[10717*3 + 2] = -0.455752f;
+ 	val_dir[10718*3 + 0] = -0.192339f;	val_dir[10718*3 + 1] = -0.841482f;	val_dir[10718*3 + 2] = -0.504889f;
+ 	val_dir[10719*3 + 0] = -0.168102f;	val_dir[10719*3 + 1] = -0.816497f;	val_dir[10719*3 + 2] = -0.552336f;
+ 	val_dir[10720*3 + 0] = -0.143427f;	val_dir[10720*3 + 1] = -0.788851f;	val_dir[10720*3 + 2] = -0.597614f;
+ 	val_dir[10721*3 + 0] = -0.118578f;	val_dir[10721*3 + 1] = -0.758899f;	val_dir[10721*3 + 2] = -0.640321f;
+ 	val_dir[10722*3 + 0] = -0.093813f;	val_dir[10722*3 + 1] = -0.727051f;	val_dir[10722*3 + 2] = -0.680144f;
+ 	val_dir[10723*3 + 0] = -0.069375f;	val_dir[10723*3 + 1] = -0.693746f;	val_dir[10723*3 + 2] = -0.716871f;
+ 	val_dir[10724*3 + 0] = -0.045478f;	val_dir[10724*3 + 1] = -0.659432f;	val_dir[10724*3 + 2] = -0.750388f;
+ 	val_dir[10725*3 + 0] = -0.022305f;	val_dir[10725*3 + 1] = -0.624540f;	val_dir[10725*3 + 2] = -0.780675f;
+ 	val_dir[10726*3 + 0] = 0.0f;	val_dir[10726*3 + 1] = -0.589469f;	val_dir[10726*3 + 2] = -0.807791f;
+ 	val_dir[10727*3 + 0] = 0.022108f;	val_dir[10727*3 + 1] = -0.574805f;	val_dir[10727*3 + 2] = -0.817992f;
+ 	val_dir[10728*3 + 0] = 0.044744f;	val_dir[10728*3 + 1] = -0.559297f;	val_dir[10728*3 + 2] = -0.827759f;
+ 	val_dir[10729*3 + 0] = 0.067867f;	val_dir[10729*3 + 1] = -0.542936f;	val_dir[10729*3 + 2] = -0.837027f;
+ 	val_dir[10730*3 + 0] = 0.091430f;	val_dir[10730*3 + 1] = -0.525723f;	val_dir[10730*3 + 2] = -0.845728f;
+ 	val_dir[10731*3 + 0] = 0.115378f;	val_dir[10731*3 + 1] = -0.507662f;	val_dir[10731*3 + 2] = -0.853796f;
+ 	val_dir[10732*3 + 0] = 0.139648f;	val_dir[10732*3 + 1] = -0.488769f;	val_dir[10732*3 + 2] = -0.861164f;
+ 	val_dir[10733*3 + 0] = 0.164173f;	val_dir[10733*3 + 1] = -0.469065f;	val_dir[10733*3 + 2] = -0.867770f;
+ 	val_dir[10734*3 + 0] = 0.188877f;	val_dir[10734*3 + 1] = -0.448583f;	val_dir[10734*3 + 2] = -0.873555f;
+ 	val_dir[10735*3 + 0] = 0.213681f;	val_dir[10735*3 + 1] = -0.427362f;	val_dir[10735*3 + 2] = -0.878466f;
+ 	val_dir[10736*3 + 0] = 0.238501f;	val_dir[10736*3 + 1] = -0.405452f;	val_dir[10736*3 + 2] = -0.882454f;
+ 	val_dir[10737*3 + 0] = 0.263251f;	val_dir[10737*3 + 1] = -0.382911f;	val_dir[10737*3 + 2] = -0.885482f;
+ 	val_dir[10738*3 + 0] = 0.287843f;	val_dir[10738*3 + 1] = -0.359804f;	val_dir[10738*3 + 2] = -0.887517f;
+ 	val_dir[10739*3 + 0] = 0.312190f;	val_dir[10739*3 + 1] = -0.336204f;	val_dir[10739*3 + 2] = -0.888540f;
+ 	val_dir[10740*3 + 0] = 0.336204f;	val_dir[10740*3 + 1] = -0.312190f;	val_dir[10740*3 + 2] = -0.888540f;
+ 	val_dir[10741*3 + 0] = 0.359804f;	val_dir[10741*3 + 1] = -0.287843f;	val_dir[10741*3 + 2] = -0.887517f;
+ 	val_dir[10742*3 + 0] = 0.382911f;	val_dir[10742*3 + 1] = -0.263251f;	val_dir[10742*3 + 2] = -0.885482f;
+ 	val_dir[10743*3 + 0] = 0.405452f;	val_dir[10743*3 + 1] = -0.238501f;	val_dir[10743*3 + 2] = -0.882454f;
+ 	val_dir[10744*3 + 0] = 0.427362f;	val_dir[10744*3 + 1] = -0.213681f;	val_dir[10744*3 + 2] = -0.878466f;
+ 	val_dir[10745*3 + 0] = 0.448583f;	val_dir[10745*3 + 1] = -0.188877f;	val_dir[10745*3 + 2] = -0.873555f;
+ 	val_dir[10746*3 + 0] = 0.469065f;	val_dir[10746*3 + 1] = -0.164173f;	val_dir[10746*3 + 2] = -0.867770f;
+ 	val_dir[10747*3 + 0] = 0.488769f;	val_dir[10747*3 + 1] = -0.139648f;	val_dir[10747*3 + 2] = -0.861164f;
+ 	val_dir[10748*3 + 0] = 0.507662f;	val_dir[10748*3 + 1] = -0.115378f;	val_dir[10748*3 + 2] = -0.853796f;
+ 	val_dir[10749*3 + 0] = 0.525723f;	val_dir[10749*3 + 1] = -0.091430f;	val_dir[10749*3 + 2] = -0.845728f;
+ 	val_dir[10750*3 + 0] = 0.542936f;	val_dir[10750*3 + 1] = -0.067867f;	val_dir[10750*3 + 2] = -0.837027f;
+ 	val_dir[10751*3 + 0] = 0.559297f;	val_dir[10751*3 + 1] = -0.044744f;	val_dir[10751*3 + 2] = -0.827759f;
+ 	val_dir[10752*3 + 0] = 0.574805f;	val_dir[10752*3 + 1] = -0.022108f;	val_dir[10752*3 + 2] = -0.817992f;
+ 	val_dir[10753*3 + 0] = 0.589469f;	val_dir[10753*3 + 1] = 0.0f;	val_dir[10753*3 + 2] = -0.807791f;
+ 	val_dir[10754*3 + 0] = 0.624540f;	val_dir[10754*3 + 1] = 0.022305f;	val_dir[10754*3 + 2] = -0.780675f;
+ 	val_dir[10755*3 + 0] = 0.659432f;	val_dir[10755*3 + 1] = 0.045478f;	val_dir[10755*3 + 2] = -0.750388f;
+ 	val_dir[10756*3 + 0] = 0.693746f;	val_dir[10756*3 + 1] = 0.069375f;	val_dir[10756*3 + 2] = -0.716871f;
+ 	val_dir[10757*3 + 0] = 0.727051f;	val_dir[10757*3 + 1] = 0.093813f;	val_dir[10757*3 + 2] = -0.680144f;
+ 	val_dir[10758*3 + 0] = 0.758899f;	val_dir[10758*3 + 1] = 0.118578f;	val_dir[10758*3 + 2] = -0.640321f;
+ 	val_dir[10759*3 + 0] = 0.788851f;	val_dir[10759*3 + 1] = 0.143427f;	val_dir[10759*3 + 2] = -0.597614f;
+ 	val_dir[10760*3 + 0] = 0.816497f;	val_dir[10760*3 + 1] = 0.168102f;	val_dir[10760*3 + 2] = -0.552336f;
+ 	val_dir[10761*3 + 0] = 0.841482f;	val_dir[10761*3 + 1] = 0.192339f;	val_dir[10761*3 + 2] = -0.504889f;
+ 	val_dir[10762*3 + 0] = 0.863530f;	val_dir[10762*3 + 1] = 0.215883f;	val_dir[10762*3 + 2] = -0.455752f;
+ 	val_dir[10763*3 + 0] = 0.882454f;	val_dir[10763*3 + 1] = 0.238501f;	val_dir[10763*3 + 2] = -0.405452f;
+ 	val_dir[10764*3 + 0] = 0.898167f;	val_dir[10764*3 + 1] = 0.259996f;	val_dir[10764*3 + 2] = -0.354540f;
+ 	val_dir[10765*3 + 0] = 0.910678f;	val_dir[10765*3 + 1] = 0.280209f;	val_dir[10765*3 + 2] = -0.303559f;
+ 	val_dir[10766*3 + 0] = 0.920087f;	val_dir[10766*3 + 1] = 0.299028f;	val_dir[10766*3 + 2] = -0.253024f;
+ 	val_dir[10767*3 + 0] = 0.926568f;	val_dir[10767*3 + 1] = 0.316389f;	val_dir[10767*3 + 2] = -0.203393f;
+ 	val_dir[10768*3 + 0] = 0.930352f;	val_dir[10768*3 + 1] = 0.332269f;	val_dir[10768*3 + 2] = -0.155059f;
+ 	val_dir[10769*3 + 0] = 0.931705f;	val_dir[10769*3 + 1] = 0.346681f;	val_dir[10769*3 + 2] = -0.108338f;
+ 	val_dir[10770*3 + 0] = 0.930917f;	val_dir[10770*3 + 1] = 0.359673f;	val_dir[10770*3 + 2] = -0.063472f;
+ 	val_dir[10771*3 + 0] = 0.928279f;	val_dir[10771*3 + 1] = 0.371312f;	val_dir[10771*3 + 2] = -0.020628f;
+ 	val_dir[10772*3 + 0] = -0.388972f;	val_dir[10772*3 + 1] = -0.921250f;	val_dir[10772*3 + 2] = 0.0f;
+ 	val_dir[10773*3 + 0] = -0.378298f;	val_dir[10773*3 + 1] = -0.924729f;	val_dir[10773*3 + 2] = -0.042033f;
+ 	val_dir[10774*3 + 0] = -0.366291f;	val_dir[10774*3 + 1] = -0.92650f;	val_dir[10774*3 + 2] = -0.086186f;
+ 	val_dir[10775*3 + 0] = -0.352865f;	val_dir[10775*3 + 1] = -0.926270f;	val_dir[10775*3 + 2] = -0.132324f;
+ 	val_dir[10776*3 + 0] = -0.337954f;	val_dir[10776*3 + 1] = -0.923742f;	val_dir[10776*3 + 2] = -0.180242f;
+ 	val_dir[10777*3 + 0] = -0.321521f;	val_dir[10777*3 + 1] = -0.918630f;	val_dir[10777*3 + 2] = -0.229658f;
+ 	val_dir[10778*3 + 0] = -0.303559f;	val_dir[10778*3 + 1] = -0.910678f;	val_dir[10778*3 + 2] = -0.280209f;
+ 	val_dir[10779*3 + 0] = -0.284108f;	val_dir[10779*3 + 1] = -0.899676f;	val_dir[10779*3 + 2] = -0.331460f;
+ 	val_dir[10780*3 + 0] = -0.263251f;	val_dir[10780*3 + 1] = -0.885482f;	val_dir[10780*3 + 2] = -0.382911f;
+ 	val_dir[10781*3 + 0] = -0.241121f;	val_dir[10781*3 + 1] = -0.868037f;	val_dir[10781*3 + 2] = -0.434019f;
+ 	val_dir[10782*3 + 0] = -0.217898f;	val_dir[10782*3 + 1] = -0.847381f;	val_dir[10782*3 + 2] = -0.484217f;
+ 	val_dir[10783*3 + 0] = -0.193801f;	val_dir[10783*3 + 1] = -0.823653f;	val_dir[10783*3 + 2] = -0.532952f;
+ 	val_dir[10784*3 + 0] = -0.169080f;	val_dir[10784*3 + 1] = -0.797092f;	val_dir[10784*3 + 2] = -0.579703f;
+ 	val_dir[10785*3 + 0] = -0.144005f;	val_dir[10785*3 + 1] = -0.768025f;	val_dir[10785*3 + 2] = -0.624020f;
+ 	val_dir[10786*3 + 0] = -0.118846f;	val_dir[10786*3 + 1] = -0.736843f;	val_dir[10786*3 + 2] = -0.665536f;
+ 	val_dir[10787*3 + 0] = -0.093865f;	val_dir[10787*3 + 1] = -0.703985f;	val_dir[10787*3 + 2] = -0.703985f;
+ 	val_dir[10788*3 + 0] = -0.069301f;	val_dir[10788*3 + 1] = -0.669905f;	val_dir[10788*3 + 2] = -0.739205f;
+ 	val_dir[10789*3 + 0] = -0.045361f;	val_dir[10789*3 + 1] = -0.635053f;	val_dir[10789*3 + 2] = -0.771136f;
+ 	val_dir[10790*3 + 0] = -0.022217f;	val_dir[10790*3 + 1] = -0.599852f;	val_dir[10790*3 + 2] = -0.799803f;
+ 	val_dir[10791*3 + 0] = 0.0f;	val_dir[10791*3 + 1] = -0.564684f;	val_dir[10791*3 + 2] = -0.825307f;
+ 	val_dir[10792*3 + 0] = 0.021979f;	val_dir[10792*3 + 1] = -0.549484f;	val_dir[10792*3 + 2] = -0.835215f;
+ 	val_dir[10793*3 + 0] = 0.044455f;	val_dir[10793*3 + 1] = -0.533465f;	val_dir[10793*3 + 2] = -0.844653f;
+ 	val_dir[10794*3 + 0] = 0.067386f;	val_dir[10794*3 + 1] = -0.516626f;	val_dir[10794*3 + 2] = -0.853556f;
+ 	val_dir[10795*3 + 0] = 0.090722f;	val_dir[10795*3 + 1] = -0.498970f;	val_dir[10795*3 + 2] = -0.861857f;
+ 	val_dir[10796*3 + 0] = 0.114407f;	val_dir[10796*3 + 1] = -0.480510f;	val_dir[10796*3 + 2] = -0.869495f;
+ 	val_dir[10797*3 + 0] = 0.138380f;	val_dir[10797*3 + 1] = -0.461266f;	val_dir[10797*3 + 2] = -0.876405f;
+ 	val_dir[10798*3 + 0] = 0.162571f;	val_dir[10798*3 + 1] = -0.441264f;	val_dir[10798*3 + 2] = -0.882528f;
+ 	val_dir[10799*3 + 0] = 0.186908f;	val_dir[10799*3 + 1] = -0.420542f;	val_dir[10799*3 + 2] = -0.887812f;
+ 	val_dir[10800*3 + 0] = 0.211312f;	val_dir[10800*3 + 1] = -0.399145f;	val_dir[10800*3 + 2] = -0.892206f;
+ 	val_dir[10801*3 + 0] = 0.235702f;	val_dir[10801*3 + 1] = -0.377124f;	val_dir[10801*3 + 2] = -0.895669f;
+ 	val_dir[10802*3 + 0] = 0.259996f;	val_dir[10802*3 + 1] = -0.354540f;	val_dir[10802*3 + 2] = -0.898167f;
+ 	val_dir[10803*3 + 0] = 0.284108f;	val_dir[10803*3 + 1] = -0.331460f;	val_dir[10803*3 + 2] = -0.899676f;
+ 	val_dir[10804*3 + 0] = 0.307957f;	val_dir[10804*3 + 1] = -0.307957f;	val_dir[10804*3 + 2] = -0.900181f;
+ 	val_dir[10805*3 + 0] = 0.331460f;	val_dir[10805*3 + 1] = -0.284108f;	val_dir[10805*3 + 2] = -0.899676f;
+ 	val_dir[10806*3 + 0] = 0.354540f;	val_dir[10806*3 + 1] = -0.259996f;	val_dir[10806*3 + 2] = -0.898167f;
+ 	val_dir[10807*3 + 0] = 0.377124f;	val_dir[10807*3 + 1] = -0.235702f;	val_dir[10807*3 + 2] = -0.895669f;
+ 	val_dir[10808*3 + 0] = 0.399145f;	val_dir[10808*3 + 1] = -0.211312f;	val_dir[10808*3 + 2] = -0.892206f;
+ 	val_dir[10809*3 + 0] = 0.420542f;	val_dir[10809*3 + 1] = -0.186908f;	val_dir[10809*3 + 2] = -0.887812f;
+ 	val_dir[10810*3 + 0] = 0.441264f;	val_dir[10810*3 + 1] = -0.162571f;	val_dir[10810*3 + 2] = -0.882528f;
+ 	val_dir[10811*3 + 0] = 0.461266f;	val_dir[10811*3 + 1] = -0.138380f;	val_dir[10811*3 + 2] = -0.876405f;
+ 	val_dir[10812*3 + 0] = 0.480510f;	val_dir[10812*3 + 1] = -0.114407f;	val_dir[10812*3 + 2] = -0.869495f;
+ 	val_dir[10813*3 + 0] = 0.498970f;	val_dir[10813*3 + 1] = -0.090722f;	val_dir[10813*3 + 2] = -0.861857f;
+ 	val_dir[10814*3 + 0] = 0.516626f;	val_dir[10814*3 + 1] = -0.067386f;	val_dir[10814*3 + 2] = -0.853556f;
+ 	val_dir[10815*3 + 0] = 0.533465f;	val_dir[10815*3 + 1] = -0.044455f;	val_dir[10815*3 + 2] = -0.844653f;
+ 	val_dir[10816*3 + 0] = 0.549484f;	val_dir[10816*3 + 1] = -0.021979f;	val_dir[10816*3 + 2] = -0.835215f;
+ 	val_dir[10817*3 + 0] = 0.564684f;	val_dir[10817*3 + 1] = 0.0f;	val_dir[10817*3 + 2] = -0.825307f;
+ 	val_dir[10818*3 + 0] = 0.599852f;	val_dir[10818*3 + 1] = 0.022217f;	val_dir[10818*3 + 2] = -0.799803f;
+ 	val_dir[10819*3 + 0] = 0.635053f;	val_dir[10819*3 + 1] = 0.045361f;	val_dir[10819*3 + 2] = -0.771136f;
+ 	val_dir[10820*3 + 0] = 0.669905f;	val_dir[10820*3 + 1] = 0.069301f;	val_dir[10820*3 + 2] = -0.739205f;
+ 	val_dir[10821*3 + 0] = 0.703985f;	val_dir[10821*3 + 1] = 0.093865f;	val_dir[10821*3 + 2] = -0.703985f;
+ 	val_dir[10822*3 + 0] = 0.736843f;	val_dir[10822*3 + 1] = 0.118846f;	val_dir[10822*3 + 2] = -0.665536f;
+ 	val_dir[10823*3 + 0] = 0.768025f;	val_dir[10823*3 + 1] = 0.144005f;	val_dir[10823*3 + 2] = -0.624020f;
+ 	val_dir[10824*3 + 0] = 0.797092f;	val_dir[10824*3 + 1] = 0.169080f;	val_dir[10824*3 + 2] = -0.579703f;
+ 	val_dir[10825*3 + 0] = 0.823653f;	val_dir[10825*3 + 1] = 0.193801f;	val_dir[10825*3 + 2] = -0.532952f;
+ 	val_dir[10826*3 + 0] = 0.847381f;	val_dir[10826*3 + 1] = 0.217898f;	val_dir[10826*3 + 2] = -0.484217f;
+ 	val_dir[10827*3 + 0] = 0.868037f;	val_dir[10827*3 + 1] = 0.241121f;	val_dir[10827*3 + 2] = -0.434019f;
+ 	val_dir[10828*3 + 0] = 0.885482f;	val_dir[10828*3 + 1] = 0.263251f;	val_dir[10828*3 + 2] = -0.382911f;
+ 	val_dir[10829*3 + 0] = 0.899676f;	val_dir[10829*3 + 1] = 0.284108f;	val_dir[10829*3 + 2] = -0.331460f;
+ 	val_dir[10830*3 + 0] = 0.910678f;	val_dir[10830*3 + 1] = 0.303559f;	val_dir[10830*3 + 2] = -0.280209f;
+ 	val_dir[10831*3 + 0] = 0.918630f;	val_dir[10831*3 + 1] = 0.321521f;	val_dir[10831*3 + 2] = -0.229658f;
+ 	val_dir[10832*3 + 0] = 0.923742f;	val_dir[10832*3 + 1] = 0.337954f;	val_dir[10832*3 + 2] = -0.180242f;
+ 	val_dir[10833*3 + 0] = 0.926270f;	val_dir[10833*3 + 1] = 0.352865f;	val_dir[10833*3 + 2] = -0.132324f;
+ 	val_dir[10834*3 + 0] = 0.92650f;	val_dir[10834*3 + 1] = 0.366291f;	val_dir[10834*3 + 2] = -0.086186f;
+ 	val_dir[10835*3 + 0] = 0.924729f;	val_dir[10835*3 + 1] = 0.378298f;	val_dir[10835*3 + 2] = -0.042033f;
+ 	val_dir[10836*3 + 0] = 0.921250f;	val_dir[10836*3 + 1] = 0.388972f;	val_dir[10836*3 + 2] = 0.0f;
+ 	val_dir[10837*3 + 0] = -0.396350f;	val_dir[10837*3 + 1] = -0.917863f;	val_dir[10837*3 + 2] = -0.020861f;
+ 	val_dir[10838*3 + 0] = -0.385341f;	val_dir[10838*3 + 1] = -0.920537f;	val_dir[10838*3 + 2] = -0.064223f;
+ 	val_dir[10839*3 + 0] = -0.372929f;	val_dir[10839*3 + 1] = -0.921354f;	val_dir[10839*3 + 2] = -0.109685f;
+ 	val_dir[10840*3 + 0] = -0.359030f;	val_dir[10840*3 + 1] = -0.920014f;	val_dir[10840*3 + 2] = -0.157075f;
+ 	val_dir[10841*3 + 0] = -0.343582f;	val_dir[10841*3 + 1] = -0.916217f;	val_dir[10841*3 + 2] = -0.206149f;
+ 	val_dir[10842*3 + 0] = -0.326554f;	val_dir[10842*3 + 1] = -0.909687f;	val_dir[10842*3 + 2] = -0.256578f;
+ 	val_dir[10843*3 + 0] = -0.307957f;	val_dir[10843*3 + 1] = -0.900181f;	val_dir[10843*3 + 2] = -0.307957f;
+ 	val_dir[10844*3 + 0] = -0.287843f;	val_dir[10844*3 + 1] = -0.887517f;	val_dir[10844*3 + 2] = -0.359804f;
+ 	val_dir[10845*3 + 0] = -0.266320f;	val_dir[10845*3 + 1] = -0.871592f;	val_dir[10845*3 + 2] = -0.411585f;
+ 	val_dir[10846*3 + 0] = -0.243541f;	val_dir[10846*3 + 1] = -0.852392f;	val_dir[10846*3 + 2] = -0.462727f;
+ 	val_dir[10847*3 + 0] = -0.219708f;	val_dir[10847*3 + 1] = -0.830009f;	val_dir[10847*3 + 2] = -0.512653f;
+ 	val_dir[10848*3 + 0] = -0.195064f;	val_dir[10848*3 + 1] = -0.804639f;	val_dir[10848*3 + 2] = -0.560809f;
+ 	val_dir[10849*3 + 0] = -0.169875f;	val_dir[10849*3 + 1] = -0.776571f;	val_dir[10849*3 + 2] = -0.606696f;
+ 	val_dir[10850*3 + 0] = -0.144421f;	val_dir[10850*3 + 1] = -0.746176f;	val_dir[10850*3 + 2] = -0.649895f;
+ 	val_dir[10851*3 + 0] = -0.118980f;	val_dir[10851*3 + 1] = -0.713881f;	val_dir[10851*3 + 2] = -0.690085f;
+ 	val_dir[10852*3 + 0] = -0.093813f;	val_dir[10852*3 + 1] = -0.680144f;	val_dir[10852*3 + 2] = -0.727051f;
+ 	val_dir[10853*3 + 0] = -0.069153f;	val_dir[10853*3 + 1] = -0.645429f;	val_dir[10853*3 + 2] = -0.760684f;
+ 	val_dir[10854*3 + 0] = -0.045198f;	val_dir[10854*3 + 1] = -0.610179f;	val_dir[10854*3 + 2] = -0.790973f;
+ 	val_dir[10855*3 + 0] = -0.022108f;	val_dir[10855*3 + 1] = -0.574805f;	val_dir[10855*3 + 2] = -0.817992f;
+ 	val_dir[10856*3 + 0] = 0.0f;	val_dir[10856*3 + 1] = -0.539666f;	val_dir[10856*3 + 2] = -0.841879f;
+ 	val_dir[10857*3 + 0] = 0.021832f;	val_dir[10857*3 + 1] = -0.523973f;	val_dir[10857*3 + 2] = -0.851455f;
+ 	val_dir[10858*3 + 0] = 0.044130f;	val_dir[10858*3 + 1] = -0.507490f;	val_dir[10858*3 + 2] = -0.860527f;
+ 	val_dir[10859*3 + 0] = 0.066848f;	val_dir[10859*3 + 1] = -0.490222f;	val_dir[10859*3 + 2] = -0.869030f;
+ 	val_dir[10860*3 + 0] = 0.089939f;	val_dir[10860*3 + 1] = -0.472178f;	val_dir[10860*3 + 2] = -0.876903f;
+ 	val_dir[10861*3 + 0] = 0.113344f;	val_dir[10861*3 + 1] = -0.453376f;	val_dir[10861*3 + 2] = -0.884083f;
+ 	val_dir[10862*3 + 0] = 0.137002f;	val_dir[10862*3 + 1] = -0.433840f;	val_dir[10862*3 + 2] = -0.890513f;
+ 	val_dir[10863*3 + 0] = 0.160845f;	val_dir[10863*3 + 1] = -0.413602f;	val_dir[10863*3 + 2] = -0.896137f;
+ 	val_dir[10864*3 + 0] = 0.184801f;	val_dir[10864*3 + 1] = -0.392703f;	val_dir[10864*3 + 2] = -0.900907f;
+ 	val_dir[10865*3 + 0] = 0.208795f;	val_dir[10865*3 + 1] = -0.371191f;	val_dir[10865*3 + 2] = -0.904777f;
+ 	val_dir[10866*3 + 0] = 0.232747f;	val_dir[10866*3 + 1] = -0.349121f;	val_dir[10866*3 + 2] = -0.907713f;
+ 	val_dir[10867*3 + 0] = 0.256578f;	val_dir[10867*3 + 1] = -0.326554f;	val_dir[10867*3 + 2] = -0.909687f;
+ 	val_dir[10868*3 + 0] = 0.280209f;	val_dir[10868*3 + 1] = -0.303559f;	val_dir[10868*3 + 2] = -0.910678f;
+ 	val_dir[10869*3 + 0] = 0.303559f;	val_dir[10869*3 + 1] = -0.280209f;	val_dir[10869*3 + 2] = -0.910678f;
+ 	val_dir[10870*3 + 0] = 0.326554f;	val_dir[10870*3 + 1] = -0.256578f;	val_dir[10870*3 + 2] = -0.909687f;
+ 	val_dir[10871*3 + 0] = 0.349121f;	val_dir[10871*3 + 1] = -0.232747f;	val_dir[10871*3 + 2] = -0.907713f;
+ 	val_dir[10872*3 + 0] = 0.371191f;	val_dir[10872*3 + 1] = -0.208795f;	val_dir[10872*3 + 2] = -0.904777f;
+ 	val_dir[10873*3 + 0] = 0.392703f;	val_dir[10873*3 + 1] = -0.184801f;	val_dir[10873*3 + 2] = -0.900907f;
+ 	val_dir[10874*3 + 0] = 0.413602f;	val_dir[10874*3 + 1] = -0.160845f;	val_dir[10874*3 + 2] = -0.896137f;
+ 	val_dir[10875*3 + 0] = 0.433840f;	val_dir[10875*3 + 1] = -0.137002f;	val_dir[10875*3 + 2] = -0.890513f;
+ 	val_dir[10876*3 + 0] = 0.453376f;	val_dir[10876*3 + 1] = -0.113344f;	val_dir[10876*3 + 2] = -0.884083f;
+ 	val_dir[10877*3 + 0] = 0.472178f;	val_dir[10877*3 + 1] = -0.089939f;	val_dir[10877*3 + 2] = -0.876903f;
+ 	val_dir[10878*3 + 0] = 0.490222f;	val_dir[10878*3 + 1] = -0.066848f;	val_dir[10878*3 + 2] = -0.869030f;
+ 	val_dir[10879*3 + 0] = 0.507490f;	val_dir[10879*3 + 1] = -0.044130f;	val_dir[10879*3 + 2] = -0.860527f;
+ 	val_dir[10880*3 + 0] = 0.523973f;	val_dir[10880*3 + 1] = -0.021832f;	val_dir[10880*3 + 2] = -0.851455f;
+ 	val_dir[10881*3 + 0] = 0.539666f;	val_dir[10881*3 + 1] = 0.0f;	val_dir[10881*3 + 2] = -0.841879f;
+ 	val_dir[10882*3 + 0] = 0.574805f;	val_dir[10882*3 + 1] = 0.022108f;	val_dir[10882*3 + 2] = -0.817992f;
+ 	val_dir[10883*3 + 0] = 0.610179f;	val_dir[10883*3 + 1] = 0.045198f;	val_dir[10883*3 + 2] = -0.790973f;
+ 	val_dir[10884*3 + 0] = 0.645429f;	val_dir[10884*3 + 1] = 0.069153f;	val_dir[10884*3 + 2] = -0.760684f;
+ 	val_dir[10885*3 + 0] = 0.680144f;	val_dir[10885*3 + 1] = 0.093813f;	val_dir[10885*3 + 2] = -0.727051f;
+ 	val_dir[10886*3 + 0] = 0.713881f;	val_dir[10886*3 + 1] = 0.118980f;	val_dir[10886*3 + 2] = -0.690085f;
+ 	val_dir[10887*3 + 0] = 0.746176f;	val_dir[10887*3 + 1] = 0.144421f;	val_dir[10887*3 + 2] = -0.649895f;
+ 	val_dir[10888*3 + 0] = 0.776571f;	val_dir[10888*3 + 1] = 0.169875f;	val_dir[10888*3 + 2] = -0.606696f;
+ 	val_dir[10889*3 + 0] = 0.804639f;	val_dir[10889*3 + 1] = 0.195064f;	val_dir[10889*3 + 2] = -0.560809f;
+ 	val_dir[10890*3 + 0] = 0.830009f;	val_dir[10890*3 + 1] = 0.219708f;	val_dir[10890*3 + 2] = -0.512653f;
+ 	val_dir[10891*3 + 0] = 0.852392f;	val_dir[10891*3 + 1] = 0.243541f;	val_dir[10891*3 + 2] = -0.462727f;
+ 	val_dir[10892*3 + 0] = 0.871592f;	val_dir[10892*3 + 1] = 0.266320f;	val_dir[10892*3 + 2] = -0.411585f;
+ 	val_dir[10893*3 + 0] = 0.887517f;	val_dir[10893*3 + 1] = 0.287843f;	val_dir[10893*3 + 2] = -0.359804f;
+ 	val_dir[10894*3 + 0] = 0.900181f;	val_dir[10894*3 + 1] = 0.307957f;	val_dir[10894*3 + 2] = -0.307957f;
+ 	val_dir[10895*3 + 0] = 0.909687f;	val_dir[10895*3 + 1] = 0.326554f;	val_dir[10895*3 + 2] = -0.256578f;
+ 	val_dir[10896*3 + 0] = 0.916217f;	val_dir[10896*3 + 1] = 0.343582f;	val_dir[10896*3 + 2] = -0.206149f;
+ 	val_dir[10897*3 + 0] = 0.920014f;	val_dir[10897*3 + 1] = 0.359030f;	val_dir[10897*3 + 2] = -0.157075f;
+ 	val_dir[10898*3 + 0] = 0.921354f;	val_dir[10898*3 + 1] = 0.372929f;	val_dir[10898*3 + 2] = -0.109685f;
+ 	val_dir[10899*3 + 0] = 0.920537f;	val_dir[10899*3 + 1] = 0.385341f;	val_dir[10899*3 + 2] = -0.064223f;
+ 	val_dir[10900*3 + 0] = 0.917863f;	val_dir[10900*3 + 1] = 0.396350f;	val_dir[10900*3 + 2] = -0.020861f;
+ 	val_dir[10901*3 + 0] = -0.413803f;	val_dir[10901*3 + 1] = -0.910366f;	val_dir[10901*3 + 2] = 0.0f;
+ 	val_dir[10902*3 + 0] = -0.403799f;	val_dir[10902*3 + 1] = -0.913860f;	val_dir[10902*3 + 2] = -0.042505f;
+ 	val_dir[10903*3 + 0] = -0.392419f;	val_dir[10903*3 + 1] = -0.915644f;	val_dir[10903*3 + 2] = -0.087204f;
+ 	val_dir[10904*3 + 0] = -0.379563f;	val_dir[10904*3 + 1] = -0.915416f;	val_dir[10904*3 + 2] = -0.133963f;
+ 	val_dir[10905*3 + 0] = -0.365148f;	val_dir[10905*3 + 1] = -0.912871f;	val_dir[10905*3 + 2] = -0.182574f;
+ 	val_dir[10906*3 + 0] = -0.349121f;	val_dir[10906*3 + 1] = -0.907713f;	val_dir[10906*3 + 2] = -0.232747f;
+ 	val_dir[10907*3 + 0] = -0.331460f;	val_dir[10907*3 + 1] = -0.899676f;	val_dir[10907*3 + 2] = -0.284108f;
+ 	val_dir[10908*3 + 0] = -0.312190f;	val_dir[10908*3 + 1] = -0.888540f;	val_dir[10908*3 + 2] = -0.336204f;
+ 	val_dir[10909*3 + 0] = -0.291386f;	val_dir[10909*3 + 1] = -0.874157f;	val_dir[10909*3 + 2] = -0.388514f;
+ 	val_dir[10910*3 + 0] = -0.269175f;	val_dir[10910*3 + 1] = -0.856465f;	val_dir[10910*3 + 2] = -0.440468f;
+ 	val_dir[10911*3 + 0] = -0.245737f;	val_dir[10911*3 + 1] = -0.835504f;	val_dir[10911*3 + 2] = -0.491473f;
+ 	val_dir[10912*3 + 0] = -0.221297f;	val_dir[10912*3 + 1] = -0.811421f;	val_dir[10912*3 + 2] = -0.540947f;
+ 	val_dir[10913*3 + 0] = -0.196116f;	val_dir[10913*3 + 1] = -0.784465f;	val_dir[10913*3 + 2] = -0.588348f;
+ 	val_dir[10914*3 + 0] = -0.170478f;	val_dir[10914*3 + 1] = -0.754976f;	val_dir[10914*3 + 2] = -0.633205f;
+ 	val_dir[10915*3 + 0] = -0.144673f;	val_dir[10915*3 + 1] = -0.723364f;	val_dir[10915*3 + 2] = -0.675140f;
+ 	val_dir[10916*3 + 0] = -0.118980f;	val_dir[10916*3 + 1] = -0.690085f;	val_dir[10916*3 + 2] = -0.713881f;
+ 	val_dir[10917*3 + 0] = -0.093659f;	val_dir[10917*3 + 1] = -0.655610f;	val_dir[10917*3 + 2] = -0.749269f;
+ 	val_dir[10918*3 + 0] = -0.068934f;	val_dir[10918*3 + 1] = -0.620403f;	val_dir[10918*3 + 2] = -0.781248f;
+ 	val_dir[10919*3 + 0] = -0.044992f;	val_dir[10919*3 + 1] = -0.584898f;	val_dir[10919*3 + 2] = -0.809858f;
+ 	val_dir[10920*3 + 0] = -0.021979f;	val_dir[10920*3 + 1] = -0.549484f;	val_dir[10920*3 + 2] = -0.835215f;
+ 	val_dir[10921*3 + 0] = 0.0f;	val_dir[10921*3 + 1] = -0.514496f;	val_dir[10921*3 + 2] = -0.857493f;
+ 	val_dir[10922*3 + 0] = 0.021668f;	val_dir[10922*3 + 1] = -0.498354f;	val_dir[10922*3 + 2] = -0.866703f;
+ 	val_dir[10923*3 + 0] = 0.043769f;	val_dir[10923*3 + 1] = -0.481457f;	val_dir[10923*3 + 2] = -0.875376f;
+ 	val_dir[10924*3 + 0] = 0.066259f;	val_dir[10924*3 + 1] = -0.463812f;	val_dir[10924*3 + 2] = -0.883452f;
+ 	val_dir[10925*3 + 0] = 0.089087f;	val_dir[10925*3 + 1] = -0.445435f;	val_dir[10925*3 + 2] = -0.890871f;
+ 	val_dir[10926*3 + 0] = 0.112197f;	val_dir[10926*3 + 1] = -0.426348f;	val_dir[10926*3 + 2] = -0.897574f;
+ 	val_dir[10927*3 + 0] = 0.135526f;	val_dir[10927*3 + 1] = -0.406579f;	val_dir[10927*3 + 2] = -0.903508f;
+ 	val_dir[10928*3 + 0] = 0.159009f;	val_dir[10928*3 + 1] = -0.386164f;	val_dir[10928*3 + 2] = -0.908622f;
+ 	val_dir[10929*3 + 0] = 0.182574f;	val_dir[10929*3 + 1] = -0.365148f;	val_dir[10929*3 + 2] = -0.912871f;
+ 	val_dir[10930*3 + 0] = 0.206149f;	val_dir[10930*3 + 1] = -0.343582f;	val_dir[10930*3 + 2] = -0.916217f;
+ 	val_dir[10931*3 + 0] = 0.229658f;	val_dir[10931*3 + 1] = -0.321521f;	val_dir[10931*3 + 2] = -0.918630f;
+ 	val_dir[10932*3 + 0] = 0.253024f;	val_dir[10932*3 + 1] = -0.299028f;	val_dir[10932*3 + 2] = -0.920087f;
+ 	val_dir[10933*3 + 0] = 0.276172f;	val_dir[10933*3 + 1] = -0.276172f;	val_dir[10933*3 + 2] = -0.920575f;
+ 	val_dir[10934*3 + 0] = 0.299028f;	val_dir[10934*3 + 1] = -0.253024f;	val_dir[10934*3 + 2] = -0.920087f;
+ 	val_dir[10935*3 + 0] = 0.321521f;	val_dir[10935*3 + 1] = -0.229658f;	val_dir[10935*3 + 2] = -0.918630f;
+ 	val_dir[10936*3 + 0] = 0.343582f;	val_dir[10936*3 + 1] = -0.206149f;	val_dir[10936*3 + 2] = -0.916217f;
+ 	val_dir[10937*3 + 0] = 0.365148f;	val_dir[10937*3 + 1] = -0.182574f;	val_dir[10937*3 + 2] = -0.912871f;
+ 	val_dir[10938*3 + 0] = 0.386164f;	val_dir[10938*3 + 1] = -0.159009f;	val_dir[10938*3 + 2] = -0.908622f;
+ 	val_dir[10939*3 + 0] = 0.406579f;	val_dir[10939*3 + 1] = -0.135526f;	val_dir[10939*3 + 2] = -0.903508f;
+ 	val_dir[10940*3 + 0] = 0.426348f;	val_dir[10940*3 + 1] = -0.112197f;	val_dir[10940*3 + 2] = -0.897574f;
+ 	val_dir[10941*3 + 0] = 0.445435f;	val_dir[10941*3 + 1] = -0.089087f;	val_dir[10941*3 + 2] = -0.890871f;
+ 	val_dir[10942*3 + 0] = 0.463812f;	val_dir[10942*3 + 1] = -0.066259f;	val_dir[10942*3 + 2] = -0.883452f;
+ 	val_dir[10943*3 + 0] = 0.481457f;	val_dir[10943*3 + 1] = -0.043769f;	val_dir[10943*3 + 2] = -0.875376f;
+ 	val_dir[10944*3 + 0] = 0.498354f;	val_dir[10944*3 + 1] = -0.021668f;	val_dir[10944*3 + 2] = -0.866703f;
+ 	val_dir[10945*3 + 0] = 0.514496f;	val_dir[10945*3 + 1] = 0.0f;	val_dir[10945*3 + 2] = -0.857493f;
+ 	val_dir[10946*3 + 0] = 0.549484f;	val_dir[10946*3 + 1] = 0.021979f;	val_dir[10946*3 + 2] = -0.835215f;
+ 	val_dir[10947*3 + 0] = 0.584898f;	val_dir[10947*3 + 1] = 0.044992f;	val_dir[10947*3 + 2] = -0.809858f;
+ 	val_dir[10948*3 + 0] = 0.620403f;	val_dir[10948*3 + 1] = 0.068934f;	val_dir[10948*3 + 2] = -0.781248f;
+ 	val_dir[10949*3 + 0] = 0.655610f;	val_dir[10949*3 + 1] = 0.093659f;	val_dir[10949*3 + 2] = -0.749269f;
+ 	val_dir[10950*3 + 0] = 0.690085f;	val_dir[10950*3 + 1] = 0.118980f;	val_dir[10950*3 + 2] = -0.713881f;
+ 	val_dir[10951*3 + 0] = 0.723364f;	val_dir[10951*3 + 1] = 0.144673f;	val_dir[10951*3 + 2] = -0.675140f;
+ 	val_dir[10952*3 + 0] = 0.754976f;	val_dir[10952*3 + 1] = 0.170478f;	val_dir[10952*3 + 2] = -0.633205f;
+ 	val_dir[10953*3 + 0] = 0.784465f;	val_dir[10953*3 + 1] = 0.196116f;	val_dir[10953*3 + 2] = -0.588348f;
+ 	val_dir[10954*3 + 0] = 0.811421f;	val_dir[10954*3 + 1] = 0.221297f;	val_dir[10954*3 + 2] = -0.540947f;
+ 	val_dir[10955*3 + 0] = 0.835504f;	val_dir[10955*3 + 1] = 0.245737f;	val_dir[10955*3 + 2] = -0.491473f;
+ 	val_dir[10956*3 + 0] = 0.856465f;	val_dir[10956*3 + 1] = 0.269175f;	val_dir[10956*3 + 2] = -0.440468f;
+ 	val_dir[10957*3 + 0] = 0.874157f;	val_dir[10957*3 + 1] = 0.291386f;	val_dir[10957*3 + 2] = -0.388514f;
+ 	val_dir[10958*3 + 0] = 0.888540f;	val_dir[10958*3 + 1] = 0.312190f;	val_dir[10958*3 + 2] = -0.336204f;
+ 	val_dir[10959*3 + 0] = 0.899676f;	val_dir[10959*3 + 1] = 0.331460f;	val_dir[10959*3 + 2] = -0.284108f;
+ 	val_dir[10960*3 + 0] = 0.907713f;	val_dir[10960*3 + 1] = 0.349121f;	val_dir[10960*3 + 2] = -0.232747f;
+ 	val_dir[10961*3 + 0] = 0.912871f;	val_dir[10961*3 + 1] = 0.365148f;	val_dir[10961*3 + 2] = -0.182574f;
+ 	val_dir[10962*3 + 0] = 0.915416f;	val_dir[10962*3 + 1] = 0.379563f;	val_dir[10962*3 + 2] = -0.133963f;
+ 	val_dir[10963*3 + 0] = 0.915644f;	val_dir[10963*3 + 1] = 0.392419f;	val_dir[10963*3 + 2] = -0.087204f;
+ 	val_dir[10964*3 + 0] = 0.913860f;	val_dir[10964*3 + 1] = 0.403799f;	val_dir[10964*3 + 2] = -0.042505f;
+ 	val_dir[10965*3 + 0] = 0.910366f;	val_dir[10965*3 + 1] = 0.413803f;	val_dir[10965*3 + 2] = 0.0f;
+ 	val_dir[10966*3 + 0] = -0.421637f;	val_dir[10966*3 + 1] = -0.906520f;	val_dir[10966*3 + 2] = -0.021082f;
+ 	val_dir[10967*3 + 0] = -0.411298f;	val_dir[10967*3 + 1] = -0.909185f;	val_dir[10967*3 + 2] = -0.064942f;
+ 	val_dir[10968*3 + 0] = -0.399507f;	val_dir[10968*3 + 1] = -0.909988f;	val_dir[10968*3 + 2] = -0.110974f;
+ 	val_dir[10969*3 + 0] = -0.386164f;	val_dir[10969*3 + 1] = -0.908622f;	val_dir[10969*3 + 2] = -0.159009f;
+ 	val_dir[10970*3 + 0] = -0.371191f;	val_dir[10970*3 + 1] = -0.904777f;	val_dir[10970*3 + 2] = -0.208795f;
+ 	val_dir[10971*3 + 0] = -0.354540f;	val_dir[10971*3 + 1] = -0.898167f;	val_dir[10971*3 + 2] = -0.259996f;
+ 	val_dir[10972*3 + 0] = -0.336204f;	val_dir[10972*3 + 1] = -0.888540f;	val_dir[10972*3 + 2] = -0.312190f;
+ 	val_dir[10973*3 + 0] = -0.316228f;	val_dir[10973*3 + 1] = -0.875708f;	val_dir[10973*3 + 2] = -0.364878f;
+ 	val_dir[10974*3 + 0] = -0.294706f;	val_dir[10974*3 + 1] = -0.859559f;	val_dir[10974*3 + 2] = -0.41750f;
+ 	val_dir[10975*3 + 0] = -0.271791f;	val_dir[10975*3 + 1] = -0.840083f;	val_dir[10975*3 + 2] = -0.469458f;
+ 	val_dir[10976*3 + 0] = -0.247689f;	val_dir[10976*3 + 1] = -0.817373f;	val_dir[10976*3 + 2] = -0.520146f;
+ 	val_dir[10977*3 + 0] = -0.222647f;	val_dir[10977*3 + 1] = -0.791633f;	val_dir[10977*3 + 2] = -0.568986f;
+ 	val_dir[10978*3 + 0] = -0.196946f;	val_dir[10978*3 + 1] = -0.763167f;	val_dir[10978*3 + 2] = -0.615457f;
+ 	val_dir[10979*3 + 0] = -0.170884f;	val_dir[10979*3 + 1] = -0.732361f;	val_dir[10979*3 + 2] = -0.659125f;
+ 	val_dir[10980*3 + 0] = -0.144757f;	val_dir[10980*3 + 1] = -0.699659f;	val_dir[10980*3 + 2] = -0.699659f;
+ 	val_dir[10981*3 + 0] = -0.118846f;	val_dir[10981*3 + 1] = -0.665536f;	val_dir[10981*3 + 2] = -0.736843f;
+ 	val_dir[10982*3 + 0] = -0.093403f;	val_dir[10982*3 + 1] = -0.630470f;	val_dir[10982*3 + 2] = -0.770574f;
+ 	val_dir[10983*3 + 0] = -0.068644f;	val_dir[10983*3 + 1] = -0.594917f;	val_dir[10983*3 + 2] = -0.800850f;
+ 	val_dir[10984*3 + 0] = -0.044744f;	val_dir[10984*3 + 1] = -0.559297f;	val_dir[10984*3 + 2] = -0.827759f;
+ 	val_dir[10985*3 + 0] = -0.021832f;	val_dir[10985*3 + 1] = -0.523973f;	val_dir[10985*3 + 2] = -0.851455f;
+ 	val_dir[10986*3 + 0] = 0.0f;	val_dir[10986*3 + 1] = -0.489251f;	val_dir[10986*3 + 2] = -0.872143f;
+ 	val_dir[10987*3 + 0] = 0.021487f;	val_dir[10987*3 + 1] = -0.472709f;	val_dir[10987*3 + 2] = -0.880957f;
+ 	val_dir[10988*3 + 0] = 0.043376f;	val_dir[10988*3 + 1] = -0.455447f;	val_dir[10988*3 + 2] = -0.889206f;
+ 	val_dir[10989*3 + 0] = 0.065622f;	val_dir[10989*3 + 1] = -0.437479f;	val_dir[10989*3 + 2] = -0.896831f;
+ 	val_dir[10990*3 + 0] = 0.088173f;	val_dir[10990*3 + 1] = -0.418823f;	val_dir[10990*3 + 2] = -0.903777f;
+ 	val_dir[10991*3 + 0] = 0.110974f;	val_dir[10991*3 + 1] = -0.399507f;	val_dir[10991*3 + 2] = -0.909988f;
+ 	val_dir[10992*3 + 0] = 0.133963f;	val_dir[10992*3 + 1] = -0.379563f;	val_dir[10992*3 + 2] = -0.915416f;
+ 	val_dir[10993*3 + 0] = 0.157075f;	val_dir[10993*3 + 1] = -0.359030f;	val_dir[10993*3 + 2] = -0.920014f;
+ 	val_dir[10994*3 + 0] = 0.180242f;	val_dir[10994*3 + 1] = -0.337954f;	val_dir[10994*3 + 2] = -0.923742f;
+ 	val_dir[10995*3 + 0] = 0.203393f;	val_dir[10995*3 + 1] = -0.316389f;	val_dir[10995*3 + 2] = -0.926568f;
+ 	val_dir[10996*3 + 0] = 0.226455f;	val_dir[10996*3 + 1] = -0.294392f;	val_dir[10996*3 + 2] = -0.928467f;
+ 	val_dir[10997*3 + 0] = 0.249357f;	val_dir[10997*3 + 1] = -0.272026f;	val_dir[10997*3 + 2] = -0.929421f;
+ 	val_dir[10998*3 + 0] = 0.272026f;	val_dir[10998*3 + 1] = -0.249357f;	val_dir[10998*3 + 2] = -0.929421f;
+ 	val_dir[10999*3 + 0] = 0.294392f;	val_dir[10999*3 + 1] = -0.226455f;	val_dir[10999*3 + 2] = -0.928467f;
+ 	val_dir[11000*3 + 0] = 0.316389f;	val_dir[11000*3 + 1] = -0.203393f;	val_dir[11000*3 + 2] = -0.926568f;
+ 	val_dir[11001*3 + 0] = 0.337954f;	val_dir[11001*3 + 1] = -0.180242f;	val_dir[11001*3 + 2] = -0.923742f;
+ 	val_dir[11002*3 + 0] = 0.359030f;	val_dir[11002*3 + 1] = -0.157075f;	val_dir[11002*3 + 2] = -0.920014f;
+ 	val_dir[11003*3 + 0] = 0.379563f;	val_dir[11003*3 + 1] = -0.133963f;	val_dir[11003*3 + 2] = -0.915416f;
+ 	val_dir[11004*3 + 0] = 0.399507f;	val_dir[11004*3 + 1] = -0.110974f;	val_dir[11004*3 + 2] = -0.909988f;
+ 	val_dir[11005*3 + 0] = 0.418823f;	val_dir[11005*3 + 1] = -0.088173f;	val_dir[11005*3 + 2] = -0.903777f;
+ 	val_dir[11006*3 + 0] = 0.437479f;	val_dir[11006*3 + 1] = -0.065622f;	val_dir[11006*3 + 2] = -0.896831f;
+ 	val_dir[11007*3 + 0] = 0.455447f;	val_dir[11007*3 + 1] = -0.043376f;	val_dir[11007*3 + 2] = -0.889206f;
+ 	val_dir[11008*3 + 0] = 0.472709f;	val_dir[11008*3 + 1] = -0.021487f;	val_dir[11008*3 + 2] = -0.880957f;
+ 	val_dir[11009*3 + 0] = 0.489251f;	val_dir[11009*3 + 1] = 0.0f;	val_dir[11009*3 + 2] = -0.872143f;
+ 	val_dir[11010*3 + 0] = 0.523973f;	val_dir[11010*3 + 1] = 0.021832f;	val_dir[11010*3 + 2] = -0.851455f;
+ 	val_dir[11011*3 + 0] = 0.559297f;	val_dir[11011*3 + 1] = 0.044744f;	val_dir[11011*3 + 2] = -0.827759f;
+ 	val_dir[11012*3 + 0] = 0.594917f;	val_dir[11012*3 + 1] = 0.068644f;	val_dir[11012*3 + 2] = -0.800850f;
+ 	val_dir[11013*3 + 0] = 0.630470f;	val_dir[11013*3 + 1] = 0.093403f;	val_dir[11013*3 + 2] = -0.770574f;
+ 	val_dir[11014*3 + 0] = 0.665536f;	val_dir[11014*3 + 1] = 0.118846f;	val_dir[11014*3 + 2] = -0.736843f;
+ 	val_dir[11015*3 + 0] = 0.699659f;	val_dir[11015*3 + 1] = 0.144757f;	val_dir[11015*3 + 2] = -0.699659f;
+ 	val_dir[11016*3 + 0] = 0.732361f;	val_dir[11016*3 + 1] = 0.170884f;	val_dir[11016*3 + 2] = -0.659125f;
+ 	val_dir[11017*3 + 0] = 0.763167f;	val_dir[11017*3 + 1] = 0.196946f;	val_dir[11017*3 + 2] = -0.615457f;
+ 	val_dir[11018*3 + 0] = 0.791633f;	val_dir[11018*3 + 1] = 0.222647f;	val_dir[11018*3 + 2] = -0.568986f;
+ 	val_dir[11019*3 + 0] = 0.817373f;	val_dir[11019*3 + 1] = 0.247689f;	val_dir[11019*3 + 2] = -0.520146f;
+ 	val_dir[11020*3 + 0] = 0.840083f;	val_dir[11020*3 + 1] = 0.271791f;	val_dir[11020*3 + 2] = -0.469458f;
+ 	val_dir[11021*3 + 0] = 0.859559f;	val_dir[11021*3 + 1] = 0.294706f;	val_dir[11021*3 + 2] = -0.41750f;
+ 	val_dir[11022*3 + 0] = 0.875708f;	val_dir[11022*3 + 1] = 0.316228f;	val_dir[11022*3 + 2] = -0.364878f;
+ 	val_dir[11023*3 + 0] = 0.888540f;	val_dir[11023*3 + 1] = 0.336204f;	val_dir[11023*3 + 2] = -0.312190f;
+ 	val_dir[11024*3 + 0] = 0.898167f;	val_dir[11024*3 + 1] = 0.354540f;	val_dir[11024*3 + 2] = -0.259996f;
+ 	val_dir[11025*3 + 0] = 0.904777f;	val_dir[11025*3 + 1] = 0.371191f;	val_dir[11025*3 + 2] = -0.208795f;
+ 	val_dir[11026*3 + 0] = 0.908622f;	val_dir[11026*3 + 1] = 0.386164f;	val_dir[11026*3 + 2] = -0.159009f;
+ 	val_dir[11027*3 + 0] = 0.909988f;	val_dir[11027*3 + 1] = 0.399507f;	val_dir[11027*3 + 2] = -0.110974f;
+ 	val_dir[11028*3 + 0] = 0.909185f;	val_dir[11028*3 + 1] = 0.411298f;	val_dir[11028*3 + 2] = -0.064942f;
+ 	val_dir[11029*3 + 0] = 0.906520f;	val_dir[11029*3 + 1] = 0.421637f;	val_dir[11029*3 + 2] = -0.021082f;
+ 	val_dir[11030*3 + 0] = -0.438835f;	val_dir[11030*3 + 1] = -0.898567f;	val_dir[11030*3 + 2] = 0.0f;
+ 	val_dir[11031*3 + 0] = -0.429537f;	val_dir[11031*3 + 1] = -0.902027f;	val_dir[11031*3 + 2] = -0.042954f;
+ 	val_dir[11032*3 + 0] = -0.418823f;	val_dir[11032*3 + 1] = -0.903777f;	val_dir[11032*3 + 2] = -0.088173f;
+ 	val_dir[11033*3 + 0] = -0.406579f;	val_dir[11033*3 + 1] = -0.903508f;	val_dir[11033*3 + 2] = -0.135526f;
+ 	val_dir[11034*3 + 0] = -0.392703f;	val_dir[11034*3 + 1] = -0.900907f;	val_dir[11034*3 + 2] = -0.184801f;
+ 	val_dir[11035*3 + 0] = -0.377124f;	val_dir[11035*3 + 1] = -0.895669f;	val_dir[11035*3 + 2] = -0.235702f;
+ 	val_dir[11036*3 + 0] = -0.359804f;	val_dir[11036*3 + 1] = -0.887517f;	val_dir[11036*3 + 2] = -0.287843f;
+ 	val_dir[11037*3 + 0] = -0.340755f;	val_dir[11037*3 + 1] = -0.876226f;	val_dir[11037*3 + 2] = -0.340755f;
+ 	val_dir[11038*3 + 0] = -0.320038f;	val_dir[11038*3 + 1] = -0.861640f;	val_dir[11038*3 + 2] = -0.393893f;
+ 	val_dir[11039*3 + 0] = -0.297775f;	val_dir[11039*3 + 1] = -0.843696f;	val_dir[11039*3 + 2] = -0.446662f;
+ 	val_dir[11040*3 + 0] = -0.274145f;	val_dir[11040*3 + 1] = -0.822434f;	val_dir[11040*3 + 2] = -0.498445f;
+ 	val_dir[11041*3 + 0] = -0.249377f;	val_dir[11041*3 + 1] = -0.798007f;	val_dir[11041*3 + 2] = -0.548630f;
+ 	val_dir[11042*3 + 0] = -0.223745f;	val_dir[11042*3 + 1] = -0.770677f;	val_dir[11042*3 + 2] = -0.596653f;
+ 	val_dir[11043*3 + 0] = -0.197546f;	val_dir[11043*3 + 1] = -0.740797f;	val_dir[11043*3 + 2] = -0.642024f;
+ 	val_dir[11044*3 + 0] = -0.171088f;	val_dir[11044*3 + 1] = -0.708794f;	val_dir[11044*3 + 2] = -0.684353f;
+ 	val_dir[11045*3 + 0] = -0.144673f;	val_dir[11045*3 + 1] = -0.675140f;	val_dir[11045*3 + 2] = -0.723364f;
+ 	val_dir[11046*3 + 0] = -0.118578f;	val_dir[11046*3 + 1] = -0.640321f;	val_dir[11046*3 + 2] = -0.758899f;
+ 	val_dir[11047*3 + 0] = -0.093048f;	val_dir[11047*3 + 1] = -0.604815f;	val_dir[11047*3 + 2] = -0.790912f;
+ 	val_dir[11048*3 + 0] = -0.068288f;	val_dir[11048*3 + 1] = -0.569064f;	val_dir[11048*3 + 2] = -0.819453f;
+ 	val_dir[11049*3 + 0] = -0.044455f;	val_dir[11049*3 + 1] = -0.533465f;	val_dir[11049*3 + 2] = -0.844653f;
+ 	val_dir[11050*3 + 0] = -0.021668f;	val_dir[11050*3 + 1] = -0.498354f;	val_dir[11050*3 + 2] = -0.866703f;
+ 	val_dir[11051*3 + 0] = 0.0f;	val_dir[11051*3 + 1] = -0.464007f;	val_dir[11051*3 + 2] = -0.885832f;
+ 	val_dir[11052*3 + 0] = 0.021291f;	val_dir[11052*3 + 1] = -0.447112f;	val_dir[11052*3 + 2] = -0.894224f;
+ 	val_dir[11053*3 + 0] = 0.042954f;	val_dir[11053*3 + 1] = -0.429537f;	val_dir[11053*3 + 2] = -0.902027f;
+ 	val_dir[11054*3 + 0] = 0.064942f;	val_dir[11054*3 + 1] = -0.411298f;	val_dir[11054*3 + 2] = -0.909185f;
+ 	val_dir[11055*3 + 0] = 0.087204f;	val_dir[11055*3 + 1] = -0.392419f;	val_dir[11055*3 + 2] = -0.915644f;
+ 	val_dir[11056*3 + 0] = 0.109685f;	val_dir[11056*3 + 1] = -0.372929f;	val_dir[11056*3 + 2] = -0.921354f;
+ 	val_dir[11057*3 + 0] = 0.132324f;	val_dir[11057*3 + 1] = -0.352865f;	val_dir[11057*3 + 2] = -0.926270f;
+ 	val_dir[11058*3 + 0] = 0.155059f;	val_dir[11058*3 + 1] = -0.332269f;	val_dir[11058*3 + 2] = -0.930352f;
+ 	val_dir[11059*3 + 0] = 0.177822f;	val_dir[11059*3 + 1] = -0.311188f;	val_dir[11059*3 + 2] = -0.933564f;
+ 	val_dir[11060*3 + 0] = 0.200545f;	val_dir[11060*3 + 1] = -0.289677f;	val_dir[11060*3 + 2] = -0.935879f;
+ 	val_dir[11061*3 + 0] = 0.223161f;	val_dir[11061*3 + 1] = -0.267793f;	val_dir[11061*3 + 2] = -0.937276f;
+ 	val_dir[11062*3 + 0] = 0.245599f;	val_dir[11062*3 + 1] = -0.245599f;	val_dir[11062*3 + 2] = -0.937743f;
+ 	val_dir[11063*3 + 0] = 0.267793f;	val_dir[11063*3 + 1] = -0.223161f;	val_dir[11063*3 + 2] = -0.937276f;
+ 	val_dir[11064*3 + 0] = 0.289677f;	val_dir[11064*3 + 1] = -0.200545f;	val_dir[11064*3 + 2] = -0.935879f;
+ 	val_dir[11065*3 + 0] = 0.311188f;	val_dir[11065*3 + 1] = -0.177822f;	val_dir[11065*3 + 2] = -0.933564f;
+ 	val_dir[11066*3 + 0] = 0.332269f;	val_dir[11066*3 + 1] = -0.155059f;	val_dir[11066*3 + 2] = -0.930352f;
+ 	val_dir[11067*3 + 0] = 0.352865f;	val_dir[11067*3 + 1] = -0.132324f;	val_dir[11067*3 + 2] = -0.926270f;
+ 	val_dir[11068*3 + 0] = 0.372929f;	val_dir[11068*3 + 1] = -0.109685f;	val_dir[11068*3 + 2] = -0.921354f;
+ 	val_dir[11069*3 + 0] = 0.392419f;	val_dir[11069*3 + 1] = -0.087204f;	val_dir[11069*3 + 2] = -0.915644f;
+ 	val_dir[11070*3 + 0] = 0.411298f;	val_dir[11070*3 + 1] = -0.064942f;	val_dir[11070*3 + 2] = -0.909185f;
+ 	val_dir[11071*3 + 0] = 0.429537f;	val_dir[11071*3 + 1] = -0.042954f;	val_dir[11071*3 + 2] = -0.902027f;
+ 	val_dir[11072*3 + 0] = 0.447112f;	val_dir[11072*3 + 1] = -0.021291f;	val_dir[11072*3 + 2] = -0.894224f;
+ 	val_dir[11073*3 + 0] = 0.464007f;	val_dir[11073*3 + 1] = 0.0f;	val_dir[11073*3 + 2] = -0.885832f;
+ 	val_dir[11074*3 + 0] = 0.498354f;	val_dir[11074*3 + 1] = 0.021668f;	val_dir[11074*3 + 2] = -0.866703f;
+ 	val_dir[11075*3 + 0] = 0.533465f;	val_dir[11075*3 + 1] = 0.044455f;	val_dir[11075*3 + 2] = -0.844653f;
+ 	val_dir[11076*3 + 0] = 0.569064f;	val_dir[11076*3 + 1] = 0.068288f;	val_dir[11076*3 + 2] = -0.819453f;
+ 	val_dir[11077*3 + 0] = 0.604815f;	val_dir[11077*3 + 1] = 0.093048f;	val_dir[11077*3 + 2] = -0.790912f;
+ 	val_dir[11078*3 + 0] = 0.640321f;	val_dir[11078*3 + 1] = 0.118578f;	val_dir[11078*3 + 2] = -0.758899f;
+ 	val_dir[11079*3 + 0] = 0.675140f;	val_dir[11079*3 + 1] = 0.144673f;	val_dir[11079*3 + 2] = -0.723364f;
+ 	val_dir[11080*3 + 0] = 0.708794f;	val_dir[11080*3 + 1] = 0.171088f;	val_dir[11080*3 + 2] = -0.684353f;
+ 	val_dir[11081*3 + 0] = 0.740797f;	val_dir[11081*3 + 1] = 0.197546f;	val_dir[11081*3 + 2] = -0.642024f;
+ 	val_dir[11082*3 + 0] = 0.770677f;	val_dir[11082*3 + 1] = 0.223745f;	val_dir[11082*3 + 2] = -0.596653f;
+ 	val_dir[11083*3 + 0] = 0.798007f;	val_dir[11083*3 + 1] = 0.249377f;	val_dir[11083*3 + 2] = -0.548630f;
+ 	val_dir[11084*3 + 0] = 0.822434f;	val_dir[11084*3 + 1] = 0.274145f;	val_dir[11084*3 + 2] = -0.498445f;
+ 	val_dir[11085*3 + 0] = 0.843696f;	val_dir[11085*3 + 1] = 0.297775f;	val_dir[11085*3 + 2] = -0.446662f;
+ 	val_dir[11086*3 + 0] = 0.861640f;	val_dir[11086*3 + 1] = 0.320038f;	val_dir[11086*3 + 2] = -0.393893f;
+ 	val_dir[11087*3 + 0] = 0.876226f;	val_dir[11087*3 + 1] = 0.340755f;	val_dir[11087*3 + 2] = -0.340755f;
+ 	val_dir[11088*3 + 0] = 0.887517f;	val_dir[11088*3 + 1] = 0.359804f;	val_dir[11088*3 + 2] = -0.287843f;
+ 	val_dir[11089*3 + 0] = 0.895669f;	val_dir[11089*3 + 1] = 0.377124f;	val_dir[11089*3 + 2] = -0.235702f;
+ 	val_dir[11090*3 + 0] = 0.900907f;	val_dir[11090*3 + 1] = 0.392703f;	val_dir[11090*3 + 2] = -0.184801f;
+ 	val_dir[11091*3 + 0] = 0.903508f;	val_dir[11091*3 + 1] = 0.406579f;	val_dir[11091*3 + 2] = -0.135526f;
+ 	val_dir[11092*3 + 0] = 0.903777f;	val_dir[11092*3 + 1] = 0.418823f;	val_dir[11092*3 + 2] = -0.088173f;
+ 	val_dir[11093*3 + 0] = 0.902027f;	val_dir[11093*3 + 1] = 0.429537f;	val_dir[11093*3 + 2] = -0.042954f;
+ 	val_dir[11094*3 + 0] = 0.898567f;	val_dir[11094*3 + 1] = 0.438835f;	val_dir[11094*3 + 2] = 0.0f;
+ 	val_dir[11095*3 + 0] = -0.447112f;	val_dir[11095*3 + 1] = -0.894224f;	val_dir[11095*3 + 2] = -0.021291f;
+ 	val_dir[11096*3 + 0] = -0.437479f;	val_dir[11096*3 + 1] = -0.896831f;	val_dir[11096*3 + 2] = -0.065622f;
+ 	val_dir[11097*3 + 0] = -0.426348f;	val_dir[11097*3 + 1] = -0.897574f;	val_dir[11097*3 + 2] = -0.112197f;
+ 	val_dir[11098*3 + 0] = -0.413602f;	val_dir[11098*3 + 1] = -0.896137f;	val_dir[11098*3 + 2] = -0.160845f;
+ 	val_dir[11099*3 + 0] = -0.399145f;	val_dir[11099*3 + 1] = -0.892206f;	val_dir[11099*3 + 2] = -0.211312f;
+ 	val_dir[11100*3 + 0] = -0.382911f;	val_dir[11100*3 + 1] = -0.885482f;	val_dir[11100*3 + 2] = -0.263251f;
+ 	val_dir[11101*3 + 0] = -0.364878f;	val_dir[11101*3 + 1] = -0.875708f;	val_dir[11101*3 + 2] = -0.316228f;
+ 	val_dir[11102*3 + 0] = -0.345075f;	val_dir[11102*3 + 1] = -0.862687f;	val_dir[11102*3 + 2] = -0.369723f;
+ 	val_dir[11103*3 + 0] = -0.323587f;	val_dir[11103*3 + 1] = -0.846305f;	val_dir[11103*3 + 2] = -0.423153f;
+ 	val_dir[11104*3 + 0] = -0.300564f;	val_dir[11104*3 + 1] = -0.826551f;	val_dir[11104*3 + 2] = -0.475893f;
+ 	val_dir[11105*3 + 0] = -0.276211f;	val_dir[11105*3 + 1] = -0.803523f;	val_dir[11105*3 + 2] = -0.527312f;
+ 	val_dir[11106*3 + 0] = -0.250785f;	val_dir[11106*3 + 1] = -0.777433f;	val_dir[11106*3 + 2] = -0.576805f;
+ 	val_dir[11107*3 + 0] = -0.224579f;	val_dir[11107*3 + 1] = -0.748598f;	val_dir[11107*3 + 2] = -0.623831f;
+ 	val_dir[11108*3 + 0] = -0.197908f;	val_dir[11108*3 + 1] = -0.717418f;	val_dir[11108*3 + 2] = -0.667940f;
+ 	val_dir[11109*3 + 0] = -0.171088f;	val_dir[11109*3 + 1] = -0.684353f;	val_dir[11109*3 + 2] = -0.708794f;
+ 	val_dir[11110*3 + 0] = -0.144421f;	val_dir[11110*3 + 1] = -0.649895f;	val_dir[11110*3 + 2] = -0.746176f;
+ 	val_dir[11111*3 + 0] = -0.118180f;	val_dir[11111*3 + 1] = -0.614535f;	val_dir[11111*3 + 2] = -0.779987f;
+ 	val_dir[11112*3 + 0] = -0.092599f;	val_dir[11112*3 + 1] = -0.578741f;	val_dir[11112*3 + 2] = -0.810237f;
+ 	val_dir[11113*3 + 0] = -0.067867f;	val_dir[11113*3 + 1] = -0.542936f;	val_dir[11113*3 + 2] = -0.837027f;
+ 	val_dir[11114*3 + 0] = -0.044130f;	val_dir[11114*3 + 1] = -0.507490f;	val_dir[11114*3 + 2] = -0.860527f;
+ 	val_dir[11115*3 + 0] = -0.021487f;	val_dir[11115*3 + 1] = -0.472709f;	val_dir[11115*3 + 2] = -0.880957f;
+ 	val_dir[11116*3 + 0] = 0.0f;	val_dir[11116*3 + 1] = -0.438835f;	val_dir[11116*3 + 2] = -0.898567f;
+ 	val_dir[11117*3 + 0] = 0.021082f;	val_dir[11117*3 + 1] = -0.421637f;	val_dir[11117*3 + 2] = -0.906520f;
+ 	val_dir[11118*3 + 0] = 0.042505f;	val_dir[11118*3 + 1] = -0.403799f;	val_dir[11118*3 + 2] = -0.913860f;
+ 	val_dir[11119*3 + 0] = 0.064223f;	val_dir[11119*3 + 1] = -0.385341f;	val_dir[11119*3 + 2] = -0.920537f;
+ 	val_dir[11120*3 + 0] = 0.086186f;	val_dir[11120*3 + 1] = -0.366291f;	val_dir[11120*3 + 2] = -0.92650f;
+ 	val_dir[11121*3 + 0] = 0.108338f;	val_dir[11121*3 + 1] = -0.346681f;	val_dir[11121*3 + 2] = -0.931705f;
+ 	val_dir[11122*3 + 0] = 0.130620f;	val_dir[11122*3 + 1] = -0.326550f;	val_dir[11122*3 + 2] = -0.936111f;
+ 	val_dir[11123*3 + 0] = 0.152971f;	val_dir[11123*3 + 1] = -0.305942f;	val_dir[11123*3 + 2] = -0.939680f;
+ 	val_dir[11124*3 + 0] = 0.175327f;	val_dir[11124*3 + 1] = -0.284907f;	val_dir[11124*3 + 2] = -0.942384f;
+ 	val_dir[11125*3 + 0] = 0.197623f;	val_dir[11125*3 + 1] = -0.263498f;	val_dir[11125*3 + 2] = -0.94420f;
+ 	val_dir[11126*3 + 0] = 0.219793f;	val_dir[11126*3 + 1] = -0.241773f;	val_dir[11126*3 + 2] = -0.945112f;
+ 	val_dir[11127*3 + 0] = 0.241773f;	val_dir[11127*3 + 1] = -0.219793f;	val_dir[11127*3 + 2] = -0.945112f;
+ 	val_dir[11128*3 + 0] = 0.263498f;	val_dir[11128*3 + 1] = -0.197623f;	val_dir[11128*3 + 2] = -0.94420f;
+ 	val_dir[11129*3 + 0] = 0.284907f;	val_dir[11129*3 + 1] = -0.175327f;	val_dir[11129*3 + 2] = -0.942384f;
+ 	val_dir[11130*3 + 0] = 0.305942f;	val_dir[11130*3 + 1] = -0.152971f;	val_dir[11130*3 + 2] = -0.939680f;
+ 	val_dir[11131*3 + 0] = 0.326550f;	val_dir[11131*3 + 1] = -0.130620f;	val_dir[11131*3 + 2] = -0.936111f;
+ 	val_dir[11132*3 + 0] = 0.346681f;	val_dir[11132*3 + 1] = -0.108338f;	val_dir[11132*3 + 2] = -0.931705f;
+ 	val_dir[11133*3 + 0] = 0.366291f;	val_dir[11133*3 + 1] = -0.086186f;	val_dir[11133*3 + 2] = -0.92650f;
+ 	val_dir[11134*3 + 0] = 0.385341f;	val_dir[11134*3 + 1] = -0.064223f;	val_dir[11134*3 + 2] = -0.920537f;
+ 	val_dir[11135*3 + 0] = 0.403799f;	val_dir[11135*3 + 1] = -0.042505f;	val_dir[11135*3 + 2] = -0.913860f;
+ 	val_dir[11136*3 + 0] = 0.421637f;	val_dir[11136*3 + 1] = -0.021082f;	val_dir[11136*3 + 2] = -0.906520f;
+ 	val_dir[11137*3 + 0] = 0.438835f;	val_dir[11137*3 + 1] = 0.0f;	val_dir[11137*3 + 2] = -0.898567f;
+ 	val_dir[11138*3 + 0] = 0.472709f;	val_dir[11138*3 + 1] = 0.021487f;	val_dir[11138*3 + 2] = -0.880957f;
+ 	val_dir[11139*3 + 0] = 0.507490f;	val_dir[11139*3 + 1] = 0.044130f;	val_dir[11139*3 + 2] = -0.860527f;
+ 	val_dir[11140*3 + 0] = 0.542936f;	val_dir[11140*3 + 1] = 0.067867f;	val_dir[11140*3 + 2] = -0.837027f;
+ 	val_dir[11141*3 + 0] = 0.578741f;	val_dir[11141*3 + 1] = 0.092599f;	val_dir[11141*3 + 2] = -0.810237f;
+ 	val_dir[11142*3 + 0] = 0.614535f;	val_dir[11142*3 + 1] = 0.118180f;	val_dir[11142*3 + 2] = -0.779987f;
+ 	val_dir[11143*3 + 0] = 0.649895f;	val_dir[11143*3 + 1] = 0.144421f;	val_dir[11143*3 + 2] = -0.746176f;
+ 	val_dir[11144*3 + 0] = 0.684353f;	val_dir[11144*3 + 1] = 0.171088f;	val_dir[11144*3 + 2] = -0.708794f;
+ 	val_dir[11145*3 + 0] = 0.717418f;	val_dir[11145*3 + 1] = 0.197908f;	val_dir[11145*3 + 2] = -0.667940f;
+ 	val_dir[11146*3 + 0] = 0.748598f;	val_dir[11146*3 + 1] = 0.224579f;	val_dir[11146*3 + 2] = -0.623831f;
+ 	val_dir[11147*3 + 0] = 0.777433f;	val_dir[11147*3 + 1] = 0.250785f;	val_dir[11147*3 + 2] = -0.576805f;
+ 	val_dir[11148*3 + 0] = 0.803523f;	val_dir[11148*3 + 1] = 0.276211f;	val_dir[11148*3 + 2] = -0.527312f;
+ 	val_dir[11149*3 + 0] = 0.826551f;	val_dir[11149*3 + 1] = 0.300564f;	val_dir[11149*3 + 2] = -0.475893f;
+ 	val_dir[11150*3 + 0] = 0.846305f;	val_dir[11150*3 + 1] = 0.323587f;	val_dir[11150*3 + 2] = -0.423153f;
+ 	val_dir[11151*3 + 0] = 0.862687f;	val_dir[11151*3 + 1] = 0.345075f;	val_dir[11151*3 + 2] = -0.369723f;
+ 	val_dir[11152*3 + 0] = 0.875708f;	val_dir[11152*3 + 1] = 0.364878f;	val_dir[11152*3 + 2] = -0.316228f;
+ 	val_dir[11153*3 + 0] = 0.885482f;	val_dir[11153*3 + 1] = 0.382911f;	val_dir[11153*3 + 2] = -0.263251f;
+ 	val_dir[11154*3 + 0] = 0.892206f;	val_dir[11154*3 + 1] = 0.399145f;	val_dir[11154*3 + 2] = -0.211312f;
+ 	val_dir[11155*3 + 0] = 0.896137f;	val_dir[11155*3 + 1] = 0.413602f;	val_dir[11155*3 + 2] = -0.160845f;
+ 	val_dir[11156*3 + 0] = 0.897574f;	val_dir[11156*3 + 1] = 0.426348f;	val_dir[11156*3 + 2] = -0.112197f;
+ 	val_dir[11157*3 + 0] = 0.896831f;	val_dir[11157*3 + 1] = 0.437479f;	val_dir[11157*3 + 2] = -0.065622f;
+ 	val_dir[11158*3 + 0] = 0.894224f;	val_dir[11158*3 + 1] = 0.447112f;	val_dir[11158*3 + 2] = -0.021291f;
+ 	val_dir[11159*3 + 0] = -0.464007f;	val_dir[11159*3 + 1] = -0.885832f;	val_dir[11159*3 + 2] = 0.0f;
+ 	val_dir[11160*3 + 0] = -0.455447f;	val_dir[11160*3 + 1] = -0.889206f;	val_dir[11160*3 + 2] = -0.043376f;
+ 	val_dir[11161*3 + 0] = -0.445435f;	val_dir[11161*3 + 1] = -0.890871f;	val_dir[11161*3 + 2] = -0.089087f;
+ 	val_dir[11162*3 + 0] = -0.433840f;	val_dir[11162*3 + 1] = -0.890513f;	val_dir[11162*3 + 2] = -0.137002f;
+ 	val_dir[11163*3 + 0] = -0.420542f;	val_dir[11163*3 + 1] = -0.887812f;	val_dir[11163*3 + 2] = -0.186908f;
+ 	val_dir[11164*3 + 0] = -0.405452f;	val_dir[11164*3 + 1] = -0.882454f;	val_dir[11164*3 + 2] = -0.238501f;
+ 	val_dir[11165*3 + 0] = -0.388514f;	val_dir[11165*3 + 1] = -0.874157f;	val_dir[11165*3 + 2] = -0.291386f;
+ 	val_dir[11166*3 + 0] = -0.369723f;	val_dir[11166*3 + 1] = -0.862687f;	val_dir[11166*3 + 2] = -0.345075f;
+ 	val_dir[11167*3 + 0] = -0.349128f;	val_dir[11167*3 + 1] = -0.847883f;	val_dir[11167*3 + 2] = -0.399004f;
+ 	val_dir[11168*3 + 0] = -0.326844f;	val_dir[11168*3 + 1] = -0.829680f;	val_dir[11168*3 + 2] = -0.452553f;
+ 	val_dir[11169*3 + 0] = -0.303046f;	val_dir[11169*3 + 1] = -0.808122f;	val_dir[11169*3 + 2] = -0.505076f;
+ 	val_dir[11170*3 + 0] = -0.277969f;	val_dir[11170*3 + 1] = -0.783368f;	val_dir[11170*3 + 2] = -0.555939f;
+ 	val_dir[11171*3 + 0] = -0.251896f;	val_dir[11171*3 + 1] = -0.755689f;	val_dir[11171*3 + 2] = -0.604551f;
+ 	val_dir[11172*3 + 0] = -0.225141f;	val_dir[11172*3 + 1] = -0.725454f;	val_dir[11172*3 + 2] = -0.650407f;
+ 	val_dir[11173*3 + 0] = -0.198030f;	val_dir[11173*3 + 1] = -0.693103f;	val_dir[11173*3 + 2] = -0.693103f;
+ 	val_dir[11174*3 + 0] = -0.170884f;	val_dir[11174*3 + 1] = -0.659125f;	val_dir[11174*3 + 2] = -0.732361f;
+ 	val_dir[11175*3 + 0] = -0.144005f;	val_dir[11175*3 + 1] = -0.624020f;	val_dir[11175*3 + 2] = -0.768025f;
+ 	val_dir[11176*3 + 0] = -0.117655f;	val_dir[11176*3 + 1] = -0.588276f;	val_dir[11176*3 + 2] = -0.800055f;
+ 	val_dir[11177*3 + 0] = -0.092057f;	val_dir[11177*3 + 1] = -0.552345f;	val_dir[11177*3 + 2] = -0.828517f;
+ 	val_dir[11178*3 + 0] = -0.067386f;	val_dir[11178*3 + 1] = -0.516626f;	val_dir[11178*3 + 2] = -0.853556f;
+ 	val_dir[11179*3 + 0] = -0.043769f;	val_dir[11179*3 + 1] = -0.481457f;	val_dir[11179*3 + 2] = -0.875376f;
+ 	val_dir[11180*3 + 0] = -0.021291f;	val_dir[11180*3 + 1] = -0.447112f;	val_dir[11180*3 + 2] = -0.894224f;
+ 	val_dir[11181*3 + 0] = 0.0f;	val_dir[11181*3 + 1] = -0.413803f;	val_dir[11181*3 + 2] = -0.910366f;
+ 	val_dir[11182*3 + 0] = 0.020861f;	val_dir[11182*3 + 1] = -0.396350f;	val_dir[11182*3 + 2] = -0.917863f;
+ 	val_dir[11183*3 + 0] = 0.042033f;	val_dir[11183*3 + 1] = -0.378298f;	val_dir[11183*3 + 2] = -0.924729f;
+ 	val_dir[11184*3 + 0] = 0.063472f;	val_dir[11184*3 + 1] = -0.359673f;	val_dir[11184*3 + 2] = -0.930917f;
+ 	val_dir[11185*3 + 0] = 0.085126f;	val_dir[11185*3 + 1] = -0.340503f;	val_dir[11185*3 + 2] = -0.936382f;
+ 	val_dir[11186*3 + 0] = 0.106941f;	val_dir[11186*3 + 1] = -0.320824f;	val_dir[11186*3 + 2] = -0.941082f;
+ 	val_dir[11187*3 + 0] = 0.128861f;	val_dir[11187*3 + 1] = -0.300676f;	val_dir[11187*3 + 2] = -0.944981f;
+ 	val_dir[11188*3 + 0] = 0.150826f;	val_dir[11188*3 + 1] = -0.280105f;	val_dir[11188*3 + 2] = -0.948047f;
+ 	val_dir[11189*3 + 0] = 0.172774f;	val_dir[11189*3 + 1] = -0.259161f;	val_dir[11189*3 + 2] = -0.950255f;
+ 	val_dir[11190*3 + 0] = 0.194643f;	val_dir[11190*3 + 1] = -0.237897f;	val_dir[11190*3 + 2] = -0.951588f;
+ 	val_dir[11191*3 + 0] = 0.216371f;	val_dir[11191*3 + 1] = -0.216371f;	val_dir[11191*3 + 2] = -0.952033f;
+ 	val_dir[11192*3 + 0] = 0.237897f;	val_dir[11192*3 + 1] = -0.194643f;	val_dir[11192*3 + 2] = -0.951588f;
+ 	val_dir[11193*3 + 0] = 0.259161f;	val_dir[11193*3 + 1] = -0.172774f;	val_dir[11193*3 + 2] = -0.950255f;
+ 	val_dir[11194*3 + 0] = 0.280105f;	val_dir[11194*3 + 1] = -0.150826f;	val_dir[11194*3 + 2] = -0.948047f;
+ 	val_dir[11195*3 + 0] = 0.300676f;	val_dir[11195*3 + 1] = -0.128861f;	val_dir[11195*3 + 2] = -0.944981f;
+ 	val_dir[11196*3 + 0] = 0.320824f;	val_dir[11196*3 + 1] = -0.106941f;	val_dir[11196*3 + 2] = -0.941082f;
+ 	val_dir[11197*3 + 0] = 0.340503f;	val_dir[11197*3 + 1] = -0.085126f;	val_dir[11197*3 + 2] = -0.936382f;
+ 	val_dir[11198*3 + 0] = 0.359673f;	val_dir[11198*3 + 1] = -0.063472f;	val_dir[11198*3 + 2] = -0.930917f;
+ 	val_dir[11199*3 + 0] = 0.378298f;	val_dir[11199*3 + 1] = -0.042033f;	val_dir[11199*3 + 2] = -0.924729f;
+ 	val_dir[11200*3 + 0] = 0.396350f;	val_dir[11200*3 + 1] = -0.020861f;	val_dir[11200*3 + 2] = -0.917863f;
+ 	val_dir[11201*3 + 0] = 0.413803f;	val_dir[11201*3 + 1] = 0.0f;	val_dir[11201*3 + 2] = -0.910366f;
+ 	val_dir[11202*3 + 0] = 0.447112f;	val_dir[11202*3 + 1] = 0.021291f;	val_dir[11202*3 + 2] = -0.894224f;
+ 	val_dir[11203*3 + 0] = 0.481457f;	val_dir[11203*3 + 1] = 0.043769f;	val_dir[11203*3 + 2] = -0.875376f;
+ 	val_dir[11204*3 + 0] = 0.516626f;	val_dir[11204*3 + 1] = 0.067386f;	val_dir[11204*3 + 2] = -0.853556f;
+ 	val_dir[11205*3 + 0] = 0.552345f;	val_dir[11205*3 + 1] = 0.092057f;	val_dir[11205*3 + 2] = -0.828517f;
+ 	val_dir[11206*3 + 0] = 0.588276f;	val_dir[11206*3 + 1] = 0.117655f;	val_dir[11206*3 + 2] = -0.800055f;
+ 	val_dir[11207*3 + 0] = 0.624020f;	val_dir[11207*3 + 1] = 0.144005f;	val_dir[11207*3 + 2] = -0.768025f;
+ 	val_dir[11208*3 + 0] = 0.659125f;	val_dir[11208*3 + 1] = 0.170884f;	val_dir[11208*3 + 2] = -0.732361f;
+ 	val_dir[11209*3 + 0] = 0.693103f;	val_dir[11209*3 + 1] = 0.198030f;	val_dir[11209*3 + 2] = -0.693103f;
+ 	val_dir[11210*3 + 0] = 0.725454f;	val_dir[11210*3 + 1] = 0.225141f;	val_dir[11210*3 + 2] = -0.650407f;
+ 	val_dir[11211*3 + 0] = 0.755689f;	val_dir[11211*3 + 1] = 0.251896f;	val_dir[11211*3 + 2] = -0.604551f;
+ 	val_dir[11212*3 + 0] = 0.783368f;	val_dir[11212*3 + 1] = 0.277969f;	val_dir[11212*3 + 2] = -0.555939f;
+ 	val_dir[11213*3 + 0] = 0.808122f;	val_dir[11213*3 + 1] = 0.303046f;	val_dir[11213*3 + 2] = -0.505076f;
+ 	val_dir[11214*3 + 0] = 0.829680f;	val_dir[11214*3 + 1] = 0.326844f;	val_dir[11214*3 + 2] = -0.452553f;
+ 	val_dir[11215*3 + 0] = 0.847883f;	val_dir[11215*3 + 1] = 0.349128f;	val_dir[11215*3 + 2] = -0.399004f;
+ 	val_dir[11216*3 + 0] = 0.862687f;	val_dir[11216*3 + 1] = 0.369723f;	val_dir[11216*3 + 2] = -0.345075f;
+ 	val_dir[11217*3 + 0] = 0.874157f;	val_dir[11217*3 + 1] = 0.388514f;	val_dir[11217*3 + 2] = -0.291386f;
+ 	val_dir[11218*3 + 0] = 0.882454f;	val_dir[11218*3 + 1] = 0.405452f;	val_dir[11218*3 + 2] = -0.238501f;
+ 	val_dir[11219*3 + 0] = 0.887812f;	val_dir[11219*3 + 1] = 0.420542f;	val_dir[11219*3 + 2] = -0.186908f;
+ 	val_dir[11220*3 + 0] = 0.890513f;	val_dir[11220*3 + 1] = 0.433840f;	val_dir[11220*3 + 2] = -0.137002f;
+ 	val_dir[11221*3 + 0] = 0.890871f;	val_dir[11221*3 + 1] = 0.445435f;	val_dir[11221*3 + 2] = -0.089087f;
+ 	val_dir[11222*3 + 0] = 0.889206f;	val_dir[11222*3 + 1] = 0.455447f;	val_dir[11222*3 + 2] = -0.043376f;
+ 	val_dir[11223*3 + 0] = 0.885832f;	val_dir[11223*3 + 1] = 0.464007f;	val_dir[11223*3 + 2] = 0.0f;
+ 	val_dir[11224*3 + 0] = -0.472709f;	val_dir[11224*3 + 1] = -0.880957f;	val_dir[11224*3 + 2] = -0.021487f;
+ 	val_dir[11225*3 + 0] = -0.463812f;	val_dir[11225*3 + 1] = -0.883452f;	val_dir[11225*3 + 2] = -0.066259f;
+ 	val_dir[11226*3 + 0] = -0.453376f;	val_dir[11226*3 + 1] = -0.884083f;	val_dir[11226*3 + 2] = -0.113344f;
+ 	val_dir[11227*3 + 0] = -0.441264f;	val_dir[11227*3 + 1] = -0.882528f;	val_dir[11227*3 + 2] = -0.162571f;
+ 	val_dir[11228*3 + 0] = -0.427362f;	val_dir[11228*3 + 1] = -0.878466f;	val_dir[11228*3 + 2] = -0.213681f;
+ 	val_dir[11229*3 + 0] = -0.411585f;	val_dir[11229*3 + 1] = -0.871592f;	val_dir[11229*3 + 2] = -0.266320f;
+ 	val_dir[11230*3 + 0] = -0.393893f;	val_dir[11230*3 + 1] = -0.861640f;	val_dir[11230*3 + 2] = -0.320038f;
+ 	val_dir[11231*3 + 0] = -0.374299f;	val_dir[11231*3 + 1] = -0.848411f;	val_dir[11231*3 + 2] = -0.374299f;
+ 	val_dir[11232*3 + 0] = -0.352879f;	val_dir[11232*3 + 1] = -0.831786f;	val_dir[11232*3 + 2] = -0.428496f;
+ 	val_dir[11233*3 + 0] = -0.329775f;	val_dir[11233*3 + 1] = -0.811754f;	val_dir[11233*3 + 2] = -0.481979f;
+ 	val_dir[11234*3 + 0] = -0.305194f;	val_dir[11234*3 + 1] = -0.788419f;	val_dir[11234*3 + 2] = -0.534090f;
+ 	val_dir[11235*3 + 0] = -0.27940f;	val_dir[11235*3 + 1] = -0.762001f;	val_dir[11235*3 + 2] = -0.584201f;
+ 	val_dir[11236*3 + 0] = -0.252699f;	val_dir[11236*3 + 1] = -0.732828f;	val_dir[11236*3 + 2] = -0.631748f;
+ 	val_dir[11237*3 + 0] = -0.225423f;	val_dir[11237*3 + 1] = -0.701316f;	val_dir[11237*3 + 2] = -0.676269f;
+ 	val_dir[11238*3 + 0] = -0.197908f;	val_dir[11238*3 + 1] = -0.667940f;	val_dir[11238*3 + 2] = -0.717418f;
+ 	val_dir[11239*3 + 0] = -0.170478f;	val_dir[11239*3 + 1] = -0.633205f;	val_dir[11239*3 + 2] = -0.754976f;
+ 	val_dir[11240*3 + 0] = -0.143427f;	val_dir[11240*3 + 1] = -0.597614f;	val_dir[11240*3 + 2] = -0.788851f;
+ 	val_dir[11241*3 + 0] = -0.117009f;	val_dir[11241*3 + 1] = -0.561644f;	val_dir[11241*3 + 2] = -0.819064f;
+ 	val_dir[11242*3 + 0] = -0.091430f;	val_dir[11242*3 + 1] = -0.525723f;	val_dir[11242*3 + 2] = -0.845728f;
+ 	val_dir[11243*3 + 0] = -0.066848f;	val_dir[11243*3 + 1] = -0.490222f;	val_dir[11243*3 + 2] = -0.869030f;
+ 	val_dir[11244*3 + 0] = -0.043376f;	val_dir[11244*3 + 1] = -0.455447f;	val_dir[11244*3 + 2] = -0.889206f;
+ 	val_dir[11245*3 + 0] = -0.021082f;	val_dir[11245*3 + 1] = -0.421637f;	val_dir[11245*3 + 2] = -0.906520f;
+ 	val_dir[11246*3 + 0] = 0.0f;	val_dir[11246*3 + 1] = -0.388972f;	val_dir[11246*3 + 2] = -0.921250f;
+ 	val_dir[11247*3 + 0] = 0.020628f;	val_dir[11247*3 + 1] = -0.371312f;	val_dir[11247*3 + 2] = -0.928279f;
+ 	val_dir[11248*3 + 0] = 0.041541f;	val_dir[11248*3 + 1] = -0.353096f;	val_dir[11248*3 + 2] = -0.934665f;
+ 	val_dir[11249*3 + 0] = 0.062691f;	val_dir[11249*3 + 1] = -0.334351f;	val_dir[11249*3 + 2] = -0.940361f;
+ 	val_dir[11250*3 + 0] = 0.084029f;	val_dir[11250*3 + 1] = -0.315109f;	val_dir[11250*3 + 2] = -0.945328f;
+ 	val_dir[11251*3 + 0] = 0.105503f;	val_dir[11251*3 + 1] = -0.295409f;	val_dir[11251*3 + 2] = -0.949528f;
+ 	val_dir[11252*3 + 0] = 0.127057f;	val_dir[11252*3 + 1] = -0.275290f;	val_dir[11252*3 + 2] = -0.952928f;
+ 	val_dir[11253*3 + 0] = 0.148634f;	val_dir[11253*3 + 1] = -0.254801f;	val_dir[11253*3 + 2] = -0.955502f;
+ 	val_dir[11254*3 + 0] = 0.170174f;	val_dir[11254*3 + 1] = -0.233990f;	val_dir[11254*3 + 2] = -0.957230f;
+ 	val_dir[11255*3 + 0] = 0.191620f;	val_dir[11255*3 + 1] = -0.212911f;	val_dir[11255*3 + 2] = -0.958098f;
+ 	val_dir[11256*3 + 0] = 0.212911f;	val_dir[11256*3 + 1] = -0.191620f;	val_dir[11256*3 + 2] = -0.958098f;
+ 	val_dir[11257*3 + 0] = 0.233990f;	val_dir[11257*3 + 1] = -0.170174f;	val_dir[11257*3 + 2] = -0.957230f;
+ 	val_dir[11258*3 + 0] = 0.254801f;	val_dir[11258*3 + 1] = -0.148634f;	val_dir[11258*3 + 2] = -0.955502f;
+ 	val_dir[11259*3 + 0] = 0.275290f;	val_dir[11259*3 + 1] = -0.127057f;	val_dir[11259*3 + 2] = -0.952928f;
+ 	val_dir[11260*3 + 0] = 0.295409f;	val_dir[11260*3 + 1] = -0.105503f;	val_dir[11260*3 + 2] = -0.949528f;
+ 	val_dir[11261*3 + 0] = 0.315109f;	val_dir[11261*3 + 1] = -0.084029f;	val_dir[11261*3 + 2] = -0.945328f;
+ 	val_dir[11262*3 + 0] = 0.334351f;	val_dir[11262*3 + 1] = -0.062691f;	val_dir[11262*3 + 2] = -0.940361f;
+ 	val_dir[11263*3 + 0] = 0.353096f;	val_dir[11263*3 + 1] = -0.041541f;	val_dir[11263*3 + 2] = -0.934665f;
+ 	val_dir[11264*3 + 0] = 0.371312f;	val_dir[11264*3 + 1] = -0.020628f;	val_dir[11264*3 + 2] = -0.928279f;
+ 	val_dir[11265*3 + 0] = 0.388972f;	val_dir[11265*3 + 1] = 0.0f;	val_dir[11265*3 + 2] = -0.921250f;
+ 	val_dir[11266*3 + 0] = 0.421637f;	val_dir[11266*3 + 1] = 0.021082f;	val_dir[11266*3 + 2] = -0.906520f;
+ 	val_dir[11267*3 + 0] = 0.455447f;	val_dir[11267*3 + 1] = 0.043376f;	val_dir[11267*3 + 2] = -0.889206f;
+ 	val_dir[11268*3 + 0] = 0.490222f;	val_dir[11268*3 + 1] = 0.066848f;	val_dir[11268*3 + 2] = -0.869030f;
+ 	val_dir[11269*3 + 0] = 0.525723f;	val_dir[11269*3 + 1] = 0.091430f;	val_dir[11269*3 + 2] = -0.845728f;
+ 	val_dir[11270*3 + 0] = 0.561644f;	val_dir[11270*3 + 1] = 0.117009f;	val_dir[11270*3 + 2] = -0.819064f;
+ 	val_dir[11271*3 + 0] = 0.597614f;	val_dir[11271*3 + 1] = 0.143427f;	val_dir[11271*3 + 2] = -0.788851f;
+ 	val_dir[11272*3 + 0] = 0.633205f;	val_dir[11272*3 + 1] = 0.170478f;	val_dir[11272*3 + 2] = -0.754976f;
+ 	val_dir[11273*3 + 0] = 0.667940f;	val_dir[11273*3 + 1] = 0.197908f;	val_dir[11273*3 + 2] = -0.717418f;
+ 	val_dir[11274*3 + 0] = 0.701316f;	val_dir[11274*3 + 1] = 0.225423f;	val_dir[11274*3 + 2] = -0.676269f;
+ 	val_dir[11275*3 + 0] = 0.732828f;	val_dir[11275*3 + 1] = 0.252699f;	val_dir[11275*3 + 2] = -0.631748f;
+ 	val_dir[11276*3 + 0] = 0.762001f;	val_dir[11276*3 + 1] = 0.27940f;	val_dir[11276*3 + 2] = -0.584201f;
+ 	val_dir[11277*3 + 0] = 0.788419f;	val_dir[11277*3 + 1] = 0.305194f;	val_dir[11277*3 + 2] = -0.534090f;
+ 	val_dir[11278*3 + 0] = 0.811754f;	val_dir[11278*3 + 1] = 0.329775f;	val_dir[11278*3 + 2] = -0.481979f;
+ 	val_dir[11279*3 + 0] = 0.831786f;	val_dir[11279*3 + 1] = 0.352879f;	val_dir[11279*3 + 2] = -0.428496f;
+ 	val_dir[11280*3 + 0] = 0.848411f;	val_dir[11280*3 + 1] = 0.374299f;	val_dir[11280*3 + 2] = -0.374299f;
+ 	val_dir[11281*3 + 0] = 0.861640f;	val_dir[11281*3 + 1] = 0.393893f;	val_dir[11281*3 + 2] = -0.320038f;
+ 	val_dir[11282*3 + 0] = 0.871592f;	val_dir[11282*3 + 1] = 0.411585f;	val_dir[11282*3 + 2] = -0.266320f;
+ 	val_dir[11283*3 + 0] = 0.878466f;	val_dir[11283*3 + 1] = 0.427362f;	val_dir[11283*3 + 2] = -0.213681f;
+ 	val_dir[11284*3 + 0] = 0.882528f;	val_dir[11284*3 + 1] = 0.441264f;	val_dir[11284*3 + 2] = -0.162571f;
+ 	val_dir[11285*3 + 0] = 0.884083f;	val_dir[11285*3 + 1] = 0.453376f;	val_dir[11285*3 + 2] = -0.113344f;
+ 	val_dir[11286*3 + 0] = 0.883452f;	val_dir[11286*3 + 1] = 0.463812f;	val_dir[11286*3 + 2] = -0.066259f;
+ 	val_dir[11287*3 + 0] = 0.880957f;	val_dir[11287*3 + 1] = 0.472709f;	val_dir[11287*3 + 2] = -0.021487f;
+ 	val_dir[11288*3 + 0] = -0.489251f;	val_dir[11288*3 + 1] = -0.872143f;	val_dir[11288*3 + 2] = 0.0f;
+ 	val_dir[11289*3 + 0] = -0.481457f;	val_dir[11289*3 + 1] = -0.875376f;	val_dir[11289*3 + 2] = -0.043769f;
+ 	val_dir[11290*3 + 0] = -0.472178f;	val_dir[11290*3 + 1] = -0.876903f;	val_dir[11290*3 + 2] = -0.089939f;
+ 	val_dir[11291*3 + 0] = -0.461266f;	val_dir[11291*3 + 1] = -0.876405f;	val_dir[11291*3 + 2] = -0.138380f;
+ 	val_dir[11292*3 + 0] = -0.448583f;	val_dir[11292*3 + 1] = -0.873555f;	val_dir[11292*3 + 2] = -0.188877f;
+ 	val_dir[11293*3 + 0] = -0.434019f;	val_dir[11293*3 + 1] = -0.868037f;	val_dir[11293*3 + 2] = -0.241121f;
+ 	val_dir[11294*3 + 0] = -0.41750f;	val_dir[11294*3 + 1] = -0.859559f;	val_dir[11294*3 + 2] = -0.294706f;
+ 	val_dir[11295*3 + 0] = -0.399004f;	val_dir[11295*3 + 1] = -0.847883f;	val_dir[11295*3 + 2] = -0.349128f;
+ 	val_dir[11296*3 + 0] = -0.378566f;	val_dir[11296*3 + 1] = -0.832845f;	val_dir[11296*3 + 2] = -0.403804f;
+ 	val_dir[11297*3 + 0] = -0.356291f;	val_dir[11297*3 + 1] = -0.814379f;	val_dir[11297*3 + 2] = -0.458088f;
+ 	val_dir[11298*3 + 0] = -0.332352f;	val_dir[11298*3 + 1] = -0.792530f;	val_dir[11298*3 + 2] = -0.511310f;
+ 	val_dir[11299*3 + 0] = -0.306987f;	val_dir[11299*3 + 1] = -0.767467f;	val_dir[11299*3 + 2] = -0.562809f;
+ 	val_dir[11300*3 + 0] = -0.280488f;	val_dir[11300*3 + 1] = -0.739469f;	val_dir[11300*3 + 2] = -0.611974f;
+ 	val_dir[11301*3 + 0] = -0.253185f;	val_dir[11301*3 + 1] = -0.708918f;	val_dir[11301*3 + 2] = -0.658281f;
+ 	val_dir[11302*3 + 0] = -0.225423f;	val_dir[11302*3 + 1] = -0.676269f;	val_dir[11302*3 + 2] = -0.701316f;
+ 	val_dir[11303*3 + 0] = -0.197546f;	val_dir[11303*3 + 1] = -0.642024f;	val_dir[11303*3 + 2] = -0.740797f;
+ 	val_dir[11304*3 + 0] = -0.169875f;	val_dir[11304*3 + 1] = -0.606696f;	val_dir[11304*3 + 2] = -0.776571f;
+ 	val_dir[11305*3 + 0] = -0.142695f;	val_dir[11305*3 + 1] = -0.570782f;	val_dir[11305*3 + 2] = -0.808608f;
+ 	val_dir[11306*3 + 0] = -0.116248f;	val_dir[11306*3 + 1] = -0.534739f;	val_dir[11306*3 + 2] = -0.836983f;
+ 	val_dir[11307*3 + 0] = -0.090722f;	val_dir[11307*3 + 1] = -0.498970f;	val_dir[11307*3 + 2] = -0.861857f;
+ 	val_dir[11308*3 + 0] = -0.066259f;	val_dir[11308*3 + 1] = -0.463812f;	val_dir[11308*3 + 2] = -0.883452f;
+ 	val_dir[11309*3 + 0] = -0.042954f;	val_dir[11309*3 + 1] = -0.429537f;	val_dir[11309*3 + 2] = -0.902027f;
+ 	val_dir[11310*3 + 0] = -0.020861f;	val_dir[11310*3 + 1] = -0.396350f;	val_dir[11310*3 + 2] = -0.917863f;
+ 	val_dir[11311*3 + 0] = 0.0f;	val_dir[11311*3 + 1] = -0.364399f;	val_dir[11311*3 + 2] = -0.931243f;
+ 	val_dir[11312*3 + 0] = 0.020387f;	val_dir[11312*3 + 1] = -0.346578f;	val_dir[11312*3 + 2] = -0.93780f;
+ 	val_dir[11313*3 + 0] = 0.041030f;	val_dir[11313*3 + 1] = -0.328244f;	val_dir[11313*3 + 2] = -0.943701f;
+ 	val_dir[11314*3 + 0] = 0.061885f;	val_dir[11314*3 + 1] = -0.309426f;	val_dir[11314*3 + 2] = -0.948908f;
+ 	val_dir[11315*3 + 0] = 0.082903f;	val_dir[11315*3 + 1] = -0.290159f;	val_dir[11315*3 + 2] = -0.953381f;
+ 	val_dir[11316*3 + 0] = 0.104031f;	val_dir[11316*3 + 1] = -0.270481f;	val_dir[11316*3 + 2] = -0.957088f;
+ 	val_dir[11317*3 + 0] = 0.125218f;	val_dir[11317*3 + 1] = -0.250435f;	val_dir[11317*3 + 2] = -0.960001f;
+ 	val_dir[11318*3 + 0] = 0.146406f;	val_dir[11318*3 + 1] = -0.230067f;	val_dir[11318*3 + 2] = -0.962099f;
+ 	val_dir[11319*3 + 0] = 0.167542f;	val_dir[11319*3 + 1] = -0.209427f;	val_dir[11319*3 + 2] = -0.963364f;
+ 	val_dir[11320*3 + 0] = 0.188567f;	val_dir[11320*3 + 1] = -0.188567f;	val_dir[11320*3 + 2] = -0.963787f;
+ 	val_dir[11321*3 + 0] = 0.209427f;	val_dir[11321*3 + 1] = -0.167542f;	val_dir[11321*3 + 2] = -0.963364f;
+ 	val_dir[11322*3 + 0] = 0.230067f;	val_dir[11322*3 + 1] = -0.146406f;	val_dir[11322*3 + 2] = -0.962099f;
+ 	val_dir[11323*3 + 0] = 0.250435f;	val_dir[11323*3 + 1] = -0.125218f;	val_dir[11323*3 + 2] = -0.960001f;
+ 	val_dir[11324*3 + 0] = 0.270481f;	val_dir[11324*3 + 1] = -0.104031f;	val_dir[11324*3 + 2] = -0.957088f;
+ 	val_dir[11325*3 + 0] = 0.290159f;	val_dir[11325*3 + 1] = -0.082903f;	val_dir[11325*3 + 2] = -0.953381f;
+ 	val_dir[11326*3 + 0] = 0.309426f;	val_dir[11326*3 + 1] = -0.061885f;	val_dir[11326*3 + 2] = -0.948908f;
+ 	val_dir[11327*3 + 0] = 0.328244f;	val_dir[11327*3 + 1] = -0.041030f;	val_dir[11327*3 + 2] = -0.943701f;
+ 	val_dir[11328*3 + 0] = 0.346578f;	val_dir[11328*3 + 1] = -0.020387f;	val_dir[11328*3 + 2] = -0.93780f;
+ 	val_dir[11329*3 + 0] = 0.364399f;	val_dir[11329*3 + 1] = 0.0f;	val_dir[11329*3 + 2] = -0.931243f;
+ 	val_dir[11330*3 + 0] = 0.396350f;	val_dir[11330*3 + 1] = 0.020861f;	val_dir[11330*3 + 2] = -0.917863f;
+ 	val_dir[11331*3 + 0] = 0.429537f;	val_dir[11331*3 + 1] = 0.042954f;	val_dir[11331*3 + 2] = -0.902027f;
+ 	val_dir[11332*3 + 0] = 0.463812f;	val_dir[11332*3 + 1] = 0.066259f;	val_dir[11332*3 + 2] = -0.883452f;
+ 	val_dir[11333*3 + 0] = 0.498970f;	val_dir[11333*3 + 1] = 0.090722f;	val_dir[11333*3 + 2] = -0.861857f;
+ 	val_dir[11334*3 + 0] = 0.534739f;	val_dir[11334*3 + 1] = 0.116248f;	val_dir[11334*3 + 2] = -0.836983f;
+ 	val_dir[11335*3 + 0] = 0.570782f;	val_dir[11335*3 + 1] = 0.142695f;	val_dir[11335*3 + 2] = -0.808608f;
+ 	val_dir[11336*3 + 0] = 0.606696f;	val_dir[11336*3 + 1] = 0.169875f;	val_dir[11336*3 + 2] = -0.776571f;
+ 	val_dir[11337*3 + 0] = 0.642024f;	val_dir[11337*3 + 1] = 0.197546f;	val_dir[11337*3 + 2] = -0.740797f;
+ 	val_dir[11338*3 + 0] = 0.676269f;	val_dir[11338*3 + 1] = 0.225423f;	val_dir[11338*3 + 2] = -0.701316f;
+ 	val_dir[11339*3 + 0] = 0.708918f;	val_dir[11339*3 + 1] = 0.253185f;	val_dir[11339*3 + 2] = -0.658281f;
+ 	val_dir[11340*3 + 0] = 0.739469f;	val_dir[11340*3 + 1] = 0.280488f;	val_dir[11340*3 + 2] = -0.611974f;
+ 	val_dir[11341*3 + 0] = 0.767467f;	val_dir[11341*3 + 1] = 0.306987f;	val_dir[11341*3 + 2] = -0.562809f;
+ 	val_dir[11342*3 + 0] = 0.792530f;	val_dir[11342*3 + 1] = 0.332352f;	val_dir[11342*3 + 2] = -0.511310f;
+ 	val_dir[11343*3 + 0] = 0.814379f;	val_dir[11343*3 + 1] = 0.356291f;	val_dir[11343*3 + 2] = -0.458088f;
+ 	val_dir[11344*3 + 0] = 0.832845f;	val_dir[11344*3 + 1] = 0.378566f;	val_dir[11344*3 + 2] = -0.403804f;
+ 	val_dir[11345*3 + 0] = 0.847883f;	val_dir[11345*3 + 1] = 0.399004f;	val_dir[11345*3 + 2] = -0.349128f;
+ 	val_dir[11346*3 + 0] = 0.859559f;	val_dir[11346*3 + 1] = 0.41750f;	val_dir[11346*3 + 2] = -0.294706f;
+ 	val_dir[11347*3 + 0] = 0.868037f;	val_dir[11347*3 + 1] = 0.434019f;	val_dir[11347*3 + 2] = -0.241121f;
+ 	val_dir[11348*3 + 0] = 0.873555f;	val_dir[11348*3 + 1] = 0.448583f;	val_dir[11348*3 + 2] = -0.188877f;
+ 	val_dir[11349*3 + 0] = 0.876405f;	val_dir[11349*3 + 1] = 0.461266f;	val_dir[11349*3 + 2] = -0.138380f;
+ 	val_dir[11350*3 + 0] = 0.876903f;	val_dir[11350*3 + 1] = 0.472178f;	val_dir[11350*3 + 2] = -0.089939f;
+ 	val_dir[11351*3 + 0] = 0.875376f;	val_dir[11351*3 + 1] = 0.481457f;	val_dir[11351*3 + 2] = -0.043769f;
+ 	val_dir[11352*3 + 0] = 0.872143f;	val_dir[11352*3 + 1] = 0.489251f;	val_dir[11352*3 + 2] = 0.0f;
+ 	val_dir[11353*3 + 0] = -0.498354f;	val_dir[11353*3 + 1] = -0.866703f;	val_dir[11353*3 + 2] = -0.021668f;
+ 	val_dir[11354*3 + 0] = -0.490222f;	val_dir[11354*3 + 1] = -0.869030f;	val_dir[11354*3 + 2] = -0.066848f;
+ 	val_dir[11355*3 + 0] = -0.480510f;	val_dir[11355*3 + 1] = -0.869495f;	val_dir[11355*3 + 2] = -0.114407f;
+ 	val_dir[11356*3 + 0] = -0.469065f;	val_dir[11356*3 + 1] = -0.867770f;	val_dir[11356*3 + 2] = -0.164173f;
+ 	val_dir[11357*3 + 0] = -0.455752f;	val_dir[11357*3 + 1] = -0.863530f;	val_dir[11357*3 + 2] = -0.215883f;
+ 	val_dir[11358*3 + 0] = -0.440468f;	val_dir[11358*3 + 1] = -0.856465f;	val_dir[11358*3 + 2] = -0.269175f;
+ 	val_dir[11359*3 + 0] = -0.423153f;	val_dir[11359*3 + 1] = -0.846305f;	val_dir[11359*3 + 2] = -0.323587f;
+ 	val_dir[11360*3 + 0] = -0.403804f;	val_dir[11360*3 + 1] = -0.832845f;	val_dir[11360*3 + 2] = -0.378566f;
+ 	val_dir[11361*3 + 0] = -0.382484f;	val_dir[11361*3 + 1] = -0.815966f;	val_dir[11361*3 + 2] = -0.433482f;
+ 	val_dir[11362*3 + 0] = -0.359329f;	val_dir[11362*3 + 1] = -0.795657f;	val_dir[11362*3 + 2] = -0.487661f;
+ 	val_dir[11363*3 + 0] = -0.334545f;	val_dir[11363*3 + 1] = -0.772027f;	val_dir[11363*3 + 2] = -0.540419f;
+ 	val_dir[11364*3 + 0] = -0.308403f;	val_dir[11364*3 + 1] = -0.745307f;	val_dir[11364*3 + 2] = -0.591105f;
+ 	val_dir[11365*3 + 0] = -0.281220f;	val_dir[11365*3 + 1] = -0.715834f;	val_dir[11365*3 + 2] = -0.639138f;
+ 	val_dir[11366*3 + 0] = -0.253347f;	val_dir[11366*3 + 1] = -0.684038f;	val_dir[11366*3 + 2] = -0.684038f;
+ 	val_dir[11367*3 + 0] = -0.225141f;	val_dir[11367*3 + 1] = -0.650407f;	val_dir[11367*3 + 2] = -0.725454f;
+ 	val_dir[11368*3 + 0] = -0.196946f;	val_dir[11368*3 + 1] = -0.615457f;	val_dir[11368*3 + 2] = -0.763167f;
+ 	val_dir[11369*3 + 0] = -0.169080f;	val_dir[11369*3 + 1] = -0.579703f;	val_dir[11369*3 + 2] = -0.797092f;
+ 	val_dir[11370*3 + 0] = -0.141816f;	val_dir[11370*3 + 1] = -0.543627f;	val_dir[11370*3 + 2] = -0.827259f;
+ 	val_dir[11371*3 + 0] = -0.115378f;	val_dir[11371*3 + 1] = -0.507662f;	val_dir[11371*3 + 2] = -0.853796f;
+ 	val_dir[11372*3 + 0] = -0.089939f;	val_dir[11372*3 + 1] = -0.472178f;	val_dir[11372*3 + 2] = -0.876903f;
+ 	val_dir[11373*3 + 0] = -0.065622f;	val_dir[11373*3 + 1] = -0.437479f;	val_dir[11373*3 + 2] = -0.896831f;
+ 	val_dir[11374*3 + 0] = -0.042505f;	val_dir[11374*3 + 1] = -0.403799f;	val_dir[11374*3 + 2] = -0.913860f;
+ 	val_dir[11375*3 + 0] = -0.020628f;	val_dir[11375*3 + 1] = -0.371312f;	val_dir[11375*3 + 2] = -0.928279f;
+ 	val_dir[11376*3 + 0] = 0.0f;	val_dir[11376*3 + 1] = -0.340136f;	val_dir[11376*3 + 2] = -0.940376f;
+ 	val_dir[11377*3 + 0] = 0.020137f;	val_dir[11377*3 + 1] = -0.322198f;	val_dir[11377*3 + 2] = -0.946458f;
+ 	val_dir[11378*3 + 0] = 0.040505f;	val_dir[11378*3 + 1] = -0.303791f;	val_dir[11378*3 + 2] = -0.951877f;
+ 	val_dir[11379*3 + 0] = 0.061059f;	val_dir[11379*3 + 1] = -0.284944f;	val_dir[11379*3 + 2] = -0.956597f;
+ 	val_dir[11380*3 + 0] = 0.081752f;	val_dir[11380*3 + 1] = -0.265694f;	val_dir[11380*3 + 2] = -0.960585f;
+ 	val_dir[11381*3 + 0] = 0.102533f;	val_dir[11381*3 + 1] = -0.246079f;	val_dir[11381*3 + 2] = -0.963811f;
+ 	val_dir[11382*3 + 0] = 0.123351f;	val_dir[11382*3 + 1] = -0.226144f;	val_dir[11382*3 + 2] = -0.966252f;
+ 	val_dir[11383*3 + 0] = 0.144154f;	val_dir[11383*3 + 1] = -0.205934f;	val_dir[11383*3 + 2] = -0.967890f;
+ 	val_dir[11384*3 + 0] = 0.164887f;	val_dir[11384*3 + 1] = -0.185498f;	val_dir[11384*3 + 2] = -0.968712f;
+ 	val_dir[11385*3 + 0] = 0.185498f;	val_dir[11385*3 + 1] = -0.164887f;	val_dir[11385*3 + 2] = -0.968712f;
+ 	val_dir[11386*3 + 0] = 0.205934f;	val_dir[11386*3 + 1] = -0.144154f;	val_dir[11386*3 + 2] = -0.967890f;
+ 	val_dir[11387*3 + 0] = 0.226144f;	val_dir[11387*3 + 1] = -0.123351f;	val_dir[11387*3 + 2] = -0.966252f;
+ 	val_dir[11388*3 + 0] = 0.246079f;	val_dir[11388*3 + 1] = -0.102533f;	val_dir[11388*3 + 2] = -0.963811f;
+ 	val_dir[11389*3 + 0] = 0.265694f;	val_dir[11389*3 + 1] = -0.081752f;	val_dir[11389*3 + 2] = -0.960585f;
+ 	val_dir[11390*3 + 0] = 0.284944f;	val_dir[11390*3 + 1] = -0.061059f;	val_dir[11390*3 + 2] = -0.956597f;
+ 	val_dir[11391*3 + 0] = 0.303791f;	val_dir[11391*3 + 1] = -0.040505f;	val_dir[11391*3 + 2] = -0.951877f;
+ 	val_dir[11392*3 + 0] = 0.322198f;	val_dir[11392*3 + 1] = -0.020137f;	val_dir[11392*3 + 2] = -0.946458f;
+ 	val_dir[11393*3 + 0] = 0.340136f;	val_dir[11393*3 + 1] = 0.0f;	val_dir[11393*3 + 2] = -0.940376f;
+ 	val_dir[11394*3 + 0] = 0.371312f;	val_dir[11394*3 + 1] = 0.020628f;	val_dir[11394*3 + 2] = -0.928279f;
+ 	val_dir[11395*3 + 0] = 0.403799f;	val_dir[11395*3 + 1] = 0.042505f;	val_dir[11395*3 + 2] = -0.913860f;
+ 	val_dir[11396*3 + 0] = 0.437479f;	val_dir[11396*3 + 1] = 0.065622f;	val_dir[11396*3 + 2] = -0.896831f;
+ 	val_dir[11397*3 + 0] = 0.472178f;	val_dir[11397*3 + 1] = 0.089939f;	val_dir[11397*3 + 2] = -0.876903f;
+ 	val_dir[11398*3 + 0] = 0.507662f;	val_dir[11398*3 + 1] = 0.115378f;	val_dir[11398*3 + 2] = -0.853796f;
+ 	val_dir[11399*3 + 0] = 0.543627f;	val_dir[11399*3 + 1] = 0.141816f;	val_dir[11399*3 + 2] = -0.827259f;
+ 	val_dir[11400*3 + 0] = 0.579703f;	val_dir[11400*3 + 1] = 0.169080f;	val_dir[11400*3 + 2] = -0.797092f;
+ 	val_dir[11401*3 + 0] = 0.615457f;	val_dir[11401*3 + 1] = 0.196946f;	val_dir[11401*3 + 2] = -0.763167f;
+ 	val_dir[11402*3 + 0] = 0.650407f;	val_dir[11402*3 + 1] = 0.225141f;	val_dir[11402*3 + 2] = -0.725454f;
+ 	val_dir[11403*3 + 0] = 0.684038f;	val_dir[11403*3 + 1] = 0.253347f;	val_dir[11403*3 + 2] = -0.684038f;
+ 	val_dir[11404*3 + 0] = 0.715834f;	val_dir[11404*3 + 1] = 0.281220f;	val_dir[11404*3 + 2] = -0.639138f;
+ 	val_dir[11405*3 + 0] = 0.745307f;	val_dir[11405*3 + 1] = 0.308403f;	val_dir[11405*3 + 2] = -0.591105f;
+ 	val_dir[11406*3 + 0] = 0.772027f;	val_dir[11406*3 + 1] = 0.334545f;	val_dir[11406*3 + 2] = -0.540419f;
+ 	val_dir[11407*3 + 0] = 0.795657f;	val_dir[11407*3 + 1] = 0.359329f;	val_dir[11407*3 + 2] = -0.487661f;
+ 	val_dir[11408*3 + 0] = 0.815966f;	val_dir[11408*3 + 1] = 0.382484f;	val_dir[11408*3 + 2] = -0.433482f;
+ 	val_dir[11409*3 + 0] = 0.832845f;	val_dir[11409*3 + 1] = 0.403804f;	val_dir[11409*3 + 2] = -0.378566f;
+ 	val_dir[11410*3 + 0] = 0.846305f;	val_dir[11410*3 + 1] = 0.423153f;	val_dir[11410*3 + 2] = -0.323587f;
+ 	val_dir[11411*3 + 0] = 0.856465f;	val_dir[11411*3 + 1] = 0.440468f;	val_dir[11411*3 + 2] = -0.269175f;
+ 	val_dir[11412*3 + 0] = 0.863530f;	val_dir[11412*3 + 1] = 0.455752f;	val_dir[11412*3 + 2] = -0.215883f;
+ 	val_dir[11413*3 + 0] = 0.867770f;	val_dir[11413*3 + 1] = 0.469065f;	val_dir[11413*3 + 2] = -0.164173f;
+ 	val_dir[11414*3 + 0] = 0.869495f;	val_dir[11414*3 + 1] = 0.480510f;	val_dir[11414*3 + 2] = -0.114407f;
+ 	val_dir[11415*3 + 0] = 0.869030f;	val_dir[11415*3 + 1] = 0.490222f;	val_dir[11415*3 + 2] = -0.066848f;
+ 	val_dir[11416*3 + 0] = 0.866703f;	val_dir[11416*3 + 1] = 0.498354f;	val_dir[11416*3 + 2] = -0.021668f;
+ 	val_dir[11417*3 + 0] = -0.514496f;	val_dir[11417*3 + 1] = -0.857493f;	val_dir[11417*3 + 2] = 0.0f;
+ 	val_dir[11418*3 + 0] = -0.507490f;	val_dir[11418*3 + 1] = -0.860527f;	val_dir[11418*3 + 2] = -0.044130f;
+ 	val_dir[11419*3 + 0] = -0.498970f;	val_dir[11419*3 + 1] = -0.861857f;	val_dir[11419*3 + 2] = -0.090722f;
+ 	val_dir[11420*3 + 0] = -0.488769f;	val_dir[11420*3 + 1] = -0.861164f;	val_dir[11420*3 + 2] = -0.139648f;
+ 	val_dir[11421*3 + 0] = -0.476731f;	val_dir[11421*3 + 1] = -0.858116f;	val_dir[11421*3 + 2] = -0.190693f;
+ 	val_dir[11422*3 + 0] = -0.462727f;	val_dir[11422*3 + 1] = -0.852392f;	val_dir[11422*3 + 2] = -0.243541f;
+ 	val_dir[11423*3 + 0] = -0.446662f;	val_dir[11423*3 + 1] = -0.843696f;	val_dir[11423*3 + 2] = -0.297775f;
+ 	val_dir[11424*3 + 0] = -0.428496f;	val_dir[11424*3 + 1] = -0.831786f;	val_dir[11424*3 + 2] = -0.352879f;
+ 	val_dir[11425*3 + 0] = -0.408248f;	val_dir[11425*3 + 1] = -0.816497f;	val_dir[11425*3 + 2] = -0.408248f;
+ 	val_dir[11426*3 + 0] = -0.386014f;	val_dir[11426*3 + 1] = -0.797762f;	val_dir[11426*3 + 2] = -0.463217f;
+ 	val_dir[11427*3 + 0] = -0.361961f;	val_dir[11427*3 + 1] = -0.775632f;	val_dir[11427*3 + 2] = -0.517088f;
+ 	val_dir[11428*3 + 0] = -0.336332f;	val_dir[11428*3 + 1] = -0.750279f;	val_dir[11428*3 + 2] = -0.569177f;
+ 	val_dir[11429*3 + 0] = -0.309426f;	val_dir[11429*3 + 1] = -0.721995f;	val_dir[11429*3 + 2] = -0.618853f;
+ 	val_dir[11430*3 + 0] = -0.281589f;	val_dir[11430*3 + 1] = -0.691173f;	val_dir[11430*3 + 2] = -0.665574f;
+ 	val_dir[11431*3 + 0] = -0.253185f;	val_dir[11431*3 + 1] = -0.658281f;	val_dir[11431*3 + 2] = -0.708918f;
+ 	val_dir[11432*3 + 0] = -0.224579f;	val_dir[11432*3 + 1] = -0.623831f;	val_dir[11432*3 + 2] = -0.748598f;
+ 	val_dir[11433*3 + 0] = -0.196116f;	val_dir[11433*3 + 1] = -0.588348f;	val_dir[11433*3 + 2] = -0.784465f;
+ 	val_dir[11434*3 + 0] = -0.168102f;	val_dir[11434*3 + 1] = -0.552336f;	val_dir[11434*3 + 2] = -0.816497f;
+ 	val_dir[11435*3 + 0] = -0.140797f;	val_dir[11435*3 + 1] = -0.516256f;	val_dir[11435*3 + 2] = -0.844782f;
+ 	val_dir[11436*3 + 0] = -0.114407f;	val_dir[11436*3 + 1] = -0.480510f;	val_dir[11436*3 + 2] = -0.869495f;
+ 	val_dir[11437*3 + 0] = -0.089087f;	val_dir[11437*3 + 1] = -0.445435f;	val_dir[11437*3 + 2] = -0.890871f;
+ 	val_dir[11438*3 + 0] = -0.064942f;	val_dir[11438*3 + 1] = -0.411298f;	val_dir[11438*3 + 2] = -0.909185f;
+ 	val_dir[11439*3 + 0] = -0.042033f;	val_dir[11439*3 + 1] = -0.378298f;	val_dir[11439*3 + 2] = -0.924729f;
+ 	val_dir[11440*3 + 0] = -0.020387f;	val_dir[11440*3 + 1] = -0.346578f;	val_dir[11440*3 + 2] = -0.93780f;
+ 	val_dir[11441*3 + 0] = 0.0f;	val_dir[11441*3 + 1] = -0.316228f;	val_dir[11441*3 + 2] = -0.948683f;
+ 	val_dir[11442*3 + 0] = 0.019881f;	val_dir[11442*3 + 1] = -0.298216f;	val_dir[11442*3 + 2] = -0.954291f;
+ 	val_dir[11443*3 + 0] = 0.039968f;	val_dir[11443*3 + 1] = -0.279776f;	val_dir[11443*3 + 2] = -0.959233f;
+ 	val_dir[11444*3 + 0] = 0.060217f;	val_dir[11444*3 + 1] = -0.260941f;	val_dir[11444*3 + 2] = -0.963475f;
+ 	val_dir[11445*3 + 0] = 0.080582f;	val_dir[11445*3 + 1] = -0.241747f;	val_dir[11445*3 + 2] = -0.966988f;
+ 	val_dir[11446*3 + 0] = 0.101015f;	val_dir[11446*3 + 1] = -0.222234f;	val_dir[11446*3 + 2] = -0.969746f;
+ 	val_dir[11447*3 + 0] = 0.121466f;	val_dir[11447*3 + 1] = -0.202444f;	val_dir[11447*3 + 2] = -0.971732f;
+ 	val_dir[11448*3 + 0] = 0.141885f;	val_dir[11448*3 + 1] = -0.182424f;	val_dir[11448*3 + 2] = -0.972929f;
+ 	val_dir[11449*3 + 0] = 0.162221f;	val_dir[11449*3 + 1] = -0.162221f;	val_dir[11449*3 + 2] = -0.973329f;
+ 	val_dir[11450*3 + 0] = 0.182424f;	val_dir[11450*3 + 1] = -0.141885f;	val_dir[11450*3 + 2] = -0.972929f;
+ 	val_dir[11451*3 + 0] = 0.202444f;	val_dir[11451*3 + 1] = -0.121466f;	val_dir[11451*3 + 2] = -0.971732f;
+ 	val_dir[11452*3 + 0] = 0.222234f;	val_dir[11452*3 + 1] = -0.101015f;	val_dir[11452*3 + 2] = -0.969746f;
+ 	val_dir[11453*3 + 0] = 0.241747f;	val_dir[11453*3 + 1] = -0.080582f;	val_dir[11453*3 + 2] = -0.966988f;
+ 	val_dir[11454*3 + 0] = 0.260941f;	val_dir[11454*3 + 1] = -0.060217f;	val_dir[11454*3 + 2] = -0.963475f;
+ 	val_dir[11455*3 + 0] = 0.279776f;	val_dir[11455*3 + 1] = -0.039968f;	val_dir[11455*3 + 2] = -0.959233f;
+ 	val_dir[11456*3 + 0] = 0.298216f;	val_dir[11456*3 + 1] = -0.019881f;	val_dir[11456*3 + 2] = -0.954291f;
+ 	val_dir[11457*3 + 0] = 0.316228f;	val_dir[11457*3 + 1] = 0.0f;	val_dir[11457*3 + 2] = -0.948683f;
+ 	val_dir[11458*3 + 0] = 0.346578f;	val_dir[11458*3 + 1] = 0.020387f;	val_dir[11458*3 + 2] = -0.93780f;
+ 	val_dir[11459*3 + 0] = 0.378298f;	val_dir[11459*3 + 1] = 0.042033f;	val_dir[11459*3 + 2] = -0.924729f;
+ 	val_dir[11460*3 + 0] = 0.411298f;	val_dir[11460*3 + 1] = 0.064942f;	val_dir[11460*3 + 2] = -0.909185f;
+ 	val_dir[11461*3 + 0] = 0.445435f;	val_dir[11461*3 + 1] = 0.089087f;	val_dir[11461*3 + 2] = -0.890871f;
+ 	val_dir[11462*3 + 0] = 0.480510f;	val_dir[11462*3 + 1] = 0.114407f;	val_dir[11462*3 + 2] = -0.869495f;
+ 	val_dir[11463*3 + 0] = 0.516256f;	val_dir[11463*3 + 1] = 0.140797f;	val_dir[11463*3 + 2] = -0.844782f;
+ 	val_dir[11464*3 + 0] = 0.552336f;	val_dir[11464*3 + 1] = 0.168102f;	val_dir[11464*3 + 2] = -0.816497f;
+ 	val_dir[11465*3 + 0] = 0.588348f;	val_dir[11465*3 + 1] = 0.196116f;	val_dir[11465*3 + 2] = -0.784465f;
+ 	val_dir[11466*3 + 0] = 0.623831f;	val_dir[11466*3 + 1] = 0.224579f;	val_dir[11466*3 + 2] = -0.748598f;
+ 	val_dir[11467*3 + 0] = 0.658281f;	val_dir[11467*3 + 1] = 0.253185f;	val_dir[11467*3 + 2] = -0.708918f;
+ 	val_dir[11468*3 + 0] = 0.691173f;	val_dir[11468*3 + 1] = 0.281589f;	val_dir[11468*3 + 2] = -0.665574f;
+ 	val_dir[11469*3 + 0] = 0.721995f;	val_dir[11469*3 + 1] = 0.309426f;	val_dir[11469*3 + 2] = -0.618853f;
+ 	val_dir[11470*3 + 0] = 0.750279f;	val_dir[11470*3 + 1] = 0.336332f;	val_dir[11470*3 + 2] = -0.569177f;
+ 	val_dir[11471*3 + 0] = 0.775632f;	val_dir[11471*3 + 1] = 0.361961f;	val_dir[11471*3 + 2] = -0.517088f;
+ 	val_dir[11472*3 + 0] = 0.797762f;	val_dir[11472*3 + 1] = 0.386014f;	val_dir[11472*3 + 2] = -0.463217f;
+ 	val_dir[11473*3 + 0] = 0.816497f;	val_dir[11473*3 + 1] = 0.408248f;	val_dir[11473*3 + 2] = -0.408248f;
+ 	val_dir[11474*3 + 0] = 0.831786f;	val_dir[11474*3 + 1] = 0.428496f;	val_dir[11474*3 + 2] = -0.352879f;
+ 	val_dir[11475*3 + 0] = 0.843696f;	val_dir[11475*3 + 1] = 0.446662f;	val_dir[11475*3 + 2] = -0.297775f;
+ 	val_dir[11476*3 + 0] = 0.852392f;	val_dir[11476*3 + 1] = 0.462727f;	val_dir[11476*3 + 2] = -0.243541f;
+ 	val_dir[11477*3 + 0] = 0.858116f;	val_dir[11477*3 + 1] = 0.476731f;	val_dir[11477*3 + 2] = -0.190693f;
+ 	val_dir[11478*3 + 0] = 0.861164f;	val_dir[11478*3 + 1] = 0.488769f;	val_dir[11478*3 + 2] = -0.139648f;
+ 	val_dir[11479*3 + 0] = 0.861857f;	val_dir[11479*3 + 1] = 0.498970f;	val_dir[11479*3 + 2] = -0.090722f;
+ 	val_dir[11480*3 + 0] = 0.860527f;	val_dir[11480*3 + 1] = 0.507490f;	val_dir[11480*3 + 2] = -0.044130f;
+ 	val_dir[11481*3 + 0] = 0.857493f;	val_dir[11481*3 + 1] = 0.514496f;	val_dir[11481*3 + 2] = 0.0f;
+ 	val_dir[11482*3 + 0] = -0.523973f;	val_dir[11482*3 + 1] = -0.851455f;	val_dir[11482*3 + 2] = -0.021832f;
+ 	val_dir[11483*3 + 0] = -0.516626f;	val_dir[11483*3 + 1] = -0.853556f;	val_dir[11483*3 + 2] = -0.067386f;
+ 	val_dir[11484*3 + 0] = -0.507662f;	val_dir[11484*3 + 1] = -0.853796f;	val_dir[11484*3 + 2] = -0.115378f;
+ 	val_dir[11485*3 + 0] = -0.496911f;	val_dir[11485*3 + 1] = -0.851847f;	val_dir[11485*3 + 2] = -0.165637f;
+ 	val_dir[11486*3 + 0] = -0.484217f;	val_dir[11486*3 + 1] = -0.847381f;	val_dir[11486*3 + 2] = -0.217898f;
+ 	val_dir[11487*3 + 0] = -0.469458f;	val_dir[11487*3 + 1] = -0.840083f;	val_dir[11487*3 + 2] = -0.271791f;
+ 	val_dir[11488*3 + 0] = -0.452553f;	val_dir[11488*3 + 1] = -0.829680f;	val_dir[11488*3 + 2] = -0.326844f;
+ 	val_dir[11489*3 + 0] = -0.433482f;	val_dir[11489*3 + 1] = -0.815966f;	val_dir[11489*3 + 2] = -0.382484f;
+ 	val_dir[11490*3 + 0] = -0.412294f;	val_dir[11490*3 + 1] = -0.798820f;	val_dir[11490*3 + 2] = -0.438063f;
+ 	val_dir[11491*3 + 0] = -0.389118f;	val_dir[11491*3 + 1] = -0.778237f;	val_dir[11491*3 + 2] = -0.492883f;
+ 	val_dir[11492*3 + 0] = -0.364159f;	val_dir[11492*3 + 1] = -0.754329f;	val_dir[11492*3 + 2] = -0.546238f;
+ 	val_dir[11493*3 + 0] = -0.337691f;	val_dir[11493*3 + 1] = -0.727334f;	val_dir[11493*3 + 2] = -0.597453f;
+ 	val_dir[11494*3 + 0] = -0.310045f;	val_dir[11494*3 + 1] = -0.697602f;	val_dir[11494*3 + 2] = -0.645928f;
+ 	val_dir[11495*3 + 0] = -0.281589f;	val_dir[11495*3 + 1] = -0.665574f;	val_dir[11495*3 + 2] = -0.691173f;
+ 	val_dir[11496*3 + 0] = -0.252699f;	val_dir[11496*3 + 1] = -0.631748f;	val_dir[11496*3 + 2] = -0.732828f;
+ 	val_dir[11497*3 + 0] = -0.223745f;	val_dir[11497*3 + 1] = -0.596653f;	val_dir[11497*3 + 2] = -0.770677f;
+ 	val_dir[11498*3 + 0] = -0.195064f;	val_dir[11498*3 + 1] = -0.560809f;	val_dir[11498*3 + 2] = -0.804639f;
+ 	val_dir[11499*3 + 0] = -0.166951f;	val_dir[11499*3 + 1] = -0.524703f;	val_dir[11499*3 + 2] = -0.834754f;
+ 	val_dir[11500*3 + 0] = -0.139648f;	val_dir[11500*3 + 1] = -0.488769f;	val_dir[11500*3 + 2] = -0.861164f;
+ 	val_dir[11501*3 + 0] = -0.113344f;	val_dir[11501*3 + 1] = -0.453376f;	val_dir[11501*3 + 2] = -0.884083f;
+ 	val_dir[11502*3 + 0] = -0.088173f;	val_dir[11502*3 + 1] = -0.418823f;	val_dir[11502*3 + 2] = -0.903777f;
+ 	val_dir[11503*3 + 0] = -0.064223f;	val_dir[11503*3 + 1] = -0.385341f;	val_dir[11503*3 + 2] = -0.920537f;
+ 	val_dir[11504*3 + 0] = -0.041541f;	val_dir[11504*3 + 1] = -0.353096f;	val_dir[11504*3 + 2] = -0.934665f;
+ 	val_dir[11505*3 + 0] = -0.020137f;	val_dir[11505*3 + 1] = -0.322198f;	val_dir[11505*3 + 2] = -0.946458f;
+ 	val_dir[11506*3 + 0] = 0.0f;	val_dir[11506*3 + 1] = -0.292714f;	val_dir[11506*3 + 2] = -0.95620f;
+ 	val_dir[11507*3 + 0] = 0.019619f;	val_dir[11507*3 + 1] = -0.274668f;	val_dir[11507*3 + 2] = -0.961339f;
+ 	val_dir[11508*3 + 0] = 0.039421f;	val_dir[11508*3 + 1] = -0.256235f;	val_dir[11508*3 + 2] = -0.965810f;
+ 	val_dir[11509*3 + 0] = 0.059362f;	val_dir[11509*3 + 1] = -0.237449f;	val_dir[11509*3 + 2] = -0.969584f;
+ 	val_dir[11510*3 + 0] = 0.079399f;	val_dir[11510*3 + 1] = -0.218347f;	val_dir[11510*3 + 2] = -0.972636f;
+ 	val_dir[11511*3 + 0] = 0.099484f;	val_dir[11511*3 + 1] = -0.198968f;	val_dir[11511*3 + 2] = -0.974943f;
+ 	val_dir[11512*3 + 0] = 0.119570f;	val_dir[11512*3 + 1] = -0.179355f;	val_dir[11512*3 + 2] = -0.976491f;
+ 	val_dir[11513*3 + 0] = 0.139610f;	val_dir[11513*3 + 1] = -0.159554f;	val_dir[11513*3 + 2] = -0.977267f;
+ 	val_dir[11514*3 + 0] = 0.159554f;	val_dir[11514*3 + 1] = -0.139610f;	val_dir[11514*3 + 2] = -0.977267f;
+ 	val_dir[11515*3 + 0] = 0.179355f;	val_dir[11515*3 + 1] = -0.119570f;	val_dir[11515*3 + 2] = -0.976491f;
+ 	val_dir[11516*3 + 0] = 0.198968f;	val_dir[11516*3 + 1] = -0.099484f;	val_dir[11516*3 + 2] = -0.974943f;
+ 	val_dir[11517*3 + 0] = 0.218347f;	val_dir[11517*3 + 1] = -0.079399f;	val_dir[11517*3 + 2] = -0.972636f;
+ 	val_dir[11518*3 + 0] = 0.237449f;	val_dir[11518*3 + 1] = -0.059362f;	val_dir[11518*3 + 2] = -0.969584f;
+ 	val_dir[11519*3 + 0] = 0.256235f;	val_dir[11519*3 + 1] = -0.039421f;	val_dir[11519*3 + 2] = -0.965810f;
+ 	val_dir[11520*3 + 0] = 0.274668f;	val_dir[11520*3 + 1] = -0.019619f;	val_dir[11520*3 + 2] = -0.961339f;
+ 	val_dir[11521*3 + 0] = 0.292714f;	val_dir[11521*3 + 1] = 0.0f;	val_dir[11521*3 + 2] = -0.95620f;
+ 	val_dir[11522*3 + 0] = 0.322198f;	val_dir[11522*3 + 1] = 0.020137f;	val_dir[11522*3 + 2] = -0.946458f;
+ 	val_dir[11523*3 + 0] = 0.353096f;	val_dir[11523*3 + 1] = 0.041541f;	val_dir[11523*3 + 2] = -0.934665f;
+ 	val_dir[11524*3 + 0] = 0.385341f;	val_dir[11524*3 + 1] = 0.064223f;	val_dir[11524*3 + 2] = -0.920537f;
+ 	val_dir[11525*3 + 0] = 0.418823f;	val_dir[11525*3 + 1] = 0.088173f;	val_dir[11525*3 + 2] = -0.903777f;
+ 	val_dir[11526*3 + 0] = 0.453376f;	val_dir[11526*3 + 1] = 0.113344f;	val_dir[11526*3 + 2] = -0.884083f;
+ 	val_dir[11527*3 + 0] = 0.488769f;	val_dir[11527*3 + 1] = 0.139648f;	val_dir[11527*3 + 2] = -0.861164f;
+ 	val_dir[11528*3 + 0] = 0.524703f;	val_dir[11528*3 + 1] = 0.166951f;	val_dir[11528*3 + 2] = -0.834754f;
+ 	val_dir[11529*3 + 0] = 0.560809f;	val_dir[11529*3 + 1] = 0.195064f;	val_dir[11529*3 + 2] = -0.804639f;
+ 	val_dir[11530*3 + 0] = 0.596653f;	val_dir[11530*3 + 1] = 0.223745f;	val_dir[11530*3 + 2] = -0.770677f;
+ 	val_dir[11531*3 + 0] = 0.631748f;	val_dir[11531*3 + 1] = 0.252699f;	val_dir[11531*3 + 2] = -0.732828f;
+ 	val_dir[11532*3 + 0] = 0.665574f;	val_dir[11532*3 + 1] = 0.281589f;	val_dir[11532*3 + 2] = -0.691173f;
+ 	val_dir[11533*3 + 0] = 0.697602f;	val_dir[11533*3 + 1] = 0.310045f;	val_dir[11533*3 + 2] = -0.645928f;
+ 	val_dir[11534*3 + 0] = 0.727334f;	val_dir[11534*3 + 1] = 0.337691f;	val_dir[11534*3 + 2] = -0.597453f;
+ 	val_dir[11535*3 + 0] = 0.754329f;	val_dir[11535*3 + 1] = 0.364159f;	val_dir[11535*3 + 2] = -0.546238f;
+ 	val_dir[11536*3 + 0] = 0.778237f;	val_dir[11536*3 + 1] = 0.389118f;	val_dir[11536*3 + 2] = -0.492883f;
+ 	val_dir[11537*3 + 0] = 0.798820f;	val_dir[11537*3 + 1] = 0.412294f;	val_dir[11537*3 + 2] = -0.438063f;
+ 	val_dir[11538*3 + 0] = 0.815966f;	val_dir[11538*3 + 1] = 0.433482f;	val_dir[11538*3 + 2] = -0.382484f;
+ 	val_dir[11539*3 + 0] = 0.829680f;	val_dir[11539*3 + 1] = 0.452553f;	val_dir[11539*3 + 2] = -0.326844f;
+ 	val_dir[11540*3 + 0] = 0.840083f;	val_dir[11540*3 + 1] = 0.469458f;	val_dir[11540*3 + 2] = -0.271791f;
+ 	val_dir[11541*3 + 0] = 0.847381f;	val_dir[11541*3 + 1] = 0.484217f;	val_dir[11541*3 + 2] = -0.217898f;
+ 	val_dir[11542*3 + 0] = 0.851847f;	val_dir[11542*3 + 1] = 0.496911f;	val_dir[11542*3 + 2] = -0.165637f;
+ 	val_dir[11543*3 + 0] = 0.853796f;	val_dir[11543*3 + 1] = 0.507662f;	val_dir[11543*3 + 2] = -0.115378f;
+ 	val_dir[11544*3 + 0] = 0.853556f;	val_dir[11544*3 + 1] = 0.516626f;	val_dir[11544*3 + 2] = -0.067386f;
+ 	val_dir[11545*3 + 0] = 0.851455f;	val_dir[11545*3 + 1] = 0.523973f;	val_dir[11545*3 + 2] = -0.021832f;
+ 	val_dir[11546*3 + 0] = -0.539666f;	val_dir[11546*3 + 1] = -0.841879f;	val_dir[11546*3 + 2] = 0.0f;
+ 	val_dir[11547*3 + 0] = -0.533465f;	val_dir[11547*3 + 1] = -0.844653f;	val_dir[11547*3 + 2] = -0.044455f;
+ 	val_dir[11548*3 + 0] = -0.525723f;	val_dir[11548*3 + 1] = -0.845728f;	val_dir[11548*3 + 2] = -0.091430f;
+ 	val_dir[11549*3 + 0] = -0.516256f;	val_dir[11549*3 + 1] = -0.844782f;	val_dir[11549*3 + 2] = -0.140797f;
+ 	val_dir[11550*3 + 0] = -0.504889f;	val_dir[11550*3 + 1] = -0.841482f;	val_dir[11550*3 + 2] = -0.192339f;
+ 	val_dir[11551*3 + 0] = -0.491473f;	val_dir[11551*3 + 1] = -0.835504f;	val_dir[11551*3 + 2] = -0.245737f;
+ 	val_dir[11552*3 + 0] = -0.475893f;	val_dir[11552*3 + 1] = -0.826551f;	val_dir[11552*3 + 2] = -0.300564f;
+ 	val_dir[11553*3 + 0] = -0.458088f;	val_dir[11553*3 + 1] = -0.814379f;	val_dir[11553*3 + 2] = -0.356291f;
+ 	val_dir[11554*3 + 0] = -0.438063f;	val_dir[11554*3 + 1] = -0.798820f;	val_dir[11554*3 + 2] = -0.412294f;
+ 	val_dir[11555*3 + 0] = -0.41590f;	val_dir[11555*3 + 1] = -0.779813f;	val_dir[11555*3 + 2] = -0.467888f;
+ 	val_dir[11556*3 + 0] = -0.391764f;	val_dir[11556*3 + 1] = -0.757410f;	val_dir[11556*3 + 2] = -0.522352f;
+ 	val_dir[11557*3 + 0] = -0.365896f;	val_dir[11557*3 + 1] = -0.731792f;	val_dir[11557*3 + 2] = -0.574979f;
+ 	val_dir[11558*3 + 0] = -0.338606f;	val_dir[11558*3 + 1] = -0.703259f;	val_dir[11558*3 + 2] = -0.625119f;
+ 	val_dir[11559*3 + 0] = -0.310253f;	val_dir[11559*3 + 1] = -0.672214f;	val_dir[11559*3 + 2] = -0.672214f;
+ 	val_dir[11560*3 + 0] = -0.281220f;	val_dir[11560*3 + 1] = -0.639138f;	val_dir[11560*3 + 2] = -0.715834f;
+ 	val_dir[11561*3 + 0] = -0.251896f;	val_dir[11561*3 + 1] = -0.604551f;	val_dir[11561*3 + 2] = -0.755689f;
+ 	val_dir[11562*3 + 0] = -0.222647f;	val_dir[11562*3 + 1] = -0.568986f;	val_dir[11562*3 + 2] = -0.791633f;
+ 	val_dir[11563*3 + 0] = -0.193801f;	val_dir[11563*3 + 1] = -0.532952f;	val_dir[11563*3 + 2] = -0.823653f;
+ 	val_dir[11564*3 + 0] = -0.165637f;	val_dir[11564*3 + 1] = -0.496911f;	val_dir[11564*3 + 2] = -0.851847f;
+ 	val_dir[11565*3 + 0] = -0.138380f;	val_dir[11565*3 + 1] = -0.461266f;	val_dir[11565*3 + 2] = -0.876405f;
+ 	val_dir[11566*3 + 0] = -0.112197f;	val_dir[11566*3 + 1] = -0.426348f;	val_dir[11566*3 + 2] = -0.897574f;
+ 	val_dir[11567*3 + 0] = -0.087204f;	val_dir[11567*3 + 1] = -0.392419f;	val_dir[11567*3 + 2] = -0.915644f;
+ 	val_dir[11568*3 + 0] = -0.063472f;	val_dir[11568*3 + 1] = -0.359673f;	val_dir[11568*3 + 2] = -0.930917f;
+ 	val_dir[11569*3 + 0] = -0.041030f;	val_dir[11569*3 + 1] = -0.328244f;	val_dir[11569*3 + 2] = -0.943701f;
+ 	val_dir[11570*3 + 0] = -0.019881f;	val_dir[11570*3 + 1] = -0.298216f;	val_dir[11570*3 + 2] = -0.954291f;
+ 	val_dir[11571*3 + 0] = 0.0f;	val_dir[11571*3 + 1] = -0.269630f;	val_dir[11571*3 + 2] = -0.962964f;
+ 	val_dir[11572*3 + 0] = 0.019353f;	val_dir[11572*3 + 1] = -0.251587f;	val_dir[11572*3 + 2] = -0.967641f;
+ 	val_dir[11573*3 + 0] = 0.038866f;	val_dir[11573*3 + 1] = -0.233197f;	val_dir[11573*3 + 2] = -0.971653f;
+ 	val_dir[11574*3 + 0] = 0.058498f;	val_dir[11574*3 + 1] = -0.214494f;	val_dir[11574*3 + 2] = -0.974972f;
+ 	val_dir[11575*3 + 0] = 0.078206f;	val_dir[11575*3 + 1] = -0.195515f;	val_dir[11575*3 + 2] = -0.977577f;
+ 	val_dir[11576*3 + 0] = 0.097945f;	val_dir[11576*3 + 1] = -0.176301f;	val_dir[11576*3 + 2] = -0.979451f;
+ 	val_dir[11577*3 + 0] = 0.117670f;	val_dir[11577*3 + 1] = -0.156893f;	val_dir[11577*3 + 2] = -0.980581f;
+ 	val_dir[11578*3 + 0] = 0.137334f;	val_dir[11578*3 + 1] = -0.137334f;	val_dir[11578*3 + 2] = -0.980958f;
+ 	val_dir[11579*3 + 0] = 0.156893f;	val_dir[11579*3 + 1] = -0.117670f;	val_dir[11579*3 + 2] = -0.980581f;
+ 	val_dir[11580*3 + 0] = 0.176301f;	val_dir[11580*3 + 1] = -0.097945f;	val_dir[11580*3 + 2] = -0.979451f;
+ 	val_dir[11581*3 + 0] = 0.195515f;	val_dir[11581*3 + 1] = -0.078206f;	val_dir[11581*3 + 2] = -0.977577f;
+ 	val_dir[11582*3 + 0] = 0.214494f;	val_dir[11582*3 + 1] = -0.058498f;	val_dir[11582*3 + 2] = -0.974972f;
+ 	val_dir[11583*3 + 0] = 0.233197f;	val_dir[11583*3 + 1] = -0.038866f;	val_dir[11583*3 + 2] = -0.971653f;
+ 	val_dir[11584*3 + 0] = 0.251587f;	val_dir[11584*3 + 1] = -0.019353f;	val_dir[11584*3 + 2] = -0.967641f;
+ 	val_dir[11585*3 + 0] = 0.269630f;	val_dir[11585*3 + 1] = 0.0f;	val_dir[11585*3 + 2] = -0.962964f;
+ 	val_dir[11586*3 + 0] = 0.298216f;	val_dir[11586*3 + 1] = 0.019881f;	val_dir[11586*3 + 2] = -0.954291f;
+ 	val_dir[11587*3 + 0] = 0.328244f;	val_dir[11587*3 + 1] = 0.041030f;	val_dir[11587*3 + 2] = -0.943701f;
+ 	val_dir[11588*3 + 0] = 0.359673f;	val_dir[11588*3 + 1] = 0.063472f;	val_dir[11588*3 + 2] = -0.930917f;
+ 	val_dir[11589*3 + 0] = 0.392419f;	val_dir[11589*3 + 1] = 0.087204f;	val_dir[11589*3 + 2] = -0.915644f;
+ 	val_dir[11590*3 + 0] = 0.426348f;	val_dir[11590*3 + 1] = 0.112197f;	val_dir[11590*3 + 2] = -0.897574f;
+ 	val_dir[11591*3 + 0] = 0.461266f;	val_dir[11591*3 + 1] = 0.138380f;	val_dir[11591*3 + 2] = -0.876405f;
+ 	val_dir[11592*3 + 0] = 0.496911f;	val_dir[11592*3 + 1] = 0.165637f;	val_dir[11592*3 + 2] = -0.851847f;
+ 	val_dir[11593*3 + 0] = 0.532952f;	val_dir[11593*3 + 1] = 0.193801f;	val_dir[11593*3 + 2] = -0.823653f;
+ 	val_dir[11594*3 + 0] = 0.568986f;	val_dir[11594*3 + 1] = 0.222647f;	val_dir[11594*3 + 2] = -0.791633f;
+ 	val_dir[11595*3 + 0] = 0.604551f;	val_dir[11595*3 + 1] = 0.251896f;	val_dir[11595*3 + 2] = -0.755689f;
+ 	val_dir[11596*3 + 0] = 0.639138f;	val_dir[11596*3 + 1] = 0.281220f;	val_dir[11596*3 + 2] = -0.715834f;
+ 	val_dir[11597*3 + 0] = 0.672214f;	val_dir[11597*3 + 1] = 0.310253f;	val_dir[11597*3 + 2] = -0.672214f;
+ 	val_dir[11598*3 + 0] = 0.703259f;	val_dir[11598*3 + 1] = 0.338606f;	val_dir[11598*3 + 2] = -0.625119f;
+ 	val_dir[11599*3 + 0] = 0.731792f;	val_dir[11599*3 + 1] = 0.365896f;	val_dir[11599*3 + 2] = -0.574979f;
+ 	val_dir[11600*3 + 0] = 0.757410f;	val_dir[11600*3 + 1] = 0.391764f;	val_dir[11600*3 + 2] = -0.522352f;
+ 	val_dir[11601*3 + 0] = 0.779813f;	val_dir[11601*3 + 1] = 0.41590f;	val_dir[11601*3 + 2] = -0.467888f;
+ 	val_dir[11602*3 + 0] = 0.798820f;	val_dir[11602*3 + 1] = 0.438063f;	val_dir[11602*3 + 2] = -0.412294f;
+ 	val_dir[11603*3 + 0] = 0.814379f;	val_dir[11603*3 + 1] = 0.458088f;	val_dir[11603*3 + 2] = -0.356291f;
+ 	val_dir[11604*3 + 0] = 0.826551f;	val_dir[11604*3 + 1] = 0.475893f;	val_dir[11604*3 + 2] = -0.300564f;
+ 	val_dir[11605*3 + 0] = 0.835504f;	val_dir[11605*3 + 1] = 0.491473f;	val_dir[11605*3 + 2] = -0.245737f;
+ 	val_dir[11606*3 + 0] = 0.841482f;	val_dir[11606*3 + 1] = 0.504889f;	val_dir[11606*3 + 2] = -0.192339f;
+ 	val_dir[11607*3 + 0] = 0.844782f;	val_dir[11607*3 + 1] = 0.516256f;	val_dir[11607*3 + 2] = -0.140797f;
+ 	val_dir[11608*3 + 0] = 0.845728f;	val_dir[11608*3 + 1] = 0.525723f;	val_dir[11608*3 + 2] = -0.091430f;
+ 	val_dir[11609*3 + 0] = 0.844653f;	val_dir[11609*3 + 1] = 0.533465f;	val_dir[11609*3 + 2] = -0.044455f;
+ 	val_dir[11610*3 + 0] = 0.841879f;	val_dir[11610*3 + 1] = 0.539666f;	val_dir[11610*3 + 2] = 0.0f;
+ 	val_dir[11611*3 + 0] = -0.549484f;	val_dir[11611*3 + 1] = -0.835215f;	val_dir[11611*3 + 2] = -0.021979f;
+ 	val_dir[11612*3 + 0] = -0.542936f;	val_dir[11612*3 + 1] = -0.837027f;	val_dir[11612*3 + 2] = -0.067867f;
+ 	val_dir[11613*3 + 0] = -0.534739f;	val_dir[11613*3 + 1] = -0.836983f;	val_dir[11613*3 + 2] = -0.116248f;
+ 	val_dir[11614*3 + 0] = -0.524703f;	val_dir[11614*3 + 1] = -0.834754f;	val_dir[11614*3 + 2] = -0.166951f;
+ 	val_dir[11615*3 + 0] = -0.512653f;	val_dir[11615*3 + 1] = -0.830009f;	val_dir[11615*3 + 2] = -0.219708f;
+ 	val_dir[11616*3 + 0] = -0.498445f;	val_dir[11616*3 + 1] = -0.822434f;	val_dir[11616*3 + 2] = -0.274145f;
+ 	val_dir[11617*3 + 0] = -0.481979f;	val_dir[11617*3 + 1] = -0.811754f;	val_dir[11617*3 + 2] = -0.329775f;
+ 	val_dir[11618*3 + 0] = -0.463217f;	val_dir[11618*3 + 1] = -0.797762f;	val_dir[11618*3 + 2] = -0.386014f;
+ 	val_dir[11619*3 + 0] = -0.442193f;	val_dir[11619*3 + 1] = -0.780340f;	val_dir[11619*3 + 2] = -0.442193f;
+ 	val_dir[11620*3 + 0] = -0.419026f;	val_dir[11620*3 + 1] = -0.759485f;	val_dir[11620*3 + 2] = -0.497594f;
+ 	val_dir[11621*3 + 0] = -0.393919f;	val_dir[11621*3 + 1] = -0.735316f;	val_dir[11621*3 + 2] = -0.551487f;
+ 	val_dir[11622*3 + 0] = -0.367152f;	val_dir[11622*3 + 1] = -0.708079f;	val_dir[11622*3 + 2] = -0.603178f;
+ 	val_dir[11623*3 + 0] = -0.339066f;	val_dir[11623*3 + 1] = -0.678133f;	val_dir[11623*3 + 2] = -0.652051f;
+ 	val_dir[11624*3 + 0] = -0.310045f;	val_dir[11624*3 + 1] = -0.645928f;	val_dir[11624*3 + 2] = -0.697602f;
+ 	val_dir[11625*3 + 0] = -0.280488f;	val_dir[11625*3 + 1] = -0.611974f;	val_dir[11625*3 + 2] = -0.739469f;
+ 	val_dir[11626*3 + 0] = -0.250785f;	val_dir[11626*3 + 1] = -0.576805f;	val_dir[11626*3 + 2] = -0.777433f;
+ 	val_dir[11627*3 + 0] = -0.221297f;	val_dir[11627*3 + 1] = -0.540947f;	val_dir[11627*3 + 2] = -0.811421f;
+ 	val_dir[11628*3 + 0] = -0.192339f;	val_dir[11628*3 + 1] = -0.504889f;	val_dir[11628*3 + 2] = -0.841482f;
+ 	val_dir[11629*3 + 0] = -0.164173f;	val_dir[11629*3 + 1] = -0.469065f;	val_dir[11629*3 + 2] = -0.867770f;
+ 	val_dir[11630*3 + 0] = -0.137002f;	val_dir[11630*3 + 1] = -0.433840f;	val_dir[11630*3 + 2] = -0.890513f;
+ 	val_dir[11631*3 + 0] = -0.110974f;	val_dir[11631*3 + 1] = -0.399507f;	val_dir[11631*3 + 2] = -0.909988f;
+ 	val_dir[11632*3 + 0] = -0.086186f;	val_dir[11632*3 + 1] = -0.366291f;	val_dir[11632*3 + 2] = -0.92650f;
+ 	val_dir[11633*3 + 0] = -0.062691f;	val_dir[11633*3 + 1] = -0.334351f;	val_dir[11633*3 + 2] = -0.940361f;
+ 	val_dir[11634*3 + 0] = -0.040505f;	val_dir[11634*3 + 1] = -0.303791f;	val_dir[11634*3 + 2] = -0.951877f;
+ 	val_dir[11635*3 + 0] = -0.019619f;	val_dir[11635*3 + 1] = -0.274668f;	val_dir[11635*3 + 2] = -0.961339f;
+ 	val_dir[11636*3 + 0] = 0.0f;	val_dir[11636*3 + 1] = -0.247004f;	val_dir[11636*3 + 2] = -0.969015f;
+ 	val_dir[11637*3 + 0] = 0.019083f;	val_dir[11637*3 + 1] = -0.228998f;	val_dir[11637*3 + 2] = -0.973240f;
+ 	val_dir[11638*3 + 0] = 0.038306f;	val_dir[11638*3 + 1] = -0.210683f;	val_dir[11638*3 + 2] = -0.976804f;
+ 	val_dir[11639*3 + 0] = 0.057628f;	val_dir[11639*3 + 1] = -0.192095f;	val_dir[11639*3 + 2] = -0.979683f;
+ 	val_dir[11640*3 + 0] = 0.077009f;	val_dir[11640*3 + 1] = -0.173269f;	val_dir[11640*3 + 2] = -0.981859f;
+ 	val_dir[11641*3 + 0] = 0.096404f;	val_dir[11641*3 + 1] = -0.154246f;	val_dir[11641*3 + 2] = -0.983318f;
+ 	val_dir[11642*3 + 0] = 0.115771f;	val_dir[11642*3 + 1] = -0.135066f;	val_dir[11642*3 + 2] = -0.984050f;
+ 	val_dir[11643*3 + 0] = 0.135066f;	val_dir[11643*3 + 1] = -0.115771f;	val_dir[11643*3 + 2] = -0.984050f;
+ 	val_dir[11644*3 + 0] = 0.154246f;	val_dir[11644*3 + 1] = -0.096404f;	val_dir[11644*3 + 2] = -0.983318f;
+ 	val_dir[11645*3 + 0] = 0.173269f;	val_dir[11645*3 + 1] = -0.077009f;	val_dir[11645*3 + 2] = -0.981859f;
+ 	val_dir[11646*3 + 0] = 0.192095f;	val_dir[11646*3 + 1] = -0.057628f;	val_dir[11646*3 + 2] = -0.979683f;
+ 	val_dir[11647*3 + 0] = 0.210683f;	val_dir[11647*3 + 1] = -0.038306f;	val_dir[11647*3 + 2] = -0.976804f;
+ 	val_dir[11648*3 + 0] = 0.228998f;	val_dir[11648*3 + 1] = -0.019083f;	val_dir[11648*3 + 2] = -0.973240f;
+ 	val_dir[11649*3 + 0] = 0.247004f;	val_dir[11649*3 + 1] = 0.0f;	val_dir[11649*3 + 2] = -0.969015f;
+ 	val_dir[11650*3 + 0] = 0.274668f;	val_dir[11650*3 + 1] = 0.019619f;	val_dir[11650*3 + 2] = -0.961339f;
+ 	val_dir[11651*3 + 0] = 0.303791f;	val_dir[11651*3 + 1] = 0.040505f;	val_dir[11651*3 + 2] = -0.951877f;
+ 	val_dir[11652*3 + 0] = 0.334351f;	val_dir[11652*3 + 1] = 0.062691f;	val_dir[11652*3 + 2] = -0.940361f;
+ 	val_dir[11653*3 + 0] = 0.366291f;	val_dir[11653*3 + 1] = 0.086186f;	val_dir[11653*3 + 2] = -0.92650f;
+ 	val_dir[11654*3 + 0] = 0.399507f;	val_dir[11654*3 + 1] = 0.110974f;	val_dir[11654*3 + 2] = -0.909988f;
+ 	val_dir[11655*3 + 0] = 0.433840f;	val_dir[11655*3 + 1] = 0.137002f;	val_dir[11655*3 + 2] = -0.890513f;
+ 	val_dir[11656*3 + 0] = 0.469065f;	val_dir[11656*3 + 1] = 0.164173f;	val_dir[11656*3 + 2] = -0.867770f;
+ 	val_dir[11657*3 + 0] = 0.504889f;	val_dir[11657*3 + 1] = 0.192339f;	val_dir[11657*3 + 2] = -0.841482f;
+ 	val_dir[11658*3 + 0] = 0.540947f;	val_dir[11658*3 + 1] = 0.221297f;	val_dir[11658*3 + 2] = -0.811421f;
+ 	val_dir[11659*3 + 0] = 0.576805f;	val_dir[11659*3 + 1] = 0.250785f;	val_dir[11659*3 + 2] = -0.777433f;
+ 	val_dir[11660*3 + 0] = 0.611974f;	val_dir[11660*3 + 1] = 0.280488f;	val_dir[11660*3 + 2] = -0.739469f;
+ 	val_dir[11661*3 + 0] = 0.645928f;	val_dir[11661*3 + 1] = 0.310045f;	val_dir[11661*3 + 2] = -0.697602f;
+ 	val_dir[11662*3 + 0] = 0.678133f;	val_dir[11662*3 + 1] = 0.339066f;	val_dir[11662*3 + 2] = -0.652051f;
+ 	val_dir[11663*3 + 0] = 0.708079f;	val_dir[11663*3 + 1] = 0.367152f;	val_dir[11663*3 + 2] = -0.603178f;
+ 	val_dir[11664*3 + 0] = 0.735316f;	val_dir[11664*3 + 1] = 0.393919f;	val_dir[11664*3 + 2] = -0.551487f;
+ 	val_dir[11665*3 + 0] = 0.759485f;	val_dir[11665*3 + 1] = 0.419026f;	val_dir[11665*3 + 2] = -0.497594f;
+ 	val_dir[11666*3 + 0] = 0.780340f;	val_dir[11666*3 + 1] = 0.442193f;	val_dir[11666*3 + 2] = -0.442193f;
+ 	val_dir[11667*3 + 0] = 0.797762f;	val_dir[11667*3 + 1] = 0.463217f;	val_dir[11667*3 + 2] = -0.386014f;
+ 	val_dir[11668*3 + 0] = 0.811754f;	val_dir[11668*3 + 1] = 0.481979f;	val_dir[11668*3 + 2] = -0.329775f;
+ 	val_dir[11669*3 + 0] = 0.822434f;	val_dir[11669*3 + 1] = 0.498445f;	val_dir[11669*3 + 2] = -0.274145f;
+ 	val_dir[11670*3 + 0] = 0.830009f;	val_dir[11670*3 + 1] = 0.512653f;	val_dir[11670*3 + 2] = -0.219708f;
+ 	val_dir[11671*3 + 0] = 0.834754f;	val_dir[11671*3 + 1] = 0.524703f;	val_dir[11671*3 + 2] = -0.166951f;
+ 	val_dir[11672*3 + 0] = 0.836983f;	val_dir[11672*3 + 1] = 0.534739f;	val_dir[11672*3 + 2] = -0.116248f;
+ 	val_dir[11673*3 + 0] = 0.837027f;	val_dir[11673*3 + 1] = 0.542936f;	val_dir[11673*3 + 2] = -0.067867f;
+ 	val_dir[11674*3 + 0] = 0.835215f;	val_dir[11674*3 + 1] = 0.549484f;	val_dir[11674*3 + 2] = -0.021979f;
+ 	val_dir[11675*3 + 0] = -0.564684f;	val_dir[11675*3 + 1] = -0.825307f;	val_dir[11675*3 + 2] = 0.0f;
+ 	val_dir[11676*3 + 0] = -0.559297f;	val_dir[11676*3 + 1] = -0.827759f;	val_dir[11676*3 + 2] = -0.044744f;
+ 	val_dir[11677*3 + 0] = -0.552345f;	val_dir[11677*3 + 1] = -0.828517f;	val_dir[11677*3 + 2] = -0.092057f;
+ 	val_dir[11678*3 + 0] = -0.543627f;	val_dir[11678*3 + 1] = -0.827259f;	val_dir[11678*3 + 2] = -0.141816f;
+ 	val_dir[11679*3 + 0] = -0.532952f;	val_dir[11679*3 + 1] = -0.823653f;	val_dir[11679*3 + 2] = -0.193801f;
+ 	val_dir[11680*3 + 0] = -0.520146f;	val_dir[11680*3 + 1] = -0.817373f;	val_dir[11680*3 + 2] = -0.247689f;
+ 	val_dir[11681*3 + 0] = -0.505076f;	val_dir[11681*3 + 1] = -0.808122f;	val_dir[11681*3 + 2] = -0.303046f;
+ 	val_dir[11682*3 + 0] = -0.487661f;	val_dir[11682*3 + 1] = -0.795657f;	val_dir[11682*3 + 2] = -0.359329f;
+ 	val_dir[11683*3 + 0] = -0.467888f;	val_dir[11683*3 + 1] = -0.779813f;	val_dir[11683*3 + 2] = -0.41590f;
+ 	val_dir[11684*3 + 0] = -0.445827f;	val_dir[11684*3 + 1] = -0.760529f;	val_dir[11684*3 + 2] = -0.472053f;
+ 	val_dir[11685*3 + 0] = -0.421637f;	val_dir[11685*3 + 1] = -0.737865f;	val_dir[11685*3 + 2] = -0.527046f;
+ 	val_dir[11686*3 + 0] = -0.395559f;	val_dir[11686*3 + 1] = -0.712007f;	val_dir[11686*3 + 2] = -0.580154f;
+ 	val_dir[11687*3 + 0] = -0.367912f;	val_dir[11687*3 + 1] = -0.683265f;	val_dir[11687*3 + 2] = -0.630706f;
+ 	val_dir[11688*3 + 0] = -0.339066f;	val_dir[11688*3 + 1] = -0.652051f;	val_dir[11688*3 + 2] = -0.678133f;
+ 	val_dir[11689*3 + 0] = -0.309426f;	val_dir[11689*3 + 1] = -0.618853f;	val_dir[11689*3 + 2] = -0.721995f;
+ 	val_dir[11690*3 + 0] = -0.27940f;	val_dir[11690*3 + 1] = -0.584201f;	val_dir[11690*3 + 2] = -0.762001f;
+ 	val_dir[11691*3 + 0] = -0.249377f;	val_dir[11691*3 + 1] = -0.548630f;	val_dir[11691*3 + 2] = -0.798007f;
+ 	val_dir[11692*3 + 0] = -0.219708f;	val_dir[11692*3 + 1] = -0.512653f;	val_dir[11692*3 + 2] = -0.830009f;
+ 	val_dir[11693*3 + 0] = -0.190693f;	val_dir[11693*3 + 1] = -0.476731f;	val_dir[11693*3 + 2] = -0.858116f;
+ 	val_dir[11694*3 + 0] = -0.162571f;	val_dir[11694*3 + 1] = -0.441264f;	val_dir[11694*3 + 2] = -0.882528f;
+ 	val_dir[11695*3 + 0] = -0.135526f;	val_dir[11695*3 + 1] = -0.406579f;	val_dir[11695*3 + 2] = -0.903508f;
+ 	val_dir[11696*3 + 0] = -0.109685f;	val_dir[11696*3 + 1] = -0.372929f;	val_dir[11696*3 + 2] = -0.921354f;
+ 	val_dir[11697*3 + 0] = -0.085126f;	val_dir[11697*3 + 1] = -0.340503f;	val_dir[11697*3 + 2] = -0.936382f;
+ 	val_dir[11698*3 + 0] = -0.061885f;	val_dir[11698*3 + 1] = -0.309426f;	val_dir[11698*3 + 2] = -0.948908f;
+ 	val_dir[11699*3 + 0] = -0.039968f;	val_dir[11699*3 + 1] = -0.279776f;	val_dir[11699*3 + 2] = -0.959233f;
+ 	val_dir[11700*3 + 0] = -0.019353f;	val_dir[11700*3 + 1] = -0.251587f;	val_dir[11700*3 + 2] = -0.967641f;
+ 	val_dir[11701*3 + 0] = 0.0f;	val_dir[11701*3 + 1] = -0.224860f;	val_dir[11701*3 + 2] = -0.974391f;
+ 	val_dir[11702*3 + 0] = 0.018811f;	val_dir[11702*3 + 1] = -0.206922f;	val_dir[11702*3 + 2] = -0.978177f;
+ 	val_dir[11703*3 + 0] = 0.037743f;	val_dir[11703*3 + 1] = -0.188713f;	val_dir[11703*3 + 2] = -0.981307f;
+ 	val_dir[11704*3 + 0] = 0.056756f;	val_dir[11704*3 + 1] = -0.170267f;	val_dir[11704*3 + 2] = -0.983762f;
+ 	val_dir[11705*3 + 0] = 0.075810f;	val_dir[11705*3 + 1] = -0.151620f;	val_dir[11705*3 + 2] = -0.985527f;
+ 	val_dir[11706*3 + 0] = 0.094865f;	val_dir[11706*3 + 1] = -0.132810f;	val_dir[11706*3 + 2] = -0.986591f;
+ 	val_dir[11707*3 + 0] = 0.113878f;	val_dir[11707*3 + 1] = -0.113878f;	val_dir[11707*3 + 2] = -0.986947f;
+ 	val_dir[11708*3 + 0] = 0.132810f;	val_dir[11708*3 + 1] = -0.094865f;	val_dir[11708*3 + 2] = -0.986591f;
+ 	val_dir[11709*3 + 0] = 0.151620f;	val_dir[11709*3 + 1] = -0.075810f;	val_dir[11709*3 + 2] = -0.985527f;
+ 	val_dir[11710*3 + 0] = 0.170267f;	val_dir[11710*3 + 1] = -0.056756f;	val_dir[11710*3 + 2] = -0.983762f;
+ 	val_dir[11711*3 + 0] = 0.188713f;	val_dir[11711*3 + 1] = -0.037743f;	val_dir[11711*3 + 2] = -0.981307f;
+ 	val_dir[11712*3 + 0] = 0.206922f;	val_dir[11712*3 + 1] = -0.018811f;	val_dir[11712*3 + 2] = -0.978177f;
+ 	val_dir[11713*3 + 0] = 0.224860f;	val_dir[11713*3 + 1] = 0.0f;	val_dir[11713*3 + 2] = -0.974391f;
+ 	val_dir[11714*3 + 0] = 0.251587f;	val_dir[11714*3 + 1] = 0.019353f;	val_dir[11714*3 + 2] = -0.967641f;
+ 	val_dir[11715*3 + 0] = 0.279776f;	val_dir[11715*3 + 1] = 0.039968f;	val_dir[11715*3 + 2] = -0.959233f;
+ 	val_dir[11716*3 + 0] = 0.309426f;	val_dir[11716*3 + 1] = 0.061885f;	val_dir[11716*3 + 2] = -0.948908f;
+ 	val_dir[11717*3 + 0] = 0.340503f;	val_dir[11717*3 + 1] = 0.085126f;	val_dir[11717*3 + 2] = -0.936382f;
+ 	val_dir[11718*3 + 0] = 0.372929f;	val_dir[11718*3 + 1] = 0.109685f;	val_dir[11718*3 + 2] = -0.921354f;
+ 	val_dir[11719*3 + 0] = 0.406579f;	val_dir[11719*3 + 1] = 0.135526f;	val_dir[11719*3 + 2] = -0.903508f;
+ 	val_dir[11720*3 + 0] = 0.441264f;	val_dir[11720*3 + 1] = 0.162571f;	val_dir[11720*3 + 2] = -0.882528f;
+ 	val_dir[11721*3 + 0] = 0.476731f;	val_dir[11721*3 + 1] = 0.190693f;	val_dir[11721*3 + 2] = -0.858116f;
+ 	val_dir[11722*3 + 0] = 0.512653f;	val_dir[11722*3 + 1] = 0.219708f;	val_dir[11722*3 + 2] = -0.830009f;
+ 	val_dir[11723*3 + 0] = 0.548630f;	val_dir[11723*3 + 1] = 0.249377f;	val_dir[11723*3 + 2] = -0.798007f;
+ 	val_dir[11724*3 + 0] = 0.584201f;	val_dir[11724*3 + 1] = 0.27940f;	val_dir[11724*3 + 2] = -0.762001f;
+ 	val_dir[11725*3 + 0] = 0.618853f;	val_dir[11725*3 + 1] = 0.309426f;	val_dir[11725*3 + 2] = -0.721995f;
+ 	val_dir[11726*3 + 0] = 0.652051f;	val_dir[11726*3 + 1] = 0.339066f;	val_dir[11726*3 + 2] = -0.678133f;
+ 	val_dir[11727*3 + 0] = 0.683265f;	val_dir[11727*3 + 1] = 0.367912f;	val_dir[11727*3 + 2] = -0.630706f;
+ 	val_dir[11728*3 + 0] = 0.712007f;	val_dir[11728*3 + 1] = 0.395559f;	val_dir[11728*3 + 2] = -0.580154f;
+ 	val_dir[11729*3 + 0] = 0.737865f;	val_dir[11729*3 + 1] = 0.421637f;	val_dir[11729*3 + 2] = -0.527046f;
+ 	val_dir[11730*3 + 0] = 0.760529f;	val_dir[11730*3 + 1] = 0.445827f;	val_dir[11730*3 + 2] = -0.472053f;
+ 	val_dir[11731*3 + 0] = 0.779813f;	val_dir[11731*3 + 1] = 0.467888f;	val_dir[11731*3 + 2] = -0.41590f;
+ 	val_dir[11732*3 + 0] = 0.795657f;	val_dir[11732*3 + 1] = 0.487661f;	val_dir[11732*3 + 2] = -0.359329f;
+ 	val_dir[11733*3 + 0] = 0.808122f;	val_dir[11733*3 + 1] = 0.505076f;	val_dir[11733*3 + 2] = -0.303046f;
+ 	val_dir[11734*3 + 0] = 0.817373f;	val_dir[11734*3 + 1] = 0.520146f;	val_dir[11734*3 + 2] = -0.247689f;
+ 	val_dir[11735*3 + 0] = 0.823653f;	val_dir[11735*3 + 1] = 0.532952f;	val_dir[11735*3 + 2] = -0.193801f;
+ 	val_dir[11736*3 + 0] = 0.827259f;	val_dir[11736*3 + 1] = 0.543627f;	val_dir[11736*3 + 2] = -0.141816f;
+ 	val_dir[11737*3 + 0] = 0.828517f;	val_dir[11737*3 + 1] = 0.552345f;	val_dir[11737*3 + 2] = -0.092057f;
+ 	val_dir[11738*3 + 0] = 0.827759f;	val_dir[11738*3 + 1] = 0.559297f;	val_dir[11738*3 + 2] = -0.044744f;
+ 	val_dir[11739*3 + 0] = 0.825307f;	val_dir[11739*3 + 1] = 0.564684f;	val_dir[11739*3 + 2] = 0.0f;
+ 	val_dir[11740*3 + 0] = -0.574805f;	val_dir[11740*3 + 1] = -0.817992f;	val_dir[11740*3 + 2] = -0.022108f;
+ 	val_dir[11741*3 + 0] = -0.569064f;	val_dir[11741*3 + 1] = -0.819453f;	val_dir[11741*3 + 2] = -0.068288f;
+ 	val_dir[11742*3 + 0] = -0.561644f;	val_dir[11742*3 + 1] = -0.819064f;	val_dir[11742*3 + 2] = -0.117009f;
+ 	val_dir[11743*3 + 0] = -0.552336f;	val_dir[11743*3 + 1] = -0.816497f;	val_dir[11743*3 + 2] = -0.168102f;
+ 	val_dir[11744*3 + 0] = -0.540947f;	val_dir[11744*3 + 1] = -0.811421f;	val_dir[11744*3 + 2] = -0.221297f;
+ 	val_dir[11745*3 + 0] = -0.527312f;	val_dir[11745*3 + 1] = -0.803523f;	val_dir[11745*3 + 2] = -0.276211f;
+ 	val_dir[11746*3 + 0] = -0.511310f;	val_dir[11746*3 + 1] = -0.792530f;	val_dir[11746*3 + 2] = -0.332352f;
+ 	val_dir[11747*3 + 0] = -0.492883f;	val_dir[11747*3 + 1] = -0.778237f;	val_dir[11747*3 + 2] = -0.389118f;
+ 	val_dir[11748*3 + 0] = -0.472053f;	val_dir[11748*3 + 1] = -0.760529f;	val_dir[11748*3 + 2] = -0.445827f;
+ 	val_dir[11749*3 + 0] = -0.448926f;	val_dir[11749*3 + 1] = -0.739407f;	val_dir[11749*3 + 2] = -0.501740f;
+ 	val_dir[11750*3 + 0] = -0.423702f;	val_dir[11750*3 + 1] = -0.714997f;	val_dir[11750*3 + 2] = -0.556108f;
+ 	val_dir[11751*3 + 0] = -0.396664f;	val_dir[11751*3 + 1] = -0.687552f;	val_dir[11751*3 + 2] = -0.608219f;
+ 	val_dir[11752*3 + 0] = -0.368166f;	val_dir[11752*3 + 1] = -0.657440f;	val_dir[11752*3 + 2] = -0.657440f;
+ 	val_dir[11753*3 + 0] = -0.338606f;	val_dir[11753*3 + 1] = -0.625119f;	val_dir[11753*3 + 2] = -0.703259f;
+ 	val_dir[11754*3 + 0] = -0.308403f;	val_dir[11754*3 + 1] = -0.591105f;	val_dir[11754*3 + 2] = -0.745307f;
+ 	val_dir[11755*3 + 0] = -0.277969f;	val_dir[11755*3 + 1] = -0.555939f;	val_dir[11755*3 + 2] = -0.783368f;
+ 	val_dir[11756*3 + 0] = -0.247689f;	val_dir[11756*3 + 1] = -0.520146f;	val_dir[11756*3 + 2] = -0.817373f;
+ 	val_dir[11757*3 + 0] = -0.217898f;	val_dir[11757*3 + 1] = -0.484217f;	val_dir[11757*3 + 2] = -0.847381f;
+ 	val_dir[11758*3 + 0] = -0.188877f;	val_dir[11758*3 + 1] = -0.448583f;	val_dir[11758*3 + 2] = -0.873555f;
+ 	val_dir[11759*3 + 0] = -0.160845f;	val_dir[11759*3 + 1] = -0.413602f;	val_dir[11759*3 + 2] = -0.896137f;
+ 	val_dir[11760*3 + 0] = -0.133963f;	val_dir[11760*3 + 1] = -0.379563f;	val_dir[11760*3 + 2] = -0.915416f;
+ 	val_dir[11761*3 + 0] = -0.108338f;	val_dir[11761*3 + 1] = -0.346681f;	val_dir[11761*3 + 2] = -0.931705f;
+ 	val_dir[11762*3 + 0] = -0.084029f;	val_dir[11762*3 + 1] = -0.315109f;	val_dir[11762*3 + 2] = -0.945328f;
+ 	val_dir[11763*3 + 0] = -0.061059f;	val_dir[11763*3 + 1] = -0.284944f;	val_dir[11763*3 + 2] = -0.956597f;
+ 	val_dir[11764*3 + 0] = -0.039421f;	val_dir[11764*3 + 1] = -0.256235f;	val_dir[11764*3 + 2] = -0.965810f;
+ 	val_dir[11765*3 + 0] = -0.019083f;	val_dir[11765*3 + 1] = -0.228998f;	val_dir[11765*3 + 2] = -0.973240f;
+ 	val_dir[11766*3 + 0] = 0.0f;	val_dir[11766*3 + 1] = -0.203216f;	val_dir[11766*3 + 2] = -0.979134f;
+ 	val_dir[11767*3 + 0] = 0.018538f;	val_dir[11767*3 + 1] = -0.185376f;	val_dir[11767*3 + 2] = -0.982493f;
+ 	val_dir[11768*3 + 0] = 0.037178f;	val_dir[11768*3 + 1] = -0.167299f;	val_dir[11768*3 + 2] = -0.985205f;
+ 	val_dir[11769*3 + 0] = 0.055882f;	val_dir[11769*3 + 1] = -0.149019f;	val_dir[11769*3 + 2] = -0.987254f;
+ 	val_dir[11770*3 + 0] = 0.074613f;	val_dir[11770*3 + 1] = -0.130573f;	val_dir[11770*3 + 2] = -0.988627f;
+ 	val_dir[11771*3 + 0] = 0.093332f;	val_dir[11771*3 + 1] = -0.111998f;	val_dir[11771*3 + 2] = -0.989316f;
+ 	val_dir[11772*3 + 0] = 0.111998f;	val_dir[11772*3 + 1] = -0.093332f;	val_dir[11772*3 + 2] = -0.989316f;
+ 	val_dir[11773*3 + 0] = 0.130573f;	val_dir[11773*3 + 1] = -0.074613f;	val_dir[11773*3 + 2] = -0.988627f;
+ 	val_dir[11774*3 + 0] = 0.149019f;	val_dir[11774*3 + 1] = -0.055882f;	val_dir[11774*3 + 2] = -0.987254f;
+ 	val_dir[11775*3 + 0] = 0.167299f;	val_dir[11775*3 + 1] = -0.037178f;	val_dir[11775*3 + 2] = -0.985205f;
+ 	val_dir[11776*3 + 0] = 0.185376f;	val_dir[11776*3 + 1] = -0.018538f;	val_dir[11776*3 + 2] = -0.982493f;
+ 	val_dir[11777*3 + 0] = 0.203216f;	val_dir[11777*3 + 1] = 0.0f;	val_dir[11777*3 + 2] = -0.979134f;
+ 	val_dir[11778*3 + 0] = 0.228998f;	val_dir[11778*3 + 1] = 0.019083f;	val_dir[11778*3 + 2] = -0.973240f;
+ 	val_dir[11779*3 + 0] = 0.256235f;	val_dir[11779*3 + 1] = 0.039421f;	val_dir[11779*3 + 2] = -0.965810f;
+ 	val_dir[11780*3 + 0] = 0.284944f;	val_dir[11780*3 + 1] = 0.061059f;	val_dir[11780*3 + 2] = -0.956597f;
+ 	val_dir[11781*3 + 0] = 0.315109f;	val_dir[11781*3 + 1] = 0.084029f;	val_dir[11781*3 + 2] = -0.945328f;
+ 	val_dir[11782*3 + 0] = 0.346681f;	val_dir[11782*3 + 1] = 0.108338f;	val_dir[11782*3 + 2] = -0.931705f;
+ 	val_dir[11783*3 + 0] = 0.379563f;	val_dir[11783*3 + 1] = 0.133963f;	val_dir[11783*3 + 2] = -0.915416f;
+ 	val_dir[11784*3 + 0] = 0.413602f;	val_dir[11784*3 + 1] = 0.160845f;	val_dir[11784*3 + 2] = -0.896137f;
+ 	val_dir[11785*3 + 0] = 0.448583f;	val_dir[11785*3 + 1] = 0.188877f;	val_dir[11785*3 + 2] = -0.873555f;
+ 	val_dir[11786*3 + 0] = 0.484217f;	val_dir[11786*3 + 1] = 0.217898f;	val_dir[11786*3 + 2] = -0.847381f;
+ 	val_dir[11787*3 + 0] = 0.520146f;	val_dir[11787*3 + 1] = 0.247689f;	val_dir[11787*3 + 2] = -0.817373f;
+ 	val_dir[11788*3 + 0] = 0.555939f;	val_dir[11788*3 + 1] = 0.277969f;	val_dir[11788*3 + 2] = -0.783368f;
+ 	val_dir[11789*3 + 0] = 0.591105f;	val_dir[11789*3 + 1] = 0.308403f;	val_dir[11789*3 + 2] = -0.745307f;
+ 	val_dir[11790*3 + 0] = 0.625119f;	val_dir[11790*3 + 1] = 0.338606f;	val_dir[11790*3 + 2] = -0.703259f;
+ 	val_dir[11791*3 + 0] = 0.657440f;	val_dir[11791*3 + 1] = 0.368166f;	val_dir[11791*3 + 2] = -0.657440f;
+ 	val_dir[11792*3 + 0] = 0.687552f;	val_dir[11792*3 + 1] = 0.396664f;	val_dir[11792*3 + 2] = -0.608219f;
+ 	val_dir[11793*3 + 0] = 0.714997f;	val_dir[11793*3 + 1] = 0.423702f;	val_dir[11793*3 + 2] = -0.556108f;
+ 	val_dir[11794*3 + 0] = 0.739407f;	val_dir[11794*3 + 1] = 0.448926f;	val_dir[11794*3 + 2] = -0.501740f;
+ 	val_dir[11795*3 + 0] = 0.760529f;	val_dir[11795*3 + 1] = 0.472053f;	val_dir[11795*3 + 2] = -0.445827f;
+ 	val_dir[11796*3 + 0] = 0.778237f;	val_dir[11796*3 + 1] = 0.492883f;	val_dir[11796*3 + 2] = -0.389118f;
+ 	val_dir[11797*3 + 0] = 0.792530f;	val_dir[11797*3 + 1] = 0.511310f;	val_dir[11797*3 + 2] = -0.332352f;
+ 	val_dir[11798*3 + 0] = 0.803523f;	val_dir[11798*3 + 1] = 0.527312f;	val_dir[11798*3 + 2] = -0.276211f;
+ 	val_dir[11799*3 + 0] = 0.811421f;	val_dir[11799*3 + 1] = 0.540947f;	val_dir[11799*3 + 2] = -0.221297f;
+ 	val_dir[11800*3 + 0] = 0.816497f;	val_dir[11800*3 + 1] = 0.552336f;	val_dir[11800*3 + 2] = -0.168102f;
+ 	val_dir[11801*3 + 0] = 0.819064f;	val_dir[11801*3 + 1] = 0.561644f;	val_dir[11801*3 + 2] = -0.117009f;
+ 	val_dir[11802*3 + 0] = 0.819453f;	val_dir[11802*3 + 1] = 0.569064f;	val_dir[11802*3 + 2] = -0.068288f;
+ 	val_dir[11803*3 + 0] = 0.817992f;	val_dir[11803*3 + 1] = 0.574805f;	val_dir[11803*3 + 2] = -0.022108f;
+ 	val_dir[11804*3 + 0] = -0.589469f;	val_dir[11804*3 + 1] = -0.807791f;	val_dir[11804*3 + 2] = 0.0f;
+ 	val_dir[11805*3 + 0] = -0.584898f;	val_dir[11805*3 + 1] = -0.809858f;	val_dir[11805*3 + 2] = -0.044992f;
+ 	val_dir[11806*3 + 0] = -0.578741f;	val_dir[11806*3 + 1] = -0.810237f;	val_dir[11806*3 + 2] = -0.092599f;
+ 	val_dir[11807*3 + 0] = -0.570782f;	val_dir[11807*3 + 1] = -0.808608f;	val_dir[11807*3 + 2] = -0.142695f;
+ 	val_dir[11808*3 + 0] = -0.560809f;	val_dir[11808*3 + 1] = -0.804639f;	val_dir[11808*3 + 2] = -0.195064f;
+ 	val_dir[11809*3 + 0] = -0.548630f;	val_dir[11809*3 + 1] = -0.798007f;	val_dir[11809*3 + 2] = -0.249377f;
+ 	val_dir[11810*3 + 0] = -0.534090f;	val_dir[11810*3 + 1] = -0.788419f;	val_dir[11810*3 + 2] = -0.305194f;
+ 	val_dir[11811*3 + 0] = -0.517088f;	val_dir[11811*3 + 1] = -0.775632f;	val_dir[11811*3 + 2] = -0.361961f;
+ 	val_dir[11812*3 + 0] = -0.497594f;	val_dir[11812*3 + 1] = -0.759485f;	val_dir[11812*3 + 2] = -0.419026f;
+ 	val_dir[11813*3 + 0] = -0.475665f;	val_dir[11813*3 + 1] = -0.739923f;	val_dir[11813*3 + 2] = -0.475665f;
+ 	val_dir[11814*3 + 0] = -0.451451f;	val_dir[11814*3 + 1] = -0.717011f;	val_dir[11814*3 + 2] = -0.531119f;
+ 	val_dir[11815*3 + 0] = -0.425195f;	val_dir[11815*3 + 1] = -0.690942f;	val_dir[11815*3 + 2] = -0.584643f;
+ 	val_dir[11816*3 + 0] = -0.397220f;	val_dir[11816*3 + 1] = -0.662034f;	val_dir[11816*3 + 2] = -0.635553f;
+ 	val_dir[11817*3 + 0] = -0.367912f;	val_dir[11817*3 + 1] = -0.630706f;	val_dir[11817*3 + 2] = -0.683265f;
+ 	val_dir[11818*3 + 0] = -0.337691f;	val_dir[11818*3 + 1] = -0.597453f;	val_dir[11818*3 + 2] = -0.727334f;
+ 	val_dir[11819*3 + 0] = -0.306987f;	val_dir[11819*3 + 1] = -0.562809f;	val_dir[11819*3 + 2] = -0.767467f;
+ 	val_dir[11820*3 + 0] = -0.276211f;	val_dir[11820*3 + 1] = -0.527312f;	val_dir[11820*3 + 2] = -0.803523f;
+ 	val_dir[11821*3 + 0] = -0.245737f;	val_dir[11821*3 + 1] = -0.491473f;	val_dir[11821*3 + 2] = -0.835504f;
+ 	val_dir[11822*3 + 0] = -0.215883f;	val_dir[11822*3 + 1] = -0.455752f;	val_dir[11822*3 + 2] = -0.863530f;
+ 	val_dir[11823*3 + 0] = -0.186908f;	val_dir[11823*3 + 1] = -0.420542f;	val_dir[11823*3 + 2] = -0.887812f;
+ 	val_dir[11824*3 + 0] = -0.159009f;	val_dir[11824*3 + 1] = -0.386164f;	val_dir[11824*3 + 2] = -0.908622f;
+ 	val_dir[11825*3 + 0] = -0.132324f;	val_dir[11825*3 + 1] = -0.352865f;	val_dir[11825*3 + 2] = -0.926270f;
+ 	val_dir[11826*3 + 0] = -0.106941f;	val_dir[11826*3 + 1] = -0.320824f;	val_dir[11826*3 + 2] = -0.941082f;
+ 	val_dir[11827*3 + 0] = -0.082903f;	val_dir[11827*3 + 1] = -0.290159f;	val_dir[11827*3 + 2] = -0.953381f;
+ 	val_dir[11828*3 + 0] = -0.060217f;	val_dir[11828*3 + 1] = -0.260941f;	val_dir[11828*3 + 2] = -0.963475f;
+ 	val_dir[11829*3 + 0] = -0.038866f;	val_dir[11829*3 + 1] = -0.233197f;	val_dir[11829*3 + 2] = -0.971653f;
+ 	val_dir[11830*3 + 0] = -0.018811f;	val_dir[11830*3 + 1] = -0.206922f;	val_dir[11830*3 + 2] = -0.978177f;
+ 	val_dir[11831*3 + 0] = 0.0f;	val_dir[11831*3 + 1] = -0.182089f;	val_dir[11831*3 + 2] = -0.983282f;
+ 	val_dir[11832*3 + 0] = 0.018264f;	val_dir[11832*3 + 1] = -0.164372f;	val_dir[11832*3 + 2] = -0.986229f;
+ 	val_dir[11833*3 + 0] = 0.036613f;	val_dir[11833*3 + 1] = -0.146450f;	val_dir[11833*3 + 2] = -0.988540f;
+ 	val_dir[11834*3 + 0] = 0.055011f;	val_dir[11834*3 + 1] = -0.128359f;	val_dir[11834*3 + 2] = -0.990201f;
+ 	val_dir[11835*3 + 0] = 0.073422f;	val_dir[11835*3 + 1] = -0.110133f;	val_dir[11835*3 + 2] = -0.991201f;
+ 	val_dir[11836*3 + 0] = 0.091809f;	val_dir[11836*3 + 1] = -0.091809f;	val_dir[11836*3 + 2] = -0.991535f;
+ 	val_dir[11837*3 + 0] = 0.110133f;	val_dir[11837*3 + 1] = -0.073422f;	val_dir[11837*3 + 2] = -0.991201f;
+ 	val_dir[11838*3 + 0] = 0.128359f;	val_dir[11838*3 + 1] = -0.055011f;	val_dir[11838*3 + 2] = -0.990201f;
+ 	val_dir[11839*3 + 0] = 0.146450f;	val_dir[11839*3 + 1] = -0.036613f;	val_dir[11839*3 + 2] = -0.988540f;
+ 	val_dir[11840*3 + 0] = 0.164372f;	val_dir[11840*3 + 1] = -0.018264f;	val_dir[11840*3 + 2] = -0.986229f;
+ 	val_dir[11841*3 + 0] = 0.182089f;	val_dir[11841*3 + 1] = 0.0f;	val_dir[11841*3 + 2] = -0.983282f;
+ 	val_dir[11842*3 + 0] = 0.206922f;	val_dir[11842*3 + 1] = 0.018811f;	val_dir[11842*3 + 2] = -0.978177f;
+ 	val_dir[11843*3 + 0] = 0.233197f;	val_dir[11843*3 + 1] = 0.038866f;	val_dir[11843*3 + 2] = -0.971653f;
+ 	val_dir[11844*3 + 0] = 0.260941f;	val_dir[11844*3 + 1] = 0.060217f;	val_dir[11844*3 + 2] = -0.963475f;
+ 	val_dir[11845*3 + 0] = 0.290159f;	val_dir[11845*3 + 1] = 0.082903f;	val_dir[11845*3 + 2] = -0.953381f;
+ 	val_dir[11846*3 + 0] = 0.320824f;	val_dir[11846*3 + 1] = 0.106941f;	val_dir[11846*3 + 2] = -0.941082f;
+ 	val_dir[11847*3 + 0] = 0.352865f;	val_dir[11847*3 + 1] = 0.132324f;	val_dir[11847*3 + 2] = -0.926270f;
+ 	val_dir[11848*3 + 0] = 0.386164f;	val_dir[11848*3 + 1] = 0.159009f;	val_dir[11848*3 + 2] = -0.908622f;
+ 	val_dir[11849*3 + 0] = 0.420542f;	val_dir[11849*3 + 1] = 0.186908f;	val_dir[11849*3 + 2] = -0.887812f;
+ 	val_dir[11850*3 + 0] = 0.455752f;	val_dir[11850*3 + 1] = 0.215883f;	val_dir[11850*3 + 2] = -0.863530f;
+ 	val_dir[11851*3 + 0] = 0.491473f;	val_dir[11851*3 + 1] = 0.245737f;	val_dir[11851*3 + 2] = -0.835504f;
+ 	val_dir[11852*3 + 0] = 0.527312f;	val_dir[11852*3 + 1] = 0.276211f;	val_dir[11852*3 + 2] = -0.803523f;
+ 	val_dir[11853*3 + 0] = 0.562809f;	val_dir[11853*3 + 1] = 0.306987f;	val_dir[11853*3 + 2] = -0.767467f;
+ 	val_dir[11854*3 + 0] = 0.597453f;	val_dir[11854*3 + 1] = 0.337691f;	val_dir[11854*3 + 2] = -0.727334f;
+ 	val_dir[11855*3 + 0] = 0.630706f;	val_dir[11855*3 + 1] = 0.367912f;	val_dir[11855*3 + 2] = -0.683265f;
+ 	val_dir[11856*3 + 0] = 0.662034f;	val_dir[11856*3 + 1] = 0.397220f;	val_dir[11856*3 + 2] = -0.635553f;
+ 	val_dir[11857*3 + 0] = 0.690942f;	val_dir[11857*3 + 1] = 0.425195f;	val_dir[11857*3 + 2] = -0.584643f;
+ 	val_dir[11858*3 + 0] = 0.717011f;	val_dir[11858*3 + 1] = 0.451451f;	val_dir[11858*3 + 2] = -0.531119f;
+ 	val_dir[11859*3 + 0] = 0.739923f;	val_dir[11859*3 + 1] = 0.475665f;	val_dir[11859*3 + 2] = -0.475665f;
+ 	val_dir[11860*3 + 0] = 0.759485f;	val_dir[11860*3 + 1] = 0.497594f;	val_dir[11860*3 + 2] = -0.419026f;
+ 	val_dir[11861*3 + 0] = 0.775632f;	val_dir[11861*3 + 1] = 0.517088f;	val_dir[11861*3 + 2] = -0.361961f;
+ 	val_dir[11862*3 + 0] = 0.788419f;	val_dir[11862*3 + 1] = 0.534090f;	val_dir[11862*3 + 2] = -0.305194f;
+ 	val_dir[11863*3 + 0] = 0.798007f;	val_dir[11863*3 + 1] = 0.548630f;	val_dir[11863*3 + 2] = -0.249377f;
+ 	val_dir[11864*3 + 0] = 0.804639f;	val_dir[11864*3 + 1] = 0.560809f;	val_dir[11864*3 + 2] = -0.195064f;
+ 	val_dir[11865*3 + 0] = 0.808608f;	val_dir[11865*3 + 1] = 0.570782f;	val_dir[11865*3 + 2] = -0.142695f;
+ 	val_dir[11866*3 + 0] = 0.810237f;	val_dir[11866*3 + 1] = 0.578741f;	val_dir[11866*3 + 2] = -0.092599f;
+ 	val_dir[11867*3 + 0] = 0.809858f;	val_dir[11867*3 + 1] = 0.584898f;	val_dir[11867*3 + 2] = -0.044992f;
+ 	val_dir[11868*3 + 0] = 0.807791f;	val_dir[11868*3 + 1] = 0.589469f;	val_dir[11868*3 + 2] = 0.0f;
+ 	val_dir[11869*3 + 0] = -0.599852f;	val_dir[11869*3 + 1] = -0.799803f;	val_dir[11869*3 + 2] = -0.022217f;
+ 	val_dir[11870*3 + 0] = -0.594917f;	val_dir[11870*3 + 1] = -0.800850f;	val_dir[11870*3 + 2] = -0.068644f;
+ 	val_dir[11871*3 + 0] = -0.588276f;	val_dir[11871*3 + 1] = -0.800055f;	val_dir[11871*3 + 2] = -0.117655f;
+ 	val_dir[11872*3 + 0] = -0.579703f;	val_dir[11872*3 + 1] = -0.797092f;	val_dir[11872*3 + 2] = -0.169080f;
+ 	val_dir[11873*3 + 0] = -0.568986f;	val_dir[11873*3 + 1] = -0.791633f;	val_dir[11873*3 + 2] = -0.222647f;
+ 	val_dir[11874*3 + 0] = -0.555939f;	val_dir[11874*3 + 1] = -0.783368f;	val_dir[11874*3 + 2] = -0.277969f;
+ 	val_dir[11875*3 + 0] = -0.540419f;	val_dir[11875*3 + 1] = -0.772027f;	val_dir[11875*3 + 2] = -0.334545f;
+ 	val_dir[11876*3 + 0] = -0.522352f;	val_dir[11876*3 + 1] = -0.757410f;	val_dir[11876*3 + 2] = -0.391764f;
+ 	val_dir[11877*3 + 0] = -0.501740f;	val_dir[11877*3 + 1] = -0.739407f;	val_dir[11877*3 + 2] = -0.448926f;
+ 	val_dir[11878*3 + 0] = -0.478683f;	val_dir[11878*3 + 1] = -0.718024f;	val_dir[11878*3 + 2] = -0.505276f;
+ 	val_dir[11879*3 + 0] = -0.453374f;	val_dir[11879*3 + 1] = -0.693395f;	val_dir[11879*3 + 2] = -0.560050f;
+ 	val_dir[11880*3 + 0] = -0.426099f;	val_dir[11880*3 + 1] = -0.665780f;	val_dir[11880*3 + 2] = -0.612517f;
+ 	val_dir[11881*3 + 0] = -0.397220f;	val_dir[11881*3 + 1] = -0.635553f;	val_dir[11881*3 + 2] = -0.662034f;
+ 	val_dir[11882*3 + 0] = -0.367152f;	val_dir[11882*3 + 1] = -0.603178f;	val_dir[11882*3 + 2] = -0.708079f;
+ 	val_dir[11883*3 + 0] = -0.336332f;	val_dir[11883*3 + 1] = -0.569177f;	val_dir[11883*3 + 2] = -0.750279f;
+ 	val_dir[11884*3 + 0] = -0.305194f;	val_dir[11884*3 + 1] = -0.534090f;	val_dir[11884*3 + 2] = -0.788419f;
+ 	val_dir[11885*3 + 0] = -0.274145f;	val_dir[11885*3 + 1] = -0.498445f;	val_dir[11885*3 + 2] = -0.822434f;
+ 	val_dir[11886*3 + 0] = -0.243541f;	val_dir[11886*3 + 1] = -0.462727f;	val_dir[11886*3 + 2] = -0.852392f;
+ 	val_dir[11887*3 + 0] = -0.213681f;	val_dir[11887*3 + 1] = -0.427362f;	val_dir[11887*3 + 2] = -0.878466f;
+ 	val_dir[11888*3 + 0] = -0.184801f;	val_dir[11888*3 + 1] = -0.392703f;	val_dir[11888*3 + 2] = -0.900907f;
+ 	val_dir[11889*3 + 0] = -0.157075f;	val_dir[11889*3 + 1] = -0.359030f;	val_dir[11889*3 + 2] = -0.920014f;
+ 	val_dir[11890*3 + 0] = -0.130620f;	val_dir[11890*3 + 1] = -0.326550f;	val_dir[11890*3 + 2] = -0.936111f;
+ 	val_dir[11891*3 + 0] = -0.105503f;	val_dir[11891*3 + 1] = -0.295409f;	val_dir[11891*3 + 2] = -0.949528f;
+ 	val_dir[11892*3 + 0] = -0.081752f;	val_dir[11892*3 + 1] = -0.265694f;	val_dir[11892*3 + 2] = -0.960585f;
+ 	val_dir[11893*3 + 0] = -0.059362f;	val_dir[11893*3 + 1] = -0.237449f;	val_dir[11893*3 + 2] = -0.969584f;
+ 	val_dir[11894*3 + 0] = -0.038306f;	val_dir[11894*3 + 1] = -0.210683f;	val_dir[11894*3 + 2] = -0.976804f;
+ 	val_dir[11895*3 + 0] = -0.018538f;	val_dir[11895*3 + 1] = -0.185376f;	val_dir[11895*3 + 2] = -0.982493f;
+ 	val_dir[11896*3 + 0] = 0.0f;	val_dir[11896*3 + 1] = -0.161489f;	val_dir[11896*3 + 2] = -0.986875f;
+ 	val_dir[11897*3 + 0] = 0.017990f;	val_dir[11897*3 + 1] = -0.143917f;	val_dir[11897*3 + 2] = -0.989426f;
+ 	val_dir[11898*3 + 0] = 0.036049f;	val_dir[11898*3 + 1] = -0.126172f;	val_dir[11898*3 + 2] = -0.991353f;
+ 	val_dir[11899*3 + 0] = 0.054144f;	val_dir[11899*3 + 1] = -0.108288f;	val_dir[11899*3 + 2] = -0.992644f;
+ 	val_dir[11900*3 + 0] = 0.072239f;	val_dir[11900*3 + 1] = -0.090299f;	val_dir[11900*3 + 2] = -0.993291f;
+ 	val_dir[11901*3 + 0] = 0.090299f;	val_dir[11901*3 + 1] = -0.072239f;	val_dir[11901*3 + 2] = -0.993291f;
+ 	val_dir[11902*3 + 0] = 0.108288f;	val_dir[11902*3 + 1] = -0.054144f;	val_dir[11902*3 + 2] = -0.992644f;
+ 	val_dir[11903*3 + 0] = 0.126172f;	val_dir[11903*3 + 1] = -0.036049f;	val_dir[11903*3 + 2] = -0.991353f;
+ 	val_dir[11904*3 + 0] = 0.143917f;	val_dir[11904*3 + 1] = -0.017990f;	val_dir[11904*3 + 2] = -0.989426f;
+ 	val_dir[11905*3 + 0] = 0.161489f;	val_dir[11905*3 + 1] = 0.0f;	val_dir[11905*3 + 2] = -0.986875f;
+ 	val_dir[11906*3 + 0] = 0.185376f;	val_dir[11906*3 + 1] = 0.018538f;	val_dir[11906*3 + 2] = -0.982493f;
+ 	val_dir[11907*3 + 0] = 0.210683f;	val_dir[11907*3 + 1] = 0.038306f;	val_dir[11907*3 + 2] = -0.976804f;
+ 	val_dir[11908*3 + 0] = 0.237449f;	val_dir[11908*3 + 1] = 0.059362f;	val_dir[11908*3 + 2] = -0.969584f;
+ 	val_dir[11909*3 + 0] = 0.265694f;	val_dir[11909*3 + 1] = 0.081752f;	val_dir[11909*3 + 2] = -0.960585f;
+ 	val_dir[11910*3 + 0] = 0.295409f;	val_dir[11910*3 + 1] = 0.105503f;	val_dir[11910*3 + 2] = -0.949528f;
+ 	val_dir[11911*3 + 0] = 0.326550f;	val_dir[11911*3 + 1] = 0.130620f;	val_dir[11911*3 + 2] = -0.936111f;
+ 	val_dir[11912*3 + 0] = 0.359030f;	val_dir[11912*3 + 1] = 0.157075f;	val_dir[11912*3 + 2] = -0.920014f;
+ 	val_dir[11913*3 + 0] = 0.392703f;	val_dir[11913*3 + 1] = 0.184801f;	val_dir[11913*3 + 2] = -0.900907f;
+ 	val_dir[11914*3 + 0] = 0.427362f;	val_dir[11914*3 + 1] = 0.213681f;	val_dir[11914*3 + 2] = -0.878466f;
+ 	val_dir[11915*3 + 0] = 0.462727f;	val_dir[11915*3 + 1] = 0.243541f;	val_dir[11915*3 + 2] = -0.852392f;
+ 	val_dir[11916*3 + 0] = 0.498445f;	val_dir[11916*3 + 1] = 0.274145f;	val_dir[11916*3 + 2] = -0.822434f;
+ 	val_dir[11917*3 + 0] = 0.534090f;	val_dir[11917*3 + 1] = 0.305194f;	val_dir[11917*3 + 2] = -0.788419f;
+ 	val_dir[11918*3 + 0] = 0.569177f;	val_dir[11918*3 + 1] = 0.336332f;	val_dir[11918*3 + 2] = -0.750279f;
+ 	val_dir[11919*3 + 0] = 0.603178f;	val_dir[11919*3 + 1] = 0.367152f;	val_dir[11919*3 + 2] = -0.708079f;
+ 	val_dir[11920*3 + 0] = 0.635553f;	val_dir[11920*3 + 1] = 0.397220f;	val_dir[11920*3 + 2] = -0.662034f;
+ 	val_dir[11921*3 + 0] = 0.665780f;	val_dir[11921*3 + 1] = 0.426099f;	val_dir[11921*3 + 2] = -0.612517f;
+ 	val_dir[11922*3 + 0] = 0.693395f;	val_dir[11922*3 + 1] = 0.453374f;	val_dir[11922*3 + 2] = -0.560050f;
+ 	val_dir[11923*3 + 0] = 0.718024f;	val_dir[11923*3 + 1] = 0.478683f;	val_dir[11923*3 + 2] = -0.505276f;
+ 	val_dir[11924*3 + 0] = 0.739407f;	val_dir[11924*3 + 1] = 0.501740f;	val_dir[11924*3 + 2] = -0.448926f;
+ 	val_dir[11925*3 + 0] = 0.757410f;	val_dir[11925*3 + 1] = 0.522352f;	val_dir[11925*3 + 2] = -0.391764f;
+ 	val_dir[11926*3 + 0] = 0.772027f;	val_dir[11926*3 + 1] = 0.540419f;	val_dir[11926*3 + 2] = -0.334545f;
+ 	val_dir[11927*3 + 0] = 0.783368f;	val_dir[11927*3 + 1] = 0.555939f;	val_dir[11927*3 + 2] = -0.277969f;
+ 	val_dir[11928*3 + 0] = 0.791633f;	val_dir[11928*3 + 1] = 0.568986f;	val_dir[11928*3 + 2] = -0.222647f;
+ 	val_dir[11929*3 + 0] = 0.797092f;	val_dir[11929*3 + 1] = 0.579703f;	val_dir[11929*3 + 2] = -0.169080f;
+ 	val_dir[11930*3 + 0] = 0.800055f;	val_dir[11930*3 + 1] = 0.588276f;	val_dir[11930*3 + 2] = -0.117655f;
+ 	val_dir[11931*3 + 0] = 0.800850f;	val_dir[11931*3 + 1] = 0.594917f;	val_dir[11931*3 + 2] = -0.068644f;
+ 	val_dir[11932*3 + 0] = 0.799803f;	val_dir[11932*3 + 1] = 0.599852f;	val_dir[11932*3 + 2] = -0.022217f;
+ 	val_dir[11933*3 + 0] = -0.613941f;	val_dir[11933*3 + 1] = -0.789352f;	val_dir[11933*3 + 2] = 0.0f;
+ 	val_dir[11934*3 + 0] = -0.610179f;	val_dir[11934*3 + 1] = -0.790973f;	val_dir[11934*3 + 2] = -0.045198f;
+ 	val_dir[11935*3 + 0] = -0.604815f;	val_dir[11935*3 + 1] = -0.790912f;	val_dir[11935*3 + 2] = -0.093048f;
+ 	val_dir[11936*3 + 0] = -0.597614f;	val_dir[11936*3 + 1] = -0.788851f;	val_dir[11936*3 + 2] = -0.143427f;
+ 	val_dir[11937*3 + 0] = -0.588348f;	val_dir[11937*3 + 1] = -0.784465f;	val_dir[11937*3 + 2] = -0.196116f;
+ 	val_dir[11938*3 + 0] = -0.576805f;	val_dir[11938*3 + 1] = -0.777433f;	val_dir[11938*3 + 2] = -0.250785f;
+ 	val_dir[11939*3 + 0] = -0.562809f;	val_dir[11939*3 + 1] = -0.767467f;	val_dir[11939*3 + 2] = -0.306987f;
+ 	val_dir[11940*3 + 0] = -0.546238f;	val_dir[11940*3 + 1] = -0.754329f;	val_dir[11940*3 + 2] = -0.364159f;
+ 	val_dir[11941*3 + 0] = -0.527046f;	val_dir[11941*3 + 1] = -0.737865f;	val_dir[11941*3 + 2] = -0.421637f;
+ 	val_dir[11942*3 + 0] = -0.505276f;	val_dir[11942*3 + 1] = -0.718024f;	val_dir[11942*3 + 2] = -0.478683f;
+ 	val_dir[11943*3 + 0] = -0.481070f;	val_dir[11943*3 + 1] = -0.694879f;	val_dir[11943*3 + 2] = -0.534522f;
+ 	val_dir[11944*3 + 0] = -0.454669f;	val_dir[11944*3 + 1] = -0.668631f;	val_dir[11944*3 + 2] = -0.588395f;
+ 	val_dir[11945*3 + 0] = -0.426401f;	val_dir[11945*3 + 1] = -0.639602f;	val_dir[11945*3 + 2] = -0.639602f;
+ 	val_dir[11946*3 + 0] = -0.396664f;	val_dir[11946*3 + 1] = -0.608219f;	val_dir[11946*3 + 2] = -0.687552f;
+ 	val_dir[11947*3 + 0] = -0.365896f;	val_dir[11947*3 + 1] = -0.574979f;	val_dir[11947*3 + 2] = -0.731792f;
+ 	val_dir[11948*3 + 0] = -0.334545f;	val_dir[11948*3 + 1] = -0.540419f;	val_dir[11948*3 + 2] = -0.772027f;
+ 	val_dir[11949*3 + 0] = -0.303046f;	val_dir[11949*3 + 1] = -0.505076f;	val_dir[11949*3 + 2] = -0.808122f;
+ 	val_dir[11950*3 + 0] = -0.271791f;	val_dir[11950*3 + 1] = -0.469458f;	val_dir[11950*3 + 2] = -0.840083f;
+ 	val_dir[11951*3 + 0] = -0.241121f;	val_dir[11951*3 + 1] = -0.434019f;	val_dir[11951*3 + 2] = -0.868037f;
+ 	val_dir[11952*3 + 0] = -0.211312f;	val_dir[11952*3 + 1] = -0.399145f;	val_dir[11952*3 + 2] = -0.892206f;
+ 	val_dir[11953*3 + 0] = -0.182574f;	val_dir[11953*3 + 1] = -0.365148f;	val_dir[11953*3 + 2] = -0.912871f;
+ 	val_dir[11954*3 + 0] = -0.155059f;	val_dir[11954*3 + 1] = -0.332269f;	val_dir[11954*3 + 2] = -0.930352f;
+ 	val_dir[11955*3 + 0] = -0.128861f;	val_dir[11955*3 + 1] = -0.300676f;	val_dir[11955*3 + 2] = -0.944981f;
+ 	val_dir[11956*3 + 0] = -0.104031f;	val_dir[11956*3 + 1] = -0.270481f;	val_dir[11956*3 + 2] = -0.957088f;
+ 	val_dir[11957*3 + 0] = -0.080582f;	val_dir[11957*3 + 1] = -0.241747f;	val_dir[11957*3 + 2] = -0.966988f;
+ 	val_dir[11958*3 + 0] = -0.058498f;	val_dir[11958*3 + 1] = -0.214494f;	val_dir[11958*3 + 2] = -0.974972f;
+ 	val_dir[11959*3 + 0] = -0.037743f;	val_dir[11959*3 + 1] = -0.188713f;	val_dir[11959*3 + 2] = -0.981307f;
+ 	val_dir[11960*3 + 0] = -0.018264f;	val_dir[11960*3 + 1] = -0.164372f;	val_dir[11960*3 + 2] = -0.986229f;
+ 	val_dir[11961*3 + 0] = 0.0f;	val_dir[11961*3 + 1] = -0.141421f;	val_dir[11961*3 + 2] = -0.989949f;
+ 	val_dir[11962*3 + 0] = 0.017716f;	val_dir[11962*3 + 1] = -0.124015f;	val_dir[11962*3 + 2] = -0.992122f;
+ 	val_dir[11963*3 + 0] = 0.035489f;	val_dir[11963*3 + 1] = -0.106466f;	val_dir[11963*3 + 2] = -0.993683f;
+ 	val_dir[11964*3 + 0] = 0.053283f;	val_dir[11964*3 + 1] = -0.088806f;	val_dir[11964*3 + 2] = -0.994623f;
+ 	val_dir[11965*3 + 0] = 0.071067f;	val_dir[11965*3 + 1] = -0.071067f;	val_dir[11965*3 + 2] = -0.994937f;
+ 	val_dir[11966*3 + 0] = 0.088806f;	val_dir[11966*3 + 1] = -0.053283f;	val_dir[11966*3 + 2] = -0.994623f;
+ 	val_dir[11967*3 + 0] = 0.106466f;	val_dir[11967*3 + 1] = -0.035489f;	val_dir[11967*3 + 2] = -0.993683f;
+ 	val_dir[11968*3 + 0] = 0.124015f;	val_dir[11968*3 + 1] = -0.017716f;	val_dir[11968*3 + 2] = -0.992122f;
+ 	val_dir[11969*3 + 0] = 0.141421f;	val_dir[11969*3 + 1] = 0.0f;	val_dir[11969*3 + 2] = -0.989949f;
+ 	val_dir[11970*3 + 0] = 0.164372f;	val_dir[11970*3 + 1] = 0.018264f;	val_dir[11970*3 + 2] = -0.986229f;
+ 	val_dir[11971*3 + 0] = 0.188713f;	val_dir[11971*3 + 1] = 0.037743f;	val_dir[11971*3 + 2] = -0.981307f;
+ 	val_dir[11972*3 + 0] = 0.214494f;	val_dir[11972*3 + 1] = 0.058498f;	val_dir[11972*3 + 2] = -0.974972f;
+ 	val_dir[11973*3 + 0] = 0.241747f;	val_dir[11973*3 + 1] = 0.080582f;	val_dir[11973*3 + 2] = -0.966988f;
+ 	val_dir[11974*3 + 0] = 0.270481f;	val_dir[11974*3 + 1] = 0.104031f;	val_dir[11974*3 + 2] = -0.957088f;
+ 	val_dir[11975*3 + 0] = 0.300676f;	val_dir[11975*3 + 1] = 0.128861f;	val_dir[11975*3 + 2] = -0.944981f;
+ 	val_dir[11976*3 + 0] = 0.332269f;	val_dir[11976*3 + 1] = 0.155059f;	val_dir[11976*3 + 2] = -0.930352f;
+ 	val_dir[11977*3 + 0] = 0.365148f;	val_dir[11977*3 + 1] = 0.182574f;	val_dir[11977*3 + 2] = -0.912871f;
+ 	val_dir[11978*3 + 0] = 0.399145f;	val_dir[11978*3 + 1] = 0.211312f;	val_dir[11978*3 + 2] = -0.892206f;
+ 	val_dir[11979*3 + 0] = 0.434019f;	val_dir[11979*3 + 1] = 0.241121f;	val_dir[11979*3 + 2] = -0.868037f;
+ 	val_dir[11980*3 + 0] = 0.469458f;	val_dir[11980*3 + 1] = 0.271791f;	val_dir[11980*3 + 2] = -0.840083f;
+ 	val_dir[11981*3 + 0] = 0.505076f;	val_dir[11981*3 + 1] = 0.303046f;	val_dir[11981*3 + 2] = -0.808122f;
+ 	val_dir[11982*3 + 0] = 0.540419f;	val_dir[11982*3 + 1] = 0.334545f;	val_dir[11982*3 + 2] = -0.772027f;
+ 	val_dir[11983*3 + 0] = 0.574979f;	val_dir[11983*3 + 1] = 0.365896f;	val_dir[11983*3 + 2] = -0.731792f;
+ 	val_dir[11984*3 + 0] = 0.608219f;	val_dir[11984*3 + 1] = 0.396664f;	val_dir[11984*3 + 2] = -0.687552f;
+ 	val_dir[11985*3 + 0] = 0.639602f;	val_dir[11985*3 + 1] = 0.426401f;	val_dir[11985*3 + 2] = -0.639602f;
+ 	val_dir[11986*3 + 0] = 0.668631f;	val_dir[11986*3 + 1] = 0.454669f;	val_dir[11986*3 + 2] = -0.588395f;
+ 	val_dir[11987*3 + 0] = 0.694879f;	val_dir[11987*3 + 1] = 0.481070f;	val_dir[11987*3 + 2] = -0.534522f;
+ 	val_dir[11988*3 + 0] = 0.718024f;	val_dir[11988*3 + 1] = 0.505276f;	val_dir[11988*3 + 2] = -0.478683f;
+ 	val_dir[11989*3 + 0] = 0.737865f;	val_dir[11989*3 + 1] = 0.527046f;	val_dir[11989*3 + 2] = -0.421637f;
+ 	val_dir[11990*3 + 0] = 0.754329f;	val_dir[11990*3 + 1] = 0.546238f;	val_dir[11990*3 + 2] = -0.364159f;
+ 	val_dir[11991*3 + 0] = 0.767467f;	val_dir[11991*3 + 1] = 0.562809f;	val_dir[11991*3 + 2] = -0.306987f;
+ 	val_dir[11992*3 + 0] = 0.777433f;	val_dir[11992*3 + 1] = 0.576805f;	val_dir[11992*3 + 2] = -0.250785f;
+ 	val_dir[11993*3 + 0] = 0.784465f;	val_dir[11993*3 + 1] = 0.588348f;	val_dir[11993*3 + 2] = -0.196116f;
+ 	val_dir[11994*3 + 0] = 0.788851f;	val_dir[11994*3 + 1] = 0.597614f;	val_dir[11994*3 + 2] = -0.143427f;
+ 	val_dir[11995*3 + 0] = 0.790912f;	val_dir[11995*3 + 1] = 0.604815f;	val_dir[11995*3 + 2] = -0.093048f;
+ 	val_dir[11996*3 + 0] = 0.790973f;	val_dir[11996*3 + 1] = 0.610179f;	val_dir[11996*3 + 2] = -0.045198f;
+ 	val_dir[11997*3 + 0] = 0.789352f;	val_dir[11997*3 + 1] = 0.613941f;	val_dir[11997*3 + 2] = 0.0f;
+ 	val_dir[11998*3 + 0] = -0.624540f;	val_dir[11998*3 + 1] = -0.780675f;	val_dir[11998*3 + 2] = -0.022305f;
+ 	val_dir[11999*3 + 0] = -0.620403f;	val_dir[11999*3 + 1] = -0.781248f;	val_dir[11999*3 + 2] = -0.068934f;
+ 	val_dir[12000*3 + 0] = -0.614535f;	val_dir[12000*3 + 1] = -0.779987f;	val_dir[12000*3 + 2] = -0.118180f;
+ 	val_dir[12001*3 + 0] = -0.606696f;	val_dir[12001*3 + 1] = -0.776571f;	val_dir[12001*3 + 2] = -0.169875f;
+ 	val_dir[12002*3 + 0] = -0.596653f;	val_dir[12002*3 + 1] = -0.770677f;	val_dir[12002*3 + 2] = -0.223745f;
+ 	val_dir[12003*3 + 0] = -0.584201f;	val_dir[12003*3 + 1] = -0.762001f;	val_dir[12003*3 + 2] = -0.27940f;
+ 	val_dir[12004*3 + 0] = -0.569177f;	val_dir[12004*3 + 1] = -0.750279f;	val_dir[12004*3 + 2] = -0.336332f;
+ 	val_dir[12005*3 + 0] = -0.551487f;	val_dir[12005*3 + 1] = -0.735316f;	val_dir[12005*3 + 2] = -0.393919f;
+ 	val_dir[12006*3 + 0] = -0.531119f;	val_dir[12006*3 + 1] = -0.717011f;	val_dir[12006*3 + 2] = -0.451451f;
+ 	val_dir[12007*3 + 0] = -0.508159f;	val_dir[12007*3 + 1] = -0.695376f;	val_dir[12007*3 + 2] = -0.508159f;
+ 	val_dir[12008*3 + 0] = -0.482798f;	val_dir[12008*3 + 1] = -0.670552f;	val_dir[12008*3 + 2] = -0.563264f;
+ 	val_dir[12009*3 + 0] = -0.455321f;	val_dir[12009*3 + 1] = -0.642806f;	val_dir[12009*3 + 2] = -0.616022f;
+ 	val_dir[12010*3 + 0] = -0.426099f;	val_dir[12010*3 + 1] = -0.612517f;	val_dir[12010*3 + 2] = -0.665780f;
+ 	val_dir[12011*3 + 0] = -0.395559f;	val_dir[12011*3 + 1] = -0.580154f;	val_dir[12011*3 + 2] = -0.712007f;
+ 	val_dir[12012*3 + 0] = -0.364159f;	val_dir[12012*3 + 1] = -0.546238f;	val_dir[12012*3 + 2] = -0.754329f;
+ 	val_dir[12013*3 + 0] = -0.332352f;	val_dir[12013*3 + 1] = -0.511310f;	val_dir[12013*3 + 2] = -0.792530f;
+ 	val_dir[12014*3 + 0] = -0.300564f;	val_dir[12014*3 + 1] = -0.475893f;	val_dir[12014*3 + 2] = -0.826551f;
+ 	val_dir[12015*3 + 0] = -0.269175f;	val_dir[12015*3 + 1] = -0.440468f;	val_dir[12015*3 + 2] = -0.856465f;
+ 	val_dir[12016*3 + 0] = -0.238501f;	val_dir[12016*3 + 1] = -0.405452f;	val_dir[12016*3 + 2] = -0.882454f;
+ 	val_dir[12017*3 + 0] = -0.208795f;	val_dir[12017*3 + 1] = -0.371191f;	val_dir[12017*3 + 2] = -0.904777f;
+ 	val_dir[12018*3 + 0] = -0.180242f;	val_dir[12018*3 + 1] = -0.337954f;	val_dir[12018*3 + 2] = -0.923742f;
+ 	val_dir[12019*3 + 0] = -0.152971f;	val_dir[12019*3 + 1] = -0.305942f;	val_dir[12019*3 + 2] = -0.939680f;
+ 	val_dir[12020*3 + 0] = -0.127057f;	val_dir[12020*3 + 1] = -0.275290f;	val_dir[12020*3 + 2] = -0.952928f;
+ 	val_dir[12021*3 + 0] = -0.102533f;	val_dir[12021*3 + 1] = -0.246079f;	val_dir[12021*3 + 2] = -0.963811f;
+ 	val_dir[12022*3 + 0] = -0.079399f;	val_dir[12022*3 + 1] = -0.218347f;	val_dir[12022*3 + 2] = -0.972636f;
+ 	val_dir[12023*3 + 0] = -0.057628f;	val_dir[12023*3 + 1] = -0.192095f;	val_dir[12023*3 + 2] = -0.979683f;
+ 	val_dir[12024*3 + 0] = -0.037178f;	val_dir[12024*3 + 1] = -0.167299f;	val_dir[12024*3 + 2] = -0.985205f;
+ 	val_dir[12025*3 + 0] = -0.017990f;	val_dir[12025*3 + 1] = -0.143917f;	val_dir[12025*3 + 2] = -0.989426f;
+ 	val_dir[12026*3 + 0] = 0.0f;	val_dir[12026*3 + 1] = -0.121891f;	val_dir[12026*3 + 2] = -0.992543f;
+ 	val_dir[12027*3 + 0] = 0.017445f;	val_dir[12027*3 + 1] = -0.104669f;	val_dir[12027*3 + 2] = -0.994354f;
+ 	val_dir[12028*3 + 0] = 0.034932f;	val_dir[12028*3 + 1] = -0.087330f;	val_dir[12028*3 + 2] = -0.995567f;
+ 	val_dir[12029*3 + 0] = 0.052430f;	val_dir[12029*3 + 1] = -0.069907f;	val_dir[12029*3 + 2] = -0.996175f;
+ 	val_dir[12030*3 + 0] = 0.069907f;	val_dir[12030*3 + 1] = -0.052430f;	val_dir[12030*3 + 2] = -0.996175f;
+ 	val_dir[12031*3 + 0] = 0.087330f;	val_dir[12031*3 + 1] = -0.034932f;	val_dir[12031*3 + 2] = -0.995567f;
+ 	val_dir[12032*3 + 0] = 0.104669f;	val_dir[12032*3 + 1] = -0.017445f;	val_dir[12032*3 + 2] = -0.994354f;
+ 	val_dir[12033*3 + 0] = 0.121891f;	val_dir[12033*3 + 1] = 0.0f;	val_dir[12033*3 + 2] = -0.992543f;
+ 	val_dir[12034*3 + 0] = 0.143917f;	val_dir[12034*3 + 1] = 0.017990f;	val_dir[12034*3 + 2] = -0.989426f;
+ 	val_dir[12035*3 + 0] = 0.167299f;	val_dir[12035*3 + 1] = 0.037178f;	val_dir[12035*3 + 2] = -0.985205f;
+ 	val_dir[12036*3 + 0] = 0.192095f;	val_dir[12036*3 + 1] = 0.057628f;	val_dir[12036*3 + 2] = -0.979683f;
+ 	val_dir[12037*3 + 0] = 0.218347f;	val_dir[12037*3 + 1] = 0.079399f;	val_dir[12037*3 + 2] = -0.972636f;
+ 	val_dir[12038*3 + 0] = 0.246079f;	val_dir[12038*3 + 1] = 0.102533f;	val_dir[12038*3 + 2] = -0.963811f;
+ 	val_dir[12039*3 + 0] = 0.275290f;	val_dir[12039*3 + 1] = 0.127057f;	val_dir[12039*3 + 2] = -0.952928f;
+ 	val_dir[12040*3 + 0] = 0.305942f;	val_dir[12040*3 + 1] = 0.152971f;	val_dir[12040*3 + 2] = -0.939680f;
+ 	val_dir[12041*3 + 0] = 0.337954f;	val_dir[12041*3 + 1] = 0.180242f;	val_dir[12041*3 + 2] = -0.923742f;
+ 	val_dir[12042*3 + 0] = 0.371191f;	val_dir[12042*3 + 1] = 0.208795f;	val_dir[12042*3 + 2] = -0.904777f;
+ 	val_dir[12043*3 + 0] = 0.405452f;	val_dir[12043*3 + 1] = 0.238501f;	val_dir[12043*3 + 2] = -0.882454f;
+ 	val_dir[12044*3 + 0] = 0.440468f;	val_dir[12044*3 + 1] = 0.269175f;	val_dir[12044*3 + 2] = -0.856465f;
+ 	val_dir[12045*3 + 0] = 0.475893f;	val_dir[12045*3 + 1] = 0.300564f;	val_dir[12045*3 + 2] = -0.826551f;
+ 	val_dir[12046*3 + 0] = 0.511310f;	val_dir[12046*3 + 1] = 0.332352f;	val_dir[12046*3 + 2] = -0.792530f;
+ 	val_dir[12047*3 + 0] = 0.546238f;	val_dir[12047*3 + 1] = 0.364159f;	val_dir[12047*3 + 2] = -0.754329f;
+ 	val_dir[12048*3 + 0] = 0.580154f;	val_dir[12048*3 + 1] = 0.395559f;	val_dir[12048*3 + 2] = -0.712007f;
+ 	val_dir[12049*3 + 0] = 0.612517f;	val_dir[12049*3 + 1] = 0.426099f;	val_dir[12049*3 + 2] = -0.665780f;
+ 	val_dir[12050*3 + 0] = 0.642806f;	val_dir[12050*3 + 1] = 0.455321f;	val_dir[12050*3 + 2] = -0.616022f;
+ 	val_dir[12051*3 + 0] = 0.670552f;	val_dir[12051*3 + 1] = 0.482798f;	val_dir[12051*3 + 2] = -0.563264f;
+ 	val_dir[12052*3 + 0] = 0.695376f;	val_dir[12052*3 + 1] = 0.508159f;	val_dir[12052*3 + 2] = -0.508159f;
+ 	val_dir[12053*3 + 0] = 0.717011f;	val_dir[12053*3 + 1] = 0.531119f;	val_dir[12053*3 + 2] = -0.451451f;
+ 	val_dir[12054*3 + 0] = 0.735316f;	val_dir[12054*3 + 1] = 0.551487f;	val_dir[12054*3 + 2] = -0.393919f;
+ 	val_dir[12055*3 + 0] = 0.750279f;	val_dir[12055*3 + 1] = 0.569177f;	val_dir[12055*3 + 2] = -0.336332f;
+ 	val_dir[12056*3 + 0] = 0.762001f;	val_dir[12056*3 + 1] = 0.584201f;	val_dir[12056*3 + 2] = -0.27940f;
+ 	val_dir[12057*3 + 0] = 0.770677f;	val_dir[12057*3 + 1] = 0.596653f;	val_dir[12057*3 + 2] = -0.223745f;
+ 	val_dir[12058*3 + 0] = 0.776571f;	val_dir[12058*3 + 1] = 0.606696f;	val_dir[12058*3 + 2] = -0.169875f;
+ 	val_dir[12059*3 + 0] = 0.779987f;	val_dir[12059*3 + 1] = 0.614535f;	val_dir[12059*3 + 2] = -0.118180f;
+ 	val_dir[12060*3 + 0] = 0.781248f;	val_dir[12060*3 + 1] = 0.620403f;	val_dir[12060*3 + 2] = -0.068934f;
+ 	val_dir[12061*3 + 0] = 0.780675f;	val_dir[12061*3 + 1] = 0.624540f;	val_dir[12061*3 + 2] = -0.022305f;
+ 	val_dir[12062*3 + 0] = -0.638018f;	val_dir[12062*3 + 1] = -0.770022f;	val_dir[12062*3 + 2] = 0.0f;
+ 	val_dir[12063*3 + 0] = -0.635053f;	val_dir[12063*3 + 1] = -0.771136f;	val_dir[12063*3 + 2] = -0.045361f;
+ 	val_dir[12064*3 + 0] = -0.630470f;	val_dir[12064*3 + 1] = -0.770574f;	val_dir[12064*3 + 2] = -0.093403f;
+ 	val_dir[12065*3 + 0] = -0.624020f;	val_dir[12065*3 + 1] = -0.768025f;	val_dir[12065*3 + 2] = -0.144005f;
+ 	val_dir[12066*3 + 0] = -0.615457f;	val_dir[12066*3 + 1] = -0.763167f;	val_dir[12066*3 + 2] = -0.196946f;
+ 	val_dir[12067*3 + 0] = -0.604551f;	val_dir[12067*3 + 1] = -0.755689f;	val_dir[12067*3 + 2] = -0.251896f;
+ 	val_dir[12068*3 + 0] = -0.591105f;	val_dir[12068*3 + 1] = -0.745307f;	val_dir[12068*3 + 2] = -0.308403f;
+ 	val_dir[12069*3 + 0] = -0.574979f;	val_dir[12069*3 + 1] = -0.731792f;	val_dir[12069*3 + 2] = -0.365896f;
+ 	val_dir[12070*3 + 0] = -0.556108f;	val_dir[12070*3 + 1] = -0.714997f;	val_dir[12070*3 + 2] = -0.423702f;
+ 	val_dir[12071*3 + 0] = -0.534522f;	val_dir[12071*3 + 1] = -0.694879f;	val_dir[12071*3 + 2] = -0.481070f;
+ 	val_dir[12072*3 + 0] = -0.510355f;	val_dir[12072*3 + 1] = -0.671519f;	val_dir[12072*3 + 2] = -0.537215f;
+ 	val_dir[12073*3 + 0] = -0.483843f;	val_dir[12073*3 + 1] = -0.645124f;	val_dir[12073*3 + 2] = -0.591364f;
+ 	val_dir[12074*3 + 0] = -0.455321f;	val_dir[12074*3 + 1] = -0.616022f;	val_dir[12074*3 + 2] = -0.642806f;
+ 	val_dir[12075*3 + 0] = -0.425195f;	val_dir[12075*3 + 1] = -0.584643f;	val_dir[12075*3 + 2] = -0.690942f;
+ 	val_dir[12076*3 + 0] = -0.393919f;	val_dir[12076*3 + 1] = -0.551487f;	val_dir[12076*3 + 2] = -0.735316f;
+ 	val_dir[12077*3 + 0] = -0.361961f;	val_dir[12077*3 + 1] = -0.517088f;	val_dir[12077*3 + 2] = -0.775632f;
+ 	val_dir[12078*3 + 0] = -0.329775f;	val_dir[12078*3 + 1] = -0.481979f;	val_dir[12078*3 + 2] = -0.811754f;
+ 	val_dir[12079*3 + 0] = -0.297775f;	val_dir[12079*3 + 1] = -0.446662f;	val_dir[12079*3 + 2] = -0.843696f;
+ 	val_dir[12080*3 + 0] = -0.266320f;	val_dir[12080*3 + 1] = -0.411585f;	val_dir[12080*3 + 2] = -0.871592f;
+ 	val_dir[12081*3 + 0] = -0.235702f;	val_dir[12081*3 + 1] = -0.377124f;	val_dir[12081*3 + 2] = -0.895669f;
+ 	val_dir[12082*3 + 0] = -0.206149f;	val_dir[12082*3 + 1] = -0.343582f;	val_dir[12082*3 + 2] = -0.916217f;
+ 	val_dir[12083*3 + 0] = -0.177822f;	val_dir[12083*3 + 1] = -0.311188f;	val_dir[12083*3 + 2] = -0.933564f;
+ 	val_dir[12084*3 + 0] = -0.150826f;	val_dir[12084*3 + 1] = -0.280105f;	val_dir[12084*3 + 2] = -0.948047f;
+ 	val_dir[12085*3 + 0] = -0.125218f;	val_dir[12085*3 + 1] = -0.250435f;	val_dir[12085*3 + 2] = -0.960001f;
+ 	val_dir[12086*3 + 0] = -0.101015f;	val_dir[12086*3 + 1] = -0.222234f;	val_dir[12086*3 + 2] = -0.969746f;
+ 	val_dir[12087*3 + 0] = -0.078206f;	val_dir[12087*3 + 1] = -0.195515f;	val_dir[12087*3 + 2] = -0.977577f;
+ 	val_dir[12088*3 + 0] = -0.056756f;	val_dir[12088*3 + 1] = -0.170267f;	val_dir[12088*3 + 2] = -0.983762f;
+ 	val_dir[12089*3 + 0] = -0.036613f;	val_dir[12089*3 + 1] = -0.146450f;	val_dir[12089*3 + 2] = -0.988540f;
+ 	val_dir[12090*3 + 0] = -0.017716f;	val_dir[12090*3 + 1] = -0.124015f;	val_dir[12090*3 + 2] = -0.992122f;
+ 	val_dir[12091*3 + 0] = 0.0f;	val_dir[12091*3 + 1] = -0.102899f;	val_dir[12091*3 + 2] = -0.994692f;
+ 	val_dir[12092*3 + 0] = 0.017175f;	val_dir[12092*3 + 1] = -0.085876f;	val_dir[12092*3 + 2] = -0.996158f;
+ 	val_dir[12093*3 + 0] = 0.034381f;	val_dir[12093*3 + 1] = -0.068761f;	val_dir[12093*3 + 2] = -0.997041f;
+ 	val_dir[12094*3 + 0] = 0.051586f;	val_dir[12094*3 + 1] = -0.051586f;	val_dir[12094*3 + 2] = -0.997335f;
+ 	val_dir[12095*3 + 0] = 0.068761f;	val_dir[12095*3 + 1] = -0.034381f;	val_dir[12095*3 + 2] = -0.997041f;
+ 	val_dir[12096*3 + 0] = 0.085876f;	val_dir[12096*3 + 1] = -0.017175f;	val_dir[12096*3 + 2] = -0.996158f;
+ 	val_dir[12097*3 + 0] = 0.102899f;	val_dir[12097*3 + 1] = 0.0f;	val_dir[12097*3 + 2] = -0.994692f;
+ 	val_dir[12098*3 + 0] = 0.124015f;	val_dir[12098*3 + 1] = 0.017716f;	val_dir[12098*3 + 2] = -0.992122f;
+ 	val_dir[12099*3 + 0] = 0.146450f;	val_dir[12099*3 + 1] = 0.036613f;	val_dir[12099*3 + 2] = -0.988540f;
+ 	val_dir[12100*3 + 0] = 0.170267f;	val_dir[12100*3 + 1] = 0.056756f;	val_dir[12100*3 + 2] = -0.983762f;
+ 	val_dir[12101*3 + 0] = 0.195515f;	val_dir[12101*3 + 1] = 0.078206f;	val_dir[12101*3 + 2] = -0.977577f;
+ 	val_dir[12102*3 + 0] = 0.222234f;	val_dir[12102*3 + 1] = 0.101015f;	val_dir[12102*3 + 2] = -0.969746f;
+ 	val_dir[12103*3 + 0] = 0.250435f;	val_dir[12103*3 + 1] = 0.125218f;	val_dir[12103*3 + 2] = -0.960001f;
+ 	val_dir[12104*3 + 0] = 0.280105f;	val_dir[12104*3 + 1] = 0.150826f;	val_dir[12104*3 + 2] = -0.948047f;
+ 	val_dir[12105*3 + 0] = 0.311188f;	val_dir[12105*3 + 1] = 0.177822f;	val_dir[12105*3 + 2] = -0.933564f;
+ 	val_dir[12106*3 + 0] = 0.343582f;	val_dir[12106*3 + 1] = 0.206149f;	val_dir[12106*3 + 2] = -0.916217f;
+ 	val_dir[12107*3 + 0] = 0.377124f;	val_dir[12107*3 + 1] = 0.235702f;	val_dir[12107*3 + 2] = -0.895669f;
+ 	val_dir[12108*3 + 0] = 0.411585f;	val_dir[12108*3 + 1] = 0.266320f;	val_dir[12108*3 + 2] = -0.871592f;
+ 	val_dir[12109*3 + 0] = 0.446662f;	val_dir[12109*3 + 1] = 0.297775f;	val_dir[12109*3 + 2] = -0.843696f;
+ 	val_dir[12110*3 + 0] = 0.481979f;	val_dir[12110*3 + 1] = 0.329775f;	val_dir[12110*3 + 2] = -0.811754f;
+ 	val_dir[12111*3 + 0] = 0.517088f;	val_dir[12111*3 + 1] = 0.361961f;	val_dir[12111*3 + 2] = -0.775632f;
+ 	val_dir[12112*3 + 0] = 0.551487f;	val_dir[12112*3 + 1] = 0.393919f;	val_dir[12112*3 + 2] = -0.735316f;
+ 	val_dir[12113*3 + 0] = 0.584643f;	val_dir[12113*3 + 1] = 0.425195f;	val_dir[12113*3 + 2] = -0.690942f;
+ 	val_dir[12114*3 + 0] = 0.616022f;	val_dir[12114*3 + 1] = 0.455321f;	val_dir[12114*3 + 2] = -0.642806f;
+ 	val_dir[12115*3 + 0] = 0.645124f;	val_dir[12115*3 + 1] = 0.483843f;	val_dir[12115*3 + 2] = -0.591364f;
+ 	val_dir[12116*3 + 0] = 0.671519f;	val_dir[12116*3 + 1] = 0.510355f;	val_dir[12116*3 + 2] = -0.537215f;
+ 	val_dir[12117*3 + 0] = 0.694879f;	val_dir[12117*3 + 1] = 0.534522f;	val_dir[12117*3 + 2] = -0.481070f;
+ 	val_dir[12118*3 + 0] = 0.714997f;	val_dir[12118*3 + 1] = 0.556108f;	val_dir[12118*3 + 2] = -0.423702f;
+ 	val_dir[12119*3 + 0] = 0.731792f;	val_dir[12119*3 + 1] = 0.574979f;	val_dir[12119*3 + 2] = -0.365896f;
+ 	val_dir[12120*3 + 0] = 0.745307f;	val_dir[12120*3 + 1] = 0.591105f;	val_dir[12120*3 + 2] = -0.308403f;
+ 	val_dir[12121*3 + 0] = 0.755689f;	val_dir[12121*3 + 1] = 0.604551f;	val_dir[12121*3 + 2] = -0.251896f;
+ 	val_dir[12122*3 + 0] = 0.763167f;	val_dir[12122*3 + 1] = 0.615457f;	val_dir[12122*3 + 2] = -0.196946f;
+ 	val_dir[12123*3 + 0] = 0.768025f;	val_dir[12123*3 + 1] = 0.624020f;	val_dir[12123*3 + 2] = -0.144005f;
+ 	val_dir[12124*3 + 0] = 0.770574f;	val_dir[12124*3 + 1] = 0.630470f;	val_dir[12124*3 + 2] = -0.093403f;
+ 	val_dir[12125*3 + 0] = 0.771136f;	val_dir[12125*3 + 1] = 0.635053f;	val_dir[12125*3 + 2] = -0.045361f;
+ 	val_dir[12126*3 + 0] = 0.770022f;	val_dir[12126*3 + 1] = 0.638018f;	val_dir[12126*3 + 2] = 0.0f;
+ 	val_dir[12127*3 + 0] = -0.648784f;	val_dir[12127*3 + 1] = -0.760644f;	val_dir[12127*3 + 2] = -0.022372f;
+ 	val_dir[12128*3 + 0] = -0.645429f;	val_dir[12128*3 + 1] = -0.760684f;	val_dir[12128*3 + 2] = -0.069153f;
+ 	val_dir[12129*3 + 0] = -0.640321f;	val_dir[12129*3 + 1] = -0.758899f;	val_dir[12129*3 + 2] = -0.118578f;
+ 	val_dir[12130*3 + 0] = -0.633205f;	val_dir[12130*3 + 1] = -0.754976f;	val_dir[12130*3 + 2] = -0.170478f;
+ 	val_dir[12131*3 + 0] = -0.623831f;	val_dir[12131*3 + 1] = -0.748598f;	val_dir[12131*3 + 2] = -0.224579f;
+ 	val_dir[12132*3 + 0] = -0.611974f;	val_dir[12132*3 + 1] = -0.739469f;	val_dir[12132*3 + 2] = -0.280488f;
+ 	val_dir[12133*3 + 0] = -0.597453f;	val_dir[12133*3 + 1] = -0.727334f;	val_dir[12133*3 + 2] = -0.337691f;
+ 	val_dir[12134*3 + 0] = -0.580154f;	val_dir[12134*3 + 1] = -0.712007f;	val_dir[12134*3 + 2] = -0.395559f;
+ 	val_dir[12135*3 + 0] = -0.560050f;	val_dir[12135*3 + 1] = -0.693395f;	val_dir[12135*3 + 2] = -0.453374f;
+ 	val_dir[12136*3 + 0] = -0.537215f;	val_dir[12136*3 + 1] = -0.671519f;	val_dir[12136*3 + 2] = -0.510355f;
+ 	val_dir[12137*3 + 0] = -0.511834f;	val_dir[12137*3 + 1] = -0.646527f;	val_dir[12137*3 + 2] = -0.565711f;
+ 	val_dir[12138*3 + 0] = -0.484193f;	val_dir[12138*3 + 1] = -0.618691f;	val_dir[12138*3 + 2] = -0.618691f;
+ 	val_dir[12139*3 + 0] = -0.454669f;	val_dir[12139*3 + 1] = -0.588395f;	val_dir[12139*3 + 2] = -0.668631f;
+ 	val_dir[12140*3 + 0] = -0.423702f;	val_dir[12140*3 + 1] = -0.556108f;	val_dir[12140*3 + 2] = -0.714997f;
+ 	val_dir[12141*3 + 0] = -0.391764f;	val_dir[12141*3 + 1] = -0.522352f;	val_dir[12141*3 + 2] = -0.757410f;
+ 	val_dir[12142*3 + 0] = -0.359329f;	val_dir[12142*3 + 1] = -0.487661f;	val_dir[12142*3 + 2] = -0.795657f;
+ 	val_dir[12143*3 + 0] = -0.326844f;	val_dir[12143*3 + 1] = -0.452553f;	val_dir[12143*3 + 2] = -0.829680f;
+ 	val_dir[12144*3 + 0] = -0.294706f;	val_dir[12144*3 + 1] = -0.41750f;	val_dir[12144*3 + 2] = -0.859559f;
+ 	val_dir[12145*3 + 0] = -0.263251f;	val_dir[12145*3 + 1] = -0.382911f;	val_dir[12145*3 + 2] = -0.885482f;
+ 	val_dir[12146*3 + 0] = -0.232747f;	val_dir[12146*3 + 1] = -0.349121f;	val_dir[12146*3 + 2] = -0.907713f;
+ 	val_dir[12147*3 + 0] = -0.203393f;	val_dir[12147*3 + 1] = -0.316389f;	val_dir[12147*3 + 2] = -0.926568f;
+ 	val_dir[12148*3 + 0] = -0.175327f;	val_dir[12148*3 + 1] = -0.284907f;	val_dir[12148*3 + 2] = -0.942384f;
+ 	val_dir[12149*3 + 0] = -0.148634f;	val_dir[12149*3 + 1] = -0.254801f;	val_dir[12149*3 + 2] = -0.955502f;
+ 	val_dir[12150*3 + 0] = -0.123351f;	val_dir[12150*3 + 1] = -0.226144f;	val_dir[12150*3 + 2] = -0.966252f;
+ 	val_dir[12151*3 + 0] = -0.099484f;	val_dir[12151*3 + 1] = -0.198968f;	val_dir[12151*3 + 2] = -0.974943f;
+ 	val_dir[12152*3 + 0] = -0.077009f;	val_dir[12152*3 + 1] = -0.173269f;	val_dir[12152*3 + 2] = -0.981859f;
+ 	val_dir[12153*3 + 0] = -0.055882f;	val_dir[12153*3 + 1] = -0.149019f;	val_dir[12153*3 + 2] = -0.987254f;
+ 	val_dir[12154*3 + 0] = -0.036049f;	val_dir[12154*3 + 1] = -0.126172f;	val_dir[12154*3 + 2] = -0.991353f;
+ 	val_dir[12155*3 + 0] = -0.017445f;	val_dir[12155*3 + 1] = -0.104669f;	val_dir[12155*3 + 2] = -0.994354f;
+ 	val_dir[12156*3 + 0] = 0.0f;	val_dir[12156*3 + 1] = -0.084443f;	val_dir[12156*3 + 2] = -0.996428f;
+ 	val_dir[12157*3 + 0] = 0.016908f;	val_dir[12157*3 + 1] = -0.067632f;	val_dir[12157*3 + 2] = -0.997567f;
+ 	val_dir[12158*3 + 0] = 0.033835f;	val_dir[12158*3 + 1] = -0.050753f;	val_dir[12158*3 + 2] = -0.998138f;
+ 	val_dir[12159*3 + 0] = 0.050753f;	val_dir[12159*3 + 1] = -0.033835f;	val_dir[12159*3 + 2] = -0.998138f;
+ 	val_dir[12160*3 + 0] = 0.067632f;	val_dir[12160*3 + 1] = -0.016908f;	val_dir[12160*3 + 2] = -0.997567f;
+ 	val_dir[12161*3 + 0] = 0.084443f;	val_dir[12161*3 + 1] = 0.0f;	val_dir[12161*3 + 2] = -0.996428f;
+ 	val_dir[12162*3 + 0] = 0.104669f;	val_dir[12162*3 + 1] = 0.017445f;	val_dir[12162*3 + 2] = -0.994354f;
+ 	val_dir[12163*3 + 0] = 0.126172f;	val_dir[12163*3 + 1] = 0.036049f;	val_dir[12163*3 + 2] = -0.991353f;
+ 	val_dir[12164*3 + 0] = 0.149019f;	val_dir[12164*3 + 1] = 0.055882f;	val_dir[12164*3 + 2] = -0.987254f;
+ 	val_dir[12165*3 + 0] = 0.173269f;	val_dir[12165*3 + 1] = 0.077009f;	val_dir[12165*3 + 2] = -0.981859f;
+ 	val_dir[12166*3 + 0] = 0.198968f;	val_dir[12166*3 + 1] = 0.099484f;	val_dir[12166*3 + 2] = -0.974943f;
+ 	val_dir[12167*3 + 0] = 0.226144f;	val_dir[12167*3 + 1] = 0.123351f;	val_dir[12167*3 + 2] = -0.966252f;
+ 	val_dir[12168*3 + 0] = 0.254801f;	val_dir[12168*3 + 1] = 0.148634f;	val_dir[12168*3 + 2] = -0.955502f;
+ 	val_dir[12169*3 + 0] = 0.284907f;	val_dir[12169*3 + 1] = 0.175327f;	val_dir[12169*3 + 2] = -0.942384f;
+ 	val_dir[12170*3 + 0] = 0.316389f;	val_dir[12170*3 + 1] = 0.203393f;	val_dir[12170*3 + 2] = -0.926568f;
+ 	val_dir[12171*3 + 0] = 0.349121f;	val_dir[12171*3 + 1] = 0.232747f;	val_dir[12171*3 + 2] = -0.907713f;
+ 	val_dir[12172*3 + 0] = 0.382911f;	val_dir[12172*3 + 1] = 0.263251f;	val_dir[12172*3 + 2] = -0.885482f;
+ 	val_dir[12173*3 + 0] = 0.41750f;	val_dir[12173*3 + 1] = 0.294706f;	val_dir[12173*3 + 2] = -0.859559f;
+ 	val_dir[12174*3 + 0] = 0.452553f;	val_dir[12174*3 + 1] = 0.326844f;	val_dir[12174*3 + 2] = -0.829680f;
+ 	val_dir[12175*3 + 0] = 0.487661f;	val_dir[12175*3 + 1] = 0.359329f;	val_dir[12175*3 + 2] = -0.795657f;
+ 	val_dir[12176*3 + 0] = 0.522352f;	val_dir[12176*3 + 1] = 0.391764f;	val_dir[12176*3 + 2] = -0.757410f;
+ 	val_dir[12177*3 + 0] = 0.556108f;	val_dir[12177*3 + 1] = 0.423702f;	val_dir[12177*3 + 2] = -0.714997f;
+ 	val_dir[12178*3 + 0] = 0.588395f;	val_dir[12178*3 + 1] = 0.454669f;	val_dir[12178*3 + 2] = -0.668631f;
+ 	val_dir[12179*3 + 0] = 0.618691f;	val_dir[12179*3 + 1] = 0.484193f;	val_dir[12179*3 + 2] = -0.618691f;
+ 	val_dir[12180*3 + 0] = 0.646527f;	val_dir[12180*3 + 1] = 0.511834f;	val_dir[12180*3 + 2] = -0.565711f;
+ 	val_dir[12181*3 + 0] = 0.671519f;	val_dir[12181*3 + 1] = 0.537215f;	val_dir[12181*3 + 2] = -0.510355f;
+ 	val_dir[12182*3 + 0] = 0.693395f;	val_dir[12182*3 + 1] = 0.560050f;	val_dir[12182*3 + 2] = -0.453374f;
+ 	val_dir[12183*3 + 0] = 0.712007f;	val_dir[12183*3 + 1] = 0.580154f;	val_dir[12183*3 + 2] = -0.395559f;
+ 	val_dir[12184*3 + 0] = 0.727334f;	val_dir[12184*3 + 1] = 0.597453f;	val_dir[12184*3 + 2] = -0.337691f;
+ 	val_dir[12185*3 + 0] = 0.739469f;	val_dir[12185*3 + 1] = 0.611974f;	val_dir[12185*3 + 2] = -0.280488f;
+ 	val_dir[12186*3 + 0] = 0.748598f;	val_dir[12186*3 + 1] = 0.623831f;	val_dir[12186*3 + 2] = -0.224579f;
+ 	val_dir[12187*3 + 0] = 0.754976f;	val_dir[12187*3 + 1] = 0.633205f;	val_dir[12187*3 + 2] = -0.170478f;
+ 	val_dir[12188*3 + 0] = 0.758899f;	val_dir[12188*3 + 1] = 0.640321f;	val_dir[12188*3 + 2] = -0.118578f;
+ 	val_dir[12189*3 + 0] = 0.760684f;	val_dir[12189*3 + 1] = 0.645429f;	val_dir[12189*3 + 2] = -0.069153f;
+ 	val_dir[12190*3 + 0] = 0.760644f;	val_dir[12190*3 + 1] = 0.648784f;	val_dir[12190*3 + 2] = -0.022372f;
+ 	val_dir[12191*3 + 0] = -0.661622f;	val_dir[12191*3 + 1] = -0.749838f;	val_dir[12191*3 + 2] = 0.0f;
+ 	val_dir[12192*3 + 0] = -0.659432f;	val_dir[12192*3 + 1] = -0.750388f;	val_dir[12192*3 + 2] = -0.045478f;
+ 	val_dir[12193*3 + 0] = -0.655610f;	val_dir[12193*3 + 1] = -0.749269f;	val_dir[12193*3 + 2] = -0.093659f;
+ 	val_dir[12194*3 + 0] = -0.649895f;	val_dir[12194*3 + 1] = -0.746176f;	val_dir[12194*3 + 2] = -0.144421f;
+ 	val_dir[12195*3 + 0] = -0.642024f;	val_dir[12195*3 + 1] = -0.740797f;	val_dir[12195*3 + 2] = -0.197546f;
+ 	val_dir[12196*3 + 0] = -0.631748f;	val_dir[12196*3 + 1] = -0.732828f;	val_dir[12196*3 + 2] = -0.252699f;
+ 	val_dir[12197*3 + 0] = -0.618853f;	val_dir[12197*3 + 1] = -0.721995f;	val_dir[12197*3 + 2] = -0.309426f;
+ 	val_dir[12198*3 + 0] = -0.603178f;	val_dir[12198*3 + 1] = -0.708079f;	val_dir[12198*3 + 2] = -0.367152f;
+ 	val_dir[12199*3 + 0] = -0.584643f;	val_dir[12199*3 + 1] = -0.690942f;	val_dir[12199*3 + 2] = -0.425195f;
+ 	val_dir[12200*3 + 0] = -0.563264f;	val_dir[12200*3 + 1] = -0.670552f;	val_dir[12200*3 + 2] = -0.482798f;
+ 	val_dir[12201*3 + 0] = -0.539164f;	val_dir[12201*3 + 1] = -0.646997f;	val_dir[12201*3 + 2] = -0.539164f;
+ 	val_dir[12202*3 + 0] = -0.512578f;	val_dir[12202*3 + 1] = -0.620490f;	val_dir[12202*3 + 2] = -0.593512f;
+ 	val_dir[12203*3 + 0] = -0.483843f;	val_dir[12203*3 + 1] = -0.591364f;	val_dir[12203*3 + 2] = -0.645124f;
+ 	val_dir[12204*3 + 0] = -0.453374f;	val_dir[12204*3 + 1] = -0.560050f;	val_dir[12204*3 + 2] = -0.693395f;
+ 	val_dir[12205*3 + 0] = -0.421637f;	val_dir[12205*3 + 1] = -0.527046f;	val_dir[12205*3 + 2] = -0.737865f;
+ 	val_dir[12206*3 + 0] = -0.389118f;	val_dir[12206*3 + 1] = -0.492883f;	val_dir[12206*3 + 2] = -0.778237f;
+ 	val_dir[12207*3 + 0] = -0.356291f;	val_dir[12207*3 + 1] = -0.458088f;	val_dir[12207*3 + 2] = -0.814379f;
+ 	val_dir[12208*3 + 0] = -0.323587f;	val_dir[12208*3 + 1] = -0.423153f;	val_dir[12208*3 + 2] = -0.846305f;
+ 	val_dir[12209*3 + 0] = -0.291386f;	val_dir[12209*3 + 1] = -0.388514f;	val_dir[12209*3 + 2] = -0.874157f;
+ 	val_dir[12210*3 + 0] = -0.259996f;	val_dir[12210*3 + 1] = -0.354540f;	val_dir[12210*3 + 2] = -0.898167f;
+ 	val_dir[12211*3 + 0] = -0.229658f;	val_dir[12211*3 + 1] = -0.321521f;	val_dir[12211*3 + 2] = -0.918630f;
+ 	val_dir[12212*3 + 0] = -0.200545f;	val_dir[12212*3 + 1] = -0.289677f;	val_dir[12212*3 + 2] = -0.935879f;
+ 	val_dir[12213*3 + 0] = -0.172774f;	val_dir[12213*3 + 1] = -0.259161f;	val_dir[12213*3 + 2] = -0.950255f;
+ 	val_dir[12214*3 + 0] = -0.146406f;	val_dir[12214*3 + 1] = -0.230067f;	val_dir[12214*3 + 2] = -0.962099f;
+ 	val_dir[12215*3 + 0] = -0.121466f;	val_dir[12215*3 + 1] = -0.202444f;	val_dir[12215*3 + 2] = -0.971732f;
+ 	val_dir[12216*3 + 0] = -0.097945f;	val_dir[12216*3 + 1] = -0.176301f;	val_dir[12216*3 + 2] = -0.979451f;
+ 	val_dir[12217*3 + 0] = -0.075810f;	val_dir[12217*3 + 1] = -0.151620f;	val_dir[12217*3 + 2] = -0.985527f;
+ 	val_dir[12218*3 + 0] = -0.055011f;	val_dir[12218*3 + 1] = -0.128359f;	val_dir[12218*3 + 2] = -0.990201f;
+ 	val_dir[12219*3 + 0] = -0.035489f;	val_dir[12219*3 + 1] = -0.106466f;	val_dir[12219*3 + 2] = -0.993683f;
+ 	val_dir[12220*3 + 0] = -0.017175f;	val_dir[12220*3 + 1] = -0.085876f;	val_dir[12220*3 + 2] = -0.996158f;
+ 	val_dir[12221*3 + 0] = 0.0f;	val_dir[12221*3 + 1] = -0.066519f;	val_dir[12221*3 + 2] = -0.997785f;
+ 	val_dir[12222*3 + 0] = 0.016644f;	val_dir[12222*3 + 1] = -0.049931f;	val_dir[12222*3 + 2] = -0.998614f;
+ 	val_dir[12223*3 + 0] = 0.033296f;	val_dir[12223*3 + 1] = -0.033296f;	val_dir[12223*3 + 2] = -0.998891f;
+ 	val_dir[12224*3 + 0] = 0.049931f;	val_dir[12224*3 + 1] = -0.016644f;	val_dir[12224*3 + 2] = -0.998614f;
+ 	val_dir[12225*3 + 0] = 0.066519f;	val_dir[12225*3 + 1] = 0.0f;	val_dir[12225*3 + 2] = -0.997785f;
+ 	val_dir[12226*3 + 0] = 0.085876f;	val_dir[12226*3 + 1] = 0.017175f;	val_dir[12226*3 + 2] = -0.996158f;
+ 	val_dir[12227*3 + 0] = 0.106466f;	val_dir[12227*3 + 1] = 0.035489f;	val_dir[12227*3 + 2] = -0.993683f;
+ 	val_dir[12228*3 + 0] = 0.128359f;	val_dir[12228*3 + 1] = 0.055011f;	val_dir[12228*3 + 2] = -0.990201f;
+ 	val_dir[12229*3 + 0] = 0.151620f;	val_dir[12229*3 + 1] = 0.075810f;	val_dir[12229*3 + 2] = -0.985527f;
+ 	val_dir[12230*3 + 0] = 0.176301f;	val_dir[12230*3 + 1] = 0.097945f;	val_dir[12230*3 + 2] = -0.979451f;
+ 	val_dir[12231*3 + 0] = 0.202444f;	val_dir[12231*3 + 1] = 0.121466f;	val_dir[12231*3 + 2] = -0.971732f;
+ 	val_dir[12232*3 + 0] = 0.230067f;	val_dir[12232*3 + 1] = 0.146406f;	val_dir[12232*3 + 2] = -0.962099f;
+ 	val_dir[12233*3 + 0] = 0.259161f;	val_dir[12233*3 + 1] = 0.172774f;	val_dir[12233*3 + 2] = -0.950255f;
+ 	val_dir[12234*3 + 0] = 0.289677f;	val_dir[12234*3 + 1] = 0.200545f;	val_dir[12234*3 + 2] = -0.935879f;
+ 	val_dir[12235*3 + 0] = 0.321521f;	val_dir[12235*3 + 1] = 0.229658f;	val_dir[12235*3 + 2] = -0.918630f;
+ 	val_dir[12236*3 + 0] = 0.354540f;	val_dir[12236*3 + 1] = 0.259996f;	val_dir[12236*3 + 2] = -0.898167f;
+ 	val_dir[12237*3 + 0] = 0.388514f;	val_dir[12237*3 + 1] = 0.291386f;	val_dir[12237*3 + 2] = -0.874157f;
+ 	val_dir[12238*3 + 0] = 0.423153f;	val_dir[12238*3 + 1] = 0.323587f;	val_dir[12238*3 + 2] = -0.846305f;
+ 	val_dir[12239*3 + 0] = 0.458088f;	val_dir[12239*3 + 1] = 0.356291f;	val_dir[12239*3 + 2] = -0.814379f;
+ 	val_dir[12240*3 + 0] = 0.492883f;	val_dir[12240*3 + 1] = 0.389118f;	val_dir[12240*3 + 2] = -0.778237f;
+ 	val_dir[12241*3 + 0] = 0.527046f;	val_dir[12241*3 + 1] = 0.421637f;	val_dir[12241*3 + 2] = -0.737865f;
+ 	val_dir[12242*3 + 0] = 0.560050f;	val_dir[12242*3 + 1] = 0.453374f;	val_dir[12242*3 + 2] = -0.693395f;
+ 	val_dir[12243*3 + 0] = 0.591364f;	val_dir[12243*3 + 1] = 0.483843f;	val_dir[12243*3 + 2] = -0.645124f;
+ 	val_dir[12244*3 + 0] = 0.620490f;	val_dir[12244*3 + 1] = 0.512578f;	val_dir[12244*3 + 2] = -0.593512f;
+ 	val_dir[12245*3 + 0] = 0.646997f;	val_dir[12245*3 + 1] = 0.539164f;	val_dir[12245*3 + 2] = -0.539164f;
+ 	val_dir[12246*3 + 0] = 0.670552f;	val_dir[12246*3 + 1] = 0.563264f;	val_dir[12246*3 + 2] = -0.482798f;
+ 	val_dir[12247*3 + 0] = 0.690942f;	val_dir[12247*3 + 1] = 0.584643f;	val_dir[12247*3 + 2] = -0.425195f;
+ 	val_dir[12248*3 + 0] = 0.708079f;	val_dir[12248*3 + 1] = 0.603178f;	val_dir[12248*3 + 2] = -0.367152f;
+ 	val_dir[12249*3 + 0] = 0.721995f;	val_dir[12249*3 + 1] = 0.618853f;	val_dir[12249*3 + 2] = -0.309426f;
+ 	val_dir[12250*3 + 0] = 0.732828f;	val_dir[12250*3 + 1] = 0.631748f;	val_dir[12250*3 + 2] = -0.252699f;
+ 	val_dir[12251*3 + 0] = 0.740797f;	val_dir[12251*3 + 1] = 0.642024f;	val_dir[12251*3 + 2] = -0.197546f;
+ 	val_dir[12252*3 + 0] = 0.746176f;	val_dir[12252*3 + 1] = 0.649895f;	val_dir[12252*3 + 2] = -0.144421f;
+ 	val_dir[12253*3 + 0] = 0.749269f;	val_dir[12253*3 + 1] = 0.655610f;	val_dir[12253*3 + 2] = -0.093659f;
+ 	val_dir[12254*3 + 0] = 0.750388f;	val_dir[12254*3 + 1] = 0.659432f;	val_dir[12254*3 + 2] = -0.045478f;
+ 	val_dir[12255*3 + 0] = 0.749838f;	val_dir[12255*3 + 1] = 0.661622f;	val_dir[12255*3 + 2] = 0.0f;
+ 	val_dir[12256*3 + 0] = -0.672504f;	val_dir[12256*3 + 1] = -0.739754f;	val_dir[12256*3 + 2] = -0.022417f;
+ 	val_dir[12257*3 + 0] = -0.669905f;	val_dir[12257*3 + 1] = -0.739205f;	val_dir[12257*3 + 2] = -0.069301f;
+ 	val_dir[12258*3 + 0] = -0.665536f;	val_dir[12258*3 + 1] = -0.736843f;	val_dir[12258*3 + 2] = -0.118846f;
+ 	val_dir[12259*3 + 0] = -0.659125f;	val_dir[12259*3 + 1] = -0.732361f;	val_dir[12259*3 + 2] = -0.170884f;
+ 	val_dir[12260*3 + 0] = -0.650407f;	val_dir[12260*3 + 1] = -0.725454f;	val_dir[12260*3 + 2] = -0.225141f;
+ 	val_dir[12261*3 + 0] = -0.639138f;	val_dir[12261*3 + 1] = -0.715834f;	val_dir[12261*3 + 2] = -0.281220f;
+ 	val_dir[12262*3 + 0] = -0.625119f;	val_dir[12262*3 + 1] = -0.703259f;	val_dir[12262*3 + 2] = -0.338606f;
+ 	val_dir[12263*3 + 0] = -0.608219f;	val_dir[12263*3 + 1] = -0.687552f;	val_dir[12263*3 + 2] = -0.396664f;
+ 	val_dir[12264*3 + 0] = -0.588395f;	val_dir[12264*3 + 1] = -0.668631f;	val_dir[12264*3 + 2] = -0.454669f;
+ 	val_dir[12265*3 + 0] = -0.565711f;	val_dir[12265*3 + 1] = -0.646527f;	val_dir[12265*3 + 2] = -0.511834f;
+ 	val_dir[12266*3 + 0] = -0.540343f;	val_dir[12266*3 + 1] = -0.621395f;	val_dir[12266*3 + 2] = -0.567360f;
+ 	val_dir[12267*3 + 0] = -0.512578f;	val_dir[12267*3 + 1] = -0.593512f;	val_dir[12267*3 + 2] = -0.620490f;
+ 	val_dir[12268*3 + 0] = -0.482798f;	val_dir[12268*3 + 1] = -0.563264f;	val_dir[12268*3 + 2] = -0.670552f;
+ 	val_dir[12269*3 + 0] = -0.451451f;	val_dir[12269*3 + 1] = -0.531119f;	val_dir[12269*3 + 2] = -0.717011f;
+ 	val_dir[12270*3 + 0] = -0.419026f;	val_dir[12270*3 + 1] = -0.497594f;	val_dir[12270*3 + 2] = -0.759485f;
+ 	val_dir[12271*3 + 0] = -0.386014f;	val_dir[12271*3 + 1] = -0.463217f;	val_dir[12271*3 + 2] = -0.797762f;
+ 	val_dir[12272*3 + 0] = -0.352879f;	val_dir[12272*3 + 1] = -0.428496f;	val_dir[12272*3 + 2] = -0.831786f;
+ 	val_dir[12273*3 + 0] = -0.320038f;	val_dir[12273*3 + 1] = -0.393893f;	val_dir[12273*3 + 2] = -0.861640f;
+ 	val_dir[12274*3 + 0] = -0.287843f;	val_dir[12274*3 + 1] = -0.359804f;	val_dir[12274*3 + 2] = -0.887517f;
+ 	val_dir[12275*3 + 0] = -0.256578f;	val_dir[12275*3 + 1] = -0.326554f;	val_dir[12275*3 + 2] = -0.909687f;
+ 	val_dir[12276*3 + 0] = -0.226455f;	val_dir[12276*3 + 1] = -0.294392f;	val_dir[12276*3 + 2] = -0.928467f;
+ 	val_dir[12277*3 + 0] = -0.197623f;	val_dir[12277*3 + 1] = -0.263498f;	val_dir[12277*3 + 2] = -0.94420f;
+ 	val_dir[12278*3 + 0] = -0.170174f;	val_dir[12278*3 + 1] = -0.233990f;	val_dir[12278*3 + 2] = -0.957230f;
+ 	val_dir[12279*3 + 0] = -0.144154f;	val_dir[12279*3 + 1] = -0.205934f;	val_dir[12279*3 + 2] = -0.967890f;
+ 	val_dir[12280*3 + 0] = -0.119570f;	val_dir[12280*3 + 1] = -0.179355f;	val_dir[12280*3 + 2] = -0.976491f;
+ 	val_dir[12281*3 + 0] = -0.096404f;	val_dir[12281*3 + 1] = -0.154246f;	val_dir[12281*3 + 2] = -0.983318f;
+ 	val_dir[12282*3 + 0] = -0.074613f;	val_dir[12282*3 + 1] = -0.130573f;	val_dir[12282*3 + 2] = -0.988627f;
+ 	val_dir[12283*3 + 0] = -0.054144f;	val_dir[12283*3 + 1] = -0.108288f;	val_dir[12283*3 + 2] = -0.992644f;
+ 	val_dir[12284*3 + 0] = -0.034932f;	val_dir[12284*3 + 1] = -0.087330f;	val_dir[12284*3 + 2] = -0.995567f;
+ 	val_dir[12285*3 + 0] = -0.016908f;	val_dir[12285*3 + 1] = -0.067632f;	val_dir[12285*3 + 2] = -0.997567f;
+ 	val_dir[12286*3 + 0] = 0.0f;	val_dir[12286*3 + 1] = -0.049121f;	val_dir[12286*3 + 2] = -0.998793f;
+ 	val_dir[12287*3 + 0] = 0.016382f;	val_dir[12287*3 + 1] = -0.032765f;	val_dir[12287*3 + 2] = -0.999329f;
+ 	val_dir[12288*3 + 0] = 0.032765f;	val_dir[12288*3 + 1] = -0.016382f;	val_dir[12288*3 + 2] = -0.999329f;
+ 	val_dir[12289*3 + 0] = 0.049121f;	val_dir[12289*3 + 1] = 0.0f;	val_dir[12289*3 + 2] = -0.998793f;
+ 	val_dir[12290*3 + 0] = 0.067632f;	val_dir[12290*3 + 1] = 0.016908f;	val_dir[12290*3 + 2] = -0.997567f;
+ 	val_dir[12291*3 + 0] = 0.087330f;	val_dir[12291*3 + 1] = 0.034932f;	val_dir[12291*3 + 2] = -0.995567f;
+ 	val_dir[12292*3 + 0] = 0.108288f;	val_dir[12292*3 + 1] = 0.054144f;	val_dir[12292*3 + 2] = -0.992644f;
+ 	val_dir[12293*3 + 0] = 0.130573f;	val_dir[12293*3 + 1] = 0.074613f;	val_dir[12293*3 + 2] = -0.988627f;
+ 	val_dir[12294*3 + 0] = 0.154246f;	val_dir[12294*3 + 1] = 0.096404f;	val_dir[12294*3 + 2] = -0.983318f;
+ 	val_dir[12295*3 + 0] = 0.179355f;	val_dir[12295*3 + 1] = 0.119570f;	val_dir[12295*3 + 2] = -0.976491f;
+ 	val_dir[12296*3 + 0] = 0.205934f;	val_dir[12296*3 + 1] = 0.144154f;	val_dir[12296*3 + 2] = -0.967890f;
+ 	val_dir[12297*3 + 0] = 0.233990f;	val_dir[12297*3 + 1] = 0.170174f;	val_dir[12297*3 + 2] = -0.957230f;
+ 	val_dir[12298*3 + 0] = 0.263498f;	val_dir[12298*3 + 1] = 0.197623f;	val_dir[12298*3 + 2] = -0.94420f;
+ 	val_dir[12299*3 + 0] = 0.294392f;	val_dir[12299*3 + 1] = 0.226455f;	val_dir[12299*3 + 2] = -0.928467f;
+ 	val_dir[12300*3 + 0] = 0.326554f;	val_dir[12300*3 + 1] = 0.256578f;	val_dir[12300*3 + 2] = -0.909687f;
+ 	val_dir[12301*3 + 0] = 0.359804f;	val_dir[12301*3 + 1] = 0.287843f;	val_dir[12301*3 + 2] = -0.887517f;
+ 	val_dir[12302*3 + 0] = 0.393893f;	val_dir[12302*3 + 1] = 0.320038f;	val_dir[12302*3 + 2] = -0.861640f;
+ 	val_dir[12303*3 + 0] = 0.428496f;	val_dir[12303*3 + 1] = 0.352879f;	val_dir[12303*3 + 2] = -0.831786f;
+ 	val_dir[12304*3 + 0] = 0.463217f;	val_dir[12304*3 + 1] = 0.386014f;	val_dir[12304*3 + 2] = -0.797762f;
+ 	val_dir[12305*3 + 0] = 0.497594f;	val_dir[12305*3 + 1] = 0.419026f;	val_dir[12305*3 + 2] = -0.759485f;
+ 	val_dir[12306*3 + 0] = 0.531119f;	val_dir[12306*3 + 1] = 0.451451f;	val_dir[12306*3 + 2] = -0.717011f;
+ 	val_dir[12307*3 + 0] = 0.563264f;	val_dir[12307*3 + 1] = 0.482798f;	val_dir[12307*3 + 2] = -0.670552f;
+ 	val_dir[12308*3 + 0] = 0.593512f;	val_dir[12308*3 + 1] = 0.512578f;	val_dir[12308*3 + 2] = -0.620490f;
+ 	val_dir[12309*3 + 0] = 0.621395f;	val_dir[12309*3 + 1] = 0.540343f;	val_dir[12309*3 + 2] = -0.567360f;
+ 	val_dir[12310*3 + 0] = 0.646527f;	val_dir[12310*3 + 1] = 0.565711f;	val_dir[12310*3 + 2] = -0.511834f;
+ 	val_dir[12311*3 + 0] = 0.668631f;	val_dir[12311*3 + 1] = 0.588395f;	val_dir[12311*3 + 2] = -0.454669f;
+ 	val_dir[12312*3 + 0] = 0.687552f;	val_dir[12312*3 + 1] = 0.608219f;	val_dir[12312*3 + 2] = -0.396664f;
+ 	val_dir[12313*3 + 0] = 0.703259f;	val_dir[12313*3 + 1] = 0.625119f;	val_dir[12313*3 + 2] = -0.338606f;
+ 	val_dir[12314*3 + 0] = 0.715834f;	val_dir[12314*3 + 1] = 0.639138f;	val_dir[12314*3 + 2] = -0.281220f;
+ 	val_dir[12315*3 + 0] = 0.725454f;	val_dir[12315*3 + 1] = 0.650407f;	val_dir[12315*3 + 2] = -0.225141f;
+ 	val_dir[12316*3 + 0] = 0.732361f;	val_dir[12316*3 + 1] = 0.659125f;	val_dir[12316*3 + 2] = -0.170884f;
+ 	val_dir[12317*3 + 0] = 0.736843f;	val_dir[12317*3 + 1] = 0.665536f;	val_dir[12317*3 + 2] = -0.118846f;
+ 	val_dir[12318*3 + 0] = 0.739205f;	val_dir[12318*3 + 1] = 0.669905f;	val_dir[12318*3 + 2] = -0.069301f;
+ 	val_dir[12319*3 + 0] = 0.739754f;	val_dir[12319*3 + 1] = 0.672504f;	val_dir[12319*3 + 2] = -0.022417f;
+ 	val_dir[12320*3 + 0] = -0.684675f;	val_dir[12320*3 + 1] = -0.728848f;	val_dir[12320*3 + 2] = 0.0f;
+ 	val_dir[12321*3 + 0] = -0.683231f;	val_dir[12321*3 + 1] = -0.728780f;	val_dir[12321*3 + 2] = -0.045549f;
+ 	val_dir[12322*3 + 0] = -0.680144f;	val_dir[12322*3 + 1] = -0.727051f;	val_dir[12322*3 + 2] = -0.093813f;
+ 	val_dir[12323*3 + 0] = -0.675140f;	val_dir[12323*3 + 1] = -0.723364f;	val_dir[12323*3 + 2] = -0.144673f;
+ 	val_dir[12324*3 + 0] = -0.667940f;	val_dir[12324*3 + 1] = -0.717418f;	val_dir[12324*3 + 2] = -0.197908f;
+ 	val_dir[12325*3 + 0] = -0.658281f;	val_dir[12325*3 + 1] = -0.708918f;	val_dir[12325*3 + 2] = -0.253185f;
+ 	val_dir[12326*3 + 0] = -0.645928f;	val_dir[12326*3 + 1] = -0.697602f;	val_dir[12326*3 + 2] = -0.310045f;
+ 	val_dir[12327*3 + 0] = -0.630706f;	val_dir[12327*3 + 1] = -0.683265f;	val_dir[12327*3 + 2] = -0.367912f;
+ 	val_dir[12328*3 + 0] = -0.612517f;	val_dir[12328*3 + 1] = -0.665780f;	val_dir[12328*3 + 2] = -0.426099f;
+ 	val_dir[12329*3 + 0] = -0.591364f;	val_dir[12329*3 + 1] = -0.645124f;	val_dir[12329*3 + 2] = -0.483843f;
+ 	val_dir[12330*3 + 0] = -0.567360f;	val_dir[12330*3 + 1] = -0.621395f;	val_dir[12330*3 + 2] = -0.540343f;
+ 	val_dir[12331*3 + 0] = -0.540738f;	val_dir[12331*3 + 1] = -0.594812f;	val_dir[12331*3 + 2] = -0.594812f;
+ 	val_dir[12332*3 + 0] = -0.511834f;	val_dir[12332*3 + 1] = -0.565711f;	val_dir[12332*3 + 2] = -0.646527f;
+ 	val_dir[12333*3 + 0] = -0.481070f;	val_dir[12333*3 + 1] = -0.534522f;	val_dir[12333*3 + 2] = -0.694879f;
+ 	val_dir[12334*3 + 0] = -0.448926f;	val_dir[12334*3 + 1] = -0.501740f;	val_dir[12334*3 + 2] = -0.739407f;
+ 	val_dir[12335*3 + 0] = -0.41590f;	val_dir[12335*3 + 1] = -0.467888f;	val_dir[12335*3 + 2] = -0.779813f;
+ 	val_dir[12336*3 + 0] = -0.382484f;	val_dir[12336*3 + 1] = -0.433482f;	val_dir[12336*3 + 2] = -0.815966f;
+ 	val_dir[12337*3 + 0] = -0.349128f;	val_dir[12337*3 + 1] = -0.399004f;	val_dir[12337*3 + 2] = -0.847883f;
+ 	val_dir[12338*3 + 0] = -0.316228f;	val_dir[12338*3 + 1] = -0.364878f;	val_dir[12338*3 + 2] = -0.875708f;
+ 	val_dir[12339*3 + 0] = -0.284108f;	val_dir[12339*3 + 1] = -0.331460f;	val_dir[12339*3 + 2] = -0.899676f;
+ 	val_dir[12340*3 + 0] = -0.253024f;	val_dir[12340*3 + 1] = -0.299028f;	val_dir[12340*3 + 2] = -0.920087f;
+ 	val_dir[12341*3 + 0] = -0.223161f;	val_dir[12341*3 + 1] = -0.267793f;	val_dir[12341*3 + 2] = -0.937276f;
+ 	val_dir[12342*3 + 0] = -0.194643f;	val_dir[12342*3 + 1] = -0.237897f;	val_dir[12342*3 + 2] = -0.951588f;
+ 	val_dir[12343*3 + 0] = -0.167542f;	val_dir[12343*3 + 1] = -0.209427f;	val_dir[12343*3 + 2] = -0.963364f;
+ 	val_dir[12344*3 + 0] = -0.141885f;	val_dir[12344*3 + 1] = -0.182424f;	val_dir[12344*3 + 2] = -0.972929f;
+ 	val_dir[12345*3 + 0] = -0.117670f;	val_dir[12345*3 + 1] = -0.156893f;	val_dir[12345*3 + 2] = -0.980581f;
+ 	val_dir[12346*3 + 0] = -0.094865f;	val_dir[12346*3 + 1] = -0.132810f;	val_dir[12346*3 + 2] = -0.986591f;
+ 	val_dir[12347*3 + 0] = -0.073422f;	val_dir[12347*3 + 1] = -0.110133f;	val_dir[12347*3 + 2] = -0.991201f;
+ 	val_dir[12348*3 + 0] = -0.053283f;	val_dir[12348*3 + 1] = -0.088806f;	val_dir[12348*3 + 2] = -0.994623f;
+ 	val_dir[12349*3 + 0] = -0.034381f;	val_dir[12349*3 + 1] = -0.068761f;	val_dir[12349*3 + 2] = -0.997041f;
+ 	val_dir[12350*3 + 0] = -0.016644f;	val_dir[12350*3 + 1] = -0.049931f;	val_dir[12350*3 + 2] = -0.998614f;
+ 	val_dir[12351*3 + 0] = 0.0f;	val_dir[12351*3 + 1] = -0.032241f;	val_dir[12351*3 + 2] = -0.999480f;
+ 	val_dir[12352*3 + 0] = 0.016125f;	val_dir[12352*3 + 1] = -0.016125f;	val_dir[12352*3 + 2] = -0.999740f;
+ 	val_dir[12353*3 + 0] = 0.032241f;	val_dir[12353*3 + 1] = 0.0f;	val_dir[12353*3 + 2] = -0.999480f;
+ 	val_dir[12354*3 + 0] = 0.049931f;	val_dir[12354*3 + 1] = 0.016644f;	val_dir[12354*3 + 2] = -0.998614f;
+ 	val_dir[12355*3 + 0] = 0.068761f;	val_dir[12355*3 + 1] = 0.034381f;	val_dir[12355*3 + 2] = -0.997041f;
+ 	val_dir[12356*3 + 0] = 0.088806f;	val_dir[12356*3 + 1] = 0.053283f;	val_dir[12356*3 + 2] = -0.994623f;
+ 	val_dir[12357*3 + 0] = 0.110133f;	val_dir[12357*3 + 1] = 0.073422f;	val_dir[12357*3 + 2] = -0.991201f;
+ 	val_dir[12358*3 + 0] = 0.132810f;	val_dir[12358*3 + 1] = 0.094865f;	val_dir[12358*3 + 2] = -0.986591f;
+ 	val_dir[12359*3 + 0] = 0.156893f;	val_dir[12359*3 + 1] = 0.117670f;	val_dir[12359*3 + 2] = -0.980581f;
+ 	val_dir[12360*3 + 0] = 0.182424f;	val_dir[12360*3 + 1] = 0.141885f;	val_dir[12360*3 + 2] = -0.972929f;
+ 	val_dir[12361*3 + 0] = 0.209427f;	val_dir[12361*3 + 1] = 0.167542f;	val_dir[12361*3 + 2] = -0.963364f;
+ 	val_dir[12362*3 + 0] = 0.237897f;	val_dir[12362*3 + 1] = 0.194643f;	val_dir[12362*3 + 2] = -0.951588f;
+ 	val_dir[12363*3 + 0] = 0.267793f;	val_dir[12363*3 + 1] = 0.223161f;	val_dir[12363*3 + 2] = -0.937276f;
+ 	val_dir[12364*3 + 0] = 0.299028f;	val_dir[12364*3 + 1] = 0.253024f;	val_dir[12364*3 + 2] = -0.920087f;
+ 	val_dir[12365*3 + 0] = 0.331460f;	val_dir[12365*3 + 1] = 0.284108f;	val_dir[12365*3 + 2] = -0.899676f;
+ 	val_dir[12366*3 + 0] = 0.364878f;	val_dir[12366*3 + 1] = 0.316228f;	val_dir[12366*3 + 2] = -0.875708f;
+ 	val_dir[12367*3 + 0] = 0.399004f;	val_dir[12367*3 + 1] = 0.349128f;	val_dir[12367*3 + 2] = -0.847883f;
+ 	val_dir[12368*3 + 0] = 0.433482f;	val_dir[12368*3 + 1] = 0.382484f;	val_dir[12368*3 + 2] = -0.815966f;
+ 	val_dir[12369*3 + 0] = 0.467888f;	val_dir[12369*3 + 1] = 0.41590f;	val_dir[12369*3 + 2] = -0.779813f;
+ 	val_dir[12370*3 + 0] = 0.501740f;	val_dir[12370*3 + 1] = 0.448926f;	val_dir[12370*3 + 2] = -0.739407f;
+ 	val_dir[12371*3 + 0] = 0.534522f;	val_dir[12371*3 + 1] = 0.481070f;	val_dir[12371*3 + 2] = -0.694879f;
+ 	val_dir[12372*3 + 0] = 0.565711f;	val_dir[12372*3 + 1] = 0.511834f;	val_dir[12372*3 + 2] = -0.646527f;
+ 	val_dir[12373*3 + 0] = 0.594812f;	val_dir[12373*3 + 1] = 0.540738f;	val_dir[12373*3 + 2] = -0.594812f;
+ 	val_dir[12374*3 + 0] = 0.621395f;	val_dir[12374*3 + 1] = 0.567360f;	val_dir[12374*3 + 2] = -0.540343f;
+ 	val_dir[12375*3 + 0] = 0.645124f;	val_dir[12375*3 + 1] = 0.591364f;	val_dir[12375*3 + 2] = -0.483843f;
+ 	val_dir[12376*3 + 0] = 0.665780f;	val_dir[12376*3 + 1] = 0.612517f;	val_dir[12376*3 + 2] = -0.426099f;
+ 	val_dir[12377*3 + 0] = 0.683265f;	val_dir[12377*3 + 1] = 0.630706f;	val_dir[12377*3 + 2] = -0.367912f;
+ 	val_dir[12378*3 + 0] = 0.697602f;	val_dir[12378*3 + 1] = 0.645928f;	val_dir[12378*3 + 2] = -0.310045f;
+ 	val_dir[12379*3 + 0] = 0.708918f;	val_dir[12379*3 + 1] = 0.658281f;	val_dir[12379*3 + 2] = -0.253185f;
+ 	val_dir[12380*3 + 0] = 0.717418f;	val_dir[12380*3 + 1] = 0.667940f;	val_dir[12380*3 + 2] = -0.197908f;
+ 	val_dir[12381*3 + 0] = 0.723364f;	val_dir[12381*3 + 1] = 0.675140f;	val_dir[12381*3 + 2] = -0.144673f;
+ 	val_dir[12382*3 + 0] = 0.727051f;	val_dir[12382*3 + 1] = 0.680144f;	val_dir[12382*3 + 2] = -0.093813f;
+ 	val_dir[12383*3 + 0] = 0.728780f;	val_dir[12383*3 + 1] = 0.683231f;	val_dir[12383*3 + 2] = -0.045549f;
+ 	val_dir[12384*3 + 0] = 0.728848f;	val_dir[12384*3 + 1] = 0.684675f;	val_dir[12384*3 + 2] = 0.0f;
+ 	val_dir[12385*3 + 0] = -0.695620f;	val_dir[12385*3 + 1] = -0.718059f;	val_dir[12385*3 + 2] = -0.022439f;
+ 	val_dir[12386*3 + 0] = -0.693746f;	val_dir[12386*3 + 1] = -0.716871f;	val_dir[12386*3 + 2] = -0.069375f;
+ 	val_dir[12387*3 + 0] = -0.690085f;	val_dir[12387*3 + 1] = -0.713881f;	val_dir[12387*3 + 2] = -0.118980f;
+ 	val_dir[12388*3 + 0] = -0.684353f;	val_dir[12388*3 + 1] = -0.708794f;	val_dir[12388*3 + 2] = -0.171088f;
+ 	val_dir[12389*3 + 0] = -0.676269f;	val_dir[12389*3 + 1] = -0.701316f;	val_dir[12389*3 + 2] = -0.225423f;
+ 	val_dir[12390*3 + 0] = -0.665574f;	val_dir[12390*3 + 1] = -0.691173f;	val_dir[12390*3 + 2] = -0.281589f;
+ 	val_dir[12391*3 + 0] = -0.652051f;	val_dir[12391*3 + 1] = -0.678133f;	val_dir[12391*3 + 2] = -0.339066f;
+ 	val_dir[12392*3 + 0] = -0.635553f;	val_dir[12392*3 + 1] = -0.662034f;	val_dir[12392*3 + 2] = -0.397220f;
+ 	val_dir[12393*3 + 0] = -0.616022f;	val_dir[12393*3 + 1] = -0.642806f;	val_dir[12393*3 + 2] = -0.455321f;
+ 	val_dir[12394*3 + 0] = -0.593512f;	val_dir[12394*3 + 1] = -0.620490f;	val_dir[12394*3 + 2] = -0.512578f;
+ 	val_dir[12395*3 + 0] = -0.568190f;	val_dir[12395*3 + 1] = -0.595247f;	val_dir[12395*3 + 2] = -0.568190f;
+ 	val_dir[12396*3 + 0] = -0.540343f;	val_dir[12396*3 + 1] = -0.567360f;	val_dir[12396*3 + 2] = -0.621395f;
+ 	val_dir[12397*3 + 0] = -0.510355f;	val_dir[12397*3 + 1] = -0.537215f;	val_dir[12397*3 + 2] = -0.671519f;
+ 	val_dir[12398*3 + 0] = -0.478683f;	val_dir[12398*3 + 1] = -0.505276f;	val_dir[12398*3 + 2] = -0.718024f;
+ 	val_dir[12399*3 + 0] = -0.445827f;	val_dir[12399*3 + 1] = -0.472053f;	val_dir[12399*3 + 2] = -0.760529f;
+ 	val_dir[12400*3 + 0] = -0.412294f;	val_dir[12400*3 + 1] = -0.438063f;	val_dir[12400*3 + 2] = -0.798820f;
+ 	val_dir[12401*3 + 0] = -0.378566f;	val_dir[12401*3 + 1] = -0.403804f;	val_dir[12401*3 + 2] = -0.832845f;
+ 	val_dir[12402*3 + 0] = -0.345075f;	val_dir[12402*3 + 1] = -0.369723f;	val_dir[12402*3 + 2] = -0.862687f;
+ 	val_dir[12403*3 + 0] = -0.312190f;	val_dir[12403*3 + 1] = -0.336204f;	val_dir[12403*3 + 2] = -0.888540f;
+ 	val_dir[12404*3 + 0] = -0.280209f;	val_dir[12404*3 + 1] = -0.303559f;	val_dir[12404*3 + 2] = -0.910678f;
+ 	val_dir[12405*3 + 0] = -0.249357f;	val_dir[12405*3 + 1] = -0.272026f;	val_dir[12405*3 + 2] = -0.929421f;
+ 	val_dir[12406*3 + 0] = -0.219793f;	val_dir[12406*3 + 1] = -0.241773f;	val_dir[12406*3 + 2] = -0.945112f;
+ 	val_dir[12407*3 + 0] = -0.191620f;	val_dir[12407*3 + 1] = -0.212911f;	val_dir[12407*3 + 2] = -0.958098f;
+ 	val_dir[12408*3 + 0] = -0.164887f;	val_dir[12408*3 + 1] = -0.185498f;	val_dir[12408*3 + 2] = -0.968712f;
+ 	val_dir[12409*3 + 0] = -0.139610f;	val_dir[12409*3 + 1] = -0.159554f;	val_dir[12409*3 + 2] = -0.977267f;
+ 	val_dir[12410*3 + 0] = -0.115771f;	val_dir[12410*3 + 1] = -0.135066f;	val_dir[12410*3 + 2] = -0.984050f;
+ 	val_dir[12411*3 + 0] = -0.093332f;	val_dir[12411*3 + 1] = -0.111998f;	val_dir[12411*3 + 2] = -0.989316f;
+ 	val_dir[12412*3 + 0] = -0.072239f;	val_dir[12412*3 + 1] = -0.090299f;	val_dir[12412*3 + 2] = -0.993291f;
+ 	val_dir[12413*3 + 0] = -0.052430f;	val_dir[12413*3 + 1] = -0.069907f;	val_dir[12413*3 + 2] = -0.996175f;
+ 	val_dir[12414*3 + 0] = -0.033835f;	val_dir[12414*3 + 1] = -0.050753f;	val_dir[12414*3 + 2] = -0.998138f;
+ 	val_dir[12415*3 + 0] = -0.016382f;	val_dir[12415*3 + 1] = -0.032765f;	val_dir[12415*3 + 2] = -0.999329f;
+ 	val_dir[12416*3 + 0] = 0.0f;	val_dir[12416*3 + 1] = -0.015871f;	val_dir[12416*3 + 2] = -0.999874f;
+ 	val_dir[12417*3 + 0] = 0.015871f;	val_dir[12417*3 + 1] = 0.0f;	val_dir[12417*3 + 2] = -0.999874f;
+ 	val_dir[12418*3 + 0] = 0.032765f;	val_dir[12418*3 + 1] = 0.016382f;	val_dir[12418*3 + 2] = -0.999329f;
+ 	val_dir[12419*3 + 0] = 0.050753f;	val_dir[12419*3 + 1] = 0.033835f;	val_dir[12419*3 + 2] = -0.998138f;
+ 	val_dir[12420*3 + 0] = 0.069907f;	val_dir[12420*3 + 1] = 0.052430f;	val_dir[12420*3 + 2] = -0.996175f;
+ 	val_dir[12421*3 + 0] = 0.090299f;	val_dir[12421*3 + 1] = 0.072239f;	val_dir[12421*3 + 2] = -0.993291f;
+ 	val_dir[12422*3 + 0] = 0.111998f;	val_dir[12422*3 + 1] = 0.093332f;	val_dir[12422*3 + 2] = -0.989316f;
+ 	val_dir[12423*3 + 0] = 0.135066f;	val_dir[12423*3 + 1] = 0.115771f;	val_dir[12423*3 + 2] = -0.984050f;
+ 	val_dir[12424*3 + 0] = 0.159554f;	val_dir[12424*3 + 1] = 0.139610f;	val_dir[12424*3 + 2] = -0.977267f;
+ 	val_dir[12425*3 + 0] = 0.185498f;	val_dir[12425*3 + 1] = 0.164887f;	val_dir[12425*3 + 2] = -0.968712f;
+ 	val_dir[12426*3 + 0] = 0.212911f;	val_dir[12426*3 + 1] = 0.191620f;	val_dir[12426*3 + 2] = -0.958098f;
+ 	val_dir[12427*3 + 0] = 0.241773f;	val_dir[12427*3 + 1] = 0.219793f;	val_dir[12427*3 + 2] = -0.945112f;
+ 	val_dir[12428*3 + 0] = 0.272026f;	val_dir[12428*3 + 1] = 0.249357f;	val_dir[12428*3 + 2] = -0.929421f;
+ 	val_dir[12429*3 + 0] = 0.303559f;	val_dir[12429*3 + 1] = 0.280209f;	val_dir[12429*3 + 2] = -0.910678f;
+ 	val_dir[12430*3 + 0] = 0.336204f;	val_dir[12430*3 + 1] = 0.312190f;	val_dir[12430*3 + 2] = -0.888540f;
+ 	val_dir[12431*3 + 0] = 0.369723f;	val_dir[12431*3 + 1] = 0.345075f;	val_dir[12431*3 + 2] = -0.862687f;
+ 	val_dir[12432*3 + 0] = 0.403804f;	val_dir[12432*3 + 1] = 0.378566f;	val_dir[12432*3 + 2] = -0.832845f;
+ 	val_dir[12433*3 + 0] = 0.438063f;	val_dir[12433*3 + 1] = 0.412294f;	val_dir[12433*3 + 2] = -0.798820f;
+ 	val_dir[12434*3 + 0] = 0.472053f;	val_dir[12434*3 + 1] = 0.445827f;	val_dir[12434*3 + 2] = -0.760529f;
+ 	val_dir[12435*3 + 0] = 0.505276f;	val_dir[12435*3 + 1] = 0.478683f;	val_dir[12435*3 + 2] = -0.718024f;
+ 	val_dir[12436*3 + 0] = 0.537215f;	val_dir[12436*3 + 1] = 0.510355f;	val_dir[12436*3 + 2] = -0.671519f;
+ 	val_dir[12437*3 + 0] = 0.567360f;	val_dir[12437*3 + 1] = 0.540343f;	val_dir[12437*3 + 2] = -0.621395f;
+ 	val_dir[12438*3 + 0] = 0.595247f;	val_dir[12438*3 + 1] = 0.568190f;	val_dir[12438*3 + 2] = -0.568190f;
+ 	val_dir[12439*3 + 0] = 0.620490f;	val_dir[12439*3 + 1] = 0.593512f;	val_dir[12439*3 + 2] = -0.512578f;
+ 	val_dir[12440*3 + 0] = 0.642806f;	val_dir[12440*3 + 1] = 0.616022f;	val_dir[12440*3 + 2] = -0.455321f;
+ 	val_dir[12441*3 + 0] = 0.662034f;	val_dir[12441*3 + 1] = 0.635553f;	val_dir[12441*3 + 2] = -0.397220f;
+ 	val_dir[12442*3 + 0] = 0.678133f;	val_dir[12442*3 + 1] = 0.652051f;	val_dir[12442*3 + 2] = -0.339066f;
+ 	val_dir[12443*3 + 0] = 0.691173f;	val_dir[12443*3 + 1] = 0.665574f;	val_dir[12443*3 + 2] = -0.281589f;
+ 	val_dir[12444*3 + 0] = 0.701316f;	val_dir[12444*3 + 1] = 0.676269f;	val_dir[12444*3 + 2] = -0.225423f;
+ 	val_dir[12445*3 + 0] = 0.708794f;	val_dir[12445*3 + 1] = 0.684353f;	val_dir[12445*3 + 2] = -0.171088f;
+ 	val_dir[12446*3 + 0] = 0.713881f;	val_dir[12446*3 + 1] = 0.690085f;	val_dir[12446*3 + 2] = -0.118980f;
+ 	val_dir[12447*3 + 0] = 0.716871f;	val_dir[12447*3 + 1] = 0.693746f;	val_dir[12447*3 + 2] = -0.069375f;
+ 	val_dir[12448*3 + 0] = 0.718059f;	val_dir[12448*3 + 1] = 0.695620f;	val_dir[12448*3 + 2] = -0.022439f;
+ 	val_dir[12449*3 + 0] = -0.707107f;	val_dir[12449*3 + 1] = -0.707107f;	val_dir[12449*3 + 2] = 0.0f;
+ 	val_dir[12450*3 + 0] = -0.706372f;	val_dir[12450*3 + 1] = -0.706372f;	val_dir[12450*3 + 2] = -0.045572f;
+ 	val_dir[12451*3 + 0] = -0.703985f;	val_dir[12451*3 + 1] = -0.703985f;	val_dir[12451*3 + 2] = -0.093865f;
+ 	val_dir[12452*3 + 0] = -0.699659f;	val_dir[12452*3 + 1] = -0.699659f;	val_dir[12452*3 + 2] = -0.144757f;
+ 	val_dir[12453*3 + 0] = -0.693103f;	val_dir[12453*3 + 1] = -0.693103f;	val_dir[12453*3 + 2] = -0.198030f;
+ 	val_dir[12454*3 + 0] = -0.684038f;	val_dir[12454*3 + 1] = -0.684038f;	val_dir[12454*3 + 2] = -0.253347f;
+ 	val_dir[12455*3 + 0] = -0.672214f;	val_dir[12455*3 + 1] = -0.672214f;	val_dir[12455*3 + 2] = -0.310253f;
+ 	val_dir[12456*3 + 0] = -0.657440f;	val_dir[12456*3 + 1] = -0.657440f;	val_dir[12456*3 + 2] = -0.368166f;
+ 	val_dir[12457*3 + 0] = -0.639602f;	val_dir[12457*3 + 1] = -0.639602f;	val_dir[12457*3 + 2] = -0.426401f;
+ 	val_dir[12458*3 + 0] = -0.618691f;	val_dir[12458*3 + 1] = -0.618691f;	val_dir[12458*3 + 2] = -0.484193f;
+ 	val_dir[12459*3 + 0] = -0.594812f;	val_dir[12459*3 + 1] = -0.594812f;	val_dir[12459*3 + 2] = -0.540738f;
+ 	val_dir[12460*3 + 0] = -0.568190f;	val_dir[12460*3 + 1] = -0.568190f;	val_dir[12460*3 + 2] = -0.595247f;
+ 	val_dir[12461*3 + 0] = -0.539164f;	val_dir[12461*3 + 1] = -0.539164f;	val_dir[12461*3 + 2] = -0.646997f;
+ 	val_dir[12462*3 + 0] = -0.508159f;	val_dir[12462*3 + 1] = -0.508159f;	val_dir[12462*3 + 2] = -0.695376f;
+ 	val_dir[12463*3 + 0] = -0.475665f;	val_dir[12463*3 + 1] = -0.475665f;	val_dir[12463*3 + 2] = -0.739923f;
+ 	val_dir[12464*3 + 0] = -0.442193f;	val_dir[12464*3 + 1] = -0.442193f;	val_dir[12464*3 + 2] = -0.780340f;
+ 	val_dir[12465*3 + 0] = -0.408248f;	val_dir[12465*3 + 1] = -0.408248f;	val_dir[12465*3 + 2] = -0.816497f;
+ 	val_dir[12466*3 + 0] = -0.374299f;	val_dir[12466*3 + 1] = -0.374299f;	val_dir[12466*3 + 2] = -0.848411f;
+ 	val_dir[12467*3 + 0] = -0.340755f;	val_dir[12467*3 + 1] = -0.340755f;	val_dir[12467*3 + 2] = -0.876226f;
+ 	val_dir[12468*3 + 0] = -0.307957f;	val_dir[12468*3 + 1] = -0.307957f;	val_dir[12468*3 + 2] = -0.900181f;
+ 	val_dir[12469*3 + 0] = -0.276172f;	val_dir[12469*3 + 1] = -0.276172f;	val_dir[12469*3 + 2] = -0.920575f;
+ 	val_dir[12470*3 + 0] = -0.245599f;	val_dir[12470*3 + 1] = -0.245599f;	val_dir[12470*3 + 2] = -0.937743f;
+ 	val_dir[12471*3 + 0] = -0.216371f;	val_dir[12471*3 + 1] = -0.216371f;	val_dir[12471*3 + 2] = -0.952033f;
+ 	val_dir[12472*3 + 0] = -0.188567f;	val_dir[12472*3 + 1] = -0.188567f;	val_dir[12472*3 + 2] = -0.963787f;
+ 	val_dir[12473*3 + 0] = -0.162221f;	val_dir[12473*3 + 1] = -0.162221f;	val_dir[12473*3 + 2] = -0.973329f;
+ 	val_dir[12474*3 + 0] = -0.137334f;	val_dir[12474*3 + 1] = -0.137334f;	val_dir[12474*3 + 2] = -0.980958f;
+ 	val_dir[12475*3 + 0] = -0.113878f;	val_dir[12475*3 + 1] = -0.113878f;	val_dir[12475*3 + 2] = -0.986947f;
+ 	val_dir[12476*3 + 0] = -0.091809f;	val_dir[12476*3 + 1] = -0.091809f;	val_dir[12476*3 + 2] = -0.991535f;
+ 	val_dir[12477*3 + 0] = -0.071067f;	val_dir[12477*3 + 1] = -0.071067f;	val_dir[12477*3 + 2] = -0.994937f;
+ 	val_dir[12478*3 + 0] = -0.051586f;	val_dir[12478*3 + 1] = -0.051586f;	val_dir[12478*3 + 2] = -0.997335f;
+ 	val_dir[12479*3 + 0] = -0.033296f;	val_dir[12479*3 + 1] = -0.033296f;	val_dir[12479*3 + 2] = -0.998891f;
+ 	val_dir[12480*3 + 0] = -0.016125f;	val_dir[12480*3 + 1] = -0.016125f;	val_dir[12480*3 + 2] = -0.999740f;
+ 	val_dir[12481*3 + 0] = 0.0f;	val_dir[12481*3 + 1] = 0.0f;	val_dir[12481*3 + 2] = -1.0f;
+ 	val_dir[12482*3 + 0] = 0.016125f;	val_dir[12482*3 + 1] = 0.016125f;	val_dir[12482*3 + 2] = -0.999740f;
+ 	val_dir[12483*3 + 0] = 0.033296f;	val_dir[12483*3 + 1] = 0.033296f;	val_dir[12483*3 + 2] = -0.998891f;
+ 	val_dir[12484*3 + 0] = 0.051586f;	val_dir[12484*3 + 1] = 0.051586f;	val_dir[12484*3 + 2] = -0.997335f;
+ 	val_dir[12485*3 + 0] = 0.071067f;	val_dir[12485*3 + 1] = 0.071067f;	val_dir[12485*3 + 2] = -0.994937f;
+ 	val_dir[12486*3 + 0] = 0.091809f;	val_dir[12486*3 + 1] = 0.091809f;	val_dir[12486*3 + 2] = -0.991535f;
+ 	val_dir[12487*3 + 0] = 0.113878f;	val_dir[12487*3 + 1] = 0.113878f;	val_dir[12487*3 + 2] = -0.986947f;
+ 	val_dir[12488*3 + 0] = 0.137334f;	val_dir[12488*3 + 1] = 0.137334f;	val_dir[12488*3 + 2] = -0.980958f;
+ 	val_dir[12489*3 + 0] = 0.162221f;	val_dir[12489*3 + 1] = 0.162221f;	val_dir[12489*3 + 2] = -0.973329f;
+ 	val_dir[12490*3 + 0] = 0.188567f;	val_dir[12490*3 + 1] = 0.188567f;	val_dir[12490*3 + 2] = -0.963787f;
+ 	val_dir[12491*3 + 0] = 0.216371f;	val_dir[12491*3 + 1] = 0.216371f;	val_dir[12491*3 + 2] = -0.952033f;
+ 	val_dir[12492*3 + 0] = 0.245599f;	val_dir[12492*3 + 1] = 0.245599f;	val_dir[12492*3 + 2] = -0.937743f;
+ 	val_dir[12493*3 + 0] = 0.276172f;	val_dir[12493*3 + 1] = 0.276172f;	val_dir[12493*3 + 2] = -0.920575f;
+ 	val_dir[12494*3 + 0] = 0.307957f;	val_dir[12494*3 + 1] = 0.307957f;	val_dir[12494*3 + 2] = -0.900181f;
+ 	val_dir[12495*3 + 0] = 0.340755f;	val_dir[12495*3 + 1] = 0.340755f;	val_dir[12495*3 + 2] = -0.876226f;
+ 	val_dir[12496*3 + 0] = 0.374299f;	val_dir[12496*3 + 1] = 0.374299f;	val_dir[12496*3 + 2] = -0.848411f;
+ 	val_dir[12497*3 + 0] = 0.408248f;	val_dir[12497*3 + 1] = 0.408248f;	val_dir[12497*3 + 2] = -0.816497f;
+ 	val_dir[12498*3 + 0] = 0.442193f;	val_dir[12498*3 + 1] = 0.442193f;	val_dir[12498*3 + 2] = -0.780340f;
+ 	val_dir[12499*3 + 0] = 0.475665f;	val_dir[12499*3 + 1] = 0.475665f;	val_dir[12499*3 + 2] = -0.739923f;
+ 	val_dir[12500*3 + 0] = 0.508159f;	val_dir[12500*3 + 1] = 0.508159f;	val_dir[12500*3 + 2] = -0.695376f;
+ 	val_dir[12501*3 + 0] = 0.539164f;	val_dir[12501*3 + 1] = 0.539164f;	val_dir[12501*3 + 2] = -0.646997f;
+ 	val_dir[12502*3 + 0] = 0.568190f;	val_dir[12502*3 + 1] = 0.568190f;	val_dir[12502*3 + 2] = -0.595247f;
+ 	val_dir[12503*3 + 0] = 0.594812f;	val_dir[12503*3 + 1] = 0.594812f;	val_dir[12503*3 + 2] = -0.540738f;
+ 	val_dir[12504*3 + 0] = 0.618691f;	val_dir[12504*3 + 1] = 0.618691f;	val_dir[12504*3 + 2] = -0.484193f;
+ 	val_dir[12505*3 + 0] = 0.639602f;	val_dir[12505*3 + 1] = 0.639602f;	val_dir[12505*3 + 2] = -0.426401f;
+ 	val_dir[12506*3 + 0] = 0.657440f;	val_dir[12506*3 + 1] = 0.657440f;	val_dir[12506*3 + 2] = -0.368166f;
+ 	val_dir[12507*3 + 0] = 0.672214f;	val_dir[12507*3 + 1] = 0.672214f;	val_dir[12507*3 + 2] = -0.310253f;
+ 	val_dir[12508*3 + 0] = 0.684038f;	val_dir[12508*3 + 1] = 0.684038f;	val_dir[12508*3 + 2] = -0.253347f;
+ 	val_dir[12509*3 + 0] = 0.693103f;	val_dir[12509*3 + 1] = 0.693103f;	val_dir[12509*3 + 2] = -0.198030f;
+ 	val_dir[12510*3 + 0] = 0.699659f;	val_dir[12510*3 + 1] = 0.699659f;	val_dir[12510*3 + 2] = -0.144757f;
+ 	val_dir[12511*3 + 0] = 0.703985f;	val_dir[12511*3 + 1] = 0.703985f;	val_dir[12511*3 + 2] = -0.093865f;
+ 	val_dir[12512*3 + 0] = 0.706372f;	val_dir[12512*3 + 1] = 0.706372f;	val_dir[12512*3 + 2] = -0.045572f;
+ 	val_dir[12513*3 + 0] = 0.707107f;	val_dir[12513*3 + 1] = 0.707107f;	val_dir[12513*3 + 2] = 0.0f;
+ 	val_dir[12514*3 + 0] = -0.718059f;	val_dir[12514*3 + 1] = -0.695620f;	val_dir[12514*3 + 2] = -0.022439f;
+ 	val_dir[12515*3 + 0] = -0.716871f;	val_dir[12515*3 + 1] = -0.693746f;	val_dir[12515*3 + 2] = -0.069375f;
+ 	val_dir[12516*3 + 0] = -0.713881f;	val_dir[12516*3 + 1] = -0.690085f;	val_dir[12516*3 + 2] = -0.118980f;
+ 	val_dir[12517*3 + 0] = -0.708794f;	val_dir[12517*3 + 1] = -0.684353f;	val_dir[12517*3 + 2] = -0.171088f;
+ 	val_dir[12518*3 + 0] = -0.701316f;	val_dir[12518*3 + 1] = -0.676269f;	val_dir[12518*3 + 2] = -0.225423f;
+ 	val_dir[12519*3 + 0] = -0.691173f;	val_dir[12519*3 + 1] = -0.665574f;	val_dir[12519*3 + 2] = -0.281589f;
+ 	val_dir[12520*3 + 0] = -0.678133f;	val_dir[12520*3 + 1] = -0.652051f;	val_dir[12520*3 + 2] = -0.339066f;
+ 	val_dir[12521*3 + 0] = -0.662034f;	val_dir[12521*3 + 1] = -0.635553f;	val_dir[12521*3 + 2] = -0.397220f;
+ 	val_dir[12522*3 + 0] = -0.642806f;	val_dir[12522*3 + 1] = -0.616022f;	val_dir[12522*3 + 2] = -0.455321f;
+ 	val_dir[12523*3 + 0] = -0.620490f;	val_dir[12523*3 + 1] = -0.593512f;	val_dir[12523*3 + 2] = -0.512578f;
+ 	val_dir[12524*3 + 0] = -0.595247f;	val_dir[12524*3 + 1] = -0.568190f;	val_dir[12524*3 + 2] = -0.568190f;
+ 	val_dir[12525*3 + 0] = -0.567360f;	val_dir[12525*3 + 1] = -0.540343f;	val_dir[12525*3 + 2] = -0.621395f;
+ 	val_dir[12526*3 + 0] = -0.537215f;	val_dir[12526*3 + 1] = -0.510355f;	val_dir[12526*3 + 2] = -0.671519f;
+ 	val_dir[12527*3 + 0] = -0.505276f;	val_dir[12527*3 + 1] = -0.478683f;	val_dir[12527*3 + 2] = -0.718024f;
+ 	val_dir[12528*3 + 0] = -0.472053f;	val_dir[12528*3 + 1] = -0.445827f;	val_dir[12528*3 + 2] = -0.760529f;
+ 	val_dir[12529*3 + 0] = -0.438063f;	val_dir[12529*3 + 1] = -0.412294f;	val_dir[12529*3 + 2] = -0.798820f;
+ 	val_dir[12530*3 + 0] = -0.403804f;	val_dir[12530*3 + 1] = -0.378566f;	val_dir[12530*3 + 2] = -0.832845f;
+ 	val_dir[12531*3 + 0] = -0.369723f;	val_dir[12531*3 + 1] = -0.345075f;	val_dir[12531*3 + 2] = -0.862687f;
+ 	val_dir[12532*3 + 0] = -0.336204f;	val_dir[12532*3 + 1] = -0.312190f;	val_dir[12532*3 + 2] = -0.888540f;
+ 	val_dir[12533*3 + 0] = -0.303559f;	val_dir[12533*3 + 1] = -0.280209f;	val_dir[12533*3 + 2] = -0.910678f;
+ 	val_dir[12534*3 + 0] = -0.272026f;	val_dir[12534*3 + 1] = -0.249357f;	val_dir[12534*3 + 2] = -0.929421f;
+ 	val_dir[12535*3 + 0] = -0.241773f;	val_dir[12535*3 + 1] = -0.219793f;	val_dir[12535*3 + 2] = -0.945112f;
+ 	val_dir[12536*3 + 0] = -0.212911f;	val_dir[12536*3 + 1] = -0.191620f;	val_dir[12536*3 + 2] = -0.958098f;
+ 	val_dir[12537*3 + 0] = -0.185498f;	val_dir[12537*3 + 1] = -0.164887f;	val_dir[12537*3 + 2] = -0.968712f;
+ 	val_dir[12538*3 + 0] = -0.159554f;	val_dir[12538*3 + 1] = -0.139610f;	val_dir[12538*3 + 2] = -0.977267f;
+ 	val_dir[12539*3 + 0] = -0.135066f;	val_dir[12539*3 + 1] = -0.115771f;	val_dir[12539*3 + 2] = -0.984050f;
+ 	val_dir[12540*3 + 0] = -0.111998f;	val_dir[12540*3 + 1] = -0.093332f;	val_dir[12540*3 + 2] = -0.989316f;
+ 	val_dir[12541*3 + 0] = -0.090299f;	val_dir[12541*3 + 1] = -0.072239f;	val_dir[12541*3 + 2] = -0.993291f;
+ 	val_dir[12542*3 + 0] = -0.069907f;	val_dir[12542*3 + 1] = -0.052430f;	val_dir[12542*3 + 2] = -0.996175f;
+ 	val_dir[12543*3 + 0] = -0.050753f;	val_dir[12543*3 + 1] = -0.033835f;	val_dir[12543*3 + 2] = -0.998138f;
+ 	val_dir[12544*3 + 0] = -0.032765f;	val_dir[12544*3 + 1] = -0.016382f;	val_dir[12544*3 + 2] = -0.999329f;
+ 	val_dir[12545*3 + 0] = -0.015871f;	val_dir[12545*3 + 1] = 0.0f;	val_dir[12545*3 + 2] = -0.999874f;
+ 	val_dir[12546*3 + 0] = 0.0f;	val_dir[12546*3 + 1] = 0.015871f;	val_dir[12546*3 + 2] = -0.999874f;
+ 	val_dir[12547*3 + 0] = 0.016382f;	val_dir[12547*3 + 1] = 0.032765f;	val_dir[12547*3 + 2] = -0.999329f;
+ 	val_dir[12548*3 + 0] = 0.033835f;	val_dir[12548*3 + 1] = 0.050753f;	val_dir[12548*3 + 2] = -0.998138f;
+ 	val_dir[12549*3 + 0] = 0.052430f;	val_dir[12549*3 + 1] = 0.069907f;	val_dir[12549*3 + 2] = -0.996175f;
+ 	val_dir[12550*3 + 0] = 0.072239f;	val_dir[12550*3 + 1] = 0.090299f;	val_dir[12550*3 + 2] = -0.993291f;
+ 	val_dir[12551*3 + 0] = 0.093332f;	val_dir[12551*3 + 1] = 0.111998f;	val_dir[12551*3 + 2] = -0.989316f;
+ 	val_dir[12552*3 + 0] = 0.115771f;	val_dir[12552*3 + 1] = 0.135066f;	val_dir[12552*3 + 2] = -0.984050f;
+ 	val_dir[12553*3 + 0] = 0.139610f;	val_dir[12553*3 + 1] = 0.159554f;	val_dir[12553*3 + 2] = -0.977267f;
+ 	val_dir[12554*3 + 0] = 0.164887f;	val_dir[12554*3 + 1] = 0.185498f;	val_dir[12554*3 + 2] = -0.968712f;
+ 	val_dir[12555*3 + 0] = 0.191620f;	val_dir[12555*3 + 1] = 0.212911f;	val_dir[12555*3 + 2] = -0.958098f;
+ 	val_dir[12556*3 + 0] = 0.219793f;	val_dir[12556*3 + 1] = 0.241773f;	val_dir[12556*3 + 2] = -0.945112f;
+ 	val_dir[12557*3 + 0] = 0.249357f;	val_dir[12557*3 + 1] = 0.272026f;	val_dir[12557*3 + 2] = -0.929421f;
+ 	val_dir[12558*3 + 0] = 0.280209f;	val_dir[12558*3 + 1] = 0.303559f;	val_dir[12558*3 + 2] = -0.910678f;
+ 	val_dir[12559*3 + 0] = 0.312190f;	val_dir[12559*3 + 1] = 0.336204f;	val_dir[12559*3 + 2] = -0.888540f;
+ 	val_dir[12560*3 + 0] = 0.345075f;	val_dir[12560*3 + 1] = 0.369723f;	val_dir[12560*3 + 2] = -0.862687f;
+ 	val_dir[12561*3 + 0] = 0.378566f;	val_dir[12561*3 + 1] = 0.403804f;	val_dir[12561*3 + 2] = -0.832845f;
+ 	val_dir[12562*3 + 0] = 0.412294f;	val_dir[12562*3 + 1] = 0.438063f;	val_dir[12562*3 + 2] = -0.798820f;
+ 	val_dir[12563*3 + 0] = 0.445827f;	val_dir[12563*3 + 1] = 0.472053f;	val_dir[12563*3 + 2] = -0.760529f;
+ 	val_dir[12564*3 + 0] = 0.478683f;	val_dir[12564*3 + 1] = 0.505276f;	val_dir[12564*3 + 2] = -0.718024f;
+ 	val_dir[12565*3 + 0] = 0.510355f;	val_dir[12565*3 + 1] = 0.537215f;	val_dir[12565*3 + 2] = -0.671519f;
+ 	val_dir[12566*3 + 0] = 0.540343f;	val_dir[12566*3 + 1] = 0.567360f;	val_dir[12566*3 + 2] = -0.621395f;
+ 	val_dir[12567*3 + 0] = 0.568190f;	val_dir[12567*3 + 1] = 0.595247f;	val_dir[12567*3 + 2] = -0.568190f;
+ 	val_dir[12568*3 + 0] = 0.593512f;	val_dir[12568*3 + 1] = 0.620490f;	val_dir[12568*3 + 2] = -0.512578f;
+ 	val_dir[12569*3 + 0] = 0.616022f;	val_dir[12569*3 + 1] = 0.642806f;	val_dir[12569*3 + 2] = -0.455321f;
+ 	val_dir[12570*3 + 0] = 0.635553f;	val_dir[12570*3 + 1] = 0.662034f;	val_dir[12570*3 + 2] = -0.397220f;
+ 	val_dir[12571*3 + 0] = 0.652051f;	val_dir[12571*3 + 1] = 0.678133f;	val_dir[12571*3 + 2] = -0.339066f;
+ 	val_dir[12572*3 + 0] = 0.665574f;	val_dir[12572*3 + 1] = 0.691173f;	val_dir[12572*3 + 2] = -0.281589f;
+ 	val_dir[12573*3 + 0] = 0.676269f;	val_dir[12573*3 + 1] = 0.701316f;	val_dir[12573*3 + 2] = -0.225423f;
+ 	val_dir[12574*3 + 0] = 0.684353f;	val_dir[12574*3 + 1] = 0.708794f;	val_dir[12574*3 + 2] = -0.171088f;
+ 	val_dir[12575*3 + 0] = 0.690085f;	val_dir[12575*3 + 1] = 0.713881f;	val_dir[12575*3 + 2] = -0.118980f;
+ 	val_dir[12576*3 + 0] = 0.693746f;	val_dir[12576*3 + 1] = 0.716871f;	val_dir[12576*3 + 2] = -0.069375f;
+ 	val_dir[12577*3 + 0] = 0.695620f;	val_dir[12577*3 + 1] = 0.718059f;	val_dir[12577*3 + 2] = -0.022439f;
+ 	val_dir[12578*3 + 0] = -0.728848f;	val_dir[12578*3 + 1] = -0.684675f;	val_dir[12578*3 + 2] = 0.0f;
+ 	val_dir[12579*3 + 0] = -0.728780f;	val_dir[12579*3 + 1] = -0.683231f;	val_dir[12579*3 + 2] = -0.045549f;
+ 	val_dir[12580*3 + 0] = -0.727051f;	val_dir[12580*3 + 1] = -0.680144f;	val_dir[12580*3 + 2] = -0.093813f;
+ 	val_dir[12581*3 + 0] = -0.723364f;	val_dir[12581*3 + 1] = -0.675140f;	val_dir[12581*3 + 2] = -0.144673f;
+ 	val_dir[12582*3 + 0] = -0.717418f;	val_dir[12582*3 + 1] = -0.667940f;	val_dir[12582*3 + 2] = -0.197908f;
+ 	val_dir[12583*3 + 0] = -0.708918f;	val_dir[12583*3 + 1] = -0.658281f;	val_dir[12583*3 + 2] = -0.253185f;
+ 	val_dir[12584*3 + 0] = -0.697602f;	val_dir[12584*3 + 1] = -0.645928f;	val_dir[12584*3 + 2] = -0.310045f;
+ 	val_dir[12585*3 + 0] = -0.683265f;	val_dir[12585*3 + 1] = -0.630706f;	val_dir[12585*3 + 2] = -0.367912f;
+ 	val_dir[12586*3 + 0] = -0.665780f;	val_dir[12586*3 + 1] = -0.612517f;	val_dir[12586*3 + 2] = -0.426099f;
+ 	val_dir[12587*3 + 0] = -0.645124f;	val_dir[12587*3 + 1] = -0.591364f;	val_dir[12587*3 + 2] = -0.483843f;
+ 	val_dir[12588*3 + 0] = -0.621395f;	val_dir[12588*3 + 1] = -0.567360f;	val_dir[12588*3 + 2] = -0.540343f;
+ 	val_dir[12589*3 + 0] = -0.594812f;	val_dir[12589*3 + 1] = -0.540738f;	val_dir[12589*3 + 2] = -0.594812f;
+ 	val_dir[12590*3 + 0] = -0.565711f;	val_dir[12590*3 + 1] = -0.511834f;	val_dir[12590*3 + 2] = -0.646527f;
+ 	val_dir[12591*3 + 0] = -0.534522f;	val_dir[12591*3 + 1] = -0.481070f;	val_dir[12591*3 + 2] = -0.694879f;
+ 	val_dir[12592*3 + 0] = -0.501740f;	val_dir[12592*3 + 1] = -0.448926f;	val_dir[12592*3 + 2] = -0.739407f;
+ 	val_dir[12593*3 + 0] = -0.467888f;	val_dir[12593*3 + 1] = -0.41590f;	val_dir[12593*3 + 2] = -0.779813f;
+ 	val_dir[12594*3 + 0] = -0.433482f;	val_dir[12594*3 + 1] = -0.382484f;	val_dir[12594*3 + 2] = -0.815966f;
+ 	val_dir[12595*3 + 0] = -0.399004f;	val_dir[12595*3 + 1] = -0.349128f;	val_dir[12595*3 + 2] = -0.847883f;
+ 	val_dir[12596*3 + 0] = -0.364878f;	val_dir[12596*3 + 1] = -0.316228f;	val_dir[12596*3 + 2] = -0.875708f;
+ 	val_dir[12597*3 + 0] = -0.331460f;	val_dir[12597*3 + 1] = -0.284108f;	val_dir[12597*3 + 2] = -0.899676f;
+ 	val_dir[12598*3 + 0] = -0.299028f;	val_dir[12598*3 + 1] = -0.253024f;	val_dir[12598*3 + 2] = -0.920087f;
+ 	val_dir[12599*3 + 0] = -0.267793f;	val_dir[12599*3 + 1] = -0.223161f;	val_dir[12599*3 + 2] = -0.937276f;
+ 	val_dir[12600*3 + 0] = -0.237897f;	val_dir[12600*3 + 1] = -0.194643f;	val_dir[12600*3 + 2] = -0.951588f;
+ 	val_dir[12601*3 + 0] = -0.209427f;	val_dir[12601*3 + 1] = -0.167542f;	val_dir[12601*3 + 2] = -0.963364f;
+ 	val_dir[12602*3 + 0] = -0.182424f;	val_dir[12602*3 + 1] = -0.141885f;	val_dir[12602*3 + 2] = -0.972929f;
+ 	val_dir[12603*3 + 0] = -0.156893f;	val_dir[12603*3 + 1] = -0.117670f;	val_dir[12603*3 + 2] = -0.980581f;
+ 	val_dir[12604*3 + 0] = -0.132810f;	val_dir[12604*3 + 1] = -0.094865f;	val_dir[12604*3 + 2] = -0.986591f;
+ 	val_dir[12605*3 + 0] = -0.110133f;	val_dir[12605*3 + 1] = -0.073422f;	val_dir[12605*3 + 2] = -0.991201f;
+ 	val_dir[12606*3 + 0] = -0.088806f;	val_dir[12606*3 + 1] = -0.053283f;	val_dir[12606*3 + 2] = -0.994623f;
+ 	val_dir[12607*3 + 0] = -0.068761f;	val_dir[12607*3 + 1] = -0.034381f;	val_dir[12607*3 + 2] = -0.997041f;
+ 	val_dir[12608*3 + 0] = -0.049931f;	val_dir[12608*3 + 1] = -0.016644f;	val_dir[12608*3 + 2] = -0.998614f;
+ 	val_dir[12609*3 + 0] = -0.032241f;	val_dir[12609*3 + 1] = 0.0f;	val_dir[12609*3 + 2] = -0.999480f;
+ 	val_dir[12610*3 + 0] = -0.016125f;	val_dir[12610*3 + 1] = 0.016125f;	val_dir[12610*3 + 2] = -0.999740f;
+ 	val_dir[12611*3 + 0] = 0.0f;	val_dir[12611*3 + 1] = 0.032241f;	val_dir[12611*3 + 2] = -0.999480f;
+ 	val_dir[12612*3 + 0] = 0.016644f;	val_dir[12612*3 + 1] = 0.049931f;	val_dir[12612*3 + 2] = -0.998614f;
+ 	val_dir[12613*3 + 0] = 0.034381f;	val_dir[12613*3 + 1] = 0.068761f;	val_dir[12613*3 + 2] = -0.997041f;
+ 	val_dir[12614*3 + 0] = 0.053283f;	val_dir[12614*3 + 1] = 0.088806f;	val_dir[12614*3 + 2] = -0.994623f;
+ 	val_dir[12615*3 + 0] = 0.073422f;	val_dir[12615*3 + 1] = 0.110133f;	val_dir[12615*3 + 2] = -0.991201f;
+ 	val_dir[12616*3 + 0] = 0.094865f;	val_dir[12616*3 + 1] = 0.132810f;	val_dir[12616*3 + 2] = -0.986591f;
+ 	val_dir[12617*3 + 0] = 0.117670f;	val_dir[12617*3 + 1] = 0.156893f;	val_dir[12617*3 + 2] = -0.980581f;
+ 	val_dir[12618*3 + 0] = 0.141885f;	val_dir[12618*3 + 1] = 0.182424f;	val_dir[12618*3 + 2] = -0.972929f;
+ 	val_dir[12619*3 + 0] = 0.167542f;	val_dir[12619*3 + 1] = 0.209427f;	val_dir[12619*3 + 2] = -0.963364f;
+ 	val_dir[12620*3 + 0] = 0.194643f;	val_dir[12620*3 + 1] = 0.237897f;	val_dir[12620*3 + 2] = -0.951588f;
+ 	val_dir[12621*3 + 0] = 0.223161f;	val_dir[12621*3 + 1] = 0.267793f;	val_dir[12621*3 + 2] = -0.937276f;
+ 	val_dir[12622*3 + 0] = 0.253024f;	val_dir[12622*3 + 1] = 0.299028f;	val_dir[12622*3 + 2] = -0.920087f;
+ 	val_dir[12623*3 + 0] = 0.284108f;	val_dir[12623*3 + 1] = 0.331460f;	val_dir[12623*3 + 2] = -0.899676f;
+ 	val_dir[12624*3 + 0] = 0.316228f;	val_dir[12624*3 + 1] = 0.364878f;	val_dir[12624*3 + 2] = -0.875708f;
+ 	val_dir[12625*3 + 0] = 0.349128f;	val_dir[12625*3 + 1] = 0.399004f;	val_dir[12625*3 + 2] = -0.847883f;
+ 	val_dir[12626*3 + 0] = 0.382484f;	val_dir[12626*3 + 1] = 0.433482f;	val_dir[12626*3 + 2] = -0.815966f;
+ 	val_dir[12627*3 + 0] = 0.41590f;	val_dir[12627*3 + 1] = 0.467888f;	val_dir[12627*3 + 2] = -0.779813f;
+ 	val_dir[12628*3 + 0] = 0.448926f;	val_dir[12628*3 + 1] = 0.501740f;	val_dir[12628*3 + 2] = -0.739407f;
+ 	val_dir[12629*3 + 0] = 0.481070f;	val_dir[12629*3 + 1] = 0.534522f;	val_dir[12629*3 + 2] = -0.694879f;
+ 	val_dir[12630*3 + 0] = 0.511834f;	val_dir[12630*3 + 1] = 0.565711f;	val_dir[12630*3 + 2] = -0.646527f;
+ 	val_dir[12631*3 + 0] = 0.540738f;	val_dir[12631*3 + 1] = 0.594812f;	val_dir[12631*3 + 2] = -0.594812f;
+ 	val_dir[12632*3 + 0] = 0.567360f;	val_dir[12632*3 + 1] = 0.621395f;	val_dir[12632*3 + 2] = -0.540343f;
+ 	val_dir[12633*3 + 0] = 0.591364f;	val_dir[12633*3 + 1] = 0.645124f;	val_dir[12633*3 + 2] = -0.483843f;
+ 	val_dir[12634*3 + 0] = 0.612517f;	val_dir[12634*3 + 1] = 0.665780f;	val_dir[12634*3 + 2] = -0.426099f;
+ 	val_dir[12635*3 + 0] = 0.630706f;	val_dir[12635*3 + 1] = 0.683265f;	val_dir[12635*3 + 2] = -0.367912f;
+ 	val_dir[12636*3 + 0] = 0.645928f;	val_dir[12636*3 + 1] = 0.697602f;	val_dir[12636*3 + 2] = -0.310045f;
+ 	val_dir[12637*3 + 0] = 0.658281f;	val_dir[12637*3 + 1] = 0.708918f;	val_dir[12637*3 + 2] = -0.253185f;
+ 	val_dir[12638*3 + 0] = 0.667940f;	val_dir[12638*3 + 1] = 0.717418f;	val_dir[12638*3 + 2] = -0.197908f;
+ 	val_dir[12639*3 + 0] = 0.675140f;	val_dir[12639*3 + 1] = 0.723364f;	val_dir[12639*3 + 2] = -0.144673f;
+ 	val_dir[12640*3 + 0] = 0.680144f;	val_dir[12640*3 + 1] = 0.727051f;	val_dir[12640*3 + 2] = -0.093813f;
+ 	val_dir[12641*3 + 0] = 0.683231f;	val_dir[12641*3 + 1] = 0.728780f;	val_dir[12641*3 + 2] = -0.045549f;
+ 	val_dir[12642*3 + 0] = 0.684675f;	val_dir[12642*3 + 1] = 0.728848f;	val_dir[12642*3 + 2] = 0.0f;
+ 	val_dir[12643*3 + 0] = -0.739754f;	val_dir[12643*3 + 1] = -0.672504f;	val_dir[12643*3 + 2] = -0.022417f;
+ 	val_dir[12644*3 + 0] = -0.739205f;	val_dir[12644*3 + 1] = -0.669905f;	val_dir[12644*3 + 2] = -0.069301f;
+ 	val_dir[12645*3 + 0] = -0.736843f;	val_dir[12645*3 + 1] = -0.665536f;	val_dir[12645*3 + 2] = -0.118846f;
+ 	val_dir[12646*3 + 0] = -0.732361f;	val_dir[12646*3 + 1] = -0.659125f;	val_dir[12646*3 + 2] = -0.170884f;
+ 	val_dir[12647*3 + 0] = -0.725454f;	val_dir[12647*3 + 1] = -0.650407f;	val_dir[12647*3 + 2] = -0.225141f;
+ 	val_dir[12648*3 + 0] = -0.715834f;	val_dir[12648*3 + 1] = -0.639138f;	val_dir[12648*3 + 2] = -0.281220f;
+ 	val_dir[12649*3 + 0] = -0.703259f;	val_dir[12649*3 + 1] = -0.625119f;	val_dir[12649*3 + 2] = -0.338606f;
+ 	val_dir[12650*3 + 0] = -0.687552f;	val_dir[12650*3 + 1] = -0.608219f;	val_dir[12650*3 + 2] = -0.396664f;
+ 	val_dir[12651*3 + 0] = -0.668631f;	val_dir[12651*3 + 1] = -0.588395f;	val_dir[12651*3 + 2] = -0.454669f;
+ 	val_dir[12652*3 + 0] = -0.646527f;	val_dir[12652*3 + 1] = -0.565711f;	val_dir[12652*3 + 2] = -0.511834f;
+ 	val_dir[12653*3 + 0] = -0.621395f;	val_dir[12653*3 + 1] = -0.540343f;	val_dir[12653*3 + 2] = -0.567360f;
+ 	val_dir[12654*3 + 0] = -0.593512f;	val_dir[12654*3 + 1] = -0.512578f;	val_dir[12654*3 + 2] = -0.620490f;
+ 	val_dir[12655*3 + 0] = -0.563264f;	val_dir[12655*3 + 1] = -0.482798f;	val_dir[12655*3 + 2] = -0.670552f;
+ 	val_dir[12656*3 + 0] = -0.531119f;	val_dir[12656*3 + 1] = -0.451451f;	val_dir[12656*3 + 2] = -0.717011f;
+ 	val_dir[12657*3 + 0] = -0.497594f;	val_dir[12657*3 + 1] = -0.419026f;	val_dir[12657*3 + 2] = -0.759485f;
+ 	val_dir[12658*3 + 0] = -0.463217f;	val_dir[12658*3 + 1] = -0.386014f;	val_dir[12658*3 + 2] = -0.797762f;
+ 	val_dir[12659*3 + 0] = -0.428496f;	val_dir[12659*3 + 1] = -0.352879f;	val_dir[12659*3 + 2] = -0.831786f;
+ 	val_dir[12660*3 + 0] = -0.393893f;	val_dir[12660*3 + 1] = -0.320038f;	val_dir[12660*3 + 2] = -0.861640f;
+ 	val_dir[12661*3 + 0] = -0.359804f;	val_dir[12661*3 + 1] = -0.287843f;	val_dir[12661*3 + 2] = -0.887517f;
+ 	val_dir[12662*3 + 0] = -0.326554f;	val_dir[12662*3 + 1] = -0.256578f;	val_dir[12662*3 + 2] = -0.909687f;
+ 	val_dir[12663*3 + 0] = -0.294392f;	val_dir[12663*3 + 1] = -0.226455f;	val_dir[12663*3 + 2] = -0.928467f;
+ 	val_dir[12664*3 + 0] = -0.263498f;	val_dir[12664*3 + 1] = -0.197623f;	val_dir[12664*3 + 2] = -0.94420f;
+ 	val_dir[12665*3 + 0] = -0.233990f;	val_dir[12665*3 + 1] = -0.170174f;	val_dir[12665*3 + 2] = -0.957230f;
+ 	val_dir[12666*3 + 0] = -0.205934f;	val_dir[12666*3 + 1] = -0.144154f;	val_dir[12666*3 + 2] = -0.967890f;
+ 	val_dir[12667*3 + 0] = -0.179355f;	val_dir[12667*3 + 1] = -0.119570f;	val_dir[12667*3 + 2] = -0.976491f;
+ 	val_dir[12668*3 + 0] = -0.154246f;	val_dir[12668*3 + 1] = -0.096404f;	val_dir[12668*3 + 2] = -0.983318f;
+ 	val_dir[12669*3 + 0] = -0.130573f;	val_dir[12669*3 + 1] = -0.074613f;	val_dir[12669*3 + 2] = -0.988627f;
+ 	val_dir[12670*3 + 0] = -0.108288f;	val_dir[12670*3 + 1] = -0.054144f;	val_dir[12670*3 + 2] = -0.992644f;
+ 	val_dir[12671*3 + 0] = -0.087330f;	val_dir[12671*3 + 1] = -0.034932f;	val_dir[12671*3 + 2] = -0.995567f;
+ 	val_dir[12672*3 + 0] = -0.067632f;	val_dir[12672*3 + 1] = -0.016908f;	val_dir[12672*3 + 2] = -0.997567f;
+ 	val_dir[12673*3 + 0] = -0.049121f;	val_dir[12673*3 + 1] = 0.0f;	val_dir[12673*3 + 2] = -0.998793f;
+ 	val_dir[12674*3 + 0] = -0.032765f;	val_dir[12674*3 + 1] = 0.016382f;	val_dir[12674*3 + 2] = -0.999329f;
+ 	val_dir[12675*3 + 0] = -0.016382f;	val_dir[12675*3 + 1] = 0.032765f;	val_dir[12675*3 + 2] = -0.999329f;
+ 	val_dir[12676*3 + 0] = 0.0f;	val_dir[12676*3 + 1] = 0.049121f;	val_dir[12676*3 + 2] = -0.998793f;
+ 	val_dir[12677*3 + 0] = 0.016908f;	val_dir[12677*3 + 1] = 0.067632f;	val_dir[12677*3 + 2] = -0.997567f;
+ 	val_dir[12678*3 + 0] = 0.034932f;	val_dir[12678*3 + 1] = 0.087330f;	val_dir[12678*3 + 2] = -0.995567f;
+ 	val_dir[12679*3 + 0] = 0.054144f;	val_dir[12679*3 + 1] = 0.108288f;	val_dir[12679*3 + 2] = -0.992644f;
+ 	val_dir[12680*3 + 0] = 0.074613f;	val_dir[12680*3 + 1] = 0.130573f;	val_dir[12680*3 + 2] = -0.988627f;
+ 	val_dir[12681*3 + 0] = 0.096404f;	val_dir[12681*3 + 1] = 0.154246f;	val_dir[12681*3 + 2] = -0.983318f;
+ 	val_dir[12682*3 + 0] = 0.119570f;	val_dir[12682*3 + 1] = 0.179355f;	val_dir[12682*3 + 2] = -0.976491f;
+ 	val_dir[12683*3 + 0] = 0.144154f;	val_dir[12683*3 + 1] = 0.205934f;	val_dir[12683*3 + 2] = -0.967890f;
+ 	val_dir[12684*3 + 0] = 0.170174f;	val_dir[12684*3 + 1] = 0.233990f;	val_dir[12684*3 + 2] = -0.957230f;
+ 	val_dir[12685*3 + 0] = 0.197623f;	val_dir[12685*3 + 1] = 0.263498f;	val_dir[12685*3 + 2] = -0.94420f;
+ 	val_dir[12686*3 + 0] = 0.226455f;	val_dir[12686*3 + 1] = 0.294392f;	val_dir[12686*3 + 2] = -0.928467f;
+ 	val_dir[12687*3 + 0] = 0.256578f;	val_dir[12687*3 + 1] = 0.326554f;	val_dir[12687*3 + 2] = -0.909687f;
+ 	val_dir[12688*3 + 0] = 0.287843f;	val_dir[12688*3 + 1] = 0.359804f;	val_dir[12688*3 + 2] = -0.887517f;
+ 	val_dir[12689*3 + 0] = 0.320038f;	val_dir[12689*3 + 1] = 0.393893f;	val_dir[12689*3 + 2] = -0.861640f;
+ 	val_dir[12690*3 + 0] = 0.352879f;	val_dir[12690*3 + 1] = 0.428496f;	val_dir[12690*3 + 2] = -0.831786f;
+ 	val_dir[12691*3 + 0] = 0.386014f;	val_dir[12691*3 + 1] = 0.463217f;	val_dir[12691*3 + 2] = -0.797762f;
+ 	val_dir[12692*3 + 0] = 0.419026f;	val_dir[12692*3 + 1] = 0.497594f;	val_dir[12692*3 + 2] = -0.759485f;
+ 	val_dir[12693*3 + 0] = 0.451451f;	val_dir[12693*3 + 1] = 0.531119f;	val_dir[12693*3 + 2] = -0.717011f;
+ 	val_dir[12694*3 + 0] = 0.482798f;	val_dir[12694*3 + 1] = 0.563264f;	val_dir[12694*3 + 2] = -0.670552f;
+ 	val_dir[12695*3 + 0] = 0.512578f;	val_dir[12695*3 + 1] = 0.593512f;	val_dir[12695*3 + 2] = -0.620490f;
+ 	val_dir[12696*3 + 0] = 0.540343f;	val_dir[12696*3 + 1] = 0.621395f;	val_dir[12696*3 + 2] = -0.567360f;
+ 	val_dir[12697*3 + 0] = 0.565711f;	val_dir[12697*3 + 1] = 0.646527f;	val_dir[12697*3 + 2] = -0.511834f;
+ 	val_dir[12698*3 + 0] = 0.588395f;	val_dir[12698*3 + 1] = 0.668631f;	val_dir[12698*3 + 2] = -0.454669f;
+ 	val_dir[12699*3 + 0] = 0.608219f;	val_dir[12699*3 + 1] = 0.687552f;	val_dir[12699*3 + 2] = -0.396664f;
+ 	val_dir[12700*3 + 0] = 0.625119f;	val_dir[12700*3 + 1] = 0.703259f;	val_dir[12700*3 + 2] = -0.338606f;
+ 	val_dir[12701*3 + 0] = 0.639138f;	val_dir[12701*3 + 1] = 0.715834f;	val_dir[12701*3 + 2] = -0.281220f;
+ 	val_dir[12702*3 + 0] = 0.650407f;	val_dir[12702*3 + 1] = 0.725454f;	val_dir[12702*3 + 2] = -0.225141f;
+ 	val_dir[12703*3 + 0] = 0.659125f;	val_dir[12703*3 + 1] = 0.732361f;	val_dir[12703*3 + 2] = -0.170884f;
+ 	val_dir[12704*3 + 0] = 0.665536f;	val_dir[12704*3 + 1] = 0.736843f;	val_dir[12704*3 + 2] = -0.118846f;
+ 	val_dir[12705*3 + 0] = 0.669905f;	val_dir[12705*3 + 1] = 0.739205f;	val_dir[12705*3 + 2] = -0.069301f;
+ 	val_dir[12706*3 + 0] = 0.672504f;	val_dir[12706*3 + 1] = 0.739754f;	val_dir[12706*3 + 2] = -0.022417f;
+ 	val_dir[12707*3 + 0] = -0.749838f;	val_dir[12707*3 + 1] = -0.661622f;	val_dir[12707*3 + 2] = 0.0f;
+ 	val_dir[12708*3 + 0] = -0.750388f;	val_dir[12708*3 + 1] = -0.659432f;	val_dir[12708*3 + 2] = -0.045478f;
+ 	val_dir[12709*3 + 0] = -0.749269f;	val_dir[12709*3 + 1] = -0.655610f;	val_dir[12709*3 + 2] = -0.093659f;
+ 	val_dir[12710*3 + 0] = -0.746176f;	val_dir[12710*3 + 1] = -0.649895f;	val_dir[12710*3 + 2] = -0.144421f;
+ 	val_dir[12711*3 + 0] = -0.740797f;	val_dir[12711*3 + 1] = -0.642024f;	val_dir[12711*3 + 2] = -0.197546f;
+ 	val_dir[12712*3 + 0] = -0.732828f;	val_dir[12712*3 + 1] = -0.631748f;	val_dir[12712*3 + 2] = -0.252699f;
+ 	val_dir[12713*3 + 0] = -0.721995f;	val_dir[12713*3 + 1] = -0.618853f;	val_dir[12713*3 + 2] = -0.309426f;
+ 	val_dir[12714*3 + 0] = -0.708079f;	val_dir[12714*3 + 1] = -0.603178f;	val_dir[12714*3 + 2] = -0.367152f;
+ 	val_dir[12715*3 + 0] = -0.690942f;	val_dir[12715*3 + 1] = -0.584643f;	val_dir[12715*3 + 2] = -0.425195f;
+ 	val_dir[12716*3 + 0] = -0.670552f;	val_dir[12716*3 + 1] = -0.563264f;	val_dir[12716*3 + 2] = -0.482798f;
+ 	val_dir[12717*3 + 0] = -0.646997f;	val_dir[12717*3 + 1] = -0.539164f;	val_dir[12717*3 + 2] = -0.539164f;
+ 	val_dir[12718*3 + 0] = -0.620490f;	val_dir[12718*3 + 1] = -0.512578f;	val_dir[12718*3 + 2] = -0.593512f;
+ 	val_dir[12719*3 + 0] = -0.591364f;	val_dir[12719*3 + 1] = -0.483843f;	val_dir[12719*3 + 2] = -0.645124f;
+ 	val_dir[12720*3 + 0] = -0.560050f;	val_dir[12720*3 + 1] = -0.453374f;	val_dir[12720*3 + 2] = -0.693395f;
+ 	val_dir[12721*3 + 0] = -0.527046f;	val_dir[12721*3 + 1] = -0.421637f;	val_dir[12721*3 + 2] = -0.737865f;
+ 	val_dir[12722*3 + 0] = -0.492883f;	val_dir[12722*3 + 1] = -0.389118f;	val_dir[12722*3 + 2] = -0.778237f;
+ 	val_dir[12723*3 + 0] = -0.458088f;	val_dir[12723*3 + 1] = -0.356291f;	val_dir[12723*3 + 2] = -0.814379f;
+ 	val_dir[12724*3 + 0] = -0.423153f;	val_dir[12724*3 + 1] = -0.323587f;	val_dir[12724*3 + 2] = -0.846305f;
+ 	val_dir[12725*3 + 0] = -0.388514f;	val_dir[12725*3 + 1] = -0.291386f;	val_dir[12725*3 + 2] = -0.874157f;
+ 	val_dir[12726*3 + 0] = -0.354540f;	val_dir[12726*3 + 1] = -0.259996f;	val_dir[12726*3 + 2] = -0.898167f;
+ 	val_dir[12727*3 + 0] = -0.321521f;	val_dir[12727*3 + 1] = -0.229658f;	val_dir[12727*3 + 2] = -0.918630f;
+ 	val_dir[12728*3 + 0] = -0.289677f;	val_dir[12728*3 + 1] = -0.200545f;	val_dir[12728*3 + 2] = -0.935879f;
+ 	val_dir[12729*3 + 0] = -0.259161f;	val_dir[12729*3 + 1] = -0.172774f;	val_dir[12729*3 + 2] = -0.950255f;
+ 	val_dir[12730*3 + 0] = -0.230067f;	val_dir[12730*3 + 1] = -0.146406f;	val_dir[12730*3 + 2] = -0.962099f;
+ 	val_dir[12731*3 + 0] = -0.202444f;	val_dir[12731*3 + 1] = -0.121466f;	val_dir[12731*3 + 2] = -0.971732f;
+ 	val_dir[12732*3 + 0] = -0.176301f;	val_dir[12732*3 + 1] = -0.097945f;	val_dir[12732*3 + 2] = -0.979451f;
+ 	val_dir[12733*3 + 0] = -0.151620f;	val_dir[12733*3 + 1] = -0.075810f;	val_dir[12733*3 + 2] = -0.985527f;
+ 	val_dir[12734*3 + 0] = -0.128359f;	val_dir[12734*3 + 1] = -0.055011f;	val_dir[12734*3 + 2] = -0.990201f;
+ 	val_dir[12735*3 + 0] = -0.106466f;	val_dir[12735*3 + 1] = -0.035489f;	val_dir[12735*3 + 2] = -0.993683f;
+ 	val_dir[12736*3 + 0] = -0.085876f;	val_dir[12736*3 + 1] = -0.017175f;	val_dir[12736*3 + 2] = -0.996158f;
+ 	val_dir[12737*3 + 0] = -0.066519f;	val_dir[12737*3 + 1] = 0.0f;	val_dir[12737*3 + 2] = -0.997785f;
+ 	val_dir[12738*3 + 0] = -0.049931f;	val_dir[12738*3 + 1] = 0.016644f;	val_dir[12738*3 + 2] = -0.998614f;
+ 	val_dir[12739*3 + 0] = -0.033296f;	val_dir[12739*3 + 1] = 0.033296f;	val_dir[12739*3 + 2] = -0.998891f;
+ 	val_dir[12740*3 + 0] = -0.016644f;	val_dir[12740*3 + 1] = 0.049931f;	val_dir[12740*3 + 2] = -0.998614f;
+ 	val_dir[12741*3 + 0] = 0.0f;	val_dir[12741*3 + 1] = 0.066519f;	val_dir[12741*3 + 2] = -0.997785f;
+ 	val_dir[12742*3 + 0] = 0.017175f;	val_dir[12742*3 + 1] = 0.085876f;	val_dir[12742*3 + 2] = -0.996158f;
+ 	val_dir[12743*3 + 0] = 0.035489f;	val_dir[12743*3 + 1] = 0.106466f;	val_dir[12743*3 + 2] = -0.993683f;
+ 	val_dir[12744*3 + 0] = 0.055011f;	val_dir[12744*3 + 1] = 0.128359f;	val_dir[12744*3 + 2] = -0.990201f;
+ 	val_dir[12745*3 + 0] = 0.075810f;	val_dir[12745*3 + 1] = 0.151620f;	val_dir[12745*3 + 2] = -0.985527f;
+ 	val_dir[12746*3 + 0] = 0.097945f;	val_dir[12746*3 + 1] = 0.176301f;	val_dir[12746*3 + 2] = -0.979451f;
+ 	val_dir[12747*3 + 0] = 0.121466f;	val_dir[12747*3 + 1] = 0.202444f;	val_dir[12747*3 + 2] = -0.971732f;
+ 	val_dir[12748*3 + 0] = 0.146406f;	val_dir[12748*3 + 1] = 0.230067f;	val_dir[12748*3 + 2] = -0.962099f;
+ 	val_dir[12749*3 + 0] = 0.172774f;	val_dir[12749*3 + 1] = 0.259161f;	val_dir[12749*3 + 2] = -0.950255f;
+ 	val_dir[12750*3 + 0] = 0.200545f;	val_dir[12750*3 + 1] = 0.289677f;	val_dir[12750*3 + 2] = -0.935879f;
+ 	val_dir[12751*3 + 0] = 0.229658f;	val_dir[12751*3 + 1] = 0.321521f;	val_dir[12751*3 + 2] = -0.918630f;
+ 	val_dir[12752*3 + 0] = 0.259996f;	val_dir[12752*3 + 1] = 0.354540f;	val_dir[12752*3 + 2] = -0.898167f;
+ 	val_dir[12753*3 + 0] = 0.291386f;	val_dir[12753*3 + 1] = 0.388514f;	val_dir[12753*3 + 2] = -0.874157f;
+ 	val_dir[12754*3 + 0] = 0.323587f;	val_dir[12754*3 + 1] = 0.423153f;	val_dir[12754*3 + 2] = -0.846305f;
+ 	val_dir[12755*3 + 0] = 0.356291f;	val_dir[12755*3 + 1] = 0.458088f;	val_dir[12755*3 + 2] = -0.814379f;
+ 	val_dir[12756*3 + 0] = 0.389118f;	val_dir[12756*3 + 1] = 0.492883f;	val_dir[12756*3 + 2] = -0.778237f;
+ 	val_dir[12757*3 + 0] = 0.421637f;	val_dir[12757*3 + 1] = 0.527046f;	val_dir[12757*3 + 2] = -0.737865f;
+ 	val_dir[12758*3 + 0] = 0.453374f;	val_dir[12758*3 + 1] = 0.560050f;	val_dir[12758*3 + 2] = -0.693395f;
+ 	val_dir[12759*3 + 0] = 0.483843f;	val_dir[12759*3 + 1] = 0.591364f;	val_dir[12759*3 + 2] = -0.645124f;
+ 	val_dir[12760*3 + 0] = 0.512578f;	val_dir[12760*3 + 1] = 0.620490f;	val_dir[12760*3 + 2] = -0.593512f;
+ 	val_dir[12761*3 + 0] = 0.539164f;	val_dir[12761*3 + 1] = 0.646997f;	val_dir[12761*3 + 2] = -0.539164f;
+ 	val_dir[12762*3 + 0] = 0.563264f;	val_dir[12762*3 + 1] = 0.670552f;	val_dir[12762*3 + 2] = -0.482798f;
+ 	val_dir[12763*3 + 0] = 0.584643f;	val_dir[12763*3 + 1] = 0.690942f;	val_dir[12763*3 + 2] = -0.425195f;
+ 	val_dir[12764*3 + 0] = 0.603178f;	val_dir[12764*3 + 1] = 0.708079f;	val_dir[12764*3 + 2] = -0.367152f;
+ 	val_dir[12765*3 + 0] = 0.618853f;	val_dir[12765*3 + 1] = 0.721995f;	val_dir[12765*3 + 2] = -0.309426f;
+ 	val_dir[12766*3 + 0] = 0.631748f;	val_dir[12766*3 + 1] = 0.732828f;	val_dir[12766*3 + 2] = -0.252699f;
+ 	val_dir[12767*3 + 0] = 0.642024f;	val_dir[12767*3 + 1] = 0.740797f;	val_dir[12767*3 + 2] = -0.197546f;
+ 	val_dir[12768*3 + 0] = 0.649895f;	val_dir[12768*3 + 1] = 0.746176f;	val_dir[12768*3 + 2] = -0.144421f;
+ 	val_dir[12769*3 + 0] = 0.655610f;	val_dir[12769*3 + 1] = 0.749269f;	val_dir[12769*3 + 2] = -0.093659f;
+ 	val_dir[12770*3 + 0] = 0.659432f;	val_dir[12770*3 + 1] = 0.750388f;	val_dir[12770*3 + 2] = -0.045478f;
+ 	val_dir[12771*3 + 0] = 0.661622f;	val_dir[12771*3 + 1] = 0.749838f;	val_dir[12771*3 + 2] = 0.0f;
+ 	val_dir[12772*3 + 0] = -0.760644f;	val_dir[12772*3 + 1] = -0.648784f;	val_dir[12772*3 + 2] = -0.022372f;
+ 	val_dir[12773*3 + 0] = -0.760684f;	val_dir[12773*3 + 1] = -0.645429f;	val_dir[12773*3 + 2] = -0.069153f;
+ 	val_dir[12774*3 + 0] = -0.758899f;	val_dir[12774*3 + 1] = -0.640321f;	val_dir[12774*3 + 2] = -0.118578f;
+ 	val_dir[12775*3 + 0] = -0.754976f;	val_dir[12775*3 + 1] = -0.633205f;	val_dir[12775*3 + 2] = -0.170478f;
+ 	val_dir[12776*3 + 0] = -0.748598f;	val_dir[12776*3 + 1] = -0.623831f;	val_dir[12776*3 + 2] = -0.224579f;
+ 	val_dir[12777*3 + 0] = -0.739469f;	val_dir[12777*3 + 1] = -0.611974f;	val_dir[12777*3 + 2] = -0.280488f;
+ 	val_dir[12778*3 + 0] = -0.727334f;	val_dir[12778*3 + 1] = -0.597453f;	val_dir[12778*3 + 2] = -0.337691f;
+ 	val_dir[12779*3 + 0] = -0.712007f;	val_dir[12779*3 + 1] = -0.580154f;	val_dir[12779*3 + 2] = -0.395559f;
+ 	val_dir[12780*3 + 0] = -0.693395f;	val_dir[12780*3 + 1] = -0.560050f;	val_dir[12780*3 + 2] = -0.453374f;
+ 	val_dir[12781*3 + 0] = -0.671519f;	val_dir[12781*3 + 1] = -0.537215f;	val_dir[12781*3 + 2] = -0.510355f;
+ 	val_dir[12782*3 + 0] = -0.646527f;	val_dir[12782*3 + 1] = -0.511834f;	val_dir[12782*3 + 2] = -0.565711f;
+ 	val_dir[12783*3 + 0] = -0.618691f;	val_dir[12783*3 + 1] = -0.484193f;	val_dir[12783*3 + 2] = -0.618691f;
+ 	val_dir[12784*3 + 0] = -0.588395f;	val_dir[12784*3 + 1] = -0.454669f;	val_dir[12784*3 + 2] = -0.668631f;
+ 	val_dir[12785*3 + 0] = -0.556108f;	val_dir[12785*3 + 1] = -0.423702f;	val_dir[12785*3 + 2] = -0.714997f;
+ 	val_dir[12786*3 + 0] = -0.522352f;	val_dir[12786*3 + 1] = -0.391764f;	val_dir[12786*3 + 2] = -0.757410f;
+ 	val_dir[12787*3 + 0] = -0.487661f;	val_dir[12787*3 + 1] = -0.359329f;	val_dir[12787*3 + 2] = -0.795657f;
+ 	val_dir[12788*3 + 0] = -0.452553f;	val_dir[12788*3 + 1] = -0.326844f;	val_dir[12788*3 + 2] = -0.829680f;
+ 	val_dir[12789*3 + 0] = -0.41750f;	val_dir[12789*3 + 1] = -0.294706f;	val_dir[12789*3 + 2] = -0.859559f;
+ 	val_dir[12790*3 + 0] = -0.382911f;	val_dir[12790*3 + 1] = -0.263251f;	val_dir[12790*3 + 2] = -0.885482f;
+ 	val_dir[12791*3 + 0] = -0.349121f;	val_dir[12791*3 + 1] = -0.232747f;	val_dir[12791*3 + 2] = -0.907713f;
+ 	val_dir[12792*3 + 0] = -0.316389f;	val_dir[12792*3 + 1] = -0.203393f;	val_dir[12792*3 + 2] = -0.926568f;
+ 	val_dir[12793*3 + 0] = -0.284907f;	val_dir[12793*3 + 1] = -0.175327f;	val_dir[12793*3 + 2] = -0.942384f;
+ 	val_dir[12794*3 + 0] = -0.254801f;	val_dir[12794*3 + 1] = -0.148634f;	val_dir[12794*3 + 2] = -0.955502f;
+ 	val_dir[12795*3 + 0] = -0.226144f;	val_dir[12795*3 + 1] = -0.123351f;	val_dir[12795*3 + 2] = -0.966252f;
+ 	val_dir[12796*3 + 0] = -0.198968f;	val_dir[12796*3 + 1] = -0.099484f;	val_dir[12796*3 + 2] = -0.974943f;
+ 	val_dir[12797*3 + 0] = -0.173269f;	val_dir[12797*3 + 1] = -0.077009f;	val_dir[12797*3 + 2] = -0.981859f;
+ 	val_dir[12798*3 + 0] = -0.149019f;	val_dir[12798*3 + 1] = -0.055882f;	val_dir[12798*3 + 2] = -0.987254f;
+ 	val_dir[12799*3 + 0] = -0.126172f;	val_dir[12799*3 + 1] = -0.036049f;	val_dir[12799*3 + 2] = -0.991353f;
+ 	val_dir[12800*3 + 0] = -0.104669f;	val_dir[12800*3 + 1] = -0.017445f;	val_dir[12800*3 + 2] = -0.994354f;
+ 	val_dir[12801*3 + 0] = -0.084443f;	val_dir[12801*3 + 1] = 0.0f;	val_dir[12801*3 + 2] = -0.996428f;
+ 	val_dir[12802*3 + 0] = -0.067632f;	val_dir[12802*3 + 1] = 0.016908f;	val_dir[12802*3 + 2] = -0.997567f;
+ 	val_dir[12803*3 + 0] = -0.050753f;	val_dir[12803*3 + 1] = 0.033835f;	val_dir[12803*3 + 2] = -0.998138f;
+ 	val_dir[12804*3 + 0] = -0.033835f;	val_dir[12804*3 + 1] = 0.050753f;	val_dir[12804*3 + 2] = -0.998138f;
+ 	val_dir[12805*3 + 0] = -0.016908f;	val_dir[12805*3 + 1] = 0.067632f;	val_dir[12805*3 + 2] = -0.997567f;
+ 	val_dir[12806*3 + 0] = 0.0f;	val_dir[12806*3 + 1] = 0.084443f;	val_dir[12806*3 + 2] = -0.996428f;
+ 	val_dir[12807*3 + 0] = 0.017445f;	val_dir[12807*3 + 1] = 0.104669f;	val_dir[12807*3 + 2] = -0.994354f;
+ 	val_dir[12808*3 + 0] = 0.036049f;	val_dir[12808*3 + 1] = 0.126172f;	val_dir[12808*3 + 2] = -0.991353f;
+ 	val_dir[12809*3 + 0] = 0.055882f;	val_dir[12809*3 + 1] = 0.149019f;	val_dir[12809*3 + 2] = -0.987254f;
+ 	val_dir[12810*3 + 0] = 0.077009f;	val_dir[12810*3 + 1] = 0.173269f;	val_dir[12810*3 + 2] = -0.981859f;
+ 	val_dir[12811*3 + 0] = 0.099484f;	val_dir[12811*3 + 1] = 0.198968f;	val_dir[12811*3 + 2] = -0.974943f;
+ 	val_dir[12812*3 + 0] = 0.123351f;	val_dir[12812*3 + 1] = 0.226144f;	val_dir[12812*3 + 2] = -0.966252f;
+ 	val_dir[12813*3 + 0] = 0.148634f;	val_dir[12813*3 + 1] = 0.254801f;	val_dir[12813*3 + 2] = -0.955502f;
+ 	val_dir[12814*3 + 0] = 0.175327f;	val_dir[12814*3 + 1] = 0.284907f;	val_dir[12814*3 + 2] = -0.942384f;
+ 	val_dir[12815*3 + 0] = 0.203393f;	val_dir[12815*3 + 1] = 0.316389f;	val_dir[12815*3 + 2] = -0.926568f;
+ 	val_dir[12816*3 + 0] = 0.232747f;	val_dir[12816*3 + 1] = 0.349121f;	val_dir[12816*3 + 2] = -0.907713f;
+ 	val_dir[12817*3 + 0] = 0.263251f;	val_dir[12817*3 + 1] = 0.382911f;	val_dir[12817*3 + 2] = -0.885482f;
+ 	val_dir[12818*3 + 0] = 0.294706f;	val_dir[12818*3 + 1] = 0.41750f;	val_dir[12818*3 + 2] = -0.859559f;
+ 	val_dir[12819*3 + 0] = 0.326844f;	val_dir[12819*3 + 1] = 0.452553f;	val_dir[12819*3 + 2] = -0.829680f;
+ 	val_dir[12820*3 + 0] = 0.359329f;	val_dir[12820*3 + 1] = 0.487661f;	val_dir[12820*3 + 2] = -0.795657f;
+ 	val_dir[12821*3 + 0] = 0.391764f;	val_dir[12821*3 + 1] = 0.522352f;	val_dir[12821*3 + 2] = -0.757410f;
+ 	val_dir[12822*3 + 0] = 0.423702f;	val_dir[12822*3 + 1] = 0.556108f;	val_dir[12822*3 + 2] = -0.714997f;
+ 	val_dir[12823*3 + 0] = 0.454669f;	val_dir[12823*3 + 1] = 0.588395f;	val_dir[12823*3 + 2] = -0.668631f;
+ 	val_dir[12824*3 + 0] = 0.484193f;	val_dir[12824*3 + 1] = 0.618691f;	val_dir[12824*3 + 2] = -0.618691f;
+ 	val_dir[12825*3 + 0] = 0.511834f;	val_dir[12825*3 + 1] = 0.646527f;	val_dir[12825*3 + 2] = -0.565711f;
+ 	val_dir[12826*3 + 0] = 0.537215f;	val_dir[12826*3 + 1] = 0.671519f;	val_dir[12826*3 + 2] = -0.510355f;
+ 	val_dir[12827*3 + 0] = 0.560050f;	val_dir[12827*3 + 1] = 0.693395f;	val_dir[12827*3 + 2] = -0.453374f;
+ 	val_dir[12828*3 + 0] = 0.580154f;	val_dir[12828*3 + 1] = 0.712007f;	val_dir[12828*3 + 2] = -0.395559f;
+ 	val_dir[12829*3 + 0] = 0.597453f;	val_dir[12829*3 + 1] = 0.727334f;	val_dir[12829*3 + 2] = -0.337691f;
+ 	val_dir[12830*3 + 0] = 0.611974f;	val_dir[12830*3 + 1] = 0.739469f;	val_dir[12830*3 + 2] = -0.280488f;
+ 	val_dir[12831*3 + 0] = 0.623831f;	val_dir[12831*3 + 1] = 0.748598f;	val_dir[12831*3 + 2] = -0.224579f;
+ 	val_dir[12832*3 + 0] = 0.633205f;	val_dir[12832*3 + 1] = 0.754976f;	val_dir[12832*3 + 2] = -0.170478f;
+ 	val_dir[12833*3 + 0] = 0.640321f;	val_dir[12833*3 + 1] = 0.758899f;	val_dir[12833*3 + 2] = -0.118578f;
+ 	val_dir[12834*3 + 0] = 0.645429f;	val_dir[12834*3 + 1] = 0.760684f;	val_dir[12834*3 + 2] = -0.069153f;
+ 	val_dir[12835*3 + 0] = 0.648784f;	val_dir[12835*3 + 1] = 0.760644f;	val_dir[12835*3 + 2] = -0.022372f;
+ 	val_dir[12836*3 + 0] = -0.770022f;	val_dir[12836*3 + 1] = -0.638018f;	val_dir[12836*3 + 2] = 0.0f;
+ 	val_dir[12837*3 + 0] = -0.771136f;	val_dir[12837*3 + 1] = -0.635053f;	val_dir[12837*3 + 2] = -0.045361f;
+ 	val_dir[12838*3 + 0] = -0.770574f;	val_dir[12838*3 + 1] = -0.630470f;	val_dir[12838*3 + 2] = -0.093403f;
+ 	val_dir[12839*3 + 0] = -0.768025f;	val_dir[12839*3 + 1] = -0.624020f;	val_dir[12839*3 + 2] = -0.144005f;
+ 	val_dir[12840*3 + 0] = -0.763167f;	val_dir[12840*3 + 1] = -0.615457f;	val_dir[12840*3 + 2] = -0.196946f;
+ 	val_dir[12841*3 + 0] = -0.755689f;	val_dir[12841*3 + 1] = -0.604551f;	val_dir[12841*3 + 2] = -0.251896f;
+ 	val_dir[12842*3 + 0] = -0.745307f;	val_dir[12842*3 + 1] = -0.591105f;	val_dir[12842*3 + 2] = -0.308403f;
+ 	val_dir[12843*3 + 0] = -0.731792f;	val_dir[12843*3 + 1] = -0.574979f;	val_dir[12843*3 + 2] = -0.365896f;
+ 	val_dir[12844*3 + 0] = -0.714997f;	val_dir[12844*3 + 1] = -0.556108f;	val_dir[12844*3 + 2] = -0.423702f;
+ 	val_dir[12845*3 + 0] = -0.694879f;	val_dir[12845*3 + 1] = -0.534522f;	val_dir[12845*3 + 2] = -0.481070f;
+ 	val_dir[12846*3 + 0] = -0.671519f;	val_dir[12846*3 + 1] = -0.510355f;	val_dir[12846*3 + 2] = -0.537215f;
+ 	val_dir[12847*3 + 0] = -0.645124f;	val_dir[12847*3 + 1] = -0.483843f;	val_dir[12847*3 + 2] = -0.591364f;
+ 	val_dir[12848*3 + 0] = -0.616022f;	val_dir[12848*3 + 1] = -0.455321f;	val_dir[12848*3 + 2] = -0.642806f;
+ 	val_dir[12849*3 + 0] = -0.584643f;	val_dir[12849*3 + 1] = -0.425195f;	val_dir[12849*3 + 2] = -0.690942f;
+ 	val_dir[12850*3 + 0] = -0.551487f;	val_dir[12850*3 + 1] = -0.393919f;	val_dir[12850*3 + 2] = -0.735316f;
+ 	val_dir[12851*3 + 0] = -0.517088f;	val_dir[12851*3 + 1] = -0.361961f;	val_dir[12851*3 + 2] = -0.775632f;
+ 	val_dir[12852*3 + 0] = -0.481979f;	val_dir[12852*3 + 1] = -0.329775f;	val_dir[12852*3 + 2] = -0.811754f;
+ 	val_dir[12853*3 + 0] = -0.446662f;	val_dir[12853*3 + 1] = -0.297775f;	val_dir[12853*3 + 2] = -0.843696f;
+ 	val_dir[12854*3 + 0] = -0.411585f;	val_dir[12854*3 + 1] = -0.266320f;	val_dir[12854*3 + 2] = -0.871592f;
+ 	val_dir[12855*3 + 0] = -0.377124f;	val_dir[12855*3 + 1] = -0.235702f;	val_dir[12855*3 + 2] = -0.895669f;
+ 	val_dir[12856*3 + 0] = -0.343582f;	val_dir[12856*3 + 1] = -0.206149f;	val_dir[12856*3 + 2] = -0.916217f;
+ 	val_dir[12857*3 + 0] = -0.311188f;	val_dir[12857*3 + 1] = -0.177822f;	val_dir[12857*3 + 2] = -0.933564f;
+ 	val_dir[12858*3 + 0] = -0.280105f;	val_dir[12858*3 + 1] = -0.150826f;	val_dir[12858*3 + 2] = -0.948047f;
+ 	val_dir[12859*3 + 0] = -0.250435f;	val_dir[12859*3 + 1] = -0.125218f;	val_dir[12859*3 + 2] = -0.960001f;
+ 	val_dir[12860*3 + 0] = -0.222234f;	val_dir[12860*3 + 1] = -0.101015f;	val_dir[12860*3 + 2] = -0.969746f;
+ 	val_dir[12861*3 + 0] = -0.195515f;	val_dir[12861*3 + 1] = -0.078206f;	val_dir[12861*3 + 2] = -0.977577f;
+ 	val_dir[12862*3 + 0] = -0.170267f;	val_dir[12862*3 + 1] = -0.056756f;	val_dir[12862*3 + 2] = -0.983762f;
+ 	val_dir[12863*3 + 0] = -0.146450f;	val_dir[12863*3 + 1] = -0.036613f;	val_dir[12863*3 + 2] = -0.988540f;
+ 	val_dir[12864*3 + 0] = -0.124015f;	val_dir[12864*3 + 1] = -0.017716f;	val_dir[12864*3 + 2] = -0.992122f;
+ 	val_dir[12865*3 + 0] = -0.102899f;	val_dir[12865*3 + 1] = 0.0f;	val_dir[12865*3 + 2] = -0.994692f;
+ 	val_dir[12866*3 + 0] = -0.085876f;	val_dir[12866*3 + 1] = 0.017175f;	val_dir[12866*3 + 2] = -0.996158f;
+ 	val_dir[12867*3 + 0] = -0.068761f;	val_dir[12867*3 + 1] = 0.034381f;	val_dir[12867*3 + 2] = -0.997041f;
+ 	val_dir[12868*3 + 0] = -0.051586f;	val_dir[12868*3 + 1] = 0.051586f;	val_dir[12868*3 + 2] = -0.997335f;
+ 	val_dir[12869*3 + 0] = -0.034381f;	val_dir[12869*3 + 1] = 0.068761f;	val_dir[12869*3 + 2] = -0.997041f;
+ 	val_dir[12870*3 + 0] = -0.017175f;	val_dir[12870*3 + 1] = 0.085876f;	val_dir[12870*3 + 2] = -0.996158f;
+ 	val_dir[12871*3 + 0] = 0.0f;	val_dir[12871*3 + 1] = 0.102899f;	val_dir[12871*3 + 2] = -0.994692f;
+ 	val_dir[12872*3 + 0] = 0.017716f;	val_dir[12872*3 + 1] = 0.124015f;	val_dir[12872*3 + 2] = -0.992122f;
+ 	val_dir[12873*3 + 0] = 0.036613f;	val_dir[12873*3 + 1] = 0.146450f;	val_dir[12873*3 + 2] = -0.988540f;
+ 	val_dir[12874*3 + 0] = 0.056756f;	val_dir[12874*3 + 1] = 0.170267f;	val_dir[12874*3 + 2] = -0.983762f;
+ 	val_dir[12875*3 + 0] = 0.078206f;	val_dir[12875*3 + 1] = 0.195515f;	val_dir[12875*3 + 2] = -0.977577f;
+ 	val_dir[12876*3 + 0] = 0.101015f;	val_dir[12876*3 + 1] = 0.222234f;	val_dir[12876*3 + 2] = -0.969746f;
+ 	val_dir[12877*3 + 0] = 0.125218f;	val_dir[12877*3 + 1] = 0.250435f;	val_dir[12877*3 + 2] = -0.960001f;
+ 	val_dir[12878*3 + 0] = 0.150826f;	val_dir[12878*3 + 1] = 0.280105f;	val_dir[12878*3 + 2] = -0.948047f;
+ 	val_dir[12879*3 + 0] = 0.177822f;	val_dir[12879*3 + 1] = 0.311188f;	val_dir[12879*3 + 2] = -0.933564f;
+ 	val_dir[12880*3 + 0] = 0.206149f;	val_dir[12880*3 + 1] = 0.343582f;	val_dir[12880*3 + 2] = -0.916217f;
+ 	val_dir[12881*3 + 0] = 0.235702f;	val_dir[12881*3 + 1] = 0.377124f;	val_dir[12881*3 + 2] = -0.895669f;
+ 	val_dir[12882*3 + 0] = 0.266320f;	val_dir[12882*3 + 1] = 0.411585f;	val_dir[12882*3 + 2] = -0.871592f;
+ 	val_dir[12883*3 + 0] = 0.297775f;	val_dir[12883*3 + 1] = 0.446662f;	val_dir[12883*3 + 2] = -0.843696f;
+ 	val_dir[12884*3 + 0] = 0.329775f;	val_dir[12884*3 + 1] = 0.481979f;	val_dir[12884*3 + 2] = -0.811754f;
+ 	val_dir[12885*3 + 0] = 0.361961f;	val_dir[12885*3 + 1] = 0.517088f;	val_dir[12885*3 + 2] = -0.775632f;
+ 	val_dir[12886*3 + 0] = 0.393919f;	val_dir[12886*3 + 1] = 0.551487f;	val_dir[12886*3 + 2] = -0.735316f;
+ 	val_dir[12887*3 + 0] = 0.425195f;	val_dir[12887*3 + 1] = 0.584643f;	val_dir[12887*3 + 2] = -0.690942f;
+ 	val_dir[12888*3 + 0] = 0.455321f;	val_dir[12888*3 + 1] = 0.616022f;	val_dir[12888*3 + 2] = -0.642806f;
+ 	val_dir[12889*3 + 0] = 0.483843f;	val_dir[12889*3 + 1] = 0.645124f;	val_dir[12889*3 + 2] = -0.591364f;
+ 	val_dir[12890*3 + 0] = 0.510355f;	val_dir[12890*3 + 1] = 0.671519f;	val_dir[12890*3 + 2] = -0.537215f;
+ 	val_dir[12891*3 + 0] = 0.534522f;	val_dir[12891*3 + 1] = 0.694879f;	val_dir[12891*3 + 2] = -0.481070f;
+ 	val_dir[12892*3 + 0] = 0.556108f;	val_dir[12892*3 + 1] = 0.714997f;	val_dir[12892*3 + 2] = -0.423702f;
+ 	val_dir[12893*3 + 0] = 0.574979f;	val_dir[12893*3 + 1] = 0.731792f;	val_dir[12893*3 + 2] = -0.365896f;
+ 	val_dir[12894*3 + 0] = 0.591105f;	val_dir[12894*3 + 1] = 0.745307f;	val_dir[12894*3 + 2] = -0.308403f;
+ 	val_dir[12895*3 + 0] = 0.604551f;	val_dir[12895*3 + 1] = 0.755689f;	val_dir[12895*3 + 2] = -0.251896f;
+ 	val_dir[12896*3 + 0] = 0.615457f;	val_dir[12896*3 + 1] = 0.763167f;	val_dir[12896*3 + 2] = -0.196946f;
+ 	val_dir[12897*3 + 0] = 0.624020f;	val_dir[12897*3 + 1] = 0.768025f;	val_dir[12897*3 + 2] = -0.144005f;
+ 	val_dir[12898*3 + 0] = 0.630470f;	val_dir[12898*3 + 1] = 0.770574f;	val_dir[12898*3 + 2] = -0.093403f;
+ 	val_dir[12899*3 + 0] = 0.635053f;	val_dir[12899*3 + 1] = 0.771136f;	val_dir[12899*3 + 2] = -0.045361f;
+ 	val_dir[12900*3 + 0] = 0.638018f;	val_dir[12900*3 + 1] = 0.770022f;	val_dir[12900*3 + 2] = 0.0f;
+ 	val_dir[12901*3 + 0] = -0.780675f;	val_dir[12901*3 + 1] = -0.624540f;	val_dir[12901*3 + 2] = -0.022305f;
+ 	val_dir[12902*3 + 0] = -0.781248f;	val_dir[12902*3 + 1] = -0.620403f;	val_dir[12902*3 + 2] = -0.068934f;
+ 	val_dir[12903*3 + 0] = -0.779987f;	val_dir[12903*3 + 1] = -0.614535f;	val_dir[12903*3 + 2] = -0.118180f;
+ 	val_dir[12904*3 + 0] = -0.776571f;	val_dir[12904*3 + 1] = -0.606696f;	val_dir[12904*3 + 2] = -0.169875f;
+ 	val_dir[12905*3 + 0] = -0.770677f;	val_dir[12905*3 + 1] = -0.596653f;	val_dir[12905*3 + 2] = -0.223745f;
+ 	val_dir[12906*3 + 0] = -0.762001f;	val_dir[12906*3 + 1] = -0.584201f;	val_dir[12906*3 + 2] = -0.27940f;
+ 	val_dir[12907*3 + 0] = -0.750279f;	val_dir[12907*3 + 1] = -0.569177f;	val_dir[12907*3 + 2] = -0.336332f;
+ 	val_dir[12908*3 + 0] = -0.735316f;	val_dir[12908*3 + 1] = -0.551487f;	val_dir[12908*3 + 2] = -0.393919f;
+ 	val_dir[12909*3 + 0] = -0.717011f;	val_dir[12909*3 + 1] = -0.531119f;	val_dir[12909*3 + 2] = -0.451451f;
+ 	val_dir[12910*3 + 0] = -0.695376f;	val_dir[12910*3 + 1] = -0.508159f;	val_dir[12910*3 + 2] = -0.508159f;
+ 	val_dir[12911*3 + 0] = -0.670552f;	val_dir[12911*3 + 1] = -0.482798f;	val_dir[12911*3 + 2] = -0.563264f;
+ 	val_dir[12912*3 + 0] = -0.642806f;	val_dir[12912*3 + 1] = -0.455321f;	val_dir[12912*3 + 2] = -0.616022f;
+ 	val_dir[12913*3 + 0] = -0.612517f;	val_dir[12913*3 + 1] = -0.426099f;	val_dir[12913*3 + 2] = -0.665780f;
+ 	val_dir[12914*3 + 0] = -0.580154f;	val_dir[12914*3 + 1] = -0.395559f;	val_dir[12914*3 + 2] = -0.712007f;
+ 	val_dir[12915*3 + 0] = -0.546238f;	val_dir[12915*3 + 1] = -0.364159f;	val_dir[12915*3 + 2] = -0.754329f;
+ 	val_dir[12916*3 + 0] = -0.511310f;	val_dir[12916*3 + 1] = -0.332352f;	val_dir[12916*3 + 2] = -0.792530f;
+ 	val_dir[12917*3 + 0] = -0.475893f;	val_dir[12917*3 + 1] = -0.300564f;	val_dir[12917*3 + 2] = -0.826551f;
+ 	val_dir[12918*3 + 0] = -0.440468f;	val_dir[12918*3 + 1] = -0.269175f;	val_dir[12918*3 + 2] = -0.856465f;
+ 	val_dir[12919*3 + 0] = -0.405452f;	val_dir[12919*3 + 1] = -0.238501f;	val_dir[12919*3 + 2] = -0.882454f;
+ 	val_dir[12920*3 + 0] = -0.371191f;	val_dir[12920*3 + 1] = -0.208795f;	val_dir[12920*3 + 2] = -0.904777f;
+ 	val_dir[12921*3 + 0] = -0.337954f;	val_dir[12921*3 + 1] = -0.180242f;	val_dir[12921*3 + 2] = -0.923742f;
+ 	val_dir[12922*3 + 0] = -0.305942f;	val_dir[12922*3 + 1] = -0.152971f;	val_dir[12922*3 + 2] = -0.939680f;
+ 	val_dir[12923*3 + 0] = -0.275290f;	val_dir[12923*3 + 1] = -0.127057f;	val_dir[12923*3 + 2] = -0.952928f;
+ 	val_dir[12924*3 + 0] = -0.246079f;	val_dir[12924*3 + 1] = -0.102533f;	val_dir[12924*3 + 2] = -0.963811f;
+ 	val_dir[12925*3 + 0] = -0.218347f;	val_dir[12925*3 + 1] = -0.079399f;	val_dir[12925*3 + 2] = -0.972636f;
+ 	val_dir[12926*3 + 0] = -0.192095f;	val_dir[12926*3 + 1] = -0.057628f;	val_dir[12926*3 + 2] = -0.979683f;
+ 	val_dir[12927*3 + 0] = -0.167299f;	val_dir[12927*3 + 1] = -0.037178f;	val_dir[12927*3 + 2] = -0.985205f;
+ 	val_dir[12928*3 + 0] = -0.143917f;	val_dir[12928*3 + 1] = -0.017990f;	val_dir[12928*3 + 2] = -0.989426f;
+ 	val_dir[12929*3 + 0] = -0.121891f;	val_dir[12929*3 + 1] = 0.0f;	val_dir[12929*3 + 2] = -0.992543f;
+ 	val_dir[12930*3 + 0] = -0.104669f;	val_dir[12930*3 + 1] = 0.017445f;	val_dir[12930*3 + 2] = -0.994354f;
+ 	val_dir[12931*3 + 0] = -0.087330f;	val_dir[12931*3 + 1] = 0.034932f;	val_dir[12931*3 + 2] = -0.995567f;
+ 	val_dir[12932*3 + 0] = -0.069907f;	val_dir[12932*3 + 1] = 0.052430f;	val_dir[12932*3 + 2] = -0.996175f;
+ 	val_dir[12933*3 + 0] = -0.052430f;	val_dir[12933*3 + 1] = 0.069907f;	val_dir[12933*3 + 2] = -0.996175f;
+ 	val_dir[12934*3 + 0] = -0.034932f;	val_dir[12934*3 + 1] = 0.087330f;	val_dir[12934*3 + 2] = -0.995567f;
+ 	val_dir[12935*3 + 0] = -0.017445f;	val_dir[12935*3 + 1] = 0.104669f;	val_dir[12935*3 + 2] = -0.994354f;
+ 	val_dir[12936*3 + 0] = 0.0f;	val_dir[12936*3 + 1] = 0.121891f;	val_dir[12936*3 + 2] = -0.992543f;
+ 	val_dir[12937*3 + 0] = 0.017990f;	val_dir[12937*3 + 1] = 0.143917f;	val_dir[12937*3 + 2] = -0.989426f;
+ 	val_dir[12938*3 + 0] = 0.037178f;	val_dir[12938*3 + 1] = 0.167299f;	val_dir[12938*3 + 2] = -0.985205f;
+ 	val_dir[12939*3 + 0] = 0.057628f;	val_dir[12939*3 + 1] = 0.192095f;	val_dir[12939*3 + 2] = -0.979683f;
+ 	val_dir[12940*3 + 0] = 0.079399f;	val_dir[12940*3 + 1] = 0.218347f;	val_dir[12940*3 + 2] = -0.972636f;
+ 	val_dir[12941*3 + 0] = 0.102533f;	val_dir[12941*3 + 1] = 0.246079f;	val_dir[12941*3 + 2] = -0.963811f;
+ 	val_dir[12942*3 + 0] = 0.127057f;	val_dir[12942*3 + 1] = 0.275290f;	val_dir[12942*3 + 2] = -0.952928f;
+ 	val_dir[12943*3 + 0] = 0.152971f;	val_dir[12943*3 + 1] = 0.305942f;	val_dir[12943*3 + 2] = -0.939680f;
+ 	val_dir[12944*3 + 0] = 0.180242f;	val_dir[12944*3 + 1] = 0.337954f;	val_dir[12944*3 + 2] = -0.923742f;
+ 	val_dir[12945*3 + 0] = 0.208795f;	val_dir[12945*3 + 1] = 0.371191f;	val_dir[12945*3 + 2] = -0.904777f;
+ 	val_dir[12946*3 + 0] = 0.238501f;	val_dir[12946*3 + 1] = 0.405452f;	val_dir[12946*3 + 2] = -0.882454f;
+ 	val_dir[12947*3 + 0] = 0.269175f;	val_dir[12947*3 + 1] = 0.440468f;	val_dir[12947*3 + 2] = -0.856465f;
+ 	val_dir[12948*3 + 0] = 0.300564f;	val_dir[12948*3 + 1] = 0.475893f;	val_dir[12948*3 + 2] = -0.826551f;
+ 	val_dir[12949*3 + 0] = 0.332352f;	val_dir[12949*3 + 1] = 0.511310f;	val_dir[12949*3 + 2] = -0.792530f;
+ 	val_dir[12950*3 + 0] = 0.364159f;	val_dir[12950*3 + 1] = 0.546238f;	val_dir[12950*3 + 2] = -0.754329f;
+ 	val_dir[12951*3 + 0] = 0.395559f;	val_dir[12951*3 + 1] = 0.580154f;	val_dir[12951*3 + 2] = -0.712007f;
+ 	val_dir[12952*3 + 0] = 0.426099f;	val_dir[12952*3 + 1] = 0.612517f;	val_dir[12952*3 + 2] = -0.665780f;
+ 	val_dir[12953*3 + 0] = 0.455321f;	val_dir[12953*3 + 1] = 0.642806f;	val_dir[12953*3 + 2] = -0.616022f;
+ 	val_dir[12954*3 + 0] = 0.482798f;	val_dir[12954*3 + 1] = 0.670552f;	val_dir[12954*3 + 2] = -0.563264f;
+ 	val_dir[12955*3 + 0] = 0.508159f;	val_dir[12955*3 + 1] = 0.695376f;	val_dir[12955*3 + 2] = -0.508159f;
+ 	val_dir[12956*3 + 0] = 0.531119f;	val_dir[12956*3 + 1] = 0.717011f;	val_dir[12956*3 + 2] = -0.451451f;
+ 	val_dir[12957*3 + 0] = 0.551487f;	val_dir[12957*3 + 1] = 0.735316f;	val_dir[12957*3 + 2] = -0.393919f;
+ 	val_dir[12958*3 + 0] = 0.569177f;	val_dir[12958*3 + 1] = 0.750279f;	val_dir[12958*3 + 2] = -0.336332f;
+ 	val_dir[12959*3 + 0] = 0.584201f;	val_dir[12959*3 + 1] = 0.762001f;	val_dir[12959*3 + 2] = -0.27940f;
+ 	val_dir[12960*3 + 0] = 0.596653f;	val_dir[12960*3 + 1] = 0.770677f;	val_dir[12960*3 + 2] = -0.223745f;
+ 	val_dir[12961*3 + 0] = 0.606696f;	val_dir[12961*3 + 1] = 0.776571f;	val_dir[12961*3 + 2] = -0.169875f;
+ 	val_dir[12962*3 + 0] = 0.614535f;	val_dir[12962*3 + 1] = 0.779987f;	val_dir[12962*3 + 2] = -0.118180f;
+ 	val_dir[12963*3 + 0] = 0.620403f;	val_dir[12963*3 + 1] = 0.781248f;	val_dir[12963*3 + 2] = -0.068934f;
+ 	val_dir[12964*3 + 0] = 0.624540f;	val_dir[12964*3 + 1] = 0.780675f;	val_dir[12964*3 + 2] = -0.022305f;
+ 	val_dir[12965*3 + 0] = -0.789352f;	val_dir[12965*3 + 1] = -0.613941f;	val_dir[12965*3 + 2] = 0.0f;
+ 	val_dir[12966*3 + 0] = -0.790973f;	val_dir[12966*3 + 1] = -0.610179f;	val_dir[12966*3 + 2] = -0.045198f;
+ 	val_dir[12967*3 + 0] = -0.790912f;	val_dir[12967*3 + 1] = -0.604815f;	val_dir[12967*3 + 2] = -0.093048f;
+ 	val_dir[12968*3 + 0] = -0.788851f;	val_dir[12968*3 + 1] = -0.597614f;	val_dir[12968*3 + 2] = -0.143427f;
+ 	val_dir[12969*3 + 0] = -0.784465f;	val_dir[12969*3 + 1] = -0.588348f;	val_dir[12969*3 + 2] = -0.196116f;
+ 	val_dir[12970*3 + 0] = -0.777433f;	val_dir[12970*3 + 1] = -0.576805f;	val_dir[12970*3 + 2] = -0.250785f;
+ 	val_dir[12971*3 + 0] = -0.767467f;	val_dir[12971*3 + 1] = -0.562809f;	val_dir[12971*3 + 2] = -0.306987f;
+ 	val_dir[12972*3 + 0] = -0.754329f;	val_dir[12972*3 + 1] = -0.546238f;	val_dir[12972*3 + 2] = -0.364159f;
+ 	val_dir[12973*3 + 0] = -0.737865f;	val_dir[12973*3 + 1] = -0.527046f;	val_dir[12973*3 + 2] = -0.421637f;
+ 	val_dir[12974*3 + 0] = -0.718024f;	val_dir[12974*3 + 1] = -0.505276f;	val_dir[12974*3 + 2] = -0.478683f;
+ 	val_dir[12975*3 + 0] = -0.694879f;	val_dir[12975*3 + 1] = -0.481070f;	val_dir[12975*3 + 2] = -0.534522f;
+ 	val_dir[12976*3 + 0] = -0.668631f;	val_dir[12976*3 + 1] = -0.454669f;	val_dir[12976*3 + 2] = -0.588395f;
+ 	val_dir[12977*3 + 0] = -0.639602f;	val_dir[12977*3 + 1] = -0.426401f;	val_dir[12977*3 + 2] = -0.639602f;
+ 	val_dir[12978*3 + 0] = -0.608219f;	val_dir[12978*3 + 1] = -0.396664f;	val_dir[12978*3 + 2] = -0.687552f;
+ 	val_dir[12979*3 + 0] = -0.574979f;	val_dir[12979*3 + 1] = -0.365896f;	val_dir[12979*3 + 2] = -0.731792f;
+ 	val_dir[12980*3 + 0] = -0.540419f;	val_dir[12980*3 + 1] = -0.334545f;	val_dir[12980*3 + 2] = -0.772027f;
+ 	val_dir[12981*3 + 0] = -0.505076f;	val_dir[12981*3 + 1] = -0.303046f;	val_dir[12981*3 + 2] = -0.808122f;
+ 	val_dir[12982*3 + 0] = -0.469458f;	val_dir[12982*3 + 1] = -0.271791f;	val_dir[12982*3 + 2] = -0.840083f;
+ 	val_dir[12983*3 + 0] = -0.434019f;	val_dir[12983*3 + 1] = -0.241121f;	val_dir[12983*3 + 2] = -0.868037f;
+ 	val_dir[12984*3 + 0] = -0.399145f;	val_dir[12984*3 + 1] = -0.211312f;	val_dir[12984*3 + 2] = -0.892206f;
+ 	val_dir[12985*3 + 0] = -0.365148f;	val_dir[12985*3 + 1] = -0.182574f;	val_dir[12985*3 + 2] = -0.912871f;
+ 	val_dir[12986*3 + 0] = -0.332269f;	val_dir[12986*3 + 1] = -0.155059f;	val_dir[12986*3 + 2] = -0.930352f;
+ 	val_dir[12987*3 + 0] = -0.300676f;	val_dir[12987*3 + 1] = -0.128861f;	val_dir[12987*3 + 2] = -0.944981f;
+ 	val_dir[12988*3 + 0] = -0.270481f;	val_dir[12988*3 + 1] = -0.104031f;	val_dir[12988*3 + 2] = -0.957088f;
+ 	val_dir[12989*3 + 0] = -0.241747f;	val_dir[12989*3 + 1] = -0.080582f;	val_dir[12989*3 + 2] = -0.966988f;
+ 	val_dir[12990*3 + 0] = -0.214494f;	val_dir[12990*3 + 1] = -0.058498f;	val_dir[12990*3 + 2] = -0.974972f;
+ 	val_dir[12991*3 + 0] = -0.188713f;	val_dir[12991*3 + 1] = -0.037743f;	val_dir[12991*3 + 2] = -0.981307f;
+ 	val_dir[12992*3 + 0] = -0.164372f;	val_dir[12992*3 + 1] = -0.018264f;	val_dir[12992*3 + 2] = -0.986229f;
+ 	val_dir[12993*3 + 0] = -0.141421f;	val_dir[12993*3 + 1] = 0.0f;	val_dir[12993*3 + 2] = -0.989949f;
+ 	val_dir[12994*3 + 0] = -0.124015f;	val_dir[12994*3 + 1] = 0.017716f;	val_dir[12994*3 + 2] = -0.992122f;
+ 	val_dir[12995*3 + 0] = -0.106466f;	val_dir[12995*3 + 1] = 0.035489f;	val_dir[12995*3 + 2] = -0.993683f;
+ 	val_dir[12996*3 + 0] = -0.088806f;	val_dir[12996*3 + 1] = 0.053283f;	val_dir[12996*3 + 2] = -0.994623f;
+ 	val_dir[12997*3 + 0] = -0.071067f;	val_dir[12997*3 + 1] = 0.071067f;	val_dir[12997*3 + 2] = -0.994937f;
+ 	val_dir[12998*3 + 0] = -0.053283f;	val_dir[12998*3 + 1] = 0.088806f;	val_dir[12998*3 + 2] = -0.994623f;
+ 	val_dir[12999*3 + 0] = -0.035489f;	val_dir[12999*3 + 1] = 0.106466f;	val_dir[12999*3 + 2] = -0.993683f;
+ 	val_dir[13000*3 + 0] = -0.017716f;	val_dir[13000*3 + 1] = 0.124015f;	val_dir[13000*3 + 2] = -0.992122f;
+ 	val_dir[13001*3 + 0] = 0.0f;	val_dir[13001*3 + 1] = 0.141421f;	val_dir[13001*3 + 2] = -0.989949f;
+ 	val_dir[13002*3 + 0] = 0.018264f;	val_dir[13002*3 + 1] = 0.164372f;	val_dir[13002*3 + 2] = -0.986229f;
+ 	val_dir[13003*3 + 0] = 0.037743f;	val_dir[13003*3 + 1] = 0.188713f;	val_dir[13003*3 + 2] = -0.981307f;
+ 	val_dir[13004*3 + 0] = 0.058498f;	val_dir[13004*3 + 1] = 0.214494f;	val_dir[13004*3 + 2] = -0.974972f;
+ 	val_dir[13005*3 + 0] = 0.080582f;	val_dir[13005*3 + 1] = 0.241747f;	val_dir[13005*3 + 2] = -0.966988f;
+ 	val_dir[13006*3 + 0] = 0.104031f;	val_dir[13006*3 + 1] = 0.270481f;	val_dir[13006*3 + 2] = -0.957088f;
+ 	val_dir[13007*3 + 0] = 0.128861f;	val_dir[13007*3 + 1] = 0.300676f;	val_dir[13007*3 + 2] = -0.944981f;
+ 	val_dir[13008*3 + 0] = 0.155059f;	val_dir[13008*3 + 1] = 0.332269f;	val_dir[13008*3 + 2] = -0.930352f;
+ 	val_dir[13009*3 + 0] = 0.182574f;	val_dir[13009*3 + 1] = 0.365148f;	val_dir[13009*3 + 2] = -0.912871f;
+ 	val_dir[13010*3 + 0] = 0.211312f;	val_dir[13010*3 + 1] = 0.399145f;	val_dir[13010*3 + 2] = -0.892206f;
+ 	val_dir[13011*3 + 0] = 0.241121f;	val_dir[13011*3 + 1] = 0.434019f;	val_dir[13011*3 + 2] = -0.868037f;
+ 	val_dir[13012*3 + 0] = 0.271791f;	val_dir[13012*3 + 1] = 0.469458f;	val_dir[13012*3 + 2] = -0.840083f;
+ 	val_dir[13013*3 + 0] = 0.303046f;	val_dir[13013*3 + 1] = 0.505076f;	val_dir[13013*3 + 2] = -0.808122f;
+ 	val_dir[13014*3 + 0] = 0.334545f;	val_dir[13014*3 + 1] = 0.540419f;	val_dir[13014*3 + 2] = -0.772027f;
+ 	val_dir[13015*3 + 0] = 0.365896f;	val_dir[13015*3 + 1] = 0.574979f;	val_dir[13015*3 + 2] = -0.731792f;
+ 	val_dir[13016*3 + 0] = 0.396664f;	val_dir[13016*3 + 1] = 0.608219f;	val_dir[13016*3 + 2] = -0.687552f;
+ 	val_dir[13017*3 + 0] = 0.426401f;	val_dir[13017*3 + 1] = 0.639602f;	val_dir[13017*3 + 2] = -0.639602f;
+ 	val_dir[13018*3 + 0] = 0.454669f;	val_dir[13018*3 + 1] = 0.668631f;	val_dir[13018*3 + 2] = -0.588395f;
+ 	val_dir[13019*3 + 0] = 0.481070f;	val_dir[13019*3 + 1] = 0.694879f;	val_dir[13019*3 + 2] = -0.534522f;
+ 	val_dir[13020*3 + 0] = 0.505276f;	val_dir[13020*3 + 1] = 0.718024f;	val_dir[13020*3 + 2] = -0.478683f;
+ 	val_dir[13021*3 + 0] = 0.527046f;	val_dir[13021*3 + 1] = 0.737865f;	val_dir[13021*3 + 2] = -0.421637f;
+ 	val_dir[13022*3 + 0] = 0.546238f;	val_dir[13022*3 + 1] = 0.754329f;	val_dir[13022*3 + 2] = -0.364159f;
+ 	val_dir[13023*3 + 0] = 0.562809f;	val_dir[13023*3 + 1] = 0.767467f;	val_dir[13023*3 + 2] = -0.306987f;
+ 	val_dir[13024*3 + 0] = 0.576805f;	val_dir[13024*3 + 1] = 0.777433f;	val_dir[13024*3 + 2] = -0.250785f;
+ 	val_dir[13025*3 + 0] = 0.588348f;	val_dir[13025*3 + 1] = 0.784465f;	val_dir[13025*3 + 2] = -0.196116f;
+ 	val_dir[13026*3 + 0] = 0.597614f;	val_dir[13026*3 + 1] = 0.788851f;	val_dir[13026*3 + 2] = -0.143427f;
+ 	val_dir[13027*3 + 0] = 0.604815f;	val_dir[13027*3 + 1] = 0.790912f;	val_dir[13027*3 + 2] = -0.093048f;
+ 	val_dir[13028*3 + 0] = 0.610179f;	val_dir[13028*3 + 1] = 0.790973f;	val_dir[13028*3 + 2] = -0.045198f;
+ 	val_dir[13029*3 + 0] = 0.613941f;	val_dir[13029*3 + 1] = 0.789352f;	val_dir[13029*3 + 2] = 0.0f;
+ 	val_dir[13030*3 + 0] = -0.799803f;	val_dir[13030*3 + 1] = -0.599852f;	val_dir[13030*3 + 2] = -0.022217f;
+ 	val_dir[13031*3 + 0] = -0.800850f;	val_dir[13031*3 + 1] = -0.594917f;	val_dir[13031*3 + 2] = -0.068644f;
+ 	val_dir[13032*3 + 0] = -0.800055f;	val_dir[13032*3 + 1] = -0.588276f;	val_dir[13032*3 + 2] = -0.117655f;
+ 	val_dir[13033*3 + 0] = -0.797092f;	val_dir[13033*3 + 1] = -0.579703f;	val_dir[13033*3 + 2] = -0.169080f;
+ 	val_dir[13034*3 + 0] = -0.791633f;	val_dir[13034*3 + 1] = -0.568986f;	val_dir[13034*3 + 2] = -0.222647f;
+ 	val_dir[13035*3 + 0] = -0.783368f;	val_dir[13035*3 + 1] = -0.555939f;	val_dir[13035*3 + 2] = -0.277969f;
+ 	val_dir[13036*3 + 0] = -0.772027f;	val_dir[13036*3 + 1] = -0.540419f;	val_dir[13036*3 + 2] = -0.334545f;
+ 	val_dir[13037*3 + 0] = -0.757410f;	val_dir[13037*3 + 1] = -0.522352f;	val_dir[13037*3 + 2] = -0.391764f;
+ 	val_dir[13038*3 + 0] = -0.739407f;	val_dir[13038*3 + 1] = -0.501740f;	val_dir[13038*3 + 2] = -0.448926f;
+ 	val_dir[13039*3 + 0] = -0.718024f;	val_dir[13039*3 + 1] = -0.478683f;	val_dir[13039*3 + 2] = -0.505276f;
+ 	val_dir[13040*3 + 0] = -0.693395f;	val_dir[13040*3 + 1] = -0.453374f;	val_dir[13040*3 + 2] = -0.560050f;
+ 	val_dir[13041*3 + 0] = -0.665780f;	val_dir[13041*3 + 1] = -0.426099f;	val_dir[13041*3 + 2] = -0.612517f;
+ 	val_dir[13042*3 + 0] = -0.635553f;	val_dir[13042*3 + 1] = -0.397220f;	val_dir[13042*3 + 2] = -0.662034f;
+ 	val_dir[13043*3 + 0] = -0.603178f;	val_dir[13043*3 + 1] = -0.367152f;	val_dir[13043*3 + 2] = -0.708079f;
+ 	val_dir[13044*3 + 0] = -0.569177f;	val_dir[13044*3 + 1] = -0.336332f;	val_dir[13044*3 + 2] = -0.750279f;
+ 	val_dir[13045*3 + 0] = -0.534090f;	val_dir[13045*3 + 1] = -0.305194f;	val_dir[13045*3 + 2] = -0.788419f;
+ 	val_dir[13046*3 + 0] = -0.498445f;	val_dir[13046*3 + 1] = -0.274145f;	val_dir[13046*3 + 2] = -0.822434f;
+ 	val_dir[13047*3 + 0] = -0.462727f;	val_dir[13047*3 + 1] = -0.243541f;	val_dir[13047*3 + 2] = -0.852392f;
+ 	val_dir[13048*3 + 0] = -0.427362f;	val_dir[13048*3 + 1] = -0.213681f;	val_dir[13048*3 + 2] = -0.878466f;
+ 	val_dir[13049*3 + 0] = -0.392703f;	val_dir[13049*3 + 1] = -0.184801f;	val_dir[13049*3 + 2] = -0.900907f;
+ 	val_dir[13050*3 + 0] = -0.359030f;	val_dir[13050*3 + 1] = -0.157075f;	val_dir[13050*3 + 2] = -0.920014f;
+ 	val_dir[13051*3 + 0] = -0.326550f;	val_dir[13051*3 + 1] = -0.130620f;	val_dir[13051*3 + 2] = -0.936111f;
+ 	val_dir[13052*3 + 0] = -0.295409f;	val_dir[13052*3 + 1] = -0.105503f;	val_dir[13052*3 + 2] = -0.949528f;
+ 	val_dir[13053*3 + 0] = -0.265694f;	val_dir[13053*3 + 1] = -0.081752f;	val_dir[13053*3 + 2] = -0.960585f;
+ 	val_dir[13054*3 + 0] = -0.237449f;	val_dir[13054*3 + 1] = -0.059362f;	val_dir[13054*3 + 2] = -0.969584f;
+ 	val_dir[13055*3 + 0] = -0.210683f;	val_dir[13055*3 + 1] = -0.038306f;	val_dir[13055*3 + 2] = -0.976804f;
+ 	val_dir[13056*3 + 0] = -0.185376f;	val_dir[13056*3 + 1] = -0.018538f;	val_dir[13056*3 + 2] = -0.982493f;
+ 	val_dir[13057*3 + 0] = -0.161489f;	val_dir[13057*3 + 1] = 0.0f;	val_dir[13057*3 + 2] = -0.986875f;
+ 	val_dir[13058*3 + 0] = -0.143917f;	val_dir[13058*3 + 1] = 0.017990f;	val_dir[13058*3 + 2] = -0.989426f;
+ 	val_dir[13059*3 + 0] = -0.126172f;	val_dir[13059*3 + 1] = 0.036049f;	val_dir[13059*3 + 2] = -0.991353f;
+ 	val_dir[13060*3 + 0] = -0.108288f;	val_dir[13060*3 + 1] = 0.054144f;	val_dir[13060*3 + 2] = -0.992644f;
+ 	val_dir[13061*3 + 0] = -0.090299f;	val_dir[13061*3 + 1] = 0.072239f;	val_dir[13061*3 + 2] = -0.993291f;
+ 	val_dir[13062*3 + 0] = -0.072239f;	val_dir[13062*3 + 1] = 0.090299f;	val_dir[13062*3 + 2] = -0.993291f;
+ 	val_dir[13063*3 + 0] = -0.054144f;	val_dir[13063*3 + 1] = 0.108288f;	val_dir[13063*3 + 2] = -0.992644f;
+ 	val_dir[13064*3 + 0] = -0.036049f;	val_dir[13064*3 + 1] = 0.126172f;	val_dir[13064*3 + 2] = -0.991353f;
+ 	val_dir[13065*3 + 0] = -0.017990f;	val_dir[13065*3 + 1] = 0.143917f;	val_dir[13065*3 + 2] = -0.989426f;
+ 	val_dir[13066*3 + 0] = 0.0f;	val_dir[13066*3 + 1] = 0.161489f;	val_dir[13066*3 + 2] = -0.986875f;
+ 	val_dir[13067*3 + 0] = 0.018538f;	val_dir[13067*3 + 1] = 0.185376f;	val_dir[13067*3 + 2] = -0.982493f;
+ 	val_dir[13068*3 + 0] = 0.038306f;	val_dir[13068*3 + 1] = 0.210683f;	val_dir[13068*3 + 2] = -0.976804f;
+ 	val_dir[13069*3 + 0] = 0.059362f;	val_dir[13069*3 + 1] = 0.237449f;	val_dir[13069*3 + 2] = -0.969584f;
+ 	val_dir[13070*3 + 0] = 0.081752f;	val_dir[13070*3 + 1] = 0.265694f;	val_dir[13070*3 + 2] = -0.960585f;
+ 	val_dir[13071*3 + 0] = 0.105503f;	val_dir[13071*3 + 1] = 0.295409f;	val_dir[13071*3 + 2] = -0.949528f;
+ 	val_dir[13072*3 + 0] = 0.130620f;	val_dir[13072*3 + 1] = 0.326550f;	val_dir[13072*3 + 2] = -0.936111f;
+ 	val_dir[13073*3 + 0] = 0.157075f;	val_dir[13073*3 + 1] = 0.359030f;	val_dir[13073*3 + 2] = -0.920014f;
+ 	val_dir[13074*3 + 0] = 0.184801f;	val_dir[13074*3 + 1] = 0.392703f;	val_dir[13074*3 + 2] = -0.900907f;
+ 	val_dir[13075*3 + 0] = 0.213681f;	val_dir[13075*3 + 1] = 0.427362f;	val_dir[13075*3 + 2] = -0.878466f;
+ 	val_dir[13076*3 + 0] = 0.243541f;	val_dir[13076*3 + 1] = 0.462727f;	val_dir[13076*3 + 2] = -0.852392f;
+ 	val_dir[13077*3 + 0] = 0.274145f;	val_dir[13077*3 + 1] = 0.498445f;	val_dir[13077*3 + 2] = -0.822434f;
+ 	val_dir[13078*3 + 0] = 0.305194f;	val_dir[13078*3 + 1] = 0.534090f;	val_dir[13078*3 + 2] = -0.788419f;
+ 	val_dir[13079*3 + 0] = 0.336332f;	val_dir[13079*3 + 1] = 0.569177f;	val_dir[13079*3 + 2] = -0.750279f;
+ 	val_dir[13080*3 + 0] = 0.367152f;	val_dir[13080*3 + 1] = 0.603178f;	val_dir[13080*3 + 2] = -0.708079f;
+ 	val_dir[13081*3 + 0] = 0.397220f;	val_dir[13081*3 + 1] = 0.635553f;	val_dir[13081*3 + 2] = -0.662034f;
+ 	val_dir[13082*3 + 0] = 0.426099f;	val_dir[13082*3 + 1] = 0.665780f;	val_dir[13082*3 + 2] = -0.612517f;
+ 	val_dir[13083*3 + 0] = 0.453374f;	val_dir[13083*3 + 1] = 0.693395f;	val_dir[13083*3 + 2] = -0.560050f;
+ 	val_dir[13084*3 + 0] = 0.478683f;	val_dir[13084*3 + 1] = 0.718024f;	val_dir[13084*3 + 2] = -0.505276f;
+ 	val_dir[13085*3 + 0] = 0.501740f;	val_dir[13085*3 + 1] = 0.739407f;	val_dir[13085*3 + 2] = -0.448926f;
+ 	val_dir[13086*3 + 0] = 0.522352f;	val_dir[13086*3 + 1] = 0.757410f;	val_dir[13086*3 + 2] = -0.391764f;
+ 	val_dir[13087*3 + 0] = 0.540419f;	val_dir[13087*3 + 1] = 0.772027f;	val_dir[13087*3 + 2] = -0.334545f;
+ 	val_dir[13088*3 + 0] = 0.555939f;	val_dir[13088*3 + 1] = 0.783368f;	val_dir[13088*3 + 2] = -0.277969f;
+ 	val_dir[13089*3 + 0] = 0.568986f;	val_dir[13089*3 + 1] = 0.791633f;	val_dir[13089*3 + 2] = -0.222647f;
+ 	val_dir[13090*3 + 0] = 0.579703f;	val_dir[13090*3 + 1] = 0.797092f;	val_dir[13090*3 + 2] = -0.169080f;
+ 	val_dir[13091*3 + 0] = 0.588276f;	val_dir[13091*3 + 1] = 0.800055f;	val_dir[13091*3 + 2] = -0.117655f;
+ 	val_dir[13092*3 + 0] = 0.594917f;	val_dir[13092*3 + 1] = 0.800850f;	val_dir[13092*3 + 2] = -0.068644f;
+ 	val_dir[13093*3 + 0] = 0.599852f;	val_dir[13093*3 + 1] = 0.799803f;	val_dir[13093*3 + 2] = -0.022217f;
+ 	val_dir[13094*3 + 0] = -0.807791f;	val_dir[13094*3 + 1] = -0.589469f;	val_dir[13094*3 + 2] = 0.0f;
+ 	val_dir[13095*3 + 0] = -0.809858f;	val_dir[13095*3 + 1] = -0.584898f;	val_dir[13095*3 + 2] = -0.044992f;
+ 	val_dir[13096*3 + 0] = -0.810237f;	val_dir[13096*3 + 1] = -0.578741f;	val_dir[13096*3 + 2] = -0.092599f;
+ 	val_dir[13097*3 + 0] = -0.808608f;	val_dir[13097*3 + 1] = -0.570782f;	val_dir[13097*3 + 2] = -0.142695f;
+ 	val_dir[13098*3 + 0] = -0.804639f;	val_dir[13098*3 + 1] = -0.560809f;	val_dir[13098*3 + 2] = -0.195064f;
+ 	val_dir[13099*3 + 0] = -0.798007f;	val_dir[13099*3 + 1] = -0.548630f;	val_dir[13099*3 + 2] = -0.249377f;
+ 	val_dir[13100*3 + 0] = -0.788419f;	val_dir[13100*3 + 1] = -0.534090f;	val_dir[13100*3 + 2] = -0.305194f;
+ 	val_dir[13101*3 + 0] = -0.775632f;	val_dir[13101*3 + 1] = -0.517088f;	val_dir[13101*3 + 2] = -0.361961f;
+ 	val_dir[13102*3 + 0] = -0.759485f;	val_dir[13102*3 + 1] = -0.497594f;	val_dir[13102*3 + 2] = -0.419026f;
+ 	val_dir[13103*3 + 0] = -0.739923f;	val_dir[13103*3 + 1] = -0.475665f;	val_dir[13103*3 + 2] = -0.475665f;
+ 	val_dir[13104*3 + 0] = -0.717011f;	val_dir[13104*3 + 1] = -0.451451f;	val_dir[13104*3 + 2] = -0.531119f;
+ 	val_dir[13105*3 + 0] = -0.690942f;	val_dir[13105*3 + 1] = -0.425195f;	val_dir[13105*3 + 2] = -0.584643f;
+ 	val_dir[13106*3 + 0] = -0.662034f;	val_dir[13106*3 + 1] = -0.397220f;	val_dir[13106*3 + 2] = -0.635553f;
+ 	val_dir[13107*3 + 0] = -0.630706f;	val_dir[13107*3 + 1] = -0.367912f;	val_dir[13107*3 + 2] = -0.683265f;
+ 	val_dir[13108*3 + 0] = -0.597453f;	val_dir[13108*3 + 1] = -0.337691f;	val_dir[13108*3 + 2] = -0.727334f;
+ 	val_dir[13109*3 + 0] = -0.562809f;	val_dir[13109*3 + 1] = -0.306987f;	val_dir[13109*3 + 2] = -0.767467f;
+ 	val_dir[13110*3 + 0] = -0.527312f;	val_dir[13110*3 + 1] = -0.276211f;	val_dir[13110*3 + 2] = -0.803523f;
+ 	val_dir[13111*3 + 0] = -0.491473f;	val_dir[13111*3 + 1] = -0.245737f;	val_dir[13111*3 + 2] = -0.835504f;
+ 	val_dir[13112*3 + 0] = -0.455752f;	val_dir[13112*3 + 1] = -0.215883f;	val_dir[13112*3 + 2] = -0.863530f;
+ 	val_dir[13113*3 + 0] = -0.420542f;	val_dir[13113*3 + 1] = -0.186908f;	val_dir[13113*3 + 2] = -0.887812f;
+ 	val_dir[13114*3 + 0] = -0.386164f;	val_dir[13114*3 + 1] = -0.159009f;	val_dir[13114*3 + 2] = -0.908622f;
+ 	val_dir[13115*3 + 0] = -0.352865f;	val_dir[13115*3 + 1] = -0.132324f;	val_dir[13115*3 + 2] = -0.926270f;
+ 	val_dir[13116*3 + 0] = -0.320824f;	val_dir[13116*3 + 1] = -0.106941f;	val_dir[13116*3 + 2] = -0.941082f;
+ 	val_dir[13117*3 + 0] = -0.290159f;	val_dir[13117*3 + 1] = -0.082903f;	val_dir[13117*3 + 2] = -0.953381f;
+ 	val_dir[13118*3 + 0] = -0.260941f;	val_dir[13118*3 + 1] = -0.060217f;	val_dir[13118*3 + 2] = -0.963475f;
+ 	val_dir[13119*3 + 0] = -0.233197f;	val_dir[13119*3 + 1] = -0.038866f;	val_dir[13119*3 + 2] = -0.971653f;
+ 	val_dir[13120*3 + 0] = -0.206922f;	val_dir[13120*3 + 1] = -0.018811f;	val_dir[13120*3 + 2] = -0.978177f;
+ 	val_dir[13121*3 + 0] = -0.182089f;	val_dir[13121*3 + 1] = 0.0f;	val_dir[13121*3 + 2] = -0.983282f;
+ 	val_dir[13122*3 + 0] = -0.164372f;	val_dir[13122*3 + 1] = 0.018264f;	val_dir[13122*3 + 2] = -0.986229f;
+ 	val_dir[13123*3 + 0] = -0.146450f;	val_dir[13123*3 + 1] = 0.036613f;	val_dir[13123*3 + 2] = -0.988540f;
+ 	val_dir[13124*3 + 0] = -0.128359f;	val_dir[13124*3 + 1] = 0.055011f;	val_dir[13124*3 + 2] = -0.990201f;
+ 	val_dir[13125*3 + 0] = -0.110133f;	val_dir[13125*3 + 1] = 0.073422f;	val_dir[13125*3 + 2] = -0.991201f;
+ 	val_dir[13126*3 + 0] = -0.091809f;	val_dir[13126*3 + 1] = 0.091809f;	val_dir[13126*3 + 2] = -0.991535f;
+ 	val_dir[13127*3 + 0] = -0.073422f;	val_dir[13127*3 + 1] = 0.110133f;	val_dir[13127*3 + 2] = -0.991201f;
+ 	val_dir[13128*3 + 0] = -0.055011f;	val_dir[13128*3 + 1] = 0.128359f;	val_dir[13128*3 + 2] = -0.990201f;
+ 	val_dir[13129*3 + 0] = -0.036613f;	val_dir[13129*3 + 1] = 0.146450f;	val_dir[13129*3 + 2] = -0.988540f;
+ 	val_dir[13130*3 + 0] = -0.018264f;	val_dir[13130*3 + 1] = 0.164372f;	val_dir[13130*3 + 2] = -0.986229f;
+ 	val_dir[13131*3 + 0] = 0.0f;	val_dir[13131*3 + 1] = 0.182089f;	val_dir[13131*3 + 2] = -0.983282f;
+ 	val_dir[13132*3 + 0] = 0.018811f;	val_dir[13132*3 + 1] = 0.206922f;	val_dir[13132*3 + 2] = -0.978177f;
+ 	val_dir[13133*3 + 0] = 0.038866f;	val_dir[13133*3 + 1] = 0.233197f;	val_dir[13133*3 + 2] = -0.971653f;
+ 	val_dir[13134*3 + 0] = 0.060217f;	val_dir[13134*3 + 1] = 0.260941f;	val_dir[13134*3 + 2] = -0.963475f;
+ 	val_dir[13135*3 + 0] = 0.082903f;	val_dir[13135*3 + 1] = 0.290159f;	val_dir[13135*3 + 2] = -0.953381f;
+ 	val_dir[13136*3 + 0] = 0.106941f;	val_dir[13136*3 + 1] = 0.320824f;	val_dir[13136*3 + 2] = -0.941082f;
+ 	val_dir[13137*3 + 0] = 0.132324f;	val_dir[13137*3 + 1] = 0.352865f;	val_dir[13137*3 + 2] = -0.926270f;
+ 	val_dir[13138*3 + 0] = 0.159009f;	val_dir[13138*3 + 1] = 0.386164f;	val_dir[13138*3 + 2] = -0.908622f;
+ 	val_dir[13139*3 + 0] = 0.186908f;	val_dir[13139*3 + 1] = 0.420542f;	val_dir[13139*3 + 2] = -0.887812f;
+ 	val_dir[13140*3 + 0] = 0.215883f;	val_dir[13140*3 + 1] = 0.455752f;	val_dir[13140*3 + 2] = -0.863530f;
+ 	val_dir[13141*3 + 0] = 0.245737f;	val_dir[13141*3 + 1] = 0.491473f;	val_dir[13141*3 + 2] = -0.835504f;
+ 	val_dir[13142*3 + 0] = 0.276211f;	val_dir[13142*3 + 1] = 0.527312f;	val_dir[13142*3 + 2] = -0.803523f;
+ 	val_dir[13143*3 + 0] = 0.306987f;	val_dir[13143*3 + 1] = 0.562809f;	val_dir[13143*3 + 2] = -0.767467f;
+ 	val_dir[13144*3 + 0] = 0.337691f;	val_dir[13144*3 + 1] = 0.597453f;	val_dir[13144*3 + 2] = -0.727334f;
+ 	val_dir[13145*3 + 0] = 0.367912f;	val_dir[13145*3 + 1] = 0.630706f;	val_dir[13145*3 + 2] = -0.683265f;
+ 	val_dir[13146*3 + 0] = 0.397220f;	val_dir[13146*3 + 1] = 0.662034f;	val_dir[13146*3 + 2] = -0.635553f;
+ 	val_dir[13147*3 + 0] = 0.425195f;	val_dir[13147*3 + 1] = 0.690942f;	val_dir[13147*3 + 2] = -0.584643f;
+ 	val_dir[13148*3 + 0] = 0.451451f;	val_dir[13148*3 + 1] = 0.717011f;	val_dir[13148*3 + 2] = -0.531119f;
+ 	val_dir[13149*3 + 0] = 0.475665f;	val_dir[13149*3 + 1] = 0.739923f;	val_dir[13149*3 + 2] = -0.475665f;
+ 	val_dir[13150*3 + 0] = 0.497594f;	val_dir[13150*3 + 1] = 0.759485f;	val_dir[13150*3 + 2] = -0.419026f;
+ 	val_dir[13151*3 + 0] = 0.517088f;	val_dir[13151*3 + 1] = 0.775632f;	val_dir[13151*3 + 2] = -0.361961f;
+ 	val_dir[13152*3 + 0] = 0.534090f;	val_dir[13152*3 + 1] = 0.788419f;	val_dir[13152*3 + 2] = -0.305194f;
+ 	val_dir[13153*3 + 0] = 0.548630f;	val_dir[13153*3 + 1] = 0.798007f;	val_dir[13153*3 + 2] = -0.249377f;
+ 	val_dir[13154*3 + 0] = 0.560809f;	val_dir[13154*3 + 1] = 0.804639f;	val_dir[13154*3 + 2] = -0.195064f;
+ 	val_dir[13155*3 + 0] = 0.570782f;	val_dir[13155*3 + 1] = 0.808608f;	val_dir[13155*3 + 2] = -0.142695f;
+ 	val_dir[13156*3 + 0] = 0.578741f;	val_dir[13156*3 + 1] = 0.810237f;	val_dir[13156*3 + 2] = -0.092599f;
+ 	val_dir[13157*3 + 0] = 0.584898f;	val_dir[13157*3 + 1] = 0.809858f;	val_dir[13157*3 + 2] = -0.044992f;
+ 	val_dir[13158*3 + 0] = 0.589469f;	val_dir[13158*3 + 1] = 0.807791f;	val_dir[13158*3 + 2] = 0.0f;
+ 	val_dir[13159*3 + 0] = -0.817992f;	val_dir[13159*3 + 1] = -0.574805f;	val_dir[13159*3 + 2] = -0.022108f;
+ 	val_dir[13160*3 + 0] = -0.819453f;	val_dir[13160*3 + 1] = -0.569064f;	val_dir[13160*3 + 2] = -0.068288f;
+ 	val_dir[13161*3 + 0] = -0.819064f;	val_dir[13161*3 + 1] = -0.561644f;	val_dir[13161*3 + 2] = -0.117009f;
+ 	val_dir[13162*3 + 0] = -0.816497f;	val_dir[13162*3 + 1] = -0.552336f;	val_dir[13162*3 + 2] = -0.168102f;
+ 	val_dir[13163*3 + 0] = -0.811421f;	val_dir[13163*3 + 1] = -0.540947f;	val_dir[13163*3 + 2] = -0.221297f;
+ 	val_dir[13164*3 + 0] = -0.803523f;	val_dir[13164*3 + 1] = -0.527312f;	val_dir[13164*3 + 2] = -0.276211f;
+ 	val_dir[13165*3 + 0] = -0.792530f;	val_dir[13165*3 + 1] = -0.511310f;	val_dir[13165*3 + 2] = -0.332352f;
+ 	val_dir[13166*3 + 0] = -0.778237f;	val_dir[13166*3 + 1] = -0.492883f;	val_dir[13166*3 + 2] = -0.389118f;
+ 	val_dir[13167*3 + 0] = -0.760529f;	val_dir[13167*3 + 1] = -0.472053f;	val_dir[13167*3 + 2] = -0.445827f;
+ 	val_dir[13168*3 + 0] = -0.739407f;	val_dir[13168*3 + 1] = -0.448926f;	val_dir[13168*3 + 2] = -0.501740f;
+ 	val_dir[13169*3 + 0] = -0.714997f;	val_dir[13169*3 + 1] = -0.423702f;	val_dir[13169*3 + 2] = -0.556108f;
+ 	val_dir[13170*3 + 0] = -0.687552f;	val_dir[13170*3 + 1] = -0.396664f;	val_dir[13170*3 + 2] = -0.608219f;
+ 	val_dir[13171*3 + 0] = -0.657440f;	val_dir[13171*3 + 1] = -0.368166f;	val_dir[13171*3 + 2] = -0.657440f;
+ 	val_dir[13172*3 + 0] = -0.625119f;	val_dir[13172*3 + 1] = -0.338606f;	val_dir[13172*3 + 2] = -0.703259f;
+ 	val_dir[13173*3 + 0] = -0.591105f;	val_dir[13173*3 + 1] = -0.308403f;	val_dir[13173*3 + 2] = -0.745307f;
+ 	val_dir[13174*3 + 0] = -0.555939f;	val_dir[13174*3 + 1] = -0.277969f;	val_dir[13174*3 + 2] = -0.783368f;
+ 	val_dir[13175*3 + 0] = -0.520146f;	val_dir[13175*3 + 1] = -0.247689f;	val_dir[13175*3 + 2] = -0.817373f;
+ 	val_dir[13176*3 + 0] = -0.484217f;	val_dir[13176*3 + 1] = -0.217898f;	val_dir[13176*3 + 2] = -0.847381f;
+ 	val_dir[13177*3 + 0] = -0.448583f;	val_dir[13177*3 + 1] = -0.188877f;	val_dir[13177*3 + 2] = -0.873555f;
+ 	val_dir[13178*3 + 0] = -0.413602f;	val_dir[13178*3 + 1] = -0.160845f;	val_dir[13178*3 + 2] = -0.896137f;
+ 	val_dir[13179*3 + 0] = -0.379563f;	val_dir[13179*3 + 1] = -0.133963f;	val_dir[13179*3 + 2] = -0.915416f;
+ 	val_dir[13180*3 + 0] = -0.346681f;	val_dir[13180*3 + 1] = -0.108338f;	val_dir[13180*3 + 2] = -0.931705f;
+ 	val_dir[13181*3 + 0] = -0.315109f;	val_dir[13181*3 + 1] = -0.084029f;	val_dir[13181*3 + 2] = -0.945328f;
+ 	val_dir[13182*3 + 0] = -0.284944f;	val_dir[13182*3 + 1] = -0.061059f;	val_dir[13182*3 + 2] = -0.956597f;
+ 	val_dir[13183*3 + 0] = -0.256235f;	val_dir[13183*3 + 1] = -0.039421f;	val_dir[13183*3 + 2] = -0.965810f;
+ 	val_dir[13184*3 + 0] = -0.228998f;	val_dir[13184*3 + 1] = -0.019083f;	val_dir[13184*3 + 2] = -0.973240f;
+ 	val_dir[13185*3 + 0] = -0.203216f;	val_dir[13185*3 + 1] = 0.0f;	val_dir[13185*3 + 2] = -0.979134f;
+ 	val_dir[13186*3 + 0] = -0.185376f;	val_dir[13186*3 + 1] = 0.018538f;	val_dir[13186*3 + 2] = -0.982493f;
+ 	val_dir[13187*3 + 0] = -0.167299f;	val_dir[13187*3 + 1] = 0.037178f;	val_dir[13187*3 + 2] = -0.985205f;
+ 	val_dir[13188*3 + 0] = -0.149019f;	val_dir[13188*3 + 1] = 0.055882f;	val_dir[13188*3 + 2] = -0.987254f;
+ 	val_dir[13189*3 + 0] = -0.130573f;	val_dir[13189*3 + 1] = 0.074613f;	val_dir[13189*3 + 2] = -0.988627f;
+ 	val_dir[13190*3 + 0] = -0.111998f;	val_dir[13190*3 + 1] = 0.093332f;	val_dir[13190*3 + 2] = -0.989316f;
+ 	val_dir[13191*3 + 0] = -0.093332f;	val_dir[13191*3 + 1] = 0.111998f;	val_dir[13191*3 + 2] = -0.989316f;
+ 	val_dir[13192*3 + 0] = -0.074613f;	val_dir[13192*3 + 1] = 0.130573f;	val_dir[13192*3 + 2] = -0.988627f;
+ 	val_dir[13193*3 + 0] = -0.055882f;	val_dir[13193*3 + 1] = 0.149019f;	val_dir[13193*3 + 2] = -0.987254f;
+ 	val_dir[13194*3 + 0] = -0.037178f;	val_dir[13194*3 + 1] = 0.167299f;	val_dir[13194*3 + 2] = -0.985205f;
+ 	val_dir[13195*3 + 0] = -0.018538f;	val_dir[13195*3 + 1] = 0.185376f;	val_dir[13195*3 + 2] = -0.982493f;
+ 	val_dir[13196*3 + 0] = 0.0f;	val_dir[13196*3 + 1] = 0.203216f;	val_dir[13196*3 + 2] = -0.979134f;
+ 	val_dir[13197*3 + 0] = 0.019083f;	val_dir[13197*3 + 1] = 0.228998f;	val_dir[13197*3 + 2] = -0.973240f;
+ 	val_dir[13198*3 + 0] = 0.039421f;	val_dir[13198*3 + 1] = 0.256235f;	val_dir[13198*3 + 2] = -0.965810f;
+ 	val_dir[13199*3 + 0] = 0.061059f;	val_dir[13199*3 + 1] = 0.284944f;	val_dir[13199*3 + 2] = -0.956597f;
+ 	val_dir[13200*3 + 0] = 0.084029f;	val_dir[13200*3 + 1] = 0.315109f;	val_dir[13200*3 + 2] = -0.945328f;
+ 	val_dir[13201*3 + 0] = 0.108338f;	val_dir[13201*3 + 1] = 0.346681f;	val_dir[13201*3 + 2] = -0.931705f;
+ 	val_dir[13202*3 + 0] = 0.133963f;	val_dir[13202*3 + 1] = 0.379563f;	val_dir[13202*3 + 2] = -0.915416f;
+ 	val_dir[13203*3 + 0] = 0.160845f;	val_dir[13203*3 + 1] = 0.413602f;	val_dir[13203*3 + 2] = -0.896137f;
+ 	val_dir[13204*3 + 0] = 0.188877f;	val_dir[13204*3 + 1] = 0.448583f;	val_dir[13204*3 + 2] = -0.873555f;
+ 	val_dir[13205*3 + 0] = 0.217898f;	val_dir[13205*3 + 1] = 0.484217f;	val_dir[13205*3 + 2] = -0.847381f;
+ 	val_dir[13206*3 + 0] = 0.247689f;	val_dir[13206*3 + 1] = 0.520146f;	val_dir[13206*3 + 2] = -0.817373f;
+ 	val_dir[13207*3 + 0] = 0.277969f;	val_dir[13207*3 + 1] = 0.555939f;	val_dir[13207*3 + 2] = -0.783368f;
+ 	val_dir[13208*3 + 0] = 0.308403f;	val_dir[13208*3 + 1] = 0.591105f;	val_dir[13208*3 + 2] = -0.745307f;
+ 	val_dir[13209*3 + 0] = 0.338606f;	val_dir[13209*3 + 1] = 0.625119f;	val_dir[13209*3 + 2] = -0.703259f;
+ 	val_dir[13210*3 + 0] = 0.368166f;	val_dir[13210*3 + 1] = 0.657440f;	val_dir[13210*3 + 2] = -0.657440f;
+ 	val_dir[13211*3 + 0] = 0.396664f;	val_dir[13211*3 + 1] = 0.687552f;	val_dir[13211*3 + 2] = -0.608219f;
+ 	val_dir[13212*3 + 0] = 0.423702f;	val_dir[13212*3 + 1] = 0.714997f;	val_dir[13212*3 + 2] = -0.556108f;
+ 	val_dir[13213*3 + 0] = 0.448926f;	val_dir[13213*3 + 1] = 0.739407f;	val_dir[13213*3 + 2] = -0.501740f;
+ 	val_dir[13214*3 + 0] = 0.472053f;	val_dir[13214*3 + 1] = 0.760529f;	val_dir[13214*3 + 2] = -0.445827f;
+ 	val_dir[13215*3 + 0] = 0.492883f;	val_dir[13215*3 + 1] = 0.778237f;	val_dir[13215*3 + 2] = -0.389118f;
+ 	val_dir[13216*3 + 0] = 0.511310f;	val_dir[13216*3 + 1] = 0.792530f;	val_dir[13216*3 + 2] = -0.332352f;
+ 	val_dir[13217*3 + 0] = 0.527312f;	val_dir[13217*3 + 1] = 0.803523f;	val_dir[13217*3 + 2] = -0.276211f;
+ 	val_dir[13218*3 + 0] = 0.540947f;	val_dir[13218*3 + 1] = 0.811421f;	val_dir[13218*3 + 2] = -0.221297f;
+ 	val_dir[13219*3 + 0] = 0.552336f;	val_dir[13219*3 + 1] = 0.816497f;	val_dir[13219*3 + 2] = -0.168102f;
+ 	val_dir[13220*3 + 0] = 0.561644f;	val_dir[13220*3 + 1] = 0.819064f;	val_dir[13220*3 + 2] = -0.117009f;
+ 	val_dir[13221*3 + 0] = 0.569064f;	val_dir[13221*3 + 1] = 0.819453f;	val_dir[13221*3 + 2] = -0.068288f;
+ 	val_dir[13222*3 + 0] = 0.574805f;	val_dir[13222*3 + 1] = 0.817992f;	val_dir[13222*3 + 2] = -0.022108f;
+ 	val_dir[13223*3 + 0] = -0.825307f;	val_dir[13223*3 + 1] = -0.564684f;	val_dir[13223*3 + 2] = 0.0f;
+ 	val_dir[13224*3 + 0] = -0.827759f;	val_dir[13224*3 + 1] = -0.559297f;	val_dir[13224*3 + 2] = -0.044744f;
+ 	val_dir[13225*3 + 0] = -0.828517f;	val_dir[13225*3 + 1] = -0.552345f;	val_dir[13225*3 + 2] = -0.092057f;
+ 	val_dir[13226*3 + 0] = -0.827259f;	val_dir[13226*3 + 1] = -0.543627f;	val_dir[13226*3 + 2] = -0.141816f;
+ 	val_dir[13227*3 + 0] = -0.823653f;	val_dir[13227*3 + 1] = -0.532952f;	val_dir[13227*3 + 2] = -0.193801f;
+ 	val_dir[13228*3 + 0] = -0.817373f;	val_dir[13228*3 + 1] = -0.520146f;	val_dir[13228*3 + 2] = -0.247689f;
+ 	val_dir[13229*3 + 0] = -0.808122f;	val_dir[13229*3 + 1] = -0.505076f;	val_dir[13229*3 + 2] = -0.303046f;
+ 	val_dir[13230*3 + 0] = -0.795657f;	val_dir[13230*3 + 1] = -0.487661f;	val_dir[13230*3 + 2] = -0.359329f;
+ 	val_dir[13231*3 + 0] = -0.779813f;	val_dir[13231*3 + 1] = -0.467888f;	val_dir[13231*3 + 2] = -0.41590f;
+ 	val_dir[13232*3 + 0] = -0.760529f;	val_dir[13232*3 + 1] = -0.445827f;	val_dir[13232*3 + 2] = -0.472053f;
+ 	val_dir[13233*3 + 0] = -0.737865f;	val_dir[13233*3 + 1] = -0.421637f;	val_dir[13233*3 + 2] = -0.527046f;
+ 	val_dir[13234*3 + 0] = -0.712007f;	val_dir[13234*3 + 1] = -0.395559f;	val_dir[13234*3 + 2] = -0.580154f;
+ 	val_dir[13235*3 + 0] = -0.683265f;	val_dir[13235*3 + 1] = -0.367912f;	val_dir[13235*3 + 2] = -0.630706f;
+ 	val_dir[13236*3 + 0] = -0.652051f;	val_dir[13236*3 + 1] = -0.339066f;	val_dir[13236*3 + 2] = -0.678133f;
+ 	val_dir[13237*3 + 0] = -0.618853f;	val_dir[13237*3 + 1] = -0.309426f;	val_dir[13237*3 + 2] = -0.721995f;
+ 	val_dir[13238*3 + 0] = -0.584201f;	val_dir[13238*3 + 1] = -0.27940f;	val_dir[13238*3 + 2] = -0.762001f;
+ 	val_dir[13239*3 + 0] = -0.548630f;	val_dir[13239*3 + 1] = -0.249377f;	val_dir[13239*3 + 2] = -0.798007f;
+ 	val_dir[13240*3 + 0] = -0.512653f;	val_dir[13240*3 + 1] = -0.219708f;	val_dir[13240*3 + 2] = -0.830009f;
+ 	val_dir[13241*3 + 0] = -0.476731f;	val_dir[13241*3 + 1] = -0.190693f;	val_dir[13241*3 + 2] = -0.858116f;
+ 	val_dir[13242*3 + 0] = -0.441264f;	val_dir[13242*3 + 1] = -0.162571f;	val_dir[13242*3 + 2] = -0.882528f;
+ 	val_dir[13243*3 + 0] = -0.406579f;	val_dir[13243*3 + 1] = -0.135526f;	val_dir[13243*3 + 2] = -0.903508f;
+ 	val_dir[13244*3 + 0] = -0.372929f;	val_dir[13244*3 + 1] = -0.109685f;	val_dir[13244*3 + 2] = -0.921354f;
+ 	val_dir[13245*3 + 0] = -0.340503f;	val_dir[13245*3 + 1] = -0.085126f;	val_dir[13245*3 + 2] = -0.936382f;
+ 	val_dir[13246*3 + 0] = -0.309426f;	val_dir[13246*3 + 1] = -0.061885f;	val_dir[13246*3 + 2] = -0.948908f;
+ 	val_dir[13247*3 + 0] = -0.279776f;	val_dir[13247*3 + 1] = -0.039968f;	val_dir[13247*3 + 2] = -0.959233f;
+ 	val_dir[13248*3 + 0] = -0.251587f;	val_dir[13248*3 + 1] = -0.019353f;	val_dir[13248*3 + 2] = -0.967641f;
+ 	val_dir[13249*3 + 0] = -0.224860f;	val_dir[13249*3 + 1] = 0.0f;	val_dir[13249*3 + 2] = -0.974391f;
+ 	val_dir[13250*3 + 0] = -0.206922f;	val_dir[13250*3 + 1] = 0.018811f;	val_dir[13250*3 + 2] = -0.978177f;
+ 	val_dir[13251*3 + 0] = -0.188713f;	val_dir[13251*3 + 1] = 0.037743f;	val_dir[13251*3 + 2] = -0.981307f;
+ 	val_dir[13252*3 + 0] = -0.170267f;	val_dir[13252*3 + 1] = 0.056756f;	val_dir[13252*3 + 2] = -0.983762f;
+ 	val_dir[13253*3 + 0] = -0.151620f;	val_dir[13253*3 + 1] = 0.075810f;	val_dir[13253*3 + 2] = -0.985527f;
+ 	val_dir[13254*3 + 0] = -0.132810f;	val_dir[13254*3 + 1] = 0.094865f;	val_dir[13254*3 + 2] = -0.986591f;
+ 	val_dir[13255*3 + 0] = -0.113878f;	val_dir[13255*3 + 1] = 0.113878f;	val_dir[13255*3 + 2] = -0.986947f;
+ 	val_dir[13256*3 + 0] = -0.094865f;	val_dir[13256*3 + 1] = 0.132810f;	val_dir[13256*3 + 2] = -0.986591f;
+ 	val_dir[13257*3 + 0] = -0.075810f;	val_dir[13257*3 + 1] = 0.151620f;	val_dir[13257*3 + 2] = -0.985527f;
+ 	val_dir[13258*3 + 0] = -0.056756f;	val_dir[13258*3 + 1] = 0.170267f;	val_dir[13258*3 + 2] = -0.983762f;
+ 	val_dir[13259*3 + 0] = -0.037743f;	val_dir[13259*3 + 1] = 0.188713f;	val_dir[13259*3 + 2] = -0.981307f;
+ 	val_dir[13260*3 + 0] = -0.018811f;	val_dir[13260*3 + 1] = 0.206922f;	val_dir[13260*3 + 2] = -0.978177f;
+ 	val_dir[13261*3 + 0] = 0.0f;	val_dir[13261*3 + 1] = 0.224860f;	val_dir[13261*3 + 2] = -0.974391f;
+ 	val_dir[13262*3 + 0] = 0.019353f;	val_dir[13262*3 + 1] = 0.251587f;	val_dir[13262*3 + 2] = -0.967641f;
+ 	val_dir[13263*3 + 0] = 0.039968f;	val_dir[13263*3 + 1] = 0.279776f;	val_dir[13263*3 + 2] = -0.959233f;
+ 	val_dir[13264*3 + 0] = 0.061885f;	val_dir[13264*3 + 1] = 0.309426f;	val_dir[13264*3 + 2] = -0.948908f;
+ 	val_dir[13265*3 + 0] = 0.085126f;	val_dir[13265*3 + 1] = 0.340503f;	val_dir[13265*3 + 2] = -0.936382f;
+ 	val_dir[13266*3 + 0] = 0.109685f;	val_dir[13266*3 + 1] = 0.372929f;	val_dir[13266*3 + 2] = -0.921354f;
+ 	val_dir[13267*3 + 0] = 0.135526f;	val_dir[13267*3 + 1] = 0.406579f;	val_dir[13267*3 + 2] = -0.903508f;
+ 	val_dir[13268*3 + 0] = 0.162571f;	val_dir[13268*3 + 1] = 0.441264f;	val_dir[13268*3 + 2] = -0.882528f;
+ 	val_dir[13269*3 + 0] = 0.190693f;	val_dir[13269*3 + 1] = 0.476731f;	val_dir[13269*3 + 2] = -0.858116f;
+ 	val_dir[13270*3 + 0] = 0.219708f;	val_dir[13270*3 + 1] = 0.512653f;	val_dir[13270*3 + 2] = -0.830009f;
+ 	val_dir[13271*3 + 0] = 0.249377f;	val_dir[13271*3 + 1] = 0.548630f;	val_dir[13271*3 + 2] = -0.798007f;
+ 	val_dir[13272*3 + 0] = 0.27940f;	val_dir[13272*3 + 1] = 0.584201f;	val_dir[13272*3 + 2] = -0.762001f;
+ 	val_dir[13273*3 + 0] = 0.309426f;	val_dir[13273*3 + 1] = 0.618853f;	val_dir[13273*3 + 2] = -0.721995f;
+ 	val_dir[13274*3 + 0] = 0.339066f;	val_dir[13274*3 + 1] = 0.652051f;	val_dir[13274*3 + 2] = -0.678133f;
+ 	val_dir[13275*3 + 0] = 0.367912f;	val_dir[13275*3 + 1] = 0.683265f;	val_dir[13275*3 + 2] = -0.630706f;
+ 	val_dir[13276*3 + 0] = 0.395559f;	val_dir[13276*3 + 1] = 0.712007f;	val_dir[13276*3 + 2] = -0.580154f;
+ 	val_dir[13277*3 + 0] = 0.421637f;	val_dir[13277*3 + 1] = 0.737865f;	val_dir[13277*3 + 2] = -0.527046f;
+ 	val_dir[13278*3 + 0] = 0.445827f;	val_dir[13278*3 + 1] = 0.760529f;	val_dir[13278*3 + 2] = -0.472053f;
+ 	val_dir[13279*3 + 0] = 0.467888f;	val_dir[13279*3 + 1] = 0.779813f;	val_dir[13279*3 + 2] = -0.41590f;
+ 	val_dir[13280*3 + 0] = 0.487661f;	val_dir[13280*3 + 1] = 0.795657f;	val_dir[13280*3 + 2] = -0.359329f;
+ 	val_dir[13281*3 + 0] = 0.505076f;	val_dir[13281*3 + 1] = 0.808122f;	val_dir[13281*3 + 2] = -0.303046f;
+ 	val_dir[13282*3 + 0] = 0.520146f;	val_dir[13282*3 + 1] = 0.817373f;	val_dir[13282*3 + 2] = -0.247689f;
+ 	val_dir[13283*3 + 0] = 0.532952f;	val_dir[13283*3 + 1] = 0.823653f;	val_dir[13283*3 + 2] = -0.193801f;
+ 	val_dir[13284*3 + 0] = 0.543627f;	val_dir[13284*3 + 1] = 0.827259f;	val_dir[13284*3 + 2] = -0.141816f;
+ 	val_dir[13285*3 + 0] = 0.552345f;	val_dir[13285*3 + 1] = 0.828517f;	val_dir[13285*3 + 2] = -0.092057f;
+ 	val_dir[13286*3 + 0] = 0.559297f;	val_dir[13286*3 + 1] = 0.827759f;	val_dir[13286*3 + 2] = -0.044744f;
+ 	val_dir[13287*3 + 0] = 0.564684f;	val_dir[13287*3 + 1] = 0.825307f;	val_dir[13287*3 + 2] = 0.0f;
+ 	val_dir[13288*3 + 0] = -0.835215f;	val_dir[13288*3 + 1] = -0.549484f;	val_dir[13288*3 + 2] = -0.021979f;
+ 	val_dir[13289*3 + 0] = -0.837027f;	val_dir[13289*3 + 1] = -0.542936f;	val_dir[13289*3 + 2] = -0.067867f;
+ 	val_dir[13290*3 + 0] = -0.836983f;	val_dir[13290*3 + 1] = -0.534739f;	val_dir[13290*3 + 2] = -0.116248f;
+ 	val_dir[13291*3 + 0] = -0.834754f;	val_dir[13291*3 + 1] = -0.524703f;	val_dir[13291*3 + 2] = -0.166951f;
+ 	val_dir[13292*3 + 0] = -0.830009f;	val_dir[13292*3 + 1] = -0.512653f;	val_dir[13292*3 + 2] = -0.219708f;
+ 	val_dir[13293*3 + 0] = -0.822434f;	val_dir[13293*3 + 1] = -0.498445f;	val_dir[13293*3 + 2] = -0.274145f;
+ 	val_dir[13294*3 + 0] = -0.811754f;	val_dir[13294*3 + 1] = -0.481979f;	val_dir[13294*3 + 2] = -0.329775f;
+ 	val_dir[13295*3 + 0] = -0.797762f;	val_dir[13295*3 + 1] = -0.463217f;	val_dir[13295*3 + 2] = -0.386014f;
+ 	val_dir[13296*3 + 0] = -0.780340f;	val_dir[13296*3 + 1] = -0.442193f;	val_dir[13296*3 + 2] = -0.442193f;
+ 	val_dir[13297*3 + 0] = -0.759485f;	val_dir[13297*3 + 1] = -0.419026f;	val_dir[13297*3 + 2] = -0.497594f;
+ 	val_dir[13298*3 + 0] = -0.735316f;	val_dir[13298*3 + 1] = -0.393919f;	val_dir[13298*3 + 2] = -0.551487f;
+ 	val_dir[13299*3 + 0] = -0.708079f;	val_dir[13299*3 + 1] = -0.367152f;	val_dir[13299*3 + 2] = -0.603178f;
+ 	val_dir[13300*3 + 0] = -0.678133f;	val_dir[13300*3 + 1] = -0.339066f;	val_dir[13300*3 + 2] = -0.652051f;
+ 	val_dir[13301*3 + 0] = -0.645928f;	val_dir[13301*3 + 1] = -0.310045f;	val_dir[13301*3 + 2] = -0.697602f;
+ 	val_dir[13302*3 + 0] = -0.611974f;	val_dir[13302*3 + 1] = -0.280488f;	val_dir[13302*3 + 2] = -0.739469f;
+ 	val_dir[13303*3 + 0] = -0.576805f;	val_dir[13303*3 + 1] = -0.250785f;	val_dir[13303*3 + 2] = -0.777433f;
+ 	val_dir[13304*3 + 0] = -0.540947f;	val_dir[13304*3 + 1] = -0.221297f;	val_dir[13304*3 + 2] = -0.811421f;
+ 	val_dir[13305*3 + 0] = -0.504889f;	val_dir[13305*3 + 1] = -0.192339f;	val_dir[13305*3 + 2] = -0.841482f;
+ 	val_dir[13306*3 + 0] = -0.469065f;	val_dir[13306*3 + 1] = -0.164173f;	val_dir[13306*3 + 2] = -0.867770f;
+ 	val_dir[13307*3 + 0] = -0.433840f;	val_dir[13307*3 + 1] = -0.137002f;	val_dir[13307*3 + 2] = -0.890513f;
+ 	val_dir[13308*3 + 0] = -0.399507f;	val_dir[13308*3 + 1] = -0.110974f;	val_dir[13308*3 + 2] = -0.909988f;
+ 	val_dir[13309*3 + 0] = -0.366291f;	val_dir[13309*3 + 1] = -0.086186f;	val_dir[13309*3 + 2] = -0.92650f;
+ 	val_dir[13310*3 + 0] = -0.334351f;	val_dir[13310*3 + 1] = -0.062691f;	val_dir[13310*3 + 2] = -0.940361f;
+ 	val_dir[13311*3 + 0] = -0.303791f;	val_dir[13311*3 + 1] = -0.040505f;	val_dir[13311*3 + 2] = -0.951877f;
+ 	val_dir[13312*3 + 0] = -0.274668f;	val_dir[13312*3 + 1] = -0.019619f;	val_dir[13312*3 + 2] = -0.961339f;
+ 	val_dir[13313*3 + 0] = -0.247004f;	val_dir[13313*3 + 1] = 0.0f;	val_dir[13313*3 + 2] = -0.969015f;
+ 	val_dir[13314*3 + 0] = -0.228998f;	val_dir[13314*3 + 1] = 0.019083f;	val_dir[13314*3 + 2] = -0.973240f;
+ 	val_dir[13315*3 + 0] = -0.210683f;	val_dir[13315*3 + 1] = 0.038306f;	val_dir[13315*3 + 2] = -0.976804f;
+ 	val_dir[13316*3 + 0] = -0.192095f;	val_dir[13316*3 + 1] = 0.057628f;	val_dir[13316*3 + 2] = -0.979683f;
+ 	val_dir[13317*3 + 0] = -0.173269f;	val_dir[13317*3 + 1] = 0.077009f;	val_dir[13317*3 + 2] = -0.981859f;
+ 	val_dir[13318*3 + 0] = -0.154246f;	val_dir[13318*3 + 1] = 0.096404f;	val_dir[13318*3 + 2] = -0.983318f;
+ 	val_dir[13319*3 + 0] = -0.135066f;	val_dir[13319*3 + 1] = 0.115771f;	val_dir[13319*3 + 2] = -0.984050f;
+ 	val_dir[13320*3 + 0] = -0.115771f;	val_dir[13320*3 + 1] = 0.135066f;	val_dir[13320*3 + 2] = -0.984050f;
+ 	val_dir[13321*3 + 0] = -0.096404f;	val_dir[13321*3 + 1] = 0.154246f;	val_dir[13321*3 + 2] = -0.983318f;
+ 	val_dir[13322*3 + 0] = -0.077009f;	val_dir[13322*3 + 1] = 0.173269f;	val_dir[13322*3 + 2] = -0.981859f;
+ 	val_dir[13323*3 + 0] = -0.057628f;	val_dir[13323*3 + 1] = 0.192095f;	val_dir[13323*3 + 2] = -0.979683f;
+ 	val_dir[13324*3 + 0] = -0.038306f;	val_dir[13324*3 + 1] = 0.210683f;	val_dir[13324*3 + 2] = -0.976804f;
+ 	val_dir[13325*3 + 0] = -0.019083f;	val_dir[13325*3 + 1] = 0.228998f;	val_dir[13325*3 + 2] = -0.973240f;
+ 	val_dir[13326*3 + 0] = 0.0f;	val_dir[13326*3 + 1] = 0.247004f;	val_dir[13326*3 + 2] = -0.969015f;
+ 	val_dir[13327*3 + 0] = 0.019619f;	val_dir[13327*3 + 1] = 0.274668f;	val_dir[13327*3 + 2] = -0.961339f;
+ 	val_dir[13328*3 + 0] = 0.040505f;	val_dir[13328*3 + 1] = 0.303791f;	val_dir[13328*3 + 2] = -0.951877f;
+ 	val_dir[13329*3 + 0] = 0.062691f;	val_dir[13329*3 + 1] = 0.334351f;	val_dir[13329*3 + 2] = -0.940361f;
+ 	val_dir[13330*3 + 0] = 0.086186f;	val_dir[13330*3 + 1] = 0.366291f;	val_dir[13330*3 + 2] = -0.92650f;
+ 	val_dir[13331*3 + 0] = 0.110974f;	val_dir[13331*3 + 1] = 0.399507f;	val_dir[13331*3 + 2] = -0.909988f;
+ 	val_dir[13332*3 + 0] = 0.137002f;	val_dir[13332*3 + 1] = 0.433840f;	val_dir[13332*3 + 2] = -0.890513f;
+ 	val_dir[13333*3 + 0] = 0.164173f;	val_dir[13333*3 + 1] = 0.469065f;	val_dir[13333*3 + 2] = -0.867770f;
+ 	val_dir[13334*3 + 0] = 0.192339f;	val_dir[13334*3 + 1] = 0.504889f;	val_dir[13334*3 + 2] = -0.841482f;
+ 	val_dir[13335*3 + 0] = 0.221297f;	val_dir[13335*3 + 1] = 0.540947f;	val_dir[13335*3 + 2] = -0.811421f;
+ 	val_dir[13336*3 + 0] = 0.250785f;	val_dir[13336*3 + 1] = 0.576805f;	val_dir[13336*3 + 2] = -0.777433f;
+ 	val_dir[13337*3 + 0] = 0.280488f;	val_dir[13337*3 + 1] = 0.611974f;	val_dir[13337*3 + 2] = -0.739469f;
+ 	val_dir[13338*3 + 0] = 0.310045f;	val_dir[13338*3 + 1] = 0.645928f;	val_dir[13338*3 + 2] = -0.697602f;
+ 	val_dir[13339*3 + 0] = 0.339066f;	val_dir[13339*3 + 1] = 0.678133f;	val_dir[13339*3 + 2] = -0.652051f;
+ 	val_dir[13340*3 + 0] = 0.367152f;	val_dir[13340*3 + 1] = 0.708079f;	val_dir[13340*3 + 2] = -0.603178f;
+ 	val_dir[13341*3 + 0] = 0.393919f;	val_dir[13341*3 + 1] = 0.735316f;	val_dir[13341*3 + 2] = -0.551487f;
+ 	val_dir[13342*3 + 0] = 0.419026f;	val_dir[13342*3 + 1] = 0.759485f;	val_dir[13342*3 + 2] = -0.497594f;
+ 	val_dir[13343*3 + 0] = 0.442193f;	val_dir[13343*3 + 1] = 0.780340f;	val_dir[13343*3 + 2] = -0.442193f;
+ 	val_dir[13344*3 + 0] = 0.463217f;	val_dir[13344*3 + 1] = 0.797762f;	val_dir[13344*3 + 2] = -0.386014f;
+ 	val_dir[13345*3 + 0] = 0.481979f;	val_dir[13345*3 + 1] = 0.811754f;	val_dir[13345*3 + 2] = -0.329775f;
+ 	val_dir[13346*3 + 0] = 0.498445f;	val_dir[13346*3 + 1] = 0.822434f;	val_dir[13346*3 + 2] = -0.274145f;
+ 	val_dir[13347*3 + 0] = 0.512653f;	val_dir[13347*3 + 1] = 0.830009f;	val_dir[13347*3 + 2] = -0.219708f;
+ 	val_dir[13348*3 + 0] = 0.524703f;	val_dir[13348*3 + 1] = 0.834754f;	val_dir[13348*3 + 2] = -0.166951f;
+ 	val_dir[13349*3 + 0] = 0.534739f;	val_dir[13349*3 + 1] = 0.836983f;	val_dir[13349*3 + 2] = -0.116248f;
+ 	val_dir[13350*3 + 0] = 0.542936f;	val_dir[13350*3 + 1] = 0.837027f;	val_dir[13350*3 + 2] = -0.067867f;
+ 	val_dir[13351*3 + 0] = 0.549484f;	val_dir[13351*3 + 1] = 0.835215f;	val_dir[13351*3 + 2] = -0.021979f;
+ 	val_dir[13352*3 + 0] = -0.841879f;	val_dir[13352*3 + 1] = -0.539666f;	val_dir[13352*3 + 2] = 0.0f;
+ 	val_dir[13353*3 + 0] = -0.844653f;	val_dir[13353*3 + 1] = -0.533465f;	val_dir[13353*3 + 2] = -0.044455f;
+ 	val_dir[13354*3 + 0] = -0.845728f;	val_dir[13354*3 + 1] = -0.525723f;	val_dir[13354*3 + 2] = -0.091430f;
+ 	val_dir[13355*3 + 0] = -0.844782f;	val_dir[13355*3 + 1] = -0.516256f;	val_dir[13355*3 + 2] = -0.140797f;
+ 	val_dir[13356*3 + 0] = -0.841482f;	val_dir[13356*3 + 1] = -0.504889f;	val_dir[13356*3 + 2] = -0.192339f;
+ 	val_dir[13357*3 + 0] = -0.835504f;	val_dir[13357*3 + 1] = -0.491473f;	val_dir[13357*3 + 2] = -0.245737f;
+ 	val_dir[13358*3 + 0] = -0.826551f;	val_dir[13358*3 + 1] = -0.475893f;	val_dir[13358*3 + 2] = -0.300564f;
+ 	val_dir[13359*3 + 0] = -0.814379f;	val_dir[13359*3 + 1] = -0.458088f;	val_dir[13359*3 + 2] = -0.356291f;
+ 	val_dir[13360*3 + 0] = -0.798820f;	val_dir[13360*3 + 1] = -0.438063f;	val_dir[13360*3 + 2] = -0.412294f;
+ 	val_dir[13361*3 + 0] = -0.779813f;	val_dir[13361*3 + 1] = -0.41590f;	val_dir[13361*3 + 2] = -0.467888f;
+ 	val_dir[13362*3 + 0] = -0.757410f;	val_dir[13362*3 + 1] = -0.391764f;	val_dir[13362*3 + 2] = -0.522352f;
+ 	val_dir[13363*3 + 0] = -0.731792f;	val_dir[13363*3 + 1] = -0.365896f;	val_dir[13363*3 + 2] = -0.574979f;
+ 	val_dir[13364*3 + 0] = -0.703259f;	val_dir[13364*3 + 1] = -0.338606f;	val_dir[13364*3 + 2] = -0.625119f;
+ 	val_dir[13365*3 + 0] = -0.672214f;	val_dir[13365*3 + 1] = -0.310253f;	val_dir[13365*3 + 2] = -0.672214f;
+ 	val_dir[13366*3 + 0] = -0.639138f;	val_dir[13366*3 + 1] = -0.281220f;	val_dir[13366*3 + 2] = -0.715834f;
+ 	val_dir[13367*3 + 0] = -0.604551f;	val_dir[13367*3 + 1] = -0.251896f;	val_dir[13367*3 + 2] = -0.755689f;
+ 	val_dir[13368*3 + 0] = -0.568986f;	val_dir[13368*3 + 1] = -0.222647f;	val_dir[13368*3 + 2] = -0.791633f;
+ 	val_dir[13369*3 + 0] = -0.532952f;	val_dir[13369*3 + 1] = -0.193801f;	val_dir[13369*3 + 2] = -0.823653f;
+ 	val_dir[13370*3 + 0] = -0.496911f;	val_dir[13370*3 + 1] = -0.165637f;	val_dir[13370*3 + 2] = -0.851847f;
+ 	val_dir[13371*3 + 0] = -0.461266f;	val_dir[13371*3 + 1] = -0.138380f;	val_dir[13371*3 + 2] = -0.876405f;
+ 	val_dir[13372*3 + 0] = -0.426348f;	val_dir[13372*3 + 1] = -0.112197f;	val_dir[13372*3 + 2] = -0.897574f;
+ 	val_dir[13373*3 + 0] = -0.392419f;	val_dir[13373*3 + 1] = -0.087204f;	val_dir[13373*3 + 2] = -0.915644f;
+ 	val_dir[13374*3 + 0] = -0.359673f;	val_dir[13374*3 + 1] = -0.063472f;	val_dir[13374*3 + 2] = -0.930917f;
+ 	val_dir[13375*3 + 0] = -0.328244f;	val_dir[13375*3 + 1] = -0.041030f;	val_dir[13375*3 + 2] = -0.943701f;
+ 	val_dir[13376*3 + 0] = -0.298216f;	val_dir[13376*3 + 1] = -0.019881f;	val_dir[13376*3 + 2] = -0.954291f;
+ 	val_dir[13377*3 + 0] = -0.269630f;	val_dir[13377*3 + 1] = 0.0f;	val_dir[13377*3 + 2] = -0.962964f;
+ 	val_dir[13378*3 + 0] = -0.251587f;	val_dir[13378*3 + 1] = 0.019353f;	val_dir[13378*3 + 2] = -0.967641f;
+ 	val_dir[13379*3 + 0] = -0.233197f;	val_dir[13379*3 + 1] = 0.038866f;	val_dir[13379*3 + 2] = -0.971653f;
+ 	val_dir[13380*3 + 0] = -0.214494f;	val_dir[13380*3 + 1] = 0.058498f;	val_dir[13380*3 + 2] = -0.974972f;
+ 	val_dir[13381*3 + 0] = -0.195515f;	val_dir[13381*3 + 1] = 0.078206f;	val_dir[13381*3 + 2] = -0.977577f;
+ 	val_dir[13382*3 + 0] = -0.176301f;	val_dir[13382*3 + 1] = 0.097945f;	val_dir[13382*3 + 2] = -0.979451f;
+ 	val_dir[13383*3 + 0] = -0.156893f;	val_dir[13383*3 + 1] = 0.117670f;	val_dir[13383*3 + 2] = -0.980581f;
+ 	val_dir[13384*3 + 0] = -0.137334f;	val_dir[13384*3 + 1] = 0.137334f;	val_dir[13384*3 + 2] = -0.980958f;
+ 	val_dir[13385*3 + 0] = -0.117670f;	val_dir[13385*3 + 1] = 0.156893f;	val_dir[13385*3 + 2] = -0.980581f;
+ 	val_dir[13386*3 + 0] = -0.097945f;	val_dir[13386*3 + 1] = 0.176301f;	val_dir[13386*3 + 2] = -0.979451f;
+ 	val_dir[13387*3 + 0] = -0.078206f;	val_dir[13387*3 + 1] = 0.195515f;	val_dir[13387*3 + 2] = -0.977577f;
+ 	val_dir[13388*3 + 0] = -0.058498f;	val_dir[13388*3 + 1] = 0.214494f;	val_dir[13388*3 + 2] = -0.974972f;
+ 	val_dir[13389*3 + 0] = -0.038866f;	val_dir[13389*3 + 1] = 0.233197f;	val_dir[13389*3 + 2] = -0.971653f;
+ 	val_dir[13390*3 + 0] = -0.019353f;	val_dir[13390*3 + 1] = 0.251587f;	val_dir[13390*3 + 2] = -0.967641f;
+ 	val_dir[13391*3 + 0] = 0.0f;	val_dir[13391*3 + 1] = 0.269630f;	val_dir[13391*3 + 2] = -0.962964f;
+ 	val_dir[13392*3 + 0] = 0.019881f;	val_dir[13392*3 + 1] = 0.298216f;	val_dir[13392*3 + 2] = -0.954291f;
+ 	val_dir[13393*3 + 0] = 0.041030f;	val_dir[13393*3 + 1] = 0.328244f;	val_dir[13393*3 + 2] = -0.943701f;
+ 	val_dir[13394*3 + 0] = 0.063472f;	val_dir[13394*3 + 1] = 0.359673f;	val_dir[13394*3 + 2] = -0.930917f;
+ 	val_dir[13395*3 + 0] = 0.087204f;	val_dir[13395*3 + 1] = 0.392419f;	val_dir[13395*3 + 2] = -0.915644f;
+ 	val_dir[13396*3 + 0] = 0.112197f;	val_dir[13396*3 + 1] = 0.426348f;	val_dir[13396*3 + 2] = -0.897574f;
+ 	val_dir[13397*3 + 0] = 0.138380f;	val_dir[13397*3 + 1] = 0.461266f;	val_dir[13397*3 + 2] = -0.876405f;
+ 	val_dir[13398*3 + 0] = 0.165637f;	val_dir[13398*3 + 1] = 0.496911f;	val_dir[13398*3 + 2] = -0.851847f;
+ 	val_dir[13399*3 + 0] = 0.193801f;	val_dir[13399*3 + 1] = 0.532952f;	val_dir[13399*3 + 2] = -0.823653f;
+ 	val_dir[13400*3 + 0] = 0.222647f;	val_dir[13400*3 + 1] = 0.568986f;	val_dir[13400*3 + 2] = -0.791633f;
+ 	val_dir[13401*3 + 0] = 0.251896f;	val_dir[13401*3 + 1] = 0.604551f;	val_dir[13401*3 + 2] = -0.755689f;
+ 	val_dir[13402*3 + 0] = 0.281220f;	val_dir[13402*3 + 1] = 0.639138f;	val_dir[13402*3 + 2] = -0.715834f;
+ 	val_dir[13403*3 + 0] = 0.310253f;	val_dir[13403*3 + 1] = 0.672214f;	val_dir[13403*3 + 2] = -0.672214f;
+ 	val_dir[13404*3 + 0] = 0.338606f;	val_dir[13404*3 + 1] = 0.703259f;	val_dir[13404*3 + 2] = -0.625119f;
+ 	val_dir[13405*3 + 0] = 0.365896f;	val_dir[13405*3 + 1] = 0.731792f;	val_dir[13405*3 + 2] = -0.574979f;
+ 	val_dir[13406*3 + 0] = 0.391764f;	val_dir[13406*3 + 1] = 0.757410f;	val_dir[13406*3 + 2] = -0.522352f;
+ 	val_dir[13407*3 + 0] = 0.41590f;	val_dir[13407*3 + 1] = 0.779813f;	val_dir[13407*3 + 2] = -0.467888f;
+ 	val_dir[13408*3 + 0] = 0.438063f;	val_dir[13408*3 + 1] = 0.798820f;	val_dir[13408*3 + 2] = -0.412294f;
+ 	val_dir[13409*3 + 0] = 0.458088f;	val_dir[13409*3 + 1] = 0.814379f;	val_dir[13409*3 + 2] = -0.356291f;
+ 	val_dir[13410*3 + 0] = 0.475893f;	val_dir[13410*3 + 1] = 0.826551f;	val_dir[13410*3 + 2] = -0.300564f;
+ 	val_dir[13411*3 + 0] = 0.491473f;	val_dir[13411*3 + 1] = 0.835504f;	val_dir[13411*3 + 2] = -0.245737f;
+ 	val_dir[13412*3 + 0] = 0.504889f;	val_dir[13412*3 + 1] = 0.841482f;	val_dir[13412*3 + 2] = -0.192339f;
+ 	val_dir[13413*3 + 0] = 0.516256f;	val_dir[13413*3 + 1] = 0.844782f;	val_dir[13413*3 + 2] = -0.140797f;
+ 	val_dir[13414*3 + 0] = 0.525723f;	val_dir[13414*3 + 1] = 0.845728f;	val_dir[13414*3 + 2] = -0.091430f;
+ 	val_dir[13415*3 + 0] = 0.533465f;	val_dir[13415*3 + 1] = 0.844653f;	val_dir[13415*3 + 2] = -0.044455f;
+ 	val_dir[13416*3 + 0] = 0.539666f;	val_dir[13416*3 + 1] = 0.841879f;	val_dir[13416*3 + 2] = 0.0f;
+ 	val_dir[13417*3 + 0] = -0.851455f;	val_dir[13417*3 + 1] = -0.523973f;	val_dir[13417*3 + 2] = -0.021832f;
+ 	val_dir[13418*3 + 0] = -0.853556f;	val_dir[13418*3 + 1] = -0.516626f;	val_dir[13418*3 + 2] = -0.067386f;
+ 	val_dir[13419*3 + 0] = -0.853796f;	val_dir[13419*3 + 1] = -0.507662f;	val_dir[13419*3 + 2] = -0.115378f;
+ 	val_dir[13420*3 + 0] = -0.851847f;	val_dir[13420*3 + 1] = -0.496911f;	val_dir[13420*3 + 2] = -0.165637f;
+ 	val_dir[13421*3 + 0] = -0.847381f;	val_dir[13421*3 + 1] = -0.484217f;	val_dir[13421*3 + 2] = -0.217898f;
+ 	val_dir[13422*3 + 0] = -0.840083f;	val_dir[13422*3 + 1] = -0.469458f;	val_dir[13422*3 + 2] = -0.271791f;
+ 	val_dir[13423*3 + 0] = -0.829680f;	val_dir[13423*3 + 1] = -0.452553f;	val_dir[13423*3 + 2] = -0.326844f;
+ 	val_dir[13424*3 + 0] = -0.815966f;	val_dir[13424*3 + 1] = -0.433482f;	val_dir[13424*3 + 2] = -0.382484f;
+ 	val_dir[13425*3 + 0] = -0.798820f;	val_dir[13425*3 + 1] = -0.412294f;	val_dir[13425*3 + 2] = -0.438063f;
+ 	val_dir[13426*3 + 0] = -0.778237f;	val_dir[13426*3 + 1] = -0.389118f;	val_dir[13426*3 + 2] = -0.492883f;
+ 	val_dir[13427*3 + 0] = -0.754329f;	val_dir[13427*3 + 1] = -0.364159f;	val_dir[13427*3 + 2] = -0.546238f;
+ 	val_dir[13428*3 + 0] = -0.727334f;	val_dir[13428*3 + 1] = -0.337691f;	val_dir[13428*3 + 2] = -0.597453f;
+ 	val_dir[13429*3 + 0] = -0.697602f;	val_dir[13429*3 + 1] = -0.310045f;	val_dir[13429*3 + 2] = -0.645928f;
+ 	val_dir[13430*3 + 0] = -0.665574f;	val_dir[13430*3 + 1] = -0.281589f;	val_dir[13430*3 + 2] = -0.691173f;
+ 	val_dir[13431*3 + 0] = -0.631748f;	val_dir[13431*3 + 1] = -0.252699f;	val_dir[13431*3 + 2] = -0.732828f;
+ 	val_dir[13432*3 + 0] = -0.596653f;	val_dir[13432*3 + 1] = -0.223745f;	val_dir[13432*3 + 2] = -0.770677f;
+ 	val_dir[13433*3 + 0] = -0.560809f;	val_dir[13433*3 + 1] = -0.195064f;	val_dir[13433*3 + 2] = -0.804639f;
+ 	val_dir[13434*3 + 0] = -0.524703f;	val_dir[13434*3 + 1] = -0.166951f;	val_dir[13434*3 + 2] = -0.834754f;
+ 	val_dir[13435*3 + 0] = -0.488769f;	val_dir[13435*3 + 1] = -0.139648f;	val_dir[13435*3 + 2] = -0.861164f;
+ 	val_dir[13436*3 + 0] = -0.453376f;	val_dir[13436*3 + 1] = -0.113344f;	val_dir[13436*3 + 2] = -0.884083f;
+ 	val_dir[13437*3 + 0] = -0.418823f;	val_dir[13437*3 + 1] = -0.088173f;	val_dir[13437*3 + 2] = -0.903777f;
+ 	val_dir[13438*3 + 0] = -0.385341f;	val_dir[13438*3 + 1] = -0.064223f;	val_dir[13438*3 + 2] = -0.920537f;
+ 	val_dir[13439*3 + 0] = -0.353096f;	val_dir[13439*3 + 1] = -0.041541f;	val_dir[13439*3 + 2] = -0.934665f;
+ 	val_dir[13440*3 + 0] = -0.322198f;	val_dir[13440*3 + 1] = -0.020137f;	val_dir[13440*3 + 2] = -0.946458f;
+ 	val_dir[13441*3 + 0] = -0.292714f;	val_dir[13441*3 + 1] = 0.0f;	val_dir[13441*3 + 2] = -0.95620f;
+ 	val_dir[13442*3 + 0] = -0.274668f;	val_dir[13442*3 + 1] = 0.019619f;	val_dir[13442*3 + 2] = -0.961339f;
+ 	val_dir[13443*3 + 0] = -0.256235f;	val_dir[13443*3 + 1] = 0.039421f;	val_dir[13443*3 + 2] = -0.965810f;
+ 	val_dir[13444*3 + 0] = -0.237449f;	val_dir[13444*3 + 1] = 0.059362f;	val_dir[13444*3 + 2] = -0.969584f;
+ 	val_dir[13445*3 + 0] = -0.218347f;	val_dir[13445*3 + 1] = 0.079399f;	val_dir[13445*3 + 2] = -0.972636f;
+ 	val_dir[13446*3 + 0] = -0.198968f;	val_dir[13446*3 + 1] = 0.099484f;	val_dir[13446*3 + 2] = -0.974943f;
+ 	val_dir[13447*3 + 0] = -0.179355f;	val_dir[13447*3 + 1] = 0.119570f;	val_dir[13447*3 + 2] = -0.976491f;
+ 	val_dir[13448*3 + 0] = -0.159554f;	val_dir[13448*3 + 1] = 0.139610f;	val_dir[13448*3 + 2] = -0.977267f;
+ 	val_dir[13449*3 + 0] = -0.139610f;	val_dir[13449*3 + 1] = 0.159554f;	val_dir[13449*3 + 2] = -0.977267f;
+ 	val_dir[13450*3 + 0] = -0.119570f;	val_dir[13450*3 + 1] = 0.179355f;	val_dir[13450*3 + 2] = -0.976491f;
+ 	val_dir[13451*3 + 0] = -0.099484f;	val_dir[13451*3 + 1] = 0.198968f;	val_dir[13451*3 + 2] = -0.974943f;
+ 	val_dir[13452*3 + 0] = -0.079399f;	val_dir[13452*3 + 1] = 0.218347f;	val_dir[13452*3 + 2] = -0.972636f;
+ 	val_dir[13453*3 + 0] = -0.059362f;	val_dir[13453*3 + 1] = 0.237449f;	val_dir[13453*3 + 2] = -0.969584f;
+ 	val_dir[13454*3 + 0] = -0.039421f;	val_dir[13454*3 + 1] = 0.256235f;	val_dir[13454*3 + 2] = -0.965810f;
+ 	val_dir[13455*3 + 0] = -0.019619f;	val_dir[13455*3 + 1] = 0.274668f;	val_dir[13455*3 + 2] = -0.961339f;
+ 	val_dir[13456*3 + 0] = 0.0f;	val_dir[13456*3 + 1] = 0.292714f;	val_dir[13456*3 + 2] = -0.95620f;
+ 	val_dir[13457*3 + 0] = 0.020137f;	val_dir[13457*3 + 1] = 0.322198f;	val_dir[13457*3 + 2] = -0.946458f;
+ 	val_dir[13458*3 + 0] = 0.041541f;	val_dir[13458*3 + 1] = 0.353096f;	val_dir[13458*3 + 2] = -0.934665f;
+ 	val_dir[13459*3 + 0] = 0.064223f;	val_dir[13459*3 + 1] = 0.385341f;	val_dir[13459*3 + 2] = -0.920537f;
+ 	val_dir[13460*3 + 0] = 0.088173f;	val_dir[13460*3 + 1] = 0.418823f;	val_dir[13460*3 + 2] = -0.903777f;
+ 	val_dir[13461*3 + 0] = 0.113344f;	val_dir[13461*3 + 1] = 0.453376f;	val_dir[13461*3 + 2] = -0.884083f;
+ 	val_dir[13462*3 + 0] = 0.139648f;	val_dir[13462*3 + 1] = 0.488769f;	val_dir[13462*3 + 2] = -0.861164f;
+ 	val_dir[13463*3 + 0] = 0.166951f;	val_dir[13463*3 + 1] = 0.524703f;	val_dir[13463*3 + 2] = -0.834754f;
+ 	val_dir[13464*3 + 0] = 0.195064f;	val_dir[13464*3 + 1] = 0.560809f;	val_dir[13464*3 + 2] = -0.804639f;
+ 	val_dir[13465*3 + 0] = 0.223745f;	val_dir[13465*3 + 1] = 0.596653f;	val_dir[13465*3 + 2] = -0.770677f;
+ 	val_dir[13466*3 + 0] = 0.252699f;	val_dir[13466*3 + 1] = 0.631748f;	val_dir[13466*3 + 2] = -0.732828f;
+ 	val_dir[13467*3 + 0] = 0.281589f;	val_dir[13467*3 + 1] = 0.665574f;	val_dir[13467*3 + 2] = -0.691173f;
+ 	val_dir[13468*3 + 0] = 0.310045f;	val_dir[13468*3 + 1] = 0.697602f;	val_dir[13468*3 + 2] = -0.645928f;
+ 	val_dir[13469*3 + 0] = 0.337691f;	val_dir[13469*3 + 1] = 0.727334f;	val_dir[13469*3 + 2] = -0.597453f;
+ 	val_dir[13470*3 + 0] = 0.364159f;	val_dir[13470*3 + 1] = 0.754329f;	val_dir[13470*3 + 2] = -0.546238f;
+ 	val_dir[13471*3 + 0] = 0.389118f;	val_dir[13471*3 + 1] = 0.778237f;	val_dir[13471*3 + 2] = -0.492883f;
+ 	val_dir[13472*3 + 0] = 0.412294f;	val_dir[13472*3 + 1] = 0.798820f;	val_dir[13472*3 + 2] = -0.438063f;
+ 	val_dir[13473*3 + 0] = 0.433482f;	val_dir[13473*3 + 1] = 0.815966f;	val_dir[13473*3 + 2] = -0.382484f;
+ 	val_dir[13474*3 + 0] = 0.452553f;	val_dir[13474*3 + 1] = 0.829680f;	val_dir[13474*3 + 2] = -0.326844f;
+ 	val_dir[13475*3 + 0] = 0.469458f;	val_dir[13475*3 + 1] = 0.840083f;	val_dir[13475*3 + 2] = -0.271791f;
+ 	val_dir[13476*3 + 0] = 0.484217f;	val_dir[13476*3 + 1] = 0.847381f;	val_dir[13476*3 + 2] = -0.217898f;
+ 	val_dir[13477*3 + 0] = 0.496911f;	val_dir[13477*3 + 1] = 0.851847f;	val_dir[13477*3 + 2] = -0.165637f;
+ 	val_dir[13478*3 + 0] = 0.507662f;	val_dir[13478*3 + 1] = 0.853796f;	val_dir[13478*3 + 2] = -0.115378f;
+ 	val_dir[13479*3 + 0] = 0.516626f;	val_dir[13479*3 + 1] = 0.853556f;	val_dir[13479*3 + 2] = -0.067386f;
+ 	val_dir[13480*3 + 0] = 0.523973f;	val_dir[13480*3 + 1] = 0.851455f;	val_dir[13480*3 + 2] = -0.021832f;
+ 	val_dir[13481*3 + 0] = -0.857493f;	val_dir[13481*3 + 1] = -0.514496f;	val_dir[13481*3 + 2] = 0.0f;
+ 	val_dir[13482*3 + 0] = -0.860527f;	val_dir[13482*3 + 1] = -0.507490f;	val_dir[13482*3 + 2] = -0.044130f;
+ 	val_dir[13483*3 + 0] = -0.861857f;	val_dir[13483*3 + 1] = -0.498970f;	val_dir[13483*3 + 2] = -0.090722f;
+ 	val_dir[13484*3 + 0] = -0.861164f;	val_dir[13484*3 + 1] = -0.488769f;	val_dir[13484*3 + 2] = -0.139648f;
+ 	val_dir[13485*3 + 0] = -0.858116f;	val_dir[13485*3 + 1] = -0.476731f;	val_dir[13485*3 + 2] = -0.190693f;
+ 	val_dir[13486*3 + 0] = -0.852392f;	val_dir[13486*3 + 1] = -0.462727f;	val_dir[13486*3 + 2] = -0.243541f;
+ 	val_dir[13487*3 + 0] = -0.843696f;	val_dir[13487*3 + 1] = -0.446662f;	val_dir[13487*3 + 2] = -0.297775f;
+ 	val_dir[13488*3 + 0] = -0.831786f;	val_dir[13488*3 + 1] = -0.428496f;	val_dir[13488*3 + 2] = -0.352879f;
+ 	val_dir[13489*3 + 0] = -0.816497f;	val_dir[13489*3 + 1] = -0.408248f;	val_dir[13489*3 + 2] = -0.408248f;
+ 	val_dir[13490*3 + 0] = -0.797762f;	val_dir[13490*3 + 1] = -0.386014f;	val_dir[13490*3 + 2] = -0.463217f;
+ 	val_dir[13491*3 + 0] = -0.775632f;	val_dir[13491*3 + 1] = -0.361961f;	val_dir[13491*3 + 2] = -0.517088f;
+ 	val_dir[13492*3 + 0] = -0.750279f;	val_dir[13492*3 + 1] = -0.336332f;	val_dir[13492*3 + 2] = -0.569177f;
+ 	val_dir[13493*3 + 0] = -0.721995f;	val_dir[13493*3 + 1] = -0.309426f;	val_dir[13493*3 + 2] = -0.618853f;
+ 	val_dir[13494*3 + 0] = -0.691173f;	val_dir[13494*3 + 1] = -0.281589f;	val_dir[13494*3 + 2] = -0.665574f;
+ 	val_dir[13495*3 + 0] = -0.658281f;	val_dir[13495*3 + 1] = -0.253185f;	val_dir[13495*3 + 2] = -0.708918f;
+ 	val_dir[13496*3 + 0] = -0.623831f;	val_dir[13496*3 + 1] = -0.224579f;	val_dir[13496*3 + 2] = -0.748598f;
+ 	val_dir[13497*3 + 0] = -0.588348f;	val_dir[13497*3 + 1] = -0.196116f;	val_dir[13497*3 + 2] = -0.784465f;
+ 	val_dir[13498*3 + 0] = -0.552336f;	val_dir[13498*3 + 1] = -0.168102f;	val_dir[13498*3 + 2] = -0.816497f;
+ 	val_dir[13499*3 + 0] = -0.516256f;	val_dir[13499*3 + 1] = -0.140797f;	val_dir[13499*3 + 2] = -0.844782f;
+ 	val_dir[13500*3 + 0] = -0.480510f;	val_dir[13500*3 + 1] = -0.114407f;	val_dir[13500*3 + 2] = -0.869495f;
+ 	val_dir[13501*3 + 0] = -0.445435f;	val_dir[13501*3 + 1] = -0.089087f;	val_dir[13501*3 + 2] = -0.890871f;
+ 	val_dir[13502*3 + 0] = -0.411298f;	val_dir[13502*3 + 1] = -0.064942f;	val_dir[13502*3 + 2] = -0.909185f;
+ 	val_dir[13503*3 + 0] = -0.378298f;	val_dir[13503*3 + 1] = -0.042033f;	val_dir[13503*3 + 2] = -0.924729f;
+ 	val_dir[13504*3 + 0] = -0.346578f;	val_dir[13504*3 + 1] = -0.020387f;	val_dir[13504*3 + 2] = -0.93780f;
+ 	val_dir[13505*3 + 0] = -0.316228f;	val_dir[13505*3 + 1] = 0.0f;	val_dir[13505*3 + 2] = -0.948683f;
+ 	val_dir[13506*3 + 0] = -0.298216f;	val_dir[13506*3 + 1] = 0.019881f;	val_dir[13506*3 + 2] = -0.954291f;
+ 	val_dir[13507*3 + 0] = -0.279776f;	val_dir[13507*3 + 1] = 0.039968f;	val_dir[13507*3 + 2] = -0.959233f;
+ 	val_dir[13508*3 + 0] = -0.260941f;	val_dir[13508*3 + 1] = 0.060217f;	val_dir[13508*3 + 2] = -0.963475f;
+ 	val_dir[13509*3 + 0] = -0.241747f;	val_dir[13509*3 + 1] = 0.080582f;	val_dir[13509*3 + 2] = -0.966988f;
+ 	val_dir[13510*3 + 0] = -0.222234f;	val_dir[13510*3 + 1] = 0.101015f;	val_dir[13510*3 + 2] = -0.969746f;
+ 	val_dir[13511*3 + 0] = -0.202444f;	val_dir[13511*3 + 1] = 0.121466f;	val_dir[13511*3 + 2] = -0.971732f;
+ 	val_dir[13512*3 + 0] = -0.182424f;	val_dir[13512*3 + 1] = 0.141885f;	val_dir[13512*3 + 2] = -0.972929f;
+ 	val_dir[13513*3 + 0] = -0.162221f;	val_dir[13513*3 + 1] = 0.162221f;	val_dir[13513*3 + 2] = -0.973329f;
+ 	val_dir[13514*3 + 0] = -0.141885f;	val_dir[13514*3 + 1] = 0.182424f;	val_dir[13514*3 + 2] = -0.972929f;
+ 	val_dir[13515*3 + 0] = -0.121466f;	val_dir[13515*3 + 1] = 0.202444f;	val_dir[13515*3 + 2] = -0.971732f;
+ 	val_dir[13516*3 + 0] = -0.101015f;	val_dir[13516*3 + 1] = 0.222234f;	val_dir[13516*3 + 2] = -0.969746f;
+ 	val_dir[13517*3 + 0] = -0.080582f;	val_dir[13517*3 + 1] = 0.241747f;	val_dir[13517*3 + 2] = -0.966988f;
+ 	val_dir[13518*3 + 0] = -0.060217f;	val_dir[13518*3 + 1] = 0.260941f;	val_dir[13518*3 + 2] = -0.963475f;
+ 	val_dir[13519*3 + 0] = -0.039968f;	val_dir[13519*3 + 1] = 0.279776f;	val_dir[13519*3 + 2] = -0.959233f;
+ 	val_dir[13520*3 + 0] = -0.019881f;	val_dir[13520*3 + 1] = 0.298216f;	val_dir[13520*3 + 2] = -0.954291f;
+ 	val_dir[13521*3 + 0] = 0.0f;	val_dir[13521*3 + 1] = 0.316228f;	val_dir[13521*3 + 2] = -0.948683f;
+ 	val_dir[13522*3 + 0] = 0.020387f;	val_dir[13522*3 + 1] = 0.346578f;	val_dir[13522*3 + 2] = -0.93780f;
+ 	val_dir[13523*3 + 0] = 0.042033f;	val_dir[13523*3 + 1] = 0.378298f;	val_dir[13523*3 + 2] = -0.924729f;
+ 	val_dir[13524*3 + 0] = 0.064942f;	val_dir[13524*3 + 1] = 0.411298f;	val_dir[13524*3 + 2] = -0.909185f;
+ 	val_dir[13525*3 + 0] = 0.089087f;	val_dir[13525*3 + 1] = 0.445435f;	val_dir[13525*3 + 2] = -0.890871f;
+ 	val_dir[13526*3 + 0] = 0.114407f;	val_dir[13526*3 + 1] = 0.480510f;	val_dir[13526*3 + 2] = -0.869495f;
+ 	val_dir[13527*3 + 0] = 0.140797f;	val_dir[13527*3 + 1] = 0.516256f;	val_dir[13527*3 + 2] = -0.844782f;
+ 	val_dir[13528*3 + 0] = 0.168102f;	val_dir[13528*3 + 1] = 0.552336f;	val_dir[13528*3 + 2] = -0.816497f;
+ 	val_dir[13529*3 + 0] = 0.196116f;	val_dir[13529*3 + 1] = 0.588348f;	val_dir[13529*3 + 2] = -0.784465f;
+ 	val_dir[13530*3 + 0] = 0.224579f;	val_dir[13530*3 + 1] = 0.623831f;	val_dir[13530*3 + 2] = -0.748598f;
+ 	val_dir[13531*3 + 0] = 0.253185f;	val_dir[13531*3 + 1] = 0.658281f;	val_dir[13531*3 + 2] = -0.708918f;
+ 	val_dir[13532*3 + 0] = 0.281589f;	val_dir[13532*3 + 1] = 0.691173f;	val_dir[13532*3 + 2] = -0.665574f;
+ 	val_dir[13533*3 + 0] = 0.309426f;	val_dir[13533*3 + 1] = 0.721995f;	val_dir[13533*3 + 2] = -0.618853f;
+ 	val_dir[13534*3 + 0] = 0.336332f;	val_dir[13534*3 + 1] = 0.750279f;	val_dir[13534*3 + 2] = -0.569177f;
+ 	val_dir[13535*3 + 0] = 0.361961f;	val_dir[13535*3 + 1] = 0.775632f;	val_dir[13535*3 + 2] = -0.517088f;
+ 	val_dir[13536*3 + 0] = 0.386014f;	val_dir[13536*3 + 1] = 0.797762f;	val_dir[13536*3 + 2] = -0.463217f;
+ 	val_dir[13537*3 + 0] = 0.408248f;	val_dir[13537*3 + 1] = 0.816497f;	val_dir[13537*3 + 2] = -0.408248f;
+ 	val_dir[13538*3 + 0] = 0.428496f;	val_dir[13538*3 + 1] = 0.831786f;	val_dir[13538*3 + 2] = -0.352879f;
+ 	val_dir[13539*3 + 0] = 0.446662f;	val_dir[13539*3 + 1] = 0.843696f;	val_dir[13539*3 + 2] = -0.297775f;
+ 	val_dir[13540*3 + 0] = 0.462727f;	val_dir[13540*3 + 1] = 0.852392f;	val_dir[13540*3 + 2] = -0.243541f;
+ 	val_dir[13541*3 + 0] = 0.476731f;	val_dir[13541*3 + 1] = 0.858116f;	val_dir[13541*3 + 2] = -0.190693f;
+ 	val_dir[13542*3 + 0] = 0.488769f;	val_dir[13542*3 + 1] = 0.861164f;	val_dir[13542*3 + 2] = -0.139648f;
+ 	val_dir[13543*3 + 0] = 0.498970f;	val_dir[13543*3 + 1] = 0.861857f;	val_dir[13543*3 + 2] = -0.090722f;
+ 	val_dir[13544*3 + 0] = 0.507490f;	val_dir[13544*3 + 1] = 0.860527f;	val_dir[13544*3 + 2] = -0.044130f;
+ 	val_dir[13545*3 + 0] = 0.514496f;	val_dir[13545*3 + 1] = 0.857493f;	val_dir[13545*3 + 2] = 0.0f;
+ 	val_dir[13546*3 + 0] = -0.866703f;	val_dir[13546*3 + 1] = -0.498354f;	val_dir[13546*3 + 2] = -0.021668f;
+ 	val_dir[13547*3 + 0] = -0.869030f;	val_dir[13547*3 + 1] = -0.490222f;	val_dir[13547*3 + 2] = -0.066848f;
+ 	val_dir[13548*3 + 0] = -0.869495f;	val_dir[13548*3 + 1] = -0.480510f;	val_dir[13548*3 + 2] = -0.114407f;
+ 	val_dir[13549*3 + 0] = -0.867770f;	val_dir[13549*3 + 1] = -0.469065f;	val_dir[13549*3 + 2] = -0.164173f;
+ 	val_dir[13550*3 + 0] = -0.863530f;	val_dir[13550*3 + 1] = -0.455752f;	val_dir[13550*3 + 2] = -0.215883f;
+ 	val_dir[13551*3 + 0] = -0.856465f;	val_dir[13551*3 + 1] = -0.440468f;	val_dir[13551*3 + 2] = -0.269175f;
+ 	val_dir[13552*3 + 0] = -0.846305f;	val_dir[13552*3 + 1] = -0.423153f;	val_dir[13552*3 + 2] = -0.323587f;
+ 	val_dir[13553*3 + 0] = -0.832845f;	val_dir[13553*3 + 1] = -0.403804f;	val_dir[13553*3 + 2] = -0.378566f;
+ 	val_dir[13554*3 + 0] = -0.815966f;	val_dir[13554*3 + 1] = -0.382484f;	val_dir[13554*3 + 2] = -0.433482f;
+ 	val_dir[13555*3 + 0] = -0.795657f;	val_dir[13555*3 + 1] = -0.359329f;	val_dir[13555*3 + 2] = -0.487661f;
+ 	val_dir[13556*3 + 0] = -0.772027f;	val_dir[13556*3 + 1] = -0.334545f;	val_dir[13556*3 + 2] = -0.540419f;
+ 	val_dir[13557*3 + 0] = -0.745307f;	val_dir[13557*3 + 1] = -0.308403f;	val_dir[13557*3 + 2] = -0.591105f;
+ 	val_dir[13558*3 + 0] = -0.715834f;	val_dir[13558*3 + 1] = -0.281220f;	val_dir[13558*3 + 2] = -0.639138f;
+ 	val_dir[13559*3 + 0] = -0.684038f;	val_dir[13559*3 + 1] = -0.253347f;	val_dir[13559*3 + 2] = -0.684038f;
+ 	val_dir[13560*3 + 0] = -0.650407f;	val_dir[13560*3 + 1] = -0.225141f;	val_dir[13560*3 + 2] = -0.725454f;
+ 	val_dir[13561*3 + 0] = -0.615457f;	val_dir[13561*3 + 1] = -0.196946f;	val_dir[13561*3 + 2] = -0.763167f;
+ 	val_dir[13562*3 + 0] = -0.579703f;	val_dir[13562*3 + 1] = -0.169080f;	val_dir[13562*3 + 2] = -0.797092f;
+ 	val_dir[13563*3 + 0] = -0.543627f;	val_dir[13563*3 + 1] = -0.141816f;	val_dir[13563*3 + 2] = -0.827259f;
+ 	val_dir[13564*3 + 0] = -0.507662f;	val_dir[13564*3 + 1] = -0.115378f;	val_dir[13564*3 + 2] = -0.853796f;
+ 	val_dir[13565*3 + 0] = -0.472178f;	val_dir[13565*3 + 1] = -0.089939f;	val_dir[13565*3 + 2] = -0.876903f;
+ 	val_dir[13566*3 + 0] = -0.437479f;	val_dir[13566*3 + 1] = -0.065622f;	val_dir[13566*3 + 2] = -0.896831f;
+ 	val_dir[13567*3 + 0] = -0.403799f;	val_dir[13567*3 + 1] = -0.042505f;	val_dir[13567*3 + 2] = -0.913860f;
+ 	val_dir[13568*3 + 0] = -0.371312f;	val_dir[13568*3 + 1] = -0.020628f;	val_dir[13568*3 + 2] = -0.928279f;
+ 	val_dir[13569*3 + 0] = -0.340136f;	val_dir[13569*3 + 1] = 0.0f;	val_dir[13569*3 + 2] = -0.940376f;
+ 	val_dir[13570*3 + 0] = -0.322198f;	val_dir[13570*3 + 1] = 0.020137f;	val_dir[13570*3 + 2] = -0.946458f;
+ 	val_dir[13571*3 + 0] = -0.303791f;	val_dir[13571*3 + 1] = 0.040505f;	val_dir[13571*3 + 2] = -0.951877f;
+ 	val_dir[13572*3 + 0] = -0.284944f;	val_dir[13572*3 + 1] = 0.061059f;	val_dir[13572*3 + 2] = -0.956597f;
+ 	val_dir[13573*3 + 0] = -0.265694f;	val_dir[13573*3 + 1] = 0.081752f;	val_dir[13573*3 + 2] = -0.960585f;
+ 	val_dir[13574*3 + 0] = -0.246079f;	val_dir[13574*3 + 1] = 0.102533f;	val_dir[13574*3 + 2] = -0.963811f;
+ 	val_dir[13575*3 + 0] = -0.226144f;	val_dir[13575*3 + 1] = 0.123351f;	val_dir[13575*3 + 2] = -0.966252f;
+ 	val_dir[13576*3 + 0] = -0.205934f;	val_dir[13576*3 + 1] = 0.144154f;	val_dir[13576*3 + 2] = -0.967890f;
+ 	val_dir[13577*3 + 0] = -0.185498f;	val_dir[13577*3 + 1] = 0.164887f;	val_dir[13577*3 + 2] = -0.968712f;
+ 	val_dir[13578*3 + 0] = -0.164887f;	val_dir[13578*3 + 1] = 0.185498f;	val_dir[13578*3 + 2] = -0.968712f;
+ 	val_dir[13579*3 + 0] = -0.144154f;	val_dir[13579*3 + 1] = 0.205934f;	val_dir[13579*3 + 2] = -0.967890f;
+ 	val_dir[13580*3 + 0] = -0.123351f;	val_dir[13580*3 + 1] = 0.226144f;	val_dir[13580*3 + 2] = -0.966252f;
+ 	val_dir[13581*3 + 0] = -0.102533f;	val_dir[13581*3 + 1] = 0.246079f;	val_dir[13581*3 + 2] = -0.963811f;
+ 	val_dir[13582*3 + 0] = -0.081752f;	val_dir[13582*3 + 1] = 0.265694f;	val_dir[13582*3 + 2] = -0.960585f;
+ 	val_dir[13583*3 + 0] = -0.061059f;	val_dir[13583*3 + 1] = 0.284944f;	val_dir[13583*3 + 2] = -0.956597f;
+ 	val_dir[13584*3 + 0] = -0.040505f;	val_dir[13584*3 + 1] = 0.303791f;	val_dir[13584*3 + 2] = -0.951877f;
+ 	val_dir[13585*3 + 0] = -0.020137f;	val_dir[13585*3 + 1] = 0.322198f;	val_dir[13585*3 + 2] = -0.946458f;
+ 	val_dir[13586*3 + 0] = 0.0f;	val_dir[13586*3 + 1] = 0.340136f;	val_dir[13586*3 + 2] = -0.940376f;
+ 	val_dir[13587*3 + 0] = 0.020628f;	val_dir[13587*3 + 1] = 0.371312f;	val_dir[13587*3 + 2] = -0.928279f;
+ 	val_dir[13588*3 + 0] = 0.042505f;	val_dir[13588*3 + 1] = 0.403799f;	val_dir[13588*3 + 2] = -0.913860f;
+ 	val_dir[13589*3 + 0] = 0.065622f;	val_dir[13589*3 + 1] = 0.437479f;	val_dir[13589*3 + 2] = -0.896831f;
+ 	val_dir[13590*3 + 0] = 0.089939f;	val_dir[13590*3 + 1] = 0.472178f;	val_dir[13590*3 + 2] = -0.876903f;
+ 	val_dir[13591*3 + 0] = 0.115378f;	val_dir[13591*3 + 1] = 0.507662f;	val_dir[13591*3 + 2] = -0.853796f;
+ 	val_dir[13592*3 + 0] = 0.141816f;	val_dir[13592*3 + 1] = 0.543627f;	val_dir[13592*3 + 2] = -0.827259f;
+ 	val_dir[13593*3 + 0] = 0.169080f;	val_dir[13593*3 + 1] = 0.579703f;	val_dir[13593*3 + 2] = -0.797092f;
+ 	val_dir[13594*3 + 0] = 0.196946f;	val_dir[13594*3 + 1] = 0.615457f;	val_dir[13594*3 + 2] = -0.763167f;
+ 	val_dir[13595*3 + 0] = 0.225141f;	val_dir[13595*3 + 1] = 0.650407f;	val_dir[13595*3 + 2] = -0.725454f;
+ 	val_dir[13596*3 + 0] = 0.253347f;	val_dir[13596*3 + 1] = 0.684038f;	val_dir[13596*3 + 2] = -0.684038f;
+ 	val_dir[13597*3 + 0] = 0.281220f;	val_dir[13597*3 + 1] = 0.715834f;	val_dir[13597*3 + 2] = -0.639138f;
+ 	val_dir[13598*3 + 0] = 0.308403f;	val_dir[13598*3 + 1] = 0.745307f;	val_dir[13598*3 + 2] = -0.591105f;
+ 	val_dir[13599*3 + 0] = 0.334545f;	val_dir[13599*3 + 1] = 0.772027f;	val_dir[13599*3 + 2] = -0.540419f;
+ 	val_dir[13600*3 + 0] = 0.359329f;	val_dir[13600*3 + 1] = 0.795657f;	val_dir[13600*3 + 2] = -0.487661f;
+ 	val_dir[13601*3 + 0] = 0.382484f;	val_dir[13601*3 + 1] = 0.815966f;	val_dir[13601*3 + 2] = -0.433482f;
+ 	val_dir[13602*3 + 0] = 0.403804f;	val_dir[13602*3 + 1] = 0.832845f;	val_dir[13602*3 + 2] = -0.378566f;
+ 	val_dir[13603*3 + 0] = 0.423153f;	val_dir[13603*3 + 1] = 0.846305f;	val_dir[13603*3 + 2] = -0.323587f;
+ 	val_dir[13604*3 + 0] = 0.440468f;	val_dir[13604*3 + 1] = 0.856465f;	val_dir[13604*3 + 2] = -0.269175f;
+ 	val_dir[13605*3 + 0] = 0.455752f;	val_dir[13605*3 + 1] = 0.863530f;	val_dir[13605*3 + 2] = -0.215883f;
+ 	val_dir[13606*3 + 0] = 0.469065f;	val_dir[13606*3 + 1] = 0.867770f;	val_dir[13606*3 + 2] = -0.164173f;
+ 	val_dir[13607*3 + 0] = 0.480510f;	val_dir[13607*3 + 1] = 0.869495f;	val_dir[13607*3 + 2] = -0.114407f;
+ 	val_dir[13608*3 + 0] = 0.490222f;	val_dir[13608*3 + 1] = 0.869030f;	val_dir[13608*3 + 2] = -0.066848f;
+ 	val_dir[13609*3 + 0] = 0.498354f;	val_dir[13609*3 + 1] = 0.866703f;	val_dir[13609*3 + 2] = -0.021668f;
+ 	val_dir[13610*3 + 0] = -0.872143f;	val_dir[13610*3 + 1] = -0.489251f;	val_dir[13610*3 + 2] = 0.0f;
+ 	val_dir[13611*3 + 0] = -0.875376f;	val_dir[13611*3 + 1] = -0.481457f;	val_dir[13611*3 + 2] = -0.043769f;
+ 	val_dir[13612*3 + 0] = -0.876903f;	val_dir[13612*3 + 1] = -0.472178f;	val_dir[13612*3 + 2] = -0.089939f;
+ 	val_dir[13613*3 + 0] = -0.876405f;	val_dir[13613*3 + 1] = -0.461266f;	val_dir[13613*3 + 2] = -0.138380f;
+ 	val_dir[13614*3 + 0] = -0.873555f;	val_dir[13614*3 + 1] = -0.448583f;	val_dir[13614*3 + 2] = -0.188877f;
+ 	val_dir[13615*3 + 0] = -0.868037f;	val_dir[13615*3 + 1] = -0.434019f;	val_dir[13615*3 + 2] = -0.241121f;
+ 	val_dir[13616*3 + 0] = -0.859559f;	val_dir[13616*3 + 1] = -0.41750f;	val_dir[13616*3 + 2] = -0.294706f;
+ 	val_dir[13617*3 + 0] = -0.847883f;	val_dir[13617*3 + 1] = -0.399004f;	val_dir[13617*3 + 2] = -0.349128f;
+ 	val_dir[13618*3 + 0] = -0.832845f;	val_dir[13618*3 + 1] = -0.378566f;	val_dir[13618*3 + 2] = -0.403804f;
+ 	val_dir[13619*3 + 0] = -0.814379f;	val_dir[13619*3 + 1] = -0.356291f;	val_dir[13619*3 + 2] = -0.458088f;
+ 	val_dir[13620*3 + 0] = -0.792530f;	val_dir[13620*3 + 1] = -0.332352f;	val_dir[13620*3 + 2] = -0.511310f;
+ 	val_dir[13621*3 + 0] = -0.767467f;	val_dir[13621*3 + 1] = -0.306987f;	val_dir[13621*3 + 2] = -0.562809f;
+ 	val_dir[13622*3 + 0] = -0.739469f;	val_dir[13622*3 + 1] = -0.280488f;	val_dir[13622*3 + 2] = -0.611974f;
+ 	val_dir[13623*3 + 0] = -0.708918f;	val_dir[13623*3 + 1] = -0.253185f;	val_dir[13623*3 + 2] = -0.658281f;
+ 	val_dir[13624*3 + 0] = -0.676269f;	val_dir[13624*3 + 1] = -0.225423f;	val_dir[13624*3 + 2] = -0.701316f;
+ 	val_dir[13625*3 + 0] = -0.642024f;	val_dir[13625*3 + 1] = -0.197546f;	val_dir[13625*3 + 2] = -0.740797f;
+ 	val_dir[13626*3 + 0] = -0.606696f;	val_dir[13626*3 + 1] = -0.169875f;	val_dir[13626*3 + 2] = -0.776571f;
+ 	val_dir[13627*3 + 0] = -0.570782f;	val_dir[13627*3 + 1] = -0.142695f;	val_dir[13627*3 + 2] = -0.808608f;
+ 	val_dir[13628*3 + 0] = -0.534739f;	val_dir[13628*3 + 1] = -0.116248f;	val_dir[13628*3 + 2] = -0.836983f;
+ 	val_dir[13629*3 + 0] = -0.498970f;	val_dir[13629*3 + 1] = -0.090722f;	val_dir[13629*3 + 2] = -0.861857f;
+ 	val_dir[13630*3 + 0] = -0.463812f;	val_dir[13630*3 + 1] = -0.066259f;	val_dir[13630*3 + 2] = -0.883452f;
+ 	val_dir[13631*3 + 0] = -0.429537f;	val_dir[13631*3 + 1] = -0.042954f;	val_dir[13631*3 + 2] = -0.902027f;
+ 	val_dir[13632*3 + 0] = -0.396350f;	val_dir[13632*3 + 1] = -0.020861f;	val_dir[13632*3 + 2] = -0.917863f;
+ 	val_dir[13633*3 + 0] = -0.364399f;	val_dir[13633*3 + 1] = 0.0f;	val_dir[13633*3 + 2] = -0.931243f;
+ 	val_dir[13634*3 + 0] = -0.346578f;	val_dir[13634*3 + 1] = 0.020387f;	val_dir[13634*3 + 2] = -0.93780f;
+ 	val_dir[13635*3 + 0] = -0.328244f;	val_dir[13635*3 + 1] = 0.041030f;	val_dir[13635*3 + 2] = -0.943701f;
+ 	val_dir[13636*3 + 0] = -0.309426f;	val_dir[13636*3 + 1] = 0.061885f;	val_dir[13636*3 + 2] = -0.948908f;
+ 	val_dir[13637*3 + 0] = -0.290159f;	val_dir[13637*3 + 1] = 0.082903f;	val_dir[13637*3 + 2] = -0.953381f;
+ 	val_dir[13638*3 + 0] = -0.270481f;	val_dir[13638*3 + 1] = 0.104031f;	val_dir[13638*3 + 2] = -0.957088f;
+ 	val_dir[13639*3 + 0] = -0.250435f;	val_dir[13639*3 + 1] = 0.125218f;	val_dir[13639*3 + 2] = -0.960001f;
+ 	val_dir[13640*3 + 0] = -0.230067f;	val_dir[13640*3 + 1] = 0.146406f;	val_dir[13640*3 + 2] = -0.962099f;
+ 	val_dir[13641*3 + 0] = -0.209427f;	val_dir[13641*3 + 1] = 0.167542f;	val_dir[13641*3 + 2] = -0.963364f;
+ 	val_dir[13642*3 + 0] = -0.188567f;	val_dir[13642*3 + 1] = 0.188567f;	val_dir[13642*3 + 2] = -0.963787f;
+ 	val_dir[13643*3 + 0] = -0.167542f;	val_dir[13643*3 + 1] = 0.209427f;	val_dir[13643*3 + 2] = -0.963364f;
+ 	val_dir[13644*3 + 0] = -0.146406f;	val_dir[13644*3 + 1] = 0.230067f;	val_dir[13644*3 + 2] = -0.962099f;
+ 	val_dir[13645*3 + 0] = -0.125218f;	val_dir[13645*3 + 1] = 0.250435f;	val_dir[13645*3 + 2] = -0.960001f;
+ 	val_dir[13646*3 + 0] = -0.104031f;	val_dir[13646*3 + 1] = 0.270481f;	val_dir[13646*3 + 2] = -0.957088f;
+ 	val_dir[13647*3 + 0] = -0.082903f;	val_dir[13647*3 + 1] = 0.290159f;	val_dir[13647*3 + 2] = -0.953381f;
+ 	val_dir[13648*3 + 0] = -0.061885f;	val_dir[13648*3 + 1] = 0.309426f;	val_dir[13648*3 + 2] = -0.948908f;
+ 	val_dir[13649*3 + 0] = -0.041030f;	val_dir[13649*3 + 1] = 0.328244f;	val_dir[13649*3 + 2] = -0.943701f;
+ 	val_dir[13650*3 + 0] = -0.020387f;	val_dir[13650*3 + 1] = 0.346578f;	val_dir[13650*3 + 2] = -0.93780f;
+ 	val_dir[13651*3 + 0] = 0.0f;	val_dir[13651*3 + 1] = 0.364399f;	val_dir[13651*3 + 2] = -0.931243f;
+ 	val_dir[13652*3 + 0] = 0.020861f;	val_dir[13652*3 + 1] = 0.396350f;	val_dir[13652*3 + 2] = -0.917863f;
+ 	val_dir[13653*3 + 0] = 0.042954f;	val_dir[13653*3 + 1] = 0.429537f;	val_dir[13653*3 + 2] = -0.902027f;
+ 	val_dir[13654*3 + 0] = 0.066259f;	val_dir[13654*3 + 1] = 0.463812f;	val_dir[13654*3 + 2] = -0.883452f;
+ 	val_dir[13655*3 + 0] = 0.090722f;	val_dir[13655*3 + 1] = 0.498970f;	val_dir[13655*3 + 2] = -0.861857f;
+ 	val_dir[13656*3 + 0] = 0.116248f;	val_dir[13656*3 + 1] = 0.534739f;	val_dir[13656*3 + 2] = -0.836983f;
+ 	val_dir[13657*3 + 0] = 0.142695f;	val_dir[13657*3 + 1] = 0.570782f;	val_dir[13657*3 + 2] = -0.808608f;
+ 	val_dir[13658*3 + 0] = 0.169875f;	val_dir[13658*3 + 1] = 0.606696f;	val_dir[13658*3 + 2] = -0.776571f;
+ 	val_dir[13659*3 + 0] = 0.197546f;	val_dir[13659*3 + 1] = 0.642024f;	val_dir[13659*3 + 2] = -0.740797f;
+ 	val_dir[13660*3 + 0] = 0.225423f;	val_dir[13660*3 + 1] = 0.676269f;	val_dir[13660*3 + 2] = -0.701316f;
+ 	val_dir[13661*3 + 0] = 0.253185f;	val_dir[13661*3 + 1] = 0.708918f;	val_dir[13661*3 + 2] = -0.658281f;
+ 	val_dir[13662*3 + 0] = 0.280488f;	val_dir[13662*3 + 1] = 0.739469f;	val_dir[13662*3 + 2] = -0.611974f;
+ 	val_dir[13663*3 + 0] = 0.306987f;	val_dir[13663*3 + 1] = 0.767467f;	val_dir[13663*3 + 2] = -0.562809f;
+ 	val_dir[13664*3 + 0] = 0.332352f;	val_dir[13664*3 + 1] = 0.792530f;	val_dir[13664*3 + 2] = -0.511310f;
+ 	val_dir[13665*3 + 0] = 0.356291f;	val_dir[13665*3 + 1] = 0.814379f;	val_dir[13665*3 + 2] = -0.458088f;
+ 	val_dir[13666*3 + 0] = 0.378566f;	val_dir[13666*3 + 1] = 0.832845f;	val_dir[13666*3 + 2] = -0.403804f;
+ 	val_dir[13667*3 + 0] = 0.399004f;	val_dir[13667*3 + 1] = 0.847883f;	val_dir[13667*3 + 2] = -0.349128f;
+ 	val_dir[13668*3 + 0] = 0.41750f;	val_dir[13668*3 + 1] = 0.859559f;	val_dir[13668*3 + 2] = -0.294706f;
+ 	val_dir[13669*3 + 0] = 0.434019f;	val_dir[13669*3 + 1] = 0.868037f;	val_dir[13669*3 + 2] = -0.241121f;
+ 	val_dir[13670*3 + 0] = 0.448583f;	val_dir[13670*3 + 1] = 0.873555f;	val_dir[13670*3 + 2] = -0.188877f;
+ 	val_dir[13671*3 + 0] = 0.461266f;	val_dir[13671*3 + 1] = 0.876405f;	val_dir[13671*3 + 2] = -0.138380f;
+ 	val_dir[13672*3 + 0] = 0.472178f;	val_dir[13672*3 + 1] = 0.876903f;	val_dir[13672*3 + 2] = -0.089939f;
+ 	val_dir[13673*3 + 0] = 0.481457f;	val_dir[13673*3 + 1] = 0.875376f;	val_dir[13673*3 + 2] = -0.043769f;
+ 	val_dir[13674*3 + 0] = 0.489251f;	val_dir[13674*3 + 1] = 0.872143f;	val_dir[13674*3 + 2] = 0.0f;
+ 	val_dir[13675*3 + 0] = -0.880957f;	val_dir[13675*3 + 1] = -0.472709f;	val_dir[13675*3 + 2] = -0.021487f;
+ 	val_dir[13676*3 + 0] = -0.883452f;	val_dir[13676*3 + 1] = -0.463812f;	val_dir[13676*3 + 2] = -0.066259f;
+ 	val_dir[13677*3 + 0] = -0.884083f;	val_dir[13677*3 + 1] = -0.453376f;	val_dir[13677*3 + 2] = -0.113344f;
+ 	val_dir[13678*3 + 0] = -0.882528f;	val_dir[13678*3 + 1] = -0.441264f;	val_dir[13678*3 + 2] = -0.162571f;
+ 	val_dir[13679*3 + 0] = -0.878466f;	val_dir[13679*3 + 1] = -0.427362f;	val_dir[13679*3 + 2] = -0.213681f;
+ 	val_dir[13680*3 + 0] = -0.871592f;	val_dir[13680*3 + 1] = -0.411585f;	val_dir[13680*3 + 2] = -0.266320f;
+ 	val_dir[13681*3 + 0] = -0.861640f;	val_dir[13681*3 + 1] = -0.393893f;	val_dir[13681*3 + 2] = -0.320038f;
+ 	val_dir[13682*3 + 0] = -0.848411f;	val_dir[13682*3 + 1] = -0.374299f;	val_dir[13682*3 + 2] = -0.374299f;
+ 	val_dir[13683*3 + 0] = -0.831786f;	val_dir[13683*3 + 1] = -0.352879f;	val_dir[13683*3 + 2] = -0.428496f;
+ 	val_dir[13684*3 + 0] = -0.811754f;	val_dir[13684*3 + 1] = -0.329775f;	val_dir[13684*3 + 2] = -0.481979f;
+ 	val_dir[13685*3 + 0] = -0.788419f;	val_dir[13685*3 + 1] = -0.305194f;	val_dir[13685*3 + 2] = -0.534090f;
+ 	val_dir[13686*3 + 0] = -0.762001f;	val_dir[13686*3 + 1] = -0.27940f;	val_dir[13686*3 + 2] = -0.584201f;
+ 	val_dir[13687*3 + 0] = -0.732828f;	val_dir[13687*3 + 1] = -0.252699f;	val_dir[13687*3 + 2] = -0.631748f;
+ 	val_dir[13688*3 + 0] = -0.701316f;	val_dir[13688*3 + 1] = -0.225423f;	val_dir[13688*3 + 2] = -0.676269f;
+ 	val_dir[13689*3 + 0] = -0.667940f;	val_dir[13689*3 + 1] = -0.197908f;	val_dir[13689*3 + 2] = -0.717418f;
+ 	val_dir[13690*3 + 0] = -0.633205f;	val_dir[13690*3 + 1] = -0.170478f;	val_dir[13690*3 + 2] = -0.754976f;
+ 	val_dir[13691*3 + 0] = -0.597614f;	val_dir[13691*3 + 1] = -0.143427f;	val_dir[13691*3 + 2] = -0.788851f;
+ 	val_dir[13692*3 + 0] = -0.561644f;	val_dir[13692*3 + 1] = -0.117009f;	val_dir[13692*3 + 2] = -0.819064f;
+ 	val_dir[13693*3 + 0] = -0.525723f;	val_dir[13693*3 + 1] = -0.091430f;	val_dir[13693*3 + 2] = -0.845728f;
+ 	val_dir[13694*3 + 0] = -0.490222f;	val_dir[13694*3 + 1] = -0.066848f;	val_dir[13694*3 + 2] = -0.869030f;
+ 	val_dir[13695*3 + 0] = -0.455447f;	val_dir[13695*3 + 1] = -0.043376f;	val_dir[13695*3 + 2] = -0.889206f;
+ 	val_dir[13696*3 + 0] = -0.421637f;	val_dir[13696*3 + 1] = -0.021082f;	val_dir[13696*3 + 2] = -0.906520f;
+ 	val_dir[13697*3 + 0] = -0.388972f;	val_dir[13697*3 + 1] = 0.0f;	val_dir[13697*3 + 2] = -0.921250f;
+ 	val_dir[13698*3 + 0] = -0.371312f;	val_dir[13698*3 + 1] = 0.020628f;	val_dir[13698*3 + 2] = -0.928279f;
+ 	val_dir[13699*3 + 0] = -0.353096f;	val_dir[13699*3 + 1] = 0.041541f;	val_dir[13699*3 + 2] = -0.934665f;
+ 	val_dir[13700*3 + 0] = -0.334351f;	val_dir[13700*3 + 1] = 0.062691f;	val_dir[13700*3 + 2] = -0.940361f;
+ 	val_dir[13701*3 + 0] = -0.315109f;	val_dir[13701*3 + 1] = 0.084029f;	val_dir[13701*3 + 2] = -0.945328f;
+ 	val_dir[13702*3 + 0] = -0.295409f;	val_dir[13702*3 + 1] = 0.105503f;	val_dir[13702*3 + 2] = -0.949528f;
+ 	val_dir[13703*3 + 0] = -0.275290f;	val_dir[13703*3 + 1] = 0.127057f;	val_dir[13703*3 + 2] = -0.952928f;
+ 	val_dir[13704*3 + 0] = -0.254801f;	val_dir[13704*3 + 1] = 0.148634f;	val_dir[13704*3 + 2] = -0.955502f;
+ 	val_dir[13705*3 + 0] = -0.233990f;	val_dir[13705*3 + 1] = 0.170174f;	val_dir[13705*3 + 2] = -0.957230f;
+ 	val_dir[13706*3 + 0] = -0.212911f;	val_dir[13706*3 + 1] = 0.191620f;	val_dir[13706*3 + 2] = -0.958098f;
+ 	val_dir[13707*3 + 0] = -0.191620f;	val_dir[13707*3 + 1] = 0.212911f;	val_dir[13707*3 + 2] = -0.958098f;
+ 	val_dir[13708*3 + 0] = -0.170174f;	val_dir[13708*3 + 1] = 0.233990f;	val_dir[13708*3 + 2] = -0.957230f;
+ 	val_dir[13709*3 + 0] = -0.148634f;	val_dir[13709*3 + 1] = 0.254801f;	val_dir[13709*3 + 2] = -0.955502f;
+ 	val_dir[13710*3 + 0] = -0.127057f;	val_dir[13710*3 + 1] = 0.275290f;	val_dir[13710*3 + 2] = -0.952928f;
+ 	val_dir[13711*3 + 0] = -0.105503f;	val_dir[13711*3 + 1] = 0.295409f;	val_dir[13711*3 + 2] = -0.949528f;
+ 	val_dir[13712*3 + 0] = -0.084029f;	val_dir[13712*3 + 1] = 0.315109f;	val_dir[13712*3 + 2] = -0.945328f;
+ 	val_dir[13713*3 + 0] = -0.062691f;	val_dir[13713*3 + 1] = 0.334351f;	val_dir[13713*3 + 2] = -0.940361f;
+ 	val_dir[13714*3 + 0] = -0.041541f;	val_dir[13714*3 + 1] = 0.353096f;	val_dir[13714*3 + 2] = -0.934665f;
+ 	val_dir[13715*3 + 0] = -0.020628f;	val_dir[13715*3 + 1] = 0.371312f;	val_dir[13715*3 + 2] = -0.928279f;
+ 	val_dir[13716*3 + 0] = 0.0f;	val_dir[13716*3 + 1] = 0.388972f;	val_dir[13716*3 + 2] = -0.921250f;
+ 	val_dir[13717*3 + 0] = 0.021082f;	val_dir[13717*3 + 1] = 0.421637f;	val_dir[13717*3 + 2] = -0.906520f;
+ 	val_dir[13718*3 + 0] = 0.043376f;	val_dir[13718*3 + 1] = 0.455447f;	val_dir[13718*3 + 2] = -0.889206f;
+ 	val_dir[13719*3 + 0] = 0.066848f;	val_dir[13719*3 + 1] = 0.490222f;	val_dir[13719*3 + 2] = -0.869030f;
+ 	val_dir[13720*3 + 0] = 0.091430f;	val_dir[13720*3 + 1] = 0.525723f;	val_dir[13720*3 + 2] = -0.845728f;
+ 	val_dir[13721*3 + 0] = 0.117009f;	val_dir[13721*3 + 1] = 0.561644f;	val_dir[13721*3 + 2] = -0.819064f;
+ 	val_dir[13722*3 + 0] = 0.143427f;	val_dir[13722*3 + 1] = 0.597614f;	val_dir[13722*3 + 2] = -0.788851f;
+ 	val_dir[13723*3 + 0] = 0.170478f;	val_dir[13723*3 + 1] = 0.633205f;	val_dir[13723*3 + 2] = -0.754976f;
+ 	val_dir[13724*3 + 0] = 0.197908f;	val_dir[13724*3 + 1] = 0.667940f;	val_dir[13724*3 + 2] = -0.717418f;
+ 	val_dir[13725*3 + 0] = 0.225423f;	val_dir[13725*3 + 1] = 0.701316f;	val_dir[13725*3 + 2] = -0.676269f;
+ 	val_dir[13726*3 + 0] = 0.252699f;	val_dir[13726*3 + 1] = 0.732828f;	val_dir[13726*3 + 2] = -0.631748f;
+ 	val_dir[13727*3 + 0] = 0.27940f;	val_dir[13727*3 + 1] = 0.762001f;	val_dir[13727*3 + 2] = -0.584201f;
+ 	val_dir[13728*3 + 0] = 0.305194f;	val_dir[13728*3 + 1] = 0.788419f;	val_dir[13728*3 + 2] = -0.534090f;
+ 	val_dir[13729*3 + 0] = 0.329775f;	val_dir[13729*3 + 1] = 0.811754f;	val_dir[13729*3 + 2] = -0.481979f;
+ 	val_dir[13730*3 + 0] = 0.352879f;	val_dir[13730*3 + 1] = 0.831786f;	val_dir[13730*3 + 2] = -0.428496f;
+ 	val_dir[13731*3 + 0] = 0.374299f;	val_dir[13731*3 + 1] = 0.848411f;	val_dir[13731*3 + 2] = -0.374299f;
+ 	val_dir[13732*3 + 0] = 0.393893f;	val_dir[13732*3 + 1] = 0.861640f;	val_dir[13732*3 + 2] = -0.320038f;
+ 	val_dir[13733*3 + 0] = 0.411585f;	val_dir[13733*3 + 1] = 0.871592f;	val_dir[13733*3 + 2] = -0.266320f;
+ 	val_dir[13734*3 + 0] = 0.427362f;	val_dir[13734*3 + 1] = 0.878466f;	val_dir[13734*3 + 2] = -0.213681f;
+ 	val_dir[13735*3 + 0] = 0.441264f;	val_dir[13735*3 + 1] = 0.882528f;	val_dir[13735*3 + 2] = -0.162571f;
+ 	val_dir[13736*3 + 0] = 0.453376f;	val_dir[13736*3 + 1] = 0.884083f;	val_dir[13736*3 + 2] = -0.113344f;
+ 	val_dir[13737*3 + 0] = 0.463812f;	val_dir[13737*3 + 1] = 0.883452f;	val_dir[13737*3 + 2] = -0.066259f;
+ 	val_dir[13738*3 + 0] = 0.472709f;	val_dir[13738*3 + 1] = 0.880957f;	val_dir[13738*3 + 2] = -0.021487f;
+ 	val_dir[13739*3 + 0] = -0.885832f;	val_dir[13739*3 + 1] = -0.464007f;	val_dir[13739*3 + 2] = 0.0f;
+ 	val_dir[13740*3 + 0] = -0.889206f;	val_dir[13740*3 + 1] = -0.455447f;	val_dir[13740*3 + 2] = -0.043376f;
+ 	val_dir[13741*3 + 0] = -0.890871f;	val_dir[13741*3 + 1] = -0.445435f;	val_dir[13741*3 + 2] = -0.089087f;
+ 	val_dir[13742*3 + 0] = -0.890513f;	val_dir[13742*3 + 1] = -0.433840f;	val_dir[13742*3 + 2] = -0.137002f;
+ 	val_dir[13743*3 + 0] = -0.887812f;	val_dir[13743*3 + 1] = -0.420542f;	val_dir[13743*3 + 2] = -0.186908f;
+ 	val_dir[13744*3 + 0] = -0.882454f;	val_dir[13744*3 + 1] = -0.405452f;	val_dir[13744*3 + 2] = -0.238501f;
+ 	val_dir[13745*3 + 0] = -0.874157f;	val_dir[13745*3 + 1] = -0.388514f;	val_dir[13745*3 + 2] = -0.291386f;
+ 	val_dir[13746*3 + 0] = -0.862687f;	val_dir[13746*3 + 1] = -0.369723f;	val_dir[13746*3 + 2] = -0.345075f;
+ 	val_dir[13747*3 + 0] = -0.847883f;	val_dir[13747*3 + 1] = -0.349128f;	val_dir[13747*3 + 2] = -0.399004f;
+ 	val_dir[13748*3 + 0] = -0.829680f;	val_dir[13748*3 + 1] = -0.326844f;	val_dir[13748*3 + 2] = -0.452553f;
+ 	val_dir[13749*3 + 0] = -0.808122f;	val_dir[13749*3 + 1] = -0.303046f;	val_dir[13749*3 + 2] = -0.505076f;
+ 	val_dir[13750*3 + 0] = -0.783368f;	val_dir[13750*3 + 1] = -0.277969f;	val_dir[13750*3 + 2] = -0.555939f;
+ 	val_dir[13751*3 + 0] = -0.755689f;	val_dir[13751*3 + 1] = -0.251896f;	val_dir[13751*3 + 2] = -0.604551f;
+ 	val_dir[13752*3 + 0] = -0.725454f;	val_dir[13752*3 + 1] = -0.225141f;	val_dir[13752*3 + 2] = -0.650407f;
+ 	val_dir[13753*3 + 0] = -0.693103f;	val_dir[13753*3 + 1] = -0.198030f;	val_dir[13753*3 + 2] = -0.693103f;
+ 	val_dir[13754*3 + 0] = -0.659125f;	val_dir[13754*3 + 1] = -0.170884f;	val_dir[13754*3 + 2] = -0.732361f;
+ 	val_dir[13755*3 + 0] = -0.624020f;	val_dir[13755*3 + 1] = -0.144005f;	val_dir[13755*3 + 2] = -0.768025f;
+ 	val_dir[13756*3 + 0] = -0.588276f;	val_dir[13756*3 + 1] = -0.117655f;	val_dir[13756*3 + 2] = -0.800055f;
+ 	val_dir[13757*3 + 0] = -0.552345f;	val_dir[13757*3 + 1] = -0.092057f;	val_dir[13757*3 + 2] = -0.828517f;
+ 	val_dir[13758*3 + 0] = -0.516626f;	val_dir[13758*3 + 1] = -0.067386f;	val_dir[13758*3 + 2] = -0.853556f;
+ 	val_dir[13759*3 + 0] = -0.481457f;	val_dir[13759*3 + 1] = -0.043769f;	val_dir[13759*3 + 2] = -0.875376f;
+ 	val_dir[13760*3 + 0] = -0.447112f;	val_dir[13760*3 + 1] = -0.021291f;	val_dir[13760*3 + 2] = -0.894224f;
+ 	val_dir[13761*3 + 0] = -0.413803f;	val_dir[13761*3 + 1] = 0.0f;	val_dir[13761*3 + 2] = -0.910366f;
+ 	val_dir[13762*3 + 0] = -0.396350f;	val_dir[13762*3 + 1] = 0.020861f;	val_dir[13762*3 + 2] = -0.917863f;
+ 	val_dir[13763*3 + 0] = -0.378298f;	val_dir[13763*3 + 1] = 0.042033f;	val_dir[13763*3 + 2] = -0.924729f;
+ 	val_dir[13764*3 + 0] = -0.359673f;	val_dir[13764*3 + 1] = 0.063472f;	val_dir[13764*3 + 2] = -0.930917f;
+ 	val_dir[13765*3 + 0] = -0.340503f;	val_dir[13765*3 + 1] = 0.085126f;	val_dir[13765*3 + 2] = -0.936382f;
+ 	val_dir[13766*3 + 0] = -0.320824f;	val_dir[13766*3 + 1] = 0.106941f;	val_dir[13766*3 + 2] = -0.941082f;
+ 	val_dir[13767*3 + 0] = -0.300676f;	val_dir[13767*3 + 1] = 0.128861f;	val_dir[13767*3 + 2] = -0.944981f;
+ 	val_dir[13768*3 + 0] = -0.280105f;	val_dir[13768*3 + 1] = 0.150826f;	val_dir[13768*3 + 2] = -0.948047f;
+ 	val_dir[13769*3 + 0] = -0.259161f;	val_dir[13769*3 + 1] = 0.172774f;	val_dir[13769*3 + 2] = -0.950255f;
+ 	val_dir[13770*3 + 0] = -0.237897f;	val_dir[13770*3 + 1] = 0.194643f;	val_dir[13770*3 + 2] = -0.951588f;
+ 	val_dir[13771*3 + 0] = -0.216371f;	val_dir[13771*3 + 1] = 0.216371f;	val_dir[13771*3 + 2] = -0.952033f;
+ 	val_dir[13772*3 + 0] = -0.194643f;	val_dir[13772*3 + 1] = 0.237897f;	val_dir[13772*3 + 2] = -0.951588f;
+ 	val_dir[13773*3 + 0] = -0.172774f;	val_dir[13773*3 + 1] = 0.259161f;	val_dir[13773*3 + 2] = -0.950255f;
+ 	val_dir[13774*3 + 0] = -0.150826f;	val_dir[13774*3 + 1] = 0.280105f;	val_dir[13774*3 + 2] = -0.948047f;
+ 	val_dir[13775*3 + 0] = -0.128861f;	val_dir[13775*3 + 1] = 0.300676f;	val_dir[13775*3 + 2] = -0.944981f;
+ 	val_dir[13776*3 + 0] = -0.106941f;	val_dir[13776*3 + 1] = 0.320824f;	val_dir[13776*3 + 2] = -0.941082f;
+ 	val_dir[13777*3 + 0] = -0.085126f;	val_dir[13777*3 + 1] = 0.340503f;	val_dir[13777*3 + 2] = -0.936382f;
+ 	val_dir[13778*3 + 0] = -0.063472f;	val_dir[13778*3 + 1] = 0.359673f;	val_dir[13778*3 + 2] = -0.930917f;
+ 	val_dir[13779*3 + 0] = -0.042033f;	val_dir[13779*3 + 1] = 0.378298f;	val_dir[13779*3 + 2] = -0.924729f;
+ 	val_dir[13780*3 + 0] = -0.020861f;	val_dir[13780*3 + 1] = 0.396350f;	val_dir[13780*3 + 2] = -0.917863f;
+ 	val_dir[13781*3 + 0] = 0.0f;	val_dir[13781*3 + 1] = 0.413803f;	val_dir[13781*3 + 2] = -0.910366f;
+ 	val_dir[13782*3 + 0] = 0.021291f;	val_dir[13782*3 + 1] = 0.447112f;	val_dir[13782*3 + 2] = -0.894224f;
+ 	val_dir[13783*3 + 0] = 0.043769f;	val_dir[13783*3 + 1] = 0.481457f;	val_dir[13783*3 + 2] = -0.875376f;
+ 	val_dir[13784*3 + 0] = 0.067386f;	val_dir[13784*3 + 1] = 0.516626f;	val_dir[13784*3 + 2] = -0.853556f;
+ 	val_dir[13785*3 + 0] = 0.092057f;	val_dir[13785*3 + 1] = 0.552345f;	val_dir[13785*3 + 2] = -0.828517f;
+ 	val_dir[13786*3 + 0] = 0.117655f;	val_dir[13786*3 + 1] = 0.588276f;	val_dir[13786*3 + 2] = -0.800055f;
+ 	val_dir[13787*3 + 0] = 0.144005f;	val_dir[13787*3 + 1] = 0.624020f;	val_dir[13787*3 + 2] = -0.768025f;
+ 	val_dir[13788*3 + 0] = 0.170884f;	val_dir[13788*3 + 1] = 0.659125f;	val_dir[13788*3 + 2] = -0.732361f;
+ 	val_dir[13789*3 + 0] = 0.198030f;	val_dir[13789*3 + 1] = 0.693103f;	val_dir[13789*3 + 2] = -0.693103f;
+ 	val_dir[13790*3 + 0] = 0.225141f;	val_dir[13790*3 + 1] = 0.725454f;	val_dir[13790*3 + 2] = -0.650407f;
+ 	val_dir[13791*3 + 0] = 0.251896f;	val_dir[13791*3 + 1] = 0.755689f;	val_dir[13791*3 + 2] = -0.604551f;
+ 	val_dir[13792*3 + 0] = 0.277969f;	val_dir[13792*3 + 1] = 0.783368f;	val_dir[13792*3 + 2] = -0.555939f;
+ 	val_dir[13793*3 + 0] = 0.303046f;	val_dir[13793*3 + 1] = 0.808122f;	val_dir[13793*3 + 2] = -0.505076f;
+ 	val_dir[13794*3 + 0] = 0.326844f;	val_dir[13794*3 + 1] = 0.829680f;	val_dir[13794*3 + 2] = -0.452553f;
+ 	val_dir[13795*3 + 0] = 0.349128f;	val_dir[13795*3 + 1] = 0.847883f;	val_dir[13795*3 + 2] = -0.399004f;
+ 	val_dir[13796*3 + 0] = 0.369723f;	val_dir[13796*3 + 1] = 0.862687f;	val_dir[13796*3 + 2] = -0.345075f;
+ 	val_dir[13797*3 + 0] = 0.388514f;	val_dir[13797*3 + 1] = 0.874157f;	val_dir[13797*3 + 2] = -0.291386f;
+ 	val_dir[13798*3 + 0] = 0.405452f;	val_dir[13798*3 + 1] = 0.882454f;	val_dir[13798*3 + 2] = -0.238501f;
+ 	val_dir[13799*3 + 0] = 0.420542f;	val_dir[13799*3 + 1] = 0.887812f;	val_dir[13799*3 + 2] = -0.186908f;
+ 	val_dir[13800*3 + 0] = 0.433840f;	val_dir[13800*3 + 1] = 0.890513f;	val_dir[13800*3 + 2] = -0.137002f;
+ 	val_dir[13801*3 + 0] = 0.445435f;	val_dir[13801*3 + 1] = 0.890871f;	val_dir[13801*3 + 2] = -0.089087f;
+ 	val_dir[13802*3 + 0] = 0.455447f;	val_dir[13802*3 + 1] = 0.889206f;	val_dir[13802*3 + 2] = -0.043376f;
+ 	val_dir[13803*3 + 0] = 0.464007f;	val_dir[13803*3 + 1] = 0.885832f;	val_dir[13803*3 + 2] = 0.0f;
+ 	val_dir[13804*3 + 0] = -0.894224f;	val_dir[13804*3 + 1] = -0.447112f;	val_dir[13804*3 + 2] = -0.021291f;
+ 	val_dir[13805*3 + 0] = -0.896831f;	val_dir[13805*3 + 1] = -0.437479f;	val_dir[13805*3 + 2] = -0.065622f;
+ 	val_dir[13806*3 + 0] = -0.897574f;	val_dir[13806*3 + 1] = -0.426348f;	val_dir[13806*3 + 2] = -0.112197f;
+ 	val_dir[13807*3 + 0] = -0.896137f;	val_dir[13807*3 + 1] = -0.413602f;	val_dir[13807*3 + 2] = -0.160845f;
+ 	val_dir[13808*3 + 0] = -0.892206f;	val_dir[13808*3 + 1] = -0.399145f;	val_dir[13808*3 + 2] = -0.211312f;
+ 	val_dir[13809*3 + 0] = -0.885482f;	val_dir[13809*3 + 1] = -0.382911f;	val_dir[13809*3 + 2] = -0.263251f;
+ 	val_dir[13810*3 + 0] = -0.875708f;	val_dir[13810*3 + 1] = -0.364878f;	val_dir[13810*3 + 2] = -0.316228f;
+ 	val_dir[13811*3 + 0] = -0.862687f;	val_dir[13811*3 + 1] = -0.345075f;	val_dir[13811*3 + 2] = -0.369723f;
+ 	val_dir[13812*3 + 0] = -0.846305f;	val_dir[13812*3 + 1] = -0.323587f;	val_dir[13812*3 + 2] = -0.423153f;
+ 	val_dir[13813*3 + 0] = -0.826551f;	val_dir[13813*3 + 1] = -0.300564f;	val_dir[13813*3 + 2] = -0.475893f;
+ 	val_dir[13814*3 + 0] = -0.803523f;	val_dir[13814*3 + 1] = -0.276211f;	val_dir[13814*3 + 2] = -0.527312f;
+ 	val_dir[13815*3 + 0] = -0.777433f;	val_dir[13815*3 + 1] = -0.250785f;	val_dir[13815*3 + 2] = -0.576805f;
+ 	val_dir[13816*3 + 0] = -0.748598f;	val_dir[13816*3 + 1] = -0.224579f;	val_dir[13816*3 + 2] = -0.623831f;
+ 	val_dir[13817*3 + 0] = -0.717418f;	val_dir[13817*3 + 1] = -0.197908f;	val_dir[13817*3 + 2] = -0.667940f;
+ 	val_dir[13818*3 + 0] = -0.684353f;	val_dir[13818*3 + 1] = -0.171088f;	val_dir[13818*3 + 2] = -0.708794f;
+ 	val_dir[13819*3 + 0] = -0.649895f;	val_dir[13819*3 + 1] = -0.144421f;	val_dir[13819*3 + 2] = -0.746176f;
+ 	val_dir[13820*3 + 0] = -0.614535f;	val_dir[13820*3 + 1] = -0.118180f;	val_dir[13820*3 + 2] = -0.779987f;
+ 	val_dir[13821*3 + 0] = -0.578741f;	val_dir[13821*3 + 1] = -0.092599f;	val_dir[13821*3 + 2] = -0.810237f;
+ 	val_dir[13822*3 + 0] = -0.542936f;	val_dir[13822*3 + 1] = -0.067867f;	val_dir[13822*3 + 2] = -0.837027f;
+ 	val_dir[13823*3 + 0] = -0.507490f;	val_dir[13823*3 + 1] = -0.044130f;	val_dir[13823*3 + 2] = -0.860527f;
+ 	val_dir[13824*3 + 0] = -0.472709f;	val_dir[13824*3 + 1] = -0.021487f;	val_dir[13824*3 + 2] = -0.880957f;
+ 	val_dir[13825*3 + 0] = -0.438835f;	val_dir[13825*3 + 1] = 0.0f;	val_dir[13825*3 + 2] = -0.898567f;
+ 	val_dir[13826*3 + 0] = -0.421637f;	val_dir[13826*3 + 1] = 0.021082f;	val_dir[13826*3 + 2] = -0.906520f;
+ 	val_dir[13827*3 + 0] = -0.403799f;	val_dir[13827*3 + 1] = 0.042505f;	val_dir[13827*3 + 2] = -0.913860f;
+ 	val_dir[13828*3 + 0] = -0.385341f;	val_dir[13828*3 + 1] = 0.064223f;	val_dir[13828*3 + 2] = -0.920537f;
+ 	val_dir[13829*3 + 0] = -0.366291f;	val_dir[13829*3 + 1] = 0.086186f;	val_dir[13829*3 + 2] = -0.92650f;
+ 	val_dir[13830*3 + 0] = -0.346681f;	val_dir[13830*3 + 1] = 0.108338f;	val_dir[13830*3 + 2] = -0.931705f;
+ 	val_dir[13831*3 + 0] = -0.326550f;	val_dir[13831*3 + 1] = 0.130620f;	val_dir[13831*3 + 2] = -0.936111f;
+ 	val_dir[13832*3 + 0] = -0.305942f;	val_dir[13832*3 + 1] = 0.152971f;	val_dir[13832*3 + 2] = -0.939680f;
+ 	val_dir[13833*3 + 0] = -0.284907f;	val_dir[13833*3 + 1] = 0.175327f;	val_dir[13833*3 + 2] = -0.942384f;
+ 	val_dir[13834*3 + 0] = -0.263498f;	val_dir[13834*3 + 1] = 0.197623f;	val_dir[13834*3 + 2] = -0.94420f;
+ 	val_dir[13835*3 + 0] = -0.241773f;	val_dir[13835*3 + 1] = 0.219793f;	val_dir[13835*3 + 2] = -0.945112f;
+ 	val_dir[13836*3 + 0] = -0.219793f;	val_dir[13836*3 + 1] = 0.241773f;	val_dir[13836*3 + 2] = -0.945112f;
+ 	val_dir[13837*3 + 0] = -0.197623f;	val_dir[13837*3 + 1] = 0.263498f;	val_dir[13837*3 + 2] = -0.94420f;
+ 	val_dir[13838*3 + 0] = -0.175327f;	val_dir[13838*3 + 1] = 0.284907f;	val_dir[13838*3 + 2] = -0.942384f;
+ 	val_dir[13839*3 + 0] = -0.152971f;	val_dir[13839*3 + 1] = 0.305942f;	val_dir[13839*3 + 2] = -0.939680f;
+ 	val_dir[13840*3 + 0] = -0.130620f;	val_dir[13840*3 + 1] = 0.326550f;	val_dir[13840*3 + 2] = -0.936111f;
+ 	val_dir[13841*3 + 0] = -0.108338f;	val_dir[13841*3 + 1] = 0.346681f;	val_dir[13841*3 + 2] = -0.931705f;
+ 	val_dir[13842*3 + 0] = -0.086186f;	val_dir[13842*3 + 1] = 0.366291f;	val_dir[13842*3 + 2] = -0.92650f;
+ 	val_dir[13843*3 + 0] = -0.064223f;	val_dir[13843*3 + 1] = 0.385341f;	val_dir[13843*3 + 2] = -0.920537f;
+ 	val_dir[13844*3 + 0] = -0.042505f;	val_dir[13844*3 + 1] = 0.403799f;	val_dir[13844*3 + 2] = -0.913860f;
+ 	val_dir[13845*3 + 0] = -0.021082f;	val_dir[13845*3 + 1] = 0.421637f;	val_dir[13845*3 + 2] = -0.906520f;
+ 	val_dir[13846*3 + 0] = 0.0f;	val_dir[13846*3 + 1] = 0.438835f;	val_dir[13846*3 + 2] = -0.898567f;
+ 	val_dir[13847*3 + 0] = 0.021487f;	val_dir[13847*3 + 1] = 0.472709f;	val_dir[13847*3 + 2] = -0.880957f;
+ 	val_dir[13848*3 + 0] = 0.044130f;	val_dir[13848*3 + 1] = 0.507490f;	val_dir[13848*3 + 2] = -0.860527f;
+ 	val_dir[13849*3 + 0] = 0.067867f;	val_dir[13849*3 + 1] = 0.542936f;	val_dir[13849*3 + 2] = -0.837027f;
+ 	val_dir[13850*3 + 0] = 0.092599f;	val_dir[13850*3 + 1] = 0.578741f;	val_dir[13850*3 + 2] = -0.810237f;
+ 	val_dir[13851*3 + 0] = 0.118180f;	val_dir[13851*3 + 1] = 0.614535f;	val_dir[13851*3 + 2] = -0.779987f;
+ 	val_dir[13852*3 + 0] = 0.144421f;	val_dir[13852*3 + 1] = 0.649895f;	val_dir[13852*3 + 2] = -0.746176f;
+ 	val_dir[13853*3 + 0] = 0.171088f;	val_dir[13853*3 + 1] = 0.684353f;	val_dir[13853*3 + 2] = -0.708794f;
+ 	val_dir[13854*3 + 0] = 0.197908f;	val_dir[13854*3 + 1] = 0.717418f;	val_dir[13854*3 + 2] = -0.667940f;
+ 	val_dir[13855*3 + 0] = 0.224579f;	val_dir[13855*3 + 1] = 0.748598f;	val_dir[13855*3 + 2] = -0.623831f;
+ 	val_dir[13856*3 + 0] = 0.250785f;	val_dir[13856*3 + 1] = 0.777433f;	val_dir[13856*3 + 2] = -0.576805f;
+ 	val_dir[13857*3 + 0] = 0.276211f;	val_dir[13857*3 + 1] = 0.803523f;	val_dir[13857*3 + 2] = -0.527312f;
+ 	val_dir[13858*3 + 0] = 0.300564f;	val_dir[13858*3 + 1] = 0.826551f;	val_dir[13858*3 + 2] = -0.475893f;
+ 	val_dir[13859*3 + 0] = 0.323587f;	val_dir[13859*3 + 1] = 0.846305f;	val_dir[13859*3 + 2] = -0.423153f;
+ 	val_dir[13860*3 + 0] = 0.345075f;	val_dir[13860*3 + 1] = 0.862687f;	val_dir[13860*3 + 2] = -0.369723f;
+ 	val_dir[13861*3 + 0] = 0.364878f;	val_dir[13861*3 + 1] = 0.875708f;	val_dir[13861*3 + 2] = -0.316228f;
+ 	val_dir[13862*3 + 0] = 0.382911f;	val_dir[13862*3 + 1] = 0.885482f;	val_dir[13862*3 + 2] = -0.263251f;
+ 	val_dir[13863*3 + 0] = 0.399145f;	val_dir[13863*3 + 1] = 0.892206f;	val_dir[13863*3 + 2] = -0.211312f;
+ 	val_dir[13864*3 + 0] = 0.413602f;	val_dir[13864*3 + 1] = 0.896137f;	val_dir[13864*3 + 2] = -0.160845f;
+ 	val_dir[13865*3 + 0] = 0.426348f;	val_dir[13865*3 + 1] = 0.897574f;	val_dir[13865*3 + 2] = -0.112197f;
+ 	val_dir[13866*3 + 0] = 0.437479f;	val_dir[13866*3 + 1] = 0.896831f;	val_dir[13866*3 + 2] = -0.065622f;
+ 	val_dir[13867*3 + 0] = 0.447112f;	val_dir[13867*3 + 1] = 0.894224f;	val_dir[13867*3 + 2] = -0.021291f;
+ 	val_dir[13868*3 + 0] = -0.898567f;	val_dir[13868*3 + 1] = -0.438835f;	val_dir[13868*3 + 2] = 0.0f;
+ 	val_dir[13869*3 + 0] = -0.902027f;	val_dir[13869*3 + 1] = -0.429537f;	val_dir[13869*3 + 2] = -0.042954f;
+ 	val_dir[13870*3 + 0] = -0.903777f;	val_dir[13870*3 + 1] = -0.418823f;	val_dir[13870*3 + 2] = -0.088173f;
+ 	val_dir[13871*3 + 0] = -0.903508f;	val_dir[13871*3 + 1] = -0.406579f;	val_dir[13871*3 + 2] = -0.135526f;
+ 	val_dir[13872*3 + 0] = -0.900907f;	val_dir[13872*3 + 1] = -0.392703f;	val_dir[13872*3 + 2] = -0.184801f;
+ 	val_dir[13873*3 + 0] = -0.895669f;	val_dir[13873*3 + 1] = -0.377124f;	val_dir[13873*3 + 2] = -0.235702f;
+ 	val_dir[13874*3 + 0] = -0.887517f;	val_dir[13874*3 + 1] = -0.359804f;	val_dir[13874*3 + 2] = -0.287843f;
+ 	val_dir[13875*3 + 0] = -0.876226f;	val_dir[13875*3 + 1] = -0.340755f;	val_dir[13875*3 + 2] = -0.340755f;
+ 	val_dir[13876*3 + 0] = -0.861640f;	val_dir[13876*3 + 1] = -0.320038f;	val_dir[13876*3 + 2] = -0.393893f;
+ 	val_dir[13877*3 + 0] = -0.843696f;	val_dir[13877*3 + 1] = -0.297775f;	val_dir[13877*3 + 2] = -0.446662f;
+ 	val_dir[13878*3 + 0] = -0.822434f;	val_dir[13878*3 + 1] = -0.274145f;	val_dir[13878*3 + 2] = -0.498445f;
+ 	val_dir[13879*3 + 0] = -0.798007f;	val_dir[13879*3 + 1] = -0.249377f;	val_dir[13879*3 + 2] = -0.548630f;
+ 	val_dir[13880*3 + 0] = -0.770677f;	val_dir[13880*3 + 1] = -0.223745f;	val_dir[13880*3 + 2] = -0.596653f;
+ 	val_dir[13881*3 + 0] = -0.740797f;	val_dir[13881*3 + 1] = -0.197546f;	val_dir[13881*3 + 2] = -0.642024f;
+ 	val_dir[13882*3 + 0] = -0.708794f;	val_dir[13882*3 + 1] = -0.171088f;	val_dir[13882*3 + 2] = -0.684353f;
+ 	val_dir[13883*3 + 0] = -0.675140f;	val_dir[13883*3 + 1] = -0.144673f;	val_dir[13883*3 + 2] = -0.723364f;
+ 	val_dir[13884*3 + 0] = -0.640321f;	val_dir[13884*3 + 1] = -0.118578f;	val_dir[13884*3 + 2] = -0.758899f;
+ 	val_dir[13885*3 + 0] = -0.604815f;	val_dir[13885*3 + 1] = -0.093048f;	val_dir[13885*3 + 2] = -0.790912f;
+ 	val_dir[13886*3 + 0] = -0.569064f;	val_dir[13886*3 + 1] = -0.068288f;	val_dir[13886*3 + 2] = -0.819453f;
+ 	val_dir[13887*3 + 0] = -0.533465f;	val_dir[13887*3 + 1] = -0.044455f;	val_dir[13887*3 + 2] = -0.844653f;
+ 	val_dir[13888*3 + 0] = -0.498354f;	val_dir[13888*3 + 1] = -0.021668f;	val_dir[13888*3 + 2] = -0.866703f;
+ 	val_dir[13889*3 + 0] = -0.464007f;	val_dir[13889*3 + 1] = 0.0f;	val_dir[13889*3 + 2] = -0.885832f;
+ 	val_dir[13890*3 + 0] = -0.447112f;	val_dir[13890*3 + 1] = 0.021291f;	val_dir[13890*3 + 2] = -0.894224f;
+ 	val_dir[13891*3 + 0] = -0.429537f;	val_dir[13891*3 + 1] = 0.042954f;	val_dir[13891*3 + 2] = -0.902027f;
+ 	val_dir[13892*3 + 0] = -0.411298f;	val_dir[13892*3 + 1] = 0.064942f;	val_dir[13892*3 + 2] = -0.909185f;
+ 	val_dir[13893*3 + 0] = -0.392419f;	val_dir[13893*3 + 1] = 0.087204f;	val_dir[13893*3 + 2] = -0.915644f;
+ 	val_dir[13894*3 + 0] = -0.372929f;	val_dir[13894*3 + 1] = 0.109685f;	val_dir[13894*3 + 2] = -0.921354f;
+ 	val_dir[13895*3 + 0] = -0.352865f;	val_dir[13895*3 + 1] = 0.132324f;	val_dir[13895*3 + 2] = -0.926270f;
+ 	val_dir[13896*3 + 0] = -0.332269f;	val_dir[13896*3 + 1] = 0.155059f;	val_dir[13896*3 + 2] = -0.930352f;
+ 	val_dir[13897*3 + 0] = -0.311188f;	val_dir[13897*3 + 1] = 0.177822f;	val_dir[13897*3 + 2] = -0.933564f;
+ 	val_dir[13898*3 + 0] = -0.289677f;	val_dir[13898*3 + 1] = 0.200545f;	val_dir[13898*3 + 2] = -0.935879f;
+ 	val_dir[13899*3 + 0] = -0.267793f;	val_dir[13899*3 + 1] = 0.223161f;	val_dir[13899*3 + 2] = -0.937276f;
+ 	val_dir[13900*3 + 0] = -0.245599f;	val_dir[13900*3 + 1] = 0.245599f;	val_dir[13900*3 + 2] = -0.937743f;
+ 	val_dir[13901*3 + 0] = -0.223161f;	val_dir[13901*3 + 1] = 0.267793f;	val_dir[13901*3 + 2] = -0.937276f;
+ 	val_dir[13902*3 + 0] = -0.200545f;	val_dir[13902*3 + 1] = 0.289677f;	val_dir[13902*3 + 2] = -0.935879f;
+ 	val_dir[13903*3 + 0] = -0.177822f;	val_dir[13903*3 + 1] = 0.311188f;	val_dir[13903*3 + 2] = -0.933564f;
+ 	val_dir[13904*3 + 0] = -0.155059f;	val_dir[13904*3 + 1] = 0.332269f;	val_dir[13904*3 + 2] = -0.930352f;
+ 	val_dir[13905*3 + 0] = -0.132324f;	val_dir[13905*3 + 1] = 0.352865f;	val_dir[13905*3 + 2] = -0.926270f;
+ 	val_dir[13906*3 + 0] = -0.109685f;	val_dir[13906*3 + 1] = 0.372929f;	val_dir[13906*3 + 2] = -0.921354f;
+ 	val_dir[13907*3 + 0] = -0.087204f;	val_dir[13907*3 + 1] = 0.392419f;	val_dir[13907*3 + 2] = -0.915644f;
+ 	val_dir[13908*3 + 0] = -0.064942f;	val_dir[13908*3 + 1] = 0.411298f;	val_dir[13908*3 + 2] = -0.909185f;
+ 	val_dir[13909*3 + 0] = -0.042954f;	val_dir[13909*3 + 1] = 0.429537f;	val_dir[13909*3 + 2] = -0.902027f;
+ 	val_dir[13910*3 + 0] = -0.021291f;	val_dir[13910*3 + 1] = 0.447112f;	val_dir[13910*3 + 2] = -0.894224f;
+ 	val_dir[13911*3 + 0] = 0.0f;	val_dir[13911*3 + 1] = 0.464007f;	val_dir[13911*3 + 2] = -0.885832f;
+ 	val_dir[13912*3 + 0] = 0.021668f;	val_dir[13912*3 + 1] = 0.498354f;	val_dir[13912*3 + 2] = -0.866703f;
+ 	val_dir[13913*3 + 0] = 0.044455f;	val_dir[13913*3 + 1] = 0.533465f;	val_dir[13913*3 + 2] = -0.844653f;
+ 	val_dir[13914*3 + 0] = 0.068288f;	val_dir[13914*3 + 1] = 0.569064f;	val_dir[13914*3 + 2] = -0.819453f;
+ 	val_dir[13915*3 + 0] = 0.093048f;	val_dir[13915*3 + 1] = 0.604815f;	val_dir[13915*3 + 2] = -0.790912f;
+ 	val_dir[13916*3 + 0] = 0.118578f;	val_dir[13916*3 + 1] = 0.640321f;	val_dir[13916*3 + 2] = -0.758899f;
+ 	val_dir[13917*3 + 0] = 0.144673f;	val_dir[13917*3 + 1] = 0.675140f;	val_dir[13917*3 + 2] = -0.723364f;
+ 	val_dir[13918*3 + 0] = 0.171088f;	val_dir[13918*3 + 1] = 0.708794f;	val_dir[13918*3 + 2] = -0.684353f;
+ 	val_dir[13919*3 + 0] = 0.197546f;	val_dir[13919*3 + 1] = 0.740797f;	val_dir[13919*3 + 2] = -0.642024f;
+ 	val_dir[13920*3 + 0] = 0.223745f;	val_dir[13920*3 + 1] = 0.770677f;	val_dir[13920*3 + 2] = -0.596653f;
+ 	val_dir[13921*3 + 0] = 0.249377f;	val_dir[13921*3 + 1] = 0.798007f;	val_dir[13921*3 + 2] = -0.548630f;
+ 	val_dir[13922*3 + 0] = 0.274145f;	val_dir[13922*3 + 1] = 0.822434f;	val_dir[13922*3 + 2] = -0.498445f;
+ 	val_dir[13923*3 + 0] = 0.297775f;	val_dir[13923*3 + 1] = 0.843696f;	val_dir[13923*3 + 2] = -0.446662f;
+ 	val_dir[13924*3 + 0] = 0.320038f;	val_dir[13924*3 + 1] = 0.861640f;	val_dir[13924*3 + 2] = -0.393893f;
+ 	val_dir[13925*3 + 0] = 0.340755f;	val_dir[13925*3 + 1] = 0.876226f;	val_dir[13925*3 + 2] = -0.340755f;
+ 	val_dir[13926*3 + 0] = 0.359804f;	val_dir[13926*3 + 1] = 0.887517f;	val_dir[13926*3 + 2] = -0.287843f;
+ 	val_dir[13927*3 + 0] = 0.377124f;	val_dir[13927*3 + 1] = 0.895669f;	val_dir[13927*3 + 2] = -0.235702f;
+ 	val_dir[13928*3 + 0] = 0.392703f;	val_dir[13928*3 + 1] = 0.900907f;	val_dir[13928*3 + 2] = -0.184801f;
+ 	val_dir[13929*3 + 0] = 0.406579f;	val_dir[13929*3 + 1] = 0.903508f;	val_dir[13929*3 + 2] = -0.135526f;
+ 	val_dir[13930*3 + 0] = 0.418823f;	val_dir[13930*3 + 1] = 0.903777f;	val_dir[13930*3 + 2] = -0.088173f;
+ 	val_dir[13931*3 + 0] = 0.429537f;	val_dir[13931*3 + 1] = 0.902027f;	val_dir[13931*3 + 2] = -0.042954f;
+ 	val_dir[13932*3 + 0] = 0.438835f;	val_dir[13932*3 + 1] = 0.898567f;	val_dir[13932*3 + 2] = 0.0f;
+ 	val_dir[13933*3 + 0] = -0.906520f;	val_dir[13933*3 + 1] = -0.421637f;	val_dir[13933*3 + 2] = -0.021082f;
+ 	val_dir[13934*3 + 0] = -0.909185f;	val_dir[13934*3 + 1] = -0.411298f;	val_dir[13934*3 + 2] = -0.064942f;
+ 	val_dir[13935*3 + 0] = -0.909988f;	val_dir[13935*3 + 1] = -0.399507f;	val_dir[13935*3 + 2] = -0.110974f;
+ 	val_dir[13936*3 + 0] = -0.908622f;	val_dir[13936*3 + 1] = -0.386164f;	val_dir[13936*3 + 2] = -0.159009f;
+ 	val_dir[13937*3 + 0] = -0.904777f;	val_dir[13937*3 + 1] = -0.371191f;	val_dir[13937*3 + 2] = -0.208795f;
+ 	val_dir[13938*3 + 0] = -0.898167f;	val_dir[13938*3 + 1] = -0.354540f;	val_dir[13938*3 + 2] = -0.259996f;
+ 	val_dir[13939*3 + 0] = -0.888540f;	val_dir[13939*3 + 1] = -0.336204f;	val_dir[13939*3 + 2] = -0.312190f;
+ 	val_dir[13940*3 + 0] = -0.875708f;	val_dir[13940*3 + 1] = -0.316228f;	val_dir[13940*3 + 2] = -0.364878f;
+ 	val_dir[13941*3 + 0] = -0.859559f;	val_dir[13941*3 + 1] = -0.294706f;	val_dir[13941*3 + 2] = -0.41750f;
+ 	val_dir[13942*3 + 0] = -0.840083f;	val_dir[13942*3 + 1] = -0.271791f;	val_dir[13942*3 + 2] = -0.469458f;
+ 	val_dir[13943*3 + 0] = -0.817373f;	val_dir[13943*3 + 1] = -0.247689f;	val_dir[13943*3 + 2] = -0.520146f;
+ 	val_dir[13944*3 + 0] = -0.791633f;	val_dir[13944*3 + 1] = -0.222647f;	val_dir[13944*3 + 2] = -0.568986f;
+ 	val_dir[13945*3 + 0] = -0.763167f;	val_dir[13945*3 + 1] = -0.196946f;	val_dir[13945*3 + 2] = -0.615457f;
+ 	val_dir[13946*3 + 0] = -0.732361f;	val_dir[13946*3 + 1] = -0.170884f;	val_dir[13946*3 + 2] = -0.659125f;
+ 	val_dir[13947*3 + 0] = -0.699659f;	val_dir[13947*3 + 1] = -0.144757f;	val_dir[13947*3 + 2] = -0.699659f;
+ 	val_dir[13948*3 + 0] = -0.665536f;	val_dir[13948*3 + 1] = -0.118846f;	val_dir[13948*3 + 2] = -0.736843f;
+ 	val_dir[13949*3 + 0] = -0.630470f;	val_dir[13949*3 + 1] = -0.093403f;	val_dir[13949*3 + 2] = -0.770574f;
+ 	val_dir[13950*3 + 0] = -0.594917f;	val_dir[13950*3 + 1] = -0.068644f;	val_dir[13950*3 + 2] = -0.800850f;
+ 	val_dir[13951*3 + 0] = -0.559297f;	val_dir[13951*3 + 1] = -0.044744f;	val_dir[13951*3 + 2] = -0.827759f;
+ 	val_dir[13952*3 + 0] = -0.523973f;	val_dir[13952*3 + 1] = -0.021832f;	val_dir[13952*3 + 2] = -0.851455f;
+ 	val_dir[13953*3 + 0] = -0.489251f;	val_dir[13953*3 + 1] = 0.0f;	val_dir[13953*3 + 2] = -0.872143f;
+ 	val_dir[13954*3 + 0] = -0.472709f;	val_dir[13954*3 + 1] = 0.021487f;	val_dir[13954*3 + 2] = -0.880957f;
+ 	val_dir[13955*3 + 0] = -0.455447f;	val_dir[13955*3 + 1] = 0.043376f;	val_dir[13955*3 + 2] = -0.889206f;
+ 	val_dir[13956*3 + 0] = -0.437479f;	val_dir[13956*3 + 1] = 0.065622f;	val_dir[13956*3 + 2] = -0.896831f;
+ 	val_dir[13957*3 + 0] = -0.418823f;	val_dir[13957*3 + 1] = 0.088173f;	val_dir[13957*3 + 2] = -0.903777f;
+ 	val_dir[13958*3 + 0] = -0.399507f;	val_dir[13958*3 + 1] = 0.110974f;	val_dir[13958*3 + 2] = -0.909988f;
+ 	val_dir[13959*3 + 0] = -0.379563f;	val_dir[13959*3 + 1] = 0.133963f;	val_dir[13959*3 + 2] = -0.915416f;
+ 	val_dir[13960*3 + 0] = -0.359030f;	val_dir[13960*3 + 1] = 0.157075f;	val_dir[13960*3 + 2] = -0.920014f;
+ 	val_dir[13961*3 + 0] = -0.337954f;	val_dir[13961*3 + 1] = 0.180242f;	val_dir[13961*3 + 2] = -0.923742f;
+ 	val_dir[13962*3 + 0] = -0.316389f;	val_dir[13962*3 + 1] = 0.203393f;	val_dir[13962*3 + 2] = -0.926568f;
+ 	val_dir[13963*3 + 0] = -0.294392f;	val_dir[13963*3 + 1] = 0.226455f;	val_dir[13963*3 + 2] = -0.928467f;
+ 	val_dir[13964*3 + 0] = -0.272026f;	val_dir[13964*3 + 1] = 0.249357f;	val_dir[13964*3 + 2] = -0.929421f;
+ 	val_dir[13965*3 + 0] = -0.249357f;	val_dir[13965*3 + 1] = 0.272026f;	val_dir[13965*3 + 2] = -0.929421f;
+ 	val_dir[13966*3 + 0] = -0.226455f;	val_dir[13966*3 + 1] = 0.294392f;	val_dir[13966*3 + 2] = -0.928467f;
+ 	val_dir[13967*3 + 0] = -0.203393f;	val_dir[13967*3 + 1] = 0.316389f;	val_dir[13967*3 + 2] = -0.926568f;
+ 	val_dir[13968*3 + 0] = -0.180242f;	val_dir[13968*3 + 1] = 0.337954f;	val_dir[13968*3 + 2] = -0.923742f;
+ 	val_dir[13969*3 + 0] = -0.157075f;	val_dir[13969*3 + 1] = 0.359030f;	val_dir[13969*3 + 2] = -0.920014f;
+ 	val_dir[13970*3 + 0] = -0.133963f;	val_dir[13970*3 + 1] = 0.379563f;	val_dir[13970*3 + 2] = -0.915416f;
+ 	val_dir[13971*3 + 0] = -0.110974f;	val_dir[13971*3 + 1] = 0.399507f;	val_dir[13971*3 + 2] = -0.909988f;
+ 	val_dir[13972*3 + 0] = -0.088173f;	val_dir[13972*3 + 1] = 0.418823f;	val_dir[13972*3 + 2] = -0.903777f;
+ 	val_dir[13973*3 + 0] = -0.065622f;	val_dir[13973*3 + 1] = 0.437479f;	val_dir[13973*3 + 2] = -0.896831f;
+ 	val_dir[13974*3 + 0] = -0.043376f;	val_dir[13974*3 + 1] = 0.455447f;	val_dir[13974*3 + 2] = -0.889206f;
+ 	val_dir[13975*3 + 0] = -0.021487f;	val_dir[13975*3 + 1] = 0.472709f;	val_dir[13975*3 + 2] = -0.880957f;
+ 	val_dir[13976*3 + 0] = 0.0f;	val_dir[13976*3 + 1] = 0.489251f;	val_dir[13976*3 + 2] = -0.872143f;
+ 	val_dir[13977*3 + 0] = 0.021832f;	val_dir[13977*3 + 1] = 0.523973f;	val_dir[13977*3 + 2] = -0.851455f;
+ 	val_dir[13978*3 + 0] = 0.044744f;	val_dir[13978*3 + 1] = 0.559297f;	val_dir[13978*3 + 2] = -0.827759f;
+ 	val_dir[13979*3 + 0] = 0.068644f;	val_dir[13979*3 + 1] = 0.594917f;	val_dir[13979*3 + 2] = -0.800850f;
+ 	val_dir[13980*3 + 0] = 0.093403f;	val_dir[13980*3 + 1] = 0.630470f;	val_dir[13980*3 + 2] = -0.770574f;
+ 	val_dir[13981*3 + 0] = 0.118846f;	val_dir[13981*3 + 1] = 0.665536f;	val_dir[13981*3 + 2] = -0.736843f;
+ 	val_dir[13982*3 + 0] = 0.144757f;	val_dir[13982*3 + 1] = 0.699659f;	val_dir[13982*3 + 2] = -0.699659f;
+ 	val_dir[13983*3 + 0] = 0.170884f;	val_dir[13983*3 + 1] = 0.732361f;	val_dir[13983*3 + 2] = -0.659125f;
+ 	val_dir[13984*3 + 0] = 0.196946f;	val_dir[13984*3 + 1] = 0.763167f;	val_dir[13984*3 + 2] = -0.615457f;
+ 	val_dir[13985*3 + 0] = 0.222647f;	val_dir[13985*3 + 1] = 0.791633f;	val_dir[13985*3 + 2] = -0.568986f;
+ 	val_dir[13986*3 + 0] = 0.247689f;	val_dir[13986*3 + 1] = 0.817373f;	val_dir[13986*3 + 2] = -0.520146f;
+ 	val_dir[13987*3 + 0] = 0.271791f;	val_dir[13987*3 + 1] = 0.840083f;	val_dir[13987*3 + 2] = -0.469458f;
+ 	val_dir[13988*3 + 0] = 0.294706f;	val_dir[13988*3 + 1] = 0.859559f;	val_dir[13988*3 + 2] = -0.41750f;
+ 	val_dir[13989*3 + 0] = 0.316228f;	val_dir[13989*3 + 1] = 0.875708f;	val_dir[13989*3 + 2] = -0.364878f;
+ 	val_dir[13990*3 + 0] = 0.336204f;	val_dir[13990*3 + 1] = 0.888540f;	val_dir[13990*3 + 2] = -0.312190f;
+ 	val_dir[13991*3 + 0] = 0.354540f;	val_dir[13991*3 + 1] = 0.898167f;	val_dir[13991*3 + 2] = -0.259996f;
+ 	val_dir[13992*3 + 0] = 0.371191f;	val_dir[13992*3 + 1] = 0.904777f;	val_dir[13992*3 + 2] = -0.208795f;
+ 	val_dir[13993*3 + 0] = 0.386164f;	val_dir[13993*3 + 1] = 0.908622f;	val_dir[13993*3 + 2] = -0.159009f;
+ 	val_dir[13994*3 + 0] = 0.399507f;	val_dir[13994*3 + 1] = 0.909988f;	val_dir[13994*3 + 2] = -0.110974f;
+ 	val_dir[13995*3 + 0] = 0.411298f;	val_dir[13995*3 + 1] = 0.909185f;	val_dir[13995*3 + 2] = -0.064942f;
+ 	val_dir[13996*3 + 0] = 0.421637f;	val_dir[13996*3 + 1] = 0.906520f;	val_dir[13996*3 + 2] = -0.021082f;
+ 	val_dir[13997*3 + 0] = -0.910366f;	val_dir[13997*3 + 1] = -0.413803f;	val_dir[13997*3 + 2] = 0.0f;
+ 	val_dir[13998*3 + 0] = -0.913860f;	val_dir[13998*3 + 1] = -0.403799f;	val_dir[13998*3 + 2] = -0.042505f;
+ 	val_dir[13999*3 + 0] = -0.915644f;	val_dir[13999*3 + 1] = -0.392419f;	val_dir[13999*3 + 2] = -0.087204f;
+ 	val_dir[14000*3 + 0] = -0.915416f;	val_dir[14000*3 + 1] = -0.379563f;	val_dir[14000*3 + 2] = -0.133963f;
+ 	val_dir[14001*3 + 0] = -0.912871f;	val_dir[14001*3 + 1] = -0.365148f;	val_dir[14001*3 + 2] = -0.182574f;
+ 	val_dir[14002*3 + 0] = -0.907713f;	val_dir[14002*3 + 1] = -0.349121f;	val_dir[14002*3 + 2] = -0.232747f;
+ 	val_dir[14003*3 + 0] = -0.899676f;	val_dir[14003*3 + 1] = -0.331460f;	val_dir[14003*3 + 2] = -0.284108f;
+ 	val_dir[14004*3 + 0] = -0.888540f;	val_dir[14004*3 + 1] = -0.312190f;	val_dir[14004*3 + 2] = -0.336204f;
+ 	val_dir[14005*3 + 0] = -0.874157f;	val_dir[14005*3 + 1] = -0.291386f;	val_dir[14005*3 + 2] = -0.388514f;
+ 	val_dir[14006*3 + 0] = -0.856465f;	val_dir[14006*3 + 1] = -0.269175f;	val_dir[14006*3 + 2] = -0.440468f;
+ 	val_dir[14007*3 + 0] = -0.835504f;	val_dir[14007*3 + 1] = -0.245737f;	val_dir[14007*3 + 2] = -0.491473f;
+ 	val_dir[14008*3 + 0] = -0.811421f;	val_dir[14008*3 + 1] = -0.221297f;	val_dir[14008*3 + 2] = -0.540947f;
+ 	val_dir[14009*3 + 0] = -0.784465f;	val_dir[14009*3 + 1] = -0.196116f;	val_dir[14009*3 + 2] = -0.588348f;
+ 	val_dir[14010*3 + 0] = -0.754976f;	val_dir[14010*3 + 1] = -0.170478f;	val_dir[14010*3 + 2] = -0.633205f;
+ 	val_dir[14011*3 + 0] = -0.723364f;	val_dir[14011*3 + 1] = -0.144673f;	val_dir[14011*3 + 2] = -0.675140f;
+ 	val_dir[14012*3 + 0] = -0.690085f;	val_dir[14012*3 + 1] = -0.118980f;	val_dir[14012*3 + 2] = -0.713881f;
+ 	val_dir[14013*3 + 0] = -0.655610f;	val_dir[14013*3 + 1] = -0.093659f;	val_dir[14013*3 + 2] = -0.749269f;
+ 	val_dir[14014*3 + 0] = -0.620403f;	val_dir[14014*3 + 1] = -0.068934f;	val_dir[14014*3 + 2] = -0.781248f;
+ 	val_dir[14015*3 + 0] = -0.584898f;	val_dir[14015*3 + 1] = -0.044992f;	val_dir[14015*3 + 2] = -0.809858f;
+ 	val_dir[14016*3 + 0] = -0.549484f;	val_dir[14016*3 + 1] = -0.021979f;	val_dir[14016*3 + 2] = -0.835215f;
+ 	val_dir[14017*3 + 0] = -0.514496f;	val_dir[14017*3 + 1] = 0.0f;	val_dir[14017*3 + 2] = -0.857493f;
+ 	val_dir[14018*3 + 0] = -0.498354f;	val_dir[14018*3 + 1] = 0.021668f;	val_dir[14018*3 + 2] = -0.866703f;
+ 	val_dir[14019*3 + 0] = -0.481457f;	val_dir[14019*3 + 1] = 0.043769f;	val_dir[14019*3 + 2] = -0.875376f;
+ 	val_dir[14020*3 + 0] = -0.463812f;	val_dir[14020*3 + 1] = 0.066259f;	val_dir[14020*3 + 2] = -0.883452f;
+ 	val_dir[14021*3 + 0] = -0.445435f;	val_dir[14021*3 + 1] = 0.089087f;	val_dir[14021*3 + 2] = -0.890871f;
+ 	val_dir[14022*3 + 0] = -0.426348f;	val_dir[14022*3 + 1] = 0.112197f;	val_dir[14022*3 + 2] = -0.897574f;
+ 	val_dir[14023*3 + 0] = -0.406579f;	val_dir[14023*3 + 1] = 0.135526f;	val_dir[14023*3 + 2] = -0.903508f;
+ 	val_dir[14024*3 + 0] = -0.386164f;	val_dir[14024*3 + 1] = 0.159009f;	val_dir[14024*3 + 2] = -0.908622f;
+ 	val_dir[14025*3 + 0] = -0.365148f;	val_dir[14025*3 + 1] = 0.182574f;	val_dir[14025*3 + 2] = -0.912871f;
+ 	val_dir[14026*3 + 0] = -0.343582f;	val_dir[14026*3 + 1] = 0.206149f;	val_dir[14026*3 + 2] = -0.916217f;
+ 	val_dir[14027*3 + 0] = -0.321521f;	val_dir[14027*3 + 1] = 0.229658f;	val_dir[14027*3 + 2] = -0.918630f;
+ 	val_dir[14028*3 + 0] = -0.299028f;	val_dir[14028*3 + 1] = 0.253024f;	val_dir[14028*3 + 2] = -0.920087f;
+ 	val_dir[14029*3 + 0] = -0.276172f;	val_dir[14029*3 + 1] = 0.276172f;	val_dir[14029*3 + 2] = -0.920575f;
+ 	val_dir[14030*3 + 0] = -0.253024f;	val_dir[14030*3 + 1] = 0.299028f;	val_dir[14030*3 + 2] = -0.920087f;
+ 	val_dir[14031*3 + 0] = -0.229658f;	val_dir[14031*3 + 1] = 0.321521f;	val_dir[14031*3 + 2] = -0.918630f;
+ 	val_dir[14032*3 + 0] = -0.206149f;	val_dir[14032*3 + 1] = 0.343582f;	val_dir[14032*3 + 2] = -0.916217f;
+ 	val_dir[14033*3 + 0] = -0.182574f;	val_dir[14033*3 + 1] = 0.365148f;	val_dir[14033*3 + 2] = -0.912871f;
+ 	val_dir[14034*3 + 0] = -0.159009f;	val_dir[14034*3 + 1] = 0.386164f;	val_dir[14034*3 + 2] = -0.908622f;
+ 	val_dir[14035*3 + 0] = -0.135526f;	val_dir[14035*3 + 1] = 0.406579f;	val_dir[14035*3 + 2] = -0.903508f;
+ 	val_dir[14036*3 + 0] = -0.112197f;	val_dir[14036*3 + 1] = 0.426348f;	val_dir[14036*3 + 2] = -0.897574f;
+ 	val_dir[14037*3 + 0] = -0.089087f;	val_dir[14037*3 + 1] = 0.445435f;	val_dir[14037*3 + 2] = -0.890871f;
+ 	val_dir[14038*3 + 0] = -0.066259f;	val_dir[14038*3 + 1] = 0.463812f;	val_dir[14038*3 + 2] = -0.883452f;
+ 	val_dir[14039*3 + 0] = -0.043769f;	val_dir[14039*3 + 1] = 0.481457f;	val_dir[14039*3 + 2] = -0.875376f;
+ 	val_dir[14040*3 + 0] = -0.021668f;	val_dir[14040*3 + 1] = 0.498354f;	val_dir[14040*3 + 2] = -0.866703f;
+ 	val_dir[14041*3 + 0] = 0.0f;	val_dir[14041*3 + 1] = 0.514496f;	val_dir[14041*3 + 2] = -0.857493f;
+ 	val_dir[14042*3 + 0] = 0.021979f;	val_dir[14042*3 + 1] = 0.549484f;	val_dir[14042*3 + 2] = -0.835215f;
+ 	val_dir[14043*3 + 0] = 0.044992f;	val_dir[14043*3 + 1] = 0.584898f;	val_dir[14043*3 + 2] = -0.809858f;
+ 	val_dir[14044*3 + 0] = 0.068934f;	val_dir[14044*3 + 1] = 0.620403f;	val_dir[14044*3 + 2] = -0.781248f;
+ 	val_dir[14045*3 + 0] = 0.093659f;	val_dir[14045*3 + 1] = 0.655610f;	val_dir[14045*3 + 2] = -0.749269f;
+ 	val_dir[14046*3 + 0] = 0.118980f;	val_dir[14046*3 + 1] = 0.690085f;	val_dir[14046*3 + 2] = -0.713881f;
+ 	val_dir[14047*3 + 0] = 0.144673f;	val_dir[14047*3 + 1] = 0.723364f;	val_dir[14047*3 + 2] = -0.675140f;
+ 	val_dir[14048*3 + 0] = 0.170478f;	val_dir[14048*3 + 1] = 0.754976f;	val_dir[14048*3 + 2] = -0.633205f;
+ 	val_dir[14049*3 + 0] = 0.196116f;	val_dir[14049*3 + 1] = 0.784465f;	val_dir[14049*3 + 2] = -0.588348f;
+ 	val_dir[14050*3 + 0] = 0.221297f;	val_dir[14050*3 + 1] = 0.811421f;	val_dir[14050*3 + 2] = -0.540947f;
+ 	val_dir[14051*3 + 0] = 0.245737f;	val_dir[14051*3 + 1] = 0.835504f;	val_dir[14051*3 + 2] = -0.491473f;
+ 	val_dir[14052*3 + 0] = 0.269175f;	val_dir[14052*3 + 1] = 0.856465f;	val_dir[14052*3 + 2] = -0.440468f;
+ 	val_dir[14053*3 + 0] = 0.291386f;	val_dir[14053*3 + 1] = 0.874157f;	val_dir[14053*3 + 2] = -0.388514f;
+ 	val_dir[14054*3 + 0] = 0.312190f;	val_dir[14054*3 + 1] = 0.888540f;	val_dir[14054*3 + 2] = -0.336204f;
+ 	val_dir[14055*3 + 0] = 0.331460f;	val_dir[14055*3 + 1] = 0.899676f;	val_dir[14055*3 + 2] = -0.284108f;
+ 	val_dir[14056*3 + 0] = 0.349121f;	val_dir[14056*3 + 1] = 0.907713f;	val_dir[14056*3 + 2] = -0.232747f;
+ 	val_dir[14057*3 + 0] = 0.365148f;	val_dir[14057*3 + 1] = 0.912871f;	val_dir[14057*3 + 2] = -0.182574f;
+ 	val_dir[14058*3 + 0] = 0.379563f;	val_dir[14058*3 + 1] = 0.915416f;	val_dir[14058*3 + 2] = -0.133963f;
+ 	val_dir[14059*3 + 0] = 0.392419f;	val_dir[14059*3 + 1] = 0.915644f;	val_dir[14059*3 + 2] = -0.087204f;
+ 	val_dir[14060*3 + 0] = 0.403799f;	val_dir[14060*3 + 1] = 0.913860f;	val_dir[14060*3 + 2] = -0.042505f;
+ 	val_dir[14061*3 + 0] = 0.413803f;	val_dir[14061*3 + 1] = 0.910366f;	val_dir[14061*3 + 2] = 0.0f;
+ 	val_dir[14062*3 + 0] = -0.917863f;	val_dir[14062*3 + 1] = -0.396350f;	val_dir[14062*3 + 2] = -0.020861f;
+ 	val_dir[14063*3 + 0] = -0.920537f;	val_dir[14063*3 + 1] = -0.385341f;	val_dir[14063*3 + 2] = -0.064223f;
+ 	val_dir[14064*3 + 0] = -0.921354f;	val_dir[14064*3 + 1] = -0.372929f;	val_dir[14064*3 + 2] = -0.109685f;
+ 	val_dir[14065*3 + 0] = -0.920014f;	val_dir[14065*3 + 1] = -0.359030f;	val_dir[14065*3 + 2] = -0.157075f;
+ 	val_dir[14066*3 + 0] = -0.916217f;	val_dir[14066*3 + 1] = -0.343582f;	val_dir[14066*3 + 2] = -0.206149f;
+ 	val_dir[14067*3 + 0] = -0.909687f;	val_dir[14067*3 + 1] = -0.326554f;	val_dir[14067*3 + 2] = -0.256578f;
+ 	val_dir[14068*3 + 0] = -0.900181f;	val_dir[14068*3 + 1] = -0.307957f;	val_dir[14068*3 + 2] = -0.307957f;
+ 	val_dir[14069*3 + 0] = -0.887517f;	val_dir[14069*3 + 1] = -0.287843f;	val_dir[14069*3 + 2] = -0.359804f;
+ 	val_dir[14070*3 + 0] = -0.871592f;	val_dir[14070*3 + 1] = -0.266320f;	val_dir[14070*3 + 2] = -0.411585f;
+ 	val_dir[14071*3 + 0] = -0.852392f;	val_dir[14071*3 + 1] = -0.243541f;	val_dir[14071*3 + 2] = -0.462727f;
+ 	val_dir[14072*3 + 0] = -0.830009f;	val_dir[14072*3 + 1] = -0.219708f;	val_dir[14072*3 + 2] = -0.512653f;
+ 	val_dir[14073*3 + 0] = -0.804639f;	val_dir[14073*3 + 1] = -0.195064f;	val_dir[14073*3 + 2] = -0.560809f;
+ 	val_dir[14074*3 + 0] = -0.776571f;	val_dir[14074*3 + 1] = -0.169875f;	val_dir[14074*3 + 2] = -0.606696f;
+ 	val_dir[14075*3 + 0] = -0.746176f;	val_dir[14075*3 + 1] = -0.144421f;	val_dir[14075*3 + 2] = -0.649895f;
+ 	val_dir[14076*3 + 0] = -0.713881f;	val_dir[14076*3 + 1] = -0.118980f;	val_dir[14076*3 + 2] = -0.690085f;
+ 	val_dir[14077*3 + 0] = -0.680144f;	val_dir[14077*3 + 1] = -0.093813f;	val_dir[14077*3 + 2] = -0.727051f;
+ 	val_dir[14078*3 + 0] = -0.645429f;	val_dir[14078*3 + 1] = -0.069153f;	val_dir[14078*3 + 2] = -0.760684f;
+ 	val_dir[14079*3 + 0] = -0.610179f;	val_dir[14079*3 + 1] = -0.045198f;	val_dir[14079*3 + 2] = -0.790973f;
+ 	val_dir[14080*3 + 0] = -0.574805f;	val_dir[14080*3 + 1] = -0.022108f;	val_dir[14080*3 + 2] = -0.817992f;
+ 	val_dir[14081*3 + 0] = -0.539666f;	val_dir[14081*3 + 1] = 0.0f;	val_dir[14081*3 + 2] = -0.841879f;
+ 	val_dir[14082*3 + 0] = -0.523973f;	val_dir[14082*3 + 1] = 0.021832f;	val_dir[14082*3 + 2] = -0.851455f;
+ 	val_dir[14083*3 + 0] = -0.507490f;	val_dir[14083*3 + 1] = 0.044130f;	val_dir[14083*3 + 2] = -0.860527f;
+ 	val_dir[14084*3 + 0] = -0.490222f;	val_dir[14084*3 + 1] = 0.066848f;	val_dir[14084*3 + 2] = -0.869030f;
+ 	val_dir[14085*3 + 0] = -0.472178f;	val_dir[14085*3 + 1] = 0.089939f;	val_dir[14085*3 + 2] = -0.876903f;
+ 	val_dir[14086*3 + 0] = -0.453376f;	val_dir[14086*3 + 1] = 0.113344f;	val_dir[14086*3 + 2] = -0.884083f;
+ 	val_dir[14087*3 + 0] = -0.433840f;	val_dir[14087*3 + 1] = 0.137002f;	val_dir[14087*3 + 2] = -0.890513f;
+ 	val_dir[14088*3 + 0] = -0.413602f;	val_dir[14088*3 + 1] = 0.160845f;	val_dir[14088*3 + 2] = -0.896137f;
+ 	val_dir[14089*3 + 0] = -0.392703f;	val_dir[14089*3 + 1] = 0.184801f;	val_dir[14089*3 + 2] = -0.900907f;
+ 	val_dir[14090*3 + 0] = -0.371191f;	val_dir[14090*3 + 1] = 0.208795f;	val_dir[14090*3 + 2] = -0.904777f;
+ 	val_dir[14091*3 + 0] = -0.349121f;	val_dir[14091*3 + 1] = 0.232747f;	val_dir[14091*3 + 2] = -0.907713f;
+ 	val_dir[14092*3 + 0] = -0.326554f;	val_dir[14092*3 + 1] = 0.256578f;	val_dir[14092*3 + 2] = -0.909687f;
+ 	val_dir[14093*3 + 0] = -0.303559f;	val_dir[14093*3 + 1] = 0.280209f;	val_dir[14093*3 + 2] = -0.910678f;
+ 	val_dir[14094*3 + 0] = -0.280209f;	val_dir[14094*3 + 1] = 0.303559f;	val_dir[14094*3 + 2] = -0.910678f;
+ 	val_dir[14095*3 + 0] = -0.256578f;	val_dir[14095*3 + 1] = 0.326554f;	val_dir[14095*3 + 2] = -0.909687f;
+ 	val_dir[14096*3 + 0] = -0.232747f;	val_dir[14096*3 + 1] = 0.349121f;	val_dir[14096*3 + 2] = -0.907713f;
+ 	val_dir[14097*3 + 0] = -0.208795f;	val_dir[14097*3 + 1] = 0.371191f;	val_dir[14097*3 + 2] = -0.904777f;
+ 	val_dir[14098*3 + 0] = -0.184801f;	val_dir[14098*3 + 1] = 0.392703f;	val_dir[14098*3 + 2] = -0.900907f;
+ 	val_dir[14099*3 + 0] = -0.160845f;	val_dir[14099*3 + 1] = 0.413602f;	val_dir[14099*3 + 2] = -0.896137f;
+ 	val_dir[14100*3 + 0] = -0.137002f;	val_dir[14100*3 + 1] = 0.433840f;	val_dir[14100*3 + 2] = -0.890513f;
+ 	val_dir[14101*3 + 0] = -0.113344f;	val_dir[14101*3 + 1] = 0.453376f;	val_dir[14101*3 + 2] = -0.884083f;
+ 	val_dir[14102*3 + 0] = -0.089939f;	val_dir[14102*3 + 1] = 0.472178f;	val_dir[14102*3 + 2] = -0.876903f;
+ 	val_dir[14103*3 + 0] = -0.066848f;	val_dir[14103*3 + 1] = 0.490222f;	val_dir[14103*3 + 2] = -0.869030f;
+ 	val_dir[14104*3 + 0] = -0.044130f;	val_dir[14104*3 + 1] = 0.507490f;	val_dir[14104*3 + 2] = -0.860527f;
+ 	val_dir[14105*3 + 0] = -0.021832f;	val_dir[14105*3 + 1] = 0.523973f;	val_dir[14105*3 + 2] = -0.851455f;
+ 	val_dir[14106*3 + 0] = 0.0f;	val_dir[14106*3 + 1] = 0.539666f;	val_dir[14106*3 + 2] = -0.841879f;
+ 	val_dir[14107*3 + 0] = 0.022108f;	val_dir[14107*3 + 1] = 0.574805f;	val_dir[14107*3 + 2] = -0.817992f;
+ 	val_dir[14108*3 + 0] = 0.045198f;	val_dir[14108*3 + 1] = 0.610179f;	val_dir[14108*3 + 2] = -0.790973f;
+ 	val_dir[14109*3 + 0] = 0.069153f;	val_dir[14109*3 + 1] = 0.645429f;	val_dir[14109*3 + 2] = -0.760684f;
+ 	val_dir[14110*3 + 0] = 0.093813f;	val_dir[14110*3 + 1] = 0.680144f;	val_dir[14110*3 + 2] = -0.727051f;
+ 	val_dir[14111*3 + 0] = 0.118980f;	val_dir[14111*3 + 1] = 0.713881f;	val_dir[14111*3 + 2] = -0.690085f;
+ 	val_dir[14112*3 + 0] = 0.144421f;	val_dir[14112*3 + 1] = 0.746176f;	val_dir[14112*3 + 2] = -0.649895f;
+ 	val_dir[14113*3 + 0] = 0.169875f;	val_dir[14113*3 + 1] = 0.776571f;	val_dir[14113*3 + 2] = -0.606696f;
+ 	val_dir[14114*3 + 0] = 0.195064f;	val_dir[14114*3 + 1] = 0.804639f;	val_dir[14114*3 + 2] = -0.560809f;
+ 	val_dir[14115*3 + 0] = 0.219708f;	val_dir[14115*3 + 1] = 0.830009f;	val_dir[14115*3 + 2] = -0.512653f;
+ 	val_dir[14116*3 + 0] = 0.243541f;	val_dir[14116*3 + 1] = 0.852392f;	val_dir[14116*3 + 2] = -0.462727f;
+ 	val_dir[14117*3 + 0] = 0.266320f;	val_dir[14117*3 + 1] = 0.871592f;	val_dir[14117*3 + 2] = -0.411585f;
+ 	val_dir[14118*3 + 0] = 0.287843f;	val_dir[14118*3 + 1] = 0.887517f;	val_dir[14118*3 + 2] = -0.359804f;
+ 	val_dir[14119*3 + 0] = 0.307957f;	val_dir[14119*3 + 1] = 0.900181f;	val_dir[14119*3 + 2] = -0.307957f;
+ 	val_dir[14120*3 + 0] = 0.326554f;	val_dir[14120*3 + 1] = 0.909687f;	val_dir[14120*3 + 2] = -0.256578f;
+ 	val_dir[14121*3 + 0] = 0.343582f;	val_dir[14121*3 + 1] = 0.916217f;	val_dir[14121*3 + 2] = -0.206149f;
+ 	val_dir[14122*3 + 0] = 0.359030f;	val_dir[14122*3 + 1] = 0.920014f;	val_dir[14122*3 + 2] = -0.157075f;
+ 	val_dir[14123*3 + 0] = 0.372929f;	val_dir[14123*3 + 1] = 0.921354f;	val_dir[14123*3 + 2] = -0.109685f;
+ 	val_dir[14124*3 + 0] = 0.385341f;	val_dir[14124*3 + 1] = 0.920537f;	val_dir[14124*3 + 2] = -0.064223f;
+ 	val_dir[14125*3 + 0] = 0.396350f;	val_dir[14125*3 + 1] = 0.917863f;	val_dir[14125*3 + 2] = -0.020861f;
+ 	val_dir[14126*3 + 0] = -0.921250f;	val_dir[14126*3 + 1] = -0.388972f;	val_dir[14126*3 + 2] = 0.0f;
+ 	val_dir[14127*3 + 0] = -0.924729f;	val_dir[14127*3 + 1] = -0.378298f;	val_dir[14127*3 + 2] = -0.042033f;
+ 	val_dir[14128*3 + 0] = -0.92650f;	val_dir[14128*3 + 1] = -0.366291f;	val_dir[14128*3 + 2] = -0.086186f;
+ 	val_dir[14129*3 + 0] = -0.926270f;	val_dir[14129*3 + 1] = -0.352865f;	val_dir[14129*3 + 2] = -0.132324f;
+ 	val_dir[14130*3 + 0] = -0.923742f;	val_dir[14130*3 + 1] = -0.337954f;	val_dir[14130*3 + 2] = -0.180242f;
+ 	val_dir[14131*3 + 0] = -0.918630f;	val_dir[14131*3 + 1] = -0.321521f;	val_dir[14131*3 + 2] = -0.229658f;
+ 	val_dir[14132*3 + 0] = -0.910678f;	val_dir[14132*3 + 1] = -0.303559f;	val_dir[14132*3 + 2] = -0.280209f;
+ 	val_dir[14133*3 + 0] = -0.899676f;	val_dir[14133*3 + 1] = -0.284108f;	val_dir[14133*3 + 2] = -0.331460f;
+ 	val_dir[14134*3 + 0] = -0.885482f;	val_dir[14134*3 + 1] = -0.263251f;	val_dir[14134*3 + 2] = -0.382911f;
+ 	val_dir[14135*3 + 0] = -0.868037f;	val_dir[14135*3 + 1] = -0.241121f;	val_dir[14135*3 + 2] = -0.434019f;
+ 	val_dir[14136*3 + 0] = -0.847381f;	val_dir[14136*3 + 1] = -0.217898f;	val_dir[14136*3 + 2] = -0.484217f;
+ 	val_dir[14137*3 + 0] = -0.823653f;	val_dir[14137*3 + 1] = -0.193801f;	val_dir[14137*3 + 2] = -0.532952f;
+ 	val_dir[14138*3 + 0] = -0.797092f;	val_dir[14138*3 + 1] = -0.169080f;	val_dir[14138*3 + 2] = -0.579703f;
+ 	val_dir[14139*3 + 0] = -0.768025f;	val_dir[14139*3 + 1] = -0.144005f;	val_dir[14139*3 + 2] = -0.624020f;
+ 	val_dir[14140*3 + 0] = -0.736843f;	val_dir[14140*3 + 1] = -0.118846f;	val_dir[14140*3 + 2] = -0.665536f;
+ 	val_dir[14141*3 + 0] = -0.703985f;	val_dir[14141*3 + 1] = -0.093865f;	val_dir[14141*3 + 2] = -0.703985f;
+ 	val_dir[14142*3 + 0] = -0.669905f;	val_dir[14142*3 + 1] = -0.069301f;	val_dir[14142*3 + 2] = -0.739205f;
+ 	val_dir[14143*3 + 0] = -0.635053f;	val_dir[14143*3 + 1] = -0.045361f;	val_dir[14143*3 + 2] = -0.771136f;
+ 	val_dir[14144*3 + 0] = -0.599852f;	val_dir[14144*3 + 1] = -0.022217f;	val_dir[14144*3 + 2] = -0.799803f;
+ 	val_dir[14145*3 + 0] = -0.564684f;	val_dir[14145*3 + 1] = 0.0f;	val_dir[14145*3 + 2] = -0.825307f;
+ 	val_dir[14146*3 + 0] = -0.549484f;	val_dir[14146*3 + 1] = 0.021979f;	val_dir[14146*3 + 2] = -0.835215f;
+ 	val_dir[14147*3 + 0] = -0.533465f;	val_dir[14147*3 + 1] = 0.044455f;	val_dir[14147*3 + 2] = -0.844653f;
+ 	val_dir[14148*3 + 0] = -0.516626f;	val_dir[14148*3 + 1] = 0.067386f;	val_dir[14148*3 + 2] = -0.853556f;
+ 	val_dir[14149*3 + 0] = -0.498970f;	val_dir[14149*3 + 1] = 0.090722f;	val_dir[14149*3 + 2] = -0.861857f;
+ 	val_dir[14150*3 + 0] = -0.480510f;	val_dir[14150*3 + 1] = 0.114407f;	val_dir[14150*3 + 2] = -0.869495f;
+ 	val_dir[14151*3 + 0] = -0.461266f;	val_dir[14151*3 + 1] = 0.138380f;	val_dir[14151*3 + 2] = -0.876405f;
+ 	val_dir[14152*3 + 0] = -0.441264f;	val_dir[14152*3 + 1] = 0.162571f;	val_dir[14152*3 + 2] = -0.882528f;
+ 	val_dir[14153*3 + 0] = -0.420542f;	val_dir[14153*3 + 1] = 0.186908f;	val_dir[14153*3 + 2] = -0.887812f;
+ 	val_dir[14154*3 + 0] = -0.399145f;	val_dir[14154*3 + 1] = 0.211312f;	val_dir[14154*3 + 2] = -0.892206f;
+ 	val_dir[14155*3 + 0] = -0.377124f;	val_dir[14155*3 + 1] = 0.235702f;	val_dir[14155*3 + 2] = -0.895669f;
+ 	val_dir[14156*3 + 0] = -0.354540f;	val_dir[14156*3 + 1] = 0.259996f;	val_dir[14156*3 + 2] = -0.898167f;
+ 	val_dir[14157*3 + 0] = -0.331460f;	val_dir[14157*3 + 1] = 0.284108f;	val_dir[14157*3 + 2] = -0.899676f;
+ 	val_dir[14158*3 + 0] = -0.307957f;	val_dir[14158*3 + 1] = 0.307957f;	val_dir[14158*3 + 2] = -0.900181f;
+ 	val_dir[14159*3 + 0] = -0.284108f;	val_dir[14159*3 + 1] = 0.331460f;	val_dir[14159*3 + 2] = -0.899676f;
+ 	val_dir[14160*3 + 0] = -0.259996f;	val_dir[14160*3 + 1] = 0.354540f;	val_dir[14160*3 + 2] = -0.898167f;
+ 	val_dir[14161*3 + 0] = -0.235702f;	val_dir[14161*3 + 1] = 0.377124f;	val_dir[14161*3 + 2] = -0.895669f;
+ 	val_dir[14162*3 + 0] = -0.211312f;	val_dir[14162*3 + 1] = 0.399145f;	val_dir[14162*3 + 2] = -0.892206f;
+ 	val_dir[14163*3 + 0] = -0.186908f;	val_dir[14163*3 + 1] = 0.420542f;	val_dir[14163*3 + 2] = -0.887812f;
+ 	val_dir[14164*3 + 0] = -0.162571f;	val_dir[14164*3 + 1] = 0.441264f;	val_dir[14164*3 + 2] = -0.882528f;
+ 	val_dir[14165*3 + 0] = -0.138380f;	val_dir[14165*3 + 1] = 0.461266f;	val_dir[14165*3 + 2] = -0.876405f;
+ 	val_dir[14166*3 + 0] = -0.114407f;	val_dir[14166*3 + 1] = 0.480510f;	val_dir[14166*3 + 2] = -0.869495f;
+ 	val_dir[14167*3 + 0] = -0.090722f;	val_dir[14167*3 + 1] = 0.498970f;	val_dir[14167*3 + 2] = -0.861857f;
+ 	val_dir[14168*3 + 0] = -0.067386f;	val_dir[14168*3 + 1] = 0.516626f;	val_dir[14168*3 + 2] = -0.853556f;
+ 	val_dir[14169*3 + 0] = -0.044455f;	val_dir[14169*3 + 1] = 0.533465f;	val_dir[14169*3 + 2] = -0.844653f;
+ 	val_dir[14170*3 + 0] = -0.021979f;	val_dir[14170*3 + 1] = 0.549484f;	val_dir[14170*3 + 2] = -0.835215f;
+ 	val_dir[14171*3 + 0] = 0.0f;	val_dir[14171*3 + 1] = 0.564684f;	val_dir[14171*3 + 2] = -0.825307f;
+ 	val_dir[14172*3 + 0] = 0.022217f;	val_dir[14172*3 + 1] = 0.599852f;	val_dir[14172*3 + 2] = -0.799803f;
+ 	val_dir[14173*3 + 0] = 0.045361f;	val_dir[14173*3 + 1] = 0.635053f;	val_dir[14173*3 + 2] = -0.771136f;
+ 	val_dir[14174*3 + 0] = 0.069301f;	val_dir[14174*3 + 1] = 0.669905f;	val_dir[14174*3 + 2] = -0.739205f;
+ 	val_dir[14175*3 + 0] = 0.093865f;	val_dir[14175*3 + 1] = 0.703985f;	val_dir[14175*3 + 2] = -0.703985f;
+ 	val_dir[14176*3 + 0] = 0.118846f;	val_dir[14176*3 + 1] = 0.736843f;	val_dir[14176*3 + 2] = -0.665536f;
+ 	val_dir[14177*3 + 0] = 0.144005f;	val_dir[14177*3 + 1] = 0.768025f;	val_dir[14177*3 + 2] = -0.624020f;
+ 	val_dir[14178*3 + 0] = 0.169080f;	val_dir[14178*3 + 1] = 0.797092f;	val_dir[14178*3 + 2] = -0.579703f;
+ 	val_dir[14179*3 + 0] = 0.193801f;	val_dir[14179*3 + 1] = 0.823653f;	val_dir[14179*3 + 2] = -0.532952f;
+ 	val_dir[14180*3 + 0] = 0.217898f;	val_dir[14180*3 + 1] = 0.847381f;	val_dir[14180*3 + 2] = -0.484217f;
+ 	val_dir[14181*3 + 0] = 0.241121f;	val_dir[14181*3 + 1] = 0.868037f;	val_dir[14181*3 + 2] = -0.434019f;
+ 	val_dir[14182*3 + 0] = 0.263251f;	val_dir[14182*3 + 1] = 0.885482f;	val_dir[14182*3 + 2] = -0.382911f;
+ 	val_dir[14183*3 + 0] = 0.284108f;	val_dir[14183*3 + 1] = 0.899676f;	val_dir[14183*3 + 2] = -0.331460f;
+ 	val_dir[14184*3 + 0] = 0.303559f;	val_dir[14184*3 + 1] = 0.910678f;	val_dir[14184*3 + 2] = -0.280209f;
+ 	val_dir[14185*3 + 0] = 0.321521f;	val_dir[14185*3 + 1] = 0.918630f;	val_dir[14185*3 + 2] = -0.229658f;
+ 	val_dir[14186*3 + 0] = 0.337954f;	val_dir[14186*3 + 1] = 0.923742f;	val_dir[14186*3 + 2] = -0.180242f;
+ 	val_dir[14187*3 + 0] = 0.352865f;	val_dir[14187*3 + 1] = 0.926270f;	val_dir[14187*3 + 2] = -0.132324f;
+ 	val_dir[14188*3 + 0] = 0.366291f;	val_dir[14188*3 + 1] = 0.92650f;	val_dir[14188*3 + 2] = -0.086186f;
+ 	val_dir[14189*3 + 0] = 0.378298f;	val_dir[14189*3 + 1] = 0.924729f;	val_dir[14189*3 + 2] = -0.042033f;
+ 	val_dir[14190*3 + 0] = 0.388972f;	val_dir[14190*3 + 1] = 0.921250f;	val_dir[14190*3 + 2] = 0.0f;
+ 	val_dir[14191*3 + 0] = -0.928279f;	val_dir[14191*3 + 1] = -0.371312f;	val_dir[14191*3 + 2] = -0.020628f;
+ 	val_dir[14192*3 + 0] = -0.930917f;	val_dir[14192*3 + 1] = -0.359673f;	val_dir[14192*3 + 2] = -0.063472f;
+ 	val_dir[14193*3 + 0] = -0.931705f;	val_dir[14193*3 + 1] = -0.346681f;	val_dir[14193*3 + 2] = -0.108338f;
+ 	val_dir[14194*3 + 0] = -0.930352f;	val_dir[14194*3 + 1] = -0.332269f;	val_dir[14194*3 + 2] = -0.155059f;
+ 	val_dir[14195*3 + 0] = -0.926568f;	val_dir[14195*3 + 1] = -0.316389f;	val_dir[14195*3 + 2] = -0.203393f;
+ 	val_dir[14196*3 + 0] = -0.920087f;	val_dir[14196*3 + 1] = -0.299028f;	val_dir[14196*3 + 2] = -0.253024f;
+ 	val_dir[14197*3 + 0] = -0.910678f;	val_dir[14197*3 + 1] = -0.280209f;	val_dir[14197*3 + 2] = -0.303559f;
+ 	val_dir[14198*3 + 0] = -0.898167f;	val_dir[14198*3 + 1] = -0.259996f;	val_dir[14198*3 + 2] = -0.354540f;
+ 	val_dir[14199*3 + 0] = -0.882454f;	val_dir[14199*3 + 1] = -0.238501f;	val_dir[14199*3 + 2] = -0.405452f;
+ 	val_dir[14200*3 + 0] = -0.863530f;	val_dir[14200*3 + 1] = -0.215883f;	val_dir[14200*3 + 2] = -0.455752f;
+ 	val_dir[14201*3 + 0] = -0.841482f;	val_dir[14201*3 + 1] = -0.192339f;	val_dir[14201*3 + 2] = -0.504889f;
+ 	val_dir[14202*3 + 0] = -0.816497f;	val_dir[14202*3 + 1] = -0.168102f;	val_dir[14202*3 + 2] = -0.552336f;
+ 	val_dir[14203*3 + 0] = -0.788851f;	val_dir[14203*3 + 1] = -0.143427f;	val_dir[14203*3 + 2] = -0.597614f;
+ 	val_dir[14204*3 + 0] = -0.758899f;	val_dir[14204*3 + 1] = -0.118578f;	val_dir[14204*3 + 2] = -0.640321f;
+ 	val_dir[14205*3 + 0] = -0.727051f;	val_dir[14205*3 + 1] = -0.093813f;	val_dir[14205*3 + 2] = -0.680144f;
+ 	val_dir[14206*3 + 0] = -0.693746f;	val_dir[14206*3 + 1] = -0.069375f;	val_dir[14206*3 + 2] = -0.716871f;
+ 	val_dir[14207*3 + 0] = -0.659432f;	val_dir[14207*3 + 1] = -0.045478f;	val_dir[14207*3 + 2] = -0.750388f;
+ 	val_dir[14208*3 + 0] = -0.624540f;	val_dir[14208*3 + 1] = -0.022305f;	val_dir[14208*3 + 2] = -0.780675f;
+ 	val_dir[14209*3 + 0] = -0.589469f;	val_dir[14209*3 + 1] = 0.0f;	val_dir[14209*3 + 2] = -0.807791f;
+ 	val_dir[14210*3 + 0] = -0.574805f;	val_dir[14210*3 + 1] = 0.022108f;	val_dir[14210*3 + 2] = -0.817992f;
+ 	val_dir[14211*3 + 0] = -0.559297f;	val_dir[14211*3 + 1] = 0.044744f;	val_dir[14211*3 + 2] = -0.827759f;
+ 	val_dir[14212*3 + 0] = -0.542936f;	val_dir[14212*3 + 1] = 0.067867f;	val_dir[14212*3 + 2] = -0.837027f;
+ 	val_dir[14213*3 + 0] = -0.525723f;	val_dir[14213*3 + 1] = 0.091430f;	val_dir[14213*3 + 2] = -0.845728f;
+ 	val_dir[14214*3 + 0] = -0.507662f;	val_dir[14214*3 + 1] = 0.115378f;	val_dir[14214*3 + 2] = -0.853796f;
+ 	val_dir[14215*3 + 0] = -0.488769f;	val_dir[14215*3 + 1] = 0.139648f;	val_dir[14215*3 + 2] = -0.861164f;
+ 	val_dir[14216*3 + 0] = -0.469065f;	val_dir[14216*3 + 1] = 0.164173f;	val_dir[14216*3 + 2] = -0.867770f;
+ 	val_dir[14217*3 + 0] = -0.448583f;	val_dir[14217*3 + 1] = 0.188877f;	val_dir[14217*3 + 2] = -0.873555f;
+ 	val_dir[14218*3 + 0] = -0.427362f;	val_dir[14218*3 + 1] = 0.213681f;	val_dir[14218*3 + 2] = -0.878466f;
+ 	val_dir[14219*3 + 0] = -0.405452f;	val_dir[14219*3 + 1] = 0.238501f;	val_dir[14219*3 + 2] = -0.882454f;
+ 	val_dir[14220*3 + 0] = -0.382911f;	val_dir[14220*3 + 1] = 0.263251f;	val_dir[14220*3 + 2] = -0.885482f;
+ 	val_dir[14221*3 + 0] = -0.359804f;	val_dir[14221*3 + 1] = 0.287843f;	val_dir[14221*3 + 2] = -0.887517f;
+ 	val_dir[14222*3 + 0] = -0.336204f;	val_dir[14222*3 + 1] = 0.312190f;	val_dir[14222*3 + 2] = -0.888540f;
+ 	val_dir[14223*3 + 0] = -0.312190f;	val_dir[14223*3 + 1] = 0.336204f;	val_dir[14223*3 + 2] = -0.888540f;
+ 	val_dir[14224*3 + 0] = -0.287843f;	val_dir[14224*3 + 1] = 0.359804f;	val_dir[14224*3 + 2] = -0.887517f;
+ 	val_dir[14225*3 + 0] = -0.263251f;	val_dir[14225*3 + 1] = 0.382911f;	val_dir[14225*3 + 2] = -0.885482f;
+ 	val_dir[14226*3 + 0] = -0.238501f;	val_dir[14226*3 + 1] = 0.405452f;	val_dir[14226*3 + 2] = -0.882454f;
+ 	val_dir[14227*3 + 0] = -0.213681f;	val_dir[14227*3 + 1] = 0.427362f;	val_dir[14227*3 + 2] = -0.878466f;
+ 	val_dir[14228*3 + 0] = -0.188877f;	val_dir[14228*3 + 1] = 0.448583f;	val_dir[14228*3 + 2] = -0.873555f;
+ 	val_dir[14229*3 + 0] = -0.164173f;	val_dir[14229*3 + 1] = 0.469065f;	val_dir[14229*3 + 2] = -0.867770f;
+ 	val_dir[14230*3 + 0] = -0.139648f;	val_dir[14230*3 + 1] = 0.488769f;	val_dir[14230*3 + 2] = -0.861164f;
+ 	val_dir[14231*3 + 0] = -0.115378f;	val_dir[14231*3 + 1] = 0.507662f;	val_dir[14231*3 + 2] = -0.853796f;
+ 	val_dir[14232*3 + 0] = -0.091430f;	val_dir[14232*3 + 1] = 0.525723f;	val_dir[14232*3 + 2] = -0.845728f;
+ 	val_dir[14233*3 + 0] = -0.067867f;	val_dir[14233*3 + 1] = 0.542936f;	val_dir[14233*3 + 2] = -0.837027f;
+ 	val_dir[14234*3 + 0] = -0.044744f;	val_dir[14234*3 + 1] = 0.559297f;	val_dir[14234*3 + 2] = -0.827759f;
+ 	val_dir[14235*3 + 0] = -0.022108f;	val_dir[14235*3 + 1] = 0.574805f;	val_dir[14235*3 + 2] = -0.817992f;
+ 	val_dir[14236*3 + 0] = 0.0f;	val_dir[14236*3 + 1] = 0.589469f;	val_dir[14236*3 + 2] = -0.807791f;
+ 	val_dir[14237*3 + 0] = 0.022305f;	val_dir[14237*3 + 1] = 0.624540f;	val_dir[14237*3 + 2] = -0.780675f;
+ 	val_dir[14238*3 + 0] = 0.045478f;	val_dir[14238*3 + 1] = 0.659432f;	val_dir[14238*3 + 2] = -0.750388f;
+ 	val_dir[14239*3 + 0] = 0.069375f;	val_dir[14239*3 + 1] = 0.693746f;	val_dir[14239*3 + 2] = -0.716871f;
+ 	val_dir[14240*3 + 0] = 0.093813f;	val_dir[14240*3 + 1] = 0.727051f;	val_dir[14240*3 + 2] = -0.680144f;
+ 	val_dir[14241*3 + 0] = 0.118578f;	val_dir[14241*3 + 1] = 0.758899f;	val_dir[14241*3 + 2] = -0.640321f;
+ 	val_dir[14242*3 + 0] = 0.143427f;	val_dir[14242*3 + 1] = 0.788851f;	val_dir[14242*3 + 2] = -0.597614f;
+ 	val_dir[14243*3 + 0] = 0.168102f;	val_dir[14243*3 + 1] = 0.816497f;	val_dir[14243*3 + 2] = -0.552336f;
+ 	val_dir[14244*3 + 0] = 0.192339f;	val_dir[14244*3 + 1] = 0.841482f;	val_dir[14244*3 + 2] = -0.504889f;
+ 	val_dir[14245*3 + 0] = 0.215883f;	val_dir[14245*3 + 1] = 0.863530f;	val_dir[14245*3 + 2] = -0.455752f;
+ 	val_dir[14246*3 + 0] = 0.238501f;	val_dir[14246*3 + 1] = 0.882454f;	val_dir[14246*3 + 2] = -0.405452f;
+ 	val_dir[14247*3 + 0] = 0.259996f;	val_dir[14247*3 + 1] = 0.898167f;	val_dir[14247*3 + 2] = -0.354540f;
+ 	val_dir[14248*3 + 0] = 0.280209f;	val_dir[14248*3 + 1] = 0.910678f;	val_dir[14248*3 + 2] = -0.303559f;
+ 	val_dir[14249*3 + 0] = 0.299028f;	val_dir[14249*3 + 1] = 0.920087f;	val_dir[14249*3 + 2] = -0.253024f;
+ 	val_dir[14250*3 + 0] = 0.316389f;	val_dir[14250*3 + 1] = 0.926568f;	val_dir[14250*3 + 2] = -0.203393f;
+ 	val_dir[14251*3 + 0] = 0.332269f;	val_dir[14251*3 + 1] = 0.930352f;	val_dir[14251*3 + 2] = -0.155059f;
+ 	val_dir[14252*3 + 0] = 0.346681f;	val_dir[14252*3 + 1] = 0.931705f;	val_dir[14252*3 + 2] = -0.108338f;
+ 	val_dir[14253*3 + 0] = 0.359673f;	val_dir[14253*3 + 1] = 0.930917f;	val_dir[14253*3 + 2] = -0.063472f;
+ 	val_dir[14254*3 + 0] = 0.371312f;	val_dir[14254*3 + 1] = 0.928279f;	val_dir[14254*3 + 2] = -0.020628f;
+ 	val_dir[14255*3 + 0] = -0.931243f;	val_dir[14255*3 + 1] = -0.364399f;	val_dir[14255*3 + 2] = 0.0f;
+ 	val_dir[14256*3 + 0] = -0.934665f;	val_dir[14256*3 + 1] = -0.353096f;	val_dir[14256*3 + 2] = -0.041541f;
+ 	val_dir[14257*3 + 0] = -0.936382f;	val_dir[14257*3 + 1] = -0.340503f;	val_dir[14257*3 + 2] = -0.085126f;
+ 	val_dir[14258*3 + 0] = -0.936111f;	val_dir[14258*3 + 1] = -0.326550f;	val_dir[14258*3 + 2] = -0.130620f;
+ 	val_dir[14259*3 + 0] = -0.933564f;	val_dir[14259*3 + 1] = -0.311188f;	val_dir[14259*3 + 2] = -0.177822f;
+ 	val_dir[14260*3 + 0] = -0.928467f;	val_dir[14260*3 + 1] = -0.294392f;	val_dir[14260*3 + 2] = -0.226455f;
+ 	val_dir[14261*3 + 0] = -0.920575f;	val_dir[14261*3 + 1] = -0.276172f;	val_dir[14261*3 + 2] = -0.276172f;
+ 	val_dir[14262*3 + 0] = -0.909687f;	val_dir[14262*3 + 1] = -0.256578f;	val_dir[14262*3 + 2] = -0.326554f;
+ 	val_dir[14263*3 + 0] = -0.895669f;	val_dir[14263*3 + 1] = -0.235702f;	val_dir[14263*3 + 2] = -0.377124f;
+ 	val_dir[14264*3 + 0] = -0.878466f;	val_dir[14264*3 + 1] = -0.213681f;	val_dir[14264*3 + 2] = -0.427362f;
+ 	val_dir[14265*3 + 0] = -0.858116f;	val_dir[14265*3 + 1] = -0.190693f;	val_dir[14265*3 + 2] = -0.476731f;
+ 	val_dir[14266*3 + 0] = -0.834754f;	val_dir[14266*3 + 1] = -0.166951f;	val_dir[14266*3 + 2] = -0.524703f;
+ 	val_dir[14267*3 + 0] = -0.808608f;	val_dir[14267*3 + 1] = -0.142695f;	val_dir[14267*3 + 2] = -0.570782f;
+ 	val_dir[14268*3 + 0] = -0.779987f;	val_dir[14268*3 + 1] = -0.118180f;	val_dir[14268*3 + 2] = -0.614535f;
+ 	val_dir[14269*3 + 0] = -0.749269f;	val_dir[14269*3 + 1] = -0.093659f;	val_dir[14269*3 + 2] = -0.655610f;
+ 	val_dir[14270*3 + 0] = -0.716871f;	val_dir[14270*3 + 1] = -0.069375f;	val_dir[14270*3 + 2] = -0.693746f;
+ 	val_dir[14271*3 + 0] = -0.683231f;	val_dir[14271*3 + 1] = -0.045549f;	val_dir[14271*3 + 2] = -0.728780f;
+ 	val_dir[14272*3 + 0] = -0.648784f;	val_dir[14272*3 + 1] = -0.022372f;	val_dir[14272*3 + 2] = -0.760644f;
+ 	val_dir[14273*3 + 0] = -0.613941f;	val_dir[14273*3 + 1] = 0.0f;	val_dir[14273*3 + 2] = -0.789352f;
+ 	val_dir[14274*3 + 0] = -0.599852f;	val_dir[14274*3 + 1] = 0.022217f;	val_dir[14274*3 + 2] = -0.799803f;
+ 	val_dir[14275*3 + 0] = -0.584898f;	val_dir[14275*3 + 1] = 0.044992f;	val_dir[14275*3 + 2] = -0.809858f;
+ 	val_dir[14276*3 + 0] = -0.569064f;	val_dir[14276*3 + 1] = 0.068288f;	val_dir[14276*3 + 2] = -0.819453f;
+ 	val_dir[14277*3 + 0] = -0.552345f;	val_dir[14277*3 + 1] = 0.092057f;	val_dir[14277*3 + 2] = -0.828517f;
+ 	val_dir[14278*3 + 0] = -0.534739f;	val_dir[14278*3 + 1] = 0.116248f;	val_dir[14278*3 + 2] = -0.836983f;
+ 	val_dir[14279*3 + 0] = -0.516256f;	val_dir[14279*3 + 1] = 0.140797f;	val_dir[14279*3 + 2] = -0.844782f;
+ 	val_dir[14280*3 + 0] = -0.496911f;	val_dir[14280*3 + 1] = 0.165637f;	val_dir[14280*3 + 2] = -0.851847f;
+ 	val_dir[14281*3 + 0] = -0.476731f;	val_dir[14281*3 + 1] = 0.190693f;	val_dir[14281*3 + 2] = -0.858116f;
+ 	val_dir[14282*3 + 0] = -0.455752f;	val_dir[14282*3 + 1] = 0.215883f;	val_dir[14282*3 + 2] = -0.863530f;
+ 	val_dir[14283*3 + 0] = -0.434019f;	val_dir[14283*3 + 1] = 0.241121f;	val_dir[14283*3 + 2] = -0.868037f;
+ 	val_dir[14284*3 + 0] = -0.411585f;	val_dir[14284*3 + 1] = 0.266320f;	val_dir[14284*3 + 2] = -0.871592f;
+ 	val_dir[14285*3 + 0] = -0.388514f;	val_dir[14285*3 + 1] = 0.291386f;	val_dir[14285*3 + 2] = -0.874157f;
+ 	val_dir[14286*3 + 0] = -0.364878f;	val_dir[14286*3 + 1] = 0.316228f;	val_dir[14286*3 + 2] = -0.875708f;
+ 	val_dir[14287*3 + 0] = -0.340755f;	val_dir[14287*3 + 1] = 0.340755f;	val_dir[14287*3 + 2] = -0.876226f;
+ 	val_dir[14288*3 + 0] = -0.316228f;	val_dir[14288*3 + 1] = 0.364878f;	val_dir[14288*3 + 2] = -0.875708f;
+ 	val_dir[14289*3 + 0] = -0.291386f;	val_dir[14289*3 + 1] = 0.388514f;	val_dir[14289*3 + 2] = -0.874157f;
+ 	val_dir[14290*3 + 0] = -0.266320f;	val_dir[14290*3 + 1] = 0.411585f;	val_dir[14290*3 + 2] = -0.871592f;
+ 	val_dir[14291*3 + 0] = -0.241121f;	val_dir[14291*3 + 1] = 0.434019f;	val_dir[14291*3 + 2] = -0.868037f;
+ 	val_dir[14292*3 + 0] = -0.215883f;	val_dir[14292*3 + 1] = 0.455752f;	val_dir[14292*3 + 2] = -0.863530f;
+ 	val_dir[14293*3 + 0] = -0.190693f;	val_dir[14293*3 + 1] = 0.476731f;	val_dir[14293*3 + 2] = -0.858116f;
+ 	val_dir[14294*3 + 0] = -0.165637f;	val_dir[14294*3 + 1] = 0.496911f;	val_dir[14294*3 + 2] = -0.851847f;
+ 	val_dir[14295*3 + 0] = -0.140797f;	val_dir[14295*3 + 1] = 0.516256f;	val_dir[14295*3 + 2] = -0.844782f;
+ 	val_dir[14296*3 + 0] = -0.116248f;	val_dir[14296*3 + 1] = 0.534739f;	val_dir[14296*3 + 2] = -0.836983f;
+ 	val_dir[14297*3 + 0] = -0.092057f;	val_dir[14297*3 + 1] = 0.552345f;	val_dir[14297*3 + 2] = -0.828517f;
+ 	val_dir[14298*3 + 0] = -0.068288f;	val_dir[14298*3 + 1] = 0.569064f;	val_dir[14298*3 + 2] = -0.819453f;
+ 	val_dir[14299*3 + 0] = -0.044992f;	val_dir[14299*3 + 1] = 0.584898f;	val_dir[14299*3 + 2] = -0.809858f;
+ 	val_dir[14300*3 + 0] = -0.022217f;	val_dir[14300*3 + 1] = 0.599852f;	val_dir[14300*3 + 2] = -0.799803f;
+ 	val_dir[14301*3 + 0] = 0.0f;	val_dir[14301*3 + 1] = 0.613941f;	val_dir[14301*3 + 2] = -0.789352f;
+ 	val_dir[14302*3 + 0] = 0.022372f;	val_dir[14302*3 + 1] = 0.648784f;	val_dir[14302*3 + 2] = -0.760644f;
+ 	val_dir[14303*3 + 0] = 0.045549f;	val_dir[14303*3 + 1] = 0.683231f;	val_dir[14303*3 + 2] = -0.728780f;
+ 	val_dir[14304*3 + 0] = 0.069375f;	val_dir[14304*3 + 1] = 0.716871f;	val_dir[14304*3 + 2] = -0.693746f;
+ 	val_dir[14305*3 + 0] = 0.093659f;	val_dir[14305*3 + 1] = 0.749269f;	val_dir[14305*3 + 2] = -0.655610f;
+ 	val_dir[14306*3 + 0] = 0.118180f;	val_dir[14306*3 + 1] = 0.779987f;	val_dir[14306*3 + 2] = -0.614535f;
+ 	val_dir[14307*3 + 0] = 0.142695f;	val_dir[14307*3 + 1] = 0.808608f;	val_dir[14307*3 + 2] = -0.570782f;
+ 	val_dir[14308*3 + 0] = 0.166951f;	val_dir[14308*3 + 1] = 0.834754f;	val_dir[14308*3 + 2] = -0.524703f;
+ 	val_dir[14309*3 + 0] = 0.190693f;	val_dir[14309*3 + 1] = 0.858116f;	val_dir[14309*3 + 2] = -0.476731f;
+ 	val_dir[14310*3 + 0] = 0.213681f;	val_dir[14310*3 + 1] = 0.878466f;	val_dir[14310*3 + 2] = -0.427362f;
+ 	val_dir[14311*3 + 0] = 0.235702f;	val_dir[14311*3 + 1] = 0.895669f;	val_dir[14311*3 + 2] = -0.377124f;
+ 	val_dir[14312*3 + 0] = 0.256578f;	val_dir[14312*3 + 1] = 0.909687f;	val_dir[14312*3 + 2] = -0.326554f;
+ 	val_dir[14313*3 + 0] = 0.276172f;	val_dir[14313*3 + 1] = 0.920575f;	val_dir[14313*3 + 2] = -0.276172f;
+ 	val_dir[14314*3 + 0] = 0.294392f;	val_dir[14314*3 + 1] = 0.928467f;	val_dir[14314*3 + 2] = -0.226455f;
+ 	val_dir[14315*3 + 0] = 0.311188f;	val_dir[14315*3 + 1] = 0.933564f;	val_dir[14315*3 + 2] = -0.177822f;
+ 	val_dir[14316*3 + 0] = 0.326550f;	val_dir[14316*3 + 1] = 0.936111f;	val_dir[14316*3 + 2] = -0.130620f;
+ 	val_dir[14317*3 + 0] = 0.340503f;	val_dir[14317*3 + 1] = 0.936382f;	val_dir[14317*3 + 2] = -0.085126f;
+ 	val_dir[14318*3 + 0] = 0.353096f;	val_dir[14318*3 + 1] = 0.934665f;	val_dir[14318*3 + 2] = -0.041541f;
+ 	val_dir[14319*3 + 0] = 0.364399f;	val_dir[14319*3 + 1] = 0.931243f;	val_dir[14319*3 + 2] = 0.0f;
+ 	val_dir[14320*3 + 0] = -0.93780f;	val_dir[14320*3 + 1] = -0.346578f;	val_dir[14320*3 + 2] = -0.020387f;
+ 	val_dir[14321*3 + 0] = -0.940361f;	val_dir[14321*3 + 1] = -0.334351f;	val_dir[14321*3 + 2] = -0.062691f;
+ 	val_dir[14322*3 + 0] = -0.941082f;	val_dir[14322*3 + 1] = -0.320824f;	val_dir[14322*3 + 2] = -0.106941f;
+ 	val_dir[14323*3 + 0] = -0.939680f;	val_dir[14323*3 + 1] = -0.305942f;	val_dir[14323*3 + 2] = -0.152971f;
+ 	val_dir[14324*3 + 0] = -0.935879f;	val_dir[14324*3 + 1] = -0.289677f;	val_dir[14324*3 + 2] = -0.200545f;
+ 	val_dir[14325*3 + 0] = -0.929421f;	val_dir[14325*3 + 1] = -0.272026f;	val_dir[14325*3 + 2] = -0.249357f;
+ 	val_dir[14326*3 + 0] = -0.920087f;	val_dir[14326*3 + 1] = -0.253024f;	val_dir[14326*3 + 2] = -0.299028f;
+ 	val_dir[14327*3 + 0] = -0.907713f;	val_dir[14327*3 + 1] = -0.232747f;	val_dir[14327*3 + 2] = -0.349121f;
+ 	val_dir[14328*3 + 0] = -0.892206f;	val_dir[14328*3 + 1] = -0.211312f;	val_dir[14328*3 + 2] = -0.399145f;
+ 	val_dir[14329*3 + 0] = -0.873555f;	val_dir[14329*3 + 1] = -0.188877f;	val_dir[14329*3 + 2] = -0.448583f;
+ 	val_dir[14330*3 + 0] = -0.851847f;	val_dir[14330*3 + 1] = -0.165637f;	val_dir[14330*3 + 2] = -0.496911f;
+ 	val_dir[14331*3 + 0] = -0.827259f;	val_dir[14331*3 + 1] = -0.141816f;	val_dir[14331*3 + 2] = -0.543627f;
+ 	val_dir[14332*3 + 0] = -0.800055f;	val_dir[14332*3 + 1] = -0.117655f;	val_dir[14332*3 + 2] = -0.588276f;
+ 	val_dir[14333*3 + 0] = -0.770574f;	val_dir[14333*3 + 1] = -0.093403f;	val_dir[14333*3 + 2] = -0.630470f;
+ 	val_dir[14334*3 + 0] = -0.739205f;	val_dir[14334*3 + 1] = -0.069301f;	val_dir[14334*3 + 2] = -0.669905f;
+ 	val_dir[14335*3 + 0] = -0.706372f;	val_dir[14335*3 + 1] = -0.045572f;	val_dir[14335*3 + 2] = -0.706372f;
+ 	val_dir[14336*3 + 0] = -0.672504f;	val_dir[14336*3 + 1] = -0.022417f;	val_dir[14336*3 + 2] = -0.739754f;
+ 	val_dir[14337*3 + 0] = -0.638018f;	val_dir[14337*3 + 1] = 0.0f;	val_dir[14337*3 + 2] = -0.770022f;
+ 	val_dir[14338*3 + 0] = -0.624540f;	val_dir[14338*3 + 1] = 0.022305f;	val_dir[14338*3 + 2] = -0.780675f;
+ 	val_dir[14339*3 + 0] = -0.610179f;	val_dir[14339*3 + 1] = 0.045198f;	val_dir[14339*3 + 2] = -0.790973f;
+ 	val_dir[14340*3 + 0] = -0.594917f;	val_dir[14340*3 + 1] = 0.068644f;	val_dir[14340*3 + 2] = -0.800850f;
+ 	val_dir[14341*3 + 0] = -0.578741f;	val_dir[14341*3 + 1] = 0.092599f;	val_dir[14341*3 + 2] = -0.810237f;
+ 	val_dir[14342*3 + 0] = -0.561644f;	val_dir[14342*3 + 1] = 0.117009f;	val_dir[14342*3 + 2] = -0.819064f;
+ 	val_dir[14343*3 + 0] = -0.543627f;	val_dir[14343*3 + 1] = 0.141816f;	val_dir[14343*3 + 2] = -0.827259f;
+ 	val_dir[14344*3 + 0] = -0.524703f;	val_dir[14344*3 + 1] = 0.166951f;	val_dir[14344*3 + 2] = -0.834754f;
+ 	val_dir[14345*3 + 0] = -0.504889f;	val_dir[14345*3 + 1] = 0.192339f;	val_dir[14345*3 + 2] = -0.841482f;
+ 	val_dir[14346*3 + 0] = -0.484217f;	val_dir[14346*3 + 1] = 0.217898f;	val_dir[14346*3 + 2] = -0.847381f;
+ 	val_dir[14347*3 + 0] = -0.462727f;	val_dir[14347*3 + 1] = 0.243541f;	val_dir[14347*3 + 2] = -0.852392f;
+ 	val_dir[14348*3 + 0] = -0.440468f;	val_dir[14348*3 + 1] = 0.269175f;	val_dir[14348*3 + 2] = -0.856465f;
+ 	val_dir[14349*3 + 0] = -0.41750f;	val_dir[14349*3 + 1] = 0.294706f;	val_dir[14349*3 + 2] = -0.859559f;
+ 	val_dir[14350*3 + 0] = -0.393893f;	val_dir[14350*3 + 1] = 0.320038f;	val_dir[14350*3 + 2] = -0.861640f;
+ 	val_dir[14351*3 + 0] = -0.369723f;	val_dir[14351*3 + 1] = 0.345075f;	val_dir[14351*3 + 2] = -0.862687f;
+ 	val_dir[14352*3 + 0] = -0.345075f;	val_dir[14352*3 + 1] = 0.369723f;	val_dir[14352*3 + 2] = -0.862687f;
+ 	val_dir[14353*3 + 0] = -0.320038f;	val_dir[14353*3 + 1] = 0.393893f;	val_dir[14353*3 + 2] = -0.861640f;
+ 	val_dir[14354*3 + 0] = -0.294706f;	val_dir[14354*3 + 1] = 0.41750f;	val_dir[14354*3 + 2] = -0.859559f;
+ 	val_dir[14355*3 + 0] = -0.269175f;	val_dir[14355*3 + 1] = 0.440468f;	val_dir[14355*3 + 2] = -0.856465f;
+ 	val_dir[14356*3 + 0] = -0.243541f;	val_dir[14356*3 + 1] = 0.462727f;	val_dir[14356*3 + 2] = -0.852392f;
+ 	val_dir[14357*3 + 0] = -0.217898f;	val_dir[14357*3 + 1] = 0.484217f;	val_dir[14357*3 + 2] = -0.847381f;
+ 	val_dir[14358*3 + 0] = -0.192339f;	val_dir[14358*3 + 1] = 0.504889f;	val_dir[14358*3 + 2] = -0.841482f;
+ 	val_dir[14359*3 + 0] = -0.166951f;	val_dir[14359*3 + 1] = 0.524703f;	val_dir[14359*3 + 2] = -0.834754f;
+ 	val_dir[14360*3 + 0] = -0.141816f;	val_dir[14360*3 + 1] = 0.543627f;	val_dir[14360*3 + 2] = -0.827259f;
+ 	val_dir[14361*3 + 0] = -0.117009f;	val_dir[14361*3 + 1] = 0.561644f;	val_dir[14361*3 + 2] = -0.819064f;
+ 	val_dir[14362*3 + 0] = -0.092599f;	val_dir[14362*3 + 1] = 0.578741f;	val_dir[14362*3 + 2] = -0.810237f;
+ 	val_dir[14363*3 + 0] = -0.068644f;	val_dir[14363*3 + 1] = 0.594917f;	val_dir[14363*3 + 2] = -0.800850f;
+ 	val_dir[14364*3 + 0] = -0.045198f;	val_dir[14364*3 + 1] = 0.610179f;	val_dir[14364*3 + 2] = -0.790973f;
+ 	val_dir[14365*3 + 0] = -0.022305f;	val_dir[14365*3 + 1] = 0.624540f;	val_dir[14365*3 + 2] = -0.780675f;
+ 	val_dir[14366*3 + 0] = 0.0f;	val_dir[14366*3 + 1] = 0.638018f;	val_dir[14366*3 + 2] = -0.770022f;
+ 	val_dir[14367*3 + 0] = 0.022417f;	val_dir[14367*3 + 1] = 0.672504f;	val_dir[14367*3 + 2] = -0.739754f;
+ 	val_dir[14368*3 + 0] = 0.045572f;	val_dir[14368*3 + 1] = 0.706372f;	val_dir[14368*3 + 2] = -0.706372f;
+ 	val_dir[14369*3 + 0] = 0.069301f;	val_dir[14369*3 + 1] = 0.739205f;	val_dir[14369*3 + 2] = -0.669905f;
+ 	val_dir[14370*3 + 0] = 0.093403f;	val_dir[14370*3 + 1] = 0.770574f;	val_dir[14370*3 + 2] = -0.630470f;
+ 	val_dir[14371*3 + 0] = 0.117655f;	val_dir[14371*3 + 1] = 0.800055f;	val_dir[14371*3 + 2] = -0.588276f;
+ 	val_dir[14372*3 + 0] = 0.141816f;	val_dir[14372*3 + 1] = 0.827259f;	val_dir[14372*3 + 2] = -0.543627f;
+ 	val_dir[14373*3 + 0] = 0.165637f;	val_dir[14373*3 + 1] = 0.851847f;	val_dir[14373*3 + 2] = -0.496911f;
+ 	val_dir[14374*3 + 0] = 0.188877f;	val_dir[14374*3 + 1] = 0.873555f;	val_dir[14374*3 + 2] = -0.448583f;
+ 	val_dir[14375*3 + 0] = 0.211312f;	val_dir[14375*3 + 1] = 0.892206f;	val_dir[14375*3 + 2] = -0.399145f;
+ 	val_dir[14376*3 + 0] = 0.232747f;	val_dir[14376*3 + 1] = 0.907713f;	val_dir[14376*3 + 2] = -0.349121f;
+ 	val_dir[14377*3 + 0] = 0.253024f;	val_dir[14377*3 + 1] = 0.920087f;	val_dir[14377*3 + 2] = -0.299028f;
+ 	val_dir[14378*3 + 0] = 0.272026f;	val_dir[14378*3 + 1] = 0.929421f;	val_dir[14378*3 + 2] = -0.249357f;
+ 	val_dir[14379*3 + 0] = 0.289677f;	val_dir[14379*3 + 1] = 0.935879f;	val_dir[14379*3 + 2] = -0.200545f;
+ 	val_dir[14380*3 + 0] = 0.305942f;	val_dir[14380*3 + 1] = 0.939680f;	val_dir[14380*3 + 2] = -0.152971f;
+ 	val_dir[14381*3 + 0] = 0.320824f;	val_dir[14381*3 + 1] = 0.941082f;	val_dir[14381*3 + 2] = -0.106941f;
+ 	val_dir[14382*3 + 0] = 0.334351f;	val_dir[14382*3 + 1] = 0.940361f;	val_dir[14382*3 + 2] = -0.062691f;
+ 	val_dir[14383*3 + 0] = 0.346578f;	val_dir[14383*3 + 1] = 0.93780f;	val_dir[14383*3 + 2] = -0.020387f;
+ 	val_dir[14384*3 + 0] = -0.940376f;	val_dir[14384*3 + 1] = -0.340136f;	val_dir[14384*3 + 2] = 0.0f;
+ 	val_dir[14385*3 + 0] = -0.943701f;	val_dir[14385*3 + 1] = -0.328244f;	val_dir[14385*3 + 2] = -0.041030f;
+ 	val_dir[14386*3 + 0] = -0.945328f;	val_dir[14386*3 + 1] = -0.315109f;	val_dir[14386*3 + 2] = -0.084029f;
+ 	val_dir[14387*3 + 0] = -0.944981f;	val_dir[14387*3 + 1] = -0.300676f;	val_dir[14387*3 + 2] = -0.128861f;
+ 	val_dir[14388*3 + 0] = -0.942384f;	val_dir[14388*3 + 1] = -0.284907f;	val_dir[14388*3 + 2] = -0.175327f;
+ 	val_dir[14389*3 + 0] = -0.937276f;	val_dir[14389*3 + 1] = -0.267793f;	val_dir[14389*3 + 2] = -0.223161f;
+ 	val_dir[14390*3 + 0] = -0.929421f;	val_dir[14390*3 + 1] = -0.249357f;	val_dir[14390*3 + 2] = -0.272026f;
+ 	val_dir[14391*3 + 0] = -0.918630f;	val_dir[14391*3 + 1] = -0.229658f;	val_dir[14391*3 + 2] = -0.321521f;
+ 	val_dir[14392*3 + 0] = -0.904777f;	val_dir[14392*3 + 1] = -0.208795f;	val_dir[14392*3 + 2] = -0.371191f;
+ 	val_dir[14393*3 + 0] = -0.887812f;	val_dir[14393*3 + 1] = -0.186908f;	val_dir[14393*3 + 2] = -0.420542f;
+ 	val_dir[14394*3 + 0] = -0.867770f;	val_dir[14394*3 + 1] = -0.164173f;	val_dir[14394*3 + 2] = -0.469065f;
+ 	val_dir[14395*3 + 0] = -0.844782f;	val_dir[14395*3 + 1] = -0.140797f;	val_dir[14395*3 + 2] = -0.516256f;
+ 	val_dir[14396*3 + 0] = -0.819064f;	val_dir[14396*3 + 1] = -0.117009f;	val_dir[14396*3 + 2] = -0.561644f;
+ 	val_dir[14397*3 + 0] = -0.790912f;	val_dir[14397*3 + 1] = -0.093048f;	val_dir[14397*3 + 2] = -0.604815f;
+ 	val_dir[14398*3 + 0] = -0.760684f;	val_dir[14398*3 + 1] = -0.069153f;	val_dir[14398*3 + 2] = -0.645429f;
+ 	val_dir[14399*3 + 0] = -0.728780f;	val_dir[14399*3 + 1] = -0.045549f;	val_dir[14399*3 + 2] = -0.683231f;
+ 	val_dir[14400*3 + 0] = -0.695620f;	val_dir[14400*3 + 1] = -0.022439f;	val_dir[14400*3 + 2] = -0.718059f;
+ 	val_dir[14401*3 + 0] = -0.661622f;	val_dir[14401*3 + 1] = 0.0f;	val_dir[14401*3 + 2] = -0.749838f;
+ 	val_dir[14402*3 + 0] = -0.648784f;	val_dir[14402*3 + 1] = 0.022372f;	val_dir[14402*3 + 2] = -0.760644f;
+ 	val_dir[14403*3 + 0] = -0.635053f;	val_dir[14403*3 + 1] = 0.045361f;	val_dir[14403*3 + 2] = -0.771136f;
+ 	val_dir[14404*3 + 0] = -0.620403f;	val_dir[14404*3 + 1] = 0.068934f;	val_dir[14404*3 + 2] = -0.781248f;
+ 	val_dir[14405*3 + 0] = -0.604815f;	val_dir[14405*3 + 1] = 0.093048f;	val_dir[14405*3 + 2] = -0.790912f;
+ 	val_dir[14406*3 + 0] = -0.588276f;	val_dir[14406*3 + 1] = 0.117655f;	val_dir[14406*3 + 2] = -0.800055f;
+ 	val_dir[14407*3 + 0] = -0.570782f;	val_dir[14407*3 + 1] = 0.142695f;	val_dir[14407*3 + 2] = -0.808608f;
+ 	val_dir[14408*3 + 0] = -0.552336f;	val_dir[14408*3 + 1] = 0.168102f;	val_dir[14408*3 + 2] = -0.816497f;
+ 	val_dir[14409*3 + 0] = -0.532952f;	val_dir[14409*3 + 1] = 0.193801f;	val_dir[14409*3 + 2] = -0.823653f;
+ 	val_dir[14410*3 + 0] = -0.512653f;	val_dir[14410*3 + 1] = 0.219708f;	val_dir[14410*3 + 2] = -0.830009f;
+ 	val_dir[14411*3 + 0] = -0.491473f;	val_dir[14411*3 + 1] = 0.245737f;	val_dir[14411*3 + 2] = -0.835504f;
+ 	val_dir[14412*3 + 0] = -0.469458f;	val_dir[14412*3 + 1] = 0.271791f;	val_dir[14412*3 + 2] = -0.840083f;
+ 	val_dir[14413*3 + 0] = -0.446662f;	val_dir[14413*3 + 1] = 0.297775f;	val_dir[14413*3 + 2] = -0.843696f;
+ 	val_dir[14414*3 + 0] = -0.423153f;	val_dir[14414*3 + 1] = 0.323587f;	val_dir[14414*3 + 2] = -0.846305f;
+ 	val_dir[14415*3 + 0] = -0.399004f;	val_dir[14415*3 + 1] = 0.349128f;	val_dir[14415*3 + 2] = -0.847883f;
+ 	val_dir[14416*3 + 0] = -0.374299f;	val_dir[14416*3 + 1] = 0.374299f;	val_dir[14416*3 + 2] = -0.848411f;
+ 	val_dir[14417*3 + 0] = -0.349128f;	val_dir[14417*3 + 1] = 0.399004f;	val_dir[14417*3 + 2] = -0.847883f;
+ 	val_dir[14418*3 + 0] = -0.323587f;	val_dir[14418*3 + 1] = 0.423153f;	val_dir[14418*3 + 2] = -0.846305f;
+ 	val_dir[14419*3 + 0] = -0.297775f;	val_dir[14419*3 + 1] = 0.446662f;	val_dir[14419*3 + 2] = -0.843696f;
+ 	val_dir[14420*3 + 0] = -0.271791f;	val_dir[14420*3 + 1] = 0.469458f;	val_dir[14420*3 + 2] = -0.840083f;
+ 	val_dir[14421*3 + 0] = -0.245737f;	val_dir[14421*3 + 1] = 0.491473f;	val_dir[14421*3 + 2] = -0.835504f;
+ 	val_dir[14422*3 + 0] = -0.219708f;	val_dir[14422*3 + 1] = 0.512653f;	val_dir[14422*3 + 2] = -0.830009f;
+ 	val_dir[14423*3 + 0] = -0.193801f;	val_dir[14423*3 + 1] = 0.532952f;	val_dir[14423*3 + 2] = -0.823653f;
+ 	val_dir[14424*3 + 0] = -0.168102f;	val_dir[14424*3 + 1] = 0.552336f;	val_dir[14424*3 + 2] = -0.816497f;
+ 	val_dir[14425*3 + 0] = -0.142695f;	val_dir[14425*3 + 1] = 0.570782f;	val_dir[14425*3 + 2] = -0.808608f;
+ 	val_dir[14426*3 + 0] = -0.117655f;	val_dir[14426*3 + 1] = 0.588276f;	val_dir[14426*3 + 2] = -0.800055f;
+ 	val_dir[14427*3 + 0] = -0.093048f;	val_dir[14427*3 + 1] = 0.604815f;	val_dir[14427*3 + 2] = -0.790912f;
+ 	val_dir[14428*3 + 0] = -0.068934f;	val_dir[14428*3 + 1] = 0.620403f;	val_dir[14428*3 + 2] = -0.781248f;
+ 	val_dir[14429*3 + 0] = -0.045361f;	val_dir[14429*3 + 1] = 0.635053f;	val_dir[14429*3 + 2] = -0.771136f;
+ 	val_dir[14430*3 + 0] = -0.022372f;	val_dir[14430*3 + 1] = 0.648784f;	val_dir[14430*3 + 2] = -0.760644f;
+ 	val_dir[14431*3 + 0] = 0.0f;	val_dir[14431*3 + 1] = 0.661622f;	val_dir[14431*3 + 2] = -0.749838f;
+ 	val_dir[14432*3 + 0] = 0.022439f;	val_dir[14432*3 + 1] = 0.695620f;	val_dir[14432*3 + 2] = -0.718059f;
+ 	val_dir[14433*3 + 0] = 0.045549f;	val_dir[14433*3 + 1] = 0.728780f;	val_dir[14433*3 + 2] = -0.683231f;
+ 	val_dir[14434*3 + 0] = 0.069153f;	val_dir[14434*3 + 1] = 0.760684f;	val_dir[14434*3 + 2] = -0.645429f;
+ 	val_dir[14435*3 + 0] = 0.093048f;	val_dir[14435*3 + 1] = 0.790912f;	val_dir[14435*3 + 2] = -0.604815f;
+ 	val_dir[14436*3 + 0] = 0.117009f;	val_dir[14436*3 + 1] = 0.819064f;	val_dir[14436*3 + 2] = -0.561644f;
+ 	val_dir[14437*3 + 0] = 0.140797f;	val_dir[14437*3 + 1] = 0.844782f;	val_dir[14437*3 + 2] = -0.516256f;
+ 	val_dir[14438*3 + 0] = 0.164173f;	val_dir[14438*3 + 1] = 0.867770f;	val_dir[14438*3 + 2] = -0.469065f;
+ 	val_dir[14439*3 + 0] = 0.186908f;	val_dir[14439*3 + 1] = 0.887812f;	val_dir[14439*3 + 2] = -0.420542f;
+ 	val_dir[14440*3 + 0] = 0.208795f;	val_dir[14440*3 + 1] = 0.904777f;	val_dir[14440*3 + 2] = -0.371191f;
+ 	val_dir[14441*3 + 0] = 0.229658f;	val_dir[14441*3 + 1] = 0.918630f;	val_dir[14441*3 + 2] = -0.321521f;
+ 	val_dir[14442*3 + 0] = 0.249357f;	val_dir[14442*3 + 1] = 0.929421f;	val_dir[14442*3 + 2] = -0.272026f;
+ 	val_dir[14443*3 + 0] = 0.267793f;	val_dir[14443*3 + 1] = 0.937276f;	val_dir[14443*3 + 2] = -0.223161f;
+ 	val_dir[14444*3 + 0] = 0.284907f;	val_dir[14444*3 + 1] = 0.942384f;	val_dir[14444*3 + 2] = -0.175327f;
+ 	val_dir[14445*3 + 0] = 0.300676f;	val_dir[14445*3 + 1] = 0.944981f;	val_dir[14445*3 + 2] = -0.128861f;
+ 	val_dir[14446*3 + 0] = 0.315109f;	val_dir[14446*3 + 1] = 0.945328f;	val_dir[14446*3 + 2] = -0.084029f;
+ 	val_dir[14447*3 + 0] = 0.328244f;	val_dir[14447*3 + 1] = 0.943701f;	val_dir[14447*3 + 2] = -0.041030f;
+ 	val_dir[14448*3 + 0] = 0.340136f;	val_dir[14448*3 + 1] = 0.940376f;	val_dir[14448*3 + 2] = 0.0f;
+ 	val_dir[14449*3 + 0] = -0.946458f;	val_dir[14449*3 + 1] = -0.322198f;	val_dir[14449*3 + 2] = -0.020137f;
+ 	val_dir[14450*3 + 0] = -0.948908f;	val_dir[14450*3 + 1] = -0.309426f;	val_dir[14450*3 + 2] = -0.061885f;
+ 	val_dir[14451*3 + 0] = -0.949528f;	val_dir[14451*3 + 1] = -0.295409f;	val_dir[14451*3 + 2] = -0.105503f;
+ 	val_dir[14452*3 + 0] = -0.948047f;	val_dir[14452*3 + 1] = -0.280105f;	val_dir[14452*3 + 2] = -0.150826f;
+ 	val_dir[14453*3 + 0] = -0.94420f;	val_dir[14453*3 + 1] = -0.263498f;	val_dir[14453*3 + 2] = -0.197623f;
+ 	val_dir[14454*3 + 0] = -0.937743f;	val_dir[14454*3 + 1] = -0.245599f;	val_dir[14454*3 + 2] = -0.245599f;
+ 	val_dir[14455*3 + 0] = -0.928467f;	val_dir[14455*3 + 1] = -0.226455f;	val_dir[14455*3 + 2] = -0.294392f;
+ 	val_dir[14456*3 + 0] = -0.916217f;	val_dir[14456*3 + 1] = -0.206149f;	val_dir[14456*3 + 2] = -0.343582f;
+ 	val_dir[14457*3 + 0] = -0.900907f;	val_dir[14457*3 + 1] = -0.184801f;	val_dir[14457*3 + 2] = -0.392703f;
+ 	val_dir[14458*3 + 0] = -0.882528f;	val_dir[14458*3 + 1] = -0.162571f;	val_dir[14458*3 + 2] = -0.441264f;
+ 	val_dir[14459*3 + 0] = -0.861164f;	val_dir[14459*3 + 1] = -0.139648f;	val_dir[14459*3 + 2] = -0.488769f;
+ 	val_dir[14460*3 + 0] = -0.836983f;	val_dir[14460*3 + 1] = -0.116248f;	val_dir[14460*3 + 2] = -0.534739f;
+ 	val_dir[14461*3 + 0] = -0.810237f;	val_dir[14461*3 + 1] = -0.092599f;	val_dir[14461*3 + 2] = -0.578741f;
+ 	val_dir[14462*3 + 0] = -0.781248f;	val_dir[14462*3 + 1] = -0.068934f;	val_dir[14462*3 + 2] = -0.620403f;
+ 	val_dir[14463*3 + 0] = -0.750388f;	val_dir[14463*3 + 1] = -0.045478f;	val_dir[14463*3 + 2] = -0.659432f;
+ 	val_dir[14464*3 + 0] = -0.718059f;	val_dir[14464*3 + 1] = -0.022439f;	val_dir[14464*3 + 2] = -0.695620f;
+ 	val_dir[14465*3 + 0] = -0.684675f;	val_dir[14465*3 + 1] = 0.0f;	val_dir[14465*3 + 2] = -0.728848f;
+ 	val_dir[14466*3 + 0] = -0.672504f;	val_dir[14466*3 + 1] = 0.022417f;	val_dir[14466*3 + 2] = -0.739754f;
+ 	val_dir[14467*3 + 0] = -0.659432f;	val_dir[14467*3 + 1] = 0.045478f;	val_dir[14467*3 + 2] = -0.750388f;
+ 	val_dir[14468*3 + 0] = -0.645429f;	val_dir[14468*3 + 1] = 0.069153f;	val_dir[14468*3 + 2] = -0.760684f;
+ 	val_dir[14469*3 + 0] = -0.630470f;	val_dir[14469*3 + 1] = 0.093403f;	val_dir[14469*3 + 2] = -0.770574f;
+ 	val_dir[14470*3 + 0] = -0.614535f;	val_dir[14470*3 + 1] = 0.118180f;	val_dir[14470*3 + 2] = -0.779987f;
+ 	val_dir[14471*3 + 0] = -0.597614f;	val_dir[14471*3 + 1] = 0.143427f;	val_dir[14471*3 + 2] = -0.788851f;
+ 	val_dir[14472*3 + 0] = -0.579703f;	val_dir[14472*3 + 1] = 0.169080f;	val_dir[14472*3 + 2] = -0.797092f;
+ 	val_dir[14473*3 + 0] = -0.560809f;	val_dir[14473*3 + 1] = 0.195064f;	val_dir[14473*3 + 2] = -0.804639f;
+ 	val_dir[14474*3 + 0] = -0.540947f;	val_dir[14474*3 + 1] = 0.221297f;	val_dir[14474*3 + 2] = -0.811421f;
+ 	val_dir[14475*3 + 0] = -0.520146f;	val_dir[14475*3 + 1] = 0.247689f;	val_dir[14475*3 + 2] = -0.817373f;
+ 	val_dir[14476*3 + 0] = -0.498445f;	val_dir[14476*3 + 1] = 0.274145f;	val_dir[14476*3 + 2] = -0.822434f;
+ 	val_dir[14477*3 + 0] = -0.475893f;	val_dir[14477*3 + 1] = 0.300564f;	val_dir[14477*3 + 2] = -0.826551f;
+ 	val_dir[14478*3 + 0] = -0.452553f;	val_dir[14478*3 + 1] = 0.326844f;	val_dir[14478*3 + 2] = -0.829680f;
+ 	val_dir[14479*3 + 0] = -0.428496f;	val_dir[14479*3 + 1] = 0.352879f;	val_dir[14479*3 + 2] = -0.831786f;
+ 	val_dir[14480*3 + 0] = -0.403804f;	val_dir[14480*3 + 1] = 0.378566f;	val_dir[14480*3 + 2] = -0.832845f;
+ 	val_dir[14481*3 + 0] = -0.378566f;	val_dir[14481*3 + 1] = 0.403804f;	val_dir[14481*3 + 2] = -0.832845f;
+ 	val_dir[14482*3 + 0] = -0.352879f;	val_dir[14482*3 + 1] = 0.428496f;	val_dir[14482*3 + 2] = -0.831786f;
+ 	val_dir[14483*3 + 0] = -0.326844f;	val_dir[14483*3 + 1] = 0.452553f;	val_dir[14483*3 + 2] = -0.829680f;
+ 	val_dir[14484*3 + 0] = -0.300564f;	val_dir[14484*3 + 1] = 0.475893f;	val_dir[14484*3 + 2] = -0.826551f;
+ 	val_dir[14485*3 + 0] = -0.274145f;	val_dir[14485*3 + 1] = 0.498445f;	val_dir[14485*3 + 2] = -0.822434f;
+ 	val_dir[14486*3 + 0] = -0.247689f;	val_dir[14486*3 + 1] = 0.520146f;	val_dir[14486*3 + 2] = -0.817373f;
+ 	val_dir[14487*3 + 0] = -0.221297f;	val_dir[14487*3 + 1] = 0.540947f;	val_dir[14487*3 + 2] = -0.811421f;
+ 	val_dir[14488*3 + 0] = -0.195064f;	val_dir[14488*3 + 1] = 0.560809f;	val_dir[14488*3 + 2] = -0.804639f;
+ 	val_dir[14489*3 + 0] = -0.169080f;	val_dir[14489*3 + 1] = 0.579703f;	val_dir[14489*3 + 2] = -0.797092f;
+ 	val_dir[14490*3 + 0] = -0.143427f;	val_dir[14490*3 + 1] = 0.597614f;	val_dir[14490*3 + 2] = -0.788851f;
+ 	val_dir[14491*3 + 0] = -0.118180f;	val_dir[14491*3 + 1] = 0.614535f;	val_dir[14491*3 + 2] = -0.779987f;
+ 	val_dir[14492*3 + 0] = -0.093403f;	val_dir[14492*3 + 1] = 0.630470f;	val_dir[14492*3 + 2] = -0.770574f;
+ 	val_dir[14493*3 + 0] = -0.069153f;	val_dir[14493*3 + 1] = 0.645429f;	val_dir[14493*3 + 2] = -0.760684f;
+ 	val_dir[14494*3 + 0] = -0.045478f;	val_dir[14494*3 + 1] = 0.659432f;	val_dir[14494*3 + 2] = -0.750388f;
+ 	val_dir[14495*3 + 0] = -0.022417f;	val_dir[14495*3 + 1] = 0.672504f;	val_dir[14495*3 + 2] = -0.739754f;
+ 	val_dir[14496*3 + 0] = 0.0f;	val_dir[14496*3 + 1] = 0.684675f;	val_dir[14496*3 + 2] = -0.728848f;
+ 	val_dir[14497*3 + 0] = 0.022439f;	val_dir[14497*3 + 1] = 0.718059f;	val_dir[14497*3 + 2] = -0.695620f;
+ 	val_dir[14498*3 + 0] = 0.045478f;	val_dir[14498*3 + 1] = 0.750388f;	val_dir[14498*3 + 2] = -0.659432f;
+ 	val_dir[14499*3 + 0] = 0.068934f;	val_dir[14499*3 + 1] = 0.781248f;	val_dir[14499*3 + 2] = -0.620403f;
+ 	val_dir[14500*3 + 0] = 0.092599f;	val_dir[14500*3 + 1] = 0.810237f;	val_dir[14500*3 + 2] = -0.578741f;
+ 	val_dir[14501*3 + 0] = 0.116248f;	val_dir[14501*3 + 1] = 0.836983f;	val_dir[14501*3 + 2] = -0.534739f;
+ 	val_dir[14502*3 + 0] = 0.139648f;	val_dir[14502*3 + 1] = 0.861164f;	val_dir[14502*3 + 2] = -0.488769f;
+ 	val_dir[14503*3 + 0] = 0.162571f;	val_dir[14503*3 + 1] = 0.882528f;	val_dir[14503*3 + 2] = -0.441264f;
+ 	val_dir[14504*3 + 0] = 0.184801f;	val_dir[14504*3 + 1] = 0.900907f;	val_dir[14504*3 + 2] = -0.392703f;
+ 	val_dir[14505*3 + 0] = 0.206149f;	val_dir[14505*3 + 1] = 0.916217f;	val_dir[14505*3 + 2] = -0.343582f;
+ 	val_dir[14506*3 + 0] = 0.226455f;	val_dir[14506*3 + 1] = 0.928467f;	val_dir[14506*3 + 2] = -0.294392f;
+ 	val_dir[14507*3 + 0] = 0.245599f;	val_dir[14507*3 + 1] = 0.937743f;	val_dir[14507*3 + 2] = -0.245599f;
+ 	val_dir[14508*3 + 0] = 0.263498f;	val_dir[14508*3 + 1] = 0.94420f;	val_dir[14508*3 + 2] = -0.197623f;
+ 	val_dir[14509*3 + 0] = 0.280105f;	val_dir[14509*3 + 1] = 0.948047f;	val_dir[14509*3 + 2] = -0.150826f;
+ 	val_dir[14510*3 + 0] = 0.295409f;	val_dir[14510*3 + 1] = 0.949528f;	val_dir[14510*3 + 2] = -0.105503f;
+ 	val_dir[14511*3 + 0] = 0.309426f;	val_dir[14511*3 + 1] = 0.948908f;	val_dir[14511*3 + 2] = -0.061885f;
+ 	val_dir[14512*3 + 0] = 0.322198f;	val_dir[14512*3 + 1] = 0.946458f;	val_dir[14512*3 + 2] = -0.020137f;
+ 	val_dir[14513*3 + 0] = -0.948683f;	val_dir[14513*3 + 1] = -0.316228f;	val_dir[14513*3 + 2] = 0.0f;
+ 	val_dir[14514*3 + 0] = -0.951877f;	val_dir[14514*3 + 1] = -0.303791f;	val_dir[14514*3 + 2] = -0.040505f;
+ 	val_dir[14515*3 + 0] = -0.953381f;	val_dir[14515*3 + 1] = -0.290159f;	val_dir[14515*3 + 2] = -0.082903f;
+ 	val_dir[14516*3 + 0] = -0.952928f;	val_dir[14516*3 + 1] = -0.275290f;	val_dir[14516*3 + 2] = -0.127057f;
+ 	val_dir[14517*3 + 0] = -0.950255f;	val_dir[14517*3 + 1] = -0.259161f;	val_dir[14517*3 + 2] = -0.172774f;
+ 	val_dir[14518*3 + 0] = -0.945112f;	val_dir[14518*3 + 1] = -0.241773f;	val_dir[14518*3 + 2] = -0.219793f;
+ 	val_dir[14519*3 + 0] = -0.937276f;	val_dir[14519*3 + 1] = -0.223161f;	val_dir[14519*3 + 2] = -0.267793f;
+ 	val_dir[14520*3 + 0] = -0.926568f;	val_dir[14520*3 + 1] = -0.203393f;	val_dir[14520*3 + 2] = -0.316389f;
+ 	val_dir[14521*3 + 0] = -0.912871f;	val_dir[14521*3 + 1] = -0.182574f;	val_dir[14521*3 + 2] = -0.365148f;
+ 	val_dir[14522*3 + 0] = -0.896137f;	val_dir[14522*3 + 1] = -0.160845f;	val_dir[14522*3 + 2] = -0.413602f;
+ 	val_dir[14523*3 + 0] = -0.876405f;	val_dir[14523*3 + 1] = -0.138380f;	val_dir[14523*3 + 2] = -0.461266f;
+ 	val_dir[14524*3 + 0] = -0.853796f;	val_dir[14524*3 + 1] = -0.115378f;	val_dir[14524*3 + 2] = -0.507662f;
+ 	val_dir[14525*3 + 0] = -0.828517f;	val_dir[14525*3 + 1] = -0.092057f;	val_dir[14525*3 + 2] = -0.552345f;
+ 	val_dir[14526*3 + 0] = -0.800850f;	val_dir[14526*3 + 1] = -0.068644f;	val_dir[14526*3 + 2] = -0.594917f;
+ 	val_dir[14527*3 + 0] = -0.771136f;	val_dir[14527*3 + 1] = -0.045361f;	val_dir[14527*3 + 2] = -0.635053f;
+ 	val_dir[14528*3 + 0] = -0.739754f;	val_dir[14528*3 + 1] = -0.022417f;	val_dir[14528*3 + 2] = -0.672504f;
+ 	val_dir[14529*3 + 0] = -0.707107f;	val_dir[14529*3 + 1] = 0.0f;	val_dir[14529*3 + 2] = -0.707107f;
+ 	val_dir[14530*3 + 0] = -0.695620f;	val_dir[14530*3 + 1] = 0.022439f;	val_dir[14530*3 + 2] = -0.718059f;
+ 	val_dir[14531*3 + 0] = -0.683231f;	val_dir[14531*3 + 1] = 0.045549f;	val_dir[14531*3 + 2] = -0.728780f;
+ 	val_dir[14532*3 + 0] = -0.669905f;	val_dir[14532*3 + 1] = 0.069301f;	val_dir[14532*3 + 2] = -0.739205f;
+ 	val_dir[14533*3 + 0] = -0.655610f;	val_dir[14533*3 + 1] = 0.093659f;	val_dir[14533*3 + 2] = -0.749269f;
+ 	val_dir[14534*3 + 0] = -0.640321f;	val_dir[14534*3 + 1] = 0.118578f;	val_dir[14534*3 + 2] = -0.758899f;
+ 	val_dir[14535*3 + 0] = -0.624020f;	val_dir[14535*3 + 1] = 0.144005f;	val_dir[14535*3 + 2] = -0.768025f;
+ 	val_dir[14536*3 + 0] = -0.606696f;	val_dir[14536*3 + 1] = 0.169875f;	val_dir[14536*3 + 2] = -0.776571f;
+ 	val_dir[14537*3 + 0] = -0.588348f;	val_dir[14537*3 + 1] = 0.196116f;	val_dir[14537*3 + 2] = -0.784465f;
+ 	val_dir[14538*3 + 0] = -0.568986f;	val_dir[14538*3 + 1] = 0.222647f;	val_dir[14538*3 + 2] = -0.791633f;
+ 	val_dir[14539*3 + 0] = -0.548630f;	val_dir[14539*3 + 1] = 0.249377f;	val_dir[14539*3 + 2] = -0.798007f;
+ 	val_dir[14540*3 + 0] = -0.527312f;	val_dir[14540*3 + 1] = 0.276211f;	val_dir[14540*3 + 2] = -0.803523f;
+ 	val_dir[14541*3 + 0] = -0.505076f;	val_dir[14541*3 + 1] = 0.303046f;	val_dir[14541*3 + 2] = -0.808122f;
+ 	val_dir[14542*3 + 0] = -0.481979f;	val_dir[14542*3 + 1] = 0.329775f;	val_dir[14542*3 + 2] = -0.811754f;
+ 	val_dir[14543*3 + 0] = -0.458088f;	val_dir[14543*3 + 1] = 0.356291f;	val_dir[14543*3 + 2] = -0.814379f;
+ 	val_dir[14544*3 + 0] = -0.433482f;	val_dir[14544*3 + 1] = 0.382484f;	val_dir[14544*3 + 2] = -0.815966f;
+ 	val_dir[14545*3 + 0] = -0.408248f;	val_dir[14545*3 + 1] = 0.408248f;	val_dir[14545*3 + 2] = -0.816497f;
+ 	val_dir[14546*3 + 0] = -0.382484f;	val_dir[14546*3 + 1] = 0.433482f;	val_dir[14546*3 + 2] = -0.815966f;
+ 	val_dir[14547*3 + 0] = -0.356291f;	val_dir[14547*3 + 1] = 0.458088f;	val_dir[14547*3 + 2] = -0.814379f;
+ 	val_dir[14548*3 + 0] = -0.329775f;	val_dir[14548*3 + 1] = 0.481979f;	val_dir[14548*3 + 2] = -0.811754f;
+ 	val_dir[14549*3 + 0] = -0.303046f;	val_dir[14549*3 + 1] = 0.505076f;	val_dir[14549*3 + 2] = -0.808122f;
+ 	val_dir[14550*3 + 0] = -0.276211f;	val_dir[14550*3 + 1] = 0.527312f;	val_dir[14550*3 + 2] = -0.803523f;
+ 	val_dir[14551*3 + 0] = -0.249377f;	val_dir[14551*3 + 1] = 0.548630f;	val_dir[14551*3 + 2] = -0.798007f;
+ 	val_dir[14552*3 + 0] = -0.222647f;	val_dir[14552*3 + 1] = 0.568986f;	val_dir[14552*3 + 2] = -0.791633f;
+ 	val_dir[14553*3 + 0] = -0.196116f;	val_dir[14553*3 + 1] = 0.588348f;	val_dir[14553*3 + 2] = -0.784465f;
+ 	val_dir[14554*3 + 0] = -0.169875f;	val_dir[14554*3 + 1] = 0.606696f;	val_dir[14554*3 + 2] = -0.776571f;
+ 	val_dir[14555*3 + 0] = -0.144005f;	val_dir[14555*3 + 1] = 0.624020f;	val_dir[14555*3 + 2] = -0.768025f;
+ 	val_dir[14556*3 + 0] = -0.118578f;	val_dir[14556*3 + 1] = 0.640321f;	val_dir[14556*3 + 2] = -0.758899f;
+ 	val_dir[14557*3 + 0] = -0.093659f;	val_dir[14557*3 + 1] = 0.655610f;	val_dir[14557*3 + 2] = -0.749269f;
+ 	val_dir[14558*3 + 0] = -0.069301f;	val_dir[14558*3 + 1] = 0.669905f;	val_dir[14558*3 + 2] = -0.739205f;
+ 	val_dir[14559*3 + 0] = -0.045549f;	val_dir[14559*3 + 1] = 0.683231f;	val_dir[14559*3 + 2] = -0.728780f;
+ 	val_dir[14560*3 + 0] = -0.022439f;	val_dir[14560*3 + 1] = 0.695620f;	val_dir[14560*3 + 2] = -0.718059f;
+ 	val_dir[14561*3 + 0] = 0.0f;	val_dir[14561*3 + 1] = 0.707107f;	val_dir[14561*3 + 2] = -0.707107f;
+ 	val_dir[14562*3 + 0] = 0.022417f;	val_dir[14562*3 + 1] = 0.739754f;	val_dir[14562*3 + 2] = -0.672504f;
+ 	val_dir[14563*3 + 0] = 0.045361f;	val_dir[14563*3 + 1] = 0.771136f;	val_dir[14563*3 + 2] = -0.635053f;
+ 	val_dir[14564*3 + 0] = 0.068644f;	val_dir[14564*3 + 1] = 0.800850f;	val_dir[14564*3 + 2] = -0.594917f;
+ 	val_dir[14565*3 + 0] = 0.092057f;	val_dir[14565*3 + 1] = 0.828517f;	val_dir[14565*3 + 2] = -0.552345f;
+ 	val_dir[14566*3 + 0] = 0.115378f;	val_dir[14566*3 + 1] = 0.853796f;	val_dir[14566*3 + 2] = -0.507662f;
+ 	val_dir[14567*3 + 0] = 0.138380f;	val_dir[14567*3 + 1] = 0.876405f;	val_dir[14567*3 + 2] = -0.461266f;
+ 	val_dir[14568*3 + 0] = 0.160845f;	val_dir[14568*3 + 1] = 0.896137f;	val_dir[14568*3 + 2] = -0.413602f;
+ 	val_dir[14569*3 + 0] = 0.182574f;	val_dir[14569*3 + 1] = 0.912871f;	val_dir[14569*3 + 2] = -0.365148f;
+ 	val_dir[14570*3 + 0] = 0.203393f;	val_dir[14570*3 + 1] = 0.926568f;	val_dir[14570*3 + 2] = -0.316389f;
+ 	val_dir[14571*3 + 0] = 0.223161f;	val_dir[14571*3 + 1] = 0.937276f;	val_dir[14571*3 + 2] = -0.267793f;
+ 	val_dir[14572*3 + 0] = 0.241773f;	val_dir[14572*3 + 1] = 0.945112f;	val_dir[14572*3 + 2] = -0.219793f;
+ 	val_dir[14573*3 + 0] = 0.259161f;	val_dir[14573*3 + 1] = 0.950255f;	val_dir[14573*3 + 2] = -0.172774f;
+ 	val_dir[14574*3 + 0] = 0.275290f;	val_dir[14574*3 + 1] = 0.952928f;	val_dir[14574*3 + 2] = -0.127057f;
+ 	val_dir[14575*3 + 0] = 0.290159f;	val_dir[14575*3 + 1] = 0.953381f;	val_dir[14575*3 + 2] = -0.082903f;
+ 	val_dir[14576*3 + 0] = 0.303791f;	val_dir[14576*3 + 1] = 0.951877f;	val_dir[14576*3 + 2] = -0.040505f;
+ 	val_dir[14577*3 + 0] = 0.316228f;	val_dir[14577*3 + 1] = 0.948683f;	val_dir[14577*3 + 2] = 0.0f;
+ 	val_dir[14578*3 + 0] = -0.954291f;	val_dir[14578*3 + 1] = -0.298216f;	val_dir[14578*3 + 2] = -0.019881f;
+ 	val_dir[14579*3 + 0] = -0.956597f;	val_dir[14579*3 + 1] = -0.284944f;	val_dir[14579*3 + 2] = -0.061059f;
+ 	val_dir[14580*3 + 0] = -0.957088f;	val_dir[14580*3 + 1] = -0.270481f;	val_dir[14580*3 + 2] = -0.104031f;
+ 	val_dir[14581*3 + 0] = -0.955502f;	val_dir[14581*3 + 1] = -0.254801f;	val_dir[14581*3 + 2] = -0.148634f;
+ 	val_dir[14582*3 + 0] = -0.951588f;	val_dir[14582*3 + 1] = -0.237897f;	val_dir[14582*3 + 2] = -0.194643f;
+ 	val_dir[14583*3 + 0] = -0.945112f;	val_dir[14583*3 + 1] = -0.219793f;	val_dir[14583*3 + 2] = -0.241773f;
+ 	val_dir[14584*3 + 0] = -0.935879f;	val_dir[14584*3 + 1] = -0.200545f;	val_dir[14584*3 + 2] = -0.289677f;
+ 	val_dir[14585*3 + 0] = -0.923742f;	val_dir[14585*3 + 1] = -0.180242f;	val_dir[14585*3 + 2] = -0.337954f;
+ 	val_dir[14586*3 + 0] = -0.908622f;	val_dir[14586*3 + 1] = -0.159009f;	val_dir[14586*3 + 2] = -0.386164f;
+ 	val_dir[14587*3 + 0] = -0.890513f;	val_dir[14587*3 + 1] = -0.137002f;	val_dir[14587*3 + 2] = -0.433840f;
+ 	val_dir[14588*3 + 0] = -0.869495f;	val_dir[14588*3 + 1] = -0.114407f;	val_dir[14588*3 + 2] = -0.480510f;
+ 	val_dir[14589*3 + 0] = -0.845728f;	val_dir[14589*3 + 1] = -0.091430f;	val_dir[14589*3 + 2] = -0.525723f;
+ 	val_dir[14590*3 + 0] = -0.819453f;	val_dir[14590*3 + 1] = -0.068288f;	val_dir[14590*3 + 2] = -0.569064f;
+ 	val_dir[14591*3 + 0] = -0.790973f;	val_dir[14591*3 + 1] = -0.045198f;	val_dir[14591*3 + 2] = -0.610179f;
+ 	val_dir[14592*3 + 0] = -0.760644f;	val_dir[14592*3 + 1] = -0.022372f;	val_dir[14592*3 + 2] = -0.648784f;
+ 	val_dir[14593*3 + 0] = -0.728848f;	val_dir[14593*3 + 1] = 0.0f;	val_dir[14593*3 + 2] = -0.684675f;
+ 	val_dir[14594*3 + 0] = -0.718059f;	val_dir[14594*3 + 1] = 0.022439f;	val_dir[14594*3 + 2] = -0.695620f;
+ 	val_dir[14595*3 + 0] = -0.706372f;	val_dir[14595*3 + 1] = 0.045572f;	val_dir[14595*3 + 2] = -0.706372f;
+ 	val_dir[14596*3 + 0] = -0.693746f;	val_dir[14596*3 + 1] = 0.069375f;	val_dir[14596*3 + 2] = -0.716871f;
+ 	val_dir[14597*3 + 0] = -0.680144f;	val_dir[14597*3 + 1] = 0.093813f;	val_dir[14597*3 + 2] = -0.727051f;
+ 	val_dir[14598*3 + 0] = -0.665536f;	val_dir[14598*3 + 1] = 0.118846f;	val_dir[14598*3 + 2] = -0.736843f;
+ 	val_dir[14599*3 + 0] = -0.649895f;	val_dir[14599*3 + 1] = 0.144421f;	val_dir[14599*3 + 2] = -0.746176f;
+ 	val_dir[14600*3 + 0] = -0.633205f;	val_dir[14600*3 + 1] = 0.170478f;	val_dir[14600*3 + 2] = -0.754976f;
+ 	val_dir[14601*3 + 0] = -0.615457f;	val_dir[14601*3 + 1] = 0.196946f;	val_dir[14601*3 + 2] = -0.763167f;
+ 	val_dir[14602*3 + 0] = -0.596653f;	val_dir[14602*3 + 1] = 0.223745f;	val_dir[14602*3 + 2] = -0.770677f;
+ 	val_dir[14603*3 + 0] = -0.576805f;	val_dir[14603*3 + 1] = 0.250785f;	val_dir[14603*3 + 2] = -0.777433f;
+ 	val_dir[14604*3 + 0] = -0.555939f;	val_dir[14604*3 + 1] = 0.277969f;	val_dir[14604*3 + 2] = -0.783368f;
+ 	val_dir[14605*3 + 0] = -0.534090f;	val_dir[14605*3 + 1] = 0.305194f;	val_dir[14605*3 + 2] = -0.788419f;
+ 	val_dir[14606*3 + 0] = -0.511310f;	val_dir[14606*3 + 1] = 0.332352f;	val_dir[14606*3 + 2] = -0.792530f;
+ 	val_dir[14607*3 + 0] = -0.487661f;	val_dir[14607*3 + 1] = 0.359329f;	val_dir[14607*3 + 2] = -0.795657f;
+ 	val_dir[14608*3 + 0] = -0.463217f;	val_dir[14608*3 + 1] = 0.386014f;	val_dir[14608*3 + 2] = -0.797762f;
+ 	val_dir[14609*3 + 0] = -0.438063f;	val_dir[14609*3 + 1] = 0.412294f;	val_dir[14609*3 + 2] = -0.798820f;
+ 	val_dir[14610*3 + 0] = -0.412294f;	val_dir[14610*3 + 1] = 0.438063f;	val_dir[14610*3 + 2] = -0.798820f;
+ 	val_dir[14611*3 + 0] = -0.386014f;	val_dir[14611*3 + 1] = 0.463217f;	val_dir[14611*3 + 2] = -0.797762f;
+ 	val_dir[14612*3 + 0] = -0.359329f;	val_dir[14612*3 + 1] = 0.487661f;	val_dir[14612*3 + 2] = -0.795657f;
+ 	val_dir[14613*3 + 0] = -0.332352f;	val_dir[14613*3 + 1] = 0.511310f;	val_dir[14613*3 + 2] = -0.792530f;
+ 	val_dir[14614*3 + 0] = -0.305194f;	val_dir[14614*3 + 1] = 0.534090f;	val_dir[14614*3 + 2] = -0.788419f;
+ 	val_dir[14615*3 + 0] = -0.277969f;	val_dir[14615*3 + 1] = 0.555939f;	val_dir[14615*3 + 2] = -0.783368f;
+ 	val_dir[14616*3 + 0] = -0.250785f;	val_dir[14616*3 + 1] = 0.576805f;	val_dir[14616*3 + 2] = -0.777433f;
+ 	val_dir[14617*3 + 0] = -0.223745f;	val_dir[14617*3 + 1] = 0.596653f;	val_dir[14617*3 + 2] = -0.770677f;
+ 	val_dir[14618*3 + 0] = -0.196946f;	val_dir[14618*3 + 1] = 0.615457f;	val_dir[14618*3 + 2] = -0.763167f;
+ 	val_dir[14619*3 + 0] = -0.170478f;	val_dir[14619*3 + 1] = 0.633205f;	val_dir[14619*3 + 2] = -0.754976f;
+ 	val_dir[14620*3 + 0] = -0.144421f;	val_dir[14620*3 + 1] = 0.649895f;	val_dir[14620*3 + 2] = -0.746176f;
+ 	val_dir[14621*3 + 0] = -0.118846f;	val_dir[14621*3 + 1] = 0.665536f;	val_dir[14621*3 + 2] = -0.736843f;
+ 	val_dir[14622*3 + 0] = -0.093813f;	val_dir[14622*3 + 1] = 0.680144f;	val_dir[14622*3 + 2] = -0.727051f;
+ 	val_dir[14623*3 + 0] = -0.069375f;	val_dir[14623*3 + 1] = 0.693746f;	val_dir[14623*3 + 2] = -0.716871f;
+ 	val_dir[14624*3 + 0] = -0.045572f;	val_dir[14624*3 + 1] = 0.706372f;	val_dir[14624*3 + 2] = -0.706372f;
+ 	val_dir[14625*3 + 0] = -0.022439f;	val_dir[14625*3 + 1] = 0.718059f;	val_dir[14625*3 + 2] = -0.695620f;
+ 	val_dir[14626*3 + 0] = 0.0f;	val_dir[14626*3 + 1] = 0.728848f;	val_dir[14626*3 + 2] = -0.684675f;
+ 	val_dir[14627*3 + 0] = 0.022372f;	val_dir[14627*3 + 1] = 0.760644f;	val_dir[14627*3 + 2] = -0.648784f;
+ 	val_dir[14628*3 + 0] = 0.045198f;	val_dir[14628*3 + 1] = 0.790973f;	val_dir[14628*3 + 2] = -0.610179f;
+ 	val_dir[14629*3 + 0] = 0.068288f;	val_dir[14629*3 + 1] = 0.819453f;	val_dir[14629*3 + 2] = -0.569064f;
+ 	val_dir[14630*3 + 0] = 0.091430f;	val_dir[14630*3 + 1] = 0.845728f;	val_dir[14630*3 + 2] = -0.525723f;
+ 	val_dir[14631*3 + 0] = 0.114407f;	val_dir[14631*3 + 1] = 0.869495f;	val_dir[14631*3 + 2] = -0.480510f;
+ 	val_dir[14632*3 + 0] = 0.137002f;	val_dir[14632*3 + 1] = 0.890513f;	val_dir[14632*3 + 2] = -0.433840f;
+ 	val_dir[14633*3 + 0] = 0.159009f;	val_dir[14633*3 + 1] = 0.908622f;	val_dir[14633*3 + 2] = -0.386164f;
+ 	val_dir[14634*3 + 0] = 0.180242f;	val_dir[14634*3 + 1] = 0.923742f;	val_dir[14634*3 + 2] = -0.337954f;
+ 	val_dir[14635*3 + 0] = 0.200545f;	val_dir[14635*3 + 1] = 0.935879f;	val_dir[14635*3 + 2] = -0.289677f;
+ 	val_dir[14636*3 + 0] = 0.219793f;	val_dir[14636*3 + 1] = 0.945112f;	val_dir[14636*3 + 2] = -0.241773f;
+ 	val_dir[14637*3 + 0] = 0.237897f;	val_dir[14637*3 + 1] = 0.951588f;	val_dir[14637*3 + 2] = -0.194643f;
+ 	val_dir[14638*3 + 0] = 0.254801f;	val_dir[14638*3 + 1] = 0.955502f;	val_dir[14638*3 + 2] = -0.148634f;
+ 	val_dir[14639*3 + 0] = 0.270481f;	val_dir[14639*3 + 1] = 0.957088f;	val_dir[14639*3 + 2] = -0.104031f;
+ 	val_dir[14640*3 + 0] = 0.284944f;	val_dir[14640*3 + 1] = 0.956597f;	val_dir[14640*3 + 2] = -0.061059f;
+ 	val_dir[14641*3 + 0] = 0.298216f;	val_dir[14641*3 + 1] = 0.954291f;	val_dir[14641*3 + 2] = -0.019881f;
+ 	val_dir[14642*3 + 0] = -0.95620f;	val_dir[14642*3 + 1] = -0.292714f;	val_dir[14642*3 + 2] = 0.0f;
+ 	val_dir[14643*3 + 0] = -0.959233f;	val_dir[14643*3 + 1] = -0.279776f;	val_dir[14643*3 + 2] = -0.039968f;
+ 	val_dir[14644*3 + 0] = -0.960585f;	val_dir[14644*3 + 1] = -0.265694f;	val_dir[14644*3 + 2] = -0.081752f;
+ 	val_dir[14645*3 + 0] = -0.960001f;	val_dir[14645*3 + 1] = -0.250435f;	val_dir[14645*3 + 2] = -0.125218f;
+ 	val_dir[14646*3 + 0] = -0.957230f;	val_dir[14646*3 + 1] = -0.233990f;	val_dir[14646*3 + 2] = -0.170174f;
+ 	val_dir[14647*3 + 0] = -0.952033f;	val_dir[14647*3 + 1] = -0.216371f;	val_dir[14647*3 + 2] = -0.216371f;
+ 	val_dir[14648*3 + 0] = -0.94420f;	val_dir[14648*3 + 1] = -0.197623f;	val_dir[14648*3 + 2] = -0.263498f;
+ 	val_dir[14649*3 + 0] = -0.933564f;	val_dir[14649*3 + 1] = -0.177822f;	val_dir[14649*3 + 2] = -0.311188f;
+ 	val_dir[14650*3 + 0] = -0.920014f;	val_dir[14650*3 + 1] = -0.157075f;	val_dir[14650*3 + 2] = -0.359030f;
+ 	val_dir[14651*3 + 0] = -0.903508f;	val_dir[14651*3 + 1] = -0.135526f;	val_dir[14651*3 + 2] = -0.406579f;
+ 	val_dir[14652*3 + 0] = -0.884083f;	val_dir[14652*3 + 1] = -0.113344f;	val_dir[14652*3 + 2] = -0.453376f;
+ 	val_dir[14653*3 + 0] = -0.861857f;	val_dir[14653*3 + 1] = -0.090722f;	val_dir[14653*3 + 2] = -0.498970f;
+ 	val_dir[14654*3 + 0] = -0.837027f;	val_dir[14654*3 + 1] = -0.067867f;	val_dir[14654*3 + 2] = -0.542936f;
+ 	val_dir[14655*3 + 0] = -0.809858f;	val_dir[14655*3 + 1] = -0.044992f;	val_dir[14655*3 + 2] = -0.584898f;
+ 	val_dir[14656*3 + 0] = -0.780675f;	val_dir[14656*3 + 1] = -0.022305f;	val_dir[14656*3 + 2] = -0.624540f;
+ 	val_dir[14657*3 + 0] = -0.749838f;	val_dir[14657*3 + 1] = 0.0f;	val_dir[14657*3 + 2] = -0.661622f;
+ 	val_dir[14658*3 + 0] = -0.739754f;	val_dir[14658*3 + 1] = 0.022417f;	val_dir[14658*3 + 2] = -0.672504f;
+ 	val_dir[14659*3 + 0] = -0.728780f;	val_dir[14659*3 + 1] = 0.045549f;	val_dir[14659*3 + 2] = -0.683231f;
+ 	val_dir[14660*3 + 0] = -0.716871f;	val_dir[14660*3 + 1] = 0.069375f;	val_dir[14660*3 + 2] = -0.693746f;
+ 	val_dir[14661*3 + 0] = -0.703985f;	val_dir[14661*3 + 1] = 0.093865f;	val_dir[14661*3 + 2] = -0.703985f;
+ 	val_dir[14662*3 + 0] = -0.690085f;	val_dir[14662*3 + 1] = 0.118980f;	val_dir[14662*3 + 2] = -0.713881f;
+ 	val_dir[14663*3 + 0] = -0.675140f;	val_dir[14663*3 + 1] = 0.144673f;	val_dir[14663*3 + 2] = -0.723364f;
+ 	val_dir[14664*3 + 0] = -0.659125f;	val_dir[14664*3 + 1] = 0.170884f;	val_dir[14664*3 + 2] = -0.732361f;
+ 	val_dir[14665*3 + 0] = -0.642024f;	val_dir[14665*3 + 1] = 0.197546f;	val_dir[14665*3 + 2] = -0.740797f;
+ 	val_dir[14666*3 + 0] = -0.623831f;	val_dir[14666*3 + 1] = 0.224579f;	val_dir[14666*3 + 2] = -0.748598f;
+ 	val_dir[14667*3 + 0] = -0.604551f;	val_dir[14667*3 + 1] = 0.251896f;	val_dir[14667*3 + 2] = -0.755689f;
+ 	val_dir[14668*3 + 0] = -0.584201f;	val_dir[14668*3 + 1] = 0.27940f;	val_dir[14668*3 + 2] = -0.762001f;
+ 	val_dir[14669*3 + 0] = -0.562809f;	val_dir[14669*3 + 1] = 0.306987f;	val_dir[14669*3 + 2] = -0.767467f;
+ 	val_dir[14670*3 + 0] = -0.540419f;	val_dir[14670*3 + 1] = 0.334545f;	val_dir[14670*3 + 2] = -0.772027f;
+ 	val_dir[14671*3 + 0] = -0.517088f;	val_dir[14671*3 + 1] = 0.361961f;	val_dir[14671*3 + 2] = -0.775632f;
+ 	val_dir[14672*3 + 0] = -0.492883f;	val_dir[14672*3 + 1] = 0.389118f;	val_dir[14672*3 + 2] = -0.778237f;
+ 	val_dir[14673*3 + 0] = -0.467888f;	val_dir[14673*3 + 1] = 0.41590f;	val_dir[14673*3 + 2] = -0.779813f;
+ 	val_dir[14674*3 + 0] = -0.442193f;	val_dir[14674*3 + 1] = 0.442193f;	val_dir[14674*3 + 2] = -0.780340f;
+ 	val_dir[14675*3 + 0] = -0.41590f;	val_dir[14675*3 + 1] = 0.467888f;	val_dir[14675*3 + 2] = -0.779813f;
+ 	val_dir[14676*3 + 0] = -0.389118f;	val_dir[14676*3 + 1] = 0.492883f;	val_dir[14676*3 + 2] = -0.778237f;
+ 	val_dir[14677*3 + 0] = -0.361961f;	val_dir[14677*3 + 1] = 0.517088f;	val_dir[14677*3 + 2] = -0.775632f;
+ 	val_dir[14678*3 + 0] = -0.334545f;	val_dir[14678*3 + 1] = 0.540419f;	val_dir[14678*3 + 2] = -0.772027f;
+ 	val_dir[14679*3 + 0] = -0.306987f;	val_dir[14679*3 + 1] = 0.562809f;	val_dir[14679*3 + 2] = -0.767467f;
+ 	val_dir[14680*3 + 0] = -0.27940f;	val_dir[14680*3 + 1] = 0.584201f;	val_dir[14680*3 + 2] = -0.762001f;
+ 	val_dir[14681*3 + 0] = -0.251896f;	val_dir[14681*3 + 1] = 0.604551f;	val_dir[14681*3 + 2] = -0.755689f;
+ 	val_dir[14682*3 + 0] = -0.224579f;	val_dir[14682*3 + 1] = 0.623831f;	val_dir[14682*3 + 2] = -0.748598f;
+ 	val_dir[14683*3 + 0] = -0.197546f;	val_dir[14683*3 + 1] = 0.642024f;	val_dir[14683*3 + 2] = -0.740797f;
+ 	val_dir[14684*3 + 0] = -0.170884f;	val_dir[14684*3 + 1] = 0.659125f;	val_dir[14684*3 + 2] = -0.732361f;
+ 	val_dir[14685*3 + 0] = -0.144673f;	val_dir[14685*3 + 1] = 0.675140f;	val_dir[14685*3 + 2] = -0.723364f;
+ 	val_dir[14686*3 + 0] = -0.118980f;	val_dir[14686*3 + 1] = 0.690085f;	val_dir[14686*3 + 2] = -0.713881f;
+ 	val_dir[14687*3 + 0] = -0.093865f;	val_dir[14687*3 + 1] = 0.703985f;	val_dir[14687*3 + 2] = -0.703985f;
+ 	val_dir[14688*3 + 0] = -0.069375f;	val_dir[14688*3 + 1] = 0.716871f;	val_dir[14688*3 + 2] = -0.693746f;
+ 	val_dir[14689*3 + 0] = -0.045549f;	val_dir[14689*3 + 1] = 0.728780f;	val_dir[14689*3 + 2] = -0.683231f;
+ 	val_dir[14690*3 + 0] = -0.022417f;	val_dir[14690*3 + 1] = 0.739754f;	val_dir[14690*3 + 2] = -0.672504f;
+ 	val_dir[14691*3 + 0] = 0.0f;	val_dir[14691*3 + 1] = 0.749838f;	val_dir[14691*3 + 2] = -0.661622f;
+ 	val_dir[14692*3 + 0] = 0.022305f;	val_dir[14692*3 + 1] = 0.780675f;	val_dir[14692*3 + 2] = -0.624540f;
+ 	val_dir[14693*3 + 0] = 0.044992f;	val_dir[14693*3 + 1] = 0.809858f;	val_dir[14693*3 + 2] = -0.584898f;
+ 	val_dir[14694*3 + 0] = 0.067867f;	val_dir[14694*3 + 1] = 0.837027f;	val_dir[14694*3 + 2] = -0.542936f;
+ 	val_dir[14695*3 + 0] = 0.090722f;	val_dir[14695*3 + 1] = 0.861857f;	val_dir[14695*3 + 2] = -0.498970f;
+ 	val_dir[14696*3 + 0] = 0.113344f;	val_dir[14696*3 + 1] = 0.884083f;	val_dir[14696*3 + 2] = -0.453376f;
+ 	val_dir[14697*3 + 0] = 0.135526f;	val_dir[14697*3 + 1] = 0.903508f;	val_dir[14697*3 + 2] = -0.406579f;
+ 	val_dir[14698*3 + 0] = 0.157075f;	val_dir[14698*3 + 1] = 0.920014f;	val_dir[14698*3 + 2] = -0.359030f;
+ 	val_dir[14699*3 + 0] = 0.177822f;	val_dir[14699*3 + 1] = 0.933564f;	val_dir[14699*3 + 2] = -0.311188f;
+ 	val_dir[14700*3 + 0] = 0.197623f;	val_dir[14700*3 + 1] = 0.94420f;	val_dir[14700*3 + 2] = -0.263498f;
+ 	val_dir[14701*3 + 0] = 0.216371f;	val_dir[14701*3 + 1] = 0.952033f;	val_dir[14701*3 + 2] = -0.216371f;
+ 	val_dir[14702*3 + 0] = 0.233990f;	val_dir[14702*3 + 1] = 0.957230f;	val_dir[14702*3 + 2] = -0.170174f;
+ 	val_dir[14703*3 + 0] = 0.250435f;	val_dir[14703*3 + 1] = 0.960001f;	val_dir[14703*3 + 2] = -0.125218f;
+ 	val_dir[14704*3 + 0] = 0.265694f;	val_dir[14704*3 + 1] = 0.960585f;	val_dir[14704*3 + 2] = -0.081752f;
+ 	val_dir[14705*3 + 0] = 0.279776f;	val_dir[14705*3 + 1] = 0.959233f;	val_dir[14705*3 + 2] = -0.039968f;
+ 	val_dir[14706*3 + 0] = 0.292714f;	val_dir[14706*3 + 1] = 0.95620f;	val_dir[14706*3 + 2] = 0.0f;
+ 	val_dir[14707*3 + 0] = -0.961339f;	val_dir[14707*3 + 1] = -0.274668f;	val_dir[14707*3 + 2] = -0.019619f;
+ 	val_dir[14708*3 + 0] = -0.963475f;	val_dir[14708*3 + 1] = -0.260941f;	val_dir[14708*3 + 2] = -0.060217f;
+ 	val_dir[14709*3 + 0] = -0.963811f;	val_dir[14709*3 + 1] = -0.246079f;	val_dir[14709*3 + 2] = -0.102533f;
+ 	val_dir[14710*3 + 0] = -0.962099f;	val_dir[14710*3 + 1] = -0.230067f;	val_dir[14710*3 + 2] = -0.146406f;
+ 	val_dir[14711*3 + 0] = -0.958098f;	val_dir[14711*3 + 1] = -0.212911f;	val_dir[14711*3 + 2] = -0.191620f;
+ 	val_dir[14712*3 + 0] = -0.951588f;	val_dir[14712*3 + 1] = -0.194643f;	val_dir[14712*3 + 2] = -0.237897f;
+ 	val_dir[14713*3 + 0] = -0.942384f;	val_dir[14713*3 + 1] = -0.175327f;	val_dir[14713*3 + 2] = -0.284907f;
+ 	val_dir[14714*3 + 0] = -0.930352f;	val_dir[14714*3 + 1] = -0.155059f;	val_dir[14714*3 + 2] = -0.332269f;
+ 	val_dir[14715*3 + 0] = -0.915416f;	val_dir[14715*3 + 1] = -0.133963f;	val_dir[14715*3 + 2] = -0.379563f;
+ 	val_dir[14716*3 + 0] = -0.897574f;	val_dir[14716*3 + 1] = -0.112197f;	val_dir[14716*3 + 2] = -0.426348f;
+ 	val_dir[14717*3 + 0] = -0.876903f;	val_dir[14717*3 + 1] = -0.089939f;	val_dir[14717*3 + 2] = -0.472178f;
+ 	val_dir[14718*3 + 0] = -0.853556f;	val_dir[14718*3 + 1] = -0.067386f;	val_dir[14718*3 + 2] = -0.516626f;
+ 	val_dir[14719*3 + 0] = -0.827759f;	val_dir[14719*3 + 1] = -0.044744f;	val_dir[14719*3 + 2] = -0.559297f;
+ 	val_dir[14720*3 + 0] = -0.799803f;	val_dir[14720*3 + 1] = -0.022217f;	val_dir[14720*3 + 2] = -0.599852f;
+ 	val_dir[14721*3 + 0] = -0.770022f;	val_dir[14721*3 + 1] = 0.0f;	val_dir[14721*3 + 2] = -0.638018f;
+ 	val_dir[14722*3 + 0] = -0.760644f;	val_dir[14722*3 + 1] = 0.022372f;	val_dir[14722*3 + 2] = -0.648784f;
+ 	val_dir[14723*3 + 0] = -0.750388f;	val_dir[14723*3 + 1] = 0.045478f;	val_dir[14723*3 + 2] = -0.659432f;
+ 	val_dir[14724*3 + 0] = -0.739205f;	val_dir[14724*3 + 1] = 0.069301f;	val_dir[14724*3 + 2] = -0.669905f;
+ 	val_dir[14725*3 + 0] = -0.727051f;	val_dir[14725*3 + 1] = 0.093813f;	val_dir[14725*3 + 2] = -0.680144f;
+ 	val_dir[14726*3 + 0] = -0.713881f;	val_dir[14726*3 + 1] = 0.118980f;	val_dir[14726*3 + 2] = -0.690085f;
+ 	val_dir[14727*3 + 0] = -0.699659f;	val_dir[14727*3 + 1] = 0.144757f;	val_dir[14727*3 + 2] = -0.699659f;
+ 	val_dir[14728*3 + 0] = -0.684353f;	val_dir[14728*3 + 1] = 0.171088f;	val_dir[14728*3 + 2] = -0.708794f;
+ 	val_dir[14729*3 + 0] = -0.667940f;	val_dir[14729*3 + 1] = 0.197908f;	val_dir[14729*3 + 2] = -0.717418f;
+ 	val_dir[14730*3 + 0] = -0.650407f;	val_dir[14730*3 + 1] = 0.225141f;	val_dir[14730*3 + 2] = -0.725454f;
+ 	val_dir[14731*3 + 0] = -0.631748f;	val_dir[14731*3 + 1] = 0.252699f;	val_dir[14731*3 + 2] = -0.732828f;
+ 	val_dir[14732*3 + 0] = -0.611974f;	val_dir[14732*3 + 1] = 0.280488f;	val_dir[14732*3 + 2] = -0.739469f;
+ 	val_dir[14733*3 + 0] = -0.591105f;	val_dir[14733*3 + 1] = 0.308403f;	val_dir[14733*3 + 2] = -0.745307f;
+ 	val_dir[14734*3 + 0] = -0.569177f;	val_dir[14734*3 + 1] = 0.336332f;	val_dir[14734*3 + 2] = -0.750279f;
+ 	val_dir[14735*3 + 0] = -0.546238f;	val_dir[14735*3 + 1] = 0.364159f;	val_dir[14735*3 + 2] = -0.754329f;
+ 	val_dir[14736*3 + 0] = -0.522352f;	val_dir[14736*3 + 1] = 0.391764f;	val_dir[14736*3 + 2] = -0.757410f;
+ 	val_dir[14737*3 + 0] = -0.497594f;	val_dir[14737*3 + 1] = 0.419026f;	val_dir[14737*3 + 2] = -0.759485f;
+ 	val_dir[14738*3 + 0] = -0.472053f;	val_dir[14738*3 + 1] = 0.445827f;	val_dir[14738*3 + 2] = -0.760529f;
+ 	val_dir[14739*3 + 0] = -0.445827f;	val_dir[14739*3 + 1] = 0.472053f;	val_dir[14739*3 + 2] = -0.760529f;
+ 	val_dir[14740*3 + 0] = -0.419026f;	val_dir[14740*3 + 1] = 0.497594f;	val_dir[14740*3 + 2] = -0.759485f;
+ 	val_dir[14741*3 + 0] = -0.391764f;	val_dir[14741*3 + 1] = 0.522352f;	val_dir[14741*3 + 2] = -0.757410f;
+ 	val_dir[14742*3 + 0] = -0.364159f;	val_dir[14742*3 + 1] = 0.546238f;	val_dir[14742*3 + 2] = -0.754329f;
+ 	val_dir[14743*3 + 0] = -0.336332f;	val_dir[14743*3 + 1] = 0.569177f;	val_dir[14743*3 + 2] = -0.750279f;
+ 	val_dir[14744*3 + 0] = -0.308403f;	val_dir[14744*3 + 1] = 0.591105f;	val_dir[14744*3 + 2] = -0.745307f;
+ 	val_dir[14745*3 + 0] = -0.280488f;	val_dir[14745*3 + 1] = 0.611974f;	val_dir[14745*3 + 2] = -0.739469f;
+ 	val_dir[14746*3 + 0] = -0.252699f;	val_dir[14746*3 + 1] = 0.631748f;	val_dir[14746*3 + 2] = -0.732828f;
+ 	val_dir[14747*3 + 0] = -0.225141f;	val_dir[14747*3 + 1] = 0.650407f;	val_dir[14747*3 + 2] = -0.725454f;
+ 	val_dir[14748*3 + 0] = -0.197908f;	val_dir[14748*3 + 1] = 0.667940f;	val_dir[14748*3 + 2] = -0.717418f;
+ 	val_dir[14749*3 + 0] = -0.171088f;	val_dir[14749*3 + 1] = 0.684353f;	val_dir[14749*3 + 2] = -0.708794f;
+ 	val_dir[14750*3 + 0] = -0.144757f;	val_dir[14750*3 + 1] = 0.699659f;	val_dir[14750*3 + 2] = -0.699659f;
+ 	val_dir[14751*3 + 0] = -0.118980f;	val_dir[14751*3 + 1] = 0.713881f;	val_dir[14751*3 + 2] = -0.690085f;
+ 	val_dir[14752*3 + 0] = -0.093813f;	val_dir[14752*3 + 1] = 0.727051f;	val_dir[14752*3 + 2] = -0.680144f;
+ 	val_dir[14753*3 + 0] = -0.069301f;	val_dir[14753*3 + 1] = 0.739205f;	val_dir[14753*3 + 2] = -0.669905f;
+ 	val_dir[14754*3 + 0] = -0.045478f;	val_dir[14754*3 + 1] = 0.750388f;	val_dir[14754*3 + 2] = -0.659432f;
+ 	val_dir[14755*3 + 0] = -0.022372f;	val_dir[14755*3 + 1] = 0.760644f;	val_dir[14755*3 + 2] = -0.648784f;
+ 	val_dir[14756*3 + 0] = 0.0f;	val_dir[14756*3 + 1] = 0.770022f;	val_dir[14756*3 + 2] = -0.638018f;
+ 	val_dir[14757*3 + 0] = 0.022217f;	val_dir[14757*3 + 1] = 0.799803f;	val_dir[14757*3 + 2] = -0.599852f;
+ 	val_dir[14758*3 + 0] = 0.044744f;	val_dir[14758*3 + 1] = 0.827759f;	val_dir[14758*3 + 2] = -0.559297f;
+ 	val_dir[14759*3 + 0] = 0.067386f;	val_dir[14759*3 + 1] = 0.853556f;	val_dir[14759*3 + 2] = -0.516626f;
+ 	val_dir[14760*3 + 0] = 0.089939f;	val_dir[14760*3 + 1] = 0.876903f;	val_dir[14760*3 + 2] = -0.472178f;
+ 	val_dir[14761*3 + 0] = 0.112197f;	val_dir[14761*3 + 1] = 0.897574f;	val_dir[14761*3 + 2] = -0.426348f;
+ 	val_dir[14762*3 + 0] = 0.133963f;	val_dir[14762*3 + 1] = 0.915416f;	val_dir[14762*3 + 2] = -0.379563f;
+ 	val_dir[14763*3 + 0] = 0.155059f;	val_dir[14763*3 + 1] = 0.930352f;	val_dir[14763*3 + 2] = -0.332269f;
+ 	val_dir[14764*3 + 0] = 0.175327f;	val_dir[14764*3 + 1] = 0.942384f;	val_dir[14764*3 + 2] = -0.284907f;
+ 	val_dir[14765*3 + 0] = 0.194643f;	val_dir[14765*3 + 1] = 0.951588f;	val_dir[14765*3 + 2] = -0.237897f;
+ 	val_dir[14766*3 + 0] = 0.212911f;	val_dir[14766*3 + 1] = 0.958098f;	val_dir[14766*3 + 2] = -0.191620f;
+ 	val_dir[14767*3 + 0] = 0.230067f;	val_dir[14767*3 + 1] = 0.962099f;	val_dir[14767*3 + 2] = -0.146406f;
+ 	val_dir[14768*3 + 0] = 0.246079f;	val_dir[14768*3 + 1] = 0.963811f;	val_dir[14768*3 + 2] = -0.102533f;
+ 	val_dir[14769*3 + 0] = 0.260941f;	val_dir[14769*3 + 1] = 0.963475f;	val_dir[14769*3 + 2] = -0.060217f;
+ 	val_dir[14770*3 + 0] = 0.274668f;	val_dir[14770*3 + 1] = 0.961339f;	val_dir[14770*3 + 2] = -0.019619f;
+ 	val_dir[14771*3 + 0] = -0.962964f;	val_dir[14771*3 + 1] = -0.269630f;	val_dir[14771*3 + 2] = 0.0f;
+ 	val_dir[14772*3 + 0] = -0.965810f;	val_dir[14772*3 + 1] = -0.256235f;	val_dir[14772*3 + 2] = -0.039421f;
+ 	val_dir[14773*3 + 0] = -0.966988f;	val_dir[14773*3 + 1] = -0.241747f;	val_dir[14773*3 + 2] = -0.080582f;
+ 	val_dir[14774*3 + 0] = -0.966252f;	val_dir[14774*3 + 1] = -0.226144f;	val_dir[14774*3 + 2] = -0.123351f;
+ 	val_dir[14775*3 + 0] = -0.963364f;	val_dir[14775*3 + 1] = -0.209427f;	val_dir[14775*3 + 2] = -0.167542f;
+ 	val_dir[14776*3 + 0] = -0.958098f;	val_dir[14776*3 + 1] = -0.191620f;	val_dir[14776*3 + 2] = -0.212911f;
+ 	val_dir[14777*3 + 0] = -0.950255f;	val_dir[14777*3 + 1] = -0.172774f;	val_dir[14777*3 + 2] = -0.259161f;
+ 	val_dir[14778*3 + 0] = -0.939680f;	val_dir[14778*3 + 1] = -0.152971f;	val_dir[14778*3 + 2] = -0.305942f;
+ 	val_dir[14779*3 + 0] = -0.926270f;	val_dir[14779*3 + 1] = -0.132324f;	val_dir[14779*3 + 2] = -0.352865f;
+ 	val_dir[14780*3 + 0] = -0.909988f;	val_dir[14780*3 + 1] = -0.110974f;	val_dir[14780*3 + 2] = -0.399507f;
+ 	val_dir[14781*3 + 0] = -0.890871f;	val_dir[14781*3 + 1] = -0.089087f;	val_dir[14781*3 + 2] = -0.445435f;
+ 	val_dir[14782*3 + 0] = -0.869030f;	val_dir[14782*3 + 1] = -0.066848f;	val_dir[14782*3 + 2] = -0.490222f;
+ 	val_dir[14783*3 + 0] = -0.844653f;	val_dir[14783*3 + 1] = -0.044455f;	val_dir[14783*3 + 2] = -0.533465f;
+ 	val_dir[14784*3 + 0] = -0.817992f;	val_dir[14784*3 + 1] = -0.022108f;	val_dir[14784*3 + 2] = -0.574805f;
+ 	val_dir[14785*3 + 0] = -0.789352f;	val_dir[14785*3 + 1] = 0.0f;	val_dir[14785*3 + 2] = -0.613941f;
+ 	val_dir[14786*3 + 0] = -0.780675f;	val_dir[14786*3 + 1] = 0.022305f;	val_dir[14786*3 + 2] = -0.624540f;
+ 	val_dir[14787*3 + 0] = -0.771136f;	val_dir[14787*3 + 1] = 0.045361f;	val_dir[14787*3 + 2] = -0.635053f;
+ 	val_dir[14788*3 + 0] = -0.760684f;	val_dir[14788*3 + 1] = 0.069153f;	val_dir[14788*3 + 2] = -0.645429f;
+ 	val_dir[14789*3 + 0] = -0.749269f;	val_dir[14789*3 + 1] = 0.093659f;	val_dir[14789*3 + 2] = -0.655610f;
+ 	val_dir[14790*3 + 0] = -0.736843f;	val_dir[14790*3 + 1] = 0.118846f;	val_dir[14790*3 + 2] = -0.665536f;
+ 	val_dir[14791*3 + 0] = -0.723364f;	val_dir[14791*3 + 1] = 0.144673f;	val_dir[14791*3 + 2] = -0.675140f;
+ 	val_dir[14792*3 + 0] = -0.708794f;	val_dir[14792*3 + 1] = 0.171088f;	val_dir[14792*3 + 2] = -0.684353f;
+ 	val_dir[14793*3 + 0] = -0.693103f;	val_dir[14793*3 + 1] = 0.198030f;	val_dir[14793*3 + 2] = -0.693103f;
+ 	val_dir[14794*3 + 0] = -0.676269f;	val_dir[14794*3 + 1] = 0.225423f;	val_dir[14794*3 + 2] = -0.701316f;
+ 	val_dir[14795*3 + 0] = -0.658281f;	val_dir[14795*3 + 1] = 0.253185f;	val_dir[14795*3 + 2] = -0.708918f;
+ 	val_dir[14796*3 + 0] = -0.639138f;	val_dir[14796*3 + 1] = 0.281220f;	val_dir[14796*3 + 2] = -0.715834f;
+ 	val_dir[14797*3 + 0] = -0.618853f;	val_dir[14797*3 + 1] = 0.309426f;	val_dir[14797*3 + 2] = -0.721995f;
+ 	val_dir[14798*3 + 0] = -0.597453f;	val_dir[14798*3 + 1] = 0.337691f;	val_dir[14798*3 + 2] = -0.727334f;
+ 	val_dir[14799*3 + 0] = -0.574979f;	val_dir[14799*3 + 1] = 0.365896f;	val_dir[14799*3 + 2] = -0.731792f;
+ 	val_dir[14800*3 + 0] = -0.551487f;	val_dir[14800*3 + 1] = 0.393919f;	val_dir[14800*3 + 2] = -0.735316f;
+ 	val_dir[14801*3 + 0] = -0.527046f;	val_dir[14801*3 + 1] = 0.421637f;	val_dir[14801*3 + 2] = -0.737865f;
+ 	val_dir[14802*3 + 0] = -0.501740f;	val_dir[14802*3 + 1] = 0.448926f;	val_dir[14802*3 + 2] = -0.739407f;
+ 	val_dir[14803*3 + 0] = -0.475665f;	val_dir[14803*3 + 1] = 0.475665f;	val_dir[14803*3 + 2] = -0.739923f;
+ 	val_dir[14804*3 + 0] = -0.448926f;	val_dir[14804*3 + 1] = 0.501740f;	val_dir[14804*3 + 2] = -0.739407f;
+ 	val_dir[14805*3 + 0] = -0.421637f;	val_dir[14805*3 + 1] = 0.527046f;	val_dir[14805*3 + 2] = -0.737865f;
+ 	val_dir[14806*3 + 0] = -0.393919f;	val_dir[14806*3 + 1] = 0.551487f;	val_dir[14806*3 + 2] = -0.735316f;
+ 	val_dir[14807*3 + 0] = -0.365896f;	val_dir[14807*3 + 1] = 0.574979f;	val_dir[14807*3 + 2] = -0.731792f;
+ 	val_dir[14808*3 + 0] = -0.337691f;	val_dir[14808*3 + 1] = 0.597453f;	val_dir[14808*3 + 2] = -0.727334f;
+ 	val_dir[14809*3 + 0] = -0.309426f;	val_dir[14809*3 + 1] = 0.618853f;	val_dir[14809*3 + 2] = -0.721995f;
+ 	val_dir[14810*3 + 0] = -0.281220f;	val_dir[14810*3 + 1] = 0.639138f;	val_dir[14810*3 + 2] = -0.715834f;
+ 	val_dir[14811*3 + 0] = -0.253185f;	val_dir[14811*3 + 1] = 0.658281f;	val_dir[14811*3 + 2] = -0.708918f;
+ 	val_dir[14812*3 + 0] = -0.225423f;	val_dir[14812*3 + 1] = 0.676269f;	val_dir[14812*3 + 2] = -0.701316f;
+ 	val_dir[14813*3 + 0] = -0.198030f;	val_dir[14813*3 + 1] = 0.693103f;	val_dir[14813*3 + 2] = -0.693103f;
+ 	val_dir[14814*3 + 0] = -0.171088f;	val_dir[14814*3 + 1] = 0.708794f;	val_dir[14814*3 + 2] = -0.684353f;
+ 	val_dir[14815*3 + 0] = -0.144673f;	val_dir[14815*3 + 1] = 0.723364f;	val_dir[14815*3 + 2] = -0.675140f;
+ 	val_dir[14816*3 + 0] = -0.118846f;	val_dir[14816*3 + 1] = 0.736843f;	val_dir[14816*3 + 2] = -0.665536f;
+ 	val_dir[14817*3 + 0] = -0.093659f;	val_dir[14817*3 + 1] = 0.749269f;	val_dir[14817*3 + 2] = -0.655610f;
+ 	val_dir[14818*3 + 0] = -0.069153f;	val_dir[14818*3 + 1] = 0.760684f;	val_dir[14818*3 + 2] = -0.645429f;
+ 	val_dir[14819*3 + 0] = -0.045361f;	val_dir[14819*3 + 1] = 0.771136f;	val_dir[14819*3 + 2] = -0.635053f;
+ 	val_dir[14820*3 + 0] = -0.022305f;	val_dir[14820*3 + 1] = 0.780675f;	val_dir[14820*3 + 2] = -0.624540f;
+ 	val_dir[14821*3 + 0] = 0.0f;	val_dir[14821*3 + 1] = 0.789352f;	val_dir[14821*3 + 2] = -0.613941f;
+ 	val_dir[14822*3 + 0] = 0.022108f;	val_dir[14822*3 + 1] = 0.817992f;	val_dir[14822*3 + 2] = -0.574805f;
+ 	val_dir[14823*3 + 0] = 0.044455f;	val_dir[14823*3 + 1] = 0.844653f;	val_dir[14823*3 + 2] = -0.533465f;
+ 	val_dir[14824*3 + 0] = 0.066848f;	val_dir[14824*3 + 1] = 0.869030f;	val_dir[14824*3 + 2] = -0.490222f;
+ 	val_dir[14825*3 + 0] = 0.089087f;	val_dir[14825*3 + 1] = 0.890871f;	val_dir[14825*3 + 2] = -0.445435f;
+ 	val_dir[14826*3 + 0] = 0.110974f;	val_dir[14826*3 + 1] = 0.909988f;	val_dir[14826*3 + 2] = -0.399507f;
+ 	val_dir[14827*3 + 0] = 0.132324f;	val_dir[14827*3 + 1] = 0.926270f;	val_dir[14827*3 + 2] = -0.352865f;
+ 	val_dir[14828*3 + 0] = 0.152971f;	val_dir[14828*3 + 1] = 0.939680f;	val_dir[14828*3 + 2] = -0.305942f;
+ 	val_dir[14829*3 + 0] = 0.172774f;	val_dir[14829*3 + 1] = 0.950255f;	val_dir[14829*3 + 2] = -0.259161f;
+ 	val_dir[14830*3 + 0] = 0.191620f;	val_dir[14830*3 + 1] = 0.958098f;	val_dir[14830*3 + 2] = -0.212911f;
+ 	val_dir[14831*3 + 0] = 0.209427f;	val_dir[14831*3 + 1] = 0.963364f;	val_dir[14831*3 + 2] = -0.167542f;
+ 	val_dir[14832*3 + 0] = 0.226144f;	val_dir[14832*3 + 1] = 0.966252f;	val_dir[14832*3 + 2] = -0.123351f;
+ 	val_dir[14833*3 + 0] = 0.241747f;	val_dir[14833*3 + 1] = 0.966988f;	val_dir[14833*3 + 2] = -0.080582f;
+ 	val_dir[14834*3 + 0] = 0.256235f;	val_dir[14834*3 + 1] = 0.965810f;	val_dir[14834*3 + 2] = -0.039421f;
+ 	val_dir[14835*3 + 0] = 0.269630f;	val_dir[14835*3 + 1] = 0.962964f;	val_dir[14835*3 + 2] = 0.0f;
+ 	val_dir[14836*3 + 0] = -0.967641f;	val_dir[14836*3 + 1] = -0.251587f;	val_dir[14836*3 + 2] = -0.019353f;
+ 	val_dir[14837*3 + 0] = -0.969584f;	val_dir[14837*3 + 1] = -0.237449f;	val_dir[14837*3 + 2] = -0.059362f;
+ 	val_dir[14838*3 + 0] = -0.969746f;	val_dir[14838*3 + 1] = -0.222234f;	val_dir[14838*3 + 2] = -0.101015f;
+ 	val_dir[14839*3 + 0] = -0.967890f;	val_dir[14839*3 + 1] = -0.205934f;	val_dir[14839*3 + 2] = -0.144154f;
+ 	val_dir[14840*3 + 0] = -0.963787f;	val_dir[14840*3 + 1] = -0.188567f;	val_dir[14840*3 + 2] = -0.188567f;
+ 	val_dir[14841*3 + 0] = -0.957230f;	val_dir[14841*3 + 1] = -0.170174f;	val_dir[14841*3 + 2] = -0.233990f;
+ 	val_dir[14842*3 + 0] = -0.948047f;	val_dir[14842*3 + 1] = -0.150826f;	val_dir[14842*3 + 2] = -0.280105f;
+ 	val_dir[14843*3 + 0] = -0.936111f;	val_dir[14843*3 + 1] = -0.130620f;	val_dir[14843*3 + 2] = -0.326550f;
+ 	val_dir[14844*3 + 0] = -0.921354f;	val_dir[14844*3 + 1] = -0.109685f;	val_dir[14844*3 + 2] = -0.372929f;
+ 	val_dir[14845*3 + 0] = -0.903777f;	val_dir[14845*3 + 1] = -0.088173f;	val_dir[14845*3 + 2] = -0.418823f;
+ 	val_dir[14846*3 + 0] = -0.883452f;	val_dir[14846*3 + 1] = -0.066259f;	val_dir[14846*3 + 2] = -0.463812f;
+ 	val_dir[14847*3 + 0] = -0.860527f;	val_dir[14847*3 + 1] = -0.044130f;	val_dir[14847*3 + 2] = -0.507490f;
+ 	val_dir[14848*3 + 0] = -0.835215f;	val_dir[14848*3 + 1] = -0.021979f;	val_dir[14848*3 + 2] = -0.549484f;
+ 	val_dir[14849*3 + 0] = -0.807791f;	val_dir[14849*3 + 1] = 0.0f;	val_dir[14849*3 + 2] = -0.589469f;
+ 	val_dir[14850*3 + 0] = -0.799803f;	val_dir[14850*3 + 1] = 0.022217f;	val_dir[14850*3 + 2] = -0.599852f;
+ 	val_dir[14851*3 + 0] = -0.790973f;	val_dir[14851*3 + 1] = 0.045198f;	val_dir[14851*3 + 2] = -0.610179f;
+ 	val_dir[14852*3 + 0] = -0.781248f;	val_dir[14852*3 + 1] = 0.068934f;	val_dir[14852*3 + 2] = -0.620403f;
+ 	val_dir[14853*3 + 0] = -0.770574f;	val_dir[14853*3 + 1] = 0.093403f;	val_dir[14853*3 + 2] = -0.630470f;
+ 	val_dir[14854*3 + 0] = -0.758899f;	val_dir[14854*3 + 1] = 0.118578f;	val_dir[14854*3 + 2] = -0.640321f;
+ 	val_dir[14855*3 + 0] = -0.746176f;	val_dir[14855*3 + 1] = 0.144421f;	val_dir[14855*3 + 2] = -0.649895f;
+ 	val_dir[14856*3 + 0] = -0.732361f;	val_dir[14856*3 + 1] = 0.170884f;	val_dir[14856*3 + 2] = -0.659125f;
+ 	val_dir[14857*3 + 0] = -0.717418f;	val_dir[14857*3 + 1] = 0.197908f;	val_dir[14857*3 + 2] = -0.667940f;
+ 	val_dir[14858*3 + 0] = -0.701316f;	val_dir[14858*3 + 1] = 0.225423f;	val_dir[14858*3 + 2] = -0.676269f;
+ 	val_dir[14859*3 + 0] = -0.684038f;	val_dir[14859*3 + 1] = 0.253347f;	val_dir[14859*3 + 2] = -0.684038f;
+ 	val_dir[14860*3 + 0] = -0.665574f;	val_dir[14860*3 + 1] = 0.281589f;	val_dir[14860*3 + 2] = -0.691173f;
+ 	val_dir[14861*3 + 0] = -0.645928f;	val_dir[14861*3 + 1] = 0.310045f;	val_dir[14861*3 + 2] = -0.697602f;
+ 	val_dir[14862*3 + 0] = -0.625119f;	val_dir[14862*3 + 1] = 0.338606f;	val_dir[14862*3 + 2] = -0.703259f;
+ 	val_dir[14863*3 + 0] = -0.603178f;	val_dir[14863*3 + 1] = 0.367152f;	val_dir[14863*3 + 2] = -0.708079f;
+ 	val_dir[14864*3 + 0] = -0.580154f;	val_dir[14864*3 + 1] = 0.395559f;	val_dir[14864*3 + 2] = -0.712007f;
+ 	val_dir[14865*3 + 0] = -0.556108f;	val_dir[14865*3 + 1] = 0.423702f;	val_dir[14865*3 + 2] = -0.714997f;
+ 	val_dir[14866*3 + 0] = -0.531119f;	val_dir[14866*3 + 1] = 0.451451f;	val_dir[14866*3 + 2] = -0.717011f;
+ 	val_dir[14867*3 + 0] = -0.505276f;	val_dir[14867*3 + 1] = 0.478683f;	val_dir[14867*3 + 2] = -0.718024f;
+ 	val_dir[14868*3 + 0] = -0.478683f;	val_dir[14868*3 + 1] = 0.505276f;	val_dir[14868*3 + 2] = -0.718024f;
+ 	val_dir[14869*3 + 0] = -0.451451f;	val_dir[14869*3 + 1] = 0.531119f;	val_dir[14869*3 + 2] = -0.717011f;
+ 	val_dir[14870*3 + 0] = -0.423702f;	val_dir[14870*3 + 1] = 0.556108f;	val_dir[14870*3 + 2] = -0.714997f;
+ 	val_dir[14871*3 + 0] = -0.395559f;	val_dir[14871*3 + 1] = 0.580154f;	val_dir[14871*3 + 2] = -0.712007f;
+ 	val_dir[14872*3 + 0] = -0.367152f;	val_dir[14872*3 + 1] = 0.603178f;	val_dir[14872*3 + 2] = -0.708079f;
+ 	val_dir[14873*3 + 0] = -0.338606f;	val_dir[14873*3 + 1] = 0.625119f;	val_dir[14873*3 + 2] = -0.703259f;
+ 	val_dir[14874*3 + 0] = -0.310045f;	val_dir[14874*3 + 1] = 0.645928f;	val_dir[14874*3 + 2] = -0.697602f;
+ 	val_dir[14875*3 + 0] = -0.281589f;	val_dir[14875*3 + 1] = 0.665574f;	val_dir[14875*3 + 2] = -0.691173f;
+ 	val_dir[14876*3 + 0] = -0.253347f;	val_dir[14876*3 + 1] = 0.684038f;	val_dir[14876*3 + 2] = -0.684038f;
+ 	val_dir[14877*3 + 0] = -0.225423f;	val_dir[14877*3 + 1] = 0.701316f;	val_dir[14877*3 + 2] = -0.676269f;
+ 	val_dir[14878*3 + 0] = -0.197908f;	val_dir[14878*3 + 1] = 0.717418f;	val_dir[14878*3 + 2] = -0.667940f;
+ 	val_dir[14879*3 + 0] = -0.170884f;	val_dir[14879*3 + 1] = 0.732361f;	val_dir[14879*3 + 2] = -0.659125f;
+ 	val_dir[14880*3 + 0] = -0.144421f;	val_dir[14880*3 + 1] = 0.746176f;	val_dir[14880*3 + 2] = -0.649895f;
+ 	val_dir[14881*3 + 0] = -0.118578f;	val_dir[14881*3 + 1] = 0.758899f;	val_dir[14881*3 + 2] = -0.640321f;
+ 	val_dir[14882*3 + 0] = -0.093403f;	val_dir[14882*3 + 1] = 0.770574f;	val_dir[14882*3 + 2] = -0.630470f;
+ 	val_dir[14883*3 + 0] = -0.068934f;	val_dir[14883*3 + 1] = 0.781248f;	val_dir[14883*3 + 2] = -0.620403f;
+ 	val_dir[14884*3 + 0] = -0.045198f;	val_dir[14884*3 + 1] = 0.790973f;	val_dir[14884*3 + 2] = -0.610179f;
+ 	val_dir[14885*3 + 0] = -0.022217f;	val_dir[14885*3 + 1] = 0.799803f;	val_dir[14885*3 + 2] = -0.599852f;
+ 	val_dir[14886*3 + 0] = 0.0f;	val_dir[14886*3 + 1] = 0.807791f;	val_dir[14886*3 + 2] = -0.589469f;
+ 	val_dir[14887*3 + 0] = 0.021979f;	val_dir[14887*3 + 1] = 0.835215f;	val_dir[14887*3 + 2] = -0.549484f;
+ 	val_dir[14888*3 + 0] = 0.044130f;	val_dir[14888*3 + 1] = 0.860527f;	val_dir[14888*3 + 2] = -0.507490f;
+ 	val_dir[14889*3 + 0] = 0.066259f;	val_dir[14889*3 + 1] = 0.883452f;	val_dir[14889*3 + 2] = -0.463812f;
+ 	val_dir[14890*3 + 0] = 0.088173f;	val_dir[14890*3 + 1] = 0.903777f;	val_dir[14890*3 + 2] = -0.418823f;
+ 	val_dir[14891*3 + 0] = 0.109685f;	val_dir[14891*3 + 1] = 0.921354f;	val_dir[14891*3 + 2] = -0.372929f;
+ 	val_dir[14892*3 + 0] = 0.130620f;	val_dir[14892*3 + 1] = 0.936111f;	val_dir[14892*3 + 2] = -0.326550f;
+ 	val_dir[14893*3 + 0] = 0.150826f;	val_dir[14893*3 + 1] = 0.948047f;	val_dir[14893*3 + 2] = -0.280105f;
+ 	val_dir[14894*3 + 0] = 0.170174f;	val_dir[14894*3 + 1] = 0.957230f;	val_dir[14894*3 + 2] = -0.233990f;
+ 	val_dir[14895*3 + 0] = 0.188567f;	val_dir[14895*3 + 1] = 0.963787f;	val_dir[14895*3 + 2] = -0.188567f;
+ 	val_dir[14896*3 + 0] = 0.205934f;	val_dir[14896*3 + 1] = 0.967890f;	val_dir[14896*3 + 2] = -0.144154f;
+ 	val_dir[14897*3 + 0] = 0.222234f;	val_dir[14897*3 + 1] = 0.969746f;	val_dir[14897*3 + 2] = -0.101015f;
+ 	val_dir[14898*3 + 0] = 0.237449f;	val_dir[14898*3 + 1] = 0.969584f;	val_dir[14898*3 + 2] = -0.059362f;
+ 	val_dir[14899*3 + 0] = 0.251587f;	val_dir[14899*3 + 1] = 0.967641f;	val_dir[14899*3 + 2] = -0.019353f;
+ 	val_dir[14900*3 + 0] = -0.969015f;	val_dir[14900*3 + 1] = -0.247004f;	val_dir[14900*3 + 2] = 0.0f;
+ 	val_dir[14901*3 + 0] = -0.971653f;	val_dir[14901*3 + 1] = -0.233197f;	val_dir[14901*3 + 2] = -0.038866f;
+ 	val_dir[14902*3 + 0] = -0.972636f;	val_dir[14902*3 + 1] = -0.218347f;	val_dir[14902*3 + 2] = -0.079399f;
+ 	val_dir[14903*3 + 0] = -0.971732f;	val_dir[14903*3 + 1] = -0.202444f;	val_dir[14903*3 + 2] = -0.121466f;
+ 	val_dir[14904*3 + 0] = -0.968712f;	val_dir[14904*3 + 1] = -0.185498f;	val_dir[14904*3 + 2] = -0.164887f;
+ 	val_dir[14905*3 + 0] = -0.963364f;	val_dir[14905*3 + 1] = -0.167542f;	val_dir[14905*3 + 2] = -0.209427f;
+ 	val_dir[14906*3 + 0] = -0.955502f;	val_dir[14906*3 + 1] = -0.148634f;	val_dir[14906*3 + 2] = -0.254801f;
+ 	val_dir[14907*3 + 0] = -0.944981f;	val_dir[14907*3 + 1] = -0.128861f;	val_dir[14907*3 + 2] = -0.300676f;
+ 	val_dir[14908*3 + 0] = -0.931705f;	val_dir[14908*3 + 1] = -0.108338f;	val_dir[14908*3 + 2] = -0.346681f;
+ 	val_dir[14909*3 + 0] = -0.915644f;	val_dir[14909*3 + 1] = -0.087204f;	val_dir[14909*3 + 2] = -0.392419f;
+ 	val_dir[14910*3 + 0] = -0.896831f;	val_dir[14910*3 + 1] = -0.065622f;	val_dir[14910*3 + 2] = -0.437479f;
+ 	val_dir[14911*3 + 0] = -0.875376f;	val_dir[14911*3 + 1] = -0.043769f;	val_dir[14911*3 + 2] = -0.481457f;
+ 	val_dir[14912*3 + 0] = -0.851455f;	val_dir[14912*3 + 1] = -0.021832f;	val_dir[14912*3 + 2] = -0.523973f;
+ 	val_dir[14913*3 + 0] = -0.825307f;	val_dir[14913*3 + 1] = 0.0f;	val_dir[14913*3 + 2] = -0.564684f;
+ 	val_dir[14914*3 + 0] = -0.817992f;	val_dir[14914*3 + 1] = 0.022108f;	val_dir[14914*3 + 2] = -0.574805f;
+ 	val_dir[14915*3 + 0] = -0.809858f;	val_dir[14915*3 + 1] = 0.044992f;	val_dir[14915*3 + 2] = -0.584898f;
+ 	val_dir[14916*3 + 0] = -0.800850f;	val_dir[14916*3 + 1] = 0.068644f;	val_dir[14916*3 + 2] = -0.594917f;
+ 	val_dir[14917*3 + 0] = -0.790912f;	val_dir[14917*3 + 1] = 0.093048f;	val_dir[14917*3 + 2] = -0.604815f;
+ 	val_dir[14918*3 + 0] = -0.779987f;	val_dir[14918*3 + 1] = 0.118180f;	val_dir[14918*3 + 2] = -0.614535f;
+ 	val_dir[14919*3 + 0] = -0.768025f;	val_dir[14919*3 + 1] = 0.144005f;	val_dir[14919*3 + 2] = -0.624020f;
+ 	val_dir[14920*3 + 0] = -0.754976f;	val_dir[14920*3 + 1] = 0.170478f;	val_dir[14920*3 + 2] = -0.633205f;
+ 	val_dir[14921*3 + 0] = -0.740797f;	val_dir[14921*3 + 1] = 0.197546f;	val_dir[14921*3 + 2] = -0.642024f;
+ 	val_dir[14922*3 + 0] = -0.725454f;	val_dir[14922*3 + 1] = 0.225141f;	val_dir[14922*3 + 2] = -0.650407f;
+ 	val_dir[14923*3 + 0] = -0.708918f;	val_dir[14923*3 + 1] = 0.253185f;	val_dir[14923*3 + 2] = -0.658281f;
+ 	val_dir[14924*3 + 0] = -0.691173f;	val_dir[14924*3 + 1] = 0.281589f;	val_dir[14924*3 + 2] = -0.665574f;
+ 	val_dir[14925*3 + 0] = -0.672214f;	val_dir[14925*3 + 1] = 0.310253f;	val_dir[14925*3 + 2] = -0.672214f;
+ 	val_dir[14926*3 + 0] = -0.652051f;	val_dir[14926*3 + 1] = 0.339066f;	val_dir[14926*3 + 2] = -0.678133f;
+ 	val_dir[14927*3 + 0] = -0.630706f;	val_dir[14927*3 + 1] = 0.367912f;	val_dir[14927*3 + 2] = -0.683265f;
+ 	val_dir[14928*3 + 0] = -0.608219f;	val_dir[14928*3 + 1] = 0.396664f;	val_dir[14928*3 + 2] = -0.687552f;
+ 	val_dir[14929*3 + 0] = -0.584643f;	val_dir[14929*3 + 1] = 0.425195f;	val_dir[14929*3 + 2] = -0.690942f;
+ 	val_dir[14930*3 + 0] = -0.560050f;	val_dir[14930*3 + 1] = 0.453374f;	val_dir[14930*3 + 2] = -0.693395f;
+ 	val_dir[14931*3 + 0] = -0.534522f;	val_dir[14931*3 + 1] = 0.481070f;	val_dir[14931*3 + 2] = -0.694879f;
+ 	val_dir[14932*3 + 0] = -0.508159f;	val_dir[14932*3 + 1] = 0.508159f;	val_dir[14932*3 + 2] = -0.695376f;
+ 	val_dir[14933*3 + 0] = -0.481070f;	val_dir[14933*3 + 1] = 0.534522f;	val_dir[14933*3 + 2] = -0.694879f;
+ 	val_dir[14934*3 + 0] = -0.453374f;	val_dir[14934*3 + 1] = 0.560050f;	val_dir[14934*3 + 2] = -0.693395f;
+ 	val_dir[14935*3 + 0] = -0.425195f;	val_dir[14935*3 + 1] = 0.584643f;	val_dir[14935*3 + 2] = -0.690942f;
+ 	val_dir[14936*3 + 0] = -0.396664f;	val_dir[14936*3 + 1] = 0.608219f;	val_dir[14936*3 + 2] = -0.687552f;
+ 	val_dir[14937*3 + 0] = -0.367912f;	val_dir[14937*3 + 1] = 0.630706f;	val_dir[14937*3 + 2] = -0.683265f;
+ 	val_dir[14938*3 + 0] = -0.339066f;	val_dir[14938*3 + 1] = 0.652051f;	val_dir[14938*3 + 2] = -0.678133f;
+ 	val_dir[14939*3 + 0] = -0.310253f;	val_dir[14939*3 + 1] = 0.672214f;	val_dir[14939*3 + 2] = -0.672214f;
+ 	val_dir[14940*3 + 0] = -0.281589f;	val_dir[14940*3 + 1] = 0.691173f;	val_dir[14940*3 + 2] = -0.665574f;
+ 	val_dir[14941*3 + 0] = -0.253185f;	val_dir[14941*3 + 1] = 0.708918f;	val_dir[14941*3 + 2] = -0.658281f;
+ 	val_dir[14942*3 + 0] = -0.225141f;	val_dir[14942*3 + 1] = 0.725454f;	val_dir[14942*3 + 2] = -0.650407f;
+ 	val_dir[14943*3 + 0] = -0.197546f;	val_dir[14943*3 + 1] = 0.740797f;	val_dir[14943*3 + 2] = -0.642024f;
+ 	val_dir[14944*3 + 0] = -0.170478f;	val_dir[14944*3 + 1] = 0.754976f;	val_dir[14944*3 + 2] = -0.633205f;
+ 	val_dir[14945*3 + 0] = -0.144005f;	val_dir[14945*3 + 1] = 0.768025f;	val_dir[14945*3 + 2] = -0.624020f;
+ 	val_dir[14946*3 + 0] = -0.118180f;	val_dir[14946*3 + 1] = 0.779987f;	val_dir[14946*3 + 2] = -0.614535f;
+ 	val_dir[14947*3 + 0] = -0.093048f;	val_dir[14947*3 + 1] = 0.790912f;	val_dir[14947*3 + 2] = -0.604815f;
+ 	val_dir[14948*3 + 0] = -0.068644f;	val_dir[14948*3 + 1] = 0.800850f;	val_dir[14948*3 + 2] = -0.594917f;
+ 	val_dir[14949*3 + 0] = -0.044992f;	val_dir[14949*3 + 1] = 0.809858f;	val_dir[14949*3 + 2] = -0.584898f;
+ 	val_dir[14950*3 + 0] = -0.022108f;	val_dir[14950*3 + 1] = 0.817992f;	val_dir[14950*3 + 2] = -0.574805f;
+ 	val_dir[14951*3 + 0] = 0.0f;	val_dir[14951*3 + 1] = 0.825307f;	val_dir[14951*3 + 2] = -0.564684f;
+ 	val_dir[14952*3 + 0] = 0.021832f;	val_dir[14952*3 + 1] = 0.851455f;	val_dir[14952*3 + 2] = -0.523973f;
+ 	val_dir[14953*3 + 0] = 0.043769f;	val_dir[14953*3 + 1] = 0.875376f;	val_dir[14953*3 + 2] = -0.481457f;
+ 	val_dir[14954*3 + 0] = 0.065622f;	val_dir[14954*3 + 1] = 0.896831f;	val_dir[14954*3 + 2] = -0.437479f;
+ 	val_dir[14955*3 + 0] = 0.087204f;	val_dir[14955*3 + 1] = 0.915644f;	val_dir[14955*3 + 2] = -0.392419f;
+ 	val_dir[14956*3 + 0] = 0.108338f;	val_dir[14956*3 + 1] = 0.931705f;	val_dir[14956*3 + 2] = -0.346681f;
+ 	val_dir[14957*3 + 0] = 0.128861f;	val_dir[14957*3 + 1] = 0.944981f;	val_dir[14957*3 + 2] = -0.300676f;
+ 	val_dir[14958*3 + 0] = 0.148634f;	val_dir[14958*3 + 1] = 0.955502f;	val_dir[14958*3 + 2] = -0.254801f;
+ 	val_dir[14959*3 + 0] = 0.167542f;	val_dir[14959*3 + 1] = 0.963364f;	val_dir[14959*3 + 2] = -0.209427f;
+ 	val_dir[14960*3 + 0] = 0.185498f;	val_dir[14960*3 + 1] = 0.968712f;	val_dir[14960*3 + 2] = -0.164887f;
+ 	val_dir[14961*3 + 0] = 0.202444f;	val_dir[14961*3 + 1] = 0.971732f;	val_dir[14961*3 + 2] = -0.121466f;
+ 	val_dir[14962*3 + 0] = 0.218347f;	val_dir[14962*3 + 1] = 0.972636f;	val_dir[14962*3 + 2] = -0.079399f;
+ 	val_dir[14963*3 + 0] = 0.233197f;	val_dir[14963*3 + 1] = 0.971653f;	val_dir[14963*3 + 2] = -0.038866f;
+ 	val_dir[14964*3 + 0] = 0.247004f;	val_dir[14964*3 + 1] = 0.969015f;	val_dir[14964*3 + 2] = 0.0f;
+ 	val_dir[14965*3 + 0] = -0.973240f;	val_dir[14965*3 + 1] = -0.228998f;	val_dir[14965*3 + 2] = -0.019083f;
+ 	val_dir[14966*3 + 0] = -0.974972f;	val_dir[14966*3 + 1] = -0.214494f;	val_dir[14966*3 + 2] = -0.058498f;
+ 	val_dir[14967*3 + 0] = -0.974943f;	val_dir[14967*3 + 1] = -0.198968f;	val_dir[14967*3 + 2] = -0.099484f;
+ 	val_dir[14968*3 + 0] = -0.972929f;	val_dir[14968*3 + 1] = -0.182424f;	val_dir[14968*3 + 2] = -0.141885f;
+ 	val_dir[14969*3 + 0] = -0.968712f;	val_dir[14969*3 + 1] = -0.164887f;	val_dir[14969*3 + 2] = -0.185498f;
+ 	val_dir[14970*3 + 0] = -0.962099f;	val_dir[14970*3 + 1] = -0.146406f;	val_dir[14970*3 + 2] = -0.230067f;
+ 	val_dir[14971*3 + 0] = -0.952928f;	val_dir[14971*3 + 1] = -0.127057f;	val_dir[14971*3 + 2] = -0.275290f;
+ 	val_dir[14972*3 + 0] = -0.941082f;	val_dir[14972*3 + 1] = -0.106941f;	val_dir[14972*3 + 2] = -0.320824f;
+ 	val_dir[14973*3 + 0] = -0.92650f;	val_dir[14973*3 + 1] = -0.086186f;	val_dir[14973*3 + 2] = -0.366291f;
+ 	val_dir[14974*3 + 0] = -0.909185f;	val_dir[14974*3 + 1] = -0.064942f;	val_dir[14974*3 + 2] = -0.411298f;
+ 	val_dir[14975*3 + 0] = -0.889206f;	val_dir[14975*3 + 1] = -0.043376f;	val_dir[14975*3 + 2] = -0.455447f;
+ 	val_dir[14976*3 + 0] = -0.866703f;	val_dir[14976*3 + 1] = -0.021668f;	val_dir[14976*3 + 2] = -0.498354f;
+ 	val_dir[14977*3 + 0] = -0.841879f;	val_dir[14977*3 + 1] = 0.0f;	val_dir[14977*3 + 2] = -0.539666f;
+ 	val_dir[14978*3 + 0] = -0.835215f;	val_dir[14978*3 + 1] = 0.021979f;	val_dir[14978*3 + 2] = -0.549484f;
+ 	val_dir[14979*3 + 0] = -0.827759f;	val_dir[14979*3 + 1] = 0.044744f;	val_dir[14979*3 + 2] = -0.559297f;
+ 	val_dir[14980*3 + 0] = -0.819453f;	val_dir[14980*3 + 1] = 0.068288f;	val_dir[14980*3 + 2] = -0.569064f;
+ 	val_dir[14981*3 + 0] = -0.810237f;	val_dir[14981*3 + 1] = 0.092599f;	val_dir[14981*3 + 2] = -0.578741f;
+ 	val_dir[14982*3 + 0] = -0.800055f;	val_dir[14982*3 + 1] = 0.117655f;	val_dir[14982*3 + 2] = -0.588276f;
+ 	val_dir[14983*3 + 0] = -0.788851f;	val_dir[14983*3 + 1] = 0.143427f;	val_dir[14983*3 + 2] = -0.597614f;
+ 	val_dir[14984*3 + 0] = -0.776571f;	val_dir[14984*3 + 1] = 0.169875f;	val_dir[14984*3 + 2] = -0.606696f;
+ 	val_dir[14985*3 + 0] = -0.763167f;	val_dir[14985*3 + 1] = 0.196946f;	val_dir[14985*3 + 2] = -0.615457f;
+ 	val_dir[14986*3 + 0] = -0.748598f;	val_dir[14986*3 + 1] = 0.224579f;	val_dir[14986*3 + 2] = -0.623831f;
+ 	val_dir[14987*3 + 0] = -0.732828f;	val_dir[14987*3 + 1] = 0.252699f;	val_dir[14987*3 + 2] = -0.631748f;
+ 	val_dir[14988*3 + 0] = -0.715834f;	val_dir[14988*3 + 1] = 0.281220f;	val_dir[14988*3 + 2] = -0.639138f;
+ 	val_dir[14989*3 + 0] = -0.697602f;	val_dir[14989*3 + 1] = 0.310045f;	val_dir[14989*3 + 2] = -0.645928f;
+ 	val_dir[14990*3 + 0] = -0.678133f;	val_dir[14990*3 + 1] = 0.339066f;	val_dir[14990*3 + 2] = -0.652051f;
+ 	val_dir[14991*3 + 0] = -0.657440f;	val_dir[14991*3 + 1] = 0.368166f;	val_dir[14991*3 + 2] = -0.657440f;
+ 	val_dir[14992*3 + 0] = -0.635553f;	val_dir[14992*3 + 1] = 0.397220f;	val_dir[14992*3 + 2] = -0.662034f;
+ 	val_dir[14993*3 + 0] = -0.612517f;	val_dir[14993*3 + 1] = 0.426099f;	val_dir[14993*3 + 2] = -0.665780f;
+ 	val_dir[14994*3 + 0] = -0.588395f;	val_dir[14994*3 + 1] = 0.454669f;	val_dir[14994*3 + 2] = -0.668631f;
+ 	val_dir[14995*3 + 0] = -0.563264f;	val_dir[14995*3 + 1] = 0.482798f;	val_dir[14995*3 + 2] = -0.670552f;
+ 	val_dir[14996*3 + 0] = -0.537215f;	val_dir[14996*3 + 1] = 0.510355f;	val_dir[14996*3 + 2] = -0.671519f;
+ 	val_dir[14997*3 + 0] = -0.510355f;	val_dir[14997*3 + 1] = 0.537215f;	val_dir[14997*3 + 2] = -0.671519f;
+ 	val_dir[14998*3 + 0] = -0.482798f;	val_dir[14998*3 + 1] = 0.563264f;	val_dir[14998*3 + 2] = -0.670552f;
+ 	val_dir[14999*3 + 0] = -0.454669f;	val_dir[14999*3 + 1] = 0.588395f;	val_dir[14999*3 + 2] = -0.668631f;
+ 	val_dir[15000*3 + 0] = -0.426099f;	val_dir[15000*3 + 1] = 0.612517f;	val_dir[15000*3 + 2] = -0.665780f;
+ 	val_dir[15001*3 + 0] = -0.397220f;	val_dir[15001*3 + 1] = 0.635553f;	val_dir[15001*3 + 2] = -0.662034f;
+ 	val_dir[15002*3 + 0] = -0.368166f;	val_dir[15002*3 + 1] = 0.657440f;	val_dir[15002*3 + 2] = -0.657440f;
+ 	val_dir[15003*3 + 0] = -0.339066f;	val_dir[15003*3 + 1] = 0.678133f;	val_dir[15003*3 + 2] = -0.652051f;
+ 	val_dir[15004*3 + 0] = -0.310045f;	val_dir[15004*3 + 1] = 0.697602f;	val_dir[15004*3 + 2] = -0.645928f;
+ 	val_dir[15005*3 + 0] = -0.281220f;	val_dir[15005*3 + 1] = 0.715834f;	val_dir[15005*3 + 2] = -0.639138f;
+ 	val_dir[15006*3 + 0] = -0.252699f;	val_dir[15006*3 + 1] = 0.732828f;	val_dir[15006*3 + 2] = -0.631748f;
+ 	val_dir[15007*3 + 0] = -0.224579f;	val_dir[15007*3 + 1] = 0.748598f;	val_dir[15007*3 + 2] = -0.623831f;
+ 	val_dir[15008*3 + 0] = -0.196946f;	val_dir[15008*3 + 1] = 0.763167f;	val_dir[15008*3 + 2] = -0.615457f;
+ 	val_dir[15009*3 + 0] = -0.169875f;	val_dir[15009*3 + 1] = 0.776571f;	val_dir[15009*3 + 2] = -0.606696f;
+ 	val_dir[15010*3 + 0] = -0.143427f;	val_dir[15010*3 + 1] = 0.788851f;	val_dir[15010*3 + 2] = -0.597614f;
+ 	val_dir[15011*3 + 0] = -0.117655f;	val_dir[15011*3 + 1] = 0.800055f;	val_dir[15011*3 + 2] = -0.588276f;
+ 	val_dir[15012*3 + 0] = -0.092599f;	val_dir[15012*3 + 1] = 0.810237f;	val_dir[15012*3 + 2] = -0.578741f;
+ 	val_dir[15013*3 + 0] = -0.068288f;	val_dir[15013*3 + 1] = 0.819453f;	val_dir[15013*3 + 2] = -0.569064f;
+ 	val_dir[15014*3 + 0] = -0.044744f;	val_dir[15014*3 + 1] = 0.827759f;	val_dir[15014*3 + 2] = -0.559297f;
+ 	val_dir[15015*3 + 0] = -0.021979f;	val_dir[15015*3 + 1] = 0.835215f;	val_dir[15015*3 + 2] = -0.549484f;
+ 	val_dir[15016*3 + 0] = 0.0f;	val_dir[15016*3 + 1] = 0.841879f;	val_dir[15016*3 + 2] = -0.539666f;
+ 	val_dir[15017*3 + 0] = 0.021668f;	val_dir[15017*3 + 1] = 0.866703f;	val_dir[15017*3 + 2] = -0.498354f;
+ 	val_dir[15018*3 + 0] = 0.043376f;	val_dir[15018*3 + 1] = 0.889206f;	val_dir[15018*3 + 2] = -0.455447f;
+ 	val_dir[15019*3 + 0] = 0.064942f;	val_dir[15019*3 + 1] = 0.909185f;	val_dir[15019*3 + 2] = -0.411298f;
+ 	val_dir[15020*3 + 0] = 0.086186f;	val_dir[15020*3 + 1] = 0.92650f;	val_dir[15020*3 + 2] = -0.366291f;
+ 	val_dir[15021*3 + 0] = 0.106941f;	val_dir[15021*3 + 1] = 0.941082f;	val_dir[15021*3 + 2] = -0.320824f;
+ 	val_dir[15022*3 + 0] = 0.127057f;	val_dir[15022*3 + 1] = 0.952928f;	val_dir[15022*3 + 2] = -0.275290f;
+ 	val_dir[15023*3 + 0] = 0.146406f;	val_dir[15023*3 + 1] = 0.962099f;	val_dir[15023*3 + 2] = -0.230067f;
+ 	val_dir[15024*3 + 0] = 0.164887f;	val_dir[15024*3 + 1] = 0.968712f;	val_dir[15024*3 + 2] = -0.185498f;
+ 	val_dir[15025*3 + 0] = 0.182424f;	val_dir[15025*3 + 1] = 0.972929f;	val_dir[15025*3 + 2] = -0.141885f;
+ 	val_dir[15026*3 + 0] = 0.198968f;	val_dir[15026*3 + 1] = 0.974943f;	val_dir[15026*3 + 2] = -0.099484f;
+ 	val_dir[15027*3 + 0] = 0.214494f;	val_dir[15027*3 + 1] = 0.974972f;	val_dir[15027*3 + 2] = -0.058498f;
+ 	val_dir[15028*3 + 0] = 0.228998f;	val_dir[15028*3 + 1] = 0.973240f;	val_dir[15028*3 + 2] = -0.019083f;
+ 	val_dir[15029*3 + 0] = -0.974391f;	val_dir[15029*3 + 1] = -0.224860f;	val_dir[15029*3 + 2] = 0.0f;
+ 	val_dir[15030*3 + 0] = -0.976804f;	val_dir[15030*3 + 1] = -0.210683f;	val_dir[15030*3 + 2] = -0.038306f;
+ 	val_dir[15031*3 + 0] = -0.977577f;	val_dir[15031*3 + 1] = -0.195515f;	val_dir[15031*3 + 2] = -0.078206f;
+ 	val_dir[15032*3 + 0] = -0.976491f;	val_dir[15032*3 + 1] = -0.179355f;	val_dir[15032*3 + 2] = -0.119570f;
+ 	val_dir[15033*3 + 0] = -0.973329f;	val_dir[15033*3 + 1] = -0.162221f;	val_dir[15033*3 + 2] = -0.162221f;
+ 	val_dir[15034*3 + 0] = -0.967890f;	val_dir[15034*3 + 1] = -0.144154f;	val_dir[15034*3 + 2] = -0.205934f;
+ 	val_dir[15035*3 + 0] = -0.960001f;	val_dir[15035*3 + 1] = -0.125218f;	val_dir[15035*3 + 2] = -0.250435f;
+ 	val_dir[15036*3 + 0] = -0.949528f;	val_dir[15036*3 + 1] = -0.105503f;	val_dir[15036*3 + 2] = -0.295409f;
+ 	val_dir[15037*3 + 0] = -0.936382f;	val_dir[15037*3 + 1] = -0.085126f;	val_dir[15037*3 + 2] = -0.340503f;
+ 	val_dir[15038*3 + 0] = -0.920537f;	val_dir[15038*3 + 1] = -0.064223f;	val_dir[15038*3 + 2] = -0.385341f;
+ 	val_dir[15039*3 + 0] = -0.902027f;	val_dir[15039*3 + 1] = -0.042954f;	val_dir[15039*3 + 2] = -0.429537f;
+ 	val_dir[15040*3 + 0] = -0.880957f;	val_dir[15040*3 + 1] = -0.021487f;	val_dir[15040*3 + 2] = -0.472709f;
+ 	val_dir[15041*3 + 0] = -0.857493f;	val_dir[15041*3 + 1] = 0.0f;	val_dir[15041*3 + 2] = -0.514496f;
+ 	val_dir[15042*3 + 0] = -0.851455f;	val_dir[15042*3 + 1] = 0.021832f;	val_dir[15042*3 + 2] = -0.523973f;
+ 	val_dir[15043*3 + 0] = -0.844653f;	val_dir[15043*3 + 1] = 0.044455f;	val_dir[15043*3 + 2] = -0.533465f;
+ 	val_dir[15044*3 + 0] = -0.837027f;	val_dir[15044*3 + 1] = 0.067867f;	val_dir[15044*3 + 2] = -0.542936f;
+ 	val_dir[15045*3 + 0] = -0.828517f;	val_dir[15045*3 + 1] = 0.092057f;	val_dir[15045*3 + 2] = -0.552345f;
+ 	val_dir[15046*3 + 0] = -0.819064f;	val_dir[15046*3 + 1] = 0.117009f;	val_dir[15046*3 + 2] = -0.561644f;
+ 	val_dir[15047*3 + 0] = -0.808608f;	val_dir[15047*3 + 1] = 0.142695f;	val_dir[15047*3 + 2] = -0.570782f;
+ 	val_dir[15048*3 + 0] = -0.797092f;	val_dir[15048*3 + 1] = 0.169080f;	val_dir[15048*3 + 2] = -0.579703f;
+ 	val_dir[15049*3 + 0] = -0.784465f;	val_dir[15049*3 + 1] = 0.196116f;	val_dir[15049*3 + 2] = -0.588348f;
+ 	val_dir[15050*3 + 0] = -0.770677f;	val_dir[15050*3 + 1] = 0.223745f;	val_dir[15050*3 + 2] = -0.596653f;
+ 	val_dir[15051*3 + 0] = -0.755689f;	val_dir[15051*3 + 1] = 0.251896f;	val_dir[15051*3 + 2] = -0.604551f;
+ 	val_dir[15052*3 + 0] = -0.739469f;	val_dir[15052*3 + 1] = 0.280488f;	val_dir[15052*3 + 2] = -0.611974f;
+ 	val_dir[15053*3 + 0] = -0.721995f;	val_dir[15053*3 + 1] = 0.309426f;	val_dir[15053*3 + 2] = -0.618853f;
+ 	val_dir[15054*3 + 0] = -0.703259f;	val_dir[15054*3 + 1] = 0.338606f;	val_dir[15054*3 + 2] = -0.625119f;
+ 	val_dir[15055*3 + 0] = -0.683265f;	val_dir[15055*3 + 1] = 0.367912f;	val_dir[15055*3 + 2] = -0.630706f;
+ 	val_dir[15056*3 + 0] = -0.662034f;	val_dir[15056*3 + 1] = 0.397220f;	val_dir[15056*3 + 2] = -0.635553f;
+ 	val_dir[15057*3 + 0] = -0.639602f;	val_dir[15057*3 + 1] = 0.426401f;	val_dir[15057*3 + 2] = -0.639602f;
+ 	val_dir[15058*3 + 0] = -0.616022f;	val_dir[15058*3 + 1] = 0.455321f;	val_dir[15058*3 + 2] = -0.642806f;
+ 	val_dir[15059*3 + 0] = -0.591364f;	val_dir[15059*3 + 1] = 0.483843f;	val_dir[15059*3 + 2] = -0.645124f;
+ 	val_dir[15060*3 + 0] = -0.565711f;	val_dir[15060*3 + 1] = 0.511834f;	val_dir[15060*3 + 2] = -0.646527f;
+ 	val_dir[15061*3 + 0] = -0.539164f;	val_dir[15061*3 + 1] = 0.539164f;	val_dir[15061*3 + 2] = -0.646997f;
+ 	val_dir[15062*3 + 0] = -0.511834f;	val_dir[15062*3 + 1] = 0.565711f;	val_dir[15062*3 + 2] = -0.646527f;
+ 	val_dir[15063*3 + 0] = -0.483843f;	val_dir[15063*3 + 1] = 0.591364f;	val_dir[15063*3 + 2] = -0.645124f;
+ 	val_dir[15064*3 + 0] = -0.455321f;	val_dir[15064*3 + 1] = 0.616022f;	val_dir[15064*3 + 2] = -0.642806f;
+ 	val_dir[15065*3 + 0] = -0.426401f;	val_dir[15065*3 + 1] = 0.639602f;	val_dir[15065*3 + 2] = -0.639602f;
+ 	val_dir[15066*3 + 0] = -0.397220f;	val_dir[15066*3 + 1] = 0.662034f;	val_dir[15066*3 + 2] = -0.635553f;
+ 	val_dir[15067*3 + 0] = -0.367912f;	val_dir[15067*3 + 1] = 0.683265f;	val_dir[15067*3 + 2] = -0.630706f;
+ 	val_dir[15068*3 + 0] = -0.338606f;	val_dir[15068*3 + 1] = 0.703259f;	val_dir[15068*3 + 2] = -0.625119f;
+ 	val_dir[15069*3 + 0] = -0.309426f;	val_dir[15069*3 + 1] = 0.721995f;	val_dir[15069*3 + 2] = -0.618853f;
+ 	val_dir[15070*3 + 0] = -0.280488f;	val_dir[15070*3 + 1] = 0.739469f;	val_dir[15070*3 + 2] = -0.611974f;
+ 	val_dir[15071*3 + 0] = -0.251896f;	val_dir[15071*3 + 1] = 0.755689f;	val_dir[15071*3 + 2] = -0.604551f;
+ 	val_dir[15072*3 + 0] = -0.223745f;	val_dir[15072*3 + 1] = 0.770677f;	val_dir[15072*3 + 2] = -0.596653f;
+ 	val_dir[15073*3 + 0] = -0.196116f;	val_dir[15073*3 + 1] = 0.784465f;	val_dir[15073*3 + 2] = -0.588348f;
+ 	val_dir[15074*3 + 0] = -0.169080f;	val_dir[15074*3 + 1] = 0.797092f;	val_dir[15074*3 + 2] = -0.579703f;
+ 	val_dir[15075*3 + 0] = -0.142695f;	val_dir[15075*3 + 1] = 0.808608f;	val_dir[15075*3 + 2] = -0.570782f;
+ 	val_dir[15076*3 + 0] = -0.117009f;	val_dir[15076*3 + 1] = 0.819064f;	val_dir[15076*3 + 2] = -0.561644f;
+ 	val_dir[15077*3 + 0] = -0.092057f;	val_dir[15077*3 + 1] = 0.828517f;	val_dir[15077*3 + 2] = -0.552345f;
+ 	val_dir[15078*3 + 0] = -0.067867f;	val_dir[15078*3 + 1] = 0.837027f;	val_dir[15078*3 + 2] = -0.542936f;
+ 	val_dir[15079*3 + 0] = -0.044455f;	val_dir[15079*3 + 1] = 0.844653f;	val_dir[15079*3 + 2] = -0.533465f;
+ 	val_dir[15080*3 + 0] = -0.021832f;	val_dir[15080*3 + 1] = 0.851455f;	val_dir[15080*3 + 2] = -0.523973f;
+ 	val_dir[15081*3 + 0] = 0.0f;	val_dir[15081*3 + 1] = 0.857493f;	val_dir[15081*3 + 2] = -0.514496f;
+ 	val_dir[15082*3 + 0] = 0.021487f;	val_dir[15082*3 + 1] = 0.880957f;	val_dir[15082*3 + 2] = -0.472709f;
+ 	val_dir[15083*3 + 0] = 0.042954f;	val_dir[15083*3 + 1] = 0.902027f;	val_dir[15083*3 + 2] = -0.429537f;
+ 	val_dir[15084*3 + 0] = 0.064223f;	val_dir[15084*3 + 1] = 0.920537f;	val_dir[15084*3 + 2] = -0.385341f;
+ 	val_dir[15085*3 + 0] = 0.085126f;	val_dir[15085*3 + 1] = 0.936382f;	val_dir[15085*3 + 2] = -0.340503f;
+ 	val_dir[15086*3 + 0] = 0.105503f;	val_dir[15086*3 + 1] = 0.949528f;	val_dir[15086*3 + 2] = -0.295409f;
+ 	val_dir[15087*3 + 0] = 0.125218f;	val_dir[15087*3 + 1] = 0.960001f;	val_dir[15087*3 + 2] = -0.250435f;
+ 	val_dir[15088*3 + 0] = 0.144154f;	val_dir[15088*3 + 1] = 0.967890f;	val_dir[15088*3 + 2] = -0.205934f;
+ 	val_dir[15089*3 + 0] = 0.162221f;	val_dir[15089*3 + 1] = 0.973329f;	val_dir[15089*3 + 2] = -0.162221f;
+ 	val_dir[15090*3 + 0] = 0.179355f;	val_dir[15090*3 + 1] = 0.976491f;	val_dir[15090*3 + 2] = -0.119570f;
+ 	val_dir[15091*3 + 0] = 0.195515f;	val_dir[15091*3 + 1] = 0.977577f;	val_dir[15091*3 + 2] = -0.078206f;
+ 	val_dir[15092*3 + 0] = 0.210683f;	val_dir[15092*3 + 1] = 0.976804f;	val_dir[15092*3 + 2] = -0.038306f;
+ 	val_dir[15093*3 + 0] = 0.224860f;	val_dir[15093*3 + 1] = 0.974391f;	val_dir[15093*3 + 2] = 0.0f;
+ 	val_dir[15094*3 + 0] = -0.978177f;	val_dir[15094*3 + 1] = -0.206922f;	val_dir[15094*3 + 2] = -0.018811f;
+ 	val_dir[15095*3 + 0] = -0.979683f;	val_dir[15095*3 + 1] = -0.192095f;	val_dir[15095*3 + 2] = -0.057628f;
+ 	val_dir[15096*3 + 0] = -0.979451f;	val_dir[15096*3 + 1] = -0.176301f;	val_dir[15096*3 + 2] = -0.097945f;
+ 	val_dir[15097*3 + 0] = -0.977267f;	val_dir[15097*3 + 1] = -0.159554f;	val_dir[15097*3 + 2] = -0.139610f;
+ 	val_dir[15098*3 + 0] = -0.972929f;	val_dir[15098*3 + 1] = -0.141885f;	val_dir[15098*3 + 2] = -0.182424f;
+ 	val_dir[15099*3 + 0] = -0.966252f;	val_dir[15099*3 + 1] = -0.123351f;	val_dir[15099*3 + 2] = -0.226144f;
+ 	val_dir[15100*3 + 0] = -0.957088f;	val_dir[15100*3 + 1] = -0.104031f;	val_dir[15100*3 + 2] = -0.270481f;
+ 	val_dir[15101*3 + 0] = -0.945328f;	val_dir[15101*3 + 1] = -0.084029f;	val_dir[15101*3 + 2] = -0.315109f;
+ 	val_dir[15102*3 + 0] = -0.930917f;	val_dir[15102*3 + 1] = -0.063472f;	val_dir[15102*3 + 2] = -0.359673f;
+ 	val_dir[15103*3 + 0] = -0.913860f;	val_dir[15103*3 + 1] = -0.042505f;	val_dir[15103*3 + 2] = -0.403799f;
+ 	val_dir[15104*3 + 0] = -0.894224f;	val_dir[15104*3 + 1] = -0.021291f;	val_dir[15104*3 + 2] = -0.447112f;
+ 	val_dir[15105*3 + 0] = -0.872143f;	val_dir[15105*3 + 1] = 0.0f;	val_dir[15105*3 + 2] = -0.489251f;
+ 	val_dir[15106*3 + 0] = -0.866703f;	val_dir[15106*3 + 1] = 0.021668f;	val_dir[15106*3 + 2] = -0.498354f;
+ 	val_dir[15107*3 + 0] = -0.860527f;	val_dir[15107*3 + 1] = 0.044130f;	val_dir[15107*3 + 2] = -0.507490f;
+ 	val_dir[15108*3 + 0] = -0.853556f;	val_dir[15108*3 + 1] = 0.067386f;	val_dir[15108*3 + 2] = -0.516626f;
+ 	val_dir[15109*3 + 0] = -0.845728f;	val_dir[15109*3 + 1] = 0.091430f;	val_dir[15109*3 + 2] = -0.525723f;
+ 	val_dir[15110*3 + 0] = -0.836983f;	val_dir[15110*3 + 1] = 0.116248f;	val_dir[15110*3 + 2] = -0.534739f;
+ 	val_dir[15111*3 + 0] = -0.827259f;	val_dir[15111*3 + 1] = 0.141816f;	val_dir[15111*3 + 2] = -0.543627f;
+ 	val_dir[15112*3 + 0] = -0.816497f;	val_dir[15112*3 + 1] = 0.168102f;	val_dir[15112*3 + 2] = -0.552336f;
+ 	val_dir[15113*3 + 0] = -0.804639f;	val_dir[15113*3 + 1] = 0.195064f;	val_dir[15113*3 + 2] = -0.560809f;
+ 	val_dir[15114*3 + 0] = -0.791633f;	val_dir[15114*3 + 1] = 0.222647f;	val_dir[15114*3 + 2] = -0.568986f;
+ 	val_dir[15115*3 + 0] = -0.777433f;	val_dir[15115*3 + 1] = 0.250785f;	val_dir[15115*3 + 2] = -0.576805f;
+ 	val_dir[15116*3 + 0] = -0.762001f;	val_dir[15116*3 + 1] = 0.27940f;	val_dir[15116*3 + 2] = -0.584201f;
+ 	val_dir[15117*3 + 0] = -0.745307f;	val_dir[15117*3 + 1] = 0.308403f;	val_dir[15117*3 + 2] = -0.591105f;
+ 	val_dir[15118*3 + 0] = -0.727334f;	val_dir[15118*3 + 1] = 0.337691f;	val_dir[15118*3 + 2] = -0.597453f;
+ 	val_dir[15119*3 + 0] = -0.708079f;	val_dir[15119*3 + 1] = 0.367152f;	val_dir[15119*3 + 2] = -0.603178f;
+ 	val_dir[15120*3 + 0] = -0.687552f;	val_dir[15120*3 + 1] = 0.396664f;	val_dir[15120*3 + 2] = -0.608219f;
+ 	val_dir[15121*3 + 0] = -0.665780f;	val_dir[15121*3 + 1] = 0.426099f;	val_dir[15121*3 + 2] = -0.612517f;
+ 	val_dir[15122*3 + 0] = -0.642806f;	val_dir[15122*3 + 1] = 0.455321f;	val_dir[15122*3 + 2] = -0.616022f;
+ 	val_dir[15123*3 + 0] = -0.618691f;	val_dir[15123*3 + 1] = 0.484193f;	val_dir[15123*3 + 2] = -0.618691f;
+ 	val_dir[15124*3 + 0] = -0.593512f;	val_dir[15124*3 + 1] = 0.512578f;	val_dir[15124*3 + 2] = -0.620490f;
+ 	val_dir[15125*3 + 0] = -0.567360f;	val_dir[15125*3 + 1] = 0.540343f;	val_dir[15125*3 + 2] = -0.621395f;
+ 	val_dir[15126*3 + 0] = -0.540343f;	val_dir[15126*3 + 1] = 0.567360f;	val_dir[15126*3 + 2] = -0.621395f;
+ 	val_dir[15127*3 + 0] = -0.512578f;	val_dir[15127*3 + 1] = 0.593512f;	val_dir[15127*3 + 2] = -0.620490f;
+ 	val_dir[15128*3 + 0] = -0.484193f;	val_dir[15128*3 + 1] = 0.618691f;	val_dir[15128*3 + 2] = -0.618691f;
+ 	val_dir[15129*3 + 0] = -0.455321f;	val_dir[15129*3 + 1] = 0.642806f;	val_dir[15129*3 + 2] = -0.616022f;
+ 	val_dir[15130*3 + 0] = -0.426099f;	val_dir[15130*3 + 1] = 0.665780f;	val_dir[15130*3 + 2] = -0.612517f;
+ 	val_dir[15131*3 + 0] = -0.396664f;	val_dir[15131*3 + 1] = 0.687552f;	val_dir[15131*3 + 2] = -0.608219f;
+ 	val_dir[15132*3 + 0] = -0.367152f;	val_dir[15132*3 + 1] = 0.708079f;	val_dir[15132*3 + 2] = -0.603178f;
+ 	val_dir[15133*3 + 0] = -0.337691f;	val_dir[15133*3 + 1] = 0.727334f;	val_dir[15133*3 + 2] = -0.597453f;
+ 	val_dir[15134*3 + 0] = -0.308403f;	val_dir[15134*3 + 1] = 0.745307f;	val_dir[15134*3 + 2] = -0.591105f;
+ 	val_dir[15135*3 + 0] = -0.27940f;	val_dir[15135*3 + 1] = 0.762001f;	val_dir[15135*3 + 2] = -0.584201f;
+ 	val_dir[15136*3 + 0] = -0.250785f;	val_dir[15136*3 + 1] = 0.777433f;	val_dir[15136*3 + 2] = -0.576805f;
+ 	val_dir[15137*3 + 0] = -0.222647f;	val_dir[15137*3 + 1] = 0.791633f;	val_dir[15137*3 + 2] = -0.568986f;
+ 	val_dir[15138*3 + 0] = -0.195064f;	val_dir[15138*3 + 1] = 0.804639f;	val_dir[15138*3 + 2] = -0.560809f;
+ 	val_dir[15139*3 + 0] = -0.168102f;	val_dir[15139*3 + 1] = 0.816497f;	val_dir[15139*3 + 2] = -0.552336f;
+ 	val_dir[15140*3 + 0] = -0.141816f;	val_dir[15140*3 + 1] = 0.827259f;	val_dir[15140*3 + 2] = -0.543627f;
+ 	val_dir[15141*3 + 0] = -0.116248f;	val_dir[15141*3 + 1] = 0.836983f;	val_dir[15141*3 + 2] = -0.534739f;
+ 	val_dir[15142*3 + 0] = -0.091430f;	val_dir[15142*3 + 1] = 0.845728f;	val_dir[15142*3 + 2] = -0.525723f;
+ 	val_dir[15143*3 + 0] = -0.067386f;	val_dir[15143*3 + 1] = 0.853556f;	val_dir[15143*3 + 2] = -0.516626f;
+ 	val_dir[15144*3 + 0] = -0.044130f;	val_dir[15144*3 + 1] = 0.860527f;	val_dir[15144*3 + 2] = -0.507490f;
+ 	val_dir[15145*3 + 0] = -0.021668f;	val_dir[15145*3 + 1] = 0.866703f;	val_dir[15145*3 + 2] = -0.498354f;
+ 	val_dir[15146*3 + 0] = 0.0f;	val_dir[15146*3 + 1] = 0.872143f;	val_dir[15146*3 + 2] = -0.489251f;
+ 	val_dir[15147*3 + 0] = 0.021291f;	val_dir[15147*3 + 1] = 0.894224f;	val_dir[15147*3 + 2] = -0.447112f;
+ 	val_dir[15148*3 + 0] = 0.042505f;	val_dir[15148*3 + 1] = 0.913860f;	val_dir[15148*3 + 2] = -0.403799f;
+ 	val_dir[15149*3 + 0] = 0.063472f;	val_dir[15149*3 + 1] = 0.930917f;	val_dir[15149*3 + 2] = -0.359673f;
+ 	val_dir[15150*3 + 0] = 0.084029f;	val_dir[15150*3 + 1] = 0.945328f;	val_dir[15150*3 + 2] = -0.315109f;
+ 	val_dir[15151*3 + 0] = 0.104031f;	val_dir[15151*3 + 1] = 0.957088f;	val_dir[15151*3 + 2] = -0.270481f;
+ 	val_dir[15152*3 + 0] = 0.123351f;	val_dir[15152*3 + 1] = 0.966252f;	val_dir[15152*3 + 2] = -0.226144f;
+ 	val_dir[15153*3 + 0] = 0.141885f;	val_dir[15153*3 + 1] = 0.972929f;	val_dir[15153*3 + 2] = -0.182424f;
+ 	val_dir[15154*3 + 0] = 0.159554f;	val_dir[15154*3 + 1] = 0.977267f;	val_dir[15154*3 + 2] = -0.139610f;
+ 	val_dir[15155*3 + 0] = 0.176301f;	val_dir[15155*3 + 1] = 0.979451f;	val_dir[15155*3 + 2] = -0.097945f;
+ 	val_dir[15156*3 + 0] = 0.192095f;	val_dir[15156*3 + 1] = 0.979683f;	val_dir[15156*3 + 2] = -0.057628f;
+ 	val_dir[15157*3 + 0] = 0.206922f;	val_dir[15157*3 + 1] = 0.978177f;	val_dir[15157*3 + 2] = -0.018811f;
+ 	val_dir[15158*3 + 0] = -0.979134f;	val_dir[15158*3 + 1] = -0.203216f;	val_dir[15158*3 + 2] = 0.0f;
+ 	val_dir[15159*3 + 0] = -0.981307f;	val_dir[15159*3 + 1] = -0.188713f;	val_dir[15159*3 + 2] = -0.037743f;
+ 	val_dir[15160*3 + 0] = -0.981859f;	val_dir[15160*3 + 1] = -0.173269f;	val_dir[15160*3 + 2] = -0.077009f;
+ 	val_dir[15161*3 + 0] = -0.980581f;	val_dir[15161*3 + 1] = -0.156893f;	val_dir[15161*3 + 2] = -0.117670f;
+ 	val_dir[15162*3 + 0] = -0.977267f;	val_dir[15162*3 + 1] = -0.139610f;	val_dir[15162*3 + 2] = -0.159554f;
+ 	val_dir[15163*3 + 0] = -0.971732f;	val_dir[15163*3 + 1] = -0.121466f;	val_dir[15163*3 + 2] = -0.202444f;
+ 	val_dir[15164*3 + 0] = -0.963811f;	val_dir[15164*3 + 1] = -0.102533f;	val_dir[15164*3 + 2] = -0.246079f;
+ 	val_dir[15165*3 + 0] = -0.953381f;	val_dir[15165*3 + 1] = -0.082903f;	val_dir[15165*3 + 2] = -0.290159f;
+ 	val_dir[15166*3 + 0] = -0.940361f;	val_dir[15166*3 + 1] = -0.062691f;	val_dir[15166*3 + 2] = -0.334351f;
+ 	val_dir[15167*3 + 0] = -0.924729f;	val_dir[15167*3 + 1] = -0.042033f;	val_dir[15167*3 + 2] = -0.378298f;
+ 	val_dir[15168*3 + 0] = -0.906520f;	val_dir[15168*3 + 1] = -0.021082f;	val_dir[15168*3 + 2] = -0.421637f;
+ 	val_dir[15169*3 + 0] = -0.885832f;	val_dir[15169*3 + 1] = 0.0f;	val_dir[15169*3 + 2] = -0.464007f;
+ 	val_dir[15170*3 + 0] = -0.880957f;	val_dir[15170*3 + 1] = 0.021487f;	val_dir[15170*3 + 2] = -0.472709f;
+ 	val_dir[15171*3 + 0] = -0.875376f;	val_dir[15171*3 + 1] = 0.043769f;	val_dir[15171*3 + 2] = -0.481457f;
+ 	val_dir[15172*3 + 0] = -0.869030f;	val_dir[15172*3 + 1] = 0.066848f;	val_dir[15172*3 + 2] = -0.490222f;
+ 	val_dir[15173*3 + 0] = -0.861857f;	val_dir[15173*3 + 1] = 0.090722f;	val_dir[15173*3 + 2] = -0.498970f;
+ 	val_dir[15174*3 + 0] = -0.853796f;	val_dir[15174*3 + 1] = 0.115378f;	val_dir[15174*3 + 2] = -0.507662f;
+ 	val_dir[15175*3 + 0] = -0.844782f;	val_dir[15175*3 + 1] = 0.140797f;	val_dir[15175*3 + 2] = -0.516256f;
+ 	val_dir[15176*3 + 0] = -0.834754f;	val_dir[15176*3 + 1] = 0.166951f;	val_dir[15176*3 + 2] = -0.524703f;
+ 	val_dir[15177*3 + 0] = -0.823653f;	val_dir[15177*3 + 1] = 0.193801f;	val_dir[15177*3 + 2] = -0.532952f;
+ 	val_dir[15178*3 + 0] = -0.811421f;	val_dir[15178*3 + 1] = 0.221297f;	val_dir[15178*3 + 2] = -0.540947f;
+ 	val_dir[15179*3 + 0] = -0.798007f;	val_dir[15179*3 + 1] = 0.249377f;	val_dir[15179*3 + 2] = -0.548630f;
+ 	val_dir[15180*3 + 0] = -0.783368f;	val_dir[15180*3 + 1] = 0.277969f;	val_dir[15180*3 + 2] = -0.555939f;
+ 	val_dir[15181*3 + 0] = -0.767467f;	val_dir[15181*3 + 1] = 0.306987f;	val_dir[15181*3 + 2] = -0.562809f;
+ 	val_dir[15182*3 + 0] = -0.750279f;	val_dir[15182*3 + 1] = 0.336332f;	val_dir[15182*3 + 2] = -0.569177f;
+ 	val_dir[15183*3 + 0] = -0.731792f;	val_dir[15183*3 + 1] = 0.365896f;	val_dir[15183*3 + 2] = -0.574979f;
+ 	val_dir[15184*3 + 0] = -0.712007f;	val_dir[15184*3 + 1] = 0.395559f;	val_dir[15184*3 + 2] = -0.580154f;
+ 	val_dir[15185*3 + 0] = -0.690942f;	val_dir[15185*3 + 1] = 0.425195f;	val_dir[15185*3 + 2] = -0.584643f;
+ 	val_dir[15186*3 + 0] = -0.668631f;	val_dir[15186*3 + 1] = 0.454669f;	val_dir[15186*3 + 2] = -0.588395f;
+ 	val_dir[15187*3 + 0] = -0.645124f;	val_dir[15187*3 + 1] = 0.483843f;	val_dir[15187*3 + 2] = -0.591364f;
+ 	val_dir[15188*3 + 0] = -0.620490f;	val_dir[15188*3 + 1] = 0.512578f;	val_dir[15188*3 + 2] = -0.593512f;
+ 	val_dir[15189*3 + 0] = -0.594812f;	val_dir[15189*3 + 1] = 0.540738f;	val_dir[15189*3 + 2] = -0.594812f;
+ 	val_dir[15190*3 + 0] = -0.568190f;	val_dir[15190*3 + 1] = 0.568190f;	val_dir[15190*3 + 2] = -0.595247f;
+ 	val_dir[15191*3 + 0] = -0.540738f;	val_dir[15191*3 + 1] = 0.594812f;	val_dir[15191*3 + 2] = -0.594812f;
+ 	val_dir[15192*3 + 0] = -0.512578f;	val_dir[15192*3 + 1] = 0.620490f;	val_dir[15192*3 + 2] = -0.593512f;
+ 	val_dir[15193*3 + 0] = -0.483843f;	val_dir[15193*3 + 1] = 0.645124f;	val_dir[15193*3 + 2] = -0.591364f;
+ 	val_dir[15194*3 + 0] = -0.454669f;	val_dir[15194*3 + 1] = 0.668631f;	val_dir[15194*3 + 2] = -0.588395f;
+ 	val_dir[15195*3 + 0] = -0.425195f;	val_dir[15195*3 + 1] = 0.690942f;	val_dir[15195*3 + 2] = -0.584643f;
+ 	val_dir[15196*3 + 0] = -0.395559f;	val_dir[15196*3 + 1] = 0.712007f;	val_dir[15196*3 + 2] = -0.580154f;
+ 	val_dir[15197*3 + 0] = -0.365896f;	val_dir[15197*3 + 1] = 0.731792f;	val_dir[15197*3 + 2] = -0.574979f;
+ 	val_dir[15198*3 + 0] = -0.336332f;	val_dir[15198*3 + 1] = 0.750279f;	val_dir[15198*3 + 2] = -0.569177f;
+ 	val_dir[15199*3 + 0] = -0.306987f;	val_dir[15199*3 + 1] = 0.767467f;	val_dir[15199*3 + 2] = -0.562809f;
+ 	val_dir[15200*3 + 0] = -0.277969f;	val_dir[15200*3 + 1] = 0.783368f;	val_dir[15200*3 + 2] = -0.555939f;
+ 	val_dir[15201*3 + 0] = -0.249377f;	val_dir[15201*3 + 1] = 0.798007f;	val_dir[15201*3 + 2] = -0.548630f;
+ 	val_dir[15202*3 + 0] = -0.221297f;	val_dir[15202*3 + 1] = 0.811421f;	val_dir[15202*3 + 2] = -0.540947f;
+ 	val_dir[15203*3 + 0] = -0.193801f;	val_dir[15203*3 + 1] = 0.823653f;	val_dir[15203*3 + 2] = -0.532952f;
+ 	val_dir[15204*3 + 0] = -0.166951f;	val_dir[15204*3 + 1] = 0.834754f;	val_dir[15204*3 + 2] = -0.524703f;
+ 	val_dir[15205*3 + 0] = -0.140797f;	val_dir[15205*3 + 1] = 0.844782f;	val_dir[15205*3 + 2] = -0.516256f;
+ 	val_dir[15206*3 + 0] = -0.115378f;	val_dir[15206*3 + 1] = 0.853796f;	val_dir[15206*3 + 2] = -0.507662f;
+ 	val_dir[15207*3 + 0] = -0.090722f;	val_dir[15207*3 + 1] = 0.861857f;	val_dir[15207*3 + 2] = -0.498970f;
+ 	val_dir[15208*3 + 0] = -0.066848f;	val_dir[15208*3 + 1] = 0.869030f;	val_dir[15208*3 + 2] = -0.490222f;
+ 	val_dir[15209*3 + 0] = -0.043769f;	val_dir[15209*3 + 1] = 0.875376f;	val_dir[15209*3 + 2] = -0.481457f;
+ 	val_dir[15210*3 + 0] = -0.021487f;	val_dir[15210*3 + 1] = 0.880957f;	val_dir[15210*3 + 2] = -0.472709f;
+ 	val_dir[15211*3 + 0] = 0.0f;	val_dir[15211*3 + 1] = 0.885832f;	val_dir[15211*3 + 2] = -0.464007f;
+ 	val_dir[15212*3 + 0] = 0.021082f;	val_dir[15212*3 + 1] = 0.906520f;	val_dir[15212*3 + 2] = -0.421637f;
+ 	val_dir[15213*3 + 0] = 0.042033f;	val_dir[15213*3 + 1] = 0.924729f;	val_dir[15213*3 + 2] = -0.378298f;
+ 	val_dir[15214*3 + 0] = 0.062691f;	val_dir[15214*3 + 1] = 0.940361f;	val_dir[15214*3 + 2] = -0.334351f;
+ 	val_dir[15215*3 + 0] = 0.082903f;	val_dir[15215*3 + 1] = 0.953381f;	val_dir[15215*3 + 2] = -0.290159f;
+ 	val_dir[15216*3 + 0] = 0.102533f;	val_dir[15216*3 + 1] = 0.963811f;	val_dir[15216*3 + 2] = -0.246079f;
+ 	val_dir[15217*3 + 0] = 0.121466f;	val_dir[15217*3 + 1] = 0.971732f;	val_dir[15217*3 + 2] = -0.202444f;
+ 	val_dir[15218*3 + 0] = 0.139610f;	val_dir[15218*3 + 1] = 0.977267f;	val_dir[15218*3 + 2] = -0.159554f;
+ 	val_dir[15219*3 + 0] = 0.156893f;	val_dir[15219*3 + 1] = 0.980581f;	val_dir[15219*3 + 2] = -0.117670f;
+ 	val_dir[15220*3 + 0] = 0.173269f;	val_dir[15220*3 + 1] = 0.981859f;	val_dir[15220*3 + 2] = -0.077009f;
+ 	val_dir[15221*3 + 0] = 0.188713f;	val_dir[15221*3 + 1] = 0.981307f;	val_dir[15221*3 + 2] = -0.037743f;
+ 	val_dir[15222*3 + 0] = 0.203216f;	val_dir[15222*3 + 1] = 0.979134f;	val_dir[15222*3 + 2] = 0.0f;
+ 	val_dir[15223*3 + 0] = -0.982493f;	val_dir[15223*3 + 1] = -0.185376f;	val_dir[15223*3 + 2] = -0.018538f;
+ 	val_dir[15224*3 + 0] = -0.983762f;	val_dir[15224*3 + 1] = -0.170267f;	val_dir[15224*3 + 2] = -0.056756f;
+ 	val_dir[15225*3 + 0] = -0.983318f;	val_dir[15225*3 + 1] = -0.154246f;	val_dir[15225*3 + 2] = -0.096404f;
+ 	val_dir[15226*3 + 0] = -0.980958f;	val_dir[15226*3 + 1] = -0.137334f;	val_dir[15226*3 + 2] = -0.137334f;
+ 	val_dir[15227*3 + 0] = -0.976491f;	val_dir[15227*3 + 1] = -0.119570f;	val_dir[15227*3 + 2] = -0.179355f;
+ 	val_dir[15228*3 + 0] = -0.969746f;	val_dir[15228*3 + 1] = -0.101015f;	val_dir[15228*3 + 2] = -0.222234f;
+ 	val_dir[15229*3 + 0] = -0.960585f;	val_dir[15229*3 + 1] = -0.081752f;	val_dir[15229*3 + 2] = -0.265694f;
+ 	val_dir[15230*3 + 0] = -0.948908f;	val_dir[15230*3 + 1] = -0.061885f;	val_dir[15230*3 + 2] = -0.309426f;
+ 	val_dir[15231*3 + 0] = -0.934665f;	val_dir[15231*3 + 1] = -0.041541f;	val_dir[15231*3 + 2] = -0.353096f;
+ 	val_dir[15232*3 + 0] = -0.917863f;	val_dir[15232*3 + 1] = -0.020861f;	val_dir[15232*3 + 2] = -0.396350f;
+ 	val_dir[15233*3 + 0] = -0.898567f;	val_dir[15233*3 + 1] = 0.0f;	val_dir[15233*3 + 2] = -0.438835f;
+ 	val_dir[15234*3 + 0] = -0.894224f;	val_dir[15234*3 + 1] = 0.021291f;	val_dir[15234*3 + 2] = -0.447112f;
+ 	val_dir[15235*3 + 0] = -0.889206f;	val_dir[15235*3 + 1] = 0.043376f;	val_dir[15235*3 + 2] = -0.455447f;
+ 	val_dir[15236*3 + 0] = -0.883452f;	val_dir[15236*3 + 1] = 0.066259f;	val_dir[15236*3 + 2] = -0.463812f;
+ 	val_dir[15237*3 + 0] = -0.876903f;	val_dir[15237*3 + 1] = 0.089939f;	val_dir[15237*3 + 2] = -0.472178f;
+ 	val_dir[15238*3 + 0] = -0.869495f;	val_dir[15238*3 + 1] = 0.114407f;	val_dir[15238*3 + 2] = -0.480510f;
+ 	val_dir[15239*3 + 0] = -0.861164f;	val_dir[15239*3 + 1] = 0.139648f;	val_dir[15239*3 + 2] = -0.488769f;
+ 	val_dir[15240*3 + 0] = -0.851847f;	val_dir[15240*3 + 1] = 0.165637f;	val_dir[15240*3 + 2] = -0.496911f;
+ 	val_dir[15241*3 + 0] = -0.841482f;	val_dir[15241*3 + 1] = 0.192339f;	val_dir[15241*3 + 2] = -0.504889f;
+ 	val_dir[15242*3 + 0] = -0.830009f;	val_dir[15242*3 + 1] = 0.219708f;	val_dir[15242*3 + 2] = -0.512653f;
+ 	val_dir[15243*3 + 0] = -0.817373f;	val_dir[15243*3 + 1] = 0.247689f;	val_dir[15243*3 + 2] = -0.520146f;
+ 	val_dir[15244*3 + 0] = -0.803523f;	val_dir[15244*3 + 1] = 0.276211f;	val_dir[15244*3 + 2] = -0.527312f;
+ 	val_dir[15245*3 + 0] = -0.788419f;	val_dir[15245*3 + 1] = 0.305194f;	val_dir[15245*3 + 2] = -0.534090f;
+ 	val_dir[15246*3 + 0] = -0.772027f;	val_dir[15246*3 + 1] = 0.334545f;	val_dir[15246*3 + 2] = -0.540419f;
+ 	val_dir[15247*3 + 0] = -0.754329f;	val_dir[15247*3 + 1] = 0.364159f;	val_dir[15247*3 + 2] = -0.546238f;
+ 	val_dir[15248*3 + 0] = -0.735316f;	val_dir[15248*3 + 1] = 0.393919f;	val_dir[15248*3 + 2] = -0.551487f;
+ 	val_dir[15249*3 + 0] = -0.714997f;	val_dir[15249*3 + 1] = 0.423702f;	val_dir[15249*3 + 2] = -0.556108f;
+ 	val_dir[15250*3 + 0] = -0.693395f;	val_dir[15250*3 + 1] = 0.453374f;	val_dir[15250*3 + 2] = -0.560050f;
+ 	val_dir[15251*3 + 0] = -0.670552f;	val_dir[15251*3 + 1] = 0.482798f;	val_dir[15251*3 + 2] = -0.563264f;
+ 	val_dir[15252*3 + 0] = -0.646527f;	val_dir[15252*3 + 1] = 0.511834f;	val_dir[15252*3 + 2] = -0.565711f;
+ 	val_dir[15253*3 + 0] = -0.621395f;	val_dir[15253*3 + 1] = 0.540343f;	val_dir[15253*3 + 2] = -0.567360f;
+ 	val_dir[15254*3 + 0] = -0.595247f;	val_dir[15254*3 + 1] = 0.568190f;	val_dir[15254*3 + 2] = -0.568190f;
+ 	val_dir[15255*3 + 0] = -0.568190f;	val_dir[15255*3 + 1] = 0.595247f;	val_dir[15255*3 + 2] = -0.568190f;
+ 	val_dir[15256*3 + 0] = -0.540343f;	val_dir[15256*3 + 1] = 0.621395f;	val_dir[15256*3 + 2] = -0.567360f;
+ 	val_dir[15257*3 + 0] = -0.511834f;	val_dir[15257*3 + 1] = 0.646527f;	val_dir[15257*3 + 2] = -0.565711f;
+ 	val_dir[15258*3 + 0] = -0.482798f;	val_dir[15258*3 + 1] = 0.670552f;	val_dir[15258*3 + 2] = -0.563264f;
+ 	val_dir[15259*3 + 0] = -0.453374f;	val_dir[15259*3 + 1] = 0.693395f;	val_dir[15259*3 + 2] = -0.560050f;
+ 	val_dir[15260*3 + 0] = -0.423702f;	val_dir[15260*3 + 1] = 0.714997f;	val_dir[15260*3 + 2] = -0.556108f;
+ 	val_dir[15261*3 + 0] = -0.393919f;	val_dir[15261*3 + 1] = 0.735316f;	val_dir[15261*3 + 2] = -0.551487f;
+ 	val_dir[15262*3 + 0] = -0.364159f;	val_dir[15262*3 + 1] = 0.754329f;	val_dir[15262*3 + 2] = -0.546238f;
+ 	val_dir[15263*3 + 0] = -0.334545f;	val_dir[15263*3 + 1] = 0.772027f;	val_dir[15263*3 + 2] = -0.540419f;
+ 	val_dir[15264*3 + 0] = -0.305194f;	val_dir[15264*3 + 1] = 0.788419f;	val_dir[15264*3 + 2] = -0.534090f;
+ 	val_dir[15265*3 + 0] = -0.276211f;	val_dir[15265*3 + 1] = 0.803523f;	val_dir[15265*3 + 2] = -0.527312f;
+ 	val_dir[15266*3 + 0] = -0.247689f;	val_dir[15266*3 + 1] = 0.817373f;	val_dir[15266*3 + 2] = -0.520146f;
+ 	val_dir[15267*3 + 0] = -0.219708f;	val_dir[15267*3 + 1] = 0.830009f;	val_dir[15267*3 + 2] = -0.512653f;
+ 	val_dir[15268*3 + 0] = -0.192339f;	val_dir[15268*3 + 1] = 0.841482f;	val_dir[15268*3 + 2] = -0.504889f;
+ 	val_dir[15269*3 + 0] = -0.165637f;	val_dir[15269*3 + 1] = 0.851847f;	val_dir[15269*3 + 2] = -0.496911f;
+ 	val_dir[15270*3 + 0] = -0.139648f;	val_dir[15270*3 + 1] = 0.861164f;	val_dir[15270*3 + 2] = -0.488769f;
+ 	val_dir[15271*3 + 0] = -0.114407f;	val_dir[15271*3 + 1] = 0.869495f;	val_dir[15271*3 + 2] = -0.480510f;
+ 	val_dir[15272*3 + 0] = -0.089939f;	val_dir[15272*3 + 1] = 0.876903f;	val_dir[15272*3 + 2] = -0.472178f;
+ 	val_dir[15273*3 + 0] = -0.066259f;	val_dir[15273*3 + 1] = 0.883452f;	val_dir[15273*3 + 2] = -0.463812f;
+ 	val_dir[15274*3 + 0] = -0.043376f;	val_dir[15274*3 + 1] = 0.889206f;	val_dir[15274*3 + 2] = -0.455447f;
+ 	val_dir[15275*3 + 0] = -0.021291f;	val_dir[15275*3 + 1] = 0.894224f;	val_dir[15275*3 + 2] = -0.447112f;
+ 	val_dir[15276*3 + 0] = 0.0f;	val_dir[15276*3 + 1] = 0.898567f;	val_dir[15276*3 + 2] = -0.438835f;
+ 	val_dir[15277*3 + 0] = 0.020861f;	val_dir[15277*3 + 1] = 0.917863f;	val_dir[15277*3 + 2] = -0.396350f;
+ 	val_dir[15278*3 + 0] = 0.041541f;	val_dir[15278*3 + 1] = 0.934665f;	val_dir[15278*3 + 2] = -0.353096f;
+ 	val_dir[15279*3 + 0] = 0.061885f;	val_dir[15279*3 + 1] = 0.948908f;	val_dir[15279*3 + 2] = -0.309426f;
+ 	val_dir[15280*3 + 0] = 0.081752f;	val_dir[15280*3 + 1] = 0.960585f;	val_dir[15280*3 + 2] = -0.265694f;
+ 	val_dir[15281*3 + 0] = 0.101015f;	val_dir[15281*3 + 1] = 0.969746f;	val_dir[15281*3 + 2] = -0.222234f;
+ 	val_dir[15282*3 + 0] = 0.119570f;	val_dir[15282*3 + 1] = 0.976491f;	val_dir[15282*3 + 2] = -0.179355f;
+ 	val_dir[15283*3 + 0] = 0.137334f;	val_dir[15283*3 + 1] = 0.980958f;	val_dir[15283*3 + 2] = -0.137334f;
+ 	val_dir[15284*3 + 0] = 0.154246f;	val_dir[15284*3 + 1] = 0.983318f;	val_dir[15284*3 + 2] = -0.096404f;
+ 	val_dir[15285*3 + 0] = 0.170267f;	val_dir[15285*3 + 1] = 0.983762f;	val_dir[15285*3 + 2] = -0.056756f;
+ 	val_dir[15286*3 + 0] = 0.185376f;	val_dir[15286*3 + 1] = 0.982493f;	val_dir[15286*3 + 2] = -0.018538f;
+ 	val_dir[15287*3 + 0] = -0.983282f;	val_dir[15287*3 + 1] = -0.182089f;	val_dir[15287*3 + 2] = 0.0f;
+ 	val_dir[15288*3 + 0] = -0.985205f;	val_dir[15288*3 + 1] = -0.167299f;	val_dir[15288*3 + 2] = -0.037178f;
+ 	val_dir[15289*3 + 0] = -0.985527f;	val_dir[15289*3 + 1] = -0.151620f;	val_dir[15289*3 + 2] = -0.075810f;
+ 	val_dir[15290*3 + 0] = -0.984050f;	val_dir[15290*3 + 1] = -0.135066f;	val_dir[15290*3 + 2] = -0.115771f;
+ 	val_dir[15291*3 + 0] = -0.980581f;	val_dir[15291*3 + 1] = -0.117670f;	val_dir[15291*3 + 2] = -0.156893f;
+ 	val_dir[15292*3 + 0] = -0.974943f;	val_dir[15292*3 + 1] = -0.099484f;	val_dir[15292*3 + 2] = -0.198968f;
+ 	val_dir[15293*3 + 0] = -0.966988f;	val_dir[15293*3 + 1] = -0.080582f;	val_dir[15293*3 + 2] = -0.241747f;
+ 	val_dir[15294*3 + 0] = -0.956597f;	val_dir[15294*3 + 1] = -0.061059f;	val_dir[15294*3 + 2] = -0.284944f;
+ 	val_dir[15295*3 + 0] = -0.943701f;	val_dir[15295*3 + 1] = -0.041030f;	val_dir[15295*3 + 2] = -0.328244f;
+ 	val_dir[15296*3 + 0] = -0.928279f;	val_dir[15296*3 + 1] = -0.020628f;	val_dir[15296*3 + 2] = -0.371312f;
+ 	val_dir[15297*3 + 0] = -0.910366f;	val_dir[15297*3 + 1] = 0.0f;	val_dir[15297*3 + 2] = -0.413803f;
+ 	val_dir[15298*3 + 0] = -0.906520f;	val_dir[15298*3 + 1] = 0.021082f;	val_dir[15298*3 + 2] = -0.421637f;
+ 	val_dir[15299*3 + 0] = -0.902027f;	val_dir[15299*3 + 1] = 0.042954f;	val_dir[15299*3 + 2] = -0.429537f;
+ 	val_dir[15300*3 + 0] = -0.896831f;	val_dir[15300*3 + 1] = 0.065622f;	val_dir[15300*3 + 2] = -0.437479f;
+ 	val_dir[15301*3 + 0] = -0.890871f;	val_dir[15301*3 + 1] = 0.089087f;	val_dir[15301*3 + 2] = -0.445435f;
+ 	val_dir[15302*3 + 0] = -0.884083f;	val_dir[15302*3 + 1] = 0.113344f;	val_dir[15302*3 + 2] = -0.453376f;
+ 	val_dir[15303*3 + 0] = -0.876405f;	val_dir[15303*3 + 1] = 0.138380f;	val_dir[15303*3 + 2] = -0.461266f;
+ 	val_dir[15304*3 + 0] = -0.867770f;	val_dir[15304*3 + 1] = 0.164173f;	val_dir[15304*3 + 2] = -0.469065f;
+ 	val_dir[15305*3 + 0] = -0.858116f;	val_dir[15305*3 + 1] = 0.190693f;	val_dir[15305*3 + 2] = -0.476731f;
+ 	val_dir[15306*3 + 0] = -0.847381f;	val_dir[15306*3 + 1] = 0.217898f;	val_dir[15306*3 + 2] = -0.484217f;
+ 	val_dir[15307*3 + 0] = -0.835504f;	val_dir[15307*3 + 1] = 0.245737f;	val_dir[15307*3 + 2] = -0.491473f;
+ 	val_dir[15308*3 + 0] = -0.822434f;	val_dir[15308*3 + 1] = 0.274145f;	val_dir[15308*3 + 2] = -0.498445f;
+ 	val_dir[15309*3 + 0] = -0.808122f;	val_dir[15309*3 + 1] = 0.303046f;	val_dir[15309*3 + 2] = -0.505076f;
+ 	val_dir[15310*3 + 0] = -0.792530f;	val_dir[15310*3 + 1] = 0.332352f;	val_dir[15310*3 + 2] = -0.511310f;
+ 	val_dir[15311*3 + 0] = -0.775632f;	val_dir[15311*3 + 1] = 0.361961f;	val_dir[15311*3 + 2] = -0.517088f;
+ 	val_dir[15312*3 + 0] = -0.757410f;	val_dir[15312*3 + 1] = 0.391764f;	val_dir[15312*3 + 2] = -0.522352f;
+ 	val_dir[15313*3 + 0] = -0.737865f;	val_dir[15313*3 + 1] = 0.421637f;	val_dir[15313*3 + 2] = -0.527046f;
+ 	val_dir[15314*3 + 0] = -0.717011f;	val_dir[15314*3 + 1] = 0.451451f;	val_dir[15314*3 + 2] = -0.531119f;
+ 	val_dir[15315*3 + 0] = -0.694879f;	val_dir[15315*3 + 1] = 0.481070f;	val_dir[15315*3 + 2] = -0.534522f;
+ 	val_dir[15316*3 + 0] = -0.671519f;	val_dir[15316*3 + 1] = 0.510355f;	val_dir[15316*3 + 2] = -0.537215f;
+ 	val_dir[15317*3 + 0] = -0.646997f;	val_dir[15317*3 + 1] = 0.539164f;	val_dir[15317*3 + 2] = -0.539164f;
+ 	val_dir[15318*3 + 0] = -0.621395f;	val_dir[15318*3 + 1] = 0.567360f;	val_dir[15318*3 + 2] = -0.540343f;
+ 	val_dir[15319*3 + 0] = -0.594812f;	val_dir[15319*3 + 1] = 0.594812f;	val_dir[15319*3 + 2] = -0.540738f;
+ 	val_dir[15320*3 + 0] = -0.567360f;	val_dir[15320*3 + 1] = 0.621395f;	val_dir[15320*3 + 2] = -0.540343f;
+ 	val_dir[15321*3 + 0] = -0.539164f;	val_dir[15321*3 + 1] = 0.646997f;	val_dir[15321*3 + 2] = -0.539164f;
+ 	val_dir[15322*3 + 0] = -0.510355f;	val_dir[15322*3 + 1] = 0.671519f;	val_dir[15322*3 + 2] = -0.537215f;
+ 	val_dir[15323*3 + 0] = -0.481070f;	val_dir[15323*3 + 1] = 0.694879f;	val_dir[15323*3 + 2] = -0.534522f;
+ 	val_dir[15324*3 + 0] = -0.451451f;	val_dir[15324*3 + 1] = 0.717011f;	val_dir[15324*3 + 2] = -0.531119f;
+ 	val_dir[15325*3 + 0] = -0.421637f;	val_dir[15325*3 + 1] = 0.737865f;	val_dir[15325*3 + 2] = -0.527046f;
+ 	val_dir[15326*3 + 0] = -0.391764f;	val_dir[15326*3 + 1] = 0.757410f;	val_dir[15326*3 + 2] = -0.522352f;
+ 	val_dir[15327*3 + 0] = -0.361961f;	val_dir[15327*3 + 1] = 0.775632f;	val_dir[15327*3 + 2] = -0.517088f;
+ 	val_dir[15328*3 + 0] = -0.332352f;	val_dir[15328*3 + 1] = 0.792530f;	val_dir[15328*3 + 2] = -0.511310f;
+ 	val_dir[15329*3 + 0] = -0.303046f;	val_dir[15329*3 + 1] = 0.808122f;	val_dir[15329*3 + 2] = -0.505076f;
+ 	val_dir[15330*3 + 0] = -0.274145f;	val_dir[15330*3 + 1] = 0.822434f;	val_dir[15330*3 + 2] = -0.498445f;
+ 	val_dir[15331*3 + 0] = -0.245737f;	val_dir[15331*3 + 1] = 0.835504f;	val_dir[15331*3 + 2] = -0.491473f;
+ 	val_dir[15332*3 + 0] = -0.217898f;	val_dir[15332*3 + 1] = 0.847381f;	val_dir[15332*3 + 2] = -0.484217f;
+ 	val_dir[15333*3 + 0] = -0.190693f;	val_dir[15333*3 + 1] = 0.858116f;	val_dir[15333*3 + 2] = -0.476731f;
+ 	val_dir[15334*3 + 0] = -0.164173f;	val_dir[15334*3 + 1] = 0.867770f;	val_dir[15334*3 + 2] = -0.469065f;
+ 	val_dir[15335*3 + 0] = -0.138380f;	val_dir[15335*3 + 1] = 0.876405f;	val_dir[15335*3 + 2] = -0.461266f;
+ 	val_dir[15336*3 + 0] = -0.113344f;	val_dir[15336*3 + 1] = 0.884083f;	val_dir[15336*3 + 2] = -0.453376f;
+ 	val_dir[15337*3 + 0] = -0.089087f;	val_dir[15337*3 + 1] = 0.890871f;	val_dir[15337*3 + 2] = -0.445435f;
+ 	val_dir[15338*3 + 0] = -0.065622f;	val_dir[15338*3 + 1] = 0.896831f;	val_dir[15338*3 + 2] = -0.437479f;
+ 	val_dir[15339*3 + 0] = -0.042954f;	val_dir[15339*3 + 1] = 0.902027f;	val_dir[15339*3 + 2] = -0.429537f;
+ 	val_dir[15340*3 + 0] = -0.021082f;	val_dir[15340*3 + 1] = 0.906520f;	val_dir[15340*3 + 2] = -0.421637f;
+ 	val_dir[15341*3 + 0] = 0.0f;	val_dir[15341*3 + 1] = 0.910366f;	val_dir[15341*3 + 2] = -0.413803f;
+ 	val_dir[15342*3 + 0] = 0.020628f;	val_dir[15342*3 + 1] = 0.928279f;	val_dir[15342*3 + 2] = -0.371312f;
+ 	val_dir[15343*3 + 0] = 0.041030f;	val_dir[15343*3 + 1] = 0.943701f;	val_dir[15343*3 + 2] = -0.328244f;
+ 	val_dir[15344*3 + 0] = 0.061059f;	val_dir[15344*3 + 1] = 0.956597f;	val_dir[15344*3 + 2] = -0.284944f;
+ 	val_dir[15345*3 + 0] = 0.080582f;	val_dir[15345*3 + 1] = 0.966988f;	val_dir[15345*3 + 2] = -0.241747f;
+ 	val_dir[15346*3 + 0] = 0.099484f;	val_dir[15346*3 + 1] = 0.974943f;	val_dir[15346*3 + 2] = -0.198968f;
+ 	val_dir[15347*3 + 0] = 0.117670f;	val_dir[15347*3 + 1] = 0.980581f;	val_dir[15347*3 + 2] = -0.156893f;
+ 	val_dir[15348*3 + 0] = 0.135066f;	val_dir[15348*3 + 1] = 0.984050f;	val_dir[15348*3 + 2] = -0.115771f;
+ 	val_dir[15349*3 + 0] = 0.151620f;	val_dir[15349*3 + 1] = 0.985527f;	val_dir[15349*3 + 2] = -0.075810f;
+ 	val_dir[15350*3 + 0] = 0.167299f;	val_dir[15350*3 + 1] = 0.985205f;	val_dir[15350*3 + 2] = -0.037178f;
+ 	val_dir[15351*3 + 0] = 0.182089f;	val_dir[15351*3 + 1] = 0.983282f;	val_dir[15351*3 + 2] = 0.0f;
+ 	val_dir[15352*3 + 0] = -0.986229f;	val_dir[15352*3 + 1] = -0.164372f;	val_dir[15352*3 + 2] = -0.018264f;
+ 	val_dir[15353*3 + 0] = -0.987254f;	val_dir[15353*3 + 1] = -0.149019f;	val_dir[15353*3 + 2] = -0.055882f;
+ 	val_dir[15354*3 + 0] = -0.986591f;	val_dir[15354*3 + 1] = -0.132810f;	val_dir[15354*3 + 2] = -0.094865f;
+ 	val_dir[15355*3 + 0] = -0.984050f;	val_dir[15355*3 + 1] = -0.115771f;	val_dir[15355*3 + 2] = -0.135066f;
+ 	val_dir[15356*3 + 0] = -0.979451f;	val_dir[15356*3 + 1] = -0.097945f;	val_dir[15356*3 + 2] = -0.176301f;
+ 	val_dir[15357*3 + 0] = -0.972636f;	val_dir[15357*3 + 1] = -0.079399f;	val_dir[15357*3 + 2] = -0.218347f;
+ 	val_dir[15358*3 + 0] = -0.963475f;	val_dir[15358*3 + 1] = -0.060217f;	val_dir[15358*3 + 2] = -0.260941f;
+ 	val_dir[15359*3 + 0] = -0.951877f;	val_dir[15359*3 + 1] = -0.040505f;	val_dir[15359*3 + 2] = -0.303791f;
+ 	val_dir[15360*3 + 0] = -0.93780f;	val_dir[15360*3 + 1] = -0.020387f;	val_dir[15360*3 + 2] = -0.346578f;
+ 	val_dir[15361*3 + 0] = -0.921250f;	val_dir[15361*3 + 1] = 0.0f;	val_dir[15361*3 + 2] = -0.388972f;
+ 	val_dir[15362*3 + 0] = -0.917863f;	val_dir[15362*3 + 1] = 0.020861f;	val_dir[15362*3 + 2] = -0.396350f;
+ 	val_dir[15363*3 + 0] = -0.913860f;	val_dir[15363*3 + 1] = 0.042505f;	val_dir[15363*3 + 2] = -0.403799f;
+ 	val_dir[15364*3 + 0] = -0.909185f;	val_dir[15364*3 + 1] = 0.064942f;	val_dir[15364*3 + 2] = -0.411298f;
+ 	val_dir[15365*3 + 0] = -0.903777f;	val_dir[15365*3 + 1] = 0.088173f;	val_dir[15365*3 + 2] = -0.418823f;
+ 	val_dir[15366*3 + 0] = -0.897574f;	val_dir[15366*3 + 1] = 0.112197f;	val_dir[15366*3 + 2] = -0.426348f;
+ 	val_dir[15367*3 + 0] = -0.890513f;	val_dir[15367*3 + 1] = 0.137002f;	val_dir[15367*3 + 2] = -0.433840f;
+ 	val_dir[15368*3 + 0] = -0.882528f;	val_dir[15368*3 + 1] = 0.162571f;	val_dir[15368*3 + 2] = -0.441264f;
+ 	val_dir[15369*3 + 0] = -0.873555f;	val_dir[15369*3 + 1] = 0.188877f;	val_dir[15369*3 + 2] = -0.448583f;
+ 	val_dir[15370*3 + 0] = -0.863530f;	val_dir[15370*3 + 1] = 0.215883f;	val_dir[15370*3 + 2] = -0.455752f;
+ 	val_dir[15371*3 + 0] = -0.852392f;	val_dir[15371*3 + 1] = 0.243541f;	val_dir[15371*3 + 2] = -0.462727f;
+ 	val_dir[15372*3 + 0] = -0.840083f;	val_dir[15372*3 + 1] = 0.271791f;	val_dir[15372*3 + 2] = -0.469458f;
+ 	val_dir[15373*3 + 0] = -0.826551f;	val_dir[15373*3 + 1] = 0.300564f;	val_dir[15373*3 + 2] = -0.475893f;
+ 	val_dir[15374*3 + 0] = -0.811754f;	val_dir[15374*3 + 1] = 0.329775f;	val_dir[15374*3 + 2] = -0.481979f;
+ 	val_dir[15375*3 + 0] = -0.795657f;	val_dir[15375*3 + 1] = 0.359329f;	val_dir[15375*3 + 2] = -0.487661f;
+ 	val_dir[15376*3 + 0] = -0.778237f;	val_dir[15376*3 + 1] = 0.389118f;	val_dir[15376*3 + 2] = -0.492883f;
+ 	val_dir[15377*3 + 0] = -0.759485f;	val_dir[15377*3 + 1] = 0.419026f;	val_dir[15377*3 + 2] = -0.497594f;
+ 	val_dir[15378*3 + 0] = -0.739407f;	val_dir[15378*3 + 1] = 0.448926f;	val_dir[15378*3 + 2] = -0.501740f;
+ 	val_dir[15379*3 + 0] = -0.718024f;	val_dir[15379*3 + 1] = 0.478683f;	val_dir[15379*3 + 2] = -0.505276f;
+ 	val_dir[15380*3 + 0] = -0.695376f;	val_dir[15380*3 + 1] = 0.508159f;	val_dir[15380*3 + 2] = -0.508159f;
+ 	val_dir[15381*3 + 0] = -0.671519f;	val_dir[15381*3 + 1] = 0.537215f;	val_dir[15381*3 + 2] = -0.510355f;
+ 	val_dir[15382*3 + 0] = -0.646527f;	val_dir[15382*3 + 1] = 0.565711f;	val_dir[15382*3 + 2] = -0.511834f;
+ 	val_dir[15383*3 + 0] = -0.620490f;	val_dir[15383*3 + 1] = 0.593512f;	val_dir[15383*3 + 2] = -0.512578f;
+ 	val_dir[15384*3 + 0] = -0.593512f;	val_dir[15384*3 + 1] = 0.620490f;	val_dir[15384*3 + 2] = -0.512578f;
+ 	val_dir[15385*3 + 0] = -0.565711f;	val_dir[15385*3 + 1] = 0.646527f;	val_dir[15385*3 + 2] = -0.511834f;
+ 	val_dir[15386*3 + 0] = -0.537215f;	val_dir[15386*3 + 1] = 0.671519f;	val_dir[15386*3 + 2] = -0.510355f;
+ 	val_dir[15387*3 + 0] = -0.508159f;	val_dir[15387*3 + 1] = 0.695376f;	val_dir[15387*3 + 2] = -0.508159f;
+ 	val_dir[15388*3 + 0] = -0.478683f;	val_dir[15388*3 + 1] = 0.718024f;	val_dir[15388*3 + 2] = -0.505276f;
+ 	val_dir[15389*3 + 0] = -0.448926f;	val_dir[15389*3 + 1] = 0.739407f;	val_dir[15389*3 + 2] = -0.501740f;
+ 	val_dir[15390*3 + 0] = -0.419026f;	val_dir[15390*3 + 1] = 0.759485f;	val_dir[15390*3 + 2] = -0.497594f;
+ 	val_dir[15391*3 + 0] = -0.389118f;	val_dir[15391*3 + 1] = 0.778237f;	val_dir[15391*3 + 2] = -0.492883f;
+ 	val_dir[15392*3 + 0] = -0.359329f;	val_dir[15392*3 + 1] = 0.795657f;	val_dir[15392*3 + 2] = -0.487661f;
+ 	val_dir[15393*3 + 0] = -0.329775f;	val_dir[15393*3 + 1] = 0.811754f;	val_dir[15393*3 + 2] = -0.481979f;
+ 	val_dir[15394*3 + 0] = -0.300564f;	val_dir[15394*3 + 1] = 0.826551f;	val_dir[15394*3 + 2] = -0.475893f;
+ 	val_dir[15395*3 + 0] = -0.271791f;	val_dir[15395*3 + 1] = 0.840083f;	val_dir[15395*3 + 2] = -0.469458f;
+ 	val_dir[15396*3 + 0] = -0.243541f;	val_dir[15396*3 + 1] = 0.852392f;	val_dir[15396*3 + 2] = -0.462727f;
+ 	val_dir[15397*3 + 0] = -0.215883f;	val_dir[15397*3 + 1] = 0.863530f;	val_dir[15397*3 + 2] = -0.455752f;
+ 	val_dir[15398*3 + 0] = -0.188877f;	val_dir[15398*3 + 1] = 0.873555f;	val_dir[15398*3 + 2] = -0.448583f;
+ 	val_dir[15399*3 + 0] = -0.162571f;	val_dir[15399*3 + 1] = 0.882528f;	val_dir[15399*3 + 2] = -0.441264f;
+ 	val_dir[15400*3 + 0] = -0.137002f;	val_dir[15400*3 + 1] = 0.890513f;	val_dir[15400*3 + 2] = -0.433840f;
+ 	val_dir[15401*3 + 0] = -0.112197f;	val_dir[15401*3 + 1] = 0.897574f;	val_dir[15401*3 + 2] = -0.426348f;
+ 	val_dir[15402*3 + 0] = -0.088173f;	val_dir[15402*3 + 1] = 0.903777f;	val_dir[15402*3 + 2] = -0.418823f;
+ 	val_dir[15403*3 + 0] = -0.064942f;	val_dir[15403*3 + 1] = 0.909185f;	val_dir[15403*3 + 2] = -0.411298f;
+ 	val_dir[15404*3 + 0] = -0.042505f;	val_dir[15404*3 + 1] = 0.913860f;	val_dir[15404*3 + 2] = -0.403799f;
+ 	val_dir[15405*3 + 0] = -0.020861f;	val_dir[15405*3 + 1] = 0.917863f;	val_dir[15405*3 + 2] = -0.396350f;
+ 	val_dir[15406*3 + 0] = 0.0f;	val_dir[15406*3 + 1] = 0.921250f;	val_dir[15406*3 + 2] = -0.388972f;
+ 	val_dir[15407*3 + 0] = 0.020387f;	val_dir[15407*3 + 1] = 0.93780f;	val_dir[15407*3 + 2] = -0.346578f;
+ 	val_dir[15408*3 + 0] = 0.040505f;	val_dir[15408*3 + 1] = 0.951877f;	val_dir[15408*3 + 2] = -0.303791f;
+ 	val_dir[15409*3 + 0] = 0.060217f;	val_dir[15409*3 + 1] = 0.963475f;	val_dir[15409*3 + 2] = -0.260941f;
+ 	val_dir[15410*3 + 0] = 0.079399f;	val_dir[15410*3 + 1] = 0.972636f;	val_dir[15410*3 + 2] = -0.218347f;
+ 	val_dir[15411*3 + 0] = 0.097945f;	val_dir[15411*3 + 1] = 0.979451f;	val_dir[15411*3 + 2] = -0.176301f;
+ 	val_dir[15412*3 + 0] = 0.115771f;	val_dir[15412*3 + 1] = 0.984050f;	val_dir[15412*3 + 2] = -0.135066f;
+ 	val_dir[15413*3 + 0] = 0.132810f;	val_dir[15413*3 + 1] = 0.986591f;	val_dir[15413*3 + 2] = -0.094865f;
+ 	val_dir[15414*3 + 0] = 0.149019f;	val_dir[15414*3 + 1] = 0.987254f;	val_dir[15414*3 + 2] = -0.055882f;
+ 	val_dir[15415*3 + 0] = 0.164372f;	val_dir[15415*3 + 1] = 0.986229f;	val_dir[15415*3 + 2] = -0.018264f;
+ 	val_dir[15416*3 + 0] = -0.986875f;	val_dir[15416*3 + 1] = -0.161489f;	val_dir[15416*3 + 2] = 0.0f;
+ 	val_dir[15417*3 + 0] = -0.988540f;	val_dir[15417*3 + 1] = -0.146450f;	val_dir[15417*3 + 2] = -0.036613f;
+ 	val_dir[15418*3 + 0] = -0.988627f;	val_dir[15418*3 + 1] = -0.130573f;	val_dir[15418*3 + 2] = -0.074613f;
+ 	val_dir[15419*3 + 0] = -0.986947f;	val_dir[15419*3 + 1] = -0.113878f;	val_dir[15419*3 + 2] = -0.113878f;
+ 	val_dir[15420*3 + 0] = -0.983318f;	val_dir[15420*3 + 1] = -0.096404f;	val_dir[15420*3 + 2] = -0.154246f;
+ 	val_dir[15421*3 + 0] = -0.977577f;	val_dir[15421*3 + 1] = -0.078206f;	val_dir[15421*3 + 2] = -0.195515f;
+ 	val_dir[15422*3 + 0] = -0.969584f;	val_dir[15422*3 + 1] = -0.059362f;	val_dir[15422*3 + 2] = -0.237449f;
+ 	val_dir[15423*3 + 0] = -0.959233f;	val_dir[15423*3 + 1] = -0.039968f;	val_dir[15423*3 + 2] = -0.279776f;
+ 	val_dir[15424*3 + 0] = -0.946458f;	val_dir[15424*3 + 1] = -0.020137f;	val_dir[15424*3 + 2] = -0.322198f;
+ 	val_dir[15425*3 + 0] = -0.931243f;	val_dir[15425*3 + 1] = 0.0f;	val_dir[15425*3 + 2] = -0.364399f;
+ 	val_dir[15426*3 + 0] = -0.928279f;	val_dir[15426*3 + 1] = 0.020628f;	val_dir[15426*3 + 2] = -0.371312f;
+ 	val_dir[15427*3 + 0] = -0.924729f;	val_dir[15427*3 + 1] = 0.042033f;	val_dir[15427*3 + 2] = -0.378298f;
+ 	val_dir[15428*3 + 0] = -0.920537f;	val_dir[15428*3 + 1] = 0.064223f;	val_dir[15428*3 + 2] = -0.385341f;
+ 	val_dir[15429*3 + 0] = -0.915644f;	val_dir[15429*3 + 1] = 0.087204f;	val_dir[15429*3 + 2] = -0.392419f;
+ 	val_dir[15430*3 + 0] = -0.909988f;	val_dir[15430*3 + 1] = 0.110974f;	val_dir[15430*3 + 2] = -0.399507f;
+ 	val_dir[15431*3 + 0] = -0.903508f;	val_dir[15431*3 + 1] = 0.135526f;	val_dir[15431*3 + 2] = -0.406579f;
+ 	val_dir[15432*3 + 0] = -0.896137f;	val_dir[15432*3 + 1] = 0.160845f;	val_dir[15432*3 + 2] = -0.413602f;
+ 	val_dir[15433*3 + 0] = -0.887812f;	val_dir[15433*3 + 1] = 0.186908f;	val_dir[15433*3 + 2] = -0.420542f;
+ 	val_dir[15434*3 + 0] = -0.878466f;	val_dir[15434*3 + 1] = 0.213681f;	val_dir[15434*3 + 2] = -0.427362f;
+ 	val_dir[15435*3 + 0] = -0.868037f;	val_dir[15435*3 + 1] = 0.241121f;	val_dir[15435*3 + 2] = -0.434019f;
+ 	val_dir[15436*3 + 0] = -0.856465f;	val_dir[15436*3 + 1] = 0.269175f;	val_dir[15436*3 + 2] = -0.440468f;
+ 	val_dir[15437*3 + 0] = -0.843696f;	val_dir[15437*3 + 1] = 0.297775f;	val_dir[15437*3 + 2] = -0.446662f;
+ 	val_dir[15438*3 + 0] = -0.829680f;	val_dir[15438*3 + 1] = 0.326844f;	val_dir[15438*3 + 2] = -0.452553f;
+ 	val_dir[15439*3 + 0] = -0.814379f;	val_dir[15439*3 + 1] = 0.356291f;	val_dir[15439*3 + 2] = -0.458088f;
+ 	val_dir[15440*3 + 0] = -0.797762f;	val_dir[15440*3 + 1] = 0.386014f;	val_dir[15440*3 + 2] = -0.463217f;
+ 	val_dir[15441*3 + 0] = -0.779813f;	val_dir[15441*3 + 1] = 0.41590f;	val_dir[15441*3 + 2] = -0.467888f;
+ 	val_dir[15442*3 + 0] = -0.760529f;	val_dir[15442*3 + 1] = 0.445827f;	val_dir[15442*3 + 2] = -0.472053f;
+ 	val_dir[15443*3 + 0] = -0.739923f;	val_dir[15443*3 + 1] = 0.475665f;	val_dir[15443*3 + 2] = -0.475665f;
+ 	val_dir[15444*3 + 0] = -0.718024f;	val_dir[15444*3 + 1] = 0.505276f;	val_dir[15444*3 + 2] = -0.478683f;
+ 	val_dir[15445*3 + 0] = -0.694879f;	val_dir[15445*3 + 1] = 0.534522f;	val_dir[15445*3 + 2] = -0.481070f;
+ 	val_dir[15446*3 + 0] = -0.670552f;	val_dir[15446*3 + 1] = 0.563264f;	val_dir[15446*3 + 2] = -0.482798f;
+ 	val_dir[15447*3 + 0] = -0.645124f;	val_dir[15447*3 + 1] = 0.591364f;	val_dir[15447*3 + 2] = -0.483843f;
+ 	val_dir[15448*3 + 0] = -0.618691f;	val_dir[15448*3 + 1] = 0.618691f;	val_dir[15448*3 + 2] = -0.484193f;
+ 	val_dir[15449*3 + 0] = -0.591364f;	val_dir[15449*3 + 1] = 0.645124f;	val_dir[15449*3 + 2] = -0.483843f;
+ 	val_dir[15450*3 + 0] = -0.563264f;	val_dir[15450*3 + 1] = 0.670552f;	val_dir[15450*3 + 2] = -0.482798f;
+ 	val_dir[15451*3 + 0] = -0.534522f;	val_dir[15451*3 + 1] = 0.694879f;	val_dir[15451*3 + 2] = -0.481070f;
+ 	val_dir[15452*3 + 0] = -0.505276f;	val_dir[15452*3 + 1] = 0.718024f;	val_dir[15452*3 + 2] = -0.478683f;
+ 	val_dir[15453*3 + 0] = -0.475665f;	val_dir[15453*3 + 1] = 0.739923f;	val_dir[15453*3 + 2] = -0.475665f;
+ 	val_dir[15454*3 + 0] = -0.445827f;	val_dir[15454*3 + 1] = 0.760529f;	val_dir[15454*3 + 2] = -0.472053f;
+ 	val_dir[15455*3 + 0] = -0.41590f;	val_dir[15455*3 + 1] = 0.779813f;	val_dir[15455*3 + 2] = -0.467888f;
+ 	val_dir[15456*3 + 0] = -0.386014f;	val_dir[15456*3 + 1] = 0.797762f;	val_dir[15456*3 + 2] = -0.463217f;
+ 	val_dir[15457*3 + 0] = -0.356291f;	val_dir[15457*3 + 1] = 0.814379f;	val_dir[15457*3 + 2] = -0.458088f;
+ 	val_dir[15458*3 + 0] = -0.326844f;	val_dir[15458*3 + 1] = 0.829680f;	val_dir[15458*3 + 2] = -0.452553f;
+ 	val_dir[15459*3 + 0] = -0.297775f;	val_dir[15459*3 + 1] = 0.843696f;	val_dir[15459*3 + 2] = -0.446662f;
+ 	val_dir[15460*3 + 0] = -0.269175f;	val_dir[15460*3 + 1] = 0.856465f;	val_dir[15460*3 + 2] = -0.440468f;
+ 	val_dir[15461*3 + 0] = -0.241121f;	val_dir[15461*3 + 1] = 0.868037f;	val_dir[15461*3 + 2] = -0.434019f;
+ 	val_dir[15462*3 + 0] = -0.213681f;	val_dir[15462*3 + 1] = 0.878466f;	val_dir[15462*3 + 2] = -0.427362f;
+ 	val_dir[15463*3 + 0] = -0.186908f;	val_dir[15463*3 + 1] = 0.887812f;	val_dir[15463*3 + 2] = -0.420542f;
+ 	val_dir[15464*3 + 0] = -0.160845f;	val_dir[15464*3 + 1] = 0.896137f;	val_dir[15464*3 + 2] = -0.413602f;
+ 	val_dir[15465*3 + 0] = -0.135526f;	val_dir[15465*3 + 1] = 0.903508f;	val_dir[15465*3 + 2] = -0.406579f;
+ 	val_dir[15466*3 + 0] = -0.110974f;	val_dir[15466*3 + 1] = 0.909988f;	val_dir[15466*3 + 2] = -0.399507f;
+ 	val_dir[15467*3 + 0] = -0.087204f;	val_dir[15467*3 + 1] = 0.915644f;	val_dir[15467*3 + 2] = -0.392419f;
+ 	val_dir[15468*3 + 0] = -0.064223f;	val_dir[15468*3 + 1] = 0.920537f;	val_dir[15468*3 + 2] = -0.385341f;
+ 	val_dir[15469*3 + 0] = -0.042033f;	val_dir[15469*3 + 1] = 0.924729f;	val_dir[15469*3 + 2] = -0.378298f;
+ 	val_dir[15470*3 + 0] = -0.020628f;	val_dir[15470*3 + 1] = 0.928279f;	val_dir[15470*3 + 2] = -0.371312f;
+ 	val_dir[15471*3 + 0] = 0.0f;	val_dir[15471*3 + 1] = 0.931243f;	val_dir[15471*3 + 2] = -0.364399f;
+ 	val_dir[15472*3 + 0] = 0.020137f;	val_dir[15472*3 + 1] = 0.946458f;	val_dir[15472*3 + 2] = -0.322198f;
+ 	val_dir[15473*3 + 0] = 0.039968f;	val_dir[15473*3 + 1] = 0.959233f;	val_dir[15473*3 + 2] = -0.279776f;
+ 	val_dir[15474*3 + 0] = 0.059362f;	val_dir[15474*3 + 1] = 0.969584f;	val_dir[15474*3 + 2] = -0.237449f;
+ 	val_dir[15475*3 + 0] = 0.078206f;	val_dir[15475*3 + 1] = 0.977577f;	val_dir[15475*3 + 2] = -0.195515f;
+ 	val_dir[15476*3 + 0] = 0.096404f;	val_dir[15476*3 + 1] = 0.983318f;	val_dir[15476*3 + 2] = -0.154246f;
+ 	val_dir[15477*3 + 0] = 0.113878f;	val_dir[15477*3 + 1] = 0.986947f;	val_dir[15477*3 + 2] = -0.113878f;
+ 	val_dir[15478*3 + 0] = 0.130573f;	val_dir[15478*3 + 1] = 0.988627f;	val_dir[15478*3 + 2] = -0.074613f;
+ 	val_dir[15479*3 + 0] = 0.146450f;	val_dir[15479*3 + 1] = 0.988540f;	val_dir[15479*3 + 2] = -0.036613f;
+ 	val_dir[15480*3 + 0] = 0.161489f;	val_dir[15480*3 + 1] = 0.986875f;	val_dir[15480*3 + 2] = 0.0f;
+ 	val_dir[15481*3 + 0] = -0.989426f;	val_dir[15481*3 + 1] = -0.143917f;	val_dir[15481*3 + 2] = -0.017990f;
+ 	val_dir[15482*3 + 0] = -0.990201f;	val_dir[15482*3 + 1] = -0.128359f;	val_dir[15482*3 + 2] = -0.055011f;
+ 	val_dir[15483*3 + 0] = -0.989316f;	val_dir[15483*3 + 1] = -0.111998f;	val_dir[15483*3 + 2] = -0.093332f;
+ 	val_dir[15484*3 + 0] = -0.986591f;	val_dir[15484*3 + 1] = -0.094865f;	val_dir[15484*3 + 2] = -0.132810f;
+ 	val_dir[15485*3 + 0] = -0.981859f;	val_dir[15485*3 + 1] = -0.077009f;	val_dir[15485*3 + 2] = -0.173269f;
+ 	val_dir[15486*3 + 0] = -0.974972f;	val_dir[15486*3 + 1] = -0.058498f;	val_dir[15486*3 + 2] = -0.214494f;
+ 	val_dir[15487*3 + 0] = -0.965810f;	val_dir[15487*3 + 1] = -0.039421f;	val_dir[15487*3 + 2] = -0.256235f;
+ 	val_dir[15488*3 + 0] = -0.954291f;	val_dir[15488*3 + 1] = -0.019881f;	val_dir[15488*3 + 2] = -0.298216f;
+ 	val_dir[15489*3 + 0] = -0.940376f;	val_dir[15489*3 + 1] = 0.0f;	val_dir[15489*3 + 2] = -0.340136f;
+ 	val_dir[15490*3 + 0] = -0.93780f;	val_dir[15490*3 + 1] = 0.020387f;	val_dir[15490*3 + 2] = -0.346578f;
+ 	val_dir[15491*3 + 0] = -0.934665f;	val_dir[15491*3 + 1] = 0.041541f;	val_dir[15491*3 + 2] = -0.353096f;
+ 	val_dir[15492*3 + 0] = -0.930917f;	val_dir[15492*3 + 1] = 0.063472f;	val_dir[15492*3 + 2] = -0.359673f;
+ 	val_dir[15493*3 + 0] = -0.92650f;	val_dir[15493*3 + 1] = 0.086186f;	val_dir[15493*3 + 2] = -0.366291f;
+ 	val_dir[15494*3 + 0] = -0.921354f;	val_dir[15494*3 + 1] = 0.109685f;	val_dir[15494*3 + 2] = -0.372929f;
+ 	val_dir[15495*3 + 0] = -0.915416f;	val_dir[15495*3 + 1] = 0.133963f;	val_dir[15495*3 + 2] = -0.379563f;
+ 	val_dir[15496*3 + 0] = -0.908622f;	val_dir[15496*3 + 1] = 0.159009f;	val_dir[15496*3 + 2] = -0.386164f;
+ 	val_dir[15497*3 + 0] = -0.900907f;	val_dir[15497*3 + 1] = 0.184801f;	val_dir[15497*3 + 2] = -0.392703f;
+ 	val_dir[15498*3 + 0] = -0.892206f;	val_dir[15498*3 + 1] = 0.211312f;	val_dir[15498*3 + 2] = -0.399145f;
+ 	val_dir[15499*3 + 0] = -0.882454f;	val_dir[15499*3 + 1] = 0.238501f;	val_dir[15499*3 + 2] = -0.405452f;
+ 	val_dir[15500*3 + 0] = -0.871592f;	val_dir[15500*3 + 1] = 0.266320f;	val_dir[15500*3 + 2] = -0.411585f;
+ 	val_dir[15501*3 + 0] = -0.859559f;	val_dir[15501*3 + 1] = 0.294706f;	val_dir[15501*3 + 2] = -0.41750f;
+ 	val_dir[15502*3 + 0] = -0.846305f;	val_dir[15502*3 + 1] = 0.323587f;	val_dir[15502*3 + 2] = -0.423153f;
+ 	val_dir[15503*3 + 0] = -0.831786f;	val_dir[15503*3 + 1] = 0.352879f;	val_dir[15503*3 + 2] = -0.428496f;
+ 	val_dir[15504*3 + 0] = -0.815966f;	val_dir[15504*3 + 1] = 0.382484f;	val_dir[15504*3 + 2] = -0.433482f;
+ 	val_dir[15505*3 + 0] = -0.798820f;	val_dir[15505*3 + 1] = 0.412294f;	val_dir[15505*3 + 2] = -0.438063f;
+ 	val_dir[15506*3 + 0] = -0.780340f;	val_dir[15506*3 + 1] = 0.442193f;	val_dir[15506*3 + 2] = -0.442193f;
+ 	val_dir[15507*3 + 0] = -0.760529f;	val_dir[15507*3 + 1] = 0.472053f;	val_dir[15507*3 + 2] = -0.445827f;
+ 	val_dir[15508*3 + 0] = -0.739407f;	val_dir[15508*3 + 1] = 0.501740f;	val_dir[15508*3 + 2] = -0.448926f;
+ 	val_dir[15509*3 + 0] = -0.717011f;	val_dir[15509*3 + 1] = 0.531119f;	val_dir[15509*3 + 2] = -0.451451f;
+ 	val_dir[15510*3 + 0] = -0.693395f;	val_dir[15510*3 + 1] = 0.560050f;	val_dir[15510*3 + 2] = -0.453374f;
+ 	val_dir[15511*3 + 0] = -0.668631f;	val_dir[15511*3 + 1] = 0.588395f;	val_dir[15511*3 + 2] = -0.454669f;
+ 	val_dir[15512*3 + 0] = -0.642806f;	val_dir[15512*3 + 1] = 0.616022f;	val_dir[15512*3 + 2] = -0.455321f;
+ 	val_dir[15513*3 + 0] = -0.616022f;	val_dir[15513*3 + 1] = 0.642806f;	val_dir[15513*3 + 2] = -0.455321f;
+ 	val_dir[15514*3 + 0] = -0.588395f;	val_dir[15514*3 + 1] = 0.668631f;	val_dir[15514*3 + 2] = -0.454669f;
+ 	val_dir[15515*3 + 0] = -0.560050f;	val_dir[15515*3 + 1] = 0.693395f;	val_dir[15515*3 + 2] = -0.453374f;
+ 	val_dir[15516*3 + 0] = -0.531119f;	val_dir[15516*3 + 1] = 0.717011f;	val_dir[15516*3 + 2] = -0.451451f;
+ 	val_dir[15517*3 + 0] = -0.501740f;	val_dir[15517*3 + 1] = 0.739407f;	val_dir[15517*3 + 2] = -0.448926f;
+ 	val_dir[15518*3 + 0] = -0.472053f;	val_dir[15518*3 + 1] = 0.760529f;	val_dir[15518*3 + 2] = -0.445827f;
+ 	val_dir[15519*3 + 0] = -0.442193f;	val_dir[15519*3 + 1] = 0.780340f;	val_dir[15519*3 + 2] = -0.442193f;
+ 	val_dir[15520*3 + 0] = -0.412294f;	val_dir[15520*3 + 1] = 0.798820f;	val_dir[15520*3 + 2] = -0.438063f;
+ 	val_dir[15521*3 + 0] = -0.382484f;	val_dir[15521*3 + 1] = 0.815966f;	val_dir[15521*3 + 2] = -0.433482f;
+ 	val_dir[15522*3 + 0] = -0.352879f;	val_dir[15522*3 + 1] = 0.831786f;	val_dir[15522*3 + 2] = -0.428496f;
+ 	val_dir[15523*3 + 0] = -0.323587f;	val_dir[15523*3 + 1] = 0.846305f;	val_dir[15523*3 + 2] = -0.423153f;
+ 	val_dir[15524*3 + 0] = -0.294706f;	val_dir[15524*3 + 1] = 0.859559f;	val_dir[15524*3 + 2] = -0.41750f;
+ 	val_dir[15525*3 + 0] = -0.266320f;	val_dir[15525*3 + 1] = 0.871592f;	val_dir[15525*3 + 2] = -0.411585f;
+ 	val_dir[15526*3 + 0] = -0.238501f;	val_dir[15526*3 + 1] = 0.882454f;	val_dir[15526*3 + 2] = -0.405452f;
+ 	val_dir[15527*3 + 0] = -0.211312f;	val_dir[15527*3 + 1] = 0.892206f;	val_dir[15527*3 + 2] = -0.399145f;
+ 	val_dir[15528*3 + 0] = -0.184801f;	val_dir[15528*3 + 1] = 0.900907f;	val_dir[15528*3 + 2] = -0.392703f;
+ 	val_dir[15529*3 + 0] = -0.159009f;	val_dir[15529*3 + 1] = 0.908622f;	val_dir[15529*3 + 2] = -0.386164f;
+ 	val_dir[15530*3 + 0] = -0.133963f;	val_dir[15530*3 + 1] = 0.915416f;	val_dir[15530*3 + 2] = -0.379563f;
+ 	val_dir[15531*3 + 0] = -0.109685f;	val_dir[15531*3 + 1] = 0.921354f;	val_dir[15531*3 + 2] = -0.372929f;
+ 	val_dir[15532*3 + 0] = -0.086186f;	val_dir[15532*3 + 1] = 0.92650f;	val_dir[15532*3 + 2] = -0.366291f;
+ 	val_dir[15533*3 + 0] = -0.063472f;	val_dir[15533*3 + 1] = 0.930917f;	val_dir[15533*3 + 2] = -0.359673f;
+ 	val_dir[15534*3 + 0] = -0.041541f;	val_dir[15534*3 + 1] = 0.934665f;	val_dir[15534*3 + 2] = -0.353096f;
+ 	val_dir[15535*3 + 0] = -0.020387f;	val_dir[15535*3 + 1] = 0.93780f;	val_dir[15535*3 + 2] = -0.346578f;
+ 	val_dir[15536*3 + 0] = 0.0f;	val_dir[15536*3 + 1] = 0.940376f;	val_dir[15536*3 + 2] = -0.340136f;
+ 	val_dir[15537*3 + 0] = 0.019881f;	val_dir[15537*3 + 1] = 0.954291f;	val_dir[15537*3 + 2] = -0.298216f;
+ 	val_dir[15538*3 + 0] = 0.039421f;	val_dir[15538*3 + 1] = 0.965810f;	val_dir[15538*3 + 2] = -0.256235f;
+ 	val_dir[15539*3 + 0] = 0.058498f;	val_dir[15539*3 + 1] = 0.974972f;	val_dir[15539*3 + 2] = -0.214494f;
+ 	val_dir[15540*3 + 0] = 0.077009f;	val_dir[15540*3 + 1] = 0.981859f;	val_dir[15540*3 + 2] = -0.173269f;
+ 	val_dir[15541*3 + 0] = 0.094865f;	val_dir[15541*3 + 1] = 0.986591f;	val_dir[15541*3 + 2] = -0.132810f;
+ 	val_dir[15542*3 + 0] = 0.111998f;	val_dir[15542*3 + 1] = 0.989316f;	val_dir[15542*3 + 2] = -0.093332f;
+ 	val_dir[15543*3 + 0] = 0.128359f;	val_dir[15543*3 + 1] = 0.990201f;	val_dir[15543*3 + 2] = -0.055011f;
+ 	val_dir[15544*3 + 0] = 0.143917f;	val_dir[15544*3 + 1] = 0.989426f;	val_dir[15544*3 + 2] = -0.017990f;
+ 	val_dir[15545*3 + 0] = -0.989949f;	val_dir[15545*3 + 1] = -0.141421f;	val_dir[15545*3 + 2] = 0.0f;
+ 	val_dir[15546*3 + 0] = -0.991353f;	val_dir[15546*3 + 1] = -0.126172f;	val_dir[15546*3 + 2] = -0.036049f;
+ 	val_dir[15547*3 + 0] = -0.991201f;	val_dir[15547*3 + 1] = -0.110133f;	val_dir[15547*3 + 2] = -0.073422f;
+ 	val_dir[15548*3 + 0] = -0.989316f;	val_dir[15548*3 + 1] = -0.093332f;	val_dir[15548*3 + 2] = -0.111998f;
+ 	val_dir[15549*3 + 0] = -0.985527f;	val_dir[15549*3 + 1] = -0.075810f;	val_dir[15549*3 + 2] = -0.151620f;
+ 	val_dir[15550*3 + 0] = -0.979683f;	val_dir[15550*3 + 1] = -0.057628f;	val_dir[15550*3 + 2] = -0.192095f;
+ 	val_dir[15551*3 + 0] = -0.971653f;	val_dir[15551*3 + 1] = -0.038866f;	val_dir[15551*3 + 2] = -0.233197f;
+ 	val_dir[15552*3 + 0] = -0.961339f;	val_dir[15552*3 + 1] = -0.019619f;	val_dir[15552*3 + 2] = -0.274668f;
+ 	val_dir[15553*3 + 0] = -0.948683f;	val_dir[15553*3 + 1] = 0.0f;	val_dir[15553*3 + 2] = -0.316228f;
+ 	val_dir[15554*3 + 0] = -0.946458f;	val_dir[15554*3 + 1] = 0.020137f;	val_dir[15554*3 + 2] = -0.322198f;
+ 	val_dir[15555*3 + 0] = -0.943701f;	val_dir[15555*3 + 1] = 0.041030f;	val_dir[15555*3 + 2] = -0.328244f;
+ 	val_dir[15556*3 + 0] = -0.940361f;	val_dir[15556*3 + 1] = 0.062691f;	val_dir[15556*3 + 2] = -0.334351f;
+ 	val_dir[15557*3 + 0] = -0.936382f;	val_dir[15557*3 + 1] = 0.085126f;	val_dir[15557*3 + 2] = -0.340503f;
+ 	val_dir[15558*3 + 0] = -0.931705f;	val_dir[15558*3 + 1] = 0.108338f;	val_dir[15558*3 + 2] = -0.346681f;
+ 	val_dir[15559*3 + 0] = -0.926270f;	val_dir[15559*3 + 1] = 0.132324f;	val_dir[15559*3 + 2] = -0.352865f;
+ 	val_dir[15560*3 + 0] = -0.920014f;	val_dir[15560*3 + 1] = 0.157075f;	val_dir[15560*3 + 2] = -0.359030f;
+ 	val_dir[15561*3 + 0] = -0.912871f;	val_dir[15561*3 + 1] = 0.182574f;	val_dir[15561*3 + 2] = -0.365148f;
+ 	val_dir[15562*3 + 0] = -0.904777f;	val_dir[15562*3 + 1] = 0.208795f;	val_dir[15562*3 + 2] = -0.371191f;
+ 	val_dir[15563*3 + 0] = -0.895669f;	val_dir[15563*3 + 1] = 0.235702f;	val_dir[15563*3 + 2] = -0.377124f;
+ 	val_dir[15564*3 + 0] = -0.885482f;	val_dir[15564*3 + 1] = 0.263251f;	val_dir[15564*3 + 2] = -0.382911f;
+ 	val_dir[15565*3 + 0] = -0.874157f;	val_dir[15565*3 + 1] = 0.291386f;	val_dir[15565*3 + 2] = -0.388514f;
+ 	val_dir[15566*3 + 0] = -0.861640f;	val_dir[15566*3 + 1] = 0.320038f;	val_dir[15566*3 + 2] = -0.393893f;
+ 	val_dir[15567*3 + 0] = -0.847883f;	val_dir[15567*3 + 1] = 0.349128f;	val_dir[15567*3 + 2] = -0.399004f;
+ 	val_dir[15568*3 + 0] = -0.832845f;	val_dir[15568*3 + 1] = 0.378566f;	val_dir[15568*3 + 2] = -0.403804f;
+ 	val_dir[15569*3 + 0] = -0.816497f;	val_dir[15569*3 + 1] = 0.408248f;	val_dir[15569*3 + 2] = -0.408248f;
+ 	val_dir[15570*3 + 0] = -0.798820f;	val_dir[15570*3 + 1] = 0.438063f;	val_dir[15570*3 + 2] = -0.412294f;
+ 	val_dir[15571*3 + 0] = -0.779813f;	val_dir[15571*3 + 1] = 0.467888f;	val_dir[15571*3 + 2] = -0.41590f;
+ 	val_dir[15572*3 + 0] = -0.759485f;	val_dir[15572*3 + 1] = 0.497594f;	val_dir[15572*3 + 2] = -0.419026f;
+ 	val_dir[15573*3 + 0] = -0.737865f;	val_dir[15573*3 + 1] = 0.527046f;	val_dir[15573*3 + 2] = -0.421637f;
+ 	val_dir[15574*3 + 0] = -0.714997f;	val_dir[15574*3 + 1] = 0.556108f;	val_dir[15574*3 + 2] = -0.423702f;
+ 	val_dir[15575*3 + 0] = -0.690942f;	val_dir[15575*3 + 1] = 0.584643f;	val_dir[15575*3 + 2] = -0.425195f;
+ 	val_dir[15576*3 + 0] = -0.665780f;	val_dir[15576*3 + 1] = 0.612517f;	val_dir[15576*3 + 2] = -0.426099f;
+ 	val_dir[15577*3 + 0] = -0.639602f;	val_dir[15577*3 + 1] = 0.639602f;	val_dir[15577*3 + 2] = -0.426401f;
+ 	val_dir[15578*3 + 0] = -0.612517f;	val_dir[15578*3 + 1] = 0.665780f;	val_dir[15578*3 + 2] = -0.426099f;
+ 	val_dir[15579*3 + 0] = -0.584643f;	val_dir[15579*3 + 1] = 0.690942f;	val_dir[15579*3 + 2] = -0.425195f;
+ 	val_dir[15580*3 + 0] = -0.556108f;	val_dir[15580*3 + 1] = 0.714997f;	val_dir[15580*3 + 2] = -0.423702f;
+ 	val_dir[15581*3 + 0] = -0.527046f;	val_dir[15581*3 + 1] = 0.737865f;	val_dir[15581*3 + 2] = -0.421637f;
+ 	val_dir[15582*3 + 0] = -0.497594f;	val_dir[15582*3 + 1] = 0.759485f;	val_dir[15582*3 + 2] = -0.419026f;
+ 	val_dir[15583*3 + 0] = -0.467888f;	val_dir[15583*3 + 1] = 0.779813f;	val_dir[15583*3 + 2] = -0.41590f;
+ 	val_dir[15584*3 + 0] = -0.438063f;	val_dir[15584*3 + 1] = 0.798820f;	val_dir[15584*3 + 2] = -0.412294f;
+ 	val_dir[15585*3 + 0] = -0.408248f;	val_dir[15585*3 + 1] = 0.816497f;	val_dir[15585*3 + 2] = -0.408248f;
+ 	val_dir[15586*3 + 0] = -0.378566f;	val_dir[15586*3 + 1] = 0.832845f;	val_dir[15586*3 + 2] = -0.403804f;
+ 	val_dir[15587*3 + 0] = -0.349128f;	val_dir[15587*3 + 1] = 0.847883f;	val_dir[15587*3 + 2] = -0.399004f;
+ 	val_dir[15588*3 + 0] = -0.320038f;	val_dir[15588*3 + 1] = 0.861640f;	val_dir[15588*3 + 2] = -0.393893f;
+ 	val_dir[15589*3 + 0] = -0.291386f;	val_dir[15589*3 + 1] = 0.874157f;	val_dir[15589*3 + 2] = -0.388514f;
+ 	val_dir[15590*3 + 0] = -0.263251f;	val_dir[15590*3 + 1] = 0.885482f;	val_dir[15590*3 + 2] = -0.382911f;
+ 	val_dir[15591*3 + 0] = -0.235702f;	val_dir[15591*3 + 1] = 0.895669f;	val_dir[15591*3 + 2] = -0.377124f;
+ 	val_dir[15592*3 + 0] = -0.208795f;	val_dir[15592*3 + 1] = 0.904777f;	val_dir[15592*3 + 2] = -0.371191f;
+ 	val_dir[15593*3 + 0] = -0.182574f;	val_dir[15593*3 + 1] = 0.912871f;	val_dir[15593*3 + 2] = -0.365148f;
+ 	val_dir[15594*3 + 0] = -0.157075f;	val_dir[15594*3 + 1] = 0.920014f;	val_dir[15594*3 + 2] = -0.359030f;
+ 	val_dir[15595*3 + 0] = -0.132324f;	val_dir[15595*3 + 1] = 0.926270f;	val_dir[15595*3 + 2] = -0.352865f;
+ 	val_dir[15596*3 + 0] = -0.108338f;	val_dir[15596*3 + 1] = 0.931705f;	val_dir[15596*3 + 2] = -0.346681f;
+ 	val_dir[15597*3 + 0] = -0.085126f;	val_dir[15597*3 + 1] = 0.936382f;	val_dir[15597*3 + 2] = -0.340503f;
+ 	val_dir[15598*3 + 0] = -0.062691f;	val_dir[15598*3 + 1] = 0.940361f;	val_dir[15598*3 + 2] = -0.334351f;
+ 	val_dir[15599*3 + 0] = -0.041030f;	val_dir[15599*3 + 1] = 0.943701f;	val_dir[15599*3 + 2] = -0.328244f;
+ 	val_dir[15600*3 + 0] = -0.020137f;	val_dir[15600*3 + 1] = 0.946458f;	val_dir[15600*3 + 2] = -0.322198f;
+ 	val_dir[15601*3 + 0] = 0.0f;	val_dir[15601*3 + 1] = 0.948683f;	val_dir[15601*3 + 2] = -0.316228f;
+ 	val_dir[15602*3 + 0] = 0.019619f;	val_dir[15602*3 + 1] = 0.961339f;	val_dir[15602*3 + 2] = -0.274668f;
+ 	val_dir[15603*3 + 0] = 0.038866f;	val_dir[15603*3 + 1] = 0.971653f;	val_dir[15603*3 + 2] = -0.233197f;
+ 	val_dir[15604*3 + 0] = 0.057628f;	val_dir[15604*3 + 1] = 0.979683f;	val_dir[15604*3 + 2] = -0.192095f;
+ 	val_dir[15605*3 + 0] = 0.075810f;	val_dir[15605*3 + 1] = 0.985527f;	val_dir[15605*3 + 2] = -0.151620f;
+ 	val_dir[15606*3 + 0] = 0.093332f;	val_dir[15606*3 + 1] = 0.989316f;	val_dir[15606*3 + 2] = -0.111998f;
+ 	val_dir[15607*3 + 0] = 0.110133f;	val_dir[15607*3 + 1] = 0.991201f;	val_dir[15607*3 + 2] = -0.073422f;
+ 	val_dir[15608*3 + 0] = 0.126172f;	val_dir[15608*3 + 1] = 0.991353f;	val_dir[15608*3 + 2] = -0.036049f;
+ 	val_dir[15609*3 + 0] = 0.141421f;	val_dir[15609*3 + 1] = 0.989949f;	val_dir[15609*3 + 2] = 0.0f;
+ 	val_dir[15610*3 + 0] = -0.992122f;	val_dir[15610*3 + 1] = -0.124015f;	val_dir[15610*3 + 2] = -0.017716f;
+ 	val_dir[15611*3 + 0] = -0.992644f;	val_dir[15611*3 + 1] = -0.108288f;	val_dir[15611*3 + 2] = -0.054144f;
+ 	val_dir[15612*3 + 0] = -0.991535f;	val_dir[15612*3 + 1] = -0.091809f;	val_dir[15612*3 + 2] = -0.091809f;
+ 	val_dir[15613*3 + 0] = -0.988627f;	val_dir[15613*3 + 1] = -0.074613f;	val_dir[15613*3 + 2] = -0.130573f;
+ 	val_dir[15614*3 + 0] = -0.983762f;	val_dir[15614*3 + 1] = -0.056756f;	val_dir[15614*3 + 2] = -0.170267f;
+ 	val_dir[15615*3 + 0] = -0.976804f;	val_dir[15615*3 + 1] = -0.038306f;	val_dir[15615*3 + 2] = -0.210683f;
+ 	val_dir[15616*3 + 0] = -0.967641f;	val_dir[15616*3 + 1] = -0.019353f;	val_dir[15616*3 + 2] = -0.251587f;
+ 	val_dir[15617*3 + 0] = -0.95620f;	val_dir[15617*3 + 1] = 0.0f;	val_dir[15617*3 + 2] = -0.292714f;
+ 	val_dir[15618*3 + 0] = -0.954291f;	val_dir[15618*3 + 1] = 0.019881f;	val_dir[15618*3 + 2] = -0.298216f;
+ 	val_dir[15619*3 + 0] = -0.951877f;	val_dir[15619*3 + 1] = 0.040505f;	val_dir[15619*3 + 2] = -0.303791f;
+ 	val_dir[15620*3 + 0] = -0.948908f;	val_dir[15620*3 + 1] = 0.061885f;	val_dir[15620*3 + 2] = -0.309426f;
+ 	val_dir[15621*3 + 0] = -0.945328f;	val_dir[15621*3 + 1] = 0.084029f;	val_dir[15621*3 + 2] = -0.315109f;
+ 	val_dir[15622*3 + 0] = -0.941082f;	val_dir[15622*3 + 1] = 0.106941f;	val_dir[15622*3 + 2] = -0.320824f;
+ 	val_dir[15623*3 + 0] = -0.936111f;	val_dir[15623*3 + 1] = 0.130620f;	val_dir[15623*3 + 2] = -0.326550f;
+ 	val_dir[15624*3 + 0] = -0.930352f;	val_dir[15624*3 + 1] = 0.155059f;	val_dir[15624*3 + 2] = -0.332269f;
+ 	val_dir[15625*3 + 0] = -0.923742f;	val_dir[15625*3 + 1] = 0.180242f;	val_dir[15625*3 + 2] = -0.337954f;
+ 	val_dir[15626*3 + 0] = -0.916217f;	val_dir[15626*3 + 1] = 0.206149f;	val_dir[15626*3 + 2] = -0.343582f;
+ 	val_dir[15627*3 + 0] = -0.907713f;	val_dir[15627*3 + 1] = 0.232747f;	val_dir[15627*3 + 2] = -0.349121f;
+ 	val_dir[15628*3 + 0] = -0.898167f;	val_dir[15628*3 + 1] = 0.259996f;	val_dir[15628*3 + 2] = -0.354540f;
+ 	val_dir[15629*3 + 0] = -0.887517f;	val_dir[15629*3 + 1] = 0.287843f;	val_dir[15629*3 + 2] = -0.359804f;
+ 	val_dir[15630*3 + 0] = -0.875708f;	val_dir[15630*3 + 1] = 0.316228f;	val_dir[15630*3 + 2] = -0.364878f;
+ 	val_dir[15631*3 + 0] = -0.862687f;	val_dir[15631*3 + 1] = 0.345075f;	val_dir[15631*3 + 2] = -0.369723f;
+ 	val_dir[15632*3 + 0] = -0.848411f;	val_dir[15632*3 + 1] = 0.374299f;	val_dir[15632*3 + 2] = -0.374299f;
+ 	val_dir[15633*3 + 0] = -0.832845f;	val_dir[15633*3 + 1] = 0.403804f;	val_dir[15633*3 + 2] = -0.378566f;
+ 	val_dir[15634*3 + 0] = -0.815966f;	val_dir[15634*3 + 1] = 0.433482f;	val_dir[15634*3 + 2] = -0.382484f;
+ 	val_dir[15635*3 + 0] = -0.797762f;	val_dir[15635*3 + 1] = 0.463217f;	val_dir[15635*3 + 2] = -0.386014f;
+ 	val_dir[15636*3 + 0] = -0.778237f;	val_dir[15636*3 + 1] = 0.492883f;	val_dir[15636*3 + 2] = -0.389118f;
+ 	val_dir[15637*3 + 0] = -0.757410f;	val_dir[15637*3 + 1] = 0.522352f;	val_dir[15637*3 + 2] = -0.391764f;
+ 	val_dir[15638*3 + 0] = -0.735316f;	val_dir[15638*3 + 1] = 0.551487f;	val_dir[15638*3 + 2] = -0.393919f;
+ 	val_dir[15639*3 + 0] = -0.712007f;	val_dir[15639*3 + 1] = 0.580154f;	val_dir[15639*3 + 2] = -0.395559f;
+ 	val_dir[15640*3 + 0] = -0.687552f;	val_dir[15640*3 + 1] = 0.608219f;	val_dir[15640*3 + 2] = -0.396664f;
+ 	val_dir[15641*3 + 0] = -0.662034f;	val_dir[15641*3 + 1] = 0.635553f;	val_dir[15641*3 + 2] = -0.397220f;
+ 	val_dir[15642*3 + 0] = -0.635553f;	val_dir[15642*3 + 1] = 0.662034f;	val_dir[15642*3 + 2] = -0.397220f;
+ 	val_dir[15643*3 + 0] = -0.608219f;	val_dir[15643*3 + 1] = 0.687552f;	val_dir[15643*3 + 2] = -0.396664f;
+ 	val_dir[15644*3 + 0] = -0.580154f;	val_dir[15644*3 + 1] = 0.712007f;	val_dir[15644*3 + 2] = -0.395559f;
+ 	val_dir[15645*3 + 0] = -0.551487f;	val_dir[15645*3 + 1] = 0.735316f;	val_dir[15645*3 + 2] = -0.393919f;
+ 	val_dir[15646*3 + 0] = -0.522352f;	val_dir[15646*3 + 1] = 0.757410f;	val_dir[15646*3 + 2] = -0.391764f;
+ 	val_dir[15647*3 + 0] = -0.492883f;	val_dir[15647*3 + 1] = 0.778237f;	val_dir[15647*3 + 2] = -0.389118f;
+ 	val_dir[15648*3 + 0] = -0.463217f;	val_dir[15648*3 + 1] = 0.797762f;	val_dir[15648*3 + 2] = -0.386014f;
+ 	val_dir[15649*3 + 0] = -0.433482f;	val_dir[15649*3 + 1] = 0.815966f;	val_dir[15649*3 + 2] = -0.382484f;
+ 	val_dir[15650*3 + 0] = -0.403804f;	val_dir[15650*3 + 1] = 0.832845f;	val_dir[15650*3 + 2] = -0.378566f;
+ 	val_dir[15651*3 + 0] = -0.374299f;	val_dir[15651*3 + 1] = 0.848411f;	val_dir[15651*3 + 2] = -0.374299f;
+ 	val_dir[15652*3 + 0] = -0.345075f;	val_dir[15652*3 + 1] = 0.862687f;	val_dir[15652*3 + 2] = -0.369723f;
+ 	val_dir[15653*3 + 0] = -0.316228f;	val_dir[15653*3 + 1] = 0.875708f;	val_dir[15653*3 + 2] = -0.364878f;
+ 	val_dir[15654*3 + 0] = -0.287843f;	val_dir[15654*3 + 1] = 0.887517f;	val_dir[15654*3 + 2] = -0.359804f;
+ 	val_dir[15655*3 + 0] = -0.259996f;	val_dir[15655*3 + 1] = 0.898167f;	val_dir[15655*3 + 2] = -0.354540f;
+ 	val_dir[15656*3 + 0] = -0.232747f;	val_dir[15656*3 + 1] = 0.907713f;	val_dir[15656*3 + 2] = -0.349121f;
+ 	val_dir[15657*3 + 0] = -0.206149f;	val_dir[15657*3 + 1] = 0.916217f;	val_dir[15657*3 + 2] = -0.343582f;
+ 	val_dir[15658*3 + 0] = -0.180242f;	val_dir[15658*3 + 1] = 0.923742f;	val_dir[15658*3 + 2] = -0.337954f;
+ 	val_dir[15659*3 + 0] = -0.155059f;	val_dir[15659*3 + 1] = 0.930352f;	val_dir[15659*3 + 2] = -0.332269f;
+ 	val_dir[15660*3 + 0] = -0.130620f;	val_dir[15660*3 + 1] = 0.936111f;	val_dir[15660*3 + 2] = -0.326550f;
+ 	val_dir[15661*3 + 0] = -0.106941f;	val_dir[15661*3 + 1] = 0.941082f;	val_dir[15661*3 + 2] = -0.320824f;
+ 	val_dir[15662*3 + 0] = -0.084029f;	val_dir[15662*3 + 1] = 0.945328f;	val_dir[15662*3 + 2] = -0.315109f;
+ 	val_dir[15663*3 + 0] = -0.061885f;	val_dir[15663*3 + 1] = 0.948908f;	val_dir[15663*3 + 2] = -0.309426f;
+ 	val_dir[15664*3 + 0] = -0.040505f;	val_dir[15664*3 + 1] = 0.951877f;	val_dir[15664*3 + 2] = -0.303791f;
+ 	val_dir[15665*3 + 0] = -0.019881f;	val_dir[15665*3 + 1] = 0.954291f;	val_dir[15665*3 + 2] = -0.298216f;
+ 	val_dir[15666*3 + 0] = 0.0f;	val_dir[15666*3 + 1] = 0.95620f;	val_dir[15666*3 + 2] = -0.292714f;
+ 	val_dir[15667*3 + 0] = 0.019353f;	val_dir[15667*3 + 1] = 0.967641f;	val_dir[15667*3 + 2] = -0.251587f;
+ 	val_dir[15668*3 + 0] = 0.038306f;	val_dir[15668*3 + 1] = 0.976804f;	val_dir[15668*3 + 2] = -0.210683f;
+ 	val_dir[15669*3 + 0] = 0.056756f;	val_dir[15669*3 + 1] = 0.983762f;	val_dir[15669*3 + 2] = -0.170267f;
+ 	val_dir[15670*3 + 0] = 0.074613f;	val_dir[15670*3 + 1] = 0.988627f;	val_dir[15670*3 + 2] = -0.130573f;
+ 	val_dir[15671*3 + 0] = 0.091809f;	val_dir[15671*3 + 1] = 0.991535f;	val_dir[15671*3 + 2] = -0.091809f;
+ 	val_dir[15672*3 + 0] = 0.108288f;	val_dir[15672*3 + 1] = 0.992644f;	val_dir[15672*3 + 2] = -0.054144f;
+ 	val_dir[15673*3 + 0] = 0.124015f;	val_dir[15673*3 + 1] = 0.992122f;	val_dir[15673*3 + 2] = -0.017716f;
+ 	val_dir[15674*3 + 0] = -0.992543f;	val_dir[15674*3 + 1] = -0.121891f;	val_dir[15674*3 + 2] = 0.0f;
+ 	val_dir[15675*3 + 0] = -0.993683f;	val_dir[15675*3 + 1] = -0.106466f;	val_dir[15675*3 + 2] = -0.035489f;
+ 	val_dir[15676*3 + 0] = -0.993291f;	val_dir[15676*3 + 1] = -0.090299f;	val_dir[15676*3 + 2] = -0.072239f;
+ 	val_dir[15677*3 + 0] = -0.991201f;	val_dir[15677*3 + 1] = -0.073422f;	val_dir[15677*3 + 2] = -0.110133f;
+ 	val_dir[15678*3 + 0] = -0.987254f;	val_dir[15678*3 + 1] = -0.055882f;	val_dir[15678*3 + 2] = -0.149019f;
+ 	val_dir[15679*3 + 0] = -0.981307f;	val_dir[15679*3 + 1] = -0.037743f;	val_dir[15679*3 + 2] = -0.188713f;
+ 	val_dir[15680*3 + 0] = -0.973240f;	val_dir[15680*3 + 1] = -0.019083f;	val_dir[15680*3 + 2] = -0.228998f;
+ 	val_dir[15681*3 + 0] = -0.962964f;	val_dir[15681*3 + 1] = 0.0f;	val_dir[15681*3 + 2] = -0.269630f;
+ 	val_dir[15682*3 + 0] = -0.961339f;	val_dir[15682*3 + 1] = 0.019619f;	val_dir[15682*3 + 2] = -0.274668f;
+ 	val_dir[15683*3 + 0] = -0.959233f;	val_dir[15683*3 + 1] = 0.039968f;	val_dir[15683*3 + 2] = -0.279776f;
+ 	val_dir[15684*3 + 0] = -0.956597f;	val_dir[15684*3 + 1] = 0.061059f;	val_dir[15684*3 + 2] = -0.284944f;
+ 	val_dir[15685*3 + 0] = -0.953381f;	val_dir[15685*3 + 1] = 0.082903f;	val_dir[15685*3 + 2] = -0.290159f;
+ 	val_dir[15686*3 + 0] = -0.949528f;	val_dir[15686*3 + 1] = 0.105503f;	val_dir[15686*3 + 2] = -0.295409f;
+ 	val_dir[15687*3 + 0] = -0.944981f;	val_dir[15687*3 + 1] = 0.128861f;	val_dir[15687*3 + 2] = -0.300676f;
+ 	val_dir[15688*3 + 0] = -0.939680f;	val_dir[15688*3 + 1] = 0.152971f;	val_dir[15688*3 + 2] = -0.305942f;
+ 	val_dir[15689*3 + 0] = -0.933564f;	val_dir[15689*3 + 1] = 0.177822f;	val_dir[15689*3 + 2] = -0.311188f;
+ 	val_dir[15690*3 + 0] = -0.926568f;	val_dir[15690*3 + 1] = 0.203393f;	val_dir[15690*3 + 2] = -0.316389f;
+ 	val_dir[15691*3 + 0] = -0.918630f;	val_dir[15691*3 + 1] = 0.229658f;	val_dir[15691*3 + 2] = -0.321521f;
+ 	val_dir[15692*3 + 0] = -0.909687f;	val_dir[15692*3 + 1] = 0.256578f;	val_dir[15692*3 + 2] = -0.326554f;
+ 	val_dir[15693*3 + 0] = -0.899676f;	val_dir[15693*3 + 1] = 0.284108f;	val_dir[15693*3 + 2] = -0.331460f;
+ 	val_dir[15694*3 + 0] = -0.888540f;	val_dir[15694*3 + 1] = 0.312190f;	val_dir[15694*3 + 2] = -0.336204f;
+ 	val_dir[15695*3 + 0] = -0.876226f;	val_dir[15695*3 + 1] = 0.340755f;	val_dir[15695*3 + 2] = -0.340755f;
+ 	val_dir[15696*3 + 0] = -0.862687f;	val_dir[15696*3 + 1] = 0.369723f;	val_dir[15696*3 + 2] = -0.345075f;
+ 	val_dir[15697*3 + 0] = -0.847883f;	val_dir[15697*3 + 1] = 0.399004f;	val_dir[15697*3 + 2] = -0.349128f;
+ 	val_dir[15698*3 + 0] = -0.831786f;	val_dir[15698*3 + 1] = 0.428496f;	val_dir[15698*3 + 2] = -0.352879f;
+ 	val_dir[15699*3 + 0] = -0.814379f;	val_dir[15699*3 + 1] = 0.458088f;	val_dir[15699*3 + 2] = -0.356291f;
+ 	val_dir[15700*3 + 0] = -0.795657f;	val_dir[15700*3 + 1] = 0.487661f;	val_dir[15700*3 + 2] = -0.359329f;
+ 	val_dir[15701*3 + 0] = -0.775632f;	val_dir[15701*3 + 1] = 0.517088f;	val_dir[15701*3 + 2] = -0.361961f;
+ 	val_dir[15702*3 + 0] = -0.754329f;	val_dir[15702*3 + 1] = 0.546238f;	val_dir[15702*3 + 2] = -0.364159f;
+ 	val_dir[15703*3 + 0] = -0.731792f;	val_dir[15703*3 + 1] = 0.574979f;	val_dir[15703*3 + 2] = -0.365896f;
+ 	val_dir[15704*3 + 0] = -0.708079f;	val_dir[15704*3 + 1] = 0.603178f;	val_dir[15704*3 + 2] = -0.367152f;
+ 	val_dir[15705*3 + 0] = -0.683265f;	val_dir[15705*3 + 1] = 0.630706f;	val_dir[15705*3 + 2] = -0.367912f;
+ 	val_dir[15706*3 + 0] = -0.657440f;	val_dir[15706*3 + 1] = 0.657440f;	val_dir[15706*3 + 2] = -0.368166f;
+ 	val_dir[15707*3 + 0] = -0.630706f;	val_dir[15707*3 + 1] = 0.683265f;	val_dir[15707*3 + 2] = -0.367912f;
+ 	val_dir[15708*3 + 0] = -0.603178f;	val_dir[15708*3 + 1] = 0.708079f;	val_dir[15708*3 + 2] = -0.367152f;
+ 	val_dir[15709*3 + 0] = -0.574979f;	val_dir[15709*3 + 1] = 0.731792f;	val_dir[15709*3 + 2] = -0.365896f;
+ 	val_dir[15710*3 + 0] = -0.546238f;	val_dir[15710*3 + 1] = 0.754329f;	val_dir[15710*3 + 2] = -0.364159f;
+ 	val_dir[15711*3 + 0] = -0.517088f;	val_dir[15711*3 + 1] = 0.775632f;	val_dir[15711*3 + 2] = -0.361961f;
+ 	val_dir[15712*3 + 0] = -0.487661f;	val_dir[15712*3 + 1] = 0.795657f;	val_dir[15712*3 + 2] = -0.359329f;
+ 	val_dir[15713*3 + 0] = -0.458088f;	val_dir[15713*3 + 1] = 0.814379f;	val_dir[15713*3 + 2] = -0.356291f;
+ 	val_dir[15714*3 + 0] = -0.428496f;	val_dir[15714*3 + 1] = 0.831786f;	val_dir[15714*3 + 2] = -0.352879f;
+ 	val_dir[15715*3 + 0] = -0.399004f;	val_dir[15715*3 + 1] = 0.847883f;	val_dir[15715*3 + 2] = -0.349128f;
+ 	val_dir[15716*3 + 0] = -0.369723f;	val_dir[15716*3 + 1] = 0.862687f;	val_dir[15716*3 + 2] = -0.345075f;
+ 	val_dir[15717*3 + 0] = -0.340755f;	val_dir[15717*3 + 1] = 0.876226f;	val_dir[15717*3 + 2] = -0.340755f;
+ 	val_dir[15718*3 + 0] = -0.312190f;	val_dir[15718*3 + 1] = 0.888540f;	val_dir[15718*3 + 2] = -0.336204f;
+ 	val_dir[15719*3 + 0] = -0.284108f;	val_dir[15719*3 + 1] = 0.899676f;	val_dir[15719*3 + 2] = -0.331460f;
+ 	val_dir[15720*3 + 0] = -0.256578f;	val_dir[15720*3 + 1] = 0.909687f;	val_dir[15720*3 + 2] = -0.326554f;
+ 	val_dir[15721*3 + 0] = -0.229658f;	val_dir[15721*3 + 1] = 0.918630f;	val_dir[15721*3 + 2] = -0.321521f;
+ 	val_dir[15722*3 + 0] = -0.203393f;	val_dir[15722*3 + 1] = 0.926568f;	val_dir[15722*3 + 2] = -0.316389f;
+ 	val_dir[15723*3 + 0] = -0.177822f;	val_dir[15723*3 + 1] = 0.933564f;	val_dir[15723*3 + 2] = -0.311188f;
+ 	val_dir[15724*3 + 0] = -0.152971f;	val_dir[15724*3 + 1] = 0.939680f;	val_dir[15724*3 + 2] = -0.305942f;
+ 	val_dir[15725*3 + 0] = -0.128861f;	val_dir[15725*3 + 1] = 0.944981f;	val_dir[15725*3 + 2] = -0.300676f;
+ 	val_dir[15726*3 + 0] = -0.105503f;	val_dir[15726*3 + 1] = 0.949528f;	val_dir[15726*3 + 2] = -0.295409f;
+ 	val_dir[15727*3 + 0] = -0.082903f;	val_dir[15727*3 + 1] = 0.953381f;	val_dir[15727*3 + 2] = -0.290159f;
+ 	val_dir[15728*3 + 0] = -0.061059f;	val_dir[15728*3 + 1] = 0.956597f;	val_dir[15728*3 + 2] = -0.284944f;
+ 	val_dir[15729*3 + 0] = -0.039968f;	val_dir[15729*3 + 1] = 0.959233f;	val_dir[15729*3 + 2] = -0.279776f;
+ 	val_dir[15730*3 + 0] = -0.019619f;	val_dir[15730*3 + 1] = 0.961339f;	val_dir[15730*3 + 2] = -0.274668f;
+ 	val_dir[15731*3 + 0] = 0.0f;	val_dir[15731*3 + 1] = 0.962964f;	val_dir[15731*3 + 2] = -0.269630f;
+ 	val_dir[15732*3 + 0] = 0.019083f;	val_dir[15732*3 + 1] = 0.973240f;	val_dir[15732*3 + 2] = -0.228998f;
+ 	val_dir[15733*3 + 0] = 0.037743f;	val_dir[15733*3 + 1] = 0.981307f;	val_dir[15733*3 + 2] = -0.188713f;
+ 	val_dir[15734*3 + 0] = 0.055882f;	val_dir[15734*3 + 1] = 0.987254f;	val_dir[15734*3 + 2] = -0.149019f;
+ 	val_dir[15735*3 + 0] = 0.073422f;	val_dir[15735*3 + 1] = 0.991201f;	val_dir[15735*3 + 2] = -0.110133f;
+ 	val_dir[15736*3 + 0] = 0.090299f;	val_dir[15736*3 + 1] = 0.993291f;	val_dir[15736*3 + 2] = -0.072239f;
+ 	val_dir[15737*3 + 0] = 0.106466f;	val_dir[15737*3 + 1] = 0.993683f;	val_dir[15737*3 + 2] = -0.035489f;
+ 	val_dir[15738*3 + 0] = 0.121891f;	val_dir[15738*3 + 1] = 0.992543f;	val_dir[15738*3 + 2] = 0.0f;
+ 	val_dir[15739*3 + 0] = -0.994354f;	val_dir[15739*3 + 1] = -0.104669f;	val_dir[15739*3 + 2] = -0.017445f;
+ 	val_dir[15740*3 + 0] = -0.994623f;	val_dir[15740*3 + 1] = -0.088806f;	val_dir[15740*3 + 2] = -0.053283f;
+ 	val_dir[15741*3 + 0] = -0.993291f;	val_dir[15741*3 + 1] = -0.072239f;	val_dir[15741*3 + 2] = -0.090299f;
+ 	val_dir[15742*3 + 0] = -0.990201f;	val_dir[15742*3 + 1] = -0.055011f;	val_dir[15742*3 + 2] = -0.128359f;
+ 	val_dir[15743*3 + 0] = -0.985205f;	val_dir[15743*3 + 1] = -0.037178f;	val_dir[15743*3 + 2] = -0.167299f;
+ 	val_dir[15744*3 + 0] = -0.978177f;	val_dir[15744*3 + 1] = -0.018811f;	val_dir[15744*3 + 2] = -0.206922f;
+ 	val_dir[15745*3 + 0] = -0.969015f;	val_dir[15745*3 + 1] = 0.0f;	val_dir[15745*3 + 2] = -0.247004f;
+ 	val_dir[15746*3 + 0] = -0.967641f;	val_dir[15746*3 + 1] = 0.019353f;	val_dir[15746*3 + 2] = -0.251587f;
+ 	val_dir[15747*3 + 0] = -0.965810f;	val_dir[15747*3 + 1] = 0.039421f;	val_dir[15747*3 + 2] = -0.256235f;
+ 	val_dir[15748*3 + 0] = -0.963475f;	val_dir[15748*3 + 1] = 0.060217f;	val_dir[15748*3 + 2] = -0.260941f;
+ 	val_dir[15749*3 + 0] = -0.960585f;	val_dir[15749*3 + 1] = 0.081752f;	val_dir[15749*3 + 2] = -0.265694f;
+ 	val_dir[15750*3 + 0] = -0.957088f;	val_dir[15750*3 + 1] = 0.104031f;	val_dir[15750*3 + 2] = -0.270481f;
+ 	val_dir[15751*3 + 0] = -0.952928f;	val_dir[15751*3 + 1] = 0.127057f;	val_dir[15751*3 + 2] = -0.275290f;
+ 	val_dir[15752*3 + 0] = -0.948047f;	val_dir[15752*3 + 1] = 0.150826f;	val_dir[15752*3 + 2] = -0.280105f;
+ 	val_dir[15753*3 + 0] = -0.942384f;	val_dir[15753*3 + 1] = 0.175327f;	val_dir[15753*3 + 2] = -0.284907f;
+ 	val_dir[15754*3 + 0] = -0.935879f;	val_dir[15754*3 + 1] = 0.200545f;	val_dir[15754*3 + 2] = -0.289677f;
+ 	val_dir[15755*3 + 0] = -0.928467f;	val_dir[15755*3 + 1] = 0.226455f;	val_dir[15755*3 + 2] = -0.294392f;
+ 	val_dir[15756*3 + 0] = -0.920087f;	val_dir[15756*3 + 1] = 0.253024f;	val_dir[15756*3 + 2] = -0.299028f;
+ 	val_dir[15757*3 + 0] = -0.910678f;	val_dir[15757*3 + 1] = 0.280209f;	val_dir[15757*3 + 2] = -0.303559f;
+ 	val_dir[15758*3 + 0] = -0.900181f;	val_dir[15758*3 + 1] = 0.307957f;	val_dir[15758*3 + 2] = -0.307957f;
+ 	val_dir[15759*3 + 0] = -0.888540f;	val_dir[15759*3 + 1] = 0.336204f;	val_dir[15759*3 + 2] = -0.312190f;
+ 	val_dir[15760*3 + 0] = -0.875708f;	val_dir[15760*3 + 1] = 0.364878f;	val_dir[15760*3 + 2] = -0.316228f;
+ 	val_dir[15761*3 + 0] = -0.861640f;	val_dir[15761*3 + 1] = 0.393893f;	val_dir[15761*3 + 2] = -0.320038f;
+ 	val_dir[15762*3 + 0] = -0.846305f;	val_dir[15762*3 + 1] = 0.423153f;	val_dir[15762*3 + 2] = -0.323587f;
+ 	val_dir[15763*3 + 0] = -0.829680f;	val_dir[15763*3 + 1] = 0.452553f;	val_dir[15763*3 + 2] = -0.326844f;
+ 	val_dir[15764*3 + 0] = -0.811754f;	val_dir[15764*3 + 1] = 0.481979f;	val_dir[15764*3 + 2] = -0.329775f;
+ 	val_dir[15765*3 + 0] = -0.792530f;	val_dir[15765*3 + 1] = 0.511310f;	val_dir[15765*3 + 2] = -0.332352f;
+ 	val_dir[15766*3 + 0] = -0.772027f;	val_dir[15766*3 + 1] = 0.540419f;	val_dir[15766*3 + 2] = -0.334545f;
+ 	val_dir[15767*3 + 0] = -0.750279f;	val_dir[15767*3 + 1] = 0.569177f;	val_dir[15767*3 + 2] = -0.336332f;
+ 	val_dir[15768*3 + 0] = -0.727334f;	val_dir[15768*3 + 1] = 0.597453f;	val_dir[15768*3 + 2] = -0.337691f;
+ 	val_dir[15769*3 + 0] = -0.703259f;	val_dir[15769*3 + 1] = 0.625119f;	val_dir[15769*3 + 2] = -0.338606f;
+ 	val_dir[15770*3 + 0] = -0.678133f;	val_dir[15770*3 + 1] = 0.652051f;	val_dir[15770*3 + 2] = -0.339066f;
+ 	val_dir[15771*3 + 0] = -0.652051f;	val_dir[15771*3 + 1] = 0.678133f;	val_dir[15771*3 + 2] = -0.339066f;
+ 	val_dir[15772*3 + 0] = -0.625119f;	val_dir[15772*3 + 1] = 0.703259f;	val_dir[15772*3 + 2] = -0.338606f;
+ 	val_dir[15773*3 + 0] = -0.597453f;	val_dir[15773*3 + 1] = 0.727334f;	val_dir[15773*3 + 2] = -0.337691f;
+ 	val_dir[15774*3 + 0] = -0.569177f;	val_dir[15774*3 + 1] = 0.750279f;	val_dir[15774*3 + 2] = -0.336332f;
+ 	val_dir[15775*3 + 0] = -0.540419f;	val_dir[15775*3 + 1] = 0.772027f;	val_dir[15775*3 + 2] = -0.334545f;
+ 	val_dir[15776*3 + 0] = -0.511310f;	val_dir[15776*3 + 1] = 0.792530f;	val_dir[15776*3 + 2] = -0.332352f;
+ 	val_dir[15777*3 + 0] = -0.481979f;	val_dir[15777*3 + 1] = 0.811754f;	val_dir[15777*3 + 2] = -0.329775f;
+ 	val_dir[15778*3 + 0] = -0.452553f;	val_dir[15778*3 + 1] = 0.829680f;	val_dir[15778*3 + 2] = -0.326844f;
+ 	val_dir[15779*3 + 0] = -0.423153f;	val_dir[15779*3 + 1] = 0.846305f;	val_dir[15779*3 + 2] = -0.323587f;
+ 	val_dir[15780*3 + 0] = -0.393893f;	val_dir[15780*3 + 1] = 0.861640f;	val_dir[15780*3 + 2] = -0.320038f;
+ 	val_dir[15781*3 + 0] = -0.364878f;	val_dir[15781*3 + 1] = 0.875708f;	val_dir[15781*3 + 2] = -0.316228f;
+ 	val_dir[15782*3 + 0] = -0.336204f;	val_dir[15782*3 + 1] = 0.888540f;	val_dir[15782*3 + 2] = -0.312190f;
+ 	val_dir[15783*3 + 0] = -0.307957f;	val_dir[15783*3 + 1] = 0.900181f;	val_dir[15783*3 + 2] = -0.307957f;
+ 	val_dir[15784*3 + 0] = -0.280209f;	val_dir[15784*3 + 1] = 0.910678f;	val_dir[15784*3 + 2] = -0.303559f;
+ 	val_dir[15785*3 + 0] = -0.253024f;	val_dir[15785*3 + 1] = 0.920087f;	val_dir[15785*3 + 2] = -0.299028f;
+ 	val_dir[15786*3 + 0] = -0.226455f;	val_dir[15786*3 + 1] = 0.928467f;	val_dir[15786*3 + 2] = -0.294392f;
+ 	val_dir[15787*3 + 0] = -0.200545f;	val_dir[15787*3 + 1] = 0.935879f;	val_dir[15787*3 + 2] = -0.289677f;
+ 	val_dir[15788*3 + 0] = -0.175327f;	val_dir[15788*3 + 1] = 0.942384f;	val_dir[15788*3 + 2] = -0.284907f;
+ 	val_dir[15789*3 + 0] = -0.150826f;	val_dir[15789*3 + 1] = 0.948047f;	val_dir[15789*3 + 2] = -0.280105f;
+ 	val_dir[15790*3 + 0] = -0.127057f;	val_dir[15790*3 + 1] = 0.952928f;	val_dir[15790*3 + 2] = -0.275290f;
+ 	val_dir[15791*3 + 0] = -0.104031f;	val_dir[15791*3 + 1] = 0.957088f;	val_dir[15791*3 + 2] = -0.270481f;
+ 	val_dir[15792*3 + 0] = -0.081752f;	val_dir[15792*3 + 1] = 0.960585f;	val_dir[15792*3 + 2] = -0.265694f;
+ 	val_dir[15793*3 + 0] = -0.060217f;	val_dir[15793*3 + 1] = 0.963475f;	val_dir[15793*3 + 2] = -0.260941f;
+ 	val_dir[15794*3 + 0] = -0.039421f;	val_dir[15794*3 + 1] = 0.965810f;	val_dir[15794*3 + 2] = -0.256235f;
+ 	val_dir[15795*3 + 0] = -0.019353f;	val_dir[15795*3 + 1] = 0.967641f;	val_dir[15795*3 + 2] = -0.251587f;
+ 	val_dir[15796*3 + 0] = 0.0f;	val_dir[15796*3 + 1] = 0.969015f;	val_dir[15796*3 + 2] = -0.247004f;
+ 	val_dir[15797*3 + 0] = 0.018811f;	val_dir[15797*3 + 1] = 0.978177f;	val_dir[15797*3 + 2] = -0.206922f;
+ 	val_dir[15798*3 + 0] = 0.037178f;	val_dir[15798*3 + 1] = 0.985205f;	val_dir[15798*3 + 2] = -0.167299f;
+ 	val_dir[15799*3 + 0] = 0.055011f;	val_dir[15799*3 + 1] = 0.990201f;	val_dir[15799*3 + 2] = -0.128359f;
+ 	val_dir[15800*3 + 0] = 0.072239f;	val_dir[15800*3 + 1] = 0.993291f;	val_dir[15800*3 + 2] = -0.090299f;
+ 	val_dir[15801*3 + 0] = 0.088806f;	val_dir[15801*3 + 1] = 0.994623f;	val_dir[15801*3 + 2] = -0.053283f;
+ 	val_dir[15802*3 + 0] = 0.104669f;	val_dir[15802*3 + 1] = 0.994354f;	val_dir[15802*3 + 2] = -0.017445f;
+ 	val_dir[15803*3 + 0] = -0.994692f;	val_dir[15803*3 + 1] = -0.102899f;	val_dir[15803*3 + 2] = 0.0f;
+ 	val_dir[15804*3 + 0] = -0.995567f;	val_dir[15804*3 + 1] = -0.087330f;	val_dir[15804*3 + 2] = -0.034932f;
+ 	val_dir[15805*3 + 0] = -0.994937f;	val_dir[15805*3 + 1] = -0.071067f;	val_dir[15805*3 + 2] = -0.071067f;
+ 	val_dir[15806*3 + 0] = -0.992644f;	val_dir[15806*3 + 1] = -0.054144f;	val_dir[15806*3 + 2] = -0.108288f;
+ 	val_dir[15807*3 + 0] = -0.988540f;	val_dir[15807*3 + 1] = -0.036613f;	val_dir[15807*3 + 2] = -0.146450f;
+ 	val_dir[15808*3 + 0] = -0.982493f;	val_dir[15808*3 + 1] = -0.018538f;	val_dir[15808*3 + 2] = -0.185376f;
+ 	val_dir[15809*3 + 0] = -0.974391f;	val_dir[15809*3 + 1] = 0.0f;	val_dir[15809*3 + 2] = -0.224860f;
+ 	val_dir[15810*3 + 0] = -0.973240f;	val_dir[15810*3 + 1] = 0.019083f;	val_dir[15810*3 + 2] = -0.228998f;
+ 	val_dir[15811*3 + 0] = -0.971653f;	val_dir[15811*3 + 1] = 0.038866f;	val_dir[15811*3 + 2] = -0.233197f;
+ 	val_dir[15812*3 + 0] = -0.969584f;	val_dir[15812*3 + 1] = 0.059362f;	val_dir[15812*3 + 2] = -0.237449f;
+ 	val_dir[15813*3 + 0] = -0.966988f;	val_dir[15813*3 + 1] = 0.080582f;	val_dir[15813*3 + 2] = -0.241747f;
+ 	val_dir[15814*3 + 0] = -0.963811f;	val_dir[15814*3 + 1] = 0.102533f;	val_dir[15814*3 + 2] = -0.246079f;
+ 	val_dir[15815*3 + 0] = -0.960001f;	val_dir[15815*3 + 1] = 0.125218f;	val_dir[15815*3 + 2] = -0.250435f;
+ 	val_dir[15816*3 + 0] = -0.955502f;	val_dir[15816*3 + 1] = 0.148634f;	val_dir[15816*3 + 2] = -0.254801f;
+ 	val_dir[15817*3 + 0] = -0.950255f;	val_dir[15817*3 + 1] = 0.172774f;	val_dir[15817*3 + 2] = -0.259161f;
+ 	val_dir[15818*3 + 0] = -0.94420f;	val_dir[15818*3 + 1] = 0.197623f;	val_dir[15818*3 + 2] = -0.263498f;
+ 	val_dir[15819*3 + 0] = -0.937276f;	val_dir[15819*3 + 1] = 0.223161f;	val_dir[15819*3 + 2] = -0.267793f;
+ 	val_dir[15820*3 + 0] = -0.929421f;	val_dir[15820*3 + 1] = 0.249357f;	val_dir[15820*3 + 2] = -0.272026f;
+ 	val_dir[15821*3 + 0] = -0.920575f;	val_dir[15821*3 + 1] = 0.276172f;	val_dir[15821*3 + 2] = -0.276172f;
+ 	val_dir[15822*3 + 0] = -0.910678f;	val_dir[15822*3 + 1] = 0.303559f;	val_dir[15822*3 + 2] = -0.280209f;
+ 	val_dir[15823*3 + 0] = -0.899676f;	val_dir[15823*3 + 1] = 0.331460f;	val_dir[15823*3 + 2] = -0.284108f;
+ 	val_dir[15824*3 + 0] = -0.887517f;	val_dir[15824*3 + 1] = 0.359804f;	val_dir[15824*3 + 2] = -0.287843f;
+ 	val_dir[15825*3 + 0] = -0.874157f;	val_dir[15825*3 + 1] = 0.388514f;	val_dir[15825*3 + 2] = -0.291386f;
+ 	val_dir[15826*3 + 0] = -0.859559f;	val_dir[15826*3 + 1] = 0.41750f;	val_dir[15826*3 + 2] = -0.294706f;
+ 	val_dir[15827*3 + 0] = -0.843696f;	val_dir[15827*3 + 1] = 0.446662f;	val_dir[15827*3 + 2] = -0.297775f;
+ 	val_dir[15828*3 + 0] = -0.826551f;	val_dir[15828*3 + 1] = 0.475893f;	val_dir[15828*3 + 2] = -0.300564f;
+ 	val_dir[15829*3 + 0] = -0.808122f;	val_dir[15829*3 + 1] = 0.505076f;	val_dir[15829*3 + 2] = -0.303046f;
+ 	val_dir[15830*3 + 0] = -0.788419f;	val_dir[15830*3 + 1] = 0.534090f;	val_dir[15830*3 + 2] = -0.305194f;
+ 	val_dir[15831*3 + 0] = -0.767467f;	val_dir[15831*3 + 1] = 0.562809f;	val_dir[15831*3 + 2] = -0.306987f;
+ 	val_dir[15832*3 + 0] = -0.745307f;	val_dir[15832*3 + 1] = 0.591105f;	val_dir[15832*3 + 2] = -0.308403f;
+ 	val_dir[15833*3 + 0] = -0.721995f;	val_dir[15833*3 + 1] = 0.618853f;	val_dir[15833*3 + 2] = -0.309426f;
+ 	val_dir[15834*3 + 0] = -0.697602f;	val_dir[15834*3 + 1] = 0.645928f;	val_dir[15834*3 + 2] = -0.310045f;
+ 	val_dir[15835*3 + 0] = -0.672214f;	val_dir[15835*3 + 1] = 0.672214f;	val_dir[15835*3 + 2] = -0.310253f;
+ 	val_dir[15836*3 + 0] = -0.645928f;	val_dir[15836*3 + 1] = 0.697602f;	val_dir[15836*3 + 2] = -0.310045f;
+ 	val_dir[15837*3 + 0] = -0.618853f;	val_dir[15837*3 + 1] = 0.721995f;	val_dir[15837*3 + 2] = -0.309426f;
+ 	val_dir[15838*3 + 0] = -0.591105f;	val_dir[15838*3 + 1] = 0.745307f;	val_dir[15838*3 + 2] = -0.308403f;
+ 	val_dir[15839*3 + 0] = -0.562809f;	val_dir[15839*3 + 1] = 0.767467f;	val_dir[15839*3 + 2] = -0.306987f;
+ 	val_dir[15840*3 + 0] = -0.534090f;	val_dir[15840*3 + 1] = 0.788419f;	val_dir[15840*3 + 2] = -0.305194f;
+ 	val_dir[15841*3 + 0] = -0.505076f;	val_dir[15841*3 + 1] = 0.808122f;	val_dir[15841*3 + 2] = -0.303046f;
+ 	val_dir[15842*3 + 0] = -0.475893f;	val_dir[15842*3 + 1] = 0.826551f;	val_dir[15842*3 + 2] = -0.300564f;
+ 	val_dir[15843*3 + 0] = -0.446662f;	val_dir[15843*3 + 1] = 0.843696f;	val_dir[15843*3 + 2] = -0.297775f;
+ 	val_dir[15844*3 + 0] = -0.41750f;	val_dir[15844*3 + 1] = 0.859559f;	val_dir[15844*3 + 2] = -0.294706f;
+ 	val_dir[15845*3 + 0] = -0.388514f;	val_dir[15845*3 + 1] = 0.874157f;	val_dir[15845*3 + 2] = -0.291386f;
+ 	val_dir[15846*3 + 0] = -0.359804f;	val_dir[15846*3 + 1] = 0.887517f;	val_dir[15846*3 + 2] = -0.287843f;
+ 	val_dir[15847*3 + 0] = -0.331460f;	val_dir[15847*3 + 1] = 0.899676f;	val_dir[15847*3 + 2] = -0.284108f;
+ 	val_dir[15848*3 + 0] = -0.303559f;	val_dir[15848*3 + 1] = 0.910678f;	val_dir[15848*3 + 2] = -0.280209f;
+ 	val_dir[15849*3 + 0] = -0.276172f;	val_dir[15849*3 + 1] = 0.920575f;	val_dir[15849*3 + 2] = -0.276172f;
+ 	val_dir[15850*3 + 0] = -0.249357f;	val_dir[15850*3 + 1] = 0.929421f;	val_dir[15850*3 + 2] = -0.272026f;
+ 	val_dir[15851*3 + 0] = -0.223161f;	val_dir[15851*3 + 1] = 0.937276f;	val_dir[15851*3 + 2] = -0.267793f;
+ 	val_dir[15852*3 + 0] = -0.197623f;	val_dir[15852*3 + 1] = 0.94420f;	val_dir[15852*3 + 2] = -0.263498f;
+ 	val_dir[15853*3 + 0] = -0.172774f;	val_dir[15853*3 + 1] = 0.950255f;	val_dir[15853*3 + 2] = -0.259161f;
+ 	val_dir[15854*3 + 0] = -0.148634f;	val_dir[15854*3 + 1] = 0.955502f;	val_dir[15854*3 + 2] = -0.254801f;
+ 	val_dir[15855*3 + 0] = -0.125218f;	val_dir[15855*3 + 1] = 0.960001f;	val_dir[15855*3 + 2] = -0.250435f;
+ 	val_dir[15856*3 + 0] = -0.102533f;	val_dir[15856*3 + 1] = 0.963811f;	val_dir[15856*3 + 2] = -0.246079f;
+ 	val_dir[15857*3 + 0] = -0.080582f;	val_dir[15857*3 + 1] = 0.966988f;	val_dir[15857*3 + 2] = -0.241747f;
+ 	val_dir[15858*3 + 0] = -0.059362f;	val_dir[15858*3 + 1] = 0.969584f;	val_dir[15858*3 + 2] = -0.237449f;
+ 	val_dir[15859*3 + 0] = -0.038866f;	val_dir[15859*3 + 1] = 0.971653f;	val_dir[15859*3 + 2] = -0.233197f;
+ 	val_dir[15860*3 + 0] = -0.019083f;	val_dir[15860*3 + 1] = 0.973240f;	val_dir[15860*3 + 2] = -0.228998f;
+ 	val_dir[15861*3 + 0] = 0.0f;	val_dir[15861*3 + 1] = 0.974391f;	val_dir[15861*3 + 2] = -0.224860f;
+ 	val_dir[15862*3 + 0] = 0.018538f;	val_dir[15862*3 + 1] = 0.982493f;	val_dir[15862*3 + 2] = -0.185376f;
+ 	val_dir[15863*3 + 0] = 0.036613f;	val_dir[15863*3 + 1] = 0.988540f;	val_dir[15863*3 + 2] = -0.146450f;
+ 	val_dir[15864*3 + 0] = 0.054144f;	val_dir[15864*3 + 1] = 0.992644f;	val_dir[15864*3 + 2] = -0.108288f;
+ 	val_dir[15865*3 + 0] = 0.071067f;	val_dir[15865*3 + 1] = 0.994937f;	val_dir[15865*3 + 2] = -0.071067f;
+ 	val_dir[15866*3 + 0] = 0.087330f;	val_dir[15866*3 + 1] = 0.995567f;	val_dir[15866*3 + 2] = -0.034932f;
+ 	val_dir[15867*3 + 0] = 0.102899f;	val_dir[15867*3 + 1] = 0.994692f;	val_dir[15867*3 + 2] = 0.0f;
+ 	val_dir[15868*3 + 0] = -0.996158f;	val_dir[15868*3 + 1] = -0.085876f;	val_dir[15868*3 + 2] = -0.017175f;
+ 	val_dir[15869*3 + 0] = -0.996175f;	val_dir[15869*3 + 1] = -0.069907f;	val_dir[15869*3 + 2] = -0.052430f;
+ 	val_dir[15870*3 + 0] = -0.994623f;	val_dir[15870*3 + 1] = -0.053283f;	val_dir[15870*3 + 2] = -0.088806f;
+ 	val_dir[15871*3 + 0] = -0.991353f;	val_dir[15871*3 + 1] = -0.036049f;	val_dir[15871*3 + 2] = -0.126172f;
+ 	val_dir[15872*3 + 0] = -0.986229f;	val_dir[15872*3 + 1] = -0.018264f;	val_dir[15872*3 + 2] = -0.164372f;
+ 	val_dir[15873*3 + 0] = -0.979134f;	val_dir[15873*3 + 1] = 0.0f;	val_dir[15873*3 + 2] = -0.203216f;
+ 	val_dir[15874*3 + 0] = -0.978177f;	val_dir[15874*3 + 1] = 0.018811f;	val_dir[15874*3 + 2] = -0.206922f;
+ 	val_dir[15875*3 + 0] = -0.976804f;	val_dir[15875*3 + 1] = 0.038306f;	val_dir[15875*3 + 2] = -0.210683f;
+ 	val_dir[15876*3 + 0] = -0.974972f;	val_dir[15876*3 + 1] = 0.058498f;	val_dir[15876*3 + 2] = -0.214494f;
+ 	val_dir[15877*3 + 0] = -0.972636f;	val_dir[15877*3 + 1] = 0.079399f;	val_dir[15877*3 + 2] = -0.218347f;
+ 	val_dir[15878*3 + 0] = -0.969746f;	val_dir[15878*3 + 1] = 0.101015f;	val_dir[15878*3 + 2] = -0.222234f;
+ 	val_dir[15879*3 + 0] = -0.966252f;	val_dir[15879*3 + 1] = 0.123351f;	val_dir[15879*3 + 2] = -0.226144f;
+ 	val_dir[15880*3 + 0] = -0.962099f;	val_dir[15880*3 + 1] = 0.146406f;	val_dir[15880*3 + 2] = -0.230067f;
+ 	val_dir[15881*3 + 0] = -0.957230f;	val_dir[15881*3 + 1] = 0.170174f;	val_dir[15881*3 + 2] = -0.233990f;
+ 	val_dir[15882*3 + 0] = -0.951588f;	val_dir[15882*3 + 1] = 0.194643f;	val_dir[15882*3 + 2] = -0.237897f;
+ 	val_dir[15883*3 + 0] = -0.945112f;	val_dir[15883*3 + 1] = 0.219793f;	val_dir[15883*3 + 2] = -0.241773f;
+ 	val_dir[15884*3 + 0] = -0.937743f;	val_dir[15884*3 + 1] = 0.245599f;	val_dir[15884*3 + 2] = -0.245599f;
+ 	val_dir[15885*3 + 0] = -0.929421f;	val_dir[15885*3 + 1] = 0.272026f;	val_dir[15885*3 + 2] = -0.249357f;
+ 	val_dir[15886*3 + 0] = -0.920087f;	val_dir[15886*3 + 1] = 0.299028f;	val_dir[15886*3 + 2] = -0.253024f;
+ 	val_dir[15887*3 + 0] = -0.909687f;	val_dir[15887*3 + 1] = 0.326554f;	val_dir[15887*3 + 2] = -0.256578f;
+ 	val_dir[15888*3 + 0] = -0.898167f;	val_dir[15888*3 + 1] = 0.354540f;	val_dir[15888*3 + 2] = -0.259996f;
+ 	val_dir[15889*3 + 0] = -0.885482f;	val_dir[15889*3 + 1] = 0.382911f;	val_dir[15889*3 + 2] = -0.263251f;
+ 	val_dir[15890*3 + 0] = -0.871592f;	val_dir[15890*3 + 1] = 0.411585f;	val_dir[15890*3 + 2] = -0.266320f;
+ 	val_dir[15891*3 + 0] = -0.856465f;	val_dir[15891*3 + 1] = 0.440468f;	val_dir[15891*3 + 2] = -0.269175f;
+ 	val_dir[15892*3 + 0] = -0.840083f;	val_dir[15892*3 + 1] = 0.469458f;	val_dir[15892*3 + 2] = -0.271791f;
+ 	val_dir[15893*3 + 0] = -0.822434f;	val_dir[15893*3 + 1] = 0.498445f;	val_dir[15893*3 + 2] = -0.274145f;
+ 	val_dir[15894*3 + 0] = -0.803523f;	val_dir[15894*3 + 1] = 0.527312f;	val_dir[15894*3 + 2] = -0.276211f;
+ 	val_dir[15895*3 + 0] = -0.783368f;	val_dir[15895*3 + 1] = 0.555939f;	val_dir[15895*3 + 2] = -0.277969f;
+ 	val_dir[15896*3 + 0] = -0.762001f;	val_dir[15896*3 + 1] = 0.584201f;	val_dir[15896*3 + 2] = -0.27940f;
+ 	val_dir[15897*3 + 0] = -0.739469f;	val_dir[15897*3 + 1] = 0.611974f;	val_dir[15897*3 + 2] = -0.280488f;
+ 	val_dir[15898*3 + 0] = -0.715834f;	val_dir[15898*3 + 1] = 0.639138f;	val_dir[15898*3 + 2] = -0.281220f;
+ 	val_dir[15899*3 + 0] = -0.691173f;	val_dir[15899*3 + 1] = 0.665574f;	val_dir[15899*3 + 2] = -0.281589f;
+ 	val_dir[15900*3 + 0] = -0.665574f;	val_dir[15900*3 + 1] = 0.691173f;	val_dir[15900*3 + 2] = -0.281589f;
+ 	val_dir[15901*3 + 0] = -0.639138f;	val_dir[15901*3 + 1] = 0.715834f;	val_dir[15901*3 + 2] = -0.281220f;
+ 	val_dir[15902*3 + 0] = -0.611974f;	val_dir[15902*3 + 1] = 0.739469f;	val_dir[15902*3 + 2] = -0.280488f;
+ 	val_dir[15903*3 + 0] = -0.584201f;	val_dir[15903*3 + 1] = 0.762001f;	val_dir[15903*3 + 2] = -0.27940f;
+ 	val_dir[15904*3 + 0] = -0.555939f;	val_dir[15904*3 + 1] = 0.783368f;	val_dir[15904*3 + 2] = -0.277969f;
+ 	val_dir[15905*3 + 0] = -0.527312f;	val_dir[15905*3 + 1] = 0.803523f;	val_dir[15905*3 + 2] = -0.276211f;
+ 	val_dir[15906*3 + 0] = -0.498445f;	val_dir[15906*3 + 1] = 0.822434f;	val_dir[15906*3 + 2] = -0.274145f;
+ 	val_dir[15907*3 + 0] = -0.469458f;	val_dir[15907*3 + 1] = 0.840083f;	val_dir[15907*3 + 2] = -0.271791f;
+ 	val_dir[15908*3 + 0] = -0.440468f;	val_dir[15908*3 + 1] = 0.856465f;	val_dir[15908*3 + 2] = -0.269175f;
+ 	val_dir[15909*3 + 0] = -0.411585f;	val_dir[15909*3 + 1] = 0.871592f;	val_dir[15909*3 + 2] = -0.266320f;
+ 	val_dir[15910*3 + 0] = -0.382911f;	val_dir[15910*3 + 1] = 0.885482f;	val_dir[15910*3 + 2] = -0.263251f;
+ 	val_dir[15911*3 + 0] = -0.354540f;	val_dir[15911*3 + 1] = 0.898167f;	val_dir[15911*3 + 2] = -0.259996f;
+ 	val_dir[15912*3 + 0] = -0.326554f;	val_dir[15912*3 + 1] = 0.909687f;	val_dir[15912*3 + 2] = -0.256578f;
+ 	val_dir[15913*3 + 0] = -0.299028f;	val_dir[15913*3 + 1] = 0.920087f;	val_dir[15913*3 + 2] = -0.253024f;
+ 	val_dir[15914*3 + 0] = -0.272026f;	val_dir[15914*3 + 1] = 0.929421f;	val_dir[15914*3 + 2] = -0.249357f;
+ 	val_dir[15915*3 + 0] = -0.245599f;	val_dir[15915*3 + 1] = 0.937743f;	val_dir[15915*3 + 2] = -0.245599f;
+ 	val_dir[15916*3 + 0] = -0.219793f;	val_dir[15916*3 + 1] = 0.945112f;	val_dir[15916*3 + 2] = -0.241773f;
+ 	val_dir[15917*3 + 0] = -0.194643f;	val_dir[15917*3 + 1] = 0.951588f;	val_dir[15917*3 + 2] = -0.237897f;
+ 	val_dir[15918*3 + 0] = -0.170174f;	val_dir[15918*3 + 1] = 0.957230f;	val_dir[15918*3 + 2] = -0.233990f;
+ 	val_dir[15919*3 + 0] = -0.146406f;	val_dir[15919*3 + 1] = 0.962099f;	val_dir[15919*3 + 2] = -0.230067f;
+ 	val_dir[15920*3 + 0] = -0.123351f;	val_dir[15920*3 + 1] = 0.966252f;	val_dir[15920*3 + 2] = -0.226144f;
+ 	val_dir[15921*3 + 0] = -0.101015f;	val_dir[15921*3 + 1] = 0.969746f;	val_dir[15921*3 + 2] = -0.222234f;
+ 	val_dir[15922*3 + 0] = -0.079399f;	val_dir[15922*3 + 1] = 0.972636f;	val_dir[15922*3 + 2] = -0.218347f;
+ 	val_dir[15923*3 + 0] = -0.058498f;	val_dir[15923*3 + 1] = 0.974972f;	val_dir[15923*3 + 2] = -0.214494f;
+ 	val_dir[15924*3 + 0] = -0.038306f;	val_dir[15924*3 + 1] = 0.976804f;	val_dir[15924*3 + 2] = -0.210683f;
+ 	val_dir[15925*3 + 0] = -0.018811f;	val_dir[15925*3 + 1] = 0.978177f;	val_dir[15925*3 + 2] = -0.206922f;
+ 	val_dir[15926*3 + 0] = 0.0f;	val_dir[15926*3 + 1] = 0.979134f;	val_dir[15926*3 + 2] = -0.203216f;
+ 	val_dir[15927*3 + 0] = 0.018264f;	val_dir[15927*3 + 1] = 0.986229f;	val_dir[15927*3 + 2] = -0.164372f;
+ 	val_dir[15928*3 + 0] = 0.036049f;	val_dir[15928*3 + 1] = 0.991353f;	val_dir[15928*3 + 2] = -0.126172f;
+ 	val_dir[15929*3 + 0] = 0.053283f;	val_dir[15929*3 + 1] = 0.994623f;	val_dir[15929*3 + 2] = -0.088806f;
+ 	val_dir[15930*3 + 0] = 0.069907f;	val_dir[15930*3 + 1] = 0.996175f;	val_dir[15930*3 + 2] = -0.052430f;
+ 	val_dir[15931*3 + 0] = 0.085876f;	val_dir[15931*3 + 1] = 0.996158f;	val_dir[15931*3 + 2] = -0.017175f;
+ 	val_dir[15932*3 + 0] = -0.996428f;	val_dir[15932*3 + 1] = -0.084443f;	val_dir[15932*3 + 2] = 0.0f;
+ 	val_dir[15933*3 + 0] = -0.997041f;	val_dir[15933*3 + 1] = -0.068761f;	val_dir[15933*3 + 2] = -0.034381f;
+ 	val_dir[15934*3 + 0] = -0.996175f;	val_dir[15934*3 + 1] = -0.052430f;	val_dir[15934*3 + 2] = -0.069907f;
+ 	val_dir[15935*3 + 0] = -0.993683f;	val_dir[15935*3 + 1] = -0.035489f;	val_dir[15935*3 + 2] = -0.106466f;
+ 	val_dir[15936*3 + 0] = -0.989426f;	val_dir[15936*3 + 1] = -0.017990f;	val_dir[15936*3 + 2] = -0.143917f;
+ 	val_dir[15937*3 + 0] = -0.983282f;	val_dir[15937*3 + 1] = 0.0f;	val_dir[15937*3 + 2] = -0.182089f;
+ 	val_dir[15938*3 + 0] = -0.982493f;	val_dir[15938*3 + 1] = 0.018538f;	val_dir[15938*3 + 2] = -0.185376f;
+ 	val_dir[15939*3 + 0] = -0.981307f;	val_dir[15939*3 + 1] = 0.037743f;	val_dir[15939*3 + 2] = -0.188713f;
+ 	val_dir[15940*3 + 0] = -0.979683f;	val_dir[15940*3 + 1] = 0.057628f;	val_dir[15940*3 + 2] = -0.192095f;
+ 	val_dir[15941*3 + 0] = -0.977577f;	val_dir[15941*3 + 1] = 0.078206f;	val_dir[15941*3 + 2] = -0.195515f;
+ 	val_dir[15942*3 + 0] = -0.974943f;	val_dir[15942*3 + 1] = 0.099484f;	val_dir[15942*3 + 2] = -0.198968f;
+ 	val_dir[15943*3 + 0] = -0.971732f;	val_dir[15943*3 + 1] = 0.121466f;	val_dir[15943*3 + 2] = -0.202444f;
+ 	val_dir[15944*3 + 0] = -0.967890f;	val_dir[15944*3 + 1] = 0.144154f;	val_dir[15944*3 + 2] = -0.205934f;
+ 	val_dir[15945*3 + 0] = -0.963364f;	val_dir[15945*3 + 1] = 0.167542f;	val_dir[15945*3 + 2] = -0.209427f;
+ 	val_dir[15946*3 + 0] = -0.958098f;	val_dir[15946*3 + 1] = 0.191620f;	val_dir[15946*3 + 2] = -0.212911f;
+ 	val_dir[15947*3 + 0] = -0.952033f;	val_dir[15947*3 + 1] = 0.216371f;	val_dir[15947*3 + 2] = -0.216371f;
+ 	val_dir[15948*3 + 0] = -0.945112f;	val_dir[15948*3 + 1] = 0.241773f;	val_dir[15948*3 + 2] = -0.219793f;
+ 	val_dir[15949*3 + 0] = -0.937276f;	val_dir[15949*3 + 1] = 0.267793f;	val_dir[15949*3 + 2] = -0.223161f;
+ 	val_dir[15950*3 + 0] = -0.928467f;	val_dir[15950*3 + 1] = 0.294392f;	val_dir[15950*3 + 2] = -0.226455f;
+ 	val_dir[15951*3 + 0] = -0.918630f;	val_dir[15951*3 + 1] = 0.321521f;	val_dir[15951*3 + 2] = -0.229658f;
+ 	val_dir[15952*3 + 0] = -0.907713f;	val_dir[15952*3 + 1] = 0.349121f;	val_dir[15952*3 + 2] = -0.232747f;
+ 	val_dir[15953*3 + 0] = -0.895669f;	val_dir[15953*3 + 1] = 0.377124f;	val_dir[15953*3 + 2] = -0.235702f;
+ 	val_dir[15954*3 + 0] = -0.882454f;	val_dir[15954*3 + 1] = 0.405452f;	val_dir[15954*3 + 2] = -0.238501f;
+ 	val_dir[15955*3 + 0] = -0.868037f;	val_dir[15955*3 + 1] = 0.434019f;	val_dir[15955*3 + 2] = -0.241121f;
+ 	val_dir[15956*3 + 0] = -0.852392f;	val_dir[15956*3 + 1] = 0.462727f;	val_dir[15956*3 + 2] = -0.243541f;
+ 	val_dir[15957*3 + 0] = -0.835504f;	val_dir[15957*3 + 1] = 0.491473f;	val_dir[15957*3 + 2] = -0.245737f;
+ 	val_dir[15958*3 + 0] = -0.817373f;	val_dir[15958*3 + 1] = 0.520146f;	val_dir[15958*3 + 2] = -0.247689f;
+ 	val_dir[15959*3 + 0] = -0.798007f;	val_dir[15959*3 + 1] = 0.548630f;	val_dir[15959*3 + 2] = -0.249377f;
+ 	val_dir[15960*3 + 0] = -0.777433f;	val_dir[15960*3 + 1] = 0.576805f;	val_dir[15960*3 + 2] = -0.250785f;
+ 	val_dir[15961*3 + 0] = -0.755689f;	val_dir[15961*3 + 1] = 0.604551f;	val_dir[15961*3 + 2] = -0.251896f;
+ 	val_dir[15962*3 + 0] = -0.732828f;	val_dir[15962*3 + 1] = 0.631748f;	val_dir[15962*3 + 2] = -0.252699f;
+ 	val_dir[15963*3 + 0] = -0.708918f;	val_dir[15963*3 + 1] = 0.658281f;	val_dir[15963*3 + 2] = -0.253185f;
+ 	val_dir[15964*3 + 0] = -0.684038f;	val_dir[15964*3 + 1] = 0.684038f;	val_dir[15964*3 + 2] = -0.253347f;
+ 	val_dir[15965*3 + 0] = -0.658281f;	val_dir[15965*3 + 1] = 0.708918f;	val_dir[15965*3 + 2] = -0.253185f;
+ 	val_dir[15966*3 + 0] = -0.631748f;	val_dir[15966*3 + 1] = 0.732828f;	val_dir[15966*3 + 2] = -0.252699f;
+ 	val_dir[15967*3 + 0] = -0.604551f;	val_dir[15967*3 + 1] = 0.755689f;	val_dir[15967*3 + 2] = -0.251896f;
+ 	val_dir[15968*3 + 0] = -0.576805f;	val_dir[15968*3 + 1] = 0.777433f;	val_dir[15968*3 + 2] = -0.250785f;
+ 	val_dir[15969*3 + 0] = -0.548630f;	val_dir[15969*3 + 1] = 0.798007f;	val_dir[15969*3 + 2] = -0.249377f;
+ 	val_dir[15970*3 + 0] = -0.520146f;	val_dir[15970*3 + 1] = 0.817373f;	val_dir[15970*3 + 2] = -0.247689f;
+ 	val_dir[15971*3 + 0] = -0.491473f;	val_dir[15971*3 + 1] = 0.835504f;	val_dir[15971*3 + 2] = -0.245737f;
+ 	val_dir[15972*3 + 0] = -0.462727f;	val_dir[15972*3 + 1] = 0.852392f;	val_dir[15972*3 + 2] = -0.243541f;
+ 	val_dir[15973*3 + 0] = -0.434019f;	val_dir[15973*3 + 1] = 0.868037f;	val_dir[15973*3 + 2] = -0.241121f;
+ 	val_dir[15974*3 + 0] = -0.405452f;	val_dir[15974*3 + 1] = 0.882454f;	val_dir[15974*3 + 2] = -0.238501f;
+ 	val_dir[15975*3 + 0] = -0.377124f;	val_dir[15975*3 + 1] = 0.895669f;	val_dir[15975*3 + 2] = -0.235702f;
+ 	val_dir[15976*3 + 0] = -0.349121f;	val_dir[15976*3 + 1] = 0.907713f;	val_dir[15976*3 + 2] = -0.232747f;
+ 	val_dir[15977*3 + 0] = -0.321521f;	val_dir[15977*3 + 1] = 0.918630f;	val_dir[15977*3 + 2] = -0.229658f;
+ 	val_dir[15978*3 + 0] = -0.294392f;	val_dir[15978*3 + 1] = 0.928467f;	val_dir[15978*3 + 2] = -0.226455f;
+ 	val_dir[15979*3 + 0] = -0.267793f;	val_dir[15979*3 + 1] = 0.937276f;	val_dir[15979*3 + 2] = -0.223161f;
+ 	val_dir[15980*3 + 0] = -0.241773f;	val_dir[15980*3 + 1] = 0.945112f;	val_dir[15980*3 + 2] = -0.219793f;
+ 	val_dir[15981*3 + 0] = -0.216371f;	val_dir[15981*3 + 1] = 0.952033f;	val_dir[15981*3 + 2] = -0.216371f;
+ 	val_dir[15982*3 + 0] = -0.191620f;	val_dir[15982*3 + 1] = 0.958098f;	val_dir[15982*3 + 2] = -0.212911f;
+ 	val_dir[15983*3 + 0] = -0.167542f;	val_dir[15983*3 + 1] = 0.963364f;	val_dir[15983*3 + 2] = -0.209427f;
+ 	val_dir[15984*3 + 0] = -0.144154f;	val_dir[15984*3 + 1] = 0.967890f;	val_dir[15984*3 + 2] = -0.205934f;
+ 	val_dir[15985*3 + 0] = -0.121466f;	val_dir[15985*3 + 1] = 0.971732f;	val_dir[15985*3 + 2] = -0.202444f;
+ 	val_dir[15986*3 + 0] = -0.099484f;	val_dir[15986*3 + 1] = 0.974943f;	val_dir[15986*3 + 2] = -0.198968f;
+ 	val_dir[15987*3 + 0] = -0.078206f;	val_dir[15987*3 + 1] = 0.977577f;	val_dir[15987*3 + 2] = -0.195515f;
+ 	val_dir[15988*3 + 0] = -0.057628f;	val_dir[15988*3 + 1] = 0.979683f;	val_dir[15988*3 + 2] = -0.192095f;
+ 	val_dir[15989*3 + 0] = -0.037743f;	val_dir[15989*3 + 1] = 0.981307f;	val_dir[15989*3 + 2] = -0.188713f;
+ 	val_dir[15990*3 + 0] = -0.018538f;	val_dir[15990*3 + 1] = 0.982493f;	val_dir[15990*3 + 2] = -0.185376f;
+ 	val_dir[15991*3 + 0] = 0.0f;	val_dir[15991*3 + 1] = 0.983282f;	val_dir[15991*3 + 2] = -0.182089f;
+ 	val_dir[15992*3 + 0] = 0.017990f;	val_dir[15992*3 + 1] = 0.989426f;	val_dir[15992*3 + 2] = -0.143917f;
+ 	val_dir[15993*3 + 0] = 0.035489f;	val_dir[15993*3 + 1] = 0.993683f;	val_dir[15993*3 + 2] = -0.106466f;
+ 	val_dir[15994*3 + 0] = 0.052430f;	val_dir[15994*3 + 1] = 0.996175f;	val_dir[15994*3 + 2] = -0.069907f;
+ 	val_dir[15995*3 + 0] = 0.068761f;	val_dir[15995*3 + 1] = 0.997041f;	val_dir[15995*3 + 2] = -0.034381f;
+ 	val_dir[15996*3 + 0] = 0.084443f;	val_dir[15996*3 + 1] = 0.996428f;	val_dir[15996*3 + 2] = 0.0f;
+ 	val_dir[15997*3 + 0] = -0.997567f;	val_dir[15997*3 + 1] = -0.067632f;	val_dir[15997*3 + 2] = -0.016908f;
+ 	val_dir[15998*3 + 0] = -0.997335f;	val_dir[15998*3 + 1] = -0.051586f;	val_dir[15998*3 + 2] = -0.051586f;
+ 	val_dir[15999*3 + 0] = -0.995567f;	val_dir[15999*3 + 1] = -0.034932f;	val_dir[15999*3 + 2] = -0.087330f;
+ 	val_dir[16000*3 + 0] = -0.992122f;	val_dir[16000*3 + 1] = -0.017716f;	val_dir[16000*3 + 2] = -0.124015f;
+ 	val_dir[16001*3 + 0] = -0.986875f;	val_dir[16001*3 + 1] = 0.0f;	val_dir[16001*3 + 2] = -0.161489f;
+ 	val_dir[16002*3 + 0] = -0.986229f;	val_dir[16002*3 + 1] = 0.018264f;	val_dir[16002*3 + 2] = -0.164372f;
+ 	val_dir[16003*3 + 0] = -0.985205f;	val_dir[16003*3 + 1] = 0.037178f;	val_dir[16003*3 + 2] = -0.167299f;
+ 	val_dir[16004*3 + 0] = -0.983762f;	val_dir[16004*3 + 1] = 0.056756f;	val_dir[16004*3 + 2] = -0.170267f;
+ 	val_dir[16005*3 + 0] = -0.981859f;	val_dir[16005*3 + 1] = 0.077009f;	val_dir[16005*3 + 2] = -0.173269f;
+ 	val_dir[16006*3 + 0] = -0.979451f;	val_dir[16006*3 + 1] = 0.097945f;	val_dir[16006*3 + 2] = -0.176301f;
+ 	val_dir[16007*3 + 0] = -0.976491f;	val_dir[16007*3 + 1] = 0.119570f;	val_dir[16007*3 + 2] = -0.179355f;
+ 	val_dir[16008*3 + 0] = -0.972929f;	val_dir[16008*3 + 1] = 0.141885f;	val_dir[16008*3 + 2] = -0.182424f;
+ 	val_dir[16009*3 + 0] = -0.968712f;	val_dir[16009*3 + 1] = 0.164887f;	val_dir[16009*3 + 2] = -0.185498f;
+ 	val_dir[16010*3 + 0] = -0.963787f;	val_dir[16010*3 + 1] = 0.188567f;	val_dir[16010*3 + 2] = -0.188567f;
+ 	val_dir[16011*3 + 0] = -0.958098f;	val_dir[16011*3 + 1] = 0.212911f;	val_dir[16011*3 + 2] = -0.191620f;
+ 	val_dir[16012*3 + 0] = -0.951588f;	val_dir[16012*3 + 1] = 0.237897f;	val_dir[16012*3 + 2] = -0.194643f;
+ 	val_dir[16013*3 + 0] = -0.94420f;	val_dir[16013*3 + 1] = 0.263498f;	val_dir[16013*3 + 2] = -0.197623f;
+ 	val_dir[16014*3 + 0] = -0.935879f;	val_dir[16014*3 + 1] = 0.289677f;	val_dir[16014*3 + 2] = -0.200545f;
+ 	val_dir[16015*3 + 0] = -0.926568f;	val_dir[16015*3 + 1] = 0.316389f;	val_dir[16015*3 + 2] = -0.203393f;
+ 	val_dir[16016*3 + 0] = -0.916217f;	val_dir[16016*3 + 1] = 0.343582f;	val_dir[16016*3 + 2] = -0.206149f;
+ 	val_dir[16017*3 + 0] = -0.904777f;	val_dir[16017*3 + 1] = 0.371191f;	val_dir[16017*3 + 2] = -0.208795f;
+ 	val_dir[16018*3 + 0] = -0.892206f;	val_dir[16018*3 + 1] = 0.399145f;	val_dir[16018*3 + 2] = -0.211312f;
+ 	val_dir[16019*3 + 0] = -0.878466f;	val_dir[16019*3 + 1] = 0.427362f;	val_dir[16019*3 + 2] = -0.213681f;
+ 	val_dir[16020*3 + 0] = -0.863530f;	val_dir[16020*3 + 1] = 0.455752f;	val_dir[16020*3 + 2] = -0.215883f;
+ 	val_dir[16021*3 + 0] = -0.847381f;	val_dir[16021*3 + 1] = 0.484217f;	val_dir[16021*3 + 2] = -0.217898f;
+ 	val_dir[16022*3 + 0] = -0.830009f;	val_dir[16022*3 + 1] = 0.512653f;	val_dir[16022*3 + 2] = -0.219708f;
+ 	val_dir[16023*3 + 0] = -0.811421f;	val_dir[16023*3 + 1] = 0.540947f;	val_dir[16023*3 + 2] = -0.221297f;
+ 	val_dir[16024*3 + 0] = -0.791633f;	val_dir[16024*3 + 1] = 0.568986f;	val_dir[16024*3 + 2] = -0.222647f;
+ 	val_dir[16025*3 + 0] = -0.770677f;	val_dir[16025*3 + 1] = 0.596653f;	val_dir[16025*3 + 2] = -0.223745f;
+ 	val_dir[16026*3 + 0] = -0.748598f;	val_dir[16026*3 + 1] = 0.623831f;	val_dir[16026*3 + 2] = -0.224579f;
+ 	val_dir[16027*3 + 0] = -0.725454f;	val_dir[16027*3 + 1] = 0.650407f;	val_dir[16027*3 + 2] = -0.225141f;
+ 	val_dir[16028*3 + 0] = -0.701316f;	val_dir[16028*3 + 1] = 0.676269f;	val_dir[16028*3 + 2] = -0.225423f;
+ 	val_dir[16029*3 + 0] = -0.676269f;	val_dir[16029*3 + 1] = 0.701316f;	val_dir[16029*3 + 2] = -0.225423f;
+ 	val_dir[16030*3 + 0] = -0.650407f;	val_dir[16030*3 + 1] = 0.725454f;	val_dir[16030*3 + 2] = -0.225141f;
+ 	val_dir[16031*3 + 0] = -0.623831f;	val_dir[16031*3 + 1] = 0.748598f;	val_dir[16031*3 + 2] = -0.224579f;
+ 	val_dir[16032*3 + 0] = -0.596653f;	val_dir[16032*3 + 1] = 0.770677f;	val_dir[16032*3 + 2] = -0.223745f;
+ 	val_dir[16033*3 + 0] = -0.568986f;	val_dir[16033*3 + 1] = 0.791633f;	val_dir[16033*3 + 2] = -0.222647f;
+ 	val_dir[16034*3 + 0] = -0.540947f;	val_dir[16034*3 + 1] = 0.811421f;	val_dir[16034*3 + 2] = -0.221297f;
+ 	val_dir[16035*3 + 0] = -0.512653f;	val_dir[16035*3 + 1] = 0.830009f;	val_dir[16035*3 + 2] = -0.219708f;
+ 	val_dir[16036*3 + 0] = -0.484217f;	val_dir[16036*3 + 1] = 0.847381f;	val_dir[16036*3 + 2] = -0.217898f;
+ 	val_dir[16037*3 + 0] = -0.455752f;	val_dir[16037*3 + 1] = 0.863530f;	val_dir[16037*3 + 2] = -0.215883f;
+ 	val_dir[16038*3 + 0] = -0.427362f;	val_dir[16038*3 + 1] = 0.878466f;	val_dir[16038*3 + 2] = -0.213681f;
+ 	val_dir[16039*3 + 0] = -0.399145f;	val_dir[16039*3 + 1] = 0.892206f;	val_dir[16039*3 + 2] = -0.211312f;
+ 	val_dir[16040*3 + 0] = -0.371191f;	val_dir[16040*3 + 1] = 0.904777f;	val_dir[16040*3 + 2] = -0.208795f;
+ 	val_dir[16041*3 + 0] = -0.343582f;	val_dir[16041*3 + 1] = 0.916217f;	val_dir[16041*3 + 2] = -0.206149f;
+ 	val_dir[16042*3 + 0] = -0.316389f;	val_dir[16042*3 + 1] = 0.926568f;	val_dir[16042*3 + 2] = -0.203393f;
+ 	val_dir[16043*3 + 0] = -0.289677f;	val_dir[16043*3 + 1] = 0.935879f;	val_dir[16043*3 + 2] = -0.200545f;
+ 	val_dir[16044*3 + 0] = -0.263498f;	val_dir[16044*3 + 1] = 0.94420f;	val_dir[16044*3 + 2] = -0.197623f;
+ 	val_dir[16045*3 + 0] = -0.237897f;	val_dir[16045*3 + 1] = 0.951588f;	val_dir[16045*3 + 2] = -0.194643f;
+ 	val_dir[16046*3 + 0] = -0.212911f;	val_dir[16046*3 + 1] = 0.958098f;	val_dir[16046*3 + 2] = -0.191620f;
+ 	val_dir[16047*3 + 0] = -0.188567f;	val_dir[16047*3 + 1] = 0.963787f;	val_dir[16047*3 + 2] = -0.188567f;
+ 	val_dir[16048*3 + 0] = -0.164887f;	val_dir[16048*3 + 1] = 0.968712f;	val_dir[16048*3 + 2] = -0.185498f;
+ 	val_dir[16049*3 + 0] = -0.141885f;	val_dir[16049*3 + 1] = 0.972929f;	val_dir[16049*3 + 2] = -0.182424f;
+ 	val_dir[16050*3 + 0] = -0.119570f;	val_dir[16050*3 + 1] = 0.976491f;	val_dir[16050*3 + 2] = -0.179355f;
+ 	val_dir[16051*3 + 0] = -0.097945f;	val_dir[16051*3 + 1] = 0.979451f;	val_dir[16051*3 + 2] = -0.176301f;
+ 	val_dir[16052*3 + 0] = -0.077009f;	val_dir[16052*3 + 1] = 0.981859f;	val_dir[16052*3 + 2] = -0.173269f;
+ 	val_dir[16053*3 + 0] = -0.056756f;	val_dir[16053*3 + 1] = 0.983762f;	val_dir[16053*3 + 2] = -0.170267f;
+ 	val_dir[16054*3 + 0] = -0.037178f;	val_dir[16054*3 + 1] = 0.985205f;	val_dir[16054*3 + 2] = -0.167299f;
+ 	val_dir[16055*3 + 0] = -0.018264f;	val_dir[16055*3 + 1] = 0.986229f;	val_dir[16055*3 + 2] = -0.164372f;
+ 	val_dir[16056*3 + 0] = 0.0f;	val_dir[16056*3 + 1] = 0.986875f;	val_dir[16056*3 + 2] = -0.161489f;
+ 	val_dir[16057*3 + 0] = 0.017716f;	val_dir[16057*3 + 1] = 0.992122f;	val_dir[16057*3 + 2] = -0.124015f;
+ 	val_dir[16058*3 + 0] = 0.034932f;	val_dir[16058*3 + 1] = 0.995567f;	val_dir[16058*3 + 2] = -0.087330f;
+ 	val_dir[16059*3 + 0] = 0.051586f;	val_dir[16059*3 + 1] = 0.997335f;	val_dir[16059*3 + 2] = -0.051586f;
+ 	val_dir[16060*3 + 0] = 0.067632f;	val_dir[16060*3 + 1] = 0.997567f;	val_dir[16060*3 + 2] = -0.016908f;
+ 	val_dir[16061*3 + 0] = -0.997785f;	val_dir[16061*3 + 1] = -0.066519f;	val_dir[16061*3 + 2] = 0.0f;
+ 	val_dir[16062*3 + 0] = -0.998138f;	val_dir[16062*3 + 1] = -0.050753f;	val_dir[16062*3 + 2] = -0.033835f;
+ 	val_dir[16063*3 + 0] = -0.997041f;	val_dir[16063*3 + 1] = -0.034381f;	val_dir[16063*3 + 2] = -0.068761f;
+ 	val_dir[16064*3 + 0] = -0.994354f;	val_dir[16064*3 + 1] = -0.017445f;	val_dir[16064*3 + 2] = -0.104669f;
+ 	val_dir[16065*3 + 0] = -0.989949f;	val_dir[16065*3 + 1] = 0.0f;	val_dir[16065*3 + 2] = -0.141421f;
+ 	val_dir[16066*3 + 0] = -0.989426f;	val_dir[16066*3 + 1] = 0.017990f;	val_dir[16066*3 + 2] = -0.143917f;
+ 	val_dir[16067*3 + 0] = -0.988540f;	val_dir[16067*3 + 1] = 0.036613f;	val_dir[16067*3 + 2] = -0.146450f;
+ 	val_dir[16068*3 + 0] = -0.987254f;	val_dir[16068*3 + 1] = 0.055882f;	val_dir[16068*3 + 2] = -0.149019f;
+ 	val_dir[16069*3 + 0] = -0.985527f;	val_dir[16069*3 + 1] = 0.075810f;	val_dir[16069*3 + 2] = -0.151620f;
+ 	val_dir[16070*3 + 0] = -0.983318f;	val_dir[16070*3 + 1] = 0.096404f;	val_dir[16070*3 + 2] = -0.154246f;
+ 	val_dir[16071*3 + 0] = -0.980581f;	val_dir[16071*3 + 1] = 0.117670f;	val_dir[16071*3 + 2] = -0.156893f;
+ 	val_dir[16072*3 + 0] = -0.977267f;	val_dir[16072*3 + 1] = 0.139610f;	val_dir[16072*3 + 2] = -0.159554f;
+ 	val_dir[16073*3 + 0] = -0.973329f;	val_dir[16073*3 + 1] = 0.162221f;	val_dir[16073*3 + 2] = -0.162221f;
+ 	val_dir[16074*3 + 0] = -0.968712f;	val_dir[16074*3 + 1] = 0.185498f;	val_dir[16074*3 + 2] = -0.164887f;
+ 	val_dir[16075*3 + 0] = -0.963364f;	val_dir[16075*3 + 1] = 0.209427f;	val_dir[16075*3 + 2] = -0.167542f;
+ 	val_dir[16076*3 + 0] = -0.957230f;	val_dir[16076*3 + 1] = 0.233990f;	val_dir[16076*3 + 2] = -0.170174f;
+ 	val_dir[16077*3 + 0] = -0.950255f;	val_dir[16077*3 + 1] = 0.259161f;	val_dir[16077*3 + 2] = -0.172774f;
+ 	val_dir[16078*3 + 0] = -0.942384f;	val_dir[16078*3 + 1] = 0.284907f;	val_dir[16078*3 + 2] = -0.175327f;
+ 	val_dir[16079*3 + 0] = -0.933564f;	val_dir[16079*3 + 1] = 0.311188f;	val_dir[16079*3 + 2] = -0.177822f;
+ 	val_dir[16080*3 + 0] = -0.923742f;	val_dir[16080*3 + 1] = 0.337954f;	val_dir[16080*3 + 2] = -0.180242f;
+ 	val_dir[16081*3 + 0] = -0.912871f;	val_dir[16081*3 + 1] = 0.365148f;	val_dir[16081*3 + 2] = -0.182574f;
+ 	val_dir[16082*3 + 0] = -0.900907f;	val_dir[16082*3 + 1] = 0.392703f;	val_dir[16082*3 + 2] = -0.184801f;
+ 	val_dir[16083*3 + 0] = -0.887812f;	val_dir[16083*3 + 1] = 0.420542f;	val_dir[16083*3 + 2] = -0.186908f;
+ 	val_dir[16084*3 + 0] = -0.873555f;	val_dir[16084*3 + 1] = 0.448583f;	val_dir[16084*3 + 2] = -0.188877f;
+ 	val_dir[16085*3 + 0] = -0.858116f;	val_dir[16085*3 + 1] = 0.476731f;	val_dir[16085*3 + 2] = -0.190693f;
+ 	val_dir[16086*3 + 0] = -0.841482f;	val_dir[16086*3 + 1] = 0.504889f;	val_dir[16086*3 + 2] = -0.192339f;
+ 	val_dir[16087*3 + 0] = -0.823653f;	val_dir[16087*3 + 1] = 0.532952f;	val_dir[16087*3 + 2] = -0.193801f;
+ 	val_dir[16088*3 + 0] = -0.804639f;	val_dir[16088*3 + 1] = 0.560809f;	val_dir[16088*3 + 2] = -0.195064f;
+ 	val_dir[16089*3 + 0] = -0.784465f;	val_dir[16089*3 + 1] = 0.588348f;	val_dir[16089*3 + 2] = -0.196116f;
+ 	val_dir[16090*3 + 0] = -0.763167f;	val_dir[16090*3 + 1] = 0.615457f;	val_dir[16090*3 + 2] = -0.196946f;
+ 	val_dir[16091*3 + 0] = -0.740797f;	val_dir[16091*3 + 1] = 0.642024f;	val_dir[16091*3 + 2] = -0.197546f;
+ 	val_dir[16092*3 + 0] = -0.717418f;	val_dir[16092*3 + 1] = 0.667940f;	val_dir[16092*3 + 2] = -0.197908f;
+ 	val_dir[16093*3 + 0] = -0.693103f;	val_dir[16093*3 + 1] = 0.693103f;	val_dir[16093*3 + 2] = -0.198030f;
+ 	val_dir[16094*3 + 0] = -0.667940f;	val_dir[16094*3 + 1] = 0.717418f;	val_dir[16094*3 + 2] = -0.197908f;
+ 	val_dir[16095*3 + 0] = -0.642024f;	val_dir[16095*3 + 1] = 0.740797f;	val_dir[16095*3 + 2] = -0.197546f;
+ 	val_dir[16096*3 + 0] = -0.615457f;	val_dir[16096*3 + 1] = 0.763167f;	val_dir[16096*3 + 2] = -0.196946f;
+ 	val_dir[16097*3 + 0] = -0.588348f;	val_dir[16097*3 + 1] = 0.784465f;	val_dir[16097*3 + 2] = -0.196116f;
+ 	val_dir[16098*3 + 0] = -0.560809f;	val_dir[16098*3 + 1] = 0.804639f;	val_dir[16098*3 + 2] = -0.195064f;
+ 	val_dir[16099*3 + 0] = -0.532952f;	val_dir[16099*3 + 1] = 0.823653f;	val_dir[16099*3 + 2] = -0.193801f;
+ 	val_dir[16100*3 + 0] = -0.504889f;	val_dir[16100*3 + 1] = 0.841482f;	val_dir[16100*3 + 2] = -0.192339f;
+ 	val_dir[16101*3 + 0] = -0.476731f;	val_dir[16101*3 + 1] = 0.858116f;	val_dir[16101*3 + 2] = -0.190693f;
+ 	val_dir[16102*3 + 0] = -0.448583f;	val_dir[16102*3 + 1] = 0.873555f;	val_dir[16102*3 + 2] = -0.188877f;
+ 	val_dir[16103*3 + 0] = -0.420542f;	val_dir[16103*3 + 1] = 0.887812f;	val_dir[16103*3 + 2] = -0.186908f;
+ 	val_dir[16104*3 + 0] = -0.392703f;	val_dir[16104*3 + 1] = 0.900907f;	val_dir[16104*3 + 2] = -0.184801f;
+ 	val_dir[16105*3 + 0] = -0.365148f;	val_dir[16105*3 + 1] = 0.912871f;	val_dir[16105*3 + 2] = -0.182574f;
+ 	val_dir[16106*3 + 0] = -0.337954f;	val_dir[16106*3 + 1] = 0.923742f;	val_dir[16106*3 + 2] = -0.180242f;
+ 	val_dir[16107*3 + 0] = -0.311188f;	val_dir[16107*3 + 1] = 0.933564f;	val_dir[16107*3 + 2] = -0.177822f;
+ 	val_dir[16108*3 + 0] = -0.284907f;	val_dir[16108*3 + 1] = 0.942384f;	val_dir[16108*3 + 2] = -0.175327f;
+ 	val_dir[16109*3 + 0] = -0.259161f;	val_dir[16109*3 + 1] = 0.950255f;	val_dir[16109*3 + 2] = -0.172774f;
+ 	val_dir[16110*3 + 0] = -0.233990f;	val_dir[16110*3 + 1] = 0.957230f;	val_dir[16110*3 + 2] = -0.170174f;
+ 	val_dir[16111*3 + 0] = -0.209427f;	val_dir[16111*3 + 1] = 0.963364f;	val_dir[16111*3 + 2] = -0.167542f;
+ 	val_dir[16112*3 + 0] = -0.185498f;	val_dir[16112*3 + 1] = 0.968712f;	val_dir[16112*3 + 2] = -0.164887f;
+ 	val_dir[16113*3 + 0] = -0.162221f;	val_dir[16113*3 + 1] = 0.973329f;	val_dir[16113*3 + 2] = -0.162221f;
+ 	val_dir[16114*3 + 0] = -0.139610f;	val_dir[16114*3 + 1] = 0.977267f;	val_dir[16114*3 + 2] = -0.159554f;
+ 	val_dir[16115*3 + 0] = -0.117670f;	val_dir[16115*3 + 1] = 0.980581f;	val_dir[16115*3 + 2] = -0.156893f;
+ 	val_dir[16116*3 + 0] = -0.096404f;	val_dir[16116*3 + 1] = 0.983318f;	val_dir[16116*3 + 2] = -0.154246f;
+ 	val_dir[16117*3 + 0] = -0.075810f;	val_dir[16117*3 + 1] = 0.985527f;	val_dir[16117*3 + 2] = -0.151620f;
+ 	val_dir[16118*3 + 0] = -0.055882f;	val_dir[16118*3 + 1] = 0.987254f;	val_dir[16118*3 + 2] = -0.149019f;
+ 	val_dir[16119*3 + 0] = -0.036613f;	val_dir[16119*3 + 1] = 0.988540f;	val_dir[16119*3 + 2] = -0.146450f;
+ 	val_dir[16120*3 + 0] = -0.017990f;	val_dir[16120*3 + 1] = 0.989426f;	val_dir[16120*3 + 2] = -0.143917f;
+ 	val_dir[16121*3 + 0] = 0.0f;	val_dir[16121*3 + 1] = 0.989949f;	val_dir[16121*3 + 2] = -0.141421f;
+ 	val_dir[16122*3 + 0] = 0.017445f;	val_dir[16122*3 + 1] = 0.994354f;	val_dir[16122*3 + 2] = -0.104669f;
+ 	val_dir[16123*3 + 0] = 0.034381f;	val_dir[16123*3 + 1] = 0.997041f;	val_dir[16123*3 + 2] = -0.068761f;
+ 	val_dir[16124*3 + 0] = 0.050753f;	val_dir[16124*3 + 1] = 0.998138f;	val_dir[16124*3 + 2] = -0.033835f;
+ 	val_dir[16125*3 + 0] = 0.066519f;	val_dir[16125*3 + 1] = 0.997785f;	val_dir[16125*3 + 2] = 0.0f;
+ 	val_dir[16126*3 + 0] = -0.998614f;	val_dir[16126*3 + 1] = -0.049931f;	val_dir[16126*3 + 2] = -0.016644f;
+ 	val_dir[16127*3 + 0] = -0.998138f;	val_dir[16127*3 + 1] = -0.033835f;	val_dir[16127*3 + 2] = -0.050753f;
+ 	val_dir[16128*3 + 0] = -0.996158f;	val_dir[16128*3 + 1] = -0.017175f;	val_dir[16128*3 + 2] = -0.085876f;
+ 	val_dir[16129*3 + 0] = -0.992543f;	val_dir[16129*3 + 1] = 0.0f;	val_dir[16129*3 + 2] = -0.121891f;
+ 	val_dir[16130*3 + 0] = -0.992122f;	val_dir[16130*3 + 1] = 0.017716f;	val_dir[16130*3 + 2] = -0.124015f;
+ 	val_dir[16131*3 + 0] = -0.991353f;	val_dir[16131*3 + 1] = 0.036049f;	val_dir[16131*3 + 2] = -0.126172f;
+ 	val_dir[16132*3 + 0] = -0.990201f;	val_dir[16132*3 + 1] = 0.055011f;	val_dir[16132*3 + 2] = -0.128359f;
+ 	val_dir[16133*3 + 0] = -0.988627f;	val_dir[16133*3 + 1] = 0.074613f;	val_dir[16133*3 + 2] = -0.130573f;
+ 	val_dir[16134*3 + 0] = -0.986591f;	val_dir[16134*3 + 1] = 0.094865f;	val_dir[16134*3 + 2] = -0.132810f;
+ 	val_dir[16135*3 + 0] = -0.984050f;	val_dir[16135*3 + 1] = 0.115771f;	val_dir[16135*3 + 2] = -0.135066f;
+ 	val_dir[16136*3 + 0] = -0.980958f;	val_dir[16136*3 + 1] = 0.137334f;	val_dir[16136*3 + 2] = -0.137334f;
+ 	val_dir[16137*3 + 0] = -0.977267f;	val_dir[16137*3 + 1] = 0.159554f;	val_dir[16137*3 + 2] = -0.139610f;
+ 	val_dir[16138*3 + 0] = -0.972929f;	val_dir[16138*3 + 1] = 0.182424f;	val_dir[16138*3 + 2] = -0.141885f;
+ 	val_dir[16139*3 + 0] = -0.967890f;	val_dir[16139*3 + 1] = 0.205934f;	val_dir[16139*3 + 2] = -0.144154f;
+ 	val_dir[16140*3 + 0] = -0.962099f;	val_dir[16140*3 + 1] = 0.230067f;	val_dir[16140*3 + 2] = -0.146406f;
+ 	val_dir[16141*3 + 0] = -0.955502f;	val_dir[16141*3 + 1] = 0.254801f;	val_dir[16141*3 + 2] = -0.148634f;
+ 	val_dir[16142*3 + 0] = -0.948047f;	val_dir[16142*3 + 1] = 0.280105f;	val_dir[16142*3 + 2] = -0.150826f;
+ 	val_dir[16143*3 + 0] = -0.939680f;	val_dir[16143*3 + 1] = 0.305942f;	val_dir[16143*3 + 2] = -0.152971f;
+ 	val_dir[16144*3 + 0] = -0.930352f;	val_dir[16144*3 + 1] = 0.332269f;	val_dir[16144*3 + 2] = -0.155059f;
+ 	val_dir[16145*3 + 0] = -0.920014f;	val_dir[16145*3 + 1] = 0.359030f;	val_dir[16145*3 + 2] = -0.157075f;
+ 	val_dir[16146*3 + 0] = -0.908622f;	val_dir[16146*3 + 1] = 0.386164f;	val_dir[16146*3 + 2] = -0.159009f;
+ 	val_dir[16147*3 + 0] = -0.896137f;	val_dir[16147*3 + 1] = 0.413602f;	val_dir[16147*3 + 2] = -0.160845f;
+ 	val_dir[16148*3 + 0] = -0.882528f;	val_dir[16148*3 + 1] = 0.441264f;	val_dir[16148*3 + 2] = -0.162571f;
+ 	val_dir[16149*3 + 0] = -0.867770f;	val_dir[16149*3 + 1] = 0.469065f;	val_dir[16149*3 + 2] = -0.164173f;
+ 	val_dir[16150*3 + 0] = -0.851847f;	val_dir[16150*3 + 1] = 0.496911f;	val_dir[16150*3 + 2] = -0.165637f;
+ 	val_dir[16151*3 + 0] = -0.834754f;	val_dir[16151*3 + 1] = 0.524703f;	val_dir[16151*3 + 2] = -0.166951f;
+ 	val_dir[16152*3 + 0] = -0.816497f;	val_dir[16152*3 + 1] = 0.552336f;	val_dir[16152*3 + 2] = -0.168102f;
+ 	val_dir[16153*3 + 0] = -0.797092f;	val_dir[16153*3 + 1] = 0.579703f;	val_dir[16153*3 + 2] = -0.169080f;
+ 	val_dir[16154*3 + 0] = -0.776571f;	val_dir[16154*3 + 1] = 0.606696f;	val_dir[16154*3 + 2] = -0.169875f;
+ 	val_dir[16155*3 + 0] = -0.754976f;	val_dir[16155*3 + 1] = 0.633205f;	val_dir[16155*3 + 2] = -0.170478f;
+ 	val_dir[16156*3 + 0] = -0.732361f;	val_dir[16156*3 + 1] = 0.659125f;	val_dir[16156*3 + 2] = -0.170884f;
+ 	val_dir[16157*3 + 0] = -0.708794f;	val_dir[16157*3 + 1] = 0.684353f;	val_dir[16157*3 + 2] = -0.171088f;
+ 	val_dir[16158*3 + 0] = -0.684353f;	val_dir[16158*3 + 1] = 0.708794f;	val_dir[16158*3 + 2] = -0.171088f;
+ 	val_dir[16159*3 + 0] = -0.659125f;	val_dir[16159*3 + 1] = 0.732361f;	val_dir[16159*3 + 2] = -0.170884f;
+ 	val_dir[16160*3 + 0] = -0.633205f;	val_dir[16160*3 + 1] = 0.754976f;	val_dir[16160*3 + 2] = -0.170478f;
+ 	val_dir[16161*3 + 0] = -0.606696f;	val_dir[16161*3 + 1] = 0.776571f;	val_dir[16161*3 + 2] = -0.169875f;
+ 	val_dir[16162*3 + 0] = -0.579703f;	val_dir[16162*3 + 1] = 0.797092f;	val_dir[16162*3 + 2] = -0.169080f;
+ 	val_dir[16163*3 + 0] = -0.552336f;	val_dir[16163*3 + 1] = 0.816497f;	val_dir[16163*3 + 2] = -0.168102f;
+ 	val_dir[16164*3 + 0] = -0.524703f;	val_dir[16164*3 + 1] = 0.834754f;	val_dir[16164*3 + 2] = -0.166951f;
+ 	val_dir[16165*3 + 0] = -0.496911f;	val_dir[16165*3 + 1] = 0.851847f;	val_dir[16165*3 + 2] = -0.165637f;
+ 	val_dir[16166*3 + 0] = -0.469065f;	val_dir[16166*3 + 1] = 0.867770f;	val_dir[16166*3 + 2] = -0.164173f;
+ 	val_dir[16167*3 + 0] = -0.441264f;	val_dir[16167*3 + 1] = 0.882528f;	val_dir[16167*3 + 2] = -0.162571f;
+ 	val_dir[16168*3 + 0] = -0.413602f;	val_dir[16168*3 + 1] = 0.896137f;	val_dir[16168*3 + 2] = -0.160845f;
+ 	val_dir[16169*3 + 0] = -0.386164f;	val_dir[16169*3 + 1] = 0.908622f;	val_dir[16169*3 + 2] = -0.159009f;
+ 	val_dir[16170*3 + 0] = -0.359030f;	val_dir[16170*3 + 1] = 0.920014f;	val_dir[16170*3 + 2] = -0.157075f;
+ 	val_dir[16171*3 + 0] = -0.332269f;	val_dir[16171*3 + 1] = 0.930352f;	val_dir[16171*3 + 2] = -0.155059f;
+ 	val_dir[16172*3 + 0] = -0.305942f;	val_dir[16172*3 + 1] = 0.939680f;	val_dir[16172*3 + 2] = -0.152971f;
+ 	val_dir[16173*3 + 0] = -0.280105f;	val_dir[16173*3 + 1] = 0.948047f;	val_dir[16173*3 + 2] = -0.150826f;
+ 	val_dir[16174*3 + 0] = -0.254801f;	val_dir[16174*3 + 1] = 0.955502f;	val_dir[16174*3 + 2] = -0.148634f;
+ 	val_dir[16175*3 + 0] = -0.230067f;	val_dir[16175*3 + 1] = 0.962099f;	val_dir[16175*3 + 2] = -0.146406f;
+ 	val_dir[16176*3 + 0] = -0.205934f;	val_dir[16176*3 + 1] = 0.967890f;	val_dir[16176*3 + 2] = -0.144154f;
+ 	val_dir[16177*3 + 0] = -0.182424f;	val_dir[16177*3 + 1] = 0.972929f;	val_dir[16177*3 + 2] = -0.141885f;
+ 	val_dir[16178*3 + 0] = -0.159554f;	val_dir[16178*3 + 1] = 0.977267f;	val_dir[16178*3 + 2] = -0.139610f;
+ 	val_dir[16179*3 + 0] = -0.137334f;	val_dir[16179*3 + 1] = 0.980958f;	val_dir[16179*3 + 2] = -0.137334f;
+ 	val_dir[16180*3 + 0] = -0.115771f;	val_dir[16180*3 + 1] = 0.984050f;	val_dir[16180*3 + 2] = -0.135066f;
+ 	val_dir[16181*3 + 0] = -0.094865f;	val_dir[16181*3 + 1] = 0.986591f;	val_dir[16181*3 + 2] = -0.132810f;
+ 	val_dir[16182*3 + 0] = -0.074613f;	val_dir[16182*3 + 1] = 0.988627f;	val_dir[16182*3 + 2] = -0.130573f;
+ 	val_dir[16183*3 + 0] = -0.055011f;	val_dir[16183*3 + 1] = 0.990201f;	val_dir[16183*3 + 2] = -0.128359f;
+ 	val_dir[16184*3 + 0] = -0.036049f;	val_dir[16184*3 + 1] = 0.991353f;	val_dir[16184*3 + 2] = -0.126172f;
+ 	val_dir[16185*3 + 0] = -0.017716f;	val_dir[16185*3 + 1] = 0.992122f;	val_dir[16185*3 + 2] = -0.124015f;
+ 	val_dir[16186*3 + 0] = 0.0f;	val_dir[16186*3 + 1] = 0.992543f;	val_dir[16186*3 + 2] = -0.121891f;
+ 	val_dir[16187*3 + 0] = 0.017175f;	val_dir[16187*3 + 1] = 0.996158f;	val_dir[16187*3 + 2] = -0.085876f;
+ 	val_dir[16188*3 + 0] = 0.033835f;	val_dir[16188*3 + 1] = 0.998138f;	val_dir[16188*3 + 2] = -0.050753f;
+ 	val_dir[16189*3 + 0] = 0.049931f;	val_dir[16189*3 + 1] = 0.998614f;	val_dir[16189*3 + 2] = -0.016644f;
+ 	val_dir[16190*3 + 0] = -0.998793f;	val_dir[16190*3 + 1] = -0.049121f;	val_dir[16190*3 + 2] = 0.0f;
+ 	val_dir[16191*3 + 0] = -0.998891f;	val_dir[16191*3 + 1] = -0.033296f;	val_dir[16191*3 + 2] = -0.033296f;
+ 	val_dir[16192*3 + 0] = -0.997567f;	val_dir[16192*3 + 1] = -0.016908f;	val_dir[16192*3 + 2] = -0.067632f;
+ 	val_dir[16193*3 + 0] = -0.994692f;	val_dir[16193*3 + 1] = 0.0f;	val_dir[16193*3 + 2] = -0.102899f;
+ 	val_dir[16194*3 + 0] = -0.994354f;	val_dir[16194*3 + 1] = 0.017445f;	val_dir[16194*3 + 2] = -0.104669f;
+ 	val_dir[16195*3 + 0] = -0.993683f;	val_dir[16195*3 + 1] = 0.035489f;	val_dir[16195*3 + 2] = -0.106466f;
+ 	val_dir[16196*3 + 0] = -0.992644f;	val_dir[16196*3 + 1] = 0.054144f;	val_dir[16196*3 + 2] = -0.108288f;
+ 	val_dir[16197*3 + 0] = -0.991201f;	val_dir[16197*3 + 1] = 0.073422f;	val_dir[16197*3 + 2] = -0.110133f;
+ 	val_dir[16198*3 + 0] = -0.989316f;	val_dir[16198*3 + 1] = 0.093332f;	val_dir[16198*3 + 2] = -0.111998f;
+ 	val_dir[16199*3 + 0] = -0.986947f;	val_dir[16199*3 + 1] = 0.113878f;	val_dir[16199*3 + 2] = -0.113878f;
+ 	val_dir[16200*3 + 0] = -0.984050f;	val_dir[16200*3 + 1] = 0.135066f;	val_dir[16200*3 + 2] = -0.115771f;
+ 	val_dir[16201*3 + 0] = -0.980581f;	val_dir[16201*3 + 1] = 0.156893f;	val_dir[16201*3 + 2] = -0.117670f;
+ 	val_dir[16202*3 + 0] = -0.976491f;	val_dir[16202*3 + 1] = 0.179355f;	val_dir[16202*3 + 2] = -0.119570f;
+ 	val_dir[16203*3 + 0] = -0.971732f;	val_dir[16203*3 + 1] = 0.202444f;	val_dir[16203*3 + 2] = -0.121466f;
+ 	val_dir[16204*3 + 0] = -0.966252f;	val_dir[16204*3 + 1] = 0.226144f;	val_dir[16204*3 + 2] = -0.123351f;
+ 	val_dir[16205*3 + 0] = -0.960001f;	val_dir[16205*3 + 1] = 0.250435f;	val_dir[16205*3 + 2] = -0.125218f;
+ 	val_dir[16206*3 + 0] = -0.952928f;	val_dir[16206*3 + 1] = 0.275290f;	val_dir[16206*3 + 2] = -0.127057f;
+ 	val_dir[16207*3 + 0] = -0.944981f;	val_dir[16207*3 + 1] = 0.300676f;	val_dir[16207*3 + 2] = -0.128861f;
+ 	val_dir[16208*3 + 0] = -0.936111f;	val_dir[16208*3 + 1] = 0.326550f;	val_dir[16208*3 + 2] = -0.130620f;
+ 	val_dir[16209*3 + 0] = -0.926270f;	val_dir[16209*3 + 1] = 0.352865f;	val_dir[16209*3 + 2] = -0.132324f;
+ 	val_dir[16210*3 + 0] = -0.915416f;	val_dir[16210*3 + 1] = 0.379563f;	val_dir[16210*3 + 2] = -0.133963f;
+ 	val_dir[16211*3 + 0] = -0.903508f;	val_dir[16211*3 + 1] = 0.406579f;	val_dir[16211*3 + 2] = -0.135526f;
+ 	val_dir[16212*3 + 0] = -0.890513f;	val_dir[16212*3 + 1] = 0.433840f;	val_dir[16212*3 + 2] = -0.137002f;
+ 	val_dir[16213*3 + 0] = -0.876405f;	val_dir[16213*3 + 1] = 0.461266f;	val_dir[16213*3 + 2] = -0.138380f;
+ 	val_dir[16214*3 + 0] = -0.861164f;	val_dir[16214*3 + 1] = 0.488769f;	val_dir[16214*3 + 2] = -0.139648f;
+ 	val_dir[16215*3 + 0] = -0.844782f;	val_dir[16215*3 + 1] = 0.516256f;	val_dir[16215*3 + 2] = -0.140797f;
+ 	val_dir[16216*3 + 0] = -0.827259f;	val_dir[16216*3 + 1] = 0.543627f;	val_dir[16216*3 + 2] = -0.141816f;
+ 	val_dir[16217*3 + 0] = -0.808608f;	val_dir[16217*3 + 1] = 0.570782f;	val_dir[16217*3 + 2] = -0.142695f;
+ 	val_dir[16218*3 + 0] = -0.788851f;	val_dir[16218*3 + 1] = 0.597614f;	val_dir[16218*3 + 2] = -0.143427f;
+ 	val_dir[16219*3 + 0] = -0.768025f;	val_dir[16219*3 + 1] = 0.624020f;	val_dir[16219*3 + 2] = -0.144005f;
+ 	val_dir[16220*3 + 0] = -0.746176f;	val_dir[16220*3 + 1] = 0.649895f;	val_dir[16220*3 + 2] = -0.144421f;
+ 	val_dir[16221*3 + 0] = -0.723364f;	val_dir[16221*3 + 1] = 0.675140f;	val_dir[16221*3 + 2] = -0.144673f;
+ 	val_dir[16222*3 + 0] = -0.699659f;	val_dir[16222*3 + 1] = 0.699659f;	val_dir[16222*3 + 2] = -0.144757f;
+ 	val_dir[16223*3 + 0] = -0.675140f;	val_dir[16223*3 + 1] = 0.723364f;	val_dir[16223*3 + 2] = -0.144673f;
+ 	val_dir[16224*3 + 0] = -0.649895f;	val_dir[16224*3 + 1] = 0.746176f;	val_dir[16224*3 + 2] = -0.144421f;
+ 	val_dir[16225*3 + 0] = -0.624020f;	val_dir[16225*3 + 1] = 0.768025f;	val_dir[16225*3 + 2] = -0.144005f;
+ 	val_dir[16226*3 + 0] = -0.597614f;	val_dir[16226*3 + 1] = 0.788851f;	val_dir[16226*3 + 2] = -0.143427f;
+ 	val_dir[16227*3 + 0] = -0.570782f;	val_dir[16227*3 + 1] = 0.808608f;	val_dir[16227*3 + 2] = -0.142695f;
+ 	val_dir[16228*3 + 0] = -0.543627f;	val_dir[16228*3 + 1] = 0.827259f;	val_dir[16228*3 + 2] = -0.141816f;
+ 	val_dir[16229*3 + 0] = -0.516256f;	val_dir[16229*3 + 1] = 0.844782f;	val_dir[16229*3 + 2] = -0.140797f;
+ 	val_dir[16230*3 + 0] = -0.488769f;	val_dir[16230*3 + 1] = 0.861164f;	val_dir[16230*3 + 2] = -0.139648f;
+ 	val_dir[16231*3 + 0] = -0.461266f;	val_dir[16231*3 + 1] = 0.876405f;	val_dir[16231*3 + 2] = -0.138380f;
+ 	val_dir[16232*3 + 0] = -0.433840f;	val_dir[16232*3 + 1] = 0.890513f;	val_dir[16232*3 + 2] = -0.137002f;
+ 	val_dir[16233*3 + 0] = -0.406579f;	val_dir[16233*3 + 1] = 0.903508f;	val_dir[16233*3 + 2] = -0.135526f;
+ 	val_dir[16234*3 + 0] = -0.379563f;	val_dir[16234*3 + 1] = 0.915416f;	val_dir[16234*3 + 2] = -0.133963f;
+ 	val_dir[16235*3 + 0] = -0.352865f;	val_dir[16235*3 + 1] = 0.926270f;	val_dir[16235*3 + 2] = -0.132324f;
+ 	val_dir[16236*3 + 0] = -0.326550f;	val_dir[16236*3 + 1] = 0.936111f;	val_dir[16236*3 + 2] = -0.130620f;
+ 	val_dir[16237*3 + 0] = -0.300676f;	val_dir[16237*3 + 1] = 0.944981f;	val_dir[16237*3 + 2] = -0.128861f;
+ 	val_dir[16238*3 + 0] = -0.275290f;	val_dir[16238*3 + 1] = 0.952928f;	val_dir[16238*3 + 2] = -0.127057f;
+ 	val_dir[16239*3 + 0] = -0.250435f;	val_dir[16239*3 + 1] = 0.960001f;	val_dir[16239*3 + 2] = -0.125218f;
+ 	val_dir[16240*3 + 0] = -0.226144f;	val_dir[16240*3 + 1] = 0.966252f;	val_dir[16240*3 + 2] = -0.123351f;
+ 	val_dir[16241*3 + 0] = -0.202444f;	val_dir[16241*3 + 1] = 0.971732f;	val_dir[16241*3 + 2] = -0.121466f;
+ 	val_dir[16242*3 + 0] = -0.179355f;	val_dir[16242*3 + 1] = 0.976491f;	val_dir[16242*3 + 2] = -0.119570f;
+ 	val_dir[16243*3 + 0] = -0.156893f;	val_dir[16243*3 + 1] = 0.980581f;	val_dir[16243*3 + 2] = -0.117670f;
+ 	val_dir[16244*3 + 0] = -0.135066f;	val_dir[16244*3 + 1] = 0.984050f;	val_dir[16244*3 + 2] = -0.115771f;
+ 	val_dir[16245*3 + 0] = -0.113878f;	val_dir[16245*3 + 1] = 0.986947f;	val_dir[16245*3 + 2] = -0.113878f;
+ 	val_dir[16246*3 + 0] = -0.093332f;	val_dir[16246*3 + 1] = 0.989316f;	val_dir[16246*3 + 2] = -0.111998f;
+ 	val_dir[16247*3 + 0] = -0.073422f;	val_dir[16247*3 + 1] = 0.991201f;	val_dir[16247*3 + 2] = -0.110133f;
+ 	val_dir[16248*3 + 0] = -0.054144f;	val_dir[16248*3 + 1] = 0.992644f;	val_dir[16248*3 + 2] = -0.108288f;
+ 	val_dir[16249*3 + 0] = -0.035489f;	val_dir[16249*3 + 1] = 0.993683f;	val_dir[16249*3 + 2] = -0.106466f;
+ 	val_dir[16250*3 + 0] = -0.017445f;	val_dir[16250*3 + 1] = 0.994354f;	val_dir[16250*3 + 2] = -0.104669f;
+ 	val_dir[16251*3 + 0] = 0.0f;	val_dir[16251*3 + 1] = 0.994692f;	val_dir[16251*3 + 2] = -0.102899f;
+ 	val_dir[16252*3 + 0] = 0.016908f;	val_dir[16252*3 + 1] = 0.997567f;	val_dir[16252*3 + 2] = -0.067632f;
+ 	val_dir[16253*3 + 0] = 0.033296f;	val_dir[16253*3 + 1] = 0.998891f;	val_dir[16253*3 + 2] = -0.033296f;
+ 	val_dir[16254*3 + 0] = 0.049121f;	val_dir[16254*3 + 1] = 0.998793f;	val_dir[16254*3 + 2] = 0.0f;
+ 	val_dir[16255*3 + 0] = -0.999329f;	val_dir[16255*3 + 1] = -0.032765f;	val_dir[16255*3 + 2] = -0.016382f;
+ 	val_dir[16256*3 + 0] = -0.998614f;	val_dir[16256*3 + 1] = -0.016644f;	val_dir[16256*3 + 2] = -0.049931f;
+ 	val_dir[16257*3 + 0] = -0.996428f;	val_dir[16257*3 + 1] = 0.0f;	val_dir[16257*3 + 2] = -0.084443f;
+ 	val_dir[16258*3 + 0] = -0.996158f;	val_dir[16258*3 + 1] = 0.017175f;	val_dir[16258*3 + 2] = -0.085876f;
+ 	val_dir[16259*3 + 0] = -0.995567f;	val_dir[16259*3 + 1] = 0.034932f;	val_dir[16259*3 + 2] = -0.087330f;
+ 	val_dir[16260*3 + 0] = -0.994623f;	val_dir[16260*3 + 1] = 0.053283f;	val_dir[16260*3 + 2] = -0.088806f;
+ 	val_dir[16261*3 + 0] = -0.993291f;	val_dir[16261*3 + 1] = 0.072239f;	val_dir[16261*3 + 2] = -0.090299f;
+ 	val_dir[16262*3 + 0] = -0.991535f;	val_dir[16262*3 + 1] = 0.091809f;	val_dir[16262*3 + 2] = -0.091809f;
+ 	val_dir[16263*3 + 0] = -0.989316f;	val_dir[16263*3 + 1] = 0.111998f;	val_dir[16263*3 + 2] = -0.093332f;
+ 	val_dir[16264*3 + 0] = -0.986591f;	val_dir[16264*3 + 1] = 0.132810f;	val_dir[16264*3 + 2] = -0.094865f;
+ 	val_dir[16265*3 + 0] = -0.983318f;	val_dir[16265*3 + 1] = 0.154246f;	val_dir[16265*3 + 2] = -0.096404f;
+ 	val_dir[16266*3 + 0] = -0.979451f;	val_dir[16266*3 + 1] = 0.176301f;	val_dir[16266*3 + 2] = -0.097945f;
+ 	val_dir[16267*3 + 0] = -0.974943f;	val_dir[16267*3 + 1] = 0.198968f;	val_dir[16267*3 + 2] = -0.099484f;
+ 	val_dir[16268*3 + 0] = -0.969746f;	val_dir[16268*3 + 1] = 0.222234f;	val_dir[16268*3 + 2] = -0.101015f;
+ 	val_dir[16269*3 + 0] = -0.963811f;	val_dir[16269*3 + 1] = 0.246079f;	val_dir[16269*3 + 2] = -0.102533f;
+ 	val_dir[16270*3 + 0] = -0.957088f;	val_dir[16270*3 + 1] = 0.270481f;	val_dir[16270*3 + 2] = -0.104031f;
+ 	val_dir[16271*3 + 0] = -0.949528f;	val_dir[16271*3 + 1] = 0.295409f;	val_dir[16271*3 + 2] = -0.105503f;
+ 	val_dir[16272*3 + 0] = -0.941082f;	val_dir[16272*3 + 1] = 0.320824f;	val_dir[16272*3 + 2] = -0.106941f;
+ 	val_dir[16273*3 + 0] = -0.931705f;	val_dir[16273*3 + 1] = 0.346681f;	val_dir[16273*3 + 2] = -0.108338f;
+ 	val_dir[16274*3 + 0] = -0.921354f;	val_dir[16274*3 + 1] = 0.372929f;	val_dir[16274*3 + 2] = -0.109685f;
+ 	val_dir[16275*3 + 0] = -0.909988f;	val_dir[16275*3 + 1] = 0.399507f;	val_dir[16275*3 + 2] = -0.110974f;
+ 	val_dir[16276*3 + 0] = -0.897574f;	val_dir[16276*3 + 1] = 0.426348f;	val_dir[16276*3 + 2] = -0.112197f;
+ 	val_dir[16277*3 + 0] = -0.884083f;	val_dir[16277*3 + 1] = 0.453376f;	val_dir[16277*3 + 2] = -0.113344f;
+ 	val_dir[16278*3 + 0] = -0.869495f;	val_dir[16278*3 + 1] = 0.480510f;	val_dir[16278*3 + 2] = -0.114407f;
+ 	val_dir[16279*3 + 0] = -0.853796f;	val_dir[16279*3 + 1] = 0.507662f;	val_dir[16279*3 + 2] = -0.115378f;
+ 	val_dir[16280*3 + 0] = -0.836983f;	val_dir[16280*3 + 1] = 0.534739f;	val_dir[16280*3 + 2] = -0.116248f;
+ 	val_dir[16281*3 + 0] = -0.819064f;	val_dir[16281*3 + 1] = 0.561644f;	val_dir[16281*3 + 2] = -0.117009f;
+ 	val_dir[16282*3 + 0] = -0.800055f;	val_dir[16282*3 + 1] = 0.588276f;	val_dir[16282*3 + 2] = -0.117655f;
+ 	val_dir[16283*3 + 0] = -0.779987f;	val_dir[16283*3 + 1] = 0.614535f;	val_dir[16283*3 + 2] = -0.118180f;
+ 	val_dir[16284*3 + 0] = -0.758899f;	val_dir[16284*3 + 1] = 0.640321f;	val_dir[16284*3 + 2] = -0.118578f;
+ 	val_dir[16285*3 + 0] = -0.736843f;	val_dir[16285*3 + 1] = 0.665536f;	val_dir[16285*3 + 2] = -0.118846f;
+ 	val_dir[16286*3 + 0] = -0.713881f;	val_dir[16286*3 + 1] = 0.690085f;	val_dir[16286*3 + 2] = -0.118980f;
+ 	val_dir[16287*3 + 0] = -0.690085f;	val_dir[16287*3 + 1] = 0.713881f;	val_dir[16287*3 + 2] = -0.118980f;
+ 	val_dir[16288*3 + 0] = -0.665536f;	val_dir[16288*3 + 1] = 0.736843f;	val_dir[16288*3 + 2] = -0.118846f;
+ 	val_dir[16289*3 + 0] = -0.640321f;	val_dir[16289*3 + 1] = 0.758899f;	val_dir[16289*3 + 2] = -0.118578f;
+ 	val_dir[16290*3 + 0] = -0.614535f;	val_dir[16290*3 + 1] = 0.779987f;	val_dir[16290*3 + 2] = -0.118180f;
+ 	val_dir[16291*3 + 0] = -0.588276f;	val_dir[16291*3 + 1] = 0.800055f;	val_dir[16291*3 + 2] = -0.117655f;
+ 	val_dir[16292*3 + 0] = -0.561644f;	val_dir[16292*3 + 1] = 0.819064f;	val_dir[16292*3 + 2] = -0.117009f;
+ 	val_dir[16293*3 + 0] = -0.534739f;	val_dir[16293*3 + 1] = 0.836983f;	val_dir[16293*3 + 2] = -0.116248f;
+ 	val_dir[16294*3 + 0] = -0.507662f;	val_dir[16294*3 + 1] = 0.853796f;	val_dir[16294*3 + 2] = -0.115378f;
+ 	val_dir[16295*3 + 0] = -0.480510f;	val_dir[16295*3 + 1] = 0.869495f;	val_dir[16295*3 + 2] = -0.114407f;
+ 	val_dir[16296*3 + 0] = -0.453376f;	val_dir[16296*3 + 1] = 0.884083f;	val_dir[16296*3 + 2] = -0.113344f;
+ 	val_dir[16297*3 + 0] = -0.426348f;	val_dir[16297*3 + 1] = 0.897574f;	val_dir[16297*3 + 2] = -0.112197f;
+ 	val_dir[16298*3 + 0] = -0.399507f;	val_dir[16298*3 + 1] = 0.909988f;	val_dir[16298*3 + 2] = -0.110974f;
+ 	val_dir[16299*3 + 0] = -0.372929f;	val_dir[16299*3 + 1] = 0.921354f;	val_dir[16299*3 + 2] = -0.109685f;
+ 	val_dir[16300*3 + 0] = -0.346681f;	val_dir[16300*3 + 1] = 0.931705f;	val_dir[16300*3 + 2] = -0.108338f;
+ 	val_dir[16301*3 + 0] = -0.320824f;	val_dir[16301*3 + 1] = 0.941082f;	val_dir[16301*3 + 2] = -0.106941f;
+ 	val_dir[16302*3 + 0] = -0.295409f;	val_dir[16302*3 + 1] = 0.949528f;	val_dir[16302*3 + 2] = -0.105503f;
+ 	val_dir[16303*3 + 0] = -0.270481f;	val_dir[16303*3 + 1] = 0.957088f;	val_dir[16303*3 + 2] = -0.104031f;
+ 	val_dir[16304*3 + 0] = -0.246079f;	val_dir[16304*3 + 1] = 0.963811f;	val_dir[16304*3 + 2] = -0.102533f;
+ 	val_dir[16305*3 + 0] = -0.222234f;	val_dir[16305*3 + 1] = 0.969746f;	val_dir[16305*3 + 2] = -0.101015f;
+ 	val_dir[16306*3 + 0] = -0.198968f;	val_dir[16306*3 + 1] = 0.974943f;	val_dir[16306*3 + 2] = -0.099484f;
+ 	val_dir[16307*3 + 0] = -0.176301f;	val_dir[16307*3 + 1] = 0.979451f;	val_dir[16307*3 + 2] = -0.097945f;
+ 	val_dir[16308*3 + 0] = -0.154246f;	val_dir[16308*3 + 1] = 0.983318f;	val_dir[16308*3 + 2] = -0.096404f;
+ 	val_dir[16309*3 + 0] = -0.132810f;	val_dir[16309*3 + 1] = 0.986591f;	val_dir[16309*3 + 2] = -0.094865f;
+ 	val_dir[16310*3 + 0] = -0.111998f;	val_dir[16310*3 + 1] = 0.989316f;	val_dir[16310*3 + 2] = -0.093332f;
+ 	val_dir[16311*3 + 0] = -0.091809f;	val_dir[16311*3 + 1] = 0.991535f;	val_dir[16311*3 + 2] = -0.091809f;
+ 	val_dir[16312*3 + 0] = -0.072239f;	val_dir[16312*3 + 1] = 0.993291f;	val_dir[16312*3 + 2] = -0.090299f;
+ 	val_dir[16313*3 + 0] = -0.053283f;	val_dir[16313*3 + 1] = 0.994623f;	val_dir[16313*3 + 2] = -0.088806f;
+ 	val_dir[16314*3 + 0] = -0.034932f;	val_dir[16314*3 + 1] = 0.995567f;	val_dir[16314*3 + 2] = -0.087330f;
+ 	val_dir[16315*3 + 0] = -0.017175f;	val_dir[16315*3 + 1] = 0.996158f;	val_dir[16315*3 + 2] = -0.085876f;
+ 	val_dir[16316*3 + 0] = 0.0f;	val_dir[16316*3 + 1] = 0.996428f;	val_dir[16316*3 + 2] = -0.084443f;
+ 	val_dir[16317*3 + 0] = 0.016644f;	val_dir[16317*3 + 1] = 0.998614f;	val_dir[16317*3 + 2] = -0.049931f;
+ 	val_dir[16318*3 + 0] = 0.032765f;	val_dir[16318*3 + 1] = 0.999329f;	val_dir[16318*3 + 2] = -0.016382f;
+ 	val_dir[16319*3 + 0] = -0.999480f;	val_dir[16319*3 + 1] = -0.032241f;	val_dir[16319*3 + 2] = 0.0f;
+ 	val_dir[16320*3 + 0] = -0.999329f;	val_dir[16320*3 + 1] = -0.016382f;	val_dir[16320*3 + 2] = -0.032765f;
+ 	val_dir[16321*3 + 0] = -0.997785f;	val_dir[16321*3 + 1] = 0.0f;	val_dir[16321*3 + 2] = -0.066519f;
+ 	val_dir[16322*3 + 0] = -0.997567f;	val_dir[16322*3 + 1] = 0.016908f;	val_dir[16322*3 + 2] = -0.067632f;
+ 	val_dir[16323*3 + 0] = -0.997041f;	val_dir[16323*3 + 1] = 0.034381f;	val_dir[16323*3 + 2] = -0.068761f;
+ 	val_dir[16324*3 + 0] = -0.996175f;	val_dir[16324*3 + 1] = 0.052430f;	val_dir[16324*3 + 2] = -0.069907f;
+ 	val_dir[16325*3 + 0] = -0.994937f;	val_dir[16325*3 + 1] = 0.071067f;	val_dir[16325*3 + 2] = -0.071067f;
+ 	val_dir[16326*3 + 0] = -0.993291f;	val_dir[16326*3 + 1] = 0.090299f;	val_dir[16326*3 + 2] = -0.072239f;
+ 	val_dir[16327*3 + 0] = -0.991201f;	val_dir[16327*3 + 1] = 0.110133f;	val_dir[16327*3 + 2] = -0.073422f;
+ 	val_dir[16328*3 + 0] = -0.988627f;	val_dir[16328*3 + 1] = 0.130573f;	val_dir[16328*3 + 2] = -0.074613f;
+ 	val_dir[16329*3 + 0] = -0.985527f;	val_dir[16329*3 + 1] = 0.151620f;	val_dir[16329*3 + 2] = -0.075810f;
+ 	val_dir[16330*3 + 0] = -0.981859f;	val_dir[16330*3 + 1] = 0.173269f;	val_dir[16330*3 + 2] = -0.077009f;
+ 	val_dir[16331*3 + 0] = -0.977577f;	val_dir[16331*3 + 1] = 0.195515f;	val_dir[16331*3 + 2] = -0.078206f;
+ 	val_dir[16332*3 + 0] = -0.972636f;	val_dir[16332*3 + 1] = 0.218347f;	val_dir[16332*3 + 2] = -0.079399f;
+ 	val_dir[16333*3 + 0] = -0.966988f;	val_dir[16333*3 + 1] = 0.241747f;	val_dir[16333*3 + 2] = -0.080582f;
+ 	val_dir[16334*3 + 0] = -0.960585f;	val_dir[16334*3 + 1] = 0.265694f;	val_dir[16334*3 + 2] = -0.081752f;
+ 	val_dir[16335*3 + 0] = -0.953381f;	val_dir[16335*3 + 1] = 0.290159f;	val_dir[16335*3 + 2] = -0.082903f;
+ 	val_dir[16336*3 + 0] = -0.945328f;	val_dir[16336*3 + 1] = 0.315109f;	val_dir[16336*3 + 2] = -0.084029f;
+ 	val_dir[16337*3 + 0] = -0.936382f;	val_dir[16337*3 + 1] = 0.340503f;	val_dir[16337*3 + 2] = -0.085126f;
+ 	val_dir[16338*3 + 0] = -0.92650f;	val_dir[16338*3 + 1] = 0.366291f;	val_dir[16338*3 + 2] = -0.086186f;
+ 	val_dir[16339*3 + 0] = -0.915644f;	val_dir[16339*3 + 1] = 0.392419f;	val_dir[16339*3 + 2] = -0.087204f;
+ 	val_dir[16340*3 + 0] = -0.903777f;	val_dir[16340*3 + 1] = 0.418823f;	val_dir[16340*3 + 2] = -0.088173f;
+ 	val_dir[16341*3 + 0] = -0.890871f;	val_dir[16341*3 + 1] = 0.445435f;	val_dir[16341*3 + 2] = -0.089087f;
+ 	val_dir[16342*3 + 0] = -0.876903f;	val_dir[16342*3 + 1] = 0.472178f;	val_dir[16342*3 + 2] = -0.089939f;
+ 	val_dir[16343*3 + 0] = -0.861857f;	val_dir[16343*3 + 1] = 0.498970f;	val_dir[16343*3 + 2] = -0.090722f;
+ 	val_dir[16344*3 + 0] = -0.845728f;	val_dir[16344*3 + 1] = 0.525723f;	val_dir[16344*3 + 2] = -0.091430f;
+ 	val_dir[16345*3 + 0] = -0.828517f;	val_dir[16345*3 + 1] = 0.552345f;	val_dir[16345*3 + 2] = -0.092057f;
+ 	val_dir[16346*3 + 0] = -0.810237f;	val_dir[16346*3 + 1] = 0.578741f;	val_dir[16346*3 + 2] = -0.092599f;
+ 	val_dir[16347*3 + 0] = -0.790912f;	val_dir[16347*3 + 1] = 0.604815f;	val_dir[16347*3 + 2] = -0.093048f;
+ 	val_dir[16348*3 + 0] = -0.770574f;	val_dir[16348*3 + 1] = 0.630470f;	val_dir[16348*3 + 2] = -0.093403f;
+ 	val_dir[16349*3 + 0] = -0.749269f;	val_dir[16349*3 + 1] = 0.655610f;	val_dir[16349*3 + 2] = -0.093659f;
+ 	val_dir[16350*3 + 0] = -0.727051f;	val_dir[16350*3 + 1] = 0.680144f;	val_dir[16350*3 + 2] = -0.093813f;
+ 	val_dir[16351*3 + 0] = -0.703985f;	val_dir[16351*3 + 1] = 0.703985f;	val_dir[16351*3 + 2] = -0.093865f;
+ 	val_dir[16352*3 + 0] = -0.680144f;	val_dir[16352*3 + 1] = 0.727051f;	val_dir[16352*3 + 2] = -0.093813f;
+ 	val_dir[16353*3 + 0] = -0.655610f;	val_dir[16353*3 + 1] = 0.749269f;	val_dir[16353*3 + 2] = -0.093659f;
+ 	val_dir[16354*3 + 0] = -0.630470f;	val_dir[16354*3 + 1] = 0.770574f;	val_dir[16354*3 + 2] = -0.093403f;
+ 	val_dir[16355*3 + 0] = -0.604815f;	val_dir[16355*3 + 1] = 0.790912f;	val_dir[16355*3 + 2] = -0.093048f;
+ 	val_dir[16356*3 + 0] = -0.578741f;	val_dir[16356*3 + 1] = 0.810237f;	val_dir[16356*3 + 2] = -0.092599f;
+ 	val_dir[16357*3 + 0] = -0.552345f;	val_dir[16357*3 + 1] = 0.828517f;	val_dir[16357*3 + 2] = -0.092057f;
+ 	val_dir[16358*3 + 0] = -0.525723f;	val_dir[16358*3 + 1] = 0.845728f;	val_dir[16358*3 + 2] = -0.091430f;
+ 	val_dir[16359*3 + 0] = -0.498970f;	val_dir[16359*3 + 1] = 0.861857f;	val_dir[16359*3 + 2] = -0.090722f;
+ 	val_dir[16360*3 + 0] = -0.472178f;	val_dir[16360*3 + 1] = 0.876903f;	val_dir[16360*3 + 2] = -0.089939f;
+ 	val_dir[16361*3 + 0] = -0.445435f;	val_dir[16361*3 + 1] = 0.890871f;	val_dir[16361*3 + 2] = -0.089087f;
+ 	val_dir[16362*3 + 0] = -0.418823f;	val_dir[16362*3 + 1] = 0.903777f;	val_dir[16362*3 + 2] = -0.088173f;
+ 	val_dir[16363*3 + 0] = -0.392419f;	val_dir[16363*3 + 1] = 0.915644f;	val_dir[16363*3 + 2] = -0.087204f;
+ 	val_dir[16364*3 + 0] = -0.366291f;	val_dir[16364*3 + 1] = 0.92650f;	val_dir[16364*3 + 2] = -0.086186f;
+ 	val_dir[16365*3 + 0] = -0.340503f;	val_dir[16365*3 + 1] = 0.936382f;	val_dir[16365*3 + 2] = -0.085126f;
+ 	val_dir[16366*3 + 0] = -0.315109f;	val_dir[16366*3 + 1] = 0.945328f;	val_dir[16366*3 + 2] = -0.084029f;
+ 	val_dir[16367*3 + 0] = -0.290159f;	val_dir[16367*3 + 1] = 0.953381f;	val_dir[16367*3 + 2] = -0.082903f;
+ 	val_dir[16368*3 + 0] = -0.265694f;	val_dir[16368*3 + 1] = 0.960585f;	val_dir[16368*3 + 2] = -0.081752f;
+ 	val_dir[16369*3 + 0] = -0.241747f;	val_dir[16369*3 + 1] = 0.966988f;	val_dir[16369*3 + 2] = -0.080582f;
+ 	val_dir[16370*3 + 0] = -0.218347f;	val_dir[16370*3 + 1] = 0.972636f;	val_dir[16370*3 + 2] = -0.079399f;
+ 	val_dir[16371*3 + 0] = -0.195515f;	val_dir[16371*3 + 1] = 0.977577f;	val_dir[16371*3 + 2] = -0.078206f;
+ 	val_dir[16372*3 + 0] = -0.173269f;	val_dir[16372*3 + 1] = 0.981859f;	val_dir[16372*3 + 2] = -0.077009f;
+ 	val_dir[16373*3 + 0] = -0.151620f;	val_dir[16373*3 + 1] = 0.985527f;	val_dir[16373*3 + 2] = -0.075810f;
+ 	val_dir[16374*3 + 0] = -0.130573f;	val_dir[16374*3 + 1] = 0.988627f;	val_dir[16374*3 + 2] = -0.074613f;
+ 	val_dir[16375*3 + 0] = -0.110133f;	val_dir[16375*3 + 1] = 0.991201f;	val_dir[16375*3 + 2] = -0.073422f;
+ 	val_dir[16376*3 + 0] = -0.090299f;	val_dir[16376*3 + 1] = 0.993291f;	val_dir[16376*3 + 2] = -0.072239f;
+ 	val_dir[16377*3 + 0] = -0.071067f;	val_dir[16377*3 + 1] = 0.994937f;	val_dir[16377*3 + 2] = -0.071067f;
+ 	val_dir[16378*3 + 0] = -0.052430f;	val_dir[16378*3 + 1] = 0.996175f;	val_dir[16378*3 + 2] = -0.069907f;
+ 	val_dir[16379*3 + 0] = -0.034381f;	val_dir[16379*3 + 1] = 0.997041f;	val_dir[16379*3 + 2] = -0.068761f;
+ 	val_dir[16380*3 + 0] = -0.016908f;	val_dir[16380*3 + 1] = 0.997567f;	val_dir[16380*3 + 2] = -0.067632f;
+ 	val_dir[16381*3 + 0] = 0.0f;	val_dir[16381*3 + 1] = 0.997785f;	val_dir[16381*3 + 2] = -0.066519f;
+ 	val_dir[16382*3 + 0] = 0.016382f;	val_dir[16382*3 + 1] = 0.999329f;	val_dir[16382*3 + 2] = -0.032765f;
+ 	val_dir[16383*3 + 0] = 0.032241f;	val_dir[16383*3 + 1] = 0.999480f;	val_dir[16383*3 + 2] = 0.0f;
+ 	val_dir[16384*3 + 0] = -0.999740f;	val_dir[16384*3 + 1] = -0.016125f;	val_dir[16384*3 + 2] = -0.016125f;
+ 	val_dir[16385*3 + 0] = -0.998793f;	val_dir[16385*3 + 1] = 0.0f;	val_dir[16385*3 + 2] = -0.049121f;
+ 	val_dir[16386*3 + 0] = -0.998614f;	val_dir[16386*3 + 1] = 0.016644f;	val_dir[16386*3 + 2] = -0.049931f;
+ 	val_dir[16387*3 + 0] = -0.998138f;	val_dir[16387*3 + 1] = 0.033835f;	val_dir[16387*3 + 2] = -0.050753f;
+ 	val_dir[16388*3 + 0] = -0.997335f;	val_dir[16388*3 + 1] = 0.051586f;	val_dir[16388*3 + 2] = -0.051586f;
+ 	val_dir[16389*3 + 0] = -0.996175f;	val_dir[16389*3 + 1] = 0.069907f;	val_dir[16389*3 + 2] = -0.052430f;
+ 	val_dir[16390*3 + 0] = -0.994623f;	val_dir[16390*3 + 1] = 0.088806f;	val_dir[16390*3 + 2] = -0.053283f;
+ 	val_dir[16391*3 + 0] = -0.992644f;	val_dir[16391*3 + 1] = 0.108288f;	val_dir[16391*3 + 2] = -0.054144f;
+ 	val_dir[16392*3 + 0] = -0.990201f;	val_dir[16392*3 + 1] = 0.128359f;	val_dir[16392*3 + 2] = -0.055011f;
+ 	val_dir[16393*3 + 0] = -0.987254f;	val_dir[16393*3 + 1] = 0.149019f;	val_dir[16393*3 + 2] = -0.055882f;
+ 	val_dir[16394*3 + 0] = -0.983762f;	val_dir[16394*3 + 1] = 0.170267f;	val_dir[16394*3 + 2] = -0.056756f;
+ 	val_dir[16395*3 + 0] = -0.979683f;	val_dir[16395*3 + 1] = 0.192095f;	val_dir[16395*3 + 2] = -0.057628f;
+ 	val_dir[16396*3 + 0] = -0.974972f;	val_dir[16396*3 + 1] = 0.214494f;	val_dir[16396*3 + 2] = -0.058498f;
+ 	val_dir[16397*3 + 0] = -0.969584f;	val_dir[16397*3 + 1] = 0.237449f;	val_dir[16397*3 + 2] = -0.059362f;
+ 	val_dir[16398*3 + 0] = -0.963475f;	val_dir[16398*3 + 1] = 0.260941f;	val_dir[16398*3 + 2] = -0.060217f;
+ 	val_dir[16399*3 + 0] = -0.956597f;	val_dir[16399*3 + 1] = 0.284944f;	val_dir[16399*3 + 2] = -0.061059f;
+ 	val_dir[16400*3 + 0] = -0.948908f;	val_dir[16400*3 + 1] = 0.309426f;	val_dir[16400*3 + 2] = -0.061885f;
+ 	val_dir[16401*3 + 0] = -0.940361f;	val_dir[16401*3 + 1] = 0.334351f;	val_dir[16401*3 + 2] = -0.062691f;
+ 	val_dir[16402*3 + 0] = -0.930917f;	val_dir[16402*3 + 1] = 0.359673f;	val_dir[16402*3 + 2] = -0.063472f;
+ 	val_dir[16403*3 + 0] = -0.920537f;	val_dir[16403*3 + 1] = 0.385341f;	val_dir[16403*3 + 2] = -0.064223f;
+ 	val_dir[16404*3 + 0] = -0.909185f;	val_dir[16404*3 + 1] = 0.411298f;	val_dir[16404*3 + 2] = -0.064942f;
+ 	val_dir[16405*3 + 0] = -0.896831f;	val_dir[16405*3 + 1] = 0.437479f;	val_dir[16405*3 + 2] = -0.065622f;
+ 	val_dir[16406*3 + 0] = -0.883452f;	val_dir[16406*3 + 1] = 0.463812f;	val_dir[16406*3 + 2] = -0.066259f;
+ 	val_dir[16407*3 + 0] = -0.869030f;	val_dir[16407*3 + 1] = 0.490222f;	val_dir[16407*3 + 2] = -0.066848f;
+ 	val_dir[16408*3 + 0] = -0.853556f;	val_dir[16408*3 + 1] = 0.516626f;	val_dir[16408*3 + 2] = -0.067386f;
+ 	val_dir[16409*3 + 0] = -0.837027f;	val_dir[16409*3 + 1] = 0.542936f;	val_dir[16409*3 + 2] = -0.067867f;
+ 	val_dir[16410*3 + 0] = -0.819453f;	val_dir[16410*3 + 1] = 0.569064f;	val_dir[16410*3 + 2] = -0.068288f;
+ 	val_dir[16411*3 + 0] = -0.800850f;	val_dir[16411*3 + 1] = 0.594917f;	val_dir[16411*3 + 2] = -0.068644f;
+ 	val_dir[16412*3 + 0] = -0.781248f;	val_dir[16412*3 + 1] = 0.620403f;	val_dir[16412*3 + 2] = -0.068934f;
+ 	val_dir[16413*3 + 0] = -0.760684f;	val_dir[16413*3 + 1] = 0.645429f;	val_dir[16413*3 + 2] = -0.069153f;
+ 	val_dir[16414*3 + 0] = -0.739205f;	val_dir[16414*3 + 1] = 0.669905f;	val_dir[16414*3 + 2] = -0.069301f;
+ 	val_dir[16415*3 + 0] = -0.716871f;	val_dir[16415*3 + 1] = 0.693746f;	val_dir[16415*3 + 2] = -0.069375f;
+ 	val_dir[16416*3 + 0] = -0.693746f;	val_dir[16416*3 + 1] = 0.716871f;	val_dir[16416*3 + 2] = -0.069375f;
+ 	val_dir[16417*3 + 0] = -0.669905f;	val_dir[16417*3 + 1] = 0.739205f;	val_dir[16417*3 + 2] = -0.069301f;
+ 	val_dir[16418*3 + 0] = -0.645429f;	val_dir[16418*3 + 1] = 0.760684f;	val_dir[16418*3 + 2] = -0.069153f;
+ 	val_dir[16419*3 + 0] = -0.620403f;	val_dir[16419*3 + 1] = 0.781248f;	val_dir[16419*3 + 2] = -0.068934f;
+ 	val_dir[16420*3 + 0] = -0.594917f;	val_dir[16420*3 + 1] = 0.800850f;	val_dir[16420*3 + 2] = -0.068644f;
+ 	val_dir[16421*3 + 0] = -0.569064f;	val_dir[16421*3 + 1] = 0.819453f;	val_dir[16421*3 + 2] = -0.068288f;
+ 	val_dir[16422*3 + 0] = -0.542936f;	val_dir[16422*3 + 1] = 0.837027f;	val_dir[16422*3 + 2] = -0.067867f;
+ 	val_dir[16423*3 + 0] = -0.516626f;	val_dir[16423*3 + 1] = 0.853556f;	val_dir[16423*3 + 2] = -0.067386f;
+ 	val_dir[16424*3 + 0] = -0.490222f;	val_dir[16424*3 + 1] = 0.869030f;	val_dir[16424*3 + 2] = -0.066848f;
+ 	val_dir[16425*3 + 0] = -0.463812f;	val_dir[16425*3 + 1] = 0.883452f;	val_dir[16425*3 + 2] = -0.066259f;
+ 	val_dir[16426*3 + 0] = -0.437479f;	val_dir[16426*3 + 1] = 0.896831f;	val_dir[16426*3 + 2] = -0.065622f;
+ 	val_dir[16427*3 + 0] = -0.411298f;	val_dir[16427*3 + 1] = 0.909185f;	val_dir[16427*3 + 2] = -0.064942f;
+ 	val_dir[16428*3 + 0] = -0.385341f;	val_dir[16428*3 + 1] = 0.920537f;	val_dir[16428*3 + 2] = -0.064223f;
+ 	val_dir[16429*3 + 0] = -0.359673f;	val_dir[16429*3 + 1] = 0.930917f;	val_dir[16429*3 + 2] = -0.063472f;
+ 	val_dir[16430*3 + 0] = -0.334351f;	val_dir[16430*3 + 1] = 0.940361f;	val_dir[16430*3 + 2] = -0.062691f;
+ 	val_dir[16431*3 + 0] = -0.309426f;	val_dir[16431*3 + 1] = 0.948908f;	val_dir[16431*3 + 2] = -0.061885f;
+ 	val_dir[16432*3 + 0] = -0.284944f;	val_dir[16432*3 + 1] = 0.956597f;	val_dir[16432*3 + 2] = -0.061059f;
+ 	val_dir[16433*3 + 0] = -0.260941f;	val_dir[16433*3 + 1] = 0.963475f;	val_dir[16433*3 + 2] = -0.060217f;
+ 	val_dir[16434*3 + 0] = -0.237449f;	val_dir[16434*3 + 1] = 0.969584f;	val_dir[16434*3 + 2] = -0.059362f;
+ 	val_dir[16435*3 + 0] = -0.214494f;	val_dir[16435*3 + 1] = 0.974972f;	val_dir[16435*3 + 2] = -0.058498f;
+ 	val_dir[16436*3 + 0] = -0.192095f;	val_dir[16436*3 + 1] = 0.979683f;	val_dir[16436*3 + 2] = -0.057628f;
+ 	val_dir[16437*3 + 0] = -0.170267f;	val_dir[16437*3 + 1] = 0.983762f;	val_dir[16437*3 + 2] = -0.056756f;
+ 	val_dir[16438*3 + 0] = -0.149019f;	val_dir[16438*3 + 1] = 0.987254f;	val_dir[16438*3 + 2] = -0.055882f;
+ 	val_dir[16439*3 + 0] = -0.128359f;	val_dir[16439*3 + 1] = 0.990201f;	val_dir[16439*3 + 2] = -0.055011f;
+ 	val_dir[16440*3 + 0] = -0.108288f;	val_dir[16440*3 + 1] = 0.992644f;	val_dir[16440*3 + 2] = -0.054144f;
+ 	val_dir[16441*3 + 0] = -0.088806f;	val_dir[16441*3 + 1] = 0.994623f;	val_dir[16441*3 + 2] = -0.053283f;
+ 	val_dir[16442*3 + 0] = -0.069907f;	val_dir[16442*3 + 1] = 0.996175f;	val_dir[16442*3 + 2] = -0.052430f;
+ 	val_dir[16443*3 + 0] = -0.051586f;	val_dir[16443*3 + 1] = 0.997335f;	val_dir[16443*3 + 2] = -0.051586f;
+ 	val_dir[16444*3 + 0] = -0.033835f;	val_dir[16444*3 + 1] = 0.998138f;	val_dir[16444*3 + 2] = -0.050753f;
+ 	val_dir[16445*3 + 0] = -0.016644f;	val_dir[16445*3 + 1] = 0.998614f;	val_dir[16445*3 + 2] = -0.049931f;
+ 	val_dir[16446*3 + 0] = 0.0f;	val_dir[16446*3 + 1] = 0.998793f;	val_dir[16446*3 + 2] = -0.049121f;
+ 	val_dir[16447*3 + 0] = 0.016125f;	val_dir[16447*3 + 1] = 0.999740f;	val_dir[16447*3 + 2] = -0.016125f;
+ 	val_dir[16448*3 + 0] = -0.999874f;	val_dir[16448*3 + 1] = -0.015871f;	val_dir[16448*3 + 2] = 0.0f;
+ 	val_dir[16449*3 + 0] = -0.999480f;	val_dir[16449*3 + 1] = 0.0f;	val_dir[16449*3 + 2] = -0.032241f;
+ 	val_dir[16450*3 + 0] = -0.999329f;	val_dir[16450*3 + 1] = 0.016382f;	val_dir[16450*3 + 2] = -0.032765f;
+ 	val_dir[16451*3 + 0] = -0.998891f;	val_dir[16451*3 + 1] = 0.033296f;	val_dir[16451*3 + 2] = -0.033296f;
+ 	val_dir[16452*3 + 0] = -0.998138f;	val_dir[16452*3 + 1] = 0.050753f;	val_dir[16452*3 + 2] = -0.033835f;
+ 	val_dir[16453*3 + 0] = -0.997041f;	val_dir[16453*3 + 1] = 0.068761f;	val_dir[16453*3 + 2] = -0.034381f;
+ 	val_dir[16454*3 + 0] = -0.995567f;	val_dir[16454*3 + 1] = 0.087330f;	val_dir[16454*3 + 2] = -0.034932f;
+ 	val_dir[16455*3 + 0] = -0.993683f;	val_dir[16455*3 + 1] = 0.106466f;	val_dir[16455*3 + 2] = -0.035489f;
+ 	val_dir[16456*3 + 0] = -0.991353f;	val_dir[16456*3 + 1] = 0.126172f;	val_dir[16456*3 + 2] = -0.036049f;
+ 	val_dir[16457*3 + 0] = -0.988540f;	val_dir[16457*3 + 1] = 0.146450f;	val_dir[16457*3 + 2] = -0.036613f;
+ 	val_dir[16458*3 + 0] = -0.985205f;	val_dir[16458*3 + 1] = 0.167299f;	val_dir[16458*3 + 2] = -0.037178f;
+ 	val_dir[16459*3 + 0] = -0.981307f;	val_dir[16459*3 + 1] = 0.188713f;	val_dir[16459*3 + 2] = -0.037743f;
+ 	val_dir[16460*3 + 0] = -0.976804f;	val_dir[16460*3 + 1] = 0.210683f;	val_dir[16460*3 + 2] = -0.038306f;
+ 	val_dir[16461*3 + 0] = -0.971653f;	val_dir[16461*3 + 1] = 0.233197f;	val_dir[16461*3 + 2] = -0.038866f;
+ 	val_dir[16462*3 + 0] = -0.965810f;	val_dir[16462*3 + 1] = 0.256235f;	val_dir[16462*3 + 2] = -0.039421f;
+ 	val_dir[16463*3 + 0] = -0.959233f;	val_dir[16463*3 + 1] = 0.279776f;	val_dir[16463*3 + 2] = -0.039968f;
+ 	val_dir[16464*3 + 0] = -0.951877f;	val_dir[16464*3 + 1] = 0.303791f;	val_dir[16464*3 + 2] = -0.040505f;
+ 	val_dir[16465*3 + 0] = -0.943701f;	val_dir[16465*3 + 1] = 0.328244f;	val_dir[16465*3 + 2] = -0.041030f;
+ 	val_dir[16466*3 + 0] = -0.934665f;	val_dir[16466*3 + 1] = 0.353096f;	val_dir[16466*3 + 2] = -0.041541f;
+ 	val_dir[16467*3 + 0] = -0.924729f;	val_dir[16467*3 + 1] = 0.378298f;	val_dir[16467*3 + 2] = -0.042033f;
+ 	val_dir[16468*3 + 0] = -0.913860f;	val_dir[16468*3 + 1] = 0.403799f;	val_dir[16468*3 + 2] = -0.042505f;
+ 	val_dir[16469*3 + 0] = -0.902027f;	val_dir[16469*3 + 1] = 0.429537f;	val_dir[16469*3 + 2] = -0.042954f;
+ 	val_dir[16470*3 + 0] = -0.889206f;	val_dir[16470*3 + 1] = 0.455447f;	val_dir[16470*3 + 2] = -0.043376f;
+ 	val_dir[16471*3 + 0] = -0.875376f;	val_dir[16471*3 + 1] = 0.481457f;	val_dir[16471*3 + 2] = -0.043769f;
+ 	val_dir[16472*3 + 0] = -0.860527f;	val_dir[16472*3 + 1] = 0.507490f;	val_dir[16472*3 + 2] = -0.044130f;
+ 	val_dir[16473*3 + 0] = -0.844653f;	val_dir[16473*3 + 1] = 0.533465f;	val_dir[16473*3 + 2] = -0.044455f;
+ 	val_dir[16474*3 + 0] = -0.827759f;	val_dir[16474*3 + 1] = 0.559297f;	val_dir[16474*3 + 2] = -0.044744f;
+ 	val_dir[16475*3 + 0] = -0.809858f;	val_dir[16475*3 + 1] = 0.584898f;	val_dir[16475*3 + 2] = -0.044992f;
+ 	val_dir[16476*3 + 0] = -0.790973f;	val_dir[16476*3 + 1] = 0.610179f;	val_dir[16476*3 + 2] = -0.045198f;
+ 	val_dir[16477*3 + 0] = -0.771136f;	val_dir[16477*3 + 1] = 0.635053f;	val_dir[16477*3 + 2] = -0.045361f;
+ 	val_dir[16478*3 + 0] = -0.750388f;	val_dir[16478*3 + 1] = 0.659432f;	val_dir[16478*3 + 2] = -0.045478f;
+ 	val_dir[16479*3 + 0] = -0.728780f;	val_dir[16479*3 + 1] = 0.683231f;	val_dir[16479*3 + 2] = -0.045549f;
+ 	val_dir[16480*3 + 0] = -0.706372f;	val_dir[16480*3 + 1] = 0.706372f;	val_dir[16480*3 + 2] = -0.045572f;
+ 	val_dir[16481*3 + 0] = -0.683231f;	val_dir[16481*3 + 1] = 0.728780f;	val_dir[16481*3 + 2] = -0.045549f;
+ 	val_dir[16482*3 + 0] = -0.659432f;	val_dir[16482*3 + 1] = 0.750388f;	val_dir[16482*3 + 2] = -0.045478f;
+ 	val_dir[16483*3 + 0] = -0.635053f;	val_dir[16483*3 + 1] = 0.771136f;	val_dir[16483*3 + 2] = -0.045361f;
+ 	val_dir[16484*3 + 0] = -0.610179f;	val_dir[16484*3 + 1] = 0.790973f;	val_dir[16484*3 + 2] = -0.045198f;
+ 	val_dir[16485*3 + 0] = -0.584898f;	val_dir[16485*3 + 1] = 0.809858f;	val_dir[16485*3 + 2] = -0.044992f;
+ 	val_dir[16486*3 + 0] = -0.559297f;	val_dir[16486*3 + 1] = 0.827759f;	val_dir[16486*3 + 2] = -0.044744f;
+ 	val_dir[16487*3 + 0] = -0.533465f;	val_dir[16487*3 + 1] = 0.844653f;	val_dir[16487*3 + 2] = -0.044455f;
+ 	val_dir[16488*3 + 0] = -0.507490f;	val_dir[16488*3 + 1] = 0.860527f;	val_dir[16488*3 + 2] = -0.044130f;
+ 	val_dir[16489*3 + 0] = -0.481457f;	val_dir[16489*3 + 1] = 0.875376f;	val_dir[16489*3 + 2] = -0.043769f;
+ 	val_dir[16490*3 + 0] = -0.455447f;	val_dir[16490*3 + 1] = 0.889206f;	val_dir[16490*3 + 2] = -0.043376f;
+ 	val_dir[16491*3 + 0] = -0.429537f;	val_dir[16491*3 + 1] = 0.902027f;	val_dir[16491*3 + 2] = -0.042954f;
+ 	val_dir[16492*3 + 0] = -0.403799f;	val_dir[16492*3 + 1] = 0.913860f;	val_dir[16492*3 + 2] = -0.042505f;
+ 	val_dir[16493*3 + 0] = -0.378298f;	val_dir[16493*3 + 1] = 0.924729f;	val_dir[16493*3 + 2] = -0.042033f;
+ 	val_dir[16494*3 + 0] = -0.353096f;	val_dir[16494*3 + 1] = 0.934665f;	val_dir[16494*3 + 2] = -0.041541f;
+ 	val_dir[16495*3 + 0] = -0.328244f;	val_dir[16495*3 + 1] = 0.943701f;	val_dir[16495*3 + 2] = -0.041030f;
+ 	val_dir[16496*3 + 0] = -0.303791f;	val_dir[16496*3 + 1] = 0.951877f;	val_dir[16496*3 + 2] = -0.040505f;
+ 	val_dir[16497*3 + 0] = -0.279776f;	val_dir[16497*3 + 1] = 0.959233f;	val_dir[16497*3 + 2] = -0.039968f;
+ 	val_dir[16498*3 + 0] = -0.256235f;	val_dir[16498*3 + 1] = 0.965810f;	val_dir[16498*3 + 2] = -0.039421f;
+ 	val_dir[16499*3 + 0] = -0.233197f;	val_dir[16499*3 + 1] = 0.971653f;	val_dir[16499*3 + 2] = -0.038866f;
+ 	val_dir[16500*3 + 0] = -0.210683f;	val_dir[16500*3 + 1] = 0.976804f;	val_dir[16500*3 + 2] = -0.038306f;
+ 	val_dir[16501*3 + 0] = -0.188713f;	val_dir[16501*3 + 1] = 0.981307f;	val_dir[16501*3 + 2] = -0.037743f;
+ 	val_dir[16502*3 + 0] = -0.167299f;	val_dir[16502*3 + 1] = 0.985205f;	val_dir[16502*3 + 2] = -0.037178f;
+ 	val_dir[16503*3 + 0] = -0.146450f;	val_dir[16503*3 + 1] = 0.988540f;	val_dir[16503*3 + 2] = -0.036613f;
+ 	val_dir[16504*3 + 0] = -0.126172f;	val_dir[16504*3 + 1] = 0.991353f;	val_dir[16504*3 + 2] = -0.036049f;
+ 	val_dir[16505*3 + 0] = -0.106466f;	val_dir[16505*3 + 1] = 0.993683f;	val_dir[16505*3 + 2] = -0.035489f;
+ 	val_dir[16506*3 + 0] = -0.087330f;	val_dir[16506*3 + 1] = 0.995567f;	val_dir[16506*3 + 2] = -0.034932f;
+ 	val_dir[16507*3 + 0] = -0.068761f;	val_dir[16507*3 + 1] = 0.997041f;	val_dir[16507*3 + 2] = -0.034381f;
+ 	val_dir[16508*3 + 0] = -0.050753f;	val_dir[16508*3 + 1] = 0.998138f;	val_dir[16508*3 + 2] = -0.033835f;
+ 	val_dir[16509*3 + 0] = -0.033296f;	val_dir[16509*3 + 1] = 0.998891f;	val_dir[16509*3 + 2] = -0.033296f;
+ 	val_dir[16510*3 + 0] = -0.016382f;	val_dir[16510*3 + 1] = 0.999329f;	val_dir[16510*3 + 2] = -0.032765f;
+ 	val_dir[16511*3 + 0] = 0.0f;	val_dir[16511*3 + 1] = 0.999480f;	val_dir[16511*3 + 2] = -0.032241f;
+ 	val_dir[16512*3 + 0] = 0.015871f;	val_dir[16512*3 + 1] = 0.999874f;	val_dir[16512*3 + 2] = 0.0f;
+ 	val_dir[16513*3 + 0] = -0.999874f;	val_dir[16513*3 + 1] = 0.0f;	val_dir[16513*3 + 2] = -0.015871f;
+ 	val_dir[16514*3 + 0] = -0.999740f;	val_dir[16514*3 + 1] = 0.016125f;	val_dir[16514*3 + 2] = -0.016125f;
+ 	val_dir[16515*3 + 0] = -0.999329f;	val_dir[16515*3 + 1] = 0.032765f;	val_dir[16515*3 + 2] = -0.016382f;
+ 	val_dir[16516*3 + 0] = -0.998614f;	val_dir[16516*3 + 1] = 0.049931f;	val_dir[16516*3 + 2] = -0.016644f;
+ 	val_dir[16517*3 + 0] = -0.997567f;	val_dir[16517*3 + 1] = 0.067632f;	val_dir[16517*3 + 2] = -0.016908f;
+ 	val_dir[16518*3 + 0] = -0.996158f;	val_dir[16518*3 + 1] = 0.085876f;	val_dir[16518*3 + 2] = -0.017175f;
+ 	val_dir[16519*3 + 0] = -0.994354f;	val_dir[16519*3 + 1] = 0.104669f;	val_dir[16519*3 + 2] = -0.017445f;
+ 	val_dir[16520*3 + 0] = -0.992122f;	val_dir[16520*3 + 1] = 0.124015f;	val_dir[16520*3 + 2] = -0.017716f;
+ 	val_dir[16521*3 + 0] = -0.989426f;	val_dir[16521*3 + 1] = 0.143917f;	val_dir[16521*3 + 2] = -0.017990f;
+ 	val_dir[16522*3 + 0] = -0.986229f;	val_dir[16522*3 + 1] = 0.164372f;	val_dir[16522*3 + 2] = -0.018264f;
+ 	val_dir[16523*3 + 0] = -0.982493f;	val_dir[16523*3 + 1] = 0.185376f;	val_dir[16523*3 + 2] = -0.018538f;
+ 	val_dir[16524*3 + 0] = -0.978177f;	val_dir[16524*3 + 1] = 0.206922f;	val_dir[16524*3 + 2] = -0.018811f;
+ 	val_dir[16525*3 + 0] = -0.973240f;	val_dir[16525*3 + 1] = 0.228998f;	val_dir[16525*3 + 2] = -0.019083f;
+ 	val_dir[16526*3 + 0] = -0.967641f;	val_dir[16526*3 + 1] = 0.251587f;	val_dir[16526*3 + 2] = -0.019353f;
+ 	val_dir[16527*3 + 0] = -0.961339f;	val_dir[16527*3 + 1] = 0.274668f;	val_dir[16527*3 + 2] = -0.019619f;
+ 	val_dir[16528*3 + 0] = -0.954291f;	val_dir[16528*3 + 1] = 0.298216f;	val_dir[16528*3 + 2] = -0.019881f;
+ 	val_dir[16529*3 + 0] = -0.946458f;	val_dir[16529*3 + 1] = 0.322198f;	val_dir[16529*3 + 2] = -0.020137f;
+ 	val_dir[16530*3 + 0] = -0.93780f;	val_dir[16530*3 + 1] = 0.346578f;	val_dir[16530*3 + 2] = -0.020387f;
+ 	val_dir[16531*3 + 0] = -0.928279f;	val_dir[16531*3 + 1] = 0.371312f;	val_dir[16531*3 + 2] = -0.020628f;
+ 	val_dir[16532*3 + 0] = -0.917863f;	val_dir[16532*3 + 1] = 0.396350f;	val_dir[16532*3 + 2] = -0.020861f;
+ 	val_dir[16533*3 + 0] = -0.906520f;	val_dir[16533*3 + 1] = 0.421637f;	val_dir[16533*3 + 2] = -0.021082f;
+ 	val_dir[16534*3 + 0] = -0.894224f;	val_dir[16534*3 + 1] = 0.447112f;	val_dir[16534*3 + 2] = -0.021291f;
+ 	val_dir[16535*3 + 0] = -0.880957f;	val_dir[16535*3 + 1] = 0.472709f;	val_dir[16535*3 + 2] = -0.021487f;
+ 	val_dir[16536*3 + 0] = -0.866703f;	val_dir[16536*3 + 1] = 0.498354f;	val_dir[16536*3 + 2] = -0.021668f;
+ 	val_dir[16537*3 + 0] = -0.851455f;	val_dir[16537*3 + 1] = 0.523973f;	val_dir[16537*3 + 2] = -0.021832f;
+ 	val_dir[16538*3 + 0] = -0.835215f;	val_dir[16538*3 + 1] = 0.549484f;	val_dir[16538*3 + 2] = -0.021979f;
+ 	val_dir[16539*3 + 0] = -0.817992f;	val_dir[16539*3 + 1] = 0.574805f;	val_dir[16539*3 + 2] = -0.022108f;
+ 	val_dir[16540*3 + 0] = -0.799803f;	val_dir[16540*3 + 1] = 0.599852f;	val_dir[16540*3 + 2] = -0.022217f;
+ 	val_dir[16541*3 + 0] = -0.780675f;	val_dir[16541*3 + 1] = 0.624540f;	val_dir[16541*3 + 2] = -0.022305f;
+ 	val_dir[16542*3 + 0] = -0.760644f;	val_dir[16542*3 + 1] = 0.648784f;	val_dir[16542*3 + 2] = -0.022372f;
+ 	val_dir[16543*3 + 0] = -0.739754f;	val_dir[16543*3 + 1] = 0.672504f;	val_dir[16543*3 + 2] = -0.022417f;
+ 	val_dir[16544*3 + 0] = -0.718059f;	val_dir[16544*3 + 1] = 0.695620f;	val_dir[16544*3 + 2] = -0.022439f;
+ 	val_dir[16545*3 + 0] = -0.695620f;	val_dir[16545*3 + 1] = 0.718059f;	val_dir[16545*3 + 2] = -0.022439f;
+ 	val_dir[16546*3 + 0] = -0.672504f;	val_dir[16546*3 + 1] = 0.739754f;	val_dir[16546*3 + 2] = -0.022417f;
+ 	val_dir[16547*3 + 0] = -0.648784f;	val_dir[16547*3 + 1] = 0.760644f;	val_dir[16547*3 + 2] = -0.022372f;
+ 	val_dir[16548*3 + 0] = -0.624540f;	val_dir[16548*3 + 1] = 0.780675f;	val_dir[16548*3 + 2] = -0.022305f;
+ 	val_dir[16549*3 + 0] = -0.599852f;	val_dir[16549*3 + 1] = 0.799803f;	val_dir[16549*3 + 2] = -0.022217f;
+ 	val_dir[16550*3 + 0] = -0.574805f;	val_dir[16550*3 + 1] = 0.817992f;	val_dir[16550*3 + 2] = -0.022108f;
+ 	val_dir[16551*3 + 0] = -0.549484f;	val_dir[16551*3 + 1] = 0.835215f;	val_dir[16551*3 + 2] = -0.021979f;
+ 	val_dir[16552*3 + 0] = -0.523973f;	val_dir[16552*3 + 1] = 0.851455f;	val_dir[16552*3 + 2] = -0.021832f;
+ 	val_dir[16553*3 + 0] = -0.498354f;	val_dir[16553*3 + 1] = 0.866703f;	val_dir[16553*3 + 2] = -0.021668f;
+ 	val_dir[16554*3 + 0] = -0.472709f;	val_dir[16554*3 + 1] = 0.880957f;	val_dir[16554*3 + 2] = -0.021487f;
+ 	val_dir[16555*3 + 0] = -0.447112f;	val_dir[16555*3 + 1] = 0.894224f;	val_dir[16555*3 + 2] = -0.021291f;
+ 	val_dir[16556*3 + 0] = -0.421637f;	val_dir[16556*3 + 1] = 0.906520f;	val_dir[16556*3 + 2] = -0.021082f;
+ 	val_dir[16557*3 + 0] = -0.396350f;	val_dir[16557*3 + 1] = 0.917863f;	val_dir[16557*3 + 2] = -0.020861f;
+ 	val_dir[16558*3 + 0] = -0.371312f;	val_dir[16558*3 + 1] = 0.928279f;	val_dir[16558*3 + 2] = -0.020628f;
+ 	val_dir[16559*3 + 0] = -0.346578f;	val_dir[16559*3 + 1] = 0.93780f;	val_dir[16559*3 + 2] = -0.020387f;
+ 	val_dir[16560*3 + 0] = -0.322198f;	val_dir[16560*3 + 1] = 0.946458f;	val_dir[16560*3 + 2] = -0.020137f;
+ 	val_dir[16561*3 + 0] = -0.298216f;	val_dir[16561*3 + 1] = 0.954291f;	val_dir[16561*3 + 2] = -0.019881f;
+ 	val_dir[16562*3 + 0] = -0.274668f;	val_dir[16562*3 + 1] = 0.961339f;	val_dir[16562*3 + 2] = -0.019619f;
+ 	val_dir[16563*3 + 0] = -0.251587f;	val_dir[16563*3 + 1] = 0.967641f;	val_dir[16563*3 + 2] = -0.019353f;
+ 	val_dir[16564*3 + 0] = -0.228998f;	val_dir[16564*3 + 1] = 0.973240f;	val_dir[16564*3 + 2] = -0.019083f;
+ 	val_dir[16565*3 + 0] = -0.206922f;	val_dir[16565*3 + 1] = 0.978177f;	val_dir[16565*3 + 2] = -0.018811f;
+ 	val_dir[16566*3 + 0] = -0.185376f;	val_dir[16566*3 + 1] = 0.982493f;	val_dir[16566*3 + 2] = -0.018538f;
+ 	val_dir[16567*3 + 0] = -0.164372f;	val_dir[16567*3 + 1] = 0.986229f;	val_dir[16567*3 + 2] = -0.018264f;
+ 	val_dir[16568*3 + 0] = -0.143917f;	val_dir[16568*3 + 1] = 0.989426f;	val_dir[16568*3 + 2] = -0.017990f;
+ 	val_dir[16569*3 + 0] = -0.124015f;	val_dir[16569*3 + 1] = 0.992122f;	val_dir[16569*3 + 2] = -0.017716f;
+ 	val_dir[16570*3 + 0] = -0.104669f;	val_dir[16570*3 + 1] = 0.994354f;	val_dir[16570*3 + 2] = -0.017445f;
+ 	val_dir[16571*3 + 0] = -0.085876f;	val_dir[16571*3 + 1] = 0.996158f;	val_dir[16571*3 + 2] = -0.017175f;
+ 	val_dir[16572*3 + 0] = -0.067632f;	val_dir[16572*3 + 1] = 0.997567f;	val_dir[16572*3 + 2] = -0.016908f;
+ 	val_dir[16573*3 + 0] = -0.049931f;	val_dir[16573*3 + 1] = 0.998614f;	val_dir[16573*3 + 2] = -0.016644f;
+ 	val_dir[16574*3 + 0] = -0.032765f;	val_dir[16574*3 + 1] = 0.999329f;	val_dir[16574*3 + 2] = -0.016382f;
+ 	val_dir[16575*3 + 0] = -0.016125f;	val_dir[16575*3 + 1] = 0.999740f;	val_dir[16575*3 + 2] = -0.016125f;
+ 	val_dir[16576*3 + 0] = 0.0f;	val_dir[16576*3 + 1] = 0.999874f;	val_dir[16576*3 + 2] = -0.015871f;
+ 	val_dir[16577*3 + 0] = -1.0f;	val_dir[16577*3 + 1] = 0.0f;	val_dir[16577*3 + 2] = 0.0f;
+ 	val_dir[16578*3 + 0] = -0.999874f;	val_dir[16578*3 + 1] = 0.015871f;	val_dir[16578*3 + 2] = 0.0f;
+ 	val_dir[16579*3 + 0] = -0.999480f;	val_dir[16579*3 + 1] = 0.032241f;	val_dir[16579*3 + 2] = 0.0f;
+ 	val_dir[16580*3 + 0] = -0.998793f;	val_dir[16580*3 + 1] = 0.049121f;	val_dir[16580*3 + 2] = 0.0f;
+ 	val_dir[16581*3 + 0] = -0.997785f;	val_dir[16581*3 + 1] = 0.066519f;	val_dir[16581*3 + 2] = 0.0f;
+ 	val_dir[16582*3 + 0] = -0.996428f;	val_dir[16582*3 + 1] = 0.084443f;	val_dir[16582*3 + 2] = 0.0f;
+ 	val_dir[16583*3 + 0] = -0.994692f;	val_dir[16583*3 + 1] = 0.102899f;	val_dir[16583*3 + 2] = 0.0f;
+ 	val_dir[16584*3 + 0] = -0.992543f;	val_dir[16584*3 + 1] = 0.121891f;	val_dir[16584*3 + 2] = 0.0f;
+ 	val_dir[16585*3 + 0] = -0.989949f;	val_dir[16585*3 + 1] = 0.141421f;	val_dir[16585*3 + 2] = 0.0f;
+ 	val_dir[16586*3 + 0] = -0.986875f;	val_dir[16586*3 + 1] = 0.161489f;	val_dir[16586*3 + 2] = 0.0f;
+ 	val_dir[16587*3 + 0] = -0.983282f;	val_dir[16587*3 + 1] = 0.182089f;	val_dir[16587*3 + 2] = 0.0f;
+ 	val_dir[16588*3 + 0] = -0.979134f;	val_dir[16588*3 + 1] = 0.203216f;	val_dir[16588*3 + 2] = 0.0f;
+ 	val_dir[16589*3 + 0] = -0.974391f;	val_dir[16589*3 + 1] = 0.224860f;	val_dir[16589*3 + 2] = 0.0f;
+ 	val_dir[16590*3 + 0] = -0.969015f;	val_dir[16590*3 + 1] = 0.247004f;	val_dir[16590*3 + 2] = 0.0f;
+ 	val_dir[16591*3 + 0] = -0.962964f;	val_dir[16591*3 + 1] = 0.269630f;	val_dir[16591*3 + 2] = 0.0f;
+ 	val_dir[16592*3 + 0] = -0.95620f;	val_dir[16592*3 + 1] = 0.292714f;	val_dir[16592*3 + 2] = 0.0f;
+ 	val_dir[16593*3 + 0] = -0.948683f;	val_dir[16593*3 + 1] = 0.316228f;	val_dir[16593*3 + 2] = 0.0f;
+ 	val_dir[16594*3 + 0] = -0.940376f;	val_dir[16594*3 + 1] = 0.340136f;	val_dir[16594*3 + 2] = 0.0f;
+ 	val_dir[16595*3 + 0] = -0.931243f;	val_dir[16595*3 + 1] = 0.364399f;	val_dir[16595*3 + 2] = 0.0f;
+ 	val_dir[16596*3 + 0] = -0.921250f;	val_dir[16596*3 + 1] = 0.388972f;	val_dir[16596*3 + 2] = 0.0f;
+ 	val_dir[16597*3 + 0] = -0.910366f;	val_dir[16597*3 + 1] = 0.413803f;	val_dir[16597*3 + 2] = 0.0f;
+ 	val_dir[16598*3 + 0] = -0.898567f;	val_dir[16598*3 + 1] = 0.438835f;	val_dir[16598*3 + 2] = 0.0f;
+ 	val_dir[16599*3 + 0] = -0.885832f;	val_dir[16599*3 + 1] = 0.464007f;	val_dir[16599*3 + 2] = 0.0f;
+ 	val_dir[16600*3 + 0] = -0.872143f;	val_dir[16600*3 + 1] = 0.489251f;	val_dir[16600*3 + 2] = 0.0f;
+ 	val_dir[16601*3 + 0] = -0.857493f;	val_dir[16601*3 + 1] = 0.514496f;	val_dir[16601*3 + 2] = 0.0f;
+ 	val_dir[16602*3 + 0] = -0.841879f;	val_dir[16602*3 + 1] = 0.539666f;	val_dir[16602*3 + 2] = 0.0f;
+ 	val_dir[16603*3 + 0] = -0.825307f;	val_dir[16603*3 + 1] = 0.564684f;	val_dir[16603*3 + 2] = 0.0f;
+ 	val_dir[16604*3 + 0] = -0.807791f;	val_dir[16604*3 + 1] = 0.589469f;	val_dir[16604*3 + 2] = 0.0f;
+ 	val_dir[16605*3 + 0] = -0.789352f;	val_dir[16605*3 + 1] = 0.613941f;	val_dir[16605*3 + 2] = 0.0f;
+ 	val_dir[16606*3 + 0] = -0.770022f;	val_dir[16606*3 + 1] = 0.638018f;	val_dir[16606*3 + 2] = 0.0f;
+ 	val_dir[16607*3 + 0] = -0.749838f;	val_dir[16607*3 + 1] = 0.661622f;	val_dir[16607*3 + 2] = 0.0f;
+ 	val_dir[16608*3 + 0] = -0.728848f;	val_dir[16608*3 + 1] = 0.684675f;	val_dir[16608*3 + 2] = 0.0f;
+ 	val_dir[16609*3 + 0] = -0.707107f;	val_dir[16609*3 + 1] = 0.707107f;	val_dir[16609*3 + 2] = 0.0f;
+ 	val_dir[16610*3 + 0] = -0.684675f;	val_dir[16610*3 + 1] = 0.728848f;	val_dir[16610*3 + 2] = 0.0f;
+ 	val_dir[16611*3 + 0] = -0.661622f;	val_dir[16611*3 + 1] = 0.749838f;	val_dir[16611*3 + 2] = 0.0f;
+ 	val_dir[16612*3 + 0] = -0.638018f;	val_dir[16612*3 + 1] = 0.770022f;	val_dir[16612*3 + 2] = 0.0f;
+ 	val_dir[16613*3 + 0] = -0.613941f;	val_dir[16613*3 + 1] = 0.789352f;	val_dir[16613*3 + 2] = 0.0f;
+ 	val_dir[16614*3 + 0] = -0.589469f;	val_dir[16614*3 + 1] = 0.807791f;	val_dir[16614*3 + 2] = 0.0f;
+ 	val_dir[16615*3 + 0] = -0.564684f;	val_dir[16615*3 + 1] = 0.825307f;	val_dir[16615*3 + 2] = 0.0f;
+ 	val_dir[16616*3 + 0] = -0.539666f;	val_dir[16616*3 + 1] = 0.841879f;	val_dir[16616*3 + 2] = 0.0f;
+ 	val_dir[16617*3 + 0] = -0.514496f;	val_dir[16617*3 + 1] = 0.857493f;	val_dir[16617*3 + 2] = 0.0f;
+ 	val_dir[16618*3 + 0] = -0.489251f;	val_dir[16618*3 + 1] = 0.872143f;	val_dir[16618*3 + 2] = 0.0f;
+ 	val_dir[16619*3 + 0] = -0.464007f;	val_dir[16619*3 + 1] = 0.885832f;	val_dir[16619*3 + 2] = 0.0f;
+ 	val_dir[16620*3 + 0] = -0.438835f;	val_dir[16620*3 + 1] = 0.898567f;	val_dir[16620*3 + 2] = 0.0f;
+ 	val_dir[16621*3 + 0] = -0.413803f;	val_dir[16621*3 + 1] = 0.910366f;	val_dir[16621*3 + 2] = 0.0f;
+ 	val_dir[16622*3 + 0] = -0.388972f;	val_dir[16622*3 + 1] = 0.921250f;	val_dir[16622*3 + 2] = 0.0f;
+ 	val_dir[16623*3 + 0] = -0.364399f;	val_dir[16623*3 + 1] = 0.931243f;	val_dir[16623*3 + 2] = 0.0f;
+ 	val_dir[16624*3 + 0] = -0.340136f;	val_dir[16624*3 + 1] = 0.940376f;	val_dir[16624*3 + 2] = 0.0f;
+ 	val_dir[16625*3 + 0] = -0.316228f;	val_dir[16625*3 + 1] = 0.948683f;	val_dir[16625*3 + 2] = 0.0f;
+ 	val_dir[16626*3 + 0] = -0.292714f;	val_dir[16626*3 + 1] = 0.95620f;	val_dir[16626*3 + 2] = 0.0f;
+ 	val_dir[16627*3 + 0] = -0.269630f;	val_dir[16627*3 + 1] = 0.962964f;	val_dir[16627*3 + 2] = 0.0f;
+ 	val_dir[16628*3 + 0] = -0.247004f;	val_dir[16628*3 + 1] = 0.969015f;	val_dir[16628*3 + 2] = 0.0f;
+ 	val_dir[16629*3 + 0] = -0.224860f;	val_dir[16629*3 + 1] = 0.974391f;	val_dir[16629*3 + 2] = 0.0f;
+ 	val_dir[16630*3 + 0] = -0.203216f;	val_dir[16630*3 + 1] = 0.979134f;	val_dir[16630*3 + 2] = 0.0f;
+ 	val_dir[16631*3 + 0] = -0.182089f;	val_dir[16631*3 + 1] = 0.983282f;	val_dir[16631*3 + 2] = 0.0f;
+ 	val_dir[16632*3 + 0] = -0.161489f;	val_dir[16632*3 + 1] = 0.986875f;	val_dir[16632*3 + 2] = 0.0f;
+ 	val_dir[16633*3 + 0] = -0.141421f;	val_dir[16633*3 + 1] = 0.989949f;	val_dir[16633*3 + 2] = 0.0f;
+ 	val_dir[16634*3 + 0] = -0.121891f;	val_dir[16634*3 + 1] = 0.992543f;	val_dir[16634*3 + 2] = 0.0f;
+ 	val_dir[16635*3 + 0] = -0.102899f;	val_dir[16635*3 + 1] = 0.994692f;	val_dir[16635*3 + 2] = 0.0f;
+ 	val_dir[16636*3 + 0] = -0.084443f;	val_dir[16636*3 + 1] = 0.996428f;	val_dir[16636*3 + 2] = 0.0f;
+ 	val_dir[16637*3 + 0] = -0.066519f;	val_dir[16637*3 + 1] = 0.997785f;	val_dir[16637*3 + 2] = 0.0f;
+ 	val_dir[16638*3 + 0] = -0.049121f;	val_dir[16638*3 + 1] = 0.998793f;	val_dir[16638*3 + 2] = 0.0f;
+ 	val_dir[16639*3 + 0] = -0.032241f;	val_dir[16639*3 + 1] = 0.999480f;	val_dir[16639*3 + 2] = 0.0f;
+ 	val_dir[16640*3 + 0] = -0.015871f;	val_dir[16640*3 + 1] = 0.999874f;	val_dir[16640*3 + 2] = 0.0f;
+ 	val_dir[16641*3 + 0] = 0.0f;	val_dir[16641*3 + 1] = 1.0f;	val_dir[16641*3 + 2] = 0.0f;
+ 	val_dir[16642*3 + 0] = 0.0f;	val_dir[16642*3 + 1] = 0.0f;	val_dir[16642*3 + 2] = 0.0f;
+	}
+}
Index: trunk/src/testing/app/volvis/vPrimitive.h
===================================================================
--- trunk/src/testing/app/volvis/vPrimitive.h	(revision 4)
+++ trunk/src/testing/app/volvis/vPrimitive.h	(revision 4)
@@ -0,0 +1,117 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef __VPRIMITIVE_H
+#define __VPRIMITIVE_H
+#include "global.h"
+#include "Trackball.h"
+//The mother of all the graphics objects
+//in the main just create a list of vPrimitives
+//and then call init/draw
+class vPrimitive {
+public:
+	vPrimitive();
+	virtual ~vPrimitive() { };
+
+	virtual  void          init() { };
+	virtual  void          draw() { };
+
+	virtual void		next() { };
+	virtual void		prev() { };
+
+	inline void setName(const char *n) {
+		strcpy(name,n);
+	}
+
+	inline void disable() {
+		enabled = false;
+	}
+
+	inline void enable() {
+		enabled = true;
+	}
+
+	inline void setTranslation(float x, float y, float z) {
+		xform.trans[0] = x;
+		xform.trans[1] = y;
+		xform.trans[2] = z;
+	}
+
+	inline void setScale(float s) {
+		xform.scale = s;
+	}
+
+	inline void setColor(float col[]) {
+		color[0] = col[0];
+		color[1] = col[1];
+		color[2] = col[2];
+		color[3] = col[3];
+	}
+
+	inline void setSelected(bool s) {
+		selected = s;
+	}
+
+	inline bool isSelected() {
+		return selected;
+	}
+
+	inline bool isAnimating() {
+		return animate;
+	}
+
+	inline void toggleAnimate() {
+		animate = !animate;
+	}
+
+	//return 1 if the key press was for you
+	//virtual  int           key(unsigned char k, int x, int y);
+	//virtual  int           special(int k, int x, int y);
+	//virtual  int           mouse(int button, int state, int x, int y);
+	//virtual  int           move(int x, int y);
+	//virtual  int           release();   //tells widget it is done
+	vTransform xform;
+	bool rot;
+	float rotAngle;
+	float color[4];
+	Trackball	track;	//global trackball
+protected:
+	//the above wil be used for the picking
+	char name[256];
+	bool enabled;
+	bool selected;
+	bool animate;
+};
+
+#endif
Index: trunk/src/testing/app/volvis/global.h
===================================================================
--- trunk/src/testing/app/volvis/global.h	(revision 4)
+++ trunk/src/testing/app/volvis/global.h	(revision 4)
@@ -0,0 +1,258 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//Contains the global windowing parameters for the vol-a-tile app
+#ifndef __GLOBAL_H
+#define __GLOBAL_H
+
+#include "glUE.h"
+#include "vVolume.h"
+#include "Trackball.h"
+#include "vNet.h"
+#include <vector>
+class vPrimitive;
+typedef enum {
+	NONE=0,
+	AGAVE,
+	CROSSEYE
+} vStereoType;
+
+enum STEREOVIEW { LEFT, RIGHT};
+
+struct vWindow {  //Window size and location attributes
+	unsigned int	width;
+	unsigned int	displayWidth;  //for stereo etc
+	unsigned int	height;
+	unsigned int	xPos;
+	unsigned int	yPos;
+	float aspect;
+};
+
+struct vFrustum {
+	float left, right, top, bottom;
+};
+
+struct vViewport {
+	float x, y, width, height;
+};
+
+struct vStereo {
+	float			halfEyeSep;
+	vStereoType		type;
+};
+
+typedef vector<vFrustum> vFrustumList;
+typedef vector<vViewport> vViewportList;
+struct vEnv {     //GL rendering Environment parameters
+	float                 eye[3];    // eye location
+	float                 at[3];     // lookat point
+	float                 up[3];     // up vector
+	// frustum[0] = left,   frustum[1] = right frustum[2] = bottom, frustum[3] = top
+	vFrustumList		frustumList;
+	vViewportList		viewportList;
+	float                 clip[2];   // clip[0] = front, clip[1] = back
+	float                 diff[4];   // diffuse color (material)
+	float                 spec[4];   // speculare color (material)
+	int                   bgColor;   // background color? 0==white 1==black
+	vStereoType	stereoType; //type of stereo, NONE, AGAVE, CROSSEYED
+	bool		renderOn;
+	bool		gameMode;
+};
+
+struct vLight{   //lighting information
+	float                 pos[3];    //light position
+	float                 startpos[3];
+};
+
+struct vCutTransform {
+	double rotn[16]; //just rotation
+	double transform[16]; //cumulative transform(with the volume)
+	double user[4]; //eqn of the cut plane
+	bool update;
+	float axis[3];
+	float angle;
+};
+
+struct vTransform{   //rendering transform parameters
+	float                 rotn[16];    //rotation from trackball
+	float                 scale;        //isotropic scale value
+	float                 trans[3];     //translation
+};
+
+struct vMouse{   //mouse state information
+	int                   button;  //GLUT mouse button
+	int                   state;   //GLUT mouse state
+	int                   pos[2];  //x,y
+	int                   last[2]; //last mouse position
+	int                   shift;   //is shift down
+	int                   ctrl;    //is control down
+	int                   alt;     //is alt down
+};
+
+struct vKey {     //key board state
+	unsigned char         key;     //GLUT key
+	int                   shift;   //is shift down
+	int                   ctrl;    //is control down
+	int                   alt;     //is alt down
+};
+
+
+struct vRen {  //volume rendering paramters
+	float                 sampleRate;   //current sample rate for rendering
+	float                 interactSamp; //interactive sample rate
+	float                 goodSamp;     //high quality sample rate
+	int 			lowRes;		//low res rendering
+	unsigned char        *deptex;       //2d dependent texture 256x256xRGBA [gb]
+	unsigned char* gDeptex;	//this is recalculated from deptex above, alpha values are recalculated based on no of slices
+	unsigned char* iDeptex;	//this is recalculated from deptex above
+	unsigned char* nDeptex;	//this is recalculated from deptex above
+
+	float lastSamp;            	//last sample rate rendered
+	float lastGoodSamp;        	//last good sample rate
+	float lastInteSamp;       	 //last interactive sample rate
+
+	int                   loadTLUT;     //reload the LUT if flag == 1
+	int 			loadVolume; //reload the volume if == 1
+	int                   scaleAlphas;  //scale alphas with sample rate
+	float                 gamma;        //constant alpha scale
+	int 			probe[3]; //the 3 points corresponding to the probe ptr
+	unsigned int	scaledDeptexName, origDeptexName;
+};
+
+typedef enum {
+	V_ROAM,
+	V_PROBE
+} vNav;
+
+struct vUI {
+	bool printFPS;
+	bool printSlices;
+	bool cutEnabled;
+	bool bboxEnabled;
+	vNav navMode;
+	bool animate;
+};
+
+
+typedef enum {  //Major axies of volume coords
+	V_Unknown,
+		V_XPos,
+		V_XNeg,
+		V_YPos,
+		V_YNeg,
+		V_ZPos,
+		V_ZNeg
+} VolRenMajorAxis;
+
+
+typedef enum {  //v Shade modes (shadows are handled by the light struct)
+		V_UNKNOWN,
+		V_AMBIENT,     //ambient
+		V_DIFFUSE,    //diffuse
+		V_DSPEC,   //diffuse + specular
+		V_FAUX,    //Faux shading
+		V_ARB,     //arbitrary shading via pixel texture
+		V_MIP
+} vShade;
+
+typedef enum {       //v platforms supported
+	GPGineric,         //default
+		GPNV20,            //-nv20 - 3D textures GeForce 3
+		GPATI8K            //ATI Radeon 8000 (R200)
+} vPlatform;
+
+
+typedef enum {
+	V_NONE,
+		V_UNDER,
+		V_OVER,
+		V_ZERO
+} vBlend;
+
+
+struct vGlobal {
+	int			debug;
+	vWindow		win;    //window
+	vEnv		env;    //environment
+	vLight		light;  //light
+	vVolume		*volume ;//pointer to the data to be rendered
+	vVolume		*fullVolume;//pointer to the full volume
+	vMouse		mouse;  //mouse
+	vPlatform	plat;   //plaform
+	vRen		volren; //volume rendering stuff
+	int			mainWindow;  //mainWindow Identifier
+	int			tfWindow;  //mainWindow Identifier
+//	vShade		shade;       //shading enable/disable flag
+//	vBlend		reblend;     //re-render scene with blend
+	vStereo		stereo; //stereo params
+	vUI			ui;
+	vCutTransform		cut;
+	float 		pointerPos[3]; //posn of the pointer in world coords
+	int		curPrimIdx; //index of the primitive thats currently selected, -1 if nothing is selected
+};
+
+void drawText(GLfloat x, GLfloat y, GLfloat z, char *message);
+
+void    mouse(int button, int state, int x, int y); //mouse callback
+void	passiveMotion(int x, int y) ;
+void    motion(int x, int y);                       //motion callback
+void    key(unsigned char key, int x, int y);   //key callback
+void    special(int key, int x, int y);         //special key callback
+void    idle();                                 //idle callback
+void    reshape(int w, int h);                      //reshape callback
+void    initGlobal() ;
+void	display();
+void    displayOneEye(STEREOVIEW eye);
+void    displayOneEye(int,int);
+void    initGL();
+void	parseCmdLine(int, char**);
+void deallocateAll() ;
+void enableTex3D(unsigned int ); //opengl init before the render
+void disableTex3D(); //opengl stuff after the render
+
+void updateAnim(int value);
+void calcFrustum();
+
+extern vGlobal     global;
+extern Trackball	cutTrack;	//global trackball
+extern vector<vPrimitive*>   renderList; //all renderables attatch to this one
+extern vector<vPrimitive*>   selectList; //all renderables that can be selected
+
+#if defined(V_DISTRIBUTED)
+extern vNet* net;
+#endif
+
+#endif
+
+
Index: trunk/src/testing/app/volvis/optiLocalIP.dat
===================================================================
--- trunk/src/testing/app/volvis/optiLocalIP.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiLocalIP.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 nico
+1 nico1-10
+2 nico2-10
+3 nico3-10
+4 nico4-10
+5 nico5-10
+6 nico6-10
+7 nico7-10
+8 nico8-10
Index: trunk/src/testing/app/volvis/CHANGELOG
===================================================================
--- trunk/src/testing/app/volvis/CHANGELOG	(revision 4)
+++ trunk/src/testing/app/volvis/CHANGELOG	(revision 4)
@@ -0,0 +1,98 @@
+CHANGELOG for Vol-a-tile
+------------------------
+Shalini Venkataraman, Luc Renambot
+Tues Sep 23
+-----------
+- Use Tab/backspace to cycle across the different geometry
+Mon Sep 22
+----------
+- added anim of volume data
+- the 3rd argument of -v specifies the thumbnail volume, if not there, theres no thumbnail vol to be displayed
+
+Sat Sep 20
+----------
+- added thumbnail for the fullres volume
+- removed dependant texture from the renderer , its in main now
+- add support for anim of isosurface, 
+
+Wed/Thus sep 18
+---------------
+- Add a pointer to select for the various render objects
+- fixed isosurface bug(GL_NORMALIZE)
+- fixed bugs in the sliceview mapping to volume mapping
+- use the mouse to click a point on the sliceview to move the probe
+
+Sun Sep 14
+----------
+- fixed bug in accesing optistore (bounds for crop should be inclusive)
+- added the 3 sliceviews and the probe to access the volume, isosurface is generated based on the current value in the probe
+- add menu for cut-plane/object/roam/probe 
+
+Thur Sep 11
+----------
+- added isosurface and point rendering, these objects are added at the mouse pointer
+- increase/ decrease isovalues
+
+Wed Sep 10
+----------
+- 2d hist is sent to TFUI everytime a new volume is roamed
+
+Mon Sep 8
+---------
+- integrated Optistore, if V_NETDATA, files are loaded from Optiserver, else from local file
+- added keys for roaming the volume, to activate roaming press key 'R'
+- volume class has 2 children vFileVolume and vOptiVolume to handle the 2 different cases
+- have a 1d histogram instead of 2d histogram
+
+Sun Sep 7
+---------
+- Added mmap instead of reading from file 
+
+Thu Sep 4
+---------
+- added a save/load for the gradient volumes
+-g to load the gradient file (8bit)
+'G' key to write the gradient into to a file (8bit)
+- added save/load for the transfer functions from UI
+use a ppm file to store texture as 1xn for the timebeing
+- 'b' key to toggle display of bounding box
+- save/load LUTs from the GUI(very primitive)
+
+Tue Sep 2
+---------
+- added QUANTA tcp to transmit transfer functions
+have a shared buffer betwen the TFUI/network thread
+- when a tcp client(tfUI) connects to volvis, send the histogram of the volume to the UI
+
+Thu Aug 28
+----------
+- keyboard rotation for volume/cutplane - done
+- added clipplane
+- reshuffled code 
+
+Thu Aug 21
+----------
+- added MPI to distribute the rendering on the tiles - high latency
+Is it possible to decouple the MPI from the display (dont think so)
+- also tried using QUANTA instead of MPI - check for any difference
+Its worse as expected
+- added a QUANTA DB server for the TF to transmit to all tiles
+(change this so that tf only transmits to master and master broadcasts to all slaves)
+
+Thu Aug 14
+----------
+- separate TF/ volvis app
+Flow something like this
+Init
+Volvis -> TFAPP : Histogram of volume data
+Every network loop
+TFAPP -> Volvis : 2d array for the transfer function
+
+Thu Aug 7
+---------
+- add the TF widget to the volvis app
+- added histogram plot of the data/gradient
+
+July 31
+-------
+- Luc added CG Fragment shader for the transfer functions                                                                                                                                           
Index: trunk/src/testing/app/volvis/scripts/GO.yorda
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.yorda	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.yorda	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiYorda.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_RANVIER.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_RANVIER.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_RANVIER.local	(revision 4)
@@ -0,0 +1,6 @@
+#for scylla
+#./volvis -v Ranvier-volume localhost Ranvier-256 -sp 3 6 1 -a 1.25 -d 256 256 256 -n $PWD/machines.dat
+#mpirun -machinefile $PWD/.gige -np 5 $PWD/volvis -v Ranvier-volume localhost Ranvier-256 -w 1024 768 -sp 3 6 1 -a 3.413 -d 256 256 256 -n $PWD/machines.dat
+#for xindi
+forall killall volvis
+mpirun -np 16 /nfs/disk2/DEMO/volatile/volvis/volvis -v Ranvier-volume optiLocal.dat Ranvier-256 -a 2.2 -d 256 256 256 -sp 3 6 1 -n /nfs/disk2/DEMO/volatile/volvis/machines.dat
Index: trunk/src/testing/app/volvis/scripts/RUN_FOOT.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_FOOT.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_FOOT.local	(revision 4)
@@ -0,0 +1,7 @@
+#aspect ratio of the display
+#XINDI
+forall killall volvis
+mpirun -np 9 $PWD/volvis -v Foot optiLocal.dat -a 2.2 -d 64 64 64 -n $PWD/machines.dat.xindi
+#scylla
+#mpirun -np 9 $PWD/volvis -v Foot localhost -a 2.08 -d 64 64 64 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/RUN_ARAD.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_ARAD.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_ARAD.local	(revision 4)
@@ -0,0 +1,10 @@
+#oaspect ratio of perspectile = 6805/3272
+#for scylla
+#mpirun -machinefile $PWD/.gige -np 15 $PWD/volvis -v Arad-volume localhost Arad-256 -d 256 256 256 -a 2.08 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+#for xindi
+#forall killall volvis
+#mpirun -np 16 /nfs/disk2/DEMO/volatile/volvis/volvis -v Arad-volume optiLocal.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n /nfs/disk2/DEMO/volatile/volvis/machines.dat
+#for igppviz
+mpirun -np 9 -machinefile $PWD/.gige.igpp /home/anayak/volatile/volvis/volvis -v Arad-full optiLocal.dat Arad-256 -a 3.413 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
+#mpirun -np 9 -machinefile $PWD/.gige.igpp /home/anayak/volatile/volvis/volvis -v Arad-256 optiLocal.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
+
Index: trunk/src/testing/app/volvis/scripts/GO-ranvier.yorda
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO-ranvier.yorda	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO-ranvier.yorda	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Ranvier-volume optiYorda.dat Ranvier-256 -a 2.2 -sp 3 6 1 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.ranvier &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/GO.global2
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.global2	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.global2	(revision 4)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cd  /nfs/disk2/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 16  /nfs/disk2/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiGlobal2.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.evl &
+
+sleep 80
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM.local	(revision 4)
@@ -0,0 +1,6 @@
+#scylla
+#mpirun -machinefile $PWD/.gige -np 16  $PWD/volvis -v Step*-vol256 localhost Step15-vol256 -d 128 128 128 -n $PWD/machines.dat
+
+#on xindi
+mpirun -np 9 $PWD/volvis -v 'Step*-vol256' optiLocal.dat Step15-vol256 -a 1.5 -d 128 128 128 -n $PWD/machines.dat.xindi
+
Index: trunk/src/testing/app/volvis/scripts/GO-arad.yorda
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO-arad.yorda	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO-arad.yorda	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiYorda.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_RANVIER
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_RANVIER	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_RANVIER	(revision 4)
@@ -0,0 +1,12 @@
+#for scylla
+forall killall -9 volvis
+#./volvis -v Ranvier-volume localhost Ranvier-256 -sp 3 6 1 -a 1.25 -d 256 256 256 -n $PWD/machines.dat
+#mpirun -machinefile $PWD/.gige -np 16 $PWD/volvis -v Ranvier-volume optiRemote.dat Ranvier-256 -w 1024 768 -sp 3 6 1 -a 3.413 -d 256 256 256 -n $PWD/machines.dat
+#for xindi
+#mpirun -np 9 $PWD/volvis -v Ranvier-volume optiRemote.dat Ranvier-256 -a 2.2 -d 256 256 256 -sp 3 6 1 -n $PWD/machines.dat.xindi
+
+
+mpirun -machinefile .gige -np 16 $PWD/volvis -v  Ranvier optiCharybdis.dat Ranvier-256 -a 2.08 -sp 3 6 1 -d 128 128 128 -n $PWD/machines.dat.evl
+
+#mpirun -machinefile .gige.2b2 -np 5 $PWD/volvis -v  Ranvier-volume optiCharybdis.dat Ranvier-256 -a 1 -sp 3 6 1 -d 256 256 256 -n $PWD/machines.dat.evl2b2
+
Index: trunk/src/testing/app/volvis/scripts/GO-arad.rocks
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO-arad.rocks	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO-arad.rocks	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiRocks.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_FOOT
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_FOOT	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_FOOT	(revision 4)
@@ -0,0 +1,7 @@
+#aspect ratio of the display
+#XINDI
+forall killall volvis
+mpirun -np 9 $PWD/volvis -v Foot optiRemote.dat -a 2.2 -d 64 64 64 -n $PWD/machines.dat.xindi
+#scylla
+#mpirun -np 9 $PWD/volvis -v Foot localhost -a 2.08 -d 64 64 64 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/RUN_ARAD_MEDIUM
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_ARAD_MEDIUM	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_ARAD_MEDIUM	(revision 4)
@@ -0,0 +1,11 @@
+#oaspect ratio of perspectile = 6805/3272
+#for scylla
+#mpirun -machinefile $PWD/.gige -np 15 $PWD/volvis -v Arad-volume localhost Arad-256 -d 256 256 256 -a 2.08 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+#for xindi
+#forall killall volvis
+#mpirun -np 16 $PWD/volvis -v Arad-volume optiRemote.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+
+# storage
+cluster-fork pkill -9 volvis
+mpirun -np 9  -machinefile $PWD/.gige.igpp  $PWD/volvis -v Arad-volume optiStorage.dat Arad-medium -a 2.2 -d 512 512 801 -n $PWD/machines.dat.igpp
+#mpirun -np 9  -machinefile $PWD/.gige.igpp  $PWD/volvis -v Arad-volume optiStorage.dat Arad-medium -a 2.2 -d 512 512 801 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
Index: trunk/src/testing/app/volvis/scripts/RUN_ARAD
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_ARAD	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_ARAD	(revision 4)
@@ -0,0 +1,16 @@
+#oaspect ratio of perspectile = 6805/3272
+#for scylla
+#mpirun -machinefile $PWD/.gige -np 15 $PWD/volvis -v Arad-volume localhost Arad-256 -d 256 256 256 -a 2.08 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+#for xindi
+#forall killall volvis
+#mpirun -np 16 $PWD/volvis -v Arad-volume optiRemote.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+
+# storage
+#cluster-fork pkill -9 volvis
+#mpirun -np 9  -machinefile $PWD/.gige.igpp  $PWD/volvis -v Arad-volume optiStorage.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
+#mpirun -np 9  -machinefile $PWD/.gige.igpp  $PWD/volvis -v Arad-full optiStorage.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
+
+killall -9 volvis
+forall killall -9 volvis
+mpirun -machinefile .gige -np 16 $PWD/volvis -v Arad-volume optiAdam.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955  -d 128 128 128 -n $PWD/machines.dat.evl
+
Index: trunk/src/testing/app/volvis/scripts/RUN.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN.local	(revision 4)
@@ -0,0 +1,7 @@
+#aspect ratio of the display
+#XINDI
+forall killall volvis
+mpirun -np 9 $PWD/volvis -v Protein optiLocal.dat -a 2.2 -d 64 64 64 -n $PWD/machines.dat.xindi
+#scylla
+#mpirun -np 9 $PWD/volvis -v Protein localhost -a 2.08 -d 64 64 64 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL.local	(revision 4)
@@ -0,0 +1,2 @@
+mpirun -np 9  $PWD/volvis -i 'Step*-100' localhost 0.001953125 -v 'Step*-vol256' localhost Step15-vol256 -a 2.2 -d 256 256 256 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/GO.local
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.local	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.local	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiLocalIP.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_VOLANIM	(revision 4)
@@ -0,0 +1,6 @@
+#scylla
+#mpirun -machinefile $PWD/.gige -np 16  $PWD/volvis -v Step*-vol256 localhost Step15-vol256 -d 128 128 128 -n $PWD/machines.dat
+
+#on xindi
+mpirun -np 9 $PWD/volvis -v 'Step*-vol256' optiRemote.dat Step15-vol256 -a 1.5 -d 128 128 128 -n $PWD/machines.dat.xindi
+
Index: trunk/src/testing/app/volvis/scripts/GO.cha
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.cha	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.cha	(revision 4)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cd  /nfs/disk2/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 16  /nfs/disk2/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiCharybdis.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.evl &
+
+sleep 80
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/GO.local-foot
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.local-foot	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.local-foot	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Foot optiLocalIP.dat Foot -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 80
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN	(revision 4)
@@ -0,0 +1,15 @@
+#aspect ratio of the display
+#XINDI
+#forall killall volvis
+
+# igppviz
+#cluster-fork pkill -9 volvis
+#mpirun -np 9 -machinefile $PWD/.gige.igpp $PWD/volvis -v Protein optiLocal.dat -a 2.2 -d 64 64 64 -n $PWD/machines.dat.igpp
+
+#storage
+cluster-fork pkill -9 volvis
+mpirun -np 9 -machinefile $PWD/.gige.igpp $PWD/volvis -v Protein optiStorage.dat -a 2.08 -d 64 64 64 -n $PWD/machines.dat.igpp
+
+#scylla
+#mpirun -np 9 $PWD/volvis -v Protein localhost -a 2.08 -d 64 64 64 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/GO.global
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.global	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.global	(revision 4)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cd  /nfs/disk2/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 16  /nfs/disk2/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiGlobal.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.evl &
+
+sleep 80
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/GO-arad.cha
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO-arad.cha	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO-arad.cha	(revision 4)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+
+cd  /home/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 9  /home/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiCharybdis2.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.nico &
+
+sleep 50
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_BOLIVIA_ISOVOL	(revision 4)
@@ -0,0 +1,4 @@
+#mpirun -np 9  $PWD/volvis -i 'Step*-100' optiLocal.dat 0.001953125 -v 'Step*-vol256' optiRemote.dat Step15-vol256 -a 2.2 -d 256 256 256 -n $PWD/machines.dat
+
+mpirun -machinefile .gige -np 16 $PWD/volvis -i 'Step*-100' optiLocalIP.dat 0.001953125 -v 'Step*-vol256' optiLocalIP.dat Step15-vol256 -a 1 -d 256 256 256 -n $PWD/machines.dat
+
Index: trunk/src/testing/app/volvis/scripts/GO.adam
===================================================================
--- trunk/src/testing/app/volvis/scripts/GO.adam	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/GO.adam	(revision 4)
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+cd  /nfs/disk2/evl/luc/Dev/volatile/volvis
+
+killall -9 volvis
+forall killall -9 volvis
+
+mpirun -machinefile .gige -np 16  /nfs/disk2/evl/luc/Dev/volatile/volvis/volvis -v Arad-full optiAdam.dat Arad-256 -a 2.08 -sp 1.5644 1.5644 1.955 -d 128 128 128 -n $PWD/machines.dat.evl &
+
+sleep 80
+
+cd ../tfUI
+./RUN.arad &
+
+wait
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/scripts/RUN_FOOT_CHA
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_FOOT_CHA	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_FOOT_CHA	(revision 4)
@@ -0,0 +1,12 @@
+
+#scylla - standalone
+#killall volvis
+#./volvis -v Foot 206.220.241.21 Foot -a 2.08 -d 64 64 64 
+
+forall killall -9 volvis
+
+mpirun -machinefile .gige.2b2 -np 5 $PWD/volvis -v  Ranvier-volume optiCharybdis.dat Ranvier-256 -a 3.413 -sp 3 6 1 -d 256 256 256 -n $PWD/machines.dat.evl2b2
+
+#mpirun -machinefile .gige.2b2 -np 5 $PWD/volvis -v 'Step*-vol256' optiCharybdis.dat Step15-vol256 -a 1.0 -d 128 128 128 -n $PWD/machines.dat.evl2b2
+
+#mpirun -machinefile .gige -np 16 $PWD/volvis -v Foot optiLocalIP.dat Foot -a 1 -d 64 64 64 -n $PWD/machines.dat.evl
Index: trunk/src/testing/app/volvis/scripts/RUN_ARAD_BIG
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_ARAD_BIG	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_ARAD_BIG	(revision 4)
@@ -0,0 +1,10 @@
+#oaspect ratio of perspectile = 6805/3272
+#for scylla
+#mpirun -machinefile $PWD/.gige -np 15 $PWD/volvis -v Arad-volume localhost Arad-256 -d 256 256 256 -a 2.08 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+#for xindi
+#forall killall volvis
+#mpirun -np 16 $PWD/volvis -v Arad-volume optiRemote.dat Arad-256 -a 2.2 -d 256 256 256 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat
+
+# storage
+cluster-fork pkill -9 volvis
+mpirun -np 9  -machinefile $PWD/.gige.igpp  $PWD/volvis -v Arad-full optiStorage.dat Arad-256 -a 2.2 -d 801 801 1001 -sp 1.5644 1.5644 1.955 -n $PWD/machines.dat.igpp
Index: trunk/src/testing/app/volvis/scripts/RUN_FOOT_ADAM
===================================================================
--- trunk/src/testing/app/volvis/scripts/RUN_FOOT_ADAM	(revision 4)
+++ trunk/src/testing/app/volvis/scripts/RUN_FOOT_ADAM	(revision 4)
@@ -0,0 +1,7 @@
+killall volvis
+
+#scylla - standalone
+#./volvis -v Foot 10.1.1.111 Foot -a 2.08 -d 64 64 64 
+
+mpirun -machinefile .gige.2b2 -np 5 $PWD/volvis -v Foot optiAdam.dat Foot -a 1 -sp 1 1 1 -d 128 128 128 -n $PWD/machines.dat.evl2b2
+
Index: trunk/src/testing/app/volvis/optiCharybdis2.dat
===================================================================
--- trunk/src/testing/app/volvis/optiCharybdis2.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiCharybdis2.dat	(revision 4)
@@ -0,0 +1,16 @@
+0 206.220.241.20
+1 206.220.241.21
+2 206.220.241.22
+3 206.220.241.23
+4 206.220.241.24
+5 206.220.241.20
+6 206.220.241.21
+7 206.220.241.22
+8 206.220.241.23
+9 206.220.241.24
+10 206.220.241.20
+11 206.220.241.21
+12 206.220.241.22
+13 206.220.241.23
+14 206.220.241.24
+15 206.220.241.24
Index: trunk/src/testing/app/volvis/README
===================================================================
--- trunk/src/testing/app/volvis/README	(revision 4)
+++ trunk/src/testing/app/volvis/README	(revision 4)
@@ -0,0 +1,172 @@
+README for Vol-a-Tile
+---------------------
+Shalini Venkataraman, Luc Renambot
+Sep 2003
+
+Usage
+-----
+Please run the .bat files in this dir for the different datasets
+or
+type
+./volvis -f filename fileX fileY fileZ  -v volName dataServerFile -d volX volY volZ -g gradientFileName -o offsetX offsetY offsetZ -s stereoType -w width height -h -n netConfigFile  
+                                                                                
+where
+
+-f filename fileX fileY fileZ
+filename : file containing the raw volume
+fileX : columns in the file(x)
+fileY : rows in the file(y)
+fileZ : no of slices in file(z)
+This is used when data is locally acceses
+
+-v volName dataServerFile
+For remote date access. volName is the symbolic name of the volume as specified in the optistore servers config. dataServerFile is the name of the file that associates the render nodes to optistore server nodes. Something like this for each render node:-
+rank# serverIP
+
+-d volX volY volZ
+dimesions of the volume that will actually be rendered. If volX, volY and volZ are not powers of 2, they are EXPANDED to the nearest power of 2. so a volume with dimensions 440x290x198 becomes 512x512x256.
+
+-g gradFilename : file containing the gradient volume. If this file is not specified, the gradient volume is computed on the fly
+
+-o offsetX offsetY offsetZ
+This can be used to skip or specify an offset from where the volume the read in
+offsetX : X offset to start reading from
+offsetY : Y offset to start reading from
+offsetZ : Z offset to start reading from
+
+-s stereoType  
+stereoType :    0 for no stereo/default
+		1 for AGAVE stereo
+		2 forCross-Eye Stereo
+
+-w width height
+width: width of window
+height: height of window
+
+-n netConfigFile
+used for distributed rendering in a cluster. The cluster configuration is specified by the netConfigFile (in our case machines.dat). For file specs, see under "cluster rendering"
+                                                                                
+Interaction
+-----------
+Keyboard
+B : toggle display of bounding box
+C : Switch between moving clip plane and object
+F : Rotate about z (-ve), roam in Z
+F : Toggle printing FPS
+G : Save the gradient volume to a file
+H : Print usage help
+N : Toggle printing number of slices
+O : Write the volume to a file (like out256x256x256.raw)
+Q : Rotate about z (+ve), roam in Z
+R : Toggle Roam mode
++ : Increase sample rate
+- : Decrease sample rate
+UP: Rotate about x (-ve), roam up in roam mode 
+DOWN: Rotate about x (+ve),roam down in roam mode  
+LEFT : Rotate about y (-ve), roam left in roam mode
+RIGHT: Rotate about y (+ve), roam right in roam mode
+PAGE UP : Increase Eye Separation for stereo
+PAGE DOWN : Decrease Eye Separation for stereo
+ESC : Quit
+                                                                                
+Mouse
+Left : Click and drag to rotate volume or clipPlane whichever is active
+Middle : Click and drag to translate volume
+Right : Click and drag to zoom volume or clipPlane whichever is active
+
+
+                                                                                
+Cluster Rendering
+-----------------
+For the machines.dat file, the view frustums are calculated as percentages
+Scylla
+------
+Width - 14.0'
+Height - 11.2'
+mullionX = 0.6'
+mullionY = 0.58'
+
+So, for the perspectile with resolution 1280x1024
+mullionX = (0.6/14.0)*1280 = 55  
+mullionY = (0.58/11.2)*1024 = 53  
+total resolution is
+X: 55 + 1280 + 2(55) + 1280 + 2(55) + 1280 + 2(55) + 1280 + 2(55) + 1280 = 6895
+Y: 53 + 1024 + 2(53) + 1024 + 2(53) + 1024 = 3337
+aspect = 2.066
+
+mullion-X = 55/6895 = 0.8
+2*mullion-X = 1.6
+mullion-Y = 53/3337 = 1.59
+2*mullion-y = 3.18
+
+resolution-X = 1280/6895 = 18.56
+resolution-Y = 1024/3337 = 30.68
+
+so for each tile from bottom -left onwards
+3 0.80 19.36 1.59 32.27
+6 20.96 39.52 1.59 32.27
+9 41.12 59.68 1.59 32.27
+12 61.28 79.84 1.59 32.27
+15 81.44 100.0 1.59 32.27
+
+2 0.8 19.36 35.45 66.13
+5 20.96 39.52 35.45 66.13
+8 41.12 59.68 35.45 66.13
+11 61.28 79.84 35.45 66.13
+14 81.44 100.0 35.45 66.13
+
+1 0.8 19.36 69.31 99.9
+4 20.96 39.52 69.31 99.9
+7 41.12 59.68 69.31 99.9
+10 61.28 79.84 69.31 99.9
+13 81.44 100.0 69.31 99.9
+
+
+Cluster Config on XINDI
+-----------------------
+Width - 15.95'
+Height - 12.05'
+mullionX = 0.725'
+mullionY = 0.65'
+
+Each tile in XINDI has resolution 1600x1200 with 
+mullionX =  72.73
+mullionY = 64.73
+
+total resolution is
+X: 72.73 + 1600 + 2(72.73) + 1600 + 2(72.73) + 1600 + 2(72.73) + 1600 + 2(72.73) + 1600 = 8654.57
+Y: 64.73 + 1200 + 2(64.73) + 1200 + 2(64.73) + 1200 = 3923.65
+aspect = 8654.57/3923.65 = 2.2
+
+as percentages
+mullion-X = 72.73/8654.57 = 0.84
+2*mullion-X = 1.68
+mullion-Y = 64.73/3923.65 = 1.65
+2*mullion-y = 3.3
+
+resolution-X = 1600/8654.57 = 18.48
+resolution-Y = 1200/3923.65 = 30.6
+
+so for each tile from bottom -left onwards
+3 0.84 19.32 1.65 32.25
+6 21.0 39.48 1.65 32.25
+9 41.16 59.64 1.65 32.25
+12 61.32 79.8 1.65 32.25
+15 81.48 99.96 1.65 32.25
+
+2 0.84 19.32 35.55 66.15
+5 21.0 39.48 35.55 66.15
+8 41.16 59.64 35.55 66.15
+11 61.32 79.8 35.55 66.15
+14 81.48 99.96 35.55 66.15
+
+1 0.84 19.32 69.45 100.0
+4 21.0 39.48 69.45 100.0
+7 41.16 59.64 69.45 100.0
+10 61.32 79.8 69.45 100.0
+13 81.48 99.96 69.45 100.0
+
+
+
+
+
Index: trunk/src/testing/app/volvis/optiRemote.dat
===================================================================
--- trunk/src/testing/app/volvis/optiRemote.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiRemote.dat	(revision 4)
@@ -0,0 +1,8 @@
+0 137.110.246.4
+1 137.110.246.5
+2 137.110.246.6
+3 137.110.246.7
+4 137.110.246.8
+5 137.110.246.9
+6 137.110.246.10
+7 137.110.246.11
Index: trunk/src/testing/app/volvis/private.h
===================================================================
--- trunk/src/testing/app/volvis/private.h	(revision 4)
+++ trunk/src/testing/app/volvis/private.h	(revision 4)
@@ -0,0 +1,85 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#if defined(WIN32)
+#include <string.h>
+#else
+#include <strings.h>
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#define QUANTA_LITTLE_ENDIAN 1
+#define QUANTA_THREAD_SAFE   1
+#define QUANTA_USE_PTHREADS  1
+#include <QUANTA.hxx>
+
+#if !defined(WIN32)
+
+#define USE_RBUDP 1
+
+#if defined(USE_RBUDP)
+#define RBUDP_RATE (300*1000)
+#define RBUDP_FRAME 1452
+//#define RBUDP_FRAME 8800
+#include <QUANTAnet_rbudpSender_c.hxx>
+#include <QUANTAnet_rbudpReceiver_c.hxx>
+#endif
+
+#endif
+
+// NETWORK PROTOCOL
+#define Q_INIT     0
+#define Q_BYE      1
+#define Q_LIST     2
+#define Q_LOAD     3
+#define Q_CROP     4
+#define Q_SAMPLE   5
+#define Q_ISO      6
+#define Q_VOL      7
+#define Q_POINT    8
+#define Q_EXIT     9
+#define Q_HISTO   10
+#define Q_GRAD    11
+#define Q_HISTO2D 12
+
Index: trunk/src/testing/app/volvis/vSliceView.cpp
===================================================================
--- trunk/src/testing/app/volvis/vSliceView.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vSliceView.cpp	(revision 4)
@@ -0,0 +1,210 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include "vSliceView.h"
+#include "vCG.h"
+#include "vARB.h"
+#include "MatrixMath.h"
+
+vProbe::vProbe() :vPrimitive() {
+	xform.scale = 1.0f/(float)global.volume->maxDim;
+}
+
+//do opngl initialization here
+void vProbe::init() {
+}
+
+vProbe::~vProbe() {
+}
+
+//draws the cone here
+void vProbe::draw()
+{
+	color[0] = 0.0f;
+	color[1] = 1.0f;
+	color[2] = 0.0f;
+	glPushMatrix();
+        glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
+	glTranslatef(xform.trans[0],xform.trans[1],xform.trans[2]);
+	glMultMatrixf(xform.rotn);
+	glutSolidSphere(xform.scale,20,20);
+        glPopAttrib();
+	glPopMatrix();
+	return;
+}
+
+float sliceDim = 0.6f;
+float sliceVertexList[4][3] = {{0.0f, 0.0f, 0.0f},
+				{0.0f, 1.0f, 0.0f},
+				{1.0f, 1.0f, 0.0f},
+				{1.0f, 0.0f, 0.0f}};
+float polygonVertexList[4][3] = {{-sliceDim*3.0f, -sliceDim, 0.0f},
+				{-sliceDim*3.0f, sliceDim, 0.0f},
+				{sliceDim*3.0f, sliceDim, 0.0f},
+				{sliceDim*3.0f, -sliceDim, 0.0f}};
+float sepVertexList[2][4] = {{sliceDim+0.5f,sliceDim+0.5f, 0.0f},
+				{sliceDim+0.5f, 0.5-sliceDim, 0.0f, 1.0f}};
+
+vSliceView::vSliceView() :vPrimitive() {
+	setTranslation(0.0f,-2.0f,0.0f);
+}
+
+//do opngl initialization here
+void vSliceView::init() {
+}
+
+vSliceView::~vSliceView() {
+}
+
+
+void vSliceView::draw() {
+	//draw slice view
+#if defined(ADDCGGL)
+	setCurTextureCG(global.volren.origDeptexName);
+#endif
+#if defined(ADDARBGL)
+	setCurTextureARB(global.volren.origDeptexName);
+#endif
+	float xptr, yptr, zptr;		//location of the probe in the volume
+	global.volume->getNormProbe(xptr,yptr,zptr);//between 0..1
+	axialProbe.setTranslation(xptr,1.0f-zptr,0.0f);
+	coronalProbe.setTranslation(xptr,yptr,0.0f);
+	sagittalProbe.setTranslation(1.0f-zptr,yptr,0.0f);
+
+	//push the slicevew down
+	glPushMatrix();
+	glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glTranslatef(xform.trans[0], xform.trans[1], xform.trans[2]);
+	glMultMatrixf(xform.rotn);
+	glScalef(xform.scale,xform.scale,xform.scale);
+	disableTex3D();
+	glDisable(GL_LIGHTING);
+	glLineWidth(0.5f);
+	if (selected)
+		glColor3f(0.5f,0.5f,0.0f);
+	else
+		glColor3f(0.5f,0.5f,0.5f);
+	glBegin(GL_LINE_LOOP); //draw slice and texture map it
+		glVertex3fv(polygonVertexList[0]);
+		glVertex3fv(polygonVertexList[1]);
+		glVertex3fv(polygonVertexList[2]);
+		glVertex3fv(polygonVertexList[3]);
+	glEnd();
+	enableTex3D(global.volume->texName);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+	//the axial view, takes the y direction to index into the volume
+	glPushMatrix();
+	glTranslatef(-sliceDim*2,0.0f,0.0f);
+	glTranslatef(-0.5f,-0.5f,0.0f);
+	disableTex3D();
+	axialProbe.draw();
+	glBegin(GL_LINES);
+		glVertex3fv(sepVertexList[0]);
+		glVertex3fv(sepVertexList[1]);
+	glEnd();
+	//get the modelview matrix, multiply the pointer posn to see if it intersects this object
+
+	enableTex3D(global.volume->texName);
+	glBegin(GL_POLYGON); //draw slice and texture map it
+		glTexCoord3f(0.0f, yptr, 0.0f);
+		glVertex3fv(sliceVertexList[1]);
+		glTexCoord3f(0.0f, yptr, 1.0f);
+		glVertex3fv(sliceVertexList[0]);
+		glTexCoord3f(1.0f, yptr, 1.0f);
+		glVertex3fv(sliceVertexList[3]);
+		glTexCoord3f(1.0f, yptr, 0.0f);
+		glVertex3fv(sliceVertexList[2]);
+	glEnd();
+	glPopMatrix();
+
+	//the coronal view, takes the z
+	glPushMatrix();
+	glTranslatef(0.0f,0.0f,0.0f);
+	glTranslatef(-0.5f,-0.5f,0.0f);
+	disableTex3D();
+	coronalProbe.draw();
+	glBegin(GL_LINES);
+		glVertex3fv(sepVertexList[0]);
+		glVertex3fv(sepVertexList[1]);
+	glEnd();
+	enableTex3D(global.volume->texName);
+	glBegin(GL_POLYGON); //draw slice and texture map it
+		glTexCoord3f(0.0f, 0.0f, zptr);
+		glVertex3fv(sliceVertexList[0]);
+		glTexCoord3f(0.0f, 1.0f, zptr);
+		glVertex3fv(sliceVertexList[1]);
+		glTexCoord3f(1.0f, 1.0f, zptr);
+		glVertex3fv(sliceVertexList[2]);
+		glTexCoord3f(1.0f, 0.0f, zptr);
+		glVertex3fv(sliceVertexList[3]);
+	glEnd();
+	glPopMatrix();
+
+
+	//the sagittal view, takes the x
+	glPushMatrix();
+	glTranslatef(sliceDim*2,0.0f,0.0f);
+	//since we are starting (0..1)
+	glTranslatef(-0.5f,-0.5f,0.0f);
+	disableTex3D();
+	sagittalProbe.draw();
+	enableTex3D(global.volume->texName);
+	glBegin(GL_POLYGON); //draw slice and texture map it
+		glTexCoord3f(xptr, 0.0f, 0.0f);
+		glVertex3fv(sliceVertexList[3]);
+		glTexCoord3f(xptr, 0.0f, 1.0f);
+		glVertex3fv(sliceVertexList[0]);
+		glTexCoord3f(xptr, 1.0f, 1.0f);
+		glVertex3fv(sliceVertexList[1]);
+		glTexCoord3f(xptr, 1.0f, 0.0f);
+		glVertex3fv(sliceVertexList[2]);
+	glEnd();
+	glPopMatrix();
+
+	glPopAttrib();
+	glPopMatrix();
+}
+
+/*
+int vSliceView::select() {
+	if (withinBounds2D(mv,polygonVertexList,global.pointerPos)) {
+		selected = 1;
+	}
+	else
+		selected = 0;
+	return selected;
+}
+*/
Index: trunk/src/testing/app/volvis/vCut.cpp
===================================================================
--- trunk/src/testing/app/volvis/vCut.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vCut.cpp	(revision 4)
@@ -0,0 +1,113 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/s
+
+#include "vCut.h"
+#include "MatrixMath.h"
+#include "global.h"
+
+vCut::vCut() {
+}
+
+
+
+//called from textures draw
+void vCut::setTransform(float objectXform[]) {
+	float temp[3];
+	temp[0]=objectXform[0]*global.cut.axis[0]+
+			objectXform[4]*global.cut.axis[1]+objectXform[8]*global.cut.axis[2];
+	temp[1]=objectXform[1]*global.cut.axis[0]+
+			objectXform[5]*global.cut.axis[1]+objectXform[9]*global.cut.axis[2];
+	temp[2]=objectXform[2]*global.cut.axis[0]+
+			objectXform[6]*global.cut.axis[1]+objectXform[10]*global.cut.axis[2];
+	computeMatrix(global.cut.angle,temp,&global.cut.transform[0]);
+}
+
+
+void vCut::disable() {
+	glDisable(GL_CLIP_PLANE0);
+}
+
+void vCut::enable() {
+	global.cut.user[0] = -global.cut.transform[0];
+	global.cut.user[1]=global.cut.transform[1];
+	global.cut.user[2]=-global.cut.transform[2];
+
+//	fprintf(stderr,"cut plane %f %f %f %f\n",global.cut.user[0],global.cut.user[1],
+			//		global.cut.user[2], global.cut.user[3]);
+	//create the points for the corners of the clip plane
+	for (int ii=0;ii<4;ii++){
+		plane[ii*3+0]=global.cut.transform[0]*global.cut.user[3];
+		plane[ii*3+1]=-global.cut.transform[1]*global.cut.user[3];
+		plane[ii*3+2]=global.cut.transform[2]*global.cut.user[3];
+		plane[ii*3+0]-=global.cut.transform[4]*((ii<2)?0.5f:-0.5f);
+		plane[ii*3+1] +=global.cut.transform[5]*((ii<2)?0.5f:-0.5f);
+		plane[ii*3+2]-=global.cut.transform[6]*((ii<2)?0.5f:-0.5f);
+		plane[ii*3+0]-=global.cut.transform[8]*((ii&0x1)?-0.5f:0.5f);
+		plane[ii*3+1]+=global.cut.transform[9]*((ii&0x1)?-0.5f:0.5f);
+		plane[ii*3+2]-=global.cut.transform[10]*((ii&0x1)?-0.5f:0.5f);
+	}
+
+	//configure the clip planes
+	glClipPlane(GL_CLIP_PLANE0,global.cut.user);
+	glEnable(GL_CLIP_PLANE0);
+}
+
+void vCut::draw() {
+	glEnable(GL_TEXTURE_3D);
+	glDepthMask(GL_FALSE);
+	glPolygonMode(GL_FRONT, GL_LINE);
+	glPolygonMode(GL_BACK, GL_LINE);
+	glBegin(GL_QUADS);
+		glVertex3fv(&plane[0]);
+		glVertex3fv(&plane[3]);
+		glVertex3fv(&plane[9]);
+		glVertex3fv(&plane[6]);
+	glEnd();
+	glDepthMask(GL_TRUE);
+
+	glDisable(GL_ALPHA_TEST);
+	glDisable(GL_TEXTURE_3D);
+
+	glBegin(GL_LINES); //draw clip plane
+		glColor3f(1.0f,0.0f,0.0f);
+		glVertex3fv(&plane[0]);
+		glVertex3fv(&plane[3]);
+		glVertex3fv(&plane[3]);
+		glVertex3fv(&plane[9]);
+		glVertex3fv(&plane[9]);
+		glVertex3fv(&plane[6]);
+		glVertex3fv(&plane[6]);
+		glVertex3fv(&plane[0]);
+	glEnd();
+}
Index: trunk/src/testing/app/volvis/CCmdLine.h
===================================================================
--- trunk/src/testing/app/volvis/CCmdLine.h	(revision 4)
+++ trunk/src/testing/app/volvis/CCmdLine.h	(revision 4)
@@ -0,0 +1,228 @@
+/*------------------------------------------------------
+   CCmdLine
+
+   A utility for parsing command lines.
+
+   Copyright (C) 1999 Chris Losinger, Smaller Animals Software.
+   http://www.smalleranimals.com
+
+   This software is provided 'as-is', without any express
+   or implied warranty.  In no event will the authors be 
+   held liable for any damages arising from the use of this software.
+
+   Permission is granted to anyone to use this software 
+   for any purpose, including commercial applications, and 
+   to alter it and redistribute it freely, subject to the 
+   following restrictions:
+
+     1. The origin of this software must not be misrepresented; 
+   you must not claim that you wrote the original software. 
+   If you use this software in a product, an acknowledgment 
+   in the product documentation would be appreciated but is not required.
+   
+     2. Altered source versions must be plainly marked as such, 
+   and must not be misrepresented as being the original software.
+   
+     3. This notice may not be removed or altered from any source 
+   distribution.
+
+  -------------------------
+
+   Example :
+
+   Our example application uses a command line that has two
+   required switches and two optional switches. The app should abort
+   if the required switches are not present and continue with default
+   values if the optional switches are not present.
+
+      Sample command line : 
+      MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2
+
+      Switches -p1 and -p2 are required. 
+      p1 has two arguments and p2 has one.
+      
+      Switches -opt1 and -opt2 are optional. 
+      opt1 requires a numeric argument. 
+      opt2 has no arguments.
+      
+      Also, assume that the app displays a 'help' screen if the '-h' switch
+      is present on the command line.
+
+   #include "CmdLine.h"
+
+   void main(int argc, char **argv)
+   {
+      // our cmd line parser object
+      CCmdLine cmdLine;
+
+      // parse argc,argv 
+      if (cmdLine.SplitLine(argc, argv) < 1)
+      {
+         // no switches were given on the command line, abort
+         ASSERT(0);
+         exit(-1);
+      }
+
+      // test for the 'help' case
+      if (cmdLine.HasSwitch("-h"))
+      {
+         show_help();
+         exit(0);
+      }
+
+      // get the required arguments
+      StringType p1_1, p1_2, p2_1;
+      try
+      {  
+         // if any of these fail, we'll end up in the catch() block
+         p1_1 = cmdLine.GetArgument("-p1", 0);
+         p1_2 = cmdLine.GetArgument("-p1", 1);
+         p2_1 = cmdLine.GetArgument("-p2", 0);
+
+      }
+      catch (...)
+      {
+         // one of the required arguments was missing, abort
+         ASSERT(0);
+         exit(-1);
+      }
+
+      // get the optional parameters
+
+      // convert to an int, default to '100'
+      int iOpt1Val =    atoi(cmdLine.GetSafeArgument("-opt1", 0, 100));
+
+      // since opt2 has no arguments, just test for the presence of
+      // the '-opt2' switch
+      bool bOptVal2 =   cmdLine.HasSwitch("-opt2");
+
+      .... and so on....
+
+   }
+
+   If this class is used in an MFC application, StringType is CString, else
+   it uses the STL 'string' type.
+
+   If this is an MFC app, you can use the __argc and __argv macros from
+   you CYourWinApp::InitInstance() function in place of the standard argc 
+   and argv variables. 
+
+------------------------------------------------------*/
+#ifndef SACMDSH
+#define SACMDSH
+
+#define StringType string
+
+// tell the compiler to shut up
+#pragma warning(disable:4786)
+
+//#include <iostream> // you may need this
+#include <map>
+#include <string>
+#include <vector>
+using namespace std ;
+
+// handy little container for our argument vector
+struct CCmdParam
+{
+   vector<StringType> m_strings;
+};
+
+// this class is actually a map of strings to vectors
+typedef map<StringType, CCmdParam> _CCmdLine;
+
+// the command line parser class
+class CCmdLine : public _CCmdLine
+{
+
+public:
+   /*------------------------------------------------------
+      int CCmdLine::SplitLine(int argc, char **argv)
+
+      parse the command line into switches and arguments.
+
+      returns number of switches found
+   ------------------------------------------------------*/
+   int         SplitLine(int argc, char **argv);
+
+   /*------------------------------------------------------
+      bool CCmdLine::HasSwitch(const char *pSwitch)
+
+      was the switch found on the command line ?
+
+      ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+      call                          return
+      ----                          ------
+      cmdLine.HasSwitch("-a")       true
+      cmdLine.HasSwitch("-z")       false
+   ------------------------------------------------------*/   
+   bool        HasSwitch(const char *pSwitch);
+
+   /*------------------------------------------------------
+
+      StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
+
+      fetch an argument associated with a switch . if the parameter at
+      index iIdx is not found, this will return the default that you
+      provide.
+
+      example :
+  
+      command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+      call                                      return
+      ----                                      ------
+      cmdLine.GetSafeArgument("-a", 0, "zz")    p1
+      cmdLine.GetSafeArgument("-a", 1, "zz")    p2
+      cmdLine.GetSafeArgument("-b", 0, "zz")    p4
+      cmdLine.GetSafeArgument("-b", 1, "zz")    zz
+
+   ------------------------------------------------------*/
+
+   StringType  GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault);
+
+   /*------------------------------------------------------
+
+      StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx)
+
+      fetch a argument associated with a switch. throws an exception 
+      of (int)0, if the parameter at index iIdx is not found.
+
+      example :
+  
+      command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+      call                             return
+      ----                             ------
+      cmdLine.GetArgument("-a", 0)     p1
+      cmdLine.GetArgument("-b", 1)     throws (int)0, returns an empty string
+
+   ------------------------------------------------------*/
+   StringType  GetArgument(const char *pSwitch, int iIdx); 
+
+   /*------------------------------------------------------
+      int CCmdLine::GetArgumentCount(const char *pSwitch)
+
+      returns the number of arguments found for a given switch.
+
+      returns -1 if the switch was not found
+
+   ------------------------------------------------------*/
+   int         GetArgumentCount(const char *pSwitch);
+
+protected:
+   /*------------------------------------------------------
+
+   protected member function
+   test a parameter to see if it's a switch :
+
+   switches are of the form : -x
+   where 'x' is one or more characters.
+   the first character of a switch must be non-numeric!
+
+   ------------------------------------------------------*/
+   bool        IsSwitch(const char *pParam);
+};
+
+#endif
Index: trunk/src/testing/app/volvis/optiStorage.dat
===================================================================
--- trunk/src/testing/app/volvis/optiStorage.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiStorage.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 137.110.246.3
+1 137.110.246.4
+2 137.110.246.5
+3 137.110.246.6
+4 137.110.246.7
+5 137.110.246.8
+6 137.110.246.9
+7 137.110.246.10
+8 137.110.246.11
Index: trunk/src/testing/app/volvis/vRenderer.cpp
===================================================================
--- trunk/src/testing/app/volvis/vRenderer.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vRenderer.cpp	(revision 4)
@@ -0,0 +1,560 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include "vRenderer.h"
+#include "VectorMath.h"
+#include "MatrixMath.h"
+#include "glUE.h"
+#include "vVolume.h"
+#include "vCG.h"
+#include "vARB.h"
+#include <math.h>
+
+
+#if defined(linux)
+extern "C"
+{
+extern void glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+}
+#endif
+
+float vo[8][3] = {{0,0,0},{1.0f,0,0},{0,1.0f,0},{1.0f,1.0f,0},{0,0,1.0f},{1.0f,0,1.0f},{0,1.0f,1.0f},{1.0f,1.0f,1.0f}};
+float tx[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}};
+float axis[3]  = {0,0,1};
+double mv[16];
+vRenderer::vRenderer() {
+	myVolume = NULL;
+	cutEnabled = true;//enable cutplane by default
+	showOverview = false;
+}
+
+vRenderer::~vRenderer() {
+}
+
+
+int vRenderer::select() {
+	if (withinBounds3D(mv,vo,global.pointerPos)) {
+		selected = 1;
+	}
+	else
+		selected = 0;
+	return selected;
+}
+
+
+void vRenderer::init()
+{
+	if (myVolume) {
+		glGenTextures(1, &myVolume->texName);
+		loadTexture3D(myVolume->getVoxelData(), myVolume->dimX,myVolume->dimY,myVolume->dimZ);
+		GlErr("vRenderer", "init");
+	}
+
+}
+
+//load 1 byte volume
+void vRenderer::loadTexture3D(unsigned char *tex, int sx, int sy, int sz)
+{
+	glEnable(GL_TEXTURE_3D);
+	glBindTexture(GL_TEXTURE_3D, myVolume->texName);
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+#ifdef _WIN32
+	glTexImage3DEXT(GL_TEXTURE_3D, 0, GL_ALPHA8, sx, sy, sz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex);
+#else
+	glTexImage3D(GL_TEXTURE_3D, 0, GL_ALPHA8, sx, sy, sz, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex);
+#endif
+
+	GlErr("vRenderer", "loadTexture3D");
+	glDisable(GL_TEXTURE_3D);
+}
+
+void vRenderer::drawBoundBox() {
+	glDisable(GL_LIGHTING);
+	glPushMatrix();
+	glTranslatef(-0.5f,-0.5f,-0.5f);
+	glBegin(GL_LINES);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+	glEnd();
+	glPopMatrix();
+	glEnable(GL_LIGHTING);
+}
+
+void vRenderer::next() {
+	myVolume->next();
+	global.volren.loadVolume = true;
+}
+
+void vRenderer::prev() {
+	myVolume->prev();
+	global.volren.loadVolume = true;
+}
+
+
+void vRenderer::drawSubvolBoundBox() {
+	float scaleX, scaleY, scaleZ;
+	float offsetX, offsetY, offsetZ;
+	global.volume->getNormOffset(offsetX, offsetY, offsetZ);
+	global.volume->getNormDim(scaleX, scaleY, scaleZ);
+
+	glPushMatrix();
+	glTranslatef(offsetX, offsetY, offsetZ);
+	glTranslatef(-0.5f, -0.5f, -0.5f);
+	glScalef(scaleX,scaleY,scaleZ);
+
+	glBegin(GL_LINES);
+		glColor3f(1.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+	glEnd();
+	glPopMatrix();
+
+}
+//update any variables here- must be called from draw
+void vRenderer::update() {
+	//check if we need to reload volume, typically set by the roamer
+	if (global.volren.loadVolume) {
+		loadTexture3D(myVolume->getVoxelData(),myVolume->dimX,myVolume->dimY,myVolume->dimZ);
+		global.volren.loadVolume = false;
+	}
+	myVolume->getNormProbe(xptr,yptr,zptr);//between 0..1
+}
+
+//called by the main
+void vRenderer::draw()
+{
+	//update any variables before doing the draw
+	update();
+	//finally render
+	renderAll();
+}
+
+//
+//     (010)        (110)
+//       6 +---------+ 7   Where 1's are the size of the brick
+//        /|        /|      allong that axis
+//       / |       / |
+// (011)/  |(111) /  |
+//   4 +---------+ 5 |
+//     |   |     |   |(100) y axis
+//     | 2 +-----+---+ 3    ^
+//     |  /(000) |  /       |
+//     | /       | /        |
+//     |/        |/         |
+//   0 +---------+ 1        +-------> x axis
+//  (001)      (101)       /
+//                        /z axis
+
+void vRenderer::renderAll()
+{
+	//now start the render
+	glPushMatrix();
+	{ //move to the volume location
+		glTranslatef(xform.trans[0], xform.trans[1], xform.trans[2]);
+		/*if (rot) {
+			glRotatef(rotAngle,0.0f,1.0f,0.0f);
+			rotAngle ++;
+		}*/
+		glMultMatrixf(xform.rotn);  //rotate
+		glScalef(myVolume->spacingX*xform.scale, myVolume->spacingY*xform.scale, myVolume->spacingZ*xform.scale);
+		glGetDoublev(GL_MODELVIEW_MATRIX, mv);  //save modelview matrix
+		//translate the volume and render it
+		if (global.cut.update && cutEnabled) {
+			cut.setTransform(xform.rotn);
+			global.cut.update = false;
+		}
+		if (cutEnabled)
+			cut.draw();
+		//draw the box framing everything
+		if (global.ui.bboxEnabled) {
+			glColor3f(0.0f,0.25f,0.25f);
+			drawBoundBox();
+		}
+		if (selected) {
+			glColor3f(0.5f,0.5f,0.0f);
+			drawBoundBox();
+		}
+		if (showOverview)
+			drawSubvolBoundBox();
+
+		//draw just the 3d textures
+		enableTex3D(myVolume->texName);
+		if (cutEnabled)
+			cut.enable();
+
+		glPushMatrix();
+			glTranslatef(-0.5, -0.5,-0.5);
+			disableTex3D();
+			volProbe.setTranslation(xptr,yptr,zptr);
+			volProbe.draw();
+
+			glGetDoublev(GL_MODELVIEW_MATRIX, mv);  //save modelview matrix
+#if defined(ADDCGGL)
+			setCurTextureCG(global.volren.scaledDeptexName);
+#endif
+#if defined(ADDARBGL)
+			setCurTextureARB(global.volren.scaledDeptexName);
+#endif
+
+
+			enableTex3D(myVolume->texName);
+			renderTexture3D(global.volren.sampleRate,mv,vo,tx,axis);
+
+
+		glPopMatrix();
+
+		if (cutEnabled)
+			cut.disable();
+	}glPopMatrix();
+
+	disableTex3D();
+
+}
+void enableTex3D(unsigned int texName)
+{
+	glDisable(GL_LIGHTING); //light makes it look bad!
+	glPolygonMode(GL_FRONT, GL_FILL);
+	glPolygonMode(GL_BACK, GL_FILL);
+	glEnable(GL_TEXTURE_3D);
+	glEnable(GL_ALPHA_TEST);
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+#if defined(ADDCGGL)
+	enableCG(texName);
+#endif
+#if defined(ADDARBGL)
+	enableARB(texName);
+#endif
+}
+
+void disableTex3D() {
+	glDisable(GL_BLEND);
+	glDisable(GL_TEXTURE_3D);
+	glDisable(GL_ALPHA_TEST);
+	glEnable(GL_LIGHTING);
+	glDepthMask(GL_TRUE);
+
+#if defined(ADDCGGL)
+	disableCG();
+#endif
+#if defined(ADDARBGL)
+	disableARB();
+#endif
+}
+
+//understand the edge vertex computation from JMK@cs.utah.edu
+//ASSUMPTION: eye is along z-axis
+//vo: volume vertex coords model-space coords
+//tx: texture vertex coords tex-space coords
+//axis: axis to slice along world-space coords
+void vRenderer::renderTexture3D(float sampleFrequency,GLdouble mv[16],float vo[8][3],float tx[8][3],float axis[3])
+{
+    float rv[8][3];     //the rotated volume (may include a scale)
+    float maxval = -10; //(tmp)
+    float minval = 10;
+    int minvert = 0, maxvert = 0;
+    GLdouble mvinv[16];
+    int i, j, k;
+    inverseMatrix(mvinv, mv); //invert model view matrix
+
+    for(i=0; i<8; ++i){
+	translateV3(rv[i], mv, vo[i]); //get the rotated vol coords
+	//now get the max and min z in view space
+	if(maxval < MAX(maxval, rv[i][2])){
+	    maxval = MAX(maxval, rv[i][2]);
+	    maxvert = i;
+	}
+	if(minval > MIN(minval, rv[i][2])){
+	    minval = MIN(minval, rv[i][2]);
+	    minvert = i;  //determine the starting corner for slicing
+	}
+    }
+
+    //find the slice plane point 'sp' (initial) and the slice plane normal 'sn'
+    //sp is the slice starting point, simply the vertex farthest from the eye
+    float sp[3] = {vo[minvert][0], vo[minvert][1], vo[minvert][2]};
+//    float sp[3] = {vo[maxvert][0], vo[maxvert][1], vo[maxvert][2]};
+    float vpn[3];
+    vpn[0] = axis[0]; vpn[1] = axis[1]; vpn[2] = axis[2];
+
+    //now calculate sn which is the normalized vpn in the model space
+    //ie where the orginal slices are stored
+    float sn[3];
+    translateV3(sn, mvinv, vpn); //move vpn to sn (model space);
+    //now normalize this
+    float normsn = (float)sqrt(sn[0]*sn[0] + sn[1]*sn[1] + sn[2]*sn[2]); //normalize
+    sn[0]/=normsn;
+    sn[1]/=normsn;
+    sn[2]/=normsn;
+
+    //now find the distance we need to slice (|max_vertex - min_vertex|)
+    float maxd[3] = {0, 0, maxval}; //(tmp) only use z-coord (view space)
+    float mind[3] = {0, 0, minval}; //(tmp) ditto	    (view space)
+    float maxv[3], minv[3];	   //(tmp)
+    translateV3(maxv, mvinv, maxd); //translate back to model space
+    translateV3(minv, mvinv, mind); //ditto
+    maxv[0] -= minv[0]; //subtract
+    maxv[1] -= minv[1];
+    maxv[2] -= minv[2];
+
+    //now take the norm of this vector... we have the distance to be sampled
+    //this distance is in the world space
+    float dist = (float)sqrt(maxv[0]*maxv[0] + maxv[1]*maxv[1] + maxv[2]*maxv[2]);
+
+#if defined(ADDCGGL) || defined(ADDARBGL)
+    glColor4f(1.0f,1.0f,1.0f,0.01);
+#else
+    glColor4f(1.0f,1.0f,1.0f,0.1);
+#endif
+
+    GlErr("vRenderer","drawVA");
+
+    //distance between samples
+    float sampleSpacing = 1.0 / (myVolume->maxDim* sampleFrequency);
+    float del[3] = {sn[0]*sampleSpacing, sn[1]*sampleSpacing, sn[2]*sampleSpacing};
+
+    int samples = (int)((dist) / sampleSpacing);//(total distance to be sam	//highly un-optimized!!!!!!!!!
+    float poly[6][3];   // for edge intersections
+    float tcoord[6][3]; // for texture intersections
+    float tpoly[6][3];  // for transformed edge intersections
+    int edges;	       // total number of edge intersections
+
+    //the dep texture should be scaled
+    glBindTexture(GL_TEXTURE_3D, myVolume->texName);
+    //sp:slice plane point
+    //sn:the slice dirn to cut thru the volume
+    //the above 2 are in world coord space
+
+    for(i = 0 ; i < samples; ++i){ //for each slice
+	//increment the slice plane point by the slice distance
+//	sp[0] -= del[0];
+//	sp[1] -= del[1];
+//	sp[2] -= del[2];
+
+	sp[0] += del[0];
+	sp[1] += del[1];
+	sp[2] += del[2];
+
+	edges = 0;
+	//now check each edge of the volume for intersection with..
+	//the plane defined by sp & sn
+	//front bottom edge
+	edges += intersect(vo[0], vo[1], tx[0], tx[1], rv[0], rv[1], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//front left edge
+	edges += intersect(vo[0], vo[2], tx[0], tx[2], rv[0], rv[2], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//front right edge
+	edges += intersect(vo[1], vo[3], tx[1], tx[3], rv[1], rv[3], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//left bottom edge
+	edges += intersect(vo[4], vo[0], tx[4], tx[0], rv[4], rv[0], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//right bottom edge
+	edges += intersect(vo[1], vo[5], tx[1], tx[5], rv[1], rv[5], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//front top edge
+	edges += intersect(vo[2], vo[3], tx[2], tx[3], rv[2], rv[3], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//back bottom edge
+	edges += intersect(vo[4], vo[5], tx[4], tx[5], rv[4], rv[5], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//back left edge
+	edges += intersect(vo[4], vo[6], tx[4], tx[6], rv[4], rv[6], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//back right edge
+	edges += intersect(vo[5], vo[7], tx[5], tx[7], rv[5], rv[7], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//back top edge
+	edges += intersect(vo[6], vo[7], tx[6], tx[7], rv[6], rv[7], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//left top edge
+	edges += intersect(vo[2], vo[6], tx[2], tx[6], rv[2], rv[6], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+	//right top edge
+	edges += intersect(vo[3], vo[7], tx[3], tx[7], rv[3], rv[7], sp, sn,
+			   poly[edges], tcoord[edges], tpoly[edges]);
+
+	// B.M.E. Moret & H.D. Shapiro "P to NP" pp. 453
+
+	float dx, dy, tt ,theta, cen[2];  //tt= TempTheta
+	cen[0] = cen[1] = 0.0;
+	int next;
+	//rather than swap 3 arrays, only one?
+	int order[6] ={0,1,2,3,4,5};
+
+	// order[6] could be an extreemly inefficient way to do this
+	for(j=0; j<edges; ++j){ //find the center of the points
+	    cen[0] += tpoly[j][0];
+	    cen[1] += tpoly[j][1];
+	} //by averaging
+	cen[0]/= edges;
+	cen[1]/= edges;
+
+	for(j=0; j<edges; ++j){ //for each vertex
+	    theta = -10;	       //find one with largest angle from center..
+	    next = j;
+	    for (k= j; k<edges; ++k){
+		//... and check angle made between other edges
+		dx = tpoly[order[k]][0] - cen[0];
+		dy = tpoly[order[k]][1] - cen[1];
+		if( (dx == 0) && (dy == 0)){ //same as center?
+		    next = k;
+		    cout << "what teh " << endl;
+		    break; //out of this for-loop
+		}
+		tt = dy/(ABS(dx) + ABS(dy)); //else compute theta [0-4]
+		if( dx < 0.0 ) tt = (float)(2.0 - tt); //check quadrants 2&3
+		else if( dy < 0.0 ) tt = (float)(4.0 + tt); //quadrant 4
+		if( theta <= tt ){  //grab the max theta
+		    next = k;
+		    theta = tt;
+		}
+	    } //end for(k) angle checking
+	    // i am using 'tt' as a temp
+	    // swap polygon vertex ( is this better than another branch?)
+	    // I am not sure wich is worse: swapping 3 vectors for every edge
+	    // or: using an array to index into another array??? hmmm....
+	    //   should have payed more attention in class
+	    int tmp = order[j];
+	    order[j] = order[next];
+	    order[next] = tmp;
+
+	} //end for(j) edge /angle sort
+	renderSlice(edges, tcoord, poly, order);
+	//}//end else compute convex hull
+    }// end for(i) each slice
+    //now draw each slice view
+
+ }
+
+
+inline void vRenderer::renderSlice(int edges,float tc[6][3], float pc[6][3],int   order[6])
+{
+    glBegin(GL_POLYGON);  {//draw slice and texture map it
+	for(int j=0; j< edges; ++j)
+	{
+	    glTexCoord3fv(tc[order[j]]);
+	    glVertex3fv(pc[order[j]]);
+	}
+    } glEnd();
+}
+
+inline int vRenderer::intersect(const float p0[3], const float p1[3], //line end points
+				const float t0[3], const float t1[3], //texture points
+				const float v0[3], const float v1[3], //view coord points
+				const float sp[3], const float sn[3], //plane point & norm
+				float pnew[3], float tnew[3], float vnew[3]) //new values
+{
+    //t = (sn.(sp - p0))/(sn.(p1 - p0))
+    float t = ((sn[0]*(sp[0] - p0[0]) + sn[1]*(sp[1] - p0[1])
+		+ sn[2]*(sp[2] - p0[2])) /
+	       (sn[0]*(p1[0] - p0[0]) + sn[1]*(p1[1] - p0[1])
+		+ sn[2]*(p1[2] - p0[2])));
+    //note if the denominator is zero t is a NAN so we should have no problems?
+
+    if( (t>=0) && (t<=1) ){
+	//compute line intersection
+	pnew[0] = p0[0] + t*(p1[0] - p0[0]);
+	pnew[1] = p0[1] + t*(p1[1] - p0[1]);
+	pnew[2] = p0[2] + t*(p1[2] - p0[2]);
+	//compute texture interseciton
+	tnew[0] = t0[0] + t*(t1[0] - t0[0]);
+	tnew[1] = t0[1] + t*(t1[1] - t0[1]);
+	tnew[2] = t0[2] + t*(t1[2] - t0[2]);
+	//compute view coordinate intersections
+	vnew[0] = v0[0] + t*(v1[0] - v0[0]);
+	vnew[1] = v0[1] + t*(v1[1] - v0[1]);
+	vnew[2] = v0[2] + t*(v1[2] - v0[2]);
+	return 1;
+    }
+    return 0;
+}
+
+
Index: trunk/src/testing/app/volvis/vPrimitive.cpp
===================================================================
--- trunk/src/testing/app/volvis/vPrimitive.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vPrimitive.cpp	(revision 4)
@@ -0,0 +1,96 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include <string.h>
+#include "vPrimitive.h"
+#include "VectorMath.h"
+#ifdef WIN32
+#include <windows.h>		//  must be included before any OpenGL
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include <iostream.h>
+
+vPrimitive::vPrimitive()
+{
+	strcpy(name,"");
+	identityMatrix(xform.rotn);  //init the rotation
+	rot = false;
+	rotAngle = 0.0f;
+	xform.scale       = 1;        //identity for scale
+	xform.trans[0] = xform.trans[1] = xform.trans[2] = 0.0f;
+	color[0] = (rand()%100)*0.01f; //upto 2 digits precision
+	color[1] = (rand()%100)*0.01f; //upto 2 digits precision
+	color[2] = (rand()%100)*0.01f; //upto 2 digits precision
+	color[3] = 1.0f;
+	track.clear();
+	selected = false;
+	animate = false;
+	enabled = true;
+}
+
+/*
+int vPrimitive::key(unsigned char k, int x, int y)
+{
+  return 0;
+}
+
+int vPrimitive::special(int k, int x, int y)
+{
+	return 0;
+}
+
+
+int vPrimitive::mouse(int button, int state,
+			  int x, int y)
+{
+  return 1;
+}
+
+int vPrimitive::move(int x, int y)
+{
+  return 1;
+}
+
+int vPrimitive::release()
+{
+  return 0;
+}
+*/
+
Index: trunk/src/testing/app/volvis/Trackball.cpp
===================================================================
--- trunk/src/testing/app/volvis/Trackball.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/Trackball.cpp	(revision 4)
@@ -0,0 +1,218 @@
+//
+// ============================================================
+//                     === OpenGL Library === 
+//
+// $Date: 2004/10/28 22:43:53 $
+// $Revision: 1.1 $
+//
+// Hacked into C++ from SGI's trackball.h---see copyright
+// at end.
+// 
+// ============================================================
+//
+
+#include <iostream.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+
+#include "Trackball.h"
+#include "VectorMath.h"
+#include "MatrixMath.h"
+
+
+//===========================================================================
+//===========================================================================
+// Static Initialization
+//===========================================================================
+//===========================================================================
+
+//  This size should really be based on the distance from the center of
+//  rotation to the point on the object underneath the mouse.  That
+//  point would then track the mouse as closely as possible.  This is a
+//  simple example, though, so that is left as an Exercise for the
+//  Programmer.
+float  Trackball::trackballSize = (float)0.9;
+
+//  Number of iterations before we renormalize.
+int  Trackball::renormCount = 97;
+
+
+//===========================================================================
+//===========================================================================
+// Constructors/Destructor
+//===========================================================================
+//===========================================================================
+
+Trackball::Trackball()
+{
+  lastX = 0.0;
+  lastY = 0.0;
+  vZero(lastQuat);
+  vZero(curQuat);
+  lastQuat[3] = 1.0;
+  curQuat[3] = 1.0;
+}
+
+
+Trackball::~Trackball()
+{
+  //  Empty.
+}
+
+
+
+//===========================================================================
+// Public Member Functions
+//===========================================================================
+
+void
+Trackball::start(float x, float y)
+{
+  lastX = x;
+  lastY = y;
+  vZero(lastQuat);
+  lastQuat[3] = 1.0;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Ok, simulate a track-ball.  Project the points onto the virtual
+//  trackball, then figure out the axis of rotation, which is the cross
+//  product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
+//  Note:  This is a deformed trackball-- is a trackball in the center,
+//  but is deformed into a hyperbolic sheet of rotation away from the
+//  center.  This particular function was chosen after trying out
+//  several variations.
+//
+//  It is assumed that the arguments to this routine are in the range
+//  (-1.0 ... 1.0)
+//
+void
+Trackball::update(float x, float y)
+{
+  float p1[3], p2[3], d[3];
+  float t;
+
+  //  Might just be able to return here.
+  if (lastX == x && lastY == y) {
+    /* Zero rotation */
+    vZero(lastQuat);
+    lastQuat[3] = 1.0;
+    return;
+  }
+
+  /*
+   * First, figure out z-coordinates for projection of P1 and P2 to
+   * deformed sphere
+   */
+  vSet(p1, lastX, lastY, projectToSphere(trackballSize, lastX, lastY));
+  vSet(p2, x,     y,     projectToSphere(trackballSize,  x,    y));
+
+  /*
+   *  Now, we want the cross product of P1 and P2
+   */
+  vCross(p2, p1, a);
+
+  /*
+   *  Figure out how much to rotate around that axis.
+   */
+  vSub(p1,p2,d);
+  t = (float)(vLength(d) / (2.0*trackballSize));
+
+  /*
+   * Avoid problems with out-of-control values...
+   */
+  if (t > 1.0) t = 1.0;
+  if (t < -1.0) t = -1.0;
+  phi = (float)(2.0 * asin(t));
+
+  axisToQuat(a, phi, lastQuat);
+
+  lastX = x;
+  lastY = y;
+
+  addQuats(lastQuat, curQuat, curQuat);
+}
+
+//get the axis and angle for the rotation
+void Trackball::getAxisAngle(float& angle, float axis[3]) {
+	angle = phi*180.0f/3.141517;
+	for (int i=0;i<3;i++) 
+		axis[i] = a[i];
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// joeys clear
+//
+void 
+Trackball::clear()
+{
+  lastX = 0.0;
+  lastY = 0.0;
+  vZero(lastQuat);
+  vZero(curQuat);
+  lastQuat[3] = 1.0;
+  curQuat[3] = 1.0;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
+//  if we are away from the center of the sphere.
+//
+float
+Trackball::projectToSphere(float r, float x, float y)
+{
+  float d, t, z;
+
+  d = (float)(sqrt(x*x + y*y));
+  if (d < r * 0.70710678118654752440) {    /* Inside sphere */
+    z = (float)(sqrt(r*r - d*d));
+  } else {           /* On hyperbola */
+    t = (float)(r / 1.41421356237309504880);
+    z = t*t / d;
+  }
+  return z;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Build a rotation matrix, given a quaternion rotation.
+//
+void
+Trackball::buildRotMatrix(float m[4][4])
+{
+  m[0][0] = (float)(1.0 - 2.0 * (curQuat[1] * curQuat[1] + curQuat[2] * curQuat[2]));
+  m[0][1] = (float)(2.0 * (curQuat[0] * curQuat[1] - curQuat[2] * curQuat[3]));
+  m[0][2] = (float)(2.0 * (curQuat[2] * curQuat[0] + curQuat[1] * curQuat[3]));
+  m[0][3] = (float)(0.0);
+
+  m[1][0] = (float)(2.0 * (curQuat[0] * curQuat[1] + curQuat[2] * curQuat[3]));
+  m[1][1]= (float)(1.0 - 2.0 * (curQuat[2] * curQuat[2] + curQuat[0] * curQuat[0]));
+  m[1][2] = (float)(2.0 * (curQuat[1] * curQuat[2] - curQuat[0] * curQuat[3]));
+  m[1][3] = (float)(0.0);
+
+  m[2][0] = (float)(2.0 * (curQuat[2] * curQuat[0] - curQuat[1] * curQuat[3]));
+  m[2][1] = (float)(2.0 * (curQuat[1] * curQuat[2] + curQuat[0] * curQuat[3]));
+  m[2][2] = (float)(1.0 - 2.0 * (curQuat[1] * curQuat[1] + curQuat[0] * curQuat[0]));
+  m[2][3] = (float)(0.0);
+
+  m[3][0] = (float)(0.0);
+  m[3][1] = (float)(0.0);
+  m[3][2] = (float)(0.0);
+  m[3][3] = (float)(1.0);
+}
+
+void
+Trackball::reapply()
+{
+  addQuats(lastQuat, curQuat, curQuat);
+}
Index: trunk/src/testing/app/volvis/mmap.h
===================================================================
--- trunk/src/testing/app/volvis/mmap.h	(revision 4)
+++ trunk/src/testing/app/volvis/mmap.h	(revision 4)
@@ -0,0 +1,73 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+// mmap.h++
+
+#ifndef _MMAP
+#define _MMAP
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+
+class Mmap {
+    public:
+        Mmap();
+        ~Mmap();
+
+        int setFilename(const char *filename, int create = 0);
+        void setSize(size_t size);
+        void setShared(int shared) { _shared = shared; }
+        void setProt(int prot) { _prot = prot; }
+        void bzero();
+
+        caddr_t doMmap();
+
+        ssize_t getSize() { return _len; }
+        const char *getFilename() { return _filename; }
+
+    private:
+        char *_filename;
+        size_t _len;
+        size_t _fileSize;
+        int _shared, _prot;
+        int _fd;
+        caddr_t _mmapAddress;
+
+};
+
+#endif
Index: trunk/src/testing/app/volvis/vVolume.h
===================================================================
--- trunk/src/testing/app/volvis/vVolume.h	(revision 4)
+++ trunk/src/testing/app/volvis/vVolume.h	(revision 4)
@@ -0,0 +1,190 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _VVOLUME_H_
+#define _VVOLUME_H_
+#include "mmap.h"
+#include "private.h"
+#include "caDataManagerClient.h"
+#include <vector>
+
+#define H2D_DIM 256*256
+//for one timestep volume
+class vFrameData {
+public:
+	GLubyte* voxelData;
+	unsigned char* gradData;
+	unsigned char* hist;
+	QUANTAts_mutex_c histMutex;
+
+	vFrameData() {
+		voxelData = gradData = hist = 0;
+	}
+};
+
+//This class defines a volume
+class vVolume {
+public:
+	//row, column and depth of volume thats loaded into gfx
+	unsigned int dimX, dimY, dimZ;
+	unsigned int maxDim; //maximum dimension
+	//dimensions of the whole volume - on file
+	unsigned int fileX, fileY, fileZ;
+	//offset into the whole volume to read the subvolume
+	unsigned int offsetX, offsetY, offsetZ;
+	//spacing into the whole volume to read the subvolume
+	float spacingX, spacingY, spacingZ;
+	//current probe point
+	unsigned int probeX, probeY, probeZ;
+	vector<vFrameData> cache; //pointer to the time-series volume
+	int curVolume, numVolumes; //no of volumes and the current volume index
+	int probeValue, isoValue; //current value of the probe
+	unsigned int texName; //name of 3D texture associated with this volume
+//Member functions
+	vVolume(int x, int y, int z); //size of the whole volume
+	virtual ~vVolume();
+	//here is where the volume is actually loaded
+	//needs to be overloaded
+	virtual void load(int loadx, int loady, int loadz) = 0;
+	virtual void load() = 0;
+	//roaming the volume - overload this
+	virtual void roam(int roamx, int roamy, int roamz) = 0;
+	virtual int hist2D(unsigned char *normHist);
+	virtual int hist1D(unsigned char *normHist);
+	virtual void saveVolume(const char* filename);
+	virtual void saveGradient(const char* filename = "grad");
+	virtual void probe(int probeX, int probeY, int probeZ);
+	virtual void next() = 0;
+	virtual void prev() = 0;
+	//sets the vol dims/does power of 2 checking etc
+	void setLoadDims(int x, int y, int z) ;
+	virtual NetVertexBuffer* isoSurface() = 0;
+	virtual NetPointBuffer* isoPoint() = 0;
+
+	inline GLubyte getValue(int d, int r, int c) {
+		return cache[curVolume].voxelData[d*dimY*dimX+r*dimX+c];
+	}
+
+	inline void setValue(int d, int r, int c, GLubyte value) {
+		cache[curVolume].voxelData[d*dimY*dimX+r*dimX+c] = value;
+	}
+
+	inline GLubyte* getVoxelData() {
+		return cache[curVolume].voxelData;
+	}
+
+	inline void getNormProbe(float& x, float& y, float& z) {
+		x = (float)probeX/(float)(dimX-1);
+		y = (float)probeY/(float)(dimY-1);
+		z = (float)probeZ/(float)(dimZ-1);
+	}
+
+	inline void getNormOffset(float& x, float& y, float& z) {
+		x = (float)offsetX/(float)(fileX-1);
+		y = (float)offsetY/(float)(fileY-1);
+		z = (float)offsetZ/(float)(fileZ-1);
+	}
+
+	inline void getNormDim(float& x, float& y, float& z) {
+		x = (float)dimX/(float)(fileX);
+		y = (float)dimY/(float)(fileY);
+		z = (float)dimZ/(float)(fileZ);
+	}
+
+	inline void incIsoValue(int inc) {
+		isoValue += inc;
+		if (isoValue > 255)
+			isoValue = 255;
+		if (isoValue < 0)
+			isoValue = 0;
+		fprintf(stderr,"Isovalue now is %d\n",isoValue);
+	}
+	inline int getIsoValue() {
+		return isoValue;
+	}
+	inline int setIsoValue(int i) {
+		isoValue = i;
+	}
+};
+#if 0
+//class that handle volume access from a file
+class vFileVolume: public vVolume {
+public:
+	//if the volume is smaller than the volume in file, we need to pad it equally
+	unsigned int padX, padY, padZ;
+	char filename[256]; //filename associated with this 3d texture
+	char* 	gradientFile; //gradient file associated with this 3d texture
+	Mmap	mmap;
+	unsigned char* fileBuffer;
+
+//public member functions
+	vFileVolume(const char* filename, int c, int r, int d);
+	virtual ~vFileVolume();
+	void load(int x, int y, int z);
+	void load() {load(fileX,fileY,fileZ);};
+	//void roam(int roamx, int roamy, int roamz);
+private:
+	void loadVolumeFromFile(const char* filename);
+	void loadGradientFromFile(const char* filename); //load gradient info from file
+	void padVolume();//if volsize > filesize, pad the volume with black
+	void readASlice(GLubyte* plane, unsigned char* &curFilePtr) ; //read one plane from file
+	//if the volume is bigger than the file size, this will pad the volume
+	void calcGradient();
+};
+#endif
+//class to handle volume access from a data server
+class vOptiVolume: public vVolume {
+public:
+    cDataManagerClient* opClient; //pointer to the op client
+	int* indexList;
+	bool updateHist;
+//public member functions
+	vOptiVolume(const char*, const char*);
+	virtual ~vOptiVolume();
+	void load(int x, int y, int z);
+	void load();
+	void roam(int roamx, int roamy, int roamz);
+	int hist2D(unsigned char *normHist);
+	//get isosurface from opClient
+	NetVertexBuffer* isoSurface();
+	NetPointBuffer* isoPoint();
+	//void hist1D(unsigned char *normHist);
+	void setUpdateHist(bool flag) ;
+	bool getUpdateHist() ;
+	void next();
+	void prev();
+	void setCurVolume(int curVolume) ;
+};
+#endif
+
Index: trunk/src/testing/app/volvis/vProbe.h
===================================================================
--- trunk/src/testing/app/volvis/vProbe.h	(revision 4)
+++ trunk/src/testing/app/volvis/vProbe.h	(revision 4)
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//implements a probe or a 3d pointer
+#ifndef _VPROBE_H_
+#define _VPROBE_H_
+
+#include "glUE.h"
+#include "vPrimitive.h"
+#include "VectorMath.h"    //useful vector/matrix operations
+
+//class that handles the probe
+class vProbe: public vPrimitive {
+public:
+	vProbe();
+	virtual ~vProbe();
+	void init();
+	void draw();
+};
+
+
+class vPointer: public vPrimitive {
+public:
+	vPointer();
+	virtual ~vPointer();
+	void init();
+	void draw();
+};
+#endif
Index: trunk/src/testing/app/volvis/machines.dat.evl
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.evl	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.evl	(revision 4)
@@ -0,0 +1,15 @@
+3 0.66 19.46 1.2 32.4 0.0 0.0 1.0 1.0
+6 20.78 39.58 1.2 32.4 0.0 0.0 1.0 1.0
+9 40.9 59.7 1.2 32.4 0.0 0.0 1.0 1.0
+12 61.2 79.82 1.2 32.4 0.0 0.0 1.0 1.0
+15 81.14 99.94 1.2 32.4 0.0 0.0 1.0 1.0
+2 0.66 19.46 34.8 66.0 0.0 0.0 1.0 1.0
+5 20.78 39.58 34.8 66.0 0.0 0.0 1.0 1.0
+8 40.9 59.7 34.8 66.0 0.0 0.0 1.0 1.0
+11 61.2 79.82 34.8 66.0 0.0 0.0 1.0 1.0
+14 81.14 99.94 34.7 66.0 0.0 0.0 1.0 1.0
+1 0.66 19.46 68.4 99.6 0.0 0.0 1.0 1.0
+4 20.78 39.58 68.4 99.6 0.0 0.0 1.0 1.0
+7 40.9 59.7 68.4 99.6 0.0 0.0 1.0 1.0
+10 61.2 79.82 68.4 99.6 0.0 0.0 1.0 1.0
+13 81.14 99.94 68.4 99.6 0.0 0.0 1.0 1.0
Index: trunk/src/testing/app/volvis/optiRocks.dat
===================================================================
--- trunk/src/testing/app/volvis/optiRocks.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiRocks.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 137.110.243.4
+1 137.110.243.5
+2 137.110.243.6
+3 137.110.243.7
+4 137.110.243.8
+5 137.110.243.9
+6 137.110.243.10
+7 137.110.243.11
+8 137.110.243.12
Index: trunk/src/testing/app/volvis/vUI.cpp
===================================================================
--- trunk/src/testing/app/volvis/vUI.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vUI.cpp	(revision 4)
@@ -0,0 +1,401 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//functions to handle UI interaction - if current
+//command is not flushed user cant do anything anymore
+#include "vUI.h"
+#include "global.h"
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+#include "MatrixMath.h"
+#include <stdlib.h>
+#include "vGeometry.h"
+#include "vPrimitive.h"
+
+extern vector<vPrimitive*>   renderList;
+
+void mouseToWorld(int x, int y, float world[3]) {
+	float dx = (float)x/(float)global.win.width - 0.5;
+	float dy = (float)y/(float)global.win.height - 0.5;
+	world[0] = dx *(global.env.frustumList[0].right-global.env.frustumList[0].left) * (global.env.eye[2]-world[2])/global.env.clip[0];
+	world[1] = dy *(global.env.frustumList[0].top-global.env.frustumList[0].bottom) * (global.env.eye[2]-world[2])/global.env.clip[0];
+}
+
+void startRotation(int x, int y) {
+	glutSetWindowTitle("Rotate");
+	if (global.ui.cutEnabled)
+		cutTrack.start((2.0 * x - global.win.width) / global.win.width,(2.0 * y - global.win.height) / global.win.height);
+	else {
+		renderList[global.curPrimIdx]->track.start((2.0 * x - global.win.width) / global.win.width,(2.0 * y - global.win.height) / global.win.height);
+	}
+	global.mouse.pos[0] = global.mouse.last[0] = x;
+	global.mouse.pos[1] = global.mouse.last[1] = y;
+	global.volren.lowRes = true;
+#ifdef V_DISTRIBUTED
+	net->setLowRes(true);
+#endif
+}
+
+//when user is rotating typically mouse drag, call this
+void doRotation(int x, int y) {
+	if (global.ui.cutEnabled) {
+		global.cut.update = true;
+		cutTrack.update((2.0 * x - global.win.width) /global.win.width,(2.0 * y - global.win.height) /global.win.height);
+		cutTrack.getAxisAngle(global.cut.angle,global.cut.axis);
+#if defined(V_DISTRIBUTED)
+		net->setCutRotation(global.cut.angle, global.cut.axis);
+#endif
+	}
+	else {
+		renderList[global.curPrimIdx]->track.update((2.0 * x - global.win.width) / global.win.width,(2.0 * y - global.win.height) / global.win.height);
+		renderList[global.curPrimIdx]->track.buildRotMatrix((float (*)[4])renderList[global.curPrimIdx]->xform.rotn);
+#if defined(V_DISTRIBUTED)
+		net->setRotn(renderList[global.curPrimIdx]->xform.rotn);
+#endif
+	}
+	global.mouse.last[0] = x;
+	global.mouse.last[1] = y;
+
+}
+
+//during a button relase
+void endInteract() {
+	glutSetWindowTitle("Vol-a-Tile");
+	global.volren.lowRes = false;
+#ifdef V_DISTRIBUTED
+	net->setLowRes(false);
+#endif
+}
+
+void startZoom(int x, int y) {
+	glutSetWindowTitle("Zoom");
+	global.mouse.pos[0] = global.mouse.last[0] = x;
+	global.mouse.pos[1] = global.mouse.last[1] = y;
+	global.volren.lowRes = true;
+#ifdef V_DISTRIBUTED
+	net->setLowRes(true);
+#endif
+}
+
+void doZoom(int x, int y) {
+	float dx = (x - global.mouse.last[0])/(float)global.win.width;
+	float dy = (y - global.mouse.last[1])/(float)global.win.height;
+	float change;
+	if (fabs(dy) > fabs(dx))
+		change = dy;
+	else
+		change = dx;
+	if (global.ui.cutEnabled) {
+		global.cut.user[3]  += change; //between -1 and 1
+#if defined(V_DISTRIBUTED)
+		net->setCutZoom(change);
+#endif
+	}
+	else {
+//		global.env.eye[2] += dx;
+		renderList[global.curPrimIdx]->xform.scale += change;
+#if defined(V_DISTRIBUTED)
+		net->setZoom(change);
+#endif
+	}
+	global.mouse.last[0] = x;
+	global.mouse.last[1] = y;
+}
+
+//TRANSLATE
+
+//on a mouse-down call this
+void startTranslate(int x, int y) {
+	glutSetWindowTitle("Translate");
+	global.mouse.pos[0] = global.mouse.last[0] = x;
+	global.mouse.pos[1] = global.mouse.last[1] = y;
+	global.volren.lowRes = true;
+#ifdef V_DISTRIBUTED
+	net->setLowRes(true);
+#endif
+}
+
+//when user is translating
+void doTranslate(int x, int y) {
+	float dx = (x - global.mouse.last[0])/(float)global.win.width;
+	float dy = (y - global.mouse.last[1])/(float)global.win.height;
+	renderList[global.curPrimIdx]->xform.trans[0] += dx *(global.env.frustumList[0].right-global.env.frustumList[0].left) * global.env.eye[2]/global.env.clip[0];
+	renderList[global.curPrimIdx]->xform.trans[1] += dy *(global.env.frustumList[0].top-global.env.frustumList[0].bottom) * global.env.eye[2]/global.env.clip[0];
+#if defined(V_DISTRIBUTED)
+	net->setTranslation(renderList[global.curPrimIdx]->xform.trans);
+#endif
+	global.mouse.last[0] = x;
+	global.mouse.last[1] = y;
+
+}
+
+void printUsage() {
+	printf("VolViz\n");
+	printf("\t'c'	  - Switch between moving clip plane and object\n");
+	printf("\t'f'	  - Toggle printing FPS\n");
+	printf("\t'g'     - Switch between gray and psuedo color\n");
+	printf("\t'h'	  - Print usage help\n");
+	printf("\t'o'	  - Write the volume to file\n");
+	printf("\t'n'	  - Toggle printing number of slices\n");
+	printf("\t'+'     - Increase number of slices\n");
+	printf("\t'-'     - Decrease number of slices\n");
+	printf("\t<PAGE UP>  - Increase Eye Separation\n");
+	printf("\t<PAGE DOWN> - Decrease Eye Separation\n");
+	printf("\t<ESC>   - Quit\n");
+}
+
+void togglePrintFPS() {
+	global.ui.printFPS = !global.ui.printFPS;
+	fprintf(stderr,"print fps %d\n",global.ui.printFPS);
+	if (global.ui.printFPS)
+		glutIdleFunc(idle);
+	else
+		glutIdleFunc(0);
+#if defined(V_DISTRIBUTED)
+	net->togglePrintFPS();
+#endif
+}
+
+void toggleCutPlane() {
+	global.ui.cutEnabled = !global.ui.cutEnabled;
+#if defined(V_DISTRIBUTED)
+	net->toggleCutPlane();
+#endif
+}
+
+void saveGradientVolume() {
+	global.volume->saveGradient();
+#if defined(V_DISTRIBUTED)
+        net->saveGradientVolume();
+#endif
+}
+
+void toggleBoundBox() {
+	global.ui.bboxEnabled = !global.ui.bboxEnabled;
+#if defined(V_DISTRIBUTED)
+	net->toggleBoundBox();
+#endif
+}
+void scaleSampleRate(float factor) {
+	global.volren.goodSamp *= factor;
+	global.volren.interactSamp *= factor;
+	global.volren.sampleRate = global.volren.goodSamp;
+#if defined(V_DISTRIBUTED)
+	net->scaleSampleRate(factor);
+#endif
+}
+
+
+
+void doExit() {
+	deallocateAll();
+#if defined(ADDCG)
+	exitCG():
+#endif
+#if defined(V_DISTRIBUTED)
+	net->deactivateTiles();
+#else
+	exit(0);
+#endif
+}
+
+void doAxisRotation(float angle, char rotaxes) {
+	float axis[] = {0.0f,0.0f,0.0f};
+	switch (rotaxes) {
+	case 'x':
+		axis[0] = 1.0f;
+		break;
+	case 'y':
+		axis[1] = 1.0f;
+		break;
+	case 'z':
+		axis[2] = 1.0f;
+		break;
+	}
+	if (global.ui.cutEnabled) {
+		global.cut.update = true;
+		global.cut.angle = angle; //in degree
+		global.cut.axis[0] = axis[0]; //in degree
+		global.cut.axis[1] = axis[1]; //in degree
+		global.cut.axis[2] = axis[2]; //in degree
+#if defined(V_DISTRIBUTED)
+		net->setCutRotation(global.cut.angle, global.cut.axis);
+#endif
+	}
+	else {
+		computeMatrix(angle, axis, renderList[global.curPrimIdx]->xform.rotn);
+#if defined(V_DISTRIBUTED)
+		net->setRotn(renderList[global.curPrimIdx]->xform.rotn);
+#endif
+	}
+}
+
+//set the lookup table, either from network or locally
+void setLUT(int size, unsigned char* data) {
+	int tfSize = 256*4*sizeof(char);
+	for (int i=0;i<tfSize;i++)
+		global.volren.deptex[i] = data[i];
+	global.volren.loadTLUT = true;
+	global.volren.lowRes = *((int*)&data[tfSize]);
+#if defined(V_DISTRIBUTED)
+	net->setLUT(size,data);
+#endif
+}
+
+//set the low res
+void setLowRes(int lowres) {
+	global.volren.lowRes = lowres;
+#ifdef V_DISTRIBUTED
+	net->setLowRes(global.volren.lowRes);
+#endif
+}
+
+//get isosurface from the optiserver
+//and place it at the mouse ptr
+void genIsosurface(int x, int y) {
+	NetVertexBuffer* theGeom = global.volume->isoSurface();
+	vGeometry* newIso = new vGeometry(theGeom);
+	mouseToWorld(x,y,newIso->xform.trans);
+	newIso->initScale = 1.0f/global.volume->maxDim;
+	fprintf(stderr,"New geom translation %f %f scale %f\n",newIso->xform.trans[0],newIso->xform.trans[1],
+			newIso->initScale);
+	renderList.push_back(newIso);
+#ifdef V_DISTRIBUTED
+	net->getIsosurface(global.volume->getIsoValue(),newIso->xform.trans[0],newIso->xform.trans[1],newIso->xform.scale);
+#endif
+}
+
+/*
+void genIsopoint(int x, int y) {
+	NetPointBuffer* theGeom = global.volume->isoPoint();
+	vGeometry* newIso = new vGeometry(theGeom);
+	float dx = (float)x/(float)global.win.width - 0.5;
+	float dy = (float)y/(float)global.win.height - 0.5;
+	newIso->xform.trans[0] = dx * (global.env.frustum[1]-global.env.frustum[0]) * global.env.eye[2]/global.env.clip[0];
+	newIso->xform.trans[1] = dy *(global.env.frustum[3]-global.env.frustum[2]) * global.env.eye[2]/global.env.clip[0];
+	newIso->xform.scale = 1.0f/global.volume->maxDim;
+	fprintf(stderr,"New geom translation %f %f scale %f\n",newIso->xform.trans[0],newIso->xform.trans[1],newIso->xform.scale);
+	renderList.push_back(newIso);
+#ifdef V_DISTRIBUTED
+	net->getIsopoint(global.volume->getIsoValue(),newIso->xform.trans[0],newIso->xform.trans[1],newIso->xform.scale);
+#endif
+}
+*/
+void incIsoValue(int value) {
+	global.volume->incIsoValue(value);
+}
+
+void setRoam() {
+	global.ui.navMode= V_ROAM;
+#if defined(V_DISTRIBUTED)
+	net->setRoam();
+#endif
+}
+
+void roamVolume(int roamX, int roamY, int roamZ) {
+	global.volume->roam(roamX, roamY, roamZ);
+	global.volren.loadVolume = true;
+#if defined(V_DISTRIBUTED)
+	net->roamVolume(roamX, roamY, roamZ);
+#endif
+}
+
+void animateVolume() {
+	for (int i=0;i<renderList.size();i++)
+		renderList[i]->toggleAnimate();
+#if defined(V_DISTRIBUTED)
+	net->animateVolume();
+#endif
+}
+
+void updateAnim(int value)
+{
+	for (int i=0;i<renderList.size();i++) {
+		if (renderList[i]->isAnimating()) {
+			renderList[i]->next();
+		}
+	}
+//if defined(V_DISTRIBUTED)
+//	net->updateAnim();
+//#endif
+	glutTimerFunc(50, updateAnim, 1);
+}
+
+
+
+void setProbe() {
+	global.ui.navMode= V_PROBE;
+#if defined(V_DISTRIBUTED)
+	net->setProbe();
+#endif
+}
+
+void probeVolume(int probeX, int probeY, int probeZ) {
+	global.volume->probe(probeX, probeY, probeZ);
+#if defined(V_DISTRIBUTED)
+	net->probeVolume(probeX, probeY, probeZ);
+#endif
+}
+
+void doSelect(int curIndex) {
+	for (int i=0;i<renderList.size();i++) {
+		if (i==curIndex)
+			renderList[i]->setSelected(true);
+		else
+			renderList[i]->setSelected(false);
+	}
+#if defined(V_DISTRIBUTED)
+	net->select(curIndex);
+#endif
+}
+
+void doSelect(int x, int y) {
+	//get the pointer position in world coords
+	mouseToWorld(x, y, global.pointerPos) ;
+	global.curPrimIdx= 0;
+	//select each primitive to see which is selected
+	/*for (int i=0;i< renderList.size();i++) {
+		if (renderList[i]->select()) {
+			global.curPrimIdx= i;
+			break;
+		}
+	}*/
+
+#if defined(V_DISTRIBUTED)
+	net->select(global.pointerPos);
+#endif
+}
Index: trunk/src/testing/app/volvis/vTF.h
===================================================================
--- trunk/src/testing/app/volvis/vTF.h	(revision 4)
+++ trunk/src/testing/app/volvis/vTF.h	(revision 4)
@@ -0,0 +1,82 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//Class to handle the networking to get the transfer functions
+//vTF.h
+#if defined(V_NETTF)
+#ifndef _vTF_h_
+#define _vTF_h_
+
+#include <iostream.h>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include "private.h"
+
+//size of each command from the master
+#define COMMAND_SIZE 2048
+
+using namespace std;
+
+#define int32 cint32
+#define uint32 cuint32
+#undef int32
+#undef uint32
+
+//class that handles the transfer functions from the network
+//QUANTAts_mutex_c tfmutex;
+class vTF {
+public:
+	//default constructor - provide the rank, total # processors and if master processor should display the image
+	vTF();
+	void init();
+	~vTF();
+	void process();
+	void checkForConnections();
+
+	QUANTAnet_tcpServer_c* tcpServer ;
+	QUANTAnet_tcpClient_c *tcpClient;//the tcp client to receive data from
+	char clientIP[256]; //name of client
+	void sendHistogram() ;
+
+};
+
+#endif
+#endif
Index: trunk/src/testing/app/volvis/directions.h
===================================================================
--- trunk/src/testing/app/volvis/directions.h	(revision 4)
+++ trunk/src/testing/app/volvis/directions.h	(revision 4)
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * OptiStore - A Data Processing Server
+ * Copyright (C) 2003 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * Authors: Luc Renambot luc@evl.uic.edu
+ *          Shalini Venkataraman shalini@evl.uic.edu
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about OptiStore to luc@evl.uic.edu
+ *****************************************************************************/
+
+void GetDirection(int idx, float *x, float *y, float *z);
+void InitDirectionsTable();
+float *ConvertDirections(int sz,int sy,int sz,unsigned short *data);
+
Index: trunk/src/testing/app/volvis/shaders/fragment20.cg
===================================================================
--- trunk/src/testing/app/volvis/shaders/fragment20.cg	(revision 4)
+++ trunk/src/testing/app/volvis/shaders/fragment20.cg	(revision 4)
@@ -0,0 +1,9 @@
+
+float4 C2E2f_passthrough(float3 texCoord0 : TEXCOORD0,
+                         uniform sampler3D texture0,
+                         uniform sampler2D texture1                       
+                       ) : COLOR
+{
+    float2 tex0 = tex3D(texture0, texCoord0).ar;
+    return tex2D(texture1, tex0);
+}
Index: trunk/src/testing/app/volvis/shaders/fragment30.cg
===================================================================
--- trunk/src/testing/app/volvis/shaders/fragment30.cg	(revision 4)
+++ trunk/src/testing/app/volvis/shaders/fragment30.cg	(revision 4)
@@ -0,0 +1,9 @@
+
+float4 C2E2f_passthrough(float3 texCoord0 : TEXCOORD0,
+                       uniform sampler3D texture0,
+                       uniform sampler1D texture1                       
+                       ) : COLOR
+{
+    float tex0 = tex3D(texture0, texCoord0).a;
+    return tex1D(texture1, tex0);
+}
Index: trunk/src/testing/app/volvis/Makefile.sage.mac
===================================================================
--- trunk/src/testing/app/volvis/Makefile.sage.mac	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.sage.mac	(revision 4)
@@ -0,0 +1,33 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+#for evl
+#QUANTA_HOME=${HOME}/Q2
+QUANTA_HOME=/usr/local
+#for ncmir
+#QUANTA_HOME=/home/cavern/Q2
+#for igpp
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L${QUANTA_HOME}/lib -L../../lib
+LIBRARIES       = -framework GLUT -framework OpenGL -framework Cg -lobjc -lm -lquanta_32 -lsail
+CXXFLAGS        = -O3 -DADDCGGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR)  -DV_SAGE -I../../include -FGLUT -FOpenGL -FCg
+
+COMPILER 	= g++ -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+		/bin/cp $(EXEC) ../../bin
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/Makefile.sage
===================================================================
--- trunk/src/testing/app/volvis/Makefile.sage	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.sage	(revision 4)
@@ -0,0 +1,32 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+#for evl
+#QUANTA_HOME=${HOME}/Q2
+QUANTA_HOME=/usr/local
+#for ncmir
+#QUANTA_HOME=/home/cavern/Q2
+#for igpp
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L/usr/lib -L/usr/X11R6/lib64 -L${QUANTA_HOME}/lib -Wl,-rpath ${QUANTA_HOME}/lib -L../../lib
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64 -lsail
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR)  -DV_SAGE -I../../include
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= g++ -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) directions.o caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/machines.dat.igpp
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.igpp	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.igpp	(revision 4)
@@ -0,0 +1,8 @@
+3 0.0 23.4375 0.0 50.0 0 0 1 1
+4 23.4375 46.875 0.0 50.0 0 0 1 1
+7 53.125 76.56265 0.0 50.0 0 0 1 1
+8 76.56265 100.0 0.0 50.0 0 0 1 1 
+1 0.0 23.4375 50.0 100.0 0 0 1 1
+2 23.4375 46.875 50.0 100.0 0 0 1 1
+5 53.125 76.56265 50.0 100.0 0 0 1 1
+6 76.56265 100.0 50.0 100.0 0 0 1 1
Index: trunk/src/testing/app/volvis/TAGS
===================================================================
--- trunk/src/testing/app/volvis/TAGS	(revision 4)
+++ trunk/src/testing/app/volvis/TAGS	(revision 4)
@@ -0,0 +1,730 @@
+
+
+calculus.h,462
+#define _CALCULUS_h2,21
+inline derivative3D(6,155
+inline derivative3DVGH(47,1565
+inline void addDer(73,2577
+int AGradArb(118,4337
+void GMag(183,6348
+void GMagHess(205,6934
+inline void scalebias(289,10165
+inline void scalebiasN(306,10800
+inline void scaleBiasHiLoUC(323,11425
+inline void csaddV3(345,12198
+inline void csaddVARB(352,12330
+inline void csaddVARB(359,12466
+inline blurV3D(390,13192
+inline blurVARB(456,16121
+inline blurV3DN(541,19077
+
+
+CCmdLine.h,234
+#define SACMDSH112,3507
+#define StringType 114,3526
+using namespace std 123,3719
+struct CCmdParam126,3795
+typedef map<StringType,StringType132,3911
+typedef map<StringType, CCmdParam> _CCmdLine;132,3911
+class CCmdLine 135,3994
+
+
+global.h,1445
+#define __GLOBAL_H3,87
+	NONE=::NONE12,247
+	AGAVE,::AGAVE13,258
+	CROSSEYE::CROSSEYE14,268
+} vStereoType;15,279
+enum STEREOVIEW 17,297
+enum STEREOVIEW { LEFT,STEREOVIEW::LEFT17,297
+enum STEREOVIEW { LEFT, RIGHT}STEREOVIEW::RIGHT17,297
+struct vWindow 19,332
+struct vFrustum 28,549
+struct vViewport 32,608
+struct vStereo 36,664
+typedef vector<vFrustum> vFrustumList;41,732
+typedef vector<vViewport> vViewportList;42,772
+struct vEnv 43,814
+struct vLight{vLight59,1545
+struct vCutTransform 64,1681
+struct vTransform{vTransform73,1898
+struct vMouse{vMouse79,2136
+struct vKey 89,2532
+struct vRen 97,2768
+	V_ROAM,::V_ROAM120,3949
+	V_PROBE::V_PROBE121,3959
+} vNav;122,3969
+struct vUI 124,3980
+	V_Unknown,::V_Unknown135,4158
+		V_XPos,::V_XPos136,4171
+		V_XNeg,::V_XNeg137,4182
+		V_YPos,::V_YPos138,4193
+		V_YNeg,::V_YNeg139,4204
+		V_ZPos,::V_ZPos140,4215
+		V_ZNeg::V_ZNeg141,4226
+} VolRenMajorAxis;142,4236
+		V_UNKNOWN,::V_UNKNOWN146,4335
+		V_AMBIENT,::V_AMBIENT147,4350
+		V_DIFFUSE,::V_DIFFUSE148,4378
+		V_DSPEC,::V_DSPEC149,4405
+		V_FAUX,::V_FAUX150,4440
+		V_ARB,::V_ARB151,4469
+		V_MIP::V_MIP152,4521
+} vShade;153,4530
+	GPGineric,::GPGineric156,4589
+		GPNV20,::GPNV20157,4620
+		GPATI8K ::GPATI8K158,4674
+} vPlatform;159,4721
+	V_NONE,::V_NONE163,4755
+		V_UNDER,::V_UNDER164,4765
+		V_OVER,::V_OVER165,4777
+		V_ZERO::V_ZERO166,4788
+} vBlend;167,4798
+struct vGlobal 170,4813
+
+
+glUE.h,339
+using namespace std;31,1359
+#define AFX_GLUE_H__F345B9AF_7BCA_4BAB_BC9E_949B280622AE__INCLUDED_34,1458
+#define WILDCAT 38,1639
+#define RADEON 39,1659
+#define R200 40,1679
+#define GEFORCE3 41,1700
+#define GEFORCE2 42,1720
+typedef void (APIENTRY * PFNGLTEXIMAGE3DPROC)72,2850
+typedef void (APIENTRY * PFNGLCOLORTABLEEXTPROC)86,3552
+
+
+MatrixMath.h,807
+#define __MatrixMath_defined2,30
+inline void computeMatrix(6,141
+inline void computeMatrix(16,474
+inline void matrixEqual(28,864
+inline void matrixEqual(33,969
+inline void matrixMult(39,1134
+inline void matrixMult(62,2353
+inline void inverseMatrix(87,3629
+inline void inverseMatrix(124,4652
+inline void transposeMatrix(162,5709
+inline void transposeMatrix(186,6045
+inline void axis2Rot(211,6451
+inline void axis2Rot(231,6950
+inline void axis2Rot(251,7384
+inline void rot2Axis(272,7887
+inline void q2R(340,9270
+inline void axisToQuat(355,9716
+inline void normalizeQuat(376,10448
+inline void addQuats(393,11064
+inline void printMatrix(427,11582
+inline void printMatrix(440,11797
+inline void buildLookAt(453,12013
+inline int withinBounds3D(503,13018
+inline int withinBounds2D(544,14416
+
+
+mmap.h,232
+#define _MMAP4,27
+class Mmap 13,169
+        void setShared(Mmap::setShared20,334
+        void setProt(Mmap::setProt21,391
+        ssize_t getSize(Mmap::getSize26,506
+        const char *getFilename(Mmap::getFilename27,549
+
+
+private.h,338
+#define QUANTA_LITTLE_ENDIAN 18,260
+#define QUANTA_THREAD_SAFE 19,291
+#define QUANTA_USE_PTHREADS 20,322
+#define Q_INIT 24,396
+#define Q_BYE 25,415
+#define Q_LIST 26,434
+#define Q_LOAD 27,453
+#define Q_CROP 28,472
+#define Q_SAMPLE 29,491
+#define Q_ISO 30,510
+#define Q_VOL 31,529
+#define Q_POINT 32,548
+#define Q_EXIT 33,567
+
+
+Trackball.h,48
+#define Trackball_H2,21
+class  Trackball 4,44
+
+
+vARB.h,22
+#define _VARB_H_6,85
+
+
+vCG.h,21
+#define _VCG_H_5,85
+
+
+vCut.h,39
+#define _vCut_h_2,18
+class vCut 4,38
+
+
+VectorMath.h,2142
+#define __VectorMath_defined2,30
+#define EPSILON 12,207
+#define V_PI 13,230
+#define CLAMP(41,893
+#define MAX(42,947
+#define MIN(43,989
+#define ABS(44,1031
+#define NOTPOW2(45,1069
+inline double CLAMP_ARB(47,1113
+inline double affine(52,1244
+inline void zeroV3(59,1485
+inline void setV3(64,1555
+inline void negateV3(72,1730
+inline void copyV3(81,1898
+inline void copyV3(88,2007
+inline void copyV3(95,2138
+inline void subV3(103,2316
+inline void subV3(110,2469
+inline void addV3(118,2691
+inline void addV3(125,2848
+inline void scaleV3(133,3072
+inline void scaleV3(140,3169
+inline void cscaleV3(148,3330
+inline void cscaleV3(155,3458
+inline void identityMatrix(163,3650
+inline void identityMatrix(171,3845
+inline void translateV4(181,4127
+inline void translateV4_3W(190,4549
+inline void translateV4(198,4897
+inline void translateV3(208,5373
+inline void translateV3(215,5659
+inline void translateV3(222,5948
+inline void translateV3W(231,6369
+inline void translateV3W(238,6647
+inline void translateV3W(245,6953
+inline void translateV3WD(253,7301
+inline void transMatrixV3(265,7737
+inline GLfloat dotV4(274,8081
+inline GLdouble dotV4(279,8215
+inline GLfloat dotV3(285,8412
+inline GLdouble dotV3(290,8530
+inline GLfloat normV3(296,8711
+inline GLdouble normV3(301,8829
+inline void normalizeV4(307,9000
+inline void normalizeV4(318,9206
+inline void normalizeV3(330,9474
+inline void normalizeV3(340,9653
+inline void homogV4(351,9894
+inline void homogV4(359,9997
+inline void crossV3(369,10182
+inline void crossV3(376,10379
+inline int makepow2_max(385,10629
+inline int makepow2_min(399,10875
+inline void printV3(414,11073
+inline void printV3(419,11173
+inline void printV4(424,11272
+void quantize(436,11667
+void quantize(460,12224
+void quantize(484,12760
+void quantize(508,13288
+void quantize(532,13838
+inline void vZero(555,14385
+inline void vSet(562,14467
+inline void vSub(569,14569
+inline void vCopy(576,14738
+inline void vCross(582,14846
+inline float vLength(592,15109
+inline void vScale(597,15221
+inline void vNormal(604,15318
+inline float vDot(609,15395
+inline void vAdd(614,15507
+
+
+vFPSText.h,257
+#define _VFPSTEXT_H_8,286
+#define FRAME_HISTORY 15,397
+class CFrameTimer 18,487
+class vText 40,1149
+	vText(vText::vText42,1194
+class vFPSText 49,1304
+	vFPSText(vFPSText::vFPSText51,1346
+class vVolText 58,1439
+	vVolText(vVolText::vVolText60,1481
+
+
+vGeometry.h,50
+#define _V_GEOMETRY_H2,22
+class vGeometry 7,119
+
+
+vNet.h,281
+#define _vNet_h_5,105
+#define COMMAND_SIZE 21,408
+using namespace std;23,437
+#define int32 25,461
+#define uint32 26,483
+class vNet 32,671
+	inline int isActiveTile(vNet::isActiveTile100,2710
+	inline void sync(vNet::sync107,2806
+	inline int getRank(vNet::getRank111,2868
+
+
+vPrimitive.h,845
+#define __VPRIMITIVE_H2,24
+class vPrimitive 8,211
+	virtual ~vPrimitive(vPrimitive::~vPrimitive11,256
+	virtual  void          init(vPrimitive::init13,288
+	virtual  void          draw(vPrimitive::draw14,325
+	virtual void		next(vPrimitive::next16,365
+	virtual void		prev(vPrimitive::prev17,393
+	inline void setName(vPrimitive::setName19,423
+	inline void disable(vPrimitive::disable23,488
+	inline void enable(vPrimitive::enable27,540
+	inline void setTranslation(vPrimitive::setTranslation31,590
+	inline void setScale(vPrimitive::setScale37,723
+	inline void setColor(vPrimitive::setColor41,783
+	inline void setSelected(vPrimitive::setSelected48,915
+	inline bool isSelected(vPrimitive::isSelected52,974
+	inline bool isAnimating(vPrimitive::isAnimating56,1029
+	inline void toggleAnimate(vPrimitive::toggleAnimate60,1084
+
+
+vProbe.h,84
+#define _VPROBE_H_3,56
+class vProbe:vProbe10,211
+class vPointer:vPointer19,318
+
+
+vRenderer.h,385
+#define _VRENDERER_H2,22
+#define depX 12,220
+#define depY 13,238
+class vRenderer 14,256
+	void setVolume(vRenderer::setVolume20,368
+	inline void enableCut(vRenderer::enableCut28,613
+	inline void disableCut(vRenderer::disableCut32,669
+	inline void enableShowOverview(vRenderer::enableShowOverview35,725
+	inline void disableShowOverview(vRenderer::disableShowOverview39,792
+
+
+vSliceView.h,91
+#define _vSliceView_h_2,23
+class vProbe:vProbe8,121
+class vSliceView:vSliceView18,259
+
+
+vTF.h,142
+#define _vTF_h_5,112
+#define COMMAND_SIZE 20,396
+using namespace std;22,425
+#define int32 24,449
+#define uint32 25,471
+class vTF 31,617
+
+
+vUI.h,21
+#define _VUI_H_2,17
+
+
+vVolume.h,752
+#define _VVOLUME_H_2,21
+#define H2D_DIM 8,138
+class vFrameData 10,190
+	vFrameData(vFrameData::vFrameData17,323
+class vVolume 23,417
+	inline GLubyte getValue(vVolume::getValue61,2040
+	inline void setValue(vVolume::setValue65,2155
+	inline GLubyte* getVoxelData(vVolume::getVoxelData69,2283
+	inline void getNormProbe(vVolume::getNormProbe73,2362
+	inline void getNormOffset(vVolume::getNormOffset79,2541
+	inline void getNormDim(vVolume::getNormDim85,2727
+	inline void incIsoValue(vVolume::incIsoValue91,2895
+	inline int getIsoValue(vVolume::getIsoValue99,3090
+	inline int setIsoValue(vVolume::setIsoValue102,3143
+class vFileVolume:vFileVolume108,3256
+	void load(vFileVolume::load121,3743
+class vOptiVolume:vOptiVolume133,4295
+
+
+CCmdLine.cpp,233
+int CCmdLine::SplitLine(52,1666
+bool CCmdLine::IsSwitch(133,3572
+bool CCmdLine::HasSwitch(172,4532
+StringType CCmdLine::GetSafeArgument(200,5431
+StringType CCmdLine::GetArgument(236,6318
+int CCmdLine::GetArgumentCount(266,7019
+
+
+glUE.cpp,3911
+PFNGLTEXIMAGE3DPROC glTexImage3DEXT;7,91
+PFNGLBLENDEQUATIONEXTPROC glBlendEquationEXT;10,159
+PFNGLCOLORTABLEEXTPROC  glColorTableEXT;15,262
+GLPIXELTEXGENEXTFUNCPTR glPixelTexGenEXT;19,343
+PFNGLACTIVETEXTUREARBPROC       glActiveTexture;24,441
+PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture;25,491
+PFNGLMULTITEXCOORD1FARBPROC     glMultiTexCoord1fARB;26,547
+PFNGLMULTITEXCOORD1FVARBPROC    glMultiTexCoord1fvARB;27,602
+PFNGLMULTITEXCOORD2FARBPROC     glMultiTexCoord2fARB;28,658
+PFNGLMULTITEXCOORD2FVARBPROC    glMultiTexCoord2fvARB;29,713
+PFNGLMULTITEXCOORD3FARBPROC     glMultiTexCoord3fARB;30,769
+PFNGLMULTITEXCOORD3FVARBPROC    glMultiTexCoord3fvARB;31,824
+PFNGLSECONDARYCOLOR3FEXTPROC   glSecondaryColor3fEXT;36,940
+PFNGLCOMBINERPARAMETERFVNVPROC              glCombinerParameterfvNV;41,1060
+PFNGLCOMBINERPARAMETERFNVPROC               glCombinerParameterfNV;42,1131
+PFNGLCOMBINERPARAMETERIVNVPROC              glCombinerParameterivNV;43,1200
+PFNGLCOMBINERPARAMETERINVPROC               glCombinerParameteriNV;44,1270
+PFNGLCOMBINERINPUTNVPROC                    glCombinerInputNV;45,1339
+PFNGLCOMBINEROUTPUTNVPROC                   glCombinerOutputNV;46,1403
+PFNGLFINALCOMBINERINPUTNVPROC               glFinalCombinerInputNV;47,1469
+PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC      glGetCombinerInputParameterfvNV;48,1538
+PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC      glGetCombinerInputParameterivNV;49,1616
+PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC     glGetCombinerOutputParameterfvNV;50,1694
+PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC     glGetCombinerOutputParameterivNV;51,1773
+PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glGetFinalCombinerInputParameterfvNV;52,1852
+PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glGetFinalCombinerInputParameterivNV;53,1935
+PFNGLGENFRAGMENTSHADERSATIPROC   glGenFragmentShadersATI;58,2079
+PFNGLBINDFRAGMENTSHADERATIPROC   glBindFragmentShaderATI;59,2138
+PFNGLDELETEFRAGMENTSHADERATIPROC glDeleteFragmentShaderATI;60,2197
+PFNGLBEGINFRAGMENTSHADERATIPROC  glBeginFragmentShaderATI;61,2258
+PFNGLENDFRAGMENTSHADERATIPROC    glEndFragmentShaderATI;62,2318
+PFNGLPASSTEXCOORDATIPROC         glPassTexCoordATI;63,2376
+PFNGLSAMPLEMAPATIPROC            glSampleMapATI;64,2429
+PFNGLCOLORFRAGMENTOP1ATIPROC     glColorFragmentOp1ATI;65,2479
+PFNGLCOLORFRAGMENTOP2ATIPROC     glColorFragmentOp2ATI;66,2536
+PFNGLCOLORFRAGMENTOP3ATIPROC     glColorFragmentOp3ATI;67,2593
+PFNGLALPHAFRAGMENTOP1ATIPROC     glAlphaFragmentOp1ATI;68,2650
+PFNGLALPHAFRAGMENTOP2ATIPROC     glAlphaFragmentOp2ATI;69,2707
+PFNGLALPHAFRAGMENTOP3ATIPROC     glAlphaFragmentOp3ATI;70,2764
+PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glSetFragmentShaderConstantATI;71,2821
+PFNGLTEXBUMPPARAMETERIVATIXPROC     glTexBumpParameterivATIX;76,2945
+PFNGLTEXBUMPPARAMETERFVATIXPROC     glTexBumpParameterfvATIX;77,3008
+PFNGLGETTEXBUMPPARAMETERIVATIXPROC  glGetTexBumpParameterivATIX;78,3071
+PFNGLGETTEXBUMPPARAMETERFVATIXPROC  glGetTexBumpParameterfvATIX;79,3137
+PFNWGLCREATEPBUFFERARBPROC    wglCreatePbufferARB;84,3259
+PFNWGLGETPBUFFERDCARBPROC     wglGetPbufferDCARB;85,3311
+PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;86,3362
+PFNWGLDESTROYPBUFFERARBPROC   wglDestroyPbufferARB;87,3417
+PFNWGLQUERYPBUFFERARBPROC     wglQueryPbufferARB;88,3470
+PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;91,3558
+PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;92,3625
+PFNWGLCHOOSEPIXELFORMATARBPROC      wglChoosePixelFormatARB;93,3692
+PFNWGLBINDTEXIMAGEARBPROC     wglBindTexImageARB;96,3813
+PFNWGLRELEASETEXIMAGEARBPROC  wglReleaseTexImageARB;97,3864
+PFNWGLSETPBUFFERATTRIBARBPROC wglSetBufferAttribARB;98,3918
+void LoadAllExtensions(105,4157
+GLboolean QueryExtension(122,4705
+int checkGfx(162,5674
+int GlErr(212,7444
+int CardProfile(227,7854
+void getOGL12(237,7915
+void getNV20(370,13540
+void getATI8K(417,15881
+void getWGL(526,20917
+
+
+main.cpp,1094
+vector<vPrimitive*>   renderList;38,849
+vGlobal		global;39,921
+Trackball	cutTrack;40,979
+vNet* net 45,1146
+vTF * tfNet 50,1237
+	MENU_ROAM ::MENU_ROAM54,1288
+	MENU_PROBE,::MENU_PROBE55,1304
+        MENU_CUT,::MENU_CUT56,1317
+	MENU_ISOSURFACE,::MENU_ISOSURFACE57,1335
+	MENU_ISOPOINTS,::MENU_ISOPOINTS58,1353
+	MENU_BOUNDBOX,::MENU_BOUNDBOX59,1370
+	MENU_FPS,::MENU_FPS60,1386
+	MENU_SAMPLERATE,::MENU_SAMPLERATE61,1397
+	MENU_SAVEVOLUME,::MENU_SAVEVOLUME62,1415
+	MENU_SAVEGRADIENT,::MENU_SAVEGRADIENT63,1433
+	MENU_HELP,::MENU_HELP64,1453
+	MENU_EXIT::MENU_EXIT65,1465
+void menuCallback(68,1480
+int buildPopupMenu 111,2175
+void calcFrustum(129,2901
+void loadDepTex(143,3389
+void copyScale(190,5406
+void update(202,5781
+void deallocateAll(243,7685
+int main(257,8008
+void    initGlobal(401,11732
+void initGL(490,14731
+void display(502,15119
+void displayOneEye(533,16072
+void mouse(579,17460
+void passiveMotion(659,18833
+void motion(667,18965
+void key(729,19872
+void special(822,21365
+void idle(883,22816
+void reshape(888,22865
+void parseCmdLine(900,23129
+
+
+mmap.cpp,134
+Mmap::Mmap(4,38
+Mmap::~Mmap(15,222
+Mmap::setFilename(32,451
+void Mmap::setSize(65,1141
+Mmap::doMmap(81,1486
+Mmap::bzero(89,1609
+
+
+Trackball.cpp,360
+float  Trackball::trackballSize 36,1155
+int  Trackball::renormCount 39,1253
+Trackball::Trackball(48,1638
+Trackball::~Trackball(59,1786
+Trackball::start(71,2031
+Trackball::update(95,2783
+void Trackball::getAxisAngle(142,3813
+Trackball::clear(152,4060
+Trackball::projectToSphere(170,4424
+Trackball::buildRotMatrix(191,4918
+Trackball::reapply(215,5915
+
+
+vARB.cpp,392
+const char *shader_code1 shader_code112,160
+const char *shader_code shader_code34,954
+const char *shader_code3 shader_code346,1357
+GLuint vertexProgram,57,1575
+GLuint vertexProgram, fragmentProgram;57,1575
+int curTexId 58,1614
+void handleARBError(60,1630
+int initARB(66,1708
+void enableARB(137,4578
+void setCurTextureARB(166,5418
+void disableARB(171,5479
+void exitARB(179,5629
+
+
+vCG.cpp,470
+CGcontext context;9,154
+CGprogram vertexProgram,10,173
+CGprogram vertexProgram, fragmentProgram;10,173
+CGprofile fprofile,11,215
+CGprofile fprofile, vprofile;11,215
+CGparameter ModelViewProj;12,245
+CGparameter hTexture0,13,272
+CGparameter hTexture0, hTexture1;13,272
+CGparameter param;14,306
+int curTexId 15,325
+void handleCgError(16,340
+int initCG(22,451
+void enableCG(139,4312
+void setCurTextureCG(150,4607
+void disableCG(154,4667
+void exitCG(161,4833
+
+
+vCut.cpp,127
+vCut::vCut(5,67
+void vCut::setTransform(11,121
+void vCut::disable(23,613
+void vCut::enable(27,671
+void vCut::draw(52,1741
+
+
+vFileVolume.cpp,309
+vFileVolume::vFileVolume(16,397
+vFileVolume::~vFileVolume(25,622
+void vFileVolume::load(31,707
+void vFileVolume::loadVolumeFromFile(41,986
+void vFileVolume::padVolume(80,2235
+void vFileVolume::readASlice(126,3220
+void vFileVolume::loadGradientFromFile(152,4086
+void vFileVolume::calcGradient(170,4719
+
+
+vFPSText.cpp,362
+  renderBitmapString(5,72
+  renderStrokeString(15,300
+CFrameTimer::CFrameTimer(24,508
+void CFrameTimer::pingFrameCounter(47,1095
+float CFrameTimer::getFPS(80,2055
+vText::vText(91,2350
+void vText::init(95,2425
+void vText::draw(98,2452
+void vFPSText::init(112,2802
+void vFPSText::draw(120,2955
+void vVolText::init(128,3111
+void vVolText::draw(135,3234
+
+
+vGeometry.cpp,397
+static float geomColor[geomColor7,131
+static float geomAxes[geomAxes13,317
+static int geomIdx 19,454
+vGeometry::vGeometry(21,511
+vGeometry::vGeometry(44,1110
+vGeometry::~vGeometry(78,2039
+void vGeometry::setCurFrame(102,2458
+void vGeometry::init(112,2846
+void vGeometry::next(117,2973
+void vGeometry::prev(125,3127
+void vGeometry::drawBoundBox(132,3237
+void vGeometry::draw(168,4201
+
+
+vNet.cpp,1102
+char* getServerIP(7,115
+QUANTAts_mutex_c tfMutex;27,549
+vNet::vNet(28,576
+vNet::~vNet(35,679
+void vNet::init(38,703
+void vNet::deactivateTiles(53,1043
+void vNet::process(57,1101
+void vNet::processCmd(89,2101
+bool vNet::readTileConfig(250,7203
+void vNet::packCommand(315,9211
+void vNet::setRotn(329,9574
+void vNet::setLUT(336,9732
+void vNet::setCutRotation(345,9955
+void vNet::setCutZoom(353,10164
+void vNet::setLowRes(359,10281
+void vNet::saveGradientVolume(366,10457
+void vNet::select(371,10549
+void vNet::select(378,10704
+void vNet::setTranslation(384,10816
+void vNet::setZoom(391,10981
+void vNet::scaleSampleRate(397,11100
+void vNet::animateVolume(403,11230
+void vNet::updateAnim(408,11319
+void vNet::togglePrintFPS(414,11416
+void vNet::toggleCutPlane(419,11513
+void vNet::toggleBoundBox(424,11611
+void vNet::setRoam(429,11690
+void vNet::setProbe(434,11762
+void vNet::roamVolume(439,11847
+void vNet::probeVolume(447,12042
+void vNet::getIsosurface(456,12276
+void vNet::getIsopoint(466,12553
+void vNet::fillDummyCommand(476,12811
+void vNet::fillExitCommand(482,12934
+
+
+vOptiVolume.cpp,516
+QUANTAts_mutex_c mutex;16,446
+vOptiVolume::vOptiVolume(19,488
+vOptiVolume::~vOptiVolume(42,1244
+bool vOptiVolume::getUpdateHist(47,1322
+void vOptiVolume::setUpdateHist(55,1444
+int vOptiVolume::hist2D(61,1552
+void vOptiVolume::load(77,2045
+void vOptiVolume::setCurVolume(81,2107
+void vOptiVolume::next(96,2849
+void vOptiVolume::prev(103,2973
+void vOptiVolume::load(112,3102
+void vOptiVolume::roam(117,3269
+NetVertexBuffer* vOptiVolume::isoSurface(163,4976
+NetPointBuffer* vOptiVolume::isoPoint(168,5105
+
+
+vPrimitive.cpp,31
+vPrimitive::vPrimitive(10,201
+
+
+vProbe.cpp,275
+enum {SPHERE ::SPHERE4,119
+enum {SPHERE = 1, CONE}::CONE4,119
+vProbe::vProbe(6,145
+void vProbe::init(11,262
+vProbe::~vProbe(14,287
+void vProbe::draw(18,332
+vPointer::vPointer(35,735
+void vPointer::init(40,827
+vPointer::~vPointer(43,854
+void vPointer::draw(47,903
+
+
+vRenderer.cpp,672
+float vo[vo15,207
+float tx[tx16,327
+float axis[axis17,411
+double mv[mv18,437
+vRenderer::vRenderer(19,452
+vRenderer::~vRenderer(25,569
+int vRenderer::select(29,599
+void vRenderer::init(39,736
+void vRenderer::loadTexture3D(50,965
+void vRenderer::drawBoundBox(71,1786
+void vRenderer::next(105,2688
+void vRenderer::prev(110,2769
+void vRenderer::drawSubvolBoundBox(116,2851
+void vRenderer::update(158,4049
+void vRenderer::draw(168,4381
+void vRenderer::renderAll(192,4979
+void enableTex3D(257,6520
+void disableTex3D(275,6909
+void vRenderer::renderTexture3D(295,7380
+inline void vRenderer::renderSlice(477,14131
+inline int vRenderer::intersect(488,14403
+
+
+vSliceView.cpp,385
+vProbe::vProbe(6,84
+void vProbe::init(11,201
+vProbe::~vProbe(14,226
+void vProbe::draw(18,271
+float sliceDim 34,640
+float sliceVertexList[sliceVertexList35,663
+float polygonVertexList[polygonVertexList39,787
+float sepVertexList[sepVertexList43,969
+vSliceView::vSliceView(46,1084
+void vSliceView::init(51,1193
+vSliceView::~vSliceView(54,1222
+void vSliceView::draw(58,1254
+
+
+vTF.cpp,208
+void* netThreadCB(10,226
+vTF::vTF(18,345
+vTF::~vTF(24,400
+void vTF::init(29,466
+void vTF::checkForConnections(42,801
+#define HISTSIZE 55,1313
+void vTF::sendHistogram(56,1339
+void vTF::process(88,2576
+
+
+vUI.cpp,746
+void mouseToWorld(13,352
+void startRotation(20,781
+void doRotation(36,1402
+void endInteract(58,2229
+void startZoom(66,2379
+void doZoom(76,2631
+void startTranslate(104,3291
+void doTranslate(115,3583
+void printUsage(128,4240
+void togglePrintFPS(143,4863
+void toggleCutPlane(155,5134
+void saveGradientVolume(162,5278
+void toggleBoundBox(169,5418
+void scaleSampleRate(175,5562
+void doExit(186,5811
+void doAxisRotation(198,5972
+void setLUT(230,6784
+void setLowRes(242,7102
+void genIsosurface(251,7311
+void incIsoValue(280,8701
+void setRoam(284,8774
+void roamVolume(291,8910
+void animateVolume(299,9130
+void updateAnim(307,9302
+void setProbe(322,9560
+void probeVolume(329,9699
+void doSelect(336,9896
+void doSelect(348,10152
+
+
+vVolume.cpp,245
+vVolume::vVolume(16,430
+vVolume::~vVolume(30,742
+void vVolume::setLoadDims(38,906
+void vVolume::probe(51,1196
+int vVolume::hist2D(77,1809
+int vVolume::hist1D(106,2422
+void vVolume::saveVolume(136,3047
+void vVolume::saveGradient(149,3516
Index: trunk/src/testing/app/volvis/CCmdLine.cpp
===================================================================
--- trunk/src/testing/app/volvis/CCmdLine.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/CCmdLine.cpp	(revision 4)
@@ -0,0 +1,282 @@
+/*------------------------------------------------------
+   CCmdLine
+
+   A utility for parsing command lines.
+
+   Copyright (C) 1999 Chris Losinger, Smaller Animals Software.
+   http://www.smalleranimals.com
+
+   This software is provided 'as-is', without any express
+   or implied warranty.  In no event will the authors be 
+   held liable for any damages arising from the use of this software.
+
+   Permission is granted to anyone to use this software 
+   for any purpose, including commercial applications, and 
+   to alter it and redistribute it freely, subject to the 
+   following restrictions:
+
+     1. The origin of this software must not be misrepresented; 
+   you must not claim that you wrote the original software. 
+   If you use this software in a product, an acknowledgment 
+   in the product documentation would be appreciated but is not required.
+   
+     2. Altered source versions must be plainly marked as such, 
+   and must not be misrepresented as being the original software.
+   
+
+     3. This notice may not be removed or altered from any source 
+   distribution.
+
+   See SACmds.h for more info.
+------------------------------------------------------*/
+
+// if you're using MFC, you'll need to un-comment this line
+// #include "stdafx.h"
+
+#include "CCmdLine.h"
+#ifdef WIN32
+#include "crtdbg.h"
+#endif
+
+#if defined(linux) || defined(__APPLE__)
+#include <ctype.h>
+#endif
+
+/*------------------------------------------------------
+  int CCmdLine::SplitLine(int argc, char **argv)
+
+  parse the command line into switches and arguments
+
+  returns number of switches found
+------------------------------------------------------*/
+int CCmdLine::SplitLine(int argc, char **argv)
+{
+   clear();
+
+   StringType curParam; // current argv[x]
+
+   // skip the exe name (start with i = 1)
+   for (int i = 1; i < argc; i++)
+   {
+      // if it's a switch, start a new CCmdLine
+      if (IsSwitch(argv[i]))
+      {
+         curParam = argv[i];
+
+         StringType arg;
+
+         // look at next input string to see if it's a switch or an argument
+         if (i + 1 < argc)
+
+         {
+            if (!IsSwitch(argv[i + 1]))
+            {
+               // it's an argument, not a switch
+               arg = argv[i + 1];
+
+               // skip to next
+               i++;
+            }
+            else
+            {
+               arg = "";
+            }
+         }
+
+         // add it
+         CCmdParam cmd;
+
+         // only add non-empty args
+         if (arg != "")
+         {
+            cmd.m_strings.push_back(arg);
+         }
+
+         // add the CCmdParam to 'this'
+         pair<CCmdLine::iterator, bool> res = insert(CCmdLine::value_type(curParam, cmd));
+
+      }
+      else
+      {
+         // it's not a new switch, so it must be more stuff for the last switch
+
+         // ...let's add it
+ 	      CCmdLine::iterator theIterator;
+
+         // get an iterator for the current param
+         theIterator = find(curParam);
+	      if (theIterator!=end())
+         {
+            (*theIterator).second.m_strings.push_back(argv[i]);
+         }
+         else
+         {
+            // ??
+         }
+      }
+   }
+
+   return size();
+}
+
+/*------------------------------------------------------
+
+   protected member function
+   test a parameter to see if it's a switch :
+
+   switches are of the form : -x
+   where 'x' is one or more characters.
+   the first character of a switch must be non-numeric!
+
+------------------------------------------------------*/
+
+bool CCmdLine::IsSwitch(const char *pParam)
+{
+   if (pParam==NULL)
+      return false;
+
+   // switches must non-empty
+   // must have at least one character after the '-'
+   int len = strlen(pParam);
+   if (len <= 1)
+   {
+      return false;
+   }
+
+   // switches always start with '-'
+   if (pParam[0]=='-')
+   {
+      // allow negative numbers as arguments.
+      // ie., don't count them as switches
+      return (!isdigit(pParam[1]));
+   }
+   else
+   {
+      return false;
+   }
+}
+
+/*------------------------------------------------------
+   bool CCmdLine::HasSwitch(const char *pSwitch)
+
+   was the switch found on the command line ?
+
+   ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+   call                          return
+   ----                          ------
+   cmdLine.HasSwitch("-a")       true
+   cmdLine.HasSwitch("-z")       false
+------------------------------------------------------*/
+
+bool CCmdLine::HasSwitch(const char *pSwitch)
+{
+	CCmdLine::iterator theIterator;
+	theIterator = find(pSwitch);
+	return (theIterator!=end());
+}
+
+/*------------------------------------------------------
+
+   StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
+
+   fetch an argument associated with a switch . if the parameter at
+   index iIdx is not found, this will return the default that you
+   provide.
+
+   example :
+  
+   command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+   call                                      return
+   ----                                      ------
+   cmdLine.GetSafeArgument("-a", 0, "zz")    p1
+   cmdLine.GetSafeArgument("-a", 1, "zz")    p2
+   cmdLine.GetSafeArgument("-b", 0, "zz")    p4
+   cmdLine.GetSafeArgument("-b", 1, "zz")    zz
+
+------------------------------------------------------*/
+
+StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
+{
+   StringType sRet;
+   
+   if (pDefault!=NULL)
+      sRet = pDefault;
+
+   try
+   {
+      sRet = GetArgument(pSwitch, iIdx);
+   }
+   catch (...)
+   {
+   }
+
+   return sRet;
+}
+
+/*------------------------------------------------------
+
+   StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx)
+
+   fetch a argument associated with a switch. throws an exception 
+   of (int)0, if the parameter at index iIdx is not found.
+
+   example :
+  
+   command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
+
+   call                             return
+   ----                             ------
+   cmdLine.GetArgument("-a", 0)     p1
+   cmdLine.GetArgument("-b", 1)     throws (int)0, returns an empty string
+
+------------------------------------------------------*/
+
+StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx)
+{
+   if (HasSwitch(pSwitch))
+   {
+	   CCmdLine::iterator theIterator;
+
+      theIterator = find(pSwitch);
+	   if (theIterator!=end())
+      {
+         if ((*theIterator).second.m_strings.size() > iIdx)
+         {
+            return (*theIterator).second.m_strings[iIdx];
+         }
+      }
+   }
+
+   throw (int)0;
+
+   return "";
+}
+
+/*------------------------------------------------------
+   int CCmdLine::GetArgumentCount(const char *pSwitch)
+
+   returns the number of arguments found for a given switch.
+
+   returns -1 if the switch was not found
+
+------------------------------------------------------*/
+
+int CCmdLine::GetArgumentCount(const char *pSwitch)
+{
+   int iArgumentCount = -1;
+
+   if (HasSwitch(pSwitch))
+   {
+	   CCmdLine::iterator theIterator;
+
+      theIterator = find(pSwitch);
+	   if (theIterator!=end())
+      {
+         iArgumentCount = (*theIterator).second.m_strings.size();
+      }
+   }
+
+   return iArgumentCount;
+}
Index: trunk/src/testing/app/volvis/calculus.h
===================================================================
--- trunk/src/testing/app/volvis/calculus.h	(revision 4)
+++ trunk/src/testing/app/volvis/calculus.h	(revision 4)
@@ -0,0 +1,642 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _CALCULUS_h
+#define _CALCULUS_h
+//======================== calculus ===================================
+
+//standard scalar derivative measure
+inline derivative3D(unsigned char *magV1,
+					float *gradV3,
+					const int sx, const int sy, const int sz,
+					const unsigned char *dat)
+{
+	float *tmp = new float[sx*sy*sz];
+	float maxm = 0;
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				if((k<2)||(k>sx-3)||(j<2)||(j>sy-3)||(i<2)||(i>sz-3)){
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = 0;
+					tmp[i*sx*sy + j*sx + k] = 0;
+				}
+				else {
+					int dx = dat[i*sx*sy + j*sx + (k+1)] - dat[i*sx*sy + j*sx + (k-1)];
+					int dy = dat[i*sx*sy + (j+1)*sx + k] - dat[i*sx*sy + (j-1)*sx + k];
+					int dz = dat[(i+1)*sx*sy + j*sx + k] - dat[(i-1)*sx*sy + j*sx + k];
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = (float)dx;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = (float)dy;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = (float)dz;
+					tmp[i*sx*sy + j*sx + k] = (float)sqrt(dx*dx + dy*dy + dz*dz);
+					maxm = maxm < tmp[i*sx*sy + j*sx + k] ? tmp[i*sx*sy + j*sx + k] : maxm;
+				}
+			}
+		}
+	}
+	for( i = 0; i < sz; ++i){
+		for(int j = 0; j < sy; ++j){
+			for(int k = 0; k < sx; ++k){
+				magV1[i*sx*sy + j*sx + k] = (unsigned char)((tmp[i*sx*sy + j*sx + k]/maxm)*255);
+			}
+		}
+	}
+	delete[] tmp;
+}
+
+
+//standard scalar derivative measure - vgh volume (value grad hessian)
+inline derivative3DVGH(float *gradV3,
+					   const int sx, const int sy, const int sz,
+					   const unsigned char *dat)
+{
+	//cerr << "hi!!!!!!!!!! " << sz << " " << sy << " " << sx << endl;
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				if((k<1)||(k>sx-2)||(j<1)||(j>sy-2)||(i<1)||(i>sz-2)){
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = 0;
+				}
+				else {
+					int dx = dat[i*sx*sy*3     + j*sx*3     +(k+1)*3] - dat[i*sx*sy*3     + j*sx*3     + (k-1)*3];
+					int dy = dat[i*sx*sy*3     + (j+1)*sx*3 + k*3]    - dat[i*sx*sy*3     + (j-1)*sx*3 + k*3];
+					int dz = dat[(i+1)*sx*sy*3 + j*sx*3     + k*3]    - dat[(i-1)*sx*sy*3 + j*sx*3     + k*3];
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = (float)dx;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = (float)dy;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = (float)dz;
+				}
+			}
+		}
+	}
+}
+
+inline void addDer(unsigned char *magV1, float *gradV3,
+				   const int sx, const int sy, const int sz,
+				   const unsigned char *dat1, const unsigned char *dat2)
+{
+	float *tmp = new float[sx*sy*sz];
+	float maxm = 0;
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				if((k<2)||(k>sx-3)||(j<2)||(j>sy-3)||(i<2)||(i>sz-3)){
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = 0;
+					tmp[i*sx*sy + j*sx + k] = 0;
+				}
+				else {
+					int dx1 = dat1[i*sx*sy + j*sx + (k+1)] - dat1[i*sx*sy + j*sx + (k-1)];
+					int dy1 = dat1[i*sx*sy + (j+1)*sx + k] - dat1[i*sx*sy + (j-1)*sx + k];
+					int dz1 = dat1[(i+1)*sx*sy + j*sx + k] - dat1[(i-1)*sx*sy + j*sx + k];
+
+					int dx2 = dat2[i*sx*sy + j*sx + (k+1)] - dat2[i*sx*sy + j*sx + (k-1)];
+					int dy2 = dat2[i*sx*sy + (j+1)*sx + k] - dat2[i*sx*sy + (j-1)*sx + k];
+					int dz2 = dat2[(i+1)*sx*sy + j*sx + k] - dat2[(i-1)*sx*sy + j*sx + k];
+
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = (float)(dx1 + dx2);
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = (float)(dy1 + dy2);
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = (float)(dz1 + dz2);
+					tmp[i*sx*sy + j*sx + k] = (float)sqrt((dx1+dx2)*(dx1+dx2) + (dy1+dy2)*(dy1+dy2) + (dz1+dz2)*(dz1+dz2));
+					maxm = maxm < tmp[i*sx*sy + j*sx + k] ? tmp[i*sx*sy + j*sx + k] : maxm;
+				}
+			}
+		}
+	}
+	for( i = 0; i < sz; ++i){
+		for(int j = 0; j < sy; ++j){
+			for(int k = 0; k < sx; ++k){
+				magV1[i*sx*sy + j*sx + k] = (unsigned char)((tmp[i*sx*sy + j*sx + k]/maxm)*255);
+			}
+		}
+	}
+	delete[] tmp;
+}
+
+template<class T>                     //compute an additive gradient
+inline
+int AGradArb(float *gradV3,           //put it in here, create your data first
+			 int sx, int sy, int sz,  //size of each axis
+			 int n,                   //first n elements of data to compute grad with
+			 int elts,                //number of elements in the data
+			 T *data)                 //the data
+{
+#if 0
+	T **minmax = new T*[elts];
+	for(int e=0; e<elts; ++e){
+		minmax[e] = new T[2];
+		minmax[e][0] = (T)10000000000;
+		minmax[e][1] = (T)-10000000000;
+	}
+
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				for(int e=0; e<n; ++e){
+					minmax[e][0] = MIN(data[i*sx*sy*elts + j*sx*elts + (k+1)*elts + e], minmax[e][0]);
+					minmax[e][1] = MAX(data[i*sx*sy*elts + j*sx*elts + (k+1)*elts + e], minmax[e][1]);
+				}
+			}
+		}
+	}
+
+	for(e=0; e<elts; ++e){
+		cerr << "Volume " << e << " , min: " << (float)minmax[e][0] << "   max: " << (float)minmax[e][1] << endl;
+	}
+#endif
+
+	for(int i = 0; i < sz; ++i)
+	{
+		for(int j = 0; j < (sy); ++j)
+		{
+			for(int k = 0; k < (sx); ++k)
+			{
+				if((k<1)||(k>sx-2)||(j<1)||(j>sy-2)||(i<1)||(i>sz-2))
+				{
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = 0;
+				}
+				else
+				{
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] = 0;
+					gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] = 0;
+					for(int e=0; e<n; ++e)
+					{
+						gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0] += data[i*sx*sy*elts + j*sx*elts + (k+1)*elts + e] -
+							data[i*sx*sy*elts + j*sx*elts + (k-1)*elts + e];
+						gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1] += data[i*sx*sy*elts + (j+1)*sx*elts + k*elts + e] -
+							data[i*sx*sy*elts + (j-1)*sx*elts + k*elts + e];
+						gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2] += data[(i+1)*sx*sy*elts + j*sx*elts + k*elts + e] -
+							data[(i-1)*sx*sy*elts + j*sx*elts + k*elts + e];
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+inline
+void GMag(unsigned char *gmag, int sx, int sy, int sz, float *grad){
+	float maxm = 0;
+	float *tmp = new float[sx*sy*sz];
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				tmp[i*sx*sy + j*sx + k] = normV3(&grad[i*sx*sy*3 + j*sx*3 + k*3]);
+				maxm = MAX(tmp[i*sx*sy + j*sx + k], maxm);
+			}
+		}
+	}
+	for(i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				gmag[i*sx*sy + j*sx + k] = (unsigned char)(tmp[i*sx*sy + j*sx + k]/maxm * 255.0);
+			}
+		}
+	}
+	delete[] tmp;
+}
+
+inline
+void GMagHess(unsigned char *gmag, unsigned char *hess, int sx, int sy, int sz, float *gradV3){
+
+	float maxm = 0;
+	//find the gradient magnitude and it's max val
+	float *tmpg = new float[sx*sy*sz];
+	for(int i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				tmpg[i*sx*sy + j*sx + k] = normV3(&gradV3[i*sx*sy*3 + j*sx*3 + k*3]);
+				maxm = MAX(tmpg[i*sx*sy + j*sx + k], maxm);
+			}
+		}
+	}
+
+	float hmax = -100000000;
+	float hmin = 100000000;
+	float *tmph = new float[sx*sy*sz];
+
+	//compute the 2nd derivative in the gradient direction
+	//  a mask would probably help out here??
+	for(i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				if((k<1)||(k>sx-2)||(j<1)||(j>sy-2)||(i<1)||(i>sz-2)){
+					tmph[i*sx*sy + j*sx + k] = 0;
+				}
+				else {
+					float h[9];
+					h[0] = gradV3[i*sx*sy*3 + j*sx*3 + (k+1)*3 + 0] - gradV3[i*sx*sy*3 + j*sx*3 + (k-1)*3 + 0];
+					h[1] = gradV3[i*sx*sy*3 + (j+1)*sx*3 + k*3 + 0] - gradV3[i*sx*sy*3 + (j-1)*sx*3 + k*3 + 0];
+					h[2] = gradV3[(i+1)*sx*sy*3 + j*sx*3 + k*3 + 0] - gradV3[(i-1)*sx*sy*3 + j*sx*3 + k*3 + 0];
+					h[3] = gradV3[i*sx*sy*3 + j*sx*3 + (k+1)*3 + 1] - gradV3[i*sx*sy*3 + j*sx*3 + (k-1)*3 + 1];
+					h[4] = gradV3[i*sx*sy*3 + (j+1)*sx*3 + k*3 + 1] - gradV3[i*sx*sy*3 + (j-1)*sx*3 + k*3 + 1];
+					h[5] = gradV3[(i+1)*sx*sy*3 + j*sx*3 + k*3 + 1] - gradV3[(i-1)*sx*sy*3 + j*sx*3 + k*3 + 1];
+					h[6] = gradV3[i*sx*sy*3 + j*sx*3 + (k+1)*3 + 2] - gradV3[i*sx*sy*3 + j*sx*3 + (k-1)*3 + 2];
+					h[7] = gradV3[i*sx*sy*3 + (j+1)*sx*3 + k*3 + 2] - gradV3[i*sx*sy*3 + (j-1)*sx*3 + k*3 + 2];
+					h[8] = gradV3[(i+1)*sx*sy*3 + j*sx*3 + k*3 + 2] - gradV3[(i-1)*sx*sy*3 + j*sx*3 + k*3 + 2];
+					float tv[3];
+					float tg[3] = {gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 0]/tmpg[i*sx*sy + j*sx + k],
+						gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 1]/tmpg[i*sx*sy + j*sx + k],
+						gradV3[i*sx*sy*3 + j*sx*3 + k*3 + 2]/tmpg[i*sx*sy + j*sx + k]};
+
+					tv[0] = tg[0] * h[0] +
+						tg[1] * h[1] +
+						tg[2] * h[2];
+					tv[1] = tg[0] * h[3] +
+						tg[1] +
+						tg[2] * h[5];
+					tv[2] = tg[0] * h[6] +
+						tg[1] * h[7] +
+						tg[2] * h[8];
+					tmph[i*sx*sy + j*sx + k] = tg[0] * tv[0] +
+						tg[1] * tv[1] +
+						tg[2] * tv[2];
+					hmax = MAX(hess[i*sx*sy + j*sx + k], hmax);
+					hmin = MIN(hess[i*sx*sy + j*sx + k], hmin);
+
+				}
+			}
+		}
+	}
+
+	//now quantize to chars
+	for(i = 0; i < sz; ++i){
+		for(int j = 0; j < (sy); ++j){
+			for(int k = 0; k < (sx); ++k){
+				gmag[i*sx*sy + j*sx + k] = (unsigned char)(tmpg[i*sx*sy + j*sx + k]/maxm * 255.0);
+				if(hess[i*sx*sy + j*sx + k] < 0){
+					float th = (float)affine(hmin, tmph[i*sx*sy + j*sx + k], 0, 0, 1);
+					//th = (float)(1.0-((1.0-th)*(1.0-th)*(1.0-th)));
+					hess[i*sx*sy + j*sx + k] = (unsigned char)affine(0,th,1, 0, 255/3);
+				} else {
+					float th = (float)affine(0, tmph[i*sx*sy + j*sx + k], hmax, 0, 1);
+					//th = (float)(1.0-((1.0-th)*(1.0-th)*(1.0-th)));
+					hess[i*sx*sy + j*sx + k] = (unsigned char)affine(0,th,1,255/3,255/3*2);
+				}
+			}
+		}
+	}
+	delete[] tmpg;
+	delete[] tmph;
+}
+
+//float vector scale and bias to 8bit unsigned char
+inline void scalebias(unsigned char *ucgradV3, float *gradV3, int sx, int sy, int sz){
+	int stx = 3;
+	int sty = sx*3;
+	int stz = sy*sx*3;
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				ucgradV3[i*stz + j*sty + k*stx + 0] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 0]*128 + 128);
+				ucgradV3[i*stz + j*sty + k*stx + 1] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 1]*128 + 128);
+				ucgradV3[i*stz + j*sty + k*stx + 2] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 2]*128 + 128);
+			}
+		}
+	}
+
+}
+
+//float vector normalize, scale, and bias to 8bit unsigned char
+inline void scalebiasN(unsigned char *ucgradV3, float *gradV3, int sx, int sy, int sz){
+	int stx = 3;
+	int sty = sx*3;
+	int stz = sy*sx*3;
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				normalizeV3(&gradV3[i*stz + j*sty + k*stx + 0]);
+				ucgradV3[i*stz + j*sty + k*stx + 0] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 0]*128 + 128);
+				ucgradV3[i*stz + j*sty + k*stx + 1] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 1]*128 + 128);
+				ucgradV3[i*stz + j*sty + k*stx + 2] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 2]*128 + 128);
+			}
+		}
+	}
+
+}
+
+inline void scaleBiasHiLoUC(unsigned char *ucgradV2, float *gradV3, int sx, int sy, int sz){
+	int stx = 3;
+	int sty = sx*3;
+	int stz = sy*sx*3;
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				normalizeV3(&gradV3[i*stz + j*sty + k*stx + 0]);
+				if(gradV3[i*stz + j*sty + k*stx + 2] < 0){
+					gradV3[i*stz + j*sty + k*stx + 0] = -gradV3[i*stz + j*sty + k*stx + 0];
+					gradV3[i*stz + j*sty + k*stx + 1] = -gradV3[i*stz + j*sty + k*stx + 1];
+				}
+				ucgradV2[i*sx*sy*2 + j*sx*2 + k*2 + 0] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 0]*128 + 128);
+				ucgradV2[i*sx*sy*2 + j*sx*2 + k*2 + 1] = (unsigned char)(gradV3[i*stz + j*sty + k*stx + 1]*128 + 128);
+			}
+		}
+	}
+
+}
+
+//copy scale and add vector
+
+inline void csaddV3(GLfloat out[3], float s, GLfloat in[3])
+{
+	out[0] += s*in[0];
+	out[1] += s*in[1];
+	out[2] += s*in[2];
+}
+
+inline void csaddVARB(GLfloat out[3], float s, GLfloat in[3], int elts)
+{
+	for(int e=0; e<elts; ++e){
+		out[e] += s*in[e];
+	}
+}
+
+inline void csaddVARB(GLfloat out[3], float s, unsigned char in[3], int elts)
+{
+	for(int e=0; e<elts; ++e){
+		out[e] += (float)(s*(in[e]/255.0));
+	}
+}
+
+//blurr a 3D 3 vector field using these weights
+//				------------
+//       /w3 /w2 /w3 /
+//      /-----------/
+//	   /w2 /w1 /w2 /        <-- z+1
+//    /-----------/
+//   /w3 /w2 /w3 /
+//  /-----------/
+//				------------
+//       /w2 /w1 /w2 / y+1
+//      /-----------/
+//	   /w1 /w0 /w1 / y      <-- z
+//    /-----------/
+//   /w2 /w1 /w2 / y-1
+//  /-----------/
+//				------------
+//       /w3 /w2 /w3 /
+//      /-----------/
+//	   /w2 /w1 /w2 /        <-- z-1
+//    /-----------/
+//   /w3 /w2 /w3 /
+//  /-----------/
+//   x-1  x  x+1
+
+inline blurV3D(float *gradV3, float w0, float w1, float w2, float w3,
+			   int sx, int sy, int sz){
+	float *tmp = new float[sx*sy*sz*3];
+	int stx = 3;
+	int sty = sx*3;
+	int stz = sy*sx*3;
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				zeroV3(&tmp[i*stz + j*sty + k*stx + 0]);
+			}
+		}
+	}
+
+	for(i = 1; i<sz-1; ++i){
+		for(int j = 1; j<sy-1; ++j){
+			for(int k = 1; k<sx-1; ++k){
+				int idx = i*stz + j*sty + k*stx + 0;
+				csaddV3(&tmp[i*stz + j*sty + k*stx + 0], w0, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + k*stx + 0], w1, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+
+				csaddV3(&tmp[(i-1)*stz + j*sty + k*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + j*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + j*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+
+				csaddV3(&tmp[i*stz + (j+1)*sty + k*stx + 0], w1, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + (j+1)*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + (j+1)*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + k*stx + 0], w1, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + j*sty + (k+1)*stx + 0], w1, &gradV3[idx]);
+				csaddV3(&tmp[i*stz + j*sty + (k-1)*stx + 0], w1, &gradV3[idx]);
+			}
+		}
+	}
+
+	float div = w0 + 6*w1 + 12*w2 + 8*w3;
+
+	for(i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				gradV3[i*stz + j*sty + k*stx + 0] = tmp[i*stz + j*sty + k*stx + 0]/div;
+				gradV3[i*stz + j*sty + k*stx + 1] = tmp[i*stz + j*sty + k*stx + 1]/div;
+				gradV3[i*stz + j*sty + k*stx + 2] = tmp[i*stz + j*sty + k*stx + 2]/div;
+			}
+		}
+	}
+
+	delete[] tmp;
+}
+
+inline blurVARB(unsigned char *dataV, float w0, float w1, float w2, float w3,
+				int sx, int sy, int sz, int elts){
+
+	//cerr << "BLUR :   " << sx << "  " << sy  << "  " << sz << " * " << elts << endl;
+
+	float *tmp = new float[sx*sy*sz*elts];
+	int stx = elts;
+	int sty = sx*elts;
+	int stz = sy*sx*elts;
+	//cerr << "   stride " << stx << " " << sty << " " << stz << endl;
+
+
+
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				for(int e = 0; e< elts; ++e){
+					tmp[i*stz + j*sty + k*stx + e] = 0.0;
+				}
+			}
+		}
+	}
+
+	for(i = 1; i<sz-1; ++i){
+		for(int j = 1; j<sy-1; ++j){
+			for(int k = 1; k<sx-1; ++k){
+				for(int e = 0; e<elts; ++ e){
+					int idx = i*stz + j*sty + k*stx + e;
+					float v0 = (float)(dataV[idx]/255.0*w0);
+					float v1 = (float)(dataV[idx]/255.0*w1/6.0);
+					float v2 = (float)(dataV[idx]/255.0*w2/12.0);
+					float v3 = (float)(dataV[idx]/255.0*w3/8.0);
+
+					tmp[i*stz + j*sty + k*stx + e] += v0; //1
+					tmp[(i+1)*stz + j*sty + k*stx + e] += v1; //1
+					tmp[(i+1)*stz + (j+1)*sty + k*stx + e] += v2; //1
+					tmp[(i+1)*stz + (j+1)*sty + (k+1)*stx + e] += v3;	//1
+					tmp[(i+1)*stz + (j+1)*sty + (k-1)*stx + e] += v3;	//2
+					tmp[(i+1)*stz + (j-1)*sty + k*stx + e] += v2; //2
+					tmp[(i+1)*stz + (j-1)*sty + (k+1)*stx + e] += v3; //3
+					tmp[(i+1)*stz + (j-1)*sty + (k-1)*stx + e] += v3; //4
+					tmp[(i+1)*stz + j*sty + (k+1)*stx + e] += v2; //3
+					tmp[(i+1)*stz + j*sty + (k-1)*stx + e] += v2; //4
+
+					tmp[(i-1)*stz + j*sty + k*stx + e] += v1; //2
+					tmp[(i-1)*stz + (j+1)*sty + k*stx + e] += v2; //5
+					tmp[(i-1)*stz + (j+1)*sty + (k+1)*stx + e] += v3;	//5
+					tmp[(i-1)*stz + (j+1)*sty + (k-1)*stx + e] += v3;	//6
+					tmp[(i-1)*stz + (j-1)*sty + k*stx + e] += v2; //6
+					tmp[(i-1)*stz + (j-1)*sty + (k+1)*stx + e] += v3; //7
+					tmp[(i-1)*stz + (j-1)*sty + (k-1)*stx + e] += v3; //8
+					tmp[(i-1)*stz + j*sty + (k+1)*stx + e] += v2; //7
+					tmp[(i-1)*stz + j*sty + (k-1)*stx + e] += v2; //8
+
+					tmp[i*stz + (j+1)*sty + k*stx + e] += v1; //3
+					tmp[i*stz + (j+1)*sty + (k+1)*stx + e] += v2; //9
+					tmp[i*stz + (j+1)*sty + (k-1)*stx + e] += v2; //10
+					tmp[i*stz + (j-1)*sty + k*stx + e] += v1; //4
+					tmp[i*stz + (j-1)*sty + (k+1)*stx + e] += v2; //11
+					tmp[i*stz + (j-1)*sty + (k-1)*stx + e] += v2; //12
+					tmp[i*stz + j*sty + (k+1)*stx + e] += v1; //5
+					tmp[i*stz + j*sty + (k-1)*stx + e] += v1; //6
+				}
+			}
+		}
+	}
+
+	//float div = w0 + 6*w1 + 12*w2 + 8*w3;
+	float div = w0 + w1 + w2 + w3;
+
+	for(i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				for(int e =0; e<elts; ++e){
+					dataV[i*stz + j*sty + k*stx + e] = (unsigned char)(CLAMP((tmp[i*stz + j*sty + k*stx + e]/div))*255);
+				}
+			}
+		}
+	}
+
+	delete[] tmp;  //why does this explode?????
+}
+
+//same as above but normalize too
+
+inline blurV3DN(float *gradV3, float w0, float w1, float w2, float w3,
+				int sx, int sy, int sz){
+	float *tmp = new float[sx*sy*sz*3];
+	int stx = 3;
+	int sty = sx*3;
+	int stz = sy*sx*3;
+	for(int i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				zeroV3(&tmp[i*stz + j*sty + k*stx + 0]);
+			}
+		}
+	}
+
+	for(i = 1; i<sz-1; ++i){
+		for(int j = 1; j<sy-1; ++j){
+			for(int k = 1; k<sx-1; ++k){
+				int idx = i*stz + j*sty + k*stx + 0;
+				csaddV3(&tmp[i*stz + j*sty + k*stx + 0], w0, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + k*stx + 0], w1, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j+1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + (j-1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i+1)*stz + j*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+
+				csaddV3(&tmp[(i-1)*stz + j*sty + k*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j+1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + k*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + (k+1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + (j-1)*sty + (k-1)*stx + 0], w3, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + j*sty + (k+1)*stx + 0], w2, &gradV3[idx]);
+				csaddV3(&tmp[(i-1)*stz + j*sty + (k-1)*stx + 0], w2, &gradV3[idx]);
+
+				csaddV3(&tmp[i*stz + (j+1)*sty + k*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + (j+1)*sty + (k+1)*stx + 0], w2, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + (j+1)*sty + (k-1)*stx + 0], w2, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + k*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + (k+1)*stx + 0], w2, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + (j-1)*sty + (k-1)*stx + 0], w2, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + j*sty + (k+1)*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+				csaddV3(&tmp[i*stz + j*sty + (k-1)*stx + 0], w1, &gradV3[i*stz + j*sty + k*stx + 0]);
+
+			}
+		}
+	}
+
+	float div = w0 + 6*w1 + 12*w2 + 8*w3;
+
+	for(i = 0; i<sz; ++i){
+		for(int j = 0; j<sy; ++j){
+			for(int k = 0; k<sx; ++k){
+				scaleV3(1/div, &tmp[i*stz + j*sty + k*stx + 0]);
+				normalizeV3(&tmp[i*stz + j*sty + k*stx + 0]);
+				copyV3(&gradV3[i*stz + j*sty + k*stx + 0], &tmp[i*stz + j*sty + k*stx + 0]);
+			}
+		}
+	}
+
+	delete[] tmp;
+
+}
+#endif
Index: trunk/src/testing/app/volvis/vNet.h
===================================================================
--- trunk/src/testing/app/volvis/vNet.h	(revision 4)
+++ trunk/src/testing/app/volvis/vNet.h	(revision 4)
@@ -0,0 +1,161 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//Class to handle the network for tiled display
+//vNet.h
+#if defined(V_DISTRIBUTED)
+#ifndef _vNet_h_
+#define _vNet_h_
+
+#include <iostream.h>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include "mpi.h"
+#include "private.h"
+
+//size of each command from the master
+#define COMMAND_SIZE 2048
+
+using namespace std;
+
+#define int32 cint32
+#define uint32 cuint32
+#undef int32
+#undef uint32
+
+char* getServerIP(int rank, const char* serverFile) ;
+//Class that handles the image control operations (including MPI broadcast)
+class vNet {
+public:
+	//default constructor - provide the rank, total # processors and if master processor should display the image
+	vNet();
+	void init(int &argc, char** &argv);
+	~vNet();
+	//kills the tiles
+	void deactivateTiles();
+	//calls the dbclients process, used by network thread
+	void process();
+	//message parsing
+	void processCmd(char* data);
+	//read the config file
+	bool readTileConfig(const char* configFile);
+
+	//set the rotation matrix for all the volumes
+	void setRotn(float rotn[16]) ;
+	//set cutplane rotation
+	void setCutRotation(float angle, float axis[3]);
+	//set cutplane zoom
+	void setCutZoom(float dzoom);
+	//set the low res rendreing for all the volumes
+	void setLowRes(int lowRes) ;
+	//set zoom
+	void setZoom(float factor);
+	//set Translation
+	void setTranslation(float translation[3]);
+	//scale the sampling
+	void scaleSampleRate(float factor);
+	//set the transfer function
+	void setLUT (int, unsigned char *);
+	//toggle printing frame rate
+	void togglePrintFPS();
+	//toggle cut plane
+	void toggleCutPlane();
+	//toggle display of bound box
+	void toggleBoundBox();
+	//save gradient volume
+	void saveGradientVolume() ;
+	//roam the volume
+	void setRoam() ;
+	//roam the volume
+	void setProbe() ;
+	//roam the volume
+	void roamVolume(int x, int y, int z);
+	//probe the volume
+	void probeVolume(int x, int y, int z);
+	//get the isosurface for this isosurface
+	void getIsosurface(int isoValue, float tx, float ty, float scale) ;
+	//get isopoint
+	void getIsopoint (int, float, float, float);
+	//animate volume
+	void animateVolume();
+	//animate volume (rotate it on X)
+	void animateVolumeRotX();
+	//update the animation if any
+	void updateAnim();
+	//select index
+	void select(int curIndex);
+
+	//set the pointer position
+	void select(float pointerPos[3]) ;
+
+	//default dummy command - to synch the master and slave displays
+	void fillDummyCommand();
+	//indicate ready to exit
+	void fillExitCommand();
+	//returns true if Im the master, false otherwise
+	inline int isActiveTile() {
+		if (rank == master)
+			return 1;
+		else
+			return 0;
+	}
+
+	inline void sync() {
+		MPI_Barrier(MPI_COMM_WORLD);
+	}
+
+	inline int getRank() {
+		return rank;
+	}
+//protected:
+	char buffer[COMMAND_SIZE]; //Command buffer that is broadcast every frame
+	int readyToDie;
+	QUANTAnet_datapack_c dataPack;  //to be replaced by MPI datapack ?
+	//network params
+	int cmdFlushed; //if the current command has been flushed in order to handle the next one
+	int rank; //my rank id - to read the right configuration
+	int master;//the master id
+	int noProcs;
+	void packCommand(const char* cmdString, int flushed =0); //to pack any command
+};
+
+#endif
+#endif
Index: trunk/src/testing/app/volvis/optiGlobal.dat
===================================================================
--- trunk/src/testing/app/volvis/optiGlobal.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiGlobal.dat	(revision 4)
@@ -0,0 +1,16 @@
+0 206.220.241.20
+1 10.1.1.113
+2 10.1.1.117
+3 10.1.1.112
+4 10.1.1.113
+5 10.1.1.117
+6 10.1.1.112
+7 206.220.241.21
+8 206.220.241.22
+9 206.220.241.23
+10 206.220.241.24
+11 206.220.241.20
+12 206.220.241.21
+13 206.220.241.22
+14 206.220.241.23
+15 206.220.241.24
Index: trunk/src/testing/app/volvis/main.cpp
===================================================================
--- trunk/src/testing/app/volvis/main.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/main.cpp	(revision 4)
@@ -0,0 +1,1168 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <vector>
+#ifdef WIN32
+#include <windows.h>		//  must be included before any OpenGL
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+
+#include "Trackball.h"     //SGI quaternion trackball
+#include "VectorMath.h"    //usefull vector/matrix operations
+#include "global.h"         //global definitions
+#include "glUE.h"          //gl utilities and extensions
+#include "CCmdLine.h"
+#include "vFPSText.h"
+#include "vRenderer.h"     //standard renderer
+#include "vPrimitive.h"
+#include "vGeometry.h"
+#include "vNet.h"
+#include "vUI.h"
+#include "vSliceView.h"
+
+#if defined(ADDCGGL)
+#include "vCG.h"
+#endif
+#if defined(ADDARBGL)
+#include "vARB.h"
+#endif
+
+#if defined(V_DISTRIBUTED)
+#include "mpi.h"
+#include "vNet.h"
+#endif
+
+#if defined(V_NETTF)
+#include "vTF.h"
+#endif
+vector<vPrimitive*>   renderList; //all renderables attatch to this one
+vGlobal		global;	//the global v data structure (global.h)
+Trackball	cutTrack;	//global trackball
+
+/* Atul June 8 2004. Commented out the # since vNet is required for
+ * stand alone version also */
+#if defined(V_DISTRIBUTED)
+vNet* net = 0;	//The volvis controller
+#endif
+/* Atul June 8 2004 */
+
+#if defined(V_NETTF)
+vTF * tfNet = 0;	//The tfcontroller
+#endif
+
+#if defined(V_SAGE)
+	// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+#endif
+
+
+
+enum {
+	MENU_ROAM = 1,
+	MENU_PROBE,
+        MENU_CUT,
+	MENU_ISOSURFACE,
+	MENU_ISOPOINTS,
+	MENU_BOUNDBOX,
+	MENU_FPS,
+	MENU_SAMPLERATE,
+	MENU_SAVEVOLUME,
+	MENU_SAVEGRADIENT,
+	MENU_HELP,
+	MENU_EXIT
+};
+
+void menuCallback(int idCommand)
+{
+	switch (idCommand)
+	{
+		case MENU_ROAM:
+			setRoam();
+			break;
+		case MENU_PROBE:
+			setProbe();
+			break;
+		case MENU_CUT:
+			toggleCutPlane();
+			break;
+		case MENU_ISOSURFACE:
+			genIsosurface(100,100);
+			break;
+		case MENU_ISOPOINTS:
+			//genIsopoint(100,100);
+			break;
+		case MENU_BOUNDBOX:
+			toggleBoundBox();
+			break;
+		case MENU_FPS:
+			togglePrintFPS();
+			break;
+		case MENU_SAMPLERATE:
+			break;
+		case MENU_SAVEVOLUME:
+			if (global.volume)
+				global.volume->saveVolume("out");
+			break;
+		case MENU_SAVEGRADIENT:
+			saveGradientVolume();
+			break;
+		case MENU_HELP:
+			printUsage();
+			break;
+		case MENU_EXIT:
+			doExit();
+			break;
+	}
+}
+
+int buildPopupMenu (void)
+{
+        int menu;
+        menu = glutCreateMenu(menuCallback);
+        glutAddMenuEntry ("Roam", MENU_ROAM);
+        glutAddMenuEntry ("Probe", MENU_PROBE);
+        glutAddMenuEntry ("Enable Cut Plane", MENU_CUT);
+        glutAddMenuEntry ("Gen Isosurface", MENU_ISOSURFACE);
+        glutAddMenuEntry ("Boundbox Toggle", MENU_BOUNDBOX);
+        glutAddMenuEntry ("FPS Toggle", MENU_FPS);
+        glutAddMenuEntry ("Sample Rate", MENU_SAMPLERATE);
+        glutAddMenuEntry ("Save Volume", MENU_SAVEVOLUME);
+        glutAddMenuEntry ("Save Gradient Volume", MENU_SAVEGRADIENT);
+        glutAddMenuEntry ("Print Help", MENU_HELP);
+        glutAddMenuEntry ("Exit", MENU_EXIT);
+        return menu;
+}
+
+void calcFrustum() {
+	float fov = 45.0f*3.1415/180.0f;
+	float b = global.env.clip[0] * (float) tan(fov * 0.5);
+	float r = b * global.win.aspect;
+	for (int i=0;i<global.env.frustumList.size();i++) {
+		global.env.frustumList[i].left *= r;  //left
+		global.env.frustumList[i].right *= r;   //right
+		global.env.frustumList[i].bottom *= b;  //bottom
+		global.env.frustumList[i].top *= b;   //top
+	}
+}
+
+//loads the data in dtex to the handle associated with the dependant texture
+//sent to CG
+void loadDepTex(unsigned int deptexName, unsigned char *dtex)
+{
+#if defined(ADDCGGL)
+	if (fprofile == CG_PROFILE_FP30) {
+		// 1D tex
+		glEnable(GL_TEXTURE_1D);
+		glBindTexture(GL_TEXTURE_1D, deptexName);
+		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, depX, 0, GL_RGBA, GL_UNSIGNED_BYTE, dtex);
+		GlErr("vRenderer", "loadDepTex - loading scaled dependant texture");
+		glDisable(GL_TEXTURE_1D);
+	}
+	else if (fprofile == CG_PROFILE_FP20) {
+		// 2D tex for FP20
+		glEnable(GL_TEXTURE_2D);
+		glBindTexture(GL_TEXTURE_2D, deptexName);
+		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, depX, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, dtex);
+		GlErr("vRenderer", "loadDepTex - loading scaled dependant texture");
+		glDisable(GL_TEXTURE_2D);
+	}
+#endif
+
+#if defined(ADDARBGL)
+	// 2D tex for FP20
+	glEnable(GL_TEXTURE_2D);
+	glBindTexture(GL_TEXTURE_2D, deptexName);
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, depX, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, dtex);
+	GlErr("vRenderer", "loadDepTex - loading scaled dependant texture");
+	glDisable(GL_TEXTURE_2D);
+#endif
+}
+
+//takes the data from the 2d texture sent from the UI and copies it to the dependant texture
+//that will be passed to CG
+//the dependant texture is 1D but the UI texture is 2d, so for now,
+//just extract the first row of the UI 2d texture to the dependant texture
+void copyScale(float sampleRate, unsigned char *cgTex)
+{
+	float alphaScale = 1.0/sampleRate;
+	for(int j=0; j<depX; ++j){
+		cgTex[j*4 + 0] = global.volren.deptex[j*4 + 0];
+		cgTex[j*4 + 1] = global.volren.deptex[j*4 + 1];
+		cgTex[j*4 + 2] = global.volren.deptex[j*4 + 2];
+		cgTex[j*4 + 3] = (1.0 - ::pow((1.0-(global.volren.deptex[j*4 + 3]/255.0)), alphaScale))*255;
+
+	}
+}
+
+void update() {
+	//set the current sampling rate based on the interaction mode
+	if (global.volren.lowRes)
+		global.volren.sampleRate = global.volren.interactSamp;
+	else
+		global.volren.sampleRate = global.volren.goodSamp;
+
+	//Re-Scale Alpha values depending on no of slices
+	//if we need to load a new TF, load it here (from the remote UI)
+	if(global.volren.scaleAlphas){
+		if((global.volren.lastSamp != global.volren.sampleRate)||(global.volren.loadTLUT)){  //see if the sample rate changed
+			if((global.volren.lastGoodSamp != global.volren.goodSamp) || global.volren.loadTLUT){ //good sample rate changed
+				copyScale(global.volren.goodSamp * 1/global.volren.gamma, global.volren.gDeptex);
+				global.volren.lastGoodSamp = global.volren.goodSamp;
+			}
+			if((global.volren.lastInteSamp != global.volren.interactSamp) || global.volren.loadTLUT){ //interact samp rate changed
+				copyScale(global.volren.interactSamp * 1/global.volren.gamma, global.volren.iDeptex);
+				global.volren.lastInteSamp = global.volren.interactSamp;
+			}
+			if(global.volren.sampleRate == global.volren.goodSamp){ //which one do we load (good)
+				loadDepTex(global.volren.scaledDeptexName,global.volren.gDeptex);
+				global.volren.lastSamp = global.volren.goodSamp;
+			}
+			else if(global.volren.sampleRate == global.volren.interactSamp){ //(interactive)
+				loadDepTex(global.volren.scaledDeptexName,global.volren.iDeptex);
+				global.volren.lastSamp = global.volren.interactSamp;
+			}
+			copyScale(0.3, global.volren.nDeptex);
+			loadDepTex(global.volren.origDeptexName, global.volren.nDeptex);
+			global.volren.loadTLUT = 0;
+		}
+	} else {  //just do gamma scale, don't update for the sample rate (for testing purposes)
+		if(global.volren.loadTLUT){
+			copyScale(1/global.volren.gamma, global.volren.gDeptex);
+			loadDepTex(global.volren.scaledDeptexName, global.volren.gDeptex);
+			global.volren.loadTLUT = 0;
+		}
+	}
+
+}
+
+void deallocateAll() {
+	if (global.volume);
+		delete global.volume;
+	if (global.fullVolume)
+		delete global.fullVolume;
+	for (int i=0;i<renderList.size();i++)
+		delete renderList[i];
+
+	delete [] global.volren.deptex ;
+	delete [] global.volren.nDeptex;
+	delete [] global.volren.gDeptex;
+	delete [] global.volren.iDeptex;
+
+}
+int main(int argc, char **argv) {
+	initGlobal(); //init global variables
+
+	//init network related - MPI will change argc and argv
+	// so pass as ref
+	QUANTAinit();
+	srand( (unsigned)time(NULL)); //initialise randon number generator
+/* Atul June 8 2004. Commented out the # since vNet is required for
+ * stand alone version also */
+#if defined(V_DISTRIBUTED)
+	net = new vNet();
+	net->init(argc,argv);
+#endif
+/* Atul June 8 2004 */
+
+#if defined(V_NETTF) //want transfer functions
+#if defined (V_DISTRIBUTED) //in distributed mode, only master has this instance
+	if (net->isActiveTile()) {
+		tfNet = new vTF();
+		tfNet->init();
+	}
+#else //in standalone instantiate it
+	 tfNet = new vTF();
+	 tfNet->init();
+#endif
+#endif
+
+	//command line parsing - stores argumenents in global.*
+	parseCmdLine(argc,argv);
+
+#ifdef V_DISTRIBUTED
+        if (net->isActiveTile()) {
+               setenv("DISPLAY", getenv("VOLATILE_DISPLAY"), 1);
+        }
+#endif
+
+	glutInit(&argc, argv);
+	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+	glutInitWindowSize(global.win.width, global.win.height);
+	glutInitWindowPosition(global.win.xPos, global.win.yPos);
+	global.mainWindow =	glutCreateWindow("Vol-a-Tile");
+
+#if defined(V_SAGE)
+#if defined (V_DISTRIBUTED)
+	if (!net->isActiveTile())
+	{
+		sageInf.init("sail.conf", "volatile", net->getRank()-1,
+                     global.win.width, global.win.height, 24, TVPIXFMT_888, BOTTOM_TO_TOP);
+		fprintf(stderr, "SAIL width %d height %d\n", global.win.width, global.win.height);
+	}
+#else
+    sageInf.init("sail.conf", "volatile", 0,
+                 global.win.width, global.win.height, 24, TVPIXFMT_888, BOTTOM_TO_TOP);
+#endif
+#endif
+
+#ifdef WIN32
+	LoadAllExtensions();
+#endif
+
+	initGL(); //opengl init stuff
+	//init the dependant textures
+	//initialize the dependant texture for transfer functions
+	//copy the good and interactive dependant textures
+	copyScale(global.volren.goodSamp, global.volren.gDeptex);
+	copyScale(global.volren.interactSamp, global.volren.iDeptex);
+	copyScale(0.3, global.volren.nDeptex);
+	global.volren.lastSamp = global.volren.goodSamp;
+	global.volren.lastGoodSamp = global.volren.goodSamp;
+	global.volren.lastInteSamp = global.volren.interactSamp;
+
+	loadDepTex(global.volren.scaledDeptexName,global.volren.gDeptex);
+	loadDepTex(global.volren.origDeptexName,global.volren.nDeptex);
+	//load the given 1D texture to CG
+
+
+#if defined(ADDCGGL)
+        //init the CG library
+#if defined (V_DISTRIBUTED)
+    if (!net->isActiveTile())
+#endif
+        initCG();  // Master doesn't need CG
+#endif
+
+#if defined(ADDARBGL)
+#if defined (V_DISTRIBUTED)
+    if (!net->isActiveTile())
+#endif
+        initARB(); //init the ARB OpenGL
+#endif
+
+	//start creating our objects
+	//creating renderer object
+	if (global.volume) {
+		vRenderer* renderer = new vRenderer();
+		renderer->setVolume(global.volume);
+		renderList.push_back(renderer);
+
+		if (global.fullVolume) {
+			vRenderer* fullRenderer = new vRenderer;
+			fullRenderer->setVolume(global.fullVolume);
+			fullRenderer->disableCut();
+			fullRenderer->enableShowOverview();
+			fullRenderer->setTranslation(2.0,0.0,0.0);
+			renderList.push_back(fullRenderer);
+		}
+		//slice view
+		vSliceView* view = new vSliceView;
+		renderList.push_back(view);
+		//the info
+		vVolText* text = new vVolText;
+		renderList.push_back(text);
+
+	}
+
+
+	//now create the FPS text
+	vFPSText* timerText = new vFPSText;
+	renderList.push_back(timerText);
+	 //now create the pointer
+	//vPointer* ptr = new vPointer;
+	//renderList.push_back(ptr);
+
+	//initialise all the objects
+	for (int i=0;i<renderList.size();i++) {
+		renderList[i]->init();
+	}
+
+	GlErr("vRenderer", "init");
+
+#ifdef V_DISTRIBUTED
+	if (net->isActiveTile()) {
+		global.win.width  = 800;
+		global.win.height = 600;
+	}
+	else {
+        if (global.env.gameMode)
+            glutFullScreen();
+		glutSetCursor(GLUT_CURSOR_NONE);
+	}
+#else
+	if (global.env.gameMode)
+		glutFullScreen();
+#endif
+
+	glutDisplayFunc(display);
+	glutReshapeFunc(reshape);
+	glutMouseFunc(mouse);
+	glutMotionFunc(motion);
+	glutPassiveMotionFunc(passiveMotion);
+	glutKeyboardFunc(key);
+	glutSpecialFunc(special);
+	//only use idle when we are in standalone mode
+#ifndef V_DISTRIBUTED
+	glutIdleFunc(idle);
+#endif
+	buildPopupMenu ();
+    glutAttachMenu (GLUT_RIGHT_BUTTON);
+	//only master does the update and broadcasts it to client
+	//so that everyone is syncronized
+#ifdef V_DISTRIBUTED
+	//if (net->isActiveTile())
+	glutTimerFunc(50, updateAnim, 1);
+#else
+	glutTimerFunc(50, updateAnim, 1);
+#endif
+	glutMainLoop();
+	return 0;
+}
+
+void    initGlobal() {
+	global.volume = 0;
+	global.fullVolume = 0;
+
+	global.win.width  = 1024;      //size
+	global.win.height = 768;
+	global.win.xPos   = 0;      //position
+	global.win.yPos   = 0;
+	global.win.aspect = 1.0f;
+
+	global.env.eye[0]     = 0;    //eye
+	global.env.eye[1]     = 0;
+	global.env.eye[2]     = 10.0;
+	global.env.at[0]      = 0;    //at
+	global.env.at[1]      = 0;
+	global.env.at[2]      = 0;
+	global.env.up[0]      = 0;    //up
+	global.env.up[1]      = 1;
+	global.env.up[2]      = 0;
+	global.env.renderOn = true;
+
+	//create a default frustum
+	vFrustum newFrustum;
+	newFrustum.left = newFrustum.bottom = -1.0;
+	newFrustum.right= newFrustum.top = 1.0;
+	global.env.frustumList.push_back(newFrustum);
+
+	//create a default viewpoert
+	vViewport newViewport;
+	newViewport.x = newViewport.y = 0.0f;
+	newViewport.width = newViewport.height = 1.0f;
+	global.env.viewportList.push_back(newViewport);
+
+	global.env.clip[0]    = 1;    //front
+	global.env.clip[1]    = 50;   //back
+	global.env.bgColor    = 0;    //white background
+
+	global.mouse.alt     = 0;
+	global.mouse.ctrl    = 0;
+	global.mouse.shift   = 0;
+
+	//lighting
+	global.light.startpos[0] = -1.0f;
+	global.light.startpos[1] = -1.0f;
+	global.light.startpos[2] =-1.0f;
+	global.light.startpos[3] = 0.0f;
+
+	global.volren.interactSamp= .1;      //Interactive sample rate
+	global.volren.goodSamp    = 1.5;     //High quality sample ..
+	global.volren.sampleRate  = global.volren.goodSamp; //samples per voxel
+	global.volren.lowRes   = 0; //highres rendering
+	global.volren.deptex = new unsigned char[256*256*4];
+	for(int j=0; j<256; ++j){
+		for(int k=0; k<256; ++k){
+			global.volren.deptex[j*256*4 + k*4 + 0] =  (unsigned char)(k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 1] =  (unsigned char)(255 - k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 2] =  (unsigned char)( k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 3] =  (unsigned char)(k/(float)255*255/(float)2);
+		}
+	}
+	global.volren.nDeptex = new unsigned char[256*4];
+	global.volren.gDeptex	= new unsigned char[256*4];
+	global.volren.iDeptex = new unsigned char[256*4];
+	global.volren.loadTLUT    = 1;       //first time - need to load LUT
+	global.volren.loadVolume = 0; 		//no need to load the volume
+	global.volren.scaleAlphas = 1;       //scale alphas to the sample rate
+	global.volren.gamma       = 1;       //gamma identitiy
+	global.volren.probe[0] = global.volren.probe[1] = global.volren.probe[2] = 0;
+
+	identityMatrix(global.cut.transform);  //init the rotation
+	global.cut.user[0] = 1.0;
+	global.cut.user[1] = global.cut.user[2] = 0.0;
+	global.cut.user[3] = 0.5f;
+	global.cut.update = false;
+
+	global.ui.printFPS = false;
+	global.ui.printSlices = false;
+	global.ui.cutEnabled = false;
+	global.ui.bboxEnabled = true;
+	global.ui.navMode = V_ROAM;
+	global.ui.animate = false;
+
+	global.pointerPos[0] = global.pointerPos[1] = 0.0f;
+	global.pointerPos[2] = 1.0f;
+	global.curPrimIdx = 0;
+	cutTrack.clear();
+}
+
+
+void initGL( void )
+{
+	glClearColor(0.0, 0.0, 0.0, 1.0);
+	glShadeModel(GL_SMOOTH);
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LEQUAL);
+	glLineWidth(3);
+	glGenTextures(1, &global.volren.scaledDeptexName);   //the dep tex that we use for the tf- passed to CG
+	glGenTextures(1, &global.volren.origDeptexName);   //the dep tex that we use for the tf- passed to CG
+	GlErr("v::","initGL()");
+}
+
+void display()
+{
+#ifdef V_DISTRIBUTED
+	net->process();
+#endif
+	update();
+	if (global.env.renderOn) {
+		int vpx, vpy, vpwidth, vpheight;
+		glEnable (GL_SCISSOR_TEST); //dont draw outside viewpott
+		//depending on no of viewports
+		for (int i=0;i<global.env.viewportList.size();i++) {
+			vpx = global.env.viewportList[i].x*global.win.width;
+			vpy = global.env.viewportList[i].y*global.win.height;
+			vpwidth = global.env.viewportList[i].width*global.win.width;
+			vpheight = global.env.viewportList[i].height*global.win.height;
+			glViewport(vpx,vpy,vpwidth,vpheight);
+			//cout<<"Viewport "<<vpx<<" "<<vpy<<" "<<vpwidth<<" "<<vpheight<<endl;
+			glScissor (vpx,vpy,vpwidth,vpheight);
+			displayOneEye(1,i); // our local display function
+		}
+		glDisable (GL_SCISSOR_TEST); //dont draw outside viewpott
+	}
+	else
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#ifdef V_DISTRIBUTED
+	net->sync();
+#endif
+
+
+#if defined(V_SAGE)
+#if defined (V_DISTRIBUTED)
+	if (!net->isActiveTile())
+#endif
+        if (winWidth > 0)
+        {
+            glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);
+            sageInf.swapBuffer((void *)rgbBuffer);
+        }
+#endif
+
+	glutSwapBuffers();
+	GlErr("v:","disp()");
+}
+
+void displayOneEye(int eye, int vpIndex)
+{
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	//dont draw anything on the master
+	glPushMatrix();
+	{
+		glMatrixMode(GL_MODELVIEW);
+		glLoadIdentity();
+		gluLookAt(global.env.eye[0],  //eye
+				global.env.eye[1],
+				global.env.eye[2],
+				global.env.at[0],   //at
+				global.env.at[1],
+				global.env.at[2],
+				global.env.up[0],
+				global.env.up[1],
+				global.env.up[2]);          //up
+
+		GLfloat light_pos[] = { 5.0, 5.0, 5.0,1.0 };
+		glEnable(GL_LIGHTING);
+		glEnable(GL_LIGHT0);
+		glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+		glMatrixMode(GL_PROJECTION);
+		glLoadIdentity();
+		glFrustum(global.env.frustumList[vpIndex].left, //left
+			global.env.frustumList[vpIndex].right, //right
+                        global.env.frustumList[vpIndex].bottom , //bottom
+			global.env.frustumList[vpIndex].top, //top
+                        global.env.clip[0],    //front
+                        global.env.clip[1]);   //back
+
+		/*cout<<"Frustrum "<<global.env.frustumList[vpIndex].left<<" "
+			<<global.env.frustumList[vpIndex].right<<" "
+			<<global.env.frustumList[vpIndex].bottom<<" "
+			<<global.env.frustumList[vpIndex].top<<" "
+			<<endl;
+			*/
+		glMatrixMode(GL_MODELVIEW);
+		for (int i=0;i<renderList.size();i++) {
+			renderList[i]->draw();
+		}
+		renderList[global.curPrimIdx]->setSelected(true);
+
+	} glPopMatrix();
+}
+
+void mouse(int button, int state, int x, int y)
+{
+	y = global.win.height - y;
+	global.mouse.button = button;
+	global.mouse.state  = state;
+
+	if(glutGetModifiers() & GLUT_ACTIVE_CTRL) global.mouse.ctrl = 1;
+	else global.mouse.ctrl = 0;
+	if(glutGetModifiers() & GLUT_ACTIVE_SHIFT) global.mouse.shift = 1;
+	else global.mouse.shift = 0;
+	if(glutGetModifiers() & GLUT_ACTIVE_ALT) global.mouse.alt = 1;
+	else global.mouse.alt = 0;
+	if(state == GLUT_UP){
+		global.mouse.button = -1;
+	}
+	//get the global coords
+
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif
+	//standard button actions...
+	switch(button){
+	case GLUT_LEFT_BUTTON:
+		{
+			if (global.mouse.ctrl) { //emulate right button
+				switch(state)
+				{
+				case GLUT_UP:
+					endInteract();
+					break;
+				case GLUT_DOWN:
+					startZoom(x,y);
+					break;
+				}
+			}
+			else {
+				switch(state)
+				{
+				case GLUT_UP:
+					endInteract();
+					break;
+				case GLUT_DOWN:
+					startRotation(x,y);
+					break;
+				}
+			}
+		}
+		break;
+	case GLUT_RIGHT_BUTTON:
+		{
+			switch(state)
+			{
+			case GLUT_UP:
+				endInteract();
+				break;
+			case GLUT_DOWN:
+				startZoom(x,y);
+				break;
+			}
+		}
+		break;
+	case GLUT_MIDDLE_BUTTON:
+		{
+			switch(state)
+			{
+			case GLUT_UP:
+				endInteract();
+				break;
+			case GLUT_DOWN:
+				startTranslate(x,y);
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void passiveMotion(int x, int y) {
+global.mouse.pos[0] = x;
+y = global.win.height-y;
+
+	//get the global coords
+//	doSelect(x,y);
+}
+
+void motion(int x, int y)
+{
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif
+	y = global.win.height-y;
+	//get the global coords
+	switch(global.mouse.button)	{
+	case GLUT_LEFT_BUTTON:
+		{
+			if (global.mouse.ctrl) { //emulate right button
+				switch(global.mouse.state)
+				{
+				case GLUT_DOWN:
+					doZoom(x,y);
+					break;
+				case GLUT_UP:
+					break;
+				}
+			}
+			else {
+				switch(global.mouse.state)
+				{
+				case GLUT_DOWN:
+					doRotation(x,y);
+					break;
+				case GLUT_UP:
+					break;
+				}
+			}
+		}
+		break;
+	case GLUT_RIGHT_BUTTON:
+		{
+			switch(global.mouse.state)
+			{
+			case GLUT_DOWN:
+				doZoom(x,y);
+				break;
+			case GLUT_UP:
+				break;
+			}
+		}
+		break;
+	case GLUT_MIDDLE_BUTTON:
+		{
+			switch(global.mouse.state)
+			{
+			case GLUT_DOWN:
+				doTranslate(x,y);
+				break;
+			case GLUT_UP:
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void key(unsigned char key, int x, int y)
+{
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif
+
+	y = global.win.height-y;
+	switch(key) {
+	case '\033': //escape
+		doExit();
+		break;
+	case 'b':
+	case 'B':
+		toggleBoundBox();
+		break;
+	case 'c':
+	case 'C':
+		toggleCutPlane();
+		break;
+	case 'f':
+	case 'F':
+		togglePrintFPS();
+		break;
+	case 'g':
+	case 'G':
+		saveGradientVolume();
+		break;
+	case 'h':
+	case 'H':
+		printUsage();
+		break;
+	case 'i':
+	case 'I':
+		genIsosurface(x,y);
+		break;
+	case 'j':
+	case 'J':
+		//genIsopoint(x,y);
+		break;
+//	case 'n':
+//	case 'N':
+//		global.ui.printSlices = !global.ui.printSlices;
+//		break;
+	case 'o':
+	case 'O':
+		global.volume->saveVolume("out");
+		break;
+	case 'p': //to probe volumes
+	case 'P':
+		setProbe();
+		break;
+	case 'r':
+	case 'R':
+		setRoam();
+		break;
+	case '+':
+		//increase the number of slices
+		scaleSampleRate(1.1);
+		break;
+	case '-':
+		//decrease the number of slices
+		scaleSampleRate(0.9);
+		break;
+	case '.':
+		//increase isosurface value
+		incIsoValue(15);
+		break;
+	case ',':
+		//decrease isosurface value
+		incIsoValue(-15);
+		break;
+	case ' ':
+		animateVolume();
+		break;
+	case 8: //backspace key
+		global.curPrimIdx--;
+		if (global.curPrimIdx < 0)
+			global.curPrimIdx = renderList.size()-1;
+		doSelect(global.curPrimIdx);
+		break;
+
+	case 9: //tab key
+		global.curPrimIdx++;
+		if (global.curPrimIdx >= renderList.size())
+			global.curPrimIdx = 0;
+		doSelect(global.curPrimIdx);
+		break;
+
+	}
+}
+
+
+void special(int key, int x, int y)
+{
+	int ROAM = global.volume->maxDim/2;
+
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif
+	switch(key){
+    case GLUT_KEY_UP:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,ROAM,0);
+		else if (global.ui.navMode == V_PROBE) {
+			probeVolume(0,1,0);
+		}
+		else
+			doAxisRotation(-1.0f,'x');
+		break;
+    case GLUT_KEY_DOWN:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,-ROAM,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,-1,0);
+		else
+			doAxisRotation(1.0f,'x');
+		break;
+    case GLUT_KEY_RIGHT:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(ROAM,0,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(1,0,0);
+		else
+			doAxisRotation(1.0f,'y');
+		break;
+    case GLUT_KEY_LEFT:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(-ROAM,0,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(-1,0,0);
+		else
+			doAxisRotation(-1.0f,'y');
+		break;
+    case GLUT_KEY_PAGE_UP: //increase eye sep
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,0,-ROAM);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,0,-1);
+		else if (global.env.stereoType)
+			global.stereo.halfEyeSep +=0.05;
+		break;
+    case GLUT_KEY_PAGE_DOWN: //decrease eye sep
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,0,ROAM);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,0,1);
+		else if (global.env.stereoType)
+			global.stereo.halfEyeSep -=0.05;
+		break;
+	}
+}
+
+void idle() {
+	display();
+	QUANTAusleep(100);
+}
+
+void reshape(int w, int h)
+{
+	GlErr("vRenderer","testing");
+	glMatrixMode(GL_MODELVIEW);
+	global.win.width  = w;
+	global.win.height = h;
+#ifndef V_DISTRIBUTED
+	global.win.aspect = (float)global.win.width/(float)global.win.height;
+#endif
+
+#if defined(V_SAGE)
+    winWidth = w;
+    winHeight = h;
+    if (rgbBuffer)
+        delete [] rgbBuffer;
+    rgbBuffer = new GLubyte[w*h*3];
+#endif
+
+	glutPostRedisplay();
+}
+
+void parseCmdLine(int argc, char **argv)
+{
+	CCmdLine cmdLine; // our cmd line parser object
+	if (cmdLine.SplitLine(argc, argv) < 1) {
+		// no switches were given on the command line, abort
+		exit(-1);
+	}
+	// test for the 'help' case
+	if (cmdLine.HasSwitch("-h")) {
+		printUsage();
+		exit(0);
+	}
+#if defined(V_NETDATA)
+	bool ok = false;
+	// remote data - get IP and volume symbolic name
+	if (cmdLine.HasSwitch("-v")) {
+		//get the symbolic name of the volume
+		string volName = cmdLine.GetArgument("-v",0);
+		//get the server IP
+		string serverIPFile = cmdLine.GetSafeArgument("-v",1,"optiserver.dat");
+		//open the file check the server IP for my rank
+		char serverIP[256];
+
+#ifdef V_DISTRIBUTED
+		strcpy(serverIP,getServerIP(net->getRank(),serverIPFile.c_str()));
+#else
+		strcpy(serverIP, serverIPFile.c_str());
+#endif
+
+		global.volume = new vOptiVolume(volName.c_str(), serverIP);
+		if (cmdLine.GetArgumentCount("-v") > 2) {//also have thumbnail volume
+			string fullVolName= cmdLine.GetArgument("-v",2);
+			global.fullVolume = new vOptiVolume(fullVolName.c_str(), serverIP);
+		}
+		ok = true;
+
+	}
+	if (cmdLine.HasSwitch("-i")) {
+		string wild = cmdLine.GetArgument("-i",0);
+		cerr <<"wildcard "<<wild<<endl;
+		//the numFiles arg is the server IP
+		string serverIPFile = cmdLine.GetSafeArgument("-v",1,"optiserver.dat");
+		//open the file check the server IP for my rank
+		char serverIP[256];
+
+#ifdef V_DISTRIBUTED
+		strcpy(serverIP,getServerIP(net->getRank(),serverIPFile.c_str()));
+#else
+		strcpy(serverIP, serverIPFile.c_str());
+#endif
+
+		float scale = 1.0f;
+		if (cmdLine.GetArgumentCount("-i") > 2) {//also have thumbnail volume
+			string scaleStr = cmdLine.GetArgument("-i",2);
+			scale = atof(scaleStr.c_str());
+		}
+
+		vGeometry* newGeom = new vGeometry((char*)wild.c_str(),(char*)serverIP,scale);
+		renderList.push_back(newGeom);
+		ok = true;
+	}
+	if (!ok) {
+		fprintf(stderr,"Specify -v or -i option\n");
+		exit(-1);
+	}
+
+
+#else
+	//local, specify filename and filedimensions
+	try {
+		string filename = cmdLine.GetArgument("-f", 0);
+		string x, y, z;
+		x = cmdLine.GetArgument( "-f", 1);
+		y = cmdLine.GetArgument( "-f", 2);
+		z = cmdLine.GetArgument( "-f", 3);
+		global.volume = new vFileVolume(filename.c_str(),
+				atoi(x.c_str()), atoi(y.c_str()), atoi(z.c_str()));
+	}
+	catch (...)
+	{
+		// one of the required arguments was missing, abort
+		exit(-1);
+	}
+
+	//load gradient volume
+	if (cmdLine.HasSwitch("-g")) {
+		((vFileVolume*)global.volume)->gradientFile = strdup(cmdLine.GetArgument("-g",0).c_str());
+	}
+#endif
+	if (global.volume) {
+		//now get the volume offset, if any - 0 by default
+		global.volume->offsetX= atoi(cmdLine.GetSafeArgument( "-o", 0, "0").c_str());
+		global.volume->offsetY = atoi(cmdLine.GetSafeArgument( "-o", 1, "0").c_str());
+		global.volume->offsetZ = atoi(cmdLine.GetSafeArgument( "-o", 2, "0").c_str());
+	}
+
+	//get screen width and height
+	if (cmdLine.HasSwitch("-w")) {
+		global.win.width  = atoi(cmdLine.GetSafeArgument("-w", 0, "512").c_str());
+		global.win.height = atoi(cmdLine.GetSafeArgument("-w", 1, "512").c_str());
+		global.win.aspect = (float)global.win.width/(float)global.win.height;
+	}
+	else
+		global.env.gameMode = true;
+
+#ifdef V_DISTRIBUTED
+	if (cmdLine.HasSwitch("-a")) {
+		global.win.aspect = atof(cmdLine.GetSafeArgument("-a", 0, "1.0").c_str());
+	}
+#endif
+	calcFrustum();
+	//get the voxel spacing
+	if (cmdLine.HasSwitch("-sp")) {
+		if (global.volume) {
+			//now get the volume offset, if any - 0 by default
+			global.volume->spacingX= atof(cmdLine.GetSafeArgument( "-sp", 0, "0").c_str());
+			global.volume->spacingY = atof(cmdLine.GetSafeArgument( "-sp", 1, "0").c_str());
+			global.volume->spacingZ = atof(cmdLine.GetSafeArgument( "-sp", 2, "0").c_str());
+		}
+		if (global.fullVolume) {
+			//now get the volume offset, if any - 0 by default
+			global.fullVolume->spacingX= atof(cmdLine.GetSafeArgument( "-sp", 0, "0").c_str());
+			global.fullVolume->spacingY = atof(cmdLine.GetSafeArgument( "-sp", 1, "0").c_str());
+			global.fullVolume->spacingZ = atof(cmdLine.GetSafeArgument( "-sp", 2, "0").c_str());
+		}
+	}
+
+	//get the texture volume dimensions
+	if (global.volume) {
+		try
+		{
+			string x = cmdLine.GetArgument("-d", 0);
+			string y = cmdLine.GetArgument( "-d", 1);
+			string z = cmdLine.GetArgument( "-d", 2);
+			global.volume->load(atoi(x.c_str()), atoi(y.c_str()), atoi(z.c_str()));
+		}
+		catch (...)
+		{
+			fprintf(stderr,"Missing args to -d command line option\n");
+			exit(-1);
+		}
+	}
+	if (global.fullVolume) //load full volume
+		global.fullVolume->load();
+
+
+#if defined(V_DISTRIBUTED)
+	char tileConfigFile[256];
+	try
+	{   // if any of these GetArgument calls fail,
+		// we'll end up in the catch() block
+		// filename
+		strcpy(tileConfigFile, cmdLine.GetArgument("-n", 0).c_str());
+	}
+	catch (...)
+	{
+		// one of the required arguments was missing, abort
+		exit(-1);
+	}
+	//init mpi related stuff
+	net->readTileConfig(tileConfigFile);
+	if (net->isActiveTile()) { //master
+		global.env.renderOn = false;
+	}
+#endif
+
+	global.env.stereoType = (vStereoType)(atoi(cmdLine.GetSafeArgument( "-s", 0, "0").c_str()));
+	global.stereo.halfEyeSep = 0.25;
+}
+
Index: trunk/src/testing/app/volvis/main.cpp.stereo
===================================================================
--- trunk/src/testing/app/volvis/main.cpp.stereo	(revision 4)
+++ trunk/src/testing/app/volvis/main.cpp.stereo	(revision 4)
@@ -0,0 +1,1035 @@
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <vector>
+#ifdef WIN32
+#include <windows.h>		//  must be included before any OpenGL
+#endif
+
+#include <GL/glut.h>       //glut includes gl and glu for you!
+#include "Trackball.h"     //SGI quaternion trackball
+#include "VectorMath.h"    //usefull vector/matrix operations
+#include "global.h"         //global definitions
+#include "glUE.h"          //gl utilities and extensions
+#include "CCmdLine.h"
+#include "vFPSText.h"
+#include "vRenderer.h"     //standard renderer
+#include "vPrimitive.h"
+#include "vGeometry.h"
+#include "vNet.h"
+#include "vUI.h"
+#include "vSliceView.h"
+
+#if defined(ADDCGGL)
+#include "vCG.h"
+#endif
+
+#if defined(V_DISTRIBUTED)
+#include "mpi.h"
+#include "vNet.h"
+#endif
+
+#if defined(V_NETTF)
+#include "vTF.h"
+#endif
+vector<vPrimitive*>   renderList; //all renderables attatch to this one
+vGlobal		global;	//the global v data structure (global.h)
+Trackball	cutTrack;	//global trackball
+
+#if defined(V_DISTRIBUTED)
+vNet* net = 0;	//The volvis controller
+#endif
+
+#if defined(V_NETTF)
+vTF * tfNet = 0;	//The tfcontroller
+#endif
+
+enum {
+	MENU_ROAM = 1,
+	MENU_PROBE,
+        MENU_CUT,
+	MENU_ISOSURFACE,
+	MENU_ISOPOINTS,
+	MENU_BOUNDBOX,
+	MENU_FPS,
+	MENU_SAMPLERATE,
+	MENU_SAVEVOLUME,
+	MENU_SAVEGRADIENT,
+	MENU_HELP,
+	MENU_EXIT
+};
+
+void menuCallback(int idCommand)
+{
+	switch (idCommand)
+	{
+		case MENU_ROAM:
+			setRoam();
+			break;
+		case MENU_PROBE:
+			setProbe();
+			break;
+		case MENU_CUT:
+			toggleCutPlane();
+			break;
+		case MENU_ISOSURFACE:
+			genIsosurface(100,100);
+			break;
+		case MENU_ISOPOINTS:
+			//genIsopoint(100,100);
+			break;
+		case MENU_BOUNDBOX:
+			toggleBoundBox();
+			break;
+		case MENU_FPS:
+			togglePrintFPS();
+			break;
+		case MENU_SAMPLERATE:
+			break;
+		case MENU_SAVEVOLUME:
+			if (global.volume)
+				global.volume->saveVolume("out");
+			break;
+		case MENU_SAVEGRADIENT:
+			saveGradientVolume();
+			break;
+		case MENU_HELP:
+			printUsage();
+			break;
+		case MENU_EXIT:
+			doExit();
+			break;
+	}
+}
+
+int buildPopupMenu (void)
+{
+        int menu;
+        menu = glutCreateMenu(menuCallback);
+        glutAddMenuEntry ("Roam", MENU_ROAM);
+        glutAddMenuEntry ("Probe", MENU_PROBE);
+        glutAddMenuEntry ("Enable Cut Plane", MENU_CUT);
+        glutAddMenuEntry ("Gen Isosurface", MENU_ISOSURFACE);
+        glutAddMenuEntry ("Boundbox Toggle", MENU_BOUNDBOX);
+        glutAddMenuEntry ("FPS Toggle", MENU_FPS);
+        glutAddMenuEntry ("Sample Rate", MENU_SAMPLERATE);
+        glutAddMenuEntry ("Save Volume", MENU_SAVEVOLUME);
+        glutAddMenuEntry ("Save Gradient Volume", MENU_SAVEGRADIENT);
+        glutAddMenuEntry ("Print Help", MENU_HELP);
+        glutAddMenuEntry ("Exit", MENU_EXIT);
+        return menu;
+}
+
+void calcFrustum() {
+	float fov = 45.0f*3.1415/180.0f;
+	float b = global.env.clip[0] * (float) tan(fov * 0.5);
+	float r = b * global.win.aspect;
+	global.env.frustum[0] *= r;  //left
+	global.env.frustum[1] *= r;   //right
+	global.env.frustum[2] *= b;  //bottom
+	global.env.frustum[3] *= b;   //top
+}
+
+//loads the data in dtex to the handle associated with the dependant texture
+//sent to CG
+void loadDepTex(unsigned int deptexName, unsigned char *dtex)
+{
+#if defined(ADDCGGL)
+	if (fprofile == CG_PROFILE_FP30) {
+		// 1D tex
+		glEnable(GL_TEXTURE_1D);
+		glBindTexture(GL_TEXTURE_1D, deptexName);
+		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, depX, 0, GL_RGBA, GL_UNSIGNED_BYTE, dtex);
+		GlErr("vRenderer", "loadDepTex - loading scaled dependant texture");	
+		glDisable(GL_TEXTURE_1D);
+	}
+	else if (fprofile == CG_PROFILE_FP20) {
+		// 2D tex for FP20
+		glEnable(GL_TEXTURE_2D);
+		glBindTexture(GL_TEXTURE_2D, deptexName);
+		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);	
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, depX, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, dtex);
+		GlErr("vRenderer", "loadDepTex - loading scaled dependant texture");	
+		glDisable(GL_TEXTURE_2D);
+	}
+#endif	
+}
+
+//takes the data from the 2d texture sent from the UI and copies it to the dependant texture
+//that will be passed to CG
+//the dependant texture is 1D but the UI texture is 2d, so for now, 
+//just extract the first row of the UI 2d texture to the dependant texture
+void copyScale(float sampleRate, unsigned char *cgTex)
+{
+	float alphaScale = 1.0/sampleRate;
+	for(int j=0; j<depX; ++j){
+		cgTex[j*4 + 0] = global.volren.deptex[j*4 + 0];
+		cgTex[j*4 + 1] = global.volren.deptex[j*4 + 1];
+		cgTex[j*4 + 2] = global.volren.deptex[j*4 + 2];
+		cgTex[j*4 + 3] = (1.0 - ::pow((1.0-(global.volren.deptex[j*4 + 3]/255.0)), alphaScale))*255;
+		
+	}
+}
+
+void update() {
+	//set the current sampling rate based on the interaction mode
+	if (global.volren.lowRes)
+		global.volren.sampleRate = global.volren.interactSamp;
+	else
+		global.volren.sampleRate = global.volren.goodSamp;
+
+	//Re-Scale Alpha values depending on no of slices
+	//if we need to load a new TF, load it here (from the remote UI)
+	if(global.volren.scaleAlphas){
+		if((global.volren.lastSamp != global.volren.sampleRate)||(global.volren.loadTLUT)){  //see if the sample rate changed
+			if((global.volren.lastGoodSamp != global.volren.goodSamp) || global.volren.loadTLUT){ //good sample rate changed
+				copyScale(global.volren.goodSamp * 1/global.volren.gamma, global.volren.gDeptex);
+				global.volren.lastGoodSamp = global.volren.goodSamp;
+			}
+			if((global.volren.lastInteSamp != global.volren.interactSamp) || global.volren.loadTLUT){ //interact samp rate changed
+				copyScale(global.volren.interactSamp * 1/global.volren.gamma, global.volren.iDeptex);
+				global.volren.lastInteSamp = global.volren.interactSamp;
+			}
+			if(global.volren.sampleRate == global.volren.goodSamp){ //which one do we load (good)
+				loadDepTex(global.volren.scaledDeptexName,global.volren.gDeptex);
+				global.volren.lastSamp = global.volren.goodSamp;
+			}
+			else if(global.volren.sampleRate == global.volren.interactSamp){ //(interactive)
+				loadDepTex(global.volren.scaledDeptexName,global.volren.iDeptex);
+				global.volren.lastSamp = global.volren.interactSamp;
+			}
+			copyScale(0.3, global.volren.nDeptex);
+			loadDepTex(global.volren.origDeptexName, global.volren.nDeptex);
+			global.volren.loadTLUT = 0;
+		}
+	} else {  //just do gamma scale, don't update for the sample rate (for testing purposes)
+		if(global.volren.loadTLUT){
+			copyScale(1/global.volren.gamma, global.volren.gDeptex);
+			loadDepTex(global.volren.scaledDeptexName, global.volren.gDeptex);
+			global.volren.loadTLUT = 0;
+		}
+	}
+
+}
+
+void deallocateAll() {
+	if (global.volume);
+		delete global.volume;
+	if (global.fullVolume)
+		delete global.fullVolume;
+	for (int i=0;i<renderList.size();i++)
+		delete renderList[i];
+
+	delete [] global.volren.deptex ;
+	delete [] global.volren.nDeptex;
+	delete [] global.volren.gDeptex;
+	delete [] global.volren.iDeptex;
+
+}
+int main(int argc, char **argv) {
+	initGlobal(); //init global variables
+	
+	//init network related - MPI will change argc and argv
+	// so pass as ref
+	QUANTAinit();	
+	srand( (unsigned)time(NULL)); //initialise randon number generator
+#if defined(V_DISTRIBUTED)
+	net = new vNet(); 
+	net->init(argc,argv);
+#endif	
+
+#if defined(V_NETTF) //want transfer functions
+#if defined (V_DISTRIBUTED) //in distributed mode, only master has this instance	
+	if (net->isActiveTile()) {
+		tfNet = new vTF();
+		tfNet->init();
+	}
+#else //in standalone instantiate it
+	 tfNet = new vTF();
+	 tfNet->init();
+#endif	
+#endif	
+	
+	//command line parsing - stores argumenents in global.*
+	parseCmdLine(argc,argv);
+	
+	glutInit(&argc, argv);
+	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+	glutInitWindowSize(global.win.width, global.win.height);
+	glutInitWindowPosition(global.win.xPos, global.win.yPos);
+	global.mainWindow =	glutCreateWindow("Vol-a-Tile");
+	
+#ifdef WIN32
+	LoadAllExtensions();
+#endif
+	
+	initGL(); //opengl init stuff
+	//init the dependant textures
+	//initialize the dependant texture for transfer functions
+	//copy the good and interactive dependant textures
+	copyScale(global.volren.goodSamp, global.volren.gDeptex);
+	copyScale(global.volren.interactSamp, global.volren.iDeptex);
+	copyScale(0.3, global.volren.nDeptex);
+	global.volren.lastSamp = global.volren.goodSamp;
+	global.volren.lastGoodSamp = global.volren.goodSamp;
+	global.volren.lastInteSamp = global.volren.interactSamp;
+
+	loadDepTex(global.volren.scaledDeptexName,global.volren.gDeptex);
+	loadDepTex(global.volren.origDeptexName,global.volren.nDeptex);
+	//load the given 1D texture to CG
+
+
+#if defined(ADDCGGL)
+	initCG(); //init the CG library
+#endif
+	
+	//start creating our objects
+	//creating renderer object
+	if (global.volume) {
+		vRenderer* renderer = new vRenderer(); 
+		renderer->setVolume(global.volume);
+		renderList.push_back(renderer);
+
+		if (global.fullVolume) {
+			vRenderer* fullRenderer = new vRenderer; 
+			fullRenderer->setVolume(global.fullVolume);
+			fullRenderer->disableCut();
+			fullRenderer->enableShowOverview();
+			fullRenderer->setTranslation(2.0,0.0,0.0);
+			renderList.push_back(fullRenderer);
+		}
+		//slice view
+		vSliceView* view = new vSliceView;
+		renderList.push_back(view);
+		//the info 
+		vVolText* text = new vVolText;
+		renderList.push_back(text);
+
+	}
+		
+
+	//now create the FPS text 
+	vFPSText* timerText = new vFPSText;
+	renderList.push_back(timerText);
+	 //now create the pointer
+	//vPointer* ptr = new vPointer;
+	//renderList.push_back(ptr);
+
+	//initialise all the objects
+	for (int i=0;i<renderList.size();i++) {	
+		renderList[i]->init();
+	}
+
+	GlErr("vRenderer", "init");
+
+	
+
+#ifdef V_DISTRIBUTED
+	if (net->isActiveTile()) {
+		global.win.width = 1024;
+		global.win.height = 1024;
+	}
+	else {
+		glutFullScreen();
+		glutSetCursor(GLUT_CURSOR_NONE);
+		
+	}
+#else
+	if (global.env.gameMode )
+		glutFullScreen();
+
+#endif	
+	glutDisplayFunc(display);
+	glutReshapeFunc(reshape);
+	glutMouseFunc(mouse);
+	glutMotionFunc(motion);
+	glutPassiveMotionFunc(passiveMotion);
+	glutKeyboardFunc(key);   
+	glutSpecialFunc(special);
+	//only use idle when we are in standalone mode 
+#ifndef V_DISTRIBUTED
+	glutIdleFunc(idle);
+#endif	
+	buildPopupMenu ();
+        glutAttachMenu (GLUT_RIGHT_BUTTON);
+	//only master does the update and broadcasts it to client
+	//so that everyone is syncronized
+#ifdef V_DISTRIBUTED
+	//if (net->isActiveTile()) 
+	glutTimerFunc(50, updateAnim, 1);
+#else
+	glutTimerFunc(50, updateAnim, 1);
+#endif	
+	glutMainLoop();
+	return 0;
+}
+
+void    initGlobal() {                  
+	global.volume = 0;
+	global.fullVolume = 0;
+	
+	global.win.width  = 1024;      //size
+	global.win.height = 768;
+	global.win.xPos   = 0;      //position
+	global.win.yPos   = 0;
+	global.win.aspect = 1.0f;
+	
+	global.env.eye[0]     = 0;    //eye
+	global.env.eye[1]     = 0;
+	global.env.eye[2]     = 10.0;
+	global.env.at[0]      = 0;    //at
+	global.env.at[1]      = 0;
+	global.env.at[2]      = 0;
+	global.env.up[0]      = 0;    //up
+	global.env.up[1]      = 1;
+	global.env.up[2]      = 0;
+	global.env.renderOn = true;
+	
+	global.env.frustum[0] = -1.0;  //left
+	global.env.frustum[1] = 1.0;   //right
+	global.env.frustum[2] = -1.0;  //bottom
+	global.env.frustum[3] = 1.0;   //top
+	global.env.clip[0]    = 1;    //front
+	global.env.clip[1]    = 50;   //back
+	global.env.bgColor    = 0;    //white background
+	
+	global.mouse.alt     = 0;
+	global.mouse.ctrl    = 0;
+	global.mouse.shift   = 0;
+	
+	//lighting
+	global.light.startpos[0] = -1.0f;
+	global.light.startpos[1] = -1.0f;
+	global.light.startpos[2] =-1.0f;
+	global.light.startpos[3] = 0.0f;
+	
+	global.volren.interactSamp= .05;      //Interactive sample rate
+	global.volren.goodSamp    = 1.0;     //High quality sample ..
+	global.volren.sampleRate  = global.volren.goodSamp; //samples per voxel
+	global.volren.lowRes   = 0; //highres rendering
+	global.volren.deptex = new unsigned char[256*256*4];
+	for(int j=0; j<256; ++j){
+		for(int k=0; k<256; ++k){
+			global.volren.deptex[j*256*4 + k*4 + 0] =  (unsigned char)(k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 1] =  (unsigned char)(255 - k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 2] =  (unsigned char)( k/(float)255*255);
+			global.volren.deptex[j*256*4 + k*4 + 3] =  (unsigned char)(k/(float)255*255/(float)2);
+		}
+	}
+	global.volren.nDeptex = new unsigned char[256*4];
+	global.volren.gDeptex	= new unsigned char[256*4];
+	global.volren.iDeptex = new unsigned char[256*4];
+	global.volren.loadTLUT    = 1;       //first time - need to load LUT
+	global.volren.loadVolume = 0; 		//no need to load the volume
+	global.volren.scaleAlphas = 1;       //scale alphas to the sample rate
+	global.volren.gamma       = 1;       //gamma identitiy
+	global.volren.probe[0] = global.volren.probe[1] = global.volren.probe[2] = 0;
+	
+	identityMatrix(global.cut.transform);  //init the rotation
+	global.cut.user[0] = 1.0;
+	global.cut.user[1] = global.cut.user[2] = 0.0;
+	global.cut.user[3] = 0.5f;
+	global.cut.update = false;
+
+	global.ui.printFPS = false;
+	global.ui.printSlices = false;
+	global.ui.cutEnabled = false;
+	global.ui.bboxEnabled = false;
+	global.ui.navMode = V_ROAM;
+	global.ui.animate = false;
+
+	global.pointerPos[0] = global.pointerPos[1] = 0.0f;
+	global.pointerPos[2] = 1.0f;
+	global.curPrimIdx = 0;
+	cutTrack.clear();
+}
+
+
+void initGL( void )
+{
+	glClearColor(0.0, 0.0, 0.0, 1.0);
+	glShadeModel(GL_SMOOTH);
+	glEnable(GL_DEPTH_TEST);
+	glDepthFunc(GL_LEQUAL);
+	glLineWidth(3);
+	glGenTextures(1, &global.volren.scaledDeptexName);   //the dep tex that we use for the tf- passed to CG
+	glGenTextures(1, &global.volren.origDeptexName);   //the dep tex that we use for the tf- passed to CG
+	GlErr("v::","initGL()");
+}
+
+void display()
+{
+#ifdef V_DISTRIBUTED
+	net->process();
+#endif	
+	glEnable (GL_SCISSOR_TEST); //dont draw outside viewpott
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	glFrustum(global.env.frustum[0], //left
+		global.env.frustum[1], //right
+		global.env.frustum[2], //top
+		global.env.frustum[3], //bottom
+		global.env.clip[0],    //front
+		global.env.clip[1]);   //back
+
+	//viewport for left eye, in the right half of the screen
+	if (global.env.stereoType) {
+		glViewport(global.win.displayWidth,0,global.win.width, global.win.height);
+		glScissor (global.win.displayWidth, 0, global.win.width, global.win.height);
+		if (global.env.stereoType == CROSSEYE)
+			displayOneEye(LEFT);
+		else
+			displayOneEye(RIGHT);
+	}
+	//viewport for right eye, left half of the screen
+	glViewport(0, 0, global.win.displayWidth, global.win.height);
+	glScissor (0, 0, global.win.displayWidth, global.win.height);
+	if (global.env.stereoType == CROSSEYE)
+		displayOneEye(RIGHT);
+	else
+		displayOneEye(LEFT);
+	glDisable (GL_SCISSOR_TEST);
+	
+#ifdef V_DISTRIBUTED
+	net->sync();
+#endif	
+	glutSwapBuffers();
+	GlErr("v:","disp()");
+}
+
+void displayOneEye(STEREOVIEW eye)
+{
+	//dont draw anything on the master	
+	glPushMatrix();
+	{
+		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+		glMatrixMode(GL_MODELVIEW);
+		glLoadIdentity();
+		if (eye == LEFT) 
+			gluLookAt(-global.stereo.halfEyeSep+global.env.eye[0],  //eye
+				global.env.eye[1], 
+				global.env.eye[2],  
+				global.env.at[0],   //at
+				global.env.at[1], 
+				global.env.at[2],  
+				global.env.up[0], 
+				global.env.up[1], 
+				global.env.up[2]);          //up
+		else
+			gluLookAt(global.stereo.halfEyeSep+global.env.eye[0],  //eye
+				global.env.eye[1], global.env.eye[2],
+				global.env.at[0],global.env.at[1],global.env.at[2],
+				global.env.up[0],global.env.up[1],global.env.up[2]);  
+
+		GLfloat light_pos[] = { 5.0, 5.0, 5.0,1.0 };
+		glEnable(GL_LIGHTING);
+		glEnable(GL_LIGHT0);
+		glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
+		update();	
+		if (global.env.renderOn) {
+			for (int i=0;i<renderList.size();i++) {
+				renderList[i]->draw();
+			}
+		}
+		renderList[global.curPrimIdx]->setSelected(true);	
+		
+	} glPopMatrix();
+}
+
+void mouse(int button, int state, int x, int y)
+{
+	y = global.win.height - y;
+	global.mouse.button = button;
+	global.mouse.state  = state;
+	
+	if(glutGetModifiers() & GLUT_ACTIVE_CTRL) global.mouse.ctrl = 1;
+	else global.mouse.ctrl = 0;
+	if(glutGetModifiers() & GLUT_ACTIVE_SHIFT) global.mouse.shift = 1;
+	else global.mouse.shift = 0;
+	if(glutGetModifiers() & GLUT_ACTIVE_ALT) global.mouse.alt = 1;
+	else global.mouse.alt = 0;
+	if(state == GLUT_UP){ 
+		global.mouse.button = -1;
+	}
+	//get the global coords
+	
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif	
+	//standard button actions...
+	switch(button){		
+	case GLUT_LEFT_BUTTON: 
+		{
+			if (global.mouse.ctrl) { //emulate right button
+				switch(state)
+				{
+				case GLUT_UP:
+					endInteract();
+					break;
+				case GLUT_DOWN:
+					startZoom(x,y);
+					break;
+				}
+			}
+			else {
+				switch(state)
+				{
+				case GLUT_UP:
+					endInteract();
+					break;
+				case GLUT_DOWN:
+					startRotation(x,y);
+					break;
+				}
+			}
+		}
+		break; 
+	case GLUT_RIGHT_BUTTON: 
+		{
+			switch(state)
+			{
+			case GLUT_UP:
+				endInteract();
+				break;
+			case GLUT_DOWN:
+				startZoom(x,y);
+				break;
+			}
+		}
+		break;
+	case GLUT_MIDDLE_BUTTON:
+		{
+			switch(state)
+			{
+			case GLUT_UP:
+				endInteract();
+				break;
+			case GLUT_DOWN:
+				startTranslate(x,y);
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void passiveMotion(int x, int y) {
+global.mouse.pos[0] = x;
+y = global.win.height-y;
+
+	//get the global coords
+//	doSelect(x,y);
+}
+
+void motion(int x, int y)
+{
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif	
+	y = global.win.height-y;
+	//get the global coords
+	switch(global.mouse.button)	{
+	case GLUT_LEFT_BUTTON: 	
+		{
+			if (global.mouse.ctrl) { //emulate right button
+				switch(global.mouse.state) 
+				{
+				case GLUT_DOWN:
+					doZoom(x,y);				
+					break;
+				case GLUT_UP: 
+					break;
+				}
+			}
+			else {
+				switch(global.mouse.state) 
+				{
+				case GLUT_DOWN:
+					doRotation(x,y);
+					break;
+				case GLUT_UP: 
+					break;
+				}
+			}
+		}
+		break; 
+	case GLUT_RIGHT_BUTTON: 
+		{
+			switch(global.mouse.state) 
+			{
+			case GLUT_DOWN:
+				doZoom(x,y);				
+				break;
+			case GLUT_UP: 
+				break;
+			}
+		}
+		break; 
+	case GLUT_MIDDLE_BUTTON: 
+		{
+			switch(global.mouse.state) 
+			{
+			case GLUT_DOWN:
+				doTranslate(x,y);
+				break;
+			case GLUT_UP: 
+				break;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void key(unsigned char key, int x, int y)
+{
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif	
+	
+	y = global.win.height-y;
+	switch(key) {
+	case '\033': //escape
+		doExit();
+		break;		
+	case 'b':
+	case 'B':
+		toggleBoundBox();
+		break;
+	case 'c':
+	case 'C':
+		toggleCutPlane();
+		break;
+	case 'f':
+	case 'F':
+		togglePrintFPS();
+		break;
+	case 'g':
+	case 'G':
+		saveGradientVolume();
+		break;
+	case 'h':
+	case 'H':
+		printUsage();
+		break;
+	case 'i':
+	case 'I':
+		genIsosurface(x,y);
+		break;
+	case 'j':
+	case 'J':
+		//genIsopoint(x,y);
+		break;
+//	case 'n':
+//	case 'N':
+//		global.ui.printSlices = !global.ui.printSlices;
+//		break;
+	case 'o':
+	case 'O':
+		global.volume->saveVolume("out");
+		break;
+	case 'p': //to probe volumes
+	case 'P':
+		setProbe();
+		break;
+	case 'r':
+	case 'R':
+		setRoam();
+		break;
+	case 'x':
+	case 'X':
+		animateVolumeRotX();
+		break;
+	case '+': 
+		//increase the number of slices		
+		scaleSampleRate(1.1);
+		break;
+	case '-': 
+		//decrease the number of slices		
+		scaleSampleRate(0.9);
+		break;
+	case '.':
+		//increase isosurface value
+		incIsoValue(15);
+		break;
+	case ',':
+		//decrease isosurface value
+		incIsoValue(-15);
+		break;
+	case ' ':
+		animateVolume();
+		break;
+	case 8: //backspace key
+		global.curPrimIdx--;
+		if (global.curPrimIdx < 0) 
+			global.curPrimIdx = renderList.size()-1;
+		doSelect(global.curPrimIdx);
+		break;
+
+	case 9: //tab key
+		global.curPrimIdx++;
+		if (global.curPrimIdx >= renderList.size())
+			global.curPrimIdx = 0;
+		doSelect(global.curPrimIdx);
+		break;
+		
+	}
+}
+
+
+void special(int key, int x, int y)
+{
+	int ROAM = global.volume->maxDim/2;
+
+#if defined(V_DISTRIBUTED)
+	if (!net->cmdFlushed)
+		return;
+#endif	
+	switch(key){
+    case GLUT_KEY_UP:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,ROAM,0);
+		else if (global.ui.navMode == V_PROBE) {
+			probeVolume(0,1,0);
+		}
+		else
+			doAxisRotation(-1.0f,'x');
+		break;
+    case GLUT_KEY_DOWN:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,-ROAM,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,-1,0);
+		else
+			doAxisRotation(1.0f,'x');
+		break;
+    case GLUT_KEY_RIGHT:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(ROAM,0,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(1,0,0);
+		else
+			doAxisRotation(1.0f,'y');
+		break;
+    case GLUT_KEY_LEFT:
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(-ROAM,0,0);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(-1,0,0);
+		else
+			doAxisRotation(-1.0f,'y');
+		break;
+    case GLUT_KEY_PAGE_UP: //increase eye sep
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,0,-ROAM);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,0,-1);
+		else if (global.env.stereoType) 
+			global.stereo.halfEyeSep +=0.05;
+		break;
+    case GLUT_KEY_PAGE_DOWN: //decrease eye sep
+		if (global.ui.navMode == V_ROAM)
+			roamVolume(0,0,ROAM);
+		else if (global.ui.navMode == V_PROBE)
+			probeVolume(0,0,1);
+		else if (global.env.stereoType) 
+			global.stereo.halfEyeSep -=0.05;
+		break;
+	}
+}
+
+void idle() {
+	display();
+	QUANTAusleep(100);
+}
+
+void reshape(int w, int h)
+{
+	GlErr("vRenderer","testing");
+	glViewport(0,0, (GLint) w -1, (GLint) h-1);
+//	glMatrixMode(GL_PROJECTION);
+//	glLoadIdentity();
+
+	
+//	global.env.frustum[0] *= (float)w/(float)global.win.width;
+//	global.env.frustum[1] *= (float)w/(float)global.win.width;
+//	global.env.frustum[2] *= (float)h/(float)global.win.height;
+//	global.env.frustum[3] *= (float)h/(float)global.win.height;
+	
+	glFrustum(global.env.frustum[0], 
+		global.env.frustum[1], 
+		global.env.frustum[2], 
+		global.env.frustum[3], 
+		global.env.clip[0], 
+		global.env.clip[1]);
+	
+	glMatrixMode(GL_MODELVIEW);
+	global.win.width  = w;
+	global.win.height = h;
+	glutPostRedisplay();
+}
+
+void parseCmdLine(int argc, char **argv)
+{
+	CCmdLine cmdLine; // our cmd line parser object
+	if (cmdLine.SplitLine(argc, argv) < 1) {
+		// no switches were given on the command line, abort
+		exit(-1);
+	}
+	// test for the 'help' case
+	if (cmdLine.HasSwitch("-h")) {
+		printUsage();
+		exit(0);
+	}
+#if defined(V_NETDATA)
+	bool ok = false;
+	// remote data - get IP and volume symbolic name
+	if (cmdLine.HasSwitch("-v")) {
+		//get the symbolic name of the volume
+		string volName = cmdLine.GetArgument("-v",0);
+		//get the server IP
+		string serverIP = cmdLine.GetSafeArgument("-v",1,"localhost");
+		global.volume = new vOptiVolume(volName.c_str(), serverIP.c_str());
+		if (cmdLine.GetArgumentCount("-v") > 2) {//also have thumbnail volume
+			string fullVolName= cmdLine.GetArgument("-v",2);
+			global.fullVolume = new vOptiVolume(fullVolName.c_str(), serverIP.c_str());
+		}
+		ok = true;
+
+	}
+	if (cmdLine.HasSwitch("-i")) {
+		string wild = cmdLine.GetArgument("-i",0);
+		cerr <<"wildcard "<<wild<<endl;
+		//the numFiles arg is the server IP
+		string serverIP = cmdLine.GetSafeArgument("-i",1,"localhost");
+		fprintf(stderr,"server IP %s\n",serverIP.c_str());
+		float scale = 1.0f;
+		if (cmdLine.GetArgumentCount("-i") > 2) {//also have thumbnail volume
+			string scaleStr = cmdLine.GetArgument("-i",2);
+			scale = atof(scaleStr.c_str());
+		}
+
+		vGeometry* newGeom = new vGeometry((char*)wild.c_str(),(char*)serverIP.c_str(),scale);
+		renderList.push_back(newGeom);
+		ok = true;
+	}
+	if (!ok) {
+		fprintf(stderr,"Specify -v or -i option\n");
+		exit(-1);
+	}
+
+
+#else	
+	//local, specify filename and filedimensions 
+	try {
+		string filename = cmdLine.GetArgument("-f", 0);
+		string x, y, z;
+		x = cmdLine.GetArgument( "-f", 1);
+		y = cmdLine.GetArgument( "-f", 2);
+		z = cmdLine.GetArgument( "-f", 3);
+		global.volume = new vFileVolume(filename.c_str(),
+				atoi(x.c_str()), atoi(y.c_str()), atoi(z.c_str()));
+	}
+	catch (...)
+	{
+		// one of the required arguments was missing, abort
+		exit(-1);
+	}
+
+	//load gradient volume
+	if (cmdLine.HasSwitch("-g")) {
+		((vFileVolume*)global.volume)->gradientFile = strdup(cmdLine.GetArgument("-g",0).c_str());
+	}
+#endif 
+	if (global.volume) {
+		//now get the volume offset, if any - 0 by default
+		global.volume->offsetX= atoi(cmdLine.GetSafeArgument( "-o", 0, "0").c_str());
+		global.volume->offsetY = atoi(cmdLine.GetSafeArgument( "-o", 1, "0").c_str());
+		global.volume->offsetZ = atoi(cmdLine.GetSafeArgument( "-o", 2, "0").c_str());
+	}
+
+	//get screen width and height
+	if (cmdLine.HasSwitch("-w")) {
+		global.win.width  = atoi(cmdLine.GetSafeArgument("-w", 0, "512").c_str());
+		global.win.height = atoi(cmdLine.GetSafeArgument("-w", 1, "512").c_str());
+	}
+	else
+		global.env.gameMode = true;
+
+	if (cmdLine.HasSwitch("-a")) {
+		global.win.aspect = atof(cmdLine.GetSafeArgument("-a", 0, "1.0").c_str());
+	}
+
+	calcFrustum();
+	//get the voxel spacing
+	if (cmdLine.HasSwitch("-sp")) {
+		if (global.volume) {
+			//now get the volume offset, if any - 0 by default
+			global.volume->spacingX= atof(cmdLine.GetSafeArgument( "-sp", 0, "0").c_str());
+			global.volume->spacingY = atof(cmdLine.GetSafeArgument( "-sp", 1, "0").c_str());
+			global.volume->spacingZ = atof(cmdLine.GetSafeArgument( "-sp", 2, "0").c_str());
+		}
+		if (global.fullVolume) {
+			//now get the volume offset, if any - 0 by default
+			global.fullVolume->spacingX= atof(cmdLine.GetSafeArgument( "-sp", 0, "0").c_str());
+			global.fullVolume->spacingY = atof(cmdLine.GetSafeArgument( "-sp", 1, "0").c_str());
+			global.fullVolume->spacingZ = atof(cmdLine.GetSafeArgument( "-sp", 2, "0").c_str());
+		}
+	}
+
+	//get the texture volume dimensions
+	if (global.volume) {
+		try
+		{  
+			string x = cmdLine.GetArgument("-d", 0);
+			string y = cmdLine.GetArgument( "-d", 1);
+			string z = cmdLine.GetArgument( "-d", 2);
+			global.volume->load(atoi(x.c_str()), atoi(y.c_str()), atoi(z.c_str()));
+		}
+		catch (...)
+		{
+			fprintf(stderr,"Missing args to -d command line option\n");
+			exit(-1);
+		}
+	}
+	if (global.fullVolume) //load full volume
+		global.fullVolume->load();
+
+
+#if defined(V_DISTRIBUTED)
+	char tileConfigFile[256];
+	try
+	{  // if any of these GetArgument calls fail, 
+		// we'll end up in the catch() block
+		// filename
+		strcpy(tileConfigFile, cmdLine.GetArgument("-n", 0).c_str());
+	}
+	catch (...)
+	{
+		// one of the required arguments was missing, abort
+		exit(-1);
+	}
+	//init mpi related stuff
+	net->readTileConfig(tileConfigFile);
+	if (net->isActiveTile()) { //master
+		global.env.renderOn = false;
+	}
+#endif	
+	
+	global.env.stereoType = (vStereoType)(atoi(cmdLine.GetSafeArgument( "-s", 0, "0").c_str()));
+	global.stereo.halfEyeSep = 0.25;
+}
+
Index: trunk/src/testing/app/volvis/volvis.dsp
===================================================================
--- trunk/src/testing/app/volvis/volvis.dsp	(revision 4)
+++ trunk/src/testing/app/volvis/volvis.dsp	(revision 4)
@@ -0,0 +1,229 @@
+# Microsoft Developer Studio Project File - Name="volvis" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=volvis - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "volvis.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "volvis.mak" CFG="volvis - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "volvis - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "volvis - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "volvis - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "volvis - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "ADDCGGL" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib CgGL.lib Cg.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "volvis - Win32 Release"
+# Name "volvis - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\CCmdLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\glUE.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Trackball.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vCG.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vCut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vFPSText.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vNet.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vPrimitive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vRenderer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vVolume.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\CCmdLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\global.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\glUE.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Trackball.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vCG.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vCut.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vFPSText.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vNet.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vPrimitive.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vRenderer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\vVolume.h
+# End Source File
+# End Group
+# Begin Group "math"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\calculus.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MatrixMath.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\VectorMath.h
+# End Source File
+# End Group
+# Begin Group "docs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\SHALINITODO.txt
+# End Source File
+# End Group
+# Begin Group "cg"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\shaders\fragment20.cg
+# End Source File
+# Begin Source File
+
+SOURCE=.\shaders\fragment30.cg
+# End Source File
+# Begin Source File
+
+SOURCE=.\shaders\vertex.cg
+# End Source File
+# End Group
+# End Target
+# End Project
Index: trunk/src/testing/app/volvis/vCut.h
===================================================================
--- trunk/src/testing/app/volvis/vCut.h	(revision 4)
+++ trunk/src/testing/app/volvis/vCut.h	(revision 4)
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _vCut_h_
+#define _vCut_h_
+
+class vCut {
+	float plane[12]; //for the corners of the clip plane
+public:
+	vCut();
+	void setTransform(float objTransform[16]) ;
+	void addTransform(float objectXform[]);
+	void enable();
+	void disable();
+	void draw();
+};
+#endif
+
Index: trunk/src/testing/app/volvis/vOptiVolume.cpp
===================================================================
--- trunk/src/testing/app/volvis/vOptiVolume.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vOptiVolume.cpp	(revision 4)
@@ -0,0 +1,208 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//Class vOptiVolume: defines a 3d volume that is accessed through a server
+//This class only manages the data(doesnt do the rendering)
+//Shalini Venkataraman, Luc Renambot
+//Sep 7 2003
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "glUE.h"
+#include "vVolume.h"
+#include "VectorMath.h"
+#include "global.h"
+
+//mutex for the update histogram
+//the transfer fn thread also acceses the histogram
+QUANTAts_mutex_c mutex;
+
+//constructor
+vOptiVolume::vOptiVolume(const char* volName, const char* serverName):vVolume(0,0,0)
+{
+    opClient = new cDataManagerClient((char*)serverName);
+    fprintf(stderr,"vOptiVolume::vOptiVolume %s\n",volName);
+    opClient->Open();
+    opClient->Init();
+    int numData = opClient->Query();
+
+	numVolumes= opClient->GetMatching((char*)volName,indexList);
+	if (!numVolumes)	{
+		fprintf(stderr,"ERROR: Cant find any volumes matching %s in Optistore\n",volName);
+		exit(1);
+	}
+	cache.resize(numVolumes);
+	opClient->GetDataDims(indexList[0],fileX, fileY, fileZ);
+	fprintf(stderr,"vOptiVolume file Dims %d %d %d\n",fileX, fileY, fileZ);
+	offsetX  = offsetY = offsetZ = 0;
+	updateHist = false;
+	isoValue = 128;
+	curVolume = 0;
+}
+
+//destructor
+vOptiVolume::~vOptiVolume() {
+    opClient->Exit();
+	free(indexList);
+}
+
+bool vOptiVolume::getUpdateHist() {
+	bool ret;
+	mutex.lock();
+	ret = updateHist;
+	mutex.unlock();
+	return ret;
+}
+
+void vOptiVolume::setUpdateHist(bool flag) {
+	mutex.lock();
+	updateHist = flag;
+	mutex.unlock();
+}
+
+int vOptiVolume::hist2D(unsigned char* normHist) {
+	// Get 2D histogram of volume+gradient
+	if (getUpdateHist()) { //if we have a new hist for the volume, copy it
+		cache[curVolume].histMutex.lock();
+		if (cache[curVolume].hist) {//if we have a hist send it
+			memcpy(normHist,cache[curVolume].hist,H2D_DIM*sizeof(unsigned char));
+			cache[curVolume].histMutex.unlock();
+			setUpdateHist(false);
+			return 1;
+		}
+		else
+			cache[curVolume].histMutex.unlock();
+	}
+	return 0;
+}
+
+void vOptiVolume::load() {
+	load(fileX, fileY, fileZ);
+}
+
+void vOptiVolume::setCurVolume(int curVolume)  {
+	if (!cache[curVolume].voxelData) {//get from server
+		opClient->Load(indexList[curVolume]);
+		//opClient->Resample(dimX,dimY,dimZ);
+		opClient->Crop(offsetX, offsetY, offsetZ ,offsetX+dimX-1,offsetY+dimY-1, offsetZ+dimZ-1);
+		cache[curVolume].voxelData = new GLubyte[dimX*dimY*dimZ];
+		memcpy(cache[curVolume].voxelData,opClient->Volume(),dimX*dimY*dimZ*sizeof(GLubyte));
+		cache[curVolume].histMutex.lock();
+		cache[curVolume].hist = new unsigned char[H2D_DIM ];
+            //memcpy(cache[curVolume].hist,opClient->Histogram2D(),H2D_DIM*sizeof(unsigned char));
+		cache[curVolume].histMutex.unlock();
+	}
+	setUpdateHist(true); //amy listeners will have to update their hist
+}
+
+void vOptiVolume::next() {
+	curVolume++;
+	if (curVolume >= numVolumes)
+		curVolume = 0;
+	setCurVolume(curVolume);
+}
+
+void vOptiVolume::prev() {
+	curVolume--;
+	if (curVolume < 0)
+		curVolume = numVolumes-1;
+	setCurVolume(curVolume);
+}
+
+
+
+void vOptiVolume::load(int loadx, int loady, int loadz) {
+	setLoadDims(loadx, loady, loadz); //does the power of 2 conversion here if needed
+	setCurVolume(0);
+}
+
+void vOptiVolume::roam(int roamX, int roamY, int roamZ) {
+	//calculate new offset(cos the orig offset is unsigned..)
+	int newOffsetX = offsetX + roamX;
+	int newOffsetY = offsetY + roamY;
+	int newOffsetZ = offsetZ + roamZ;
+	//have to minus 1 since the bounds in Optistore are inclusive
+	int cropX = dimX-1;//so if dimX = 64, crop from (0,0,0) ->(63,63,63)
+	int cropY = dimY-1;
+	int cropZ = dimZ-1;
+	//now check if the newoFfset is withing range if not make it
+	if (newOffsetX+cropX>= fileX) //eg (1+63) >=64 so, offset = 64-64 = 0
+		newOffsetX = fileX-dimX;
+	if (newOffsetY+cropY>= fileY)
+		newOffsetY = fileY-dimY;
+	if (newOffsetZ+cropZ >= fileZ)
+		newOffsetZ = fileZ-dimZ;
+	if (newOffsetX < 0)
+		newOffsetX = 0;
+	if (newOffsetY < 0)
+		newOffsetY = 0;
+	if (newOffsetZ < 0)
+		newOffsetZ = 0;
+	//copy to the offset
+	offsetX = newOffsetX;
+	offsetY = newOffsetY;
+	offsetZ = newOffsetZ;
+
+	//at this point delete our  cache
+	for (int i=0;i<cache.size();i++) {
+		delete [] cache[i].voxelData;
+		cache[i].voxelData = 0;
+		cache[i].histMutex.lock();
+		delete [] cache[i].hist;
+		cache[i].hist= 0;
+		cache[i].histMutex.unlock();
+	}
+	opClient->Crop(offsetX, offsetY, offsetZ ,offsetX+dimX-1,offsetY+dimY-1, offsetZ+dimZ-1);
+	cache[curVolume].voxelData = new GLubyte[dimX*dimY*dimZ];
+	memcpy(cache[curVolume].voxelData,opClient->Volume(),dimX*dimY*dimZ*sizeof(GLubyte));
+	cache[curVolume].histMutex.lock();
+	cache[curVolume].hist = new unsigned char[H2D_DIM ];
+        //memcpy(cache[curVolume].hist,opClient->Histogram2D(),H2D_DIM*sizeof(unsigned char));
+	cache[curVolume].histMutex.unlock();
+	setUpdateHist(true); //amy listeners will have to update their hist
+}
+
+NetVertexBuffer* vOptiVolume::isoSurface() {
+	isoValue = probeValue;
+	return (opClient->Isosurface(isoValue, 1, 0.40f));
+}
+
+NetPointBuffer* vOptiVolume::isoPoint() {
+	isoValue = probeValue;
+	return (opClient->IsoPoints(isoValue, 1, 8000));
+}
+
+
+
Index: trunk/src/testing/app/volvis/mmap.cpp
===================================================================
--- trunk/src/testing/app/volvis/mmap.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/mmap.cpp	(revision 4)
@@ -0,0 +1,129 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include "mmap.h"
+#include <stdio.h>
+
+Mmap::Mmap()
+{
+    _filename = 0;
+    _len = 0;
+    _fd = -1;
+    //_prot = PROT_READ|PROT_WRITE;
+    _prot = PROT_READ;
+    _shared = MAP_PRIVATE;
+    _mmapAddress = (caddr_t) -1;
+}
+
+Mmap::~Mmap()
+{
+
+    // free filename
+    if(_filename)
+        delete _filename;
+
+    // close file
+    if(_fd >= 0)
+        close(_fd);
+
+    // unmap file
+    if(_mmapAddress)
+        munmap(_mmapAddress, _len);
+}
+
+int
+Mmap::setFilename(const char *filename, int create)
+{
+    int len = strlen(filename)+1;
+    _filename = new char [len];
+    strcpy(_filename, filename);
+
+    struct stat statbuf;
+
+
+    if(!create)
+    {
+        // told not to create it -- it must exist already
+        _fd = open(_filename, O_RDONLY) ;
+    }
+    else {
+        _fd = open(_filename, O_RDONLY|O_CREAT, 00600);
+    }
+
+    if(_fd < 0)
+        return -1;
+
+    int rc = stat(_filename, &statbuf);
+    if(rc < 0)
+    {
+        // Strange -- we could open but not stat????
+        return(-1);
+    }
+
+    _len = (size_t) statbuf.st_size;
+    fprintf(stderr,"File size %d\n",_len);
+    return 1;
+}
+
+void Mmap::setSize(size_t size)
+{
+    if(_len != size) {
+        // Must resize the file
+        lseek(_fd, (off_t) size, SEEK_SET);
+        // write one byte to ensure that we're at least this size
+        write(_fd, "", 1);
+        // Now truncate the file to be this size
+        ftruncate(_fd, size);
+    }
+    _len = size;
+}
+
+
+
+caddr_t
+Mmap::doMmap()
+{
+    _mmapAddress = (caddr_t) mmap(0, _len, _prot, _shared, _fd, 0);
+
+    return _mmapAddress;
+}
+
+void
+Mmap::bzero()
+{
+    if(_mmapAddress != (caddr_t) -1)
+        memset(_mmapAddress, 0, _len);
+}
+
+
Index: trunk/src/testing/app/volvis/machines.dat.onlyone
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.onlyone	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.onlyone	(revision 4)
@@ -0,0 +1,1 @@
+1 0 100 0 100 0 0 1 1
Index: trunk/src/testing/app/volvis/vARB.h
===================================================================
--- trunk/src/testing/app/volvis/vARB.h	(revision 4)
+++ trunk/src/testing/app/volvis/vARB.h	(revision 4)
@@ -0,0 +1,68 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//vARB.h
+//contains cg related code from Luc
+
+#if defined(ADDARBGL)
+#ifndef _VARB_H_
+#define _VARB_H_
+
+#include "glUE.h"
+#include <assert.h>
+
+extern "C"
+{
+void glProgramStringARB(GLenum target, GLenum format, GLsizei len, const void *string);
+void glGenProgramsARB(GLsizei n, GLuint *programs);
+void glBindProgramARB(GLenum target, GLuint program);
+void glGetProgramivARB(GLenum target, GLenum pname, GLint *params);
+void glDeleteProgramsARB(GLsizei n, const GLuint *programs);
+void glActiveTextureARB (GLenum);
+void glProgramLocalParameter4fARB(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void glProgramEnvParameter4dARB(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+}
+
+extern GLuint vertexProgram, fragmentProgram;
+
+void handleARBError();
+int initARB();
+void exitARB();
+void enableARB(unsigned int);
+void disableARB();
+void setCurTextureARB(int name) ;
+
+#endif
+#endif
+
Index: trunk/src/testing/app/volvis/README_ATUL
===================================================================
--- trunk/src/testing/app/volvis/README_ATUL	(revision 4)
+++ trunk/src/testing/app/volvis/README_ATUL	(revision 4)
@@ -0,0 +1,35 @@
+1. June 8 2004
+--------------
+
+Trying to use Makefile.standalone. In main.cpp, I copied localhost to serverIP on lines 890 and 931. 
+
+2. June 14 2004
+---------------
+
+Spoke to Shalini. She helped me run volatile between master and one slave. Here is what I did :
+
+On igppviz : Execute the Optistore server
+On compute-0-1 : Execute the Optistore server
+
+On iggpviz run the client :
+
+ mpirun -np 2  -machinefile /home/anayak/volatile/volvis/.gige.twoigppviz $PWD/volvis -v Protein onlyonemachine.dat -a 2.08 -d 64 64 64 -n /home/anayak/volatile/volvis/machines.dat.onlyone
+
+the .gige.twoigppviz file contains :
+
+[anayak@igppviz volvis]$ cat .gige.twoigppviz 
+compute-0-1
+
+the onlyonemachine.dat 
+[anayak@igppviz volvis]$ cat onlyonemachine.dat 
+0 localhost
+1 localhost
+
+the machines.dat.onlyone contains
+
+[anayak@igppviz volvis]$ cat machines.dat.onlyone 
+1 0 100 0 100 0 0 1 1
+
+So this draws the entire volume on compute-0-1. 
+
+
Index: trunk/src/testing/app/volvis/Trackball.h
===================================================================
--- trunk/src/testing/app/volvis/Trackball.h	(revision 4)
+++ trunk/src/testing/app/volvis/Trackball.h	(revision 4)
@@ -0,0 +1,88 @@
+#ifndef Trackball_H
+#define Trackball_H
+
+class  Trackball {
+  
+ public:
+  Trackball();
+  ~Trackball();
+
+  void start(float x, float y);
+
+  // Pass the x and y coordinates of the last and current positions of
+  // the mouse, scaled so they are from (-1.0 ... 1.0).
+  //
+  // The resulting rotation is returned as a quaternion rotation in the
+  // first paramater.
+  void update(float x, float y);
+
+  // This function was added by joe kniss to facilitate a home key!
+  void clear();
+
+  // A useful function, builds a rotation matrix in Matrix based on
+  // given quaternion.
+  void buildRotMatrix(float m[4][4]);
+
+  // This function computes a quaternion based on an axis (defined by
+  // the given vector) and an angle about which to rotate.  The angle is
+  // expressed in radians.  The result is put into the third argument.
+  void reapply();
+
+  // This funciton was also written by joe to allow arbitary views
+  void setMatrix(float rot[16]);
+  void getAxisAngle(float& angle, float axis[3]);
+
+ private:
+  static float        trackballSize;
+  static int          renormCount;
+
+  float               curQuat[4];
+  float               lastQuat[4];
+  float               lastX;
+  float               lastY;
+  float		a[3]; /* Axis of rotation */
+  float		phi;  /* how much to rotate about axis */
+
+  float projectToSphere(float, float, float);
+
+};
+
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+
+#endif
+
Index: trunk/src/testing/app/volvis/caDataManagerClient.cpp
===================================================================
--- trunk/src/testing/app/volvis/caDataManagerClient.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/caDataManagerClient.cpp	(revision 4)
@@ -0,0 +1,554 @@
+/******************************************************************************
+ * OptiStore - A Data Processing Server
+ * Copyright (C) 2003 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * Authors: Luc Renambot luc@evl.uic.edu
+ *          Shalini Venkataraman shalini@evl.uic.edu
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about OptiStore to luc@evl.uic.edu
+ *****************************************************************************/
+
+#include "caDataManagerClient.h"
+
+int cDataManagerClient::RBUDP_PORT = 38049;
+
+//a simple lightweight function to compare a string with a wildcard
+//1 if there is a match, 0 otherwise
+int wildcmp(char *wild, char *string) {
+	char *newString, *newWild;
+	while ((*string) && (*wild != '*')) {
+		//if two char are normal characters they should match
+		if ((*wild != *string) && (*wild != '?'))
+			return 0;
+		wild++;
+		string++;
+	}
+	//found a "*"
+	while (*string) {
+		if (*wild == '*') {
+			//last char - found a match
+			if(!*++wild)
+				return 1;
+			newWild = wild;
+			newString = string+1;
+		}
+		//if we found a '?' just increment both by 1
+		else if ((*wild == *string) || (*wild == '?')) {
+			wild++;
+			string++;
+		}
+		//need to search with new string and wild card
+		else {
+			wild = newWild;
+			string = newString++;
+		}
+	}
+	//make sure that the remaining chars are just *
+	while (*wild == '*')
+		wild++;
+	return !*wild;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/////    cDataManagetClient class  /////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+
+cDataManagerClient::cDataManagerClient(char *_hostname)
+{
+    hostname = strdup(_hostname);
+    client = new QUANTAnet_tcpClient_c;
+
+    char name[128];
+    client->getSelfIP(name);
+    fprintf(stderr, "Client> %s,%u\n", name, client->getSelfPort());
+
+    dataptr = NULL;
+    gradptr = NULL;
+    vb = NULL;
+    pb = NULL;
+
+		// Initialize lookup table for gradient directions
+	InitDirectionsTable();
+
+    RBUDP_PORT = RBUDP_PORT + 1;
+}
+
+void cDataManagerClient::Open(int _port)
+{
+    port = _port;
+
+        //client->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, 2*256*256*256);
+
+    if (client->connectToServer(hostname, port) < 0)
+    {
+        fprintf(stderr, "Cannot connect to server [%s] port %d\n", hostname, port);
+        exit(-1);
+    }
+}
+
+void cDataManagerClient::Init()
+{
+    fprintf(stderr, "Sending init\n");
+
+        // Init phase
+    dataSize = sizeof(int);
+    command = Q_INIT;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+    int val[2];
+    int _port;
+
+    fprintf(stderr, "Waiting for init reply\n");
+
+    dataSize = sizeof(int) * 2;
+        //status =  client->read((char*)&id, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    status =  client->read((char*)val, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+	id = val[0];
+    _port = val[1];
+
+    fprintf(stderr, "Client> MyID is [%d]\n", id);
+
+#if defined(USE_RBUDP)
+    fprintf(stderr, "Client> My RBUDP port is [%d]\n", _port);
+
+    sleep(1);
+        // Get connection with the remote RBUDP server
+        //blastee = new QUANTAnet_rbudpReceiver_c(RBUDP_PORT);
+    blastee = new QUANTAnet_rbudpReceiver_c(_port);
+    blastee->init(hostname);
+#endif
+
+}
+
+void cDataManagerClient::Exit()
+{
+        // Exit phase
+    dataSize = sizeof(int);
+    command = Q_EXIT;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    fprintf(stderr, "Client> Exit\n");
+}
+
+int cDataManagerClient::Query()
+{
+    int i;
+    char name[128];
+    int dims[3];
+
+        // Query phase
+    dataSize = sizeof(int);
+    command = Q_LIST;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+    dataSize = sizeof(int);
+    status =  client->read((char*)&num_datasets, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    fprintf(stderr, "Client> There are [%d] datasets\n", num_datasets);
+    datasets = (DataDesc*)malloc(num_datasets*sizeof(DataDesc));
+    for (i=0;i<num_datasets;i++)
+    {
+        memset(name, 0, 128);
+        dataSize = 128;
+        status = client->read((char*)name,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+        datasets[i].name = strdup(name);
+
+        dataSize = 3*sizeof(int);
+        status = client->read((char*)dims,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+        datasets[i].x = dims[0];
+        datasets[i].y = dims[1];
+        datasets[i].z = dims[2];
+
+        //fprintf(stderr, "Client> \tDataset [%d] : [%s]  -- [%d %d %d]\n", i, name, dims[0], dims[1], dims[2]);
+    }
+
+    return num_datasets;
+}
+
+void cDataManagerClient::Load(int ds)
+{
+    int val;
+
+        // Load a dataset
+    dataSize = sizeof(int);
+    command = Q_LOAD;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+        // Dataset #
+    dataSize = sizeof(int);
+    val = ds;
+    status = client->write((char*)&val, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    fprintf(stderr, "Client> Picking dataset %d [%s]\n", val, datasets[val].name);
+}
+
+void cDataManagerClient::Resample(int sx, int sy, int sz)
+{
+        // Resample a dataset
+    dataSize = sizeof(int);
+    command = Q_SAMPLE;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+        // Parameter: 3 int for dimensions
+    dataSize = 3 * sizeof(int);
+    sizes[0] = sx;
+    sizes[1] = sy;
+    sizes[2] = sz;
+    status = client->write((char*)sizes, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    fprintf(stderr, "Client> Asking for resampling at [%3d %3d %3d]\n", sizes[0], sizes[1], sizes[2]);
+}
+
+
+void cDataManagerClient::Crop(int ox, int oy, int oz, int sx, int sy, int sz)
+{
+        // Crop a dataset
+    dataSize = sizeof(int);
+    command = Q_CROP;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+        // Parameter: 3 int for dimensions
+    dataSize = 6 * sizeof(int);
+    sizes[0] = ox;
+    sizes[1] = oy;
+    sizes[2] = oz;
+    sizes[3] = sx;
+    sizes[4] = sy;
+    sizes[5] = sz;
+    status = client->write((char*)sizes, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    fprintf(stderr, "Client> Asking for cropping from [%3d %3d %3d] to [%3d %3d %3d]\n",
+            sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], sizes[5]);
+
+
+        // Allocate data storage for volume
+    if (dataptr != NULL) free(dataptr);
+    dataptr = (unsigned char*)malloc ((sizes[3]-sizes[0]+1) *
+                                      (sizes[4]-sizes[1]+1) * (sizes[5]-sizes[2]+1) );
+
+    if (gradptr != NULL) free(gradptr);
+    gradptr = (unsigned short*)malloc ((sizes[3]-sizes[0]+1) *
+                                       (sizes[4]-sizes[1]+1) * (sizes[5]-sizes[2]+1)
+                                       * sizeof(unsigned short));
+
+        //client->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, 2*sizes[0]*sizes[1]*sizes[2]);
+        //fflush(stdout);
+}
+
+
+unsigned char* cDataManagerClient::Volume()
+{
+	int amount;
+
+		/////////////////////////////////////////////////////////////////////////
+		// Volume
+		/////////////////////////////////////////////////////////////////////////
+	fprintf(stderr, "Client> Asking for volume\n");
+	dataSize = sizeof(int);
+	command = Q_VOL;
+	status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	dataSize = sizeof(int);
+	status = client->read((char*)&amount,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+	dataSize = amount;
+#if defined(USE_RBUDP)
+	blastee->receive((void*)dataptr, dataSize, RBUDP_FRAME);
+#else
+	status = client->read((char*)dataptr,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+#endif
+
+	fprintf(stderr, "Client> Got volume of %d bytes\n\n", amount);
+
+	if (status != QUANTAnet_tcpClient_c::OK)
+		client->showStatus(status, dataSize);
+		/////////////////////////////////////////////////////////////////////////
+		/////////////////////////////////////////////////////////////////////////
+
+	return dataptr;
+}
+
+unsigned short* cDataManagerClient::Gradient()
+{
+	int amount;
+
+		/////////////////////////////////////////////////////////////////////////
+		// Gradient
+		/////////////////////////////////////////////////////////////////////////
+	fprintf(stderr, "Client> Asking for gradient volume\n");
+	dataSize = sizeof(int);
+	command = Q_GRAD;
+	status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	dataSize = sizeof(int);
+	status = client->read((char*)&amount,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	dataSize = amount;
+#if defined(USE_RBUDP)
+	blastee->receive((void*)gradptr, dataSize, RBUDP_FRAME);
+#else
+	status = client->read((char*)gradptr,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+#endif
+
+	fprintf(stderr, "Client> Got gradient volume of %d bytes\n\n", amount);
+
+	if (status != QUANTAnet_tcpClient_c::OK)
+		client->showStatus(status, dataSize);
+		/////////////////////////////////////////////////////////////////////////
+		/////////////////////////////////////////////////////////////////////////
+
+	return gradptr;
+}
+
+int* cDataManagerClient::Histogram()
+{
+		/////////////////////////////////////////////////////////////////////////
+		// Histogram command
+		/////////////////////////////////////////////////////////////////////////
+	fprintf(stderr, "Client> Asking for volume histogram\n");
+	dataSize = sizeof(int);
+	command = Q_HISTO;
+	status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	dataSize = 259*sizeof(int);
+    int *histo = (int*)malloc(dataSize);
+    memset(histo, 0, dataSize);
+	status = client->read((char*)histo,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	fprintf(stderr, "Client> Got volume histogram of %d bytes\n", dataSize);
+	fprintf(stderr, "Client>     Histogram: min %d max %d mean %d\n\n",
+            histo[0], histo[1], histo[2]);
+
+	if (status != QUANTAnet_tcpClient_c::OK)
+		client->showStatus(status, dataSize);
+		/////////////////////////////////////////////////////////////////////////
+		/////////////////////////////////////////////////////////////////////////
+
+	return histo;
+}
+
+unsigned char* cDataManagerClient::Histogram2D()
+{
+		/////////////////////////////////////////////////////////////////////////
+		// Histogram2D command
+		/////////////////////////////////////////////////////////////////////////
+	fprintf(stderr, "Client> Asking for volume gradient histogram2D\n");
+	dataSize = sizeof(int);
+	command = Q_HISTO2D;
+	status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	dataSize = 256*256*sizeof(unsigned char);
+    unsigned char *histo = (unsigned char*)malloc(dataSize);
+    memset(histo, 0, dataSize);
+	status = client->read((char*)histo,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+	fprintf(stderr, "Client> Got gradient histogram2D of %d bytes\n", dataSize);
+
+	if (status != QUANTAnet_tcpClient_c::OK)
+		client->showStatus(status, dataSize);
+		/////////////////////////////////////////////////////////////////////////
+		/////////////////////////////////////////////////////////////////////////
+
+	return histo;
+}
+
+NetPointBuffer*
+cDataManagerClient::IsoPoints(int isoval, int inc, int maxp)
+{
+    int val[3];
+
+        /////////////////////////////////////////////////////////////////////////
+        // Isosurface
+        /////////////////////////////////////////////////////////////////////////
+    dataSize = sizeof(int);
+    command = Q_POINT;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+        // Parameter: iso value
+    dataSize = 3*sizeof(int);
+    val[0] = isoval;
+    val[1] = inc;
+    val[2] = maxp;
+    status = client->write((char*)&val[0], &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    fprintf(stderr, "Client> Asking for isopoints at [%d] increment [%d]\n", val[0], val[1]);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+    if (pb)
+    {
+        free(pb->vertex);
+        free(pb);
+    }
+
+    pb = (NetPointBuffer*)malloc(sizeof(NetPointBuffer));
+    dataSize = 1 * sizeof(int);
+    status =  client->read((char*)sizes, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    pb->nbpts = sizes[0];
+    pb->vertex = (float*)malloc( pb->nbpts * 3 * sizeof(float) );
+
+    dataSize = pb->nbpts * 3 * sizeof(float);
+    status = client->read((char*)pb->vertex,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    fprintf(stderr, "Client> Got isopoints of %d bytes\n\n", dataSize);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+        /////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////////////////////
+    return pb;
+}
+
+
+NetVertexBuffer* cDataManagerClient::Isosurface(int isoval, int gaussp, float decim)
+{
+    int val[2], total;
+	float fval;
+
+        /////////////////////////////////////////////////////////////////////////
+        // Isosurface
+        /////////////////////////////////////////////////////////////////////////
+    dataSize = sizeof(int);
+    command = Q_ISO;
+    status = client->write((char*)&command, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+        // Parameter: iso value
+    dataSize = 2 * sizeof(int);
+    val[0] = isoval;
+    val[1] = gaussp;
+    status = client->write((char*)&val, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    fprintf(stderr, "Client> Asking for isosurface at [%d]\n", val[0]);
+
+    dataSize = sizeof(float);
+    fval = decim;
+    status = client->write((char*)&fval, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+    if (vb)
+    {
+        free(vb->vertex);
+        free(vb->normal);
+        free(vb->index);
+        free(vb->length);
+        free(vb);
+    }
+
+    vb = (NetVertexBuffer*)malloc(sizeof(NetVertexBuffer));
+    dataSize = 3 * sizeof(int);
+    status =  client->read((char*)sizes, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+    vb->nbpts     = sizes[0];
+    vb->nbindices = sizes[1];
+    vb->lengths   = sizes[2];
+
+    vb->vertex = (float*)malloc( vb->nbpts * 3 * sizeof(float) );
+    vb->normal = (float*)malloc( vb->nbpts * 3 * sizeof(float) );
+    vb->index  = (unsigned int*)malloc( vb->nbindices * sizeof(unsigned int) );
+    vb->length = (unsigned short*)malloc( vb->lengths * sizeof(unsigned short) );
+
+    dataSize = vb->nbpts * 3 * sizeof(float);
+    status = client->read((char*)vb->vertex,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    total = dataSize;
+    dataSize = vb->nbpts * 3 * sizeof(float);
+    status = client->read((char*)vb->normal,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    total += dataSize;
+    dataSize = vb->nbindices * sizeof(unsigned int);
+    status = client->read((char*)vb->index,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    total += dataSize;
+    dataSize = vb->lengths * sizeof(unsigned short);
+    status = client->read((char*)vb->length,&dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+    total += dataSize;
+
+    fprintf(stderr, "Client> Got isosurface of %d bytes\n\n", total);
+
+    if (status != QUANTAnet_tcpClient_c::OK)
+        client->showStatus(status, dataSize);
+
+        /////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////////////////////
+    return vb;
+}
+
+
+char *cDataManagerClient::Name(int _idx)
+{
+    if (_idx >=0 && _idx < num_datasets)
+        return datasets[_idx].name;
+    else
+        return NULL;
+}
+
+cDataManagerClient::~cDataManagerClient()
+{
+#if defined(USE_RBUDP)
+    blastee->close();
+#endif
+}
+
+//Given the symbolic name of a volume, returns its index
+//if the volume is not found return -1;
+int cDataManagerClient::Lookup(const char* name)
+{
+  	for (int i=0;i<num_datasets;i++)
+    {
+  		if (strcmp(name,datasets[i].name) == 0)
+  			return i;
+  	}
+  	return -1;
+}
+
+//Given the symbolic name of a volume as a wild card, returns no of
+//that correspond to this name,
+//if not found, return 0;
+//caller has to free the memory
+int cDataManagerClient::GetMatching(char* wildcard, int *&indexList)
+{
+	int curIndex = 0;
+	indexList = (int*)malloc(num_datasets*sizeof(int));
+	for (int i=0;i<num_datasets;i++)
+	{
+		if (wildcmp(wildcard,datasets[i].name))
+			indexList[curIndex++] = i;
+  	}
+	indexList = (int*)realloc(indexList,curIndex*sizeof(int));
+  	return curIndex;
+}
+
+    //get the size of the datasets
+void cDataManagerClient::GetDataDims(unsigned int idx, unsigned int& x, unsigned int& y, unsigned int& z)
+{
+  	x = datasets[idx].x;
+  	y = datasets[idx].y;
+ 	z = datasets[idx].z;
+}
Index: trunk/src/testing/app/volvis/machines.dat.evl2b2
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.evl2b2	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.evl2b2	(revision 4)
@@ -0,0 +1,4 @@
+1 0.8 49.2 51.68 100 0.0 0.0 0.5 1
+1 51.68 100 51.68 100 0.5 0.0 0.5 1
+2 0.8 49.2 0.8 49.2 0.0 0.0 0.5 1
+2 51.68 100 0.8 49.2 0.5 0.0 0.5 1
Index: trunk/src/testing/app/volvis/vUI.h
===================================================================
--- trunk/src/testing/app/volvis/vUI.h	(revision 4)
+++ trunk/src/testing/app/volvis/vUI.h	(revision 4)
@@ -0,0 +1,74 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef _VUI_H_
+#define _VUI_H_
+//Translates from mouse coords to world coords
+void mouseToWorld(int x, int y, float world[3]) ;
+void startRotation(int x, int y);
+void doRotation(int x, int y);
+
+void startZoom(int x, int y);
+void doZoom(int x, int y);
+
+void startTranslate(int x, int y);
+void doTranslate(int x, int y);
+
+void endInteract();
+
+void printUsage();
+void scaleSampleRate(float factor);
+void togglePrintFPS() ;
+void doExit();
+void toggleCutPlane();
+void toggleBoundBox() ;
+void saveGradientVolume();
+
+void doAxisRotation(float angle, char rotaxes) ;
+void setLUT(int size, unsigned char* data) ;
+void setLowRes(int lowres);
+void genIsosurface(int x, int y) ;
+void genIsopoint(int x, int y) ;
+void incIsoValue(int value) ;
+
+void setRoam();
+void roamVolume(int roamX, int roamY, int roamZ) ;
+void animateVolume();
+void animateSelected();
+void updateAnim(int value);
+void setProbe();
+void probeVolume(int probeX, int probeY, int probeZ) ;
+void doSelect(int curIndex) ;
+void doSelect(int x, int y) ;
+#endif
Index: trunk/src/testing/app/volvis/Kill
===================================================================
--- trunk/src/testing/app/volvis/Kill	(revision 4)
+++ trunk/src/testing/app/volvis/Kill	(revision 4)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+killall -9 volvis
+forall killall -9 volvis
+
Index: trunk/src/testing/app/volvis/optiLocal.dat
===================================================================
--- trunk/src/testing/app/volvis/optiLocal.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiLocal.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 localhost
+1 localhost
+2 localhost
+3 localhost
+4 localhost
+5 localhost
+6 localhost
+7 localhost
+8 localhost
Index: trunk/src/testing/app/volvis/vNet.cpp
===================================================================
--- trunk/src/testing/app/volvis/vNet.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vNet.cpp	(revision 4)
@@ -0,0 +1,523 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#if defined(V_DISTRIBUTED)
+#include "vNet.h"
+#include "global.h"
+#include "vGeometry.h"
+#include <string.h>
+
+char* getServerIP(int rank, const char* serverFile) {
+	string line;
+	ifstream in(serverFile); // Read
+	if (!in) {
+		cerr <<"File "<<serverFile<<" cant be read\n";
+		return NULL;
+	}
+	while(getline(in,line)) {
+		istringstream line_stream(line);
+		int tileRank;
+		string serverIP;
+		line_stream >> tileRank;
+		line_stream >> serverIP;
+		if (tileRank == rank)
+			return (char*)serverIP.c_str();
+	}
+	return NULL;
+}
+
+
+QUANTAts_mutex_c tfMutex;
+vNet::vNet()
+{
+	master = 0;
+	cmdFlushed = 1;
+	readyToDie =0;		//dont want to die right away
+}
+
+vNet::~vNet() {
+}
+
+void vNet::init(int &argc, char** &argv)
+{
+	//init MPI
+	int rc = MPI_Init(&argc, &argv);
+	MPI_Comm comm;
+	rc = MPI_Comm_size(MPI_COMM_WORLD, &noProcs);
+	rc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	if (setenv("DISPLAY", ":0", 1) == -1)
+	{
+		cerr<<"\nCannot display on Tile "<<rank<<endl;
+		exit(1);
+	}
+}
+
+//Clean up and exit
+void vNet::deactivateTiles() {
+	fillExitCommand();
+}
+
+void vNet::process() {
+	if (master != rank)	//slaves
+    {
+		char* data = new char[COMMAND_SIZE];
+		bzero(data, COMMAND_SIZE);
+		cmdFlushed = 1;
+		//listen from master node for commands
+		MPI_Bcast(data, COMMAND_SIZE, MPI_BYTE, master, MPI_COMM_WORLD );
+		//fprintf(stderr, "Proc %d/%d> Receiving command\n", rank, noProcs);
+		processCmd(data);	//process the command
+		glutPostRedisplay();
+    }
+	else
+    { //master
+		//Broadcast a command that has been set appropriately
+		//fprintf(stderr, "Proc %d/%d> Sending command\n", rank, noProcs);
+		tfMutex.lock();
+		MPI_Bcast(buffer, COMMAND_SIZE, MPI_BYTE, master, MPI_COMM_WORLD );
+		tfMutex.unlock();
+
+
+		if (readyToDie == 1)
+		{
+			int rc = MPI_Finalize(); //wait and clean up
+			exit(0);         //All dead, We can now exit
+		}
+		fillDummyCommand(); //just to keep everyone displaying
+		//fprintf(stderr, "Proc %d/%d> After Sending command, before display\n", rank, noProcs);
+		glutPostRedisplay();
+    }
+}
+
+void vNet::processCmd(char* data)
+{
+	//Unpack data - contains command name and arguments
+	dataPack.initUnpack(data, COMMAND_SIZE);
+	char key[24];
+	int len;
+	dataPack.unpackInt(&len);   //str length of command
+	dataPack.unpack(key, len);
+	if (!strcmp(key,"DUMMY"))
+	{
+		//do nothing - ignore (this is just to synchronize display calls of all tiles with master)
+	}
+	else if (!strcmp(key,"VOL_ROTN")) {
+		//set the global transform rotn to be this one
+		for (int i=0;i<16;i++)
+			dataPack.unpackFloat(&renderList[global.curPrimIdx]->xform.rotn[i]);
+	}
+	else if (!strcmp(key,"VOL_CUTROTN")) {
+		global.cut.update = true;
+		//set the cut rotn to be this one
+		dataPack.unpackFloat(&global.cut.angle);
+		for (int i=0;i<3;i++)
+			dataPack.unpackFloat(&global.cut.axis[i]);
+	}
+	else if (!strcmp(key,"VOL_LOWRES")) { //use tag to distinguish messages
+		//set the global transform lowresrto be this one
+		dataPack.unpackInt(&global.volren.lowRes);
+	}
+	else if (!strcmp(key,"VOL_TRANSLATION")) { //use tag to distinguish messages
+		//set the global transform lowresrto be this one
+		for (int i=0;i<3;i++)
+			dataPack.unpackFloat(&renderList[global.curPrimIdx]->xform.trans[i]);
+	}
+	else if (!strcmp(key,"VOL_ZOOM")) { //use tag to distinguish messages
+		//set the global transform lowresrto be this one
+		float zoomFactor;
+		dataPack.unpackFloat(&zoomFactor);
+		renderList[global.curPrimIdx]->xform.scale += zoomFactor;
+		//global.env.eye[2] += zoomFactor;
+	}
+	else if (!strcmp(key,"VOL_CUTZOOM")) { //use tag to distinguish messages
+		//set the global transform lowresrto be this one
+		float zoomFactor;
+		dataPack.unpackFloat(&zoomFactor);
+		global.cut.user[3] += zoomFactor;
+	}
+	else if (!strcmp(key,"VOL_SAMPLERATE")) { //use tag to distinguish messages
+		//set the global transform lowresrto be this one
+		float scaleSample;
+		dataPack.unpackFloat(&scaleSample);
+		global.volren.goodSamp *= scaleSample;
+		global.volren.interactSamp *= scaleSample;
+		global.volren.sampleRate = global.volren.goodSamp;
+	}
+	else if (!strcmp(key,"VOL_PRINTFPS")) {
+		global.ui.printFPS = !global.ui.printFPS;
+		if (global.ui.printFPS)
+			glutIdleFunc(idle);
+		else
+			glutIdleFunc(0);
+	}
+	else if (!strcmp(key,"VOL_CUTPLANE")) {
+		global.ui.cutEnabled = !global.ui.cutEnabled;
+	}
+	else if (!strcmp(key,"VOL_BOUNDBOX")) {
+		global.ui.bboxEnabled = !global.ui.bboxEnabled;
+	}
+	else if (!strcmp(key,"VOL_NAVROAM")) {
+		global.ui.navMode = V_ROAM;
+	}
+	else if (!strcmp(key,"VOL_NAVPROBE")) {
+		global.ui.navMode = V_PROBE;
+	}
+	else if (!strcmp(key,"VOL_ISOSURFACE")) {
+		int isoValue;
+		float tx, ty, scale;
+		dataPack.unpackInt(&isoValue);
+		dataPack.unpackFloat(&tx);
+		dataPack.unpackFloat(&ty);
+		dataPack.unpackFloat(&scale);
+		global.volume->setIsoValue(isoValue);
+		NetVertexBuffer* theGeom = global.volume->isoSurface();
+		vGeometry* newIso = new vGeometry(theGeom);
+		newIso->xform.trans[0] = tx;
+		newIso->xform.trans[1] = ty;
+		newIso->xform.scale = scale;
+		fprintf(stderr,"VOL_ISOSURFACE: New geom translation %f %f scale %f\n",newIso->xform.trans[0],newIso->xform.trans[1],
+			newIso->xform.scale);
+		renderList.push_back(newIso);
+	}
+	else if (!strcmp(key,"VOL_LUT")) {
+		for (int i=0;i<256*4;i++) {
+			dataPack.unpackChar((char*)&global.volren.deptex[i]);
+		}
+		dataPack.unpackInt(&global.volren.lowRes);
+		global.volren.loadTLUT = 1;
+	}
+	else if (!strcmp(key,"VOL_SAVEGRADIENTVOL")) {
+		global.volume->saveGradient();
+	}
+	else if (!strcmp(key,"VOL_ROAM")) {
+		int x, y, z;
+		dataPack.unpackInt(&x);
+		dataPack.unpackInt(&y);
+		dataPack.unpackInt(&z);
+		global.volume->roam(x,y,z);
+		global.volren.loadVolume = 1;
+	}
+	else if (!strcmp(key,"VOL_PROBE")) {
+		int x, y, z;
+		dataPack.unpackInt(&x);
+		dataPack.unpackInt(&y);
+		dataPack.unpackInt(&z);
+		global.volume->probe(x,y,z);
+	}
+	/*
+	else if (!strcmp(key,"VOL_POINTERPOS")) {
+		dataPack.unpackFloat(&global.pointerPos[0]);
+		dataPack.unpackFloat(&global.pointerPos[1]);
+		dataPack.unpackFloat(&global.pointerPos[2]);
+		global.curPrimIdx= 0;
+		//select each primitive to see which is selected
+		for (int i=0;i< renderList.size();i++) {
+			if (renderList[i]->select()) {
+				global.curPrimIdx= i;
+				break;
+			}
+		}
+	}
+	*/
+	else if (!strcmp(key,"VOL_SELECT")) {
+		dataPack.unpackInt(&global.curPrimIdx);
+		for (int i=0;i<renderList.size();i++) {
+			if (i==global.curPrimIdx)
+				renderList[i]->setSelected(true);
+			else
+				renderList[i]->setSelected(false);
+		}
+	}
+	else if (!strcmp(key,"VOL_TOGGLEANIMATE")) {
+		for (int i=0;i<renderList.size();i++)
+			renderList[i]->toggleAnimate();
+	}
+	else if (!strcmp(key,"VOL_UPDATEANIM")) {
+		for (int i=0;i<renderList.size();i++) {
+			if (renderList[i]->isAnimating()) {
+				renderList[i]->next();
+			}
+		}
+	}
+	else if (!strcmp(key,"EXIT"))
+	{
+		int rc = MPI_Finalize(); //clean up mpi stuff
+		if (data) delete data;   //be responsible
+		deallocateAll();
+		exit(0);
+	}
+	if (data) delete data;
+}
+
+// Called when tile needs to be refreshed
+bool vNet::readTileConfig(const char* configFile) {
+	cerr << rank<<" readTileConfig : filename is "<<configFile<<endl;
+	string line;
+	ifstream in(configFile); // Read
+	if (!in) {
+		cerr <<"File "<<configFile<<" cant be read\n";
+		return false;
+	}
+	global.env.frustumList.clear();
+	global.env.viewportList.clear();
+	while(getline(in,line)) {
+		istringstream line_stream(line);
+		int tileRank;
+		float	minX, maxX, minY, maxY;
+		float	vpx, vpy, vpwidth, vpheight;
+		line_stream >> tileRank;
+		//read the tile extent
+		line_stream >> minX;
+		line_stream >> maxX;
+		line_stream >> minY;
+		line_stream >> maxY;
+
+		//read the viewport for each frustum
+		if (line_stream.eof()) { //fill in default values
+			vpx = vpy = 0.0;
+			vpwidth = vpheight = 1.0f;
+		}
+		else {
+			line_stream >> vpx;
+			line_stream >> vpy;
+			line_stream >> vpwidth;
+			line_stream >> vpheight;
+		}
+
+		if (tileRank == rank)  //if the rank matches, store the values
+		{
+			//fprintf(stderr, "\nTile %d Image offsets: %d %d ", rank, xOffset, yOffset);
+			vFrustum curFrustum;
+			vViewport curvp;
+			curFrustum.left = (minX - 50.0) / 50.0;
+			curFrustum.right = (maxX - 50.0) / 50.0;
+			curFrustum.bottom = (minY - 50.0) / 50.0;
+			curFrustum.top = (maxY - 50.0) / 50.0;
+			float fov = 45.0f*M_PI/180.0f;
+			float b = global.env.clip[0] * (float) tan(fov * 0.5);
+			fprintf(stderr,"Node %d aspect %f\n",rank,global.win.aspect);
+			float r = b * global.win.aspect;
+			curFrustum.left *= r;  //left
+			curFrustum.right *= r;   //right
+			curFrustum.bottom *= b;  //bottom
+			curFrustum.top *= b;   //top
+
+			//now add the current frustum to the frustum list
+			global.env.frustumList.push_back(curFrustum);
+
+			curvp.x = vpx;
+			curvp.y = vpy;
+			curvp.width = vpwidth;
+			curvp.height = vpheight;
+			global.env.viewportList.push_back(curvp);
+			fprintf(stderr,"*******viewport %f %f %f %f\n",curvp.x, curvp.y, curvp.width, curvp.height);
+		}
+	}  //end while
+	return true;
+}
+void vNet::packCommand(const char* cmdString, int flushed)
+{
+	memset(buffer, 0, COMMAND_SIZE);
+	dataPack.initPack(buffer, COMMAND_SIZE);
+	char cmd[25];
+	strcpy(cmd, cmdString);
+	int len = strlen(cmd) +1;
+	dataPack.packInt(len);
+	dataPack.pack(cmd, len );
+	cmdFlushed = flushed;
+	//the command is sent during the display call
+}
+
+//send vol rotation
+void vNet::setRotn(float rotn[16]) {
+	packCommand("VOL_ROTN");
+	for (int i=0;i<16;i++)
+		dataPack.packFloat(rotn[i]);
+}
+
+//send the transfer function
+void vNet::setLUT(int size, unsigned char* data) {
+	tfMutex.lock();
+	packCommand("VOL_LUT");
+	for (int i=0;i<size;i++)
+		dataPack.packChar(data[i]);
+	tfMutex.unlock();
+}
+
+//send the cutplane rotation in axis angle
+void vNet::setCutRotation(float angle, float axis[3]) {
+	packCommand("VOL_CUTROTN");
+	dataPack.packFloat(angle);
+	for (int i=0;i<3;i++)
+		dataPack.packFloat(axis[i]);
+}
+
+//set the zoom of the cutplane
+void vNet::setCutZoom(float dzoom) {
+	packCommand("VOL_CUTZOOM");
+	dataPack.packFloat(dzoom);
+}
+
+//send lowres
+void vNet::setLowRes(int lowRes) {
+	packCommand("VOL_LOWRES");
+	dataPack.packInt(lowRes);
+	//fprintf(stderr,"In setLowRes: lowres %d\n",lowRes);
+}
+
+//save GRadient Info
+void vNet::saveGradientVolume() {
+	 packCommand("VOL_SAVEGRADIENTVOL");
+}
+
+//do select
+void vNet::select(float pointerPos[3]) {
+	packCommand("VOL_POINTERPOS");
+	for (int i=0;i<3;i++)
+		dataPack.packFloat(pointerPos[i]);
+}
+
+//do select
+void vNet::select(int index) {
+	packCommand("VOL_SELECT");
+	dataPack.packInt(index);
+}
+
+//set translation
+void vNet::setTranslation(float translation[3]) {
+	packCommand("VOL_TRANSLATION");
+	for (int i=0;i<3;i++)
+		dataPack.packFloat(translation[i]);
+}
+
+//set zoom
+void vNet::setZoom(float factor) {
+	packCommand("VOL_ZOOM");
+	dataPack.packFloat(factor);
+}
+
+//scale sample rate
+void vNet::scaleSampleRate(float factor) {
+	packCommand("VOL_SAMPLERATE");
+	dataPack.packFloat(factor);
+}
+
+//animate volume
+void vNet::animateVolume() {
+	packCommand("VOL_TOGGLEANIMATE");
+}
+
+//animate volume
+void vNet::updateAnim() {
+	packCommand("VOL_UPDATEANIM");
+}
+
+
+//toggle printing frame rate
+void vNet::togglePrintFPS() {
+	packCommand("VOL_PRINTFPS");
+}
+
+//toggle printing frame rate
+void vNet::toggleCutPlane() {
+	packCommand("VOL_CUTPLANE");
+}
+
+//toggle display of bound box
+void vNet::toggleBoundBox() {
+	packCommand("VOL_BOUNDBOX");
+}
+
+//set roam
+void vNet::setRoam() {
+	packCommand("VOL_NAVROAM");
+}
+
+//set probe
+void vNet::setProbe() {
+	packCommand("VOL_NAVPROBE");
+}
+
+//send the roam factor
+void vNet::roamVolume(int roamX, int roamY, int roamZ) {
+	packCommand("VOL_ROAM");
+	dataPack.packInt(roamX);
+	dataPack.packInt(roamY);
+	dataPack.packInt(roamZ);
+}
+
+//send the roam factor
+void vNet::probeVolume(int probeX, int probeY, int probeZ) {
+	packCommand("VOL_PROBE");
+	dataPack.packInt(probeX);
+	dataPack.packInt(probeY);
+	dataPack.packInt(probeZ);
+
+}
+
+//send command to get the isosurface and display it
+void vNet::getIsosurface(int isoValue, float tx, float ty, float scale) {
+	packCommand("VOL_ISOSURFACE");
+	dataPack.packInt(isoValue);
+	dataPack.packFloat(tx);
+	dataPack.packFloat(ty);
+	dataPack.packFloat(scale);
+
+}
+
+//send command to get the isopoint and display it
+void vNet::getIsopoint(int isoValue, float tx, float ty, float scale) {
+	packCommand("VOL_ISOPOINT");
+	dataPack.packInt(isoValue);
+	dataPack.packFloat(tx);
+	dataPack.packFloat(ty);
+	dataPack.packFloat(scale);
+
+}
+
+//send empty broadcasts to clients
+void vNet::fillDummyCommand()
+{
+	packCommand("DUMMY", 1);
+}
+
+//fill up a command to do MPI_Finalize (clean up MPI)
+void vNet::fillExitCommand()
+{
+	packCommand("EXIT");
+	readyToDie =1;		//set flag -ready to exit now
+}
+
+
+#endif
Index: trunk/src/testing/app/volvis/vCG.cpp
===================================================================
--- trunk/src/testing/app/volvis/vCG.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vCG.cpp	(revision 4)
@@ -0,0 +1,200 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//vCG.cpp
+//has the CG related code from Luc Renambot
+#if defined(ADDCGGL)
+
+#include "vCG.h"
+#include "global.h"
+#include <stdio.h>
+#include <stdlib.h>
+CGcontext context;
+CGprogram vertexProgram, fragmentProgram;
+CGprofile fprofile, vprofile;
+CGparameter ModelViewProj;
+CGparameter hTexture0, hTexture1;
+CGparameter param;
+int curTexId ;
+void handleCgError()
+{
+    fprintf(stderr, "Cg> error: %s\n", cgGetErrorString(cgGetError()));
+    exit(1);
+}
+
+int initCG()
+{
+	// Basic Cg setup; register a callback function for any errors
+	// and create an initial context
+	cgSetErrorCallback(handleCgError);
+
+	/* cgContext creation */
+	context = cgCreateContext();
+	assert(cgIsContext(context));
+
+	fprintf(stderr, "---------------------------------------------------------\n");
+
+	if (cgGLIsProfileSupported(CG_PROFILE_FP30))
+    {
+		fprintf(stderr, "CG> success : FP30 fragment profile supported on this system.\n");
+		fprofile = CG_PROFILE_FP30;
+    }
+	else
+    {
+		fprintf(stderr, "CG> warning : FP30 fragment profile NOT supported on this system.\n");
+		if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1))
+		{
+			fprintf(stderr, "CG> success : ARBFP1 fragment profile supported on this system.\n");
+			fprofile = CG_PROFILE_ARBFP1;
+		}
+		else
+		{
+			fprintf(stderr, "CG> warning : ARBFP1 fragment profile NOT supported on this system.\n");
+			if (cgGLIsProfileSupported(CG_PROFILE_FP20))
+			{
+				fprintf(stderr, "CG> success : FP20 fragment profile supported on this system.\n");
+				fprofile = CG_PROFILE_FP20;
+			}
+			else
+			{
+				fprintf(stderr, "CG> warning : FP20 fragment profile NOT supported on this system.\n");
+				fprintf(stderr, "CG> error : NO fragment profile supported on this system.\n");
+				fprintf(stderr, "---------------------------------------------------------\n");
+				exit(1);
+			}
+		}
+    }
+
+	fprintf(stderr, "---------------------------------------------------------\n");
+
+	if (cgGLIsProfileSupported(CG_PROFILE_VP30))
+    {
+		fprintf(stderr, "CG> success : VP30 vertex profile supported on this system.\n");
+		vprofile = CG_PROFILE_VP30;
+    }
+	else
+    {
+		fprintf(stderr, "CG> warning : VP30 vertex profile NOT supported on this system.\n");
+		if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1))
+		{
+			fprintf(stderr, "CG> success : ARBVP1 vertex profile supported on this system.\n");
+			vprofile = CG_PROFILE_ARBVP1;
+		}
+		else
+		{
+			fprintf(stderr, "CG> warning : ARBVP1 vertex profile NOT supported on this system.\n");
+			if (cgGLIsProfileSupported(CG_PROFILE_VP20))
+			{
+				fprintf(stderr, "CG> success : VP20 vertex profile supported on this system.\n");
+				vprofile = CG_PROFILE_VP20;
+			}
+			else
+			{
+				fprintf(stderr, "CG> warning : VP20 vertex profile NOT supported on this system.\n");
+				fprintf(stderr, "CG> error : NO vertex profile supported on this system.\n");
+				fprintf(stderr, "---------------------------------------------------------\n");
+				exit(1);
+			}
+		}
+    }
+
+	fprintf(stderr, "---------------------------------------------------------\n");
+
+	// adding source text to context
+	//shalini commenting out for cutplane
+/*	vertexProgram = cgCreateProgramFromFile(
+		context, CG_SOURCE, "shaders/vertex.cg", vprofile, "C4E1v_transform", NULL);
+	fprintf(stderr, "CG> Compiling Vertex [shaders/vertex.cg]....\n");
+	if (!cgIsProgramCompiled(vertexProgram))
+		cgCompileProgram(vertexProgram);
+	fprintf(stderr, "CG> \t done\n");
+	cgGLLoadProgram(vertexProgram);
+
+	ModelViewProj = cgGetNamedParameter(vertexProgram, "modelViewProj");
+*/
+	if (fprofile == CG_PROFILE_FP20)
+    {
+		fragmentProgram = cgCreateProgramFromFile(
+			context, CG_SOURCE, "shaders/fragment20.cg", fprofile, "C2E2f_passthrough", NULL);
+		fprintf(stderr, "CG> Compiling Fragment [shaders/fragment20.cg] ....\n");
+    }
+	else
+		if (fprofile == CG_PROFILE_FP30)
+		{
+			fragmentProgram = cgCreateProgramFromFile(
+				context, CG_SOURCE, "shaders/fragment30.cg", fprofile, "C2E2f_passthrough", NULL);
+			fprintf(stderr, "CG> Compiling Fragment [shaders/fragment30.cg] ....\n");
+		}
+
+		if (!cgIsProgramCompiled(fragmentProgram))
+			cgCompileProgram(fragmentProgram);
+		fprintf(stderr, "CG> \t done\n");
+		cgGLLoadProgram(fragmentProgram);
+
+		hTexture0 = cgGetNamedParameter(fragmentProgram, "texture0");
+		hTexture1 = cgGetNamedParameter(fragmentProgram, "texture1");
+
+		return 1;
+
+}
+
+void enableCG(unsigned int volTex) {
+	cgGLBindProgram(fragmentProgram);
+	cgGLEnableProfile(fprofile);
+
+	cgGLSetTextureParameter(hTexture0, global.volume->texName);
+	cgGLSetTextureParameter(hTexture1, curTexId);
+
+	cgGLEnableTextureParameter(hTexture0);
+	cgGLEnableTextureParameter(hTexture1);
+}
+
+void setCurTextureCG(int texName) {
+	curTexId = texName;
+}
+
+void disableCG() {
+	cgGLDisableProfile(vprofile);
+	cgGLDisableProfile(fprofile);
+	cgGLDisableTextureParameter(hTexture0);
+	cgGLDisableTextureParameter(hTexture1);
+}
+
+void exitCG() {
+//	cgDestroyProgram(vertexProgram);
+	cgDestroyProgram(fragmentProgram);
+	cgDestroyContext(context);
+}
+
+#endif
Index: trunk/src/testing/app/volvis/vGeometry.cpp
===================================================================
--- trunk/src/testing/app/volvis/vGeometry.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vGeometry.cpp	(revision 4)
@@ -0,0 +1,274 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include "global.h"
+#include "vGeometry.h"
+#include "VectorMath.h"    //usefull vector/matrix operations
+#include "MatrixMath.h"
+
+
+static float geomColor[6][4] = {{0.5f,0.0f,1.0f,1.0f},
+			{0.0f,0.5f,1.0f,1.0f},
+			{0.0f,1.0f,0.5f,1.0f},
+			{1.0f,0.5f,0.0f,1.0f},
+			{1.0f,0.0f,0.5f,1.0f},
+			{0.5f,0.0f,1.0f,1.0f}};
+static float geomAxes[6][3] = {{0.0,1.0,1.0},
+			{1.0,1.0,0.0},
+			{1.0,0.0,1.0},
+			{0.5,0.0,1.0},
+			{1.0,0.0,0.5},
+			{1.0,0.5,0.0}};
+static int geomIdx = 0;
+//only one geometry in this case
+vGeometry::vGeometry(NetVertexBuffer* vb) :vPrimitive() {
+    opClient = NULL;
+	indexList = 0;
+	curFrame = 0;
+	initScale = 1.0f;
+	NetVertexBuffer* tmp = (NetVertexBuffer* )malloc(sizeof(NetVertexBuffer));
+	tmp->copy(vb);
+	cache.push_back(tmp);
+	numFrames = 1;
+	color[0] = geomColor[geomIdx][0];
+	color[1] = geomColor[geomIdx][1];
+	color[2] = geomColor[geomIdx][2];
+	color[3] = geomColor[geomIdx][3];
+	axes[0] = geomAxes[geomIdx][0];
+	axes[1] = geomAxes[geomIdx][1];
+	axes[2] = geomAxes[geomIdx][2];
+	angle = 0.0f;
+	geomIdx ++;
+	geomIdx = geomIdx%6;
+	//pb = 0;
+}
+
+//may have an animation of geometry
+vGeometry::vGeometry(char* wildcard, char* serverName, float scale = 1.0f)
+{
+    opClient = new cDataManagerClient((char*)serverName);
+    fprintf(stderr,"vGeometry::vGeometry %s \n",wildcard);
+    opClient->Open();
+    opClient->Init();
+    int num_datasets = opClient->Query();
+
+	indexList = 0;
+	numFrames= opClient->GetMatching(wildcard,indexList);
+	if (!numFrames) {
+		fprintf(stderr,"ERROR: Cant find any geometry matching %s in Optistore\n",wildcard);
+		exit(1);
+	}
+	fprintf(stderr,"Number of frames %d\n",numFrames);
+	cache.resize(numFrames,NULL); //initialise the cache with null
+	curFrame = 0;
+	initScale = scale;
+	color[0] = geomColor[geomIdx][0];
+	color[1] = geomColor[geomIdx][1];
+	color[2] = geomColor[geomIdx][2];
+	color[3] = geomColor[geomIdx][3];
+	axes[0] = geomAxes[geomIdx][0];
+	axes[1] = geomAxes[geomIdx][1];
+	axes[2] = geomAxes[geomIdx][2];
+	angle = 0.0f;
+	geomIdx ++;
+	geomIdx = geomIdx%6;
+
+	//pb = 0;
+}
+
+
+
+vGeometry::~vGeometry() {
+	fprintf(stderr,"~vGeometry() after opClient->Exit()\n");
+	if (numFrames) {
+		for (int i=0;i<numFrames;i++) {
+			if (cache[i]) {
+				cache[i]->freeArrays();
+				free(cache[i]);
+			}
+		}
+	}
+	if (indexList)
+		free(indexList);
+    if (opClient)
+        opClient->Exit();
+
+	/*if (pb) {
+		free(pb->vertex);
+		free(pb);
+	}
+	*/
+
+}
+
+//checks if the curframe is loaded, if not grabs it from the server
+void vGeometry::setCurFrame(int curFrame) {
+	if (cache[curFrame] == NULL) {//get file from server
+		opClient->Load(indexList[curFrame]);//get the index of this frame
+		NetVertexBuffer* vb = opClient->Isosurface(1, 1, 0.20); // fake values
+		cache[curFrame] = (NetVertexBuffer* )malloc(sizeof(NetVertexBuffer));
+		cache[curFrame]->copy(vb);
+	}
+
+}
+//get the first geometry if its animation
+void vGeometry::init() {
+	fprintf(stderr,"Loading cur frame %d index %d\n",curFrame, indexList[curFrame]);
+	setCurFrame(0);
+}
+
+void vGeometry::next() {
+	curFrame++;
+	fprintf(stderr,"next frame %d\n",curFrame);
+	if (curFrame >= numFrames)
+		curFrame = 0;
+	setCurFrame(curFrame);
+}
+
+void vGeometry::prev() {
+	curFrame--;
+	if (curFrame < 0)
+		curFrame = numFrames-1;
+	setCurFrame(curFrame);
+}
+
+void vGeometry::drawBoundBox() {
+	glDisable(GL_LIGHTING);
+	glPushMatrix();
+	glTranslatef(-0.5f,-0.5f,-0.5f);
+	glBegin(GL_LINES);
+		glColor3f(0.0f,0.5f,0.5f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+		glVertex3f(1.0f,1.0f,1.0f);
+		glVertex3f(0.0f,1.0f,1.0f);
+		glVertex3f(1.0f,1.0f,0.0f);
+		glVertex3f(0.0f,1.0f,0.0f);
+		glVertex3f(1.0f,0.0f,1.0f);
+		glVertex3f(0.0f,0.0f,1.0f);
+		glVertex3f(1.0f,0.0f,0.0f);
+		glVertex3f(0.0f,0.0f,0.0f);
+	glEnd();
+	glPopMatrix();
+	glEnable(GL_LIGHTING);
+}
+
+//draws the triangele strip here
+void vGeometry::draw()
+{
+	int i,l;
+	glPushMatrix();
+	glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glTranslatef(xform.trans[0], xform.trans[1], xform.trans[2]);
+	glMultMatrixf(xform.rotn);
+	glScalef(xform.scale, xform.scale,xform.scale);
+	if (selected)
+		drawBoundBox();
+	glTranslatef(-0.5,-0.5,-0.5);
+	glScalef(initScale, initScale,initScale);
+	glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
+	if (cache[curFrame]) {
+		glEnable(GL_NORMALIZE);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glVertexPointer(3,GL_FLOAT,0, cache[curFrame]->vertex);
+
+		//glEnableClientState(GL_COLOR_ARRAY);
+		//glColorPointer(4,GL_UNSIGNED_BYTE,0,(void* )((GLubyte* )diffuse));
+		glDisableClientState(GL_COLOR_ARRAY);
+
+		glEnableClientState(GL_NORMAL_ARRAY);
+		glNormalPointer(GL_FLOAT,0, cache[curFrame]->normal);
+		//glDisableClientState(GL_NORMAL_ARRAY);
+
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+		//glPolygonMode(GL_FRONT, GL_LINE);
+		//glPolygonMode(GL_BACK, GL_LINE);
+
+		for(i = 0,l = 0; i < cache[curFrame]->lengths; l += cache[curFrame]->length[i],i++)
+		{
+		    glDrawElements(GL_TRIANGLE_STRIP,
+                           cache[curFrame]->length[i],GL_UNSIGNED_INT,&(((GLuint* )cache[curFrame]->index)[l]));
+		}
+
+		glDisable(GL_NORMAL_ARRAY);
+		//glDisable(GL_VERTEX_ARRAY);
+	}
+	/*
+	if (pb) {
+		glBegin(GL_POINTS); // draw some points
+		for (int i=0;i<pb->nbpts;i++)
+			glVertex3f(pb->vertex[i*3+0],pb->vertex[i*3+1],pb->vertex[i*3+2]);
+		glEnd();
+	}
+	*/
+	glPopAttrib();
+	glPopMatrix();
+	return;
+}
+
+//for the pointer
+/*
+float geomVertexList[8][3] = {{0,0,0},{1.0f,0,0},{0,1.0f,0},{1.0f,1.0f,0},{0,0,1.0f},{1.0f,0,1.0f},{0,1.0f,1.0f},{1.0f,1.0f,1.0f}};
+int vGeometry::select() {
+	if (withinBounds3D(mv,geomVertexList,global.pointerPos)) {
+		selected = 1;
+	}
+	else
+		selected = 0;
+	return selected;
+}
+*/
+
+/*
+vGeometry::vGeometry(NetPointBuffer* thePoints) :vPrimitive() {
+	pb = (NetPointBuffer* )malloc(sizeof(NetPointBuffer));
+	pb->nbpts = thePoints->nbpts;
+	pb->vertex = (float* )malloc(sizeof(float)*pb->nbpts*3);
+	numFrames = curFrame = 0;
+}
+*/
Index: trunk/src/testing/app/volvis/VectorMath.h
===================================================================
--- trunk/src/testing/app/volvis/VectorMath.h	(revision 4)
+++ trunk/src/testing/app/volvis/VectorMath.h	(revision 4)
@@ -0,0 +1,671 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+
+#ifndef __VectorMath_defined
+#define __VectorMath_defined
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+
+#include <math.h>
+#include <stdio.h>
+#include <iostream>
+#include <limits.h>
+#define EPSILON 2e-07
+#define V_PI    3.1415926535897932384626433832795
+
+#if 0 //matrix representation for mat[16], same as OpenGl matrix rep
+
++-          -+
+|0  4  8   12|
+|1  5  9   13|
+|2  6  10  14|
+|3  7  11  15|
++-          -+
+
+#endif
+
+/*
+******** NRRD_AFFINE(i,x,I,o,O)
+**
+** given intervals [i,I], [o,O] and a value x which may or may not be
+** inside [i,I], return the value y such that y stands in the same
+** relationship to [o,O] that x does with [i,I].  Or:
+**
+**    y - o         x - i
+**   -------   =   -------
+**    O - o         I - i
+**
+** It is the callers responsibility to make sure I-i and O-o are
+** both greater than zero
+*/
+
+#define CLAMP(x) ((((x)>0) ? (((x)<1) ? x : 1) : 0))
+#define MAX(x,y) (((x)>(y)) ? (x) : (y))
+#define MIN(x,y) (((x)<(y)) ? (x) : (y))
+#define ABS(x) ((x)<0 ? (-x) : (x))
+#define NOTPOW2(num) ((num) & (num - 1))
+
+inline double CLAMP_ARB(const double c, const double x, const double C)
+{
+	return ((((x)>c) ? (((x)<(C)) ? x : (C)) : c));
+}
+
+inline double affine(const double i, const double x, const double I,
+					 const double o, const double O)
+{
+	return  ( ((O)-(o))*((x)-(i)) / ((I)-(i)) + (o) );
+}
+
+// make a vector all zeros -----------------------------------------
+inline void zeroV3(GLfloat* in)
+{
+	in[0] = in[1] = in[2] = 0;
+}
+
+inline void setV3(GLfloat* v, float x, float y, float z)
+{
+  v[0] = x;
+  v[1] = y;
+  v[2] = z;
+}
+
+// negate all components of a vector -------------------------------
+inline void negateV3(GLfloat* in)
+{
+	in[0] = -in[0];
+	in[1] = -in[1];
+	in[2] = -in[2];
+}
+
+
+// copy vector 'out' = 'in';---------------------------------------
+inline void copyV3(GLfloat* out, GLfloat* in)
+{
+	out[0] = in[0];
+	out[1] = in[1];
+	out[2] = in[2];
+}
+
+inline void copyV3(GLfloat* out, GLdouble* in)
+{
+	out[0] = (float)in[0];
+	out[1] = (float)in[1];
+	out[2] = (float)in[2];
+}
+
+inline void copyV3(GLdouble* out, GLfloat* in)
+{
+	out[0] = in[0];
+	out[1] = in[1];
+	out[2] = in[2];
+}
+
+// out = inl - inr -----------------------------------------------
+inline void subV3(GLfloat* out, GLfloat* inl, GLfloat* inr)
+{
+	out[0] = inl[0] - inr[0];
+	out[1] = inl[1] - inr[1];
+	out[2] = inl[2] - inr[2];
+}
+
+inline void subV3(GLdouble* out, GLdouble* inl, GLdouble* inr)
+{
+	out[0] = inl[0] - inr[0];
+	out[1] = inl[1] - inr[1];
+	out[2] = inl[2] - inr[2];
+}
+
+// out = inl + inr ---------------------------------------------
+inline void addV3(GLfloat *out, GLfloat inl[3], GLfloat inr[3])
+{
+	out[0] = inl[0] + inr[0];
+	out[1] = inl[1] + inr[1];
+	out[2] = inl[2] + inr[2];
+}
+
+inline void addV3(GLdouble *out, GLdouble inl[3], GLdouble inr[3])
+{
+	out[0] = inl[0] + inr[0];
+	out[1] = inl[1] + inr[1];
+	out[2] = inl[2] + inr[2];
+}
+
+// one *= s --------------------------------------------------
+inline void scaleV3(float s, GLfloat *one)
+{
+	one[0] *= s;
+	one[1] *= s;
+	one[2] *= s;
+}
+
+inline void scaleV3(double s, GLdouble *one)
+{
+	one[0] *= s;
+	one[1] *= s;
+	one[2] *= s;
+}
+
+// out = in * s --------------------------------------------
+inline void cscaleV3(GLfloat *out, float s, GLfloat in[3])
+{
+	out[0] = s*in[0];
+	out[1] = s*in[1];
+	out[2] = s*in[2];
+}
+
+inline void cscaleV3(GLdouble *out, double s, GLdouble in[3])
+{
+	out[0] = s*in[0];
+	out[1] = s*in[1];
+	out[2] = s*in[2];
+}
+
+// set a matrix 'm' to the identity -----------------------
+inline void identityMatrix(GLfloat m[16])
+{
+	m[0]=1; m[4]=0; m[8]= 0; m[12]=0;
+	m[1]=0; m[5]=1; m[9]= 0; m[13]=0;
+	m[2]=0; m[6]=0; m[10]=1; m[14]=0;
+	m[3]=0; m[7]=0; m[11]=0; m[15]=1;
+}
+
+inline void identityMatrix(GLdouble m[16])
+{
+	m[0]=1; m[4]=0; m[8]= 0; m[12]=0;
+	m[1]=0; m[5]=1; m[9]= 0; m[13]=0;
+	m[2]=0; m[6]=0; m[10]=1; m[14]=0;
+	m[3]=0; m[7]=0; m[11]=0; m[15]=1;
+}
+
+// vector matrix multiplication [4] vector ----------------------
+// out = mat * in
+inline void translateV4(GLfloat out[4], GLfloat mat[16], GLfloat in[4])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12]*in[3];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13]*in[3];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14]*in[3];
+	out[3] = mat[3]*in[0] + mat[7]*in[1] + mat[11]*in[2] + mat[15]*in[3];
+}
+
+//3 vector with implict w=1 mult matrix to 4 vector
+inline void translateV4_3W(GLfloat out[4], GLfloat mat[16], GLfloat in[3])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14];
+	out[3] = mat[3]*in[0] + mat[7]*in[1] + mat[11]*in[2] + mat[15];
+}
+
+inline void translateV4(GLdouble out[4], GLdouble mat[16], GLdouble in[4])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12]*in[3];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13]*in[3];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14]*in[3];
+	out[3] = mat[3]*in[0] + mat[7]*in[1] + mat[11]*in[2] + mat[15]*in[3];
+}
+
+// vector matrix multiplicaiton [3] vector with no translation ---
+// (only rotation) out = mat * in;
+inline void translateV3(GLfloat *out, GLfloat mat[16], GLfloat in[3])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2];// + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2];// + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2];// + mat[14];
+}
+
+inline void translateV3(GLdouble *out, GLdouble mat[16], GLdouble in[3])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2];// + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2];// + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2];// + mat[14];
+}
+
+inline void translateV3(GLfloat *out, GLdouble mat[16], GLfloat in[3])
+{
+	out[0] = (float)(mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2]);// + mat[12];
+	out[1] = (float)(mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2]);// + mat[13];
+	out[2] = (float)(mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2]);// + mat[14];
+}
+
+// [3] vector * matrix --------------------------------------------
+// out = mat * in (with translation)
+inline void translateV3W(GLfloat *out, GLfloat mat[16], GLfloat in[3])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14];
+}
+
+inline void translateV3W(GLfloat *out, GLdouble mat[16], GLfloat in[3])
+{
+	out[0] = (float)(mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12]);
+	out[1] = (float)(mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13]);
+	out[2] = (float)(mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14]);
+}
+
+inline void translateV3W(GLdouble *out, GLdouble mat[16], GLdouble in[3])
+{
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14];
+}
+
+//transformation of 3 vector with implicit w=1 and homoginization
+inline void translateV3WD(GLfloat *out, GLfloat mat[16], GLfloat in[3])
+{
+	out[0] = (float)(mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12]);
+	out[1] = (float)(mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13]);
+	out[2] = (float)(mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14]);
+	float w= (float)(mat[3]*in[0] + mat[7]*in[1] + mat[11]*in[2] + mat[15]);
+	out[0]/=w;
+	out[1]/=w;
+	out[2]/=w;
+}
+
+// legacy call
+inline void transMatrixV3(GLfloat *out, GLfloat mat[16], GLfloat in[3])
+{
+
+	out[0] = mat[0]*in[0] + mat[4]*in[1] + mat[8]* in[2] + mat[12];
+	out[1] = mat[1]*in[0] + mat[5]*in[1] + mat[9]* in[2] + mat[13];
+	out[2] = mat[2]*in[0] + mat[6]*in[1] + mat[10]*in[2] + mat[14];
+}
+
+// dot product of two [4] vecotrs --------------------------
+inline GLfloat dotV4(GLfloat one[4], GLfloat two[4])
+{
+	return one[0]*two[0] + one[1]*two[1] + one[2]*two[2] + one[3]*two[3];
+}
+
+inline GLdouble dotV4(GLdouble one[4], GLdouble two[4])
+{
+	return one[0]*two[0] + one[1]*two[1] + one[2]*two[2] + one[3]*two[3];
+}
+
+// dot product of two [3] vectors ------------------------
+inline GLfloat dotV3(GLfloat one[4], GLfloat two[4])
+{
+	return one[0]*two[0] + one[1]*two[1] + one[2]*two[2];
+}
+
+inline GLdouble dotV3(GLdouble one[4], GLdouble two[4])
+{
+	return one[0]*two[0] + one[1]*two[1] + one[2]*two[2];
+}
+
+// compute the length of a [3] vector --------------------
+inline GLfloat normV3(GLfloat *one)
+{
+	return (GLfloat)sqrt( one[0]*one[0] + one[1]*one[1] + one[2]*one[2]);
+}
+
+inline GLdouble normV3(GLdouble *one)
+{
+	return sqrt( one[0]*one[0] + one[1]*one[1] + one[2]*one[2]);
+}
+
+// normalize a [4] vector --------------------------------
+inline void normalizeV4(GLfloat v[4])
+{
+	GLfloat len = (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]);
+	if(len > 0){
+		v[0] /= len;
+		v[1] /= len;
+		v[2] /= len;
+		v[3] /= len;
+	}
+}
+
+inline void normalizeV4(GLdouble v[4])
+{
+	GLfloat len = (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]);
+	if(len > 0){
+		v[0] /= len;
+		v[1] /= len;
+		v[2] /= len;
+		v[3] /= len;
+	}
+}
+
+// normalize a [3] vector ---------------------------------
+inline void normalizeV3(GLfloat v[3])
+{
+	GLfloat len = (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+	if(len > 0){
+		v[0] /= len;
+		v[1] /= len;
+		v[2] /= len;
+	}
+}
+
+inline void normalizeV3(GLdouble v[3])
+{
+	GLfloat len = (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+	if(len > 0){
+		v[0] /= len;
+		v[1] /= len;
+		v[2] /= len;
+	}
+}
+
+// divide out the 'W' part of a [4] vector ----------------
+inline void homogV4(GLfloat v[4])
+{
+	v[0] /= v[3];
+	v[1] /= v[3];
+	v[2] /= v[3];
+	v[3] = 1;
+}
+
+inline void homogV4(GLdouble v[4])
+{
+	v[0] /= v[3];
+	v[1] /= v[3];
+	v[2] /= v[3];
+	v[3] = 1;
+}
+
+// compute cross product of [3] vector -------------------
+// out = one X two;
+inline void crossV3(GLfloat *out, GLfloat *one, GLfloat *two)
+{
+	out[0] = one[1]*two[2] - one[2]*two[1];
+	out[1] = one[2]*two[0] - one[0]*two[2];
+	out[2] = one[0]*two[1] - one[1]*two[0];
+}
+
+inline void crossV3(GLdouble *out, GLdouble *one, GLdouble *two)
+{
+	out[0] = one[1]*two[2] - one[2]*two[1];
+	out[1] = one[2]*two[0] - one[0]*two[2];
+	out[2] = one[0]*two[1] - one[1]*two[0];
+}
+
+
+//returns 2^n such that 2^n < number < 2^(n+1)
+inline int makepow2_max(int val) {
+    if (NOTPOW2(val)) {
+		int power = 0;
+		if(!val)
+			return 0;
+		while(val >>= 1)
+			power++;
+		return(1 << (power+1));
+	}
+	else
+		return val;
+}
+
+//returns 2^n such that 2^n < number < 2^(n+1)
+inline int makepow2_min(int val) {
+    if (NOTPOW2(val)) {
+		int power = 0;
+		if(!val)
+			return 0;
+		while(val >>= 1)
+			power++;
+		return(1 << power);
+	}
+	else
+		return val;
+}
+
+
+
+inline void printV3(double v[3])
+{
+	std::cerr << " " << v[0] << "," << v[1] << "," << v[2];
+}
+
+inline void printV3(float v[3])
+{
+	std::cerr << " " << v[0] << "," << v[1] << "," << v[2];
+}
+
+inline void printV4(float v[3])
+{
+	std::cerr << " " << v[0] << "," << v[1] << "," << v[2] << "," << v[3];
+}
+
+
+
+//=====================================================================================
+//---------------------- Quantize -----------------------------------------------------
+//=====================================================================================
+
+inline
+void quantize(unsigned char *dout, int sx, int sy, int sz, unsigned short *din){
+
+	unsigned short max = 0;
+	unsigned short min = USHRT_MAX;
+    int i, j, k;
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				max = MAX(max, din[i*sx*sy + j*sx + k]);
+				min = MIN(min, din[i*sx*sy + j*sx + k]);
+
+			}
+		}
+	}
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				dout[i*sx*sy + j*sx + k] = (unsigned char)affine(min,din[i*sx*sy + j*sx + k], max, 0, 255);
+			}
+		}
+	}
+}
+
+inline
+void quantize(unsigned char *dout, int sx, int sy, int sz, short *din){
+
+	short max = SHRT_MIN;
+	short min = SHRT_MAX;
+    int i, j, k;
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				max = MAX(max, din[i*sx*sy + j*sx + k]);
+				min = MIN(min, din[i*sx*sy + j*sx + k]);
+
+			}
+		}
+	}
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				dout[i*sx*sy + j*sx + k] = (unsigned char)affine(min,din[i*sx*sy + j*sx + k], max, 0, 255);
+			}
+		}
+	}
+}
+
+inline
+void quantize(unsigned char *dout, int sx, int sy, int sz, int *din){
+
+    int i, j, k;
+	int max = INT_MIN;
+	int min = INT_MAX;
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				max = MAX(max, din[i*sx*sy + j*sx + k]);
+				min = MIN(min, din[i*sx*sy + j*sx + k]);
+
+			}
+		}
+	}
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				dout[i*sx*sy + j*sx + k] = (unsigned char)affine(min,din[i*sx*sy + j*sx + k], max, 0, 255);
+			}
+		}
+	}
+}
+
+inline
+void quantize(unsigned char *dout, int sx, int sy, int sz, unsigned int *din){
+
+	unsigned int max = 0;
+	unsigned int min = UINT_MAX;
+    int i, j, k;
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				max = MAX(max, din[i*sx*sy + j*sx + k]);
+				min = MIN(min, din[i*sx*sy + j*sx + k]);
+
+			}
+		}
+	}
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				dout[i*sx*sy + j*sx + k] = (unsigned char)affine(min,din[i*sx*sy + j*sx + k], max, 0, 255);
+			}
+		}
+	}
+}
+
+inline
+void quantize(unsigned char *dout, int sx, int sy, int sz, float *din)
+{
+	float max = -10000000000.0;
+	float min = 10000000000.0;
+    int i, j, k;
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				max = MAX(max, din[i*sx*sy + j*sx + k]);
+				min = MIN(min, din[i*sx*sy + j*sx + k]);
+			}
+		}
+	}
+	for(i = 0; i<sz; ++i){
+		for(j = 0; j<sy; ++j){
+			for(k = 0; k<sx; ++k){
+				dout[i*sx*sy + j*sx + k] = (unsigned char)affine(min, din[i*sx*sy + j*sx + k], max, 0, 255);
+			}
+		}
+	}
+}
+
+//for trackball
+inline void vZero(float *v)
+{
+  v[0] = 0.0;
+  v[1] = 0.0;
+  v[2] = 0.0;
+}
+
+inline void vSet(float *v, float x, float y, float z)
+{
+  v[0] = x;
+  v[1] = y;
+  v[2] = z;
+}
+
+inline void vSub(const float *src1, const float *src2, float *dst)
+{
+  dst[0] = src1[0] - src2[0];
+  dst[1] = src1[1] - src2[1];
+  dst[2] = src1[2] - src2[2];
+}
+
+inline void vCopy(const float *v1, float *v2)
+{
+  for (int i = 0 ; i < 3 ; i++)
+    v2[i] = v1[i];
+}
+
+inline void vCross(const float *v1, const float *v2, float *cross)
+{
+  float temp[3];
+
+  temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+  temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+  temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+  vCopy(temp, cross);
+}
+
+inline float vLength(const float *v)
+{
+  return (float)(sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
+}
+
+inline void vScale(float *v, float div)
+{
+  v[0] *= div;
+  v[1] *= div;
+  v[2] *= div;
+}
+
+inline void vNormal(float *v)
+{
+  vScale(v,(float)(1.0/vLength(v)));
+}
+
+inline float vDot(const float *v1, const float *v2)
+{
+  return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+inline void vAdd(const float *src1, const float *src2, float *dst)
+{
+  dst[0] = src1[0] + src2[0];
+  dst[1] = src1[1] + src2[1];
+  dst[2] = src1[2] + src2[2];
+}
+
+#endif
+
+
+
+
+
+
+
+
Index: trunk/src/testing/app/volvis/vFPSText.cpp
===================================================================
--- trunk/src/testing/app/volvis/vFPSText.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vFPSText.cpp	(revision 4)
@@ -0,0 +1,174 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#include <stdio.h>
+#include "vFPSText.h"
+#include "global.h"
+GLvoid
+  renderBitmapString( char *string )
+  {
+      int i;
+      int len = (int) strlen(string);
+      for (i = 0; i < len; i++) {
+          glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);
+      }
+  }
+
+  GLvoid
+  renderStrokeString( void *font, char *string )
+  {
+      int i;
+      int len = (int) strlen(string);
+      for (i = 0; i < len; i++) {
+          glutStrokeCharacter(font, string[i]);
+      }
+  }
+
+CFrameTimer::CFrameTimer() {
+  #ifdef WIN32
+	LARGE_INTEGER num;
+	//get current performance-counter frequency, in counts per second
+	QueryPerformanceFrequency(&num);
+	timerResolution = (double)num.HighPart*4294967296.0;
+	timerResolution += (double)num.LowPart;
+	timerResolution=1.0/timerResolution; //get time for 1 count
+	QueryPerformanceCounter(&last); //store current counter as last
+
+  #endif
+
+#if defined(linux) || defined(__APPLE__)
+	//struct timeval _tstart;
+	//struct timezone tz;
+	gettimeofday(&_tstart, &tz);
+#endif
+
+	elapsedTime=0.0;
+	frameLocation=0;
+	framesProcessed=0;
+
+}
+
+void CFrameTimer::pingFrameCounter(){
+#ifdef WIN32
+	LARGE_INTEGER t;
+	double elapsed;
+
+	QueryPerformanceCounter(&t); //get current counter
+	//get elapsed = current counter - last counter
+	elapsed=((double)t.HighPart-(double)last.HighPart)*4294967296.0;
+	elapsed+=(double)t.LowPart-(double)last.LowPart;
+	elapsed *= timerResolution;
+	//update last counter
+	last.HighPart=t.HighPart;
+	last.LowPart=t.LowPart;
+#endif
+
+#if defined(linux) || defined(__APPLE__)
+	struct timeval _tend;
+	gettimeofday(&_tend,&tz);
+	double t1, t2;
+	t1 =  (double)_tstart.tv_sec + (double)_tstart.tv_usec/(1000*1000);
+	t2 =  (double)_tend.tv_sec + (double)_tend.tv_usec/(1000*1000);
+	//return t2-t1;
+	double elapsed;
+	elapsed = t2 - t1;
+	_tstart = _tend;
+#endif
+
+	frameTimes[frameLocation]= elapsed; //store elapsed
+	elapsedTime += frameTimes[frameLocation]; //add to the total elapsed time
+	frameLocation = (frameLocation+1)%FRAME_HISTORY; //next index
+	framesProcessed++;
+}
+
+float CFrameTimer::getFPS(){
+	int top=(FRAME_HISTORY>framesProcessed)?framesProcessed:FRAME_HISTORY;
+
+	double total=0.0f;
+	for(int ii=0;ii<top;ii++)
+		total+=frameTimes[ii];
+	total/=(float)FRAME_HISTORY; //no of secs per frame
+	total=1.0f/total; //get fps
+	return (float)total;
+}
+
+vText::vText(const char* txt) : vPrimitive() {
+	strcpy(myText,txt);
+}
+
+void vText::init() {
+}
+
+void vText::draw() {
+	glPushMatrix();
+	glRasterPos3f(xform.trans[0],xform.trans[1],xform.trans[2]);
+	if (selected)
+		glColor3f(0.0f,0.5f,0.5f);
+	else
+		glColor3f(1.0f,1.0f,1.0f);
+	//glScalef(xform.scale,xform.scale,xform.scale);
+	//glScalef(0.5, 0.5, 0.5);
+	//renderStrokeString(myText);
+	renderBitmapString(myText);
+	glPopMatrix();
+}
+
+void vFPSText::init() {
+	xform.trans[0] = -6.0f;
+	xform.trans[1] = -5.0f;
+	xform.trans[2] = 0.0f;
+	vText::init();
+	timer = new CFrameTimer();
+}
+
+void vFPSText::draw() {
+	timer->pingFrameCounter();
+	if (global.ui.printFPS) {
+		sprintf(myText,"FPS %f",timer->getFPS());
+		vText::draw();
+	}
+}
+
+void vVolText::init() {
+	xform.trans[0] = 1.0f;
+	xform.trans[1] = -3.0f;
+	xform.trans[2] = 0.0f;
+	vText::init();
+}
+
+void vVolText::draw() {
+	sprintf(myText,"(X,Y,Z):(%d,%d,%d) Vox:%d",global.volume->probeX, global.volume->probeY,
+			global.volume->probeZ, global.volume->probeValue);
+	vText::draw();
+}
Index: trunk/src/testing/app/volvis/MatrixMath.h
===================================================================
--- trunk/src/testing/app/volvis/MatrixMath.h	(revision 4)
+++ trunk/src/testing/app/volvis/MatrixMath.h	(revision 4)
@@ -0,0 +1,618 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+#ifndef __MatrixMath_defined
+#define __MatrixMath_defined
+#include "VectorMath.h"
+
+//BAD SHALINI...dont assume Opengl - do this by hand
+inline void computeMatrix(float angle, float axis[],GLdouble* mat) {
+	// Have OpenGL compute the new transformation (simple but slow)
+	glPushMatrix();
+	glLoadIdentity();
+	glRotatef(angle, axis[0], axis[1], axis[2]);
+	glMultMatrixd((GLdouble *) mat);
+	glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble *) mat);
+	glPopMatrix();
+}
+
+inline void computeMatrix(float angle, float axis[],GLfloat* mat) {
+	// Have OpenGL compute the new transformation (simple but slow)
+	glPushMatrix();
+	glLoadIdentity();
+	glRotatef(angle, axis[0], axis[1], axis[2]);
+	glMultMatrixf((GLfloat *) mat);
+	glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) mat);
+	glPopMatrix();
+}
+
+
+// copy two matricies -----------------------------------
+inline void matrixEqual(GLfloat me[16], GLfloat m[16])
+{
+	for(int i=0; i< 16; ++i) me[i] = m[i];
+}
+
+inline void matrixEqual(GLdouble me[16], GLdouble m[16])
+{
+	for(int i=0; i< 16; ++i) me[i] = m[i];
+}
+
+// maxb = ma * mb --------------------------------------
+inline void matrixMult( GLfloat maxb[16], GLfloat ma[16], GLfloat mb[16] )
+{
+	maxb[0] = ma[0]*mb[0] + ma[4]*mb[1] + ma[8]*mb[2] + ma[12]*mb[3];
+	maxb[1] = ma[1]*mb[0] + ma[5]*mb[1] + ma[9]*mb[2] + ma[13]*mb[3];
+	maxb[2] = ma[2]*mb[0] + ma[6]*mb[1] + ma[10]*mb[2] + ma[14]*mb[3];
+	maxb[3] = ma[3]*mb[0] + ma[7]*mb[1] + ma[11]*mb[2] + ma[15]*mb[3];
+
+	maxb[4] = ma[0]*mb[4] + ma[4]*mb[5] + ma[8]*mb[6] + ma[12]*mb[7];
+	maxb[5] = ma[1]*mb[4] + ma[5]*mb[5] + ma[9]*mb[6] + ma[13]*mb[7];
+	maxb[6] = ma[2]*mb[4] + ma[6]*mb[5] + ma[10]*mb[6] + ma[14]*mb[7];
+	maxb[7] = ma[3]*mb[4] + ma[7]*mb[5] + ma[11]*mb[6] + ma[15]*mb[7];
+
+	maxb[8] = ma[0]*mb[8] + ma[4]*mb[9] + ma[8]*mb[10] + ma[12]*mb[11];
+	maxb[9] = ma[1]*mb[8] + ma[5]*mb[9] + ma[9]*mb[10] + ma[13]*mb[11];
+	maxb[10] = ma[2]*mb[8] + ma[6]*mb[9] + ma[10]*mb[10] + ma[14]*mb[11];
+	maxb[11] = ma[3]*mb[8] + ma[7]*mb[9] + ma[11]*mb[10] + ma[15]*mb[11];
+
+	maxb[12] = ma[0]*mb[12] + ma[4]*mb[13] + ma[8]*mb[14] + ma[12]*mb[15];
+	maxb[13] = ma[1]*mb[12] + ma[5]*mb[13] + ma[9]*mb[14] + ma[13]*mb[15];
+	maxb[14] = ma[2]*mb[12] + ma[6]*mb[13] + ma[10]*mb[14] + ma[14]*mb[15];
+	maxb[15] = ma[3]*mb[12] + ma[7]*mb[13] + ma[11]*mb[14] + ma[15]*mb[15];
+}
+
+inline void matrixMult( GLdouble maxb[16], GLdouble ma[16], GLdouble mb[16] )
+{
+	maxb[0] = ma[0]*mb[0] + ma[4]*mb[1] + ma[8]*mb[2] + ma[12]*mb[3];
+	maxb[1] = ma[1]*mb[0] + ma[5]*mb[1] + ma[9]*mb[2] + ma[13]*mb[3];
+	maxb[2] = ma[2]*mb[0] + ma[6]*mb[1] + ma[10]*mb[2] + ma[14]*mb[3];
+	maxb[3] = ma[3]*mb[0] + ma[7]*mb[1] + ma[11]*mb[2] + ma[15]*mb[3];
+
+	maxb[4] = ma[0]*mb[4] + ma[4]*mb[5] + ma[8]*mb[6] + ma[12]*mb[7];
+	maxb[5] = ma[1]*mb[4] + ma[5]*mb[5] + ma[9]*mb[6] + ma[13]*mb[7];
+	maxb[6] = ma[2]*mb[4] + ma[6]*mb[5] + ma[10]*mb[6] + ma[14]*mb[7];
+	maxb[7] = ma[3]*mb[4] + ma[7]*mb[5] + ma[11]*mb[6] + ma[15]*mb[7];
+
+	maxb[8] = ma[0]*mb[8] + ma[4]*mb[9] + ma[8]*mb[10] + ma[12]*mb[11];
+	maxb[9] = ma[1]*mb[8] + ma[5]*mb[9] + ma[9]*mb[10] + ma[13]*mb[11];
+	maxb[10] = ma[2]*mb[8] + ma[6]*mb[9] + ma[10]*mb[10] + ma[14]*mb[11];
+	maxb[11] = ma[3]*mb[8] + ma[7]*mb[9] + ma[11]*mb[10] + ma[15]*mb[11];
+
+	maxb[12] = ma[0]*mb[12] + ma[4]*mb[13] + ma[8]*mb[14] + ma[12]*mb[15];
+	maxb[13] = ma[1]*mb[12] + ma[5]*mb[13] + ma[9]*mb[14] + ma[13]*mb[15];
+	maxb[14] = ma[2]*mb[12] + ma[6]*mb[13] + ma[10]*mb[14] + ma[14]*mb[15];
+	maxb[15] = ma[3]*mb[12] + ma[7]*mb[13] + ma[11]*mb[14] + ma[15]*mb[15];
+}
+
+// compute the inverse of a matrix
+// invm = m^(-1)
+inline void inverseMatrix( GLfloat invm[16], GLfloat m[16] )
+{
+	GLfloat det =
+		m[0]*m[5]*m[10]-
+		m[0]*m[6]*m[9]-
+		m[1]*m[4]*m[10]+
+		m[1]*m[6]*m[8]+
+		m[2]*m[4]*m[9]-
+		m[2]*m[5]*m[8];
+
+	invm[0] = (m[5]*m[10]-m[6]*m[9])/det;
+	invm[1] = (-m[1]*m[10]+m[2]*m[9])/det;
+	invm[2] = (m[1]*m[6]-m[2]*m[5])/det;
+	invm[3] = 0.0;
+
+	invm[4] = (-m[4]*m[10]+m[6]*m[8])/det;
+	invm[5] = (m[0]*m[10]-m[2]*m[8])/det;
+	invm[6] = (-m[0]*m[6]+m[2]*m[4])/det;
+	invm[7] = 0.0;
+
+	invm[8] = (m[4]*m[9]-m[5]*m[8])/det;
+	invm[9] = (-m[0]*m[9]+m[1]*m[8])/det;
+	invm[10] = (m[0]*m[5]-m[1]*m[4])/det;
+	invm[11] = 0.0;
+
+	invm[12] = (-m[4]*m[9]*m[14]+m[4]*m[13]*m[10]+
+		m[5]*m[8]*m[14]-m[5]*m[12]*m[10]-
+		m[6]*m[8]*m[13]+m[6]*m[12]*m[9])/det;
+	invm[13] = (m[0]*m[9]*m[14]-m[0]*m[13]*m[10]-
+		m[1]*m[8]*m[14]+m[1]*m[12]*m[10]+
+		m[2]*m[8]*m[13]-m[2]*m[12]*m[9])/det;
+	invm[14] = (-m[0]*m[5]*m[14]+m[0]*m[13]*m[6]+
+		m[1]*m[4]*m[14]-m[1]*m[12]*m[6]-
+		m[2]*m[4]*m[13]+m[2]*m[12]*m[5])/det;
+	invm[15] = 1.0;
+}
+
+inline void inverseMatrix( GLdouble invm[16], GLdouble m[16] )
+{
+	GLfloat det = (float)(
+		m[0]*m[5]*m[10]-
+		m[0]*m[6]*m[9]-
+		m[1]*m[4]*m[10]+
+		m[1]*m[6]*m[8]+
+		m[2]*m[4]*m[9]-
+		m[2]*m[5]*m[8]);
+
+	invm[0] = (m[5]*m[10]-m[6]*m[9])/det;
+	invm[1] = (-m[1]*m[10]+m[2]*m[9])/det;
+	invm[2] = (m[1]*m[6]-m[2]*m[5])/det;
+	invm[3] = 0.0;
+
+	invm[4] = (-m[4]*m[10]+m[6]*m[8])/det;
+	invm[5] = (m[0]*m[10]-m[2]*m[8])/det;
+	invm[6] = (-m[0]*m[6]+m[2]*m[4])/det;
+	invm[7] = 0.0;
+
+	invm[8] = (m[4]*m[9]-m[5]*m[8])/det;
+	invm[9] = (-m[0]*m[9]+m[1]*m[8])/det;
+	invm[10] = (m[0]*m[5]-m[1]*m[4])/det;
+	invm[11] = 0.0;
+
+	invm[12] = (-m[4]*m[9]*m[14]+m[4]*m[13]*m[10]+
+		m[5]*m[8]*m[14]-m[5]*m[12]*m[10]-
+		m[6]*m[8]*m[13]+m[6]*m[12]*m[9])/det;
+	invm[13] = (m[0]*m[9]*m[14]-m[0]*m[13]*m[10]-
+		m[1]*m[8]*m[14]+m[1]*m[12]*m[10]+
+		m[2]*m[8]*m[13]-m[2]*m[12]*m[9])/det;
+	invm[14] = (-m[0]*m[5]*m[14]+m[0]*m[13]*m[6]+
+		m[1]*m[4]*m[14]-m[1]*m[12]*m[6]-
+		m[2]*m[4]*m[13]+m[2]*m[12]*m[5])/det;
+	invm[15] = 1.0;
+}
+
+//transpose a matrix
+inline void transposeMatrix(GLfloat m[16])
+{
+	GLfloat tmp;
+	tmp = m[1];
+	m[1] = m[4];
+	m[4] = tmp;
+	tmp = m[2];
+	m[2] = m[8];
+	m[8] = tmp;
+	tmp = m[3];
+	m[3] = m[12];
+	m[12] = tmp;
+	tmp = m[6];
+	m[6] = m[9];
+	m[9] = tmp;
+	tmp = m[7];
+	m[7] = m[13];
+	m[13] = tmp;
+	tmp = m[11];
+	m[11] = m[14];
+	m[14] = tmp;
+
+}
+
+inline void transposeMatrix(GLdouble m[16])
+{
+	GLdouble tmp;
+	tmp = m[1];
+	m[1] = m[4];
+	m[4] = tmp;
+	tmp = m[2];
+	m[2] = m[8];
+	m[8] = tmp;
+	tmp = m[3];
+	m[3] = m[12];
+	m[12] = tmp;
+	tmp = m[6];
+	m[6] = m[9];
+	m[9] = tmp;
+	tmp = m[7];
+	m[7] = m[13];
+	m[13] = tmp;
+	tmp = m[11];
+	m[11] = m[14];
+	m[14] = tmp;
+
+}
+
+//angle and axis to a rotation matrix ----------------------------
+inline void axis2Rot( GLfloat m[16], GLfloat k[3], GLfloat theta )
+{
+	float c = (float)cos(theta);
+	float s = (float)sin(theta);
+	float v = 1 - c;
+
+	m[0] = k[0]*k[0]*v + c;
+	m[4] = k[0]*k[1]*v - k[2]*s;
+	m[8] = k[0]*k[2]*v + k[1]*s;
+
+	m[1] = k[0]*k[1]*v + k[2]*s;
+	m[5] = k[1]*k[1]*v + c;
+	m[9] = k[1]*k[2]*v - k[0]*s;
+
+	m[2] = k[0]*k[2]*v - k[1]*s;
+	m[6] = k[1]*k[2]*v + k[0]*s;
+	m[10] = k[2]*k[2]*v + c;
+}
+
+//angle and axis to a rotation matrix ----------------------------
+inline void axis2Rot( GLdouble m[16], GLfloat k[3], GLfloat theta )
+{
+	float c = (float)cos(theta);
+	float s = (float)sin(theta);
+	float v = 1 - c;
+
+	m[0] = k[0]*k[0]*v + c;
+	m[4] = k[0]*k[1]*v - k[2]*s;
+	m[8] = k[0]*k[2]*v + k[1]*s;
+
+	m[1] = k[0]*k[1]*v + k[2]*s;
+	m[5] = k[1]*k[1]*v + c;
+	m[9] = k[1]*k[2]*v - k[0]*s;
+
+	m[2] = k[0]*k[2]*v - k[1]*s;
+	m[6] = k[1]*k[2]*v + k[0]*s;
+	m[10] = k[2]*k[2]*v + c;
+}
+
+
+inline void axis2Rot( GLdouble m[16], GLdouble k[3], GLdouble theta )
+{
+	float c = (float)cos(theta);
+	float s = (float)sin(theta);
+	float v = 1 - c;
+
+	m[0] = k[0]*k[0]*v + c;
+	m[4] = k[0]*k[1]*v - k[2]*s;
+	m[8] = k[0]*k[2]*v + k[1]*s;
+
+	m[1] = k[0]*k[1]*v + k[2]*s;
+	m[5] = k[1]*k[1]*v + c;
+	m[9] = k[1]*k[2]*v - k[0]*s;
+
+	m[2] = k[0]*k[2]*v - k[1]*s;
+	m[6] = k[1]*k[2]*v + k[0]*s;
+	m[10] = k[2]*k[2]*v + c;
+}
+
+// Inverse angle-axis formula.-----------------------------------
+
+inline void rot2Axis( GLfloat k[3], GLfloat *theta, GLfloat m[16] )
+{
+	GLfloat c = (float)(0.5 * (m[0] + m[5] + m[10] - 1.0));
+	GLfloat r1 = m[6] - m[9];
+	GLfloat r2 = m[8] - m[2];
+	GLfloat r3 = m[1] - m[4];
+	GLfloat s = (float)(0.5 * sqrt(r1*r1+r2*r2+r3*r3));
+
+	*theta = (float)atan2(s, c);
+
+	if( fabs(s) > EPSILON )
+    {
+		c = (float)(2.0*s);
+
+		k[0] = r1 / c;
+		k[1] = r2 / c;
+		k[2] = r3 / c;
+    }
+	else
+    {
+		if( c > 0 ) // theta = 0
+		{
+			k[0] = 0;
+			k[1] = 0;
+			k[2] = 1;
+		}
+		else // theta = +-pi: Shepperd procedure
+		{
+			GLfloat k0_2 = (m[0] + 1)/2;
+			GLfloat k1_2 = (m[5] + 1)/2;
+			GLfloat k2_2 = (m[10] + 1)/2;
+
+			if( k0_2 > k1_2 )
+			{
+				if( k0_2 > k2_2 ) // k0 biggest
+				{
+					k[0] = (float)sqrt(k1_2);
+					k[1] = (m[1] + m[4])/(4*k[0]);
+					k[2] = (m[2] + m[8])/(4*k[0]);
+				}
+				else // k2 biggest
+				{
+					k[2] = (float)sqrt(k2_2);
+					k[0] = (m[2] + m[8])/(4*k[2]);
+					k[1] = (m[6] + m[9])/(4*k[2]);
+				}
+			}
+			else
+			{
+				if( k1_2 > k2_2 ) // k1 biggest
+				{
+					k[1] = (float)sqrt(k1_2);
+					k[0] = (m[1] + m[4])/(4*k[1]);
+					k[2] = (m[6] + m[9])/(4*k[1]);
+				}
+				else // k2 biggest
+				{
+					k[2] = (float)sqrt(k2_2);
+					k[0] = (m[2] + m[8])/(4*k[2]);
+					k[1] = (m[6] + m[9])/(4*k[2]);
+				}
+			}
+		}
+    }
+}
+
+//quaternion to rotation matrix
+
+inline void q2R( GLfloat m[16], GLfloat q[4] )
+{
+	m[0] = q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3];
+	m[1] = 2*q[1]*q[2] + 2*q[0]*q[3];
+	m[2] = 2*q[1]*q[3] - 2*q[0]*q[2];
+
+	m[4] = 2*q[1]*q[2] - 2*q[0]*q[3];
+	m[5] = q[0]*q[0] + q[2]*q[2] - q[1]*q[1] - q[3]*q[3];
+	m[6] = 2*q[2]*q[3] + 2*q[0]*q[1];
+
+	m[8] = 2*q[1]*q[3] + 2*q[0]*q[2];
+	m[9] = 2*q[2]*q[3] - 2*q[0]*q[1];
+	m[10]= q[0]*q[0] + q[3]*q[3] - q[1]*q[1] - q[2]*q[2];
+}
+
+inline void axisToQuat(float a[3], float phi, float q[4])
+{
+  vNormal(a);
+  vCopy(a,q);
+  vScale(q,(float)(sin(phi/2.0)));
+  q[3] = (float)(cos(phi/2.0));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
+//  If they don't add up to 1.0, dividing by their magnitued will
+//  renormalize them.
+//
+//  Note: See the following for more information on quaternions:
+//
+//  - Shoemake, K., Animating rotation with quaternion curves, Computer
+//    Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+//  - Pletinckx, D., Quaternion calculus as a basic tool in computer
+//    graphics, The Visual Computer 5, 2-13, 1989.
+//
+inline void normalizeQuat(float q[4])
+{
+    float  mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+    for (int i = 0; i < 4; i++) q[i] /= mag;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+//  Given two rotations, e1 and e2, expressed as quaternion rotations,
+//  figure out the equivalent single rotation and stuff it into dest.
+//
+//  This routine also normalizes the result every RENORMCOUNT times it is
+//  called, to keep error from creeping in.
+//
+//  NOTE: This routine is written so that q1 or q2 may be the same
+//  as dest (or each other).
+//
+inline void addQuats(float q1[4], float q2[4], float dest[4])
+{
+  static int count=0;
+  float t1[4], t2[4], t3[4];
+  float tf[4];
+
+  vCopy(q1,t1);
+  vScale(t1,q2[3]);
+
+  vCopy(q2,t2);
+  vScale(t2,q1[3]);
+
+  vCross(q2,q1,t3);
+  vAdd(t1,t2,tf);
+  vAdd(t3,tf,tf);
+  tf[3] = q1[3] * q2[3] - vDot(q1,q2);
+
+  dest[0] = tf[0];
+  dest[1] = tf[1];
+  dest[2] = tf[2];
+  dest[3] = tf[3];
+
+  if (++count > 97) {
+    count = 0;
+    normalizeQuat(dest);
+  }
+}
+
+
+
+/*
+* Prints matrix to stderr.
+*/
+
+inline void printMatrix( GLfloat m[16] )
+{
+	int i, j;
+
+	for( i=0; i<4; i++ )
+    {
+		for( j=0; j<4; j++ )
+			fprintf(stderr, "%f ", m[i+j*4]);
+		fprintf(stderr, "\n");
+    }
+	fprintf(stderr, "\n");
+}
+
+inline void printMatrix( GLdouble m[16] )
+{
+	int i, j;
+
+	for( i=0; i<4; i++ )
+    {
+		for( j=0; j<4; j++ )
+			fprintf(stderr, "%f ", m[i+j*4]);
+		fprintf(stderr, "\n");
+    }
+	fprintf(stderr, "\n");
+}
+
+inline void buildLookAt(GLfloat m[16],
+						GLfloat eye[3], GLfloat at[3], GLfloat up[3])
+{
+	//I am not 100% certain that my cross products are in the right order
+
+	GLfloat tmp1[3], tmp2[3], tmp3[3];
+
+	subV3(tmp1, eye, at);
+	GLfloat norm;
+	norm = normV3(tmp1);
+	tmp1[0] /=norm;
+	tmp1[1] /=norm;
+	tmp1[2] /=norm;
+
+	m[2]     =tmp1[0];
+	m[6]     =tmp1[1];
+	m[10]    =tmp1[2];
+
+	crossV3(tmp2, up, tmp1);
+	norm = normV3(tmp2);
+	tmp2[0] /=norm;
+	tmp2[1] /=norm;
+	tmp2[2] /=norm;
+
+	m[0]     =tmp2[0];
+	m[4]     =tmp2[1];
+	m[8]     =tmp2[2];
+
+	crossV3(tmp3, tmp1, tmp2);
+	norm = normV3(tmp3);
+	tmp3[0] /=norm;
+	tmp3[1] /=norm;
+	tmp3[2] /=norm;
+
+	m[1]     =tmp3[0];
+	m[5]     =tmp3[1];
+	m[9]     =tmp3[2];
+
+	m[12]= -eye[0];
+	m[13]= -eye[1];
+	m[14]= -eye[2];
+	m[15]= 1;
+
+	m[3]  = 0;
+	m[7]  = 0;
+	m[11] = 0;
+}
+
+//give the original 8 vertices and the model view matrix
+//This function returns true if the given point is within the bounds of these vertices
+inline int withinBounds3D(GLdouble mv[16], float bbox[8][3], float point[3]) {
+	float min[3], max[3];
+	min[0] = min[1] = min[2] = 10;
+	max[0] = max[1] = max[2] = -10;
+	float rotatedbbox[8][3];
+	for(int i=0; i<8; ++i){
+		translateV3W(rotatedbbox[i], mv, bbox[i]); //get the rotated vol coords
+		//now get the max and min z in view space
+		if(max[2]< MAX(max[2], rotatedbbox[i][2])){
+			max[2] = MAX(max[2], rotatedbbox[i][2]);
+		}
+		if(min[2] > MIN(min[2], rotatedbbox[i][2])){
+			min[2] = MIN(min[2], rotatedbbox[i][2]);
+		}
+		//now get the max and min x in view space
+		if(max[0]< MAX(max[0], rotatedbbox[i][0])){
+			max[0] = MAX(max[0], rotatedbbox[i][0]);
+		}
+		if(min[0] > MIN(min[0], rotatedbbox[i][0])){
+			min[0] = MIN(min[0], rotatedbbox[i][0]);
+		}
+		//now get the max and min y in view space
+		if(max[1]< MAX(max[1], rotatedbbox[i][1])){
+			max[1] = MAX(max[1], rotatedbbox[i][1]);
+		}
+		if(min[1] > MIN(min[1], rotatedbbox[i][1])){
+			min[1] = MIN(min[1], rotatedbbox[i][1]);
+		}
+	}
+	if (point[0]>min[0] && point[0]<max[0]
+	 	&& point[1]>min[1] && point[1]<max[1]) {
+	 //	&& point[2]>min[2] && point[2]<max[2]) {
+	       //pointer is within the bounds
+		return true;
+	}
+	else
+		return false;
+}
+
+//give the original 4 vertices and the model view matrix
+//This function returns true if the given point is within the bounds of these vertices
+inline int withinBounds2D(GLdouble mv[16], float bbox[4][3], float point[3]) {
+	float min[3], max[3];
+	min[0] = min[1] = min[2] = 10;
+	max[0] = max[1] = max[2] = -10;
+	float rotatedbbox[4][3];
+	for(int i=0; i<4; ++i){
+		translateV3W(rotatedbbox[i], mv, bbox[i]); //get the rotated vol coords
+		//now get the max and min z in view space
+		if(max[2]< MAX(max[2], rotatedbbox[i][2])){
+			max[2] = MAX(max[2], rotatedbbox[i][2]);
+		}
+		if(min[2] > MIN(min[2], rotatedbbox[i][2])){
+			min[2] = MIN(min[2], rotatedbbox[i][2]);
+		}
+		//now get the max and min x in view space
+		if(max[0]< MAX(max[0], rotatedbbox[i][0])){
+			max[0] = MAX(max[0], rotatedbbox[i][0]);
+		}
+		if(min[0] > MIN(min[0], rotatedbbox[i][0])){
+			min[0] = MIN(min[0], rotatedbbox[i][0]);
+		}
+		//now get the max and min y in view space
+		if(max[1]< MAX(max[1], rotatedbbox[i][1])){
+			max[1] = MAX(max[1], rotatedbbox[i][1]);
+		}
+		if(min[1] > MIN(min[1], rotatedbbox[i][1])){
+			min[1] = MIN(min[1], rotatedbbox[i][1]);
+		}
+	}
+	if (point[0]>min[0] && point[0]<max[0]
+	 	&& point[1]>min[1] && point[1]<max[1]) {
+//	 	&& point[2]>min[2] && point[2]<max[2]) {
+	       //pointer is within the bounds
+		return true;
+	}
+	else
+		return false;
+}
+
+
+#endif
Index: trunk/src/testing/app/volvis/TODO
===================================================================
--- trunk/src/testing/app/volvis/TODO	(revision 4)
+++ trunk/src/testing/app/volvis/TODO	(revision 4)
@@ -0,0 +1,7 @@
+do the switch of vp like in stereo
+addded an array to store the vp and frustums
+changed the machines.dat file to store the vp with the frustum as %s
+
+
+in vNet.cpp
+need to add vp in readTileConfig
Index: trunk/src/testing/app/volvis/machines.dat.xindi
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.xindi	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.xindi	(revision 4)
@@ -0,0 +1,15 @@
+1 0.84 19.32 69.45 100.0 0.0 0.0 0.5 1.0 
+1 21.0 39.48 69.45 100.0 0.5 0.0 0.5 1.0
+2 0.84 19.32 35.55 66.15 0.0 0.0 0.5 1.0 
+2 21.0 39.48 35.55 66.15 0.5 0.0 0.5 1.0
+3 0.84 19.32 1.65 32.25 0.0 0.0 0.5 1.0 
+3 21.0 39.48 1.65 32.25	0.5 0.0 0.5 1.0
+4 41.16 59.64 69.45 100.0 0.0 0.0 0.5 1.0 
+4 61.32 79.8 69.45 100.0 0.5 0.0 0.5 1.0 
+5 41.16 59.64 35.55 66.15 0.0 0.0 0.5 1.0 
+5 61.32 79.8 35.55 66.15 0.5 0.0 0.5 1.0
+6 41.16 59.64 1.65 32.25 0.0 0.0 0.5 1.0 
+6 61.32 79.8 1.65 32.25 0.5 0.0 0.5 1.0
+7 81.48 99.96 35.55 66.15 0.0 0.0 1.0 0.5 
+7 81.48 99.96 69.45 100.0 0.0 0.5 1.0 0.5 
+8 81.48 99.96 1.65 32.25 0.0 0.0 1.0 1.0 
Index: trunk/src/testing/app/volvis/Makefile.linux
===================================================================
--- trunk/src/testing/app/volvis/Makefile.linux	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.linux	(revision 4)
@@ -0,0 +1,31 @@
+# Makefile for  cluster volvis
+# The slaves run the volvis with their respective frustum using MPI
+# Master does the interaction (MPI) 
+# The transfer-fn UI communicates with the master (QUANTA), and master broadcasts this to slaves(MPI)
+#QUANTA_HOME=/home/cavern/Q2
+QUANTA_HOME=${HOME}/Q2
+#QUANTA_HOME=/home/luc/Q2
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore 
+LIBRARY_DIR 	= -L/usr/lib -L/usr/X11R6/lib -L${QUANTA_HOME}/lib -Wl,-rpath ${QUANTA_HOME}/lib
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_32
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_DISTRIBUTED -DV_NETDATA $(COMPILER_FLAGS) -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(INCLUDE_DIR) 
+CXX		= mpiCC 
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= mpiCC -O3
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o 
+
+OBJ_FILES	= $(VOLOBJ_FILES) ../OptiStore/directions.o ../OptiStore/caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/optiCharybdis.dat
===================================================================
--- trunk/src/testing/app/volvis/optiCharybdis.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiCharybdis.dat	(revision 4)
@@ -0,0 +1,9 @@
+0 206.220.240.230
+1 206.220.240.231
+2 206.220.240.232
+3 206.220.240.233
+4 206.220.240.230
+5 206.220.240.231
+6 206.220.240.232
+7 206.220.240.233
+8 206.220.240.230
Index: trunk/src/testing/app/volvis/vARB.cpp
===================================================================
--- trunk/src/testing/app/volvis/vARB.cpp	(revision 4)
+++ trunk/src/testing/app/volvis/vARB.cpp	(revision 4)
@@ -0,0 +1,219 @@
+/********************************************************************************
+ * Volatile - Volume Visualization Software for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Volatile to www.evl.uic.edu/cavern/forum
+ *********************************************************************************/
+
+//vARB.cpp
+//has the CG related code from Luc Renambot
+
+#if defined(ADDARBGL)
+
+#include "vARB.h"
+#include "global.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <GL/glext.h>
+
+
+const char *shader_code1 =
+"!!ARBfp1.0\n"
+"# cgc version 1.3.0001, build date Jul 16 2004 12:35:04\n"
+"# command line args: -profile arbfp1 -entry C2E2f_passthrough\n"
+"# source file: fragment20.cg\n"
+"#vendor NVIDIA Corporation\n"
+"#version 1.0.02\n"
+"#profile arbfp1\n"
+"#program C2E2f_passthrough\n"
+"#semantic C2E2f_passthrough.texture0\n"
+"#semantic C2E2f_passthrough.texture1\n"
+"#var float3 texCoord0 : $vin.TEX0 : TEX0 : 0 : 1\n"
+"#var sampler3D texture0 :  : texunit 0 : 1 : 1\n"
+"#var sampler2D texture1 :  : texunit 1 : 2 : 1\n"
+"#var float4 C2E2f_passthrough : $vout.COL : COL : -1 : 1\n"
+"PARAM c[1] = { program.local[0] };\n"
+"TEMP R0;\n"
+"TEX R0.xw, fragment.texcoord[0], texture[0], 3D;\n"
+"TEX result.color, R0.wxzw, texture[1], 2D;\n"
+"END\n"
+"# 2 instructions, 1 R-regs\n";
+
+const char *shader_code =
+"!!ARBfp1.0\n"
+"#var float3 texCoord0 : $vin.TEXCOORD0 : TEXCOORD0 : 0 : 1\n"
+"#var sampler3D texture0 :  : texunit 0 : 1 : 1\n"
+"#var sampler2D texture1 :  : texunit 1 : 2 : 1\n"
+"#var float4 C2E2f_passthrough : $vout.COLOR : COLOR : -1 : 1\n"
+"TEMP R0;\n"
+"TEX R0.xw, fragment.texcoord[0], texture[0], 3D;\n"
+"TEX result.color, R0.wxww, texture[1], 2D;\n"
+"END\n";
+
+// WORKS
+const char *shader_code3 =
+"!!ARBfp1.0\n"
+"OUTPUT out = result.color;\n"
+"TEMP temp;\n"
+"PARAM pink = { 1.0, 0.4, 0.4, 0.0}; \n"
+"TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
+"ADD out, temp, pink;\n"
+"END\n";
+
+
+
+GLuint vertexProgram, fragmentProgram;
+int curTexId ;
+
+void handleARBError()
+{
+    fprintf(stderr, "ARB> error \n");
+    exit(1);
+}
+
+int initARB()
+{
+	int notgood;
+        const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
+        size_t sysExtsLen = strlen(extensions);
+
+	notgood = 0;
+
+        if(strstr(extensions,"GL_ARB_vertex_program"))
+                fprintf(stderr, "GL_ARB_vertex_program supported\n");
+        else
+        {
+                fprintf(stderr, "GL_ARB_vertex_program NOT supported\n");
+		notgood = 1;
+        }
+        if(strstr(extensions,"GL_ARB_fragment_program"))
+                fprintf(stderr, "GL_ARB_fragment_program supported\n");
+        else
+        {
+                fprintf(stderr, "GL_ARB_fragment_program NOT supported\n");
+		notgood = 1;
+        }
+
+	if (notgood)
+	{
+		fprintf(stderr, "ARB> error : fragment and vertex program required (GL_ARB_fragment_program, GL_ARB_vertex_program).\n");
+		fprintf(stderr, "---------------------------------------------------------\n");
+		exit(1);
+	}
+	else
+	{
+		GLint maxInsts, maxTemps, maxParams;
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &maxInsts );
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &maxTemps );
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_PARAMETERS_ARB, &maxParams );
+		fprintf(stderr, "ARB> GL_ARB_fragment_program, GL_ARB_vertex_program present\n");
+		fprintf(stderr, "ARB> \t %d max instructions, %d max temp varriables, %d max variables\n",
+			maxInsts, maxTemps, maxParams);
+		fprintf(stderr, "---------------------------------------------------------\n");
+	}
+
+        glGenProgramsARB(1, &fragmentProgram);
+        glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fragmentProgram);
+        glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(shader_code), (GLubyte *) shader_code);
+
+        GLint error_pos;
+        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
+        if (error_pos != -1)
+{
+                const GLubyte *error_string;
+                error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
+                fprintf(stderr, "Program error at position: %d\n%s\n", error_pos, error_string);
+        }
+	else
+	{
+		GLint maxInsts, maxTemps, maxParams;
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_INSTRUCTIONS_ARB, &maxInsts );
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_TEMPORARIES_ARB, &maxTemps );
+		glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_PARAMETERS_ARB, &maxParams );
+		fprintf(stderr, "ARB> GL_ARB_fragment_program, GL_ARB_vertex_program present\n");
+		fprintf(stderr, "ARB> \t %d current instructions, %d current varriables, %d current variables\n",
+			maxInsts, maxTemps, maxParams);
+		fprintf(stderr, "---------------------------------------------------------\n");
+	}
+
+	//hTexture0 = cgGetNamedParameter(fragmentProgram, "texture0");
+	//hTexture1 = cgGetNamedParameter(fragmentProgram, "texture1");
+
+	return 1;
+}
+
+void enableARB(unsigned int volTex)
+{
+	glEnable(GL_FRAGMENT_PROGRAM_ARB);
+	glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fragmentProgram);
+
+	glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, global.volume->texName, curTexId, 0, 0);
+
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+	glBindTexture(GL_TEXTURE_3D, global.volume->texName);
+
+	glActiveTextureARB(GL_TEXTURE1_ARB);
+	glBindTexture(GL_TEXTURE_2D, curTexId);
+
+    glActiveTextureARB(GL_TEXTURE0_ARB);
+
+	//cgGLSetTextureParameter(hTexture0, global.volume->texName);
+	//cgGLSetTextureParameter(hTexture1, curTexId);
+
+	//cgGLEnableTextureParameter(hTexture0);
+	//cgGLEnableTextureParameter(hTexture1);
+
+
+	//glActiveTextureARB( GL_TEXTURE0_ARB );
+	//glBindTexture(GL_TEXTURE_3D, global.volume->texName);
+	//glActiveTextureARB( GL_TEXTURE1_ARB );
+	//glBindTexture(GL_TEXTURE_3D, curTexId);
+
+}
+
+void setCurTextureARB(int texName)
+{
+	curTexId = texName;
+}
+
+void disableARB()
+{
+    glDisable(GL_FRAGMENT_PROGRAM_ARB);
+
+	//cgGLDisableTextureParameter(hTexture0);
+	//cgGLDisableTextureParameter(hTexture1);
+}
+
+void exitARB()
+{
+	glDeleteProgramsARB(1, &fragmentProgram);
+}
+
+#endif
Index: trunk/src/testing/app/volvis/glUE.h
===================================================================
--- trunk/src/testing/app/volvis/glUE.h	(revision 4)
+++ trunk/src/testing/app/volvis/glUE.h	(revision 4)
@@ -0,0 +1,245 @@
+//////////////////////////////////////////////////////////////////////
+//                   ________    ____   ___ 
+//                  |        \  /    | /  /
+//                  +---+     \/     |/  /
+//                  +--+|  |\    /|     < 
+//                  |  ||  | \  / |  |\  \ 
+//                  |      |  \/  |  | \  \ 
+//                   \_____|      |__|  \__\
+//                       Copyright  2001 
+//                      Joe Michael Kniss
+//                    <<<jmk@cs.utah.edu>>>
+//               "All Your Base are Belong to Us"
+//
+//    GL Utills and Extensions v0.01(beta)
+//
+// glUE.h: interface for the glUE class.
+//  The purpose of the "class" is to provide access to extensions 
+//    without having to go through the hassle of aquiring them
+//    in various places.  They are defined as "extern" so that a
+//    single function pointer is kept around, ie. this file can
+//    be included in multiple files.  The "glue" class should be 
+//    created right after the gl window is created.  
+//
+//  NOTE: Many of the extensions defined by this header will require
+//    "exparamental" drivers from the chip/card manufacurer.  If an
+//    extension that you want is not detected, this is probably why.
+//////////////////////////////////////////////////////////////////////
+
+#include <iostream>
+
+using namespace std;
+
+#if !defined(AFX_GLUE_H__F345B9AF_7BCA_4BAB_BC9E_949B280622AE__INCLUDED_)
+#define AFX_GLUE_H__F345B9AF_7BCA_4BAB_BC9E_949B280622AE__INCLUDED_
+
+//---------------------- Sort of lame card select --------------
+// This is being phased out, do not use it
+#define WILDCAT  0
+#define RADEON   0
+#define R200     0 
+#define GEFORCE3 0
+#define GEFORCE2 0
+//--------------------------------------------------------------
+
+#ifdef WIN32
+#include <windows.h>		//  must be included before any OpenGL
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#include <OpenGL/glext.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+#endif
+
+
+#ifdef WIN32
+//------- This include file is nVidia specific!!!-----------
+#include <GL/glExt.h>
+
+//------- This include file is windows specific!!!----------
+#include <GL/wglext.h>
+
+//------ This include file is ATI specific!!! --------------
+//#include <GL/glATI.h>
+//#include <GL/wglATI.h>
+
+//==================================================================================
+//------------------ Extension Definitions -----------------------------------------
+//==================================================================================
+// NOTE: To quickly test if an extension is available, simply test if the function 
+//       pointer is non zero. ie:
+//     if(<functionName>){ ...<functionName>(..); ...} else { ... do something else}
+//
+//   
+//------------------ 3d texture ----------------------------------------------------
+typedef void (APIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level,
+                                               GLint internalformat,
+                                               GLsizei width, GLsizei height,
+                                               GLsizei depth, GLint border,
+                                               GLenum format, GLenum type,
+                                               const GLvoid *pixels);
+extern PFNGLTEXIMAGE3DPROC  glTexImage3DEXT;
+
+#ifdef GL_EXT_blend_minmax
+extern PFNGLBLENDEQUATIONEXTPROC glBlendEquationEXT;
+#endif
+
+//------------------ Palated texture -----------------------------------------------
+#ifdef GL_EXT_color_table
+typedef void (APIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target,
+                                                  GLenum internalformat,
+                                                  GLsizei width,
+                                                  GLenum format,
+                                                  GLenum type,
+                                                  const GLvoid *table);
+extern PFNGLCOLORTABLEEXTPROC  glColorTableEXT;
+#endif // end palated texture
+
+//------------------ Multi-texture -------------------------------------------------
+#ifdef GL_ARB_multitexture
+extern PFNGLACTIVETEXTUREARBPROC       glActiveTexture;
+extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture;
+extern PFNGLMULTITEXCOORD1FARBPROC     glMultiTexCoord1fARB;
+extern PFNGLMULTITEXCOORD1FVARBPROC    glMultiTexCoord1fvARB;
+extern PFNGLMULTITEXCOORD2FARBPROC     glMultiTexCoord2fARB;
+extern PFNGLMULTITEXCOORD2FVARBPROC    glMultiTexCoord2fvARB;
+extern PFNGLMULTITEXCOORD3FARBPROC     glMultiTexCoord3fARB;
+extern PFNGLMULTITEXCOORD3FVARBPROC    glMultiTexCoord3fvARB;
+#endif //end multi texture
+
+//----------------- Secondary color ------------------------------------------------
+#ifdef GL_EXT_secondary_color
+extern PFNGLSECONDARYCOLOR3FEXTPROC   glSecondaryColor3fEXT;
+#endif
+
+//------------------   nVidia Stuff ------------------------------------------------
+//------------------ Register Combiners --------------------------------------------
+#ifdef GL_NV_register_combiners
+extern PFNGLCOMBINERPARAMETERFVNVPROC              glCombinerParameterfvNV; 
+extern PFNGLCOMBINERPARAMETERFNVPROC               glCombinerParameterfNV;
+extern PFNGLCOMBINERPARAMETERIVNVPROC              glCombinerParameterivNV;
+extern PFNGLCOMBINERPARAMETERINVPROC               glCombinerParameteriNV;
+extern PFNGLCOMBINERINPUTNVPROC                    glCombinerInputNV;
+extern PFNGLCOMBINEROUTPUTNVPROC                   glCombinerOutputNV; 
+extern PFNGLFINALCOMBINERINPUTNVPROC               glFinalCombinerInputNV;
+extern PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC      glGetCombinerInputParameterfvNV;
+extern PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC      glGetCombinerInputParameterivNV;
+extern PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC     glGetCombinerOutputParameterfvNV;
+extern PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC     glGetCombinerOutputParameterivNV;
+extern PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC glGetFinalCombinerInputParameterfvNV;
+extern PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC glGetFinalCombinerInputParameterivNV;
+#endif
+
+//------------------      ATI Stuff ------------------------------------------------
+//------------------ env-bump map/ pixel texture -----------------------------------
+//   NOTE: This extension is only for ATI Radions, it can be used to achieve 
+//          pixel texture as well as reflective bump mapping
+//              but, fragment shaders are the bomb!!
+#ifdef GL_ATIX_envmap_bumpmap
+extern PFNGLTEXBUMPPARAMETERIVATIXPROC     glTexBumpParameterivATIX;
+extern PFNGLTEXBUMPPARAMETERFVATIXPROC     glTexBumpParameterfvATIX;
+extern PFNGLGETTEXBUMPPARAMETERIVATIXPROC  glGetTexBumpParameterivATIX;
+extern PFNGLGETTEXBUMPPARAMETERFVATIXPROC  glGetTexBumpParameterfvATIX;
+#endif //end EMBM
+
+#ifdef GL_ATI_fragment_shader
+extern PFNGLGENFRAGMENTSHADERSATIPROC   glGenFragmentShadersATI;
+extern PFNGLBINDFRAGMENTSHADERATIPROC   glBindFragmentShaderATI;
+extern PFNGLDELETEFRAGMENTSHADERATIPROC glDeleteFragmentShaderATI;
+extern PFNGLBEGINFRAGMENTSHADERATIPROC  glBeginFragmentShaderATI;
+extern PFNGLENDFRAGMENTSHADERATIPROC    glEndFragmentShaderATI;
+extern PFNGLPASSTEXCOORDATIPROC         glPassTexCoordATI;
+extern PFNGLSAMPLEMAPATIPROC            glSampleMapATI;
+extern PFNGLCOLORFRAGMENTOP1ATIPROC     glColorFragmentOp1ATI;
+extern PFNGLCOLORFRAGMENTOP2ATIPROC     glColorFragmentOp2ATI;
+extern PFNGLCOLORFRAGMENTOP3ATIPROC     glColorFragmentOp3ATI;
+extern PFNGLALPHAFRAGMENTOP1ATIPROC     glAlphaFragmentOp1ATI;
+extern PFNGLALPHAFRAGMENTOP2ATIPROC     glAlphaFragmentOp2ATI;
+extern PFNGLALPHAFRAGMENTOP3ATIPROC     glAlphaFragmentOp3ATI;
+extern PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glSetFragmentShaderConstantATI;
+#endif
+
+
+//------------------ WGL Extensions ------------------------------------------------
+#ifdef WGL_ARB_pbuffer
+extern PFNWGLCREATEPBUFFERARBPROC    wglCreatePbufferARB;
+extern PFNWGLGETPBUFFERDCARBPROC     wglGetPbufferDCARB;
+extern PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+extern PFNWGLDESTROYPBUFFERARBPROC   wglDestroyPbufferARB;
+extern PFNWGLQUERYPBUFFERARBPROC     wglQueryPbufferARB;
+#endif 
+#ifdef WGL_ARB_pixel_format
+extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
+extern PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
+extern PFNWGLCHOOSEPIXELFORMATARBPROC      wglChoosePixelFormatARB;
+#endif
+#ifdef WGL_ARB_render_texture //render to texture
+extern PFNWGLBINDTEXIMAGEARBPROC     wglBindTexImageARB;
+extern PFNWGLRELEASETEXIMAGEARBPROC  wglReleaseTexImageARB;
+extern PFNWGLSETPBUFFERATTRIBARBPROC wglSetBufferAttribARB;
+#endif
+
+
+#endif // #ifdef WIN32
+
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+
+//------------------ Capture and Report gl Errors ----------------------------------
+//  NOTE: the calling convention for GLErr is: 
+//            location = "Classname.function()" to identify where you made the call
+//            glfuncname = "Name" of the gl Function which you are testing for errors
+//        Returns 0 if no error, 1 if there was an error. 
+
+int GlErr(char *location, char *glfuncname);
+
+//------------------ Query extensions ----------------------------------------------
+//  Returns true (!=0) if the extension defined by the extName string is available for 
+//  the card.  If the extName string == "Print" all of the extensions available on the 
+//  card are printed to standard out.
+
+GLboolean QueryExtension(char *extName);
+
+int checkGfx();
+
+//------------------ Load all Extensions -------------------------------------------
+//  Attempts to load all of the extensions for the defined card flag
+//   Needs to be adapted for LINUX !!!
+
+#ifdef WIN32
+void LoadAllExtensions();
+//----- get individual sets of extensions
+void getOGL12();
+void getNV20();
+void getATI8K();
+void getWGL();
+#endif
+
+//------------------ Card Profile --------------------------------------------------
+//  Figure out what card we are using, by checking for unique extensions
+//
+//  returns an integer from the gluvv.plat enum (gluvvPlatform)
+
+int CardProfile();
+
+
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+//==============================================================================
+
+#endif // !defined(AFX_GLUE_H__F345B9AF_7BCA_4BAB_BC9E_949B280622AE__INCLUDED_)
Index: trunk/src/testing/app/volvis/optiGlobal2.dat
===================================================================
--- trunk/src/testing/app/volvis/optiGlobal2.dat	(revision 4)
+++ trunk/src/testing/app/volvis/optiGlobal2.dat	(revision 4)
@@ -0,0 +1,16 @@
+0  10.1.1.111
+1 10.1.1.113
+2 10.1.1.117
+3 10.1.1.112
+4 10.1.1.113
+5 10.1.1.117
+6 10.1.1.112
+7 206.220.241.21
+8 206.220.241.22
+9 206.220.241.23
+10 206.220.241.24
+11 206.220.241.20
+12 206.220.241.21
+13 206.220.241.22
+14 206.220.241.23
+15 206.220.241.24
Index: trunk/src/testing/app/volvis/machines.dat.nico
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.nico	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.nico	(revision 4)
@@ -0,0 +1,15 @@
+1 0.84 19.32 69.45 100.0 0.0 0.0 0.5 1.0 
+1 21.0 39.48 69.45 100.0 0.5 0.0 0.5 1.0
+2 0.84 19.32 35.55 66.15 0.0 0.0 0.5 1.0 
+2 21.0 39.48 35.55 66.15 0.5 0.0 0.5 1.0
+3 0.84 19.32 1.65 32.25 0.0 0.0 0.5 1.0 
+3 21.0 39.48 1.65 32.25	0.5 0.0 0.5 1.0
+4 41.16 59.64 69.45 100.0 0.0 0.0 0.5 1.0 
+4 61.32 79.8 69.45 100.0 0.5 0.0 0.5 1.0 
+5 41.16 59.64 35.55 66.15 0.0 0.0 0.5 1.0 
+5 61.32 79.8 35.55 66.15 0.5 0.0 0.5 1.0
+6 41.16 59.64 1.65 32.25 0.0 0.0 0.5 1.0 
+6 61.32 79.8 1.65 32.25 0.5 0.0 0.5 1.0
+7 81.48 99.96 35.55 66.15 0.0 0.0 1.0 0.5 
+7 81.48 99.96 69.45 100.0 0.0 0.5 1.0 0.5 
+8 81.48 99.96 1.65 32.25 0.0 0.0 1.0 1.0 
Index: trunk/src/testing/app/volvis/Makefile.amd64
===================================================================
--- trunk/src/testing/app/volvis/Makefile.amd64	(revision 4)
+++ trunk/src/testing/app/volvis/Makefile.amd64	(revision 4)
@@ -0,0 +1,33 @@
+#Makefile for a Geowall type configuration
+#ie the volvis runs on the geowall and the transfer-fn UI runs on a remote machine
+
+QUANTA_HOME=${HOME}/QUANTA64
+
+
+INCLUDE_DIR 	= -I/usr/local/include -I../OptiStore   
+LIBRARY_DIR 	= -L/usr/X11R6/lib64 -L${QUANTA_HOME}/lib64 -Wl,-rpath ${QUANTA_HOME}/lib64
+#LIBRARIES 	= -L${GLUT_HOME}/lib -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64
+LIBRARIES 	= -lCgGL -lCg -lglut -lGLU -lGL -lXi -lXmu -lXext -lX11 -lm -lquanta_64
+CXXFLAGS 	= -O3 -DADDCGGL -DV_NETTF -DV_DISTRIBUTED -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR) 
+#CXXFLAGS 	= -O3 -DADDARBGL -DV_NETTF -DV_NETDATA -I${QUANTA_HOME}/include/QUANTA -I${QUANTA_HOME}/include $(COMPILER_FLAGS) $(INCLUDE_DIR) -Wno-deprecated
+# -DADDARBGL
+CXXINCLUDE	= $(QUANTA_CFLAGS) 
+COMPILER 	= mpiCC -O3
+CXX             = mpiCC -O3
+
+
+VOLOBJ_FILES 	= CCmdLine.o glUE.o main.o Trackball.o vARB.o vCG.o vCut.o mmap.o vFPSText.o vNet.o vSliceView.o \
+		 vPrimitive.o vRenderer.o vTF.o vUI.o vVolume.o vOptiVolume.o vFileVolume.o vGeometry.o
+
+OBJ_FILES	= $(VOLOBJ_FILES) ../OptiStore/directions.o ../OptiStore/caDataManagerClient.o
+
+EXEC 		= volvis
+
+$(EXEC):	$(OBJ_FILES)
+		$(COMPILER) $(COMPILER_FLAGS) -o $(EXEC) $(OBJ_FILES) \
+			$(LIBRARY_DIR) $(LIBRARIES) -lpthread
+
+
+clean:
+		\rm -f $(VOLOBJ_FILES) $(EXEC)
+
Index: trunk/src/testing/app/volvis/machines.dat.igpp.bak
===================================================================
--- trunk/src/testing/app/volvis/machines.dat.igpp.bak	(revision 4)
+++ trunk/src/testing/app/volvis/machines.dat.igpp.bak	(revision 4)
@@ -0,0 +1,8 @@
+3 0.0 23.4375 0.0 50.0
+4 23.4375 46.875 0.0 50.0
+7 53.125 76.56265 0.0 50.0
+8 76.56265 100.0 0.0 50.0
+1 0.0 23.4375 50.0 100.0
+2 23.4375 46.875 50.0 100.0
+5 53.125 76.56265 50.0 100.0
+6 76.56265 100.0 50.0 100.0
Index: trunk/src/testing/app/yuv/yuv.cxx
===================================================================
--- trunk/src/testing/app/yuv/yuv.cxx	(revision 4)
+++ trunk/src/testing/app/yuv/yuv.cxx	(revision 4)
@@ -0,0 +1,134 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+//
+// Streams a YUV buffer (or an image)
+//    ./yuv 0 width height fps filename
+//
+
+int main(int argc, char *argv[])
+{
+	double t1, t2, fps;
+	char *fn;
+	void *pixels = NULL;
+	sail sageInf; // sail object
+	int nodeID;
+
+	if (argc < 2)
+		nodeID = 0;
+	else
+		nodeID = atoi(argv[1]);
+		 
+	int resX = 400, resY = 400;
+	if (argc >= 4) {
+		resX = atoi(argv[2]);
+		resY = atoi(argv[3]); 	 
+	}	
+	double rate = 10.0;
+	if (argc >= 5) {
+		rate = atof(argv[4]);
+	}	
+	if (argc >= 6) {
+		fn = strdup(argv[5]);
+		FILE *f = fopen(fn, "r");
+		pixels = malloc(resX*resY*2);
+		memset(pixels, 0, resX*resY*2);
+		int nb = fread(pixels, 1, resX*resY*2, f);
+		fclose(f);
+	}	
+	
+	std::cout << std::endl << "ResX = " << resX << "  ResY = " << resY << std::endl;
+
+	sailConfig scfg;
+	scfg.init("yuv.conf");
+	scfg.setAppName("yuv");
+	scfg.rank = nodeID;
+			
+	scfg.resX = resX;
+	scfg.resY = resY;
+
+	sageRect renderImageMap;
+	renderImageMap.left = 0.0;
+	renderImageMap.right = 1.0;
+	renderImageMap.bottom = 0.0;
+	renderImageMap.top = 1.0;
+
+	scfg.imageMap = renderImageMap;
+	scfg.pixFmt = PIXFMT_YUV;
+	scfg.rowOrd = TOP_TO_BOTTOM;
+	scfg.master = true;
+	scfg.nwID = 1;
+	 		 
+	sageInf.init(scfg);	 
+	std::cout << "sail initialized " << std::endl;
+	
+	void *buffer = sageInf.getBuffer();
+	unsigned char color = 200;
+	
+	while(1) {
+		t1 = sage::getTime();
+		if (pixels)
+			memcpy(buffer, pixels, resX*resY*2);
+		else
+			memset(buffer, color, resX*resY*2);
+		sageInf.swapBuffer();
+		buffer = sageInf.getBuffer();
+		color = (color + 1) % 256;	
+		sageMessage msg;
+		if (sageInf.checkMsg(msg, false) > 0) {
+			switch (msg.getCode()) {
+				 case APP_QUIT : {
+					sageInf.shutdown();
+					exit(0);
+					break;
+				}
+			}	
+		}
+		t2 = sage::getTime();
+		fps = (1000000.0/(t2-t1));
+		if (fps > rate) {
+			sage::usleep( (1000000.0/rate) - (t2-t1)  );
+		}
+	}
+	
+	return 0;
+}
Index: trunk/src/testing/app/yuv/yuv.conf
===================================================================
--- trunk/src/testing/app/yuv/yuv.conf	(revision 4)
+++ trunk/src/testing/app/yuv/yuv.conf	(revision 4)
@@ -0,0 +1,13 @@
+masterIP 127.0.0.1
+nwID     1
+msgPort  22010
+syncPort 12010
+nodeNum  1
+appID    3
+pixelBlockSize 64 64
+winX 0
+winY 0
+winWidth 1280
+winHeight 720
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/app/yuv/Makefile
===================================================================
--- trunk/src/testing/app/yuv/Makefile	(revision 4)
+++ trunk/src/testing/app/yuv/Makefile	(revision 4)
@@ -0,0 +1,29 @@
+
+###################################################################
+# Makefile for yuv
+###################################################################
+
+include ../../config.mk
+
+CFLAGS=-fPIC -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(QUANTA_LIB) $(GLEW_LIB) -L../../lib -lsail
+CC=$(COMPILER)
+
+
+PROGRAM = yuv
+FILES= yuv.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(COMPILER) -o $(PROGRAM) $(FILES) $(LIBS)
+
+yuv.o: yuv.cxx
+	$(COMPILER) $(CFLAGS) -c yuv.cxx
+
+
+clean:
+	\rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/qshare/qshare.pro.user
===================================================================
--- trunk/src/testing/app/qshare/qshare.pro.user	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.pro.user	(revision 4)
@@ -0,0 +1,79 @@
+<!DOCTYPE QtCreatorProject>
+<qtcreator>
+ <data>
+  <variable>ProjectExplorer.Project.ActiveTarget</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.EditorSettings</variable>
+  <valuemap type="QVariantMap">
+   <value key="EditorConfiguration.Codec" type="QByteArray">System</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Target.0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Desktop</value>
+   <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Target.DesktopTarget</value>
+   <value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
+   <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
+   <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value>
+     <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList"/>
+    </valuemap>
+    <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value>
+    <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap">
+     <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value>
+     <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value>
+     <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value>
+     <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList">
+      <value type="QString">clean</value>
+     </valuelist>
+     <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value>
+    </valuemap>
+    <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value>
+    <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
+    <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">C:/Users/renambot/Desktop/sage3.0/app/qshare</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">4</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">3</value>
+    <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">false</value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">1</value>
+   <valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
+    <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qshare</value>
+    <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4RunConfiguration</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase" type="int">2</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.ProFile" type="QString">qshare.pro</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal" type="bool">false</value>
+    <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges" type="QVariantList"/>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetName" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetWorkingDirectory" type="bool">false</value>
+    <value key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory" type="QString"></value>
+   </valuemap>
+   <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.TargetCount</variable>
+  <value type="int">1</value>
+ </data>
+ <data>
+  <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+  <value type="int">4</value>
+ </data>
+</qtcreator>
Index: trunk/src/testing/app/qshare/qshare.pro.user.1.3
===================================================================
--- trunk/src/testing/app/qshare/qshare.pro.user.1.3	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.pro.user.1.3	(revision 4)
@@ -0,0 +1,286 @@
+<!DOCTYPE QtCreatorProject>
+<qtcreator>
+ <data>
+  <variable>RunConfiguration0-BaseEnvironmentBase</variable>
+  <value type="int">2</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-CommandLineArguments</variable>
+  <valuelist type="QVariantList"/>
+ </data>
+ <data>
+  <variable>RunConfiguration0-ProFile</variable>
+  <value type="QString">qshare.pro</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-RunConfiguration.name</variable>
+  <value type="QString">qshare</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UseDyldImageSuffix</variable>
+  <value type="bool">false</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UseTerminal</variable>
+  <value type="bool">false</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UserEnvironmentChanges</variable>
+  <valuelist type="QVariantList"/>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UserSetName</variable>
+  <value type="bool">false</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UserSetWorkingDirectory</variable>
+  <value type="bool">false</value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-UserWorkingDirectory</variable>
+  <value type="QString"></value>
+ </data>
+ <data>
+  <variable>RunConfiguration0-type</variable>
+  <value type="QString">Qt4ProjectManager.Qt4RunConfiguration</value>
+ </data>
+ <data>
+  <variable>activeRunConfiguration</variable>
+  <value type="int">0</value>
+ </data>
+ <data>
+  <variable>activebuildconfiguration</variable>
+  <value type="QString">Debug</value>
+ </data>
+ <data>
+  <variable>buildConfiguration-Debug</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">Debug</value>
+   <value key="QtVersionId" type="int">2</value>
+   <value key="ToolChain" type="int">0</value>
+   <value key="addQDumper" type=""></value>
+   <value key="buildConfiguration" type="int">2</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildconfiguration-Debug-buildstep0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">Debug</value>
+   <valuelist key="abstractProcess.Environment" type="QVariantList">
+    <value type="QString">AMANITHDIR=/Users/luc/Desktop/SVG/amanith</value>
+    <value type="QString">Apple_PubSub_Socket_Render=/tmp/launch-Edjt5I/Render</value>
+    <value type="QString">CEI_HOME=/Applications/CEI/</value>
+    <value type="QString">COMMAND_LINE_INSTALL=1</value>
+    <value type="QString">COMMAND_MODE=unix2003</value>
+    <value type="QString">CVSROOT=:pserver:cavern@cube.evl.uic.edu:/Users/Shared/CVS</value>
+    <value type="QString">CVS_RSH=ssh</value>
+    <value type="QString">DAZSTUDIO=/Applications/DAZStudio</value>
+    <value type="QString">DAZSTUDIOVERSION=DAZStudio</value>
+    <value type="QString">DISPLAY=:0.0</value>
+    <value type="QString">DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib</value>
+    <value type="QString">DYLD_LIBRARY_PATH=/Users/luc/Dev/SVN/sage3.0-ratko/lib</value>
+    <value type="QString">EDITOR=vi</value>
+    <value type="QString">GL_ENABLE_DEBUG_ATTACH=YES</value>
+    <value type="QString">GOARCH=386</value>
+    <value type="QString">GOOS=darwin</value>
+    <value type="QString">GOROOT=/Users/luc/Dev/GO</value>
+    <value type="QString">GROUP=luc</value>
+    <value type="QString">HOME=/Users/luc</value>
+    <value type="QString">HOST=galette.evl.uic.edu</value>
+    <value type="QString">HOSTTYPE=intel-mac</value>
+    <value type="QString">LANG=en_US.UTF-8</value>
+    <value type="QString">LAPTOP=130.37.34.47:0.0</value>
+    <value type="QString">LD_LIBRARY_PATH=/Users/luc/Dev/SVN/sage3.0-ratko/lib:/Developer/Applications/Qt/QtCreator.app/Contents/Frameworks/</value>
+    <value type="QString">LOGNAME=luc</value>
+    <value type="QString">MACHTYPE=x86_64</value>
+    <value type="QString">MPICH=/home/mpich.gcc/</value>
+    <value type="QString">OSTYPE=darwin</value>
+    <value type="QString">PATH=/Developer/Tools/Qt:/opt/local/bin:/opt/local/sbin:/Users/luc/Dev/SVN/sage3.0-ratko/bin:/Users/luc/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/teTeX/bin/i386-apple-darwin-current:/opt/local/bin:/sbin:/usr/etc:/usr/sbin:/usr/local/bin:/usr/local/mysql/bin:/usr/X11R6/bin:.:/Users/luc/Dev/pbrt-1.02/bin</value>
+    <value type="QString">PBRT_SEARCHPATH=/Users/luc/Dev/pbrt-1.02/bin</value>
+    <value type="QString">PIXIEHOME=/Applications/Graphics/Pixie</value>
+    <value type="QString">PKG_CONFIG=/opt/local/bin/pkg-config</value>
+    <value type="QString">PKG_CONFIG_PATH=/opt/local/lib/pkgconfig</value>
+    <value type="QString">PLASMA=graffiti:0.0</value>
+    <value type="QString">PRINTER=evl2036ps</value>
+    <value type="QString">PWD=/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare</value>
+    <value type="QString">QTDIR=/usr/local/Qt4.6</value>
+    <value type="QString">REMOTEHOST=</value>
+    <value type="QString">SAGE_DIRECTORY=/Users/luc/Dev/SVN/sage3.0-ratko</value>
+    <value type="QString">SDL_WINDOW_POS=0x-50</value>
+    <value type="QString">SHELL=/bin/tcsh</value>
+    <value type="QString">SHLVL=1</value>
+    <value type="QString">SSH_AUTH_SOCK=/tmp/launch-RJ7KlT/Listeners</value>
+    <value type="QString">TERM=vt100</value>
+    <value type="QString">TERM_PROGRAM=Apple_Terminal</value>
+    <value type="QString">TERM_PROGRAM_VERSION=273</value>
+    <value type="QString">TMPDIR=/var/folders/7p/7pefsr17FgSHHtIsxeOpSE+++TI/-Tmp-/</value>
+    <value type="QString">USER=luc</value>
+    <value type="QString">VENDOR=apple</value>
+    <value type="QString">ZHORA=zhora:0.0</value>
+    <value type="QString">__CF_USER_TEXT_ENCODING=0x1F5:0:0</value>
+    <value type="QString">__GL_FSAA_MODE=5</value>
+    <value type="QString">__GL_SYNC_TO_VBLANK=1</value>
+   </valuelist>
+   <valuelist key="abstractProcess.arguments" type="QVariantList">
+    <value type="QString">/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare/qshare.pro</value>
+    <value type="QString">-spec</value>
+    <value type="QString">macx-g++</value>
+    <value type="QString">-r</value>
+   </valuelist>
+   <value key="abstractProcess.command" type="QString">/usr/bin/qmake</value>
+   <value key="abstractProcess.enabled" type="bool">false</value>
+   <value key="abstractProcess.workingDirectory" type="QString">/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildconfiguration-Debug-buildstep1</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">Debug</value>
+   <valuelist key="abstractProcess.Environment" type="QVariantList">
+    <value type="QString">AMANITHDIR=/Users/luc/Desktop/SVG/amanith</value>
+    <value type="QString">Apple_PubSub_Socket_Render=/tmp/launch-Edjt5I/Render</value>
+    <value type="QString">CEI_HOME=/Applications/CEI/</value>
+    <value type="QString">COMMAND_LINE_INSTALL=1</value>
+    <value type="QString">COMMAND_MODE=unix2003</value>
+    <value type="QString">CVSROOT=:pserver:cavern@cube.evl.uic.edu:/Users/Shared/CVS</value>
+    <value type="QString">CVS_RSH=ssh</value>
+    <value type="QString">DAZSTUDIO=/Applications/DAZStudio</value>
+    <value type="QString">DAZSTUDIOVERSION=DAZStudio</value>
+    <value type="QString">DISPLAY=:0.0</value>
+    <value type="QString">DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib</value>
+    <value type="QString">DYLD_LIBRARY_PATH=/Users/luc/Dev/SVN/sage3.0-ratko/lib</value>
+    <value type="QString">EDITOR=vi</value>
+    <value type="QString">GL_ENABLE_DEBUG_ATTACH=YES</value>
+    <value type="QString">GOARCH=386</value>
+    <value type="QString">GOOS=darwin</value>
+    <value type="QString">GOROOT=/Users/luc/Dev/GO</value>
+    <value type="QString">GROUP=luc</value>
+    <value type="QString">HOME=/Users/luc</value>
+    <value type="QString">HOST=galette.evl.uic.edu</value>
+    <value type="QString">HOSTTYPE=intel-mac</value>
+    <value type="QString">LANG=en_US.UTF-8</value>
+    <value type="QString">LAPTOP=130.37.34.47:0.0</value>
+    <value type="QString">LD_LIBRARY_PATH=/Users/luc/Dev/SVN/sage3.0-ratko/lib:/Developer/Applications/Qt/QtCreator.app/Contents/Frameworks/</value>
+    <value type="QString">LOGNAME=luc</value>
+    <value type="QString">MACHTYPE=x86_64</value>
+    <value type="QString">MPICH=/home/mpich.gcc/</value>
+    <value type="QString">OSTYPE=darwin</value>
+    <value type="QString">PATH=/Developer/Tools/Qt:/opt/local/bin:/opt/local/sbin:/Users/luc/Dev/SVN/sage3.0-ratko/bin:/Users/luc/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/teTeX/bin/i386-apple-darwin-current:/opt/local/bin:/sbin:/usr/etc:/usr/sbin:/usr/local/bin:/usr/local/mysql/bin:/usr/X11R6/bin:.:/Users/luc/Dev/pbrt-1.02/bin</value>
+    <value type="QString">PBRT_SEARCHPATH=/Users/luc/Dev/pbrt-1.02/bin</value>
+    <value type="QString">PIXIEHOME=/Applications/Graphics/Pixie</value>
+    <value type="QString">PKG_CONFIG=/opt/local/bin/pkg-config</value>
+    <value type="QString">PKG_CONFIG_PATH=/opt/local/lib/pkgconfig</value>
+    <value type="QString">PLASMA=graffiti:0.0</value>
+    <value type="QString">PRINTER=evl2036ps</value>
+    <value type="QString">PWD=/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare</value>
+    <value type="QString">QTDIR=/usr/local/Qt4.6</value>
+    <value type="QString">REMOTEHOST=</value>
+    <value type="QString">SAGE_DIRECTORY=/Users/luc/Dev/SVN/sage3.0-ratko</value>
+    <value type="QString">SDL_WINDOW_POS=0x-50</value>
+    <value type="QString">SHELL=/bin/tcsh</value>
+    <value type="QString">SHLVL=1</value>
+    <value type="QString">SSH_AUTH_SOCK=/tmp/launch-RJ7KlT/Listeners</value>
+    <value type="QString">TERM=vt100</value>
+    <value type="QString">TERM_PROGRAM=Apple_Terminal</value>
+    <value type="QString">TERM_PROGRAM_VERSION=273</value>
+    <value type="QString">TMPDIR=/var/folders/7p/7pefsr17FgSHHtIsxeOpSE+++TI/-Tmp-/</value>
+    <value type="QString">USER=luc</value>
+    <value type="QString">VENDOR=apple</value>
+    <value type="QString">ZHORA=zhora:0.0</value>
+    <value type="QString">__CF_USER_TEXT_ENCODING=0x1F5:0:0</value>
+    <value type="QString">__GL_FSAA_MODE=5</value>
+    <value type="QString">__GL_SYNC_TO_VBLANK=1</value>
+   </valuelist>
+   <value key="abstractProcess.IgnoreReturnValue" type="bool">false</value>
+   <valuelist key="abstractProcess.arguments" type="QVariantList">
+    <value type="QString">-w</value>
+   </valuelist>
+   <value key="abstractProcess.command" type="QString">/usr/bin/make</value>
+   <value key="abstractProcess.enabled" type="bool">true</value>
+   <value key="abstractProcess.workingDirectory" type="QString">/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildconfiguration-Debug-cleanstep0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString">Debug</value>
+   <valuelist key="abstractProcess.Environment" type="QVariantList">
+    <value type="QString">Apple_PubSub_Socket_Render=/tmp/launch-0mwRH1/Render</value>
+    <value type="QString">CA_XLOG_KEY=125</value>
+    <value type="QString">COMMAND_MODE=unix2003</value>
+    <value type="QString">DAZSTUDIO=/Applications/DAZStudio</value>
+    <value type="QString">DAZSTUDIOVERSION=DAZStudio</value>
+    <value type="QString">DISPLAY=/tmp/launch-wXBWu8/org.x:0</value>
+    <value type="QString">GL_ENABLE_DEBUG_ATTACH=YES</value>
+    <value type="QString">HOME=/Users/luc</value>
+    <value type="QString">LOGNAME=luc</value>
+    <value type="QString">PATH=/Developer/Tools/Qt:/usr/bin:/bin:/usr/sbin:/sbin</value>
+    <value type="QString">QTDIR=/usr/local/Qt4.6</value>
+    <value type="QString">SHELL=/bin/tcsh</value>
+    <value type="QString">SSH_AUTH_SOCK=/tmp/launch-f9I54v/Listeners</value>
+    <value type="QString">TMPDIR=/var/folders/7p/7pefsr17FgSHHtIsxeOpSE+++TI/-Tmp-/</value>
+    <value type="QString">USER=luc</value>
+    <value type="QString">__CF_USER_TEXT_ENCODING=0x1F5:0:0</value>
+   </valuelist>
+   <value key="abstractProcess.IgnoreReturnValue" type="bool">true</value>
+   <valuelist key="abstractProcess.arguments" type="QVariantList">
+    <value type="QString">clean</value>
+    <value type="QString">-w</value>
+   </valuelist>
+   <value key="abstractProcess.command" type="QString">/usr/bin/make</value>
+   <value key="abstractProcess.enabled" type="bool">true</value>
+   <value key="abstractProcess.workingDirectory" type="QString">/Users/luc/Dev/SVN/sage3.0-ratko/app/qshare</value>
+   <value key="cleanConfig" type="bool">true</value>
+   <valuelist key="makeargs" type="QVariantList">
+    <value type="QString">clean</value>
+   </valuelist>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildconfigurations</variable>
+  <valuelist type="QVariantList">
+   <value type="QString">Debug</value>
+  </valuelist>
+ </data>
+ <data>
+  <variable>buildstep0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString"></value>
+   <value key="mkspec" type="QString"></value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildstep1</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString"></value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>buildsteps</variable>
+  <valuelist type="QVariantList">
+   <value type="QString">trolltech.qt4projectmanager.qmake</value>
+   <value type="QString">trolltech.qt4projectmanager.make</value>
+  </valuelist>
+ </data>
+ <data>
+  <variable>cleanstep0</variable>
+  <valuemap type="QVariantMap">
+   <value key="ProjectExplorer.BuildConfiguration.DisplayName" type="QString"></value>
+   <value key="clean" type="bool">true</value>
+  </valuemap>
+ </data>
+ <data>
+  <variable>cleansteps</variable>
+  <valuelist type="QVariantList">
+   <value type="QString">trolltech.qt4projectmanager.make</value>
+  </valuelist>
+ </data>
+ <data>
+  <variable>defaultFileEncoding</variable>
+  <value type="QByteArray">System</value>
+ </data>
+ <data>
+  <variable>project</variable>
+  <valuemap type="QVariantMap"/>
+ </data>
+</qtcreator>
Index: trunk/src/testing/app/qshare/GO.mac
===================================================================
--- trunk/src/testing/app/qshare/GO.mac	(revision 4)
+++ trunk/src/testing/app/qshare/GO.mac	(revision 4)
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+make distclean
+rm -fr qshare.app
+rm -fr qshare
+rm -f qshare.zip
+
+qmake -spec macx-g++
+
+make
+
+macdeployqt qshare.app
+
+cp $SAGE_DIRECTORY/lib/libsail.dylib qshare.app/Contents/Frameworks
+cp $SAGE_DIRECTORY/lib/libquanta.so qshare.app/Contents/Frameworks
+
+install_name_tool -id @executable_path/../Frameworks/libquanta.so qshare.app/Contents/Frameworks/libquanta.so
+install_name_tool -change libquanta.so @executable_path/../Frameworks/libquanta.so qshare.app/Contents/Frameworks/libsail.dylib
+
+mkdir qshare
+cp -r qshare.app qshare
+cp qshare.conf qshare
+cp *.png qshare
+
+zip -r -3 qshare qshare
+
Index: trunk/src/testing/app/qshare/GO
===================================================================
--- trunk/src/testing/app/qshare/GO	(revision 4)
+++ trunk/src/testing/app/qshare/GO	(revision 4)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+make distclean
+qmake
+make -j 4
+make install
Index: trunk/src/testing/app/qshare/main.cpp
===================================================================
--- trunk/src/testing/app/qshare/main.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/main.cpp	(revision 4)
@@ -0,0 +1,19 @@
+
+#include "capturewindow.h"
+
+
+int main(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
+
+    CaptureWindow *widget = new CaptureWindow;
+
+#if defined(__APPLE__)
+	//widget->setWindowIcon();
+#endif
+
+	widget->show();
+
+    return app.exec();
+}
+
Index: trunk/src/testing/app/qshare/capturewindow.ui
===================================================================
--- trunk/src/testing/app/qshare/capturewindow.ui	(revision 4)
+++ trunk/src/testing/app/qshare/capturewindow.ui	(revision 4)
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CaptureWindow</class>
+ <widget class="QMainWindow" name="CaptureWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>352</width>
+    <height>250</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>400</width>
+    <height>300</height>
+   </size>
+  </property>
+  <property name="baseSize">
+   <size>
+    <width>350</width>
+    <height>250</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Capture Window</string>
+  </property>
+  <property name="unifiedTitleAndToolBarOnMac">
+   <bool>true</bool>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QVBoxLayout" name="verticalLayout_3">
+    <item>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>SAGE IP address</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>Frame rate</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Compression</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>Cursor</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <item>
+         <widget class="QLineEdit" name="lineEdit">
+          <property name="text">
+           <string>127.0.0.1</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="spinBox">
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="maximum">
+           <number>100</number>
+          </property>
+          <property name="singleStep">
+           <number>1</number>
+          </property>
+          <property name="value">
+           <number>25</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="checkBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>DXT</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="checkBox_2">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>On</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </item>
+    <item>
+     <spacer name="verticalSpacer_2">
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>20</width>
+        <height>5</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+    <item>
+     <widget class="Line" name="line">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <layout class="QHBoxLayout" name="horizontalLayout_4">
+      <item>
+       <widget class="QPushButton" name="pushButton">
+        <property name="text">
+         <string>Start</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pushButton_2">
+        <property name="text">
+         <string>Pause</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pushButton_3">
+        <property name="text">
+         <string>Stop</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>352</width>
+     <height>22</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>onStart()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>63</x>
+     <y>213</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>174</x>
+     <y>129</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pushButton_2</sender>
+   <signal>clicked()</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>onPause()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>170</x>
+     <y>213</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>174</x>
+     <y>129</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pushButton_3</sender>
+   <signal>clicked()</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>onStop()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>277</x>
+     <y>213</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>174</x>
+     <y>129</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>lineEdit</sender>
+   <signal>textChanged(QString)</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>fsIP(QString)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>247</x>
+     <y>45</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>175</x>
+     <y>124</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>spinBox</sender>
+   <signal>valueChanged(int)</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>frameRate(int)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>247</x>
+     <y>79</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>175</x>
+     <y>124</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>checkBox</sender>
+   <signal>stateChanged(int)</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>compression(int)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>251</x>
+     <y>108</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>175</x>
+     <y>124</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>checkBox_2</sender>
+   <signal>stateChanged(int)</signal>
+   <receiver>CaptureWindow</receiver>
+   <slot>cursor(int)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>261</x>
+     <y>130</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>175</x>
+     <y>124</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+ <slots>
+  <slot>onStart()</slot>
+  <slot>onPause()</slot>
+  <slot>onStop()</slot>
+  <slot>fsIP(QString)</slot>
+  <slot>frameRate(int)</slot>
+  <slot>compression(int)</slot>
+  <slot>cursor(int)</slot>
+ </slots>
+</ui>
Index: trunk/src/testing/app/qshare/qshare.conf
===================================================================
--- trunk/src/testing/app/qshare/qshare.conf	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.conf	(revision 4)
@@ -0,0 +1,18 @@
+bridgeOn false
+bridgeIP 67.58.62.45
+bridgePort 42000
+fsIP  127.0.0.1
+fsPort 20002
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    2
+pixelBlockSize 256 256
+groupSize 262144
+winX 0
+winY 0
+nwProtocol TCP
+asyncUpdate true
+frameRate 30
Index: trunk/src/testing/app/qshare/qsharerc.rc
===================================================================
--- trunk/src/testing/app/qshare/qsharerc.rc	(revision 4)
+++ trunk/src/testing/app/qshare/qsharerc.rc	(revision 4)
@@ -0,0 +1,1 @@
+ IDI_ICON1               ICON    DISCARDABLE     "qshareico.ico"
Index: trunk/src/testing/app/qshare/capturewindow.cpp
===================================================================
--- trunk/src/testing/app/qshare/capturewindow.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/capturewindow.cpp	(revision 4)
@@ -0,0 +1,503 @@
+#include "capturewindow.h"
+
+#if defined(__linux__)
+
+#include <X11/Xutil.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xfixes.h>
+
+struct x11_grab
+{
+    int frame_size;          /* Size in bytes of a grabbed frame */
+    int height;              /* Height of the grab frame */
+    int width;               /* Width of the grab frame */
+    int x_off;               /* Horizontal top-left corner coordinate */
+    int y_off;               /* Vertical top-left corner coordinate */
+
+    Display *dpy;            /* X11 display from which x11grab grabs frames */
+    XImage *image;           /* X11 image holding the grab */
+    int use_shm;             /* !0 when using XShm extension */
+    XShmSegmentInfo shminfo; /* When using XShm, keeps track of XShm infos */
+    int nomouse;
+};
+
+struct x11_grab *x11grab;
+
+#endif
+
+#if defined(WIN32)
+HWND    hDesktopWnd;
+HDC     hDesktopDC;
+HDC     hCaptureDC;
+HBITMAP hCaptureBitmap;
+void*	pBits = NULL;
+#endif
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+// Compression
+#include "libdxt.h"
+
+// headers for SAGE
+GLubyte *rgbBuffer = NULL;
+GLubyte *dxtBuffer = NULL;
+sail sageInf;
+sailConfig scfg;
+
+
+CaptureWindow::CaptureWindow(QWidget *parent) :
+        QMainWindow(parent)
+{
+    dxt_aInitialize();
+
+    // Build the UI
+    ui.setupUi(this);
+    ui.statusBar->showMessage(QString("Desktop capture"), 0);
+
+	// Disable DXT for now
+	ui.checkBox->setEnabled(false);
+
+    // Get dimensions
+    QDesktopWidget *desktop = QApplication::desktop();
+    WW = desktop->width();
+    HH = desktop->height(); 
+    sage::printLog("QSHARE> Desktop width %d height %d", WW, HH);
+
+    // Set private variable
+    fps = 25;
+    started = false;
+    dxt = false;
+    count = 0;
+    showcursor = true;
+
+#if defined(__APPLE__)
+    /////////////////////////
+    // Get the OpenGL context
+    CGLPixelFormatObj pixelFormatObj ;
+    GLint numPixelFormats ;
+    CGDirectDisplayID displayId = CGMainDisplayID();
+    CGRect dRect = CGDisplayBounds( displayId );
+    WW = dRect.size.width;
+    HH = dRect.size.height;
+    CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(displayId);
+
+    CGLPixelFormatAttribute attribs[] =
+    {
+        (CGLPixelFormatAttribute)kCGLPFAFullScreen,
+        (CGLPixelFormatAttribute)kCGLPFADisplayMask,
+        (CGLPixelFormatAttribute)displayMask,
+        (CGLPixelFormatAttribute)0
+    };
+    CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
+    CGLCreateContext( pixelFormatObj, NULL, &glContextObj ) ;
+    CGLDestroyPixelFormat( pixelFormatObj ) ;
+    CGLSetCurrentContext( glContextObj ) ;
+    glReadBuffer(GL_FRONT);
+    CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
+    CGLSetCurrentContext( NULL );
+    qDebug() << "W " << WW << "  H" << HH;
+    /////////////////////////
+#endif
+
+#if defined(__linux__)
+    //
+    // Initialize x11 frame grabber
+    //
+    Display *dpy;
+    XImage *image;
+    int use_shm;
+
+    x11grab = (struct x11_grab*)malloc(sizeof(struct x11_grab));
+    memset(x11grab, 0, sizeof(struct x11_grab));
+
+    dpy = XOpenDisplay(0);
+    if(!dpy) {
+        sage::printLog("QSHARE> Could not open X display");
+    }
+ 
+    use_shm = XShmQueryExtension(dpy);
+    sage::printLog("QSHARE> shared memory extension %s found", use_shm ? "" : "not");
+
+    if(use_shm) {
+        int scr = XDefaultScreen(dpy);
+        image = XShmCreateImage(dpy,
+                                DefaultVisual(dpy, scr),
+                                DefaultDepth(dpy, scr),
+                                ZPixmap,
+                                NULL,
+                                &x11grab->shminfo,
+                                WW, HH);
+	sage::printLog("QSHARE> Image: widht %d  height %d bytes_per_line %d, depth %d", image->width,image->height,image->bytes_per_line, DefaultDepth(dpy, scr));
+        x11grab->shminfo.shmid = shmget(IPC_PRIVATE,
+                                        image->bytes_per_line * image->height,
+                                        IPC_CREAT|0777);
+        if (x11grab->shminfo.shmid == -1) {
+            sage::printLog("QSHARE> Fatal: Can't get shared memory!");
+        }
+        x11grab->shminfo.shmaddr = image->data = (char*)shmat(x11grab->shminfo.shmid, 0, 0);
+        x11grab->shminfo.readOnly = False;
+
+        if (!XShmAttach(dpy, &x11grab->shminfo)) {
+            sage::printLog("QSHARE> Fatal: Failed to attach shared memory!");
+        }
+    } else {
+        image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
+                          0, 0, WW, HH,
+                          AllPlanes, ZPixmap);
+    }
+
+    switch (image->bits_per_pixel) {
+    case 8:
+        sage::printLog("QSHARE> 8 bit palette");
+        //input_pixfmt = PIX_FMT_PAL8;
+        break;
+    case 16:
+        if (       image->red_mask   == 0xf800 &&
+                   image->green_mask == 0x07e0 &&
+                   image->blue_mask  == 0x001f ) {
+            sage::printLog("QSHARE> 16 bit RGB565");
+            //input_pixfmt = PIX_FMT_RGB565;
+        } else if (image->red_mask   == 0x7c00 &&
+                   image->green_mask == 0x03e0 &&
+                   image->blue_mask  == 0x001f ) {
+            sage::printLog("QSHARE> 16 bit RGB555");
+            //input_pixfmt = PIX_FMT_RGB555;
+        } else {
+            sage::printLog("QSHARE> RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel);
+            sage::printLog("QSHARE> color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask);
+        }
+        break;
+    case 24:
+        if (        image->red_mask   == 0xff0000 &&
+                    image->green_mask == 0x00ff00 &&
+                    image->blue_mask  == 0x0000ff ) {
+            sage::printLog("QSHARE> 24 bit BGR24");
+            //input_pixfmt = PIX_FMT_BGR24;
+        } else if ( image->red_mask   == 0x0000ff &&
+                    image->green_mask == 0x00ff00 &&
+                    image->blue_mask  == 0xff0000 ) {
+	    sage::printLog("QSHARE> 24 bit RGB24");
+            //input_pixfmt = PIX_FMT_RGB24;
+       } else {
+            sage::printLog("QSHARE> rgb ordering at image depth %i not supported ... aborting", image->bits_per_pixel);
+	    sage::printLog("QSHARE> color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx", image->red_mask, image->green_mask, image->blue_mask);
+        }
+        break;
+    case 32:
+	sage::printLog("QSHARE> 32 bit RGB32");
+	//input_pixfmt = PIX_FMT_RGB32;
+        break;
+    default:
+        sage::printLog("QSHARE> image depth %i not supported ... aborting", image->bits_per_pixel);
+    }
+    x11grab->nomouse = 1;
+    x11grab->frame_size = WW * HH * image->bits_per_pixel/8;
+    x11grab->dpy = dpy;
+    x11grab->width = WW;
+    x11grab->height = HH;
+    x11grab->x_off = 0;
+    x11grab->y_off = 0;
+    x11grab->image = image;
+    x11grab->use_shm = use_shm;   
+#endif
+
+#if defined(WIN32)
+    BITMAPINFO	bmpInfo;
+    ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+    bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+    bmpInfo.bmiHeader.biBitCount=24;//BITSPERPIXEL;
+    bmpInfo.bmiHeader.biCompression = BI_RGB;
+    bmpInfo.bmiHeader.biWidth=WW;
+    bmpInfo.bmiHeader.biHeight=HH;
+    bmpInfo.bmiHeader.biPlanes=1;
+    bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;
+
+    hDesktopWnd = GetDesktopWindow();
+    hDesktopDC = GetDC(hDesktopWnd);
+    hCaptureDC = CreateCompatibleDC(hDesktopDC);
+    hCaptureBitmap = CreateDIBSection(hDesktopDC,&bmpInfo,DIB_RGB_COLORS,&pBits,NULL,0);
+    SelectObject(hCaptureDC,hCaptureBitmap);
+#endif
+
+    // Enables buttons
+    ui.pushButton->setEnabled(true);
+    ui.pushButton_2->setEnabled(false);
+    ui.pushButton_3->setEnabled(false);
+
+    // Load the pointer
+    cursor_icon = new QImage("arrow2.png");
+
+    // Load SAIL config
+    scfg.init((char*)"qshare.conf");
+    scfg.setAppName((char*)"qshare");
+
+    fsip = QString(scfg.fsIP);
+    qDebug() << "FSIP " << fsip;
+    ui.lineEdit->setText(fsip);
+
+    // Timer setup
+    timer = new QTimer(this);
+    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
+}
+
+void CaptureWindow::closeEvent(QCloseEvent *event)
+{
+#if defined(__linux__)
+    //
+    // Close x11 frame grabber
+    //
+		
+    // Detach cleanly from shared mem
+    // if (x11grab && x11grab->use_shm) {
+    // 	XShmDetach(x11grab->dpy, &x11grab->shminfo);
+    // 	shmdt(x11grab->shminfo.shmaddr);
+    // 	shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL);
+    // }
+		
+    // Destroy X11 image
+    // if (x11grab && x11grab->image) {
+    // 	XDestroyImage(x11grab->image);
+    // 	x11grab->image = NULL;
+    // }
+		
+    // Free X11 display
+    // if (x11grab)
+    // 	XCloseDisplay(x11grab->dpy);
+#endif
+    onStop();
+    event->accept();
+}
+
+void CaptureWindow::frameRate(int f)
+{
+    fps = f;
+    qDebug() << "framerate " << fps;
+    timer->setInterval(1000/fps);
+}
+
+
+void CaptureWindow::fsIP(QString f)
+{
+    fsip = f;
+    qDebug() << "FSIP changed" << fsip;
+}
+
+void CaptureWindow::update()
+{
+    if (started) {
+
+        // Capture the desktop pixels
+        capture((char*)rgbBuffer,0,0,WW,HH);
+
+        if (showcursor) {
+	    // Get mouse position
+            QPoint pt = QCursor::pos();
+
+	    // Flip the Y value
+            int adjust = HH - pt.y();
+	    if (adjust < 0) adjust = 0;
+            pt.setY(adjust);
+	    
+	    // Compute boundaries
+            int startx = MAX(0,pt.x());
+            // int starty = MAX(0, pt.y()-cursor_icon->height());
+            int starty = pt.y()-cursor_icon->height();
+	    
+	    // Compose desktop with cursor
+            QImage resultImage = QImage((uchar*)rgbBuffer, WW, HH, QImage::Format_RGB888);
+            QPainter painter(&resultImage);
+            painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+            painter.drawImage(startx, starty, *cursor_icon);
+            painter.end();
+	    // rgbBuffer is filled after that point
+        }
+
+        if (dxt)
+        {
+            CompressDXT(rgbBuffer, dxtBuffer, WW, HH, FORMAT_DXT1, 1);
+            sageInf.swapBuffer();
+            dxtBuffer = (GLubyte *)sageInf.getBuffer();
+        }
+        else
+        {
+            sageInf.swapBuffer();
+            rgbBuffer = (GLubyte *)sageInf.getBuffer();
+        }
+
+        sageMessage msg;
+        if (sageInf.checkMsg(msg, false) > 0) {
+            switch (msg.getCode()) {
+            case APP_QUIT:
+		exit(1);
+                break;
+            }
+        }
+
+
+        QString str;
+        double nowt = dxt_aTime();
+        //qDebug() << "now " << nowt << "   startt" << startt;
+        double dfps = 1.0 / (nowt - startt);
+        str = QString("%1 ms / %2 fps/ # %3 / DXT %4 / %5x%6").arg(nowt-startt,5,'f',1).arg(dfps,5,'f',1).arg(count++).arg(dxt).arg(WW).arg(HH);
+        ui.statusBar->showMessage( str, 0 );
+
+#if 1
+        if (dfps < fps) {
+            timer->start( MAX(0, (2*(1000/fps)-(1000/dfps) ) ) );
+        }
+        else
+            timer->start(1000/fps);
+#else
+        timer->start(0);
+#endif
+        startt = nowt;
+    }
+}
+
+void CaptureWindow::capture(char* m_pFrameRGB,int x,int y,int cx,int cy)
+{
+#if defined(__APPLE__)
+    CGLSetCurrentContext( glContextObj ) ;
+    //CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
+    //glReadBuffer(GL_FRONT);
+
+    if (dxt)
+        glReadPixels(x,y,cx,cy,GL_RGBA,GL_UNSIGNED_BYTE,m_pFrameRGB);
+    else
+        glReadPixels(x,y,cx,cy,GL_RGB,GL_UNSIGNED_BYTE,m_pFrameRGB);
+
+    CGLSetCurrentContext( NULL );
+#endif
+
+#if defined(__linux__)
+    if (x11grab->use_shm) {
+	if (!XShmGetImage(x11grab->dpy, RootWindow(x11grab->dpy, DefaultScreen(x11grab->dpy)),
+			  x11grab->image, 0, 0, AllPlanes)) {
+	    sage::printLog("QSHARE> XShmGetImage() failed");
+	}
+	else {
+	    // Upside-down and RGBA-to-RGB conversion
+	    for (int i = 0 ; i < cy; i++) {
+		for (int j = 0 ; j < cx; j++) {
+		    m_pFrameRGB [ (i*cx+j) * 3 + 0 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 2 ];
+		    m_pFrameRGB [ (i*cx+j) * 3 + 1 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 1 ];
+		    m_pFrameRGB [ (i*cx+j) * 3 + 2 ] = x11grab->image->data [ ((cy-i-1)*cx+j) * 4 + 0 ];
+		}
+	    }
+	}
+    } 
+#endif
+
+#if defined(WIN32)
+	BitBlt(hCaptureDC,0,0,WW,HH,hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
+	memcpy(m_pFrameRGB, pBits, WW*HH*3);
+#endif
+}
+
+void CaptureWindow::onStart()
+{
+    if (! started) {
+        ui.pushButton->setEnabled(false);
+        ui.pushButton_2->setEnabled(true);
+        ui.pushButton_3->setEnabled(true);
+        ui.lineEdit->setEnabled(false);
+        ui.spinBox->setEnabled(true);
+        ui.checkBox->setEnabled(false);
+
+        qDebug() << "On Start";
+
+        sageRect ishareImageMap;
+        ishareImageMap.left = 0.0;
+        ishareImageMap.right = 1.0;
+        ishareImageMap.bottom = 0.0;
+        ishareImageMap.top = 1.0;
+
+        scfg.rank = 0;
+        scfg.resX = WW;
+        scfg.resY = HH;
+        scfg.winWidth  = WW;
+        scfg.winHeight = HH;
+        scfg.imageMap = ishareImageMap;
+	
+	// Copy back the text box into the SAGE variable
+	memset(scfg.fsIP, 0, SAGE_IP_LEN);
+	strncpy(scfg.fsIP, fsip.toAscii().constData(), SAGE_IP_LEN);
+
+        if (dxt)
+            scfg.pixFmt = PIXFMT_DXT;
+        else
+#if defined(WIN32)
+			scfg.pixFmt = PIXFMT_888_INV; // for some reasons, win32 is BGR
+#else
+			scfg.pixFmt = PIXFMT_888;
+#endif
+
+        scfg.rowOrd = BOTTOM_TO_TOP;
+        scfg.master = true;
+
+        sageInf.init(scfg);
+
+        if (dxt) {
+            dxtBuffer = (GLubyte *)sageInf.getBuffer();
+            if (rgbBuffer) delete [] rgbBuffer;
+            rgbBuffer = (byte*)memalign(16, WW*HH*4);
+            memset(rgbBuffer, 0,  WW*HH*4);
+        }
+        else {
+            rgbBuffer = (GLubyte *)sageInf.getBuffer();
+        }
+
+
+        started = true;
+        timer->setSingleShot(true);
+        timer->start(1000/fps);
+        //timer->start();
+
+        startt = dxt_aTime();
+    }
+}
+
+void CaptureWindow::compression(int c)
+{
+    dxt = c;
+}
+
+void CaptureWindow::cursor(int c)
+{
+    showcursor = c;
+}
+
+void CaptureWindow::onStop()
+{
+    qDebug() << "On Stop";
+    started = false;
+    timer->stop();
+    ui.pushButton->setEnabled(true);
+    ui.pushButton_2->setEnabled(false);
+    ui.pushButton_3->setEnabled(false);
+    ui.lineEdit->setEnabled(true);
+    ui.spinBox->setEnabled(true);
+    ui.checkBox->setEnabled(true);
+    sageInf.shutdown();
+}
+
+void CaptureWindow::onPause()
+{
+    if (started) {
+        qDebug() << "Pause";
+        started = false;
+        timer->stop();
+    }
+    else {
+        qDebug() << "UnPause";
+        started = true;
+        timer->start(1000/fps);
+    }
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+
Index: trunk/src/testing/app/qshare/FastDXT/glext.h
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/glext.h	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/glext.h	(revision 4)
@@ -0,0 +1,6531 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef __glext_h_
+#define __glext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: This software was created using the
+** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has
+** not been independently verified as being compliant with the OpenGL(R)
+** version 1.2.1 Specification.
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+/*************************************************************/
+
+/* Header file version number, required by OpenGL ABI for Linux */
+/* glext.h last updated 2005/06/20 */
+/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */
+#define GL_GLEXT_VERSION 29
+
+#ifndef GL_VERSION_1_2
+#define GL_UNSIGNED_BYTE_3_3_2            0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_INT_8_8_8_8           0x8035
+#define GL_UNSIGNED_INT_10_10_10_2        0x8036
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_TEXTURE_BINDING_3D             0x806A
+#define GL_PACK_SKIP_IMAGES               0x806B
+#define GL_PACK_IMAGE_HEIGHT              0x806C
+#define GL_UNPACK_SKIP_IMAGES             0x806D
+#define GL_UNPACK_IMAGE_HEIGHT            0x806E
+#define GL_TEXTURE_3D                     0x806F
+#define GL_PROXY_TEXTURE_3D               0x8070
+#define GL_TEXTURE_DEPTH                  0x8071
+#define GL_TEXTURE_WRAP_R                 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE            0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV        0x8362
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV       0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV     0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV     0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#define GL_BGR                            0x80E0
+#define GL_BGRA                           0x80E1
+#define GL_MAX_ELEMENTS_VERTICES          0x80E8
+#define GL_MAX_ELEMENTS_INDICES           0x80E9
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_TEXTURE_MIN_LOD                0x813A
+#define GL_TEXTURE_MAX_LOD                0x813B
+#define GL_TEXTURE_BASE_LEVEL             0x813C
+#define GL_TEXTURE_MAX_LEVEL              0x813D
+#define GL_LIGHT_MODEL_COLOR_CONTROL      0x81F8
+#define GL_SINGLE_COLOR                   0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR        0x81FA
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY  0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY  0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#endif
+
+#ifndef GL_ARB_imaging
+#define GL_CONSTANT_COLOR                 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002
+#define GL_CONSTANT_ALPHA                 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004
+#define GL_BLEND_COLOR                    0x8005
+#define GL_FUNC_ADD                       0x8006
+#define GL_MIN                            0x8007
+#define GL_MAX                            0x8008
+#define GL_BLEND_EQUATION                 0x8009
+#define GL_FUNC_SUBTRACT                  0x800A
+#define GL_FUNC_REVERSE_SUBTRACT          0x800B
+#define GL_CONVOLUTION_1D                 0x8010
+#define GL_CONVOLUTION_2D                 0x8011
+#define GL_SEPARABLE_2D                   0x8012
+#define GL_CONVOLUTION_BORDER_MODE        0x8013
+#define GL_CONVOLUTION_FILTER_SCALE       0x8014
+#define GL_CONVOLUTION_FILTER_BIAS        0x8015
+#define GL_REDUCE                         0x8016
+#define GL_CONVOLUTION_FORMAT             0x8017
+#define GL_CONVOLUTION_WIDTH              0x8018
+#define GL_CONVOLUTION_HEIGHT             0x8019
+#define GL_MAX_CONVOLUTION_WIDTH          0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT         0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE     0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS      0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023
+#define GL_HISTOGRAM                      0x8024
+#define GL_PROXY_HISTOGRAM                0x8025
+#define GL_HISTOGRAM_WIDTH                0x8026
+#define GL_HISTOGRAM_FORMAT               0x8027
+#define GL_HISTOGRAM_RED_SIZE             0x8028
+#define GL_HISTOGRAM_GREEN_SIZE           0x8029
+#define GL_HISTOGRAM_BLUE_SIZE            0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE           0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C
+#define GL_HISTOGRAM_SINK                 0x802D
+#define GL_MINMAX                         0x802E
+#define GL_MINMAX_FORMAT                  0x802F
+#define GL_MINMAX_SINK                    0x8030
+#define GL_TABLE_TOO_LARGE                0x8031
+#define GL_COLOR_MATRIX                   0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB
+#define GL_COLOR_TABLE                    0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2
+#define GL_PROXY_COLOR_TABLE              0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE              0x80D6
+#define GL_COLOR_TABLE_BIAS               0x80D7
+#define GL_COLOR_TABLE_FORMAT             0x80D8
+#define GL_COLOR_TABLE_WIDTH              0x80D9
+#define GL_COLOR_TABLE_RED_SIZE           0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF
+#define GL_CONSTANT_BORDER                0x8151
+#define GL_REPLICATE_BORDER               0x8153
+#define GL_CONVOLUTION_BORDER_COLOR       0x8154
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+#define GL_MULTISAMPLE_BIT                0x20000000
+#define GL_NORMAL_MAP                     0x8511
+#define GL_REFLECTION_MAP                 0x8512
+#define GL_TEXTURE_CUBE_MAP               0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+#define GL_COMPRESSED_ALPHA               0x84E9
+#define GL_COMPRESSED_LUMINANCE           0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB
+#define GL_COMPRESSED_INTENSITY           0x84EC
+#define GL_COMPRESSED_RGB                 0x84ED
+#define GL_COMPRESSED_RGBA                0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT       0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0
+#define GL_TEXTURE_COMPRESSED             0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+#define GL_CLAMP_TO_BORDER                0x812D
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_SOURCE0_RGB                    0x8580
+#define GL_SOURCE1_RGB                    0x8581
+#define GL_SOURCE2_RGB                    0x8582
+#define GL_SOURCE0_ALPHA                  0x8588
+#define GL_SOURCE1_ALPHA                  0x8589
+#define GL_SOURCE2_ALPHA                  0x858A
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_SUBTRACT                       0x84E7
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_BLEND_DST_RGB                  0x80C8
+#define GL_BLEND_SRC_RGB                  0x80C9
+#define GL_BLEND_DST_ALPHA                0x80CA
+#define GL_BLEND_SRC_ALPHA                0x80CB
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_GENERATE_MIPMAP                0x8191
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+#define GL_DEPTH_COMPONENT16              0x81A5
+#define GL_DEPTH_COMPONENT24              0x81A6
+#define GL_DEPTH_COMPONENT32              0x81A7
+#define GL_MIRRORED_REPEAT                0x8370
+#define GL_FOG_COORDINATE_SOURCE          0x8450
+#define GL_FOG_COORDINATE                 0x8451
+#define GL_FRAGMENT_DEPTH                 0x8452
+#define GL_CURRENT_FOG_COORDINATE         0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE      0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE    0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER   0x8456
+#define GL_FOG_COORDINATE_ARRAY           0x8457
+#define GL_COLOR_SUM                      0x8458
+#define GL_CURRENT_SECONDARY_COLOR        0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE     0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE     0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE   0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER  0x845D
+#define GL_SECONDARY_COLOR_ARRAY          0x845E
+#define GL_MAX_TEXTURE_LOD_BIAS           0x84FD
+#define GL_TEXTURE_FILTER_CONTROL         0x8500
+#define GL_TEXTURE_LOD_BIAS               0x8501
+#define GL_INCR_WRAP                      0x8507
+#define GL_DECR_WRAP                      0x8508
+#define GL_TEXTURE_DEPTH_SIZE             0x884A
+#define GL_DEPTH_TEXTURE_MODE             0x884B
+#define GL_TEXTURE_COMPARE_MODE           0x884C
+#define GL_TEXTURE_COMPARE_FUNC           0x884D
+#define GL_COMPARE_R_TO_TEXTURE           0x884E
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+#define GL_QUERY_COUNTER_BITS             0x8864
+#define GL_CURRENT_QUERY                  0x8865
+#define GL_QUERY_RESULT                   0x8866
+#define GL_QUERY_RESULT_AVAILABLE         0x8867
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+#define GL_ARRAY_BUFFER_BINDING           0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING    0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING    0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING     0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING     0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING    0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY                      0x88B8
+#define GL_WRITE_ONLY                     0x88B9
+#define GL_READ_WRITE                     0x88BA
+#define GL_BUFFER_ACCESS                  0x88BB
+#define GL_BUFFER_MAPPED                  0x88BC
+#define GL_BUFFER_MAP_POINTER             0x88BD
+#define GL_STREAM_DRAW                    0x88E0
+#define GL_STREAM_READ                    0x88E1
+#define GL_STREAM_COPY                    0x88E2
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_STATIC_READ                    0x88E5
+#define GL_STATIC_COPY                    0x88E6
+#define GL_DYNAMIC_DRAW                   0x88E8
+#define GL_DYNAMIC_READ                   0x88E9
+#define GL_DYNAMIC_COPY                   0x88EA
+#define GL_SAMPLES_PASSED                 0x8914
+#define GL_FOG_COORD_SRC                  GL_FOG_COORDINATE_SOURCE
+#define GL_FOG_COORD                      GL_FOG_COORDINATE
+#define GL_CURRENT_FOG_COORD              GL_CURRENT_FOG_COORDINATE
+#define GL_FOG_COORD_ARRAY_TYPE           GL_FOG_COORDINATE_ARRAY_TYPE
+#define GL_FOG_COORD_ARRAY_STRIDE         GL_FOG_COORDINATE_ARRAY_STRIDE
+#define GL_FOG_COORD_ARRAY_POINTER        GL_FOG_COORDINATE_ARRAY_POINTER
+#define GL_FOG_COORD_ARRAY                GL_FOG_COORDINATE_ARRAY
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
+#define GL_SRC0_RGB                       GL_SOURCE0_RGB
+#define GL_SRC1_RGB                       GL_SOURCE1_RGB
+#define GL_SRC2_RGB                       GL_SOURCE2_RGB
+#define GL_SRC0_ALPHA                     GL_SOURCE0_ALPHA
+#define GL_SRC1_ALPHA                     GL_SOURCE1_ALPHA
+#define GL_SRC2_ALPHA                     GL_SOURCE2_ALPHA
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_BLEND_EQUATION_RGB             GL_BLEND_EQUATION
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625
+#define GL_CURRENT_VERTEX_ATTRIB          0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE      0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE        0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645
+#define GL_STENCIL_BACK_FUNC              0x8800
+#define GL_STENCIL_BACK_FAIL              0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803
+#define GL_MAX_DRAW_BUFFERS               0x8824
+#define GL_DRAW_BUFFER0                   0x8825
+#define GL_DRAW_BUFFER1                   0x8826
+#define GL_DRAW_BUFFER2                   0x8827
+#define GL_DRAW_BUFFER3                   0x8828
+#define GL_DRAW_BUFFER4                   0x8829
+#define GL_DRAW_BUFFER5                   0x882A
+#define GL_DRAW_BUFFER6                   0x882B
+#define GL_DRAW_BUFFER7                   0x882C
+#define GL_DRAW_BUFFER8                   0x882D
+#define GL_DRAW_BUFFER9                   0x882E
+#define GL_DRAW_BUFFER10                  0x882F
+#define GL_DRAW_BUFFER11                  0x8830
+#define GL_DRAW_BUFFER12                  0x8831
+#define GL_DRAW_BUFFER13                  0x8832
+#define GL_DRAW_BUFFER14                  0x8833
+#define GL_DRAW_BUFFER15                  0x8834
+#define GL_BLEND_EQUATION_ALPHA           0x883D
+#define GL_POINT_SPRITE                   0x8861
+#define GL_COORD_REPLACE                  0x8862
+#define GL_MAX_VERTEX_ATTRIBS             0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_COORDS             0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS        0x8872
+#define GL_FRAGMENT_SHADER                0x8B30
+#define GL_VERTEX_SHADER                  0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS  0x8B4A
+#define GL_MAX_VARYING_FLOATS             0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE                    0x8B4F
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_SAMPLER_1D                     0x8B5D
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_3D                     0x8B5F
+#define GL_SAMPLER_CUBE                   0x8B60
+#define GL_SAMPLER_1D_SHADOW              0x8B61
+#define GL_SAMPLER_2D_SHADOW              0x8B62
+#define GL_DELETE_STATUS                  0x8B80
+#define GL_COMPILE_STATUS                 0x8B81
+#define GL_LINK_STATUS                    0x8B82
+#define GL_VALIDATE_STATUS                0x8B83
+#define GL_INFO_LOG_LENGTH                0x8B84
+#define GL_ATTACHED_SHADERS               0x8B85
+#define GL_ACTIVE_UNIFORMS                0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH      0x8B87
+#define GL_SHADER_SOURCE_LENGTH           0x8B88
+#define GL_ACTIVE_ATTRIBUTES              0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH    0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION       0x8B8C
+#define GL_CURRENT_PROGRAM                0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN      0x8CA0
+#define GL_LOWER_LEFT                     0x8CA1
+#define GL_UPPER_LEFT                     0x8CA2
+#define GL_STENCIL_BACK_REF               0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK         0x8CA5
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_TEXTURE0_ARB                   0x84C0
+#define GL_TEXTURE1_ARB                   0x84C1
+#define GL_TEXTURE2_ARB                   0x84C2
+#define GL_TEXTURE3_ARB                   0x84C3
+#define GL_TEXTURE4_ARB                   0x84C4
+#define GL_TEXTURE5_ARB                   0x84C5
+#define GL_TEXTURE6_ARB                   0x84C6
+#define GL_TEXTURE7_ARB                   0x84C7
+#define GL_TEXTURE8_ARB                   0x84C8
+#define GL_TEXTURE9_ARB                   0x84C9
+#define GL_TEXTURE10_ARB                  0x84CA
+#define GL_TEXTURE11_ARB                  0x84CB
+#define GL_TEXTURE12_ARB                  0x84CC
+#define GL_TEXTURE13_ARB                  0x84CD
+#define GL_TEXTURE14_ARB                  0x84CE
+#define GL_TEXTURE15_ARB                  0x84CF
+#define GL_TEXTURE16_ARB                  0x84D0
+#define GL_TEXTURE17_ARB                  0x84D1
+#define GL_TEXTURE18_ARB                  0x84D2
+#define GL_TEXTURE19_ARB                  0x84D3
+#define GL_TEXTURE20_ARB                  0x84D4
+#define GL_TEXTURE21_ARB                  0x84D5
+#define GL_TEXTURE22_ARB                  0x84D6
+#define GL_TEXTURE23_ARB                  0x84D7
+#define GL_TEXTURE24_ARB                  0x84D8
+#define GL_TEXTURE25_ARB                  0x84D9
+#define GL_TEXTURE26_ARB                  0x84DA
+#define GL_TEXTURE27_ARB                  0x84DB
+#define GL_TEXTURE28_ARB                  0x84DC
+#define GL_TEXTURE29_ARB                  0x84DD
+#define GL_TEXTURE30_ARB                  0x84DE
+#define GL_TEXTURE31_ARB                  0x84DF
+#define GL_ACTIVE_TEXTURE_ARB             0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_MULTISAMPLE_ARB                0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F
+#define GL_SAMPLE_COVERAGE_ARB            0x80A0
+#define GL_SAMPLE_BUFFERS_ARB             0x80A8
+#define GL_SAMPLES_ARB                    0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB
+#define GL_MULTISAMPLE_BIT_ARB            0x20000000
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_NORMAL_MAP_ARB                 0x8511
+#define GL_REFLECTION_MAP_ARB             0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_COMPRESSED_ALPHA_ARB           0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB       0x84EC
+#define GL_COMPRESSED_RGB_ARB             0x84ED
+#define GL_COMPRESSED_RGBA_ARB            0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB         0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_ARB            0x812D
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_POINT_SIZE_MIN_ARB             0x8126
+#define GL_POINT_SIZE_MAX_ARB             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_MAX_VERTEX_UNITS_ARB           0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6
+#define GL_VERTEX_BLEND_ARB               0x86A7
+#define GL_CURRENT_WEIGHT_ARB             0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC
+#define GL_WEIGHT_ARRAY_ARB               0x86AD
+#define GL_MODELVIEW0_ARB                 0x1700
+#define GL_MODELVIEW1_ARB                 0x850A
+#define GL_MODELVIEW2_ARB                 0x8722
+#define GL_MODELVIEW3_ARB                 0x8723
+#define GL_MODELVIEW4_ARB                 0x8724
+#define GL_MODELVIEW5_ARB                 0x8725
+#define GL_MODELVIEW6_ARB                 0x8726
+#define GL_MODELVIEW7_ARB                 0x8727
+#define GL_MODELVIEW8_ARB                 0x8728
+#define GL_MODELVIEW9_ARB                 0x8729
+#define GL_MODELVIEW10_ARB                0x872A
+#define GL_MODELVIEW11_ARB                0x872B
+#define GL_MODELVIEW12_ARB                0x872C
+#define GL_MODELVIEW13_ARB                0x872D
+#define GL_MODELVIEW14_ARB                0x872E
+#define GL_MODELVIEW15_ARB                0x872F
+#define GL_MODELVIEW16_ARB                0x8730
+#define GL_MODELVIEW17_ARB                0x8731
+#define GL_MODELVIEW18_ARB                0x8732
+#define GL_MODELVIEW19_ARB                0x8733
+#define GL_MODELVIEW20_ARB                0x8734
+#define GL_MODELVIEW21_ARB                0x8735
+#define GL_MODELVIEW22_ARB                0x8736
+#define GL_MODELVIEW23_ARB                0x8737
+#define GL_MODELVIEW24_ARB                0x8738
+#define GL_MODELVIEW25_ARB                0x8739
+#define GL_MODELVIEW26_ARB                0x873A
+#define GL_MODELVIEW27_ARB                0x873B
+#define GL_MODELVIEW28_ARB                0x873C
+#define GL_MODELVIEW29_ARB                0x873D
+#define GL_MODELVIEW30_ARB                0x873E
+#define GL_MODELVIEW31_ARB                0x873F
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_MATRIX_PALETTE_ARB             0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB       0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_COMBINE_ARB                    0x8570
+#define GL_COMBINE_RGB_ARB                0x8571
+#define GL_COMBINE_ALPHA_ARB              0x8572
+#define GL_SOURCE0_RGB_ARB                0x8580
+#define GL_SOURCE1_RGB_ARB                0x8581
+#define GL_SOURCE2_RGB_ARB                0x8582
+#define GL_SOURCE0_ALPHA_ARB              0x8588
+#define GL_SOURCE1_ALPHA_ARB              0x8589
+#define GL_SOURCE2_ALPHA_ARB              0x858A
+#define GL_OPERAND0_RGB_ARB               0x8590
+#define GL_OPERAND1_RGB_ARB               0x8591
+#define GL_OPERAND2_RGB_ARB               0x8592
+#define GL_OPERAND0_ALPHA_ARB             0x8598
+#define GL_OPERAND1_ALPHA_ARB             0x8599
+#define GL_OPERAND2_ALPHA_ARB             0x859A
+#define GL_RGB_SCALE_ARB                  0x8573
+#define GL_ADD_SIGNED_ARB                 0x8574
+#define GL_INTERPOLATE_ARB                0x8575
+#define GL_SUBTRACT_ARB                   0x84E7
+#define GL_CONSTANT_ARB                   0x8576
+#define GL_PRIMARY_COLOR_ARB              0x8577
+#define GL_PREVIOUS_ARB                   0x8578
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_DOT3_RGB_ARB                   0x86AE
+#define GL_DOT3_RGBA_ARB                  0x86AF
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_ARB            0x8370
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_DEPTH_COMPONENT16_ARB          0x81A5
+#define GL_DEPTH_COMPONENT24_ARB          0x81A6
+#define GL_DEPTH_COMPONENT32_ARB          0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif
+
+#ifndef GL_ARB_window_pos
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_COLOR_SUM_ARB                  0x8458
+#define GL_VERTEX_PROGRAM_ARB             0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626
+#define GL_PROGRAM_LENGTH_ARB             0x8627
+#define GL_PROGRAM_STRING_ARB             0x8628
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_CURRENT_MATRIX_ARB             0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B
+#define GL_PROGRAM_BINDING_ARB            0x8677
+#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ERROR_STRING_ARB       0x8874
+#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
+#define GL_PROGRAM_FORMAT_ARB             0x8876
+#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB         0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB            0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7
+#define GL_MATRIX0_ARB                    0x88C0
+#define GL_MATRIX1_ARB                    0x88C1
+#define GL_MATRIX2_ARB                    0x88C2
+#define GL_MATRIX3_ARB                    0x88C3
+#define GL_MATRIX4_ARB                    0x88C4
+#define GL_MATRIX5_ARB                    0x88C5
+#define GL_MATRIX6_ARB                    0x88C6
+#define GL_MATRIX7_ARB                    0x88C7
+#define GL_MATRIX8_ARB                    0x88C8
+#define GL_MATRIX9_ARB                    0x88C9
+#define GL_MATRIX10_ARB                   0x88CA
+#define GL_MATRIX11_ARB                   0x88CB
+#define GL_MATRIX12_ARB                   0x88CC
+#define GL_MATRIX13_ARB                   0x88CD
+#define GL_MATRIX14_ARB                   0x88CE
+#define GL_MATRIX15_ARB                   0x88CF
+#define GL_MATRIX16_ARB                   0x88D0
+#define GL_MATRIX17_ARB                   0x88D1
+#define GL_MATRIX18_ARB                   0x88D2
+#define GL_MATRIX19_ARB                   0x88D3
+#define GL_MATRIX20_ARB                   0x88D4
+#define GL_MATRIX21_ARB                   0x88D5
+#define GL_MATRIX22_ARB                   0x88D6
+#define GL_MATRIX23_ARB                   0x88D7
+#define GL_MATRIX24_ARB                   0x88D8
+#define GL_MATRIX25_ARB                   0x88D9
+#define GL_MATRIX26_ARB                   0x88DA
+#define GL_MATRIX27_ARB                   0x88DB
+#define GL_MATRIX28_ARB                   0x88DC
+#define GL_MATRIX29_ARB                   0x88DD
+#define GL_MATRIX30_ARB                   0x88DE
+#define GL_MATRIX31_ARB                   0x88DF
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_FRAGMENT_PROGRAM_ARB           0x8804
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_MAX_TEXTURE_COORDS_ARB         0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_BUFFER_SIZE_ARB                0x8764
+#define GL_BUFFER_USAGE_ARB               0x8765
+#define GL_ARRAY_BUFFER_ARB               0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB                  0x88B8
+#define GL_WRITE_ONLY_ARB                 0x88B9
+#define GL_READ_WRITE_ARB                 0x88BA
+#define GL_BUFFER_ACCESS_ARB              0x88BB
+#define GL_BUFFER_MAPPED_ARB              0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#define GL_STREAM_DRAW_ARB                0x88E0
+#define GL_STREAM_READ_ARB                0x88E1
+#define GL_STREAM_COPY_ARB                0x88E2
+#define GL_STATIC_DRAW_ARB                0x88E4
+#define GL_STATIC_READ_ARB                0x88E5
+#define GL_STATIC_COPY_ARB                0x88E6
+#define GL_DYNAMIC_DRAW_ARB               0x88E8
+#define GL_DYNAMIC_READ_ARB               0x88E9
+#define GL_DYNAMIC_COPY_ARB               0x88EA
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_QUERY_COUNTER_BITS_ARB         0x8864
+#define GL_CURRENT_QUERY_ARB              0x8865
+#define GL_QUERY_RESULT_ARB               0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867
+#define GL_SAMPLES_PASSED_ARB             0x8914
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_PROGRAM_OBJECT_ARB             0x8B40
+#define GL_SHADER_OBJECT_ARB              0x8B48
+#define GL_OBJECT_TYPE_ARB                0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB             0x8B4F
+#define GL_FLOAT_VEC2_ARB                 0x8B50
+#define GL_FLOAT_VEC3_ARB                 0x8B51
+#define GL_FLOAT_VEC4_ARB                 0x8B52
+#define GL_INT_VEC2_ARB                   0x8B53
+#define GL_INT_VEC3_ARB                   0x8B54
+#define GL_INT_VEC4_ARB                   0x8B55
+#define GL_BOOL_ARB                       0x8B56
+#define GL_BOOL_VEC2_ARB                  0x8B57
+#define GL_BOOL_VEC3_ARB                  0x8B58
+#define GL_BOOL_VEC4_ARB                  0x8B59
+#define GL_FLOAT_MAT2_ARB                 0x8B5A
+#define GL_FLOAT_MAT3_ARB                 0x8B5B
+#define GL_FLOAT_MAT4_ARB                 0x8B5C
+#define GL_SAMPLER_1D_ARB                 0x8B5D
+#define GL_SAMPLER_2D_ARB                 0x8B5E
+#define GL_SAMPLER_3D_ARB                 0x8B5F
+#define GL_SAMPLER_CUBE_ARB               0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62
+#define GL_SAMPLER_2D_RECT_ARB            0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB         0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB              0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB            0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_POINT_SPRITE_ARB               0x8861
+#define GL_COORD_REPLACE_ARB              0x8862
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ARB           0x8824
+#define GL_DRAW_BUFFER0_ARB               0x8825
+#define GL_DRAW_BUFFER1_ARB               0x8826
+#define GL_DRAW_BUFFER2_ARB               0x8827
+#define GL_DRAW_BUFFER3_ARB               0x8828
+#define GL_DRAW_BUFFER4_ARB               0x8829
+#define GL_DRAW_BUFFER5_ARB               0x882A
+#define GL_DRAW_BUFFER6_ARB               0x882B
+#define GL_DRAW_BUFFER7_ARB               0x882C
+#define GL_DRAW_BUFFER8_ARB               0x882D
+#define GL_DRAW_BUFFER9_ARB               0x882E
+#define GL_DRAW_BUFFER10_ARB              0x882F
+#define GL_DRAW_BUFFER11_ARB              0x8830
+#define GL_DRAW_BUFFER12_ARB              0x8831
+#define GL_DRAW_BUFFER13_ARB              0x8832
+#define GL_DRAW_BUFFER14_ARB              0x8833
+#define GL_DRAW_BUFFER15_ARB              0x8834
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_ARB          0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_RGBA_FLOAT_MODE_ARB            0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B
+#define GL_CLAMP_READ_COLOR_ARB           0x891C
+#define GL_FIXED_ONLY_ARB                 0x891D
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_HALF_FLOAT_ARB                 0x140B
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_TEXTURE_RED_TYPE_ARB           0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17
+#define GL_RGBA32F_ARB                    0x8814
+#define GL_RGB32F_ARB                     0x8815
+#define GL_ALPHA32F_ARB                   0x8816
+#define GL_INTENSITY32F_ARB               0x8817
+#define GL_LUMINANCE32F_ARB               0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB         0x8819
+#define GL_RGBA16F_ARB                    0x881A
+#define GL_RGB16F_ARB                     0x881B
+#define GL_ALPHA16F_ARB                   0x881C
+#define GL_INTENSITY16F_ARB               0x881D
+#define GL_LUMINANCE16F_ARB               0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB         0x881F
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_ABGR_EXT                       0x8000
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_CONSTANT_COLOR_EXT             0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002
+#define GL_CONSTANT_ALPHA_EXT             0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004
+#define GL_BLEND_COLOR_EXT                0x8005
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_POLYGON_OFFSET_EXT             0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_ALPHA4_EXT                     0x803B
+#define GL_ALPHA8_EXT                     0x803C
+#define GL_ALPHA12_EXT                    0x803D
+#define GL_ALPHA16_EXT                    0x803E
+#define GL_LUMINANCE4_EXT                 0x803F
+#define GL_LUMINANCE8_EXT                 0x8040
+#define GL_LUMINANCE12_EXT                0x8041
+#define GL_LUMINANCE16_EXT                0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT          0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT          0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT          0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT         0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT        0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT        0x8048
+#define GL_INTENSITY_EXT                  0x8049
+#define GL_INTENSITY4_EXT                 0x804A
+#define GL_INTENSITY8_EXT                 0x804B
+#define GL_INTENSITY12_EXT                0x804C
+#define GL_INTENSITY16_EXT                0x804D
+#define GL_RGB2_EXT                       0x804E
+#define GL_RGB4_EXT                       0x804F
+#define GL_RGB5_EXT                       0x8050
+#define GL_RGB8_EXT                       0x8051
+#define GL_RGB10_EXT                      0x8052
+#define GL_RGB12_EXT                      0x8053
+#define GL_RGB16_EXT                      0x8054
+#define GL_RGBA2_EXT                      0x8055
+#define GL_RGBA4_EXT                      0x8056
+#define GL_RGB5_A1_EXT                    0x8057
+#define GL_RGBA8_EXT                      0x8058
+#define GL_RGB10_A2_EXT                   0x8059
+#define GL_RGBA12_EXT                     0x805A
+#define GL_RGBA16_EXT                     0x805B
+#define GL_TEXTURE_RED_SIZE_EXT           0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061
+#define GL_REPLACE_EXT                    0x8062
+#define GL_PROXY_TEXTURE_1D_EXT           0x8063
+#define GL_PROXY_TEXTURE_2D_EXT           0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT          0x8065
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_PACK_SKIP_IMAGES_EXT           0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E
+#define GL_TEXTURE_3D_EXT                 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT           0x8070
+#define GL_TEXTURE_DEPTH_EXT              0x8071
+#define GL_TEXTURE_WRAP_R_EXT             0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_FILTER4_SGIS                   0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147
+#endif
+
+#ifndef GL_EXT_subtexture
+#endif
+
+#ifndef GL_EXT_copy_texture
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_HISTOGRAM_EXT                  0x8024
+#define GL_PROXY_HISTOGRAM_EXT            0x8025
+#define GL_HISTOGRAM_WIDTH_EXT            0x8026
+#define GL_HISTOGRAM_FORMAT_EXT           0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C
+#define GL_HISTOGRAM_SINK_EXT             0x802D
+#define GL_MINMAX_EXT                     0x802E
+#define GL_MINMAX_FORMAT_EXT              0x802F
+#define GL_MINMAX_SINK_EXT                0x8030
+#define GL_TABLE_TOO_LARGE_EXT            0x8031
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_CONVOLUTION_1D_EXT             0x8010
+#define GL_CONVOLUTION_2D_EXT             0x8011
+#define GL_SEPARABLE_2D_EXT               0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015
+#define GL_REDUCE_EXT                     0x8016
+#define GL_CONVOLUTION_FORMAT_EXT         0x8017
+#define GL_CONVOLUTION_WIDTH_EXT          0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT         0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+#endif
+
+#ifndef GL_SGI_color_matrix
+#define GL_COLOR_MATRIX_SGI               0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_COLOR_TABLE_SGI                0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI          0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI          0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI           0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_PIXEL_TEXTURE_SGIS             0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_PIXEL_TEX_GEN_SGIX             0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133
+#define GL_TEXTURE_4D_SGIS                0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS          0x8135
+#define GL_TEXTURE_4DSIZE_SGIS            0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS            0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS        0x814F
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_CMYK_EXT                       0x800C
+#define GL_CMYKA_EXT                      0x800D
+#define GL_PACK_CMYK_HINT_EXT             0x800E
+#define GL_UNPACK_CMYK_HINT_EXT           0x800F
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_TEXTURE_PRIORITY_EXT           0x8066
+#define GL_TEXTURE_RESIDENT_EXT           0x8067
+#define GL_TEXTURE_1D_BINDING_EXT         0x8068
+#define GL_TEXTURE_2D_BINDING_EXT         0x8069
+#define GL_TEXTURE_3D_BINDING_EXT         0x806A
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS             0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_LINEAR_SHARPEN_SGIS            0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_TEXTURE_MIN_LOD_SGIS           0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS           0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_MULTISAMPLE_SGIS               0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F
+#define GL_SAMPLE_MASK_SGIS               0x80A0
+#define GL_1PASS_SGIS                     0x80A1
+#define GL_2PASS_0_SGIS                   0x80A2
+#define GL_2PASS_1_SGIS                   0x80A3
+#define GL_4PASS_0_SGIS                   0x80A4
+#define GL_4PASS_1_SGIS                   0x80A5
+#define GL_4PASS_2_SGIS                   0x80A6
+#define GL_4PASS_3_SGIS                   0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS            0x80A8
+#define GL_SAMPLES_SGIS                   0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB
+#define GL_SAMPLE_PATTERN_SGIS            0x80AC
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_RESCALE_NORMAL_EXT             0x803A
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_VERTEX_ARRAY_EXT               0x8074
+#define GL_NORMAL_ARRAY_EXT               0x8075
+#define GL_COLOR_ARRAY_EXT                0x8076
+#define GL_INDEX_ARRAY_EXT                0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT            0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT           0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT           0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT          0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT           0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT          0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT        0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT        0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_GENERATE_MIPMAP_SGIS           0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_TEXTURE_COMPARE_SGIX           0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_CLAMP_TO_EDGE_SGIS             0x812F
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_SGIS           0x812D
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_FUNC_ADD_EXT                   0x8006
+#define GL_MIN_EXT                        0x8007
+#define GL_MAX_EXT                        0x8008
+#define GL_BLEND_EQUATION_EXT             0x8009
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_FUNC_SUBTRACT_EXT              0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_INTERLACE_SGIX                 0x8094
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145
+#endif
+
+#ifndef GL_SGIS_texture_select
+#define GL_DUAL_ALPHA4_SGIS               0x8110
+#define GL_DUAL_ALPHA8_SGIS               0x8111
+#define GL_DUAL_ALPHA12_SGIS              0x8112
+#define GL_DUAL_ALPHA16_SGIS              0x8113
+#define GL_DUAL_LUMINANCE4_SGIS           0x8114
+#define GL_DUAL_LUMINANCE8_SGIS           0x8115
+#define GL_DUAL_LUMINANCE12_SGIS          0x8116
+#define GL_DUAL_LUMINANCE16_SGIS          0x8117
+#define GL_DUAL_INTENSITY4_SGIS           0x8118
+#define GL_DUAL_INTENSITY8_SGIS           0x8119
+#define GL_DUAL_INTENSITY12_SGIS          0x811A
+#define GL_DUAL_INTENSITY16_SGIS          0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D
+#define GL_QUAD_ALPHA4_SGIS               0x811E
+#define GL_QUAD_ALPHA8_SGIS               0x811F
+#define GL_QUAD_LUMINANCE4_SGIS           0x8120
+#define GL_QUAD_LUMINANCE8_SGIS           0x8121
+#define GL_QUAD_INTENSITY4_SGIS           0x8122
+#define GL_QUAD_INTENSITY8_SGIS           0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SPRITE_SGIX                    0x8148
+#define GL_SPRITE_MODE_SGIX               0x8149
+#define GL_SPRITE_AXIS_SGIX               0x814A
+#define GL_SPRITE_TRANSLATION_SGIX        0x814B
+#define GL_SPRITE_AXIAL_SGIX              0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_POINT_SIZE_MIN_EXT             0x8126
+#define GL_POINT_SIZE_MAX_EXT             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128
+#define GL_DISTANCE_ATTENUATION_EXT       0x8129
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_POINT_SIZE_MIN_SGIS            0x8126
+#define GL_POINT_SIZE_MAX_SGIS            0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS      0x8129
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_FRAMEZOOM_SGIX                 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#endif
+
+#ifndef GL_FfdMaskSGIX
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX       0x8195
+#define GL_DEFORMATIONS_MASK_SGIX         0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_REFERENCE_PLANE_SGIX           0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_DEPTH_COMPONENT16_SGIX         0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX         0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX         0x81A7
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_FOG_FUNC_SGIS                  0x812A
+#define GL_FOG_FUNC_POINTS_SGIS           0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_FOG_OFFSET_SGIX                0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX          0x8199
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_IMAGE_SCALE_X_HP               0x8155
+#define GL_IMAGE_SCALE_Y_HP               0x8156
+#define GL_IMAGE_TRANSLATE_X_HP           0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP           0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B
+#define GL_IMAGE_MAG_FILTER_HP            0x815C
+#define GL_IMAGE_MIN_FILTER_HP            0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E
+#define GL_CUBIC_HP                       0x815F
+#define GL_AVERAGE_HP                     0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP          0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_IGNORE_BORDER_HP               0x8150
+#define GL_CONSTANT_BORDER_HP             0x8151
+#define GL_REPLICATE_BORDER_HP            0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154
+#endif
+
+#ifndef GL_INGR_palette_buffer
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE
+#endif
+
+#ifndef GL_EXT_color_subtable
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_VERTEX_DATA_HINT_PGI           0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI            0x1A22D
+#define GL_COLOR3_BIT_PGI                 0x00010000
+#define GL_COLOR4_BIT_PGI                 0x00020000
+#define GL_EDGEFLAG_BIT_PGI               0x00040000
+#define GL_INDEX_BIT_PGI                  0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI            0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000
+#define GL_MAT_EMISSION_BIT_PGI           0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000
+#define GL_MAT_SHININESS_BIT_PGI          0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI           0x04000000
+#define GL_NORMAL_BIT_PGI                 0x08000000
+#define GL_TEXCOORD1_BIT_PGI              0x10000000
+#define GL_TEXCOORD2_BIT_PGI              0x20000000
+#define GL_TEXCOORD3_BIT_PGI              0x40000000
+#define GL_TEXCOORD4_BIT_PGI              0x80000000
+#define GL_VERTEX23_BIT_PGI               0x00000004
+#define GL_VERTEX4_BIT_PGI                0x00000008
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI          0x1A219
+#define GL_CLIP_NEAR_HINT_PGI             0x1A220
+#define GL_CLIP_FAR_HINT_PGI              0x1A221
+#define GL_WIDE_LINE_HINT_PGI             0x1A222
+#define GL_BACK_NORMALS_HINT_PGI          0x1A223
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_COLOR_INDEX1_EXT               0x80E2
+#define GL_COLOR_INDEX2_EXT               0x80E3
+#define GL_COLOR_INDEX4_EXT               0x80E4
+#define GL_COLOR_INDEX8_EXT               0x80E5
+#define GL_COLOR_INDEX12_EXT              0x80E6
+#define GL_COLOR_INDEX16_EXT              0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_LIST_PRIORITY_SGIX             0x8182
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_IR_INSTRUMENT1_SGIX            0x817F
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SHADOW_AMBIENT_SGIX            0x80BF
+#endif
+
+#ifndef GL_EXT_index_texture
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_INDEX_MATERIAL_EXT             0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_INDEX_TEST_EXT                 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT            0x81B6
+#define GL_INDEX_TEST_REF_EXT             0x81B7
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_IUI_V2F_EXT                    0x81AD
+#define GL_IUI_V3F_EXT                    0x81AE
+#define GL_IUI_N3F_V2F_EXT                0x81AF
+#define GL_IUI_N3F_V3F_EXT                0x81B0
+#define GL_T2F_IUI_V2F_EXT                0x81B1
+#define GL_T2F_IUI_V3F_EXT                0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_CULL_VERTEX_EXT                0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_YCRCB_422_SGIX                 0x81BB
+#define GL_YCRCB_444_SGIX                 0x81BC
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_FRAGMENT_LIGHTING_SGIX         0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406
+#define GL_LIGHT_ENV_MODE_SGIX            0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX           0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX           0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX           0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX           0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX           0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX           0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX           0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX           0x8413
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP       0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_PHONG_WIN                      0x80EA
+#define GL_PHONG_HINT_WIN                 0x80EB
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_FRAGMENT_MATERIAL_EXT          0x8349
+#define GL_FRAGMENT_NORMAL_EXT            0x834A
+#define GL_FRAGMENT_COLOR_EXT             0x834C
+#define GL_ATTENUATION_EXT                0x834D
+#define GL_SHADOW_ATTENUATION_EXT         0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F
+#define GL_TEXTURE_LIGHT_EXT              0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+/* reuse GL_FRAGMENT_DEPTH_EXT */
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_ALPHA_MIN_SGIX                 0x8320
+#define GL_ALPHA_MAX_SGIX                 0x8321
+#endif
+
+#ifndef GL_SGIX_impact_pixel_texture
+#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX   0x8184
+#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX     0x8185
+#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX     0x8186
+#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187
+#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188
+#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX    0x8189
+#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX    0x818A
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_BGR_EXT                        0x80E0
+#define GL_BGRA_EXT                       0x80E1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_ASYNC_MARKER_SGIX              0x8329
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX         0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_ASYNC_HISTOGRAM_SGIX           0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D
+#endif
+
+#ifndef GL_INTEL_texture_scissor
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_PARALLEL_ARRAYS_INTEL          0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_OCCLUSION_TEST_HP              0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP       0x8166
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330
+#define GL_PIXEL_MAG_FILTER_EXT           0x8331
+#define GL_PIXEL_MIN_FILTER_EXT           0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333
+#define GL_CUBIC_EXT                      0x8334
+#define GL_AVERAGE_EXT                    0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8
+#define GL_SINGLE_COLOR_EXT               0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_COLOR_SUM_EXT                  0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_PERTURB_EXT                    0x85AE
+#define GL_TEXTURE_NORMAL_EXT             0x85AF
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450
+#define GL_FOG_COORDINATE_EXT             0x8451
+#define GL_FRAGMENT_DEPTH_EXT             0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_SCREEN_COORDINATES_REND        0x8490
+#define GL_INVERTED_SCREEN_W_REND         0x8491
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_TANGENT_ARRAY_EXT              0x8439
+#define GL_BINORMAL_ARRAY_EXT             0x843A
+#define GL_CURRENT_TANGENT_EXT            0x843B
+#define GL_CURRENT_BINORMAL_EXT           0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443
+#define GL_MAP1_TANGENT_EXT               0x8444
+#define GL_MAP2_TANGENT_EXT               0x8445
+#define GL_MAP1_BINORMAL_EXT              0x8446
+#define GL_MAP2_BINORMAL_EXT              0x8447
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_COMBINE_EXT                    0x8570
+#define GL_COMBINE_RGB_EXT                0x8571
+#define GL_COMBINE_ALPHA_EXT              0x8572
+#define GL_RGB_SCALE_EXT                  0x8573
+#define GL_ADD_SIGNED_EXT                 0x8574
+#define GL_INTERPOLATE_EXT                0x8575
+#define GL_CONSTANT_EXT                   0x8576
+#define GL_PRIMARY_COLOR_EXT              0x8577
+#define GL_PREVIOUS_EXT                   0x8578
+#define GL_SOURCE0_RGB_EXT                0x8580
+#define GL_SOURCE1_RGB_EXT                0x8581
+#define GL_SOURCE2_RGB_EXT                0x8582
+#define GL_SOURCE0_ALPHA_EXT              0x8588
+#define GL_SOURCE1_ALPHA_EXT              0x8589
+#define GL_SOURCE2_ALPHA_EXT              0x858A
+#define GL_OPERAND0_RGB_EXT               0x8590
+#define GL_OPERAND1_RGB_EXT               0x8591
+#define GL_OPERAND2_RGB_EXT               0x8592
+#define GL_OPERAND0_ALPHA_EXT             0x8598
+#define GL_OPERAND1_ALPHA_EXT             0x8599
+#define GL_OPERAND2_ALPHA_EXT             0x859A
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_TRANSFORM_HINT_APPLE           0x85B1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_FOG_SCALE_SGIX                 0x81FC
+#define GL_FOG_SCALE_VALUE_SGIX           0x81FD
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_GLOBAL_ALPHA_SUN               0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_RESTART_SUN                    0x0001
+#define GL_REPLACE_MIDDLE_SUN             0x0002
+#define GL_REPLACE_OLDEST_SUN             0x0003
+#define GL_TRIANGLE_LIST_SUN              0x81D7
+#define GL_REPLACEMENT_CODE_SUN           0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN                   0x85C4
+#define GL_R1UI_C4UB_V3F_SUN              0x85C5
+#define GL_R1UI_C3F_V3F_SUN               0x85C6
+#define GL_R1UI_N3F_V3F_SUN               0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8
+#define GL_R1UI_T2F_V3F_SUN               0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB
+#endif
+
+#ifndef GL_SUN_vertex
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_BLEND_DST_RGB_EXT              0x80C8
+#define GL_BLEND_SRC_RGB_EXT              0x80C9
+#define GL_BLEND_DST_ALPHA_EXT            0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT            0x80CB
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_RED_MIN_CLAMP_INGR             0x8560
+#define GL_GREEN_MIN_CLAMP_INGR           0x8561
+#define GL_BLUE_MIN_CLAMP_INGR            0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR           0x8563
+#define GL_RED_MAX_CLAMP_INGR             0x8564
+#define GL_GREEN_MAX_CLAMP_INGR           0x8565
+#define GL_BLUE_MAX_CLAMP_INGR            0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR           0x8567
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INTERLACE_READ_INGR            0x8568
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_INCR_WRAP_EXT                  0x8507
+#define GL_DECR_WRAP_EXT                  0x8508
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_422_EXT                        0x80CC
+#define GL_422_REV_EXT                    0x80CD
+#define GL_422_AVERAGE_EXT                0x80CE
+#define GL_422_REV_AVERAGE_EXT            0x80CF
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NORMAL_MAP_NV                  0x8511
+#define GL_REFLECTION_MAP_NV              0x8512
+#endif
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_NORMAL_MAP_EXT                 0x8511
+#define GL_REFLECTION_MAP_EXT             0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_WRAP_BORDER_SUN                0x81D4
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT           0x8501
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_MODELVIEW0_STACK_DEPTH_EXT     GL_MODELVIEW_STACK_DEPTH
+#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502
+#define GL_MODELVIEW0_MATRIX_EXT          GL_MODELVIEW_MATRIX
+#define GL_MODELVIEW1_MATRIX_EXT          0x8506
+#define GL_VERTEX_WEIGHTING_EXT           0x8509
+#define GL_MODELVIEW0_EXT                 GL_MODELVIEW
+#define GL_MODELVIEW1_EXT                 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_MAX_SHININESS_NV               0x8504
+#define GL_MAX_SPOT_EXPONENT_NV           0x8505
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_NV          0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_REGISTER_COMBINERS_NV          0x8522
+#define GL_VARIABLE_A_NV                  0x8523
+#define GL_VARIABLE_B_NV                  0x8524
+#define GL_VARIABLE_C_NV                  0x8525
+#define GL_VARIABLE_D_NV                  0x8526
+#define GL_VARIABLE_E_NV                  0x8527
+#define GL_VARIABLE_F_NV                  0x8528
+#define GL_VARIABLE_G_NV                  0x8529
+#define GL_CONSTANT_COLOR0_NV             0x852A
+#define GL_CONSTANT_COLOR1_NV             0x852B
+#define GL_PRIMARY_COLOR_NV               0x852C
+#define GL_SECONDARY_COLOR_NV             0x852D
+#define GL_SPARE0_NV                      0x852E
+#define GL_SPARE1_NV                      0x852F
+#define GL_DISCARD_NV                     0x8530
+#define GL_E_TIMES_F_NV                   0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV           0x8536
+#define GL_UNSIGNED_INVERT_NV             0x8537
+#define GL_EXPAND_NORMAL_NV               0x8538
+#define GL_EXPAND_NEGATE_NV               0x8539
+#define GL_HALF_BIAS_NORMAL_NV            0x853A
+#define GL_HALF_BIAS_NEGATE_NV            0x853B
+#define GL_SIGNED_IDENTITY_NV             0x853C
+#define GL_SIGNED_NEGATE_NV               0x853D
+#define GL_SCALE_BY_TWO_NV                0x853E
+#define GL_SCALE_BY_FOUR_NV               0x853F
+#define GL_SCALE_BY_ONE_HALF_NV           0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541
+#define GL_COMBINER_INPUT_NV              0x8542
+#define GL_COMBINER_MAPPING_NV            0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546
+#define GL_COMBINER_MUX_SUM_NV            0x8547
+#define GL_COMBINER_SCALE_NV              0x8548
+#define GL_COMBINER_BIAS_NV               0x8549
+#define GL_COMBINER_AB_OUTPUT_NV          0x854A
+#define GL_COMBINER_CD_OUTPUT_NV          0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV         0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV       0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV       0x854E
+#define GL_COLOR_SUM_CLAMP_NV             0x854F
+#define GL_COMBINER0_NV                   0x8550
+#define GL_COMBINER1_NV                   0x8551
+#define GL_COMBINER2_NV                   0x8552
+#define GL_COMBINER3_NV                   0x8553
+#define GL_COMBINER4_NV                   0x8554
+#define GL_COMBINER5_NV                   0x8555
+#define GL_COMBINER6_NV                   0x8556
+#define GL_COMBINER7_NV                   0x8557
+/* reuse GL_TEXTURE0_ARB */
+/* reuse GL_TEXTURE1_ARB */
+/* reuse GL_ZERO */
+/* reuse GL_NONE */
+/* reuse GL_FOG */
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_FOG_DISTANCE_MODE_NV           0x855A
+#define GL_EYE_RADIAL_NV                  0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C
+/* reuse GL_EYE_PLANE */
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_EMBOSS_LIGHT_NV                0x855D
+#define GL_EMBOSS_CONSTANT_NV             0x855E
+#define GL_EMBOSS_MAP_NV                  0x855F
+#endif
+
+#ifndef GL_NV_blend_square
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_COMBINE4_NV                    0x8503
+#define GL_SOURCE3_RGB_NV                 0x8583
+#define GL_SOURCE3_ALPHA_NV               0x858B
+#define GL_OPERAND3_RGB_NV                0x8593
+#define GL_OPERAND3_ALPHA_NV              0x859B
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#endif
+
+#ifndef GL_MESA_window_pos
+#endif
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_CULL_VERTEX_IBM                103050
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_VERTEX_ARRAY_LIST_IBM          103070
+#define GL_NORMAL_ARRAY_LIST_IBM          103071
+#define GL_COLOR_ARRAY_LIST_IBM           103072
+#define GL_INDEX_ARRAY_LIST_IBM           103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_YCRCB_SGIX                     0x8318
+#define GL_YCRCBA_SGIX                    0x8319
+#endif
+
+#ifndef GL_SGI_depth_pass_instrument
+#define GL_DEPTH_PASS_INSTRUMENT_SGIX     0x8310
+#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311
+#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_MULTISAMPLE_3DFX               0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX            0x86B3
+#define GL_SAMPLES_3DFX                   0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX           0x20000000
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_MULTISAMPLE_EXT                0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F
+#define GL_SAMPLE_MASK_EXT                0x80A0
+#define GL_1PASS_EXT                      0x80A1
+#define GL_2PASS_0_EXT                    0x80A2
+#define GL_2PASS_1_EXT                    0x80A3
+#define GL_4PASS_0_EXT                    0x80A4
+#define GL_4PASS_1_EXT                    0x80A5
+#define GL_4PASS_2_EXT                    0x80A6
+#define GL_4PASS_3_EXT                    0x80A7
+#define GL_SAMPLE_BUFFERS_EXT             0x80A8
+#define GL_SAMPLES_EXT                    0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB
+#define GL_SAMPLE_PATTERN_EXT             0x80AC
+#define GL_MULTISAMPLE_BIT_EXT            0x20000000
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_VERTEX_PRECLIP_SGIX            0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_CONVOLUTION_HINT_SGIX          0x8316
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_PACK_RESAMPLE_SGIX             0x842C
+#define GL_UNPACK_RESAMPLE_SGIX           0x842D
+#define GL_RESAMPLE_REPLICATE_SGIX        0x842E
+#define GL_RESAMPLE_ZERO_FILL_SGIX        0x842F
+#define GL_RESAMPLE_DECIMATE_SGIX         0x8430
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3
+#define GL_EYE_POINT_SGIS                 0x81F4
+#define GL_OBJECT_POINT_SGIS              0x81F5
+#define GL_EYE_LINE_SGIS                  0x81F6
+#define GL_OBJECT_LINE_SGIS               0x81F7
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_DOT3_RGB_EXT                   0x8740
+#define GL_DOT3_RGBA_EXT                  0x8741
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_MIRROR_CLAMP_ATI               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743
+#endif
+
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV               0x84F2
+#define GL_FENCE_STATUS_NV                0x84F3
+#define GL_FENCE_CONDITION_NV             0x84F4
+#endif
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_IBM            0x8370
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_EVAL_2D_NV                     0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1
+#define GL_MAP_TESSELLATION_NV            0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV        0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_DEPTH_STENCIL_NV               0x84F9
+#define GL_UNSIGNED_INT_24_8_NV           0x84FA
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_PER_STAGE_CONSTANTS_NV         0x8535
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_NV           0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV          0x86DC
+#define GL_SHADER_CONSISTENT_NV           0x86DD
+#define GL_TEXTURE_SHADER_NV              0x86DE
+#define GL_SHADER_OPERATION_NV            0x86DF
+#define GL_CULL_MODES_NV                  0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    GL_OFFSET_TEXTURE_MATRIX_NV
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV     GL_OFFSET_TEXTURE_SCALE_NV
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV      GL_OFFSET_TEXTURE_BIAS_NV
+#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4
+#define GL_CONST_EYE_NV                   0x86E5
+#define GL_PASS_THROUGH_NV                0x86E6
+#define GL_CULL_FRAGMENT_NV               0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV           0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA
+#define GL_DOT_PRODUCT_NV                 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV                        0x86F4
+#define GL_DSDT_NV                        0x86F5
+#define GL_DSDT_MAG_NV                    0x86F6
+#define GL_DSDT_MAG_VIB_NV                0x86F7
+#define GL_HILO16_NV                      0x86F8
+#define GL_SIGNED_HILO_NV                 0x86F9
+#define GL_SIGNED_HILO16_NV               0x86FA
+#define GL_SIGNED_RGBA_NV                 0x86FB
+#define GL_SIGNED_RGBA8_NV                0x86FC
+#define GL_SIGNED_RGB_NV                  0x86FE
+#define GL_SIGNED_RGB8_NV                 0x86FF
+#define GL_SIGNED_LUMINANCE_NV            0x8701
+#define GL_SIGNED_LUMINANCE8_NV           0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704
+#define GL_SIGNED_ALPHA_NV                0x8705
+#define GL_SIGNED_ALPHA8_NV               0x8706
+#define GL_SIGNED_INTENSITY_NV            0x8707
+#define GL_SIGNED_INTENSITY8_NV           0x8708
+#define GL_DSDT8_NV                       0x8709
+#define GL_DSDT8_MAG8_NV                  0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV                    0x870E
+#define GL_LO_SCALE_NV                    0x870F
+#define GL_DS_SCALE_NV                    0x8710
+#define GL_DT_SCALE_NV                    0x8711
+#define GL_MAGNITUDE_SCALE_NV             0x8712
+#define GL_VIBRANCE_SCALE_NV              0x8713
+#define GL_HI_BIAS_NV                     0x8714
+#define GL_LO_BIAS_NV                     0x8715
+#define GL_DS_BIAS_NV                     0x8716
+#define GL_DT_BIAS_NV                     0x8717
+#define GL_MAGNITUDE_BIAS_NV              0x8718
+#define GL_VIBRANCE_BIAS_NV               0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV       0x871A
+#define GL_TEXTURE_HI_SIZE_NV             0x871B
+#define GL_TEXTURE_LO_SIZE_NV             0x871C
+#define GL_TEXTURE_DS_SIZE_NV             0x871D
+#define GL_TEXTURE_DT_SIZE_NV             0x871E
+#define GL_TEXTURE_MAG_SIZE_NV            0x871F
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_VERTEX_PROGRAM_NV              0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV        0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625
+#define GL_CURRENT_ATTRIB_NV              0x8626
+#define GL_PROGRAM_LENGTH_NV              0x8627
+#define GL_PROGRAM_STRING_NV              0x8628
+#define GL_MODELVIEW_PROJECTION_NV        0x8629
+#define GL_IDENTITY_NV                    0x862A
+#define GL_INVERSE_NV                     0x862B
+#define GL_TRANSPOSE_NV                   0x862C
+#define GL_INVERSE_TRANSPOSE_NV           0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV          0x862F
+#define GL_MATRIX0_NV                     0x8630
+#define GL_MATRIX1_NV                     0x8631
+#define GL_MATRIX2_NV                     0x8632
+#define GL_MATRIX3_NV                     0x8633
+#define GL_MATRIX4_NV                     0x8634
+#define GL_MATRIX5_NV                     0x8635
+#define GL_MATRIX6_NV                     0x8636
+#define GL_MATRIX7_NV                     0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640
+#define GL_CURRENT_MATRIX_NV              0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643
+#define GL_PROGRAM_PARAMETER_NV           0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645
+#define GL_PROGRAM_TARGET_NV              0x8646
+#define GL_PROGRAM_RESIDENT_NV            0x8647
+#define GL_TRACK_MATRIX_NV                0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV      0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SCALEBIAS_HINT_SGIX            0x8322
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_INTERLACE_OML                  0x8980
+#define GL_INTERLACE_READ_OML             0x8981
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983
+#endif
+
+#ifndef GL_OML_resample
+#define GL_PACK_RESAMPLE_OML              0x8984
+#define GL_UNPACK_RESAMPLE_OML            0x8985
+#define GL_RESAMPLE_REPLICATE_OML         0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML         0x8987
+#define GL_RESAMPLE_AVERAGE_OML           0x8988
+#define GL_RESAMPLE_DECIMATE_OML          0x8989
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_BUMP_ROT_MATRIX_ATI            0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777
+#define GL_BUMP_TEX_UNITS_ATI             0x8778
+#define GL_DUDV_ATI                       0x8779
+#define GL_DU8DV8_ATI                     0x877A
+#define GL_BUMP_ENVMAP_ATI                0x877B
+#define GL_BUMP_TARGET_ATI                0x877C
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_FRAGMENT_SHADER_ATI            0x8920
+#define GL_REG_0_ATI                      0x8921
+#define GL_REG_1_ATI                      0x8922
+#define GL_REG_2_ATI                      0x8923
+#define GL_REG_3_ATI                      0x8924
+#define GL_REG_4_ATI                      0x8925
+#define GL_REG_5_ATI                      0x8926
+#define GL_REG_6_ATI                      0x8927
+#define GL_REG_7_ATI                      0x8928
+#define GL_REG_8_ATI                      0x8929
+#define GL_REG_9_ATI                      0x892A
+#define GL_REG_10_ATI                     0x892B
+#define GL_REG_11_ATI                     0x892C
+#define GL_REG_12_ATI                     0x892D
+#define GL_REG_13_ATI                     0x892E
+#define GL_REG_14_ATI                     0x892F
+#define GL_REG_15_ATI                     0x8930
+#define GL_REG_16_ATI                     0x8931
+#define GL_REG_17_ATI                     0x8932
+#define GL_REG_18_ATI                     0x8933
+#define GL_REG_19_ATI                     0x8934
+#define GL_REG_20_ATI                     0x8935
+#define GL_REG_21_ATI                     0x8936
+#define GL_REG_22_ATI                     0x8937
+#define GL_REG_23_ATI                     0x8938
+#define GL_REG_24_ATI                     0x8939
+#define GL_REG_25_ATI                     0x893A
+#define GL_REG_26_ATI                     0x893B
+#define GL_REG_27_ATI                     0x893C
+#define GL_REG_28_ATI                     0x893D
+#define GL_REG_29_ATI                     0x893E
+#define GL_REG_30_ATI                     0x893F
+#define GL_REG_31_ATI                     0x8940
+#define GL_CON_0_ATI                      0x8941
+#define GL_CON_1_ATI                      0x8942
+#define GL_CON_2_ATI                      0x8943
+#define GL_CON_3_ATI                      0x8944
+#define GL_CON_4_ATI                      0x8945
+#define GL_CON_5_ATI                      0x8946
+#define GL_CON_6_ATI                      0x8947
+#define GL_CON_7_ATI                      0x8948
+#define GL_CON_8_ATI                      0x8949
+#define GL_CON_9_ATI                      0x894A
+#define GL_CON_10_ATI                     0x894B
+#define GL_CON_11_ATI                     0x894C
+#define GL_CON_12_ATI                     0x894D
+#define GL_CON_13_ATI                     0x894E
+#define GL_CON_14_ATI                     0x894F
+#define GL_CON_15_ATI                     0x8950
+#define GL_CON_16_ATI                     0x8951
+#define GL_CON_17_ATI                     0x8952
+#define GL_CON_18_ATI                     0x8953
+#define GL_CON_19_ATI                     0x8954
+#define GL_CON_20_ATI                     0x8955
+#define GL_CON_21_ATI                     0x8956
+#define GL_CON_22_ATI                     0x8957
+#define GL_CON_23_ATI                     0x8958
+#define GL_CON_24_ATI                     0x8959
+#define GL_CON_25_ATI                     0x895A
+#define GL_CON_26_ATI                     0x895B
+#define GL_CON_27_ATI                     0x895C
+#define GL_CON_28_ATI                     0x895D
+#define GL_CON_29_ATI                     0x895E
+#define GL_CON_30_ATI                     0x895F
+#define GL_CON_31_ATI                     0x8960
+#define GL_MOV_ATI                        0x8961
+#define GL_ADD_ATI                        0x8963
+#define GL_MUL_ATI                        0x8964
+#define GL_SUB_ATI                        0x8965
+#define GL_DOT3_ATI                       0x8966
+#define GL_DOT4_ATI                       0x8967
+#define GL_MAD_ATI                        0x8968
+#define GL_LERP_ATI                       0x8969
+#define GL_CND_ATI                        0x896A
+#define GL_CND0_ATI                       0x896B
+#define GL_DOT2_ADD_ATI                   0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F
+#define GL_NUM_PASSES_ATI                 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975
+#define GL_SWIZZLE_STR_ATI                0x8976
+#define GL_SWIZZLE_STQ_ATI                0x8977
+#define GL_SWIZZLE_STR_DR_ATI             0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI             0x8979
+#define GL_SWIZZLE_STRQ_ATI               0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B
+#define GL_RED_BIT_ATI                    0x00000001
+#define GL_GREEN_BIT_ATI                  0x00000002
+#define GL_BLUE_BIT_ATI                   0x00000004
+#define GL_2X_BIT_ATI                     0x00000001
+#define GL_4X_BIT_ATI                     0x00000002
+#define GL_8X_BIT_ATI                     0x00000004
+#define GL_HALF_BIT_ATI                   0x00000008
+#define GL_QUARTER_BIT_ATI                0x00000010
+#define GL_EIGHTH_BIT_ATI                 0x00000020
+#define GL_SATURATE_BIT_ATI               0x00000040
+#define GL_COMP_BIT_ATI                   0x00000002
+#define GL_NEGATE_BIT_ATI                 0x00000004
+#define GL_BIAS_BIT_ATI                   0x00000008
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_PN_TRIANGLES_ATI               0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_STATIC_ATI                     0x8760
+#define GL_DYNAMIC_ATI                    0x8761
+#define GL_PRESERVE_ATI                   0x8762
+#define GL_DISCARD_ATI                    0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_VERTEX_SHADER_EXT              0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT      0x8781
+#define GL_OP_INDEX_EXT                   0x8782
+#define GL_OP_NEGATE_EXT                  0x8783
+#define GL_OP_DOT3_EXT                    0x8784
+#define GL_OP_DOT4_EXT                    0x8785
+#define GL_OP_MUL_EXT                     0x8786
+#define GL_OP_ADD_EXT                     0x8787
+#define GL_OP_MADD_EXT                    0x8788
+#define GL_OP_FRAC_EXT                    0x8789
+#define GL_OP_MAX_EXT                     0x878A
+#define GL_OP_MIN_EXT                     0x878B
+#define GL_OP_SET_GE_EXT                  0x878C
+#define GL_OP_SET_LT_EXT                  0x878D
+#define GL_OP_CLAMP_EXT                   0x878E
+#define GL_OP_FLOOR_EXT                   0x878F
+#define GL_OP_ROUND_EXT                   0x8790
+#define GL_OP_EXP_BASE_2_EXT              0x8791
+#define GL_OP_LOG_BASE_2_EXT              0x8792
+#define GL_OP_POWER_EXT                   0x8793
+#define GL_OP_RECIP_EXT                   0x8794
+#define GL_OP_RECIP_SQRT_EXT              0x8795
+#define GL_OP_SUB_EXT                     0x8796
+#define GL_OP_CROSS_PRODUCT_EXT           0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798
+#define GL_OP_MOV_EXT                     0x8799
+#define GL_OUTPUT_VERTEX_EXT              0x879A
+#define GL_OUTPUT_COLOR0_EXT              0x879B
+#define GL_OUTPUT_COLOR1_EXT              0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC
+#define GL_OUTPUT_FOG_EXT                 0x87BD
+#define GL_SCALAR_EXT                     0x87BE
+#define GL_VECTOR_EXT                     0x87BF
+#define GL_MATRIX_EXT                     0x87C0
+#define GL_VARIANT_EXT                    0x87C1
+#define GL_INVARIANT_EXT                  0x87C2
+#define GL_LOCAL_CONSTANT_EXT             0x87C3
+#define GL_LOCAL_EXT                      0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4
+#define GL_X_EXT                          0x87D5
+#define GL_Y_EXT                          0x87D6
+#define GL_Z_EXT                          0x87D7
+#define GL_W_EXT                          0x87D8
+#define GL_NEGATIVE_X_EXT                 0x87D9
+#define GL_NEGATIVE_Y_EXT                 0x87DA
+#define GL_NEGATIVE_Z_EXT                 0x87DB
+#define GL_NEGATIVE_W_EXT                 0x87DC
+#define GL_ZERO_EXT                       0x87DD
+#define GL_ONE_EXT                        0x87DE
+#define GL_NEGATIVE_ONE_EXT               0x87DF
+#define GL_NORMALIZED_RANGE_EXT           0x87E0
+#define GL_FULL_RANGE_EXT                 0x87E1
+#define GL_CURRENT_VERTEX_EXT             0x87E2
+#define GL_MVP_MATRIX_EXT                 0x87E3
+#define GL_VARIANT_VALUE_EXT              0x87E4
+#define GL_VARIANT_DATATYPE_EXT           0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7
+#define GL_VARIANT_ARRAY_EXT              0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9
+#define GL_INVARIANT_VALUE_EXT            0x87EA
+#define GL_INVARIANT_DATATYPE_EXT         0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_MAX_VERTEX_STREAMS_ATI         0x876B
+#define GL_VERTEX_STREAM0_ATI             0x876C
+#define GL_VERTEX_STREAM1_ATI             0x876D
+#define GL_VERTEX_STREAM2_ATI             0x876E
+#define GL_VERTEX_STREAM3_ATI             0x876F
+#define GL_VERTEX_STREAM4_ATI             0x8770
+#define GL_VERTEX_STREAM5_ATI             0x8771
+#define GL_VERTEX_STREAM6_ATI             0x8772
+#define GL_VERTEX_STREAM7_ATI             0x8773
+#define GL_VERTEX_SOURCE_ATI              0x8774
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ELEMENT_ARRAY_ATI              0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_QUAD_MESH_SUN                  0x8614
+#define GL_TRIANGLE_MESH_SUN              0x8615
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SLICE_ACCUM_SUN                0x85CC
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_DEPTH_CLAMP_NV                 0x864F
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_PIXEL_COUNTER_BITS_NV          0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865
+#define GL_PIXEL_COUNT_NV                 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_POINT_SPRITE_NV                0x8861
+#define GL_COORD_REPLACE_NV               0x8862
+#define GL_POINT_SPRITE_R_MODE_NV         0x8863
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV                       0x885E
+#define GL_SIGNED_HILO8_NV                0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV           0x8860
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_ELEMENT_ARRAY_APPLE            0x8768
+#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8769
+#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x876A
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_DRAW_PIXELS_APPLE              0x8A0A
+#define GL_FENCE_APPLE                    0x8A0B
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CACHED_APPLE           0x85BE
+#define GL_STORAGE_SHARED_APPLE           0x85BF
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_YCBCR_422_APPLE                0x85B9
+#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_RGB_S3TC                       0x83A0
+#define GL_RGB4_S3TC                      0x83A1
+#define GL_RGBA_S3TC                      0x83A2
+#define GL_RGBA4_S3TC                     0x83A3
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ATI           0x8824
+#define GL_DRAW_BUFFER0_ATI               0x8825
+#define GL_DRAW_BUFFER1_ATI               0x8826
+#define GL_DRAW_BUFFER2_ATI               0x8827
+#define GL_DRAW_BUFFER3_ATI               0x8828
+#define GL_DRAW_BUFFER4_ATI               0x8829
+#define GL_DRAW_BUFFER5_ATI               0x882A
+#define GL_DRAW_BUFFER6_ATI               0x882B
+#define GL_DRAW_BUFFER7_ATI               0x882C
+#define GL_DRAW_BUFFER8_ATI               0x882D
+#define GL_DRAW_BUFFER9_ATI               0x882E
+#define GL_DRAW_BUFFER10_ATI              0x882F
+#define GL_DRAW_BUFFER11_ATI              0x8830
+#define GL_DRAW_BUFFER12_ATI              0x8831
+#define GL_DRAW_BUFFER13_ATI              0x8832
+#define GL_DRAW_BUFFER14_ATI              0x8833
+#define GL_DRAW_BUFFER15_ATI              0x8834
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_TYPE_RGBA_FLOAT_ATI            0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_MODULATE_ADD_ATI               0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI        0x8745
+#define GL_MODULATE_SUBTRACT_ATI          0x8746
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_RGBA_FLOAT32_ATI               0x8814
+#define GL_RGB_FLOAT32_ATI                0x8815
+#define GL_ALPHA_FLOAT32_ATI              0x8816
+#define GL_INTENSITY_FLOAT32_ATI          0x8817
+#define GL_LUMINANCE_FLOAT32_ATI          0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819
+#define GL_RGBA_FLOAT16_ATI               0x881A
+#define GL_RGB_FLOAT16_ATI                0x881B
+#define GL_ALPHA_FLOAT16_ATI              0x881C
+#define GL_INTENSITY_FLOAT16_ATI          0x881D
+#define GL_LUMINANCE_FLOAT16_ATI          0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_FLOAT_R_NV                     0x8880
+#define GL_FLOAT_RG_NV                    0x8881
+#define GL_FLOAT_RGB_NV                   0x8882
+#define GL_FLOAT_RGBA_NV                  0x8883
+#define GL_FLOAT_R16_NV                   0x8884
+#define GL_FLOAT_R32_NV                   0x8885
+#define GL_FLOAT_RG16_NV                  0x8886
+#define GL_FLOAT_RG32_NV                  0x8887
+#define GL_FLOAT_RGB16_NV                 0x8888
+#define GL_FLOAT_RGB32_NV                 0x8889
+#define GL_FLOAT_RGBA16_NV                0x888A
+#define GL_FLOAT_RGBA32_NV                0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D
+#define GL_FLOAT_RGBA_MODE_NV             0x888E
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV            0x8870
+#define GL_MAX_TEXTURE_COORDS_NV          0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873
+#define GL_PROGRAM_ERROR_STRING_NV        0x8874
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_HALF_FLOAT_NV                  0x140B
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_PRIMITIVE_RESTART_NV           0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif
+
+#ifndef GL_NV_vertex_program2
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_STENCIL_BACK_FUNC_ATI          0x8800
+#define GL_STENCIL_BACK_FAIL_ATI          0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890
+#define GL_DEPTH_BOUNDS_EXT               0x8891
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_MIRROR_CLAMP_EXT               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_BLEND_EQUATION_RGB_EXT         GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_PACK_INVERT_MESA               0x8758
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB
+#define GL_YCBCR_MESA                     0x8757
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */
+/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */
+#endif
+
+#ifndef GL_NV_vertex_program3
+/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT         0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT           0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT         0x8D20
+#define GL_FRAMEBUFFER_EXT                0x8D40
+#define GL_RENDERBUFFER_EXT               0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT             0x8D46
+#define GL_STENCIL_INDEX4_EXT             0x8D47
+#define GL_STENCIL_INDEX8_EXT             0x8D48
+#define GL_STENCIL_INDEX16_EXT            0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#endif
+
+
+/*************************************************************/
+
+#include <stddef.h>
+#ifndef GL_VERSION_2_0
+/* GL type for program/shader text */
+typedef char GLchar;			/* native character */
+#endif
+
+#ifndef GL_VERSION_1_5
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+#endif
+
+#ifndef GL_ARB_shader_objects
+/* GL types for handling shader object handles and program/shader text */
+typedef char GLcharARB;		/* native character */
+typedef unsigned int GLhandleARB;	/* shader object handle */
+#endif
+
+/* GL types for "half" precision (s10e5) float data in host memory */
+#ifndef GL_ARB_half_float_pixel
+typedef unsigned short GLhalfARB;
+#endif
+
+#ifndef GL_NV_half_float
+typedef unsigned short GLhalfNV;
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf);
+GLAPI void APIENTRY glBlendEquation (GLenum);
+GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogram (GLenum);
+GLAPI void APIENTRY glResetMinmax (GLenum);
+GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum);
+GLAPI void APIENTRY glClientActiveTexture (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glFogCoordf (GLfloat);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *);
+GLAPI void APIENTRY glFogCoordd (GLdouble);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glPointParameteri (GLenum, GLint);
+GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2i (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *);
+GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *);
+GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *);
+GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint);
+GLAPI void APIENTRY glBeginQuery (GLenum, GLuint);
+GLAPI void APIENTRY glEndQuery (GLenum);
+GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *);
+GLAPI void APIENTRY glBindBuffer (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint);
+GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum);
+GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint);
+GLAPI void APIENTRY glAttachShader (GLuint, GLuint);
+GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *);
+GLAPI void APIENTRY glCompileShader (GLuint);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum);
+GLAPI void APIENTRY glDeleteProgram (GLuint);
+GLAPI void APIENTRY glDeleteShader (GLuint);
+GLAPI void APIENTRY glDetachShader (GLuint, GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint);
+GLAPI GLboolean APIENTRY glIsShader (GLuint);
+GLAPI void APIENTRY glLinkProgram (GLuint);
+GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *);
+GLAPI void APIENTRY glUseProgram (GLuint);
+GLAPI void APIENTRY glUniform1f (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1i (GLint, GLint);
+GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glValidateProgram (GLuint);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *);
+GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *);
+GLAPI void APIENTRY glWeightivARB (GLint, const GLint *);
+GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *);
+GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *);
+GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexBlendARB (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#endif
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint);
+GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint);
+GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint);
+GLAPI void APIENTRY glEndQueryARB (GLenum);
+GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1iARB (GLint, GLint);
+GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+#endif
+
+#ifndef GL_EXT_color_matrix
+#define GL_EXT_color_matrix 1
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint);
+GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *);
+GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#endif
+
+#ifndef GL_SGIX_texture_select
+#define GL_SGIX_texture_select 1
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#endif
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#endif
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum);
+GLAPI void APIENTRY glTextureLightEXT (GLenum);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *);
+GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *);
+GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_SGIX_fog_scale 1
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#endif
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#endif
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride);
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params);
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#endif
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint);
+GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFinishFenceNV (GLuint);
+GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *);
+GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint);
+GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#endif
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint);
+GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *);
+GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *);
+GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+/* This is really a WGL extension, but defines some associated GL enums.
+ * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string.
+ */
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#endif
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/testing/app/qshare/FastDXT/viewdxt.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/viewdxt.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/viewdxt.cpp	(revision 4)
@@ -0,0 +1,347 @@
+/******************************************************************************
+ * a DXT viewing utility
+ *
+ * Author : Robert Kooima
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if defined(WIN32)
+#define strdup(x) _strdup(x)
+#else
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#define MAXSTR 256
+
+#include "dxt.h"
+#include "glsl.h"
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#endif
+
+#ifdef __linux__
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+#define glGetProcAddress(n) glXGetProcAddressARB((GLubyte *) n)
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include "glext.h"
+#define glGetProcAddress(n) wglGetProcAddress(n)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+byte *in_data;
+byte *dxt_data;
+byte *ref_data;
+
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef GLSL_YCOCG
+#ifndef __APPLE__
+static PFNGLGETCOMPRESSEDTEXIMAGEARBPROC  glGetCompressedTexImage;
+static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC   glCompressedTexImage2D;
+#endif
+#endif
+
+static void init_gl(void)
+{
+#ifndef __APPLE__
+    glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)
+               glGetProcAddress("glGetCompressedTexImageARB");
+    glCompressedTexImage2D  = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)
+               glGetProcAddress("glCompressedTexImage2DARB");
+#endif
+
+    glEnable(GL_TEXTURE_2D);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void out_rgb(int w, int h, const char *name)
+{
+    double e;
+    FILE *fout = NULL;
+
+    if ((fout = fopen(name, "wb")))
+    {
+        GLsizei sz = 3 * w * h;
+        GLubyte *p;
+
+        if ((p = (GLubyte *) malloc(sz)))
+        {
+	    glReadPixels( 0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, p );
+
+	    dxt_data = p;
+
+            fwrite(p, 1, sz, fout);
+
+            //free(p);
+
+	    // Compute error
+		e = ComputeError(ref_data, dxt_data, w, h);
+	    fprintf(stdout, "RMS Error %.4f\n", e);
+        }
+        fclose(fout);
+    }
+    else perror("fopen");
+}
+
+
+static void in_dxt(int w, int h, int format, const char *name)
+{
+    FILE *fin = NULL;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	if (format == 5 || format == 6)
+	  sz = 4 * w * h / 4;
+	else
+	  sz = 8 * (w / 4) * (h / 4);
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    int ww, hh;
+	    fread( &ww, sizeof( int ), 1, fin );
+	    fread( &hh, sizeof( int ), 1, fin );
+
+            fread(p, 1, sz, fin);
+
+	    if (format == 5 || format == 6)
+	      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+				     GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+				     w, h, 0, sz, p);
+	    else
+	      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+				     GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+				     w, h, 0, sz, p);
+            //free(p);
+	    in_data = p;
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void in_rgb(int w, int h, const char *name)
+{
+    FILE *fin = NULL;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	sz = 4 * w * h;
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    memset(p, 0, sz);
+
+            fread(p, 1, sz, fin);
+
+	    ref_data = p;
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void display(int w, int h)
+{
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustum(0, w, 0, h, 0, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glClearColor(0,1,0,0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glBegin(GL_POLYGON);
+    {
+        glTexCoord2i(0, 1); glVertex2i(-1, -1);
+        glTexCoord2i(1, 1); glVertex2i(+1, -1);
+        glTexCoord2i(1, 0); glVertex2i(+1, +1);
+        glTexCoord2i(0, 0); glVertex2i(-1, +1);
+    }
+    glEnd();
+
+    SDL_GL_SwapBuffers();
+}
+
+/*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+    int w = 1024;
+    int h = 512;
+    int p = 1;
+    int format = 1; // DXT1 or DXT5 or DXT5YCoCg (6)
+    int out = 0;
+    int argi;
+    char *rgbfile;
+
+    /* Process arguments. */
+
+    for (argi = 1; argi < argc; ++argi)
+        if      (strcmp(argv[argi], "-p") == 0) p = 0;
+        else if (strcmp(argv[argi], "-5") == 0) format = 5;
+        else if (strcmp(argv[argi], "-6") == 0) format = 6;
+        else if (strcmp(argv[argi], "-1") == 0) format = 1;
+        else if (strcmp(argv[argi], "-o") == 0) out = 1;
+        else if (strcmp(argv[argi], "-r") == 0) rgbfile = strdup(argv[++argi]);
+        else if (strcmp(argv[argi], "-w") == 0) w = atoi(argv[++argi]);
+        else if (strcmp(argv[argi], "-h") == 0) h = atoi(argv[++argi]);
+        else     break;
+
+    /* Use SDL to get an OpenGL context for use as compressor/decompressor. */
+
+    if (SDL_Init(SDL_INIT_VIDEO) == 0)
+    {
+        SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     8);
+        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   8);
+        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    8);
+        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
+        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+        if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL))
+        {
+            SDL_Event e;
+
+            init_gl();
+
+            /* Convert and display named files. */
+
+#if defined(GLSL_YCOCG)
+	    // Initialize the "OpenGL Extension Wrangler" library
+	    glewInit();
+
+	    if (!glewIsSupported("GL_VERSION_2_0 "
+				 "GL_ARB_vertex_program "
+				 "GL_ARB_fragment_program "
+				 "GL_ARB_texture_compression "
+				 "GL_EXT_texture_compression_s3tc "
+				 )
+		) {
+	      fprintf(stderr, "GLSL_YCOCG> Unable to load required OpenGL extension\n");
+	      exit(-1);
+	    }
+
+	    // Load the shaders
+	    GLchar *FragmentShaderSource;
+	    GLchar *VertexShaderSource;
+	    GLSLreadShaderSource("ycocg", &VertexShaderSource, &FragmentShaderSource);
+	    PHandle = GLSLinstallShaders(VertexShaderSource, FragmentShaderSource);
+
+	    /* Finally, use the program. */
+	    glUseProgramObjectARB(PHandle);
+
+	    glUseProgramObjectARB(0);
+#endif
+
+	    in_dxt(w, h, format, argv[argi]);
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      {
+		glUseProgramObjectARB(PHandle);
+		glActiveTexture(GL_TEXTURE0);
+		int h=glGetUniformLocationARB(PHandle,"yuvtex");
+		glUniform1iARB(h,0);  /* Bind yuvtex to texture unit 0 */
+	      }
+#endif
+
+	    display(w, h);
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      glUseProgramObjectARB(0);
+#endif
+
+	    if (out)
+	      {
+		in_rgb(w, h, rgbfile);      // ref_data
+		out_rgb(w, h, "out.rgb");   // dxt_data
+	      }
+
+            /* Pause until the user closes the window. */
+
+            if (p)
+            {
+                while (SDL_WaitEvent(&e))
+                    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+                        break;
+                    else {
+		      //display(w, h);
+		    }
+            }
+        }
+        else fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+
+        SDL_Quit();
+    }
+    else fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/qshare/FastDXT/example.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/example.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/example.cpp	(revision 4)
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+int
+main(int argc, char** argv)
+{
+  byte *in;
+  byte *out;
+  int nbbytes;
+
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[3], "rb");
+  fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting from raw: %ldx%ld\n", width, height);
+
+#define NUM_LOOPS 100
+
+  double t1, t2;
+
+  t1 = aTime();
+  for (int k=0;k<NUM_LOOPS;k++)
+    {
+      //CompressDXT(in, out, width, height, FORMAT_DXT5YCOCG, 4);
+      //CompressDXT(in, out, width, height, FORMAT_DXT5, 4);
+      CompressDXT(in, out, width, height, FORMAT_DXT1, 2);
+    }
+  t2 = aTime();
+
+  fprintf(stderr, "Time %.2f sec, Single %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, (t2-t1)/(double)NUM_LOOPS, ((double)NUM_LOOPS)/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+	  ((double)(width*height*NUM_LOOPS)) / ((t2-t1)*1000000.0) );
+
+#if 1
+  FILE *g=fopen("out.dxt", "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  //nbbytes = width * height * 4 / 4; //DXT5
+  nbbytes = width * height * 3 / 6; // DXT1
+  fwrite(out, 1, nbbytes, g);
+  fclose(g);
+#endif
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
+
+
Index: trunk/src/testing/app/qshare/FastDXT/libdxt.h
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/libdxt.h	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app/qshare/FastDXT/Makefile
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/Makefile	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/Makefile	(revision 4)
@@ -0,0 +1,73 @@
+CC=g++
+CXX=g++
+LDFLAGS=-O3
+LDLIBS=-lpthread
+CXXFLAGS=-O3 -funroll-loops -fomit-frame-pointer 
+
+OPTIM=1
+
+MACHINE=$(shell uname -s)
+ARCHITECTURE=$(shell uname -p)
+
+ifeq ($(MACHINE), Darwin)
+
+CXXFLAGS+=-I/opt/local/include
+LDLIBS+=-framework OpenGL
+
+ifeq ($(OPTIM), 1)
+# MacPro
+# CXXFLAGS+=-march=nocona -msse3 -DDXT_INTR
+
+# MacbookPro
+#CXXFLAGS+=-march=i686 -msse2 -DDXT_INTR
+CXXFLAGS+=-m32
+LDFLAGS+=-m32
+
+endif
+
+ifeq ($(ARCHITECTURE), powerpc)
+	# PowerPC Mac
+echo "Disabling SSE instructions on PowerPC"
+CXXFLAGS+=
+
+endif
+
+else
+
+LDLIBS+=-lGL
+
+ifeq ($(ARCHITECTURE), x86_64)
+	# Opteron
+CXXFLAGS+=-march=opteron -msse2 -DDXT_INTR
+
+else
+
+	# everything considered i386/linux
+CXXFLAGS+=-msse2 -DDXT_INTR
+
+endif
+
+endif
+
+CFLAGS=$(CXXFLAGS) `sdl-config --cflags` -I/opt/local/include
+
+
+default: main example 2dxt viewdxt playdxt
+
+main: dxt.o main.o util.o intrinsic.o
+example: example.o libdxt.o dxt.o util.o intrinsic.o
+2dxt: dxt.o 2dxt.o libdxt.o util.o intrinsic.o
+
+
+viewdxt:viewdxt.o glsl.o dxt.o
+	${CC} ${LDFLAGS} -o viewdxt viewdxt.o glsl.o dxt.o intrinsic.o `sdl-config --libs` $(LDLIBS) -lGLEW
+
+playdxt:playdxt.o glsl.o dxt.o
+	${CC} ${LDFLAGS} -o playdxt playdxt.o glsl.o dxt.o intrinsic.o `sdl-config --libs` $(LDLIBS) -lGLEW
+
+install: default
+	/bin/cp -f main example 2dxt playdxt viewdxt bin
+
+clean:
+	/bin/rm -f *.o *~ main example 2dxt playdxt viewdxt *.rgba *.dxt out.*
+
Index: trunk/src/testing/app/qshare/FastDXT/dxt.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app/qshare/FastDXT/glsl.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/glsl.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/glsl.cpp	(revision 4)
@@ -0,0 +1,341 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "glsl.h"
+
+#if defined(GLSL_YCOCG)
+
+GLhandleARB FSHandle,PHandle;
+
+/*---------------------------------------------------------------------------*/
+
+
+#define GLSLVertexShader   1
+#define GLSLFragmentShader 2
+
+int GLSLprintlError(char *file, int line)
+{
+    //
+    // Returns 1 if an OpenGL error occurred, 0 otherwise.
+    //
+    GLenum glErr;
+    int    retCode = 0;
+
+    glErr = glGetError();
+    while (glErr != GL_NO_ERROR)
+    {
+        fprintf(stderr, "GLSL> glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
+        retCode = 1;
+        glErr = glGetError();
+    }
+    return retCode;
+}
+
+//
+// Print out the information log for a shader object
+//
+static
+void GLSLprintShaderInfoLog(GLuint shader)
+{
+    GLint infologLength = 0;
+    GLint charsWritten  = 0;
+    GLchar *infoLog;
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    if (infologLength > 0)
+    {
+        infoLog = (GLchar *)malloc(infologLength);
+        if (infoLog == NULL)
+        {
+            fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+            exit(1);
+        }
+        glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
+        fprintf(stderr, "GLSL> Shader InfoLog:%s\n", infoLog);
+        free(infoLog);
+    }
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+//
+// Print out the information log for a program object
+//
+static
+void GLSLprintProgramInfoLog(GLuint program)
+{
+    GLint infologLength = 0;
+    GLint charsWritten  = 0;
+    GLchar *infoLog;
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    if (infologLength > 0)
+    {
+        infoLog = (GLchar *)malloc(infologLength);
+        if (infoLog == NULL)
+        {
+            fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+            exit(1);
+        }
+        glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
+        fprintf(stderr, "GLSL> Program InfoLog:%s\n", infoLog);
+        free(infoLog);
+    }
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+static
+int GLSLShaderSize(char *fileName, int shaderType)
+{
+    //
+    // Returns the size in bytes of the shader fileName.
+    // If an error occurred, it returns -1.
+    //
+    // File name convention:
+    //
+    // <fileName>.vert
+    // <fileName>.frag
+    //
+    int fd;
+    char name[256];
+    int count = -1;
+
+        memset(name, 0, 256);
+    strcpy(name, fileName);
+
+    switch (shaderType)
+    {
+        case GLSLVertexShader:
+            strcat(name, ".vert");
+            break;
+        case GLSLFragmentShader:
+            strcat(name, ".frag");
+            break;
+        default:
+            fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+            exit(1);
+            break;
+    }
+
+    //
+    // Open the file, seek to the end to find its length
+    //
+#ifdef WIN32
+    fd = _open(name, _O_RDONLY);
+    if (fd != -1)
+    {
+        count = _lseek(fd, 0, SEEK_END) + 1;
+        _close(fd);
+    }
+#else
+    fd = open(name, O_RDONLY);
+    if (fd != -1)
+    {
+        count = lseek(fd, 0, SEEK_END) + 1;
+        close(fd);
+    }
+#endif
+    return count;
+}
+
+
+int GLSLreadShader(char *fileName, int shaderType, char *shaderText, int size)
+{
+    //
+    // Reads a shader from the supplied file and returns the shader in the
+    // arrays passed in. Returns 1 if successful, 0 if an error occurred.
+    // The parameter size is an upper limit of the amount of bytes to read.
+    // It is ok for it to be too big.
+    //
+    FILE *fh;
+    char name[100];
+    int count;
+
+    strcpy(name, fileName);
+
+    switch (shaderType)
+    {
+        case GLSLVertexShader:
+            strcat(name, ".vert");
+            break;
+        case GLSLFragmentShader:
+            strcat(name, ".frag");
+            break;
+        default:
+            fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+            exit(1);
+            break;
+    }
+
+    //
+    // Open the file
+    //
+    fh = fopen(name, "r");
+    if (!fh)
+        return -1;
+
+
+    //
+    // Get the shader from a file.
+    //
+    fseek(fh, 0, SEEK_SET);
+    count = (int) fread(shaderText, 1, size, fh);
+    shaderText[count] = '\0';
+
+    if (ferror(fh))
+        count = 0;
+
+    fclose(fh);
+    return count;
+}
+
+int GLSLreadShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)
+{
+    int vSize, fSize;
+
+    //
+    // Allocate memory to hold the source of our shaders.
+    //
+
+    fprintf(stderr, "GLSL> load shader %s\n", fileName);
+    if (vertexShader) {
+        vSize = GLSLShaderSize(fileName, GLSLVertexShader);
+
+        if (vSize == -1) {
+            fprintf(stderr, "GLSL> Cannot determine size of the vertex shader %s\n", fileName);
+            return 0;
+        }
+
+        *vertexShader = (GLchar *) malloc(vSize);
+
+        //
+        // Read the source code
+        //
+        if (!GLSLreadShader(fileName, GLSLVertexShader, *vertexShader, vSize)) {
+            fprintf(stderr, "GLSL> Cannot read the file %s.vert\n", fileName);
+            return 0;
+        }
+    }
+
+    if (fragmentShader) {
+        fSize = GLSLShaderSize(fileName, GLSLFragmentShader);
+
+        if (fSize == -1) {
+            fprintf(stderr, "GLSL> Cannot determine size of the fragment shader %s\n", fileName);
+            return 0;
+        }
+
+        *fragmentShader = (GLchar *) malloc(fSize);
+
+        if (!GLSLreadShader(fileName, GLSLFragmentShader, *fragmentShader, fSize)) {
+            fprintf(stderr, "GLSL> Cannot read the file %s.frag\n", fileName);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+
+GLuint GLSLinstallShaders(const GLchar *Vertex, const GLchar *Fragment)
+{
+        GLuint VS, FS, Prog;   // handles to objects
+        GLint  vertCompiled, fragCompiled;    // status values
+        GLint  linked;
+
+        // Create a program object
+        Prog = glCreateProgram();
+
+        // Create a vertex shader object and a fragment shader object
+        if (Vertex) {
+                VS = glCreateShader(GL_VERTEX_SHADER);
+
+                // Load source code strings into shaders
+                glShaderSource(VS, 1, &Vertex, NULL);
+
+                // Compile the vertex shader, and print out
+                // the compiler log file.
+
+                glCompileShader(VS);
+                GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+                glGetShaderiv(VS, GL_COMPILE_STATUS, &vertCompiled);
+                GLSLprintShaderInfoLog(VS);
+
+                if (!vertCompiled)
+                  return 0;
+
+                glAttachShader(Prog, VS);
+        }
+
+
+        if (Fragment) {
+                FS = glCreateShader(GL_FRAGMENT_SHADER);
+
+                glShaderSource(FS, 1, &Fragment, NULL);
+
+                glCompileShader(FS);
+                GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+                glGetShaderiv(FS, GL_COMPILE_STATUS, &fragCompiled);
+                GLSLprintShaderInfoLog(FS);
+
+                if (!fragCompiled)
+                  return 0;
+
+                glAttachShader(Prog, FS);
+        }
+
+        // Link the program object and print out the info log
+        glLinkProgram(Prog);
+        GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+        glGetProgramiv(Prog, GL_LINK_STATUS, &linked);
+        GLSLprintProgramInfoLog(Prog);
+
+        if (!linked)
+          return 0;
+
+        return Prog;
+}
+
+#endif
+
Index: trunk/src/testing/app/qshare/FastDXT/intrinsic.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app/qshare/FastDXT/dxt.h
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/dxt.h	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/dxt.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app/qshare/FastDXT/glsl.h
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/glsl.h	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/glsl.h	(revision 4)
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#define GLSL_YCOCG 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#if defined(WIN32)
+#include <io.h>
+#else
+#include <unistd.h>
+#define GLEW_STATIC 1
+#endif
+
+#if defined(GLSL_YCOCG)
+
+#include <GL/glew.h>
+
+
+extern GLhandleARB PHandle;
+
+int GLSLreadShader(char *fileName, int shaderType, char *shaderText, int size);
+int GLSLreadShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader);
+GLuint GLSLinstallShaders(const GLchar *Vertex, const GLchar *Fragment);
+
+#endif
+
Index: trunk/src/testing/app/qshare/FastDXT/util.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/util.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/util.cpp	(revision 4)
@@ -0,0 +1,152 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+static LARGE_INTEGER perf_freq;
+static LARGE_INTEGER perf_start;
+static HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void dxt_aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double dxt_aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
Index: trunk/src/testing/app/qshare/FastDXT/2dxt.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/2dxt.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/2dxt.cpp	(revision 4)
@@ -0,0 +1,121 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//
+// Usage: ./2dxt width height type rawfile dxtfile
+//
+
+#define NUMTHREAD 2
+
+#include "libdxt.h"
+
+int
+main(int argc, char** argv)
+{
+  byte *in;
+  byte *out;
+  int nbbytes;
+
+  if (argc != 6)
+  {
+	fprintf(stderr, "Usage: ./2dxt width height type rawfile dxtfile\n");
+	exit(0);
+  }
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  int format = 1;
+  format = atoi(argv[3]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[4], "rb");
+  int res=(int)fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting to raw: %ldx%ld\n", width, height);
+
+  double t1, t2;
+  t1 = aTime();
+  nbbytes = 0;
+  switch (format) {
+  case 1:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT1, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT1: from %d bytes to %ld bytes\n",
+	    width*height*4, nbbytes);
+    break;
+  case 5:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT5, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT5: from %d bytes to %ld bytes\n",
+	  width*height*4, nbbytes);
+    break;
+  case 6:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT5YCOCG, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT5-YCoCg: from %d bytes to %ld bytes\n",
+	    width*height*4, nbbytes);
+    break;
+  }
+  t2 = aTime();
+
+  fprintf(stderr, "Time %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, 1.0/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+          ((double)(width*height)) / ((t2-t1)*1000000.0) );
+
+  FILE *g=fopen(argv[5], "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  int res2=(int)fwrite(out, 1, nbbytes, g);
+  fclose(g);
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
+
Index: trunk/src/testing/app/qshare/FastDXT/util.h
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/util.h	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/util.h	(revision 4)
@@ -0,0 +1,92 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   dxt_aInitialize();
+
+double dxt_aTime();
+
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
Index: trunk/src/testing/app/qshare/FastDXT/main.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/main.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/main.cpp	(revision 4)
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+int
+main(int argc, char** argv)
+{
+  ALIGN16( byte *in );
+  ALIGN16( byte *out);
+  double t1, t2;
+  int nbbytes;
+
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[3], "rb");
+  fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting to raw: %ldx%ld\n", width, height);
+
+  t1 = aTime();
+  for (int k=0;k<100;k++)
+    {
+		CompressImageDXT1( in, out, width, height, nbbytes);
+    }
+  t2 = aTime();
+
+  fprintf(stderr, "Converted to DXT: %d byte, compression %ld\n",
+	  nbbytes, (width*height*4) / (nbbytes));
+  fprintf(stderr, "Time %.2f sec, Single %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, (t2-t1)/100.0, 100.0/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+	  ((double)(width*height)) / ((t2-t1)*10000.0) );
+
+#if 1
+  FILE *g=fopen("out.dxt", "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  //nbbytes = width * height * 4 / 4; //DXT5
+  nbbytes = width * height * 3 / 6; // DXT1
+  fwrite(out, 1, nbbytes, g);
+  fclose(g);
+#endif
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
Index: trunk/src/testing/app/qshare/FastDXT/playdxt.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/playdxt.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/playdxt.cpp	(revision 4)
@@ -0,0 +1,274 @@
+/******************************************************************************
+ * a DXT viewing utility
+ *
+ * Author : Robert Kooima
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#define MAXSTR 256
+
+#include "dxt.h"
+#include "glsl.h"
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#endif
+
+#ifdef __linux__
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+#define glGetProcAddress(n) glXGetProcAddressARB((GLubyte *) n)
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include "glext.h"
+#define glGetProcAddress(n) wglGetProcAddress(n)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef GLSL_YCOCG
+#ifndef __APPLE__
+static PFNGLGETCOMPRESSEDTEXIMAGEARBPROC  glGetCompressedTexImage;
+static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC   glCompressedTexImage2D;
+#endif
+#endif
+
+static void init_gl(void)
+{
+#ifndef __APPLE__
+    glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)
+               glGetProcAddress("glGetCompressedTexImageARB");
+    glCompressedTexImage2D  = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)
+               glGetProcAddress("glCompressedTexImage2DARB");
+#endif
+
+    glEnable(GL_TEXTURE_2D);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+static void in_dxt(int w, int h, int format, const char *name)
+{
+    FILE *fin = NULL;
+    static int first = 1;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	if (format == 5 || format == 6)
+	  sz = 4 * w * h / 4;
+	else
+	  sz = 8 * (w / 4) * (h / 4);
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    int ww, hh;
+	    fread( &ww, sizeof( int ), 1, fin );
+	    fread( &hh, sizeof( int ), 1, fin );
+
+            fread(p, 1, sz, fin);
+
+		    if (format == 5 || format == 6)
+		      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+					     GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+					     w, h, 0, sz, p);
+		    else
+		      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+					     GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+					     w, h, 0, sz, p);
+            free(p);
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void display(int w, int h)
+{
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustum(0, w, 0, h, 0, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glClearColor(0,1,0,1);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glBegin(GL_POLYGON);
+    {
+        glTexCoord2i(0, 1); glVertex2i(-1, -1);
+        glTexCoord2i(1, 1); glVertex2i(+1, -1);
+        glTexCoord2i(1, 0); glVertex2i(+1, +1);
+        glTexCoord2i(0, 0); glVertex2i(-1, +1);
+    }
+    glEnd();
+
+    glFinish();
+
+    SDL_GL_SwapBuffers();
+}
+
+/*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+    int w = 1024;
+    int h = 512;
+    int format = 1; // DXT1 or DXT5 or DXT5YCoCg (6)
+    int out = 0;
+    int argi;
+
+    /* Process arguments. */
+
+    for (argi = 1; argi < argc; ++argi)
+        if (strcmp(argv[argi], "-5") == 0) format = 5;
+        else if (strcmp(argv[argi], "-6") == 0) format = 6;
+        else if (strcmp(argv[argi], "-1") == 0) format = 1;
+        else if (strcmp(argv[argi], "-w") == 0) w = atoi(argv[++argi]);
+        else if (strcmp(argv[argi], "-h") == 0) h = atoi(argv[++argi]);
+        else     break;
+
+    /* Use SDL to get an OpenGL context for use as compressor/decompressor. */
+
+    if (SDL_Init(SDL_INIT_VIDEO) == 0)
+    {
+        //SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     8);
+        //SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   8);
+        //SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    8);
+        //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
+        //SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+        if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL))
+        {
+            SDL_Event e;
+
+            init_gl();
+
+            /* Convert and display named files. */
+
+#if defined(GLSL_YCOCG)
+	    // Initialize the "OpenGL Extension Wrangler" library
+	    glewInit();
+
+	    if (!glewIsSupported("GL_VERSION_2_0 "
+				 "GL_ARB_vertex_program "
+				 "GL_ARB_fragment_program "
+				 "GL_ARB_texture_compression "
+				 "GL_EXT_texture_compression_s3tc "
+				 )
+		) {
+	      fprintf(stderr, "GLSL_YCOCG> Unable to load required OpenGL extension\n");
+	      exit(-1);
+	    }
+
+	    // Load the shaders
+	    GLchar *FragmentShaderSource;
+	    GLchar *VertexShaderSource;
+	    GLSLreadShaderSource("ycocg", &VertexShaderSource, &FragmentShaderSource);
+	    PHandle = GLSLinstallShaders(VertexShaderSource, FragmentShaderSource);
+
+	    /* Finally, use the program. */
+	    glUseProgramObjectARB(PHandle);
+
+	    glUseProgramObjectARB(0);
+#endif
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	    {
+			glUseProgramObjectARB(PHandle);
+			glActiveTexture(GL_TEXTURE0);
+			int h=glGetUniformLocationARB(PHandle,"yuvtex");
+			glUniform1iARB(h,0);  /* Bind yuvtex to texture unit 0 */
+	    }
+#endif
+
+
+		for (; argi < argc; ++argi)
+		{
+			in_dxt(w, h, format, argv[argi]);
+			display(w, h);
+
+			while (SDL_PollEvent(&e))
+			    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+				break;
+		}
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      glUseProgramObjectARB(0);
+#endif
+
+		while (SDL_WaitEvent(&e))
+		    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+			break;
+
+        }
+        else fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+
+        SDL_Quit();
+    }
+    else fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/qshare/FastDXT/libdxt.cpp
===================================================================
--- trunk/src/testing/app/qshare/FastDXT/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app/qshare/FastDXT/libdxt.cpp	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app/qshare/Makefile
===================================================================
--- trunk/src/testing/app/qshare/Makefile	(revision 4)
+++ trunk/src/testing/app/qshare/Makefile	(revision 4)
@@ -0,0 +1,255 @@
+#############################################################################
+# Makefile for building: qshare
+# Generated by qmake (2.01a) (Qt 4.7.2) on: czw. sty 26 13:58:09 2012
+# Project:  qshare.pro
+# Template: app
+# Command: /usr/bin/qmake -o Makefile qshare.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
+CFLAGS        = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+CXXFLAGS      = -pipe -DDXT_INTR -O2 -Wall -W -D_REENTRANT $(DEFINES)
+INCPATH       = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -IFastDXT -I../../include -I. -I.
+LINK          = g++
+LFLAGS        = -Wl,-O1
+LIBS          = $(SUBLIBS)  -L/usr/lib -L../../lib -lsail -lquanta -lQtGui -lQtCore -lpthread 
+AR            = ar cqs
+RANLIB        = 
+QMAKE         = /usr/bin/qmake
+TAR           = tar -cf
+COMPRESS      = gzip -9f
+COPY          = cp -f
+SED           = sed
+COPY_FILE     = $(COPY)
+COPY_DIR      = $(COPY) -r
+STRIP         = strip
+INSTALL_FILE  = install -m 644 -p
+INSTALL_DIR   = $(COPY_DIR)
+INSTALL_PROGRAM = install -m 755 -p
+DEL_FILE      = rm -f
+SYMLINK       = ln -f -s
+DEL_DIR       = rmdir
+MOVE          = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR         = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR   = ./
+
+####### Files
+
+SOURCES       = main.cpp \
+		capturewindow.cpp \
+		FastDXT/libdxt.cpp \
+		FastDXT/dxt.cpp \
+		FastDXT/util.cpp \
+		FastDXT/intrinsic.cpp moc_capturewindow.cpp
+OBJECTS       = main.o \
+		capturewindow.o \
+		libdxt.o \
+		dxt.o \
+		util.o \
+		intrinsic.o \
+		moc_capturewindow.o
+DIST          = /usr/share/qt4/mkspecs/common/g++.conf \
+		/usr/share/qt4/mkspecs/common/unix.conf \
+		/usr/share/qt4/mkspecs/common/linux.conf \
+		/usr/share/qt4/mkspecs/qconfig.pri \
+		/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
+		/usr/share/qt4/mkspecs/features/qt_functions.prf \
+		/usr/share/qt4/mkspecs/features/qt_config.prf \
+		/usr/share/qt4/mkspecs/features/exclusive_builds.prf \
+		/usr/share/qt4/mkspecs/features/default_pre.prf \
+		/usr/share/qt4/mkspecs/features/release.prf \
+		/usr/share/qt4/mkspecs/features/default_post.prf \
+		/usr/share/qt4/mkspecs/features/warn_on.prf \
+		/usr/share/qt4/mkspecs/features/qt.prf \
+		/usr/share/qt4/mkspecs/features/unix/thread.prf \
+		/usr/share/qt4/mkspecs/features/moc.prf \
+		/usr/share/qt4/mkspecs/features/resources.prf \
+		/usr/share/qt4/mkspecs/features/uic.prf \
+		/usr/share/qt4/mkspecs/features/yacc.prf \
+		/usr/share/qt4/mkspecs/features/lex.prf \
+		/usr/share/qt4/mkspecs/features/include_source_dir.prf \
+		qshare.pro
+QMAKE_TARGET  = qshare
+DESTDIR       = 
+TARGET        = qshare
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .o .c .cpp .cc .cxx .C
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.C.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
+
+####### Build rules
+
+all: Makefile $(TARGET)
+
+$(TARGET): ui_capturewindow.h $(OBJECTS)  
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
+
+Makefile: qshare.pro  /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \
+		/usr/share/qt4/mkspecs/common/unix.conf \
+		/usr/share/qt4/mkspecs/common/linux.conf \
+		/usr/share/qt4/mkspecs/qconfig.pri \
+		/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \
+		/usr/share/qt4/mkspecs/features/qt_functions.prf \
+		/usr/share/qt4/mkspecs/features/qt_config.prf \
+		/usr/share/qt4/mkspecs/features/exclusive_builds.prf \
+		/usr/share/qt4/mkspecs/features/default_pre.prf \
+		/usr/share/qt4/mkspecs/features/release.prf \
+		/usr/share/qt4/mkspecs/features/default_post.prf \
+		/usr/share/qt4/mkspecs/features/warn_on.prf \
+		/usr/share/qt4/mkspecs/features/qt.prf \
+		/usr/share/qt4/mkspecs/features/unix/thread.prf \
+		/usr/share/qt4/mkspecs/features/moc.prf \
+		/usr/share/qt4/mkspecs/features/resources.prf \
+		/usr/share/qt4/mkspecs/features/uic.prf \
+		/usr/share/qt4/mkspecs/features/yacc.prf \
+		/usr/share/qt4/mkspecs/features/lex.prf \
+		/usr/share/qt4/mkspecs/features/include_source_dir.prf \
+		/usr/lib/libQtGui.prl \
+		/usr/lib/libQtCore.prl
+	$(QMAKE) -o Makefile qshare.pro
+/usr/share/qt4/mkspecs/common/g++.conf:
+/usr/share/qt4/mkspecs/common/unix.conf:
+/usr/share/qt4/mkspecs/common/linux.conf:
+/usr/share/qt4/mkspecs/qconfig.pri:
+/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri:
+/usr/share/qt4/mkspecs/features/qt_functions.prf:
+/usr/share/qt4/mkspecs/features/qt_config.prf:
+/usr/share/qt4/mkspecs/features/exclusive_builds.prf:
+/usr/share/qt4/mkspecs/features/default_pre.prf:
+/usr/share/qt4/mkspecs/features/release.prf:
+/usr/share/qt4/mkspecs/features/default_post.prf:
+/usr/share/qt4/mkspecs/features/warn_on.prf:
+/usr/share/qt4/mkspecs/features/qt.prf:
+/usr/share/qt4/mkspecs/features/unix/thread.prf:
+/usr/share/qt4/mkspecs/features/moc.prf:
+/usr/share/qt4/mkspecs/features/resources.prf:
+/usr/share/qt4/mkspecs/features/uic.prf:
+/usr/share/qt4/mkspecs/features/yacc.prf:
+/usr/share/qt4/mkspecs/features/lex.prf:
+/usr/share/qt4/mkspecs/features/include_source_dir.prf:
+/usr/lib/libQtGui.prl:
+/usr/lib/libQtCore.prl:
+qmake:  FORCE
+	@$(QMAKE) -o Makefile qshare.pro
+
+dist: 
+	@$(CHK_DIR_EXISTS) .tmp/qshare1.0.0 || $(MKDIR) .tmp/qshare1.0.0 
+	$(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/qshare1.0.0/ && $(COPY_FILE) --parents capturewindow.h .tmp/qshare1.0.0/ && $(COPY_FILE) --parents main.cpp capturewindow.cpp FastDXT/libdxt.cpp FastDXT/dxt.cpp FastDXT/util.cpp FastDXT/intrinsic.cpp .tmp/qshare1.0.0/ && $(COPY_FILE) --parents capturewindow.ui .tmp/qshare1.0.0/ && (cd `dirname .tmp/qshare1.0.0` && $(TAR) qshare1.0.0.tar qshare1.0.0 && $(COMPRESS) qshare1.0.0.tar) && $(MOVE) `dirname .tmp/qshare1.0.0`/qshare1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/qshare1.0.0
+
+
+clean:compiler_clean 
+	-$(DEL_FILE) $(OBJECTS)
+	-$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+	-$(DEL_FILE) $(TARGET) 
+	-$(DEL_FILE) Makefile
+
+
+check: first
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+compiler_moc_header_make_all: moc_capturewindow.cpp
+compiler_moc_header_clean:
+	-$(DEL_FILE) moc_capturewindow.cpp
+moc_capturewindow.cpp: ui_capturewindow.h \
+		capturewindow.h
+	/usr/bin/moc-qt4 $(DEFINES) $(INCPATH) capturewindow.h -o moc_capturewindow.cpp
+
+compiler_rcc_make_all:
+compiler_rcc_clean:
+compiler_image_collection_make_all: qmake_image_collection.cpp
+compiler_image_collection_clean:
+	-$(DEL_FILE) qmake_image_collection.cpp
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all: ui_capturewindow.h
+compiler_uic_clean:
+	-$(DEL_FILE) ui_capturewindow.h
+ui_capturewindow.h: capturewindow.ui
+	/usr/bin/uic-qt4 capturewindow.ui -o ui_capturewindow.h
+
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_moc_header_clean compiler_uic_clean 
+
+####### Compile
+
+main.o: main.cpp capturewindow.h \
+		ui_capturewindow.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
+
+capturewindow.o: capturewindow.cpp capturewindow.h \
+		ui_capturewindow.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o capturewindow.o capturewindow.cpp
+
+libdxt.o: FastDXT/libdxt.cpp FastDXT/libdxt.h \
+		FastDXT/dxt.h \
+		FastDXT/util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o libdxt.o FastDXT/libdxt.cpp
+
+dxt.o: FastDXT/dxt.cpp FastDXT/dxt.h \
+		FastDXT/util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o dxt.o FastDXT/dxt.cpp
+
+util.o: FastDXT/util.cpp FastDXT/util.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o util.o FastDXT/util.cpp
+
+intrinsic.o: FastDXT/intrinsic.cpp FastDXT/dxt.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o intrinsic.o FastDXT/intrinsic.cpp
+
+moc_capturewindow.o: moc_capturewindow.cpp 
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_capturewindow.o moc_capturewindow.cpp
+
+####### Install
+
+install_target: first FORCE
+	@$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/home/jawora/SAGE/experimental/app/qshare/../../bin/ || $(MKDIR) $(INSTALL_ROOT)/home/jawora/SAGE/experimental/app/qshare/../../bin/ 
+	-$(INSTALL_PROGRAM) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/home/jawora/SAGE/experimental/bin/$(QMAKE_TARGET)"
+	-$(STRIP) "$(INSTALL_ROOT)/home/jawora/SAGE/experimental/bin/$(QMAKE_TARGET)"
+
+uninstall_target:  FORCE
+	-$(DEL_FILE) "$(INSTALL_ROOT)/home/jawora/SAGE/experimental/bin/$(QMAKE_TARGET)"
+	-$(DEL_DIR) $(INSTALL_ROOT)/home/jawora/SAGE/experimental/app/qshare/../../bin/ 
+
+
+install:  install_target  FORCE
+
+uninstall: uninstall_target   FORCE
+
+FORCE:
+
Index: trunk/src/testing/app/qshare/qshare.sln
===================================================================
--- trunk/src/testing/app/qshare/qshare.sln	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.sln	(revision 4)
@@ -0,0 +1,25 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qshare", "qshare.vcproj", "{F4057A98-7444-366A-8797-8922F87DCDD0}"
+EndProject
+Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "qshare_install", "qshare_install\qshare_install.vdproj", "{55324C5B-E96E-4A3A-9879-39FDD0853D7F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F4057A98-7444-366A-8797-8922F87DCDD0}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F4057A98-7444-366A-8797-8922F87DCDD0}.Debug|Win32.Build.0 = Debug|Win32
+		{F4057A98-7444-366A-8797-8922F87DCDD0}.Release|Win32.ActiveCfg = Release|Win32
+		{F4057A98-7444-366A-8797-8922F87DCDD0}.Release|Win32.Build.0 = Release|Win32
+		{55324C5B-E96E-4A3A-9879-39FDD0853D7F}.Debug|Win32.ActiveCfg = Debug
+		{55324C5B-E96E-4A3A-9879-39FDD0853D7F}.Debug|Win32.Build.0 = Debug
+		{55324C5B-E96E-4A3A-9879-39FDD0853D7F}.Release|Win32.ActiveCfg = Release
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
Index: trunk/src/testing/app/qshare/capturewindow.h
===================================================================
--- trunk/src/testing/app/qshare/capturewindow.h	(revision 4)
+++ trunk/src/testing/app/qshare/capturewindow.h	(revision 4)
@@ -0,0 +1,64 @@
+#ifndef CAPTUREWINDOW_H
+#define CAPTUREWINDOW_H
+
+#include <QMainWindow>
+#include <QCloseEvent>
+#include <QtDebug>
+#include <QTimer>
+#include <QDir>
+#include <QImage>
+#include <QPainter>
+#include <QDesktopWidget>
+#include "ui_capturewindow.h"
+
+#if defined(__APPLE__)
+  // Mac Headers
+  #include <CoreFoundation/CoreFoundation.h>
+  #include <ApplicationServices/ApplicationServices.h>
+  #include <OpenGL/OpenGL.h>
+  #include <OpenGL/gl.h>
+  #include <OpenGL/glext.h>
+#endif
+
+
+class CaptureWindow : public QMainWindow
+{
+Q_OBJECT
+public:
+    explicit CaptureWindow(QWidget *parent = 0);
+
+protected:
+     void closeEvent(QCloseEvent *event);
+
+public slots:
+    void onStart();
+    void onStop();
+    void onPause();
+    void update();
+    void fsIP(QString);
+    void frameRate(int);
+    void compression(int);
+    void cursor(int);
+
+private:
+    Ui_CaptureWindow ui;
+    int fps;
+    double startt;
+    int count;
+    bool started;
+    bool dxt;
+    bool showcursor;
+    QTimer *timer;
+    QImage *cursor_icon, *desktop;
+    int WW, HH;
+    QString fsip;
+
+#if defined(__APPLE__)
+    CGLContextObj  glContextObj;
+#endif
+
+private:
+    void capture(char* m_pFrameRGB,int x,int y,int cx,int cy);
+};
+
+#endif // CAPTUREWINDOW_H
Index: trunk/src/testing/app/qshare/qshare.pro
===================================================================
--- trunk/src/testing/app/qshare/qshare.pro	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.pro	(revision 4)
@@ -0,0 +1,53 @@
+# Mac - Linux : to expand with: qmake -spec macx-g++
+# Win32 :
+#  set QMAKESPEC=win32-msvc2008
+#  qmake -tp vc -config debug
+
+
+TARGET = qshare
+DESTDIR= $$(PWD)
+CONFIG += x86
+TEMPLATE = app
+FORMS = capturewindow.ui
+SOURCES = main.cpp \
+	capturewindow.cpp \
+	FastDXT/libdxt.cpp \
+        FastDXT/dxt.cpp \
+        FastDXT/util.cpp \
+        FastDXT/intrinsic.cpp
+
+HEADERS += capturewindow.h
+
+INCLUDEPATH += FastDXT
+
+QMAKE_CXXFLAGS += -DDXT_INTR
+
+RC_FILE = qsharerc.rc
+
+macx { 
+    INCLUDEPATH += ../../include
+    LIBS += -m32 -L../../lib -lsail -framework OpenGL -framework Cocoa -framework IOKit -lobjc -lm
+}
+unix:!macx { 
+    INCLUDEPATH += ../../include
+    LIBS += -L../../lib -lsail -lquanta
+}
+win32 {
+    QMAKE_CXXFLAGS += -D_CRT_SECURE_NO_WARNINGS
+    CONFIG += embed_manifest_exe
+    INCLUDEPATH += ../../include
+    INCLUDEPATH += ../../win32/include
+    LIBS += -L../../lib -L../../win32/lib -lsail -lpthread -lWs2_32 -lquanta
+}
+
+RESOURCES += 
+target.path=../../bin
+INSTALLS += target
+
+message(Qt version: $$[QT_VERSION])
+message(Qt is installed in $$[QT_INSTALL_PREFIX])
+message(Qt resources can be found in the following locations:)
+message(Header files: $$[QT_INSTALL_HEADERS])
+message(Libraries: $$[QT_INSTALL_LIBS])
+
+OTHER_FILES +=
Index: trunk/src/testing/app/qshare/qshare.vcproj
===================================================================
--- trunk/src/testing/app/qshare/qshare.vcproj	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.vcproj	(revision 4)
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9,00"
+	Name="qshare"
+	ProjectGUID="{F4057A98-7444-366A-8797-8922F87DCDD0}"
+	Keyword="Qt4VSv1.0">
+	<Platforms>
+		<Platform
+			Name="Win32" />
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="."
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			ConfigurationType="1"
+			IntermediateDirectory="debug\"
+			UseOfMfc="0">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;c:\Qt\4.7.0\include\QtCore&quot;,&quot;c:\Qt\4.7.0\include\QtGui&quot;,&quot;c:\Qt\4.7.0\include&quot;,&quot;FastDXT&quot;,&quot;..\..\include&quot;,&quot;..\..\win32\include&quot;,&quot;c:\Qt\4.7.0\include\ActiveQt&quot;,&quot;debug&quot;,&quot;.&quot;,c:\Qt\4.7.0\mkspecs\win32-msvc2008"
+				AdditionalOptions="-Zm200 -w34100 -w34189"
+				AssemblerListingLocation="debug\"
+				BufferSecurityCheck="false"
+				DebugInformationFormat="3"
+				ExceptionHandling="1"
+				GeneratePreprocessedFile="0"
+				ObjectFile="debug\"
+				Optimization ="4"
+				PreprocessorDefinitions="DXT_INTR,_CRT_SECURE_NO_WARNINGS,_WINDOWS,UNICODE,WIN32,QT_LARGEFILE_SUPPORT,QT_DLL,QT_GUI_LIB,QT_CORE_LIB,QT_THREAD_SUPPORT"
+				ProgramDataBaseFileName=".\"
+				RuntimeLibrary="3"
+				RuntimeTypeInfo="true"
+				SuppressStartupBanner="true"
+				TreatWChar_tAsBuiltInType="false"
+				WarningLevel="3" />
+			<Tool
+				Name="VCCustomBuildTool" />
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="c:\Qt\4.7.0\lib\qtmaind.lib ../../lib\sail.lib ../../win32/lib\pthread.lib Ws2_32.lib ../../win32/lib\quanta.lib c:\Qt\4.7.0\lib\QtGuid4.lib c:\Qt\4.7.0\lib\QtCored4.lib"
+				AdditionalLibraryDirectories="c:\Qt\4.7.0\lib,../../lib,../../win32/lib"
+				AdditionalOptions="&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot;"
+				GenerateDebugInformation="true"
+				IgnoreImportLibrary="true"
+				LinkTimeCodeGeneration="0"
+				OutputFile="debug\qshare.exe"
+				ProgramDatabaseFile=""
+				SubSystem="2"
+				SuppressStartupBanner="true" />
+			<Tool
+				Name="VCMIDLTool"
+				DefaultCharType="0"
+				EnableErrorChecks="1"
+				WarningLevel="0" />
+			<Tool
+				Name="VCPostBuildEventTool" />
+			<Tool
+				Name="VCPreBuildEventTool" />
+			<Tool
+				Name="VCPreLinkEventTool" />
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="DXT_INTR,_CRT_SECURE_NO_WARNINGS,_WINDOWS,UNICODE,WIN32,QT_LARGEFILE_SUPPORT,QT_DLL,QT_GUI_LIB,QT_CORE_LIB,QT_THREAD_SUPPORT,_DEBUG" />
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="."
+			ATLMinimizesCRunTimeLibraryUsage="false"
+			ConfigurationType="1"
+			IntermediateDirectory="release\"
+			UseOfMfc="0">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;c:\Qt\4.7.0\include\QtCore&quot;,&quot;c:\Qt\4.7.0\include\QtGui&quot;,&quot;c:\Qt\4.7.0\include&quot;,&quot;FastDXT&quot;,&quot;..\..\include&quot;,&quot;..\..\win32\include&quot;,&quot;c:\Qt\4.7.0\include\ActiveQt&quot;,&quot;release&quot;,&quot;.&quot;,c:\Qt\4.7.0\mkspecs\win32-msvc2008"
+				AdditionalOptions="-Zm200 -w34100 -w34189"
+				AssemblerListingLocation="release\"
+				BufferSecurityCheck="false"
+				DebugInformationFormat="0"
+				ExceptionHandling="1"
+				GeneratePreprocessedFile="0"
+				ObjectFile="release\"
+				Optimization ="2"
+				PreprocessorDefinitions="DXT_INTR,_CRT_SECURE_NO_WARNINGS,QT_NO_DEBUG,NDEBUG,_WINDOWS,UNICODE,WIN32,QT_LARGEFILE_SUPPORT,QT_DLL,QT_NO_DEBUG,QT_GUI_LIB,QT_CORE_LIB,QT_THREAD_SUPPORT,NDEBUG"
+				ProgramDataBaseFileName=".\"
+				RuntimeLibrary="2"
+				RuntimeTypeInfo="true"
+				SuppressStartupBanner="true"
+				TreatWChar_tAsBuiltInType="false"
+				WarningLevel="3" />
+			<Tool
+				Name="VCCustomBuildTool" />
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="c:\Qt\4.7.0\lib\qtmain.lib ../../lib\sail.lib ../../win32/lib\pthread.lib Ws2_32.lib ../../win32/lib\quanta.lib c:\Qt\4.7.0\lib\QtGui4.lib c:\Qt\4.7.0\lib\QtCore4.lib"
+				AdditionalLibraryDirectories="c:\Qt\4.7.0\lib,../../lib,../../win32/lib"
+				AdditionalOptions="&quot;/MANIFESTDEPENDENCY:type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos; processorArchitecture=&apos;*&apos;&quot;"
+				GenerateDebugInformation="false"
+				IgnoreImportLibrary="true"
+				LinkIncremental="1"
+				LinkTimeCodeGeneration="0"
+				OutputFile="release\qshare.exe"
+				ProgramDatabaseFile=""
+				SubSystem="2"
+				SuppressStartupBanner="true" />
+			<Tool
+				Name="VCMIDLTool"
+				DefaultCharType="0"
+				EnableErrorChecks="1"
+				WarningLevel="0" />
+			<Tool
+				Name="VCPostBuildEventTool" />
+			<Tool
+				Name="VCPreBuildEventTool" />
+			<Tool
+				Name="VCPreLinkEventTool" />
+			<Tool
+				Name="VCResourceCompilerTool"
+				PreprocessorDefinitions="DXT_INTR,_CRT_SECURE_NO_WARNINGS,QT_NO_DEBUG,NDEBUG,_WINDOWS,UNICODE,WIN32,QT_LARGEFILE_SUPPORT,QT_DLL,QT_NO_DEBUG,QT_GUI_LIB,QT_CORE_LIB,QT_THREAD_SUPPORT" />
+		</Configuration>
+	</Configurations>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="capturewindow.cpp" />
+			<File
+				RelativePath="FastDXT\dxt.cpp" />
+			<File
+				RelativePath="FastDXT\intrinsic.cpp" />
+			<File
+				RelativePath="FastDXT\libdxt.cpp" />
+			<File
+				RelativePath="main.cpp" />
+			<File
+				RelativePath="FastDXT\util.cpp" />
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath="capturewindow.h">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+						Name="VCCustomBuildTool"
+						AdditionalDependencies="C:\Qt\4.7.0\bin\moc.exe;capturewindow.h"
+						CommandLine="C:\Qt\4.7.0\bin\moc.exe  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I&quot;c:\Qt\4.7.0\include\QtCore&quot; -I&quot;c:\Qt\4.7.0\include\QtGui&quot; -I&quot;c:\Qt\4.7.0\include&quot; -I&quot;FastDXT&quot; -I&quot;..\..\include&quot; -I&quot;..\..\win32\include&quot; -I&quot;c:\Qt\4.7.0\include\ActiveQt&quot; -I&quot;debug&quot; -I&quot;.&quot; -Ic:\Qt\4.7.0\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 capturewindow.h -o debug\moc_capturewindow.cpp"
+						Description="MOC capturewindow.h"
+						Outputs="debug\moc_capturewindow.cpp"
+						Path="c:\Qt\4.7.0\bin" />
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+						Name="VCCustomBuildTool"
+						AdditionalDependencies="C:\Qt\4.7.0\bin\moc.exe;capturewindow.h"
+						CommandLine="C:\Qt\4.7.0\bin\moc.exe  -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I&quot;c:\Qt\4.7.0\include\QtCore&quot; -I&quot;c:\Qt\4.7.0\include\QtGui&quot; -I&quot;c:\Qt\4.7.0\include&quot; -I&quot;FastDXT&quot; -I&quot;..\..\include&quot; -I&quot;..\..\win32\include&quot; -I&quot;c:\Qt\4.7.0\include\ActiveQt&quot; -I&quot;release&quot; -I&quot;.&quot; -Ic:\Qt\4.7.0\mkspecs\win32-msvc2008 -D_MSC_VER=1500 -DWIN32 capturewindow.h -o release\moc_capturewindow.cpp"
+						Description="MOC capturewindow.h"
+						Outputs="release\moc_capturewindow.cpp"
+						Path="c:\Qt\4.7.0\bin" />
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<Filter
+			Name="Generated Files"
+			Filter="cpp;c;cxx;moc;h;def;odl;idl;res;"
+			UniqueIdentifier="{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}">
+			<File
+				RelativePath="debug\moc_capturewindow.cpp">
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true" />
+			</File>
+			<File
+				RelativePath="release\moc_capturewindow.cpp">
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true" />
+			</File>
+			<File
+				RelativePath="debug\qsharerc.res">
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true" />
+			</File>
+			<File
+				RelativePath="release\qsharerc.res">
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true" />
+			</File>
+			<File
+				RelativePath="ui_capturewindow.h" />
+		</Filter>
+		<Filter
+			Name="Form Files"
+			Filter="ui"
+			UniqueIdentifier="{99349809-55BA-4b9d-BF79-8FDBB0286EB3}"
+			ParseFiles="false">
+			<File
+				RelativePath="capturewindow.ui">
+				<FileConfiguration
+					Name="Debug|Win32">
+					<Tool
+						Name="VCCustomBuildTool"
+						AdditionalDependencies="C:\Qt\4.7.0\bin\uic.exe;capturewindow.ui"
+						CommandLine="C:\Qt\4.7.0\bin\uic.exe capturewindow.ui -o ui_capturewindow.h"
+						Description="UIC capturewindow.ui"
+						Outputs="ui_capturewindow.h"
+						Path="c:\Qt\4.7.0\bin" />
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32">
+					<Tool
+						Name="VCCustomBuildTool"
+						AdditionalDependencies="C:\Qt\4.7.0\bin\uic.exe;capturewindow.ui"
+						CommandLine="C:\Qt\4.7.0\bin\uic.exe capturewindow.ui -o ui_capturewindow.h"
+						Description="UIC capturewindow.ui"
+						Outputs="ui_capturewindow.h"
+						Path="c:\Qt\4.7.0\bin" />
+				</FileConfiguration>
+			</File>
+		</Filter>
+		<File
+			RelativePath="qsharerc.rc" />
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: trunk/src/testing/app/qshare/qshare.rc
===================================================================
--- trunk/src/testing/app/qshare/qshare.rc	(revision 4)
+++ trunk/src/testing/app/qshare/qshare.rc	(revision 4)
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource2.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource2.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1               ICON                    "qshareico.ico"
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
Index: trunk/src/testing/app/atlantis-fbo/shark.c
===================================================================
--- trunk/src/testing/app/atlantis-fbo/shark.c	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/shark.c	(revision 4)
@@ -0,0 +1,1316 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N002[3] = {0.000077 ,-0.020611 ,0.999788};
+static float N003[3] = {0.961425 ,0.258729 ,-0.093390};
+static float N004[3] = {0.510811 ,-0.769633 ,-0.383063};
+static float N005[3] = {0.400123 ,0.855734 ,-0.328055};
+static float N006[3] = {-0.770715 ,0.610204 ,-0.183440};
+static float N007[3] = {-0.915597 ,-0.373345 ,-0.149316};
+static float N008[3] = {-0.972788 ,0.208921 ,-0.100179};
+static float N009[3] = {-0.939713 ,-0.312268 ,-0.139383};
+static float N010[3] = {-0.624138 ,-0.741047 ,-0.247589};
+static float N011[3] = {0.591434 ,-0.768401 ,-0.244471};
+static float N012[3] = {0.935152 ,-0.328495 ,-0.132598};
+static float N013[3] = {0.997102 ,0.074243 ,-0.016593};
+static float N014[3] = {0.969995 ,0.241712 ,-0.026186};
+static float N015[3] = {0.844539 ,0.502628 ,-0.184714};
+static float N016[3] = {-0.906608 ,0.386308 ,-0.169787};
+static float N017[3] = {-0.970016 ,0.241698 ,-0.025516};
+static float N018[3] = {-0.998652 ,0.050493 ,-0.012045};
+static float N019[3] = {-0.942685 ,-0.333051 ,-0.020556};
+static float N020[3] = {-0.660944 ,-0.750276 ,0.015480};
+static float N021[3] = {0.503549 ,-0.862908 ,-0.042749};
+static float N022[3] = {0.953202 ,-0.302092 ,-0.012089};
+static float N023[3] = {0.998738 ,0.023574 ,0.044344};
+static float N024[3] = {0.979297 ,0.193272 ,0.060202};
+static float N025[3] = {0.798300 ,0.464885 ,0.382883};
+static float N026[3] = {-0.756590 ,0.452403 ,0.472126};
+static float N027[3] = {-0.953855 ,0.293003 ,0.065651};
+static float N028[3] = {-0.998033 ,0.040292 ,0.048028};
+static float N029[3] = {-0.977079 ,-0.204288 ,0.059858};
+static float N030[3] = {-0.729117 ,-0.675304 ,0.111140};
+static float N031[3] = {0.598361 ,-0.792753 ,0.116221};
+static float N032[3] = {0.965192 ,-0.252991 ,0.066332};
+static float N033[3] = {0.998201 ,-0.002790 ,0.059892};
+static float N034[3] = {0.978657 ,0.193135 ,0.070207};
+static float N035[3] = {0.718815 ,0.680392 ,0.142733};
+static float N036[3] = {-0.383096 ,0.906212 ,0.178936};
+static float N037[3] = {-0.952831 ,0.292590 ,0.080647};
+static float N038[3] = {-0.997680 ,0.032417 ,0.059861};
+static float N039[3] = {-0.982629 ,-0.169881 ,0.074700};
+static float N040[3] = {-0.695424 ,-0.703466 ,0.146700};
+static float N041[3] = {0.359323 ,-0.915531 ,0.180805};
+static float N042[3] = {0.943356 ,-0.319387 ,0.089842};
+static float N043[3] = {0.998272 ,-0.032435 ,0.048993};
+static float N044[3] = {0.978997 ,0.193205 ,0.065084};
+static float N045[3] = {0.872144 ,0.470094 ,-0.135565};
+static float N046[3] = {-0.664282 ,0.737945 ,-0.119027};
+static float N047[3] = {-0.954508 ,0.288570 ,0.075107};
+static float N048[3] = {-0.998273 ,0.032406 ,0.048993};
+static float N049[3] = {-0.979908 ,-0.193579 ,0.048038};
+static float N050[3] = {-0.858736 ,-0.507202 ,-0.072938};
+static float N051[3] = {0.643545 ,-0.763887 ,-0.048237};
+static float N052[3] = {0.955580 ,-0.288954 ,0.058068};
+static float N058[3] = {0.000050 ,0.793007 ,-0.609213};
+static float N059[3] = {0.913510 ,0.235418 ,-0.331779};
+static float N060[3] = {-0.807970 ,0.495000 ,-0.319625};
+static float N061[3] = {0.000000 ,0.784687 ,-0.619892};
+static float N062[3] = {0.000000 ,-1.000000 ,0.000000};
+static float N063[3] = {0.000000 ,1.000000 ,0.000000};
+static float N064[3] = {0.000000 ,1.000000 ,0.000000};
+static float N065[3] = {0.000000 ,1.000000 ,0.000000};
+static float N066[3] = {-0.055784 ,0.257059 ,0.964784};
+static float N069[3] = {-0.000505 ,-0.929775 ,-0.368127};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float P002[3] = {0.00, -36.59, 5687.72};
+static float P003[3] = {90.00, 114.73, 724.38};
+static float P004[3] = {58.24, -146.84, 262.35};
+static float P005[3] = {27.81, 231.52, 510.43};
+static float P006[3] = {-27.81, 230.43, 509.76};
+static float P007[3] = {-46.09, -146.83, 265.84};
+static float P008[3] = {-90.00, 103.84, 718.53};
+static float P009[3] = {-131.10, -165.92, 834.85};
+static float P010[3] = {-27.81, -285.31, 500.00};
+static float P011[3] = {27.81, -285.32, 500.00};
+static float P012[3] = {147.96, -170.89, 845.50};
+static float P013[3] = {180.00, 0.00, 2000.00};
+static float P014[3] = {145.62, 352.67, 2000.00};
+static float P015[3] = {55.62, 570.63, 2000.00};
+static float P016[3] = {-55.62, 570.64, 2000.00};
+static float P017[3] = {-145.62, 352.68, 2000.00};
+static float P018[3] = {-180.00, 0.01, 2000.00};
+static float P019[3] = {-178.20, -352.66, 2001.61};
+static float P020[3] = {-55.63, -570.63, 2000.00};
+static float P021[3] = {55.62, -570.64, 2000.00};
+static float P022[3] = {179.91, -352.69, 1998.39};
+static float P023[3] = {150.00, 0.00, 3000.00};
+static float P024[3] = {121.35, 293.89, 3000.00};
+static float P025[3] = {46.35, 502.93, 2883.09};
+static float P026[3] = {-46.35, 497.45, 2877.24};
+static float P027[3] = {-121.35, 293.90, 3000.00};
+static float P028[3] = {-150.00, 0.00, 3000.00};
+static float P029[3] = {-152.21, -304.84, 2858.68};
+static float P030[3] = {-46.36, -475.52, 3000.00};
+static float P031[3] = {46.35, -475.53, 3000.00};
+static float P032[3] = {155.64, -304.87, 2863.50};
+static float P033[3] = {90.00, 0.00, 4000.00};
+static float P034[3] = {72.81, 176.33, 4000.00};
+static float P035[3] = {27.81, 285.32, 4000.00};
+static float P036[3] = {-27.81, 285.32, 4000.00};
+static float P037[3] = {-72.81, 176.34, 4000.00};
+static float P038[3] = {-90.00, 0.00, 4000.00};
+static float P039[3] = {-72.81, -176.33, 4000.00};
+static float P040[3] = {-27.81, -285.31, 4000.00};
+static float P041[3] = {27.81, -285.32, 4000.00};
+static float P042[3] = {72.81, -176.34, 4000.00};
+static float P043[3] = {30.00, 0.00, 5000.00};
+static float P044[3] = {24.27, 58.78, 5000.00};
+static float P045[3] = {9.27, 95.11, 5000.00};
+static float P046[3] = {-9.27, 95.11, 5000.00};
+static float P047[3] = {-24.27, 58.78, 5000.00};
+static float P048[3] = {-30.00, 0.00, 5000.00};
+static float P049[3] = {-24.27, -58.78, 5000.00};
+static float P050[3] = {-9.27, -95.10, 5000.00};
+static float P051[3] = {9.27, -95.11, 5000.00};
+static float P052[3] = {24.27, -58.78, 5000.00};
+static float P058[3] = {0.00, 1212.72, 2703.08};
+static float P059[3] = {50.36, 0.00, 108.14};
+static float P060[3] = {-22.18, 0.00, 108.14};
+static float P061[3] = {0.00, 1181.61, 6344.65};
+static float P062[3] = {516.45, -887.08, 2535.45};
+static float P063[3] = {-545.69, -879.31, 2555.63};
+static float P064[3] = {618.89, -1005.64, 2988.32};
+static float P065[3] = {-635.37, -1014.79, 2938.68};
+static float P066[3] = {0.00, 1374.43, 3064.18};
+static float P069[3] = {0.00, -418.25, 5765.04};
+static float P070[3] = {0.00, 1266.91, 6629.60};
+static float P071[3] = {-139.12, -124.96, 997.98};
+static float P072[3] = {-139.24, -110.18, 1020.68};
+static float P073[3] = {-137.33, -94.52, 1022.63};
+static float P074[3] = {-137.03, -79.91, 996.89};
+static float P075[3] = {-135.21, -91.48, 969.14};
+static float P076[3] = {-135.39, -110.87, 968.76};
+static float P077[3] = {150.23, -78.44, 995.53};
+static float P078[3] = {152.79, -92.76, 1018.46};
+static float P079[3] = {154.19, -110.20, 1020.55};
+static float P080[3] = {151.33, -124.15, 993.77};
+static float P081[3] = {150.49, -111.19, 969.86};
+static float P082[3] = {150.79, -92.41, 969.70};
+static float iP002[3] = {0.00, -36.59, 5687.72};
+static float iP004[3] = {58.24, -146.84, 262.35};
+static float iP007[3] = {-46.09, -146.83, 265.84};
+static float iP010[3] = {-27.81, -285.31, 500.00};
+static float iP011[3] = {27.81, -285.32, 500.00};
+static float iP023[3] = {150.00, 0.00, 3000.00};
+static float iP024[3] = {121.35, 293.89, 3000.00};
+static float iP025[3] = {46.35, 502.93, 2883.09};
+static float iP026[3] = {-46.35, 497.45, 2877.24};
+static float iP027[3] = {-121.35, 293.90, 3000.00};
+static float iP028[3] = {-150.00, 0.00, 3000.00};
+static float iP029[3] = {-121.35, -304.84, 2853.86};
+static float iP030[3] = {-46.36, -475.52, 3000.00};
+static float iP031[3] = {46.35, -475.53, 3000.00};
+static float iP032[3] = {121.35, -304.87, 2853.86};
+static float iP033[3] = {90.00, 0.00, 4000.00};
+static float iP034[3] = {72.81, 176.33, 4000.00};
+static float iP035[3] = {27.81, 285.32, 4000.00};
+static float iP036[3] = {-27.81, 285.32, 4000.00};
+static float iP037[3] = {-72.81, 176.34, 4000.00};
+static float iP038[3] = {-90.00, 0.00, 4000.00};
+static float iP039[3] = {-72.81, -176.33, 4000.00};
+static float iP040[3] = {-27.81, -285.31, 4000.00};
+static float iP041[3] = {27.81, -285.32, 4000.00};
+static float iP042[3] = {72.81, -176.34, 4000.00};
+static float iP043[3] = {30.00, 0.00, 5000.00};
+static float iP044[3] = {24.27, 58.78, 5000.00};
+static float iP045[3] = {9.27, 95.11, 5000.00};
+static float iP046[3] = {-9.27, 95.11, 5000.00};
+static float iP047[3] = {-24.27, 58.78, 5000.00};
+static float iP048[3] = {-30.00, 0.00, 5000.00};
+static float iP049[3] = {-24.27, -58.78, 5000.00};
+static float iP050[3] = {-9.27, -95.10, 5000.00};
+static float iP051[3] = {9.27, -95.11, 5000.00};
+static float iP052[3] = {24.27, -58.78, 5000.00};
+static float iP061[3] = {0.00, 1181.61, 6344.65};
+static float iP069[3] = {0.00, -418.25, 5765.04};
+static float iP070[3] = {0.00, 1266.91, 6629.60};
+/* *INDENT-ON* */
+
+void
+Fish001(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P072);
+    glVertex3fv(P073);
+    glVertex3fv(P074);
+    glVertex3fv(P075);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P077);
+    glVertex3fv(P078);
+    glVertex3fv(P079);
+    glVertex3fv(P080);
+    glVertex3fv(P081);
+    glVertex3fv(P082);
+    glEnd();
+}
+
+void
+Fish002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+}
+
+void
+Fish004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+}
+
+void
+Fish005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Fish006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+}
+
+void
+Fish007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+}
+
+void
+Fish008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish009(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P059);
+    glVertex3fv(P012);
+    glVertex3fv(P009);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P012);
+    glVertex3fv(P004);
+    glVertex3fv(P007);
+    glVertex3fv(P009);
+    glEnd();
+}
+
+void
+Fish_1(void)
+{
+    Fish004();
+    Fish005();
+    Fish003();
+    Fish007();
+    Fish006();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_2(void)
+{
+    Fish005();
+    Fish004();
+    Fish003();
+    Fish008();
+    Fish006();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_3(void)
+{
+    Fish005();
+    Fish004();
+    Fish007();
+    Fish003();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_4(void)
+{
+    Fish005();
+    Fish004();
+    Fish008();
+    Fish003();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_5(void)
+{
+    Fish009();
+    Fish006();
+    Fish007();
+    Fish001();
+    Fish002();
+    Fish003();
+    Fish008();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_6(void)
+{
+    Fish009();
+    Fish006();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_7(void)
+{
+    Fish009();
+    Fish001();
+    Fish007();
+    Fish005();
+    Fish002();
+    Fish008();
+    Fish003();
+    Fish004();
+    Fish006();
+}
+
+void
+Fish_8(void)
+{
+    Fish009();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish005();
+    Fish004();
+    Fish006();
+}
+
+void
+DrawShark(fishRec * fish)
+{
+    int n;
+    float seg1, seg2, seg3, seg4, segup;
+    float thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 50.0 * fish->v;
+
+    seg1 = 0.6 * thrash * sin(fish->htail * RRAD);
+    seg2 = 1.8 * thrash * sin((fish->htail + 45.0) * RRAD);
+    seg3 = 3.0 * thrash * sin((fish->htail + 90.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 110.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P004[1] = iP004[1] + chomp;
+    P007[1] = iP007[1] + chomp;
+    P010[1] = iP010[1] + chomp;
+    P011[1] = iP011[1] + chomp;
+
+    P023[0] = iP023[0] + seg1;
+    P024[0] = iP024[0] + seg1;
+    P025[0] = iP025[0] + seg1;
+    P026[0] = iP026[0] + seg1;
+    P027[0] = iP027[0] + seg1;
+    P028[0] = iP028[0] + seg1;
+    P029[0] = iP029[0] + seg1;
+    P030[0] = iP030[0] + seg1;
+    P031[0] = iP031[0] + seg1;
+    P032[0] = iP032[0] + seg1;
+    P033[0] = iP033[0] + seg2;
+    P034[0] = iP034[0] + seg2;
+    P035[0] = iP035[0] + seg2;
+    P036[0] = iP036[0] + seg2;
+    P037[0] = iP037[0] + seg2;
+    P038[0] = iP038[0] + seg2;
+    P039[0] = iP039[0] + seg2;
+    P040[0] = iP040[0] + seg2;
+    P041[0] = iP041[0] + seg2;
+    P042[0] = iP042[0] + seg2;
+    P043[0] = iP043[0] + seg3;
+    P044[0] = iP044[0] + seg3;
+    P045[0] = iP045[0] + seg3;
+    P046[0] = iP046[0] + seg3;
+    P047[0] = iP047[0] + seg3;
+    P048[0] = iP048[0] + seg3;
+    P049[0] = iP049[0] + seg3;
+    P050[0] = iP050[0] + seg3;
+    P051[0] = iP051[0] + seg3;
+    P052[0] = iP052[0] + seg3;
+    P002[0] = iP002[0] + seg4;
+    P061[0] = iP061[0] + seg4;
+    P069[0] = iP069[0] + seg4;
+    P070[0] = iP070[0] + seg4;
+
+    fish->vtail += ((fish->dtheta - fish->vtail) * 0.1);
+
+    if (fish->vtail > 0.5) {
+        fish->vtail = 0.5;
+    } else if (fish->vtail < -0.5) {
+        fish->vtail = -0.5;
+    }
+    segup = thrash * fish->vtail;
+
+    P023[1] = iP023[1] + segup;
+    P024[1] = iP024[1] + segup;
+    P025[1] = iP025[1] + segup;
+    P026[1] = iP026[1] + segup;
+    P027[1] = iP027[1] + segup;
+    P028[1] = iP028[1] + segup;
+    P029[1] = iP029[1] + segup;
+    P030[1] = iP030[1] + segup;
+    P031[1] = iP031[1] + segup;
+    P032[1] = iP032[1] + segup;
+    P033[1] = iP033[1] + segup * 5.0;
+    P034[1] = iP034[1] + segup * 5.0;
+    P035[1] = iP035[1] + segup * 5.0;
+    P036[1] = iP036[1] + segup * 5.0;
+    P037[1] = iP037[1] + segup * 5.0;
+    P038[1] = iP038[1] + segup * 5.0;
+    P039[1] = iP039[1] + segup * 5.0;
+    P040[1] = iP040[1] + segup * 5.0;
+    P041[1] = iP041[1] + segup * 5.0;
+    P042[1] = iP042[1] + segup * 5.0;
+    P043[1] = iP043[1] + segup * 12.0;
+    P044[1] = iP044[1] + segup * 12.0;
+    P045[1] = iP045[1] + segup * 12.0;
+    P046[1] = iP046[1] + segup * 12.0;
+    P047[1] = iP047[1] + segup * 12.0;
+    P048[1] = iP048[1] + segup * 12.0;
+    P049[1] = iP049[1] + segup * 12.0;
+    P050[1] = iP050[1] + segup * 12.0;
+    P051[1] = iP051[1] + segup * 12.0;
+    P052[1] = iP052[1] + segup * 12.0;
+    P002[1] = iP002[1] + segup * 17.0;
+    P061[1] = iP061[1] + segup * 17.0;
+    P069[1] = iP069[1] + segup * 17.0;
+    P070[1] = iP070[1] + segup * 17.0;
+
+    glPushMatrix();
+
+    glTranslatef(0.0, 0.0, -3000.0);
+
+//    glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0][0]);
+    n = 0;
+/*
+    if (mat[0][2] >= 0.0) {
+        n += 1;
+    }
+    if (mat[1][2] >= 0.0) {
+        n += 2;
+    }
+    if (mat[2][2] >= 0.0) {
+        n += 4;
+    }
+*/
+    glScalef(2.0, 1.0, 1.0);
+
+    glEnable(GL_CULL_FACE);
+    switch (n) {
+    case 0:
+        Fish_1();
+        break;
+    case 1:
+        Fish_2();
+        break;
+    case 2:
+        Fish_3();
+        break;
+    case 3:
+        Fish_4();
+        break;
+    case 4:
+        Fish_5();
+        break;
+    case 5:
+        Fish_6();
+        break;
+    case 6:
+        Fish_7();
+        break;
+    case 7:
+        Fish_8();
+        break;
+    }
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-fbo/Makefile.mac
===================================================================
--- trunk/src/testing/app/atlantis-fbo/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/Makefile.mac	(revision 4)
@@ -0,0 +1,20 @@
+PROGRAM = atlantis
+
+CFLAGS		= 
+LDFLAGS		= 
+LDFLAGS		+= -lm  -framework GLUT -framework OpenGL -lobjc -lz
+CFLAGS  	+= -O3 -FGLUT -FOpenGL
+CC	        = g++
+
+FILES = atlantis.o dolphin.o shark.o swim.o whale.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(CC) -o $(PROGRAM) $(FILES) $(LDFLAGS)
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/atlantis-fbo/Makefile
===================================================================
--- trunk/src/testing/app/atlantis-fbo/Makefile	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/Makefile	(revision 4)
@@ -0,0 +1,62 @@
+# QUANTA settings
+QUANTA_DIR=/usr/local
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include -DQUANTA_USE_PTHREADS -DQUANTA_THREAD_SAFE
+QUANTA_LIB=-L${QUANTA_DIR}/lib
+
+INCLUDE_DIR 	= -I/usr/local/include -I/usr/X11R6/include -I../../include
+LIBRARY_DIR 	= -L/usr/X11R6/lib -L../../lib
+LIBRARIES	= -lglut -lGLU -lGL -lXmu -lXext -lX11 -lm -lpthread -lsail
+COMPILER_FLAGS 	= -O3 -Wno-deprecated -fomit-frame-pointer -ffast-math
+COMPILER 	= g++
+
+CC=$(COMPILER)
+
+# Machine specific settings
+MACHINE=$(shell uname -p)
+   #powerpc  MacOSX
+   #x86_64   Opteron Linux
+   #ia64     Itanium Linux (SGI)
+   #else     32bit Linux
+
+ifeq ($(MACHINE), powerpc)
+
+   LIBRARIES       = -framework GLUT -framework OpenGL -lobjc -lm -lpthread -lsail
+   COMPILER_FLAGS  += -FGLUT -FOpenGL
+
+else
+
+ifeq ($(MACHINE), x86_64)
+   LIBRARY_DIR = -L/usr/X11R6/lib64 -L../../lib
+else
+
+ifeq ($(MACHINE), ia64)
+   LIBRARY_DIR = -L/usr/X11R6/lib64 -L../../lib
+else
+
+   # anything else is 32bit 
+
+   LIBRARIES       += $(QUANTA_LIB) -lquanta_32
+
+
+endif
+endif
+endif
+
+CFLAGS=$(COMPILER_FLAGS) $(INCLUDE_DIR)
+LDFLAGS=$(LIBRARY_DIR) $(LIBRARIES)
+
+PROGRAM = atlantis
+
+FILES = atlantis.o dolphin.o shark.o swim.o whale.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(CC) -o $(PROGRAM) $(FILES) $(LDFLAGS)
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
+
Index: trunk/src/testing/app/atlantis-fbo/dolphin.c
===================================================================
--- trunk/src/testing/app/atlantis-fbo/dolphin.c	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/dolphin.c	(revision 4)
@@ -0,0 +1,1949 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {-0.005937 ,-0.101998 ,-0.994767};
+static float N002[3] = {0.936780 ,-0.200803 ,0.286569};
+static float N003[3] = {-0.233062 ,0.972058 ,0.028007};
+static float N005[3] = {0.898117 ,0.360171 ,0.252315};
+static float N006[3] = {-0.915437 ,0.348456 ,0.201378};
+static float N007[3] = {0.602263 ,-0.777527 ,0.180920};
+static float N008[3] = {-0.906912 ,-0.412015 ,0.088061};
+static float N012[3] = {0.884408 ,-0.429417 ,-0.182821};
+static float N013[3] = {0.921121 ,0.311084 ,-0.234016};
+static float N014[3] = {0.382635 ,0.877882 ,-0.287948};
+static float N015[3] = {-0.380046 ,0.888166 ,-0.258316};
+static float N016[3] = {-0.891515 ,0.392238 ,-0.226607};
+static float N017[3] = {-0.901419 ,-0.382002 ,-0.203763};
+static float N018[3] = {-0.367225 ,-0.911091 ,-0.187243};
+static float N019[3] = {0.339539 ,-0.924846 ,-0.171388};
+static float N020[3] = {0.914706 ,-0.378617 ,-0.141290};
+static float N021[3] = {0.950662 ,0.262713 ,-0.164994};
+static float N022[3] = {0.546359 ,0.801460 ,-0.243218};
+static float N023[3] = {-0.315796 ,0.917068 ,-0.243431};
+static float N024[3] = {-0.825687 ,0.532277 ,-0.186875};
+static float N025[3] = {-0.974763 ,-0.155232 ,-0.160435};
+static float N026[3] = {-0.560596 ,-0.816658 ,-0.137119};
+static float N027[3] = {0.380210 ,-0.910817 ,-0.160786};
+static float N028[3] = {0.923772 ,-0.358322 ,-0.135093};
+static float N029[3] = {0.951202 ,0.275053 ,-0.139859};
+static float N030[3] = {0.686099 ,0.702548 ,-0.188932};
+static float N031[3] = {-0.521865 ,0.826719 ,-0.210220};
+static float N032[3] = {-0.923820 ,0.346739 ,-0.162258};
+static float N033[3] = {-0.902095 ,-0.409995 ,-0.134646};
+static float N034[3] = {-0.509115 ,-0.848498 ,-0.144404};
+static float N035[3] = {0.456469 ,-0.880293 ,-0.129305};
+static float N036[3] = {0.873401 ,-0.475489 ,-0.105266};
+static float N037[3] = {0.970825 ,0.179861 ,-0.158584};
+static float N038[3] = {0.675609 ,0.714187 ,-0.183004};
+static float N039[3] = {-0.523574 ,0.830212 ,-0.191360};
+static float N040[3] = {-0.958895 ,0.230808 ,-0.165071};
+static float N041[3] = {-0.918285 ,-0.376803 ,-0.121542};
+static float N042[3] = {-0.622467 ,-0.774167 ,-0.114888};
+static float N043[3] = {0.404497 ,-0.908807 ,-0.102231};
+static float N044[3] = {0.930538 ,-0.365155 ,-0.027588};
+static float N045[3] = {0.921920 ,0.374157 ,-0.100345};
+static float N046[3] = {0.507346 ,0.860739 ,0.041562};
+static float N047[3] = {-0.394646 ,0.918815 ,-0.005730};
+static float N048[3] = {-0.925411 ,0.373024 ,-0.066837};
+static float N049[3] = {-0.945337 ,-0.322309 ,-0.049551};
+static float N050[3] = {-0.660437 ,-0.750557 ,-0.022072};
+static float N051[3] = {0.488835 ,-0.871950 ,-0.027261};
+static float N052[3] = {0.902599 ,-0.421397 ,0.087969};
+static float N053[3] = {0.938636 ,0.322606 ,0.122020};
+static float N054[3] = {0.484605 ,0.871078 ,0.079878};
+static float N055[3] = {-0.353607 ,0.931559 ,0.084619};
+static float N056[3] = {-0.867759 ,0.478564 ,0.134054};
+static float N057[3] = {-0.951583 ,-0.296030 ,0.082794};
+static float N058[3] = {-0.672355 ,-0.730209 ,0.121384};
+static float N059[3] = {0.528336 ,-0.842452 ,0.105525};
+static float N060[3] = {0.786913 ,-0.564760 ,0.248627};
+static float N062[3] = {0.622098 ,0.765230 ,0.165584};
+static float N063[3] = {-0.631711 ,0.767816 ,0.106773};
+static float N064[3] = {-0.687886 ,0.606351 ,0.398938};
+static float N065[3] = {-0.946327 ,-0.281623 ,0.158598};
+static float N066[3] = {-0.509549 ,-0.860437 ,0.002776};
+static float N067[3] = {0.462594 ,-0.876692 ,0.131977};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N078[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N079[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N080[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N081[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N082[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N083[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N084[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N085[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N086[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N087[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N088[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N089[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N090[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N097[3] = {-0.697296 ,0.702881 ,0.140491};
+static float N098[3] = {0.918864 ,0.340821 ,0.198819};
+static float N099[3] = {-0.932737 ,0.201195 ,0.299202};
+static float N100[3] = {0.029517 ,0.981679 ,0.188244};
+static float N102[3] = {0.813521 ,-0.204936 ,0.544229};
+static float N110[3] = {-0.781480 ,-0.384779 ,0.491155};
+static float N111[3] = {-0.722243 ,0.384927 ,0.574627};
+static float N112[3] = {-0.752278 ,0.502679 ,0.425901};
+static float N113[3] = {0.547257 ,0.367910 ,0.751766};
+static float N114[3] = {0.725949 ,-0.232568 ,0.647233};
+static float N115[3] = {-0.747182 ,-0.660786 ,0.071280};
+static float N116[3] = {0.931519 ,0.200748 ,0.303270};
+static float N117[3] = {-0.828928 ,0.313757 ,0.463071};
+static float N118[3] = {0.902554 ,-0.370967 ,0.218587};
+static float N119[3] = {-0.879257 ,-0.441851 ,0.177973};
+static float N120[3] = {0.642327 ,0.611901 ,0.461512};
+static float N121[3] = {0.964817 ,-0.202322 ,0.167910};
+static float N122[3] = {0.000000 ,1.000000 ,0.000000};
+static float P001[3] = {5.68, -300.95, 1324.70};
+static float P002[3] = {338.69, -219.63, 9677.03};
+static float P003[3] = {12.18, 474.59, 9138.14};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 68.74, 9427.85};
+static float P007[3] = {156.52, -266.72, 10311.68};
+static float P008[3] = {-185.56, -266.51, 10310.47};
+static float P009[3] = {124.39, -261.46, 1942.34};
+static float P010[3] = {-130.05, -261.46, 1946.03};
+static float P011[3] = {141.07, -320.11, 1239.38};
+static float P012[3] = {156.48, -360.12, 2073.41};
+static float P013[3] = {162.00, -175.88, 2064.44};
+static float P014[3] = {88.16, -87.72, 2064.02};
+static float P015[3] = {-65.21, -96.13, 2064.02};
+static float P016[3] = {-156.48, -180.96, 2064.44};
+static float P017[3] = {-162.00, -368.93, 2082.39};
+static float P018[3] = {-88.16, -439.22, 2082.39};
+static float P019[3] = {65.21, -440.32, 2083.39};
+static float P020[3] = {246.87, -356.02, 2576.95};
+static float P021[3] = {253.17, -111.15, 2567.15};
+static float P022[3] = {132.34, 51.41, 2559.84};
+static float P023[3] = {-97.88, 40.44, 2567.15};
+static float P024[3] = {-222.97, -117.49, 2567.15};
+static float P025[3] = {-252.22, -371.53, 2569.92};
+static float P026[3] = {-108.44, -518.19, 2586.75};
+static float P027[3] = {97.88, -524.79, 2586.75};
+static float P028[3] = {370.03, -421.19, 3419.70};
+static float P029[3] = {351.15, -16.98, 3423.17};
+static float P030[3] = {200.66, 248.46, 3430.37};
+static float P031[3] = {-148.42, 235.02, 3417.91};
+static float P032[3] = {-360.21, -30.27, 3416.84};
+static float P033[3] = {-357.90, -414.89, 3407.04};
+static float P034[3] = {-148.88, -631.35, 3409.90};
+static float P035[3] = {156.38, -632.59, 3419.70};
+static float P036[3] = {462.61, -469.21, 4431.51};
+static float P037[3] = {466.60, 102.25, 4434.98};
+static float P038[3] = {243.05, 474.34, 4562.02};
+static float P039[3] = {-191.23, 474.40, 4554.42};
+static float P040[3] = {-476.12, 111.05, 4451.11};
+static float P041[3] = {-473.36, -470.74, 4444.78};
+static float P042[3] = {-266.95, -748.41, 4447.78};
+static float P043[3] = {211.14, -749.91, 4429.73};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 6360.63};
+static float P046[3] = {371.29, 804.51, 6486.26};
+static float P047[3] = {-291.43, 797.22, 6494.28};
+static float P048[3] = {-784.13, 370.75, 6378.01};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float iP001[3] = {5.68, -300.95, 1324.70};
+static float iP009[3] = {124.39, -261.46, 1942.34};
+static float iP010[3] = {-130.05, -261.46, 1946.03};
+static float iP011[3] = {141.07, -320.11, 1239.38};
+static float iP012[3] = {156.48, -360.12, 2073.41};
+static float iP013[3] = {162.00, -175.88, 2064.44};
+static float iP014[3] = {88.16, -87.72, 2064.02};
+static float iP015[3] = {-65.21, -96.13, 2064.02};
+static float iP016[3] = {-156.48, -180.96, 2064.44};
+static float iP017[3] = {-162.00, -368.93, 2082.39};
+static float iP018[3] = {-88.16, -439.22, 2082.39};
+static float iP019[3] = {65.21, -440.32, 2083.39};
+static float iP020[3] = {246.87, -356.02, 2576.95};
+static float iP021[3] = {253.17, -111.15, 2567.15};
+static float iP022[3] = {132.34, 51.41, 2559.84};
+static float iP023[3] = {-97.88, 40.44, 2567.15};
+static float iP024[3] = {-222.97, -117.49, 2567.15};
+static float iP025[3] = {-252.22, -371.53, 2569.92};
+static float iP026[3] = {-108.44, -518.19, 2586.75};
+static float iP027[3] = {97.88, -524.79, 2586.75};
+static float iP028[3] = {370.03, -421.19, 3419.70};
+static float iP029[3] = {351.15, -16.98, 3423.17};
+static float iP030[3] = {200.66, 248.46, 3430.37};
+static float iP031[3] = {-148.42, 235.02, 3417.91};
+static float iP032[3] = {-360.21, -30.27, 3416.84};
+static float iP033[3] = {-357.90, -414.89, 3407.04};
+static float iP034[3] = {-148.88, -631.35, 3409.90};
+static float iP035[3] = {156.38, -632.59, 3419.70};
+static float iP036[3] = {462.61, -469.21, 4431.51};
+static float iP037[3] = {466.60, 102.25, 4434.98};
+static float iP038[3] = {243.05, 474.34, 4562.02};
+static float iP039[3] = {-191.23, 474.40, 4554.42};
+static float iP040[3] = {-476.12, 111.05, 4451.11};
+static float iP041[3] = {-473.36, -470.74, 4444.78};
+static float iP042[3] = {-266.95, -748.41, 4447.78};
+static float iP043[3] = {211.14, -749.91, 4429.73};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 6360.63};
+static float iP046[3] = {371.29, 804.51, 6486.26};
+static float iP047[3] = {-291.43, 797.22, 6494.28};
+static float iP048[3] = {-784.13, 370.75, 6378.01};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -300.15, 7894.03};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {246.22, 558.53, 8460.50};
+static float P055[3] = {-230.41, 559.84, 8473.23};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 338.75, 9450.30};
+static float P063[3] = {-165.71, 341.04, 9462.35};
+static float P064[3] = {-298.11, 110.13, 10180.37};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -491.45, 9348.73};
+static float P068[3] = {-136.29, -319.84, 1228.73};
+static float P069[3] = {1111.17, -314.14, 1314.19};
+static float P070[3] = {-1167.34, -321.61, 1319.45};
+static float P071[3] = {1404.86, -306.66, 1235.45};
+static float P072[3] = {-1409.73, -314.14, 1247.66};
+static float P073[3] = {1254.01, -296.87, 1544.58};
+static float P074[3] = {-1262.09, -291.70, 1504.26};
+static float P075[3] = {965.71, -269.26, 1742.65};
+static float P076[3] = {-900.97, -276.74, 1726.07};
+static float iP068[3] = {-136.29, -319.84, 1228.73};
+static float iP069[3] = {1111.17, -314.14, 1314.19};
+static float iP070[3] = {-1167.34, -321.61, 1319.45};
+static float iP071[3] = {1404.86, -306.66, 1235.45};
+static float iP072[3] = {-1409.73, -314.14, 1247.66};
+static float iP073[3] = {1254.01, -296.87, 1544.58};
+static float iP074[3] = {-1262.09, -291.70, 1504.26};
+static float iP075[3] = {965.71, -269.26, 1742.65};
+static float iP076[3] = {-900.97, -276.74, 1726.07};
+static float P077[3] = {1058.00, -448.81, 8194.66};
+static float P078[3] = {-1016.51, -456.43, 8190.62};
+static float P079[3] = {-1515.96, -676.45, 7754.93};
+static float P080[3] = {1856.75, -830.34, 7296.56};
+static float P081[3] = {1472.16, -497.38, 7399.68};
+static float P082[3] = {-1775.26, -829.51, 7298.46};
+static float P083[3] = {911.09, -252.51, 7510.99};
+static float P084[3] = {-1451.94, -495.62, 7384.30};
+static float P085[3] = {1598.75, -669.26, 7769.90};
+static float P086[3] = {-836.53, -250.08, 7463.25};
+static float P087[3] = {722.87, -158.18, 8006.41};
+static float P088[3] = {-688.86, -162.28, 7993.89};
+static float P089[3] = {-626.92, -185.30, 8364.98};
+static float P090[3] = {647.72, -189.46, 8354.99};
+static float P091[3] = {0.00, 835.01, 5555.62};
+static float P092[3] = {0.00, 1350.18, 5220.86};
+static float P093[3] = {0.00, 1422.94, 5285.27};
+static float P094[3] = {0.00, 1296.75, 5650.19};
+static float P095[3] = {0.00, 795.63, 6493.88};
+static float iP091[3] = {0.00, 835.01, 5555.62};
+static float iP092[3] = {0.00, 1350.18, 5220.86};
+static float iP093[3] = {0.00, 1422.94, 5285.27};
+static float iP094[3] = {0.00, 1296.75, 5650.19};
+static float iP095[3] = {0.00, 795.63, 6493.88};
+static float P097[3] = {-194.91, -357.14, 10313.32};
+static float P098[3] = {135.35, -357.66, 10307.94};
+static float iP097[3] = {-194.91, -357.14, 10313.32};
+static float iP098[3] = {135.35, -357.66, 10307.94};
+static float P099[3] = {-380.53, -221.14, 9677.98};
+static float P100[3] = {0.00, 412.99, 9629.33};
+static float P102[3] = {59.51, -412.55, 10677.58};
+static float iP102[3] = {59.51, -412.55, 10677.58};
+static float P103[3] = {6.50, 484.74, 9009.94};
+static float P105[3] = {-41.86, 476.51, 9078.17};
+static float P108[3] = {49.20, 476.83, 9078.24};
+static float P110[3] = {-187.62, -410.04, 10674.12};
+static float iP110[3] = {-187.62, -410.04, 10674.12};
+static float P111[3] = {-184.25, -318.70, 10723.88};
+static float iP111[3] = {-184.25, -318.70, 10723.88};
+static float P112[3] = {-179.61, -142.81, 10670.26};
+static float P113[3] = {57.43, -147.94, 10675.26};
+static float P114[3] = {54.06, -218.90, 10712.44};
+static float P115[3] = {-186.35, -212.09, 10713.76};
+static float P116[3] = {205.90, -84.61, 10275.97};
+static float P117[3] = {-230.96, -83.26, 10280.09};
+static float iP118[3] = {216.78, -509.17, 10098.94};
+static float iP119[3] = {-313.21, -510.79, 10102.62};
+static float P118[3] = {216.78, -509.17, 10098.94};
+static float P119[3] = {-313.21, -510.79, 10102.62};
+static float P120[3] = {217.95, 96.34, 10161.62};
+static float P121[3] = {71.99, -319.74, 10717.70};
+static float iP121[3] = {71.99, -319.74, 10717.70};
+static float P122[3] = {0.00, 602.74, 5375.84};
+static float iP122[3] = {0.00, 602.74, 5375.84};
+static float P123[3] = {-448.94, -203.14, 9499.60};
+static float P124[3] = {-442.64, -185.20, 9528.07};
+static float P125[3] = {-441.07, -148.05, 9528.07};
+static float P126[3] = {-443.43, -128.84, 9499.60};
+static float P127[3] = {-456.87, -146.78, 9466.67};
+static float P128[3] = {-453.68, -183.93, 9466.67};
+static float P129[3] = {428.43, -124.08, 9503.03};
+static float P130[3] = {419.73, -142.14, 9534.56};
+static float P131[3] = {419.92, -179.96, 9534.56};
+static float P132[3] = {431.20, -199.73, 9505.26};
+static float P133[3] = {442.28, -181.67, 9475.96};
+static float P134[3] = {442.08, -143.84, 9475.96};
+/* *INDENT-ON* */
+
+void
+Dolphin001(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P072);
+    glVertex3fv(P074);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P072);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P074);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P001);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Dolphin002(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P001);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P075);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P009);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P071);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Dolphin003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Dolphin004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Dolphin005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Dolphin006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Dolphin007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Dolphin008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Dolphin009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Dolphin010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Dolphin011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Dolphin012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+}
+
+void
+Dolphin013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P007);
+    glVertex3fv(P008);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P007);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+}
+
+void
+Dolphin014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P098);
+    glVertex3fv(P097);
+    glVertex3fv(P111);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P099);
+    glVertex3fv(P097);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+Dolphin015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Dolphin016(void)
+{
+
+    glDisable(GL_DEPTH_TEST);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P123);
+    glVertex3fv(P124);
+    glVertex3fv(P125);
+    glVertex3fv(P126);
+    glVertex3fv(P127);
+    glVertex3fv(P128);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P129);
+    glVertex3fv(P130);
+    glVertex3fv(P131);
+    glVertex3fv(P132);
+    glVertex3fv(P133);
+    glVertex3fv(P134);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P103);
+    glVertex3fv(P105);
+    glVertex3fv(P108);
+    glEnd();
+    glEnable(GL_DEPTH_TEST);
+}
+
+void
+DrawDolphin(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch, thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (10.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg3 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.0 * thrash * sin((fish->htail + 4.0) * RRAD);
+    seg2 = 3.0 * thrash * sin((fish->htail + 6.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg5 = 4.5 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg6 = 5.0 * thrash * sin((fish->htail + 20.0) * RRAD);
+    seg7 = 6.0 * thrash * sin((fish->htail + 30.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail + 180.0) * RRAD);
+
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    chomp = 100.0;
+
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3;
+    P122[1] = iP122[1] + seg3 * 1.5;
+
+    P097[1] = iP097[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P102[1] = iP102[1] + chomp;
+    P110[1] = iP110[1] + chomp;
+    P111[1] = iP111[1] + chomp;
+    P121[1] = iP121[1] + chomp;
+    P118[1] = iP118[1] + chomp;
+    P119[1] = iP119[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 7000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+/*	glGetFloatv(GL_MODELVIEW_MATRIX, f);
+	printf("Modelview:\n");
+	printf("%f %f %f %f ", f[0], f[1], f[2], f[3]);
+	printf("%f %f %f %f ", f[4], f[5], f[6], f[7]);
+	printf("%f %f %f %f ", f[8], f[9], f[10], f[11]);
+	printf("%f %f %f %f\n", f[12], f[13], f[14], f[15]);
+*/
+    //glEnable(GL_CULL_FACE);
+    Dolphin014();
+    Dolphin010();
+    Dolphin009();
+    Dolphin012();
+    Dolphin013();
+    Dolphin006();
+    Dolphin002();
+    Dolphin001();
+    Dolphin003();
+    Dolphin015();
+    Dolphin004();
+    Dolphin005();
+    Dolphin007();
+    Dolphin008();
+    Dolphin011();
+    Dolphin016();
+    //glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-fbo/atlantis.c
===================================================================
--- trunk/src/testing/app/atlantis-fbo/atlantis.c	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/atlantis.c	(revision 4)
@@ -0,0 +1,630 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#include <sys\timeb.h>
+int gettimeofday(struct timeval *tp, void *tzp);
+#else
+#include <sys/time.h>
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+
+#include "atlantis.h"
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+
+
+GLuint tname;
+void *pixels;
+GLint viewport[4];
+
+
+GLuint g_dynamicTextureID;
+GLuint g_frameBuffer;
+GLuint g_depthRenderBuffer;
+int xwin, ywin;
+
+
+
+#if defined(WIN32)
+int
+gettimeofday(struct timeval *tp, void *tzp)
+{
+	struct _timeb t;
+
+    _ftime(&t);
+    tp->tv_sec = t.time;
+    tp->tv_usec = t.millitm * 1000;
+    return 0;
+}
+#endif
+
+fishRec sharks[NUM_SHARKS];
+fishRec momWhale;
+fishRec babyWhale;
+fishRec dolph;
+
+GLboolean moving;
+int screenshot = 0;
+int fr = 0;
+float t1,t2;
+struct timeval tv_start;
+
+double getTime()
+{
+    struct timeval tv;
+		        
+    gettimeofday(&tv,0);
+    return (double)(tv.tv_sec - tv_start.tv_sec) +
+        (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+}
+
+void
+InitFishs(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        sharks[i].x = 15000.0 + rand() % 6000;
+        sharks[i].y = (rand() % 20000) - 10000;
+        sharks[i].z = (rand() % 6000) - 5000;
+        sharks[i].psi = rand() % 360 - 180.0;
+        sharks[i].v = 1.0;
+    }
+
+    dolph.x = 30000.0;
+    dolph.y = 0.0;
+    dolph.z = 6000.0;
+    dolph.psi = 90.0;
+    dolph.theta = 0.0;
+    dolph.v = 3.0;
+
+    momWhale.x = 70000.0;
+    momWhale.y = 0.0;
+    momWhale.z = 0.0;
+    momWhale.psi = 90.0;
+    momWhale.theta = 0.0;
+    momWhale.v = 3.0;
+
+    babyWhale.x = 60000.0;
+    babyWhale.y = -2000.0;
+    babyWhale.z = -2000.0;
+    babyWhale.psi = 90.0;
+    babyWhale.theta = 0.0;
+    babyWhale.v = 3.0;
+}
+
+void
+Init(void)
+{
+    static float ambient[] =
+    {0.1, 0.1, 0.1, 1.0};
+    static float diffuse[] =
+    {1.0, 1.0, 1.0, 1.0};
+    static float position[] =
+    {0.0, 1.0, 0.0, 0.0};
+    static float mat_shininess[] =
+    {90.0};
+    static float mat_specular[] =
+    {0.8, 0.8, 0.8, 1.0};
+    static float mat_diffuse[] =
+    {0.46, 0.66, 0.795, 1.0};
+    static float mat_ambient[] =
+    {0.0, 0.1, 0.2, 1.0};
+    static float lmodel_ambient[] =
+    {0.4, 0.4, 0.4, 1.0};
+    static float lmodel_localviewer[] =
+    {1.0};
+
+    glFrontFace(GL_CW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    InitFishs();
+
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glGenTextures(1,&tname);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB,tname);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+    glDisable(GL_TEXTURE_2D);
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+
+    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    //    glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+
+    //
+    // Create a frame-buffer object and a render-buffer object...
+    //
+    
+    glGenFramebuffersEXT( 1, &g_frameBuffer );
+    glGenRenderbuffersEXT( 1, &g_depthRenderBuffer );
+
+    // Initialize the render-buffer for usage as a depth buffer.
+    // We don't really need this to render things into the frame-buffer object,
+    // but without it the geometry will not be sorted properly.
+
+    glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer );
+    glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, xwin, ywin);
+
+    //
+    // Check for errors...
+    //
+
+    GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
+
+    switch( status )
+      {
+      case GL_FRAMEBUFFER_COMPLETE_EXT:
+	fprintf(stderr, "GL_FRAMEBUFFER_COMPLETE_EXT!\n");
+	break;
+      
+      case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+	fprintf(stderr, "GL_FRAMEBUFFER_UNSUPPORTED_EXT!\n");
+	exit(0);
+	break;
+	
+      default:
+	exit(0);
+      }
+
+
+    glGenTextures(1, &g_dynamicTextureID );
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g_dynamicTextureID );
+
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, 
+		  xwin, ywin, 0, GL_RGB, GL_UNSIGNED_BYTE, 0 );
+
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+
+extern "C"
+{
+#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879
+void glPixelDataRangeNV(GLenum target, GLsizei length, GLvoid *pointer);
+}
+
+void
+Reshape(int width, int height)
+{
+    winWidth = width;
+    winHeight = height;	
+
+    glViewport(0, 0, width, height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(4.0, 2.0, 10000.0, 400000.0);
+    glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+    viewport[0] = 0;
+    viewport[1] = 0;
+    viewport[2] = width;
+    viewport[3] = height;
+    
+#if 0
+        // Video Memory : 0,0,1
+        // AGP memory   : 0,0,0.5
+	pixels = glXAllocateMemoryNV(width * height * 4, 1.0,0.0,1.0);
+	glEnable(GL_READ_PIXEL_DATA_RANGE_NV);
+	glEnableClientState(GL_READ_PIXEL_DATA_RANGE_NV);
+	glPixelDataRangeNV(GL_READ_PIXEL_DATA_RANGE_NV, width*height*3, pixels);
+	int rs = glIsEnabled(GL_READ_PIXEL_DATA_RANGE_NV);
+	fprintf(stderr, "Is Range enabled : %d\n", rs);
+	//void glFlushPixelDataRangeNV(enum target);
+#else
+	pixels = malloc( width * height * 3 );
+#endif
+
+	assert( pixels );
+	memset( pixels, 0, width * height * 3 );
+
+    fprintf(stderr, "buffer there (%p): %d %d \n\n", pixels,width, height);
+}
+
+void
+Animate(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        SharkPilot(&sharks[i]);
+        SharkMiss(i);
+    }
+    WhalePilot(&dolph);
+    dolph.phi++;
+    glutPostRedisplay();
+    WhalePilot(&momWhale);
+    momWhale.phi++;
+    WhalePilot(&babyWhale);
+    babyWhale.phi++;
+}
+
+void
+Key(unsigned char key, int x, int y)
+{
+	(void) x;
+	(void) y;
+    switch (key) 
+	{
+	  case 27:           /* Esc will quit */
+        exit(1);
+        break;
+	  case ' ':          /* space will advance frame */
+        if (!moving) {
+            Animate();
+        }
+    }
+}
+
+
+void
+save_frame( void )
+{
+  int x, y, width, height;
+  double t1, t2;
+  float p[4];
+  GLboolean valid;
+  int i, j, stepi, stepj, block;
+  static int first = 1;
+    
+  x = viewport[0];
+  y = viewport[1];
+  width = viewport[2];
+  height = viewport[3];
+
+  t1 = getTime();
+    glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+    //fprintf(stderr, "Return Read [%s]\n", gluErrorString(glGetError()));
+  t2 = getTime();
+  fprintf(stderr, "Read %12.4f -- %.2f Hz -- %.1f Mpixels/sec -- %.1f MB/sec\n",
+	  t2-t1, 1.0/(t2-t1), ((double)(width*height))/(1000000*(t2-t1)),
+	   ((double)(width*height*4))/(1000000*(t2-t1)));
+
+  
+  glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
+
+
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrtho(0, width, 0, height, -1.0, 1.0);
+  glDisable(GL_DEPTH_TEST);
+  glDepthMask(GL_FALSE);
+
+  t1 = getTime();
+
+
+#if 1
+  glDrawPixels( width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+  //fprintf(stderr, "Return Draw [%s]\n", gluErrorString(glGetError()));
+#else
+    glColor4f(0.5f,0.5f,0.5f,1.0f);
+    
+    glEnable(GL_TEXTURE_2D);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB,tname);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_BLEND);
+
+    if (first)
+      {
+	//glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_COMPRESSED_RGB_S3TC_DXT1_ARB,width,height,0,GL_RGB, GL_UNSIGNED_BYTE,pixels);
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,0,GL_RGB8,width,height,0,GL_RGB, GL_UNSIGNED_BYTE,pixels);
+	first = 0;
+	//fprintf(stderr, "Return glTexImage2D [%s]\n", gluErrorString(glGetError()));
+      }
+    else
+      {
+	glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,width,height,GL_RGB, GL_UNSIGNED_BYTE,pixels);
+	//fprintf(stderr, "Return glTexSubImage2D [%s]\n", gluErrorString(glGetError()));
+      }
+    
+    glBegin(GL_QUADS);
+
+        glTexCoord2f(0.0, 0.0);
+        glVertex3f(10, 10, 0.2);
+
+        glTexCoord2f(0.0, height);
+        glVertex3f(10, height-10, 0.2);
+  
+        glTexCoord2f(width, height);
+        glVertex3f( width-10,  height-10, 0.2);
+
+        glTexCoord2f(width, 0.0);
+        glVertex3f( width-10, 10, 0.2);
+
+    glEnd();
+
+    glDisable(GL_TEXTURE_RECTANGLE_ARB);
+    glDisable(GL_TEXTURE_2D);
+
+#endif
+
+  t2 = getTime();
+  fprintf(stderr, "Draw %12.4f -- %.2f Hz -- %.1f Mpixels/sec\n",
+	  t2-t1, 1.0/(t2-t1), ((double)(width*height))/(1000000*(t2-t1)));
+
+  glMatrixMode(GL_MODELVIEW);
+  glEnable(GL_DEPTH_TEST);
+  glDepthMask(GL_TRUE);
+}
+
+void
+DisplayFrame( void )
+{
+    float ambient[] = {0.1, 0.1, 0.1, 1.0};
+    float diffuse[] = {1.0, 1.0, 1.0, 1.0};
+    float position[] = {0.0, 1.0, 0.0, 0.0};
+    float mat_shininess[] = {90.0};
+    float mat_specular[] = {0.8, 0.8, 0.8, 1.0};
+    float mat_diffuse[] = {0.46, 0.66, 0.795, 1.0};
+    float mat_ambient[] = {0.0, 0.1, 0.2, 1.0};
+    float lmodel_ambient[] = {0.4, 0.4, 0.4, 1.0};
+    float lmodel_localviewer[] = {0.0};
+
+    int i;
+
+
+    //
+    // Bind the frame-buffer object and attach to it a render-buffer object 
+    // set up as a depth-buffer.
+    //
+    
+    glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, g_frameBuffer );
+    glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+    			       GL_TEXTURE_RECTANGLE_ARB, g_dynamicTextureID, 0 );
+    glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+				  GL_RENDERBUFFER_EXT, g_depthRenderBuffer );
+    
+    //
+    // Set up the frame-buffer object just like you would set up a window.
+    //
+    glViewport( 0, 0, xwin, ywin);
+
+
+
+    glFrontFace(GL_CCW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(40.0, 2.0, 10000.0, 400000.0);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    
+    for (i = 0; i < NUM_SHARKS; i++) {
+      glPushMatrix();
+      FishTransform(&sharks[i]);
+      DrawShark(&sharks[i]);
+      glPopMatrix();
+    }
+
+    glPushMatrix();
+    FishTransform(&dolph);
+    DrawDolphin(&dolph);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&momWhale);
+    DrawWhale(&momWhale);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&babyWhale);
+    glScalef(0.45, 0.45, 0.3);
+    DrawWhale(&babyWhale);
+    glPopMatrix();
+
+    if (winWidth > 0) {
+		glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);	
+		sageInf.swapBuffer();
+    	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+	 }
+
+	 sageMessage msg;
+	 if (sageInf.checkMsg(msg, false) > 0) {
+		 switch (msg.getCode()) {
+			 case APP_QUIT : {
+			 	sageInf.shutdown();
+				exit(0);
+				break;
+			}
+		 }	
+	 }
+	 
+
+    //save_frame();
+    
+    glFinish();
+
+    
+    
+    glutSwapBuffers( );
+    /*
+	 if (fr> 1000)
+    {			                
+        t2 = getTime();	
+        printf("Time: %f, Framerate: %f\n", t2-t1, fr/(t2-t1));
+        exit(0);
+    }
+    fr++;
+	 */
+}
+
+void
+Visible(int state)
+{
+    if (state == GLUT_VISIBLE) {
+        if (moving)
+            glutIdleFunc(Animate);
+    } else {
+        if (moving)
+            glutIdleFunc(NULL);
+    }
+}
+
+void
+menuSelect(int value)
+{
+    switch (value) {
+    case 1:
+        moving = GL_TRUE;
+        glutIdleFunc(Animate);
+        break;
+    case 2:
+        moving = GL_FALSE;;
+        glutIdleFunc(NULL);
+        break;
+    case 3:
+        exit(0);
+        break;
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+	 int appID;
+	 if (argc < 2)
+	 	appID = 0;
+	 else
+	 	appID = atoi(argv[1]);
+		
+	 int nodeId = 0;
+
+ 	 int resX = 300, resY = 300;
+	 if (argc > 3) {
+		 resX = atoi(argv[2]);
+		 resY = atoi(argv[3]);
+	 }	
+	
+	 sageRect atlantisImageMap;
+	 atlantisImageMap.left = 0.0;
+	 atlantisImageMap.right = 1.0;
+	 atlantisImageMap.bottom = 0.0;
+	 atlantisImageMap.top = 1.0;
+	 
+	 sailConfig scfg;
+	 scfg.init("atlantis.conf");
+	 scfg.setAppName("atlantis");
+	 scfg.rank = nodeId;
+	 scfg.appID = appID;
+	 scfg.resX = resX;
+	 scfg.resY = resY;
+	 scfg.imageMap = atlantisImageMap;
+	 scfg.pixFmt = PIXFMT_888;
+	 scfg.rowOrd = BOTTOM_TO_TOP;
+	 scfg.master = true;
+	 scfg.nwID = 1;
+	 
+	 if (argc > 4)
+	 	scfg.nwID = atoi(argv[4]);
+				 
+	 sageInf.init(scfg);
+	
+	 std::cout << "sail initialized " << std::endl;
+
+
+    gettimeofday(&tv_start,0);
+	
+    glutInit(&argc, argv);
+    xwin = resX;
+    ywin = resY;
+    glutInitWindowSize(xwin, ywin);
+    glutInitWindowPosition(0,0);
+    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+    glutCreateWindow("GLUT Atlantis Demo");
+    //glutFullScreen();
+    printf("sharks: %d\n",NUM_SHARKS);
+
+    Init();
+    
+    glutDisplayFunc(DisplayFrame);
+    glutReshapeFunc(Reshape);
+    glutKeyboardFunc(Key);
+    moving = GL_TRUE;
+    glutIdleFunc(Animate);
+    // glutVisibilityFunc(Visible);
+    glutCreateMenu(menuSelect);
+    glutAddMenuEntry("Start motion", 1);
+    glutAddMenuEntry("Stop motion", 2);
+    glutAddMenuEntry("Quit", 3);
+    glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+	if (rgbBuffer)
+	    delete [] rgbBuffer;
+    rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+   
+    t1 = getTime();
+	    
+
+    glutMainLoop();
+    return 0;             /* ANSI C requires main to return int. */
+}
Index: trunk/src/testing/app/atlantis-fbo/swim.c
===================================================================
--- trunk/src/testing/app/atlantis-fbo/swim.c	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/swim.c	(revision 4)
@@ -0,0 +1,194 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#include <stdlib.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include "atlantis.h"
+
+void
+FishTransform(fishRec * fish)
+{
+	glTranslatef(fish->y, fish->z, -fish->x);
+	glRotatef(-fish->psi, 0.0, 1.0, 0.0);
+    glRotatef(fish->theta, 1.0, 0.0, 0.0);
+    glRotatef(-fish->phi, 0.0, 0.0, 1.0);
+}
+
+void
+WhalePilot(fishRec * fish)
+{
+
+    fish->phi = -20.0;
+    fish->theta = 0.0;
+    fish->psi -= 0.5;
+
+    fish->x += WHALESPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += WHALESPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += WHALESPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkPilot(fishRec * fish)
+{
+    static int sign = 1;
+    float X, Y, Z, tpsi, ttheta, thetal;
+
+    fish->xt = 60000.0;
+    fish->yt = 0.0;
+    fish->zt = 0.0;
+
+    X = fish->xt - fish->x;
+    Y = fish->yt - fish->y;
+    Z = fish->zt - fish->z;
+
+    thetal = fish->theta;
+
+    ttheta = RAD * atan(Z / (sqrt(X * X + Y * Y)));
+
+    if (ttheta > fish->theta + 0.25) {
+        fish->theta += 0.5;
+    } else if (ttheta < fish->theta - 0.25) {
+        fish->theta -= 0.5;
+    }
+    if (fish->theta > 90.0) {
+        fish->theta = 90.0;
+    }
+    if (fish->theta < -90.0) {
+        fish->theta = -90.0;
+    }
+    fish->dtheta = fish->theta - thetal;
+
+    tpsi = RAD * atan2(Y, X);
+
+    fish->attack = 0;
+
+    if (fabs(tpsi - fish->psi) < 10.0) {
+        fish->attack = 1;
+    } else if (fabs(tpsi - fish->psi) < 45.0) {
+        if (fish->psi > tpsi) {
+            fish->psi -= 0.5;
+            if (fish->psi < -180.0) {
+                fish->psi += 360.0;
+            }
+        } else if (fish->psi < tpsi) {
+            fish->psi += 0.5;
+            if (fish->psi > 180.0) {
+                fish->psi -= 360.0;
+            }
+        }
+    } else {
+        if (rand() % 100 > 98) {
+            sign = 1 - sign;
+        }
+        fish->psi += sign;
+        if (fish->psi > 180.0) {
+            fish->psi -= 360.0;
+        }
+        if (fish->psi < -180.0) {
+            fish->psi += 360.0;
+        }
+    }
+
+    if (fish->attack) {
+        if (fish->v < 1.1) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.2;
+        }
+        if (fish->v > 5.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.2;
+        }
+    } else {
+        if (!(rand() % 400) && (!fish->spurt)) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.05;
+        }
+        if (fish->v > 3.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.05;
+        }
+    }
+
+    fish->x += SHARKSPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += SHARKSPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += SHARKSPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkMiss(int i)
+{
+    int j;
+    float avoid, thetal;
+    float X, Y, Z, R;
+
+    for (j = 0; j < NUM_SHARKS; j++) {
+        if (j != i) {
+            X = sharks[j].x - sharks[i].x;
+            Y = sharks[j].y - sharks[i].y;
+            Z = sharks[j].z - sharks[i].z;
+
+            R = sqrt(X * X + Y * Y + Z * Z);
+
+            avoid = 1.0;
+            thetal = sharks[i].theta;
+
+            if (R < SHARKSIZE) {
+                if (Z > 0.0) {
+                    sharks[i].theta -= avoid;
+                } else {
+                    sharks[i].theta += avoid;
+                }
+            }
+            sharks[i].dtheta += (sharks[i].theta - thetal);
+        }
+    }
+}
Index: trunk/src/testing/app/atlantis-fbo/whale.c
===================================================================
--- trunk/src/testing/app/atlantis-fbo/whale.c	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/whale.c	(revision 4)
@@ -0,0 +1,1813 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {0.019249 ,0.011340 ,-0.999750};
+static float N002[3] = {-0.132579 ,0.954547 ,0.266952};
+static float N003[3] = {-0.196061 ,0.980392 ,-0.019778};
+static float N004[3] = {0.695461 ,0.604704 ,0.388158};
+static float N005[3] = {0.870600 ,0.425754 ,0.246557};
+static float N006[3] = {-0.881191 ,0.392012 ,0.264251};
+static float N008[3] = {-0.341437 ,0.887477 ,0.309523};
+static float N009[3] = {0.124035 ,-0.992278 ,0.000000};
+static float N010[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N011[3] = {0.588172 ,0.000000 ,0.808736};
+static float N012[3] = {0.929824 ,-0.340623 ,-0.139298};
+static float N013[3] = {0.954183 ,0.267108 ,-0.134865};
+static float N014[3] = {0.495127 ,0.855436 ,-0.151914};
+static float N015[3] = {-0.390199 ,0.906569 ,-0.160867};
+static float N016[3] = {-0.923605 ,0.354581 ,-0.145692};
+static float N017[3] = {-0.955796 ,-0.260667 ,-0.136036};
+static float N018[3] = {-0.501283 ,-0.853462 ,-0.142540};
+static float N019[3] = {0.405300 ,-0.901974 ,-0.148913};
+static float N020[3] = {0.909913 ,-0.392746 ,-0.133451};
+static float N021[3] = {0.936494 ,0.331147 ,-0.115414};
+static float N022[3] = {0.600131 ,0.793724 ,-0.099222};
+static float N023[3] = {-0.231556 ,0.968361 ,-0.093053};
+static float N024[3] = {-0.844369 ,0.525330 ,-0.105211};
+static float N025[3] = {-0.982725 ,-0.136329 ,-0.125164};
+static float N026[3] = {-0.560844 ,-0.822654 ,-0.093241};
+static float N027[3] = {0.263884 ,-0.959981 ,-0.093817};
+static float N028[3] = {0.842057 ,-0.525192 ,-0.122938};
+static float N029[3] = {0.921620 ,0.367565 ,-0.124546};
+static float N030[3] = {0.613927 ,0.784109 ,-0.090918};
+static float N031[3] = {-0.448754 ,0.888261 ,-0.098037};
+static float N032[3] = {-0.891865 ,0.434376 ,-0.126077};
+static float N033[3] = {-0.881447 ,-0.448017 ,-0.149437};
+static float N034[3] = {-0.345647 ,-0.922057 ,-0.174183};
+static float N035[3] = {0.307998 ,-0.941371 ,-0.137688};
+static float N036[3] = {0.806316 ,-0.574647 ,-0.140124};
+static float N037[3] = {0.961346 ,0.233646 ,-0.145681};
+static float N038[3] = {0.488451 ,0.865586 ,-0.110351};
+static float N039[3] = {-0.374290 ,0.921953 ,-0.099553};
+static float N040[3] = {-0.928504 ,0.344533 ,-0.138485};
+static float N041[3] = {-0.918419 ,-0.371792 ,-0.135189};
+static float N042[3] = {-0.520666 ,-0.833704 ,-0.183968};
+static float N043[3] = {0.339204 ,-0.920273 ,-0.195036};
+static float N044[3] = {0.921475 ,-0.387382 ,-0.028636};
+static float N045[3] = {0.842465 ,0.533335 ,-0.076204};
+static float N046[3] = {0.380110 ,0.924939 ,0.002073};
+static float N047[3] = {-0.276128 ,0.961073 ,-0.009579};
+static float N048[3] = {-0.879684 ,0.473001 ,-0.049250};
+static float N049[3] = {-0.947184 ,-0.317614 ,-0.044321};
+static float N050[3] = {-0.642059 ,-0.764933 ,-0.051363};
+static float N051[3] = {0.466794 ,-0.880921 ,-0.077990};
+static float N052[3] = {0.898509 ,-0.432277 ,0.076279};
+static float N053[3] = {0.938985 ,0.328141 ,0.103109};
+static float N054[3] = {0.442420 ,0.895745 ,0.043647};
+static float N055[3] = {-0.255163 ,0.966723 ,0.018407};
+static float N056[3] = {-0.833769 ,0.540650 ,0.111924};
+static float N057[3] = {-0.953653 ,-0.289939 ,0.080507};
+static float N058[3] = {-0.672357 ,-0.730524 ,0.119461};
+static float N059[3] = {0.522249 ,-0.846652 ,0.102157};
+static float N060[3] = {0.885868 ,-0.427631 ,0.179914};
+static float N062[3] = {0.648942 ,0.743116 ,0.163255};
+static float N063[3] = {-0.578967 ,0.807730 ,0.111219};
+static float N065[3] = {-0.909864 ,-0.352202 ,0.219321};
+static float N066[3] = {-0.502541 ,-0.818090 ,0.279610};
+static float N067[3] = {0.322919 ,-0.915358 ,0.240504};
+static float N068[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N069[3] = {0.000000 ,1.000000 ,0.000000};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N072[3] = {0.000000 ,1.000000 ,0.000000};
+static float N073[3] = {0.000000 ,1.000000 ,0.000000};
+static float N074[3] = {0.000000 ,1.000000 ,0.000000};
+static float N075[3] = {0.031220 ,0.999025 ,-0.031220};
+static float N076[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {0.446821 ,0.893642 ,0.041889};
+static float N078[3] = {0.863035 ,-0.100980 ,0.494949};
+static float N079[3] = {0.585597 ,-0.808215 ,0.062174};
+static float N080[3] = {0.000000 ,1.000000 ,0.000000};
+static float N081[3] = {1.000000 ,0.000000 ,0.000000};
+static float N082[3] = {0.000000 ,1.000000 ,0.000000};
+static float N083[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N084[3] = {-0.478893 ,0.837129 ,-0.264343};
+static float N085[3] = {0.000000 ,1.000000 ,0.000000};
+static float N086[3] = {0.763909 ,0.539455 ,-0.354163};
+static float N087[3] = {0.446821 ,0.893642 ,0.041889};
+static float N088[3] = {0.385134 ,-0.908288 ,0.163352};
+static float N089[3] = {-0.605952 ,0.779253 ,-0.159961};
+static float N090[3] = {0.000000 ,1.000000 ,0.000000};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N096[3] = {0.644444 ,-0.621516 ,0.445433};
+static float N097[3] = {-0.760896 ,-0.474416 ,0.442681};
+static float N098[3] = {0.636888 ,-0.464314 ,0.615456};
+static float N099[3] = {-0.710295 ,0.647038 ,0.277168};
+static float N100[3] = {0.009604 ,0.993655 ,0.112063};
+static float iP001[3] = {18.74, 13.19, 3.76};
+static float P001[3] = {18.74, 13.19, 3.76};
+static float P002[3] = {0.00, 390.42, 10292.57};
+static float P003[3] = {55.80, 622.31, 8254.35};
+static float P004[3] = {20.80, 247.66, 10652.13};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 199.04, 9353.01};
+static float P008[3] = {-34.67, 247.64, 10663.71};
+static float iP009[3] = {97.46, 67.63, 593.82};
+static float iP010[3] = {-84.33, 67.63, 588.18};
+static float iP011[3] = {118.69, 8.98, -66.91};
+static float P009[3] = {97.46, 67.63, 593.82};
+static float P010[3] = {-84.33, 67.63, 588.18};
+static float P011[3] = {118.69, 8.98, -66.91};
+static float iP012[3] = {156.48, -31.95, 924.54};
+static float iP013[3] = {162.00, 110.22, 924.54};
+static float iP014[3] = {88.16, 221.65, 924.54};
+static float iP015[3] = {-65.21, 231.16, 924.54};
+static float iP016[3] = {-156.48, 121.97, 924.54};
+static float iP017[3] = {-162.00, -23.93, 924.54};
+static float iP018[3] = {-88.16, -139.10, 924.54};
+static float iP019[3] = {65.21, -148.61, 924.54};
+static float iP020[3] = {246.87, -98.73, 1783.04};
+static float iP021[3] = {253.17, 127.76, 1783.04};
+static float iP022[3] = {132.34, 270.77, 1783.04};
+static float iP023[3] = {-97.88, 285.04, 1783.04};
+static float iP024[3] = {-222.97, 139.80, 1783.04};
+static float iP025[3] = {-225.29, -86.68, 1783.04};
+static float iP026[3] = {-108.44, -224.15, 1783.04};
+static float iP027[3] = {97.88, -221.56, 1783.04};
+static float iP028[3] = {410.55, -200.66, 3213.87};
+static float iP029[3] = {432.19, 148.42, 3213.87};
+static float iP030[3] = {200.66, 410.55, 3213.87};
+static float iP031[3] = {-148.42, 432.19, 3213.87};
+static float iP032[3] = {-407.48, 171.88, 3213.87};
+static float iP033[3] = {-432.19, -148.42, 3213.87};
+static float iP034[3] = {-148.88, -309.74, 3213.87};
+static float iP035[3] = {156.38, -320.17, 3213.87};
+static float iP036[3] = {523.39, -303.81, 4424.57};
+static float iP037[3] = {574.66, 276.84, 4424.57};
+static float iP038[3] = {243.05, 492.50, 4424.57};
+static float iP039[3] = {-191.23, 520.13, 4424.57};
+static float iP040[3] = {-523.39, 304.01, 4424.57};
+static float iP041[3] = {-574.66, -231.83, 4424.57};
+static float iP042[3] = {-266.95, -578.17, 4424.57};
+static float iP043[3] = {211.14, -579.67, 4424.57};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 5943.46};
+static float iP046[3] = {371.29, 614.13, 5943.46};
+static float iP047[3] = {-291.43, 621.86, 5943.46};
+static float iP048[3] = {-784.13, 362.60, 5943.46};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P012[3] = {156.48, -31.95, 924.54};
+static float P013[3] = {162.00, 110.22, 924.54};
+static float P014[3] = {88.16, 221.65, 924.54};
+static float P015[3] = {-65.21, 231.16, 924.54};
+static float P016[3] = {-156.48, 121.97, 924.54};
+static float P017[3] = {-162.00, -23.93, 924.54};
+static float P018[3] = {-88.16, -139.10, 924.54};
+static float P019[3] = {65.21, -148.61, 924.54};
+static float P020[3] = {246.87, -98.73, 1783.04};
+static float P021[3] = {253.17, 127.76, 1783.04};
+static float P022[3] = {132.34, 270.77, 1783.04};
+static float P023[3] = {-97.88, 285.04, 1783.04};
+static float P024[3] = {-222.97, 139.80, 1783.04};
+static float P025[3] = {-225.29, -86.68, 1783.04};
+static float P026[3] = {-108.44, -224.15, 1783.04};
+static float P027[3] = {97.88, -221.56, 1783.04};
+static float P028[3] = {410.55, -200.66, 3213.87};
+static float P029[3] = {432.19, 148.42, 3213.87};
+static float P030[3] = {200.66, 410.55, 3213.87};
+static float P031[3] = {-148.42, 432.19, 3213.87};
+static float P032[3] = {-407.48, 171.88, 3213.87};
+static float P033[3] = {-432.19, -148.42, 3213.87};
+static float P034[3] = {-148.88, -309.74, 3213.87};
+static float P035[3] = {156.38, -320.17, 3213.87};
+static float P036[3] = {523.39, -303.81, 4424.57};
+static float P037[3] = {574.66, 276.84, 4424.57};
+static float P038[3] = {243.05, 492.50, 4424.57};
+static float P039[3] = {-191.23, 520.13, 4424.57};
+static float P040[3] = {-523.39, 304.01, 4424.57};
+static float P041[3] = {-574.66, -231.83, 4424.57};
+static float P042[3] = {-266.95, -578.17, 4424.57};
+static float P043[3] = {211.14, -579.67, 4424.57};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 5943.46};
+static float P046[3] = {371.29, 614.13, 5943.46};
+static float P047[3] = {-291.43, 621.86, 5943.46};
+static float P048[3] = {-784.13, 362.60, 5943.46};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -332.24, 7902.59};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {321.55, 558.53, 7902.59};
+static float P055[3] = {-260.54, 559.84, 7902.59};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 438.98, 9364.77};
+static float P063[3] = {-165.71, 441.27, 9355.44};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -504.03, 9355.44};
+static float iP068[3] = {-112.44, 9.25, -64.42};
+static float iP069[3] = {1155.63, 0.00, -182.46};
+static float iP070[3] = {-1143.13, 0.00, -181.54};
+static float iP071[3] = {1424.23, 0.00, -322.09};
+static float iP072[3] = {-1368.01, 0.00, -310.38};
+static float iP073[3] = {1255.57, 2.31, 114.05};
+static float iP074[3] = {-1149.38, 0.00, 117.12};
+static float iP075[3] = {718.36, 0.00, 433.36};
+static float iP076[3] = {-655.90, 0.00, 433.36};
+static float P068[3] = {-112.44, 9.25, -64.42};
+static float P069[3] = {1155.63, 0.00, -182.46};
+static float P070[3] = {-1143.13, 0.00, -181.54};
+static float P071[3] = {1424.23, 0.00, -322.09};
+static float P072[3] = {-1368.01, 0.00, -310.38};
+static float P073[3] = {1255.57, 2.31, 114.05};
+static float P074[3] = {-1149.38, 0.00, 117.12};
+static float P075[3] = {718.36, 0.00, 433.36};
+static float P076[3] = {-655.90, 0.00, 433.36};
+static float P077[3] = {1058.00, -2.66, 7923.51};
+static float P078[3] = {-1016.51, -15.47, 7902.87};
+static float P079[3] = {-1363.99, -484.50, 7593.38};
+static float P080[3] = {1478.09, -861.47, 7098.12};
+static float P081[3] = {1338.06, -284.68, 7024.15};
+static float P082[3] = {-1545.51, -860.64, 7106.60};
+static float P083[3] = {1063.19, -70.46, 7466.60};
+static float P084[3] = {-1369.18, -288.11, 7015.34};
+static float P085[3] = {1348.44, -482.50, 7591.41};
+static float P086[3] = {-1015.45, -96.80, 7474.86};
+static float P087[3] = {731.04, 148.38, 7682.58};
+static float P088[3] = {-697.03, 151.82, 7668.81};
+static float P089[3] = {-686.82, 157.09, 7922.29};
+static float P090[3] = {724.73, 147.75, 7931.39};
+static float iP091[3] = {0.00, 327.10, 2346.55};
+static float iP092[3] = {0.00, 552.28, 2311.31};
+static float iP093[3] = {0.00, 721.16, 2166.41};
+static float iP094[3] = {0.00, 693.42, 2388.80};
+static float iP095[3] = {0.00, 389.44, 2859.97};
+static float P091[3] = {0.00, 327.10, 2346.55};
+static float P092[3] = {0.00, 552.28, 2311.31};
+static float P093[3] = {0.00, 721.16, 2166.41};
+static float P094[3] = {0.00, 693.42, 2388.80};
+static float P095[3] = {0.00, 389.44, 2859.97};
+static float iP096[3] = {222.02, -183.67, 10266.89};
+static float iP097[3] = {-128.90, -182.70, 10266.89};
+static float iP098[3] = {41.04, 88.31, 10659.36};
+static float iP099[3] = {-48.73, 88.30, 10659.36};
+static float P096[3] = {222.02, -183.67, 10266.89};
+static float P097[3] = {-128.90, -182.70, 10266.89};
+static float P098[3] = {41.04, 88.31, 10659.36};
+static float P099[3] = {-48.73, 88.30, 10659.36};
+static float P100[3] = {0.00, 603.42, 9340.68};
+static float P104[3] = {-9.86, 567.62, 7858.65};
+static float P105[3] = {31.96, 565.27, 7908.46};
+static float P106[3] = {22.75, 568.13, 7782.83};
+static float P107[3] = {58.93, 568.42, 7775.94};
+static float P108[3] = {55.91, 565.59, 7905.86};
+static float P109[3] = {99.21, 566.00, 7858.65};
+static float P110[3] = {-498.83, 148.14, 9135.10};
+static float P111[3] = {-495.46, 133.24, 9158.48};
+static float P112[3] = {-490.82, 146.23, 9182.76};
+static float P113[3] = {-489.55, 174.11, 9183.66};
+static float P114[3] = {-492.92, 189.00, 9160.28};
+static float P115[3] = {-497.56, 176.02, 9136.00};
+static float P116[3] = {526.54, 169.68, 9137.70};
+static float P117[3] = {523.49, 184.85, 9161.42};
+static float P118[3] = {518.56, 171.78, 9186.06};
+static float P119[3] = {516.68, 143.53, 9186.98};
+static float P120[3] = {519.73, 128.36, 9163.26};
+static float P121[3] = {524.66, 141.43, 9138.62};
+/* *INDENT-ON* */
+
+void
+Whale001(void)
+{
+
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Whale002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Whale003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Whale004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Whale005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Whale006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Whale007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Whale008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Whale009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Whale010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Whale011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Whale012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+}
+
+void
+Whale013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P005);
+    glVertex3fv(P006);
+    glVertex3fv(P099);
+    glVertex3fv(P098);
+    glEnd();
+}
+
+void
+Whale014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P006);
+    glVertex3fv(P005);
+    glVertex3fv(P004);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+}
+
+void
+Whale015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+}
+
+void
+Whale016(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P104);
+    glVertex3fv(P105);
+    glVertex3fv(P106);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P107);
+    glVertex3fv(P108);
+    glVertex3fv(P109);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P110);
+    glVertex3fv(P111);
+    glVertex3fv(P112);
+    glVertex3fv(P113);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P116);
+    glVertex3fv(P117);
+    glVertex3fv(P118);
+    glVertex3fv(P119);
+    glVertex3fv(P120);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+DrawWhale(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch=0.0, thrash, chomp;
+
+
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.5 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.5 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg2 = 3.7 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg3 = 4.8 * thrash * sin((fish->htail + 23.0) * RRAD);
+    seg4 = 6.0 * thrash * sin((fish->htail + 28.0) * RRAD);
+    seg5 = 6.5 * thrash * sin((fish->htail + 35.0) * RRAD);
+    seg6 = 6.5 * thrash * sin((fish->htail + 40.0) * RRAD);
+    seg7 = 6.5 * thrash * sin((fish->htail + 55.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail - 160.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3 * 1.1;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3 * 0.9;
+
+    P099[1] = iP099[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P097[1] = iP097[1] + chomp;
+    P096[1] = iP096[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 8000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+    glScalef(3.0, 3.0, 3.0);
+
+    glEnable(GL_CULL_FACE);
+
+    Whale001();
+    Whale002();
+    Whale003();
+    Whale004();
+    Whale005();
+    Whale006();
+    Whale007();
+    Whale008();
+    Whale009();
+    Whale010();
+    Whale011();
+    Whale012();
+
+
+
+    Whale013();
+
+    Whale014();
+
+    Whale015();
+
+    Whale016();
+
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-fbo/atlantis.conf
===================================================================
--- trunk/src/testing/app/atlantis-fbo/atlantis.conf	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/atlantis.conf	(revision 4)
@@ -0,0 +1,11 @@
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+winWidth 1000
+winHeight 1000
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/app/atlantis-fbo/atlantis.h
===================================================================
--- trunk/src/testing/app/atlantis-fbo/atlantis.h	(revision 4)
+++ trunk/src/testing/app/atlantis-fbo/atlantis.h	(revision 4)
@@ -0,0 +1,69 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#define RAD 57.295
+#define RRAD 0.01745
+
+#define NUM_SHARKS  25
+#define SHARKSIZE 6000
+#define SHARKSPEED 100.0
+
+#define WHALESPEED 250.0
+
+typedef struct _fishRec {
+    float x, y, z, phi, theta, psi, v;
+    float xt, yt, zt;
+    float htail, vtail;
+    float dtheta;
+    int spurt, attack;
+} fishRec;
+
+extern fishRec sharks[NUM_SHARKS];
+extern fishRec momWhale;
+extern fishRec babyWhale;
+extern fishRec dolph;
+
+extern void FishTransform(fishRec *);
+extern void WhalePilot(fishRec *);
+extern void SharkPilot(fishRec *);
+extern void SharkMiss(int);
+extern void DrawWhale(fishRec *);
+extern void DrawShark(fishRec *);
+extern void DrawDolphin(fishRec *);
+
+#ifdef WINDOWS
+#pragma warning(disable:4305 4101)
+#endif
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5200
Index: trunk/src/testing/app/JuxtaView/UImulti/Makefile.amd64
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/Makefile.amd64	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/Makefile.amd64	(revision 4)
@@ -0,0 +1,15 @@
+QUANTA_DIR=/usr/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags`
+LDFLAGS=-L$(QUANTA_DIR)/lib64 -lquanta_64 `wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o Overview.o
+
+Overview.o: Overview.cpp
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UImulti/Overview.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/Overview.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/Overview.cpp	(revision 4)
@@ -0,0 +1,245 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  Overview.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 15 August 2005
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#include "JuxtaSCUI.h"
+
+
+JuxtaOverviewFrame::JuxtaOverviewFrame(wxWindow* parent, int id, const wxString& title,
+					const wxPoint& pos, const wxSize& size,
+					long style)
+			:wxFrame(parent,id,title,pos,size,style)
+{
+	data.imgArray = NULL;
+	img = NULL;
+	bmptodraw = NULL;
+	penColor.Set(255,255,255);
+
+}
+
+BEGIN_EVENT_TABLE( JuxtaOverviewFrame, wxFrame )
+	EVT_PAINT( JuxtaOverviewFrame::OnPaint )
+	EVT_RIGHT_UP( JuxtaOverviewFrame::OnDropDownMenu )
+	EVT_MENU( ID_ChangePenColor, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_MENU( ID_ZoomOutFromMouse, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_MENU( ID_ZoomInFromMouse, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_LEFT_UP( JuxtaOverviewFrame::OnLeftMouseUp )
+END_EVENT_TABLE()
+
+JuxtaOverviewFrame::~JuxtaOverviewFrame()
+{
+
+
+}
+
+void JuxtaOverviewFrame::SetImage(int w, int h, unsigned char* pixels)
+{
+	SetSize(w,h);
+
+	//get the data
+	data.w = w;
+	data.h = h;
+	if(data.imgArray)
+		delete [] data.imgArray;
+	data.imgArray = pixels;
+
+	//make an image out of it
+	if(img)
+		delete img;
+
+	img = new wxImage(data.w,data.h,data.imgArray,TRUE);
+
+	if(bmptodraw)
+		delete bmptodraw;
+
+	bmptodraw = new wxBitmap(img);
+
+	Refresh();
+
+
+}
+
+void JuxtaOverviewFrame::SetExtentRectangle(float nx, float ny, float nw, float nh)
+{
+	data.normX = nx;
+	data.normY = ny;
+	data.normW = nw;
+	data.normH = nh;
+}
+
+void JuxtaOverviewFrame::OnPaint(wxPaintEvent& event)
+{
+	pdc = new wxPaintDC(this);
+	wxPen pen(penColor,5,wxDOT_DASH);
+	pdc->SetPen(pen);
+	pdc->BeginDrawing();
+		if(bmptodraw)
+		{
+			fprintf(stderr,"Bitmap valid! Drawing\n");
+			pdc->DrawBitmap((*bmptodraw),0,0,TRUE);
+			//draw some lines with the extents
+		//	pdc->GetPen().SetJoin(wxJOIN_ROUND);
+		//	pdc->GetPen().SetWidth(10);
+		//	pdc->GetPen().SetCap(wxCAP_PROJECTING);
+		//	pdc->GetPen().SetColour(255,255,255);
+		//	pdc->GetPen().SetStyle(wxCROSSDIAG_HATCH);
+
+			int x0,y0,x1,y1;
+			x0 = (int)(data.normX * data.w);
+			y0 = (int)(data.normY * data.h);
+			x1 = (int)(x0 + (data.normW * data.w));
+			y1 = (int)(y0 + (data.normH * data.h));
+
+			pdc->DrawLine( x0,y0,x1,y0);
+			pdc->DrawLine( x0,y0,x0,y1);
+			pdc->DrawLine( x1,y0,x1,y1);
+			pdc->DrawLine( x0,y1,x1,y1);
+
+		}
+	pdc->EndDrawing();
+
+	delete pdc;
+}
+
+
+char OverviewMenuLabels[OVERVIEW_MENU_ITEM_COUNT][OVERVIEW_MENU_LABEL_LENGTH] =
+	{ "Change Border Color", "Zoom Out","Zoom In" };
+
+void JuxtaOverviewFrame::OnDropDownMenu(wxMouseEvent& event)
+{
+	//make the drop down menu
+	wxMenu *menu = new wxMenu();
+	for ( int i = 0; i < OVERVIEW_MENU_ITEM_COUNT; i++)
+	{
+		menu->Append( i, wxString(OverviewMenuLabels[i]));
+	}
+
+	PopupMenu(menu,event.GetX(),event.GetY());
+}
+
+void JuxtaOverviewFrame::OnMenuSelection(wxCommandEvent& event)
+{
+	wxColourDialog *dlg;
+	switch( event.GetId())
+	{
+	case ID_ChangePenColor:
+		fprintf(stderr,"Opening Color Dialog!\n");
+		//change the color of the pen
+		dlg = new wxColourDialog(this);
+		if( dlg->ShowModal() == wxID_OK)
+		{
+			unsigned char red, green, blue;
+			red = dlg->GetColourData().GetColour().Red();
+			green = dlg->GetColourData().GetColour().Green();
+			blue = dlg->GetColourData().GetColour().Blue();
+
+			penColor.Set(red,green,blue);
+			Refresh();
+		}
+
+		dlg->Destroy();
+		break;
+	case ID_ZoomOutFromMouse:
+		if(gMainFrame)
+		{
+			gMainFrame->PassEvent(JVZOOM_OUT);
+			gMainFrame->GetExtents(0);
+			Refresh();
+		}
+		break;
+	case ID_ZoomInFromMouse:
+		if(gMainFrame)
+		{
+			gMainFrame->PassEvent(JVZOOM_IN);
+			gMainFrame->GetExtents(0);
+			Refresh();
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+
+void JuxtaOverviewFrame::OnLeftMouseUp(wxMouseEvent& event)
+{
+	//figure out what normalized coordinates to send to the UI server...
+	float coords[2] = { 0.0, 0.0 };
+	fprintf(stderr,"Left mouse up at %d, %d\n",event.GetX(),event.GetY());
+	coords[0] = ((float)event.GetX() / (float)data.w) - (data.normW / 2.0);
+	coords[1] = ((float)event.GetY() / (float)data.h) - (data.normH / 2.0);
+
+	if( coords[0] + data.normW > 1 )
+	{
+		coords[0] += 1 - ( coords[0] + data.normW );
+	}
+	else if( coords[0] < 0 )
+	{
+		coords[0] = 0;
+	}
+
+	if( coords[1] + data.normH > 1 )
+	{
+		coords[1] += 1 - ( coords[1] + data.normH );
+	}
+	else if( coords[1] < 0 )
+	{
+		coords[1] = 0;
+	}
+
+	fprintf(stderr,"Passing normalized coords %f, %f to server\n",coords[0],coords[1]);
+	if( gMainFrame)
+	{
+		gMainFrame->PassEvent(JVTRANSLATE);
+		gMainFrame->PassBuffer((void*)coords,sizeof(float) * 2);
+		//gMainFrame->GetExtents(0);
+		//gMainFrame->GetExtents(1);
+		gMainFrame->BigRefresh();
+	}
+
+	Refresh();
+
+}
+
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5200.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5200.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5200.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5200
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico4300.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico4300.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico4300.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5300
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5300.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5300.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5300.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5300
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5400.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5400.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5400.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5400
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5500.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5500.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5500.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5500
Index: trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.cpp	(revision 4)
@@ -0,0 +1,612 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUI.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 15 August 2005
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include "JuxtaSCUI.h"
+
+void SkipComments(FILE* fin,char commentFlag);
+#define COMMENT_FLAG '#'
+
+JuxtaSCUIFrame::JuxtaSCUIFrame(bool ov, char* skinfilename,wxWindow* parent, int id, const wxString& title,
+			   const wxPoint& pos, const wxSize& size, long style)
+			   :wxFrame(parent,id,title,pos,size,style)
+{
+	QUANTAinit();
+	client = NULL;
+	num_clients = 0;
+
+
+	//---------setup the ui
+	wxImage* img;
+	wxBitmapButton* bmpbtn;
+	wxBitmap* bmp;
+	wxPanel* panel;
+	char buffer[100];
+	char background[100];
+	char upfile[100];
+	char downfile[100];
+	int xpos,ypos;
+
+	gApp->SetTopWindow(this);
+
+	panel = new wxPanel(this,-1);
+
+	//background
+	wxInitAllImageHandlers();
+	FILE* skinfile = NULL;
+
+	if(skinfilename == NULL)
+		skinfile = fopen("Skins/default.jsk","r");
+	else
+		skinfile = fopen(skinfilename,"r");
+
+	if(skinfile == NULL)
+		return;
+
+	SkipComments(skinfile,COMMENT_FLAG);
+
+	//get the background filename
+	fscanf(skinfile,"%s\n",background);
+	img = new wxImage(background);
+	bmp = new wxBitmap((*img));
+	statbmp = new wxStaticBitmap(panel,20,(*bmp),wxPoint(0,0));
+#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS_)
+	statbmp->Disable();	//to make sure the button pushes go to the buttons, not the background image
+#endif
+
+	//get the pan up info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanUp,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan down info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanDown,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan left info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanLeft,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan right info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanRight,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the fast pan up info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanUp,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan down button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanDown,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan left button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanLeft,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan right button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanRight,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the zoom in button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_ZoomIn,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the zoom out button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_ZoomOut,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the Quit button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_Quit,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	fclose(skinfile);
+
+	overviewframe = NULL;
+	showoverview = ov;
+
+}
+
+
+void JuxtaSCUIFrame::Show()
+{
+    for (int i = 0 ; i < num_clients ; i++)
+	if(overviewframe[i] && showoverview)
+		overviewframe[i]->Show();
+
+	wxFrame::Show();
+}
+
+
+BEGIN_EVENT_TABLE( JuxtaSCUIFrame, wxFrame)
+	EVT_BUTTON( ID_PanUp, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanDown, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanLeft, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanRight, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanUp, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanDown, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanLeft, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanRight, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_ZoomIn, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_ZoomOut, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_Quit, JuxtaSCUIFrame::OnEvent)
+END_EVENT_TABLE()
+
+//------------------------------------------
+JuxtaSCUIFrame::~JuxtaSCUIFrame()
+{
+
+	if(client)
+	{
+		PassEvent(JVQUIT);
+		for (int i = 0 ; i < num_clients ; i++) {
+		    client[i] -> close();
+		    delete client[i];
+		    client[i] = NULL;
+		}
+		delete client;
+	}
+
+}
+
+
+//------------------------------------------
+void JuxtaSCUIFrame::Init(char* configfilename)
+{
+	FILE* fin = fopen(configfilename,"r");
+	if(!fin)
+		return;
+
+	char ip[32];
+	int port;
+	memset(ip,0,32);
+
+	// get number of clients to connect to
+	fscanf(fin,"%d", &num_clients);
+
+	// allocate array of pointers to clients
+	client = new QUANTAnet_tcpClient_c *[num_clients];
+
+	// allocate array of pointers to overview frames
+	overviewframe = new JuxtaOverviewFrame *[num_clients];
+
+	// allocate QUANTA objects for each client
+	for (int i = 0 ; i < num_clients ; i++) {
+	    client[i] = new QUANTAnet_tcpClient_c();
+	}
+
+	cout << "*****Number of clients: " << num_clients << endl;
+
+	for (int i = 0 ; i < num_clients ; i++) {
+
+	    // read client info and connect
+	    fscanf(fin,"%s : %d\n",ip,&port);
+
+	    //client[i] = new QUANTAnet_tcpClient_c();
+	    if(client[i] -> connectToServer(ip, port) < 0)
+	    {
+		client[i] -> close();
+		delete client[i];
+		client[i] = NULL;
+
+#if DEBUG
+		wxMessageBox("Failed To Connect To Server.\nMake sure juxtauiclient.conf file has correct server ip and port number.\nCorrect format is \"server ip\" : \"port number\"");
+#endif
+	    }
+
+	    else
+	    {
+		//make sure the user didn't disable the overview
+		if(showoverview)
+		{
+		    fprintf(stderr,"Attempting to load overview\n");
+		    //ask for the overview!!!!
+		    overviewframe[i] = new JuxtaOverviewFrame(gApp->GetTopWindow(),
+							      -1,"Overview",
+							      wxPoint(wxWindow::GetSize().GetWidth(),0),
+							      wxSize(100,200),
+							      wxMINIMIZE_BOX | wxFRAME_NO_TASKBAR | wxRESIZE_BORDER);
+		    overviewframe[i]->Layout();
+		    overviewframe[i]->Show();
+
+		    GetOverview(i);
+		    GetExtents(i);
+		}
+		else
+		{
+		    fprintf(stderr,"Not attempting to make overview\n");
+		    overviewframe[i] = new JuxtaOverviewFrame(0,-1,"",wxPoint(0,0),wxSize(0,0),wxSIMPLE_BORDER);
+		    overviewframe[i]->Layout();
+		    overviewframe[i]->Show();
+		}
+
+		fflush(stderr);
+
+	    }
+
+	}
+
+/*
+
+	if(client[0] == NULL)
+	{
+            client[0] -> close();
+	    delete client[i];
+	    client[0] = NULL;
+
+#if DEBUG
+	    wxMessageBox("Failed To Connect To Server.\nMake sure juxtauicl\
+ient.conf file has correct server ip and port number.\nCorrect format is \"serv\
+er ip\" : \"port number\"");
+#endif
+	}
+	else
+	{
+	    //make sure the user didn't disable the overview
+	    if(showoverview)
+	    {
+		fprintf(stderr,"Attempting to load overview\n");
+		//ask for the overview!!!!
+		overviewframe = new JuxtaOverviewFrame(gApp->GetTopWindow()\
+						       ,
+						       -1,"Overview",
+						       wxPoint(wxWindow::GetSize().GetWidth(),0),
+						       wxSize(100,200),
+                                                           wxMINIMIZE_BOX | wxFRAME_NO_TASKBAR | wxRESIZE_BORDER);
+		overviewframe->Layout();
+		overviewframe->Show();
+
+		GetOverview(i);
+		GetExtents(i);
+	    }
+	    else
+	    {
+		fprintf(stderr,"Not attempting to make overview\n");
+		overviewframe = new JuxtaOverviewFrame(0,-1,"",wxPoint(0,0)\
+						       ,wxSize(0,0),wxSIMPLE_BORDER);
+		overviewframe[i]->Layout();
+		overviewframe[i]->Show();
+	    }
+
+	    fflush(stderr);
+
+	}
+*/
+	fclose(fin);
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::OnEvent(wxCommandEvent& event)
+{
+
+	//disable all buttons but quit
+	//here's the tree
+	//	this
+	//	|_______panel
+	//		|________All the buttons!!!!!!
+
+//	this->GetChildren().GetFirst()->GetData()->Disable();
+
+	switch(event.GetId())
+	{
+	case ID_FastPanLeft:
+		PassEvent(JVFAST_PAN_LEFT);
+		break;
+	case ID_FastPanRight:
+	    	PassEvent(JVFAST_PAN_RIGHT);
+		break;
+	case ID_FastPanUp:
+		PassEvent(JVFAST_PAN_UP);
+		break;
+	case ID_FastPanDown:
+		PassEvent(JVFAST_PAN_DOWN);
+		break;
+	case ID_PanLeft:
+		PassEvent(JVPAN_LEFT);
+		break;
+	case ID_PanRight:
+		PassEvent(JVPAN_RIGHT);
+		break;
+	case ID_PanUp:
+		PassEvent(JVPAN_UP);
+		break;
+	case ID_PanDown:
+		PassEvent(JVPAN_DOWN);
+		break;
+	case ID_ZoomIn:
+		PassEvent(JVZOOM_IN);
+		break;
+	case ID_ZoomOut:
+		PassEvent(JVZOOM_OUT);
+		break;
+	case ID_Quit:
+		PassEvent(JVQUIT);
+		break;
+	default:
+		break;
+	}	//end switch
+
+	//ask for the extent if it's not quit
+	if( event.GetId() != ID_Quit)
+
+	    for (int i = 0 ; i < num_clients ; i++) {
+		if (overviewframe[i] && showoverview )
+		{
+		    GetExtents(i);
+		    if(overviewframe[i])
+			overviewframe[i]->Refresh();
+		}
+	    }
+
+	Refresh();
+
+//	this->GetChildren().GetFirst()->GetData()->Enable();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::BigRefresh()
+{
+    for (int i = 0 ; i < num_clients ; i++) {
+	if (overviewframe[i] && showoverview )
+	{
+	    GetExtents(i);
+	    if(overviewframe[i])
+		overviewframe[i]->Refresh();
+	}
+    }
+
+    Refresh();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::PassEvent(char* strEvent)
+{
+#if DEBUG
+	fprintf(stderr,"passing event %s\n",strEvent);
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int size = TRANSMISSION_SIZE;
+
+	clientMutex.Lock();
+		memset(sendBuffer,0,TRANSMISSION_SIZE);
+		strcpy(sendBuffer,strEvent);
+		for (int i = 0 ; i < num_clients ; i++) {
+		    if(client[i])
+		    {
+			client[i]->write(sendBuffer,&size, QUANTAnet_tcpClient_c::BLOCKING);
+		    }
+		}
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::PassBuffer(void* buffer,int size)
+{
+	clientMutex.Lock();
+	for (int i = 0 ; i < num_clients ; i++) {
+	    if(client[i])
+	    {
+		client[i]->write((const char*)buffer,&size,QUANTAnet_tcpClient_c::BLOCKING);
+	    }
+	}
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::GetExtents(int cn)
+{
+#if DEBUG
+	fprintf(stderr,"Getting extents for overview\n");
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int sendsize = TRANSMISSION_SIZE;
+	static int readsize = sizeof(float) * 4;
+
+	memset(sendBuffer,0,TRANSMISSION_SIZE);
+	clientMutex.Lock();
+		strcpy(sendBuffer,JVEXTENTS);
+
+		float readarray[4];
+		if( client[cn] )
+		{
+			client[cn]->write(sendBuffer,&sendsize,QUANTAnet_tcpClient_c::BLOCKING);
+			//get four floats
+			client[cn]->read((char*)readarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+			if(overviewframe[cn])
+				overviewframe[cn]->SetExtentRectangle(readarray[0],readarray[1],readarray[2],readarray[3]);
+
+#if DEBUG
+		fprintf(stderr,"floats recieved: %f, %f, %f, %f\n",readarray[0],readarray[1],readarray[2],readarray[3]);
+#endif
+		}
+	clientMutex.Unlock();
+
+}
+
+void JuxtaSCUIFrame::GetOverview(int cn)
+{
+#if DEBUG
+	fprintf(stderr,"Getting overview image\n");
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int sendsize = TRANSMISSION_SIZE;
+	static int readsize;
+
+	memset(sendBuffer,0,TRANSMISSION_SIZE);
+
+	clientMutex.Lock();
+		strcpy(sendBuffer,JVOVERVIEW);
+
+		if(client[cn])
+		{
+			//ask for the overview
+			client[cn]->write(sendBuffer,&sendsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			//get two ints
+			int dimarray[2];
+			readsize = sizeof(int) * 2;
+			client[cn]->read((char*)dimarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			//get pixels
+			readsize = dimarray[0] * dimarray[1] * 3;
+			unsigned char* img = new unsigned char[readsize];
+			client[cn]->read((char*)img,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			if(overviewframe[cn])
+				overviewframe[cn]->SetImage(dimarray[0],dimarray[1],img);
+
+#if DEBUG
+		fprintf(stderr,"Got overview of dims %d x %d\n",dimarray[0],dimarray[1]);
+#endif
+
+		}
+
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+
+void SkipComments(FILE* fin,char commentFlag)
+{
+	char c;
+	c = fgetc(fin);
+	bool skipline;
+	if( c == commentFlag)
+	{
+		skipline = true;
+		while(skipline)
+		{
+			while( c != '\n' && !feof(fin))
+				c = fgetc(fin);
+
+			if(feof(fin))
+				return;
+
+			long position = ftell(fin);
+			c = fgetc(fin);
+			if(c != commentFlag)
+			{
+				skipline = false;
+				fseek(fin,position,0);
+			}
+		}
+	}
+	else
+	{
+		fseek(fin, ftell(fin) - 1, 0);
+	}
+}
Index: trunk/src/testing/app/JuxtaView/UImulti/Makefile.32
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/Makefile.32	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/Makefile.32	(revision 4)
@@ -0,0 +1,14 @@
+QUANTA_DIR=/home/arun/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags`
+LDFLAGS=-L$(QUANTA_DIR)/lib -lquanta_32 `wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o
+
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UImulti/mac.r
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/mac.r	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/mac.r	(revision 4)
@@ -0,0 +1,13 @@
+data 'MBAR' (128) {
+	$"0001 0080"                                          /* ... */
+};
+
+data 'MENU' (128, "Apple") {
+	$"0080 0000 0000 0000 0000 FFFF FFFB 0114"            /* .........ÿÿÿû.. */
+	$"0A41 626F 7574 2046 4C54 4B00 0000 0001"            /* ÂAbout FLTK..... */
+	$"2D00 0000 0000"                                     /* -..... */
+};
+
+data 'carb' (0) {
+};
+
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5600.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5600.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5600.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5600
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5700.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5700.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5700.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5700
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5800.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5800.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient-nico5800.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+nico.evl.uic.edu : 5800
Index: trunk/src/testing/app/JuxtaView/UImulti/main.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/main.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/main.cpp	(revision 4)
@@ -0,0 +1,93 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  main.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 15 August 2005
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#include "JuxtaSCUI.h"
+#include <wx/wx.h>
+#include <wx/frame.h>
+
+JuxtaSCUIFrame* gMainFrame = NULL;
+wxApp* gApp = NULL;
+
+class JuxtaViewSCUIApp : public wxApp
+{
+public:
+    bool OnInit();
+	int OnExit();
+};
+
+IMPLEMENT_APP(JuxtaViewSCUIApp)
+
+
+bool JuxtaViewSCUIApp::OnInit()
+{
+	bool overview = true;
+
+	gApp = (wxApp*) this;
+	char* skinfile = NULL;
+	/*
+	if( argc > 1 )
+		skinfile = argv[1];
+	*/
+#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS_)
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(405,430));
+#elif defined(MAC_OSX)
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(400,420));
+#else
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(400,400));
+#endif
+	mainFrame->Init(wxApp::argv[1]);
+	mainFrame->Layout();
+	mainFrame->Show();
+
+	gMainFrame = mainFrame;
+
+	return true;
+}
+
+int JuxtaViewSCUIApp::OnExit()
+{
+	return 0;
+}
Index: trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.h
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUI.h	(revision 4)
@@ -0,0 +1,167 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUI.h - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 15 August 2005
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#ifndef JUXTASCUI_H
+#define JUXTASCUI_H
+
+#include <wx/wx.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <QUANTA/QUANTAinit.hxx>
+#include <QUANTA/QUANTAnet_tcp_c.hxx>
+#include <QUANTA/QUANTAnet_datapack_c.hxx>
+
+#include <wx/frame.h>
+#include <iostream>
+using namespace std;
+
+#include <wx/panel.h>
+#include <wx/button.h>
+#include <wx/image.h>	//for loading in images
+#include <wx/bitmap.h>	//for drawing images
+#include <wx/bmpbuttn.h>	//for placing images on buttons...deprecaited method
+#include <wx/statbmp.h>		//new header for drawing images...
+
+#include "JuxtaSCUICommon.h"
+#define DEBUG 1
+//list ID's for buttons
+enum
+{
+	ID_PanLeft = 1000,
+	ID_PanRight,
+	ID_PanDown,
+	ID_PanUp,
+	ID_FastPanLeft,
+	ID_FastPanRight,
+	ID_FastPanDown,
+	ID_FastPanUp,
+	ID_ZoomOut,
+	ID_ZoomIn,
+	ID_Quit
+};
+
+struct SOverview
+{
+	unsigned char* imgArray;
+	int w;
+	int h;
+	float normX;
+	float normY;
+	float normW;
+	float normH;
+
+};
+
+#include <wx/dcclient.h>
+#include <wx/pen.h>
+#include <wx/colordlg.h>
+
+#define OVERVIEW_MENU_ITEM_COUNT 3
+#define OVERVIEW_MENU_LABEL_LENGTH 21
+enum{
+	ID_ChangePenColor = 0,
+	ID_ZoomOutFromMouse,
+	ID_ZoomInFromMouse
+};
+
+class JuxtaOverviewFrame : public wxFrame
+{
+private:
+	SOverview data;
+	wxImage* img;
+	wxBitmap* bmptodraw;
+	wxPaintDC* pdc;
+	wxColour penColor;
+public:
+	JuxtaOverviewFrame( wxWindow* parent, int id, const wxString& title,
+				const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize,
+				long style=wxDEFAULT_FRAME_STYLE);
+	~JuxtaOverviewFrame();
+	void SetImage(int w, int h, unsigned char* pixels);
+	void SetExtentRectangle(float nx, float ny, float nw, float nh);
+	void OnPaint(wxPaintEvent& event);
+	void OnDropDownMenu(wxMouseEvent& event);
+	void OnMenuSelection(wxCommandEvent& event);
+	void OnLeftMouseUp(wxMouseEvent& event);
+
+	DECLARE_EVENT_TABLE();
+};
+
+//-------------------------------------------
+class JuxtaSCUIFrame : public wxFrame
+{
+private:
+	QUANTAnet_tcpClient_c** client;
+	wxStaticBitmap* statbmp;
+	JuxtaOverviewFrame** overviewframe;
+	bool showoverview;
+	wxMutex clientMutex;
+	int num_clients;
+public:
+	JuxtaSCUIFrame( bool ov, char* skinfilename, wxWindow* parent, int id, const wxString& title,
+					const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize,
+					long style=wxDEFAULT_FRAME_STYLE);
+
+	~JuxtaSCUIFrame();
+	void Init(char* );	//pass config filename
+	void OnEvent(wxCommandEvent& event);
+	void GetExtents(int cn);
+	void GetOverview(int cn);
+	virtual void Show();
+	void PassEvent(char*);
+	void PassBuffer(void*,int);
+	void BigRefresh();
+
+	DECLARE_EVENT_TABLE();
+};
+
+extern JuxtaSCUIFrame *gMainFrame;
+extern wxApp* gApp;
+
+#endif
Index: trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf2
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf2	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/uiclient.nico.conf2	(revision 4)
@@ -0,0 +1,3 @@
+2
+nico.evl.uic.edu : 5200
+nico.evl.uic.edu : 5300
Index: trunk/src/testing/app/JuxtaView/UImulti/Makefile.mac
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/Makefile.mac	(revision 4)
@@ -0,0 +1,18 @@
+QUANTA_DIR=/usr/local
+#WX_DIR=/usr/local/wxMac-2.5.3
+WX_DIR=/usr/local/bin
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `$(WX_DIR)/wx-config --cflags` -DMAC_OSX
+LDFLAGS=-L$(QUANTA_DIR)/lib -lquanta_32 `$(WX_DIR)/wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o
+	$(CC) $(LDFLAGS) -o JuxtaSCUI main.o JuxtaSCUI.o
+	/Developer/Tools/Rez -t APPL -o JuxtaSCUI mac.r
+
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UImulti/Makefile
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/Makefile	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/Makefile	(revision 4)
@@ -0,0 +1,15 @@
+QUANTA_DIR=/usr/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags`
+LDFLAGS=-L$(QUANTA_DIR)/lib64 -lquanta_64 `wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o Overview.o
+
+Overview.o: Overview.cpp
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUICommon.h
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUICommon.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/JuxtaSCUICommon.h	(revision 4)
@@ -0,0 +1,70 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUICommon.h - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 9 September 2005
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+
+#ifndef JUXTASCUI_COMMON_H
+#define JUXTASCUI_COMMON_H
+
+#define TRANSMISSION_SIZE 10	//send 10 bytes at a time
+
+//Messages To Transmit
+#define JVPAN_LEFT "jvleft"
+#define JVPAN_RIGHT "jvright"
+#define JVPAN_UP "jvup"
+#define JVPAN_DOWN "jvdown"
+#define JVFAST_PAN_LEFT "jvfleft"
+#define JVFAST_PAN_RIGHT "jvfright"
+#define JVFAST_PAN_UP "jvfup"
+#define JVFAST_PAN_DOWN "jvfdown"
+#define JVZOOM_OUT "jvzoomout"
+#define JVZOOM_IN "jvzoomin"
+#define JVEXTENTS "jvextent"
+#define JVOVERVIEW "jvoverv"
+#define JVTRANSLATE "jvfreepan"
+#define JVQUIT "jvquit"
+#define JVRESEND "jvresend"
+
+
+#endif
Index: trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-1.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-1.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-1.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+raster.ucsd.edu : 5300
Index: trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-2.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-2.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UImulti/JuxtaView-uiclient-raster-2.conf	(revision 4)
@@ -0,0 +1,3 @@
+2
+raster.ucsd.edu : 5300
+raster.ucsd.edu : 5400
Index: trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.h
===================================================================
--- trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.h	(revision 4)
@@ -0,0 +1,325 @@
+/******************************************************************************
+ * Program: GlobalCoordinatesToFileMapper
+ * Module:  GlobalCoordinatesToFileMapper.h
+ * Authors: Nicholas Schwarz, schwarz@evl.uic.edu
+ * Date:    21 September 2004
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+// .NAME GlobalCoordinatesToFileMapper
+// .SECTION Description
+// GlobalCoordinatesToFileMapper is a class that maps from the global
+// coordinate space, usually pixels, of an image formed from a montage of
+// smaller, identically sized, rectangular images to the real image files
+// that the larger images consists of.
+
+
+#ifndef GLOBAL_COORDINATES_TO_FILE_MAPPER_H
+#define GLOBAL_COORDINATES_TO_FILE_MAPPER_H
+
+
+// Preprocessor definition error code for invalid extent
+#define GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_EXTENT 0
+
+// Preporcessor definition error code for invalid file name
+#define GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_FILE 1
+
+// Preprocessor definition error code for un-initialized mapper
+#define GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_NOT_INITIALIZED 2
+
+// Preprocessor definition to indicate operation success
+#define GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS 3
+
+
+#include <fstream.h>
+#include <stddef.h>
+#include <string.h>
+
+
+// class FileInfo holds information about individual files.
+#include "FileInfo.h"
+
+
+class GlobalCoordinatesToFileMapper {
+
+ public:
+
+  // Description:
+  // Constructor
+  GlobalCoordinatesToFileMapper();
+
+  // Description:
+  // Get description of the global image.
+  const char* GetDescription();
+
+  // Description:
+  // Get height of a single file that makes up the global image in coordinates
+  // local to the file, usually pixels. We assume that all files are the same
+  // size.
+  long GetFileCoordinateDimensionH();
+
+  // Description:
+  // Get width of a single file that makes up the global image in coordinates
+  // local to the file, usually pixels. We assume that all files are the same
+  // size.
+  long GetFileCoordinateDimensionW();
+
+  // Description:
+  // Get height of the global image in global coordinates, usually pixels.
+  long GetGlobalCoordinateDimensionH();
+
+  // Description:
+  // Get width of the global image in global coordinates, usually pixels.
+  long GetGlobalCoordinateDimensionW();
+
+  // Description:
+  // Get extent for a given file that makes up the global image in global
+  // coordinates, usually pixels.
+  long GetGlobalCoordinates(const char* name,
+			    long* x,
+			    long* y,
+			    long* w,
+			    long* h);
+
+  // Description:
+  // Get the GlobalFileLayoutArray, and its corresponding dimensions.The
+  // GlobalFileLayoutArray is an adjacency matrix that specifies the layout of
+  // files in the global image. The matrix starts in the upper left of the
+  // global image, and is stored in column, row order. The matrix is an array
+  // of pointers to character strings. Each character string contains the name
+  // of its corresponding file. This class allocates and deallocates storage
+  // for this array.
+  char** GetGlobalFileLayoutArray(long* cols,
+				  long* rows);
+
+  // Description:
+  // Get the dimensions of the GlobalFileArray. The GlobalFileLayoutArray is
+  // an adjacency matrix that specifies the layout of files in the global
+  // image. The matrix starts in the upper left of the global image, and is
+  // stored in column, row order. The matrix is an array of pointers to
+  // character strings. Each character string contains the name of its
+  // corresponding file. This class allocates and deallocates storage for this
+  // array.
+  void GetGlobalFileLayoutDimensions(long* cols,
+				     long* rows);
+
+  // Description:
+  // Get the height of the current query's extent in global coordinates,
+  // usually pixels.
+  long GetQueryExtentH();
+
+  // Description:
+  // Get the width of the current query's extent in global coordinates,
+  // usually pixels.
+  long GetQueryExtentW();
+
+  // Description:
+  // Get the starting x position of the current query's extent in global
+  // coordinates, usually pixels. We assume that position (0,0) is in the
+  // upper left corner.
+  long GetQueryExtentX();
+
+  // Description:
+  // Get the starting y position of the current query's extent in global
+  // coordinates, usually pixels. We assume that position (0,0) is in the
+  // upper left corner.
+  long GetQueryExtentY();
+
+  // Description:
+  // Get the FileInfoArray, and its corresponding dimensions. The FileInfoArray
+  // is a 1D array of type FileInfo stored in column, row order. The FileInfo
+  // array is updated by the Query() method. When making a query this array is
+  // its result.
+  FileInfo* GetQueryFileInfoArray(long* cols,
+				  long* rows);
+
+  // Description:
+  // Get the dimensions of the FileInfoArray. The FileInfoArray is a 1D array
+  // of type FileInfo stored in column, row order. The FileInfo array is
+  // updated by the Query() method.
+  void GetQueryFileInfoDimensions(long* cols,
+				  long* rows);
+
+  // Description:
+  // Initialize the class based on information in the file given.
+  int Initialize(const char* name);
+
+  // Description:
+  // Returns whether this instance of the class has been initialized.
+  bool IsInitialized();
+
+  // Description:
+  // Print self.
+  void PrintSelf(ostream& os);
+
+  // Description:
+  // Query this instance of the class. Returns an error if the instance is
+  // not initialized, or the data extent is not within the global coordinate
+  // space. Call this method each time the query extent is changed. When the
+  // query is complete, the FileInfoArray is updated.
+  int Query();
+
+  // Description:
+  // Set description for the global image.
+  void SetDescription(const char* string);
+
+  // Description:
+  // Set the dimensions of a single file that makes up the global image in
+  // coordinates local to the file, usually pixels. We assume that all files
+  // are the same size.
+  void SetFileCoordinateDimensions(long w,
+				   long h);
+
+  // Description:
+  // Set the state of this instance to not initialized. This method should only
+  // be invoked by the Initialize(...) method.
+  void SetInitializedFalse();
+
+  // Description:
+  // Set the state of this instance to initialized. This method should only be
+  // invoked by the Initialize(...) method.
+  void SetInitializedTrue();
+
+  // Description:
+  // Set the dimensions of the global image in global coordinates, usually
+  // pixels.
+  void SetGlobalCoordinateDimensions(long w,
+				     long h);
+
+  // Description:
+  // Set the GlobalFileLayoutArray, along with its dimensions in columns and
+  // rows. The GlobalFileLayoutArray is an adjacency matrix that specifies
+  // the layout of files in the global image. The matrix starts in the upper
+  // left of the global image, and is stored in column, row order. The matrix
+  // is an array of pointers to character strings. Each character string
+  // contains the name of its corresponding file. This class allocates and
+  // deallocates storage for this array. This method should only be invoked by
+  // the Initialize(...) method.
+  void SetGlobalFileLayoutArray(char** array,
+				long cols,
+				long rows);
+
+  // Description:
+  // Set the dimensions of the GlobalFileArray. The GlobalFileLayoutArray is
+  // an adjacency matrix that specifies the layout of files in the global
+  // image. The matrix starts in the upper left of the global image, and is
+  // stored in column, row order. The matrix is an array of pointers to
+  // character strings. Each character string contains the name of its
+  // corresponding file. This class allocates and deallocates storage for this
+  // array. This method should only be invoked by the Initialize(...), or
+  // SetGlobalFileLayoutArray(...) methods.
+  void SetGlobalFileLayoutDimensions(long cols,
+				     long rows);
+
+  // Description:
+  // Set the extent of the current query. Set this information before calling
+  // the Query() method.
+  void SetQueryExtent(long x, long y,
+		      long w, long h);
+
+  // Description:
+  // Set the FileInfoArray, and its corresponding dimensions. The FileInfoArray
+  // is a 1D array of type FileInfo stored in column, row order. This method
+  // should only be invoked by the Query() method.
+  void SetQueryFileInfoArray(FileInfo* array,
+			     long cols,
+			     long rows);
+
+  // Description:
+  // Set the dimensions of the FileInfoArray. The FileInfoArray is a 1D array
+  // of type FileInfo stored in column, row order. This method should only be
+  // invoked by the Query(), or SetQueryFileInfoArray(...) methods.
+  void SetQueryFileInfoDimensions(long cols,
+				  long rows);
+
+  // Description:
+  // Destructor
+  ~GlobalCoordinatesToFileMapper();
+
+
+ private:
+
+  // Description:
+  // Description of the global image.
+  char* Description;
+
+  // Description:
+  // The width and height of a single file that makes up the global image in
+  // coordinates local to the file, usually pixels. We assume that all files
+  // are the same size.
+  long FileCoordinateDimensions[2];
+
+  // Description:
+  // The width and height of the global image in global coordinates, usually
+  // pixels.
+  long GlobalCoordinateDimensions[2];
+
+  // Description:
+  // The GlobalFileLayoutArray is an adjacency matrix that specifies the
+  // layout of files in the global image. The matrix starts in the upper left
+  // of the global image, and is stored in column, row order. The matrix is an
+  // array of pointers to character strings. Each character string contains
+  // the name of its corresponding file. This class allocates and deallocates
+  // storage for this array.
+  char** GlobalFileLayoutArray;
+
+  // Description:
+  // The number of columns and rows of files that make up the global image.
+  long GlobalFileLayoutDimensions[2];
+
+  // Description:
+  // Flag indicating whether the instance of the class is initialized.
+  bool Initialized;
+
+  // Description:
+  // The extent of the current query as the x and y locations of the upper
+  // left corner of the extent, and the width and height of the extent in
+  // global coordinates, usually pixels.
+  long QueryExtent[4];
+
+  // Description:
+  // The FileInfoArray is a 1D array of type FileInfo stored in column, row
+  // order. The FileInfo array is updated by the Query() method. When making a
+  // query this array is its result.
+  FileInfo* QueryFileInfoArray;
+
+  // Description:
+  // The number of columns and rows in the FileInfoArray. Updated by the
+  // Query() method.
+  long QueryFileInfoDimensions[2];
+
+};
+
+
+#endif
Index: trunk/src/testing/app/JuxtaView/juxtaconfig-nico-1.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtaconfig-nico-1.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtaconfig-nico-1.conf	(revision 4)
@@ -0,0 +1,2 @@
+1
+0.0 0.0 1.0 1.0 BDR_TBLR 10.0.8.111
Index: trunk/src/testing/app/JuxtaView/juxtaconfig-nico-4.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtaconfig-nico-4.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtaconfig-nico-4.conf	(revision 4)
@@ -0,0 +1,5 @@
+4
+0.0 0.5 0.5 1.0 BDR_BL
+0.5 0.5 1.0 1.0 BDR_BR
+0.0 0.0 0.5 0.5 BDR_TL
+0.5 0.0 1.0 0.5 BDR_TR
Index: trunk/src/testing/app/JuxtaView/README
===================================================================
--- trunk/src/testing/app/JuxtaView/README	(revision 4)
+++ trunk/src/testing/app/JuxtaView/README	(revision 4)
@@ -0,0 +1,66 @@
+Tiny readme for JuxtaView for SAGE
+Nicholas Schwarz
+28 October 2004
+
+juxtaconfig.conf - Determines viewports of slave, display nodes.
+
+First line is the number of slave, display nodes. Each following line is the
+normalized viewport coordinates (0.0 - 1.0) for x_min, y_min, x_max, y_max.
+Origin is the upper left corner of the screen. Then follows a flag 
+indicating which sides of the viewport to draw a border to.
+
+NOTE: It would be nice if a tile-config library could convert between, pixels
+and normalized coordinates, and convert between different origins as well.
+
+
+juxtadata.conf - Describes the data.
+
+First line: x, y origin of the data and the width and height of the data. Data
+refers to the entire, huge image. The origin is always the upper left corner
+of the data.
+
+Second line: x, y position of the starting location in the data. This is where
+the application starts.
+
+Third line: slow_pan amount, fast_pan amount.
+
+Fourth line: width, height of data extent to fetch. This should be the size
+of the SAGE window.
+
+Fifth line: scale factor for overview file given to UI
+
+Sixth line: path of overview file for the dataset for UI
+
+
+juxtalayout.conf
+
+Data layout specification file used by GlobalCoordinatesToFileMapper class.
+
+First line: width, height of entire, huge image.
+
+Second line: number_columns, number_rows of tiles that make up the entire, huge
+image.
+
+Thrid line: dim_x, dim_y of each file. This assumes that all files are the same
+size. This should change in the future.
+
+Following lines: Files that make up the entire, huge image. Specified column
+by column from the top of the column down. So in the sample file
+
+/home/evl/schwarz/data/16tdn155040.tif
+/home/evl/schwarz/data/16tdn155025.tif
+/home/evl/schwarz/data/16tdn155010.tif
+
+is the left most column, where /home/evl/schwarz/data/16tdn155040.tif is the
+top row in that column, and /home/evl/schwarz/data/16tdn155010.tif is the
+bottom row in that column.
+
+
+juxtauiserver.conf - config file used by JuxtaUIServer class.
+
+port to listen for incoming connections.
+
+
+juxtaclient.conf - config file used by JuxtaView Client UI.
+
+IP_address : port_number of server
Index: trunk/src/testing/app/JuxtaView/juxtaconfig-nico-8.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtaconfig-nico-8.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtaconfig-nico-8.conf	(revision 4)
@@ -0,0 +1,9 @@
+8
+0.0 0.75 0.5 1.0 BDR_BL 10.0.8.111
+0.0 0.5 0.5 0.75 BDR_L 10.0.8.112
+0.0 0.25 0.5 0.5 BDR_L 10.0.8.113
+0.0 0.0 0.5 0.25 BDR_TL 10.0.8.114
+0.5 0.75 1.0 1.0 BDR_BR 10.0.8.115
+0.5 0.5 1.0 0.75 BDR_R 10.0.8.116
+0.5 0.25 1.0 0.5 BDR_R 10.0.8.117
+0.5 0.0 1.0 0.25 BDR_TR 10.0.8.118
Index: trunk/src/testing/app/JuxtaView/JuxtaUIServer.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/JuxtaUIServer.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/JuxtaUIServer.cpp	(revision 4)
@@ -0,0 +1,200 @@
+/******************************************************************************
+ * Program: JuxtaView for SAGE
+ * Module:  JuxtaSCUICommon.cpp - Part of JuxtaView's UI
+ * Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 9 September 2005
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "JuxtaUIServer.h"
+#include <string.h>
+
+JuxtaUIServer::JuxtaUIServer()
+{
+	server = new QUANTAnet_tcpServer_c();
+	client = NULL;
+	recmsg = NULL;
+}
+
+JuxtaUIServer::~JuxtaUIServer()
+{
+	if(client)
+		client->close();
+
+	if(server)
+		server->close();
+
+	if(client)
+		delete client;
+
+	if(server)
+		delete server;
+
+	if(recmsg)
+		delete [] recmsg;
+}
+
+bool JuxtaUIServer::Init(char* configfilename)
+{
+	FILE* fin = fopen(configfilename,"r");
+	if(!fin) {
+	  printf("return\n");
+		return false;
+	}
+
+
+	int port;
+	fscanf(fin,"%d\n",&port);
+
+	fprintf(stderr, "!!!****************SERVER PORT 1: %d\n ", port);
+	if( server->init(port) <  0)
+	{
+	  printf("!!!******************SERVER PORT 2: %d\n ", port);
+		server->close();
+		delete server;
+		server = NULL;
+		fclose(fin);
+		return false;
+	}
+
+    fprintf(stderr, "!!!****************SERVER PORT 3: %d\n ", port);
+	fclose(fin);
+	return true;
+}
+
+char* JuxtaUIServer::WaitForMessage()
+{
+	if(recmsg == NULL)
+		recmsg = new char[TRANSMISSION_SIZE];
+	memset(recmsg,0,TRANSMISSION_SIZE);
+	static int size = TRANSMISSION_SIZE;
+
+	if(client == NULL && server != NULL)
+	{
+		fprintf(stderr,"Waiting For Client To Connect.\n");
+		client = server->waitForNewConnection();
+		fprintf(stderr,"Ready For Messages.\n");
+	}
+
+	if(client)
+	{
+
+	  int re = client->read(recmsg,&size,QUANTAnet_tcpClient_c::NON_BLOCKING);
+
+	  // no data is read
+	  if (re == QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA) {
+	    strcpy(recmsg, JVRESEND);
+	    return recmsg;
+	  }
+
+	  // data is read
+	  else {
+	    return recmsg;
+	  }
+
+	  /*
+	  client->read(recmsg,&size,QUANTAnet_tcpClient_c::NON_BLOCKING);
+	  printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-%s\n", recmsg);
+	  return recmsg;
+	  */
+
+	}
+
+	return NULL;
+}
+
+
+void JuxtaUIServer::SendNormalizedExtents(float x, float y, float w, float h)
+{
+	int size;
+	if(client)
+	{
+		fprintf(stderr,"Sending normalized coords and dims:\n%f, %f\n%f x %f\n",x,y,w,h);
+		size = sizeof(float) * 4;
+		float array[4];
+		array[0] = x;
+		array[1] = y;
+		array[2] = w;
+		array[3] = h;
+		client->write((const char*)array,&size,QUANTAnet_tcpClient_c::BLOCKING);
+	}
+
+}
+
+void JuxtaUIServer::SendOverview(int w, int h,unsigned char* bmp)
+{
+	int size;
+	if(client)
+	{
+		fprintf(stderr,"Sending overview of size: %d x %d\n",w,h);
+		size = sizeof(int) * 2;
+		int array[2];
+		array[0] = w;
+		array[1] = h;
+		//send pixel dimensions first
+		client->write((const char*)array,&size,QUANTAnet_tcpClient_c::BLOCKING);
+		//send pixels next
+		size = w * h * 3;
+		client->write((const char*)bmp,&size,QUANTAnet_tcpClient_c::BLOCKING);
+
+	}
+
+}
+
+void JuxtaUIServer::GetNormalizedFreeTranslation(float* x, float* y)
+{
+	float array[2] = { 0.0 , 0.0 };
+	int size = sizeof(float) * 2;
+
+	if( client )
+	{
+		fprintf(stderr,"Reading normalized free translation from client!\n");
+		client->read((char*)array,&size,QUANTAnet_tcpClient_c::BLOCKING);
+
+
+	}
+
+	*x = array[0];
+	*y = array[1];
+}
+
Index: trunk/src/testing/app/JuxtaView/juxtauiserver.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtauiserver.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtauiserver.conf	(revision 4)
@@ -0,0 +1,1 @@
+5200
Index: trunk/src/testing/app/JuxtaView/RUN
===================================================================
--- trunk/src/testing/app/JuxtaView/RUN	(revision 4)
+++ trunk/src/testing/app/JuxtaView/RUN	(revision 4)
@@ -0,0 +1,1 @@
+mpirun -np 2 JuxtaView
Index: trunk/src/testing/app/JuxtaView/main.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/main.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/main.cpp	(revision 4)
@@ -0,0 +1,1207 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  main.cpp - main MPI control for JuxtaView
+  Authors: Nicholas Schwarz, schwarz@evl.uic.edu,
+           Arun Rao, arao@evl.uic.edu,
+           Luc Renambot, luc@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 9 September 2005
+
+   Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// for MPI
+#include "mpi.h"
+
+// for UI
+#include "JuxtaUIServer.h"
+
+// for communication with UI via QUANTA
+#include <QUANTA/QUANTAinit.hxx>
+#include <QUANTA/QUANTAnet_tcp_c.hxx>
+
+// for converting global image coordinates, in pixels, to
+// individual files and their respective extents
+#include "GlobalCoordinatesToFileMapper.h"
+
+// for reading tiff files
+#include <tiffio.h>
+
+// for SAGE
+#include <sail.h>
+#include <misc.h>
+
+// SAGE Stuff
+int winWidth, winHeight;
+sail sageInf; // sail object
+
+#define LEFT 0
+#define RIGHT 1
+#define UP 2
+#define DOWN 3
+#define FASTLEFT 4
+#define FASTRIGHT 5
+#define FASTUP 6
+#define FASTDOWN 7
+#define ZOOMOUT 8
+#define ZOOMIN 9
+#define QUIT 10
+#define EXTENTS 11
+#define OVERVIEW 12
+#define FREETRANS 13
+#define RESEND 14
+
+// windows border definitions
+#define DBDR_TBLR 0
+#define DBDR_TB 1
+#define DBDR_LR 2
+#define DBDR_TL 3
+#define DBDR_TR 4
+#define DBDR_BL 5
+#define DBDR_BR 6
+#define DBDR_T 7
+#define DBDR_B 8
+#define DBDR_L 9
+#define DBDR_R 10
+#define DBDR_N 11
+#define DBDR_TLR 12
+#define DBDR_BLR 13
+#define DBDR_TBL 14
+#define DBDR_TBR 15
+
+#include <time.h>
+
+
+/* data set information */
+typedef struct {
+  long origin_x;         // image origin, usually 0,0
+  long origin_y;         // image origin, usually 0,0
+  long image_width;      // image width
+  long image_height;     // image height
+  long start_x;          // start position
+  long start_y;          // start position
+  long pan_amount;       // number of pixels to pan
+  long fast_pan_amount;  // number of pixels to fast pan
+  long fetch_w;          // horizontal extent to fetch, i.e. window size
+  long fetch_h;          // vertical extent to fetch, i.e. window size
+  int samplerate;        // sample rate for overview file
+  char name[512];        // overview file name
+} description;
+
+
+/* extent within the global image in pixel coordinates and the command */
+typedef struct {
+  long x;
+  long y;
+  long w;
+  long h;
+  long command;
+  long zoom;
+  long border;
+} info;
+
+
+/* viewport in normalized coordinates */
+typedef struct {
+  float x_min;
+  float y_min;
+  float x_max;
+  float y_max;
+  long border;
+  char ip[16];
+} viewport;
+
+
+/* begin - read config file given file name and return array of viewport */
+viewport* read_config(const char* name) {
+
+  // number of nodes in addition to master
+  int num;
+
+  // border
+  char border[10];
+
+  // file pointer
+  FILE *fptr = NULL;
+
+  // attempt to open the configuration file.
+  if ((fptr = fopen(name, "r")) == NULL)
+    return NULL;
+
+  // read number of nodes
+  fscanf(fptr, "%d", &num);
+
+  // allocate space for node configuration
+  viewport* viewports = (viewport*) malloc(sizeof(viewport) * num);
+
+  // check if memory allocation succeded
+  if (viewports == NULL)
+    return NULL;
+
+  // Read configuration data
+  for (int i = 0 ; i < num ; i++)
+    {
+      // read viewports
+      fscanf(fptr, "%f", &viewports[i].x_min);
+      //printf("%f\n", viewports[i].x_min);
+      fscanf(fptr, "%f", &viewports[i].y_min);
+      //printf("%f\n", viewports[i].y_min);
+      fscanf(fptr, "%f", &viewports[i].x_max);
+      //printf("%f\n", viewports[i].x_max);
+      fscanf(fptr, "%f", &viewports[i].y_max);
+      //printf("%f\n", viewports[i].y_max);
+      fscanf(fptr, "%s", border);
+      //printf("%s\n\n", border);
+
+      // determine and set border type
+      if (!strcmp(border, "BDR_TBLR")) {
+	viewports[i].border = DBDR_TBLR;
+      }
+      else if (!strcmp(border, "BDR_TB")) {
+	viewports[i].border = DBDR_TB;
+      }
+      else if (!strcmp(border, "BDR_LR")) {
+	viewports[i].border = DBDR_LR;
+      }
+      else if (!strcmp(border, "BDR_TL")) {
+	viewports[i].border = DBDR_TL;
+      }
+      else if (!strcmp(border, "BDR_TR")) {
+	viewports[i].border = DBDR_TR;
+      }
+      else if (!strcmp(border, "BDR_BL")) {
+	viewports[i].border = DBDR_BL;
+      }
+      else if (!strcmp(border, "BDR_BR")) {
+	viewports[i].border = DBDR_BR;
+      }
+      else if (!strcmp(border, "BDR_T")) {
+	viewports[i].border = DBDR_T;
+      }
+      else if (!strcmp(border, "BDR_B")) {
+	viewports[i].border = DBDR_B;
+      }
+      else if (!strcmp(border, "BDR_L")) {
+	viewports[i].border = DBDR_L;
+      }
+      else if (!strcmp(border, "BDR_R")) {
+	viewports[i].border = DBDR_R;
+      }
+      else if (!strcmp(border, "BDR_N")) {
+	viewports[i].border = DBDR_N;
+      }
+      else if (!strcmp(border, "BDR_TLR")) {
+	viewports[i].border = DBDR_TLR;
+      }
+      else if (!strcmp(border, "BDR_BLR")) {
+	viewports[i].border = DBDR_BLR;
+      }
+      else if (!strcmp(border, "BDR_TBL")) {
+	viewports[i].border = DBDR_TBL;
+      }
+      else if (!strcmp(border, "BDR_TBR")) {
+	viewports[i].border = DBDR_TBR;
+      }
+      else {
+	viewports[i].border = DBDR_N;
+      }
+
+      fscanf(fptr, "%s", viewports[i].ip);
+      //printf("%s\n", viewports[i].ip);
+
+    }
+
+  // close file
+  fclose(fptr);
+
+  // return
+  return viewports;
+
+} /* end - read config file */
+
+
+/* begin - read data description file given file name */
+description read_data(const char* name) {
+
+  // data description
+  description data;
+
+  // file pointer
+  FILE *fptrd = NULL;
+
+  // attempt to open the configuration file.
+  if ((fptrd = fopen(name, "r")) == NULL) {
+    printf("Can not read data description file.\n");
+    exit(EXIT_FAILURE);
+  }
+
+  // read origin and extent
+  fscanf(fptrd, "%ld %ld %ld %ld", &data.origin_x, &data.origin_y,
+	 &data.image_width, &data.image_height);
+
+  // read starting position
+  fscanf(fptrd, "%ld %ld", &data.start_x, &data.start_y);
+
+  // read pan values
+  fscanf(fptrd, "%ld %ld", &data.pan_amount, &data.fast_pan_amount);
+
+  // width and height of data to fetch
+  fscanf(fptrd, "%ld %ld", &data.fetch_w, &data.fetch_h);
+
+  // overview file sample rate
+  fscanf(fptrd, "%d", &data.samplerate);
+
+  // overview file name
+  fscanf(fptrd, "%s", data.name);
+
+  // close file
+  fclose(fptrd);
+
+  // return true
+  return data;
+
+} /* end - read data description file */
+
+
+/* begin - add border to the top; called by add_border */
+void add_border_top(unsigned char* buffer, info extent) {
+
+  unsigned char r = 139;
+  unsigned char g = 161;
+  unsigned char b = 105;
+
+  for (long row = 0 ; row < 8 ; row++) {
+    for (long col = 0 ; col < (extent.w / extent.zoom) ; col++) {
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3)] = r;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 1] = g;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 2] = b;
+    }
+  }
+
+} /* end - add border to the top; called by add_border */
+
+
+/* begin - add border to the top; called by add_border */
+void add_border_bottom(unsigned char* buffer, info extent) {
+
+  unsigned char r = 139;
+  unsigned char g = 161;
+  unsigned char b = 105;
+
+  for (long row = (extent.h / extent.zoom) - 8 ;
+       row < (extent.h / extent.zoom) ;
+       row++) {
+    for (long col = 0 ; col < (extent.w / extent.zoom) ; col++) {
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3)] = r;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 1] = g;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 2] = b;
+    }
+  }
+
+} /* end - add border to the bottom; called by add_border */
+
+
+/* begin - add border to the left; called by add_border */
+void add_border_left(unsigned char* buffer, info extent) {
+
+  unsigned char r = 139;
+  unsigned char g = 161;
+  unsigned char b = 105;
+
+  for (long col = 0 ; col < 8 ; col++) {
+    for (long row = 0 ; row < (extent.h / extent.zoom) ; row++) {
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3)] = r;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 1] = g;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 2] = b;
+    }
+  }
+
+} /* end - add border to the left; called by add_border */
+
+
+/* begin - add border to the right; called by add_border */
+void add_border_right(unsigned char* buffer, info extent) {
+
+  unsigned char r = 139;
+  unsigned char g = 161;
+  unsigned char b = 105;
+
+  for (long col = (extent.w / extent.zoom) - 8 ;
+       col < (extent.w / extent.zoom) ;
+       col++) {
+    for (long row = 0 ; row < (extent.h / extent.zoom) ; row++) {
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3)] = r;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 1] = g;
+      buffer[row * 3 * (extent.w / extent.zoom) + (col * 3) + 2] = b;
+    }
+  }
+
+} /* end - add border to the right; called by add_border */
+
+
+/* begin - add border to the buffer */
+void add_border(unsigned char* buffer, info extent) {
+
+  switch(extent.border) {
+  case DBDR_TBLR:
+    add_border_top(buffer, extent);
+    add_border_bottom(buffer, extent);
+    add_border_left(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_TB:
+    add_border_top(buffer, extent);
+    add_border_bottom(buffer, extent);
+    break;
+  case DBDR_LR:
+    add_border_left(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_TL:
+    add_border_top(buffer, extent);
+    add_border_left(buffer, extent);
+    break;
+  case DBDR_TR:
+    add_border_top(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_BL:
+    add_border_bottom(buffer, extent);
+    add_border_left(buffer, extent);
+    break;
+  case DBDR_BR:
+    add_border_bottom(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_T:
+    add_border_top(buffer, extent);
+    break;
+  case DBDR_B:
+    add_border_bottom(buffer, extent);
+    break;
+  case DBDR_L:
+    add_border_left(buffer, extent);
+    break;
+  case DBDR_R:
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_N:
+    break;
+  case DBDR_TLR:
+    add_border_top(buffer, extent);
+    add_border_left(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_BLR:
+    add_border_bottom(buffer, extent);
+    add_border_left(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  case DBDR_TBL:
+    add_border_top(buffer, extent);
+    add_border_bottom(buffer, extent);
+    add_border_left(buffer, extent);
+    break;
+  case DBDR_TBR:
+    add_border_top(buffer, extent);
+    add_border_bottom(buffer, extent);
+    add_border_right(buffer, extent);
+    break;
+  }
+
+} /* end - add border to the buffer */
+
+
+/* begin - main */
+int main(int argc, char** argv) {
+
+  bool quit = false; // exit flag
+
+  info extent;  // extent that each node fetches
+
+  long zoom = 1;      // zoom out factor
+  long max_zoom = 7;  // max zoom out factor
+
+  int rank = 0;  // node rank
+  int size = 0;  // number of nodes
+  int frameRate = 5;
+
+  MPI_Datatype pinfo;  // info structure
+  MPI_Datatype ipinfo; // ip infor structure
+
+  // MPI Initialization
+  MPI_Init(&argc, &argv);
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  MPI_Comm_size(MPI_COMM_WORLD, &size);
+  MPI_Type_contiguous(7, MPI_LONG, &pinfo);
+  MPI_Type_contiguous(16, MPI_CHAR, &ipinfo);
+  MPI_Type_commit(&pinfo);
+  MPI_Type_commit(&ipinfo);
+
+  // Print some information about the program
+  printf("----------------------------------------------------------------\n");
+  printf("JuxtaView for SAGE - Node %d of %d\n", rank, size);
+  printf("9 September 2005\n");
+  printf("----------------------------------------------------------------\n");
+
+  // sync
+  MPI_Barrier(MPI_COMM_WORLD);
+
+  /* *********************************************************************** */
+  /* Begin - Master node                                                     */
+
+  if (rank == 0) {
+
+    /* Initialize QUANTA */
+    QUANTAinit();
+
+    /* Create a server for the UI */
+    JuxtaUIServer* server = new JuxtaUIServer();
+
+    /* Initialize server for UI */
+    if (!server -> Init(argv[4])) {
+      delete server;
+      printf("Can not create a UI server.\n");
+      return EXIT_FAILURE;
+    }
+
+    /* read viewports for each node */
+    viewport* viewports = read_config(argv[1]);
+    //cout << "********MASTER********** config " << argv[1] << endl;
+
+    /* check that viewports were read correctly */
+    if (viewports == NULL) {
+      printf("Can not read config file.\n");
+      return EXIT_FAILURE;
+    }
+
+    /* read data description file */
+    //description data = read_data("juxtadata.conf");
+    description data = read_data(argv[2]);
+    //cout << "********MASTER********** data " << argv[2]<< endl;
+
+    /* begin - read overview file */
+
+    //if the bitmap hasn't been read yet then read it!
+    //for now just read the whole tiff file
+    TIFF* tiffile = TIFFOpen(data.name, "r");
+
+    uint32 width = 1, height = 1;
+
+    if(tiffile)
+      {
+	//get the image width and height
+	TIFFGetField(tiffile, TIFFTAG_IMAGEWIDTH, &width);
+	TIFFGetField(tiffile, TIFFTAG_IMAGELENGTH, &height);
+      }
+
+    //get the pixels
+    int samplerate = data.samplerate;
+    int bmpW = width / samplerate;
+    int bmpH = height / samplerate;
+    if( bmpW == 0)
+      bmpW = 1;
+    if( bmpH == 0)
+      bmpH = 1;
+
+    unsigned char* bitmap = new unsigned char[bmpW * bmpH * 3];
+    fprintf(stderr,"Loading overview of size %d x %d\n",bmpW,bmpH);
+    memset(bitmap,0,bmpW * bmpH * 3);
+    if(tiffile)
+      {
+	char* scanline = (char*) _TIFFmalloc( TIFFScanlineSize(tiffile));
+
+	for( int row = 0; row < bmpH; row++)
+	  {
+	    TIFFReadScanline(tiffile,scanline,row * samplerate);
+	    for( int i = 0; i < bmpW; i++)
+	      {
+		memcpy(bitmap + (i * 3) + (row * 3 * bmpW),
+		       scanline + (samplerate * i * 3),
+		       3);
+	      }
+	  }
+
+	_TIFFfree(scanline);
+	TIFFClose(tiffile);
+      }
+
+    /* end - read overview file */
+
+    printf("Origin X: %ld\n", data.origin_x);
+    printf("Origin Y: %ld\n", data.origin_y);
+    printf("Image Width: %ld\n", data.image_width);
+    printf("Image Height: %ld\n", data.image_height);
+    printf("Start x: %ld\n", data.start_x);
+    printf("Start y: %ld\n", data.start_y);
+    printf("Pan amount: %ld\n", data.pan_amount);
+    printf("Fast pan amount: %d\n", data.fast_pan_amount);
+    printf("Fetch w: %ld\n", data.fetch_w);
+    printf("Fetch h: %ld\n", data.fetch_h);
+
+    /* extent to fetch */
+    long Xg = data.start_x;  // current x position in global image
+    long Yg = data.start_y;  // current y position in global image
+    long Wg = data.fetch_w;  // width of extent to fetch
+    long Hg = data.fetch_h;  // height of extent to fetch
+
+    for (int j = 0 ; j < size - 1 ; j++) {
+      MPI_Send(&(viewports[j].x_min), 1, MPI_FLOAT, j+1, 1, MPI_COMM_WORLD);
+    }
+    MPI_Barrier(MPI_COMM_WORLD);
+    for (int j = 0 ; j < size - 1 ; j++) {
+      MPI_Send(&(viewports[j].y_min), 1, MPI_FLOAT, j+1, 1, MPI_COMM_WORLD);
+    }
+    MPI_Barrier(MPI_COMM_WORLD);
+    for (int j = 0 ; j < size - 1 ; j++) {
+      MPI_Send(&(viewports[j].x_max), 1, MPI_FLOAT, j+1, 1, MPI_COMM_WORLD);
+    }
+    MPI_Barrier(MPI_COMM_WORLD);
+    for (int j = 0 ; j < size - 1 ; j++) {
+      MPI_Send(&(viewports[j].y_max), 1, MPI_FLOAT, j+1, 1, MPI_COMM_WORLD);
+    }
+    MPI_Barrier(MPI_COMM_WORLD);
+    for (int j = 0 ; j < size - 1 ; j++) {
+      MPI_Send(viewports[j].ip, 1, ipinfo, j+1, 1, MPI_COMM_WORLD);
+    }
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    // insert code here to show first frame before GUI starts
+
+    // calculate and send extent for each node
+    for (int i = 0 ; i < size - 1 ; i++) {
+      extent.x = ((long)(Wg * viewports[i].x_min)) + Xg;
+      extent.y = ((long)(Hg * viewports[i].y_min)) + Yg;
+      extent.w = (long)(Wg * (viewports[i].x_max - viewports[i].x_min));
+      extent.h = (long)(Hg * (viewports[i].y_max - viewports[i].y_min));
+      extent.zoom = zoom;
+      extent.border = viewports[i].border;
+      MPI_Send(&extent, 1, pinfo, i+1, 1, MPI_COMM_WORLD);
+    }
+
+    // synchronize
+    MPI_Barrier(MPI_COMM_WORLD);
+
+
+    //cout << "Master entering loop" << endl;
+
+    /* begin - event loop */
+    while (!quit) {
+
+      // block until incoming message from UI
+      char* msg = server -> WaitForMessage();
+
+      //printf("Before: xg %ld, yg %ld, wg %ld, hg %ld\n", Xg, Yg, Wg, Hg);
+
+      // pan left
+      if (!strcmp(msg, JVPAN_LEFT)) {
+	if (Xg - data.pan_amount >= data.origin_x) {
+	  Xg = Xg - data.pan_amount;
+	}
+	else {
+	  Xg = data.origin_x;
+	}
+	extent.command = LEFT;
+      }
+
+      // pan right
+      else if (!strcmp(msg, JVPAN_RIGHT)) {
+	if (Xg + Wg + data.pan_amount <
+	    data.origin_x + data.image_width) {
+	  Xg = Xg + data.pan_amount;
+	}
+	else {
+	  Xg = Xg + (data.origin_x + data.image_width) - (Xg + Wg) - 1;
+	}
+	extent.command = RIGHT;
+      }
+
+      // pan up
+      else if (!strcmp(msg, JVPAN_UP)) {
+	if (Yg - data.pan_amount >= data.origin_y) {
+	  Yg = Yg - data.pan_amount;
+	}
+	else {
+	  Yg = data.origin_y;
+	}
+	extent.command = UP;
+      }
+
+      // pan down
+      else if (!strcmp(msg, JVPAN_DOWN)) {
+	if (Yg + Hg + data.pan_amount <=
+	    data.origin_y + data.image_height) {
+	  Yg = Yg + data.pan_amount;
+	}
+	else {
+	  Yg = Yg + (data.origin_y + data.image_height) - (Yg + Hg) - 1;
+	}
+	extent.command = DOWN;
+      }
+
+      // fast pan left
+      else if(!strcmp(msg, JVFAST_PAN_LEFT)) {
+	if (Xg - data.fast_pan_amount >= data.origin_x) {
+	  Xg = Xg - data.fast_pan_amount;
+	}
+	else {
+	  Xg = data.origin_x;
+	}
+	extent.command = FASTLEFT;
+      }
+
+      // fast pan right
+      else if(!strcmp(msg, JVFAST_PAN_RIGHT)) {
+	if (Xg + Wg + data.fast_pan_amount <
+	    data.origin_x + data.image_width) {
+	  Xg = Xg + data.fast_pan_amount;
+	}
+	else {
+	  Xg = Xg + (data.origin_x + data.image_width) - (Xg + Wg) - 1;
+	}
+	extent.command = FASTRIGHT;
+      }
+
+      // fast pan up
+      else if(!strcmp(msg, JVFAST_PAN_UP)) {
+	if (Yg - data.fast_pan_amount >= data.origin_y) {
+	  Yg = Yg - data.fast_pan_amount;
+	}
+	else {
+	  Yg = data.origin_y;
+	}
+	extent.command = FASTUP;
+      }
+
+      // fast pan down
+      else if(!strcmp(msg, JVFAST_PAN_DOWN)) {
+	if (Yg + Hg + data.fast_pan_amount <=
+	    data.origin_y + data.image_height) {
+	  Yg = Yg + data.fast_pan_amount;
+	}
+	else {
+	  Yg = Yg + (data.origin_y + data.image_height) - (Yg + Hg) -1;
+	}
+	extent.command = FASTDOWN;
+      }
+
+      // zoom out
+      else if(!strcmp(msg, JVZOOM_OUT)) {
+	if (zoom + 1 <= max_zoom) {
+
+	  // calcualte new upper left corner and extents
+	  long center_x = Xg + (Wg / 2);
+	  long center_y = Yg + (Hg / 2);
+	  long tXg = center_x - ((Wg + data.fetch_w) / 2);
+	  long tYg = center_y - ((Hg + data.fetch_h) / 2);
+	  long tHg = Hg + data.fetch_h;
+	  long tWg = Wg + data.fetch_w;
+
+	  // check that zoomed out image is within the image size
+	  if (tWg <= data.image_width && tHg <= data.image_height) {
+
+	    // new x position is too far left
+	    if (tXg < data.origin_x) {
+	      tXg = data.origin_x;
+	    }
+
+	    // new y position is too far up
+	    if (tYg < data.origin_y) {
+	      tYg = data.origin_y;
+	    }
+
+	    // new x extent is too far right
+	    if (tXg + tWg >= data.origin_x + data.image_width) {
+	      long delta_x = (tXg + tWg) - (data.origin_x + data.image_width);
+	      tXg = tXg - delta_x - 1;
+	    }
+
+	    // new y extent is too far down
+	    if (tYg + tHg >= data.origin_y + data.image_height) {
+	      long delta_y = (tYg + tHg) - (data.origin_y + data.image_height);
+	      tYg = tYg - delta_y - 1;
+	    }
+
+	    // update everthing
+	    zoom++;
+	    Xg = tXg;
+	    Yg = tYg;
+	    Hg = tHg;
+	    Wg = tWg;
+
+	  }
+
+	}
+	extent.command = ZOOMOUT;
+      }
+
+      // zoom in
+      else if(!strcmp(msg, JVZOOM_IN)) {
+	if (zoom - 1 >= 1) {
+	  if ((Yg + Hg - data.fetch_h <= data.origin_y + data.image_height) &&
+	      (Xg + Wg - data.fetch_w <= data.origin_x + data.image_width)) {
+	    long center_x = Xg + (Wg / 2);
+	    long center_y = Yg + (Hg / 2);
+	    Xg = center_x - ((Wg - data.fetch_w) / 2);
+	    Yg = center_y - ((Hg - data.fetch_h) / 2);
+	    extent.command = ZOOMIN;
+	    zoom--;
+	    Hg -= data.fetch_h;
+	    Wg -= data.fetch_w;
+	  }
+	}
+	extent.command = ZOOMIN;
+      }
+
+      // free translation
+      else if (!strcmp(msg, JVTRANSLATE)) {
+
+	// normalized free translation coordinates
+	float nx = 0.0;
+	float ny = 0.0;
+
+	// get normalized free translation coordinates
+	server -> GetNormalizedFreeTranslation(&nx, &ny);
+
+	// convert normalized values to actual pixel coordinates
+	long tXg = (long) (nx * data.image_width);
+	long tYg = (long) (ny * data.image_height);
+
+	// set command
+	extent.command = FREETRANS;
+
+	// check left x
+	if (tXg < data.origin_x)
+	  Xg = data.origin_x;
+	else
+	  Xg = tXg;
+
+	// check top y
+	if (tYg < data.origin_y)
+	  Yg = data.origin_y;
+	else
+	  Yg = tYg;
+
+	// check right x
+	if (tXg + Wg >= data.origin_x + data.image_width)
+	  Xg = Xg + (data.origin_x + data.image_width) - (Xg + Wg) - 1;
+	else
+	  Xg = tXg;
+
+	// check bottom y
+        if (tYg + Hg >= data.origin_y + data.image_height)
+          Yg = Yg + (data.origin_y + data.image_height) - (Yg + Hg) - 1;
+	else
+	  Yg = tYg;
+
+	//cout << "Freetrans tXg: " << tXg << " tYg: " << tYg << endl;
+	//cout << "Freetrans Xg: " << Xg << " Yg: " << Yg << endl;
+	//cout << "End of freetrans" << endl;
+      }
+
+      // send normalized extent of displayed area
+      else if (!strcmp(msg, JVEXTENTS)) {
+	float nx = (float) Xg / (float) data.image_width;
+	float ny = (float) Yg / (float) data.image_height;
+	float nw = (float) Wg / (float) data.image_width;
+	float nh = (float) Hg / (float) data.image_height;
+
+	//cout << "MASTER: normalized extents nx: " << nx
+	//     << " ny: " << ny << " nw: " << nw << " nh: " << nh << endl;
+	server -> SendNormalizedExtents(nx, ny, nw, nh);
+	extent.command = EXTENTS;
+	//cout << "End of extents" << endl;
+      }
+
+      else if (!strcmp(msg, JVOVERVIEW)) {
+	server -> SendOverview(bmpW, bmpH, bitmap);
+	extent.command = OVERVIEW;
+      }
+
+      // quit
+      else if(!strcmp(msg, JVQUIT)) {
+	quit = true;
+	extent.command = QUIT;
+      }
+
+      // resend
+      else if(!strcmp(msg, JVRESEND)) {
+        extent.command = RESEND;
+      }
+
+      //printf("After: xg %d, yg %d, wg %d, hg %d\n", Xg, Yg, Wg, Hg);
+
+      //fprintf(logfile,"Message Returned: %s\n",msg);
+
+      // calculate and send extent for each node
+      for (int i = 0 ; i < size - 1 ; i++) {
+	extent.x = ((long)(Wg * viewports[i].x_min)) + Xg;
+	extent.y = ((long)(Hg * viewports[i].y_min)) + Yg;
+	extent.w = (long)(Wg * (viewports[i].x_max - viewports[i].x_min));
+	extent.h = (long)(Hg * (viewports[i].y_max - viewports[i].y_min));
+	extent.zoom = zoom;
+	extent.border = viewports[i].border;
+	MPI_Send(&extent, 1, pinfo, i+1, 1, MPI_COMM_WORLD);
+      }
+
+      // synchronize
+      MPI_Barrier(MPI_COMM_WORLD);
+
+      // free memory used by message from UI
+      //cout << "Master deleting message - begin" << endl;
+      //delete [] msg;
+      //cout << "Master deleting message - end" << endl;
+
+    } /* end - event loop */
+
+    // free memory used by viewport list
+    free(viewports);
+
+    // free memory used by overview
+    free(bitmap);
+
+  }
+
+  /* End - Master node                                                       */
+  /* *************************************************************************/
+
+  /* *********************************************************************** */
+  /* Begin - Slave node                                                      */
+
+  else {
+
+    // first time slave is run
+    bool virgin = true;
+
+    // MPI status variable
+    MPI_Status status;
+
+    // create GlobalCoordinatesToFileMapper instance
+    GlobalCoordinatesToFileMapper gmapper;
+
+    // initialize GlobalCoordinatesToFileMapper instance
+    // TODO: change this to command line argument!!
+    //gmapper.Initialize("juxtalayout.conf");
+    gmapper.Initialize(argv[3]);
+    //cout << "********SLAVE********** layout " << endl;
+
+    // big image buffer
+    unsigned char* pixelarray = NULL;
+
+    // zoom adjusted image buffer
+    unsigned char* buffer = NULL;
+
+    // viewport information
+    viewport view;
+
+    // get viewport information
+    MPI_Recv(&(view.x_min), 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &status);
+    MPI_Barrier(MPI_COMM_WORLD);
+    MPI_Recv(&(view.y_min), 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &status);
+    MPI_Barrier(MPI_COMM_WORLD);
+    MPI_Recv(&(view.x_max), 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &status);
+    MPI_Barrier(MPI_COMM_WORLD);
+    MPI_Recv(&(view.y_max), 1, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &status);
+    MPI_Barrier(MPI_COMM_WORLD);
+    MPI_Recv(view.ip, 1, ipinfo, 0, 1, MPI_COMM_WORLD, &status);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    /*
+    cout << "Rank: " << rank << " x_min: " << view.x_min << endl;
+    cout << "Rank: " << rank << " y_min: " << view.y_min << endl;
+    cout << "Rank: " << rank << " x_max: " << view.x_max << endl;
+    cout << "Rank: " << rank << " y_max: " << view.y_max << endl;
+    */
+
+
+    /* begin - event loop */
+    while(!quit) {
+
+      //fprintf(stderr, "Proc %d> Receiving\n", rank);
+
+      // receive command from master
+      MPI_Recv(&extent, 1, pinfo, 0, 1, MPI_COMM_WORLD, &status);
+      //cout << "Rank: " << rank << " V1" << endl;
+      if (virgin) {
+
+	// initialize SAGE
+
+	sailConfig scfg;
+	scfg.init("JuxtaView.conf");
+	scfg.setAppName("JuxtaView");
+	if (argc > 6)
+		scfg.nwID = atoi(argv[6]);
+	scfg.rank = rank - 1;
+
+	scfg.resX = (extent.w / extent.zoom);
+	scfg.resY = (extent.h / extent.zoom);
+
+	sageRect renderImageMap;
+	renderImageMap.left = view.x_min;
+	renderImageMap.right = view.x_max;
+	renderImageMap.bottom = 1.0 - view.y_max;
+	renderImageMap.top = 1.0 - view.y_min;
+
+	scfg.imageMap = renderImageMap;
+	scfg.pixFmt = PIXFMT_888;
+	//scfg.rowOrd = TOP_TO_BOTTOM;
+	scfg.rowOrd = TOP_TO_BOTTOM;
+
+	if (scfg.rank == 0)
+		scfg.master = true;
+	else
+		scfg.master = false;
+
+	sageInf.init(scfg);
+
+	if (argc > 7)
+		frameRate = atoi(argv[7]);
+
+	//cout << "Rank: " << rank << " V1.1" << endl;
+
+	// create zoom adjusted image buffer
+	if (buffer)
+		delete [] buffer;
+
+	buffer = (unsigned char*)sageInf.getBuffer();
+
+	//cout << "Rank: " << rank << " V1.2" << endl;
+
+	// no longer a virgin
+	virgin = false;
+      }
+
+      //cout << "Rank: " << rank << " V1.3" << endl;
+
+      // quit
+      if (extent.command == QUIT) {
+
+	// set quit flag
+	quit = true;
+
+	// synchronize
+	MPI_Barrier(MPI_COMM_WORLD);
+
+      }
+
+      // resend
+      else if (extent.command == RESEND) {
+        if (!virgin) {
+          // synchronize
+          MPI_Barrier(MPI_COMM_WORLD);
+			 /*
+			 useconds_t interval = (useconds_t)floor(1.0/frameRate*1000000.0);
+			 usleep(interval);
+          // swap buffer
+          sageInf.swapBuffer();
+			 buffer = (unsigned char *)sageInf.getBuffer();
+			 */
+        }
+      }
+
+      // get and display data
+      else {
+	//cout << "Rank: " << rank << " V2" << endl;
+	// print the current query for this node
+	//cout << "QueryExtent at node " << rank << " " << extent.x << " "
+	//     << extent.y << " " << extent.w << " " << extent.h << endl;
+
+	// create big image buffer
+	if (!pixelarray)
+	  pixelarray = new unsigned char[extent.w * extent.h * 3];
+
+	// set extent of data to fetch
+	gmapper.SetQueryExtent(extent.x, extent.y, extent.w, extent.h);
+
+	// make query - this actually makes the mapper calculate
+	// all the files this program should load
+	gmapper.Query();
+
+	// print the state of the mapper
+	//gmapper.PrintSelf(cout);
+
+	// number of columns and rows in the query result
+	long columnResult = 0;
+	long rowResult = 0;
+
+	// get the array of FileInfo and the number of rows and columns of
+	// the 2D array of FileInfo
+	FileInfo* files =
+	  gmapper.GetQueryFileInfoArray(&columnResult, &rowResult);
+
+	// print the number of columns and rows in the query result
+	//cout << "FileInfoArrayDimensions: " << columnResult << " "
+	//     << rowResult << endl;
+
+	// NOTE: THIS DOES NOT WORK. IT'S A MESS!!!
+	// ANOTHER NOTE: IT WORKS NOW, BUT VERY, VERY SLOWLY
+	// ////////////////////////////////////////////////////////////////////
+	// Begin - read from files
+
+	long localx = 0;
+	long localy = 0;
+	long localw = 0;
+	long localh = 0;
+	long globalw = extent.w;
+	long globalh = extent.h;
+
+	//cout << "Extent.w: " << extent.w << " Extent.h: "
+	//     << extent.h << endl;
+	//cout << "Rank: " << rank << " V3" << endl;
+
+	int array_index = 0;
+	int array_max = columnResult * rowResult;
+
+	//cout << "Rank: " << rank << " V4" << endl;
+
+	memset(pixelarray, 0, globalw * globalh * 3);
+
+	//cout << "Rank: " << rank << " V5" << endl;
+
+	for(long c = 0; array_index < array_max && c < globalw; ){
+	  for(long r = 0; array_index < array_max && r < globalh; ){
+
+	    TIFF* tiffile = NULL;
+	    tiffile = TIFFOpen(files[array_index].GetFileName(), "r");
+
+	    // if the tif exists
+	    if (tiffile != NULL) {
+
+	      //get the scanlines needed
+	      unsigned char *scanline =
+		(unsigned char *) _TIFFmalloc(TIFFScanlineSize(tiffile));
+
+	      files[array_index].GetExtent(&localx, &localy, &localw, &localh);
+	      //cout << "Rank: " << rank
+	      //	   << "file: " << files[array_index].GetFileName()
+	      //	   << "localx: " << localx
+	      //	   << "localy: " << localy
+	      //	   << "localw: " << localw
+	      //	   << "localh: " << localh
+	      //	   << endl;
+
+	      for (int l = 0,  k = localy ; k < localy + (localh) ; k++, l++)
+		{
+		  //cout << "Rank: " << rank << " row: " << k << endl;
+		  TIFFReadScanline(tiffile,scanline,k);
+		  //for(int j = 0; j < localw; j++){
+		  memcpy(&(pixelarray[ (r + l) * globalw *3 + c * 3]),
+			 &(scanline[localx * 3]),localw * 3);
+		}
+
+	      _TIFFfree(scanline);
+	      TIFFClose(tiffile);
+
+	    }
+
+	    array_index++;
+	    r += localh;
+	  }
+	  c += localw;
+	}
+
+	//cout << "Rank: " << rank << " V6" << endl;
+
+	// End - read from files
+	// ////////////////////////////////////////////////////////////////////
+
+	// clear the zoom adjusted image buffer
+	memset(buffer,
+	       0,
+	       (extent.w / extent.zoom) * (extent.h / extent.zoom) * 3);
+
+	// adjust for zoom by skipping pixels
+	// NOTE: Zooming is from the upper left, not the center, I know
+	// that's bad, so some day I'll fix it.
+	for (long r = 0, rz = 0 ; r < extent.h ; r += extent.zoom, rz++) {
+	  for (long c = 0, cz = 0 ; c < extent.w ; c += extent.zoom, cz++) {
+	    buffer[rz * 3 * (extent.w / extent.zoom) + (cz * 3)] =
+	      pixelarray[r * 3 * extent.w + (c * 3)];
+	    buffer[rz * 3 * (extent.w / extent.zoom) + (cz * 3) + 1] =
+	      pixelarray[r * 3 * extent.w + (c * 3) + 1];
+	    buffer[rz * 3 * (extent.w / extent.zoom) + (cz * 3) + 2] =
+	      pixelarray[r * 3 * extent.w + (c * 3) + 2];
+	  }
+	}
+
+	// delete big image buffer
+	//cout << "slave deleting pixelarray - begin" << endl;
+	delete [] pixelarray;
+	//cout << "slave deleting pixelarray - end" << endl;
+	pixelarray = NULL;
+
+	// add borders
+	add_border(buffer, extent);
+
+	// synchronize
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// swap buffer
+	sageInf.swapBuffer();
+	buffer = (unsigned char *)sageInf.getBuffer();
+
+      }
+
+    } /* end - event loop */
+
+    if (rank == 1)
+      sageInf.shutdown();
+
+    // delete zoom adjusted image buffer
+    delete [] buffer;
+    buffer = NULL;
+
+  }
+
+  /* End - Slave node                                                        */
+  /* *************************************************************************/
+
+  // finalize
+  MPI_Finalize();
+
+  // exit
+  return EXIT_SUCCESS;
+
+} /* end - main */
Index: trunk/src/testing/app/JuxtaView/juxtaconfig.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtaconfig.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtaconfig.conf	(revision 4)
@@ -0,0 +1,9 @@
+8
+0.0 0.75 0.5 1.0 BDR_BL 10.0.8.111
+0.0 0.5 0.5 0.75 BDR_L 10.0.8.112
+0.0 0.25 0.5 0.5 BDR_L 10.0.8.113
+0.0 0.0 0.5 0.25 BDR_TL 10.0.8.114
+0.5 0.75 1.0 1.0 BDR_BR 10.0.8.115
+0.5 0.5 1.0 0.75 BDR_R 10.0.8.116
+0.5 0.25 1.0 0.5 BDR_R 10.0.8.117
+0.5 0.0 1.0 0.25 BDR_TR 10.0.8.118
Index: trunk/src/testing/app/JuxtaView/JuxtaUIServer.h
===================================================================
--- trunk/src/testing/app/JuxtaView/JuxtaUIServer.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/JuxtaUIServer.h	(revision 4)
@@ -0,0 +1,74 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaUIServer.h - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#ifndef JUXTAUI_SERVER_H
+#define JUXTAUI_SERVER_H
+
+#include <QUANTA/QUANTAinit.hxx>
+#include <QUANTA/QUANTAnet_tcp_c.hxx>
+#include "JuxtaSCUICommon.h"
+
+
+class JuxtaUIServer
+{
+private:
+	QUANTAnet_tcpServer_c* server;
+	QUANTAnet_tcpClient_c* client;
+	char* recmsg;
+public:
+	JuxtaUIServer();
+	~JuxtaUIServer();
+	bool Init(char*); //pass the config file name
+	char* WaitForMessage();
+	void SendNormalizedExtents( float x, float y, float w, float h);
+	void SendOverview(int w, int h, unsigned char* bmp);
+	void GetNormalizedFreeTranslation( float* x, float* y);
+};
+
+#endif
+
Index: trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago-noUI
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago-noUI	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago-noUI	(revision 4)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+mpirun -machinefile machine.yorda.dat -np 9 JuxtaView juxtaconfig-chicago.conf juxtadata.conf juxtalayout.conf ui5201.conf Chicago 1 30 &
+
Index: trunk/src/testing/app/JuxtaView/bin/juxtaconfig-chicago.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/juxtaconfig-chicago.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/juxtaconfig-chicago.conf	(revision 4)
@@ -0,0 +1,9 @@
+8
+0.0 0.75 0.5 1.0 BDR_N 192.168.81.122
+0.0 0.5 0.5 0.75 BDR_N 192.168.81.123
+0.0 0.25 0.5 0.5 BDR_N 192.168.81.124
+0.0 0.0 0.5 0.25 BDR_N 192.168.81.125
+0.5 0.75 1.0 1.0 BDR_N 192.168.81.126
+0.5 0.5 1.0 0.75 BDR_N 192.168.81.127
+0.5 0.25 1.0 0.5 BDR_N 192.168.81.128
+0.5 0.0 1.0 0.25 BDR_N 192.168.81.129
Index: trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/Juxta-Chicago	(revision 4)
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+mpirun -machinefile machine.yorda.dat -np 9 JuxtaView juxtaconfig-chicago.conf juxtadata.conf juxtalayout.conf ui5201.conf Chicago 1 30 &
+
+sleep 10
+
+cd ../UI
+./JuxtaSCUI ui5201-yorda.conf &
+
Index: trunk/src/testing/app/JuxtaView/bin/fsManager.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/fsManager.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/fsManager.conf	(revision 4)
@@ -0,0 +1,5 @@
+fsManager 	yorda 10.0.8.120 131.193.78.203
+systemPort	30002
+uiPort		30001
+trackPort	30003
+conManager	10.0.8.120 15556	
Index: trunk/src/testing/app/JuxtaView/bin/machine.yorda.dat
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/machine.yorda.dat	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/machine.yorda.dat	(revision 4)
@@ -0,0 +1,8 @@
+yorda2-10
+yorda3-10
+yorda4-10
+yorda5-10
+yorda6-10
+yorda7-10
+yorda8-10
+yorda9-10
Index: trunk/src/testing/app/JuxtaView/bin/juxtadata.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/juxtadata.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/juxtadata.conf	(revision 4)
@@ -0,0 +1,6 @@
+0 0 300000 335000
+0 0
+200 5000
+6500 3200
+1
+/data/evl/JuxtaView2.0/usgs/chicago/chicago-overview.tif
Index: trunk/src/testing/app/JuxtaView/bin/ui5201.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/ui5201.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/ui5201.conf	(revision 4)
@@ -0,0 +1,1 @@
+5201
Index: trunk/src/testing/app/JuxtaView/bin/juxtaview.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/juxtaview.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/juxtaview.conf	(revision 4)
@@ -0,0 +1,12 @@
+masterIP 10.0.8.122
+nwID     1
+msgPort  23000
+syncPort 13000
+nodeNum  8
+appID    0
+pixelBlockSize 64 64
+winWidth 4800
+winHeight 2400
+winX 100
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/app/JuxtaView/bin/juxtalayout.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/bin/juxtalayout.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/bin/juxtalayout.conf	(revision 4)
@@ -0,0 +1,4023 @@
+300000 335000
+60 67
+5000 5000
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm425005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm590215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm590200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890005.tif
Index: trunk/src/testing/app/JuxtaView/juxtadata.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtadata.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtadata.conf	(revision 4)
@@ -0,0 +1,6 @@
+0 0 300000 335000
+0 0
+200 5000
+2000 2000
+1
+/data/evl/JuxtaView2.0/usgs/chicago/chicago-overview.tif
Index: trunk/src/testing/app/JuxtaView/FileInfo.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/FileInfo.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/FileInfo.cpp	(revision 4)
@@ -0,0 +1,221 @@
+/******************************************************************************
+ * Program: GlobalCoordinatesToFileMapper
+ * Module:  FileInfo.cpp
+ * Authors: Nicholas Schwarz, schwarz@evl.uic.edu
+ * Date:    21 September 2004
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+// Include header file for this class
+#include "FileInfo.h"
+
+
+//-----------------------------------------------------------------------------
+FileInfo::FileInfo()
+{
+  this -> Dimensions[0] = 0;
+  this -> Dimensions[1] = 0;
+  this -> FileName = NULL;
+  this -> Extent[0] = 0;
+  this -> Extent[1] = 0;
+  this -> Extent[2] = 0;
+  this -> Extent[3] = 0;
+  this -> LocalPosition[0] = 0;
+  this -> LocalPosition[1] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::GetDimensions(long* w, long* h)
+{
+  *w = this -> Dimensions[0];
+  *h = this -> Dimensions[1];
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::GetExtent(long* x, long* y,
+			 long* w, long* h)
+{
+  *x = this -> Extent[0];
+  *y = this -> Extent[1];
+  *w = this -> Extent[2];
+  *h = this -> Extent[3];
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+const char* FileInfo::GetFileName()
+{
+  return this -> FileName;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::GetLocalPosition(long* col, long* row)
+{
+  *col = this -> LocalPosition[0];
+  *row = this -> LocalPosition[1];
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::PrintSelf(ostream& os)
+{
+
+  os << "File Info Start --------------------------------------------\n";
+
+  os << "Dimensions: "
+     << this -> Dimensions[0] << " "
+     << this -> Dimensions[1] << "\n";
+
+  if (this -> FileName != NULL)
+    os << "File Name: " << this -> FileName << "\n";
+  else
+    os << "File Name: null\n";
+
+  os << "Extent: "
+     << this -> Extent[0] << " "
+     << this -> Extent[1] << " "
+     << this -> Extent[2] << " "
+     << this -> Extent[3] << "\n";
+
+  os << "Local Position: "
+     << this -> LocalPosition[0] << " "
+     << this -> LocalPosition[1] << "\n";
+
+  os << "File Info End ----------------------------------------------" << endl;
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetDimensions(long w, long h)
+{
+  this -> Dimensions[0] = w;
+  this -> Dimensions[1] = h;
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void  FileInfo::SetExtent(long x, long y,
+			  long w, long h)
+{
+  this -> Extent[0] = x;
+  this -> Extent[1] = y;
+  this -> Extent[2] = w;
+  this -> Extent[3] = h;
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetExtentX(long x)
+{
+  this -> Extent[0] = x;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetExtentY(long y)
+{
+  this -> Extent[1] = y;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetExtentW(long w)
+{
+  this -> Extent[2] = w;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetExtentH(long h)
+{
+  this -> Extent[3] = h;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetFileName(const char* name)
+{
+  if (this -> FileName != NULL)
+    {
+      delete [] this -> FileName;
+    }
+
+  if (name != NULL)
+    {
+      this -> FileName = new char[strlen(name) + 1];
+      strcpy(this -> FileName, name);
+    }
+  else {
+    this -> FileName = NULL;
+  }
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+void FileInfo::SetLocalPosition(long col, long row)
+{
+  this -> LocalPosition[0] = col;
+  this -> LocalPosition[1] = row;
+
+  return;
+}
+
+
+//-----------------------------------------------------------------------------
+FileInfo::~FileInfo()
+{
+  if (this -> FileName != NULL)
+    {
+      delete [] this -> FileName;
+    }
+}
Index: trunk/src/testing/app/JuxtaView/UI/Makefile.mac
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Makefile.mac	(revision 4)
@@ -0,0 +1,18 @@
+QUANTA_DIR=/usr/local
+#WX_DIR=/usr/local/wxMac-2.5.3
+WX_DIR=/usr/local/bin
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `$(WX_DIR)/wx-config --cflags` -DMAC_OSX
+LDFLAGS=-L$(QUANTA_DIR)/lib -lquanta_32 `$(WX_DIR)/wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o
+	$(CC) $(LDFLAGS) -o JuxtaSCUI main.o JuxtaSCUI.o
+	/Developer/Tools/Rez -t APPL -o JuxtaSCUI mac.r
+
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf	(revision 4)
@@ -0,0 +1,1 @@
+localhost : 5200
Index: trunk/src/testing/app/JuxtaView/UI/Makefile
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Makefile	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Makefile	(revision 4)
@@ -0,0 +1,15 @@
+QUANTA_DIR=/usr/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags --unicode=no`
+LDFLAGS=-L$(QUANTA_DIR)/lib64 -lquanta_64 `wx-config --libs --unicode=no`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o Overview.o
+
+Overview.o: Overview.cpp
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UI/JuxtaSCUICommon.h
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/JuxtaSCUICommon.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/JuxtaSCUICommon.h	(revision 4)
@@ -0,0 +1,69 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUICommon.h - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#ifndef JUXTASCUI_COMMON_H
+#define JUXTASCUI_COMMON_H
+
+#define TRANSMISSION_SIZE 10	//send 10 bytes at a time
+
+//Messages To Transmit
+#define JVPAN_LEFT "jvleft"
+#define JVPAN_RIGHT "jvright"
+#define JVPAN_UP "jvup"
+#define JVPAN_DOWN "jvdown"
+#define JVFAST_PAN_LEFT "jvfleft"
+#define JVFAST_PAN_RIGHT "jvfright"
+#define JVFAST_PAN_UP "jvfup"
+#define JVFAST_PAN_DOWN "jvfdown"
+#define JVZOOM_OUT "jvzoomout"
+#define JVZOOM_IN "jvzoomin"
+#define JVEXTENTS "jvextent"
+#define JVOVERVIEW "jvoverv"
+#define JVTRANSLATE "jvfreepan"
+#define JVQUIT "jvquit"
+
+
+#endif
+
Index: trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico1
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico1	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico1	(revision 4)
@@ -0,0 +1,1 @@
+192.168.81.110 : 5201
Index: trunk/src/testing/app/JuxtaView/UI/ui5200-yorda.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5200-yorda.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5200-yorda.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.120 : 5200
Index: trunk/src/testing/app/JuxtaView/UI/ui5201-yorda.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5201-yorda.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5201-yorda.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.120 : 5201
Index: trunk/src/testing/app/JuxtaView/UI/ui5202-yorda.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5202-yorda.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5202-yorda.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.120 : 5202
Index: trunk/src/testing/app/JuxtaView/UI/Skins/default.jsk
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Skins/default.jsk	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Skins/default.jsk	(revision 4)
@@ -0,0 +1,21 @@
+# juxtaview skin file format
+# <background image>
+# for each function: <function> <raised button image> <depressed button image> <position e.g. (0,0)>
+# order of buttons: 
+# pan up, down, left, right
+# fast pan up, fast pan down, fast pan left, fast pan right
+# zoom in, out
+# close
+#
+./Skins/default/jux_back.jpg
+pan_up ./Skins/default/pan_up.jpg ./Skins/default/pan_up_down.jpg (160,80)
+pan_down ./Skins/default/pan_down.jpg ./Skins/default/pan_down_down.jpg (160,260)
+pan_left ./Skins/default/pan_left.jpg ./Skins/default/pan_left_down.jpg (80,160)
+pan_right ./Skins/default/pan_right.jpg ./Skins/default/pan_right_down.jpg (260,160)
+fast_pan_up ./Skins/default/fast_pan_up.jpg ./Skins/default/fast_pan_up_down.jpg (140,0)
+fast_pan_down ./Skins/default/fast_pan_down.jpg ./Skins/default/fast_pan_down_down.jpg (140,320)
+fast_pan_left ./Skins/default/fast_pan_left.jpg ./Skins/default/fast_pan_left_down.jpg (0,140)
+fast_pan_right ./Skins/default/fast_pan_right.jpg ./Skins/default/fast_pan_right_down.jpg (320,140)
+zoom_in ./Skins/default/zoom_in.jpg ./Skins/default/zoom_in_down.jpg (160,140)
+zoom_out ./Skins/default/zoom_out.jpg ./Skins/default/zoom_out_down.jpg (140,200)
+close ./Skins/default/close_down.jpg ./Skins/default/close.jpg (340,340)
Index: trunk/src/testing/app/JuxtaView/UI/Overview.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Overview.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Overview.cpp	(revision 4)
@@ -0,0 +1,243 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  Overview.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#include "JuxtaSCUI.h"
+
+
+JuxtaOverviewFrame::JuxtaOverviewFrame(wxWindow* parent, int id, const wxString& title,
+					const wxPoint& pos, const wxSize& size,
+					long style)
+			:wxFrame(parent,id,title,pos,size,style)
+{
+	data.imgArray = NULL;
+	img = NULL;
+	bmptodraw = NULL;
+	penColor.Set(255,255,255);
+
+}
+
+BEGIN_EVENT_TABLE( JuxtaOverviewFrame, wxFrame )
+	EVT_PAINT( JuxtaOverviewFrame::OnPaint )
+	EVT_RIGHT_UP( JuxtaOverviewFrame::OnDropDownMenu )
+	EVT_MENU( ID_ChangePenColor, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_MENU( ID_ZoomOutFromMouse, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_MENU( ID_ZoomInFromMouse, JuxtaOverviewFrame::OnMenuSelection )
+	EVT_LEFT_UP( JuxtaOverviewFrame::OnLeftMouseUp )
+END_EVENT_TABLE()
+
+JuxtaOverviewFrame::~JuxtaOverviewFrame()
+{
+
+
+}
+
+void JuxtaOverviewFrame::SetImage(int w, int h, unsigned char* pixels)
+{
+	SetSize(w,h);
+
+	//get the data
+	data.w = w;
+	data.h = h;
+	if(data.imgArray)
+		delete [] data.imgArray;
+	data.imgArray = pixels;
+
+	//make an image out of it
+	if(img)
+		delete img;
+
+	img = new wxImage(data.w,data.h,data.imgArray,TRUE);
+
+	if(bmptodraw)
+		delete bmptodraw;
+
+	bmptodraw = new wxBitmap(img);
+
+	Refresh();
+
+
+}
+
+void JuxtaOverviewFrame::SetExtentRectangle(float nx, float ny, float nw, float nh)
+{
+	data.normX = nx;
+	data.normY = ny;
+	data.normW = nw;
+	data.normH = nh;
+}
+
+void JuxtaOverviewFrame::OnPaint(wxPaintEvent& event)
+{
+	pdc = new wxPaintDC(this);
+	wxPen pen(penColor,5,wxDOT_DASH);
+	pdc->SetPen(pen);
+	pdc->BeginDrawing();
+		if(bmptodraw)
+		{
+			fprintf(stderr,"Bitmap valid! Drawing\n");
+			pdc->DrawBitmap((*bmptodraw),0,0,TRUE);
+			//draw some lines with the extents
+		//	pdc->GetPen().SetJoin(wxJOIN_ROUND);
+		//	pdc->GetPen().SetWidth(10);
+		//	pdc->GetPen().SetCap(wxCAP_PROJECTING);
+		//	pdc->GetPen().SetColour(255,255,255);
+		//	pdc->GetPen().SetStyle(wxCROSSDIAG_HATCH);
+
+			int x0,y0,x1,y1;
+			x0 = (int)(data.normX * data.w);
+			y0 = (int)(data.normY * data.h);
+			x1 = (int)(x0 + (data.normW * data.w));
+			y1 = (int)(y0 + (data.normH * data.h));
+
+			pdc->DrawLine( x0,y0,x1,y0);
+			pdc->DrawLine( x0,y0,x0,y1);
+			pdc->DrawLine( x1,y0,x1,y1);
+			pdc->DrawLine( x0,y1,x1,y1);
+
+		}
+	pdc->EndDrawing();
+
+	delete pdc;
+}
+
+
+char OverviewMenuLabels[OVERVIEW_MENU_ITEM_COUNT][OVERVIEW_MENU_LABEL_LENGTH] =
+	{ "Change Border Color", "Zoom Out","Zoom In" };
+
+void JuxtaOverviewFrame::OnDropDownMenu(wxMouseEvent& event)
+{
+	//make the drop down menu
+	wxMenu *menu = new wxMenu();
+	for ( int i = 0; i < OVERVIEW_MENU_ITEM_COUNT; i++)
+	{
+		menu->Append( i, wxString(OverviewMenuLabels[i]));
+	}
+
+	PopupMenu(menu,event.GetX(),event.GetY());
+}
+
+void JuxtaOverviewFrame::OnMenuSelection(wxCommandEvent& event)
+{
+	wxColourDialog *dlg;
+	switch( event.GetId())
+	{
+	case ID_ChangePenColor:
+		fprintf(stderr,"Opening Color Dialog!\n");
+		//change the color of the pen
+		dlg = new wxColourDialog(this);
+		if( dlg->ShowModal() == wxID_OK)
+		{
+			unsigned char red, green, blue;
+			red = dlg->GetColourData().GetColour().Red();
+			green = dlg->GetColourData().GetColour().Green();
+			blue = dlg->GetColourData().GetColour().Blue();
+
+			penColor.Set(red,green,blue);
+			Refresh();
+		}
+
+		dlg->Destroy();
+		break;
+	case ID_ZoomOutFromMouse:
+		if(gMainFrame)
+		{
+			gMainFrame->PassEvent(JVZOOM_OUT);
+			gMainFrame->GetExtents();
+			Refresh();
+		}
+		break;
+	case ID_ZoomInFromMouse:
+		if(gMainFrame)
+		{
+			gMainFrame->PassEvent(JVZOOM_IN);
+			gMainFrame->GetExtents();
+			Refresh();
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+
+void JuxtaOverviewFrame::OnLeftMouseUp(wxMouseEvent& event)
+{
+	//figure out what normalized coordinates to send to the UI server...
+	float coords[2] = { 0.0, 0.0 };
+	fprintf(stderr,"Left mouse up at %d, %d\n",event.GetX(),event.GetY());
+	coords[0] = ((float)event.GetX() / (float)data.w) - (data.normW / 2.0);
+	coords[1] = ((float)event.GetY() / (float)data.h) - (data.normH / 2.0);
+
+	if( coords[0] + data.normW > 1 )
+	{
+		coords[0] += 1 - ( coords[0] + data.normW );
+	}
+	else if( coords[0] < 0 )
+	{
+		coords[0] = 0;
+	}
+
+	if( coords[1] + data.normH > 1 )
+	{
+		coords[1] += 1 - ( coords[1] + data.normH );
+	}
+	else if( coords[1] < 0 )
+	{
+		coords[1] = 0;
+	}
+
+	fprintf(stderr,"Passing normalized coords %f, %f to server\n",coords[0],coords[1]);
+	if( gMainFrame)
+	{
+		gMainFrame->PassEvent(JVTRANSLATE);
+		gMainFrame->PassBuffer((void*)coords,sizeof(float) * 2);
+
+		gMainFrame->GetExtents();
+	}
+
+	Refresh();
+
+}
+
Index: trunk/src/testing/app/JuxtaView/UI/Makefile.amd64
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Makefile.amd64	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Makefile.amd64	(revision 4)
@@ -0,0 +1,15 @@
+QUANTA_DIR=/usr/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags`
+LDFLAGS=-L$(QUANTA_DIR)/lib64 -lquanta_64 `wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o Overview.o
+
+Overview.o: Overview.cpp
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.yorda
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.yorda	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.yorda	(revision 4)
@@ -0,0 +1,1 @@
+131.193.48.163 : 5200
Index: trunk/src/testing/app/JuxtaView/UI/ui5200-nico.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5200-nico.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5200-nico.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.110 : 5200
Index: trunk/src/testing/app/JuxtaView/UI/ui5201-nico.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5201-nico.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5201-nico.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.110 : 5201
Index: trunk/src/testing/app/JuxtaView/UI/ui5202-nico.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/ui5202-nico.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/ui5202-nico.conf	(revision 4)
@@ -0,0 +1,1 @@
+10.0.8.110 : 5202
Index: trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.cpp	(revision 4)
@@ -0,0 +1,514 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUI.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#include "JuxtaSCUI.h"
+
+void SkipComments(FILE* fin,char commentFlag);
+#define COMMENT_FLAG '#'
+
+JuxtaSCUIFrame::JuxtaSCUIFrame(bool ov, char* skinfilename,wxWindow* parent, int id, const wxString& title,
+			   const wxPoint& pos, const wxSize& size, long style)
+			   :wxFrame(parent,id,title,pos,size,style)
+{
+	QUANTAinit();
+	client = NULL;
+
+
+	//---------setup the ui
+	wxImage* img;
+	wxBitmapButton* bmpbtn;
+	wxBitmap* bmp;
+	wxPanel* panel;
+	char buffer[100];
+	char background[100];
+	char upfile[100];
+	char downfile[100];
+	int xpos,ypos;
+
+	gApp->SetTopWindow(this);
+
+	panel = new wxPanel(this,-1);
+
+	//background
+	wxInitAllImageHandlers();
+	FILE* skinfile = NULL;
+
+	if(skinfilename == NULL)
+		skinfile = fopen("Skins/default.jsk","r");
+	else
+		skinfile = fopen(skinfilename,"r");
+
+	if(skinfile == NULL)
+		return;
+
+	SkipComments(skinfile,COMMENT_FLAG);
+
+	//get the background filename
+	fscanf(skinfile,"%s\n",background);
+	img = new wxImage(wxCSTRINGCAST(background));
+	bmp = new wxBitmap((*img));
+	statbmp = new wxStaticBitmap(panel,20,(*bmp),wxPoint(0,0));
+#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS_)
+	statbmp->Disable();	//to make sure the button pushes go to the buttons, not the background image
+#endif
+
+	//get the pan up info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanUp,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan down info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanDown,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan left info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanLeft,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the pan right info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_PanRight,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//get the fast pan up info
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanUp,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan down button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanDown,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan left button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanLeft,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the fast pan right button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_FastPanRight,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the zoom in button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_ZoomIn,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the zoom out button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_ZoomOut,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	//load up the Quit button
+	SkipComments(skinfile,COMMENT_FLAG);
+	fscanf(skinfile,"%s %s %s (%d,%d)\n",buffer,upfile,downfile,&xpos,&ypos);
+	img = new wxImage(upfile);
+	bmpbtn = new wxBitmapButton(panel,ID_Quit,(*img),wxPoint(xpos,ypos),
+					wxSize(img->GetWidth(),img->GetHeight()),wxBORDER_NONE);
+	img = new wxImage(downfile);
+	bmpbtn->SetBitmapSelected((*img));
+	bmpbtn->SetToolTip(buffer);
+
+	fclose(skinfile);
+
+	overviewframe = NULL;
+	showoverview = ov;
+
+}
+
+
+void JuxtaSCUIFrame::Show()
+{
+	if(overviewframe && showoverview)
+		overviewframe->Show();
+
+	wxFrame::Show();
+}
+
+
+BEGIN_EVENT_TABLE( JuxtaSCUIFrame, wxFrame)
+	EVT_BUTTON( ID_PanUp, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanDown, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanLeft, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_PanRight, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanUp, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanDown, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanLeft, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_FastPanRight, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_ZoomIn, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_ZoomOut, JuxtaSCUIFrame::OnEvent)
+	EVT_BUTTON( ID_Quit, JuxtaSCUIFrame::OnEvent)
+END_EVENT_TABLE()
+
+//------------------------------------------
+JuxtaSCUIFrame::~JuxtaSCUIFrame()
+{
+
+	if(client)
+	{
+		PassEvent(JVQUIT);
+		client->close();
+		delete client;
+	}
+
+}
+
+
+//------------------------------------------
+void JuxtaSCUIFrame::Init(char* configfilename)
+{
+	FILE* fin = fopen(configfilename,"r");
+	if(!fin)
+		return;
+
+	char ip[32];
+	int port;
+	memset(ip,0,32);
+
+	fscanf(fin,"%s : %d\n",ip,&port);
+
+	client = new QUANTAnet_tcpClient_c();
+	if( client->connectToServer(ip,port) < 0)
+	{
+		client->close();
+		delete client;
+		client = NULL;
+#if DEBUG
+		wxMessageBox("Failed To Connect To Server.\nMake sure juxtauiclient.conf file has correct server ip and port number.\nCorrect format is \"server ip\" : \"port number\"");
+#endif
+	}
+	else
+	{
+		//make sure the user didn't disable the overview
+		if(showoverview)
+		{
+			fprintf(stderr,"Attempting to load overview\n");
+			//ask for the overview!!!!
+			overviewframe = new JuxtaOverviewFrame(gApp->GetTopWindow(),
+							-1,"Overview",
+							wxPoint(wxWindow::GetSize().GetWidth(),0),
+							wxSize(100,200),
+							wxMINIMIZE_BOX | wxFRAME_NO_TASKBAR | wxRESIZE_BORDER);
+			overviewframe->Layout();
+			overviewframe->Show();
+
+			GetOverview();
+			GetExtents();
+		}
+		else
+		{
+			fprintf(stderr,"Not attempting to make overview\n");
+			overviewframe = new JuxtaOverviewFrame(0,-1,"",wxPoint(0,0),wxSize(0,0),wxSIMPLE_BORDER);
+			overviewframe->Layout();
+			overviewframe->Show();
+		}
+
+		fflush(stderr);
+
+	}
+
+	fclose(fin);
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::OnEvent(wxCommandEvent& event)
+{
+
+	//disable all buttons but quit
+	//here's the tree
+	//	this
+	//	|_______panel
+	//		|________All the buttons!!!!!!
+
+//	this->GetChildren().GetFirst()->GetData()->Disable();
+
+	switch(event.GetId())
+	{
+	case ID_FastPanLeft:
+		PassEvent(JVFAST_PAN_LEFT);
+		break;
+	case ID_FastPanRight:
+	    	PassEvent(JVFAST_PAN_RIGHT);
+		break;
+	case ID_FastPanUp:
+		PassEvent(JVFAST_PAN_UP);
+		break;
+	case ID_FastPanDown:
+		PassEvent(JVFAST_PAN_DOWN);
+		break;
+	case ID_PanLeft:
+		PassEvent(JVPAN_LEFT);
+		break;
+	case ID_PanRight:
+		PassEvent(JVPAN_RIGHT);
+		break;
+	case ID_PanUp:
+		PassEvent(JVPAN_UP);
+		break;
+	case ID_PanDown:
+		PassEvent(JVPAN_DOWN);
+		break;
+	case ID_ZoomIn:
+		PassEvent(JVZOOM_IN);
+		break;
+	case ID_ZoomOut:
+		PassEvent(JVZOOM_OUT);
+		break;
+	case ID_Quit:
+		PassEvent(JVQUIT);
+		break;
+	default:
+		break;
+	}	//end switch
+
+	//ask for the extent if it's not quit
+	if( event.GetId() != ID_Quit && overviewframe && showoverview )
+	{
+		GetExtents();
+		if(overviewframe)
+			overviewframe->Refresh();
+	}
+
+	Refresh();
+
+//	this->GetChildren().GetFirst()->GetData()->Enable();
+
+}
+//------------------------------------------
+void JuxtaSCUIFrame::PassEvent(char* strEvent)
+{
+#if DEBUG
+	fprintf(stderr,"passing event %s\n",strEvent);
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int size = TRANSMISSION_SIZE;
+
+	clientMutex.Lock();
+		memset(sendBuffer,0,TRANSMISSION_SIZE);
+		strcpy(sendBuffer,strEvent);
+
+		if(client)
+		{
+			client->write(sendBuffer,&size, QUANTAnet_tcpClient_c::BLOCKING);
+		}
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::PassBuffer(void* buffer,int size)
+{
+	clientMutex.Lock();
+		if(client)
+		{
+			client->write((const char*)buffer,&size,QUANTAnet_tcpClient_c::BLOCKING);
+		}
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+void JuxtaSCUIFrame::GetExtents()
+{
+#if DEBUG
+	fprintf(stderr,"Getting extents for overview\n");
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int sendsize = TRANSMISSION_SIZE;
+	static int readsize = sizeof(float) * 4;
+
+	memset(sendBuffer,0,TRANSMISSION_SIZE);
+	clientMutex.Lock();
+		strcpy(sendBuffer,JVEXTENTS);
+
+		float readarray[4];
+		if( client )
+		{
+			client->write(sendBuffer,&sendsize,QUANTAnet_tcpClient_c::BLOCKING);
+			//get four floats
+			client->read((char*)readarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+			if(overviewframe)
+				overviewframe->SetExtentRectangle(readarray[0],readarray[1],readarray[2],readarray[3]);
+
+#if DEBUG
+		fprintf(stderr,"floats recieved: %f, %f, %f, %f\n",readarray[0],readarray[1],readarray[2],readarray[3]);
+#endif
+		}
+	clientMutex.Unlock();
+
+
+
+}
+
+void JuxtaSCUIFrame::GetOverview()
+{
+#if DEBUG
+	fprintf(stderr,"Getting overview image\n");
+#endif
+	//pass event to server
+	static char sendBuffer[TRANSMISSION_SIZE];
+	static int sendsize = TRANSMISSION_SIZE;
+	static int readsize;
+
+	memset(sendBuffer,0,TRANSMISSION_SIZE);
+
+	clientMutex.Lock();
+		strcpy(sendBuffer,JVOVERVIEW);
+
+		if(client)
+		{
+			//ask for the overview
+			client->write(sendBuffer,&sendsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			//get two ints
+			int dimarray[2];
+			readsize = sizeof(int) * 2;
+			client->read((char*)dimarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			//get pixels
+			readsize = dimarray[0] * dimarray[1] * 3;
+			unsigned char* img = new unsigned char[readsize];
+			client->read((char*)img,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+
+			if(overviewframe)
+				overviewframe->SetImage(dimarray[0],dimarray[1],img);
+
+#if DEBUG
+		fprintf(stderr,"Got overview of dims %d x %d\n",dimarray[0],dimarray[1]);
+#endif
+
+		}
+
+	clientMutex.Unlock();
+
+}
+
+//------------------------------------------
+
+void SkipComments(FILE* fin,char commentFlag)
+{
+	char c;
+	c = fgetc(fin);
+	bool skipline;
+	if( c == commentFlag)
+	{
+		skipline = true;
+		while(skipline)
+		{
+			while( c != '\n' && !feof(fin))
+				c = fgetc(fin);
+
+			if(feof(fin))
+				return;
+
+			long position = ftell(fin);
+			c = fgetc(fin);
+			if(c != commentFlag)
+			{
+				skipline = false;
+				fseek(fin,position,0);
+			}
+		}
+	}
+	else
+	{
+		fseek(fin, ftell(fin) - 1, 0);
+	}
+}
Index: trunk/src/testing/app/JuxtaView/UI/Makefile.32
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/Makefile.32	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/Makefile.32	(revision 4)
@@ -0,0 +1,14 @@
+QUANTA_DIR=/home/arun/local
+CXXFLAGS=-Wno-deprecated -I$(QUANTA_DIR)/include `wx-config --cflags`
+LDFLAGS=-L$(QUANTA_DIR)/lib -lquanta_32 `wx-config --libs`
+CXX=g++
+CC=$(CXX)
+
+JuxtaSCUI: JuxtaSCUI.o main.o
+
+JuxtaSCUI.o: JuxtaSCUI.cpp
+main.o: main.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaSCUI
+
Index: trunk/src/testing/app/JuxtaView/UI/mac.r
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/mac.r	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/mac.r	(revision 4)
@@ -0,0 +1,13 @@
+data 'MBAR' (128) {
+	$"0001 0080"                                          /* ... */
+};
+
+data 'MENU' (128, "Apple") {
+	$"0080 0000 0000 0000 0000 FFFF FFFB 0114"            /* .........ÿÿÿû.. */
+	$"0A41 626F 7574 2046 4C54 4B00 0000 0001"            /* ÂAbout FLTK..... */
+	$"2D00 0000 0000"                                     /* -..... */
+};
+
+data 'carb' (0) {
+};
+
Index: trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/juxtauiclient.conf.nico	(revision 4)
@@ -0,0 +1,1 @@
+192.168.81.110 : 5200
Index: trunk/src/testing/app/JuxtaView/UI/main.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/main.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/main.cpp	(revision 4)
@@ -0,0 +1,92 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  main.cpp - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#include "JuxtaSCUI.h"
+#include <wx/wx.h>
+#include <wx/frame.h>
+
+JuxtaSCUIFrame* gMainFrame = NULL;
+wxApp* gApp = NULL;
+
+class JuxtaViewSCUIApp : public wxApp
+{
+public:
+    bool OnInit();
+	int OnExit();
+};
+
+IMPLEMENT_APP(JuxtaViewSCUIApp)
+
+
+bool JuxtaViewSCUIApp::OnInit()
+{
+	bool overview = true;
+
+	gApp = (wxApp*) this;
+	char* skinfile = NULL;
+	/*
+	if( argc > 1 )
+		skinfile = argv[1];
+	*/
+#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS_)
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(405,430));
+#elif defined(MAC_OSX)
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(400,420));
+#else
+	JuxtaSCUIFrame*  mainFrame = new JuxtaSCUIFrame(overview,skinfile,0,-1,"JuxtaView SC",wxPoint(0,0),wxSize(400,400));
+#endif
+	mainFrame->Init(wxApp::argv[1]);
+	mainFrame->Layout();
+	mainFrame->Show();
+
+	gMainFrame = mainFrame;
+
+	return true;
+}
+
+int JuxtaViewSCUIApp::OnExit()
+{
+	return 0;
+}
Index: trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.h
===================================================================
--- trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/UI/JuxtaSCUI.h	(revision 4)
@@ -0,0 +1,164 @@
+/*=============================================================================
+
+  Program: JuxtaView for SAGE
+  Module:  JuxtaSCUI.h - Part of JuxtaView's UI
+  Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 28 October 2004
+
+  Copyright (c) 2005 Electronic Visualization Laboratory,
+                     University of Illinois at Chicago
+
+  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Direct questions, comments, etc. to schwarz@evl.uic.edu or
+  http://www.evl.uic.edu/cavern/forum/
+
+=============================================================================*/
+
+#ifndef JUXTASCUI_H
+#define JUXTASCUI_H
+
+#include <wx/wx.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <QUANTA/QUANTAinit.hxx>
+#include <QUANTA/QUANTAnet_tcp_c.hxx>
+#include <QUANTA/QUANTAnet_datapack_c.hxx>
+
+#include <wx/frame.h>
+#include <iostream>
+using namespace std;
+
+#include <wx/panel.h>
+#include <wx/button.h>
+#include <wx/image.h>	//for loading in images
+#include <wx/bitmap.h>	//for drawing images
+#include <wx/bmpbuttn.h>	//for placing images on buttons...deprecaited method
+#include <wx/statbmp.h>		//new header for drawing images...
+
+#include "JuxtaSCUICommon.h"
+#define DEBUG 1
+//list ID's for buttons
+enum
+{
+	ID_PanLeft = 1000,
+	ID_PanRight,
+	ID_PanDown,
+	ID_PanUp,
+	ID_FastPanLeft,
+	ID_FastPanRight,
+	ID_FastPanDown,
+	ID_FastPanUp,
+	ID_ZoomOut,
+	ID_ZoomIn,
+	ID_Quit
+};
+
+struct SOverview
+{
+	unsigned char* imgArray;
+	int w;
+	int h;
+	float normX;
+	float normY;
+	float normW;
+	float normH;
+
+};
+
+#include <wx/dcclient.h>
+#include <wx/pen.h>
+#include <wx/colordlg.h>
+
+#define OVERVIEW_MENU_ITEM_COUNT 3
+#define OVERVIEW_MENU_LABEL_LENGTH 21
+enum{
+	ID_ChangePenColor = 0,
+	ID_ZoomOutFromMouse,
+	ID_ZoomInFromMouse
+};
+
+class JuxtaOverviewFrame : public wxFrame
+{
+private:
+	SOverview data;
+	wxImage* img;
+	wxBitmap* bmptodraw;
+	wxPaintDC* pdc;
+	wxColour penColor;
+public:
+	JuxtaOverviewFrame( wxWindow* parent, int id, const wxString& title,
+				const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize,
+				long style=wxDEFAULT_FRAME_STYLE);
+	~JuxtaOverviewFrame();
+	void SetImage(int w, int h, unsigned char* pixels);
+	void SetExtentRectangle(float nx, float ny, float nw, float nh);
+	void OnPaint(wxPaintEvent& event);
+	void OnDropDownMenu(wxMouseEvent& event);
+	void OnMenuSelection(wxCommandEvent& event);
+	void OnLeftMouseUp(wxMouseEvent& event);
+
+	DECLARE_EVENT_TABLE();
+};
+
+//-------------------------------------------
+class JuxtaSCUIFrame : public wxFrame
+{
+private:
+	QUANTAnet_tcpClient_c *client;
+	wxStaticBitmap* statbmp;
+	JuxtaOverviewFrame* overviewframe;
+	bool showoverview;
+	wxMutex clientMutex;
+public:
+	JuxtaSCUIFrame( bool ov, char* skinfilename, wxWindow* parent, int id, const wxString& title,
+					const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize,
+					long style=wxDEFAULT_FRAME_STYLE);
+
+	~JuxtaSCUIFrame();
+	void Init(char* );	//pass config filename
+	void OnEvent(wxCommandEvent& event);
+	void GetExtents();
+	void GetOverview();
+	virtual void Show();
+	void PassEvent(char*);
+	void PassBuffer(void*,int);
+
+	DECLARE_EVENT_TABLE();
+};
+
+extern JuxtaSCUIFrame *gMainFrame;
+extern wxApp* gApp;
+
+#endif
Index: trunk/src/testing/app/JuxtaView/Makefile
===================================================================
--- trunk/src/testing/app/JuxtaView/Makefile	(revision 4)
+++ trunk/src/testing/app/JuxtaView/Makefile	(revision 4)
@@ -0,0 +1,25 @@
+include ../../config.mk
+
+CXXFLAGS= -Wno-deprecated  -fPIC -O3 -I../../include -I/opt/mpich/include  $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(QUANTA_LIB) $(GLEW_LIB) -L../../lib -lsail -ltiff -L/opt/mpich/ch-p4/lib64 -lmpich
+CC=$(COMPILER)
+
+default: JuxtaView
+
+install: JuxtaView
+	cp JuxtaView bin
+
+JuxtaView: JuxtaUIServer.o FileInfo.o GlobalCoordinatesToFileMapper.o main.cpp Makefile
+	$(CXX) $(CXXFLAGS) -o JuxtaView main.cpp JuxtaUIServer.o GlobalCoordinatesToFileMapper.o FileInfo.o $(LIBS)
+
+UIServer: JuxtaUIServer.o servermain.o Makefile
+	g++ -o JuxtaUIServer JuxtaUIServer.o servermain.o -L$(QUANTA_DIR)/lib64 -ltiff -lquanta_64 -lpthread
+
+JuxtaUIServer.o: JuxtaUIServer.cpp
+servermain.o: servermain.cpp
+FileInfo.o: FileInfo.cpp
+GlobalCoordinatesToFileMapper.o: GlobalCoordinatesToFileMapper.cpp
+
+clean:
+	rm -rf *.o *~ JuxtaView
+
Index: trunk/src/testing/app/JuxtaView/juxtalayout.conf
===================================================================
--- trunk/src/testing/app/JuxtaView/juxtalayout.conf	(revision 4)
+++ trunk/src/testing/app/JuxtaView/juxtalayout.conf	(revision 4)
@@ -0,0 +1,4023 @@
+300000 335000
+60 67
+5000 5000
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm005770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm005470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm005005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm020770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm020470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm020005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm035770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm035470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm035005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm050770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm050470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol017/16tdm050005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm065770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm065470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm065005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm080770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm080470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm080005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm095770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm095470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm095005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm110770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm110470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm110005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm125770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm125470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm125005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol011/16tdm140770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol013/16tdm140470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol018/16tdm140005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm155200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm155005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm170200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm170005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm185200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm185005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm200200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm200005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm215200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm215005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm230200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm230005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm245365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol002/16tdm245200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm245005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm260200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm260005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm275200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol005/16tdm275005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm290200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm290005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm305200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm305005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320890.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320875.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320860.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320845.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320830.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320815.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320800.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320785.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320770.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320755.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm320200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm320005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335905.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm335530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol003/16tdm335200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm335005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350995.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350980.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350965.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350950.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350935.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350920.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350740.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350725.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350710.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350695.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm350200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm350005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm365200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm365005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380680.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380665.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380650.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380635.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm380200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm380005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm395200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm395005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410620.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410605.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm410200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm410005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm425200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm425020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol006/16tdm425005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440590.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440575.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440560.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440545.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440530.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm440200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm440005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455515.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455500.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455485.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm455200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm455005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470470.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470455.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470440.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470425.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm470200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm470005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485410.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485395.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm485200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm485005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500380.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500365.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500350.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500335.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500320.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500305.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm500200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm500005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515290.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm515200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm515005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530275.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530260.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530245.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm530200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm530005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm545200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm545005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm560200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol007/16tdm560005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575230.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm575200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm575005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm590215.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/16tdm590200.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590185.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590170.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590155.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm590005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm605005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm620005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm635005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm650005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665140.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665125.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm665005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm680005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm695005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/16tdm710005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm725005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm740005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm755005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm770005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm785005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm800005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm815005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm830005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm845005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm860005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm875005.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol004/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol008/nodata.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890110.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890095.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890080.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890065.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890050.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890035.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890020.tif
+/data/evl/JuxtaView2.0/usgs/chicago/vol009/16tdm890005.tif
Index: trunk/src/testing/app/JuxtaView/JuxtaSCUICommon.h
===================================================================
--- trunk/src/testing/app/JuxtaView/JuxtaSCUICommon.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/JuxtaSCUICommon.h	(revision 4)
@@ -0,0 +1,69 @@
+/******************************************************************************
+ * Program: JuxtaView for SAGE
+ * Module:  JuxtaSCUICommon.h - Part of JuxtaView's UI
+ * Authors: Arun Rao, arao@evl.uic.edu,
+           Ratko Jagodic, rjagodic@evl.uic.edu,
+           Nicholas Schwarz, schwarz@evl.uic.edu,
+           et al.
+  Date:    30 September 2004
+  Modified: 9 September 2005
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#ifndef JUXTASCUI_COMMON_H
+#define JUXTASCUI_COMMON_H
+
+#define TRANSMISSION_SIZE 10	//send 10 bytes at a time
+
+//Messages To Transmit
+#define JVPAN_LEFT "jvleft"
+#define JVPAN_RIGHT "jvright"
+#define JVPAN_UP "jvup"
+#define JVPAN_DOWN "jvdown"
+#define JVFAST_PAN_LEFT "jvfleft"
+#define JVFAST_PAN_RIGHT "jvfright"
+#define JVFAST_PAN_UP "jvfup"
+#define JVFAST_PAN_DOWN "jvfdown"
+#define JVZOOM_OUT "jvzoomout"
+#define JVZOOM_IN "jvzoomin"
+#define JVEXTENTS "jvextent"
+#define JVOVERVIEW "jvoverv"
+#define JVTRANSLATE "jvfreepan"
+#define JVQUIT "jvquit"
+#define JVRESEND "jvresend"
+
+
+#endif
Index: trunk/src/testing/app/JuxtaView/FileInfo.h
===================================================================
--- trunk/src/testing/app/JuxtaView/FileInfo.h	(revision 4)
+++ trunk/src/testing/app/JuxtaView/FileInfo.h	(revision 4)
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * Program: GlobalCoordinatesToFileMapper
+ * Module:  FileInfo.h
+ * Authors: Nicholas Schwarz, schwarz@evl.uic.edu
+ * Date:    21 September 2004
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// .NAME FileInfo
+// .SECTION Description
+// FileInfo is a class used to pass data concerning a file's usage. The extent
+// does not refer to the extent of the file in relation to the global space
+// (although it could (it could refer to any extent depending on the context))
+// but to the extent of the file that is of interest.
+
+
+#ifndef FILE_INFO_H
+#define FILE_INFO_H
+
+
+#include <ostream.h>
+#include <stddef.h>
+#include <string.h>
+
+
+class FileInfo {
+
+ public:
+
+  // Description:
+  // Constructor
+  FileInfo();
+
+  // Description:
+  // Get the width and height of the file in its coordinates, usually pixels.
+  void GetDimensions(long* w, long* h);
+
+  // Description:
+  // Get the extent of the file in its coordinates, usually pixels.
+  void GetExtent(long* x, long* y,
+		 long* w, long* h);
+
+  // Description:
+  // Get the file name.
+  const char* GetFileName();
+
+  // Description:
+  // Get the local column and row that the file resides in.
+  void GetLocalPosition(long* col, long* row);
+
+  // Description:
+  // Print itself
+  void PrintSelf(ostream& os);
+
+  // Set the width and height of the file in its coordinates, usually pixels.
+  void SetDimensions(long w, long h);
+
+  // Set the extent of the file in its coordinates, usually pixels.
+  void SetExtent(long x, long y,
+		 long w, long h);
+
+  // Set the height of the extent in the file's coordinates, usually pixels.
+  void SetExtentH(long h);
+
+  // Set the width of the extent in the file's coordinates, usually pixels.
+  void SetExtentW(long w);
+
+  // Set the starting x position of the extent in the file's coordinates,
+  // usually pixels. The upper left corner is (0, 0).
+  void SetExtentX(long x);
+
+  // Set the starting y position of the extent in the file's coordinates,
+  // usually pixels. The upper left corner is (0, 0).
+  void SetExtentY(long y);
+
+  // Set the file name.
+  void SetFileName(const char*);
+
+  // Set the column and row of the file's local position.
+  void SetLocalPosition(long col, long row);
+
+  // Description:
+  // Destructor
+  ~FileInfo();
+
+
+ private:
+
+  // File's dimensions in its coordinate system, usually in pixels.
+  long Dimensions[2];
+
+  // The extent of the file that should be used, given as starting x, y, and
+  // width and height of the extent in the file's coordinate system, usually
+  // in pixels.
+  long Extent[4];
+
+  // File name.
+  char* FileName;
+
+  // The local column and row that the file resides in.
+  long LocalPosition[2];
+
+};
+
+
+#endif
Index: trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.cpp
===================================================================
--- trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.cpp	(revision 4)
+++ trunk/src/testing/app/JuxtaView/GlobalCoordinatesToFileMapper.cpp	(revision 4)
@@ -0,0 +1,761 @@
+/******************************************************************************
+ * Program: GlobalCoordinatesToFileMapper
+ * Module:  GlobalCoordinatesToFileMapper.cpp
+ * Authors: Nicholas Schwarz, schwarz@evl.uic.edu
+ * Date:    21 September 2004
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to schwarz@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+// Include header file for this class
+#include "GlobalCoordinatesToFileMapper.h"
+
+
+//-----------------------------------------------------------------------------
+GlobalCoordinatesToFileMapper::GlobalCoordinatesToFileMapper()
+{
+
+  // Initialize global image description to NULL.
+  this -> Description = NULL;
+
+  // Initialize file coordinate dimensions to 0 by 0.
+  this -> FileCoordinateDimensions[0] = 0;
+  this -> FileCoordinateDimensions[1] = 0;
+
+  // Initialize global coordinate dimensions to 0 by 0.
+  this -> GlobalCoordinateDimensions[0] = 0;
+  this -> GlobalCoordinateDimensions[1] = 0;
+
+  // Initalize global file layour array to NULL.
+  this -> GlobalFileLayoutArray = NULL;
+
+  // Initialize global file layout dimensions to 0.
+  this -> GlobalFileLayoutDimensions[0] = 0;
+  this -> GlobalFileLayoutDimensions[1] = 0;
+
+  // Initialize the initialized flag to false.
+  this -> Initialized = false;
+
+  // Initialize the query extent.
+  this -> QueryExtent[0] = 0;
+  this -> QueryExtent[1] = 0;
+  this -> QueryExtent[2] = 0;
+  this -> QueryExtent[3] = 0;
+
+  // Initialize the query file info array to NULL.
+  this -> QueryFileInfoArray = NULL;
+
+  // Initialize the query file info array dimensions to 0 by 0.
+  this -> QueryFileInfoDimensions[0] = 0;
+  this -> QueryFileInfoDimensions[1] = 0;
+
+}
+
+
+//-----------------------------------------------------------------------------
+const char* GlobalCoordinatesToFileMapper::GetDescription()
+{
+
+  // Return pointer to global image description.
+  return this -> Description;
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetFileCoordinateDimensionH()
+{
+
+  // Return FileCoordinateDimensionH
+  return this -> FileCoordinateDimensions[1];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetFileCoordinateDimensionW()
+{
+
+  // Return FileCoordinateDimensionW
+  return this -> FileCoordinateDimensions[0];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetGlobalCoordinateDimensionH()
+{
+
+  // Return GlobalCoordinateDimensionH
+  return this -> GlobalCoordinateDimensions[1];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetGlobalCoordinateDimensionW()
+{
+
+  // Return GlobalCoordinateDimensionW
+  return this -> GlobalCoordinateDimensions[0];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetGlobalCoordinates(const char* name,
+							 long* x,
+							 long* y,
+							 long* w,
+							 long* h)
+{
+
+  // Check if instance is initialized
+  if (this -> Initialized == false)
+    {
+      return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_NOT_INITIALIZED;
+    }
+
+  // Loop through the global file layout array.
+  for (long c = 0, p = 0 ; c < GlobalFileLayoutDimensions[0] ; c++)
+    {
+      for (long r = 0 ; r < GlobalFileLayoutDimensions[1] ; r++, p++)
+	{
+	  // Check for given file.
+	  if (strcmp(this -> GlobalFileLayoutArray[p], name) == 0)
+	    {
+	      *x = this -> FileCoordinateDimensions[0] * c;
+	      *y = this -> FileCoordinateDimensions[1] * r;
+	      *w = this -> FileCoordinateDimensions[0];
+	      *h = this -> FileCoordinateDimensions[1];
+	      return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
+	    }
+	}
+    }
+
+  // Return error is the file does not exist in the mapper.
+  return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_FILE;
+
+}
+
+
+//-----------------------------------------------------------------------------
+char** GlobalCoordinatesToFileMapper::GetGlobalFileLayoutArray(long* cols,
+							       long* rows)
+{
+
+  // GlobalFileLayoutDimensions
+  *cols = this -> GlobalFileLayoutDimensions[0];
+  *rows = this -> GlobalFileLayoutDimensions[1];
+
+  // Return pointer to the global file layout array
+  return this -> GlobalFileLayoutArray;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::GetGlobalFileLayoutDimensions(long* cols,
+								  long* rows)
+{
+
+  // GlobalFileLayoutDimensions
+  *cols = this -> GlobalFileLayoutDimensions[0];
+  *rows = this -> GlobalFileLayoutDimensions[1];
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetQueryExtentH()
+{
+
+  // Return QueryExtentH
+  return this -> QueryExtent[3];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetQueryExtentW()
+{
+
+  // Return QueryExtentW
+  return this -> QueryExtent[2];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetQueryExtentX()
+{
+
+  // Return QueryExtentH
+  return this -> QueryExtent[0];
+
+}
+
+
+//-----------------------------------------------------------------------------
+long GlobalCoordinatesToFileMapper::GetQueryExtentY()
+{
+
+  // Return QueryExtentH
+  return this -> QueryExtent[1];
+
+}
+
+
+//-----------------------------------------------------------------------------
+FileInfo* GlobalCoordinatesToFileMapper::GetQueryFileInfoArray(long* cols,
+							       long* rows)
+{
+
+  // QueryFileInfoArray dimensions
+  *cols = this -> QueryFileInfoDimensions[0];
+  *rows = this -> QueryFileInfoDimensions[1];
+
+  // Return QueryFileInfoArray
+  return this -> QueryFileInfoArray;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::GetQueryFileInfoDimensions(long* cols,
+							       long* rows)
+{
+
+  // QueryFileInfoArray dimensions
+  *cols = this -> QueryFileInfoDimensions[0];
+  *rows = this -> QueryFileInfoDimensions[1];
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+int GlobalCoordinatesToFileMapper::Initialize(const char* name)
+{
+
+  // Try to open file for reading.
+  ifstream file(name);
+
+  // Check if file is open.
+  if (!file.is_open())
+    {
+      return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_FILE;
+    }
+
+  // Read GlobalCoordinateDimensions, GlobalFileLayoutDimensions, and
+  // FileCoordinateDimensions, respectively.
+  file >> this -> GlobalCoordinateDimensions[0]
+       >> this -> GlobalCoordinateDimensions[1]
+       >> this -> GlobalFileLayoutDimensions[0]
+       >> this -> GlobalFileLayoutDimensions[1]
+       >> this -> FileCoordinateDimensions[0]
+       >> this -> FileCoordinateDimensions[1];
+
+  // Allocate storage for the GlobalFileLayoutArray
+  this -> GlobalFileLayoutArray =
+    new char*[GlobalFileLayoutDimensions[0] * GlobalFileLayoutDimensions[1]];
+
+  // Read each file in the global image in order. Entries in the file are
+  // column by column.
+  for (long i = 0 ;
+       i < GlobalFileLayoutDimensions[0] * GlobalFileLayoutDimensions[1] ;
+       i++)
+    {
+      this -> GlobalFileLayoutArray[i] = new char[100];
+      file >> this -> GlobalFileLayoutArray[i];
+    }
+
+  // Close file
+  file.close();
+
+  // Set initialized to true
+  this -> Initialized = true;
+
+  // Return successfully
+  return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
+
+}
+
+
+//-----------------------------------------------------------------------------
+bool GlobalCoordinatesToFileMapper::IsInitialized()
+{
+
+  // Return Initialized
+  return this -> Initialized;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::PrintSelf(ostream& os)
+{
+
+  os << "GlobalCoordinatesToFileMapper - Begin PrintSelf ------------------\n";
+
+  if (this -> Description != NULL)
+    os << "  Description: " << this -> Description << "\n";
+  else
+    os << "  Description: null\n";
+
+  os << "  File Coordinate Dimensions: "
+     << this -> FileCoordinateDimensions[0] << " "
+     << this -> FileCoordinateDimensions[1] << "\n";
+
+  os << "  Global Coordinate Dimensions: "
+     << this -> GlobalCoordinateDimensions[0] << " "
+     << this -> GlobalCoordinateDimensions[1] << "\n";
+
+  os << "  Global File Layout Array:\n";
+  for (long i = 0 ;
+       i < this -> GlobalFileLayoutDimensions[0] *
+	 GlobalFileLayoutDimensions[1] ;
+       i++)
+    {
+      if (this -> GlobalFileLayoutArray != NULL)
+	{
+	  if (this -> GlobalFileLayoutArray[i] != NULL)
+	    {
+	      os << "    " << this -> GlobalFileLayoutArray[i] << "\n";
+	    }
+	  else
+	    {
+	      os << "    null" << endl;
+	    }
+	}
+    }
+
+  os << "  Global File Layout Dimensions: "
+     << this -> GlobalFileLayoutDimensions[0] << " "
+     << this -> GlobalFileLayoutDimensions[1] << "\n";
+
+  os << "  Query Extent: "
+     << this -> QueryExtent[0] << " "
+     << this -> QueryExtent[1] << " "
+     << this -> QueryExtent[2] << " "
+     << this -> QueryExtent[3] << "\n";
+
+  os << "  Query File Info Dimensions: "
+     << this -> QueryFileInfoDimensions[0] << " "
+     << this -> QueryFileInfoDimensions[1] << "\n";
+
+  os << "GlobalCoordinatesToFileMapper - End PrintSelf --------------------\n"
+     << endl;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+int GlobalCoordinatesToFileMapper::Query()
+{
+
+  // Check if instance is initialized
+  if (this -> Initialized == false)
+    {
+      return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_NOT_INITIALIZED;
+    }
+
+  // Check that query extent is within global image bounds
+  if ((this -> QueryExtent[0] + this -> QueryExtent[2] >
+       this -> GlobalCoordinateDimensions[0]) ||
+      (this -> QueryExtent[1] + this -> QueryExtent[3] >
+       this -> GlobalCoordinateDimensions[1]))
+    {
+      return GLOBAL_COORDINATES_TO_FILE_MAPPER_ERROR_INVALID_EXTENT;
+    }
+
+  // Calculate the first column and row
+  long fc = this -> QueryExtent[0] / this -> FileCoordinateDimensions[0];
+  long fr = this -> QueryExtent[1] / this -> FileCoordinateDimensions[1];
+
+  // Calculate the last column and row
+  long lc = (this -> QueryExtent[0] + this -> QueryExtent[2]) /
+    this -> FileCoordinateDimensions[0];
+  long lr = (this -> QueryExtent[1] + this -> QueryExtent[3]) /
+    this -> FileCoordinateDimensions[1];
+
+  // Set the query file info dimensions
+  this -> QueryFileInfoDimensions[0] = lc - fc + 1;
+  this -> QueryFileInfoDimensions[1] = lr - fr + 1;
+
+  // Calculate the total number of files in the result
+  long tot = (lc - fc + 1) * (lr - fr + 1);
+
+  // Delete previous query result.
+  if (this -> QueryFileInfoArray != NULL)
+    {
+      delete [] this -> QueryFileInfoArray;
+    }
+
+  // Allocate storage for new query.
+  this -> QueryFileInfoArray = new FileInfo[tot];
+
+  // Count number of files in FileInfoArray
+  long fcnt = 0;
+
+  // Create FileInfoArray for query. Loop through each column, and row
+  // of the global array specified by the bounds computed above, filling in
+  // the array. This probably isn't the best way to do this, but it's what
+  // I came up with in one night.
+  for (long cgc = fc, clc = 0 ; cgc <= lc ; cgc++, clc++)
+    {
+      for (long cgr = fr, clr = 0 ; cgr <= lr ; cgr++, clr++)
+	{
+	  // Set file dimensions
+	  this -> QueryFileInfoArray[fcnt].
+	    SetDimensions(this -> FileCoordinateDimensions[0],
+			  this -> FileCoordinateDimensions[1]);
+
+	  // Determine file's position in global array
+	  long pos = (cgc * this -> GlobalFileLayoutDimensions[1]) + cgr;
+
+	  // Calculate and set the extent for the current individual file.
+
+	  // first and last column
+	  if (clc == 0 && lc - fc == 0)
+	    {
+	      if (this -> QueryExtent[0] >=
+		  this -> FileCoordinateDimensions[0])
+		{
+		  this -> QueryFileInfoArray[fcnt].
+		    SetExtentX(this -> QueryExtent[0] -
+			       (cgc * this -> FileCoordinateDimensions[0]));
+		}
+	      else
+		{
+		  this -> QueryFileInfoArray[fcnt].SetExtentX(this ->
+							      QueryExtent[0]);
+		}
+	      this -> QueryFileInfoArray[fcnt].SetExtentW(this ->
+							  QueryExtent[2]);
+	    }
+
+	  // first and last row
+	  if (clr == 0 && lr - fr == 0)
+	    {
+	      // if first row is from 0 then it's OK, but if it's not
+	      // then subtract number of rows * fileDim
+	      if (this -> QueryExtent[1] >=
+		  this -> FileCoordinateDimensions[1])
+		{
+		  this -> QueryFileInfoArray[fcnt].
+		    SetExtentY(this -> QueryExtent[1] -
+			       (cgr * this -> FileCoordinateDimensions[1]));
+		}
+	      else
+		{
+		  this -> QueryFileInfoArray[fcnt].SetExtentY(this ->
+							      QueryExtent[1]);
+		}
+	      this -> QueryFileInfoArray[fcnt].SetExtentH(this ->
+							  QueryExtent[3]);
+
+	    }
+
+	  // first, but not last, column
+	  if (clc == 0 && lc - fc != 0)
+	    {
+	      long tmp = this -> QueryExtent[0] -
+		(cgc * this -> FileCoordinateDimensions[0]);
+	      this -> QueryFileInfoArray[fcnt].SetExtentX(tmp);
+	      this -> QueryFileInfoArray[fcnt].
+		SetExtentW(this -> FileCoordinateDimensions[0] - tmp);
+	    }
+
+	  // first, but not last, row
+	  if (clr == 0 && lr - fr != 0)
+	    {
+	      long tmp = this -> QueryExtent[1] -
+		(cgr * this -> FileCoordinateDimensions[1]);
+	      this -> QueryFileInfoArray[fcnt].SetExtentY(tmp);
+	      this -> QueryFileInfoArray[fcnt].
+		SetExtentH(this -> FileCoordinateDimensions[1] - tmp);
+	    }
+
+	  // last, but not only, column
+	  if (clc == (lc - fc) && clc != 0)
+	    {
+	      long tmp = (this -> QueryExtent[0] + this -> QueryExtent[2]) -
+		(cgc * this -> FileCoordinateDimensions[0]);
+	      this -> QueryFileInfoArray[fcnt].SetExtentX(0);
+	      this -> QueryFileInfoArray[fcnt].SetExtentW(tmp);
+	    }
+
+	  // last, but not only, row
+	  if (clr == (lr - fr) && clr != 0)
+	    {
+	      long tmp = (this -> QueryExtent[1] + this -> QueryExtent[3]) -
+		(cgr * this -> FileCoordinateDimensions[1]);
+	      this -> QueryFileInfoArray[fcnt].SetExtentY(0);
+	      this -> QueryFileInfoArray[fcnt].SetExtentH(tmp);
+	    }
+
+	  // Not the first and not the last column
+	  if (clc != 0 && clc != (lc - fc))
+	    {
+	      this -> QueryFileInfoArray[fcnt].SetExtentX(0);
+	      this -> QueryFileInfoArray[fcnt].
+		SetExtentW(this -> FileCoordinateDimensions[0]);
+	    }
+
+	  // Not the first and not the last row
+	  if (clr != 0 && clr != (lr - fr))
+	    {
+	      this -> QueryFileInfoArray[fcnt].SetExtentY(0);
+	      this -> QueryFileInfoArray[fcnt].
+		SetExtentH(this -> FileCoordinateDimensions[1]);
+	    }
+
+	  // Set file name
+	  this -> QueryFileInfoArray[fcnt].
+	    SetFileName(this -> GlobalFileLayoutArray[pos]);
+
+	  // Set local file position to current local column,
+	  // current local row.
+	  this -> QueryFileInfoArray[fcnt].SetLocalPosition(clc, clr);
+
+	  // Increment number of files in FileInfoArray
+	  fcnt++;
+	}
+    }
+
+  // Return successfully
+  return GLOBAL_COORDINATES_TO_FILE_MAPPER_SUCCESS;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetDescription(const char* string)
+{
+
+  // Delete current description.
+  if (this -> Description != NULL)
+    {
+      delete [] this -> Description;
+      this -> Description = NULL;
+    }
+
+  // Copy string as new description.
+  if (string != NULL)
+    {
+      this -> Description = new char[strlen(string) + 1];
+      strcpy(this -> Description, string);
+    }
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetFileCoordinateDimensions(long w,
+								long h)
+{
+
+  // Set FileCoordinateDimensions
+  this -> FileCoordinateDimensions[0] = w;
+  this -> FileCoordinateDimensions[1] = h;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetInitializedFalse()
+{
+
+  // Set Initialized to false.
+  this -> Initialized = false;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetInitializedTrue()
+{
+
+  // Set Initialized to true.
+  this -> Initialized = true;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetGlobalCoordinateDimensions(long w,
+								  long h)
+{
+
+  // Set GlobalCoordinateDimensions
+  this -> GlobalCoordinateDimensions[0] = w;
+  this -> GlobalCoordinateDimensions[1] = h;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetGlobalFileLayoutArray(char** array,
+							     long cols,
+							     long rows)
+{
+
+  // Set GlobalFileLayoutDimensions
+  this -> GlobalFileLayoutDimensions[0] = cols;
+  this -> GlobalFileLayoutDimensions[1] = rows;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetGlobalFileLayoutDimensions(long cols,
+								  long rows)
+{
+
+  // Set GlobalFileLayoutDimensions
+  this -> GlobalFileLayoutDimensions[0] = cols;
+  this -> GlobalFileLayoutDimensions[1] = rows;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetQueryExtent(long x, long y,
+						   long w, long h)
+{
+
+  // Set QueryExtent
+  this -> QueryExtent[0] = x;
+  this -> QueryExtent[1] = y;
+  this -> QueryExtent[2] = w;
+  this -> QueryExtent[3] = h;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetQueryFileInfoArray(FileInfo* array,
+							  long cols,
+							  long rows)
+{
+
+  // Check if an array exists, and if so delete it.
+  if (this -> QueryFileInfoArray != NULL)
+    {
+      delete [] this -> QueryFileInfoArray;
+    }
+
+  // Assigned array. NOTE: This is bad, very, very bad. Should be a deep
+  // copy operation.
+  this -> QueryFileInfoArray = array;
+
+  // Set QueryFileInfoDimensions
+  this -> QueryFileInfoDimensions[0] = cols;
+  this -> QueryFileInfoDimensions[1] = rows;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+void GlobalCoordinatesToFileMapper::SetQueryFileInfoDimensions(long cols,
+							       long rows)
+{
+
+  // Set QueryFileInfoDimensions
+  this -> QueryFileInfoDimensions[0] = cols;
+  this -> QueryFileInfoDimensions[1] = rows;
+
+  return;
+
+}
+
+
+//-----------------------------------------------------------------------------
+GlobalCoordinatesToFileMapper::~GlobalCoordinatesToFileMapper()
+{
+
+  // Deallocate memory used for description.
+  if (this -> Description != NULL)
+    {
+      delete [] this -> Description;
+    }
+
+  // Deallocate memory used for the GlobalFileLayoutArray
+  if (this -> GlobalFileLayoutArray != NULL)
+    {
+      for (long i = 0 ;
+	   i < this -> GlobalFileLayoutDimensions[0] *
+	     this -> GlobalFileLayoutDimensions[1] ;
+	   i++)
+	{
+	  if (this -> GlobalFileLayoutArray[i] != NULL)
+	    {
+	      delete [] this -> GlobalFileLayoutArray[i];
+	    }
+	}
+      delete [] this -> GlobalFileLayoutArray;
+    }
+
+  // Deallocate memory for QueryFileInfoArray
+  if (this -> QueryFileInfoArray != NULL)
+    {
+      delete [] this -> QueryFileInfoArray;
+    }
+
+}
Index: trunk/src/testing/app/vnc/README
===================================================================
--- trunk/src/testing/app/vnc/README	(revision 4)
+++ trunk/src/testing/app/vnc/README	(revision 4)
@@ -0,0 +1,39 @@
+-----------------------------------------------
+
+VNCViewer for SAGE2
+
+-----------------------------------------------
+
+
+
+(1) INSTALLATION:
+-----------------
+
+- type "make install" (after you have already compiled SAGE)
+- make an entry for VNCViewer in the $SAGE_DIRECTORY/bin/appLauncher/sage.conf file, such as:
+
+VNCViewer {
+configName MyDesktop
+nodeNum 1
+Init 100 100 1024 768
+exec 127.0.0.1 VNCViewer
+nwProtocol tvTcpModule.so
+}
+
+- don't worry about the Init line too much because that information will be overwritten automatically
+  so that it corresponds to your desktop size
+
+
+(2) HOW TO USE:
+---------------
+- from the SAGE UI click on the "VNC" icon and then choose "MyDesktop" from the menu
+- a dialog will pop up where you can change some parameters: in most cases you will 
+  only need to type the password to match your vnc server's password.
+- click "Show" and your desktop should show up on the SAGE display
+- to stop sharing your desktop just close the SAGE window for your vnc session from the SAGE UI
+
+- by default the VNCViewer will stream your desktop to SAGE at 1fps. This is done to minimize the
+  bandwidth usage but still be useful for sharing your desktop. However, this frame rate can be
+  changed but you will need to start the VNCViewer by hand as follows:
+  VNCviewer <hostname> <display#> <width> <height> <password> <fps>
+
Index: trunk/src/testing/app/vnc/vncauth.h
===================================================================
--- trunk/src/testing/app/vnc/vncauth.h	(revision 4)
+++ trunk/src/testing/app/vnc/vncauth.h	(revision 4)
@@ -0,0 +1,31 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/* 
+ * vncauth.h - describes the functions provided by the vncauth library.
+ */
+
+#define MAXPWLEN 8
+#define CHALLENGESIZE 16
+
+extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
+extern char *vncDecryptPasswdFromFile(char *fname);
+extern void vncRandomBytes(unsigned char *bytes);
+extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
+
Index: trunk/src/testing/app/vnc/vncviewer.h
===================================================================
--- trunk/src/testing/app/vnc/vncviewer.h	(revision 4)
+++ trunk/src/testing/app/vnc/vncviewer.h	(revision 4)
@@ -0,0 +1,251 @@
+/*****************************************************************************************
+ * VNCViewer for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about VNCViewer for SAGE to www.evl.uic.edu/cavern/forum
+ *****************************************************************************************/
+
+#ifndef AURA_VNCVIEW_H
+#define AURA_VNCVIEW_H
+
+#define False 0
+#define True 1
+typedef char *String;
+
+typedef unsigned char uchar;
+typedef int Bool;
+
+#if defined(WIN32)
+//#include <Winsock2.h>
+#else
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+
+// Util functions
+void aLog(const char* format,...);
+void aError(const char* format,...);
+
+
+
+#include "rfb.h"
+
+#define MAX_ENCODINGS 10
+
+#define FLASH_PORT_OFFSET 5400
+#define SERVER_PORT_OFFSET 5900
+
+// note that the CoRRE encoding uses this buffer and assumes it is big enough
+// to hold 255 * 255 * 32 bits -> 260100 bytes.  640*480 = 307200 bytes
+// also hextile assumes it is big enough to hold 16 * 16 * 32 bits
+#define BUFFER_SIZE (640*480)
+
+// socket buffer
+#define BUF_SIZE 8192
+
+class sgVNCViewer;
+
+class VNCViewer
+{
+public:
+    Bool shareDesktop;
+    Bool viewOnly;
+    Bool fullScreen;
+
+    String encodingsString;
+
+    Bool useBGR233;
+    int nColours;
+    Bool useSharedColours;
+    Bool forceOwnCmap;
+    Bool forceTrueColour;
+    int requestedDepth;
+
+    Bool useShm;
+
+    int wmDecorationWidth;
+    int wmDecorationHeight;
+
+    char *passwordFile;
+    Bool passwordDialog;
+
+    int rawDelay;
+    int copyRectDelay;
+
+    Bool debug;
+
+    int popupButtonCount;
+
+    int bumpScrollTime;
+    int bumpScrollPixels;
+
+    int compressLevel;
+    int qualityLevel;
+    Bool useRemoteCursor;
+
+    char vncServerHost[256];
+    int  vncServerPort;
+
+    int  rfbsock;
+    Bool canUseCoRRE;
+    Bool canUseHextile;
+    char *desktopName;
+    rfbPixelFormat myFormat;
+    rfbServerInitMsg si;
+    char *serverCutText;
+    Bool newServerCutText;
+
+        // socket buffering
+    char buffer[BUFFER_SIZE];
+    int buffered;
+    char buf[BUF_SIZE];
+    char *bufoutptr;
+    
+public:
+    VNCViewer()
+        {
+            encodingsString = strdup("hextile corre rre raw copyrect");
+            shareDesktop = True;
+            viewOnly = False;
+            fullScreen = False;
+            passwordFile = strdup("passwd");
+            passwordDialog = False;
+            useBGR233 = False;
+            nColours = 256;
+            useSharedColours = True;
+            forceOwnCmap = False;
+            forceTrueColour = False;
+            requestedDepth = 0;
+            wmDecorationWidth = 4;
+            wmDecorationHeight = 24;
+            popupButtonCount = 0;
+            debug = False;
+            rawDelay = 0;
+            copyRectDelay = 0;
+            bumpScrollTime = 25;
+            bumpScrollPixels = 20;
+            compressLevel   = 4;
+            qualityLevel    = 2;
+            useRemoteCursor = False;
+
+            vncServerPort = 0;
+            serverCutText = NULL;
+            newServerCutText = False;
+            buffered = 0;
+            bufoutptr = buf;
+        };
+    ~VNCViewer()
+        {};
+    
+    void GetArgsAndResources(int argc, char **argv);
+    Bool ConnectToRFBServer();
+    Bool InitialiseRFBConnection(char *pass);
+    Bool SetFormatAndEncodings();
+    Bool SendIncrementalFramebufferUpdateRequest();
+    Bool SendFramebufferUpdateRequest(int x, int y, int w, int h,
+                                      Bool incremental);
+    Bool SendPointerEvent(int x, int y, int buttonMask);
+    Bool SendKeyEvent(CARD32 key, Bool down);
+    Bool SendClientCutText(char *str, int len);
+
+    void PrintPixelFormat(rfbPixelFormat *format);
+    void SetVisualAndCmap();
+
+    Bool HandleCoRRE8  (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleCoRRE16 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleCoRRE32 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+
+    Bool HandleHextile8  (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleHextile16 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleHextile32 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+
+    Bool HandleRRE8  (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleRRE16 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleRRE32 (sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+
+    Bool HandleZlib8(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleZlib16(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleZlib32(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+
+    Bool HandleTight8(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleTight16(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+    Bool HandleTight32(sgVNCViewer *ct, int rx, int ry, int rw, int rh);
+
+
+    void FilterGradient24 (int numRows, CARD32 *dst);
+
+    int  InitFilterCopy8 (int rw, int rh);
+    void FilterCopy8 (int numRows, CARD8 *dst);
+    int  InitFilterGradient8 (int rw, int rh);
+    void FilterGradient8 (int numRows, CARD8 *dst);
+    int  InitFilterPalette8 (int rw, int rh);
+    void FilterPalette8 (int numRows, CARD8 *dst);
+
+    int  InitFilterCopy16 (int rw, int rh);
+    void FilterCopy16 (int numRows, CARD16 *dst);
+    int  InitFilterGradient16 (int rw, int rh);
+    void FilterGradient16 (int numRows, CARD16 *dst);
+    int  InitFilterPalette16 (int rw, int rh);
+    void FilterPalette16 (int numRows, CARD16 *dst);
+
+    int  InitFilterCopy32 (int rw, int rh);
+    void FilterCopy32 (int numRows, CARD32 *dst);
+    int  InitFilterGradient32 (int rw, int rh);
+    void FilterGradient32 (int numRows, CARD32 *dst);
+    int  InitFilterPalette32 (int rw, int rh);
+    void FilterPalette32 (int numRows, CARD32 *dst);
+    
+    long ReadCompactLen (void);
+    Bool DecompressJpegRect8(sgVNCViewer *ct, int x, int y, int w, int h);
+    Bool DecompressJpegRect16(sgVNCViewer *ct, int x, int y, int w, int h);
+    Bool DecompressJpegRect32(sgVNCViewer *ct, int x, int y, int w, int h);
+
+    Bool ReadFromRFBServer(char *out, unsigned int n);
+    Bool HandleRFBServerMessage(sgVNCViewer *ct);
+};
+
+
+
+/* sockets.c */
+
+extern Bool WriteExact(int sock, char *buf, int n);
+extern int  ConnectToTcpAddr(unsigned int host, int port);
+extern Bool SetNonBlocking(int sock);
+
+extern int  StringToIPAddr(const char *str, unsigned long *addr);
+extern Bool SameMachine(int sock);
+
+#endif
Index: trunk/src/testing/app/vnc/rfb.h
===================================================================
--- trunk/src/testing/app/vnc/rfb.h	(revision 4)
+++ trunk/src/testing/app/vnc/rfb.h	(revision 4)
@@ -0,0 +1,93 @@
+//  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+//  This file is part of the VNC system.
+//
+//  The VNC system is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+//  USA.
+//
+// If the source code for the VNC system is not available from the place 
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+
+
+// rfb.h
+// This includes the rfb spec header, the port numbers,
+// the CARD type definitions and various useful macros.
+//
+
+#ifndef RFB_H__
+#define RFB_H__
+
+// Define the CARD* types as used in X11/Xmd.h
+
+#if defined(WIN32)
+typedef unsigned long CARD32;
+typedef unsigned short CARD16;
+typedef short INT16;
+typedef unsigned char  CARD8;
+#else
+#include <X11/Xmd.h> // **** CORRECTION HACK - Miko 6/6/2003
+#endif
+
+/*
+ * Data structure used by color operations
+ */
+//  typedef struct {
+//  	unsigned long pixel;
+//  	unsigned short red, green, blue;
+//  	char flags;
+//  	char pad;
+//  } XColor;
+//  #define DoRed			(1<<0)
+//  #define DoGreen			(1<<1)
+//  #define DoBlue			(1<<2)
+
+// Define the port number offsets
+#define FLASH_PORT_OFFSET 5400
+#define INCOMING_PORT_OFFSET 5500
+#define HTTP_PORT_OFFSET 5800	// we don't use this in Venice
+#define RFB_PORT_OFFSET 5900
+
+#define PORT_TO_DISPLAY(p) ( (p) - RFB_PORT_OFFSET )
+#define DISPLAY_TO_PORT(d) ( (d) + RFB_PORT_OFFSET )
+
+// include the protocol spec
+#include "rfbproto.h"
+
+// define some quick endian conversions
+// change this if necessary
+#if not defined(__APPLE__)
+#define LITTLE_ENDIAN_HOST
+#endif
+
+#ifdef LITTLE_ENDIAN_HOST
+
+#define Swap16IfLE(s) \
+    ((CARD16) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)))
+#define Swap32IfLE(l) \
+    ((CARD32) ((((l) & 0xff000000) >> 24) | \
+     (((l) & 0x00ff0000) >> 8)  | \
+	 (((l) & 0x0000ff00) << 8)  | \
+	 (((l) & 0x000000ff) << 24)))
+
+#else
+
+#define Swap16IfLE(s) (s)
+#define Swap32IfLE(l) (l)
+
+#endif
+
+
+#endif
Index: trunk/src/testing/app/vnc/tight.cpp
===================================================================
--- trunk/src/testing/app/vnc/tight.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/tight.cpp	(revision 4)
@@ -0,0 +1,610 @@
+/************************************************************************
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * tight.c - handle ``tight'' encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple
+ * times by rfbproto.c, each time with a different definition of the
+ * macro BPP. For each value of BPP, this file defines a function
+ * which handles a tight-encoded rectangle with BPP bits per pixel.
+ *
+ */
+
+#define TIGHT_MIN_TO_COMPRESS 12
+
+#define CARDBPP CONCAT2E(CARD,BPP)
+#define filterPtrBPP CONCAT2E(filterPtr,BPP)
+
+#define HandleTightBPP CONCAT2E(HandleTight,BPP)
+#define ReceiveTightBPP CONCAT2E(ReceiveTight,BPP)
+#define flushTightBPP CONCAT2E(flushTight,BPP)
+#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
+#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
+#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
+#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
+#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
+#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
+
+#if BPP != 8
+#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
+#endif
+
+#ifndef RGB_TO_PIXEL
+
+#define RGB_TO_PIXEL(bpp,r,g,b)						\
+  (((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift |		\
+   ((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift |	\
+   ((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL(bpp,r,g,b)                                       \
+   ((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255             \
+    << myFormat.redShift |                                              \
+    (((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255           \
+    << myFormat.greenShift |                                            \
+    (((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255            \
+    << myFormat.blueShift)
+
+#define RGB24_TO_PIXEL32(r,g,b)						\
+  (((CARD32)(r) & 0xFF) << myFormat.redShift |				\
+   ((CARD32)(g) & 0xFF) << myFormat.greenShift |			\
+   ((CARD32)(b) & 0xFF) << myFormat.blueShift)
+
+#endif
+
+/* Type declarations */
+
+typedef void (VNCViewer::*filterPtrBPP)(int, CARDBPP *);
+
+/* Prototypes */
+
+//  static int InitFilterCopyBPP (int rw, int rh);
+//  static int InitFilterPaletteBPP (int rw, int rh);
+//  static int InitFilterGradientBPP (int rw, int rh);
+//  static void FilterCopyBPP (int numRows, CARDBPP *destBuffer);
+//  static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer);
+//  static void FilterGradientBPP (int numRows, CARDBPP *destBuffer);
+
+#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
+#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
+#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
+#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
+#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
+#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
+
+//static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
+
+/* Definitions */
+
+Bool
+VNCViewer::HandleTightBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
+{
+    CARDBPP fill_colour;
+    CARD8 comp_ctl;
+    CARD8 filter_id;
+    filterPtrBPP filterFn;
+    z_streamp zs;
+    char *buffer2;
+    int err, stream_id, compressedLen, bitsPixel;
+    int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
+
+    if (!ReadFromRFBServer((char *)&comp_ctl, 1))
+        return False;
+
+        /* Flush zlib streams if we are told by the server to do so. */
+    for (stream_id = 0; stream_id < 4; stream_id++) {
+        if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
+            if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
+                zlibStream[stream_id].msg != NULL)
+                aLog("inflateEnd: %s\n", zlibStream[stream_id].msg);
+            zlibStreamActive[stream_id] = False;
+        }
+        comp_ctl >>= 1;
+    }
+
+        /* Handle solid rectangles. */
+    if (comp_ctl == rfbTightFill) {
+#if BPP == 32
+        if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+            myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+            if (!ReadFromRFBServer(buffer, 3))
+                return False;
+            fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
+        } else {
+            if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+                return False;
+        }
+#else
+        if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
+            return False;
+#endif
+
+        ct->FillToScreen(fill_colour, rx, ry, rw, rh);
+
+        return True;
+    }
+
+#if BPP == 8
+    if (comp_ctl == rfbTightJpeg) {
+        aLog("Tight encoding: JPEG is not supported in 8 bpp mode.\n");
+        return False;
+    }
+#else
+    if (comp_ctl == rfbTightJpeg) {
+        return DecompressJpegRectBPP(ct,rx, ry, rw, rh);
+    }
+#endif
+
+        /* Quit on unsupported subencoding value. */
+    if (comp_ctl > rfbTightMaxSubencoding) {
+        aLog("Tight encoding: bad subencoding value received.\n");
+        return False;
+    }
+
+        /*
+         * Here primary compression mode handling begins.
+         * Data was processed with optional filter + zlib compression.
+         */
+
+        /* First, we should identify a filter to use. */
+    if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+        if (!ReadFromRFBServer((char*)&filter_id, 1))
+            return False;
+
+        switch (filter_id) {
+            case rfbTightFilterCopy:
+                filterFn = &VNCViewer::FilterCopyBPP;
+                bitsPixel = InitFilterCopyBPP(rw, rh);
+                break;
+            case rfbTightFilterPalette:
+                filterFn = &VNCViewer::FilterPaletteBPP;
+                bitsPixel = InitFilterPaletteBPP(rw, rh);
+                break;
+            case rfbTightFilterGradient:
+                filterFn = &VNCViewer::FilterGradientBPP;
+                bitsPixel = InitFilterGradientBPP(rw, rh);
+                break;
+          default:
+                aLog("Tight encoding: unknown filter code received.\n");
+                return False;
+        }
+    } else {
+        filterFn = &VNCViewer::FilterCopyBPP;
+        bitsPixel = InitFilterCopyBPP(rw, rh);
+    }
+    if (bitsPixel == 0) {
+        aLog("Tight encoding: error receiving palette.\n");
+        return False;
+    }
+
+        /* Determine if the data should be decompressed or just copied. */
+    rowSize = (rw * bitsPixel + 7) / 8;
+    if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
+        if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
+            return False;
+
+        buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
+        (this->*filterFn)(rh, (CARDBPP *)buffer2);
+        ct->CopyDataToScreen(buffer2, rx, ry, rw, rh);
+
+        return True;
+    }
+
+        /* Read the length (1..3 bytes) of compressed data following. */
+    compressedLen = (int)ReadCompactLen();
+    if (compressedLen <= 0) {
+        aLog("Incorrect data received from the server.\n");
+        return False;
+    }
+
+        /* Now let's initialize compression stream if needed. */
+    stream_id = comp_ctl & 0x03;
+    zs = &zlibStream[stream_id];
+    if (!zlibStreamActive[stream_id]) {
+        zs->zalloc = Z_NULL;
+        zs->zfree = Z_NULL;
+        zs->opaque = Z_NULL;
+        err = inflateInit(zs);
+        if (err != Z_OK) {
+            if (zs->msg != NULL)
+                aLog("InflateInit error: %s.\n", zs->msg);
+            return False;
+        }
+        zlibStreamActive[stream_id] = True;
+    }
+
+        /* Read, decode and draw actual pixel data in a loop. */
+
+    bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
+    buffer2 = &buffer[bufferSize];
+    if (rowSize > bufferSize) {
+            /* Should be impossible when BUFFER_SIZE >= 16384 */
+        aLog("Internal error: incorrect buffer size.\n");
+        return False;
+    }
+
+    rowsProcessed = 0;
+    extraBytes = 0;
+
+    while (compressedLen > 0) {
+        if (compressedLen > ZLIB_BUFFER_SIZE)
+            portionLen = ZLIB_BUFFER_SIZE;
+        else
+            portionLen = compressedLen;
+
+        if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
+            return False;
+
+        compressedLen -= portionLen;
+
+        zs->next_in = (Bytef *)zlib_buffer;
+        zs->avail_in = portionLen;
+
+        do {
+            zs->next_out = (Bytef *)&buffer[extraBytes];
+            zs->avail_out = bufferSize - extraBytes;
+
+            err = inflate(zs, Z_SYNC_FLUSH);
+            if (err == Z_BUF_ERROR)   /* Input exhausted -- no problem. */
+                break;
+            if (err != Z_OK && err != Z_STREAM_END) {
+                if (zs->msg != NULL) {
+                    aLog("Inflate error: %s.\n", zs->msg);
+                } else {
+                    aLog("Inflate error: %d.\n", err);
+                }
+                return False;
+            }
+
+            numRows = (bufferSize - zs->avail_out) / rowSize;
+
+            (this->*filterFn)(numRows, (CARDBPP *)buffer2);
+
+            extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
+            if (extraBytes > 0)
+                memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
+
+            ct->CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
+            rowsProcessed += numRows;
+        }
+        while (zs->avail_out == 0);
+    }
+
+    if (rowsProcessed != rh) {
+        aLog("Incorrect number of scan lines after decompression.\n");
+        return False;
+    }
+
+    return True;
+}
+
+/*----------------------------------------------------------------------------
+ *
+ * Filter stuff.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool cutZeros;
+     static int rectWidth, rectColors;
+     static CARD8 tightPalette[256*4];
+     static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
+*/
+
+int
+VNCViewer::InitFilterCopyBPP (int rw, int rh)
+{
+    rectWidth = rw;
+
+#if BPP == 32
+    if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+        myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+        cutZeros = True;
+        return 24;
+    } else {
+        cutZeros = False;
+    }
+#endif
+
+    return BPP;
+}
+
+void
+VNCViewer::FilterCopyBPP (int numRows, CARDBPP *dst)
+{
+
+#if BPP == 32
+    int x, y;
+
+    if (cutZeros) {
+        for (y = 0; y < numRows; y++) {
+            for (x = 0; x < rectWidth; x++) {
+                dst[y*rectWidth+x] =
+                    RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3],
+                                     buffer[(y*rectWidth+x)*3+1],
+                                     buffer[(y*rectWidth+x)*3+2]);
+            }
+        }
+        return;
+    }
+#endif
+
+    memcpy (dst, buffer, numRows * rectWidth * (BPP / 8));
+}
+
+int
+VNCViewer::InitFilterGradientBPP (int rw, int rh)
+{
+    int bits;
+
+    bits = InitFilterCopyBPP(rw, rh);
+    if (cutZeros)
+        memset(tightPrevRow, 0, rw * 3);
+    else
+        memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
+
+    return bits;
+}
+
+#if BPP == 32
+
+void
+VNCViewer::FilterGradient24 (int numRows, CARD32 *dst)
+{
+    int x, y, c;
+    CARD8 thisRow[2048*3];
+    CARD8 pix[3];
+    int est[3];
+
+    for (y = 0; y < numRows; y++) {
+
+            /* First pixel in a row */
+        for (c = 0; c < 3; c++) {
+            pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c];
+            thisRow[c] = pix[c];
+        }
+        dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+
+            /* Remaining pixels of a row */
+        for (x = 1; x < rectWidth; x++) {
+            for (c = 0; c < 3; c++) {
+                est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
+                    (int)tightPrevRow[(x-1)*3+c];
+                if (est[c] > 0xFF) {
+                    est[c] = 0xFF;
+                } else if (est[c] < 0x00) {
+                    est[c] = 0x00;
+                }
+                pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
+                thisRow[x*3+c] = pix[c];
+            }
+            dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
+        }
+
+        memcpy(tightPrevRow, thisRow, rectWidth * 3);
+    }
+}
+
+#endif
+
+void
+VNCViewer::FilterGradientBPP (int numRows, CARDBPP *dst)
+{
+    int x, y, c;
+    CARDBPP *src = (CARDBPP *)buffer;
+    CARD16 *thatRow = (CARD16 *)tightPrevRow;
+    CARD16 thisRow[2048*3];
+    CARD16 pix[3];
+    CARD16 max[3];
+    int shift[3];
+    int est[3];
+
+#if BPP == 32
+    if (cutZeros) {
+        FilterGradient24(numRows, dst);
+        return;
+    }
+#endif
+
+    max[0] = myFormat.redMax;
+    max[1] = myFormat.greenMax;
+    max[2] = myFormat.blueMax;
+
+    shift[0] = myFormat.redShift;
+    shift[1] = myFormat.greenShift;
+    shift[2] = myFormat.blueShift;
+
+    for (y = 0; y < numRows; y++) {
+
+            /* First pixel in a row */
+        for (c = 0; c < 3; c++) {
+            pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
+            thisRow[c] = pix[c];
+        }
+        dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+
+            /* Remaining pixels of a row */
+        for (x = 1; x < rectWidth; x++) {
+            for (c = 0; c < 3; c++) {
+                est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
+                if (est[c] > (int)max[c]) {
+                    est[c] = (int)max[c];
+                } else if (est[c] < 0) {
+                    est[c] = 0;
+                }
+                pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
+                thisRow[x*3+c] = pix[c];
+            }
+            dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
+        }
+        memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
+    }
+}
+
+int
+VNCViewer::InitFilterPaletteBPP (int rw, int rh)
+{
+    CARD8 numColors;
+    CARDBPP *palette = (CARDBPP *)tightPalette;
+
+    rectWidth = rw;
+
+    if (!ReadFromRFBServer((char*)&numColors, 1))
+        return 0;
+
+    rectColors = (int)numColors;
+    if (++rectColors < 2)
+        return 0;
+
+#if BPP == 32
+	int i;
+    if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
+        myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
+        if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
+            return 0;
+        for (i = rectColors - 1; i >= 0; i--) {
+            palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
+                                          tightPalette[i*3+1],
+                                          tightPalette[i*3+2]);
+        }
+        return (rectColors == 2) ? 1 : 8;
+    }
+#endif
+
+    if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
+        return 0;
+
+    return (rectColors == 2) ? 1 : 8;
+}
+
+void
+VNCViewer::FilterPaletteBPP (int numRows, CARDBPP *dst)
+{
+    int x, y, b, w;
+    CARD8 *src = (CARD8 *)buffer;
+    CARDBPP *palette = (CARDBPP *)tightPalette;
+
+    if (rectColors == 2) {
+        w = (rectWidth + 7) / 8;
+        for (y = 0; y < numRows; y++) {
+            for (x = 0; x < rectWidth / 8; x++) {
+                for (b = 7; b >= 0; b--)
+                    dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+            }
+            for (b = 7; b >= 8 - rectWidth % 8; b--) {
+                dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
+            }
+        }
+    } else {
+        for (y = 0; y < numRows; y++)
+            for (x = 0; x < rectWidth; x++)
+                dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
+    }
+}
+
+
+#if BPP != 8
+
+/*----------------------------------------------------------------------------
+ *
+ * JPEG decompression.
+ *
+ */
+
+/*
+   The following variables are defined in rfbproto.c:
+     static Bool jpegError;
+     static struct jpeg_source_mgr jpegSrcManager;
+     static JOCTET *jpegBufferPtr;
+     static size_t *jpegBufferLen;
+*/
+
+Bool
+VNCViewer::DecompressJpegRectBPP(sgVNCViewer *ct, int x, int y, int w, int h)
+{
+    struct jpeg_decompress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    int compressedLen;
+    CARD8 *compressedData;
+    CARDBPP *pixelPtr;
+    JSAMPROW rowPointer[1];
+    int dx, dy;
+
+    compressedLen = (int)ReadCompactLen();
+    if (compressedLen <= 0) {
+        aLog("Incorrect data received from the server.\n");
+        return False;
+    }
+
+    compressedData = (CARD8*)malloc(compressedLen);
+    if (compressedData == NULL) {
+        aLog("Memory allocation error.\n");
+        return False;
+    }
+
+    if (!ReadFromRFBServer((char*)compressedData, compressedLen)) {
+        free(compressedData);
+        return False;
+    }
+
+    cinfo.err = jpeg_std_error(&jerr);
+    jpeg_create_decompress(&cinfo);
+
+    JpegSetSrcManager(&cinfo, compressedData, compressedLen);
+
+    jpeg_read_header(&cinfo, TRUE);
+    cinfo.out_color_space = JCS_RGB;
+
+    jpeg_start_decompress(&cinfo);
+    if (cinfo.output_width != w || cinfo.output_height != h ||
+        cinfo.output_components != 3) {
+        aLog("Tight Encoding: Wrong JPEG data received.\n");
+        jpeg_destroy_decompress(&cinfo);
+        free(compressedData);
+        return False;
+    }
+
+    rowPointer[0] = (JSAMPROW)buffer;
+    dy = 0;
+    while (cinfo.output_scanline < cinfo.output_height) {
+        jpeg_read_scanlines(&cinfo, rowPointer, 1);
+        if (jpegError) {
+            break;
+        }
+        pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2];
+        for (dx = 0; dx < w; dx++) {
+            *pixelPtr++ =
+                RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]);
+        }
+        ct->CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
+        dy++;
+    }
+
+    if (!jpegError)
+        jpeg_finish_decompress(&cinfo);
+
+    jpeg_destroy_decompress(&cinfo);
+    free(compressedData);
+
+    return !jpegError;
+}
+
+#endif
+
Index: trunk/src/testing/app/vnc/main.cpp
===================================================================
--- trunk/src/testing/app/vnc/main.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/main.cpp	(revision 4)
@@ -0,0 +1,383 @@
+/*****************************************************************************************
+ * VNCViewer for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about VNCViewer for SAGE to www.evl.uic.edu/cavern/forum
+ *****************************************************************************************/
+
+#if defined(USE_LIBVNC)
+#include <rfb/rfbclient.h>
+#else
+#include "sgVNCViewer.h"
+#include <sys/fcntl.h>
+#endif
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+#include <time.h>
+#include <unistd.h>
+
+// Global variables
+char *passwd, *server;
+
+
+// Configuration for SAGE, example:
+//	nodeNum 1
+//	Init 200 200 1480 1224
+//	exec 10.0.8.120 VNCViewer 1
+//	nwProtocol tvTcpModule.so
+
+#if defined(WIN32)
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+void aInitialize()
+{
+#if defined(WIN32)
+    QueryPerformanceCounter(&perf_start);
+    QueryPerformanceFrequency(&perf_freq);
+#elif defined(__APPLE__)
+    if( perf_conversion == 0.0 )
+    {
+        mach_timebase_info_data_t info;
+        kern_return_t err = mach_timebase_info( &info );
+
+            //Convert the timebase into seconds
+        if( err == 0  )
+            perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+    }
+        // Start of time
+    perf_start = mach_absolute_time();
+
+        // Initialize the random generator
+    srand(getpid());
+#else
+        // Start of time
+    gettimeofday(&tv_start,0);
+        // Initialize the random generator
+    srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+    QueryPerformanceCounter(&perf_counter);
+    return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time(); - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+    gettimeofday(&tv,0);
+    return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+// Comment/uncomment to use 24bit or 32bit SAGE application stream
+#define VNC_SAGE_USE_24bit 1
+
+#if defined(USE_LIBVNC)
+rfbClient* vnc;
+#else
+sgVNCViewer* vnc;
+#endif
+
+#if defined(USE_LIBVNC)
+
+static rfbBool got_data = FALSE;
+static void signal_handler(int signal)
+{
+    rfbClientLog("Cleaning up.\n");
+}
+
+static rfbBool resize_func(rfbClient* client)
+{
+    static rfbBool first=TRUE;
+    if(!first) {
+        rfbClientLog("I don't know yet how to change resolutions!\n");
+        exit(1);
+    }
+    signal(SIGINT,signal_handler);
+
+    int width=client->width;
+    int height=client->height;
+    int depth=client->format.bitsPerPixel;
+    client->updateRect.x = client->updateRect.y = 0;
+    client->updateRect.w = width; client->updateRect.h = height;
+
+    client->frameBuffer = (uint8_t*)malloc(width*height*depth);
+    memset(client->frameBuffer, 0, width*height*depth);
+
+    rfbClientLog("Allocate %d bytes: %d x %d x %d\n", width*height*depth, width,height,depth);
+    return TRUE;
+}
+
+static void frame_func(rfbClient* client)
+{
+    rfbClientLog("Received a frame\n");
+}
+
+static rfbBool position_func(rfbClient* client, int x, int y)
+{
+    //rfbClientLog("Received a position for %d,%d\n",x,y);
+    return TRUE;
+}
+
+static char *password_func(rfbClient* client)
+{
+    char *str = (char*)malloc(64);
+    memset(str, 0, 64);
+    strncpy(str, passwd, 64);
+    return str;
+}
+
+static void update_func(rfbClient* client,int x,int y,int w,int h)
+{
+    rfbPixelFormat* pf=&client->format;
+    int bpp=pf->bitsPerPixel/8;
+    int row_stride=client->width*bpp;
+
+    got_data = TRUE;
+
+    //rfbClientLog("Received an update for %d,%d,%d,%d.\n",x,y,w,h);
+}
+
+
+#endif
+
+int
+main(int argc, char **argv)
+{
+    int winWidth, winHeight, display;
+    sail sageInf; // sail object
+    double rate = 10;  //by default stream at 1fps
+
+    aInitialize();
+
+    if (argc < 6)
+    {
+        fprintf(stderr, "\nUsage> VNCviewer <hostname> <display#> <width> <height> <password> [fps]\n\n");
+        exit(0);
+    }
+
+        // VNC Init
+    server    = strdup(argv[1]);
+    display   = atoi(argv[2]);
+    winWidth  = atoi(argv[3]);
+    winHeight = atoi(argv[4]);
+    passwd    = argv[5];
+    if (argc > 6)
+        rate = atoi(argv[6]);
+
+
+#if defined(USE_LIBVNC)
+    // get a vnc client structure (don't connect yet).
+    // bits, channels, bytes
+    vnc = rfbGetClient(8,3,4);
+    vnc->canHandleNewFBSize = FALSE;
+    // to get position update callbacks
+    vnc->appData.useRemoteCursor=TRUE;
+    //vnc->appData.compressLevel=3;
+    //vnc->appData.qualityLevel=5;
+
+    /* open VNC connection */
+    vnc->MallocFrameBuffer=resize_func;
+    vnc->GotFrameBufferUpdate=update_func;
+    vnc->HandleCursorPos=position_func;
+    vnc->GetPassword=password_func;
+    //client->FinishedFrameBufferUpdate=frame_func;
+
+
+    int margc = 2;
+    char *margv[2];
+    margv[0] = strdup("vnc");
+    margv[1] = (char*)malloc(256);
+    memset(margv[1], 0, 256);
+    sprintf(margv[1], "%s:%d", server, display);
+    if(!rfbInitClient(vnc,&margc,margv)) {
+        printf("usage: %s server:port password\n"
+               "VNC client.\n", argv[0]);
+        exit(1);
+    }
+    if (vnc->serverPort==-1)
+        vnc->vncRec->doNotSleep = TRUE; /* vncrec playback */
+
+    winWidth  = vnc->width;
+    winHeight = vnc->height;
+
+#else
+
+        // Connection to VNC server:
+        //	host, display number, x offset, y offset, width, height, passwd
+        //	passwd is by default 'evl123' but a different one can be specified so that one will be used
+    vnc = new sgVNCViewer(server, display, 0,0,winWidth,winHeight, passwd);
+#endif
+
+        // Sage Init
+    sailConfig scfg;
+    scfg.init("VNCViewer.conf");
+    scfg.setAppName("VNCViewer");
+    scfg.rank = 0;
+
+    scfg.resX = winWidth;
+    scfg.resY = winHeight;
+
+    sageRect renderImageMap;
+    renderImageMap.left = 0.0;
+    renderImageMap.right = 1.0;
+    renderImageMap.bottom = 0.0;
+    renderImageMap.top = 1.0;
+
+    scfg.imageMap = renderImageMap;
+#if defined(VNC_SAGE_USE_24bit)
+    scfg.pixFmt = PIXFMT_888;
+#else
+    scfg.pixFmt = PIXFMT_8888;
+#endif
+    scfg.rowOrd = TOP_TO_BOTTOM;
+    scfg.master = true;
+
+    sageInf.init(scfg);
+
+
+        // data pointer
+    unsigned char *buffer = 0;
+    unsigned char *vncpixels;
+
+    double t1, t2;
+    t1 = aTime();
+
+        // Main lopp
+    while (1)
+    {
+#if defined(USE_LIBVNC)
+        double now = sage::getTime();
+        while ( (sage::getTime() - now) < (1000000/rate)) {
+            int i=WaitForMessage(vnc,100000);
+            if(i<0) {
+                rfbClientLog("VNC error, quit\n");
+                sageInf.shutdown();
+                exit(0);
+            }
+            if(i) {
+                if(!HandleRFBServerMessage(vnc)) {
+                    rfbClientLog("HandleRFBServerMessage quit\n");
+                    sageInf.shutdown();
+                    exit(0);
+                }
+            }
+        }
+
+        // Copy VNC buffer into SAGE buffer
+        buffer    = (unsigned char *) sageInf.getBuffer();
+        vncpixels = (unsigned char *) vnc->frameBuffer;
+
+        for (int k =0 ; k<winWidth*winHeight; k++) {
+            buffer[3*k + 0] = vncpixels[ 4*k + 0];
+            buffer[3*k + 1] = vncpixels[ 4*k + 1];
+            buffer[3*k + 2] = vncpixels[ 4*k + 2];
+        }
+
+
+        // SAGE Swap
+        sageInf.swapBuffer( );
+
+        // Process SAGE messages
+        sageMessage msg;
+        if (sageInf.checkMsg(msg, false) > 0) {
+            switch (msg.getCode()) {
+            case APP_QUIT:
+                sageInf.shutdown();
+                exit(0);
+                break;
+            }
+        }
+#else
+
+        if (!vnc->Step())
+        {
+            sageInf.shutdown();
+            exit(0);
+        }
+
+            // if it's been (roughly) xxx second since the last
+            // sent frame, send another one
+        t2 = aTime();
+        if ( (t2-t1) > (1.0/rate) )
+        {
+
+                //fprintf(stderr, "Rate: %.2f\n", 1.0/(t2-t1) );
+            buffer = (unsigned char *) sageInf.getBuffer();
+            vncpixels = (unsigned char *) vnc->Data();
+#if defined(VNC_SAGE_USE_24bit)
+            for (int k =0 ; k<winWidth*winHeight; k++) {
+                buffer[3*k + 0] = vncpixels[ 4*k + 0];
+                buffer[3*k + 1] = vncpixels[ 4*k + 1];
+                buffer[3*k + 2] = vncpixels[ 4*k + 2];
+            }
+#else
+            memcpy(buffer, (unsigned char *) vnc->Data(), winWidth*winHeight*4);
+#endif
+            sageInf.swapBuffer( );
+            t1 = aTime();
+        }
+
+        sageMessage msg;
+        if (sageInf.checkMsg(msg, false) > 0) {
+            switch (msg.getCode()) {
+                case APP_QUIT:
+                    exit(0);
+                    break;
+            }
+        }
+#endif
+    }
+
+    return 1;
+}
+
+
Index: trunk/src/testing/app/vnc/argsresources.cpp
===================================================================
--- trunk/src/testing/app/vnc/argsresources.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/argsresources.cpp	(revision 4)
@@ -0,0 +1,96 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ ************************************************************************/
+
+/*
+ * argsresources.c - deal with command-line args and resources.
+ */
+#include "vncviewer.h"
+
+
+void
+VNCViewer::GetArgsAndResources(int argc, char **argv)
+{
+    int i;
+    char *vncServerName;
+    
+        //encodingsString = strdup("tight copyrect");
+        //encodingsString = strdup("zlib copyrect");
+        //encodingsString = strdup("copyrect hextile");
+    //encodingsString = strdup("hextile corre rre raw copyrect");
+        //default : raw copyrect hextile corre rre
+    encodingsString = strdup("tight hextile copyrect");
+
+
+    shareDesktop = True;
+    viewOnly = False;
+    fullScreen = False;
+
+        //passwordFile = strdup("/home/luc/.vnc/passwd");
+        //passwordFile = strdup("/home/renambot/.vnc/passwd");
+        //passwordFile = strdup("passwd");
+    passwordFile = NULL;
+
+    passwordDialog = False;
+    useBGR233 = False;
+    nColours = 256;
+    useSharedColours = True;
+    forceOwnCmap = False;
+    forceTrueColour = False;
+    requestedDepth = 0;
+    wmDecorationWidth = 4;
+    wmDecorationHeight = 24;
+    popupButtonCount = 0;
+    debug = False;
+    rawDelay = 0;
+    copyRectDelay = 0;
+    bumpScrollTime = 25;
+    bumpScrollPixels = 20;
+
+    compressLevel   = 6;
+    qualityLevel    = 4;
+    useRemoteCursor = False;
+
+    if (argc == 2)
+    {
+        vncServerName = argv[1];
+
+        if (vncServerName[0] == '-')
+        {
+            aLog("invalid command line argument\n");
+            exit(-1);
+        }
+    }
+    
+    if (strlen(vncServerName) > 255)
+        aError("VNC server name too long\n");
+    
+    for (i = 0; vncServerName[i] != ':' && vncServerName[i] != 0; i++);
+
+    memset(vncServerHost, 0, 256);
+    strncpy(vncServerHost, vncServerName, i);
+
+    if (vncServerName[i] == ':')
+        vncServerPort = atoi(&vncServerName[i+1]);
+    else
+        vncServerPort = 0;
+
+    if (vncServerPort < 100)
+        vncServerPort += SERVER_PORT_OFFSET;
+}
Index: trunk/src/testing/app/vnc/rre.cpp
===================================================================
--- trunk/src/testing/app/vnc/rre.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/rre.cpp	(revision 4)
@@ -0,0 +1,78 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ ************************************************************************/
+
+/*
+ * rre.c - handle RRE encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles an RRE
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#ifdef HandleRREBPP
+#undef HandleRREBPP
+#endif
+#ifdef CARDBPP
+#undef CARDBPP
+#endif
+
+#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
+#define ReceiveRREBPP CONCAT2E(ReceiveRRE,BPP)
+#define flushRREBPP CONCAT2E(flushRRE,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+
+Bool
+VNCViewer::HandleRREBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
+{
+    rfbRREHeader hdr;
+    int i;
+    CARDBPP pix;
+    rfbRectangle subrect;
+
+    if (!ReadFromRFBServer((char *)&hdr, sz_rfbRREHeader))
+        return False;
+
+    hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
+
+    if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
+        return False;
+ 
+    ct->FillToScreen(pix, rx, ry, rw, rh);
+
+    for (i = 0; i < hdr.nSubrects; i++) {
+        if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
+            return False;
+
+        if (!ReadFromRFBServer((char *)&subrect, sz_rfbRectangle))
+            return False;
+
+        subrect.x = Swap16IfLE(subrect.x);
+        subrect.y = Swap16IfLE(subrect.y);
+        subrect.w = Swap16IfLE(subrect.w);
+        subrect.h = Swap16IfLE(subrect.h);
+
+        ct->FillToScreen(pix, rx + subrect.x, ry + subrect.y,
+                         subrect.w, subrect.h);
+    }
+
+    return True;
+}
+
Index: trunk/src/testing/app/vnc/Makefile
===================================================================
--- trunk/src/testing/app/vnc/Makefile	(revision 4)
+++ trunk/src/testing/app/vnc/Makefile	(revision 4)
@@ -0,0 +1,49 @@
+###################################################################
+# Makefile for VNC
+###################################################################
+
+include ../../config.mk
+
+CC=$(COMPILER)
+
+ifeq ($(MACHINE), Darwin)
+VNCTEST=/opt/local/bin/libvncserver-config
+else
+VNCTEST=/usr/bin/libvncserver-config
+endif
+
+# Test for installation of libvncserver/libvncclient
+#    otherwise, it's using the old code
+ifneq "$(wildcard $(VNCTEST) )" ""
+FILES = main.o
+CFLAGS=-DUSE_LIBVNC  $(SAGE_CFLAGS) -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS+=-lvncclient $(SAGE_LDFLAGS) -L../../lib -lsail -lz -ljpeg $(QUANTA_LDFLAGS) $(PAUDIO_LIB)
+else
+CFLAGS=$(SAGE_CFLAGS) -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS+=$(SAGE_LDFLAGS) -L../../lib -lsail -lz -ljpeg $(QUANTA_LDFLAGS) $(PAUDIO_LIB)
+FILES = d3des.o vncauth.o argsresources.o colour.o rfbproto.o sockets.o sgVNCViewer.o main.o
+endif
+
+ifeq ($(MACHINE), Darwin)
+        CFLAGS+= -I/opt/local/include
+        LIBS+= -L/opt/local/lib
+endif
+
+
+PROGRAM = VNCViewer
+
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(CC) -o $(PROGRAM) $(FILES) $(LIBS)
+
+.cpp.o :
+	$(COMPILER) $(CFLAGS) -c -o $@ $<
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
+
Index: trunk/src/testing/app/vnc/rfbproto.cpp
===================================================================
--- trunk/src/testing/app/vnc/rfbproto.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/rfbproto.cpp	(revision 4)
@@ -0,0 +1,972 @@
+/************************************************************************
+ *
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+
+/*
+ * rfbproto.c - functions to deal with client side of RFB protocol.
+ */
+
+#if defined(WIN32)
+#include <io.h>
+#include <Winsock2.h>
+#else
+#include <unistd.h>
+#include <pwd.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "sgVNCViewer.h"
+#include "vncauth.h"
+// RJ added for decrypting the password received from SAGE UI
+extern void decryptUIpass(unsigned char *outpass, unsigned char *inpass, unsigned char *key);
+extern unsigned char fixedkey[8]; // = {23,82,107,6,35,78,88,7};
+
+#if defined(WIN32)
+extern "C"
+{
+#define XMD_H
+#include "jpeglib.h"
+}
+#define strncasecmp strnicmp
+#define strcasecmp stricmp
+#include <zlib.h>
+#else
+
+#include <zlib.h>
+
+extern "C" {
+#include <jpeglib.h>
+}
+
+#endif
+
+
+#define TRUE 1
+
+/* The zlib encoding requires expansion/decompression/deflation of the
+   compressed data in the "buffer" above into another, result buffer.
+   However, the size of the result buffer can be determined precisely
+   based on the bitsPerPixel, height and width of the rectangle.  We
+   allocate this buffer one time to be the full size of the buffer. */
+
+static int raw_buffer_size = -1;
+static char *raw_buffer;
+
+static z_stream decompStream;
+static Bool decompStreamInited = False;
+
+
+/*
+ * Variables for the ``tight'' encoding implementation.
+ */
+
+/* Separate buffer for compressed data. */
+#define ZLIB_BUFFER_SIZE 512
+static char zlib_buffer[ZLIB_BUFFER_SIZE];
+
+/* Four independent compression streams for zlib library. */
+static z_stream zlibStream[4];
+static Bool zlibStreamActive[4] = {
+  False, False, False, False
+};
+
+/* Filter stuff. Should be initialized by filter initialization code. */
+static Bool cutZeros;
+static int rectWidth, rectColors;
+static char tightPalette[256*4];
+static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
+
+/* JPEG decoder state. */
+static Bool jpegError;
+
+static void JpegInitSource(j_decompress_ptr cinfo);
+static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
+static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
+static void JpegTermSource(j_decompress_ptr cinfo);
+static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
+                              int compressedLen);
+
+/*
+ * ConnectToRFBServer.
+ */
+
+Bool
+VNCViewer::ConnectToRFBServer()
+{
+    unsigned long host;
+
+    if (!StringToIPAddr(vncServerHost, &host)) {
+        aLog("Couldn't convert '%s' to host address\n", vncServerHost);
+        return False;
+    }
+
+    rfbsock = ConnectToTcpAddr(host, vncServerPort);
+
+    if (rfbsock < 0) {
+        aLog("Unable to connect to VNC server\n");
+        return False;
+    }
+        // return SetNonBlocking(rfbsock); // does not work
+    return TRUE;
+}
+
+
+/*
+ * InitialiseRFBConnection.
+ */
+
+Bool
+VNCViewer::InitialiseRFBConnection(char *pass)
+{
+    char *desktopName;
+    rfbProtocolVersionMsg pv;
+    int major,minor;
+    CARD32 authScheme, reasonLen, authResult;
+    char *reason;
+    CARD8 challenge[CHALLENGESIZE];
+    char passwd[8];
+    int i;
+    rfbClientInitMsg ci;
+
+        /* if the connection is immediately closed, don't report anything, so
+           that pmw's monitor can make test connections */
+
+    if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) return False;
+    
+    pv[sz_rfbProtocolVersionMsg] = 0;
+
+    if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
+        aLog("Not a valid VNC server\n");
+        return False;
+    }
+
+    aLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n",
+            major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+    major = rfbProtocolMajorVersion;
+    minor = rfbProtocolMinorVersion;
+
+    sprintf(pv,rfbProtocolVersionFormat,major,minor);
+
+    if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) return False;
+
+    if (!ReadFromRFBServer((char *)&authScheme, 4)) return False;
+    
+    authScheme = Swap32IfLE(authScheme);
+
+    switch (authScheme) {
+
+        case rfbConnFailed:
+            if (!ReadFromRFBServer((char *)&reasonLen, 4)) return False;
+            reasonLen = Swap32IfLE(reasonLen);
+
+            reason = (char*) malloc(reasonLen);
+
+            if (!ReadFromRFBServer(reason, reasonLen)) return False;
+
+            aLog("VNC connection failed: %.*s\n",(int)reasonLen, reason);
+            return False;
+
+        case rfbNoAuth:
+            aLog("No authentication needed\n");
+            break;
+
+        case rfbVncAuth:
+            aLog("here\n");
+            
+            if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) return False;
+            if (passwordFile) {
+                strcpy(passwd, vncDecryptPasswdFromFile(passwordFile));
+                if (!passwd) {
+                    aLog("Cannot read valid password from file \"%s\"\n",
+                            passwordFile);
+                    return False;
+                }
+            } else 
+	      {
+		// sageui will send the password as a DES encrypted string so decrypt it here
+		//decryptUIpass((unsigned char*)passwd, (unsigned char*)pass, fixedkey);
+		strcpy(passwd, pass);
+	      }
+
+            if ((!passwd) || (strlen(passwd) == 0)) {
+                aLog("Reading password failed\n");
+                return False;
+            }
+            if (strlen(passwd) > 8) {
+                passwd[8] = '\0';
+            }
+
+            vncEncryptBytes(challenge, passwd);
+                /* Lose the password from memory */
+            for (i = strlen(passwd); i >= 0; i--) {
+                passwd[i] = '\0';
+            }
+
+            if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) return False;
+
+            if (!ReadFromRFBServer((char *)&authResult, 4)) return False;
+
+            authResult = Swap32IfLE(authResult);
+
+            switch (authResult) {
+                case rfbVncAuthOK:
+                    aLog("VNC authentication succeeded\n");
+                    break;
+                case rfbVncAuthFailed:
+                    aLog("VNC authentication failed\n");
+                    return False;
+                case rfbVncAuthTooMany:
+                    aLog("VNC authentication failed - too many tries\n");
+                    return False;
+                default:
+                    aLog("Unknown VNC authentication result: %d\n",
+                            (int)authResult);
+                    return False;
+            }
+            break;
+
+        default:
+            aLog("Unknown authentication scheme from VNC server: %d\n",
+                    (int)authScheme);
+            return False;
+    }
+
+    ci.shared = (shareDesktop ? 1 : 0);
+
+    if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) return False;
+
+    if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) return False;
+
+    si.framebufferWidth = Swap16IfLE(si.framebufferWidth);
+    si.framebufferHeight = Swap16IfLE(si.framebufferHeight);
+    si.format.redMax = Swap16IfLE(si.format.redMax);
+    si.format.greenMax = Swap16IfLE(si.format.greenMax);
+    si.format.blueMax = Swap16IfLE(si.format.blueMax);
+    si.nameLength = Swap32IfLE(si.nameLength);
+
+    desktopName = (char*) malloc(si.nameLength + 1);
+
+    if (!ReadFromRFBServer(desktopName, si.nameLength)) return False;
+
+    desktopName[si.nameLength] = 0;
+
+    aLog("Desktop name \"%s\"\n",desktopName);
+    aLog("Connected to VNC server, using protocol version %d.%d\n",
+            rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+    aLog("VNC server default format:\n");
+
+    PrintPixelFormat(&si.format);
+
+    return True;
+}
+
+
+/*
+ * SetFormatAndEncodings.
+ */
+
+Bool
+VNCViewer::SetFormatAndEncodings()
+{
+    rfbSetPixelFormatMsg spf;
+    char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
+    rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
+    CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
+    int len = 0;
+    Bool requestCompressLevel = False;
+    Bool requestQualityLevel = False;
+    Bool requestLastRectEncoding = False;
+
+    spf.type            = rfbSetPixelFormat;
+    spf.format          = myFormat;
+    spf.format.redMax   = Swap16IfLE(spf.format.redMax);
+    spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
+    spf.format.blueMax  = Swap16IfLE(spf.format.blueMax);
+
+    if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg))
+        return False;
+
+    se->type = rfbSetEncodings;
+    se->nEncodings = 0;
+
+    if (encodingsString)
+    {
+        char *encStr = encodingsString;
+        int encStrLen;
+        do {
+            char *nextEncStr = strchr(encStr, ' ');
+            if (nextEncStr)
+            {
+                encStrLen = nextEncStr - encStr;
+                nextEncStr++;
+            } else
+            {
+                encStrLen = strlen(encStr);
+            }
+
+            if (strncmp(encStr,"raw",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+            } else if (strncmp(encStr,"copyrect",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+            } else if (strncasecmp(encStr,"tight",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+                requestLastRectEncoding = True;
+                if (compressLevel >= 0 && compressLevel <= 9)
+                    requestCompressLevel = True;
+                if (qualityLevel >= 0 && qualityLevel <= 9)
+                    requestQualityLevel = True;
+            } else if (strncmp(encStr,"hextile",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+            } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+                if (compressLevel >= 0 && compressLevel <= 9)
+                    requestCompressLevel = True;
+            } else if (strncmp(encStr,"corre",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
+            } else if (strncmp(encStr,"rre",encStrLen) == 0)
+            {
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
+            } else
+            {
+                aLog("Unknown encoding '%.*s'\n",encStrLen,encStr);
+            }
+            
+            encStr = nextEncStr;
+        } while (encStr && se->nEncodings < MAX_ENCODINGS);
+        
+        if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel)
+        {
+            encs[se->nEncodings++] = Swap32IfLE(compressLevel +
+                                                rfbEncodingCompressLevel0);
+        }
+        
+        if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel)
+        {
+            encs[se->nEncodings++] = Swap32IfLE(qualityLevel +
+                                                rfbEncodingQualityLevel0);
+        }
+        
+        if (useRemoteCursor)
+        {
+            if (se->nEncodings < MAX_ENCODINGS)
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
+            if (se->nEncodings < MAX_ENCODINGS)
+                encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+        }
+        
+        if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
+            encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+        }
+        
+    } else
+    {
+        if (SameMachine(rfbsock))
+        {
+            aLog("Same machine: preferring raw encoding\n");
+            encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
+        }
+
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
+
+        if (compressLevel >= 0 && compressLevel <= 9) 
+        {
+            encs[se->nEncodings++] = Swap32IfLE(compressLevel +
+                                                rfbEncodingCompressLevel0);
+        }
+        else
+        {
+            encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCompressLevel1);
+        }
+        
+        if (qualityLevel >= 0 && qualityLevel <= 9)
+        {
+            encs[se->nEncodings++] = Swap32IfLE(qualityLevel +
+                                                rfbEncodingQualityLevel0);
+        }
+
+        if (useRemoteCursor)
+        {
+            encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
+            encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
+        }
+
+        encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
+    }
+
+    len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
+
+    se->nEncodings = Swap16IfLE(se->nEncodings);
+
+    if (!WriteExact(rfbsock, buf, len)) return False;
+
+    return True;
+}
+
+
+/*
+ * SendIncrementalFramebufferUpdateRequest.
+ */
+
+Bool
+VNCViewer::SendIncrementalFramebufferUpdateRequest()
+{
+    return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
+                                        si.framebufferHeight, True);
+}
+
+
+/*
+ * SendFramebufferUpdateRequest.
+ */
+
+Bool
+VNCViewer::SendFramebufferUpdateRequest(int x, int y,
+                                        int w, int h,
+                                        Bool incremental)
+{
+    Bool res;
+    
+    rfbFramebufferUpdateRequestMsg fur;
+
+    fur.type = rfbFramebufferUpdateRequest;
+    fur.incremental = incremental ? 1 : 0;
+    fur.x = Swap16IfLE(x);
+    fur.y = Swap16IfLE(y);
+    fur.w = Swap16IfLE(w);
+    fur.h = Swap16IfLE(h);
+
+    res = WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg);
+
+    if (!res)
+        return False;
+
+    return True;
+}
+
+
+/*
+ * SendPointerEvent.
+ */
+
+Bool
+VNCViewer::SendPointerEvent(int x, int y, int buttonMask)
+{
+    rfbPointerEventMsg pe;
+
+    pe.type = rfbPointerEvent;
+    pe.buttonMask = buttonMask;
+    if (x < 0) x = 0;
+    if (y < 0) y = 0;
+    pe.x = Swap16IfLE(x);
+    pe.y = Swap16IfLE(y);
+    return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
+}
+
+
+/*
+ * SendKeyEvent.
+ */
+
+Bool
+VNCViewer::SendKeyEvent(CARD32 key, Bool down)
+{
+    rfbKeyEventMsg ke;
+
+    ke.type = rfbKeyEvent;
+    ke.down = down ? 1 : 0;
+    ke.key = Swap32IfLE(key);
+    return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
+}
+
+
+/*
+ * SendClientCutText.
+ */
+
+Bool
+VNCViewer::SendClientCutText(char *str, int len)
+{
+    rfbClientCutTextMsg cct;
+
+    if (serverCutText)
+        free(serverCutText);
+    serverCutText = NULL;
+
+    cct.type = rfbClientCutText;
+    cct.length = Swap32IfLE(len);
+    aLog( "Send SendClientCutText\n");
+    return  (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
+             WriteExact(rfbsock, str, len));
+}
+
+
+/*
+ * HandleRFBServerMessage.
+ */
+
+Bool
+VNCViewer::HandleRFBServerMessage(sgVNCViewer *ct)
+{
+    rfbServerToClientMsg msg;
+
+    fd_set fds;
+    
+    FD_ZERO(&fds);
+    FD_SET(rfbsock,&fds);
+
+    struct timeval timeout;
+    timeout.tv_usec = 5000000;
+    timeout.tv_sec  = 0;
+
+    if (!select(rfbsock+1, &fds, NULL, NULL, &timeout))
+    {
+      //fprintf(stderr, "VNC Timeout --> closing VNCViewer.\n");
+      //return False;
+      ;    
+    }
+    
+    //fprintf(stderr, "NO Timeout\n");
+    
+
+	if (!ReadFromRFBServer((char *)&msg, 1))
+    {
+        aLog("VNC> Failed to read message\n");
+        return False;
+    }
+    
+    switch (msg.type)
+    {
+        case rfbSetColourMapEntries:
+            break;
+
+        case rfbFramebufferUpdate:
+            rfbFramebufferUpdateRectHeader rect;
+            int linesToRead;
+            int bytesPerLine;
+            int i;
+
+            if (!ReadFromRFBServer(((char *)&msg.fu) + 1,
+                                   sz_rfbFramebufferUpdateMsg - 1))
+                return False;
+
+            msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
+
+            for (i = 0; i < msg.fu.nRects; i++)
+            {
+                if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
+                    return False;
+
+                rect.encoding = Swap32IfLE(rect.encoding);
+
+                if (rect.encoding == rfbEncodingLastRect)
+                    break;
+
+                rect.r.x = Swap16IfLE(rect.r.x);
+                rect.r.y = Swap16IfLE(rect.r.y);
+                rect.r.w = Swap16IfLE(rect.r.w);
+                rect.r.h = Swap16IfLE(rect.r.h);
+
+                if (rect.encoding == rfbEncodingXCursor)
+                {
+                    continue;
+                }
+                if (rect.encoding == rfbEncodingRichCursor)
+                {
+                    continue;
+                }
+
+                if ((rect.r.x + rect.r.w > si.framebufferWidth) ||
+                    (rect.r.y + rect.r.h > si.framebufferHeight))
+                {
+                    aLog("Rect too large: %dx%d at (%d, %d)\n",
+                         rect.r.w, rect.r.h, rect.r.x, rect.r.y);
+                    return False;
+                }
+
+                if ((rect.r.h * rect.r.w) == 0) {
+                    aLog("Zero size rect - ignoring\n");
+                    continue;
+                }
+
+                    // If RichCursor encoding is used, we should prevent collisions
+                    // between framebuffer updates and cursor drawing operations.
+//                  SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);
+
+                switch (rect.encoding)
+                {
+                    case rfbEncodingRaw:
+                        bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
+                        linesToRead = BUFFER_SIZE / bytesPerLine;
+
+                        while (rect.r.h > 0)
+                        {
+                            if (linesToRead > rect.r.h)
+                                linesToRead = rect.r.h;
+
+                            if (!ReadFromRFBServer(buffer,
+                                                   bytesPerLine*linesToRead))
+                                return False;
+
+                            ct->CopyDataToScreen(buffer,
+                                                 rect.r.x, rect.r.y, rect.r.w,
+                                                 linesToRead);
+
+                            rect.r.h -= linesToRead;
+                            rect.r.y += linesToRead;
+
+                        }
+                        break;
+
+                    case rfbEncodingCopyRect:
+                    {
+                        rfbCopyRect cr;
+
+                        if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect))
+                            return False;
+
+                        cr.srcX = Swap16IfLE(cr.srcX);
+                        cr.srcY = Swap16IfLE(cr.srcY);
+                        
+                            // If RichCursor encoding is used, we should extend our
+                            //  "cursor lock area" (previously set to destination
+                            // rectangle) to the source rectangle as well.
+//                        SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
+
+                        ct->RectDataToScreen(rect.r.x, rect.r.y,
+                                             rect.r.w, rect.r.h,
+                                             cr.srcX, cr.srcY);
+                        break;
+                    }
+
+                    case rfbEncodingRRE:
+                        switch (myFormat.bitsPerPixel)
+                        {
+                            case 8:
+                                if (!HandleRRE8(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 16:
+                                if (!HandleRRE16(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 32:
+                                if (!HandleRRE32(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                        }
+                        break;
+
+                    case rfbEncodingCoRRE:
+                        switch (myFormat.bitsPerPixel)
+                        {
+                            case 8:
+                                if (!HandleCoRRE8(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 16:
+                                if (!HandleCoRRE16(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 32:
+                                if (!HandleCoRRE32(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                        }
+                        break;
+
+                    case rfbEncodingHextile:
+                        switch (myFormat.bitsPerPixel)
+                        {
+                            case 8:
+                                if (!HandleHextile8(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 16:
+                                if (!HandleHextile16(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 32:
+                                if (!HandleHextile32(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                        }
+                        break;
+
+                    case rfbEncodingZlib:
+                        switch (myFormat.bitsPerPixel) {
+                            case 8:
+                                if (!HandleZlib8(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 16:
+                                if (!HandleZlib16(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 32:
+                                if (!HandleZlib32(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                        }
+                        break;
+
+                    case rfbEncodingTight:
+                        switch (myFormat.bitsPerPixel) {
+                            case 8:
+                                if (!HandleTight8(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 16:
+                                if (!HandleTight16(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                            case 32:
+                                if (!HandleTight32(ct, rect.r.x,rect.r.y,rect.r.w,rect.r.h))
+                                    return False;
+                                break;
+                        }
+                        break;
+
+                    default:
+                        aLog("Unknown rect encoding %d\n",
+                             (int)rect.encoding);
+                        return False;
+                }
+                    // Now we may discard "soft cursor locks".
+//                  SoftCursorUnlockScreen();
+                
+            }
+            
+            if (!SendIncrementalFramebufferUpdateRequest())
+            {
+                aLog("VNC> !SendIncrementalFramebufferUpdateRequest() == true\n");
+                return False;
+            }
+            
+            break;
+
+        case rfbBell:
+            break;
+
+        case rfbServerCutText:
+            if (!ReadFromRFBServer(((char *)&msg) + 1,
+                                   sz_rfbServerCutTextMsg - 1))
+                return False;
+
+            msg.sct.length = Swap32IfLE(msg.sct.length);
+
+            if (serverCutText)
+                free(serverCutText);
+
+            serverCutText = (char*) malloc(msg.sct.length+1);
+
+            if (!ReadFromRFBServer(serverCutText, msg.sct.length))
+                return False;
+
+            serverCutText[msg.sct.length] = 0;
+
+            newServerCutText = True;
+
+            break;
+
+        default:
+            aLog("Unknown message type %d from VNC server\n",msg.type);
+            return False;
+    }
+
+    return True;
+}
+
+
+#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++)
+
+#define GET_PIXEL16(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
+			       ((CARD8*)&(pix))[1] = *(ptr)++)
+
+#define GET_PIXEL32(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
+			       ((CARD8*)&(pix))[1] = *(ptr)++, \
+			       ((CARD8*)&(pix))[2] = *(ptr)++, \
+			       ((CARD8*)&(pix))[3] = *(ptr)++)
+
+/* CONCAT2 concatenates its two arguments.  CONCAT2E does the same but also
+   expands its arguments if they are macros */
+
+#define CONCAT2(a,b) a##b
+#define CONCAT2E(a,b) CONCAT2(a,b)
+
+#define BPP 8
+#include "rre.cpp"
+#include "corre.cpp"
+#include "hextile.cpp"
+#include "zlib.cpp"
+#include "tight.cpp"
+#undef BPP
+#define BPP 16
+#include "rre.cpp"
+#include "corre.cpp"
+#include "hextile.cpp"
+#include "zlib.cpp"
+#include "tight.cpp"
+#undef BPP
+#define BPP 32
+#include "rre.cpp"
+#include "corre.cpp"
+#include "hextile.cpp"
+#include "zlib.cpp"
+#include "tight.cpp"
+#undef BPP
+
+
+/*
+ * PrintPixelFormat.
+ */
+
+void
+VNCViewer::PrintPixelFormat(rfbPixelFormat *format)
+{
+    if (format->bitsPerPixel == 1)
+    {
+        aLog("  Single bit per pixel.\n");
+        aLog( "  %s significant bit in each byte is leftmost on the screen.\n",
+                (format->bigEndian ? "Most" : "Least"));
+    }
+    else
+    {
+        aLog("  %d bits per pixel.\n",format->bitsPerPixel);
+        if (format->bitsPerPixel != 8)
+        {
+            aLog("  %s significant byte first in each pixel.\n",
+                    (format->bigEndian ? "Most" : "Least"));
+        }
+        if (format->trueColour)
+        {
+            aLog("  True colour: max red %d green %d blue %d",
+                    format->redMax, format->greenMax, format->blueMax);
+            aLog(", shift red %d green %d blue %d\n",
+                    format->redShift, format->greenShift, format->blueShift);
+        }
+        else
+        {
+            aLog("  Colour map (not true colour).\n");
+        }
+    }
+}
+
+long
+VNCViewer::ReadCompactLen (void)
+{
+    long len;
+    CARD8 b;
+
+    if (!ReadFromRFBServer((char *)&b, 1))
+        return -1;
+    len = (int)b & 0x7F;
+    if (b & 0x80) {
+        if (!ReadFromRFBServer((char *)&b, 1))
+            return -1;
+        len |= ((int)b & 0x7F) << 7;
+        if (b & 0x80) {
+            if (!ReadFromRFBServer((char *)&b, 1))
+                return -1;
+            len |= ((int)b & 0xFF) << 14;
+        }
+    }
+    return len;
+}
+
+/*
+ * JPEG source manager functions for JPEG decompression in Tight decoder.
+ */
+
+static struct jpeg_source_mgr jpegSrcManager;
+static JOCTET *jpegBufferPtr;
+static size_t jpegBufferLen;
+
+static void
+JpegInitSource(j_decompress_ptr cinfo)
+{
+  jpegError = False;
+}
+
+static boolean
+JpegFillInputBuffer(j_decompress_ptr cinfo)
+{
+  jpegError = True;
+  jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+  jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+
+  return TRUE;
+}
+
+static void
+JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
+{
+  if (num_bytes < 0 || num_bytes > jpegSrcManager.bytes_in_buffer) {
+    jpegError = True;
+    jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+    jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
+  } else {
+    jpegSrcManager.next_input_byte += (size_t) num_bytes;
+    jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+static void
+JpegTermSource(j_decompress_ptr cinfo)
+{
+  /* No work necessary here. */
+}
+
+static void
+JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
+		  int compressedLen)
+{
+  jpegBufferPtr = (JOCTET *)compressedData;
+  jpegBufferLen = (size_t)compressedLen;
+
+  jpegSrcManager.init_source = JpegInitSource;
+  jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
+  jpegSrcManager.skip_input_data = JpegSkipInputData;
+  jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
+  jpegSrcManager.term_source = JpegTermSource;
+  jpegSrcManager.next_input_byte = jpegBufferPtr;
+  jpegSrcManager.bytes_in_buffer = jpegBufferLen;
+
+  cinfo->src = &jpegSrcManager;
+}
Index: trunk/src/testing/app/vnc/zlib.cpp
===================================================================
--- trunk/src/testing/app/vnc/zlib.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/zlib.cpp	(revision 4)
@@ -0,0 +1,160 @@
+/************************************************************************
+ *
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+ 
+/*
+ * zlib.c - handle zlib encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles an zlib
+ * encoded rectangle with BPP bits per pixel.
+ */
+#ifdef HandleZlibBPP
+#undef HandleZlibBPP
+#endif
+#ifdef ReceiveZlibBPP
+#undef ReceiveZlibBPP
+#endif
+
+#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
+#define ReceiveZlibBPP CONCAT2E(ReceiveZlib,BPP)
+#define flushZlibBPP CONCAT2E(flushZlib,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+
+Bool
+VNCViewer::HandleZlibBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
+{
+    rfbZlibHeader hdr;
+    int remaining;
+    int inflateResult;
+    int toRead;
+
+        /* First make sure we have a large enough raw buffer to hold the
+         * decompressed data.  In practice, with a fixed BPP, fixed frame
+         * buffer size and the first update containing the entire frame
+         * buffer, this buffer allocation should only happen once, on the
+         * first update.
+         */
+    if ( raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
+
+        if ( raw_buffer != NULL ) {
+
+            free( raw_buffer );
+
+        }
+
+        raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
+        raw_buffer = (char*) malloc( raw_buffer_size );
+
+    }
+
+    if (!ReadFromRFBServer((char *)&hdr, sz_rfbZlibHeader))
+        return False;
+
+    remaining = Swap32IfLE(hdr.nBytes);
+
+        /* Need to initialize the decompressor state. */
+    decompStream.next_in   = ( Bytef * )buffer;
+    decompStream.avail_in  = 0;
+    decompStream.next_out  = ( Bytef * )raw_buffer;
+    decompStream.avail_out = raw_buffer_size;
+    decompStream.data_type = Z_BINARY;
+
+        /* Initialize the decompression stream structures on the first invocation. */
+    if ( decompStreamInited == False ) {
+
+        inflateResult = inflateInit( &decompStream );
+
+        if ( inflateResult != Z_OK ) {
+            aLog("inflateInit returned error: %d, msg: %s\n",
+                 inflateResult, decompStream.msg);
+            return False;
+        }
+
+        decompStreamInited = True;
+
+    }
+
+    inflateResult = Z_OK;
+
+        /* Process buffer full of data until no more to process, or
+         * some type of inflater error, or Z_STREAM_END.
+         */
+    while (( remaining > 0 ) &&
+           ( inflateResult == Z_OK )) {
+  
+        if ( remaining > BUFFER_SIZE ) {
+            toRead = BUFFER_SIZE;
+        }
+        else {
+            toRead = remaining;
+        }
+
+            /* Fill the buffer, obtaining data from the server. */
+        if (!ReadFromRFBServer(buffer,toRead))
+            return False;
+
+        decompStream.next_in  = ( Bytef * )buffer;
+        decompStream.avail_in = toRead;
+
+            /* Need to uncompress buffer full. */
+        inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
+
+            /* We never supply a dictionary for compression. */
+        if ( inflateResult == Z_NEED_DICT ) {
+            aLog("zlib inflate needs a dictionary!\n");
+            return False;
+        }
+        if ( inflateResult < 0 ) {
+            aLog("zlib inflate returned error: %d, msg: %s\n",
+                 inflateResult, decompStream.msg);
+            return False;
+        }
+
+            /* Result buffer allocated to be at least large enough.  We should
+             * never run out of space!
+             */
+        if (( decompStream.avail_in > 0 ) &&
+            ( decompStream.avail_out <= 0 )) {
+            aLog("zlib inflate ran out of space!\n");
+            return False;
+        }
+
+        remaining -= toRead;
+
+    } /* while ( remaining > 0 ) */
+
+    if ( inflateResult == Z_OK ) {
+
+            /* Put the uncompressed contents of the update on the screen. */
+        ct->CopyDataToScreen(raw_buffer, rx, ry, rw, rh);
+
+    }
+    else {
+        aLog("zlib inflate returned error: %d, msg: %s\n",
+             inflateResult, decompStream.msg);
+        return False;
+
+    }
+
+    return True;
+}
+
Index: trunk/src/testing/app/vnc/d3des.cpp
===================================================================
--- trunk/src/testing/app/vnc/d3des.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/d3des.cpp	(revision 4)
@@ -0,0 +1,466 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+/* March 3, 2006
+   Modified by Ratko Jagodic
+   Added a method for using normal DES decryption where the bits of
+   every byte of the password are not mirrored.
+*/
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+static unsigned long KnR[32] = { 0L };
+static unsigned long Kn3[32] = { 0L };
+static unsigned char Df_Key[24] = {
+	0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+	0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+	0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
+
+// Ratko Jagodic changed so that bytebit can be changed later
+static unsigned short bytebitArray[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+static unsigned short *bytebit = bytebitArray;
+
+
+static unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static unsigned char totrot[16] = {
+        1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+
+
+/* Ratko Jagodic added to support normal decryption 
+   (without flipping the bits of every byte of a password)
+   more explanation here:
+   http://www.vidarholen.net/contents/junk/vnc.html
+*/
+extern void decryptUIpass(unsigned char *outpass, unsigned char *inpass, unsigned char *key);
+void decryptUIpass(unsigned char *outpass, unsigned char *inpass, unsigned char *key)
+{
+  // set the correct bit order of the password
+  unsigned short bytebitArray2[] = { 0200, 0100, 040, 020, 010, 04, 02, 01 };
+  bytebit = bytebitArray2;
+
+  // perform decryption
+  deskey(key, DE1);
+  des(inpass, outpass);
+  
+  // put back the flipped bit order for vnc usage
+  bytebit = bytebitArray;
+
+  return;
+}
+/* end edit, Ratko Jagodic */
+
+
+
+void deskey(unsigned char *key, int edf)
+	/* Thanks to James Gillogly & Phil Karn! */
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+    }
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+        }
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+        }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+        }
+    }
+	cookey(kn);
+	return;
+}
+
+static void cookey(register unsigned long *raw1)
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+    }
+	usekey(dough);
+	return;
+}
+
+void cpkey(register unsigned long *into)
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+}
+
+void usekey(register unsigned long *from)
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+}
+
+void des(unsigned char *inblock, unsigned char *outblock)
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+}
+
+static void scrunch(register unsigned char *outof, register unsigned long *into)
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+}
+
+static void unscrun(register unsigned long *outof, register unsigned char *into)
+{
+	*into++ = (unsigned char) ( (*outof >> 24) & 0xffL );
+	*into++ = (unsigned char) ( (*outof >> 16) & 0xffL );
+	*into++ = (unsigned char) ( (*outof >>  8) & 0xffL );
+	*into++ = (unsigned char) (  *outof++	 & 0xffL );
+	*into++ = (unsigned char) (  (*outof >> 24) & 0xffL );
+	*into++ = (unsigned char) (  (*outof >> 16) & 0xffL );
+	*into++ = (unsigned char) (  (*outof >>  8) & 0xffL );
+	*into	= (unsigned char) (   *outof	 & 0xffL );
+	return;
+}
+
+static unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(register unsigned long *block, register unsigned long *keys)
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+    }
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
Index: trunk/src/testing/app/vnc/hextile.cpp
===================================================================
--- trunk/src/testing/app/vnc/hextile.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/hextile.cpp	(revision 4)
@@ -0,0 +1,141 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ ************************************************************************/
+
+/*
+ * hextile.c - handle hextile encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles a hextile
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#ifdef HandleRREBPP
+#undef HandleRREBPP
+#endif
+#ifdef ReceiveRREBPP
+#undef ReceiveRREBPP
+#endif
+#ifdef flushRREBPP
+#undef flushRREBPP
+#endif
+#ifdef CARDBPP
+#undef CARDBPP
+#endif
+#ifdef HandleHextileBPP
+#undef HandleHextileBPP
+#endif
+#ifdef GET_PIXEL
+#undef GET_PIXEL
+#endif
+
+
+#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
+#define ReceiveHextileBPP CONCAT2E(ReceiveHextile,BPP)
+#define flushHextileBPP CONCAT2E(flushHextile,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
+
+Bool
+VNCViewer::HandleHextileBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
+{
+    CARDBPP bg, fg;
+    int i;
+    CARD8 *ptr;
+    int x, y, w, h;
+    int sx, sy, sw, sh;
+    CARD8 subencoding;
+    CARD8 nSubrects;
+
+    for (y = ry; y < ry+rh; y += 16) {
+        for (x = rx; x < rx+rw; x += 16) {
+            w = h = 16;
+            if (rx+rw - x < 16)
+                w = rx+rw - x;
+            if (ry+rh - y < 16)
+                h = ry+rh - y;
+
+            if (!ReadFromRFBServer((char *)&subencoding, 1))
+                return False;
+
+            if (subencoding & rfbHextileRaw) {
+                if (!ReadFromRFBServer(buffer, w * h * (BPP / 8)))
+                    return False;
+
+                ct->CopyDataToScreen(buffer, x, y, w, h);
+                continue;
+            }
+
+            if (subencoding & rfbHextileBackgroundSpecified)
+                if (!ReadFromRFBServer((char *)&bg, sizeof(bg)))
+                    return False;
+
+            ct->FillToScreen(bg, x, y, w, h);
+
+            if (subencoding & rfbHextileForegroundSpecified)
+                if (!ReadFromRFBServer((char *)&fg, sizeof(fg)))
+                    return False;
+
+            if (!(subencoding & rfbHextileAnySubrects)) {
+                continue;
+            }
+
+            if (!ReadFromRFBServer((char *)&nSubrects, 1))
+                return False;
+
+            ptr = (CARD8 *)buffer;
+
+            if (subencoding & rfbHextileSubrectsColoured) {
+                if (!ReadFromRFBServer(buffer, nSubrects * (2 + (BPP / 8))))
+                    return False;
+
+                for (i = 0; i < nSubrects; i++) {
+                    GET_PIXEL(fg, ptr);
+                    sx = rfbHextileExtractX(*ptr);
+                    sy = rfbHextileExtractY(*ptr);
+                    ptr++;
+                    sw = rfbHextileExtractW(*ptr);
+                    sh = rfbHextileExtractH(*ptr);
+                    ptr++;
+
+                    ct->FillToScreen(fg, x+sx, y+sy, sw, sh);
+                }
+
+            } else {
+                if (!ReadFromRFBServer(buffer, nSubrects * 2))
+                    return False;
+
+                for (i = 0; i < nSubrects; i++) {
+                    sx = rfbHextileExtractX(*ptr);
+                    sy = rfbHextileExtractY(*ptr);
+                    ptr++;
+                    sw = rfbHextileExtractW(*ptr);
+                    sh = rfbHextileExtractH(*ptr);
+                    ptr++;
+
+                    ct->FillToScreen(fg, x+sx, y+sy, sw, sh);
+                }
+            }
+        }
+    }
+
+    return True;
+}
+
Index: trunk/src/testing/app/vnc/rfbproto.h
===================================================================
--- trunk/src/testing/app/vnc/rfbproto.h	(revision 4)
+++ trunk/src/testing/app/vnc/rfbproto.h	(revision 4)
@@ -0,0 +1,783 @@
+/*
+ *  Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
+ *  Copyright (C) 2000 Tridia Corporation.  All Rights Reserved.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol version 3.3
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct {
+
+    CARD8 bitsPerPixel;		/* 8,16,32 only */
+
+    CARD8 depth;		/* 8 to 32 */
+
+    CARD8 bigEndian;		/* True if multi-byte pixels are interpreted
+				   as big endian, or if single-bit-per-pixel
+				   has most significant bit of the byte
+				   corresponding to first (leftmost) pixel. Of
+				   course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;		/* If false then we need a "colour map" to
+				   convert pixels to RGB.  If true, xxxMax and
+				   xxxShift specify bits used for red, green
+				   and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;		/* maximum red value (= 2^n - 1 where n is the
+				   number of bits used for red). Note this
+				   value is always in big endian order. */
+
+    CARD16 greenMax;		/* similar for green */
+
+    CARD16 blueMax;		/* and blue */
+
+    CARD8 redShift;		/* number of shifts needed to get the red
+				   value in a pixel to the least significant
+				   bit. To find the red value from a given
+				   pixel, do the following:
+				   1) Swap pixel value according to bigEndian
+				      (e.g. if bigEndian is false and host byte
+				      order is big endian, then swap).
+				   2) Shift right by redShift.
+				   3) AND with redMax (in host byte order).
+				   4) You now have the red value between 0 and
+				      redMax. */
+
+    CARD8 greenShift;		/* similar for green */
+
+    CARD8 blueShift;		/* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.3
+ * this is "RFB 003.003\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];	/* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * Authentication
+ *
+ * Once the protocol version has been decided, the server then sends a 32-bit
+ * word indicating whether any authentication is needed on the connection.
+ * The value of this word determines the authentication scheme in use.  For
+ * version 3.0 of the protocol this may have one of the following values:
+ */
+
+#define rfbConnFailed 0
+#define rfbNoAuth 1
+#define rfbVncAuth 2
+
+/*
+ * rfbConnFailed:	For some reason the connection failed (e.g. the server
+ *			cannot support the desired protocol version).  This is
+ *			followed by a string describing the reason (where a
+ *			string is specified as a 32-bit length followed by that
+ *			many ASCII characters).
+ *
+ * rfbNoAuth:		No authentication is needed.
+ *
+ * rfbVncAuth:		The VNC authentication scheme is to be used.  A 16-byte
+ *			challenge follows, which the client encrypts as
+ *			appropriate using the password and sends the resulting
+ *			16-byte response.  If the response is correct, the
+ *			server sends the 32-bit word rfbVncAuthOK.  If a simple
+ *			failure happens, the server sends rfbVncAuthFailed and
+ *			closes the connection. If the server decides that too
+ *			many failures have occurred, it sends rfbVncAuthTooMany
+ *			and closes the connection.  In the latter case, the
+ *			server should not allow an immediate reconnection by
+ *			the client.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;	/* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1	/* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+
+
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw 0
+#define rfbEncodingCopyRect 1
+#define rfbEncodingRRE 2
+#define rfbEncodingCoRRE 4
+#define rfbEncodingHextile 5
+#define rfbEncodingZlib 6
+#define rfbEncodingTight 7
+#define rfbEncodingZlibHex 8
+
+
+/*
+ * Special encoding numbers:
+ *   0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
+ *   0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data;
+ *   0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions;
+ *   0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet;
+ *   0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor;
+ *   0xFFFFFFF0 .. 0xFFFFFFFF -- cross-encoding compression levels.
+ */
+
+#define rfbEncodingCompressLevel0  0xFFFFFF00
+#define rfbEncodingCompressLevel1  0xFFFFFF01
+#define rfbEncodingCompressLevel2  0xFFFFFF02
+#define rfbEncodingCompressLevel3  0xFFFFFF03
+#define rfbEncodingCompressLevel4  0xFFFFFF04
+#define rfbEncodingCompressLevel5  0xFFFFFF05
+#define rfbEncodingCompressLevel6  0xFFFFFF06
+#define rfbEncodingCompressLevel7  0xFFFFFF07
+#define rfbEncodingCompressLevel8  0xFFFFFF08
+#define rfbEncodingCompressLevel9  0xFFFFFF09
+
+#define rfbEncodingXCursor         0xFFFFFF10
+#define rfbEncodingRichCursor      0xFFFFFF11
+
+#define rfbEncodingLastRect        0xFFFFFF20
+
+#define rfbEncodingQualityLevel0   0xFFFFFFE0
+#define rfbEncodingQualityLevel1   0xFFFFFFE1
+#define rfbEncodingQualityLevel2   0xFFFFFFE2
+#define rfbEncodingQualityLevel3   0xFFFFFFE3
+#define rfbEncodingQualityLevel4   0xFFFFFFE4
+#define rfbEncodingQualityLevel5   0xFFFFFFE5
+#define rfbEncodingQualityLevel6   0xFFFFFFE6
+#define rfbEncodingQualityLevel7   0xFFFFFFE7
+#define rfbEncodingQualityLevel8   0xFFFFFFE8
+#define rfbEncodingQualityLevel9   0xFFFFFFE9
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct {
+    rfbRectangle r;
+    CARD32 encoding;	/* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw			(1 << 0)
+#define rfbHextileBackgroundSpecified	(1 << 1)
+#define rfbHextileForegroundSpecified	(1 << 2)
+#define rfbHextileAnySubrects		(1 << 3)
+#define rfbHextileSubrectsColoured	(1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * zlib - zlib compressed Encoding.  We have an rfbZlibHeader structure
+ * giving the number of bytes following.  Finally the data follows is
+ * zlib compressed version of the raw pixel data as negotiated.
+ */
+
+typedef struct {
+    CARD32 nBytes;
+} rfbZlibHeader;
+
+#define sz_rfbZlibHeader 4
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Tight Encoding.  FIXME: Add more documentation.
+ */
+
+#define rfbTightExplicitFilter         0x04
+#define rfbTightFill                   0x08
+#define rfbTightJpeg                   0x09
+#define rfbTightMaxSubencoding         0x09
+
+/* Filters to improve compression efficiency */
+#define rfbTightFilterCopy             0x00
+#define rfbTightFilterPalette          0x01
+#define rfbTightFilterGradient         0x02
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * XCursor encoding. This is a special encoding used to transmit X-style
+ * cursor shapes from server to clients. Note that for this encoding,
+ * coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot
+ * position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB
+ * samples are sent after header in the rfbXCursorColors structure. They
+ * denote foreground and background colors of the cursor. If a client
+ * supports only black-and-white cursors, it should ignore these colors and
+ * assume that foreground is black and background is white. Next, two bitmaps
+ * (1 bits per pixel) follow: first one with actual data (value 0 denotes
+ * background color, value 1 denotes foreground color), second one with
+ * transparency data (bits with zero value mean that these pixels are
+ * transparent). Both bitmaps represent cursor data in a byte stream, from
+ * left to right, from top to bottom, and each row is byte-aligned. Most
+ * significant bits correspond to leftmost pixels. The number of bytes in
+ * each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor
+ * should be hidden (or default local cursor should be set by the client).
+ */
+
+typedef struct {
+    CARD8 foreRed;
+    CARD8 foreGreen;
+    CARD8 foreBlue;
+    CARD8 backRed;
+    CARD8 backGreen;
+    CARD8 backBlue;
+} rfbXCursorColors;
+
+#define sz_rfbXCursorColors 6
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RichCursor encoding. This is a special encoding used to transmit cursor
+ * shapes from server to clients. It is similar to the XCursor encoding but
+ * uses client pixel format instead of two RGB colors to represent cursor
+ * image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader
+ * structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h).
+ * After header, two pixmaps follow: first one with cursor image in current
+ * client pixel format (like in raw encoding), second with transparency data
+ * (1 bit per pixel, exactly the same format as used for transparency bitmap
+ * in the XCursor encoding). If (w * h == 0), cursor should be hidden (or
+ * default local cursor should be set by the client).
+ */
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbSetColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace		0xff08
+ * Tab			0xff09
+ * Return or Enter	0xff0d
+ * Escape		0xff1b
+ * Insert		0xff63
+ * Delete		0xffff
+ * Home			0xff50
+ * End			0xff57
+ * Page Up		0xff55
+ * Page Down		0xff56
+ * Left			0xff51
+ * Up			0xff52
+ * Right		0xff53
+ * Down			0xff54
+ * F1			0xffbe
+ * F2			0xffbf
+ * ...			...
+ * F12			0xffc9
+ * Shift		0xffe1
+ * Control		0xffe3
+ * Meta			0xffe7
+ * Alt			0xffe9
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbKeyEvent */
+    CARD8 down;			/* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;			/* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbPointerEvent */
+    CARD8 buttonMask;		/* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;			/* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+} rfbClientToServerMsg;
+
Index: trunk/src/testing/app/vnc/sgVNCViewer.cpp
===================================================================
--- trunk/src/testing/app/vnc/sgVNCViewer.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/sgVNCViewer.cpp	(revision 4)
@@ -0,0 +1,295 @@
+/*****************************************************************************************
+ * VNCViewer for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about VNCViewer for SAGE to www.evl.uic.edu/cavern/forum
+ *****************************************************************************************/
+
+#include "sgVNCViewer.h"
+
+
+static int ok = 0;
+
+
+void aLog(const char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+    fprintf(stderr, "%s", line);
+}
+
+void aError(const char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+	fprintf(stderr,"ERROR: %s\n",line);
+
+#if defined(WIN32)
+        // Open a dialog
+	MessageBox(0, line, "Log Message", MB_OK);
+#endif
+        // Quit
+	exit(-1);
+}
+
+
+static int
+NextPower(int val)
+{
+    int res;
+    float tmp;
+
+    res = 0;
+    tmp = (float) val;
+    while (tmp > 1.0)
+    {
+        tmp /= 2.0;
+        res ++;
+    }
+    res = 1 << res;
+    return res;
+}
+
+
+sgVNCViewer::sgVNCViewer(char *host, int display, int _ox, int _oy, int _sw, int _sh, char *passwd)
+{
+    char dest[256];
+    VNC = new VNCViewer;
+
+#if defined(WIN32)
+    InitWinsock();
+#endif
+
+    hostname = strdup( host );
+    password = strdup( passwd );
+    displaynumber = display;
+    sprintf(dest, "%s:%d", hostname, displaynumber);
+    
+    int argc = 2;
+    char *argv[2];
+    argv[0] = strdup ( "viewer" );   // program name
+    argv[1] = strdup ( dest );       // display name
+    
+    
+        // Connection to the server
+    VNC->GetArgsAndResources(argc, argv);
+
+    if (!VNC->ConnectToRFBServer())
+	 aError("ConnectToRFBServer\n");
+    
+    if (!VNC->InitialiseRFBConnection(password))
+        aError("InitialiseRFBConnection\n");
+
+    VNC->SetVisualAndCmap();
+    VNC->SetFormatAndEncodings();
+    aLog("Framebuffer width %d , height %d\n",
+         VNC->si.framebufferWidth, VNC->si.framebufferHeight);
+
+        // Building the visualization
+    ox = _ox;
+    oy = _oy;
+    sw = _sw;
+    sh = _sh;
+
+    rectData = 0;
+    screen_back = (uchar* )malloc(sw * sh * 4);
+    memset(screen_back, 0, sw * sh * 4);
+    screen_front = (uchar* )malloc(sw * sh * 4);
+    memset(screen_front, 0, sw * sh * 4);
+
+        // First update from VNC server
+    VNC->SendFramebufferUpdateRequest(ox, oy, sw, sh, False);
+    
+    rectData = 0;
+    
+    focus = 0;    // Tracker inside, i.e. the mouse
+    bstate = 0;   // button state
+
+        // No update yet
+    ok = 0;
+
+    Step();
+}
+
+sgVNCViewer::~sgVNCViewer()
+{
+    delete VNC;
+    
+}
+
+
+
+void sgVNCViewer::SendKey(unsigned long key, int down)
+{
+    //aLog("sending key %d (%d)\n", key, down);
+    
+    VNC->SendKeyEvent(key, down);
+}
+
+void sgVNCViewer::SendMouse(int x, int y, int button)
+{
+  int mask;
+
+  switch (button)
+    {
+    case MK_LEFT:
+      mask = 1;
+      break;
+    case MK_RIGHT:
+      mask = 2;
+      break;
+    case MK_MIDDLE:
+      mask = 4;
+      break;
+    default:
+      mask = 0;
+      break;
+    }
+  //aLog("sending mouse %d\n", mask);
+  
+  VNC->SendPointerEvent(x, y, mask);
+}
+
+
+uchar*
+sgVNCViewer::Data()
+{
+    return screen_front;
+}
+
+bool
+sgVNCViewer::Step()
+{
+    if (VNC->HandleRFBServerMessage(this))
+    {
+            // Copy into main memory
+        memcpy(screen_front, screen_back, sw*sh*4);
+        
+        rectData = 1;
+        VNC->SendFramebufferUpdateRequest(ox, oy, sw, sh, True);
+	return true;
+    }
+    return false;
+    
+}
+
+void
+sgVNCViewer::CopyDataToScreen(char *buf, int x, int y, int width, int height)
+{
+    x -= ox;
+    y -= oy;
+    
+        
+#if defined(WIN32)
+    if (VNC->rawDelay != 0) Sleep(VNC->rawDelay);
+#else
+        //if (VNC->rawDelay != 0) usleep(VNC->rawDelay*1000);
+#endif
+
+    if (!VNC->useBGR233)
+    {
+        int h;
+        uchar *src, *scr;
+        scr = &screen_back[y*sw*4+x*4];
+        src = (uchar*) buf;
+        for (h = 0; h < height; h++)
+        {
+            memcpy(scr, src, width*4);
+            src += width*4;
+            scr += sw*4;
+        }
+    }
+}
+
+void
+sgVNCViewer::FillToScreen(CARD32 pix, int x, int y, int width, int height)
+{
+    x -= ox;
+    y -= oy;
+    
+#if defined(WIN32)
+    if (VNC->rawDelay != 0) Sleep(VNC->rawDelay);
+#else
+            //if (VNC->rawDelay != 0) usleep(VNC->rawDelay*1000);
+#endif
+    if (!VNC->useBGR233)
+    {
+        int h,i;
+        uchar *src, *scr;
+
+        scr = &screen_back[y*sw*4+x*4];
+        src = (uchar*) pix;
+        for (h = 0; h < height; h++)
+        {
+                //memcpy(scr, src, width*4);
+            for (i = 0; i<width;i++)
+                memcpy(&scr[i*4], &pix, 4);;
+            
+            src += width*4;
+            scr += sw*4;
+        }
+	}
+}
+
+void
+sgVNCViewer::RectDataToScreen(int x, int y, int w, int h, int orix, int oriy)
+{
+    
+    x -= ox;
+    y -= oy;
+    orix -= ox;
+    oriy -= oy;
+    if (rectData)
+    {
+            // Prepare double buffer
+        memcpy(screen_front, screen_back, sw*sh*4);
+        rectData = 0;
+    }
+   
+    uchar *scr = &screen_back[y*sw*4+x*4];
+    uchar *src = &screen_front[oriy*sw*4+orix*4];
+    for (int _h = 0; _h < h; _h++)
+    {
+        memcpy(scr, src, w*4);
+        src += sw*4;
+        scr += sw*4;
+    }
+}
+
Index: trunk/src/testing/app/vnc/colour.cpp
===================================================================
--- trunk/src/testing/app/vnc/colour.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/colour.cpp	(revision 4)
@@ -0,0 +1,111 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ ************************************************************************/
+ 
+/*
+ * colour.c - functions to deal with colour - i.e. RFB pixel formats, X visuals
+ * and colormaps.  Thanks to Grant McDorman for some of the ideas used here.
+ */
+
+#include "vncviewer.h"
+#include <limits.h>
+
+
+#define INVALID_PIXEL 0xffffffff
+#define MAX_CMAP_SIZE 256
+
+/*
+ * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
+ * equivalent to the RFB protocol's "pixel format").  Having decided on the
+ * best visual, it also creates a colormap if necessary, sets the appropriate
+ * resources on the toplevel widget, and sets up the myFormat structure to
+ * describe the pixel format in terms that the RFB server will be able to
+ * understand.
+ *
+ * The algorithm for deciding which visual to use is as follows:
+ *
+ * If forceOwnCmap is true then we try to use a PseudoColor visual - we first
+ * see if there's one of the same depth as the RFB server, followed by an 8-bit
+ * deep one.
+ *
+ * If forceTrueColour is true then we try to use a TrueColor visual - if
+ * requestedDepth is set then it must be of that depth, otherwise any depth
+ * will be used.
+ *
+ * Otherwise, we use the X server's default visual and colormap.  If this is
+ * TrueColor then we just ask the RFB server for this format.  If the default
+ * isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
+ * BGR233 pixel format and use a lookup table to translate to the nearest
+ * colours provided by the X server.
+ */
+
+void
+VNCViewer::SetVisualAndCmap()
+{
+    if (forceOwnCmap) {
+        if (!si.format.trueColour) {
+                //if (GetPseudoColorVisualAndCmap(si.format.depth))	return;
+        }
+            //if (GetPseudoColorVisualAndCmap(8)) return;
+        aLog("Couldn't find a matching PseudoColor visual.\n");
+    }
+
+    if (forceTrueColour) {
+            // if (GetTrueColorVisualAndCmap(appData.requestedDepth)) return;
+        aLog("Couldn't find a matching TrueColor visual.\n");
+    }
+
+        /* just use default visual and colormap */
+
+    if (!useBGR233)
+    {
+        myFormat.bitsPerPixel = 32;
+        myFormat.depth = 24;
+        myFormat.trueColour = 1;
+            //myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
+        myFormat.bigEndian = 0;
+
+        myFormat.redShift = 0;
+        myFormat.greenShift = 8;
+        myFormat.blueShift = 16;
+        myFormat.redMax = 255;
+        myFormat.greenMax = 255;
+        myFormat.blueMax = 255;
+
+        aLog("Using default colormap which is TrueColor.  Pixel format:\n");
+        PrintPixelFormat(&myFormat);
+        return;
+    }
+
+    useBGR233 = True;
+
+    myFormat.bitsPerPixel = 8;
+    myFormat.depth = 8;
+    myFormat.trueColour = 1;
+    myFormat.bigEndian = 0;
+    myFormat.redMax = 7;
+    myFormat.greenMax = 7;
+    myFormat.blueMax = 3;
+    myFormat.redShift = 0;
+    myFormat.greenShift = 3;
+    myFormat.blueShift = 6;
+
+    aLog("Using default colormap and translating from BGR233.  Pixel format:\n");
+    PrintPixelFormat(&myFormat);
+}
Index: trunk/src/testing/app/vnc/d3des.h
===================================================================
--- trunk/src/testing/app/vnc/d3des.h	(revision 4)
+++ trunk/src/testing/app/vnc/d3des.h	(revision 4)
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* d3des.h -
+ *
+ *	Headers and defines for d3des.c
+ *	Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *	(GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0	0	/* MODE == encrypt */
+#define DE1	1	/* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/*		      hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/*		    cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/*		   cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/*		    from[8]	      to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
Index: trunk/src/testing/app/vnc/sgVNCViewer.h
===================================================================
--- trunk/src/testing/app/vnc/sgVNCViewer.h	(revision 4)
+++ trunk/src/testing/app/vnc/sgVNCViewer.h	(revision 4)
@@ -0,0 +1,87 @@
+/*****************************************************************************************
+ * VNCViewer for SAGE
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about VNCViewer for SAGE to www.evl.uic.edu/cavern/forum
+ *****************************************************************************************/
+
+
+#ifndef _AURA_H_sgVNCViewer
+#define _AURA_H_sgVNCViewer
+
+#include "vncviewer.h"
+
+
+#define CMD_UPDATE 0xDE50001
+
+#if defined(WIN32)
+void InitWinsock();
+#endif
+
+// [M]ouse buttons
+#define MK_NOTHING 0x0000
+#define MK_LEFT    0x0001
+#define MK_RIGHT   0x0002
+#define MK_MIDDLE  0x0003
+
+
+class sgVNCViewer
+{
+protected:
+    int ox, oy;     // origin of the tile
+    int sw, sh;     // size of the tile
+
+    char *hostname;
+    char *password;
+    int displaynumber;
+    int focus;
+    int bstate;
+    
+    VNCViewer *VNC;
+    uchar *screen_back;
+    uchar *screen_front;
+    int rectData;
+
+public:
+    sgVNCViewer(char *host, int display, int _ox, int _oy, int _sw, int _sh, char *passwd);
+    ~sgVNCViewer();
+
+    virtual bool Step();
+    uchar *Data();
+    
+    void CopyDataToScreen(char *buf, int x, int y, int width, int height);
+    void RectDataToScreen(int x, int y, int w, int h, int ox, int oy);
+    void FillToScreen(CARD32 pix, int x, int y, int width, int height);
+    void SendKey(unsigned long key, int down);
+    void SendMouse(int x, int y, int button);
+
+};
+
+#endif
Index: trunk/src/testing/app/vnc/vncauth.cpp
===================================================================
--- trunk/src/testing/app/vnc/vncauth.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/vncauth.cpp	(revision 4)
@@ -0,0 +1,180 @@
+/*
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * vncauth.c - Functions for VNC password management and authentication.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(WIN32)
+#include <io.h>
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "vncauth.h"
+#include "d3des.h"
+
+
+/*
+ * We use a fixed key to store passwords, since we assume that our local
+ * file system is secure but nonetheless don't want to store passwords
+ * as plaintext.
+ */
+
+unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
+
+
+/*
+ * Encrypt a password and store it in a file.  Returns 0 if successful,
+ * 1 if the file could not be written.
+ */
+
+int
+vncEncryptAndStorePasswd(char *passwd, char *fname)
+{
+    FILE *fp;
+    int i;
+    unsigned char encryptedPasswd[8];
+
+    if ((fp = fopen(fname,"w")) == NULL) return 1;
+
+#if defined(WIN32)
+    _chmod(fname, _S_IREAD | _S_IWRITE);
+#else
+    chmod(fname, S_IRUSR|S_IWUSR);
+#endif
+
+    /* pad password with nulls */
+
+    for (i = 0; i < 8; i++) {
+		if (i < (int)strlen(passwd)) {
+			encryptedPasswd[i] = passwd[i];
+		} else {
+			encryptedPasswd[i] = 0;
+		}
+    }
+
+    /* Do encryption in-place - this way we overwrite our copy of the plaintext
+       password */
+
+    deskey(fixedkey, EN0);
+    des(encryptedPasswd, encryptedPasswd);
+
+    for (i = 0; i < 8; i++) {
+	putc(encryptedPasswd[i], fp);
+    }
+  
+    fclose(fp);
+    return 0;
+}
+
+
+/*
+ * Decrypt a password from a file.  Returns a pointer to a newly allocated
+ * string containing the password or a null pointer if the password could
+ * not be retrieved for some reason.
+ */
+
+char *
+vncDecryptPasswdFromFile(char *fname)
+{
+    FILE *fp;
+    int i, ch;
+    unsigned char *passwd = (unsigned char *)malloc(9);
+
+    if ((fp = fopen(fname,"r")) == NULL) return NULL;
+
+    for (i = 0; i < 8; i++) {
+        ch = getc(fp);
+        if (ch == EOF) {
+            fclose(fp);
+            return NULL;
+        }
+        passwd[i] = ch;
+    }
+
+    fclose(fp);
+
+    deskey(fixedkey, DE1);
+    des(passwd, passwd);
+
+    passwd[8] = 0;
+
+    return (char *)passwd;
+}
+
+
+/*
+ * Generate CHALLENGESIZE random bytes for use in challenge-response
+ * authentication.
+ */
+
+void
+vncRandomBytes(unsigned char *bytes)
+{
+    int i;
+    unsigned int seed = (unsigned int) time(0);
+
+#if defined(WIN32)
+    srand(seed);
+#else
+    srandom(seed);
+#endif
+    for (i = 0; i < CHALLENGESIZE; i++) {
+#if defined(WIN32)
+		bytes[i] = (unsigned char)(rand() & 255);    
+#else
+		bytes[i] = (unsigned char)(random() & 255);    
+#endif
+    }
+}
+
+
+/*
+ * Encrypt CHALLENGESIZE bytes in memory using a password.
+ */
+
+void
+vncEncryptBytes(unsigned char *bytes, char *passwd)
+{
+    unsigned char key[8];
+    int i;
+
+    /* key is simply password padded with nulls */
+
+    for (i = 0; i < 8; i++) {
+		if (i < (int)strlen(passwd)) {
+			key[i] = passwd[i];
+		} else {
+			key[i] = 0;
+		}
+    }
+
+    deskey(key, EN0);
+
+    for (i = 0; i < CHALLENGESIZE; i += 8) {
+	des(bytes+i, bytes+i);
+    }
+}
Index: trunk/src/testing/app/vnc/corre.cpp
===================================================================
--- trunk/src/testing/app/vnc/corre.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/corre.cpp	(revision 4)
@@ -0,0 +1,87 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ ************************************************************************/
+ 
+/*
+ * corre.c - handle CoRRE encoding.
+ *
+ * This file shouldn't be compiled directly.  It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP.  For
+ * each value of BPP, this file defines a function which handles a CoRRE
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#ifdef HandleRREBPP
+#undef HandleRREBPP
+#endif
+#ifdef ReceiveRREBPP
+#undef ReceiveeRREBPP
+#endif
+#ifdef flushRREBPP
+#undef flushRREBPP
+#endif
+#ifdef CARDBPP
+#undef CARDBPP
+#endif
+#ifdef HandleCoRREBPP
+#undef HandleCoRREBPP
+#endif
+
+#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
+#define ReceiveCoRREBPP CONCAT2E(ReceiveCoRRE,BPP)
+#define flushCoRREBPP CONCAT2E(flushCoRRE,BPP)
+#define CARDBPP CONCAT2E(CARD,BPP)
+
+Bool
+VNCViewer::HandleCoRREBPP (sgVNCViewer *ct, int rx, int ry, int rw, int rh)
+{
+    rfbRREHeader hdr;
+    int i;
+    CARDBPP pix;
+    CARD8 *ptr;
+    int x, y, w, h;
+
+    if (!ReadFromRFBServer((char *)&hdr, sz_rfbRREHeader))
+        return False;
+
+    hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
+
+    if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
+        return False;
+
+    ct->FillToScreen(pix, rx, ry, rw, rh);
+
+    if (!ReadFromRFBServer(buffer, hdr.nSubrects * (4 + (BPP / 8))))
+        return False;
+
+    ptr = (CARD8 *)buffer;
+
+    for (i = 0; i < hdr.nSubrects; i++) {
+        pix = *(CARDBPP *)ptr;
+        ptr += BPP/8;
+        x = *ptr++;
+        y = *ptr++;
+        w = *ptr++;
+        h = *ptr++;
+
+        ct->FillToScreen(pix, rx + x, ry + y, w, h);
+    }
+    return True;
+}
+
Index: trunk/src/testing/app/vnc/sockets.cpp
===================================================================
--- trunk/src/testing/app/vnc/sockets.cpp	(revision 4)
+++ trunk/src/testing/app/vnc/sockets.cpp	(revision 4)
@@ -0,0 +1,408 @@
+/************************************************************************
+ *
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+ 
+/*
+ * sockets.c - functions to deal with sockets.
+ */
+
+#include "vncviewer.h"
+
+#if defined(WIN32)
+#include <Winsock2.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#endif
+
+#if defined(__sun)
+#include <sys/filio.h> 
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned long) -1)
+#endif
+#endif
+
+#include <errno.h>
+#include <assert.h>
+
+
+
+#if defined(WIN32)
+void InitWinsock()
+{
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int err;
+ 
+    wVersionRequested = MAKEWORD( 2, 2 );
+ 
+    err = WSAStartup(wVersionRequested, &wsaData);
+    if (err != 0)
+	{
+		aError("Cannot load the valid winsock 2 dll\n");
+        exit(1);
+    }
+}
+#endif
+
+
+/*
+ * ReadFromRFBServer is called whenever we want to read some data from the RFB
+ * server.  It is non-trivial for two reasons:
+ *
+ * 1. For efficiency it performs some intelligent buffering, avoiding invoking
+ *    the read() system call too often.  For small chunks of data, it simply
+ *    copies the data out of an internal buffer.  For large amounts of data it
+ *    reads directly into the buffer provided by the caller.
+ *
+ * 2. Whenever read() would block, it invokes the Xt event dispatching
+ *    mechanism to process X events.  In fact, this is the only place these
+ *    events are processed, as there is no XtAppMainLoop in the program.
+ */
+
+
+Bool
+VNCViewer::ReadFromRFBServer(char *out, unsigned int n)
+{
+    if (n <= buffered)
+    {
+        memcpy(out, bufoutptr, n);
+        bufoutptr += n;
+        buffered -= n;
+        return True;
+    }
+
+    memcpy(out, bufoutptr, buffered);
+
+    out += buffered;
+    n -= buffered;
+
+    bufoutptr = buf;
+    buffered = 0;
+
+    if (n <= BUF_SIZE) {
+
+        while (buffered < n) {
+#if defined(WIN32)
+            int i = recv(rfbsock, buf + buffered, BUF_SIZE - buffered,0);
+#else
+            int i = read(rfbsock, buf + buffered, BUF_SIZE - buffered);
+#endif
+            if (i <= 0) {
+                if (i < 0) {
+                    if (errno == EAGAIN) {
+                        i = 0;
+                    } else {
+                        aLog("error : read1 -- i %d errno %d rfbsock %d\n",
+								i, errno, rfbsock);
+                        return False;
+                    }
+                } else {
+                    aLog("VNC server closed connection\n");
+                    return False;
+                }
+            }
+            buffered += i;
+        }
+
+        memcpy(out, bufoutptr, n);
+        bufoutptr += n;
+        buffered -= n;
+        return True;
+
+    } else
+    {
+        while (n > 0) {
+#if defined(WIN32)
+            int i = recv(rfbsock, out, n, 0);
+#else
+            int i = read(rfbsock, out, n);
+#endif
+            if (i <= 0) {
+                if (i < 0) {
+                    if (errno == EAGAIN) {
+                        i = 0;
+                    } else {
+                        aLog("error : read2 -- i %d errno %d\n", i, errno);
+                        return False;
+                    }
+                } else {
+                    aLog("VNC server closed connection\n");
+                    return False;
+                }
+            }
+            out += i;
+            n -= i;
+        }
+
+        return True;
+    }
+}
+
+
+/*
+ * Write an exact number of bytes, and don't return until you've sent them.
+ */
+
+Bool
+WriteExact(int sock, char *buf, int n)
+{
+    fd_set fds;
+    int i = 0;
+    int j;
+
+    while (i < n) {
+#if defined(WIN32)
+        j = send (sock, buf + i, (n - i), 0);
+#else
+        j = write(sock, buf + i, (n - i));
+#endif
+        if (j <= 0) {
+            if (j < 0) {
+                if (errno == EAGAIN) {
+                    FD_ZERO(&fds);
+                    FD_SET(sock,&fds);
+
+                    if (select(sock+1, NULL, &fds, NULL, NULL) <= 0) {
+                        aLog("error : select");
+                        return False;
+                    }
+                    j = 0;
+                } else {
+                    aLog("error : write");
+                    return False;
+                }
+            } else {
+                aLog("write failed\n");
+                return False;
+            }
+        }
+        i += j;
+    }
+    return True;
+}
+
+
+/*
+ * ConnectToTcpAddr connects to the given TCP port.
+ */
+
+
+int
+ConnectToTcpAddr(unsigned int host, int port)
+{
+    int sock;
+    struct sockaddr_in addr;
+    int one = 1;
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = host;
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        aLog("ConnectToTcpAddr: socket\n" );
+        return -1;
+    }
+
+    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        aLog("ConnectToTcpAddr: connect");
+        close(sock);
+        return -1;
+    }
+
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+                   (char *)&one, sizeof(one)) < 0) {
+        aLog("ConnectToTcpAddr: setsockopt");
+        close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+
+
+/*
+ * ListenAtTcpPort starts listening at the given TCP port.
+ */
+
+int
+ListenAtTcpPort(int port)
+{
+    int sock;
+    struct sockaddr_in addr;
+    int one = 1;
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = INADDR_ANY;
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+		aLog("ListenAtTcpPort: socket");
+        return -1;
+    }
+
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                   (const char *)&one, sizeof(one)) < 0) {
+        aLog("ListenAtTcpPort: setsockopt");
+        close(sock);
+        return -1;
+    }
+
+    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        aLog("ListenAtTcpPort: bind");
+        close(sock);
+        return -1;
+    }
+
+    if (listen(sock, 5) < 0) {
+        aLog("ListenAtTcpPort: listen");
+        close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+
+/*
+ * AcceptTcpConnection accepts a TCP connection.
+ */
+
+int
+AcceptTcpConnection(int listenSock)
+{
+    int sock;
+    struct sockaddr_in addr;
+#if defined(WIN32)
+    int addrlen = sizeof(addr);
+#else
+    socklen_t addrlen = sizeof(addr);
+#endif
+    int one = 1;
+
+    sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
+    if (sock < 0) {
+		aLog("AcceptTcpConnection: accept");
+        return -1;
+    }
+
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+                   (char *)&one, sizeof(one)) < 0) {
+        aLog("AcceptTcpConnection: setsockopt");
+        close(sock);
+        return -1;
+    }
+
+    return sock;
+}
+
+
+/*
+ * SetNonBlocking sets a socket into non-blocking mode.
+ */
+
+Bool
+SetNonBlocking(int sock)
+{
+#if defined (WIN32)
+	unsigned long one = 1;
+	if (ioctlsocket (sock, FIONBIO, &one) )
+	{
+		aLog("SetNonBlocking: fcntl");
+		return False;
+	}
+	return True;
+#else
+#ifdef O_ASYNC 
+    if (fcntl(sock, F_SETFL, O_ASYNC) < 0) {
+#else
+    int yes = 1; 
+    if (ioctl(sock, FIOASYNC, &yes) < 0) {
+#endif
+        aLog("SetNonBlocking: fcntl");
+        return False;
+    }
+    return True;
+#endif
+}
+
+
+/*
+ * StringToIPAddr - convert a host string to an IP address.
+ */
+
+Bool
+StringToIPAddr(const char *str, unsigned long *addr)
+{
+    struct hostent *hp;
+
+    if (strcmp(str,"") == 0) {
+        *addr = 0; /* local */
+        return True;
+    }
+
+    *addr = inet_addr(str);
+
+	aLog("inet_addr %s = %d\n", str, *addr);
+
+    if (*addr != INADDR_NONE)
+        return True;
+
+    hp = gethostbyname(str);
+
+	aLog("gethostbyname %s = %x\n", str, hp);
+
+    if (hp) {
+        *addr = *(unsigned int *)hp->h_addr;
+        return True;
+    }
+
+    return False;
+}
+
+
+/*
+ * Test if the other end of a socket is on the same machine.
+ */
+
+Bool
+SameMachine(int sock)
+{
+    struct sockaddr_in peeraddr, myaddr;
+#if defined (WIN32)
+    int addrlen = sizeof(struct sockaddr_in);
+#else
+    socklen_t addrlen = sizeof(struct sockaddr_in);
+#endif
+
+    getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
+    getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
+
+    return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
+}
Index: trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.h	(revision 4)
@@ -0,0 +1,46 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_SERVER_ABSTRACT_COMMAND_H
+#define SYNCHRONIZER_SERVER_ABSTRACT_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+class SynchronizerServerAbstractCommand {
+
+public:
+
+  // Destructor
+  virtual ~SynchronizerServerAbstractCommand();
+  
+  // Execute command
+  virtual bool Execute(int value);
+
+protected:  
+
+  // Constructor
+  SynchronizerServerAbstractCommand();
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.h	(revision 4)
@@ -0,0 +1,163 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_COLOR_TRANSFER_FUNCTION_H
+#define FL_COLOR_TRANSFER_FUNCTION_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <Fl/Fl_Gl_Window.H>
+#include <GL/gl.h>
+
+#include "ColorTransferFunctionWidget.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define DOWN 1
+#define UP 0
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Color_Transfer_Function : public Fl_Gl_Window {
+
+public:
+
+  // Constructor
+  Fl_Color_Transfer_Function(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Color_Transfer_Function();
+
+  // Get control point
+  void GetControlPoint(int index, float* scalar, float* r, float* g, float* b);
+
+  // Get index of control point that lies at given pixel position, or -1
+  int GetControlPointIndex(int px, int py);
+
+  // Get index of control point that lies at given function coordinates, or -1
+  int GetControlPointIndex(float scalar);
+
+  // Get function coordinates at given pixel coordinates, if possible
+  bool GetFunctionCoordinates(int px, int py, float* scalar, float* r, 
+                              float* g, float* b);
+
+  // Get number of control points
+  int GetNumberOfControlPoints();
+
+  // Get color for a given scalar value
+  void GetColor(float scalar, float* r, float* g, float* b);
+
+  // Get index of selected control point
+  int GetSelectedControlPoint();
+
+  // Get scalar range
+  void GetScalarRange(float* min, float* max);
+
+  // Modify control point's color, if possible
+  bool ModifyControlPointColor(int index, float r, float g, float b);
+
+  // Move control point to corresponding pixel coordinate, if possible
+  bool MoveControlPoint(int index, int px, int py);
+
+  // Move control point to corresponding function coordinate, if possible
+  bool MoveControlPoint(int index, float scalar);
+
+  // Remove control point
+  bool RemoveControlPoint(int index);
+
+  // Restore control points from a list
+  void RestoreControlPoints(int number, float max, float* scalar, 
+                            float* r, float* g, float* b);
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set box color
+  void SetBoxColor(float r, float g, float b, float a);
+
+  // Set control point color
+  void SetControlPointColor(float r, float g, float b, float a);
+
+  // Set control point size
+  void SetControlPointSize(int size);
+
+  // Set focus point color
+  void SetFocusPointColor(float r, float g, float b, float a);
+
+  // Set line color
+  void SetLineColor(float r, float g, float b, float a);
+
+  // Set maximum scalar value
+  void SetMaximumScalar(float max);
+
+  // Set move callback: called when a control point is moved
+  void SetMoveCallback(void (*cb)(void*), void* p);
+
+  // Set select callback: called when a control point is selected
+  void SetSelectCallback(void (*cb)(void*), void* p);
+
+  // Set text color
+  void SetTextColor(float r, float g, float b, float a);
+
+  // Set unselect callback: called when a control point is unselected
+  void SetUnselectCallback(void (*cb)(void*), void* p);
+
+  // Implementation of draw method
+  void draw();
+
+  // Implementation of handle method
+  int handle(int event);
+
+private:
+
+  // Move callback
+  void (*_callbackMove)(void*);
+
+  // Move pointer
+  void* _callbackMovePtr;
+
+  // Select callback
+  void (*_callbackSelect)(void*);
+
+  // Select pointer
+  void* _callbackSelectPtr;
+
+  // Unselect callback
+  void (*_callbackUnselect)(void*);
+
+  // Unselect pointer
+  void* _callbackUnselectPtr;
+
+  // Control point picked
+  int _controlPointPicked;
+
+  // Mouse button states
+  int _mouseButtonState[3];
+
+  // Opacity transferfunction widget
+  ColorTransferFunctionWidget* _ctfw;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.h	(revision 4)
@@ -0,0 +1,189 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_SERVER_ABSTRACT_COMMAND_H
+#define USER_INTERFACE_SERVER_ABSTRACT_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceServerAbstractCommand {
+
+public:
+
+  // Destructor
+  virtual ~UserInterfaceServerAbstractCommand();
+
+  // Get axis state
+  virtual void GetAxis(bool* state);
+
+  // Get axis position
+  virtual void GetAxisPosition(float* x, float* y, float* z);
+
+  // Get bounding box state
+  virtual void GetBoundingBox(bool* state);
+
+  // Get brick box state
+  virtual void GetBrickBox(bool* state);
+
+  // Get clipping planes
+  virtual void GetClippingPlanes(int node, float* near, float* far);
+
+  // Get data
+  virtual void GetData(char* filename);
+
+  // Get data and cache sizes
+  virtual void GetData(char* filename, int* ramSize, int* vramSize);
+
+  // Get dataset list file
+  virtual void GetDatasetListFile(int index, char* file);
+
+  // Get dataset list name
+  virtual void GetDatasetListName(int index, char* name);
+
+  // Get dataset list prefix
+  virtual void GetDatasetListPrefix(int index, char* prefix);
+
+  // Get dataset list size
+  virtual void GetDatasetListSize(int* size);
+
+  // Get dataset type
+  virtual void GetDatasetType(int* type);
+
+  // Get display size
+  virtual void GetDisplaySize(int node, int* width, int* height,
+                              bool* fullScreen,
+                              float* left, float* right,
+                              float* bottom, float* top);
+
+  // Get frustum
+  virtual void GetFrustum(int node, float* left, float* right,
+                          float* bottom, float* top);
+
+  // Get map
+  virtual void GetMap(unsigned char* map);
+
+  // Get overview vertices
+  virtual void GetOverviewVertices(float vertices[24]);
+
+  // Get prefix
+  virtual void GetPrefix(char* prefix);
+
+  // Get rotation matrix
+  virtual void GetRotationMatrix(float m[16]);
+  
+  // Get scale matrix
+  virtual void GetScaleMatrix(float m[16]);
+
+  // Get slice frequency
+  virtual void GetSliceFrequency(double* frequency);
+
+  // Get total display dimensions
+  virtual void GetTotalDisplayDimensions(int* w, int* h);
+
+  // Get total display frustum
+  virtual void GetTotalDisplayFrustum(float frustum[6]);
+
+  // Get translation matrix
+  virtual void GetTranslationMatrix(float m[16]);
+
+  // Get vertical field of view
+  virtual void GetVerticalFieldOfView(float* vFOV);
+
+  // Get viewport
+  virtual void GetViewport(int node, int* x, int* y, int* w, int* h);
+
+  // Reset view
+  virtual void ResetView();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(int node, float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set render flag
+  virtual void SetCommandRender();
+
+  // Set data
+  virtual void SetData(char* filename);
+
+  // Set data and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set frustum
+  virtual void SetFrustum(int node, float left, float right,
+                          float bottom, float top);
+
+  // Set transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set 16-bit transfer function
+  virtual void SetMap16(unsigned char* map);
+  
+  // Set prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float m[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float m[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float m[16]);
+
+  // Set viewport
+  virtual void SetViewport(int node, int x, int y, int w, int h);
+
+protected:
+
+  // Constructor
+  UserInterfaceServerAbstractCommand();
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheRAMNode.h
===================================================================
--- trunk/src/testing/app/VRA/src/CacheRAMNode.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheRAMNode.h	(revision 4)
@@ -0,0 +1,74 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef CACHE_RAM_NODE_H
+#define CACEH_RAM_NODE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class CacheRAMNode {
+
+public:
+
+  // Default constructor
+  CacheRAMNode();
+
+  // Default destructor
+  ~CacheRAMNode();
+
+  // Get next node
+  CacheRAMNode* GetNext();
+
+  // Get node
+  OctreeNode* GetOctreeNode();
+
+  // Get previous node
+  CacheRAMNode* GetPrevious();
+
+  // Set next node
+  void SetNext(CacheRAMNode* node);
+
+  // Set node
+  void SetOctreeNode(OctreeNode* node);
+
+  // Set previous node
+  void SetPrevious(CacheRAMNode* node);
+
+private:
+
+  // Node
+  OctreeNode* _node;
+
+  // Previous node in list
+  CacheRAMNode* _previous;
+
+  // Next node in list
+  CacheRAMNode* _next;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Slave.h
===================================================================
--- trunk/src/testing/app/VRA/src/Slave.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Slave.h	(revision 4)
@@ -0,0 +1,187 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef SLAVE_H
+#define SLAVE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "Communicator.h"
+#include "CommunicatorAbstractCommand.h"
+#include "Octree.h"
+#include "VolumeRendererShell.h"
+
+/*--------------------------------------------------------------------------*/
+
+class Slave {
+
+public:
+
+  // Constructor
+  Slave(Communicator* communicator);
+
+  // Destructor
+  ~Slave();
+
+  // Main loop
+  void Run();
+
+  // Axis off callback
+  void UpdateAxisOff();
+
+  // Axis on callback
+  void UpdateAxisOn();
+
+  // Axis position callback
+  void UpdateAxisPosition(float x, float y, float z);
+
+  // Brick box off callback
+  void UpdateBrickBoxOff();
+
+  // Brick box on callback
+  void UpdateBrickBoxOn();
+
+  // Bounding box off callback
+  void UpdateBoundingBoxOff();
+
+  // Bounding box on callback
+  void UpdateBoundingBoxOn();
+
+  // Clipping planes callback
+  void UpdateClippingPlanes(float near, float far);
+
+  // Exit callback
+  void UpdateCommandExit();
+
+  // Render callback
+  void UpdateCommandRender();
+
+  // Data callback
+  void UpdateData(char* filename);
+
+  // Data callback
+  void UpdateData(char* filename, int ramSize, int vramSize);
+
+  // Display size callback
+  void UpdateDisplaySize(int width, int height, bool fullScreen,
+                         char* hostname, int port,
+                         float left, float right, 
+                         float bottom, float top);
+
+  // Frustum callback
+  void UpdateFrustum(float left, float right, float bottom, float top);
+  
+  // 8-bit map callback
+  void UpdateMap(unsigned char* map);
+
+  // 16-bit map callback
+  void UpdateMap16(unsigned char* map);
+
+  // Prefix callback
+  void UpdatePrefix(char* prefix);
+
+  // Rotation matrix callback
+  void UpdateRotationMatrix(float m[16]);
+
+  // Scale matrix callback
+  void UpdateScaleMatrix(float m[16]);
+
+  // Slice frequency callback
+  void UpdateSliceFrequency(double frequency);
+
+  // Translation matrix callback
+  void UpdateTranslationMatrix(float m[16]);
+
+  // Viewport callback
+  void UpdateViewport(int x, int y, int w, int h);
+
+private:
+
+  // Axis on flag
+  bool _axisOnFlag;
+
+  // Brick box on flag
+  bool _brickBoxOnFlag;
+
+  // Bounding box on flag
+  bool _boundingBoxOnFlag;
+
+  // Axis position
+  float _axisPosition[3];
+
+  // Clipping planes
+  float _clippingPlanes[2];
+
+  // Communicator
+  Communicator* _communicator;
+
+  // Data
+  Octree* _data;
+
+  // Data meta filename
+  char _dataFilename[1024];
+
+  // Data meta prefix
+  char _dataPrefix[1024];
+
+  // Display size
+  int _displaySize[2];
+
+  // Exit flag
+  bool _exitFlag;
+
+  // Frustum
+  float _frustum[4];
+
+  // Full screen flag
+  bool _fullScreenFlag;
+
+  // Map
+  unsigned char* _map;
+
+  // Normalized coordinates of rendered area
+  float _normalCoordinates[4];
+
+  // Observer
+  CommunicatorAbstractCommand* _observer;
+
+  // Slice frequency
+  double _sliceFrequency;
+
+  // Transformation matrices
+  float _R[16];
+  float _S[16];
+  float _T[16];
+
+  // Viewport
+  int _viewport[4];
+
+  // Volume renderer shell
+  VolumeRendererShell* _volumeRendererShell;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif 
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Connect.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Connect.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Connect.h	(revision 4)
@@ -0,0 +1,78 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_CONNECT_H
+#define FL_CONNECT_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Connect : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Connect(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Connect();
+
+  // Get host
+  const char* GetHost();
+
+  // Get port
+  int GetPort();
+
+  // Set connect button callback
+  void SetConnectButtonCallback(Fl_Callback* cb, void* v);
+
+  // Set exit button callback
+  void SetExitButtonCallback(Fl_Callback* cb, void* v);
+
+private:
+
+  // Connect button
+  Fl_Return_Button* _connectButton;
+
+  // Exit button
+  Fl_Button* _exitButton;
+
+  // Host input field
+  Fl_Input* _hostInput;
+
+  // Port input field
+  Fl_Input* _portInput;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Octree.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Octree.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Octree.cpp	(revision 4)
@@ -0,0 +1,443 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Octree.h"
+
+/*--------------------------------------------------------------------------*/
+
+Octree::Octree() {
+
+  // Initialize data format
+  _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+
+  // Initialize data type
+  _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+
+  // Initialize data prefix
+  memset(_prefix, 0, 1024);
+
+  // Initialize root to NULL
+  _root = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Octree::~Octree() {
+
+  // Clean up octree recursively
+  if (_root != NULL) {
+    delete _root;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Octree::GetDataFormat() {
+
+  // Return data format
+  return _dataFormat;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Octree::GetDataType() {
+
+  // Return data type
+  return _dataType;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Octree::GetNumberOfLevels() {
+
+  // Return number of levels in octree
+  return _numberOfLevels;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Octree::GetNumberOfNodes() {
+
+  // Return number of nodes in octree
+  return _numberOfNodes;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode* Octree::GetRoot() {
+
+  // Return root node
+  return _root;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::LoadFromFile(const char* filename) {
+  fprintf(stderr, "LFF\n");
+  // Create full path and filename of file to load
+  char path[2048];
+  memset(path, 0, sizeof(char) * 2048);
+  memcpy(path, _prefix, sizeof(char) * strlen(_prefix));
+  memcpy(&path[strlen(path)], filename, sizeof(char) * strlen(filename));
+
+  // Open file
+  FILE* metafptr;
+  if ((metafptr = fopen(path, "r")) == NULL) {
+    fprintf(stderr, "Octree: Error reading metadata file %s.\n", path);
+    return;
+  }
+
+  // Read name of root node file
+  char datafilename[128];
+  fscanf(metafptr, "%s", datafilename);
+
+  // Read number of levels in octree
+  int numberOfLevels = 0;
+  fscanf(metafptr, "%d", &numberOfLevels);
+
+  // Read number of nodes in octree
+  int numberOfNodes = 0;
+  fscanf(metafptr, "%d", &numberOfNodes);
+
+  // Read data type of nodes in octree
+  char dataTypeString[128];
+  fscanf(metafptr, "%s", dataTypeString);
+
+  // Read data format of nodes in octree
+  char dataFormatString[128];
+  fscanf(metafptr, "%s", dataFormatString);
+
+  // Close file
+  fclose(metafptr);
+
+  // Allocate root node
+  if ((_root = new OctreeNode) == NULL) {
+    fprintf(stderr, "Octree: Memory allocation error.\n");
+    return;
+  }
+
+  // Load root node and entire tree recursively
+  _root -> SetPrefix(_prefix);
+  _root -> LoadFromFile(datafilename);
+
+  // Set number of levels and nodes in octree
+  _numberOfLevels = numberOfLevels;
+  _numberOfNodes = numberOfNodes;
+
+  // Set data type of nodes in octree
+  if (!strcmp(dataTypeString, "UNSIGNED_8_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+  else if (!strcmp(dataTypeString, "UNSIGNED_16_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_16_INT;
+  }
+  else {
+    fprintf(stderr, "Octree: Unknown data type.\n");
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+
+  // Set data format of nodes in octree
+  if (!strcmp(dataFormatString, "BIG_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+  }
+  else if (!strcmp(dataFormatString, "LITTLE_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_LITTLE_ENDIAN;
+  }
+  else {
+    fprintf(stderr, "Octree: Unknown data format.\n");
+    _dataType = OCTREE_NODE_BIG_ENDIAN;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::LoadFromFile2(const char* filename) {
+
+  // Create full path and filename of file to load
+  char path[2048];
+  memset(path, 0, sizeof(char) * 2048);
+  memcpy(path, _prefix, sizeof(char) * strlen(_prefix));
+  memcpy(&path[strlen(path)], filename, sizeof(char) * strlen(filename));
+
+  // Open file
+  FILE* metafptr;
+  if ((metafptr = fopen(path, "r")) == NULL) {
+    fprintf(stderr, "Octree: Error reading metadata file %s.\n", path);
+    return;
+  }
+
+
+  // Read number of levels in octree
+  int numberOfLevels = 0;
+  fscanf(metafptr, "%d", &numberOfLevels);
+
+  // Read number of nodes in octree
+  int numberOfNodes = 0;
+  fscanf(metafptr, "%d", &numberOfNodes);
+
+  // Read data type of nodes in octree
+  char dataTypeString[128];
+  fscanf(metafptr, "%s", dataTypeString);
+
+  // Read data format of nodes in octree
+  char dataFormatString[128];
+  fscanf(metafptr, "%s", dataFormatString);
+
+  // Set data type of nodes in octree
+  if (!strcmp(dataTypeString, "UNSIGNED_8_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+  else if (!strcmp(dataTypeString, "UNSIGNED_16_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_16_INT;
+  }
+  else {
+    fprintf(stderr, "Octree: Unknown data type.\n");
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+
+  // Set data format of nodes in octree
+  if (!strcmp(dataFormatString, "BIG_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+  }
+  else if (!strcmp(dataFormatString, "LITTLE_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_LITTLE_ENDIAN;
+  }
+  else {
+    fprintf(stderr, "Octree: Unknown data format.\n");
+    _dataType = OCTREE_NODE_BIG_ENDIAN;
+  }
+
+  // Set number of levels and nodes in octree
+  _numberOfLevels = numberOfLevels;
+  _numberOfNodes = numberOfNodes;
+
+
+  // Allocate root node
+  if ((_root = new OctreeNode) == NULL) {
+    fprintf(stderr, "Octree: Memory allocation error.\n");
+    return;
+  }
+
+  // Load root node prefix
+  _root -> SetPrefix(_prefix);
+
+  // load recursively
+  LoadFromFileRecursive(metafptr, _root);
+
+
+  // Close file
+  fclose(metafptr);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::LoadFromFileRecursive(FILE* metafptr, OctreeNode* node) {
+
+  // id
+  int id;
+
+  // level
+  int level;
+
+  // vertices
+  float v0x, v0y, v0z;
+  float v1x, v1y, v1z;
+  float v2x, v2y, v2z;
+  float v3x, v3y, v3z;
+  float v4x, v4y, v4z;
+  float v5x, v5y, v5z;
+  float v6x, v6y, v6z;
+  float v7x, v7y, v7z;
+
+  // width, height, depth
+  int w, h, d;
+
+  // Data type
+  char dataTypeString[128];
+
+  // Data format
+  char dataFormatString[128];
+
+  // raw data file name
+  char datafilename[128];
+
+  // number of children
+  int numberofchildren;
+
+
+  // read id and level
+  fscanf(metafptr, "%d %d", &id, &level);
+
+  // read vertices
+  fscanf(metafptr, "%f %f %f", &v0x, &v0y, &v0z);
+  fscanf(metafptr, "%f %f %f", &v1x, &v1y, &v1z);
+  fscanf(metafptr, "%f %f %f", &v2x, &v2y, &v2z);
+  fscanf(metafptr, "%f %f %f", &v3x, &v3y, &v3z);
+  fscanf(metafptr, "%f %f %f", &v4x, &v4y, &v4z);
+  fscanf(metafptr, "%f %f %f", &v5x, &v5y, &v5z);
+  fscanf(metafptr, "%f %f %f", &v6x, &v6y, &v6z);
+  fscanf(metafptr, "%f %f %f", &v7x, &v7y, &v7z);
+
+  // read width, height, depth
+  fscanf(metafptr, "%d %d %d", &w, &h, &d);
+
+  // read data type
+  fscanf(metafptr, "%s", dataTypeString);
+
+  // read data format
+  fscanf(metafptr, "%s", dataFormatString);
+
+  // read raw data filename
+  fscanf(metafptr, "%s", datafilename);
+
+  // read children flag
+  fscanf(metafptr, "%d", &numberofchildren);
+
+
+  // assign id and level
+  node -> SetID(id);
+  node -> SetLevel(level);
+
+  // assign vertices
+  node -> SetVertex(0, v0x, v0y, v0z);
+  node -> SetVertex(1, v1x, v1y, v1z);
+  node -> SetVertex(2, v2x, v2y, v2z);
+  node -> SetVertex(3, v3x, v3y, v3z);
+  node -> SetVertex(4, v4x, v4y, v4z);
+  node -> SetVertex(5, v5x, v5y, v5z);
+  node -> SetVertex(6, v6x, v6y, v6z);
+  node -> SetVertex(7, v7x, v7y, v7z);
+
+  // assign width, height, depth
+  node -> SetWHD(w, h, d);
+
+  // assign data type
+  if (!strcmp(dataTypeString, "UNSIGNED_8_INT")) {
+    node -> SetDataType(OCTREE_NODE_UNSIGNED_8_INT);
+  }
+  else if (!strcmp(dataTypeString, "UNSIGNED_16_INT")) {
+    node -> SetDataType(OCTREE_NODE_UNSIGNED_16_INT);
+  }
+  else {
+    fprintf(stderr, "OctreeNode: Unknown data type.\n");
+    node -> SetDataType(OCTREE_NODE_UNSIGNED_8_INT);
+  }
+
+  // assign data format
+  if (!strcmp(dataFormatString, "BIG_ENDIAN")) {
+    node -> SetDataFormat(OCTREE_NODE_BIG_ENDIAN);
+  }
+  else if (!strcmp(dataFormatString, "LITTLE_ENDIAN")) {
+    node -> SetDataFormat(OCTREE_NODE_LITTLE_ENDIAN);
+  }
+  else {
+    fprintf(stderr, "OctreeNode: Unknown data format.\n");
+    node -> SetDataFormat(OCTREE_NODE_BIG_ENDIAN);
+  }
+
+  // assign filename
+  node -> SetFilename(datafilename);
+
+
+  // load children
+  for (int i = 0 ; i < numberofchildren ; i++) {
+
+    // allocate child node
+    OctreeNode* child = NULL;
+    if ((child = new OctreeNode) == NULL) {
+      fprintf(stderr, "OctreeNode: Memory allocation error.\n");
+    }
+
+    // set child
+    node -> SetChild(i, child);
+    child -> SetPrefix(_prefix);
+
+    // load recursively
+    LoadFromFileRecursive(metafptr, child);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetDataFormat(int format) {
+
+  // Set data format
+  _dataFormat = format;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetDataType(int type) {
+
+  // Set data type
+  _dataType = type;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetNumberOfLevels(int numberOfLevels) {
+
+  // Set number of levels in octree
+  _numberOfLevels = numberOfLevels;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetNumberOfNodes(int numberOfNodes) {
+
+  // Set number of nodes in octree
+  _numberOfNodes = numberOfNodes;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetPrefix(const char* prefix) {
+
+  // Set data prefix
+  if (prefix != NULL) {
+    strcpy(_prefix, prefix);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Octree::SetRoot(OctreeNode* root) {
+
+  // Set root node
+  _root = root;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.cpp	(revision 4)
@@ -0,0 +1,202 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceClientAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClientAbstractCommand::UserInterfaceClientAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClientAbstractCommand::~UserInterfaceClientAbstractCommand() {
+}
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetAxisOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetAxisOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetAxisPosition(float x, 
+                                                         float y, 
+                                                         float z) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetBoundingBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetBoundingBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetBrickBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetBrickBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetClippingPlanes(int node, 
+                                                           float near, 
+                                                           float far) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetCommandExit() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetData(char* filename) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetData(char* filename,
+                                                 int ramSize, int vramSize) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDatasetListFile(int index, 
+                                                            char* file) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDatasetListName(int index, 
+                                                            char* name) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDatasetListPrefix(int index, 
+                                                              char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDatasetListSize(int size) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDatasetType(int type) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetDisplaySize(int node,
+                                                        int width, 
+                                                        int height, 
+                                                        bool fullScreen,
+                                                        float left,
+                                                        float right,
+                                                        float bottom,
+                                                        float top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetFrustum(int node, 
+                                                    float left, float right,
+                                                    float bottom, float top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetMap(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetOverviewVertices(float 
+                                                             vertices[24]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetPrefix(char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetProgress(int value, int total) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetRotationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetScaleMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetSliceFrequency(double frequency) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetTotalDisplayDimensions(int w, 
+                                                                   int h) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetTotalDisplayFrustum(float 
+                                                                frustum[6]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetTranslationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetVerticalFieldOfView(float vFOV) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientAbstractCommand::SetViewport(int node, int x, int y, 
+                                                     int w, int h) {
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.cpp	(revision 4)
@@ -0,0 +1,152 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CommunicatorAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+CommunicatorAbstractCommand::CommunicatorAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+CommunicatorAbstractCommand::~CommunicatorAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetAxisOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetAxisOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetAxisPosition(float x, float y, float z) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetBrickBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetBrickBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetBoundingBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetBoundingBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetClippingPlanes(float near, float far) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetCommandExit() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetCommandRender() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetData(char* filename) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetData(char* filename, 
+                                          int ramSize, int vramSize) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetDisplaySize(int width, 
+                                                 int height, 
+                                                 bool fullScreen, 
+                                                 char* hostname,
+                                                 int port,
+                                                 float left,
+                                                 float right,
+                                                 float bottom,
+                                                 float top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetFrustum(float left, float right,
+                                             float bottom, float top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetMap(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetMap16(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetPrefix(char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetRotationMatrix(float matrix[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetScaleMatrix(float matrix[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetSliceFrequency(double frequency) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetTranslationMatrix(float matrix[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorAbstractCommand::SetViewport(int x, int y, int w, int h) {
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/main.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/main.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/main.cpp	(revision 4)
@@ -0,0 +1,103 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "Communicator.h"
+#include "Log.h"
+#include "Master.h"
+#include "Slave.h"
+#include "SynchronizerServer.h"
+
+/*--------------------------------------------------------------------------*/
+
+Communicator* communicator;
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char** argv) {
+
+  // Communicator
+  communicator = new Communicator;
+
+  // Initialize communication between nodes
+  communicator -> Init(argc, argv);
+
+  // Start logging
+  Log::Start();
+
+  // Master process
+  if (communicator -> GetRank() == 0) {
+
+    // Sync all nodes
+    communicator -> Barrier();
+
+    // Create master
+    Master* master = new Master(communicator);
+
+    // Sync all nodes
+    communicator -> Barrier();
+
+    // Initialize master
+    master -> Init("config");
+
+    // Run master
+    master -> Run();
+
+    // Clean up master
+    delete master;
+
+  }
+
+  // Slave processes
+  else {
+    
+    // Sync all nodes
+    communicator -> Barrier();
+
+    // Create slave
+    Slave* slave = new Slave(communicator);
+
+    // Sync all nodes
+    communicator -> Barrier();
+
+    // Run slave
+    slave -> Run();
+
+    // Clean up slave
+    delete slave;
+
+  }
+
+  // Stop logging
+  Log::Stop();
+
+  // Wait for all communication to end
+  communicator -> Destroy();
+ 
+  // Clean up communicator
+  delete communicator;
+
+  // Exit
+  return 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererShell.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererShell.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererShell.cpp	(revision 4)
@@ -0,0 +1,1035 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "VolumeRendererShell.h"
+
+#include "SynchronizerClient.h"
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef SAGE
+
+// Define static variable for glXPBuffer
+GLXPbufferSGIX VolumeRendererShell::_glXPBuffer = 0;
+
+// Define static variable for X display
+Display* VolumeRendererShell::_xDisplay = NULL;
+
+// Define static variable for X error flag
+int VolumeRendererShell::_xErrorFlag = 0;
+
+// Define static variable for X visual info
+XVisualInfo* VolumeRendererShell::_xVisualInfo = NULL;
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererShell::VolumeRendererShell() {
+
+  // Initialize condition variable
+  pthread_cond_init(&_conditionCond, NULL);
+
+  // Initialize mutex
+  pthread_mutex_init(&_conditionMutex, NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererShell::~VolumeRendererShell() {
+
+  // Clean up condition variable
+  pthread_cond_destroy(&_conditionCond);
+
+  // Clean up mutex
+  pthread_mutex_destroy(&_conditionMutex);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::AbortRender(bool flag) {
+
+  // Set abort flag
+  _info._abortFlag = flag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::DestroyDisplay() {
+
+#ifdef SAGE
+
+  // Clean up pbuffer
+  glXDestroyGLXPbufferSGIX(_xDisplay, _glXPBuffer);
+
+  // Clean up visual info
+  XFree(_xVisualInfo);
+
+  // Close X connection
+  XCloseDisplay(_xDisplay);
+
+#else
+  
+  // Quit SDL
+  SDL_Quit();
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef SAGE
+
+int VolumeRendererShell::HandleXError(Display* display, XErrorEvent *event) {
+
+  // Set error flag
+  _xErrorFlag = 1;
+
+  // Return 0
+  return 0;
+
+}
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::Init(int width, int height, bool fullScreen, 
+                               char* hostname, int port,
+                               float left, float right,
+                               float bottom, float top,
+                               int rank, int numberOfNodes) {
+
+  // Set mutex and condition variable in thread state
+  _info._conditionCond = &_conditionCond;
+  _info._conditionMutex = &_conditionMutex;
+
+  // Set display information in thread state
+  _info._displaySize[0] = width;
+  _info._displaySize[1] = height;
+  _info._fullScreenFlag = fullScreen;
+  _info._normalCoordinates[0] = left;
+  _info._normalCoordinates[1] = right;
+  _info._normalCoordinates[2] = bottom;
+  _info._normalCoordinates[3] = top;
+
+  // Set synchronization hostname and port
+  strcpy(_info._synchronizationHostname, hostname);
+  _info._synchronizationPort = port;
+
+  // Set rank and number of nodes
+  _info._rank = rank;
+  _info._numberOfNodes = numberOfNodes;
+
+  // Create thread
+  pthread_create(&_thread, NULL, VolumeRendererShell::ThreadFunction, &_info);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::InitDisplay(int width, int height, bool fullScreen, 
+                                      float left, float right, 
+                                      float bottom, float top) {
+
+#ifdef SAGE
+
+  // GLX context
+  GLXContext glXContext;
+
+  // GLX pbuffer
+  GLXFBConfigSGIX glXFBConfig = 0;
+
+  // X screen
+  int xScreen = 0;
+
+  // Open display
+  _xDisplay = XOpenDisplay(NULL);
+  if (!_xDisplay) {
+    fprintf(stderr, "VolumeRendererShell: Could not open X display.\n");
+    return;
+  }
+
+  // Get default screen
+  xScreen = DefaultScreen(_xDisplay);
+
+  // Double buffered, with depth buffer
+  int fbAttribs[] = {
+    GLX_RENDER_TYPE_SGIX, GLX_RGBA_BIT_SGIX,
+    GLX_DRAWABLE_TYPE_SGIX, GLX_PIXMAP_BIT_SGIX,
+    GLX_RED_SIZE, 1,
+    GLX_GREEN_SIZE, 1,
+    GLX_BLUE_SIZE, 1,
+    GLX_DEPTH_SIZE, 1,
+    GLX_DOUBLEBUFFER, 1,
+    GLX_STENCIL_SIZE, 0,
+    None
+  };
+
+  // Attributes
+  int pbAttribs[] = {
+    GLX_LARGEST_PBUFFER_SGIX, True,
+    GLX_PRESERVED_CONTENTS_SGIX, False,
+    None
+  }; 
+
+  // Possible configurations
+  GLXFBConfigSGIX* glXFBConfigs = NULL;
+  int numberOfGLXFBConfigs;
+  
+  // Get list of possible frame buffer configurations
+  glXFBConfigs = glXChooseFBConfigSGIX(_xDisplay, xScreen, 
+                                       fbAttribs, &numberOfGLXFBConfigs);
+  if (numberOfGLXFBConfigs == 0 || !glXFBConfigs) {
+    fprintf(stderr, "VolumeRendererShell: Choosing FBConfig failed.\n");
+    XCloseDisplay(_xDisplay);
+    return;
+  }
+
+  // Create pbuffer using first config in the list that works
+  for (int i = 0 ; i < numberOfGLXFBConfigs ; i++) {
+
+    // Catch X errors with error handler
+    int (*oldHandler)(Display*, XErrorEvent*);
+    oldHandler = XSetErrorHandler(HandleXError);
+    _xErrorFlag = 0;
+
+    // Create pbuffer
+    _glXPBuffer = glXCreateGLXPbufferSGIX(_xDisplay, glXFBConfigs[i], 
+                                         width, height, pbAttribs);
+
+    // Restore original X error handler
+    (void) XSetErrorHandler(oldHandler);
+
+    // Found a working configuration
+    if (!_xErrorFlag && _glXPBuffer != None) {
+      glXFBConfig = glXFBConfigs[i];
+      break;
+    }
+  }
+
+  // Clean up
+  XFree(glXFBConfigs);
+
+  // If a pbuffer couldn't be created
+  if (_glXPBuffer == None) {
+    fprintf(stderr, "VolumeRendererShell: Couldn't create pbuffer.\n");
+    XCloseDisplay(_xDisplay);
+    return;
+  }
+
+  // Get corresponding XVisualInfo
+  _xVisualInfo = glXGetVisualFromFBConfigSGIX(_xDisplay, glXFBConfig);
+  if (!_xVisualInfo) {
+    fprintf(stderr, "VolumeRendererShell: Can't get XVisualInfo.\n");
+    XCloseDisplay(_xDisplay);
+    return;
+  }
+
+  // Create GLX context
+  glXContext = glXCreateContext(_xDisplay, _xVisualInfo, NULL, True);
+  if (!glXContext) {
+    glXContext = glXCreateContext(_xDisplay, _xVisualInfo, NULL, False);
+    if (!glXContext) {
+      fprintf(stderr, "VolumeRendererShell: Couldn't create GLXContext.\n");
+      XFree(_xVisualInfo);
+      XCloseDisplay(_xDisplay);
+      return;
+    }
+  }
+
+  // Bind context to pbuffer
+  if (!glXMakeCurrent(_xDisplay, _glXPBuffer, glXContext)) {
+    fprintf(stderr, "VolumeRendererShell: glXMakeCurrent failed.\n");
+    XFree(_xVisualInfo);
+    XCloseDisplay(_xDisplay);
+    return;
+  }
+
+#else
+
+  // Initialize SDL
+  SDL_Init(SDL_INIT_VIDEO);
+  
+  // Set video mode
+  if (fullScreen == false) {
+    SDL_SetVideoMode(width, 
+                     height, 
+                     0, 
+                     SDL_DOUBLEBUF | SDL_OPENGL);
+  }
+  else {
+   SDL_SetVideoMode(width, 
+                    height, 
+                    0, 
+                    SDL_DOUBLEBUF | SDL_OPENGL | SDL_FULLSCREEN);
+   SDL_ShowCursor(SDL_DISABLE);
+  }
+  SDL_WM_SetCaption("Volume Renderer", NULL);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRendererShell::InRender() {
+
+  // Return in render flag
+  return _info._inRenderFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRendererShell::IsInitialized() {
+
+  // To be implemented
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+  
+void VolumeRendererShell::Render() {
+
+  // Signal thread to update volume renderer and render
+  pthread_mutex_lock(&_conditionMutex);
+  _info._renderFlag = true;
+  pthread_cond_signal(&_conditionCond);
+  pthread_mutex_unlock(&_conditionMutex);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetAxisOff() {
+
+  // Set flag
+  _info._axisOnFlag = false;
+
+  // Set update flag
+  _info._updateAxis = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetAxisOn() {
+
+  // Set flag
+  _info._axisOnFlag = true;
+
+  // Set update flag
+  _info._updateAxis = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetAxisPosition(float x, float y, float z) {
+
+  // Set data
+  _info._axisPosition[0] = x;
+  _info._axisPosition[1] = y;
+  _info._axisPosition[2] = z;
+
+  // Set update flag
+  _info._updateAxis = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetBrickBoxOff() {
+
+  // Set flag
+  _info._brickBoxOnFlag = false;
+
+  // Set update flag
+  _info._updateBrickBox = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetBrickBoxOn() {
+
+  // Set flag
+  _info._brickBoxOnFlag = true;
+
+  // Set update flag
+  _info._updateBrickBox = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetBoundingBoxOff() {
+
+  // Set flag
+  _info._boundingBoxOnFlag = false;
+
+  // Set update flag
+  _info._updateBoundingBox = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetBoundingBoxOn() {
+
+  // Set flag
+  _info._boundingBoxOnFlag = true;
+
+  // Set update flag
+  _info._updateBoundingBox = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetData(Octree* data) {
+
+  // Set data
+  _info._data = data;
+
+  // Set default cache sizes
+  _info._ramSize = 50;
+  _info._vramSize = 10;
+
+  // Set update flag
+  _info._updateData = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetData(Octree* data, int ramSize, int vramSize) {
+
+  // Set data
+  _info._data = data;
+
+  // Set cache sizes
+  _info._ramSize = ramSize;
+  _info._vramSize = vramSize;
+
+  // Set update flag
+  _info._updateData = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetExitFlag() {
+
+  // Set exit flag
+  _info._exitFlag = true;
+
+  // Signal thread to update volume renderer and render
+  pthread_mutex_lock(&_conditionMutex);
+  _info._renderFlag = true;
+  pthread_cond_signal(&_conditionCond);
+  pthread_mutex_unlock(&_conditionMutex);
+
+  // Wait for thread to finish
+  pthread_join(_thread, NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetFrustum(float left, float right, float bottom,
+                                     float top, float near, float far) {
+
+  // Set frustum
+  _info._frustum[0] = left;
+  _info._frustum[1] = right;
+  _info._frustum[2] = bottom;
+  _info._frustum[3] = top;
+  _info._frustum[4] = near;
+  _info._frustum[5] = far;
+
+  // Set update flag
+  _info._updateFrustum = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetMap(unsigned char* map) {
+
+  // Set map
+  _info._map = map;
+  _info._mapType = VOLUME_RENDERER_THREAD_INFO_MAP_8;
+
+  // Set update flag
+  _info._updateMap = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetMap8(unsigned char* map) {
+
+  // Set map
+  _info._map = map;
+  _info._mapType = VOLUME_RENDERER_THREAD_INFO_MAP_8;
+
+  // Set update flag
+  _info._updateMap = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetMap16(unsigned char* map) {
+
+  // Set map
+  _info._map = map;
+  _info._mapType = VOLUME_RENDERER_THREAD_INFO_MAP_16;
+
+  // Set update flag
+  _info._updateMap = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetR(float m[16]) {
+
+  // Set rotation matrix
+  _info._R[0] = m[0];     
+  _info._R[1] = m[1]; 
+  _info._R[2] = m[2]; 
+  _info._R[3] = m[3]; 
+
+  _info._R[4] = m[4];
+  _info._R[5] = m[5];
+  _info._R[6] = m[6];
+  _info._R[7] = m[7];
+
+  _info._R[8] = m[8];
+  _info._R[9] = m[9];
+  _info._R[10] = m[10];
+  _info._R[11] = m[11];
+
+  _info._R[12] = m[12];
+  _info._R[13] = m[13];
+  _info._R[14] = m[14];
+  _info._R[15] = m[15];
+
+  // Set update flag
+  _info._updateR = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetS(float m[16]) {
+
+  // Set scale matrix
+  _info._S[0] = m[0];     
+  _info._S[1] = m[1]; 
+  _info._S[2] = m[2]; 
+  _info._S[3] = m[3]; 
+
+  _info._S[4] = m[4];
+  _info._S[5] = m[5];
+  _info._S[6] = m[6];
+  _info._S[7] = m[7];
+
+  _info._S[8] = m[8];
+  _info._S[9] = m[9];
+  _info._S[10] = m[10];
+  _info._S[11] = m[11];
+
+  _info._S[12] = m[12];
+  _info._S[13] = m[13];
+  _info._S[14] = m[14];
+  _info._S[15] = m[15];
+
+  // Set update flag
+  _info._updateS = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetSliceFrequency(double frequency) {
+
+  // Set slice frequency
+  _info._sliceFrequency = frequency;
+
+  // Set update flag
+  _info._updateSliceFrequency = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRendererShell::SetT(float m[16]) {
+
+  // Set translation matrix
+  _info._T[0] = m[0];     
+  _info._T[1] = m[1]; 
+  _info._T[2] = m[2]; 
+  _info._T[3] = m[3]; 
+
+  _info._T[4] = m[4];
+  _info._T[5] = m[5];
+  _info._T[6] = m[6];
+  _info._T[7] = m[7];
+
+  _info._T[8] = m[8];
+  _info._T[9] = m[9];
+  _info._T[10] = m[10];
+  _info._T[11] = m[11];
+
+  _info._T[12] = m[12];
+  _info._T[13] = m[13];
+  _info._T[14] = m[14];
+  _info._T[15] = m[15];
+
+  // Set update flag
+  _info._updateT = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+  
+void VolumeRendererShell::SetViewport(int x, int y, int w, int h) {
+
+  // Set viewport
+  _info._viewport[0] = x;
+  _info._viewport[1] = y;
+  _info._viewport[2] = w;
+  _info._viewport[3] = h;
+
+  // Set update flag
+  _info._updateViewport = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *VolumeRendererShell::ThreadFunction(void* ptr) {
+
+#ifdef SAGE
+
+  // Swap buffer observer class for SAGE
+  class SwapBuffers : public VolumeRendererCommand {
+
+  public:
+
+    // Constructor
+    SwapBuffers(int width, int height, 
+                Display* display, GLXPbufferSGIX pbuffer,
+                char* hostname, int port,
+                float left, float right, float bottom, float top,
+                int rank, int numberOfNodes, int* level) {
+
+      // Current level
+      _level = level;
+
+      // Display variables
+      _xDisplay = display;
+      _glXPBuffer = pbuffer;      
+      _height = height;
+      _width = width;
+
+      // Initialize synchronizer
+      _synchronizerClient.Init(hostname, port);
+
+      // Setup SAGE viewport
+      _sageImageMap.left = left;
+      _sageImageMap.right = right;
+      _sageImageMap.bottom = bottom;
+      _sageImageMap.top = top;
+
+      // SAGE parameters
+      _sageConfig.init("VRA.conf");
+      _sageConfig.setAppName("VRA");
+      _sageConfig.rank = rank;
+      _sageConfig.nodeNum = numberOfNodes - 1;
+      _sageConfig.resX = _width;
+      _sageConfig.resY = _height;
+      _sageConfig.imageMap = _sageImageMap;
+      _sageConfig.pixFmt = PIXFMT_888;
+      _sageConfig.rowOrd = BOTTOM_TO_TOP;
+      _sageConfig.master = false;
+      _sageConfig.rendering = true;
+
+      // Initialize SAGE
+      _sageInf.init(_sageConfig);
+
+      // Check buffer
+      _image = NULL;
+      if (_image != NULL)
+        delete [] _image;
+
+      // Get buffer from SAGE
+      _image = (GLubyte*) _sageInf.getBuffer();
+
+    }
+
+    // Destructor
+    ~SwapBuffers() {
+      
+      // Finalize synchronizer
+      _synchronizerClient.Finalize();
+      
+    }
+
+    // Execute callback
+    bool Execute(int value) { 
+
+      // Setup readback
+      glReadBuffer(GL_FRONT);
+      glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+      // Synchronize with other nodes
+      _synchronizerClient.Barrier(*_level);
+
+      // Swap buffer
+      if (value == 0) {
+        glXSwapBuffers(_xDisplay, _glXPBuffer);
+        glReadPixels(0, 0, _width, _height, 
+                     GL_RGB, GL_UNSIGNED_BYTE, _image);
+        _sageInf.swapBuffer();
+        _image = (GLubyte*) _sageInf.getBuffer();
+        return true;
+      }
+
+      // Send current buffer
+      else {
+        glReadPixels(0, 0, _width, _height, 
+                     GL_RGB, GL_UNSIGNED_BYTE, _image);
+        _sageInf.swapBuffer();
+        _image = (GLubyte*) _sageInf.getBuffer();
+        return false;
+      }
+
+    }
+
+  private:
+
+    // Current level
+    int* _level;
+
+    // Display variables
+    Display* _xDisplay;
+    GLXPbufferSGIX _glXPBuffer;
+    GLubyte* _image;
+    int _height;
+    int _width;
+    
+    // SAGE variables
+    sageRect _sageImageMap;
+    sail _sageInf;
+    sailConfig _sageConfig;
+
+    // Synchronizer
+    SynchronizerClient _synchronizerClient;
+
+  };
+
+#else
+
+  // Swap buffer observer class for SDL
+  class SwapBuffers : public VolumeRendererCommand {
+
+  public:
+
+    // Constructor
+    SwapBuffers(char* hostname, int port, int* level) {
+
+      // Current level
+      _level = level;
+
+      // Initialize synchronizer
+      _synchronizerClient.Init(hostname, port);
+
+    }
+
+    // Destructor
+    ~SwapBuffers() {
+ 
+      // Finalize synchronizer
+      _synchronizerClient.Finalize();
+ 
+    }
+
+    // Execute callback
+    virtual bool Execute(int value) {
+
+      // Synchronizer with other nodes
+      _synchronizerClient.Barrier(*_level);
+
+      // Swap buffer
+      if (value == 0) {
+        SDL_GL_SwapBuffers();
+        return true;
+      }
+
+      return false;
+
+    }
+
+  private:
+
+    // Current level
+    int* _level;
+
+    // Synchronizer
+    SynchronizerClient _synchronizerClient;
+
+  };
+
+#endif
+
+  // Progress observer class
+  class ProgressUpdate : public VolumeRendererCommand {
+  public:
+    ProgressUpdate(int* level) {
+      _level = level;
+    }
+    virtual bool Execute(int value) {
+      *_level = value;
+      return true;
+    }
+  private:
+    int* _level;
+  };
+
+  // Abort check observer class
+  class AbortCheck : public VolumeRendererCommand {
+  public:
+    AbortCheck(VolumeRendererThreadInfo* info) {
+      _info = info;
+    }
+    virtual bool Execute(int value) {
+      if (_info -> _abortFlag == true) {
+        _info -> _abortFlag = false;
+        return true;
+      }
+      return false;
+    }
+  private:
+    VolumeRendererThreadInfo* _info;
+  };
+
+  // Current level
+  int level = 0;
+
+  // Cast thread info class
+  VolumeRendererThreadInfo* info = (VolumeRendererThreadInfo*) ptr;
+
+  // Initialize display
+  InitDisplay(info -> _displaySize[0], 
+              info -> _displaySize[1],
+              info -> _fullScreenFlag,
+              info -> _normalCoordinates[0],
+              info -> _normalCoordinates[1],
+              info -> _normalCoordinates[2],
+              info -> _normalCoordinates[3]);
+
+  // Initialize volume renderer
+  VolumeRenderer* renderer = new VolumeRenderer;
+  renderer -> Init();
+
+  // Abort render observer
+  VolumeRendererCommand* ac = new AbortCheck(info);
+  renderer -> SetAbortRenderObserver(ac);  
+
+  // Progress observer
+  VolumeRendererCommand* pu = new ProgressUpdate(&level);
+  renderer -> SetProgressObserver(pu);  
+
+#ifdef SAGE
+
+  // Swap buffer observer
+  VolumeRendererCommand* sb = 
+    new SwapBuffers(info -> _displaySize[0], 
+                    info -> _displaySize[1],
+                    _xDisplay, _glXPBuffer,
+                    info -> _synchronizationHostname,
+                    info -> _synchronizationPort,
+                    info -> _normalCoordinates[0],
+                    info -> _normalCoordinates[1],
+                    info -> _normalCoordinates[2],
+                    info -> _normalCoordinates[3],
+                    info -> _rank,
+                    info -> _numberOfNodes,
+                    &level);
+  renderer -> SetSwapBuffersObserver(sb);
+
+#else
+
+  // Swap buffer observer
+  VolumeRendererCommand* sb = 
+    new SwapBuffers(info -> _synchronizationHostname,
+                    info -> _synchronizationPort,
+                    &level);
+  renderer -> SetSwapBuffersObserver(sb);
+
+#endif
+
+  // Get mutex and condition variables
+  pthread_mutex_t* conditionMutex = info -> _conditionMutex;
+  pthread_cond_t* conditionCond = info -> _conditionCond;
+
+  // Thread loop
+  while(info -> _exitFlag == false) {
+
+    // Wait on condition variable
+    pthread_mutex_lock(conditionMutex);
+    while(info -> _renderFlag == false) {
+      pthread_cond_wait(conditionCond, conditionMutex);
+    }
+    pthread_mutex_unlock(conditionMutex);
+ 
+    // Check exit flag
+    if (info -> _exitFlag == true) {
+      continue;
+    }
+
+    // Check for update axis flag
+    if (info -> _updateAxis == true) {
+      if (info -> _axisOnFlag == true) {
+        renderer -> SetAxisOn();
+      }
+      else {
+        renderer -> SetAxisOff();
+      }
+      renderer -> SetAxisPosition(info -> _axisPosition[0], 
+                                  info -> _axisPosition[1], 
+                                  info -> _axisPosition[2]);
+      info -> _updateAxis = false;
+    }
+
+    // Check for update brick box flag
+    if (info -> _updateBrickBox == true) {
+      if (info -> _brickBoxOnFlag == true) {
+        renderer -> SetBrickBoxOn();
+      }
+      else {
+        renderer -> SetBrickBoxOff();
+      }
+    }
+
+    // Check for update bounding box flag
+    if (info -> _updateBoundingBox == true) {
+      if (info -> _boundingBoxOnFlag == true) {
+        renderer -> SetBoundingBoxOn();
+      }
+      else {
+        renderer -> SetBoundingBoxOff();
+      }
+    }
+
+    // Check for update data flag
+    if (info -> _updateData == true) {
+      renderer -> SetData(info -> _data, info -> _ramSize, info -> _vramSize);
+      info -> _updateData = false;
+    }
+
+    // Check for update frustum flag
+    if (info -> _updateFrustum == true) {
+      renderer -> SetFrustum(info -> _frustum[0], info -> _frustum[1],
+                             info -> _frustum[2], info -> _frustum[3],
+                             info -> _frustum[4], info -> _frustum[5]);
+      info -> _updateFrustum = false;
+    }
+
+    // Check for update map flag
+    if (info -> _updateMap == true) {
+      if (info -> _mapType == VOLUME_RENDERER_THREAD_INFO_MAP_8) {
+        renderer -> SetMapUnsigned8Int(info -> _map);
+      }
+      else if (info -> _mapType == VOLUME_RENDERER_THREAD_INFO_MAP_16) {
+        renderer -> SetMapUnsigned16Int(info -> _map);
+      }
+      info -> _updateMap = false;
+    }
+
+    // Check for update R flag
+    if (info -> _updateR == true) {
+      renderer -> SetR(info -> _R);
+      info -> _updateR = false;
+    }
+
+    // Check for update S flag
+    if (info -> _updateS == true) {
+      renderer -> SetS(info -> _S);
+      info -> _updateS = false;
+    }
+
+    // Check for update slice frequency flag
+    if (info -> _updateSliceFrequency == true) {
+      renderer -> SetSliceFrequency(info -> _sliceFrequency);
+      info -> _updateSliceFrequency = false;
+    }
+
+    // Check for update T flag
+    if (info -> _updateT == true) {
+      renderer -> SetT(info -> _T);
+      info -> _updateT = false;
+    }
+
+    // Check for update viewport flag
+    if (info -> _updateViewport == true) {
+      renderer -> SetViewport(info -> _viewport[0], info -> _viewport[1],
+                              info -> _viewport[2], info -> _viewport[3]);
+      info -> _updateViewport = false;
+    }
+
+    // Render
+    info -> _inRenderFlag = true;
+    renderer -> Render();
+    info -> _abortFlag = false;
+    info -> _inRenderFlag = false;
+
+    // Reset render flag
+    info -> _renderFlag = false;
+
+  }
+
+  // Clean up renderer
+  delete renderer;
+
+  // Clean up abort render observer
+  delete ac;
+
+  // Clean up progress observer
+  delete pu;
+
+  // Clean up swap buffer observer
+  delete sb;
+
+  // Clean up display
+  DestroyDisplay();
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OctreeNode.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/OctreeNode.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/OctreeNode.cpp	(revision 4)
@@ -0,0 +1,962 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode::OctreeNode() {
+
+  // Message
+  //Assert("Constructor begin.");
+
+  // Initialize children
+  _child[0] = NULL;
+  _child[1] = NULL;
+  _child[2] = NULL;
+  _child[3] = NULL;
+  _child[4] = NULL;
+  _child[5] = NULL;
+  _child[6] = NULL;
+  _child[7] = NULL;
+
+  // Initialize data
+  _data = NULL;
+  _dataLoadedFlag = false;
+  _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+  _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+
+  // Initialize node id
+  _id = 0;
+
+  // Initialize node level
+  _level = 0;
+
+  // Initialize data prefix
+  memset(_prefix, 0, 1024);
+
+  // Initialize texture
+  _texture = 0;
+  _textureLoadedFlag = false;
+
+  // Initialize data dimensions
+  _whd[0] = 0;
+  _whd[1] = 0;
+  _whd[2] = 0;
+
+  // Message
+  //Assert("Constructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode::~OctreeNode() {
+
+  // Message
+  Assert("Destructor begin.");
+
+  // Clean up children (and octree) recursively
+  for (int i = 0 ; i < 8 ; i++) {
+    if (_child[i] != NULL) {
+      delete _child[i];
+    }
+  }
+
+  // Delete texture
+  UnloadTexture();
+
+  // Clean up data
+  if (_data != NULL) {
+    delete [] _data;
+  }
+
+  // Message
+  Assert("Destructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Print message and time to stdout
+  char buffer[1024];
+  sprintf(buffer, "OctreeNode: %s", message);
+  Log::Assert(buffer);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode* OctreeNode::GetChild(int index) {
+
+  // Test index and return child
+  if (index >= 0 && index <= 7) {
+    return _child[index];
+  }
+  else {
+    return NULL;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetD() {
+
+  // Return depth
+  return _whd[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+unsigned char* OctreeNode::GetData() {
+
+  // Return data
+  return _data;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetDataFormat() {
+
+  // Return data format
+  return _dataFormat;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetDataType() {
+
+  // Return data type
+  return _dataType;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetH() {
+
+  // Return height
+  return _whd[1];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetID() {
+
+  // Return node id
+  return _id;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetLevel() {
+
+  // Return node level
+  return _level;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+GLuint OctreeNode::GetTexture() {
+
+  // Return texture id
+  return _texture;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::GetVertex(int index, Vertex* vertex) {
+
+  // Test index and return vertex
+  if (index >= 0 && index <= 7) {
+    *vertex = _vertex[index];
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::GetVertex(int index, float* x, float* y, float *z) {
+
+  // Test index and return vertex
+  if (index >= 0 && index <= 7) {
+    *x = _vertex[index].GetX();
+    *y = _vertex[index].GetY();
+    *z = _vertex[index].GetZ();
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OctreeNode::GetW() {
+
+  // Return width
+  return _whd[0];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::GetWHD(int whd[3]) {
+
+  // Return dimensions
+  whd[0] = _whd[0];
+  whd[1] = _whd[1];
+  whd[2] = _whd[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::GetWHD(int* w, int* h, int* d) {
+
+  // Return dimensions
+  *w = _whd[0];
+  *h = _whd[1];
+  *d = _whd[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OctreeNode::IsDataLoaded() {
+
+  // Return data loaded flag
+  return _dataLoadedFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OctreeNode::IsTextureLoaded() {
+
+  // Return texture loaded flag
+  return _textureLoadedFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::LoadData() {
+
+  // Message
+  char message[1024];
+  sprintf(message, "LoadData node %d begin.", _id);
+  Assert(message);
+
+  // Create full path and filename of file to load
+  char path[2048];
+  memset(path, 0, sizeof(char) * 2048);
+  memcpy(path, _prefix, sizeof(char) * strlen(_prefix));
+  memcpy(&path[strlen(path)], _filename, sizeof(char) * strlen(_filename));
+
+  // open raw data file
+  FILE* datafptr;
+  if ((datafptr = fopen(path, "r")) == NULL) {
+    fprintf(stderr, 
+            "OctreeNode: Error reading data file %s.\n", 
+            path);
+    return;
+  }
+  
+  // raw data
+  unsigned char* data = NULL;
+
+  // Load unsigned 8bit int
+  if (_dataType == OCTREE_NODE_UNSIGNED_8_INT) {
+
+    // allocate memory for raw data
+    if ((data = new unsigned char[(int)(_whd[0]* _whd[1] * _whd[2])]) == 
+        NULL) {
+      fprintf(stderr, "OctreeNode: Memory allocation error\n.");
+      return;
+    }
+
+    // read raw data
+    if (fread(data, sizeof(unsigned char), 
+              _whd[0] * _whd[1] * _whd[2], datafptr) != 
+        _whd[0] * _whd[1] * _whd[2]) {
+      fprintf(stderr, 
+              "OctreeNode: Error reading data from file %s.\n", _filename);
+
+    }
+
+  }
+
+  // Load unsigned 16bit int
+  else if (_dataType == OCTREE_NODE_UNSIGNED_16_INT) {
+
+    // allocate memory for raw data
+    if ((data = new unsigned char[(int)(_whd[0] * _whd[1] * _whd[2] * 2)]) == 
+        NULL) {
+      fprintf(stderr, "OctreeNode: Memory allocation error\n.");
+      return;
+    }
+    
+    // read raw data
+    if (fread(data, sizeof(unsigned char), 
+              _whd[0] * _whd[1] * _whd[2] * 2, datafptr) != 
+        _whd[0] * _whd[1] * _whd[2] * 2) {
+      fprintf(stderr, 
+              "OctreeNode: Error reading data from file %s.\n", _filename);
+    }
+
+    // swap bytes
+    if (_dataFormat == OCTREE_NODE_LITTLE_ENDIAN) {
+      for (int i = 0 ; i < _whd[0] * _whd[1] * _whd[2] * 2 ; i += 2) {
+        unsigned char temp = 0;
+        temp = data[i];
+        data[i] = data[i+1];
+        data[i+1] = temp;
+      }
+    }
+
+  }
+
+  // close raw data file
+  fclose(datafptr);
+
+  // assign data
+  _data = data;
+
+  // set data loaded flag
+  _dataLoadedFlag = true;
+
+  // Message
+  sprintf(message, "LoadData node %d end.", _id);
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::LoadFromFile(const char* filename) {
+
+  // Message
+  Assert("LoadMetaData begin.");
+
+  // raw data file name
+  char datafilename[128];
+
+  // vertices
+  float v0x, v0y, v0z;
+  float v1x, v1y, v1z;
+  float v2x, v2y, v2z;
+  float v3x, v3y, v3z;
+  float v4x, v4y, v4z;
+  float v5x, v5y, v5z;
+  float v6x, v6y, v6z;
+  float v7x, v7y, v7z;
+
+  // width, height, depth
+  int w, h, d;
+
+  // Data type
+  char dataTypeString[128];
+
+  // Data format
+  char dataFormatString[128];
+
+  // level
+  int level;
+
+  // id
+  int id;
+
+  // number of children
+  int numberofchildren;
+
+  // child file name
+  char childfilename[128];
+
+  // Create full path and filename of file to load
+  char path[2048];
+  memset(path, 0, sizeof(char) * 2048);
+  memcpy(path, _prefix, sizeof(char) * strlen(_prefix));
+  memcpy(&path[strlen(path)], filename, sizeof(char) * strlen(filename));
+
+  // open metadata file
+  FILE* metafptr;
+  if ((metafptr = fopen(path, "r")) == NULL) {
+    fprintf(stderr, 
+            "OctreeNode: Error reading metadata file %s.\n", 
+            path);
+    return;
+  }
+
+  // read raw data filename
+  fscanf(metafptr, "%s", datafilename);
+
+  // read vertices
+  fscanf(metafptr, "%f %f %f", &v0x, &v0y, &v0z);
+  fscanf(metafptr, "%f %f %f", &v1x, &v1y, &v1z);
+  fscanf(metafptr, "%f %f %f", &v2x, &v2y, &v2z);
+  fscanf(metafptr, "%f %f %f", &v3x, &v3y, &v3z);
+  fscanf(metafptr, "%f %f %f", &v4x, &v4y, &v4z);
+  fscanf(metafptr, "%f %f %f", &v5x, &v5y, &v5z);
+  fscanf(metafptr, "%f %f %f", &v6x, &v6y, &v6z);
+  fscanf(metafptr, "%f %f %f", &v7x, &v7y, &v7z);
+  
+  // read width, height, depth
+  fscanf(metafptr, "%d %d %d", &w, &h, &d);
+
+  // read data type
+  fscanf(metafptr, "%s", dataTypeString);
+
+  // read data format
+  fscanf(metafptr, "%s", dataFormatString);
+
+  // read level, parent id, id
+  fscanf(metafptr, "%d %d", &level, &id);
+
+  // read children flag
+  fscanf(metafptr, "%d", &numberofchildren);
+
+  // assign data filename
+  strcpy(_filename, datafilename);
+
+  // assign vertices
+  _vertex[0].SetXYZ(v0x, v0y, v0z);
+  _vertex[1].SetXYZ(v1x, v1y, v1z);
+  _vertex[2].SetXYZ(v2x, v2y, v2z);
+  _vertex[3].SetXYZ(v3x, v3y, v3z);
+  _vertex[4].SetXYZ(v4x, v4y, v4z);
+  _vertex[5].SetXYZ(v5x, v5y, v5z);
+  _vertex[6].SetXYZ(v6x, v6y, v6z);
+  _vertex[7].SetXYZ(v7x, v7y, v7z);
+
+  // assign width, height, depth
+  _whd[0] = w;
+  _whd[1] = h;
+  _whd[2] = d;
+
+  // assign data type
+  if (!strcmp(dataTypeString, "UNSIGNED_8_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+  else if (!strcmp(dataTypeString, "UNSIGNED_16_INT")) {
+    _dataType = OCTREE_NODE_UNSIGNED_16_INT;
+  }
+  else {
+    fprintf(stderr, "OctreeNode: Unknown data type.\n");
+    _dataType = OCTREE_NODE_UNSIGNED_8_INT;
+  }
+
+  // assign data format
+  if (!strcmp(dataFormatString, "BIG_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+  }
+  else if (!strcmp(dataFormatString, "LITTLE_ENDIAN")) {
+    _dataFormat = OCTREE_NODE_LITTLE_ENDIAN;
+  }
+  else {
+    fprintf(stderr, "OctreeNode: Unknown data format.\n");
+    _dataFormat = OCTREE_NODE_BIG_ENDIAN;
+  }
+
+  // assign level
+  _level = level;
+
+  // assign id
+  _id = id;
+
+  // read children
+  for (int i = 0 ; i < numberofchildren ; i++) {
+    fscanf(metafptr, "%s", childfilename);
+    if ((_child[i] = new OctreeNode) == NULL) {
+      fprintf(stderr, "OctreeNode: Memory allocation error.\n");
+    }
+
+    // Create full path and filename of file to load
+    char childpath[2048];
+    memset(childpath, 0, sizeof(char) * 2048);
+    memcpy(childpath, _prefix, sizeof(char) * strlen(_prefix));
+    memcpy(&path[strlen(path)], childfilename, 
+           sizeof(char) * strlen(childfilename));
+
+    // Load child
+    _child[i] -> SetPrefix(_prefix);
+    _child[i] -> LoadFromFile(childfilename);
+  }
+
+  // close meta data file
+  fclose(metafptr);
+
+  // Message
+  Assert("LoadMetaData end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::LoadTexture() {
+
+  // Load unsigned 8 int
+  if (_dataType == OCTREE_NODE_UNSIGNED_8_INT) {
+    LoadTexture8();
+  }
+
+  // Load unsigned 16 int
+  else if (_dataType == OCTREE_NODE_UNSIGNED_16_INT) {
+    LoadTexture16();
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::LoadTexture8() {
+
+  // Message
+  char message[1024];
+  sprintf(message, "LoadTexture node %d begin.", _id);
+  Assert(message);
+
+  // Don't load if it's already loaded
+  if (_textureLoadedFlag == true) {
+    return;
+  }
+
+  // Enable 3D textures
+  glEnable(GL_TEXTURE_3D);
+
+  // Generate texture
+  glGenTextures(1, &_texture);
+
+  // Bind texture
+  glBindTexture(GL_TEXTURE_3D, _texture);
+
+  // Set clamping and interpolation parameters
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_S, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_T, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_R, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_MAG_FILTER, 
+                  GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_MIN_FILTER, 
+                  GL_LINEAR);
+  
+  // Load proxy texture
+  glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_ALPHA,  
+               GetW(), 
+               GetH(), 
+               GetD(),
+               0, GL_ALPHA, GL_UNSIGNED_BYTE, 
+               NULL);
+
+  // Get proxy texture width, height and depth
+  GLint width, height, depth;
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_WIDTH, &width);
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_HEIGHT, &height);
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_DEPTH, &depth);
+
+  // Test if there's enough resources for the desired texture
+  if (width == 0 || height == 0 || depth == 0) {
+    fprintf(stderr, "VolumeRenderer: Error loading texture.\n");
+    glDeleteTextures(1, &_texture);
+    fprintf(stderr, "Not loading data.\n");
+    return;
+  }
+
+  // Load texture
+  glTexImage3D(GL_TEXTURE_3D, 0, GL_ALPHA, 
+               GetW(),
+               GetH(),
+               GetD(),
+               0, GL_ALPHA, GL_UNSIGNED_BYTE,
+               GetData());
+
+  // Set texture loaded flag
+  _textureLoadedFlag = true;
+
+  // Disable 3D textures
+  glDisable(GL_TEXTURE_3D);
+
+  // Message
+  sprintf(message, "LoadTexture node %d end.", _id);
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::LoadTexture16() {
+
+  // Message
+  char message[1024];
+  sprintf(message, "LoadTexture node %d begin.", _id);
+  Assert(message);
+
+  // Don't load if it's already loaded
+  if (_textureLoadedFlag == true) {
+    return;
+  }
+
+  // Enable 3D textures
+  glEnable(GL_TEXTURE_3D);
+
+  // Generate texture
+  glGenTextures(1, &_texture);
+
+  // Bind texture
+  glBindTexture(GL_TEXTURE_3D, _texture);
+
+  // Set clamping and interpolation parameters
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_S, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_T, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_WRAP_R, 
+                  GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_MAG_FILTER, 
+                  GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_3D, 
+                  GL_TEXTURE_MIN_FILTER, 
+                  GL_LINEAR);
+  
+  // Load proxy texture
+  glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_LUMINANCE_ALPHA,  
+               GetW(), 
+               GetH(), 
+               GetD(),
+               0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 
+               NULL);
+
+  // Get proxy texture width, height and depth
+  GLint width, height, depth;
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_WIDTH, &width);
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_HEIGHT, &height);
+  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, 
+                           GL_TEXTURE_DEPTH, &depth);
+
+  // Test if there's enough resources for the desired texture
+  if (width == 0 || height == 0 || depth == 0) {
+    fprintf(stderr, "VolumeRenderer: Error loading texture.\n");
+    glDeleteTextures(1, &_texture);
+    fprintf(stderr, "Not loading data.\n");
+    return;
+  }
+
+  // Load texture
+  glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE_ALPHA, 
+               GetW(),
+               GetH(),
+               GetD(),
+               0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
+               GetData());
+
+  // Set texture loaded flag
+  _textureLoadedFlag = true;
+
+  // Disable 3D textures
+  glDisable(GL_TEXTURE_3D);
+
+  // Message
+  sprintf(message, "LoadTexture node %d end.", _id);
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::Print() {
+
+  // Message
+  char message[1024];
+  Assert("Printing OctreeNode begin.");
+
+  // Print node id
+  sprintf(message, 
+          "  Node ID: %d ", 
+          GetID());
+  Assert(message);
+
+  // Print node level
+  sprintf(message, 
+          "    Node Level: %d ", 
+          GetLevel());
+  Assert(message);
+
+  // Print node w, h, d
+  sprintf(message, 
+          "    W: %d", 
+          GetW());
+  Assert(message);
+  sprintf(message, 
+          "    H: %d", 
+          GetH());
+  Assert(message);
+  sprintf(message, 
+          "    D: %d", 
+          GetD());
+  Assert(message);
+
+  // Print data loaded flag
+  if (IsDataLoaded() == true) {
+    sprintf(message, 
+            "    Data Loaded: true");
+  }
+  else {
+    sprintf(message, 
+            "    Data Loaded: false");
+  }
+  Assert(message);
+
+  // Print texture loaded flag
+  if (IsTextureLoaded() == true) {
+    sprintf(message, 
+            "    Texture Loaded: true");
+  }
+  else {
+    sprintf(message, 
+            "    Texture Loaded: false");
+  }
+  Assert(message);
+  
+  // Message
+  Assert("Printing OctreeNode end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetChild(int index, OctreeNode* child) {
+
+  // Test index and set child node
+  if (index >= 0 && index <= 7) {
+    _child[index] = child;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetD(int d) {
+
+  // Set depth
+  _whd[2] = d;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetData(unsigned char* data) {
+
+  // Set data
+  _data = data;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetDataFormat(int format) {
+
+  // Set data format
+  _dataFormat = format;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetDataType(int type) {
+
+  // Set data type
+  _dataType = type;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetFilename(const char* filename) {
+
+  // Update local variables
+  if (filename != NULL) {
+    strcpy(_filename, filename);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetH(int h) {
+
+  // Set height
+  _whd[1] = h;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetID(int id) {
+
+  // Set node id
+  _id = id;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetLevel(int level) {
+
+  // Set node level
+  _level = level;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetPrefix(const char* prefix) {
+
+  // Update local variables
+  if (prefix != NULL) {
+    strcpy(_prefix, prefix);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetVertex(int index, Vertex vertex) {
+    
+  // Test index and set vertex
+  if (index >= 0 && index <= 7) {
+    _vertex[index] = vertex;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetVertex(int index, float x, float y, float z) {
+
+  // Test index and set vertex
+  if (index >= 0 && index <= 7) {
+    _vertex[index].SetXYZ(x, y, z);
+  }
+    
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetW(int w) {
+
+  // Set width
+  _whd[0] = w;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetWHD(int whd[3]) {
+
+  // Set dimensions
+  _whd[0] = whd[0];
+  _whd[1] = whd[1];
+  _whd[2] = whd[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::SetWHD(int w, int h, int d) {
+
+  // Set dimension
+  _whd[0] = w;
+  _whd[1] = h;
+  _whd[2] = d;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::UnloadData() {
+
+  // Message
+  char message[1024];
+  sprintf(message, "UnloadData node %d begin.", _id);
+  Assert(message);
+
+  // Clean up data
+  if (_dataLoadedFlag == true) {
+    if (_data != NULL) {
+      delete [] _data;
+      _data = NULL;
+    }
+    _dataLoadedFlag = false;
+  }
+
+  // Message
+  sprintf(message, "UnloadData node %d end.", _id);
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNode::UnloadTexture() {
+
+  // Message
+  char message[1024];
+  sprintf(message, "UnloadTexture node %d begin.", _id);
+  Assert(message);
+
+  // Delete texture
+  if (_textureLoadedFlag == true) {
+    glDeleteTextures(1, &_texture);
+    _textureLoadedFlag = false;
+  }
+
+  // Message
+  sprintf(message, "UnloadTexture node %d end.", _id);
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServer.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServer.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServer.h	(revision 4)
@@ -0,0 +1,121 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_SERVER_H
+#define SYNCHRONIZER_SERVER_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "SynchronizerServerAbstractCommand.h"
+#include "SynchronizerServerClientThreadInfo.h"
+#include "SynchronizerServerListenThreadInfo.h"
+
+/*--------------------------------------------------------------------------*/
+
+class SynchronizerServer {
+
+public:
+
+  // Default constructor
+  SynchronizerServer();
+
+  // Default destructor
+  ~SynchronizerServer();
+
+  // Finalize
+  void Finalize();
+
+  // Initialize
+  void Init(int port);
+
+  // Client thread function
+  static void *ClientThreadFunction(void* ptr);
+
+  // Listen thread function
+  static void *ListenThreadFunction(void* ptr);
+
+  // Monitor barrier thread function
+  static void *MonitorThreadFunction(void* ptr);
+
+  // Set progress observer
+  void SetProgressObserver(SynchronizerServerAbstractCommand* observer);
+
+private:
+
+  // Client thread info
+  SynchronizerServerClientThreadInfo _clientInfo[128];
+
+  // Client thread
+  pthread_t _clientThread[128];
+
+  // Condition mutex
+  pthread_mutex_t _conditionMutex;
+
+  // Condition variable
+  pthread_cond_t _conditionVariable;
+
+  // Finalize flag
+  bool _finalizeFlag;
+
+  // Current level
+  int _level;
+
+  // State for listen thread
+  SynchronizerServerListenThreadInfo _listenInfo;
+
+  // Thread listening for new clients
+  pthread_t _listenThread;
+
+  // Thread monitoring clients waiting at barrier
+  pthread_t _monitorThread;
+
+  // Number of clients connected
+  int _numberOfClients;
+
+  // Number of clients waiting at barrier
+  int _numberOfClientsWaiting;
+
+  // Server port
+  int _port;
+
+  // Progress observer
+  SynchronizerServerAbstractCommand* _progressObserver;
+
+  // Server address
+  struct sockaddr_in _serverAddress;
+
+  // Server socket file descriptor
+  int _serverSocketFileDescriptor;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Overview.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Overview.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Overview.h	(revision 4)
@@ -0,0 +1,155 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_OVERVIEW_H
+#define FL_OVERVIEW_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Gl_Window.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <GL/gl.h>
+
+#include "Matrix.h"
+#include "Trackball.h"
+#include "Vertex.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define FL_OVERVIEW_DOWN 0
+#define FL_OVERVIEW_UP 1
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Overview : public Fl_Gl_Window {
+
+public:
+
+  // Constructor
+  Fl_Overview(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Overview();
+
+  // Get scale matrix
+  void GetScaleMatrix(float m[16]);
+
+  // Get translation matrix
+  void GetTranslationMatrix(float m[16]);
+
+  // Reset view
+  void ResetView();
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set frustum
+  void SetFrustum(float frustum[6]);
+
+  // Set render callback
+  void SetRenderCallback(void (*cb)());
+
+  // Set rotation callback
+  void SetRotationCallback(void (*cb)(float* m));
+
+  // Set rotation matrix
+  void SetRotationMatrix(float m[16]);
+
+  // Set scale callback
+  void SetScaleCallback(void (*cb)(float* m));
+
+  // Set scale matrix
+  void SetScaleMatrix(float m[16]);
+
+  // Set translation callback
+  void SetTranslationCallback(void (*cb)(float* m));
+
+  // Set translation matrix
+  void SetTranslationMatrix(float m[16]);
+
+  // Set overview vertices
+  void SetVertices(Vertex vertex[8]);
+
+  // Implementation of draw method
+  void draw();
+
+  // Implementation of handle method
+  int handle(int event);
+
+private:
+
+  // Background color
+  float _backgroundColor[4];
+
+  // Frustum
+  float _frustum[6];
+
+  // Line color
+  float _lineColor[4];
+
+  // Mouse button state
+  int _mouseButtonState[3];
+
+  // Mouse position
+  int _mousePosition[2];
+
+  // Rotation matrix
+  float _R[16];
+
+  // Scale matrix
+  float _S[16];
+
+  // Translation matrix
+  float _T[16];
+
+  // Trackball rotation
+  Trackball trackball;
+
+  // Update render callback
+  void (*_updateRenderCallback)();
+
+  // Update rotation callback
+  void (*_updateRotationCallback)(float* m);
+
+  // Update scale callback
+  void (*_updateScaleCallback)(float* m);
+
+  // Update translation callback
+  void (*_updateTranslationCallback)(float* m);
+
+  // Vertex
+  Vertex _vertex[8];
+
+  // World rotate factor
+  float _worldRotate[3];
+
+  // World scale factor
+  float _worldScale[3];
+
+  // World translation factor
+  float _worldTranslate[3];
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OctreeNodeQueue.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/OctreeNodeQueue.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/OctreeNodeQueue.cpp	(revision 4)
@@ -0,0 +1,215 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "OctreeNodeQueue.h"
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNodeQueue::OctreeNodeQueue() {
+
+  // Initialize queue values
+  _back = -1;
+  _currentSize = 0;
+  _front = 0;
+  _maximumSize = 0;
+
+  // Allocate memory for queue
+  if ((_array = new OctreeNode*[128]) == NULL) {
+    fprintf(stderr, "OctreeNodeQueue: Memory allocation error.\n");
+  }
+  else {
+    _maximumSize = 128;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNodeQueue::OctreeNodeQueue(int size) {
+
+  // Initialize queue values
+  _back = -1;
+  _currentSize = 0;
+  _front = 0;
+  _maximumSize = 0;
+
+  // Allocate memory for queue
+  if ((_array = new OctreeNode*[size]) == NULL) {
+    fprintf(stderr, "OctreeNodeQueue: Memory allocation error.\n");
+  }
+  else {
+    _maximumSize = size;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNodeQueue::~OctreeNodeQueue() {
+
+  // Clean up queue
+  if (_array != NULL) {
+    delete [] _array;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNodeQueue::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Print message and time to log
+  char buffer[1024];
+  sprintf(buffer, "OctreeNodeQueue: %s", message);
+  Log::Assert(buffer);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNodeQueue::Clear() {
+
+  // Reset queue values
+  _back = -1;
+  _currentSize = 0;
+  _front = 0;
+
+  // Clear queue
+  for (int i = 0 ; i < _maximumSize ; i++) {
+    _array[i] = NULL;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OctreeNodeQueue::IsEmpty() {
+
+  // Check if queue is empty
+  if (_currentSize == 0) {
+    return true;
+  }
+  else {
+    return false;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OctreeNodeQueue::IsFull() {
+
+  // Check if queue is full
+  if (_currentSize == _maximumSize) {
+    return true;
+  }
+  else {
+    return false;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OctreeNodeQueue::Insert(OctreeNode* node) {
+
+  // Check if queue is full
+  if (IsFull() == true) {
+    return false;
+  }
+
+  // If end reaches end of array, set it to beginning
+  if (++_back == _maximumSize) {
+    _back = 0;
+  }
+
+  // Set node in queue
+  _array[_back] = node;
+
+  // Increment size
+  _currentSize++;
+
+  // Return
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OctreeNodeQueue::Print() {
+
+  // Message
+  Assert("Printing OctreeNodeQueue begin.");
+
+  // Message
+  char message[1024];
+  sprintf(message, "  Current Size: %d", _currentSize);
+  Assert(message);
+  sprintf(message, "  Maximum Size: %d", _maximumSize);
+  Assert(message);
+
+  // Print each node
+  for (int i = 0 ; i < _currentSize ; i++) {
+
+    // Location
+    int location = (_front + i) % _maximumSize;
+
+    // Print node
+    _array[i] -> Print();
+
+  }
+
+  // Message
+  Assert("Printing OctreeNodeQueue end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode* OctreeNodeQueue::Remove() {
+
+  // Check if queue is empty
+  if (IsEmpty() == true) {
+    return NULL;
+  }
+
+  // Decrement size
+  _currentSize--;
+
+  // Get node from front
+  OctreeNode* node = _array[_front];
+
+  // Set front to NULL
+  _array[_front] = NULL;
+
+  // If front reaches end of array, set it to beginning
+  if (++_front == _maximumSize) {
+    _front = 0;
+  }
+
+  // Return node
+  return node;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClient.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClient.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClient.cpp	(revision 4)
@@ -0,0 +1,2829 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceClient.h"
+#include <Fl/Fl.H>
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClient::UserInterfaceClient() {
+
+  // Initialize exit flag
+  _exitFlag = false;
+
+  // Initialize hostname
+  memset(_hostname, 0, 1024);
+
+  // Initialize is initialized flag
+  _isInitialized = false;
+
+  // Initialize observer
+  _observer = NULL;
+  
+  // Initialize port number
+  _port = 0;
+
+  // Initialize server
+  _server = NULL;
+
+  // Initialize server socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClient::~UserInterfaceClient() {
+
+  // Set exit flag
+  _exitFlag = true;
+
+  // If socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceClient: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("UserInterfaceClient: Error during socket close");
+    }
+
+  }
+
+  // Wait for thread to finish
+  if (_isInitialized == true) {
+    pthread_join(_thread, NULL);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::Disconnect() {
+
+  // Check that client is connected
+  if (_isInitialized == false) {
+    return;
+  }
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DCT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+
+  // Set exit flag
+  _exitFlag = true;
+
+
+  // If socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceClient: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("UserInterfaceClient: Error during socket close");
+    }
+
+  }
+
+
+  // Wait for thread listening for server updates to complete
+  pthread_join(_thread, NULL);
+
+  // Reset hostname
+  memset(_hostname, 0, 1024);
+
+  // Reset port
+  _port = 0;
+
+  // Reset socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+  // Set is initialized flag to false
+  _isInitialized = false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetAxis() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_AXS");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetAxisPosition() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_APO");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetBoundingBox() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_BOX");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetBrickBox() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_BBX");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetClippingPlanes(int node) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_CLI");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetData() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDatasetListFile(int index) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DSF");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDatasetListName(int index) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DSN");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDatasetListPrefix(int index) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DSP");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDatasetListSize() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DSS");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDatasetType() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DTP");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetDisplaySize(int node) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_DIS");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetFrustum(int node) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_FRU");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetMap() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_MAP");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetNumberOfSlaves() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_NUM");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetOverviewVertices() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_OVV");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetPrefix() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_PRE");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetRotationMatrix() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_ROT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetScaleMatrix() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_SCA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetSliceFrequency() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_SLF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetTotalDisplayDimensions() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_TDD");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetTotalDisplayFrustum() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_TDF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetTranslationMatrix() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_TRA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetVerticalFieldOfView() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_VFV");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::GetViewport(int node) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "GET_VIE");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int UserInterfaceClient::Init(char* hostname, int port) {
+
+  // Assign hostname
+  memcpy(_hostname, hostname, 1024);
+
+  // Assign server port number
+  _port = port;
+
+  // Create server socket
+  if ((_serverSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+    perror("UserInterfaceClient: Error creating socket");
+    return USER_INTERFACE_CLIENT_ERROR;
+  }
+
+  // Set TCP_NODELAY
+  int optVal = 1;
+  int optLen = sizeof(optVal);
+  if(setsockopt(_serverSocketFileDescriptor,
+                IPPROTO_TCP,
+                TCP_NODELAY,
+                (void*) &optVal,
+                (socklen_t) optLen) != 0) {
+    perror("UserInterfaceServer: Error setting TCP_NODELAY");
+  }
+
+  // Get host by name
+  if ((_server = gethostbyname(hostname)) == NULL) {
+    herror("UserInterfaceClient: Error resolving hostname");
+    close(_serverSocketFileDescriptor);
+    return USER_INTERFACE_CLIENT_ERROR;
+  }
+
+  // Initialize server address
+  memset(&_serverAddress, 0, sizeof(_serverAddress));
+  _serverAddress.sin_family = AF_INET;
+  bcopy((char*) _server -> h_addr,
+        (char*) &_serverAddress.sin_addr.s_addr,
+        _server -> h_length);
+  _serverAddress.sin_port = htons(_port);
+
+  // Connect to server
+  if (connect(_serverSocketFileDescriptor, 
+              (struct sockaddr*) &_serverAddress, 
+              sizeof(_serverAddress)) != 0) {
+    perror("UserInterfaceClient: Error connecting to server");
+    close(_serverSocketFileDescriptor);
+    _serverSocketFileDescriptor = -1;
+    return USER_INTERFACE_CLIENT_ERROR;
+  }
+
+  // Reset exit flag
+  _exitFlag = false;
+
+  // Create thread listening for server updates
+  pthread_create(&_thread,
+                 NULL,
+                 UserInterfaceClient::ThreadFunction,
+                 this);
+
+  // Set is initialized flag
+  _isInitialized = true;
+
+  // Return OK
+  return USER_INTERFACE_CLIENT_OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::ResetView() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_RVI");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendAxisOff() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AOF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendAxisOn() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AON");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendAxisPosition(float x, float y, float z) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AON");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(x);
+  packer.PackFloat(y);
+  packer.PackFloat(z);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendBoundingBoxOff() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BOF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendBoundingBoxOn() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BON");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendBrickBoxOff() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendBrickBoxOn() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBN");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendClippingPlanes(int node, 
+                                             float near, 
+                                             float far) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_CLI");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(near);
+  packer.PackFloat(far);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendCommandExit() {
+
+  // Check that client is connected
+  if (_isInitialized == false) {
+    return;
+  }
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_EXI");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+
+  // Set exit flag
+  _exitFlag = true;
+
+
+  // If socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceClient: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("UserInterfaceClient: Error during socket close");
+    }
+
+  }
+
+
+  // Wait for thread listening for server updates to complete
+  pthread_join(_thread, NULL);
+
+  // Reset hostname
+  memset(_hostname, 0, 1024);
+
+  // Reset port
+  _port = 0;
+
+  // Reset socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+  // Set is initialized flag to false
+  _isInitialized = false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendCommandRender() {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_REN");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendData(char* filename) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(filename[i]);
+  }
+  packer.PackInt(-1);
+  packer.PackInt(-1);
+  
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendData(char* filename,
+                                   int ramSize, int vramSize) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(filename[i]);
+  }
+  packer.PackInt(ramSize);
+  packer.PackInt(vramSize);
+  
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendFrustum(int node, float left, float right, 
+                                      float bottom, float top) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_FRU");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(left);
+  packer.PackFloat(right);
+  packer.PackFloat(bottom);
+  packer.PackFloat(top);
+  
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendMap(unsigned char* map) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_MAP");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackUnsignedChar(map[i]);
+  }
+  
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendMap16(unsigned char* map) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_M16");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+  // Payload
+  unsigned char payload[65536*4];
+  memset(payload, 0, 65536*4);
+
+  // Data packer
+  DataPacker ppacker;
+  ppacker.SetBuffer(payload, 65536*4);
+
+  // Pack data
+  for (int i = 0 ; i < 65536*4 ; i++) {
+    ppacker.PackUnsignedChar(map[i]);
+  }
+
+  // Send command
+  messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            payload, 
+                            65536*4, 
+                            0)) != 65536*4) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendPrefix(char* prefix) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_PRE");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < (int) strlen(prefix) ; i++) {
+    packer.PackChar(prefix[i]);
+  }
+
+  // Pack '/'
+  packer.PackChar('/');
+
+  // Pack end of string character
+  packer.PackChar('\0');
+  
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendRotationMatrix(float matrix[16]) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_ROT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(matrix[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendScaleMatrix(float matrix[16]) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SCA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(matrix[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendSliceFrequency(double frequency) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SLF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat((float) frequency);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendTranslationMatrix(float matrix[16]) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TRA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(matrix[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SendViewport(int node, int x, int y, 
+                                       int w, int h) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_VIE");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(x);
+  packer.PackInt(y);
+  packer.PackInt(w);
+  packer.PackInt(h);
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClient::SetObserver(UserInterfaceClientAbstractCommand* 
+                                      observer) {
+
+  // Set observer
+  _observer = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *UserInterfaceClient::ThreadFunction(void* ptr) {
+
+  // Cast user interface client class
+  UserInterfaceClient* uiclient = (UserInterfaceClient*) ptr;
+
+  // Loop accepting connections
+  while (1) {
+
+    // Buffer
+    unsigned char buffer[2048];
+    memset(buffer, 0, 2048);
+
+    // Command
+    char command[8];
+    memset(command, 0, 8);
+
+    // Destination
+    int destination = 0;
+    
+    // Message length
+    int messageLength = 0;
+
+    // Wait for message
+    if ((messageLength = recv(uiclient -> _serverSocketFileDescriptor, 
+                              buffer, 
+                              2048, 
+                              MSG_WAITALL)) != 2048) {
+
+      // If exit flag is set
+      if (uiclient -> _exitFlag == true) {
+        
+        // Exit thread
+        pthread_exit(NULL);
+
+      }
+
+      // Error receiving message from server
+      else {
+
+        // Print error message
+        perror("UserInterfaceClient: Error receiving message");
+
+        // Set exit flag
+        uiclient -> _exitFlag = true;
+
+        // If socket is open
+        if (uiclient -> _serverSocketFileDescriptor != -1) {
+          
+          // Shutdown socket
+          if (shutdown(uiclient -> _serverSocketFileDescriptor, 
+                       SHUT_RDWR) == -1) {
+            perror("UserInterfaceClient: Error during socket shutdown");
+          }
+          
+          // Close socket
+          if (close(uiclient -> _serverSocketFileDescriptor) == -1) {
+            perror("UserInterfaceClient: Error during socket close");
+          }
+          
+        }
+
+        // Reset hostname
+        memset(uiclient -> _hostname, 0, 1024);
+        
+        // Reset port
+        uiclient -> _port = 0;
+        
+        // Reset socket file descriptor
+        uiclient -> _serverSocketFileDescriptor = -1;
+        
+        // Set is initialized flag to false
+        uiclient -> _isInitialized = false;
+        
+        // Observer
+        if (uiclient -> _observer != NULL) {
+          uiclient -> _observer -> SetCommandExit();
+        }
+        
+        // Exit thread
+        pthread_exit(NULL);
+
+      }
+
+    }
+
+    // Data packer
+    DataPacker unpacker;
+    unpacker.SetBuffer(buffer, 2048);
+
+    // Unpack command from buffer
+    for (int i = 0 ; i < 8 ; i++) {
+      unpacker.UnpackChar(&command[i]);
+    }
+
+    // Unpack destination from buffer
+    unpacker.UnpackInt(&destination);
+    
+    // axis off
+    if (!strcmp(command, "CMD_AOF")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetAxisOff();
+      }
+
+    }
+
+
+    // axis on
+    else if (!strcmp(command, "CMD_AON")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetAxisOn();
+      }
+
+    }
+
+
+    // axis position
+    else if (!strcmp(command, "CMD_APO")) {
+
+      // Unpack data from buffer
+      float x = 0.0;
+      float y = 0.0;
+      float z = 0.0;
+      unpacker.UnpackFloat(&x);
+      unpacker.UnpackFloat(&y);
+      unpacker.UnpackFloat(&z);
+ 
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetAxisPosition(x, y, z);
+      }
+
+    }
+
+
+    // bounding box off
+    else if (!strcmp(command, "CMD_BOF")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetBoundingBoxOff();
+      }
+
+    }
+
+
+    // bounding box on
+    else if (!strcmp(command, "CMD_BON")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetBoundingBoxOn();
+      }
+
+    }
+
+
+    // brick box off
+    else if (!strcmp(command, "CMD_BBF")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetBrickBoxOff();
+      }
+
+    }
+
+
+    // brick box on
+    else if (!strcmp(command, "CMD_BBN")) {
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetBrickBoxOn();
+      }
+
+    }
+
+
+    // clipping planes
+    else if (!strcmp(command, "CMD_CLI")) {
+
+      // Unpack data from buffer
+      float near = 0.0;
+      float far = 0.0;
+      unpacker.UnpackFloat(&near);
+      unpacker.UnpackFloat(&far);
+ 
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetClippingPlanes(destination, near, far);
+      }
+
+    }
+
+
+    // exit
+    else if(!strcmp(command, "CMD_EXI")) {
+
+      // Set exit flag
+      uiclient -> _exitFlag = true;
+
+      // If socket is open
+      if (uiclient -> _serverSocketFileDescriptor != -1) {
+
+        // Shutdown socket
+        if (shutdown(uiclient -> _serverSocketFileDescriptor, 
+                     SHUT_RDWR) == -1) {
+          perror("UserInterfaceClient: Error during socket shutdown");
+        }
+
+        // Close socket
+        if (close(uiclient -> _serverSocketFileDescriptor) == -1) {
+          perror("UserInterfaceClient: Error during socket close");
+        }
+
+      }
+
+      // Reset hostname
+      memset(uiclient -> _hostname, 0, 1024);
+
+      // Reset port
+      uiclient -> _port = 0;
+
+      // Reset socket file descriptor
+      uiclient -> _serverSocketFileDescriptor = -1;
+
+      // Set is initialized flag to false
+      uiclient -> _isInitialized = false;
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetCommandExit();
+      }
+
+      // Exit thread
+      pthread_exit(NULL);
+
+    }
+
+
+    // data
+    else if(!strcmp(command, "CMD_DAT")) {
+
+      // Unpack data from buffer
+      char data[1024];
+      int ramSize = 0;
+      int vramSize = 0;
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackChar(&data[i]);
+      }
+      unpacker.UnpackInt(&ramSize);
+      unpacker.UnpackInt(&vramSize);
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetData(data, ramSize, vramSize);
+      }
+
+    }
+
+
+    // dataset list file
+    else if(!strcmp(command, "CMD_DSF")) {
+
+      // Unpack data from buffer
+      char data[1024];
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackChar(&data[i]);
+      }
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDatasetListFile(destination, data);
+      }
+
+    }
+
+
+    // dataset list name
+    else if(!strcmp(command, "CMD_DSN")) {
+
+      // Unpack data from buffer
+      char data[1024];
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackChar(&data[i]);
+      }
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDatasetListName(destination, data);
+      }
+
+    }
+
+
+    // dataset list name
+    else if(!strcmp(command, "CMD_DSP")) {
+
+      // Unpack data from buffer
+      char data[1024];
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackChar(&data[i]);
+      }
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDatasetListPrefix(destination, data);
+      }
+
+    }
+
+
+    // dataset list size
+    else if(!strcmp(command, "CMD_DSS")) {
+
+      // Unpack data from buffer
+      int data;
+      unpacker.UnpackInt(&data);
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDatasetListSize(data);
+      }
+
+    }
+
+
+    // dataset type
+    else if(!strcmp(command, "CMD_DTP")) {
+
+      // Unpack data from buffer
+      int data;
+      unpacker.UnpackInt(&data);
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDatasetType(data);
+      }
+
+    }
+
+
+    // display size
+    else if (!strcmp(command, "CMD_DIS")) {
+
+      // Unpack data from buffer
+      int width = 0;
+      int height = 0;
+      int flag = 0;
+      float left = 0.0;
+      float right = 0.0;
+      float bottom = 0.0;
+      float top = 0.0;
+      unpacker.UnpackInt(&width);
+      unpacker.UnpackInt(&height);
+      unpacker.UnpackInt(&flag);
+      unpacker.UnpackFloat(&left);
+      unpacker.UnpackFloat(&right);
+      unpacker.UnpackFloat(&bottom);
+      unpacker.UnpackFloat(&top);
+      
+      // Full screen flag
+      bool fullScreen = false;
+      if (flag == 1) {
+        fullScreen = true;
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetDisplaySize(destination, width, height, 
+                                                fullScreen, left, right, 
+                                                bottom, top);
+      }
+
+    }
+
+
+    // frustum
+    else if (!strcmp(command, "CMD_FRU")) {
+
+      // Unpack data from buffer
+      float left = 0.0;
+      float right = 0.0;
+      float bottom = 0.0;
+      float top = 0.0;
+      unpacker.UnpackFloat(&left);
+      unpacker.UnpackFloat(&right);
+      unpacker.UnpackFloat(&bottom);
+      unpacker.UnpackFloat(&top);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetFrustum(destination, left, right, 
+                                            bottom, top);
+      }
+
+    }
+
+
+    // map
+    else if (!strcmp(command, "CMD_MAP")) {
+
+      // Unpack data from buffer
+      unsigned char data[1024];
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackUnsignedChar(&data[i]);
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetMap(data);
+      }
+
+    }
+
+
+    // progress
+    else if (!strcmp(command, "CMD_PRO")) {
+
+      // Unpack data from buffer
+      int value = 0;
+      int total = 0;
+      unpacker.UnpackInt(&value);
+      unpacker.UnpackInt(&total);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetProgress(value, total);
+      }
+
+    }
+
+
+    // overview vertices
+    else if (!strcmp(command, "CMD_OVV")) {
+
+      // Unpack data from buffer
+      float data[24];
+      for (int i = 0 ; i < 24 ; i++) {
+        unpacker.UnpackFloat(&data[i]);
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetOverviewVertices(data);
+      }
+
+    }
+
+
+    // prefix
+    else if(!strcmp(command, "CMD_PRE")) {
+
+      // Unpack data from buffer
+      char data[1024];
+      for (int i = 0 ; i < 1024 ; i++) {
+        unpacker.UnpackChar(&data[i]);
+      }
+      
+      // Observer 
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetPrefix(data);
+      }
+
+    }
+
+    
+    // rotation matrix
+    else if (!strcmp(command, "CMD_ROT")) {
+
+      // Unpack data from buffer
+      float data[16];
+      for (int i = 0 ; i < 16 ; i++) {
+        unpacker.UnpackFloat(&data[i]);
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetRotationMatrix(data);
+      }
+
+    }
+
+
+    // scale matrix
+    else if (!strcmp(command, "CMD_SCA")) {
+
+      // Unpack data from buffer
+      float data[16];
+      for (int i = 0 ; i < 16 ; i++) {
+        unpacker.UnpackFloat(&data[i]);
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetScaleMatrix(data);
+      }
+
+    }
+
+
+    // slice frequency
+    else if (!strcmp(command, "CMD_SLF")) {
+
+      // Unpack data from buffer
+      float data;
+      unpacker.UnpackFloat(&data);
+      
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetSliceFrequency((double) data);
+      }
+
+    }
+
+
+    // total display dimensions
+    else if (!strcmp(command, "CMD_TDD")) {
+      
+      // Unpack data from buffer
+      int w = 0;
+      int h = 0;
+      unpacker.UnpackInt(&w);
+      unpacker.UnpackInt(&h);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetTotalDisplayDimensions(w, h);
+      }
+
+    }
+
+
+    // total display frustum
+    else if (!strcmp(command, "CMD_TDF")) {
+      
+      // Unpack data from buffer
+      float data[6];
+      unpacker.UnpackFloat(&data[0]);
+      unpacker.UnpackFloat(&data[1]);
+      unpacker.UnpackFloat(&data[2]);
+      unpacker.UnpackFloat(&data[3]);
+      unpacker.UnpackFloat(&data[4]);
+      unpacker.UnpackFloat(&data[5]);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetTotalDisplayFrustum(data);
+      }
+
+    }
+
+
+    // translation matrix
+    else if (!strcmp(command, "CMD_TRA")) {
+
+      // Unpack data from buffer
+      float data[16];
+      for (int i = 0 ; i < 16 ; i++) {
+        unpacker.UnpackFloat(&data[i]);
+      }
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetTranslationMatrix(data);
+      }
+
+    }
+
+
+    // vertical field of view
+    else if (!strcmp(command, "CMD_VFV")) {
+
+      // Unpack data from buffer
+      float vFOV = 0.0;
+      unpacker.UnpackFloat(&vFOV);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetVerticalFieldOfView(vFOV);
+      }
+
+    }
+
+
+    // viewport matrix
+    else if (!strcmp(command, "CMD_VIE")) {
+
+      // Unpack data from buffer
+      int x = 0;
+      int y = 0;
+      int w = 0;
+      int h = 0;
+      unpacker.UnpackInt(&x);
+      unpacker.UnpackInt(&y);
+      unpacker.UnpackInt(&w);
+      unpacker.UnpackInt(&h);
+
+      // Observer
+      if (uiclient -> _observer != NULL) {
+        uiclient -> _observer -> SetViewport(destination, x, y, w, h);
+      }
+      
+    }
+
+
+    // undefined command
+    else {
+    }
+
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.cpp	(revision 4)
@@ -0,0 +1,154 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "VolumeRendererThreadInfo.h"
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererThreadInfo::VolumeRendererThreadInfo() {
+
+  // Initialize abort render flag
+  _abortFlag = false;
+
+  // Initialize axis on flag
+  _axisOnFlag = false;
+
+  // Initialize axis position
+  _axisPosition[0] = 0.0;
+  _axisPosition[1] = 0.0;
+  _axisPosition[2] = 0.0;
+
+  // Initialize brick box flag
+  _brickBoxOnFlag = false;
+
+  // Initialize bounding box flag
+  _boundingBoxOnFlag = false;
+
+  // Initialize condition variable to NULL
+  _conditionCond = NULL;
+
+  // Initialize mutex to NULL
+  _conditionMutex = NULL;
+
+  // Initialize data to NULL
+  _data = NULL;
+
+  // Initialize display size
+  _displaySize[0] = 0;
+  _displaySize[1] = 1;
+
+  // Initialize exit flag
+  _exitFlag = false;
+
+  // Initialize frustum
+  _frustum[0] = 0.0;
+  _frustum[1] = 0.0;
+  _frustum[2] = 0.0;
+  _frustum[3] = 0.0;
+  _frustum[4] = 0.0;
+  _frustum[5] = 0.0;
+
+  // Initialize full screen flag
+  _fullScreenFlag = false;
+
+  // Initialize render in progress flag
+  _inRenderFlag = false;
+
+  // Initialize map to NULL
+  _map = NULL;
+
+  // Initialize map type
+  _mapType = VOLUME_RENDERER_THREAD_INFO_MAP_8;
+
+  // Initialize normal coordinates
+  _normalCoordinates[0] = 0.0;
+  _normalCoordinates[1] = 0.0;
+  _normalCoordinates[2] = 0.0;
+  _normalCoordinates[3] = 0.0;
+
+  // Initialize number of nodes
+  _numberOfNodes = 0;
+
+  // Initialize rotation matrix to identity
+  _R[0] = 1.0; _R[4] = 0.0; _R[8] = 0.0; _R[12] = 0.0;
+  _R[1] = 0.0; _R[5] = 1.0; _R[9] = 0.0; _R[13] = 0.0;
+  _R[2] = 0.0; _R[6] = 0.0; _R[10] = 1.0; _R[14] = 0.0;
+  _R[3] = 0.0; _R[7] = 0.0; _R[11] = 0.0; _R[15] = 1.0;
+
+  // Initialize CacheRAM Size
+  _ramSize = 50;
+
+  // Initialize rank
+  _rank = 0;
+
+  // Initialize render flag to false
+  _renderFlag = false;
+
+  // Initialize scale matrix to identity
+  _S[0] = 1.0; _S[4] = 0.0; _S[8] = 0.0; _S[12] = 0.0;
+  _S[1] = 0.0; _S[5] = 1.0; _S[9] = 0.0; _S[13] = 0.0;
+  _S[2] = 0.0; _S[6] = 0.0; _S[10] = 1.0; _S[14] = 0.0;
+  _S[3] = 0.0; _S[7] = 0.0; _S[11] = 0.0; _S[15] = 1.0;
+
+  // Initialize slice frequency
+  _sliceFrequency = 1.0;
+
+  // Initialize synchronization server hostname
+  memset(_synchronizationHostname, 0, 128);
+
+  // Initialize synchronization server port
+  _synchronizationPort = 0;
+
+  // Initialize translation matrix to identity
+  _T[0] = 1.0; _T[4] = 0.0; _T[8] = 0.0; _T[12] = 0.0;
+  _T[1] = 0.0; _T[5] = 1.0; _T[9] = 0.0; _T[13] = 0.0;
+  _T[2] = 0.0; _T[6] = 0.0; _T[10] = 1.0; _T[14] = 0.0;
+  _T[3] = 0.0; _T[7] = 0.0; _T[11] = 0.0; _T[15] = 1.0;
+
+  // Initialize all update property flags to false
+  _updateAxis = false;
+  _updateBrickBox = false;
+  _updateBoundingBox = false;
+  _updateData = false;
+  _updateFrustum = false;
+  _updateMap = false;
+  _updateR = false;
+  _updateS = false;
+  _updateSliceFrequency = false;
+  _updateT = false;
+  _updateViewport = false;
+
+  // Initialize viewport
+  _viewport[0] = 0;
+  _viewport[1] = 0;
+  _viewport[2] = 0;
+  _viewport[3] = 0;
+
+  // Initialize CacheVRAM Size
+  _vramSize = 10;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererThreadInfo::~VolumeRendererThreadInfo() {
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.cpp	(revision 4)
@@ -0,0 +1,445 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Opacity_Transfer_Function.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Opacity_Transfer_Function::Fl_Opacity_Transfer_Function(int x, int y, 
+                                                           int w, int h, 
+                                                           const char *l) 
+  : Fl_Gl_Window(x, y, w, h, l) {
+
+  // Initialize callbacks
+  _callbackMove = NULL;
+  _callbackSelect = NULL;
+  _callbackUnselect = NULL;
+
+  // Initialize callback data
+  _callbackMovePtr = NULL;
+  _callbackSelectPtr = NULL;
+  _callbackUnselectPtr = NULL;
+
+  // Initialize control point picked
+  _controlPointPicked = -1;
+
+  // Create new transfer function widget
+  _otfw = new OpacityTransferFunctionWidget(w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Opacity_Transfer_Function::~Fl_Opacity_Transfer_Function() {
+
+  // Clean up
+  delete _otfw;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::GetControlPoint(int index, 
+                                                   float* scalar, 
+                                                   float* opacity) {
+
+  // Get control point
+  _otfw -> GetControlPoint(index, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int  Fl_Opacity_Transfer_Function::GetControlPointIndex(int px, int py) {
+
+  // Get control point index
+  return _otfw -> GetControlPointIndex(px, py);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int  Fl_Opacity_Transfer_Function::GetControlPointIndex(float scalar, 
+                                                        float opacity) {
+
+  // Get control point index
+  return _otfw -> GetControlPointIndex(scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Opacity_Transfer_Function::GetFunctionCoordinates(int px, int py, 
+                                                          float* scalar, 
+                                                          float* opacity) {
+
+  // Get function coordinates
+  return _otfw -> GetFunctionCoordinates(px, py, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Opacity_Transfer_Function::GetNumberOfControlPoints() {
+
+  // Get number of control points
+  return _otfw -> GetNumberOfControlPoints();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Opacity_Transfer_Function::GetSelectedControlPoint() {
+
+  // Return slected control point
+  return _controlPointPicked;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Fl_Opacity_Transfer_Function::GetOpacity(float scalar) {
+
+  // Get opacity
+  return _otfw -> GetOpacity(scalar);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::GetOpacityRange(float* min, float* max) {
+
+  // Get opacity range
+  _otfw -> GetOpacityRange(min, max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::GetScalarRange(float* min, float* max) {
+
+  // Get scalar range
+  _otfw -> GetScalarRange(min, max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Opacity_Transfer_Function::MoveControlPoint(int index, int px, int py) {
+
+  // Move control point
+  return _otfw -> MoveControlPoint(index, px, py);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Opacity_Transfer_Function::MoveControlPoint(int index, 
+                                                    float scalar, 
+                                                    float opacity) {
+
+  // Move control point
+  return _otfw -> MoveControlPoint(index, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Opacity_Transfer_Function::RemoveControlPoint(int index) {
+
+  // Remove control point
+  return _otfw -> RemoveControlPoint(index);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::RestoreControlPoints(int number, 
+                                                        float max, 
+                                                        float* scalar, 
+                                                        float* opacity) {
+
+  // Restore control points
+  _otfw -> RestoreControlPoints(number, max, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetBackgroundColor(float r, float g, 
+                                                      float b, float a) {
+
+  // Set background color
+  _otfw -> SetBackgroundColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetBoxColor(float r, float g, 
+                                               float b, float a) {
+
+  // Set box color
+  _otfw -> SetBoxColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetControlPointColor(float r, float g, 
+                                                        float b, float a) {
+
+  // Set control point color
+  _otfw -> SetControlPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetControlPointSize(int size) {
+
+  // Set control point size
+  _otfw -> SetControlPointSize(size);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetFocusPointColor(float r, float g, 
+                                                      float b, float a) {
+
+  // Set focus point color
+  _otfw -> SetFocusPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetLineColor(float r, float g, 
+                                                float b, float a) {
+
+  // Set line color
+  _otfw -> SetLineColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetMaximumScalar(float max) {
+
+  // Set maximum scalar
+  _otfw -> SetMaximumScalar(max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetMoveCallback(void (*cb)(void*), 
+                                                   void* p) {
+
+  // Set callback
+  _callbackMove = cb;
+
+  // Set pointer
+  _callbackMovePtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetSelectCallback(void (*cb)(void*), 
+                                                     void* p) {
+
+  // Set callback
+  _callbackSelect = cb;
+
+  // Set pointer
+  _callbackSelectPtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetTextColor(float r, float g, 
+                                                float b, float a) {
+
+  // Set text color
+  _otfw -> SetTextColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::SetUnselectCallback(void (*cb)(void*),
+                                                       void* p) {
+
+  // Set callback
+  _callbackUnselect = cb;
+
+  // Set pointer
+  _callbackUnselectPtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Opacity_Transfer_Function::draw() {
+
+  // Set dimensions
+  _otfw -> SetDimensions(w(), h());
+
+  // Draw widget
+  _otfw -> Draw();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Opacity_Transfer_Function::handle(int event) {
+
+  // Check event
+  switch(event) {
+
+
+  case FL_PUSH: {
+
+    // Get button
+    int button = Fl::event_button();
+
+    // Check select button
+    if (button == 1) {
+      _mouseButtonState[0] = DOWN;
+      _controlPointPicked = 
+        _otfw -> GetControlPointIndex(Fl::event_x(), Fl::event_y());
+
+      // Check callback
+      if (_callbackSelect != NULL && _callbackUnselect != NULL) {
+        if (_controlPointPicked == -1) {
+          _callbackUnselect(_callbackUnselectPtr);
+        }
+        else {
+          _callbackSelect(_callbackSelectPtr);
+        }
+      }
+
+    }
+
+    // Check remove button
+    else if (button == 2) {
+      _mouseButtonState[1] = DOWN;
+      _controlPointPicked = 
+        _otfw -> GetControlPointIndex(Fl::event_x(), Fl::event_y());
+      if (_callbackSelect != NULL && _callbackUnselect != NULL) {
+        if (_otfw -> RemoveControlPoint(_controlPointPicked) == true ||
+            _controlPointPicked == -1) {
+          _callbackUnselect(_callbackUnselectPtr);
+        }
+        else {
+          _callbackSelect(_callbackSelectPtr);
+        }
+      }
+    }
+
+    // Check add button
+    else if (button == 3) {
+      _mouseButtonState[2] = DOWN;
+      if (_otfw -> AddControlPoint(Fl::event_x(), Fl::event_y()) == true) {
+        _controlPointPicked = 
+          _otfw -> GetControlPointIndex(Fl::event_x(), Fl::event_y());
+        if (_callbackSelect != NULL) {
+          _callbackSelect(_callbackSelectPtr);
+        }
+      }
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_DRAG: {
+
+    // Move the picked control point
+    if (_mouseButtonState[0] == DOWN) {
+      _otfw -> MoveControlPoint(_controlPointPicked, 
+                                Fl::event_x(), Fl::event_y());
+
+      // Check callback
+      if (_callbackMove != NULL) {
+        if (_controlPointPicked != -1) {
+          _callbackMove(_callbackMovePtr);
+        }
+      }
+
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_RELEASE: {
+
+    // Get button
+    int button = Fl::event_button();
+    
+    // Check which button
+    if (button == 1) {
+      _mouseButtonState[0] = UP;
+      //_controlPointPicked = -1;
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  default: {
+
+    // Pass other events to the base class
+    return Fl_Gl_Window::handle(event);
+
+  }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheRAM.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CacheRAM.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheRAM.cpp	(revision 4)
@@ -0,0 +1,394 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CacheRAM.h"
+
+/*--------------------------------------------------------------------------*/
+
+CacheRAM::CacheRAM(int size) {
+
+  // Message
+  Assert("Constructor begin.");
+
+  // Initialize size
+  _currentSize = 0;
+
+  // Initialize maximum size
+  _maximumSize = size;
+
+  // Initialize front
+  _front = NULL;
+
+  // Message
+  Assert("Constructor end.");
+
+}
+  
+/*--------------------------------------------------------------------------*/
+
+CacheRAM::~CacheRAM() {
+
+  // Message
+  Assert("Destructor begin.");
+
+  // Current and next node pointers used to iterate through cache
+  CacheRAMNode* current = NULL;
+  CacheRAMNode* next = NULL;
+
+  // Iterate through cache deleting each node
+  while (current != NULL) {
+    next = current -> GetNext();
+    delete current;
+    current = next;
+  }
+
+  // Message
+  Assert("Destructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Print message to log
+  char buffer[1024];
+  sprintf(buffer, "CacheRAM: %s", message);
+  Log::Assert(buffer);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool CacheRAM::IsFull() {
+
+  // Check if cache is full
+  if (_currentSize >= _maximumSize) {
+
+    // Message
+    Assert("Is cache full? True.");
+
+    // Return true
+    return true;
+  }
+
+  // Message
+  Assert("Is cache full? False.");
+
+  // Return false
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool CacheRAM::IsLoaded(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Is node %d loaded? Checking...", node -> GetID());
+  Assert(message);
+
+  // Node pointers used for iteration
+  CacheRAMNode* tmp = _front;
+ 
+  // Iterate through cache until node is found based on its id
+  while (tmp != NULL) {
+
+    // Check if node is found
+    if (tmp -> GetOctreeNode() -> GetID() == node -> GetID()) {
+
+      // Message
+      sprintf(message, "Is node %d loaded? True.", node -> GetID());
+      Assert(message);
+
+      // Return true
+      return true;
+    }
+
+    // Next node
+    tmp = tmp -> GetNext();
+
+  }
+
+  // Message
+  sprintf(message, "Is node %d loaded? False.", node -> GetID());
+  Assert(message);
+
+  // Return false
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::Load(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Load node %d begin.", node -> GetID());
+  Assert(message);
+
+  // Allocate new node
+  CacheRAMNode* tmp = new CacheRAMNode;
+  if (tmp == NULL) {
+    fprintf(stderr, "CacheRAM: Memory allocation error.\n");
+    return;
+  }
+
+  // If cache is full, remove LRU node at end of cache
+  if (IsFull() == true) {
+    RemoveLast();
+  }
+
+  // Load octree node's data
+  node -> LoadData();
+
+  // Set cache node's parameters
+  tmp -> SetOctreeNode(node);
+  tmp -> SetNext(_front);
+  tmp -> SetPrevious(NULL);
+
+  // Place in front
+  if (_front != NULL) {
+    _front -> SetPrevious(tmp);
+  }
+
+  // Set front
+  _front = tmp;
+
+  // Increment size
+  _currentSize++;
+
+  // Message
+  sprintf(message, "Load node %d end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::MakeCurrent(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Make node %d current begin.", node -> GetID());
+  Assert(message);
+
+  // If octree node data is loaded, move it to the front
+  if (IsLoaded(node) == true) {
+
+    // Message
+    sprintf(message, 
+            "Make node %d current. Move node to front.", 
+            node -> GetID());
+    Assert(message);
+
+    // Move node to front
+    MoveToFront(node);
+  }
+
+  // Load node, automatically placing it at front
+  else {
+
+    // Message
+    sprintf(message, 
+            "Make node %d current. Load node.", 
+            node -> GetID());
+    Assert(message);
+
+    // Load node
+    Load(node);
+  }
+
+  // Message
+  sprintf(message, "Make node %d current end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::MoveToFront(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Move node %d to front begin.", node -> GetID());
+  Assert(message);
+
+  // Node pointers used for iteration
+  CacheRAMNode* tmp = _front;
+
+  // Iterate through cache until node is found based on its id
+  while (tmp != NULL) {
+    if (tmp -> GetOctreeNode() -> GetID() == node -> GetID()) {
+      break;
+    }
+    tmp = tmp -> GetNext();
+  }
+
+  // Node is not found
+  if (tmp == NULL) {
+    return;
+  }
+
+  // Node is already at the front
+  if (tmp -> GetPrevious() == NULL) {
+    return;
+  }
+
+  // Connect the node's previous and next node
+  (tmp -> GetPrevious()) -> SetNext(tmp -> GetNext());
+  if (tmp -> GetNext() != NULL) {
+    (tmp -> GetNext()) -> SetPrevious(tmp -> GetPrevious());
+  }
+
+  // Place at front
+  tmp -> SetPrevious(NULL);
+  if (_front != NULL) {
+    _front -> SetPrevious(tmp);
+  }
+  tmp -> SetNext(_front);
+
+  // Set front
+  _front = tmp;
+
+  // Message
+  sprintf(message, "Move node %d to front end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::Print() {
+
+  // Message
+  Assert("Printing CacheRAM begin.");
+
+  // Message
+  char message[1024];
+  sprintf(message, "  Current Size: %d", _currentSize);
+  Assert(message);
+  sprintf(message, "  Maximum Size: %d", _maximumSize);
+  Assert(message);
+
+  // Front of queue
+  CacheRAMNode* current = _front;
+
+  // Traverse queue
+  while (current != NULL) {
+
+    // Print node id
+    sprintf(message, 
+            "  Node ID: %d ", 
+            current -> GetOctreeNode() -> GetID());
+    Assert(message);
+
+    // Print level id
+    sprintf(message, 
+            "    Node Level: %d", 
+            current -> GetOctreeNode() -> GetLevel());
+    Assert(message);
+
+    // Print data loaded flag
+    if (current -> GetOctreeNode() -> IsDataLoaded() == true) {
+      sprintf(message, 
+              "    Data Loaded: true");
+    }
+    else {
+      sprintf(message, 
+              "    Data Loaded: false");
+    }
+    Assert(message);
+
+    // Print texture loaded flag
+    if (current -> GetOctreeNode() -> IsTextureLoaded() == true) {
+      sprintf(message, 
+              "    Texture Loaded: true");
+    }
+    else {
+      sprintf(message, 
+              "    Texture Loaded: false");
+    }
+    Assert(message);
+
+    // Next node
+    current = current -> GetNext();
+
+  }
+
+  // Message
+  Assert("Printing CacheRAM end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAM::RemoveLast() {
+
+  // Message
+  Assert("Removing last node begin.");
+
+  // Current and next node pointers used to iterate through cache
+  CacheRAMNode* previous = NULL;
+  CacheRAMNode* current = _front;
+
+  // Empty cache
+  if (current == NULL) {
+    return;
+  }
+
+  // Decrement size
+  _currentSize--;
+
+  // Iterate until the end of the cache is reached
+  while (current != NULL) {
+    previous = current;
+    current = current -> GetNext();
+  }
+
+  // Get the last node
+  current = previous;
+  previous = current -> GetPrevious();
+
+  // Remove last node rom cache
+  if (previous == NULL) {
+    _front = NULL;
+  }
+  else {
+    previous -> SetNext(NULL);
+  }
+
+  // Unload octree nodes' data
+  current -> GetOctreeNode() -> UnloadData();
+
+  // Clean up node
+  delete current;
+
+  // Message
+  Assert("Removing last node end.");
+
+}
+  
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/DataPacker.h
===================================================================
--- trunk/src/testing/app/VRA/src/DataPacker.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/DataPacker.h	(revision 4)
@@ -0,0 +1,116 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#ifndef DATA_PACKER_H
+#define DATA_PACKER_H
+
+/*---------------------------------------------------------------------------*/
+
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*---------------------------------------------------------------------------*/
+
+// Status
+#define DATA_PACKER_OK 0
+#define DATA_PACKER_ERROR 1
+
+// Data types
+#define DATA_PACKER_CHAR 2
+#define DATA_PACKER_FLOAT 3
+#define DATA_PACKER_INT 4
+#define DATA_PACKER_UNSIGNED_CHAR 5
+
+// Data type sizes
+#define DATA_PACKER_CHAR_SIZE 1
+#define DATA_PACKER_FLOAT_SIZE 4
+#define DATA_PACKER_INT_SIZE 4
+#define DATA_PACKER_UNSIGNED_CHAR_SIZE 1
+
+/*---------------------------------------------------------------------------*/
+
+class DataPacker {
+
+public:
+
+  // Default constructor
+  DataPacker();
+
+  // Default destructor
+  ~DataPacker();
+
+  // Get buffer and buffer size
+  void* GetBuffer(int* size);
+
+  // Get buffer position
+  int GetPosition();
+
+  // Pack char
+  int PackChar(char value);
+
+  // Pack float
+  int PackFloat(float value);
+
+  // Pack int
+  int PackInt(int value);
+
+  // Pack unsigned char
+  int PackUnsignedChar(unsigned char value);
+
+  // Reset
+  void Reset();
+
+  // Set buffer and buffer size
+  void SetBuffer(void* buffer, int size);
+
+  // Set buffer position
+  int SetPosition(int position);
+
+  // Pack char
+  int UnpackChar(char* value);
+
+  // Pack float
+  int UnpackFloat(float* value);
+
+  // Pack int
+  int UnpackInt(int* value);
+
+  // Pack unsigned char
+  int UnpackUnsignedChar(unsigned char* value);
+
+private:
+
+  // Data buffer
+  unsigned char* _buffer;
+
+  // Buffer position
+  int _position;
+
+  // Buffer size
+  int _size;
+
+};
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerAbstractCommand.cpp	(revision 4)
@@ -0,0 +1,37 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "SynchronizerServerAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServerAbstractCommand::SynchronizerServerAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServerAbstractCommand::~SynchronizerServerAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool SynchronizerServerAbstractCommand::Execute(int value) {
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheRAMNode.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CacheRAMNode.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheRAMNode.cpp	(revision 4)
@@ -0,0 +1,92 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CacheRAMNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+CacheRAMNode::CacheRAMNode() {
+
+  // Initialize cache node values to NULL
+  _previous = NULL;
+  _next = NULL;
+  _node = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheRAMNode::~CacheRAMNode() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheRAMNode* CacheRAMNode::GetNext() {
+
+  // Return next cache node
+  return _next;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode* CacheRAMNode::GetOctreeNode() {
+
+  // Return octree node
+  return _node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheRAMNode* CacheRAMNode::GetPrevious() {
+
+  // Return previous cache node
+  return _previous;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAMNode::SetNext(CacheRAMNode* node) {
+
+  // Set next cache node
+  _next = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAMNode::SetOctreeNode(OctreeNode* node) {
+
+  // Set octree node
+  _node = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheRAMNode::SetPrevious(CacheRAMNode* node) {
+
+  // Set previous cache node
+  _previous = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServerAbstractCommand.cpp	(revision 4)
@@ -0,0 +1,300 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceServerAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServerAbstractCommand::UserInterfaceServerAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServerAbstractCommand::~UserInterfaceServerAbstractCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetAxis(bool* state) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetAxisPosition(float* x,
+                                                         float* y,
+                                                         float* z) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetBoundingBox(bool* state) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetBrickBox(bool* state) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetClippingPlanes(int node, 
+                                                           float* near, 
+                                                           float* far) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetData(char* filename) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetData(char* filename,
+                                                 int* ramSize, int* vramSize) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDatasetListFile(int index,
+                                                            char* file) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDatasetListName(int index,
+                                                            char* name) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDatasetListPrefix(int index,
+                                                              char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDatasetListSize(int* size) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDatasetType(int* type) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetDisplaySize(int node, 
+                                                        int* width, 
+                                                        int* height,
+                                                        bool* fullScreen,
+                                                        float* left, 
+                                                        float* right,
+                                                        float* bottom, 
+                                                        float* top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetFrustum(int node, 
+                                                    float* left, 
+                                                    float* right,
+                                                    float* bottom, 
+                                                    float* top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetMap(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetPrefix(char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetOverviewVertices(float 
+                                                             vertices[24]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetRotationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetScaleMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetSliceFrequency(double* frequency) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetTotalDisplayDimensions(int* w, 
+                                                                   int* h) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetTotalDisplayFrustum(float 
+                                                                frustum[6]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetTranslationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetVerticalFieldOfView(float* vFOV) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::GetViewport(int node, 
+                                                     int* x, 
+                                                     int* y, 
+                                                     int* w, 
+                                                     int* h) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::ResetView() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetAxisOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetAxisOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetAxisPosition(float x, float y, 
+                                                         float z) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetBoundingBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetBoundingBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetBrickBoxOff() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetBrickBoxOn() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetClippingPlanes(int node, 
+                                                           float near, 
+                                                           float far) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetCommandExit() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetCommandRender() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetData(char* filename) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetData(char* filename,
+                                                 int ramSize, int vramSize) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetFrustum(int node, 
+                                                    float left, float right,
+                                                    float bottom, float top) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetMap(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetMap16(unsigned char* map) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetPrefix(char* prefix) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetRotationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetScaleMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetSliceFrequency(double frequency) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetTranslationMatrix(float m[16]) {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerAbstractCommand::SetViewport(int node, int x, int y, 
+                                                     int w, int h) {
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Transfer_Function.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Transfer_Function.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Transfer_Function.cpp	(revision 4)
@@ -0,0 +1,898 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Transfer_Function.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Transfer_Function::Fl_Transfer_Function(int x, int y, int w, int h, 
+                                           const char *l) 
+  : Fl_Double_Window(x, y, 640, 220, l) {
+
+  // Create new transfer function widget
+  _ctf = new Fl_Color_Transfer_Function(0, 0, 520, 105);
+  _ctf -> SetBackgroundColor(0.75, 0.75, 0.75, 1.0);
+  _ctf -> SetBoxColor(0.0, 0.0, 0.0, 1.0);
+  _ctf -> SetTextColor(0.0, 0.0, 0.0, 1.0);
+  _ctf -> SetMoveCallback(StaticCallbackColorMove, this);
+  _ctf -> SetSelectCallback(StaticCallbackColorSelect, this);
+  _ctf -> SetUnselectCallback(StaticCallbackColorUnselect, this);
+
+  // Create a nice transfer function
+  float s[] = {0.0, 0.5, 1.0};
+  float r[] = {0.0, 0.0, 1.0};
+  float g[] = {0.0, 1.0, 0.0};
+  float b[] = {1.0, 0.0, 0.0};
+  _ctf -> RestoreControlPoints(3, 1.0, s, r, g, b);
+
+  // Create color scalar input field
+  _colorScalarInput = new Fl_Int_Input(565, 5, 70, 20, "Scalar:");
+  _colorScalarInput -> labelsize(11);
+  _colorScalarInput -> textsize(11);
+  _colorScalarInput -> value("");
+  _colorScalarInput -> callback(StaticCallbackChangeColorScalar, this);
+  _colorScalarInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _colorScalarInput -> deactivate();
+
+  // Create color scalar input field
+  _redInput = new Fl_Float_Input(565, 30, 70, 20, "Red:");
+  _redInput -> labelsize(11);
+  _redInput -> textsize(11);
+  _redInput -> value("");
+  _redInput -> callback(StaticCallbackChangeRed, this);
+  _redInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _redInput -> deactivate();
+
+  // Create color scalar input field
+  _greenInput = new Fl_Float_Input(565, 55, 70, 20, "Green:");
+  _greenInput -> labelsize(11);
+  _greenInput -> textsize(11);
+  _greenInput -> value("");
+  _greenInput -> callback(StaticCallbackChangeGreen, this);
+  _greenInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _greenInput -> deactivate();
+
+  // Create color scalar input field
+  _blueInput = new Fl_Float_Input(565, 80, 70, 20, "Blue:");
+  _blueInput -> labelsize(11);
+  _blueInput -> textsize(11);
+  _blueInput -> value("");
+  _blueInput -> callback(StaticCallbackChangeBlue, this);
+  _blueInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _blueInput -> deactivate();
+
+
+  // Create new transfer function widget
+  _otf = new Fl_Opacity_Transfer_Function(0, 115, 520, 105);
+  _otf -> SetBackgroundColor(0.75, 0.75, 0.75, 1.0);
+  _otf -> SetBoxColor(0.0, 0.0, 0.0, 1.0);
+  _otf -> SetTextColor(0.0, 0.0, 0.0, 1.0);
+  _otf -> SetMoveCallback(StaticCallbackOpacityMove, this);
+  _otf -> SetSelectCallback(StaticCallbackOpacitySelect, this);
+  _otf -> SetUnselectCallback(StaticCallbackOpacityUnselect, this);
+
+  // Create scalar input field
+  _scalarInput = new Fl_Int_Input(565, 120, 70, 20, "Scalar:");
+  _scalarInput -> labelsize(11);
+  _scalarInput -> textsize(11);
+  _scalarInput -> value("");
+  _scalarInput -> callback(StaticCallbackChangeScalar, this);
+  _scalarInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _scalarInput -> deactivate();
+
+  // Create opacity input field
+  _opacityInput = new Fl_Float_Input(565, 145, 70, 20, "Opacity:");
+  _opacityInput -> labelsize(11);
+  _opacityInput -> textsize(11);
+  _opacityInput -> value("");
+  _opacityInput -> callback(StaticCallbackChangeOpacity, this);
+  _opacityInput -> when(FL_WHEN_ENTER_KEY | FL_WHEN_RELEASE);
+  _opacityInput -> deactivate();
+
+  // Initialize update callback and update callback data
+  _updateCallback = NULL;
+  _updateCallbackData = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Transfer_Function::~Fl_Transfer_Function() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeBlue() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Modify color
+  _ctf -> ModifyControlPointColor(index,
+                                  (float) atof(_redInput -> value()),
+                                  (float) atof(_greenInput -> value()),
+                                  (float) atof(_blueInput -> value()));
+
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.3f", r);
+  sprintf(gString, "%.3f", g);
+  sprintf(bString, "%.3f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Redraw widget
+  _ctf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeColorScalar() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Move control point
+  _ctf -> MoveControlPoint(index, (float) atof(_colorScalarInput -> value())); 
+                           
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.4f", r);
+  sprintf(gString, "%.4f", g);
+  sprintf(bString, "%.4f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Redraw widget
+  _ctf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeGreen() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Modify color
+  _ctf -> ModifyControlPointColor(index,
+                                  (float) atof(_redInput -> value()),
+                                  (float) atof(_greenInput -> value()),
+                                  (float) atof(_blueInput -> value()));
+
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.3f", r);
+  sprintf(gString, "%.3f", g);
+  sprintf(bString, "%.3f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Redraw widget
+  _ctf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeOpacity() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float opacity = 0.0;
+  char opacityString[128];
+
+  // Get selected control point
+  index = _otf -> GetSelectedControlPoint();
+
+  // Move control point
+  _otf -> MoveControlPoint(index, 
+                           (float) atof(_scalarInput -> value()), 
+                           (float) atof(_opacityInput -> value()));
+
+  // Get function coordinates
+  _otf -> GetControlPoint(index, &scalar, &opacity);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(opacityString, "%.3f", opacity);
+
+  // Update input fields
+  _scalarInput -> value(scalarString);
+  _opacityInput -> value(opacityString);
+
+  // Redraw widget
+  _otf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeRed() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Modify color
+  _ctf -> ModifyControlPointColor(index,
+                                  (float) atof(_redInput -> value()),
+                                  (float) atof(_greenInput -> value()),
+                                  (float) atof(_blueInput -> value()));
+
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.3f", r);
+  sprintf(gString, "%.3f", g);
+  sprintf(bString, "%.3f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Redraw widget
+  _ctf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackChangeScalar() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float opacity = 0.0;
+  char opacityString[128];
+
+  // Get selected control point
+  index = _otf -> GetSelectedControlPoint();
+
+  // Move control point
+  _otf -> MoveControlPoint(index, 
+                           (float) atof(_scalarInput -> value()), 
+                           (float) atof(_opacityInput -> value()));
+
+  // Get function coordinates
+  _otf -> GetControlPoint(index, &scalar, &opacity);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(opacityString, "%.3f", opacity);
+
+  // Update input fields
+  _scalarInput -> value(scalarString);
+  _opacityInput -> value(opacityString);
+
+  // Redraw widget
+  _otf -> redraw();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackColorMove() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.3f", r);
+  sprintf(gString, "%.3f", g);
+  sprintf(bString, "%.3f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackColorSelect() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float r = 0.0;
+  char rString[128];
+  float g = 0.0;
+  char gString[128];
+  float b = 0.0;
+  char bString[128];
+
+  // Get selected control point
+  index = _ctf -> GetSelectedControlPoint();
+
+  // Get function coordinates
+  _ctf -> GetControlPoint(index, &scalar, &r, &g, &b);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(rString, "%.3f", r);
+  sprintf(gString, "%.3f", g);
+  sprintf(bString, "%.3f", b);
+
+  // Update input fields
+  _colorScalarInput -> value(scalarString);
+  _redInput -> value(rString);
+  _greenInput -> value(gString);
+  _blueInput -> value(bString);
+
+  // Activate input fields
+  _colorScalarInput -> activate();
+  _redInput -> activate();
+  _greenInput -> activate();
+  _blueInput -> activate();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackColorUnselect() {
+
+  // Update input fields
+  _colorScalarInput -> value("");
+  _redInput -> value("");
+  _greenInput -> value("");
+  _blueInput -> value("");
+
+  // Disable input fields
+  _colorScalarInput -> deactivate();
+  _redInput -> deactivate();
+  _greenInput -> deactivate();
+  _blueInput -> deactivate();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackOpacityMove() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float opacity = 0.0;
+  char opacityString[128];
+
+  // Get selected control point
+  index = _otf -> GetSelectedControlPoint();
+
+  // Get function coordinates
+  _otf -> GetControlPoint(index, &scalar, &opacity);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(opacityString, "%.3f", opacity);
+
+  // Update input fields
+  _scalarInput -> value(scalarString);
+  _opacityInput -> value(opacityString);
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackOpacitySelect() {
+
+  // Temporary variables
+  int index = 0;
+  float scalar = 0.0;
+  char scalarString[128];
+  float opacity = 0.0;
+  char opacityString[128];
+
+  // Get selected control point
+  index = _otf -> GetSelectedControlPoint();
+
+  // Get function coordinates
+  _otf -> GetControlPoint(index, &scalar, &opacity);
+
+  // Convert to strings
+  sprintf(scalarString, "%d", (int) scalar);
+  sprintf(opacityString, "%.3f", opacity);
+
+  // Update input fields
+  _scalarInput -> value(scalarString);
+  _opacityInput -> value(opacityString);
+
+  // Activate input fields
+  _scalarInput -> activate();
+  _opacityInput -> activate();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::CallbackOpacityUnselect() {
+
+  // Update input fields
+  _scalarInput -> value("");
+  _opacityInput -> value("");
+
+  // Disable input fields
+  _scalarInput -> deactivate();
+  _opacityInput -> deactivate();
+
+  // Update callback
+  if (_updateCallback != NULL) {
+    _updateCallback(_updateCallbackData);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::GetColor(float scalar, float* r, 
+                                    float* g, float* b) {
+
+  // Get color
+  _ctf -> GetColor(scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::GetColorControlPoint(int index, float* scalar, 
+                                                float* r, float* g, float* b) {
+
+  // Return color control point
+  _ctf -> GetControlPoint(index, scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Transfer_Function::GetNumberOfColorControlPoints() {
+
+  // Return number of color control points
+  return _ctf -> GetNumberOfControlPoints();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Transfer_Function::GetNumberOfOpacityControlPoints() {
+
+  // Return number of opacity control points
+  return _otf -> GetNumberOfControlPoints();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Fl_Transfer_Function::GetOpacity(float scalar) {
+
+  // Return opacity for given value
+  return _otf -> GetOpacity(scalar);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::GetOpacityControlPoint(int index, float* scalar, 
+                                                  float* opacity) {
+
+  // Get opacity control point
+  _otf -> GetControlPoint(index, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::GetOpacityRange(float* min, float* max) {
+
+  // Get opacity range
+  _otf -> GetOpacityRange(min, max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::GetScalarRange(float* min, float* max) {
+
+  // Get scalar range: opacity and color function ranges should match
+  _otf -> GetScalarRange(min, max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::Redraw() {
+
+  // Redraw
+  _ctf -> redraw();
+  _otf -> redraw();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::RestoreColorControlPoints(int number, float max, 
+                                                     float* scalar, 
+                                                     float* r, float* g, 
+                                                     float* b) {
+
+  // Restore color control points
+  _ctf -> RestoreControlPoints(number, max, scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::RestoreOpacityControlPoints(int number, float max, 
+                                                       float* scalar, 
+                                                       float* opacity) {
+
+  // Restore opacity control points
+  _otf -> RestoreControlPoints(number, max, scalar, opacity);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetBackgroundColor(float r, float g, 
+                                              float b, float a) {
+
+  // Set background color
+  _ctf -> SetBackgroundColor(r, g, b, a);
+  _otf -> SetBackgroundColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetBoxColor(float r, float g, float b, float a) {
+
+  // Set box color
+  _ctf -> SetBoxColor(r, g, b, a);
+  _otf -> SetBoxColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetControlPointColor(float r, float g, 
+                                                float b, float a) {
+
+  // Set control point color
+  _ctf -> SetControlPointColor(r, g, b, a);
+  _otf -> SetControlPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetControlPointSize(int size) {
+
+  // Set control point size
+  _ctf -> SetControlPointSize(size);
+  _otf -> SetControlPointSize(size);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetFocusPointColor(float r, float g, 
+                                              float b, float a) {
+
+  // Set focus point color
+  _ctf -> SetFocusPointColor(r, g, b, a);
+  _otf -> SetFocusPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetLineColor(float r, float g, float b, float a) {
+
+  // Set line color
+  _ctf -> SetLineColor(r, g, b, a);
+  _otf -> SetLineColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetMaximumScalar(float max) {
+
+  // Set maximum scalar
+  _ctf -> SetMaximumScalar(max);
+  _otf -> SetMaximumScalar(max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetTextColor(float r, float g, float b, float a) {
+
+  // Set text color
+  _ctf -> SetTextColor(r, g, b, a);
+  _otf -> SetTextColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::SetUpdateCallback(void (*cb)(void* p), void* d) {
+
+  // Set update callback and update callback data
+  _updateCallback = cb;
+  _updateCallbackData = d;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeBlue(Fl_Widget* w, void *v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeBlue();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeColorScalar(Fl_Widget* w, 
+                                                           void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeColorScalar();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeGreen(Fl_Widget* w, void *v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeGreen();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeOpacity(Fl_Widget* w, void *v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeOpacity();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeRed(Fl_Widget* w, void *v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeRed();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackChangeScalar(Fl_Widget* w, void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackChangeScalar();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackColorMove(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackColorMove();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackColorSelect(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackColorSelect();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackColorUnselect(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackColorUnselect();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackOpacityMove(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackOpacityMove();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackOpacitySelect(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackOpacitySelect();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Transfer_Function::StaticCallbackOpacityUnselect(void* v) {
+
+  // Callback
+  ((Fl_Transfer_Function*) v) -> CallbackOpacityUnselect();
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.cpp	(revision 4)
@@ -0,0 +1,1243 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceClientConcreteCommand.h"
+#include <stdio.h>
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClientConcreteCommand::UserInterfaceClientConcreteCommand() {
+
+  _addMessageCallback = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClientConcreteCommand::
+UserInterfaceClientConcreteCommand(void (*cb)(unsigned char* message)) {
+
+  _addMessageCallback = cb;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceClientConcreteCommand::~UserInterfaceClientConcreteCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetAxisOff() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AOF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetAxisOn() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AON");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetAxisPosition(float x,
+                                                         float y, 
+                                                         float z) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_APO");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(x);
+  packer.PackFloat(y);
+  packer.PackFloat(z);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetBoundingBoxOff() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BOF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetBoundingBoxOn() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BON");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetBrickBoxOff() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetBrickBoxOn() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBN");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetClippingPlanes(int node, 
+                                                           float near, 
+                                                           float far) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_CLI");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(near);
+  packer.PackFloat(far);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetCommandExit() {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_EXI");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetData(char* filename) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(filename[i]);
+  }
+  packer.PackInt(-1);
+  packer.PackInt(-1);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetData(char* filename,
+                                                 int ramSize, int vramSize) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(filename[i]);
+  }
+  packer.PackInt(ramSize);
+  packer.PackInt(vramSize);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDatasetListFile(int index, 
+                                                            char* file) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DSF");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(file[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDatasetListName(int index, 
+                                                            char* name) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DSN");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(name[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDatasetListPrefix(int index, 
+                                                              char* prefix) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DSP");
+
+  // Destination
+  int destination = index;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(prefix[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDatasetListSize(int size) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DSS");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(size);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }  
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDatasetType(int type) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DTP");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(type);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }  
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetDisplaySize(int node, 
+                                                        int width, 
+                                                        int height, 
+                                                        bool fullScreen, 
+                                                        float left, 
+                                                        float right, 
+                                                        float bottom, 
+                                                        float top) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DIS");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Full screen flag
+  int flag = 0;
+  if (fullScreen == true) {
+    flag = 1;
+  }
+
+  // Pack data
+  packer.PackInt(width);
+  packer.PackInt(height);
+  packer.PackInt(flag);
+  packer.PackFloat(left);
+  packer.PackFloat(right);
+  packer.PackFloat(bottom);
+  packer.PackFloat(top);
+      
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetFrustum(int node, 
+                                                    float left, 
+                                                    float right,
+                                                    float bottom, 
+                                                    float top) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_FRU");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(left);
+  packer.PackFloat(right);
+  packer.PackFloat(bottom);
+  packer.PackFloat(top);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetMap(unsigned char* map) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_MAP");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackUnsignedChar(map[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetOverviewVertices(float 
+                                                             vertices[24]) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_OVV");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 24 ; i++) {
+    packer.PackFloat(vertices[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetPrefix(char* prefix) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_PRE");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(prefix[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetProgress(int value, int total) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_PRO");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(value);
+  packer.PackInt(total);
+
+  //fprintf(stderr, "UICCC level: %d of %d\n", value, total);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetRotationMatrix(float m[16]) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_ROT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetScaleMatrix(float m[16]) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SCA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetSliceFrequency(double frequency) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SLF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat((float) frequency);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetTotalDisplayDimensions(int w, 
+                                                                   int h) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TDD");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(w);
+  packer.PackInt(h);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetTotalDisplayFrustum(float 
+                                                                frustum[6]) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TDF");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(frustum[0]);
+  packer.PackFloat(frustum[1]);
+  packer.PackFloat(frustum[2]);
+  packer.PackFloat(frustum[3]);
+  packer.PackFloat(frustum[4]);
+  packer.PackFloat(frustum[5]);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetTranslationMatrix(float m[16]) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TRA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetVerticalFieldOfView(float vFOV) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_VFV");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackFloat(vFOV);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceClientConcreteCommand::SetViewport(int node, int x, int y, 
+                                                     int w, int h) {
+
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_VIE");
+
+  // Destination
+  int destination = node;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  packer.PackInt(x);
+  packer.PackInt(y);
+  packer.PackInt(w);
+  packer.PackInt(h);
+
+  // Add message
+  if (_addMessageCallback != NULL) {
+    _addMessageCallback(buffer);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Vertex.h
===================================================================
--- trunk/src/testing/app/VRA/src/Vertex.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Vertex.h	(revision 4)
@@ -0,0 +1,113 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VERTEX_H
+#define VERTEX_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Vertex {
+
+ public:
+
+  // Default constructor
+  Vertex();
+
+  // Constructor
+  Vertex(double x, double y, double z);
+
+  // Constructor
+  Vertex(float x, float y, float z);
+  
+  // Constructor
+  Vertex(double xyz[3]);
+
+  // Constructor
+  Vertex(float xyz[3]);
+
+  // Default destructor
+  ~Vertex();
+
+  // Get X
+  float GetX();
+
+  // Get Y
+  float GetY();
+
+  // Get Z
+  float GetZ();
+
+  // Get XYZ
+  void GetXYZ(double* x, double* y, double* z);
+
+  // Get XYZ
+  void GetXYZ(float* x, float* y, float* z);
+
+  // Get XYZ
+  void GetXYZ(double xyz[3]);
+
+  // Get XYZ
+  void GetXYZ(float xyz[3]);
+
+  // Set X
+  void SetX(double x);
+
+  // Set X
+  void SetX(float x);
+
+  // Set Y
+  void SetY(double y);
+
+  // Set Y
+  void SetY(float y);
+
+  // Set Z 
+  void SetZ(double z);
+
+  // Set Z 
+  void SetZ(float z);
+
+  // Set XYZ
+  void SetXYZ(double x, double y, double z);
+
+  // Set XYZ
+  void SetXYZ(float x, float y, float z);
+
+  // Set XYZ
+  void SetXYZ(double xyz[3]);
+
+  // Set XYZ
+  void SetXYZ(float xyz[3]);
+  
+ private:
+  
+  // Vertex
+  float _xyz[3];
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.cpp	(revision 4)
@@ -0,0 +1,232 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CommunicatorConcreteCommand.h"
+#include "Slave.h"
+
+/*--------------------------------------------------------------------------*/
+
+CommunicatorConcreteCommand::CommunicatorConcreteCommand() {
+
+  _slave = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CommunicatorConcreteCommand::CommunicatorConcreteCommand(void* slave) {
+
+  _slave = slave;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CommunicatorConcreteCommand::~CommunicatorConcreteCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetAxisOff() {
+
+  ((Slave*) _slave) -> UpdateAxisOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetAxisOn() {
+
+  ((Slave*) _slave) -> UpdateAxisOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetAxisPosition(float x, float y, float z) {
+
+  ((Slave*) _slave) -> UpdateAxisPosition(x, y, z);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetBrickBoxOff() {
+
+  ((Slave*) _slave) -> UpdateBrickBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetBrickBoxOn() {
+
+  ((Slave*) _slave) -> UpdateBrickBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetBoundingBoxOff() {
+
+  ((Slave*) _slave) -> UpdateBoundingBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetBoundingBoxOn() {
+
+  ((Slave*) _slave) -> UpdateBoundingBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetClippingPlanes(float near, float far) {
+
+  ((Slave*) _slave) -> UpdateClippingPlanes(near, far);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetCommandExit() {
+
+  ((Slave*) _slave) -> UpdateCommandExit();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetCommandRender() {
+
+  ((Slave*) _slave) -> UpdateCommandRender();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetData(char* filename) {
+
+  ((Slave*) _slave) -> UpdateData(filename);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetData(char* filename,
+                                          int ramSize, int vramSize) {
+
+  ((Slave*) _slave) -> UpdateData(filename, ramSize, vramSize);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetDisplaySize(int width, 
+                                                 int height, 
+                                                 bool fullScreen,
+                                                 char* hostname,
+                                                 int port,
+                                                 float left,
+                                                 float right,
+                                                 float bottom,
+                                                 float top) {
+
+  ((Slave*) _slave) -> 
+    UpdateDisplaySize(width, height, fullScreen, hostname, port, 
+                      left, right, bottom, top);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetFrustum(float left, float right,
+                                             float bottom, float top) {
+
+  ((Slave*) _slave) -> UpdateFrustum(left, right, bottom, top);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetMap(unsigned char* map) {
+
+  ((Slave*) _slave) -> UpdateMap(map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetMap16(unsigned char* map) {
+
+  ((Slave*) _slave) -> UpdateMap16(map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetPrefix(char* prefix) {
+
+  ((Slave*) _slave) -> UpdatePrefix(prefix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetRotationMatrix(float matrix[16]) {
+
+  ((Slave*) _slave) -> UpdateRotationMatrix(matrix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetScaleMatrix(float matrix[16]) {
+
+  ((Slave*) _slave) -> UpdateScaleMatrix(matrix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetSliceFrequency(double frequency) {
+
+  ((Slave*) _slave) -> UpdateSliceFrequency(frequency);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetTranslationMatrix(float matrix[16]) {
+
+  ((Slave*) _slave) -> UpdateTranslationMatrix(matrix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CommunicatorConcreteCommand::SetViewport(int x, int y, int w, int h) {
+
+  ((Slave*) _slave) -> UpdateViewport(x, y, w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServer.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServer.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServer.cpp	(revision 4)
@@ -0,0 +1,2177 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceServer.h"
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServer::UserInterfaceServer() {
+
+  // Initialize client socket file descriptor
+  _clientSocketFileDescriptor = -1;
+
+  // Initialize is connected flag
+  _isConnected = false;
+
+  // Initialize is initialized flag
+  _isInitialized = false;
+
+  // Initialize observer
+  _observer = NULL;
+  
+  // Initialize port number
+  _port = 0;
+
+  // Initialize server
+  _server = NULL;
+
+  // Initialize server socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServer::~UserInterfaceServer() {
+
+  // If server socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("UserInterfaceServer: Error during socket close");
+    }
+
+  }
+
+  // If client socket is open
+  if (_clientSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_clientSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_clientSocketFileDescriptor) == -1) {
+      perror("UserInterfaceServer: Error during socket close");
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int UserInterfaceServer::Accept() {
+
+  // Initialize variables to hold client info
+  memset(&_clientAddress, 0, sizeof(_clientAddress));
+  int clientLength = sizeof(_clientAddress);
+  
+  // Wait for a new connection
+  _clientSocketFileDescriptor = 
+    accept(_serverSocketFileDescriptor, 
+           (struct sockaddr*) &_clientAddress, 
+           (socklen_t*) &clientLength);
+  
+  // Check for error with accept
+  if (_clientSocketFileDescriptor == -1) {
+    perror("UserInterfaceServer: Error accepting new connections");
+    return USER_INTERFACE_SERVER_ERROR;
+  }
+  
+  // Set SO_REUSEADDR
+  int optVal = 1;
+  int optLen = sizeof(optVal);
+  if(setsockopt(_clientSocketFileDescriptor, 
+                SOL_SOCKET, 
+                SO_REUSEADDR, 
+                (void*) &optVal, 
+                (socklen_t) optLen) != 0) {
+    perror("UserInterfaceServer: Error setting SO_REUSEADDR");
+  }
+
+  // Set TCP_NODELAY
+  optVal = 1;
+  optLen = sizeof(optVal);
+  if(setsockopt(_clientSocketFileDescriptor,
+                IPPROTO_TCP,
+                TCP_NODELAY,
+                (void*) &optVal,
+                (socklen_t) optLen) != 0) {
+    perror("UserInterfaceServer: Error setting TCP_NODELAY");
+  }
+  
+  // Check for error during accept
+  if (_clientSocketFileDescriptor == -1) {
+    perror("UserInterfaceServer: Error accepting new connection");
+    close(_serverSocketFileDescriptor);
+    return USER_INTERFACE_SERVER_ERROR;
+  }
+
+  // Set is connected flag
+  _isConnected = true;
+
+  // Return OK
+  return USER_INTERFACE_SERVER_OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int UserInterfaceServer::GetCommand() {
+
+  // Check if server is intialized
+  if (_isInitialized == false) {
+    return USER_INTERFACE_SERVER_ERROR;
+  }
+
+  // Check if server is connected
+  if (_isConnected == false) {
+    return USER_INTERFACE_SERVER_ERROR;
+  }
+
+
+  // Message buffer
+  char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+
+  // Destination
+  int destination = 0;
+
+  // Message length
+  int messageLength = 0;
+
+
+  // File descriptor set
+  fd_set rfds;
+
+  // Timeout for select
+  struct timeval timeout;
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 100;
+
+  // Setup for select
+  FD_ZERO(&rfds);
+  FD_SET(_clientSocketFileDescriptor, &rfds);
+
+  // Check for data
+  if (select(_clientSocketFileDescriptor + 1, &rfds, NULL, NULL, &timeout) == 
+      0) {
+    return USER_INTERFACE_SERVER_NO_DATA;
+  }
+
+
+  // Wait for message from client
+  if ((messageLength = recv(_clientSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            MSG_WAITALL)) != 2048) {
+    return USER_INTERFACE_SERVER_ERROR;
+  }
+
+
+  // Data packer
+  DataPacker unpacker;
+  unpacker.SetBuffer(buffer, 2048);
+
+  // Unpack command from buffer
+  for (int i = 0 ; i < 8 ; i++) {
+    unpacker.UnpackChar(&command[i]);
+  }
+
+  // Unpack destination from buffer
+  unpacker.UnpackInt(&destination);
+  //fprintf(stderr, "UIS Command %s\n", command);
+
+  // get axis state
+  if (!strcmp(command, "GET_AXS")) {
+
+    // Data
+    bool state = false;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetAxis(&state);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    if (state == false) { strcpy(command, "CMD_AOF"); }
+    else { strcpy(command, "CMD_AON"); }
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get axis position
+  else if (!strcmp(command, "GET_APO")) {
+
+    // Data
+    float x = 0.0;
+    float y = 0.0;
+    float z = 0.0;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetAxisPosition(&x, &y, &z);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_APO");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackFloat(x);
+    packer.PackFloat(y);
+    packer.PackFloat(z);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get bounding box state
+  else if (!strcmp(command, "GET_BOX")) {
+
+    // Data
+    bool state = false;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetBoundingBox(&state);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    if (state == false) { strcpy(command, "CMD_BOF"); }
+    else { strcpy(command, "CMD_BON"); }
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get brick box state
+  else if (!strcmp(command, "GET_BBX")) {
+
+    // Data
+    bool state = false;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetBoundingBox(&state);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    if (state == false) { strcpy(command, "CMD_BBF"); }
+    else { strcpy(command, "CMD_BBN"); }
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get clipping planes
+  else if (!strcmp(command, "GET_CLI")) {
+
+    // Data
+    float near = 0.0;
+    float far = 0.0;
+ 
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetClippingPlanes(destination, &near, &far);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_CLI");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    packer.PackFloat(near);
+    packer.PackFloat(far);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get data
+  else if (!strcmp(command, "GET_DAT")) {
+
+    // Data
+    char data[1024];
+    int ramSize = -1;
+    int vramSize = -1;
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetData(data, &ramSize, &vramSize);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DAT");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(data[i]);
+    }
+    packer.PackInt(ramSize);
+    packer.PackInt(vramSize);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get dataset list file
+  else if (!strcmp(command, "GET_DSF")) {
+
+    // Data
+    char data[1024];
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetDatasetListFile(destination, data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DSF");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get dataset list name
+  else if (!strcmp(command, "GET_DSN")) {
+
+    // Data
+    char data[1024];
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetDatasetListName(destination, data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DSN");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get dataset list file
+  else if (!strcmp(command, "GET_DSP")) {
+
+    // Data
+    char data[1024];
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetDatasetListPrefix(destination, data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DSP");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get data
+  else if (!strcmp(command, "GET_DSS")) {
+
+    // Data
+    int size;
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetDatasetListSize(&size);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DSS");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackInt(size);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get display size
+  else if (!strcmp(command, "GET_DIS")) {
+
+    // Data
+    int width = 0;
+    int height = 0;
+    bool fullScreen = false;
+    float left = 0.0;
+    float right = 0.0;
+    float bottom = 0.0;
+    float top = 0.0;
+      
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetDisplaySize(destination, &width, &height, &fullScreen, 
+                                  &left, &right, &bottom, &top);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DIS");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Flag
+    int flag = 0;
+    if (fullScreen == true) {
+      flag = 1;
+    }
+
+    // Pack data
+    packer.PackInt(width);
+    packer.PackInt(height);
+    packer.PackInt(flag);
+    packer.PackFloat(left);
+    packer.PackFloat(right);
+    packer.PackFloat(bottom);
+    packer.PackFloat(top);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get data type
+  else if (!strcmp(command, "GET_DTP")) {
+
+    // Data
+    int type;
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetDatasetType(&type);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_DTP");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackInt(type);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get frustum
+  else if (!strcmp(command, "GET_FRU")) {
+
+    // Data
+    float left = 0.0;
+    float right = 0.0;
+    float bottom = 0.0;
+    float top = 0.0;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetFrustum(destination, &left, &right, &bottom, &top);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_FRU");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    packer.PackFloat(left);
+    packer.PackFloat(right);
+    packer.PackFloat(bottom);
+    packer.PackFloat(top);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get map
+  else if (!strcmp(command, "GET_MAP")) {
+
+    // Data
+    unsigned char data[1024];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetMap(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_MAP");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackUnsignedChar(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get map
+  else if (!strcmp(command, "GET_OVV")) {
+
+    // Data
+    float data[24];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetOverviewVertices(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_OVV");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 24 ; i++) {
+      packer.PackFloat(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get prefix
+  else if (!strcmp(command, "GET_PRE")) {
+
+    // Data
+    char data[1024];
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> GetPrefix(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_PRE");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get rotation matrix
+  else if (!strcmp(command, "GET_ROT")) {
+
+    // Data
+    float data[16];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetRotationMatrix(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_ROT");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 16 ; i++) {
+      packer.PackFloat(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get scale matrix
+  else if (!strcmp(command, "GET_SCA")) {
+
+    // Data
+    float data[16];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetScaleMatrix(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_SCA");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 16 ; i++) {
+      packer.PackFloat(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get slice frequency
+  else if (!strcmp(command, "GET_SLF")) {
+
+    // Data
+    double data;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetSliceFrequency(&data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_SLF");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    float frequency = (float) data;
+    packer.PackFloat(frequency);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get total display dimensions
+  else if (!strcmp(command, "GET_TDD")) {
+
+    // Data
+    int w = 0;
+    int h = 0;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetTotalDisplayDimensions(&w, &h);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_TDD");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackInt(w);
+    packer.PackInt(h);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+    
+  }
+
+
+  // get total display dimensions
+  else if (!strcmp(command, "GET_TDF")) {
+
+    // Data
+    float data[6];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetTotalDisplayFrustum(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_TDF");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackFloat(data[0]);
+    packer.PackFloat(data[1]);
+    packer.PackFloat(data[2]);
+    packer.PackFloat(data[3]);
+    packer.PackFloat(data[4]);
+    packer.PackFloat(data[5]);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+    
+  }
+
+
+  // get translation matrix
+  else if (!strcmp(command, "GET_TRA")) {
+
+    // Data
+    float data[16];
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetTranslationMatrix(data);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_TRA");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    for (int i = 0 ; i < 16 ; i++) {
+      packer.PackFloat(data[i]);
+    }
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get vertical field of view
+  else if (!strcmp(command, "GET_VFV")) {
+
+    // Data
+    float vFOV = 0.0;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetVerticalFieldOfView(&vFOV);
+    }
+    
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_VFV");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(0);
+
+    // Pack data
+    packer.PackFloat(vFOV);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // get viewport
+  else if (!strcmp(command, "GET_VIE")) {
+
+    // Data
+    int x = 0;
+    int y = 0;
+    int w = 0;
+    int h = 0;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> GetViewport(destination, &x, &y, &w, &h);
+    }
+
+    // Buffer
+    memset(buffer, 0, 2048);
+
+    // Command
+    memset(command, 0, 8);
+    strcpy(command, "CMD_VIE");
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    packer.PackInt(x);
+    packer.PackInt(y);
+    packer.PackInt(w);
+    packer.PackInt(h);
+
+    // Send message
+    messageLength = 0;
+    if ((messageLength = send(_clientSocketFileDescriptor,
+                              buffer,
+                              2048,
+                              0)) != 2048) {
+      perror("UserInterfaceServer: Error sending message");
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // set axis off
+  else if (!strcmp(command, "CMD_AOF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisOff();
+    }
+
+  }
+
+
+  // set axis on
+  else if (!strcmp(command, "CMD_AON")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisOn();
+    }
+
+  }
+
+
+  // set axis on
+  else if (!strcmp(command, "CMD_APO")) {
+
+    // Unpack data from buffer
+    float x = 0.0;
+    float y = 0.0;
+    float z = 0.0;
+    unpacker.UnpackFloat(&x);
+    unpacker.UnpackFloat(&y);
+    unpacker.UnpackFloat(&z);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisPosition(x, y, z);
+    }
+
+  }
+
+
+  // set bounding box off
+  else if (!strcmp(command, "CMD_BOF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBoundingBoxOff();
+    }
+
+  }
+
+
+  // set bounding box on
+  else if (!strcmp(command, "CMD_BON")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBoundingBoxOn();
+    }
+
+  }
+
+
+  // set brick box off
+  else if (!strcmp(command, "CMD_BBF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBrickBoxOff();
+    }
+
+  }
+
+
+  // set brick box on
+  else if (!strcmp(command, "CMD_BBN")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBrickBoxOn();
+    }
+
+  }
+
+
+  // set clipping planes
+  else if (!strcmp(command, "CMD_CLI")) {
+
+    // Unpack data from buffer
+    float near = 0.0;
+    float far = 0.0;
+    unpacker.UnpackFloat(&near);
+    unpacker.UnpackFloat(&far);
+ 
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetClippingPlanes(destination, near, far);
+    }
+
+  }
+
+
+  // set command disconnect
+  else if (!strcmp(command, "CMD_DCT")) {
+
+    // If client socket is open
+    if (_clientSocketFileDescriptor != -1) {
+
+      // Shutdown socket
+      //if (shutdown(_clientSocketFileDescriptor, SHUT_RDWR) == -1) {
+      //  perror("UserInterfaceServer: Error during socket shutdown");
+      //}
+
+      // Close socket
+      if (close(_clientSocketFileDescriptor) == -1) {
+        perror("UserInterfaceServer: Error during socket close");
+      }
+
+      // Set client socket file descriptor
+      _clientSocketFileDescriptor = -1;
+
+    }
+
+    // Set connected flag
+    _isConnected = false;
+
+    // Return error
+    return USER_INTERFACE_SERVER_ERROR;
+
+  }
+
+
+  // set command exit
+  else if (!strcmp(command, "CMD_EXI")) {
+
+    // If client socket is open
+    if (_clientSocketFileDescriptor != -1) {
+
+      // Shutdown socket
+      //if (shutdown(_clientSocketFileDescriptor, SHUT_RDWR) == -1) {
+      //  perror("UserInterfaceServer: Error during socket shutdown");
+      //}
+
+      // Close socket
+      if (close(_clientSocketFileDescriptor) == -1) {
+        perror("UserInterfaceServer: Error during socket close");
+      }
+
+      // Set client socket file descriptor
+      _clientSocketFileDescriptor = -1;
+
+    }
+
+    // Set connected flag
+    _isConnected = false;
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetCommandExit();
+    }
+
+    // Return error
+    return USER_INTERFACE_SERVER_ERROR;
+
+  }
+
+
+  // set command render
+  else if (!strcmp(command, "CMD_REN")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetCommandRender();
+    }
+
+  }
+
+
+  // set data
+  else if (!strcmp(command, "CMD_DAT")) {
+
+    // Unpack data from buffer
+    char data[1024];
+    int ramSize = -1;
+    int vramSize = 1;
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+    unpacker.UnpackInt(&ramSize);
+    unpacker.UnpackInt(&vramSize);
+      
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> SetData(data, ramSize, vramSize);
+    }
+
+  }
+
+
+  // set frustum
+  else if (!strcmp(command, "CMD_FRU")) {
+
+    // Unpack data from buffer
+    float left = 0.0;
+    float right = 0.0;
+    float bottom = 0.0;
+    float top = 0.0;
+    unpacker.UnpackFloat(&left);
+    unpacker.UnpackFloat(&right);
+    unpacker.UnpackFloat(&bottom);
+    unpacker.UnpackFloat(&top);
+    
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetFrustum(destination, left, right, bottom, top);
+    }
+
+  }
+
+
+  // set map
+  else if (!strcmp(command, "CMD_MAP")) {
+
+    // Unpack data from buffer
+    unsigned char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackUnsignedChar(&data[i]);
+    }
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetMap(data);
+    }
+
+  }
+
+
+  // set 16-bit map
+  else if (!strcmp(command, "CMD_M16")) {
+
+    // Payload
+    unsigned char payload[65536*4];
+
+    // Wait for message from client
+    if ((messageLength = recv(_clientSocketFileDescriptor, 
+                              payload, 
+                              65536*4, 
+                              MSG_WAITALL)) != 65536*4) {
+      return USER_INTERFACE_SERVER_ERROR;
+    }
+
+    // Data
+    unsigned char data[65536*4];
+
+    // Data packer
+    DataPacker punpacker;
+    punpacker.SetBuffer(payload, 65536*4);
+    
+    for (int i = 0 ; i < 65536*4 ; i++) {
+      punpacker.UnpackUnsignedChar(&data[i]);
+    }
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetMap16(data);
+    }
+
+  }
+
+
+  // set prefix
+  else if (!strcmp(command, "CMD_PRE")) {
+
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+      
+    // Observer 
+    if (_observer != NULL) {
+
+      _observer -> SetPrefix(data);
+    }
+
+  }
+
+
+  // set rotation matrix
+  else if (!strcmp(command, "CMD_ROT")) {
+
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetRotationMatrix(data);
+    }
+
+  }
+
+
+  // reset view
+  else if (!strcmp(command, "CMD_RVI")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> ResetView();
+    }
+
+    // Return reply
+    return USER_INTERFACE_SERVER_REPLY;
+
+  }
+
+
+  // set scale matrix
+  else if (!strcmp(command, "CMD_SCA")) {
+
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetScaleMatrix(data);
+    }
+
+  }
+
+
+  // set slice frequency
+  else if (!strcmp(command, "CMD_SLF")) {
+
+    // Unpack data from buffer
+    float data;
+    unpacker.UnpackFloat(&data);    
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetSliceFrequency((double) data);
+    }
+
+  }
+
+
+  // set translation matrix
+  else if (!strcmp(command, "CMD_TRA")) {
+
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetTranslationMatrix(data);
+    }
+
+  }
+
+  
+  // set viewport
+  else if (!strcmp(command, "CMD_VIE")) {
+
+    // Unpack data from buffer
+    int x = 0;
+    int y = 0;
+    int w = 0;
+    int h = 0;
+    unpacker.UnpackInt(&x);
+    unpacker.UnpackInt(&y);
+    unpacker.UnpackInt(&w);
+    unpacker.UnpackInt(&h);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetViewport(destination, x, y, w, h);
+    }
+
+  }
+
+  
+  // Return OK
+  return USER_INTERFACE_SERVER_OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::Init(int port) {
+  
+  // Assign server port number
+  _port = port;
+
+  // Create server socket
+  if ((_serverSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+    perror("UserInterfaceServer: Error creating socket");
+    return;
+  }
+
+  // Set SO_REUSEADDR
+  int optVal = 1;
+  int optLen = sizeof(optVal);
+  if(setsockopt(_serverSocketFileDescriptor, 
+                SOL_SOCKET, 
+                SO_REUSEADDR, 
+                (void*) &optVal, 
+                (socklen_t) optLen) != 0) {
+    perror("UserInterfaceServer: Error setting SO_REUSEADDR");
+  }
+
+  // Set TCP_NODELAY
+  optVal = 1;
+  optLen = sizeof(optVal);
+  if(setsockopt(_serverSocketFileDescriptor,
+                IPPROTO_TCP,
+                TCP_NODELAY,
+                (void*) &optVal,
+                (socklen_t) optLen) != 0) {
+    perror("UserInterfaceServer: Error setting TCP_NODELAY");
+  }
+  
+  // Initialize server address
+  memset(&_serverAddress, 0, sizeof(_serverAddress));
+  _serverAddress.sin_family = AF_INET;
+  _serverAddress.sin_port = htons(_port);
+  
+  // Bind address
+  if (bind(_serverSocketFileDescriptor, 
+           (struct sockaddr*) &_serverAddress, 
+           sizeof(_serverAddress)) != 0) {
+    perror("UserInterfaceServer: Error binding address");
+    close(_serverSocketFileDescriptor);
+  }
+  
+  // Set listen mode
+  if (listen(_serverSocketFileDescriptor, 5) != 0) {
+    perror("UserInterfaceServer: Error setting listen mode");
+    close(_serverSocketFileDescriptor);
+  }
+  
+  // Set is initialized flag
+  _isInitialized = true;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool UserInterfaceServer::IsInit() {
+
+  // Check if connection is established
+  if (_isInitialized == true && _isConnected == true) {
+    return true;
+  }
+
+  // Connection is not established
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SendCommandExit() {
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+
+  // Destination
+  int destination = 0;
+    
+  // Message length
+  int messageLength = 0;
+
+  // Command
+  memset(command, 0, 8);
+  strcpy(command, "CMD_EXI");
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(0);
+
+  // Send message
+  if ((messageLength = send(_clientSocketFileDescriptor,
+                            buffer,
+                            2048,
+                            0)) != 2048) {
+    perror("UserInterfaceServer: Error sending message");
+  }  
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SendProgress(int value, int total) {
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+
+  // Destination
+  int destination = 0;
+    
+  // Message length
+  int messageLength = 0;
+
+  // Command
+  memset(command, 0, 8);
+  strcpy(command, "CMD_PRO");
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack value and total
+  packer.PackInt(value);
+  packer.PackInt(total);
+
+  // Send message
+  if ((messageLength = send(_clientSocketFileDescriptor,
+                            buffer,
+                            2048,
+                            0)) != 2048) {
+    perror("UserInterfaceServer: Error sending message");
+  }  
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SendRotationMatrix(float m[16]) {
+
+  // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_ROT");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_clientSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SendScaleMatrix(float m[16]) {
+
+ // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SCA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_clientSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SendTranslationMatrix(float m[16]) {
+
+ // Buffer
+  unsigned char* buffer[2048];
+  memset(buffer, 0 , 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TRA");
+
+  // Destination
+  int destination = 0;
+
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+
+  // Pack destination
+  packer.PackInt(destination);
+
+  // Pack data
+  for (int i = 0 ; i < 16 ; i++) {
+    packer.PackFloat(m[i]);
+  }
+
+  // Send command
+  int messageLength = 0;
+  if ((messageLength = send(_clientSocketFileDescriptor, 
+                            buffer, 
+                            2048, 
+                            0)) != 2048) {
+    perror("UserInterfaceClient: Error sending message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::SetObserver(UserInterfaceServerAbstractCommand* 
+                                      observer) {
+
+  // Set observer
+  _observer = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServer::Shutdown() {
+
+  // If server socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("UserInterfaceServer: Error during socket close");
+    }
+
+    // Reset file descriptor
+    _serverSocketFileDescriptor = -1;
+
+  }
+
+  // If client socket is open
+  if (_clientSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_clientSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("UserInterfaceServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_clientSocketFileDescriptor) == -1) {
+      perror("UserInterfaceServer: Error during socket close");
+    }
+
+    // Reset file descriptor
+    _clientSocketFileDescriptor = -1;
+
+  }
+
+  // Set is connected flag
+  _isConnected = false;
+
+  // Set is initialized flag
+  _isInitialized = false;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Overview.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Overview.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Overview.cpp	(revision 4)
@@ -0,0 +1,766 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Overview.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Overview::Fl_Overview(int x, int y, int w, int h, const char *l) 
+  : Fl_Gl_Window(x, y, w, h, l) {
+
+  // Initialize background color
+  _backgroundColor[0] = 0.75;
+  _backgroundColor[1] = 0.75;
+  _backgroundColor[2] = 0.75;
+  _backgroundColor[3] = 0.75;
+
+  // Initialize frustum
+  _frustum[0] = -1.0;
+  _frustum[1] = 1.0;
+  _frustum[2] = -1.0;
+  _frustum[3] = 1.0;
+  _frustum[4] = -1.0;
+  _frustum[5] = 1.0;
+
+  // Initialize line color
+  _lineColor[0] = 1.0;
+  _lineColor[1] = 1.0;
+  _lineColor[2] = 1.0;
+  _lineColor[3] = 1.0;
+
+  // Initialize mouse button state
+  _mouseButtonState[0] = FL_OVERVIEW_UP;
+  _mouseButtonState[1] = FL_OVERVIEW_UP;
+  _mouseButtonState[2] = FL_OVERVIEW_UP;
+
+  // Initialize mouse position
+  _mousePosition[0] = 0;
+  _mousePosition[1] = 0;
+
+  // Initialize rotation matrix
+  _R[0] = 1.0; _R[4] = 0.0; _R[8] = 0.0; _R[12] = 0.0;
+  _R[1] = 0.0; _R[5] = 1.0; _R[9] = 0.0; _R[13] = 0.0;
+  _R[2] = 0.0; _R[6] = 0.0; _R[10] = 1.0; _R[14] = 0.0;
+  _R[3] = 0.0; _R[7] = 0.0; _R[11] = 0.0; _R[15] = 1.0;
+  
+  // Initialize scale matrix
+  _S[0] = 1.0; _S[4] = 0.0; _S[8] = 0.0; _S[12] = 0.0;
+  _S[1] = 0.0; _S[5] = 1.0; _S[9] = 0.0; _S[13] = 0.0;
+  _S[2] = 0.0; _S[6] = 0.0; _S[10] = 1.0; _S[14] = 0.0;
+  _S[3] = 0.0; _S[7] = 0.0; _S[11] = 0.0; _S[15] = 1.0;
+  
+  // Initialize translation matrix
+  _T[0] = 1.0; _T[4] = 0.0; _T[8] = 0.0; _T[12] = 0.0;
+  _T[1] = 0.0; _T[5] = 1.0; _T[9] = 0.0; _T[13] = 0.0;
+  _T[2] = 0.0; _T[6] = 0.0; _T[10] = 1.0; _T[14] = 0.0;
+  _T[3] = 0.0; _T[7] = 0.0; _T[11] = 0.0; _T[15] = 1.0;
+
+  // Initialize callbacks
+  _updateRenderCallback = NULL;
+  _updateRotationCallback = NULL;
+  _updateScaleCallback = NULL;
+  _updateTranslationCallback = NULL;
+
+  // Initialize vertices
+  _vertex[0].SetXYZ(-0.5, -0.5, 0.5);
+  _vertex[1].SetXYZ(-0.5, -0.5, -0.5);
+  _vertex[2].SetXYZ(0.5, -0.5, -0.5);
+  _vertex[3].SetXYZ(0.5, -0.5, 0.5);
+  _vertex[4].SetXYZ(-0.5, 0.5, 0.5);
+  _vertex[5].SetXYZ(-0.5, 0.5, -0.5);
+  _vertex[6].SetXYZ(0.5, 0.5, -0.5);
+  _vertex[7].SetXYZ(0.5, 0.5, 0.5);
+
+  // Initialize world rotate factor
+  _worldRotate[0] = 0.0;
+  _worldRotate[1] = 0.0;
+  _worldRotate[2] = 0.0;
+
+  // Initialize world scale factor
+  _worldScale[0] = 1.0;
+  _worldScale[1] = 1.0;  
+  _worldScale[2] = 1.0;
+
+  // Initialize world translate factor
+  _worldTranslate[0] = 0.0;
+  _worldTranslate[1] = 0.0;
+  _worldTranslate[2] = 0.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Overview::~Fl_Overview() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::GetScaleMatrix(float m[16]) {
+
+  // Copy transltion matrix
+  for (int i = 0 ; i < 16 ; i++) {
+    m[i] = _S[i];
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::GetTranslationMatrix(float m[16]) {
+
+  // Copy transltion matrix
+  for (int i = 0 ; i < 16 ; i++) {
+    m[i] = _T[i];
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::ResetView() {
+
+  // Reset rotation
+  _worldRotate[0] = 0.0;
+  _worldRotate[1] = 0.0;
+
+  // Reset scale
+  _worldScale[0] = 1.0;
+  _worldScale[1] = 1.0;
+  _worldScale[2] = 1.0;
+
+  // Reset translation
+  _worldTranslate[0] = 0.0;
+  _worldTranslate[1] = 0.0;
+  _worldTranslate[2] = 0.0;
+
+  // Reset trackball
+  trackball.Clear();
+
+  // Calculate rotation matrix
+  float R[16];
+  float Rx[16];
+  float Ry[16];
+  float Rz[16];
+  calc_rot_x(Rx, _worldRotate[0]);
+  calc_rot_y(Ry, _worldRotate[1]);
+  calc_rot_z(Rz, _worldRotate[2]);
+  mult4x4(R, Rx, Ry);
+  mult4x4(R, R, Rz);
+
+  // Set rotation matrix
+  SetRotationMatrix(R);
+
+  // Calcuate scale matrix
+  float S[16];
+  calc_scale(S, _worldScale[0], _worldScale[1], _worldScale[2]);
+  
+  // Set scale matrix
+  SetScaleMatrix(S);
+
+  // Calculate translation matrix
+  float T[16];
+  calc_trans(T, 
+             _worldTranslate[0], 
+             _worldTranslate[1], 
+             _worldTranslate[2]);
+  
+  // Set translation matrix
+  SetTranslationMatrix(T);
+
+  // Callbacks
+  if (_updateRotationCallback != NULL) _updateRotationCallback(_R);
+  if (_updateScaleCallback != NULL) _updateScaleCallback(_S);
+  if (_updateTranslationCallback != NULL) _updateTranslationCallback(_T);
+  if (_updateRenderCallback != NULL) _updateRenderCallback();
+  if (_updateRenderCallback != NULL) _updateRenderCallback();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetBackgroundColor(float r, float g, float b, float a) {
+
+  // Set background color
+  _backgroundColor[0] = r;
+  _backgroundColor[1] = g;
+  _backgroundColor[2] = b;
+  _backgroundColor[3] = a;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetFrustum(float frustum[6]) {
+
+  // Set frustum
+  _frustum[0] = frustum[0];
+  _frustum[1] = frustum[1];
+  _frustum[2] = frustum[2];
+  _frustum[3] = frustum[3];
+  _frustum[4] = frustum[4];
+  _frustum[5] = frustum[5];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetRenderCallback(void (*cb)()) {
+
+  // Set callback
+  _updateRenderCallback = cb;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetRotationCallback(void (*cb)(float* m)) {
+
+  // Set callback
+  _updateRotationCallback = cb;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetRotationMatrix(float m[16]) {
+
+  // Set rotation matrix
+  _R[0] = m[0]; _R[4] = m[4]; _R[8] = m[8]; _R[12] = m[12];
+  _R[1] = m[1]; _R[5] = m[5]; _R[9] = m[9]; _R[13] = m[13];
+  _R[2] = m[2]; _R[6] = m[6]; _R[10] = m[10]; _R[14] = m[14];
+  _R[3] = m[3]; _R[7] = m[7]; _R[11] = m[11]; _R[15] = m[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetScaleCallback(void (*cb)(float* m)) {
+
+  // Set callback
+  _updateScaleCallback = cb;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetScaleMatrix(float m[16]) {
+
+  _worldScale[0] = m[0];
+  _worldScale[1] = m[5];
+  _worldScale[2] = m[10];
+
+  // Set scale matrix
+  _S[0] = m[0]; _S[4] = m[4]; _S[8] = m[8]; _S[12] = m[12];
+  _S[1] = m[1]; _S[5] = m[5]; _S[9] = m[9]; _S[13] = m[13];
+  _S[2] = m[2]; _S[6] = m[6]; _S[10] = m[10]; _S[14] = m[14];
+  _S[3] = m[3]; _S[7] = m[7]; _S[11] = m[11]; _S[15] = m[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetTranslationCallback(void (*cb)(float* m)) {
+
+  // Set callback
+  _updateTranslationCallback = cb;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetTranslationMatrix(float m[16]) {
+
+  _worldTranslate[0] = m[12];
+  _worldTranslate[1] = m[13];
+  _worldTranslate[2] = m[14];
+
+  // Set translation matrix
+  _T[0] = m[0]; _T[4] = m[4]; _T[8] = m[8]; _T[12] = m[12];
+  _T[1] = m[1]; _T[5] = m[5]; _T[9] = m[9]; _T[13] = m[13];
+  _T[2] = m[2]; _T[6] = m[6]; _T[10] = m[10]; _T[14] = m[14];
+  _T[3] = m[3]; _T[7] = m[7]; _T[11] = m[11]; _T[15] = m[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::SetVertices(Vertex vertex[8]) {
+
+  // Set vertex
+  _vertex[0] = vertex[0];
+  _vertex[1] = vertex[1];
+  _vertex[2] = vertex[2];
+  _vertex[3] = vertex[3];
+  _vertex[4] = vertex[4];
+  _vertex[5] = vertex[5];
+  _vertex[6] = vertex[6];
+  _vertex[7] = vertex[7];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Overview::draw() {
+
+  // Clear color
+  glClearColor(_backgroundColor[0], _backgroundColor[1],
+               _backgroundColor[2], _backgroundColor[3]);
+
+  // Clear bufffer
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Set viewport 
+  glViewport(0, 0, w(), h());
+    
+  // Set projection mode
+  glMatrixMode(GL_PROJECTION);
+
+  // Load identity
+  glLoadIdentity();
+    
+  // Set frustum
+  glOrtho(_frustum[0], _frustum[1], 
+          _frustum[2], _frustum[3],
+          _frustum[4], _frustum[5]);
+  
+  // Set modelview mode
+  glMatrixMode(GL_MODELVIEW);
+
+
+  // Overview
+
+  // Push matrix
+  glPushMatrix();
+
+  // Load identity
+  glLoadIdentity();
+
+  // Add scale if zooming out beyond original scale
+  if (_S[0] < 1.0 || _S[5] < 1.0 || _S[10] < 1.0) {
+
+    // Add translation
+    glMultMatrixf(_T);
+
+    // Add scale
+    glMultMatrixf(_S);
+
+  }
+
+  // If zooming in then divide translation by scale
+  else {
+
+    // Divide translation by scale
+    float matrix[16];
+    matrix[0] = 1.0;
+    matrix[1] = 0.0;
+    matrix[2] = 0.0;
+    matrix[3] = 0.0;
+    matrix[4] = 0.0;
+    matrix[5] = 1.0;
+    matrix[6] = 0.0;
+    matrix[7] = 0.0;
+    matrix[8] = 0.0;
+    matrix[9] = 0.0;
+    matrix[10] = 1.0;
+    matrix[11] = 0.0;    
+    matrix[12] = _T[12] / _S[0];
+    matrix[13] = _T[13] / _S[5];
+    matrix[14] = _T[14] / _S[10];
+    matrix[15] = 1.0;
+
+    // Add matrix
+    glMultMatrixf(matrix);
+
+  }
+
+  // Add rotation
+  glMultMatrixf(_R);
+  
+  // Line color
+  glColor4f(_lineColor[0], _lineColor[1], _lineColor[2], _lineColor[3]);
+
+  // Draw bottom face
+  glBegin(GL_LINE_STRIP);
+  glVertex3f(_vertex[0].GetX(), _vertex[0].GetY(), _vertex[0].GetZ());
+  glVertex3f(_vertex[1].GetX(), _vertex[1].GetY(), _vertex[1].GetZ());
+  glVertex3f(_vertex[3].GetX(), _vertex[2].GetY(), _vertex[2].GetZ());
+  glVertex3f(_vertex[2].GetX(), _vertex[3].GetY(), _vertex[3].GetZ());
+  glVertex3f(_vertex[0].GetX(), _vertex[0].GetY(), _vertex[0].GetZ());
+  glEnd();
+  
+  // Draw top face
+  glBegin(GL_LINE_STRIP);
+  glVertex3f(_vertex[4].GetX(), _vertex[4].GetY(), _vertex[4].GetZ());
+  glVertex3f(_vertex[5].GetX(), _vertex[5].GetY(), _vertex[5].GetZ());
+  glVertex3f(_vertex[7].GetX(), _vertex[6].GetY(), _vertex[6].GetZ());
+  glVertex3f(_vertex[6].GetX(), _vertex[7].GetY(), _vertex[7].GetZ());
+  glVertex3f(_vertex[4].GetX(), _vertex[4].GetY(), _vertex[4].GetZ());
+  glEnd();
+    
+  // Connect top and bottom
+  glBegin(GL_LINES);
+  glVertex3f(_vertex[0].GetX(), _vertex[0].GetY(), _vertex[0].GetZ());
+  glVertex3f(_vertex[4].GetX(), _vertex[4].GetY(), _vertex[4].GetZ());
+  glVertex3f(_vertex[1].GetX(), _vertex[1].GetY(), _vertex[1].GetZ());
+  glVertex3f(_vertex[5].GetX(), _vertex[5].GetY(), _vertex[5].GetZ());
+  glVertex3f(_vertex[2].GetX(), _vertex[2].GetY(), _vertex[2].GetZ());
+  glVertex3f(_vertex[6].GetX(), _vertex[6].GetY(), _vertex[6].GetZ());
+  glVertex3f(_vertex[3].GetX(), _vertex[3].GetY(), _vertex[3].GetZ());
+  glVertex3f(_vertex[7].GetX(), _vertex[7].GetY(), _vertex[7].GetZ());
+  glEnd();
+
+  // Pop matrix
+  glPopMatrix();
+
+
+  // Frustum bounding box
+
+  // Push matrix
+  glPushMatrix();
+
+  // Load identity
+  glLoadIdentity();
+
+  // Line color
+  glColor4f(0.0, 0.0, 0.0, 1.0);
+
+  // Add scale if zooming in past original scale
+  if (_S[0] > 1.0 || _S[5] > 1.0 || _S[10] > 1.0) {
+
+    // Draw box
+    glBegin(GL_LINE_STRIP);
+    glVertex3f(_frustum[0]/_S[0], _frustum[2]/_S[5], 0.0);
+    glVertex3f(_frustum[1]/_S[0], _frustum[2]/_S[5], 0.0);
+    glVertex3f(_frustum[1]/_S[0], _frustum[3]/_S[5], 0.0);
+    glVertex3f(_frustum[0]/_S[0], _frustum[3]/_S[5], 0.0);
+    glVertex3f(_frustum[0]/_S[0], _frustum[2]/_S[5], 0.0);
+    glEnd();
+
+  }
+
+  // Don't add scale
+  else {
+
+    // Draw box
+    glLineWidth(5.0);
+    glBegin(GL_LINE_STRIP);
+    glVertex3f(_frustum[0], _frustum[2], 0.0);
+    glVertex3f(_frustum[1], _frustum[2], 0.0);
+    glVertex3f(_frustum[1], _frustum[3], 0.0);
+    glVertex3f(_frustum[0], _frustum[3], 0.0);
+    glVertex3f(_frustum[0], _frustum[2], 0.0);
+    glEnd();
+
+  }
+
+  glLineWidth(1.0);
+
+  // Pop matrix
+  glPopMatrix();
+
+
+  // Load identity
+  glLoadIdentity();
+
+
+  // Draw bottom border
+  glLineWidth(2.0);
+  glBegin(GL_LINES);
+  glVertex3f(_frustum[0], _frustum[2], 0.0);
+  glVertex3f(_frustum[1], _frustum[2], 0.0);
+  glEnd();
+  glLineWidth(1.0);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Overview::handle(int event) {
+
+  // Check event
+  switch(event) {
+
+
+  case FL_PUSH: {
+
+    // Get button
+    int button = Fl::event_button();
+
+    // Check which button
+    if (button == 1) {
+      _mouseButtonState[0] = FL_OVERVIEW_DOWN;
+
+      // Start trackball
+      trackball.Start(((2.0 * Fl::event_x() - w()) / w()) -
+                      0.0, 
+                      ((2.0 * (h() - Fl::event_y()) - h()) / h()) -
+                      0.0);  
+    }
+    else if (button == 2) {
+      _mouseButtonState[1] = FL_OVERVIEW_DOWN;
+    }
+    else if (button == 3) {
+      _mouseButtonState[2] = FL_OVERVIEW_DOWN;
+    }
+
+    // If a button is down
+   if (_mouseButtonState[0] == FL_OVERVIEW_DOWN ||
+        _mouseButtonState[1] == FL_OVERVIEW_DOWN ||
+        _mouseButtonState[2] == FL_OVERVIEW_DOWN) {
+
+     // Callbacks
+     if (_updateRotationCallback != NULL) _updateRotationCallback(_R);
+     if (_updateScaleCallback != NULL) _updateScaleCallback(_S);
+     if (_updateTranslationCallback != NULL) _updateTranslationCallback(_T);
+     if (_updateRenderCallback != NULL) _updateRenderCallback();
+   }
+
+    // Update mouse position
+    _mousePosition[0] = Fl::event_x();
+    _mousePosition[1] = Fl::event_y();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_DRAG: {
+
+    // Calculate mouse delta factor
+    float mouseDeltaFactor[2];
+    mouseDeltaFactor[0] = (_frustum[1] - _frustum[0]) / w();
+    mouseDeltaFactor[1] = (_frustum[3] - _frustum[2]) / h();
+
+    // Calculate mouse delta
+    int mouseDelta[2];
+    mouseDelta[0] = Fl::event_x() - _mousePosition[0];
+    mouseDelta[1] = Fl::event_y() - _mousePosition[1];
+
+    // Update mouse position
+    _mousePosition[0] = Fl::event_x();
+    _mousePosition[1] = Fl::event_y();
+
+    // Rotate
+    if (_mouseButtonState[0] == FL_OVERVIEW_DOWN) {
+
+      // Calculate rotation amount
+      _worldRotate[0] += mouseDelta[1];
+      _worldRotate[1] += mouseDelta[0];
+
+      // Calculate rotation matrix
+      float R[16];
+
+      // Update trackball
+      trackball.Update(((2.0 * Fl::event_x() - w()) / w()) - 
+                       0.0, 
+                       ((2.0 * (h() - Fl::event_y()) - h()) / h()) - 
+                       0.0);
+
+      // Get rotation from trackball
+      trackball.GetRotationMatrix(R);
+
+      // Set rotation matrix
+      SetRotationMatrix(R);
+
+      // Callback
+      if (_updateRotationCallback != NULL) _updateRotationCallback(_R);
+      if (_updateRenderCallback != NULL) _updateRenderCallback();
+    }
+
+    // Scale
+    if (_mouseButtonState[1] == FL_OVERVIEW_DOWN) {
+
+      // Calculate scale amount
+      _worldScale[0] *= 1.0 - mouseDelta[1] * 0.01;
+      _worldScale[1] *= 1.0 - mouseDelta[1] * 0.01;
+      _worldScale[2] *= 1.0 - mouseDelta[1] * 0.01;
+
+      // Don't let world scale go below 1.0
+      if (_worldScale[0] < 1.0) _worldScale[0] = 1.0;
+      if (_worldScale[1] < 1.0) _worldScale[1] = 1.0;
+      if (_worldScale[2] < 1.0) _worldScale[2] = 1.0;
+
+      // Calcuate scale matrix
+      float S[16];
+      calc_scale(S, _worldScale[0], _worldScale[1], _worldScale[2]);
+
+      // Set scale matrix
+      SetScaleMatrix(S);
+
+      // Callback
+      if (_updateScaleCallback != NULL) _updateScaleCallback(_S);
+      if (_updateRenderCallback != NULL) _updateRenderCallback();
+    }
+
+    // Translate
+    if (_mouseButtonState[2] == FL_OVERVIEW_DOWN) {
+
+      // Calculate translation amount
+      _worldTranslate[0] += mouseDelta[0] * mouseDeltaFactor[0];
+      _worldTranslate[1] -= mouseDelta[1] * mouseDeltaFactor[1];
+
+      // Calculate translation matrix
+      float T[16];
+      calc_trans(T, 
+                 _worldTranslate[0], 
+                 _worldTranslate[1], 
+                 _worldTranslate[2]);
+
+      // Set translation matrix
+      SetTranslationMatrix(T);
+
+      // Callback
+      if (_updateTranslationCallback != NULL) _updateTranslationCallback(_T);
+      if (_updateRenderCallback != NULL) _updateRenderCallback();
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_RELEASE: {
+
+    // Get button
+    int button = Fl::event_button();
+    
+    // Check which button
+    if (button == 1) {
+      _mouseButtonState[0] = FL_OVERVIEW_UP;
+    }
+    else if (button == 2) {
+      _mouseButtonState[1] = FL_OVERVIEW_UP;
+    }
+    else if (button == 3) {
+      _mouseButtonState[2] = FL_OVERVIEW_UP;
+    }
+
+    // If all buttons are up
+    if (_mouseButtonState[0] == FL_OVERVIEW_UP &&
+        _mouseButtonState[1] == FL_OVERVIEW_UP &&
+        _mouseButtonState[2] == FL_OVERVIEW_UP) {
+
+      // Callback
+      if (_updateRenderCallback != NULL) _updateRenderCallback();
+    }
+
+    // Update mouse position
+    _mousePosition[0] = Fl::event_x();
+    _mousePosition[1] = Fl::event_y();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_KEYDOWN: {
+
+    // Get key
+    int key = Fl::event_key();
+
+    // Check which key
+    if (key == 'R' || key == 'r') {
+
+      // Reset rotation
+      _worldRotate[0] = 0.0;
+      _worldRotate[1] = 0.0;
+
+      // Reset scale
+      _worldScale[0] = 1.0;
+      _worldScale[1] = 1.0;
+      _worldScale[2] = 1.0;
+
+      // Reset translation
+      _worldTranslate[0] = 0.0;
+      _worldTranslate[1] = 0.0;
+      _worldTranslate[2] = 0.0;
+
+      // Calculate rotation matrix
+      float R[16];
+      float Rx[16];
+      float Ry[16];
+      float Rz[16];
+      calc_rot_x(Rx, _worldRotate[0]);
+      calc_rot_y(Ry, _worldRotate[1]);
+      calc_rot_z(Rz, _worldRotate[2]);
+      mult4x4(R, Rx, Ry);
+      mult4x4(R, R, Rz);
+
+      // Set rotation matrix
+      SetRotationMatrix(R);
+
+      // Calcuate scale matrix
+      float S[16];
+      calc_scale(S, _worldScale[0], _worldScale[1], _worldScale[2]);
+
+      // Set scale matrix
+      SetScaleMatrix(S);
+
+      // Calculate translation matrix
+      float T[16];
+      calc_trans(T, 
+                 _worldTranslate[0], 
+                 _worldTranslate[1], 
+                 _worldTranslate[2]);
+
+      // Set translation matrix
+      SetTranslationMatrix(T);
+
+      // Callbacks
+      if (_updateRotationCallback != NULL) _updateRotationCallback(_R);
+      if (_updateScaleCallback != NULL) _updateScaleCallback(_S);
+      if (_updateTranslationCallback != NULL) _updateTranslationCallback(_T);
+      if (_updateRenderCallback != NULL) _updateRenderCallback();
+      
+      // Draw scene
+      redraw();
+      
+      // Swap buffers
+      swap_buffers();
+
+      // Return
+      return 1;
+
+    }
+
+  }
+
+
+  default: {
+
+    // Pass other events to the base class
+    return Fl_Gl_Window::handle(event);
+
+  }
+
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererShell.h
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererShell.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererShell.h	(revision 4)
@@ -0,0 +1,186 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VOLUME_RENDERER_SHELL_H
+#define VOLUME_RENDERER_SHELL_H
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef SAGE
+#define GLX_GLXEXT_PROTOTYPES
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <sail.h>
+#include <misc.h>
+#endif
+
+#include <pthread.h>
+#include <SDL.h>
+
+#include "Octree.h"
+#include "VolumeRenderer.h"
+#include "VolumeRendererThreadInfo.h"
+
+/*--------------------------------------------------------------------------*/
+
+class VolumeRendererShell {
+
+public:
+
+  // Default constructor
+  VolumeRendererShell();
+
+  // Default destructor
+  ~VolumeRendererShell();
+
+  // Abort render
+  void AbortRender(bool flag);
+
+  // Destroy pbuffer
+  static void DestroyDisplay();
+
+#ifdef SAGE
+
+  // X error handler
+  static int HandleXError(Display* display, XErrorEvent *event);
+
+#endif
+
+  // Initialize
+  void Init(int width, int height, bool fullScreen, 
+            char* hostname, int port, 
+            float left, float right, 
+            float bottom, float top,
+            int rank, int numberOfNodes);
+
+  // Initialize display
+  static void InitDisplay(int width, int height, bool fullScreen, 
+                          float left, float right, 
+                          float bottom, float top);
+
+  // Is a render in progress
+  bool InRender();
+  
+  // User must call Init before any other method
+  bool IsInitialized();
+  
+  // Render
+  void Render();
+
+  // Set axis off
+  void SetAxisOff();
+
+  // Set axis on
+  void SetAxisOn();
+
+  // Set axis position
+  void SetAxisPosition(float x, float y, float z);
+
+  // Set brick box off
+  void SetBrickBoxOff();
+
+  // Set brick box on
+  void SetBrickBoxOn();
+
+  // Set bounding box off
+  void SetBoundingBoxOff();
+
+  // Set bounding box on
+  void SetBoundingBoxOn();
+
+  // Set data
+  void SetData(Octree* data);
+
+  // Set data
+  void SetData(Octree* data, int ramSize, int vramSize);
+
+  // Set exit flag
+  void SetExitFlag();
+  
+  // Set frustum
+  void SetFrustum(float left, float right, float bottom,
+                  float top, float near, float far);
+
+  // Set color and opacity map
+  void SetMap(unsigned char* map);
+
+  // Set 8bit color and opacity map
+  void SetMap8(unsigned char* map);
+
+  // Set 16bit color and opacity map
+  void SetMap16(unsigned char* map);
+
+  // Set rotation matrix
+  void SetR(float m[16]);
+  
+  // Set scale matrix
+  void SetS(float m[16]);
+
+  // Set slice frequency
+  void SetSliceFrequency(double frequency);
+  
+  // Set translation matrix
+  void SetT(float m[16]);
+  
+  // Set viewport
+  void SetViewport(int x, int y, int w, int h);
+
+  // Thread function
+  static void *ThreadFunction(void* ptr);
+
+private:
+
+  // Condition variable
+  pthread_cond_t _conditionCond;
+  
+  // Condition variable mutex
+  pthread_mutex_t _conditionMutex;
+
+  // State for thread
+  VolumeRendererThreadInfo _info;
+
+  // User must call Init before any other method
+  bool _isInitialized;
+
+  // Rendering thread
+  pthread_t _thread;
+
+#ifdef SAGE
+
+  // Declare static variable for glXPBuffer
+  static GLXPbufferSGIX _glXPBuffer;
+  
+  // Declare static variable for X display
+  static Display* _xDisplay;
+
+  // Declare static variable for X error flag
+  static int _xErrorFlag;
+
+  // Declare static variable for X visual info
+  static XVisualInfo* _xVisualInfo;
+
+#endif
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.h
===================================================================
--- trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.h	(revision 4)
@@ -0,0 +1,189 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "ControlPoint.h"
+
+#include <math.h>
+#include <FL/glut.h>
+#include <GL/gl.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector.h>
+
+/*--------------------------------------------------------------------------*/
+
+class OpacityTransferFunctionWidget {
+
+public:
+
+  // Constructor specifying window width and height
+  OpacityTransferFunctionWidget(int w, int h);
+
+  // Destructor
+  ~OpacityTransferFunctionWidget();
+
+  // Add control point based on corresponding pixel coordinate, if valid
+  bool AddControlPoint(int px, int py);
+
+  // Draw
+  void Draw();
+
+  // Get control point
+  void GetControlPoint(int index, float* scalar, float* opacity);
+
+  // Get index of control point that lies at given pixel position, or -1
+  int GetControlPointIndex(int px, int py);
+
+  // Get index of control point that lies at given function coordinates, or -1
+  int GetControlPointIndex(float scalar, float opacity);
+
+  // Get function coordinates at given pixel coordinates, if possible
+  bool GetFunctionCoordinates(int px, int py, float* scalar, float* opacity);
+
+  // Get number of control points
+  int GetNumberOfControlPoints();
+
+  // Get opacity for a given scalar value
+  float GetOpacity(float scalar);
+
+  // Get opacity range
+  void GetOpacityRange(float* min, float* max);
+
+  // Get scalar range
+  void GetScalarRange(float* min, float* max);
+  
+  // Move control point to corresponding pixel coordinate, if possible
+  bool MoveControlPoint(int index, int px, int py);
+
+  // Move control point to corresponding function coordinate, if possible
+  bool MoveControlPoint(int index, float scalar, float opacity);
+
+  // Restore control points from a list
+  void RestoreControlPoints(int number, float max, 
+                            float* scalar, float* opacity);
+
+  // Remove control point
+  bool RemoveControlPoint(int index);
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set box color
+  void SetBoxColor(float r, float g, float b, float a);
+
+  // Set control point color
+  void SetControlPointColor(float r, float g, float b, float a);
+
+  // Set control point size
+  void SetControlPointSize(int size);
+
+  // Set window dimensions
+  void SetDimensions(int w, int h);
+
+  // Set focus point color
+  void SetFocusPointColor(float r, float g, float b, float a);
+
+  // Set line color
+  void SetLineColor(float r, float g, float b, float a);
+
+  // Set maximum scalar value
+  void SetMaximumScalar(float max);
+
+  // Set text color
+  void SetTextColor(float r, float g, float b, float a);
+
+private:
+
+  // Convert box coordinates to function coordinates
+  void BoxToFunction(float bx, float by, float* scalar, float* opacity);
+  
+  // Convert box coordinates to world coordinates
+  void BoxToWorld(float bx, float by, float* wx, float* wy);
+
+  // Convert function coordinates to box coordinates
+  void FunctionToBox(float scalar, float opacity, float* bx, float* by);
+  
+  // Is box coordinate valid in world space
+  bool IsBoxInWorld(float bx, float by);
+
+  // Is function coordinate valid in box space
+  bool IsFunctionInBox(float scalar, float opacity);
+
+  // Is pixel coordinate valid in world space
+  bool IsPixelInWorld(int px, int py);
+
+  // Is world coordinate valid in box space
+  bool IsWorldInBox(float wx, float wy);
+
+  // Convert pixel coordinates to world coordinates
+  void PixelToWorld(int px, int py, float* wx, float* wy);
+
+  // Convert world coordinates to box coordinates
+  void WorldToBox(float wx, float wy, float* bx, float* by);
+
+  // Background color
+  float _backgroundColor[4];
+
+  // Box bounds in world coordinates
+  float _boxBound[4];
+
+  // Box color
+  float _boxColor[4];
+
+  // Control points
+  vector <ControlPoint> _controlPoint;
+
+  // Control point color
+  float _controlPointColor[4];
+
+  // Control point size
+  int _controlPointSize;
+
+  // Focus point index
+  int _focusPoint;
+
+  // Focus point color
+  float _focusPointColor[4];
+
+  // Frustum
+  float _frustum[6];
+
+  // Line color
+  float _lineColor[4];
+
+  // Number of control points
+  int _numberOfControlPoints;
+
+  // Opacity range
+  float _opacityMaximum;
+  float _opacityMinimum;
+  
+  // Window size
+  int _pixelDimensions[2];
+
+  // Scalar range
+  float _scalarMaximum;
+  float _scalarMinimum;
+
+  // Text color
+  float _textColor[4];
+
+};
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Load_Data.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Load_Data.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Load_Data.h	(revision 4)
@@ -0,0 +1,78 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_LOAD_DATA_H
+#define FL_LOAD_DATA_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Load_Data : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Load_Data(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Load_Data();
+
+  // Add an entry to the end
+  void Add(const char* entry);
+
+  // Clear all entries
+  void Clear();
+
+  // Gets the selected line or zero if no selection
+  int GetSelected();
+
+  // Set ok button callback
+  void SetOKButtonCallback(Fl_Callback* cb, void* v);
+
+  // Set cancel button callback
+  void SetCancelButtonCallback(Fl_Callback* cb, void* v);
+
+private:
+
+  // Connect button
+  Fl_Return_Button* _okButton;
+
+  // Exit button
+  Fl_Button* _cancelButton;
+
+  // Host input field
+  Fl_Hold_Browser* _dataBrowser;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRenderer.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRenderer.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRenderer.cpp	(revision 4)
@@ -0,0 +1,2595 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include <GL/glut.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "VolumeRenderer.h"
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRenderer::VolumeRenderer() {
+
+  // Message
+  Assert("Constructor begin.");
+
+  // Initialize observers
+  m_abortRenderObserver = NULL;
+  m_swapBuffersObserver = NULL;
+
+  // Initialize axis flag
+  m_axisFlag = false;
+
+  // Initialize axis position
+  m_axisPosition[0] = 0.0;
+  m_axisPosition[1] = 0.0;
+  m_axisPosition[2] = 0.0;
+
+  // Initialize bounding box flag
+  m_boundingBoxFlag = false;
+
+  // Initialize brick box flag
+  m_brickBoxFlag = false;
+
+  // Initialize RAM cache
+  m_cacheRAM = NULL;
+  m_cacheRAM = new CacheRAM(50);
+
+  // Initialize VRAM cache
+  m_cacheVRAM = NULL;
+  m_cacheVRAM = new CacheVRAM(10);
+
+  // Initialize data
+  m_data = NULL;
+  
+  // Initialize depth list
+  m_depthList = NULL;
+
+  // Initialize frustum
+  m_frustum[0] = 0.0;
+  m_frustum[1] = 0.0;
+  m_frustum[2] = 0.0;
+  m_frustum[3] = 0.0;
+  m_frustum[4] = 0.0;
+  m_frustum[5] = 0.0;
+  
+  // Initialize initialized flag
+  m_isInitialized = false;
+  
+  // Initialize map loaded flag
+  m_isMapLoaded = false;
+
+  // Initialize map
+  m_map = NULL;
+
+  // Initialize map dimensions
+  m_mapDimensions[0] = 0;
+  m_mapDimensions[1] = 1;
+  
+  // Initialize map texture
+  m_mapTexture = 0;
+
+  // Initialize number of nodes on render list
+  m_numberOfNodesOnRenderList = 0;
+
+  // Initialize original map
+  m_originalMap = m_map;
+
+  // Initialize original slice frequency
+  m_originalSliceFrequency = 1.0;
+
+  // Initialize queue for rendering
+  m_queue = NULL;
+
+  // Initialize traversal queue
+  m_queueTraversal = NULL;
+
+  // Initialize visible node queue
+  m_queueVisible = NULL;
+  
+  // Initialize render list
+  m_renderList = NULL;
+
+  // Initialize rotation matrix
+  m_R[0] = 1.0; m_R[4] = 0.0; m_R[8] = 0.0; m_R[12] = 0.0;
+  m_R[1] = 0.0; m_R[5] = 1.0; m_R[9] = 0.0; m_R[13] = 0.0;
+  m_R[2] = 0.0; m_R[6] = 0.0; m_R[10] = 1.0; m_R[14] = 0.0;
+  m_R[3] = 0.0; m_R[7] = 0.0; m_R[11] = 0.0; m_R[15] = 1.0;
+  
+  // Initialize scale matrix
+  m_S[0] = 1.0; m_S[4] = 0.0; m_S[8] = 0.0; m_S[12] = 0.0;
+  m_S[1] = 0.0; m_S[5] = 1.0; m_S[9] = 0.0; m_S[13] = 0.0;
+  m_S[2] = 0.0; m_S[6] = 0.0; m_S[10] = 1.0; m_S[14] = 0.0;
+  m_S[3] = 0.0; m_S[7] = 0.0; m_S[11] = 0.0; m_S[15] = 1.0;
+
+  // Initialize slice frequency
+  m_sliceFrequency = m_originalSliceFrequency;
+  
+  // Initialize translation matrix
+  m_T[0] = 1.0; m_T[4] = 0.0; m_T[8] = 0.0; m_T[12] = 0.0;
+  m_T[1] = 0.0; m_T[5] = 1.0; m_T[9] = 0.0; m_T[13] = 0.0;
+  m_T[2] = 0.0; m_T[6] = 0.0; m_T[10] = 1.0; m_T[14] = 0.0;
+  m_T[3] = 0.0; m_T[7] = 0.0; m_T[11] = 0.0; m_T[15] = 1.0;
+  
+  // Initialize viewport
+  m_viewport[0] = 0;
+  m_viewport[1] = 0;
+  m_viewport[2] = 0;
+  m_viewport[3] = 0;
+  
+  // Message
+  Assert("Constructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRenderer::~VolumeRenderer() {
+
+  // Message
+  Assert("Destructor begin.");
+
+  // Delete queue
+  if (m_queue != NULL) {
+    delete m_queue;
+  }
+
+  // Delete old traversal queue
+  if (m_queueTraversal != NULL) {
+    delete m_queueTraversal;
+  }
+
+  // Delete old visible node queue
+  if (m_queueVisible != NULL) {
+    delete m_queueVisible;
+  }
+
+  // Delete old render list
+  if (m_renderList != NULL) {
+    delete m_renderList;
+  }
+
+  // Delete old depth list
+  if (m_depthList != NULL) {
+    delete m_depthList;
+  }
+
+ // Delete cache
+  if (m_cacheRAM != NULL) {
+    delete m_cacheRAM;
+  }
+
+ // Delete cache
+  if (m_cacheVRAM != NULL) {
+    delete m_cacheVRAM;
+  }
+
+  // Delete data
+  if (m_data != NULL) {
+    delete m_data;
+  }
+
+  // Delete map
+  if (m_map != NULL) {
+    delete [] m_map;
+  }
+
+  // Delete original color and opacity map
+  if (m_originalMap != NULL) {
+    delete [] m_originalMap;
+  }
+
+  // Uninitialize Cg
+  if (m_isInitialized == true) {
+    UnInitCg();
+  }
+
+  // Message
+  Assert("Destructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Print message to log
+  char buffer[1024];
+  sprintf(buffer, "VolumeRenderer: %s", message);
+  Log::Assert(buffer);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::BuildVisibleNodeQueue() {
+
+  // Message
+  Assert("Build visible node queue begin.");
+
+  // Current node
+  OctreeNode* current = NULL;
+
+  // Child node
+  OctreeNode* child = NULL;
+
+  // ModelView matrix
+  float mv[16];
+
+  // Projection matrix
+  float p[16];
+
+  // A node's relation to current view
+  int result = 0;
+
+  // Node vertices
+  float x0, y0, z0;
+  float x1, y1, z1;
+  float x2, y2, z2;
+  float x3, y3, z3;
+  float x4, y4, z4;
+  float x5, y5, z5;
+  float x6, y6, z6;
+  float x7, y7, z7;
+
+
+  // Get MV and P from OpenGL
+  glLoadIdentity();
+  glPushMatrix();
+  glMultMatrixf(m_T);
+  glMultMatrixf(m_S);
+  glMultMatrixf(m_R);
+  glGetFloatv(GL_MODELVIEW_MATRIX, mv);
+  glGetFloatv(GL_PROJECTION_MATRIX, p);
+  glPopMatrix();
+  glLoadIdentity();
+
+  // Setup frustum planes calculator
+  m_frustumPlanes.SetModelViewMatrix(mv);
+  m_frustumPlanes.SetProjectionMatrix(p);
+  m_frustumPlanes.CalculateFrustumPlanes();
+
+
+  // Clear traversal queue
+  m_queueTraversal -> Clear();
+
+  // Clear queue of visible nodes
+  m_queueVisible -> Clear();
+
+
+  // Check if there is an octree
+  if (m_data == NULL) {
+
+    // No octree so return
+    return;
+
+  }
+
+  // Get root node
+  current = m_data -> GetRoot();
+
+
+  // Check if there is a root node
+  if (current == NULL) {
+
+    // No root node so return
+    return;
+
+  }
+
+  // Get root node's vertices
+  current -> GetVertex(0, &x0, &y0, &z0);
+  current -> GetVertex(1, &x1, &y1, &z1);
+  current -> GetVertex(2, &x2, &y2, &z2);
+  current -> GetVertex(3, &x3, &y3, &z3);
+  current -> GetVertex(4, &x4, &y4, &z4);
+  current -> GetVertex(5, &x5, &y5, &z5);
+  current -> GetVertex(6, &x6, &y6, &z6);
+  current -> GetVertex(7, &x7, &y7, &z7);
+
+  // Determine root node's relation to current view
+  result = m_frustumPlanes.CalculateRelationToFrustum(x0, y0, z0,
+                                                      x1, y1, z1,
+                                                      x2, y2, z2,
+                                                      x3, y3, z3,
+                                                      x4, y4, z4,
+                                                      x5, y5, z5,
+                                                      x6, y6, z6,
+                                                      x7, y7, z7);
+
+  // Check if root node is in current view
+  if (result == INSIDE_FRUSTUM || result == INTERSECT_FRUSTUM) {
+
+    // Insert root node in traversal queue
+    m_queueTraversal -> Insert(current);
+
+  }
+
+
+  // Traverse octree
+  while (m_queueTraversal -> IsEmpty() == false) {
+    
+    // Remove node from traversal queue
+    current = m_queueTraversal -> Remove();
+
+    // Insert node in visible node queue
+    m_queueVisible -> Insert(current);
+
+    // Get each of the current node's children
+    for (int i = 0 ; i < 8 ; i++) {
+
+      // Get child i
+      child = current -> GetChild(i);
+
+      // Check if child exists
+      if (child != NULL) {
+
+        // Get child node's vertices
+        child -> GetVertex(0, &x0, &y0, &z0);
+        child -> GetVertex(1, &x1, &y1, &z1);
+        child -> GetVertex(2, &x2, &y2, &z2);
+        child -> GetVertex(3, &x3, &y3, &z3);
+        child -> GetVertex(4, &x4, &y4, &z4);
+        child -> GetVertex(5, &x5, &y5, &z5);
+        child -> GetVertex(6, &x6, &y6, &z6);
+        child -> GetVertex(7, &x7, &y7, &z7);
+
+        // Determine child node's relation to current view
+        result = m_frustumPlanes.CalculateRelationToFrustum(x0, y0, z0,
+                                                            x1, y1, z1,
+                                                            x2, y2, z2,
+                                                            x3, y3, z3,
+                                                            x4, y4, z4,
+                                                            x5, y5, z5,
+                                                            x6, y6, z6,
+                                                            x7, y7, z7);
+
+        // Check if root node is in current view
+        if (result == INSIDE_FRUSTUM || result == INTERSECT_FRUSTUM) {
+
+          // Insert child in traversal queue
+          m_queueTraversal -> Insert(child);
+
+        }
+
+      }
+
+    }
+
+  }
+
+  // Message
+  Assert("Build visible node queue end.");
+
+  // Message
+  //Assert("Printing visible node queue begin.");
+
+  // Print visible node queue
+  //_queueVisible -> Print();
+
+  // Message
+  //Assert("Printing visible node queue end.");
+
+  // Return
+  return;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::DisableCg() {
+
+  // Disable profile
+  cgGLDisableProfile(m_cgFProfile);
+
+  // Disable parameters
+  cgGLDisableTextureParameter(m_cgFMapTexture);
+  cgGLDisableTextureParameter(m_cgFDataTexture);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::DisableTextureGL() {
+
+  // Disable blending
+  glDisable(GL_BLEND);
+
+  // Disable alpha test
+  glDisable(GL_ALPHA_TEST);
+
+  // Disable 3D textures
+  glDisable(GL_TEXTURE_3D);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::EnableCg() {
+
+  // Bind program
+  cgGLBindProgram(m_cgFProgram);
+
+  // Enable profile
+  cgGLEnableProfile(m_cgFProfile);
+
+  // Set parameters
+  cgGLSetTextureParameter(m_cgFMapTexture, m_mapTexture);
+  cgGLSetTextureParameter(m_cgFDataTexture, 0);
+  
+  // Enable parameters
+  cgGLEnableTextureParameter(m_cgFMapTexture);
+  cgGLEnableTextureParameter(m_cgFDataTexture);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::EnableTextureGL() {
+
+  // Disable lighting
+  glDisable(GL_LIGHTING);
+
+  // Disable culling
+  glDisable(GL_CULL_FACE);
+
+  // Set polygon modes
+  glPolygonMode(GL_FRONT, GL_FILL);
+  glPolygonMode(GL_BACK, GL_FILL);
+
+  // Enable 3D textures
+  glEnable(GL_TEXTURE_3D);
+
+  // Enable alpha test
+  glEnable(GL_ALPHA_TEST);
+
+  // Enable blending
+  glEnable(GL_BLEND);
+
+  // Set blend function
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+Octree* VolumeRenderer::GetData() {
+
+  // Return data
+  return m_data;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetFrustum(float* left, float* right, float* bottom,
+                                float* top, float* near, float* far) {
+
+  // Get frustum
+  *left = m_frustum[0];
+  *right = m_frustum[1];
+  *bottom = m_frustum[2];
+  *top = m_frustum[3];
+  *near = m_frustum[4];
+  *far = m_frustum[5];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetFrustum(float frustum[6]) {
+
+  // Get frustum
+  frustum[0] = m_frustum[0];
+  frustum[1] = m_frustum[1];
+  frustum[2] = m_frustum[2];
+  frustum[3] = m_frustum[3];
+  frustum[4] = m_frustum[4];
+  frustum[5] = m_frustum[5];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+unsigned char* VolumeRenderer::GetMap() {
+
+  // Return map
+  return m_map;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetR(double m[16]) {
+
+  // Get rotation matrix
+  m[0] = m_R[0];  m[4] = m_R[4];  m[8] = m_R[8];    m[12] = m_R[12];
+  m[1] = m_R[1];  m[5] = m_R[5];  m[9] = m_R[9];    m[13] = m_R[13];
+  m[2] = m_R[2];  m[6] = m_R[6];  m[10] = m_R[10];  m[14] = m_R[14];
+  m[3] = m_R[3];  m[7] = m_R[7];  m[11] = m_R[11];  m[15] = m_R[15];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetS(double m[16]) {
+
+  // Get scale matrix
+  m[0] = m_S[0];  m[4] = m_S[4];  m[8] = m_S[8];    m[12] = m_S[12];
+  m[1] = m_S[1];  m[5] = m_S[5];  m[9] = m_S[9];    m[13] = m_S[13];
+  m[2] = m_S[2];  m[6] = m_S[6];  m[10] = m_S[10];  m[14] = m_S[14];
+  m[3] = m_S[3];  m[7] = m_S[7];  m[11] = m_S[11];  m[15] = m_S[15];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+double VolumeRenderer::GetSliceFrequency() {
+
+  // Return slice frequency
+  return m_sliceFrequency;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetT(double m[16]) {
+
+  // Get translation matrix
+  m[0] = m_T[0];  m[4] = m_T[4];  m[8] = m_T[8];    m[12] = m_T[12];
+  m[1] = m_T[1];  m[5] = m_T[5];  m[9] = m_T[9];    m[13] = m_T[13];
+  m[2] = m_T[2];  m[6] = m_T[6];  m[10] = m_T[10];  m[14] = m_T[14];
+  m[3] = m_T[3];  m[7] = m_T[7];  m[11] = m_T[11];  m[15] = m_T[15];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetViewport(int* x, int* y, int* w, int* h) {
+
+  // Get viewport
+  *x = m_viewport[0];
+  *y = m_viewport[1];
+  *w = m_viewport[2];
+  *h = m_viewport[3];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::GetViewport(int viewport[4]) {
+
+  // Get viewport
+  viewport[0] = m_viewport[0];
+  viewport[1] = m_viewport[1];
+  viewport[2] = m_viewport[2];
+  viewport[3] = m_viewport[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRenderer::Init() {
+  
+  // Initialize Cg
+  return InitCg();
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+bool VolumeRenderer::InitCg() {
+
+  // Required profile is not supported
+  if (!cgGLIsProfileSupported(CG_PROFILE_ARBFP1)) {
+
+    // Return false
+    return false;
+
+  }
+
+  // Set profile
+  m_cgFProfile = CG_PROFILE_ARBFP1;
+
+  // Create Cg context
+  m_cgContext = cgCreateContext();
+
+  // Create program
+  m_cgFProgram = cgCreateProgramFromFile(m_cgContext,
+                                         CG_SOURCE,
+                                         "Fragment.cg",
+                                         m_cgFProfile,
+                                         "Fragment",
+                                         0);
+
+  // Load program
+  cgGLLoadProgram(m_cgFProgram);
+
+  // Get parameters
+  m_cgFMapTexture = cgGetNamedParameter(m_cgFProgram, "MapTexture");
+  m_cgFDataTexture = cgGetNamedParameter(m_cgFProgram, "DataTexture");
+
+  // Set initialized flag
+  m_isInitialized = true;
+
+  // Return true
+  return true;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int VolumeRenderer::Intersect(double p0[3], double p1[3],       
+                              double t0[3], double t1[3],
+                              double v0[3], double v1[3],
+                              double sp[3], double sn[3],
+                              double pnew[3], double tnew[3], double vnew[3]) {
+  
+  float t = 
+    ((sn[0] * (sp[0] - p0[0]) + 
+      sn[1] * (sp[1] - p0[1]) + 
+      sn[2] * (sp[2] - p0[2])) / 
+     (sn[0] * (p1[0] - p0[0]) + 
+      sn[1] * (p1[1] - p0[1]) + 
+      sn[2] * (p1[2] - p0[2])));
+ 
+  // Intersection
+  if ((t >= 0) && (t <= 1))  {
+
+    // Compute line intersection
+    pnew[0] = p0[0] + t * (p1[0] - p0[0]); 
+    pnew[1] = p0[1] + t * (p1[1] - p0[1]); 
+    pnew[2] = p0[2] + t * (p1[2] - p0[2]);
+
+    // Compute texture interseciton
+    tnew[0] = t0[0] + t * (t1[0] - t0[0]); 
+    tnew[1] = t0[1] + t * (t1[1] - t0[1]); 
+    tnew[2] = t0[2] + t * (t1[2] - t0[2]);
+
+    // Compute view coordinate intersections
+    vnew[0] = v0[0] + t * (v1[0] - v0[0]); 
+    vnew[1] = v0[1] + t * (v1[1] - v0[1]); 
+    vnew[2] = v0[2] + t * (v1[2] - v0[2]);
+
+    // Return intersection
+    return 1;
+
+  }
+
+  // No intersection
+  return 0;
+
+} 
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRenderer::IsInitialized() {
+
+  // Check if object is initialized
+  if (m_isInitialized == false) {
+    fprintf(stderr, "VolumeRenderer: Call Init before any other method.\n");
+  }
+  
+  return m_isInitialized;
+  
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::LoadMapTexture(int w, int h) {
+
+  // Enable 2D textures
+  glEnable(GL_TEXTURE_2D);
+
+  // Generate texture
+  glGenTextures(1, &m_mapTexture);
+
+  // Bind texture
+  glBindTexture(GL_TEXTURE_2D, m_mapTexture);
+
+  // Set texture parameters
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+  // Load texture data
+  glTexImage2D(GL_TEXTURE_2D, 
+               0, 
+               GL_RGBA8, 
+               w,
+               h,
+               0,
+               GL_RGBA,
+               GL_UNSIGNED_BYTE, 
+               m_map);
+
+  // Disable 2D textures
+  glDisable(GL_TEXTURE_2D);
+
+  // Set flag
+  m_isMapLoaded = true;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+bool VolumeRenderer::Render() {
+
+  // Message
+  char message[4096];
+  sprintf(message, "Render begin.");
+  Assert(message);
+
+  // Message
+  sprintf(message,
+          "  T: %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+          m_T[0], m_T[4], m_T[8], m_T[12], m_T[1], m_T[5], m_T[9], m_T[13],
+          m_T[2], m_T[6], m_T[10], m_T[14], m_T[3], m_T[7], m_T[11], m_T[15]);
+  Assert(message);
+
+  // Message
+  sprintf(message,
+          "  R: %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+          m_R[0], m_R[4], m_R[8], m_R[12], m_R[1], m_R[5], m_R[9], m_R[13],
+          m_R[2], m_R[6], m_R[10], m_R[14], m_R[3], m_R[7], m_R[11], m_R[15]);
+  Assert(message);
+
+  // Message
+  sprintf(message,
+          "  S: %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
+          m_S[0], m_S[4], m_S[8], m_S[12], m_S[1], m_S[5], m_S[9], m_S[13],
+          m_S[2], m_S[6], m_S[10], m_S[14], m_S[3], m_S[7], m_S[11], m_S[15]);
+  Assert(message);
+
+  // Number of times swap buffer callback is executed
+  int called = 0;
+
+  // ModelView matrix
+  float mv[16];
+
+  // Octree node
+  OctreeNode* node = NULL;
+
+  // Previous level rendered
+  int preLevel = 0;
+
+  // Transformed node center used for sorting
+  float transformedCenter[3];
+
+  // Untransformed node center used for sorting
+  float untransformedCenter[3];
+
+  // Node vertices used for sorting
+  Vertex v0, v1, v2, v3, v4;
+
+  // Level 0 vertices used for bounding box
+  Vertex ov0, ov1, ov2, ov3, ov4, ov5, ov6, ov7;
+
+
+  // Check if user called Init
+  IsInitialized();
+
+
+  // Check that render list exists
+  if (m_renderList == NULL) {
+
+    // Message
+    sprintf(message, "Render end. No render list.");
+    Assert(message);
+
+    // Return
+    return false;
+
+  }
+
+  // Check that depth list exists
+  if (m_depthList == NULL) {
+
+    // Message
+    sprintf(message, "Render end. No depth list.");
+    Assert(message);
+
+    // Return
+    return false;
+
+  }
+
+
+  // Build queue of visible nodes for current view
+  BuildVisibleNodeQueue();
+
+
+  // Clear number of nodes on render list
+  m_numberOfNodesOnRenderList = 0;
+
+
+  // Set viewport and frustum
+  SetViewportAndFrustum();
+
+
+  // Get MV from OpenGL
+  glLoadIdentity();
+  glPushMatrix();
+  glMultMatrixf(m_T);
+  glMultMatrixf(m_S);
+  glMultMatrixf(m_R);
+  glGetFloatv(GL_MODELVIEW_MATRIX, mv);
+  glPopMatrix();
+  glLoadIdentity();
+
+
+  // Clear the back buffer
+  glClear(GL_COLOR_BUFFER_BIT);
+
+
+  // Render axis
+  if (m_axisFlag == true) {
+    RenderAxis();
+  }
+
+
+  // Render all levels except the last
+
+  // Render each node
+  while (m_queueVisible -> IsEmpty() == false) {
+    
+    // Get next node from queue
+    node = m_queueVisible -> Remove();
+
+    // Save vertices for bounding box
+    if (node -> GetLevel() == 0) {
+      node -> GetVertex(0, &ov0);
+      node -> GetVertex(1, &ov1);
+      node -> GetVertex(2, &ov2);
+      node -> GetVertex(3, &ov3);
+      node -> GetVertex(4, &ov4);
+      node -> GetVertex(5, &ov5);
+      node -> GetVertex(6, &ov6);
+      node -> GetVertex(7, &ov7);
+    }
+
+    // Check if the node just removed from queue is from a different level
+    // or if the end of the queue has been reached
+    if (node -> GetLevel() != preLevel) {
+
+      // Delete old map
+      if (m_map != NULL) {
+        delete [] m_map;
+      }
+
+      // Allocate memory for a new map
+      m_map = new unsigned char[m_mapDimensions[0] * m_mapDimensions[1] * 4];
+
+      // Scale alpha values according to the slice frequency
+      //ScaleAlpha(m_originalSliceFrequency * (preLevel+1), 
+      //           m_originalSliceFrequency, m_map, 
+      //           m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+      ScaleAlpha(m_originalSliceFrequency, 
+                 m_originalSliceFrequency, m_map, 
+                 m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+//ScaleAlpha(m_originalSliceFrequency*(m_data->GetNumberOfLevels()-preLevel+1),
+//             m_originalSliceFrequency,
+//             m_map, 
+//             m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+
+      // Load map texture
+      LoadMapTexture(m_mapDimensions[0], m_mapDimensions[1]);
+
+      // Message
+      sprintf(message, "Render level %d begin.", preLevel);
+      Assert(message);
+
+      // Calculate depth of each node on render list
+      for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+
+        // Get node vertices
+        m_renderList[i] -> GetVertex(0, &v0);
+        m_renderList[i] -> GetVertex(1, &v1);
+        m_renderList[i] -> GetVertex(2, &v2);
+        m_renderList[i] -> GetVertex(3, &v3);
+        m_renderList[i] -> GetVertex(4, &v4);
+
+        // Calculate center of each brick
+        //untransformedCenter[0] = ((v3.GetX() - v0.GetX()) / 2.0) + v0.GetX();
+        //untransformedCenter[1] = ((v4.GetY() - v0.GetY()) / 2.0) + v0.GetY();
+        //untransformedCenter[2] = ((v1.GetZ() - v0.GetZ()) / 2.0) + v0.GetZ();
+        untransformedCenter[0] = ((v1.GetX() - v0.GetX()) / 2.0) + v0.GetX();
+        untransformedCenter[1] = ((v4.GetY() - v0.GetY()) / 2.0) + v0.GetY();
+        untransformedCenter[2] = ((v2.GetZ() - v0.GetZ()) / 2.0) + v0.GetZ();
+
+        // Calculate transformed center based on MV
+        transformedCenter[0] = 
+          mv[0] * untransformedCenter[0] +
+          mv[4] * untransformedCenter[1] + 
+          mv[8] * untransformedCenter[2] +
+          mv[12];
+        transformedCenter[1] = 
+          mv[1] * untransformedCenter[0] +
+          mv[5] * untransformedCenter[1] + 
+          mv[9] * untransformedCenter[2] +
+          mv[13];
+        transformedCenter[2] = 
+          mv[2] * untransformedCenter[0] +
+          mv[6] * untransformedCenter[1] + 
+          mv[10] * untransformedCenter[2];
+
+        // Only use depth
+        m_depthList[i] = transformedCenter[2];
+
+      }
+
+      // Sort back-to-front
+      for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+        for (int j = i+1 ; j < m_numberOfNodesOnRenderList ; j++) {
+          if (m_depthList[i] > m_depthList[j]) {
+            float tmpDepth = m_depthList[i];
+            OctreeNode* tmpNode = m_renderList[i];
+            m_depthList[i] = m_depthList[j];
+            m_renderList[i] = m_renderList[j];
+            m_depthList[j] = tmpDepth;
+            m_renderList[j] = tmpNode;
+          }
+        }
+      }
+
+      // Message
+      //Assert("Printing render list begin.");
+
+      // Print render list
+      //for (int i = 0 ; i < _numberOfNodesOnRenderList ; i++) {
+      //  _renderList[i] -> Print();
+      //}
+
+      // Message
+      //Assert("Printing render list end.");
+
+      // Render nodes on render list
+      for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+
+        // Render node i
+        RenderNode(m_renderList[i]);
+
+        // Only allow a render to be aborted if it's not level 0
+        if (m_renderList[i] -> GetLevel() > 0) {
+        
+          // Check for an abort render observer
+          if (m_abortRenderObserver != NULL) {
+            
+            // Check if the render has been aborted
+            if (m_abortRenderObserver -> Execute(0) == true) {
+              
+              // Execute swap buffers as many times as there are levels
+              for (int i = called ; i < m_data -> GetNumberOfLevels() ; i++) {
+                
+                // Check is swap buffers observer exists
+                if (m_swapBuffersObserver != NULL) {
+                  
+                  // Execute swap buffers observer
+                  m_swapBuffersObserver -> Execute(-1);
+                  
+                }
+                
+                // Clear back buffer
+                glClear(GL_COLOR_BUFFER_BIT);
+
+                // Render axis
+                if (m_axisFlag == true) {
+                  RenderAxis();
+                }
+                
+                // Increment number of times swap buffers observer was executed
+                called++;
+              }
+
+              // Message
+              sprintf(message, "Render end. Level %d aborted.", preLevel);
+              Assert(message);
+              
+              // Return false
+              return false;
+            }
+            
+          }
+
+        }
+        
+      }
+
+      // Render bounding box
+      if (m_boundingBoxFlag == true) {
+        RenderBoundingBox(ov0, ov1, ov2, ov3, ov4, ov5, ov6, ov7);
+      }
+
+      // Execute progress observer
+      if (m_progressObserver != NULL) {
+
+        // Execute progress observer
+        m_progressObserver -> Execute(preLevel);
+
+      }
+      
+      // Execute swap buffers observer
+      if (m_swapBuffersObserver != NULL) {
+
+        // Execute swap buffers observer
+        m_swapBuffersObserver -> Execute(0);
+
+        // Increment number of times swap buffers observer has been executed
+        called++;
+
+      }
+
+      // Clear number of nodes on render list
+      m_numberOfNodesOnRenderList = 0;
+
+      // Clear the back buffer
+      glClear(GL_COLOR_BUFFER_BIT);
+
+      // Render axis
+      if (m_axisFlag == true) {
+        RenderAxis();
+      }
+
+      // Message
+      sprintf(message, "Render level %d end.", preLevel);
+      Assert(message);
+
+    }
+
+    // Add node to render list
+    m_renderList[m_numberOfNodesOnRenderList] = node;
+
+    // Increment number of nodes on render list
+    m_numberOfNodesOnRenderList++;
+
+    // Set the previous level
+    preLevel = node -> GetLevel();
+
+  }
+
+
+  // Render the last level: this code is very redundant
+
+  // Message
+  sprintf(message, "Render level %d begin.", preLevel);
+  Assert(message);
+
+  // Delete old map
+  if (m_map != NULL) {
+    delete [] m_map;
+  }
+
+  // Allocate memory for a new map
+  m_map = new unsigned char[m_mapDimensions[0] * m_mapDimensions[1] * 4];
+
+  // Scale alpha values according to the slice frequency
+  //ScaleAlpha(m_originalSliceFrequency * (preLevel+1), 
+  //           m_originalSliceFrequency, m_map, 
+  //           m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+  ScaleAlpha(m_originalSliceFrequency, 
+             m_originalSliceFrequency, m_map, 
+            m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+  //ScaleAlpha(m_originalSliceFrequency*(m_data->GetNumberOfLevels()-preLevel+1),
+  //           m_originalSliceFrequency,
+  //           m_map, 
+  //           m_originalMap, m_mapDimensions[0], m_mapDimensions[1]);
+
+  // Load map texture
+  LoadMapTexture(m_mapDimensions[0], m_mapDimensions[1]);
+
+  // Calculate depth of each node on render list
+  for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+
+    // Get node vertices
+    m_renderList[i] -> GetVertex(0, &v0);
+    m_renderList[i] -> GetVertex(1, &v1);
+    m_renderList[i] -> GetVertex(2, &v2);
+    m_renderList[i] -> GetVertex(3, &v3);
+    m_renderList[i] -> GetVertex(4, &v4);
+
+    // Calculate center of each brick
+    //untransformedCenter[0] = ((v3.GetX() - v0.GetX()) / 2.0) + v0.GetX();
+    //untransformedCenter[1] = ((v4.GetY() - v0.GetY()) / 2.0) + v0.GetY();
+    //untransformedCenter[2] = ((v1.GetZ() - v0.GetZ()) / 2.0) + v0.GetZ();
+    untransformedCenter[0] = ((v1.GetX() - v0.GetX()) / 2.0) + v0.GetX();
+    untransformedCenter[1] = ((v4.GetY() - v0.GetY()) / 2.0) + v0.GetY();
+    untransformedCenter[2] = ((v2.GetZ() - v0.GetZ()) / 2.0) + v0.GetZ();
+
+    // Calculate transformed center based on MV
+    transformedCenter[0] = 
+      mv[0] * untransformedCenter[0] +
+      mv[4] * untransformedCenter[1] + 
+      mv[8] * untransformedCenter[2] +
+      mv[12];
+    transformedCenter[1] = 
+      mv[1] * untransformedCenter[0] +
+      mv[5] * untransformedCenter[1] + 
+      mv[9] * untransformedCenter[2] +
+      mv[13];
+    transformedCenter[2] = 
+      mv[2] * untransformedCenter[0] +
+      mv[6] * untransformedCenter[1] + 
+      mv[10] * untransformedCenter[2];
+    
+    // Only use depth
+    m_depthList[i] = transformedCenter[2];
+    
+  }
+
+  // Sort back-to-front
+  for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+    for (int j = i+1 ; j < m_numberOfNodesOnRenderList ; j++) {
+      if (m_depthList[i] > m_depthList[j]) {
+        float tmpDepth = m_depthList[i];
+        OctreeNode* tmpNode = m_renderList[i];
+        m_depthList[i] = m_depthList[j];
+        m_renderList[i] = m_renderList[j];
+        m_depthList[j] = tmpDepth;
+        m_renderList[j] = tmpNode;
+      }
+    }
+  }
+
+  // Message
+  //Assert("Printing render list begin.");
+
+  // Print render list
+  //for (int i = 0 ; i < _numberOfNodesOnRenderList ; i++) {
+  //  _renderList[i] -> Print();
+  //}
+
+  // Message
+  //Assert("Printing render list end.");
+
+  // Render nodes on render list
+  for (int i = 0 ; i < m_numberOfNodesOnRenderList ; i++) {
+
+    // Render node i
+    RenderNode(m_renderList[i]);
+
+    // Only allow a render to be aborted if it's not level 0
+    if (m_renderList[i] -> GetLevel() > 0) {
+
+      // Check for an abort render observer
+      if (m_abortRenderObserver != NULL) {
+        
+        // Check if the render has been aborted
+        if (m_abortRenderObserver -> Execute(0) == true) {
+          
+          // Execute swap buffers as many times as there are levels
+          for (int i = called ; i < m_data -> GetNumberOfLevels() ; i++) {
+            
+            // Check is swap buffers observer exists
+            if (m_swapBuffersObserver != NULL) {
+
+              // Execute swap buffers observer
+              m_swapBuffersObserver -> Execute(-1);
+              
+            }
+            
+            // Clear back buffer
+            glClear(GL_COLOR_BUFFER_BIT);
+
+            // Render axis
+            if (m_axisFlag == true) {
+              RenderAxis();
+            }
+
+            // Increment number of times swap buffers observer was executed
+            called++;
+          }
+
+          // Message
+          sprintf(message, "Render end. Level %d aborted.", preLevel);
+          Assert(message);
+
+          // Return false
+          return false;
+        }
+        
+      }
+      
+    }
+
+  }
+
+  // Render bounding box
+  if (m_boundingBoxFlag == true) {
+    RenderBoundingBox(ov0, ov1, ov2, ov3, ov4, ov5, ov6, ov7);
+  }
+  
+  // Execute progress observer
+  if (m_progressObserver != NULL) {
+    
+    // Execute progress observer
+    m_progressObserver -> Execute(preLevel);
+    
+  }
+  
+  // Execute swap buffers observer
+  if (m_swapBuffersObserver != NULL) {
+    
+    // Execute swap buffers observer
+    m_swapBuffersObserver -> Execute(0);
+    
+    // Increment number of times swap buffers observer has been executed
+    called++;
+    
+  }
+
+  // Message
+  sprintf(message, "Render level %d end.", preLevel);
+  Assert(message);
+
+
+  // Swap buffers to make number of calls to swap equal to number of levels
+  for (int i = called ; i < m_data -> GetNumberOfLevels() ; i++) {
+
+    // Execute swap buffers observer
+    if (m_swapBuffersObserver != NULL) {
+      m_swapBuffersObserver -> Execute(-1);
+    }
+
+    // Clear back buffer
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    // Render axis
+    if (m_axisFlag == true) {
+      RenderAxis();
+    }
+
+    // Increment number of times swap buffers observer is executed
+    called++;
+
+  }
+
+  // Message
+  sprintf(message, "Render end. Completed.");
+  Assert(message);
+
+
+  // Return true
+  return true;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::RenderAxis() {
+
+  // Perform transforms
+  glPushMatrix();
+  glLoadIdentity();
+  glTranslatef(m_axisPosition[0], m_axisPosition[1], m_axisPosition[2]);
+  glMultMatrixf(m_R);
+
+  // Set line width
+  glLineWidth(4.0);
+
+  // Draw as GL_LINES
+  glBegin(GL_LINES);
+
+  // X-axis
+  glColor4d(1.0, 1.0, 0.0, 1.0);
+  glVertex3d(0.0, 0.0, 0.0);
+  glVertex3d(0.5, 0.0, 0.0);
+
+  // Y-axis
+  glColor4d(0.0, 0.0, 1.0, 1.0);
+  glVertex3d(0.0, 0.0, 0.0);
+  glVertex3d(0.0, 0.5, 0.0);
+
+  // Z-axis
+  glColor4d(1.0, 0.0, 0.0, 1.0);
+  glVertex3d(0.0, 0.0, 0.0);
+  glVertex3d(0.0, 0.0, 0.5);
+  
+  // Done
+  glEnd();
+
+  // Reset line width
+  glLineWidth(1.0);
+
+  // Pop transforms
+  glPopMatrix();
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::RenderBoundingBox(OctreeNode* node) {
+
+  // Bounding box vertices
+  double volumeBoundingBoxVertex[8][3];
+
+  // Get volume bouding box vertices
+  Vertex v;
+  node -> GetVertex(0, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[0]);
+  node -> GetVertex(1, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[1]);
+  node -> GetVertex(2, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[2]);
+  node -> GetVertex(3, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[3]);
+  node -> GetVertex(4, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[4]);
+  node -> GetVertex(5, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[5]);
+  node -> GetVertex(6, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[6]);
+  node -> GetVertex(7, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[7]);
+
+  // Set color
+  glColor4d(1.0, 1.0, 1.0, 1.0);
+
+  // Draw as GL_LINES
+  glBegin(GL_LINES);
+
+  // Bottom
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+
+  // Top
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+
+  // Connect bottom and top
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+
+  // Done
+  glEnd();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::RenderBoundingBox(Vertex v0, Vertex v1, Vertex v2, 
+                                       Vertex v3, Vertex v4, Vertex v5, 
+                                       Vertex v6, Vertex v7) {
+
+  // Bounding box vertices
+  double volumeBoundingBoxVertex[8][3];
+
+  // Get volume bouding box vertices
+  v0.GetXYZ(volumeBoundingBoxVertex[0]);
+  v1.GetXYZ(volumeBoundingBoxVertex[1]);
+  v2.GetXYZ(volumeBoundingBoxVertex[2]);
+  v3.GetXYZ(volumeBoundingBoxVertex[3]);
+  v4.GetXYZ(volumeBoundingBoxVertex[4]);
+  v5.GetXYZ(volumeBoundingBoxVertex[5]);
+  v6.GetXYZ(volumeBoundingBoxVertex[6]);
+  v7.GetXYZ(volumeBoundingBoxVertex[7]);
+
+  // Set color
+  glColor4d(1.0, 1.0, 1.0, 1.0);
+
+  // Perform transforms
+  glPushMatrix();
+  glLoadIdentity();
+  glMultMatrixf(m_T);
+  glMultMatrixf(m_S);
+  glMultMatrixf(m_R);
+
+  // Draw as GL_LINES
+  glBegin(GL_LINES);
+
+  // Bottom
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+
+  // Top
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+
+  // Connect bottom and top
+  glVertex3dv(volumeBoundingBoxVertex[0]);
+  glVertex3dv(volumeBoundingBoxVertex[4]);
+  glVertex3dv(volumeBoundingBoxVertex[1]);
+  glVertex3dv(volumeBoundingBoxVertex[5]);
+  glVertex3dv(volumeBoundingBoxVertex[2]);
+  glVertex3dv(volumeBoundingBoxVertex[6]);
+  glVertex3dv(volumeBoundingBoxVertex[3]);
+  glVertex3dv(volumeBoundingBoxVertex[7]);
+
+  // Done
+  glEnd();
+
+  // Pop transforms
+  glPopMatrix();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::RenderNode(OctreeNode* node) {
+
+  // This method follows Algorthm 39-2. View-Aligned Slicing for Volume
+  // Rendering found in Chapter 39 "Volume Rendering Techniques" by 
+  // Milan Ikits, Joe Kniss, Aaron Lefohn, and Charles Hansen of GPU Gems.
+  // Simian, http://www.cs.utah.edu/~jmk/simian/, and Vol-a-Tile are
+  // referenced for implementation details.
+  //                          
+  //       6 +---------+ 7                                       
+  //        /|        /|                      
+  //       / |       / |
+  //      /  |      /  |
+  //   4 +---------+ 5 |
+  //     |   |     |   |      y axis
+  //     | 2 +-----+---+ 3    ^   
+  //     |  /      |  /       |   
+  //     | /       | /        | 
+  //     |/        |/         |
+  //   0 +---------+ 1        +-------> x axis 
+  //                         /
+  //                        /z axis
+
+  // Message
+  char message[1024];
+  sprintf(message, "Render node %d begin.", node -> GetID());
+  Assert(message);
+
+  // Node vertices
+  float x0, y0, z0;
+  float x1, y1, z1;
+  float x2, y2, z2;
+  float x3, y3, z3;
+  float x4, y4, z4;
+  float x5, y5, z5;
+  float x6, y6, z6;
+  float x7, y7, z7;
+
+  // Get vertices
+  node -> GetVertex(0, &x0, &y0, &z0);
+  node -> GetVertex(1, &x1, &y1, &z1);
+  node -> GetVertex(2, &x2, &y2, &z2);
+  node -> GetVertex(3, &x3, &y3, &z3);
+  node -> GetVertex(4, &x4, &y4, &z4);
+  node -> GetVertex(5, &x5, &y5, &z5);
+  node -> GetVertex(6, &x6, &y6, &z6);
+  node -> GetVertex(7, &x7, &y7, &z7);
+
+  // Determine scale factor
+  float sx = x3 - x0;
+  float sy = y4 - y0;
+  float sz = -(z0 - z1);
+
+  // Determine translation factor
+  float tx = (((x3 - x0) / 2) + x0);
+  float ty = (((y4 - y0) / 2) + y0);
+  float tz = (((z0 - z1) / 2) + z1);
+
+  // Enable GL for textures
+  EnableTextureGL();
+
+  // Enable Cg
+  EnableCg();
+
+  // Print CacheRAM
+  //_cacheRAM -> Print();
+          
+  // Make the node current in RAM cache
+  m_cacheRAM -> MakeCurrent(node);
+
+  // Print CacheRAM
+  //_cacheRAM -> Print();
+
+  // Print CacheVRAM
+  //_cacheVRAM -> Print();
+
+  // Make the node current in VRAM cache
+  m_cacheVRAM -> MakeCurrent(node);
+
+  // Print CacheVRAM
+  //_cacheVRAM -> Print();
+
+  // Bind texture
+  glBindTexture(GL_TEXTURE_3D, node -> GetTexture());
+
+  // Set viewport and frustum
+  SetViewportAndFrustum();
+
+
+  // Perform transforms
+  glPushMatrix();
+  glLoadIdentity();
+  glMultMatrixf(m_T);
+  glMultMatrixf(m_S);
+  glMultMatrixf(m_R);
+
+
+  // 1. Transform the volume bounding box vertices into view coordinates
+  // using the model-view matrix.
+
+  // Volume bounding box vertices
+  double volumeBoundingBoxVertex[8][3];
+
+  // Volume view vertices
+  double volumeViewVertex[8][3];
+
+  // Get volume bouding box vertices
+  Vertex v;
+  /*
+  node -> GetVertex(0, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[2]);
+  node -> GetVertex(1, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[0]);
+  node -> GetVertex(2, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[1]);
+  node -> GetVertex(3, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[3]);
+  node -> GetVertex(4, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[6]);
+  node -> GetVertex(5, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[4]);
+  node -> GetVertex(6, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[5]);
+  node -> GetVertex(7, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[7]);
+  */
+  /*
+  node -> GetVertex(0, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[0]);
+  node -> GetVertex(1, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[2]);
+  node -> GetVertex(2, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[3]);
+  node -> GetVertex(3, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[1]);
+  node -> GetVertex(4, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[4]);
+  node -> GetVertex(5, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[6]);
+  node -> GetVertex(6, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[7]);
+  node -> GetVertex(7, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[5]);
+  */
+  node -> GetVertex(0, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[0]);
+  node -> GetVertex(1, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[1]);
+  node -> GetVertex(2, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[2]);
+  node -> GetVertex(3, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[3]);
+  node -> GetVertex(4, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[4]);
+  node -> GetVertex(5, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[5]);
+  node -> GetVertex(6, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[6]);
+  node -> GetVertex(7, &v);
+  v.GetXYZ(volumeBoundingBoxVertex[7]);
+
+  // Get model-view matrix
+  double mv[16];
+  glGetDoublev(GL_MODELVIEW_MATRIX, mv);
+
+  // Get inverse model-view matrix
+  double mvinv[16];
+  inverse4x4(mvinv, mv);
+
+  // Transform bounding box vertices into view coordinates using the
+  // model-view matrix
+  for (int i = 0 ; i < 8 ; i++) {
+    translate3V(volumeViewVertex[i], mv, volumeBoundingBoxVertex[i]);
+  }
+
+
+
+  // 2. Find the minimum and maximum z coordinates of the transformed vertices.
+  // Compute the number of sampling planes used between these two values using
+  // equidistant spacing from the view origin. The sampling distance is 
+  // computed from the voxel size and current sampling rate.
+
+  // Minimum and maximum z coordinates of transformed vertices
+  double minZViewCoordinateValue = 10000.0;
+  double maxZViewCoordinateValue = -10000.0;
+  int minZViewCoordinateVertex = -1;
+  int maxZViewCoordinateVertex = -1;
+
+  // Find the minimum and maximum z coordinates of transformed vertices
+  for (int i = 0 ; i < 8 ; i++) {
+
+    // Find minimum
+    if (minZViewCoordinateValue > minimum(minZViewCoordinateValue,
+                                          volumeViewVertex[i][2])) {
+      minZViewCoordinateValue = minimum(minZViewCoordinateValue, 
+                                        volumeViewVertex[i][2]);
+      minZViewCoordinateVertex = i;
+    }
+ 
+    // Find maximum
+    if (maxZViewCoordinateValue < maximum(maxZViewCoordinateValue,
+                                          volumeViewVertex[i][2])) {
+      maxZViewCoordinateValue = maximum(maxZViewCoordinateValue, 
+                                        volumeViewVertex[i][2]);
+      maxZViewCoordinateVertex = i;
+    }
+
+  }
+
+  // View plane normal
+  double viewPlaneNormal[3] = {0.0, 0.0, 1.0};
+
+  // Normalize view plane normal
+  normalize3V(viewPlaneNormal);
+
+  // Slice plane point - vertex farthest from the eye
+  // Location where slice planes will start
+  double slicePlanePoint[3] = 
+    {volumeBoundingBoxVertex[minZViewCoordinateVertex][0],
+     volumeBoundingBoxVertex[minZViewCoordinateVertex][1],
+     volumeBoundingBoxVertex[minZViewCoordinateVertex][2]};
+
+  // Slice plane normal - normalized VPN in model space
+  double slicePlaneNormal[3];
+  translate3V(slicePlaneNormal, mvinv, viewPlaneNormal);
+  normalize3V(slicePlaneNormal);
+
+  // Translate minimum and maximum z coordinates back to model space
+  double minModelCoordinate[3];
+  double maxModelCoordinate[3];
+  double tmpMin[3] = {0.0, 0.0, minZViewCoordinateValue};
+  double tmpMax[3] = {0.0, 0.0, maxZViewCoordinateValue};
+  translate3V(minModelCoordinate, mvinv, tmpMin);
+  translate3V(maxModelCoordinate, mvinv, tmpMax);
+
+  // Determine distnace between min and max model space coordinates
+  double minMaxDistance[3];
+  sub3V(minMaxDistance, maxModelCoordinate, minModelCoordinate);
+
+  // Slice distance - distance to slice across
+  double sliceDistance = (double) sqrt(minMaxDistance[0] * minMaxDistance[0] +
+                                       minMaxDistance[1] * minMaxDistance[1] +
+                                       minMaxDistance[2] * minMaxDistance[2]);
+
+  // Slice spacing - distance between slices
+  double sliceSpacing = 
+    sliceDistance / ((double) (node -> GetW()) * m_sliceFrequency);
+
+  // Number of slices, i.e. sample planes
+  int numberOfSlices = (int) (sliceDistance / sliceSpacing);
+
+
+
+  // 3. For each plane in front-to-back or back-to-front order:
+  for (int slice = 0 ; slice < numberOfSlices ; slice++) {
+
+    // a. Test for intersections with the edges of the bounding box. Add each
+    // intersection point to a temporary vertex list. Up to six intersections 
+    // are generated, so the maximum size of the list is fixed.
+
+    // Texture coordinates
+    double textureCoordinates[8][3] = {{0.0, 0.0, 1.0},
+                                       {1.0, 0.0, 1.0},
+                                       {0.0, 0.0, 0.0},
+                                       {1.0, 0.0, 0.0},
+                                       {0.0, 1.0, 1.0},
+                                       {1.0, 1.0, 1.0},
+                                       {0.0, 1.0, 0.0},
+                                       {1.0, 1.0, 0.0}};
+
+    /*
+    // Texture coordinates
+    double textureCoordinates[8][3] = {{0.0, 0.0, 0.0},
+                                       {1.0, 0.0, 0.0},
+                                       {0.0, 0.0, 1.0},
+                                       {1.0, 0.0, 1.0},
+                                       {0.0, 1.0, 0.0},
+                                       {1.0, 1.0, 0.0},
+                                       {0.0, 1.0, 1.0},
+                                       {1.0, 1.0, 1.0}};
+    */
+
+    // Temporary vertex lists
+    double tmpUVert[6][3];  // untransformed edge intersections
+    double tmpUText[6][3];  // untransformed texture intersections
+    double tmpTVert[6][3];  // transformed edge intersections
+    int numberOfEdges = 0;  // number of edges
+
+    // Distance to increment the slice plane point by
+    double d[3] = {slicePlaneNormal[0] * sliceSpacing,
+                   slicePlaneNormal[1] * sliceSpacing,
+                   slicePlaneNormal[2] * sliceSpacing};
+
+    // Increment the slice plane point
+    slicePlanePoint[0] += d[0];
+    slicePlanePoint[1] += d[1];
+    slicePlanePoint[2] += d[2];
+
+    // Test for intersections with bounding box
+
+    // Front bottom edge 0 1
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[0], 
+                               volumeBoundingBoxVertex[1],
+                               textureCoordinates[0], 
+                               textureCoordinates[1],
+                               volumeViewVertex[0], 
+                               volumeViewVertex[1],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Front left edge 0 2
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[0], 
+                               volumeBoundingBoxVertex[2],
+                               textureCoordinates[0], 
+                               textureCoordinates[2],
+                               volumeViewVertex[0], 
+                               volumeViewVertex[2],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+ 
+    // Front right edge 1 3
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[1], 
+                               volumeBoundingBoxVertex[3],
+                               textureCoordinates[1], 
+                               textureCoordinates[3],
+                               volumeViewVertex[1], 
+                               volumeViewVertex[3],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Left bottom edge 4 0
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[4], 
+                               volumeBoundingBoxVertex[0],
+                               textureCoordinates[4], 
+                               textureCoordinates[0],
+                               volumeViewVertex[4], 
+                               volumeViewVertex[0],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Right bottom edge 1 5
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[1], 
+                               volumeBoundingBoxVertex[5],
+                               textureCoordinates[1], 
+                               textureCoordinates[5],
+                               volumeViewVertex[1], 
+                               volumeViewVertex[5],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Front top edge 2 3
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[2], 
+                               volumeBoundingBoxVertex[3],
+                               textureCoordinates[2], 
+                               textureCoordinates[3],
+                               volumeViewVertex[2], 
+                               volumeViewVertex[3],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Back bottom edge 4 5
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[4], 
+                               volumeBoundingBoxVertex[5],
+                               textureCoordinates[4], 
+                               textureCoordinates[5],
+                               volumeViewVertex[4], 
+                               volumeViewVertex[5],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Back left edge 4 6
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[4], 
+                               volumeBoundingBoxVertex[6],
+                               textureCoordinates[4], 
+                               textureCoordinates[6],
+                               volumeViewVertex[4], 
+                               volumeViewVertex[6],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Back right edge 5 7
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[5], 
+                               volumeBoundingBoxVertex[7],
+                               textureCoordinates[5], 
+                               textureCoordinates[7],
+                               volumeViewVertex[5],
+                               volumeViewVertex[7],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Back top edge 6 7
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[6], 
+                               volumeBoundingBoxVertex[7],
+                               textureCoordinates[6], 
+                               textureCoordinates[7],
+                               volumeViewVertex[6], 
+                               volumeViewVertex[7],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Left top edge 2 6
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[2],
+                               volumeBoundingBoxVertex[6],
+                               textureCoordinates[2], 
+                               textureCoordinates[6],
+                               volumeViewVertex[2], 
+                               volumeViewVertex[6],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+    // Right top edge 3 7
+    numberOfEdges += Intersect(volumeBoundingBoxVertex[3], 
+                               volumeBoundingBoxVertex[7],
+                               textureCoordinates[3], 
+                               textureCoordinates[7],
+                               volumeViewVertex[3], 
+                               volumeViewVertex[7],
+                               slicePlanePoint, 
+                               slicePlaneNormal,
+                               tmpUVert[numberOfEdges], 
+                               tmpUText[numberOfEdges], 
+                               tmpTVert[numberOfEdges]);
+
+
+    // b. Compute the center of the proxy polygon by averaging the intersection
+    // points. Sort the polygon vertices clockwise or counterclockwise by
+    // projecting them onto the x-y plane and computing their angle around the
+    // center, with the first vertex or the x axis as the reference. Note that 
+    // to avoid trigonometric computations, the tangent of the angle and the 
+    // sign of the coordinates, combined into a single scalar value called the
+    // pseudo-angle, can be used for sorting the vertices (Moret and 
+    // Shapiro 1991).
+
+    // Note: This is right out of Simian.
+
+    int i, j, k;
+    float dx, dy, tt, theta, cen[2];
+    cen[0] = cen[1] = 0.0;
+    int next;
+    int order[6] = {0, 1, 2, 3, 4, 5};
+
+    for (j = 0 ; j < numberOfEdges ; j++) {
+      cen[0] += tmpTVert[j][0];
+      cen[1] += tmpTVert[j][1];
+    }
+    cen[0] /= numberOfEdges;
+    cen[1] /= numberOfEdges;
+
+    for (j = 0 ; j < numberOfEdges ; j++) {
+    
+      theta = -10;
+      next = j;
+      for (k = j ; k < numberOfEdges ; k++) {
+
+        dx = tmpTVert[order[k]][0] - cen[0];
+        dy = tmpTVert[order[k]][1] - cen[1];
+        if ((dx == 0) && (dy == 0)) {
+          next = k;
+          break;
+        }
+
+        tt = dy / (fabs(dx) + fabs(dy));
+        if (dx < 0.0) tt = (float) (2.0 - tt);
+        else if (dy < 0.0) tt = (float) (4.0 + tt);
+        if (theta <= tt) {
+          next = k;
+          theta = tt;
+        }
+
+      }
+
+      int tmp = order[j];
+      order[j] = order[next];
+      order[next] = tmp;
+
+    }
+
+
+    // c. Tessellate the proxy polygon into triangles and add the resulting
+    // vertices to the output vertex array. The slice polygon can be 
+    // tessellated into a triangle strip or triangle fan using the center. 
+    // Depending on the rendering algorithm, the vertices may need to be 
+    // transformed back to object space during this step.
+
+    // Note: Tessellation into triangles is not implemented. Each slice is
+    // rendered as a GL_POLYGON.
+
+
+    // Render a slice
+    RenderSlice(numberOfEdges, tmpUText, tmpUVert, order);
+
+  }
+
+  // Disable GL for textures
+  DisableTextureGL();
+
+  // Disable Cg
+  DisableCg();
+
+
+  // Render brick box
+  if (m_brickBoxFlag == true) {
+    RenderBoundingBox(node);
+  }
+
+
+  // Pop all transformations
+  glPopMatrix();
+  
+  // Message
+  sprintf(message, "Render node %d end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::RenderSlice(int numberOfEdges, double t[6][3], 
+                                 double v[6][3], int order[6]) {
+
+  // Render a slice as a polygon
+  glBegin(GL_POLYGON);
+  for (int i = 0 ; i < numberOfEdges ; i++) {
+    glTexCoord3dv(t[order[i]]);
+    glVertex3dv(v[order[i]]);
+  }
+  glEnd();
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::ScaleAlpha(double newSliceFrequency, 
+                                double originalSliceFrequency,
+                                unsigned char* newTexture, 
+                                unsigned char* originalTexture,
+                                int width, int height) {
+
+  // Go through each entry
+  for (int i = 0 ; i < height ; i++) {
+    for (int j = 0 ; j < width ; j++) {
+
+      // Copy color components
+      newTexture[(i * width * 4) + (j * 4) + 0] = 
+        originalTexture[(i * width * 4) + (j * 4) + 0];
+      newTexture[(i * width * 4) + (j * 4) + 1] = 
+        originalTexture[(i * width * 4) + (j * 4) + 1];
+      newTexture[(i * width * 4) + (j * 4) + 2] = 
+        originalTexture[(i * width * 4) + (j * 4) + 2];
+
+      /*
+      double originalR =
+        (double) originalTexture[(i * width * 4) + (j * 4) + 0] / 255.0;
+      double originalG =
+        (double) originalTexture[(i * width * 4) + (j * 4) + 1] / 255.0;
+      double originalB =
+        (double) originalTexture[(i * width * 4) + (j * 4) + 2] / 255.0;
+      */
+
+      /*
+      double newR = (1.0 - pow(1.0 - originalR, 
+                               originalSliceFrequency / newSliceFrequency));
+      double newG = (1.0 - pow(1.0 - originalG, 
+                               originalSliceFrequency / newSliceFrequency));
+      double newB = (1.0 - pow(1.0 - originalB, 
+                               originalSliceFrequency / newSliceFrequency));
+      double newR = originalR * (originalSliceFrequency / newSliceFrequency);
+      double newG = originalG * (originalSliceFrequency / newSliceFrequency);
+      double newB = originalB * (originalSliceFrequency / newSliceFrequency);
+      newTexture[(i * width * 4) + (j * 4) + 0] = 
+        (unsigned char) (newR * 255.0);
+      newTexture[(i * width * 4) + (j * 4) + 1] = 
+        (unsigned char) (newG * 255.0);
+      newTexture[(i * width * 4) + (j * 4) + 2] = 
+        (unsigned char) (newB * 255.0);
+      */
+           
+      // Get original alpha and normalize it
+      double originalA = 
+        (double) originalTexture[(i * width * 4) + (j * 4) + 3] / 255.0;
+      
+      // Calculate new alpha
+      //double newA = originalA*newSliceFrequency;
+
+      // Calculate new alpha
+      double newA = (1.0 - pow(1.0 - originalA, 
+                               originalSliceFrequency / newSliceFrequency));
+
+      // Assign new alpha
+      newTexture[(i * width * 4) + (j * 4) + 3] = 
+        (unsigned char) (newA * 255.0);
+
+    }
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetAbortRenderObserver(VolumeRendererCommand* observer) {
+
+  // Set observer
+  m_abortRenderObserver = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetAxisOff() {
+
+  // Set flag
+  m_axisFlag = false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetAxisOn() {
+
+  // Set flag
+  m_axisFlag = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetAxisPosition(float x, float y, float z) {
+
+  // Set position
+  m_axisPosition[0] = x;
+  m_axisPosition[1] = y;
+  m_axisPosition[2] = z;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetBoundingBoxOff() {
+
+  // Set flag
+  m_boundingBoxFlag = false;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetBoundingBoxOn() {
+
+  // Set flag
+  m_boundingBoxFlag = true;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetBrickBoxOff() {
+
+  // Set flag
+  m_brickBoxFlag = false;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetBrickBoxOn() {
+
+  // Set flag
+  m_brickBoxFlag = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRenderer::SetData(Octree* data) {
+
+  // Set data with default cache sizes
+  return SetData(data, 50, 10);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRenderer::SetData(Octree* data, int ramSize, int vramSize) {
+
+  // Message
+  Assert("SetData begin.");
+
+  // Delete old RAM cache
+  if (m_cacheRAM != NULL) {
+    delete m_cacheRAM;
+  }
+
+  // Delete old VRAM cache
+  if (m_cacheVRAM != NULL) {
+    delete m_cacheVRAM;
+  }
+
+  // Delete old queue
+  if (m_queue != NULL) {
+    delete m_queue;
+  }
+
+  // Delete old traversal queue
+  if (m_queueTraversal != NULL) {
+    delete m_queueTraversal;
+  }
+
+  // Delete old visible node queue
+  if (m_queueVisible != NULL) {
+    delete m_queueVisible;
+  }
+
+  // Delete old data
+  if (m_data != NULL) {
+    delete m_data;
+  }
+
+  // Delete old render list
+  if (m_renderList != NULL) {
+    delete m_renderList;
+  }
+
+  // Delete old depth list
+  if (m_depthList != NULL) {
+    delete m_depthList;
+  }
+
+  // Set new data
+  if (data != NULL) {
+    m_data = data;
+  }
+  else {
+    return false;
+  }
+
+  // Stop current log
+  Log::Stop();
+
+  // Start new log
+  char sufix[256];
+  memset(sufix, 0, 256);
+  sprintf(sufix, 
+          "%d-%d", vramSize, ramSize);
+  Log::Start(sufix);
+
+  // Allocate new CacheRAM
+  if ((m_cacheRAM = new CacheRAM(ramSize)) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new CacheVRAM
+  if ((m_cacheVRAM = new CacheVRAM(vramSize)) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new queue
+  if ((m_queue = new OctreeNodeQueue(m_data -> GetNumberOfNodes())) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new traversal queue
+  if ((m_queueTraversal = 
+       new OctreeNodeQueue(m_data -> GetNumberOfNodes())) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new visible node queue
+  if ((m_queueVisible = 
+       new OctreeNodeQueue(m_data -> GetNumberOfNodes())) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new render list
+  if ((m_renderList = new OctreeNode*[m_data -> GetNumberOfNodes()]) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Allocate new depth list
+  if ((m_depthList = new float[m_data -> GetNumberOfNodes()]) == NULL) {
+    fprintf(stderr, "VolumeRenderer: Memory allocation error.\n");
+    return false;
+  }
+
+  // Message
+  Assert("SetData end.");
+
+  // Return true
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetFrustum(float left, float right, float bottom,
+                                float top, float near, float far) {
+
+  // Message
+  Assert("SetFrustum begin.");
+
+  // Check if user called Init
+  IsInitialized();
+
+  // Set frustum
+  m_frustum[0] = left;
+  m_frustum[1] = right;
+  m_frustum[2] = bottom;
+  m_frustum[3] = top;
+  m_frustum[4] = near;
+  m_frustum[5] = far;
+
+  // Message
+  Assert("SetFrustum end.");
+  
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetFrustum(float frustum[6]) {
+
+  // Message
+  Assert("SetFrustum begin.");
+
+  // Check if user called Init
+  IsInitialized();
+
+  // Set frustum
+  m_frustum[0] = frustum[0];
+  m_frustum[1] = frustum[1];
+  m_frustum[2] = frustum[2];
+  m_frustum[3] = frustum[3];
+  m_frustum[4] = frustum[4];
+  m_frustum[5] = frustum[5];
+
+  // Message
+  Assert("SetFrustum end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetMap(unsigned char* map) {
+
+  // Message
+  Assert("SetMap begin.");
+
+  // Check if user called Init
+  IsInitialized();
+  
+  // Set map
+  SetMapUnsigned8Int(map);
+
+  // Message
+  Assert("SetMap end.");
+  
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetMapUnsigned8Int(unsigned char* map) {
+
+  // Delete original map
+  if (m_originalMap != NULL) {
+
+    // Delete map
+    delete [] m_originalMap;
+
+  }
+
+  // Delete map
+  if (m_map != NULL) {
+
+    // Unload texture
+    UnloadMapTexture();
+
+    // Delete map
+    delete [] m_map;
+
+  }
+
+  // Set original map
+  m_originalMap = map;
+
+  // Set map dimensions
+  m_mapDimensions[0] = 256;
+  m_mapDimensions[1] = 1;
+
+  // Allocate memory for a new map
+  m_map = new unsigned char[m_mapDimensions[0] * m_mapDimensions[1] * 4];
+
+  // Scale alpha values according to the slice frequency
+  ScaleAlpha(m_sliceFrequency, m_originalSliceFrequency, m_map, m_originalMap, 
+             m_mapDimensions[0], m_mapDimensions[1]);
+
+  // Load map texture
+  LoadMapTexture(m_mapDimensions[0], m_mapDimensions[1]);
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetMapUnsigned16Int(unsigned char* map) {
+
+  // Delete original map
+  if (m_originalMap != NULL) {
+
+    // Delete map
+    delete [] m_originalMap;
+
+  }
+
+  // Delete map
+  if (m_map != NULL) {
+
+    // Unload texture
+    UnloadMapTexture();
+
+    // Delete map
+    delete [] m_map;
+
+  }
+
+  // Set original map
+  m_originalMap = map;
+
+  // Set map dimensions
+  m_mapDimensions[0] = 256;
+  m_mapDimensions[1] = 256;
+
+  // Allocate memory for a new map
+  m_map = new unsigned char[m_mapDimensions[0] * m_mapDimensions[1] * 4];
+
+  // Scale alpha values according to the slice frequency
+  ScaleAlpha(m_sliceFrequency, m_originalSliceFrequency, m_map, m_originalMap, 
+             m_mapDimensions[0], m_mapDimensions[1]);
+
+  // Load map texture
+  LoadMapTexture(m_mapDimensions[0], m_mapDimensions[1]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetProgressObserver(VolumeRendererCommand* observer){
+
+  // Set observer
+  m_progressObserver = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetR(float m[16]) {
+
+  // Message
+  Assert("SetRotationMatrix begin.");
+  
+  // Check if user called Init
+  IsInitialized();
+  
+  // Set rotation matrix
+  m_R[0] = m[0]; m_R[4] = m[4]; m_R[8] = m[8]; m_R[12] = m[12];
+  m_R[1] = m[1]; m_R[5] = m[5]; m_R[9] = m[9]; m_R[13] = m[13];
+  m_R[2] = m[2]; m_R[6] = m[6]; m_R[10] = m[10]; m_R[14] = m[14];
+  m_R[3] = m[3]; m_R[7] = m[7]; m_R[11] = m[11]; m_R[15] = m[15];
+  
+  // Message
+  Assert("SetRotationMatrix end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetS(float m[16]) {
+  
+  // Message
+  Assert("SetScaleMatrix begin.");
+
+  // Check if user called Init
+  IsInitialized();
+
+  // Set scale matrix
+  m_S[0] = m[0]; m_S[4] = m[4]; m_S[8] = m[8]; m_S[12] = m[12];
+  m_S[1] = m[1]; m_S[5] = m[5]; m_S[9] = m[9]; m_S[13] = m[13];
+  m_S[2] = m[2]; m_S[6] = m[6]; m_S[10] = m[10]; m_S[14] = m[14];
+  m_S[3] = m[3]; m_S[7] = m[7]; m_S[11] = m[11]; m_S[15] = m[15];
+
+  // Message
+  Assert("SetScaleMatrix end.");
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetSliceFrequency(double frequency) {
+
+  // Set slice frequency
+  m_sliceFrequency = frequency;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetSwapBuffersObserver(VolumeRendererCommand* observer){
+
+  // Set observer
+  m_swapBuffersObserver = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetT(float m[16]) {
+
+  // Message
+  Assert("SetTranslationMatrix begin.");
+
+  // Check if user called Init
+  IsInitialized();
+  
+  // Set translation matrix
+  m_T[0] = m[0]; m_T[4] = m[4]; m_T[8] = m[8]; m_T[12] = m[12];
+  m_T[1] = m[1]; m_T[5] = m[5]; m_T[9] = m[9]; m_T[13] = m[13];
+  m_T[2] = m[2]; m_T[6] = m[6]; m_T[10] = m[10]; m_T[14] = m[14];
+  m_T[3] = m[3]; m_T[7] = m[7]; m_T[11] = m[11]; m_T[15] = m[15];
+
+  // Message
+  Assert("SetTranslationMatrix end.");
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetViewport(int x, int y, int w, int h) {
+  
+  // Message
+  Assert("SetViewport begin.");
+
+  // Check if user called Init
+  IsInitialized();
+  
+  // Set viewport
+  m_viewport[0] = x;
+  m_viewport[1] = y;
+  m_viewport[2] = w;
+  m_viewport[3] = h;
+
+  // Message
+  Assert("SetViewport end.");
+  
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::SetViewportAndFrustum() {
+
+  // Set viewport
+  glViewport(m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
+
+  // Switch to projection mode
+  glMatrixMode(GL_PROJECTION);
+
+  // Set frustum
+  glLoadIdentity();
+  glOrtho(m_frustum[0], m_frustum[1], m_frustum[2],
+          m_frustum[3], m_frustum[4], m_frustum[5]);
+
+  // Switch to modelview mode
+  glMatrixMode(GL_MODELVIEW);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void VolumeRenderer::UnInitCg() {
+
+  // Destroy fragment programs
+  cgDestroyProgram(m_cgFProgram);
+
+  // Destroy context
+  cgDestroyContext(m_cgContext);
+
+  // Set initialized flag
+  m_isInitialized = false;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void VolumeRenderer::UnloadMapTexture() {
+
+  // Delete map texture
+  glDeleteTextures(1, &m_mapTexture);
+
+  // Set flag
+  m_isMapLoaded = false;
+
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/DataPacker.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/DataPacker.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/DataPacker.cpp	(revision 4)
@@ -0,0 +1,301 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#include "DataPacker.h"
+
+/*---------------------------------------------------------------------------*/
+
+DataPacker::DataPacker() {
+
+  // Initialize to NULL
+  _buffer = NULL;
+
+  // Initialize to -1
+  _position = -1;
+
+  // Initialize to 0
+  _size = 0;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+DataPacker::~DataPacker() {
+}
+
+/*---------------------------------------------------------------------------*/
+
+void* DataPacker::GetBuffer(int* size) {
+
+  // Set size
+  *size = _size;
+
+  // Return buffer
+  return (void*) _buffer;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::GetPosition() {
+
+  // Return position
+  return _position;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::PackChar(char value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_CHAR_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Pack value
+  _buffer[_position] = value;
+
+  // Increment position
+  _position += DATA_PACKER_CHAR_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::PackFloat(float value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_FLOAT_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Pack value
+  uint32_t tmp = htonl(*(uint32_t*) ((void*) &value));
+  memcpy(&_buffer[_position], &tmp, DATA_PACKER_FLOAT_SIZE);
+
+  // Increment position
+  _position += DATA_PACKER_FLOAT_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::PackInt(int value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_INT_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Pack value
+  uint32_t tmp = htonl(*(uint32_t*) ((void*) &value));
+  memcpy(&_buffer[_position], &tmp, DATA_PACKER_INT_SIZE);
+
+  // Increment position
+  _position += DATA_PACKER_INT_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::PackUnsignedChar(unsigned char value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_UNSIGNED_CHAR_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Pack value
+  _buffer[_position] = value;
+
+  // Increment position
+  _position += DATA_PACKER_UNSIGNED_CHAR_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void DataPacker::Reset() {
+
+  // Reset to NULL
+  _buffer = NULL;
+
+  // Reset to -1
+  _position = -1;
+
+  // Reset to 0
+  _size = 0;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void DataPacker::SetBuffer(void* buffer, int size) {
+
+  // Set buffer
+  _buffer = (unsigned char*) buffer;
+
+  // Set position
+  _position = 0;
+
+  // Set size
+  _size = size;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::SetPosition(int position) {
+
+  // Check buffer size and position
+  if (position >= _size || position < 0) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Set position
+  _position = position;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::UnpackChar(char* value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_CHAR_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Unpack value
+  *value = _buffer[_position];
+
+  // Increment position
+  _position += DATA_PACKER_UNSIGNED_CHAR_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::UnpackFloat(float* value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_FLOAT_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Unpack value
+  uint32_t tmp = ntohl(*(uint32_t*) ((void*) &_buffer[_position]));
+  memcpy(value, &tmp, DATA_PACKER_FLOAT_SIZE);
+
+  // Increment position
+  _position += DATA_PACKER_FLOAT_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::UnpackInt(int* value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_INT_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Unpack value
+  uint32_t tmp = ntohl(*(uint32_t*) ((void*) &_buffer[_position]));
+  memcpy(value, &tmp, DATA_PACKER_INT_SIZE);
+
+  // Increment position
+  _position += DATA_PACKER_INT_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+int DataPacker::UnpackUnsignedChar(unsigned char* value) {
+
+  // Check buffer size
+  if (_position + DATA_PACKER_CHAR_SIZE - 1 >= _size) {
+
+    // Return ERROR
+    return DATA_PACKER_ERROR;
+
+  }
+
+  // Unpack value
+  *value = _buffer[_position];
+
+  // Increment position
+  _position += DATA_PACKER_UNSIGNED_CHAR_SIZE;
+
+  // Return OK
+  return DATA_PACKER_OK;
+
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OctreeNodeQueue.h
===================================================================
--- trunk/src/testing/app/VRA/src/OctreeNodeQueue.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/OctreeNodeQueue.h	(revision 4)
@@ -0,0 +1,87 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef OCTREE_NODE_QUEUE_H
+#define OCTREE_NODE_QUEUE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "Log.h"
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class OctreeNodeQueue {
+
+ public:
+
+  // Default constructor
+  OctreeNodeQueue();
+
+  // Constructor to specify size of queue
+  OctreeNodeQueue(int size);
+
+  // Default destructor
+  ~OctreeNodeQueue();
+
+  // Clear queue
+  void Clear();
+
+  // Is queue empty
+  bool IsEmpty();
+
+  // Is queue full
+  bool IsFull();
+
+  // Insert at back of queue
+  bool Insert(OctreeNode* node);
+
+  // Print
+  void Print();
+
+  // Remove from front of queue
+  OctreeNode* Remove();
+
+ private:
+
+  // Print a message to stdout
+  void Assert(const char* message);
+
+  // Array
+  OctreeNode** _array;
+
+  // Back
+  int _back;
+
+  // Current size
+  int _currentSize;
+
+  // Front
+  int _front;
+
+  // Maximum size
+  int _maximumSize;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.h
===================================================================
--- trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.h	(revision 4)
@@ -0,0 +1,186 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "ControlPoint.h"
+
+#include <math.h>
+#include <FL/glut.h>
+#include <GL/gl.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector.h>
+
+/*--------------------------------------------------------------------------*/
+
+class ColorTransferFunctionWidget {
+
+public:
+
+  // Constructor specifying window width and height
+  ColorTransferFunctionWidget(int w, int h);
+
+  // Destructor
+  ~ColorTransferFunctionWidget();
+
+  // Add control point based on corresponding pixel coordinate, if valid
+  bool AddControlPoint(int px, int py);
+
+  // Draw
+  void Draw();
+
+  // Get control point
+  void GetControlPoint(int index, float* scalar, float* r, float* g, float* b);
+
+  // Get index of control point that lies at given pixel position, or -1
+  int GetControlPointIndex(int px, int py);
+
+  // Get index of control point that lies at given function coordinates, or -1
+  int GetControlPointIndex(float scalar);
+
+  // Get function coordinates at given pixel coordinates, if possible
+  bool GetFunctionCoordinates(int px, int py, float* scalar, float* r, 
+                              float* g, float* b);
+
+  // Get number of control points
+  int GetNumberOfControlPoints();
+
+  // Get color for a given scalar value
+  void GetColor(float scalar, float* r, float* g, float* b);
+
+  // Get scalar range
+  void GetScalarRange(float* min, float* max);
+  
+  // Modify a control point's color, if possible
+  bool ModifyControlPointColor(int index, float r, float g, float b);
+
+  // Move control point to corresponding pixel coordinate, if possible
+  bool MoveControlPoint(int index, int px, int py);
+
+  // Move control point to corresponding function coordinate, if possible
+  bool MoveControlPoint(int index, float scalar);
+
+  // Restore control points from a list
+  void RestoreControlPoints(int number, float max, float* scalar, 
+                            float* r, float* g, float* b);
+
+  // Remove control point
+  bool RemoveControlPoint(int index);
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set box color
+  void SetBoxColor(float r, float g, float b, float a);
+
+  // Set control point color
+  void SetControlPointColor(float r, float g, float b, float a);
+
+  // Set control point size
+  void SetControlPointSize(int size);
+
+  // Set window dimensions
+  void SetDimensions(int w, int h);
+
+  // Set focus point color
+  void SetFocusPointColor(float r, float g, float b, float a);
+
+  // Set line color
+  void SetLineColor(float r, float g, float b, float a);
+
+  // Set maximum scalar value
+  void SetMaximumScalar(float max);
+
+  // Set text color
+  void SetTextColor(float r, float g, float b, float a);
+
+private:
+
+  // Convert box coordinates to function coordinates
+  void BoxToFunction(float bx, float by, float* scalar);
+  
+  // Convert box coordinates to world coordinates
+  void BoxToWorld(float bx, float by, float* wx, float* wy);
+
+  // Convert function coordinates to box coordinates
+  void FunctionToBox(float scalar, float* bx, float* by);
+  
+  // Is box coordinate valid in world space
+  bool IsBoxInWorld(float bx, float by);
+
+  // Is function coordinate valid in box space
+  bool IsFunctionInBox(float scalar);
+
+  // Is pixel coordinate valid in world space
+  bool IsPixelInWorld(int px, int py);
+
+  // Is world coordinate valid in box space
+  bool IsWorldInBox(float wx, float wy);
+
+  // Convert pixel coordinates to world coordinates
+  void PixelToWorld(int px, int py, float* wx, float* wy);
+
+  // Convert world coordinates to box coordinates
+  void WorldToBox(float wx, float wy, float* bx, float* by);
+
+  // Background color
+  float _backgroundColor[4];
+
+  // Box bounds in world coordinates
+  float _boxBound[4];
+
+  // Box color
+  float _boxColor[4];
+
+  // Control points
+  vector <ControlPoint> _controlPoint;
+
+  // Control point color
+  float _controlPointColor[4];
+
+  // Control point size
+  int _controlPointSize;
+
+  // Focus point index
+  int _focusPoint;
+
+  // Focus point color
+  float _focusPointColor[4];
+
+  // Frustum
+  float _frustum[6];
+
+  // Line color
+  float _lineColor[4];
+
+  // Number of control points
+  int _numberOfControlPoints;
+
+  // Window size
+  int _pixelDimensions[2];
+
+  // Scalar range
+  float _scalarMaximum;
+  float _scalarMinimum;
+
+  // Text color
+  float _textColor[4];
+
+};
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererCommand.h	(revision 4)
@@ -0,0 +1,46 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VOLUME_RENDERER_COMMAND_H
+#define VOLUME_RENDERER_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+class VolumeRendererCommand {
+
+public:
+
+  // Destructor
+  virtual ~VolumeRendererCommand();
+  
+  // Execute command
+  virtual bool Execute(int value);
+
+protected:  
+
+  // Constructor
+  VolumeRendererCommand();
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClient.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClient.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClient.h	(revision 4)
@@ -0,0 +1,244 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_CLIENT_H
+#define USER_INTERFACE_CLIENT_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "DataPacker.h"
+#include "UserInterfaceClientAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define USER_INTERFACE_CLIENT_ERROR -1
+#define USER_INTERFACE_CLIENT_OK 0
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceClient {
+
+public:
+
+  // Default constructor
+  UserInterfaceClient();
+
+  // Default destructor
+  ~UserInterfaceClient();
+
+  // Disconnect from server
+  void Disconnect();
+
+  // Get axis state
+  void GetAxis();
+
+  // Get axis position
+  void GetAxisPosition();
+
+  // Get bounding box state
+  void GetBoundingBox();
+
+  // Get brick box state
+  void GetBrickBox();
+
+  // Get clipping planes
+  void GetClippingPlanes(int node);
+
+  // Get meta data filename
+  void GetData();
+
+  // Get dataset list file
+  void GetDatasetListFile(int index);
+
+  // Get dataset list name
+  void GetDatasetListName(int index);
+
+  // Get dataset list prefix
+  void GetDatasetListPrefix(int index);
+
+  // Get dataset list size
+  void GetDatasetListSize();
+
+  // Get dataset type
+  void GetDatasetType();
+
+  // Get display size
+  void GetDisplaySize(int node);
+
+  // Get frustum
+  void GetFrustum(int node);
+
+  // Get map
+  void GetMap();
+
+  // Get number of slaves
+  void GetNumberOfSlaves();
+
+  // Get overview vertices
+  void GetOverviewVertices();
+
+  // Get data prefix
+  void GetPrefix();
+
+  // Get rotation matrix
+  void GetRotationMatrix();
+
+  // Get scale matrix
+  void GetScaleMatrix();
+
+  // Get slice frequency
+  void GetSliceFrequency();
+
+  // Get total display dimensions
+  void GetTotalDisplayDimensions();
+
+  // Get total display frustum
+  void GetTotalDisplayFrustum();
+
+  // Get translation matrix
+  void GetTranslationMatrix();
+
+  // Get vertical field of view
+  void GetVerticalFieldOfView();
+
+  // Get viewport
+  void GetViewport(int node);
+
+  // Initialize connection to server
+  int Init(char* hostname, int port);
+
+  // Reset view
+  void ResetView();
+
+  // Send axis off
+  void SendAxisOff();
+
+  // Send axis on
+  void SendAxisOn();
+
+  // Send axis position
+  void SendAxisPosition(float x, float y, float z);
+
+  // Send bounding box off
+  void SendBoundingBoxOff();
+
+  // Send bounding box on
+  void SendBoundingBoxOn();
+
+  // Send brick box off
+  void SendBrickBoxOff();
+
+  // Send brick box on
+  void SendBrickBoxOn();
+
+  // Send clipping planes
+  void SendClippingPlanes(int node, float near, float far);
+
+  // Send command exit
+  void SendCommandExit();
+
+  // Send command render
+  void SendCommandRender();
+
+  // Send meta data filename
+  void SendData(char* filename);
+
+  // Send meta data filename and cache sizes
+  void SendData(char* filename, int ramSize, int vramSize);
+
+  // Send frustum
+  void SendFrustum(int node, float left, float right, 
+                   float bottom, float top);
+
+  // Send map
+  void SendMap(unsigned char* map);
+
+  // Send 16-bit map
+  void SendMap16(unsigned char* map);
+
+  // Send data prefix
+  void SendPrefix(char* prefix);
+
+  // Send rotation matrix
+  void SendRotationMatrix(float matrix[16]);
+
+  // Send scale matrix
+  void SendScaleMatrix(float matrix[16]);
+
+  // Send slice frequency
+  void SendSliceFrequency(double frequency);
+
+  // Send translation matrix
+  void SendTranslationMatrix(float matrix[16]);
+
+  // Send viewport
+  void SendViewport(int node, int x, int y, int w, int h);
+
+  // Set observer
+  void SetObserver(UserInterfaceClientAbstractCommand* observer);
+
+  // Thread to listen for updates from server
+  static void *ThreadFunction(void* ptr);
+
+private:
+
+  // Exit flag
+  bool _exitFlag;
+
+  // Server hostname
+  char _hostname[1024];
+
+  // Is initialized flag
+  bool _isInitialized;
+
+  // Observer
+  UserInterfaceClientAbstractCommand* _observer;
+
+  // Server port number
+  int _port;
+
+  // Server
+  struct hostent* _server;
+
+  // Server address
+  struct sockaddr_in _serverAddress;
+
+  // Socket file descriptor
+  int _serverSocketFileDescriptor;
+
+  // Thread listening for server updates
+  pthread_t _thread;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Trackball.h
===================================================================
--- trunk/src/testing/app/VRA/src/Trackball.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Trackball.h	(revision 4)
@@ -0,0 +1,192 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*                                                                          */
+/*                                                                          */
+/* (c) Copyright 1993, 1994, Silicon Graphics, Inc.                         */
+/* ALL RIGHTS RESERVED                                                      */
+/* Permission to use, copy, modify, and distribute this software for        */
+/* any purpose and without fee is hereby granted, provided that the above   */
+/* copyright notice appear in all copies and that both the copyright notice */
+/* and this permission notice appear in supporting documentation, and that  */
+/* the name of Silicon Graphics, Inc. not be used in advertising            */
+/* or publicity pertaining to distribution of the software without specific,*/
+/* written prior permission.                                                */
+/*                                                                          */
+/* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"        */
+/* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,         */
+/* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR         */
+/* FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON             */
+/* GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,          */
+/* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY            */
+/* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,           */
+/* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF        */
+/* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN           */
+/* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON           */
+/* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE        */
+/* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.                         */
+/*                                                                          */
+/* US Government Users Restricted Rights                                    */
+/* Use, duplication, or disclosure by the Government is subject to          */
+/* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph            */
+/* (c)(1)(ii) of the Rights in Technical Data and Computer Software         */
+/* clause at DFARS 252.227-7013 and/or in similar or successor              */
+/* clauses in the FAR or the DOD or NASA FAR Supplement.                    */
+/* Unpublished-- rights reserved under the copyright laws of the            */
+/* United States.  Contractor/manufacturer is Silicon Graphics,             */
+/* Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.            */
+/*                                                                          */
+/* OpenGL(TM) is a trademark of Silicon Graphics, Inc.                      */
+/*--------------------------------------------------------------------------*/
+
+#ifndef TRACKBALL_H
+#define TRACKBALL_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <math.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Trackball {
+
+public:
+
+  // Default constructor
+  Trackball();
+
+  // Default destructor
+  ~Trackball();
+
+  // Clear
+  void Clear();
+
+  // Get the axis and angle for the current rotation
+  void GetAxisAngle(float* angle, float axis[3]);
+
+  // Build a rotation matrix from the current quaternion rotation
+  void GetRotationMatrix(float m[16]);
+
+  // Compute a quaternion based on an axis (defined by the given vector) and 
+  // an angle about which to rotate. The angle is expressed in radians. The 
+  // result is put into the third argument.
+  void Reapply();
+
+  // Start rotation.
+  // Input is in the range (-1.0, 1.0)
+  void Start(float x, float y);
+
+  // Project the points onto the virtual trackball, then figure out the axis 
+  // of rotation, which is the cross product of P1 P2 and O P1 (O is the center
+  // of the ball, 0,0,0)
+  // Note:  This is a deformed trackball -- this is a trackball in the center,
+  // but it is deformed into a hyperbolic sheet of rotation away from the
+  // center.
+  // Input is in the range (-1.0, 1.0)
+  void Update(float x, float y);
+
+private:
+
+  // Given two rotations, e1 and e2, expressed as quaternion rotations,
+  // figure out the equivalent single rotation and stuff it into dest.
+  // This routine also normalizes the result every RENORMCOUNT times it is
+  // called, to keep error from creeping in.
+  // NOTE: This routine is written so that q1 or q2 may be the same
+  // as dest (or each other).
+  void AddQuaternions(float q1[4], float q2[4], float dest[4]);
+
+  // Create quaternion based on axis and angle
+  void AxisToQuaternion(float a[3], float phi, float q[4]);
+
+  // Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
+  // If they don't add up to 1.0, dividing by their magnitued will
+  // renormalize them.
+  //
+  // Note: See the following for more information on quaternions:
+  // - Shoemake, K., Animating rotation with quaternion curves, Computer
+  //   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+  // - Pletinckx, D., Quaternion calculus as a basic tool in computer
+  //   graphics, The Visual Computer 5, 2-13, 1989.
+  void NormalizeQuaternion(float q[4]);
+
+  // Project an x, y pair on to a sphere of radius r or a hyperbolic 
+  // sheet if we are away from the center of the sphere
+  float ProjectToSphere(float r, float x, float y);
+
+  // Add two vectors
+  void vAdd(const float* src1, const float* src2, float* dst);
+
+  // Copy two vectors
+  void vCopy(const float* v1, float* v2);
+
+  // Compute cross product of two vectors
+  void vCross(const float* v1, const float* v2, float* cross);
+
+  // Compute dot produce of two vectors
+  float vDot(const float* v1, const float* v2);
+
+  // Compute length of a vector
+  float vLength(const float *v);
+
+  // Normalize vector
+  void vNormal(float* v);
+
+  // Scale a vector
+  void vScale(float* v, float div);
+
+  // Set a vector
+  void vSet(float* v, float x, float y, float z);
+
+  // Subtract two vectors
+  void vSub(const float* src1, const float* src2, float* dst);
+
+  // Zero out a vector
+  void vZero(float* v);
+
+  // This size should really be based on the distance from the center of
+  // rotation to the point on the object underneath the mouse. That
+  // point would then track the mouse as closely as possible.
+  float _trackballSize;
+  
+  // Number of iterations before renormalizing
+  int _renormalizeCount;
+
+  // Current quaternion
+  float _currentQuaternion[4];
+
+  // Last quaternion
+  float _lastQuaternion[4];
+
+  // Last X position
+  float _lastX;
+
+  // Last Y position
+  float _lastY;
+
+  // Axis of rotation
+  float	_axis[3];
+
+  // Amount to rotate about axis of roatation
+  float	_phi;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.cpp	(revision 4)
@@ -0,0 +1,53 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "SynchronizerServerConcreteCommand.h"
+#include "Master.h"
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServerConcreteCommand::SynchronizerServerConcreteCommand() {
+
+  _master = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServerConcreteCommand::SynchronizerServerConcreteCommand(void* 
+                                                                     master) {
+
+  _master = master;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServerConcreteCommand::~SynchronizerServerConcreteCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool SynchronizerServerConcreteCommand::Execute(int value) {
+
+  ((Master*) _master) -> UpdateProgress(value);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Lambda.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Lambda.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Lambda.h	(revision 4)
@@ -0,0 +1,72 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_LAMBDA_H
+#define FL_LAMBDA_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Lambda : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Lambda(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Lambda();
+
+  // Get port
+  int GetPort();
+
+  // Set cancel button callback
+  void SetCancelButtonCallback(Fl_Callback* cb, void* v);
+
+  // Set listen button callback
+  void SetListenButtonCallback(Fl_Callback* cb, void* v);
+
+private:
+
+  // Cancel button
+  Fl_Button* _cancelButton;
+
+  // Listen button
+  Fl_Return_Button* _listenButton;
+
+  // Port input field
+  Fl_Input* _portInput;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Opacity_Transfer_Function.h	(revision 4)
@@ -0,0 +1,162 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_OPACITY_TRANSFER_FUNCTION_H
+#define FL_OPACITY_TRANSFER_FUNCTION_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <Fl/Fl_Gl_Window.H>
+#include <GL/gl.h>
+
+#include "OpacityTransferFunctionWidget.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define DOWN 1
+#define UP 0
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Opacity_Transfer_Function : public Fl_Gl_Window {
+
+public:
+
+  // Constructor
+  Fl_Opacity_Transfer_Function(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Opacity_Transfer_Function();
+
+  // Get control point
+  void GetControlPoint(int index, float* scalar, float* opacity);
+
+  // Get index of control point that lies at given pixel position, or -1
+  int GetControlPointIndex(int px, int py);
+
+  // Get index of control point that lies at given function coordinates, or -1
+  int GetControlPointIndex(float scalar, float opacity);
+
+  // Get function coordinates at given pixel coordinates, if possible
+  bool GetFunctionCoordinates(int px, int py, float* scalar, float* opacity);
+
+  // Get number of control points
+  int GetNumberOfControlPoints();
+
+  // Get index of selected control point
+  int GetSelectedControlPoint();
+
+  // Get opacity for a given scalar value
+  float GetOpacity(float scalar);
+
+  // Get opacity range
+  void GetOpacityRange(float* min, float* max);
+
+  // Get scalar range
+  void GetScalarRange(float* min, float* max);
+
+  // Move control point to corresponding pixel coordinate, if possible
+  bool MoveControlPoint(int index, int px, int py);
+
+  // Move control point to corresponding function coordinate, if possible
+  bool MoveControlPoint(int index, float scalar, float opacity);
+
+  // Remove control point
+  bool RemoveControlPoint(int index);
+
+  // Restore control points from a list
+  void RestoreControlPoints(int number, float max, 
+                            float* scalar, float* opacity);
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set box color
+  void SetBoxColor(float r, float g, float b, float a);
+
+  // Set control point color
+  void SetControlPointColor(float r, float g, float b, float a);
+
+  // Set control point size
+  void SetControlPointSize(int size);
+
+  // Set focus point color
+  void SetFocusPointColor(float r, float g, float b, float a);
+
+  // Set line color
+  void SetLineColor(float r, float g, float b, float a);
+
+  // Set maximum scalar value
+  void SetMaximumScalar(float max);
+
+  // Set move callback: called when a control point is moved
+  void SetMoveCallback(void (*cb)(void*), void* p);
+
+  // Set select callback: called when a control point is selected
+  void SetSelectCallback(void (*cb)(void*), void* p);
+
+  // Set text color
+  void SetTextColor(float r, float g, float b, float a);
+
+  // Set unselect callback: called when a control point is unselected
+  void SetUnselectCallback(void (*cb)(void*), void* p);
+
+  // Implementation of draw method
+  void draw();
+
+  // Implementation of handle method
+  int handle(int event);
+
+private:
+
+  // Move callback
+  void (*_callbackMove)(void*);
+
+  // Move pointer
+  void* _callbackMovePtr;
+
+  // Select callback
+  void (*_callbackSelect)(void*);
+
+  // Select pointer
+  void* _callbackSelectPtr;
+
+  // Unselect callback
+  void (*_callbackUnselect)(void*);
+
+  // Unselect pointer
+  void* _callbackUnselectPtr;
+
+  // Control point picked
+  int _controlPointPicked;
+
+  // Mouse button states
+  int _mouseButtonState[3];
+
+  // Opacity transferfunction widget
+  OpacityTransferFunctionWidget* _otfw;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.h
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererThreadInfo.h	(revision 4)
@@ -0,0 +1,169 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VOLUME_RENDERER_THREAD_INFO_H
+#define VOLUME_RENDERER_THREAD_INFO_H
+
+/*--------------------------------------------------------------------------*/
+
+#define VOLUME_RENDERER_THREAD_INFO_MAP_8 8
+#define VOLUME_RENDERER_THREAD_INFO_MAP_16 16
+
+/*--------------------------------------------------------------------------*/
+
+#include <pthread.h>
+
+#include "Octree.h"
+
+/*--------------------------------------------------------------------------*/
+
+class VolumeRendererThreadInfo {
+
+public:
+
+  // Default constructor
+  VolumeRendererThreadInfo();
+
+  // Default destructor
+  ~VolumeRendererThreadInfo();
+
+  // Abort render flag
+  bool _abortFlag;
+
+  // Axis on flag
+  bool _axisOnFlag;
+
+  // Axis position
+  float _axisPosition[3];
+
+  // Brick box on flag
+  bool _brickBoxOnFlag;
+
+  // Bounding box on flag
+  bool _boundingBoxOnFlag;
+
+  // Condition variable
+  pthread_cond_t* _conditionCond;
+
+  // Condition variable mutex
+  pthread_mutex_t* _conditionMutex;
+
+  // Data
+  Octree* _data;
+
+  // Display size
+  int _displaySize[2];
+
+  // Exit flag
+  bool _exitFlag;
+
+  // Frustum
+  float _frustum[6];
+
+  // Full screen flag
+  bool _fullScreenFlag;
+
+  // In render flag
+  bool _inRenderFlag;
+
+  // Color and opacity map
+  unsigned char* _map;
+
+  // Color and opacity map type
+  int _mapType;
+
+  // Normalized coordinates of rendered area
+  float _normalCoordinates[4];
+
+  // Number of nodes
+  int _numberOfNodes;
+
+  // Rotation matrix
+  float _R[16];
+
+  // CacheRAM Size
+  int _ramSize;
+
+  // Rank
+  int _rank;
+
+  // Render flag
+  bool _renderFlag;
+
+  // Scale matrix
+  float _S[16];
+
+  // Slice frequency
+  double _sliceFrequency;
+
+  // Synchronization server hostname
+  char _synchronizationHostname[128];
+
+  // Synchronization server port
+  int _synchronizationPort;
+
+  // Translation matrix
+  float _T[16];
+
+  // Viewport
+  int _viewport[4];
+
+  // Update axis flag
+  bool _updateAxis;
+
+  // Update brick box
+  bool _updateBrickBox;
+
+  // Update bounding box
+  bool _updateBoundingBox;
+
+  // Update data flag
+  bool _updateData;
+
+  // Update frustum flag
+  bool _updateFrustum;
+
+  // Update map flag
+  bool _updateMap;
+
+  // Update rotation matrix flag
+  bool _updateR;
+
+  // Update scale matrix flag
+  bool _updateS;
+
+  // Update slice frequency flag
+  bool _updateSliceFrequency;
+
+  // Update translation matrix flag
+  bool _updateT;
+
+  // Update viewport flag
+  bool _updateViewport;
+
+  // CacheVRAM Size
+  int _vramSize;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/FrustumPlanes.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/FrustumPlanes.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/FrustumPlanes.cpp	(revision 4)
@@ -0,0 +1,327 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "FrustumPlanes.h"
+
+/*--------------------------------------------------------------------------*/
+
+FrustumPlanes::FrustumPlanes() {
+
+  // Initialize MV
+  _mv[0] = 1.0; _mv[4] = 0.0; _mv[8] = 0.0; _mv[12] = 0.0;
+  _mv[1] = 0.0; _mv[5] = 1.0; _mv[9] = 0.0; _mv[13] = 0.0;
+  _mv[2] = 0.0; _mv[6] = 0.0; _mv[10] = 1.0; _mv[14] = 0.0;
+  _mv[3] = 0.0; _mv[7] = 0.0; _mv[11] = 0.0; _mv[15] = 1.0;
+  
+  // Initialize MVP
+  _mvp[0] = 1.0; _mvp[4] = 0.0; _mvp[8] = 0.0; _mvp[12] = 0.0;
+  _mvp[1] = 0.0; _mvp[5] = 1.0; _mvp[9] = 0.0; _mvp[13] = 0.0;
+  _mvp[2] = 0.0; _mvp[6] = 0.0; _mvp[10] = 1.0; _mvp[14] = 0.0;
+  _mvp[3] = 0.0; _mvp[7] = 0.0; _mvp[11] = 0.0; _mvp[15] = 1.0;
+  
+  // Initialize P
+  _p[0] = 1.0; _p[4] = 0.0; _p[8] = 0.0; _p[12] = 0.0;
+  _p[1] = 0.0; _p[5] = 1.0; _p[9] = 0.0; _p[13] = 0.0;
+  _p[2] = 0.0; _p[6] = 0.0; _p[10] = 1.0; _p[14] = 0.0;
+  _p[3] = 0.0; _p[7] = 0.0; _p[11] = 0.0; _p[15] = 1.0;
+
+  // Initialize planes
+  _planes[0][0] = 0.0;
+  _planes[0][1] = 0.0;
+  _planes[0][2] = 0.0;
+  _planes[0][3] = 0.0;
+
+  _planes[1][0] = 0.0;
+  _planes[1][1] = 0.0;
+  _planes[1][2] = 0.0;
+  _planes[1][3] = 0.0;
+  
+  _planes[2][0] = 0.0;
+  _planes[2][1] = 0.0;
+  _planes[2][2] = 0.0;
+  _planes[2][3] = 0.0;
+  
+  _planes[3][0] = 0.0;
+  _planes[3][1] = 0.0;
+  _planes[3][2] = 0.0;
+  _planes[3][3] = 0.0;
+  
+  _planes[4][0] = 0.0;
+  _planes[4][1] = 0.0;
+  _planes[4][2] = 0.0;
+  _planes[4][3] = 0.0;
+  
+  _planes[5][0] = 0.0;
+  _planes[5][1] = 0.0;
+  _planes[5][2] = 0.0;
+  _planes[5][3] = 0.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+FrustumPlanes::~FrustumPlanes() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+float FrustumPlanes::CalculateDistanceToFrustumPlane(int plane, float x,
+                                                     float y, float z) {
+
+  // Distnace to plane
+  float distance = 0.0;
+  
+  // Calculate distance
+  distance = _planes[plane][0] * x +
+    _planes[plane][1] * y +
+    _planes[plane][2] * z +
+    _planes[plane][3];
+  
+  // Return distance
+  return distance;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumPlanes::CalculateFrustumPlanes() {
+  
+  // normalize value
+  float n = 0.0;
+
+  // Calculate a combined MVP from MV and P
+  mult4x4(_mvp, _p, _mv);
+  
+
+  // Extract the frustum's left clipping plane and normalize it.
+  _planes[0][0] = _mvp[3] + _mvp[0];
+  _planes[0][1] = _mvp[7] + _mvp[4];
+  _planes[0][2] = _mvp[11] + _mvp[8];
+  _planes[0][3] = _mvp[15] + _mvp[12];
+  
+  n = (float) sqrt(_planes[0][0] * _planes[0][0] +
+                   _planes[0][1] * _planes[0][1] +
+                   _planes[0][2] * _planes[0][2]);
+  
+  _planes[0][0] /= n;
+  _planes[0][1] /= n;
+  _planes[0][2] /= n;
+  _planes[0][3] /= n;
+  
+
+  // Extract the frustum's right clipping plane and normalize it.
+  _planes[1][0] = _mvp[3] - _mvp[0];
+  _planes[1][1] = _mvp[7] - _mvp[4];
+  _planes[1][2] = _mvp[11] - _mvp[8];
+  _planes[1][3] = _mvp[15] - _mvp[12];
+  
+  n = (float) sqrt(_planes[1][0] * _planes[1][0] +
+                   _planes[1][1] * _planes[1][1] +
+                   _planes[1][2] * _planes[1][2]);
+  
+  _planes[1][0] /= n;
+  _planes[1][1] /= n;
+  _planes[1][2] /= n;
+  _planes[1][3] /= n;
+
+
+  // Extract the frustum's bottom clipping plane and normalize it.
+  _planes[2][0] = _mvp[3] + _mvp[1];
+  _planes[2][1] = _mvp[7] + _mvp[5];
+  _planes[2][2] = _mvp[11] + _mvp[9];
+  _planes[2][3] = _mvp[15] + _mvp[13];
+
+  n = (float) sqrt(_planes[2][0] * _planes[2][0] +
+                   _planes[2][1] * _planes[2][1] +
+                   _planes[2][2] * _planes[2][2]);
+  
+  _planes[2][0] /= n;
+  _planes[2][1] /= n;
+  _planes[2][2] /= n;
+  _planes[2][3] /= n;
+  
+
+  // Extract the frustum's top clipping plane and normalize it.
+  _planes[3][0] = _mvp[3] - _mvp[1];
+  _planes[3][1] = _mvp[7] - _mvp[5];
+  _planes[3][2] = _mvp[11] - _mvp[9];
+  _planes[3][3] = _mvp[15] - _mvp[13];
+  
+  n = (float) sqrt(_planes[3][0] * _planes[3][0] +
+                   _planes[3][1] * _planes[3][1] +
+                   _planes[3][2] * _planes[3][2]);
+  
+  _planes[3][0] /= n;
+  _planes[3][1] /= n;
+  _planes[3][2] /= n;
+  _planes[3][3] /= n;
+
+
+  // Extract the frustum's far clipping plane and normalize it.
+  _planes[4][0] = _mvp[3] - _mvp[2];
+  _planes[4][1] = _mvp[7] - _mvp[6];
+  _planes[4][2] = _mvp[11] - _mvp[10];
+  _planes[4][3] = _mvp[15] - _mvp[14];
+
+  n = (float) sqrt(_planes[4][0] * _planes[4][0] +
+                   _planes[4][1] * _planes[4][1] +
+                   _planes[4][2] * _planes[4][2]);
+  
+  _planes[4][0] /= n;
+  _planes[4][1] /= n;
+  _planes[4][2] /= n;
+  _planes[4][3] /= n;
+    
+
+  // Extract the frustum's near clipping plane and normalize it.
+  _planes[5][0] = _mvp[3] + _mvp[2];
+  _planes[5][1] = _mvp[7] + _mvp[6];
+  _planes[5][2] = _mvp[11] + _mvp[10];
+  _planes[5][3] = _mvp[15] + _mvp[14];
+  
+  n = (float) sqrt(_planes[5][0] * _planes[5][0] +
+                   _planes[5][1] * _planes[5][1] +
+                   _planes[5][2] * _planes[5][2] );
+  
+  _planes[5][0] /= n;
+  _planes[5][1] /= n;
+  _planes[5][2] /= n;
+  _planes[5][3] /= n;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+int FrustumPlanes::CalculateRelationToFrustum(float x0, float y0, float z0,
+                                              float x1, float y1, float z1,
+                                              float x2, float y2, float z2,
+                                              float x3, float y3, float z3,
+                                              float x4, float y4, float z4,
+                                              float x5, float y5, float z5,
+                                              float x6, float y6, float z6,
+                                              float x7, float y7, float z7) {
+
+  // Total points
+  int total = 0;
+
+  // Determine whether a set of vertices are inside, outside or intersect
+  for (int plane = 0 ; plane < 6 ; plane++) {
+    
+    int count = 8;
+    int ptIn = 1;
+    
+    if (CalculateDistanceToFrustumPlane(plane, x0, y0, z0) < 0) {
+      ptIn = 0;
+      --count;
+    }
+    
+    if (CalculateDistanceToFrustumPlane(plane, x1, y1, z1) < 0) {
+      ptIn = 0;
+      --count;
+    }
+    
+    if (CalculateDistanceToFrustumPlane(plane, x2, y2, z2) < 0) {
+      ptIn = 0;
+      --count;
+    }
+    
+    if (CalculateDistanceToFrustumPlane(plane, x3, y3, z3) < 0) {
+      ptIn = 0;
+      --count;
+    }
+
+    if (CalculateDistanceToFrustumPlane(plane, x4, y4, z4) < 0) {
+      ptIn = 0;
+      --count;
+    }
+    
+    if (CalculateDistanceToFrustumPlane(plane, x5, y5, z5) < 0) {
+      ptIn = 0;
+      --count;
+    }
+    
+    if (CalculateDistanceToFrustumPlane(plane, x6, y6, z6) < 0) {
+      ptIn = 0;
+      --count;
+    }
+
+    if (CalculateDistanceToFrustumPlane(plane, x7, y7, z7) < 0) {
+      ptIn = 0;
+      --count;
+    }
+
+    // all points outside plane
+    if (count == 0) {
+      return OUTSIDE_FRUSTUM;
+    }
+    
+    total += ptIn;
+    
+  }
+  
+  // all points inside view
+  if (total == 6) {
+    return INSIDE_FRUSTUM;
+  }
+  
+  // points intersect intersect frustum
+  return INTERSECT_FRUSTUM;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+int FrustumPlanes::CalculateRelationToFrustumPlane(int plane, float x,
+                                                   float y, float z) {
+  
+  // x, y, and z should be world points
+  // not multiplied by mvp, or mv, or p
+  float distance = CalculateDistanceToFrustumPlane(plane, x, y, z);
+  
+  if (distance == 0) return INTERSECT_PLANE;
+  else if (distance > 0) return INSIDE_PLANE;
+  else return OUTSIDE_PLANE;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumPlanes::SetModelViewMatrix(float mv[16]) {
+
+  // Set MV
+  _mv[0] = mv[0]; _mv[4] = mv[4]; _mv[8] = mv[8]; _mv[12] = mv[12];
+  _mv[1] = mv[1]; _mv[5] = mv[5]; _mv[9] = mv[9]; _mv[13] = mv[13];
+  _mv[2] = mv[2]; _mv[6] = mv[6]; _mv[10] = mv[10]; _mv[14] = mv[14];
+  _mv[3] = mv[3]; _mv[7] = mv[7]; _mv[11] = mv[11]; _mv[15] = mv[15];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumPlanes::SetProjectionMatrix(float p[16]) {
+
+  // Set P
+  _p[0] = p[0]; _p[4] = p[4]; _p[8] = p[8]; _p[12] = p[12];
+  _p[1] = p[1]; _p[5] = p[5]; _p[9] = p[9]; _p[13] = p[13];
+  _p[2] = p[2]; _p[6] = p[6]; _p[10] = p[10]; _p[14] = p[14];
+  _p[3] = p[3]; _p[7] = p[7]; _p[11] = p[11]; _p[15] = p[15];
+  
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.cpp	(revision 4)
@@ -0,0 +1,456 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "UserInterfaceServerConcreteCommand.h"
+#include "Master.h"
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServerConcreteCommand::UserInterfaceServerConcreteCommand() {
+
+  _master = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServerConcreteCommand::UserInterfaceServerConcreteCommand(void* 
+                                                                       master) {
+
+  _master = master;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+UserInterfaceServerConcreteCommand::~UserInterfaceServerConcreteCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetAxis(bool* state) {
+
+  ((Master*) _master) -> GetAxis(state);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetAxisPosition(float* x,
+                                                         float* y,
+                                                         float* z) {
+
+  ((Master*) _master) -> GetAxisPosition(x, y, z);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetBoundingBox(bool* state) {
+
+  ((Master*) _master) -> GetBoundingBox(state);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetBrickBox(bool* state) {
+
+  ((Master*) _master) -> GetBrickBox(state);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetClippingPlanes(int node, 
+                                                           float* near, 
+                                                           float* far) {
+
+  ((Master*) _master) -> GetClippingPlanes(node, near, far);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetData(char* filename) {
+
+  ((Master*) _master) -> GetData(filename);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetData(char* filename,
+                                                 int* ramSize, int* vramSize) {
+
+  ((Master*) _master) -> GetData(filename, ramSize, vramSize);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDatasetListFile(int index, 
+                                                            char* file) {
+
+  ((Master*) _master) -> GetDatasetListFile(index, file);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDatasetListName(int index, 
+                                                            char* name) {
+
+  ((Master*) _master) -> GetDatasetListName(index, name);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDatasetListPrefix(int index, 
+                                                              char* prefix) {
+
+  ((Master*) _master) -> GetDatasetListPrefix(index, prefix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDatasetListSize(int* size) {
+
+  ((Master*) _master) -> GetDatasetListSize(size);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDatasetType(int* type) {
+
+  ((Master*) _master) -> GetDatasetType(type);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetDisplaySize(int node, 
+                                                        int* width, 
+                                                        int* height,
+                                                        bool* fullScreen,
+                                                        float* left, 
+                                                        float* right,
+                                                        float* bottom, 
+                                                        float* top) {
+
+  ((Master*) _master) -> GetDisplaySize(node, width, height, fullScreen,
+                                        left, right, bottom, top);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetFrustum(int node, 
+                                                    float* left, 
+                                                    float* right,
+                                                    float* bottom, 
+                                                    float* top) {
+
+  ((Master*) _master) -> GetFrustum(node, left, right, bottom, top);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetMap(unsigned char* map) {
+
+  ((Master*) _master) -> GetMap(map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetOverviewVertices(float 
+                                                             vertices[24]) {
+
+  ((Master*) _master) -> GetOverviewVertices(vertices);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetPrefix(char* prefix) {
+
+  ((Master*) _master) -> GetPrefix(prefix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetRotationMatrix(float m[16]) {
+
+  ((Master*) _master) -> GetRotationMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetScaleMatrix(float m[16]) {
+
+  ((Master*) _master) -> GetScaleMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetSliceFrequency(double* frequency) {
+
+  ((Master*) _master) -> GetSliceFrequency(frequency);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetTotalDisplayDimensions(int* w,
+                                                                   int* h) {
+
+  ((Master*) _master) -> GetTotalDisplayDimensions(w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetTotalDisplayFrustum(float
+                                                                frustum[6]) {
+
+  ((Master*) _master) -> GetTotalDisplayFrustum(frustum);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetTranslationMatrix(float m[16]) {
+
+  ((Master*) _master) -> GetTranslationMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetVerticalFieldOfView(float* vFOV) {
+
+  ((Master*) _master) -> GetVerticalFieldOfView(vFOV);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::GetViewport(int node, 
+                                                     int* x, 
+                                                     int* y, 
+                                                     int* w, 
+                                                     int* h) {
+
+  ((Master*) _master) -> GetViewport(node, x, y, w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::ResetView() {
+
+  ((Master*) _master) -> ResetView();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetAxisOff() {
+
+  ((Master*) _master) -> UpdateAxisOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetAxisOn() {
+
+  ((Master*) _master) -> UpdateAxisOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetAxisPosition(float x, 
+                                                         float y, 
+                                                         float z) {
+
+  ((Master*) _master) -> UpdateAxisPosition(x, y, z);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetBoundingBoxOff() {
+
+  ((Master*) _master) -> UpdateBoundingBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetBoundingBoxOn() {
+
+  ((Master*) _master) -> UpdateBoundingBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetBrickBoxOff() {
+
+  ((Master*) _master) -> UpdateBrickBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetBrickBoxOn() {
+
+  ((Master*) _master) -> UpdateBrickBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetClippingPlanes(int node, 
+                                                           float near, 
+                                                           float far) {
+
+  ((Master*) _master) -> UpdateClippingPlanes(node, near, far);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetCommandExit() {
+
+  ((Master*) _master) -> UpdateCommandExit();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetCommandRender() {
+
+  ((Master*) _master) -> UpdateCommandRender();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetData(char* filename) {
+
+  ((Master*) _master) -> UpdateData(filename);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetData(char* filename,
+                                                 int ramSize, int vramSize) {
+
+  ((Master*) _master) -> UpdateData(filename, ramSize, vramSize);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetFrustum(int node, 
+                                                    float left, float right,
+                                                    float bottom, float top) {
+
+  ((Master*) _master) -> UpdateFrustum(node, left, right, bottom, top);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetMap(unsigned char* map) {
+
+  ((Master*) _master) -> UpdateMap(map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetMap16(unsigned char* map) {
+
+  ((Master*) _master) -> UpdateMap16(map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetPrefix(char* prefix) {
+
+  ((Master*) _master) -> UpdatePrefix(prefix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetRotationMatrix(float m[16]) {
+
+  ((Master*) _master) -> UpdateRotationMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetScaleMatrix(float m[16]) {
+
+  ((Master*) _master) -> UpdateScaleMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetSliceFrequency(double frequency) {
+
+  ((Master*) _master) -> UpdateSliceFrequency(frequency);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetTranslationMatrix(float m[16]) {
+
+  ((Master*) _master) -> UpdateTranslationMatrix(m);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void UserInterfaceServerConcreteCommand::SetViewport(int node, int x, int y, 
+                                                     int w, int h) {
+
+  ((Master*) _master) -> UpdateViewport(node, x, y, w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/ScriptGenerator.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/ScriptGenerator.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/ScriptGenerator.cpp	(revision 4)
@@ -0,0 +1,309 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application Testing Tools                                */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "FrustumCalculator.h"
+#include "Matrix.h"
+#include "Vertex.h"
+
+/*---------------------------------------------------------------------------*/
+
+#define max(A,B) ( (A) > (B) ? (A):(B))
+#define min(A,B) ( (A) < (B) ? (A):(B))
+
+/*---------------------------------------------------------------------------*/
+
+int main(int argc, char** argv) {
+
+  // Data set name
+  char _dataName[1024];
+
+  // Data set prefix
+  char _dataPrefix[1024];
+
+  // Total display width in pixels
+  int _displayWidth = 0;
+
+  // Total display height in pixels
+  int _displayHeight = 0;
+
+  // Total display's vertical field of view
+  float _displayVFOV = 0.0;
+
+  // Total display's near clipping plane
+  float _displayNear = 0.0;
+
+  // Total display's far clipping plane
+  float _displayFar = 0.0;
+
+  // Total dislay's left clipping plane
+  float _displayLeft = 0.0;
+
+  // Total display's right clipping plane
+  float _displayRight = 0.0;
+
+  // Total display's bottom clipping plane
+  float _displayBottom = 0.0;
+
+  // Total display's top clipping planes
+  float _displayTop = 0.0;
+
+  // CacheRAM size
+  int _ramSize = -1;
+
+  // Scale matrix
+  float S[16];
+
+  // CacheVRAM size
+  int _vramSize = -1;
+
+  // Wait time between operations
+  int _wait = 0;
+
+
+  // Bounding vertices of entire data set
+  Vertex _dataVertex[8];
+
+
+  // Check command line arguments
+  if (argc != 3) {
+    fprintf(stderr, "Usage: ScriptGenerator inputFile outputFile\n");
+    exit(1);
+  }
+
+  // Input file
+  FILE* infptr = NULL;
+
+  // Try to open input file
+  if ((infptr = fopen(argv[1], "r")) == NULL) {
+    fprintf(stderr, "Can not read input file %s\n", argv[1]);
+  }
+
+  // Read display width and height
+  fscanf(infptr, "%d %d", &_displayWidth, &_displayHeight);
+
+  // Read display's vertical field of view
+  fscanf(infptr, "%f", &_displayVFOV);
+
+  // Read display's near and far clipping planes
+  fscanf(infptr, "%f %f", &_displayNear, &_displayFar);
+
+  // Read overview vertices
+  for (int i = 0 ; i < 8 ; i++) {
+    float x, y, z;
+    fscanf(infptr, "%f %f %f", &x, &y, &z);
+    _dataVertex[i].SetXYZ(x, y, z);
+  }
+
+  // Read inital scale matrix
+  fscanf(infptr, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", 
+         &S[0], &S[4], &S[8], &S[12],
+         &S[1], &S[5], &S[9], &S[13],
+         &S[2], &S[6], &S[10], &S[14],
+         &S[3], &S[7], &S[11], &S[15]);
+
+  // Read wait time
+  fscanf(infptr, "%d", &_wait);
+
+  // Read data set prefix
+  fscanf(infptr, "%s", _dataPrefix);
+
+  // Read data set name
+  fscanf(infptr, "%s", _dataName);
+
+  // Read cache sizes
+  fscanf(infptr, "%d %d", &_vramSize, &_ramSize);
+
+  // Close input file
+  fclose(infptr);
+
+
+  // Output file
+  FILE* outfptr = NULL;
+
+  // Try to open output file
+  if ((outfptr = fopen(argv[2], "w")) == NULL) {
+    fprintf(stderr, "Can not open output file %s\n", argv[2]);
+  }
+
+  // Print script header
+  fprintf(outfptr, "VRA_UI_SCRIPT\n");
+
+  // Print data set prefix
+  fprintf(outfptr, "CMD_PRE %s\n", _dataPrefix);
+
+  // Print data set name
+  fprintf(outfptr, "CMD_DAT %s %d %d\n", _dataName, _ramSize, _vramSize);
+
+  // Wait for some time while data is loaded
+  fprintf(outfptr, "WAIT 30\n");
+
+
+  // Setup frustum calculator
+  FrustumCalculator frustumCalculator;
+  frustumCalculator.SetDisplayWidth(_displayWidth);
+  frustumCalculator.SetDisplayHeight(_displayHeight);
+  frustumCalculator.SetNearClippingPlane(_displayNear);
+  frustumCalculator.SetVerticalFieldOfView(_displayVFOV);
+
+  // Calculate full frustum for entire display
+  frustumCalculator.CalculateFrustum();
+  frustumCalculator.GetFullFrustum(&_displayLeft,
+                                   &_displayRight,
+                                   &_displayBottom,
+                                   &_displayTop);
+
+
+  // Calculate frustum width, height, and depth
+  float frustumWidth = fabs(_displayRight - _displayLeft);
+  float frustumHeight = fabs(_displayTop - _displayBottom);
+  float frustumDepth = fabs(_displayFar - _displayNear);
+
+  // Determine minimum frustum axis
+  float minFrustumAxis = min(frustumWidth, min(frustumHeight, frustumDepth));
+
+
+  // Calculate width, height, and depth of data set
+  float dataWidth = fabs(_dataVertex[3].GetX() - _dataVertex[0].GetX());
+  float dataHeight = fabs(_dataVertex[4].GetY() - _dataVertex[0].GetY());
+  float dataDepth = fabs(_dataVertex[1].GetZ() - _dataVertex[0].GetZ());
+
+  // Determine maximum data axis
+  float maxDataAxis = max(dataWidth, max(dataHeight, dataDepth));
+
+
+  // Calculate scale factor
+  //float scaleFactor = maxDataAxis / minFrustumAxis;
+  float scaleFactor = frustumWidth / dataWidth;
+
+
+  // Write scale matrix
+  //fprintf(outfptr, 
+  //        "CMD_SCA %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+  //        S[0], S[4], S[8], S[12], S[1], S[5], S[9], S[13],
+  //        S[2], S[6], S[10], S[14], S[3], S[7], S[11], S[15]);
+  fprintf(outfptr, 
+          "CMD_SCA %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+          scaleFactor, 0.0, 0.0, 0.0, 0.0, scaleFactor, 0.0, 0.0,
+          0.0, 0.0, scaleFactor, 0.0, 0.0, 0.0, 0.0, 1.0);
+
+
+  /*
+  // Base rotation matrix: UNUSED
+  float Rb[16];
+
+  // Calculate base rotation: UNUSED
+
+  // Width is biggest
+  if (dataWidth >= dataHeight && dataWidth >= dataDepth) {
+
+    // Rotate 0.0 degrees about the x axis producing the identity matrix
+    calc_rot_x(Rb, 0.0);
+
+  }
+
+  // Height is biggest
+  else if (dataHeight >= dataWidth && dataHeight >= dataDepth) {
+
+    // Rotate 90.0 degrees about the z axis
+    calc_rot_z(Rb, 90.0);
+
+  }
+
+  // Depth is biggest
+  else if (dataDepth >= dataWidth && dataDepth >= dataHeight) {
+
+    // Rotate 90.0 degrees about the y axis
+    calc_rot_y(Rb, 90.0);
+
+  }
+  */
+
+
+  // Rotation matrix
+  float R[16];
+
+  // Rotate about y axis
+  for (float i = 0.0 ; i < 180.0 ; i += 1.0) {
+
+    // Calculate rotation about y axis
+    calc_rot_y(R, i);
+
+    fprintf(outfptr, 
+            "CMD_ROT %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+            R[0], R[4], R[8], R[12], R[1], R[5], R[9], R[13],
+            R[2], R[6], R[10], R[14], R[3], R[7], R[11], R[15]);
+    fprintf(outfptr, "WAIT 1\n");
+    fprintf(outfptr, "CMD_REN\n");
+    fprintf(outfptr, "WAIT %d\n", _wait);
+
+  }
+
+
+  // Rotate about x axis
+  /*
+  for (float i = 0.0 ; i < 360.0 ; i += 1.0) {
+
+    // Calculate rotation about x axis
+    calc_rot_x(R, i);
+
+    fprintf(outfptr, 
+            "CMD_ROT %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+            R[0], R[4], R[8], R[12], R[1], R[5], R[9], R[13],
+            R[2], R[6], R[10], R[14], R[3], R[7], R[11], R[15]);
+    fprintf(outfptr, "WAIT 1\n");
+    fprintf(outfptr, "CMD_REN\n");
+    fprintf(outfptr, "WAIT %d\n", _wait);
+
+  }
+  */
+
+
+  // Rotate about z axis
+  /*
+  for (float i = 0.0 ; i < 360.0 ; i += 1.0) {
+
+    // Calculate rotation about y axis
+    calc_rot_z(R, i);
+
+    fprintf(outfptr, 
+            "CMD_ROT %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
+            R[0], R[4], R[8], R[12], R[1], R[5], R[9], R[13],
+            R[2], R[6], R[10], R[14], R[3], R[7], R[11], R[15]);
+    fprintf(outfptr, "WAIT 1\n");
+    fprintf(outfptr, "CMD_REN\n");
+    fprintf(outfptr, "WAIT %d\n", _wait);
+
+  }
+  */
+  
+
+  // Close output file
+  fclose(outfptr);
+
+
+  // Return
+  return 0;
+
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Vertex.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Vertex.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Vertex.cpp	(revision 4)
@@ -0,0 +1,251 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Vertex.h"
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::Vertex() {
+
+  // Initialize vertex
+  _xyz[0] = 0.0;
+  _xyz[1] = 0.0;
+  _xyz[2] = 0.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::Vertex(double x, double y, double z) {
+  
+  // Initialize vertex
+  _xyz[0] = (float) x;
+  _xyz[1] = (float) y;
+  _xyz[2] = (float) z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::Vertex(float x, float y, float z) {
+  
+  // Initialize vertex
+  _xyz[0] = x;
+  _xyz[1] = y;
+  _xyz[2] = z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::Vertex(double xyz[3]) {
+  
+  // Initialize vertex
+  _xyz[0] = (float) xyz[0];
+  _xyz[1] = (float) xyz[1];
+  _xyz[2] = (float) xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::Vertex(float xyz[3]) {
+  
+  // Initialize vertex
+  _xyz[0] = xyz[0];
+  _xyz[1] = xyz[1];
+  _xyz[2] = xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+Vertex::~Vertex() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Vertex::GetX() {
+
+  // Return X
+  return _xyz[0];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Vertex::GetY() {
+  
+  // Return Y
+  return _xyz[1];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Vertex::GetZ() {
+  
+  // Return Z
+  return _xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::GetXYZ(double* x, double* y, double* z) {
+  
+  // Get X, Y, Z
+  *x = (double) _xyz[0];
+  *y = (double) _xyz[1];
+  *z = (double) _xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::GetXYZ(float* x, float* y, float* z) {
+  
+  // Get X, Y, Z
+  *x = _xyz[0];
+  *y = _xyz[1];
+  *z = _xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::GetXYZ(double xyz[3]) {
+  
+  // Get X, Y, Z
+  xyz[0] = (double) _xyz[0];
+  xyz[1] = (double) _xyz[1];
+  xyz[2] = (double) _xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::GetXYZ(float xyz[3]) {
+  
+  // Get X, Y, Z
+  xyz[0] = _xyz[0];
+  xyz[1] = _xyz[1];
+  xyz[2] = _xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetX(double x) {
+  
+  // Set X
+  _xyz[0] = (float) x;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetX(float x) {
+  
+  // Set X
+  _xyz[0] = x;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetY(double y) {
+  
+  // Set Y
+  _xyz[1] = (float) y;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetY(float y) {
+  
+  // Set Y
+  _xyz[1] = y;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetZ(double z) {
+  
+  // Set Z
+  _xyz[2] = (float) z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetZ(float z) {
+  
+  // Set Z
+  _xyz[2] = z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetXYZ(double x, double y, double z) {
+  
+  // Set X, Y, Z
+  _xyz[0] = (float) x;
+  _xyz[1] = (float) y;
+  _xyz[2] = (float) z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetXYZ(float x, float y, float z) {
+  
+  // Set X, Y, Z
+  _xyz[0] = x;
+  _xyz[1] = y;
+  _xyz[2] = z;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetXYZ(double xyz[3]) {
+  
+  // Set X, Y, Z
+  _xyz[0] = (float) xyz[0];
+  _xyz[1] = (float) xyz[1];
+  _xyz[2] = (float) xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Vertex::SetXYZ(float xyz[3]) {
+  
+  // Set X, Y, Z
+  _xyz[0] = xyz[0];
+  _xyz[1] = xyz[1];
+  _xyz[2] = xyz[2];
+  
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Transfer_Function.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Transfer_Function.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Transfer_Function.h	(revision 4)
@@ -0,0 +1,219 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_TRANSFER_FUNCTION_H
+#define FL_TRANSFER_FUNCTION_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Box.H>
+#include <Fl/Fl_Double_Window.H>
+#include <Fl/Fl_Float_Input.H>
+#include <Fl/Fl_Int_Input.H>
+
+#include "Fl_Color_Transfer_Function.h"
+#include "Fl_Opacity_Transfer_Function.h"
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Transfer_Function : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Transfer_Function(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Transfer_Function();
+
+  // Color blue field changed
+  void CallbackChangeBlue();
+
+  // Color scalar field changed
+  void CallbackChangeColorScalar();
+
+  // Color green field changed
+  void CallbackChangeGreen();
+
+  // Opacity opacity field changed
+  void CallbackChangeOpacity();
+
+  // Color red field changed
+  void CallbackChangeRed();
+
+  // Opacity scalar field changed
+  void CallbackChangeScalar();
+
+  // Color move
+  void CallbackColorMove();
+
+  // Color select
+  void CallbackColorSelect();
+
+  // Color unselect
+  void CallbackColorUnselect();
+
+  // Opacity move
+  void CallbackOpacityMove();
+
+  // Opacity select
+  void CallbackOpacitySelect();
+
+  // Opacity unselect
+  void CallbackOpacityUnselect();
+
+  // Get color for a given scalar value
+  void GetColor(float scalar, float* r, float* g, float* b);
+
+  // Get color control point
+  void GetColorControlPoint(int index, float* scalar, float* r, 
+                            float* g, float* b);
+
+  // Get number of color control points
+  int GetNumberOfColorControlPoints();
+
+  // Get number of opacity control points
+  int GetNumberOfOpacityControlPoints();
+
+  // Get opacity for a given scalar value
+  float GetOpacity(float scalar);
+
+  // Get opacity control point
+  void GetOpacityControlPoint(int index, float* scalar, float* opacity);
+
+  // Get opacity range
+  void GetOpacityRange(float* min, float* max);
+
+  // Get scalar range
+  void GetScalarRange(float* min, float* max);
+
+  // Redraw
+  void Redraw();
+
+  // Restore color control points from a list
+  void RestoreColorControlPoints(int number, float max, float* scalar, 
+                                 float* r, float* g, float* b);
+
+  // Restore opacity control points from a list
+  void RestoreOpacityControlPoints(int number, float max, float* scalar, 
+                                   float* opacity);
+
+  // Set background color
+  void SetBackgroundColor(float r, float g, float b, float a);
+
+  // Set box color
+  void SetBoxColor(float r, float g, float b, float a);
+
+  // Set control point color
+  void SetControlPointColor(float r, float g, float b, float a);
+
+  // Set control point size
+  void SetControlPointSize(int size);
+
+  // Set focus point color
+  void SetFocusPointColor(float r, float g, float b, float a);
+
+  // Set line color
+  void SetLineColor(float r, float g, float b, float a);
+
+  // Set maximum scalar value
+  void SetMaximumScalar(float max);
+
+  // Set text color
+  void SetTextColor(float r, float g, float b, float a);
+
+  // Set update callback
+  void SetUpdateCallback(void (*cb)(void* p), void* d);
+
+private:
+
+  // Static blue field changed
+  static void StaticCallbackChangeBlue(Fl_Widget* w, void *v);
+
+  // Static color scalar field changed
+  static void StaticCallbackChangeColorScalar(Fl_Widget* w, void* v);
+
+  // Static green field changed
+  static void StaticCallbackChangeGreen(Fl_Widget* w, void *v);
+
+  // Static opacity opacity field changed
+  static void StaticCallbackChangeOpacity(Fl_Widget* w, void *v);
+
+  // Static red field changed
+  static void StaticCallbackChangeRed(Fl_Widget* w, void *v);
+
+  // Static opacity scalar field changed
+  static void StaticCallbackChangeScalar(Fl_Widget* w, void* v);
+
+  // Static color move 
+  static void StaticCallbackColorMove(void* v);
+
+  // Static color select
+  static void StaticCallbackColorSelect(void* v);
+
+  // Static color unselect
+  static void StaticCallbackColorUnselect(void* f);
+
+  // Static opacity move 
+  static void StaticCallbackOpacityMove(void* v);
+
+  // Static opacity select
+  static void StaticCallbackOpacitySelect(void* v);
+
+  // Static opacity unselect
+  static void StaticCallbackOpacityUnselect(void* f);
+
+  // Color transfer function
+  Fl_Color_Transfer_Function* _ctf;
+
+  // Scalar input field
+  Fl_Int_Input* _colorScalarInput;
+
+  // Red input field
+  Fl_Float_Input* _redInput;
+
+  // Green input field
+  Fl_Float_Input* _greenInput;
+
+  // Blue input field
+  Fl_Float_Input* _blueInput;
+
+  // Opacity transfer function
+  Fl_Opacity_Transfer_Function* _otf;
+
+  // Scalar input field
+  Fl_Int_Input* _scalarInput;
+
+  // Opacity input field
+  Fl_Float_Input* _opacityInput;
+
+  // Update callback
+  void (*_updateCallback)(void* p);
+
+  // Update callback data
+  void* _updateCallbackData;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Dialog.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Dialog.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Dialog.cpp	(revision 4)
@@ -0,0 +1,64 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Dialog.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Dialog::Fl_Dialog(int x, int y, int w, int h, const char* l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Resize to correct size
+  size(195, 75);
+
+  // Set modal
+  //set_modal();
+  
+  // Create box
+  _box = new Fl_Box(10, 10, 175, 20);
+  
+  // Create ok button
+  _okButton = new Fl_Return_Button(90, 40, 95, 25, "OK");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Dialog::~Fl_Dialog() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Dialog::SetMessage(char* message) {
+
+  // Set message
+  _box -> copy_label(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Dialog::SetOKButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _okButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/FrustumCalculator.h
===================================================================
--- trunk/src/testing/app/VRA/src/FrustumCalculator.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/FrustumCalculator.h	(revision 4)
@@ -0,0 +1,122 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VOLUME_FRUSTUM_CALCULATOR_H
+#define VOLUME_FRUSTUM_CALCULATOR_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <math.h>
+
+/*--------------------------------------------------------------------------*/
+
+class FrustumCalculator {
+
+ public:
+
+  // Constructor
+  FrustumCalculator();
+
+  // Destructor
+  ~FrustumCalculator();
+
+  // Calculate frustum based on percentage
+  void CalculateFrustum();
+
+  // Get display height in pixels
+  int GetDisplayHeight();
+
+  // Get display width in pixels
+  int GetDisplayWidth();
+
+  // Get full frustum for display (call CalculateFrustum to compute)
+  void GetFullFrustum(float* left, float* right,
+                      float* bottom, float* top);
+
+  // Get full frustum for display (call CalculateFrustum to compute)
+  void GetFullFrustum(float array[4]);
+
+  // Get frustum (call CalculateFrustum to compute the frustum)
+  void GetFrustum(float* left, float* right,
+                  float* bottom, float* top);
+
+  // Get frustum (call CalculateFrustum to compute the frustum)
+  void GetFrustum(float array[4]);
+
+  // Get near clipping plane
+  float GetNearClippingPlane();
+
+  // Get the percentage of the display for the frustum
+  void GetPercentage(float* left, float* right,
+                     float* bottom, float* top);
+
+  // Get the percentage of the display for the frustum
+  void GetPercentage(float array[4]);
+
+  // Get the vertical field of view as an angle
+  float GetVerticalFieldOfView();
+
+  // Set display height in pixels
+  void SetDisplayHeight(int pixels);
+
+  // Set display width in pixels
+  void SetDisplayWidth(int pixels);
+
+  // Set near clipping plane
+  void SetNearClippingPlane(float near);
+
+  // Set the percentage of the display for the frustum
+  void SetPercentage(float left, float right, float bottom, float top);
+
+  // Set the percentage of the display for the frustum
+  void SetPercentage(float array[4]);
+
+  // Set the vertical field of view as an angle
+  void SetVerticalFieldOfView(float angle);
+
+ private:
+
+  // Height of display in pixels
+  int _displayHeight;
+
+  // Width of display in pixels
+  int _displayWidth;
+
+  // View frustum as left, right, bottom, top
+  float _frustum[4];
+
+  // Full view frustum for display
+  float _fullFrustum[4];
+
+  // Near clipping plane
+  float _nearClippingPlane;
+
+  // Percentage of the display for the frustum
+  float _percentage[4];
+
+  // Vertical field of view as an angle
+  float _verticalFieldOfView;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClientConcreteCommand.h	(revision 4)
@@ -0,0 +1,152 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_CLIENT_CONCRETE_COMMAND_H
+#define USER_INTERFACE_CLIENT_CONCRETE_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DataPacker.h"
+#include "UserInterfaceClientAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceClientConcreteCommand : 
+public UserInterfaceClientAbstractCommand {
+
+public:
+
+  // Constructor
+  UserInterfaceClientConcreteCommand();
+
+  // Constructor giving add message callback
+  UserInterfaceClientConcreteCommand(void (*cb)(unsigned char* message));
+
+  // Destructor
+  virtual ~UserInterfaceClientConcreteCommand();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(int node, float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set data set filename
+  virtual void SetData(char* filename);
+
+  // Set data set filename and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set data set list file
+  virtual void SetDatasetListFile(int index, char* file);
+
+  // Set data set list name
+  virtual void SetDatasetListName(int index, char* name);
+
+  // Set data set list prefix
+  virtual void SetDatasetListPrefix(int index, char* prefix);
+
+  // Set data set list size
+  virtual void SetDatasetListSize(int size);
+
+  // Set data set type
+  virtual void SetDatasetType(int type);
+
+  // Set display size
+  virtual void SetDisplaySize(int node, int width, int height, 
+                              bool fullScreen, 
+                              float left, float right, 
+                              float bottom, float top);
+
+  // Set frustum
+  virtual void SetFrustum(int node, float left, float right,
+                          float bottom, float top);
+
+  // Set transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set overview vertices function
+  virtual void SetOverviewVertices(float vertices[24]);
+
+  // Set data prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set progress
+  virtual void SetProgress(int value, int total);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float m[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float m[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set total display dimensions
+  virtual void SetTotalDisplayDimensions(int w, int h);
+
+  // Set total display frustum
+  virtual void SetTotalDisplayFrustum(float frustum[6]);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float m[16]);
+
+  // Set vertical field of view
+  virtual void SetVerticalFieldOfView(float vFOV);
+
+  // Set viewport
+  virtual void SetViewport(int node, int x, int y, int w, int h);
+
+private:
+
+  // Add message callback
+  void (*_addMessageCallback)(unsigned char* message);
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Log.h
===================================================================
--- trunk/src/testing/app/VRA/src/Log.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Log.h	(revision 4)
@@ -0,0 +1,65 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef LOG_H
+#define LOG_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <mpi.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Log {
+
+public:
+
+  // Print message and time to standard output
+  void static Assert(const char* message);
+
+  // Start log
+  void static Start();
+
+  // Start log with sufix
+  void static Start(char* sufix);
+
+  // Stop log
+  void static Stop();
+
+  // Message count
+  static int logCount;
+
+  // Log file pointer
+  static FILE* logFile;
+
+  // Mutex
+  static pthread_mutex_t logMutex;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/OpacityTransferFunctionWidget.cpp	(revision 4)
@@ -0,0 +1,1484 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "OpacityTransferFunctionWidget.h"
+
+/*--------------------------------------------------------------------------*/
+
+OpacityTransferFunctionWidget::OpacityTransferFunctionWidget(int w, int h) {
+
+  // Initialize background color
+  _backgroundColor[0] = 0.0;
+  _backgroundColor[1] = 0.0;
+  _backgroundColor[2] = 0.0;
+  _backgroundColor[3] = 0.0;
+
+  // Initialize box bound
+  _boxBound[0] = 0.0;
+  _boxBound[1] = 0.0;
+  _boxBound[2] = 0.0;
+  _boxBound[3] = 0.0;
+
+  // Initialize box color
+  _boxColor[0] = 1.0;
+  _boxColor[1] = 1.0;
+  _boxColor[2] = 1.0;
+  _boxColor[3] = 1.0;
+
+  // Initialize control point color
+  _controlPointColor[0] = 1.0;
+  _controlPointColor[1] = 1.0;
+  _controlPointColor[2] = 1.0;
+  _controlPointColor[3] = 1.0;
+
+  // Initialize control point size
+  _controlPointSize = 8;
+
+  // Initialize focus point index
+  _focusPoint = -1;
+
+  // Initialize focus point color
+  _focusPointColor[0] = 0.0;
+  _focusPointColor[1] = 0.0;
+  _focusPointColor[2] = 0.0;
+  _focusPointColor[3] = 1.0;
+
+  // Initialize frustum
+  _frustum[0] = 0.0;
+  _frustum[1] = 1.0;
+  _frustum[2] = 0.0;
+  _frustum[3] = 1.0;
+  _frustum[4] = -1.0;
+  _frustum[5] = 1.0;
+
+  // Initialize line color
+  _lineColor[0] = 1.0;
+  _lineColor[1] = 1.0;  
+  _lineColor[2] = 1.0;
+  _lineColor[3] = 1.0;
+
+  // Initialize number of control points
+  _numberOfControlPoints = 0;
+
+  // Initialize opacity range
+  _opacityMaximum = 1.0;
+  _opacityMinimum = 0.0;
+
+  // Initialize size of window
+  _pixelDimensions[0] = w;
+  _pixelDimensions[1] = h;
+
+  // Initialize scalar range
+  _scalarMaximum = 1.0;
+  _scalarMinimum = 0.0;
+
+  // Initialize text color
+  _textColor[0] = 1.0;
+  _textColor[1] = 1.0;
+  _textColor[2] = 1.0;
+  _textColor[3] = 1.0;
+
+  // Initialize transfer function
+  ControlPoint controlPoint;
+
+  // First control point
+  controlPoint.SetScalar(0.0);
+  controlPoint.SetOpacity(0.0);
+  _controlPoint.push_back(controlPoint);
+
+  // Second control point
+  controlPoint.SetScalar(1.0);
+  controlPoint.SetOpacity(1.0);
+  _controlPoint.push_back(controlPoint);
+
+  // Increment number of control points
+  _numberOfControlPoints = 2;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OpacityTransferFunctionWidget::~OpacityTransferFunctionWidget() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::AddControlPoint(int px, int py) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Control point
+  ControlPoint controlPoint;
+
+  // Function coordinates
+  float scalar = 0.0;
+  float opacity = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, &scalar, &opacity);
+
+      // Set control point
+      controlPoint.SetOpacity(opacity);
+      controlPoint.SetScalar(scalar);
+
+      // Add control point
+      _controlPoint.push_back(controlPoint);
+
+      // Sort control points
+      sort(_controlPoint.begin(), _controlPoint.end());
+
+      // Get index of newly added point
+      _focusPoint = GetControlPointIndex(scalar, opacity);
+
+      // Increment number of control points
+      _numberOfControlPoints++;
+
+      // Control point added
+      return true;
+
+    }
+
+  }
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Did not add control point
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::BoxToFunction(float bx, 
+                                                  float by,
+                                                  float* scalar, 
+                                                  float* opacity) {
+
+  // Convert from box coordinates to function coordinates
+  *scalar = ((bx * (_scalarMaximum - _scalarMinimum)) + _scalarMinimum);
+  *opacity = ((by * (_opacityMaximum - _opacityMinimum)) + _opacityMinimum);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::BoxToWorld(float bx, float by, 
+                                               float* wx, float* wy) {
+
+  // Convert from box coordinates to world coordinates
+  *wx = (bx * (_boxBound[1] - _boxBound[0])) + _boxBound[0];
+  *wy = (by * (_boxBound[3] - _boxBound[2])) + _boxBound[2];
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::Draw() {
+
+  // Clear color
+  glClearColor(_backgroundColor[0], _backgroundColor[1],
+               _backgroundColor[2], _backgroundColor[3]);
+
+  // Clear bufffer
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Set viewport
+  glViewport(0, 0, _pixelDimensions[0], _pixelDimensions[1]);
+
+  // Set projection mode
+  glMatrixMode(GL_PROJECTION);
+
+  // Load identity
+  glLoadIdentity();
+
+  // Set frustum
+  glOrtho(_frustum[0], _frustum[1], 
+          _frustum[2], _frustum[3], 
+          _frustum[4], _frustum[5]);
+
+  // Set modelview mode
+  glMatrixMode(GL_MODELVIEW);
+
+
+  // Text color
+  glColor4f(_textColor[0], _textColor[1], _textColor[2], _textColor[3]);
+
+  // Text border in pixels
+  int textBorder = 5;
+
+  // Text height in pixels
+  int textHeight = 10;
+
+
+  /*
+  // Minimum opacity
+
+  // Calculate offsets for text
+  float opacityMinimumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float opacityMinimumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder + (float) textHeight + (float) textBorder);
+
+  // Create text string
+  char opacityMinimumString[128];
+  sprintf(opacityMinimumString, "%.1f", _opacityMinimum);
+
+  // Calculate width
+  float opacityMinimumWidth = 0.0;
+  for (int i = 0 ; i < strlen(opacityMinimumString) ; i++) {
+    opacityMinimumWidth += 
+      glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, opacityMinimumString[i]);
+  }
+
+  // Position text
+  glRasterPos3f(_frustum[0] + opacityMinimumHorizontalOffset, 
+                _frustum[2] + opacityMinimumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < strlen(opacityMinimumString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, opacityMinimumString[i]);
+  }
+  */
+
+
+  /*
+  // Maximum opacity
+
+  // Calculate offsets for text
+  float opacityMaximumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float opacityMaximumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     ((float) textBorder + (float) textHeight);
+
+  // Create text string
+  char opacityMaximumString[128];
+  sprintf(opacityMaximumString, "%.1f", _opacityMaximum);
+
+  // Calculate width
+  float opacityMaximumWidth = 0.0;
+  for (int i = 0 ; i < strlen(opacityMaximumString) ; i++) {
+    opacityMaximumWidth += 
+      glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, opacityMaximumString[i]);
+  }
+
+  // Position text
+  glRasterPos3f(_frustum[0] + opacityMaximumHorizontalOffset, 
+                _frustum[3] - opacityMaximumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < strlen(opacityMinimumString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, opacityMaximumString[i]);
+  }
+  */
+
+
+  // Minimum scalar
+
+  // Calculate offsets for text
+  float scalarMinimumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder /*+ opacityMinimumWidth + (float) textBorder*/);
+  float scalarMinimumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Create text string
+  char scalarMinimumString[128];
+  sprintf(scalarMinimumString, "%.0f", _scalarMinimum);
+
+  // Calculate width
+  float scalarMinimumWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarMinimumString) ; i++) {
+    //scalarMinimumWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarMinimumString[i]);
+  }
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarMinimumHorizontalOffset, 
+                _frustum[2] + scalarMinimumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarMinimumString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarMinimumString[i]);
+  }
+
+
+  // Maximum scalar
+
+  // Create text string
+  char scalarMaximumString[128];
+  sprintf(scalarMaximumString, "%.0f", _scalarMaximum);
+
+  // Calculate width
+  float scalarMaximumWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarMaximumString) ; i++) {
+    //scalarMaximumWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarMaximumString[i]);
+  }
+
+  // Calculate offsets for text
+  float scalarMaximumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder + scalarMaximumWidth);
+  float scalarMaximumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[1] - scalarMaximumHorizontalOffset, 
+                _frustum[2] + scalarMaximumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarMaximumString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarMaximumString[i]);
+  }
+
+
+  // Determine left bound
+  _boxBound[0] = _frustum[0] + 
+    scalarMinimumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+     scalarMinimumWidth) / 2.0;
+
+  // Determine right bound
+  _boxBound[1] = _frustum[1] -
+    scalarMaximumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    scalarMaximumWidth) / 2.0;
+
+  // Determine bottom bound
+  _boxBound[2] = _frustum[2] +
+    /*opacityMinimumVerticalOffset +*/
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     ((float) textHeight + (float) textBorder + (float) textBorder)) /*/ 2.0*/;
+  
+  // Determine top bound
+  _boxBound[3]  = _frustum[3] -
+    /*opacityMaximumVerticalOffset +*/
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    (float) textHeight) / 2.0;
+
+
+  /*
+  // Opacity label
+ 
+  // Opacity width
+  float opacityLabelWidth = glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, 'O');
+
+  // Calculate offsets for text
+  float opacityLabelHorizontalOffset =
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+   float opacityLabelVerticalOffset =
+     ((_boxBound[3] - _boxBound[2]) / 2.0) + _boxBound[2] -
+     ((((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+       (float) textHeight) / 2.0);
+   
+  // Position text
+  glRasterPos3f(_frustum[0] + opacityLabelHorizontalOffset, 
+                _frustum[2] + opacityLabelVerticalOffset, 
+                0.0);
+
+  // Display text
+  glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, 'O');
+  */
+
+
+  // Scalar label
+
+  // Create text string
+  char scalarLabelString[128];
+
+  // Fill text string
+  sprintf(scalarLabelString, "Scalar");
+
+  // Scalar width
+  float scalarLabelWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarLabelString) ; i++) {
+    //scalarLabelWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarLabelString[i]);
+  }
+
+  // Calculate offsets for text
+  float scalarLabelHorizontalOffset = 
+    ((_boxBound[1] - _boxBound[0]) / 2.0) + _boxBound[0] - 
+    ((((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+      scalarLabelWidth) / 2.0);
+  float scalarLabelVerticalOffset =
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarLabelHorizontalOffset, 
+                _frustum[2] + scalarLabelVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarLabelString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarLabelString[i]);
+  }
+
+
+  /*
+  // Control point scalar readout
+
+  // Calculate offsets for text
+  float scalarReadoutHorizontalOffset = 
+    _boxBound[0] + 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float scalarReadoutVerticalOffset = 
+    (_frustum[3] - _boxBound[3]) +
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) *
+    ((float) textHeight + (float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarReadoutHorizontalOffset, 
+                _frustum[3] - scalarReadoutVerticalOffset, 
+                0.0);
+
+  // Create text string
+  char scalarReadoutString[128];
+
+  // If a valid control point has the focus
+  if (_focusPoint >= 0 && _focusPoint < _numberOfControlPoints) {
+    
+    // Function coordinates
+    float s = 0.0;
+    float o = 0.0;
+
+    // Get control point
+    GetControlPoint(_focusPoint, &s, &o);
+
+    // Fill text string
+    sprintf(scalarReadoutString, "%s %.4f", "S:", s);
+
+  }
+
+  // If no point has focus
+  else {
+
+    // Fill text string
+    sprintf(scalarReadoutString, "%s", "S:");
+
+  }
+
+  // Display text
+  for (int i = 0 ; i < strlen(scalarReadoutString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarReadoutString[i]);
+  }
+  */
+
+
+  /*
+  // Control point opacity readout
+
+  // Calculate offsets for text
+  float opacityReadoutHorizontalOffset = 
+    _boxBound[0] + 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float opacityReadoutVerticalOffset = 
+    scalarReadoutVerticalOffset +
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) *
+    ((float) textHeight + (float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + opacityReadoutHorizontalOffset, 
+                _frustum[3] - opacityReadoutVerticalOffset, 
+                0.0);
+
+  // Create text string
+  char opacityReadoutString[128];
+
+  // If a valid control point has the focus
+  if (_focusPoint >= 0 && _focusPoint < _numberOfControlPoints) {
+    
+    // Function coordinates
+    float s = 0.0;
+    float o = 0.0;
+
+    // Get control point
+    GetControlPoint(_focusPoint, &s, &o);
+
+    // Fill text string
+    sprintf(opacityReadoutString, "%s %.4f", "O:", o);
+
+  }
+
+  // If no point has focus
+  else {
+
+    // Fill text string
+    sprintf(opacityReadoutString, "%s", "O:");
+
+  }
+
+  // Display text
+  for (int i = 0 ; i < strlen(opacityReadoutString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, opacityReadoutString[i]);
+  }
+  */
+
+
+  // Box color
+  glColor4f(_boxColor[0], _boxColor[1], _boxColor[2], _boxColor[3]);
+
+  // Draw box
+  glLoadIdentity();
+  glBegin(GL_LINES);
+  glVertex3f(_boxBound[0], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[3], 0.0);
+  glEnd();
+
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+  float opacity = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+    
+
+  // Line color
+  glColor4f(_lineColor[0], _lineColor[1], _lineColor[2], _lineColor[3]);
+
+  // Draw lines connecting control points
+  glBegin(GL_LINE_STRIP);
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    scalar = _controlPoint[i].GetScalar();
+    opacity = _controlPoint[i].GetOpacity();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar, opacity) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, opacity, &bx, &by);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(bx, by) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(bx, by, &wx, &wy);
+
+        // Next point in line strip
+        glVertex3f(wx, wy, 0.0);
+
+      }
+
+    }
+
+  }
+  glEnd();
+
+
+  // Draw each control point
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    scalar = _controlPoint[i].GetScalar();
+    opacity = _controlPoint[i].GetOpacity();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar, opacity) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, opacity, &bx, &by);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(bx, by) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(bx, by, &wx, &wy);
+
+        // Draw focus point
+        if (i == _focusPoint) {
+
+          // Draw bigger outline point
+          glPointSize(_controlPointSize * 2.0);
+          glColor4f(_focusPointColor[0], _focusPointColor[1],
+                    _focusPointColor[2], _focusPointColor[3]); 
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+
+          // Draw regular point inside
+          glPointSize((float) _controlPointSize);
+          glColor4f(_controlPointColor[0], _controlPointColor[1], 
+                    _controlPointColor[2], _controlPointColor[3]);
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+
+          // Draw even smaller point
+          glPointSize((float) _controlPointSize / 4.0);
+          glColor4f(_focusPointColor[0], _focusPointColor[1],
+                    _focusPointColor[2], _focusPointColor[3]); 
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+        }
+
+        // Draw single control point
+        else {
+          glPointSize(_controlPointSize);
+          glColor4f(_controlPointColor[0], _controlPointColor[1], 
+                    _controlPointColor[2], _controlPointColor[3]);
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+        }
+
+      }
+
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::FunctionToBox(float scalar, float opacity,
+                                                  float* bx, float* by) {
+
+  // Convert from function coordinates to box coordinates
+  *bx = (scalar - _scalarMinimum) / (_scalarMaximum - _scalarMinimum);
+  *by = (opacity - _opacityMinimum) / (_opacityMaximum - _opacityMinimum);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::GetControlPoint(int index, 
+                                                    float* scalar, 
+                                                    float* opacity) {
+
+  // Get control point
+  *scalar = _controlPoint[index].GetScalar();
+  *opacity = _controlPoint[index].GetOpacity();
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OpacityTransferFunctionWidget::GetControlPointIndex(int px, int py) {
+
+  // Control point box coordinates
+  float cbx = 0.0;
+  float cby = 0.0;
+
+  // Control point world coordinates
+  float cwx = 0.0;
+  float cwy = 0.0;
+
+  // Pixel world coordinates
+  float pwx = 0.0;
+  float pwy = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+  float opacity = 0.0;
+
+  // Distances
+  vector <float> distance;
+
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == false) {
+    return -1;
+  }
+
+  // Get corresponding world coordinates
+  PixelToWorld(px, py, &pwx, &pwy);
+
+  // Check that world coordinates are within box space
+  if (IsWorldInBox(pwx, pwy) == false) {
+    return -1;
+  }
+
+  // Check for control points
+  if (_numberOfControlPoints < 1) {
+    return -1;
+  }
+
+  
+  // Calculate distance to each control point
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    opacity = _controlPoint[i].GetOpacity();
+    scalar = _controlPoint[i].GetScalar();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar, opacity) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, opacity, &cbx, &cby);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(cbx, cby) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(cbx, cby, &cwx, &cwy);
+
+        // Calculate distance and correct for aspect ratio
+        float dX = pwx - cwx;
+        float dY = (pwy - cwy) / (_pixelDimensions[0] / _pixelDimensions[1]);
+        float d = sqrt(dX*dX + dY*dY);
+
+        // Add distance
+        distance.push_back(d);
+
+      }
+
+    }
+
+  }
+
+
+  // Size of control point in world coordinates
+  float ctrlPtSizeX = 0.0;
+  float ctrlPtSizeY = 0.0;
+
+  // Calculate size of a control point in world coordinates
+  PixelToWorld(_controlPointSize / 2, 
+               _pixelDimensions[1] - (_controlPointSize / 2), 
+               &ctrlPtSizeX, 
+               &ctrlPtSizeY);
+
+
+  // Minimum distance
+  float minimum = distance[0];
+
+  // Index of control point closest to pixel coordinates
+  int index = 0;
+
+  // Find minimum distance
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+    if (distance[i] < minimum) {
+      minimum = distance[i];
+      index = i;
+    }
+  }
+
+
+  // Get control point values for closest point
+  opacity = _controlPoint[index].GetOpacity();
+  scalar = _controlPoint[index].GetScalar();
+
+  // Check that function coordinates are within box space
+  if (IsFunctionInBox(scalar, opacity) == true) {
+
+    // Get corresponding box coordinates
+    FunctionToBox(scalar, opacity, &cbx, &cby);
+
+    // Check that box coordinates are within world space
+    if (IsBoxInWorld(cbx, cby) == true) {
+
+      // Get corresponding world coordinates
+      BoxToWorld(cbx, cby, &cwx, &cwy);
+
+      // Return control point index and set focus point if it's picked
+      if (pwx >= cwx - ctrlPtSizeX && pwx <= cwx + ctrlPtSizeX &&
+          pwy >= cwy - ctrlPtSizeY && pwy <= cwy + ctrlPtSizeY) {
+        _focusPoint = index;
+        return index;
+      }
+
+    }
+
+  }
+
+
+  // No control point picked
+  return -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OpacityTransferFunctionWidget::GetControlPointIndex(float scalar, 
+                                                        float opacity) {
+
+  // Check each control point for matching function coordinates
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+    if (_controlPoint[i].GetScalar() == scalar &&
+        _controlPoint[i].GetOpacity() == opacity) {
+      return i;
+    }
+  }
+
+  // No control point picked
+  return -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::GetFunctionCoordinates(int px, int py, 
+                                                           float* scalar, 
+                                                           float* opacity) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, scalar, opacity);
+
+      // Control point added
+      return true;
+
+    }
+
+  }
+
+  // Not within bounds
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int OpacityTransferFunctionWidget::GetNumberOfControlPoints() {
+
+  // Return number of control points
+  return _numberOfControlPoints;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float OpacityTransferFunctionWidget::GetOpacity(float scalar) {
+
+  // Check minimum bound
+  if (scalar < _controlPoint[0].GetScalar()) {
+    return _controlPoint[0].GetOpacity();
+  }
+
+  // Check maximum bound
+  if (scalar > _controlPoint[_numberOfControlPoints - 1].GetScalar()) {
+    return _controlPoint[_numberOfControlPoints - 1].GetOpacity();
+  }
+
+  // Control points that border scalar value
+  int left = 0;
+  int right = 0;
+      
+  // Find control points that border scalar value
+  for (int i = 1 ; i < _numberOfControlPoints ; i++) {
+    if (scalar < _controlPoint[i].GetScalar()) {
+      right = i;
+      break;
+    }
+    left = i;
+  }
+
+  // Function coordinates of control points
+  float xl = _controlPoint[left].GetScalar();
+  float xr = _controlPoint[right].GetScalar();
+  float yl = _controlPoint[left].GetOpacity();
+  float yr = _controlPoint[right].GetOpacity();
+
+  // Interpolate between bordering control points
+  float opacity = yl + (((scalar - xl) / (xr - xl)) * (yr - yl));
+  
+  // Return opacity
+  return opacity;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::GetOpacityRange(float* min, float* max) {
+
+  // Set opacity range
+  *min = _opacityMinimum;
+  *max = _opacityMaximum;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::GetScalarRange(float* min, float* max) {
+
+  // Set scalar range
+  *min = _scalarMinimum;
+  *max = _scalarMaximum;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::IsBoxInWorld(float bx, float by) {
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Calculate world coordinates
+  BoxToWorld(bx, by, &wx, &wy);
+
+  // Check if box coordinates are in world space
+  if (wx >= _frustum[0] && wx <= _frustum[1] &&
+      wy >= _frustum[2] && wy <= _frustum[3]) {
+    return true;
+  }
+
+  // Not in world space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::IsFunctionInBox(float scalar, 
+                                                    float opacity) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Calculate box coordinates
+  FunctionToBox(scalar, opacity, &bx, &by);
+
+  // Check if function coordinates are in box space
+  if (bx >= 0.0 && bx <= 1.0 && 
+      by >= 0.0 && by <= 1.0) {
+    return true;
+  }
+
+  // Not in box space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::IsPixelInWorld(int px, int py) {
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Calculate world coordinates
+  PixelToWorld(px, py, &wx, &wy);
+
+  // Check if pixel coordinates are in world space
+  if (wx >= _frustum[0] && wx <= _frustum[1] &&
+      wy >= _frustum[2] && wy <= _frustum[3]) {
+    return true;
+  }
+
+  // Not in world space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::IsWorldInBox(float wx, float wy) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Calculate box coordinates
+  WorldToBox(wx, wy, &bx, &by);
+
+  // Check if world coordinates are in box space
+  if (bx >= 0.0 && bx <= 1.0 &&
+      by >= 0.0 && by <= 1.0) {
+    return true;
+  }
+
+  // Not in box space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::MoveControlPoint(int index, 
+                                                     int px, 
+                                                     int py) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+  float opacity = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, &scalar, &opacity);
+
+      // Check that control point picked is not an edge point and is valid
+      if (index > 0 && index < _numberOfControlPoints - 1) {
+
+        // Check that new scalar is not past next point
+        if (scalar >= _controlPoint[index + 1].GetScalar()) {
+          float s = _controlPoint[index + 1].GetScalar() - 0.0001;
+          _controlPoint[index].SetScalar(s);
+        }
+
+        // Check that new scalar is not before previous point
+        else if (scalar <= _controlPoint[index - 1].GetScalar()) {
+          float s = _controlPoint[index - 1].GetScalar() + 0.0001;
+          _controlPoint[index].SetScalar(s);
+        }
+
+        // Check that new scalar is not greater than maximum scalar value
+        else if (scalar > _scalarMaximum) {
+          _controlPoint[index].SetScalar(_scalarMaximum);
+        }
+
+        // Check that new scalar is not less than minimum scalar value
+        else if (scalar < _scalarMinimum) {
+          _controlPoint[index].SetScalar(_scalarMinimum);
+        }
+
+        // New scalar value is valid
+        else {
+          _controlPoint[index].SetScalar(scalar);
+        }
+
+      }
+      
+      // Check that control point picked is valid
+      if (index >= 0 && index <= _numberOfControlPoints - 1) {
+
+        // Check that new opacity is not greater than maximum opacity value
+        if (opacity > _opacityMaximum) {
+          _controlPoint[index].SetOpacity(_opacityMaximum);
+        }
+
+        // Check that new opacity is not less than minimum opacity value
+        else if (opacity < _opacityMinimum) {
+          _controlPoint[index].SetOpacity(_opacityMinimum);
+        }
+        
+        // New opacity value is valid
+        else {
+          _controlPoint[index].SetOpacity(opacity);
+        }
+
+      }
+
+      // Control point moved
+      return true;
+
+    }
+
+  }
+
+  // Can't move control point to desired position
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::MoveControlPoint(int index, float scalar,
+                                                     float opacity) {
+
+  // Check that control point picked is not an edge point and is valid
+  if (index > 0 && index < _numberOfControlPoints - 1) {
+
+    // Check that new scalar is not past next point
+    if (scalar >= _controlPoint[index + 1].GetScalar()) {
+      float s = _controlPoint[index + 1].GetScalar() - 0.0001;
+      _controlPoint[index].SetScalar(s);
+    }
+
+    // Check that new scalar is not before previous point
+    else if (scalar <= _controlPoint[index - 1].GetScalar()) {
+      float s = _controlPoint[index - 1].GetScalar() + 0.0001;
+      _controlPoint[index].SetScalar(s);
+    }
+
+    // Check that new scalar is not greater than maximum scalar value
+    else if (scalar > _scalarMaximum) {
+      _controlPoint[index].SetScalar(_scalarMaximum);
+    }
+
+    // Check that new scalar is not less than minimum scalar value
+    else if (scalar < _scalarMinimum) {
+      _controlPoint[index].SetScalar(_scalarMinimum);
+    }
+
+    // New scalar value is valid
+    else {
+      _controlPoint[index].SetScalar(scalar);
+    }
+
+  }
+
+  // Check that control point is valid
+  if (index >= 0 && index <= _numberOfControlPoints - 1) {
+
+    // Check that new opacity is not greater than maximum opacity value
+    if (opacity > _opacityMaximum) {
+      _controlPoint[index].SetOpacity(_opacityMaximum);
+    }
+
+    // Check that new opacity is not less than minimum opacity value
+    else if (opacity < _opacityMinimum) {
+      _controlPoint[index].SetOpacity(_opacityMinimum);
+    }
+
+    // New opacity value is valid
+    else {
+      _controlPoint[index].SetOpacity(opacity);
+    }
+
+  }
+
+  // Control point moved
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::PixelToWorld(int px, int py, 
+                                                 float* wx, float* wy) {
+
+  // Flip y coordinate
+  py = _pixelDimensions[1] - py;
+
+  // Convert from pixel coordinates to world coordinates
+  *wx = _frustum[0] + 
+    (((float) px / (float) _pixelDimensions[0]) * (_frustum[1] - _frustum[0]));
+  *wy = _frustum[2] + 
+    (((float) py / (float) _pixelDimensions[1]) * (_frustum[3] - _frustum[2]));
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::RestoreControlPoints(int number,
+                                                         float max,
+                                                         float* scalar, 
+                                                         float* opacity) {
+
+  // Temporary control point
+  ControlPoint tmp;
+
+  // Set number of control points
+  _numberOfControlPoints = number;
+
+  // Set maximum scalar value
+  _scalarMaximum = max;
+
+  // Clear all control points
+  _controlPoint.clear();
+
+  // Set each control point from arrays
+  for (int i = 0 ; i < number ; i++) {
+    tmp.SetScalar(scalar[i]);
+    tmp.SetOpacity(opacity[i]);
+    _controlPoint.push_back(tmp);
+  }
+
+  // Set focus point
+  _focusPoint = -1;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool OpacityTransferFunctionWidget::RemoveControlPoint(int index) {
+
+  // Check that index is within bounds and set focus point
+  if (index < 1 || index >= _numberOfControlPoints - 1) {
+    _focusPoint = index;
+    return false;
+  }
+
+  // Remove control point
+  _controlPoint.erase(_controlPoint.begin() + index);
+
+  // Decrement number of control points
+  _numberOfControlPoints--;
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Success
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetBackgroundColor(float r, float g, 
+                                                       float b, float a) {
+
+  // Set background color
+  _backgroundColor[0] = r;
+  _backgroundColor[1] = g;
+  _backgroundColor[2] = b;
+  _backgroundColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetBoxColor(float r, float g, 
+                                                float b, float a) {
+
+  // Set box color
+  _boxColor[0] = r;
+  _boxColor[1] = g;
+  _boxColor[2] = b;
+  _boxColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetControlPointColor(float r, float g,
+                                                         float b, float a) {
+
+  // Set control point color
+  _controlPointColor[0] = r;
+  _controlPointColor[1] = g;
+  _controlPointColor[2] = b;
+  _controlPointColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetControlPointSize(int size) {
+
+  // Set control point size
+  _controlPointSize = size;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetDimensions(int w, int h) {
+
+  // Set dimensions
+  _pixelDimensions[0] = w;
+  _pixelDimensions[1] = h;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetFocusPointColor(float r, float g, 
+                                                       float b, float a) {
+
+  // Set focus point color
+  _focusPointColor[0] = r;
+  _focusPointColor[1] = g;
+  _focusPointColor[2] = b;
+  _focusPointColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetLineColor(float r, float g, 
+                                                 float b, float a) {
+
+  // Set line color
+  _lineColor[0] = r;
+  _lineColor[1] = g;
+  _lineColor[2] = b;
+  _lineColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetMaximumScalar(float max) {
+
+  // New scalar values
+  float newMax = max;
+  float newMin = _scalarMinimum;
+
+  // Old scalar values
+  float oldMax = _scalarMaximum;
+  float oldMin = _scalarMinimum;
+
+  // Resample each control point's scalar value
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get old scalar value
+    float oldScalar = _controlPoint[i].GetScalar();
+
+    // Normalize old scalar value
+    float normal = (oldScalar - oldMin) / (oldMax - oldMin);
+
+    // Resample old scalar value to new bounds
+    float newScalar = ((newMax - newMin) * normal) + newMin;
+
+    // Set new scalar value
+    _controlPoint[i].SetScalar(newScalar);
+
+  }
+
+  // Set maximum scalar
+  _scalarMaximum = max;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::SetTextColor(float r, float g, 
+                                                 float b, float a) {
+
+  // Set text color
+  _textColor[0] = r;
+  _textColor[1] = g;
+  _textColor[2] = b;
+  _textColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void OpacityTransferFunctionWidget::WorldToBox(float wx, float wy, 
+                                               float* bx, float* by) {
+
+  // Convert from world coordinates to box coordinates
+  *bx = (wx - _boxBound[0]) / (_boxBound[1] - _boxBound[0]);
+  *by = (wy - _boxBound[2]) / (_boxBound[3] - _boxBound[2]);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CommunicatorConcreteCommand.h	(revision 4)
@@ -0,0 +1,125 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef COMMUNICATOR_CONCRETE_COMMAND_H
+#define COMMUNICATOR_CONCRETE_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+
+#include "CommunicatorAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+class CommunicatorConcreteCommand : public CommunicatorAbstractCommand {
+  
+public:
+
+  // Constructor
+  CommunicatorConcreteCommand();
+
+  // Constructor with pointer to instance of class Slave
+  CommunicatorConcreteCommand(void* slave);
+
+  // Destructor
+  virtual ~CommunicatorConcreteCommand();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set render flag
+  virtual void SetCommandRender();
+
+  // Set data set filename
+  virtual void SetData(char* filename);
+
+  // Set data set filename and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set display size
+  virtual void SetDisplaySize(int width, int height, bool fullScreen,
+                              char* hostname, int port,
+                              float left, float right,
+                              float bottom, float top);
+
+  // Set frustum
+  virtual void SetFrustum(float left, float right,
+                          float bottom, float top);
+
+  // Set 8-bit transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set 16-bit transfer function
+  virtual void SetMap16(unsigned char* map);
+
+  // Set data set prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float matrix[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float matrix[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float matrix[16]);
+
+  // Set viewport
+  virtual void SetViewport(int x, int y, int w, int h);
+
+private:
+
+  // Pointer to instance of class slave
+  void* _slave;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Load_Data.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Load_Data.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Load_Data.cpp	(revision 4)
@@ -0,0 +1,94 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Load_Data.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Load_Data::Fl_Load_Data(int x, int y, int w, int h, const char *l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Resize to the correct size
+  size(220, 305);
+
+  // Set modal
+  //set_modal();
+
+  // Create data browser
+  _dataBrowser = new Fl_Hold_Browser(10, 10, 200, 250);
+
+  // Create ok button
+  _okButton = new Fl_Return_Button(10, 270, 95, 25, "OK");
+
+  // Create cancel button
+  _cancelButton = new Fl_Button(115, 270, 95, 25, "Cancel");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Load_Data::~Fl_Load_Data() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Load_Data::Add(const char* entry) {
+
+  // Add entry to browser
+  _dataBrowser -> add(entry);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Load_Data::Clear() {
+
+  // Clear all entries in browser
+  _dataBrowser -> clear();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Load_Data::GetSelected() {
+
+  // Return selected line
+  return _dataBrowser -> value();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Load_Data::SetOKButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _okButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Load_Data::SetCancelButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _cancelButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/ControlPoint.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/ControlPoint.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/ControlPoint.cpp	(revision 4)
@@ -0,0 +1,178 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "ControlPoint.h"
+
+/*--------------------------------------------------------------------------*/
+
+ControlPoint::ControlPoint() {
+
+  // Initialize opacity
+  _opacity = 0.0;
+
+  // Initialize color
+  _rgb[0] = 0.0;
+  _rgb[1] = 0.0;
+  _rgb[2] = 0.0;
+
+  // Initialize scalar
+  _scalar = 0.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+ControlPoint::ControlPoint(const ControlPoint &copyin) {
+
+  // Copy opacity
+  _opacity = copyin._opacity;
+
+  // Copy color
+  _rgb[0] = copyin._rgb[0];
+  _rgb[1] = copyin._rgb[1];
+  _rgb[2] = copyin._rgb[2];
+
+  // Copy scalar
+  _scalar = copyin._scalar;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+ControlPoint::~ControlPoint() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+ControlPoint& ControlPoint::operator=(const ControlPoint &rhs) {
+
+  // Assign opacity
+  this -> _opacity = rhs._opacity;
+
+  // Assign color
+  this -> _rgb[0] = rhs._rgb[0];
+  this -> _rgb[1] = rhs._rgb[1];
+  this -> _rgb[2] = rhs._rgb[2];
+
+  // Assign scalar
+  this -> _scalar = rhs._scalar;
+
+  // Return pointer to this
+  return *this;
+
+}
+
+/*--------------------------------------------------------------------------*/
+  
+int ControlPoint::operator==(const ControlPoint &rhs) const {
+
+  // Compare opacity members
+  if (this -> _opacity != rhs._opacity) {
+    return 0;
+  }
+
+  // Compare color members
+  if (this -> _rgb[0] != rhs._rgb[0] ||
+      this -> _rgb[1] != rhs._rgb[1] ||
+      this -> _rgb[2] != rhs._rgb[2]) {
+    return 0;
+  }
+
+  // Compare scalar members
+  if (this -> _scalar != rhs._scalar) {
+    return 0;
+  }
+
+  // Equality
+  return 1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int ControlPoint::operator<(const ControlPoint &rhs) const {
+
+  // Compare scalar values
+  if (this -> _scalar < rhs._scalar) {
+    return 1;
+  }
+
+  // Not less than
+  return 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float ControlPoint::GetOpacity() {
+
+  // Return opacity
+  return _opacity;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ControlPoint::GetRGB(float* r, float* g, float* b) {
+
+  // Get color
+  *r = _rgb[0];
+  *g = _rgb[1];
+  *b = _rgb[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float ControlPoint::GetScalar() {
+
+  // Return scalar
+  return _scalar;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ControlPoint::SetOpacity(float opacity) {
+
+  // Set opacity
+  _opacity = opacity;
+
+}
+/*--------------------------------------------------------------------------*/
+
+void ControlPoint::SetRGB(float r, float g, float b) {
+
+  // Set color
+  _rgb[0] = r;
+  _rgb[1] = g;
+  _rgb[2] = b;
+
+}
+
+/*--------------------------------------------------------------------------*/
+ 
+void ControlPoint::SetScalar(float scalar) {
+
+  // Set scalar
+  _scalar = scalar;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServer.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServer.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServer.h	(revision 4)
@@ -0,0 +1,126 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_SERVER_H
+#define USER_INTERFACE_SERVER_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "DataPacker.h"
+#include "UserInterfaceServerAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define USER_INTERFACE_SERVER_ERROR -1
+#define USER_INTERFACE_SERVER_OK 0
+#define USER_INTERFACE_SERVER_REPLY 1
+#define USER_INTERFACE_SERVER_NO_DATA 2
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceServer {
+
+public:
+
+  // Default constructor
+  UserInterfaceServer();
+
+  // Default destructor
+  ~UserInterfaceServer();
+
+  // Accept connection
+  int Accept();
+
+  // Process a command from the client
+  int GetCommand();
+
+  // Initialize server
+  void Init(int port);
+
+  // Is initialized
+  bool IsInit();
+
+  // Send exit command
+  void SendCommandExit();
+
+  // Send progress update
+  void SendProgress(int value, int total);
+
+  // Send rotation matrix
+  void SendRotationMatrix(float m[16]);
+
+  // Send scale matrix
+  void SendScaleMatrix(float m[16]);
+
+  // Send translation matrix
+  void SendTranslationMatrix(float m[16]);
+
+  // Set observer
+  void SetObserver(UserInterfaceServerAbstractCommand* observer);
+
+  // Shutdwon server
+  void Shutdown();
+
+private:
+
+  // Client address
+  struct sockaddr_in _clientAddress;
+
+  // Client socket file descriptor
+  int _clientSocketFileDescriptor;
+
+  // Is connected to client flag
+  bool _isConnected;
+
+  // Is initialized flag
+  bool _isInitialized;
+
+  // Observer
+  UserInterfaceServerAbstractCommand* _observer;
+
+  // Server port number
+  int _port;
+
+  // Server
+  struct hostent* _server;
+
+  // Server address
+  struct sockaddr_in _serverAddress;
+
+  // Server socket file descriptor
+  int _serverSocketFileDescriptor;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Main_Window.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Main_Window.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Main_Window.cpp	(revision 4)
@@ -0,0 +1,116 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Main_Window.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Main_Window::Fl_Main_Window(int x, int y, int w, int h, const char *l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Create menu bar
+  _menuBar = new Fl_Menu_Bar(0, 0, 640, 30);
+
+  // Create menu items
+  Fl_Menu_Item menuitems[] = {
+    {"&File",          0, 0, 0, FL_SUBMENU},
+    {"&Connect to Server...",      FL_CTRL + 'c', NULL},
+    {"&Disconnect from Server",    FL_CTRL + 'd', NULL, 0, FL_MENU_DIVIDER},
+    {"&Shutdown Server",           FL_CTRL + 's', NULL, 0, FL_MENU_DIVIDER},
+    {"&Load Data...",              FL_CTRL + 'l', NULL, 0, FL_MENU_DIVIDER},
+    {"L&oad Script...",            FL_CTRL + 'o', NULL, 0, FL_MENU_DIVIDER},
+    {"E&xit",                      FL_CTRL + 'q', NULL, 0},
+    {0},
+    {0}
+  };
+
+  // Add menu items to menu bar
+  _menuBar -> copy(menuitems);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Main_Window::~Fl_Main_Window() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::ActivateConnect() {
+
+  // Deactivate
+  _menuBar -> mode(1, 0);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::ActivateDisconnect() {
+
+  // Deactivate
+  _menuBar -> mode(2, 0);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::ActivateShutdown() {
+
+  // Deactivate
+  _menuBar -> mode(3, 0|0x80);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::DeactivateConnect() {
+
+  // Deactivate
+  _menuBar -> mode(1, 1);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::DeactivateDisconnect() {
+
+  // Deactivate
+  _menuBar -> mode(2, 1);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::DeactivateShutdown() {
+
+  // Deactivate
+  _menuBar -> mode(3, 1|0x80);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Main_Window::SetMenuItems(Fl_Menu_Item* items) {
+
+  // Copy menu items
+  _menuBar -> copy(items);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerClient.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerClient.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerClient.cpp	(revision 4)
@@ -0,0 +1,243 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "SynchronizerClient.h"
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerClient::SynchronizerClient() {
+
+  // Initialize is initialized flag
+  _isInitialized = false;
+  
+  // Initialize port number
+  _port = 0;
+
+  // Initialize server
+  _server = NULL;
+
+  // Reset socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerClient::~SynchronizerClient() {
+
+  // If socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("SynchronizerClient: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("SynchronizerClient: Error during socket close");
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerClient::Barrier() {
+
+  // Check is user called Init
+  IsInitialized();
+
+  // Message buffer
+  char buffer[256];
+
+  // Message length
+  int messageLength = 0;
+
+  // Initialize buffer
+  memset(buffer, 0, 256);
+
+  // Create message
+  sprintf(buffer, "MSG_BARRIER 0");
+
+  // Send message
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            255, 
+                            0)) != 255) {
+    perror("SynchronizerClient: Error sending barrier message");
+  }
+
+  // Wait for return message
+  if ((messageLength = recv(_serverSocketFileDescriptor, 
+                            buffer, 
+                            255, 
+                            MSG_WAITALL)) != 255) {
+    perror("SynchronizerClient: Error receiving barrier message");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerClient::Barrier(int level) {
+
+  // Check is user called Init
+  IsInitialized();                                                             
+
+  // Message buffer
+  char buffer[256];                                                            
+
+  // Message length                                                         
+  int messageLength = 0;
+
+  // Initialize buffer
+  memset(buffer, 0, 256);
+
+  // Create message
+  sprintf(buffer, "MSG_BARRIER %d", level);
+
+  // Send message
+  if ((messageLength = send(_serverSocketFileDescriptor,
+                            buffer,
+                            255,
+                            0)) != 255) {                
+    perror("SynchronizerClient: Error sending barrier message");
+  }
+                                                    
+  // Wait for return message
+  if ((messageLength = recv(_serverSocketFileDescriptor,
+                            buffer,
+                            255,                             
+                            MSG_WAITALL)) != 255) {              
+    perror("SynchronizerClient: Error receiving barrier message");
+  }                    
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerClient::Finalize() {
+
+  // Check is user called Init
+  IsInitialized();
+
+  // Message buffer
+  char buffer[256];
+
+  // Message length
+  int messageLength = 0;
+
+  // Initialize buffer
+  memset(buffer, 0, 256);
+
+  // Create message
+  sprintf(buffer, "MSG_FINALIZE 0");
+
+  // Send message
+  if ((messageLength = send(_serverSocketFileDescriptor, 
+                            buffer, 
+                            255, 
+                            0)) != 255) {
+    perror("SynchronizerClient: Error sending finalize message");
+  }
+
+  // Wait for return message
+  if ((messageLength = recv(_serverSocketFileDescriptor, 
+                            buffer, 
+                            255, 
+                            MSG_WAITALL)) != 255) {
+    perror("SynchronizerClient: Error receiving finalize message");
+  }
+
+  // Shutdown socket
+  if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+    perror("SynchronizerClient: Error during socket shutdown");
+  }
+
+  // Close socket
+  if (close(_serverSocketFileDescriptor) == -1) {
+    perror("SynchronizerClient: Error during socket close");
+  }
+
+  // Reset socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+  // Set is initialized flag to false
+  _isInitialized = false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerClient::Init(char* hostname, int port) {
+
+  // Assign server port number
+  _port = port;
+
+  // Create server socket
+  if ((_serverSocketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+    perror("SynchronizerClient: Error creating socket");
+    return;
+  }
+
+  // Get host by name
+  if ((_server = gethostbyname(hostname)) == NULL) {
+    herror("SynchronizerClient: Error resolving hostname");
+    close(_serverSocketFileDescriptor);
+    return;
+  }
+
+  // Initialize server address
+  memset(&_serverAddress, 0, sizeof(_serverAddress));
+  _serverAddress.sin_family = AF_INET;
+  bcopy((char*) _server -> h_addr,
+        (char*) &_serverAddress.sin_addr.s_addr,
+        _server -> h_length);
+  _serverAddress.sin_port = htons(_port);
+
+  // Connect to server
+  if (connect(_serverSocketFileDescriptor, 
+              (struct sockaddr*) &_serverAddress, 
+              sizeof(_serverAddress)) != 0) {
+    perror("SynchronizerClient: Error connecting to server");
+    close(_serverSocketFileDescriptor);
+    return;
+  }
+
+  // Set is initialized flag
+  _isInitialized = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool SynchronizerClient::IsInitialized() {
+
+  if (_isInitialized == false) {
+    fprintf(stderr, 
+            "SynchronizerClient: Call Init before any other method\n");
+  }
+
+  return _isInitialized;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Makefile
===================================================================
--- trunk/src/testing/app/VRA/src/Makefile	(revision 4)
+++ trunk/src/testing/app/VRA/src/Makefile	(revision 4)
@@ -0,0 +1,392 @@
+##############################################################################
+# Volume Rendering Application
+# Copyright (C) 2006-2007 Nicholas Schwarz
+#
+# This software is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either Version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License along
+# with this library; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+
+MPI_FLAGS = -I/opt/mpich/ch-p4/include
+MPI_LIBS = -L/opt/mpich/ch-p4/lib64 -lmpich
+
+SDL_FLAGS = `sdl-config --cflags`
+SDL_LIBS = `sdl-config --libs`
+
+SAGE_CFLAGS = -I./../../../include
+SAGE_LIBS = -L./../../../lib -lsail
+
+CXX_FLAGS = $(MPI_FLAGS) $(SDL_FLAGS) -Wno-deprecated $(SAGE_CFLAGS) -D SAGE
+CXX_LIBS = $(MPI_LIBS) $(SDL_LIBS) -lGL -lCg -lCgGL -lglut $(SAGE_LIBS)
+
+CXX_FLAGS_CO = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+CXX_FLAGS_UI = `fltk-config --cxxflags --use-gl` -Wno-deprecated -D SAGE
+CXX_LIBS_UI = -lGL -L/usr/lib64 -lglut `fltk-config --ldflags --use-gl` -lpthread
+
+CXX = g++
+
+default: VRA VRA_UI ScriptGenerator
+
+VRA: main.o                               \
+     CacheRAM.o                           \
+     CacheRAMNode.o                       \
+     CacheVRAM.o                          \
+     CacheVRAMNode.o                      \
+     Communicator.o                       \
+     CommunicatorAbstractCommand.o        \
+     CommunicatorConcreteCommand.o        \
+     DataPacker.o                         \
+     FrustumCalculator.o                  \
+     FrustumPlanes.o                      \
+     Log.o                                \
+     Master.o                             \
+     Matrix.o                             \
+     Octree.o                             \
+     OctreeNode.o                         \
+     OctreeNodeQueue.o                    \
+     Slave.o                              \
+     SynchronizerClient.o                 \
+     SynchronizerServer.o                 \
+     SynchronizerServerAbstractCommand.o  \
+     SynchronizerServerConcreteCommand.o  \
+     SynchronizerServerClientThreadInfo.o \
+     SynchronizerServerListenThreadInfo.o \
+     Trackball.o                          \
+     UserInterfaceServer.o                \
+     UserInterfaceServerAbstractCommand.o \
+     UserInterfaceServerConcreteCommand.o \
+     Vertex.o                             \
+     VolumeRenderer.o                     \
+     VolumeRendererCommand.o              \
+     VolumeRendererShell.o                \
+     VolumeRendererThreadInfo.o           \
+     Makefile
+	$(CXX) $(CXX_FLAGS) -o VRA main.o                               \
+                                   CacheRAM.o                           \
+                                   CacheRAMNode.o                       \
+                                   CacheVRAM.o                          \
+                                   CacheVRAMNode.o                      \
+                                   Communicator.o                       \
+                                   CommunicatorAbstractCommand.o        \
+                                   CommunicatorConcreteCommand.o        \
+                                   DataPacker.o                         \
+                                   FrustumCalculator.o                  \
+                                   FrustumPlanes.o                      \
+                                   Log.o                                \
+                                   Master.o                             \
+                                   Matrix.o                             \
+                                   Octree.o                             \
+                                   OctreeNode.o                         \
+                                   OctreeNodeQueue.o                    \
+                                   Slave.o                              \
+                                   SynchronizerClient.o                 \
+                                   SynchronizerServer.o                 \
+                                   SynchronizerServerAbstractCommand.o  \
+                                   SynchronizerServerConcreteCommand.o  \
+                                   SynchronizerServerClientThreadInfo.o \
+                                   SynchronizerServerListenThreadInfo.o \
+                                   Trackball.o                          \
+                                   UserInterfaceServer.o                \
+                                   UserInterfaceServerAbstractCommand.o \
+                                   UserInterfaceServerConcreteCommand.o \
+                                   Vertex.o                             \
+                                   VolumeRenderer.o                     \
+                                   VolumeRendererCommand.o              \
+                                   VolumeRendererShell.o                \
+                                   VolumeRendererThreadInfo.o           \
+                                   $(CXX_LIBS)
+	cp VRA ../bin
+	cp ../shaders/Fragment.cg ../bin
+
+VRA_UI: UI.o                                 \
+        ColorTransferFunctionWidget.o        \
+        ControlPoint.o                       \
+        DataPacker.o                         \
+        Fl_Color_Transfer_Function.o         \
+        Fl_Connect.o                         \
+        Fl_Dialog.o                          \
+	Fl_Lambda.o                          \
+        Fl_Load_Data.o                       \
+        Fl_Main_Window.o                     \
+        Fl_Opacity_Transfer_Function.o       \
+        Fl_Overview.o                        \
+        Fl_Slice_Frequency.o                 \
+        Fl_Transfer_Function.o               \
+        Matrix.o                             \
+        OpacityTransferFunctionWidget.o      \
+        Trackball.o                          \
+        UserInterfaceClient.o                \
+        UserInterfaceClientAbstractCommand.o \
+        UserInterfaceClientConcreteCommand.o \
+        Vertex.o                             \
+        Makefile
+	$(CXX) $(CXX_FLAGS_UI) -o VRA_UI UI.o                                 \
+                                         ColorTransferFunctionWidget.o        \
+                                         ControlPoint.o                       \
+                                         DataPacker.o                         \
+                                         Fl_Color_Transfer_Function.o         \
+                                         Fl_Connect.o                         \
+                                         Fl_Dialog.o                          \
+                                         Fl_Lambda.o                          \
+                                         Fl_Load_Data.o                       \
+                                         Fl_Main_Window.o                     \
+                                         Fl_Opacity_Transfer_Function.o       \
+                                         Fl_Overview.o                        \
+                                         Fl_Slice_Frequency.o                 \
+                                         Fl_Transfer_Function.o               \
+                                         Matrix.o                             \
+                                         OpacityTransferFunctionWidget.o      \
+                                         Trackball.o                          \
+                                         UserInterfaceClient.o                \
+                                         UserInterfaceClientAbstractCommand.o \
+                                         UserInterfaceClientConcreteCommand.o \
+                                         Vertex.o                             \
+                                         $(CXX_LIBS_UI)
+	cp VRA_UI ../bin
+
+ScriptGenerator: ScriptGenerator.o   \
+                 FrustumCalculator.o \
+                 Matrix.o            \
+                 Vertex.o            \
+                 Makefile
+	$(CXX) -o ScriptGenerator ScriptGenerator.o   \
+                                  FrustumCalculator.o \
+                                  Matrix.o            \
+                                  Vertex.o
+	cp ScriptGenerator ../bin
+
+main.o: main.cpp Communicator.h Master.h Slave.h SynchronizerServer.h
+	$(CXX) $(CXX_FLAGS) -c main.cpp
+
+CacheRAM.o: CacheRAM.cpp CacheRAM.h CacheRAMNode.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c CacheRAM.cpp
+
+CacheRAMNode.o: CacheRAMNode.cpp CacheRAMNode.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c CacheRAMNode.cpp
+
+CacheVRAM.o: CacheVRAM.cpp CacheVRAM.h CacheVRAMNode.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c CacheVRAM.cpp
+
+CacheVRAMNode.o: CacheVRAMNode.cpp CacheVRAMNode.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c CacheVRAMNode.cpp
+
+ColorTransferFunctionWidget.o: ColorTransferFunctionWidget.cpp \
+                               ColorTransferFunctionWidget.h
+	$(CXX) $(CXX_FLAGS_UI) -c ColorTransferFunctionWidget.cpp
+
+CommunicatorAbstractCommand.o: CommunicatorAbstractCommand.cpp \
+                               CommunicatorAbstractCommand.h	
+	$(CXX) $(CXX_FLAGS) -c CommunicatorAbstractCommand.cpp
+
+CommunicatorConcreteCommand.o: CommunicatorConcreteCommand.cpp \
+                               CommunicatorConcreteCommand.h   \
+                               CommunicatorAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c CommunicatorConcreteCommand.cpp
+
+Communicator.o: Communicator.cpp Communicator.h \
+                CommunicatorAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c Communicator.cpp
+
+ControlPoint.o: ControlPoint.cpp ControlPoint.h
+	$(CXX) -c ControlPoint.cpp
+
+DataPacker.o: DataPacker.cpp DataPacker.h
+	$(CXX) -c DataPacker.cpp
+
+Fl_Color_Transfer_Function.o: Fl_Color_Transfer_Function.cpp \
+                              Fl_Color_Transfer_Function.h   \
+                              ColorTransferFunctionWidget.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Color_Transfer_Function.cpp
+
+Fl_Connect.o: Fl_Connect.cpp Fl_Connect.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Connect.cpp
+
+Fl_Dialog.o: Fl_Dialog.cpp Fl_Dialog.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Dialog.cpp
+
+Fl_Lambda.o: Fl_Lambda.cpp Fl_Lambda.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Lambda.cpp
+
+Fl_Load_Data.o: Fl_Load_Data.cpp Fl_Load_Data.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Load_Data.cpp
+
+Fl_Main_Window.o: Fl_Main_Window.cpp Fl_Main_Window.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Main_Window.cpp
+
+Fl_Opacity_Transfer_Function.o: Fl_Opacity_Transfer_Function.cpp \
+                                Fl_Opacity_Transfer_Function.h   \
+                                OpacityTransferFunctionWidget.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Opacity_Transfer_Function.cpp
+
+Fl_Overview.o: Fl_Overview.cpp Fl_Overview.h Matrix.h Trackball.h Vertex.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Overview.cpp
+
+Fl_Transfer_Function.o: Fl_Transfer_Function.cpp Fl_Transfer_Function.h \
+                        Fl_Color_Transfer_Function.h                    \
+                        Fl_Opacity_Transfer_Function.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Transfer_Function.cpp
+
+Fl_Slice_Frequency.o: Fl_Slice_Frequency.cpp Fl_Slice_Frequency.h
+	$(CXX) $(CXX_FLAGS_UI) -c Fl_Slice_Frequency.cpp
+
+FrustumCalculator.o: FrustumCalculator.cpp FrustumCalculator.h
+	$(CXX) $(CXX_FLAGS) -c FrustumCalculator.cpp
+
+FrustumPlanes.o: FrustumPlanes.cpp FrustumPlanes.h
+	$(CXX) $(CXX_FLAGS) -c FrustumPlanes.cpp
+
+Log.o: Log.cpp Log.h
+	$(CXX) $(CXX_FLAGS) -c Log.cpp
+
+Master.o: Master.cpp Master.h                  \
+          Communicator.h                       \
+          FrustumCalculator.h                  \
+          Matrix.h                             \
+          Octree.h                             \
+          SynchronizerServer.h                 \
+	  Trackball.h                          \
+          UserInterfaceServer.h                \
+          UserInterfaceServerAbstractCommand.h \
+          Vertex.h
+	$(CXX) $(CXX_FLAGS) -c Master.cpp
+
+Matrix.o: Matrix.cpp Matrix.h
+	$(CXX) -c Matrix.cpp
+
+Octree.o: Octree.cpp Octree.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c Octree.cpp
+
+OctreeNode.o: OctreeNode.cpp OctreeNode.h Vertex.h
+	$(CXX) $(CXX_FLAGS) -c OctreeNode.cpp
+
+OctreeNodeQueue.o: OctreeNodeQueue.cpp OctreeNodeQueue.h OctreeNode.h
+	$(CXX) $(CXX_FLAGS) -c OctreeNodeQueue.cpp
+
+OpacityTransferFunctionWidget.o: OpacityTransferFunctionWidget.cpp \
+                                 OpacityTransferFunctionWidget.h
+	$(CXX) $(CXX_FLAGS_UI) -c OpacityTransferFunctionWidget.cpp
+
+ScriptGenerator.o: ScriptGenerator.cpp \
+                   FrustumCalculator.h \
+                   Matrix.h            \
+                   Vertex.h
+	$(CXX) -c ScriptGenerator.cpp
+
+Slave.o: Slave.cpp Slave.h             \
+         Communicator.h                \
+         CommunicatorAbstractCommand.h \
+         Octree.h                      \
+         VolumeRendererShell.h
+	$(CXX) $(CXX_FLAGS) -c Slave.cpp
+
+SynchronizerServerAbstractCommand.o: SynchronizerServerAbstractCommand.cpp \
+                                     SynchronizerServerAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerServerAbstractCommand.cpp
+
+SynchronizerServerConcreteCommand.o: SynchronizerServerConcreteCommand.cpp \
+                                     SynchronizerServerConcreteCommand.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerServerConcreteCommand.cpp
+
+SynchronizerClient.o: SynchronizerClient.cpp SynchronizerClient.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerClient.cpp
+
+SynchronizerServerClientThreadInfo.o: SynchronizerServerClientThreadInfo.cpp \
+                                      SynchronizerServerClientThreadInfo.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerServerClientThreadInfo.cpp
+
+SynchronizerServer.o: SynchronizerServer.cpp SynchronizerServer.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerServer.cpp
+
+SynchronizerServerListenThreadInfo.o: SynchronizerServerListenThreadInfo.cpp \
+                                      SynchronizerServerListenThreadInfo.h
+	$(CXX) $(CXX_FLAGS) -c SynchronizerServerListenThreadInfo.cpp
+
+Trackball.o: Trackball.cpp Trackball.h
+	$(CXX) -c Trackball.cpp
+
+UI.o: UI.cpp                               \
+      DataPacker.h                         \
+      Fl_Connect.h                         \
+      Fl_Dialog.h                          \
+      Fl_Load_Data.h                       \
+      Fl_Main_Window.h                     \
+      Fl_Overview.h                        \
+      Fl_Transfer_Function.h               \
+      Trackball.h                          \
+      UserInterfaceClient.h                \
+      UserInterfaceClientConcreteCommand.h \
+      Vertex.h
+	$(CXX) $(CXX_FLAGS_UI) -c UI.cpp
+
+UserInterfaceClientAbstractCommand.o: UserInterfaceClientAbstractCommand.cpp \
+                                      UserInterfaceClientAbstractCommand.h
+	$(CXX) $(CXX_FLAGS_UI) -c UserInterfaceClientAbstractCommand.cpp
+
+UserInterfaceClientConcreteCommand.o: UserInterfaceClientConcreteCommand.cpp \
+                                      UserInterfaceClientConcreteCommand.h   \
+                                      DataPacker.h                           \
+                                      UserInterfaceClientAbstractCommand.h
+	$(CXX) $(CXX_FLAGS_UI) -c UserInterfaceClientConcreteCommand.cpp
+
+UserInterfaceClient.o: UserInterfaceClient.cpp UserInterfaceClient.h \
+                       DataPacker.h                                  \
+                       UserInterfaceClientAbstractCommand.h
+	$(CXX) $(CXX_FLAGS_UI) -c UserInterfaceClient.cpp
+
+UserInterfaceServerAbstractCommand.o: UserInterfaceServerAbstractCommand.cpp \
+                                      UserInterfaceServerAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c UserInterfaceServerAbstractCommand.cpp
+
+UserInterfaceServerConcreteCommand.o: UserInterfaceServerConcreteCommand.cpp \
+                                      UserInterfaceServerConcreteCommand.h   \
+                                      UserInterfaceServerAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c UserInterfaceServerConcreteCommand.cpp
+
+UserInterfaceServer.o: UserInterfaceServer.cpp UserInterfaceServer.h \
+                       DataPacker.h                                  \
+                       UserInterfaceServerAbstractCommand.h
+	$(CXX) $(CXX_FLAGS) -c UserInterfaceServer.cpp
+
+Vertex.o: Vertex.cpp Vertex.h
+	$(CXX) -c Vertex.cpp
+
+VolumeRendererCommand.o: VolumeRendererCommand.cpp VolumeRendererCommand.h
+	$(CXX) $(CXX_FLAGS) -c VolumeRendererCommand.cpp
+
+VolumeRenderer.o: VolumeRenderer.cpp VolumeRenderer.h \
+                  CacheRAM.h                          \
+                  CacheVRAM.h                         \
+                  FrustumPlanes.h                     \
+                  Octree.h                            \
+                  OctreeNodeQueue.h                   \
+                  VolumeRendererCommand.h
+	$(CXX) $(CXX_FLAGS) -c VolumeRenderer.cpp
+
+VolumeRendererShell.o: VolumeRendererShell.cpp VolumeRenderer.h \
+                       Octree.h                                 \
+                       VolumeRenderer.h                         \
+                       VolumeRendererThreadInfo.h
+	$(CXX) $(CXX_FLAGS) -c VolumeRendererShell.cpp
+
+VolumeRendererThreadInfo.o: VolumeRendererThreadInfo.cpp \
+                            VolumeRendererThreadInfo.h   \
+                            Octree.h
+	$(CXX) $(CXX_FLAGS) -c VolumeRendererThreadInfo.cpp
+
+clean:
+	rm -rf *.o *~ VRA VRA_UI ScriptGenerator
+	rm -rf ../bin/VRA             \
+               ../bin/Fragment.cg     \
+               ../bin/VRA_UI          \
+               ../bin/ScriptGenerator
Index: trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.h	(revision 4)
@@ -0,0 +1,75 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_SERVER_CLIENT_THREAD_INFO_H
+#define SYNCHRONIZER_SERVER_CLIENT_THREAD_INFO_H
+
+/*---------------------------------------------------------------------------*/
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/*---------------------------------------------------------------------------*/
+
+class SynchronizerServerClientThreadInfo {
+
+public:
+
+  // Default constructor
+  SynchronizerServerClientThreadInfo();
+
+  // Default destructor
+  ~SynchronizerServerClientThreadInfo();
+
+  // Client address
+  struct sockaddr_in _clientAddress;
+
+  // Client socket file descriptor
+  int _clientSocketFileDescriptor;
+
+  // Mutex
+  pthread_mutex_t* _conditionMutex;
+
+  // Condition variable
+  pthread_cond_t* _conditionVariable;
+
+  // Finalize flag
+  bool* _finalizeFlag;
+
+  // Current level
+  int* _level;
+
+  // Number of connected clients
+  int* _numberOfClients;
+
+  // Number of connected clients waiting at barrier
+  int* _numberOfClientsWaiting;
+
+};
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/ColorTransferFunctionWidget.cpp	(revision 4)
@@ -0,0 +1,1453 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "ColorTransferFunctionWidget.h"
+
+/*--------------------------------------------------------------------------*/
+
+ColorTransferFunctionWidget::ColorTransferFunctionWidget(int w, int h) {
+
+  // Initialize background color
+  _backgroundColor[0] = 0.0;
+  _backgroundColor[1] = 0.0;
+  _backgroundColor[2] = 0.0;
+  _backgroundColor[3] = 0.0;
+
+  // Initialize box bound
+  _boxBound[0] = 0.0;
+  _boxBound[1] = 0.0;
+  _boxBound[2] = 0.0;
+  _boxBound[3] = 0.0;
+
+  // Initialize box color
+  _boxColor[0] = 1.0;
+  _boxColor[1] = 1.0;
+  _boxColor[2] = 1.0;
+  _boxColor[3] = 1.0;
+
+  // Initialize control point color
+  _controlPointColor[0] = 1.0;
+  _controlPointColor[1] = 1.0;
+  _controlPointColor[2] = 1.0;
+  _controlPointColor[3] = 1.0;
+
+  // Initialize control point size
+  _controlPointSize = 8;
+
+  // Initialize focus point index
+  _focusPoint = -1;
+
+  // Initialize focus point color
+  _focusPointColor[0] = 0.0;
+  _focusPointColor[1] = 0.0;
+  _focusPointColor[2] = 0.0;
+  _focusPointColor[3] = 1.0;
+
+  // Initialize frustum
+  _frustum[0] = 0.0;
+  _frustum[1] = 1.0;
+  _frustum[2] = 0.0;
+  _frustum[3] = 1.0;
+  _frustum[4] = -1.0;
+  _frustum[5] = 1.0;
+
+  // Initialize line color
+  _lineColor[0] = 1.0;
+  _lineColor[1] = 1.0;  
+  _lineColor[2] = 1.0;
+  _lineColor[3] = 1.0;
+
+  // Initialize number of control points
+  _numberOfControlPoints = 0;
+
+  // Initialize size of window
+  _pixelDimensions[0] = w;
+  _pixelDimensions[1] = h;
+
+  // Initialize scalar range
+  _scalarMaximum = 1.0;
+  _scalarMinimum = 0.0;
+
+  // Initialize text color
+  _textColor[0] = 1.0;
+  _textColor[1] = 1.0;
+  _textColor[2] = 1.0;
+  _textColor[3] = 1.0;
+
+  // Initialize transfer function
+  ControlPoint controlPoint;
+
+  // First control point
+  controlPoint.SetScalar(0.0);
+  controlPoint.SetRGB(0.0, 0.0, 0.0);
+  _controlPoint.push_back(controlPoint);
+
+  // Second control point
+  controlPoint.SetScalar(1.0);
+  controlPoint.SetRGB(1.0, 1.0, 1.0);
+  _controlPoint.push_back(controlPoint);
+
+  // Increment number of control points
+  _numberOfControlPoints = 2;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+ColorTransferFunctionWidget::~ColorTransferFunctionWidget() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::AddControlPoint(int px, int py) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Control point
+  ControlPoint controlPoint;
+
+  // Function coordinates
+  float rgb[3] = {0.0, 0.0, 0.0};
+  float scalar = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, &scalar);
+
+      // Set control point
+      controlPoint.SetScalar(scalar);
+
+      // Determine color for this scalar value
+      GetColor(scalar, &rgb[0], &rgb[1], &rgb[2]);
+
+      // Set control point color
+      controlPoint.SetRGB(rgb[0], rgb[1], rgb[2]);
+
+      // Add control point
+      _controlPoint.push_back(controlPoint);
+
+      // Sort control points
+      sort(_controlPoint.begin(), _controlPoint.end());
+
+      // Get index of newly added point
+      _focusPoint = GetControlPointIndex(scalar);
+
+      // Increment number of control points
+      _numberOfControlPoints++;
+
+      // Control point added
+      return true;
+
+    }
+
+  }
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Did not add control point
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::BoxToFunction(float bx, 
+                                                float by,
+                                                float* scalar) {
+
+  // Convert from box coordinates to function coordinates
+  *scalar = ((bx * (_scalarMaximum - _scalarMinimum)) + _scalarMinimum);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::BoxToWorld(float bx, float by, 
+                                             float* wx, float* wy) {
+
+  // Convert from box coordinates to world coordinates
+  *wx = (bx * (_boxBound[1] - _boxBound[0])) + _boxBound[0];
+  *wy = (by * (_boxBound[3] - _boxBound[2])) + _boxBound[2];
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::Draw() {
+
+  // Clear color
+  glClearColor(_backgroundColor[0], _backgroundColor[1],
+               _backgroundColor[2], _backgroundColor[3]);
+
+  // Clear bufffer
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  // Set viewport
+  glViewport(0, 0, _pixelDimensions[0], _pixelDimensions[1]);
+
+  // Set projection mode
+  glMatrixMode(GL_PROJECTION);
+
+  // Load identity
+  glLoadIdentity();
+
+  // Set frustum
+  glOrtho(_frustum[0], _frustum[1], 
+          _frustum[2], _frustum[3], 
+          _frustum[4], _frustum[5]);
+
+  // Set modelview mode
+  glMatrixMode(GL_MODELVIEW);
+
+
+  // Text color
+  glColor4f(_textColor[0], _textColor[1], _textColor[2], _textColor[3]);
+
+  // Text border in pixels
+  int textBorder = 5;
+
+  // Text height in pixels
+  int textHeight = 10;
+
+
+  // Minimum scalar
+
+  // Calculate offsets for text
+  float scalarMinimumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float scalarMinimumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Create text string
+  char scalarMinimumString[128];
+  sprintf(scalarMinimumString, "%.0f", _scalarMinimum);
+
+  // Calculate width
+  float scalarMinimumWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarMinimumString) ; i++) {
+    //scalarMinimumWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarMinimumString[i]);
+  }
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarMinimumHorizontalOffset, 
+                _frustum[2] + scalarMinimumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarMinimumString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarMinimumString[i]);
+  }
+
+
+  // Maximum scalar
+
+  // Create text string
+  char scalarMaximumString[128];
+  sprintf(scalarMaximumString, "%.0f", _scalarMaximum);
+
+  // Calculate width
+  float scalarMaximumWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarMaximumString) ; i++) {
+    //scalarMaximumWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarMaximumString[i]);
+  }
+
+  // Calculate offsets for text
+  float scalarMaximumHorizontalOffset = 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder + scalarMaximumWidth);
+  float scalarMaximumVerticalOffset = 
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[1] - scalarMaximumHorizontalOffset, 
+                _frustum[2] + scalarMaximumVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarMaximumString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarMaximumString[i]);
+  }
+
+
+  // Boundary of color gradient box
+  float colorBound[4];
+
+  // Determine left bound of color gradient
+  colorBound[0] = _frustum[0] + 
+    scalarMinimumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+     scalarMinimumWidth) / 2.0;
+
+  // Determine right bound of color gradient
+  colorBound[1] = _frustum[1] -
+    scalarMaximumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    scalarMaximumWidth) / 2.0;
+
+  // Determine bottom bound of color gradient
+  colorBound[2] = _frustum[2] +
+    scalarMinimumVerticalOffset +
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     ((float) textHeight + (float) textBorder));
+  
+  // Determine top bound of color gradient
+  colorBound[3]  = colorBound[2] + 
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     (float) textHeight * 1.5);
+
+
+  // Draw color gradient
+
+  // Color
+  float rgb[3] = {0.0, 0.0, 0.0};
+
+  // Step size in horizontal direction
+  float boxStep = (colorBound[1] - colorBound[0]) / 1024.0;
+
+  // Scalar step size
+  float scalarStep = (_scalarMaximum - _scalarMinimum) / 1024.0;
+
+  // Sample transfer function at even intervals
+  glBegin(GL_QUAD_STRIP);
+  for (int i = 0 ; i <= 1024 ; i++) {
+
+    // Get color at interval
+    GetColor(_scalarMinimum + (i * scalarStep), &rgb[0], &rgb[1], &rgb[2]); 
+
+    // Set color
+    glColor4f(rgb[0], rgb[1], rgb[2], 1.0);
+
+    // Draw vertex
+    glVertex3f(colorBound[0] + (i * boxStep), colorBound[3], 0.0);
+    glVertex3f(colorBound[0] + (i * boxStep), colorBound[2], 0.0);
+  }
+  glEnd();
+
+
+  // Color gradient box color
+  glColor4f(_boxColor[0], _boxColor[1], _boxColor[2], _boxColor[3]);
+
+  // Draw color gradient box
+  glLoadIdentity();
+  glBegin(GL_LINES);
+  glVertex3f(colorBound[0], colorBound[2], 0.0);
+  glVertex3f(colorBound[0], colorBound[3], 0.0);
+  glVertex3f(colorBound[1], colorBound[2], 0.0);
+  glVertex3f(colorBound[1], colorBound[3], 0.0);
+  glVertex3f(colorBound[0], colorBound[2], 0.0);
+  glVertex3f(colorBound[1], colorBound[2], 0.0);
+  glVertex3f(colorBound[0], colorBound[3], 0.0);
+  glVertex3f(colorBound[1], colorBound[3], 0.0);
+  glEnd();
+
+
+  // Determine left bound of box
+  _boxBound[0] = _frustum[0] + 
+    scalarMinimumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+     scalarMinimumWidth) / 2.0;
+
+  // Determine right bound of box
+  _boxBound[1] = _frustum[1] -
+    scalarMaximumHorizontalOffset +
+    (((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    scalarMaximumWidth) / 2.0;
+
+  // Determine bottom bound of box
+  _boxBound[2] = colorBound[3] + 
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     (float) textBorder);
+  
+  // Determine top bound of box
+  _boxBound[3]  = _frustum[3] -
+    (((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+     (float) textBorder);
+  
+
+  // Scalar label
+
+  // Create text string
+  char scalarLabelString[128];
+
+  // Fill text string
+  sprintf(scalarLabelString, "Scalar");
+
+  // Scalar width
+  float scalarLabelWidth = 0.0;
+  for (int i = 0 ; i < (int) strlen(scalarLabelString) ; i++) {
+    //scalarLabelWidth += 
+    //  glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, scalarLabelString[i]);
+  }
+
+  // Calculate offsets for text
+  float scalarLabelHorizontalOffset = 
+    ((_boxBound[1] - _boxBound[0]) / 2.0) + _boxBound[0] - 
+    ((((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+      scalarLabelWidth) / 2.0);
+  float scalarLabelVerticalOffset =
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) * 
+    ((float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarLabelHorizontalOffset, 
+                _frustum[2] + scalarLabelVerticalOffset, 
+                0.0);
+
+  // Display text
+  for (int i = 0 ; i < (int) strlen(scalarLabelString) ; i++) {
+    //glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarLabelString[i]);
+  }
+
+
+  /*
+  // Control point scalar readout
+
+  // Calculate offsets for text
+  float scalarReadoutHorizontalOffset = 
+    _boxBound[0] + 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float scalarReadoutVerticalOffset = 
+    (_frustum[3] - _boxBound[3]) +
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) *
+    ((float) textHeight + (float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + scalarReadoutHorizontalOffset, 
+                _frustum[3] - scalarReadoutVerticalOffset, 
+                0.0);
+
+  // Create text string
+  char scalarReadoutString[128];
+
+  // If a valid control point has the focus
+  if (_focusPoint >= 0 && _focusPoint < _numberOfControlPoints) {
+    
+    // Function coordinates
+    float s = 0.0;
+    float r = 0.0;
+    float g = 0.0;
+    float b = 0.0;
+
+    // Get control point
+    GetControlPoint(_focusPoint, &s, &r, &g, &b);
+
+    // Fill text string
+    sprintf(scalarReadoutString, "%s %.4f", "S:", s);
+
+  }
+
+  // If no point has focus
+  else {
+
+    // Fill text string
+    sprintf(scalarReadoutString, "%s", "S:");
+
+  }
+
+  // Display text
+  for (int i = 0 ; i < strlen(scalarReadoutString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, scalarReadoutString[i]);
+  }
+  */
+
+
+  /*
+  // Control point color readout
+
+  // Calculate offsets for text
+  float colorReadoutHorizontalOffset = 
+    _boxBound[0] + 
+    ((_frustum[1] - _frustum[0]) / (float) _pixelDimensions[0]) * 
+    ((float) textBorder);
+  float colorReadoutVerticalOffset = 
+    scalarReadoutVerticalOffset +
+    ((_frustum[3] - _frustum[2]) / (float) _pixelDimensions[1]) *
+    ((float) textHeight + (float) textBorder);
+
+  // Position text
+  glRasterPos3f(_frustum[0] + colorReadoutHorizontalOffset, 
+                _frustum[3] - colorReadoutVerticalOffset, 
+                0.0);
+
+  // Create text string
+  char colorReadoutString[128];
+
+  // If a valid control point has the focus
+  if (_focusPoint >= 0 && _focusPoint < _numberOfControlPoints) {
+    
+    // Function coordinates
+    float s = 0.0;
+    float r = 0.0;
+    float g = 0.0;
+    float b = 0.0;
+
+    // Get control point
+    GetControlPoint(_focusPoint, &s, &r, &g, &b);
+
+    // Fill text string
+    sprintf(colorReadoutString, "R: %.4f G: %.4f B: %.4f", r, g, b);
+
+  }
+
+  // If no point has focus
+  else {
+
+    // Fill text string
+    sprintf(colorReadoutString, "%s", "R: G: B:");
+
+  }
+
+  // Display text
+  for (int i = 0 ; i < strlen(colorReadoutString) ; i++) {
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, colorReadoutString[i]);
+  }
+  */
+
+
+  // Box color
+  glColor4f(_boxColor[0], _boxColor[1], _boxColor[2], _boxColor[3]);
+
+  // Draw box
+  glLoadIdentity();
+  glBegin(GL_LINES);
+  glVertex3f(_boxBound[0], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[2], 0.0);
+  glVertex3f(_boxBound[0], _boxBound[3], 0.0);
+  glVertex3f(_boxBound[1], _boxBound[3], 0.0);
+  glEnd();
+
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+    
+
+  // Line color
+  glColor4f(_lineColor[0], _lineColor[1], _lineColor[2], _lineColor[3]);
+
+  // Draw lines connecting control points
+  glBegin(GL_LINE_STRIP);
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    scalar = _controlPoint[i].GetScalar();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, &bx, &by);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(bx, by) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(bx, by, &wx, &wy);
+
+        // Next point in line strip
+        glVertex3f(wx, wy, 0.0);
+
+      }
+
+    }
+
+  }
+  glEnd();
+
+
+  // Draw each control point
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    scalar = _controlPoint[i].GetScalar();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, &bx, &by);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(bx, by) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(bx, by, &wx, &wy);
+
+        // Control point color
+        float rgb[3];
+
+        // Draw focus point
+        if (i == _focusPoint) {
+
+          // Draw bigger outline point
+          glPointSize(_controlPointSize * 2.0);
+          glColor4f(_focusPointColor[0], _focusPointColor[1],
+                    _focusPointColor[2], _focusPointColor[3]); 
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+
+          // Draw regular point inside
+          glPointSize((float) _controlPointSize);
+          _controlPoint[i].GetRGB(&rgb[0], &rgb[1], &rgb[2]);
+          glColor4f(rgb[0], rgb[1], rgb[2], 1.0);
+          //glColor4f(_controlPointColor[0], _controlPointColor[1], 
+          //          _controlPointColor[2], _controlPointColor[3]);
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+
+          // Draw even smaller point
+          glPointSize((float) _controlPointSize / 4.0);
+          glColor4f(_focusPointColor[0], _focusPointColor[1],
+                    _focusPointColor[2], _focusPointColor[3]); 
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+        }
+
+        // Draw single control point
+        else {
+          glPointSize(_controlPointSize);
+          _controlPoint[i].GetRGB(&rgb[0], &rgb[1], &rgb[2]);
+          glColor4f(rgb[0], rgb[1], rgb[2], 1.0);
+          //glColor4f(_controlPointColor[0], _controlPointColor[1], 
+          //          _controlPointColor[2], _controlPointColor[3]);
+          glBegin(GL_POINTS);
+          glVertex3f(wx, wy, 0.0);
+          glEnd();
+        }
+
+      }
+
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::FunctionToBox(float scalar, float* bx, 
+                                                float* by) {
+
+  // Convert from function coordinates to box coordinates
+  *bx = (scalar - _scalarMinimum) / (_scalarMaximum - _scalarMinimum);
+  *by = 0.5;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::GetControlPoint(int index, float* scalar, 
+                                                  float* r, float* g, 
+                                                  float* b) {
+
+  // Get control point
+  *scalar = _controlPoint[index].GetScalar();
+  _controlPoint[index].GetRGB(r, g, b);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int ColorTransferFunctionWidget::GetControlPointIndex(int px, int py) {
+
+  // Control point box coordinates
+  float cbx = 0.0;
+  float cby = 0.0;
+
+  // Control point world coordinates
+  float cwx = 0.0;
+  float cwy = 0.0;
+
+  // Pixel world coordinates
+  float pwx = 0.0;
+  float pwy = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+
+  // Distances
+  vector <float> distance;
+
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == false) {
+    return -1;
+  }
+
+  // Get corresponding world coordinates
+  PixelToWorld(px, py, &pwx, &pwy);
+
+  // Check that world coordinates are within box space
+  if (IsWorldInBox(pwx, pwy) == false) {
+    return -1;
+  }
+
+  // Check for control points
+  if (_numberOfControlPoints < 1) {
+    return -1;
+  }
+
+  
+  // Calculate distance to each control point
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get control point values
+    scalar = _controlPoint[i].GetScalar();
+
+    // Check that function coordinates are within box space
+    if (IsFunctionInBox(scalar) == true) {
+
+      // Get corresponding box coordinates
+      FunctionToBox(scalar, &cbx, &cby);
+
+      // Check that box coordinates are within world space
+      if (IsBoxInWorld(cbx, cby) == true) {
+
+        // Get corresponding world coordinates
+        BoxToWorld(cbx, cby, &cwx, &cwy);
+
+        // Calculate distance and correct for aspect ratio
+        float dX = pwx - cwx;
+        float dY = (pwy - cwy) / (_pixelDimensions[0] / _pixelDimensions[1]);
+        float d = sqrt(dX*dX + dY*dY);
+
+        // Add distance
+        distance.push_back(d);
+
+      }
+
+    }
+
+  }
+
+
+  // Size of control point in world coordinates
+  float ctrlPtSizeX = 0.0;
+  float ctrlPtSizeY = 0.0;
+
+  // Calculate size of a control point in world coordinates
+  PixelToWorld(_controlPointSize / 2, 
+               _pixelDimensions[1] - (_controlPointSize / 2), 
+               &ctrlPtSizeX, 
+               &ctrlPtSizeY);
+
+
+  // Minimum distance
+  float minimum = distance[0];
+
+  // Index of control point closest to pixel coordinates
+  int index = 0;
+
+  // Find minimum distance
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+    if (distance[i] < minimum) {
+      minimum = distance[i];
+      index = i;
+    }
+  }
+
+
+  // Get control point values for closest point
+  scalar = _controlPoint[index].GetScalar();
+
+  // Check that function coordinates are within box space
+  if (IsFunctionInBox(scalar) == true) {
+
+    // Get corresponding box coordinates
+    FunctionToBox(scalar, &cbx, &cby);
+
+    // Check that box coordinates are within world space
+    if (IsBoxInWorld(cbx, cby) == true) {
+
+      // Get corresponding world coordinates
+      BoxToWorld(cbx, cby, &cwx, &cwy);
+
+      // Return control point index and set focus point if it's picked
+      if (pwx >= cwx - ctrlPtSizeX && pwx <= cwx + ctrlPtSizeX &&
+          pwy >= cwy - ctrlPtSizeY && pwy <= cwy + ctrlPtSizeY) {
+        _focusPoint = index;
+        return index;
+      }
+
+    }
+
+  }
+
+
+  // No control point picked
+  return -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int ColorTransferFunctionWidget::GetControlPointIndex(float scalar) {
+
+  // Check each control point for matching function coordinates
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+    if (_controlPoint[i].GetScalar() == scalar) {
+      return i;
+    }
+  }
+
+  // No control point picked
+  return -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::GetFunctionCoordinates(int px, int py, 
+                                                         float* scalar, 
+                                                         float* r,
+                                                         float* g,
+                                                         float* b) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, scalar);
+
+      // Get color values
+      GetColor(*scalar, r, g, b);
+
+      // Control point added
+      return true;
+
+      }
+
+  }
+
+  // Not within bounds
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int ColorTransferFunctionWidget::GetNumberOfControlPoints() {
+
+  // Return number of control points
+  return _numberOfControlPoints;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::GetColor(float scalar, 
+                                           float* r, 
+                                           float* g,
+                                           float* b) {
+
+  // Check minimum bound
+  if (scalar < _controlPoint[0].GetScalar()) {
+    _controlPoint[0].GetRGB(r, g, b);
+    return;
+  }
+
+  // Check maximum bound
+  if (scalar > _controlPoint[_numberOfControlPoints - 1].GetScalar()) {
+    _controlPoint[_numberOfControlPoints - 1].GetRGB(r, g, b);
+    return;
+  }
+
+  // Control points that border scalar value
+  int left = 0;
+  int right = 0;
+      
+  // Find control points that border scalar value
+  for (int i = 1 ; i < _numberOfControlPoints ; i++) {
+    if (scalar < _controlPoint[i].GetScalar()) {
+      right = i;
+      break;
+    }
+    left = i;
+  }
+
+  // Scalar coordinates of control points
+  float xl = _controlPoint[left].GetScalar();
+  float xr = _controlPoint[right].GetScalar();
+
+  // Color coordinates of control points
+  float rgbl[3];
+  float rgbr[3];
+  _controlPoint[left].GetRGB(&rgbl[0], &rgbl[1], &rgbl[2]);
+  _controlPoint[right].GetRGB(&rgbr[0], &rgbr[1], &rgbr[2]);
+
+  // Interpolate between bordering control points
+  *r = rgbl[0] + (((scalar - xl) / (xr - xl)) * (rgbr[0] - rgbl[0]));
+  *g = rgbl[1] + (((scalar - xl) / (xr - xl)) * (rgbr[1] - rgbl[1]));
+  *b = rgbl[2] + (((scalar - xl) / (xr - xl)) * (rgbr[2] - rgbl[2]));
+
+  // Return
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::GetScalarRange(float* min, float* max) {
+
+  // Set scalar range
+  *min = _scalarMinimum;
+  *max = _scalarMaximum;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::IsBoxInWorld(float bx, float by) {
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Calculate world coordinates
+  BoxToWorld(bx, by, &wx, &wy);
+
+  // Check if box coordinates are in world space
+  if (wx >= _frustum[0] && wx <= _frustum[1] &&
+      wy >= _frustum[2] && wy <= _frustum[3]) {
+    return true;
+  }
+
+  // Not in world space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::IsFunctionInBox(float scalar) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Calculate box coordinates
+  FunctionToBox(scalar, &bx, &by);
+
+  // Check if function coordinates are in box space
+  if (bx >= 0.0 && bx <= 1.0 && 
+      by >= 0.0 && by <= 1.0) {
+    return true;
+  }
+
+  // Not in box space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::IsPixelInWorld(int px, int py) {
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Calculate world coordinates
+  PixelToWorld(px, py, &wx, &wy);
+
+  // Check if pixel coordinates are in world space
+  if (wx >= _frustum[0] && wx <= _frustum[1] &&
+      wy >= _frustum[2] && wy <= _frustum[3]) {
+    return true;
+  }
+
+  // Not in world space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::IsWorldInBox(float wx, float wy) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Calculate box coordinates
+  WorldToBox(wx, wy, &bx, &by);
+
+  // Check if world coordinates are in box space
+  if (bx >= 0.0 && bx <= 1.0 &&
+      by >= 0.0 && by <= 1.0) {
+    return true;
+  }
+
+  // Not in box space
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::ModifyControlPointColor(int index, float r, 
+                                                          float g, float b) {
+
+  // Check that control point exists
+  if (index >= 0 && index < _numberOfControlPoints) {
+
+    // Check bounds on colors
+    if (r < 0.0) r = 0.0;
+    if (r > 1.0) r = 1.0;
+    if (g < 0.0) g = 0.0;
+    if (g > 1.0) g = 1.0;
+    if (b < 0.0) b = 0.0;
+    if (b > 1.0) b = 1.0;
+
+    // Set new color
+    _controlPoint[index].SetRGB(r, g, b);
+
+    // Return true
+    return true;
+
+  }
+
+  // Return false
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::MoveControlPoint(int index, int px, int py) {
+
+  // Box coordinates
+  float bx = 0.0;
+  float by = 0.0;
+
+  // Function coordinates
+  float scalar = 0.0;
+
+  // World coordinates
+  float wx = 0.0;
+  float wy = 0.0;
+
+  // Check that pixel coordinates are within world space
+  if (IsPixelInWorld(px, py) == true) {
+
+    // Get corresponding world coordinates
+    PixelToWorld(px, py, &wx, &wy);
+
+    // Check that world coordinates are within box space
+    if (IsWorldInBox(wx, wy) == true) {
+
+      // Get corresponding box coordinates
+      WorldToBox(wx, wy, &bx, &by);
+
+      // Get corresponding function coordinates
+      BoxToFunction(bx, by, &scalar);
+
+      // Check that control point picked is not an edge point and is valid
+      if (index > 0 && index < _numberOfControlPoints - 1) {
+
+        // Check that new scalar is not past next point
+        if (scalar >= _controlPoint[index + 1].GetScalar()) {
+          float s = _controlPoint[index + 1].GetScalar() - 1.0;
+          _controlPoint[index].SetScalar(s);
+        }
+
+        // Check that new scalar is not before previous point
+        else if (scalar <= _controlPoint[index - 1].GetScalar()) {
+          float s = _controlPoint[index - 1].GetScalar() + 1.0;
+          _controlPoint[index].SetScalar(s);
+        }
+
+        // Check that new scalar is not greater than maximum scalar value
+        else if (scalar > _scalarMaximum) {
+          _controlPoint[index].SetScalar(_scalarMaximum);
+        }
+
+        // Check that new scalar is not less than minimum scalar value
+        else if (scalar < _scalarMinimum) {
+          _controlPoint[index].SetScalar(_scalarMinimum);
+        }
+
+        // New scalar value is valid
+        else {
+          _controlPoint[index].SetScalar(scalar);
+        }
+
+      }
+
+      // Control point moved
+      return true;
+
+    }
+
+  }
+
+  // Can't move control point to desired position
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::MoveControlPoint(int index, float scalar) {
+
+  // Check that control point picked is not an edge point and is valid
+  if (index > 0 && index < _numberOfControlPoints - 1) {
+
+    // Check that new scalar is not past next point
+    if (scalar >= _controlPoint[index + 1].GetScalar()) {
+      float s = _controlPoint[index + 1].GetScalar() - 1.0;
+      _controlPoint[index].SetScalar(s);
+    }
+
+    // Check that new scalar is not before previous point
+    else if (scalar <= _controlPoint[index - 1].GetScalar()) {
+      float s = _controlPoint[index - 1].GetScalar() + 1.0;
+      _controlPoint[index].SetScalar(s);
+    }
+
+    // Check that new scalar is not greater than maximum scalar value
+    else if (scalar > _scalarMaximum) {
+      _controlPoint[index].SetScalar(_scalarMaximum);
+    }
+
+    // Check that new scalar is not less than minimum scalar value
+    else if (scalar < _scalarMinimum) {
+      _controlPoint[index].SetScalar(_scalarMinimum);
+    }
+
+    // New scalar value is valid
+    else {
+      _controlPoint[index].SetScalar(scalar);
+    }
+
+  }
+
+  // Control point moved
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::PixelToWorld(int px, int py, 
+                                               float* wx, float* wy) {
+
+  // Flip y coordinate
+  py = _pixelDimensions[1] - py;
+
+  // Convert from pixel coordinates to world coordinates
+  *wx = _frustum[0] + 
+    (((float) px / (float) _pixelDimensions[0]) * (_frustum[1] - _frustum[0]));
+  *wy = _frustum[2] + 
+    (((float) py / (float) _pixelDimensions[1]) * (_frustum[3] - _frustum[2]));
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::RestoreControlPoints(int number,
+                                                       float max,
+                                                       float* scalar, 
+                                                       float* r,
+                                                       float* g,
+                                                       float* b) {
+
+  // Temporary control point
+  ControlPoint tmp;
+
+  // Set number of control points
+  _numberOfControlPoints = number;
+
+  // Set maximum scalar value
+  _scalarMaximum = max;
+
+  // Clear all control points
+  _controlPoint.clear();
+
+  // Set each control point from arrays
+  for (int i = 0 ; i < number ; i++) {
+    tmp.SetScalar(scalar[i]);
+    tmp.SetRGB(r[i], g[i], b[i]);
+    _controlPoint.push_back(tmp);
+  }
+
+  // Set focus point
+  _focusPoint = -1;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool ColorTransferFunctionWidget::RemoveControlPoint(int index) {
+
+  // Check that index is within bounds and set focus point
+  if (index < 1 || index >= _numberOfControlPoints - 1) {
+    _focusPoint = index;
+    return false;
+  }
+
+  // Remove control point
+  _controlPoint.erase(_controlPoint.begin() + index);
+
+  // Decrement number of control points
+  _numberOfControlPoints--;
+
+  // Set focus point
+  _focusPoint = -1;
+
+  // Success
+  return true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetBackgroundColor(float r, float g, 
+                                                     float b, float a) {
+
+  // Set background color
+  _backgroundColor[0] = r;
+  _backgroundColor[1] = g;
+  _backgroundColor[2] = b;
+  _backgroundColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetBoxColor(float r, float g, 
+                                              float b, float a) {
+
+  // Set box color
+  _boxColor[0] = r;
+  _boxColor[1] = g;
+  _boxColor[2] = b;
+  _boxColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetControlPointColor(float r, float g,
+                                                       float b, float a) {
+
+  // Set control point color
+  _controlPointColor[0] = r;
+  _controlPointColor[1] = g;
+  _controlPointColor[2] = b;
+  _controlPointColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetControlPointSize(int size) {
+
+  // Set control point size
+  _controlPointSize = size;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetDimensions(int w, int h) {
+
+  // Set dimensions
+  _pixelDimensions[0] = w;
+  _pixelDimensions[1] = h;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetFocusPointColor(float r, float g, 
+                                                     float b, float a) {
+
+  // Set focus point color
+  _focusPointColor[0] = r;
+  _focusPointColor[1] = g;
+  _focusPointColor[2] = b;
+  _focusPointColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetLineColor(float r, float g, 
+                                               float b, float a) {
+
+  // Set line color
+  _lineColor[0] = r;
+  _lineColor[1] = g;
+  _lineColor[2] = b;
+  _lineColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetMaximumScalar(float max) {
+
+  // New scalar values
+  float newMax = max;
+  float newMin = _scalarMinimum;
+
+  // Old scalar values
+  float oldMax = _scalarMaximum;
+  float oldMin = _scalarMinimum;
+
+  // Resample each control point's scalar value
+  for (int i = 0 ; i < _numberOfControlPoints ; i++) {
+
+    // Get old scalar value
+    float oldScalar = _controlPoint[i].GetScalar();
+
+    // Normalize old scalar value
+    float normal = (oldScalar - oldMin) / (oldMax - oldMin);
+
+    // Resample old scalar value to new bounds
+    float newScalar = ((newMax - newMin) * normal) + newMin;
+
+    // Set new scalar value
+    _controlPoint[i].SetScalar(newScalar);
+
+  }
+
+  // Set maximum scalar
+  _scalarMaximum = max;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::SetTextColor(float r, float g, 
+                                               float b, float a) {
+
+  // Set text color
+  _textColor[0] = r;
+  _textColor[1] = g;
+  _textColor[2] = b;
+  _textColor[3] = a;
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void ColorTransferFunctionWidget::WorldToBox(float wx, float wy, 
+                                             float* bx, float* by) {
+
+  // Convert from world coordinates to box coordinates
+  *bx = (wx - _boxBound[0]) / (_boxBound[1] - _boxBound[0]);
+  *by = (wy - _boxBound[2]) / (_boxBound[3] - _boxBound[2]);
+
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRendererCommand.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRendererCommand.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRendererCommand.cpp	(revision 4)
@@ -0,0 +1,37 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "VolumeRendererCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererCommand::VolumeRendererCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+VolumeRendererCommand::~VolumeRendererCommand() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool VolumeRendererCommand::Execute(int value) {
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheVRAM.h
===================================================================
--- trunk/src/testing/app/VRA/src/CacheVRAM.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheVRAM.h	(revision 4)
@@ -0,0 +1,82 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef CACHE_VRAM_H
+#define CACHE_VRAM_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "CacheVRAMNode.h"
+#include "Log.h"
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class CacheVRAM {
+  
+public:
+  
+  // Default constructor
+  CacheVRAM(int size);
+  
+  // Default destructor
+  ~CacheVRAM();
+
+  // Is cache full
+  bool IsFull();
+
+  // Is item loaded
+  bool IsLoaded(OctreeNode* node);
+
+  // Load item
+  void Load(OctreeNode* node);
+
+  // Make item current
+  void MakeCurrent(OctreeNode* node);
+
+  // Move item to front of cache
+  void MoveToFront(OctreeNode* node);
+
+  // Print cache
+  void Print();
+
+  // Remove last item in cache
+  void RemoveLast();
+  
+private:
+
+  // Print a message to stdout
+  void Assert(const char* message);
+
+  // Current size of cache
+  int _currentSize;
+
+  // Maximum size of cache
+  int _maximumSize;
+
+  // Front of cache
+  CacheVRAMNode* _front;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Trackball.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Trackball.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Trackball.cpp	(revision 4)
@@ -0,0 +1,410 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*                                                                          */
+/*                                                                          */
+/* (c) Copyright 1993, 1994, Silicon Graphics, Inc.                         */
+/* ALL RIGHTS RESERVED                                                      */
+/* Permission to use, copy, modify, and distribute this software for        */
+/* any purpose and without fee is hereby granted, provided that the above   */
+/* copyright notice appear in all copies and that both the copyright notice */
+/* and this permission notice appear in supporting documentation, and that  */
+/* the name of Silicon Graphics, Inc. not be used in advertising            */
+/* or publicity pertaining to distribution of the software without specific,*/
+/* written prior permission.                                                */
+/*                                                                          */
+/* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"        */
+/* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,         */
+/* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR         */
+/* FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON             */
+/* GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,          */
+/* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY            */
+/* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,           */
+/* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF        */
+/* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN           */
+/* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON           */
+/* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE        */
+/* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.                         */
+/*                                                                          */
+/* US Government Users Restricted Rights                                    */
+/* Use, duplication, or disclosure by the Government is subject to          */
+/* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph            */
+/* (c)(1)(ii) of the Rights in Technical Data and Computer Software         */
+/* clause at DFARS 252.227-7013 and/or in similar or successor              */
+/* clauses in the FAR or the DOD or NASA FAR Supplement.                    */
+/* Unpublished-- rights reserved under the copyright laws of the            */
+/* United States.  Contractor/manufacturer is Silicon Graphics,             */
+/* Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.            */
+/*                                                                          */
+/* OpenGL(TM) is a trademark of Silicon Graphics, Inc.                      */
+/*--------------------------------------------------------------------------*/
+
+#include "Trackball.h"
+
+/*--------------------------------------------------------------------------*/
+
+Trackball::Trackball() {
+
+  // Initialize last x, y position
+  _lastX = 0.0;
+  _lastY = 0.0;
+
+  // Initialize renormalize count
+  _renormalizeCount = 97;
+
+  // Initialize current quaternion
+  _currentQuaternion[0] = 0.0;
+  _currentQuaternion[1] = 0.0;
+  _currentQuaternion[2] = 0.0;
+  _currentQuaternion[3] = 1.0;
+
+  // Initialize last quaternion
+  _lastQuaternion[0] = 0.0;
+  _lastQuaternion[1] = 0.0;
+  _lastQuaternion[2] = 0.0;
+  _lastQuaternion[3] = 1.0;
+
+  // Initialize trackball size
+  _trackballSize = (float) 0.5;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Trackball::~Trackball() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::AddQuaternions(float q1[4], float q2[4], float dest[4]) {
+
+  static int count = 0;
+
+  float t1[4];
+  float t2[4];
+  float t3[4];
+  float tf[4];
+
+  vCopy(q1, t1);
+  vScale(t1, q2[3]);
+
+  vCopy(q2, t2);
+  vScale(t2, q1[3]);
+
+  vCross(q2, q1, t3);
+  vAdd(t1, t2, tf);
+  vAdd(t3, tf, tf);
+  tf[3] = q1[3] * q2[3] - vDot(q1, q2);
+
+  dest[0] = tf[0];
+  dest[1] = tf[1];
+  dest[2] = tf[2];
+  dest[3] = tf[3];
+  
+  if (++count > _renormalizeCount) {
+    count = 0;
+    NormalizeQuaternion(dest);
+  }
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::AxisToQuaternion(float a[3], float phi, float q[4]) {
+
+  vNormal(a);
+  vCopy(a, q);
+  vScale(q, (float) (sin(phi / 2.0)));
+  q[3] = (float) (cos(phi / 2.0));
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::Clear() {
+
+  // Reset last x, y position
+  _lastX = 0.0;
+  _lastY = 0.0;
+
+  // Reset current quaternion
+  _currentQuaternion[0] = 0.0;
+  _currentQuaternion[1] = 0.0;
+  _currentQuaternion[2] = 0.0;
+  _currentQuaternion[3] = 1.0;
+
+  // Reset last quaternion
+  _lastQuaternion[0] = 0.0;
+  _lastQuaternion[1] = 0.0;
+  _lastQuaternion[2] = 0.0;
+  _lastQuaternion[3] = 1.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::GetAxisAngle(float* angle, float axis[3]) {
+
+  // Computer angle
+  *angle = _phi * 180.0f / 3.141517;
+
+  // Set axis
+  for (int i = 0 ; i < 3 ;i++) {
+    axis[i] = _axis[i];
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::GetRotationMatrix(float m[16]) {
+
+  // Build rotation matrix given a quaternion rotation
+  m[0] = (float)(1.0 - 2.0 * (_currentQuaternion[1] * _currentQuaternion[1] + 
+                              _currentQuaternion[2] * _currentQuaternion[2]));
+  m[1] = (float)(2.0 * (_currentQuaternion[0] * _currentQuaternion[1] - 
+                        _currentQuaternion[2] * _currentQuaternion[3]));
+  m[2] = (float)(2.0 * (_currentQuaternion[2] * _currentQuaternion[0] + 
+                        _currentQuaternion[1] * _currentQuaternion[3]));
+  m[3] = (float)(0.0);
+
+
+  m[4] = (float)(2.0 * (_currentQuaternion[0] * _currentQuaternion[1] + 
+                        _currentQuaternion[2] * _currentQuaternion[3]));
+  m[5] = (float)(1.0 - 2.0 * (_currentQuaternion[2] * _currentQuaternion[2] + 
+                              _currentQuaternion[0] * _currentQuaternion[0]));
+  m[6] = (float)(2.0 * (_currentQuaternion[1] * _currentQuaternion[2] - 
+                        _currentQuaternion[0] * _currentQuaternion[3]));
+  m[7] = (float)(0.0);
+
+
+  m[8] = (float)(2.0 * (_currentQuaternion[2] * _currentQuaternion[0] - 
+                        _currentQuaternion[1] * _currentQuaternion[3]));
+  m[9] = (float)(2.0 * (_currentQuaternion[1] * _currentQuaternion[2] + 
+                        _currentQuaternion[0] * _currentQuaternion[3]));
+  m[10] = (float)(1.0 - 2.0 * (_currentQuaternion[1] * _currentQuaternion[1] +
+                               _currentQuaternion[0] * _currentQuaternion[0]));
+  m[11] = (float)(0.0);
+
+
+  m[12] = (float)(0.0);
+  m[13] = (float)(0.0);
+  m[14] = (float)(0.0);
+  m[15] = (float)(1.0);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::NormalizeQuaternion(float q[4]) {
+
+    float mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
+
+    for (int i = 0 ; i < 4 ; i++) {
+      q[i] /= mag;
+    }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Trackball::ProjectToSphere(float r, float x, float y) {
+
+  float d;
+  float t;
+  float z;
+
+  d = (float) (sqrt(x * x + y * y));
+
+  // Inside sphere
+  if (d < r * 0.70710678118654752440) {
+    z = (float) (sqrt(r*r - d*d));
+  } 
+
+  // On hyperbola
+  else {
+    t = (float) (r / 1.41421356237309504880);
+    z = t * t / d;
+  }
+
+  return z;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::Reapply() {
+
+  // Add quaternions
+  AddQuaternions(_lastQuaternion, _currentQuaternion, _currentQuaternion);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::Start(float x, float y) {
+
+  _lastX = x;
+  _lastY = y;
+  vZero(_lastQuaternion);
+  _lastQuaternion[3] = 1.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::Update(float x, float y) {
+
+  float p1[3];
+  float p2[3];
+  float d[3];
+  float t;
+
+  // If no movement then return
+  if (_lastX == x && _lastY == y) {
+    vZero(_lastQuaternion);
+    _lastQuaternion[3] = 1.0;
+    return;
+  }
+
+  // Figure out z-coordinates for projection of P1 and P2 to deformed sphere
+  vSet(p1, _lastX, _lastY, ProjectToSphere(_trackballSize, _lastX, _lastY));
+  vSet(p2, x, y, ProjectToSphere(_trackballSize, x, y));
+
+  // Computer the cross product of P1 and P2
+  vCross(p2, p1, _axis);
+
+  // Determine amount to rotate around that axis
+  vSub(p1, p2, d);
+  t = (float)(vLength(d) / (2.0 * _trackballSize));
+
+  // Avoid problems with out-of-control values.
+  if (t > 1.0) t = 1.0;
+  if (t < -1.0) t = -1.0;
+  _phi = (float)(2.0 * asin(t));
+
+  // Convert axis to quaternion
+  AxisToQuaternion(_axis, _phi, _lastQuaternion);
+
+  // Update last x, y position
+  _lastX = x;
+  _lastY = y;
+
+  // Add quaternions
+  AddQuaternions(_lastQuaternion, _currentQuaternion, _currentQuaternion);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vAdd(const float* src1, const float* src2, float* dst) {
+
+  dst[0] = src1[0] + src2[0];
+  dst[1] = src1[1] + src2[1];
+  dst[2] = src1[2] + src2[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vCopy(const float* v1, float* v2) {
+
+  v2[0] = v1[0];
+  v2[1] = v1[1];
+  v2[2] = v1[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vCross(const float* v1, const float* v2, float* cross) {
+
+  float temp[3];
+
+  temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+  temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+  temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+
+  vCopy(temp, cross);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Trackball::vDot(const float* v1, const float* v2) {
+
+  return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float Trackball::vLength(const float* v) {
+
+  return (float) (sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vNormal(float* v) {
+
+  vScale(v, (float) (1.0 / vLength(v)));
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vScale(float* v, float div) {
+
+  v[0] *= div;
+  v[1] *= div;
+  v[2] *= div;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vSet(float* v, float x, float y, float z) {
+
+  v[0] = x;
+  v[1] = y;
+  v[2] = z;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vSub(const float* src1, const float* src2, float* dst) {
+
+  dst[0] = src1[0] - src2[0];
+  dst[1] = src1[1] - src2[1];
+  dst[2] = src1[2] - src2[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Trackball::vZero(float* v) {
+
+  v[0] = 0.0;
+  v[1] = 0.0;
+  v[2] = 0.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Master.h
===================================================================
--- trunk/src/testing/app/VRA/src/Master.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Master.h	(revision 4)
@@ -0,0 +1,362 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef MASTER_H
+#define MASTER_H
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef SAGE
+#include <sail.h>
+#include <misc.h>
+#endif
+
+#include <stdio.h>
+
+#include "Communicator.h"
+#include "FrustumCalculator.h"
+#include "Matrix.h"
+#include "Octree.h"
+#include "OctreeNode.h"
+#include "SynchronizerServer.h"
+#include "SynchronizerServerAbstractCommand.h"
+#include "Trackball.h"
+#include "UserInterfaceServer.h"
+#include "UserInterfaceServerAbstractCommand.h"
+#include "Vertex.h"
+
+/*--------------------------------------------------------------------------*/
+
+class Master {
+
+public:
+
+  // Constructor
+  Master(Communicator* communicator);
+
+  // Destructor
+  ~Master();
+
+  // Get axis on callback
+  void GetAxis(bool* state);
+
+  // Get axis position callback
+  void GetAxisPosition(float* x, float* y, float* z);
+
+  // Get brick box callback
+  void GetBrickBox(bool* state);
+
+  // Get bounding box callback
+  void GetBoundingBox(bool* state);
+
+  // Get clipping planes callback
+  void GetClippingPlanes(int node, float* near, float* far);
+
+  // Get data callback
+  void GetData(char* filename);
+
+  // Get data callback
+  void GetData(char* filename, int* ramSize, int* vramSize);
+
+  // Get dataset list callback
+  void GetDatasetListFile(int index, char* file);
+
+  // Get dataset list callback
+  void GetDatasetListName(int index, char* name);
+
+  // Get dataset list callback
+  void GetDatasetListPrefix(int index, char* prefix);
+
+  // Get dataset list size
+  void GetDatasetListSize(int* size);
+
+  // Get dataset type
+  void GetDatasetType(int* type);
+
+  // Get display size callback
+  void GetDisplaySize(int node, int* width, int* height, 
+                      bool* fullScreen,
+                      float* left, float* right, 
+                      float* bottom, float* top);
+
+  // Get frustum callback
+  void GetFrustum(int node, float* left, float* right,
+                  float* bottom, float* top);
+
+  // Get map callback
+  void GetMap(unsigned char* map);
+
+  // Get overview vertices
+  void GetOverviewVertices(float vertices[24]);
+
+  // Get prefix callback
+  void GetPrefix(char* prefix);
+
+  // Get rotation matrix callback
+  void GetRotationMatrix(float m[16]);
+
+  // Get scale matrix callback
+  void GetScaleMatrix(float m[16]);
+
+  // Get slice frequency
+  void GetSliceFrequency(double* frequency);
+
+  // Get total display dimensions
+  void GetTotalDisplayDimensions(int* w, int* h);
+
+  // Get total display frustum
+  void GetTotalDisplayFrustum(float frustum[6]);
+
+  // Get translation matrix callback
+  void GetTranslationMatrix(float m[16]);
+
+  // Get vertical field of view callback
+  void GetVerticalFieldOfView(float* vFOV);
+
+  // Get viewport callback
+  void GetViewport(int node, int* x, int* y, int* w, int* h);
+
+  // Initialize
+  void Init(char* filename);
+
+  // Reset view
+  void ResetView();
+
+  // Main loop
+  void Run();
+
+  // Axis off callback
+  void UpdateAxisOff();
+
+  // Axis on callback
+  void UpdateAxisOn();
+
+  // Axis position callback
+  void UpdateAxisPosition(float x, float y, float z);
+
+  // Brick box off callback
+  void UpdateBrickBoxOff();
+
+  // Brick box on callback
+  void UpdateBrickBoxOn();
+
+  // Bounding box off callback
+  void UpdateBoundingBoxOff();
+
+  // Bounding box on callback
+  void UpdateBoundingBoxOn();
+
+  // Clipping planes callback
+  void UpdateClippingPlanes(int node, float near, float far);
+
+  // Exit callback
+  void UpdateCommandExit();
+
+  // Render callback
+  void UpdateCommandRender();
+
+  // Data callback
+  void UpdateData(char* filename);
+
+  // Data callback
+  void UpdateData(char* filename, int ramSize, int vramSize);
+
+  // Display size callback
+  void UpdateDisplaySize(int node, int width, int height, 
+                         bool fullScreen, char* hostname, int port,
+                         float left, float right, 
+                         float bottom, float top);
+
+  // Frustum callback
+  void UpdateFrustum(int node, float left, float right, 
+                     float bottom, float top);
+  
+  // 8-bit map callback
+  void UpdateMap(unsigned char* map);
+
+  // 16-bit map callback
+  void UpdateMap16(unsigned char* map);
+
+  // Prefix callback
+  void UpdatePrefix(char* prefix);
+
+  // Progress callback
+  void UpdateProgress(int value);
+
+  // Rotation matrix callback
+  void UpdateRotationMatrix(float m[16]);
+
+  // Scale matrix callback
+  void UpdateScaleMatrix(float m[16]);
+
+  // Slice frequency callback
+  void UpdateSliceFrequency(double frequency);
+
+  // Translation matrix callback
+  void UpdateTranslationMatrix(float m[16]);
+
+  // Viewport callback
+  void UpdateViewport(int node, int x, int y, int w, int h);
+
+private:
+
+  // Axis flag
+  bool _axisFlag;
+
+  // Axis position
+  float _axisPosition[3];
+
+  // Box around bricks flag
+  bool _brickBoxFlag;
+
+  // Bounding box around entire dataset flag
+  bool _boundingBoxFlag;
+
+  // Clipping planes
+  float** _clippingPlanes;
+
+  // Communicator
+  Communicator* _communicator;
+
+  // Data meta filename
+  char _dataFilename[1024];
+
+  // Data prefix
+  char _dataPrefix[1024];
+
+  // Dataset list dataset file name
+  char** _datasetListFile;
+
+  // Dataset list dataset name
+  char** _datasetListName;
+
+  // Dataset list dataset prefix
+  char** _datasetListPrefix;
+
+  // Data type
+  int _dataType;
+
+  // Display percentages
+  float** _displayPercentages;
+
+  // Display size
+  int** _displaySize;
+
+  // Exit flag
+  bool _exitFlag;
+
+  // Frustum
+  float** _frustum;
+
+  // Full screen flag
+  bool* _fullScreenFlag;
+
+  // Map
+  unsigned char* _map;
+
+  // Number of datasets in dataset list
+  int _numberOfDatasets;
+
+  // Number of levels in current dataset
+  int _numberOfLevels;
+
+  // Number of slaves
+  int _numberOfSlaves;
+
+  // Observer
+  UserInterfaceServerAbstractCommand* _observer;
+
+  // Progress observer
+  SynchronizerServerAbstractCommand* _progressObserver;
+
+  // Slice frequency
+  double _sliceFrequency;
+
+  // Transformation matrices
+  float _R[16];
+  float _S[16];
+  float _T[16];
+
+  // CacheRAM size
+  int _ramSize;
+
+  // CacheVRAM size
+  int _vramSize;
+
+  // Total display dimensions
+  int _totalDisplayWidth;
+  int _totalDisplayHeight;
+
+  // Total display frustum
+  float _totalDisplayFrustum[6];
+
+  // Synchronization server
+  SynchronizerServer _synchronizationServer;
+
+  // User interface server
+  UserInterfaceServer _userInterfaceServer;
+
+  // Overview vertices
+  Vertex _vertex[8];
+
+  // Vertical field of view
+  float _vFOV;
+
+  // Viewport
+  int** _viewport;
+
+#ifdef SAGE
+
+  // Positon of the rotate device in normalized window coordinates
+  float _rotatePosition[3];
+
+  // Position of scale device in normalized window coordinates
+  float _scalePosition[3];
+
+  // Position of scale device with respect to the untransfomred object
+  // in world space
+  float _scalePositionUntransformed[3];
+
+  // Trackball for SAGE rotation event
+  Trackball _eventTrackball;
+
+  // Position of translate device in normalized window coordinates
+  float _translatePosition[3];
+
+  // SAIL configuration
+  sailConfig _sageConfig;
+
+  // SAIL object
+  sail _sageInf;
+
+  // Scale in world space
+  float _worldScale[3];
+
+  // Translation in world space
+  float _worldTranslate[3];
+
+#endif
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif 
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Communicator.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Communicator.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Communicator.cpp	(revision 4)
@@ -0,0 +1,1307 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Communicator.h"
+#include <stdio.h>
+
+/*--------------------------------------------------------------------------*/
+
+Communicator::Communicator() {
+  
+  // Initialize number of nodes to 0
+  _numberOfNodes = 0;
+
+  // Initialize observer to NULL
+  _observer = NULL;
+
+  // Initialize rank to 0
+  _rank = 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Communicator::~Communicator() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::Barrier() {
+
+  // MPI Barrier
+  MPI_Barrier(MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::Destroy() {
+
+  // Finalize MPI
+  MPI_Finalize();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::GetCommand() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+
+  // Destination
+  int destination = 0;
+
+
+  // Get buffer
+  MPI_Bcast(buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+  // Unpack command from buffer
+  MPI_Unpack(buffer, 2048, &position, command,
+             8, MPI_CHAR, MPI_COMM_WORLD);
+
+  // Unpack destination from buffer
+  MPI_Unpack(buffer, 2048, &position, &destination,
+             1, MPI_INT, MPI_COMM_WORLD);
+
+
+  // axis off
+  if (!strcmp(command, "CMD_AOF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisOff();
+    }
+
+  }
+
+
+  // axis on
+  else if (!strcmp(command, "CMD_AON")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisOn();
+    }
+
+  }
+
+
+  // brick box off
+  else if (!strcmp(command, "CMD_BBF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBrickBoxOff();
+    }
+
+  }
+
+
+  // brick box on
+  else if (!strcmp(command, "CMD_BBN")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBrickBoxOn();
+    }
+
+  }
+
+
+  // bounding box off
+  else if (!strcmp(command, "CMD_BOF")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBoundingBoxOff();
+    }
+
+  }
+
+
+  // bounding box on
+  else if (!strcmp(command, "CMD_BON")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetBoundingBoxOn();
+    }
+
+  }
+
+
+  // axis position
+  else if (!strcmp(command, "CMD_APO")) {
+
+    // Unpack data from buffer
+    float data[3];
+    MPI_Unpack(buffer, 2048, &position, data, 3, MPI_FLOAT, MPI_COMM_WORLD);
+ 
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetAxisPosition(data[0], data[1], data[2]);
+    }
+
+  }
+
+
+  // clipping planes
+  else if (!strcmp(command, "CMD_CLI")) {
+
+    // Unpack data from buffer
+    float data[2];
+    MPI_Unpack(buffer, 2048, &position, data, 2, MPI_FLOAT, MPI_COMM_WORLD);
+ 
+    // Observer
+    if ((_observer != NULL) && (destination == GetRank())) {
+      _observer -> SetClippingPlanes(data[0], data[1]);
+    }
+
+  }
+
+
+  // exit
+  else if(!strcmp(command, "CMD_EXI")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetCommandExit();
+    }
+
+  }
+
+
+  // render
+  else if(!strcmp(command, "CMD_REN")) {
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetCommandRender();
+    }
+
+  }
+
+
+  // data
+  else if(!strcmp(command, "CMD_DAT")) {
+
+    // Unpack data from buffer
+    char data[1024];
+    int ramSize = 0;
+    int vramSize = 0;
+    MPI_Unpack(buffer, 2048, &position, data, 1024, MPI_CHAR, MPI_COMM_WORLD);
+    MPI_Unpack(buffer, 2048, &position, &ramSize, 1, MPI_INT, MPI_COMM_WORLD);
+    MPI_Unpack(buffer, 2048, &position, &vramSize, 1, MPI_INT, MPI_COMM_WORLD);
+
+    // Observer 
+    if (_observer !=NULL) {
+      if (ramSize == -1 || vramSize == -1) {
+        _observer -> SetData(data);
+      }
+      else {
+        _observer -> SetData(data, ramSize, vramSize);
+      }
+    }
+
+  }
+
+
+  // display size
+  else if(!strcmp(command, "CMD_DIS")) {
+
+    // Unpack data from buffer
+    int data[3];
+    char host[128];
+    int port;
+    float normalCoordinates[4];
+    MPI_Unpack(buffer, 2048, &position, data, 3, MPI_INT, MPI_COMM_WORLD);
+    MPI_Unpack(buffer, 2048, &position, host, 128, MPI_CHAR, MPI_COMM_WORLD);
+    MPI_Unpack(buffer, 2048, &position, &port, 1, MPI_INT, MPI_COMM_WORLD);
+    MPI_Unpack(buffer, 2048, &position, normalCoordinates, 4, 
+               MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Full screen flag
+    bool fullScreen = false;
+    if (data[2] == 1) {
+      fullScreen = true;
+    }
+
+    // Observer
+    if ((_observer != NULL) && (destination == GetRank())) {
+      _observer -> SetDisplaySize(data[0], data[1], fullScreen, host, port,
+                                  normalCoordinates[0], normalCoordinates[1],
+                                  normalCoordinates[2], normalCoordinates[3]);
+    }
+
+  }
+
+
+  // frustum
+  else if(!strcmp(command, "CMD_FRU")) {
+
+    // Unpack data from buffer
+    float data[4];
+    MPI_Unpack(buffer, 2048, &position, data, 4, MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Observer
+    if ((_observer != NULL) && (destination == GetRank())) {
+      _observer -> SetFrustum(data[0], data[1], data[2], data[3]);
+    }
+
+  }
+
+
+  // 8-bit map
+  else if(!strcmp(command, "CMD_MAP")) {
+    
+    // Allocate space for data
+    unsigned char* data = new unsigned char[1024];
+
+    // Unpack data from buffer
+    MPI_Unpack(buffer, 2048, &position, data, 1024, MPI_BYTE, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetMap(data);
+    }
+
+  }
+
+
+  // 16-bit map
+  else if(!strcmp(command, "CMD_M16")) {
+    
+    // Payload position
+    int payloadPosition = 0;
+
+    // Payload
+    unsigned char payload[65536*4];
+
+    // Allocate space for data
+    unsigned char* data = new unsigned char[65536*4];
+
+    // MPI Barrier
+    MPI_Barrier(MPI_COMM_WORLD);    
+
+    // Get buffer
+    MPI_Bcast(payload, 65536*4, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+    // Unpack data from buffer
+    MPI_Unpack(payload, 65536*4, &payloadPosition, data, 65536*4, 
+               MPI_BYTE, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetMap16(data);
+    }
+
+  }
+
+
+  // prefix
+  else if(!strcmp(command, "CMD_PRE")) {
+
+    // Unpack data from buffer
+    char prefix[1024];
+    MPI_Unpack(buffer, 2048, &position, prefix, 1024, 
+               MPI_CHAR, MPI_COMM_WORLD);
+
+    // Observer 
+    if (_observer != NULL) {
+      _observer -> SetPrefix(prefix);
+    }
+
+  }
+
+
+  // rotation matrix
+  else if(!strcmp(command, "CMD_ROT")) {
+
+    // Unpack data from buffer
+    float data[16];
+    MPI_Unpack(buffer, 2048, &position, data, 16, MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetRotationMatrix(data);
+    }
+
+  }
+
+
+  // scale matrix
+  else if(!strcmp(command, "CMD_SCA")) {
+
+    // Unpack data from buffer
+    float data[16];
+    MPI_Unpack(buffer, 2048, &position, data, 16, MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetScaleMatrix(data);
+    }
+
+  }
+
+
+  // slice frequency
+  else if(!strcmp(command, "CMD_SLF")) {
+
+    // Unpack data from buffer
+    float data;
+    MPI_Unpack(buffer, 2048, &position, &data, 1, MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetSliceFrequency((double) data);
+    }
+
+  }
+
+
+  // translation matrix
+  else if(!strcmp(command, "CMD_TRA")) {
+
+    // Unpack data from buffer
+    float data[16];
+    MPI_Unpack(buffer, 2048, &position, data, 16, MPI_FLOAT, MPI_COMM_WORLD);
+
+    // Observer
+    if (_observer != NULL) {
+      _observer -> SetTranslationMatrix(data);
+    }
+
+  }
+
+
+  // viewport
+  else if(!strcmp(command, "CMD_VIE")) {
+
+    // Unpack data from buffer
+    int data[4];
+    MPI_Unpack(buffer, 2048, &position, data, 4, MPI_INT, MPI_COMM_WORLD);
+
+    // Observer
+    if ((_observer != NULL) && (destination == GetRank())) {
+      _observer -> SetViewport(data[0], data[1], data[2], data[3]);
+    }
+
+  }
+
+
+  // undefined command
+  else {
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::GetMasterNodeName(char* name) {
+  
+  // Check for NULL
+  if (name != NULL) {
+
+    // Copy name
+    strcpy(name, _masterNodeName);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::GetNodeName(char* name) {
+
+  // Check for NULL
+  if (name != NULL) {
+
+    // Copy name
+    strcpy(name, _nodeName);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Communicator::GetNumberOfNodes() {
+
+  // Get number of nodes
+  return _numberOfNodes;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Communicator::GetRank() {
+
+  // Get rank
+  return _rank;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::Init(int argc, char** argv) {
+
+  // Length of node name
+  int length = 0;
+
+  // Initialize MPI and get the number of nodes, current rank and node name
+  if (MPI_Init(&argc, &argv) == MPI_SUCCESS) {
+
+    // Get number of nodes, current rank and node name
+    MPI_Comm_size(MPI_COMM_WORLD, &_numberOfNodes);
+    MPI_Comm_rank(MPI_COMM_WORLD, &_rank);
+    MPI_Get_processor_name(_nodeName, &length);
+
+    // Synchronize nodes
+    MPI_Barrier(MPI_COMM_WORLD);
+    
+    // Send name of master node to all nodes
+    if (_rank == 0) {
+      strcpy(_masterNodeName, _nodeName);
+      MPI_Bcast(&_nodeName, MPI_MAX_PROCESSOR_NAME, 
+                MPI_CHAR, 0, MPI_COMM_WORLD);
+    }
+    else {
+      MPI_Bcast(&_masterNodeName, MPI_MAX_PROCESSOR_NAME,
+                MPI_CHAR, 0, MPI_COMM_WORLD);
+    }
+
+    // Synchronize nodes
+    MPI_Barrier(MPI_COMM_WORLD);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendAxisOff() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AOF");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendAxisOn() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_AON");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendAxisPosition(float x, float y, float z) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_APO");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(&x, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&y, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&z, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendBrickBoxOff() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBF");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendBrickBoxOn() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BBN");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendBoundingBoxOff() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BOF");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendBoundingBoxOn() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_BON");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendClippingPlanes(int node, float near, float far) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_CLI");
+
+  // Destination
+  int destination = node;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(&near, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&far, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendCommandExit() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_EXI");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendCommandRender() {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_REN");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendData(char* filename) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Default cache sizes: -1 tells the slave communicator processes to call
+  // versions of SetData/UpdateData that don't specify cache sizes. This
+  // is something to sort out in the future.
+  int ramSize = -1;
+  int vramSize = -1;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(filename, 1024, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&ramSize, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&vramSize, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendData(char* filename, int ramSize, int vramSize) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DAT");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(filename, 1024, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&ramSize, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&vramSize, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendDisplaySize(int node, 
+                                   int width, 
+                                   int height, 
+                                   bool fullScreen, 
+                                   char* hostname, 
+                                   int port,
+                                   float left,
+                                   float right,
+                                   float bottom,
+                                   float top) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_DIS");
+
+  // Destination
+  int destination = node;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Convert full screen flag from bool to integer
+  int flag = 0;
+  if (fullScreen == true) {
+    flag = 1;
+  }
+
+  // Pack data
+  MPI_Pack(&width, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&height, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&flag, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(hostname, 128, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&port, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&left, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&right, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&bottom, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&top, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendFrustum(int node, float left, float right,
+                               float bottom, float top) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_FRU");
+
+  // Destination
+  int destination = node;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(&left, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&right, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&bottom, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&top, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendMap(unsigned char* map) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_MAP");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(map, 1024, MPI_BYTE, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendMap8(unsigned char* map) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_MAP");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(map, 1024, MPI_BYTE, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendMap16(unsigned char* map) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_M16");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+  // MPI Barrier
+  MPI_Barrier(MPI_COMM_WORLD);
+
+  // Position in payload
+  position = 0;
+
+  // Payload
+  unsigned char payload[65536*4];
+  memset(payload, 0, 65536*4);
+
+  // Pack data
+  MPI_Pack(map, 65536*4, MPI_BYTE, payload, 65536*4, 
+           &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&payload, 65536*4, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendPrefix(char* prefix) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_PRE");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(prefix, 1024, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendRotationMatrix(float matrix[16]) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_ROT");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(matrix, 16, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendScaleMatrix(float matrix[16]) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SCA");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(matrix, 16, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendSliceFrequency(double frequency) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_SLF");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  float data = (float) frequency;
+  MPI_Pack(&data, 1, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendTranslationMatrix(float matrix[16]) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_TRA");
+
+  // Destination
+  int destination = 0;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(matrix, 16, MPI_FLOAT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SendViewport(int node, int x, int y, int w, int h) {
+
+  // Position in buffer
+  int position = 0;
+
+  // Buffer
+  unsigned char buffer[2048];
+  memset(buffer, 0, 2048);
+
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "CMD_VIE");
+
+  // Destination
+  int destination = node;
+
+  // Pack command
+  MPI_Pack(command, 8, MPI_CHAR, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack destination
+  MPI_Pack(&destination, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Pack data
+  MPI_Pack(&x, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&y, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&w, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+  MPI_Pack(&h, 1, MPI_INT, buffer, 2048, &position, MPI_COMM_WORLD);
+
+  // Send command
+  MPI_Bcast(&buffer, 2048, MPI_BYTE, 0, MPI_COMM_WORLD);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Communicator::SetObserver(CommunicatorAbstractCommand* observer) {
+
+  // Set observer
+  _observer = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Lambda.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Lambda.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Lambda.cpp	(revision 4)
@@ -0,0 +1,77 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Lambda.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Lambda::Fl_Lambda(int x, int y, int w, int h, const char *l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Resize to the correct size
+  size(255, 115);
+
+  // Set modal
+  //set_modal();
+
+  // Create port input field
+  _portInput = new Fl_Input(45, 10, 200, 25, "Port:");
+  _portInput -> value("7000");
+
+  // Create connect button
+  _listenButton = new Fl_Return_Button(45, 80, 95, 25, "Listen");
+
+  // Create exit button
+  _cancelButton = new Fl_Button(150, 80, 95, 25, "Cancel");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Lambda::~Fl_Lambda() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Lambda::GetPort() {
+
+  // Return port
+  return atoi(_portInput -> value());
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Lambda::SetCancelButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _cancelButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Lambda::SetListenButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _listenButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/VolumeRenderer.h
===================================================================
--- trunk/src/testing/app/VRA/src/VolumeRenderer.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/VolumeRenderer.h	(revision 4)
@@ -0,0 +1,375 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef VOLUME_RENDERER_H
+#define VOLUME_RENDERER_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <Cg/cg.h>
+#include <Cg/cgGL.h>
+#include <GL/gl.h>
+
+#include "CacheRAM.h"
+#include "CacheVRAM.h"
+#include "FrustumPlanes.h"
+#include "Log.h"
+#include "Matrix.h"
+#include "Octree.h"
+#include "OctreeNodeQueue.h"
+#include "Vertex.h"
+#include "VolumeRendererCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+extern "C" {
+  extern void glTexImage3D(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei,
+                           GLint, GLenum, GLenum, const GLvoid*);
+}
+
+/*--------------------------------------------------------------------------*/
+
+class VolumeRenderer {
+  
+public:
+  
+  // Default constructor
+  VolumeRenderer();
+  
+  // Default destructor
+  ~VolumeRenderer();
+  
+  // Get data
+  Octree* GetData();
+
+  // Get frustum
+  void GetFrustum(float* left, float* right, float* bottom,
+                  float* top, float* near, float* far);
+
+  // Get frustum
+  void GetFrustum(float frustum[6]);
+
+  // Get color and opacity map
+  unsigned char* GetMap();
+
+  // Get rotation matrix
+  void GetR(double m[16]);
+
+  // Get scale matrix
+  void GetS(double m[16]);
+
+  // Get slice frequency/sample frequency
+  double GetSliceFrequency();
+
+  // Get translation matrix
+  void GetT(double m[16]);
+
+  // Get viewport
+  void GetViewport(int* x, int* y, int* w, int* h);
+
+  // Get viewport
+  void GetViewport(int viewport[4]);
+
+  // Initialize - Call this after the OpenGL rendering context has been created
+  bool Init();
+  
+  // User must call Init before any other method
+  bool IsInitialized();
+  
+  // Render
+  bool Render();
+
+  // Render axis
+  void RenderAxis();
+
+  // Render bounding box
+  void RenderBoundingBox(OctreeNode* node);
+
+  // Render bounding box
+  void RenderBoundingBox(Vertex v0, Vertex v1, Vertex v2, Vertex v3,
+                         Vertex v4, Vertex v5, Vertex v6, Vertex v7);
+
+  // Scale alpha values based on slice frequency
+  // newA = 
+  //       1.0 - ((1.0 - originalA) ^ originalSliceFrequency/newSliceFrequency)
+  void ScaleAlpha(double newSliceFrequency, double originalSliceFrequency,
+                  unsigned char* newTexture, unsigned char* originalTexture,
+                  int width, int height);
+
+  // Set abort render observer
+  void SetAbortRenderObserver(VolumeRendererCommand* observer);
+
+  // Set axis off
+  void SetAxisOff();
+
+  // Set axis on
+  void SetAxisOn();
+
+  // Set axis position
+  void SetAxisPosition(float x, float y, float z);
+
+  // Turn bounding box off
+  void SetBoundingBoxOff();
+
+  // Turn bounding box on
+  void SetBoundingBoxOn();
+
+  // Turn bounding box off
+  void SetBrickBoxOff();
+
+  // Turn bounding box on
+  void SetBrickBoxOn();
+
+  // Set data - Returns true if data is loaded, false otherwise. The data 
+  // should be allocated on the heap using the new operator. This class will 
+  // attempt to delete the data with the delete operator when new data is set 
+  // or when the destructor is called.
+  bool SetData(Octree* data);
+
+  // Set data - Returns true if data is loaded, false otherwise. The data 
+  // should be allocated on the heap using the new operator. This class will 
+  // attempt to delete the data with the delete operator when new data is set 
+  // or when the destructor is called.
+  bool SetData(Octree* data, int ramSize, int vramSize);
+  
+  // Set frustum
+  void SetFrustum(float left, float right, float bottom,
+                  float top, float near, float far);
+  
+  // Set frustum
+  void SetFrustum(float frustum[6]);
+
+  // Set 8-bit color and opacity map - This map should be allocated on the heap
+  // using the new operator. This class will attempt to delete the map with the
+  // delete operator when a new map is set, when the slice frequency is changed
+  // or when the destructor is called.
+  void SetMap(unsigned char* map);
+
+  // Set 8-bit color and opacity map - This map should be allocated on the heap
+  // using the new operator. This class will attempt to delete the map with the
+  // delete operator when a new map is set, when the slice frequency is changed
+  // or when the destructor is called.
+  void SetMapUnsigned8Int(unsigned char* map);
+
+  // Set 16-bit color and opacity map - This map should be allocated on the 
+  // heap using the new operator. This class will attempt to delete the map 
+  // with the delete operator when a new map is set, when the slice frequency 
+  // is changed and when the destructor is called.
+  void SetMapUnsigned16Int(unsigned char* map);
+
+  // Set progress observer
+  void SetProgressObserver(VolumeRendererCommand* observer);
+
+  // Set rotation matrix
+  void SetR(double m[16]);
+
+  // Set rotation matrix
+  void SetR(float m[16]);
+
+  // Set scale matrix
+  void SetS(double m[16]);
+
+  // Set scale matrix
+  void SetS(float m[16]);
+
+  // Set slice frquency/sample frequency
+  void SetSliceFrequency(double frequency);
+
+  // Set swap buffers observer
+  void SetSwapBuffersObserver(VolumeRendererCommand* observer);
+
+  // Set translation matrix
+  void SetT(double m[16]);
+
+  // Set translation matrix
+  void SetT(float m[16]);
+  
+  // Set viewport
+  void SetViewport(int x, int y, int w, int h);
+
+  // Set viewport
+  void SetViewport(int viewport[4]);
+  
+private:
+
+  // Print a message to stdout
+  void Assert(const char* message);
+
+  // Build queue of visible nodes. Uses a BFS and two queues to construct a
+  // queue of all visible nodes level by level.
+  void BuildVisibleNodeQueue();
+  
+  // Disable Cg
+  void DisableCg();
+
+  // Disable texture state in OpenGL
+  void DisableTextureGL();
+
+  // Enable Cg
+  void EnableCg();
+
+  // Enable texture state in OpenGL
+  void EnableTextureGL();
+
+  // Initialize Cg
+  bool InitCg();
+
+  // Compute intersection with bounding box - Returns one if there's an
+  // intersection and computes new values, returns zero otherwise.
+  int Intersect(double p0[3], double p1[3],       // bounding box coordinates
+                double t0[3], double t1[3],       // texture coordinates
+                double v0[3], double v1[3],       // view coordinates
+                double sp[3], double sn[3],       // slice plane point & normal
+                double pnew[3], double tnew[3], double vnew[3]);  // new values
+
+  // Load map texture
+  void LoadMapTexture(int w, int h);
+
+  // Render node
+  void RenderNode(OctreeNode* node);
+
+  // Render a single slice given the number of edges, texture coordinates,
+  // vertices, and the vertex order.
+  void RenderSlice(int numberOfEdges, double t[6][3], 
+                   double v[6][3], int order[6]);
+  
+  // Set the viewport and frustum
+  void SetViewportAndFrustum();
+
+  // Uninitialize Cg
+  void UnInitCg();
+
+  // Unload data texture
+  void UnloadDataTexture();
+
+  // Unload map texture
+  void UnloadMapTexture();
+
+  // Abort render observer
+  VolumeRendererCommand* m_abortRenderObserver;
+
+  // Render axis flag
+  bool m_axisFlag;
+
+  // Axis position
+  float m_axisPosition[3];
+
+  // Render bounding box flag
+  bool m_boundingBoxFlag;
+
+  // Render brick box flag
+  bool m_brickBoxFlag;
+
+  // RAM cache
+  CacheRAM* m_cacheRAM;
+
+  // VRAM cache
+  CacheVRAM* m_cacheVRAM;
+
+  // Cg context
+  CGcontext m_cgContext;
+
+  // Cg data texture
+  CGparameter m_cgFDataTexture;
+
+  // Cg map texture
+  CGparameter m_cgFMapTexture;
+
+  // Cg fragment profile
+  CGprofile m_cgFProfile;
+
+  // Cg fragment program
+  CGprogram m_cgFProgram;
+
+  // Data
+  Octree* m_data;
+
+  // Depth list: used by Render()
+  float* m_depthList;
+  
+  // Frustum and viewport
+  float m_frustum[6];
+  
+  // Frustum planes utility class
+  FrustumPlanes m_frustumPlanes;
+  
+  // User must call Init before any other method
+  bool m_isInitialized;
+
+  // Map loaded flag
+  bool m_isMapLoaded;
+
+  // Color and opacity map
+  unsigned char* m_map;
+
+  // Color and opacity map dimensions
+  int m_mapDimensions[2];
+
+  // Texture for map
+  GLuint m_mapTexture;
+
+  // Number of nodes on render list
+  int m_numberOfNodesOnRenderList;
+
+  // Original color and opacity map
+  unsigned char* m_originalMap;
+
+  // Original slice frequency
+  double m_originalSliceFrequency;
+
+  // Progress observer
+  VolumeRendererCommand* m_progressObserver;
+
+  // Queue
+  OctreeNodeQueue* m_queue;
+
+  // Traversal queue
+  OctreeNodeQueue* m_queueTraversal;
+
+  // Visible node queue
+  OctreeNodeQueue* m_queueVisible;
+  
+  // Rotation matrix
+  float m_R[16];
+
+  // Render list: used by Render()
+  OctreeNode** m_renderList;
+
+  // Scale matrix
+  float m_S[16];
+
+  // Slice frequency
+  double m_sliceFrequency;
+
+  // Swap buffer observer
+  VolumeRendererCommand* m_swapBuffersObserver;
+
+  // Translation matrix
+  float m_T[16];
+  
+  // Viewport
+  int m_viewport[4];
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Matrix.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Matrix.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Matrix.cpp	(revision 4)
@@ -0,0 +1,324 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Matrix.h"
+
+/*--------------------------------------------------------------------------*/
+
+void calc_rot_x(float matrix[16], float angle) {
+  
+  matrix[0] = 1.0;
+  matrix[1] = 0.0;
+  matrix[2] = 0.0;
+  matrix[3] = 0.0;
+  
+  matrix[4] = 0.0;
+  matrix[5] = cos(angle * 0.0174532);
+  matrix[6] = sin(angle * 0.0174532);
+  matrix[7] = 0.0;
+  
+  matrix[8] = 0.0;
+  matrix[9] = -sin(angle * 0.0174532);
+  matrix[10] = cos(angle * 0.0174532);
+  matrix[11] = 0.0;
+  
+  matrix[12] = 0.0;
+  matrix[13] = 0.0;
+  matrix[14] = 0.0;
+  matrix[15] = 1.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void calc_rot_y(float matrix[16], float angle) {
+  
+  matrix[0] = cos(angle * 0.0174532);
+  matrix[1] = 0.0;
+  matrix[2] = -sin(angle * 0.0174532);
+  matrix[3] = 0.0;
+  
+  matrix[4] = 0.0;
+  matrix[5] = 1.0;
+  matrix[6] = 0.0;
+  matrix[7] = 0.0;
+  
+  matrix[8] = sin(angle * 0.0174532);
+  matrix[9] = 0.0;
+  matrix[10] = cos(angle * 0.0174532);
+  matrix[11] = 0.0;
+  
+  matrix[12] = 0.0;
+  matrix[13] = 0.0;
+  matrix[14] = 0.0;
+  matrix[15] = 1.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void calc_rot_z(float matrix[16], float angle) {
+  
+  matrix[0] = cos(angle * 0.0174532);
+  matrix[1] = sin(angle * 0.0174532);
+  matrix[2] = 0.0;
+  matrix[3] = 0.0;
+  
+  matrix[4] = -sin(angle * 0.0174532);
+  matrix[5] = cos(angle * 0.0174532);
+  matrix[6] = 0.0;
+  matrix[7] = 0.0;
+  
+  matrix[8] = 0.0;
+  matrix[9] = 0.0;
+  matrix[10] = 1.0;
+  matrix[11] = 0.0;
+  
+  matrix[12] = 0.0;
+  matrix[13] = 0.0;
+  matrix[14] = 0.0;
+  matrix[15] = 1.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void calc_scale(float matrix[16], float x, float y, float z) {
+  
+  matrix[0] = x;
+  matrix[1] = 0.0;
+  matrix[2] = 0.0;
+  matrix[3] = 0.0;
+  
+  matrix[4] = 0.0;
+  matrix[5] = y;
+  matrix[6] = 0.0;
+  matrix[7] = 0.0;
+  
+  matrix[8] = 0.0;
+  matrix[9] = 0.0;
+  matrix[10] = z;
+  matrix[11] = 0.0;
+  
+  matrix[12] = 0.0;
+  matrix[13] = 0.0;
+  matrix[14] = 0.0;
+  matrix[15] = 1.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void calc_trans(float matrix[16], float x, float y, float z) {
+
+  matrix[0] = 1.0;
+  matrix[1] = 0.0;
+  matrix[2] = 0.0;
+  matrix[3] = 0.0;
+  
+  matrix[4] = 0.0;
+  matrix[5] = 1.0;
+  matrix[6] = 0.0;
+  matrix[7] = 0.0;
+
+  matrix[8]  = 0.0;
+  matrix[9]  = 0.0;
+  matrix[10] = 1.0;
+  matrix[11] = 0.0;
+  
+  matrix[12] = x;
+  matrix[13] = y;
+  matrix[14] = z;
+  matrix[15] = 1.0;
+  
+}
+
+/*--------------------------------------------------------------------------*/
+
+void inverse4x4(double out[16], double in[16]) {
+  
+  double det = (double) (in[0] * in[5] * in[10] -
+                         in[0] * in[6] * in[9] -
+                         in[1] * in[4] * in[10] +
+                         in[1] * in[6] * in[8] +
+                         in[2] * in[4] * in[9] -
+                         in[2] * in[5] * in[8]);
+
+  out[0] = (in[5] * in[10] - in[6] * in[9]) / det;
+  out[1] = (-in[1] * in[10] + in[2] * in[9]) / det;
+  out[2] = (in[1] * in[6] - in[2] * in[5]) / det;
+  out[3] = 0.0;
+
+  out[4] = (-in[4] * in[10] + in[6] * in[8]) / det;
+  out[5] = (in[0] * in[10] - in[2] * in[8])  /det;
+  out[6] = (-in[0] * in[6] + in[2] * in[4]) / det;
+  out[7] = 0.0;
+
+  out[8] = (in[4] * in[9] - in[5] * in[8]) / det;
+  out[9] = (-in[0] * in[9] + in[1] * in[8]) / det;
+  out[10] = (in[0] * in[5] - in[1] * in[4]) / det;
+  out[11] = 0.0;
+
+  out[12] = (-in[4] * in[9] * in[14] + in[4] * in[13] * in[10] +
+             in[5] * in[8] * in[14] - in[5] * in[12] * in[10] -
+             in[6] * in[8] * in[13] + in[6] * in[12] * in[9]) / det;
+  out[13] = (in[0] * in[9] * in[14] - in[0] * in[13] * in[10] -
+             in[1] * in[8] * in[14] + in[1] * in[12] * in[10] +
+             in[2] * in[8] * in[13] - in[2] * in[12] * in[9]) / det;
+  out[14] = (-in[0] * in[5] * in[14] + in[0] * in[13] * in[6] +
+             in[1] * in[4] * in[14] - in[1] * in[12] * in[6] -
+             in[2] * in[4] * in[13] + in[2] * in[12] * in[5]) / det;
+  out[15] = 1.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void inverse4x4(float out[16], float in[16]) {
+
+  float det = (float)(in[0] * in[5] * in[10] -
+                      in[0] * in[6] * in[9] -
+                      in[1] * in[4] * in[10] +
+                      in[1] * in[6] * in[8] +
+                      in[2] * in[4] * in[9] -
+                      in[2] * in[5] * in[8]);
+
+  out[0] = (in[5] * in[10] - in[6] * in[9]) / det;
+  out[1] = (-in[1] * in[10] + in[2] * in[9]) / det;
+  out[2] = (in[1] * in[6] - in[2] * in[5]) / det;
+  out[3] = 0.0;
+
+  out[4] = (-in[4] * in[10] + in[6] * in[8]) / det;
+  out[5] = (in[0] * in[10] - in[2] * in[8])  /det;
+  out[6] = (-in[0] * in[6] + in[2] * in[4]) / det;
+  out[7] = 0.0;
+
+  out[8] = (in[4] * in[9] - in[5] * in[8]) / det;
+  out[9] = (-in[0] * in[9] + in[1] * in[8]) / det;
+  out[10] = (in[0] * in[5] - in[1] * in[4]) / det;
+  out[11] = 0.0;
+
+  out[12] = (-in[4] * in[9] * in[14] + in[4] * in[13] * in[10] +
+             in[5] * in[8] * in[14] - in[5] * in[12] * in[10] -
+             in[6] * in[8] * in[13] + in[6] * in[12] * in[9]) / det;
+  out[13] = (in[0] * in[9] * in[14] - in[0] * in[13] * in[10] -
+             in[1] * in[8] * in[14] + in[1] * in[12] * in[10] +
+             in[2] * in[8] * in[13] - in[2] * in[12] * in[9]) / det;
+  out[14] = (-in[0] * in[5] * in[14] + in[0] * in[13] * in[6] +
+             in[1] * in[4] * in[14] - in[1] * in[12] * in[6] -
+             in[2] * in[4] * in[13] + in[2] * in[12] * in[5]) / det;
+  out[15] = 1.0;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+double maximum(double in1, double in2) {
+
+  // First value is greater than second value
+  if (in1 > in2) {
+    return in1;
+  }
+
+  // Second value is greater than or equal to first value
+  return in2;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+double minimum(double in1, double in2) {
+
+  // First value is less than second value
+  if (in1 < in2) {
+    return in1;
+  }
+
+  // Second value is less than or equal to first value
+  return in2;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void mult4x4(float out[16], float one[16], float two[16]) {
+
+  out[0] = one[0]*two[0] + one[4]*two[1] + one[8]*two[2] + one[12]*two[3];
+  out[1] = one[1]*two[0] + one[5]*two[1] + one[9]*two[2] + one[13]*two[3];
+  out[2] = one[2]*two[0] + one[6]*two[1] + one[10]*two[2] + one[14]*two[3];
+  out[3] = one[3]*two[0] + one[7]*two[1] + one[11]*two[2] + one[15]*two[3];
+  
+  out[4] = one[0]*two[4] + one[4]*two[5] + one[8]*two[6] + one[12]*two[7];
+  out[5] = one[1]*two[4] + one[5]*two[5] + one[9]*two[6] + one[13]*two[7];
+  out[6] = one[2]*two[4] + one[6]*two[5] + one[10]*two[6] + one[14]*two[7];
+  out[7] = one[3]*two[4] + one[7]*two[5] + one[11]*two[6] + one[15]*two[7];
+  
+  out[8] = one[0]*two[8] + one[4]*two[9] + one[8]*two[10] + one[12]*two[11];
+  out[9] = one[1]*two[8] + one[5]*two[9] + one[9]*two[10] + one[13]*two[11];
+  out[10] = one[2]*two[8] + one[6]*two[9] + one[10]*two[10] + one[14]*two[11];
+  out[11] = one[3]*two[8] + one[7]*two[9] + one[11]*two[10] + one[15]*two[11];
+  
+  out[12] 
+    = one[0]*two[12] + one[4]*two[13] + one[8]*two[14] + one[12]*two[15];
+  out[13] 
+    = one[1]*two[12] + one[5]*two[13] + one[9]*two[14] + one[13]*two[15];
+  out[14]
+    = one[2]*two[12] + one[6]*two[13] + one[10]*two[14] + one[14]*two[15];
+  out[15]
+    = one[3]*two[12] + one[7]*two[13] + one[11]*two[14] + one[15]*two[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void normalize3V(double in[3]) {
+
+  // Lenght of vector
+  double  len = (double) sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]); 
+
+  // Divide each component of input vector by its length
+  if (len > 0){
+    in[0] /= len;
+    in[1] /= len;
+    in[2] /= len;
+  }
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void sub3V(double out[3], double in1[3], double in2[3]) {
+
+  out[0] = in1[0] - in2[0];
+  out[1] = in1[1] - in2[1];
+  out[2] = in1[2] - in2[2];
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+void translate3V(double out[3], double in1[16], double in2[3]) {
+
+  out[0] = in1[0] * in2[0] + in1[4] * in2[1] + in1[8] * in2[2];
+  out[1] = in1[1] * in2[0] + in1[5] * in2[1] + in1[9] * in2[2];
+  out[2] = in1[2] * in2[0] + in1[6] * in2[1] + in1[10] * in2[2];
+
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheVRAMNode.h
===================================================================
--- trunk/src/testing/app/VRA/src/CacheVRAMNode.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheVRAMNode.h	(revision 4)
@@ -0,0 +1,74 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef CACHE_VRAM_NODE_H
+#define CACEH_VRAM_NODE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class CacheVRAMNode {
+
+public:
+
+  // Default constructor
+  CacheVRAMNode();
+
+  // Default destructor
+  ~CacheVRAMNode();
+
+  // Get next node
+  CacheVRAMNode* GetNext();
+
+  // Get node
+  OctreeNode* GetOctreeNode();
+
+  // Get previous node
+  CacheVRAMNode* GetPrevious();
+
+  // Set next node
+  void SetNext(CacheVRAMNode* node);
+
+  // Set node
+  void SetOctreeNode(OctreeNode* node);
+
+  // Set previous node
+  void SetPrevious(CacheVRAMNode* node);
+
+private:
+
+  // Node
+  OctreeNode* _node;
+
+  // Previous node in list
+  CacheVRAMNode* _previous;
+
+  // Next node in list
+  CacheVRAMNode* _next;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.h	(revision 4)
@@ -0,0 +1,75 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_SLICE_FREQUENCY_H
+#define FL_SLICE_FREQUENCY_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Counter.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Slice_Frequency : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Slice_Frequency(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Slice_Frequency();
+
+  // Get slice frequency
+  double GetSliceFrequency();
+
+  // Set ok button callback
+  void SetOKButtonCallback(Fl_Callback* cb, void* v);
+
+  // Set cancel button callback
+  void SetCancelButtonCallback(Fl_Callback* cb, void* v);
+
+  // Set slice frequency
+  void SetSliceFrequency(double frequency);
+
+private:
+
+  // OK button
+  Fl_Return_Button* _okButton;
+
+  // Cancel button
+  Fl_Button* _cancelButton;
+
+  // Slice frequency counter
+  Fl_Counter* _counter;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Color_Transfer_Function.cpp	(revision 4)
@@ -0,0 +1,473 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Color_Transfer_Function.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Color_Transfer_Function::Fl_Color_Transfer_Function(int x, int y, 
+                                                       int w, int h, 
+                                                       const char *l) 
+  : Fl_Gl_Window(x, y, w, h, l) {
+
+  // Initialize callbacks
+  _callbackMove = NULL;
+  _callbackSelect = NULL;
+  _callbackUnselect = NULL;
+
+  // Initialize callback data
+  _callbackMovePtr = NULL;
+  _callbackSelectPtr = NULL;
+  _callbackUnselectPtr = NULL;
+
+  // Initialize control point picked
+  _controlPointPicked = -1;
+
+  // Create new transfer function widget
+  _ctfw = new ColorTransferFunctionWidget(w, h);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Color_Transfer_Function::~Fl_Color_Transfer_Function() {
+
+  // Clean up
+  delete _ctfw;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::GetControlPoint(int index, float* scalar, 
+                                                 float* r, float* g, float* b) {
+
+  // Get control point
+  _ctfw -> GetControlPoint(index, scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Color_Transfer_Function::GetControlPointIndex(int px, int py) {
+
+  // Get control point index
+  return _ctfw -> GetControlPointIndex(px, py);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Color_Transfer_Function::GetControlPointIndex(float scalar) {
+
+  // Get control point index
+  return _ctfw -> GetControlPointIndex(scalar);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Color_Transfer_Function::GetFunctionCoordinates(int px, int py, 
+                                                        float* scalar, float* r,
+                                                        float* g, float* b) {
+
+  // Get function coordinates
+  return _ctfw -> GetFunctionCoordinates(px, py, scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Color_Transfer_Function::GetNumberOfControlPoints() {
+
+  // Get number of control points
+  return _ctfw -> GetNumberOfControlPoints();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Color_Transfer_Function::GetSelectedControlPoint() {
+
+  // Return slected control point
+  return _controlPointPicked;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::GetColor(float scalar, float* r, float* g,
+                                           float* b) {
+
+  // Get color
+  _ctfw -> GetColor(scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::GetScalarRange(float* min, float* max) {
+
+  // Get scalar range
+  _ctfw -> GetScalarRange(min, max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Color_Transfer_Function::ModifyControlPointColor(int index, float r, 
+                                                         float g, float b) {
+
+  // Modify control point color
+  return _ctfw -> ModifyControlPointColor(index, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Color_Transfer_Function::MoveControlPoint(int index, int px, int py) {
+
+  // Move control point
+  return _ctfw -> MoveControlPoint(index, px, py);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Color_Transfer_Function::MoveControlPoint(int index, float scalar) {
+
+  // Move control point
+  return _ctfw -> MoveControlPoint(index, scalar);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool Fl_Color_Transfer_Function::RemoveControlPoint(int index) {
+
+  // Remove control point
+  return _ctfw -> RemoveControlPoint(index);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::RestoreControlPoints(int number, 
+                                                      float max, 
+                                                      float* scalar, 
+                                                      float* r,
+                                                      float* g,
+                                                      float* b) {
+
+  // Restore control points
+  _ctfw -> RestoreControlPoints(number, max, scalar, r, g, b);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetBackgroundColor(float r, float g, 
+                                                    float b, float a) {
+
+  // Set background color
+  _ctfw -> SetBackgroundColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetBoxColor(float r, float g, 
+                                             float b, float a) {
+
+  // Set box color
+  _ctfw -> SetBoxColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetControlPointColor(float r, float g, 
+                                                      float b, float a) {
+
+  // Set control point color
+  _ctfw -> SetControlPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetControlPointSize(int size) {
+
+  // Set control point size
+  _ctfw -> SetControlPointSize(size);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetFocusPointColor(float r, float g, 
+                                                    float b, float a) {
+
+  // Set focus point color
+  _ctfw -> SetFocusPointColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetLineColor(float r, float g, 
+                                              float b, float a) {
+
+  // Set line color
+  _ctfw -> SetLineColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetMaximumScalar(float max) {
+
+  // Set maximum scalar
+  _ctfw -> SetMaximumScalar(max);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetMoveCallback(void (*cb)(void*), 
+                                                 void* p) {
+
+  // Set callback
+  _callbackMove = cb;
+
+  // Set pointer
+  _callbackMovePtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetSelectCallback(void (*cb)(void*), 
+                                                   void* p) {
+
+  // Set callback
+  _callbackSelect = cb;
+
+  // Set pointer
+  _callbackSelectPtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetTextColor(float r, float g, 
+                                              float b, float a) {
+
+  // Set text color
+  _ctfw -> SetTextColor(r, g, b, a);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::SetUnselectCallback(void (*cb)(void*),
+                                                     void* p) {
+
+  // Set callback
+  _callbackUnselect = cb;
+
+  // Set pointer
+  _callbackUnselectPtr = p;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Color_Transfer_Function::draw() {
+
+  // Set dimensions
+  _ctfw -> SetDimensions(w(), h());
+
+  // Draw widget
+  _ctfw -> Draw();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Color_Transfer_Function::handle(int event) {
+
+  // Check event
+  switch(event) {
+
+
+  case FL_PUSH: {
+
+    // Get button
+    int button = Fl::event_button();
+
+    // Check select button
+    if (button == 1) {
+      _mouseButtonState[0] = DOWN;
+
+      // Get point picked
+      _controlPointPicked = 
+        _ctfw -> GetControlPointIndex(Fl::event_x(), Fl::event_y());
+
+      // Check callback
+      if (_callbackSelect != NULL && _callbackUnselect != NULL) {
+
+        // Unselect if no point picked
+        if (_controlPointPicked == -1) {
+          _callbackUnselect(_callbackUnselectPtr);
+        }
+
+        // Select if point picked
+        else {
+          _callbackSelect(_callbackSelectPtr);
+        }
+
+      }
+
+    }
+
+    // Check remove button
+    else if (button == 2) {
+      _mouseButtonState[1] = DOWN;
+
+      // Get point index
+      _controlPointPicked = 
+        _ctfw -> GetControlPointIndex(Fl::event_x(), Fl::event_y());
+
+      // Check callback
+      if (_callbackSelect != NULL && _callbackUnselect != NULL) {
+
+        // Unselect if point not removed
+        if (_ctfw -> RemoveControlPoint(_controlPointPicked) == true ||
+            _controlPointPicked == -1) {
+          _callbackUnselect(_callbackUnselectPtr);
+        }
+
+        // Select if no point removed
+        else {
+          _callbackSelect(_callbackSelectPtr);
+        }
+
+      }
+
+    }
+
+    // Check add button
+    else if (button == 3) {
+      _mouseButtonState[2] = DOWN;
+
+      // Check that a point was added
+      if (_ctfw -> AddControlPoint(Fl::event_x(), Fl::event_y()) == true) {
+
+        // Get scalar value for point added
+        float s, r, g, b;
+        GetFunctionCoordinates(Fl::event_x(), Fl::event_y(), &s, &r, &g, &b);
+
+        // Get point index for point added
+        _controlPointPicked = _ctfw -> GetControlPointIndex(s);
+
+        // Check callback
+        if (_callbackSelect != NULL) {
+          _callbackSelect(_callbackSelectPtr);
+        }
+
+      }
+
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_DRAG: {
+
+    // Move the picked control point
+    if (_mouseButtonState[0] == DOWN) {
+      _ctfw -> MoveControlPoint(_controlPointPicked, 
+                                Fl::event_x(), Fl::event_y());
+
+      // Check callback
+      if (_callbackMove != NULL) {
+        if (_controlPointPicked != -1) {
+          _callbackMove(_callbackMovePtr);
+        }
+      }
+
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  case FL_RELEASE: {
+
+    // Get button
+    int button = Fl::event_button();
+    
+    // Check which button
+    if (button == 1) {
+      _mouseButtonState[0] = UP;
+      //_controlPointPicked = -1;
+    }
+
+    // Draw scene
+    redraw();
+
+    // Swap buffers
+    swap_buffers();
+
+    // Return
+    return 1;
+
+  }
+
+
+  default: {
+
+    // Pass other events to the base class
+    return Fl_Gl_Window::handle(event);
+
+  }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Connect.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Connect.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Connect.cpp	(revision 4)
@@ -0,0 +1,90 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Connect.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Connect::Fl_Connect(int x, int y, int w, int h, const char *l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Resize to the correct size
+  size(255, 115);
+
+  // Set modal
+  //set_modal();
+
+  // Create host input field
+  _hostInput = new Fl_Input(45, 10, 200, 25, "Host:");
+  _hostInput -> value("localhost");
+
+  // Create port input field
+  _portInput = new Fl_Input(45, 45, 200, 25, "Port:");
+  _portInput -> value("10001");
+
+  // Create connect button
+  _connectButton = new Fl_Return_Button(45, 80, 95, 25, "Connect");
+
+  // Create exit button
+  _exitButton = new Fl_Button(150, 80, 95, 25, "Exit");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Connect::~Fl_Connect() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+const char* Fl_Connect::GetHost() {
+
+  // Return host
+  return _hostInput -> value();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Fl_Connect::GetPort() {
+
+  // Return port
+  return atoi(_portInput -> value());
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Connect::SetConnectButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _connectButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Connect::SetExitButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _exitButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Slave.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Slave.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Slave.cpp	(revision 4)
@@ -0,0 +1,509 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Communicator.h"
+#include "CommunicatorConcreteCommand.h"
+#include "Slave.h"
+
+/*--------------------------------------------------------------------------*/
+
+Slave::Slave(Communicator* communicator) {
+
+  // Initialize axis on flag
+  _axisOnFlag = false;
+
+  // Initialize axis position
+  _axisPosition[0] = 0.0;
+  _axisPosition[1] = 0.0;
+  _axisPosition[2] = 0.0;
+
+  // Initialize brick box on flag
+  _brickBoxOnFlag = false;
+
+  // Initialize bounding box on flag
+  _boundingBoxOnFlag = false;
+
+  // Initialize clipping planes
+  _clippingPlanes[0] = 0.0;
+  _clippingPlanes[1] = 0.0;
+
+  // Initialize communicator
+  _communicator = communicator;
+
+  // Initialize data
+  _data = NULL;
+
+  // Initialize data filename
+  memset(_dataFilename, 0, 1024);
+
+  // Initialize data prefix
+  memset(_dataPrefix, 0, 1024);
+
+  // Initialize display size
+  _displaySize[0] = 0;
+  _displaySize[1] = 0;
+
+  // Initialize exit flag
+  _exitFlag = false;
+
+  // Initialize frustum
+  _frustum[0] = 0.0;
+  _frustum[1] = 0.0;
+  _frustum[2] = 0.0;
+  _frustum[3] = 0.0;
+
+  // Initialize full screen flag
+  _fullScreenFlag = false;
+
+  // Initialize map
+  _map = NULL;
+
+  // Initialize normal coordinates
+  _normalCoordinates[0] = 0.0;
+  _normalCoordinates[1] = 0.0;
+  _normalCoordinates[2] = 0.0;
+  _normalCoordinates[3] = 0.0;
+
+  // Initialize and register observer with communicator
+  _observer = new CommunicatorConcreteCommand(this);
+  _communicator -> SetObserver(_observer);
+  if (_observer == NULL) {
+    fprintf(stderr, "Slave: Error creating CommunicatorConcreteCommand.\n");
+  }
+
+  // Slice frequency
+  _sliceFrequency = 1.0;
+
+  // Initialize rotation matrix
+  _R[0] = 1.0; _R[4] = 0.0; _R[8] = 0.0; _R[12] = 0.0;
+  _R[1] = 0.0; _R[5] = 1.0; _R[9] = 0.0; _R[13] = 0.0;
+  _R[2] = 0.0; _R[6] = 0.0; _R[10] = 1.0; _R[14] = 0.0;
+  _R[3] = 0.0; _R[7] = 0.0; _R[11] = 0.0; _R[15] = 1.0;
+
+  // Initialize scale matrix
+  _S[0] = 1.0; _S[4] = 0.0; _S[8] = 0.0; _S[12] = 0.0;
+  _S[1] = 0.0; _S[5] = 1.0; _S[9] = 0.0; _S[13] = 0.0;
+  _S[2] = 0.0; _S[6] = 0.0; _S[10] = 1.0; _S[14] = 0.0;
+  _S[3] = 0.0; _S[7] = 0.0; _S[11] = 0.0; _S[15] = 1.0;
+
+  // Initialize translation matrix
+  _T[0] = 1.0; _T[4] = 0.0; _T[8] = 0.0; _T[12] = 0.0;
+  _T[1] = 0.0; _T[5] = 1.0; _T[9] = 0.0; _T[13] = 0.0;
+  _T[2] = 0.0; _T[6] = 0.0; _T[10] = 1.0; _T[14] = 0.0;
+  _T[3] = 0.0; _T[7] = 0.0; _T[11] = 0.0; _T[15] = 1.0;
+
+  // Initialize viewport
+  _viewport[0] = 0;
+  _viewport[1] = 0;
+  _viewport[2] = 0;
+  _viewport[3] = 0;
+
+  // Initialize renderer
+  _volumeRendererShell = new VolumeRendererShell();
+  if (_volumeRendererShell == NULL) {
+    fprintf(stderr, "Slave: Error creating VolumeRendererShell.\n");
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Slave::~Slave() {
+
+  // Clean up observer
+  if (_observer != NULL) {
+    delete _observer;
+  }
+
+  // Clean up volume renderer shell
+  if (_volumeRendererShell != NULL) {
+    delete _volumeRendererShell;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::Run() {
+
+  // Event loop
+  while (_exitFlag == false) {
+
+    // Process a command from the Communicator
+    _communicator -> GetCommand();
+
+    // Sync with other nodes
+    _communicator -> Barrier();
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateAxisOff() {
+
+  // Update local variables
+  _axisOnFlag = false;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetAxisOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateAxisOn() {
+
+  // Update local variables
+  _axisOnFlag = true;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetAxisOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateAxisPosition(float x, float y, float z) {
+
+  // Update local variables
+  _axisPosition[0] = x;
+  _axisPosition[1] = y;
+  _axisPosition[2] = z;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetAxisPosition(x, y, z);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateBrickBoxOff() {
+
+  // Update local variables
+  _brickBoxOnFlag = false;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetBrickBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateBrickBoxOn() {
+
+  // Update local variables
+  _brickBoxOnFlag = true;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetBrickBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateBoundingBoxOff() {
+
+  // Update local variables
+  _boundingBoxOnFlag = false;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetBoundingBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateBoundingBoxOn() {
+
+  // Update local variables
+  _boundingBoxOnFlag = true;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetBoundingBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateClippingPlanes(float near, float far) {
+
+  // Update local variables
+  _clippingPlanes[0] = near;
+  _clippingPlanes[1] = far;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetFrustum(_frustum[0], _frustum[1], 
+                                     _frustum[2], _frustum[3],
+                                     _clippingPlanes[0], _clippingPlanes[1]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateCommandExit() {
+
+  // Update local variables
+  _exitFlag = true;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetExitFlag();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateCommandRender() {
+
+  // Update volume renderer
+  _volumeRendererShell -> Render();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateData(char* filename) {
+
+  // Update local variables
+  if (filename != NULL) {
+    strcpy(_dataFilename, filename);
+  }
+
+  // Allocate new octree
+  _data = new Octree();
+  if (_data == NULL) {
+    fprintf(stderr, "Slave: Memory allocation error while loading data.\n");
+    return;
+  }
+
+  // Load metadata
+  _data -> SetPrefix(_dataPrefix);
+  _data -> LoadFromFile2(_dataFilename);
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetData(_data);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateData(char* filename, int ramSize, int vramSize) {
+
+  // Update local variables
+  if (filename != NULL) {
+    strcpy(_dataFilename, filename);
+  }
+
+  // Allocate new octree
+  _data = new Octree();
+  if (_data == NULL) {
+    fprintf(stderr, "Slave: Memory allocation error while loading data.\n");
+    return;
+  }
+
+  // Load metadata
+  _data -> SetPrefix(_dataPrefix);
+  _data -> LoadFromFile2(_dataFilename);
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetData(_data, ramSize, vramSize);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateDisplaySize(int width, int height, bool fullScreen, 
+                              char* hostname, int port,
+                              float left, float right, 
+                              float bottom, float top) {
+
+  // Update local variables
+  _displaySize[0] = width;
+  _displaySize[1] = height;
+  _fullScreenFlag = fullScreen;
+  _normalCoordinates[0] = left;
+  _normalCoordinates[1] = right;
+  _normalCoordinates[2] = bottom;
+  _normalCoordinates[3] = top;
+
+  // Update volume renderer
+  _volumeRendererShell -> Init(_displaySize[0], 
+                               _displaySize[1], 
+                               _fullScreenFlag, 
+                               hostname, 
+                               port,
+                               _normalCoordinates[0],
+                               _normalCoordinates[1],
+                               _normalCoordinates[2],
+                               _normalCoordinates[3],
+                               _communicator -> GetRank(),
+                               _communicator -> GetNumberOfNodes());
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateFrustum(float left, float right, float bottom, float top) {
+
+  // Update local variables
+  _frustum[0] = left;
+  _frustum[1] = right;
+  _frustum[2] = bottom;
+  _frustum[3] = top;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetFrustum(_frustum[0], _frustum[1], 
+                                     _frustum[2], _frustum[3],
+                                     _clippingPlanes[0], _clippingPlanes[1]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+  
+void Slave::UpdateMap(unsigned char* map) {
+
+  // Update local variables
+  _map = map;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetMap(_map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+  
+void Slave::UpdateMap16(unsigned char* map) {
+
+  // Update local variables
+  _map = map;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetMap16(_map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdatePrefix(char* prefix) {
+
+  // Update local variables
+  if (prefix != NULL) {
+    strcpy(_dataPrefix, prefix);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateRotationMatrix(float m[16]) {
+
+  // Update local variables
+  _R[0] = m[0]; _R[4] = m[4]; _R[8] = m[8]; _R[12] = m[12];
+  _R[1] = m[1]; _R[5] = m[5]; _R[9] = m[9]; _R[13] = m[13];
+  _R[2] = m[2]; _R[6] = m[6]; _R[10] = m[10]; _R[14] = m[14];
+  _R[3] = m[3]; _R[7] = m[7]; _R[11] = m[11]; _R[15] = m[15];
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetR(_R);
+  _volumeRendererShell -> Render();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateScaleMatrix(float m[16]) {
+
+  // Update local variables
+  _S[0] = m[0]; _S[4] = m[4]; _S[8] = m[8]; _S[12] = m[12];
+  _S[1] = m[1]; _S[5] = m[5]; _S[9] = m[9]; _S[13] = m[13];
+  _S[2] = m[2]; _S[6] = m[6]; _S[10] = m[10]; _S[14] = m[14];
+  _S[3] = m[3]; _S[7] = m[7]; _S[11] = m[11]; _S[15] = m[15];
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetS(_S);
+  _volumeRendererShell -> Render();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateSliceFrequency(double frequency) {
+
+  // Update local variable
+  _sliceFrequency = frequency;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetSliceFrequency(frequency);
+  _volumeRendererShell -> Render();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateTranslationMatrix(float m[16]) {
+
+  // Update local variables
+  _T[0] = m[0]; _T[4] = m[4]; _T[8] = m[8]; _T[12] = m[12];
+  _T[1] = m[1]; _T[5] = m[5]; _T[9] = m[9]; _T[13] = m[13];
+  _T[2] = m[2]; _T[6] = m[6]; _T[10] = m[10]; _T[14] = m[14];
+  _T[3] = m[3]; _T[7] = m[7]; _T[11] = m[11]; _T[15] = m[15];
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetT(_T);
+  _volumeRendererShell -> Render();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Slave::UpdateViewport(int x, int y, int w, int h) {
+
+  // Update local variables
+  _viewport[0] = x;
+  _viewport[1] = y;
+  _viewport[2] = w;
+  _viewport[3] = h;
+
+  // Update volume renderer
+  _volumeRendererShell -> AbortRender(true);
+  _volumeRendererShell -> SetViewport(_viewport[0], _viewport[1], 
+                                      _viewport[2], _viewport[3]);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerConcreteCommand.h	(revision 4)
@@ -0,0 +1,57 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_SERVER_CONCRETE_COMMAND_H
+#define SYNCHRONIZER_SERVER_CONCRETE_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "SynchronizerServerAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+class SynchronizerServerConcreteCommand : 
+public SynchronizerServerAbstractCommand {
+
+public:
+
+  // Constructor
+  SynchronizerServerConcreteCommand();
+
+  // Constructor with pointer to instance of class Master
+  SynchronizerServerConcreteCommand(void* master);
+
+  // Destructor
+  virtual ~SynchronizerServerConcreteCommand();
+  
+  // Execute command
+  virtual bool Execute(int value);
+
+private:
+
+  // Pointer to instance of class master
+  void* _master;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.h	(revision 4)
@@ -0,0 +1,85 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_SERVER_LISTEN_THREAD_INFO_H
+#define SYNCHRONIZER_SERVER_LISTEN_THREAD_INFO_H
+
+/*---------------------------------------------------------------------------*/
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "SynchronizerServerAbstractCommand.h"
+#include "SynchronizerServerClientThreadInfo.h"
+
+/*---------------------------------------------------------------------------*/
+
+class SynchronizerServerListenThreadInfo {
+
+public:
+
+  // Default constructor
+  SynchronizerServerListenThreadInfo();
+
+  // Default destructor
+  ~SynchronizerServerListenThreadInfo();
+
+  // Client thread info
+  SynchronizerServerClientThreadInfo* _clientInfo;
+
+  // Client thread
+  pthread_t* _clientThread;
+
+  // Condition mutex
+  pthread_mutex_t* _conditionMutex;
+
+  // Condition variable
+  pthread_cond_t* _conditionVariable;
+
+  // Finalize flag
+  bool* _finalizeFlag;
+
+  // Current level
+  int* _level;
+
+  // Number of clients connected
+  int* _numberOfClients;
+
+  // Number of clients waiting at barrier
+  int* _numberOfClientsWaiting;
+
+  // Server port
+  int* _port;
+
+  // Progress observer
+  SynchronizerServerAbstractCommand* _progressObserver;
+
+  // Server address
+  struct sockaddr_in* _serverAddress;
+
+  // Server socket file descriptor
+  int* _serverSocketFileDescriptor;
+
+};
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UI.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/UI.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/UI.cpp	(revision 4)
@@ -0,0 +1,3090 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_File_Chooser.H>
+#include <pthread.h>
+#include <queue.h>
+#include <unistd.h>
+
+#include "DataPacker.h"
+#include "Fl_Connect.h"
+#include "Fl_Dialog.h"
+#include "Fl_Lambda.h"
+#include "Fl_Load_Data.h"
+#include "Fl_Main_Window.h"
+#include "Fl_Overview.h"
+#include "Fl_Slice_Frequency.h"
+#include "Fl_Transfer_Function.h"
+#include "Trackball.h"
+#include "UserInterfaceClient.h"
+#include "UserInterfaceClientConcreteCommand.h"
+#include "Vertex.h"
+
+/*--------------------------------------------------------------------------*/
+
+static void message_cb(Fl_Button* b, void* v);
+static void stopLambda_cb(Fl_Button* b, void* v);
+static void message_data_cb(Fl_Button* b, void* v);
+static void connect_cb(Fl_Button* b, void* v);
+static void exit_cb(Fl_Button* b, void* v);
+static void render_cb();
+void *lambda_thread_function(void* ptr);
+static void mes_script_cb(Fl_Button* b, void* v);
+static void overview_cb(Fl_Widget *w, void *data);
+static void map_cb(void* d);
+static void menu_axis_cb();
+static void menu_bounding_cb();
+static void menu_brick_cb();
+static void slice_frequency();
+static void slice_ok_cb(Fl_Button* b, void* v);
+static void slice_cancel_cb(Fl_Button* b, void* v);
+void run_script(const char* filename);
+
+/*--------------------------------------------------------------------------*/
+
+float goodx = 0.0;
+float goody = 0.0;
+
+// Menu items
+static Fl_Menu_Item g_miAxis = 
+  {"Axis", 0, (Fl_Callback*) menu_axis_cb, 0, FL_MENU_TOGGLE};
+static Fl_Menu_Item g_miBoundingBox = 
+  {"Bounding Box", 0, (Fl_Callback*) menu_bounding_cb, 0, FL_MENU_TOGGLE};
+static Fl_Menu_Item g_miBrickBoxes = 
+  {"Brick Boxes", 0, (Fl_Callback*) menu_brick_cb, 0, FL_MENU_TOGGLE};
+
+// User interface client
+static UserInterfaceClient* client = NULL;
+
+// Dataset list size
+static int datasetListSize = 0;
+
+// Dataset list file
+static char** datasetListFile = NULL;
+
+// Dataset list name
+static char** datasetListName = NULL;
+
+// Dataset list prefix
+static char** datasetListPrefix = NULL;
+
+// User interface client observer
+static UserInterfaceClientConcreteCommand* observer = NULL;
+
+// Message queue
+static queue<unsigned char*> messageQueue;
+
+// Message queue mutex
+static pthread_mutex_t messageMutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Connect window
+static Fl_Connect* connectWindow = NULL;
+
+// Lambda window
+static Fl_Lambda* lambdaWindow = NULL;
+
+// Load data window
+static Fl_Load_Data* loadDataWindow = NULL;
+
+// Status bar
+static Fl_Box* statusBar = NULL;
+
+// Data bar
+static Fl_Box* dataBar = NULL;
+
+// Progress bar
+static Fl_Box* progressBar = NULL;
+
+// Dataset type
+static int datasetType = 8;
+
+// Main window
+static Fl_Main_Window* mainWindow = NULL;
+
+// Message window
+static Fl_Dialog* messageWindow = NULL;
+
+// Stop LambdaTracker window
+static Fl_Dialog* stopLambdaWindow = NULL;
+
+// Overview widget
+static Fl_Overview* overview = NULL;
+
+// Transfer function widget
+static Fl_Transfer_Function* widget = NULL;
+
+// Slice frequency widget
+static Fl_Slice_Frequency* slice = NULL;
+
+// Slice frequency
+static double sliceFrequency = 1.0;
+
+// Progress level for script thread
+static int progressLevel = -1;
+static int totalLevel = -1;
+
+// Thread listening for server updates
+pthread_t _thread;
+
+// Thread listening for LabmdaTracker updates
+pthread_t _lambdaThread;
+
+// Structure for script thread
+typedef struct {
+  UserInterfaceClient* client;
+  const char* scriptfile;
+  bool* cancelScript;
+  void (*cb)(unsigned char* message);
+} scriptData;
+
+// Structure for LambdaTracker thread
+typedef struct {
+  int port;
+  bool stopFlag;
+} lambdaData;
+
+// Data for lambda thread
+lambdaData info;
+
+// Script info mutex
+static pthread_mutex_t scriptMutex = PTHREAD_MUTEX_INITIALIZER;
+
+// User cancels script
+bool _cancelScript = false;
+
+// LambdaTable transforms
+float world_rotate[3] = {0.0, 0.0, 0.0};
+float world_scale[3] = {0.0, 0.0, 0.0};
+float world_scale_angle = 0.0;
+float world_translate[3] = {0.0, 0.0, 0.0};
+
+// LambdaTable state
+bool rotateUp = true;
+bool scaleUp = true;
+bool translateUp = true;
+
+// LambdaTable position
+float rotatePuckPos[2] = {0.0, 0.0};
+float translatePuckPos[2] = {0.0, 0.0};
+float scalePuckPos[2] = {0.0, 0.0};
+
+// Total display frustum
+float _totalDisplayFrustum[6] = {-1.0, 1.0, -1.0, 1.0, -1.0, 1.0};
+
+float scaleDeltaX = 0.0;
+float scaleDeltaY = 0.0;
+float oriX = 0.0;
+float oriY = 0.0;
+float wtnX = 0.0;
+float scale_pos_f[3] = {0.0, 0.0, 0.0};
+float scalePuckPosI[2] = {0.0, 0.0};
+float scaleAngleI = 0.0;
+
+// Identity matrices
+float RI[16] = {1.0, 0.0, 0.0, 0.0,
+                0.0, 1.0, 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 1.0};
+float SI[16] = {1.0, 0.0, 0.0, 0.0,
+                0.0, 1.0, 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 1.0};
+float TI[16] = {1.0, 0.0, 0.0, 0.0,
+                0.0, 1.0, 0.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 1.0};
+
+// Trackball interaction for LambdaTracker
+Trackball lambdaTrackball;
+
+/*--------------------------------------------------------------------------*/
+
+static void reset_transforms() {
+
+  // Reset translation matrix
+  overview -> SetTranslationMatrix(TI);
+  client -> SendTranslationMatrix(TI);
+  
+  // Reset scale matrix
+  overview -> SetScaleMatrix(SI);
+  client -> SendScaleMatrix(SI);
+
+  // Reset rotation matrix
+  overview -> SetRotationMatrix(RI);
+  client -> SendRotationMatrix(RI);
+
+  // Reset overview
+  overview -> ResetView();
+
+  // Reset master trackball for SAGE events
+  client -> ResetView();
+
+  // Reset trackball
+  lambdaTrackball.Clear();
+
+  // Force a sleep for one second
+  usleep(1000000);
+
+  // Send render command
+  client -> SendCommandRender();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void reset_view(Fl_Button* b, void* v) {
+
+  // Reset view transforms
+  reset_transforms();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void load_tf_file(char* name) {
+
+  // File pointer
+  FILE* fptr = NULL;
+  
+  // Attempt to open file
+  if ((fptr = fopen(name, "r")) == NULL) {
+    fl_message("Could not open file %s", name);
+    return;
+  }
+
+  // Operation
+  char operation[128];
+  memset(operation, 0, 128);
+
+  // Maximum scalar value
+  float max = 0.0;
+
+  // Entry
+  float* s = NULL;
+  float* r = NULL;
+  float* g = NULL;
+  float* b = NULL;
+  float* o = NULL;
+
+  // Number of entries
+  int num = 0;
+
+  // Read maximum scalar value
+  fscanf(fptr, "%f", &max);
+
+  // Read operation
+  fscanf(fptr, "%s %d", operation, &num);
+
+  // Check for color tag
+  if (strcmp(operation, "COLOR")) {
+    fl_message("Invalid format.");
+    fclose(fptr);
+    return;
+  }
+
+  // Allocate space for points
+  s = new float[num];
+  r = new float[num];
+  g = new float[num];
+  b = new float[num];
+
+  // Read entries
+  for (int i = 0 ; i < num ; i++) {
+    fscanf(fptr, "%f %f %f %f", &s[i], &r[i], &g[i], &b[i]);
+  }
+
+  // Restore color points
+  widget -> RestoreColorControlPoints(num, max, s, r, g, b);
+
+  // Deallocate storage
+  delete [] s;
+  delete [] r;
+  delete [] g;
+  delete [] b;
+
+  // Read operation
+  fscanf(fptr, "%s %d", operation, &num);
+
+  // Check for color tag
+  if (strcmp(operation, "OPACITY")) {
+    fl_message("Invalid format.");
+    fclose(fptr);
+    return;
+  }
+
+  // Allocate space for points
+  s = new float[num];
+  o = new float[num];
+
+  // Read entries
+  for (int i = 0 ; i < num ; i++) {
+    fscanf(fptr, "%f %f", &s[i], &o[i]);
+  }
+
+  // Restore color points
+  widget -> RestoreOpacityControlPoints(num, max, s, o);
+
+  // Deallocate storage
+  delete [] s;
+  delete [] o;
+
+  // Close file
+  fclose(fptr);
+
+  // Set maximum scalar value
+  if (datasetType == 8) {
+    widget -> SetMaximumScalar(255.0);
+  }
+  else if (datasetType == 16) {
+    widget -> SetMaximumScalar(65536.0);
+  }
+
+  // Redraw widget
+  widget -> Redraw();
+
+  // Load map
+  map_cb(widget);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void load_tf() {
+
+  // Show file chooser
+  char* filename = fl_file_chooser("Load Transfer Function", "*.tf", NULL);
+
+  // Check if a file was selected
+  if (filename != NULL) {
+    load_tf_file(filename);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void save_tf_file(char* name) {
+
+  // File pointer
+  FILE* fptr = NULL;
+  
+  // Attempt to open file
+  if ((fptr = fopen(name, "w")) == NULL) {
+    fl_message("Could not open file %s", name);
+    return;
+  }
+
+  
+  // Maximum value
+  float min = 0.0;
+  float max = 0.0;
+  widget -> GetScalarRange(&min, &max);
+  fprintf(fptr, "%f\n", max);
+
+
+  // Operation
+  fprintf(fptr, "COLOR ");
+
+  // Get number of color control points
+  int num = widget -> GetNumberOfColorControlPoints();
+  fprintf(fptr, "%d\n", num);
+
+  // Entry
+  float s = 0.0;
+  float r = 0.0;
+  float g = 0.0;
+  float b = 0.0;
+  float o = 0.0;
+
+  // Get color control points
+  for (int i = 0 ; i < num ; i++) {
+    widget -> GetColorControlPoint(i, &s, &r, &g, &b);
+    fprintf(fptr, "%f %f %f %f\n", s, r, g, b);
+  }
+
+
+  // Operation
+  fprintf(fptr, "OPACITY ");
+
+  // Get number of color control points
+  num = widget -> GetNumberOfOpacityControlPoints();
+  fprintf(fptr, "%d\n", num);
+
+  // Get color control points
+  for (int i = 0 ; i < num ; i++) {
+    widget -> GetOpacityControlPoint(i, &s, &o);
+    fprintf(fptr, "%f %f\n", s, o);
+  }
+
+
+  // Redraw widget
+  widget -> Redraw();
+
+  // Load map
+  map_cb(widget);
+
+
+  // Close
+  fclose(fptr);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void save_tf() {
+
+  // Show file chooser
+  char* filename = fl_file_chooser("Save Transfer Function", NULL, NULL);
+
+  // Check if a file was selected
+  if (filename != NULL) {
+    save_tf_file(filename);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void slice_frequency() {
+
+  // Calculate position of message window
+  int posx = (mainWindow -> x()) +
+    (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+    (225 / 2);
+  int posy = (mainWindow -> y()) +
+    (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+    (80 / 2);
+  
+  // Create new connect window
+  slice = new Fl_Slice_Frequency(posx, posy, 225, 80, "Slice Frequency");
+
+  // Set slice frequency value
+  slice -> SetSliceFrequency(sliceFrequency);
+
+  // Set modal
+  slice -> set_modal();
+
+  // Show connect window
+  slice -> show();
+
+  // Set callback
+  slice -> callback((Fl_Callback*) slice_cancel_cb);
+
+  // Set connect button callback
+  slice -> SetOKButtonCallback((Fl_Callback*) slice_ok_cb, NULL);
+
+  // Set exit button callback
+  slice -> SetCancelButtonCallback((Fl_Callback*) slice_cancel_cb, NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void slice_ok_cb(Fl_Button* b, void* v) {
+
+  // Hide slice window
+  slice -> hide();
+
+  // Get slice frequency
+  double frequency = slice -> GetSliceFrequency();
+  sliceFrequency = frequency;
+
+  // Set slice frequency
+  client -> SendSliceFrequency(frequency);
+
+  // Delete slice window
+  delete slice;
+  slice = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void slice_cancel_cb(Fl_Button* b, void* v) {
+
+  // Hide slice window
+  slice -> hide();
+
+  // Delete slice window
+  delete slice;
+  slice = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void menu_axis_cb() {
+
+  // Check for client
+  if (client != NULL) {
+
+    // Turn off axis
+    if (g_miAxis.value()) {
+      client -> SendAxisOff();
+      g_miAxis.clear();
+    }
+
+    // Turn on axis
+    else {
+      client -> SendAxisOn();
+      g_miAxis.set();
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void menu_bounding_cb() {
+
+  // Check for client
+  if (client != NULL) {
+
+    // Turn off bounding box
+    if (g_miBoundingBox.value()) {
+      client -> SendBoundingBoxOff();
+      g_miBoundingBox.clear();
+    }
+
+    // Turn on bounding box
+    else {
+      client -> SendBoundingBoxOn();
+      g_miBoundingBox.set();
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void menu_brick_cb() {
+
+  // Check for client
+  if (client != NULL) {
+
+    // Turn off brick box
+    if (g_miBrickBoxes.value()) {
+      client -> SendBrickBoxOff();
+      g_miBrickBoxes.clear();
+    }
+
+    // Turn on brick box
+    else {
+      client -> SendBrickBoxOn();
+      g_miBrickBoxes.set();
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void add_message(unsigned char* message) {
+
+  // Lock message mutex
+  pthread_mutex_lock(&messageMutex);
+
+  // Push message to back of queue
+  messageQueue.push(message);
+
+  // Unlock message mutex
+  pthread_mutex_unlock(&messageMutex);
+
+  // Interrupt Fl::wait in the main thread
+  //Fl::awake(NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void map_cb(void* d) {
+
+  // 8-bit map
+  if (datasetType == 8) {
+
+    // Color and opacity map
+    unsigned char map[256*4];
+  
+    // Transfer function values
+    float r = 0.0;
+    float g = 0.0;
+    float b = 0.0;
+    float o = 0.0;
+
+    // Build map
+    for (int i = 0 ; i < 256 ; i++) {
+      
+      // Get color values from widget
+      ((Fl_Transfer_Function*) d) -> GetColor((float) i, &r, &g, &b);
+      
+      // Get opacity value from widget
+      o = ((Fl_Transfer_Function*) d) -> GetOpacity((float) i);
+      
+      // Convert from 0.0 - 1.0 to 0 - 255
+      map[(i*4)] = (unsigned char) (r * 255.0);
+      map[(i*4) + 1] = (unsigned char) (g * 255.0);
+      map[(i*4) + 2] = (unsigned char) (b * 255.0);
+      map[(i*4) + 3] = (unsigned char) (o * 255.0);
+      
+    }
+    
+    // Send map
+    if (client != NULL) {
+      client -> SendMap(map);
+      client -> SendCommandRender();
+      client -> SendCommandRender();
+    }
+
+  }
+
+  // 16-bit map
+  else if (datasetType == 16) {
+
+    // Color and opacity map
+    unsigned char map[65536*4];
+  
+    // Transfer function values
+    float r = 0.0;
+    float g = 0.0;
+    float b = 0.0;
+    float o = 0.0;
+
+    // Build map
+    for (int i = 0 ; i < 65536 ; i++) {
+      
+      // Get color values from widget
+      ((Fl_Transfer_Function*) d) -> GetColor((float) i, &r, &g, &b);
+      
+      // Get opacity value from widget
+      o = ((Fl_Transfer_Function*) d) -> GetOpacity((float) i);
+      
+      // Convert from 0.0 - 1.0 to 0 - 255
+      map[(i*4)] = (unsigned char) (r * 255.0);
+      map[(i*4) + 1] = (unsigned char) (g * 255.0);
+      map[(i*4) + 2] = (unsigned char) (b * 255.0);
+      map[(i*4) + 3] = (unsigned char) (o * 255.0);
+     
+    }
+    
+    // Send map
+    if (client != NULL) {
+      client -> SendMap16(map);
+      client -> SendCommandRender();
+      client -> SendCommandRender();
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void connect_show() {
+
+  // Calculate position of message window
+  int posx = (mainWindow -> x()) +
+    (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+    (255 / 2);
+  int posy = (mainWindow -> y()) +
+    (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+    (115 / 2);
+  
+  // Create new connect window
+  connectWindow = new Fl_Connect(posx, posy, 255, 115, "Connect");
+
+  // Set modal
+  connectWindow -> set_modal();
+
+  // Show connect window
+  connectWindow -> show();
+
+  // Set callback
+  connectWindow -> callback(overview_cb);
+
+  // Set connect button callback
+  connectWindow -> SetConnectButtonCallback((Fl_Callback*) connect_cb, NULL);
+
+  // Set exit button callback
+  connectWindow -> SetExitButtonCallback((Fl_Callback*) exit_cb, NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void listenToLambdaTracker(int port) {
+
+  // Setup data
+  info.port = port;
+  info.stopFlag = false;
+
+  // Create thread listening for LambdaTracker updates
+  pthread_create(&_lambdaThread,
+		 NULL,
+		 lambda_thread_function,
+		 &info);
+
+  // Calculate position of message window
+  int posx = (mainWindow -> x()) +
+      (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+      (195 / 2);
+  int posy = (mainWindow -> y()) +
+      (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+      (75 / 2);
+
+  // Create new message window
+  stopLambdaWindow = new Fl_Dialog(posx, posy, 195, 75, "LambdaTracker");
+
+  // Set ok button callback
+  stopLambdaWindow -> 
+      SetOKButtonCallback((Fl_Callback*) stopLambda_cb, (void*) &info);
+    
+  // Set callback
+  //stopLambdaWindow -> callback(overview_cb);
+
+  // Set message
+  stopLambdaWindow -> SetMessage("Stop listening?");
+
+  // Set modal
+  //messageWindow -> set_modal();
+
+  // Show dialog
+  stopLambdaWindow -> show();
+
+  // Update scale for LambdaTable
+  float Sm[16];
+  overview -> GetScaleMatrix(Sm);
+  world_scale[0] = Sm[0];
+  world_scale[1] = Sm[5];
+  world_scale[2] = Sm[10];
+
+  // Update translation for LambdaTable
+  float Tm[16];
+  overview -> GetTranslationMatrix(Tm);
+  world_translate[0] = Tm[12];
+  world_translate[1] = Tm[13];
+
+  /*  
+  // Update connection
+  char hostport[1024];
+  sprintf(hostport, "Connected to %s:%d", host, port);
+  statusBar -> copy_label(hostport);
+
+  // Deactivate connect menu item
+  mainWindow -> DeactivateConnect();
+
+  // Activate disconnect menu item
+  mainWindow -> ActivateDisconnect();
+
+  // Activate shutdown menu item
+  mainWindow -> ActivateShutdown();
+
+  // Get data
+  client -> GetData();
+
+  // Get number of datasets
+  client -> GetDatasetListSize();
+
+  // Get total display dimenstions
+  client -> GetTotalDisplayDimensions();
+
+  // Get total display frustum
+  client -> GetTotalDisplayFrustum();
+
+  // Get overview vertices
+  client -> GetOverviewVertices();
+
+  // Get dataset type
+  client -> GetDatasetType();
+
+  // Get rotation matrix
+  client -> GetRotationMatrix();
+
+  // Get scale matrix
+  client -> GetScaleMatrix();
+
+  // Get translation matrix
+  client -> GetTranslationMatrix();
+
+  // Get axis state
+  client -> GetAxis();
+
+  // Get bounding box state
+  client -> GetBoundingBox();
+
+  // Get brick box state
+  client -> GetBrickBox();
+
+  // Get slice frequency
+  client -> GetSliceFrequency();
+
+  // Redraw tf widget
+  widget -> Redraw();
+
+  // Load map
+  map_cb(widget);
+    */
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void connect(char* host, int port) {
+
+  // Connect to server
+  if ((client -> Init(host, port)) != USER_INTERFACE_CLIENT_OK) {
+
+    // Calculate position of message window
+    int posx = (mainWindow -> x()) +
+      (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+      (195 / 2);
+    int posy = (mainWindow -> y()) +
+      (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+      (75 / 2);
+
+    // Create new message window
+    messageWindow = new Fl_Dialog(posx, posy, 195, 75, "Error");
+
+    // Set ok button callback
+    messageWindow -> SetOKButtonCallback((Fl_Callback*) message_cb, NULL);
+    
+    // Set callback
+    messageWindow -> callback(overview_cb);
+
+    // Set message
+    messageWindow -> SetMessage("Can not connect to server.");
+
+    // Set modal
+    messageWindow -> set_modal();
+
+    // Show dialog
+    messageWindow -> show();
+
+    // Return
+    return;
+
+  }
+  
+  // Update connection
+  char hostport[1024];
+  sprintf(hostport, "Connected to %s:%d", host, port);
+  statusBar -> copy_label(hostport);
+
+  // Deactivate connect menu item
+  mainWindow -> DeactivateConnect();
+
+  // Activate disconnect menu item
+  mainWindow -> ActivateDisconnect();
+
+  // Activate shutdown menu item
+  mainWindow -> ActivateShutdown();
+
+  // Get data
+  client -> GetData();
+
+  // Get number of datasets
+  client -> GetDatasetListSize();
+
+  // Get total display dimenstions
+  client -> GetTotalDisplayDimensions();
+
+  // Get total display frustum
+  client -> GetTotalDisplayFrustum();
+
+  // Get overview vertices
+  client -> GetOverviewVertices();
+
+  // Get dataset type
+  client -> GetDatasetType();
+
+  // Get rotation matrix
+  client -> GetRotationMatrix();
+
+  // Get scale matrix
+  client -> GetScaleMatrix();
+
+  // Get translation matrix
+  client -> GetTranslationMatrix();
+
+  // Get axis state
+  client -> GetAxis();
+
+  // Get bounding box state
+  client -> GetBoundingBox();
+
+  // Get brick box state
+  client -> GetBrickBox();
+
+  // Get slice frequency
+  client -> GetSliceFrequency();
+
+  // Redraw tf widget
+  widget -> Redraw();
+
+  // Load map
+  map_cb(widget);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void disconnect() {
+
+  // Disconnect from server
+  client -> Disconnect();
+
+  // Update connection
+  statusBar -> copy_label("Not connected.");
+
+  // Update data bar
+  dataBar -> copy_label("No data.");
+
+  // Update progress bar
+  progressBar -> copy_label("Level");
+
+  // Activate connect menu item
+  mainWindow -> ActivateConnect();
+
+  // Deactivate disconnect menu item
+  mainWindow -> DeactivateDisconnect();
+
+  // Deactivate shutdown menu item
+  mainWindow -> DeactivateShutdown();
+
+  // Show connect window
+  connect_show();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void data_ok_cb(Fl_Button* b, void* v) {
+
+  // Hide message window
+  loadDataWindow -> hide();
+
+  // Get selected data set
+  int selected = loadDataWindow -> GetSelected();
+
+  // Delete load data window
+  delete loadDataWindow;
+  loadDataWindow = NULL;
+
+  // Load data
+  if (selected != 0) {
+
+    // Send data prefix
+    client -> SendPrefix(datasetListPrefix[selected - 1]);
+
+    // Send data file name
+    client -> SendData(datasetListFile[selected - 1]);
+
+    // Get overview vertices
+    client -> GetOverviewVertices();
+
+    // Get dataset type
+    client -> GetDatasetType();
+
+    // Get rotation matrix
+    //client -> GetRotationMatrix();
+
+    // Get scale matrix
+    //client -> GetScaleMatrix();
+
+    // Get translation matrix
+    //client -> GetTranslationMatrix();
+
+    // Redraw tf widget
+    widget -> Redraw();
+
+    // Send transfer function
+    map_cb(widget);
+
+    // Update data bar
+    dataBar -> copy_label(datasetListFile[selected - 1]);
+
+    // Reset view transforms
+    reset_transforms();
+
+  }
+
+  // If user didn't select anything
+  else {
+
+    // Calculate position of message window
+    int posx = (mainWindow -> x()) +
+      (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+      (195 / 2);
+    int posy = (mainWindow -> y()) +
+      (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+      (75 / 2);
+
+    // Create new message window
+    messageWindow = new Fl_Dialog(posx, posy, 195, 75, "Error");
+
+    // Set ok button callback
+    messageWindow -> SetOKButtonCallback((Fl_Callback*) message_data_cb, NULL);
+
+    // Set message
+    messageWindow -> SetMessage("Select a dataset to load.");
+
+    // Set modal
+    messageWindow -> set_modal();
+
+    // Show dialog
+    messageWindow -> show();
+
+    // Return
+    return;
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void data_cancel_cb(Fl_Button* b, void* v) {
+
+  // Hide message window
+  loadDataWindow -> hide();
+
+  // Delete load data window
+  delete loadDataWindow;
+  loadDataWindow = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *lambda_thread_function(void* ptr) {
+
+  // Cast data
+  lambdaData* info = (lambdaData*) ptr;
+
+  // Socket info
+  struct sockaddr_in serverAddress;
+  int serverSocketFileDescriptor;
+
+  // Create server socket
+  if ((serverSocketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+    perror("ListenToLambdaTracker: Error creating socket");
+
+    // Exit thread
+    pthread_exit(NULL);
+
+  }
+
+  // Set SO_REUSEADDR
+  int optVal = 1;
+  int optLen = sizeof(optVal);
+  if(setsockopt(serverSocketFileDescriptor, 
+                SOL_SOCKET, 
+                SO_REUSEADDR, 
+                (void*) &optVal, 
+                (socklen_t) optLen) != 0) {
+    perror("ListenToLambdaTrakcer: Error setting SO_REUSEADDR");
+  }
+
+  // Initialize server address
+  memset(&serverAddress, 0, sizeof(serverAddress));
+  serverAddress.sin_family = AF_INET;
+  serverAddress.sin_port = htons(info -> port);
+  serverAddress.sin_addr.s_addr = INADDR_ANY;
+  
+  // Bind address
+  if (bind(serverSocketFileDescriptor, 
+           (struct sockaddr*) &serverAddress, 
+           sizeof(serverAddress)) != 0) {
+    perror("ListenToLambdaTracker: Error binding address");
+    close(serverSocketFileDescriptor);
+  }
+  
+  // Listen for messages from LambdaTracker
+  while(info -> stopFlag == false) {
+
+    // Message variables
+    char msg[60];
+    int ret;
+    socklen_t sin_length;
+
+    // Get message
+    sin_length = sizeof(struct sockaddr_in);
+    ret = recvfrom(serverSocketFileDescriptor, 
+		   msg, 60, 0, (struct sockaddr*) &serverAddress, &sin_length);
+
+    //printf("%d bytes received from %s (port %d)\n",
+    //ret, inet_ntoa(serverAddress.sin_addr), serverAddress.sin_port);
+    //for (int i = 0 ; i < 60 ; i++) {
+    //  printf("%c", msg[i]);
+    //}
+    //printf("\n");
+
+    // Buffer
+    unsigned char* buffer = new unsigned char[2048];
+    memset(buffer, 0 , 2048);
+
+    // Command
+    char command[8];
+    memset(command, 0, 8);
+    strcpy(command, "CMD_LTM");
+
+    // Destination
+    int destination = 0;
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Pack data
+    for (int i = 0 ; i < 60 ; i++) {
+	packer.PackChar(msg[i]);
+    }
+
+    // Add message to queue
+    add_message(buffer);
+
+  }
+
+  // Close socket
+  close(serverSocketFileDescriptor);
+
+  // Exit thread
+  pthread_exit(NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void lambda_listen_cb(Fl_Button* b, void* v) {
+
+  // Get port
+  int port = 0;
+  port = lambdaWindow -> GetPort();
+
+  // Set non modal
+  lambdaWindow -> set_non_modal();
+
+  // Hide lambda window
+  lambdaWindow -> hide();
+
+  // Delete lambda window
+  delete lambdaWindow;
+  lambdaWindow = NULL;
+
+  // Listen to LambdaTracker
+  listenToLambdaTracker(port);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void lambda_cancel_cb(Fl_Button* b, void* v) {
+
+  // Set non modal
+  lambdaWindow -> set_non_modal();
+
+  // Hide lambda window
+  lambdaWindow -> hide();
+
+  // Delete lambda window
+  delete lambdaWindow;
+  lambdaWindow = NULL;  
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void listen_lambda() {
+
+  // Calculate position of message window
+  int posx = (mainWindow -> x()) +
+    (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+    (255 / 2);
+  int posy = (mainWindow -> y()) +
+    (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+    (115 / 2);
+  
+  // Create new connect window
+  lambdaWindow = 
+      new Fl_Lambda(posx, posy, 255, 115, "Listen to LambdaTracker");
+
+  // Set modal
+  lambdaWindow -> set_modal();
+
+  // Show connect window
+  lambdaWindow -> show();
+
+  // Set callback
+  lambdaWindow -> callback((Fl_Callback*) lambda_cancel_cb);
+
+  // Set listen button callback
+  lambdaWindow -> 
+      SetListenButtonCallback((Fl_Callback*) lambda_listen_cb, NULL);
+
+  // Set cancel button callback
+  lambdaWindow -> 
+      SetCancelButtonCallback((Fl_Callback*) lambda_cancel_cb, NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void load_data() {
+
+  // Calculate position of load data window
+  int posx = (mainWindow -> x()) +
+    (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+    (220 / 2);
+  int posy = (mainWindow -> y()) +
+    (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+    (305 / 2);
+
+  // Create new load data winodw
+  loadDataWindow = new Fl_Load_Data(posx, posy, 220, 305, "Load Data");
+
+  // Set ok button callback
+  loadDataWindow -> SetOKButtonCallback((Fl_Callback*) data_ok_cb, NULL);
+
+  // Set cancel button callback
+  loadDataWindow -> 
+    SetCancelButtonCallback((Fl_Callback*) data_cancel_cb, NULL);
+
+  // Set modal
+  loadDataWindow -> set_modal();
+
+  // Populate browser with dataset names
+  for (int i = 0 ; i < datasetListSize ; i++) {
+    loadDataWindow -> Add(datasetListName[i]);
+  }
+
+  // Show dialog
+  loadDataWindow -> show();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void load_script() {
+
+  // Show file chooser
+  char* filename = fl_file_chooser("Load Script", NULL, NULL);
+
+  // Check if a file was selected
+  if (filename != NULL) {
+
+    // Run script
+    run_script(filename);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *thread_function(void* ptr) {
+
+  // Cast data
+  scriptData* info = (scriptData*) ptr;
+
+  // Get data members
+  const char* filename = info -> scriptfile;
+  UserInterfaceClient* client = info -> client;
+  bool* cancelScript = info -> cancelScript;
+  void (*cb)(unsigned char* message) = info -> cb;
+
+  // File pointer
+  FILE* fptr = NULL;
+    
+  // Attempt to open file
+  if ((fptr = fopen(filename, "r")) == NULL) {
+    
+    // Tell main process that the script is finished
+
+    // Buffer
+    unsigned char* buffer = new unsigned char[2048];
+    memset(buffer, 0 , 2048);
+
+    // Command
+    char command[8];
+    memset(command, 0, 8);
+    strcpy(command, "SCR_COM");
+
+    // Destination
+    int destination = 0;
+
+    // Packer
+    DataPacker packer;
+    packer.SetBuffer(buffer, 2048);
+
+    // Pack command
+    for (int i = 0 ; i < 8 ; i++) {
+      packer.PackChar(command[i]);
+    }
+
+    // Pack destination
+    packer.PackInt(destination);
+
+    // Create message
+    char m[1024];
+    sprintf(m, "Can not open script file %s", filename);
+
+    // Pack data
+    for (int i = 0 ; i < 1024 ; i++) {
+      packer.PackChar(m[i]);
+    }
+
+    // Add message
+    if (cb != NULL) {
+      cb(buffer);
+    }
+
+    // Exit thread
+    pthread_exit(NULL);
+
+  }
+
+  // Data read from file
+  char data[1024];
+
+  // Command number
+  int commandNumber = 0;
+
+  // Continue processing commands as long as they're in the file
+  while (fscanf(fptr, "%s", data) != EOF) {
+
+    // Check if script is canceled
+    if (*cancelScript == true) {
+
+      // Tell main process that the script is finished
+
+      // Buffer
+      unsigned char* buffer = new unsigned char[2048];
+      memset(buffer, 0 , 2048);
+
+      // Command
+      char command[8];
+      memset(command, 0, 8);
+      strcpy(command, "SCR_CAN");
+
+      // Destination
+      int destination = 0;
+
+      // Packer
+      DataPacker packer;
+      packer.SetBuffer(buffer, 2048);
+
+      // Pack command
+      for (int i = 0 ; i < 8 ; i++) {
+        packer.PackChar(command[i]);
+      }
+
+      // Pack destination
+      packer.PackInt(destination);
+
+      // Close script file
+      fclose(fptr);
+
+      // Add message
+      if (cb != NULL) {
+        cb(buffer);
+      }
+
+      // Exit thread
+      pthread_exit(NULL);
+
+    }
+
+    // Check if first command
+    if (commandNumber == 0) {
+
+      if(strcmp(data, "VRA_UI_SCRIPT")) {
+        
+        // Tell main process that the script is finished
+
+        // Buffer
+        unsigned char* buffer = new unsigned char[2048];
+        memset(buffer, 0 , 2048);
+        
+        // Command
+        char command[8];
+        memset(command, 0, 8);
+        strcpy(command, "SCR_COM");
+
+        // Destination
+        int destination = 0;
+
+        // Packer
+        DataPacker packer;
+        packer.SetBuffer(buffer, 2048);
+        
+        // Pack command
+        for (int i = 0 ; i < 8 ; i++) {
+          packer.PackChar(command[i]);
+        }
+
+        // Pack destination
+        packer.PackInt(destination);
+
+        // Create message
+        char m[1024];
+        sprintf(m, "File %s is not a valid script file.", filename);
+
+        // Pack data
+        for (int i = 0 ; i < 1024 ; i++) {
+          packer.PackChar(m[i]);
+        }
+
+        // Close file
+        fclose(fptr);
+
+        // Add message
+        if (cb != NULL) {
+          cb(buffer);
+        }
+
+        // Exit thread
+        pthread_exit(NULL);
+
+      }
+      
+      // Increment command number
+      commandNumber++;
+
+      // Start at top of loop
+      continue;
+
+    }
+
+    // Load data
+    if (!strcmp(data, "CMD_DAT")) {
+      
+      // Data name
+      char dataname[1024];
+
+      // Cache sizes
+      int ramSize = -1;
+      int vramSize = -1;
+      
+      // Read filename
+      if (fscanf(fptr, "%s %d %d", dataname, &ramSize, &vramSize) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      
+      // Send command
+      client -> SendData(dataname, ramSize, vramSize);
+      
+    }
+    
+    // Disconnect
+    else if (!strcmp(data, "CMD_DIS")) {
+
+      // Disconnect
+      disconnect();
+      
+    }
+    
+    // Exit
+    else if (!strcmp(data, "CMD_EXI")) {
+      
+      // Send command
+      //client -> SendCommandExit();
+      
+    }
+    
+    // Data prefix
+    else if (!strcmp(data, "CMD_PRE")) {
+
+      // Data name
+      char dataprefix[1024];
+      
+      // Read filename
+      if (fscanf(fptr, "%s", dataprefix) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      
+      // Send command
+      client -> SendPrefix(dataprefix);
+      
+      }
+    
+    // Render
+    else if (!strcmp(data, "CMD_REN")) {
+      
+      // Send command
+      client -> SendCommandRender();
+      
+    }
+    
+    // Rotation
+    else if (!strcmp(data, "CMD_ROT")) {
+      
+      // Rotation matrix
+      float R[16];
+      
+      // Read rotation matrix
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &R[0], &R[1], &R[2], &R[3]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &R[4], &R[5], &R[6], &R[7]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &R[8], &R[9], &R[10], &R[11]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &R[12], &R[13], &R[14], &R[15]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      
+      // Send command
+      client -> SendRotationMatrix(R);
+      
+    }
+
+    // Scale
+    else if (!strcmp(data, "CMD_SCA")) {
+
+      // Scale matrix
+      float S[16];
+
+      // Read scale matrix
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &S[0], &S[1], &S[2], &S[3]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &S[4], &S[5], &S[6], &S[7]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &S[8], &S[9], &S[10], &S[11]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &S[12], &S[13], &S[14], &S[15]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      
+      // Send command
+      client -> SendScaleMatrix(S);
+
+    }
+    
+    // Translation
+    else if (!strcmp(data, "CMD_TRA")) {
+      
+      // Translation matrix
+      float T[16];
+
+      // Read translation matrix
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &T[0], &T[1], &T[2], &T[3]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &T[4], &T[5], &T[6], &T[7]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &T[8], &T[9], &T[10], &T[11]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      if (fscanf(fptr, "%f %f %f %f", 
+                 &T[12], &T[13], &T[14], &T[15]) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }
+      
+      // Send command
+      client -> SendTranslationMatrix(T);
+      
+    }
+
+    // Wait
+    else if (!strcmp(data, "WAIT")) {
+      
+      // Time to sleep
+      int time = 0;
+
+      // Read time to sleep
+      if (fscanf(fptr, "%d", &time) == EOF) {
+        fprintf(stderr, "Error reading script file.\n");
+      }      
+      
+      // Wait until all levels-of-detail are rendered
+      if (time < 0) {
+
+        // Wait until all levels have been rendered
+        while((progressLevel + 1) < totalLevel) {
+          usleep(100000);
+        }
+
+      }
+
+      // Sleep a determined amount of seconds
+      else {
+       
+        // Sleep
+        usleep(time * 1000000);
+        
+      }
+
+    }
+
+    // Unknown command
+    else {
+      fprintf(stderr, "Unknown command %s. Attempting to continue...\n", 
+              data);
+    }
+    
+    // Increment command number
+    commandNumber++;
+    
+  }
+  
+  // Close file
+  fclose(fptr);
+  
+  // Tell main process that the script is finished
+  
+  // Buffer
+  unsigned char* buffer = new unsigned char[2048];
+  memset(buffer, 0 , 2048);
+  
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+  strcpy(command, "SCR_COM");
+
+  // Destination
+  int destination = 0;
+  
+  // Packer
+  DataPacker packer;
+  packer.SetBuffer(buffer, 2048);
+
+  // Pack command
+  for (int i = 0 ; i < 8 ; i++) {
+    packer.PackChar(command[i]);
+  }
+  
+  // Pack destination
+  packer.PackInt(destination);
+  
+  // Create message
+  char m[1024];
+  sprintf(m, "Script completed.");
+
+  // Pack data
+  for (int i = 0 ; i < 1024 ; i++) {
+    packer.PackChar(m[i]);
+  }
+
+  // Add message
+  if (cb != NULL) {
+    cb(buffer);
+  }
+
+  // Exit thread
+  pthread_exit(NULL);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void run_script(const char* filename) {
+
+  // Check if a file was selected
+  if (filename != NULL) {
+
+    // Setup script thread info
+    scriptData info;
+    info.client = client;
+    info.scriptfile = filename;
+    info.cancelScript = &_cancelScript;
+    info.cb = add_message;
+
+    // Reset cancel script
+    _cancelScript = false;
+
+    // Lock message mutex
+    pthread_mutex_lock(&scriptMutex);
+
+    // Unlock message mutex
+    pthread_mutex_unlock(&scriptMutex);
+
+    // Create thread listening for server updates
+    pthread_create(&_thread,
+                   NULL,
+                   thread_function,
+                   &info);
+
+    // Calculate position of message window
+    int posx = (mainWindow -> x()) +
+      (((mainWindow -> x() + mainWindow -> w()) - mainWindow -> x()) / 2) -
+      (195 / 2);
+    int posy = (mainWindow -> y()) +
+      (((mainWindow -> y() + mainWindow -> h()) - mainWindow -> y()) / 2) -
+      (75 / 2);
+
+    // Create new message window
+    messageWindow = new Fl_Dialog(posx, posy, 195, 75, "Script");
+
+    // Set ok button callback
+    messageWindow -> SetOKButtonCallback((Fl_Callback*) mes_script_cb, NULL);
+
+    // Set message
+    messageWindow -> SetMessage("Script running. Cancel script?");
+
+    // Set modal
+    messageWindow -> set_modal();
+
+    // Show dialog
+    messageWindow -> show();
+  }
+
+  // Return
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void connect_cb(Fl_Button* b, void* v) {
+
+  // Get host
+  char host[1024];
+  strcpy(host, connectWindow -> GetHost());
+
+  // Get port
+  int port = 0;
+  port = connectWindow -> GetPort();
+
+  // Set non modal
+  connectWindow -> set_non_modal();
+
+  // Hide connect window
+  connectWindow -> hide();
+
+  // Delete connect window
+  delete connectWindow;
+  connectWindow = NULL;
+
+  // Connect to server
+  connect(host, port);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void exit_server() {
+
+  // Send disconnect command
+  if (client != NULL) {
+    client -> SendCommandExit();
+  }
+
+  // Update connection
+  statusBar -> copy_label("Not connected.");
+
+  // Update progress bar
+  progressBar -> copy_label("Level");
+
+  // Update data bar
+  dataBar -> copy_label("No data.");
+
+  // Activate connect menu item
+  mainWindow -> ActivateConnect();
+
+  // Deactivate disconnect menu item
+  mainWindow -> DeactivateDisconnect();
+
+  // Deactivate shutdown menu item
+  mainWindow -> DeactivateShutdown();
+
+  // Show connect window
+  connect_show();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void exit_application() {
+
+  // Send disconnect command
+  if (client != NULL) {
+    client -> SendCommandExit();
+  }
+
+  // Clean up observer
+  if (observer != NULL) {
+    delete observer;
+  }
+
+  // Clean up client
+  if (client != NULL) {
+    delete client;
+  }
+
+  // Clean up widget
+  if (widget != NULL) {
+    delete widget;
+  }
+
+  // Clean up overview
+  if (overview != NULL) {
+    delete overview;
+  }
+
+  // Clean up connect window
+  if (connectWindow != NULL) {
+    delete connectWindow;
+  }
+
+  // Clean up load data window
+  if (loadDataWindow != NULL) {
+    delete loadDataWindow;
+  }
+
+  // Clean up dataset list dataset file
+  for (int i = 0 ; i < datasetListSize ; i++) {
+    delete [] datasetListFile[i];
+  }
+  delete [] datasetListFile;
+
+  // Clean up dataset list dataset name
+  for (int i = 0 ; i < datasetListSize ; i++) {
+    delete [] datasetListName[i];
+  }
+  delete [] datasetListName;
+
+  // Clean up dataset list dataset prefix
+  for (int i = 0 ; i < datasetListSize ; i++) {
+    delete [] datasetListPrefix[i];
+  }
+  delete [] datasetListPrefix;
+
+  // Destroy mutex
+  pthread_mutex_destroy(&messageMutex);
+
+  // Exit
+  exit(0);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void exit_cb(Fl_Button* b, void* v) {
+
+  // Exit
+  exit_application();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void message_data_cb(Fl_Button* b, void* v) {
+
+  // Set non modal
+  messageWindow -> set_non_modal();
+
+  // Hide message window
+  messageWindow -> hide();
+
+  // Delete message window
+  delete messageWindow;
+  messageWindow = NULL;
+
+  // Show connect window
+  load_data();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void stopLambda_cb(Fl_Button* b, void* v) {
+
+  // Set stop flag
+  lambdaData* info = (lambdaData*) v;
+  info -> stopFlag = true;
+
+  // Hide message window
+  stopLambdaWindow -> hide();
+
+  // Delete message window
+  delete stopLambdaWindow;
+  stopLambdaWindow = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void message_cb(Fl_Button* b, void* v) {
+
+  // Set non modal
+  messageWindow -> set_non_modal();
+
+  // Hide message window
+  messageWindow -> hide();
+
+  // Delete message window
+  delete messageWindow;
+  messageWindow = NULL;
+
+  // Show connect window
+  connect_show();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void mes_script_cb(Fl_Button* b, void* v) {
+
+  // Canceling script
+  _cancelScript = true;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void overview_cb(Fl_Widget *w, void *data) {
+
+  // Exit
+  exit_application();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void process_lambda_message(char* msg) {
+
+  // Message state variables
+  int id = 0;
+  float xpos = 0.0;
+  float ypos = 0.0;
+  float angle = 0.0;
+  int type = 0;
+
+  // id
+  char idb[11];
+  memset(idb, 0, 11);
+  strncpy(idb, &msg[10], 10);
+  id = atoi(idb);
+
+  // xpos
+  char xposb[11];
+  memset(xposb, 0, 11);
+  strncpy(xposb, &msg[20], 10);
+  xpos = atof(xposb);
+
+  // ypos
+  char yposb[11];
+  memset(yposb, 0, 11);
+  strncpy(yposb, &msg[30], 10);
+  ypos = atof(yposb);
+
+  // angle
+  char angleb[11];
+  memset(angleb, 0, 11);
+  strncpy(angleb, &msg[40], 10);
+  angle = atof(angleb);
+
+  // type
+  char typeb[11];
+  memset(typeb, 0, 11);
+  strncpy(typeb, &msg[50], 10);
+  type = atoi(typeb);
+
+
+  //printf("Message: %d %f %f %f %d\n", id, xpos, ypos, angle, type);
+
+
+  // Translate operation
+  if (id == 4) {
+
+    // Up
+    if (type == 1) {
+      // End of push
+      if (translateUp == false) {
+	client -> SendCommandRender();
+      }
+      translateUp = true;
+
+    }
+
+    // Mouse down
+    else if (type == 2) {
+      
+      // Start of push
+      if (translateUp == true) {
+	translatePuckPos[0] = xpos;
+        translatePuckPos[1] = ypos;
+      }
+      translateUp = false;
+      
+    }
+    
+    // Calculate amount the puck has moved in world space
+    float delta[2] = {((xpos - translatePuckPos[0]) * 
+		       (_totalDisplayFrustum[1] - _totalDisplayFrustum[0])), 
+		      ((ypos - translatePuckPos[1]) *
+		       (_totalDisplayFrustum[3] - _totalDisplayFrustum[2]))};
+    
+    // The puck is activated by the user
+    if (translateUp == false) {
+
+      // Add the offset
+      world_translate[0] += delta[0];
+      world_translate[1] += delta[1];
+
+      // Determine translation matrix
+      float T[16];
+      calc_trans(T, 
+		 world_translate[0], 
+		 world_translate[1], 
+		 0.0);
+
+      // Set the translation matrix
+      overview -> SetTranslationMatrix(T);
+      client -> SendTranslationMatrix(T);
+    }
+    
+    // Update the translation puck position
+    translatePuckPos[0] = xpos;
+    translatePuckPos[1] = ypos;
+    
+  }
+
+  
+  // Scale operation
+  if (id == 7) {
+    
+    // Up
+    if (type == 1) {
+      // End of push
+      if (scaleUp == false) {
+ 	client -> SendCommandRender();
+      }
+      scaleUp = true;
+      
+    }
+    
+    // Mouse down
+    else if (type == 2) {
+
+      // Start of push
+      if (scaleUp == true) {
+	scalePuckPos[0] = xpos;
+        scalePuckPos[1] = ypos;
+
+	scalePuckPosI[0] = xpos;
+        scalePuckPosI[1] = ypos;
+
+        scaleAngleI = angle - 87.6;
+        
+        //float scale_pos_f[3] = {0.0, 0.0, 0.0};
+        scale_pos_f[0] = 
+          (scalePuckPos[0] *
+           (_totalDisplayFrustum[1] -_totalDisplayFrustum[0])) +
+          _totalDisplayFrustum[0];
+        scale_pos_f[1] = 
+          (scalePuckPos[1] * 
+           (_totalDisplayFrustum[3] -_totalDisplayFrustum[2])) +
+          _totalDisplayFrustum[2];
+
+        // Position of the puck when clicked in WSC
+        oriX = scale_pos_f[0];
+        oriY = scale_pos_f[1];
+
+        scale_pos_f[0] -= world_translate[0];
+        scale_pos_f[1] -= world_translate[1];    
+        scale_pos_f[0] /= world_scale[0];
+        scale_pos_f[1] /= world_scale[1];
+
+        goodx = scale_pos_f[0];
+        goody = scale_pos_f[1];
+
+      }
+      scaleUp = false;
+      
+      // Calculate amount puck has been rotated
+      float deltaA = 0.0;
+      if ((angle - world_scale_angle) >= 100.0) {
+        deltaA = -1.0;
+      }
+      else if((angle - world_scale_angle) < -100.0) {
+        deltaA = 1.0;
+      }
+      else {
+        deltaA = angle - world_scale_angle;
+      }
+
+      // Calculate amount puck has moved
+      float delta1[2] = {xpos - scalePuckPos[0],
+                         ypos - scalePuckPos[1]};
+
+      // The puck is activated by the user
+      if (scaleUp == false) {
+
+        // Determine the base offset along puck axis
+        float newX = (cos(-scaleAngleI*0.0174532925) * delta1[0]) + 
+          (-sin(-scaleAngleI*0.0174532925) * delta1[1]);
+        float newY = (-sin(scaleAngleI*0.0174532925) * delta1[0]) + 
+          (cos(-scaleAngleI*0.0174532925) * delta1[1]);
+        
+        // Update world scale
+        world_scale[0] *= 1.0 - ((newX * 2.25) + (newY * 2.25));
+        world_scale[1] *= 1.0 - ((newX * 2.25) + (newY * 2.25));
+        world_scale[2] *= 1.0 - ((newX * 2.25) + (newY * 2.25));
+
+        // Don't let scale go below 1.0
+        if (world_scale[0] < 1.0) world_scale[0] = 1.0;
+        if (world_scale[1] < 1.0) world_scale[1] = 1.0;
+        if (world_scale[2] < 1.0) world_scale[2] = 1.0;
+
+        // Determine scale matrix
+        float S[16];
+        calc_scale(S, 
+                   world_scale[0], 
+                   world_scale[1], 
+                   world_scale[2]);
+        
+        
+        float scale_pos_f[3] = {0.0, 0.0, 0.0};
+        scale_pos_f[0] = 
+          (scalePuckPosI[0] * 
+           (_totalDisplayFrustum[1] -_totalDisplayFrustum[0])) + 
+          _totalDisplayFrustum[0];
+        scale_pos_f[1] = 
+          (scalePuckPosI[1] * 
+           (_totalDisplayFrustum[3] -_totalDisplayFrustum[2])) + 
+          _totalDisplayFrustum[2];
+        
+        // Determine new translation based on the scale
+        world_translate[0] = (scale_pos_f[0]) - (goodx*world_scale[0]);
+        world_translate[1] = (scale_pos_f[1]) - (goody*world_scale[1]);
+
+        // Determine new translation matrix
+        float T[16];
+        calc_trans(T, 
+                   world_translate[0], 
+                   world_translate[1], 
+                   0.0);
+        
+        // Update matrices
+        overview -> SetScaleMatrix(S);
+        client -> SendScaleMatrix(S);
+        overview -> SetTranslationMatrix(T);
+        client -> SendTranslationMatrix(T);
+        
+      }
+      
+    }
+
+    // Update puck position and angle
+    scalePuckPos[0] = xpos;
+    scalePuckPos[1] = ypos;
+    world_scale_angle = angle;
+    
+  }
+
+
+  // Rotate operation
+  if (id == 8) {
+    
+    // Up
+    if (type == 1) {
+      // End of push
+      if (rotateUp == false) {
+	client -> SendCommandRender();
+      }
+      rotateUp = true;
+      
+    }
+    
+    // Mouse down
+    else if (type == 2) {
+      
+      // Start of push
+      if (rotateUp == true) {
+
+        // Normalize object's translation to (-1.0, 1.0)
+        float nTx = (world_translate[0] - _totalDisplayFrustum[0]) /
+          (_totalDisplayFrustum[1] - _totalDisplayFrustum[0]);
+        nTx = (nTx * 2.0) - 1.0;
+        float nTy = (world_translate[1] - _totalDisplayFrustum[2]) /
+          (_totalDisplayFrustum[3] - _totalDisplayFrustum[2]);
+        nTy = (nTy * 2.0) - 1.0;
+        
+        // Normalize puck's position to (-1.0, 1.0)
+        float nXpos = (xpos * 2.0) - 1.0;
+        float nYpos = (ypos * 2.0) - 1.0;
+        
+        // Start trackball
+        lambdaTrackball.Start(nXpos - nTx, nYpos - nTy);
+
+      }
+      rotateUp = false;
+     
+    }
+    
+    // The puck is activated by the user
+    if (rotateUp == false) {
+
+      // Normalize object's translation to (-1.0, 1.0)
+      float nTx = (world_translate[0] - _totalDisplayFrustum[0]) /
+        (_totalDisplayFrustum[1] - _totalDisplayFrustum[0]);
+      nTx = (nTx * 2.0) - 1.0;
+      float nTy = (world_translate[1] - _totalDisplayFrustum[2]) /
+        (_totalDisplayFrustum[3] - _totalDisplayFrustum[2]);
+      nTy = (nTy * 2.0) - 1.0;
+
+      // Normalize puck's position to (-1.0, 1.0)
+      float nXpos = (xpos * 2.0) - 1.0;
+      float nYpos = (ypos * 2.0) - 1.0;
+
+      // Update trackball
+      lambdaTrackball.Update(nXpos - nTx, nYpos - nTy);
+      
+      // Get rotation from trackball
+      float R[16];
+      lambdaTrackball.GetRotationMatrix(R);
+
+      // Update matrix
+      overview -> SetRotationMatrix(R);
+      client -> SendRotationMatrix(R);
+
+    }
+    
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void process_message(unsigned char* message) {
+  
+  // Command
+  char command[8];
+  memset(command, 0, 8);
+
+  // Destination
+  int destination = 0;
+
+  // Data packer
+  DataPacker unpacker;
+  unpacker.SetBuffer(message, 2048);
+
+  // Unpack command from buffer
+  for (int i = 0 ; i < 8 ; i++) {
+    unpacker.UnpackChar(&command[i]);
+  }
+  
+  // Unpack destination from buffer
+  unpacker.UnpackInt(&destination);
+  
+
+  // axis off
+  if (!strcmp(command, "CMD_AOF")) {
+
+    // Clear check box
+    //g_miAxis.clear();
+    //g_miAxis.show();
+    //fprintf(stderr, "AxisOff\n");
+
+  }
+
+
+  // lambda table message
+  else if (!strcmp(command, "CMD_LTM")) {
+
+    // Unpack message
+    char msg[60];
+    for (int i = 0 ; i < 60 ; i++) {
+      unpacker.UnpackChar(&msg[i]);
+    }
+
+    // Process
+    process_lambda_message(msg);
+
+  }
+
+
+  // axis on
+  else if (!strcmp(command, "CMD_AON")) {
+
+    // Set check box
+    //g_miAxis.set();
+    //g_miAxis.show();
+    //fprintf(stderr, "AxisOn %d\n", g_miAxis.value());
+
+  }
+
+
+  // clipping planes
+  else if (!strcmp(command, "CMD_CLI")) {
+    
+    // Unpack data from buffer
+    float near = 0.0;
+    float far = 0.0;
+    unpacker.UnpackFloat(&near);
+    unpacker.UnpackFloat(&far);
+    
+  }
+  
+  
+  // exit
+  else if(!strcmp(command, "CMD_EXI")) {
+
+    // Exit
+    //exit_application();
+    disconnect();
+
+  }
+  
+  
+  // data
+  else if(!strcmp(command, "CMD_DAT")) {
+    
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+
+    // Update data bar
+    if (strlen(data) <= 0) {
+      dataBar -> copy_label("No data.");
+    }
+    else {
+      dataBar -> copy_label(data);
+    }
+
+  }
+
+
+  // dataset list file
+  else if(!strcmp(command, "CMD_DSF")) {
+    
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+
+    // Copy data
+    if (datasetListFile != NULL) {
+      strcpy(datasetListFile[destination], data);
+    }
+
+  }
+
+
+  // dataset list name
+  else if(!strcmp(command, "CMD_DSN")) {
+    
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+
+    // Copy data
+    if (datasetListName != NULL) {
+      strcpy(datasetListName[destination], data);
+    }
+
+  }
+
+
+  // dataset list prefix
+  else if(!strcmp(command, "CMD_DSP")) {
+    
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+
+    // Copy data
+    if (datasetListPrefix != NULL) {
+      strcpy(datasetListPrefix[destination], data);
+    }
+
+  }
+
+
+  // data set list size
+  else if(!strcmp(command, "CMD_DSS")) {
+    
+    // Unpack data from buffer
+    int data;
+    unpacker.UnpackInt(&data);
+
+    // Clean up dataset list dataset file
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      delete [] datasetListFile[i];
+    }
+    delete [] datasetListFile;
+    
+    // Clean up dataset list dataset name
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      delete [] datasetListName[i];
+    }
+    delete [] datasetListName;
+    
+    // Clean up dataset list dataset prefix
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      delete [] datasetListPrefix[i];
+    }
+    delete [] datasetListPrefix;
+
+    // Update data
+    datasetListSize = data;
+
+    // Allocate memory for dataset list dataset file name
+    datasetListFile = new char*[datasetListSize];
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      datasetListFile[i] = new char[1024];
+    }
+
+    // Allocate memory for dataset list dataset name
+    datasetListName = new char*[datasetListSize];
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      datasetListName[i] = new char[1024];
+    }
+    
+    // Allocate memory for dataset list dataset prefix
+    datasetListPrefix = new char*[datasetListSize];
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      datasetListPrefix[i] = new char[1024];
+    }
+
+    // Update dataset lists
+    for (int i = 0 ; i < datasetListSize ; i++) {
+      client -> GetDatasetListFile(i);
+      client -> GetDatasetListName(i);
+      client -> GetDatasetListPrefix(i);
+    }
+
+  }
+  
+  
+  // display size
+  else if (!strcmp(command, "CMD_DIS")) {
+
+    // Unpack data from buffer
+    int width = 0;
+    int height = 0;
+    int flag = 0;
+    float left = 0.0;
+    float right = 0.0;
+    float bottom = 0.0;
+    float top = 0.0;
+    unpacker.UnpackInt(&width);
+    unpacker.UnpackInt(&height);
+    unpacker.UnpackInt(&flag);
+    unpacker.UnpackFloat(&left);
+    unpacker.UnpackFloat(&right);
+    unpacker.UnpackFloat(&bottom);
+    unpacker.UnpackFloat(&top);
+    
+    // Full screen flag
+    bool fullScreen = false;
+    if (flag == 1) {
+      fullScreen = true;
+    }
+    
+  }
+
+
+  // dataset type
+  else if(!strcmp(command, "CMD_DTP")) {
+    
+    // Unpack data from buffer
+    int data;
+    unpacker.UnpackInt(&data);
+
+    // Copy dataset type
+    datasetType = data;
+
+    // Set maximum scalar value
+    if (datasetType == 8) {
+      widget -> SetMaximumScalar(255.0);
+    }
+    else if (datasetType == 16) {
+      widget -> SetMaximumScalar(65536.0);
+    }
+
+  }
+  
+  
+  // frustum
+  else if (!strcmp(command, "CMD_FRU")) {
+    
+    // Unpack data from buffer
+    float left = 0.0;
+    float right = 0.0;
+    float bottom = 0.0;
+    float top = 0.0;
+    unpacker.UnpackFloat(&left);
+    unpacker.UnpackFloat(&right);
+    unpacker.UnpackFloat(&bottom);
+    unpacker.UnpackFloat(&top);
+    
+  }
+  
+  
+  // map
+  else if (!strcmp(command, "CMD_MAP")) {
+    
+    // Unpack data from buffer
+    unsigned char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackUnsignedChar(&data[i]);
+    }
+    
+  }
+
+
+  // overview vertices
+  else if (!strcmp(command, "CMD_OVV")) {
+    
+    // Unpack data from buffer
+    float data[24];
+    for (int i = 0 ; i < 24 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Set vertices
+    Vertex vertex[8];
+    vertex[0].SetXYZ(data[0], data[1], data[2]);
+    vertex[1].SetXYZ(data[3], data[4], data[5]);
+    vertex[2].SetXYZ(data[6], data[7], data[8]);
+    vertex[3].SetXYZ(data[9], data[10], data[11]);
+    vertex[4].SetXYZ(data[12], data[13], data[14]);
+    vertex[5].SetXYZ(data[15], data[16], data[17]);
+    vertex[6].SetXYZ(data[18], data[19], data[20]);
+    vertex[7].SetXYZ(data[21], data[22], data[23]);
+    
+    // Set property
+    if (overview != NULL) {
+      overview -> SetVertices(vertex);
+    }
+
+  }
+
+
+  // progress
+  else if (!strcmp(command, "CMD_PRO")) {
+    
+    // Unpack data from buffer
+    int value = 0;
+    int total = 0;
+    unpacker.UnpackInt(&value);
+    unpacker.UnpackInt(&total);
+
+    // Update progress bar
+    char progress[128];
+    sprintf(progress, "Level %d of %d", value + 1, total);
+    progressBar -> copy_label(progress);
+    progressLevel = value;
+    totalLevel = total;
+    //fprintf(stderr, "Update Progress Bar: %d of %d\n", value, total);
+
+  }
+  
+  
+  // rotation matrix
+  else if (!strcmp(command, "CMD_ROT")) {
+    
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Set property
+    if (overview != NULL) {
+      overview -> SetRotationMatrix(data);
+    }
+    
+  }
+  
+  
+  // scale matrix
+  else if (!strcmp(command, "CMD_SCA")) {
+    
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+
+    // Set property
+    if (overview != NULL) {
+      overview -> SetScaleMatrix(data);
+    }
+    
+  }
+
+
+  // slice frequency
+  else if (!strcmp(command, "CMD_SLF")) {
+    
+    // Unpack data from buffer
+    float data = 0.0;
+    unpacker.UnpackFloat(&data);
+
+    // Set slice frequency
+    sliceFrequency = data;
+
+  }
+  
+
+  // total display dimensions
+  else if (!strcmp(command, "CMD_TDD")) {
+    
+    // Unpack data from buffer
+    int w = 0;
+    int h = 0;
+    unpacker.UnpackInt(&w);
+    unpacker.UnpackInt(&h);
+
+    // Set property
+    if (mainWindow != NULL) {
+      mainWindow -> size(640, ((int) (((float) h / (float) w) * 640.0)) + 50);
+    }
+
+    // Set property
+    if (overview != NULL) {
+      overview -> size(640, (int) (((float) h / (float) w) * 640.0));
+    }    
+
+    // Set property
+    if (statusBar != NULL) {
+      statusBar -> position(0, mainWindow -> h() - 20);
+    }    
+
+    // Set progress
+    if (progressBar != NULL) {
+      progressBar -> position(213, mainWindow -> h() - 20);
+    }    
+
+    // Set property
+    if (dataBar != NULL) {
+      dataBar -> position(427, mainWindow -> h() - 20);
+    }    
+    
+  }
+
+
+  // total display frustum
+  else if (!strcmp(command, "CMD_TDF")) {
+    
+    // Unpack data from buffer
+    float data[6];
+    unpacker.UnpackFloat(&data[0]);
+    unpacker.UnpackFloat(&data[1]);
+    unpacker.UnpackFloat(&data[2]);
+    unpacker.UnpackFloat(&data[3]);
+    unpacker.UnpackFloat(&data[4]);
+    unpacker.UnpackFloat(&data[5]);
+
+    // Set for LambdaTracker
+    _totalDisplayFrustum[0] = data[0];
+    _totalDisplayFrustum[1] = data[1];
+    _totalDisplayFrustum[2] = data[2];
+    _totalDisplayFrustum[3] = data[3];
+    _totalDisplayFrustum[4] = data[4];
+    _totalDisplayFrustum[5] = data[5];
+
+    // Set property
+    if (overview != NULL) {
+      overview -> SetFrustum(data);
+    }
+    
+  }
+  
+  
+  // translation matrix
+  else if (!strcmp(command, "CMD_TRA")) {
+    
+    // Unpack data from buffer
+    float data[16];
+    for (int i = 0 ; i < 16 ; i++) {
+      unpacker.UnpackFloat(&data[i]);
+    }
+     
+    // Set property
+    if (overview != NULL) {
+      overview -> SetTranslationMatrix(data);
+    }
+
+  }
+  
+  
+  // vertical field of view
+  else if (!strcmp(command, "CMD_VFV")) {
+    
+    // Unpack data from buffer
+    float vFOV = 0.0;
+    unpacker.UnpackFloat(&vFOV);
+    
+  }
+  
+  
+  // viewport matrix
+  else if (!strcmp(command, "CMD_VIE")) {
+    
+    // Unpack data from buffer
+    int x = 0;
+    int y = 0;
+    int w = 0;
+    int h = 0;
+    unpacker.UnpackInt(&x);
+    unpacker.UnpackInt(&y);
+    unpacker.UnpackInt(&w);
+    unpacker.UnpackInt(&h);
+    
+  }
+
+
+  // script canceled
+  else if (!strcmp(command, "SCR_CAN")) {
+    
+    // Set non modal
+    messageWindow -> set_non_modal();
+
+    // Hide message window
+    messageWindow -> hide();
+
+    // Delete message window
+    delete messageWindow;
+    messageWindow = NULL;
+
+    // Print message
+    fl_message("Script canceled.");
+
+  }
+
+
+  // script complete
+  else if (!strcmp(command, "SCR_COM")) {
+    
+    // Set non modal
+    messageWindow -> set_non_modal();
+
+    // Hide message window
+    messageWindow -> hide();
+
+    // Delete message window
+    delete messageWindow;
+    messageWindow = NULL;
+
+    // Unpack data from buffer
+    char data[1024];
+    for (int i = 0 ; i < 1024 ; i++) {
+      unpacker.UnpackChar(&data[i]);
+    }
+
+    // Print message
+    fl_message("%s", data);
+
+  }  
+  
+
+  // undefined command
+  else {
+  }
+  
+
+  // Redraw overview
+  overview -> redraw();
+
+  // Redraw transfer function widget
+  widget -> Redraw();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void render_cb() {
+
+  // Send render command
+  if (client != NULL) {
+    client -> SendCommandRender();
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void rotation_cb(float* m) {
+
+  // Send rotation matrix
+  if (client != NULL) {
+    client -> SendRotationMatrix(m);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void scale_cb(float* m) {
+
+  // Update scale for LambdaTable
+  world_scale[0] = m[0];
+  world_scale[1] = m[5];
+  world_scale[2] = m[10];
+
+  // Send scale matrix
+  if (client != NULL) {
+    client -> SendScaleMatrix(m);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void translation_cb(float* m) {
+
+  // Update translation for LambdaTable
+  world_translate[0] = m[12];
+  world_translate[1] = m[13];
+
+  // Send translation matrix
+  if (client != NULL) {
+    client -> SendTranslationMatrix(m);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void widget_cb(Fl_Widget *w, void *data) {
+
+  // Do nothing
+  return;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char** argv) {
+
+  // Create new client
+  client = new UserInterfaceClient();
+  if (client == NULL) {
+    fprintf(stderr, "Could not create UserInterfaceClient.\n");
+    exit_application();
+  }
+
+  // Create new command observer
+  observer = new UserInterfaceClientConcreteCommand(add_message);
+  if (observer == NULL) {
+    fprintf(stderr, "Could not create UserInterfaceClientConcreteCommand.\n");
+    exit_application();
+  }
+
+  // Set client observer
+  client -> SetObserver(observer);
+
+
+  // Create new widget
+  widget = new Fl_Transfer_Function(100, 560, 640, 400, "Transfer Function");
+
+  // Set maximum scalar value
+  widget -> SetMaximumScalar(255.0);
+
+  // Set callbacks
+  widget -> callback(widget_cb);
+  widget -> SetUpdateCallback(map_cb, widget);
+
+  // Show widget
+  widget -> show();
+
+
+  // Create new overview
+  overview = new Fl_Overview(0, 30, 640, 480);
+
+  // Set callbacks
+  overview -> SetRenderCallback(render_cb);
+  overview -> SetRotationCallback(rotation_cb);
+  overview -> SetScaleCallback(scale_cb);
+  overview -> SetTranslationCallback(translation_cb);
+
+
+  // Create new status bar
+  statusBar = new Fl_Box(0, 510, 213, 20);
+
+  // Set box type
+  statusBar -> box(FL_FLAT_BOX);
+  statusBar -> align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
+  statusBar -> label("Not connected.");
+
+
+  // Create new progress bar
+  progressBar = new Fl_Box(213, 510, 214, 20);
+
+  // Set box type
+  progressBar -> box(FL_FLAT_BOX);
+  progressBar -> align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
+  progressBar -> label("Level");
+
+
+  // Create new data bar
+  dataBar = new Fl_Box(427, 510, 213, 20);
+
+  // Set box type
+  dataBar -> box(FL_FLAT_BOX);
+  dataBar -> align(FL_ALIGN_INSIDE | FL_ALIGN_RIGHT);
+  dataBar -> label("No Data.");
+
+
+  // Create new main window
+  mainWindow = 
+    new Fl_Main_Window(100, 0, 640, 530, "Volume Rendering Application");
+
+  // Add overview window
+  mainWindow -> add(overview);
+
+  // Add status bar
+  mainWindow -> add(statusBar);
+
+  // Add progress bar
+  mainWindow -> add(progressBar);
+
+  // Add data bar
+  mainWindow -> add(dataBar);
+
+  // Create menu items
+  Fl_Menu_Item menuitems[] = {
+    {"&File", 0, 0, 0, FL_SUBMENU},
+    {"&Connect to Server...", FL_CTRL + 'c', (Fl_Callback*) connect_show},
+    {"&Disconnect from Server", FL_CTRL + 'd', (Fl_Callback*) disconnect, 
+     0, FL_MENU_DIVIDER},
+    {"&Shutdown Server", FL_CTRL + 's', (Fl_Callback*) exit_server, 0, 
+     FL_MENU_DIVIDER},
+#ifdef SAGE
+    {"Listen to LambdaTracker...", 0, (Fl_Callback*) listen_lambda, 0,
+     FL_MENU_DIVIDER | FL_MENU_INACTIVE},
+#else
+    {"Listen to LambdaTracker...", 0, (Fl_Callback*) listen_lambda, 0,
+     FL_MENU_DIVIDER},
+#endif
+    {"&Load Data...", FL_CTRL + 'l', (Fl_Callback*) load_data, 0, 
+     FL_MENU_DIVIDER},
+    {"L&oad Script...", FL_CTRL + 'o', (Fl_Callback*) load_script, 0, 
+     FL_MENU_DIVIDER},
+    {"Load Transfer Function...", 0, (Fl_Callback*) load_tf},
+    {"Save Transfer Function...", 0, (Fl_Callback*) save_tf, 0, 
+     FL_MENU_DIVIDER},
+    {"E&xit", FL_CTRL + 'q', (Fl_Callback*) exit_application, 0},
+    {0},
+
+    {"&View", 0, 0, 0, FL_SUBMENU},
+    g_miAxis,
+    g_miBoundingBox,
+    g_miBrickBoxes,
+    {"Slice Frequency...", 0, (Fl_Callback*) slice_frequency, 0, 
+     FL_MENU_DIVIDER},
+    {"Reset View", 0, (Fl_Callback*) reset_view, 0},
+    {0},
+
+    {0}
+  };
+
+  // Set menu items
+  mainWindow -> SetMenuItems(menuitems);
+
+  // Set callback
+  mainWindow -> callback(overview_cb);
+
+  // Show main window
+  mainWindow -> show();
+
+
+  // Check if user entered server on command line
+  if (argc == 3) {
+
+    // Connect to server 
+    connect(argv[1], atoi(argv[2]));
+
+  }
+
+  // User did not enter server on command line
+  else {
+
+    // Show connect window
+    connect_show();
+
+  }
+
+  // Event loop
+  while (true) { 
+
+    // Wait for an event
+    Fl::wait(0.1);
+
+    // Lock message mutex
+    pthread_mutex_lock(&messageMutex);
+
+    // Process messages in queue
+    while (messageQueue.empty() == false) {
+      
+      // Get message
+      unsigned char* message = messageQueue.front();
+
+      // Remove message from queue
+      messageQueue.pop();
+
+      // Process message
+      process_message(message);
+
+      // Clean up message
+      delete [] message;
+
+    }
+
+    // Unlock message mutex
+    pthread_mutex_unlock(&messageMutex);
+
+  }
+
+
+  // Return
+  return 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceServerConcreteCommand.h	(revision 4)
@@ -0,0 +1,202 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_SERVER_CONCRETE_COMMAND_H
+#define USER_INTERFACE_SERVER_CONCRETE_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+
+#include "UserInterfaceServerAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceServerConcreteCommand : 
+public UserInterfaceServerAbstractCommand {
+
+public:
+
+  // Constructor
+  UserInterfaceServerConcreteCommand();
+
+  // Constructor with pointer to instance of class Master
+  UserInterfaceServerConcreteCommand(void* master);
+
+  // Destructor
+  virtual ~UserInterfaceServerConcreteCommand();
+
+  // Get axis state
+  virtual void GetAxis(bool* state);
+
+  // Get axis position
+  virtual void GetAxisPosition(float* x, float* y, float* z);
+
+  // Get bounding box state
+  virtual void GetBoundingBox(bool* state);
+
+  // Get brick box state
+  virtual void GetBrickBox(bool* state);
+
+  // Get clipping planes
+  virtual void GetClippingPlanes(int node, float* near, float* far);
+
+  // Get data
+  virtual void GetData(char* filename);
+
+  // Get data and cache sizes
+  virtual void GetData(char* filename, int* ramSize, int* vramSize);
+
+  // Get dataset list file
+  virtual void GetDatasetListFile(int index, char* file);
+
+  // Get dataset list name
+  virtual void GetDatasetListName(int index, char* name);
+
+  // Get dataset list prefix
+  virtual void GetDatasetListPrefix(int index, char* prefix);
+
+  // Get dataset list size
+  virtual void GetDatasetListSize(int* size);
+
+  // Get dataset type
+  virtual void GetDatasetType(int* type);
+
+  // Get display size
+  virtual void GetDisplaySize(int node, int* width, int* height,
+                              bool* fullScreen,
+                              float* left, float* right,
+                              float* bottom, float* top);
+
+  // Get frustum
+  virtual void GetFrustum(int node, float* left, float* right,
+                          float* bottom, float* top);
+
+  // Get map
+  virtual void GetMap(unsigned char* map);
+
+  // Get overview vertices
+  virtual void GetOverviewVertices(float vertices[24]);
+
+  // Get prefix
+  virtual void GetPrefix(char* prefix);
+
+  // Get rotation matrix
+  virtual void GetRotationMatrix(float m[16]);
+  
+  // Get scale matrix
+  virtual void GetScaleMatrix(float m[16]);
+
+  // Get slice frequency
+  virtual void GetSliceFrequency(double* frequency);
+
+  // Get total display dimensions
+  virtual void GetTotalDisplayDimensions(int* w, int* h);
+
+  // Get total display frustum
+  virtual void GetTotalDisplayFrustum(float frustum[6]);
+
+  // Get translation matrix
+  virtual void GetTranslationMatrix(float m[16]);
+
+  // Get vertical field of view
+  virtual void GetVerticalFieldOfView(float* vFOV);
+
+  // Get viewport
+  virtual void GetViewport(int node, int* x, int* y, int* w, int* h);
+
+  // Reset view
+  virtual void ResetView();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(int node, float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set render flag
+  virtual void SetCommandRender();
+
+  // Set data
+  virtual void SetData(char* filename);
+
+  // Set data and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set frustum
+  virtual void SetFrustum(int node, float left, float right,
+                          float bottom, float top);
+
+  // Set transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set 16-bit transfer function
+  virtual void SetMap16(unsigned char* map);
+  
+  // Set prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float m[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float m[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float m[16]);
+
+  // Set viewport
+  virtual void SetViewport(int node, int x, int y, int w, int h);
+
+private:
+
+  // Pointer to instance of class Master
+  void* _master;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/FrustumPlanes.h
===================================================================
--- trunk/src/testing/app/VRA/src/FrustumPlanes.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/FrustumPlanes.h	(revision 4)
@@ -0,0 +1,102 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FRUSTUM_PLANES_H
+#define FRUSTUM_PLANES_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "Matrix.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define LEFT_PLANE 0
+#define RIGHT_PLANE 1
+#define TOP_PLANE 2
+#define BOTTOM_PLANE 3
+#define NEAR_PLANE 4
+#define FAR_PLANE 5
+#define INSIDE_PLANE 1
+#define INTERSECT_PLANE 0
+#define OUTSIDE_PLANE -1
+#define INSIDE_FRUSTUM 1
+#define INTERSECT_FRUSTUM 0
+#define OUTSIDE_FRUSTUM -1
+
+/*--------------------------------------------------------------------------*/
+
+class FrustumPlanes {
+
+ public:
+  
+  // Default constructor
+  FrustumPlanes();
+
+  // Default destructor
+  ~FrustumPlanes();
+
+  // Calculate the distance from a plane to a point
+  float CalculateDistanceToFrustumPlane(int plane, float x, float y, float z);
+
+  // Calculate each plane of the frustum
+  void CalculateFrustumPlanes();
+
+  // Calculate a cube's relation to the frustum
+  int CalculateRelationToFrustum(float x0, float y0, float z0,
+                                 float x1, float y1, float z1,
+                                 float x2, float y2, float z2,
+                                 float x3, float y3, float z3,
+                                 float x4, float y4, float z4,
+                                 float x5, float y5, float z5,
+                                 float x6, float y6, float z6,
+                                 float x7, float y7, float z7);
+
+  // Calculate a plane's relation to the frustum
+  int CalculateRelationToFrustumPlane(int plane, float x, float y, float z);
+
+  // Set ModelView matrix
+  void SetModelViewMatrix(float mv[16]);
+
+  // Set Projection matrix
+  void SetProjectionMatrix(float p[16]);
+  
+ private:
+
+  // ModelView matrix
+  float _mv[16];
+
+  // ModelView-Projection matrix
+  float _mvp[16];
+
+  // Projection matrix
+  float _p[16];
+
+  // Frustum planes
+  float _planes[6][4];
+  
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/FrustumCalculator.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/FrustumCalculator.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/FrustumCalculator.cpp	(revision 4)
@@ -0,0 +1,258 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "FrustumCalculator.h"
+
+/*--------------------------------------------------------------------------*/
+
+FrustumCalculator::FrustumCalculator() {
+
+  // Initialize display size
+  _displayHeight = 0;
+  _displayWidth = 0;
+
+  // Initialize frustum
+  _frustum[0] = 0.0;
+  _frustum[1] = 0.0;
+  _frustum[2] = 0.0;
+  _frustum[3] = 0.0;
+
+  // Initialize near clipping plane
+  _nearClippingPlane = 0.0;
+
+  _percentage[0] = 0.0;
+  _percentage[1] = 0.0;
+  _percentage[2] = 0.0;
+  _percentage[3] = 0.0;
+
+  // Initialize vertical field of view
+  _verticalFieldOfView = 0.0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+FrustumCalculator::~FrustumCalculator() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::CalculateFrustum() {
+
+  // Calculate aspect ratio of display
+  float aspect = (float) _displayWidth / (float) _displayHeight;
+
+  // Calculate half frustums
+  float half_x = fabs(aspect * 
+                      _nearClippingPlane * 
+                      tanf(_verticalFieldOfView * 0.0174532 / 2));
+  float half_y = fabs(_nearClippingPlane * 
+                      tanf(_verticalFieldOfView * 0.0174532 / 2));
+
+  // Calculate full frsutums
+  float full_x = 2 * half_x;
+  float full_y = 2 * half_y;
+
+  // Calculate frustum based on percentage
+  _frustum[0] = -half_x + (_percentage[0] * full_x);
+  _frustum[1] = -half_x + (_percentage[1] * full_x);
+  _frustum[2] = -half_y + (_percentage[2] * full_y);
+  _frustum[3] = -half_y + (_percentage[3] * full_y);
+
+  // Calculate full frustum for entire display
+  _fullFrustum[0] = -half_x;
+  _fullFrustum[1] = half_x;
+  _fullFrustum[2] = -half_y;
+  _fullFrustum[3] = half_y;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int FrustumCalculator::GetDisplayHeight() {
+
+  // Return display height
+  return _displayHeight;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int FrustumCalculator::GetDisplayWidth() {
+
+  // Return display width
+  return _displayWidth;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetFullFrustum(float* left, float* right,
+                                       float* bottom, float* top) {
+
+  // Get full frustum
+  *left = _fullFrustum[0];
+  *right = _fullFrustum[1];
+  *bottom = _fullFrustum[2];
+  *top = _fullFrustum[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetFullFrustum(float array[4]) {
+
+  // Get full frustum
+  array[0] = _fullFrustum[0];
+  array[1] = _fullFrustum[1];
+  array[2] = _fullFrustum[2];
+  array[3] = _fullFrustum[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetFrustum(float* left, float* right,
+                                   float* bottom, float* top) {
+
+  // Get frustum
+  *left = _frustum[0];
+  *right = _frustum[1];
+  *bottom = _frustum[2];
+  *top = _frustum[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetFrustum(float array[4]) {
+
+  // Get frustum
+  array[0] = _frustum[0];
+  array[1] = _frustum[1];
+  array[2] = _frustum[2];
+  array[3] = _frustum[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float FrustumCalculator::GetNearClippingPlane() {
+
+  // Return near clipping plane
+  return _nearClippingPlane;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetPercentage(float* left, float* right,
+                                      float* bottom, float* top) {
+
+  // Get display percentage
+  *left = _percentage[0];
+  *right = _percentage[1];
+  *bottom = _percentage[2];
+  *top = _percentage[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::GetPercentage(float array[4]) {
+
+  // Get display percentage
+  array[0] = _percentage[0];
+  array[1] = _percentage[1];
+  array[2] = _percentage[2];
+  array[3] = _percentage[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+float FrustumCalculator::GetVerticalFieldOfView() {
+
+  // Return vFOV
+  return _verticalFieldOfView;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetDisplayHeight(int pixels) {
+
+  // Set display height
+  _displayHeight = pixels;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetDisplayWidth(int pixels) {
+
+  // Set display width
+  _displayWidth = pixels;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetNearClippingPlane(float near) {
+
+  // Set near clipping plane
+  _nearClippingPlane = near;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetPercentage(float left, float right, 
+                                      float bottom, float top) {
+
+  // Set display percentage
+  _percentage[0] = left;
+  _percentage[1] = right;
+  _percentage[2] = bottom;
+  _percentage[3] = top;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetPercentage(float array[4]) {
+
+  // Set display percentage
+  _percentage[0] = array[0];
+  _percentage[1] = array[1];
+  _percentage[2] = array[2];
+  _percentage[3] = array[3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void FrustumCalculator::SetVerticalFieldOfView(float angle) {
+
+  // Set vFOV
+  _verticalFieldOfView = angle;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Log.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Log.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Log.cpp	(revision 4)
@@ -0,0 +1,166 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Log.h"
+
+/*--------------------------------------------------------------------------*/
+
+// Define logCount
+int Log::logCount = 0;
+
+// Define logFile
+FILE* Log::logFile = NULL;
+
+// Define logMutex
+pthread_mutex_t Log::logMutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*--------------------------------------------------------------------------*/
+
+void Log::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Rank
+  int rank = 0;
+
+  // Get rank (This is a hack)
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  // Clock time
+  struct timeval clockTime;
+
+  // Get time
+  gettimeofday(&clockTime, NULL);
+
+  // Convert time to microseconds
+  long long t = ((long long) clockTime.tv_sec * (long long) 1000000) + 
+    (long long) clockTime.tv_usec;
+
+  // Lock mutex
+  pthread_mutex_lock(&Log::logMutex);
+
+  // Print message and time to standard output
+  //fprintf(stderr, 
+  //      "[%d %d Log - Time: %ds %ldus %s]\n",
+  //      rank, Log::logCount++, clockTime.tv_sec, clockTime.tv_usec, message);
+  if (Log::logFile != NULL) {
+    fprintf(logFile, 
+            "[%d %d Log - Time: %lldus %s]\n",
+            rank, Log::logCount++, t, message);
+  }
+
+  // Unlock mutex
+  pthread_mutex_unlock(&Log::logMutex);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Log::Start() {
+
+#ifdef LOG
+
+  // Rank
+  int rank = 0;
+
+  // Get rank (This is a hack)
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  // Clock time
+  struct timeval clockTime;
+
+  // Get time
+  gettimeofday(&clockTime, NULL);
+
+  // Convert time to microseconds
+  long long t = ((long long) clockTime.tv_sec * (long long) 1000000) + 
+    (long long) clockTime.tv_usec;
+
+  // Create filename
+  char filename[256];
+  memset(filename, 0, 256);
+  sprintf(filename, 
+          "/pvfs2/evl/schwarz/benchmarks/VRA_LOG_%d_%lld", 
+          rank, t);
+
+  // Attempt to open log file
+  if ((Log::logFile = fopen(filename, "w")) == NULL) {
+    fprintf(stderr, "Log: Can't open log file.\n");
+  }
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Log::Start(char* sufix) {
+
+#ifdef LOG
+
+  // Rank
+  int rank = 0;
+
+  // Get rank (This is a hack)
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  // Clock time
+  struct timeval clockTime;
+
+  // Get time
+  gettimeofday(&clockTime, NULL);
+
+  // Convert time to microseconds
+  long long t = ((long long) clockTime.tv_sec * (long long) 1000000) +
+    (long long) clockTime.tv_usec;
+
+  // Create filename
+  char filename[512];
+  memset(filename, 0, 512);
+  sprintf(filename, 
+          "/pvfs2/evl/schwarz/benchmarks/VRA_LOG_%d_%lld_%s", 
+          rank, t, sufix);
+
+  // Attempt to open log file
+  if ((Log::logFile = fopen(filename, "w")) == NULL) {
+    fprintf(stderr, "Log: Can't open log file.\n");
+  }
+
+#endif                        
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Log::Stop() {
+
+#ifdef LOG
+
+  // Close log file
+  if (Log::logFile != NULL) {
+    fclose(Log::logFile);
+  }
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServer.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServer.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServer.cpp	(revision 4)
@@ -0,0 +1,522 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "SynchronizerServer.h"
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServer::SynchronizerServer() {
+
+  // Initialize condition mutex
+  pthread_mutex_init(&_conditionMutex, NULL);
+
+  // Initialize condition variable
+  pthread_cond_init (&_conditionVariable, NULL);
+
+  // Initialize finalize flag
+  _finalizeFlag = false;
+
+  // Initialize current level
+  _level = 0;
+
+  // Initialize number of clients connected
+  _numberOfClients = 0;
+
+  // Initialize number of clients waiting at barrier
+  _numberOfClientsWaiting = 0;
+
+  // Initialize port number
+  _port = 0;
+
+  // Initialize progress observer
+  _progressObserver = NULL;
+
+  // Initialize server socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+SynchronizerServer::~SynchronizerServer() {
+
+  // Clean up mutex
+  pthread_mutex_destroy(&_conditionMutex);
+
+  // Clean up condition variable
+  pthread_cond_destroy(&_conditionVariable);
+
+  // If socket is open
+  if (_serverSocketFileDescriptor != -1) {
+
+    // Shutdown socket
+    if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+      perror("SynchronizerServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close(_serverSocketFileDescriptor) == -1) {
+      perror("SynchronizerServer: Error during socket close");
+    }
+
+  }
+
+  // Close client sockets
+  for (int i = 0 ; i < _numberOfClients ; i++) {
+
+    // If socket is opne
+    if (_clientInfo[i]._clientSocketFileDescriptor != -1) {
+
+      // Shutdown socket
+      if (shutdown(_clientInfo[i]._clientSocketFileDescriptor, 
+                   SHUT_RDWR) == -1) {
+        perror("SynchronizerServer: Error during socket shutdown");
+      }
+
+      // Close socket
+      if (close(_clientInfo[i]._clientSocketFileDescriptor) == -1) {
+        perror("SynchronizerServer: Error during socket close");
+      }
+
+    }
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerServer::Finalize() {
+
+  // If no clients are connected, force it to quit
+  if (_numberOfClients == 0) {
+    _finalizeFlag = true;
+  }
+
+  // Wait for monitor thread to complete
+  pthread_join(_monitorThread, NULL);
+
+  // Shutdown socket
+  if (shutdown(_serverSocketFileDescriptor, SHUT_RDWR) == -1) {
+    perror("SynchronizerServer: Error during server socket shutdown");
+  }
+
+  // Close socket
+  if (close(_serverSocketFileDescriptor) == -1) {
+    perror("SynchronizerServer: Error during server socket close");
+  }
+
+  // Wait for listen thread to complete
+  pthread_join(_listenThread, NULL);
+
+  // Wait for client threads to complete
+  for (int i = 0 ; i < _numberOfClients ; i++) {
+    pthread_join(_clientThread[i], NULL);
+  }
+
+  // Reset socket file descriptor
+  _serverSocketFileDescriptor = -1;
+
+  // Reset number of connected clients
+  _numberOfClients = 0;
+
+  // Reset number of clients waiting at barrier
+  _numberOfClientsWaiting = 0;
+
+  // Reset port
+  _port = 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerServer::Init(int port) {
+
+  // Set thread state
+  _listenInfo._clientInfo = _clientInfo;
+  _listenInfo._clientThread = _clientThread;
+  _listenInfo._conditionMutex = &_conditionMutex;
+  _listenInfo._conditionVariable = &_conditionVariable;
+  _listenInfo._finalizeFlag = &_finalizeFlag;
+  _listenInfo._level = &_level;
+  _listenInfo._numberOfClients = &_numberOfClients;
+  _listenInfo._numberOfClientsWaiting = &_numberOfClientsWaiting;
+  _listenInfo._port = &_port;
+  _listenInfo._progressObserver = _progressObserver;
+  _listenInfo._serverAddress = &_serverAddress;
+  _listenInfo._serverSocketFileDescriptor = &_serverSocketFileDescriptor;
+
+  // Initialize server port
+  _port = port;
+
+  // Create thread to listen for new clients
+  pthread_create(&_listenThread, 
+                 NULL, 
+                 SynchronizerServer::ListenThreadFunction,
+                 &_listenInfo);
+
+  // Create thread to monitor number of clients waiting at barrier
+  pthread_create(&_monitorThread,
+                 NULL,
+                 SynchronizerServer::MonitorThreadFunction,
+                 &_listenInfo);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *SynchronizerServer::ClientThreadFunction(void* ptr) {
+
+  // Cast thread info class
+  SynchronizerServerClientThreadInfo* info = 
+    (SynchronizerServerClientThreadInfo*) ptr;
+
+  // Exit flag
+  bool exitFlag = false;
+
+  // Message buffer
+  char buffer[256];
+
+  // Message length
+  int messageLength = 0;
+
+  // Loop receiving messages
+  while (exitFlag == false) {
+
+    // Initialize message length
+    messageLength = 0;
+
+    // Initialize buffer
+    memset(buffer, 0, 256);
+
+    // Wait for message from client
+    if ((messageLength = recv(info -> _clientSocketFileDescriptor, 
+                              buffer, 
+                              255, 
+                              MSG_WAITALL)) != 255) {
+      perror("SynchronizerServer: Error receiving message");
+
+      // Set exit flag
+      exitFlag = true;
+    }
+
+    // Command
+    char command[256];
+    memset(command, 0, 256);
+
+    // Level
+    int level = 0;
+
+    // Get command
+    sscanf(buffer, "%s %d", command, &level);
+
+    // Process barrier message
+    if (!strcmp(command, "MSG_BARRIER")) {
+
+      // Lock mutex
+      pthread_mutex_lock(info -> _conditionMutex);
+
+      // Increment number of clients waiting at barrier
+      *(info -> _numberOfClientsWaiting) += 1;
+
+      // Update level
+      *(info -> _level) = level;
+
+      // Check condition and signal if all nodes are waiting on barrier
+      if (*(info -> _numberOfClientsWaiting) >= *(info -> _numberOfClients)) {
+        pthread_cond_signal(info -> _conditionVariable);
+      }
+
+      // Unlock mutex
+      pthread_mutex_unlock(info -> _conditionMutex);
+
+    }
+
+    // Process disconnect message
+    else if(!strcmp(command, "MSG_FINALIZE")) {
+      
+      // Lock mutex
+      pthread_mutex_lock(info -> _conditionMutex);
+
+      // Set finalize flag
+      *(info -> _finalizeFlag) = true;
+
+      // Increment number of clients waiting at barrier
+      *(info -> _numberOfClientsWaiting) += 1;
+
+      // Update level
+      *(info -> _level) = level;
+
+      // Check condition and signal if all nodes are waiting on barrier
+      if (*(info -> _numberOfClientsWaiting) >= *(info -> _numberOfClients)) {
+        pthread_cond_signal(info -> _conditionVariable);
+      }
+
+      // Unlock mutex
+      pthread_mutex_unlock(info -> _conditionMutex);
+
+      // Set exit flag
+      exitFlag = true;
+
+    }
+    
+    // Unknown message
+    else {
+      fprintf(stderr, "SynchronizerServer: Unknown message from client\n");
+    }
+    
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *SynchronizerServer::ListenThreadFunction(void* ptr) {
+
+  // Cast listen thread info class
+  SynchronizerServerListenThreadInfo* info = 
+    (SynchronizerServerListenThreadInfo*) ptr;
+
+  // Create server socket
+  if ((*(info -> _serverSocketFileDescriptor) = socket(AF_INET,
+                                                       SOCK_STREAM, 
+                                                       0)) == -1) {
+    perror("SynchronizerServer: Error creating socket");
+  }
+
+  // Set SO_REUSEADDR
+  int optVal = 1;
+  int optLen = sizeof(optVal);
+  if(setsockopt(*(info -> _serverSocketFileDescriptor), 
+                SOL_SOCKET, 
+                SO_REUSEADDR, 
+                (void*) &optVal, 
+                (socklen_t) optLen) != 0) {
+    perror("SynchronizerServer: Error setting SO_REUSEADDR");
+  }
+
+  // Initialize server address
+  memset(info -> _serverAddress, 0, sizeof(*(info -> _serverAddress)));
+  (*(info -> _serverAddress)).sin_family = AF_INET;
+  (*(info -> _serverAddress)).sin_port = htons(*(info -> _port));
+
+  // Bind address
+  if (bind(*(info -> _serverSocketFileDescriptor), 
+           (struct sockaddr*) info -> _serverAddress, 
+           sizeof(*(info -> _serverAddress))) != 0) {
+    perror("SynchronizerServer: Error binding address");
+    close(*(info -> _serverSocketFileDescriptor));
+  }
+
+  // Set listen mode
+  if (listen(*(info -> _serverSocketFileDescriptor), 5) != 0) {
+    perror("SynchronizerServer: Error setting listen mode");
+    close(*(info -> _serverSocketFileDescriptor));
+  }
+
+  // Loop accepting new connections
+  while (1) {
+
+    // Variables to hold client info
+    struct sockaddr_in clientAddress;
+    int clientLength;
+    int clientSocketFileDescriptor;
+
+    // Initialize variables to hold client info
+    memset(&clientAddress, 0, sizeof(clientAddress));
+    clientLength = sizeof(clientAddress);
+    clientSocketFileDescriptor = 0;
+
+    // Wait for a new connection
+    clientSocketFileDescriptor = 
+      accept(*(info -> _serverSocketFileDescriptor), 
+             (struct sockaddr*) &clientAddress, 
+             (socklen_t*) &clientLength);
+
+    // Check for error with accept
+    if (clientSocketFileDescriptor == -1) {
+      if (*(info -> _finalizeFlag) == true) {
+        pthread_exit(NULL);
+      }
+      else {
+        perror("SynchronizerServer: Error accepting new connections");
+      }
+    }
+
+    // Set SO_REUSEADDR
+    int optVal = 1;
+    int optLen = sizeof(optVal);
+    if(setsockopt(clientSocketFileDescriptor, 
+                  SOL_SOCKET, 
+                  SO_REUSEADDR, 
+                  (void*) &optVal, 
+                  (socklen_t) optLen) != 0) {
+      perror("SynchronizerServer: Error setting SO_REUSEADDR");
+    }
+
+    // Lock mutex
+    pthread_mutex_lock(info -> _conditionMutex);
+
+    // Check for error during accept
+    if (clientSocketFileDescriptor == -1) {
+      perror("SynchronizerServer: Error accepting new connection");
+      close(*(info -> _serverSocketFileDescriptor));
+    }
+
+    // Update client address
+    memcpy(&((info->_clientInfo)[*(info->_numberOfClients)]._clientAddress),
+           &clientAddress,
+           sizeof(clientAddress));
+
+    // Update client socket file descriptor
+    (info->_clientInfo)[*(info->_numberOfClients)]._clientSocketFileDescriptor =
+      clientSocketFileDescriptor;
+
+    // Update mutex and condition variable
+    (info->_clientInfo)[*(info->_numberOfClients)]._conditionMutex =
+      info -> _conditionMutex;
+    (info->_clientInfo)[*(info->_numberOfClients)]._conditionVariable =
+      info -> _conditionVariable;
+
+    // Update finalize flag
+    (info->_clientInfo)[*(info->_numberOfClients)]._finalizeFlag =
+      info -> _finalizeFlag;
+
+    // Update finalize flag
+    (info->_clientInfo)[*(info->_numberOfClients)]._level =
+      info -> _level;
+
+    // Update number of clients and number of clients waiting
+    (info->_clientInfo)[*(info->_numberOfClients)]._numberOfClients =
+      info -> _numberOfClients;
+    (info->_clientInfo)[*(info->_numberOfClients)]._numberOfClientsWaiting =
+      info -> _numberOfClientsWaiting;
+
+    // Create thread to handle new client
+    pthread_create(&(info -> _clientThread)[*(info -> _numberOfClients)], 
+                   NULL, 
+                   SynchronizerServer::ClientThreadFunction,
+                   &(info -> _clientInfo)[*(info -> _numberOfClients)]);
+
+    // Increment number of connected clients
+    *(info -> _numberOfClients) += 1;
+
+    // Unlock mutex
+    pthread_mutex_unlock(info -> _conditionMutex);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void *SynchronizerServer::MonitorThreadFunction(void* ptr) {
+
+  // Cast listen thread info class
+  SynchronizerServerListenThreadInfo* info = 
+    (SynchronizerServerListenThreadInfo*) ptr;
+
+  // Exit flag
+  bool exitFlag = false;
+
+  // Message buffer
+  char buffer[256];
+
+  // Message length
+  int messageLength = 0;
+
+  // Loop waiting for all clients to reach barrier or finalize
+  while (exitFlag == false) {
+
+    // Lock mutex
+    pthread_mutex_lock(info -> _conditionMutex);
+
+    // Check condition and signal if all nodes are waiting on barrier
+    while (*(info -> _numberOfClientsWaiting) < *(info -> _numberOfClients)) {
+      pthread_cond_wait(info -> _conditionVariable, info -> _conditionMutex);
+    }
+
+    // Initialize buffer
+    memset(buffer, 0, 256);
+    sprintf(buffer, "MSG_CONTINUE");
+
+    // Initialize message length
+    messageLength = 0;
+
+    // Send continue message to all clients
+    for (int i = 0 ; i < *(info -> _numberOfClients) ; i++) {
+      if ((messageLength = 
+           send((info -> _clientInfo)[i]._clientSocketFileDescriptor,
+                buffer,
+                255,
+                0)) != 255) {
+        perror("SynchronizerServer: Error sending barrier message");
+      }
+    }
+
+    // Update level in observer
+    if (info -> _progressObserver != NULL) {
+      info -> _progressObserver -> Execute(*(info -> _level));
+    }
+
+    // Reset number of clients waiting at barrier
+    *(info -> _numberOfClientsWaiting) = 0;
+
+    // Check finalize flag
+    if (*(info -> _finalizeFlag) == true) {
+       exitFlag = true;
+    }
+
+    // Unlock mutex
+    pthread_mutex_unlock(info -> _conditionMutex);
+
+  }
+
+  // Shutdown communication and close each client socket
+  for (int i = 0 ; i < *(info -> _numberOfClients) ; i++) {
+
+    // Shutdown communication
+    if (shutdown((info -> _clientInfo)[i]._clientSocketFileDescriptor, 
+                 SHUT_RDWR) == -1) {
+      perror("SynchronizerServer: Error during socket shutdown");
+    }
+
+    // Close socket
+    if (close((info -> _clientInfo)[i]._clientSocketFileDescriptor) == -1) {
+      perror("SynchronizerServer: Error during socket close");
+    }
+
+    // Reset socket file descriptor
+    (info -> _clientInfo)[i]._clientSocketFileDescriptor = -1;
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void SynchronizerServer::SetProgressObserver(SynchronizerServerAbstractCommand* 
+                                             observer) {
+
+  // Set observer
+  _progressObserver = observer;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Dialog.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Dialog.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Dialog.h	(revision 4)
@@ -0,0 +1,65 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_DIALOG__H
+#define FL_DIALOG_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Dialog : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Dialog(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Dialog();
+
+  // Set message
+  void SetMessage(char* message);
+
+  // Set connect button callback
+  void SetOKButtonCallback(Fl_Callback* cb, void* v);
+
+private:
+
+  // Message
+  Fl_Box* _box;
+
+  // OK button
+  Fl_Return_Button* _okButton;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/UserInterfaceClientAbstractCommand.h	(revision 4)
@@ -0,0 +1,137 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef USER_INTERFACE_ABSTRACT_COMMAND_H
+#define USER_INTERFACE_ABSTRACT_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+class UserInterfaceClientAbstractCommand {
+
+public:
+
+  // Destructor
+  virtual ~UserInterfaceClientAbstractCommand();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(int node, float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set data set filename
+  virtual void SetData(char* filename);
+
+  // Set data set filename and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set data set list file
+  virtual void SetDatasetListFile(int index, char* file);
+
+  // Set data set list name
+  virtual void SetDatasetListName(int index, char* name);
+
+  // Set data set list prefix
+  virtual void SetDatasetListPrefix(int index, char* prefix);
+
+  // Set data set list size
+  virtual void SetDatasetListSize(int size);
+
+  // Set data set type
+  virtual void SetDatasetType(int type);
+
+  // Set display size
+  virtual void SetDisplaySize(int node, int width, int height, 
+                              bool fullScreen, 
+                              float left, float right, 
+                              float bottom, float top);
+
+  // Set frustum
+  virtual void SetFrustum(int node, float left, float right,
+                          float bottom, float top);
+
+  // Set transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set overview vertices
+  virtual void SetOverviewVertices(float vertices[24]);
+
+  // Set data prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set progress
+  virtual void SetProgress(int value, int total);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float m[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float m[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set total display dimensions
+  virtual void SetTotalDisplayDimensions(int w, int h);
+
+  // Set total display frustum
+  virtual void SetTotalDisplayFrustum(float frustum[6]);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float m[16]);
+
+  // Set vertical field of view
+  virtual void SetVerticalFieldOfView(float vFOV);
+
+  // Set viewport
+  virtual void SetViewport(int node, int x, int y, int w, int h);
+
+protected:
+
+  // Constructor
+  UserInterfaceClientAbstractCommand();
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Octree.h
===================================================================
--- trunk/src/testing/app/VRA/src/Octree.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Octree.h	(revision 4)
@@ -0,0 +1,107 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef OCTREE_H
+#define OCTREE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class Octree {
+
+ public:
+
+  // Default constructor
+  Octree();
+
+  // Default destructor
+  ~Octree();
+
+  // Get data format
+  int GetDataFormat();
+
+  // Get data type
+  int GetDataType();
+
+  // Get number of levels
+  int GetNumberOfLevels();
+
+  // Get number of nodes
+  int GetNumberOfNodes();
+
+  // Get root
+  OctreeNode* GetRoot();
+
+  // Load octree recursively from file
+  void LoadFromFile(const char* filename);
+
+  // Load octree from file
+  void LoadFromFile2(const char* filename);
+
+  // Load octree from file recursively called from LoadFromFile2
+  void LoadFromFileRecursive(FILE* fptr, OctreeNode* node);
+
+  // Set data format
+  void SetDataFormat(int format);
+
+  // Set data type
+  void SetDataType(int type);
+
+  // Set number of levels
+  void SetNumberOfLevels(int numberOfLevels);
+
+  // Set number of nodes
+  void SetNumberOfNodes(int numberOfNodes);
+
+  // Set file prefix
+  void SetPrefix(const char* prefix);
+
+  // Set root
+  void SetRoot(OctreeNode* root);
+
+ private:
+
+  // Data format
+  int _dataFormat;
+
+  // Data type
+  int _dataType;
+
+  // Number of levels;
+  int _numberOfLevels;
+
+  // Number of nodes
+  int _numberOfNodes;
+
+  // File prefix
+  char _prefix[1024];
+
+  // Root node
+  OctreeNode* _root;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerClientThreadInfo.cpp	(revision 4)
@@ -0,0 +1,57 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#include "SynchronizerServerClientThreadInfo.h"
+
+/*---------------------------------------------------------------------------*/
+
+SynchronizerServerClientThreadInfo::SynchronizerServerClientThreadInfo() {
+
+  // Initialize to 0
+  memset(&_clientAddress, 0, sizeof(_clientAddress));
+
+  // Initialize to 0
+  _clientSocketFileDescriptor = 0;
+
+  // Initialize to NULL
+  _conditionMutex = NULL;
+
+  // Initialize to NULL
+  _conditionVariable = NULL;
+
+  // Initialize to NULL
+  _finalizeFlag = NULL;
+
+  // Initialize to NULL
+  _level = NULL;
+
+  // Initialize to NULL
+  _numberOfClients = NULL;
+
+  // Initialize to NULL
+  _numberOfClientsWaiting = NULL;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+SynchronizerServerClientThreadInfo::~SynchronizerServerClientThreadInfo() {
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.h
===================================================================
--- trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CommunicatorAbstractCommand.h	(revision 4)
@@ -0,0 +1,113 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef COMMUNICATOR_ABSTRACT_COMMAND_H
+#define COMMUNICATOR_ABSTRACT_COMMAND_H
+
+/*--------------------------------------------------------------------------*/
+
+class CommunicatorAbstractCommand {
+
+public:
+
+  // Destructor
+  virtual ~CommunicatorAbstractCommand();
+
+  // Set axis off
+  virtual void SetAxisOff();
+
+  // Set axis on
+  virtual void SetAxisOn();
+
+  // Set axis position
+  virtual void SetAxisPosition(float x, float y, float z);
+
+  // Set brick box off
+  virtual void SetBrickBoxOff();
+
+  // Set brick box on
+  virtual void SetBrickBoxOn();
+
+  // Set bounding box off
+  virtual void SetBoundingBoxOff();
+
+  // Set bounding box on
+  virtual void SetBoundingBoxOn();
+
+  // Set clipping planes
+  virtual void SetClippingPlanes(float near, float far);
+
+  // Set exit flag
+  virtual void SetCommandExit();
+
+  // Set render flag
+  virtual void SetCommandRender();
+
+  // Set data set filename
+  virtual void SetData(char* filename);
+
+  // Set data set filename and cache sizes
+  virtual void SetData(char* filename, int ramSize, int vramSize);
+
+  // Set display size
+  virtual void SetDisplaySize(int width, int height, bool fullScreen, 
+                              char* hostname, int port,
+                              float left, float right, 
+                              float bottom, float top);
+
+  // Set frustum
+  virtual void SetFrustum(float left, float right,
+                          float bottom, float top);
+
+  // Set 8-bit transfer function
+  virtual void SetMap(unsigned char* map);
+
+  // Set 16-bit transfer function
+  virtual void SetMap16(unsigned char* map);
+
+  // Set data set prefix
+  virtual void SetPrefix(char* prefix);
+
+  // Set rotation matrix
+  virtual void SetRotationMatrix(float matrix[16]);
+
+  // Set scale matrix
+  virtual void SetScaleMatrix(float matrix[16]);
+
+  // Set slice frequency
+  virtual void SetSliceFrequency(double frequency);
+
+  // Set translation matrix
+  virtual void SetTranslationMatrix(float matrix[16]);
+
+  // Set viewport
+  virtual void SetViewport(int x, int y, int w, int h);
+
+protected:
+
+  // Constructor
+  CommunicatorAbstractCommand();
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheVRAM.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CacheVRAM.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheVRAM.cpp	(revision 4)
@@ -0,0 +1,394 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CacheVRAM.h"
+
+/*--------------------------------------------------------------------------*/
+
+CacheVRAM::CacheVRAM(int size) {
+
+  // Message
+  Assert("Constructor begin.");
+
+  // Initialize size
+  _currentSize = 0;
+
+  // Initialize maximum size
+  _maximumSize = size;
+
+  // Initialize front
+  _front = NULL;
+
+  // Message
+  Assert("Constructor end.");
+
+}
+  
+/*--------------------------------------------------------------------------*/
+
+CacheVRAM::~CacheVRAM() {
+
+  // Message
+  Assert("Destructor begin.");
+
+  // Current and next node pointers used to iterate through cache
+  CacheVRAMNode* current = NULL;
+  CacheVRAMNode* next = NULL;
+
+  // Iterate through cache deleting each node
+  while (current != NULL) {
+    next = current -> GetNext();
+    delete current;
+    current = next;
+  }
+
+  // Message
+  Assert("Destructor end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::Assert(const char* message) {
+
+#ifdef LOG
+
+  // Print message and time to log
+  char buffer[1024];
+  sprintf(buffer, "CacheVRAM: %s", message);
+  Log::Assert(buffer);
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool CacheVRAM::IsFull() {
+
+  // Check if cache is full
+  if (_currentSize >= _maximumSize) {
+
+    // Message
+    Assert("Is cache full? True.");
+
+    // Return true
+    return true;
+  }
+
+  // Message
+  Assert("Is cache full? False.");
+
+  // Return false
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+bool CacheVRAM::IsLoaded(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Is node %d loaded? Checking...", node -> GetID());
+  Assert(message);
+
+  // Node pointers used for iteration
+  CacheVRAMNode* tmp = _front;
+ 
+  // Iterate through cache until node is found based on its id
+  while (tmp != NULL) {
+
+    // Check if node is found
+    if (tmp -> GetOctreeNode() -> GetID() == node -> GetID()) {
+
+      // Message
+      sprintf(message, "Is node %d loaded? True.", node -> GetID());
+      Assert(message);
+
+      // Return true
+      return true;
+    }
+
+    // Next node
+    tmp = tmp -> GetNext();
+
+  }
+
+  // Message
+  sprintf(message, "Is node %d loaded? False.", node -> GetID());
+  Assert(message);
+
+  // Return false
+  return false;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::Load(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Load node %d begin.", node -> GetID());
+  Assert(message);
+
+  // Allocate new node
+  CacheVRAMNode* tmp = new CacheVRAMNode;
+  if (tmp == NULL) {
+    fprintf(stderr, "CacheVRAM: Memory allocation error.\n");
+    return;
+  }
+
+  // If cache is full, remove LRU node at end of cache
+  if (IsFull() == true) {
+    RemoveLast();
+  }
+
+  // Load octree node's data
+  node -> LoadTexture();
+
+  // Set cache node's parameters
+  tmp -> SetOctreeNode(node);
+  tmp -> SetNext(_front);
+  tmp -> SetPrevious(NULL);
+
+  // Place in front
+  if (_front != NULL) {
+    _front -> SetPrevious(tmp);
+  }
+
+  // Set front
+  _front = tmp;
+
+  // Increment size
+  _currentSize++;
+
+  // Message
+  sprintf(message, "Load node %d end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::MakeCurrent(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Make node %d current begin.", node -> GetID());
+  Assert(message);
+
+  // If octree node data is loaded, move it to the front
+  if (IsLoaded(node) == true) {
+
+    // Message
+    sprintf(message, 
+            "Make node %d current. Move node to front.", 
+            node -> GetID());
+    Assert(message);
+
+    // Move node to front
+    MoveToFront(node);
+  }
+
+  // Load node, automatically placing it at front
+  else {
+
+    // Message
+    sprintf(message, 
+            "Make node %d current. Load node.", 
+            node -> GetID());
+    Assert(message);
+
+    // Load node
+    Load(node);
+  }
+
+  // Message
+  sprintf(message, "Make node %d current end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::MoveToFront(OctreeNode* node) {
+
+  // Message
+  char message[1024];
+  sprintf(message, "Move node %d to front begin.", node -> GetID());
+  Assert(message);
+
+  // Node pointers used for iteration
+  CacheVRAMNode* tmp = _front;
+
+  // Iterate through cache until node is found based on its id
+  while (tmp != NULL) {
+    if (tmp -> GetOctreeNode() -> GetID() == node -> GetID()) {
+      break;
+    }
+    tmp = tmp -> GetNext();
+  }
+
+  // Node is not found
+  if (tmp == NULL) {
+    return;
+  }
+
+  // Node is already at the front
+  if (tmp -> GetPrevious() == NULL) {
+    return;
+  }
+
+  // Connect the node's previous and next node
+  (tmp -> GetPrevious()) -> SetNext(tmp -> GetNext());
+  if (tmp -> GetNext() != NULL) {
+    (tmp -> GetNext()) -> SetPrevious(tmp -> GetPrevious());
+  }
+
+  // Place at front
+  tmp -> SetPrevious(NULL);
+  if (_front != NULL) {
+    _front -> SetPrevious(tmp);
+  }
+  tmp -> SetNext(_front);
+
+  // Set front
+  _front = tmp;
+
+  // Message
+  sprintf(message, "Move node %d to front end.", node -> GetID());
+  Assert(message);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::Print() {
+
+  // Message
+  Assert("Printing CacheVRAM begin.");
+
+  // Message
+  char message[1024];
+  sprintf(message, "  Current Size: %d", _currentSize);
+  Assert(message);
+  sprintf(message, "  Maximum Size: %d", _maximumSize);
+  Assert(message);
+
+  // Front of queue
+  CacheVRAMNode* current = _front;
+
+  // Traverse queue
+  while (current != NULL) {
+
+    // Print node id
+    sprintf(message, 
+            "  Node ID: %d ", 
+            current -> GetOctreeNode() -> GetID());
+    Assert(message);
+
+    // Print level id
+    sprintf(message, 
+            "    Node Level: %d", 
+            current -> GetOctreeNode() -> GetLevel());
+    Assert(message);
+
+    // Print data loaded flag
+    if (current -> GetOctreeNode() -> IsDataLoaded() == true) {
+      sprintf(message, 
+              "    Data Loaded: true");
+    }
+    else {
+      sprintf(message, 
+              "    Data Loaded: false");
+    }
+    Assert(message);
+
+    // Print texture loaded flag
+    if (current -> GetOctreeNode() -> IsTextureLoaded() == true) {
+      sprintf(message, 
+              "    Texture Loaded: true");
+    }
+    else {
+      sprintf(message, 
+              "    Texture Loaded: false");
+    }
+    Assert(message);
+
+    // Next node
+    current = current -> GetNext();
+
+  }
+
+  // Message
+  Assert("Printing CacheVRAM end.");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAM::RemoveLast() {
+
+  // Message
+  Assert("Removing last node begin.");
+
+  // Current and next node pointers used to iterate through cache
+  CacheVRAMNode* previous = NULL;
+  CacheVRAMNode* current = _front;
+
+  // Empty cache
+  if (current == NULL) {
+    return;
+  }
+
+  // Decrement size
+  _currentSize--;
+
+  // Iterate until the end of the cache is reached
+  while (current != NULL) {
+    previous = current;
+    current = current -> GetNext();
+  }
+
+  // Get the last node
+  current = previous;
+  previous = current -> GetPrevious();
+
+  // Remove last node rom cache
+  if (previous == NULL) {
+    _front = NULL;
+  }
+  else {
+    previous -> SetNext(NULL);
+  }
+
+  // Unload octree nodes' data
+  current -> GetOctreeNode() -> UnloadTexture();
+
+  // Clean up node
+  delete current;
+
+  // Message
+  Assert("Removing last node end.");
+
+}
+  
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Master.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Master.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Master.cpp	(revision 4)
@@ -0,0 +1,1594 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Master.h"
+#include "SynchronizerServerConcreteCommand.h"
+#include "UserInterfaceServerConcreteCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+Master::Master(Communicator* communicator) {
+
+  // Initialize communicator
+  _communicator = communicator;
+
+  // Get number of slaves from communicator
+  _numberOfSlaves = _communicator -> GetNumberOfNodes() - 1;
+
+  // Initialize axis flag
+  _axisFlag = false;
+
+  // Initialize axis position
+  _axisPosition[0] = 0.0;
+  _axisPosition[1] = 0.0;
+  _axisPosition[2] = 0.0;
+
+  // Initialize clipping planes
+  _clippingPlanes = new float*[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _clippingPlanes[i] = new float[2];
+    _clippingPlanes[i][0] = 0.0;
+    _clippingPlanes[i][1] = 0.0;
+  }
+
+  // Initialize data filename
+  memset(_dataFilename, 0, 1024 * sizeof(char));
+
+  // Initialize data prefix
+  memset(_dataPrefix, 0, 1024 * sizeof(char));
+
+  // Initialize dataset list dataset file name
+  _datasetListFile = NULL;
+
+  // Initialize dataset list dataset name
+  _datasetListName = NULL;
+
+  // Initialize dataset list dataset prefix
+  _datasetListPrefix = NULL;
+
+  // Initialize data type to 8-bit
+  _dataType = 8;
+
+  // Initialize display percentages
+  _displayPercentages = new float*[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _displayPercentages[i] = new float[4];
+    _displayPercentages[i][0] = 0.0;
+    _displayPercentages[i][1] = 0.0;
+    _displayPercentages[i][2] = 0.0;
+    _displayPercentages[i][3] = 0.0;
+  }
+
+  // Initialize display size
+  _displaySize = new int*[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _displaySize[i] = new int[2];
+    _displaySize[i][0] = 0;
+    _displaySize[i][1] = 0;
+  }
+
+  // Initialize exit flag
+  _exitFlag = false;
+
+  // Initialize frustum
+  _frustum = new float*[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _frustum[i] = new float[4];
+    _frustum[i][0] = 0.0;
+    _frustum[i][1] = 0.0;
+    _frustum[i][2] = 0.0;
+    _frustum[i][3] = 0.0;
+  }
+
+  // Initialize full screen flag
+  _fullScreenFlag = new bool[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _fullScreenFlag[i] = false;
+  }
+
+  // Initialize map
+  _map = NULL;
+
+  // Initialize number of datasets in dataset list
+  _numberOfDatasets = 0;
+
+  // Initialize number of levels
+  _numberOfLevels = 0;
+
+  // Initialize and register observer with user interface server
+  _observer = new UserInterfaceServerConcreteCommand(this);
+  _userInterfaceServer.SetObserver(_observer);
+  if (_observer == NULL) {
+    fprintf(stderr, 
+            "Master: Error creating UserInterfaceServerConcreteCommand.\n");
+  }
+
+  // Initialize slice frequency
+  _sliceFrequency = 1.0;
+
+  // Initialize rotation matrix
+  _R[0] = 1.0; _R[4] = 0.0; _R[8] = 0.0; _R[12] = 0.0;
+  _R[1] = 0.0; _R[5] = 1.0; _R[9] = 0.0; _R[13] = 0.0;
+  _R[2] = 0.0; _R[6] = 0.0; _R[10] = 1.0; _R[14] = 0.0;
+  _R[3] = 0.0; _R[7] = 0.0; _R[11] = 0.0; _R[15] = 1.0;
+
+  // Initialize scale matrix
+  _S[0] = 1.0; _S[4] = 0.0; _S[8] = 0.0; _S[12] = 0.0;
+  _S[1] = 0.0; _S[5] = 1.0; _S[9] = 0.0; _S[13] = 0.0;
+  _S[2] = 0.0; _S[6] = 0.0; _S[10] = 1.0; _S[14] = 0.0;
+  _S[3] = 0.0; _S[7] = 0.0; _S[11] = 0.0; _S[15] = 1.0;
+
+  // Initialize translation matrix
+  _T[0] = 1.0; _T[4] = 0.0; _T[8] = 0.0; _T[12] = 0.0;
+  _T[1] = 0.0; _T[5] = 1.0; _T[9] = 0.0; _T[13] = 0.0;
+  _T[2] = 0.0; _T[6] = 0.0; _T[10] = 1.0; _T[14] = 0.0;
+  _T[3] = 0.0; _T[7] = 0.0; _T[11] = 0.0; _T[15] = 1.0;
+
+  // Initialize CacheRAM size
+  _ramSize = 0;
+
+  // Initialize CacheVRAM size
+  _vramSize = 0;
+
+  // Initialize total display dimensions
+  _totalDisplayWidth = 0;
+  _totalDisplayHeight = 0;
+
+  // Initialize total display frustum
+  _totalDisplayFrustum[0] = 0.0;
+  _totalDisplayFrustum[1] = 0.0;
+  _totalDisplayFrustum[2] = 0.0;
+  _totalDisplayFrustum[3] = 0.0;
+  _totalDisplayFrustum[4] = 0.0;
+  _totalDisplayFrustum[5] = 0.0;
+
+  // Initialize vertical field of view
+  _vFOV = 0.0;
+
+  // Initialize viewport
+  _viewport = new int*[_numberOfSlaves];
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _viewport[i] = new int[4];
+    _viewport[i][0] = 0;
+    _viewport[i][1] = 0;
+    _viewport[i][2] = 0;
+    _viewport[i][3] = 0;
+  }
+
+#ifdef SAGE
+
+  // Initialize rotate device position
+  _rotatePosition[0] = 0.0;
+  _rotatePosition[1] = 0.0;
+  _rotatePosition[2] = 0.0;
+
+  // Initialize scale device position
+  _scalePosition[0] = 0.0;
+  _scalePosition[1] = 0.0;
+  _scalePosition[2] = 0.0;
+
+  // Initialize scale device position
+  _scalePositionUntransformed[0] = 0.0;
+  _scalePositionUntransformed[1] = 0.0;
+  _scalePositionUntransformed[2] = 0.0;
+
+  // Initialize translate device position
+  _translatePosition[0] = 0.0;
+  _translatePosition[1] = 0.0;
+  _translatePosition[2] = 0.0;
+
+  // Initialize world scale
+  _worldScale[0] = 1.0;
+  _worldScale[1] = 1.0;
+  _worldScale[2] = 1.0;
+
+  // Initialize world translate
+  _worldTranslate[0] = 0.0;
+  _worldTranslate[1] = 0.0;
+  _worldTranslate[2] = 0.0;
+
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Master::~Master() {
+
+  // Finalize frame synchronization
+  _synchronizationServer.Finalize();
+
+  // Clean up observer
+  if (_observer != NULL) {
+    delete _observer;
+  }
+
+  // Clean up clipping planes
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    delete [] _clippingPlanes[i];
+  }
+  delete [] _clippingPlanes;
+
+  // Clean up display percentages
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    delete [] _displayPercentages[i];
+  }
+  delete [] _displayPercentages;
+
+  // Clean up display size
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    delete [] _displaySize[i];
+  }
+  delete [] _displaySize;
+
+  // Clean up frustums
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    delete [] _frustum[i];
+  }
+  delete [] _frustum;
+
+  // Clean up full screen flag
+  delete [] _fullScreenFlag;
+
+  // Clean up viewport
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    delete [] _viewport[i];
+  }
+  delete [] _viewport;
+
+  // Clean up dataset list dataset file
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    delete [] _datasetListFile[i];
+  }
+  delete [] _datasetListFile;
+
+  // Clean up dataset list dataset name
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    delete [] _datasetListName[i];
+  }
+  delete [] _datasetListName;
+
+  // Clean up dataset list dataset prefix
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    delete [] _datasetListPrefix[i];
+  }
+  delete [] _datasetListPrefix;
+
+  // Shutdown user interface server
+  _userInterfaceServer.Shutdown();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetAxis(bool* state) {
+
+  // Set state
+  *state = _axisFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetAxisPosition(float* x, float* y, float* z) {
+
+  // Set state
+  *x = _axisPosition[0];
+  *y = _axisPosition[1];
+  *z = _axisPosition[2];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetBrickBox(bool* state) {
+
+  // Set state
+  *state = _brickBoxFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetBoundingBox(bool* state) {
+
+  // Set state
+  *state = _boundingBoxFlag;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetClippingPlanes(int node, float* near, float* far) {
+
+  // Set state
+  *near = _clippingPlanes[node - 1][0];
+  *far = _clippingPlanes[node - 1][1];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetData(char* filename) {
+
+  // Copy data meta file name
+  strcpy(filename, _dataFilename);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetData(char* filename, int* ramSize, int* vramSize) {
+
+  // Copy data meta file name
+  strcpy(filename, _dataFilename);
+
+  // Copy cache sizes
+  *ramSize = _ramSize;
+  *vramSize = _vramSize;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDatasetListFile(int index, char* file) {
+
+  // Copy dataset list
+  strcpy(file, _datasetListFile[index]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDatasetListName(int index, char* name) {
+
+  // Copy dataset list
+  strcpy(name, _datasetListName[index]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDatasetListPrefix(int index, char* prefix) {
+
+  // Copy dataset list
+  strcpy(prefix, _datasetListPrefix[index]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDatasetListSize(int* size) {
+
+  // Set dataset list size
+  *size = _numberOfDatasets;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDatasetType(int* type) {
+
+  // Set dataset type
+  *type = _dataType;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetDisplaySize(int node, int* width, int* height, 
+                            bool* fullScreen,
+                            float* left, float* right, 
+                            float* bottom, float* top) {
+
+  // Set display size
+  *width = _displaySize[node - 1][0];
+  *height = _displaySize[node - 1][1];
+
+  // Set full screen flag
+  *fullScreen = _fullScreenFlag[node - 1];
+
+  // Set display percentages
+  *left = _displayPercentages[node - 1][0];
+  *right = _displayPercentages[node - 1][1];
+  *bottom = _displayPercentages[node - 1][2];
+  *top = _displayPercentages[node - 1][3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetFrustum(int node, float* left, float* right,
+                        float* bottom, float* top) {
+
+  // Set state
+  *left = _frustum[node - 1][0];
+  *right = _frustum[node - 1][1];
+  *bottom = _frustum[node - 1][2];
+  *top = _frustum[node - 1][3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetMap(unsigned char* map) {
+
+  // Set state
+  memcpy(map, _map, 1024);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetOverviewVertices(float vertices[24]) {
+
+  // Set state
+  vertices[0] = _vertex[0].GetX();
+  vertices[1] = _vertex[0].GetY();
+  vertices[2] = _vertex[0].GetZ();
+  vertices[3] = _vertex[1].GetX();
+  vertices[4] = _vertex[1].GetY();
+  vertices[5] = _vertex[1].GetZ();
+  vertices[6] = _vertex[2].GetX();
+  vertices[7] = _vertex[2].GetY();
+  vertices[8] = _vertex[2].GetZ();
+  vertices[9] = _vertex[3].GetX();
+  vertices[10] = _vertex[3].GetY();
+  vertices[11] = _vertex[3].GetZ();
+  vertices[12] = _vertex[4].GetX();
+  vertices[13] = _vertex[4].GetY();
+  vertices[14] = _vertex[4].GetZ();
+  vertices[15] = _vertex[5].GetX();
+  vertices[16] = _vertex[5].GetY();
+  vertices[17] = _vertex[5].GetZ();
+  vertices[18] = _vertex[6].GetX();
+  vertices[19] = _vertex[6].GetY();
+  vertices[20] = _vertex[6].GetZ();
+  vertices[21] = _vertex[7].GetX();
+  vertices[22] = _vertex[7].GetY();
+  vertices[23] = _vertex[7].GetZ();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetPrefix(char* prefix) {
+
+  // Copy data prefix
+  strcpy(prefix, _dataPrefix);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetRotationMatrix(float m[16]) {
+
+  // Set state
+  m[0] = _R[0]; m[4] = _R[4]; m[8] = _R[8]; m[12] = _R[12];
+  m[1] = _R[1]; m[5] = _R[5]; m[9] = _R[9]; m[13] = _R[13];
+  m[2] = _R[2]; m[6] = _R[6]; m[10] = _R[10]; m[14] = _R[14];
+  m[3] = _R[3]; m[7] = _R[7]; m[11] = _R[11]; m[15] = _R[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetScaleMatrix(float m[16]) {
+
+  // Set state
+  m[0] = _S[0]; m[4] = _S[4]; m[8] = _S[8]; m[12] = _S[12];
+  m[1] = _S[1]; m[5] = _S[5]; m[9] = _S[9]; m[13] = _S[13];
+  m[2] = _S[2]; m[6] = _S[6]; m[10] = _S[10]; m[14] = _S[14];
+  m[3] = _S[3]; m[7] = _S[7]; m[11] = _S[11]; m[15] = _S[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetSliceFrequency(double* frequency) {
+
+  // Set state
+  *frequency = _sliceFrequency;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetTotalDisplayDimensions(int* w, int* h) {
+
+  // Set state
+  *w = _totalDisplayWidth;
+  *h = _totalDisplayHeight;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetTotalDisplayFrustum(float frustum[6]) {
+
+  // Set state
+  frustum[0] = _totalDisplayFrustum[0];
+  frustum[1] = _totalDisplayFrustum[1];
+  frustum[2] = _totalDisplayFrustum[2];
+  frustum[3] = _totalDisplayFrustum[3];
+  frustum[4] = _totalDisplayFrustum[4];
+  frustum[5] = _totalDisplayFrustum[5];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetTranslationMatrix(float m[16]) {
+
+  // Set state
+  m[0] = _T[0]; m[4] = _T[4]; m[8] = _T[8]; m[12] = _T[12];
+  m[1] = _T[1]; m[5] = _T[5]; m[9] = _T[9]; m[13] = _T[13];
+  m[2] = _T[2]; m[6] = _T[6]; m[10] = _T[10]; m[14] = _T[14];
+  m[3] = _T[3]; m[7] = _T[7]; m[11] = _T[11]; m[15] = _T[15];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetVerticalFieldOfView(float* vFOV) {
+
+  // Set state
+  *vFOV = _vFOV;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::GetViewport(int node, int* x, int* y, int* w, int* h) {
+
+  // Set state
+  *x = _viewport[node - 1][0];
+  *y = _viewport[node - 1][1];
+  *w = _viewport[node - 1][2];
+  *h = _viewport[node - 1][3];
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::Init(char* filename) {
+
+  // Local clipping planes
+  float clipNear = 0.0;
+  float clipFar = 0.0;
+
+  // Local synchronization server port
+  int synchronizationPort = 0;
+
+  // Local user interface server port
+  int userInterfacePort = 0;
+
+
+#ifdef SAGE
+
+  // Connect to SAGE
+
+  // SAGE configuration
+  _sageConfig.init("VRA.conf");
+  _sageConfig.setAppName("VRA");
+  _sageConfig.rank = 0;
+  _sageConfig.nodeNum = (_communicator -> GetNumberOfNodes()) -1;
+  _sageConfig.master = true;
+  _sageConfig.rendering = false;
+
+  // Initialize SAGE
+  _sageInf.init(_sageConfig);
+
+#endif
+
+
+  // Read configuration file from disk
+
+  // File pointer
+  FILE* fptr = NULL;
+
+  // Attempt to open file
+  if ((fptr = fopen(filename, "r")) == NULL) {
+    fprintf(stderr, 
+            "Master: Can not read display configuration file %s\n.", 
+            filename);
+    return;
+  }
+
+  // Read user interface port
+  fscanf(fptr, "%d", &userInterfacePort);
+
+  // Read synchronization port
+  fscanf(fptr, "%d", &synchronizationPort);
+
+  // Read near and far clipping planes
+  fscanf(fptr, "%f %f", &clipNear, &clipFar);
+
+  // Assign all clipping planes
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    _clippingPlanes[i][0] = clipNear;
+    _clippingPlanes[i][1] = clipFar;
+  }
+
+  // Read total display size
+  fscanf(fptr, "%d %d", &_totalDisplayWidth, &_totalDisplayHeight);
+
+  // Read vertical field of view
+  fscanf(fptr, "%f", &_vFOV);
+
+  // Read and assign viewport and normalize coordinates for each node
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+
+    // Read viewport and normalized coordinates
+    fscanf(fptr, "%d %d %d %d %f %f %f %f",
+           &_viewport[i][0], &_viewport[i][1],
+           &_viewport[i][2], &_viewport[i][3],
+           &_displayPercentages[i][0], &_displayPercentages[i][1],
+           &_displayPercentages[i][2], &_displayPercentages[i][3]);
+
+    // Assign display size based on viewport
+    _displaySize[i][0] = _viewport[i][2];
+    _displaySize[i][1] = _viewport[i][3];
+
+    // Read and interpret full screen flag
+    int flag = 0;
+    fscanf(fptr, "%d", &flag);
+    if (flag == 0) {
+      _fullScreenFlag[i] = false;
+    }
+    else {
+      _fullScreenFlag[i] = true;
+    }
+
+  }
+
+  // Read number of datasets in dataset list
+  fscanf(fptr, "%d", &_numberOfDatasets);
+
+  // Allocate memory for dataset list dataset file name
+  _datasetListFile = new char*[_numberOfDatasets];
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    _datasetListFile[i] = new char[1024];
+  }
+
+  // Allocate memory for dataset list dataset name
+  _datasetListName = new char*[_numberOfDatasets];
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    _datasetListName[i] = new char[1024];
+  }
+
+  // Allocate memory for dataset list dataset prefix
+  _datasetListPrefix = new char*[_numberOfDatasets];
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    _datasetListPrefix[i] = new char[1024];
+  }
+
+  // Read dataset list
+  for (int i = 0 ; i < _numberOfDatasets ; i++) {
+    fscanf(fptr, 
+           "%s %s %s", 
+           _datasetListName[i], 
+           _datasetListPrefix[i], 
+           _datasetListFile[i]);
+  }
+
+  // Close file
+  fclose(fptr);
+
+
+  // Calculate frustums
+
+  // Setup frustum calculator
+  FrustumCalculator frustumCalculator;
+  frustumCalculator.SetDisplayWidth(_totalDisplayWidth);
+  frustumCalculator.SetDisplayHeight(_totalDisplayHeight);
+  frustumCalculator.SetNearClippingPlane(clipNear);
+  frustumCalculator.SetVerticalFieldOfView(_vFOV);
+
+  // Calculate frustum for each node
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    frustumCalculator.SetPercentage(_displayPercentages[i]);
+    frustumCalculator.CalculateFrustum();
+    frustumCalculator.GetFrustum(_frustum[i]);
+  }
+
+  // Calculate full frustum for entire display
+  frustumCalculator.GetFullFrustum(&_totalDisplayFrustum[0],
+                                   &_totalDisplayFrustum[1],
+                                   &_totalDisplayFrustum[2],
+                                   &_totalDisplayFrustum[3]);
+  _totalDisplayFrustum[4] = clipNear; 
+  _totalDisplayFrustum[5] = clipFar;
+
+
+  // Initialize and register observer with synchronizer server
+  _progressObserver = new SynchronizerServerConcreteCommand(this);
+  _synchronizationServer.SetProgressObserver(_progressObserver);
+  if (_progressObserver == NULL) {
+    fprintf(stderr, 
+            "Master: Error creating SynchronizerServerConcreteCommand.\n");
+  }
+
+  // Initialize synchronization server
+  _synchronizationServer.Init(synchronizationPort);
+
+
+  // Initialize slaves
+
+  // Get name of master node
+  char hostname[128];
+  _communicator -> GetMasterNodeName(hostname);
+
+  // Send display size to slaves
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    UpdateDisplaySize(i+1, _displaySize[i][0], _displaySize[i][1],
+                      _fullScreenFlag[i], hostname, synchronizationPort,
+                      _displayPercentages[i][0], _displayPercentages[i][1],
+                      _displayPercentages[i][2], _displayPercentages[i][3]);
+    _communicator -> Barrier();
+  }
+
+  // Send clipping planes to slaves
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    UpdateClippingPlanes(i+1, _clippingPlanes[i][0], _clippingPlanes[i][1]);  
+    _communicator -> Barrier();
+  }
+
+  // Send frustums to slaves
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    UpdateFrustum(i+1, _frustum[i][0], _frustum[i][1],
+                  _frustum[i][2], _frustum[i][3]);
+    _communicator -> Barrier();
+  }
+
+  // Send viewports to slaves
+  for (int i = 0 ; i < _numberOfSlaves ; i++) {
+    UpdateViewport(i+1, _viewport[i][0], _viewport[i][1],
+                   _viewport[i][2], _viewport[i][3]);
+    _communicator -> Barrier();
+  }
+
+  // Turn axis on
+  UpdateAxisOn();
+  _communicator -> Barrier();
+
+  // Set axis position
+  UpdateAxisPosition(_totalDisplayFrustum[0] + 0.5,
+                     _totalDisplayFrustum[2] + 0.5,
+                     0.0);
+  _communicator -> Barrier();
+
+  // Turn on bounding box
+  UpdateBoundingBoxOn();
+  _communicator -> Barrier();
+
+  // Turn off brick box
+  UpdateBrickBoxOff();
+  _communicator -> Barrier();
+
+  // Initialize user interface server
+  _userInterfaceServer.Init(userInterfacePort);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::ResetView() {
+
+#ifdef SAGE
+
+  // Reset trackball
+  _eventTrackball.Clear();
+  
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::Run() {
+
+  // Event loop
+  while(_exitFlag == false) {
+
+    // Wait for a new connection from 
+    _userInterfaceServer.Accept();
+
+    // Client error
+    int error = USER_INTERFACE_SERVER_OK;
+
+    // Loop getting commands from user as long as a client is connected
+    while (error != USER_INTERFACE_SERVER_ERROR) {
+
+      // Get command from client
+      error = _userInterfaceServer.GetCommand();
+
+      // If client received a command call barrier
+      if (error == USER_INTERFACE_SERVER_OK) {
+        _communicator -> Barrier();
+      }
+
+#ifdef SAGE
+
+      // SAGE message
+      sageMessage msg;
+
+      // Check for SAGE message
+      if (_sageInf.checkMsg(msg, false) > 0) {
+
+        // Get SAGE message data
+        char* data = (char*) msg.getData();
+
+        // Determine message
+        switch(msg.getCode()) {
+          
+        // Quit
+        case APP_QUIT:
+          
+          // Send exit command to UI
+          _userInterfaceServer.SendCommandExit();
+
+          // Send exit command
+          UpdateCommandExit();         
+
+          // Stop this loop
+          error = USER_INTERFACE_SERVER_ERROR;
+          
+          break;
+        
+
+        // Click event
+        case EVT_CLICK: {
+
+          // Click event x and y location normalized to size of window
+          float clickX, clickY;
+
+          // Ckick device Id, button Id, and is down flag
+          int clickDeviceId, clickButtonId, clickIsDown, clickEvent;
+
+          // Parse message
+          sscanf(data, 
+                 "%d %f %f %d %d %d", 
+                 &clickDeviceId, &clickX, &clickY, 
+                 &clickButtonId, &clickIsDown, &clickEvent);
+
+          // If down event for EVT_PAN
+          if (clickIsDown && clickEvent == EVT_PAN) {
+
+            // Set initial position of click event
+            _translatePosition[0] = clickX;
+            _translatePosition[1] = clickY;
+
+          }
+
+          // If down event for EVT_ZOOM
+          if (clickIsDown && clickEvent == EVT_ZOOM) {
+
+            // Set initial position of click event
+            _scalePosition[0] = clickX;
+            _scalePosition[1] = clickY;
+
+            // Calculate the location of the device in world space
+            float initX = 
+              (_scalePosition[0] * 
+               (_totalDisplayFrustum[1] - _totalDisplayFrustum[0])) +
+              _totalDisplayFrustum[0];
+            float initY =
+              (_scalePosition[1] * 
+               (_totalDisplayFrustum[3] - _totalDisplayFrustum[2])) +
+              _totalDisplayFrustum[2];
+
+            // Calculate the location of the device with respect to the
+            // untransfomred object in world space
+            initX -= _worldTranslate[0];
+            initY -= _worldTranslate[1];
+            initX /= _worldScale[0];
+            initY /= _worldScale[1];
+
+            // Keep these values
+            _scalePositionUntransformed[0] = initX;
+            _scalePositionUntransformed[1] = initY;
+            
+          }
+
+          // If down event for EVT_ROTATE
+          if (clickIsDown && clickEvent == EVT_ROTATE) {
+
+            // Set inital position
+            _rotatePosition[0] = clickX;
+            _rotatePosition[1] = clickY;
+
+            // Normalize object's translation to (-1.0, 1.0)
+            float nTx = (_worldTranslate[0] - _totalDisplayFrustum[0]) /
+              (_totalDisplayFrustum[1] - _totalDisplayFrustum[0]);
+            nTx = (nTx * 2.0) - 1.0;
+            float nTy = (_worldTranslate[1] - _totalDisplayFrustum[2]) /
+              (_totalDisplayFrustum[3] - _totalDisplayFrustum[2]);
+            nTy = (nTy * 2.0) - 1.0;
+        
+            // Normalize puck's position to (-1.0, 1.0)
+            float nXpos = (clickX * 2.0) - 1.0;
+            float nYpos = (clickY * 2.0) - 1.0;
+        
+            // Start trackball
+            _eventTrackball.Start(nXpos - nTx, nYpos - nTy);
+
+          }
+
+          // If up event
+          if (clickIsDown == 0) {
+
+            // Force the renderer to update
+            UpdateCommandRender();
+            _communicator -> Barrier();
+            UpdateCommandRender();
+            _communicator -> Barrier();
+            UpdateCommandRender();
+            _communicator -> Barrier();
+            UpdateCommandRender();
+            _communicator -> Barrier();
+            UpdateCommandRender();
+            _communicator -> Barrier();
+
+          }
+
+          // Done with EVT_CLICK case
+          break;
+
+        }
+        
+
+        // Pan event
+        case EVT_PAN: {
+
+          // Pan event properties
+          int panDeviceId;
+          
+          // Pan event x and y location and change in x, y and z direction
+          // normalized to size of window
+          float panX, panY, panDX, panDY, panDZ;
+          sscanf(data, 
+                 "%d %f %f %f %f %f", 
+                 &panDeviceId, &panX, &panY, &panDX, &panDY, &panDZ);
+
+          // Print event
+          //fprintf(stderr,
+          //        "PAN MESSAGE: %f %f %f %f %f\n",
+          //        panX, panY, panDX, panDY, panDZ);
+
+          // Calculate amount the device has moved in world space since it 
+          // was clicked.
+          float deltaT[2] = {((_translatePosition[0]-
+                               (_translatePosition[0] + panDX)) * 
+                              (_totalDisplayFrustum[1] - 
+                               _totalDisplayFrustum[0])), 
+                             ((_translatePosition[1]-
+                               (_translatePosition[1] + panDY)) *
+                              (_totalDisplayFrustum[3] - 
+                               _totalDisplayFrustum[2]))};
+          
+          // Add the offset
+          _worldTranslate[0] -= deltaT[0];
+          _worldTranslate[1] -= deltaT[1];
+          
+          // Determine translation matrix
+          float T[16];
+          calc_trans(T, 
+                     _worldTranslate[0], 
+                     _worldTranslate[1], 
+                     0.0);
+          
+          // Send translation matrix to UI
+          _userInterfaceServer.SendTranslationMatrix(T);
+
+          // Set the translation matrix
+          UpdateTranslationMatrix(T);
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+
+          // Update translate device position
+          _translatePosition[0] += panDX;
+          _translatePosition[1] += panDY;
+          
+          // Done with EVT_PAN case
+          break;
+
+        }
+
+        // Zoom event
+        case EVT_ZOOM: {
+
+          // Zoom event properties
+          int zoomDeviceId;
+          
+          // Zoom event x and y location and change in x, y and z direction
+          // normalized to size of window
+          float zoomX, zoomY, zoomDX, zoomDY, zoomDZ;
+          sscanf(data, 
+                 "%d %f %f %f %f %f", 
+                 &zoomDeviceId, &zoomX, &zoomY, &zoomDX, &zoomDY, &zoomDZ);
+
+          // Print event
+          //fprintf(stderr,
+          //        "ZOOM MESSAGE: %f %f %f %f %f\n",
+          //        zoomX, zoomY, zoomDX, zoomDY, zoomDZ);
+
+          // Calcualte amount the device has moved
+          float deltaZ[2] = {-zoomDX, -zoomDY};
+
+          // Update world scale by delta
+          _worldScale[0] *= 1.0 - (deltaZ[0] + deltaZ[1]);
+          _worldScale[1] *= 1.0 - (deltaZ[0] + deltaZ[1]);
+          _worldScale[2] *= 1.0 - (deltaZ[0] + deltaZ[1]);
+
+          // Don't let world scale go below 1.0
+          if (_worldScale[0] < 1.0) _worldScale[0] = 1.0;
+          if (_worldScale[1] < 1.0) _worldScale[1] = 1.0;
+          if (_worldScale[2] < 1.0) _worldScale[2] = 1.0;
+
+          // Determine scale matrix
+          float S[16];
+          calc_scale(S, 
+                     _worldScale[0], 
+                     _worldScale[1], 
+                     _worldScale[2]);
+
+          // Calculate the initial location of the device in world space
+          float initX = 
+            (zoomX * 
+             (_totalDisplayFrustum[1] - _totalDisplayFrustum[0])) +
+            _totalDisplayFrustum[0];
+          float initY =
+            (zoomY * 
+             (_totalDisplayFrustum[3] - _totalDisplayFrustum[2])) +
+            _totalDisplayFrustum[2];
+
+          // Determine new translation based on scale
+          _worldTranslate[0] = 
+            initX - (_scalePositionUntransformed[0] * _worldScale[0]);
+          _worldTranslate[1] = 
+            initY - (_scalePositionUntransformed[1] * _worldScale[1]);
+
+          // Determine new translation matrix
+          float T[16];
+          calc_trans(T, 
+                     _worldTranslate[0], 
+                     _worldTranslate[1], 
+                     0.0);
+
+          // Send scale matrix to UI
+          _userInterfaceServer.SendScaleMatrix(S);
+
+          // Send translation matrix to UI
+          _userInterfaceServer.SendTranslationMatrix(T);
+
+          // Set the scale and translation matrices
+          UpdateScaleMatrix(S);
+          _communicator -> Barrier();
+          UpdateTranslationMatrix(T);
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+
+          // Done with EVT_ZOOM case
+          break;
+             
+        }
+
+        // Rotate event
+        case EVT_ROTATE: {
+
+          // Rotate event properties
+          int rotateDeviceId;
+          
+          // Rotate event x and y location and change in x, y and z direction
+          // normalized to size of window
+          float rotateX, rotateY, rotateDX, rotateDY, rotateDZ;
+          sscanf(data, 
+                 "%d %f %f %f %f %f", 
+                 &rotateDeviceId, &rotateX, &rotateY, 
+                 &rotateDX, &rotateDY, &rotateDZ);
+
+          //fprintf(stderr, "EVT_ROTATE: %f %f %f %f %f\n",
+          //        rotateX, rotateY, rotateDX, rotateDY, rotateDZ);
+
+          // Normalize object's translation to (-1.0, 1.0)
+          float nTx = (_worldTranslate[0] - _totalDisplayFrustum[0]) /
+            (_totalDisplayFrustum[1] - _totalDisplayFrustum[0]);
+          nTx = (nTx * 2.0) - 1.0;
+          float nTy = (_worldTranslate[1] - _totalDisplayFrustum[2]) /
+            (_totalDisplayFrustum[3] - _totalDisplayFrustum[2]);
+          nTy = (nTy * 2.0) - 1.0;
+
+          // Normalize puck's position to (-1.0, 1.0)
+          float nXpos = (_rotatePosition[0] * 2.0) - 1.0;
+          float nYpos = (_rotatePosition[1] * 2.0) - 1.0;
+
+          // Update trackball
+          _eventTrackball.Update(nXpos - nTx, nYpos - nTy);
+      
+          // Get rotation from trackball
+          float R[16];
+          _eventTrackball.GetRotationMatrix(R);
+
+          // Send rotation matrix to UI
+          _userInterfaceServer.SendRotationMatrix(R);
+
+          // Set the rotation matrix
+          UpdateRotationMatrix(R);
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+          UpdateCommandRender();
+          _communicator -> Barrier();
+
+          _rotatePosition[0] += rotateDX;
+          _rotatePosition[1] += rotateDY;
+
+          // Done with EVT_ZOOM case
+          break;
+
+        }
+
+        }
+        
+      }
+
+#endif
+
+    }
+
+  }
+
+  // One last barrier
+  _communicator -> Barrier();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateAxisOff() {
+
+  // Set state
+  _axisFlag = false;
+
+  // Send command
+  _communicator -> SendAxisOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateAxisOn() {
+
+  // Set state
+  _axisFlag = true;
+
+  // Send command
+  _communicator -> SendAxisOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateAxisPosition(float x, float y, float z) {
+
+  // Set state
+  _axisPosition[0] = x;
+  _axisPosition[1] = y;
+  _axisPosition[2] = z;
+
+  // Send command
+  _communicator -> SendAxisPosition(_axisPosition[0], 
+                                    _axisPosition[1], 
+                                    _axisPosition[2]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateBrickBoxOff() {
+
+  // Set state
+  _brickBoxFlag = false;
+
+  // Send command
+  _communicator -> SendBrickBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateBrickBoxOn() {
+
+  // Set state
+  _brickBoxFlag = true;
+
+  // Send command
+  _communicator -> SendBrickBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateBoundingBoxOff() {
+
+  // Set state
+  _boundingBoxFlag = false;
+
+  // Send command
+  _communicator -> SendBoundingBoxOff();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateBoundingBoxOn() {
+
+  // Set state
+  _boundingBoxFlag = true;
+
+  // Send command
+  _communicator -> SendBoundingBoxOn();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateClippingPlanes(int node, float near, float far) {
+
+  // Set state
+  _clippingPlanes[node - 1][0] = near;
+  _clippingPlanes[node - 1][1] = far;
+
+  // Send command
+  _communicator -> SendClippingPlanes(node,
+                                      _clippingPlanes[node - 1][0],
+                                      _clippingPlanes[node - 1][1]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateCommandExit() {
+
+#ifdef SAGE
+
+  // Shutdown SAGE
+  _sageInf.shutdown();
+
+#endif
+
+  // Set state
+  _exitFlag = 1;
+
+  // Send command
+  _communicator -> SendCommandExit();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateCommandRender() {
+
+  // Send command
+  _communicator -> SendCommandRender();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateData(char* filename) {
+
+  // Check if not NULL
+  if (filename != NULL) {
+
+    // Set state
+    strcpy(_dataFilename, filename);
+    _ramSize = 0;
+    _vramSize = 0;
+
+    // Send command
+    _communicator -> SendData(_dataFilename);
+
+    // Load metadata
+    Octree* data = new Octree();
+    data -> SetPrefix(_dataPrefix);
+    data -> LoadFromFile2(_dataFilename);
+    _numberOfLevels = data -> GetNumberOfLevels();
+    if (data -> GetDataType() == OCTREE_NODE_UNSIGNED_8_INT) {
+      _dataType = 8;
+    }
+    else if (data -> GetDataType() == OCTREE_NODE_UNSIGNED_16_INT) {
+      _dataType = 16;
+    }
+
+    // Get vertices from root node
+    OctreeNode* node = data -> GetRoot();
+    for (int i = 0 ; i < 8 ; i++) {
+      node -> GetVertex(i, &_vertex[i]);
+    }
+
+    // Clean up
+    delete data;
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateData(char* filename, int ramSize, int vramSize) {
+
+  // Check if not NULL
+  if (filename != NULL) {
+
+    // Set state
+    strcpy(_dataFilename, filename);
+    _ramSize = ramSize;
+    _vramSize = vramSize;
+
+    // Send command
+    _communicator -> SendData(_dataFilename, _ramSize, _vramSize);
+
+    // Load metadata
+    Octree* data = new Octree();
+    data -> SetPrefix(_dataPrefix);
+    data -> LoadFromFile2(_dataFilename);
+    _numberOfLevels = data -> GetNumberOfLevels();
+    if (data -> GetDataType() == OCTREE_NODE_UNSIGNED_8_INT) {
+      _dataType = 8;
+    }
+    else if (data -> GetDataType() == OCTREE_NODE_UNSIGNED_16_INT) {
+      _dataType = 16;
+    }
+
+    // Get vertices from root node
+    OctreeNode* node = data -> GetRoot();
+    for (int i = 0 ; i < 8 ; i++) {
+      node -> GetVertex(i, &_vertex[i]);
+    }
+
+    // Clean up
+    delete data;
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateDisplaySize(int node, int width, int height, 
+                               bool fullScreen, char* hostname, int port,
+                               float left, float right, 
+                               float bottom, float top) {
+
+  // Set state
+  _displaySize[node - 1][0] = width;
+  _displaySize[node - 1][1] = height;
+  _fullScreenFlag[node - 1] = fullScreen;
+  _displayPercentages[node - 1][0] = left;
+  _displayPercentages[node - 1][1] = right;
+  _displayPercentages[node - 1][2] = bottom;
+  _displayPercentages[node - 1][3] = top;
+
+  // Send command
+  _communicator -> SendDisplaySize(node,
+                                   _displaySize[node - 1][0],
+                                   _displaySize[node - 1][1],
+                                   _fullScreenFlag[node - 1],
+                                   hostname,
+                                   port,
+                                   _displayPercentages[node - 1][0],
+                                   _displayPercentages[node - 1][1],
+                                   _displayPercentages[node - 1][2],
+                                   _displayPercentages[node - 1][3]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateFrustum(int node, float left, float right, 
+                           float bottom, float top) {
+
+  // Set state
+  _frustum[node - 1][0] = left;
+  _frustum[node - 1][1] = right;
+  _frustum[node - 1][2] = bottom;
+  _frustum[node - 1][3] = top;
+
+  // Send command
+  _communicator -> SendFrustum(node,
+                               _frustum[node - 1][0],
+                               _frustum[node - 1][1],
+                               _frustum[node - 1][2],
+                               _frustum[node - 1][3]);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateMap(unsigned char* map) {
+
+  // Set state
+  _map = map;
+
+  // Send command
+  _communicator -> SendMap(_map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateMap16(unsigned char* map) {
+
+  // Set state
+  _map = map;
+
+  // Send command
+  _communicator -> SendMap16(_map);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdatePrefix(char* prefix) {
+
+  // Check if not NULL
+  if (prefix != NULL) {
+
+    // Set state
+    strcpy(_dataPrefix, prefix);
+
+    // Send command
+    _communicator -> SendPrefix(_dataPrefix);
+
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateProgress(int value) {
+
+  // Send progress to UI server
+  if (_userInterfaceServer.IsInit() == true) {
+    _userInterfaceServer.SendProgress(value, _numberOfLevels);
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateRotationMatrix(float m[16]) {
+
+  // Set state
+  _R[0] = m[0]; _R[4] = m[4]; _R[8] = m[8]; _R[12] = m[12];
+  _R[1] = m[1]; _R[5] = m[5]; _R[9] = m[9]; _R[13] = m[13];
+  _R[2] = m[2]; _R[6] = m[6]; _R[10] = m[10]; _R[14] = m[14];
+  _R[3] = m[3]; _R[7] = m[7]; _R[11] = m[11]; _R[15] = m[15];
+
+  // Send command
+  _communicator -> SendRotationMatrix(_R);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateScaleMatrix(float m[16]) {
+
+#ifdef SAGE
+
+  // Update world scale for SAGE events
+  _worldScale[0] = m[0];
+  _worldScale[1] = m[5];
+  _worldScale[2] = m[10];
+
+#endif
+
+  // Set statea
+  _S[0] = m[0]; _S[4] = m[4]; _S[8] = m[8]; _S[12] = m[12];
+  _S[1] = m[1]; _S[5] = m[5]; _S[9] = m[9]; _S[13] = m[13];
+  _S[2] = m[2]; _S[6] = m[6]; _S[10] = m[10]; _S[14] = m[14];
+  _S[3] = m[3]; _S[7] = m[7]; _S[11] = m[11]; _S[15] = m[15];
+
+  // Send command
+  _communicator -> SendScaleMatrix(_S);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateSliceFrequency(double frequency) {
+
+  // Set statea
+  _sliceFrequency = frequency;
+
+  // Send command
+  _communicator -> SendSliceFrequency(_sliceFrequency);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateTranslationMatrix(float m[16]) {
+  
+#ifdef SAGE
+
+  // Update world translate for SAGE events
+  _worldTranslate[0] = m[12];
+  _worldTranslate[1] = m[13];
+  _worldTranslate[2] = m[14];
+
+#endif
+
+  // Set state
+  _T[0] = m[0]; _T[4] = m[4]; _T[8] = m[8]; _T[12] = m[12];
+  _T[1] = m[1]; _T[5] = m[5]; _T[9] = m[9]; _T[13] = m[13];
+  _T[2] = m[2]; _T[6] = m[6]; _T[10] = m[10]; _T[14] = m[14];
+  _T[3] = m[3]; _T[7] = m[7]; _T[11] = m[11]; _T[15] = m[15];
+
+  // Send command
+  _communicator -> SendTranslationMatrix(_T);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Master::UpdateViewport(int node, int x, int y, int w, int h) {
+
+  // Set state
+  _viewport[node-1][0] = x;
+  _viewport[node-1][1] = y;
+  _viewport[node-1][2] = w;
+  _viewport[node-1][3] = h;
+
+  // Send command
+  _communicator -> SendViewport(node,
+                                _viewport[node-1][0],
+                                _viewport[node-1][1],
+                                _viewport[node-1][2],
+                                _viewport[node-1][3]);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/OctreeNode.h
===================================================================
--- trunk/src/testing/app/VRA/src/OctreeNode.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/OctreeNode.h	(revision 4)
@@ -0,0 +1,227 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef OCTREE_NODE_H
+#define OCTREE_NODE_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <GL/gl.h>
+#include <string.h>
+
+#include "Log.h"
+#include "Vertex.h"
+
+/*--------------------------------------------------------------------------*/
+
+// Data type definitions
+#define OCTREE_NODE_UNSIGNED_8_INT 0
+#define OCTREE_NODE_UNSIGNED_16_INT 1
+
+// Data format definitions
+#define OCTREE_NODE_BIG_ENDIAN 0
+#define OCTREE_NODE_LITTLE_ENDIAN 1
+
+/*--------------------------------------------------------------------------*/
+
+extern "C" {
+  extern void glTexImage3D(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei,
+                           GLint, GLenum, GLenum, const GLvoid*);
+}
+
+/*--------------------------------------------------------------------------*/
+
+class OctreeNode {
+
+ public:
+
+  // Default constructor
+  OctreeNode();
+
+  // Default destructor
+  ~OctreeNode();
+
+  // Get child node
+  OctreeNode* GetChild(int index);
+
+  // Get depth
+  int GetD();
+
+  // Get data
+  unsigned char* GetData();
+
+  // Get data format
+  int GetDataFormat();
+
+  // Get data type
+  int GetDataType();
+
+  // Get height
+  int GetH();
+
+  // Get id
+  int GetID();
+
+  // Get level id
+  int GetLevel();
+
+  // Get texture
+  GLuint GetTexture();
+
+  // Get vertex
+  void GetVertex(int index, Vertex* v);
+
+  // Get vertex
+  void GetVertex(int index, float* x, float* y, float *z);
+
+  // Get width
+  int GetW();
+
+  // Get width, height, depth
+  void GetWHD(int whd[3]);
+
+  // Get width, height, depth
+  void GetWHD(int* w, int* h, int* d);
+
+  // Is data loaded in RAM
+  bool IsDataLoaded();
+
+  // Is texture loaded in VRAM
+  bool IsTextureLoaded();
+
+  // Load recursively from file
+  void LoadFromFile(const char* filename);
+
+  // Load data to RAM
+  void LoadData();
+
+  // Load texture to VRAM
+  void LoadTexture();
+  
+  // Print
+  void Print();
+
+  // Set child node
+  void SetChild(int index, OctreeNode* child);
+
+  // Set depth
+  void SetD(int d);
+
+  // Set data
+  void SetData(unsigned char* data);
+
+  // Set data format
+  void SetDataFormat(int format);
+
+  // Set data type
+  void SetDataType(int type);
+
+  // Set filename
+  void SetFilename(const char* filename);
+
+  // Set height
+  void SetH(int h);
+
+  // Set id
+  void SetID(int id);
+
+  // Set level id
+  void SetLevel(int level);
+
+  // Set prefix
+  void SetPrefix(const char* prefix);
+
+  // Set vertex
+  void SetVertex(int index, Vertex v);
+
+  // Set vertex
+  void SetVertex(int index, float x, float y, float z);
+
+  // Set width
+  void SetW(int w);
+
+  // Set width, height, depth
+  void SetWHD(int whd[3]);
+
+  // Set width, height, depth
+  void SetWHD(int w, int h, int d);
+
+  // Unload data from RAM
+  void UnloadData();
+
+  // Unload texture from VRAM
+  void UnloadTexture();
+
+ private:
+
+  // Print a message to stdout
+  void Assert(const char* message);
+
+  // Load unsigned 8 int texture to VRAM
+  void LoadTexture8();
+
+  // Load unsigned 16 int texture to VRAM
+  void LoadTexture16();
+
+  // Children
+  OctreeNode* _child[8];
+
+  // Data
+  unsigned char* _data;
+
+  // Data loaded flag
+  bool _dataLoadedFlag;
+
+  // Data type
+  int _dataType;
+
+  // Data format
+  int _dataFormat;
+
+  // Filename
+  char _filename[128];
+
+  // ID
+  int _id;
+
+  // Level ID
+  int _level;
+
+  // Prefix
+  char _prefix[1024];
+
+  // Texture
+  GLuint _texture;
+
+  // Texture loaded flag
+  bool _textureLoadedFlag;
+
+  // Vertices
+  Vertex _vertex[8];
+
+  // Width, height, depth
+  int _whd[3];
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/ControlPoint.h
===================================================================
--- trunk/src/testing/app/VRA/src/ControlPoint.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/ControlPoint.h	(revision 4)
@@ -0,0 +1,82 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_CONTROL_POINT_H
+#define FL_CONTROL_POINT_H
+
+/*--------------------------------------------------------------------------*/
+
+class ControlPoint {
+
+public:
+
+  // Default constructor
+  ControlPoint();
+
+  // Overloaded constructor
+  ControlPoint(const ControlPoint &copyin);
+
+  // Default destructor
+  ~ControlPoint();
+
+  // Overloaded operator=
+  ControlPoint& operator=(const ControlPoint &rhs);
+
+  // Overloaded operator==
+  int operator==(const ControlPoint &rhs) const;
+
+  // Overloaded operator<
+  int operator<(const ControlPoint &rhs) const;
+
+  // Get opacity
+  float GetOpacity();
+
+  // Get color
+  void GetRGB(float* r, float* g, float* b);
+
+  // Get scalar
+  float GetScalar();
+
+  // Set opacity
+  void SetOpacity(float opacity);
+
+  // Set color
+  void SetRGB(float r, float g, float b);
+
+  // Set scalar
+  void SetScalar(float scalar);
+  
+private:
+
+  // Opacity value
+  float _opacity;
+
+  // Color value
+  float _rgb[3];
+
+  // Scalar value
+  float _scalar;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheVRAMNode.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/CacheVRAMNode.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheVRAMNode.cpp	(revision 4)
@@ -0,0 +1,92 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "CacheVRAMNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+CacheVRAMNode::CacheVRAMNode() {
+
+  // Initialize cache node values to NULL
+  _previous = NULL;
+  _next = NULL;
+  _node = NULL;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheVRAMNode::~CacheVRAMNode() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheVRAMNode* CacheVRAMNode::GetNext() {
+
+  // Return next cache node
+  return _next;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+OctreeNode* CacheVRAMNode::GetOctreeNode() {
+
+  // Return octree node
+  return _node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+CacheVRAMNode* CacheVRAMNode::GetPrevious() {
+
+  // Return previous cache node
+  return _previous;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAMNode::SetNext(CacheVRAMNode* node) {
+
+  // Set next cache node
+  _next = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAMNode::SetOctreeNode(OctreeNode* node) {
+
+  // Set octree node
+  _node = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void CacheVRAMNode::SetPrevious(CacheVRAMNode* node) {
+
+  // Set previous cache node
+  _previous = node;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Main_Window.h
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Main_Window.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Main_Window.h	(revision 4)
@@ -0,0 +1,79 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef FL_MENU_H
+#define FL_MENU_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Return_Button.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Fl_Main_Window : public Fl_Double_Window {
+
+public:
+
+  // Constructor
+  Fl_Main_Window(int x, int y, int w, int h, const char* l = 0);
+
+  // Destructor
+  ~Fl_Main_Window();
+  
+  // Activate connect
+  void ActivateConnect();
+
+  // Activate disconnect
+  void ActivateDisconnect();
+
+  // Activate shutdown
+  void ActivateShutdown();
+
+  // Deactivate connect
+  void DeactivateConnect();
+
+  // Deactivate disconnect
+  void DeactivateDisconnect();
+
+  // Deactivate shutdown
+  void DeactivateShutdown();
+
+  // Set menu items
+  void SetMenuItems(Fl_Menu_Item* items);
+
+private:
+
+  // Menu bar
+  Fl_Menu_Bar* _menuBar;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerClient.h
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerClient.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerClient.h	(revision 4)
@@ -0,0 +1,83 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef SYNCHRONIZER_CLIENT_H
+#define SYNCHRONIZER_CLIENT_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+/*--------------------------------------------------------------------------*/
+
+class SynchronizerClient {
+
+public:
+
+  // Default constructor
+  SynchronizerClient();
+
+  // Default destructor
+  ~SynchronizerClient();
+
+  // Barrier
+  void Barrier();
+
+  // Barrier
+  void Barrier(int level);
+
+  // Disconnect
+  void Finalize();
+
+  // Initialize
+  void Init(char* hostname, int port);
+
+  // Is initialized
+  bool IsInitialized();
+
+private:
+
+  // Is initialized flag
+  bool _isInitialized;
+
+  // Server port number
+  int _port;
+
+  // Server
+  struct hostent* _server;
+
+  // Server address
+  struct sockaddr_in _serverAddress;
+
+  // Socket file descriptor
+  int _serverSocketFileDescriptor;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/Fl_Slice_Frequency.cpp	(revision 4)
@@ -0,0 +1,89 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Fl_Slice_Frequency.h"
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Slice_Frequency::Fl_Slice_Frequency(int x, int y, int w, int h, 
+                                       const char *l)
+  : Fl_Double_Window(x, y, w, h, l) {
+
+  // Resize to the correct size
+  size(225, 80);
+
+  // Set modal
+  //set_modal();
+
+  // Create slice frequency counter
+  _counter = new Fl_Counter(10, 10, 200, 25, "");
+  _counter -> type(FL_SIMPLE_COUNTER);
+  _counter -> minimum(0.0);
+  _counter -> maximum(100.0);
+
+  // Create connect button
+  _okButton = new Fl_Return_Button(10, 45, 95, 25, "OK");
+
+  // Create exit button
+  _cancelButton = new Fl_Button(115, 45, 95, 25, "Cancel");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Fl_Slice_Frequency::~Fl_Slice_Frequency() {
+}
+
+/*--------------------------------------------------------------------------*/
+
+double Fl_Slice_Frequency::GetSliceFrequency() {
+
+  // Return host
+  return _counter -> value();
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Slice_Frequency::SetOKButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _okButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Slice_Frequency::SetCancelButtonCallback(Fl_Callback* cb, void* v) {
+
+  // Set callback
+  _cancelButton -> callback(cb, v);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Fl_Slice_Frequency::SetSliceFrequency(double frequency) {
+
+  // Set counter value
+  _counter -> value(frequency);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Communicator.h
===================================================================
--- trunk/src/testing/app/VRA/src/Communicator.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Communicator.h	(revision 4)
@@ -0,0 +1,171 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef COMMUNICATOR_H
+#define COMMUNICATOR_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <mpi.h>
+#include <string.h>
+
+#include "CommunicatorAbstractCommand.h"
+
+/*--------------------------------------------------------------------------*/
+
+class Communicator {
+
+public:
+
+  // Constructor
+  Communicator();
+
+  // Destructor
+  ~Communicator();
+
+  // Barrier
+  void Barrier();
+
+  // Destroy communication
+  void Destroy();
+
+  // Get command
+  void GetCommand();
+
+  // Get the master node's name
+  void GetMasterNodeName(char* name);
+
+  // Get the current node's name
+  void GetNodeName(char* name);
+
+  // Get total number of nodes
+  int GetNumberOfNodes();
+
+  // Get rank of current node
+  int GetRank();
+
+  // Initialize
+  void Init(int argc, char** argv);
+
+  // Turn axis off
+  void SendAxisOff();
+
+  // Turn axis on
+  void SendAxisOn();
+
+  // Turn brick box off
+  void SendBrickBoxOff();
+
+  // Turn brick box on
+  void SendBrickBoxOn();
+
+  // Turn bounding box off
+  void SendBoundingBoxOff();
+
+  // Turn bounding box on
+  void SendBoundingBoxOn();
+
+  // Send axis poistion
+  void SendAxisPosition(float x, float y, float z);
+
+  // Send clipping planes to specified node
+  void SendClippingPlanes(int node, float near, float far);
+
+  // Send exit command to all nodes
+  void SendCommandExit();
+
+  // Send render command to all nodes
+  void SendCommandRender();
+
+  // Send meta data filename to all nodes to load new data
+  void SendData(char* filename);
+
+  // Send meta data filename and cache sizes to all nodes to load new data
+  void SendData(char* filename, int ramSize, int vramSize);
+
+  // Send display size information to specified node
+  void SendDisplaySize(int node, 
+                       int width, 
+                       int height, 
+                       bool fullScreen, 
+                       char* hostname, 
+                       int port,
+                       float left,
+                       float right,
+                       float bottom,
+                       float top);
+
+  // Send frustum to specified node
+  void SendFrustum(int node, float left, float right,
+                   float bottom, float top);
+
+  // Send 8-bit color and opacity transfer function to all nodes
+  void SendMap(unsigned char* map);
+
+  // Send 8-bit color and opacity transfer function to all nodes
+  void SendMap8(unsigned char* map);
+
+  // Send 16-bit color and opacity transfer function to all nodes
+  void SendMap16(unsigned char* map);
+
+  // Send data prefix to all nodes
+  void SendPrefix(char* prefix);
+
+  // Send rotation matrix to all nodes
+  void SendRotationMatrix(float matrix[16]);
+
+  // Send scale matrix to all nodes
+  void SendScaleMatrix(float matrix[16]);
+
+  // Send slice frequency
+  void SendSliceFrequency(double frequency);
+
+  // Send translation matrix to all nodes
+  void SendTranslationMatrix(float matrix[16]);
+
+  // Send viewport to specified node
+  void SendViewport(int node, int x, int y, int w, int h);
+
+  // Set observer
+  void SetObserver(CommunicatorAbstractCommand* observer);
+
+private:
+  
+  // Master node name
+  char _masterNodeName[MPI_MAX_PROCESSOR_NAME];
+
+  // Node name
+  char _nodeName[MPI_MAX_PROCESSOR_NAME];
+
+  // Total number of nodes
+  int _numberOfNodes;
+
+  // Observer
+  CommunicatorAbstractCommand* _observer;
+
+  // Rank of current node
+  int _rank;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.cpp
===================================================================
--- trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/src/SynchronizerServerListenThreadInfo.cpp	(revision 4)
@@ -0,0 +1,69 @@
+/*---------------------------------------------------------------------------*/
+/* Volume Rendering Application                                              */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                  */
+/*                                                                           */
+/* This software is free software; you can redistribute it and/or modify it  */
+/* under the terms of the GNU Lesser General Public License as published by  */
+/* the Free Software Foundation; either Version 2.1 of the License, or       */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This software is distributed in the hope that it will be useful, but      */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser   */
+/* General Public License for more details.                                  */
+/*                                                                           */
+/* You should have received a copy of the GNU Lesser Public License along    */
+/* with this library; if not, write to the Free Software Foundation, Inc.,   */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     */
+/*---------------------------------------------------------------------------*/
+
+#include "SynchronizerServerListenThreadInfo.h"
+
+/*---------------------------------------------------------------------------*/
+
+SynchronizerServerListenThreadInfo::SynchronizerServerListenThreadInfo() {
+
+  // Initialize to NULL
+  _clientInfo = NULL;
+
+  // Initialize to NULL
+  _clientThread = NULL;
+
+  // Initialize to NULL
+  _conditionMutex = NULL;
+
+  // Initialize to NULL
+  _conditionVariable = NULL;
+
+  // Initialize to NULL
+  _finalizeFlag = NULL;
+
+  // Initialize to NULL
+  _level = NULL;
+
+  // Initialize to NULL
+  _numberOfClients = NULL;
+
+  // Initialize to NULL
+  _numberOfClientsWaiting = NULL;
+
+  // Initialize to NULL
+  _port = NULL;
+
+  // Initialize to NULL
+  _progressObserver = NULL;
+
+  // Initialize to NULL
+  _serverAddress = NULL;
+
+  // Initialize to NULL
+  _serverSocketFileDescriptor = NULL;
+
+}
+
+/*---------------------------------------------------------------------------*/
+
+SynchronizerServerListenThreadInfo::~SynchronizerServerListenThreadInfo() {
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/CacheRAM.h
===================================================================
--- trunk/src/testing/app/VRA/src/CacheRAM.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/CacheRAM.h	(revision 4)
@@ -0,0 +1,82 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef CACHE_RAM_H
+#define CACHE_RAM_H
+
+/*--------------------------------------------------------------------------*/
+
+#include "CacheRAMNode.h"
+#include "Log.h"
+#include "OctreeNode.h"
+
+/*--------------------------------------------------------------------------*/
+
+class CacheRAM {
+  
+public:
+  
+  // Default constructor
+  CacheRAM(int size);
+  
+  // Default destructor
+  ~CacheRAM();
+
+  // Is cache full
+  bool IsFull();
+
+  // Is item loaded
+  bool IsLoaded(OctreeNode* node);
+
+  // Load item
+  void Load(OctreeNode* node);
+
+  // Make item current
+  void MakeCurrent(OctreeNode* node);
+
+  // Move item to front of cache
+  void MoveToFront(OctreeNode* node);
+
+  // Print cache
+  void Print();
+
+  // Remove last item in cache
+  void RemoveLast();
+  
+private:
+
+  // Print a message to stdout
+  void Assert(const char* message);
+
+  // Current size of cache
+  int _currentSize;
+
+  // Maximum size of cache
+  int _maximumSize;
+
+  // Front of cache
+  CacheRAMNode* _front;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/src/Matrix.h
===================================================================
--- trunk/src/testing/app/VRA/src/Matrix.h	(revision 4)
+++ trunk/src/testing/app/VRA/src/Matrix.h	(revision 4)
@@ -0,0 +1,73 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef MATRIX_H
+#define MATRIX_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <math.h>
+
+/*--------------------------------------------------------------------------*/
+
+// Calculate rotation matrix about x axis
+void calc_rot_x(float matrix[16], float angle);
+
+// Calculate rotation matrix about y axis
+void calc_rot_y(float matrix[16], float angle);
+
+// Calculate rotation matrix about z axis
+void calc_rot_z(float matrix[16], float angle);
+
+// Calculate scale matrix
+void calc_scale(float matrix[16], float x, float y, float z);
+
+// Calculate translation matrix
+void calc_trans(float matrix[16], float x, float y, float z);
+
+// Calculate inverse matrix
+void inverse4x4(double out[16], double in[16]);
+
+// Calculate inverse matrix
+void inverse4x4(float out[16], float in[16]);
+
+// Return the maximum value
+double maximum(double in1, double in2);
+
+// Return the minimum value
+double minimum(double in1, double in2);
+
+// Multiply a 4x4 matrix by a 4x4 matrix
+void mult4x4(float out[16], float one[16], float two[16]);
+
+// Normalize the input vector
+void normalize3V(double in[3]);
+
+// Subtract the vectors
+// out = in1 - in2
+void sub3V(double out[3], double in1[3], double in2[3]);
+
+// Translate in1 by in2
+void translate3V(double out[3], double in1[16], double in2[3]);
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/bin/Fragment.cg
===================================================================
--- trunk/src/testing/app/VRA/bin/Fragment.cg	(revision 4)
+++ trunk/src/testing/app/VRA/bin/Fragment.cg	(revision 4)
@@ -0,0 +1,30 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+void Fragment(in float3 inTex : TEXCOORD0,
+              out float4 outColor : COLOR0,
+              const uniform sampler3D DataTexture,
+              const uniform sampler2D MapTexture) {
+
+  float2 val = tex3D(DataTexture, inTex).ar;
+  outColor = tex2D(MapTexture, val);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/bin/machine.dat
===================================================================
--- trunk/src/testing/app/VRA/bin/machine.dat	(revision 4)
+++ trunk/src/testing/app/VRA/bin/machine.dat	(revision 4)
@@ -0,0 +1,3 @@
+teiburu3-10
+teiburu2-10
+teiburu1-10
Index: trunk/src/testing/app/VRA/bin/VRA.conf
===================================================================
--- trunk/src/testing/app/VRA/bin/VRA.conf	(revision 4)
+++ trunk/src/testing/app/VRA/bin/VRA.conf	(revision 4)
@@ -0,0 +1,18 @@
+bridgeOn false
+fsIP 10.0.8.10
+fsPort 20002
+masterIP 10.0.8.10
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 3
+appID 0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+winWidth 1536
+winHeight 512
+syncMode 0
+asyncUpdate true
+nwProtocol TCP
Index: trunk/src/testing/app/VRA/bin/PurkinjeCell-BlueYellow.tf
===================================================================
--- trunk/src/testing/app/VRA/bin/PurkinjeCell-BlueYellow.tf	(revision 4)
+++ trunk/src/testing/app/VRA/bin/PurkinjeCell-BlueYellow.tf	(revision 4)
@@ -0,0 +1,22 @@
+255.000000
+COLOR 5
+0.000000 0.000000 0.000000 1.000000
+55.999992 0.000000 0.078431 0.921569
+127.500000 0.000000 1.000000 0.000000
+207.500000 0.914000 1.000000 0.000000
+255.000000 1.000000 0.000000 0.000000
+OPACITY 14
+0.000000 0.000000
+43.999992 0.000000
+86.999992 0.100000
+94.000084 0.000000
+99.999992 0.087500
+109.000092 0.000000
+153.999985 0.000000
+164.500000 0.000000
+177.000000 0.075000
+225.000000 0.100000
+228.500000 0.087500
+232.500000 0.112500
+235.999985 0.000000
+255.000000 0.000000
Index: trunk/src/testing/app/VRA/bin/PurkinjeCell-RedGreenBlue.tf
===================================================================
--- trunk/src/testing/app/VRA/bin/PurkinjeCell-RedGreenBlue.tf	(revision 4)
+++ trunk/src/testing/app/VRA/bin/PurkinjeCell-RedGreenBlue.tf	(revision 4)
@@ -0,0 +1,15 @@
+255.000000
+COLOR 5
+0.000000 0.000000 1.000000 0.000000
+76.499992 1.000000 1.000000 0.500000
+105.999992 0.000000 0.061947 0.938053
+127.500000 0.000000 1.000000 0.000000
+255.000000 1.000000 0.010000 0.000000
+OPACITY 7
+0.000000 0.000000
+55.499996 0.000000
+128.500000 0.237500
+202.000000 0.100000
+214.000000 0.010000
+234.000000 0.075000
+255.000000 0.087500
Index: trunk/src/testing/app/VRA/bin/VisibleFemale-Bone.tf
===================================================================
--- trunk/src/testing/app/VRA/bin/VisibleFemale-Bone.tf	(revision 4)
+++ trunk/src/testing/app/VRA/bin/VisibleFemale-Bone.tf	(revision 4)
@@ -0,0 +1,13 @@
+65536.000000
+COLOR 3
+0.000000 0.780000 0.500000 0.240000
+4096.000000 1.000000 1.000000 1.000000
+65536.000000 1.000000 1.000000 1.000000
+OPACITY 7
+0.000000 0.000000
+600.000000 0.000000
+1542.000000 0.000000
+2441.537354 0.437500
+4096.000000 0.463000
+4097.000000 0.000000
+65536.000000 0.000000
Index: trunk/src/testing/app/VRA/bin/KILL_VRA
===================================================================
--- trunk/src/testing/app/VRA/bin/KILL_VRA	(revision 4)
+++ trunk/src/testing/app/VRA/bin/KILL_VRA	(revision 4)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+for node in `cat .nodes`
+do
+        ssh -fx $node "killall -9 VRA VRA_UI" 
+done
Index: trunk/src/testing/app/VRA/bin/VisibleFemale-SkinBone.tf
===================================================================
--- trunk/src/testing/app/VRA/bin/VisibleFemale-SkinBone.tf	(revision 4)
+++ trunk/src/testing/app/VRA/bin/VisibleFemale-SkinBone.tf	(revision 4)
@@ -0,0 +1,12 @@
+65536.000000
+COLOR 3
+0.000000 0.780000 0.500000 0.240000
+4096.000000 1.000000 1.000000 1.000000
+65536.000000 1.000000 1.000000 1.000000
+OPACITY 6
+0.000000 0.000000
+642.509827 0.000000
+2441.537354 0.437500
+4096.000000 0.463000
+4097.000000 0.000000
+65536.000000 0.000000
Index: trunk/src/testing/app/VRA/bin/config
===================================================================
--- trunk/src/testing/app/VRA/bin/config	(revision 4)
+++ trunk/src/testing/app/VRA/bin/config	(revision 4)
@@ -0,0 +1,12 @@
+10001
+10002
+-5.0 5.0
+1536 512
+45.0
+0 0 512 512 0.00000 0.33333 0.0 1.00 0
+0 0 512 512 0.33333 0.66667 0.0 1.00 0
+0 0 512 512 0.66667 1.00000 0.0 1.00 0
+3
+NCMIR-Small /home/evl/schwarz/data/ncmir-small/ncmir-small_D-2048x4096x128_B-128x256x128 ncmir-small_D-2048x4096x128_B-128x256x128.meta
+Rock /home/evl/schwarz/data/06ET-2B/06ET-2B_D-1024x1024x4096_B-64x64x256 06ET-2B_D-1024x1024x4096_B-64x64x256.meta
+Visible-Female /home/evl/schwarz/data/visible-female/visible-female_D-512x512x2048_B-64x64x256 visible-female_D-512x512x2048_B-64x64x256.meta
Index: trunk/src/testing/app/VRA/bin/.nodes
===================================================================
--- trunk/src/testing/app/VRA/bin/.nodes	(revision 4)
+++ trunk/src/testing/app/VRA/bin/.nodes	(revision 4)
@@ -0,0 +1,4 @@
+teiburu
+teiburu1-10
+teiburu2-10
+teiburu3-10
Index: trunk/src/testing/app/VRA/bin/Run-VRA
===================================================================
--- trunk/src/testing/app/VRA/bin/Run-VRA	(revision 4)
+++ trunk/src/testing/app/VRA/bin/Run-VRA	(revision 4)
@@ -0,0 +1,3 @@
+mpirun -machinefile machine.dat -np 4 VRA &
+
+./VRA_UI &
Index: trunk/src/testing/app/VRA/shaders/Fragment.cg
===================================================================
--- trunk/src/testing/app/VRA/shaders/Fragment.cg	(revision 4)
+++ trunk/src/testing/app/VRA/shaders/Fragment.cg	(revision 4)
@@ -0,0 +1,30 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+void Fragment(in float3 inTex : TEXCOORD0,
+              out float4 outColor : COLOR0,
+              const uniform sampler3D DataTexture,
+              const uniform sampler2D MapTexture) {
+
+  float2 val = tex3D(DataTexture, inTex).ar;
+  outColor = tex2D(MapTexture, val);
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Makefile
===================================================================
--- trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Makefile	(revision 4)
+++ trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Makefile	(revision 4)
@@ -0,0 +1,42 @@
+##############################################################################
+# Volume Rendering Application
+# Copyright (C) 2006-2007 Nicholas Schwarz
+#
+# This software is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either Version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License along
+# with this library; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+
+CXX_FLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Wno-deprecated
+
+CXX = g++
+
+default: BenchmarkAnalyzer
+
+BenchmarkAnalyzer: BenchmarkAnalyzer.o \
+                   Operation.o         \
+                   Makefile
+	$(CXX) $(CXX_FLAGS) -o BenchmarkAnalyzer BenchmarkAnalyzer.o \
+                                                 Operation.o
+	cp BenchmarkAnalyzer ../../bin
+
+BenchmarkAnalyzer.o: BenchmarkAnalyzer.cpp Operation.h 
+	$(CXX) $(CXX_FLAGS) -c BenchmarkAnalyzer.cpp
+
+Operation.o: Operation.cpp Operation.h 
+	$(CXX) $(CXX_FLAGS) -c Operation.cpp
+
+clean:
+	rm -rf *.o *~ BenchmarkAnalyzer
+	rm -rf ../../bin/BenchmarkAnalyzer
+
Index: trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/BenchmarkAnalyzer.cpp
===================================================================
--- trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/BenchmarkAnalyzer.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/BenchmarkAnalyzer.cpp	(revision 4)
@@ -0,0 +1,1834 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <vector.h>
+
+#include "Operation.h"
+
+/*--------------------------------------------------------------------------*/
+
+#define ERROR 1
+#define OK 0
+
+/*--------------------------------------------------------------------------*/
+
+// Brick size
+int _brickSize[3];
+
+// Size of CacheRAM
+int _cacheRAMSize = 0;
+
+// Size of CacheVRAM
+int _cacheVRAMSize = 0;
+
+// Input file pointer
+FILE* _inputFilePtr = NULL;
+
+// Number of LODs
+int _numberOfLOD = 0;
+
+// Number of processes
+int _numberOfProcesses = 0;
+
+// Vector to hold number of cacheRAM hits for each LOD for each process
+vector<long long>* _cacheRAMHits = NULL;
+
+// Vector to hold number of cacheRAM misses for each LOD for each process
+vector<long long>* _cacheRAMMisses = NULL;
+
+// Vector to hold number of cacheVRAM hits for each LOD for each process
+vector<long long>* _cacheVRAMHits = NULL;
+
+// Vector to hold number of cacheVRAM misses for each LOD for each process
+vector<long long>* _cacheVRAMMisses = NULL;
+
+// Vector to hold time to load data for each LOD for each process
+vector<long long>* _loadDataTimePerLOD = NULL;
+
+// Vector to hold time to load textures for each LOD for each process
+vector<long long>* _loadTextureTimePerLOD = NULL;
+
+// Operation vector to hold operations for each process
+vector<Operation*>* _operationVector = NULL;
+
+// Vector to hold render time for all LODs for each process
+vector<long long>* _renderTimeAllLOD = NULL;
+
+// Vector to hold render time for each brick for each LOD for each process
+vector<long long>* _renderTimeBrickPerLOD = NULL;
+
+// Vector to hold render time for each LOD for each process
+vector<long long>* _renderTimePerLOD = NULL;
+
+/*--------------------------------------------------------------------------*/
+
+int allocate_storage() {
+
+  // Allocate memory for cacheRAM hits for each LOD for each process
+  _cacheRAMHits = new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_cacheRAMHits == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for cacheRAM misses for each LOD for each process
+  _cacheRAMMisses = new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_cacheRAMMisses == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for cacheVRAM hits for each LOD for each process
+  _cacheVRAMHits = new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_cacheVRAMHits == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for cacheVRAM misses for each LOD for each process
+  _cacheVRAMMisses = new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_cacheVRAMMisses == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for time to load data for each LOD for each process
+  _loadDataTimePerLOD = 
+    new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_loadDataTimePerLOD == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for time to load textures for each LOD for each process
+  _loadTextureTimePerLOD = 
+    new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_loadTextureTimePerLOD == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for operations from each process
+  _operationVector = new vector<Operation*>[_numberOfProcesses];
+
+  // Check for error
+  if (_operationVector == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for render time for all LODs for each process
+  _renderTimeAllLOD = new vector<long long>[_numberOfProcesses];
+
+  // Check for error
+  if (_renderTimeAllLOD == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for render time for each LOD for each process
+  _renderTimeBrickPerLOD = 
+    new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_renderTimeBrickPerLOD == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Allocate memory for render time for each LOD for each process
+  _renderTimePerLOD = new vector<long long>[_numberOfProcesses * _numberOfLOD];
+
+  // Check for error
+  if (_renderTimePerLOD == NULL) {
+    fprintf(stderr, "\nMemory allocation error\n");
+    return ERROR;
+  }
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int analyze_all() {
+
+  fprintf(stdout,
+          "---------------------------------------------------------------\n");
+  fflush(stdout);
+
+  long long rhits = 0;
+  long long rmisses = 0;
+  long long vrhits = 0;
+  long long vrmisses = 0;
+
+  long double averageLoadDataTime = 0.0;
+  long long numberOfLoadDataTimeEntries = 0;
+  long double stdDevLoadDataTime = 0.0;
+
+  long double averageLoadTextureTime = 0.0;
+  long long numberOfLoadTextureTimeEntries = 0;
+  long double stdDevLoadTextureTime = 0.0;
+
+  long double averageRenderTimeAllLOD = 0.0;
+  long long numberOfRenderTimeAllLODEntries = 0;
+  long double stdDevRenderTimeAllLOD = 0.0;
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _cacheRAMHits[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        rhits += _cacheRAMHits[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+  }
+  fprintf(stdout, 
+          "All CacheRAM Hits:                     %lld\n", 
+          rhits);
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _cacheRAMMisses[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        rmisses += _cacheRAMMisses[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+  }
+  fprintf(stdout, 
+          "All CacheRAM Misses:                   %lld\n", 
+          rmisses);
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _cacheVRAMHits[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        vrhits += _cacheVRAMHits[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+  }
+  fprintf(stdout, 
+          "All CacheVRAM Hits:                    %lld\n", 
+          vrhits);
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _cacheVRAMMisses[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        vrmisses += _cacheVRAMMisses[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+  }
+  fprintf(stdout, 
+          "All CacheVRAM Misses:                  %lld\n", 
+          vrmisses);
+
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _loadDataTimePerLOD[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        averageLoadDataTime += 
+          (long double) _loadDataTimePerLOD[(proc*_numberOfLOD)+level].at(i);
+        numberOfLoadDataTimeEntries++;
+      }
+    }
+  }
+  averageLoadDataTime /= (long double) numberOfLoadDataTimeEntries;
+  fprintf(stdout,
+          "Number of data loads:                  %lld\n",
+          numberOfLoadDataTimeEntries);
+  fprintf(stdout, 
+          "All average load data time:            %Lfus", 
+          averageLoadDataTime);
+
+  for (int p = 1 ; p < _numberOfProcesses ; p++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ; 
+           i < _loadDataTimePerLOD[(p*_numberOfLOD)+level].size() ; 
+           i++) {
+        stdDevLoadDataTime += 
+          ((long double) _loadDataTimePerLOD[(p*_numberOfLOD)+level].at(i)- 
+           averageLoadDataTime) *
+          ((long double) _loadDataTimePerLOD[(p*_numberOfLOD)+level].at(i)- 
+           averageLoadDataTime);
+      }
+    }
+  }
+  stdDevLoadDataTime /= (long double) (numberOfLoadDataTimeEntries-1);
+  stdDevLoadDataTime = sqrt(stdDevLoadDataTime);
+  fprintf(stdout, 
+          " sd: %Lfus\n", 
+          stdDevLoadDataTime);
+
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ;  
+           i < _loadTextureTimePerLOD[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        averageLoadTextureTime += 
+          (long double) _loadTextureTimePerLOD[(proc*_numberOfLOD)+level].
+          at(i);
+        numberOfLoadTextureTimeEntries++;
+      }
+    }
+  }
+  averageLoadTextureTime /= (long double) numberOfLoadTextureTimeEntries;
+  fprintf(stdout,
+          "Number of texture loads:               %lld\n",
+          numberOfLoadTextureTimeEntries);
+  fprintf(stdout, 
+          "All average load texture time:         %Lfus", 
+          averageLoadTextureTime);
+
+  for (int p = 1 ; p < _numberOfProcesses ; p++) {
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int i = 0 ; 
+           i < _loadTextureTimePerLOD[(p*_numberOfLOD)+level].size() ; 
+           i++) {
+        stdDevLoadTextureTime += 
+          ((long double) _loadTextureTimePerLOD[(p*_numberOfLOD)+level].at(i)- 
+           averageLoadTextureTime) *
+          ((long double) _loadTextureTimePerLOD[(p*_numberOfLOD)+level].at(i)- 
+           averageLoadTextureTime);
+      }
+    }
+  }
+  stdDevLoadTextureTime /= (long double) (numberOfLoadTextureTimeEntries-1);
+  stdDevLoadTextureTime = sqrt(stdDevLoadTextureTime);
+  fprintf(stdout, 
+          " sd: %Lfus\n", 
+          stdDevLoadTextureTime);
+
+
+  for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+    for (int i = 0 ; i < _renderTimeAllLOD[proc].size() ; i++) {
+      averageRenderTimeAllLOD += (long double) _renderTimeAllLOD[proc].at(i);
+      numberOfRenderTimeAllLODEntries++;
+    }    
+  }
+  averageRenderTimeAllLOD /= (long double) numberOfRenderTimeAllLODEntries;
+  fprintf(stdout,
+          "Number of complete frames:             %lld\n",
+          numberOfRenderTimeAllLODEntries);
+  fprintf(stdout, 
+          "All render complete frame time:        %Lfus", 
+          averageRenderTimeAllLOD);
+
+
+  for (int p = 1 ; p < _numberOfProcesses ; p++) {
+    for (int i = 0 ; i < _renderTimeAllLOD[p].size() ; i++) {
+      stdDevRenderTimeAllLOD += 
+        ((long double) _renderTimeAllLOD[p].at(i) - averageRenderTimeAllLOD) *
+        ((long double) _renderTimeAllLOD[p].at(i) - averageRenderTimeAllLOD);
+    }
+  }
+  stdDevRenderTimeAllLOD /= (long double) (numberOfRenderTimeAllLODEntries-1);
+  stdDevRenderTimeAllLOD = sqrt(stdDevRenderTimeAllLOD);
+  fprintf(stdout, 
+          " sd: %Lfus\n", 
+          stdDevRenderTimeAllLOD);
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int analyze_each_level() {
+
+  fprintf(stdout,
+          "---------------------------------------------------------------\n");
+  fflush(stdout);
+
+  for (int level = 0 ; level < _numberOfLOD ; level++) {
+
+    fprintf(stdout, "Level: %d\n", level);
+    fflush(stdout);
+
+    long long rhits = 0;
+    long long rmisses = 0;
+    long long vrhits = 0;
+    long long vrmisses = 0;
+
+    long double averageLoadDataTime = 0.0;
+    long long numberOfLoadDataTimeEntries = 0;
+    long double stdDevLoadDataTime = 0.0;
+
+    long double averageLoadTextureTime = 0.0;
+    long long numberOfLoadTextureTimeEntries = 0;
+    long double stdDevLoadTextureTime = 0.0;
+
+    long double averageRenderTimeAllLOD = 0.0;
+    long long numberOfRenderTimeAllLODEntries = 0;
+    long double stdDevRenderTimeAllLOD = 0.0;
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int i = 0 ;  
+           i < _cacheRAMHits[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        rhits += _cacheRAMHits[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+    fprintf(stdout, 
+            "  CacheRAM Hits:                     %lld\n", 
+            rhits);
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int i = 0 ;  
+           i < _cacheRAMMisses[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        rmisses += _cacheRAMMisses[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+    fprintf(stdout, 
+            "  CacheRAM Misses:                   %lld\n", 
+            rmisses);
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int i = 0 ;  
+           i < _cacheVRAMHits[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        vrhits += _cacheVRAMHits[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+    fprintf(stdout, 
+            "  CacheVRAM Hits:                    %lld\n", 
+            vrhits);
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int i = 0 ;  
+           i < _cacheVRAMMisses[(proc*_numberOfLOD)+level].size() ;
+           i++) {
+        vrmisses += _cacheVRAMMisses[(proc*_numberOfLOD)+level].at(i);
+      }
+    }
+    fprintf(stdout, 
+            "  CacheVRAM Misses:                  %lld\n", 
+            vrmisses);
+
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadDataTime += 
+          (long double) _loadDataTimePerLOD[(proc * _numberOfLOD) + level].
+          at(j);
+      }
+      numberOfLoadDataTimeEntries += 
+        _loadDataTimePerLOD[(proc * _numberOfLOD) + level].size();
+    }
+    averageLoadDataTime /= (long double) numberOfLoadDataTimeEntries;
+    
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadDataTime += 
+          ((long double) _loadDataTimePerLOD[(proc*_numberOfLOD) + level]
+           .at(j) - averageLoadDataTime) *
+          ((long double) _loadDataTimePerLOD[(proc*_numberOfLOD) + level]
+           .at(j) - averageLoadDataTime);
+      }
+    }
+    stdDevLoadDataTime /= (long double) (numberOfLoadDataTimeEntries - 1);
+    stdDevLoadDataTime = sqrt(stdDevLoadDataTime);
+
+    // Print 
+    fprintf(stdout, 
+            "  Average load data time:            %Lfus  ", 
+            averageLoadDataTime);
+    fprintf(stdout, 
+            "sd: %Lfus\n", 
+            stdDevLoadDataTime);
+
+
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadTextureTime += 
+          (long double) _loadTextureTimePerLOD[(proc * _numberOfLOD) + level].
+          at(j);
+      }
+      numberOfLoadTextureTimeEntries += 
+        _loadTextureTimePerLOD[(proc * _numberOfLOD) + level].size();
+    }
+    averageLoadTextureTime /= (long double) numberOfLoadTextureTimeEntries;
+    
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadTextureTime += 
+          ((long double) _loadTextureTimePerLOD[(proc*_numberOfLOD) + level]
+           .at(j) - averageLoadTextureTime) *
+          ((long double) _loadTextureTimePerLOD[(proc*_numberOfLOD) + level]
+           .at(j) - averageLoadTextureTime);
+      }
+    }
+    stdDevLoadTextureTime /= (long double) (numberOfLoadTextureTimeEntries- 1);
+    stdDevLoadTextureTime = sqrt(stdDevLoadTextureTime);
+
+    // Print 
+    fprintf(stdout, 
+            "  Average load texture time:         %Lfus  ", 
+            averageLoadTextureTime);
+    fprintf(stdout, 
+            "sd: %Lfus\n", 
+            stdDevLoadTextureTime);
+
+
+    // Average render time per frame for this level
+    long double averageRenderTimePerLOD = 0.0;
+    long long numPerLOD = 0;
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _renderTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageRenderTimePerLOD += 
+          (long double) _renderTimePerLOD[(proc * _numberOfLOD) + level].at(j);
+        numPerLOD++;
+      }
+    }
+    averageRenderTimePerLOD /= 
+      (long double) numPerLOD;
+
+    // Standard deviation of the render time per frame for this level
+    long double stdDevRenderTimePerLOD = 0.0;
+    for (int proc = 1 ; proc < _numberOfProcesses ; proc++) {
+      for (int j = 0 ; 
+           j < _renderTimePerLOD[(proc * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevRenderTimePerLOD += 
+          ((long double) _renderTimePerLOD[(proc*_numberOfLOD)+level].at(j) - 
+           averageRenderTimePerLOD) *
+          ((long double) _renderTimePerLOD[(proc*_numberOfLOD)+level].at(j) - 
+           averageRenderTimePerLOD);
+      }
+    }
+    stdDevRenderTimePerLOD /= 
+      (long double) (numPerLOD - 1);
+    stdDevRenderTimePerLOD = sqrt(stdDevRenderTimePerLOD);
+    
+    // Print 
+    fprintf(stdout, 
+            "  Average time to render:            %Lfus  ", 
+            averageRenderTimePerLOD);
+    fprintf(stdout, 
+            "sd: %Lfus\n", 
+            stdDevRenderTimePerLOD);
+    
+  }
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int analyze_each_process() {
+
+  fprintf(stdout,
+          "---------------------------------------------------------------\n");
+  fflush(stdout);
+
+  // One process at a time
+  for (int i = 1 ; i < _numberOfProcesses ; i++) {
+
+    // Print process number
+    fprintf(stdout, "Process number:                  %d\n", i);
+
+    // Print number of complete frames
+    fprintf(stdout, "Number of complete frames:       %d\n", 
+            _renderTimeAllLOD[i].size());
+
+    // Average render time per frame for all LODs
+    long double averageRenderTimeAllLOD = 0.0;
+    for (int j = 0 ; j < _renderTimeAllLOD[i].size() ; j++) {
+      averageRenderTimeAllLOD += (long double) _renderTimeAllLOD[i].at(j);
+    }
+    averageRenderTimeAllLOD /= (long double) _renderTimeAllLOD[i].size();
+
+    // Standard deviation of the render time per frame for all LODs
+    long double stdDevRenderTimeAllLOD = 0.0;
+    for (int j = 0 ; j < _renderTimeAllLOD[i].size() ; j++) {
+      stdDevRenderTimeAllLOD += 
+        ((long double) _renderTimeAllLOD[i].at(j) - averageRenderTimeAllLOD) *
+        ((long double) _renderTimeAllLOD[i].at(j) - averageRenderTimeAllLOD);
+    }
+    stdDevRenderTimeAllLOD /= (long double) (_renderTimeAllLOD[i].size() - 1);
+    stdDevRenderTimeAllLOD = sqrt(stdDevRenderTimeAllLOD);
+
+    // Print average time to render all LODs of a frame
+    fprintf(stdout, 
+            "Average time to render all LODs:                  %Lfus\n", 
+            averageRenderTimeAllLOD);
+
+    // Print standard deviation of time to render all LODs of a frame
+    fprintf(stdout, 
+            "Standard deviation of time to render all LODs:    %Lfus\n", 
+            stdDevRenderTimeAllLOD);
+
+
+    // Average time to load data for this process
+    long double averageLoadDataTimePerProcess = 0.0;
+    long long numberOfLoadDataTimeEntries = 0;
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadDataTimePerProcess += 
+          (long double) _loadDataTimePerLOD[(i * _numberOfLOD) + level].
+          at(j);
+      }
+      numberOfLoadDataTimeEntries += 
+        _loadDataTimePerLOD[(i * _numberOfLOD) + level].size();
+    }
+    averageLoadDataTimePerProcess /= 
+      (long double) numberOfLoadDataTimeEntries;
+
+    // Standard deviation of the load data time for this process
+    long double stdDevLoadDataTimePerProcess = 0.0;
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadDataTimePerProcess += 
+          ((long double) _loadDataTimePerLOD[(i*_numberOfLOD) + level].at(j) - 
+           averageLoadDataTimePerProcess) *
+          ((long double) _loadDataTimePerLOD[(i*_numberOfLOD) + level].at(j) - 
+           averageLoadDataTimePerProcess);
+      }
+    }
+    stdDevLoadDataTimePerProcess /= 
+      (long double) (numberOfLoadDataTimeEntries - 1);
+    stdDevLoadDataTimePerProcess = sqrt(stdDevLoadDataTimePerProcess);
+
+    // Print 
+    fprintf(stdout, 
+            "Average load data time:                           %Lfus\n", 
+            averageLoadDataTimePerProcess);
+    fprintf(stdout, 
+            "Standard deviation of average load data time:     %Lfus\n", 
+            stdDevLoadDataTimePerProcess);
+
+
+    // Average time to load texture for this process
+    long double averageLoadTextureTimePerProcess = 0.0;
+    long long numberOfLoadTextureTimeEntries = 0;
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadTextureTimePerProcess += 
+          (long double) _loadTextureTimePerLOD[(i * _numberOfLOD) + level].
+          at(j);
+      }
+      numberOfLoadTextureTimeEntries += 
+        _loadTextureTimePerLOD[(i * _numberOfLOD) + level].size();
+    }
+    averageLoadTextureTimePerProcess /= 
+      (long double) numberOfLoadTextureTimeEntries;
+
+    // Standard deviation of the load texture time for this process
+    long double stdDevLoadTextureTimePerProcess = 0.0;
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadTextureTimePerProcess += 
+          ((long double) _loadTextureTimePerLOD[(i*_numberOfLOD)+level].at(j)- 
+           averageLoadTextureTimePerProcess) *
+          ((long double) _loadTextureTimePerLOD[(i*_numberOfLOD)+level].at(j)- 
+           averageLoadTextureTimePerProcess);
+      }
+    }
+    stdDevLoadTextureTimePerProcess /= 
+      (long double) (numberOfLoadTextureTimeEntries - 1);
+    stdDevLoadTextureTimePerProcess = sqrt(stdDevLoadTextureTimePerProcess);
+
+    // Print 
+    fprintf(stdout, 
+            "Average load texture time:                        %Lfus\n", 
+            averageLoadTextureTimePerProcess);
+    fprintf(stdout, 
+            "Standard deviation of average load texture time:  %Lfus\n", 
+            stdDevLoadTextureTimePerProcess);
+
+
+    // Cache (V)RAM hits and misses
+    long long trhits = 0;
+    long long trmisses = 0;
+    long long tvrhits = 0;
+    long long tvrmisses = 0;
+
+    // Calculate all cacheRAM hits for this process
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _cacheRAMHits[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        trhits += _cacheRAMHits[(i * _numberOfLOD) + level].at(j);
+      }
+    }
+
+    // Calculate all cacheRAM misses for this process
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _cacheRAMMisses[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        trmisses += _cacheRAMMisses[(i * _numberOfLOD) + level].at(j);
+      }
+    }
+
+    // Print 
+    fprintf(stdout, 
+            "CacheRAM Hits:                                    %lld\n", 
+            trhits);
+    fprintf(stdout, 
+            "CacheRAM Misses:                                  %lld\n", 
+            trmisses);
+
+    // Calculate all cacheVRAM hits for this process
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _cacheVRAMHits[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        tvrhits += _cacheVRAMHits[(i * _numberOfLOD) + level].at(j);
+      }
+    }
+
+    // Calculate all cacheVRAM misses for this process
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+      for (int j = 0 ; 
+           j < _cacheVRAMMisses[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        tvrmisses += _cacheVRAMMisses[(i * _numberOfLOD) + level].at(j);
+      }
+    }
+
+    // Print 
+    fprintf(stdout, 
+            "CacheVRAM Hits:                                   %lld\n", 
+            tvrhits);
+    fprintf(stdout, 
+            "CacheVRAM Misses:                                 %lld\n", 
+            tvrmisses);
+
+
+    // One level at a time
+    for (int level = 0 ; level < _numberOfLOD ; level++) {
+
+      // Print level number
+      fprintf(stdout, "  Level number:                  %d\n", level);
+
+      // Cache (V)RAM hits and misses
+      long long rhits = 0;
+      long long rmisses = 0;
+      long long vrhits = 0;
+      long long vrmisses = 0;
+
+      // Calculate cacheRAM hits
+      for (int j = 0 ; 
+           j < _cacheRAMHits[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        rhits += _cacheRAMHits[(i * _numberOfLOD) + level].at(j);
+      }
+
+      // Calculate cacheRAM misses
+      for (int j = 0 ; 
+           j < _cacheRAMMisses[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        rmisses += _cacheRAMMisses[(i * _numberOfLOD) + level].at(j);
+      }
+
+      // Calculate cacheVRAM hits
+      for (int j = 0 ; 
+           j < _cacheVRAMHits[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        vrhits += _cacheVRAMHits[(i * _numberOfLOD) + level].at(j);
+      }
+
+      // Calculate cacheVRAM misses
+      for (int j = 0 ; 
+           j < _cacheVRAMMisses[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        vrmisses += _cacheVRAMMisses[(i * _numberOfLOD) + level].at(j);
+      }
+
+      // Print 
+      fprintf(stdout, "  CacheRAM Hits:                 %lld\n", rhits);
+      fprintf(stdout, "  CacheRAM Misses:               %lld\n", rmisses);
+      fprintf(stdout, "  CacheVRAM Hits:                %lld\n", vrhits);
+      fprintf(stdout, "  CacheVRAM Misses:              %lld\n", vrmisses);
+
+
+      // Average time to load data for this level
+      long double averageLoadDataTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadDataTimePerLOD += 
+          (long double) _loadDataTimePerLOD[(i * _numberOfLOD) + level].
+          at(j);
+      }
+      averageLoadDataTimePerLOD /= 
+        (long double) _loadDataTimePerLOD[(i * _numberOfLOD) + level].size();
+
+      // Standard deviation of the load data time for this level
+      long double stdDevLoadDataTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _loadDataTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadDataTimePerLOD += 
+          ((long double) _loadDataTimePerLOD[(i*_numberOfLOD) + level].at(j) - 
+           averageLoadDataTimePerLOD) *
+          ((long double) _loadDataTimePerLOD[(i*_numberOfLOD) + level].at(j) - 
+           averageLoadDataTimePerLOD);
+      }
+      stdDevLoadDataTimePerLOD /= 
+        (long double) (_loadDataTimePerLOD[(i*_numberOfLOD)+level].size() - 1);
+      stdDevLoadDataTimePerLOD = sqrt(stdDevLoadDataTimePerLOD);
+
+      // Print 
+      fprintf(stdout, 
+              "  Average load data time:                           %Lfus\n", 
+              averageLoadDataTimePerLOD);
+      fprintf(stdout, 
+              "  Standard deviation of average load data time:     %Lfus\n", 
+              stdDevLoadDataTimePerLOD);
+
+
+      // Average time to load texture for this level
+      long double averageLoadTextureTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageLoadTextureTimePerLOD += 
+          (long double) _loadTextureTimePerLOD[(i*_numberOfLOD) + level].
+          at(j);
+      }
+      averageLoadTextureTimePerLOD /= 
+        (long double) _loadTextureTimePerLOD[(i*_numberOfLOD) + level].size();
+
+      // Standard deviation of the load texture time for this level
+      long double stdDevLoadTextureTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _loadTextureTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevLoadTextureTimePerLOD += 
+          ((long double) _loadTextureTimePerLOD[(i*_numberOfLOD)+level].at(j)- 
+           averageLoadTextureTimePerLOD) *
+          ((long double) _loadTextureTimePerLOD[(i*_numberOfLOD)+level].at(j)- 
+           averageLoadTextureTimePerLOD);
+      }
+      stdDevLoadTextureTimePerLOD /= 
+        (long double)(_loadTextureTimePerLOD[(i*_numberOfLOD)+level].size()-1);
+      stdDevLoadTextureTimePerLOD = sqrt(stdDevLoadTextureTimePerLOD);
+
+      // Print 
+      fprintf(stdout, 
+              "  Average load texture time:                        %Lfus\n", 
+              averageLoadTextureTimePerLOD);
+      fprintf(stdout, 
+              "  Standard deviation of average load texture time:  %Lfus\n", 
+              stdDevLoadTextureTimePerLOD);
+
+
+      // Average render time per frame for this level
+      long double averageRenderTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _renderTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        averageRenderTimePerLOD += 
+          (long double) _renderTimePerLOD[(i * _numberOfLOD) + level].at(j);
+      }
+      averageRenderTimePerLOD /= 
+        (long double) _renderTimePerLOD[(i * _numberOfLOD) + level].size();
+
+      // Standard deviation of the render time per frame for this level
+      long double stdDevRenderTimePerLOD = 0.0;
+      for (int j = 0 ; 
+           j < _renderTimePerLOD[(i * _numberOfLOD) + level].size() ; 
+           j++) {
+        stdDevRenderTimePerLOD += 
+          ((long double) _renderTimePerLOD[(i * _numberOfLOD) + level].at(j) - 
+           averageRenderTimePerLOD) *
+          ((long double) _renderTimePerLOD[(i * _numberOfLOD) + level].at(j) - 
+           averageRenderTimePerLOD);
+      }
+      stdDevRenderTimePerLOD /= 
+        (long double) (_renderTimeAllLOD[(i*_numberOfLOD)+level].size() - 1);
+      stdDevRenderTimePerLOD = sqrt(stdDevRenderTimePerLOD);
+
+      // Print 
+      fprintf(stdout, 
+              "  Average time to render:                           %Lfus\n", 
+              averageRenderTimePerLOD);
+      fprintf(stdout, 
+              "  Standard deviation of average render time:        %Lfus\n", 
+              stdDevRenderTimePerLOD);
+
+    }
+
+  }
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int brick_size() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Check for valid file pointer
+  if (_inputFilePtr == NULL) {
+
+    // Return error
+    return ERROR;
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Determining brick size... ");
+  fflush(stdout);
+
+
+  // Read each line looking for brick size
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+    
+    // Temporary operation object
+    Operation test(line);
+
+    // Find an operation that has brick width
+    if ((!strcmp(test.GetClassName(), "OctreeNode")) &&
+        (strstr(test.GetInfo(), "W:") != NULL)) {
+      
+      // Find width
+      char* info = test.GetInfo();
+      char tmp[128];
+      memset(tmp, 0, 128);
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Convert to decimal
+      _brickSize[0] = atoi(tmp);
+
+    }
+
+    // Find an operation that has brick height
+    if ((!strcmp(test.GetClassName(), "OctreeNode")) &&
+        (strstr(test.GetInfo(), "H:") != NULL)) {
+      
+      // Find width
+      char* info = test.GetInfo();
+      char tmp[128];
+      memset(tmp, 0, 128);
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Convert to decimal
+      _brickSize[1] = atoi(tmp);
+
+    }
+
+    // Find an operation that has brick height
+    if ((!strcmp(test.GetClassName(), "OctreeNode")) &&
+        (strstr(test.GetInfo(), "D:") != NULL) &&
+        (strstr(test.GetInfo(), "ID:") == NULL)) {
+      
+      // Find width
+      char* info = test.GetInfo();
+      char tmp[128];
+      memset(tmp, 0, 128);
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Convert to decimal
+      _brickSize[2] = atoi(tmp);
+
+    }
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "%d x %d x %d\n", 
+          _brickSize[0], _brickSize[1], _brickSize[2]);
+  fflush(stdout);
+
+
+  // Set file pointer to beginning of file
+  rewind(_inputFilePtr);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cacheRAM_size() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Check for valid file pointer
+  if (_inputFilePtr == NULL) {
+
+    // Return error
+    return ERROR;
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Determining final number of bricks in CacheRAM... ");
+  fflush(stdout);
+
+
+  // Read each line looking for CacheRAM operations
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+    
+    // Temporary operation object
+    Operation test(line);
+
+    // Find an operation that has maximum size of CacheRAM
+    if ((!strcmp(test.GetClassName(), "CacheRAM")) &&
+        (strstr(test.GetInfo(), "Maximum Size") != NULL)) {
+      
+      // Find size
+      char* info = test.GetInfo();
+      char tmp[128];
+      memset(tmp, 0, 128);
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Convert to decimal
+      _cacheRAMSize = atoi(tmp);
+
+    }
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "%d\n", _cacheRAMSize);
+  fflush(stdout);
+
+
+  // Set file pointer to beginning of file
+  rewind(_inputFilePtr);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int cacheVRAM_size() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Check for valid file pointer
+  if (_inputFilePtr == NULL) {
+
+    // Return error
+    return ERROR;
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Determining final number of bricks in CacheVRAM... ");
+  fflush(stdout);
+
+
+  // Read each line looking for CacheRAM operations
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+    
+    // Temporary operation object
+    Operation test(line);
+
+    // Find an operation that has maximum size of CacheRAM
+    if ((!strcmp(test.GetClassName(), "CacheVRAM")) &&
+        (strstr(test.GetInfo(), "Maximum Size") != NULL)) {
+      
+      // Find size
+      char* info = test.GetInfo();
+      char tmp[128];
+      memset(tmp, 0, 128);
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Convert to decimal
+      _cacheVRAMSize = atoi(tmp);
+
+    }
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "%d\n", _cacheVRAMSize);
+  fflush(stdout);
+
+
+  // Set file pointer to beginning of file
+  rewind(_inputFilePtr);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int deallocate_storage() {
+
+  if (_cacheRAMHits != NULL) {
+    delete [] _cacheRAMHits;
+  }
+
+  if (_cacheRAMMisses != NULL) {
+    delete [] _cacheRAMMisses;
+  }
+
+  if (_cacheVRAMHits != NULL) {
+    delete [] _cacheVRAMHits;
+  }
+
+  if (_cacheVRAMMisses != NULL) {
+    delete [] _cacheVRAMMisses;
+  }
+
+  if (_loadDataTimePerLOD != NULL) {
+    delete [] _loadDataTimePerLOD;
+  }
+
+  if (_loadTextureTimePerLOD != NULL) {
+    delete [] _loadTextureTimePerLOD;
+  }
+
+  if (_operationVector != NULL) {
+    for (int i = 0 ; i < _numberOfProcesses ; i++) {
+      for (int j = 0 ; j < _operationVector[i].size() ; j++) {
+        Operation* tmp = _operationVector[i].at(j);
+        if (tmp != NULL) {
+          delete tmp;
+        }
+      }
+    }
+    delete [] _operationVector;
+  }
+
+  if (_renderTimeAllLOD != NULL) {
+    delete [] _renderTimeAllLOD;
+  }
+
+  if (_renderTimeBrickPerLOD != NULL) {
+    delete [] _renderTimeBrickPerLOD;
+  }
+
+  if (_renderTimePerLOD != NULL) {
+    delete [] _renderTimePerLOD;
+  }
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int num_lod() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Check for valid file pointer
+  if (_inputFilePtr == NULL) {
+
+    // Return error
+    return ERROR;
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Determining number of LODs... ");
+  fflush(stdout);
+
+
+  // Read each line looking for process numbers
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+    
+    // Temporary operation object
+    Operation test(line);
+
+    // Find an operation that has a level number in it
+    if ((!strcmp(test.GetClassName(), "VolumeRenderer")) &&
+        (strstr(test.GetInfo(), "Render level") != NULL)) {
+      
+      // Find level number
+      char* info = test.GetInfo();
+      char tmp[128];
+      int j = 0;      
+      for (int i = 0 ; i < strlen(info) ; i++) {
+        char c = info[i];
+        if (isdigit(c)) {
+          tmp[j++] = c;
+        }
+      }
+
+      // Check for greatest number of LOD
+      if (atoi(tmp) + 1 > _numberOfLOD) {
+        _numberOfLOD = atoi(tmp) + 1;
+      }
+
+    }
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "%d\n", _numberOfLOD);
+  fflush(stdout);
+
+
+  // Set file pointer to beginning of file
+  rewind(_inputFilePtr);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int num_processes() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Check for valid file pointer
+  if (_inputFilePtr == NULL) {
+
+    // Return error
+    return ERROR;
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Determining number of processes... ");
+  fflush(stdout);
+
+
+  // Read each line looking for process numbers
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+      
+    // Temporary operation object
+    Operation test(line);
+
+    // Check for greatest process number
+    if (test.GetProcessNumber() + 1 > _numberOfProcesses) {
+      _numberOfProcesses = test.GetProcessNumber() + 1;
+    }
+
+  }
+
+
+  // Nice message
+  fprintf(stdout, "%d\n", _numberOfProcesses);
+  fflush(stdout);
+
+
+  // Set file pointer to beginning of file
+  rewind(_inputFilePtr);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int open_file(char* filename) {
+
+  // Nice message
+  fprintf(stdout, "Opening input file %s... ", filename);
+  fflush(stdout);
+
+  // Attempt to open input file
+  if ((_inputFilePtr = fopen(filename, "r")) == NULL) {
+    fprintf(stdout, "Failed to open input file %s.\n", filename);
+    return ERROR;
+  }
+
+  // Nice message
+  fprintf(stdout, "Success\n");
+  fflush(stdout);
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int process() {
+
+  // Line
+  char* line = NULL;
+
+  // Line length
+  size_t len = 0;
+
+  // Size of line read
+  ssize_t read;
+
+
+  // Nice message
+  fprintf(stdout, "Processing... ");
+  fflush(stdout);
+
+
+  // Begin and end of a render operation flags for each process
+  bool* renderBeginFound = new bool[_numberOfProcesses];
+  bool* renderEndFound = new bool[_numberOfProcesses];
+  for (int i = 0 ; i < _numberOfProcesses ; i++) {
+    renderBeginFound[i] = false;
+    renderEndFound[i] = false;
+  }
+
+
+  // Read each line
+  while ((read = getline(&line, &len, _inputFilePtr)) != -1) {
+
+
+    // Create new operation
+    Operation* op = new Operation(line);
+
+
+    // Check if it's a begin
+    if ((!strcmp(op -> GetClassName(), "VolumeRenderer")) &&
+        (strstr(op -> GetInfo(), "Render begin") != NULL)) {
+
+      // Mark begin flag
+      renderBeginFound[op -> GetProcessNumber()] = true;
+
+      // Add operation to end of list
+      _operationVector[op -> GetProcessNumber()].push_back(op);
+
+    }
+
+
+    // Check if it's an end
+    else if ((!strcmp(op -> GetClassName(), "VolumeRenderer")) &&
+             (strstr(op -> GetInfo(), "Render end") != NULL)) {      
+   
+      // Mark end flag
+      renderEndFound[op -> GetProcessNumber()] = true;
+
+      // Add operation to end of list
+      _operationVector[op -> GetProcessNumber()].push_back(op);
+
+    }
+
+
+    // Operation is between a begin and an end; keep it
+    else if (renderBeginFound[op -> GetProcessNumber()] == true && 
+             renderEndFound[op -> GetProcessNumber()] == false) {
+
+      // Add operation to end of list
+      _operationVector[op -> GetProcessNumber()].push_back(op);
+
+    }
+
+
+    // If it's outside a begin and an end
+    else {
+
+      // Delete operation
+      delete op;
+
+      // Go to top of loop and process next event
+      continue;
+
+    }    
+
+
+    // Get process number
+    int procNum = op -> GetProcessNumber();
+
+
+    // Found both a begin and an end for current process number
+    if (renderBeginFound[procNum] == true && 
+        renderEndFound[procNum] == true) {
+      
+      // Get information string
+      char* opStr = 
+        _operationVector[procNum].at(_operationVector[procNum].size() - 1) -> 
+        GetInfo();
+
+      // Check for a complete frame
+      if(strstr(opStr, "Completed") != NULL) {
+
+
+        // Time to render all LODs for a complete frame
+        long long startTime = 
+          (_operationVector[procNum].at(0)) 
+          -> GetTime();
+        long long endTime = 
+          (_operationVector[procNum].at(_operationVector[procNum].size() - 1)) 
+          -> GetTime();
+        long long totalTime = endTime - startTime;
+        _renderTimeAllLOD[procNum].push_back(totalTime);
+
+        
+        // Time to render each LOD
+        // CacheRAM Hits and Misses
+        // CacheVRAM Hits and Misses
+
+        // Cache RAM hits and misses
+        long long cacheRAMHits = 0;
+        long long cacheRAMMisses = 0;
+
+        // Cache VRAM hits and misses
+        long long cacheVRAMHits = 0;
+        long long cacheVRAMMisses = 0;
+
+        // Current level
+        int level = 0;
+
+        // Level begin and end flags
+        bool levelBegin = false;
+        bool levelEnd = false;
+
+        // Load data begin and end flags
+        bool loadDataBegin = false;
+        bool loadDataEnd = false;
+
+        // Load data start and end times
+        long long loadDataBeginTime = 0;
+        long long loadDataEndTime = 0;
+
+        // Load texture begin and end flags
+        bool loadTextureBegin = false;
+        bool loadTextureEnd = false;
+
+        // Load texture start and end times
+        long long loadTextureBeginTime = 0;
+        long long loadTextureEndTime = 0;
+
+        // Go through each operation in current frame
+        for (int i = 0 ; i < _operationVector[procNum].size() ; i++) {
+
+          // Get operation
+          Operation* tmp = _operationVector[procNum].at(i);
+
+          // Check if it's a level begin
+          if ((!strcmp(tmp -> GetClassName(), "VolumeRenderer")) &&
+              (strstr(tmp -> GetInfo(), "Render level") != NULL) &&
+              (strstr(tmp -> GetInfo(), "begin") != NULL)) {
+
+            // Start time
+            startTime = tmp -> GetTime();
+
+            // Mark begin flag
+            levelBegin = true;
+
+          }
+
+          // Check if it's a level end
+          else if ((!strcmp(tmp -> GetClassName(), "VolumeRenderer")) &&
+                   (strstr(tmp -> GetInfo(), "Render level") != NULL) &&
+                   (strstr(tmp -> GetInfo(), "end") != NULL)) {
+
+            // End time
+            endTime = tmp -> GetTime();
+
+            // Mark end flag
+            levelEnd = true;
+
+          }
+
+          // Operation is between a level begin and a level end; process it
+          else if (levelBegin == true && levelEnd == false){
+
+            // CacheRAM Hit
+            if ((!strcmp(tmp -> GetClassName(), "CacheRAM")) &&
+                (strstr(tmp -> GetInfo(), "loaded? True") != NULL)) {
+              cacheRAMHits++;
+            }
+
+            // CacheRAM Miss
+            else if ((!strcmp(tmp -> GetClassName(), "CacheRAM")) &&
+                     (strstr(tmp -> GetInfo(), "loaded? False") != NULL)) {
+              cacheRAMMisses++;
+            }
+
+            // CacheVRAM Hit
+            else if ((!strcmp(tmp -> GetClassName(), "CacheVRAM")) &&
+                     (strstr(tmp -> GetInfo(), "loaded? True") != NULL)) {
+              cacheVRAMHits++;
+            }
+
+            // CacheVRAM Miss
+            else if ((!strcmp(tmp -> GetClassName(), "CacheVRAM")) &&
+                     (strstr(tmp -> GetInfo(), "loaded? False") != NULL)) {
+              cacheVRAMMisses++;
+            }
+
+            // Begin of load data
+            else if ((!strcmp(tmp -> GetClassName(), "OctreeNode")) &&
+                     (strstr(tmp -> GetInfo(), "LoadData") != NULL) &&
+                     (strstr(tmp -> GetInfo(), "begin") != NULL)) {
+
+              // Set flag
+              loadDataBegin = true;
+
+              // Get start time
+              loadDataBeginTime = tmp -> GetTime();
+
+            }
+
+            // End of load data
+            else if ((!strcmp(tmp -> GetClassName(), "OctreeNode")) &&
+                     (strstr(tmp -> GetInfo(), "LoadData") != NULL) &&
+                     (strstr(tmp -> GetInfo(), "end") != NULL)) {
+
+              // Set flag
+              loadDataEnd = true;
+
+              // Get end time
+              loadDataEndTime = tmp -> GetTime();
+
+              // Check to make sure there's a matching begin and end
+              if (loadDataBegin == true && loadDataEnd == true) {
+
+                // Save time to load data
+                _loadDataTimePerLOD[(procNum * _numberOfLOD) + level].
+                  push_back(loadDataEndTime - loadDataBeginTime);
+
+              }
+
+              // Reset flags
+              loadDataBegin = false;
+              loadDataEnd = false;
+
+            }
+
+            // Begin of load texture
+            else if ((!strcmp(tmp -> GetClassName(), "OctreeNode")) &&
+                     (strstr(tmp -> GetInfo(), "LoadTexture") != NULL) &&
+                     (strstr(tmp -> GetInfo(), "begin") != NULL)) {
+
+              // Set flag
+              loadTextureBegin = true;
+
+              // Get start time
+              loadTextureBeginTime = tmp -> GetTime();
+
+            }
+
+            // End of load texture
+            else if ((!strcmp(tmp -> GetClassName(), "OctreeNode")) &&
+                     (strstr(tmp -> GetInfo(), "LoadTexture") != NULL) &&
+                     (strstr(tmp -> GetInfo(), "end") != NULL)) {
+
+              // Set flag
+              loadTextureEnd = true;
+
+              // Get end time
+              loadTextureEndTime = tmp -> GetTime();
+
+              // Check to make sure there's a matching begin and end
+              if (loadTextureBegin == true && loadTextureEnd == true) {
+
+                // Save time to load data
+                _loadTextureTimePerLOD[(procNum * _numberOfLOD) + level].
+                  push_back(loadTextureEndTime - loadTextureBeginTime);
+
+              }
+
+              // Reset flags
+              loadTextureBegin = false;
+              loadTextureEnd = false;
+
+            }
+
+          }
+
+          // Operation is outside a level begin and a level end
+          else {
+
+            // Go to top of loop
+            continue;
+
+          }
+
+          // Found both a begin and an end
+          if (levelBegin == true && levelEnd == true) {
+
+            // Calcualte time
+            totalTime = endTime - startTime;
+
+            // Save time
+            _renderTimePerLOD[(procNum * _numberOfLOD) + level].
+              push_back(totalTime);
+
+            // Save cacheRAM hits
+            _cacheRAMHits[(procNum * _numberOfLOD) + level].
+              push_back(cacheRAMHits);
+
+            // Save cacheRAM misses
+            _cacheRAMMisses[(procNum * _numberOfLOD) + level].
+              push_back(cacheRAMMisses);
+
+            // Save cacheVRAM hits
+            _cacheVRAMHits[(procNum * _numberOfLOD) + level].
+              push_back(cacheVRAMHits);
+
+            // Save cacheVRAM misses
+            _cacheVRAMMisses[(procNum * _numberOfLOD) + level].
+              push_back(cacheVRAMMisses);
+
+            // Reset cacheRAM stats
+            cacheRAMHits = 0;
+            cacheRAMMisses = 0;
+
+            // Reset cacheVRAM stats
+            cacheVRAMHits = 0;
+            cacheVRAMMisses = 0;
+
+            // Reset flags
+            levelBegin = false;
+            levelEnd = false;
+
+            // Increment level
+            level++;
+
+          }
+
+        }
+
+
+      }
+
+      // Clear flags
+      renderBeginFound[procNum] = false;
+      renderEndFound[procNum] = false;
+      
+      // Clean up operations      
+      for (int i = 0 ; i < _operationVector[procNum].size() ; i++) {
+        Operation* tmp = _operationVector[procNum].at(i);
+        if (tmp != NULL) {
+          delete tmp;
+        }
+      }
+      _operationVector[procNum].clear();
+      
+    }    
+  
+
+  }
+
+
+  // Clean up render begin flag
+  if (renderBeginFound != NULL) {
+    delete [] renderBeginFound;
+  }
+
+  // Clean up render end flag
+  if (renderEndFound != NULL) {
+    delete [] renderEndFound;
+  }
+
+
+  // Nice message
+  fprintf(stdout, "Done\n");
+  fflush(stdout);
+
+
+  // Return OK
+  return OK;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char** argv) {
+
+  // Nice message
+  fprintf(stdout, "Benchmark Analyzer for Volume Rendering Application\n");
+  fflush(stdout);
+
+  // Check command line arguments
+  if (argc != 2) {
+    fprintf(stderr, "Usage: Analyzer inputFile\n");
+    exit(1);
+  }
+
+  // Open input file
+  open_file(argv[1]);
+
+  // Determine number of processes
+  num_processes();
+
+  // Determine number of levels-of-detail
+  num_lod();
+
+  // Determine size of CacheRAM
+  cacheRAM_size();
+
+  // Determine size of CacheVRAM
+  cacheVRAM_size();
+
+  // Determine brick size
+  brick_size();
+
+  // Allocate storage
+  allocate_storage();
+
+  // Process data
+  process();
+
+  // Analyze data and print out results
+  analyze_each_process();
+
+  // Analyze data for each level
+  analyze_each_level();
+
+  // Analyze all processes
+  analyze_all();
+
+  // Deallocate storage
+  deallocate_storage();
+
+  // Return
+  return 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.cpp
===================================================================
--- trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.cpp	(revision 4)
@@ -0,0 +1,328 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include "Operation.h"
+
+/*--------------------------------------------------------------------------*/
+
+Operation::Operation() {
+
+  // Initialize class name
+  memset(_className, 0, 1024);
+
+  // Initialize operation information
+  memset(_info, 0, 4096);
+
+  // Initialize log number
+  _logNumber = -1;
+
+  // Initialize process number
+  _processNumber = -1;
+
+  // Initialize time
+  _time = -1;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Operation::Operation(char* string) {
+
+  // Initialize class name
+  memset(_className, 0, 1024);
+
+  // Initialize operation information
+  memset(_info, 0, 4096);
+
+  // Initialize log number
+  _logNumber = -1;
+
+  // Initialize process number
+  _processNumber = -1;
+
+  // Initialize time
+  _time = -1;
+
+
+  // Position in input string
+  int stringPosition = 0;
+
+  // Start of operation found flag
+  bool foundStart = false;
+
+  // End of operation found flag
+  bool foundEnd = false;
+
+  // Log number as string
+  char logNumberString[128];
+  memset(logNumberString, 0, 128);
+
+  // Process number as string
+  char processNumberString[128];
+  memset(processNumberString, 0, 128);
+
+  // Nice text message
+  char text[12];
+  memset(text, 0, 12);
+
+  // Time as string
+  char timeString[128];
+  memset(timeString, 0, 128);
+
+  // Class name
+  char className[1024];
+  memset(className, 0, 1024);
+
+  // Class name
+  char info[4096];
+  memset(info, 0, 4096);
+
+  //fprintf(stdout, "%s\n", string);
+
+  // Search for beginning of operation message indicated by '['
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c == '[') {
+      foundStart = true;
+      stringPosition++;
+      break;
+    }
+  }
+
+  // Check that start of operation is found
+  if (foundStart == false) {
+    fprintf(stderr, "Invalid operation format 0.\n");
+    return;
+  }
+
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+  // Get process number
+  for (int i = 0 ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      processNumberString[i] = c;
+      i++;
+    }
+    else {
+      break;
+    }
+  }
+
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+  // Get log number
+  for (int i = 0 ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      logNumberString[i] = c;
+      i++;
+    }
+    else {
+      break;
+    }
+  }
+
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+
+  // Skip nice text message
+  for (int i = 0 ; 
+       string[stringPosition] != '\0' && i < 11 ; 
+       i++, stringPosition++) {
+    text[i] = string[stringPosition];
+  }
+
+  // Check that nice message is correct
+  if (strcmp("Log - Time:", text)) {
+    fprintf(stderr, "Invalid operation format 1.\n");
+    return;
+  }
+  
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+  // Get time
+  for (int i = 0 ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ' && c != 'u' && c != 's') {
+      timeString[i] = c;
+      i++;
+    }
+    else {
+      break;
+    }
+  }
+
+  // Check for 'u' in 'us'
+  if (string[stringPosition++] != 'u') {
+    fprintf(stderr, "Invalid operation format 2.\n");
+    return;
+  }
+
+  // Check for 's' in 'us'
+  if (string[stringPosition++] != 's') {
+    fprintf(stderr, "Invalid operation format 3.\n");
+    return;
+  }
+
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+  // Get class name
+  for (int i = 0 ; 
+       string[stringPosition] != '\0' && i < 1024 ; 
+       i++, stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ':' && c != ' ') {
+      className[i] = c;
+    }
+    else {
+      stringPosition++;
+      break;
+    }
+  }
+
+  // Skip spaces
+  for ( ; string[stringPosition] != '\0' ; stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ' ') {
+      break;
+    }
+  }
+
+  // Get operation info
+  for (int i = 0 ; 
+       string[stringPosition] != '\0' && i < 4096 ; 
+       i++, stringPosition++) {
+    char c = string[stringPosition];
+    if (c != ']') {
+      info[i] = c;
+    }
+    else {
+      foundEnd = true;
+      break;
+    }
+  }
+
+  // Check that end of operation is found
+  if (foundEnd == false) {
+    fprintf(stderr, "Invalid operation format 4.\n");
+    return;
+  }
+
+  // Convert log number
+  _logNumber = atoi(logNumberString);
+
+  // Convert process number
+  _processNumber = atoi(processNumberString);
+
+  // Convert time
+  _time = atoll(timeString);
+
+  // Copy class name
+  strcpy(_className, className);
+
+  // Copy operation information
+  strcpy(_info, info);
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+Operation::~Operation() {
+
+  //fprintf(stdout, "Destructor\n");
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+char* Operation::GetClassName() {
+
+  // Return class name
+  return _className;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+char* Operation::GetInfo() {
+
+  // Return operation information
+  return _info;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Operation::GetLogNumber() {
+
+  // Return log number
+  return _logNumber;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+int Operation::GetProcessNumber() {
+
+  // Return process number
+  return _processNumber;
+
+}
+
+/*--------------------------------------------------------------------------*/
+
+long long Operation::GetTime() {
+
+  // Return operation time
+  return _time;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.h
===================================================================
--- trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.h	(revision 4)
+++ trunk/src/testing/app/VRA/testing/BenchmarkAnalyzer/Operation.h	(revision 4)
@@ -0,0 +1,82 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#ifndef OPERATION_H
+#define OPERATION_H
+
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*--------------------------------------------------------------------------*/
+
+class Operation {
+
+public:
+
+  // Default constructor
+  Operation();
+
+  // Constructor that parses a message string
+  Operation(char* string);
+
+  // Default destructor
+  ~Operation();
+
+  // Get class name
+  char* GetClassName();
+
+  // Get operation information
+  char* GetInfo();
+
+  // Get log number
+  int GetLogNumber();
+
+  // Get process number
+  int GetProcessNumber();
+
+  // Get operation time
+  long long GetTime();
+
+private:
+
+  // Class name
+  char _className[1024];
+
+  // Operation information
+  char _info[4096];
+
+  // Log number
+  int _logNumber;
+
+  // Process number
+  int _processNumber;
+
+  // Operation time
+  long long _time;
+
+};
+
+/*--------------------------------------------------------------------------*/
+
+#endif
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/VRA/testing/GenerateBrick/Makefile
===================================================================
--- trunk/src/testing/app/VRA/testing/GenerateBrick/Makefile	(revision 4)
+++ trunk/src/testing/app/VRA/testing/GenerateBrick/Makefile	(revision 4)
@@ -0,0 +1,37 @@
+##############################################################################
+# Volume Rendering Application
+# Copyright (C) 2006-2007 Nicholas Schwarz
+#
+# This software is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either Version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License along
+# with this library; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+
+CXX_FLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Wno-deprecated
+
+CXX = g++
+
+default: GenerateBrick
+
+GenerateBrick: GenerateBrick.o \
+               Makefile
+	$(CXX) $(CXX_FLAGS) -o GenerateBrick GenerateBrick.o
+	cp GenerateBrick ../../bin
+
+GenerateBrick.o: GenerateBrick.cpp
+	$(CXX) $(CXX_FLAGS) -c GenerateBrick.cpp
+
+clean:
+	rm -rf *.o *~ GenerateBrick
+	rm -rf ../../bin/GenerateBrick
+
Index: trunk/src/testing/app/VRA/testing/GenerateBrick/GenerateBrick.cpp
===================================================================
--- trunk/src/testing/app/VRA/testing/GenerateBrick/GenerateBrick.cpp	(revision 4)
+++ trunk/src/testing/app/VRA/testing/GenerateBrick/GenerateBrick.cpp	(revision 4)
@@ -0,0 +1,77 @@
+/*--------------------------------------------------------------------------*/
+/* Volume Rendering Application                                             */
+/* Copyright (C) 2006-2007 Nicholas Schwarz                                 */
+/*                                                                          */
+/* This software is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU Lesser General Public License as published by */
+/* the Free Software Foundation; either Version 2.1 of the License, or      */
+/* (at your option) any later version.                                      */
+/*                                                                          */
+/* This software is distributed in the hope that it will be useful, but     */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of               */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser  */
+/* General Public License for more details.                                 */
+/*                                                                          */
+/* You should have received a copy of the GNU Lesser Public License along   */
+/* with this library; if not, write to the Free Software Foundation, Inc.,  */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                    */
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*--------------------------------------------------------------------------*/
+
+int main(int argc, char** argv) {
+  
+  // Check command line arguments
+  if (argc != 3) {
+    fprintf(stderr, "Usage: GenerateBrick outfile extent\n");
+    exit(1);
+  }
+
+  // Get size
+  int size = atoi(argv[2]);
+
+  // Attempt to open file for writing
+  FILE* outfptr = NULL;
+  if ((outfptr = fopen(argv[1], "w")) == NULL) {
+    fprintf(stderr, "Can't open file %s for writing.\n", argv[1]);
+    exit(1);
+  }
+
+  // Data value to write
+  unsigned short value = 0;
+
+  // Generate and write data
+  for (int z = 0 ; z < size ; z++) {
+    for (int y = 0 ; y < size ; y++) {
+      for (int x = 0 ; x < size ; x++) {
+
+        //if (fseeko(outfptr, (z*size*size)+(y*size)+x, SEEK_SET) != 0) {
+        //  fprintf(stderr, "Error setting file position.\n");
+        //}
+
+        // Make value
+        value = 
+          (unsigned short) (int) (((long double) z / (long double) size) * 
+                                  (long double) 65535.0);
+
+        // Write value
+        if (fwrite(&value, sizeof(unsigned short), 1, outfptr) != 1) {
+          fprintf(stderr, "Error writting value.\n");
+        }
+        
+      }
+    }
+  }
+
+  // Close file
+  fclose(outfptr);
+
+  // Return
+  return 0;
+
+}
+
+/*--------------------------------------------------------------------------*/
Index: trunk/src/testing/app/hd-video-player/resource.h
===================================================================
--- trunk/src/testing/app/hd-video-player/resource.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/resource.h	(revision 4)
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by DecklinkCapture.rc
+//
+#define IDR_MANIFEST                    1
+#define IDM_ABOUTBOX                    0x0010
+#define IDD_ABOUTBOX                    100
+#define IDS_ABOUTBOX                    101
+#define IDD_DECKLINKCAPTURE_DIALOG      102
+#define IDR_MAINFRAME                   128
+#define IDC_COMBO_VIDEOFORMATS          1000
+#define IDC_COMBO_AUDIOFORMATS          1001
+#define IDC_STATIC_PREVIEW              1002
+#define IDC_CHECK_AUDIOMUTE             1003
+#define IDC_EDIT_CAPTUREFILE            1004
+#define IDC_BUTTON_BROWSE               1005
+#define IDC_BUTTON_CAPTURE              1006
+#define IDC_BUTTON_STOP                 1007
+#define IDC_COMBO_COMPRESSION           1008
+#define IDC_BUTTON_CODECPROPERTIES      1009
+#define IDC_COMBO_VIDEODEVICE           1010
+#define IDC_COMBO_AUDIODEVICE           1011
+#define IDC_SAGE_START                  1012
+#define IDC_SAGE_STOP                   1013
+#define IDC_SAGE_ADDR                   1014
+#define IDC_EDIT1                       1015
+#define IDC_SAGE_EDIT_IP                1015
+#define IDC_SAGE_STOP2                  1016
+#define IDC_SAGE_REG                    1016
+#define IDC_COMBO_COMPRESSION2          1017
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        129
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1016
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
Index: trunk/src/testing/app/hd-video-player/GrabberProc.h
===================================================================
--- trunk/src/testing/app/hd-video-player/GrabberProc.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/GrabberProc.h	(revision 4)
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#ifndef _GRABBERCB_
+#define _GRABBERCB_
+
+#include <qedit.h>   // Sample grabber
+
+#include "Histogram.h"
+#include "Utils.h"
+#include "output_sail.h"
+
+class C_GrabProc {
+
+//	static GrabberCB m_grabberCallback;  // Make this global so that it stays in scope while the graph exists
+	// create filter------------
+	AM_MEDIA_TYPE m_mt;
+	AM_MEDIA_TYPE m_audiomt;
+	CComPtr<IBaseFilter> m_pGrabF;
+	CComPtr<IBaseFilter> m_pAudioGrabF;
+	CComPtr<IBaseFilter> m_pYUVtransF;
+	int m_sub_type;
+	// send image---------------
+    BYTE*   m_pImg;
+    BYTE*   m_pAudioSamples;
+    DWORD   m_dwWidth;
+    DWORD   m_dwHeight;
+    LONG    m_lStride;
+    int     m_iBitDepth;
+	int		m_out_color_mode;
+	unsigned char* m_pbRGB_buff;
+	DWORD m_bufLen;
+	bool m_sageOn;
+	CString m_ip;
+
+	class C_Output_sail Out_sail;
+
+public :
+	// create filter------------
+	C_GrabProc(void);
+	void FreeFilter(void);
+	HRESULT SetFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName, int out_color_mode, bool sage=false);
+	HRESULT SetAudioFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName);
+	IBaseFilter* GrabF(void);
+	// send image---------------
+	HRESULT SetVideoFormat(const VIDEOINFOHEADER& vih, int out_color_mode);
+    HRESULT SetImageBuffer(BYTE *pBuffer);
+    HRESULT SetAudioBuffer(BYTE *pBuffer);
+	HRESULT ConvertImage();
+	int SendToBmp(void);
+	int SendToSage(void);
+	int SendAudioToSage(int buflen);
+	void setIP(CString ip);
+
+	void SetAudioOn(bool on);
+	void SetAudioCaptureMode(bool on);
+	void Shutdown();
+
+	bool GetSageOn();
+};
+
+// GrabberCB: Class to implement the callback function for the sample grabber
+// Note: No ref-counting, so keep the object in scope while you're using it!
+class GrabberCB : public ISampleGrabberCB
+{
+private:
+    BITMAPINFOHEADER m_bmi;  // Holds the bitmap format
+    bool m_fFirstSample;     // true if the next sample is the first one.
+
+public:
+
+    GrabberCB();
+    ~GrabberCB();
+
+	C_GrabProc m_GrabProc;
+	int m_out_color_mode;
+
+    // IUnknown methods
+    STDMETHODIMP_(ULONG) AddRef() { return 1; }
+    STDMETHODIMP_(ULONG) Release() { return 2; }
+    STDMETHOD(QueryInterface)(REFIID iid, void** ppv);
+
+    // ISampleGrabberCB methods
+    STDMETHOD(SampleCB)(double SampleTime, IMediaSample *pSample);
+    STDMETHODIMP BufferCB(double, BYTE *, long) { return E_NOTIMPL; }
+
+};
+
+// AudioGrabberCB: Class to implement the callback function for the sample grabber
+// Note: No ref-counting, so keep the object in scope while you're using it!
+class AudioGrabberCB : public ISampleGrabberCB
+{
+private:
+    BITMAPINFOHEADER m_bmi;  // Holds the bitmap format
+    bool m_fFirstSample;     // true if the next sample is the first one.
+	int m_index;
+public:
+
+    AudioGrabberCB();
+    ~AudioGrabberCB();
+
+	C_GrabProc* m_GrabProc;
+
+    // IUnknown methods
+    STDMETHODIMP_(ULONG) AddRef() { return 1; }
+    STDMETHODIMP_(ULONG) Release() { return 2; }
+    STDMETHOD(QueryInterface)(REFIID iid, void** ppv);
+
+    // ISampleGrabberCB methods
+    STDMETHOD(SampleCB)(double SampleTime, IMediaSample *pSample);
+    STDMETHODIMP BufferCB(double, BYTE *, long) { return E_NOTIMPL; }
+
+};
+
+// GUID media_type_ary[] = {MEDIASUBTYPE_UYVY, MEDIASUBTYPE_YUY2, MEDIASUBTYPE_YUYV};
+
+#ifdef _MAIN_
+GrabberCB grabberCallback;  // Make this global so that it stays in scope while the graph exists
+AudioGrabberCB AudioGrabCallback;
+#else
+extern GrabberCB grabberCallback;  // Make this global so that it stays in scope while the graph exists
+extern AudioGrabberCB AudioGrabCallback;
+#endif
+
+
+#endif
Index: trunk/src/testing/app/hd-video-player/stdafx.h
===================================================================
--- trunk/src/testing/app/hd-video-player/stdafx.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/stdafx.h	(revision 4)
@@ -0,0 +1,83 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#ifndef VC_EXTRALEAN
+#define VC_EXTRALEAN		// Exclude rarely-used stuff from Windows headers
+#endif
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER				// Allow use of features specific to Windows 95 and Windows NT 4 or later.
+#define WINVER 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#endif
+
+#ifndef _WIN32_WINNT		// Allow use of features specific to Windows NT 4 or later.
+#define _WIN32_WINNT 0x0400		// Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
+#endif
+
+#ifndef _WIN32_WINDOWS		// Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE			// Allow use of features specific to IE 4.0 or later.
+#define _WIN32_IE 0x0400	// Change this to the appropriate value to target IE 5.0 or later.
+#endif
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// some CString constructors will be explicit
+
+// turns off MFC's hiding of some common and often safely ignored warning messages
+#define _AFX_ALL_WARNINGS
+
+#include <afxwin.h>         // MFC core and standard components
+#include <afxext.h>         // MFC extensions
+#include <afxdisp.h>        // MFC Automation classes
+
+#include <afxdtctl.h>		// MFC support for Internet Explorer 4 Common Controls
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h>			// MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <streams.h>			// DShow
+#include <strsafe.h>
+#include <DecklinkInterface.h>	// Decklink
+#include <Dshowasf.h>			// Windows Media Encoder
+#include <wmsysprf.h>			// WM8 system profiles
Index: trunk/src/testing/app/hd-video-player/decklinkcapturedlg.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/decklinkcapturedlg.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/decklinkcapturedlg.cpp	(revision 4)
@@ -0,0 +1,1708 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// $Id: DecklinkCaptureDlg.cpp,v 1.9 2006/04/11 01:11:07 ivanr Exp $
+//
+// Desc: DirectShow capture sample
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//
+// Modified by khchoi (khchoi@netmedia.gist.ac.kr) 2006/08/28
+//-----------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "DecklinkCapture.h"
+#include "DecklinkCaptureDlg.h"
+#define _SMART_TREE_
+#define _MAIN_
+#include "GrabberProc.h"
+#include "Utils2.h"
+
+#include <initguid.h>	// TODO: move this to a lib
+//#include "DecklinkSample_uuids.h"
+
+#undef lstrlenW
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+#define WM_GRAPHNOTIFY		WM_APP+1		// for Filter Graph event notification
+
+int FrameRate = FR20; // 20fps
+
+//-----------------------------------------------------------------------------
+// CAboutDlg
+//-----------------------------------------------------------------------------
+
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialog
+{
+public:
+	CAboutDlg();
+
+// Dialog Data
+	enum { IDD = IDD_ABOUTBOX };
+
+	protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+// Implementation
+protected:
+	DECLARE_MESSAGE_MAP()
+};
+
+CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
+{
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+END_MESSAGE_MAP()
+
+
+//-----------------------------------------------------------------------------
+// CDecklinkCaptureDlg dialog
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Constructor
+//
+CDecklinkCaptureDlg::CDecklinkCaptureDlg(CWnd* pParent /*=NULL*/)
+	: CDialog(CDecklinkCaptureDlg::IDD, pParent)
+	, m_pIVW(NULL)
+{
+	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+CDecklinkCaptureDlg::~CDecklinkCaptureDlg() {
+	grabberCallback.m_GrabProc.FreeFilter();
+}
+
+//-----------------------------------------------------------------------------
+// DoDataExchange
+//
+void CDecklinkCaptureDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialog::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_COMBO_VIDEOFORMATS, m_videoFormatCtrl);
+	DDX_Control(pDX, IDC_COMBO_AUDIOFORMATS, m_audioFormatCtrl);
+
+	DDX_Control(pDX, IDC_STATIC_PREVIEW, m_preview);
+
+	DDX_Control(pDX, IDC_EDIT_CAPTUREFILE, m_captureFileCtrl);
+	DDX_Control(pDX, IDC_COMBO_COMPRESSION, m_compressionCtrl);
+	DDX_Control(pDX, IDC_COMBO_COMPRESSION2, m_framerateCtrl);
+	DDX_Control(pDX, IDC_COMBO_VIDEODEVICE, m_videoDeviceCtrl);
+	DDX_Control(pDX, IDC_COMBO_AUDIODEVICE, m_audioDeviceCtrl);
+
+	DDX_Control(pDX, IDC_SAGE_ADDR,		m_sageStreamCtrl);
+	DDX_Control(pDX, IDC_SAGE_EDIT_IP,	m_sageIPCtrl);
+
+	DDX_Control(pDX, IDC_CHECK_AUDIOMUTE, m_MuteCtrl);
+}
+
+BEGIN_MESSAGE_MAP(CDecklinkCaptureDlg, CDialog)
+	ON_WM_SYSCOMMAND()
+	ON_WM_PAINT()
+	ON_WM_QUERYDRAGICON()
+	//}}AFX_MSG_MAP
+	ON_CBN_SELCHANGE(IDC_COMBO_VIDEOFORMATS, OnCbnSelchangeComboVideoformats)
+	ON_CBN_SELCHANGE(IDC_COMBO_AUDIOFORMATS, OnCbnSelchangeComboAudioformats)
+	ON_BN_CLICKED(IDC_CHECK_AUDIOMUTE, OnBnClickedCheckAudiomute)
+	ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnBnClickedButtonBrowse)
+	ON_BN_CLICKED(IDC_BUTTON_CAPTURE, OnBnClickedButtonCapture)
+	ON_BN_CLICKED(IDC_BUTTON_STOP, OnBnClickedButtonStop)
+	ON_CBN_SELCHANGE(IDC_COMBO_COMPRESSION, OnCbnSelchangeComboCompression)
+	ON_CBN_SELCHANGE(IDC_COMBO_VIDEODEVICE, OnCbnSelchangeComboVideodevice)
+	ON_CBN_SELCHANGE(IDC_COMBO_AUDIODEVICE, OnCbnSelchangeComboAudiodevice)
+	ON_BN_CLICKED(IDC_BUTTON_CODECPROPERTIES, &CDecklinkCaptureDlg::OnBnClickedButtonCodecproperties)
+	ON_BN_CLICKED(IDC_SAGE_START, &CDecklinkCaptureDlg::OnBnClickedSageStart)
+	ON_BN_CLICKED(IDC_SAGE_STOP, &CDecklinkCaptureDlg::OnBnClickedSageStop)
+	ON_CBN_SELCHANGE(IDC_SAGE_ADDR, &CDecklinkCaptureDlg::OnCbnSelchangeSageAddr)
+	ON_EN_CHANGE(IDC_SAGE_EDIT_IP, &CDecklinkCaptureDlg::OnEnChangeSageEditIp)
+	ON_BN_CLICKED(IDC_SAGE_REG, &CDecklinkCaptureDlg::OnBnClickedSageReg)
+	ON_CBN_SELCHANGE(IDC_COMBO_COMPRESSION2, &CDecklinkCaptureDlg::OnCbnSelchangeComboCompression2)
+END_MESSAGE_MAP()
+
+
+//-----------------------------------------------------------------------------
+// CDecklinkCaptureDlg message handlers
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// OnInitDialog
+// Called before the dialog is displayed, use this message handler to initialise
+// our app
+BOOL CDecklinkCaptureDlg::OnInitDialog()
+{
+	CDialog::OnInitDialog();
+
+	// Add "About..." menu item to system menu.
+
+	// IDM_ABOUTBOX must be in the system command range.
+	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
+	ASSERT(IDM_ABOUTBOX < 0xF000);
+
+	CMenu* pSysMenu = GetSystemMenu(FALSE);
+	if (pSysMenu != NULL)
+	{
+		CString strAboutMenu;
+		strAboutMenu.LoadString(IDS_ABOUTBOX);
+		if (!strAboutMenu.IsEmpty())
+		{
+			pSysMenu->AppendMenu(MF_SEPARATOR);
+			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
+		}
+	}
+
+	// Set the icon for this dialog.  The framework does this automatically
+	//  when the application's main window is not a dialog
+	SetIcon(m_hIcon, TRUE);			// Set big icon
+	SetIcon(m_hIcon, FALSE);		// Set small icon
+
+	// create a basic capture graph and preview the incoming video
+	m_pGraph = NULL;
+	m_pVideoCapture = NULL;
+	m_pAudioCapture = NULL;
+	m_pVideoRenderer = NULL;
+	m_pSmartT = NULL;
+
+	m_pControl = NULL;
+
+	m_pIVW = NULL;
+	m_pMediaEvent = NULL;
+
+	m_ROTRegister = 0;
+	m_bAudioMute = FALSE;
+
+	m_compressor = 0;
+	m_framerate = 0;
+	m_bEnableCompressionCtrl = TRUE;
+
+	m_captureFile = "<Select File>";
+
+	// initialise default video media type
+	ZeroMemory(&m_vihDefault, sizeof(m_vihDefault));
+	m_vihDefault.AvgTimePerFrame = 333667;
+	m_vihDefault.bmiHeader.biWidth = 720;
+	m_vihDefault.bmiHeader.biHeight = 486;
+	m_vihDefault.bmiHeader.biBitCount = 16;
+	m_vihDefault.bmiHeader.biCompression = 'YVYU';
+
+	LoadIpInfo();
+
+	/*m_sageStreamCtrl.InsertString(0, _T("Yorda"));
+	m_sageStreamCtrl.InsertString(1, _T("Caesar"));
+	m_sageStreamCtrl.InsertString(2, _T("PathFinder"));
+	m_sageStreamCtrl.SetCurSel(1);
+	m_sageIPCtrl.SetWindowText("67.58.62.21");
+	*/
+
+	// initialise default audio media type
+	ZeroMemory(&m_wfexDefault, sizeof(m_wfexDefault));
+	m_wfexDefault.nChannels = 2;	// the only field of interest
+
+	// retrieve last state
+	QueryRegistry();
+
+	m_captureFileCtrl.SetWindowText(m_captureFile);
+
+	EnableControls();
+
+	// create a preview graph
+	// add the filters that will be used by all the graphs; preview, uncompressed capture, dv capture,
+	// mpeg capture and windows media capture
+	HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, reinterpret_cast<void**>(&m_pGraph));
+	if (SUCCEEDED(hr))
+	{
+#ifdef _DEBUG
+//		hr = CDSUtils::AddGraphToRot(m_pGraph, &m_ROTRegister);
+#endif
+		hr = m_pGraph->QueryInterface(IID_IMediaControl, reinterpret_cast<void**>(&m_pControl));
+		if (SUCCEEDED(hr))
+		{
+			// locate the video capture devices
+			hr = PopulateDeviceControl(&CLSID_VideoInputDeviceCategory, &m_videoDeviceCtrl);
+			if (SUCCEEDED(hr))
+			{
+				hr = PopulateDeviceControl(&CLSID_AudioInputDeviceCategory, &m_audioDeviceCtrl);
+				if (SUCCEEDED(hr))
+				{
+					PWSTR pVideoName = (PWSTR)m_videoDeviceCtrl.GetItemData(m_videoDeviceCtrl.SetCurSel(0));
+					PWSTR pAudioName = (PWSTR)m_audioDeviceCtrl.GetItemData(m_audioDeviceCtrl.SetCurSel(0));
+					if (pVideoName && pAudioName)
+					{
+						hr = CDSUtils::AddFilter2(m_pGraph, CLSID_VideoInputDeviceCategory, pVideoName, &m_pVideoCapture);
+						if (SUCCEEDED(hr))
+						{
+							hr = CDSUtils::AddFilter2(m_pGraph, CLSID_AudioInputDeviceCategory, pAudioName, &m_pAudioCapture);
+							if (SUCCEEDED(hr))
+							{
+								PopulateVideoControl();	// populate the video format control with the video formats of the currently selected device
+								PopulateAudioControl();	// populate the audio format control with the audio formats of the currently selected device
+								PopulateCompressionControl();
+
+								// locate video screen renderer for the preview window
+								hr = CDSUtils::AddFilter(m_pGraph, CLSID_VideoRendererDefault, L"Video Renderer", &m_pVideoRenderer);
+								if (SUCCEEDED(hr))
+								{
+									hr = CreatePreviewGraph();
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return TRUE;  // return TRUE  unless you set the focus to a control
+}
+
+//-----------------------------------------------------------------------------
+// DestroyWindow
+// Called when the window is being destroyed, clean up and free all resources.
+BOOL CDecklinkCaptureDlg::DestroyWindow()
+{
+	m_regUtils.Close();
+#ifdef _DEBUG
+	CDSUtils::RemoveGraphFromRot(m_ROTRegister);
+#endif
+	DestroyGraph();
+
+	grabberCallback.m_GrabProc.Shutdown();
+
+	SAFE_RELEASE(m_pControl);
+
+	// Hide Video Window and remove owner. This has to be done prior to
+	// destroying any window that displays video/still.
+	if (m_pIVW)
+	{
+		m_pIVW->put_Visible(OAFALSE);
+		m_pIVW->put_Owner(NULL);
+	}
+
+	SAFE_RELEASE(m_pIVW);
+	SAFE_RELEASE(m_pMediaEvent);
+
+	grabberCallback.m_GrabProc.FreeFilter();
+	SAFE_RELEASE(m_pVideoRenderer);
+	SAFE_RELEASE(m_pAudioCapture);
+	SAFE_RELEASE(m_pVideoCapture);
+
+	SAFE_RELEASE(m_pGraph);
+
+	// free mediatypes attached to format controls
+	int count = m_videoFormatCtrl.GetCount();
+	for (int item=0; item<count; ++item)
+	{
+		DeleteMediaType((AM_MEDIA_TYPE*)m_videoFormatCtrl.GetItemData(item));
+	}
+
+	count = m_audioFormatCtrl.GetCount();
+	int item;
+	for (item=0; item<count; ++item)
+	{
+		DeleteMediaType((AM_MEDIA_TYPE*)m_audioFormatCtrl.GetItemData(item));
+	}
+
+	// release the device names attached to the item's data
+	count = m_videoDeviceCtrl.GetCount();
+	for (item=0; item<count; ++item)
+	{
+		PWSTR pName = (PWSTR)m_videoDeviceCtrl.GetItemData(item);
+		delete [] pName;
+	}
+
+	count = m_audioDeviceCtrl.GetCount();
+	for (item=0; item<count; ++item)
+	{
+		PWSTR pName = (PWSTR)m_audioDeviceCtrl.GetItemData(item);
+		delete [] pName;
+	}
+
+	return CDialog::DestroyWindow();
+}
+
+//-----------------------------------------------------------------------------
+// OnSysCommand
+//
+void CDecklinkCaptureDlg::OnSysCommand(UINT nID, LPARAM lParam)
+{
+	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
+	{
+		CAboutDlg dlgAbout;
+		dlgAbout.DoModal();
+	}
+	else
+	{
+		CDialog::OnSysCommand(nID, lParam);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnPaint
+// If you add a minimize button to your dialog, you will need the code below
+//  to draw the icon.  For MFC applications using the document/view model,
+//  this is automatically done for you by the framework.
+void CDecklinkCaptureDlg::OnPaint()
+{
+	if (IsIconic())
+	{
+		CPaintDC dc(this); // device context for painting
+
+		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
+
+		// Center icon in client rectangle
+		int cxIcon = GetSystemMetrics(SM_CXICON);
+		int cyIcon = GetSystemMetrics(SM_CYICON);
+		CRect rect;
+		GetClientRect(&rect);
+		int x = (rect.Width() - cxIcon + 1) / 2;
+		int y = (rect.Height() - cyIcon + 1) / 2;
+
+		// Draw the icon
+		dc.DrawIcon(x, y, m_hIcon);
+	}
+	else
+	{
+		CDialog::OnPaint();
+	}
+}
+
+//-----------------------------------------------------------------------------
+// HandleGraphEvent
+// At the moment we just read the event, discard it and release memory used to store it.
+void CDecklinkCaptureDlg::HandleGraphEvent(void)
+{
+	LONG lEventCode, lEventParam1, lEventParam2;
+
+	if (!m_pMediaEvent)
+	{
+		return;
+	}
+
+	while (SUCCEEDED(m_pMediaEvent->GetEvent(&lEventCode, reinterpret_cast<LONG_PTR *>(&lEventParam1), reinterpret_cast<LONG_PTR *>(&lEventParam2), 0)))
+	{
+		// just free memory associated with event
+		m_pMediaEvent->FreeEventParams(lEventCode, lEventParam1, lEventParam2);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// WindowProc
+// Have to add our own message handling loop to handle events from the preview video
+// window and to pass Window events onto it - this is so it redraws itself correctly etc.
+LRESULT CDecklinkCaptureDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+	switch (message)
+	{
+		case WM_GRAPHNOTIFY:
+			HandleGraphEvent();
+			break;
+	}
+
+	// Pass all msgs to video window. vid window exists as child of static
+	// picture frame. This ensures video window redraws itself etc.
+	if (m_pIVW)
+	{
+		m_pIVW->NotifyOwnerMessage(reinterpret_cast<LONG_PTR>(m_hWnd) /* from me */, message, wParam, lParam);
+	}
+
+	return CDialog::WindowProc(message, wParam, lParam);
+}
+
+//-----------------------------------------------------------------------------
+// OnQueryDragIcon
+// The system calls this function to obtain the cursor to display while the user drags
+//  the minimized window.
+HCURSOR CDecklinkCaptureDlg::OnQueryDragIcon()
+{
+	return static_cast<HCURSOR>(m_hIcon);
+}
+
+//-----------------------------------------------------------------------------
+// CreatePreviewGraph
+// Create a graph to preview the input
+// NOTE: There are many ways of building graphs, you could opt for the ICaptureGraphBuilder interface which would
+// make things are lot simpler, however it doesn't always build the most efficient graphs.
+HRESULT CDecklinkCaptureDlg::CreatePreviewGraph()
+{
+	HRESULT hr = S_OK;
+
+	if (m_pGraph)
+	{
+		// locate smart-T
+		// NOTE: The smart-T appears to hold references to its upstream connections even when its input pin
+		// is diconnected.  The smart-T has to be removed from the graph in order to clear these references which
+		// is why the filter is enumerated and added every time the preview graph is built and removed whenever
+		// it is destroyed.
+
+		if (SUCCEEDED(hr))
+		{
+			//SaveLog.ToLog("\n For uncompressed in Preview");
+
+			hr = CDSUtils::ConnectFilters(m_pGraph, m_pVideoCapture, NULL, m_pVideoRenderer, NULL);
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	if (SUCCEEDED(hr))
+	{
+		// the video path has been connected, initialise the preview window
+		InitialiseVideoPreview();
+
+		// optionally connect the audio path
+		if (FALSE == m_bAudioMute)
+		{
+			// connect the Decklink audio capture pin to the mux
+//hjhur			//hr = CDSUtils::RenderFilter(m_pGraph, m_pAudioCapture, L"Capture");
+		}
+
+		// run the graph so that we can preview the input video
+		if (m_pControl)
+		{
+			hr = m_pControl->Run();
+		}
+		else
+		{
+			hr = E_POINTER;
+		}
+	}
+
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(m_pGraph, L"Preview.GRF"));
+
+	return hr;
+}
+
+
+//-----------------------------------------------------------------------------
+// CreateCaptureGraph
+// Create a graph to capture the input
+HRESULT CDecklinkCaptureDlg::CreateCaptureGraph(bool sage)
+{
+	HRESULT hr = S_OK;
+
+	CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK_AUDIOMUTE);
+	if (pCheck)
+	{
+		m_bAudioMute = pCheck->GetState() & 0x0003;
+		grabberCallback.m_GrabProc.SetAudioOn(!m_bAudioMute);
+	}
+
+	if (m_pGraph)
+	{
+		// locate smart-T
+		// NOTE: The smart-T appears to hold references to its upstream connections even when its input pin
+		// is diconnected.  The smart-T has to be removed from the graph in order to clear these references which
+		// is why the filter is enumerated and added every time the preview graph is built and removed whenever
+		// it is destroyed.
+#ifdef _SMART_TREE_
+		if(m_pSmartT == NULL) {
+			//SaveLog.ToLog("\n Create Smart Tree");
+			hr = CDSUtils::AddFilter(m_pGraph, CLSID_SmartTee, L"Smart Tee", &m_pSmartT);
+		}
+#else
+		hr = 1;
+#endif
+		if (SUCCEEDED(hr))
+		{
+			//SaveLog.ToLog("\n For uncompressed in Capture");
+			// uncompressed, mpeg and wm preview
+			// create the following:
+			//
+			//  Decklink Video Capture -> Smart-T -> AVI Decompressor -> Video Renderer
+			//  Decklink Audio Capture -> Default Audio Renderer
+			//
+
+			// render the preview pin on the smart-T filter
+			// first connect the Decklink video capture pin to the smart-T
+#ifdef _SMART_TREE_
+			hr = CDSUtils::ConnectFilters(m_pGraph, m_pVideoCapture, NULL, m_pSmartT, NULL);
+			if(FAILED(hr)) {
+				//SaveLog.ToLog("\n Can not connect Smart filter to VideoCature");
+				return hr;
+			}
+#endif
+			if (SUCCEEDED(hr))
+			{
+#ifdef _SMART_TREE_
+				int color_mode = m_compressionCtrl.GetItemData(m_compressionCtrl.GetCurSel());
+				//SaveLog.ToLog("\n Color mode : "); 	SaveLog.ToLog(color_mode);
+				hr = grabberCallback.m_GrabProc.SetFilter(m_pGraph, m_pSmartT, L"Preview", color_mode, sage);
+
+				if(FAILED(hr)) {
+					//SaveLog.ToLog("\n Can not connect Grabber to Smart filter");
+					return hr;
+				}
+#else
+				int color_mode = m_compressionCtrl.GetItemData(m_compressionCtrl.GetCurSel();
+				hr = grabberCallback.m_GrabProc.SetFilter(m_pGraph, m_pVideoCapture, L"Capture", color_mode);
+#endif
+				// now connect the preview pin of the smart-T to the video renderer
+				hr = CDSUtils::ConnectFilters(m_pGraph, m_pSmartT, L"Capture", m_pVideoRenderer, NULL);
+				if(FAILED(hr)) {
+					//SaveLog.ToLog("\n Can not connect VideoRenderer to SmartT");
+					return hr;
+				}
+			}
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	if (SUCCEEDED(hr))
+	{
+		// the video path has been connected, initialise the preview window
+		InitialiseVideoPreview();
+		// optionally connect the audio path
+		if (FALSE == m_bAudioMute)
+		{
+
+			int streamID = m_sageStreamCtrl.GetCurSel();
+			if (streamID >= 0)
+			{
+				// connect the Decklink audio capture pin to the mux
+				//hr = CDSUtils::RenderFilter(m_pGraph, m_pAudioCapture, L"Capture");
+				int audioDevice = m_audioDeviceCtrl.GetCurSel();
+				if(audioDevice == 1) {	// from HD cam
+					//grabberCallback.m_GrabProc.SetAudioCaptureMode(false);
+					hr = grabberCallback.m_GrabProc.SetAudioFilter(m_pGraph, m_pAudioCapture, L"Capture");
+				} else {				// capture
+					grabberCallback.m_GrabProc.SetAudioCaptureMode(true);
+				}
+			}
+		}
+
+		// run the graph so that we can preview the input video
+		if (m_pControl)
+		{
+			hr = m_pControl->Run();
+		}
+		else
+		{
+			hr = E_POINTER;
+		}
+	}
+
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(m_pGraph, L"CreateCaptureGraph.GRF"));
+	return hr;
+}
+
+
+//-----------------------------------------------------------------------------
+// DestroyGraph
+// Remove all intermediate filters, keep any Decklink and video render filters as
+// these are used by all the graphs.
+HRESULT CDecklinkCaptureDlg::DestroyGraph(bool sage)
+{
+	HRESULT hr = S_OK;
+
+	if (m_pGraph && m_pControl)
+	{
+		m_pControl->Stop();
+
+		// release our outstanding reference on this filter so it can be removed from the graph
+#ifdef _SMART_TREE_
+		SAFE_RELEASE(m_pSmartT);
+#endif
+
+		// retrieve the name of the capture device, don't remove it in this method
+		PWSTR pNameVideoCapture = (PWSTR)m_videoDeviceCtrl.GetItemData(m_videoDeviceCtrl.GetCurSel());
+		PWSTR pNameAudioCapture = (PWSTR)m_audioDeviceCtrl.GetItemData(m_audioDeviceCtrl.GetCurSel());
+
+		CComPtr<IEnumFilters> pEnum = NULL;
+		hr = m_pGraph->EnumFilters(&pEnum);
+		if (SUCCEEDED(hr))
+		{
+			IBaseFilter* pFilter = NULL;
+			while (S_OK == pEnum->Next(1, &pFilter, NULL))
+			{
+				FILTER_INFO filterInfo = {0};
+				hr = pFilter->QueryFilterInfo(&filterInfo);
+				if (SUCCEEDED(hr))
+				{
+					SAFE_RELEASE(filterInfo.pGraph);
+
+					if ((NULL == wcsstr(filterInfo.achName, pNameVideoCapture)) && (NULL == wcsstr(filterInfo.achName, pNameAudioCapture)) && (NULL == wcsstr(filterInfo.achName, L"Video Renderer")))
+					{
+						hr = m_pGraph->RemoveFilter(pFilter);
+						if (SUCCEEDED(hr))
+						{
+							hr = pEnum->Reset();
+						}
+					}
+				}
+				SAFE_RELEASE(pFilter);
+			}
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// InitialiseVideoPreview
+// In short get the video screen renderer to draw into the picture control, which is our preview window
+// the following code sets this up, in addition to adding the HandleGraphEvent and WindowProc methods
+// read the DXSDK docos for more detailed information
+void CDecklinkCaptureDlg::InitialiseVideoPreview(void)
+{
+	// modify the preview window
+	if (m_pVideoRenderer)
+	{
+		if (NULL == m_pIVW)
+		{
+			if (SUCCEEDED(m_pVideoRenderer->QueryInterface(IID_IVideoWindow, reinterpret_cast<void**>(&m_pIVW))))
+			{
+				// get the window to handle redraws, etc
+				// Set msg drain of VideoWindow to point to our dialog window. The dialog's
+				// window procedure then handles events from the VideoWindow.
+				HRESULT hr = m_pIVW->put_MessageDrain(reinterpret_cast<OAHWND>(m_hWnd));
+
+				if (NULL == m_pMediaEvent)
+				{
+					// Make graph send WM_GRAPHNOTIFY when it wants our attention see "Learning
+					// When an Event Occurs" in the DX9 documentation.
+					hr = m_pGraph->QueryInterface(IID_IMediaEventEx, reinterpret_cast<void**>(&m_pMediaEvent));
+					if (SUCCEEDED(hr))
+					{
+						hr = m_pMediaEvent->SetNotifyWindow(reinterpret_cast<OAHWND>(m_hWnd), WM_GRAPHNOTIFY, 0);
+					}
+
+					// object created for it.
+					RECT rc;
+					m_preview.GetClientRect(&rc);
+					m_pIVW->SetWindowPosition(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
+
+					// VideoWindow is a child window of the bounding rect
+					hr = m_pIVW->put_WindowStyle(WS_CHILD);
+					hr = m_pIVW->put_Owner(reinterpret_cast<OAHWND>(m_preview.GetSafeHwnd()));
+					hr = m_pIVW->SetWindowForeground(0);
+				}
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// PopulateDeviceControl
+// Fill device combo box with available devices of the specified category
+HRESULT CDecklinkCaptureDlg::PopulateDeviceControl(const GUID* pCategory, CComboBox* pCtrl)
+{
+	HRESULT hr = S_OK;
+	if (pCategory && pCtrl)
+	{
+		// first enumerate the system devices for the specifed class and filter name
+		CComPtr<ICreateDevEnum> pSysDevEnum = NULL;
+		hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pSysDevEnum));
+
+		if (SUCCEEDED(hr))
+		{
+			CComPtr<IEnumMoniker> pEnumCat = NULL;
+			hr = pSysDevEnum->CreateClassEnumerator(*pCategory, &pEnumCat, 0);
+
+			if (S_OK == hr)
+			{
+				IMoniker* pMoniker = NULL;
+				bool Loop = true;
+				while ((S_OK == pEnumCat->Next(1, &pMoniker, NULL)) && Loop)
+				{
+					IPropertyBag* pPropBag = NULL;
+					hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, reinterpret_cast<void**>(&pPropBag));
+
+					if (SUCCEEDED(hr))
+					{
+						VARIANT varName;
+						VariantInit(&varName);
+						hr = pPropBag->Read(L"FriendlyName", &varName, 0);
+						if (SUCCEEDED(hr))
+						{
+							size_t len = wcslen(varName.bstrVal) + 1;
+							PWSTR pName = new WCHAR [len];
+							StringCchCopyW(pName, len, varName.bstrVal);
+							CW2AEX<> buf(varName.bstrVal);
+							pCtrl->SetItemData(pCtrl->AddString(buf), (DWORD)pName);
+						}
+
+						VariantClear(&varName);
+
+						// contained within a loop, decrement the reference count
+						SAFE_RELEASE(pPropBag);
+					}
+					SAFE_RELEASE(pMoniker);
+				}
+			}
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// PopulateVideoControl
+// Fill video format combo box with supported video formats using the IAMStreamConfig
+// interface.
+HRESULT CDecklinkCaptureDlg::PopulateVideoControl()
+{
+	HRESULT hr = S_OK;
+
+	if (m_pVideoCapture)
+	{
+		// free mediatypes attached to format controls
+		int count = m_videoFormatCtrl.GetCount();
+		if (count)
+		{
+			for (int item=0; item<count; ++item)
+			{
+				DeleteMediaType((AM_MEDIA_TYPE*)m_videoFormatCtrl.GetItemData(item));
+			}
+			m_videoFormatCtrl.ResetContent();
+		}
+
+		// locate the video capture pin and QI for stream control
+		CComPtr<IAMStreamConfig> pISC = NULL;
+		hr = CDSUtils::FindPinInterface(m_pVideoCapture, &MEDIATYPE_Video, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+	    if (SUCCEEDED(hr))
+	    {
+			// loop through all the capabilities (video formats) and populate the control
+			int count, size;
+			hr = pISC->GetNumberOfCapabilities(&count, &size);
+			if (SUCCEEDED(hr))
+			{
+				if (sizeof(VIDEO_STREAM_CONFIG_CAPS) == size)
+				{
+					AM_MEDIA_TYPE* pmt = NULL;
+					VIDEO_STREAM_CONFIG_CAPS vscc;
+					VIDEOINFOHEADER* pvih = NULL;
+
+					for (int index=0; index<count; ++index)
+					{
+						hr = pISC->GetStreamCaps(index, &pmt, reinterpret_cast<BYTE*>(&vscc));
+						if (SUCCEEDED(hr))
+						{
+							char buffer[128];
+							WORD PixelFormat;
+							float FrameRate;
+
+							ZeroMemory(buffer, sizeof(buffer));
+
+							pvih = (VIDEOINFOHEADER*)pmt->pbFormat;
+
+							char* pPixelFormatLUT[] = {"4:2:2", "4:4:4"};
+							if (pvih->bmiHeader.biBitCount == 16) PixelFormat = 8;
+							else if (pvih->bmiHeader.biBitCount == 20) PixelFormat = 10;
+							else PixelFormat = pvih->bmiHeader.biBitCount;
+
+							// provide a useful description of the formats
+							if (486 == pvih->bmiHeader.biHeight)
+							{
+								if (417083 == pvih->AvgTimePerFrame)
+								{
+									StringCbPrintfA(buffer, sizeof(buffer), "NTSC %d-bit %s (3:2 pulldown removal)", PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+								}
+								else
+								{
+									StringCbPrintfA(buffer, sizeof(buffer), "NTSC %d-bit %s", PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+								}
+							}
+							else if (576 == pvih->bmiHeader.biHeight)
+							{
+								StringCbPrintfA(buffer, sizeof(buffer), "PAL %d-bit %s", PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+							}
+							else
+							{
+								char* pFrameRateFormat[] = {"%.2f", "%.0f"};
+								FrameRate = (float)(long)UNITS / pvih->AvgTimePerFrame;
+
+								if ((720 == pvih->bmiHeader.biHeight) && (59.94 > FrameRate))
+								{
+									if ((FrameRate - (int)FrameRate) > 0.01)
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD720 %.2fp %d-bit %s (Overcranked 60p)", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+									else
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD720 %.0fp %d-bit %s (Overcranked 60p)", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+								}
+								else if ((720 == pvih->bmiHeader.biHeight) && (59.94 <= FrameRate))
+								{
+									if ((FrameRate - (int)FrameRate) > 0.01)
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD720 %.2fp %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+									else
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD720 %.0fp %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+								}
+								else if ((1080 == pvih->bmiHeader.biHeight) && (50.00 <= FrameRate))
+								{
+									if ((FrameRate - (int)FrameRate) > 0.01)
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD1080 %.2fi %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+									else
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD1080 %.0fi %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+								}
+								else
+								{
+									if ((FrameRate - (int)FrameRate) > 0.01)
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD1080 %.2fPsF %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+									else
+									{
+										StringCbPrintfA(buffer, sizeof(buffer), "HD1080 %.0fPsF %d-bit %s", FrameRate, PixelFormat, pPixelFormatLUT[(30 == PixelFormat)]);
+									}
+								}
+							}
+
+							// add the item description to combo box
+							int n = m_videoFormatCtrl.AddString(buffer);
+							// store media type pointer in item's data section
+							//m_videoFormatCtrl.SetItemData(n, (DWORD_PTR)pmt);
+							m_videoFormatCtrl.SetItemData(n, (DWORD_PTR)pmt);
+
+							// set default format
+							if ((pvih->AvgTimePerFrame == m_vihDefault.AvgTimePerFrame) &&
+								(pvih->bmiHeader.biWidth == m_vihDefault.bmiHeader.biWidth) &&
+								(pvih->bmiHeader.biHeight == m_vihDefault.bmiHeader.biHeight) &&
+								(pvih->bmiHeader.biBitCount == m_vihDefault.bmiHeader.biBitCount))
+							{
+								m_videoFormatCtrl.SetCurSel(n);
+								pISC->SetFormat(pmt);
+							}
+						}
+					}
+				}
+				else
+				{
+					m_videoFormatCtrl.AddString("ERROR: Unable to retrieve video formats");
+				}
+			}
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	// initial
+	m_videoFormatCtrl.SetCurSel(4);
+	OnCbnSelchangeComboVideoformats();
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// PopulateAudioControl
+// Fill audio format combo box with supported audio formats using the IAMStreamConfig
+// interface.
+HRESULT CDecklinkCaptureDlg::PopulateAudioControl()
+{
+	HRESULT hr = S_OK;
+
+	if (m_pAudioCapture)
+	{
+		// free mediatypes attached to format controls
+		int count = m_audioFormatCtrl.GetCount();
+		if (count)
+		{
+			for (int item=0; item<count; ++item)
+			{
+				DeleteMediaType((AM_MEDIA_TYPE*)m_audioFormatCtrl.GetItemData(item));
+			}
+			m_audioFormatCtrl.ResetContent();
+		}
+
+		// locate the audio capture pin and QI for stream control
+		CComPtr<IAMStreamConfig> pISC = NULL;
+		hr = CDSUtils::FindPinInterface(m_pAudioCapture, &MEDIATYPE_Audio, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+	    if (SUCCEEDED(hr))
+	    {
+			// loop through all the capabilities (audio formats) and populate the control
+			int count, size;
+			hr = pISC->GetNumberOfCapabilities(&count, &size);
+			if (SUCCEEDED(hr))
+			{
+				if (sizeof(AUDIO_STREAM_CONFIG_CAPS) == size)
+				{
+					AM_MEDIA_TYPE* pmt = NULL;
+					AUDIO_STREAM_CONFIG_CAPS ascc;
+					WAVEFORMATEX* pwfex = NULL;
+
+					for (int index=0; index<count; ++index)
+					{
+						hr = pISC->GetStreamCaps(index, &pmt, reinterpret_cast<BYTE*>(&ascc));
+						if (SUCCEEDED(hr))
+						{
+							char buffer[32];
+
+							ZeroMemory(buffer, sizeof(buffer));
+
+							pwfex = (WAVEFORMATEX*)pmt->pbFormat;
+
+							// provide a useful description of the formats
+							if (1 == pwfex->nChannels)
+							{
+								StringCbPrintfA(buffer, sizeof(buffer), "%d channel, %2.1fkHz, %d-bit", (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample);
+							}
+							else
+							{
+								StringCbPrintfA(buffer, sizeof(buffer), "%d channels, %2.1fkHz, %d-bit", (int)pwfex->nChannels, (float)pwfex->nSamplesPerSec / 1000, (int)pwfex->wBitsPerSample);
+							}
+
+							// add the item description to combo box
+							int n = m_audioFormatCtrl.AddString(buffer);
+							// store media type pointer in item's data section
+							m_audioFormatCtrl.SetItemData(n, (DWORD_PTR)pmt);
+
+							// set default format
+							if ((pwfex->wFormatTag == m_wfexDefault.wFormatTag) &&
+								(pwfex->nChannels == m_wfexDefault.nChannels) &&
+								(pwfex->nSamplesPerSec == m_wfexDefault.nSamplesPerSec) &&
+								(pwfex->nAvgBytesPerSec == m_wfexDefault.nAvgBytesPerSec))
+							{
+								m_audioFormatCtrl.SetCurSel(n);
+								pISC->SetFormat(pmt);
+							}
+						}
+					}
+				}
+				else
+				{
+					m_audioFormatCtrl.AddString("ERROR: Unable to retrieve audio formats");
+				}
+			}
+		}
+	}
+	else
+	{
+		hr = E_POINTER;
+	}
+
+	// initial
+	m_audioFormatCtrl.SetCurSel(1);
+	OnCbnSelchangeComboAudioformats();
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// PopulateCompressionControl
+// Fill compression control with a selection of video compressors, locate the
+// encoders and add them to the combo box if they exist.
+HRESULT CDecklinkCaptureDlg::PopulateCompressionControl()
+{
+	// Pixel format
+	int n = m_compressionCtrl.AddString("RGB24");
+	m_compressionCtrl.SetItemData(n, (DWORD_PTR)RGB24);
+
+	n = m_compressionCtrl.AddString("RGB16");
+	m_compressionCtrl.SetItemData(n, (DWORD_PTR)RGB16);
+
+	n = m_compressionCtrl.AddString("YUV");
+	m_compressionCtrl.SetItemData(n, (DWORD_PTR)YUV);
+
+	// Frame rate
+	n = m_framerateCtrl.AddString("10fps");
+	m_framerateCtrl.SetItemData(n, (DWORD_PTR)FR10);
+	n = m_framerateCtrl.AddString("15fps");
+	m_framerateCtrl.SetItemData(n, (DWORD_PTR)FR15);
+	n = m_framerateCtrl.AddString("20fps");
+	m_framerateCtrl.SetItemData(n, (DWORD_PTR)FR20);
+	n = m_framerateCtrl.AddString("25fps");
+	m_framerateCtrl.SetItemData(n, (DWORD_PTR)FR25);
+	n = m_framerateCtrl.AddString("30fps");
+	m_framerateCtrl.SetItemData(n, (DWORD_PTR)FR30);
+
+/*
+	// search for the DV encoder, MPEG encoder and WM encoder
+	IBaseFilter* pFilter = NULL;
+	HRESULT hr = CoCreateInstance(CLSID_DVVideoEnc, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter));
+	if (SUCCEEDED(hr))
+	{
+		n = m_compressionCtrl.SetCurSel(m_compressionCtrl.AddString("DV Video Encoder"));
+		m_compressionCtrl.SetItemData(n, (DWORD_PTR)ENC_DV);
+		SAFE_RELEASE(pFilter);
+	}
+
+	hr = CoCreateInstance(CLSID_WMAsfWriter, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter));
+	if (SUCCEEDED(hr))
+	{
+		n = m_compressionCtrl.SetCurSel(m_compressionCtrl.AddString("Windows Media Encoder"));
+		m_compressionCtrl.SetItemData(n, (DWORD_PTR)ENC_WM);
+		SAFE_RELEASE(pFilter);
+	}
+*/
+	// initial
+	m_compressor =2;
+	m_compressionCtrl.SetCurSel(m_compressor);
+	//OnCbnSelchangeComboCompression();
+
+	m_framerate = 2; // 20fps
+	m_framerateCtrl.SetCurSel(m_framerate);
+	FrameRate = FR20;
+
+	return S_OK;
+}
+
+//-----------------------------------------------------------------------------
+// OnCbnSelchangeComboVideodevice
+// Rebuild graph with selected capture device
+void CDecklinkCaptureDlg::OnCbnSelchangeComboVideodevice()
+{
+	SAFE_RELEASE(m_pVideoCapture);	// release our outstanding reference
+	// remove intermediate filters, since the device selection has changed the capture device will also be removed
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		// rebuild graph with new capture device selection
+		PWSTR pName = (PWSTR)m_videoDeviceCtrl.GetItemData(m_videoDeviceCtrl.GetCurSel());
+		if (pName)
+		{
+			hr = CDSUtils::AddFilter2(m_pGraph, CLSID_VideoInputDeviceCategory, pName, &m_pVideoCapture);
+			if (SUCCEEDED(hr))
+			{
+				// as the device has changed get the current operating format so that the control
+				// and display this as the current selection
+				CComPtr<IAMStreamConfig> pISC = NULL;
+				hr = CDSUtils::FindPinInterface(m_pVideoCapture, &MEDIATYPE_Video, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+				if (SUCCEEDED(hr))
+				{
+					// get the current format of the device to set the current selection of the control
+					AM_MEDIA_TYPE* pamt = NULL;
+					hr = pISC->GetFormat(&pamt);
+					if (SUCCEEDED(hr))
+					{
+						if (pamt->pbFormat)
+						{
+							m_vihDefault = *(VIDEOINFOHEADER*)pamt->pbFormat;
+						}
+						DeleteMediaType(pamt);
+					}
+				}
+
+				hr = PopulateVideoControl();	// repopulate the control with formats from the new device
+				if (SUCCEEDED(hr))
+				{
+					hr = CreatePreviewGraph();	// rebuild the graph with the new device
+				}
+			}
+		}
+		else
+		{
+			hr = E_POINTER;
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnCbnSelchangeComboAudiodevice
+// Rebuild graph with selected capture device
+void CDecklinkCaptureDlg::OnCbnSelchangeComboAudiodevice()
+{
+	SAFE_RELEASE(m_pAudioCapture);	// release our outstanding reference
+	// remove intermediate filters, since the device selection has changed the capture device will also be removed
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		PWSTR pName = (PWSTR)m_audioDeviceCtrl.GetItemData(m_audioDeviceCtrl.GetCurSel());
+		if (pName)
+		{
+			hr = CDSUtils::AddFilter2(m_pGraph, CLSID_AudioInputDeviceCategory, pName, &m_pAudioCapture);
+			if (SUCCEEDED(hr))
+			{
+				// as the device has changed get the current operating format so that the control
+				// and display this as the current selection
+				CComPtr<IAMStreamConfig> pISC = NULL;
+				hr = CDSUtils::FindPinInterface(m_pAudioCapture, &MEDIATYPE_Audio, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+				if (SUCCEEDED(hr))
+				{
+					// get the current format of the device to set the current selection of the control
+					AM_MEDIA_TYPE* pamt = NULL;
+					hr = pISC->GetFormat(&pamt);
+					if (SUCCEEDED(hr))
+					{
+						if (pamt->pbFormat)
+						{
+							m_wfexDefault = *(WAVEFORMATEX*)pamt->pbFormat;
+						}
+						DeleteMediaType(pamt);
+					}
+				}
+
+				hr = PopulateAudioControl();	// repopulate the control with formats from the new device
+				if (SUCCEEDED(hr))
+				{
+					hr = CreatePreviewGraph();	// rebuild the graph with the new device
+				}
+			}
+		}
+		else
+		{
+			hr = E_POINTER;
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnCbnSelchangeComboVideoformats
+// Rebuild preview graph if format selection changed
+void CDecklinkCaptureDlg::OnCbnSelchangeComboVideoformats()
+{
+	HRESULT hr = DestroyGraph();
+
+	if (SUCCEEDED(hr))
+	{
+		// locate the video capture pin and QI for stream control
+		CComPtr<IAMStreamConfig> pISC = NULL;
+		hr = CDSUtils::FindPinInterface(m_pVideoCapture, &MEDIATYPE_Video, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+	    if (SUCCEEDED(hr))
+	    {
+			// set the new media format
+			AM_MEDIA_TYPE* pmt = (AM_MEDIA_TYPE*)m_videoFormatCtrl.GetItemData(m_videoFormatCtrl.GetCurSel());
+			m_vihDefault = *(VIDEOINFOHEADER*)pmt->pbFormat;
+			ASSERT(sizeof(VIDEOINFOHEADER) <= pmt->cbFormat);
+			hr = pISC->SetFormat(pmt);
+			if (SUCCEEDED(hr))
+			{
+				// save the new format
+				//ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("VideoFormat", reinterpret_cast<const BYTE*>(&m_vihDefault), sizeof(m_vihDefault)));
+				m_regUtils.SetBinary("VideoFormat", reinterpret_cast<const BYTE*>(&m_vihDefault), sizeof(m_vihDefault));
+
+
+				// update compression control, we don't have an HD compression filter so disable compression for HD formats
+				if (576 < m_vihDefault.bmiHeader.biHeight)
+				{
+					m_compressor = 2;
+					m_compressionCtrl.SetCurSel(m_compressor);
+					// save the new state
+					//ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("VideoDecoder", reinterpret_cast<const BYTE*>(&m_compressor), sizeof(m_compressor)));
+					m_regUtils.SetBinary("VideoDecoder", reinterpret_cast<const BYTE*>(&m_compressor), sizeof(m_compressor));
+
+					m_bEnableCompressionCtrl = FALSE;
+				}
+				else
+				{
+					m_bEnableCompressionCtrl = TRUE;
+				}
+				EnableControls();
+
+				// rebuild the graph
+				hr = CreatePreviewGraph();
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnCbnSelchangeComboAudioformats
+// Rebuild preview graph if format selection changed
+void CDecklinkCaptureDlg::OnCbnSelchangeComboAudioformats()
+{
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		// locate the audio capture pin and QI for stream control
+		CComPtr<IAMStreamConfig> pISC = NULL;
+		hr = CDSUtils::FindPinInterface(m_pAudioCapture, &MEDIATYPE_Audio, PINDIR_OUTPUT, IID_IAMStreamConfig, reinterpret_cast<void**>(&pISC));
+	    if (SUCCEEDED(hr))
+	    {
+			// set the new media format
+			AM_MEDIA_TYPE* pmt = (AM_MEDIA_TYPE*)m_audioFormatCtrl.GetItemData(m_audioFormatCtrl.GetCurSel());
+			m_wfexDefault = *(WAVEFORMATEX*)pmt->pbFormat;
+			ASSERT(sizeof(WAVEFORMATEX) == pmt->cbFormat);
+			hr = pISC->SetFormat(pmt);
+			if (SUCCEEDED(hr))
+			{
+				// save the new format
+				//EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("AudioFormat", reinterpret_cast<const BYTE*>(&m_wfexDefault), sizeof(m_wfexDefault)));
+				m_regUtils.SetBinary("AudioFormat", reinterpret_cast<const BYTE*>(&m_wfexDefault), sizeof(m_wfexDefault));
+
+				// rebuild the graph
+				hr = CreatePreviewGraph();
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnCbnSelchangeComboCompression
+// Rebuild preview graph if compression selection changed
+void CDecklinkCaptureDlg::OnCbnSelchangeComboCompression()
+{
+/*
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		// save the new state
+		m_compressor = m_compressionCtrl.GetCurSel();
+		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("VideoDecoder", reinterpret_cast<const BYTE*>(&m_compressor), sizeof(m_compressor)));
+		// rebuild the graph
+		hr = CreatePreviewGraph();
+	}
+*/
+}
+
+//-----------------------------------------------------------------------------
+// OnBnClickedCheckAudiomute
+// Rebuild the capture graph to reflect the new audio setting
+void CDecklinkCaptureDlg::OnBnClickedCheckAudiomute()
+{
+	CButton* pCheck = (CButton*)GetDlgItem(IDC_CHECK_AUDIOMUTE);
+	if (pCheck)
+	{
+		m_bAudioMute = pCheck->GetState() & 0x0003;
+// hjhur
+		grabberCallback.m_GrabProc.SetAudioOn(!m_bAudioMute);
+
+		HRESULT hr = DestroyGraph();
+		if (SUCCEEDED(hr))
+		{
+			// save the new state
+			//EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("AudioMute", reinterpret_cast<const BYTE*>(&m_bAudioMute), sizeof(m_bAudioMute)));
+
+			m_regUtils.SetBinary("AudioMute", reinterpret_cast<const BYTE*>(&m_bAudioMute), sizeof(m_bAudioMute));
+
+			// rebuild the graph which reflects the new audio setting
+			hr = CreatePreviewGraph();
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnBnClickedButtonBrowse
+// Create a file open dialog to browse for a file location
+void CDecklinkCaptureDlg::OnBnClickedButtonBrowse()
+{
+	char BASED_CODE szFilters[] = "Windows Media Files|*.avi;*.asf;*.wmv|All Files (*.*)|*.*||";
+
+	char* pExt[] = {"*.avi", "*.avi", "*.asf;*.wmv"};
+
+	CFileDialog FileDlg(TRUE, "Windows Media Files", pExt[m_compressor], 0, szFilters, this);
+
+	if (FileDlg.DoModal() == IDOK)
+	{
+		m_captureFile = FileDlg.GetPathName();
+		m_captureFileCtrl.SetWindowText(m_captureFile);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// OnBnClickedButtonCapture
+// Create a capture graph a start capture
+void CDecklinkCaptureDlg::OnBnClickedButtonCapture()
+{
+	DisableControls();
+
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreateCaptureGraph();
+		if (SUCCEEDED(hr))
+		{
+			DisableControls();
+			return;
+		}
+	}
+
+	hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreatePreviewGraph();
+		if (SUCCEEDED(hr))
+		{
+			EnableControls();
+		}
+	}
+
+	exit(1);
+	return;
+}
+
+//-----------------------------------------------------------------------------
+// OnBnClickedButtonStop
+// Stop capture and revert to preview
+void CDecklinkCaptureDlg::OnBnClickedButtonStop()
+{
+	HRESULT hr = DestroyGraph();
+	grabberCallback.m_GrabProc.Shutdown();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreatePreviewGraph();
+		if (SUCCEEDED(hr))
+		{
+			EnableControls();
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// EnableControls
+//
+void CDecklinkCaptureDlg::EnableControls(void)
+{
+	CWnd* pWnd = GetDlgItem(IDC_COMBO_VIDEODEVICE);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_COMBO_VIDEOFORMATS);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_COMBO_AUDIODEVICE);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_COMBO_AUDIOFORMATS);
+	//pWnd->EnableWindow(TRUE);
+	pWnd->EnableWindow(FALSE);
+
+	pWnd = GetDlgItem(IDC_CHECK_AUDIOMUTE);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_COMBO_COMPRESSION);
+	pWnd->EnableWindow(TRUE);
+//	m_bEnableCompressionCtrl = (576 < m_vihDefault.bmiHeader.biHeight) ? FALSE : TRUE;	// don't have an HDV codec do disable compression control for HD formats
+//	pWnd->EnableWindow(m_bEnableCompressionCtrl);
+	pWnd = GetDlgItem(IDC_EDIT_CAPTUREFILE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_BROWSE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_CAPTURE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_STOP);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_SAGE_ADDR);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_SAGE_START);
+	pWnd->EnableWindow(TRUE);
+	pWnd = GetDlgItem(IDC_SAGE_STOP);
+	pWnd->EnableWindow(FALSE);
+}
+
+//-----------------------------------------------------------------------------
+// DisableControls
+//
+void CDecklinkCaptureDlg::DisableControls(void)
+{
+	CWnd* pWnd = GetDlgItem(IDC_COMBO_VIDEODEVICE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_COMBO_VIDEOFORMATS);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_COMBO_AUDIODEVICE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_COMBO_AUDIOFORMATS);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_CHECK_AUDIOMUTE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_COMBO_COMPRESSION);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_EDIT_CAPTUREFILE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_BROWSE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_CAPTURE);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_BUTTON_STOP);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_SAGE_ADDR);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_SAGE_START);
+	pWnd->EnableWindow(FALSE);
+	pWnd = GetDlgItem(IDC_SAGE_STOP);
+	pWnd->EnableWindow(TRUE);
+}
+
+//-----------------------------------------------------------------------------
+// QueryRegistry
+// retrieve previous media formats from registry
+void CDecklinkCaptureDlg::QueryRegistry(void)
+{
+	if (ERROR_SUCCESS == m_regUtils.Open("DecklinkCaptureSample"))
+	{
+		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.GetBinary("VideoFormat", reinterpret_cast<LPBYTE>(&m_vihDefault), sizeof(m_vihDefault)));
+		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.GetBinary("AudioFormat", reinterpret_cast<LPBYTE>(&m_wfexDefault), sizeof(m_wfexDefault)));
+		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.GetBinary("AudioMute", reinterpret_cast<LPBYTE>(&m_bAudioMute), sizeof(m_bAudioMute)));
+		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.GetBinary("VideoDecoder", reinterpret_cast<LPBYTE>(&m_compressor), sizeof(m_compressor)));
+
+		WCHAR captureFile[MAX_PATH];
+		ZeroMemory(captureFile, sizeof(captureFile));
+//		EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.GetString("CaptureFile", reinterpret_cast<LPBYTE>(captureFile), sizeof(captureFile)));
+		m_captureFile = captureFile;
+	}
+	else
+	{
+		// create the key and registry values
+		if (ERROR_SUCCESS == m_regUtils.Create("DecklinkCaptureSample"))
+		{
+			EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("VideoFormat", reinterpret_cast<const BYTE*>(&m_vihDefault), sizeof(m_vihDefault)));
+			EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("AudioFormat", reinterpret_cast<const BYTE*>(&m_wfexDefault), sizeof(m_wfexDefault)));
+			EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("AudioMute", reinterpret_cast<const BYTE*>(&m_bAudioMute), sizeof(m_bAudioMute)));
+			EXECUTE_ASSERT(ERROR_SUCCESS == m_regUtils.SetBinary("VideoDecoder", reinterpret_cast<const BYTE*>(&m_compressor), sizeof(m_compressor)));
+		}
+	}
+
+	// update mute audio check box control
+	CButton* pButton = (CButton*)GetDlgItem(IDC_CHECK_AUDIOMUTE);
+	pButton->SetCheck(m_bAudioMute);
+}
+
+
+void CDecklinkCaptureDlg::OnBnClickedButtonCodecproperties()
+{
+	// TODO: Add your control notification handler code here
+}
+
+void CDecklinkCaptureDlg::OnBnClickedSageStart()
+{
+	int index = m_sageStreamCtrl.GetCurSel();
+	//ChangeMasterIP(index);
+	CString iptxt;
+	m_sageIPCtrl.GetWindowTextA(iptxt);
+	grabberCallback.m_GrabProc.setIP(iptxt);
+
+	// TODO: Add your control notification handler code here
+	DisableControls();
+
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreateCaptureGraph();
+		if (SUCCEEDED(hr))
+		{
+			DisableControls();
+			return;
+		}
+	}
+
+	hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreatePreviewGraph();
+		if (SUCCEEDED(hr))
+		{
+			EnableControls();
+		}
+	}
+
+	exit(1);
+	return;
+}
+
+void CDecklinkCaptureDlg::OnBnClickedSageStop()
+{
+	// TODO: Add your control notification handler code here
+	HRESULT hr = DestroyGraph();
+	if (SUCCEEDED(hr))
+	{
+		hr = CreatePreviewGraph();
+		if (SUCCEEDED(hr))
+		{
+			EnableControls();
+		}
+	}
+	grabberCallback.m_GrabProc.Shutdown();
+
+	exit(1);
+}
+
+void CDecklinkCaptureDlg::OnCbnSelchangeSageAddr()
+{
+	// TODO: Add your control notification handler code here
+	int index = m_sageStreamCtrl.GetCurSel();
+
+	CString iptxt;
+	m_sageStreamCtrl.GetWindowTextA(iptxt);
+
+	m_sageIPCtrl.SetWindowText(iptxt);
+
+	/*
+	switch (index)
+	{
+	case 0:
+		m_sageIPCtrl.SetWindowText("67.58.62.100");
+		break;
+	case 1:
+		m_sageIPCtrl.SetWindowText("67.58.62.21");
+		break;
+	case 2:
+		m_sageIPCtrl.SetWindowText("67.58.62.23");
+		break;
+	}
+	*/
+	//ChangeMasterIP(index);
+}
+
+void CDecklinkCaptureDlg::OnEnChangeSageEditIp()
+{
+	// TODO:  If this is a RICHEDIT control, the control will not
+	// send this notification unless you override the CDialog::OnInitDialog()
+	// function and call CRichEditCtrl().SetEventMask()
+	// with the ENM_CHANGE flag ORed into the mask.
+
+	// TODO:  Add your control notification handler code here
+}
+
+int CDecklinkCaptureDlg::ChangeMasterIP(int index)
+{
+	char fileName[100];
+	memset(fileName,' ', 100);
+	char *sageDir = getenv("SAGE_DIRECTORY");
+	sprintf(fileName, "%s/bin/fsManager.conf", sageDir);
+
+	FILE *fp = fopen(fileName, "w+");
+
+	if (!fp) {
+		printf("fail to open fsClient config file\n");
+		return -1;
+	}
+
+	CString iptxt;
+	m_sageIPCtrl.GetWindowTextA(iptxt);
+	if(iptxt == "") return -1;
+	char sip[25];
+	sprintf(sip, "%s", iptxt.GetBuffer());
+
+	switch (index)
+	{
+	case 0:
+		fprintf(fp, "fsManager global %s\nsystemPort 20002\n",sip);
+		break;
+	case 1:
+		fprintf(fp, "fsManager global %s\nsystemPort 20002\n",sip);
+		break;
+	case 2:
+		fprintf(fp, "fsManager global %s\nsystemPort 20002\n",sip);
+		break;
+	}
+
+	fprintf(fp, "receiverBufSize    100\n");
+	fprintf(fp, "rcvNwBufSize 16777216\n");
+	fprintf(fp, "sendNwBufSize 1048576\n");
+	fprintf(fp, "MTU 8800\n");
+
+	fclose(fp);
+	return 1;
+}
+void CDecklinkCaptureDlg::OnBnClickedSageReg()
+{
+	char fileName[100];
+	memset(fileName,' ', 100);
+	char *sageDir = getenv("SAGE_DIRECTORY");
+	sprintf(fileName, "%s/bin/ips.sys", sageDir);
+
+	FILE *fp = fopen(fileName, "a+");
+
+	if (!fp) {
+		printf("fail to open fsClient config file\n");
+		return;
+	}
+
+	fseek(fp, 0, SEEK_END);
+	CString ip;
+	m_sageIPCtrl.GetWindowTextA(ip);
+
+	fprintf(fp, "\n%s",ip.GetBuffer());
+
+	char sip[255];
+	memset(sip, 0, 255);
+	sprintf(sip, "%s", ip.GetBuffer());
+
+	int index = m_sageStreamCtrl.GetCount();
+	m_sageStreamCtrl.InsertString(index, sip);
+
+	fclose(fp);
+}
+
+
+int CDecklinkCaptureDlg::LoadIpInfo()
+{
+	char fileName[100];
+	memset(fileName,' ', 100);
+	char *sageDir = getenv("SAGE_DIRECTORY");
+	sprintf(fileName, "%s/bin/ips.sys", sageDir);
+	//sprintf(fileName, "C:/sources/bijeong/bin/ips.sys");
+
+	FILE *fp = fopen(fileName, "r+");
+
+	if (!fp) {
+		printf("fail to open fsClient config file\n");
+		return -1;
+	}
+
+	char sip[255];
+	memset(sip, 0, 255);
+	int index =0;
+
+	do {
+		fscanf(fp, "%s", &sip);
+		if(strlen(sip) > 0) {
+			if(index == 0) {
+				m_sageIPCtrl.SetWindowText(sip);
+			}
+			m_sageStreamCtrl.InsertString(index, sip);
+			index++;
+		}
+	} while (!feof(fp));
+
+	fclose(fp);
+
+	m_sageStreamCtrl.SetCurSel(0);
+	return 1;
+}
+void CDecklinkCaptureDlg::OnCbnSelchangeComboCompression2()
+{
+	// Framerate changed
+	DWORD_PTR val = (DWORD_PTR)m_framerateCtrl.GetItemData(m_framerateCtrl.GetCurSel());
+	FrameRate = val;
+}
Index: trunk/src/testing/app/hd-video-player/Utils.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/Utils.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/Utils.cpp	(revision 4)
@@ -0,0 +1,858 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//------------------------------------------------------------------------------------
+// $Id: Utils.cpp,v 1.10 2006/04/11 01:13:06 ivanr Exp $
+//
+// Desc: DirectShow utility class implementation
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//------------------------------------------------------------------------------------
+
+#include "stdafx.h"
+#include "Utils.h"
+
+//-----------------------------------------------------------------------------
+// CDSUtils - Directshow utility class
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// AddFilter
+// Attempts to locate a filter of a given class ID and name	and add it to the graph
+// If your DirectShow application supports playback of DRM-protected files,
+// then you generally should not use RenderFile to create the filter graph
+// because there is no way to specify which DRM rights you are requesting before the file is opened.
+// The WM ASF Reader by default asks for only playback rights.
+// The filter is not added to the graph, and is therefore not discoverable by applications, until a file is successfully opened.
+HRESULT CDSUtils::AddFilter(IGraphBuilder* pGraph, const GUID &clsid, LPCWSTR pName, IBaseFilter** ppFilter)
+{
+	HRESULT hr = S_OK;
+
+	if (pGraph && pName && ppFilter)
+	{
+		*ppFilter = NULL;
+		IBaseFilter* pFilter = NULL;
+		hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter));
+		if (SUCCEEDED(hr))
+		{
+			hr = pGraph->AddFilter(pFilter, pName);
+			if (SUCCEEDED(hr))
+			{
+				*ppFilter = pFilter;
+			}
+			else
+			{
+				SAFE_RELEASE(pFilter);
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// AddFilter2
+// Attempts to locate a filter of a given class category and name
+HRESULT CDSUtils::AddFilter2(IGraphBuilder* pGraph, const GUID &clsid, LPCWSTR pName, IBaseFilter** ppFilter)
+{
+	HRESULT hr = S_OK;
+
+	if (pGraph && pName && ppFilter)
+	{
+		// first enumerate the system devices for the specifed class and filter name
+		CComPtr<ICreateDevEnum> pSysDevEnum = NULL;
+		hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pSysDevEnum));
+
+		if (SUCCEEDED(hr))
+		{
+			CComPtr<IEnumMoniker> pEnumCat = NULL;
+			hr = pSysDevEnum->CreateClassEnumerator(clsid, &pEnumCat, 0);
+
+			if (S_OK == hr)
+			{
+				IMoniker* pMoniker = NULL;
+				bool Loop = true;
+				while ((S_OK == pEnumCat->Next(1, &pMoniker, NULL)) && Loop)
+				{
+					IPropertyBag* pPropBag = NULL;
+					hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, reinterpret_cast<void**>(&pPropBag));
+
+					if (SUCCEEDED(hr))
+					{
+						VARIANT varName;
+						VariantInit(&varName);
+						hr = pPropBag->Read(L"FriendlyName", &varName, 0);
+						if (SUCCEEDED(hr))
+						{
+							if (0 == wcscmp(varName.bstrVal, pName))
+							{
+								hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, reinterpret_cast<void**>(ppFilter));
+								Loop = false;
+							}
+						}
+
+						VariantClear(&varName);
+
+						// contained within a loop, decrement the reference count
+						SAFE_RELEASE(pPropBag);
+					}
+					SAFE_RELEASE(pMoniker);
+				}
+			}
+		}
+
+		// if a filter has been located add it to the graph
+		if (*ppFilter)
+		{
+			hr = pGraph->AddFilter(reinterpret_cast<IBaseFilter*>(*ppFilter), pName);
+		}
+		else
+		{
+			hr = E_FAIL;
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-------------------------------------------------------------------------------------------------
+// GetUnconnectedPin
+// Attemptes to locate an unconnected pin on filter
+HRESULT CDSUtils::GetUnconnectedPin(IBaseFilter* pFilter, PIN_DIRECTION PinDir, IPin** ppPin)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && ppPin)
+	{
+		CComPtr<IEnumPins> pEnum = NULL;
+		IPin* pPin = NULL;
+
+		hr = pFilter->EnumPins(&pEnum);
+		if (SUCCEEDED(hr))
+		{
+			while (pEnum->Next(1, &pPin, NULL) == S_OK)
+			{
+				PIN_DIRECTION ThisPinDir;
+				pPin->QueryDirection(&ThisPinDir);
+				if (ThisPinDir == PinDir)
+				{
+					IPin* pPinTemp = NULL;
+
+					hr = pPin->ConnectedTo(&pPinTemp);
+					if (SUCCEEDED(hr))
+					{
+						SAFE_RELEASE(pPinTemp);
+					}
+					else
+					{
+						// unconnected, return this pin
+						*ppPin = pPin;
+						hr = S_OK;
+						break;
+					}
+				}
+				SAFE_RELEASE(pPin);
+			}
+		}
+
+		if (NULL == *ppPin)
+		{
+			// failed to find an unconnected pin
+			hr = E_FAIL;
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// GetPin
+// Find the pin of the specified name on the given filter
+// This method leaves an outstanding reference on the pin if successful
+HRESULT CDSUtils::GetPin(IBaseFilter* pFilter, const wchar_t* pName, IPin** ppPin)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && pName && ppPin)
+	{
+		CComPtr<IEnumPins> pIEnumPins = NULL;
+		hr = pFilter->EnumPins(&pIEnumPins);
+		if (SUCCEEDED(hr))
+		{
+			IPin* pIPin = NULL;
+			while (S_OK == pIEnumPins->Next(1, &pIPin, NULL))
+			{
+				PIN_INFO info = {0};
+				hr = pIPin->QueryPinInfo(&info);
+				if (SUCCEEDED(hr))
+				{
+					SAFE_RELEASE(info.pFilter);
+
+					if (0 == wcsncmp(info.achName, pName, wcslen(pName)))
+					{
+						// matched the pin category
+						*ppPin = pIPin;
+						break;
+					}
+				}
+				SAFE_RELEASE(pIPin);
+			}
+		}
+
+		if (NULL == *ppPin)
+		{
+			// failed to find the named pin
+			hr = E_FAIL;
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// GetPin
+// Find the pin of the specified format type on the given filter
+// This method leaves an outstanding reference on the pin if successful
+HRESULT CDSUtils::GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && pFormat && ppPin)
+	{
+		CComPtr<IEnumPins> pIEnumPins = NULL;
+		hr = pFilter->EnumPins(&pIEnumPins);
+		if (SUCCEEDED(hr))
+		{
+			// find the pin with the specified format
+			IPin* pIPin = NULL;
+			while (S_OK == pIEnumPins->Next(1, &pIPin, NULL))
+			{
+				// match the pin direction
+				PIN_DIRECTION pinDir;
+				pIPin->QueryDirection(&pinDir);
+				if (pinDir == PinDir)
+				{
+					// match pin direction check the first media type returned from the upstream pin
+					CComPtr<IEnumMediaTypes> pIEnumMT = NULL;
+					hr = pIPin->EnumMediaTypes(&pIEnumMT);
+					if (SUCCEEDED(hr))
+					{
+						AM_MEDIA_TYPE* pmt = NULL;
+						hr = pIEnumMT->Next(1, &pmt, NULL);
+						if (S_OK == hr)
+						{
+							if (pmt->majortype == *pFormat)
+							{
+								// found the pin with the specified format
+								*ppPin = pIPin;
+								DeleteMediaType(pmt);
+								break;
+							}
+							else
+							{
+								DeleteMediaType(pmt);
+							}
+						}
+					}
+				}
+				SAFE_RELEASE(pIPin);
+			}
+
+			if (NULL == *ppPin)
+			{
+				// failed to find the named pin
+				hr = E_FAIL;
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// ConnectFiltersNamedPin
+// Connects two filters using the pin names, if no name is supplied the first
+// unconnected pin is used
+HRESULT CDSUtils::ConnectFilters(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName, IBaseFilter* pDownstream, wchar_t* pDownstreamPinName)
+{
+	HRESULT hr = S_OK;
+
+	if (pUpstream && pDownstream)
+	{
+		// get the upstream output pin
+		CComPtr<IPin> pIPinOutput = NULL;
+		if (pUpstreamPinName)
+		{
+			hr = GetPin(pUpstream, pUpstreamPinName, &pIPinOutput);
+		}
+		else
+		{
+			hr = GetUnconnectedPin(pUpstream, PINDIR_OUTPUT, &pIPinOutput);
+		}
+
+		if (SUCCEEDED(hr))
+		{
+			// get the downstream input pin
+			CComPtr<IPin> pIPinInput = NULL;
+			if (pDownstreamPinName)
+			{
+				hr = GetPin(pDownstream, pDownstreamPinName, &pIPinInput);
+			}
+			else
+			{
+				hr = GetUnconnectedPin(pDownstream, PINDIR_INPUT, &pIPinInput);
+			}
+
+			if (SUCCEEDED(hr))
+			{
+				// connect the pins
+				hr = pGraph->Connect(pIPinOutput, pIPinInput);
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// ConnectFilters
+// Connects two filters by finding a pin on the upstream filter with the specified
+// major format type, e.g. For connecting an audio pin to a downstream filter
+HRESULT CDSUtils::ConnectFilters(IGraphBuilder* pGraph, IBaseFilter* pUpstream, IBaseFilter* pDownstream, const GUID* pFormat)
+{
+	HRESULT hr = S_OK;
+
+	if (pUpstream && pDownstream && pFormat)
+	{
+		// find the upstream output pin with the specified format
+		CComPtr<IPin> pIPinOutput = NULL;
+		hr = GetPin(pUpstream, pFormat, PINDIR_OUTPUT, &pIPinOutput);
+		if (SUCCEEDED(hr))
+		{
+			// get the downstream input pin
+			CComPtr<IPin> pIPinInput = NULL;
+			hr = GetPin(pDownstream, pFormat, PINDIR_INPUT, &pIPinInput);
+
+			if (SUCCEEDED(hr))
+			{
+				// connect the pins
+				hr = pGraph->Connect(pIPinOutput, pIPinInput);
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// RenderFilter
+// Renders the named output pin of the filter, or the first unconnected output if
+// no name is provided
+HRESULT CDSUtils::RenderFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName)
+{
+	HRESULT hr = S_OK;
+
+	if (pUpstream)
+	{
+		CComPtr<IPin> pIPinOutput = NULL;
+		if (pUpstreamPinName)
+		{
+			hr = GetPin(pUpstream, pUpstreamPinName, &pIPinOutput);
+		}
+		else
+		{
+			hr = GetUnconnectedPin(pUpstream, PINDIR_OUTPUT, &pIPinOutput);
+		}
+
+		if (SUCCEEDED(hr))
+		{
+			hr = pGraph->Render(pIPinOutput);
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// DisconnectAllPins
+// Disconnect all the pins of the filters in a graph
+HRESULT CDSUtils::DisconnectAllPins(IGraphBuilder* pGraph)
+{
+	HRESULT hr = S_OK;
+
+	if (pGraph)
+	{
+		CComPtr<IEnumFilters> pIEnumFilters = NULL;
+		hr = pGraph->EnumFilters(&pIEnumFilters);
+		if (SUCCEEDED(hr))
+		{
+			IBaseFilter* pFilter = NULL;
+			while (S_OK == pIEnumFilters->Next(1, &pFilter, NULL))
+			{
+				CComPtr<IEnumPins> pIEnumPins = NULL;
+				hr = pFilter->EnumPins(&pIEnumPins);
+				if (SUCCEEDED(hr))
+				{
+					IPin* pIPin = NULL;
+					while (S_OK == pIEnumPins->Next(1, &pIPin, NULL))
+					{
+						IPin* pIPinConnection = NULL;
+						if (S_OK == pIPin->ConnectedTo(&pIPinConnection))
+						{
+							// pins are connected, to disconnect filters, both pins must be disconnected
+							hr = pGraph->Disconnect(pIPin);
+							hr = pGraph->Disconnect(pIPinConnection);
+							SAFE_RELEASE(pIPinConnection);
+						}
+						SAFE_RELEASE(pIPin);
+					}
+				}
+				SAFE_RELEASE(pFilter);
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// FindFilterInterface
+// Attempt to locate the specified interface
+HRESULT CDSUtils::FindFilterInterface(IBaseFilter* pFilter, const IID& riid, void** ppvInterface)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && ppvInterface)
+	{
+		hr = pFilter->QueryInterface(riid, ppvInterface);
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// FindPinInterface
+// Attempt to locate the interface on the named pin or on the first pin if no
+// name is provided.
+HRESULT CDSUtils::FindPinInterface(IBaseFilter* pFilter, wchar_t* pName, const IID& riid, void** ppvInterface)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && ppvInterface)
+	{
+		CComPtr<IPin> pIPin = NULL;
+		if (pName)
+		{
+			hr = GetPin(pFilter, pName, &pIPin);
+		}
+		else
+		{
+			CComPtr<IEnumPins> pIEnumPins = NULL;
+			hr = pFilter->EnumPins(&pIEnumPins);
+			if (SUCCEEDED(hr))
+			{
+				hr = pIEnumPins->Next(1, &pIPin, NULL);
+			}
+		}
+
+		if (SUCCEEDED(hr))
+		{
+			hr = pIPin->QueryInterface(riid, ppvInterface);
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// FindPinInterface
+// Attempt to locate the interface on the pin with the specified format or on the first pin if no
+// format is provided.
+HRESULT CDSUtils::FindPinInterface(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, const IID& riid, void** ppvInterface)
+{
+	HRESULT hr = S_OK;
+
+	if (pFilter && ppvInterface)
+	{
+		CComPtr<IPin> pIPin = NULL;
+		if (pFormat)
+		{
+			hr = GetPin(pFilter, pFormat, PinDir, &pIPin);
+		}
+		else
+		{
+			CComPtr<IEnumPins> pIEnumPins = NULL;
+			hr = pFilter->EnumPins(&pIEnumPins);
+			if (SUCCEEDED(hr))
+			{
+				hr = pIEnumPins->Next(1, &pIPin, NULL);
+			}
+		}
+
+		if (SUCCEEDED(hr))
+		{
+			hr = pIPin->QueryInterface(riid, ppvInterface);
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+	return hr;
+}
+
+//-----------------------------------------------------------------------------
+// AddGraphToRot
+// Adds a DirectShow filter graph to the Running Object Table,
+// allowing GraphEdit to "spy" on a remote filter graph.
+HRESULT CDSUtils::AddGraphToRot(IUnknown* pUnkGraph, DWORD* pdwRegister)
+{
+    HRESULT hr = S_OK;
+
+    if (pUnkGraph && pdwRegister)
+	{
+		CComPtr<IRunningObjectTable> pROT = NULL;
+		hr = GetRunningObjectTable(0, &pROT);
+		if (SUCCEEDED(hr))
+		{
+			WCHAR wsz[128];
+			StringCchPrintfW(wsz, 128, L"FilterGraph %08x pid %08x\0", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
+
+			CComPtr<IMoniker> pMoniker = NULL;
+			hr = CreateItemMoniker(L"!", wsz, &pMoniker);
+			if(SUCCEEDED(hr))
+			{
+				// Use the ROTFLAGS_REGISTRATIONKEEPSALIVE to ensure a strong reference
+				// to the object.  Using this flag will cause the object to remain
+				// registered until it is explicitly revoked with the Revoke() method.
+				//
+				// Not using this flag means that if GraphEdit remotely connects
+				// to this graph and then GraphEdit exits, this object registration
+				// will be deleted, causing future attempts by GraphEdit to fail until
+				// this application is restarted or until the graph is registered again.
+				hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
+			}
+		}
+	}
+	else
+	{
+		hr = E_INVALIDARG;
+	}
+
+    return hr;
+}
+
+//-----------------------------------------------------------------------------
+// RemoveGraphFromRot
+// Removes a filter graph from the Running Object Table
+void CDSUtils::RemoveGraphFromRot(DWORD pdwRegister)
+{
+    CComPtr<IRunningObjectTable> pROT = NULL;
+
+    if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
+    {
+        pROT->Revoke(pdwRegister);
+    }
+}
+
+//------------------------------------------------------------------------------------
+// CRegUtils - Registry utility class
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+// Constructor
+//
+CRegUtils::CRegUtils()
+	: m_hKey(NULL)
+{
+}
+
+//------------------------------------------------------------------------------------
+// Destructor
+//
+CRegUtils::~CRegUtils()
+{
+	Close();
+}
+
+//------------------------------------------------------------------------------------
+// Open
+// Opens the specified subkey
+LONG CRegUtils::Open(LPCTSTR lpSubKey)
+{
+	Close();
+	m_subKeyName = "Software\\Blackmagic Design\\Samples\\";
+	m_subKeyName += lpSubKey;
+	return RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_subKeyName.c_str(), 0, KEY_ALL_ACCESS, &m_hKey);
+}
+
+//------------------------------------------------------------------------------------
+// Create
+// Creates the specified subkey
+LONG CRegUtils::Create(LPCTSTR lpSubKey)
+{
+	Close();
+	m_subKeyName = "Software\\Blackmagic Design\\Samples\\";
+	m_subKeyName += lpSubKey;
+	return RegCreateKeyEx(HKEY_LOCAL_MACHINE, m_subKeyName.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hKey, NULL);
+}
+
+//------------------------------------------------------------------------------------
+// Close
+// Closes the subkey
+void CRegUtils::Close()
+{
+	RegCloseKey(m_hKey);
+	m_hKey = NULL;
+	m_subKeyName.empty();
+}
+
+//------------------------------------------------------------------------------------
+// SetString
+// Set the key for the named value of type string
+LONG CRegUtils::SetString(LPCTSTR valueName, const BYTE* lpData, DWORD cbData)
+{
+	return RegSetValueEx(m_hKey, valueName, 0, REG_SZ, lpData, cbData);
+}
+
+//------------------------------------------------------------------------------------
+// GetString
+// Query the key for the named value of type string
+LONG CRegUtils::GetString(LPCTSTR valueName, LPBYTE lpData, DWORD cbData)
+{
+	LONG ret = ERROR_SUCCESS;
+	DWORD size = cbData, type = 0;
+	ret = RegQueryValueEx(m_hKey, valueName, NULL, &type, lpData, &size);
+	if ((size != cbData) || (REG_SZ != type))
+	{
+		ret = ERROR_INVALID_PARAMETER;
+	}
+	return ret;
+}
+
+//------------------------------------------------------------------------------------
+// SetBinary
+// Set the key for the named value of type binary
+LONG CRegUtils::SetBinary(LPCTSTR valueName, const BYTE* lpData, DWORD cbData)
+{
+	return RegSetValueEx(m_hKey, valueName, 0, REG_BINARY, lpData, cbData);
+}
+
+//------------------------------------------------------------------------------------
+// GetBinary
+// Query the key for the named value of type binary
+LONG CRegUtils::GetBinary(LPCTSTR valueName, LPBYTE lpData, DWORD cbData)
+{
+	LONG ret = ERROR_SUCCESS;
+	DWORD size = cbData, type = 0;
+	ret = RegQueryValueEx(m_hKey, valueName, NULL, &type, lpData, &size);
+	if ((size != cbData) || (REG_BINARY != type))
+	{
+		ret = ERROR_INVALID_PARAMETER;
+	}
+	return ret;
+}
+
+//------------------------------------------------------------------------------------
+// SetDword
+// Set the key for the named value of type DWORD
+LONG CRegUtils::SetDword(LPCTSTR valueName, const BYTE* lpData, DWORD cbData)
+{
+	return RegSetValueEx(m_hKey, valueName, 0, REG_DWORD, lpData, cbData);
+}
+
+//------------------------------------------------------------------------------------
+// GetDword
+// Query the key for the named value of type DWORD
+LONG CRegUtils::GetDword(LPCTSTR valueName, LPBYTE lpData, DWORD cbData)
+{
+	LONG ret = ERROR_SUCCESS;
+	DWORD size = cbData, type = 0;
+	ret = RegQueryValueEx(m_hKey, valueName, NULL, &type, lpData, &size);
+	if ((size != cbData) || (REG_DWORD != type))
+	{
+		ret = ERROR_INVALID_PARAMETER;
+	}
+	return ret;
+}
+
+//------------------------------------------------------------------------------------
+// CUtils - utility class
+//------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// GetBMIHeader
+// Returns the BITMAPINFOHEADER structure from media type format extension
+BITMAPINFOHEADER* CUtils::GetBMIHeader(const AM_MEDIA_TYPE* pamt)
+{
+	BITMAPINFOHEADER* pbmih = NULL;
+
+	if (pamt)
+	{
+		if (FORMAT_VideoInfo == pamt->formattype)
+		{
+			VIDEOINFOHEADER* pvih = reinterpret_cast<VIDEOINFOHEADER*>(pamt->pbFormat);
+			ASSERT(sizeof(VIDEOINFOHEADER) <= pamt->cbFormat);
+			pbmih = &pvih->bmiHeader;
+		}
+		else if (FORMAT_VideoInfo2 == pamt->formattype)
+		{
+			VIDEOINFOHEADER2* pvih = reinterpret_cast<VIDEOINFOHEADER2*>(pamt->pbFormat);
+			ASSERT(sizeof(VIDEOINFOHEADER2) <= pamt->cbFormat);
+			pbmih = &pvih->bmiHeader;
+		}
+	}
+
+	return pbmih;
+}
+
+//-----------------------------------------------------------------------------
+// GetBMIHeader
+// Returns the BITMAPINFOHEADER structure from media type format extension
+BITMAPINFOHEADER* CUtils::GetBMIHeader(const CMediaType& mt)
+{
+	BITMAPINFOHEADER* pbmih = NULL;
+
+	if (FORMAT_VideoInfo == mt.formattype)
+	{
+		VIDEOINFOHEADER* pvih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);
+		ASSERT(sizeof(VIDEOINFOHEADER) <= mt.cbFormat);
+		pbmih = &pvih->bmiHeader;
+	}
+	else if (FORMAT_VideoInfo2 == mt.formattype)
+	{
+		VIDEOINFOHEADER2* pvih = reinterpret_cast<VIDEOINFOHEADER2*>(mt.pbFormat);
+		ASSERT(sizeof(VIDEOINFOHEADER2) <= mt.cbFormat);
+		pbmih = &pvih->bmiHeader;
+	}
+
+	return pbmih;
+}
+
+//-----------------------------------------------------------------------------
+// GetAvgTimePerFrame
+// Returns the average time per frame from media type format extension
+REFERENCE_TIME CUtils::GetAvgTimePerFrame(const AM_MEDIA_TYPE* pamt)
+{
+	REFERENCE_TIME rtAvgTimePerFrame = 0;
+
+	if (pamt)
+	{
+		if (FORMAT_VideoInfo == pamt->formattype)
+		{
+			VIDEOINFOHEADER* pvih = reinterpret_cast<VIDEOINFOHEADER*>(pamt->pbFormat);
+			ASSERT(sizeof(VIDEOINFOHEADER) <= pamt->cbFormat);
+			rtAvgTimePerFrame = pvih->AvgTimePerFrame;
+		}
+		else if (FORMAT_VideoInfo2 == pamt->formattype)
+		{
+			VIDEOINFOHEADER2* pvih = reinterpret_cast<VIDEOINFOHEADER2*>(pamt->pbFormat);
+			ASSERT(sizeof(VIDEOINFOHEADER2) <= pamt->cbFormat);
+			rtAvgTimePerFrame = pvih->AvgTimePerFrame;
+		}
+	}
+
+	return rtAvgTimePerFrame;
+}
+
+//------------------------------------------------------------------------------------
+// GetImageSize
+// Calculates the image size
+unsigned long CUtils::GetImageSize(BITMAPINFOHEADER* pbmih)
+{
+	unsigned long dwImageSize = 0;
+
+	if (pbmih)
+	{
+		switch (pbmih->biCompression)
+		{
+			default:
+			case BI_RGB:
+				dwImageSize = (pbmih->biWidth * abs(pbmih->biHeight) * pbmih->biBitCount) >> 3;
+				break;
+
+			case 'YVYU':
+			case '2YUY':
+				dwImageSize = (pbmih->biWidth * abs(pbmih->biHeight) * 16) >> 3;
+				break;
+		}
+	}
+
+	return dwImageSize;
+}
+
Index: trunk/src/testing/app/hd-video-player/Histogram.h
===================================================================
--- trunk/src/testing/app/hd-video-player/Histogram.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/Histogram.h	(revision 4)
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _CONVERT_To_SAIL_
+#define _CONVERT_To_SAIL_
+
+#include "output_sail.h"
+#include "stdafx.h"
+
+// CConvToRGB: Base class for image operations
+class CConvToRGB
+{
+public:
+
+    CConvToRGB();
+
+    HRESULT SetFormat(const VIDEOINFOHEADER& vih);
+    HRESULT SetImage(BYTE *pBuffer);
+    HRESULT ConvertImage();
+	int SendToBmp(void);
+	int SendToSage(void);
+
+protected:
+
+//	SVC_output_sail m_sail;
+
+    DWORD NumPixels() { return m_dwHeight * m_dwWidth; }
+
+    BYTE*   m_pImg;
+    DWORD   m_dwWidth;
+    DWORD   m_dwHeight;
+    LONG    m_lStride;
+    int     m_iBitDepth;
+	unsigned char* m_pbRGB_buff;
+
+
+	DWORD m_bufLen;
+};
+
+#endif
Index: trunk/src/testing/app/hd-video-player/DecklinkCaptureDlg.h
===================================================================
--- trunk/src/testing/app/hd-video-player/DecklinkCaptureDlg.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/DecklinkCaptureDlg.h	(revision 4)
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// $Id: DecklinkCaptureDlg.h,v 1.5 2006/04/11 01:11:07 ivanr Exp $
+//
+// Desc: DirectShow capture sample
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//-----------------------------------------------------------------------------
+
+#pragma once
+#include "afxwin.h"
+#include "Utils.h"
+
+// CDecklinkCaptureDlg dialog
+class CDecklinkCaptureDlg : public CDialog
+{
+// Construction
+public:
+	CDecklinkCaptureDlg(CWnd* pParent = NULL);	// standard constructor
+	~CDecklinkCaptureDlg();
+// Dialog Data
+	enum { IDD = IDD_DECKLINKCAPTURE_DIALOG };
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
+
+	afx_msg void OnCbnSelchangeComboVideodevice();
+	afx_msg void OnCbnSelchangeComboAudiodevice();
+	afx_msg void OnCbnSelchangeComboVideoformats();
+	afx_msg void OnCbnSelchangeComboAudioformats();
+	afx_msg void OnBnClickedCheckAudiomute();
+	afx_msg void OnBnClickedButtonBrowse();
+	afx_msg void OnBnClickedButtonCapture();
+	afx_msg void OnBnClickedButtonStop();
+	afx_msg void OnCbnSelchangeComboCompression();
+	afx_msg void OnBnClickedSageStart();
+	afx_msg void OnBnClickedSageStop();
+	afx_msg void OnCbnSelchangeSageAddr();
+	afx_msg void OnEnChangeSageEditIp();
+// Implementation
+protected:
+	HICON m_hIcon;
+
+	// Generated message map functions
+	virtual BOOL OnInitDialog();
+	virtual BOOL DestroyWindow();
+	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
+	afx_msg void OnPaint();
+	afx_msg HCURSOR OnQueryDragIcon();
+	DECLARE_MESSAGE_MAP()
+
+	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
+	void HandleGraphEvent();
+
+private:
+	IGraphBuilder* m_pGraph;
+	IBaseFilter* m_pVideoCapture;
+	IBaseFilter* m_pAudioCapture;
+	IBaseFilter* m_pVideoRenderer;
+	IBaseFilter* m_pSmartT;
+
+	IMediaControl* m_pControl;
+
+	IVideoWindow* m_pIVW;	// for the preview window
+	IMediaEventEx* m_pMediaEvent;	// for the preview window
+
+	DWORD m_ROTRegister;
+
+	CComboBox m_videoDeviceCtrl;
+	CComboBox m_audioDeviceCtrl;
+	CComboBox m_videoFormatCtrl;
+	CComboBox m_audioFormatCtrl;
+	CComboBox m_compressionCtrl;
+	CComboBox m_sageStreamCtrl;
+	CComboBox m_framerateCtrl;
+
+	CButton m_MuteCtrl;
+
+	CEdit m_sageIPCtrl;
+
+	CStatic m_preview;
+	BOOL m_bAudioMute;
+	int m_compressor;
+	int m_framerate;
+	BOOL m_bEnableCompressionCtrl;
+	enum { ENC_NONE, ENC_DV, ENC_WM };
+	//enum { COLOR_RGB24, COLOR_16 };
+
+	CString m_captureFile;
+	CEdit m_captureFileCtrl;
+
+	VIDEOINFOHEADER m_vihDefault;
+	WAVEFORMATEX m_wfexDefault;
+	CRegUtils m_regUtils;
+
+	HRESULT CreatePreviewGraph();
+	HRESULT CreateCaptureGraph(bool sage=false);
+	HRESULT CreateUncompressedCaptureGraph();
+	HRESULT CreateDVCaptureGraph();
+	HRESULT CreateWMCaptureGraph();
+	HRESULT ConfigureWMEncoder(IBaseFilter* pASFWriter);
+	HRESULT DestroyGraph(bool sage=false);
+
+	void InitialiseVideoPreview(void);
+
+	HRESULT PopulateDeviceControl(const GUID* pCategory, CComboBox* pCtrl);
+	HRESULT PopulateVideoControl();
+	HRESULT PopulateAudioControl();
+	HRESULT PopulateCompressionControl();
+
+	int  ChangeMasterIP(int index);
+	void EnableControls(void);
+	void DisableControls(void);
+
+	int LoadIpInfo();
+
+	void QueryRegistry(void);
+	afx_msg void OnBnClickedButtonCodecproperties();
+public:
+	afx_msg void OnBnClickedSageReg();
+	afx_msg void OnCbnSelchangeComboFramerate();
+	afx_msg void OnCbnSelchangeComboCompression2();
+};
Index: trunk/src/testing/app/hd-video-player/Utils.h
===================================================================
--- trunk/src/testing/app/hd-video-player/Utils.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/Utils.h	(revision 4)
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//------------------------------------------------------------------------------------
+// $Id: Utils.h,v 1.6 2006/03/21 07:00:57 ivanr Exp $
+//
+// Desc: DirectShow utility class header
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//------------------------------------------------------------------------------------
+
+#pragma once
+
+#include <string>
+#include <dvdmedia.h>
+
+//------------------------------------------------------------------------------------
+// CDSUtils - Directshow utility class
+//------------------------------------------------------------------------------------
+class CDSUtils
+{
+public:
+	static HRESULT AddFilter(IGraphBuilder* pGraph, const GUID &clsid, LPCWSTR pName, IBaseFilter** ppFilter);
+	static HRESULT AddFilter2(IGraphBuilder* pGraph, const GUID &clsid, LPCWSTR pName, IBaseFilter** ppFilter);
+
+	static HRESULT GetUnconnectedPin(IBaseFilter* pFilter, PIN_DIRECTION PinDir, IPin** ppPin);
+	static HRESULT GetPin(IBaseFilter* pFilter, const wchar_t* pName, IPin** ppPin);
+	static HRESULT GetPin(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, IPin** ppPin);
+
+	static HRESULT ConnectFilters(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName, IBaseFilter* pDownstream, wchar_t* pDownstreamPinName);
+	static HRESULT ConnectFilters(IGraphBuilder* pGraph, IBaseFilter* pUpstream, IBaseFilter* pDownstream, const GUID* pFormat);
+	static HRESULT RenderFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName);
+
+	static HRESULT DisconnectAllPins(IGraphBuilder* pGraph);
+
+	static HRESULT FindFilterInterface(IBaseFilter* pFilter, const IID& riid, void** ppvInterface);
+	static HRESULT FindPinInterface(IBaseFilter* pFilter, wchar_t* pName, const IID& riid, void** ppvInterface);
+	static HRESULT FindPinInterface(IBaseFilter* pFilter, const GUID* pFormat, PIN_DIRECTION PinDir, const IID& riid, void** ppvInterface);
+
+	static HRESULT AddGraphToRot(IUnknown* pUnkGraph, DWORD* pdwRegister);
+	static void RemoveGraphFromRot(DWORD pdwRegister);
+};
+
+//------------------------------------------------------------------------------------
+// CRegUtils - Registry utility class
+//------------------------------------------------------------------------------------
+class CRegUtils
+{
+public:
+	CRegUtils();
+	~CRegUtils();
+
+	LONG Open(LPCTSTR lpSubKey);
+	LONG Create(LPCTSTR lpSubKey);
+	void Close();
+
+	LONG SetString(LPCTSTR valueName, const BYTE* lpData, DWORD cbData);
+	LONG GetString(LPCTSTR valueName, LPBYTE lpData, DWORD cbData);
+
+	LONG SetBinary(LPCTSTR valueName, const BYTE* lpData, DWORD cbData);
+	LONG GetBinary(LPCTSTR valueName, LPBYTE lpData, DWORD cbData);
+
+	LONG SetDword(LPCTSTR valueName, const BYTE* lpData, DWORD cbData);
+	LONG GetDword(LPCTSTR valueName, LPBYTE lpData, DWORD cbData);
+
+private:
+	std::string m_subKeyName;
+	HKEY m_hKey;
+};
+
+//------------------------------------------------------------------------------------
+// CUtils - utility class
+//------------------------------------------------------------------------------------
+class CUtils
+{
+public:
+	static BITMAPINFOHEADER* GetBMIHeader(const AM_MEDIA_TYPE* pamt);
+	static BITMAPINFOHEADER* GetBMIHeader(const CMediaType& mt);
+	static REFERENCE_TIME GetAvgTimePerFrame(const AM_MEDIA_TYPE* pamt);
+	static unsigned long GetImageSize(BITMAPINFOHEADER* pbmih);
+};
+
+//------------------------------------------------------------------------------
+// UNITS = 10 ^ 7
+// UNITS / 30 = 30 fps;
+// UNITS / 20 = 20 fps, etc
+const REFERENCE_TIME FPS_30 = UNITS / 30;
+const REFERENCE_TIME FPS_2997 = UNITS * 1001 / 30000;
+const REFERENCE_TIME FPS_25 = UNITS / 25;
+const REFERENCE_TIME FPS_24 = UNITS / 24;
+const REFERENCE_TIME FPS_23976 = UNITS * 1001 / 24000;
+const REFERENCE_TIME FPS_20 = UNITS / 20;
+const REFERENCE_TIME FPS_10 = UNITS / 10;
+const REFERENCE_TIME FPS_5  = UNITS / 5;
+const REFERENCE_TIME FPS_4  = UNITS / 4;
+const REFERENCE_TIME FPS_3  = UNITS / 3;
+const REFERENCE_TIME FPS_2  = UNITS / 2;
+const REFERENCE_TIME FPS_1  = UNITS / 1;
+
+//------------------------------------------------------------------------------
+#define SAFE_DELETE(p)			{ if(p) { delete (p);     (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p)	{ if(p) { delete [] (p);     (p)=NULL; } }
+#define SAFE_RELEASE(p)			{ if(p) { (p)->Release(); (p)=NULL; } }
+#define SIZEOF_ARRAY(x)			(sizeof(x)/sizeof((x)[0]))
Index: trunk/src/testing/app/hd-video-player/DecklinkCapture.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/DecklinkCapture.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/DecklinkCapture.cpp	(revision 4)
@@ -0,0 +1,119 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// $Id: DecklinkCapture.cpp,v 1.2 2006/04/11 01:11:07 ivanr Exp $
+//
+// Desc: DirectShow capture sample
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//-----------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+#include "DecklinkCapture.h"
+#include "DecklinkCaptureDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+
+// CDecklinkCaptureApp
+
+BEGIN_MESSAGE_MAP(CDecklinkCaptureApp, CWinApp)
+	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+
+// CDecklinkCaptureApp construction
+
+CDecklinkCaptureApp::CDecklinkCaptureApp()
+{
+	// TODO: add construction code here,
+	// Place all significant initialization in InitInstance
+}
+
+
+// The one and only CDecklinkCaptureApp object
+
+CDecklinkCaptureApp theApp;
+
+
+// CDecklinkCaptureApp initialization
+
+BOOL CDecklinkCaptureApp::InitInstance()
+{
+	// InitCommonControls() is required on Windows XP if an application
+	// manifest specifies use of ComCtl32.dll version 6 or later to enable
+	// visual styles.  Otherwise, any window creation will fail.
+	InitCommonControls();
+
+	CWinApp::InitInstance();
+
+	AfxEnableControlContainer();
+
+	CoInitialize(NULL);
+
+	// Standard initialization
+	// If you are not using these features and wish to reduce the size
+	// of your final executable, you should remove from the following
+	// the specific initialization routines you do not need
+	// Change the registry key under which our settings are stored
+	// TODO: You should modify this string to be something appropriate
+	// such as the name of your company or organization
+	SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+
+	CDecklinkCaptureDlg dlg;
+	m_pMainWnd = &dlg;
+	INT_PTR nResponse = dlg.DoModal();
+	if (nResponse == IDOK)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with OK
+	}
+	else if (nResponse == IDCANCEL)
+	{
+		// TODO: Place code here to handle when the dialog is
+		//  dismissed with Cancel
+	}
+
+	CoUninitialize();
+
+	// Since the dialog has been closed, return FALSE so that we exit the
+	//  application, rather than start the application's message pump.
+	return FALSE;
+}
Index: trunk/src/testing/app/hd-video-player/output_sail.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/output_sail.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/output_sail.cpp	(revision 4)
@@ -0,0 +1,381 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "stdafx.h"
+#include "output_sail.h"
+
+
+C_Output_sail::C_Output_sail() {
+	SetZero();
+	sageInf = NULL;
+ }
+
+void C_Output_sail::SetZero() {
+	m_width = 0;
+	m_height = 0;
+	m_byte_pixel = 0;
+	m_color_mode = 0;
+	m_flag_empty = 0;
+	m_frame_buf = 0;
+
+	m_execConfigName = NULL;
+	m_nwID = 0;
+
+	m_flag_notinit = 1;
+	m_output_addr = 0;
+	m_output_port = 0;
+
+	//m_audioOn =true;
+	m_sailstarted =false;
+}
+
+//-------------------------------------------------------------------------------------
+void C_Output_sail::setSailEnv(char* execConfigName, int nwID) {
+        m_execConfigName = execConfigName;
+        m_nwID = nwID;
+
+	fprintf(stderr, "\r\n m_exec : %s , m_nwID : %d", execConfigName, nwID);
+}
+
+
+//-------------------------------------------------------------------------------------
+int C_Output_sail::sailInit()
+{
+    sailConfig scfg;
+    sageRect glImageMap;
+
+	glImageMap.left = 0.0;
+    glImageMap.right = 1.0;
+    glImageMap.bottom = 0.0;
+    glImageMap.top = 1.0;
+
+
+	if(sageInf != NULL) {
+		sageInf->shutdown();
+		delete sageInf;
+		sageInf = NULL;
+	}
+	sageInf = new sail();
+
+#if defined(SAGE_VERSION1)
+	scfg.cfgFile = strdup("sage.conf");
+    scfg.appName = strdup("svt");
+    scfg.rank = 0;
+    scfg.ip = NULL; // strdup("192.168.81.120");
+	scfg.execConfig = NULL;
+    scfg.nwID = 2;
+
+	if(m_color_mode == RGB24) {
+		m_byte_pixel = 3;
+		scfg.colorDepth = 24;
+	    scfg.pixFmt = TVPIXFMT_888_INV;
+	} else if(m_color_mode == RGB16) {
+		m_byte_pixel = 2;
+		scfg.colorDepth = 16;
+	    scfg.pixFmt = TVPIXFMT_565;
+	} else return -1;
+
+    scfg.resX = m_width;
+    scfg.resY = m_height;
+    scfg.imageMap = glImageMap;
+    scfg.rowOrd = BOTTOM_TO_TOP;
+
+	//m_frame_buf = (unsigned char *)malloc(m_width * m_height * m_byte_pixel);
+    //memset(m_frame_buf, 0, scfg.resX *scfg.resY*m_byte_pixel);
+
+#else
+	sage::win32Init();
+
+	if(m_audioOn) {
+#if defined (SAGE_AUDIO)
+		scfg.framePerBuffer = m_framePerBuffer;
+#endif
+	}
+
+	scfg.init("svt.conf");
+	scfg.setAppName("svt");
+	scfg.rank = 0;
+	scfg.master = true;
+	scfg.nwID = 1;
+	scfg.syncPort = 13000;
+	scfg.nodeNum = 1;
+	scfg.blockX= 64; // 128; // 64;
+	scfg.blockY= 64; // 90;  // 64;
+	sprintf(scfg.fsIP, "%s", m_output_addr);
+
+	if(m_color_mode == RGB24) {
+		m_byte_pixel = 3;
+	    scfg.pixFmt = PIXFMT_888_INV; //PIXFMT_888;
+		scfg.rowOrd = BOTTOM_TO_TOP;
+		sage::printLog("SAGE> color mode 24 888 bits\n");
+	} else if(m_color_mode == RGB16) {
+		m_byte_pixel = 2;
+	    scfg.pixFmt = PIXFMT_565;
+		scfg.rowOrd = BOTTOM_TO_TOP;
+		sage::printLog("SAGE> color mode 16 565 bits\n");
+	} else if(m_color_mode == YUV) {
+		m_byte_pixel = 2;
+	    scfg.pixFmt = PIXFMT_YUV;
+		scfg.rowOrd = TOP_TO_BOTTOM;
+		sage::printLog("SAGE> color mode YUV bits\n");
+	} else return -1;
+
+    scfg.resX = m_width;
+    scfg.resY = m_height;
+    scfg.imageMap = glImageMap;
+
+		// Position and size on the display side
+    scfg.winX = 0;
+    scfg.winY = 0;
+    scfg.winWidth = m_width*1;
+    scfg.winHeight = m_height*1;
+
+	sage::printLog("SAGE> Init: w %d h %d\n\n", m_width, m_height);
+	// for setting up audio configuration
+	if(m_audioOn) {
+#if defined (SAGE_AUDIO)
+		scfg.audioMode = m_audioMode;
+		scfg.audioPort = m_audioPort;
+		scfg.audioDeviceNum = m_audioDeviceNum;
+		scfg.sampleFmt = m_sampleFmt;
+		scfg.samplingRate = m_samplingRate;
+		scfg.channels = m_channels;
+		//scfg.framePerBuffer = m_framePerBuffer;
+		scfg.audioOn = true;
+		if(m_audioMode == SAGE_AUDIO_APP) {
+			scfg.audioBuffSize = m_abuffsize;
+		}
+#endif
+	}
+
+#endif
+
+	m_sailstarted  = true;
+    sageInf->init(scfg);
+
+	return 0;
+}
+
+//-------------------------------------------------------------------------------------
+int C_Output_sail::init(int width, int height, int color_mode, char* output_addr, int output_port)
+{
+	SetZero();
+    m_width = width;
+    m_height = height;
+
+    if(output_addr == NULL)
+	{
+            fprintf(stderr, "\r\n Output Address is needed");
+//            g_done_control = 1;
+            return -1;
+    } else
+		m_output_addr = strdup(output_addr);
+
+    m_output_port = output_port;
+    m_color_mode = color_mode;
+
+#if defined (SAGE_AUDIO)
+	if(m_audioOn == false) {
+		if(m_flag_notinit) {
+            return sailInit();
+            //m_flag_notinit = 0;
+		}
+	}
+#endif
+
+    return 0;
+}
+
+
+
+//-------------------------------------------------------------------------------------
+int C_Output_sail::push_data(unsigned char* buf , int buf_len)
+{
+		static int framenum = 0;
+
+        // check some messages
+        sageMessage msg;
+        if (sageInf->checkMsg(msg, false) > 0) {
+                switch (msg.getCode()) {
+                        case APP_QUIT : {
+                                //g_done_control = 1;
+                                return -1;
+                        }
+
+                }
+        }
+
+#if defined(SAGE_VERSION1)
+		//memcpy(m_frame_buf, buf, m_width *m_height*m_byte_pixel);
+		if(buf == NULL || sageInf->swapBuffer(buf) == -1) {
+			//g_done_control = 1;
+			return -1;
+		}
+#else
+
+#endif
+		if(buf == NULL)
+		{
+			//g_done_control = 1;
+			return -1;
+		}
+		else
+		{
+			switch (FrameRate) {
+				case FR10:
+					if ( (framenum % 3) != 0 ) {
+						framenum = (framenum + 1) % 30;
+						return 0;
+					}
+					break;
+				case FR15:
+					if ( (framenum % 2) == 0 ) {
+						framenum = (framenum + 1) % 30;
+						return 0;
+					}
+					break;
+				case FR20:
+					if ( (framenum % 3) == 0 ) {
+						framenum = (framenum + 1) % 30;
+						return 0;
+					}
+					break;
+				case FR25:
+					if ( (framenum == 1) || (framenum == 7) || (framenum == 13) || (framenum == 19) || (framenum == 25) ) {
+						framenum = (framenum + 1) % 30;
+						return 0;
+					}
+					break;
+				case FR30:
+					break;
+				default:
+					break;
+			}
+
+			void *m_frame = sageInf->getBuffer();
+
+			memcpy(m_frame, buf, m_width *m_height*m_byte_pixel);
+
+			sageInf->swapBuffer();
+
+			framenum = (framenum + 1) % 30;
+		}
+
+		return 0;
+}
+
+//-------------------------------------------------------------------------------------
+int C_Output_sail::push_audiodata(unsigned char* buf, int buf_len)
+{
+#if defined(SAGE_AUDIO)
+	sageInf->pushAudioData(buf_len, (void*)buf);
+#endif
+	return 0;
+}
+
+void C_Output_sail::setAudioOn(bool on)
+{
+	m_audioOn= on;
+}
+
+
+int C_Output_sail::init(int size)
+{
+	// for the test
+#if defined (SAGE_AUDIO)
+	m_audioMode = SAGE_AUDIO_APP;
+	m_sampleFmt = SAGE_SAMPLE_INT16;
+#endif
+	m_audioPort = 26000;
+	m_audioDeviceNum = -1;
+	m_samplingRate = 48000; //48000;			// audio sampling rate : default-44100
+	m_channels =2;				// number of audio channel
+	m_framePerBuffer = 512;//1024; // 1536;		// audio frames per buffer 1536 /  2 = 768
+	m_abuffsize = size;
+
+	if(m_flag_notinit) {
+        return sailInit();
+        //m_flag_notinit = 0;
+	}
+	return -1;
+}
+
+int C_Output_sail::initAudioCaptureMode()
+{
+#if defined (SAGE_AUDIO)
+	m_audioMode = SAGE_AUDIO_CAPTURE;
+	m_sampleFmt = SAGE_SAMPLE_INT16;
+#endif
+	m_audioPort = 26000;
+	m_audioDeviceNum = 0;
+	m_samplingRate = 44100;			// audio sampling rate : default-44100
+	m_channels =2;					// number of audio channel
+	m_framePerBuffer = 512; // 1536;		// audio frames per buffer 1024 /  2 = 512
+
+	if(m_flag_notinit) {
+        return sailInit();
+        //m_flag_notinit = 0;
+	}
+	return -1;
+}
+
+void C_Output_sail::shutdown()
+{
+	if(m_sailstarted == true) {
+#if defined (SAGE_AUDIO)
+		// Question ????
+		//sageInf->stop();
+#endif
+		sageInf->shutdown();
+		m_sailstarted = false;
+		Sleep(100);
+		if(sageInf) {
+			delete sageInf;
+			sageInf = NULL;
+		}
+	}
+}
+
+C_Output_sail::~C_Output_sail ()
+{
+		if(sageInf) {
+			sageInf->shutdown();
+			delete sageInf;
+			sageInf = NULL;
+		}
+}
+
+
Index: trunk/src/testing/app/hd-video-player/YUV_RGB.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/YUV_RGB.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YUV_RGB.cpp	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "stdafx.h"
+#include "YUV_RGB.h"
+
+/*
+typedef struct tagRGBQUAD {
+        BYTE    rgbBlue;
+        BYTE    rgbGreen;
+        BYTE    rgbRed;
+        BYTE    rgbReserved;
+} RGBQUAD;
+
+typedef struct tagBITMAPINFOHEADER {
+        DWORD      biSize;
+        LONG       biWidth;
+        LONG       biHeight;
+        WORD       biPlanes;
+        WORD       biBitCount;
+        DWORD      biCompression;
+        DWORD      biSizeImage;
+        LONG       biXPelsPerMeter;
+        LONG       biYPelsPerMeter;
+        DWORD      biClrUsed;
+        DWORD      biClrImportant;
+} BITMAPINFOHEADER;
+
+typedef struct tagBITMAPFILEHEADER {
+        WORD    bfType;
+        DWORD   bfSize;
+        WORD    bfReserved1;
+        WORD    bfReserved2;
+        DWORD   bfOffBits;
+} BITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFO {
+	BITMAPINFOHEADER    bmiHeader;			//
+	RGBQUAD             bmiColors[1];		// »ý»ó Å×ÀÌºí
+} BITMAPINFO;
+//*/
+
+
+//-----------------------------------------------------------------------------
+//		SaveBMP Function
+//
+//	ÁÖŸîÁø °æ·Î·Î ÀúÀå.
+void SaveToBmp(char *Path, unsigned char *img_buff, int width, int height, int bitcount) {
+///*
+	BITMAPFILEHEADER fh;		// bmp file header
+	BITMAPINFOHEADER bh;		// bmp info header
+
+	int palSize;
+	DWORD dwWritten;
+	HANDLE hFile;
+
+	palSize = (bitcount==24 ? 0:1 << bitcount)*sizeof(RGBQUAD);
+
+	// bmp info header
+	bh.biSize = sizeof(BITMAPINFOHEADER);	// Bmp Header Size
+	bh.biWidth = width;						// Width
+	bh.biHeight = height;					// Height
+	bh.biPlanes = 1;							// Planes
+	bh.biBitCount = 24;						// BitCount
+	//	YUV - mmioFOURCC('I','4','2','0'), width*height*3/2),
+	//  RGB24 (non compression)
+	bh.biCompression = BI_RGB;				// Compression
+//	bh.biSizeImage = (((width * 3) + 3) / 4) * 4 * height;
+	bh.biSizeImage = width * height * (bitcount/8);
+	bh.biXPelsPerMeter = 0;					// X,Y Pixels per Meter
+	bh.biYPelsPerMeter = 0;
+	bh.biClrUsed = 0;			// Colors that used(if 0, Maximum colors)
+	bh.biClrImportant = 0;		// Important colors that used(if 0, all colors are important)
+
+	// BITMAPFILEHEADER.
+	fh.bfType = 0x4d42;
+	fh.bfReserved1 = 0;
+	fh.bfReserved2 = 0;
+	fh.bfSize = bh.biSize + palSize + bh.biSizeImage + sizeof(BITMAPFILEHEADER);
+	fh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+palSize;
+
+	// Write to File.
+	hFile=CreateFile(Path,GENERIC_WRITE,0,NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
+	WriteFile(hFile, &fh, sizeof(fh), &dwWritten, NULL);
+	WriteFile(hFile, &bh, sizeof(bh), &dwWritten, NULL);
+	WriteFile(hFile, img_buff, bh.biSizeImage, &dwWritten, NULL);
+
+	CloseHandle(hFile);
+//	*/
+}
Index: trunk/src/testing/app/hd-video-player/DecklinkCapture.h
===================================================================
--- trunk/src/testing/app/hd-video-player/DecklinkCapture.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/DecklinkCapture.h	(revision 4)
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//-----------------------------------------------------------------------------
+// $Id: DecklinkCapture.h,v 1.2 2006/04/11 01:11:07 ivanr Exp $
+//
+// Desc: DirectShow capture sample
+//
+// Copyright (c) Blackmagic Design 2005. All rights reserved.
+//-----------------------------------------------------------------------------
+
+#pragma once
+
+#ifndef __AFXWIN_H__
+	#error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h"		// main symbols
+
+
+// CDecklinkCaptureApp:
+// See DecklinkCapture.cpp for the implementation of this class
+//
+
+class CDecklinkCaptureApp : public CWinApp
+{
+public:
+	CDecklinkCaptureApp();
+
+// Overrides
+	public:
+	virtual BOOL InitInstance();
+
+// Implementation
+
+	DECLARE_MESSAGE_MAP()
+};
+
+extern CDecklinkCaptureApp theApp;
Index: trunk/src/testing/app/hd-video-player/output_sail.h
===================================================================
--- trunk/src/testing/app/hd-video-player/output_sail.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/output_sail.h	(revision 4)
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/* Output Pixel Format Define */
+#ifndef _OUTPUT_SAIL_
+#define _OUTPUT_SAIL_
+
+//#include <stdio.h>
+
+#include "sail.h"
+#include "misc.h"
+
+#define RGB16     90
+#define RGB24	  91
+#define RGB32	  92
+#define YUV		  93
+
+#define FR10		  100
+#define FR15		  115
+#define FR20		  120
+#define FR25		  125
+#define FR30		  130
+
+extern int FrameRate;
+
+class C_Output_sail {
+	int m_width;
+	int m_height;
+	int m_byte_pixel;
+	int m_color_mode;
+	int m_flag_empty;
+	unsigned char* m_frame_buf;
+	bool m_sailstarted;
+
+	char* m_execConfigName;
+	int m_nwID;
+
+	sail *sageInf;
+
+	int m_flag_notinit;
+	char* m_output_addr;
+	int m_output_port;
+
+	bool m_audioOn;				// audio on/off flag
+#if defined (SAGE_AUDIO)
+	sageAudioMode m_audioMode;	// audio mode : capture, play, read, write
+	sageSampleFmt m_sampleFmt;	// audio sampling format : float, short, char, unsigned char
+#endif
+	int  m_audioPort;				// audio port number
+	int  m_audioDeviceNum;		// device number
+	long m_samplingRate;			// audio sampling rate : default-44100
+	int  m_channels;				// number of audio channel
+	int  m_framePerBuffer;		// audio frames per buffer
+	int m_abuffsize;
+
+	void SetZero(void);
+	int sailInit(void);
+
+public :
+
+	C_Output_sail ();
+	virtual ~C_Output_sail ();
+
+	int init(int width, int height, int color_mode,char* output_addr, int output_port);
+	void setSailEnv(char* execConfigName, int nwID);
+	int push_data(unsigned char* buf , int buf_len);
+	int push_audiodata(unsigned char* buf, int buf_len);
+	void setAudioOn(bool on);
+	int init(int size);
+	int initAudioCaptureMode();
+	void shutdown();
+
+};
+
+
+
+#endif
Index: trunk/src/testing/app/hd-video-player/YuvToRGB.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/YuvToRGB.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YuvToRGB.cpp	(revision 4)
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <windows.h>
+#include "stdafx.h"
+#include "YuvToRGB.h"
+
+#define MYUCHAR(_flt_) ((_flt_>0 && _flt_<256)?_flt_:((_flt_<0)?0:255))
+
+// U0 Y0 Vo Y1 | U2 Y2 V2 Y3 | U4 Y4 V4 Y5 | ...
+void YUV422UYVY_ToRGB24(unsigned char* pbYUV, unsigned char* pbRGB, DWORD yuv_len)
+{
+
+//	 /*
+	int B_Cb128,R_Cr128,G_CrCb128;
+    int Y0,U,Y1,V;
+    int R,G,B;
+
+	BYTE *yuv_index;
+	BYTE *rgb_index;
+
+//	long lStride_out = (((dwWidth * 3) + 3) / 4) * 4;
+
+	yuv_index = pbYUV;
+	rgb_index = pbRGB;
+
+    for (DWORD i = 0, j = 0; i < yuv_len; )
+    {
+        // Each WORD is a 'UY' or 'VY' block.
+        // Set the low byte (chroma) to 0x80 and leave the high byte (luma)
+//            WORD pixel = pwSource[x] & 0xFF00;
+//          pixel |= 0x0080;
+//        pwTarget[x] = pixel;
+
+// R = 1.164(Y - 16)					+ 1.596(V - 128)
+// G = 1.164(Y - 16)					- 0.813(V - 128) - 0.391(U - 128)
+// B = 1.164(Y - 16)                   + 2.018(U - 128)
+
+		U  = (int)((float)yuv_index[i++]-128.0f);
+		Y0 = (int)(1.164f * ((float)pbYUV[i++]-16.0f));
+		V  = (int)((float)yuv_index[i++]-128.0f);
+		Y1 = (int)(1.164f * ((float)yuv_index[i++]-16.0f));
+
+		R_Cr128   =  (int)(1.596f*V);
+		G_CrCb128 = (int)(-0.813f*V - 0.391f*U);
+		B_Cb128   =  (int)(2.018f*U);
+
+		R= Y0 + R_Cr128;
+		G = Y0 + G_CrCb128;
+		B = Y0 + B_Cb128;
+
+		rgb_index[j++] = max(0, min(B, 255));
+		rgb_index[j++] = max(0, min(G, 255));
+		rgb_index[j++] = max(0, min(R, 255));
+
+		R= Y1 + R_Cr128;
+		G = Y1 + G_CrCb128;
+		B = Y1 + B_Cb128;
+
+		rgb_index[j++] = max(0, min(B, 255));
+		rgb_index[j++] = max(0, min(G, 255));
+		rgb_index[j++] = max(0, min(R, 255));
+	}
+//	*/
+}
Index: trunk/src/testing/app/hd-video-player/Utils2.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/Utils2.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/Utils2.cpp	(revision 4)
@@ -0,0 +1,83 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "stdafx.h"
+#include "Utils2.h"
+
+
+// This code was also brazenly stolen from the DX9 SDK
+// Pass it a file name in wszPath, and it will save the filter graph to that file.
+HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath)
+{
+    const WCHAR wszStreamName[] = L"ActiveMovieGraph";
+    HRESULT hr;
+    IStorage *pStorage = NULL;
+
+	// First, create a document file which will hold the GRF file
+	hr = StgCreateDocfile(
+        wszPath,
+        STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+        0, &pStorage);
+    if(FAILED(hr))
+    {
+        return hr;
+    }
+
+	// Next, create a stream to store.
+    IStream *pStream;
+    hr = pStorage->CreateStream(
+		wszStreamName,
+        STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+        0, 0, &pStream);
+    if (FAILED(hr))
+    {
+        pStorage->Release();
+        return hr;
+    }
+
+	// The IPersistStream converts a stream into a persistent object.
+    IPersistStream *pPersist = NULL;
+    pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast<void**>(&pPersist));
+    hr = pPersist->Save(pStream, TRUE);
+    pStream->Release();
+    pPersist->Release();
+    if (SUCCEEDED(hr))
+    {
+        hr = pStorage->Commit(STGC_DEFAULT);
+    }
+    pStorage->Release();
+    return hr;
+}
Index: trunk/src/testing/app/hd-video-player/YUV_RGB.h
===================================================================
--- trunk/src/testing/app/hd-video-player/YUV_RGB.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YUV_RGB.h	(revision 4)
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#ifndef _YUV_RGB_
+#define _YUV_RGB_
+
+#include <windows.h>
+#include "stdafx.h"
+
+// nominal luma range
+#define MIN_LUMA		16
+#define MAX_LUMA		235
+#define LUMA_RANGE	(MAX_LUMA - MIN_LUMA + 1)	 // Total number of valid luma values
+
+#define clipRGB(x) clip((x), 0, 255)
+#define clipYUV(x) clip((x), MIN_LUMA, MAX_LUMA)
+
+typedef struct _UYVY {
+	unsigned char u;
+	unsigned char y0;
+	unsigned char v;
+	unsigned char y1;
+}UYVY_ARRAY;
+
+void SaveToBmp(char *Path, unsigned char *img_buff, int width, int height, int bitcount);
+
+inline long clip(long i, long min, long max)
+{
+    if (i < min) return min;
+    if (i > max) return max;
+    return i;
+}
+
+// RGB2YUV: Convert an RGB pixel to YUV
+
+inline BYTE RGB2Y(DWORD r, DWORD g, DWORD b)
+{
+    BYTE luma = static_cast<BYTE>(( (  66 * r + 129 * g +  25 * b + 128) >> 8) +  16);
+    _ASSERTE(luma >= MIN_LUMA);
+    _ASSERTE(luma <= MAX_LUMA);
+    return luma;
+}
+
+inline BYTE RGB2U(DWORD r, DWORD g, DWORD b)
+{
+    return static_cast<BYTE>(( ( -38 * r -  74 * g + 112 * b + 128) >> 8) + 128);
+}
+
+inline BYTE RGB2V(DWORD r, DWORD g, DWORD b)
+{
+    return static_cast<BYTE>(( ( 112 * r -  94 * g -  18 * b + 128) >> 8) + 128);
+}
+
+// Convert YUV to RGB
+
+inline BYTE YUV2Red(long y, long u, long v)
+{
+    return static_cast<BYTE>(clipRGB(( 298 * (y - 16) + 409 * (v - 128) + 128) >> 8));
+}
+
+
+inline BYTE YUV2Green(long y, long u, long v)
+{
+    return static_cast<BYTE>((clipRGB(( 298 * (y - 16) - 100 * (u - 128) - 208 * (v - 128) + 128) >> 8)));
+}
+
+inline BYTE YUV2Blue(long y, long u, long v)
+{
+    return static_cast<BYTE>((clipRGB(( 298 * (y - 16) + 516 * (u - 128) + 128) >> 8)));
+}
+
+
+#endif
Index: trunk/src/testing/app/hd-video-player/YUV.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/YUV.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YUV.cpp	(revision 4)
@@ -0,0 +1,291 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "stdafx.h"
+#include "YUV.h"
+#include <windows.h>
+
+#define MYUCHAR(_flt_) ((_flt_>0 && _flt_<256)?_flt_:((_flt_<0)?0:255))
+
+
+/*
+  -. YUV422ToRGB24() added by shoong
+  -. pbYUV : YUV array (Y0UY1V Y2UY3V ...)
+  -. pbRGB : RGB array (RGB º¯È¯µÈ °á°ú°ª)
+  -. nFileLen : YUV file length
+*/
+void CYUVtoRGB24::YUV422YUY2_ToRGB24(BYTE *pbYUV, BYTE *pbRGB, int nFileLen)
+{
+    float B_Cb128,R_Cr128,G_CrCb128;
+    float Y0,U,Y1,V;
+    float R,G,B;
+
+	int j=0;
+
+    for (int i = 0; i < m_yuv_len; )
+    {
+        Y0 = 1.164f * ((float)pbYUV[i++]-16.0f);
+		U  = (float)pbYUV[i++]-128.0f;
+        Y1 = 1.164f * ((float)pbYUV[i++]-16.0f);
+		V  = (float)pbYUV[i++]-128.0f;
+
+        R_Cr128   =  1.596f*V;
+        G_CrCb128 = -0.813f*V - 0.391f*U;
+        B_Cb128   =  2.018f*U;
+
+		R= Y0 + R_Cr128;
+		G = Y0 + G_CrCb128;
+		B = Y0 + B_Cb128;
+
+		pbRGB[j++] = (unsigned char)MYUCHAR(B);
+		pbRGB[j++] = (unsigned char)MYUCHAR(G);
+		pbRGB[j++] = (unsigned char)MYUCHAR(R);
+
+		R= Y1 + R_Cr128;
+		G = Y1 + G_CrCb128;
+		B = Y1 + B_Cb128;
+
+		pbRGB[j++] = (unsigned char)MYUCHAR(B);
+		pbRGB[j++] = (unsigned char)MYUCHAR(G);
+		pbRGB[j++] = (unsigned char)MYUCHAR(R);
+    }
+}
+
+
+void CYUVtoRGB24::YUV422UYVY_ToRGB24(BYTE *pbYUV, BYTE *pbRGB, int width, int height, int Stride)
+{
+    float B_Cb128,R_Cr128,G_CrCb128;
+    float Y0,U,Y1,V;
+    float R,G,B;
+
+	int j=0;
+
+    for (DWORD y = 0; y < dwHeight; y++)
+    {
+        WORD *pwTarget = (WORD*)pbTarget;
+        WORD *pwSource = (WORD*)pbSource;
+
+        for (DWORD x = 0; x < dwWidth; x++)
+        {
+
+            // Each WORD is a 'UY' or 'VY' block.
+            // Set the low byte (chroma) to 0x80 and leave the high byte (luma)
+
+            WORD pixel = pwSource[x] & 0xFF00;
+            pixel |= 0x0080;
+            pwTarget[x] = pixel;
+        }
+
+        // Advance the stride on both buffers.
+
+        pbTarget += lStrideOut;
+        pbSource += lStrideIn;
+    }
+
+
+    for (int i = 0; i < m_yuv_len; )
+    {
+        Y0 = 1.164f * ((float)pbYUV[i++]-16.0f);
+		U  = (float)pbYUV[i++]-128.0f;
+        Y1 = 1.164f * ((float)pbYUV[i++]-16.0f);
+		V  = (float)pbYUV[i++]-128.0f;
+
+        R_Cr128   =  1.596f*V;
+        G_CrCb128 = -0.813f*V - 0.391f*U;
+        B_Cb128   =  2.018f*U;
+
+		R= Y0 + R_Cr128;
+		G = Y0 + G_CrCb128;
+		B = Y0 + B_Cb128;
+
+		pbRGB[j++] = (unsigned char)MYUCHAR(B);
+		pbRGB[j++] = (unsigned char)MYUCHAR(G);
+		pbRGB[j++] = (unsigned char)MYUCHAR(R);
+
+		R= Y1 + R_Cr128;
+		G = Y1 + G_CrCb128;
+		B = Y1 + B_Cb128;
+
+		pbRGB[j++] = (unsigned char)MYUCHAR(B);
+		pbRGB[j++] = (unsigned char)MYUCHAR(G);
+		pbRGB[j++] = (unsigned char)MYUCHAR(R);
+    }
+}
+
+
+/*
+  -. YUV420ToRGB24() added by shoong
+  -. ŸÆ·¡¿Í °°ÀÌ ÀúÀåµÈ YUV420 fileÀ» RGB·Î º¯È¯ (IMC4 ÇüÅÂ)
+	+------------------+
+	|                          |
+	|           Y             |
+	+------------------+
+	|    Cb    |    Cr      |
+	+--------+---------+
+*/
+void CYUVtoRGB24::YUV420ToRGB24(BYTE *pbYUV, BYTE *pbRGB, int nWidth, int nHeight)
+{
+	int i, j;
+	int dataLeng = nHeight * nWidth;
+	BYTE* yData = new BYTE[dataLeng];
+	BYTE* uData = new BYTE[dataLeng];
+	BYTE* vData = new BYTE[dataLeng];
+	int nIndex = dataLeng;
+	int offset;
+
+	ZeroMemory(yData, dataLeng);
+	ZeroMemory(uData, dataLeng);
+	ZeroMemory(vData, dataLeng);
+
+	// Y-Data ÀÔ·Â
+	for(i = 0; i < dataLeng; i++)
+	{
+		yData[i] = pbYUV[i];
+	}
+
+	offset = dataLeng;
+	// U-Data ÀÔ·Â
+	for(i = 0; i < nHeight -2; i++)
+	{
+		for(j = 0; j < nWidth; j++)
+			uData[i*nWidth + j] = pbYUV[dataLeng + (int(i/2))*nWidth/2 + (int(j/2))];
+	}
+
+	// V-Data ÀÔ·Â
+	for(i = 0; i < nHeight -2; i++)
+	{
+		for(j = 0; j < nWidth; j++)
+			vData[i*nWidth + j] = pbYUV[dataLeng * (int)5/4 + (int(i/2))*nWidth/2 + (int(j/2))];
+	}
+
+	// Convert to RGB
+	BYTE r = 0;
+	BYTE g = 0;
+	BYTE b = 0;
+
+/*
+
+  Y=0.3R+0.59G +0.11B
+U=(B-Y)x0.493
+V=(R-Y)x0.877
+
+R=Y+0.956U+0.621V
+G=Y+0.272U+0.647V
+B=Y+1.1061U+1.703V
+
+*/
+	for(i = 0; i < dataLeng; i++)
+	{
+
+//		pbRGB[i*3] = max(0, min(yData[i] + 0.956 * uData[i] + 0.621 * vData[i], 255));
+//		pbRGB[i*3+1] = max(0, min(yData[i] + 0.272 * uData[i] + 0.647 * vData[i], 255));
+//		pbRGB[i*3+2] = max(0, min(yData[i] + 1.1061 * uData[i] + 1.703 * vData[i], 255));
+
+		pbRGB[i*3] = CYUVTable::GetB((int)yData[i], (int)uData[i], (int)vData[i]);
+		pbRGB[i*3+1] = CYUVTable::GetG((int)yData[i], (int)uData[i], (int)vData[i]);
+		pbRGB[i*3+2] = CYUVTable::GetR((int)yData[i], (int)uData[i], (int)vData[i]);
+	}
+
+	delete [] yData;
+	delete [] uData;
+	delete [] vData;
+}
+
+
+
+CYUVtoRGB24::CYUVtoRGB24() {
+
+	m_yuv_len = m_rgb_len = m_yuv_type = 0;
+	m_rgb_buff = m_yuv_buff = NULL;
+}
+
+CYUVtoRGB24::~CYUVtoRGB24() {
+	free(m_yuv_buff);
+	free(m_rgb_buff);
+}
+
+// copy image data to yuv_buff
+int CYUVtoRGB24::SetYuvImage(unsigned char* buff, int yuv_len, int width, int height, int type = YUV420) {
+
+	if(!buff) return 0;
+
+	m_width = width;
+	m_height = height;
+	m_yuv_len = yuv_len;
+	m_rgb_len = m_width * m_height * 3;
+
+	if(type == YUV420) m_yuv_type = YUV420;
+	else if(type == YUV422) m_yuv_type = YUV422;
+	else return 0;
+
+	// If previous yuv_image exist, delete and allocate at new
+	if(m_yuv_buff) free(m_yuv_buff);
+	m_yuv_buff = (unsigned char*)malloc(sizeof(char) *  m_yuv_len);
+
+	memcpy(m_yuv_buff, buff, m_yuv_len);
+}
+
+
+// Conversion yuv data to RGB32 as defined yuv_type
+int CYUVtoRGB24::YUVtoRGB(void) {
+
+	if(!m_yuv_buff) return 0;
+
+	switch(m_yuv_type) {
+	case YUV420 :
+		if(!m_rgb_buff) free(m_rgb_buff);
+		m_rgb_buff = (unsigned char*)malloc(m_width * m_height * 3);
+
+		YUV420ToRGB24(m_yuv_buff, m_rgb_buff, m_width, m_height);
+		break;
+	case YUV422 :
+		if(!m_rgb_buff) free(m_rgb_buff);
+		m_rgb_buff = (unsigned char*)malloc(m_width * m_height * 3);
+
+		YUV422ToRGB24(m_yuv_buff, m_rgb_buff, m_yuv_len) ;
+		break;
+	default :
+		return 0;
+	}
+
+	return 1;
+
+}
+
+// return rgb image data
+unsigned char* CYUVtoRGB24::GetRgbImage(void) {
+	return m_rgb_buff;
+}
Index: trunk/src/testing/app/hd-video-player/YuvToRGB.h
===================================================================
--- trunk/src/testing/app/hd-video-player/YuvToRGB.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YuvToRGB.h	(revision 4)
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _YUVTORGB_
+#define _YUVTORGB_
+
+#define PTW32_STATIC_LIB 1
+#include <pthread.h>
+
+
+
+#include <windows.h>
+#include <stdio.h>
+
+#define LOG_INT		0
+#define LOG_STR		1
+
+class CYUVTable
+{
+public :
+	// Static methods
+	static BYTE GetY(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int y = (int)(0.299 * p_nR + 0.587 * p_nG + 0.114 * p_nB);
+		return max(0, min(y, 255));
+	};
+	static BYTE GetU(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int u = (int)(-0.169 * p_nR - 0.311 * p_nG + 0.500 * p_nB) + 128;
+		return max(0, min(u, 255));
+	};
+	static BYTE GetV(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int v = (int)(0.500 * p_nR - 0.419 * p_nG - 0.081 * p_nB) + 128;
+		return max(0, min(v, 255));
+	};
+
+//		pbRGB[i*3] = Y+0.956U+0.621V
+//		pbRGB[i*3+1] = Y+0.272U+0.647V
+//		pbRGB[i*3+2] = Y+1.1061U+1.703V
+
+	static BYTE GetR(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int r = (int)(p_nY - 0.001 * (p_nU - 128) + 1.402 * (p_nV - 128));
+		return max(0, min(r, 255));
+	};
+	static BYTE GetG(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int g = (int)(p_nY - 0.344 * (p_nU - 128) - 0.714 * (p_nV - 128));
+		return max(0, min(g, 255));
+	};
+	static BYTE GetB(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int b = (int)(p_nY + 1.772 * (p_nU - 128) + 0.001 * (p_nV - 128));
+		return max(0, min(b, 255));
+	};
+};
+
+void YUV422UYVY_ToRGB24(unsigned char* pbYUV, unsigned char* pbRGB, DWORD yuv_len);
+
+void SaveToBmp(char *Path, unsigned char* img_buff, int width, int height, int bitcount);
+
+void SaveToLog(void* string, int type);
+
+#endif
Index: trunk/src/testing/app/hd-video-player/Utils2.h
===================================================================
--- trunk/src/testing/app/hd-video-player/Utils2.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/Utils2.h	(revision 4)
@@ -0,0 +1,132 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#ifndef _UTIL2_
+#define _UTIL2_
+
+#include <dvdmedia.h>
+
+HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath);
+
+class C_SaveToLog {
+	FILE *fp;
+	char fileName[125];
+
+	int index;
+	char string[1024];
+
+public :
+	C_SaveToLog(char*str = NULL) {
+		if(str == NULL)
+			strcpy(fileName, "log.txt");
+		else
+			strcpy(fileName, str);
+
+		fp = fopen(fileName, "w");
+
+		fprintf(fp, "<Log file> \n ");
+
+		index = 0;
+	}
+
+	~C_SaveToLog() {
+		if(fp)
+			fclose(fp);
+	}
+
+	void ToLog(char* str) {
+		if(fp)
+			fprintf(fp, "%s", str);
+	}
+
+	void ToLog(int input) {
+		if(fp)
+			fprintf(fp, "%d", input);
+	}
+
+	void ToLog(char* str, int len) {
+		if(fp) {
+			char tmp[1024];
+			strncpy(tmp, str, len);
+			strcat(tmp, "");
+			fprintf(fp, "\n Len(%d) : %s", len, tmp);
+		}
+	}
+
+	void ToLog16(char* str, int len) {
+		if(fp) {
+			char tmp[1024];
+			strncpy(tmp, str, len);
+			strcat(tmp, "");
+			fprintf(fp, "\n Len(%d) : %d", len, tmp);
+			for(int i = 0; i < len; i++)
+				fprintf(fp, "\n %x", tmp[i]);
+		}
+	}
+
+	void CleanStr(void) {
+		index = 0;
+	}
+
+	void ToStr(char* str) {
+		strcpy(&string[index], str);
+		index += strlen(string);
+	}
+
+	void ToStr(int input) {
+		char str[100];
+
+		itoa(input, str, 10);
+		strcpy(&string[index], str);
+		index += strlen(string);
+	}
+
+	void SaveStr(void) {
+		if(fp)
+			fprintf(fp, "\n%s", string);
+	}
+};
+
+
+#ifdef _MAIN_
+class C_SaveToLog SaveLog(NULL);
+#else
+extern class C_SaveToLog SaveLog;
+#endif
+
+
+#endif
Index: trunk/src/testing/app/hd-video-player/GrabberProc.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/GrabberProc.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/GrabberProc.cpp	(revision 4)
@@ -0,0 +1,784 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "StdAfx.h"
+#include <aviriff.h>  // defines 'FCC' macro
+
+#include "math.h"
+#include "YUV_RGB.h"
+
+#include "GrabberProc.h"
+#include "Utils2.h"
+
+//------------------------------------
+// If you want to test with saving BMP files, delete this define.
+#define _SAGE_
+//------------------------------------
+
+//-------------------------------------------------------------------------------------------
+//=================================[ class GrabberCB ]=======================================
+//-------------------------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------------------------
+GrabberCB::GrabberCB() : m_fFirstSample(true)
+{
+}
+
+//-------------------------------------------------------------------------------------------
+GrabberCB::~GrabberCB()
+{
+}
+
+//-------------------------------------------------------------------------------------------
+// Support querying for ISampleGrabberCB interface
+HRESULT GrabberCB::QueryInterface(REFIID iid, void**ppv)
+{
+    if (!ppv) { return E_POINTER; }
+    if (iid == IID_IUnknown)
+    {
+        *ppv = static_cast<IUnknown*>(this);
+    }
+    else if (iid == IID_ISampleGrabberCB)
+    {
+        *ppv = static_cast<ISampleGrabberCB*>(this);
+    }
+    else
+    {
+        return E_NOINTERFACE;
+    }
+    AddRef();  // We don't actually ref count, but in case we change the implementation later.
+    return S_OK;
+}
+
+//-------------------------------------------------------------------------------------------
+// SampleCB: This is where we process each sample
+HRESULT GrabberCB::SampleCB(double SampleTime, IMediaSample *pSample)
+{
+	static int init_flag = 0;
+/*
+	FILE *fp;
+
+	fp = fopen("./log.dat", "w");
+	fprintf(fp, "\r\nin sampleCB");
+	fclose(fp);
+*/
+
+    HRESULT hr;
+
+    // Get the pointer to the buffer
+    BYTE *pBuffer;
+    hr = pSample->GetPointer(&pBuffer);
+
+	// This funtion must be called every time
+	m_GrabProc.SetImageBuffer(pBuffer);
+
+    if (FAILED(hr))
+    {
+        OutputDebugString(TEXT("SampleCB: GetPointer FAILED\n"));
+        return hr;
+    }
+
+    // Scan the image on the first sample. Re-scan is there is a discontinuity.
+    // (This will produce horrible results if there are big scene changes in the
+    // video that are not associated with discontinuities. Might be safer to re-scan
+    // each image, at a higher perf cost.)
+
+#ifdef _SAGE_
+	// RGB -> Send
+	//if(m_GrabProc.GetSageOn() == true) {
+		hr = m_GrabProc.SendToSage();
+	//}
+#else
+    // Convert the image
+	// RGB -> Save
+	hr = m_GrabProc.SendToBmp();
+	// YUV -> RGB -> Send or Save
+//	hr = m_GrabProc.ConvertImage();
+#endif
+
+	if(FAILED(hr)) {
+		exit(1);
+	}
+
+    return hr;
+}
+
+//-------------------------------------------------------------------------------------------
+//=================================[ class AudioGrabberCB ]=======================================
+//-------------------------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------------------------
+AudioGrabberCB::AudioGrabberCB() : m_fFirstSample(true), m_index(0)
+{
+	m_GrabProc = NULL;
+}
+
+//-------------------------------------------------------------------------------------------
+AudioGrabberCB::~AudioGrabberCB()
+{
+}
+
+//-------------------------------------------------------------------------------------------
+// Support querying for ISampleGrabberCB interface
+HRESULT AudioGrabberCB::QueryInterface(REFIID iid, void**ppv)
+{
+    if (!ppv) { return E_POINTER; }
+    if (iid == IID_IUnknown)
+    {
+        *ppv = static_cast<IUnknown*>(this);
+    }
+    else if (iid == IID_ISampleGrabberCB)
+    {
+        *ppv = static_cast<ISampleGrabberCB*>(this);
+    }
+    else
+    {
+        return E_NOINTERFACE;
+    }
+    AddRef();  // We don't actually ref count, but in case we change the implementation later.
+    return S_OK;
+}
+
+//-------------------------------------------------------------------------------------------
+// SampleCB: This is where we process each sample
+HRESULT AudioGrabberCB::SampleCB(double SampleTime, IMediaSample *pSample)
+{
+
+    HRESULT hr;
+
+	// Get the pointer to the buffer
+    BYTE *pBuffer;
+    hr = pSample->GetPointer(&pBuffer);
+
+	/////// for the test
+	int lenBuf = pSample->GetActualDataLength();
+
+	// This funtion must be called every time
+	m_GrabProc->SetAudioBuffer(pBuffer);
+
+    if (FAILED(hr))
+    {
+        OutputDebugString(TEXT("SampleCB: GetPointer FAILED\n"));
+        return hr;
+    }
+
+    // Scan the image on the first sample. Re-scan is there is a discontinuity.
+    // (This will produce horrible results if there are big scene changes in the
+    // video that are not associated with discontinuities. Might be safer to re-scan
+    // each image, at a higher perf cost.)
+
+#ifdef _SAGE_
+	// RGB -> Send
+	//if(m_GrabProc->GetSageOn() == true) {
+		hr = m_GrabProc->SendAudioToSage(lenBuf);
+	//}
+#else
+
+#endif
+
+	if(FAILED(hr)) {
+		exit(1);
+	}
+
+    return hr;
+}
+
+
+//-------------------------------------------------------------------------------------------
+//=================================[ class GrabProc ]=======================================
+//-------------------------------------------------------------------------------------------
+
+// #define _YUVtransF_
+
+#define MAX_SUB_TYPE	4
+GUID media_type_ary[] = {MEDIASUBTYPE_RGB24, MEDIASUBTYPE_UYVY, MEDIASUBTYPE_YUY2, MEDIASUBTYPE_YUYV};
+
+// {A6512C9F-A47B-45ba-A054-0DB0D4BB87F7}
+//static const GUID CLSID_YuvGray =
+//{ 0xa6512c9f, 0xa47b, 0x45ba, { 0xa0, 0x54, 0xd, 0xb0, 0xd4, 0xbb, 0x87, 0xf7 } };
+//{ 0xB179A682, 0x641B, 0x11D2, { 0xA4, 0xD9, 0x00, 0x60, 0x08, 0x0B, 0xA6, 0x34} };
+
+//{B179A682-641B-11D2-A4D9-0060080BA634}
+#ifdef _YUVtransF_
+static const GUID CLSID_YUVxfm =
+{ 0xB179A682, 0x641B, 0x11D2, { 0xA4, 0xD9, 0x00, 0x60, 0x08, 0x0B, 0xA6, 0x34} };
+#endif
+
+//{ 0xa6512c9f, 0xa47b, 0x45ba, { 0xa0, 0x54, 0xd, 0xb0, 0xd4, 0xbb, 0x87, 0xf7 } };
+// {B179A682-641B-11D2-A4D9-0060080BA634}
+//DEFINE_GUID(CLSID_YUVxfm,
+//0xB179A682, 0x641B, 0x11D2, 0xA4, 0xD9, 0x00, 0x60, 0x08, 0x0B, 0xA6, 0x34);
+// 0x2fa4f053, 0x6d60, 0x4cb0, 0x95, 0x3, 0x8e, 0x89, 0x23, 0x4f, 0x3f, 0x73);
+
+//-------------------------------------------------------------------------------------------
+C_GrabProc::C_GrabProc(void) {
+	m_pGrabF = NULL;
+	m_pAudioGrabF = NULL;
+	m_pYUVtransF = NULL;
+
+	m_dwWidth = m_dwHeight = m_lStride = m_iBitDepth;
+	m_pImg = NULL;
+	m_pAudioSamples = NULL;
+	m_pbRGB_buff = NULL;
+	m_sageOn = false;
+}
+
+
+//-------------------------------------------------------------------------------------------
+void C_GrabProc::FreeFilter(void) {
+//	m_pGrabF->Release();
+
+///*
+	if(m_pGrabF) {
+		grabberCallback.Release();
+
+#ifdef _YUVtransF_
+		delete m_pYUVtransF;
+		m_pYUVtransF = NULL;
+#endif
+
+// Don't use delete with filter. Delete is ungraceful
+//		delete m_pGrabF;
+		m_pGrabF = NULL;
+	}
+// */
+	if(m_pbRGB_buff) {
+		free(m_pbRGB_buff);
+		m_pbRGB_buff = NULL;
+	}
+}
+
+HRESULT C_GrabProc::SetFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName, int out_color_mode, bool sage) {
+	HRESULT hr;
+
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"Before Add filter.GRF"));
+
+	m_sageOn = sage;
+#ifdef _YUVtransF_
+		hr = CDSUtils::AddFilter(pGraph, CLSID_YUVxfm, L"YUV Transform", &m_pYUVtransF);
+#endif
+
+	if(m_pGrabF == NULL) {
+		hr = CDSUtils::AddFilter(pGraph, CLSID_SampleGrabber, L"Grabber", &m_pGrabF);
+		if(hr < 0) {
+			//SaveLog.ToLog("\n Can not Add filter : Grabber.");
+			return hr;
+		}
+		//SaveLog.ToLog("\n Grabber is added ");
+		//SaveLog.ToLog((int)&m_pGrabF);
+	}
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"Before connect filter.GRF"));
+
+    CComQIPtr<ISampleGrabber> pGrabber(m_pGrabF);
+
+//	if(++m_sub_type > MAX_SUB_TYPE) return -1;
+
+	// Configure the sample grabber
+	ZeroMemory(&m_mt, sizeof(AM_MEDIA_TYPE));
+	m_mt.majortype = MEDIATYPE_Video;
+	m_mt.formattype = FORMAT_VideoInfo;
+
+	if(out_color_mode == RGB24) m_mt.subtype = MEDIASUBTYPE_RGB24;
+		else if(out_color_mode == RGB16) m_mt.subtype = MEDIASUBTYPE_RGB565;
+			else if(out_color_mode == YUV)m_mt.subtype = MEDIASUBTYPE_UYVY;
+				else {
+					//SaveLog.ToLog("\n Color mode is not correct");
+					return -1;
+				}
+
+
+	// Note: I don't expect the next few methods to fail ....
+	hr = pGrabber->SetMediaType(&m_mt);  // Set the media type we want for the connection.
+	hr = pGrabber->SetOneShot(FALSE);  // Disable "one-shot" mode
+	hr = pGrabber->SetBufferSamples(FALSE); // Disable sample buffering
+	hr = pGrabber->SetCallback(&grabberCallback, 0); // Set our callback. '0' means 'use the SampleCB callback'
+
+#ifdef _YUVtransF_
+
+	hr = CDSUtils::ConnectFilters(pGraph, pUpstream, pUpstreamPinName, m_pYUVtransF, NULL);
+	//if(hr < 0) SaveLog.ToLog("\n Can not ConnectFilter : YUV Transform.");
+	//SaveGraphFile(pGraph, L"ConnectYUVtransF.GRF");
+	hr = CDSUtils::ConnectFilters(pGraph, m_pYUVtransF, L"XForm Out", m_pGrabF, NULL);
+//	hr = CDSUtils::ConnectFilters(pGraph, m_pYUVtransF, pUpstreamPinName, m_pGrabF, NULL);
+	//if(hr < 0) SaveLog.ToLog("\n Can not ConnectFilter : Grabber.");
+	//SaveGraphFile(pGraph, L"ConnectGrabber.GRF");
+#else
+	hr = CDSUtils::ConnectFilters(pGraph, pUpstream, pUpstreamPinName, m_pGrabF, NULL);
+	if(hr < 0) {
+		//SaveLog.ToLog("\n Can not ConnectFilter : Grabber.");
+		return hr;
+	}
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"ConnectGrabber.GRF"));
+#endif
+	// If input is YUV, add YUVtransform filter.
+	//SaveLog.ToLog("\n In SetFilter m_sub_type");
+	//SaveLog.ToLog(m_sub_type);
+/*
+	if(m_sub_type == 0) {
+
+	} else {
+		hr = CDSUtils::ConnectFilters(pGraph, pUpstream, NULL, m_pGrabF, NULL);
+		if(FAILED(hr)) continue;
+	}
+*/
+	// Find out the exact video format.
+	hr = pGrabber->GetConnectedMediaType(&m_mt);
+	if (FAILED(hr))
+	{
+		//SaveLog.ToLog("\nCould not get the video format.");
+		return -1;
+	}
+
+	VIDEOINFOHEADER *pVih;
+	pVih = reinterpret_cast<VIDEOINFOHEADER*>(m_mt.pbFormat);
+
+	if(SetVideoFormat(*pVih, out_color_mode) < 0, sage) return -1;
+	CoTaskMemFree(m_mt.pbFormat);
+
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"InSetFilter.GRF"));
+
+//	if(pGrabber) delete pGrabber;
+//	SAFE_RELEASE(pGrabber);
+
+	return hr;
+}
+HRESULT C_GrabProc::SetAudioFilter(IGraphBuilder* pGraph, IBaseFilter* pUpstream, wchar_t* pUpstreamPinName)
+{
+	HRESULT hr;
+	AudioGrabCallback.m_GrabProc = this;
+
+	EXECUTE_ASSERT(ERROR_SUCCESS == SaveGraphFile(pGraph, L"Before Add filter.GRF"));
+
+	hr = CDSUtils::AddFilter(pGraph, CLSID_SampleGrabber, L"Audio Grabber", &m_pAudioGrabF);
+	if(hr < 0) {
+		//SaveLog.ToLog("\n Can not Add filter : Audio Grabber.");
+		return hr;
+	}
+	//SaveLog.ToLog("\n Grabber is added ");
+	//SaveLog.ToLog((int)&m_pAudioGrabF);
+	EXECUTE_ASSERT(ERROR_SUCCESS == SaveGraphFile(pGraph, L"Before connect filter.GRF"));
+
+    CComQIPtr<ISampleGrabber> pGrabber(m_pAudioGrabF);
+
+	// mediatype definition
+	/*typedef struct _MediaType {
+		GUID     majortype;
+		GUID     subtype;
+		BOOL     bFixedSizeSamples;
+		BOOL     bTemporalCompression;
+		ULONG    lSampleSize;
+		GUID     formattype;
+		IUnknown *pUnk;
+		ULONG    cbFormat;
+		BYTE     *pbFormat;
+	} AM_MEDIA_TYPE;*/
+
+	// Configure the sample grabber
+	ZeroMemory(&m_audiomt, sizeof(AM_MEDIA_TYPE));
+	m_audiomt.majortype = MEDIATYPE_Audio;
+	m_audiomt.subtype = MEDIASUBTYPE_PCM;
+	m_audiomt.lSampleSize = 1024 * 2 * 2; //(16 but-> 2byte) // Size of the sample in bytes. For compressed data, the value can be zero
+	m_audiomt.bFixedSizeSamples = TRUE;		// 1024 1536
+	m_audiomt.bTemporalCompression = FALSE;
+	m_audiomt.formattype = FORMAT_WaveFormatEx;
+
+	// Allocate the format block to hold the WAVEFORMATEX structure.
+	// waveformat definition
+	/*typedef struct
+	{
+	  WORD  wFormatTag;
+	  WORD  nChannels;
+	  DWORD  nSamplesPerSec;
+	  DWORD  nAvgBytesPerSec;
+	  WORD  nBlockAlign;
+	  WORD  wBitsPerSample;
+	  WORD  cbSize;
+	} WAVEFORMATEX; *PWAVEFORMATEX;|*/
+
+	WAVEFORMATEX *pwav = new WAVEFORMATEX;
+	m_audiomt.pbFormat = (BYTE *)pwav;
+	//WAVEFORMATEX *pwav = (WAVEFORMATEX*)m_audiomt.pbFormat;
+
+	//WAVE_FORMAT_PCM 	PCM (pulse-code modulated) data in integer format.
+	//WAVE_FORMAT_IEEE_FLOAT 	PCM data in IEEE floating-point format.
+	//WAVE_FORMAT_DRM 	DRM-encoded format (for digital-audio content protected by Microsoft Digital Rights Management).
+	//WAVE_FORMAT_EXTENSIBLE 	Extended WAVEFORMATEX structure (see WAVEFORMATEXTENSIBLE).
+	//WAVE_FORMAT_ALAW 	A-law-encoded format.
+	//WAVE_FORMAT_MULAW 	Mu-law-encoded format.
+	//WAVE_FORMAT_ADPCM 	ADPCM (adaptive differential pulse-code modulated) data.
+	//WAVE_FORMAT_MPEG 	MPEG-1 data format (stream conforms to ISO 11172-3 Audio specification).
+	//WAVE_FORMAT_DOLBY_AC3_SPDIF 	AC3 (aka Dolby Digital) over S/PDIF.
+	pwav->wFormatTag = WAVE_FORMAT_PCM;
+
+	pwav->nChannels = 2;
+	pwav->nSamplesPerSec = 48000;
+
+	// Specifies the number of bits per sample for the format type specified by wFormatTag.
+	// If wFormatTag = WAVE_FORMAT_PCM, then wBitsPerSample should be set to either 8 or 16.
+	pwav->wBitsPerSample = 16;
+
+	// Specifies the block alignment in bytes. The block alignment is the size of the minimum
+	// atomic unit of data for the wFormatTag format type. If wFormatTag = WAVE_FORMAT_PCM,
+	// set nBlockAlign to (nChannels*wBitsPerSample)/8, which is the size of a single audio frame.
+	pwav->nBlockAlign = (pwav->nChannels * pwav->wBitsPerSample)/8;
+
+	pwav->nAvgBytesPerSec = pwav->nSamplesPerSec * pwav->nBlockAlign;
+
+	// Specifies the size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure.
+	// This information can be used by non-PCM formats to store extra attributes for the wFormatTag.
+	pwav->cbSize = 0;
+
+	// Note: I don't expect the next few methods to fail ....
+	hr = pGrabber->SetMediaType(&m_audiomt);  // Set the media type we want for the connection.
+	hr = pGrabber->SetOneShot(FALSE);  // Disable "one-shot" mode
+	hr = pGrabber->SetBufferSamples(FALSE); // Disable sample buffering
+	hr = pGrabber->SetCallback(&AudioGrabCallback,0); // Set our callback. '0' means 'use the SampleCB callback'
+
+	hr = CDSUtils::ConnectFilters(pGraph, pUpstream, pUpstreamPinName, m_pAudioGrabF, NULL);
+	if(hr < 0) {
+		//SaveLog.ToLog("\n Can not ConnectFilter : Audio Grabber.");
+		return hr;
+	}
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"ConnectGrabber.GRF"));
+
+	// Find out the exact video format.
+	hr = pGrabber->GetConnectedMediaType(&m_audiomt);
+	if (FAILED(hr))
+	{
+		//SaveLog.ToLog("\nCould not get the audio format.");
+		return -1;
+	}
+
+#ifdef _SAGE_
+	//if(m_sageOn == true) {
+		if(Out_sail.init(pwav->nAvgBytesPerSec) < 0)
+			return -1;
+
+	//}	//Out_sail.setSailEnv(NULL, 1);
+#endif
+
+	//CoTaskMemFree(m_mt.pbFormat);
+
+	EXECUTE_ASSERT(ERROR_SUCCESS ==SaveGraphFile(pGraph, L"InSetFilter.GRF"));
+
+	return hr;
+}
+
+void C_GrabProc::Shutdown()
+{
+#ifdef _SAGE_
+	//if(m_sageOn == true) {
+		Out_sail.shutdown();
+	//}
+	//Out_sail.setSailEnv(NULL, 1);
+#endif
+}
+
+//-------------------------------------------------------------------------------------------
+IBaseFilter* C_GrabProc::GrabF(void) {
+	return m_pGrabF;
+}
+
+void C_GrabProc::setIP(CString ip)
+{
+	m_ip = ip;
+}
+
+// SetFormat: Sets the image format (height, width, etc).
+
+// Use UYVY only!
+/*
+typedef struct tagVIDEOINFOHEADER {
+
+    RECT            rcSource;          // The bit we really want to use
+    RECT            rcTarget;          // Where the video should go
+    DWORD           dwBitRate;         // Approximate bit data rate
+    DWORD           dwBitErrorRate;    // Bit error rate for this stream
+    REFERENCE_TIME  AvgTimePerFrame;   // Average time per frame (100ns units)
+
+    BITMAPINFOHEADER bmiHeader;
+
+} VIDEOINFOHEADER;
+*/
+//-------------------------------------------------------------------------------------------
+HRESULT C_GrabProc::SetVideoFormat(const VIDEOINFOHEADER& vih, int color_mode)
+{
+
+// /*
+    // Check if UYVY
+	char tmp[125];
+	//SaveLog.ToLog("\n In SetFormat ");
+//	SaveLog.ToLog((char*)&(vih.bmiHeader.biCompression), sizeof(DWORD));
+//	SaveLog.ToLog16((char*)&(vih.bmiHeader.biCompression), sizeof(DWORD));
+
+	if (vih.bmiHeader.biCompression == BI_RGB)
+    {
+		//SaveLog.ToLog("\r\n It is RGB24");
+    }
+
+	if (vih.bmiHeader.biCompression == FCC('UYVY'))
+    {
+		//SaveLog.ToLog("\r\n It's UYVY");
+    }
+
+	if (vih.bmiHeader.biCompression == FCC('YUYV'))
+    {
+		//SaveLog.ToLog("\r\n It's YUYV");
+    }
+
+	if (vih.bmiHeader.biCompression == FCC('2YUV'))
+    {
+		//SaveLog.ToLog("\r\n It's 2YUV");
+    }
+
+	if (vih.bmiHeader.biCompression == FCC('YUV2'))
+    {
+		//SaveLog.ToLog("\r\n It's YUV2");
+    }
+/*
+	if (vih.bmiHeader.biCompression != FCC('UYVY'))
+    {
+		//SaveLog.ToLog("\r\n In SetFormat : It's not UYVY");
+        return E_INVALIDARG;
+    }
+// */
+    int BytesPerPixel = vih.bmiHeader.biBitCount / 8;
+
+    // If the target rectangle (rcTarget) is empty, the image width and the stride are both biWidth.
+    // Otherwise, image width is given by rcTarget and the stride is given by biWidth.
+
+    if (IsRectEmpty(&vih.rcTarget))
+    {
+        m_dwWidth = vih.bmiHeader.biWidth;
+        m_lStride = m_dwWidth;
+    }
+    else
+    {
+        m_dwWidth = vih.rcTarget.right;
+        m_lStride = vih.bmiHeader.biWidth;
+    }
+
+    m_lStride = (m_lStride * BytesPerPixel + 3) & ~3; // stride for UYVY is rounded to the nearest DWORD
+
+    m_dwHeight = abs(vih.bmiHeader.biHeight);  // biHeight can be < 0, but YUV is always top-down
+    m_iBitDepth = vih.bmiHeader.biBitCount;
+	m_out_color_mode = color_mode;
+
+	if(m_pbRGB_buff) {
+		free(m_pbRGB_buff);
+		m_pbRGB_buff = NULL;
+	}
+	m_bufLen = m_lStride * m_dwHeight;
+
+#ifdef _SAGE_
+	//if(m_sageOn == true) {
+		//int sail_init(int width, int height, int color_mode,char* output_addr, int output_port);
+		//if(Out_sail.init(m_dwWidth, m_dwHeight, m_out_color_mode, "192.168.81.120", 0) < 0)
+		char sip[25];
+		sprintf(sip, "%s", m_ip.GetBuffer());
+
+		if(Out_sail.init(m_dwWidth, m_dwHeight, m_out_color_mode, sip, 22000) < 0)
+			return -1;
+		//void setSailEnv(char* execConfigName, int nwID);
+		Out_sail.setSailEnv(NULL, 1);
+	//}
+#endif
+// /*
+	//SaveLog.ToLog("\nLog test");
+
+	//SaveLog.ToLog("\n width : ");
+	//SaveLog.ToLog(m_dwWidth);
+	//SaveLog.ToLog("height : ");
+	//SaveLog.ToLog(m_dwHeight);
+// */
+    return S_OK;
+}
+
+//-------------------------------------------------------------------------------------------
+HRESULT C_GrabProc::SetImageBuffer(BYTE *pBuffer)
+{
+    m_pImg = pBuffer;
+    return S_OK;
+}
+
+//-------------------------------------------------------------------------------------------
+HRESULT C_GrabProc::SetAudioBuffer(BYTE *pBuffer)
+{
+	/*m_startPoint
+	m_avgBytesPerSec
+
+	int m_startPoint;
+	int m_avgBytesPerSec;
+	int m_bitsPerSample;
+	int m_channels;
+*/
+	// seek first of pointer
+	/*if(m_bitsPerSample == 16) {
+		short* data = (short*) pBuffer;
+		int index = m_startPoint/2;
+		m_pAudioSamples = (BYTE *) &data[index];
+		// 2 bytes
+	}
+	else if(m_bitsPerSample == 8){
+		char* data = (char*) pBuffer;
+		m_pAudioSamples = (BYTE *) &data[m_startPoint];
+		// 1 bytes
+	}
+
+	m_startPoint += m_fixedSampleSize;
+	if(m_startPoint >= m_avgBytesPerSec) {
+		m_startPoint =0;
+	}*/
+
+	m_pAudioSamples = pBuffer;
+    return S_OK;
+}
+
+
+//-------------------------------------------------------------------------------------------
+// RGB -> Bmp file
+int C_GrabProc::SendToBmp(void) {
+	//SaveLog.ToLog("\n SendToBmp ");
+	char fileName[125];
+	static int index = 0;
+
+	sprintf(fileName, "outBmp_%0d.bmp", ++index);
+	SaveToBmp(fileName, m_pImg, m_dwWidth, m_dwHeight, 24);
+
+	return 1;
+}
+
+//-------------------------------------------------------------------------------------------
+// RGB -> sail
+int C_GrabProc::SendToSage(void) {
+	//SaveLog.ToLog("\n SendToSage ");
+	//void push_data(unsigned char* buf , int buf_len);
+	if(!m_pImg) return -1;
+	return Out_sail.push_data(m_pImg , m_bufLen);
+}
+
+//-------------------------------------------------------------------------------------------
+// AUDIOSAMPLES -> sail
+int C_GrabProc::SendAudioToSage(int buflen) {
+	//SaveLog.ToLog("\n SendToSage ");
+	if(!m_pAudioSamples) return -1;
+	return Out_sail.push_audiodata(m_pAudioSamples, buflen);
+}
+
+//-------------------------------------------------------------------------------------------
+// /*
+// YUV -> Bmp file or sail.
+HRESULT C_GrabProc::ConvertImage()
+{
+	//SaveLog.ToLog("\n ConvertImage ");
+	if (!m_pImg)
+    {
+        return E_UNEXPECTED;
+    }
+
+	if(!m_pbRGB_buff) {
+		m_pbRGB_buff = (unsigned char*)malloc(m_dwWidth * m_dwHeight * 3);
+	}
+
+	DWORD iRow, iPixel;  // looping variables
+    BYTE *pRow = m_pImg; // pointer to the first row in the buffer (don't care about image orientation)
+	unsigned char *in_buff, *out_buff;
+
+	UYVY_ARRAY uyvy;
+
+	in_buff = m_pImg;
+	out_buff = m_pbRGB_buff;
+
+    for (iRow = 0; iRow < m_dwHeight; iRow++)
+    {
+        for (iPixel = 0; iPixel < m_dwWidth; iPixel += 2)
+        {
+			memcpy(&uyvy, in_buff, 4);
+
+			// for saving in a file : BGR
+			// for sending to sail : RGB
+			*(out_buff) = YUV2Red(uyvy.y0, uyvy.u, uyvy.v);
+			*(++out_buff) = YUV2Green(uyvy.y0, uyvy.u, uyvy.v);
+			*(++out_buff) = YUV2Blue(uyvy.y0, uyvy.u, uyvy.v);
+			out_buff++;
+
+			*(out_buff) = YUV2Red(uyvy.y1, uyvy.u, uyvy.v);
+			*(++out_buff) = YUV2Green(uyvy.y1, uyvy.u, uyvy.v);
+			*(++out_buff) = YUV2Blue(uyvy.y1, uyvy.u, uyvy.v);
+			out_buff++;
+
+			in_buff += 4;
+
+//			//SaveLog.ToLog("\n iPixel : "); SaveLog.ToLog(iPixel);
+		}
+
+//	SaveLog.ToLog("\n----iRow : "); SaveLog.ToLog(iRow);
+    }
+
+#ifdef _SAGE_
+	//void push_data(unsigned char* buf , int buf_len);
+	Out_sail.push_data(m_pbRGB_buff , 0);
+#else
+	char fileName[125];
+	static int index = 0;
+	sprintf(fileName, "outBmp_%03d.bmp", ++index);
+	SaveToBmp(fileName, m_pbRGB_buff, m_dwWidth, m_dwHeight, 24);
+#endif
+
+    return S_OK;
+}
+
+void C_GrabProc::SetAudioOn(bool on)
+{
+#ifdef _SAGE_
+	//void push_data(unsigned char* buf , int buf_len);
+	Out_sail.setAudioOn(on);
+#endif
+}
+
+bool C_GrabProc::GetSageOn()
+{
+	return m_sageOn;
+}
+
+void C_GrabProc::SetAudioCaptureMode(bool on)
+{
+	if(on == true)
+	{
+		Out_sail.initAudioCaptureMode();
+	}
+}
+// */\\
Index: trunk/src/testing/app/hd-video-player/YUV.h
===================================================================
--- trunk/src/testing/app/hd-video-player/YUV.h	(revision 4)
+++ trunk/src/testing/app/hd-video-player/YUV.h	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _YUV_H
+#define _YUV_H
+
+#include <windows.h>
+#include "stdafx.h"
+
+#define YUV422	422
+#define YUV420	420
+
+class CYUVTable
+{
+public :
+	// Static methods
+	static BYTE GetY(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int y = (int)(0.299 * p_nR + 0.587 * p_nG + 0.114 * p_nB);
+		return max(0, min(y, 255));
+	};
+	static BYTE GetU(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int u = (int)(-0.169 * p_nR - 0.311 * p_nG + 0.500 * p_nB) + 128;
+		return max(0, min(u, 255));
+	};
+	static BYTE GetV(const BYTE p_nR, const BYTE p_nG, const BYTE p_nB)
+	{
+		int v = (int)(0.500 * p_nR - 0.419 * p_nG - 0.081 * p_nB) + 128;
+		return max(0, min(v, 255));
+	};
+
+//		pbRGB[i*3] = Y+0.956U+0.621V
+//		pbRGB[i*3+1] = Y+0.272U+0.647V
+//		pbRGB[i*3+2] = Y+1.1061U+1.703V
+
+	static BYTE GetR(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int r = (int)(p_nY - 0.001 * (p_nU - 128) + 1.402 * (p_nV - 128));
+		return max(0, min(r, 255));
+	};
+	static BYTE GetG(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int g = (int)(p_nY - 0.344 * (p_nU - 128) - 0.714 * (p_nV - 128));
+		return max(0, min(g, 255));
+	};
+	static BYTE GetB(const int p_nY, const int p_nU, const int p_nV)
+	{
+		int b = (int)(p_nY + 1.772 * (p_nU - 128) + 0.001 * (p_nV - 128));
+		return max(0, min(b, 255));
+	};
+};
+
+
+class CYUVtoRGB24 {
+
+	int m_width, m_height;
+
+	int m_yuv_len;
+	int m_rgb_len;
+	int m_yuv_type;
+
+	unsigned char *m_rgb_buff;
+	unsigned char *m_yuv_buff;
+
+private :
+
+	void YUV422UYVY_ToRGB24(unsigned char *m_pbYUV, unsigned char *m_pbRGB, int m_yuv_len);
+	void YUV422YUY2_ToRGB24(unsigned char *m_pbYUV, unsigned char *m_pbRGB, int m_yuv_len);
+	void YUV420ToRGB24(unsigned char *m_pbYUV, unsigned char *m_pbRGB, int m_width, int m_height);
+	void YUV422UYVY_ToRGB24(BYTE *pbYUV, BYTE *pbRGB, int width, int height, int Stride);
+
+public :
+
+	CYUVtoRGB24();
+	~CYUVtoRGB24();
+
+	// copy image data to yuv_buff
+	int SetYuvImage(unsigned char *buff, int len, int width, int height, int type);
+
+	// Conversion yuv data to RGB32 as defined yuv_type
+	int YUVtoRGB(void);
+
+	// return rgb image data
+	unsigned char* GetRgbImage(void);
+
+}; // class C_YUVtoRGB32
+
+#endif
Index: trunk/src/testing/app/hd-video-player/stdafx.cpp
===================================================================
--- trunk/src/testing/app/hd-video-player/stdafx.cpp	(revision 4)
+++ trunk/src/testing/app/hd-video-player/stdafx.cpp	(revision 4)
@@ -0,0 +1,7 @@
+// stdafx.cpp : source file that includes just the standard includes
+// DecklinkCapture.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+
Index: trunk/src/testing/app/wshare/dxt.h
===================================================================
--- trunk/src/testing/app/wshare/dxt.h	(revision 4)
+++ trunk/src/testing/app/wshare/dxt.h	(revision 4)
@@ -0,0 +1,85 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app/wshare/screencapture.conf
===================================================================
--- trunk/src/testing/app/wshare/screencapture.conf	(revision 4)
+++ trunk/src/testing/app/wshare/screencapture.conf	(revision 4)
@@ -0,0 +1,13 @@
+masterIP 127.0.0.1
+nwID     1
+msgPort  22010
+syncPort 12010
+nodeNum  1
+appID    3
+pixelBlockSize 64 64
+winX 50
+winY 50
+winWidth 1280
+winHeight 800
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/app/wshare/ScreenCapture.h
===================================================================
--- trunk/src/testing/app/wshare/ScreenCapture.h	(revision 4)
+++ trunk/src/testing/app/wshare/ScreenCapture.h	(revision 4)
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#pragma once
+
+#include "resource.h"
Index: trunk/src/testing/app/wshare/util.cpp
===================================================================
--- trunk/src/testing/app/wshare/util.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/util.cpp	(revision 4)
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
+/// File findind
+// From Nvidia toolkit
+
+using namespace std;
+
+string data_path::get_path(std::string filename)
+{
+  FILE* fp;
+  bool found = false;
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+	  break;
+        }
+    }
+
+  if (found == false)
+    {
+      path_name = filename;
+      fp = ::fopen(path_name.c_str(),"r");
+      if (fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+        }
+    }
+
+  if (found == false)
+    return "";
+
+  int loc = path_name.rfind('\\');
+  if (loc == -1)
+    {
+      loc = path_name.rfind('/');
+    }
+
+  if (loc != -1)
+    file_path = path_name.substr(0, loc);
+  else
+    file_path = ".";
+  return file_path;
+}
+
+string data_path::get_file(std::string filename)
+{
+  FILE* fp;
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  return path_name;
+        }
+    }
+
+  path_name = filename;
+  fp = ::fopen(path_name.c_str(),"r");
+  if (fp != 0)
+    {
+      fclose(fp);
+      return path_name;
+    }
+  return "";
+}
+
+// data files, for read only
+FILE * data_path::fopen(std::string filename, const char * mode)
+{
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+      FILE * fp = ::fopen(s.c_str(), mode);
+
+      if(fp != 0)
+	return fp;
+      else if (!strcmp(path[i].c_str(),""))
+	{
+	  FILE* fp = ::fopen(filename.c_str(),mode);
+	  if (fp != 0)
+	    return fp;
+	}
+    }
+  // no luck... return null
+  return 0;
+}
+
+//  fill the file stats structure
+//  useful to get the file size and stuff
+int data_path::fstat(std::string filename,
+#ifdef WIN32
+		     struct _stat
+#else
+		     struct stat
+#endif
+		     * stat)
+{
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+#ifdef WIN32
+      int fh = ::_open(s.c_str(), _O_RDONLY);
+#else
+      int fh = ::open(s.c_str(), O_RDONLY);
+#endif
+      if(fh >= 0)
+        {
+#ifdef WIN32
+	  int result = ::_fstat( fh, stat );
+#else
+	  int result = ::fstat (fh,stat);
+#endif
+	  if( result != 0 )
+            {
+	      fprintf( stderr, "An fstat error occurred.\n" );
+	      return 0;
+            }
+#ifdef WIN32
+	  ::_close( fh );
+#else
+	  ::close (fh);
+#endif
+	  return 1;
+    	}
+    }
+  // no luck...
+  return 0;
+}
Index: trunk/src/testing/app/wshare/ScreenCapture.sln
===================================================================
--- trunk/src/testing/app/wshare/ScreenCapture.sln	(revision 4)
+++ trunk/src/testing/app/wshare/ScreenCapture.sln	(revision 4)
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScreenCapture", "ScreenCapture.vcproj", "{722C60A5-1818-450C-8F15-E8FB0EF58B8B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{722C60A5-1818-450C-8F15-E8FB0EF58B8B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{722C60A5-1818-450C-8F15-E8FB0EF58B8B}.Debug|Win32.Build.0 = Debug|Win32
+		{722C60A5-1818-450C-8F15-E8FB0EF58B8B}.Release|Win32.ActiveCfg = Release|Win32
+		{722C60A5-1818-450C-8F15-E8FB0EF58B8B}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
Index: trunk/src/testing/app/wshare/AviFile.cpp
===================================================================
--- trunk/src/testing/app/wshare/AviFile.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/AviFile.cpp	(revision 4)
@@ -0,0 +1,356 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "StdAfx.h"
+#include "avifile.h"
+
+/// FPS defines the Number of Frames per second;
+/// Here we set FPS to 1 meaning one Frame per Second.
+/// Increase it it you need more Frames Per Second.
+#define FPS			1	// Frames Per Second
+
+/// VIDEOCODEC defines the Codec that need to be used for the Movie.
+/// Change the definition to use a different codec. For example,
+/// Change it to mmioFOURCC('D','I','V','X') to use DIVX codec; or
+/// Change it to mmioFOURCC('I','V','5','0') to use IV50 codec etc..
+/// Also, you can change it to 0 to avoid the codecs altogether. In that case, Frames would be saved as they are;
+/// However, make sure you have the codec installed on the machine before using its Fourcc here.
+#define VIDEOCODEC	mmioFOURCC('M','P','G','4')
+
+//#define VIDEOCODEC	0	/// Frames will be saved as they are - movie size would be HUGE !!
+
+CAviFile::CAviFile(LPCTSTR lpszFileName)
+{
+
+	AVIFileInit();
+
+	_tcscpy(m_szFileName,lpszFileName);
+
+	m_hHeap=NULL;
+	m_hAviDC=NULL;
+	m_lpBits=NULL;
+	m_lSample=NULL;
+	m_pAviFile=NULL;
+	m_pAviStream=NULL;
+	m_pAviCompressedStream=NULL;
+
+	pAppendFrame[0]= &CAviFile::AppendDummy;			// VC8 requires & for Function Pointer; Remove it if your compiler complains;
+	pAppendFrame[1]= &CAviFile::AppendFrameFirstTime;
+	pAppendFrame[2]= &CAviFile::AppendFrameUsual;
+
+	pAppendFrameBits[0]=&CAviFile::AppendDummy;
+	pAppendFrameBits[1]=&CAviFile::AppendFrameFirstTime;
+	pAppendFrameBits[2]=&CAviFile::AppendFrameUsual;
+
+	nAppendFuncSelector=1;		//0=Dummy	1=FirstTime	2=Usual
+}
+
+CAviFile::~CAviFile(void)
+{
+	ReleaseMemory();
+
+	AVIFileExit();
+}
+
+void CAviFile::ReleaseMemory()
+{
+	nAppendFuncSelector=0;		//Point to DummyFunction
+
+	if(m_hAviDC)
+	{
+		DeleteDC(m_hAviDC);
+		m_hAviDC=NULL;
+	}
+	if(m_pAviCompressedStream)
+	{
+		AVIStreamRelease(m_pAviCompressedStream);
+		m_pAviCompressedStream=NULL;
+	}
+	if(m_pAviStream)
+	{
+		AVIStreamRelease(m_pAviStream);
+		m_pAviStream=NULL;
+	}
+	if(m_pAviFile)
+	{
+		AVIFileRelease(m_pAviFile);
+		m_pAviFile=NULL;
+	}
+	if(m_lpBits)
+	{
+		HeapFree(m_hHeap,HEAP_NO_SERIALIZE,m_lpBits);
+		m_lpBits=NULL;
+	}
+	if(m_hHeap)
+	{
+		HeapDestroy(m_hHeap);
+		m_hHeap=NULL;
+	}
+}
+
+HRESULT	CAviFile::AppendFrameFirstTime(HBITMAP	hBitmap)
+{
+	int	nMaxWidth=GetSystemMetrics(SM_CXSCREEN),nMaxHeight=GetSystemMetrics(SM_CYSCREEN);
+
+	BITMAPINFO	bmpInfo;
+
+	m_hAviDC=CreateCompatibleDC(NULL);
+	if(m_hAviDC==NULL)
+	{
+		//MessageBox(NULL,"Unable to Create Compatible DC","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInit;
+	}
+
+	ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+	bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+
+	GetDIBits(m_hAviDC,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
+
+	bmpInfo.bmiHeader.biCompression=BI_RGB;
+
+	if(bmpInfo.bmiHeader.biHeight>nMaxHeight)	nMaxHeight=bmpInfo.bmiHeader.biHeight;
+	if(bmpInfo.bmiHeader.biWidth>nMaxWidth)	nMaxWidth=bmpInfo.bmiHeader.biWidth;
+
+	m_hHeap=HeapCreate(HEAP_NO_SERIALIZE,nMaxWidth*nMaxHeight*4,0);
+	if(m_hHeap==NULL)
+	{
+		//MessageBox(NULL,"Unable to Allocate Memory","Error",MB_OK);
+		goto TerminateInit;
+	}
+
+	m_lpBits=HeapAlloc(m_hHeap,HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE,nMaxWidth*nMaxHeight*4);
+	if(m_lpBits==NULL)
+	{
+		//MessageBox(NULL,"Unable to Allocate Memory","Error",MB_OK);
+		goto TerminateInit;
+	}
+
+	if(FAILED(AVIFileOpen(&m_pAviFile,m_szFileName,OF_CREATE|OF_WRITE,NULL)))
+	{
+		//MessageBox(NULL,"Unable to Create the Movie File","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInit;
+	}
+
+	ZeroMemory(&m_AviStreamInfo,sizeof(AVISTREAMINFO));
+	m_AviStreamInfo.fccType=streamtypeVIDEO;
+	m_AviStreamInfo.fccHandler=VIDEOCODEC;
+	m_AviStreamInfo.dwScale=1;
+	m_AviStreamInfo.dwRate=FPS;		//Frames Per Second;
+	m_AviStreamInfo.dwQuality=-1;	//Default Quality
+	m_AviStreamInfo.dwSuggestedBufferSize=nMaxWidth*nMaxHeight*4;
+    SetRect(&m_AviStreamInfo.rcFrame,0,0,bmpInfo.bmiHeader.biWidth,bmpInfo.bmiHeader.biHeight);
+	strcpy(m_AviStreamInfo.szName,"Video Stream");
+
+	if(FAILED(AVIFileCreateStream(m_pAviFile,&m_pAviStream,&m_AviStreamInfo)))
+	{
+		//MessageBox(NULL,"Unable to Create Stream","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInit;
+
+	}
+
+	ZeroMemory(&m_AviCompressOptions,sizeof(AVICOMPRESSOPTIONS));
+	m_AviCompressOptions.fccType=streamtypeVIDEO;
+	m_AviCompressOptions.fccHandler=m_AviStreamInfo.fccHandler;
+	m_AviCompressOptions.dwFlags=AVICOMPRESSF_KEYFRAMES|AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
+	m_AviCompressOptions.dwKeyFrameEvery=15;
+	//m_AviCompressOptions.dwBytesPerSecond=1000/8;
+	//m_AviCompressOptions.dwQuality=100;
+
+	if(FAILED(AVIMakeCompressedStream(&m_pAviCompressedStream,m_pAviStream,&m_AviCompressOptions,NULL)))
+	{
+		//MessageBox(NULL,"Unable to Create Compressed Stream","Error",MB_OK);
+		goto TerminateInit;
+	}
+
+	if(FAILED(AVIStreamSetFormat(m_pAviCompressedStream,0,(LPVOID)&bmpInfo,bmpInfo.bmiHeader.biSize)))
+	{
+		//MessageBox(NULL,"Unable to Set Format","Error",MB_OK);
+		goto TerminateInit;
+	}
+
+	nAppendFuncSelector=2;		//Point to UsualAppend Function
+
+	return AppendFrameUsual(hBitmap);
+
+TerminateInit:
+
+	ReleaseMemory();	MessageBox(NULL,"Error Occured While Rendering the Movie","Error",MB_OK|MB_ICONERROR);
+
+	return E_FAIL;
+}
+
+HRESULT CAviFile::AppendFrameUsual(HBITMAP hBitmap)
+{
+	BITMAPINFO	bmpInfo;
+
+	bmpInfo.bmiHeader.biBitCount=0;
+	bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+
+	GetDIBits(m_hAviDC,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
+
+	bmpInfo.bmiHeader.biCompression=BI_RGB;
+
+	GetDIBits(m_hAviDC,hBitmap,0,bmpInfo.bmiHeader.biHeight,m_lpBits,&bmpInfo,DIB_RGB_COLORS);
+
+	if(FAILED(AVIStreamWrite(m_pAviCompressedStream,m_lSample++,1,m_lpBits,bmpInfo.bmiHeader.biSizeImage,0,NULL,NULL)))
+		return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT CAviFile::AppendDummy(HBITMAP)
+{
+	return E_FAIL;
+}
+
+HRESULT CAviFile::AppendNewFrame(HBITMAP hBitmap)
+{
+	return (this->*pAppendFrame[nAppendFuncSelector])((HBITMAP)hBitmap);
+}
+
+HRESULT	CAviFile::AppendNewFrame(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
+{
+	return (this->*pAppendFrameBits[nAppendFuncSelector])(nWidth,nHeight,pBits,nBitsPerPixel);
+}
+
+HRESULT	CAviFile::AppendFrameFirstTime(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
+{
+	int	nMaxWidth=GetSystemMetrics(SM_CXSCREEN),nMaxHeight=GetSystemMetrics(SM_CYSCREEN);
+
+	BITMAPINFO	bmpInfo;
+
+	m_hAviDC=CreateCompatibleDC(NULL);
+	if(m_hAviDC==NULL)
+	{
+		//MessageBox(NULL,"Unable to Create Compatible DC","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInitBits;
+	}
+
+	ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+	bmpInfo.bmiHeader.biPlanes=1;
+	bmpInfo.bmiHeader.biWidth=nWidth;
+	bmpInfo.bmiHeader.biHeight=nHeight;
+	bmpInfo.bmiHeader.biCompression=BI_RGB;
+	bmpInfo.bmiHeader.biBitCount=nBitsPerPixel;
+	bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+	bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biHeight*bmpInfo.bmiHeader.biBitCount/8;
+
+	if(bmpInfo.bmiHeader.biHeight>nMaxHeight)	nMaxHeight=bmpInfo.bmiHeader.biHeight;
+	if(bmpInfo.bmiHeader.biWidth>nMaxWidth)	nMaxWidth=bmpInfo.bmiHeader.biWidth;
+
+	m_hHeap=HeapCreate(HEAP_NO_SERIALIZE,nMaxWidth*nMaxHeight*4,0);
+	if(m_hHeap==NULL)
+	{
+		//MessageBox(NULL,"Unable to Allocate Memory","Error",MB_OK);
+		goto TerminateInitBits;
+	}
+
+	m_lpBits=HeapAlloc(m_hHeap,HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE,nMaxWidth*nMaxHeight*4);
+	if(m_lpBits==NULL)
+	{
+		//MessageBox(NULL,"Unable to Allocate Memory","Error",MB_OK);
+		goto TerminateInitBits;
+	}
+
+	if(FAILED(AVIFileOpen(&m_pAviFile,m_szFileName,OF_CREATE|OF_WRITE,NULL)))
+	{
+		//MessageBox(NULL,"Unable to Create the Movie File","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInitBits;
+	}
+
+	ZeroMemory(&m_AviStreamInfo,sizeof(AVISTREAMINFO));
+	m_AviStreamInfo.fccType=streamtypeVIDEO;
+	m_AviStreamInfo.fccHandler=VIDEOCODEC;
+	m_AviStreamInfo.dwScale=1;
+	m_AviStreamInfo.dwRate= FPS;	//Frames Per Second;
+	m_AviStreamInfo.dwQuality=-1;	//Default Quality
+	m_AviStreamInfo.dwSuggestedBufferSize=nMaxWidth*nMaxHeight*4;
+    SetRect(&m_AviStreamInfo.rcFrame,0,0,bmpInfo.bmiHeader.biWidth,bmpInfo.bmiHeader.biHeight);
+	strcpy(m_AviStreamInfo.szName,"Video Stream");
+
+	if(FAILED(AVIFileCreateStream(m_pAviFile,&m_pAviStream,&m_AviStreamInfo)))
+	{
+		//MessageBox(NULL,"Unable to Create Stream","Error",MB_OK|MB_ICONERROR);
+		goto TerminateInitBits;
+
+	}
+
+	ZeroMemory(&m_AviCompressOptions,sizeof(AVICOMPRESSOPTIONS));
+	m_AviCompressOptions.fccType=streamtypeVIDEO;
+	m_AviCompressOptions.fccHandler=m_AviStreamInfo.fccHandler;
+	m_AviCompressOptions.dwFlags=AVICOMPRESSF_KEYFRAMES|AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
+	m_AviCompressOptions.dwKeyFrameEvery=15;
+	//m_AviCompressOptions.dwBytesPerSecond=1000/8;
+	//m_AviCompressOptions.dwQuality=100;
+
+	if(FAILED(AVIMakeCompressedStream(&m_pAviCompressedStream,m_pAviStream,&m_AviCompressOptions,NULL)))
+	{
+		//MessageBox(NULL,"Unable to Create Compressed Stream","Error",MB_OK);
+		goto TerminateInitBits;
+	}
+
+	if(FAILED(AVIStreamSetFormat(m_pAviCompressedStream,0,(LPVOID)&bmpInfo,bmpInfo.bmiHeader.biSize)))
+	{
+		//MessageBox(NULL,"Unable to Set Format","Error",MB_OK);
+		goto TerminateInitBits;
+	}
+
+	nAppendFuncSelector=2;		//Point to UsualAppend Function
+
+	return AppendFrameUsual(nWidth,nHeight,pBits,nBitsPerPixel);
+
+TerminateInitBits:
+
+	ReleaseMemory();	MessageBox(NULL,"Error Occured While Rendering the Movie","Error",MB_OK|MB_ICONERROR);
+
+	return E_FAIL;
+
+}
+
+HRESULT	CAviFile::AppendFrameUsual(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
+{
+	DWORD	dwSize=nWidth*nHeight*nBitsPerPixel/8;
+
+	if(FAILED(AVIStreamWrite(m_pAviCompressedStream,m_lSample++,1,pBits,dwSize,0,NULL,NULL)))
+		return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT	CAviFile::AppendDummy(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
+{
+	return E_FAIL;
+}
Index: trunk/src/testing/app/wshare/util.h
===================================================================
--- trunk/src/testing/app/wshare/util.h	(revision 4)
+++ trunk/src/testing/app/wshare/util.h	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
+// From NVIDIA Toolkit
+
+#ifndef DATA_PATH_H
+#define DATA_PATH_H
+
+class data_path
+{
+public:
+  std::string              file_path;
+  std::string              path_name;
+  std::vector<std::string> path;
+
+  std::string get_path(std::string filename);
+  std::string get_file(std::string filename);
+
+  FILE *fopen(std::string filename, const char * mode = "rb");
+
+#ifdef WIN32
+  int fstat(std::string filename, struct _stat * stat);
+#else
+  int fstat(std::string filename, struct stat * stat);
+#endif
+};
+
+#endif
Index: trunk/src/testing/app/wshare/AviFile.h
===================================================================
--- trunk/src/testing/app/wshare/AviFile.h	(revision 4)
+++ trunk/src/testing/app/wshare/AviFile.h	(revision 4)
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#pragma once
+
+#ifndef __AVIFILE_H
+#define __AVIFILE_H
+
+#include <vfw.h>
+
+class CAviFile
+{
+	HDC				m_hAviDC;
+	HANDLE			m_hHeap;
+	LPVOID			m_lpBits;
+	LONG			m_lSample;
+	TCHAR			m_szFileName[MAX_PATH];
+	PAVIFILE		m_pAviFile;
+	PAVISTREAM		m_pAviStream;
+	PAVISTREAM		m_pAviCompressedStream;
+	AVISTREAMINFO	m_AviStreamInfo;
+	AVICOMPRESSOPTIONS	m_AviCompressOptions;
+
+	int		nAppendFuncSelector;		//0=Dummy	1=FirstTime	2=Usual
+	HRESULT	AppendFrameFirstTime(HBITMAP );
+	HRESULT	AppendFrameUsual(HBITMAP);
+	HRESULT	AppendDummy(HBITMAP);
+	HRESULT	(CAviFile::*pAppendFrame[3])(HBITMAP hBitmap);
+
+	HRESULT	AppendFrameFirstTime(int, int, LPVOID,int );
+	HRESULT	AppendFrameUsual(int, int, LPVOID,int );
+	HRESULT	AppendDummy(int, int, LPVOID,int );
+	HRESULT	(CAviFile::*pAppendFrameBits[3])(int, int, LPVOID,int );
+	void	ReleaseMemory();
+public:
+	CAviFile(LPCSTR	lpszFileName=_T("Output.avi"));
+	~CAviFile(void);
+	HRESULT	AppendNewFrame(HBITMAP hBitmap);
+	HRESULT	AppendNewFrame(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel=32);
+};
+
+#endif
Index: trunk/src/testing/app/wshare/ScreenCapture.vcproj
===================================================================
--- trunk/src/testing/app/wshare/ScreenCapture.vcproj	(revision 4)
+++ trunk/src/testing/app/wshare/ScreenCapture.vcproj	(revision 4)
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="ScreenCapture"
+	ProjectGUID="{722C60A5-1818-450C-8F15-E8FB0EF58B8B}"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="C:\sources\sage3.0\win32\include;C:\sources\sage3.0\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="d3d9.lib d3dx9.lib vfw32.lib shell32.lib Ws2_32.lib pthread.lib quanta.lib sail.lib portaudio_x86.lib"
+				OutputFile="$(OutDir)/ScreenCapture.exe"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="C:\sources\sage3.0\lib;C:\sources\sage3.0\win32\lib"
+				IgnoreAllDefaultLibraries="false"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/ScreenCapture.pdb"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				OmitFramePointers="true"
+				AdditionalIncludeDirectories="C:\sources\sage3.0\win32\include;C:\sources\sage3.0\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;"
+				StringPooling="true"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="d3d9.lib d3dx9.lib vfw32.lib Ws2_32.lib pthread.lib quanta.lib sail.lib portaudio_x86.lib"
+				OutputFile="$(OutDir)/ScreenCapture.exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="C:\sources\sage3.0\lib;C:\sources\sage3.0\win32\lib"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+			>
+			<File
+				RelativePath="AviFile.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\dxt.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\intrinsic.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\libdxt.cpp"
+				>
+			</File>
+			<File
+				RelativePath="ScreenCapture.cpp"
+				>
+			</File>
+			<File
+				RelativePath="stdafx.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\util.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc"
+			>
+			<File
+				RelativePath="AviFile.h"
+				>
+			</File>
+			<File
+				RelativePath=".\dxt.h"
+				>
+			</File>
+			<File
+				RelativePath=".\libdxt.h"
+				>
+			</File>
+			<File
+				RelativePath="Resource.h"
+				>
+			</File>
+			<File
+				RelativePath="ScreenCapture.h"
+				>
+			</File>
+			<File
+				RelativePath="stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\util.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+			>
+			<File
+				RelativePath="ico00001.ico"
+				>
+			</File>
+			<File
+				RelativePath="icon1.ico"
+				>
+			</File>
+			<File
+				RelativePath="ScreenCapture.ico"
+				>
+			</File>
+			<File
+				RelativePath="ScreenCapture.rc"
+				>
+			</File>
+			<File
+				RelativePath="small.ico"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: trunk/src/testing/app/wshare/ScreenCapture.rc
===================================================================
--- trunk/src/testing/app/wshare/ScreenCapture.rc	(revision 4)
+++ trunk/src/testing/app/wshare/ScreenCapture.rc	(revision 4)
@@ -0,0 +1,158 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SCREENCAPTURE       ICON                    "ScreenCapture.ico"
+IDI_SMALL               ICON                    "small.ico"
+IDI_ICON_PAUSE          ICON                    "icon1.ico"
+IDI_ICON_START          ICON                    "ico00001.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_SCREENCAPTURE MENU 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "Start Capturing to Avi",      ID_FILE_STARTCAPTURINGTOAVI
+        MENUITEM "Pause Capturing to Avi",      ID_FILE_PAUSECAPTURINGTOAVI
+        MENUITEM SEPARATOR
+        MENUITEM "CaptureScreenShot",           ID_FILE_CAPTURESCREENSHOT
+        MENUITEM SEPARATOR
+        MENUITEM "&Show Window",                ID_FILE_SHOWWINDOW
+        MENUITEM "&Hide Window",                133
+        MENUITEM SEPARATOR
+        MENUITEM "E&xit",                       IDM_EXIT
+    END
+    POPUP "&Edit"
+    BEGIN
+        MENUITEM "Save Screen Shot As Bmp",     ID_EDIT_SAVEASBMP
+    END
+    POPUP "Capture"
+    BEGIN
+        MENUITEM "&Start",                      ID_CAPTURE_START
+        MENUITEM "&Pause",                      ID_CAPTURE_STOP
+    END
+    POPUP "&Help"
+    BEGIN
+        MENUITEM "&About ...",                  IDM_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_SCREENCAPTURE ACCELERATORS 
+BEGIN
+    "?",            IDM_ABOUT,              ASCII,  ALT
+    "/",            IDM_ABOUT,              ASCII,  ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 22, 17, 230, 54
+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System", 0, 0, 0x0
+BEGIN
+    ICON            IDI_SCREENCAPTURE,IDC_MYICON,14,18,16,16
+    LTEXT           "ScreenCapture Version 1.0",IDC_STATIC,49,10,119,8,
+                    SS_NOPREFIX
+    LTEXT           "Copyright (C) 2003",IDC_STATIC,49,22,119,8
+    DEFPUSHBUTTON   "OK",IDOK,181,20,30,11,WS_GROUP
+    LTEXT           "Captures the Screen using DirectX",IDC_STATIC,50,35,112,
+                    8
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE 
+BEGIN
+    IDS_APP_TITLE           "ScreenCapture"
+    IDC_SCREENCAPTURE       "SCREENCAPTURE"
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
Index: trunk/src/testing/app/wshare/libdxt.cpp
===================================================================
--- trunk/src/testing/app/wshare/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/libdxt.cpp	(revision 4)
@@ -0,0 +1,131 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app/wshare/stdafx.cpp
===================================================================
--- trunk/src/testing/app/wshare/stdafx.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/stdafx.cpp	(revision 4)
@@ -0,0 +1,44 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// stdafx.cpp : source file that includes just the standard includes
+// ScreenCapture.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
Index: trunk/src/testing/app/wshare/libdxt.h
===================================================================
--- trunk/src/testing/app/wshare/libdxt.h	(revision 4)
+++ trunk/src/testing/app/wshare/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app/wshare/resource.h
===================================================================
--- trunk/src/testing/app/wshare/resource.h	(revision 4)
+++ trunk/src/testing/app/wshare/resource.h	(revision 4)
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ScreenCapture.rc
+//
+#define IDC_MYICON                      2
+#define IDD_SCREENCAPTURE_DIALOG        102
+#define IDS_APP_TITLE                   103
+#define IDD_ABOUTBOX                    103
+#define IDM_ABOUT                       104
+#define IDM_EXIT                        105
+#define IDI_SCREENCAPTURE               107
+#define IDI_SMALL                       108
+#define IDC_SCREENCAPTURE               109
+#define IDR_MAINFRAME                   128
+#define ID_CAPTURE_START                129
+#define ID_CAPTURE_STOP                 130
+#define ID_FILE_SHOWWINDOW              131
+#define ID_EDIT_COPYTOCLIPBOARD         132
+#define ID_FILE_HIDEWINDOW              133
+#define ID_EDIT_COPYSCREENSHOTTOCLIPBOARD 134
+#define ID_EDIT_SAVEASBMP               135
+#define ID_FILE_CAPTURESCREENSHOT       136
+#define ID_FILE_STARTCAPTURINGTOAVI     137
+#define ID_FILE_PAUSECAPTURINGTOAVI     138
+#define IDI_ICON_PAUSE                  139
+#define IDI_ICON_START                  140
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_NEXT_RESOURCE_VALUE        141
+#define _APS_NEXT_COMMAND_VALUE         32771
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
Index: trunk/src/testing/app/wshare/stdafx.h
===================================================================
--- trunk/src/testing/app/wshare/stdafx.h	(revision 4)
+++ trunk/src/testing/app/wshare/stdafx.h	(revision 4)
@@ -0,0 +1,54 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+#include <d3d9.h>
+#include <d3dx9.h>
Index: trunk/src/testing/app/wshare/dxt.cpp
===================================================================
--- trunk/src/testing/app/wshare/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app/wshare/intrinsic.cpp
===================================================================
--- trunk/src/testing/app/wshare/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app/wshare/ScreenCapture.cpp
===================================================================
--- trunk/src/testing/app/wshare/ScreenCapture.cpp	(revision 4)
+++ trunk/src/testing/app/wshare/ScreenCapture.cpp	(revision 4)
@@ -0,0 +1,809 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// ScreenCapture.cpp : Defines the entry point for the application.
+//
+
+#include "stdafx.h"
+#include "ScreenCapture.h"
+#include <stdio.h>
+#include "avifile.h"
+#include <shellapi.h>
+#include <commdlg.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+#include "libdxt.h"
+
+#include <direct.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+sail *sageInf = NULL; // sail object
+
+#define MAX_LOADSTRING 100
+
+#define	WM_NOTIFYICON_MESSAGE	WM_USER+1000
+
+#define	ErrorMessage(x)		MessageBox(NULL,x,"Error",MB_OK|MB_ICONERROR)
+
+#define	WINDOW_MODE			true				//Not in fullscreen mode
+#define BITSPERPIXEL		32
+
+HINSTANCE hInst;								// current instance
+TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
+
+ATOM				MyRegisterClass(HINSTANCE hInstance);
+BOOL				InitInstance(HINSTANCE, int);
+LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
+
+HWND	ghWnd;
+HDC		hBackDC=NULL;
+LPVOID	pBits=NULL;
+HBITMAP	hBackBitmap=NULL;
+HBITMAP	hOldBitmap=NULL;
+
+int	nDisplayWidth;
+int	nDisplayHeight;
+
+IDirect3D9*			g_pD3D=NULL;
+IDirect3DDevice9*	g_pd3dDevice=NULL;
+IDirect3DSurface9*	g_pSurface=NULL;
+
+HRESULT Reset();
+void	Render();
+void	Cleanup();
+HRESULT	InitD3D(HWND hWnd);
+void	SaveBitmap(char *szFilename,HBITMAP hBitmap);
+
+UINT_PTR	nTimerId=0;
+CAviFile	*pAviFile=NULL;
+HMENU		ghMenu=NULL;
+RECT		gScreenRect ={0,0,0,0};
+bool		gbCapturing=false;
+
+int     nScreenWidth;
+int     nScreenHeight;
+HWND    hDesktopWnd;
+HDC     hDesktopDC;
+HDC     hCaptureDC;
+HBITMAP hCaptureBitmap;
+
+
+
+
+int APIENTRY _tWinMain(HINSTANCE hInstance,
+                     HINSTANCE hPrevInstance,
+                     LPTSTR    lpCmdLine,
+                     int       nCmdShow)
+{
+	MSG msg;
+	HACCEL hAccelTable;
+
+	// Initialize global strings
+	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+	LoadString(hInstance, IDC_SCREENCAPTURE, szWindowClass, MAX_LOADSTRING);
+	MyRegisterClass(hInstance);
+
+	// Perform application initialization:
+	if (!InitInstance (hInstance, nCmdShow))
+	{
+		return FALSE;
+	}
+
+	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SCREENCAPTURE);
+
+	// Main message loop:
+	while (GetMessage(&msg, NULL, 0, 0))
+	{
+		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+		{
+			TranslateMessage(&msg);
+			DispatchMessage(&msg);
+		}
+	}
+
+	return (int) msg.wParam;
+}
+
+
+
+//
+//  FUNCTION: MyRegisterClass()
+//
+//  PURPOSE: Registers the window class.
+//
+//  COMMENTS:
+//
+//    This function and its usage are only necessary if you want this code
+//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
+//    function that was added to Windows 95. It is important to call this function
+//    so that the application will get 'well formed' small icons associated
+//    with it.
+//
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+	WNDCLASSEX wcex;
+
+	wcex.cbSize = sizeof(WNDCLASSEX);
+
+	wcex.style			= CS_HREDRAW | CS_VREDRAW;
+	wcex.lpfnWndProc	= (WNDPROC)WndProc;
+	wcex.cbClsExtra		= 0;
+	wcex.cbWndExtra		= 0;
+	wcex.hInstance		= hInstance;
+	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_SCREENCAPTURE);
+	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
+	wcex.hbrBackground	= NULL;//(HBRUSH)(COLOR_WINDOW+1);
+	wcex.lpszMenuName	= (LPCTSTR)IDC_SCREENCAPTURE;
+	wcex.lpszClassName	= szWindowClass;
+	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
+
+	return RegisterClassEx(&wcex);
+}
+
+//
+//   FUNCTION: InitInstance(HANDLE, int)
+//
+//   PURPOSE: Saves instance handle and creates main window
+//
+//   COMMENTS:
+//
+//        In this function, we save the instance handle in a global variable and
+//        create and display the main program window.
+//
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+
+   hInst = hInstance; // Store instance handle in our global variable
+
+   ghWnd = CreateWindow(szWindowClass, szTitle, WS_POPUPWINDOW|WS_CAPTION|WS_VISIBLE,
+      480, 400, 320, 240, NULL, NULL, hInstance, NULL);
+
+   if (!ghWnd)
+   {
+      return FALSE;
+   }
+
+   ShowWindow(ghWnd, nCmdShow);
+   UpdateWindow(ghWnd);
+
+   return TRUE;
+}
+
+//
+//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for the main window.
+//
+//  WM_COMMAND	- process the application menu
+//  WM_PAINT	- Paint the main window
+//  WM_DESTROY	- post a quit message and return
+//
+//
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+	int wmId, wmEvent;
+	static NOTIFYICONDATA	nid;
+	static RECT	clientRect = {0,0,0,0};
+	static bool	bMinimized=false;
+
+	switch (message)
+	{
+	case WM_SYSCOMMAND:
+		{
+			if(wParam==SC_CLOSE)
+			{
+				SendMessage(hWnd,WM_SYSCOMMAND,SC_MINIMIZE,0);
+				return 0;
+			}
+			if(wParam==SC_MINIMIZE)
+			{
+				bMinimized=true;
+				LONG_PTR ret=DefWindowProc(hWnd,message,wParam,lParam);
+				SendMessage(hWnd,WM_COMMAND,MAKEWPARAM(ID_FILE_HIDEWINDOW,0),0);
+				return ret;
+			}
+			return DefWindowProc(hWnd, message, wParam, lParam);
+		}
+
+	case WM_COMMAND:
+		wmId    = LOWORD(wParam);
+		wmEvent = HIWORD(wParam);
+		// Parse the menu selections:
+		switch (wmId)
+		{
+		case ID_FILE_STARTCAPTURINGTOAVI:
+		case ID_CAPTURE_START:
+			{
+				if(pAviFile==NULL)
+				{
+					OPENFILENAME	ofn;
+					char	szFileName[512];
+					strcpy(szFileName,"Output.avi");
+					ZeroMemory(&ofn,sizeof(ofn));
+					ofn.lStructSize=sizeof(OPENFILENAME);
+					ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
+					ofn.lpstrFilter="Avi Files (*.avi)\0*.avi\0";
+					ofn.lpstrDefExt="avi";
+					ofn.lpstrFile=szFileName;
+					ofn.nMaxFile=512;
+					ofn.hwndOwner = hWnd;
+					if(!GetSaveFileName(&ofn))	break;
+
+					pAviFile = new CAviFile(szFileName);
+
+					nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
+					nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
+
+					//aInitialize();
+					//aLog("%d %d \n",nScreenWidth, nScreenHeight);
+
+					sageInf = new sail();
+					_chdir("C:\\sources\\sage3.0\\bin");
+
+					sailConfig scfg;
+					scfg.init("screencapture.conf");
+					scfg.setAppName("screencapture");
+					scfg.rank = 0;
+					scfg.master = true;
+					scfg.nwID = 1;
+					scfg.syncPort = 13000;
+					scfg.nodeNum = 1;
+					scfg.blockX= 64;
+					scfg.blockY= 64;
+					scfg.pixFmt = PIXFMT_888_INV;
+					//scfg.pixFmt = PIXFMT_8888_INV;
+					//scfg.pixFmt = PIXFMT_DXT;
+					scfg.rowOrd = BOTTOM_TO_TOP;
+					scfg.resX = nScreenWidth;
+					scfg.resY = nScreenHeight;
+					sageRect renderImageMap;
+					renderImageMap.left = 0.0;
+					renderImageMap.right = 1.0;
+					renderImageMap.bottom = 0.0;
+					renderImageMap.top = 1.0;
+					scfg.imageMap = renderImageMap;
+
+					scfg.winX = 0;
+					scfg.winY = 0;
+					scfg.winWidth  = nScreenWidth*2;
+					scfg.winHeight = nScreenHeight*2;
+
+					sageInf->init(scfg);
+					//aLog("Init done\n");
+
+					BITMAPINFO	bmpInfo;
+					ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+					bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+					bmpInfo.bmiHeader.biBitCount=24;//BITSPERPIXEL;
+					bmpInfo.bmiHeader.biCompression = BI_RGB;
+					bmpInfo.bmiHeader.biWidth=nScreenWidth;
+					bmpInfo.bmiHeader.biHeight=nScreenHeight;
+					bmpInfo.bmiHeader.biPlanes=1;
+					bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;
+
+					hDesktopWnd = GetDesktopWindow();
+					hDesktopDC = GetDC(hDesktopWnd);
+					hCaptureDC = CreateCompatibleDC(hDesktopDC);
+					hCaptureBitmap = CreateDIBSection(hDesktopDC,&bmpInfo,DIB_RGB_COLORS,&pBits,NULL,0);
+					SelectObject(hCaptureDC,hCaptureBitmap);
+				}
+
+				nid.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON_PAUSE));
+				strcpy(nid.szTip,"Capturing the Screen - Double Click to Pause");
+
+				if(!Shell_NotifyIcon(NIM_MODIFY,&nid))				//Modify the Icon State
+					MessageBox(NULL,"Unable to Set Notification Icon","Error",MB_ICONINFORMATION|MB_OK);
+
+				SendMessage(hWnd,WM_SYSCOMMAND,SC_MINIMIZE,0);
+
+                gbCapturing = true;
+
+				break;
+			}
+		case ID_FILE_PAUSECAPTURINGTOAVI:
+		case ID_CAPTURE_STOP:
+			{
+				nid.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON_START));
+				strcpy(nid.szTip,"Screen Capture Paused - Double Click to Resume");
+
+				if(!Shell_NotifyIcon(NIM_MODIFY,&nid))				//Modify the Icon State
+					MessageBox(NULL,"Unable to Set Notification Icon","Error",MB_ICONINFORMATION|MB_OK);
+
+				gbCapturing = false;
+
+				break;
+			}
+		case ID_FILE_SHOWWINDOW:
+			{
+				if(bMinimized)	ShowWindow(hWnd,SW_RESTORE);
+				else			ShowWindow(hWnd,SW_SHOW);
+				SetForegroundWindow(hWnd);
+				bMinimized=false;
+				break;
+			}
+		case ID_FILE_HIDEWINDOW:
+			{
+				ShowWindow(hWnd,SW_HIDE);
+				break;
+			}
+		case ID_FILE_CAPTURESCREENSHOT:
+		case ID_EDIT_SAVEASBMP:
+			{
+				OPENFILENAME	ofn;
+				char	szFileName[512];
+
+				strcpy(szFileName,"ScreenShot.bmp");
+
+                ZeroMemory(&ofn,sizeof(ofn));
+				ofn.lStructSize=sizeof(OPENFILENAME);
+				ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
+				ofn.lpstrFilter="Bitmap Files (*.bmp)\0*.bmp\0";
+				ofn.lpstrDefExt="bmp";
+				ofn.lpstrFile=szFileName;
+				ofn.nMaxFile=512;
+				ofn.hwndOwner = hWnd;
+				if(!GetSaveFileName(&ofn))	break;
+
+				SetCursor(LoadCursor(NULL,IDC_WAIT));
+
+				g_pd3dDevice->GetFrontBufferData(0, g_pSurface);
+				D3DXSaveSurfaceToFile(szFileName,D3DXIFF_BMP,g_pSurface,NULL,NULL);		//Save to File
+
+				D3DLOCKED_RECT	lockedRect;
+				if(FAILED(g_pSurface->LockRect(&lockedRect,NULL,D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
+				{
+					ErrorMessage("Unable to Lock Front Buffer Surface");	break;
+				}
+				for(int i=0;i<gScreenRect.bottom;i++)
+				{
+					memcpy((BYTE*)pBits+(gScreenRect.bottom-i-1)*gScreenRect.right*BITSPERPIXEL/8,(BYTE*)lockedRect.pBits+i*lockedRect.Pitch,gScreenRect.right*BITSPERPIXEL/8);//g_d3dpp.BackBufferHeight*g_d3dpp.BackBufferWidth*4);
+				}
+				g_pSurface->UnlockRect();
+				InvalidateRect(hWnd,NULL,false);
+
+				SetCursor(LoadCursor(NULL,IDC_ARROW));
+				break;
+			}
+		case IDM_ABOUT:
+			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
+			break;
+		case IDM_EXIT:
+			DestroyWindow(hWnd);
+			break;
+		default:
+			return DefWindowProc(hWnd, message, wParam, lParam);
+		}
+		break;
+	case WM_INITMENU:
+		{
+			HMENU	hMenu = (HMENU)wParam;
+			EnableMenuItem(hMenu,ID_FILE_SHOWWINDOW,IsWindowVisible(hWnd)?MF_GRAYED:MF_ENABLED|MF_BYCOMMAND);
+			EnableMenuItem(hMenu,ID_FILE_HIDEWINDOW,IsWindowVisible(hWnd)?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			EnableMenuItem(hMenu,ID_FILE_CAPTURESCREENSHOT,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(hMenu,ID_FILE_STARTCAPTURINGTOAVI,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(hMenu,ID_FILE_PAUSECAPTURINGTOAVI,gbCapturing?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			EnableMenuItem(hMenu,ID_CAPTURE_START,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(hMenu,ID_CAPTURE_STOP,gbCapturing?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			break;
+		}
+	case WM_INITMENUPOPUP:
+		{
+			EnableMenuItem(ghMenu,ID_FILE_SHOWWINDOW,IsWindowVisible(hWnd)?MF_GRAYED:MF_ENABLED|MF_BYCOMMAND);
+			EnableMenuItem(ghMenu,ID_FILE_HIDEWINDOW,IsWindowVisible(hWnd)?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			EnableMenuItem(ghMenu,ID_FILE_CAPTURESCREENSHOT,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(ghMenu,ID_FILE_STARTCAPTURINGTOAVI,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(ghMenu,ID_FILE_PAUSECAPTURINGTOAVI,gbCapturing?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			EnableMenuItem(ghMenu,ID_CAPTURE_START,gbCapturing?MF_GRAYED|MF_BYCOMMAND:MF_ENABLED);
+			EnableMenuItem(ghMenu,ID_CAPTURE_STOP,gbCapturing?MF_ENABLED:MF_GRAYED|MF_BYCOMMAND);
+			break;
+		}
+	case WM_CREATE:
+		{
+			LRESULT	ret=DefWindowProc(hWnd,message,wParam,lParam);
+			if(ret<0)	return ret;
+
+			BITMAPINFO	bmpInfo;
+			ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+			bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+			bmpInfo.bmiHeader.biBitCount=BITSPERPIXEL;
+			bmpInfo.bmiHeader.biCompression = BI_RGB;
+			bmpInfo.bmiHeader.biWidth=GetSystemMetrics(SM_CXSCREEN);
+			bmpInfo.bmiHeader.biHeight=GetSystemMetrics(SM_CYSCREEN);
+			bmpInfo.bmiHeader.biPlanes=1;
+			bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;
+
+			HDC	hdc=GetDC(GetDesktopWindow());
+			hBackDC=CreateCompatibleDC(hdc);
+			hBackBitmap=CreateDIBSection(hdc,&bmpInfo,DIB_RGB_COLORS,&pBits,NULL,0);
+			if(hBackBitmap==NULL)
+			{
+				ErrorMessage("Unable to Create BackBuffer Bitamp");		return -1;
+			}
+			ReleaseDC(GetDesktopWindow(),hdc);
+
+			ZeroMemory(&nid,sizeof(nid));
+			nid.cbSize=sizeof(nid);
+			nid.uID=1000;
+			nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
+			nid.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_SCREENCAPTURE));
+			nid.hWnd=hWnd;
+			strcpy(nid.szTip,"Screen Capture Application - Double Click to Start Capturing");
+			nid.uCallbackMessage=WM_NOTIFYICON_MESSAGE;
+			if(!Shell_NotifyIcon(NIM_ADD,&nid))	MessageBox(NULL,"Unable to Set Notification Icon","Error",MB_ICONINFORMATION|MB_OK);
+			ghMenu=LoadMenu(hInst,MAKEINTRESOURCE(IDC_SCREENCAPTURE));
+
+			if(FAILED(InitD3D(hWnd)))	return -1;
+
+			nTimerId=SetTimer(hWnd,1,1000/35,NULL);	//Timer set to 500 ms.
+
+			return ret;
+		}
+	case WM_CHAR:
+		{
+			if(wParam==VK_ESCAPE)
+				DestroyWindow(hWnd);
+			break;
+		}
+	case WM_TIMER:
+		{
+			if(gbCapturing == false)	break;
+
+			/*
+			D3DLOCKED_RECT	lockedRect;
+			g_pd3dDevice->GetFrontBufferData(0, g_pSurface);
+			if(FAILED(g_pSurface->LockRect(&lockedRect,&gScreenRect,D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY)))
+			{
+				ErrorMessage("Unable to Lock Front Buffer Surface");	break;
+			}
+			for(int i=0;i<gScreenRect.bottom;i++)
+			{
+				//memcpy((BYTE*)pBits+(gScreenRect.bottom-i-1)*gScreenRect.right*BITSPERPIXEL/8,(BYTE*)lockedRect.pBits+i*lockedRect.Pitch,gScreenRect.right*BITSPERPIXEL/8);
+			}
+			g_pSurface->UnlockRect();
+			InvalidateRect(hWnd,NULL,false);
+			*/
+
+			//pAviFile->AppendNewFrame(gScreenRect.right,gScreenRect.bottom,pBits);			//Append this Captured ScreenShot to the Movie
+
+			void *buffer = sageInf->getBuffer();
+			BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
+
+		    //CompressDXT((const byte*)pBits, (byte*)buffer, nScreenWidth, nScreenHeight, FORMAT_DXT1, 1);
+
+			//memcpy(buffer, pBits, nScreenWidth*nScreenHeight*4);
+
+			memcpy(buffer, pBits, nScreenWidth*nScreenHeight*3);
+
+			sageInf->swapBuffer();
+
+			sageMessage msg;
+			if (sageInf->checkMsg(msg, false) > 0) {
+				switch (msg.getCode()) {
+					 case APP_QUIT : {
+						sageInf->shutdown();
+						exit(0);
+					break;
+					}
+				}
+			}
+
+			break;
+		}
+	case WM_PAINT:
+		{
+			PAINTSTRUCT	ps;
+			HBITMAP hOldBitmap = (HBITMAP)SelectObject(hBackDC,hBackBitmap);
+			HDC hdc = BeginPaint(hWnd, &ps);
+			StretchBlt(hdc,0,0,clientRect.right,clientRect.bottom,hBackDC,0,0,gScreenRect.right,gScreenRect.bottom,SRCCOPY);
+			EndPaint(hWnd, &ps);
+			SelectObject(hBackDC,hOldBitmap);
+			break;
+		}
+	case WM_SIZE:
+		{
+			clientRect.right = LOWORD(lParam);
+			clientRect.bottom = HIWORD(lParam);
+			break;
+		}
+	case WM_NOTIFYICON_MESSAGE:
+		{
+			switch(lParam)
+			{
+				case WM_MOUSEMOVE:break;
+				case WM_LBUTTONDBLCLK:
+					{
+						SendMessage(hWnd,WM_COMMAND,MAKEWPARAM(gbCapturing?ID_FILE_PAUSECAPTURINGTOAVI:ID_FILE_STARTCAPTURINGTOAVI,0),0);
+						break;
+					}
+				case WM_RBUTTONDOWN:
+					{
+						POINT pt;GetCursorPos(&pt);
+						SetForegroundWindow(hWnd);
+						TrackPopupMenu(GetSubMenu(ghMenu,0),TPM_LEFTALIGN|TPM_BOTTOMALIGN,pt.x,pt.y,0,hWnd,NULL);
+						break;
+					}
+			}
+			break;
+		}
+	case WM_DESTROY:
+		{
+			if(nTimerId)
+			{
+				KillTimer(hWnd,nTimerId);
+				nTimerId=0;
+			}
+			Cleanup();
+			if(pAviFile)
+			{
+				delete pAviFile;
+				pAviFile = NULL;
+			}
+			if(hBackDC)
+			{
+				DeleteDC(hBackDC);
+				hBackDC=NULL;
+			}
+			if(hBackBitmap)
+			{
+				DeleteObject(hBackBitmap);
+				hBackBitmap=NULL;
+			}
+			Shell_NotifyIcon(NIM_DELETE,&nid);
+			DestroyMenu(ghMenu);
+			PostQuitMessage(0);
+			break;
+		}
+	default:
+		return DefWindowProc(hWnd, message, wParam, lParam);
+	}
+	return 0;
+}
+
+// Message handler for about box.
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+	switch (message)
+	{
+	case WM_INITDIALOG:
+		return TRUE;
+
+	case WM_COMMAND:
+		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+		{
+			EndDialog(hDlg, LOWORD(wParam));
+			return TRUE;
+		}
+		break;
+	}
+	return FALSE;
+}
+
+void Render()
+{
+	HRESULT	hr;
+	if(g_pd3dDevice)
+	{
+		hr=g_pd3dDevice->TestCooperativeLevel();//Check Device Status - if Alt+tab or some such thing have caused any trouble
+		if(hr!=D3D_OK)
+		{
+			if(hr==D3DERR_DEVICELOST)	return;	//Device is lost - Do not render now
+			if(hr==D3DERR_DEVICENOTRESET)		//Device is ready to be acquired
+			{
+				if(FAILED(Reset()))
+				{
+					DestroyWindow(ghWnd);		//If Unable to Reset Device - Close the Application
+					return;
+				}
+			}
+		}
+		g_pd3dDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,200),1.0f,0);
+		g_pd3dDevice->BeginScene();
+		g_pd3dDevice->EndScene();
+		g_pd3dDevice->Present(NULL,NULL,NULL,NULL);
+	}
+}
+
+void Cleanup()
+{
+	if(g_pSurface)
+	{
+		g_pSurface->Release();
+		g_pSurface=NULL;
+	}
+	if(g_pd3dDevice)
+	{
+		g_pd3dDevice->Release();
+		g_pd3dDevice=NULL;
+	}
+	if(g_pD3D)
+	{
+		g_pD3D->Release();
+		g_pD3D=NULL;
+	}
+}
+
+HRESULT	InitD3D(HWND hWnd)
+{
+	D3DDISPLAYMODE	ddm;
+	D3DPRESENT_PARAMETERS	d3dpp;
+
+	if((g_pD3D=Direct3DCreate9(D3D_SDK_VERSION))==NULL)
+	{
+		ErrorMessage("Unable to Create Direct3D ");
+		return E_FAIL;
+	}
+
+	if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))
+	{
+		ErrorMessage("Unable to Get Adapter Display Mode");
+		return E_FAIL;
+	}
+
+	ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
+
+	d3dpp.Windowed=WINDOW_MODE;
+	d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+	d3dpp.BackBufferFormat=ddm.Format;
+	d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
+	d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
+	d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
+	d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
+	d3dpp.hDeviceWindow=hWnd;
+	d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
+	d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
+
+	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dpp,&g_pd3dDevice)))
+	{
+		ErrorMessage("Unable to Create Device");
+		return E_FAIL;
+	}
+
+	if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &g_pSurface, NULL)))
+	{
+		ErrorMessage("Unable to Create Surface");
+		return E_FAIL;
+	}
+
+	return S_OK;
+}
+
+HRESULT Reset()
+{
+	D3DDISPLAYMODE	ddm;
+	D3DPRESENT_PARAMETERS	d3dpp;
+
+	if(g_pSurface)														//Release the Surface - we need to get the latest surface
+	{
+		g_pSurface->Release();
+		g_pSurface = NULL;
+	}
+
+	if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&ddm)))	//User might have changed the mode - Get it afresh
+	{
+		ErrorMessage("Unable to Get Adapter Display Mode");
+		return E_FAIL;
+	}
+
+	ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
+
+	d3dpp.Windowed=WINDOW_MODE;
+	d3dpp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+	d3dpp.BackBufferFormat=ddm.Format;
+	d3dpp.BackBufferHeight=nDisplayHeight=gScreenRect.bottom =ddm.Height;
+	d3dpp.BackBufferWidth=nDisplayWidth=gScreenRect.right =ddm.Width;
+	d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
+	d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
+	d3dpp.hDeviceWindow=ghWnd;
+	d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT;
+	d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
+
+	if(FAILED(g_pd3dDevice->Reset(&d3dpp)))
+	{
+		//ErrorMessage("Unable to Create Device");				//Dont present messages when device is lost
+		return E_FAIL;
+	}
+
+	if(FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &g_pSurface, NULL)))
+	{
+		//ErrorMessage("Unable to Create Surface");
+		return E_FAIL;
+	}
+
+	return S_OK;
+}
+
+void	SaveBitmap(char *szFilename,HBITMAP hBitmap)
+{
+	HDC					hdc=NULL;
+	FILE*				fp=NULL;
+	LPVOID				pBuf=NULL;
+	BITMAPINFO			bmpInfo;
+	BITMAPFILEHEADER	bmpFileHeader;
+
+	do{
+
+		hdc=GetDC(NULL);
+		ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
+		bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+		GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
+
+		if(bmpInfo.bmiHeader.biSizeImage<=0)
+			bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
+
+		if((pBuf=malloc(bmpInfo.bmiHeader.biSizeImage))==NULL)
+		{
+			MessageBox(NULL,_T("Unable to Allocate Bitmap Memory"),_T("Error"),MB_OK|MB_ICONERROR);
+			break;
+		}
+
+		bmpInfo.bmiHeader.biCompression=BI_RGB;
+		GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf,&bmpInfo,DIB_RGB_COLORS);
+
+		if((fp=fopen(szFilename,"wb"))==NULL)
+		{
+			MessageBox(NULL,_T("Unable to Create Bitmap File"),_T("Error"),MB_OK|MB_ICONERROR);
+			break;
+		}
+
+		bmpFileHeader.bfReserved1=0;
+		bmpFileHeader.bfReserved2=0;
+		bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
+		bmpFileHeader.bfType='MB';
+		bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
+
+		fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
+		fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
+		fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
+
+	}while(false);
+
+		if(hdc)
+			ReleaseDC(NULL,hdc);
+
+		if(pBuf)
+			free(pBuf);
+
+		if(fp)
+			fclose(fp);
+}
Index: trunk/src/testing/app/mframes/README.txt
===================================================================
--- trunk/src/testing/app/mframes/README.txt	(revision 4)
+++ trunk/src/testing/app/mframes/README.txt	(revision 4)
@@ -0,0 +1,28 @@
+_____________To compile:
+
+1.
+  cd init_code
+  make
+  cd ..
+2.
+  cd machine_gen
+  make
+  cd ..
+3.
+  make
+
+______________Dataset file example:
+
+1. NOSAGE
+2. MagicFrames 0 0
+3. 11400 2800
+4. 512 512
+5. 117
+6. /data/evl/MagicCarpet/animations/jt_slices 1
+
+1 -- SAGE or NOSAGE
+2 -- Application Name, Horizontal/Vertical offset 4 the window
+3 -- Resolution of the global image
+4 -- Resolution of the data tiles
+5 -- Number of frames
+6 -- Location of the dataset and number of color components
Index: trunk/src/testing/app/mframes/machine.dat
===================================================================
--- trunk/src/testing/app/mframes/machine.dat	(revision 4)
+++ trunk/src/testing/app/mframes/machine.dat	(revision 4)
@@ -0,0 +1,6 @@
+10.0.8.111
+10.0.8.112
+10.0.8.113
+10.0.8.116
+10.0.8.117
+10.0.8.118
Index: trunk/src/testing/app/mframes/Makefile
===================================================================
--- trunk/src/testing/app/mframes/Makefile	(revision 4)
+++ trunk/src/testing/app/mframes/Makefile	(revision 4)
@@ -0,0 +1,13 @@
+build: machinefile_gen init_magic_frames
+
+machinefile_gen: machinefile_code/machinefile_gen
+	cp machinefile_code/machinefile_gen .
+	
+init_magic_frames: init_code/init_magic_frames
+	cp init_code/init_magic_frames .
+
+clean:
+	rm machinefile_gen
+	rm init_magic_frames
+	cd machinefile_code && make clean
+	cd init_code && make clean
Index: trunk/src/testing/app/mframes/init_code/file_parsers.cpp
===================================================================
--- trunk/src/testing/app/mframes/init_code/file_parsers.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/file_parsers.cpp	(revision 4)
@@ -0,0 +1,688 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: file_parsers.cpp
+-	Purpose: Contains function implementation for file i/o to load in
+-	and write out tiled display system descriptions
+---------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+using namespace std;
+
+#include "file_parsers.h"
+
+#define UP_MULLION 0
+#define DOWN_MULLION 1
+#define LEFT_MULLION 2
+#define RIGHT_MULLION 3
+
+#ifdef _cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------
+int stdInputFileParser(char* filename,PhysicalDisplay*& pd,DisplayCluster*& dc,VirtualDesktop*& vd)
+{
+	if(filename == NULL)
+		return -1;
+
+	FILE* fin = fopen(filename,"r");
+
+	if(fin == NULL)
+		return -1;
+
+	//create objects
+//	cout << "Creating High Level Objects" << endl;
+
+	if(pd == NULL)
+		pd = new PhysicalDisplay();
+	if(dc == NULL)
+		dc = new DisplayCluster();
+	if(vd == NULL)
+		vd = new VirtualDesktop();
+
+	//setup associations
+//	cout << "Setting Associations" << endl;
+	dc->VirtualDesktopAssoc(vd);
+	dc->PhysicalDisplayAssoc(pd);
+	vd->PhysicalDisplayAssoc(pd);
+	vd->DisplayClusterAssoc(dc);
+	pd->VirtualDesktopAssoc(vd);
+	pd->DisplayClusterAssoc(dc);
+
+	Virtual_Desktop_Tile** tempVDT = NULL;
+	Physical_Tile** tempPT = NULL;
+	Display_Node** tempDN = NULL;
+	VDTtoPTmapper*** tempMapper = NULL;
+	char buffer1[32];
+
+//	cout << "Gathering: Dimensions - ";
+	//First is Dimension Data
+	fscanf(fin,"%s",buffer1);
+	while( !strcmp( buffer1, "#" ))
+	{
+		while(fgetc(fin) != '\n');
+		fscanf(fin,"%s",buffer1);
+	}
+
+	if(strcmp( buffer1, "TileDisplay"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Dimensions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+	int dimx, dimy;
+	fscanf(fin, "%d %d\n", &dimx, &dimy);
+
+	//Next is the Mullions for every screen
+//	cout << "Mullions - ";
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Mullions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float mullions[4];
+	fscanf( fin, "%f %f %f %f\n", &mullions[UP_MULLION], &mullions[DOWN_MULLION],
+					&mullions[LEFT_MULLION], &mullions[RIGHT_MULLION]);
+
+//	cout << "Resolution - ";
+	//Next is Resolution of each screen
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Resolution"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float resolution[2];
+	fscanf( fin, "%f %f\n", &resolution[0], &resolution[1]);
+
+//	cout << "Pixels Per Inch - ";
+	//Pixels Per Inch Is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "PPI"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float pixelsPerInch;
+	fscanf(fin, "%f\n", &pixelsPerInch);
+	pd->PixelsPerInch( pixelsPerInch );
+
+	//Determine Screen Dimensions from Pixels Per Inch & Screen Resolutions
+	float screenWidth, screenHeight;
+	screenWidth = resolution[0] / (float)pixelsPerInch;
+	screenHeight = resolution[1] / (float)pixelsPerInch;
+//	cout << "ScreenWidth x ScreenHeight: " << screenWidth << 'x' << screenHeight << endl;
+	//figure out the "total dimensions" of a tile
+	float totalWidth = screenWidth + mullions[LEFT_MULLION] + mullions[RIGHT_MULLION];
+	float totalHeight = screenHeight + mullions[UP_MULLION] + mullions[DOWN_MULLION];
+
+//	cout << "Machine Count" << endl;
+	//Number of Machines is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Machines"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	int machineCount;
+	fscanf(fin,"%d\n",&machineCount);
+
+
+	//Create the Virtual Desktop Tiles, Physical Tiles & Mappers to connect each one
+	tempVDT = new Virtual_Desktop_Tile*[dimx];
+	tempPT = new Physical_Tile*[dimx];
+//	tempMapper = new VDTtoPTmapper**[dimx];
+//	cout << "Generating Tiles & Virtual Tiles" << endl;
+	for(int i = 0; i < dimx; i++)
+	{
+		tempVDT[i] = new Virtual_Desktop_Tile[dimy];
+		tempPT[i] = new Physical_Tile[dimy];
+//		tempMapper[i] = new VDTtoPTMapper*[dimy];
+
+		for(int j = 0; j < dimy; j++)
+		{
+
+			tempPT[i][j].ScreenHeightDimension( screenHeight );
+			tempPT[i][j].ScreenWidthDimension( screenWidth );
+			tempPT[i][j].BottomMullionThickness( mullions[DOWN_MULLION] );
+			tempPT[i][j].LeftMullionThickness( mullions[LEFT_MULLION] );
+			tempPT[i][j].RightMullionThickness( mullions[RIGHT_MULLION] );
+			tempPT[i][j].TopMullionThickness( mullions[UP_MULLION] );
+
+			tempPT[i][j].LowerLeftX( i * totalWidth );
+			tempPT[i][j].LowerLeftY( j * totalHeight );
+			pd->AddPhysicalTile( &(tempPT[i][j]));
+
+		}
+	}
+
+	//Go through and get each machine
+//	cout << "Generating Machines & Creating Mappings" << endl;
+	for(int k = 0; k < machineCount; k++)
+	{
+		char ip[16];
+		char name[32];
+		int maps;
+		int tileX, tileY;
+
+//		cout << k << ' ';
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "DisplayNode"))
+		{
+//			cout << "Read: " << buffer1 << " instead of \"DisplayNode\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+		//Name
+//		cout << "Name ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Name"))
+		{
+//			cout << "Read: " << buffer1 << " instead of \"Name\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",name);
+//		cout << name << ' ';
+		//ip
+//		cout << "IP: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "IP"))
+		{
+//			cout << "Read: " << buffer1 << " instead of \"IP\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",ip);
+//		cout << ip << ' ';
+		//Monitors
+//		cout << "Monitors: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Monitors"))
+		{
+//			cout << "Read: " << buffer1 << " instead of \"Monitors\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%d", &maps );
+//		cout << maps << ' ';;
+		Display_Node* dn;
+		dn = new Display_Node();
+		dn->NumberOfMaps( maps );
+		dn->Name( name );
+		dn->IP( ip );
+
+		dc->AddDisplayNode( dn );
+
+		for( int i = 0; i < maps; i++)
+		{
+//			cout << '.';
+			fscanf(fin," (%d,%d)", &tileX, &tileY);
+//			cout << '(' <<  tileX << ',' << tileY << ')';
+			dc->GenerateMapping( &(tempVDT[tileX][tileY]), &(tempPT[tileX][tileY]), dn );
+			vd->AddTile( &(tempVDT[tileX][tileY]) );
+
+		}
+
+		//fscanf(fin,"%s\n", buffer1);
+//		cout << endl;
+
+#ifdef _DEBUG
+
+
+#endif
+
+	}
+
+//	cout << endl << "Updating Virutal Desktop" << endl;
+
+	vd->Update();
+
+	fclose(fin);
+
+	return 1;
+}
+
+//--------------------------------------------------------
+void stdOutputFileWriter(char* filename,PhysicalDisplay* pd,DisplayCluster* dc,VirtualDesktop* vd)
+{
+
+}
+
+
+//--------------------------------------------------------
+int corewallInputFileParser(char* filename, PhysicalDisplay*& pd, DisplayCluster*& dc, VirtualDesktop*& vd, int*& startPos)
+{
+
+		if(filename == NULL)
+		return -1;
+
+	FILE* fin = fopen(filename,"r");
+
+	if(fin == NULL)
+		return -1;
+
+	//create objects
+	cout << "Creating High Level Objects" << endl;
+	if(pd == NULL)
+		pd = new PhysicalDisplay();
+	if(dc == NULL)
+		dc = new DisplayCluster();
+	if(vd == NULL)
+		vd = new VirtualDesktop();
+
+	//setup associations
+	cout << "Setting Associations" << endl;
+
+	dc->VirtualDesktopAssoc(vd);
+	dc->PhysicalDisplayAssoc(pd);
+	vd->PhysicalDisplayAssoc(pd);
+	vd->DisplayClusterAssoc(dc);
+	pd->VirtualDesktopAssoc(vd);
+	pd->DisplayClusterAssoc(dc);
+
+	Virtual_Desktop_Tile** tempVDT = NULL;
+	Physical_Tile** tempPT = NULL;
+	Display_Node** tempDN = NULL;
+	VDTtoPTmapper*** tempMapper = NULL;
+	char buffer1[32];
+
+	//cout << "Gathering: Dimensions - ";
+	printf("getting dimensions\n");
+	//First is Dimension Data
+	fscanf(fin,"%s",buffer1);
+	while( !strcmp( buffer1, "#" ))
+	{
+		while(fgetc(fin) != '\n');
+		fscanf(fin,"%s",buffer1);
+	}
+
+	if(strcmp( buffer1, "TileDisplay"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Dimensions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+	int dimx, dimy;
+	fscanf(fin, "%d %d\n", &dimx, &dimy);
+
+	//Next is the Mullions for every screen
+	cout << "Mullions - ";
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Mullions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float mullions[4];
+	fscanf( fin, "%f %f %f %f\n", &mullions[UP_MULLION], &mullions[DOWN_MULLION],
+					&mullions[LEFT_MULLION], &mullions[RIGHT_MULLION]);
+
+	cout << "Resolution - ";
+	//Next is Resolution of each screen
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Resolution"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float resolution[2];
+	fscanf( fin, "%f %f\n", &resolution[0], &resolution[1]);
+
+	cout << "Pixels Per Inch - ";
+	//Pixels Per Inch Is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "PPI"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float pixelsPerInch;
+	fscanf(fin, "%f\n", &pixelsPerInch);
+	pd->PixelsPerInch( pixelsPerInch );
+
+	//Determine Screen Dimensions from Pixels Per Inch & Screen Resolutions
+	float screenWidth, screenHeight;
+	screenWidth = resolution[0] / (float)pixelsPerInch;
+	screenHeight = resolution[1] / (float)pixelsPerInch;
+	cout << "ScreenWidth x ScreenHeight: " << screenWidth << 'x' << screenHeight << endl;
+	//figure out the "total dimensions" of a tile
+	float totalWidth = screenWidth + mullions[LEFT_MULLION] + mullions[RIGHT_MULLION];
+	float totalHeight = screenHeight + mullions[UP_MULLION] + mullions[DOWN_MULLION];
+
+	cout << "Machine Count" << endl;
+	//Number of Machines is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Machines"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	int machineCount;
+	fscanf(fin,"%d\n",&machineCount);
+
+	//get the offsets
+	cout << "OffsetX" << endl;
+	//OffsetX is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "OffsetX"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%d\n",&(startPos[0]));
+
+
+	cout << "OffsetY" << endl;
+	//OffsetY is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "OffsetY"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%d\n",&(startPos[1]));
+
+
+	//Create the Virtual Desktop Tiles, Physical Tiles & Mappers to connect each one
+	tempVDT = new Virtual_Desktop_Tile*[dimx];
+	tempPT = new Physical_Tile*[dimx];
+//	tempMapper = new VDTtoPTmapper**[dimx];
+	cout << "Generating Tiles & Virtual Tiles" << endl;
+	for(int i = 0; i < dimx; i++)
+	{
+		tempVDT[i] = new Virtual_Desktop_Tile[dimy];
+		tempPT[i] = new Physical_Tile[dimy];
+//		tempMapper[i] = new VDTtoPTMapper*[dimy];
+
+		for(int j = 0; j < dimy; j++)
+		{
+
+			tempPT[i][j].ScreenHeightDimension( screenHeight );
+			tempPT[i][j].ScreenWidthDimension( screenWidth );
+			tempPT[i][j].BottomMullionThickness( mullions[DOWN_MULLION] );
+			tempPT[i][j].LeftMullionThickness( mullions[LEFT_MULLION] );
+			tempPT[i][j].RightMullionThickness( mullions[RIGHT_MULLION] );
+			tempPT[i][j].TopMullionThickness( mullions[UP_MULLION] );
+
+			tempPT[i][j].LowerLeftX( i * totalWidth );
+			tempPT[i][j].LowerLeftY( j * totalHeight );
+			pd->AddPhysicalTile( &(tempPT[i][j]));
+
+		}
+	}
+
+	//Get the starting offsets
+	//Go through and get each machine
+	cout << "Generating Machines & Creating Mappings" << endl;
+	for(int k = 0; k < machineCount; k++)
+	{
+		char ip[16];
+		char name[32];
+		int maps;
+		int tileX, tileY;
+
+		cout << k << ' ';
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "DisplayNode"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"DisplayNode\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+		//Name
+		cout << "Name ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Name"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Name\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",name);
+		cout << name << ' ';
+		//ip
+		cout << "IP: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "IP"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"IP\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",ip);
+		cout << ip << ' ';
+		//Monitors
+		cout << "Monitors: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Monitors"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Monitors\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%d", &maps );
+		cout << maps << ' ';;
+		Display_Node* dn;
+		dn = new Display_Node();
+		dn->NumberOfMaps( maps );
+		dn->Name( name );
+		dn->IP( ip );
+
+		dc->AddDisplayNode( dn );
+
+		for( int i = 0; i < maps; i++)
+		{
+			cout << '.';
+			fscanf(fin," (%d,%d)", &tileX, &tileY);
+//			cout << '(' <<  tileX << ',' << tileY << ')';
+			dc->GenerateMapping( &(tempVDT[tileX][tileY]), &(tempPT[tileX][tileY]), dn );
+			tempVDT[tileX][tileY].NonMullionLLX( resolution[0] * tileX );
+			tempVDT[tileX][tileY].NonMullionLLY( resolution[1] * tileY );
+			cout << "NonMullion x,y: " << screenWidth * tileX << ", "
+				<< screenHeight * tileY << endl;
+			vd->AddTile( &(tempVDT[tileX][tileY]) );
+		}
+
+		//fscanf(fin,"%s\n", buffer1);
+//		cout << endl;
+
+#ifdef _DEBUG
+
+
+#endif
+
+	}
+
+	cout << endl << "Updating Virutal Desktop" << endl;
+
+	vd->Update();
+
+	fclose(fin);
+
+	return 1;
+}
+
+#ifdef _cplusplus
+}
+#endif
+
Index: trunk/src/testing/app/mframes/init_code/initf.h
===================================================================
--- trunk/src/testing/app/mframes/init_code/initf.h	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/initf.h	(revision 4)
@@ -0,0 +1,352 @@
+
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#ifndef ANIMVIEWER_H
+#define ANIMVIEWER_H
+
+//#include "vtkXOpenGLOffScreenRenderWindow.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+using namespace std;
+
+/************************/
+
+#include "tile_config.h"
+#include "file_parsers.h"
+
+// SAGE related headers
+#include <sail.h>
+#include <misc.h>
+
+/************************/
+
+
+/* MPI */
+#include <mpi.h>
+
+/* VTK */
+#include <vtk/vtkActor.h>
+#include <vtk/vtkCamera.h>
+#include <vtk/vtkLight.h>
+#include <vtk/vtkRenderWindow.h>
+#include <vtk/vtkRenderer.h>
+#include <vtk/vtkImageImport.h>
+#include <vtk/vtkTexture.h>
+#include <vtk/vtkTransformTextureCoords.h>
+#include <vtk/vtkTextureMapToPlane.h>
+#include <vtk/vtkPlaneSource.h>
+#include <vtk/vtkMergeFilter.h>
+#include <vtk/vtkPolyDataMapper.h>
+#include <vtk/vtkImageFlip.h>
+#include <vtk/vtkProperty.h>
+#include <vtk/vtkSphereSource.h>
+#include <vtk/vtkTextSource.h>
+#include <vtk/vtkFrustumCoverageCuller.h>
+#include <vtk/vtkTextActor.h>
+#include <vtk/vtkTextProperty.h>
+
+#include <vtk/vtkSphereSource.h>
+#include <vtk/vtkCubeSource.h>
+#include <vtk/vtkConeSource.h>
+#include <vtk/vtkJPEGReader.h>
+#include <vtk/vtkImageMapper.h>
+#include <vtk/vtkActor2D.h>
+
+/* QUANTA */
+#include <QUANTA/QUANTAinit.hxx>
+#include <QUANTA/QUANTAnet_tcp_c.hxx>
+#include <QUANTA/QUANTAnet_datapack_c.hxx>
+
+#define PANLEFT "panleft"
+#define PANRIGHT "panright"
+#define PANUP "panup"
+#define PANDOWN "pandown"
+#define BROWSERIGHT "browseright"
+#define BROWSELEFT "browseleft"
+#define ZOOMIN "zoomin"
+#define ZOOMOUT "zoomout"
+#define SELECT "select"
+#define RELEASE "release"
+#define PRESS "press"
+#define SLIDER1 "slider1"
+#define SLIDER2 "slider2"
+#define SLIDER3 "slider3"
+#define QUIT "quit"
+#define CENTER "center"
+
+int PORT= 5678;
+#define TRANSMISSION_SIZE 16
+
+#define ZIN 1
+#define ZOUT 0
+
+QUANTAnet_tcpServer_c* server;
+QUANTAnet_tcpClient_c* client;
+char* recmsg;
+
+double CamPosition[3];
+double Fpoint[3];
+double PanAmount;
+
+double Zoom = 7;
+double ZoomAmount;
+
+double StartingZ;
+
+//SAGE STUFF
+int winWidth, winHeight;
+sail sageInf;
+
+int rank;
+int size;
+
+int xWindowPos = 0;
+int yWindowPos = 0;
+
+vtkRenderer* renA = vtkRenderer::New();
+vtkRenderer* renB = vtkRenderer::New();
+vtkRenderWindow* renWin = vtkRenderWindow::New();
+vtkLight* light = vtkLight::New();
+vtkFrustumCoverageCuller* culler = vtkFrustumCoverageCuller::New();
+vtkTextActor *text = vtkTextActor::New();
+
+vtkConeSource *cone = vtkConeSource::New();
+vtkCubeSource *cube = vtkCubeSource::New();
+vtkSphereSource *sphere = vtkSphereSource::New();
+vtkPolyDataMapper *sphereMapper = vtkPolyDataMapper::New();
+vtkActor *pointer = vtkActor::New();
+
+vtkJPEGReader *splash = vtkJPEGReader::New();
+vtkImageMapper *splashMapper = vtkImageMapper::New();
+vtkActor2D *splashScreen = vtkActor2D::New();
+
+#define PANSUBDIVISIONS 10
+
+#define GRAYSCALE 1
+#define RGB 3
+#define RGBA 4
+int MODE;
+
+int start = 0;
+int end = 0;
+
+#define LEFT -1
+#define RIGHT 1
+#define UP -2
+#define DOWN 2
+#define ACCEPT 0
+
+#define X 0
+#define Y 1
+
+int CurrentLevel = 0;
+
+//#define DEBUG
+
+struct ZBound {
+	double bound;
+};
+
+struct Viewable {
+	long level;
+	bool virgin;
+	unsigned char*** pixels;
+};
+
+struct Point {
+	long l;
+	long c;
+	long r;
+};
+
+struct Geometry {
+	vtkImageImport *importer;
+	vtkTexture* texture;
+	vtkPolyDataMapper *mapper;
+	vtkActor* actor;
+	vtkPlaneSource *plane;
+	vtkImageFlip *flip;
+
+	vtkTextSource *textSource;
+	vtkPolyDataMapper *textMapper;
+	vtkActor *textActor;
+
+
+	int fd;
+};
+
+struct Info {
+
+	double scale[2];
+	double position[3];
+	double depth[1];
+};
+
+
+
+
+
+class AnimViewer {
+
+
+public:
+
+	AnimViewer();
+	~AnimViewer();
+
+	string IntToString(long);
+	void CopyBuffer(unsigned char*, unsigned char*);
+	long GetNumOfCols(long, long);
+	long GetNumOfRows(long, long);
+	long GetLevelBlockWidth(long);
+	long GetLevelBlockHeight(long);
+	long GetLevelNumOfCols(long);
+	long GetLevelNumOfRows(long);
+	void InitViewer(char*);
+	void GetAnimFiles();
+	unsigned char* GetPixelsFromFile(long, long, long);
+	unsigned char* MMap(long, long, long);
+	void InitRendering();
+	void SetUpPipeline();
+	void UpdateBlock(long, long, long);
+	void ImportQueryWindowPixels();
+	void FindStartingQueryWindow();
+	void GivePixelsToVTK();
+	void QueryWindowPanRight();
+	void QueryWindowPanLeft();
+	void QueryWindowPanUp();
+	void QueryWindowPanDown();
+	void QueryWindowZoomIn();
+	void QueryWindowZoomOut();
+	void PositionAndScaleBlocks();
+	void ComputeStartingBlockSize();
+	double GetRowPositionAtLevel(long, long);
+	double GetColPositionAtLevel(long, long);
+	double GetBlockWidthAtLevel(long);
+	double GetBlockHeightAtLevel(long);
+	void AddBlock(long, long, long);
+	void RemoveBlock(long, long, long);
+
+	void AdjustLevelMovement(int, int);
+	int AdjustZoomMovement(int);
+	long GetQueryWindowLevel();
+	int BlockOutOfBounds(long, long, long, long);
+
+	void ZoomIn();
+	void ZoomOut();
+	void PanLeft();
+	void PanRight();
+	void PanUp();
+	void PanDown();
+	void UpdateCamera(double[], double[]);
+	double GetCenterX();
+	double GetCenterY();
+	void RepositionCamera();
+
+	void RemoveRegion(long, long, long, long, long);
+	void AddRegion(long, long, long, long, long);
+
+	void GetCamProjection(double, double);
+	void BuildMainQueryWindow();
+
+	void BringUpStartingImage();
+
+	bool NeedToUpdateMainWindow();
+
+	void CleanUpMainWindow();
+
+	void SetTimeStep(int);
+
+	void CreateZoomBounds();
+
+	void GetZProjection(double);
+
+	void SetCurrentLevel(int);
+
+	void SetInitialCamPosition();
+
+
+private:
+
+	int BlockDimensions[2];
+	int GlobalDimensions[2];
+
+
+	int Colorspace;
+
+	string AnimDir;
+
+	int NumOfLevels;
+
+	int StartingLevel;
+
+	unsigned char* pixelbuff;
+
+	string*** AnimFiles;
+
+	Geometry*** Block;
+
+	Viewable QueryWindow;
+	Info** BlockInfo;
+	double BlockInitSize[2];
+
+	Point CamProjection;
+
+	ZBound* ZoomBounds;
+	int NumOfZBounds;
+
+	unsigned char* Blank;
+
+
+	int NumOfCols;
+	int NumOfRows;
+};
+
+
+#endif
Index: trunk/src/testing/app/mframes/init_code/display.cfg
===================================================================
--- trunk/src/testing/app/mframes/init_code/display.cfg	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/display.cfg	(revision 4)
@@ -0,0 +1,51 @@
+TileDisplay
+	Dimensions 3 3
+	Mullions 0 0 0 0
+	Resolution 800 600 
+	PPI 85
+	Machines 9
+
+DisplayNode 
+	Name something1
+	IP 131.193.108.111
+	Monitors 1 (0,0)
+
+DisplayNode 
+	Name something2
+	IP 131.193.108.112
+	Monitors 1 (1,0)
+
+DisplayNode 
+	Name something3
+	IP 131.193.108.113
+	Monitors 1 (2,0)
+
+DisplayNode 
+	Name something4
+	IP 131.193.108.114
+	Monitors 1 (0,1)
+
+DisplayNode 
+	Name something5
+	IP 131.193.108.115
+	Monitors 1 (1,1)
+
+DisplayNode 
+	Name something6
+	IP 131.193.108.116
+	Monitors 1 (1,2)
+
+DisplayNode 
+	Name something7
+	IP 131.193.108.117
+	Monitors 1 (0,2)
+
+DisplayNode 
+	Name something8
+	IP 131.193.108.118
+	Monitors 1 (1,2)
+
+DisplayNode 
+	Name something9
+	IP 131.193.108.119
+	Monitors 1 (2,2)
Index: trunk/src/testing/app/mframes/init_code/tile_config.cpp
===================================================================
--- trunk/src/testing/app/mframes/init_code/tile_config.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/tile_config.cpp	(revision 4)
@@ -0,0 +1,909 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: tile_config.cpp
+-	Purpose: Contains all class details/implementation for building
+-	a description of a tile display system, at run time
+---------------------------------------------------------------------------*/
+#include "tile_config.h"
+#include <string.h>
+
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Physical_Tile::Physical_Tile():screenWidth(0),screenHeight(0),
+				leftMullion(0),rightMullion(0),topMullion(0),bottomMullion(0),
+				id(-1),next(NULL),source(NULL)
+{
+	//nothing else to do
+}
+
+Physical_Tile::~Physical_Tile()
+{
+
+	source = NULL;
+	next = NULL;
+
+}
+
+void Physical_Tile::Source(Display_Node* dn)
+{
+	source = dn;
+}
+
+Display_Node* Physical_Tile::Source()
+{ return source; }
+
+float Physical_Tile::LowerLeftX(){ return lowerleftX; }
+float Physical_Tile::LowerLeftY(){ return lowerleftY; }
+
+void Physical_Tile::LowerLeftX(float lx){ lowerleftX = lx; }
+void Physical_Tile::LowerLeftY(float ly){ lowerleftY = ly; }
+
+
+float Physical_Tile::ScreenWidthDimension()
+{ return screenWidth; }
+
+void Physical_Tile::ScreenWidthDimension(float dim)
+{ screenWidth = dim; }
+
+float Physical_Tile::ScreenHeightDimension(void)
+{ return screenHeight; }
+
+void Physical_Tile::ScreenHeightDimension(float dim)
+{ screenHeight = dim; }
+
+float Physical_Tile::TopMullionThickness()
+{ return topMullion; }
+
+void Physical_Tile::TopMullionThickness(float t)
+{ topMullion = t; }
+
+float Physical_Tile::BottomMullionThickness()
+{ return bottomMullion; }
+
+void Physical_Tile::BottomMullionThickness(float t)
+{ bottomMullion = t; }
+
+float Physical_Tile::LeftMullionThickness()
+{ return leftMullion; }
+
+void Physical_Tile::LeftMullionThickness(float t)
+{ leftMullion = t; }
+
+float Physical_Tile::RightMullionThickness()
+{ return rightMullion; }
+
+void Physical_Tile::RightMullionThickness(float t)
+{ rightMullion = t; }
+
+int Physical_Tile::ID()
+{ return id; }
+
+void Physical_Tile::ID(int i)
+{ id = i; }
+
+Physical_Tile* Physical_Tile::Next()
+{ return next; }
+
+void Physical_Tile::Next(Physical_Tile* n)
+{ next = n; }
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Virtual_Desktop_Tile::Virtual_Desktop_Tile():lowerLeftX(0),lowerLeftY(0),widthRatio(0),
+						heightRatio(0),id(-1),next(NULL),nonMullionLLX(0),
+						nonMullionLLY(0)
+{
+	//do nothing
+}
+
+Virtual_Desktop_Tile::~Virtual_Desktop_Tile()
+{
+
+	next = NULL;
+}
+
+float Virtual_Desktop_Tile::LowerLeftX()
+{ return lowerLeftX; }
+
+void Virtual_Desktop_Tile::LowerLeftX(float x)
+{ lowerLeftX = x; }
+
+float Virtual_Desktop_Tile::LowerLeftY()
+{ return lowerLeftY; }
+
+void Virtual_Desktop_Tile::LowerLeftY(float y)
+{ lowerLeftY = y; }
+
+void Virtual_Desktop_Tile::LowerLeftPixelX(int p)
+{ lowerLeftPixelX = p; }
+
+void Virtual_Desktop_Tile::LowerLeftPixelY(int p)
+{ lowerLeftPixelY = p; }
+
+void Virtual_Desktop_Tile::WidthInPixels(int p)
+{ widthInPixels = p; }
+
+void Virtual_Desktop_Tile::HeightInPixels(int p)
+{ heightInPixels = p; }
+
+int Virtual_Desktop_Tile::LowerLeftPixelX()
+{ return lowerLeftPixelX; }
+
+int Virtual_Desktop_Tile::LowerLeftPixelY()
+{ return lowerLeftPixelY; }
+
+int Virtual_Desktop_Tile::WidthInPixels()
+{ return widthInPixels; }
+
+int Virtual_Desktop_Tile::HeightInPixels()
+{ return heightInPixels; }
+
+float Virtual_Desktop_Tile::WidthRatio()
+{ return widthRatio; }
+
+void Virtual_Desktop_Tile::WidthRatio(float r)
+{ widthRatio = r; }
+
+float Virtual_Desktop_Tile::HeightRatio()
+{ return heightRatio; }
+
+void Virtual_Desktop_Tile::HeightRatio(float r)
+{ heightRatio = r; }
+
+int Virtual_Desktop_Tile::ID()
+{ return id; }
+
+void Virtual_Desktop_Tile::ID(int i)
+{ id = i; }
+
+Virtual_Desktop_Tile* Virtual_Desktop_Tile::Next()
+{ return next; }
+
+void Virtual_Desktop_Tile::Next(Virtual_Desktop_Tile* vdt)
+{ next = vdt; }
+
+Display_Node* Virtual_Desktop_Tile::DisplayNode()
+{ return dispNode; }
+
+void Virtual_Desktop_Tile::DisplayNode(Display_Node* dn)
+{ dispNode = dn; }
+
+int Virtual_Desktop_Tile::NonMullionLLX()
+{ return nonMullionLLX; }
+
+int Virtual_Desktop_Tile::NonMullionLLY()
+{ return nonMullionLLY; }
+
+void Virtual_Desktop_Tile::NonMullionLLX(int x)
+{ nonMullionLLX = x; }
+
+void Virtual_Desktop_Tile::NonMullionLLY(int y)
+{ nonMullionLLY = y; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+VDTtoPTmapper::VDTtoPTmapper(Physical_Tile* tpt, Virtual_Desktop_Tile* tvdt):pt(tpt),vdt(tvdt)
+{ }
+
+VDTtoPTmapper::~VDTtoPTmapper()
+{ }
+
+Physical_Tile* VDTtoPTmapper::PhysicalTile(){ return pt; }
+
+Virtual_Desktop_Tile* VDTtoPTmapper::VirtualDesktopTile(){ return vdt; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Display_Node::Display_Node():nodeName(NULL),ip(NULL),next(NULL),maps(NULL),numberOfMaps(0)
+{
+
+}
+
+Display_Node::~Display_Node()
+{
+
+	if( maps && numberOfMaps)
+	{
+
+
+	}
+
+	if( ip )
+		delete [] ip;
+
+	if( nodeName )
+		delete [] nodeName;
+
+	next = NULL;
+}
+
+void Display_Node::Name(char* newName)
+{
+	if( nodeName )
+		delete [] nodeName;
+
+	nodeName = new char[strlen(newName) + 1];
+	strcpy(nodeName,newName);
+}
+
+void Display_Node::IP(char* newIP)
+{
+	if( ip )
+		delete [] ip;
+
+	ip = new char[strlen(newIP) + 1];
+	strcpy(ip,newIP);
+}
+
+char* Display_Node::Name(){ return nodeName; }
+char* Display_Node::IP(){ return ip; }
+Display_Node* Display_Node::Next(){ return next; }
+void Display_Node::Next(Display_Node* dn){ next = dn; }
+
+int Display_Node::NumberOfMaps(){ return numberOfMaps; }
+void Display_Node::NumberOfMaps(int n)	//need to adjust maps
+{
+	VDTtoPTmapper** tempMap = maps;
+	maps = NULL;
+	maps = new VDTtoPTmapper*[n];
+
+	int i = 0;
+
+	//copy over as many nodes as the new maps array can fit
+	for(	; i < n; i++)
+	{
+		if( i < numberOfMaps && tempMap)
+		{
+			maps[i] = tempMap[i];
+			tempMap[i] = NULL;
+		}
+		else
+			maps[i] = NULL;
+	}
+
+	//clean up any nodes left over in the old maps array
+	for(	; i < numberOfMaps && tempMap; i++)
+	{
+		tempMap[i]->VirtualDesktopTile()->DisplayNode(NULL);
+		tempMap[i]->PhysicalTile()->Source(NULL);
+
+	}
+
+	delete [] tempMap;
+	numberOfMaps = n;
+
+}
+
+
+VDTtoPTmapper** Display_Node::Maps(){ return maps; }
+
+bool Display_Node::AddMap(VDTtoPTmapper* pMap)
+{
+
+	for(int i = 0; i < numberOfMaps; i++)
+	{
+		if(maps[i] == NULL)
+		{
+			maps[i] = pMap;
+			maps[i]->VirtualDesktopTile()->DisplayNode(this);
+			maps[i]->PhysicalTile()->Source(this);
+			return true;
+
+		}
+
+	}
+
+	return false;
+}
+
+void Display_Node::RemoveMap(VDTtoPTmapper* vpMap)
+{
+	for(int i = 0; i < numberOfMaps; i++)
+	{
+		if(maps[i] && maps[i] == vpMap)
+		{
+			delete maps[i];
+			maps[i] = NULL;
+		}
+	}
+}
+
+void Display_Node::RemoveMap(int index)
+{
+	if(index < numberOfMaps && maps[index])
+	{
+		delete maps[index];
+		maps[index] = NULL;
+	}
+}
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+DisplayCluster::DisplayCluster():displayNodeListHead(NULL)
+{
+
+}
+
+DisplayCluster::~DisplayCluster()
+{
+
+}
+
+
+void DisplayCluster::AddDisplayNode(Display_Node* dn)
+{
+	Display_Node* temp = displayNodeListHead;
+	if(temp)
+	{
+		while(temp->Next())
+		{
+			temp = temp->Next();
+		}
+
+		temp->Next(dn);
+		dn->Next(NULL);
+	}
+	else
+	{
+		displayNodeListHead = dn;
+		dn->Next(NULL);
+
+	}
+
+}
+
+
+void DisplayCluster::RemoveDisplayNode(char* name)
+{
+
+}
+
+void DisplayCluster::RemoveDisplayNodeByName(char* name)
+{
+	RemoveDisplayNode(name);
+}
+
+
+void DisplayCluster::RemoveDisplayNodeByIP(char* ip)
+{
+
+}
+
+Display_Node* DisplayCluster::getFirstNode()
+{
+	return this->displayNodeListHead;
+}
+
+
+//Generate and insert a mapping between virtual tile and physical tile to a display node
+//Assuming the physical tile already knows the display node source
+bool DisplayCluster::GenerateMapping(Virtual_Desktop_Tile* vdt, Physical_Tile* pt)
+{
+	//make sure the physical tile is on the physical display associated with this display cluster
+	if(!pd->TileOnPhysicalDisplay(pt))
+		return false;
+
+
+	if(pt->Source() == NULL)
+		return false;		//the physical tile must already have a source
+
+	//make sure that the source node is on this display cluster
+	if(!NodeOnCluster(pt->Source()))
+		return false;
+
+	VDTtoPTmapper* map = new VDTtoPTmapper(pt,vdt);
+	if(pt->Source()->AddMap(map))
+		return true;
+
+	delete map;
+	return false;
+
+}
+
+PhysicalDisplay* DisplayCluster::PhysicalDisplayAssoc(){ return pd; }
+void DisplayCluster::PhysicalDisplayAssoc(PhysicalDisplay* tpd)
+{
+	pd = tpd;
+}
+
+//Generate and insert a mapping between virtual and physical tile using the given display node
+bool DisplayCluster::GenerateMapping(Virtual_Desktop_Tile* vdt, Physical_Tile *pt, Display_Node *dn)
+{
+	//make sure the physical tile is on the physical display associated with this display cluster
+	if(!pd->TileOnPhysicalDisplay(pt))
+		return false;
+
+	Display_Node *itr = displayNodeListHead;
+	//make sure the node is on this display cluster
+	if(!NodeOnCluster(dn))
+		return false;
+
+	VDTtoPTmapper* map = new VDTtoPTmapper(pt,vdt);
+	if(dn->AddMap(map))
+		return true;
+
+	delete map;
+	return false;
+
+}
+
+void DisplayCluster::RemoveMapping(Virtual_Desktop_Tile* vdt, Physical_Tile *pt, Display_Node* dn)
+{
+	if(!NodeOnCluster(dn))
+		return;
+
+	VDTtoPTmapper** maps = dn->Maps();
+	int count = dn->NumberOfMaps();
+
+	for(int i = 0; i < count; i++)
+	{
+		if(maps[i] && maps[i]->PhysicalTile() == pt && maps[i]->VirtualDesktopTile() == vdt)
+			dn->RemoveMap(i);
+	}
+
+}
+
+bool DisplayCluster::NodeOnCluster(Display_Node* dn)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		if(itr == dn)
+		{
+			return true;
+		}
+		itr = itr->Next();
+	}
+
+	return false;
+}
+
+void DisplayCluster::RemoveMapsWith(Virtual_Desktop_Tile* tvdt)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		VDTtoPTmapper** maps = itr->Maps();
+		int count = itr->NumberOfMaps();
+		for(	;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == tvdt)
+				itr->RemoveMap(count - 1);
+		}
+
+		itr = itr->Next();
+	}
+}
+
+void DisplayCluster::RemoveMapsWith(Physical_Tile* tpt)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		VDTtoPTmapper** maps = itr->Maps();
+		int count = itr->NumberOfMaps();
+		for(	;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->PhysicalTile() == tpt)
+				itr->RemoveMap(count - 1);
+		}
+
+		itr = itr->Next();
+	}
+}
+
+VirtualDesktop* DisplayCluster::VirtualDesktopAssoc(){ return vd; }
+void DisplayCluster::VirtualDesktopAssoc(VirtualDesktop* tvd)
+{
+
+}
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+
+PhysicalDisplay::PhysicalDisplay():physicalTileListHead(NULL),vd(NULL),dc(NULL),
+pixelsPerInch(1.0)
+{
+
+
+}
+
+PhysicalDisplay::~PhysicalDisplay()
+{
+
+}
+
+void PhysicalDisplay::VirtualDesktopAssoc(VirtualDesktop *tvd)
+{
+	vd = tvd;
+}
+VirtualDesktop* PhysicalDisplay::VirtualDesktopAssoc(){ return vd; }
+
+int PhysicalDisplay::AddPhysicalTile(Physical_Tile* pt)
+{
+	int ID = 1;
+	if(physicalTileListHead == NULL)
+	{
+		physicalTileListHead = pt;
+	}
+	else
+	{
+		Physical_Tile *itr = physicalTileListHead;
+		while(itr->Next())
+		{
+			itr = itr->Next();
+			ID++;
+		}
+
+		itr->Next(pt);
+		pt->Next(NULL);
+	}
+
+	pt->ID(ID);
+	return ID;
+}
+
+Physical_Tile* PhysicalDisplay::RemovePhysicalTileByID(int ID, bool delquery)
+{
+
+	Physical_Tile *itr = physicalTileListHead;
+
+	if(itr->ID() == ID)
+	{
+		physicalTileListHead = itr->Next();
+
+	}
+	else
+	{
+		while(itr->Next())
+		{
+			//in order to take care of accidental redundant data, loop for each entry
+			if(itr->Next()->ID() == ID)
+			{
+				itr->Next(itr->Next()->Next());
+				if(dc)
+					dc->RemoveMapsWith(itr);
+
+			}
+		}
+	}
+
+	if(delquery)
+	{
+		delete itr;
+		return NULL;
+	}
+	else
+		return itr;
+
+
+}
+
+
+DisplayCluster* PhysicalDisplay::DisplayClusterAssoc()
+{ return dc; }
+
+void PhysicalDisplay::DisplayClusterAssoc(DisplayCluster* tdc)
+{
+	//go through the current display cluster and remove all the mappings that were made to the
+	//physical tiles associated with this display cluster
+	Physical_Tile* itr = physicalTileListHead;
+	while(itr)
+	{
+		if(dc)
+			dc->RemoveMapsWith(itr);
+		itr->Source(NULL);
+		itr = itr->Next();
+	}
+
+	dc = tdc;
+
+
+}
+
+bool PhysicalDisplay::TileOnPhysicalDisplay(Physical_Tile* pt)
+{
+	Physical_Tile* itr = physicalTileListHead;
+	while(itr)
+	{
+		if(itr == pt)
+			return true;
+
+		itr = itr->Next();
+	}
+
+	return false;
+}
+Physical_Tile* PhysicalDisplay::getFirstNode()
+{ return physicalTileListHead; }
+
+float PhysicalDisplay::PixelsPerInch(){ return pixelsPerInch; }
+void PhysicalDisplay::PixelsPerInch(float ratio)
+{ pixelsPerInch = ratio; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+VirtualDesktop::VirtualDesktop():dc(NULL),pd(NULL),tileListHead(NULL),vertRes(1),horizRes(1)	//just 1 pixel by 1 pixel
+{
+}
+
+VirtualDesktop::~VirtualDesktop()
+{
+	Virtual_Desktop_Tile* itr = tileListHead;
+	while(itr)
+	{
+		if(dc)
+			dc->RemoveMapsWith(itr);
+		tileListHead = itr->Next();
+		delete itr;
+		itr = tileListHead;
+	}
+}
+
+DisplayCluster* VirtualDesktop::DisplayClusterAssoc(){ return dc; }
+void VirtualDesktop::DisplayClusterAssoc(DisplayCluster *tdc)
+{
+	dc = tdc;
+}
+
+PhysicalDisplay* VirtualDesktop::PhysicalDisplayAssoc(){ return pd; }
+void VirtualDesktop::PhysicalDisplayAssoc(PhysicalDisplay* tpd)
+{
+	pd = tpd;
+}
+
+void VirtualDesktop::AddTile(Virtual_Desktop_Tile* tvdt)
+{
+	//the tile has to be already mapped to a physical tile,
+	VDTtoPTmapper* mapping = NULL;
+	if(!dc)
+		return;
+
+	Display_Node* itr = dc->getFirstNode();
+
+	while(itr)
+	{
+		int count = itr->NumberOfMaps();
+		VDTtoPTmapper** maps = itr->Maps();
+		for( ;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == tvdt)
+			{
+				mapping = maps[count - 1];
+				itr = NULL;
+				break;
+			}
+		}
+
+		if(itr)
+			itr = itr->Next();
+	}
+
+	if(!mapping)
+		return;
+
+	//there is a mapping...continue
+
+
+	//put at end of list
+	Virtual_Desktop_Tile* vdtItr = tileListHead;
+	if(vdtItr == NULL)
+	{
+		tileListHead = tvdt;
+		tvdt->Next(NULL);
+		return;
+	}
+
+	while(vdtItr->Next())
+	{
+		vdtItr = vdtItr->Next();
+	}
+
+	vdtItr->Next(tvdt);
+	tvdt->Next(NULL);
+
+}
+
+void VirtualDesktop::RemoveTile(Virtual_Desktop_Tile* tvdt)
+{
+	Virtual_Desktop_Tile* itr = tileListHead;
+	while(itr)
+	{
+		if(itr == tvdt)
+		{
+			if(dc)
+			{
+				return dc->RemoveMapsWith(tvdt);
+			}
+		}
+		itr = itr->Next();
+	}
+
+}
+
+Virtual_Desktop_Tile* VirtualDesktop::getFirstNode(void)
+{
+	return tileListHead;
+}
+
+bool VirtualDesktop::Update()
+{
+	if(!pd)
+		return false;
+
+
+	float positiveHoriz, positiveVert, negativeHoriz, negativeVert;
+	positiveHoriz = positiveVert = negativeHoriz = negativeVert = 0.0;
+	float leftMullion, bottomMullion;
+	//need to determine the whole virtual desktop size
+	Physical_Tile* ptItr = pd->getFirstNode();
+	while(ptItr)
+	{
+		if(ptItr->LowerLeftX() < negativeHoriz)
+		{
+			negativeHoriz = ptItr->LowerLeftX();
+			leftMullion = ptItr->LeftMullionThickness();
+		}
+		else if(ptItr->LowerLeftX() + ptItr->ScreenWidthDimension() > positiveHoriz)
+		{
+			positiveHoriz = ptItr->LowerLeftX() + ptItr->ScreenWidthDimension();
+		}
+
+		if(ptItr->LowerLeftY() < negativeVert)
+		{
+			negativeVert = ptItr->LowerLeftY();
+			bottomMullion = ptItr->BottomMullionThickness();
+
+		}
+		else if(ptItr->LowerLeftY() + ptItr->ScreenHeightDimension() > positiveVert)
+		{
+			positiveVert = ptItr->LowerLeftY() + ptItr->ScreenHeightDimension();
+		}
+
+		ptItr = ptItr->Next();
+	}
+
+	//save off the resolutions.
+	horizRes = (int)((positiveHoriz - negativeHoriz) * (pd->PixelsPerInch()));
+	vertRes = (int)((positiveVert - negativeVert) * (pd->PixelsPerInch()));
+
+
+	//go through all the virtual tiles and adjust their properties based on their mapped physical tiles
+	Virtual_Desktop_Tile* vdtItr = tileListHead;
+	while(vdtItr)
+	{
+		VDTtoPTmapper* mapping;
+
+		mapping = NULL;
+		if(!dc)
+			return false;
+
+		Display_Node* itr = dc->getFirstNode();
+
+		while(itr)
+		{
+			int count = itr->NumberOfMaps();
+			VDTtoPTmapper** maps = itr->Maps();
+			for( ;count > 0; count--)
+			{
+				if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == vdtItr)
+				{
+					mapping = maps[count - 1];
+					itr = NULL;
+					break;
+				}
+			}
+
+			if(itr)
+				itr = itr->Next();
+		}
+
+		//we have an unmapped virtual tile....doesn't make sense, stop and return false
+		if(!mapping)
+			return false;
+
+		//calculate the virtual tile properties
+		float posXRatio, posYRatio, widthRatio, heightRatio;
+		posXRatio = posYRatio = widthRatio = heightRatio = 0.0;
+		Physical_Tile* ptTemp = mapping->PhysicalTile();
+
+		vdtItr->LowerLeftPixelX( (ptTemp->LowerLeftX() + ptTemp->LeftMullionThickness())  * pd->PixelsPerInch() );
+		vdtItr->LowerLeftPixelY( (ptTemp->LowerLeftY() + ptTemp->BottomMullionThickness()) * pd->PixelsPerInch() );
+		vdtItr->LowerLeftX( (float)vdtItr->LowerLeftPixelX() / horizRes);
+		vdtItr->LowerLeftY( (float)vdtItr->LowerLeftPixelY() / vertRes);
+
+		vdtItr->WidthInPixels( ptTemp->ScreenWidthDimension() * pd->PixelsPerInch() );
+		vdtItr->HeightInPixels( ptTemp->ScreenHeightDimension() * pd->PixelsPerInch());
+		vdtItr->WidthRatio( (float)vdtItr->WidthInPixels() / horizRes);
+		vdtItr->HeightRatio( (float)vdtItr->HeightInPixels() / vertRes);
+
+		vdtItr->ID( ptTemp->ID());	//map the id of the virtual tile to the same id of the physical tile
+
+		//move on
+		vdtItr = vdtItr->Next();
+
+	}
+
+
+	return true;
+
+}
Index: trunk/src/testing/app/mframes/init_code/file_parsers.h
===================================================================
--- trunk/src/testing/app/mframes/init_code/file_parsers.h	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/file_parsers.h	(revision 4)
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: file_parsers.h
+-	Purpose: Contains function prototypes for file i/o to load in
+-	and write out tiled display system descriptions
+---------------------------------------------------------------------------*/
+#ifndef TILE_CONFIG_FILE_PARSERS_H
+#define TILE_CONFIG_FILE_PARSERS_H
+
+#include "tile_config.h"
+
+//Standard File, I/O functions for tile_config library
+//----------------------------------------------------
+//Parameters
+// [in] filename	- name of the config file
+// [in, out] pd		- the returned physical display (send a pointer that isn't pointing to an actual physical display)
+// [in, out] dc		- the returned display cluster (send a pointer that isn't pointing to an actual display cluster)
+// [in, out] vd		- the returned virutal desktop (send a pointer that isn't pointing to an actual virtual desktop)
+
+#ifdef _cplusplus
+extern "C" {
+#endif
+
+int stdInputFileParser(char* filename,PhysicalDisplay*& pd,DisplayCluster*& dc,VirtualDesktop*& vd);
+void stdOutputFileWriter(char* filename,PhysicalDisplay* pd,DisplayCluster* dc,VirtualDesktop* vd);
+int corewallInputFileParser(char* filename, PhysicalDisplay*& pd, DisplayCluster*& dc, VirtualDesktop*& vd, int*& startPos);
+
+#ifdef _cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.cxx
===================================================================
--- trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.cxx	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.cxx	(revision 4)
@@ -0,0 +1,1140 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    $RCSfile: vtkXOpenGLOffScreenRenderWindow.cxx,v $
+  Language:  C++
+  Date:      $Date: 2003/03/26 14:04:59 $
+  Version:   $Revision: 1.42 $
+
+  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include <GL/gl.h>
+#include "GL/glx.h"
+
+#include "vtkXOpenGLOffScreenRenderWindow.h"
+#include "vtk/vtkOpenGLRenderer.h"
+#include "vtk/vtkOpenGLProperty.h"
+#include "vtk/vtkOpenGLTexture.h"
+#include "vtk/vtkOpenGLCamera.h"
+#include "vtk/vtkOpenGLLight.h"
+#include "vtk/vtkOpenGLActor.h"
+#include "vtk/vtkOpenGLPolyDataMapper.h"
+
+
+
+#include "vtk/vtkToolkits.h"
+
+#include "vtk/vtkCommand.h"
+#include "vtk/vtkIdList.h"
+#include "vtk/vtkObjectFactory.h"
+#include "vtk/vtkRendererCollection.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+
+class vtkXOpenGLOffScreenRenderWindow;
+class vtkRenderWindow;
+class vtkXOpenGLOffScreenRenderWindowInternal
+{
+  friend class vtkXOpenGLOffScreenRenderWindow;
+private:
+  vtkXOpenGLOffScreenRenderWindowInternal(vtkRenderWindow*);
+
+  GLXContext ContextId;
+};
+
+vtkXOpenGLOffScreenRenderWindowInternal::vtkXOpenGLOffScreenRenderWindowInternal(
+  vtkRenderWindow * vtkNotUsed(rw))
+{
+  this->ContextId = NULL;
+}
+
+
+vtkCxxRevisionMacro(vtkXOpenGLOffScreenRenderWindow, "$Revision: 0.01 $");
+vtkStandardNewMacro(vtkXOpenGLOffScreenRenderWindow);
+
+
+#define MAX_LIGHTS 8
+
+
+XVisualInfo *vtkXOpenGLOffScreenRenderWindowTryForVisual(Display *DisplayId,
+                                               int doublebuff, int stereo,
+                                               int multisamples)
+{
+  int           index;
+  static int    attributes[50];
+
+  // setup the default stuff we ask for
+  index = 0;
+  attributes[index++] = GLX_RGBA;
+  attributes[index++] = GLX_RED_SIZE;
+  attributes[index++] = 1;
+  attributes[index++] = GLX_GREEN_SIZE;
+  attributes[index++] = 1;
+  attributes[index++] = GLX_BLUE_SIZE;
+  attributes[index++] = 1;
+  attributes[index++] = GLX_DEPTH_SIZE;
+  attributes[index++] = 1;
+  if (doublebuff)
+    {
+    attributes[index++] = GLX_DOUBLEBUFFER;
+    }
+  if (stereo)
+    {
+    // also try for STEREO
+    attributes[index++] = GLX_STEREO;
+    }
+  if (multisamples)
+    {
+#ifdef GLX_SAMPLE_BUFFERS_SGIS
+    attributes[index++] = GLX_SAMPLE_BUFFERS_SGIS;
+    attributes[index++] = 1;
+    attributes[index++] = GLX_SAMPLES_SGIS;
+    attributes[index++] = multisamples;
+#endif
+    }
+
+  attributes[index++] = None;
+
+  return glXChooseVisual(DisplayId, DefaultScreen(DisplayId), attributes );
+}
+
+XVisualInfo *vtkXOpenGLOffScreenRenderWindow::GetDesiredVisualInfo()
+{
+  XVisualInfo   *v = NULL;
+  int           multi;
+  int           stereo = 0;
+
+  // get the default display connection
+  if (!this->DisplayId)
+    {
+    this->DisplayId = XOpenDisplay((char *)NULL);
+    if (this->DisplayId == NULL)
+      {
+      vtkErrorMacro(<< "bad X server connection.\n");
+      }
+    this->OwnDisplay = 1;
+    }
+
+  // try every possibility stoping when we find one that works
+  for (stereo = this->StereoCapableWindow; !v && stereo >= 0; stereo--)
+    {
+    for (multi = this->MultiSamples; !v && multi >= 0; multi--)
+      {
+      if (v)
+        {
+        XFree(v);
+        }
+      v = vtkXOpenGLOffScreenRenderWindowTryForVisual(this->DisplayId,
+                                            this->DoubleBuffer,
+                                            stereo, multi);
+      if (v && this->StereoCapableWindow && !stereo)
+        {
+        // requested a stereo capable window but we could not get one
+        this->StereoCapableWindow = 0;
+        }
+      }
+    }
+  for (stereo = this->StereoCapableWindow; !v && stereo >= 0; stereo--)
+    {
+    for (multi = this->MultiSamples; !v && multi >= 0; multi--)
+      {
+      if (v)
+        {
+        XFree(v);
+        }
+      v = vtkXOpenGLOffScreenRenderWindowTryForVisual(this->DisplayId,
+                                            !this->DoubleBuffer,
+                                            stereo, multi);
+      if (v)
+        {
+        this->DoubleBuffer = !this->DoubleBuffer;
+        }
+      if (v && this->StereoCapableWindow && !stereo)
+        {
+        // requested a stereo capable window but we could not get one
+        this->StereoCapableWindow = 0;
+        }
+      }
+    }
+  if (!v)
+    {
+    vtkErrorMacro(<< "Could not find a decent visual\n");
+    }
+  return ( v );
+}
+
+vtkXOpenGLOffScreenRenderWindow::vtkXOpenGLOffScreenRenderWindow()
+{
+  this->ParentId = (Window)NULL;
+  this->ScreenSize[0] = 0;
+  this->ScreenSize[1] = 0;
+  this->OwnDisplay = 0;
+  this->CursorHidden = 0;
+  this->ForceMakeCurrent = 0;
+  this->UsingHardware = 0;
+  this->DisplayId = (Display *)NULL;
+  this->WindowId = (Window)NULL;
+  this->NextWindowId = (Window)NULL;
+  this->ColorMap = (Colormap)0;
+  this->OwnWindow = 0;
+
+  this->Internal = new vtkXOpenGLOffScreenRenderWindowInternal(this);
+
+  this->XCArrow =   0;
+  this->XCSizeAll = 0;
+  this->XCSizeNS =  0;
+  this->XCSizeWE =  0;
+  this->XCSizeNE =  0;
+  this->XCSizeNW =  0;
+  this->XCSizeSE =  0;
+  this->XCSizeSW =  0;
+
+  this->Capabilities = 0;
+}
+
+// free up memory & close the window
+vtkXOpenGLOffScreenRenderWindow::~vtkXOpenGLOffScreenRenderWindow()
+{
+  GLuint id;
+  short cur_light;
+  vtkOpenGLRenderer *ren;
+
+  // free the cursors
+  if (this->DisplayId)
+    {
+    if (this->WindowId)
+      {
+      XUndefineCursor(this->DisplayId,this->WindowId);
+      }
+    if (this->XCArrow)
+      {
+      XFreeCursor(this->DisplayId,this->XCArrow);
+      }
+    if (this->XCSizeAll)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeAll);
+      }
+    if (this->XCSizeNS)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeNS);
+      }
+    if (this->XCSizeWE)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeWE);
+      }
+    if (this->XCSizeNE)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeNE);
+      }
+    if (this->XCSizeNW)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeNW);
+      }
+    if (this->XCSizeSE)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeSE);
+      }
+    if (this->XCSizeSW)
+      {
+      XFreeCursor(this->DisplayId,this->XCSizeSW);
+      }
+    }
+
+  // make sure we have been initialized
+  if (this->Internal->ContextId)
+    {
+    this->MakeCurrent();
+
+    /* first delete all the old lights */
+    for (cur_light = GL_LIGHT0; cur_light < GL_LIGHT0+MAX_LIGHTS; cur_light++)
+      {
+      glDisable((GLenum)cur_light);
+      }
+
+    /* now delete all textures */
+    glDisable(GL_TEXTURE_2D);
+    for (int i = 1; i < this->TextureResourceIds->GetNumberOfIds(); i++)
+      {
+      id = (GLuint) this->TextureResourceIds->GetId(i);
+#ifdef GL_VERSION_1_1
+      if (glIsTexture(id))
+        {
+        glDeleteTextures(1, &id);
+        }
+#else
+      if (glIsList(id))
+        {
+        glDeleteLists(id,1);
+        }
+#endif
+      }
+
+    // tell each of the renderers that this render window/graphics context
+    // is being removed (the RendererCollection is removed by vtkRenderWindow's
+    // destructor)
+    this->Renderers->InitTraversal();
+    for ( ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject());
+          ren != NULL;
+          ren = vtkOpenGLRenderer::SafeDownCast(this->Renderers->GetNextItemAsObject())  )
+      {
+      ren->SetRenderWindow(NULL);
+      }
+
+    glFinish();
+
+    glXDestroyGLXPixmap(this->DisplayId,this->WindowId);
+    XFreePixmap(this->DisplayId,this->pixmap);
+
+      {
+      glXDestroyContext( this->DisplayId, this->Internal->ContextId);
+      this->Internal->ContextId = NULL;
+
+      // then close the old window
+      if (this->OwnWindow && this->DisplayId && this->WindowId)
+        {
+        XDestroyWindow(this->DisplayId,this->WindowId);
+        this->WindowId = (Window)NULL;
+        }
+      }
+    }
+
+  if (this->DisplayId)
+    {
+    XSync(this->DisplayId,0);
+    }
+  // if we create the display, we'll delete it
+  if (this->OwnDisplay && this->DisplayId)
+    {
+    XCloseDisplay(this->DisplayId);
+    this->DisplayId = NULL;
+    }
+  delete this->Internal;
+  delete[] this->Capabilities;
+}
+
+// End the rendering process and display the image.
+void vtkXOpenGLOffScreenRenderWindow::Frame(void)
+{
+  this->MakeCurrent();
+ //  glFlush();
+//   if (!this->AbortRender && this->DoubleBuffer && this->SwapBuffers)
+//     {
+//     glXSwapBuffers(this->DisplayId, this->WindowId);
+//     vtkDebugMacro(<< " glXSwapBuffers\n");
+//     }
+}
+
+//
+// Set the variable that indicates that we want a stereo capable window
+// be created. This method can only be called before a window is realized.
+//
+void vtkXOpenGLOffScreenRenderWindow::SetStereoCapableWindow(int capable)
+{
+  if (!this->WindowId)
+    {
+    vtkOpenGLRenderWindow::SetStereoCapableWindow(capable);
+    }
+  else
+    {
+    vtkWarningMacro(<< "Requesting a StereoCapableWindow must be performed "
+                    << "before the window is realized, i.e. before a render.");
+    }
+}
+
+// Initialize the window for rendering.
+void vtkXOpenGLOffScreenRenderWindow::WindowInitialize (void)
+{
+    XVisualInfo  *v, matcher;
+    int width = ((this->Size[0] > 0) ? this->Size[0] : 300);
+    int height = ((this->Size[1] > 0) ? this->Size[1] : 300);
+
+    // get the default display connection
+    if (!this->DisplayId)
+      {
+	this->DisplayId = XOpenDisplay((char *)NULL);
+	if (this->DisplayId == NULL)
+	  {
+	    vtkErrorMacro(<<"bad X server connection.\n");
+	  }
+      }
+
+    // get visual info and set up pixmap buffer
+    int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1,
+			    GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
+			    GLX_DEPTH_SIZE, 1, None };
+    printf("glxChooseVis DPY=%u SCRN=%u \n",(unsigned int)(this->DisplayId),
+	   DefaultScreen(this->DisplayId));
+    v = glXChooseVisual(this->DisplayId,
+			DefaultScreen(this->DisplayId),
+			attributeList);
+    fprintf(stderr,"Visual selected.\n");
+    this->Internal->ContextId = glXCreateContext(this->DisplayId,v,0,GL_FALSE);
+    /* create offscreen pixmap to render to (same depth as RootWindow) */
+    this->pixmap = XCreatePixmap(this->DisplayId,
+				 RootWindow(this->DisplayId,v->screen),
+				 width,
+				 height,
+				 v->depth);
+    printf("Depth=%d\n",v->depth);
+    this->WindowId= glXCreateGLXPixmap(this->DisplayId,v,this->pixmap);
+
+    if (v)
+      {
+      XFree(v);
+      }
+
+    this->MakeCurrent();
+    vtkDebugMacro(<< " glMatrixMode ModelView\n");
+    glMatrixMode( GL_MODELVIEW );
+    vtkDebugMacro(<< " zbuffer enabled\n");
+    glDepthFunc( GL_LEQUAL );
+    glEnable( GL_DEPTH_TEST );
+    vtkDebugMacro(" texture stuff\n");
+    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+    // initialize blending for transparency
+    vtkDebugMacro(<< " blend func stuff\n");
+    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+    glEnable(GL_BLEND);
+    glEnable( GL_NORMALIZE );
+    glAlphaFunc(GL_GREATER,0);
+    this->Mapped = 0; // if its mapped, then it trys windowgetattributes which fails!
+    this->SwapBuffers = 0;
+    this->DoubleBuffer = 0;
+}
+
+// Initialize the rendering window.
+void vtkXOpenGLOffScreenRenderWindow::Initialize (void)
+{
+  // make sure we havent already been initialized
+  if (this->Internal->ContextId)
+    {
+    return;
+    }
+
+  // now initialize the window
+  this->WindowInitialize();
+}
+
+// Change the window to fill the entire screen.
+void vtkXOpenGLOffScreenRenderWindow::SetFullScreen(int arg)
+{
+  // Just Disable it
+  return;
+}
+
+// Set the preferred window size to full screen.
+void vtkXOpenGLOffScreenRenderWindow::PrefFullScreen()
+{
+
+  // limit the off screen size
+  this->Size[0] = 1280;
+  this->Size[1] = 1024;
+
+  // don't show borders
+  this->Borders = 0;
+}
+
+// Resize the window.
+void vtkXOpenGLOffScreenRenderWindow::WindowRemap()
+{
+  short cur_light;
+
+  /* first delete all the old lights */
+  for (cur_light = GL_LIGHT0; cur_light < GL_LIGHT0+MAX_LIGHTS; cur_light++)
+    {
+    glDisable((GLenum)cur_light);
+    }
+    {
+    glXDestroyContext( this->DisplayId, this->Internal->ContextId);
+    // then close the old window
+    if (this->OwnWindow)
+      {
+      XDestroyWindow(this->DisplayId,this->WindowId);
+      }
+    }
+
+
+  // set the default windowid
+  this->WindowId = this->NextWindowId;
+  this->NextWindowId = (Window)NULL;
+
+  // configure the window
+  this->WindowInitialize();
+}
+
+// Begin the rendering process.
+void vtkXOpenGLOffScreenRenderWindow::Start(void)
+{
+  // if the renderer has not been initialized, do so now
+  if (!this->Internal->ContextId)
+    {
+    this->Initialize();
+    }
+
+  // set the current window
+  this->MakeCurrent();
+}
+
+
+// Specify the size of the rendering window.
+void vtkXOpenGLOffScreenRenderWindow::SetSize(int x,int y)
+{
+  if ((this->Size[0] != x)||(this->Size[1] != y))
+    {
+    this->Modified();
+    this->Size[0] = x;
+    this->Size[1] = y;
+    }
+
+  // if we arent mappen then just set the ivars
+  if (!this->Mapped)
+    {
+      return;
+    }
+
+  XResizeWindow(this->DisplayId,this->WindowId,x,y);
+  XSync(this->DisplayId,False);
+
+}
+
+
+
+int vtkXOpenGLOffScreenRenderWindow::GetDesiredDepth()
+{
+  XVisualInfo *v;
+  int depth = 0;
+
+  // get the default visual to use
+  v = this->GetDesiredVisualInfo();
+
+  if (v)
+    {
+    depth = v->depth;
+    XFree(v);
+    }
+
+  return depth;
+}
+
+// Get a visual from the windowing system.
+Visual *vtkXOpenGLOffScreenRenderWindow::GetDesiredVisual ()
+{
+  XVisualInfo *v;
+  Visual *vis=0;
+
+  // get the default visual to use
+  v = this->GetDesiredVisualInfo();
+
+  if (v)
+    {
+    vis = v->visual;
+    XFree(v);
+    }
+
+  return vis;
+}
+
+
+// Get a colormap from the windowing system.
+Colormap vtkXOpenGLOffScreenRenderWindow::GetDesiredColormap ()
+{
+  XVisualInfo *v;
+
+  if (this->ColorMap) return this->ColorMap;
+
+  // get the default visual to use
+  v = this->GetDesiredVisualInfo();
+
+  if (v)
+    {
+    this->ColorMap = XCreateColormap(this->DisplayId,
+                                     RootWindow( this->DisplayId, v->screen),
+                                     v->visual, AllocNone );
+    XFree(v);
+    }
+
+  return this->ColorMap;
+}
+
+void vtkXOpenGLOffScreenRenderWindow::PrintSelf(ostream& os, vtkIndent indent)
+{
+  this->Superclass::PrintSelf(os,indent);
+
+  os << indent << "ContextId: " << this->Internal->ContextId << "\n";
+// #ifdef VTK_OPENGL_HAS_OSMESA
+//   os << indent << "OffScreenContextId: " << this->Internal->OffScreenContextId << "\n";
+// #endif
+  os << indent << "Color Map: " << this->ColorMap << "\n";
+  os << indent << "Display Id: " << this->GetDisplayId() << "\n";
+  os << indent << "Next Window Id: " << this->NextWindowId << "\n";
+  os << indent << "Window Id: " << this->GetWindowId() << "\n";
+}
+
+// the following can be useful for debugging XErrors
+// When uncommented (along with the lines in MakeCurrent)
+// it will cause a segfault upon an XError instead of
+// the normal XError handler
+//  extern "C" {int vtkXError(Display *display, XErrorEvent *err)
+//  {
+//  // cause a segfault
+//    *(float *)(0x01) = 1.0;
+//    return 1;
+//  }}
+
+void vtkXOpenGLOffScreenRenderWindow::MakeCurrent()
+{
+  // when debugging XErrors uncomment the following lines
+  //  if (this->DisplayId)
+//      {
+//        XSynchronize(this->DisplayId,1);
+//      }
+//     XSetErrorHandler(vtkXError);
+
+    {
+    if (this->Internal->ContextId && ((this->Internal->ContextId != glXGetCurrentContext()) || this->ForceMakeCurrent))
+      {
+      glXMakeCurrent(this->DisplayId,this->WindowId,this->Internal->ContextId);
+      this->ForceMakeCurrent = 0;
+      }
+    }
+}
+
+void vtkXOpenGLOffScreenRenderWindow::SetForceMakeCurrent()
+{
+  this->ForceMakeCurrent = 1;
+}
+
+int vtkXOpenGLOffScreenRenderWindowFoundMatch;
+
+extern "C"
+{
+  Bool vtkXOpenGLOffScreenRenderWindowPredProc(Display *vtkNotUsed(disp),
+                                      XEvent *event,
+                                      char *arg)
+  {
+    Window win = (Window)arg;
+
+    if (((reinterpret_cast<XAnyEvent *>(event))->window == win) &&
+        ((event->type == ButtonPress)))
+      {
+      vtkXOpenGLOffScreenRenderWindowFoundMatch = 1;
+      }
+
+    return 0;
+  }
+}
+
+void *vtkXOpenGLOffScreenRenderWindow::GetGenericContext()
+{
+  static GC gc = (GC) NULL;
+  if (!gc) gc = XCreateGC(this->DisplayId, this->WindowId, 0, 0);
+  return (void *) gc;
+}
+
+int vtkXOpenGLOffScreenRenderWindow::GetEventPending()
+{
+  XEvent report;
+
+  vtkXOpenGLOffScreenRenderWindowFoundMatch = 0;
+  XCheckIfEvent(this->DisplayId, &report, vtkXOpenGLOffScreenRenderWindowPredProc,
+                (char *)this->WindowId);
+  return vtkXOpenGLOffScreenRenderWindowFoundMatch;
+}
+
+// Get the size of the screen in pixels
+int *vtkXOpenGLOffScreenRenderWindow::GetScreenSize()
+{
+  // get the default display connection
+  if (!this->DisplayId)
+    {
+    this->DisplayId = XOpenDisplay((char *)NULL);
+    if (this->DisplayId == NULL)
+      {
+      vtkErrorMacro(<< "bad X server connection.\n");
+      }
+    else
+      {
+      this->OwnDisplay = 1;
+      }
+    }
+
+  this->ScreenSize[0] =
+    DisplayWidth(this->DisplayId, DefaultScreen(this->DisplayId));
+  this->ScreenSize[1] =
+    DisplayHeight(this->DisplayId, DefaultScreen(this->DisplayId));
+
+  return this->ScreenSize;
+}
+
+// Get this RenderWindow's X display id.
+Display *vtkXOpenGLOffScreenRenderWindow::GetDisplayId()
+{
+  // get the default display connection
+  if (!this->DisplayId)
+    {
+    this->DisplayId = XOpenDisplay((char *)NULL);
+    if (this->DisplayId == NULL)
+      {
+      vtkErrorMacro(<< "bad X server connection.\n");
+      }
+    this->OwnDisplay = 1;
+    }
+  vtkDebugMacro(<< "Returning DisplayId of " << (void *)this->DisplayId << "\n");
+
+  return this->DisplayId;
+}
+
+// Get this RenderWindow's parent X window id.
+Window vtkXOpenGLOffScreenRenderWindow::GetParentId()
+{
+  vtkDebugMacro(<< "Returning ParentId of " << (void *)this->ParentId << "\n");
+  return this->ParentId;
+}
+
+// Get this RenderWindow's X window id.
+Window vtkXOpenGLOffScreenRenderWindow::GetWindowId()
+{
+  vtkDebugMacro(<< "Returning WindowId of " << (void *)this->WindowId << "\n");
+  return this->WindowId;
+}
+
+// Sets the parent of the window that WILL BE created.
+void vtkXOpenGLOffScreenRenderWindow::SetParentId(Window arg)
+{
+//   if (this->ParentId)
+//     {
+//     vtkErrorMacro("ParentId is already set.");
+//     return;
+//     }
+
+  vtkDebugMacro(<< "Setting ParentId to " << (void *)arg << "\n");
+
+  this->ParentId = arg;
+}
+
+// Set this RenderWindow's X window id to a pre-existing window.
+void vtkXOpenGLOffScreenRenderWindow::SetWindowId(Window arg)
+{
+  vtkDebugMacro(<< "Setting WindowId to " << (void *)arg << "\n");
+
+  this->WindowId = arg;
+
+  if (this->CursorHidden)
+    {
+    this->CursorHidden = 0;
+    this->HideCursor();
+    }
+}
+
+// Set this RenderWindow's X window id to a pre-existing window.
+void vtkXOpenGLOffScreenRenderWindow::SetWindowInfo(char *info)
+{
+  int tmp;
+
+  // get the default display connection
+  if (!this->DisplayId)
+    {
+    this->DisplayId = XOpenDisplay((char *)NULL);
+    if (this->DisplayId == NULL)
+      {
+      vtkErrorMacro(<< "bad X server connection.\n");
+      }
+    else
+      {
+      this->OwnDisplay = 1;
+      }
+    }
+
+  sscanf(info,"%i",&tmp);
+
+  this->SetWindowId(tmp);
+}
+
+// Set this RenderWindow's X window id to a pre-existing window.
+void vtkXOpenGLOffScreenRenderWindow::SetNextWindowInfo(char *info)
+{
+   int tmp;
+   sscanf(info,"%i",&tmp);
+
+   this->SetNextWindowId((Window)tmp);
+}
+
+// Sets the X window id of the window that WILL BE created.
+void vtkXOpenGLOffScreenRenderWindow::SetParentInfo(char *info)
+{
+  int tmp;
+
+  // get the default display connection
+  if (!this->DisplayId)
+    {
+    this->DisplayId = XOpenDisplay((char *)NULL);
+    if (this->DisplayId == NULL)
+      {
+      vtkErrorMacro(<< "bad X server connection.\n");
+      }
+    else
+      {
+      this->OwnDisplay = 1;
+      }
+    }
+
+  sscanf(info,"%i",&tmp);
+
+  this->SetParentId(tmp);
+}
+
+void vtkXOpenGLOffScreenRenderWindow::SetWindowId(void *arg)
+{
+  this->SetWindowId((Window)arg);
+}
+void vtkXOpenGLOffScreenRenderWindow::SetParentId(void *arg)
+{
+  this->SetParentId((Window)arg);
+}
+
+const char* vtkXOpenGLOffScreenRenderWindow::ReportCapabilities()
+{
+  MakeCurrent();
+
+  if (!this->DisplayId)
+    {
+    return "display id not set";
+    }
+
+  int scrnum = DefaultScreen(this->DisplayId);
+  const char *serverVendor = glXQueryServerString(this->DisplayId, scrnum, GLX_VENDOR);
+  const char *serverVersion = glXQueryServerString(this->DisplayId, scrnum, GLX_VERSION);
+  const char *serverExtensions = glXQueryServerString(this->DisplayId, scrnum, GLX_EXTENSIONS);
+  const char *clientVendor = glXGetClientString(this->DisplayId, GLX_VENDOR);
+  const char *clientVersion = glXGetClientString(this->DisplayId, GLX_VERSION);
+  const char *clientExtensions = glXGetClientString(this->DisplayId, GLX_EXTENSIONS);
+  const char *glxExtensions = glXQueryExtensionsString(this->DisplayId, scrnum);
+  const char *glVendor = (const char *) glGetString(GL_VENDOR);
+  const char *glRenderer = (const char *) glGetString(GL_RENDERER);
+  const char *glVersion = (const char *) glGetString(GL_VERSION);
+  const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
+
+  ostrstream strm;
+  strm << "server glx vendor string:  " << serverVendor << endl;
+  strm << "server glx version string:  " << serverVersion << endl;
+  strm << "server glx extensions:  " << serverExtensions << endl;
+  strm << "client glx vendor string:  " << clientVendor << endl;
+  strm << "client glx version string:  " << clientVersion << endl;
+  strm << "client glx extensions:  " << clientExtensions << endl;
+  strm << "glx extensions:  " << glxExtensions << endl;
+  strm << "OpenGL vendor string:  " << glVendor << endl;
+  strm << "OpenGL renderer string:  " << glRenderer << endl;
+  strm << "OpenGL version string:  " << glVersion << endl;
+  strm << "OpenGL extensions:  " << glExtensions << endl;
+  strm << "X Extensions:  ";
+
+  int n = 0;
+  char **extlist = XListExtensions(this->DisplayId, &n);
+
+  for (int i = 0; i < n; i++)
+    {
+      if (i != n-1) {
+        strm << extlist[i] << ", ";
+      } else {
+        strm << extlist[i] << endl;
+      }
+    }
+  strm << ends;
+  delete[] this->Capabilities;
+  this->Capabilities = strm.str();
+  return this->Capabilities;
+}
+
+int vtkXOpenGLOffScreenRenderWindow::SupportsOpenGL()
+{
+  MakeCurrent();
+  if (!this->DisplayId)
+    {
+    return 0;
+    }
+
+  int value = 0;
+  XVisualInfo *v = this->GetDesiredVisualInfo();
+  if (v)
+    {
+      glXGetConfig(this->DisplayId, v, GLX_USE_GL, &value);
+    }
+
+  return value;
+}
+
+
+int vtkXOpenGLOffScreenRenderWindow::IsDirect()
+{
+  MakeCurrent();
+  if (!this->DisplayId || !this->Internal->ContextId)
+    {
+      return 0;
+    }
+  this->UsingHardware = glXIsDirect(this->DisplayId,
+                                    this->Internal->ContextId) ? 1:0;
+  return this->UsingHardware;
+}
+
+
+void vtkXOpenGLOffScreenRenderWindow::SetWindowName(const char * cname)
+{
+  char *name = new char[ strlen(cname)+1 ];
+  strcpy(name, cname);
+  XTextProperty win_name_text_prop;
+
+  vtkOpenGLRenderWindow::SetWindowName( name );
+
+  if (this->Mapped)
+    {
+    if( XStringListToTextProperty( &name, 1, &win_name_text_prop ) == 0 )
+      {
+      XFree (win_name_text_prop.value);
+      vtkWarningMacro(<< "Can't rename window");
+      delete [] name;
+      return;
+      }
+
+    XSetWMName( this->DisplayId, this->WindowId, &win_name_text_prop );
+    XSetWMIconName( this->DisplayId, this->WindowId, &win_name_text_prop );
+    XFree (win_name_text_prop.value);
+    }
+  delete [] name;
+}
+
+
+// Specify the X window id to use if a WindowRemap is done.
+void vtkXOpenGLOffScreenRenderWindow::SetNextWindowId(Window arg)
+{
+  vtkDebugMacro(<< "Setting NextWindowId to " << (void *)arg << "\n");
+
+  this->NextWindowId = arg;
+}
+
+void vtkXOpenGLOffScreenRenderWindow::SetNextWindowId(void *arg)
+{
+   this->SetNextWindowId((Window)arg);
+}
+
+
+// Set the X display id for this RenderWindow to use to a pre-existing
+// X display id.
+void vtkXOpenGLOffScreenRenderWindow::SetDisplayId(Display  *arg)
+{
+  vtkDebugMacro(<< "Setting DisplayId to " << (void *)arg << "\n");
+
+  this->DisplayId = arg;
+  this->OwnDisplay = 0;
+
+}
+void vtkXOpenGLOffScreenRenderWindow::SetDisplayId(void *arg)
+{
+  this->SetDisplayId((Display *)arg);
+  this->OwnDisplay = 0;
+}
+
+void vtkXOpenGLOffScreenRenderWindow::Render()
+{
+  XWindowAttributes attribs;
+
+  // To avoid the expensive XGetWindowAttributes call,
+  // compute size at the start of a render and use
+  // the ivar other times.
+  if (this->Mapped)
+    {
+    //  Find the current window size
+    XGetWindowAttributes(this->DisplayId,
+                                    this->WindowId, &attribs);
+
+    this->Size[0] = attribs.width;
+    this->Size[1] = attribs.height;
+    }
+
+  // Now do the superclass stuff
+  this->vtkOpenGLRenderWindow::Render();
+}
+
+//----------------------------------------------------------------------------
+void vtkXOpenGLOffScreenRenderWindow::HideCursor()
+{
+  static char blankBits[] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  static XColor black = { 0, 0, 0, 0, 0, 0 };
+
+  if (!this->DisplayId || !this->WindowId)
+    {
+    this->CursorHidden = 1;
+    }
+  else if (!this->CursorHidden)
+    {
+    Pixmap blankPixmap = XCreateBitmapFromData(this->DisplayId,
+                                               this->WindowId,
+                                               blankBits, 16, 16);
+
+    Cursor blankCursor = XCreatePixmapCursor(this->DisplayId, blankPixmap,
+                                             blankPixmap, &black, &black,
+                                             7, 7);
+
+    XDefineCursor(this->DisplayId, this->WindowId, blankCursor);
+
+    XFreePixmap(this->DisplayId, blankPixmap);
+
+    this->CursorHidden = 1;
+    }
+}
+
+//----------------------------------------------------------------------------
+void vtkXOpenGLOffScreenRenderWindow::ShowCursor()
+{
+  if (!this->DisplayId || !this->WindowId)
+    {
+    this->CursorHidden = 0;
+    }
+  else if (this->CursorHidden)
+    {
+    XUndefineCursor(this->DisplayId, this->WindowId);
+    this->CursorHidden = 0;
+    }
+}
+
+
+
+// This probably has been moved to superclass.
+void *vtkXOpenGLOffScreenRenderWindow::GetGenericWindowId()
+{
+  return (void *)this->WindowId;
+}
+
+void vtkXOpenGLOffScreenRenderWindow::SetCurrentCursor(int shape)
+{
+  if ( this->InvokeEvent(vtkCommand::CursorChangedEvent,&shape) )
+    {
+    return;
+    }
+  this->Superclass::SetCurrentCursor(shape);
+  if (!this->DisplayId || !this->WindowId)
+    {
+    return;
+    }
+
+  if (shape == VTK_CURSOR_DEFAULT)
+    {
+    XUndefineCursor(this->DisplayId,this->WindowId);
+    return;
+    }
+
+  switch (shape)
+    {
+    case VTK_CURSOR_ARROW:
+      if (!this->XCArrow)
+        {
+        this->XCArrow = XCreateFontCursor(this->DisplayId, XC_top_left_arrow);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCArrow);
+      break;
+    case VTK_CURSOR_SIZEALL:
+      if (!this->XCSizeAll)
+        {
+        this->XCSizeAll = XCreateFontCursor(this->DisplayId, XC_fleur);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeAll);
+      break;
+    case VTK_CURSOR_SIZENS:
+      if (!this->XCSizeNS)
+        {
+        this->XCSizeNS = XCreateFontCursor(this->DisplayId,
+                                           XC_sb_v_double_arrow);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeNS);
+      break;
+    case VTK_CURSOR_SIZEWE:
+      if (!this->XCSizeWE)
+        {
+        this->XCSizeWE = XCreateFontCursor(this->DisplayId,
+                                           XC_sb_h_double_arrow);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeWE);
+      break;
+    case VTK_CURSOR_SIZENE:
+      if (!this->XCSizeNE)
+        {
+        this->XCSizeNE = XCreateFontCursor(this->DisplayId,
+                                           XC_top_right_corner);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeNE);
+      break;
+    case VTK_CURSOR_SIZENW:
+      if (!this->XCSizeNW)
+        {
+        this->XCSizeNW = XCreateFontCursor(this->DisplayId,
+                                           XC_top_left_corner);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeNW);
+      break;
+    case VTK_CURSOR_SIZESE:
+      if (!this->XCSizeSE)
+        {
+        this->XCSizeSE = XCreateFontCursor(this->DisplayId,
+                                           XC_bottom_right_corner);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeSE);
+      break;
+    case VTK_CURSOR_SIZESW:
+      if (!this->XCSizeSW)
+        {
+        this->XCSizeSW = XCreateFontCursor(this->DisplayId,
+                                           XC_bottom_left_corner);
+        }
+      XDefineCursor(this->DisplayId, this->WindowId, this->XCSizeSW);
+      break;
+    }
+}
Index: trunk/src/testing/app/mframes/init_code/tile_config.h
===================================================================
--- trunk/src/testing/app/mframes/init_code/tile_config.h	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/tile_config.h	(revision 4)
@@ -0,0 +1,312 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: tile_config.h
+-	Purpose: Contains all class descriptions for building
+-	a description of a tile display system, at run time
+---------------------------------------------------------------------------*/
+#ifndef SAGE_TILE_CONFIG_H
+#define SAGE_TILE_CONFIG_H
+
+#define _DEBUG 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+//__________________________________________
+class Physical_Tile;
+class Display_Node;
+class Virtual_Desktop_Tile;
+
+class DisplayCluster;
+class PhysicalDisplay;
+class VirtualDesktop;
+//__________________________________________
+
+class Physical_Tile
+{
+private:
+	//int horizRes;	//horizontal resolution
+	//int vertRes;	//vertical resolution
+	float screenWidth;	//width of screen in inches
+	float screenHeight;	//height of screen in inches
+	float leftMullion;	//the width of the left Mullion in inches
+	float rightMullion;	// "	"	"  right " 	"
+	float topMullion;		// "	"	"  top   "	"
+	float bottomMullion;	// "	"	"  bottom "	"
+	float lowerleftX;	//the x position of the bottom left corner of the tile (including the mullions from left)
+						//with respect to some arbritrary origin
+	float lowerleftY;	//the y position of the bottom left corner of the tile (including the mullions from bottom)
+						//with respect to some arbritrary origin
+	int id;
+	Virtual_Desktop_Tile* virtDeskTile;	//the virtual desktop tile that the physical tile will display
+	Physical_Tile* next;
+	Display_Node*	 source;	//the display node that is the source to the physical tile
+public:
+	Physical_Tile();
+	~Physical_Tile();
+
+	float ScreenWidthDimension();
+	float ScreenHeightDimension();
+	float LeftMullionThickness();
+	float RightMullionThickness();
+	float TopMullionThickness();
+	float BottomMullionThickness();
+	float LowerLeftX();
+	float LowerLeftY();
+	int ID();
+	Physical_Tile* Next();
+	Display_Node* Source();
+	Virtual_Desktop_Tile* VirtualDesktopTile();
+
+
+	void ScreenWidthDimension(float);
+	void ScreenHeightDimension(float);
+	void RightMullionThickness(float);
+	void LeftMullionThickness(float);
+	void TopMullionThickness(float);
+	void BottomMullionThickness(float);
+	void LowerLeftX(float);
+	void LowerLeftY(float);
+	void ID(int);
+	void Next(Physical_Tile*);
+	void Source(Display_Node*);
+	void VirtualDesktopTile(Virtual_Desktop_Tile*);
+};
+
+class Virtual_Desktop_Tile
+{
+private:
+	float	lowerLeftX;	//the ratio of the lower left x position to the entire virtual desktop width
+	float 	lowerLeftY;	//the ratio of the lower left y position to the entire virtual desktop height
+
+	float   widthRatio;   //the ratio of the width of the virtual desktop tile
+				//to the entire virtual desktop width
+
+	float 	heightRatio;	//the ratio of the height of the virtual desktop tile
+				//to the entire virtual desktop height
+
+	int 	id;		//the id of the virtual desktop tile
+
+
+	int		lowerLeftPixelX;
+	int		lowerLeftPixelY;
+	int		widthInPixels;
+	int		heightInPixels;
+
+	int 	nonMullionLLX;	//lower left X on a zero mullion display
+	int		nonMullionLLY;	//lower left Y on a zero mullion display
+
+	Display_Node* dispNode;	//the node that will display the virtual desktop tile to the associated physical tile
+	Virtual_Desktop_Tile *next;
+
+
+public:
+	Virtual_Desktop_Tile();
+	~Virtual_Desktop_Tile();
+	float LowerLeftX();
+	float LowerLeftY();
+	int	LowerLeftPixelX();
+	int LowerLeftPixelY();
+	int WidthInPixels();
+	int HeightInPixels();
+	int NonMullionLLX();
+	int NonMullionLLY();
+
+	float WidthRatio();	//The ratio of the width of the tile to that of the whole virtual desktop
+	float HeightRatio();	//The ratio of the height of the tile to that of the whole virtual desktop
+	int ID();		//The unique ID of the tile
+	Display_Node* DisplayNode();	//The physical tile that this virtual desktop tile resides
+	Virtual_Desktop_Tile* Next();
+
+	void LowerLeftX(float);
+	void LowerLeftY(float);
+	void NonMullionLLX(int);
+	void NonMullionLLY(int);
+	void LowerLeftPixelX(int);
+	void LowerLeftPixelY(int);
+	void WidthInPixels(int);
+	void HeightInPixels(int);
+	void WidthRatio(float);
+	void HeightRatio(float);
+	void ID(int);
+	void DisplayNode(Display_Node*);
+	void Next(Virtual_Desktop_Tile*);
+
+};
+
+class VDTtoPTmapper
+{
+	Physical_Tile* pt;
+	Virtual_Desktop_Tile *vdt;
+
+public:
+	VDTtoPTmapper(Physical_Tile*, Virtual_Desktop_Tile*);
+	~VDTtoPTmapper();
+	Physical_Tile* PhysicalTile();
+	Virtual_Desktop_Tile* VirtualDesktopTile();
+
+};
+
+class Display_Node
+{
+private:
+	char* nodeName;		//the name of the computer that holds pixels to display
+	char* ip;		//ip address of the computer the holds pixels to display
+	VDTtoPTmapper**	maps;	//pointer to the array of VDTtoPTmapper objects
+	Display_Node* next;	//next display node in list
+	int numberOfMaps;	//The number of mappings from virtual desktop tile to physical tile
+				//that this display node can make (i.e. how many outputs the display node has)
+public:
+	Display_Node();
+	~Display_Node();
+	void Name(char* );
+	void IP(char* );
+	char* Name(void);
+	char* IP(void);
+	int  NumberOfMaps();
+	void NumberOfMaps(int);
+	VDTtoPTmapper** Maps();
+	bool AddMap(VDTtoPTmapper*);
+	Display_Node* Next();
+	void Next(Display_Node*);
+	void RemoveMap(VDTtoPTmapper*);
+	void RemoveMap(int);		//delete a specific mapping given an index
+};
+
+
+//__________________________________________
+
+class DisplayCluster
+{
+protected:
+	Display_Node*		displayNodeListHead;	//pointer to the display node linked list
+	VirtualDesktop*		vd;
+	PhysicalDisplay*	pd;
+
+public:
+	DisplayCluster();
+	~DisplayCluster();
+	void AddDisplayNode(Display_Node* );
+	void RemoveDisplayNode(char*);		//remove a display node given the display node name
+	void RemoveDisplayNodeByName(char*);
+	void RemoveDisplayNodeByIP(char*);	//remove a display node given the display node ip
+	Display_Node*	getFirstNode();		//return the first node in the display node list
+
+	VirtualDesktop* VirtualDesktopAssoc();
+	void VirtualDesktopAssoc(VirtualDesktop* );
+	PhysicalDisplay* PhysicalDisplayAssoc();
+	void PhysicalDisplayAssoc(PhysicalDisplay*);
+
+	bool GenerateMapping(Virtual_Desktop_Tile*, Physical_Tile*);
+	bool GenerateMapping(Virtual_Desktop_Tile*, Physical_Tile*, Display_Node*);
+	void RemoveMapping(Virtual_Desktop_Tile*, Physical_Tile*, Display_Node*);
+	void RemoveMapsWith(Virtual_Desktop_Tile*);	//Removes any mappings made witht the given virtual tile
+	void RemoveMapsWith(Physical_Tile*);		//Removes any mappings made with the given physical tile
+	bool NodeOnCluster(Display_Node*);
+
+};
+
+
+class PhysicalDisplay
+{
+protected:
+	Physical_Tile* 	physicalTileListHead;	//pointer to the physical tile linked list
+
+	VirtualDesktop*		vd;
+	DisplayCluster*		dc;
+	float				pixelsPerInch;		//the pixels per inch ratio
+
+public:
+	PhysicalDisplay();
+	~PhysicalDisplay();
+	VirtualDesktop* VirtualDesktopAssoc();
+	void VirtualDesktopAssoc(VirtualDesktop* );
+	DisplayCluster* DisplayClusterAssoc();
+	void DisplayClusterAssoc(DisplayCluster* );
+	int AddPhysicalTile(Physical_Tile*);				//adds a tile to the display and returns its unique id
+
+	Physical_Tile* RemovePhysicalTileByID(int, bool);		//remove a physical tile from this physical display
+									//the second parameter is used to have the tile deleted
+									//or just removed.  If "true" the tile will be deleted
+									//from memory, otherwise the address of the tile will
+									//be returned
+
+	Physical_Tile* getFirstNode();		//returns the first node in the physical tile list
+	bool TileOnPhysicalDisplay(Physical_Tile*);
+	float PixelsPerInch();				//get the pixels per inch that ALL the physical tiles on this display conform to
+	void PixelsPerInch(float);			//set the pixels per inch that ALL the physical tiles on this display conform to
+};
+
+class VirtualDesktop
+{
+protected:
+	int horizRes;		//horizontal resolution	of virtual desktop
+	int vertRes;		//vertical resolution of virtual desktop
+
+	//pointer to Virtual_Desktop_Tile linked list
+	Virtual_Desktop_Tile* tileListHead;
+
+	PhysicalDisplay*	pd;
+	DisplayCluster*		dc;
+
+
+public:
+	VirtualDesktop();
+	~VirtualDesktop();
+
+	PhysicalDisplay* PhysicalDisplayAssoc();
+	void PhysicalDisplayAssoc(PhysicalDisplay*);
+	DisplayCluster* DisplayClusterAssoc();
+	void DisplayClusterAssoc(DisplayCluster*);
+
+	int HorizRes(void){ return horizRes; }
+	int VertRes(void){ return vertRes; }
+
+	void AddTile(Virtual_Desktop_Tile*);
+	void RemoveTile(Virtual_Desktop_Tile*);
+
+	Virtual_Desktop_Tile* getFirstNode(void);
+
+	bool Update(void);		//update the virtual desktop with newly added/removed tile mappings
+
+};
+
+#endif
Index: trunk/src/testing/app/mframes/init_code/initf.cpp
===================================================================
--- trunk/src/testing/app/mframes/init_code/initf.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/initf.cpp	(revision 4)
@@ -0,0 +1,1463 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "initf.h"
+
+//#define SAGE
+
+#define HORIZONTAL 0
+#define VERTICAL 1
+
+
+AnimViewer animviewer;
+
+double PointerPosition[2];
+
+int uiaction;
+double pos[3];
+
+double cw0, cw1, ch0, ch1;
+
+int window_w, window_h;
+
+// default is 1
+int ScreensPerNode = 1;
+
+
+
+char* hostname;
+
+string appname;
+
+
+
+bool SAGE;
+string sageStr;
+
+AnimViewer::AnimViewer() {
+
+	QueryWindow.virgin = true;
+
+	text->SetInput("Loading!!!");
+	text->SetDisplayPosition(300, 350);
+	text->GetTextProperty()->SetFontFamilyToArial();
+	text->GetTextProperty()->SetFontSize(150);
+	text->GetTextProperty()->SetColor(0.0,0.0,0.0);
+
+	sphere->SetThetaResolution(32);
+	sphere->SetPhiResolution(32);
+
+	sphereMapper->SetInput(sphere->GetOutput());
+	pointer->SetMapper(sphereMapper);
+	pointer->GetProperty()->SetColor(1,0,0);
+	pointer->GetProperty()->SetOpacity(0.6);
+	pointer->GetProperty()->BackfaceCullingOn();
+
+}
+
+AnimViewer::~AnimViewer() {
+
+	delete [] this->Blank;
+	this->Blank = NULL;
+
+}
+
+string AnimViewer::IntToString(long num) {
+
+	ostringstream o;
+	if (!(o << num))
+		printf("Error in conversion from int to string \n");
+
+	return o.str();
+
+}
+
+long AnimViewer::GetNumOfCols(long wtotal, long wblock) {
+
+
+	return (long) ceil(double(wtotal) / double(wblock));
+
+}
+
+long AnimViewer::GetNumOfRows(long wtotal, long wblock) {
+
+	return (long) ceil(double(wtotal) / double(wblock));
+
+}
+
+void AnimViewer::GetAnimFiles() {
+
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+	string dirname, filename;
+
+	this->AnimFiles = new string**[this->NumOfLevels];
+
+	for(int i=0; i<this->NumOfLevels; i++) {
+
+		this->AnimFiles[i] = new string*[cols];
+
+		dirname.clear();
+		dirname += "/frame";
+		dirname += this->IntToString(i);
+
+		for(int c=0 ; c<cols; c++) {
+
+			this->AnimFiles[i][c] = new string[rows];
+
+			for(int r=0; r<rows; r++) {
+
+				filename.clear();
+				filename += dirname;
+				filename += "/b_";
+				filename += this->IntToString(c);
+				filename += "_";
+				filename += this->IntToString(r);
+
+
+				this->AnimFiles[i][c][r] += filename;
+
+				/*
+				printf("%i %i %i ... ", i, c, r);
+				printf("%s\n", this->AnimFiles[i][c][r].c_str());
+				*/
+			}
+		}
+	}
+
+	printf("Created file locator.\n");
+
+}
+
+unsigned char* AnimViewer::MMap(long l, long c, long r) {
+	string filename;
+	filename += AnimDir;
+	filename += this->AnimFiles[l][c][r];
+
+	size_t len = this->BlockDimensions[0] * this->BlockDimensions[1] * MODE;
+
+	// Open file
+	this->Block[l][c][r].fd = open(filename.c_str(), O_RDONLY);
+
+	if(this->Block[l][c][r].fd < 0) {
+		printf("File does not exist. Could not map.\n");
+		printf("Assigning a blank tile...\n");
+
+		this->pixelbuff = this->Blank;
+	}
+	else {
+		//printf("Mapping %s.\n", filename.c_str());
+		this->pixelbuff = (unsigned char*) mmap(0,len,PROT_READ,MAP_SHARED,
+								this->Block[l][c][r].fd,0);
+
+		madvise(0, len, MADV_SEQUENTIAL);
+	}
+
+	// Close file
+	close(this->Block[l][c][r].fd);
+
+	return this->pixelbuff;
+}
+
+/* Takes the filename and returns its pixels content */
+unsigned char* AnimViewer::GetPixelsFromFile(long l, long c, long r) {
+	string filename;
+	filename += AnimDir;
+	filename += this->AnimFiles[l][c][r];
+
+	this->pixelbuff =
+			new unsigned char[this->BlockDimensions[0] * this->BlockDimensions[1] * MODE];
+
+	//fprintf(stderr, "Opening [%s]\n", filename.c_str() );
+
+	FILE* fptr = fopen(filename.c_str(),"rb");
+	//setvbuf(fptr, NULL, _IOFBF, 3*1024*1024);
+
+	if(!fptr) {
+		if(rank != 0)
+			printf("Can't open %s\n", filename.c_str());
+
+		this->pixelbuff = this->Blank;
+	}
+	else {
+		//printf("Opening file %s\n", name.c_str());
+		fread(this->pixelbuff, this->BlockDimensions[0] *
+				this->BlockDimensions[1] * MODE, sizeof(unsigned char),
+					fptr);
+
+		fclose(fptr);
+	}
+	//fprintf(stderr, "Closing [%s]\n", filename.c_str() );
+
+	return this->pixelbuff;
+}
+
+void AnimViewer::InitRendering() {
+
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+
+	this->Block = new Geometry**[this->NumOfLevels];
+
+	for(int i=0 ; i<this->NumOfLevels; i++) {
+
+	this->Block[i] = new Geometry*[cols];
+
+	for(int c=0 ; c<cols; c++) {
+
+		this->Block[i][c] = new Geometry[rows];
+
+		for(int r=0; r<rows; r++) {
+
+			this->Block[i][c][r].importer = vtkImageImport::New();
+			this->Block[i][c][r].texture = vtkTexture::New();
+			this->Block[i][c][r].actor = vtkActor::New();
+			this->Block[i][c][r].plane = vtkPlaneSource::New();
+			this->Block[i][c][r].mapper = vtkPolyDataMapper::New();
+			this->Block[i][c][r].flip = vtkImageFlip::New();
+
+			this->Block[i][c][r].textSource = vtkTextSource::New();
+			this->Block[i][c][r].textMapper = vtkPolyDataMapper::New();
+			this->Block[i][c][r].textActor = vtkActor::New();
+
+			this->Block[i][c][r].importer->ReleaseDataFlagOn();
+			this->Block[i][c][r].flip->ReleaseDataFlagOn();
+
+		}
+	}
+
+	}
+
+
+}
+
+void AnimViewer::SetUpPipeline() {
+
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+	for(int i=0 ; i<this->NumOfLevels; i++) {
+
+	for(int c=0 ; c<cols; c++) {
+
+		for(int r=0; r<rows; r++) {
+
+			this->Block[i][c][r].plane->SetResolution(1,1);
+
+			this->Block[i][c][r].texture->RepeatOff();
+
+			this->Block[i][c][r].texture->InterpolateOn();
+
+			this->Block[i][c][r].mapper->SetInput(
+					(vtkPolyData*) this->Block[i][c][r].plane->GetOutput());
+
+			this->Block[i][c][r].actor->SetMapper(
+					this->Block[i][c][r].mapper);
+
+			this->Block[i][c][r].actor->GetProperty()->BackfaceCullingOn();
+
+			this->Block[i][c][r].textSource->SetForegroundColor(1,0,0);
+			this->Block[i][c][r].textSource->BackingOff();
+			this->Block[i][c][r].textMapper->SetInput(
+						this->Block[i][c][r].textSource->GetOutput());
+			this->Block[i][c][r].textActor->SetMapper(this->Block[i][c][r].textMapper);
+				this->Block[i][c][r].textActor->GetProperty()->SetOpacity(0.5);
+
+		}
+	}
+	}
+
+}
+
+void AnimViewer::CopyBuffer(unsigned char* dest, unsigned char* origin) {
+
+	for(int i=0; i <
+		this->BlockDimensions[0] * this->BlockDimensions[1] * MODE; i++) {
+
+		dest[i] = origin[i];
+	}
+
+}
+
+
+
+
+void AnimViewer::ImportQueryWindowPixels() {
+
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+	if(QueryWindow.virgin == true) {
+		this->QueryWindow.pixels = new unsigned char**[cols];
+
+		for(int c = 0; c < cols; c++) {
+
+			this->QueryWindow.pixels[c] = new unsigned char*[rows];
+		}
+	}
+	else {
+		for(int c=0; c < cols; c++) {
+
+			for(int r=0; r < rows; r++) {
+
+				munmap(this->QueryWindow.pixels[c][r],
+					this->BlockDimensions[0] * this->BlockDimensions[1] * MODE);
+				//delete [] this->QueryWindow.pixels[c][r];
+				//this->QueryWindow.pixels[c][r] = NULL;
+			}
+		}
+	}
+
+	for(int c = 0; c < cols; c++ ) {
+		for(int r = 0; r < rows; r++) {
+
+				this->QueryWindow.pixels[c][r] = //GetPixelsFromFile(this->QueryWindow.level, c, r);
+				this->MMap(this->QueryWindow.level, c, r);
+
+				string label;
+				label += IntToString(this->QueryWindow.level);
+				label += " ";
+				label += IntToString(c);
+				label += " ";
+				label += IntToString(r);
+
+				this->Block[this->QueryWindow.level][c][r].textSource->SetText(label.c_str());
+		}
+	}
+
+	QueryWindow.virgin = false;
+
+	printf("IMPORTED PIXELS\n");
+
+}
+
+void AnimViewer::GivePixelsToVTK() {
+
+	long l = this->QueryWindow.level;
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+	for(int c = 0; c < cols; c++ ) {
+		for(int r = 0; r < rows; r++) {
+
+			this->Block[l][c][r].importer->
+							SetDataScalarTypeToUnsignedChar();
+			this->Block[l][c][r].importer->
+							SetNumberOfScalarComponents(MODE);
+			this->Block[l][c][r].importer->
+							SetDataOrigin(0,0,0);
+			this->Block[l][c][r].importer->
+							SetWholeExtent(0, this->BlockDimensions[0] - 1, 0,
+											  this->BlockDimensions[1] - 1, 0, 0);
+			this->Block[l][c][r].importer->
+							SetDataExtentToWholeExtent();
+
+			this->Block[l][c][r].importer->
+							SetImportVoidPointer(this->QueryWindow.pixels[c][r]);
+
+			this->UpdateBlock(l, c, r);
+
+		}
+	}
+
+	this->AddRegion(l, 0, 0, cols, rows);
+
+}
+
+void AnimViewer::UpdateBlock(long l, long c, long r) {
+
+	/* flip the image */
+	this->Block[l][c][r].flip->
+			SetInput(this->Block[l][c][r].importer->GetOutput());
+
+	this->Block[l][c][r].flip->SetFilteredAxis(1);
+	this->Block[l][c][r].flip->FlipAboutOriginOn();
+
+	this->Block[l][c][r].texture->
+			SetInput(this->Block[l][c][r].flip->GetOutput());
+
+	this->Block[l][c][r].actor->
+			SetTexture(this->Block[l][c][r].texture);
+}
+
+void AnimViewer::AddBlock(long l, long c, long r) {
+
+	renA->AddActor(this->Block[l][c][r].actor);
+	if(ScreensPerNode > 1)
+		renB->AddActor(this->Block[l][c][r].actor);
+#ifdef DEBUG
+	renA->AddActor(this->Block[l][c][r].textActor);
+#endif
+}
+
+void AnimViewer::RemoveBlock(long l, long c, long r) {
+
+	renA->RemoveActor(this->Block[l][c][r].actor);
+
+	if(ScreensPerNode > 1)
+		renB->RemoveActor(this->Block[l][c][r].actor);
+#ifdef DEBUG
+	renA->RemoveActor(this->Block[l][c][r].textActor);
+#endif
+}
+
+
+void AnimViewer::RemoveRegion(long l, long c, long r, long w, long h) {
+
+	for(int i = c; i < c+w; i++) {
+		for(int j = r; j < r+h; j++) {
+			this->RemoveBlock(l, i, j);
+		}
+	}
+}
+
+void AnimViewer::AddRegion(long l, long c, long r, long w, long h) {
+
+	for(int i = c; i < c+w; i++) {
+		for(int j = r; j < r+h; j++) {
+			this->AddBlock(l, i, j);
+		}
+	}
+}
+
+
+void AnimViewer::CleanUpMainWindow() {
+
+	this->RemoveRegion(this->QueryWindow.level, 0, 0, this->NumOfCols, this->NumOfCols);
+}
+
+
+
+void AnimViewer::ComputeStartingBlockSize() {
+
+	double sw, sh;
+
+	double dw = double(this->BlockDimensions[0]) /
+						double(this->BlockDimensions[1]);
+	double dh = double(this->BlockDimensions[1]) /
+						double(this->BlockDimensions[0]);
+
+	if(dw > dh) {
+
+		sw = double(this->BlockDimensions[0]) /
+						double(this->BlockDimensions[0]);
+		sh = double(this->BlockDimensions[1]) /
+						double(this->BlockDimensions[0]);
+
+	}
+	else {
+
+		sw = double(this->BlockDimensions[0]) /
+						double(this->BlockDimensions[1]);
+		sh = double(this->BlockDimensions[1]) /
+						double(this->BlockDimensions[1]);
+	}
+
+	this->BlockInitSize[0] = sw;
+	this->BlockInitSize[1] = sh;
+}
+
+
+
+
+void AnimViewer::PositionAndScaleBlocks() {
+
+
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+	this->ComputeStartingBlockSize();
+
+	this->BlockInfo = new Info*[cols];
+
+	for(int c=0 ; c<cols; c++) {
+
+		this->BlockInfo[c] = new Info[rows];
+
+		for(int r=0 ; r<rows; r++) {
+
+			this->BlockInfo[c][r].scale[0] =
+						this->BlockInitSize[0];
+
+			this->BlockInfo[c][r].scale[1] =
+						this->BlockInitSize[1];
+
+			this->BlockInfo[c][r].position[0] =
+					double(c) * this->BlockInitSize[0];
+
+			this->BlockInfo[c][r].position[1] =
+					double(r) * this->BlockInitSize[1];
+
+			this->BlockInfo[c][r].position[2] = 0.1;
+
+		}
+	}
+
+	for(int l = 0; l<this->NumOfLevels; l++) {
+		for(int c=0 ; c<cols; c++) {
+			for(int r=0 ; r<rows; r++) {
+
+
+				this->Block[l][c][r].actor->
+					SetPosition(this->BlockInfo[c][r].position[0],
+						-this->BlockInfo[c][r].position[1],
+							-this->BlockInfo[c][r].position[2]);
+
+				this->Block[l][c][r].actor->
+					SetScale(this->BlockInfo[c][r].scale[0],
+						this->BlockInfo[c][r].scale[1], 0);
+
+
+				this->Block[l][c][r].textActor->
+					SetPosition(this->BlockInfo[c][r].position[0],
+						-this->BlockInfo[c][r].position[1],
+							-this->BlockInfo[c][r].position[2]);
+
+				this->Block[l][c][r].textActor->
+					SetScale(this->BlockInfo[c][r].scale[0] / 70,
+						this->BlockInfo[c][r].scale[1] / 40, 0);
+
+			}
+		}
+
+	}
+}
+
+
+void AnimViewer::AdjustLevelMovement(int direction, int axis) {
+
+	PanAmount = this->BlockInfo[0][0].scale[axis] / PANSUBDIVISIONS;
+
+}
+
+
+void AnimViewer::InitViewer(char* name) {
+
+	ifstream file(name);
+
+	if (!file.is_open()) {
+		printf("Can not read dat file.\n");
+		exit(0);
+    }
+
+
+	file >> sageStr >> appname >> xWindowPos >> yWindowPos >>
+			 this->GlobalDimensions[0] >> this->GlobalDimensions[1]
+		 >> this->BlockDimensions[0] >> this->BlockDimensions[1]
+		 >> this->NumOfLevels >> this->AnimDir >> this->Colorspace;
+
+	if(!strcmp(sageStr.c_str(), "SAGE")) {
+		SAGE = true;
+		printf("Render to sage.   %s\n", sageStr.c_str());
+	}
+	else {
+
+		SAGE == false;
+		printf("No sage  %s\n", sageStr.c_str());
+	}
+
+
+	end = this->NumOfLevels;
+	MODE = this->Colorspace;
+
+	this->NumOfCols = this->GetNumOfCols(GlobalDimensions[0], BlockDimensions[0]);
+	this->NumOfRows = this->GetNumOfRows(GlobalDimensions[1], BlockDimensions[1]);
+
+	printf("Columns = %i Rows = %i \n", this->NumOfCols, this->NumOfRows);
+
+	this->Blank =
+		new unsigned char[this->BlockDimensions[0] *
+						this->BlockDimensions[1] * MODE];
+
+	for(int i=0; i < this->BlockDimensions[0] *
+			this->BlockDimensions[1] * MODE; i++) {
+		this->Blank[i] = (unsigned char) 0;
+	}
+
+	memset(this->Blank,
+		0, this->BlockDimensions[0] * this->BlockDimensions[1] * MODE);
+
+	/*
+	printf("------------------------\n");
+	printf("Global dim: %i %i\nBlock dim: %i %i\nNum of levels: %i\n",
+		this->GlobalDimensions[0], this->GlobalDimensions[1],
+		this->BlockDimensions[0], this->BlockDimensions[1],
+		this->NumOfLevels);
+	printf("------------------------\n");
+	*/
+}
+
+
+void AnimViewer::PanLeft() {
+	PointerPosition[0] -= PanAmount;
+	pointer->SetPosition(PointerPosition[0], PointerPosition[1], 0);
+	//CamPosition[0] -= PanAmount;
+	//Fpoint[0] -= PanAmount;
+	//UpdateCamera(CamPosition, Fpoint);
+}
+
+void AnimViewer::PanRight() {
+
+	PointerPosition[0] += PanAmount;
+	pointer->SetPosition(PointerPosition[0], PointerPosition[1], 0);
+
+	//CamPosition[0] += PanAmount;
+	//Fpoint[0] += PanAmount;
+	//UpdateCamera(CamPosition, Fpoint);
+}
+
+void AnimViewer::PanUp() {
+
+	PointerPosition[1] += PanAmount;
+	pointer->SetPosition(PointerPosition[0], PointerPosition[1], 0);
+
+	//CamPosition[1] += PanAmount;
+	//Fpoint[1] += PanAmount;
+	//UpdateCamera(CamPosition, Fpoint);
+}
+
+void AnimViewer::PanDown() {
+	PointerPosition[1] -= PanAmount;
+	pointer->SetPosition(PointerPosition[0], PointerPosition[1], 0);
+
+	//CamPosition[1] -= PanAmount;
+	//Fpoint[1] -= PanAmount;
+	//UpdateCamera(CamPosition, Fpoint);
+}
+
+void AnimViewer::UpdateCamera(double c[], double f[]) {
+
+	pointer->SetScale(CamPosition[2]/20, CamPosition[2]/20, 0);
+	pointer->SetPosition(CamPosition[0], CamPosition[1], 0);
+
+	PointerPosition[0] = CamPosition[0];
+	PointerPosition[1] = CamPosition[1];
+
+
+	renA->GetActiveCamera()->SetPosition(c);
+	renA->GetActiveCamera()->SetFocalPoint(f);
+
+	if(ScreensPerNode > 1) {
+		renB->GetActiveCamera()->SetPosition(c);
+		renB->GetActiveCamera()->SetFocalPoint(f);
+	}
+}
+
+
+
+int AnimViewer::BlockOutOfBounds(long c, long r, long cols, long rows) {
+	//printf("Available cols and rows: %i %i\n", cols, rows);
+
+	if(c >= 0 && c < cols && r >= 0 && r < rows) {
+		printf("Accepted %i %i\n", c, r);
+		return ACCEPT;
+	}
+	else {
+		printf("This one is off: %i %i\n", c, r);
+		if( c < 0 )
+			return RIGHT;
+		if( c >= cols )
+			return LEFT;
+		if( r < 0 )
+			return UP;
+		if( r >= rows )
+			return DOWN;
+	}
+
+}
+
+void AnimViewer::CreateZoomBounds() {
+
+	ZoomBounds = new ZBound[this->StartingLevel + 1];
+	int i;
+	double Z = StartingZ;
+	for(i = this->StartingLevel; i >= 0; i--) {
+		ZoomBounds[i].bound = Z;
+		Z /=2;
+	}
+
+	this->NumOfZBounds = this->StartingLevel + 1;
+}
+
+void AnimViewer::GetZProjection(double zpos) {
+
+	for(int i = 0 ; i < this->NumOfZBounds; i++) {
+		if(ZoomBounds[i].bound >= zpos) {
+			CamProjection.l = i;
+			cout<<i<<endl;
+			return;
+		}
+	}
+}
+
+void AnimViewer::SetInitialCamPosition() {
+	long cols = this->NumOfCols;
+	long rows = this->NumOfRows;
+
+
+	CamPosition[0] = this->BlockInfo[cols/2][rows/2].position[0] -
+			this->BlockInfo[0][0].scale[0]/2;
+	CamPosition[1] = -this->BlockInfo[cols/2][rows/2].position[1] +
+			this->BlockInfo[0][0].scale[1]/2;
+
+
+	Fpoint[0] = CamPosition[0];
+	Fpoint[1] = CamPosition[1];
+
+
+	CamPosition[2] = (cols * this->BlockInfo[0][0].scale[0]) * 0.3;
+	//CamPosition[2] = 3.2;
+}
+
+char* WaitForMessage()
+{
+	if(recmsg == NULL)
+		recmsg = new char[TRANSMISSION_SIZE];
+	memset(recmsg,0,TRANSMISSION_SIZE);
+	static int size = TRANSMISSION_SIZE;
+
+	if(client == NULL && server != NULL)
+	{
+		fprintf(stderr,"Waiting For Client To Connect.\n");
+		client = server->waitForNewConnection();
+		fprintf(stderr,"Ready For Messages.\n");
+
+
+		int size;
+		size = sizeof(float) * 3;
+		float array[3];
+		array[0] = CamPosition[0];
+		array[1] = CamPosition[1];
+		array[2] = CamPosition[2];
+		client->write((const char*)array,&size,QUANTAnet_tcpClient_c::BLOCKING);
+	}
+
+	if(client)
+	{
+		int status;
+		status = client->read(recmsg,&size,QUANTAnet_tcpClient_c::NON_BLOCKING);
+	    if (status == QUANTAnet_tcpClient_c::OK)
+			return recmsg;
+		else
+			{
+				if (status == QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA) usleep(1000);
+				return NULL;
+			}
+	}
+
+	return NULL;
+}
+
+void AnimViewer::SetTimeStep(int direction) {
+	int step = CurrentLevel + direction;
+
+	if(step == this->NumOfLevels) {
+		step = 0;
+	}
+
+	if(step >= 0 && step < this->NumOfLevels) {
+		this->CleanUpMainWindow();
+
+		CurrentLevel = step;
+		this->QueryWindow.level = CurrentLevel;
+		cout<<"TIMESTEP *************"<<step<<endl;;
+	}
+}
+
+void AnimViewer::SetCurrentLevel(int frame) {
+	CurrentLevel = frame;
+	this->QueryWindow.level = CurrentLevel;
+}
+
+
+
+void vtkWindowUp(int resx, int resy, double cw0, double ch0, double cw1, double ch1) {
+
+	culler->SetMinimumCoverage(0.0);
+	culler->SetMaximumCoverage(0.0);
+	culler->SetSortingStyleToFrontToBack();
+
+	light->SetLightTypeToSceneLight();
+	light->SetPosition(0,0,10);
+
+	renA->AddLight(light);
+	renA->SetBackground(0,0,0);
+
+	renB->AddLight(light);
+	renB->SetBackground(0,0,0);
+
+	if(rank > 0) {
+		if(resx > resy) {
+			renA->SetViewport(0,0,0.5,1);
+			renB->SetViewport(0.5,0,1,1);
+		}
+		else {
+
+			renA->SetViewport(0,0,1,0.5);
+			renB->SetViewport(0,0.5,1,1);
+		}
+
+		renA->GetActiveCamera()->SetWindowCenter(cw0, ch0);
+		renB->GetActiveCamera()->SetWindowCenter(cw1, ch1);
+	}
+
+	renA->AddCuller(culler);
+	renB->AddCuller(culler);
+
+	renWin->AddRenderer(renA);
+	renWin->AddRenderer(renB);
+
+	//renA->ResetCamera();
+	//renB->ResetCamera();
+
+	renWin->BordersOff();
+	renWin->SetSize(resx, resy);
+
+
+}
+
+
+
+void vtkWindowUp(int resx, int resy, double cw, double ch) {
+
+	culler->SetMinimumCoverage(0.0);
+	culler->SetMaximumCoverage(0.0);
+	culler->SetSortingStyleToFrontToBack();
+
+	light->SetLightTypeToSceneLight();
+	light->SetPosition(0,0,10);
+
+	renA->AddLight(light);
+	renA->SetBackground(0,0,0);
+
+	if(rank > 0)
+		renA->GetActiveCamera()->SetWindowCenter(cw, ch);
+
+	renA->AddCuller(culler);
+
+	renWin->AddRenderer(renA);
+
+	//renA->ResetCamera();
+
+	renWin->BordersOff();
+	renWin->SetSize(resx, resy );
+}
+
+// Bad way to figure out location of global image center
+// BAD!!!!!!!! BAD!!!!!!!!??? BAD!!!!!!!!
+void UpCam() {
+
+	renWin->AddRenderer(renA);
+	renA->ResetCamera();
+
+	if(ScreensPerNode > 1) {
+		renWin->AddRenderer(renB);
+		renB->ResetCamera();
+	}
+}
+
+
+
+int main(int argc, char* argv[]) {
+
+	char temp[HOST_NAME_MAX];
+	gethostname(temp, HOST_NAME_MAX);
+	hostname = temp;
+	printf("Hostname: %s \n", hostname);
+
+	if(rank == 0) {
+
+		PORT = atoi(argv[3]);
+	}
+
+
+
+	unsigned char* windowBuf = NULL;
+
+	MPI_Datatype action;
+	MPI_Datatype position;
+
+	// MPI Initialization
+	MPI_Init(&argc, &argv);
+	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	MPI_Comm_size(MPI_COMM_WORLD, &size);
+
+	MPI_Type_contiguous(1, MPI_LONG, &action);
+	MPI_Type_contiguous(3, MPI_DOUBLE, &position);
+	MPI_Type_commit(&position);
+
+
+	animviewer.InitViewer(argv[2]);
+	printf("App name: %s\n",appname.c_str());
+	printf("X: %i Y: %i\n", xWindowPos, yWindowPos);
+
+
+	// SAGE --------------------------------------------------------------------
+
+	VirtualDesktop *vd = new VirtualDesktop();
+	PhysicalDisplay *pd = new PhysicalDisplay();
+	DisplayCluster *dc = new DisplayCluster();
+
+	if(rank > 0) {
+
+		int retcode;
+		retcode = stdInputFileParser( argv[1], pd, dc, vd);
+		if( retcode < 0 )
+		{
+			cout << "Node " << rank << " Failed to parse config file!" << endl;
+			return 1;
+		}
+
+		//find the display node that matches our hostname
+		char hostname[128] = "";
+		if( gethostname( hostname, 128 ) )
+		{
+			cout << "Node " << rank << " Could not retrieve hostname!" << endl;
+			return 1;
+		}
+
+		Display_Node* dn = dc->getFirstNode();
+
+		while( dn && strcmp( dn->Name(), hostname ))
+		{
+			dn = dn->Next();
+		}
+
+		if( !dn || dn->NumberOfMaps() <= 0)
+		{
+			cout << "Node " << rank << "Could not match a display node with hostname: "
+				<< hostname << endl;
+			return 1;
+		}
+
+		//assume only one mapping per node for the app
+		VDTtoPTmapper** maps = dn->Maps();
+
+		// initialize SAGE
+		sailConfig scfg;
+
+//#ifdef SAGE
+if(SAGE == true) {
+		//sailConfig scfg;
+		scfg.init("mframes.conf");
+		cout<<"~~~~~~~~~~~~~~"<<endl;
+		scfg.setAppName((char*)appname.c_str());
+		scfg.rank = rank-1;
+		scfg.nwID = 1;
+		scfg.resX = maps[0]->VirtualDesktopTile()->WidthInPixels();
+		scfg.resY = maps[0]->VirtualDesktopTile()->HeightInPixels();
+
+		sageRect renderImageMap;
+		renderImageMap.left = maps[0]->VirtualDesktopTile()->LowerLeftX();
+		renderImageMap.bottom = maps[0]->VirtualDesktopTile()->LowerLeftY();
+		renderImageMap.top = maps[0]->VirtualDesktopTile()->LowerLeftY() +
+			maps[0]->VirtualDesktopTile()->HeightRatio();
+		renderImageMap.right = maps[0]->VirtualDesktopTile()->LowerLeftX() +
+			maps[0]->VirtualDesktopTile()->WidthRatio();
+
+		scfg.imageMap = renderImageMap;
+		scfg.pixFmt = PIXFMT_888;
+		scfg.rowOrd = BOTTOM_TO_TOP;
+
+		cout << "NODE: " << rank << " = w: " << scfg.resX
+			<< " h: " << scfg.resY
+			<< " coords: " << renderImageMap.left << ", "
+			<< renderImageMap.top << " to "
+			<< renderImageMap.right << ", "
+			<< renderImageMap.bottom << endl;
+
+}
+//#endif
+		int resX = window_w = maps[0]->VirtualDesktopTile()->WidthInPixels();
+		int resY = window_h = maps[0]->VirtualDesktopTile()->HeightInPixels();
+
+
+//#ifdef SAGE
+if(SAGE == true) {
+		sageInf.init(scfg);
+		windowBuf = (unsigned char*)sageInf.getBuffer();
+		cout << "sail initialized " << endl;
+}
+//#endif
+
+
+		cout << "NODE " << rank << " WAITING TO QUIT" << endl;
+
+		// Viewport window center calculations
+		cw0 = - (vd->HorizRes() - 2*vd->HorizRes() *
+					maps[0]->VirtualDesktopTile()->LowerLeftX()) /
+					maps[0]->VirtualDesktopTile()->WidthInPixels() +
+					(1.0 - maps[0]->PhysicalTile()->LeftMullionThickness() / 10);
+
+		ch0 = - (vd->VertRes() - 2*vd->VertRes() *
+					maps[0]->VirtualDesktopTile()->LowerLeftY()) /
+					maps[0]->VirtualDesktopTile()->HeightInPixels() +
+					(1.0 - maps[0]->PhysicalTile()->BottomMullionThickness() / 10);
+
+
+		if(dn->NumberOfMaps() > 1) {
+				ScreensPerNode = 2;
+
+				cw1 = - (vd->HorizRes() - 2*vd->HorizRes() *
+					maps[1]->VirtualDesktopTile()->LowerLeftX()) /
+					maps[1]->VirtualDesktopTile()->WidthInPixels() +
+					(1.0 - maps[1]->PhysicalTile()->LeftMullionThickness() / 10);
+
+				ch1 = - (vd->VertRes() - 2*vd->VertRes() *
+					maps[1]->VirtualDesktopTile()->LowerLeftY()) /
+					maps[1]->VirtualDesktopTile()->HeightInPixels() +
+					(1.0 - maps[1]->PhysicalTile()->BottomMullionThickness() / 10);
+
+
+				if(maps[0]->VirtualDesktopTile()->LowerLeftY() ==
+							maps[1]->VirtualDesktopTile()->LowerLeftY())
+					vtkWindowUp(resX*2, resY, cw0, ch0, cw1, ch1);
+				else
+					vtkWindowUp(resX, resY*2, cw0, ch0, cw1, ch1);
+		}
+
+		else {
+
+			vtkWindowUp(resX, resY, cw0, ch0);
+		}
+	}
+
+	// SAGE --------------------------------------------------------------------
+
+	//UpCam();
+
+
+	renWin->SetPosition(xWindowPos, yWindowPos);
+
+	animviewer.GetAnimFiles();
+	animviewer.InitRendering();
+	animviewer.SetUpPipeline();
+
+	animviewer.PositionAndScaleBlocks();
+	animviewer.ImportQueryWindowPixels();
+	animviewer.GivePixelsToVTK();
+
+
+	animviewer.SetInitialCamPosition();
+	/*
+	renA->InteractiveOff();
+	renA->GetActiveCamera()->GetPosition(CamPosition);
+	renA->GetActiveCamera()->SetClippingRange(-500,500);
+	renA->GetActiveCamera()->GetFocalPoint(Fpoint);
+
+
+
+	if(ScreensPerNode > 1) {
+
+		renB->InteractiveOff();
+		//renB->GetActiveCamera()->GetPosition(CamPosition);
+		renB->GetActiveCamera()->SetClippingRange(-500,500);
+		//renB->GetActiveCamera()->GetFocalPoint(Fpoint);
+	}
+
+	CamPosition[2] = 3.2;
+
+	*/
+
+	StartingZ = CamPosition[2];
+	animviewer.UpdateCamera(CamPosition, Fpoint);
+
+
+	if(rank == 0) {
+
+
+		QUANTAinit();
+		server = new QUANTAnet_tcpServer_c();
+		client = NULL;
+		recmsg = NULL;
+
+		if( server->init(PORT) <  0)
+		{
+			printf("Bad port: %i", PORT);
+			server->close();
+			delete server;
+			server = NULL;
+			exit(0);
+		}
+
+		printf("Running on port %i\n", PORT);
+
+
+		while(true) {
+
+			uiaction = -100;
+
+			char* msg = WaitForMessage();
+
+			if (msg != NULL)
+			{
+				printf("%s\n", msg);
+
+				if(!strcmp(msg, SLIDER1)) {
+					uiaction = 0;
+
+					static int readsize = sizeof(float) * 1;
+					float readarray[1];
+					if( client ) {
+						client->read((char*)readarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+					}
+
+					pos[0] = readarray[0];
+				}
+
+				else if(!strcmp(msg, SLIDER2)) {
+					uiaction = 1;
+
+					static int readsize = sizeof(float) * 1;
+					float readarray[1];
+					if( client ) {
+						client->read((char*)readarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+					}
+
+					pos[1] = readarray[0];
+				}
+
+				else if(!strcmp(msg, SLIDER3)) {
+					uiaction = 2;
+
+					static int readsize = sizeof(float) * 1;
+					float readarray[1];
+					if( client ) {
+						client->read((char*)readarray,&readsize,QUANTAnet_tcpClient_c::BLOCKING);
+					}
+
+					pos[2] = readarray[0];
+				}
+
+				else if(!strcmp(msg, RELEASE)) {
+					uiaction = 3;
+				}
+
+				else if(!strcmp(msg, PRESS)) {
+					uiaction = 4;
+				}
+
+				else if(!strcmp(msg, BROWSELEFT)) {
+					uiaction = 5;
+				}
+
+				else if(!strcmp(msg, BROWSERIGHT)) {
+					uiaction = 6;
+				}
+
+				else if(!strcmp(msg, PANLEFT)) {
+					uiaction = 7;
+				}
+
+				else if(!strcmp(msg, PANRIGHT)) {
+					uiaction = 8;
+				}
+
+				else if(!strcmp(msg, PANUP)) {
+					uiaction = 9;
+				}
+
+				else if(!strcmp(msg, PANDOWN)) {
+					uiaction = 10;
+				}
+
+				else if(!strcmp(msg, QUIT)) {
+					if(client)
+						client->close();
+
+					if(server)
+						server->close();
+
+					if(client)
+						delete client;
+
+					if(server)
+						delete server;
+
+					if(msg)
+						delete [] msg;
+
+					uiaction = 11;
+				}
+
+				else if(!strcmp(msg, CENTER)) {
+					uiaction = 12;
+				}
+
+			}
+
+			for (int i = 0 ; i < size - 1 ; i++) {
+				MPI_Send(&uiaction, 1, action, i+1, 1, MPI_COMM_WORLD);
+			}
+
+			for (int i = 0 ; i < size - 1 ; i++) {
+				MPI_Send(&pos, 1, position, i+1, 1, MPI_COMM_WORLD);
+			}
+
+			if(uiaction == 11) break;
+
+			// synchronize
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+
+	}
+
+	else if (rank > 0) {
+		// MPI status variable
+    	MPI_Status status;
+		MPI_Status status1;
+
+		animviewer.CreateZoomBounds();
+
+		cout<<"Cam "<<CamPosition[0]<<" "<<CamPosition[1]
+					<<" "<<CamPosition[2]<<endl;
+
+		/*
+		if(rank == 5) {
+			renA->AddActor2D(text);
+			renWin->Render();
+		}
+
+		int preload = 0;
+		if(end < 20) preload = end;
+		else preload = 20;
+
+		for(int i=start; i<preload; i++) {
+			animviewer.SetTimeStep(1);
+			animviewer.ImportQueryWindowPixels();
+			animviewer.GivePixelsToVTK();
+			renWin->Render();
+		}
+
+		if(rank == 5) {
+			renA->RemoveActor2D(text);
+		}
+		*/
+
+		pointer->SetPosition(CamPosition[0], CamPosition[1], 0);
+		renA->AddActor(pointer);
+		if(ScreensPerNode > 1) renB->AddActor(pointer);
+
+		pointer->SetScale(CamPosition[2]/20, CamPosition[2]/20, 0);
+
+
+		// Reset to first frame
+		animviewer.SetCurrentLevel(start);
+		//animviewer.ImportQueryWindowPixels();
+		//animviewer.GivePixelsToVTK();
+		renWin->Render();
+
+		while(true) {
+
+			MPI_Recv(&uiaction, 1, action, 0, 1, MPI_COMM_WORLD, &status);
+
+			MPI_Recv(&pos, 1, position, 0, 1, MPI_COMM_WORLD, &status1);
+
+			if(uiaction == 0) {
+
+				CamPosition[0] = pos[0];
+				Fpoint[0] = pos[0];
+
+				animviewer.UpdateCamera(CamPosition, Fpoint);
+
+			}
+
+			if(uiaction == 1) {
+
+				CamPosition[1] = pos[1];
+				Fpoint[1] = pos[1];
+
+				animviewer.UpdateCamera(CamPosition, Fpoint);
+
+			}
+
+			if(uiaction == 2) {
+				if(pos[2] > 0) {
+					CamPosition[2] = pos[2];
+
+					animviewer.UpdateCamera(CamPosition, Fpoint);
+				}
+			}
+
+			if(uiaction == 5) {
+
+				animviewer.SetTimeStep(-1);
+
+				//if(rank == 5) {
+				//	renA->AddActor2D(text);
+				//	renWin->Render();
+				//}
+
+				animviewer.ImportQueryWindowPixels();
+				animviewer.GivePixelsToVTK();
+
+				//if(rank == 5) {
+				//	renA->RemoveActor2D(text);
+				//}
+
+			}
+
+			if(uiaction == 6) {
+
+				animviewer.SetTimeStep(1);
+
+				//if(rank == 5) {
+				//	renA->AddActor2D(text);
+				//	renWin->Render();
+				//}
+
+				animviewer.ImportQueryWindowPixels();
+				animviewer.GivePixelsToVTK();
+
+				//if(rank == 5) {
+				//	renA->RemoveActor2D(text);
+				//}
+
+			}
+
+
+			if(uiaction == 7) {
+
+				animviewer.AdjustLevelMovement(LEFT,X);
+
+				animviewer.PanLeft();
+
+
+			}
+
+			if(uiaction == 8) {
+
+				animviewer.AdjustLevelMovement(RIGHT,X);
+
+				animviewer.PanRight();
+
+
+			}
+
+			if(uiaction == 10) {
+
+
+				animviewer.AdjustLevelMovement(DOWN,Y);
+
+				animviewer.PanDown();
+
+			}
+
+			if(uiaction == 9) {
+
+				animviewer.AdjustLevelMovement(UP,Y);
+
+				animviewer.PanUp();
+
+			}
+
+
+			if(uiaction == 3) {
+
+			}
+
+			if(uiaction == 4) {
+				//animviewer.CleanUpMainWindow();
+			}
+
+			if(uiaction == 12) {
+				CamPosition[0] = PointerPosition[0];
+				CamPosition[1] = PointerPosition[1];
+				Fpoint[0] = PointerPosition[0];
+				Fpoint[1] = PointerPosition[1];
+
+				animviewer.UpdateCamera(CamPosition, Fpoint);
+
+
+			}
+
+			if(uiaction == 11) {
+				if(SAGE == true) {
+					//if (windowBuf) delete [] windowBuf;
+				}
+				break;
+			}
+
+
+
+
+			renWin->Render();
+//#ifdef SAGE
+			if(SAGE == true) {
+
+			//if (windowBuf) delete [] windowBuf;
+
+
+			memcpy(windowBuf, renWin->GetPixelData(0, 0, window_w-1, window_h-1, 1), window_w*window_h*3);
+}
+//#endif
+
+			// synchronize
+			MPI_Barrier(MPI_COMM_WORLD);
+//#ifdef SAGE
+if(SAGE == true) {
+			sageInf.swapBuffer();
+			windowBuf = (unsigned char *)sageInf.getBuffer();
+}
+//#endif
+
+		}
+	}
+
+	// finalize
+	MPI_Finalize();
+
+	renA->Delete();
+	renB->Delete();
+	renWin->Delete();
+	light->Delete();
+	culler->Delete();
+	text->Delete();
+
+	cone->Delete();
+	cube->Delete();
+	sphere->Delete();
+	sphereMapper->Delete();
+	pointer->Delete();
+
+	splash->Delete();
+	splashMapper->Delete();
+	splashScreen->Delete();
+
+	// exit
+	return EXIT_SUCCESS;
+}
Index: trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.h
===================================================================
--- trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.h	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/vtkXOpenGLOffScreenRenderWindow.h	(revision 4)
@@ -0,0 +1,272 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    $RCSfile: vtkXOpenGLOffScreenRenderWindow.h,v $
+  Language:  C++
+  Date:      $Date: 2003/03/26 14:04:59 $
+  Version:   $Revision: 1.22 $
+
+  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+// .NAME vtkXOpenGLOffScreenRenderWindow - OpenGL rendering window
+// .SECTION Description
+// vtkXOpenGLOffScreenRenderWindow is a concrete implementation of the abstract class
+// vtkRenderWindow. vtkOpenGLRenderer interfaces to the OpenGL graphics
+// library. Application programmers should normally use vtkRenderWindow
+// instead of the OpenGL specific version.
+
+#ifndef __vtkXOpenGLOffScreenRenderWindow_h
+#define __vtkXOpenGLOffScreenRenderWindow_h
+
+#include "vtk/vtkOpenGLRenderWindow.h"
+#include <X11/Xlib.h> // Needed for X types used in the public interface
+#include <X11/Xutil.h> // Needed for X types used in the public interface
+
+class vtkIdList;
+class vtkXOpenGLOffScreenRenderWindowInternal;
+
+class VTK_RENDERING_EXPORT vtkXOpenGLOffScreenRenderWindow : public vtkOpenGLRenderWindow
+{
+public:
+  static vtkXOpenGLOffScreenRenderWindow *New();
+  vtkTypeRevisionMacro(vtkXOpenGLOffScreenRenderWindow,vtkOpenGLRenderWindow);
+  void PrintSelf(ostream& os, vtkIndent indent);
+
+  // Description:
+  // Begin the rendering process.
+  virtual void Start(void);
+
+  // Description:
+  // End the rendering process and display the image.
+  virtual void Frame(void);
+
+  // Description:
+  // Initialize the window for rendering.
+  virtual void WindowInitialize(void);
+
+  // Description:
+  // Initialize the rendering window.
+  virtual void Initialize(void);
+
+  // Description:
+  // Change the window to fill the entire screen.
+  virtual void SetFullScreen(int);
+
+  // Description:
+  // Resize the window.
+  virtual void WindowRemap(void);
+
+  // Description:
+  // Set the preferred window size to full screen.
+  virtual void PrefFullScreen(void);
+
+  // Description:
+  // Specify the size of the rendering window.
+  virtual void SetSize(int,int);
+  virtual void SetSize(int a[2]) {this->SetSize(a[0], a[1]);};
+
+  // Description:
+  // Get the X properties of an ideal rendering window.
+  virtual Colormap GetDesiredColormap();
+  virtual Visual  *GetDesiredVisual();
+  virtual XVisualInfo     *GetDesiredVisualInfo();
+  virtual int      GetDesiredDepth();
+
+  // Description:
+  // Prescribe that the window be created in a stereo-capable mode. This
+  // method must be called before the window is realized. This method
+  // overrides the superclass method since this class can actually check
+  // whether the window has been realized yet.
+  virtual void SetStereoCapableWindow(int capable);
+
+  // Description:
+  // Make this window the current OpenGL context.
+  void MakeCurrent();
+
+  // Description:
+  // If called, allow MakeCurrent() to skip cache-check when called.
+  // MakeCurrent() reverts to original behavior of cache-checking
+  // on the next render.
+  void SetForceMakeCurrent();
+
+  // Description:
+  // Get report of capabilities for the render window
+  const char *ReportCapabilities();
+
+  // Description:
+  // Does this render window support OpenGL? 0-false, 1-true
+  int SupportsOpenGL();
+
+  // Description:
+  // Is this render window using hardware acceleration? 0-false, 1-true
+  int IsDirect();
+
+  // Description:
+  // Xwindow get set functions
+  virtual void *GetGenericDisplayId() {return (void *)this->GetDisplayId();};
+  virtual void *GetGenericWindowId();
+  virtual void *GetGenericParentId()  {return (void *)this->ParentId;};
+  virtual void *GetGenericContext();
+  virtual void *GetGenericDrawable()  {return (void *)this->WindowId;};
+
+  // Description:
+  // Get the size of the screen in pixels
+  virtual int     *GetScreenSize();
+
+  // Description:
+  // Get this RenderWindow's X display id.
+  Display *GetDisplayId();
+
+  // Description:
+  // Create the default pixmap
+  Pixmap pixmap;
+
+  // Description:
+  // Set the X display id for this RenderWindow to use to a pre-existing
+  // X display id.
+  void     SetDisplayId(Display *);
+  void     SetDisplayId(void *);
+
+  // Description:
+  // Get this RenderWindow's parent X window id.
+  Window   GetParentId();
+
+  // Description:
+  // Sets the parent of the window that WILL BE created.
+  void     SetParentId(Window);
+  void     SetParentId(void *);
+
+  // Description:
+  // Get this RenderWindow's X window id.
+  Window   GetWindowId();
+
+  // Description:
+  // Set this RenderWindow's X window id to a pre-existing window.
+  void     SetWindowId(Window);
+  void     SetWindowId(void *);
+
+  // Description:
+  // Specify the X window id to use if a WindowRemap is done.
+  void     SetNextWindowId(Window);
+
+  // Description:
+  // Set the window id of the new window once a WindowRemap is done.
+  // This is the generic prototype as required by the vtkRenderWindow
+  // parent.
+  void     SetNextWindowId(void *);
+
+  void     SetWindowName(const char *);
+
+  // Description:
+  // Hide or Show the mouse cursor, it is nice to be able to hide the
+  // default cursor if you want VTK to display a 3D cursor instead.
+  void HideCursor();
+  void ShowCursor();
+
+  // Description:
+  // Change the shape of the cursor
+  virtual void SetCurrentCursor(int);
+
+  // Description:
+  // Check to see if a mouse button has been pressed.
+  // All other events are ignored by this method.
+  // This is a useful check to abort a long render.
+  virtual  int GetEventPending();
+
+  // Description:
+  // Set this RenderWindow's X window id to a pre-existing window.
+  void     SetWindowInfo(char *info);
+
+  // Description:
+  // Set the window info that will be used after WindowRemap()
+  void     SetNextWindowInfo(char *info);
+
+  // Description:
+  // Sets the X window id of the window that WILL BE created.
+  void     SetParentInfo(char *info);
+
+  // Description:
+  // This computes the size of the render window
+  // before calling the supper classes render
+  void Render();
+
+protected:
+  vtkXOpenGLOffScreenRenderWindow();
+  ~vtkXOpenGLOffScreenRenderWindow();
+
+  vtkXOpenGLOffScreenRenderWindowInternal *Internal;
+
+  Window   ParentId;
+  Window   WindowId;
+  Window   NextWindowId;
+  Display *DisplayId;
+  Colormap ColorMap;
+  int      OwnWindow;
+  int      OwnDisplay;
+  int      ScreenSize[2];
+  int      CursorHidden;
+  int      ForceMakeCurrent;
+  int      UsingHardware;
+  char    *Capabilities;
+
+  // we must keep track of the cursors we are using
+  Cursor XCArrow;
+  Cursor XCSizeAll;
+  Cursor XCSizeNS;
+  Cursor XCSizeWE;
+  Cursor XCSizeNE;
+  Cursor XCSizeNW;
+  Cursor XCSizeSE;
+  Cursor XCSizeSW;
+
+private:
+  vtkXOpenGLOffScreenRenderWindow(const vtkXOpenGLOffScreenRenderWindow&);  // Not implemented.
+  void operator=(const vtkXOpenGLOffScreenRenderWindow&);  // Not implemented.
+};
+
+
+
+#endif
Index: trunk/src/testing/app/mframes/init_code/machine.dat
===================================================================
--- trunk/src/testing/app/mframes/init_code/machine.dat	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/machine.dat	(revision 4)
@@ -0,0 +1,12 @@
+10.0.8.116
+10.0.8.117
+10.0.8.118
+10.0.8.111
+10.0.8.112
+10.0.8.113
+10.0.8.129
+10.0.8.130
+10.0.8.131
+10.0.8.132
+10.0.8.133
+10.0.8.134
Index: trunk/src/testing/app/mframes/init_code/Makefile
===================================================================
--- trunk/src/testing/app/mframes/init_code/Makefile	(revision 4)
+++ trunk/src/testing/app/mframes/init_code/Makefile	(revision 4)
@@ -0,0 +1,35 @@
+QUANTA_DIR=/usr/local
+QUANTA_CFLAGS=-I$(QUANTA_DIR)/include -DQUANTA_USE_PTHREADS -DQUANTA_THREAD_SAFE
+QUANTA_LIB=-L$(QUANTA_DIR)/lib64 -lquanta_64
+
+SAGE_CFLAGS=-I../../../include
+SAGE_LIB=-L../../../lib -lsail
+
+VTK_INCLUDE=/usr/local/VTK-4.4/include
+VTK_LIB=/usr/local/VTK-4.4/lib/vtk
+
+SDL_INCLUDE=/usr/include
+SDL_LIB=/usr/lib64
+
+CFLAGS=-Wno-deprecated -I/opt/mpich/ch-p4/include -I$(VTK_INCLUDE) -I$(SDL_INCLUDE)
+
+LDFLAGS=-L/opt/mpich/ch-p4/lib64 -lmpich \
+-L$(VTK_LIB) -lvtkRendering -lvtkImaging -lvtkHybrid \
+-L$(SDL_LIB) -lSDL
+
+CXX=g++
+
+OBJS= initf.o file_parsers.o tile_config.o
+
+init_magic_frames: $(OBJS) 
+	$(CXX) -g -O -o init_magic_frames $(OBJS) $(SAGE_LIB) $(QUANTA_LIB) $(LDFLAGS)
+
+
+install: init_magic_frames
+	cp init_magic_frames ../../../bin/MAGIC 
+
+%.o: %.cpp
+	$(CXX) -g -c -O $(CFLAGS) $(SAGE_CFLAGS) $(QUANTA_CFLAGS) -o $@ $< 
+
+clean:
+	rm *.o init_magic_frames 
Index: trunk/src/testing/app/mframes/machinefile_code/tile_config.h
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/tile_config.h	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/tile_config.h	(revision 4)
@@ -0,0 +1,312 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: tile_config.h
+-	Purpose: Contains all class descriptions for building
+-	a description of a tile display system, at run time
+---------------------------------------------------------------------------*/
+#ifndef SAGE_TILE_CONFIG_H
+#define SAGE_TILE_CONFIG_H
+
+#define _DEBUG 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+//__________________________________________
+class Physical_Tile;
+class Display_Node;
+class Virtual_Desktop_Tile;
+
+class DisplayCluster;
+class PhysicalDisplay;
+class VirtualDesktop;
+//__________________________________________
+
+class Physical_Tile
+{
+private:
+	//int horizRes;	//horizontal resolution
+	//int vertRes;	//vertical resolution
+	float screenWidth;	//width of screen in inches
+	float screenHeight;	//height of screen in inches
+	float leftMullion;	//the width of the left Mullion in inches
+	float rightMullion;	// "	"	"  right " 	"
+	float topMullion;		// "	"	"  top   "	"
+	float bottomMullion;	// "	"	"  bottom "	"
+	float lowerleftX;	//the x position of the bottom left corner of the tile (including the mullions from left)
+						//with respect to some arbritrary origin
+	float lowerleftY;	//the y position of the bottom left corner of the tile (including the mullions from bottom)
+						//with respect to some arbritrary origin
+	int id;
+	Virtual_Desktop_Tile* virtDeskTile;	//the virtual desktop tile that the physical tile will display
+	Physical_Tile* next;
+	Display_Node*	 source;	//the display node that is the source to the physical tile
+public:
+	Physical_Tile();
+	~Physical_Tile();
+
+	float ScreenWidthDimension();
+	float ScreenHeightDimension();
+	float LeftMullionThickness();
+	float RightMullionThickness();
+	float TopMullionThickness();
+	float BottomMullionThickness();
+	float LowerLeftX();
+	float LowerLeftY();
+	int ID();
+	Physical_Tile* Next();
+	Display_Node* Source();
+	Virtual_Desktop_Tile* VirtualDesktopTile();
+
+
+	void ScreenWidthDimension(float);
+	void ScreenHeightDimension(float);
+	void RightMullionThickness(float);
+	void LeftMullionThickness(float);
+	void TopMullionThickness(float);
+	void BottomMullionThickness(float);
+	void LowerLeftX(float);
+	void LowerLeftY(float);
+	void ID(int);
+	void Next(Physical_Tile*);
+	void Source(Display_Node*);
+	void VirtualDesktopTile(Virtual_Desktop_Tile*);
+};
+
+class Virtual_Desktop_Tile
+{
+private:
+	float	lowerLeftX;	//the ratio of the lower left x position to the entire virtual desktop width
+	float 	lowerLeftY;	//the ratio of the lower left y position to the entire virtual desktop height
+
+	float   widthRatio;   //the ratio of the width of the virtual desktop tile
+				//to the entire virtual desktop width
+
+	float 	heightRatio;	//the ratio of the height of the virtual desktop tile
+				//to the entire virtual desktop height
+
+	int 	id;		//the id of the virtual desktop tile
+
+
+	int		lowerLeftPixelX;
+	int		lowerLeftPixelY;
+	int		widthInPixels;
+	int		heightInPixels;
+
+	int 	nonMullionLLX;	//lower left X on a zero mullion display
+	int		nonMullionLLY;	//lower left Y on a zero mullion display
+
+	Display_Node* dispNode;	//the node that will display the virtual desktop tile to the associated physical tile
+	Virtual_Desktop_Tile *next;
+
+
+public:
+	Virtual_Desktop_Tile();
+	~Virtual_Desktop_Tile();
+	float LowerLeftX();
+	float LowerLeftY();
+	int	LowerLeftPixelX();
+	int LowerLeftPixelY();
+	int WidthInPixels();
+	int HeightInPixels();
+	int NonMullionLLX();
+	int NonMullionLLY();
+
+	float WidthRatio();	//The ratio of the width of the tile to that of the whole virtual desktop
+	float HeightRatio();	//The ratio of the height of the tile to that of the whole virtual desktop
+	int ID();		//The unique ID of the tile
+	Display_Node* DisplayNode();	//The physical tile that this virtual desktop tile resides
+	Virtual_Desktop_Tile* Next();
+
+	void LowerLeftX(float);
+	void LowerLeftY(float);
+	void NonMullionLLX(int);
+	void NonMullionLLY(int);
+	void LowerLeftPixelX(int);
+	void LowerLeftPixelY(int);
+	void WidthInPixels(int);
+	void HeightInPixels(int);
+	void WidthRatio(float);
+	void HeightRatio(float);
+	void ID(int);
+	void DisplayNode(Display_Node*);
+	void Next(Virtual_Desktop_Tile*);
+
+};
+
+class VDTtoPTmapper
+{
+	Physical_Tile* pt;
+	Virtual_Desktop_Tile *vdt;
+
+public:
+	VDTtoPTmapper(Physical_Tile*, Virtual_Desktop_Tile*);
+	~VDTtoPTmapper();
+	Physical_Tile* PhysicalTile();
+	Virtual_Desktop_Tile* VirtualDesktopTile();
+
+};
+
+class Display_Node
+{
+private:
+	char* nodeName;		//the name of the computer that holds pixels to display
+	char* ip;		//ip address of the computer the holds pixels to display
+	VDTtoPTmapper**	maps;	//pointer to the array of VDTtoPTmapper objects
+	Display_Node* next;	//next display node in list
+	int numberOfMaps;	//The number of mappings from virtual desktop tile to physical tile
+				//that this display node can make (i.e. how many outputs the display node has)
+public:
+	Display_Node();
+	~Display_Node();
+	void Name(char* );
+	void IP(char* );
+	char* Name(void);
+	char* IP(void);
+	int  NumberOfMaps();
+	void NumberOfMaps(int);
+	VDTtoPTmapper** Maps();
+	bool AddMap(VDTtoPTmapper*);
+	Display_Node* Next();
+	void Next(Display_Node*);
+	void RemoveMap(VDTtoPTmapper*);
+	void RemoveMap(int);		//delete a specific mapping given an index
+};
+
+
+//__________________________________________
+
+class DisplayCluster
+{
+protected:
+	Display_Node*		displayNodeListHead;	//pointer to the display node linked list
+	VirtualDesktop*		vd;
+	PhysicalDisplay*	pd;
+
+public:
+	DisplayCluster();
+	~DisplayCluster();
+	void AddDisplayNode(Display_Node* );
+	void RemoveDisplayNode(char*);		//remove a display node given the display node name
+	void RemoveDisplayNodeByName(char*);
+	void RemoveDisplayNodeByIP(char*);	//remove a display node given the display node ip
+	Display_Node*	getFirstNode();		//return the first node in the display node list
+
+	VirtualDesktop* VirtualDesktopAssoc();
+	void VirtualDesktopAssoc(VirtualDesktop* );
+	PhysicalDisplay* PhysicalDisplayAssoc();
+	void PhysicalDisplayAssoc(PhysicalDisplay*);
+
+	bool GenerateMapping(Virtual_Desktop_Tile*, Physical_Tile*);
+	bool GenerateMapping(Virtual_Desktop_Tile*, Physical_Tile*, Display_Node*);
+	void RemoveMapping(Virtual_Desktop_Tile*, Physical_Tile*, Display_Node*);
+	void RemoveMapsWith(Virtual_Desktop_Tile*);	//Removes any mappings made witht the given virtual tile
+	void RemoveMapsWith(Physical_Tile*);		//Removes any mappings made with the given physical tile
+	bool NodeOnCluster(Display_Node*);
+
+};
+
+
+class PhysicalDisplay
+{
+protected:
+	Physical_Tile* 	physicalTileListHead;	//pointer to the physical tile linked list
+
+	VirtualDesktop*		vd;
+	DisplayCluster*		dc;
+	float				pixelsPerInch;		//the pixels per inch ratio
+
+public:
+	PhysicalDisplay();
+	~PhysicalDisplay();
+	VirtualDesktop* VirtualDesktopAssoc();
+	void VirtualDesktopAssoc(VirtualDesktop* );
+	DisplayCluster* DisplayClusterAssoc();
+	void DisplayClusterAssoc(DisplayCluster* );
+	int AddPhysicalTile(Physical_Tile*);				//adds a tile to the display and returns its unique id
+
+	Physical_Tile* RemovePhysicalTileByID(int, bool);		//remove a physical tile from this physical display
+									//the second parameter is used to have the tile deleted
+									//or just removed.  If "true" the tile will be deleted
+									//from memory, otherwise the address of the tile will
+									//be returned
+
+	Physical_Tile* getFirstNode();		//returns the first node in the physical tile list
+	bool TileOnPhysicalDisplay(Physical_Tile*);
+	float PixelsPerInch();				//get the pixels per inch that ALL the physical tiles on this display conform to
+	void PixelsPerInch(float);			//set the pixels per inch that ALL the physical tiles on this display conform to
+};
+
+class VirtualDesktop
+{
+protected:
+	int horizRes;		//horizontal resolution	of virtual desktop
+	int vertRes;		//vertical resolution of virtual desktop
+
+	//pointer to Virtual_Desktop_Tile linked list
+	Virtual_Desktop_Tile* tileListHead;
+
+	PhysicalDisplay*	pd;
+	DisplayCluster*		dc;
+
+
+public:
+	VirtualDesktop();
+	~VirtualDesktop();
+
+	PhysicalDisplay* PhysicalDisplayAssoc();
+	void PhysicalDisplayAssoc(PhysicalDisplay*);
+	DisplayCluster* DisplayClusterAssoc();
+	void DisplayClusterAssoc(DisplayCluster*);
+
+	int HorizRes(void){ return horizRes; }
+	int VertRes(void){ return vertRes; }
+
+	void AddTile(Virtual_Desktop_Tile*);
+	void RemoveTile(Virtual_Desktop_Tile*);
+
+	Virtual_Desktop_Tile* getFirstNode(void);
+
+	bool Update(void);		//update the virtual desktop with newly added/removed tile mappings
+
+};
+
+#endif
Index: trunk/src/testing/app/mframes/machinefile_code/machine.dat
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/machine.dat	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/machine.dat	(revision 4)
@@ -0,0 +1,12 @@
+10.0.8.116
+10.0.8.117
+10.0.8.118
+10.0.8.111
+10.0.8.112
+10.0.8.113
+10.0.8.129
+10.0.8.130
+10.0.8.131
+10.0.8.132
+10.0.8.133
+10.0.8.134
Index: trunk/src/testing/app/mframes/machinefile_code/Makefile
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/Makefile	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/Makefile	(revision 4)
@@ -0,0 +1,15 @@
+CC=g++
+
+OBJS= machinefile_gen.o file_parsers.o tile_config.o
+
+machinefile_gen: $(OBJS) 
+	$(CC) -g -o machinefile_gen $(OBJS) 
+
+install: machinefile_gen
+	cp machinefile_gen /home/evl/dmitr/IGRID2005/bin
+
+%.o: %.cpp
+	$(CC) -c -o $@ $< 
+
+clean:
+	rm *.o machinefile_gen
Index: trunk/src/testing/app/mframes/machinefile_code/machinefile_gen.cpp
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/machinefile_gen.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/machinefile_gen.cpp	(revision 4)
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "tile_config.h"
+#include "file_parsers.h"
+
+PhysicalDisplay* pd;
+DisplayCluster* dc;
+VirtualDesktop* vd;
+
+int main(int argc, char** argv)
+{
+
+	if( argc < 3 )
+	{
+		printf("Usage: machinefile_gen <tile config file> <machine file>\n");
+		printf("input - tile config file\noutput - machine file\n");
+		return 0;
+	}
+
+	pd = new PhysicalDisplay();
+	dc = new DisplayCluster();
+	vd = new VirtualDesktop();
+
+	int retcode;
+	retcode = stdInputFileParser( argv[1], pd, dc, vd );
+	if( retcode < 0 )
+	{
+		delete pd;
+		delete dc;
+	//	delete vd;
+		return 1;
+	}
+
+	FILE* fptr = fopen(argv[2],"w");
+	Display_Node* dn = dc->getFirstNode();
+	while( dn )
+	{
+		fprintf( fptr, "%s\n", dn->IP() );
+		dn = dn->Next();
+	}
+
+	fclose(fptr);
+
+	delete pd;
+	delete dc;
+//	delete vd;
+
+	return 0;
+}
+
Index: trunk/src/testing/app/mframes/machinefile_code/file_parsers.cpp
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/file_parsers.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/file_parsers.cpp	(revision 4)
@@ -0,0 +1,687 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: file_parsers.cpp
+-	Purpose: Contains function implementation for file i/o to load in
+-	and write out tiled display system descriptions
+---------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+using namespace std;
+
+#include "file_parsers.h"
+
+#define UP_MULLION 0
+#define DOWN_MULLION 1
+#define LEFT_MULLION 2
+#define RIGHT_MULLION 3
+
+#ifdef _cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------
+int stdInputFileParser(char* filename,PhysicalDisplay*& pd,DisplayCluster*& dc,VirtualDesktop*& vd)
+{
+	if(filename == NULL)
+		return -1;
+
+	FILE* fin = fopen(filename,"r");
+
+	if(fin == NULL)
+		return -1;
+
+	//create objects
+	cout << "Creating High Level Objects" << endl;
+
+	if(pd == NULL)
+		pd = new PhysicalDisplay();
+	if(dc == NULL)
+		dc = new DisplayCluster();
+	if(vd == NULL)
+		vd = new VirtualDesktop();
+
+	//setup associations
+	cout << "Setting Associations" << endl;
+	dc->VirtualDesktopAssoc(vd);
+	dc->PhysicalDisplayAssoc(pd);
+	vd->PhysicalDisplayAssoc(pd);
+	vd->DisplayClusterAssoc(dc);
+	pd->VirtualDesktopAssoc(vd);
+	pd->DisplayClusterAssoc(dc);
+
+	Virtual_Desktop_Tile** tempVDT = NULL;
+	Physical_Tile** tempPT = NULL;
+	Display_Node** tempDN = NULL;
+	VDTtoPTmapper*** tempMapper = NULL;
+	char buffer1[32];
+
+	cout << "Gathering: Dimensions - ";
+	//First is Dimension Data
+	fscanf(fin,"%s",buffer1);
+	while( !strcmp( buffer1, "#" ))
+	{
+		while(fgetc(fin) != '\n');
+		fscanf(fin,"%s",buffer1);
+	}
+
+	if(strcmp( buffer1, "TileDisplay"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Dimensions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+	int dimx, dimy;
+	fscanf(fin, "%d %d\n", &dimx, &dimy);
+
+	//Next is the Mullions for every screen
+	cout << "Mullions - ";
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Mullions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float mullions[4];
+	fscanf( fin, "%f %f %f %f\n", &mullions[UP_MULLION], &mullions[DOWN_MULLION],
+					&mullions[LEFT_MULLION], &mullions[RIGHT_MULLION]);
+
+	cout << "Resolution - ";
+	//Next is Resolution of each screen
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Resolution"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float resolution[2];
+	fscanf( fin, "%f %f\n", &resolution[0], &resolution[1]);
+
+	cout << "Pixels Per Inch - ";
+	//Pixels Per Inch Is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "PPI"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float pixelsPerInch;
+	fscanf(fin, "%f\n", &pixelsPerInch);
+	pd->PixelsPerInch( pixelsPerInch );
+
+	//Determine Screen Dimensions from Pixels Per Inch & Screen Resolutions
+	float screenWidth, screenHeight;
+	screenWidth = resolution[0] / (float)pixelsPerInch;
+	screenHeight = resolution[1] / (float)pixelsPerInch;
+	cout << "ScreenWidth x ScreenHeight: " << screenWidth << 'x' << screenHeight << endl;
+	//figure out the "total dimensions" of a tile
+	float totalWidth = screenWidth + mullions[LEFT_MULLION] + mullions[RIGHT_MULLION];
+	float totalHeight = screenHeight + mullions[UP_MULLION] + mullions[DOWN_MULLION];
+
+	cout << "Machine Count" << endl;
+	//Number of Machines is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Machines"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	int machineCount;
+	fscanf(fin,"%d\n",&machineCount);
+
+
+	//Create the Virtual Desktop Tiles, Physical Tiles & Mappers to connect each one
+	tempVDT = new Virtual_Desktop_Tile*[dimx];
+	tempPT = new Physical_Tile*[dimx];
+//	tempMapper = new VDTtoPTmapper**[dimx];
+	cout << "Generating Tiles & Virtual Tiles" << endl;
+	for(int i = 0; i < dimx; i++)
+	{
+		tempVDT[i] = new Virtual_Desktop_Tile[dimy];
+		tempPT[i] = new Physical_Tile[dimy];
+//		tempMapper[i] = new VDTtoPTMapper*[dimy];
+
+		for(int j = 0; j < dimy; j++)
+		{
+
+			tempPT[i][j].ScreenHeightDimension( screenHeight );
+			tempPT[i][j].ScreenWidthDimension( screenWidth );
+			tempPT[i][j].BottomMullionThickness( mullions[DOWN_MULLION] );
+			tempPT[i][j].LeftMullionThickness( mullions[LEFT_MULLION] );
+			tempPT[i][j].RightMullionThickness( mullions[RIGHT_MULLION] );
+			tempPT[i][j].TopMullionThickness( mullions[UP_MULLION] );
+
+			tempPT[i][j].LowerLeftX( i * totalWidth );
+			tempPT[i][j].LowerLeftY( j * totalHeight );
+			pd->AddPhysicalTile( &(tempPT[i][j]));
+
+		}
+	}
+
+	//Go through and get each machine
+	cout << "Generating Machines & Creating Mappings" << endl;
+	for(int k = 0; k < machineCount; k++)
+	{
+		char ip[16];
+		char name[32];
+		int maps;
+		int tileX, tileY;
+
+		cout << k << ' ';
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "DisplayNode"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"DisplayNode\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+		//Name
+		cout << "Name ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Name"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Name\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",name);
+		cout << name << ' ';
+		//ip
+		cout << "IP: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "IP"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"IP\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",ip);
+		cout << ip << ' ';
+		//Monitors
+		cout << "Monitors: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Monitors"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Monitors\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%d", &maps );
+		cout << maps << ' ';;
+		Display_Node* dn;
+		dn = new Display_Node();
+		dn->NumberOfMaps( maps );
+		dn->Name( name );
+		dn->IP( ip );
+
+		dc->AddDisplayNode( dn );
+
+		for( int i = 0; i < maps; i++)
+		{
+			cout << '.';
+			fscanf(fin," (%d,%d)", &tileX, &tileY);
+			cout << '(' <<  tileX << ',' << tileY << ')';
+			dc->GenerateMapping( &(tempVDT[tileX][tileY]), &(tempPT[tileX][tileY]), dn );
+			vd->AddTile( &(tempVDT[tileX][tileY]) );
+
+		}
+
+		//fscanf(fin,"%s\n", buffer1);
+		cout << endl;
+
+#ifdef _DEBUG
+
+
+#endif
+
+	}
+
+	cout << endl << "Updating Virutal Desktop" << endl;
+
+	vd->Update();
+
+	fclose(fin);
+
+	return 1;
+}
+
+//--------------------------------------------------------
+void stdOutputFileWriter(char* filename,PhysicalDisplay* pd,DisplayCluster* dc,VirtualDesktop* vd)
+{
+
+}
+
+
+//--------------------------------------------------------
+int corewallInputFileParser(char* filename, PhysicalDisplay*& pd, DisplayCluster*& dc, VirtualDesktop*& vd, int*& startPos)
+{
+
+		if(filename == NULL)
+		return -1;
+
+	FILE* fin = fopen(filename,"r");
+
+	if(fin == NULL)
+		return -1;
+
+	//create objects
+	cout << "Creating High Level Objects" << endl;
+	if(pd == NULL)
+		pd = new PhysicalDisplay();
+	if(dc == NULL)
+		dc = new DisplayCluster();
+	if(vd == NULL)
+		vd = new VirtualDesktop();
+
+	//setup associations
+	cout << "Setting Associations" << endl;
+
+	dc->VirtualDesktopAssoc(vd);
+	dc->PhysicalDisplayAssoc(pd);
+	vd->PhysicalDisplayAssoc(pd);
+	vd->DisplayClusterAssoc(dc);
+	pd->VirtualDesktopAssoc(vd);
+	pd->DisplayClusterAssoc(dc);
+
+	Virtual_Desktop_Tile** tempVDT = NULL;
+	Physical_Tile** tempPT = NULL;
+	Display_Node** tempDN = NULL;
+	VDTtoPTmapper*** tempMapper = NULL;
+	char buffer1[32];
+
+	//cout << "Gathering: Dimensions - ";
+	printf("getting dimensions\n");
+	//First is Dimension Data
+	fscanf(fin,"%s",buffer1);
+	while( !strcmp( buffer1, "#" ))
+	{
+		while(fgetc(fin) != '\n');
+		fscanf(fin,"%s",buffer1);
+	}
+
+	if(strcmp( buffer1, "TileDisplay"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Dimensions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+	int dimx, dimy;
+	fscanf(fin, "%d %d\n", &dimx, &dimy);
+
+	//Next is the Mullions for every screen
+	cout << "Mullions - ";
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Mullions"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float mullions[4];
+	fscanf( fin, "%f %f %f %f\n", &mullions[UP_MULLION], &mullions[DOWN_MULLION],
+					&mullions[LEFT_MULLION], &mullions[RIGHT_MULLION]);
+
+	cout << "Resolution - ";
+	//Next is Resolution of each screen
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Resolution"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float resolution[2];
+	fscanf( fin, "%f %f\n", &resolution[0], &resolution[1]);
+
+	cout << "Pixels Per Inch - ";
+	//Pixels Per Inch Is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "PPI"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	float pixelsPerInch;
+	fscanf(fin, "%f\n", &pixelsPerInch);
+	pd->PixelsPerInch( pixelsPerInch );
+
+	//Determine Screen Dimensions from Pixels Per Inch & Screen Resolutions
+	float screenWidth, screenHeight;
+	screenWidth = resolution[0] / (float)pixelsPerInch;
+	screenHeight = resolution[1] / (float)pixelsPerInch;
+	cout << "ScreenWidth x ScreenHeight: " << screenWidth << 'x' << screenHeight << endl;
+	//figure out the "total dimensions" of a tile
+	float totalWidth = screenWidth + mullions[LEFT_MULLION] + mullions[RIGHT_MULLION];
+	float totalHeight = screenHeight + mullions[UP_MULLION] + mullions[DOWN_MULLION];
+
+	cout << "Machine Count" << endl;
+	//Number of Machines is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "Machines"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	int machineCount;
+	fscanf(fin,"%d\n",&machineCount);
+
+	//get the offsets
+	cout << "OffsetX" << endl;
+	//OffsetX is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "OffsetX"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%d\n",&(startPos[0]));
+
+
+	cout << "OffsetY" << endl;
+	//OffsetY is Next
+	fscanf(fin,"%s",buffer1);
+	if(strcmp( buffer1, "OffsetY"))
+	{
+		delete pd;
+		delete dc;
+		delete vd;
+		pd = NULL;
+		dc = NULL;
+		vd = NULL;
+		return -1;
+	}
+
+	fscanf(fin,"%d\n",&(startPos[1]));
+
+
+	//Create the Virtual Desktop Tiles, Physical Tiles & Mappers to connect each one
+	tempVDT = new Virtual_Desktop_Tile*[dimx];
+	tempPT = new Physical_Tile*[dimx];
+//	tempMapper = new VDTtoPTmapper**[dimx];
+	cout << "Generating Tiles & Virtual Tiles" << endl;
+	for(int i = 0; i < dimx; i++)
+	{
+		tempVDT[i] = new Virtual_Desktop_Tile[dimy];
+		tempPT[i] = new Physical_Tile[dimy];
+//		tempMapper[i] = new VDTtoPTMapper*[dimy];
+
+		for(int j = 0; j < dimy; j++)
+		{
+
+			tempPT[i][j].ScreenHeightDimension( screenHeight );
+			tempPT[i][j].ScreenWidthDimension( screenWidth );
+			tempPT[i][j].BottomMullionThickness( mullions[DOWN_MULLION] );
+			tempPT[i][j].LeftMullionThickness( mullions[LEFT_MULLION] );
+			tempPT[i][j].RightMullionThickness( mullions[RIGHT_MULLION] );
+			tempPT[i][j].TopMullionThickness( mullions[UP_MULLION] );
+
+			tempPT[i][j].LowerLeftX( i * totalWidth );
+			tempPT[i][j].LowerLeftY( j * totalHeight );
+			pd->AddPhysicalTile( &(tempPT[i][j]));
+
+		}
+	}
+
+	//Get the starting offsets
+	//Go through and get each machine
+	cout << "Generating Machines & Creating Mappings" << endl;
+	for(int k = 0; k < machineCount; k++)
+	{
+		char ip[16];
+		char name[32];
+		int maps;
+		int tileX, tileY;
+
+		cout << k << ' ';
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "DisplayNode"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"DisplayNode\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+		//Name
+		cout << "Name ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Name"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Name\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",name);
+		cout << name << ' ';
+		//ip
+		cout << "IP: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "IP"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"IP\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%s",ip);
+		cout << ip << ' ';
+		//Monitors
+		cout << "Monitors: ";
+		fscanf(fin,"%s",buffer1);
+		if(strcmp( buffer1, "Monitors"))
+		{
+			cout << "Read: " << buffer1 << " instead of \"Monitors\"" << endl;
+			delete pd;
+			delete dc;
+			delete vd;
+			pd = NULL;
+			dc = NULL;
+			vd = NULL;
+			return -1;
+		}
+
+		fscanf(fin,"%d", &maps );
+		cout << maps << ' ';;
+		Display_Node* dn;
+		dn = new Display_Node();
+		dn->NumberOfMaps( maps );
+		dn->Name( name );
+		dn->IP( ip );
+
+		dc->AddDisplayNode( dn );
+
+		for( int i = 0; i < maps; i++)
+		{
+			cout << '.';
+			fscanf(fin," (%d,%d)", &tileX, &tileY);
+//			cout << '(' <<  tileX << ',' << tileY << ')';
+			dc->GenerateMapping( &(tempVDT[tileX][tileY]), &(tempPT[tileX][tileY]), dn );
+			tempVDT[tileX][tileY].NonMullionLLX( resolution[0] * tileX );
+			tempVDT[tileX][tileY].NonMullionLLY( resolution[1] * tileY );
+			cout << "NonMullion x,y: " << screenWidth * tileX << ", "
+				<< screenHeight * tileY << endl;
+			vd->AddTile( &(tempVDT[tileX][tileY]) );
+		}
+
+		//fscanf(fin,"%s\n", buffer1);
+//		cout << endl;
+
+#ifdef _DEBUG
+
+
+#endif
+
+	}
+
+	cout << endl << "Updating Virutal Desktop" << endl;
+
+	vd->Update();
+
+	fclose(fin);
+
+	return 1;
+}
+
+#ifdef _cplusplus
+}
+#endif
Index: trunk/src/testing/app/mframes/machinefile_code/display.cfg
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/display.cfg	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/display.cfg	(revision 4)
@@ -0,0 +1,51 @@
+TileDisplay
+	Dimensions 3 3
+	Mullions 0 0 0 0
+	Resolution 800 600 
+	PPI 85
+	Machines 9
+
+DisplayNode 
+	Name something1
+	IP 131.193.108.111
+	Monitors 1 (0,0)
+
+DisplayNode 
+	Name something2
+	IP 131.193.108.112
+	Monitors 1 (1,0)
+
+DisplayNode 
+	Name something3
+	IP 131.193.108.113
+	Monitors 1 (2,0)
+
+DisplayNode 
+	Name something4
+	IP 131.193.108.114
+	Monitors 1 (0,1)
+
+DisplayNode 
+	Name something5
+	IP 131.193.108.115
+	Monitors 1 (1,1)
+
+DisplayNode 
+	Name something6
+	IP 131.193.108.116
+	Monitors 1 (1,2)
+
+DisplayNode 
+	Name something7
+	IP 131.193.108.117
+	Monitors 1 (0,2)
+
+DisplayNode 
+	Name something8
+	IP 131.193.108.118
+	Monitors 1 (1,2)
+
+DisplayNode 
+	Name something9
+	IP 131.193.108.119
+	Monitors 1 (2,2)
Index: trunk/src/testing/app/mframes/machinefile_code/tile_config.cpp
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/tile_config.cpp	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/tile_config.cpp	(revision 4)
@@ -0,0 +1,909 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: tile_config.cpp
+-	Purpose: Contains all class details/implementation for building
+-	a description of a tile display system, at run time
+---------------------------------------------------------------------------*/
+#include "tile_config.h"
+#include <string.h>
+
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Physical_Tile::Physical_Tile():screenWidth(0),screenHeight(0),
+				leftMullion(0),rightMullion(0),topMullion(0),bottomMullion(0),
+				id(-1),next(NULL),source(NULL)
+{
+	//nothing else to do
+}
+
+Physical_Tile::~Physical_Tile()
+{
+
+	source = NULL;
+	next = NULL;
+
+}
+
+void Physical_Tile::Source(Display_Node* dn)
+{
+	source = dn;
+}
+
+Display_Node* Physical_Tile::Source()
+{ return source; }
+
+float Physical_Tile::LowerLeftX(){ return lowerleftX; }
+float Physical_Tile::LowerLeftY(){ return lowerleftY; }
+
+void Physical_Tile::LowerLeftX(float lx){ lowerleftX = lx; }
+void Physical_Tile::LowerLeftY(float ly){ lowerleftY = ly; }
+
+
+float Physical_Tile::ScreenWidthDimension()
+{ return screenWidth; }
+
+void Physical_Tile::ScreenWidthDimension(float dim)
+{ screenWidth = dim; }
+
+float Physical_Tile::ScreenHeightDimension(void)
+{ return screenHeight; }
+
+void Physical_Tile::ScreenHeightDimension(float dim)
+{ screenHeight = dim; }
+
+float Physical_Tile::TopMullionThickness()
+{ return topMullion; }
+
+void Physical_Tile::TopMullionThickness(float t)
+{ topMullion = t; }
+
+float Physical_Tile::BottomMullionThickness()
+{ return bottomMullion; }
+
+void Physical_Tile::BottomMullionThickness(float t)
+{ bottomMullion = t; }
+
+float Physical_Tile::LeftMullionThickness()
+{ return leftMullion; }
+
+void Physical_Tile::LeftMullionThickness(float t)
+{ leftMullion = t; }
+
+float Physical_Tile::RightMullionThickness()
+{ return rightMullion; }
+
+void Physical_Tile::RightMullionThickness(float t)
+{ rightMullion = t; }
+
+int Physical_Tile::ID()
+{ return id; }
+
+void Physical_Tile::ID(int i)
+{ id = i; }
+
+Physical_Tile* Physical_Tile::Next()
+{ return next; }
+
+void Physical_Tile::Next(Physical_Tile* n)
+{ next = n; }
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Virtual_Desktop_Tile::Virtual_Desktop_Tile():lowerLeftX(0),lowerLeftY(0),widthRatio(0),
+						heightRatio(0),id(-1),next(NULL),nonMullionLLX(0),
+						nonMullionLLY(0)
+{
+	//do nothing
+}
+
+Virtual_Desktop_Tile::~Virtual_Desktop_Tile()
+{
+
+	next = NULL;
+}
+
+float Virtual_Desktop_Tile::LowerLeftX()
+{ return lowerLeftX; }
+
+void Virtual_Desktop_Tile::LowerLeftX(float x)
+{ lowerLeftX = x; }
+
+float Virtual_Desktop_Tile::LowerLeftY()
+{ return lowerLeftY; }
+
+void Virtual_Desktop_Tile::LowerLeftY(float y)
+{ lowerLeftY = y; }
+
+void Virtual_Desktop_Tile::LowerLeftPixelX(int p)
+{ lowerLeftPixelX = p; }
+
+void Virtual_Desktop_Tile::LowerLeftPixelY(int p)
+{ lowerLeftPixelY = p; }
+
+void Virtual_Desktop_Tile::WidthInPixels(int p)
+{ widthInPixels = p; }
+
+void Virtual_Desktop_Tile::HeightInPixels(int p)
+{ heightInPixels = p; }
+
+int Virtual_Desktop_Tile::LowerLeftPixelX()
+{ return lowerLeftPixelX; }
+
+int Virtual_Desktop_Tile::LowerLeftPixelY()
+{ return lowerLeftPixelY; }
+
+int Virtual_Desktop_Tile::WidthInPixels()
+{ return widthInPixels; }
+
+int Virtual_Desktop_Tile::HeightInPixels()
+{ return heightInPixels; }
+
+float Virtual_Desktop_Tile::WidthRatio()
+{ return widthRatio; }
+
+void Virtual_Desktop_Tile::WidthRatio(float r)
+{ widthRatio = r; }
+
+float Virtual_Desktop_Tile::HeightRatio()
+{ return heightRatio; }
+
+void Virtual_Desktop_Tile::HeightRatio(float r)
+{ heightRatio = r; }
+
+int Virtual_Desktop_Tile::ID()
+{ return id; }
+
+void Virtual_Desktop_Tile::ID(int i)
+{ id = i; }
+
+Virtual_Desktop_Tile* Virtual_Desktop_Tile::Next()
+{ return next; }
+
+void Virtual_Desktop_Tile::Next(Virtual_Desktop_Tile* vdt)
+{ next = vdt; }
+
+Display_Node* Virtual_Desktop_Tile::DisplayNode()
+{ return dispNode; }
+
+void Virtual_Desktop_Tile::DisplayNode(Display_Node* dn)
+{ dispNode = dn; }
+
+int Virtual_Desktop_Tile::NonMullionLLX()
+{ return nonMullionLLX; }
+
+int Virtual_Desktop_Tile::NonMullionLLY()
+{ return nonMullionLLY; }
+
+void Virtual_Desktop_Tile::NonMullionLLX(int x)
+{ nonMullionLLX = x; }
+
+void Virtual_Desktop_Tile::NonMullionLLY(int y)
+{ nonMullionLLY = y; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+VDTtoPTmapper::VDTtoPTmapper(Physical_Tile* tpt, Virtual_Desktop_Tile* tvdt):pt(tpt),vdt(tvdt)
+{ }
+
+VDTtoPTmapper::~VDTtoPTmapper()
+{ }
+
+Physical_Tile* VDTtoPTmapper::PhysicalTile(){ return pt; }
+
+Virtual_Desktop_Tile* VDTtoPTmapper::VirtualDesktopTile(){ return vdt; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+Display_Node::Display_Node():nodeName(NULL),ip(NULL),next(NULL),maps(NULL),numberOfMaps(0)
+{
+
+}
+
+Display_Node::~Display_Node()
+{
+
+	if( maps && numberOfMaps)
+	{
+
+
+	}
+
+	if( ip )
+		delete [] ip;
+
+	if( nodeName )
+		delete [] nodeName;
+
+	next = NULL;
+}
+
+void Display_Node::Name(char* newName)
+{
+	if( nodeName )
+		delete [] nodeName;
+
+	nodeName = new char[strlen(newName) + 1];
+	strcpy(nodeName,newName);
+}
+
+void Display_Node::IP(char* newIP)
+{
+	if( ip )
+		delete [] ip;
+
+	ip = new char[strlen(newIP) + 1];
+	strcpy(ip,newIP);
+}
+
+char* Display_Node::Name(){ return nodeName; }
+char* Display_Node::IP(){ return ip; }
+Display_Node* Display_Node::Next(){ return next; }
+void Display_Node::Next(Display_Node* dn){ next = dn; }
+
+int Display_Node::NumberOfMaps(){ return numberOfMaps; }
+void Display_Node::NumberOfMaps(int n)	//need to adjust maps
+{
+	VDTtoPTmapper** tempMap = maps;
+	maps = NULL;
+	maps = new VDTtoPTmapper*[n];
+
+	int i = 0;
+
+	//copy over as many nodes as the new maps array can fit
+	for(	; i < n; i++)
+	{
+		if( i < numberOfMaps && tempMap)
+		{
+			maps[i] = tempMap[i];
+			tempMap[i] = NULL;
+		}
+		else
+			maps[i] = NULL;
+	}
+
+	//clean up any nodes left over in the old maps array
+	for(	; i < numberOfMaps && tempMap; i++)
+	{
+		tempMap[i]->VirtualDesktopTile()->DisplayNode(NULL);
+		tempMap[i]->PhysicalTile()->Source(NULL);
+
+	}
+
+	delete [] tempMap;
+	numberOfMaps = n;
+
+}
+
+
+VDTtoPTmapper** Display_Node::Maps(){ return maps; }
+
+bool Display_Node::AddMap(VDTtoPTmapper* pMap)
+{
+
+	for(int i = 0; i < numberOfMaps; i++)
+	{
+		if(maps[i] == NULL)
+		{
+			maps[i] = pMap;
+			maps[i]->VirtualDesktopTile()->DisplayNode(this);
+			maps[i]->PhysicalTile()->Source(this);
+			return true;
+
+		}
+
+	}
+
+	return false;
+}
+
+void Display_Node::RemoveMap(VDTtoPTmapper* vpMap)
+{
+	for(int i = 0; i < numberOfMaps; i++)
+	{
+		if(maps[i] && maps[i] == vpMap)
+		{
+			delete maps[i];
+			maps[i] = NULL;
+		}
+	}
+}
+
+void Display_Node::RemoveMap(int index)
+{
+	if(index < numberOfMaps && maps[index])
+	{
+		delete maps[index];
+		maps[index] = NULL;
+	}
+}
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+DisplayCluster::DisplayCluster():displayNodeListHead(NULL)
+{
+
+}
+
+DisplayCluster::~DisplayCluster()
+{
+
+}
+
+
+void DisplayCluster::AddDisplayNode(Display_Node* dn)
+{
+	Display_Node* temp = displayNodeListHead;
+	if(temp)
+	{
+		while(temp->Next())
+		{
+			temp = temp->Next();
+		}
+
+		temp->Next(dn);
+		dn->Next(NULL);
+	}
+	else
+	{
+		displayNodeListHead = dn;
+		dn->Next(NULL);
+
+	}
+
+}
+
+
+void DisplayCluster::RemoveDisplayNode(char* name)
+{
+
+}
+
+void DisplayCluster::RemoveDisplayNodeByName(char* name)
+{
+	RemoveDisplayNode(name);
+}
+
+
+void DisplayCluster::RemoveDisplayNodeByIP(char* ip)
+{
+
+}
+
+Display_Node* DisplayCluster::getFirstNode()
+{
+	return this->displayNodeListHead;
+}
+
+
+//Generate and insert a mapping between virtual tile and physical tile to a display node
+//Assuming the physical tile already knows the display node source
+bool DisplayCluster::GenerateMapping(Virtual_Desktop_Tile* vdt, Physical_Tile* pt)
+{
+	//make sure the physical tile is on the physical display associated with this display cluster
+	if(!pd->TileOnPhysicalDisplay(pt))
+		return false;
+
+
+	if(pt->Source() == NULL)
+		return false;		//the physical tile must already have a source
+
+	//make sure that the source node is on this display cluster
+	if(!NodeOnCluster(pt->Source()))
+		return false;
+
+	VDTtoPTmapper* map = new VDTtoPTmapper(pt,vdt);
+	if(pt->Source()->AddMap(map))
+		return true;
+
+	delete map;
+	return false;
+
+}
+
+PhysicalDisplay* DisplayCluster::PhysicalDisplayAssoc(){ return pd; }
+void DisplayCluster::PhysicalDisplayAssoc(PhysicalDisplay* tpd)
+{
+	pd = tpd;
+}
+
+//Generate and insert a mapping between virtual and physical tile using the given display node
+bool DisplayCluster::GenerateMapping(Virtual_Desktop_Tile* vdt, Physical_Tile *pt, Display_Node *dn)
+{
+	//make sure the physical tile is on the physical display associated with this display cluster
+	if(!pd->TileOnPhysicalDisplay(pt))
+		return false;
+
+	Display_Node *itr = displayNodeListHead;
+	//make sure the node is on this display cluster
+	if(!NodeOnCluster(dn))
+		return false;
+
+	VDTtoPTmapper* map = new VDTtoPTmapper(pt,vdt);
+	if(dn->AddMap(map))
+		return true;
+
+	delete map;
+	return false;
+
+}
+
+void DisplayCluster::RemoveMapping(Virtual_Desktop_Tile* vdt, Physical_Tile *pt, Display_Node* dn)
+{
+	if(!NodeOnCluster(dn))
+		return;
+
+	VDTtoPTmapper** maps = dn->Maps();
+	int count = dn->NumberOfMaps();
+
+	for(int i = 0; i < count; i++)
+	{
+		if(maps[i] && maps[i]->PhysicalTile() == pt && maps[i]->VirtualDesktopTile() == vdt)
+			dn->RemoveMap(i);
+	}
+
+}
+
+bool DisplayCluster::NodeOnCluster(Display_Node* dn)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		if(itr == dn)
+		{
+			return true;
+		}
+		itr = itr->Next();
+	}
+
+	return false;
+}
+
+void DisplayCluster::RemoveMapsWith(Virtual_Desktop_Tile* tvdt)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		VDTtoPTmapper** maps = itr->Maps();
+		int count = itr->NumberOfMaps();
+		for(	;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == tvdt)
+				itr->RemoveMap(count - 1);
+		}
+
+		itr = itr->Next();
+	}
+}
+
+void DisplayCluster::RemoveMapsWith(Physical_Tile* tpt)
+{
+	Display_Node* itr = displayNodeListHead;
+	while(itr)
+	{
+		VDTtoPTmapper** maps = itr->Maps();
+		int count = itr->NumberOfMaps();
+		for(	;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->PhysicalTile() == tpt)
+				itr->RemoveMap(count - 1);
+		}
+
+		itr = itr->Next();
+	}
+}
+
+VirtualDesktop* DisplayCluster::VirtualDesktopAssoc(){ return vd; }
+void DisplayCluster::VirtualDesktopAssoc(VirtualDesktop* tvd)
+{
+
+}
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+
+PhysicalDisplay::PhysicalDisplay():physicalTileListHead(NULL),vd(NULL),dc(NULL),
+pixelsPerInch(1.0)
+{
+
+
+}
+
+PhysicalDisplay::~PhysicalDisplay()
+{
+
+}
+
+void PhysicalDisplay::VirtualDesktopAssoc(VirtualDesktop *tvd)
+{
+	vd = tvd;
+}
+VirtualDesktop* PhysicalDisplay::VirtualDesktopAssoc(){ return vd; }
+
+int PhysicalDisplay::AddPhysicalTile(Physical_Tile* pt)
+{
+	int ID = 1;
+	if(physicalTileListHead == NULL)
+	{
+		physicalTileListHead = pt;
+	}
+	else
+	{
+		Physical_Tile *itr = physicalTileListHead;
+		while(itr->Next())
+		{
+			itr = itr->Next();
+			ID++;
+		}
+
+		itr->Next(pt);
+		pt->Next(NULL);
+	}
+
+	pt->ID(ID);
+	return ID;
+}
+
+Physical_Tile* PhysicalDisplay::RemovePhysicalTileByID(int ID, bool delquery)
+{
+
+	Physical_Tile *itr = physicalTileListHead;
+
+	if(itr->ID() == ID)
+	{
+		physicalTileListHead = itr->Next();
+
+	}
+	else
+	{
+		while(itr->Next())
+		{
+			//in order to take care of accidental redundant data, loop for each entry
+			if(itr->Next()->ID() == ID)
+			{
+				itr->Next(itr->Next()->Next());
+				if(dc)
+					dc->RemoveMapsWith(itr);
+
+			}
+		}
+	}
+
+	if(delquery)
+	{
+		delete itr;
+		return NULL;
+	}
+	else
+		return itr;
+
+
+}
+
+
+DisplayCluster* PhysicalDisplay::DisplayClusterAssoc()
+{ return dc; }
+
+void PhysicalDisplay::DisplayClusterAssoc(DisplayCluster* tdc)
+{
+	//go through the current display cluster and remove all the mappings that were made to the
+	//physical tiles associated with this display cluster
+	Physical_Tile* itr = physicalTileListHead;
+	while(itr)
+	{
+		if(dc)
+			dc->RemoveMapsWith(itr);
+		itr->Source(NULL);
+		itr = itr->Next();
+	}
+
+	dc = tdc;
+
+
+}
+
+bool PhysicalDisplay::TileOnPhysicalDisplay(Physical_Tile* pt)
+{
+	Physical_Tile* itr = physicalTileListHead;
+	while(itr)
+	{
+		if(itr == pt)
+			return true;
+
+		itr = itr->Next();
+	}
+
+	return false;
+}
+Physical_Tile* PhysicalDisplay::getFirstNode()
+{ return physicalTileListHead; }
+
+float PhysicalDisplay::PixelsPerInch(){ return pixelsPerInch; }
+void PhysicalDisplay::PixelsPerInch(float ratio)
+{ pixelsPerInch = ratio; }
+
+//----------------------------------------------------------
+//
+//
+//
+//
+//
+//-----------------------------------------------------------
+
+VirtualDesktop::VirtualDesktop():dc(NULL),pd(NULL),tileListHead(NULL),vertRes(1),horizRes(1)	//just 1 pixel by 1 pixel
+{
+}
+
+VirtualDesktop::~VirtualDesktop()
+{
+	Virtual_Desktop_Tile* itr = tileListHead;
+	while(itr)
+	{
+		if(dc)
+			dc->RemoveMapsWith(itr);
+		tileListHead = itr->Next();
+		delete itr;
+		itr = tileListHead;
+	}
+}
+
+DisplayCluster* VirtualDesktop::DisplayClusterAssoc(){ return dc; }
+void VirtualDesktop::DisplayClusterAssoc(DisplayCluster *tdc)
+{
+	dc = tdc;
+}
+
+PhysicalDisplay* VirtualDesktop::PhysicalDisplayAssoc(){ return pd; }
+void VirtualDesktop::PhysicalDisplayAssoc(PhysicalDisplay* tpd)
+{
+	pd = tpd;
+}
+
+void VirtualDesktop::AddTile(Virtual_Desktop_Tile* tvdt)
+{
+	//the tile has to be already mapped to a physical tile,
+	VDTtoPTmapper* mapping = NULL;
+	if(!dc)
+		return;
+
+	Display_Node* itr = dc->getFirstNode();
+
+	while(itr)
+	{
+		int count = itr->NumberOfMaps();
+		VDTtoPTmapper** maps = itr->Maps();
+		for( ;count > 0; count--)
+		{
+			if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == tvdt)
+			{
+				mapping = maps[count - 1];
+				itr = NULL;
+				break;
+			}
+		}
+
+		if(itr)
+			itr = itr->Next();
+	}
+
+	if(!mapping)
+		return;
+
+	//there is a mapping...continue
+
+
+	//put at end of list
+	Virtual_Desktop_Tile* vdtItr = tileListHead;
+	if(vdtItr == NULL)
+	{
+		tileListHead = tvdt;
+		tvdt->Next(NULL);
+		return;
+	}
+
+	while(vdtItr->Next())
+	{
+		vdtItr = vdtItr->Next();
+	}
+
+	vdtItr->Next(tvdt);
+	tvdt->Next(NULL);
+
+}
+
+void VirtualDesktop::RemoveTile(Virtual_Desktop_Tile* tvdt)
+{
+	Virtual_Desktop_Tile* itr = tileListHead;
+	while(itr)
+	{
+		if(itr == tvdt)
+		{
+			if(dc)
+			{
+				return dc->RemoveMapsWith(tvdt);
+			}
+		}
+		itr = itr->Next();
+	}
+
+}
+
+Virtual_Desktop_Tile* VirtualDesktop::getFirstNode(void)
+{
+	return tileListHead;
+}
+
+bool VirtualDesktop::Update()
+{
+	if(!pd)
+		return false;
+
+
+	float positiveHoriz, positiveVert, negativeHoriz, negativeVert;
+	positiveHoriz = positiveVert = negativeHoriz = negativeVert = 0.0;
+	float leftMullion, bottomMullion;
+	//need to determine the whole virtual desktop size
+	Physical_Tile* ptItr = pd->getFirstNode();
+	while(ptItr)
+	{
+		if(ptItr->LowerLeftX() < negativeHoriz)
+		{
+			negativeHoriz = ptItr->LowerLeftX();
+			leftMullion = ptItr->LeftMullionThickness();
+		}
+		else if(ptItr->LowerLeftX() + ptItr->ScreenWidthDimension() > positiveHoriz)
+		{
+			positiveHoriz = ptItr->LowerLeftX() + ptItr->ScreenWidthDimension();
+		}
+
+		if(ptItr->LowerLeftY() < negativeVert)
+		{
+			negativeVert = ptItr->LowerLeftY();
+			bottomMullion = ptItr->BottomMullionThickness();
+
+		}
+		else if(ptItr->LowerLeftY() + ptItr->ScreenHeightDimension() > positiveVert)
+		{
+			positiveVert = ptItr->LowerLeftY() + ptItr->ScreenHeightDimension();
+		}
+
+		ptItr = ptItr->Next();
+	}
+
+	//save off the resolutions.
+	horizRes = (int)((positiveHoriz - negativeHoriz) * (pd->PixelsPerInch()));
+	vertRes = (int)((positiveVert - negativeVert) * (pd->PixelsPerInch()));
+
+
+	//go through all the virtual tiles and adjust their properties based on their mapped physical tiles
+	Virtual_Desktop_Tile* vdtItr = tileListHead;
+	while(vdtItr)
+	{
+		VDTtoPTmapper* mapping;
+
+		mapping = NULL;
+		if(!dc)
+			return false;
+
+		Display_Node* itr = dc->getFirstNode();
+
+		while(itr)
+		{
+			int count = itr->NumberOfMaps();
+			VDTtoPTmapper** maps = itr->Maps();
+			for( ;count > 0; count--)
+			{
+				if(maps[count - 1] && maps[count - 1]->VirtualDesktopTile() == vdtItr)
+				{
+					mapping = maps[count - 1];
+					itr = NULL;
+					break;
+				}
+			}
+
+			if(itr)
+				itr = itr->Next();
+		}
+
+		//we have an unmapped virtual tile....doesn't make sense, stop and return false
+		if(!mapping)
+			return false;
+
+		//calculate the virtual tile properties
+		float posXRatio, posYRatio, widthRatio, heightRatio;
+		posXRatio = posYRatio = widthRatio = heightRatio = 0.0;
+		Physical_Tile* ptTemp = mapping->PhysicalTile();
+
+		vdtItr->LowerLeftPixelX( (ptTemp->LowerLeftX() + ptTemp->LeftMullionThickness())  * pd->PixelsPerInch() );
+		vdtItr->LowerLeftPixelY( (ptTemp->LowerLeftY() + ptTemp->BottomMullionThickness()) * pd->PixelsPerInch() );
+		vdtItr->LowerLeftX( (float)vdtItr->LowerLeftPixelX() / horizRes);
+		vdtItr->LowerLeftY( (float)vdtItr->LowerLeftPixelY() / vertRes);
+
+		vdtItr->WidthInPixels( ptTemp->ScreenWidthDimension() * pd->PixelsPerInch() );
+		vdtItr->HeightInPixels( ptTemp->ScreenHeightDimension() * pd->PixelsPerInch());
+		vdtItr->WidthRatio( (float)vdtItr->WidthInPixels() / horizRes);
+		vdtItr->HeightRatio( (float)vdtItr->HeightInPixels() / vertRes);
+
+		vdtItr->ID( ptTemp->ID());	//map the id of the virtual tile to the same id of the physical tile
+
+		//move on
+		vdtItr = vdtItr->Next();
+
+	}
+
+
+	return true;
+
+}
Index: trunk/src/testing/app/mframes/machinefile_code/file_parsers.h
===================================================================
--- trunk/src/testing/app/mframes/machinefile_code/file_parsers.h	(revision 4)
+++ trunk/src/testing/app/mframes/machinefile_code/file_parsers.h	(revision 4)
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*------------------------------------------------------------------------
+-	Author: Arun Rao
+-	Library: Tile Config
+-	Revision Date: 4/22/2004
+-	Module: file_parsers.h
+-	Purpose: Contains function prototypes for file i/o to load in
+-	and write out tiled display system descriptions
+---------------------------------------------------------------------------*/
+#ifndef TILE_CONFIG_FILE_PARSERS_H
+#define TILE_CONFIG_FILE_PARSERS_H
+
+#include "tile_config.h"
+
+//Standard File, I/O functions for tile_config library
+//----------------------------------------------------
+//Parameters
+// [in] filename	- name of the config file
+// [in, out] pd		- the returned physical display (send a pointer that isn't pointing to an actual physical display)
+// [in, out] dc		- the returned display cluster (send a pointer that isn't pointing to an actual display cluster)
+// [in, out] vd		- the returned virutal desktop (send a pointer that isn't pointing to an actual virtual desktop)
+
+#ifdef _cplusplus
+extern "C" {
+#endif
+
+int stdInputFileParser(char* filename,PhysicalDisplay*& pd,DisplayCluster*& dc,VirtualDesktop*& vd);
+void stdOutputFileWriter(char* filename,PhysicalDisplay* pd,DisplayCluster* dc,VirtualDesktop* vd);
+int corewallInputFileParser(char* filename, PhysicalDisplay*& pd, DisplayCluster*& dc, VirtualDesktop*& vd, int*& startPos);
+
+#ifdef _cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/testing/app/svc/include/SVC_decode_mpeg2.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_decode_mpeg2.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_decode_mpeg2.h	(revision 4)
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_DECODE_MPEG2_H
+#define SVC_DECODE_MPEG2_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include "SVC_codecs.h"
+extern "C"
+{
+#include "mpeg2dec/mpeg2.h"
+#include "mpeg2dec/mpeg2convert.h"
+}
+#include "SVC_output_module.h"
+//#include "SVC_decode_module.h"
+
+
+#define DEMUX_PAYLOAD_START 1
+#define DEMUX_HEADER 0
+#define DEMUX_DATA 1
+#define DEMUX_SKIP 2
+static int state = DEMUX_SKIP;
+static int state_bytes = 0;
+static uint8_t head_buf[264];
+static int buffer_size =  188;
+
+typedef struct {
+    int (* convert) (int stage, void * id,
+                     const struct mpeg2_sequence_s * sequence,
+                     int stride, uint32_t accel, void * arg,
+                     struct mpeg2_convert_init_s * result);
+} vo_setup_result_t;
+
+
+class SVC_decode_mpeg2
+{
+public:
+      SVC_decode_mpeg2();
+      void init(int program_id, int color_mode, int buf_size, char* output_addr, int output_port);
+      void set_output_callback(void* output_obj, DECODEOUTPUT_CALLBACK callback);
+      void decode (unsigned char* input_data, int input_size);
+      static void * malloc_hook (unsigned size, mpeg2_alloc_t reason);
+      void mpeg2_initialization();
+      void set_output_module(SVC_output_module* o_module);
+      void stop();
+      int demux (uint8_t * buf, uint8_t * end, int flags);
+      void decode_mpeg2 (uint8_t * current, uint8_t * end);
+      int output_setup (unsigned int width,
+                   unsigned int height, unsigned int chroma_width,
+                   unsigned int chroma_height);
+private:
+      int m_byte_pixel;
+      int demux_pid;
+      int demux_track;
+      int m_color_mode;
+      int total_offset;
+      mpeg2dec_t * mpeg2dec;
+      vo_setup_result_t m_convert_result;
+      DECODEOUTPUT_CALLBACK m_output_callback;
+      void * m_output_obj;
+      SVC_output_module * m_output_module;
+      char* m_output_addr;
+      int m_output_port;
+
+      //decoded image information
+      unsigned int m_width;
+      unsigned int m_height;
+      unsigned int m_chroma_width;
+      unsigned int m_chroma_height;
+      unsigned char * fbuf[3][3];
+
+      uint8_t * buffer;
+      uint8_t * buf;
+      uint8_t * nextbuf;
+      uint8_t * data;
+      uint8_t * end;
+};
+#endif
+
Index: trunk/src/testing/app/svc/include/SVC_input_1394.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_input_1394.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_input_1394.h	(revision 4)
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_INPUT_1394_H
+#define SVC_INPUT_1394_H
+
+#include <stdio.h>
+#include "libiec61883/iec61883.h"
+#include <sys/select.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "SVC_input_module.h"
+#include "SVC_output_module.h"
+#include "SVC_decode_mpeg2.h"
+#include "SVC_buffer_manager.h"
+
+typedef void (*CAPTURE_CALLBACK)(raw1394handle_t handle, void* obj, int channe);
+
+class SVC_input_1394 : public SVC_input_module
+{
+public:
+    SVC_input_1394();
+    void process();
+    void init(int codec, int color_mode, char* o_addr, int o_port);
+    static int write_frame_dv (unsigned char *data, int len, int complete, void *callback_data);
+    static int write_packet_mpeg2 (unsigned char *data, int len, unsigned int dropped, void *callback_data);
+    static void dv_receive( raw1394handle_t handle, void* obj, int channel);
+    static void mpeg2_receive (raw1394handle_t handle, void *obj, int channel);
+    int insert2buffer(unsigned char* data, int len);
+    static void* input_thread(void* obj);
+    void input_thread2();
+    void select_decoder(int codec);
+    int insert2buffer(unsigned char* data, long len);
+    void setOutput(SVC_output_module* output);
+    void stop();
+    void run();
+    void join();
+    void setBuffer(SVC_buffer*);
+    static void decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height);
+    SVC_decode_mpeg2* m_decode_mpeg2;
+    void set_imagesize(int width, int height);
+    void decode_ouput(uint8_t * const * buf);
+    int m_codec;
+    SVC_output_module* m_output_module;
+
+private:
+    raw1394handle_t handle;
+    CAPTURE_CALLBACK m_capture_callback;
+    pthread_t inputThreadID;
+    SVC_buffer* m_svc_buffer;
+    int m_byte_pixel;
+    int m_pid;
+    int m_color_mode;
+    int m_width;
+    int m_height;
+    char* m_output_addr;
+    int m_output_port;
+
+};
+
+
+#endif
Index: trunk/src/testing/app/svc/include/SVC_control.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_control.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_control.h	(revision 4)
@@ -0,0 +1,87 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_CONTROL_H
+#define SVC_CONTROL_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include "SVC_input_1394.h"
+#include "SVC_buffer_manager.h"
+#include "SVC_input_module.h"
+#include "SVC_output_module.h"
+#include "SVC_codecs.h"
+#include "SVC_common.h"
+#include "SVC_output_sail.h"
+#include "SVC_input_net.h"
+#include "SVC_input_null.h"
+#include "SVC_output_null.h"
+#include "SVC_output_net.h"
+
+//later will be included
+//#include "SVC_output_sidel.h"
+//#include "SVC_io_module.h"          //description of input, output module
+
+class SVC_control
+{
+public:
+	SVC_control();
+	int create_interface_module(int argc,char** argv);
+	int init(int argc, char** argv);
+        int create_session();
+	void run();
+	void print_usage(char ** argv);
+	static void sighandler (int sig);
+
+private:
+	SVC_input_module* m_input_module;
+	SVC_output_module* m_output_module;
+	SVC_buffer_manager* m_buffer_manager;
+	int m_codec;
+        int m_flag_rtp;
+        char* m_input_addr;
+        char* m_output_addr;
+	int m_input_port;
+	int m_output_port;
+	int flag_1394;
+	int flag_null;
+	int flag_net;
+	int m_color_mode;
+};
+
+#endif // SVC_CONTROL_H
Index: trunk/src/testing/app/svc/include/SVC_common.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_common.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_common.h	(revision 4)
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+extern int g_done_control;	//for signal capturing
Index: trunk/src/testing/app/svc/include/SVC_decode_module.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_decode_module.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_decode_module.h	(revision 4)
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+ifndef SVC_DECODE_MODULE_H
+#define SVC_DECODE_MODULE_H
+
+class SVC_decode_module
+{
+public:
+      SVC_decode_module();
+private:
+};
+#endif
+~
+~
+~
+~
+~
+~
+
Index: trunk/src/testing/app/svc/include/SVC_input_null.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_input_null.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_input_null.h	(revision 4)
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_INPUT_NULL_H
+#define SVC_INPUT_NULL_H
+
+#include "SVC_common.h"
+#include "SVC_input_module.h"
+#include "SVC_output_module.h"
+#include "SVC_decode_mpeg2.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+typedef void (*NETRECEIVE_CALLBACK)(void* obj);
+
+
+class SVC_input_null : public SVC_input_module
+{
+public:
+      SVC_input_null();
+      void setOutput(SVC_output_module *output_instance);
+      void init(int codec,int color_mode, int buffer_size, int rtp_flag, char* i_addr, int i_port, char* o_addr, int o_port);
+      static void decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height);
+      void run();
+      void select_decoder(int codec);
+      static void mpeg2_receive(void* obj);
+      static void dv_receive(void* obj);
+      void decode_ouput(uint8_t * const * buf);
+      void set_imagesize (int width, int height);
+      int get_input_port();
+      char* get_input_addr();
+      int get_buffer_size();
+      SVC_output_module* m_output_module;
+      int m_codec;
+
+
+private:
+      SVC_decode_mpeg2* m_decode_mpeg2;
+      NETRECEIVE_CALLBACK m_receive_callback;
+      int m_byte_pixel;
+      int m_pid;
+      int m_color_mode;
+      int m_width;
+      int m_height;
+      int m_input_port;
+      char* m_input_addr;
+      int m_output_port;
+      char* m_output_addr;
+      int m_buffer_size;
+
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_output_null.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_output_null.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_output_null.h	(revision 4)
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_OUTPUT_NULL_H
+#define SVC_OUTPUT_NULL_H
+
+#include "SVC_output_module.h"
+
+class SVC_output_null: public SVC_output_module
+{
+public:
+    SVC_output_null();
+    void init2();
+    void push_data(unsigned char* buf , int width, int height, int b_pixel);
+    unsigned char* init(int width, int height, int b_pixel,char* output_addr, int output_port);
+
+private:
+    int m_width;
+    int m_height;
+    int m_byte_pixel;
+    int m_color_mode;
+    int m_flag_done;
+    unsigned char* m_inter_buffer;
+    int m_flag_notinit;
+    char* m_output_addr;
+    int m_output_port;
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_codecs.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_codecs.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_codecs.h	(revision 4)
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_CODEC_H
+#define SVC_CODEC_H
+
+#include <inttypes.h>
+#include <stdio.h>
+/* Codec Define */
+#define DV        77
+#define MPEG2     78
+#define UNCOM     79
+
+/* Output Pixel Format Define */
+#define RGB16     90
+#define RGB24	  91
+#define RGB32	  92
+#define YUV	  93
+
+static int convert_format2pixelbyte(int color_mode)
+{
+	switch(color_mode)
+	{
+	 case RGB16:
+		return 2;
+	 case RGB24:
+		return 3;
+	 case RGB32:
+		return 4;
+	 case YUV:
+		return 2;
+	 default:
+		fprintf(stderr,"Incorrect color_mode in convert_format2pixelbyte()\n");
+	}
+}
+
+/* RTP Enable Option Define */
+#define RTP_ENABLE  100
+#define RTP_DISABLE 101
+
+/* Global Constant Define */
+#define VLC_SEND_BUFFER_SIZE		1316	/* MPEG2TS x 7*/
+#define STD_MPEG2TS_READ_BUFFER_SIZE	1316	/* MPEG2TS x 14*/
+#define SVC_MAX_INPUTNET_BUFFER_SIZE	3000
+#define CAPTURE1394_SEND_BUFFER_SIZE	188	/* MPEG2TS * 1 */
+#define RTP_HEADER_SIZE 		12
+#define MPEG2TS_PACKET_SIZE 		188
+#define SVC_INPUT_NET_PORT 		9090
+#define SVC_OUTPUT_NET_PORT 		9090
+#define DEFAULT_INPUT_ADDRESS		NULL
+#define DEFAULT_OUTPUT_ADDRESS		"127.0.0.1"
+/* Callback Function Define */
+typedef void (*DECODEOUTPUT_CALLBACK) (void* output_obj, uint8_t * const * buf, void * id, int width, int height);
+
+#endif
Index: trunk/src/testing/app/svc/include/unused/iec61883.h
===================================================================
--- trunk/src/testing/app/svc/include/unused/iec61883.h	(revision 4)
+++ trunk/src/testing/app/svc/include/unused/iec61883.h	(revision 4)
@@ -0,0 +1,1182 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * libiec61883/iec61883.h - Linux IEEE 1394 streaming media library.
+ * Copyright (C) 2004 Kristian Hogsberg, Dan Dennedy, and Dan Maas.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _IEC61883_H
+#define _IEC61883_H
+
+#include <libraw1394/raw1394.h>
+#include <endian.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum iec61883_datarate {
+    IEC61883_DATARATE_100 = 0,
+    IEC61883_DATARATE_200,
+    IEC61883_DATARATE_400
+};
+
+/*******************************************************************************
+ * Audio and Music Data Transport Protocol
+ **/
+
+enum iec61883_amdtp_format {
+	IEC61883_AMDTP_FORMAT_RAW,
+	IEC61883_AMDTP_FORMAT_IEC958_PCM,
+	IEC61883_AMDTP_FORMAT_IEC958_AC3
+};
+
+enum iec61883_cip_mode {
+	IEC61883_MODE_BLOCKING_EMPTY,
+	IEC61883_MODE_BLOCKING_NODATA,
+	IEC61883_MODE_NON_BLOCKING,
+};
+
+enum iec61883_amdtp_sample_format {
+	IEC61883_AMDTP_INPUT_NA = -1,
+	IEC61883_AMDTP_INPUT_LE16 = 0,
+	IEC61883_AMDTP_INPUT_BE16,
+	IEC61883_AMDTP_INPUT_LE20,
+	IEC61883_AMDTP_INPUT_BE20,
+	IEC61883_AMDTP_INPUT_LE24,
+	IEC61883_AMDTP_INPUT_BE24
+};
+
+#define IEC61883_FDF_SFC_32KHZ   0x00
+#define IEC61883_FDF_SFC_44K1HZ  0x01
+#define IEC61883_FDF_SFC_48KHZ   0x02
+#define IEC61883_FDF_SFC_88K2HZ  0x03
+#define IEC61883_FDF_SFC_96KHZ   0x04
+#define IEC61883_FDF_SFC_176K4HZ 0x05
+#define IEC61883_FDF_SFC_192KHZ  0x06
+
+typedef struct iec61883_amdtp* iec61883_amdtp_t;
+
+/**
+ * iec61883_amdtp_recv_t - AMDTP receive callback function prototype
+ * @data: pointer to the buffer containing audio data
+ * @nsamples: the number of samples in the buffer
+ * @dimension: the number of audio channels
+ * @rate: sampling frequency
+ * @format: one of enum iec61883_amdtp_format
+ * @sample_format: one of enum iec61883_amdtp_sample_format
+ * @callback_data: the opaque pointer you supplied in the init function
+ *
+ * The buffer contains consumer-ready 16bit raw PCM if it is in that format.
+ * Otherwise, the data consists of quadlets containing only one sample with
+ * any necessary padding minus the label if pcm, otherwise, for IEC958
+ * audio data, the header remains intact.
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ */
+typedef int
+(*iec61883_amdtp_recv_t) (iec61883_amdtp_t amdtp, char *data, int nsamples,
+	unsigned int dbc, unsigned int dropped, void *callback_data);
+
+typedef int
+(*iec61883_amdtp_xmit_t) (iec61883_amdtp_t amdtp, char *data, int nevents,
+	unsigned int dbc, unsigned int dropped, void *callback_data);
+
+/**
+ * iec61883_amdtp_xmit_init - setup transmission of AMDTP
+ * @handle: the libraw1394 handle to use for all operations
+ * @rate: one of enum iec61883_datarate
+ * @format: one of enum iec61883_amdtp_format to describe audio data format
+ * @sample_format: one of enum iec61883_amdtp_sample_format
+ * @mode: one of iec61883_cip_mode
+ * @dimension: the number of audio channels
+ * @get_data: a function pointer to your callback routine
+ * @callback_data: an opaque pointer to provide to your callback function
+ *
+ * AMDTP =  Audio and Music Data Transport Protocol
+ *
+ * Returns:
+ * A pointer to an iec61883_amdtp object upon success or NULL on failure.
+ **/
+iec61883_amdtp_t
+iec61883_amdtp_xmit_init(raw1394handle_t handle,
+		int rate, int format, int sample_format, int mode, int dimension,
+		iec61883_amdtp_xmit_t get_data, void *callback_data);
+
+/**
+ * iec61883_amdtp_recv_init - setup reception of AMDTP
+ * @handle: the libraw1394 handle to use for all operations
+ * @put_data: a function pointer to your callback routine
+ * @callback_data: an opaque pointer to provide to your callback function
+ *
+ * Returns:
+ * A pointer to an iec61883_amdtp object upon success or NULL on failure.
+ **/
+iec61883_amdtp_t
+iec61883_amdtp_recv_init(raw1394handle_t handle,
+		iec61883_amdtp_recv_t put_data, void *callback_data);
+
+/**
+ * iec61883_amdtp_xmit_start - start transmission of AMDTP
+ * @amdtp: pointer to iec61883_amdtp object
+ * @channel: the isochronous channel number to use
+ **/
+int
+iec61883_amdtp_xmit_start(iec61883_amdtp_t amdtp, int channel);
+
+/**
+ * iec61883_amdtp_xmit_stop - stop transmission of AMDTP
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+void
+iec61883_amdtp_xmit_stop(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_recv_start - start reception of AMDTP
+ * @amdtp: pointer to iec61883_amdtp object
+ * @channel: the isochronous channel number to use
+ **/
+int
+iec61883_amdtp_recv_start(iec61883_amdtp_t amdtp, int channel);
+
+/**
+ * iec61883_amdtp_recv_stop - stop reception of AMDTP
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+void
+iec61883_amdtp_recv_stop(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_close - destroy an amdtp object
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+void
+iec61883_amdtp_close(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_buffers - get the size of the buffer
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+unsigned int
+iec61883_amdtp_get_buffers(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_set_buffers - set the size of the buffer
+ * @amdtp: pointer to iec61883_amdtp object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_amdtp_set_buffers(iec61883_amdtp_t amdtp, unsigned int packets);
+
+/**
+ * iec61883_amdtp_get_prebuffers - get the size of the pre-transmission buffer
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+unsigned int
+iec61883_amdtp_get_prebuffers(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_set_prebuffers - set the size of the pre-transmission buffer
+ * @amdtp: pointer to iec61883_amdtp object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_amdtp_set_prebuffers(iec61883_amdtp_t amdtp, unsigned int packets);
+
+/**
+ * iec61883_amdtp_get_irq_interval - get the interrupt rate
+ * @amdtp: pointer to iec61883_amdtp object
+ **/
+unsigned int
+iec61883_amdtp_get_irq_interval(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_set_irq_interval - set the interrupt rate
+ * @amdtp: pointer to iec61883_amdtp object
+ * @packets: the size of the interval in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_amdtp_set_irq_interval(iec61883_amdtp_t amdtp, unsigned int packets);
+
+/**
+ * iec61883_amdtp_get_synch - get behavior on close
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+int
+iec61883_amdtp_get_synch(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_set_synch - set behavior on close
+ * @amdtp: pointer to iec61883_amdtp object
+ * @synch: 1 if you want sync behaviour, 0 otherwise
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+void
+iec61883_amdtp_set_synch(iec61883_amdtp_t amdtp, int synch);
+
+/**
+ * iec61883_amdtp_get_speed - get data rate for transmission
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * Returns:
+ * one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+int
+iec61883_amdtp_get_speed(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_set_speed - set data rate for transmission
+ * @amdtp: pointer to iec61883_amdtp object
+ * @speed: one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+void
+iec61883_amdtp_set_speed(iec61883_amdtp_t amdtp, int speed);
+
+/**
+ * iec61883_amdtp_get_dropped - get the total number of dropped packets
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * Returns:
+ * The total number of dropped packets since starting transmission or reception.
+ **/
+unsigned int
+iec61883_amdtp_get_dropped(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_callback_data - get the callback data you supplied
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * This function is useful in bus reset callback routines because only
+ * the libraw1394 handle is available, and libiec61883 uses the userdata
+ * field of the libraw1394 handle.
+ *
+ * Returns:
+ * An opaque pointer to whatever you supplied when you called init.
+ **/
+void *
+iec61883_amdtp_get_callback_data(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_dimension - get the AMDTP dimension
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * This function is useful in your callbacks.
+ *
+ * Returns:
+ * The numeric value of the current dimension.
+ **/
+int
+iec61883_amdtp_get_dimension(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_rate - get the AMDTP sampling frequency
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * This function is useful in your callbacks.
+ *
+ * Returns:
+ * The numeric value of the sampling frequency.
+ **/
+int
+iec61883_amdtp_get_rate(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_format - get the AMDTP data format
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * This function is useful in your callbacks.
+ *
+ * Returns:
+ * One of enum iec61883_amdtp_format.
+ **/
+enum iec61883_amdtp_format
+iec61883_amdtp_get_format(iec61883_amdtp_t amdtp);
+
+/**
+ * iec61883_amdtp_get_sample_format - get the AMDTP sample format
+ * @amdtp: pointer to iec61883_amdtp object
+ *
+ * This function is useful in your callbacks.
+ *
+ * Returns:
+ * One of enum iec61883_amdtp_sample_format.
+ **/
+enum iec61883_amdtp_sample_format
+iec61883_amdtp_get_sample_format(iec61883_amdtp_t amdtp);
+
+
+
+/*******************************************************************************
+ * DV Digital Video
+ **/
+
+typedef struct iec61883_dv* iec61883_dv_t;
+
+typedef int
+(*iec61883_dv_recv_t)(unsigned char *data, int len, unsigned int dropped,
+	void *callback_data);
+
+typedef int
+(*iec61883_dv_xmit_t)(unsigned char *data, int n_dif_blocks,
+	unsigned int dropped, void *callback_data);
+
+/**
+ * iec61883_dv_recv_init - setup reception of a DV stream
+ * @handle: the libraw1394 handle to use for all operations
+ * @put_data: a function pointer to your reception callback routine
+ * @callback_data: an opaque data pointer to provide to your callback function
+ *
+ * Returns:
+ * A pointer to an iec61883_dv object upon success or NULL on failure.
+ **/
+iec61883_dv_t
+iec61883_dv_recv_init(raw1394handle_t handle,
+		iec61883_dv_recv_t put_data,
+		void *callback_data);
+
+/**
+ * iec61883_dv_xmit_init - setup transmission of a DV stream
+ * @handle: the libraw1394 handle to use for all operations
+ * @is_pal: set to non-zero if transmitting a PAL stream (applies to transmission only)
+ * @get_data: a function pointer to your transmission callback routine
+ * @callback_data: an opaque data pointer to provide to your callback function
+ *
+ * Returns:
+ * A pointer to an iec61883_dv object upon success or NULL on failure.
+ **/
+iec61883_dv_t
+iec61883_dv_xmit_init(raw1394handle_t handle, int is_pal,
+		iec61883_dv_xmit_t get_data,
+		void *callback_data);
+
+/**
+ * iec61883_dv_recv_start - start receiving a DV stream
+ * @dv: pointer to iec61883_dv object
+ * @channel: the isochronous channel number
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ **/
+int
+iec61883_dv_recv_start(iec61883_dv_t dv, int channel);
+
+/**
+ * iec61883_dv_xmit_start - start transmitting a DV stream
+ * @dv: pointer to iec61883_dv object
+ * @channel: the isochronous channel number
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ **/
+int
+iec61883_dv_xmit_start(iec61883_dv_t dv, int channel);
+
+/**
+ * iec61883_dv_recv_stop - stop reception of a DV stream
+ * @dv: pointer to iec61883_dv ojbect
+ **/
+void
+iec61883_dv_recv_stop(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_xmit_stop - stop transmission of a DV stream
+ * @dv: pointer to iec61883_dv object
+ **/
+void
+iec61883_dv_xmit_stop(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_close - stop reception or transmission and destroy iec61883_dv object
+ * @dv: pointer to iec61883_dv object
+ **/
+void
+iec61883_dv_close(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_get_buffers - get the size of the buffer
+ * @dv: pointer to iec61883_dv object
+ **/
+unsigned int
+iec61883_dv_get_buffers(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_set_buffers - set the size of the buffer
+ * @dv: pointer to iec61883_dv object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_dv_set_buffers(iec61883_dv_t dv, unsigned int packets);
+
+/**
+ * iec61883_dv_get_prebuffers - get the size of the pre-transmission buffer
+ * @dv: pointer to iec61883_dv object
+ **/
+unsigned int
+iec61883_dv_get_prebuffers(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_set_prebuffers - set the size of the pre-transmission buffer
+ * @dv: pointer to iec61883_dv object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_dv_set_prebuffers(iec61883_dv_t dv, unsigned int packets);
+
+/**
+ * iec61883_dv_get_irq_interval - get the interrupt rate
+ * @dv: pointer to iec61883_dv object
+ **/
+unsigned int
+iec61883_dv_get_irq_interval(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_set_irq_interval - set the interrupt rate
+ * @dv: pointer to iec61883_dv object
+ * @packets: the size of the interval in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_dv_set_irq_interval(iec61883_dv_t dv, unsigned int packets);
+
+/**
+ * iec61883_dv_get_synch - get behavior on close
+ * @dv: pointer to iec61883_dv object
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+int
+iec61883_dv_get_synch(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_set_synch - set behavior on close
+ * @dv: pointer to iec61883_dv object
+ * @synch: 1 if you want sync behaviour, 0 otherwise
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+void
+iec61883_dv_set_synch(iec61883_dv_t dv, int synch);
+
+/**
+ * iec61883_dv_get_speed - get data rate for transmission
+ * @dv: pointer to iec61883_dv object
+ *
+ * Returns:
+ * one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+int
+iec61883_dv_get_speed(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_set_speed - set data rate for transmission
+ * @dv: pointer to iec61883_dv object
+ * @speed: one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+void
+iec61883_dv_set_speed(iec61883_dv_t dv, int speed);
+
+/**
+ * iec61883_dv_get_dropped - get the total number of dropped packets
+ * @dv: pointer to iec61883_dv object
+ *
+ * Returns:
+ * The total number of dropped packets since starting transmission or reception.
+ **/
+unsigned int
+iec61883_dv_get_dropped(iec61883_dv_t dv);
+
+/**
+ * iec61883_dv_get_callback_data - get the callback data you supplied
+ * @dv: pointer to iec61883_dv object
+ *
+ * This function is useful in bus reset callback routines because only
+ * the libraw1394 handle is available, and libiec61883 uses the userdata
+ * field of the libraw1394 handle.
+ *
+ * Returns:
+ * An opaque pointer to whatever you supplied when you called init.
+ **/
+void *
+iec61883_dv_get_callback_data(iec61883_dv_t dv);
+
+
+/*******************************************************************************
+ * The DV frame interface
+ **/
+
+typedef struct iec61883_dv_fb* iec61883_dv_fb_t;
+
+typedef int
+(*iec61883_dv_fb_recv_t)(unsigned char *data, int len, int complete,
+	void *callback_data);
+
+/**
+ * iec61883_dv_fb_init - setup reception of DV frames
+ * @handle: raw1394 handle.
+ * @put_data: your callback function.
+ * @callback_data: an opaque pointer you can send to your callback.
+ *
+ * This provides a frame-oriented instead of stream-oriented interface as
+ * compared to iec61883_dv_init(). This means that starts at the beginning of a
+ * frame, and all data is frame-aligned. Your callback function
+ * will receive a complete DV frame even if packets are dropped.
+ * The callback parameter @complete indicates if a full frame is received.
+ *
+ * Returns:
+ * A pointer to an iec61883_dv_fb object upon success or NULL on failure.
+ **/
+iec61883_dv_fb_t
+iec61883_dv_fb_init (raw1394handle_t handle,
+		iec61883_dv_fb_recv_t put_data,
+		void *callback_data);
+
+/**
+ * iec61883_dv_fb_start - start receiving DV frames
+ * @dvfb: pointer to iec61883_dv_fb object
+ * @channel: the isochronous channel number
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ **/
+int
+iec61883_dv_fb_start(iec61883_dv_fb_t dvfb, int channel);
+
+/**
+ * iec61883_dv_fb_stop - stop receiving DV frames
+ * @dvfb: pointer to iec61883_dv_fb object
+ **/
+void
+iec61883_dv_fb_stop(iec61883_dv_fb_t dvfb);
+
+/**
+ * iec61883_dv_fb_close - stop receiving DV frames and destroy iec61883_dv_fb object
+ * @dvfb: pointer to iec61883_dv_fb object
+ **/
+void
+iec61883_dv_fb_close(iec61883_dv_fb_t dvfb);
+
+/**
+ * iec61883_dv_fb_get_incomplete - get the total number of incomplete frames
+ * @dvfb: point to the iec61883_dv_fb object
+ *
+ * Returns:
+ * The total number of incomplete frames due to dropped packets since starting
+ * reception.
+ **/
+unsigned int
+iec61883_dv_fb_get_incomplete(iec61883_dv_fb_t dvfb);
+
+/**
+ * iec61883_dv_fb_get_callback_data - get the callback data you supplied
+ * @dvfb: pointer to iec61883_dv_fb object
+ *
+ * This function is useful in bus reset callback routines because only
+ * the libraw1394 handle is available, and libiec61883 uses the userdata
+ * field of the libraw1394 handle.
+ *
+ * Returns:
+ * An opaque pointer to whatever you supplied when you called init.
+ **/
+void *
+iec61883_dv_fb_get_callback_data(iec61883_dv_fb_t dvfb);
+
+
+/*******************************************************************************
+ * MPEG-2 Transport Stream
+ **/
+
+/* MPEG2 Time Shift Flag - not currently used anywhere */
+#define IEC61883_FDF_MPEG2_TSF 0x01
+
+/* size of a MPEG-2 Transport Stream packet */
+#define IEC61883_MPEG2_TSP_SIZE 188
+
+typedef struct iec61883_mpeg2* iec61883_mpeg2_t;
+
+typedef int
+(*iec61883_mpeg2_recv_t)(unsigned char *data, int len, unsigned int dropped,
+	void *callback_data);
+
+typedef int
+(*iec61883_mpeg2_xmit_t)(unsigned char *data, int n_packets,
+	unsigned int dropped, void *callback_data);
+
+/**
+ * iec61883_mpeg2_recv_init - setup reception of MPEG2-TS
+ * @handle: the libraw1394 handle to use for all operations
+ * @put_data: a function pointer to your callback routine
+ * @callback_data: an opaque pointer to provide to your callback function
+ *
+ * Returns:
+ * A pointer to an iec61883_mpeg2 object upon success or NULL for failure.
+ **/
+iec61883_mpeg2_t
+iec61883_mpeg2_recv_init(raw1394handle_t handle,
+		iec61883_mpeg2_recv_t put_data,
+		void *callback_data);
+
+/**
+ * iec61883_mpeg2_xmit_init - setup transmission of MPEG2-TS
+ * @handle: the libraw1394 handle to use for all operations
+ * @get_data: a function pointer to your callback routine
+ * @callback_data: an opaque pointer to provide to your callback function
+ *
+ * Returns:
+ * A pointer to an iec61883_mpeg2 object upon success or NULL for failure.
+ **/
+iec61883_mpeg2_t
+iec61883_mpeg2_xmit_init(raw1394handle_t handle,
+		iec61883_mpeg2_xmit_t get_data,
+		void *callback_data);
+
+/**
+ * iec61883_mpeg2_recv_start - start receiving MPEG2-TS
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @channel: isochronous channel number
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ **/
+int
+iec61883_mpeg2_recv_start(iec61883_mpeg2_t mpeg2, int channel);
+
+/**
+ * iec61883_mpeg2_xmit_start - start transmitting MPEG2-TS
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @pid: the program ID of the transport stream to select
+ * @channel: isochronous channel number
+ *
+ * Returns:
+ * 0 for success or -1 for failure
+ **/
+int
+iec61883_mpeg2_xmit_start(iec61883_mpeg2_t mpeg2, int pid, int channel);
+
+/**
+ * iec61883_mpeg2_recv_stop - stop receiving MPEG2-TS
+ * @mpeg2: pointer to the iec61883_mpeg2 object
+ **/
+void
+iec61883_mpeg2_recv_stop(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_xmit_stop - stop transmitting MPEG2-TS
+ * @mpeg2: pointer to the iec61883_mpeg2 object
+ **/
+void
+iec61883_mpeg2_xmit_stop(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_close - stop receiving or transmitting and destroy iec61883_mpeg2 object
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ **/
+void
+iec61883_mpeg2_close(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_get_buffers - get the size of the raw1394 buffer
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ **/
+unsigned int
+iec61883_mpeg2_get_buffers(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_set_buffers - set the size of the raw1394 buffer
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_mpeg2_set_buffers(iec61883_mpeg2_t mpeg2, unsigned int packets);
+
+/**
+ * iec61883_mpeg2_get_prebuffers - get the size of the pre-transmission buffer
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ **/
+unsigned int
+iec61883_mpeg2_get_prebuffers(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_set_prebuffers - set the size of the pre-transmission buffer
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @packets: the size of the buffer in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_mpeg2_set_prebuffers(iec61883_mpeg2_t mpeg2, unsigned int packets);
+
+/**
+ * iec61883_mpeg2_get_irq_interval - get the interrupt rate
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ **/
+unsigned int
+iec61883_mpeg2_get_irq_interval(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_set_irq_interval - set the interrupt rate
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @packets: the size of the interval in packets
+ *
+ * This is an advanced option that can only be set after initialization and
+ * before reception or transmission.
+ **/
+void
+iec61883_mpeg2_set_irq_interval(iec61883_mpeg2_t mpeg2, unsigned int packets);
+
+/**
+ * iec61883_mpeg2_get_synch - get behavior on close
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+int
+iec61883_mpeg2_get_synch(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_set_synch - set behavior on close
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ * @synch: 1 if you want sync behaviour, 0 otherwise
+ *
+ * If synch is not zero, then when stopping reception all packets in
+ * raw1394 buffers are flushed and invoking your callback function and when
+ * stopping transmission all packets in the raw1394 buffers are sent before
+ * the close function returns.
+ **/
+void
+iec61883_mpeg2_set_synch(iec61883_mpeg2_t mpeg2, int synch);
+
+/**
+ * iec61883_mpeg2_get_speed - get data rate for transmission
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ *
+ * Returns:
+ * one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+int
+iec61883_mpeg2_get_speed(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_set_speed - set data rate for transmission
+ * @mpeg2: pointer to iec61883_mepg2 object
+ * @speed: one of enum raw1394_iso_speed (S100, S200, or S400)
+ **/
+void
+iec61883_mpeg2_set_speed(iec61883_mpeg2_t mpeg2, int speed);
+
+/**
+ * iec61883_mpeg2_get_dropped - get the total number of dropped packets
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ *
+ * Returns:
+ * The total number of dropped packets since starting transmission or reception.
+ **/
+unsigned int
+iec61883_mpeg2_get_dropped(iec61883_mpeg2_t mpeg2);
+
+/**
+ * iec61883_mpeg2_get_callback_data - get the callback data you supplied
+ * @mpeg2: pointer to iec61883_mpeg2 object
+ *
+ * This function is useful in bus reset callback routines because only
+ * the libraw1394 handle is available, and libiec61883 uses the userdata
+ * field of the libraw1394 handle.
+ *
+ * Returns:
+ * An opaque pointer to whatever you supplied when you called init.
+ **/
+void *
+iec61883_mpeg2_get_callback_data(iec61883_mpeg2_t mpeg2);
+
+
+/*******************************************************************************
+ * Connection Management Procedures
+ **/
+
+enum iec61883_pcr_overhead_id {
+	IEC61883_OVERHEAD_512 = 0,
+	IEC61883_OVERHEAD_32,
+	IEC61883_OVERHEAD_64,
+	IEC61883_OVERHEAD_96,
+	IEC61883_OVERHEAD_128,
+	IEC61883_OVERHEAD_160,
+	IEC61883_OVERHEAD_192,
+	IEC61883_OVERHEAD_224,
+	IEC61883_OVERHEAD_256,
+	IEC61883_OVERHEAD_288,
+	IEC61883_OVERHEAD_320,
+	IEC61883_OVERHEAD_352,
+	IEC61883_OVERHEAD_384,
+	IEC61883_OVERHEAD_416,
+	IEC61883_OVERHEAD_448,
+	IEC61883_OVERHEAD_480
+};
+
+/**
+ * iec61883_cmp_calc_bandwidth - calculate bandwidth allocation units
+ * @handle: a libraw1394 handle
+ * @output: the node id of the transmitter
+ * @plug: the index of the output plug
+ * @speed: if >= 0 then override the data rate factor
+ *
+ * Uses parameters of the output plug control register of the transmitter to
+ * calculate what its bandwidth requirements are. Parameters inlude payload,
+ * overhead_id, and data rate (optionally @speed).
+ *
+ * Returns:
+ * bandwidth allocation units or -1 on failure
+ **/
+int
+iec61883_cmp_calc_bandwidth (raw1394handle_t handle, nodeid_t output, int plug,
+	int speed);
+
+/**
+ * iec61883_cmp_connect - establish or overlay connection automatically
+ * @handle: a libraw1394 handle
+ * @output: node id of the transmitter
+ * @oplug: the output plug to use. If -1, find the first online plug, and
+ * upon return, contains the plug number used.
+ * @input: node id of the receiver
+ * @iplug: the input plug to use. If -1, find the first online plug, and
+ * upon return, contains the plug number used.
+ * @bandwidth: an input/output parameter. As an input this is a boolean that
+ * indicates whether to perform bandwidth allocation. Supply 0 to skip bandwidth
+ * allocation; any other value permits it. Upon return, actual bandwidth allocation
+ * units allocated are returned, which you supply to the disconnect routine.
+ *
+ * This is a high level function that attempts to be as smart as possible, but
+ * it gives point-to-point connections higher priority over broadcast connections.
+ * It can automatically handle situations where either @input and/or @output does
+ * not implement plug control registers. However, if one node implements plug
+ * registers it assumes the other node has some sort of manual channel selection
+ * (i.e., through software or a control panel).
+ *
+ * Returns:
+ * It returns the isochronous channel number selected or -1 if the function has
+ * failed for any reason.
+ **/
+int
+iec61883_cmp_connect (raw1394handle_t handle, nodeid_t output, int *oplug,
+	nodeid_t input, int *iplug, int *bandwidth);
+
+/**
+ * iec61883_cmp_reconnect - reestablish or overlay connection after a bus reset
+ * @handle: a libraw1394 handle
+ * @output: node id of the transmitter
+ * @oplug: the output plug to use. If -1, find the first online plug, and
+ * upon return, contains the plug number used.
+ * @input: node id of the receiver
+ * @iplug: the input plug to use. If -1, find the first online plug, and
+ * upon return, contains the plug number used.
+ * @bandwidth: an input/output parameter. As an input this is a boolean that
+ * indicates whether to perform bandwidth allocation. Supply 0 to skip bandwidth
+ * allocation; any other value permits it. Upon return, actual bandwidth allocation
+ * units allocated are returned, which you supply to the disconnect routine.
+ * @channel: the channel number on which to reconnect, if possible
+ *
+ * This is a high level function that attempts to be as smart as possible, but
+ * it gives point-to-point connections higher priority over broadcast connections.
+ * It can automatically handle situations where either @input and/or @output does
+ * not implement plug control registers. However, if one node implements plug
+ * registers it assumes the other node has some sort of manual channel selection
+ * (i.e., through software or a control panel).
+ *
+ * This function is useful in bus reset situations where it would be nice to
+ * reconfigure the transmission or reception if the channel does not need to
+ * change.
+ *
+ * Returns:
+ * It returns the isochronous channel number selected or -1 if the function has
+ * failed for any reason.
+ **/
+int
+iec61883_cmp_reconnect (raw1394handle_t handle, nodeid_t output, int *oplug,
+	nodeid_t input, int *iplug, int *bandwidth, int channel);
+
+/**
+ * iec61883_cmp_disconnect - break connection automatically
+ * @handle: a libraw1394 handle
+ * @output: node id of the transmitter
+ * @oplug: the output plug to use, or -1 to find the first online plug.
+ * @input: node id of the receiver
+ * @iplug: the input plug to use, or -1 to find the first online plug.
+ * @channel: the isochronous channel in use
+ * @bandwidth: the number of bandwidth allocation units to release when needed
+ *
+ * This high level connection management function automatically locates the
+ * appropriate plug on @output and @input based upon the channel number. It
+ * gracefully handles when node plugs exist on @output and/or @input. When there
+ * are no more point-to-point connections on output plug, then the channel and
+ * bandwidth are released.
+ *
+ * Returns:
+ * 0 on success or -1 on failure
+ **/
+int
+iec61883_cmp_disconnect (raw1394handle_t handle, nodeid_t output, int oplug,
+	nodeid_t input, int iplug, unsigned int channel, unsigned int bandwidth);
+
+/**
+ * iec61883_cmp_normalize_output - make IRM channels available consistent with plug
+ * @handle: a libraw1394 handle
+ * @node: node id of the transmitter
+ *
+ * Loops over every output plug on the node, and if it has a point-to-point or
+ * broadcast connection, then make sure the channel is allocated with the
+ * isochronous resource manager. This is used to help provide bus sanity and prevent
+ * a channel from being used on a subsequent connection that might really already be
+ * in usage!
+ *
+ * Returns:
+ * 0 on success or -1 ojn failure
+ **/
+int
+iec61883_cmp_normalize_output (raw1394handle_t handle, nodeid_t node);
+
+/*
+ * The following CMP functions are lower level routines used by the above
+ * connection procedures exposed here in case the above procedures do not fit
+ * your use cases.
+ */
+int
+iec61883_cmp_create_p2p (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	nodeid_t input_node, int input_plug,
+	unsigned int channel, unsigned int speed);
+
+int
+iec61883_cmp_create_p2p_output (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	unsigned int channel, unsigned int speed);
+
+int
+iec61883_cmp_create_p2p_input (raw1394handle_t handle,
+	nodeid_t input_node, int input_plug,
+	unsigned int channel);
+
+int
+iec61883_cmp_create_bcast (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	nodeid_t input_node, int input_plug,
+	unsigned int channel, unsigned int speed);
+
+int
+iec61883_cmp_create_bcast_output (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	unsigned int channel, unsigned int speed);
+
+int
+iec61883_cmp_create_bcast_input (raw1394handle_t handle,
+	nodeid_t input_node, int input_plug,
+	unsigned int channel);
+
+int
+iec61883_cmp_overlay_p2p (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	nodeid_t input_node, int input_plug);
+
+int
+iec61883_cmp_overlay_p2p_output (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug);
+
+int
+iec61883_cmp_overlay_p2p_input (raw1394handle_t handle,
+	nodeid_t input_node, int input_plug);
+
+int
+iec61883_cmp_overlay_bcast (raw1394handle_t handle,
+	nodeid_t output_node, int output_plug,
+	nodeid_t input_node, int input_plug);
+
+/**
+ * iec61883_plug_impr_init - Initialise hosting of local input plug registers.
+ * @h: A raw1394 handle.
+ * @data_rate: an enum iec61883_datarate
+ *
+ * Initially, no plugs are available; call iec61883_plug_add_ipcr() to add
+ * plugs.
+ *
+ * Returns:
+ * 0 for success, -EINVAL if data_rate is invalid, or or -1 (errno) on
+ * libraw1394 failure.
+ **/
+int
+iec61883_plug_impr_init (raw1394handle_t h, unsigned int data_rate);
+
+/**
+ * ice61883_plug_impr_clear - Set the number of input plugs to zero.
+ * @h: A raw1394 handle.
+ **/
+void
+iec61883_plug_impr_clear (raw1394handle_t h);
+
+/**
+ * iec61883_plug_impr_close - Stop hosting local input plugs.
+ * @h: A raw1394 handle.
+ *
+ * Returns:
+ * 0 for success, -1 (errno) on error.
+ **/
+int
+iec61883_plug_impr_close (raw1394handle_t h);
+
+/**
+ * iec61883_plug_add_ipcr - Add a local input plug.
+ * @h: A raw1394 handle.
+ * @online: The initial state of the plug: online (1) or not (0).
+ *
+ * You must call iec61883_plug_impr_init() before this.
+ *
+ * Returns:
+ * plug number (>=0) on sucess or -EINVAL if online is not 0 or 1,
+ * -ENOSPC if maximum plugs reached, or -EPERM if iec61883_plug_impr_init()
+ * not called.
+ **/
+int
+iec61883_plug_ipcr_add (raw1394handle_t h, unsigned int online);
+
+/**
+ * iec61883_plug_ompr_init - Initialise hosting of local output plug registers.
+ * @h: A raw1394 handle
+ * @data_rate: one of enum iec61883_datarate
+ * @bcast_channel: the broacast channel base (0 - 63)
+ *
+ * Initially, no plugs are available; call iec61883_plug_add_opcr() to add
+ * plugs.
+ *
+ * Returns:
+ * 0 for success, -EINVAL if data_rate or bcast_channel is invalid,
+ * or or -1 (errno) on libraw1394 failure.
+ **/
+int
+iec61883_plug_ompr_init (raw1394handle_t h, unsigned int data_rate,
+	unsigned int bcast_channel);
+
+/**
+ * ice61883_plug_ompr_clear - Set the number of output plugs to zero.
+ * @h: A raw1394 handle.
+ **/
+void
+iec61883_plug_ompr_clear (raw1394handle_t h);
+
+/**
+ * iec61883_plug_ompr_close - Stop hosting local output plugs.
+ * @h: A raw1394 handle.
+ *
+ * Returns:
+ * 0 for success, -1 (errno) on error.
+ **/
+int
+iec61883_plug_ompr_close (raw1394handle_t h);
+
+/**
+ * iec61883_plug_add_opcr - Add a local output plug.
+ * @h: A raw1394 handle.
+ * @online: The initial state of the plug: online (1) or not (0).
+ * @overhead_id: one of enum iec61883_pcr_overhead_id.
+ * @payload: the maximum number of quadlets per packet.
+ *
+ * You must call iec61883_plug_ompr_init() before this.
+ *
+ * Returns:
+ * plug number (>=0) on sucess, -EINVAL if online is not 0 or 1 or
+ * if overhead_id or payload are out of range, -ENOSPC if maximum plugs
+ * reached, or -EPERM if iec61883_plug_ompr_init() not called.
+ **/
+int
+iec61883_plug_opcr_add (raw1394handle_t h, unsigned int online,
+	unsigned int overhead_id, unsigned int payload);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IEC61883_H */
Index: trunk/src/testing/app/svc/include/unused/mpeg2.h
===================================================================
--- trunk/src/testing/app/svc/include/unused/mpeg2.h	(revision 4)
+++ trunk/src/testing/app/svc/include/unused/mpeg2.h	(revision 4)
@@ -0,0 +1,232 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * mpeg2.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MPEG2_H
+#define MPEG2_H
+
+#define MPEG2_VERSION(a,b,c) (((a)<<16)|((b)<<8)|(c))
+#define MPEG2_RELEASE MPEG2_VERSION (0, 4, 0)	/* 0.4.0 */
+
+#define SEQ_FLAG_MPEG2 1
+#define SEQ_FLAG_CONSTRAINED_PARAMETERS 2
+#define SEQ_FLAG_PROGRESSIVE_SEQUENCE 4
+#define SEQ_FLAG_LOW_DELAY 8
+#define SEQ_FLAG_COLOUR_DESCRIPTION 16
+
+#define SEQ_MASK_VIDEO_FORMAT 0xe0
+#define SEQ_VIDEO_FORMAT_COMPONENT 0
+#define SEQ_VIDEO_FORMAT_PAL 0x20
+#define SEQ_VIDEO_FORMAT_NTSC 0x40
+#define SEQ_VIDEO_FORMAT_SECAM 0x60
+#define SEQ_VIDEO_FORMAT_MAC 0x80
+#define SEQ_VIDEO_FORMAT_UNSPECIFIED 0xa0
+
+typedef struct mpeg2_sequence_s {
+    unsigned int width, height;
+    unsigned int chroma_width, chroma_height;
+    unsigned int byte_rate;
+    unsigned int vbv_buffer_size;
+    uint32_t flags;
+
+    unsigned int picture_width, picture_height;
+    unsigned int display_width, display_height;
+    unsigned int pixel_width, pixel_height;
+    unsigned int frame_period;
+
+    uint8_t profile_level_id;
+    uint8_t colour_primaries;
+    uint8_t transfer_characteristics;
+    uint8_t matrix_coefficients;
+} mpeg2_sequence_t;
+
+#define GOP_FLAG_DROP_FRAME 1
+#define GOP_FLAG_BROKEN_LINK 2
+#define GOP_FLAG_CLOSED_GOP 4
+
+typedef struct mpeg2_gop_s {
+    uint8_t hours;
+    uint8_t minutes;
+    uint8_t seconds;
+    uint8_t pictures;
+    uint32_t flags;
+} mpeg2_gop_t;
+
+#define PIC_MASK_CODING_TYPE 7
+#define PIC_FLAG_CODING_TYPE_I 1
+#define PIC_FLAG_CODING_TYPE_P 2
+#define PIC_FLAG_CODING_TYPE_B 3
+#define PIC_FLAG_CODING_TYPE_D 4
+
+#define PIC_FLAG_TOP_FIELD_FIRST 8
+#define PIC_FLAG_PROGRESSIVE_FRAME 16
+#define PIC_FLAG_COMPOSITE_DISPLAY 32
+#define PIC_FLAG_SKIP 64
+#define PIC_FLAG_TAGS 128
+#define PIC_MASK_COMPOSITE_DISPLAY 0xfffff000
+
+typedef struct mpeg2_picture_s {
+    unsigned int temporal_reference;
+    unsigned int nb_fields;
+    uint32_t tag, tag2;
+    uint32_t flags;
+    struct {
+	int x, y;
+    } display_offset[3];
+} mpeg2_picture_t;
+
+typedef struct mpeg2_fbuf_s {
+    uint8_t * buf[3];
+    void * id;
+} mpeg2_fbuf_t;
+
+typedef struct mpeg2_info_s {
+    const mpeg2_sequence_t * sequence;
+    const mpeg2_gop_t * gop;
+    const mpeg2_picture_t * current_picture;
+    const mpeg2_picture_t * current_picture_2nd;
+    const mpeg2_fbuf_t * current_fbuf;
+    const mpeg2_picture_t * display_picture;
+    const mpeg2_picture_t * display_picture_2nd;
+    const mpeg2_fbuf_t * display_fbuf;
+    const mpeg2_fbuf_t * discard_fbuf;
+    const uint8_t * user_data;
+    unsigned int user_data_len;
+} mpeg2_info_t;
+
+typedef struct mpeg2dec_s mpeg2dec_t;
+typedef struct mpeg2_decoder_s mpeg2_decoder_t;
+
+typedef enum {
+    STATE_BUFFER = 0,
+    STATE_SEQUENCE = 1,
+    STATE_SEQUENCE_REPEATED = 2,
+    STATE_GOP = 3,
+    STATE_PICTURE = 4,
+    STATE_SLICE_1ST = 5,
+    STATE_PICTURE_2ND = 6,
+    STATE_SLICE = 7,
+    STATE_END = 8,
+    STATE_INVALID = 9,
+    STATE_INVALID_END = 10
+} mpeg2_state_t;
+
+typedef struct mpeg2_convert_init_s {
+    unsigned int id_size;
+    unsigned int buf_size[3];
+    void (* start) (void * id, const mpeg2_fbuf_t * fbuf,
+		    const mpeg2_picture_t * picture, const mpeg2_gop_t * gop);
+    void (* copy) (void * id, uint8_t * const * src, unsigned int v_offset);
+} mpeg2_convert_init_t;
+typedef enum {
+    MPEG2_CONVERT_SET = 0,
+    MPEG2_CONVERT_STRIDE = 1,
+    MPEG2_CONVERT_START = 2
+} mpeg2_convert_stage_t;
+typedef int mpeg2_convert_t (int stage, void * id,
+			     const mpeg2_sequence_t * sequence, int stride,
+			     uint32_t accel, void * arg,
+			     mpeg2_convert_init_t * result);
+int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg);
+int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride);
+void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id);
+void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf);
+
+#define MPEG2_ACCEL_X86_MMX 1
+#define MPEG2_ACCEL_X86_3DNOW 2
+#define MPEG2_ACCEL_X86_MMXEXT 4
+#define MPEG2_ACCEL_PPC_ALTIVEC 1
+#define MPEG2_ACCEL_ALPHA 1
+#define MPEG2_ACCEL_ALPHA_MVI 2
+#define MPEG2_ACCEL_SPARC_VIS 1
+#define MPEG2_ACCEL_SPARC_VIS2 2
+#define MPEG2_ACCEL_DETECT 0x80000000
+
+uint32_t mpeg2_accel (uint32_t accel);
+mpeg2dec_t * mpeg2_init (void);
+const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec);
+void mpeg2_close (mpeg2dec_t * mpeg2dec);
+
+void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end);
+int mpeg2_getpos (mpeg2dec_t * mpeg2dec);
+mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec);
+
+void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset);
+void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip);
+void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end);
+
+void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2);
+
+void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, uint8_t * current_fbuf[3],
+		      uint8_t * forward_fbuf[3], uint8_t * backward_fbuf[3]);
+void mpeg2_slice (mpeg2_decoder_t * decoder, int code, const uint8_t * buffer);
+
+typedef enum {
+    MPEG2_ALLOC_MPEG2DEC = 0,
+    MPEG2_ALLOC_CHUNK = 1,
+    MPEG2_ALLOC_YUV = 2,
+    MPEG2_ALLOC_CONVERT_ID = 3,
+    MPEG2_ALLOC_CONVERTED = 4
+} mpeg2_alloc_t;
+
+void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason);
+void mpeg2_free (void * buf);
+void mpeg2_malloc_hooks (void * malloc (unsigned, mpeg2_alloc_t),
+			 int free (void *));
+
+#endif /* MPEG2_H */
Index: trunk/src/testing/app/svc/include/unused/mpeg2convert.h
===================================================================
--- trunk/src/testing/app/svc/include/unused/mpeg2convert.h	(revision 4)
+++ trunk/src/testing/app/svc/include/unused/mpeg2convert.h	(revision 4)
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * mpeg2convert.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MPEG2CONVERT_H
+#define MPEG2CONVERT_H
+
+mpeg2_convert_t mpeg2convert_rgb32;
+mpeg2_convert_t mpeg2convert_rgb24;
+mpeg2_convert_t mpeg2convert_rgb16;
+mpeg2_convert_t mpeg2convert_rgb15;
+mpeg2_convert_t mpeg2convert_rgb8;
+mpeg2_convert_t mpeg2convert_bgr32;
+mpeg2_convert_t mpeg2convert_bgr24;
+mpeg2_convert_t mpeg2convert_bgr16;
+mpeg2_convert_t mpeg2convert_bgr15;
+mpeg2_convert_t mpeg2convert_bgr8;
+
+typedef enum {
+    MPEG2CONVERT_RGB = 0,
+    MPEG2CONVERT_BGR = 1
+} mpeg2convert_rgb_order_t;
+
+mpeg2_convert_t * mpeg2convert_rgb (mpeg2convert_rgb_order_t order,
+				    unsigned int bpp);
+
+mpeg2_convert_t mpeg2convert_uyvy;
+
+#endif /* MPEG2CONVERT_H */
Index: trunk/src/testing/app/svc/include/SVC_buffer_manager.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_buffer_manager.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_buffer_manager.h	(revision 4)
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_BUFFER_MANAGER_H
+#define SVC_BUFFER_MANAGER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#define RAWDATA_BUFFER_LENGTH 60
+
+
+
+class SVC_buffer
+{
+public:
+	SVC_buffer();
+	int init(int width, int height, int byte_pixel);
+	void put_data(unsigned char* data, long size);
+	unsigned char* pop_data();
+	int pop_data(unsigned char* output_buffer);
+	void print_current_buflen();
+	int isnotinit();
+	int get_width(){ return m_width;};
+	int get_height(){ return m_height;}
+	int get_byte_pixel(){return m_byte_pixel;}
+
+
+private:
+	unsigned char **m_buffer_list;
+	int m_width;
+	int m_height;
+	int m_byte_pixel;
+	int m_buf_front;
+	int m_buf_rear;
+	int m_first_flag;
+	pthread_mutex_t m_put_lock;
+	pthread_mutex_t m_pop_lock;
+	pthread_cond_t m_cond;
+};
+
+
+class SVC_buffer_manager
+{
+public:
+	SVC_buffer_manager();
+	SVC_buffer* create_buffer_instance();
+
+private:
+	SVC_buffer** m_svc_buffer_list;
+};
+
+
+#endif
Index: trunk/src/testing/app/svc/include/SVC_input_module.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_input_module.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_input_module.h	(revision 4)
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_INPUT_MODULE_H
+#define SVC_INPUT_MODULE_H
+
+#include "SVC_buffer_manager.h"
+#include "SVC_common.h"
+#include "SVC_output_module.h"
+#include "SVC_codecs.h"
+
+class SVC_input_module
+{
+public:
+      SVC_input_module();
+//    virtual void setBuffer(SVC_buffer *buffer_instance) {return;}
+      virtual void setOutput(SVC_output_module *output_instance) {return;}
+      virtual void init(int codec,int color_mode,char* o_addr, int o_port ){return;}
+      virtual void init(int codec,int color_mode, int buffer_size, int rtp_flag, char* i_addr, int i_port, char* o_addr, int o_port){return;}	//for SVC_input_net
+      virtual void run(){return;}
+      virtual void join(){return ;}
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_input_net.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_input_net.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_input_net.h	(revision 4)
@@ -0,0 +1,90 @@
+
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#ifndef SVC_INPUT_NET_H
+#define SVC_INPUT_NET_H
+
+#include "SVC_common.h"
+#include "SVC_input_module.h"
+#include "SVC_output_module.h"
+#include "SVC_decode_mpeg2.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+typedef void (*NETRECEIVE_CALLBACK)(void* obj);
+
+
+class SVC_input_net : public SVC_input_module
+{
+public:
+      SVC_input_net();
+      void setOutput(SVC_output_module *output_instance);
+      void init(int codec,int color_mode, int buffer_size, int rtp_flag, char* i_addr, int i_port, char* o_addr, int o_port);
+      static void decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height);
+      void run();
+      void select_decoder(int codec);
+      static void mpeg2_receive(void* obj);
+      static void dv_receive(void* obj);
+      void decode_ouput(uint8_t * const * buf);
+      void set_imagesize (int width, int height);
+      int get_input_port();
+      char* get_input_addr();
+      int get_buffer_size();
+      SVC_output_module* m_output_module;
+      int m_codec;
+      int is_multicast_addr(char* m_input_addr);
+
+
+private:
+      SVC_decode_mpeg2* m_decode_mpeg2;
+      NETRECEIVE_CALLBACK m_receive_callback;
+      int m_byte_pixel;
+      int m_pid;
+      int m_color_mode;
+      int m_width;
+      int m_height;
+      int m_input_port;
+      char* m_input_addr;
+      int m_output_port;
+      char* m_output_addr;
+      int m_buffer_size;
+
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_output_module.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_output_module.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_output_module.h	(revision 4)
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#ifndef SVC_OUTPUT_MODULE_H
+#define SVC_OUTPUT_MODULE_H
+
+#include "SVC_buffer_manager.h"
+#include "SVC_common.h"
+#include "SVC_codecs.h"
+
+class SVC_output_module
+{
+public:
+    SVC_output_module();
+    virtual void run(){return;}
+    virtual void stop(){return;}
+    virtual void setBuffer(SVC_buffer *buffer_instance) {return;}
+    virtual unsigned char* init(int width, int height, int b_depth,char* addr, int port) {return NULL;}
+    virtual void init(){return;}
+    virtual void push_data(unsigned char* buf , int width, int height, int b_pixel){return;}
+    virtual void join(){return;}
+private:
+//    SVC_buffer* m_buffer;
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_output_net.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_output_net.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_output_net.h	(revision 4)
@@ -0,0 +1,74 @@
+
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_OUTPUT_NET_H
+#define SVC_OUTPUT_NET_H
+
+#include "SVC_output_module.h"
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+class SVC_output_net: public SVC_output_module
+{
+public:
+    SVC_output_net();
+    void init2();
+    void push_data(unsigned char* buf , int width, int height, int b_pixel);
+    unsigned char* init(int width, int height, int b_pixel,char* output_addr, int output_port);
+
+private:
+    int m_width;
+    int m_height;
+    int m_byte_pixel;
+    int m_color_mode;
+    int m_flag_done;
+    unsigned char* m_inter_buffer,*m_inter_buffer_ptr;
+    int m_flag_notinit;
+    char* m_output_addr;
+    int m_output_port;
+    int m_count;
+
+    int fd;
+    struct sockaddr_in cli_addr,serv_addr;
+    int result;
+    socklen_t cli_len,serv_len;
+
+};
+#endif
Index: trunk/src/testing/app/svc/include/SVC_output_sail.h
===================================================================
--- trunk/src/testing/app/svc/include/SVC_output_sail.h	(revision 4)
+++ trunk/src/testing/app/svc/include/SVC_output_sail.h	(revision 4)
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SVC_OUTPUT_SAIL_H
+#define SVC_OUTPUT_SAIL_H
+
+#include "SVC_output_module.h"
+#include <pthread.h>
+#include "sail.h"
+#include "misc.h"
+
+class SVC_output_sail: public SVC_output_module
+{
+public:
+    SVC_output_sail();
+    void init2();
+    void push_data(unsigned char* buf , int width, int height, int b_pixel);
+    unsigned char* init(int width, int height, int b_pixel,char* output_addr, int output_port);
+
+private:
+    pthread_t outputThreadID;
+    int m_width;
+    int m_height;
+    int m_byte_pixel;
+    int m_color_mode;
+    int m_flag_done;
+    unsigned char* m_inter_buffer;
+    sail sageInf;
+    int m_flag_notinit;
+    char* m_output_addr;
+    int m_output_port;
+    int framenum;
+};
+#endif
Index: trunk/src/testing/app/svc/src/SVC_input_null.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_input_null.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_input_null.cpp	(revision 4)
@@ -0,0 +1,210 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_input_null.h"
+
+SVC_input_null::SVC_input_null()
+{
+    m_pid = 69;
+    m_byte_pixel = 2;
+    m_color_mode = RGB16;
+    m_decode_mpeg2 = NULL;
+}
+
+void SVC_input_null::setOutput(SVC_output_module *o_module)
+{
+	m_output_module = o_module;
+        	if(m_decode_mpeg2)
+                	m_decode_mpeg2 -> set_output_module(m_output_module);
+        if(m_codec == UNCOM)
+		m_output_module ->init (m_buffer_size,1,0,m_output_addr,m_output_port);
+}
+void SVC_input_null::init(int codec,int color_mode, int buffer_size, int rtp_flag, char* addr, int port, char* output_addr, int output_port)
+{
+	//setting network configuration
+	m_input_addr = addr;
+	m_input_port = port;
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+        m_codec = codec;
+	m_byte_pixel = convert_format2pixelbyte(m_color_mode);
+	m_buffer_size = buffer_size;
+
+	//setting decoder configuration
+	select_decoder(codec);
+}
+void SVC_input_null::run()
+{
+	m_receive_callback((void*)this);	//process for specific decoder
+}
+void SVC_input_null::select_decoder(int codec)
+{
+    switch(codec)
+    {
+        case MPEG2:
+                /* setting capture callback function */
+                m_receive_callback = mpeg2_receive;
+                fprintf(stderr,"CODEC:MPEG2\n");
+                /* setting decoder */
+                m_decode_mpeg2 = new SVC_decode_mpeg2();
+                m_decode_mpeg2 -> init(m_pid, m_color_mode,m_buffer_size,m_output_addr,m_output_port);
+                m_decode_mpeg2 -> set_output_callback((void*)this, decode_output_callback);
+
+            break;
+        case DV:
+                /* setting capture callback function */
+                m_receive_callback = dv_receive;
+                fprintf(stderr,"CODEC:DV\n");
+
+                /* setting decoder */
+
+            break;
+        case UNCOM:
+                m_receive_callback = mpeg2_receive;
+                /* setting capture callback function */
+                fprintf(stderr,"CODEC:NULL\n");
+                /* setting decoder */
+
+            break;
+
+        default:
+                fprintf(stderr,"This codec is not supported\n");
+            break;
+    }
+}
+
+void SVC_input_null::decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height)
+{
+	SVC_input_null* THIS = (SVC_input_null*) output_obj;
+        THIS -> set_imagesize(width, height);
+        THIS -> decode_ouput(buf);
+}
+void SVC_input_null::decode_ouput(uint8_t * const * buf)
+{
+        m_output_module -> push_data((unsigned char*)buf[0],m_width,m_height,m_byte_pixel);
+}
+void SVC_input_null::set_imagesize (int width, int height)
+{
+        m_width = width;
+        m_height = height;
+}
+char* SVC_input_null::get_input_addr()
+{
+	return m_input_addr;
+}
+int SVC_input_null::get_input_port()
+{
+	return m_input_port;
+}
+int SVC_input_null::get_buffer_size()
+{
+	return m_buffer_size;
+}
+
+void SVC_input_null::mpeg2_receive(void* obj)
+{
+	SVC_input_null* THIS = (SVC_input_null *)obj;
+
+	int fd =0;	//stdin
+	struct timeval tv;
+        fd_set rfds;
+        int result = 0;
+        int buf_size = THIS -> get_buffer_size();
+	char* stream = (char*) malloc(sizeof(char)*SVC_MAX_INPUTNET_BUFFER_SIZE);
+
+        fprintf (stderr, "Starting to receive input_null\n");
+        int total = 0;
+
+        do {
+                  FD_ZERO (&rfds);
+                  FD_SET (fd, &rfds);
+                  tv.tv_sec = 0;
+                  tv.tv_usec = 20000;
+
+                  if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0)    //if data is received
+	  	  {
+				sleep(0);
+				if(FD_ISSET(fd, &rfds))
+				{
+				     //read data from standard input
+				     result = fread(stream,1,buf_size,stdin);
+
+					if(result == buf_size)
+					{
+						//fprintf(stderr, "SVC_input_null::read data %d\n",result);
+						//forward data received from stdin to decode
+						if(THIS-> m_codec != UNCOM)
+							THIS -> m_decode_mpeg2 -> decode((unsigned char*)stream,result);
+						else
+							THIS -> m_output_module -> push_data((unsigned char*)stream,result,1,1);
+
+                                                total += result;
+                                                if (total > 7800) // 6 packets == 1 frame ??
+                                                {
+                                                        //usleep((int)(1000.0/30.0)*1000); // get 30fps
+																		  usleep(1);
+                                                        total = 0;
+                                                }
+
+
+					}
+					else {
+						fprintf(stderr, "SVC_input_null::incorrect received byte size %d -> %d received\n",buf_size,result);
+						break;
+					}
+				}
+				else
+					fprintf(stderr, "SVC_input_null::other's data\n");
+
+			}
+			else
+			{
+				//fprintf(stderr, "SVC_input_null::no data\n");
+			}
+
+
+		}while (g_done_control == 0 ||  result == 0);	//should check
+
+		free(stream);
+
+                fprintf (stderr, "input_null is done.\n");
+}
+void SVC_input_null::dv_receive(void* obj)
+{
+	SVC_input_null* THIS = (SVC_input_null *)obj;
+
+}
Index: trunk/src/testing/app/svc/src/SVC_output_null.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_output_null.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_output_null.cpp	(revision 4)
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_output_null.h"
+
+SVC_output_null::SVC_output_null()
+{
+	m_width = 0;
+	m_height = 0;
+	m_byte_pixel = 0;
+	m_flag_notinit = 1;
+	m_inter_buffer = NULL;
+}
+unsigned char* SVC_output_null::init(int width, int height, int color_mode,char* output_addr, int output_port)
+{
+	m_width = width;
+	m_height = height;
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+	m_byte_pixel = convert_format2pixelbyte(color_mode);
+	if(m_flag_notinit)
+	{
+		init2();
+		m_flag_notinit =0;
+	}
+    	return m_inter_buffer;
+}
+
+void SVC_output_null::push_data(unsigned char* buf , int width, int height, int b_pixel)
+{
+	int ret;
+	ret = fwrite(buf,1,width*height*b_pixel,stdout);
+	//fprintf(stderr, "%d byte is write\n");
+}
+void SVC_output_null::init2()
+{
+
+}
+
Index: trunk/src/testing/app/svc/src/SVC_buffer_manager.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_buffer_manager.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_buffer_manager.cpp	(revision 4)
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_buffer_manager.h"
+
+
+
+SVC_buffer_manager::SVC_buffer_manager()
+{
+	m_svc_buffer_list = NULL;
+}
+SVC_buffer* SVC_buffer_manager::create_buffer_instance()
+{
+	return new SVC_buffer();
+}
+
+
+
+///////////////////////////////////////////////
+
+//               SVC_buffer class
+
+//////////////////////////////////////////////
+
+
+SVC_buffer::SVC_buffer()
+{
+	m_buffer_list = NULL;
+        m_width = 0;
+        m_height = 0;
+        m_byte_pixel = 0;
+	m_buf_front = 0;
+	m_buf_rear = 0;
+	m_first_flag =1;
+}
+
+int SVC_buffer::isnotinit()
+{
+	return m_first_flag;
+}
+int SVC_buffer::init(int width, int height, int byte_pixel)
+{
+	int i;
+	m_width = width;
+	m_height = height;
+	m_byte_pixel = byte_pixel;
+
+   	pthread_mutexattr_t mutexAttr;
+   	pthread_mutexattr_init(&mutexAttr);
+   	pthread_mutex_init(&m_pop_lock, &mutexAttr);
+   	pthread_mutex_lock(&m_pop_lock);
+
+   	pthread_mutexattr_init(&mutexAttr);
+   	pthread_mutex_init(&m_put_lock, &mutexAttr);
+   	pthread_mutex_unlock(&m_put_lock);
+
+	pthread_cond_init(&m_cond,NULL);
+
+	m_buffer_list = (unsigned char**)malloc(sizeof(unsigned char*)*RAWDATA_BUFFER_LENGTH);
+
+	for(i=0; i< RAWDATA_BUFFER_LENGTH; i++)
+	{
+		m_buffer_list[i] = (unsigned char*) malloc (sizeof(unsigned char*) * width * height * byte_pixel);
+		if(m_buffer_list[i] == NULL)
+			return 1;
+	}
+	m_first_flag=0;
+	return 0;
+}
+void SVC_buffer::put_data(unsigned char* data, long size)
+{
+	if(data == NULL)
+		return;
+	if(size != (m_width * m_height * m_byte_pixel)){
+		fprintf(stderr,"different data size in SVC_buffer from %ld to %ld\n");
+		return;
+	}
+
+	if((m_buf_front+1)%RAWDATA_BUFFER_LENGTH == m_buf_rear)	//buffer_list is full
+	{
+		// smoothing buffer management should be implemented. now just return.
+		// kind of random dropping like RED in Active Queue Management
+
+		fprintf(stderr,"buffer_list is full in SVC_buffer\n");
+		return;
+	}
+	else	//buffer_list has enough space
+	{
+		m_buf_front = (m_buf_front+1) % RAWDATA_BUFFER_LENGTH;
+		memcpy (m_buffer_list[m_buf_front], data, size);
+   		pthread_cond_signal(&m_cond);
+	}
+
+}
+unsigned char* SVC_buffer::pop_data()
+{
+	if(m_buf_rear == m_buf_front)	//buffer is empty
+	{
+   		pthread_cond_wait(&m_cond,&m_pop_lock);
+		return NULL;
+	}
+	else	//buffer_list has data
+	{
+		int temp_rear;
+		temp_rear = (m_buf_rear + 1) %	RAWDATA_BUFFER_LENGTH;
+		unsigned char* temp = (unsigned char*)malloc(sizeof(unsigned char)*m_width * m_height * m_byte_pixel);
+	        memcpy(temp,m_buffer_list[temp_rear],sizeof(unsigned char)*m_width*m_height*m_byte_pixel);
+		m_buf_rear = (m_buf_rear + 1) %	RAWDATA_BUFFER_LENGTH;
+		return temp;
+	}
+}
+int SVC_buffer::pop_data(unsigned char* output_buffer)
+{
+	if(m_buf_rear == m_buf_front)	//buffer is empty
+	{
+   		pthread_cond_wait(&m_cond,&m_pop_lock);
+		return 1 ;
+	}
+	else	//buffer_list has data
+	{
+		int temp_rear;
+		temp_rear = (m_buf_rear + 1) %	RAWDATA_BUFFER_LENGTH;
+	        memcpy(output_buffer,m_buffer_list[temp_rear],sizeof(unsigned char)*m_width*m_height*m_byte_pixel);
+		m_buf_rear = (m_buf_rear + 1) %	RAWDATA_BUFFER_LENGTH;
+		return 0;
+	}
+}
+
+void SVC_buffer::print_current_buflen()
+{
+	int diff;
+	if(diff= (m_buf_front - m_buf_rear) < 0)
+		diff = diff + RAWDATA_BUFFER_LENGTH -1;
+	fprintf(stderr,"current buffer length is %d\n",diff);
+}
+
+
+
+
+
Index: trunk/src/testing/app/svc/src/SVC_input_module.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_input_module.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_input_module.cpp	(revision 4)
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_input_module.h"
+
+SVC_input_module::SVC_input_module()
+{
+
+}
+
+
+
Index: trunk/src/testing/app/svc/src/SVC_input_net.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_input_net.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_input_net.cpp	(revision 4)
@@ -0,0 +1,287 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_input_net.h"
+
+SVC_input_net::SVC_input_net()
+{
+    m_pid = 69;
+    //m_pid = 2064;
+    m_byte_pixel = 2;
+    m_color_mode = RGB16;
+    m_decode_mpeg2 = NULL;
+}
+
+void SVC_input_net::setOutput(SVC_output_module *o_module)
+{
+	m_output_module = o_module;
+        	if(m_decode_mpeg2)
+                	m_decode_mpeg2 -> set_output_module(m_output_module);
+        if(m_codec == UNCOM)
+		m_output_module ->init (m_buffer_size,1,0,m_output_addr,m_output_port);
+}
+void SVC_input_net::init(int codec,int color_mode, int buffer_size, int rtp_flag, char* addr, int port, char* output_addr, int output_port)
+{
+	//setting network configuration
+	m_input_addr = addr;
+	m_input_port = port;
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+        m_codec = codec;
+	m_byte_pixel = convert_format2pixelbyte(m_color_mode);
+
+	if(rtp_flag == RTP_ENABLE)
+		m_buffer_size = buffer_size + RTP_HEADER_SIZE;
+	else
+		m_buffer_size = buffer_size;
+
+	//setting decoder configuration
+	select_decoder(codec);
+}
+void SVC_input_net::run()
+{
+	m_receive_callback((void*)this);	//process for specific decoder
+}
+void SVC_input_net::select_decoder(int codec)
+{
+    switch(codec)
+    {
+        case MPEG2:
+                /* setting capture callback function */
+                m_receive_callback = mpeg2_receive;
+                fprintf(stderr,"CODEC:MPEG2\n");
+                /* setting decoder */
+                m_decode_mpeg2 = new SVC_decode_mpeg2();
+                m_decode_mpeg2 -> init(m_pid, m_color_mode,VLC_SEND_BUFFER_SIZE,m_output_addr,m_output_port);
+                m_decode_mpeg2 -> set_output_callback((void*)this, decode_output_callback);
+
+            break;
+        case DV:
+                /* setting capture callback function */
+                m_receive_callback = dv_receive;
+                fprintf(stderr,"CODEC:DV\n");
+
+                /* setting decoder */
+
+            break;
+        case UNCOM:
+                m_receive_callback = mpeg2_receive;
+                /* setting capture callback function */
+                fprintf(stderr,"CODEC:NULL\n");
+                /* setting decoder */
+
+            break;
+
+        default:
+                fprintf(stderr,"This codec is not supported\n");
+            break;
+    }
+}
+
+void SVC_input_net::decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height)
+{
+	SVC_input_net* THIS = (SVC_input_net*) output_obj;
+        THIS -> set_imagesize(width, height);
+        THIS -> decode_ouput(buf);
+}
+void SVC_input_net::decode_ouput(uint8_t * const * buf)
+{
+        m_output_module -> push_data((unsigned char*)buf[0],m_width,m_height,m_byte_pixel);
+}
+void SVC_input_net::set_imagesize (int width, int height)
+{
+        m_width = width;
+        m_height = height;
+}
+char* SVC_input_net::get_input_addr()
+{
+	return m_input_addr;
+}
+int SVC_input_net::get_input_port()
+{
+	return m_input_port;
+}
+int SVC_input_net::get_buffer_size()
+{
+	return m_buffer_size;
+}
+
+void SVC_input_net::mpeg2_receive(void* obj)
+{
+	SVC_input_net* THIS = (SVC_input_net*)obj;
+
+	unsigned char* data;
+        int data_len;
+
+	//initialization of network interface
+
+		int fd = -1;
+                struct sockaddr_in cli_addr, serv_addr;
+		struct ip_mreq mreq;
+		char* addr;
+		struct timeval tv;
+                fd_set rfds;
+                int result = 0;
+		socklen_t cli_len = sizeof(cli_addr);
+		int buf_size = THIS -> get_buffer_size();
+
+		bzero((char*) &serv_addr, sizeof(serv_addr));
+		serv_addr.sin_family 	= AF_INET;
+		if((addr = (THIS -> get_input_addr())) == NULL)
+		{
+			serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+			fprintf(stderr, "SVC_input_net::ADDR is NULL\n");
+		}
+		serv_addr.sin_port = htons(THIS -> get_input_port());
+
+		if(( fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
+		{
+			fprintf(stderr, "SVC_input_net::Fail in creating socket\n ");
+			exit(1);
+		}
+
+	 //set socket option
+		int on = 1;
+		if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) < 0)
+			fprintf(stderr, "SVC_input_net::Fail in REUSEADDR\n ");
+
+
+		int rcvbufsize = 200000;
+		if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcvbufsize, sizeof(rcvbufsize)) < 0)
+			fprintf(stderr, "SVC_input_net::Fail in RCVBUF %d\n",rcvbufsize);
+
+		if( bind(fd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
+		{
+			fprintf(stderr, "SVC_input_net::Fail in binding socket\n ");
+			exit(1);
+		}
+
+	 //check multicast
+		if((addr != NULL) && THIS -> is_multicast_addr(addr))
+		{
+
+			fprintf(stderr, "SVC_input_net::MULTICAST ADDRESS\n ");
+
+			mreq.imr_multiaddr.s_addr = inet_addr(addr);
+			mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+			//mreq.imr_interface.s_addr = htonl(inet_addr(""));
+
+			unsigned char ttl = 1;
+			unsigned char loop = 1;
+			if (setsockopt (fd, IPPROTO_IP,IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)
+				fprintf(stderr, "SVC_input_net::MULTICAST_LOOP\n ");
+
+			if(setsockopt (fd, IPPROTO_IP,IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
+				fprintf(stderr, "SVC_input_net::MULTICAST_TTL\n ");
+
+			if(setsockopt (fd, IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) < 0)
+				fprintf(stderr, "SVC_input_net::IP_ADD_MEMBERSHIP\n ");
+
+		}
+
+		char* stream = (char*) malloc(sizeof(char)*SVC_MAX_INPUTNET_BUFFER_SIZE);
+
+		//network receiving loop
+
+                fprintf (stderr, "Starting to receive input_net port -> %d\n",ntohs(serv_addr.sin_port));
+
+                do {
+                        FD_ZERO (&rfds);
+                        FD_SET (fd, &rfds);
+                        tv.tv_sec = 0;
+                        tv.tv_usec = 20000;
+
+                        if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0)    //if data is received
+			{
+				if(FD_ISSET(fd, &rfds))
+				{
+			             //fprintf(stderr, "SVC_input_net::ready to read data\n");
+
+				     //read data from network
+				     result = recvfrom (fd,stream,SVC_MAX_INPUTNET_BUFFER_SIZE,0,(struct sockaddr*)&cli_addr,&cli_len);
+
+					if(result != buf_size)
+					{
+						fprintf(stderr, "SVC_input_net::incorrect buffer_size %d received\n",result);
+						continue;
+					}
+					else {
+						//fprintf(stderr, "SVC_input_net::read data %d\n",result);
+						//forward data received from network to decode
+						if(THIS-> m_codec != UNCOM)
+							THIS -> m_decode_mpeg2 -> decode((unsigned char*)stream,result);
+						else
+							THIS -> m_output_module -> push_data((unsigned char*)stream,result,1,1);
+					}
+				}
+				else
+					fprintf(stderr, "SVC_input_net::other's data\n");
+
+			}
+			else
+			{
+				//fprintf(stderr, "SVC_input_net::no data\n");
+			}
+
+
+		}while (g_done_control == 0 ||  result == 0);	//should check
+
+		close (fd);
+		free(stream);
+
+                fprintf (stderr, "input_net is done.\n");
+}
+void SVC_input_net::dv_receive(void* obj)
+{
+	SVC_input_net* THIS = (SVC_input_net*)obj;
+
+}
+
+
+int SVC_input_net::is_multicast_addr(char* addr_str)
+{
+	unsigned long addr_i = ntohl(inet_addr(addr_str));
+	if((addr_i & 0xf0000000) != 0xe0000000){	//if unicast
+		return 0;
+	}
+	else{						//if multicast
+		return 1;
+	}
+}
+
+
+
Index: trunk/src/testing/app/svc/src/SVC_output_module.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_output_module.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_output_module.cpp	(revision 4)
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_output_module.h"
+
+SVC_output_module::SVC_output_module()
+{
+
+}
+
+
+
+
Index: trunk/src/testing/app/svc/src/SVC_output_net.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_output_net.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_output_net.cpp	(revision 4)
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_output_net.h"
+
+
+SVC_output_net::SVC_output_net()
+{
+	m_width = 0;
+	m_height = 0;
+	m_byte_pixel = 0;
+	m_flag_notinit = 1;
+	m_inter_buffer = NULL;
+	m_count =0;
+}
+unsigned char* SVC_output_net::init(int width, int height, int color_mode,char* output_addr, int output_port)
+{
+	m_width = width;
+	m_height = height;
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+	m_byte_pixel = convert_format2pixelbyte(color_mode);
+	if(m_flag_notinit)
+	{
+		init2();
+		m_flag_notinit =0;
+	}
+    	return m_inter_buffer;
+}
+
+void SVC_output_net::push_data(unsigned char* buf , int width, int height, int b_pixel)
+{
+	if(buf == NULL || fd < 0)
+	{
+		fprintf(stderr, "socket init is not yet\n");
+		return;
+	}
+
+	memcpy(m_inter_buffer_ptr, buf, width);
+	m_count += width;
+	m_inter_buffer_ptr += width;
+
+	if(m_count >= m_width)
+	{
+		result = sendto(fd,m_inter_buffer,m_width,0,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
+		//result = fwrite(m_inter_buffer,1, m_width,stdout);
+		m_inter_buffer_ptr = m_inter_buffer;
+		m_count =0;
+	}
+
+	if(result != m_width)
+             fprintf(stderr, "SVC_output_net::Incorrect send buf size %d -> %d\n",m_width,result);
+}
+void SVC_output_net::init2()
+{
+	fd = -1;
+        cli_len = sizeof(cli_addr);
+        serv_len = sizeof(serv_addr);
+
+	//Sender
+        bzero((char*) &cli_addr, sizeof(cli_addr));
+        cli_addr.sin_family    = AF_INET;
+        cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+        cli_addr.sin_port = htons(0);
+
+	//Receiver
+        bzero((char*) &serv_addr, sizeof(serv_addr));
+        serv_addr.sin_family    = AF_INET;
+        serv_addr.sin_addr.s_addr = inet_addr(m_output_addr);
+        serv_addr.sin_port = htons(m_output_port);
+
+	fprintf(stderr,"Sending address is %s port is %d\n",m_output_addr,m_output_port);
+
+
+        if(( fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
+        {
+             fprintf(stderr, "SVC_output_net::Fail in creating socket\n ");
+             exit(1);
+        }
+
+        if( bind(fd, (struct sockaddr*) &cli_addr, sizeof(cli_addr)) < 0)
+        {
+             fprintf(stderr, "SVC_output_net::Fail in binding socket\n ");
+             exit(1);
+         }
+
+	 m_inter_buffer = (unsigned char*) malloc (m_width*sizeof(unsigned char));
+	 m_inter_buffer_ptr = m_inter_buffer;
+}
+
Index: trunk/src/testing/app/svc/src/SVC_output_sail.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_output_sail.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_output_sail.cpp	(revision 4)
@@ -0,0 +1,140 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_output_sail.h"
+
+int g_done_out;
+extern int nwID;
+void *sageBuf = NULL;
+
+SVC_output_sail::SVC_output_sail()
+{
+	m_width = 0;
+	m_height = 0;
+	m_byte_pixel = 0;
+	g_done_out =0;
+	m_flag_notinit = 1;
+	m_inter_buffer = NULL;
+	framenum = 0;
+}
+unsigned char* SVC_output_sail::init(int width, int height, int color_mode,char* output_addr, int output_port)
+{
+	m_width = width;
+	m_height = height;
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+	m_byte_pixel = convert_format2pixelbyte(color_mode);
+	if(m_flag_notinit)
+	{
+		init2();
+		m_flag_notinit =0;
+	}
+    	return m_inter_buffer;
+}
+
+void SVC_output_sail::push_data(unsigned char* buf , int width, int height, int b_pixel)
+{
+	// push the frame
+
+	// 15 fps
+	// if ( (framenum%2) )
+	// 25 fps
+	if ( (framenum == 1) || (framenum == 7) || (framenum == 13) || (framenum == 19) || (framenum == 25) )
+	// 30 fps
+	//if ( 0 )
+	{
+	}
+	else
+	{
+		memcpy(sageBuf, buf, width*height*b_pixel);
+		sageInf.swapBuffer();
+		sageBuf = sageInf.getBuffer();
+	}
+	framenum = (framenum + 1) % 30;
+
+	// check some messages
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+		switch (msg.getCode()) {
+			case APP_QUIT : {
+				exit(0);
+				break;
+			}
+
+		}
+	}
+}
+
+void SVC_output_sail::init2()
+{
+    sageRect glImageMap;
+    glImageMap.left = 0.0;
+    glImageMap.right = 1.0;
+    glImageMap.bottom = 0.0;
+    glImageMap.top = 1.0;
+
+    sailConfig scfg;
+    scfg.init("svc.conf");
+    scfg.setAppName("svc");
+    scfg.rank = 0;
+	 scfg.nwID = nwID;
+
+    scfg.resX = m_width;
+    scfg.resY = m_height;
+    scfg.imageMap = glImageMap;
+    scfg.rowOrd = TOP_TO_BOTTOM;
+
+    /* find TeraVision color format */
+	switch(m_color_mode)
+        {
+	     case RGB16:
+    		scfg.pixFmt = PIXFMT_565;
+		break;
+        case RGB24:
+    		scfg.pixFmt = PIXFMT_888;
+		break;
+        case RGB32:
+    		scfg.pixFmt = PIXFMT_8888;
+		break;
+        case YUV:
+    		scfg.pixFmt = PIXFMT_YUV;
+		break;
+        }
+    sageInf.init(scfg);
+	 sageBuf = sageInf.getBuffer();
+}
+
Index: trunk/src/testing/app/svc/src/main.cpp
===================================================================
--- trunk/src/testing/app/svc/src/main.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/main.cpp	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_control.h"
+
+int main(int argc, char** argv)
+{
+	SVC_control* app = new SVC_control();
+	if(app -> init(argc, argv))
+	{
+		return 1;
+	}
+	app -> run();
+
+	return 0;
+}
Index: trunk/src/testing/app/svc/src/SVC_decode_mpeg2.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_decode_mpeg2.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_decode_mpeg2.cpp	(revision 4)
@@ -0,0 +1,482 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_decode_mpeg2.h"
+
+#define NEEDBYTES(x)                                            \
+    do {                                                        \
+        int missing;                                            \
+                                                                \
+        missing = (x) - bytes;                                  \
+        if (missing > 0) {                                      \
+            if (header == head_buf) {                           \
+                if (missing <= end - buf) {                     \
+                    memcpy (header + bytes, buf, missing);      \
+                    buf += missing;                             \
+                    bytes = (x);                                \
+                } else {                                        \
+                    memcpy (header + bytes, buf, end - buf);    \
+                    state_bytes = bytes + end - buf;            \
+                    return 0;                                   \
+                }                                               \
+            } else {                                            \
+                memcpy (head_buf, header, bytes);               \
+                state = DEMUX_HEADER;                           \
+                state_bytes = bytes;                            \
+                return 0;                                       \
+            }                                                   \
+        }                                                       \
+    } while (0)
+
+#define DONEBYTES(x)            \
+    do {                        \
+        if (header != head_buf) \
+            buf = header + (x); \
+    } while (0)
+
+
+SVC_decode_mpeg2::SVC_decode_mpeg2()
+{
+     total_offset = 0;
+     buffer = NULL;
+     buf = NULL;
+     nextbuf = NULL;
+     data = NULL;
+     end = NULL;
+     m_output_callback = NULL;
+     m_output_obj = NULL;	//input module
+     m_output_module = NULL;	//output module
+}
+void SVC_decode_mpeg2::init(int program_id, int color_mode,int buf_size,char* output_addr, int output_port)
+{
+     m_byte_pixel = convert_format2pixelbyte(color_mode);
+     demux_pid = -1;
+     m_color_mode = color_mode;
+     m_output_addr = output_addr;
+     m_output_port = output_port;
+     buffer_size = buf_size;
+     mpeg2_initialization();
+}
+void SVC_decode_mpeg2::decode (unsigned char* input_data, int input_size)
+{
+	int pid;
+	//end = buf + fread (buf, 1, buffer + buffer_size - buf, in_file);
+	memcpy(buf,input_data,input_size);
+	//fprintf(stderr,"input_size in decode is %d\n ",input_size);
+	end = buf + input_size;
+
+        buf = buffer;
+
+        for (; (nextbuf = buf + 188) <= end; buf = nextbuf) {
+	    if (*buf != 0x47) {
+                fprintf (stderr, "bad sync byte\n");
+                nextbuf = buf + 1;
+                continue;
+            }
+            pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
+            if (pid != demux_pid && demux_pid != -1)
+	    {
+                continue;
+	    }
+            data = buf + 4;
+            if (buf[3] & 0x20) {        /* buf contains an adaptation field */
+                data = buf + 5 + buf[4];
+                if (data > nextbuf)
+                    continue;
+            }
+
+	    //Begin_automatically detecting video pid
+	    if((buf[1] & 0x40 && demux_pid == -1) ){       	//payload unit start indicator
+                        if(((data[0] << 16) + (data[1] << 8) + data[2]) == 0x000001){	//pes start code
+                                if((data[3] >> 4) == 0xe){	//pes -> stream_id
+                                        demux_pid = pid;
+                                }
+				else
+					continue;
+                        }
+                        else
+                                continue;
+            }
+	    //End_automatically detecting video pid
+
+
+            if (buf[3] & 0x10)
+	    {
+                demux (data, nextbuf,
+                       (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
+	    }
+        }
+
+        if (end != buffer + input_size)
+        {
+		fprintf(stderr,"strange size in decode()\n");
+		return;
+	}
+        memcpy (buffer, buf, end - buf);
+        buf = buffer + (end - buf);
+}
+void SVC_decode_mpeg2::mpeg2_initialization()
+{
+	mpeg2dec = mpeg2_init ();
+	if(mpeg2dec == NULL)
+	{
+		fprintf (stderr, "Can not get mpeg2dec\n");
+		exit(1);
+	}
+	mpeg2_malloc_hooks (malloc_hook, NULL);
+
+	buffer = (uint8_t *) malloc (buffer_size);
+    	if (buffer == NULL || buffer_size < 188)
+        	exit (1);
+    	buf = buffer;
+}
+void* SVC_decode_mpeg2::malloc_hook (unsigned size, mpeg2_alloc_t reason)
+{
+	void* buf;
+	if ((int)reason < 0) {
+        return NULL;
+    	}
+    	buf = mpeg2_malloc (size, (mpeg2_alloc_t)-1);
+    	if (buf && (reason == MPEG2_ALLOC_YUV || reason == MPEG2_ALLOC_CONVERTED))
+        	memset (buf, 0, size);
+    	return buf;
+}
+
+void SVC_decode_mpeg2::stop()
+{
+	mpeg2_close (mpeg2dec);
+}
+
+int SVC_decode_mpeg2::output_setup (unsigned int width,
+                         unsigned int height, unsigned int chroma_width,
+                         unsigned int chroma_height)
+{
+	m_width = width;
+        m_height = height;
+        m_chroma_width = chroma_width;
+        m_chroma_height = chroma_height;
+
+	/* setting m_convert_result according to color mode */
+	switch(m_color_mode)
+	{
+		case RGB16:
+			m_convert_result.convert = mpeg2convert_rgb16;
+		break;
+
+		case RGB24:
+			m_convert_result.convert = mpeg2convert_rgb24;
+		break;
+
+		case RGB32:
+			m_convert_result.convert = mpeg2convert_rgb32;
+		break;
+
+                case YUV:
+                        m_convert_result.convert = mpeg2convert_uyvy;
+		break;
+		default:
+			fprintf(stderr,"not supported color mode\n");
+			return 1;
+		break;
+	}
+	return 0;
+}
+
+void SVC_decode_mpeg2::set_output_module(SVC_output_module * o_module)
+{
+	m_output_module = o_module;
+}
+void SVC_decode_mpeg2::decode_mpeg2 (uint8_t * current, uint8_t * end)
+{
+    const mpeg2_info_t * info;
+    mpeg2_state_t state;
+
+    mpeg2_buffer (mpeg2dec, current, end);
+    total_offset += end - current;
+
+    info = mpeg2_info (mpeg2dec);
+    while (1) {
+        state = mpeg2_parse (mpeg2dec);
+        switch (state) {
+        case STATE_BUFFER:
+            return;
+        case STATE_SEQUENCE:
+            /* might set nb fbuf, convert format, stride */
+            /* might set fbufs */
+            if (output_setup (info->sequence->width,
+                               info->sequence->height,
+                               info->sequence->chroma_width,
+                               info->sequence->chroma_height)) {
+                fprintf (stderr, "display setup failed\n");
+                exit (1);
+            }
+
+	    if (m_convert_result.convert &&
+                mpeg2_convert (mpeg2dec, m_convert_result.convert, NULL)) {
+                fprintf (stderr, "color conversion setup failed\n");
+                exit (1);
+            }
+
+	if(m_output_module != NULL)
+  	    m_output_module -> init(m_width, m_height, m_color_mode,m_output_addr,m_output_port);
+
+	    for (int i = 0; i < 3; i++) {
+                fbuf[i][0] = (unsigned char *) malloc (sizeof(unsigned char)*m_width*m_height*m_byte_pixel);
+                fbuf[i][1] = fbuf[i][2] = NULL;
+                if (!fbuf[i][0]) {
+                    fprintf (stderr, "Could not allocate an output buffer.\n");
+                    exit (1);
+                }
+
+                mpeg2_set_buf (mpeg2dec, fbuf[i], NULL);
+            }
+
+            mpeg2_skip (mpeg2dec, 0);	//maybe not skip
+            break;
+
+	case STATE_PICTURE:
+            /* might skip */
+            /* might set fbuf */
+            break;
+        case STATE_SLICE:
+        case STATE_END:
+        case STATE_INVALID_END:
+
+            /* draw current picture */
+            /* might free frame buffer */
+            if (info->display_fbuf) {
+                if (m_output_callback && m_output_obj)
+                    m_output_callback (m_output_obj, info->display_fbuf->buf,
+                                  info->display_fbuf->id, m_width, m_height);
+            }
+
+  	   /*
+	    	//for discard, it is not used
+            if (output->discard && info->discard_fbuf)
+                output->discard (m_output_obj, info->discard_fbuf->buf,
+                                 info->discard_fbuf->id);
+	    */
+            break;
+        default:
+            break;
+        }
+    }
+
+
+}
+void SVC_decode_mpeg2::set_output_callback(void* output_obj, DECODEOUTPUT_CALLBACK callback)
+{
+	m_output_obj = output_obj;
+	m_output_callback = callback;
+}
+
+int SVC_decode_mpeg2::demux (uint8_t * buf, uint8_t * end, int flags)
+{
+	static int mpeg1_skip_table[16] = {
+            0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    	};
+    	uint8_t * header;
+    	int bytes;
+    	int len;
+
+	if (flags & DEMUX_PAYLOAD_START)
+	        goto payload_start;
+        switch (state) {
+     		case DEMUX_HEADER:
+        	if (state_bytes > 0) {
+            		header = head_buf;
+            		bytes = state_bytes;
+            		goto continue_header;
+        	}
+        	break;
+    		case DEMUX_DATA:
+        	if (demux_pid || (state_bytes > end - buf)) {
+            	   	decode_mpeg2 (buf, end);
+            		state_bytes -= end - buf;
+            		return 0;
+        	}
+        	decode_mpeg2 (buf, buf + state_bytes);
+        	buf += state_bytes;
+        	break;
+    		case DEMUX_SKIP:
+        	if (demux_pid || (state_bytes > end - buf)) {
+            		state_bytes -= end - buf;
+            		return 0;
+       		}
+        	buf += state_bytes;
+        	break;
+    	}
+
+    	while (1) {
+        	if (demux_pid) {
+            		state = DEMUX_SKIP;
+            	return 0;
+        	}
+    payload_start:
+	header = buf;
+        bytes = end - buf;
+    continue_header:
+        NEEDBYTES (4);
+        if (header[0] || header[1] || (header[2] != 1)) {
+            if (demux_pid) {
+                state = DEMUX_SKIP;
+                return 0;
+            } else if (header != head_buf) {
+                buf++;
+                goto payload_start;
+            } else {
+                header[0] = header[1];
+                header[1] = header[2];
+                header[2] = header[3];
+                bytes = 3;
+                goto continue_header;
+            }
+        }
+        if (demux_pid) {
+            if ((header[3] >= 0xe0) && (header[3] <= 0xef))
+                goto pes;
+            fprintf (stderr, "bad stream id %x\n", header[3]);
+            exit (1);
+        }
+        switch (header[3]) {
+        case 0xb9:      /* program end code */
+            /* DONEBYTES (4); */
+            /* break;         */
+            return 1;
+        case 0xba:      /* pack header */
+            NEEDBYTES (5);
+            if ((header[4] & 0xc0) == 0x40) {   /* mpeg2 */
+                NEEDBYTES (14);
+		len = 14 + (header[13] & 7);
+                NEEDBYTES (len);
+                DONEBYTES (len);
+                /* header points to the mpeg2 pack header */
+            } else if ((header[4] & 0xf0) == 0x20) {    /* mpeg1 */
+                NEEDBYTES (12);
+                DONEBYTES (12);
+                /* header points to the mpeg1 pack header */
+            } else {
+                fprintf (stderr, "weird pack header\n");
+                DONEBYTES (5);
+            }
+            break;
+        default:
+            if (header[3] == demux_track) {
+            pes:
+                NEEDBYTES (7);
+                if ((header[6] & 0xc0) == 0x80) {       /* mpeg2 */
+                    NEEDBYTES (9);
+                    len = 9 + header[8];
+                    NEEDBYTES (len);
+                    /* header points to the mpeg2 pes header */
+                    if (header[7] & 0x80) {
+                        uint32_t pts, dts;
+
+                        pts = (((header[9] >> 1) << 30) |
+                               (header[10] << 22) | ((header[11] >> 1) << 15) |
+                               (header[12] << 7) | (header[13] >> 1));
+                        dts = (!(header[7] & 0x40) ? pts :
+				(((header[14] >> 1) << 30) |
+                                (header[15] << 22) |
+                                ((header[16] >> 1) << 15) |
+                                (header[17] << 7) | (header[18] >> 1)));
+                        mpeg2_tag_picture (mpeg2dec, pts, dts);
+                    }
+                } else {        /* mpeg1 */
+                    int len_skip;
+                    uint8_t * ptsbuf;
+
+                    len = 7;
+                    while (header[len - 1] == 0xff) {
+                        len++;
+                        NEEDBYTES (len);
+                        if (len > 23) {
+                            fprintf (stderr, "too much stuffing\n");
+                            break;
+                        }
+                    }
+                    if ((header[len - 1] & 0xc0) == 0x40) {
+                        len += 2;
+                        NEEDBYTES (len);
+                    }
+                    len_skip = len;
+                    len += mpeg1_skip_table[header[len - 1] >> 4];
+                    NEEDBYTES (len);
+                    /* header points to the mpeg1 pes header */
+                    ptsbuf = header + len_skip;
+                    if ((ptsbuf[-1] & 0xe0) == 0x20) {
+                        uint32_t pts, dts;
+
+                        pts = (((ptsbuf[-1] >> 1) << 30) |
+                               (ptsbuf[0] << 22) | ((ptsbuf[1] >> 1) << 15) |
+				(ptsbuf[2] << 7) | (ptsbuf[3] >> 1));
+                        dts = (((ptsbuf[-1] & 0xf0) != 0x30) ? pts :
+                               (((ptsbuf[4] >> 1) << 30) |
+                                (ptsbuf[5] << 22) | ((ptsbuf[6] >> 1) << 15) |
+                                (ptsbuf[7] << 7) | (ptsbuf[18] >> 1)));
+                        mpeg2_tag_picture (mpeg2dec, pts, dts);
+                    }
+                }
+                DONEBYTES (len);
+                bytes = 6 + (header[4] << 8) + header[5] - len;
+                if (demux_pid || (bytes > end - buf)) {
+                    decode_mpeg2 (buf, end);
+                    state = DEMUX_DATA;
+                    state_bytes = bytes - (end - buf);
+                    return 0;
+                } else if (bytes > 0) {
+                    decode_mpeg2 (buf, buf + bytes);
+                    buf += bytes;
+                }
+            } else if (header[3] < 0xb9) {
+                fprintf (stderr,
+                         "looks like a video stream, not system stream\n");
+                DONEBYTES (4);
+            } else {
+                NEEDBYTES (6);
+                DONEBYTES (6);
+                bytes = (header[4] << 8) + header[5];
+                if (bytes > end - buf) {
+                    state = DEMUX_SKIP;
+		    state_bytes = bytes - (end - buf);
+                    return 0;
+                }
+                buf += bytes;
+            }
+        }
+    }
+}
+
Index: trunk/src/testing/app/svc/src/SVC_input_1394.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_input_1394.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_input_1394.cpp	(revision 4)
@@ -0,0 +1,245 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_input_1394.h"
+
+SVC_input_1394::SVC_input_1394()
+{
+    m_pid = 2064;
+    m_byte_pixel = 2;
+    m_color_mode = RGB16;
+    m_decode_mpeg2 = NULL;
+    handle = raw1394_new_handle_on_port (0);
+    if(!handle)
+    {
+	fprintf (stderr, "Failed to get libraw1394 handle\n");
+	exit(1);
+    }
+}
+
+void* SVC_input_1394::input_thread(void* obj)
+{
+    SVC_input_1394* THIS = (SVC_input_1394*) obj;
+    THIS -> input_thread2();
+    return NULL;
+}
+
+void SVC_input_1394::input_thread2()
+{
+    m_capture_callback (handle, (void*)this, 63);
+}
+
+void SVC_input_1394::run()
+{
+    m_capture_callback (handle, (void*)this, 63);
+}
+
+void SVC_input_1394::join()
+{
+}
+
+void SVC_input_1394::init(int codec, int color_mode, char* output_addr, int output_port)
+{
+	m_output_addr = output_addr;
+	m_output_port = output_port;
+	m_color_mode = color_mode;
+	m_codec = codec;
+	m_byte_pixel = convert_format2pixelbyte(m_color_mode);
+	select_decoder(codec);
+}
+
+void SVC_input_1394::setBuffer (SVC_buffer* buffer)
+{
+	m_svc_buffer = buffer;
+}
+void SVC_input_1394::select_decoder (int codec)
+{
+    switch(codec)
+    {
+	case MPEG2:
+		/* setting capture callback function */
+		m_capture_callback = mpeg2_receive;
+		fprintf(stderr,"CODEC:MPEG2\n");
+		/* setting decoder */
+                m_decode_mpeg2 = new SVC_decode_mpeg2();
+		m_decode_mpeg2 -> init(m_pid, m_color_mode,CAPTURE1394_SEND_BUFFER_SIZE,m_output_addr,m_output_port);
+     		m_decode_mpeg2 -> set_output_callback((void*)this, decode_output_callback);
+
+	    break;
+	case DV:
+		/* setting capture callback function */
+		m_capture_callback = dv_receive;
+		fprintf(stderr,"CODEC:DV\n");
+
+		/* setting decoder */
+
+	    break;
+	case UNCOM:
+		/* setting capture callback function */
+		m_capture_callback = mpeg2_receive;
+		fprintf(stderr,"CODEC:NULL\n");
+
+		/* setting decoder */
+
+	    break;
+
+	default:
+	    break;
+    }
+}
+void SVC_input_1394::decode_output_callback(void* output_obj, uint8_t * const * buf, void * id, int width, int height)
+{
+	SVC_input_1394* THIS = (SVC_input_1394*) output_obj;
+	THIS -> set_imagesize(width, height);
+	THIS -> decode_ouput(buf);
+}
+
+void SVC_input_1394::decode_ouput(uint8_t * const * buf)
+{
+	m_output_module -> push_data((unsigned char*)buf[0],m_width,m_height,m_byte_pixel);
+}
+void SVC_input_1394::setOutput (SVC_output_module* o_module)
+{
+	m_output_module = o_module;
+	if(m_decode_mpeg2)
+		m_decode_mpeg2 -> set_output_module(m_output_module);
+        if(m_codec == UNCOM)
+                m_output_module ->init (VLC_SEND_BUFFER_SIZE,1,0,m_output_addr,m_output_port);
+}
+void SVC_input_1394::set_imagesize (int width, int height)
+{
+	m_width = width;
+	m_height = height;
+}
+
+int SVC_input_1394::write_packet_mpeg2 (unsigned char *data, int len, unsigned int dropped, void *callback_obj)
+{
+        SVC_input_1394 *THIS = (SVC_input_1394*) callback_obj;
+
+        if (dropped)
+                fprintf (stderr, "\a%d packets dropped!\n", dropped);
+
+	if(THIS && THIS -> m_decode_mpeg2 )
+		THIS -> m_decode_mpeg2 -> decode(data,len);
+	else if(THIS -> m_codec == UNCOM)
+		 THIS -> m_output_module -> push_data((unsigned char*)data,len,1,1);
+	else
+                fprintf (stderr, "decoder is not created\n");
+
+        return 0; //obj -> insert2buffer(data, len);
+}
+
+int SVC_input_1394::insert2buffer(unsigned char* data, int len)
+{
+//	m_buffer -> insert_data(data,len);
+
+	fwrite(data,1,len,stdout);
+	return 0;
+}
+
+int SVC_input_1394::write_frame_dv (unsigned char *data, int len, int complete, void *callback_obj)
+{
+        SVC_input_1394 *obj = (SVC_input_1394*) callback_obj;
+
+        if (complete == 0)
+                fprintf (stderr, "Error: incomplete frame received!\n");
+        return obj -> insert2buffer(data, len);
+}
+
+void SVC_input_1394::mpeg2_receive (raw1394handle_t handle, void *obj, int channel)
+{
+   	iec61883_mpeg2_t mpeg = iec61883_mpeg2_recv_init (handle, write_packet_mpeg2,
+                obj );
+
+        if ( mpeg && iec61883_mpeg2_recv_start (mpeg, channel) == 0)
+        {
+                int fd = raw1394_get_fd (handle);
+                struct timeval tv;
+                fd_set rfds;
+                int result = 0;
+                fprintf (stderr, "Starting to receive 1394\n");
+
+                do {
+                        FD_ZERO (&rfds);
+                        FD_SET (fd, &rfds);
+                        tv.tv_sec = 0;
+                        tv.tv_usec = 20000;
+
+                        if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0)
+				if(FD_ISSET(fd, &rfds))
+                                	result = raw1394_loop_iterate (handle);
+
+                } while (g_done_control == 0 && result == 0);
+
+                fprintf (stderr, "input_1394 is done.\n");
+        }
+        iec61883_mpeg2_close (mpeg);
+}
+
+void SVC_input_1394::dv_receive( raw1394handle_t handle, void* obj, int channel)
+{
+        iec61883_dv_fb_t frame = iec61883_dv_fb_init (handle, write_frame_dv, obj);
+
+        if (frame && iec61883_dv_fb_start (frame, channel) == 0)
+        {
+                int fd = raw1394_get_fd (handle);
+                struct timeval tv;
+                fd_set rfds;
+                int result = 0;
+
+                fprintf (stderr, "Starting to receive\n");
+
+                do {
+                        FD_ZERO (&rfds);
+                        FD_SET (fd, &rfds);
+                        tv.tv_sec = 0;
+                        tv.tv_usec = 20000;
+
+                        if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0)
+                                result = raw1394_loop_iterate (handle);
+
+                } while (g_done_control == 0 && result == 0);
+
+                fprintf (stderr, "done.\n");
+        }
+        iec61883_dv_fb_close (frame);
+}
+
+
+void SVC_input_1394::stop ()
+{
+    raw1394_destroy_handle (handle);
+}
Index: trunk/src/testing/app/svc/src/SVC_control.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_control.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_control.cpp	(revision 4)
@@ -0,0 +1,257 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_control.h"
+
+int g_done_control=0;
+int nwID;
+
+SVC_control::SVC_control()
+{
+
+    m_input_module = NULL;
+    m_output_module = NULL;
+    m_buffer_manager = NULL;
+    m_codec = MPEG2;
+    m_flag_rtp = RTP_DISABLE;
+    m_input_addr = DEFAULT_INPUT_ADDRESS;
+    m_output_addr = DEFAULT_OUTPUT_ADDRESS;
+    m_input_port =SVC_INPUT_NET_PORT;
+    m_output_port =SVC_OUTPUT_NET_PORT;
+    flag_1394 = 0;
+    flag_net = 0;
+    flag_null = 0;
+    m_color_mode = RGB16;
+}
+
+int SVC_control::init(int argc, char** argv)
+{
+	 nwID = 1;
+    int rt=0;
+
+    rt = create_interface_module(argc,argv);
+    if(rt)	// fail in creating interface
+	return rt;
+
+    // create buffer manager
+    if (rt = create_session())
+        return rt;
+
+    return rt;
+}
+void SVC_control::run()
+{
+
+     signal (SIGINT, sighandler);
+     signal (SIGTERM, sighandler);
+     signal (SIGPIPE, sighandler);
+
+    if(m_input_module)
+    	m_input_module -> run();
+}
+void SVC_control::sighandler (int sig)
+{
+        g_done_control = 1;
+}
+
+int SVC_control::create_session()
+{
+
+    if(m_input_module && m_output_module)
+	m_input_module -> setOutput(m_output_module);
+
+    return 0;
+}
+
+int SVC_control::create_interface_module(int argc,char** argv)
+{
+
+    int opt;
+    while((opt = getopt (argc, argv, "i:o:f:a:b:c:d:t:e:n:")) != -1)
+    {
+	switch(opt)
+	{
+	    case 'i':
+		if(strcmp("1394", optarg) == 0)
+		{
+		    flag_1394 =1;
+		    m_input_module = (SVC_input_module *)new SVC_input_1394();
+		}
+		else if (strcmp ("net",optarg) == 0)
+                {
+		    flag_net = 1;
+		    m_input_module = (SVC_input_module *)new SVC_input_net();
+                }
+		else if (strcmp ("null",optarg) == 0)
+                {
+		    flag_null = 1;
+		    m_input_module = (SVC_input_module *)new SVC_input_null();
+                }
+	    	else{
+		    print_usage(argv);
+		    return 1;
+		}
+		break;
+
+	    case 'o':
+	    	if(strcmp("sail", optarg) == 0)
+		{
+                        m_output_module = (SVC_output_module *)new SVC_output_sail();
+	 		m_output_module -> init();	//initialize output module
+		}
+                else if (strcmp ("svclib",optarg) == 0)
+		{
+                        ;//m_output_module = (SVC_output_module *)new SVC_output_sidel();
+		}
+		else if (strcmp ("net",optarg) == 0)
+		{
+                        m_output_module = (SVC_output_module *)new SVC_output_net();
+		}
+		else if (strcmp ("null",optarg) == 0)
+		{
+                        m_output_module = (SVC_output_module *)new SVC_output_null();
+		}
+                else{
+                        print_usage(argv);
+			return 1;
+		}
+		break;
+
+            case 'f':
+	    	if(strcmp("rgb16", optarg) == 0)
+		{
+			m_color_mode = RGB16;
+		}
+                else if (strcmp ("rgb24",optarg) == 0)
+		{
+			m_color_mode = RGB24;
+		}
+		else if (strcmp ("rgb32",optarg) == 0)
+		{
+			m_color_mode = RGB32;
+		}
+                else if (strcmp ("yuv",optarg) == 0)
+		{
+			m_color_mode = YUV;
+		}
+                else{
+                        print_usage(argv);
+			return 1;
+		}
+		break;
+
+            case 'a':
+		m_input_addr = (char*) malloc (sizeof(char) * 256);
+	    	memcpy(m_input_addr, optarg, 256);
+		break;
+
+            case 'b':
+	    	m_input_port = atoi(optarg);
+		break;
+
+            case 'c':
+		m_output_addr = (char*) malloc (sizeof(char) * 256);
+	    	memcpy(m_output_addr, optarg, 256);
+		break;
+
+            case 'd':
+	    	m_output_port = atoi(optarg);
+		break;
+
+            case 't':
+	    	if(strcmp("mpeg2", optarg) == 0)
+		{
+			m_codec = MPEG2;
+		}
+                else if (strcmp ("dv",optarg) == 0)
+		{
+			m_codec = DV;
+		}
+                else if (strcmp ("null",optarg) == 0)
+		{
+			m_codec = UNCOM;
+		}
+                else{
+                        print_usage(argv);
+			return 1;
+		}
+		break;
+
+		case 'n' :
+			nwID = atoi(optarg);
+		break;
+
+	    default:
+		print_usage(argv);
+		return 1;
+		break;
+	}//switch
+    }//while
+
+//only for MPEG2 TS
+
+    if(flag_1394){
+	    m_input_module -> init(m_codec,m_color_mode,m_output_addr,m_output_port);
+    }
+    else if(flag_net){
+	    m_input_module -> init(m_codec,m_color_mode,VLC_SEND_BUFFER_SIZE,RTP_DISABLE, m_input_addr, m_input_port,m_output_addr, m_output_port);
+    }
+    else if(flag_null){
+	    m_input_module -> init(m_codec,m_color_mode,STD_MPEG2TS_READ_BUFFER_SIZE,RTP_DISABLE, m_input_addr, m_input_port,m_output_addr, m_output_port);
+    }
+
+    else{
+	print_usage(argv);
+	return 1;
+    }
+
+    return 0;
+
+}
+
+void SVC_control::print_usage(char ** argv)
+{
+	fprintf(stderr, "usage: "
+ 		"%s -i input_module (1394|net|null) -o output_module (net|sail|svclib|null)\n"
+	        "\t\t[-f output pixel format (rgb16|rgb24|rgb32|yuv)]\n"
+	        "\t\t[-a input address]\n"
+	        "\t\t[-b input port number]\n"
+	        "\t\t[-c output address]\n"
+	        "\t\t[-d output port number]\n"
+	        "\t\t[-t decode codec (mpeg2|dv|null)]\n"
+		, argv[0]
+	);
+}
Index: trunk/src/testing/app/svc/src/Makefile
===================================================================
--- trunk/src/testing/app/svc/src/Makefile	(revision 4)
+++ trunk/src/testing/app/svc/src/Makefile	(revision 4)
@@ -0,0 +1,15 @@
+include ../../../config.mk
+
+CFLAGS=-fPIC -O3 -I../include -I../../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(QUANTA_LIB) $(GLEW_LIB) -L../../../lib -lsail -lraw1394 -lpthread -liec61883 -lmpeg2 -lmpeg2convert $(PAUDIO_LIB)
+CC=$(COMPILER)
+
+default:
+	g++ -c $(CFLAGS) main.cpp SVC_control.cpp SVC_input_1394.cpp SVC_input_module.cpp SVC_decode_mpeg2.cpp SVC_buffer_manager.cpp SVC_output_module.cpp SVC_output_sail.cpp SVC_input_net.cpp SVC_output_null.cpp SVC_output_net.cpp SVC_input_null.cpp
+	g++ $(LIBS) -o svc main.o SVC_control.o SVC_input_1394.o SVC_input_module.o SVC_decode_mpeg2.o SVC_buffer_manager.o SVC_output_module.o SVC_output_sail.o SVC_input_net.o SVC_output_null.o SVC_output_net.o SVC_input_null.o 
+
+install: default
+	cp svc  ../../../bin
+
+clean:
+	/bin/rm -f *.o svc
Index: trunk/src/testing/app/svc/src/SVC_decode_module.cpp
===================================================================
--- trunk/src/testing/app/svc/src/SVC_decode_module.cpp	(revision 4)
+++ trunk/src/testing/app/svc/src/SVC_decode_module.cpp	(revision 4)
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "SVC_decode_module.h"
+
+SVC_decode_module::SVC_decode_module()
+{
+
+}
Index: trunk/src/testing/app/ImageFlip/Makefile
===================================================================
--- trunk/src/testing/app/ImageFlip/Makefile	(revision 4)
+++ trunk/src/testing/app/ImageFlip/Makefile	(revision 4)
@@ -0,0 +1,24 @@
+
+SAGE_DIR = ../..
+
+CFLAGS=`Wand-config --cflags --cppflags`  -I$(SAGE_DIR)/include -fno-stack-protector
+LIBS= `Wand-config --ldflags --libs` -lpthread -lstdc++ -lltdl -L$(SAGE_DIR)/lib -lsail  -lquanta
+
+FILES=imageflip.o util.o
+TARGET=imageflip
+
+
+default: $(TARGET)
+
+install: $(TARGET)
+	/bin/cp -f imageflip $(SAGE_DIR)/bin
+	
+imageflip: $(FILES)
+	g++ -o imageflip $(FILES) $(LIBS)
+
+%.o: %.cpp
+	g++ $(CFLAGS) -c -o $@ $<
+
+clean:
+	/bin/rm -f *.o *~ imageflip
+
Index: trunk/src/testing/app/ImageFlip/imageflip.cpp
===================================================================
--- trunk/src/testing/app/ImageFlip/imageflip.cpp	(revision 4)
+++ trunk/src/testing/app/ImageFlip/imageflip.cpp	(revision 4)
@@ -0,0 +1,334 @@
+/*****************************************************************************************
+ * imageflip: loads an image sequence and sends it to SAGE for display
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to www.evl.uic.edu/cavern/forum
+ *
+ * Author: Ratko Jagodic, Luc Renambot
+ *
+ *****************************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <time.h>
+#include <unistd.h>
+#include <wand/magick-wand.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+#include "util.h"
+
+#define FLIP_DEPTH 10
+
+
+// Set of filenames
+std::set<std::string> Names;
+// Number of images to ne processed
+int Limit;
+
+
+#if MagickLibVersion >= 0x645
+#define MagickGetImagePixels MagickGetAuthenticPixels
+#endif
+
+
+
+typedef unsigned char byte;
+#define memalign(x,y) malloc((y))
+
+using namespace std;
+
+
+#define ThrowWandException(wand)		\
+  {						\
+    char					\
+      *description;				\
+						\
+    ExceptionType				\
+      severity;					\
+						    \
+    description=MagickGetException(wand,&severity);			\
+    (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \
+    description=(char *) MagickRelinquishMemory(description);		\
+    exit(-1);								\
+  }
+
+
+// -----------------------------------------------------------------------------
+
+void getRGB(string fileName, byte *rgb, unsigned int &width, unsigned int &height)
+{
+    // use ImageMagick to read all other formats
+    MagickBooleanType status;
+    MagickWand *wand;
+
+    // read file
+    wand=NewMagickWand();
+    status=MagickReadImage(wand, fileName.data());
+    if (status == MagickFalse)
+	ThrowWandException(wand);
+
+    // get the image size
+    width = MagickGetImageWidth(wand);
+    height = MagickGetImageHeight(wand);
+
+    // get the pixels
+    MagickGetImagePixels(wand, 0, 0, width, height, "RGB", CharPixel, rgb);
+    DestroyMagickWand(wand);
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+
+void getDimensions(string fileName, unsigned int &width, unsigned int &height)
+{
+    // use ImageMagick to read all other formats
+    MagickBooleanType status;
+    MagickWand *wand;
+
+    // read file
+    wand=NewMagickWand();
+    status=MagickReadImage(wand, fileName.data());
+    if (status == MagickFalse)
+	ThrowWandException(wand);
+
+    // get the image size
+    width = MagickGetImageWidth(wand);
+    height = MagickGetImageHeight(wand);
+
+    DestroyMagickWand(wand);
+}
+
+// -----------------------------------------------------------------------------
+
+void RefreshList(string dir)
+{
+   DIR *dirh;
+  struct dirent *dirp;
+  char pathname[1024];
+  char linkname[1024];
+  struct stat statbuf;
+
+   const char *dn = dir.c_str();
+
+
+if ((dirh = opendir(dn)) == NULL)
+   {
+   perror("opendir");
+   exit(1);
+   }
+
+
+for (dirp = readdir(dirh); dirp != NULL; dirp = readdir(dirh))
+   {
+   if (strcmp(".",dirp->d_name) == 0 || strcmp("..",dirp->d_name) == 0)
+      {
+      continue;
+      }
+ 
+   sprintf(pathname,"%s/%s",dn,dirp->d_name);
+
+   if (lstat(pathname,&statbuf) == -1)                /* see man stat */
+     {
+     perror("stat");
+     continue;
+     }
+
+   if (S_ISREG(statbuf.st_mode))
+      {
+      //printf("%s is a regular file\n",pathname);
+	string pn = string(pathname);
+	string fileExt = pn.substr(pn.rfind("."));
+	if ( (fileExt.compare(".JPG") == 0) || (fileExt.compare(".jpg") == 0) )
+		if (Names.insert(pathname).second)
+		{
+			cout << pathname << " added successfully" << endl;
+		}
+		else
+		{
+			//cout << pathname << " rejected" << endl;
+		}
+
+      }
+
+   if (S_ISDIR(statbuf.st_mode))
+      {
+      //printf("%s is a directory\n",pathname);
+      }
+
+   if (S_ISLNK(statbuf.st_mode))
+      {
+      bzero(linkname,1024);                         /* clear string */
+      readlink(pathname,linkname,1024);
+      //printf("%s is a link to %s\n",pathname,linkname);
+      }
+
+   //printf("The mode of %s is %o\n\n",pathname,statbuf.st_mode & 07777);
+   }
+
+   closedir(dirh);
+
+  Limit = Names.size() < FLIP_DEPTH ? 0 : Names.size() - FLIP_DEPTH;
+
+}
+
+// -----------------------------------------------------------------------------
+
+
+
+int main(int argc,char **argv)
+{
+    byte *sageBuffer = NULL;  // buffer for sage
+    unsigned int width, height;  // image size
+    unsigned int window_width=0, window_height=0;  // sage window size
+
+
+    // parse command line arguments
+    if (argc < 2){
+	fprintf(stderr, "\n\nUSAGE: imageflip directory [width] [height]");
+	return 0;
+    }
+    for (int argNum=2; argNum<argc; argNum++)
+    {
+	if(atoi(argv[argNum]) != 0 && atoi(argv[argNum+1]) != 0) {
+	    window_width = atoi( argv[argNum] );
+	    window_height = atoi( argv[argNum+1] );
+	    argNum++;  // increment because we read two args here
+	}
+    }
+
+
+    // check file extension
+    string dirName;
+    dirName = string(argv[1]);
+
+
+		// Populate the filename list
+	RefreshList(dirName);
+
+   cout << Names.size() << " elements in the set" << endl;
+
+
+	// List the names
+  set<string>::iterator it;
+  int k =0;
+  for ( it = Names.begin() ; k < Limit ; it++ ) {k++;}
+  for ( ; it != Names.end(); it++ )
+    cout << " " << *it << endl;
+
+   // last element
+    cout << "Last element: " << *(Names.rbegin()) << endl;
+
+    string firstname = *( Names.begin() );
+
+    // if the user didn't specify the window size, use the image size
+    if (window_height == 0 && window_width == 0)
+    {
+	// Get the dimensions of the first file
+        getDimensions(firstname ,  width, height);
+	window_width = width;
+	window_height = height;
+	cout << "Dimensions of image series: " << window_width << "x" << window_height << endl;
+    }
+
+    // initialize SAIL
+    sail sageInf; // sail object
+    sailConfig scfg;
+    scfg.init("imageflip.conf");
+    scfg.setAppName("imageflip");
+
+    scfg.resX = width;
+    scfg.resY = height;
+
+    if (scfg.winWidth == -1 || scfg.winHeight == -1)
+    {
+	scfg.winWidth = window_width;
+	scfg.winHeight = window_height;
+    }
+
+    scfg.pixFmt = PIXFMT_888;
+    scfg.rowOrd = TOP_TO_BOTTOM;
+
+    sageInf.init(scfg);
+
+
+    // get buffer from SAGE and fill it with data
+    sageBuffer = (byte*)sageInf.getBuffer();
+	// Get some pixels
+    getRGB(firstname, sageBuffer, width, height);
+    sageInf.swapBuffer();
+
+	// Rewind
+    k = 0;
+    for ( it = Names.begin() ; k < Limit ; it++ ) {k++;}
+
+	// Wait the end
+    while (1)
+    {
+	if (it == Names.end()) {
+		// Rewind
+		k = 0;
+		for ( it = Names.begin() ; k < Limit ; it++ ) {k++;}
+	}
+
+		// get buffer from SAGE and fill it with data
+	sageBuffer = (byte*)sageInf.getBuffer();
+		// Get some pixels
+	getRGB(*it, sageBuffer, width, height);
+	cerr << "Getting " << *it << "\r";  // endl;
+	sageInf.swapBuffer();
+		// Next step
+	it++;
+
+		// Refresh the filename list
+	RefreshList(dirName);
+
+		// Process SAGE messages
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+	    switch (msg.getCode()) {
+	    case APP_QUIT:
+		cout << "\nDone\n\n";
+		sageInf.shutdown();
+		exit(1);
+		break;
+	    }
+	}
+    }
+
+    return 0;
+}
Index: trunk/src/testing/app/ImageFlip/util.cpp
===================================================================
--- trunk/src/testing/app/ImageFlip/util.cpp	(revision 4)
+++ trunk/src/testing/app/ImageFlip/util.cpp	(revision 4)
@@ -0,0 +1,357 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+void aLog(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+}
+
+void aError(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+
+    exit(1);
+}
+
+
+
+void* aAlloc(size_t const n)
+{
+	void* result;
+#if defined(WIN32)
+	result = LocalAlloc(0,n);
+#else
+	result = malloc(n);
+#endif
+	// Filling with zeros
+	memset(result, 0, n);
+
+	if(!result)
+		aError("Aura: not enough memory for %d bytes",n);
+	return result;
+}
+
+void aFree(void* const p)
+{
+#if defined(WIN32)
+	LocalFree(p);
+#else
+	if (p)
+        free(p);
+    else
+        aError("Alloc> Trying to free a NULL pointer\n");
+#endif
+}
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
+/// File findind
+// From Nvidia toolkit
+
+using namespace std;
+
+string data_path::get_path(std::string filename)
+{
+  FILE* fp;
+  bool found = false;
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+	  break;
+        }
+    }
+
+  if (found == false)
+    {
+      path_name = filename;
+      fp = ::fopen(path_name.c_str(),"r");
+      if (fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+        }
+    }
+
+  if (found == false)
+    return "";
+
+  int loc = path_name.rfind('\\');
+  if (loc == -1)
+    {
+      loc = path_name.rfind('/');
+    }
+
+  if (loc != -1)
+    file_path = path_name.substr(0, loc);
+  else
+    file_path = ".";
+  return file_path;
+}
+
+string data_path::get_file(std::string filename)
+{
+  FILE* fp;
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  return path_name;
+        }
+    }
+
+  path_name = filename;
+  fp = ::fopen(path_name.c_str(),"r");
+  if (fp != 0)
+    {
+      fclose(fp);
+      return path_name;
+    }
+  return "";
+}
+
+// data files, for read only
+FILE * data_path::fopen(std::string filename, const char * mode)
+{
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+      FILE * fp = ::fopen(s.c_str(), mode);
+
+      if(fp != 0)
+	return fp;
+      else if (!strcmp(path[i].c_str(),""))
+	{
+	  FILE* fp = ::fopen(filename.c_str(),mode);
+	  if (fp != 0)
+	    return fp;
+	}
+    }
+  // no luck... return null
+  return 0;
+}
+
+//  fill the file stats structure
+//  useful to get the file size and stuff
+int data_path::fstat(std::string filename,
+#ifdef WIN32
+		     struct _stat
+#else
+		     struct stat
+#endif
+		     * stat)
+{
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+#ifdef WIN32
+      int fh = ::_open(s.c_str(), _O_RDONLY);
+#else
+      int fh = ::open(s.c_str(), O_RDONLY);
+#endif
+      if(fh >= 0)
+        {
+#ifdef WIN32
+	  int result = ::_fstat( fh, stat );
+#else
+	  int result = ::fstat (fh,stat);
+#endif
+	  if( result != 0 )
+            {
+	      fprintf( stderr, "An fstat error occurred.\n" );
+	      return 0;
+            }
+#ifdef WIN32
+	  ::_close( fh );
+#else
+	  ::close (fh);
+#endif
+	  return 1;
+    	}
+    }
+  // no luck...
+  return 0;
+}
+
Index: trunk/src/testing/app/ImageFlip/imageflip.conf
===================================================================
--- trunk/src/testing/app/ImageFlip/imageflip.conf	(revision 4)
+++ trunk/src/testing/app/ImageFlip/imageflip.conf	(revision 4)
@@ -0,0 +1,17 @@
+fsIP 67.58.62.100
+fsPort 20002
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 10
+winY 10
+winWidth 1600
+winHeight 1200
+syncMode 0
+nwProtocol TCP
+asyncUpdate true
Index: trunk/src/testing/app/ImageFlip/util.h
===================================================================
--- trunk/src/testing/app/ImageFlip/util.h	(revision 4)
+++ trunk/src/testing/app/ImageFlip/util.h	(revision 4)
@@ -0,0 +1,123 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <set>
+#include <string>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
+// From NVIDIA Toolkit
+
+#ifndef DATA_PATH_H
+#define DATA_PATH_H
+
+class data_path
+{
+public:
+  std::string              file_path;
+  std::string              path_name;
+  std::vector<std::string> path;
+
+  std::string get_path(std::string filename);
+  std::string get_file(std::string filename);
+
+  FILE *fopen(std::string filename, const char * mode = "rb");
+
+#ifdef WIN32
+  int fstat(std::string filename, struct _stat * stat);
+#else
+  int fstat(std::string filename, struct stat * stat);
+#endif
+};
+
+#endif
+
Index: trunk/src/testing/app/dxt/Makefile
===================================================================
--- trunk/src/testing/app/dxt/Makefile	(revision 4)
+++ trunk/src/testing/app/dxt/Makefile	(revision 4)
@@ -0,0 +1,34 @@
+include ../../config.mk
+
+###################################################################
+# Makefile for dxt
+###################################################################
+
+CFLAGS=-fPIC -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(QUANTA_LIB) $(GLEW_LIB) -L../../lib -lsail
+CC=$(COMPILER)
+
+PROGRAM = dxt
+#FILES= dxt.o app.o
+FILES= app2.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(COMPILER) -o $(PROGRAM) $(FILES) $(LIBS)
+
+dxt.o: dxt.cpp
+	$(COMPILER) $(CFLAGS) -c dxt.cpp
+
+app.o: app.cpp
+	$(COMPILER) $(CFLAGS) -c app.cpp
+
+app2.o: app2.cpp
+	$(COMPILER) $(CFLAGS) -c app2.cpp
+
+clean:
+	\rm -f *~ *.o $(PROGRAM)
+
Index: trunk/src/testing/app/dxt/README
===================================================================
--- trunk/src/testing/app/dxt/README	(revision 4)
+++ trunk/src/testing/app/dxt/README	(revision 4)
@@ -0,0 +1,6 @@
+
+To run:
+   ./dxt <widht> <height> <filename>
+
+   ./dxt 256 256 ../app/dxt/lena-dxt1-256.dxt
+
Index: trunk/src/testing/app/dxt/dxt.cpp
===================================================================
--- trunk/src/testing/app/dxt/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/dxt/dxt.cpp	(revision 4)
@@ -0,0 +1,284 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+
+byte *globalOutData;
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+word ColorTo565( const byte *color );
+void EmitByte( byte b );
+void EmitWord( word s );
+void EmitDoubleWord( dword i );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor );
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+#if 0
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+#else
+  byte block[64];
+  byte minColor[4];
+  byte maxColor[4];
+#endif
+
+  globalOutData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+      ExtractBlock( inBuf + i * 4, width, block );
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+      EmitWord( ColorTo565( maxColor ) );
+      EmitWord( ColorTo565( minColor ) );
+      EmitColorIndicesFast( block, minColor, maxColor );
+    }
+  }
+  outputBytes = globalOutData - outBuf;
+}
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b )
+{
+  globalOutData[0] = b;
+  globalOutData += 1;
+}
+
+void EmitWord( word s )
+{
+  globalOutData[0] = ( s >> 0 ) & 255;
+  globalOutData[1] = ( s >> 8 ) & 255;
+  globalOutData += 2;
+}
+
+void EmitDoubleWord( dword i )
+{
+  globalOutData[0] = ( i >> 0 ) & 255;
+  globalOutData[1] = ( i >> 8 ) & 255;
+  globalOutData[2] = ( i >> 16 ) & 255;
+  globalOutData[3] = ( i >> 24 ) & 255;
+  globalOutData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result );
+}
Index: trunk/src/testing/app/dxt/app.cpp
===================================================================
--- trunk/src/testing/app/dxt/app.cpp	(revision 4)
+++ trunk/src/testing/app/dxt/app.cpp	(revision 4)
@@ -0,0 +1,187 @@
+/******************************************************************************
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+
+//A simple test program that pushes DXT pixels to SAGE frame buffer
+//written by Luc Renambot
+//Feb 2007
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include "dxt.h"
+#include <wand/magick_wand.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+#define ThrowWandException(wand)                \
+  {                                             \
+    char                                        \
+      *description;                             \
+                                                \
+    ExceptionType                               \
+      severity;                                 \
+                                                    \
+    description=MagickGetException(wand,&severity);                     \
+    (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \
+    description=(char *) MagickRelinquishMemory(description);           \
+    exit(-1);                                                           \
+  }
+
+
+int main(int argc, char *argv[])
+{
+    sail sageInf; // sail object
+    int nodeID;
+
+    byte *in;
+    int nbbytes;
+
+    nodeID = 0;
+
+    /*
+      Read an image.
+    */
+    MagickBooleanType status;
+    MagickWand *magick_wand;
+
+    int count = 1;
+    int framenb = atoi(argv[2]);
+    char fn[256];
+
+    memset(fn, 0, 256);
+    sprintf(fn, "%s/%08d.tga", argv[1], count++);
+
+    magick_wand=NewMagickWand();
+    status=MagickReadImage(magick_wand, fn);
+    if (status == MagickFalse)
+        ThrowWandException(magick_wand);
+
+    unsigned long width = MagickGetImageWidth(magick_wand);
+    unsigned long height = MagickGetImageHeight(magick_wand);
+
+    int resX = width;
+    int resY = height;
+
+    std::cout << "File = " << argv[1] << std::endl;
+    std::cout << std::endl << "ResX = " << resX << "  ResY = " << resY << std::endl;
+
+    in = (byte*)malloc(width*height*4);
+    memset(in, 0, width*height*4);
+
+    fprintf(stderr, "Converting to raw: %ldx%ld\n", width, height);
+    MagickGetImagePixels(magick_wand, 0, 0, width, height, "RGBA", CharPixel, in);
+
+    sailConfig scfg;
+    scfg.init("dxt.conf");
+    scfg.setAppName("dxt");
+    scfg.rank = nodeID;
+
+    scfg.resX = resX;
+    scfg.resY = resY;
+
+    sageRect renderImageMap;
+    renderImageMap.left = 0.0;
+    renderImageMap.right = 1.0;
+    renderImageMap.bottom = 0.0;
+    renderImageMap.top = 1.0;
+
+    scfg.imageMap = renderImageMap;
+    scfg.pixFmt = PIXFMT_DXT;
+    //scfg.rowOrd = TOP_TO_BOTTOM;
+    scfg.rowOrd = BOTTOM_TO_TOP;
+    scfg.master = true;
+    scfg.nwID = 1;
+
+    sageInf.init(scfg);
+    std::cout << "sail initialized " << std::endl;
+
+
+    void *buffer = sageInf.getBuffer();
+    nbbytes = 0;
+    CompressImageDXT1( in, (byte*)buffer, width, height, nbbytes);
+
+    sageInf.swapBuffer();
+    buffer = sageInf.getBuffer();
+
+
+    while(1) {
+        fprintf(stderr, "Frame %d\n", count);
+        memset(fn, 0, 256);
+        sprintf(fn, "%s/%08d.tga", argv[1], count);
+        count = (count + 1) % framenb;
+        if (count == 0) count = 1;
+
+        MagickRemoveImage(magick_wand);
+        status=MagickReadImage(magick_wand, fn);
+        if (status == MagickFalse)
+            ThrowWandException(magick_wand);
+        MagickGetImagePixels(magick_wand, 0, 0, width, height, "RGBA", CharPixel, in);
+
+        nbbytes = 0;
+        CompressImageDXT1( in, (byte*)buffer, width, height, nbbytes);
+#if 0
+        memset(fn, 0, 256);
+        sprintf(fn, "%s/%08d.dxt", argv[1], count);
+        FILE *f=fopen(fn, "w+");
+        int res=fwrite(buffer, 1, nbbytes, f);
+        fclose(f);
+#endif
+	sageInf.swapBuffer();
+	buffer = sageInf.getBuffer();
+
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+	    switch (msg.getCode()) {
+		case APP_QUIT : {
+		    sageInf.shutdown();
+		    exit(0);
+		    break;
+		}
+	    }
+	}
+
+    }
+
+    magick_wand=DestroyMagickWand(magick_wand);
+    MagickWandTerminus();
+
+    return 0;
+}
Index: trunk/src/testing/app/dxt/app2.cpp
===================================================================
--- trunk/src/testing/app/dxt/app2.cpp	(revision 4)
+++ trunk/src/testing/app/dxt/app2.cpp	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+//A simple test program that pushes DXT pixels to SAGE frame buffer
+//written by Luc Renambot
+//Feb 2007
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+int main(int argc, char *argv[])
+{
+    sail sageInf; // sail object
+    int nodeID;
+    char fn[256];
+    FILE *fin;
+
+    nodeID = 0;
+
+    int resX = atoi(argv[1]);
+    int resY = atoi(argv[2]);
+
+    GLsizei sz = 8 * (resX / 4) * (resY / 4);
+
+    std::cout << std::endl << "ResX = " << resX << "  ResY = " << resY << std::endl;
+    std::cout << "File = " << argv[3] << std::endl;
+
+    sailConfig scfg;
+    scfg.init("dxt.conf");
+    scfg.setAppName("dxt");
+    scfg.rank = nodeID;
+
+    scfg.resX = resX;
+    scfg.resY = resY;
+
+    sageRect renderImageMap;
+    renderImageMap.left = 0.0;
+    renderImageMap.right = 1.0;
+    renderImageMap.bottom = 0.0;
+    renderImageMap.top = 1.0;
+
+    scfg.imageMap = renderImageMap;
+    scfg.pixFmt = PIXFMT_DXT;
+    scfg.rowOrd = BOTTOM_TO_TOP;
+    scfg.master = true;
+    scfg.nwID = 1;
+
+    sageInf.init(scfg);
+    std::cout << "sail initialized " << std::endl;
+
+    void *buffer, *pix;
+
+    pix = malloc(sz);
+    memset(pix, 0, sz);
+	 int dummy_w, dummy_h;
+    fin = fopen(argv[3], "rb");
+	 fread(&dummy_w, 1, sizeof(int), fin);
+	 fread(&dummy_h, 1, sizeof(int), fin);
+    fread(pix, 1, sz, fin);
+    fclose(fin);
+
+
+    while(1) {
+
+	buffer = sageInf.getBuffer();
+	memcpy(buffer, pix, sz);
+
+    sageInf.swapBuffer();
+    sageMessage msg;
+
+		if (sageInf.checkMsg(msg, false) > 0) {
+      		  switch (msg.getCode()) {
+               		 case APP_QUIT : {
+                     		  exit(0);
+                     		  break;
+               		}
+      		  }
+		}
+	}
+
+    return 0;
+}
Index: trunk/src/testing/app/dxt/dxt.h
===================================================================
--- trunk/src/testing/app/dxt/dxt.h	(revision 4)
+++ trunk/src/testing/app/dxt/dxt.h	(revision 4)
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
Index: trunk/src/testing/app/py_sail/README
===================================================================
--- trunk/src/testing/app/py_sail/README	(revision 4)
+++ trunk/src/testing/app/py_sail/README	(revision 4)
@@ -0,0 +1,64 @@
+-----------------------------------------------------
+
+     PY_SAIL - write SAGE applications in python
+
+-----------------------------------------------------
+Author: Ratko Jagodic
+Last Update: April 19, 2007 (updated for SAGE 2)
+
+
+
+
+	PREREQUISITES:
+----------------------------------------------------
+- python (any fairly recent version should work)
+- gcc compiler
+- compiled SAGE and the $SAGE_DIRECTORY 
+  environment variable set up
+
+
+
+	HOW TO INSTALL:
+----------------------------------------------------
+- run the "install_me" script
+- this will create the py_sail.so and put it into 
+  $SAGE_DIRECTORY/lib
+- it may also create another file ending in .egg-info
+  (if it's there, leave it, if not, don't worry)
+
+
+
+	RUN THE TEST EXAMPLE:
+----------------------------------------------------
+- test.py is an example of how to write your applications
+  with py_sail
+- since this is python, there is no need to install the 
+  example but you still need to configure it
+- in your $SAGE_DIRECTORY/bin/appLauncher/sage.conf add
+  something like this (change the paths of course):
+
+pysail_test {
+configName test
+nodeNum 1
+Init 100 100 600 600
+exec 127.0.0.1 python /home/evl/rjagodic/sage2/app/py_sail/test.py
+nwProtocol tvTcpModule.so
+binDir /home/evl/rjagodic/sage2/app/py_sail
+staticApp
+}
+
+- now you can run the test from the SAGE UI by clicking 
+  on its icon and a small rectangle with a gradient
+  should show up on your SAGE display
+
+
+
+	WRITE YOUR OWN APPLICATIONS WITH PY_SAIL:
+----------------------------------------------------
+- the main steps go something like this:
+
+(1) import py_sail
+(2) initialize your application with py_sail.initSail()
+(3) get your buffer and send it to py_sail with py_sail.setBuffer()
+    (you use this function every time you want to swap a buffer)
+(4) check for sail messages with py_sail.checkMessages()
Index: trunk/src/testing/app/py_sail/py_sail.cpp
===================================================================
--- trunk/src/testing/app/py_sail/py_sail.cpp	(revision 4)
+++ trunk/src/testing/app/py_sail/py_sail.cpp	(revision 4)
@@ -0,0 +1,205 @@
+/*****************************************************************************************
+ * py_sail: A library that allows you to use SAIL from python (ie write SAGE apps with python)
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about py_sail to www.evl.uic.edu/cavern/forum
+ *
+ * Author: Ratko Jagodic
+ *
+ *****************************************************************************************/
+
+
+#include <Python.h>
+#include <iostream>
+
+// sage headers
+#include <sail.h>
+#include <misc.h>
+
+
+
+using namespace std;
+
+
+// SAGE Stuff
+sail sageInf; // sail object
+sailConfig scfg;
+sageRect renderImageMap;
+unsigned char *buffer = NULL;
+
+
+// prototypes
+static PyObject* initSail(PyObject *self, PyObject *args);
+static PyObject* setBuffer(PyObject *self, PyObject *args);
+static PyObject* checkMessages(PyObject *self, PyObject *args);
+PyMODINIT_FUNC initpy_sail(void);
+
+
+
+//-----------------------------------------------------------------------
+
+
+
+// all the methods callable from Python have to be
+// listed here
+static PyMethodDef PySailMethods[] = {
+    {"initSail",  initSail, METH_VARARGS,
+     "Initialize Sail Python interface."},
+
+    {"setBuffer", setBuffer, METH_VARARGS,
+     "Receives the buffer from python."},
+
+    {"checkMessages", checkMessages, METH_VARARGS,
+     "Checks for new sail messages from SAGE."},
+
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+
+// this function is called when we do import py_sail from python
+// it let's the python interpreter know about all the functions
+// in this module available for calling
+PyMODINIT_FUNC initpy_sail(void)
+{
+    (void) Py_InitModule("py_sail", PySailMethods);
+}
+
+
+
+//-----------------------------------------------------------------------
+
+
+
+// initializes the sail object from python
+static PyObject* initSail(PyObject *self, PyObject *args)
+{
+    char *appName;
+    char confName[128];
+    int width, height;
+
+    // parse the arguments
+    if (!PyArg_ParseTuple(args, "sii", &appName, &width, &height))
+        return NULL;
+
+    // initialize sail and sage stuff
+    renderImageMap.left = 0.0;
+    renderImageMap.right = 1.0;
+    renderImageMap.bottom = 0.0;
+    renderImageMap.top = 1.0;
+    scfg.imageMap = renderImageMap;
+
+    // the config name should be "appName.conf"
+    strcpy(confName, appName);
+    strcat(confName, ".conf");
+    fprintf(stderr, "\n\nSAIL CONFIG FILE BEING USED: %s", confName);
+
+    scfg.init(confName);
+    scfg.setAppName(appName);  // case sensitive
+    scfg.rank = 0;
+
+    scfg.resX = width;
+    scfg.resY = height;
+
+    scfg.pixFmt = PIXFMT_888;
+    scfg.rowOrd = TOP_TO_BOTTOM;
+    scfg.master = true;
+
+    sageInf.init(scfg);
+    // return none
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
+
+// receives the buffer and swaps it via sail object
+static PyObject* setBuffer(PyObject *self, PyObject *args)
+{
+    int bufSize;
+    unsigned char *pybuf = NULL;
+
+    // parse the arguments
+    if (!PyArg_ParseTuple(args, "s#", &pybuf, &bufSize))
+    {
+      cout << "py_sail.so:  ParseTuple failed..." << endl;
+      return NULL;
+    }
+
+    // if something went wrong so just return None
+    if (pybuf == NULL)
+      {
+	cout << "\n\npy_sail.so:  Buffer received from Python is NULL... returning without swapBuffer\n\n";
+	Py_INCREF(Py_None);
+	return Py_None;
+      }
+
+    // finally, swap the buffer via sail
+    buffer = (unsigned char *) sageInf.getBuffer();  // get the new buffer from sage first
+    memcpy(buffer, pybuf, scfg.resX*scfg.resY*3);
+    sageInf.swapBuffer();
+
+    // this function returns None
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
+/* checks for messages sent from SAGE
+ defined messages and their return values (to the python program):
+
+ APP_QUIT    -1
+
+*/
+static PyObject* checkMessages(PyObject *self, PyObject *args)
+{
+  sageMessage msg;
+  int returnVal = 0;
+  if (sageInf.checkMsg(msg, false) > 0)
+    {
+      switch (msg.getCode()) {
+	  case APP_QUIT : {
+	    returnVal = -1;
+	    break;
+	  }
+       }
+    }
+
+  if (returnVal == 0)
+    {
+      Py_INCREF(Py_None);
+      return Py_None;
+    }
+  else
+    return Py_BuildValue("i", returnVal);
+}
Index: trunk/src/testing/app/py_sail/test.py
===================================================================
--- trunk/src/testing/app/py_sail/test.py	(revision 4)
+++ trunk/src/testing/app/py_sail/test.py	(revision 4)
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+############################################################################
+#
+# py_sail: An example of how to write SAGE applications using python and py_sail
+#
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+import os, sys, time, array
+
+
+# for importing py_sail properly
+sys.path.append(os.environ["SAGE_DIRECTORY"]+"/lib")
+import py_sail
+
+
+# size of SAGE buffer for this app
+BUFFER_WIDTH = 200
+BUFFER_HEIGHT = 200
+
+
+# initialize sail with appName, buffer width and height
+py_sail.initSail("pysail_test", BUFFER_WIDTH, BUFFER_HEIGHT)
+
+
+# make a pixel array of size BUFFER_WIDTH * BUFFER_HEIGHT * 3
+a = array.array('B')            # unsigned char type
+numPixels = BUFFER_WIDTH * BUFFER_HEIGHT
+for i in xrange(0, BUFFER_WIDTH * BUFFER_HEIGHT):
+    p = 1-i/float(numPixels)
+    a.append(int(p*255)); a.append(int(p*255)); a.append(int(p*255))  #R,G,B
+
+
+# convert the array to a string and send it to py_sail
+buf = a.tostring()
+py_sail.setBuffer(buf)
+
+
+# keep looping and checking for the quit message
+# you could also swap buffers here if you need 
+# to update the image
+while True:
+    time.sleep(0.5)
+    msg = py_sail.checkMessages()
+    if msg == -1:    # -1 is returned when SAGE wants to close the app
+        print "quitting..."
+        break
Index: trunk/src/testing/app/py_sail/install_me
===================================================================
--- trunk/src/testing/app/py_sail/install_me	(revision 4)
+++ trunk/src/testing/app/py_sail/install_me	(revision 4)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# build the py_sail library and put it in the correct place (SAGE_DIRECTORY/lib)
+echo "building py_sail library"
+python setup.py install --install-lib=$SAGE_DIRECTORY/lib
+
Index: trunk/src/testing/app/py_sail/setup.py
===================================================================
--- trunk/src/testing/app/py_sail/setup.py	(revision 4)
+++ trunk/src/testing/app/py_sail/setup.py	(revision 4)
@@ -0,0 +1,52 @@
+##################################################################################
+# Copyright (C) 2007 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about SAGE UI to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#        
+##################################################################################
+
+from distutils.core import setup, Extension
+import os
+
+sageDir = os.environ["SAGE_DIRECTORY"]
+
+module1 = Extension('py_sail',
+                    include_dirs = [sageDir + '/include'],
+                    libraries = ['sail'],
+                    library_dirs = [sageDir + '/lib'],
+                    sources = ['py_sail.cpp'])
+
+setup (name = 'py_sail',
+       version = '0.2',
+       author = 'Ratko Jagodic',
+       description = 'This is a python-sail interface that enables you to use python for SAGE apps',
+       ext_modules = [module1])
Index: trunk/src/testing/app/FileViewer/ImageViewer/intrinsic.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/util.h
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/util.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/util.h	(revision 4)
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/dxt.h
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/dxt.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/dxt.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app/FileViewer/ImageViewer/imageviewer.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/imageviewer.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/imageviewer.cpp	(revision 4)
@@ -0,0 +1,361 @@
+/*****************************************************************************************
+ * imageviewer: loads an image and sends it to SAGE for display
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to www.evl.uic.edu/cavern/forum
+ *
+ * Author: Ratko Jagodic, Luc Renambot
+ *
+ *****************************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <time.h>
+#include <unistd.h>
+#include <wand/magick-wand.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+
+//#if MagickLibVersion >= 0x645
+//#define MagickGetImagePixels MagickGetAuthenticPixels
+//#endif
+
+
+#ifdef USE_DXT
+
+// for dxt compression
+#include "libdxt.h"
+// if true, it will show the original image and not the dxt compressed one
+bool loadDXT = true;
+
+#else
+
+bool loadDXT = false;
+typedef unsigned char byte;
+#define memalign(x,y) malloc((y))
+
+#endif
+
+
+using namespace std;
+
+
+#define ThrowWandException(wand)		\
+  {						\
+    char					\
+      *description;				\
+						\
+    ExceptionType				\
+      severity;					\
+						    \
+    description=MagickGetException(wand,&severity);			\
+    (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \
+    description=(char *) MagickRelinquishMemory(description);		\
+    exit(-1);								\
+  }
+
+
+// -----------------------------------------------------------------------------
+
+#ifdef USE_DXT
+void readDXT(string fileName, byte **buffer, unsigned int &width,
+	     unsigned int &height)
+{
+    unsigned long r;
+    unsigned int numBytes;
+    FILE *f = fopen(fileName.data(), "rb");
+
+    // read the size of the image from the first 8 bytes
+    r = fread(&width, sizeof(unsigned int), 1, f);
+    r = fread(&height, sizeof(unsigned int), 1, f);
+    r = fread(&numBytes, sizeof(unsigned int), 1, f);
+
+    // allocate buffer size and read the rest of the file into it
+    *buffer = (byte*) malloc(width*height*4/8);
+    memset(*buffer, 0, width*height*4/8);
+    r = fread(*buffer, 1, width*height*4/8, f);
+    fclose(f);
+}
+
+
+void writeDXT(string fileName, byte *buffer, unsigned int width,
+	      unsigned int height, unsigned int numBytes)
+{
+    fprintf(stderr, "\n**** Writing DXT to file... %u bytes", numBytes);
+
+    unsigned long r;
+    FILE *f = fopen(fileName.data(), "wb");
+
+    if (f != NULL)
+    {
+	// write the size of the image in the first 8 bytes
+	r = fwrite(&width, sizeof(unsigned int), 1, f);
+	r = fwrite(&height, sizeof(unsigned int), 1, f);
+	r = fwrite(&numBytes, sizeof(unsigned int), 1, f);
+
+	// write the buffer out to the file
+	r = fwrite(buffer, 1, numBytes, f);
+	fclose(f);
+    }
+    else
+	fprintf(stderr, "\n**** Imageviewer ERROR: Unable to write DXT file. Check dir permissions.\n");
+}
+#endif
+
+
+void getRGBA(string fileName, byte **rgba, unsigned int &width,
+	      unsigned int &height)
+{
+    // use ImageMagick to read all other formats
+    MagickBooleanType status;
+    MagickWand *wand;
+
+    // read file
+    wand=NewMagickWand();
+    status=MagickReadImage(wand, fileName.data());
+    if (status == MagickFalse)
+	ThrowWandException(wand);
+
+    // get the image size
+    width = MagickGetImageWidth(wand);
+    height = MagickGetImageHeight(wand);
+
+    // crop the image if necessary to make sure it's a multiple of 4
+    if (loadDXT)
+    {
+	if (width%4 != 0 || height%4 != 0)
+	{
+	    fprintf(stderr, "\n**** Image cropped a few pixels to be a multiple of 4 for dxt");
+	    width -= width%4;
+	    height -= height%4;
+	}
+
+	// flip the image to have the correct orientation for dxt
+	MagickFlipImage(wand);
+    }
+
+    // get the pixels
+    *rgba = (byte*) memalign(16, width*height*4);
+    memset(*rgba, 0, width*height*4);
+    MagickGetImagePixels(wand, 0, 0, width, height, "RGBA", CharPixel, *rgba);
+    DestroyMagickWand(wand);
+}
+
+#ifdef USE_DXT
+void rgbaToDXT(string fileName, byte **rgba, byte **dxt, unsigned int width,
+	       unsigned int height)
+{
+    unsigned int numBytes;
+
+    // compress into DXT
+    *dxt = (byte*) memalign(16, width*height*4/8);
+    memset(*dxt, 0, width*height*4/8);
+    numBytes = CompressDXT(*rgba, *dxt, width, height, FORMAT_DXT1, 1);
+
+    // write this DXT out to a file (change extension to .dxt)
+    string dxtFileName = string(fileName);
+    dxtFileName.resize(fileName.rfind("."));
+    dxtFileName += ".dxt";
+    writeDXT(dxtFileName, *dxt, width, height, numBytes);
+}
+
+
+bool dxtFileExists(string fileName)
+{
+    // replace the extension with .dxt
+    string dxtFileName = string(fileName);
+    dxtFileName.resize(fileName.rfind("."));
+    dxtFileName += ".dxt";
+
+    // check whether the file exists by trying to open it
+    FILE *dxtFile = fopen(dxtFileName.data(), "r");
+    if ( dxtFile == NULL)
+    {
+	fprintf(stderr, "\nDXT file for %s doesn't exist yet.", fileName.data());
+	return false;
+    }
+    else
+    {
+	fclose(dxtFile);
+	return true;
+    }
+}
+#endif
+
+// -----------------------------------------------------------------------------
+
+
+
+int main(int argc,char **argv)
+{
+    byte *sageBuffer = NULL;  // buffers for sage and dxt data
+    byte *dxt = NULL;
+    byte *rgba = NULL;
+    unsigned int width, height;  // image size
+    unsigned int window_width=0, window_height=0;  // sage window size
+
+
+    // parse command line arguments
+    if (argc < 2){
+	fprintf(stderr, "\n\nUSAGE: imageviewer filename [width] [height] [-show_original]");
+	return 0;
+    }
+    for (int argNum=2; argNum<argc; argNum++)
+    {
+	if (strcmp(argv[argNum], "-show_original") == 0) {
+	    loadDXT = false;
+	}
+	else if(atoi(argv[argNum]) != 0 && atoi(argv[argNum+1]) != 0) {
+	    window_width = atoi( argv[argNum] );
+	    window_height = atoi( argv[argNum+1] );
+	    argNum++;  // increment because we read two args here
+	}
+    }
+
+
+    // check file extension
+    string fileName, fileExt;
+    fileName = string(argv[1]);
+    fileExt = fileName.substr(fileName.rfind("."));
+
+    // if image is in DXT load it directly, otherwise compress and load
+    if(fileExt.compare(".dxt") == 0)   // DXT
+#ifndef USE_DXT
+    {
+	fprintf(stderr, "\n\nImageviewer was not compiled with DXT option\n");
+	exit(0);
+    }
+#else
+	readDXT(fileName, &dxt, width, height);
+
+    else if(loadDXT && dxtFileExists(fileName))
+    {
+	// replace the extension with .dxt and read the file
+	string dxtFileName = string(fileName);
+	dxtFileName.resize(fileName.rfind("."));
+	dxtFileName += ".dxt";
+	readDXT(dxtFileName, &dxt, width, height);
+    }
+#endif
+    else                               // all other image formats
+    {
+	getRGBA(fileName, &rgba, width, height);
+	#ifdef USE_DXT
+	if (loadDXT)
+	{
+	    rgbaToDXT(fileName, &rgba, &dxt, width, height);
+	    free(rgba);
+	    rgba = NULL;
+	}
+	#endif
+    }
+
+    // if the user didn't specify the window size, use the image size
+    if (window_height == 0 && window_width == 0)
+    {
+	window_width = width;
+	window_height = height;
+    }
+
+    // initialize SAIL
+    sail sageInf; // sail object
+    sailConfig scfg;
+    scfg.init("imageviewer.conf");
+    scfg.setAppName("imageviewer");
+
+    scfg.resX = width;
+    scfg.resY = height;
+
+    if (scfg.winWidth == -1 || scfg.winHeight == -1)
+    {
+	scfg.winWidth = window_width;
+	scfg.winHeight = window_height;
+    }
+
+    if (loadDXT)
+    {
+	scfg.pixFmt = PIXFMT_DXT;
+	scfg.rowOrd = BOTTOM_TO_TOP;
+    }
+    else
+    {
+	scfg.pixFmt = PIXFMT_8888;
+	scfg.rowOrd = TOP_TO_BOTTOM;
+    }
+    sageInf.init(scfg);
+
+
+    // get buffer from SAGE and fill it with dxt data
+    sageBuffer = (byte*)sageInf.getBuffer();
+    if (loadDXT)
+	memcpy(sageBuffer, dxt, width*height*4/8);
+    else
+	memcpy(sageBuffer, rgba, width*height*4);
+    sageInf.swapBuffer();
+
+    // a second time for the backbuffer
+    /* doesn't need with END_FRAME fix
+    sageBuffer = (byte*)sageInf.getBuffer();
+    if (loadDXT)
+	memcpy(sageBuffer, dxt, width*height*4/8);
+    else
+	memcpy(sageBuffer, rgba, width*height*4);
+    sageInf.swapBuffer();
+    */
+
+    // release the memory
+    free(dxt);
+    free(rgba);
+
+
+    // Wait the end
+    while (1)
+    {
+	usleep(500000);  // so that we don't keep spinning too frequently (0.5s)
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+	    switch (msg.getCode()) {
+	    case APP_QUIT:
+		sageInf.shutdown();
+		exit(1);
+		break;
+	    }
+	}
+    }
+
+    return 0;
+}
Index: trunk/src/testing/app/FileViewer/ImageViewer/libdxt.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/libdxt.cpp	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app/FileViewer/ImageViewer/dirToDxt.py
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/dirToDxt.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/dirToDxt.py	(revision 4)
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+############################################################################
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc  to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+
+
+#
+# Processes all the images in the passed in directory name and converts
+# them to DXT using a imgToDxt
+#
+# Call with: python dirToDxt.py dirName
+#
+# Author: Ratko Jagodic
+#
+
+import os, sys, os.path
+
+if len(sys.argv) < 2:
+    print "\nUsage: python dirToDxt.py directoryName\n"
+    sys.exit(0)
+
+count = 0
+skippedDirs = []
+for root, dirs, files in os.walk(sys.argv[1]):
+
+    # skip dir if we have no write permissions
+    if not os.access(root, os.W_OK):
+        skippedDirs.append(root)
+        print "\n***** No write permissions. Skipping ", root
+        continue
+    
+    for name in files:
+        # skip existing dxt files
+        if name.endswith(".dxt"):
+            continue
+        
+        count += 1
+        filePath = os.path.abspath(os.path.join(root, name))
+        print "\n\n#",count, "   -------------- ", filePath, " ---------------"
+        cmd = "imgToDxt '%s'" % filePath
+        os.system(cmd)
+
+
+print "\n\n", 10 * "------"
+print "Directories skipped due to insufficient write permissions:\n"
+for d in skippedDirs:
+    print d
+print "\n"
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/libdxt.h
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/libdxt.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/Makefile
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/Makefile	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/Makefile	(revision 4)
@@ -0,0 +1,91 @@
+include ../../../config.mk
+DXT=1   # comment out for no DXT support
+
+SAGE_DIR = ../../..
+
+CFLAGS=$(SAGE_CFLAGS) -I$(SAGE_DIR)/include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS+=$(SAGE_LDFLAGS) -L$(SAGE_DIR)/lib -lsail -lz -ljpeg $(QUANTA_LDFLAGS) $(PAUDIO_LIB)
+
+CFLAGS += `Wand-config --cflags --cppflags` -fno-stack-protector
+LIBS += `Wand-config --ldflags --libs` -lpthread
+
+ifeq ($(MACHINE), Darwin)
+        LIBS+= -L/opt/local/lib -lstdc++ -lltdl
+endif
+
+FILES=imageviewer.o
+TARGET=imageviewer
+
+#----------------  BEGIN FastDXT stuff  ----------------#
+ifdef DXT
+#echo "USING DXT"
+FILES+=dxt.o libdxt.o util.o intrinsic.o
+TARGET+=imgToDxt
+CFLAGS+=-DUSE_DXT
+
+OPTIM=1
+
+MACHINE=$(shell uname -s)
+ARCHITECTURE=$(shell uname -p)
+
+ifeq ($(MACHINE), Darwin)
+
+CFLAGS+=-I/opt/local/include
+
+ifeq ($(ARCHITECTURE), i386)
+	# Intel Mac
+
+ifeq ($(OPTIM), 1)
+# MacPro
+CXXFLAGS+=-march=nocona -msse3 -DDXT_INTR
+
+# MacbookPro
+#CFLAGS+=-march=i686 -msse2 -DDXT_INTR
+endif
+
+endif
+
+ifeq ($(ARCHITECTURE), powerpc)
+	# PowerPC Mac
+#echo "Disabling SSE instructions on PowerPC"
+CFLAGS+=
+endif
+endif
+
+ifeq ($(ARCHITECTURE), x86_64)
+	# Opteron
+CFLAGS+=-march=opteron -msse2 -DDXT_INTR
+
+else
+
+	# everything considered i386/linux
+CFLAGS+=-msse2 -DDXT_INTR
+
+endif
+
+
+endif
+#------------------  END FastDXT stuff  -------------------#
+
+
+
+default: $(TARGET)
+
+install: $(TARGET)
+	/bin/cp -f imageviewer $(SAGE_DIR)/bin
+ifdef DXT
+	/bin/cp -f imgToDxt dirToDxt.py $(SAGE_DIR)/bin/fileServer
+endif
+	
+imageviewer: $(FILES)
+	g++ -o imageviewer $(FILES) $(LIBS)
+
+imgToDxt: imgToDxt.o dxt.o libdxt.o util.o intrinsic.o 
+	g++ -o imgToDxt imgToDxt.o dxt.o libdxt.o util.o intrinsic.o $(LIBS)
+
+%.o: %.cpp
+	g++ $(CFLAGS) -c -o $@ $<
+
+clean:
+	/bin/rm -f *.o *~ imageviewer imgToDxt
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/util.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/util.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/util.cpp	(revision 4)
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+void aLog(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+}
+
+void aError(const char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+
+    exit(1);
+}
+
+
+
+void* aAlloc(size_t const n)
+{
+	void* result;
+#if defined(WIN32)
+	result = LocalAlloc(0,n);
+#else
+	result = malloc(n);
+#endif
+	// Filling with zeros
+	memset(result, 0, n);
+
+	if(!result)
+		aError("Aura: not enough memory for %d bytes",n);
+	return result;
+}
+
+void aFree(void* const p)
+{
+#if defined(WIN32)
+	LocalFree(p);
+#else
+	if (p)
+        free(p);
+    else
+        aError("Alloc> Trying to free a NULL pointer\n");
+#endif
+}
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
Index: trunk/src/testing/app/FileViewer/ImageViewer/dxt.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app/FileViewer/ImageViewer/imgToDxt.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/ImageViewer/imgToDxt.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/ImageViewer/imgToDxt.cpp	(revision 4)
@@ -0,0 +1,210 @@
+/*****************************************************************************************
+ * imgToDxt: converts a single image to a dxt-compressed image
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc to www.evl.uic.edu/cavern/forum
+ *
+ * Author: Ratko Jagodic
+ *
+ *****************************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <wand/magick-wand.h>
+
+//#if MagickLibVersion >= 0x645
+//#define MagickGetImagePixels MagickGetAuthenticPixels
+//#endif
+
+// for dxt compression
+#include "libdxt.h"
+
+
+using namespace std;
+
+
+#define ThrowWandException(wand)		\
+  {						\
+    char					\
+      *description;				\
+						\
+    ExceptionType				\
+      severity;					\
+						    \
+    description=MagickGetException(wand,&severity);			\
+    (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \
+    description=(char *) MagickRelinquishMemory(description);		\
+    exit(-1);								\
+  }
+
+
+// -----------------------------------------------------------------------------
+
+
+
+void writeDXT(string fileName, byte *buffer, unsigned int width, 
+	      unsigned int height, unsigned int numBytes)
+{
+    fprintf(stderr, "\nImgToDxt: Writing DXT to file... %u bytes", numBytes);
+
+    unsigned long r;
+    FILE *f = fopen(fileName.data(), "wb");
+
+    if (f != NULL)
+    {
+	// write the size of the image in the first 8 bytes
+	r = fwrite(&width, sizeof(unsigned int), 1, f);
+	r = fwrite(&height, sizeof(unsigned int), 1, f);
+	r = fwrite(&numBytes, sizeof(unsigned int), 1, f);
+	
+	// write the buffer out to the file
+	r = fwrite(buffer, 1, numBytes, f);
+	fclose(f);
+    }
+    else
+	fprintf(stderr, "\nImgToDxt: ERROR: Unable to write DXT file. Check dir permissions.");
+}
+
+
+
+void getRGBA(string fileName, byte **rgba, unsigned int &width, 
+	      unsigned int &height)
+{
+    // use ImageMagick to read all other formats
+    MagickBooleanType status;  
+    MagickWand *wand;
+    
+    // read file
+    wand=NewMagickWand();  
+    status=MagickReadImage(wand, fileName.data());
+    if (status == MagickFalse)
+	ThrowWandException(wand);
+
+    // get the image size
+    width = MagickGetImageWidth(wand);
+    height = MagickGetImageHeight(wand);
+
+    if (width%4 != 0 || height%4 != 0)
+    {
+	fprintf(stderr, "\nImgToDxt: Image cropped a few pixels to be a multiple of 4 for dxt");
+	width -= width%4;
+	height -= height%4;
+    }
+	
+    // flip the image to have the correct orientation for dxt
+    MagickFlipImage(wand);
+    
+    // get the pixels
+    *rgba = (byte*) memalign(16, width*height*4);
+    memset(*rgba, 0, width*height*4);
+    MagickGetImagePixels(wand, 0, 0, width, height, "RGBA", CharPixel, *rgba);
+    DestroyMagickWand(wand);
+}
+
+
+void rgbaToDXT(string fileName, byte **rgba, byte **dxt, unsigned int width, 
+	       unsigned int height)
+{
+    unsigned int numBytes;
+
+    // compress into DXT
+    *dxt = (byte*) memalign(16, width*height*4/8);
+    memset(*dxt, 0, width*height*4/8);
+    numBytes = CompressDXT(*rgba, *dxt, width, height, FORMAT_DXT1, 1);
+
+    // write this DXT out to a file (change extension to .dxt)
+    string dxtFileName = string(fileName);
+    dxtFileName.resize(fileName.rfind("."));
+    dxtFileName += ".dxt";
+    writeDXT(dxtFileName, *dxt, width, height, numBytes);
+}
+
+
+bool dxtFileExists(string fileName)
+{
+    // replace the extension with .dxt
+    string dxtFileName = string(fileName);
+    dxtFileName.resize(fileName.rfind("."));
+    dxtFileName += ".dxt";
+
+    // check whether the file exists by trying to open it
+    FILE *dxtFile = fopen(dxtFileName.data(), "r");
+    if ( dxtFile == NULL)
+    {
+	fprintf(stderr, "\nImgToDxt: DXT file for %s doesn't exist yet.", fileName.data());
+	return false;
+    }
+    else 
+    {
+	fclose(dxtFile);
+	return true;
+    }
+}
+
+
+// -----------------------------------------------------------------------------
+
+
+
+int main(int argc,char **argv)
+{
+    byte *dxt = NULL;   
+    byte *rgba = NULL;
+    unsigned int width, height;  // image size
+     
+    
+    // parse command line arguments
+    if (argc < 2){
+	fprintf(stderr, "\n\nUSAGE: imgToDxt filename\n");
+	return 0;
+    }
+
+    // check file extension
+    string fileName, fileExt;
+    fileName = string(argv[1]);
+    fileExt = fileName.substr(fileName.rfind("."));
+
+    // if image is in DXT load it directly, otherwise compress and load
+    if(fileExt.compare(".dxt") == 0 || dxtFileExists(fileName))   // DXT already exists
+	return(0);
+    else                               // all other image formats
+    {
+	getRGBA(fileName, &rgba, width, height);
+	rgbaToDXT(fileName, &rgba, &dxt, width, height);
+	free(dxt);
+	free(rgba);
+    }
+
+    return(0);
+}
Index: trunk/src/testing/app/FileViewer/FileServer/misc/__init__.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/__init__.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/__init__.py	(revision 4)
@@ -0,0 +1,2 @@
+### miscellaneous 3rd party modules used by File Server
+__all__ = ["mmpython", "imsize", "countPDFpages"]
Index: trunk/src/testing/app/FileViewer/FileServer/misc/imsize.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/imsize.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/imsize.py	(revision 4)
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+# (c) Copyright 2001-2005 Hewlett-Packard Development Company, L.P.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# Author: Don Welch
+# Ported from Perl's Image::Size module by Randy J. Ray
+# Modified by Perenzo, 2006
+
+import os, os.path, re, struct
+
+xbm_pat = re.compile(r'^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)', re.IGNORECASE)
+xpm_pat = re.compile(r'"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"', re.IGNORECASE)
+ppm_pat1 = re.compile(r'^\#.*', re.IGNORECASE | re.MULTILINE)
+ppm_pat2 = re.compile(r'^(P[1-6])\s+(\d+)\s+(\d+)', re.IGNORECASE)
+ppm_pat3 = re.compile(r'IMGINFO:(\d+)x(\d+)', re.IGNORECASE)
+tiff_endian_pat = re.compile(r'II\x2a\x00')
+
+def readin(stream, length, offset=0):
+    if offset != 0:
+        stream.seek(offset, 0)
+    return stream.read(length)
+
+def xbmsize(stream):
+    width, height = -1, -1
+    match = xbm_pat.match(readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def xpmsize(stream):
+    width, height = -1, -1
+    match = re.search(xpm_pat, readin(stream, 1024))
+    try:
+        width = int(match.group(1))
+        height = int(match.group(2))
+    except:
+        pass
+    return width, height
+
+def pngsize(stream): # also does MNG
+    width, height = -1, -1
+    if readin(stream, 4, 12) in ('IHDR', 'MHDR'):
+        height, width = struct.unpack("!II", stream.read(8))
+
+    return height, width #width, height
+
+def jpegsize(stream):
+    width, height = -1, -1
+    stream.seek(2)
+    while 1:
+        length = 4
+        buffer = readin(stream, length)
+        try:
+            marker, code, length = struct.unpack("!ccH", buffer)
+        except:
+            break
+        if marker != '\xff':
+            break
+        if 0xc0 <= ord(code) <= 0xc3:
+            length = 5
+            height, width = struct.unpack("!xHH", readin(stream, length))
+        else:
+            readin(stream, length-2)
+    return width, height
+
+def ppmsize(stream):
+    width, height = -1, -1
+    header = re.sub(ppm_pat1, '', readin(stream, 1024))
+    match = ppm_pat2.match(header)
+    typ = ''
+    try:
+        typ = match.group(1)
+        width = int(match.group(2))
+        height = int(match.group(3))
+    except:
+        pass
+    if typ == 'P7':
+        match = ppm_pat3.match(header)
+
+        try:
+            width = int(match.group(1))
+            height = int(match.group(2))
+        except:
+            pass
+    return width, height
+
+def tiffsize(stream):
+    header = readin(stream, 4)
+    endian = ">"
+    match = tiff_endian_pat.match(header)
+    if match is not None:
+        endian = "<"
+    input = readin(stream, 4, 4)
+    offset = struct.unpack('%si' % endian, input)[0]
+    num_dirent = struct.unpack('%sH' % endian, readin(stream, 2, offset))[0]
+    offset += 2
+    num_dirent = offset+(num_dirent*12)
+    width, height = -1, -1
+    while True:
+        ifd = readin(stream, 12, offset)
+        if ifd == '' or offset > num_dirent:
+            break
+        offset += 12
+        tag = struct.unpack('%sH'% endian, ifd[0:2])[0]
+        type = struct.unpack('%sH' % endian, ifd[2:4])[0]
+        if tag == 0x0100:
+            width = struct.unpack("%si" % endian, ifd[8:12])[0]
+        elif tag == 0x0101:
+            height = struct.unpack("%si" % endian, ifd[8:12])[0]
+    return width, height
+
+def bmpsize(stream):
+    width, height = struct.unpack("<II", readin(stream, 8, 18))
+    return width, height
+
+def gifsize(stream):
+    # since we only care about the printed size of the image
+    # we only need to get the logical screen sizes, which are
+    # the maximum extents of the image. This code is much simpler
+    # than the code from Image::Size
+    #width, height = -1, -1
+    buf = readin(stream, 7, 6) # LSx, GCTF, etc
+    height, width, flags, bci, par = struct.unpack('<HHBBB', buf)
+    return height, width #width, height
+
+TYPE_MAP = { re.compile('^GIF8[7,9]a')              : ('image/gif', gifsize),
+             re.compile("^\xFF\xD8")                : ('image/jpeg', jpegsize),
+             re.compile("^\x89PNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+             re.compile("^P[1-7]")                  : ('image/x-portable-pixmap', ppmsize),
+             re.compile('\#define\s+\S+\s+\d+')     : ('image/x-xbitmap', xbmsize),
+             re.compile('\/\* XPM \*\/')            : ('image/x-xpixmap', xpmsize),
+             re.compile('^MM\x00\x2a')              : ('image/tiff', tiffsize),
+             re.compile('^II\*\x00')                : ('image/tiff', tiffsize),
+             re.compile('^BM')                      : ('image/x-bitmap', bmpsize),
+             re.compile("^\x8aMNG\x0d\x0a\x1a\x0a") : ('image/png', pngsize),
+           }
+
+def imagesize(filename, mime_type=''):
+    width, height = -1, -1
+    f = file(filename, 'rb')
+    buffer = f.read(4096)
+    if not mime_type:
+        for t in TYPE_MAP:
+            match = t.search(buffer)
+            if match is not None:
+                mime_type, func = TYPE_MAP[t]
+                break
+    if mime_type and func:
+        f.seek(0)
+        width, height = func(f)
+    else:
+        width, height = -1, -1
+    f.close()
+    return height, width, mime_type
+
+if __name__=="__main__":
+    import sys
+    print imagesize(sys.argv[1])
Index: trunk/src/testing/app/FileViewer/FileServer/misc/countPDFpages.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/countPDFpages.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/countPDFpages.py	(revision 4)
@@ -0,0 +1,18 @@
+import re
+
+def getPDFPageCount(filename):    
+    """Counts pages in a PDF document. 
+    
+    This is GPLed code written by J.Alet on 2004/06/19
+    """
+    try:
+        infile = open(filename, "rb")
+        regexp = re.compile(r"(/Type) ?(/Page)[/ \r\n]")
+        pagecount = 0
+        for line in infile.xreadlines(): 
+            pagecount += len(regexp.findall(line))
+        infile.close()
+        return pagecount
+    except:
+        return -1
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/table.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/table.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/table.py	(revision 4)
@@ -0,0 +1,100 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: table.py,v 1.9 2004/05/28 12:26:24 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: table.py,v $
+# Revision 1.9  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.8  2003/07/02 11:17:29  the_krow
+# language is now part of the table key
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from gettext import GNUTranslations
+import os
+
+LOCALEDIR = 'i18n'
+
+class Table:
+    def __init__(self, hashmap, name, language='en'):
+        self.dict = hashmap
+        self.name = name
+        self.language = language
+        self.translations = {}
+        self.languages = []
+        self.i18ndir = os.path.join(LOCALEDIR, name.lower())
+        try:
+            self.read_translations()
+        except:
+            pass
+    
+    def read_translations(self):
+        for filename in [x for x in os.listdir(self.i18ndir) if x.endswith('.mo')]:
+            lang = filename[:-3]
+            filename = os.path.join(self.i18ndir, filename)
+            f = open(filename, 'rb')
+            self.translations[lang] = GNUTranslations(f)
+            f.close()
+        self.languages = self.translations.keys()
+        
+    def gettext(self, message, language = None):
+        try:
+            return self.translations[language].gettext(unicode(message))
+        except KeyError:
+            return unicode(message)
+        
+    def __setitem__(self,key,value):
+        self.dict[key] = value
+        
+    def __getitem__(self,key):
+        try:
+            return self.dict[key]
+        except KeyError:
+            return None
+         
+    def getstr(self,key):
+        s = self[key]
+        try:
+            if s and len(unicode(s)) < 100: 
+                return s
+            else:
+                return "Not Displayable"
+        except UnicodeDecodeError:
+            return "Not Displayable"
+         
+    def has_key(self, key):
+        return self.dict.has_key(key)    
+    
+    def getEntry(self, key, language = 'en'):
+        pair = (self.gettext(key), unicode(self.dict[key]))
+    
+    def __unicode__(self):
+        header = "\nTable %s (%s):" % (self.name, self.language)
+        result = reduce( lambda a,b: self[b] and "%s\n        %s: %s" % \
+                         (a, self.gettext(b,'en'), self.getstr(b)) or \
+                         a, self.dict.keys(), header )
+        return result
+
+    def accept(self,mi):
+        pass
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/id3v2.pot
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/id3v2.pot	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/id3v2.pot	(revision 4)
@@ -0,0 +1,257 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "AENC"
+msgstr "Audio encryption"
+
+msgid "APIC"
+msgstr "Attached picture"
+
+msgid "ASPI"
+msgstr "Audio seek point index"
+
+msgid "COMM"
+msgstr "Comments"
+
+msgid "COMR"
+msgstr "Commercial frame"
+
+msgid "ENCR"
+msgstr "Encryption method registration"
+
+msgid "EQU2"
+msgstr "Equalisation (2)"
+
+msgid "ETCO"
+msgstr "Event timing codes"
+
+msgid "GEOB"
+msgstr "General encapsulated object"
+
+msgid "GRID"
+msgstr "Group identification registration"
+
+msgid "LINK"
+msgstr "Linked information"
+
+msgid "MCDI"
+msgstr "Music CD identifier"
+
+msgid "MLLT"
+msgstr "MPEG location lookup table"
+
+msgid "OWNE"
+msgstr "Ownership frame"
+
+msgid "PRIV"
+msgstr "Private frame"
+
+msgid "PCNT"
+msgstr "Play counter"
+
+msgid "POPM"
+msgstr "Popularimeter"
+
+msgid "POSS"
+msgstr "Position synchronisation frame"
+
+msgid "RBUF"
+msgstr "Recommended buffer size"
+
+msgid "RVA2"
+msgstr "Relative volume adjustment (2)"
+
+msgid "RVRB"
+msgstr "Reverb"
+
+msgid "SEEK"
+msgstr "Seek frame"
+
+msgid "SIGN"
+msgstr "Signature frame"
+
+msgid "SYLT"
+msgstr "Synchronised lyric/text"
+
+msgid "SYTC"
+msgstr "Synchronised tempo codes"
+
+msgid "TALB"
+msgstr "Album/Movie/Show title"
+
+msgid "TBPM"
+msgstr "BPM (beats per minute)"
+
+msgid "TCOM"
+msgstr "Composer"
+
+msgid "TCON"
+msgstr "Content type"
+
+msgid "TCOP"
+msgstr "Copyright message"
+
+msgid "TDEN"
+msgstr "Encoding time"
+
+msgid "TDLY"
+msgstr "Playlist delay"
+
+msgid "TDOR"
+msgstr "Original release time"
+
+msgid "TDRC"
+msgstr "Recording time"
+
+msgid "TDRL"
+msgstr "Release time"
+
+msgid "TDTG"
+msgstr "Tagging time"
+
+msgid "TENC"
+msgstr "Encoded by"
+
+msgid "TEXT"
+msgstr "Lyricist/Text writer"
+
+msgid "TFLT"
+msgstr "File type"
+
+msgid "TIPL"
+msgstr "Involved people list"
+
+msgid "TIT1"
+msgstr "Content group description"
+
+msgid "TIT2"
+msgstr "Title/songname/content description"
+
+msgid "TIT3"
+msgstr "Subtitle/Description refinement"
+
+msgid "TKEY"
+msgstr "Initial key"
+
+msgid "TLAN"
+msgstr "Language(s)"
+
+msgid "TLEN"
+msgstr "Length"
+
+msgid "TMCL"
+msgstr "Musician credits list"
+
+msgid "TMED"
+msgstr "Media type"
+
+msgid "TMOO"
+msgstr "Mood"
+
+msgid "TOAL"
+msgstr "Original album/movie/show title"
+
+msgid "TOFN"
+msgstr "Original filename"
+
+msgid "TOLY"
+msgstr "Original lyricist(s)/text writer(s)"
+
+msgid "TOPE"
+msgstr "Original artist(s)/performer(s)"
+
+msgid "TOWN"
+msgstr "File owner/licensee"
+
+msgid "TPE1"
+msgstr "Lead performer(s)/Soloist(s)"
+
+msgid "TPE2"
+msgstr "Band/orchestra/accompaniment"
+
+msgid "TPE3"
+msgstr "Conductor/performer refinement"
+
+msgid "TPE4"
+msgstr "Interpreted, remixed, or otherwise modified by"
+
+msgid "TPOS"
+msgstr "Part of a set"
+
+msgid "TPRO"
+msgstr "Produced notice"
+
+msgid "TPUB"
+msgstr "Publisher"
+
+msgid "TRCK"
+msgstr "Track number/Position in set"
+
+msgid "TRSN"
+msgstr "Internet radio station name"
+
+msgid "TRSO"
+msgstr "Internet radio station owner"
+
+msgid "TSOA"
+msgstr "Album sort order"
+
+msgid "TSOP"
+msgstr "Performer sort order"
+
+msgid "TSOT"
+msgstr "Title sort order"
+
+msgid "TSRC"
+msgstr "ISRC (international standard recording code)"
+
+msgid "TSSE"
+msgstr "Software/Hardware and settings used for encoding"
+
+msgid "TSST"
+msgstr "Set subtitle"
+
+msgid "TXXX"
+msgstr "User defined text information frame"
+
+msgid "UFID"
+msgstr "Unique file identifier"
+
+msgid "USER"
+msgstr "Terms of use"
+
+msgid "USLT"
+msgstr "Unsynchronised lyric/text transcription"
+
+msgid "WCOM"
+msgstr "Commercial information"
+
+msgid "WCOP"
+msgstr "Copyright/Legal information"
+
+msgid "WOAF"
+msgstr "Official audio file webpage"
+
+msgid "WOAR"
+msgstr "Official artist/performer webpage"
+
+msgid "WOAS"
+msgstr "Official audio source webpage"
+
+msgid "WORS"
+msgstr "Official Internet radio station homepage"
+
+msgid "WPAY"
+msgstr "Payment"
+
+msgid "WPUB"
+msgstr "Publishers official webpage"
+
+msgid "WXXX"
+msgstr "User defined URL link frame"
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/en.po
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/en.po	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/id3v2/en.po	(revision 4)
@@ -0,0 +1,260 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython id3v2\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 15:13+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schueppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "AENC"
+msgstr "Audio encryption"
+
+msgid "APIC"
+msgstr "Attached picture"
+
+msgid "ASPI"
+msgstr "Audio seek point index"
+
+msgid "COMM"
+msgstr "Comments"
+
+msgid "COMR"
+msgstr "Commercial frame"
+
+msgid "ENCR"
+msgstr "Encryption method registration"
+
+msgid "EQU2"
+msgstr "Equalisation (2)"
+
+msgid "ETCO"
+msgstr "Event timing codes"
+
+msgid "GEOB"
+msgstr "General encapsulated object"
+
+msgid "GRID"
+msgstr "Group identification registration"
+
+msgid "LINK"
+msgstr "Linked information"
+
+msgid "MCDI"
+msgstr "Music CD identifier"
+
+msgid "MLLT"
+msgstr "MPEG location lookup table"
+
+msgid "OWNE"
+msgstr "Ownership frame"
+
+msgid "PRIV"
+msgstr "Private frame"
+
+msgid "PCNT"
+msgstr "Play counter"
+
+msgid "POPM"
+msgstr "Popularimeter"
+
+msgid "POSS"
+msgstr "Position synchronisation frame"
+
+msgid "RBUF"
+msgstr "Recommended buffer size"
+
+msgid "RVA2"
+msgstr "Relative volume adjustment (2)"
+
+msgid "RVRB"
+msgstr "Reverb"
+
+msgid "SEEK"
+msgstr "Seek frame"
+
+msgid "SIGN"
+msgstr "Signature frame"
+
+msgid "SYLT"
+msgstr "Synchronised lyric/text"
+
+msgid "SYTC"
+msgstr "Synchronised tempo codes"
+
+msgid "TALB"
+msgstr "Album/Movie/Show title"
+
+msgid "TBPM"
+msgstr "BPM (beats per minute)"
+
+msgid "TCOM"
+msgstr "Composer"
+
+msgid "TCON"
+msgstr "Content type"
+
+msgid "TCOP"
+msgstr "Copyright message"
+
+msgid "TDEN"
+msgstr "Encoding time"
+
+msgid "TDLY"
+msgstr "Playlist delay"
+
+msgid "TDOR"
+msgstr "Original release time"
+
+msgid "TDRC"
+msgstr "Recording time"
+
+msgid "TDRL"
+msgstr "Release time"
+
+msgid "TDTG"
+msgstr "Tagging time"
+
+msgid "TENC"
+msgstr "Encoded by"
+
+msgid "TEXT"
+msgstr "Lyricist/Text writer"
+
+msgid "TFLT"
+msgstr "File type"
+
+msgid "TIPL"
+msgstr "Involved people list"
+
+msgid "TIT1"
+msgstr "Content group description"
+
+msgid "TIT2"
+msgstr "Title/songname/content description"
+
+msgid "TIT3"
+msgstr "Subtitle/Description refinement"
+
+msgid "TKEY"
+msgstr "Initial key"
+
+msgid "TLAN"
+msgstr "Language(s)"
+
+msgid "TLEN"
+msgstr "Length"
+
+msgid "TMCL"
+msgstr "Musician credits list"
+
+msgid "TMED"
+msgstr "Media type"
+
+msgid "TMOO"
+msgstr "Mood"
+
+msgid "TOAL"
+msgstr "Original album/movie/show title"
+
+msgid "TOFN"
+msgstr "Original filename"
+
+msgid "TOLY"
+msgstr "Original lyricist(s)/text writer(s)"
+
+msgid "TOPE"
+msgstr "Original artist(s)/performer(s)"
+
+msgid "TOWN"
+msgstr "File owner/licensee"
+
+msgid "TPE1"
+msgstr "Lead performer(s)/Soloist(s)"
+
+msgid "TPE2"
+msgstr "Band/orchestra/accompaniment"
+
+msgid "TPE3"
+msgstr "Conductor/performer refinement"
+
+msgid "TPE4"
+msgstr "Interpreted, remixed, or otherwise modified by"
+
+msgid "TPOS"
+msgstr "Part of a set"
+
+msgid "TPRO"
+msgstr "Produced notice"
+
+msgid "TPUB"
+msgstr "Publisher"
+
+msgid "TRCK"
+msgstr "Track number/Position in set"
+
+msgid "TRSN"
+msgstr "Internet radio station name"
+
+msgid "TRSO"
+msgstr "Internet radio station owner"
+
+msgid "TSOA"
+msgstr "Album sort order"
+
+msgid "TSOP"
+msgstr "Performer sort order"
+
+msgid "TSOT"
+msgstr "Title sort order"
+
+msgid "TSRC"
+msgstr "ISRC (international standard recording code)"
+
+msgid "TSSE"
+msgstr "Software/Hardware and settings used for encoding"
+
+msgid "TSST"
+msgstr "Set subtitle"
+
+msgid "TXXX"
+msgstr "User defined text information frame"
+
+msgid "UFID"
+msgstr "Unique file identifier"
+
+msgid "USER"
+msgstr "Terms of use"
+
+msgid "USLT"
+msgstr "Unsynchronised lyric/text transcription"
+
+msgid "WCOM"
+msgstr "Commercial information"
+
+msgid "WCOP"
+msgstr "Copyright/Legal information"
+
+msgid "WOAF"
+msgstr "Official audio file webpage"
+
+msgid "WOAR"
+msgstr "Official artist/performer webpage"
+
+msgid "WOAS"
+msgstr "Official audio source webpage"
+
+msgid "WORS"
+msgstr "Official Internet radio station homepage"
+
+msgid "WPAY"
+msgstr "Payment"
+
+msgid "WPUB"
+msgstr "Publishers official webpage"
+
+msgid "WXXX"
+msgstr "User defined URL link frame"
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/aviinfo.pot	(revision 4)
@@ -0,0 +1,212 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+msgid "INAM"
+msgstr ""
+
+msgid "IART"
+msgstr ""
+
+msgid "ICOP"
+msgstr ""
+
+msgid "IPRD"
+msgstr ""
+
+msgid "ICRD"
+msgstr ""
+
+msgid "IGNR"
+msgstr ""
+
+msgid "ISGN"
+msgstr ""
+
+msgid "ISBJ"
+msgstr ""
+
+msgid "IKEY"
+msgstr ""
+
+msgid "ICMT"
+msgstr ""
+
+msgid "IWRI"
+msgstr ""
+
+msgid "IPRO"
+msgstr ""
+
+msgid "ICNM"
+msgstr ""
+
+msgid "IPDS"
+msgstr ""
+
+msgid "IEDT"
+msgstr ""
+
+msgid "ICDS"
+msgstr ""
+
+msgid "IMUS"
+msgstr ""
+
+msgid "ISTD"
+msgstr ""
+
+msgid "IDST"
+msgstr ""
+
+msgid "ICNT"
+msgstr ""
+
+msgid "ILNG"
+msgstr ""
+
+msgid "LANG"
+msgstr ""
+
+msgid "IRTD"
+msgstr ""
+
+msgid "IPRT"
+msgstr ""
+
+msgid "PRT1"
+msgstr ""
+
+msgid "IFRM"
+msgstr ""
+
+msgid "PRT2"
+msgstr ""
+
+msgid "ISTR"
+msgstr ""
+
+msgid "STAR"
+msgstr ""
+
+msgid "ISFT"
+msgstr ""
+
+msgid "ISFT"
+msgstr ""
+
+msgid "ITCH"
+msgstr ""
+
+msgid "ITCH"
+msgstr ""
+
+msgid "CODE"
+msgstr ""
+
+msgid "IENC"
+msgstr ""
+
+msgid "IRIP"
+msgstr ""
+
+msgid "IDIT"
+msgstr ""
+
+msgid "IWEB"
+msgstr ""
+
+msgid "IBSU"
+msgstr ""
+
+msgid "ISRF"
+msgstr ""
+
+msgid "IMED"
+msgstr ""
+
+msgid "ISRC"
+msgstr ""
+
+msgid "IARL"
+msgstr ""
+
+msgid "ICMS"
+msgstr ""
+
+msgid "IENG"
+msgstr ""
+
+msgid "ICRP"
+msgstr ""
+
+msgid "ISHP"
+msgstr ""
+
+msgid "IDIM"
+msgstr ""
+
+msgid "ILGT"
+msgstr ""
+
+msgid "IDPI"
+msgstr ""
+
+msgid "IPLT"
+msgstr ""
+
+msgid "IAS1"
+msgstr ""
+
+msgid "IAS2"
+msgstr ""
+
+msgid "IAS3"
+msgstr ""
+
+msgid "IAS4"
+msgstr ""
+
+msgid "IAS5"
+msgstr ""
+
+msgid "IAS6"
+msgstr ""
+
+msgid "IAS7"
+msgstr ""
+
+msgid "IAS8"
+msgstr ""
+
+msgid "IAS9"
+msgstr ""
+
+msgid "ICAS"
+msgstr ""
+
+msgid "ILGU"
+msgstr ""
+
+msgid "ILIU"
+msgstr ""
+
+msgid "IWMU"
+msgstr ""
+
+msgid "IMIU"
+msgstr ""
+
+msgid "IMBI"
+msgstr ""
+
+msgid "IMBU"
+msgstr ""
+
+msgid "IMIT"
+msgstr ""
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/en.po
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/en.po	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/aviinfo/en.po	(revision 4)
@@ -0,0 +1,152 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython aviinfo\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 11:30+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schueppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "INAM"
+msgstr "Title"
+
+msgid "IART"
+msgstr "Director"
+
+msgid "ICOP"
+msgstr "Copyright"
+
+msgid "IPRD"
+msgstr "Product"
+
+msgid "ICRD"
+msgstr "Creation Date"
+
+msgid "IGNR"
+msgstr "Genre"
+
+msgid "ISGN"
+msgstr "Secondary Genre"
+
+msgid "ISBJ"
+msgstr "Subject"
+
+msgid "IKEY"
+msgstr "Keywords"
+
+msgid "ICMT"
+msgstr "Comments"
+
+msgid "IWRI"
+msgstr "Written by"
+
+msgid "IPRO"
+msgstr "Produced by"
+
+msgid "ICNM"
+msgstr "Cinematographer"
+
+msgid "IPDS"
+msgstr "Production Designer"
+
+msgid "IEDT"
+msgstr "Edited by"
+
+msgid "ICDS"
+msgstr "Costume Designer"
+
+msgid "IMUS"
+msgstr "Music by"
+
+msgid "ISTD"
+msgstr "Production Studio"
+
+msgid "IDST"
+msgstr "Distributed by"
+
+msgid "ICNT"
+msgstr "Country"
+
+msgid "ILNG"
+msgstr "Language"
+
+msgid "LANG"
+msgstr "Language"
+
+msgid "IRTD"
+msgstr "Rating"
+
+msgid "IPRT"
+msgstr "Part"
+
+msgid "PRT1"
+msgstr "Part"
+
+msgid "IFRM"
+msgstr "Total Number of Parts"
+
+msgid "PRT2"
+msgstr "Total Number of Parts"
+
+msgid "ISTR"
+msgstr "Starring"
+
+msgid "STAR"
+msgstr "Starring"
+
+msgid "ISFT"
+msgstr "Software"
+
+msgid "ISFT"
+msgstr "Software"
+
+msgid "ITCH"
+msgstr "Encoded by"
+
+msgid "ITCH"
+msgstr "Technician"
+
+msgid "CODE"
+msgstr "Encoded by"
+
+msgid "IENC"
+msgstr "Encoded by"
+
+msgid "IRIP"
+msgstr "Ripped by"
+
+msgid "IDIT"
+msgstr "Digitizing Date"
+
+msgid "IWEB"
+msgstr "Internet Address"
+
+msgid "IBSU"
+msgstr "Base URL"
+
+msgid "ISRF"
+msgstr "Source Form"
+
+msgid "IMED"
+msgstr "Medium"
+
+msgid "ISRC"
+msgstr "Source"
+
+msgid "IARL"
+msgstr "Archival Location"
+
+msgid "ICMS"
+msgstr "Commissioned by"
+
+msgid "IENG"
+msgstr "Engineer"
+
+msgid "ICRP"
+msgstr "Cropped"
+
+msgid "ISHP"
+msgstr "Sha"
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/iptc.pot
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/iptc.pot	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/iptc.pot	(revision 4)
@@ -0,0 +1,68 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "613"
+msgstr ""
+
+msgid "615"
+msgstr ""
+
+msgid "552"
+msgstr ""
+
+msgid "617"
+msgstr ""
+
+msgid "517"
+msgstr ""
+
+msgid "622"
+msgstr ""
+
+msgid "527"
+msgstr ""
+
+msgid "592"
+msgstr ""
+
+msgid "627"
+msgstr ""
+
+msgid "628"
+msgstr ""
+
+msgid "597"
+msgstr ""
+
+msgid "567"
+msgstr ""
+
+msgid "632"
+msgstr ""
+
+msgid "634"
+msgstr ""
+
+msgid "602"
+msgstr ""
+
+msgid "607"
+msgstr ""
+
+msgid "537"
+msgstr ""
+
+msgid "522"
+msgstr ""
+
+msgid "512"
+msgstr ""
+
+msgid "256"
+msgstr ""
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/en.po
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/en.po	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/iptc/en.po	(revision 4)
@@ -0,0 +1,62 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 11:30+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team:  <>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "613"
+msgstr "Country"
+
+msgid "615"
+msgstr "Transmission"
+
+msgid "552"
+msgstr "Special Instructions"
+
+msgid "617"
+msgstr "Headline"
+
+msgid "517"
+msgstr "Object Name"
+
+msgid "622"
+msgstr "Credits"
+
+msgid "527"
+msgstr "Categories"
+
+msgid "592"
+msgstr "Byline"
+
+msgid "627"
+msgstr "Source"
+
+msgid "628"
+msgstr "Copyright"
+
+msgid "597"
+msgstr "Byline Title"
+
+msgid "567"
+msgstr "Date"
+
+msgid "632"
+msgstr "Caption"
+
+msgid "634"
+msgstr "Caption Writer"
+
+msgid "602"
+msgstr "City"
+
+msgid "607"
+msgstr "State"
+
+msgid "537"
+msgstr "Keywords"
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/en.po
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/en.po	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/en.po	(revision 4)
@@ -0,0 +1,100 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: mmpython\n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: 2003-07-02 13:35+0100\n"
+"Last-Translator: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"Language-Team: Thomas Schüppel <stain@cs.tu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+# Copyright statement.
+msgid "cpy"
+msgstr "Copyright"
+
+msgid "aut"
+msgstr "Author"
+
+msgid "nam"
+msgstr "Title"
+
+# Date the movie content was created.
+msgid "day"
+msgstr "Day"
+
+msgid "dir"
+msgstr "Name of movies director"
+
+msgid "ed1"
+msgstr "Edit dates and descriptions"
+
+msgid "ed2"
+msgstr "Edit dates and descriptions"
+
+msgid "ed3"
+msgstr "Edit dates and descriptions"
+
+msgid "ed4"
+msgstr "Edit dates and descriptions"
+
+msgid "ed5"
+msgstr "Edit dates and descriptions"
+
+msgid "ed6"
+msgstr "Edit dates and descriptions"
+
+msgid "ed7"
+msgstr "Edit dates and descriptions"
+
+msgid "ed8"
+msgstr "Edit dates and descriptions"
+
+msgid "ed9"
+msgstr "Edit dates and descriptions"
+
+msgid "fmt"
+msgstr "Indication of movie format (computer-generated, digitized, and so on)"
+
+msgid "inf"
+msgstr "Information about the movie"
+
+msgid "prd"
+msgstr "Name of movies producer"
+
+msgid "prf"
+msgstr "Names of performers"
+
+msgid "req"
+msgstr "Special hardware and software requirements"
+
+msgid "src"
+msgstr "Credits for those who provided movie source content"
+
+msgid "wrt"
+msgstr "Name of movies writer"
+
+msgid "name"
+msgstr "Name of object"
+
+msgid "WLOC"
+msgstr "Default window location for movie. Two 16-bit values, {x,y}"
+
+msgid "LOOP"
+msgstr "Looping. This atom is not present unless the movie is set to loop. Long integer indicating looping style. 0 for normal looping, 21 for palindromic looping"
+
+msgid "SelO"
+msgstr "Play selection only. Byte indicating that only the selected area of the movie should be played"
+
+msgid "AllF"
+msgstr "Play all frames. Byte indicating that all frames of video should be played, regardless of timing"
+
+msgid "ptv "
+msgstr "Print to video. Display movie in full screen mode. This atom contains a 16-byte structure, described in Print to Video (Full Screen Mode) (page 46)"
+
+msgid "hnti"
+msgstr "Hint info atom. Data used for real-time streaming of a movie or a track. For more information, see Movie Hint Info Atom (page 188) and Hint Track User Data Atom (page 188)"
+
+msgid "hinf"
+msgstr "Hint track information. Statistical data for real-time streaming of a particular track. For more information, see Hint Track User Data Atom (page 188)"
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/qtudta.pot
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/qtudta.pot	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/i18n/qtudta/qtudta.pot	(revision 4)
@@ -0,0 +1,95 @@
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2002-09-10 14:09+CET\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+msgid "cpy"
+msgstr "Copyright statement"
+
+msgid "aut"
+msgstr "Author"
+
+msgid "nam"
+msgstr "Title"
+
+msgid "day"
+msgstr "Date the movie content was created"
+
+msgid "dir" 
+msgstr "Name of movies director"
+
+msgid "ed1" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed2" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed3" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed4" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed5" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed6" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed7" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed8" 
+msgstr "Edit dates and descriptions"
+
+msgid "ed9" 
+msgstr "Edit dates and descriptions"
+
+msgid "fmt" 
+msgstr "Indication of movie format (computer-generated, digitized, and so on)"
+
+msgid "inf" 
+msgstr "Information about the movie"
+
+msgid "prd" 
+msgstr "Name of movies producer"
+
+msgid "prf" 
+msgstr "Names of performers"
+
+msgid "req" 
+msgstr "Special hardware and software requirements"
+
+msgid "src" 
+msgstr "Credits for those who provided movie source content"
+
+msgid "wrt" 
+msgstr "Name of movies writer"
+
+msgid "name" 
+msgstr "Name of object"
+
+msgid "WLOC" 
+msgstr "Default window location for movie. Two 16-bit values, {x,y}"
+
+msgid "LOOP" 
+msgstr "Looping. This atom is not present unless the movie is set to loop. Long integer indicating looping style. 0 for normal looping, 21 for palindromic looping"
+
+msgid "SelO" 
+msgstr "Play selection only. Byte indicating that only the selected area of the movie should be played"
+
+msgid "AllF" 
+msgstr "Play all frames. Byte indicating that all frames of video should be played, regardless of timing"
+
+msgid "ptv " 
+msgstr "Print to video. Display movie in full screen mode. This atom contains a 16-byte structure, described in Print to Video (Full Screen Mode) (page 46)"
+
+msgid "hnti" 
+msgstr "Hint info atom. Data used for real-time streaming of a movie or a track. For more information, see Movie Hint Info Atom (page 188) and Hint Track User Data Atom (page 188)"
+
+msgid "hinf"
+msgstr "Hint track information. Statistical data for real-time streaming of a particular track. For more information, see Hint Track User Data Atom (page 188)"
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/vcdinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/vcdinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/vcdinfo.py	(revision 4)
@@ -0,0 +1,113 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# vcdinfo.py - parse vcd track informations
+# -----------------------------------------------------------------------
+# $Id: vcdinfo.py,v 1.8 2004/06/25 13:20:35 dischi Exp $
+#
+# $Log: vcdinfo.py,v $
+# Revision 1.8  2004/06/25 13:20:35  dischi
+# FreeBSD patches
+#
+# Revision 1.7  2003/06/30 13:17:19  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.6  2003/06/10 22:11:36  dischi
+# some fixes
+#
+# Revision 1.5  2003/06/09 12:47:53  dischi
+# more track info
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+import mmpython
+from mmpython import mediainfo
+from discinfo import DiscInfo
+import cdrom
+
+class VCDInfo(DiscInfo):
+    def __init__(self,device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'video/vcd'
+        self.type = 'CD'        
+        self.subtype = 'video'
+
+    def isDisc(self, device):
+        type = None
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+        
+        # brute force reading of the device to find out if it is a VCD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+        f.close()
+
+        if buffer.find('SVCD') > 0 and buffer.find('TRACKS.SVD') > 0 and \
+               buffer.find('ENTRIES.SVD') > 0:
+            type = 'SVCD'
+
+        elif buffer.find('INFO.VCD') > 0 and buffer.find('ENTRIES.VCD') > 0:
+            type = 'VCD'
+
+        else:
+            return 0
+
+        # read the tracks to generate the title list
+        device = open(device)
+        (first, last) = cdrom.toc_header(device)
+
+        lmin = 0
+        lsec = 0
+
+        num = 0
+        for i in range(first, last + 2):
+            if i == last + 1:
+                min, sec, frames = cdrom.leadout(device)
+            else:
+                min, sec, frames = cdrom.toc_entry(device, i)
+            if num:
+                vi = mediainfo.VideoInfo()
+                # XXX add more static information here, it's also possible
+                # XXX to scan for more informations like fps
+                # XXX Settings to MPEG1/2 is a wild guess, maybe the track
+                # XXX isn't playable at all (e.g. the menu)
+                if type == 'VCD':
+                    vi.codec = 'MPEG1'
+                else:
+                    vi.codec = 'MPEG2'
+                vi.length = (min-lmin) * 60 + (sec-lsec)
+                self.tracks.append(vi)
+            num += 1
+            lmin, lsec = min, sec
+        device.close()
+        return 1
+
+    
+mmpython.registertype( 'video/vcd', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_AV, VCDInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/dvdinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/dvdinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/dvdinfo.py	(revision 4)
@@ -0,0 +1,193 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# dvdinfo.py - parse dvd title structure
+# -----------------------------------------------------------------------
+# $Id: dvdinfo.py,v 1.18 2005/01/13 20:20:20 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+import os
+import ifoparser
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+class DVDAudio(mediainfo.AudioInfo):
+    def __init__(self, title, number):
+        mediainfo.AudioInfo.__init__(self)
+        self.number = number
+        self.title  = title
+        self.id, self.language, self.codec, self.channels, self.samplerate = \
+                 ifoparser.audio(title, number)
+
+
+class DVDTitle(mediainfo.AVInfo):
+    def __init__(self, number):
+        mediainfo.AVInfo.__init__(self)
+        self.number = number
+        self.chapters, self.angles, self.length, audio_num, \
+                       subtitles_num = ifoparser.title(number)
+
+        self.keys.append('chapters')
+        self.keys.append('subtitles')
+        
+        self.mime = 'video/mpeg'
+        for a in range(1, audio_num+1):
+            self.audio.append(DVDAudio(number, a))
+            
+        for s in range(1, subtitles_num+1):
+            self.subtitles.append(ifoparser.subtitle(number, s)[0])
+
+            
+class DVDInfo(DiscInfo):
+    def __init__(self, device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+
+        if mediainfo.DEBUG > 1:
+            print 'trying buggy dvd detection'
+
+        if isinstance(device, file):
+            self.valid = self.isDVDiso(device)
+        elif os.path.isdir(device):
+            self.valid = self.isDVDdir(device)
+        else:
+            self.valid = self.isDisc(device)
+
+        if self.valid and self.tracks:
+            self.keys.append('length')
+            self.length = 0
+            first       = 0
+
+            for t in self.tracks:
+                self.length += t.length
+                if not first:
+                    first = t.length
+            
+            if self.length/len(self.tracks) == first:
+                # badly mastered dvd
+                self.length = first
+
+        self.mime    = 'video/dvd'
+        self.type    = 'DVD'
+        self.subtype = 'video'
+
+
+    def isDVDdir(self, dirname):
+        if not (os.path.isdir(dirname+'/VIDEO_TS') or \
+                os.path.isdir(dirname+'/video_ts') or \
+                os.path.isdir(dirname+'/Video_ts')):
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(dirname)
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+
+        ifoparser.close()
+        return 1
+
+    
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        # brute force reading of the device to find out if it is a DVD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            f.close()
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+        f.close()
+
+        if buffer.find('VIDEO_TS') == -1 and buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(device)
+
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+        
+        ifoparser.close()
+        return 1
+
+
+    def isDVDiso(self, f):
+        # brute force reading of the device to find out if it is a DVD
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+
+        if buffer.find('VIDEO_TS') == -1 and buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        # OK, try libdvdread
+        title_num = ifoparser.open(f.name)
+
+        if not title_num:
+            return 0
+
+        for title in range(1, title_num+1):
+            ti = DVDTitle(title)
+            ti.trackno = title
+            ti.trackof = title_num
+            self.appendtrack(ti)
+        
+        ifoparser.close()
+        return 1
+
+
+if not mmpython.gettype('video/dvd', mediainfo.EXTENSION_DEVICE):
+    mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DEVICE,
+                           mediainfo.TYPE_AV, DVDInfo )
+
+if not mmpython.gettype('video/dvd', mediainfo.EXTENSION_DIRECTORY):
+    mmpython.registertype('video/dvd', mediainfo.EXTENSION_DIRECTORY,
+                          mediainfo.TYPE_AV, DVDInfo)
+
+mmpython.registertype('video/dvd', ['iso'], mediainfo.TYPE_AV, DVDInfo)
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/CDDB.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/CDDB.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/CDDB.py	(revision 4)
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+
+# Module for retrieving CDDB v1 data from CDDB servers via HTTP
+
+# Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+# This work is released under the GNU GPL, version 2 or later.
+
+# Release version 1.3
+# CVS ID: $Id: CDDB.py,v 1.4 2004/11/14 19:26:38 dischi Exp $
+
+import urllib, string, socket, os, struct, re
+
+name = 'CDDB.py'
+version = 1.3
+
+if os.environ.has_key('EMAIL'):
+    (default_user, hostname) = string.split(os.environ['EMAIL'], '@')
+else:
+    try:
+        default_user = os.geteuid() or os.environ['USER'] or 'user'
+    except:
+        default_user = 'user'
+    hostname = socket.gethostname() or 'host'
+
+proto = 4
+default_server = 'http://freedb.freedb.org/~cddb/cddb.cgi'
+
+def query(track_info, server_url=default_server,
+	  user=default_user, host=hostname, client_name=name,
+          client_version=version, trying=0):
+
+    disc_id = track_info[0]
+    num_tracks = track_info[1]
+
+    query_str = (('%08lx %d ') % (long(disc_id), num_tracks))
+
+    for i in track_info[2:]:
+	query_str = query_str + ('%d ' % i)
+	
+    query_str = urllib.quote_plus(string.rstrip(query_str))
+
+    url = "%s?cmd=cddb+query+%s&hello=%s+%s+%s+%s&proto=%i" % \
+	  (server_url, query_str, user, host, client_name,
+           client_version, proto)
+
+    response = urllib.urlopen(url)
+    
+    # Four elements in header: status, category, disc-id, title
+    header = string.split(string.rstrip(response.readline()), ' ', 3)
+
+    try:
+        header[0] = string.atoi(header[0])
+    except:
+        if trying > 10:
+            return [ 900, None ]
+        return query(track_info, default_server,
+                     default_user, hostname, name, version, trying+1)
+
+    if header[0] == 200:		# OK
+	result = { 'category': header[1], 'disc_id': header[2], 'title':
+		   header[3] }
+
+	return [ header[0], result ]
+
+    elif header[0] == 211 or header[0] == 210: # multiple matches
+	result = []
+
+	for line in response.readlines():
+	    line = string.rstrip(line)
+
+	    if line == '.':		# end of matches
+		break
+					# otherwise:
+					# split into 3 pieces, not 4
+					# (thanks to bgp for the fix!)
+	    match = string.split(line, ' ', 2)
+
+	    result.append({ 'category': match[0], 'disc_id': match[1], 'title':
+			    match[2] })
+
+	return [ header[0], result ]
+
+    else:
+	return [ header[0], None ]
+
+def read(category, disc_id, server_url=default_server, 
+	 user=default_user, host=hostname, client_name=name,
+         client_version=version, trying=0):
+
+    url = "%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=%i" % \
+	  (server_url, category, disc_id, user, host, client_name,
+           client_version, proto)
+
+    response = urllib.urlopen(url)
+    
+    header = string.split(string.rstrip(response.readline()), ' ', 3)
+
+    try:
+        header[0] = string.atoi(header[0])
+    except:
+        if trying > 10:
+            return [ 900, None ]
+        return read(category, disc_id, default_server, 
+                    user, host, client_name, client_version, trying+1)
+
+    if header[0] == 210 or header[0] == 417: # success or access denied
+	reply = []
+
+	for line in response.readlines():
+	    line = string.rstrip(line)
+
+	    if line == '.':
+		break;
+
+	    line = string.replace(line, r'\t', "\t")
+	    line = string.replace(line, r'\n', "\n")
+	    line = string.replace(line, r'\\', "\\")
+
+	    reply.append(line)
+
+	if header[0] == 210:		# success, parse the reply
+	    return [ header[0], parse_read_reply(reply) ]
+	else:				# access denied. :(
+	    return [ header[0], reply ]
+    else:
+	return [ header[0], None ]
+
+def parse_read_reply(comments):
+    
+    len_re = re.compile(r'#\s*Disc length:\s*(\d+)\s*seconds')
+    revis_re = re.compile(r'#\s*Revision:\s*(\d+)')
+    submit_re = re.compile(r'#\s*Submitted via:\s*(.+)')
+    keyword_re = re.compile(r'([^=]+)=(.*)')
+
+    result = {}
+
+    for line in comments:
+	keyword_match = keyword_re.match(line)
+	if keyword_match:
+	    (keyword, data) = keyword_match.groups()
+
+	    if result.has_key(keyword):
+		result[keyword] = result[keyword] + data
+	    else:
+		result[keyword] = data
+	    continue
+
+	len_match = len_re.match(line)
+	if len_match:
+	    result['disc_len'] = int(len_match.group(1))
+	    continue
+
+	revis_match = revis_re.match(line)
+	if revis_match:
+	    result['revision'] = int(revis_match.group(1))
+	    continue
+
+	submit_match = submit_re.match(line)
+	if submit_match:
+	    result['submitted_via'] = submit_match.group(1)
+	    continue
+
+    return result
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/lsdvd.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/lsdvd.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/lsdvd.py	(revision 4)
@@ -0,0 +1,234 @@
+# -----------------------------------------------------------------------
+# lsdvdinfo.py - parse dvd title structure
+# -----------------------------------------------------------------------
+# $Id: lsdvd.py,v 1.13.2.1 2005/06/30 17:28:24 dischi Exp $
+#
+# Use lsdvd to get dvd informations.
+#
+# -----------------------------------------------------------------------
+# $Log: lsdvd.py,v $
+# Revision 1.13.2.1  2005/06/30 17:28:24  dischi
+# fix to new lsdvd
+#
+# Revision 1.13  2005/01/13 20:19:34  dischi
+# detect video_ts in lower case
+#
+# Revision 1.12  2004/08/27 17:27:44  dischi
+# do not import ifoparser
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+
+
+import os
+import re
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+LSDVD_EXE='lsdvd'
+
+class DVDAudio(mediainfo.AudioInfo):
+    def __init__(self, data):
+        mediainfo.AudioInfo.__init__(self)
+        self.number   = int(data[1])
+        if data[3] != 'xx':
+            self.language = data[3]
+            try:
+                # some DVDs have a very bad language setting
+                self.language.encode()
+            except UnicodeError:
+                self.language = ''
+
+        try:
+            self.codec = data[7]
+            try:
+                self.samplerate = int(data[9])
+            except ValueError, e:
+                if data[9].lower().find('khz') > 0:
+                    pos = data[9].lower().find('khz')
+                    self.samplerate = int(data[9][:pos]) * 1000
+                else:
+                    raise e
+            self.channels = data[13]
+        except Exception, e:
+            # WTF, strange DVD, now try to find the bug (may not work)
+            self.codec = data[data.index('Format:') + 1]
+            try:
+                freq = data[data.index('Frequency:') + 1]
+                self.samplerate = int(freq)
+            except ValueError:
+                if freq.lower().find('khz') > 0:
+                    self.samplerate = int(freq[:freq.lower().find('khz')])*1000
+            self.channels = int(data[data.index('Channels:') + 1])
+
+
+class DVDVideo(mediainfo.VideoInfo):
+    def __init__(self, data):
+        mediainfo.VideoInfo.__init__(self)
+        self.width  = int(data[12])
+        self.height = int(data[14])
+        self.fps    = float(data[5])
+        self.aspect = data[10]
+
+
+class DVDTitle(mediainfo.AVInfo):
+    def __init__(self, data):
+        mediainfo.AVInfo.__init__(self)
+        self.number = int(data[1])
+
+        self.keys.append('subtitles')
+        self.keys.append('chapters')
+        
+        self.mime = 'video/mpeg'
+
+        l = re.split('[:.]', data[3])
+        self.length   = (int(l[0])*60+int(l[1]))*60+int(l[2])
+        self.trackno  = int(data[1])
+        self.chapters = int(data[5])
+        
+            
+class DVDInfo(DiscInfo):
+    def __init__(self, device):
+        DiscInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        if mediainfo.DEBUG > 1:
+            print 'trying lsdvd for scanning the disc'
+
+        if os.path.isdir(device):
+            self.valid = self.isDVDdir(device)
+        else:
+            self.valid = self.isDisc(device)
+
+        if self.valid and self.tracks:
+            self.keys.append('length')
+            self.length = 0
+            first       = 0
+
+            for t in self.tracks:
+                self.length += t.length
+                if not first:
+                    first = t.length
+            
+            if self.length/len(self.tracks) == first:
+                # badly mastered dvd
+                self.length = first
+
+            if mediainfo.DEBUG > 1:
+                print 'lsdvd detection ok'
+            
+        self.mime    = 'video/dvd'
+        self.type    = 'DVD'
+        self.subtype = 'video'
+
+
+    def lsdvd(self, path):
+        """
+        use lsdvd to get informations about this disc
+        """
+        import popen2
+        child = popen2.Popen3('%s -v -n -a -s "%s"' % \
+                              (LSDVD_EXE, path), 1, 100)
+        for line in child.fromchild.readlines():
+            data = line.replace(',', '').replace('\t', '').\
+                   replace('\n', '').lstrip(' ').split(' ')
+            if len(data) > 2:
+                if data[0] == 'Title:':
+                    ti = DVDTitle(data)
+                    self.appendtrack(ti)
+                elif data[0] == 'Audio:':
+                    self.tracks[-1].audio.append(DVDAudio(data))
+                elif data[0] == 'Subtitle:':
+                    self.tracks[-1].subtitles.append(data[3])
+                elif data[0] == 'VTS:':
+                    self.tracks[-1].video.append(DVDVideo(data))
+                    self.tracks[-1].video[-1].length = self.tracks[-1].length
+                elif data[:3] == ['Number', 'of', 'Angles:']:
+                    self.tracks[-1].angles = int(data[3])
+                    self.tracks[-1].keys.append('angles')
+                    
+        child.wait()
+        child.fromchild.close()
+        child.childerr.close()
+        child.tochild.close()
+
+        if len(self.tracks) > 0:
+            for ti in self.tracks:
+                ti.trackof = len(self.tracks)
+            return 1
+
+        return 0
+    
+            
+    def isDVDdir(self, dirname):
+        if os.path.isdir(dirname+'/VIDEO_TS') or \
+               os.path.isdir(dirname+'/video_ts') or \
+               os.path.isdir(dirname+'/Video_ts'):
+            return self.lsdvd(dirname)
+        return 0
+
+    
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        # brute force reading of the device to find out if it is a DVD
+        f = open(device,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+
+        if buffer.find('UDF') == -1:
+            f.close()
+            return 0
+
+        # seems to be a DVD, read a little bit more
+        buffer += f.read(550000)
+        f.close()
+
+        if buffer.find('VIDEO_TS') == -1 and \
+               buffer.find('VIDEO_TS.IFO') == -1 and \
+               buffer.find('OSTA UDF Compliant') == -1:
+            return 0
+
+        ret = self.lsdvd(device)
+        if not ret:
+            # we are very sure this is a DVD, maybe the drive was not
+            # ready, let's try again
+            return self.lsdvd(device)
+        return 1
+
+
+if os.environ.has_key('LSDVD') and os.environ['LSDVD']:
+    LSDVD_EXE = os.environ['LSDVD']
+else:
+    for path in os.environ['PATH'].split(':'):
+        if os.path.isfile(os.path.join(path, 'lsdvd')):
+            LSDVD_EXE = os.path.join(path, 'lsdvd')
+            break
+    else:
+        if mediainfo.DEBUG:
+            print 'ImportError: lsdvd not found'
+        raise ImportError
+
+mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DEVICE,
+                       mediainfo.TYPE_AV, DVDInfo )
+mmpython.registertype( 'video/dvd', mediainfo.EXTENSION_DIRECTORY,
+                       mediainfo.TYPE_AV, DVDInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/audioinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/audioinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/audioinfo.py	(revision 4)
@@ -0,0 +1,162 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# audioinfo.py - support for audio cds
+# -----------------------------------------------------------------------
+# $Id: audioinfo.py,v 1.22 2004/05/28 19:32:59 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import discinfo
+import DiscID
+import CDDB
+import cdrom
+
+_debug = mediainfo._debug
+
+class AudioDiscInfo(discinfo.DiscInfo):
+    def __init__(self,device):
+        discinfo.DiscInfo.__init__(self)
+        self.context = 'audio'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'audio/cd'
+        self.type = 'CD'
+        self.subtype = 'audio'
+
+    def isDisc(self, device):
+        if discinfo.DiscInfo.isDisc(self, device) != 1:
+            return 0
+        
+        disc_id = DiscID.disc_id(device)
+        if mmpython.USE_NETWORK:
+            try:
+                (query_stat, query_info) = CDDB.query(disc_id)
+            except:
+                # Oops no connection
+                query_stat = 404
+        else:
+            query_stat = 404
+
+
+        if query_stat == 210 or query_stat == 211:
+            # set this to success
+            query_stat = 200
+
+            for i in query_info:
+                if i['title'] != i['title'].upper():
+                    query_info = i
+                    break
+            else:
+                query_info = query_info[0]
+
+        elif query_stat != 200:
+            _debug("failure getting disc info, status %i" % query_stat)
+
+        if query_stat == 200:
+            qi = query_info['title'].split('/')
+            self.artist = qi[0].strip()
+            self.title = qi[1].strip()
+            for type in ('title', 'artist'):
+                if getattr(self, type) and getattr(self, type)[0] in ('"', '\'') \
+                       and getattr(self, type)[-1] in ('"', '\''):
+                    setattr(self, type, getattr(self, type)[1:-1])
+            (read_stat, read_info) = CDDB.read(query_info['category'], 
+                                               query_info['disc_id'])
+            # id = disc_id + number of tracks
+            #self.id = '%s_%s' % (query_info['disc_id'], disc_id[1])
+
+            if read_stat == 210:
+                for i in range(0, disc_id[1]):
+                    mi = mediainfo.MusicInfo()
+                    mi.title = read_info['TTITLE' + `i`]
+                    mi.album = self.title
+                    mi.artist = self.artist
+                    mi.genre = query_info['category']
+                    mi.codec = 'PCM'
+                    mi.samplerate = 44.1
+                    mi.trackno = i+1
+                    mi.trackof = disc_id[1]
+                    self.tracks.append(mi)
+                    for type in ('title', 'album', 'artist', 'genre'):
+                        if getattr(mi, type) and getattr(mi, type)[0] in ('"', '\'') \
+                           and getattr(mi, type)[-1] in ('"', '\''):
+                            setattr(mi, type, getattr(mi, type)[1:-1])
+            else:
+                _debug("failure getting track info, status: %i" % read_stat)
+                # set query_stat to somthing != 200
+                query_stat = 400
+            
+
+        if query_stat != 200:
+            _debug("failure getting disc info, status %i" % query_stat)
+            self.no_caching = 1
+            for i in range(0, disc_id[1]):
+                mi = mediainfo.MusicInfo()
+                mi.title = 'Track %s' % (i+1)
+                mi.codec = 'PCM'
+                mi.samplerate = 44.1
+                mi.trackno = i+1
+                mi.trackof = disc_id[1]
+                self.tracks.append(mi)
+                
+                
+        # read the tracks to generate the title list
+        device = open(device)
+        (first, last) = cdrom.toc_header(device)
+
+        lmin = 0
+        lsec = 0
+
+        num = 0
+        for i in range(first, last + 2):
+            if i == last + 1:
+                min, sec, frames = cdrom.leadout(device)
+            else:
+                min, sec, frames = cdrom.toc_entry(device, i)
+            if num:
+                self.tracks[num-1].length = (min-lmin)*60 + (sec-lsec)
+            num += 1
+            lmin, lsec = min, sec
+        device.close()
+
+        # correct bad titles for the tracks, containing also the artist
+        for t in self.tracks:
+            if not self.artist or not t.title.startswith(self.artist):
+                break
+        else:
+            for t in self.tracks:
+                t.title = t.title[len(self.artist):].lstrip('/ \t-_')
+
+        # correct bad titles for the tracks, containing also the title
+        for t in self.tracks:
+            if not self.title or not t.title.startswith(self.title):
+                break
+        else:
+            for t in self.tracks:
+                t.title = t.title[len(self.title):].lstrip('/ \t-_')
+        return 1
+    
+        
+mmpython.registertype( 'audio/cd', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_AUDIO,
+                       AudioDiscInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/ifomodule.c
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/ifomodule.c	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/ifomodule.c	(revision 4)
@@ -0,0 +1,259 @@
+//based on http://arnfast.net/projects/ifoinfo.php by Jens Arnfast 
+
+#include <Python.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <dvdread/dvd_reader.h>
+#include <dvdread/ifo_types.h>
+#include <dvdread/ifo_read.h>
+
+static PyObject *ifoinfo_open(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_close(PyObject *self, PyObject *args);
+
+static PyObject *ifoinfo_read_title(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_get_audio_tracks(PyObject *self, PyObject *args);
+static PyObject *ifoinfo_get_subtitle_tracks(PyObject *self, PyObject *args);
+
+static PyMethodDef IfoMethods[] = {
+  {"open",  ifoinfo_open, METH_VARARGS},
+  {"close",  ifoinfo_close, METH_VARARGS},
+  {"title", ifoinfo_read_title, METH_VARARGS},
+  {"audio", ifoinfo_get_audio_tracks, METH_VARARGS},
+  {"subtitle", ifoinfo_get_subtitle_tracks, METH_VARARGS},
+  {NULL, NULL}
+};
+
+
+void initifoparser() {
+   (void) Py_InitModule("ifoparser", IfoMethods);
+}
+
+
+dvd_reader_t *dvd;
+ifo_handle_t *ifofile;
+
+static PyObject *ifoinfo_open(PyObject *self, PyObject *args) {
+  tt_srpt_t *tt_srpt;
+  int i, ch, gotopt = -1, dochapters = -1;
+  char *dvddevice;
+
+  if (!PyArg_ParseTuple(args, "s", &dvddevice))
+    return Py_BuildValue("i", 0);
+
+  dvd = DVDOpen(dvddevice);
+  
+  if (!dvd)
+    return Py_BuildValue("i", 0);
+  
+  ifofile = ifoOpen(dvd, 0);
+  if (!ifofile) {
+    DVDClose(dvd);
+    return Py_BuildValue("i", 0);
+  }
+
+  tt_srpt = ifofile->tt_srpt;
+  return Py_BuildValue("i", tt_srpt->nr_of_srpts);
+}
+
+
+static PyObject *ifoinfo_close(PyObject *self, PyObject *args) {
+  ifoClose(ifofile);
+  DVDClose(dvd);
+  return Py_BuildValue("i", 0);
+}
+
+
+static PyObject *ifoinfo_read_title(PyObject *self, PyObject *args) {
+  int i;
+
+  tt_srpt_t *tt_srpt;
+  ifo_handle_t *vtsfile;
+  int vtsnum, ttnnum, j;
+  long playtime;
+
+  if (!PyArg_ParseTuple(args, "i", &i))
+    return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
+
+  i--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum  = tt_srpt->title[i].title_set_nr;
+  ttnnum  = tt_srpt->title[i].vts_ttn;
+     
+  vtsfile = ifoOpen(dvd, vtsnum);
+    
+  if (!vtsfile)
+    return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
+
+  playtime = 0;
+  
+  if (vtsfile->vts_pgcit) {
+    dvd_time_t *ttime;
+    ttime = &vtsfile->vts_pgcit->pgci_srp[0].pgc->playback_time;
+    playtime = ((ttime->hour * 60) + ttime->minute) * 60 + ttime->second;
+  }
+
+  // Number of Chapters, Number of Angles, Playback time, Num Audio tracks,
+  // Num subtitles
+  return Py_BuildValue("(iiiii)", tt_srpt->title[i].nr_of_ptts,
+		       tt_srpt->title[i].nr_of_angles, playtime,		       
+		       vtsfile->vtsi_mat->nr_of_vts_audio_streams,
+		       vtsfile->vtsi_mat->nr_of_vts_subp_streams);
+}
+
+
+static PyObject * ifoinfo_get_subtitle_tracks(PyObject *self, PyObject *args) {
+  char language[5];
+  int trackno;
+  tt_srpt_t *tt_srpt;
+  int vtsnum, ttnnum;
+  ifo_handle_t *vtsfile;
+  int i;
+  subp_attr_t *attr;
+  
+  if (!PyArg_ParseTuple(args, "ii", &i, &trackno))
+    return Py_BuildValue("(s)", "N/A");
+
+  i--;
+  trackno--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum = tt_srpt->title[i].title_set_nr;
+  ttnnum = tt_srpt->title[i].vts_ttn;
+  
+  vtsfile = ifoOpen(dvd, vtsnum);
+  
+  if (vtsfile->vts_pgcit) {
+    attr = &vtsfile->vtsi_mat->vts_subp_attr[trackno];
+
+    if ( attr->type == 0
+	 && attr->lang_code == 0
+	 && attr->zero1 == 0
+	 && attr->zero2 == 0
+	 && attr->lang_extension == 0 ) {
+      return Py_BuildValue("(s)", "N/A");
+    }
+
+    /* language code */
+    if (isalpha((int)(attr->lang_code >> 8)) && isalpha((int)(attr->lang_code & 0xff))) {
+      snprintf(language, 5, "%c%c", attr->lang_code >> 8, attr->lang_code & 0xff);
+    } else {
+      snprintf(language, 5, "%02x%02x", 0xff & (unsigned)(attr->lang_code >> 8), 
+	       0xff & (unsigned)(attr->lang_code & 0xff));
+    }
+
+    return Py_BuildValue("(s)", language);
+  }
+}
+
+
+static PyObject * ifoinfo_get_audio_tracks(PyObject *self, PyObject *args) {
+  char audioformat[10];
+  char audiolang[5];
+  int audiochannels;
+  int audioid;
+  int audiofreq;
+  audio_attr_t *attr;
+  int i;
+  int trackno;
+  tt_srpt_t *tt_srpt;
+  int vtsnum, ttnnum;
+  ifo_handle_t *vtsfile;
+  
+  if (!PyArg_ParseTuple(args, "ii", &i, &trackno))
+    return Py_BuildValue("i", 0);
+
+  i--;
+  trackno--;
+  
+  tt_srpt = ifofile->tt_srpt;
+  vtsnum = tt_srpt->title[i].title_set_nr;
+  ttnnum = tt_srpt->title[i].vts_ttn;
+  
+  vtsfile = ifoOpen(dvd, vtsnum);
+  
+  if (vtsfile->vts_pgcit && vtsfile->vtsi_mat) {
+    attr = &vtsfile->vtsi_mat->vts_audio_attr[trackno];
+
+    audioid = trackno + 128;
+    
+    if ( attr->audio_format == 0
+	 && attr->multichannel_extension == 0
+	 && attr->lang_type == 0
+	 && attr->application_mode == 0
+	 && attr->quantization == 0
+	 && attr->sample_frequency == 0
+	 && attr->channels == 0
+	 && attr->lang_extension == 0
+	 && attr->unknown1 == 0
+	 && attr->unknown1 == 0) {
+      snprintf(audioformat, 10, "Unknown");
+      return Py_BuildValue("i", 0);
+    }
+    
+    /* audio format */
+    switch (attr->audio_format) {
+    case 0:
+      snprintf(audioformat, 10, "ac3");
+      break;
+    case 1:
+      snprintf(audioformat, 10, "N/A");
+      break;
+    case 2:
+      snprintf(audioformat, 10, "mpeg1");
+      break;
+    case 3:
+      snprintf(audioformat, 10, "mpeg2ext");
+    break;
+    case 4:
+      snprintf(audioformat, 10, "lpcm");
+      break;
+    case 5:
+      snprintf(audioformat, 10, "N/A");
+      break;
+    case 6:
+      snprintf(audioformat, 10, "dts");
+      break;
+    default:
+      snprintf(audioformat, 10, "N/A");
+    }
+    
+    switch (attr->lang_type) {
+    case 0:
+      assert(attr->lang_code == 0 || attr->lang_code == 0xffff);
+      snprintf(audiolang, 5, "N/A");
+      break;
+    case 1:
+      snprintf(audiolang, 5, "%c%c", attr->lang_code>>8, attr->lang_code & 0xff);
+      break;
+    default:
+      snprintf(audiolang, 5, "N/A");
+    }
+    
+    switch(attr->sample_frequency) {
+    case 0:
+      audiofreq = 48;
+      break;
+    case 1:
+      audiofreq = -1;
+      break;
+    default:
+      audiofreq = -1;
+    }
+    
+    audiochannels = attr->channels + 1;
+    
+    //AUDIOTRACK: ID=%i; LANG=%s; FORMAT=%s; CHANNELS=%i; FREQ=%ikHz
+    return Py_BuildValue("(issii)", audioid, audiolang, audioformat, audiochannels,
+			 audiofreq);
+  }
+
+  return NULL;
+}
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/discinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/discinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/discinfo.py	(revision 4)
@@ -0,0 +1,295 @@
+# -----------------------------------------------------------------------
+# discinfo.py - basic class for any discs containing collections of
+# media.
+# -----------------------------------------------------------------------
+# $Id: discinfo.py,v 1.23 2004/09/14 20:12:25 dischi Exp $
+#
+# $Log: discinfo.py,v $
+# Revision 1.23  2004/09/14 20:12:25  dischi
+# fix future warning
+#
+# Revision 1.22  2004/08/28 17:27:16  dischi
+# handle empty discs
+#
+# Revision 1.21  2004/06/25 13:20:35  dischi
+# FreeBSD patches
+#
+# Revision 1.20  2004/02/08 17:44:05  dischi
+# close fd
+#
+# Revision 1.19  2004/01/24 18:40:44  dischi
+# add md5 as possible way to generate the id
+#
+# Revision 1.18  2003/11/07 09:43:40  dischi
+# make interface compatible to old one
+#
+# Revision 1.17  2003/11/05 20:58:26  dischi
+# detect mixed audio cds
+#
+# Revision 1.16  2003/10/18 11:13:03  dischi
+# patch from Cyril Lacoux to detect blank discs
+#
+# Revision 1.15  2003/09/23 13:51:27  outlyer
+# More *BSD fixes from Lars; repairs a problem in his older patch.
+#
+# Revision 1.14  2003/09/14 13:32:12  dischi
+# set self.id for audio discs in discinfo.py to make it possible to use the cache for cddb
+#
+# Revision 1.13  2003/09/14 01:41:37  outlyer
+# FreeBSD support
+#
+# Revision 1.12  2003/09/10 18:50:31  dischi
+# error handling
+#
+# Revision 1.11  2003/08/26 21:21:18  outlyer
+# Fix two more Python 2.3 warnings.
+#
+# Revision 1.10  2003/08/26 18:01:26  outlyer
+# Patch from Lars Eggert for FreeBSD support
+#
+# Revision 1.9  2003/08/23 17:54:14  dischi
+# move id translation of bad chars directly after parsing
+#
+# Revision 1.8  2003/07/04 15:32:52  outlyer
+# Fix the label so we don't try to cache into a directory instead of a file.
+#
+# Revision 1.7  2003/07/02 22:04:26  dischi
+# just to be save
+#
+# Revision 1.6  2003/07/02 22:03:13  dischi
+# cache the disc id, it cannot change in 1 sec
+#
+# Revision 1.5  2003/06/23 19:26:16  dischi
+# Fixed bug in the cdrommodule that the file was not closed after usage.
+# The result was a drive you can't eject while the program (e.g. Freevo)
+# is running. Added cvs log for DiscID and cdrommodule to keep track of
+# all changes we did for mmpython.
+#
+# Revision 1.4  2003/06/23 09:22:54  the_krow
+# Typo and Indentation fixes.
+#
+# Revision 1.3  2003/06/10 22:11:36  dischi
+# some fixes
+#
+# Revision 1.2  2003/06/10 11:50:52  dischi
+# Moved all ioctl calls for discs to discinfo.cdrom_disc_status. This function
+# uses try catch around ioctl so it will return 0 (== no disc) for systems
+# without ioctl (e.g. Windows)
+#
+# Revision 1.1  2003/06/10 10:56:54  the_krow
+# - Build try-except blocks around disc imports to make it run on platforms
+#   not compiling / running the C extensions.
+# - moved DiscInfo class to disc module
+# - changed video.VcdInfo to be derived from CollectionInfo instead of
+#   DiskInfo so it can be used without the cdrom extensions which are
+#   hopefully not needed for bin-files.
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+from mmpython import mediainfo
+import os
+import re
+import time
+import array
+import md5
+from struct import *
+
+CREATE_MD5_ID = 0
+
+try:
+    from fcntl import ioctl
+    import DiscID
+except:
+    print 'WARNING: failed to import ioctl, discinfo won\'t work'
+
+
+def cdrom_disc_status(device, handle_mix = 0):
+    """
+    check the current disc in device
+    return: no disc (0), audio cd (1), data cd (2), blank cd (3)
+    """
+    CDROM_DRIVE_STATUS=0x5326
+    CDSL_CURRENT=( (int ) ( ~ 0 >> 1 ) )
+    CDROM_DISC_STATUS=0x5327
+    CDS_AUDIO=100
+    CDS_MIXED=105
+    CDS_DISC_OK=4
+    
+    # FreeBSD ioctls - there is no CDROM.py
+    # XXX 0xc0086305 below creates a warning, but 0xc0086305L
+    # doesn't work. Suppress that warning for Linux users,
+    # until a better solution can be found.
+    if os.uname()[0] == 'FreeBSD':
+        CDIOREADTOCENTRYS = 0xc0086305L
+        CD_MSF_FORMAT = 2
+        
+    try:
+        fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
+        if os.uname()[0] == 'FreeBSD':
+            try:
+                cd_toc_entry = array.array('c', '\000'*4096)
+                (address, length) = cd_toc_entry.buffer_info()
+                buf = pack('BBHP', CD_MSF_FORMAT, 0, length, address)
+                s = ioctl(fd, CDIOREADTOCENTRYS, buf)
+                s = CDS_DISC_OK
+            except:
+                s = CDS_NO_DISC
+        else:
+            s = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)
+    except:
+        print 'ERROR: no permission to read %s' % device
+        print 'Media detection not possible, set drive to \'empty\''
+        
+        # maybe we need to close the fd if ioctl fails, maybe
+        # open fails and there is no fd, maye we aren't running
+        # linux and don't have ioctl
+        try:
+            os.close(fd)
+        except:
+            pass
+        return 0
+
+    if not s == CDS_DISC_OK:
+        # no disc, error, whatever
+        return 0
+    
+    if os.uname()[0] == 'FreeBSD':
+        s = 0
+        # We already have the TOC from above
+        for i in range(0, 4096, 8):
+            control = unpack('B', cd_toc_entry[i+1])[0] & 4
+            track = unpack('B', cd_toc_entry[i+2])[0]
+            if track == 0:
+                break
+            if control == 0 and s != CDS_MIXED:
+                s = CDS_AUDIO
+            elif control != 0:
+                if s == CDS_AUDIO:
+                    s = CDS_MIXED
+                else:
+                    s = 100 + control # ugly, but encodes Linux ioctl returns
+            elif control == 5:
+                s = CDS_MIXED
+
+    else:
+        s = ioctl(fd, CDROM_DISC_STATUS)
+    os.close(fd)
+    if s == CDS_MIXED and handle_mix:
+        return 4
+    if s == CDS_AUDIO or s == CDS_MIXED:
+        return 1
+    
+    try:
+        fd = open(device, 'rb')
+        # try to read from the disc to get information if the disc
+        # is a rw medium not written yet
+        
+        fd.seek(32768) # 2048 multiple boundary for FreeBSD
+        # FreeBSD doesn't return IOError unless we try and read:
+        fd.read(1)
+    except IOError:
+        # not readable
+    	fd.close()
+	return 3
+    else:
+        # disc ok
+    	fd.close()
+    	return 2
+    
+
+id_cache = {}
+
+def cdrom_disc_id(device, handle_mix=0):
+    """
+    return the disc id of the device or None if no disc is there
+    """
+    global id_cache
+    try:
+        if id_cache[device][0] + 0.9 > time.time():
+            return id_cache[device][1:]
+    except:
+        pass
+
+    disc_type = cdrom_disc_status(device, handle_mix=handle_mix)
+    if disc_type == 0 or disc_type == 3:
+        return 0, None
+        
+    elif disc_type == 1 or disc_type == 4:
+        disc_id = DiscID.disc_id(device)
+        id = '%08lx_%d' % (disc_id[0], disc_id[1])
+    else:
+        f = open(device,'rb')
+
+        if os.uname()[0] == 'FreeBSD':
+            # FreeBSD can only seek to 2048 multiple boundaries.
+            # Below works on Linux and FreeBSD:
+            f.seek(32768)
+            id = f.read(829)
+            label = id[40:72]
+            id = id[813:829]
+        else:
+            f.seek(0x0000832d)
+            id = f.read(16)
+            f.seek(32808, 0)
+            label = f.read(32)
+
+        if CREATE_MD5_ID:
+            id_md5 = md5.new()
+            id_md5.update(f.read(51200))
+            id = id_md5.hexdigest()
+
+        f.close()
+            
+        m = re.match("^(.*[^ ]) *$", label)
+        if m:
+            id = '%s%s' % (id, m.group(1))
+        id = re.compile('[^a-zA-Z0-9()_-]').sub('_', id)
+            
+        
+    id_cache[device] = time.time(), disc_type, id
+    id = id.replace('/','_')
+    return disc_type, id
+
+
+class DiscInfo(mediainfo.CollectionInfo):
+    def isDisc(self, device):
+        (type, self.id) = cdrom_disc_id(device, handle_mix=1)
+        if type != 2:
+            if type == 4:
+                self.keys.append('mixed')
+                self.mixed = 1
+                type = 1 
+            return type
+        
+        if CREATE_MD5_ID:
+            if len(self.id) == 32:
+                self.label = ''
+            else:
+                self.label = self.id[32:]
+        else:
+            if len(self.id) == 16:
+                self.label = ''
+            else:
+                self.label = self.id[16:]
+
+        self.keys.append('label')
+        return type
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/DiscID.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/DiscID.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/DiscID.py	(revision 4)
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Module for fetching information about an audio compact disc and
+# returning it in a format friendly to CDDB.
+
+# If called from the command line, will print out disc info in a
+# format identical to Robert Woodcock's 'cd-discid' program.
+
+# Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+# This work is released under the GNU GPL, version 2 or later.
+
+# Release version 1.3
+
+
+# changes for mmpython:
+#
+# $Log: DiscID.py,v $
+# Revision 1.4  2004/11/14 19:26:38  dischi
+# fix future warning
+#
+# Revision 1.3  2003/06/23 19:26:16  dischi
+# Fixed bug in the cdrommodule that the file was not closed after usage.
+# The result was a drive you can't eject while the program (e.g. Freevo)
+# is running. Added cvs log for DiscID and cdrommodule to keep track of
+# all changes we did for mmpython.
+#
+#
+
+try:
+    import cdrom, sys
+except ImportError:
+    # Seems cdrom has either not been compiler or is not supported
+    # on this System
+    pass
+    
+
+def cddb_sum(n):
+    ret = 0
+    
+    while n > 0:
+	ret = ret + (n % 10)
+	n = n / 10
+
+    return ret
+
+def disc_id(device):
+    device = cdrom.open(device)
+    (first, last) = cdrom.toc_header(device)
+
+    track_frames = []
+    checksum = 0
+    
+    for i in range(first, last + 1):
+	(min, sec, frame) = cdrom.toc_entry(device, i)
+	checksum = checksum + cddb_sum(min*60 + sec)
+	track_frames.append(min*60*75 + sec*75 + frame)
+
+    (min, sec, frame) = cdrom.leadout(device)
+    track_frames.append(min*60*75 + sec*75 + frame)
+
+    total_time = (track_frames[-1] / 75) - (track_frames[0] / 75)
+	       
+    discid = ((long(checksum) % 0xff) << 24 | total_time << 8 | last)
+    cdrom.close(device)
+    return [discid, last] + track_frames[:-1] + [ track_frames[-1] / 75 ]
+
+if __name__ == '__main__':
+
+    dev_name = None
+    device = None
+    
+    if len(sys.argv) >= 2:
+	dev_name = sys.argv[1]
+
+    if dev_name:
+        device = open(dev_name)
+    else:
+        device = open()
+        
+    disc_info = disc_id(device)
+
+    print ('%08lx' % disc_info[0]),
+
+    for i in disc_info[1:]:
+	print ('%d' % i),
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/cdrommodule.c
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/cdrommodule.c	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/cdrommodule.c	(revision 4)
@@ -0,0 +1,275 @@
+/* 
+ * cdrommodule.c 
+ * Python extension module for reading in audio CD-ROM data
+ *
+ * Please port me to other OSes besides Linux, Solaris, OpenBSD,
+ * and FreeBSD! 
+ *
+ * See the README for info.
+ *
+ * Written 17 Nov 1999 by Ben Gertzfield <che@debian.org>
+ * This work is released under the GNU GPL, version 2 or later.
+ *
+ * FreeBSD support by Michael Yoon <michael@yoon.org>
+ * OpenBSD support added by Alexander Guy <alex@andern.org>
+ *
+ * Thanks to Viktor Fougstedt <viktor@dtek.chalmers.se> for info
+ * on the <sys/cdio.h> include file to make this work on Solaris!
+ *
+ * Release version 1.2
+ *
+ *
+ *
+ * changes for mmpython:
+ *
+ * $Log: cdrommodule.c,v $
+ * Revision 1.2  2003/06/23 19:26:16  dischi
+ * Fixed bug in the cdrommodule that the file was not closed after usage.
+ * The result was a drive you can't eject while the program (e.g. Freevo)
+ * is running. Added cvs log for DiscID and cdrommodule to keep track of
+ * all changes we did for mmpython.
+ *
+ *
+ * CVS ID: $Id: cdrommodule.c,v 1.2 2003/06/23 19:26:16 dischi Exp $
+ */
+
+#include "Python.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#ifdef __linux__
+#include <linux/cdrom.h>
+#endif
+
+#if defined(sun) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#include <sys/cdio.h>
+#endif
+
+/* 
+ * Since FreeBSD has identical support but different names for lots
+ * of these structs and constants, we'll just #define CDDB_WHATEVER
+ * so that we don't have to repeat the code.
+ */
+
+#ifdef __FreeBSD__
+
+#define CDDB_TOC_HEADER_STRUCT ioc_toc_header 
+#define CDDB_STARTING_TRACK_FIELD starting_track 
+#define CDDB_ENDING_TRACK_FIELD ending_track
+#define CDDB_READ_TOC_HEADER_FLAG CDIOREADTOCHEADER 
+#define CDDB_TOC_ENTRY_STRUCT ioc_read_toc_single_entry 
+#define CDDB_TRACK_FIELD track 
+#define CDDB_FORMAT_FIELD address_format 
+#define CDDB_MSF_FORMAT CD_MSF_FORMAT 
+#define CDDB_ADDR_FIELD entry.addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDIOREADTOCENTRY 
+#define CDDB_CDROM_LEADOUT 0xaa 
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#define CDDB_DEFAULT_CDROM_FLAGS 0
+
+#elif defined(__OpenBSD__)
+
+#define CDDB_TOC_HEADER_STRUCT ioc_toc_header 
+#define CDDB_STARTING_TRACK_FIELD starting_track 
+#define CDDB_ENDING_TRACK_FIELD ending_track
+#define CDDB_READ_TOC_HEADER_FLAG CDIOREADTOCHEADER 
+#define CDDB_TOC_ENTRY_STRUCT ioc_read_toc_entry 
+#define CDDB_TRACK_FIELD starting_track 
+#define CDDB_FORMAT_FIELD address_format 
+#define CDDB_MSF_FORMAT CD_MSF_FORMAT  
+#define CDDB_ADDR_FIELD data->addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDIOREADTOCENTRIES
+#define CDDB_CDROM_LEADOUT 0xaa 
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#define CDDB_DEFAULT_CDROM_FLAGS 0
+
+#else /* Linux and Solaris */
+
+#define CDDB_TOC_HEADER_STRUCT cdrom_tochdr 
+#define CDDB_STARTING_TRACK_FIELD cdth_trk0 
+#define CDDB_ENDING_TRACK_FIELD cdth_trk1 
+#define CDDB_READ_TOC_HEADER_FLAG CDROMREADTOCHDR 
+#define CDDB_TOC_ENTRY_STRUCT cdrom_tocentry
+#define CDDB_TRACK_FIELD cdte_track 
+#define CDDB_FORMAT_FIELD cdte_format 
+#define CDDB_MSF_FORMAT CDROM_MSF 
+#define CDDB_ADDR_FIELD cdte_addr 
+#define CDDB_READ_TOC_ENTRY_FLAG CDROMREADTOCENTRY 
+#define CDDB_CDROM_LEADOUT CDROM_LEADOUT
+
+#ifdef sun
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/vol/alias/cdrom0"
+#else
+#define CDDB_DEFAULT_CDROM_DEVICE "/dev/cdrom"
+#endif /* sun */
+
+#define CDDB_DEFAULT_CDROM_FLAGS O_RDONLY | O_NONBLOCK
+
+#endif /* __FreeBSD__ */
+
+static PyObject *cdrom_error;
+
+static PyObject *cdrom_toc_header(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_HEADER_STRUCT hdr;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_HEADER_FLAG, &hdr) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+    
+    return Py_BuildValue("bb", hdr.CDDB_STARTING_TRACK_FIELD, 
+			 hdr.CDDB_ENDING_TRACK_FIELD);
+}
+
+static PyObject *cdrom_toc_entry(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_ENTRY_STRUCT entry;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+    unsigned char track;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!b", &PyFile_Type, &cdrom_fileobj, &track))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    entry.CDDB_TRACK_FIELD = track;
+    entry.CDDB_FORMAT_FIELD = CDDB_MSF_FORMAT;
+
+#if defined(__OpenBSD__)
+    entry.data = &data;
+    entry.data_len = sizeof(data);
+#endif
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_ENTRY_FLAG, &entry) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    return Py_BuildValue("bbb", entry.CDDB_ADDR_FIELD.msf.minute, 
+			 entry.CDDB_ADDR_FIELD.msf.second, 
+			 entry.CDDB_ADDR_FIELD.msf.frame);
+}
+
+static PyObject *cdrom_leadout(PyObject *self, PyObject *args)
+{
+    struct CDDB_TOC_ENTRY_STRUCT entry;
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+
+    entry.CDDB_TRACK_FIELD = CDDB_CDROM_LEADOUT;
+    entry.CDDB_FORMAT_FIELD = CDDB_MSF_FORMAT;
+
+#if defined(__OpenBSD__)
+    entry.data = &data;
+    entry.data_len = sizeof(data);
+#endif
+
+    if (ioctl(cdrom_fd, CDDB_READ_TOC_ENTRY_FLAG, &entry) < 0) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    return Py_BuildValue("bbb", entry.CDDB_ADDR_FIELD.msf.minute, 
+			 entry.CDDB_ADDR_FIELD.msf.second, 
+			 entry.CDDB_ADDR_FIELD.msf.frame);
+}
+
+int cdrom_close(FILE *cdrom_file) 
+{
+  return 0;
+}
+
+static PyObject *cdrom_really_close(PyObject *self, PyObject *args)
+{
+    PyObject *cdrom_fileobj;
+    int cdrom_fd;
+
+#if defined(__OpenBSD__)
+    struct cd_toc_entry data;
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!", &PyFile_Type, &cdrom_fileobj))
+	return  NULL;
+
+    cdrom_fd = fileno(PyFile_AsFile(cdrom_fileobj));
+    close(cdrom_fd);
+    return Py_BuildValue("b", 1);
+}
+
+static PyObject* cdrom_open(PyObject *self, PyObject *args)
+{
+    int cdrom_fd;
+    FILE *cdrom_file;
+    char *cdrom_device = CDDB_DEFAULT_CDROM_DEVICE;
+    int cdrom_open_flags = CDDB_DEFAULT_CDROM_FLAGS;
+
+    PyObject *cdrom_file_object;
+
+    if (!PyArg_ParseTuple(args, "|si", &cdrom_device, &cdrom_open_flags))
+	return NULL;
+
+    cdrom_fd = open(cdrom_device, cdrom_open_flags);
+
+    if (cdrom_fd == -1) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+    
+    cdrom_file = fdopen(cdrom_fd, "r");
+
+    if (cdrom_file == NULL) {
+	PyErr_SetFromErrno(cdrom_error);
+	return NULL;
+    }
+
+    cdrom_file_object = PyFile_FromFile(cdrom_file, cdrom_device, "r", cdrom_close);
+
+    if (cdrom_file_object == NULL) {
+	PyErr_SetString(cdrom_error, "Internal conversion from file pointer to Python object failed");
+	fclose(cdrom_file);
+	return NULL;
+    }
+
+    return Py_BuildValue("O", cdrom_file_object);
+}
+
+static PyMethodDef cdrom_methods[] = {
+    { "toc_header", cdrom_toc_header, METH_VARARGS },
+    { "toc_entry", cdrom_toc_entry, METH_VARARGS },
+    { "leadout", cdrom_leadout, METH_VARARGS},
+    { "open", cdrom_open, METH_VARARGS},
+    { "close", cdrom_really_close, METH_VARARGS},
+    { NULL, NULL }
+};
+
+void initcdrom(void)
+{
+    PyObject *module, *dict;
+
+    module = Py_InitModule("cdrom", cdrom_methods);
+    dict = PyModule_GetDict(module);
+    cdrom_error = PyErr_NewException("cdrom.error", NULL, NULL);
+    PyDict_SetItemString(dict, "error", cdrom_error);
+}
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/datainfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/datainfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/disc/datainfo.py	(revision 4)
@@ -0,0 +1,50 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# datainfo.py - info about a normal data disc
+# -----------------------------------------------------------------------
+# $Id: datainfo.py,v 1.3 2004/02/28 18:45:05 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+from discinfo import DiscInfo
+
+class DataDiscInfo(DiscInfo):
+    def __init__(self,device):
+        DiscInfo.__init__(self)
+        self.context = 'unknown'
+        self.offset = 0
+        self.valid = self.isDisc(device)
+        self.mime = 'unknown/unknown'
+        self.type = 'CD'
+        self.subtype = 'data'
+
+    def isDisc(self, device):
+        if DiscInfo.isDisc(self, device) != 2:
+            return 0
+
+        return 1
+
+
+
+mmpython.registertype( 'cd/unknown', mediainfo.EXTENSION_DEVICE, mediainfo.TYPE_NONE, DataDiscInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/ImageInfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/ImageInfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/ImageInfo.py	(revision 4)
@@ -0,0 +1,124 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: ImageInfo.py,v 1.2 2005/04/16 15:01:53 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: ImageInfo.py,v $
+# Revision 1.2  2005/04/16 15:01:53  dischi
+# read gthumb comment files
+#
+# Revision 1.1  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import mmpython
+from mmpython import mediainfo
+
+import os
+import gzip
+#from xml.utils import qp_xml   #this doesn't exist for some reason
+import xml.parsers.expat as qp_xml
+
+DEBUG = mediainfo.DEBUG
+
+try:
+    import Image
+except:
+    if DEBUG:
+        print 'Python Imaging not found'
+
+import bins
+
+def add(filename, object):
+    if os.path.isfile(filename + '.xml'):
+        try:
+            binsinfo = bins.get_bins_desc(filename)
+            # get needed keys from exif infos
+            for key in mediainfo.IMAGECORE + mediainfo.MEDIACORE:
+                if not object[key] and binsinfo['exif'].has_key(key):
+                    object[key] = binsinfo['exif'][key]
+            # get _all_ infos from description
+            for key in binsinfo['desc']:
+                object[key] = binsinfo['desc'][key]
+                if not key in mediainfo.IMAGECORE + mediainfo.MEDIACORE:
+                    # if it's in desc it must be important
+                    object.keys.append(key)
+        except Exception, e:
+            if DEBUG:
+                print e
+            pass
+
+    comment_file = os.path.join(os.path.dirname(filename),
+                                '.comments',
+                                os.path.basename(filename) + '.xml')
+    if os.path.isfile(comment_file):
+        try:
+            f = gzip.open(comment_file)
+            p = qp_xml.Parser()
+            tree = p.parse(f)
+            f.close()
+            for c in tree.children:
+                if c.name == 'Place':
+                    object.location = c.textof()
+                if c.name == 'Note':
+                    object.description = c.textof()
+        except:
+            pass
+    try:
+        i = Image.open(filename)
+    except:
+        return 0
+
+    if not object.mime:
+        object.mime = 'image/%s' % i.format.lower()
+        
+    object.type = i.format_description
+
+    if i.info.has_key('dpi'):
+        object['dpi'] = '%sx%s' % i.info['dpi']
+
+    if DEBUG:
+        for info in i.info:
+            if not info == 'exif':
+                print '%s: %s' % (info, i.info[info])
+
+    object.mode = i.mode
+    if not object.height:
+        object.width, object.height = i.size
+
+    return 1
+
+
+
+
+
+class ImageInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.mime  = ''
+        self.type  = ''
+        self.valid = add(file.name, self)
+        
+mmpython.registertype( 'image/gif', ('gif',), mediainfo.TYPE_IMAGE, ImageInfo )
+mmpython.registertype( 'image/bmp', ('bmp',), mediainfo.TYPE_IMAGE, ImageInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/IPTC.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/IPTC.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/IPTC.py	(revision 4)
@@ -0,0 +1,117 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: IPTC.py,v 1.9 2004/05/04 22:03:17 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: IPTC.py,v $
+# Revision 1.9  2004/05/04 22:03:17  dischi
+# handle bad jpeg
+#
+# Revision 1.8  2003/06/09 16:11:57  the_krow
+# TIFF parser changed to new tables structure
+# debug statements removed / changed to _debug
+#
+# Revision 1.7  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.6  2003/05/13 17:49:41  the_krow
+# IPTC restructured
+# EXIF Height read correctly
+# JPEG Endmarker read
+#
+# Revision 1.5  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.4  2003/05/13 15:16:02  the_krow
+# width+height hacked
+#
+# Revision 1.3  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+# http://www.ap.org/apserver/userguide/codes.htm
+
+from struct import unpack
+
+def flatten(list):
+    try:
+        for i in list.keys():
+            val = list[i]
+            if len(val) == 0: list[i] = None
+            elif len(val) == 1: list[i] = val[0]
+            else: list[i] = tuple(val)
+        return list
+    except:
+        return []
+
+def parseiptc(app):
+    iptc = {}
+    if app[:14] == "Photoshop 3.0\x00":
+       app = app[14:]
+    if 1:
+       # parse the image resource block
+       offset = 0
+       data = None
+       while app[offset:offset+4] == "8BIM":
+          offset = offset + 4
+          # resource code
+          code = unpack("<H", app[offset:offset+2])[0]
+          offset = offset + 2
+          # resource name (usually empty)
+          name_len = ord(app[offset])
+          name = app[offset+1:offset+1+name_len]
+          offset = 1 + offset + name_len
+          if offset & 1:
+              offset = offset + 1
+          # resource data block
+          size = unpack("<L", app[offset:offset+4])[0]
+          offset = offset + 4
+          if code == 0x0404:
+              # 0x0404 contains IPTC/NAA data
+              data = app[offset:offset+size]
+              break
+          offset = offset + size
+          if offset & 1:
+              offset = offset + 1
+       if not data:
+          return None
+       offset = 0
+       iptc = {}
+       while 1:
+           try:
+               intro = ord(data[offset])
+           except IndexError:
+               return ''
+           if intro != 0x1c:
+               return iptc
+           (key,len) = unpack('>HH',data[offset+1:offset+5])
+           val = data[offset+5:offset+len+5]
+           if iptc.has_key(key):
+               iptc[key].append(val)
+           else:
+               iptc[key] = [val]
+           offset += len + 5
+    return iptc
+    
+    
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/pnginfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/pnginfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/pnginfo.py	(revision 4)
@@ -0,0 +1,144 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: pnginfo.py,v 1.11 2005/04/16 17:09:12 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: pnginfo.py,v $
+# Revision 1.11  2005/04/16 17:09:12  dischi
+# add thumbnail data to internal vars
+#
+# Revision 1.10  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.9  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.8  2003/06/23 20:59:11  the_krow
+# PNG should now fill a correct table.
+#
+# Revision 1.7  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.6  2003/06/08 20:27:42  dischi
+# small fix for broken files and fixed a wrong bins_data call
+#
+# Revision 1.5  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# Revision 1.1  2003/05/13 12:31:11  the_krow
+# + GNU Copyright Notice
+# + PNG Parsing
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+import zlib
+import ImageInfo
+
+# interesting file format info:
+# http://www.libpng.org/pub/png/png-sitemap.html#programming
+# http://pmt.sourceforge.net/pngmeta/
+
+PNGSIGNATURE = "\211PNG\r\n\032\n"
+
+_print = mediainfo._debug
+
+class PNGInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.iptc = None        
+        self.mime = 'image/png'
+        self.type = 'PNG image'
+        self.valid = 1
+        signature = file.read(8)
+        if ( signature != PNGSIGNATURE ):
+            self.valid = 0
+            return
+        self.meta = {}
+        while self._readChunk(file):
+            pass
+        if len(self.meta.keys()):
+            self.appendtable( 'PNGMETA', self.meta )
+        for key, value in self.meta.items():
+            if key.startswith('Thumb:') or key == 'Software':
+                setattr(self, key, value)
+                if not key in self.keys:
+                    self.keys.append(key)
+        ImageInfo.add(file.name, self)
+        return       
+        
+    def _readChunk(self,file):
+        try:
+            (length, type) = struct.unpack('>I4s', file.read(8))
+        except:
+            return 0
+        if ( type == 'tEXt' ):
+          _print('latin-1 Text found.')
+          (data, crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          (key, value) = data.split('\0')
+          self.meta[key] = value
+          _print("%s -> %s" % (key,value))
+        elif ( type == 'zTXt' ):
+          _print('Compressed Text found.')
+          (data,crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          split = data.split('\0')
+          key = split[0]
+          value = "".join(split[1:])
+          compression = ord(value[0])
+          value = value[1:]
+          if compression == 0:
+              decompressed = zlib.decompress(value)
+              _print("%s (Compressed %i) -> %s" % (key,compression,decompressed))
+          else:
+              _print("%s has unknown Compression %c" % (key,compression))
+          self.meta[key] = value
+        elif ( type == 'iTXt' ):
+          _print('International Text found.')
+          (data,crc) = struct.unpack('>%isI' % length,file.read(length+4))
+          (key, value) = data.split('\0')
+          self.meta[key] = value
+          _print("%s -> %s" % (key,value))
+        else:
+          file.seek(length+4,1)
+          _print("%s of length %d ignored." % (type, length))
+        return 1
+
+
+mmpython.registertype( 'image/png', ('png',), mediainfo.TYPE_IMAGE, PNGInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/tiffinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/tiffinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/tiffinfo.py	(revision 4)
@@ -0,0 +1,157 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: tiffinfo.py,v 1.11 2004/05/20 15:56:31 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: tiffinfo.py,v $
+# Revision 1.11  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.10  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.9  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.8  2003/06/09 16:11:57  the_krow
+# TIFF parser changed to new tables structure
+# debug statements removed / changed to _debug
+#
+# Revision 1.7  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.6  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.5  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.4  2003/05/13 15:52:43  the_krow
+# Caption added
+#
+# Revision 1.3  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.2  2003/05/13 15:16:02  the_krow
+# width+height hacked
+#
+# Revision 1.1  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# -----------------------------------------------------------------------
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+import ImageInfo
+
+MOTOROLASIGNATURE = 'MM\x00\x2a'
+INTELSIGNATURE = 'II\x2a\x00'
+
+# http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf
+
+_debug = mediainfo._debug
+
+class TIFFInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        self.iptc = None        
+        self.mime = 'image/tiff'
+        self.type = 'TIFF image'
+        self.intel = 0
+        self.valid = 0
+        iptc = {}
+        header = file.read(8)
+        if header[:4] == MOTOROLASIGNATURE:
+            self.valid = 1
+            self.intel = 0
+            (offset,) = struct.unpack(">I", header[4:8])
+            file.seek(offset)
+            (len,) = struct.unpack(">H", file.read(2))
+            app = file.read(len*12)
+            for i in range(len):
+                (tag, type, length, value, offset) = struct.unpack('>HHIHH', app[i*12:i*12+12])
+                _debug("[%i/%i] tag: 0x%.4x, type 0x%.4x, len %d, value %d, offset %d)" % (i,len,tag,type,length,value,offset))
+                if tag == 0x8649:
+                    file.seek(offset,0)
+                    iptc = IPTC.flatten(IPTC.parseiptc(file.read(1000)))
+                elif tag == 0x0100:
+                    if value != 0:
+                        self.width = value
+                    else:
+                        self.width = offset
+                elif tag == 0x0101:
+                    if value != 0:
+                        self.height = value
+                    else:
+                        self.height = offset
+
+        elif header[:4] == INTELSIGNATURE:
+            self.valid = 1
+            self.intel = 1
+            (offset,) = struct.unpack("<I", header[4:8])
+            file.seek(offset,0)
+            (len,) = struct.unpack("<H", file.read(2))
+            app = file.read(len*12)
+            for i in range(len):
+                (tag, type, length, offset, value) = struct.unpack('<HHIHH', app[i*12:i*12+12])
+                _debug("[%i/%i] tag: 0x%.4x, type 0x%.4x, len %d, value %d, offset %d)" % (i,len,tag,type,length,value,offset))
+                if tag == 0x8649:
+                    file.seek(offset)
+                    iptc = IPTC.flatten(IPTC.parseiptc(file.read(1000)))
+                elif tag == 0x0100:
+                    if value != 0:
+                        self.width = value
+                    else:
+                        self.width = offset
+                elif tag == 0x0101:
+                    if value != 0:
+                        self.height = value
+                    else:
+                        self.height = offset
+        else:
+            ImageInfo.add(file.name, self)
+            return
+            
+        if iptc:
+            self.setitem( 'title', iptc, 517 ) 
+            self.setitem( 'date' , iptc, 567 )
+            self.setitem( 'comment', iptc, 617 )
+            self.setitem( 'keywords', iptc, 537 )
+            self.setitem( 'artist', iptc, 592 )
+            self.setitem( 'country', iptc, 612 ) 
+            self.setitem( 'caption', iptc, 632 )
+            self.appendtable('IPTC', iptc)
+
+        ImageInfo.add(file.name, self)
+        return
+            
+
+mmpython.registertype( 'image/tiff', ('tif','tiff'), mediainfo.TYPE_IMAGE, TIFFInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/EXIF.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/EXIF.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/EXIF.py	(revision 4)
@@ -0,0 +1,1194 @@
+# Library to extract EXIF information in digital camera image files
+#
+# To use this library call with:
+#    f=open(path_name, 'rb')
+#    tags=EXIF.process_file(f)
+# tags will now be a dictionary mapping names of EXIF tags to their
+# values in the file named by path_name.  You can process the tags
+# as you wish.  In particular, you can iterate through all the tags with:
+#     for tag in tags.keys():
+#         if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename',
+#                        'EXIF MakerNote'):
+#             print "Key: %s, value %s" % (tag, tags[tag])
+# (This code uses the if statement to avoid printing out a few of the
+# tags that tend to be long or boring.)
+#
+# The tags dictionary will include keys for all of the usual EXIF
+# tags, and will also include keys for Makernotes used by some
+# cameras, for which we have a good specification.
+#
+# Contains code from "exifdump.py" originally written by Thierry Bousch
+# <bousch@topo.math.u-psud.fr> and released into the public domain.
+#
+# Updated and turned into general-purpose library by Gene Cash
+# <email gcash at cfl.rr.com>
+#
+# This copyright license is intended to be similar to the FreeBSD license.
+#
+# Copyright 2002 Gene Cash All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    1. Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#    2. Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the
+#       distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GENE CASH ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# This means you may do anything you want with this code, except claim you
+# wrote it. Also, if it breaks you get to keep both pieces.
+#
+# Patch Contributors:
+# * Simon J. Gerraty <sjg@crufty.net>
+#   s2n fix & orientation decode
+# * John T. Riedl <riedl@cs.umn.edu>
+#   Added support for newer Nikon type 3 Makernote format for D70 and some
+#   other Nikon cameras.
+# * Joerg Schaefer <schaeferj@gmx.net>
+#   Fixed subtle bug when faking an EXIF header, which affected maker notes
+#   using relative offsets, and a fix for Nikon D100.
+#
+# 21-AUG-99 TB  Last update by Thierry Bousch to his code.
+# 17-JAN-02 CEC Discovered code on web.
+#               Commented everything.
+#               Made small code improvements.
+#               Reformatted for readability.
+# 19-JAN-02 CEC Added ability to read TIFFs and JFIF-format JPEGs.
+#               Added ability to extract JPEG formatted thumbnail.
+#               Added ability to read GPS IFD (not tested).
+#               Converted IFD data structure to dictionaries indexed by
+#               tag name.
+#               Factored into library returning dictionary of IFDs plus
+#               thumbnail, if any.
+# 20-JAN-02 CEC Added MakerNote processing logic.
+#               Added Olympus MakerNote.
+#               Converted data structure to single-level dictionary, avoiding
+#               tag name collisions by prefixing with IFD name.  This makes
+#               it much easier to use.
+# 23-JAN-02 CEC Trimmed nulls from end of string values.
+# 25-JAN-02 CEC Discovered JPEG thumbnail in Olympus TIFF MakerNote.
+# 26-JAN-02 CEC Added ability to extract TIFF thumbnails.
+#               Added Nikon, Fujifilm, Casio MakerNotes.
+# 30-NOV-03 CEC Fixed problem with canon_decode_tag() not creating an
+#               IFD_Tag() object.
+# 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
+#
+
+# field type descriptions as (length, abbreviation, full name) tuples
+FIELD_TYPES=(
+    (0, 'X',  'Proprietary'), # no such type
+    (1, 'B',  'Byte'),
+    (1, 'A',  'ASCII'),
+    (2, 'S',  'Short'),
+    (4, 'L',  'Long'),
+    (8, 'R',  'Ratio'),
+    (1, 'SB', 'Signed Byte'),
+    (1, 'U',  'Undefined'),
+    (2, 'SS', 'Signed Short'),
+    (4, 'SL', 'Signed Long'),
+    (8, 'SR', 'Signed Ratio')
+    )
+
+# dictionary of main EXIF tag names
+# first element of tuple is tag name, optional second element is
+# another dictionary giving names to values
+EXIF_TAGS={
+    0x0100: ('ImageWidth', ),
+    0x0101: ('ImageLength', ),
+    0x0102: ('BitsPerSample', ),
+    0x0103: ('Compression',
+             {1: 'Uncompressed TIFF',
+              6: 'JPEG Compressed'}),
+    0x0106: ('PhotometricInterpretation', ),
+    0x010A: ('FillOrder', ),
+    0x010D: ('DocumentName', ),
+    0x010E: ('ImageDescription', ),
+    0x010F: ('Make', ),
+    0x0110: ('Model', ),
+    0x0111: ('StripOffsets', ),
+    0x0112: ('Orientation',
+             {1: 'Horizontal (normal)',
+              2: 'Mirrored horizontal',
+              3: 'Rotated 180',
+              4: 'Mirrored vertical',
+              5: 'Mirrored horizontal then rotated 90 CCW',
+              6: 'Rotated 90 CW',
+              7: 'Mirrored horizontal then rotated 90 CW',
+              8: 'Rotated 90 CCW'}),
+    0x0115: ('SamplesPerPixel', ),
+    0x0116: ('RowsPerStrip', ),
+    0x0117: ('StripByteCounts', ),
+    0x011A: ('XResolution', ),
+    0x011B: ('YResolution', ),
+    0x011C: ('PlanarConfiguration', ),
+    0x0128: ('ResolutionUnit',
+             {1: 'Not Absolute',
+              2: 'Pixels/Inch',
+              3: 'Pixels/Centimeter'}),
+    0x012D: ('TransferFunction', ),
+    0x0131: ('Software', ),
+    0x0132: ('DateTime', ),
+    0x013B: ('Artist', ),
+    0x013E: ('WhitePoint', ),
+    0x013F: ('PrimaryChromaticities', ),
+    0x0156: ('TransferRange', ),
+    0x0200: ('JPEGProc', ),
+    0x0201: ('JPEGInterchangeFormat', ),
+    0x0202: ('JPEGInterchangeFormatLength', ),
+    0x0211: ('YCbCrCoefficients', ),
+    0x0212: ('YCbCrSubSampling', ),
+    0x0213: ('YCbCrPositioning', ),
+    0x0214: ('ReferenceBlackWhite', ),
+    0x828D: ('CFARepeatPatternDim', ),
+    0x828E: ('CFAPattern', ),
+    0x828F: ('BatteryLevel', ),
+    0x8298: ('Copyright', ),
+    0x829A: ('ExposureTime', ),
+    0x829D: ('FNumber', ),
+    0x83BB: ('IPTC/NAA', ),
+    0x8769: ('ExifOffset', ),
+    0x8773: ('InterColorProfile', ),
+    0x8822: ('ExposureProgram',
+             {0: 'Unidentified',
+              1: 'Manual',
+              2: 'Program Normal',
+              3: 'Aperture Priority',
+              4: 'Shutter Priority',
+              5: 'Program Creative',
+              6: 'Program Action',
+              7: 'Portrait Mode',
+              8: 'Landscape Mode'}),
+    0x8824: ('SpectralSensitivity', ),
+    0x8825: ('GPSInfo', ),
+    0x8827: ('ISOSpeedRatings', ),
+    0x8828: ('OECF', ),
+    # print as string
+    0x9000: ('ExifVersion', lambda x: ''.join(map(chr, x))),
+    0x9003: ('DateTimeOriginal', ),
+    0x9004: ('DateTimeDigitized', ),
+    0x9101: ('ComponentsConfiguration',
+             {0: '',
+              1: 'Y',
+              2: 'Cb',
+              3: 'Cr',
+              4: 'Red',
+              5: 'Green',
+              6: 'Blue'}),
+    0x9102: ('CompressedBitsPerPixel', ),
+    0x9201: ('ShutterSpeedValue', ),
+    0x9202: ('ApertureValue', ),
+    0x9203: ('BrightnessValue', ),
+    0x9204: ('ExposureBiasValue', ),
+    0x9205: ('MaxApertureValue', ),
+    0x9206: ('SubjectDistance', ),
+    0x9207: ('MeteringMode',
+             {0: 'Unidentified',
+              1: 'Average',
+              2: 'CenterWeightedAverage',
+              3: 'Spot',
+              4: 'MultiSpot'}),
+    0x9208: ('LightSource',
+             {0:   'Unknown',
+              1:   'Daylight',
+              2:   'Fluorescent',
+              3:   'Tungsten',
+              10:  'Flash',
+              17:  'Standard Light A',
+              18:  'Standard Light B',
+              19:  'Standard Light C',
+              20:  'D55',
+              21:  'D65',
+              22:  'D75',
+              255: 'Other'}),
+    0x9209: ('Flash', {0:  'No',
+                       1:  'Fired',
+                       5:  'Fired (?)', # no return sensed
+                       7:  'Fired (!)', # return sensed
+                       9:  'Fill Fired',
+                       13: 'Fill Fired (?)',
+                       15: 'Fill Fired (!)',
+                       16: 'Off',
+                       24: 'Auto Off',
+                       25: 'Auto Fired',
+                       29: 'Auto Fired (?)',
+                       31: 'Auto Fired (!)',
+                       32: 'Not Available'}),
+    0x920A: ('FocalLength', ),
+    0x927C: ('MakerNote', ),
+    # print as string
+    0x9286: ('UserComment', lambda x: ''.join(map(chr, x))),
+    0x9290: ('SubSecTime', ),
+    0x9291: ('SubSecTimeOriginal', ),
+    0x9292: ('SubSecTimeDigitized', ),
+    # print as string
+    0xA000: ('FlashPixVersion', lambda x: ''.join(map(chr, x))),
+    0xA001: ('ColorSpace', ),
+    0xA002: ('ExifImageWidth', ),
+    0xA003: ('ExifImageLength', ),
+    0xA005: ('InteroperabilityOffset', ),
+    0xA20B: ('FlashEnergy', ),               # 0x920B in TIFF/EP
+    0xA20C: ('SpatialFrequencyResponse', ),  # 0x920C    -  -
+    0xA20E: ('FocalPlaneXResolution', ),     # 0x920E    -  -
+    0xA20F: ('FocalPlaneYResolution', ),     # 0x920F    -  -
+    0xA210: ('FocalPlaneResolutionUnit', ),  # 0x9210    -  -
+    0xA214: ('SubjectLocation', ),           # 0x9214    -  -
+    0xA215: ('ExposureIndex', ),             # 0x9215    -  -
+    0xA217: ('SensingMethod', ),             # 0x9217    -  -
+    0xA300: ('FileSource',
+             {3: 'Digital Camera'}),
+    0xA301: ('SceneType',
+             {1: 'Directly Photographed'}),
+    0xA302: ('CVAPattern',),
+    }
+
+# interoperability tags
+INTR_TAGS={
+    0x0001: ('InteroperabilityIndex', ),
+    0x0002: ('InteroperabilityVersion', ),
+    0x1000: ('RelatedImageFileFormat', ),
+    0x1001: ('RelatedImageWidth', ),
+    0x1002: ('RelatedImageLength', ),
+    }
+
+# GPS tags (not used yet, haven't seen camera with GPS)
+GPS_TAGS={
+    0x0000: ('GPSVersionID', ),
+    0x0001: ('GPSLatitudeRef', ),
+    0x0002: ('GPSLatitude', ),
+    0x0003: ('GPSLongitudeRef', ),
+    0x0004: ('GPSLongitude', ),
+    0x0005: ('GPSAltitudeRef', ),
+    0x0006: ('GPSAltitude', ),
+    0x0007: ('GPSTimeStamp', ),
+    0x0008: ('GPSSatellites', ),
+    0x0009: ('GPSStatus', ),
+    0x000A: ('GPSMeasureMode', ),
+    0x000B: ('GPSDOP', ),
+    0x000C: ('GPSSpeedRef', ),
+    0x000D: ('GPSSpeed', ),
+    0x000E: ('GPSTrackRef', ),
+    0x000F: ('GPSTrack', ),
+    0x0010: ('GPSImgDirectionRef', ),
+    0x0011: ('GPSImgDirection', ),
+    0x0012: ('GPSMapDatum', ),
+    0x0013: ('GPSDestLatitudeRef', ),
+    0x0014: ('GPSDestLatitude', ),
+    0x0015: ('GPSDestLongitudeRef', ),
+    0x0016: ('GPSDestLongitude', ),
+    0x0017: ('GPSDestBearingRef', ),
+    0x0018: ('GPSDestBearing', ),
+    0x0019: ('GPSDestDistanceRef', ),
+    0x001A: ('GPSDestDistance', )
+    }
+
+# Nikon E99x MakerNote Tags
+# http://members.tripod.com/~tawba/990exif.htm
+MAKERNOTE_NIKON_NEWER_TAGS={
+    0x0002: ('ISOSetting', ),
+    0x0003: ('ColorMode', ),
+    0x0004: ('Quality', ),
+    0x0005: ('Whitebalance', ),
+    0x0006: ('ImageSharpening', ),
+    0x0007: ('FocusMode', ),
+    0x0008: ('FlashSetting', ),
+    0x0009: ('AutoFlashMode', ),
+    0x000B: ('WhiteBalanceBias', ),
+    0x000C: ('WhiteBalanceRBCoeff', ),
+    0x000F: ('ISOSelection', ),
+    0x0012: ('FlashCompensation', ),
+    0x0013: ('ISOSpeedRequested', ),
+    0x0016: ('PhotoCornerCoordinates', ),
+    0x0018: ('FlashBracketCompensationApplied', ),
+    0x0019: ('AEBracketCompensationApplied', ),
+    0x0080: ('ImageAdjustment', ),
+    0x0081: ('ToneCompensation', ),
+    0x0082: ('AuxiliaryLens', ),
+    0x0083: ('LensType', ),
+    0x0084: ('LensMinMaxFocalMaxAperture', ),
+    0x0085: ('ManualFocusDistance', ),
+    0x0086: ('DigitalZoomFactor', ),
+    0x0088: ('AFFocusPosition',
+             {0x0000: 'Center',
+              0x0100: 'Top',
+              0x0200: 'Bottom',
+              0x0300: 'Left',
+              0x0400: 'Right'}),
+    0x0089: ('BracketingMode',
+             {0x00: 'Single frame, no bracketing',
+              0x01: 'Continuous, no bracketing',
+              0x02: 'Timer, no bracketing',
+              0x10: 'Single frame, exposure bracketing',
+              0x11: 'Continuous, exposure bracketing',
+              0x12: 'Timer, exposure bracketing',
+              0x40: 'Single frame, white balance bracketing',
+              0x41: 'Continuous, white balance bracketing',
+              0x42: 'Timer, white balance bracketing'}),
+    0x008D: ('ColorMode', ),
+    0x008F: ('SceneMode?', ),
+    0x0090: ('LightingType', ),
+    0x0092: ('HueAdjustment', ),
+    0x0094: ('Saturation',
+             {-3: 'B&W',
+              -2: '-2',
+              -1: '-1',
+              0:  '0',
+              1:  '1',
+              2:  '2'}),
+    0x0095: ('NoiseReduction', ),
+    0x00A7: ('TotalShutterReleases', ),
+    0x00A9: ('ImageOptimization', ),
+    0x00AA: ('Saturation', ),
+    0x00AB: ('DigitalVariProgram', ),
+    0x0010: ('DataDump', )
+    }
+
+MAKERNOTE_NIKON_OLDER_TAGS={
+    0x0003: ('Quality',
+             {1: 'VGA Basic',
+              2: 'VGA Normal',
+              3: 'VGA Fine',
+              4: 'SXGA Basic',
+              5: 'SXGA Normal',
+              6: 'SXGA Fine'}),
+    0x0004: ('ColorMode',
+             {1: 'Color',
+              2: 'Monochrome'}),
+    0x0005: ('ImageAdjustment',
+             {0: 'Normal',
+              1: 'Bright+',
+              2: 'Bright-',
+              3: 'Contrast+',
+              4: 'Contrast-'}),
+    0x0006: ('CCDSpeed',
+             {0: 'ISO 80',
+              2: 'ISO 160',
+              4: 'ISO 320',
+              5: 'ISO 100'}),
+    0x0007: ('WhiteBalance',
+             {0: 'Auto',
+              1: 'Preset',
+              2: 'Daylight',
+              3: 'Incandescent',
+              4: 'Fluorescent',
+              5: 'Cloudy',
+              6: 'Speed Light'})
+    }
+
+# decode Olympus SpecialMode tag in MakerNote
+def olympus_special_mode(v):
+    a={
+        0: 'Normal',
+        1: 'Unknown',
+        2: 'Fast',
+        3: 'Panorama'}
+    b={
+        0: 'Non-panoramic',
+        1: 'Left to right',
+        2: 'Right to left',
+        3: 'Bottom to top',
+        4: 'Top to bottom'}
+    return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
+        
+MAKERNOTE_OLYMPUS_TAGS={
+    # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
+    # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
+    0x0100: ('JPEGThumbnail', ),
+    0x0200: ('SpecialMode', olympus_special_mode),
+    0x0201: ('JPEGQual',
+             {1: 'SQ',
+              2: 'HQ',
+              3: 'SHQ'}),
+    0x0202: ('Macro',
+             {0: 'Normal',
+              1: 'Macro'}),
+    0x0204: ('DigitalZoom', ),
+    0x0207: ('SoftwareRelease',  ),
+    0x0208: ('PictureInfo',  ),
+    # print as string
+    0x0209: ('CameraID', lambda x: ''.join(map(chr, x))),
+    0x0F00: ('DataDump',  )
+    }
+
+MAKERNOTE_CASIO_TAGS={
+    0x0001: ('RecordingMode',
+             {1: 'Single Shutter',
+              2: 'Panorama',
+              3: 'Night Scene',
+              4: 'Portrait',
+              5: 'Landscape'}),
+    0x0002: ('Quality',
+             {1: 'Economy',
+              2: 'Normal',
+              3: 'Fine'}),
+    0x0003: ('FocusingMode',
+             {2: 'Macro',
+              3: 'Auto Focus',
+              4: 'Manual Focus',
+              5: 'Infinity'}),
+    0x0004: ('FlashMode',
+             {1: 'Auto',
+              2: 'On',
+              3: 'Off',
+              4: 'Red Eye Reduction'}),
+    0x0005: ('FlashIntensity',
+             {11: 'Weak',
+              13: 'Normal',
+              15: 'Strong'}),
+    0x0006: ('Object Distance', ),
+    0x0007: ('WhiteBalance',
+             {1:   'Auto',
+              2:   'Tungsten',
+              3:   'Daylight',
+              4:   'Fluorescent',
+              5:   'Shade',
+              129: 'Manual'}),
+    0x000B: ('Sharpness',
+             {0: 'Normal',
+              1: 'Soft',
+              2: 'Hard'}),
+    0x000C: ('Contrast',
+             {0: 'Normal',
+              1: 'Low',
+              2: 'High'}),
+    0x000D: ('Saturation',
+             {0: 'Normal',
+              1: 'Low',
+              2: 'High'}),
+    0x0014: ('CCDSpeed',
+             {64:  'Normal',
+              80:  'Normal',
+              100: 'High',
+              125: '+1.0',
+              244: '+3.0',
+              250: '+2.0',})
+    }
+
+MAKERNOTE_FUJIFILM_TAGS={
+    0x0000: ('NoteVersion', lambda x: ''.join(map(chr, x))),
+    0x1000: ('Quality', ),
+    0x1001: ('Sharpness',
+             {1: 'Soft',
+              2: 'Soft',
+              3: 'Normal',
+              4: 'Hard',
+              5: 'Hard'}),
+    0x1002: ('WhiteBalance',
+             {0:    'Auto',
+              256:  'Daylight',
+              512:  'Cloudy',
+              768:  'DaylightColor-Fluorescent',
+              769:  'DaywhiteColor-Fluorescent',
+              770:  'White-Fluorescent',
+              1024: 'Incandescent',
+              3840: 'Custom'}),
+    0x1003: ('Color',
+             {0:   'Normal',
+              256: 'High',
+              512: 'Low'}),
+    0x1004: ('Tone',
+             {0:   'Normal',
+              256: 'High',
+              512: 'Low'}),
+    0x1010: ('FlashMode',
+             {0: 'Auto',
+              1: 'On',
+              2: 'Off',
+              3: 'Red Eye Reduction'}),
+    0x1011: ('FlashStrength', ),
+    0x1020: ('Macro',
+             {0: 'Off',
+              1: 'On'}),
+    0x1021: ('FocusMode',
+             {0: 'Auto',
+              1: 'Manual'}),
+    0x1030: ('SlowSync',
+             {0: 'Off',
+              1: 'On'}),
+    0x1031: ('PictureMode',
+             {0:   'Auto',
+              1:   'Portrait',
+              2:   'Landscape',
+              4:   'Sports',
+              5:   'Night',
+              6:   'Program AE',
+              256: 'Aperture Priority AE',
+              512: 'Shutter Priority AE',
+              768: 'Manual Exposure'}),
+    0x1100: ('MotorOrBracket',
+             {0: 'Off',
+              1: 'On'}),
+    0x1300: ('BlurWarning',
+             {0: 'Off',
+              1: 'On'}),
+    0x1301: ('FocusWarning',
+             {0: 'Off',
+              1: 'On'}),
+    0x1302: ('AEWarning',
+             {0: 'Off',
+              1: 'On'})
+    }
+
+MAKERNOTE_CANON_TAGS={
+    0x0006: ('ImageType', ),
+    0x0007: ('FirmwareVersion', ),
+    0x0008: ('ImageNumber', ),
+    0x0009: ('OwnerName', )
+    }
+
+# see http://www.burren.cx/david/canon.html by David Burren
+# this is in element offset, name, optional value dictionary format
+MAKERNOTE_CANON_TAG_0x001={
+    1: ('Macromode',
+        {1: 'Macro',
+         2: 'Normal'}),
+    2: ('SelfTimer', ),
+    3: ('Quality',
+        {2: 'Normal',
+         3: 'Fine',
+         5: 'Superfine'}),
+    4: ('FlashMode',
+        {0: 'Flash Not Fired',
+         1: 'Auto',
+         2: 'On',
+         3: 'Red-Eye Reduction',
+         4: 'Slow Synchro',
+         5: 'Auto + Red-Eye Reduction',
+         6: 'On + Red-Eye Reduction',
+         16: 'external flash'}),
+    5: ('ContinuousDriveMode',
+        {0: 'Single Or Timer',
+         1: 'Continuous'}),
+    7: ('FocusMode',
+        {0: 'One-Shot',
+         1: 'AI Servo',
+         2: 'AI Focus',
+         3: 'MF',
+         4: 'Single',
+         5: 'Continuous',
+         6: 'MF'}),
+    10: ('ImageSize',
+         {0: 'Large',
+          1: 'Medium',
+          2: 'Small'}),
+    11: ('EasyShootingMode',
+         {0: 'Full Auto',
+          1: 'Manual',
+          2: 'Landscape',
+          3: 'Fast Shutter',
+          4: 'Slow Shutter',
+          5: 'Night',
+          6: 'B&W',
+          7: 'Sepia',
+          8: 'Portrait',
+          9: 'Sports',
+          10: 'Macro/Close-Up',
+          11: 'Pan Focus'}),
+    12: ('DigitalZoom',
+         {0: 'None',
+          1: '2x',
+          2: '4x'}),
+    13: ('Contrast',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    14: ('Saturation',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    15: ('Sharpness',
+         {0xFFFF: 'Low',
+          0: 'Normal',
+          1: 'High'}),
+    16: ('ISO',
+         {0: 'See ISOSpeedRatings Tag',
+          15: 'Auto',
+          16: '50',
+          17: '100',
+          18: '200',
+          19: '400'}),
+    17: ('MeteringMode',
+         {3: 'Evaluative',
+          4: 'Partial',
+          5: 'Center-weighted'}),
+    18: ('FocusType',
+         {0: 'Manual',
+          1: 'Auto',
+          3: 'Close-Up (Macro)',
+          8: 'Locked (Pan Mode)'}),
+    19: ('AFPointSelected',
+         {0x3000: 'None (MF)',
+          0x3001: 'Auto-Selected',
+          0x3002: 'Right',
+          0x3003: 'Center',
+          0x3004: 'Left'}),
+    20: ('ExposureMode',
+         {0: 'Easy Shooting',
+          1: 'Program',
+          2: 'Tv-priority',
+          3: 'Av-priority',
+          4: 'Manual',
+          5: 'A-DEP'}),
+    23: ('LongFocalLengthOfLensInFocalUnits', ),
+    24: ('ShortFocalLengthOfLensInFocalUnits', ),
+    25: ('FocalUnitsPerMM', ),
+    28: ('FlashActivity',
+         {0: 'Did Not Fire',
+          1: 'Fired'}),
+    29: ('FlashDetails',
+         {14: 'External E-TTL',
+          13: 'Internal Flash',
+          11: 'FP Sync Used',
+          7: '2nd("Rear")-Curtain Sync Used',
+          4: 'FP Sync Enabled'}),
+    32: ('FocusMode',
+         {0: 'Single',
+          1: 'Continuous'})
+    }
+
+MAKERNOTE_CANON_TAG_0x004={
+    7: ('WhiteBalance',
+        {0: 'Auto',
+         1: 'Sunny',
+         2: 'Cloudy',
+         3: 'Tungsten',
+         4: 'Fluorescent',
+         5: 'Flash',
+         6: 'Custom'}),
+    9: ('SequenceNumber', ),
+    14: ('AFPointUsed', ),
+    15: ('FlashBias',
+        {0XFFC0: '-2 EV',
+         0XFFCC: '-1.67 EV',
+         0XFFD0: '-1.50 EV',
+         0XFFD4: '-1.33 EV',
+         0XFFE0: '-1 EV',
+         0XFFEC: '-0.67 EV',
+         0XFFF0: '-0.50 EV',
+         0XFFF4: '-0.33 EV',
+         0X0000: '0 EV',
+         0X000C: '0.33 EV',
+         0X0010: '0.50 EV',
+         0X0014: '0.67 EV',
+         0X0020: '1 EV',
+         0X002C: '1.33 EV',
+         0X0030: '1.50 EV',
+         0X0034: '1.67 EV',
+         0X0040: '2 EV'}),
+    19: ('SubjectDistance', )
+    }
+
+# extract multibyte integer in Motorola format (little endian)
+def s2n_motorola(str):
+    x=0
+    for c in str:
+        x=(x << 8) | ord(c)
+    return x
+
+# extract multibyte integer in Intel format (big endian)
+def s2n_intel(str):
+    x=0
+    y=0L
+    for c in str:
+        x=x | (ord(c) << y)
+        y=y+8
+    return x
+
+# ratio object that eventually will be able to reduce itself to lowest
+# common denominator for printing
+def gcd(a, b):
+   if b == 0:
+      return a
+   else:
+      return gcd(b, a % b)
+
+class Ratio:
+    def __init__(self, num, den):
+        self.num=num
+        self.den=den
+
+    def __repr__(self):
+        self.reduce()
+        if self.den == 1:
+            return str(self.num)
+        return '%d/%d' % (self.num, self.den)
+
+    def reduce(self):
+        div=gcd(self.num, self.den)
+        if div > 1:
+            self.num=self.num/div
+            self.den=self.den/div
+
+# for ease of dealing with tags
+class IFD_Tag:
+    def __init__(self, printable, tag, field_type, values, field_offset,
+                 field_length):
+        # printable version of data
+        self.printable=printable
+        # tag ID number
+        self.tag=tag
+        # field type as index into FIELD_TYPES
+        self.field_type=field_type
+        # offset of start of field in bytes from beginning of IFD
+        self.field_offset=field_offset
+        # length of data field in bytes
+        self.field_length=field_length
+        # either a string or array of data items
+        self.values=values
+        
+    def __str__(self):
+        return self.printable
+    
+    def __repr__(self):
+        return '(0x%04X) %s=%s @ %d' % (self.tag,
+                                        FIELD_TYPES[self.field_type][2],
+                                        self.printable,
+                                        self.field_offset)
+
+# class that handles an EXIF header
+class EXIF_header:
+    def __init__(self, file, endian, offset, fake_exif, debug=0):
+        self.file=file
+        self.endian=endian
+        self.offset=offset
+        self.fake_exif=fake_exif
+        self.debug=debug
+        self.tags={}
+        
+    # convert slice to integer, based on sign and endian flags
+    # usually this offset is assumed to be relative to the beginning of the
+    # start of the EXIF information.  For some cameras that use relative tags,
+    # this offset may be relative to some other starting point.
+    def s2n(self, offset, length, signed=0):
+        self.file.seek(self.offset+offset)
+        slice=self.file.read(length)
+        if self.endian == 'I':
+            val=s2n_intel(slice)
+        else:
+            val=s2n_motorola(slice)
+        # Sign extension ?
+        if signed:
+            msb=1L << (8*length-1)
+            if val & msb:
+                val=val-(msb << 1)
+        return val
+
+    # convert offset to string
+    def n2s(self, offset, length):
+        s=''
+        for i in range(length):
+            if self.endian == 'I':
+                s=s+chr(offset & 0xFF)
+            else:
+                s=chr(offset & 0xFF)+s
+            offset=offset >> 8
+        return s
+    
+    # return first IFD
+    def first_IFD(self):
+        return self.s2n(4, 4)
+
+    # return pointer to next IFD
+    def next_IFD(self, ifd):
+        entries=self.s2n(ifd, 2)
+        return self.s2n(ifd+2+12*entries, 4)
+
+    # return list of IFDs in header
+    def list_IFDs(self):
+        i=self.first_IFD()
+        a=[]
+        while i:
+            a.append(i)
+            i=self.next_IFD(i)
+        return a
+
+    # return list of entries in this IFD
+    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0):
+        entries=self.s2n(ifd, 2)
+        for i in range(entries):
+            # entry is index of start of this IFD in the file
+            entry=ifd+2+12*i
+            tag=self.s2n(entry, 2)
+            # get tag name.  We do it early to make debugging easier
+            tag_entry=dict.get(tag)
+            if tag_entry:
+                tag_name=tag_entry[0]
+            else:
+                tag_name='Tag 0x%04X' % tag
+            field_type=self.s2n(entry+2, 2)
+            if not 0 < field_type < len(FIELD_TYPES):
+                # unknown field type
+                raise ValueError, \
+                      'unknown type %d in tag 0x%04X' % (field_type, tag)
+            typelen=FIELD_TYPES[field_type][0]
+            count=self.s2n(entry+4, 4)
+            offset=entry+8
+            if count*typelen > 4:
+                # offset is not the value; it's a pointer to the value
+                # if relative we set things up so s2n will seek to the right
+                # place when it adds self.offset.  Note that this 'relative'
+                # is for the Nikon type 3 makernote.  Other cameras may use
+                # other relative offsets, which would have to be computed here
+                # slightly differently.
+                if relative:
+                    tmp_offset=self.s2n(offset, 4)
+                    offset=tmp_offset+ifd-self.offset+4
+                    if self.fake_exif:
+                        offset=offset+18
+                else:
+                    offset=self.s2n(offset, 4)
+            field_offset=offset
+            if field_type == 2:
+                # special case: null-terminated ASCII string
+                if count != 0:
+                    self.file.seek(self.offset+offset)
+                    values=self.file.read(count)
+                    values=values.strip().replace('\x00','')
+                else:
+                    values=''
+            else:
+                values=[]
+                signed=(field_type in [6, 8, 9, 10])
+                for j in range(count):
+                    if field_type in (5, 10):
+                        # a ratio
+                        value_j=Ratio(self.s2n(offset,   4, signed),
+                                      self.s2n(offset+4, 4, signed))
+                    else:
+                        value_j=self.s2n(offset, typelen, signed)
+                    values.append(value_j)
+                    offset=offset+typelen
+            # now "values" is either a string or an array
+            if count == 1 and field_type != 2:
+                printable=str(values[0])
+            else:
+                printable=str(values)
+            # compute printable version of values
+            if tag_entry:
+                if len(tag_entry) != 1:
+                    # optional 2nd tag element is present
+                    if callable(tag_entry[1]):
+                        # call mapping function
+                        printable=tag_entry[1](values)
+                    else:
+                        printable=''
+                        for i in values:
+                            # use lookup table for this tag
+                            printable+=tag_entry[1].get(i, repr(i))
+            self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
+                                                     field_type,
+                                                     values, field_offset,
+                                                     count*typelen)
+            if self.debug:
+                print ' debug:   %s: %s' % (tag_name,
+                                            repr(self.tags[ifd_name+' '+tag_name]))
+
+    # extract uncompressed TIFF thumbnail (like pulling teeth)
+    # we take advantage of the pre-existing layout in the thumbnail IFD as
+    # much as possible
+    def extract_TIFF_thumbnail(self, thumb_ifd):
+        entries=self.s2n(thumb_ifd, 2)
+        # this is header plus offset to IFD ...
+        if self.endian == 'M':
+            tiff='MM\x00*\x00\x00\x00\x08'
+        else:
+            tiff='II*\x00\x08\x00\x00\x00'
+        # ... plus thumbnail IFD data plus a null "next IFD" pointer
+        self.file.seek(self.offset+thumb_ifd)
+        tiff+=self.file.read(entries*12+2)+'\x00\x00\x00\x00'
+        
+        # fix up large value offset pointers into data area
+        for i in range(entries):
+            entry=thumb_ifd+2+12*i
+            tag=self.s2n(entry, 2)
+            field_type=self.s2n(entry+2, 2)
+            typelen=FIELD_TYPES[field_type][0]
+            count=self.s2n(entry+4, 4)
+            oldoff=self.s2n(entry+8, 4)
+            # start of the 4-byte pointer area in entry
+            ptr=i*12+18
+            # remember strip offsets location
+            if tag == 0x0111:
+                strip_off=ptr
+                strip_len=count*typelen
+            # is it in the data area?
+            if count*typelen > 4:
+                # update offset pointer (nasty "strings are immutable" crap)
+                # should be able to say "tiff[ptr:ptr+4]=newoff"
+                newoff=len(tiff)
+                tiff=tiff[:ptr]+self.n2s(newoff, 4)+tiff[ptr+4:]
+                # remember strip offsets location
+                if tag == 0x0111:
+                    strip_off=newoff
+                    strip_len=4
+                # get original data and store it
+                self.file.seek(self.offset+oldoff)
+                tiff+=self.file.read(count*typelen)
+                
+        # add pixel strips and update strip offset info
+        old_offsets=self.tags['Thumbnail StripOffsets'].values
+        old_counts=self.tags['Thumbnail StripByteCounts'].values
+        for i in range(len(old_offsets)):
+            # update offset pointer (more nasty "strings are immutable" crap)
+            offset=self.n2s(len(tiff), strip_len)
+            tiff=tiff[:strip_off]+offset+tiff[strip_off+strip_len:]
+            strip_off+=strip_len
+            # add pixel strip to end
+            self.file.seek(self.offset+old_offsets[i])
+            tiff+=self.file.read(old_counts[i])
+            
+        self.tags['TIFFThumbnail']=tiff
+        
+    # decode all the camera-specific MakerNote formats
+
+    # Note is the data that comprises this MakerNote.  The MakerNote will
+    # likely have pointers in it that point to other parts of the file.  We'll
+    # use self.offset as the starting point for most of those pointers, since
+    # they are relative to the beginning of the file.
+    #
+    # If the MakerNote is in a newer format, it may use relative addressing
+    # within the MakerNote.  In that case we'll use relative addresses for the
+    # pointers.
+    #
+    # As an aside: it's not just to be annoying that the manufacturers use
+    # relative offsets.  It's so that if the makernote has to be moved by the
+    # picture software all of the offsets don't have to be adjusted.  Overall,
+    # this is probably the right strategy for makernotes, though the spec is
+    # ambiguous.  (The spec does not appear to imagine that makernotes would
+    # follow EXIF format internally.  Once they did, it's ambiguous whether
+    # the offsets should be from the header at the start of all the EXIF info,
+    # or from the header at the start of the makernote.)
+    def decode_maker_note(self):
+        note=self.tags['EXIF MakerNote']
+        make=self.tags['Image Make'].printable
+        model=self.tags['Image Model'].printable
+
+        # Nikon
+        # The maker note usually starts with the word Nikon, followed by the
+        # type of the makernote (1 or 2, as a short).  If the word Nikon is
+        # not at the start of the makernote, it's probably type 2, since some
+        # cameras work that way.
+        if make in ('NIKON', 'NIKON CORPORATION'):
+            if note.values[0:7] == [78, 105, 107, 111, 110, 00, 01]:
+                if self.debug:
+                    print "Looks like a type 1 Nikon MakerNote."
+                self.dump_IFD(note.field_offset+8, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_OLDER_TAGS)
+            elif note.values[0:7] == [78, 105, 107, 111, 110, 00, 02]:
+                if self.debug:
+                    print "Looks like a labeled type 2 Nikon MakerNote"
+                if note.values[12:14] != [0, 42] and note.values[12:14] != [42L, 0L]:
+                    raise ValueError, "Missing marker tag '42' in MakerNote."
+                # skip the Makernote label and the TIFF header
+                self.dump_IFD(note.field_offset+10+8, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_NEWER_TAGS, relative=1)
+            else:
+                # E99x or D1
+                if self.debug:
+                    print "Looks like an unlabeled type 2 Nikon MakerNote"
+                self.dump_IFD(note.field_offset, 'MakerNote',
+                              dict=MAKERNOTE_NIKON_NEWER_TAGS)
+            return
+
+        # Olympus
+        if make[:7] == 'OLYMPUS':
+            self.dump_IFD(note.field_offset+8, 'MakerNote',
+                          dict=MAKERNOTE_OLYMPUS_TAGS)
+            return
+
+        # Casio
+        if make == 'Casio':
+            self.dump_IFD(note.field_offset, 'MakerNote',
+                          dict=MAKERNOTE_CASIO_TAGS)
+            return
+        
+        # Fujifilm
+        if make == 'FUJIFILM':
+            # bug: everything else is "Motorola" endian, but the MakerNote
+            # is "Intel" endian
+            endian=self.endian
+            self.endian='I'
+            # bug: IFD offsets are from beginning of MakerNote, not
+            # beginning of file header
+            offset=self.offset
+            self.offset+=note.field_offset
+            # process note with bogus values (note is actually at offset 12)
+            self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS)
+            # reset to correct values
+            self.endian=endian
+            self.offset=offset
+            return
+        
+        # Canon
+        if make == 'Canon':
+            self.dump_IFD(note.field_offset, 'MakerNote',
+                          dict=MAKERNOTE_CANON_TAGS)
+            for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001),
+                      ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
+                self.canon_decode_tag(self.tags[i[0]].values, i[1])
+            return
+
+    # decode Canon MakerNote tag based on offset within tag
+    # see http://www.burren.cx/david/canon.html by David Burren
+    def canon_decode_tag(self, value, dict):
+        for i in range(1, len(value)):
+            x=dict.get(i, ('Unknown', ))
+            if self.debug:
+                print i, x
+            name=x[0]
+            if len(x) > 1:
+                val=x[1].get(value[i], 'Unknown')
+            else:
+                val=value[i]
+            # it's not a real IFD Tag but we fake one to make everybody
+            # happy. this will have a "proprietary" type
+            self.tags['MakerNote '+name]=IFD_Tag(str(val), None, 0, None,
+                                                 None, None)
+
+# process an image file (expects an open file object)
+# this is the function that has to deal with all the arbitrary nasty bits
+# of the EXIF standard
+def process_file(file, debug=0):
+    # determine whether it's a JPEG or TIFF
+    data=file.read(12)
+    if data[0:4] in ['II*\x00', 'MM\x00*']:
+        # it's a TIFF file
+        file.seek(0)
+        endian=file.read(1)
+        file.read(1)
+        offset=0
+    elif data[0:2] == '\xFF\xD8':
+        # it's a JPEG file
+        # skip JFIF style header(s)
+        fake_exif=0
+        while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM'):
+            length=ord(data[4])*256+ord(data[5])
+            file.read(length-8)
+            # fake an EXIF beginning of file
+            data='\xFF\x00'+file.read(10)
+            fake_exif=1
+        if data[2] == '\xFF' and data[6:10] == 'Exif':
+            # detected EXIF header
+            offset=file.tell()
+            endian=file.read(1)
+        else:
+            # no EXIF information
+            return {}
+    else:
+        # file format not recognized
+        return {}
+
+    # deal with the EXIF info we found
+    if debug:
+        print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format'
+    hdr=EXIF_header(file, endian, offset, fake_exif, debug)
+    ifd_list=hdr.list_IFDs()
+    ctr=0
+    for i in ifd_list:
+        if ctr == 0:
+            IFD_name='Image'
+        elif ctr == 1:
+            IFD_name='Thumbnail'
+            thumb_ifd=i
+        else:
+            IFD_name='IFD %d' % ctr
+        if debug:
+            print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
+        hdr.dump_IFD(i, IFD_name)
+        # EXIF IFD
+        exif_off=hdr.tags.get(IFD_name+' ExifOffset')
+        if exif_off:
+            if debug:
+                print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
+            hdr.dump_IFD(exif_off.values[0], 'EXIF')
+            # Interoperability IFD contained in EXIF IFD
+            intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
+            if intr_off:
+                if debug:
+                    print ' EXIF Interoperability SubSubIFD at offset %d:' \
+                          % intr_off.values[0]
+                hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
+                             dict=INTR_TAGS)
+        # GPS IFD
+        gps_off=hdr.tags.get(IFD_name+' GPSInfo')
+        if gps_off:
+            if debug:
+                print ' GPS SubIFD at offset %d:' % gps_off.values[0]
+            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
+        ctr+=1
+
+    # extract uncompressed TIFF thumbnail
+    thumb=hdr.tags.get('Thumbnail Compression')
+    if thumb and thumb.printable == 'Uncompressed TIFF':
+        hdr.extract_TIFF_thumbnail(thumb_ifd)
+        
+    # JPEG thumbnail (thankfully the JPEG data is stored as a unit)
+    thumb_off=hdr.tags.get('Thumbnail JPEGInterchangeFormat')
+    if thumb_off:
+        file.seek(offset+thumb_off.values[0])
+        size=hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
+        hdr.tags['JPEGThumbnail']=file.read(size)
+        
+    # deal with MakerNote contained in EXIF IFD
+    if hdr.tags.has_key('EXIF MakerNote'):
+        hdr.decode_maker_note()
+
+    # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote
+    # since it's not allowed in a uncompressed TIFF IFD
+    if not hdr.tags.has_key('JPEGThumbnail'):
+        thumb_off=hdr.tags.get('MakerNote JPEGThumbnail')
+        if thumb_off:
+            file.seek(offset+thumb_off.values[0])
+            hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length)
+            
+    return hdr.tags
+
+# library test/debug function (dump given files)
+if __name__ == '__main__':
+    import sys
+    
+    if len(sys.argv) < 2:
+        print 'Usage: %s files...\n' % sys.argv[0]
+        sys.exit(0)
+        
+    for filename in sys.argv[1:]:
+        try:
+            file=open(filename, 'rb')
+        except:
+            print filename, 'unreadable'
+            print
+            continue
+        print filename+':'
+        # data=process_file(file, 1) # with debug info
+        data=process_file(file)
+        if not data:
+            print 'No EXIF information found'
+            continue
+
+        x=data.keys()
+        x.sort()
+        for i in x:
+            if i in ('JPEGThumbnail', 'TIFFThumbnail'):
+                continue
+            try:
+                print '   %s (%s): %s' % \
+                      (i, FIELD_TYPES[data[i].field_type][2], data[i].printable)
+            except:
+                print 'error', i, '"', data[i], '"'
+        if data.has_key('JPEGThumbnail'):
+            print 'File has JPEG thumbnail'
+        print
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/bins.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/bins.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/bins.py	(revision 4)
@@ -0,0 +1,151 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# bins.py - Python interface to bins data files.
+# -----------------------------------------------------------------------
+# $Id: bins.py,v 1.2 2004/05/04 22:02:59 dischi Exp $
+#
+# -----------------------------------------------------------------------
+# $Log: bins.py,v $
+# Revision 1.2  2004/05/04 22:02:59  dischi
+# fix crash with empty exif tag
+#
+# Revision 1.1  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+#
+# -----------------------------------------------------------------------
+# This file Copyright (C) 2002 John Cooper
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from xml.sax import make_parser, ContentHandler
+from xml.sax.handler import feature_namespaces
+import string
+import os
+import re
+
+
+def normalize_whitespace(text):
+    # Remove Redundant whitespace from a string
+    return ' '.join(text.split())
+
+RE_TEXT = re.compile("^[ \n\t]*(.*[^ \n\t])[ \n\t]*$").match
+
+# remove redundant whitespaces/tabs/newlines at the beginning and the end
+def normalize_text(text):
+    m = RE_TEXT(text)
+    if m:
+        return m.group(1)
+    return text
+
+
+def format_text(text):
+    while len(text) and text[0] in (' ', '\t', '\n'):
+        text = text[1:]
+    text = re.sub('\n[\t *]', ' ', text)
+    while len(text) and text[-1] in (' ', '\t', '\n'):
+        text = text[:-1]
+    return text
+
+
+class BinsDiscription(ContentHandler):
+    """
+    This is a handler for getting the information from a bins Album.
+    """
+    def __init__(self):
+        self.desc = {}
+	self.exif = {}
+        self.inDisc = 0
+        self.inField = 0
+	self.inExif = 0
+	self.inTag = 0
+
+    def startElement(self,name,attrs):
+        # Check that we  have a discription section
+        if name == u'description':
+            self.inDisc = 1
+        if name == u'field':
+            self.thisField = normalize_whitespace(attrs.get('name', ''))
+            self.inField = 1
+            self.desc[self.thisField] = ''
+	if name == u'exif':
+	    self.inExif = 1
+	if name == u'tag':
+	    self.inTag = 1
+	    self.thisTag = normalize_whitespace(attrs.get('name', ''))
+	    self.exif[self.thisTag] = ''
+
+
+    def characters(self,ch):
+        if self.inDisc:
+            if self.inField:
+                self.desc[self.thisField] = self.desc[self.thisField] + ch
+        if self.inExif:
+	    if self.inTag:
+	        self.exif[self.thisTag] = self.exif[self.thisTag] + ch
+
+ 
+    def endElement(self,name):
+        if name == 'discription':
+            self.inDisc = 0
+        if name == 'field':
+            self.desc[self.thisField] = normalize_text(self.desc[self.thisField])
+            self.inField = 0
+	if name == 'exif':
+            try:
+                self.exif[self.thisTag] = normalize_text(self.exif[self.thisTag])
+            except:
+                pass
+            self.inExif = 0
+                
+	if name == 'tag':
+	    self.inTag = 0
+
+def get_bins_desc(binsname):
+     parser = make_parser()
+     parser.setFeature(feature_namespaces,0)
+     dh = BinsDiscription()
+     parser.setContentHandler(dh)
+     # check that the xml file exists for a dir or image
+     if os.path.isfile(binsname + '/album.xml'):
+         binsname = binsname + '/album.xml'
+     elif os.path.isfile(binsname + '.xml'):
+         binsname = binsname + '.xml'
+     else:
+         dh.desc['title'] == os.path.basename(dirname)
+
+     # Check that there is a title
+     parser.parse(binsname)
+
+     # remove whitespace at the beginning
+     for d in dh.desc:
+         dh.desc[d] = format_text(dh.desc[d])
+     for d in dh.exif:
+         dh.exif[d] = format_text(dh.exif[d])
+
+     return {'desc':dh.desc , 'exif':dh.exif}
+
+
+if __name__ == '__main__':
+    parser = make_parser()
+    parser.setFeature(feature_namespaces,0)
+    dh = GetAlbum()
+    parser.setContentHandler(dh)
+    parser.parse('album.xml')
+    print dh.desc
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/jpginfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/jpginfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/image/jpginfo.py	(revision 4)
@@ -0,0 +1,198 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: jpginfo.py,v 1.21 2005/04/16 17:08:40 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: jpginfo.py,v $
+# Revision 1.21  2005/04/16 17:08:40  dischi
+# read metadata from epeg
+#
+# Revision 1.20  2005/04/16 15:01:15  dischi
+# convert exif tags to str
+#
+# Revision 1.19  2004/05/20 15:56:31  dischi
+# use Python Imaging for more info and gif/bmp support
+#
+# Revision 1.18  2003/06/30 13:17:19  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.17  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.16  2003/06/10 13:02:32  the_krow
+# Softened JPEG parser a little so it accepts jpegs that do not end in FFD9.
+#
+# Revision 1.15  2003/06/09 14:31:57  the_krow
+# fixes on the mpeg parser
+# resolutions, fps and bitrate should be reported correctly now
+#
+# Revision 1.14  2003/06/09 12:50:08  the_krow
+# mp3 now fills tables
+#
+# Revision 1.13  2003/06/08 19:55:22  dischi
+# added bins metadata support
+#
+# Revision 1.12  2003/06/08 16:48:08  dischi
+# Changed self.exif to exif_info and the same for ipc. We should extract
+# everything we need to self.xxx and don't remember where the info came
+# from (it's bad for the cache, we cache everything twice).
+# Also added thumbnail to the list of things we want
+#
+# Revision 1.11  2003/06/08 13:44:57  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.10  2003/06/08 13:11:51  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.9  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.8  2003/05/13 18:28:17  the_krow
+# JPEG Resolution
+#
+# Revision 1.7  2003/05/13 17:49:41  the_krow
+# IPTC restructured\nEXIF Height read correctly\nJPEG Endmarker read
+#
+# Revision 1.6  2003/05/13 15:52:42  the_krow
+# Caption added
+#
+# Revision 1.5  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.4  2003/05/13 15:00:23  the_krow
+# Tiff parsing
+#
+# Revision 1.3  2003/05/13 12:31:11  the_krow
+# + GNU Copyright Notice
+# + PNG Parsing
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import IPTC
+import EXIF
+import struct
+
+import ImageInfo
+
+# interesting file format info:
+# http://www.dcs.ed.ac.uk/home/mxr/gfx/2d-hi.html
+# http://www.funducode.com/freec/Fileformats/format3/format3b.htm
+
+SOF = { 0xC0 : "Baseline",   
+        0xC1 : "Extended sequential",   
+        0xC2 : "Progressive",   
+        0xC3 : "Lossless",   
+        0xC5 : "Differential sequential",   
+        0xC6 : "Differential progressive",   
+        0xC7 : "Differential lossless",   
+        0xC9 : "Extended sequential, arithmetic coding",   
+        0xCA : "Progressive, arithmetic coding",   
+        0xCB : "Lossless, arithmetic coding",   
+        0xCD : "Differential sequential, arithmetic coding",   
+        0xCE : "Differential progressive, arithmetic coding",   
+        0xCF : "Differential lossless, arithmetic coding",
+}
+
+_debug = mediainfo._debug
+
+class JPGInfo(mediainfo.ImageInfo):
+
+    def __init__(self,file):
+        mediainfo.ImageInfo.__init__(self)
+        iptc_info = None        
+        self.mime = 'image/jpeg'
+        self.type = 'jpeg image'
+        self.valid = 1
+        if file.read(2) != '\xff\xd8':
+            self.valid = 0
+            return
+        file.seek(-2,2)
+        if file.read(2) != '\xff\xd9':
+            # Normally an JPEG should end in ffd9. This does not however
+            # we assume it's an jpeg for now
+            mediainfo._debug("Wrong encode found for jpeg")
+        file.seek(2)
+        app = file.read(4)
+        self.meta = {}
+        while (len(app) == 4):
+            (ff,segtype,seglen) = struct.unpack(">BBH", app)
+            if ff != 0xff: break
+            _debug("SEGMENT: 0x%x%x, len=%d" % (ff,segtype,seglen))
+            if segtype == 0xd9:
+                break
+            elif SOF.has_key(segtype):
+                data = file.read(seglen-2)
+                (precision,self.height,self.width,num_comp) = struct.unpack('>BHHB', data[:6])
+                #_debug("H/W: %i / %i" % (self.height, self.width))
+            elif segtype == 0xed:
+                app = file.read(seglen-2)
+                iptc_info = IPTC.flatten(IPTC.parseiptc(app))
+                break
+            elif segtype == 0xe7:
+                # information created by libs like epeg
+                data = file.read(seglen-2)
+                if data.count('\n') == 1:
+                    key, value = data.split('\n')
+                    self.meta[key] = value
+            else:
+                file.seek(seglen-2,1)
+            app = file.read(4)
+        file.seek(0)
+        exif_info = EXIF.process_file(file)
+        if exif_info:
+            self.setitem( 'date', exif_info, 'Image DateTime', True )            
+            self.setitem( 'artist', exif_info, 'Image Artist', True )
+            self.setitem( 'hardware', exif_info, 'Image Model', True )
+            self.setitem( 'software', exif_info, 'Image Software', True )
+            self.setitem( 'thumbnail', exif_info, 'JPEGThumbnail', True )
+            self.appendtable( 'EXIF', exif_info )
+        if iptc_info:
+            self.setitem( 'title', iptc_info, 517, True ) 
+            self.setitem( 'date' , iptc_info, 567, True )
+            self.setitem( 'comment', iptc_info, 617, True )
+            self.setitem( 'keywords', iptc_info, 537, True )
+            self.setitem( 'artist', iptc_info, 592, True )
+            self.setitem( 'country', iptc_info, 612, True ) 
+            self.setitem( 'caption', iptc_info, 632, True )
+            self.appendtable( 'IPTC', iptc_info )            
+
+        if len(self.meta.keys()):
+            self.appendtable( 'JPGMETA', self.meta )
+        for key, value in self.meta.items():
+            if key.startswith('Thumb:') or key == 'Software':
+                setattr(self, key, value)
+                if not key in self.keys:
+                    self.keys.append(key)
+
+        ImageInfo.add(file.name, self)
+        return
+       
+
+mmpython.registertype( 'image/jpeg', ('jpg','jpeg'), mediainfo.TYPE_IMAGE, JPGInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mediainfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mediainfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mediainfo.py	(revision 4)
@@ -0,0 +1,431 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mediainfo.py,v 1.68.2.1 2005/05/07 11:37:08 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: mediainfo.py,v $
+# Revision 1.68.2.1  2005/05/07 11:37:08  dischi
+# make sure all strings are unicode
+#
+# Revision 1.68  2005/04/16 15:01:15  dischi
+# convert exif tags to str
+#
+# Revision 1.67  2005/02/04 12:44:26  dischi
+# fix unicode bug
+#
+# Revision 1.66  2004/09/14 20:13:59  dischi
+# detect rar vobsub files
+#
+# Revision 1.65  2004/09/14 14:38:11  outlyer
+# Fix the broken 'less than' comparison so it is at least consistent, but I'm
+# not sure why we need to add zeroes to numbers anyway. It looks ugly for
+# albums with less than 10 tracks, and it seems unecessary since the
+# sort functions in Freevo add the '0' as needed.
+#
+# Revision 1.64  2004/09/10 19:43:12  outlyer
+# Added discs to exported dict.
+#
+# Revision 1.63  2004/05/29 12:30:36  dischi
+# add function to correct data from the different mime modules
+#
+# Revision 1.62  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.61  2004/05/27 08:59:50  dischi
+# fix chapters printing
+#
+# Revision 1.60  2004/05/20 15:55:08  dischi
+# add xml file detection
+#
+# Revision 1.59  2004/05/18 21:54:49  dischi
+# add chapter support
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+TYPE_NONE = 0
+TYPE_AUDIO = 1
+TYPE_VIDEO = 2
+TYPE_IMAGE = 4
+TYPE_AV = 5
+TYPE_MUSIC = 6
+TYPE_HYPERTEXT = 8
+TYPE_MISC = 10
+
+import string
+import types
+import table
+import traceback
+import locale
+
+import re
+import urllib
+import urlparse
+import os
+
+LOCAL_ENCODING = locale.getpreferredencoding();
+if not LOCAL_ENCODING or LOCAL_ENCODING == "ANSI_X3.4-1968":
+    LOCAL_ENCODING = 'latin1';
+
+MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
+             'date', 'keywords', 'country', 'language', 'url']
+
+AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
+             'bitrate', 'language']
+
+VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'samplebits',
+             'width', 'height', 'fps', 'aspect']
+
+IMAGECORE = ['description', 'people', 'location', 'event',
+             'width','height','thumbnail','software','hardware', 'dpi']
+
+MUSICCORE = ['trackno', 'trackof', 'album', 'genre','discs']
+
+AVCORE    = ['length', 'encoder', 'trackno', 'trackof', 'copyright', 'product',
+             'genre', 'secondary genre', 'subject', 'writer', 'producer', 
+             'cinematographer', 'production designer', 'edited by', 'costume designer',
+             'music by', 'studio', 'distributed by', 'rating', 'starring', 'ripped by',
+             'digitizing date', 'internet address', 'source form', 'medium', 'source',
+             'archival location', 'commisioned by', 'engineer', 'cropped', 'sharpness',
+             'dimensions', 'lightness', 'dots per inch', 'palette setting',
+             'default audio stream', 'logo url', 'watermark url', 'info url',
+             'banner image', 'banner url', 'infotext', 'delay']
+
+
+UNPRINTABLE_KEYS = [ 'thumbnail', ]
+
+import table
+import mmpython
+
+EXTENSION_DEVICE    = 'device'
+EXTENSION_DIRECTORY = 'directory'
+EXTENSION_STREAM    = 'stream'
+
+DEBUG = 0
+
+try:
+    DEBUG = int(os.environ['MMPYTHON_DEBUG'])
+except:
+    pass
+
+def _debug(text):
+    """
+    Function for debug prints of MediaItem implementations.
+    """
+    if DEBUG > 1:
+        try:
+            print text
+        except:
+            print text.encode('latin-1', 'replace')
+    
+
+class MediaInfo:
+    """
+    MediaInfo is the base class to all Media Metadata Containers. It defines the 
+    basic structures that handle metadata. MediaInfo and its derivates contain
+    a common set of metadata attributes that is listed in keys. Specific derivates
+    contain additional keys to the dublin core set that is defined in MediaInfo.
+    MediaInfo also contains tables of addional metadata. These tables are maps
+    of keys to values. The keys themselves should remain in the format that is
+    defined by the metadata (I.E. Hex-Numbers, FOURCC, ...) and will be translated
+    to more readable and i18nified values by an external entity.
+    """
+    def __init__(self):
+        self.keys = []
+        self._tables = {}
+        for k in MEDIACORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+    def __unicode__(self):
+        import copy
+        keys = copy.copy(self.keys)
+
+        for k in UNPRINTABLE_KEYS:
+            if k in keys:
+                keys.remove(k)
+
+        result = u''
+        result += reduce( lambda a,b: self[b] and b != u'url' and u'%s\n        %s: %s' % \
+                         (a, unicode(b), unicode(self[b])) or a, keys, u'' )
+        if DEBUG:
+            try:
+                for i in self._tables.keys():
+                    try:
+                        result += unicode(self._tables[i])
+                    except AttributeError:
+                        pass
+            except AttributeError:
+                pass
+        return result
+        
+
+    def appendtable(self, name, hashmap, language='en'):
+        """
+        Appends a tables of additional metadata to the Object. 
+        If such a table already exists, the given tables items are
+        added to the existing one.
+        """
+        if not self._tables.has_key((name, language)):
+            self._tables[(name, language)] = table.Table(hashmap, name, language)
+        else:
+            # Append to the already existing table
+            for k in hashmap.keys():
+                self._tables[(name, language)][k] = hashmap[k]
+    
+
+    def correct_data(self):
+        """
+        Correct same data based on specific rules
+        """
+        # make sure all strings are unicode
+        for key in self.keys:
+            value = getattr(self, key)
+            if isinstance(value, str):
+                setattr(self, key, unicode(value, LOCAL_ENCODING, 'replace'))
+
+
+    def gettable(self, name, language='en'):
+        """
+        returns a table of the given name and language        
+        """
+        return self._tables.get((name, language), {})
+    
+
+    def setitem(self, item, dict, key, convert_to_str=False):
+        """
+        set item to a specific value for the dict
+        """
+        try:
+            if self.__dict__.has_key(item):
+                if isinstance(dict[key], str):
+                    self.__dict__[item] = unicode(dict[key])
+                elif convert_to_str:
+                    self.__dict__[item] = unicode(dict[key])
+                else:
+                    self.__dict__[item] = dict[key]
+            else:
+                _debug("Unknown key: %s" % item)
+        except:
+            pass
+
+
+    def __getitem__(self,key):
+        """
+        get the value of 'key'
+        """
+        if self.__dict__.has_key(key):
+            if isinstance(self.__dict__[key], str):
+                return self.__dict__[key].strip().rstrip().replace('\0', '')
+            return self.__dict__[key]
+        elif hasattr(self, key):
+            return getattr(self, key)
+        return None
+
+        
+    def __setitem__(self, key, val):
+        """
+        set the value of 'key' to 'val'
+        """
+        self.__dict__[key] = val
+
+
+    def has_key(self, key):
+        """
+        check if the object has a key 'key'
+        """
+        return self.__dict__.has_key(key) or hasattr(self, key)
+
+
+    def __delitem__(self, key):
+        """
+        delete informations about 'key'
+        """
+        try:
+            del self.__dict__[key]
+        except:
+            pass
+        if hasattr(self, key):
+            setattr(self, key, None)
+
+        
+class AudioInfo(MediaInfo):
+    """
+    Audio Tracks in a Multiplexed Container.
+    """
+    def __init__(self):
+        self.keys = []
+        for k in AUDIOCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+class MusicInfo(AudioInfo):
+    """
+    Digital Music.
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        for k in AUDIOCORE+MUSICCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+    def correct_data(self):
+        """
+        correct trackof to be two digest
+        """
+        AudioInfo.correct_data(self)
+        if self['trackof']:
+            try:
+                # XXX Why is this needed anyway?
+                if int(self['trackno']) < 10:
+                    self['trackno'] = '0%s' % int(self['trackno'])
+            except:
+                pass
+
+            
+class VideoInfo(MediaInfo):
+    """
+    Video Tracks in a Multiplexed Container.
+    """
+    def __init__(self):
+        self.keys = []
+        for k in VIDEOCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+           
+
+class ChapterInfo(MediaInfo):
+    """
+    Chapter in a Multiplexed Container.
+    """
+    def __init__(self, name, pos=0):
+        self.keys = ['name', 'pos']
+        setattr(self,'name', name)
+        setattr(self,'pos', pos)
+           
+
+class AVInfo(MediaInfo):
+    """
+    Container for Audio and Video streams. This is the Container Type for
+    all media, that contain more than one stream. 
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        for k in AVCORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+        self.audio = []
+        self.video = []
+        self.subtitles = []
+        self.chapters  = []
+
+
+    def correct_data(self):
+        """
+        correct length to be an int
+        """
+        MediaInfo.correct_data(self)
+        if not self['length'] and len(self.video) and self.video[0]['length']:
+            self['length'] = self.video[0]['length']
+        for container in [ self ] + self.video + self.audio:
+            if container['length']:
+                container['length'] = int(container['length'])
+            
+                                 
+    def find_subtitles(self, filename):
+        """
+        Search for subtitle files. Right now only VobSub is supported
+        """
+        base = os.path.splitext(filename)[0]
+        if os.path.isfile(base+'.idx') and \
+               (os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
+            file = open(base+'.idx')
+            if file.readline().find('VobSub index file') > 0:
+                line = file.readline()
+                while (line):
+                    if line.find('id') == 0:
+                        self.subtitles.append(line[4:6])
+                    line = file.readline()
+            file.close()
+
+            
+    def __unicode__(self):
+        result = u'Attributes:'
+        result += MediaInfo.__unicode__(self)
+        if len(self.video) + len(self.audio) + len(self.subtitles) > 0:
+            result += "\n Stream list:"
+            if len(self.video):
+                result += reduce( lambda a,b: a + u'  \n   Video Stream:' + unicode(b),
+                                  self.video, u'' )
+            if len(self.audio):
+                result += reduce( lambda a,b: a + u'  \n   Audio Stream:' + unicode(b),
+                                  self.audio, u'' )
+            if len(self.subtitles):
+                result += reduce( lambda a,b: a + u'  \n   Subtitle Stream:' + unicode(b),
+                                  self.subtitles, u'' )
+        if not isinstance(self.chapters, int) and len(self.chapters) > 0:
+            result += u'\n Chapter list:'
+            for i in range(len(self.chapters)):
+                result += u'\n   %2s: "%s" %s' % (i+1, unicode(self.chapters[i]['name']),
+                                                  self.chapters[i]['pos'])
+        return result
+
+        
+class ImageInfo(MediaInfo):
+    """
+    Digital Images, Photos, Pictures.
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)        
+        for k in IMAGECORE:
+            setattr(self,k,None)
+            self.keys.append(k)
+
+
+class CollectionInfo(MediaInfo):
+    """
+    Collection of Digial Media like CD, DVD, Directory, Playlist
+    """
+    def __init__(self):
+        MediaInfo.__init__(self)
+        self.tracks = []
+        self.keys.append('id')
+        self.id = None
+
+    def __unicode__(self):
+        result = MediaInfo.__unicode__(self)
+        result += u'\nTrack list:'
+        for counter in range(0,len(self.tracks)):
+             result += u' \nTrack %d:\n%s' % (counter+1, unicode(self.tracks[counter]))
+        return result
+    
+    def appendtrack(self, track):
+        self.tracks.append(track)
+
+
+def get_singleton():
+    print "This function is deprecated. Please use 'mmpython.Factory' instead."
+    return mmpython.Factory()
+
+    
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mminfo
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mminfo	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mminfo	(revision 4)
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mminfo,v 1.4 2004/05/28 12:26:24 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: mminfo,v $
+# Revision 1.4  2004/05/28 12:26:24  dischi
+# Replace __str__ with unicode to avoid bad transformations. Everything
+# inside mmpython should be handled as unicode object.
+#
+# Revision 1.3  2004/05/24 12:54:35  dischi
+# debug update
+#
+# Revision 1.2  2004/05/17 19:10:57  dischi
+# better DEBUG handling
+#
+# Revision 1.1  2004/05/17 19:00:58  dischi
+# rename mediatest.py to mminfo and install it as script to bin
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+import sys
+import os
+
+# add .. for source usage
+sys.path = ['..'] + sys.path
+
+
+print 'mmpython media info'
+
+if len(sys.argv) < 2 or sys.argv[1] in ('-h', '--help'):
+    print
+    print 'usage: mminfo [options] files'
+    print
+    print 'options:'
+    print '  -d   turn on debug information. For complete debug set -d 2'
+    print
+    print 'A file can be a normal file, a device for VCD/VCD/AudioCD'
+    print
+    print 'Examples:'
+    print '  mminfo foo.avi bar.mpg'
+    print '  mminfo /dev/dvd'
+    print
+    sys.exit(0)
+
+# turn on debug
+if sys.argv[1] == '-d':
+    try:
+        int(sys.argv[2])
+        os.environ['MMPYTHON_DEBUG'] = sys.argv[2]
+        sys.argv = sys.argv[2:]
+    except:
+        os.environ['MMPYTHON_DEBUG'] = '1'
+        sys.argv = sys.argv[1:]
+    
+from mmpython import *
+
+for file in sys.argv[1:]:
+    medium = parse(file)
+    print
+    if len(file) > 70:
+        print "filename : %s[...]%s" % (file[:30], file[len(file)-30:])
+    else:
+        print "filename : %s" % file
+    if medium:
+        print unicode(medium).encode('latin-1', 'replace')
+        print
+        print
+    else:
+        print "No Match found"
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/__init__.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/__init__.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/__init__.py	(revision 4)
@@ -0,0 +1,178 @@
+#!/usr/bin/python
+#if 0
+# -----------------------------------------------------------------------
+# $Id: __init__.py,v 1.35 2004/10/15 09:02:11 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: __init__.py,v $
+# Revision 1.35  2004/10/15 09:02:11  dischi
+# add ac3 parser
+#
+# Revision 1.34  2004/05/20 15:55:08  dischi
+# add xml file detection
+#
+# Revision 1.33  2004/05/02 08:28:20  dischi
+# dvd iso support
+#
+# Revision 1.32  2004/04/18 09:11:36  dischi
+# improved lsdvd support
+#
+# Revision 1.31  2004/04/17 18:38:54  dischi
+# add lsdvd parser to avoid problems with our own
+#
+# Revision 1.30  2004/01/31 12:24:39  dischi
+# add basic matroska info
+#
+# Revision 1.29  2004/01/27 20:27:52  dischi
+# remove cache, it does not belong in mmpython
+#
+# Revision 1.28  2004/01/03 17:44:04  dischi
+# catch OSError in case the file is removed file scanning
+#
+# Revision 1.27  2003/11/24 20:30:17  dischi
+# fix again, dvd may fail, but datadir may not
+#
+# Revision 1.26  2003/11/24 20:29:26  dischi
+# resort to let dvd work again
+#
+# Revision 1.25  2003/11/07 13:58:52  dischi
+# extra check for dvd
+#
+# Revision 1.24  2003/09/22 16:24:58  the_krow
+# o added flac
+# o try-except block around ioctl since it is not avaiable in all OS
+#
+# Revision 1.23  2003/09/14 13:50:42  dischi
+# make it possible to scan extention based only
+#
+# Revision 1.22  2003/09/10 18:41:44  dischi
+# add USE_NETWORK, maybe there is no network connection
+#
+# Revision 1.20  2003/08/26 13:16:41  outlyer
+# Enabled m4a support
+#
+# Revision 1.19  2003/07/10 11:17:35  the_krow
+# ogminfo is used to parse ogg files
+#
+# Revision 1.18  2003/07/01 21:07:42  dischi
+# switch back to eyed3info
+#
+# Revision 1.17  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+# Do this stuff before importing the info instances since they 
+# depend on this function
+
+import factory
+
+from synchronizedobject import SynchronizedObject
+
+_factory = None
+
+def Factory():
+    global _factory
+
+    # One-time init
+    if _factory == None:
+        _factory = SynchronizedObject(factory.Factory())
+        
+    return _factory
+
+def registertype(mimetype,extensions,type,c):
+    f = Factory()
+    f.register(mimetype,extensions,type,c)    
+
+def gettype(mimetype,extensions):
+    f = Factory()
+    return f.get(mimetype,extensions)    
+    
+
+# Okay Regular imports and code follow
+
+import sys
+import os
+import mediainfo
+#import audio.ogginfo
+import audio.pcminfo
+import audio.m4ainfo
+import audio.ac3info
+import video.riffinfo
+import video.mpeginfo
+import video.asfinfo
+import video.movinfo
+import image.jpginfo
+import image.pnginfo
+import image.tiffinfo
+import image.ImageInfo
+import video.vcdinfo
+import video.realinfo
+import video.ogminfo
+import video.mkvinfo
+import misc.xmlinfo
+
+# import some disc modules (may fail)
+try:
+    import disc.discinfo
+    import disc.vcdinfo
+    import disc.audioinfo
+except ImportError:
+    pass
+
+# find the best working DVD module
+try:
+    import disc.lsdvd
+except ImportError:
+    pass
+
+try:
+    import disc.dvdinfo
+except ImportError:
+    pass
+
+# use fallback disc module
+try:
+    import disc.datainfo
+except ImportError:
+    pass
+
+import audio.eyed3info
+#import audio.mp3info
+import audio.webradioinfo
+import audio.flacinfo
+
+
+
+USE_NETWORK     = 1
+
+
+def parse(filename, ext_only = 0):
+    """
+    parse the file
+    """
+    return Factory().create(filename, ext_only)
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/setup.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/setup.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/setup.py	(revision 4)
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+"""Setup script for the mmpython distribution."""
+
+__revision__ = "$Id: setup.py,v 1.12 2004/05/25 14:10:19 the_krow Exp $"
+
+from distutils.core import setup, Extension
+import popen2
+import version
+
+extensions = [ Extension('mmpython/disc/cdrom', ['disc/cdrommodule.c']) ]
+# check for libdvdread (bad hack!)
+# Windows does not have Popen4, so catch exception here
+try:
+    child = popen2.Popen4('gcc -ldvdread')
+    if child.fromchild.readline().find('cannot find') == -1:
+        # gcc failed, but not with 'cannot find', so libdvd must be
+        # somewhere (I hope)
+        extensions.append(Extension('mmpython/disc/ifoparser', ['disc/ifomodule.c'],
+                                    libraries=[ 'dvdread' ], 
+                                    library_dirs=['/usr/local/lib'],
+                                    include_dirs=['/usr/local/include']))
+    child.wait()
+except AttributeError, e:
+    print "No Popen4 found. This seems to be Windows."
+    print "Installing without libdvdread support."
+    # Hack: disable extensions for Windows. 
+    # This would better be done by a clean detect of windows. But how?
+    extensions = []
+    
+    
+
+setup (# Distribution meta-data
+       name = "mmpython",
+       version = version.VERSION,
+       description = "Module for retrieving information about media files",
+       author = "Thomas Schueppel, Dirk Meyer",
+       author_email = "freevo-devel@lists.sourceforge.net",
+       url = "http://mmpython.sf.net",
+
+       scripts     = [ 'mminfo' ],
+       package_dir = {'mmpython.video': 'video',
+                      'mmpython.audio': 'audio',
+                      'mmpython.audio.eyeD3': 'audio/eyeD3',
+                      'mmpython.image': 'image',
+                      'mmpython.disc' : 'disc',
+                      'mmpython.misc' : 'misc',
+                      'mmpython': ''},
+
+       packages = [ 'mmpython', 'mmpython.video', 'mmpython.audio', 'mmpython.audio.eyeD3',
+                    'mmpython.image', 'mmpython.disc', 'mmpython.misc' ],
+       
+       # Description of the modules and packages in the distribution
+       ext_modules = extensions
+                       
+      )
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/misc/xmlinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/misc/xmlinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/misc/xmlinfo.py	(revision 4)
@@ -0,0 +1,77 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: xmlinfo.py,v 1.2 2004/05/24 10:50:48 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: xmlinfo.py,v $
+# Revision 1.2  2004/05/24 10:50:48  dischi
+# bugfix
+#
+# Revision 1.1  2004/05/20 15:55:09  dischi
+# add xml file detection
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import os
+import mmpython
+from mmpython import mediainfo
+
+DEBUG = mediainfo.DEBUG
+
+try:
+    # XML support
+    from xml.utils import qp_xml
+except:
+    if DEBUG:
+        print 'Python XML not found'
+
+
+XML_TAG_INFO = {
+    'image':  'Bins Image Description',
+    'freevo': 'Freevo XML Definition'
+    }
+    
+class XMLInfo(mediainfo.MediaInfo):
+
+    def __init__(self,file):
+        mediainfo.MediaInfo.__init__(self)
+        self.valid = 0
+        if not file.name.endswith('.xml') and not file.name.endswith('.fxd'):
+            return
+
+        self.mime  = 'text/xml'
+        self.type  = ''
+
+        try:
+            parser = qp_xml.Parser()
+            tree = parser.parse(file)
+        except:
+            return 0
+
+        if tree.name in XML_TAG_INFO:
+            self.type = XML_TAG_INFO[tree.name]
+        else:
+            self.type = 'XML file'
+        self.valid = 1
+        
+
+mmpython.registertype( 'text/xml', ('xml', 'fxd'), mediainfo.TYPE_MISC, XMLInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/CREDITS
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/CREDITS	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/CREDITS	(revision 4)
@@ -0,0 +1,30 @@
+Credits for mmpython
+====================
+
+$Id: CREDITS,v 1.3 2003/06/09 12:50:07 the_krow Exp $
+
+
+Maintainer: Thomas Schueppel <stain@acm.org>
+
+Developers:
+o Thomas Schueppel <stain@acm.org>
+o Dirk Meyer <dmeyer@tzi.de>
+
+
+
+This package also includes some code from the following projects:
+
+- disc/ifomodule.c is based on ifoinfo from Jens Arnfast
+  http://arnfast.net/projects/ifoinfo.php
+
+- The Python CDDB module from Ben Gertzfield <che@debian.org>
+  http://cddb-py.sourceforge.net/
+
+- bins support by John Cooper, made for the Freevo project
+
+- code from "exifdump.py" originally written by Thierry Bousch
+  <bousch@topo.math.u-psud.fr> and released into the public domain.
+  and code by Gene Cash <gcash@cfl.rr.com>
+
+- code out of Vivake Guptas mp3info which is to be found at
+  http://www.omniscia.org/~vivake/python/MP3Info.py 
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/README
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/README	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/README	(revision 4)
@@ -0,0 +1,7 @@
+To install just run 'python setup.py install' as root. For more
+options like build only and making tarballs please run 
+'python setup.py --help' for more commands.
+
+If you have questions, please contact the Freevo mailing list
+(http://freevo.sf.net)
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/synchronizedobject.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/synchronizedobject.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/synchronizedobject.py	(revision 4)
@@ -0,0 +1,59 @@
+# -*- coding: iso-8859-1 -*-
+
+
+#
+# synchronized objects and methods.
+# By André Bjärby
+# From http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65202
+# 
+
+from types import *
+
+def _get_method_names (obj):
+    if type(obj) == InstanceType:
+        return _get_method_names(obj.__class__)
+    
+    elif type(obj) == ClassType:
+        result = []
+        for name, func in obj.__dict__.items():
+            if type(func) == FunctionType:
+                result.append((name, func))
+
+        for base in obj.__bases__:
+            result.extend(_get_method_names(base))
+
+        return result
+
+
+class _SynchronizedMethod:
+
+    def __init__ (self, method, obj, lock):
+        self.__method = method
+        self.__obj = obj
+        self.__lock = lock
+
+    def __call__ (self, *args, **kwargs):
+        self.__lock.acquire()
+        try:
+            #print 'Calling method %s from obj %s' % (self.__method, self.__obj)
+            return self.__method(self.__obj, *args, **kwargs)
+        finally:
+            self.__lock.release()
+
+class SynchronizedObject:    
+    def __init__ (self, obj, ignore=[], lock=None):
+        import threading
+
+        self.__methods = {}
+        self.__obj = obj
+        lock = lock and lock or threading.RLock()
+        for name, method in _get_method_names(obj):
+            if not name in ignore:
+                self.__methods[name] = _SynchronizedMethod(method, obj, lock)
+
+    def __getattr__ (self, name):
+        try:
+            return self.__methods[name]
+        except KeyError:
+            return getattr(self.__obj, name)
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/factory.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/factory.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/factory.py	(revision 4)
@@ -0,0 +1,306 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: factory.py,v 1.20.2.1 2005/05/07 11:37:08 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: factory.py,v $
+# Revision 1.20.2.1  2005/05/07 11:37:08  dischi
+# make sure all strings are unicode
+#
+# Revision 1.20  2004/05/29 12:30:36  dischi
+# add function to correct data from the different mime modules
+#
+# Revision 1.19  2004/05/28 19:32:31  dischi
+# remove old stuff
+#
+# Revision 1.18  2004/05/17 19:10:57  dischi
+# better DEBUG handling
+#
+# Revision 1.17  2004/05/02 08:28:20  dischi
+# dvd iso support
+#
+# Revision 1.16  2004/02/03 20:41:18  dischi
+# add directory support
+#
+# Revision 1.15  2004/01/31 12:25:20  dischi
+# better ext checking
+#
+# Revision 1.13  2003/09/22 16:24:58  the_krow
+# o added flac
+# o try-except block around ioctl since it is not avaiable in all OS
+#
+# Revision 1.12  2003/09/14 13:50:42  dischi
+# make it possible to scan extention based only
+#
+# Revision 1.11  2003/09/01 19:23:23  dischi
+# ignore case when searching the correct extention
+#
+# Revision 1.10  2003/08/30 12:16:24  dischi
+# special handling for directories
+#
+# Revision 1.8  2003/08/26 18:01:26  outlyer
+# Patch from Lars Eggert for FreeBSD support
+#
+# Revision 1.4  2003/07/04 15:34:45  outlyer
+# Allow 'cdda' as well as 'cd' since we get that sometimes, and make sure
+# we import urllib.
+#
+# Revision 1.3  2003/07/02 09:32:16  the_krow
+# More Keys
+# import traceback was missing in factory
+#
+# Revision 1.1  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import mediainfo
+import stat
+import os
+import urlparse
+import traceback
+import urllib
+
+DEBUG = 0
+
+try:
+    DEBUG = int(os.environ['MMPYTHON_DEBUG'])
+except:
+    pass
+
+
+
+def isurl(url):
+    return url.find('://') > 0
+
+class Factory:
+    """
+    Abstract Factory for the creation of MediaInfo instances. The different Methods
+    create MediaInfo objects by parsing the given medium. 
+    """
+    def __init__(self):
+        self.extmap = {}
+        self.mimemap = {}
+        self.types = []
+        self.device_types = []
+        self.directory_types = []
+        self.stream_types = []
+        
+    def create_from_file(self, file, ext_only=0):
+        """
+        create based on the file stream 'file
+        """
+        # Check extension as a hint
+        for e in self.extmap.keys():
+            if DEBUG > 1: print "trying ext %s" % e
+            if file.name.lower().endswith(e.lower()):
+                if DEBUG == 1: print "trying ext %s" % e
+                try:
+                    file.seek(0,0)
+                    t = self.extmap[e][3](file)
+                    if t.valid: return t
+                except:
+                    if DEBUG:
+                        traceback.print_exc()
+
+        # no searching on all types
+        if ext_only:
+            return None
+
+        if DEBUG:
+            print "No Type found by Extension. Trying all"
+
+        for e in self.types:
+            if DEBUG: print "Trying %s" % e[0]
+            try:
+                file.seek(0,0)
+                t = e[3](file)
+                if t.valid:
+                    if DEBUG: print 'found'
+                    return t
+            except:
+                if DEBUG:
+                    traceback.print_exc()
+        if DEBUG: print 'not found'
+        return None
+
+
+    def create_from_url(self,url):
+        """
+        Create information for urls. This includes file:// and cd://
+        """
+        split  = urlparse.urlsplit(url)
+        scheme = split[0]
+
+        if scheme == 'file':
+            (scheme, location, path, query, fragment) = split
+            return self.create_from_filename(location+path)
+
+        elif scheme == 'cdda':
+            r = self.create_from_filename(split[4])
+            if r:
+                r.url = url
+            return r
+        
+        elif scheme == 'http':
+            # Quick Hack for webradio support
+            # We will need some more soffisticated and generic construction
+            # method for this. Perhaps move file.open stuff into __init__
+            # instead of doing it here...
+            for e in self.stream_types:
+                if DEBUG: print 'Trying %s' % e[0]
+                t = e[3](url)
+                if t.valid:
+                    t.url = url
+                    return t
+            
+        else:
+            (scheme, location, path, query, fragment) = split
+            uhandle = urllib.urlopen(url)
+            mime = uhandle.info().gettype()
+            print "Trying %s" % mime
+            if self.mimemap.has_key(mime):
+                t = self.mimemap[mime][3](file)
+                if t.valid: return t
+            # XXX Todo: Try other types
+        pass
+
+
+    def create_from_filename(self, filename, ext_only=0):
+        """
+        Create information for the given filename
+        """
+        if os.path.isdir(filename):
+            return None
+        if os.path.isfile(filename):
+            try:
+                f = open(filename,'rb')
+            except IOError:
+                print 'IOError reading %s' % filename
+                return None
+            r = self.create_from_file(f, ext_only)
+            f.close()
+            if r:
+                r.correct_data()
+                r.url = 'file://%s' % os.path.abspath(filename)
+                return r
+        return None
+    
+
+    def create_from_device(self,devicename):
+        """
+        Create information from the device. Currently only rom drives
+        are supported.
+        """
+        for e in self.device_types:
+            if DEBUG: print 'Trying %s' % e[0]
+            t = e[3](devicename)
+            if t.valid:
+                t.url = 'file://%s' % os.path.abspath(devicename)
+                return t
+        return None
+            
+
+    def create_from_directory(self, dirname):
+        """
+        Create information from the directory.
+        """
+        for e in self.directory_types:
+            if DEBUG: print 'Trying %s' % e[0]
+            t = e[3](dirname)
+            if t.valid:
+                return t
+        return None
+            
+
+    def create(self, name, ext_only=0):
+        """
+        Global 'create' function. This function calls the different
+        'create_from_'-functions.
+        """
+        try:
+            if isurl(name):
+                return self.create_from_url(name)
+            if not os.path.exists(name):
+                return None
+            try:
+                if (os.uname()[0] == 'FreeBSD' and \
+                    stat.S_ISCHR(os.stat(name)[stat.ST_MODE])) \
+                    or stat.S_ISBLK(os.stat(name)[stat.ST_MODE]):
+                    return self.create_from_device(name)
+            except AttributeError:
+                pass            
+            if os.path.isdir(name):
+                return self.create_from_directory(name)
+            return self.create_from_filename(name, ext_only)
+        except:
+            print 'mmpython.create error:'
+            traceback.print_exc()
+            print
+            print 'Please report this bug to the Freevo mailing list'
+            return None
+
+
+        
+    def register(self,mimetype,extensions,type,c):
+        """
+        register the parser to mmpython
+        """
+        if DEBUG > 0:
+            print "%s registered" % mimetype
+        tuple = (mimetype,extensions,type,c)
+
+        if extensions == mediainfo.EXTENSION_DEVICE:
+            self.device_types.append(tuple)
+        elif extensions == mediainfo.EXTENSION_DIRECTORY:
+            self.directory_types.append(tuple)
+        elif extensions == mediainfo.EXTENSION_STREAM:
+            self.stream_types.append(tuple)
+        else:
+            self.types.append(tuple)
+            for e in extensions:
+                self.extmap[e] = tuple
+            self.mimemap[mimetype] = tuple
+
+
+    def get(self, mimetype, extensions):
+        """
+        return the object for mimetype/extensions or None
+        """
+        if extensions == mediainfo.EXTENSION_DEVICE:
+            l = self.device_types
+        elif extensions == mediainfo.EXTENSION_DIRECTORY:
+            l = self.directory_types
+        elif extensions == mediainfo.EXTENSION_STREAM:
+            l = self.stream_types
+        else:
+            l = self.types
+
+        for info in l:
+            if info[0] == mimetype and info[1] == extensions:
+                return info[3]
+
+        return None
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/mp3info.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/mp3info.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/mp3info.py	(revision 4)
@@ -0,0 +1,532 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: mp3info.py,v 1.12 2003/07/10 13:05:05 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: mp3info.py,v $
+# Revision 1.12  2003/07/10 13:05:05  the_krow
+# o id3v2 tabled added to eyed3
+# o type changed to MUSIC
+#
+# Revision 1.11  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.10  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.9  2003/06/09 22:59:37  the_krow
+# hopefully mp3 files are not detected everytime an mp3 stream is inside a
+# container any longer.
+#
+# Revision 1.8  2003/06/09 14:31:56  the_krow
+# fixes on the mpeg parser
+# resolutions, fps and bitrate should be reported correctly now
+#
+# Revision 1.7  2003/06/09 12:50:08  the_krow
+# mp3 now fills tables
+#
+# Revision 1.6  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.4  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.3  2003/06/07 23:10:50  the_krow
+# Changed mp3 into new format.
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Most of the code of this module was taken from Vivake Guptas mp3info
+# code. Below is his copyright notice. All credit to him.
+#
+# Copyright (c) 2002 Vivake Gupta (vivakeATomniscia.org).  All rights reserved.
+# This software is maintained by Vivake (vivakeATomniscia.org) and is available at:
+#     http://www.omniscia.org/~vivake/python/MP3Info.py
+#
+#
+
+
+import struct
+import string
+from mmpython import mediainfo
+import mmpython
+import re
+
+def _from_synch_safe(synchsafe):
+    if isinstance(synchsafe, type(1)):
+        (b3, b2, b1, b0) = struct.unpack('!4b', struct.pack('!1i', synchsafe))
+    else:
+        while len(synchsafe) < 4:
+            synchsafe = (0,) + synchsafe
+        (b3, b2, b1, b0) = synchsafe
+
+    x = 256
+    return (((b3 * x + b2) * x + b1) * x + b0)
+
+def _strip_zero(s):
+    start = 0
+    while start < len(s) and (s[start] == '\0' or s[start] == ' '):
+        start = start + 1
+
+    end = len(s) - 1
+    while end >= 0 and (s[end] == '\0' or s[end] == ' '):
+        end = end - 1
+
+    return s[start:end+1]
+
+class ID3v2Frame:
+    def __init__(self, file, version):
+        self.name = ""
+        self.version = 0
+        self.padding = 0
+        self.size = 0
+        self.data = ""
+
+        self.flags = {}
+        self.f_tag_alter_preservation = 0
+        self.f_file_alter_preservation = 0
+        self.f_read_only = 0
+        self.f_compression = 0
+        self.f_encryption = 0
+        self.f_grouping_identity = 0
+        self.f_unsynchronization = 0
+        self.f_data_length_indicator = 0
+
+        if version == 2:
+            nameSize = 3
+        else:
+            nameSize = 4
+        self.name = file.read(nameSize)
+
+        self.version = version
+
+        if self.name == nameSize * '\0':
+            self.padding = 1
+            return
+
+        if self.name[0] < 'A' or self.name[0] > 'Z':
+            self.padding = 1
+            return
+
+        size = ()
+        if version == 2:
+            size = struct.unpack('!3b', file.read(3))
+        elif version == 3 or version == 4:
+            size = struct.unpack('!4b', file.read(4))
+
+        if version == 3:  # abc00000 def00000
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_tag_alter_preservation  = flags >> 7 & 1 #a
+            self.f_file_alter_preservation = flags >> 6 & 1 #b
+            self.f_read_only               = flags >> 5 & 1 #c
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_compression             = flags >> 7 & 1 #d
+            self.f_encryption              = flags >> 6 & 1 #e
+            self.f_grouping_identity       = flags >> 5 & 1 #f
+        elif version == 4: # 0abc0000 0h00kmnp
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_tag_alter_preservation  = flags >> 6 & 1 #a
+            self.f_file_alter_preservation = flags >> 5 & 1 #b
+            self.f_read_only               = flags >> 4 & 1 #c
+            (flags,) = struct.unpack('!1b', file.read(1))
+            self.f_grouping_identity       = flags >> 6 & 1 #h
+            self.f_compression             = flags >> 3 & 1 #k
+            self.f_encryption              = flags >> 2 & 1 #m
+            self.f_unsynchronization       = flags >> 1 & 1 #n
+            self.f_data_length_indicator   = flags >> 0 & 1 #p
+        self.size = _from_synch_safe(size)
+        # An ugly hack to obmit crashing for large data
+        if self.size < 65536:
+            self.data = _strip_zero(file.read(self.size))
+
+_genres = [
+    "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
+    "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
+    "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
+    "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
+    "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
+    "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
+    "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
+    "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-industrial",
+    "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
+    "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
+    "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
+    "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
+    "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
+    "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin",
+    "Revival", "Celtic", "Bluegrass", "Avantegarde", "Gothic Rock",
+    "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
+    "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
+    "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
+    "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
+    "Folklore", "Ballad", "Power Ballad", "Rythmic Soul", "Freestyle", "Duet",
+    "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa",
+    "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop",
+    "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
+    "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue",
+    "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop",
+]
+
+class ID3v1:
+    def __init__(self, file):
+        self.valid = 0
+
+        self.tags = { }
+
+        try:
+            file.seek(-128, 2)
+        except IOError:
+            pass
+
+        data = file.read(128)
+        if data[0:3] != 'TAG':
+            return
+        else:
+            self.valid = 1
+
+        self.tags['TT2'] = _strip_zero(data[ 3: 33])
+        self.tags['TP1'] = _strip_zero(data[33: 63])
+        self.tags['TAL'] = _strip_zero(data[63: 93])
+        self.tags['TYE'] = _strip_zero(data[93: 97])
+        self.tags['COM'] = _strip_zero(data[97:125])
+
+        if data[125] == '\0':
+            self.tags['TRK'] = ord(data[126])
+
+        try:
+            self.tags['TCO'] = _genres[ord(data[127])]
+        except IndexError:
+            self.tags['TCO'] = "(%i)" % ord(data[127])
+
+
+class ID3v2:
+    def __init__(self, file):
+        self.valid = 0
+
+        self.tags = { }
+
+        self.header_size = 0
+
+        self.major_version = 0
+        self.minor_version = 0
+
+        self.f_unsynchronization = 0
+        self.f_extended_header = 0
+        self.f_experimental = 0
+        self.f_footer = 0
+
+        self.f_extended_header_zie = 0
+        self.f_extended_num_flag_bytes = 0
+
+        self.ef_update = 0
+        self.ef_crc = 0
+        self.ef_restrictions = 0
+
+        self.crc = 0
+        self.restrictions = 0
+
+        self.frames = []
+        self.tags = {}
+
+        file.seek(0, 0)
+        if file.read(3) != "ID3":
+            return
+        else:
+            self.valid = 1
+
+        (self.major_version, self.minor_version) = struct.unpack('!2b', file.read(2))
+
+        # abcd 0000
+        (flags,) = struct.unpack('!1b', file.read(1))
+        self.f_unsynchronization = flags >> 7 & 1 # a
+        self.f_extended_header   = flags >> 6 & 1 # b
+        self.f_experimental      = flags >> 5 & 1 # c
+        self.f_footer            = flags >> 4 & 1 # d
+
+        self.header_size = _from_synch_safe(struct.unpack('!4b', file.read(4)))
+
+        while 1:
+            if file.tell() >= self.header_size:
+                break
+            frame = ID3v2Frame(file, self.major_version)
+            if frame.padding:
+                file.seek(self.header_size)
+                break
+
+            self.frames.append(frame)
+            self.tags[frame.name] = frame.data
+
+_bitrates = [
+    [ # MPEG-2 & 2.5
+        [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,None], # Layer 1
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None], # Layer 2
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None]  # Layer 3
+    ],
+
+    [ # MPEG-1
+        [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,None], # Layer 1
+        [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,None], # Layer 2
+        [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,None]  # Layer 3
+    ]
+]
+
+_samplerates = [
+    [ 11025, 12000,  8000, None], # MPEG-2.5
+    [  None,  None,  None, None], # reserved
+    [ 22050, 24000, 16000, None], # MPEG-2
+    [ 44100, 48000, 32000, None], # MPEG-1
+]
+
+_modes = [ "stereo", "joint stereo", "dual channel", "mono" ]
+
+_mode_extensions = [
+    [ "4-31", "8-31", "12-31", "16-31" ],
+    [ "4-31", "8-31", "12-31", "16-31" ],
+    [     "",   "IS",    "MS", "IS+MS" ]
+]
+
+_emphases = [ "none", "50/15 ms", "reserved", "CCIT J.17" ]
+
+_MP3_HEADER_SEEK_LIMIT = 4096
+
+class MPEG:
+    def __init__(self, file):
+        self.valid = 0
+        s = file.read(4096)
+        if s[:3] == 'ID3':
+            self.valid = 1
+        if re.compile(r'0*\xFF\xFB\xB0\x04$').search(s):
+            self.valid = 1
+        if re.compile(r'0*\xFF\xFA\xB0\x04$').search(s):
+            self.valid = 1
+        file.seek(0, 2)
+        self.filesize = file.tell()        
+        file.seek(0, 0)
+
+        self.version = 0
+        self.layer = 0
+        self.protection = 0
+        self.bitrate = 0
+        self.samplerate = 0
+        self.padding = 0
+        self.private = 0
+        self.mode = ""
+        self.mode_extension = ""
+        self.copyright = 0
+        self.original = 0
+        self.emphasis = ""
+        self.length = 0
+
+        offset, header = self._find_header(file)
+        if offset == -1 or header is None:
+            return
+
+        self._parse_header(header)
+        ### offset + framelength will find another header. verify??
+        if not self.valid:
+            return
+
+        self._parse_xing(file)
+
+
+    def _find_header(self, file):
+        file.seek(0, 0)
+        amount_read = 0
+
+        # see if we get lucky with the first four bytes
+        amt = 4
+
+        while amount_read < _MP3_HEADER_SEEK_LIMIT:
+            header = file.read(amt)
+            if len(header) < amt:
+                # awfully short file. just give up.
+                return -1, None
+
+            amount_read = amount_read + len(header)
+
+            # on the next read, grab a lot more
+            amt = 500
+
+            # look for the sync byte
+            offset = string.find(header, chr(255))
+            if offset == -1:
+                continue
+            ### maybe verify more sync bits in next byte?
+
+            if offset + 4 > len(header):
+                more = file.read(4)
+                if len(more) < 4:
+                    # end of file. can't find a header
+                    return -1, None
+                amount_read = amount_read + 4
+                header = header + more
+            return amount_read - len(header) + offset, header[offset:offset+4]
+
+        # couldn't find the header
+        return -1, None
+
+    def _parse_header(self, header):
+        # AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
+        (bytes,) = struct.unpack('>i', header)
+        mpeg_version =    (bytes >> 19) & 3  # BB   00 = MPEG2.5, 01 = res, 10 = MPEG2, 11 = MPEG1
+        layer =           (bytes >> 17) & 3  # CC   00 = res, 01 = Layer 3, 10 = Layer 2, 11 = Layer 1
+        protection_bit =  (bytes >> 16) & 1  # D    0 = protected, 1 = not protected
+        bitrate =         (bytes >> 12) & 15 # EEEE 0000 = free, 1111 = bad
+        samplerate =      (bytes >> 10) & 3  # F    11 = res
+        padding_bit =     (bytes >> 9)  & 1  # G    0 = not padded, 1 = padded
+        private_bit =     (bytes >> 8)  & 1  # H
+        mode =            (bytes >> 6)  & 3  # II   00 = stereo, 01 = joint stereo, 10 = dual channel, 11 = mono
+        mode_extension =  (bytes >> 4)  & 3  # JJ
+        copyright =       (bytes >> 3)  & 1  # K    00 = not copyrighted, 01 = copyrighted
+        original =        (bytes >> 2)  & 1  # L    00 = copy, 01 = original
+        emphasis =        (bytes >> 0)  & 3  # MM   00 = none, 01 = 50/15 ms, 10 = res, 11 = CCIT J.17
+
+        if mpeg_version == 0:
+            self.version = 2.5
+        elif mpeg_version == 2:
+            self.version = 2
+        elif mpeg_version == 3:
+            self.version = 1
+        else:
+            return
+
+        if layer > 0:
+            self.layer = 4 - layer
+        else:
+            return
+
+        self.protection = protection_bit
+
+        self.bitrate = _bitrates[mpeg_version & 1][self.layer - 1][bitrate]
+        self.samplerate = _samplerates[mpeg_version][samplerate]
+
+        if self.bitrate is None or self.samplerate is None:
+            return
+
+        self.padding = padding_bit
+        self.private = private_bit
+        self.mode = _modes[mode]
+        self.mode_extension = _mode_extensions[self.layer - 1][mode_extension]
+        self.copyright = copyright
+        self.original = original
+        self.emphasis = _emphases[emphasis]
+
+        if self.layer == 1:
+            self.framelength = ((  12 * (self.bitrate * 1000.0)/self.samplerate) + padding_bit) * 4
+            self.samplesperframe = 384.0
+        else:
+            self.framelength =  ( 144 * (self.bitrate * 1000.0)/self.samplerate) + padding_bit
+            self.samplesperframe = 1152.0
+        self.length = int(round((self.filesize / self.framelength) * (self.samplesperframe / self.samplerate)))
+
+        self.valid = 1
+
+    def _parse_xing(self, file):
+        """Parse the Xing-specific header.
+
+        For variable-bitrate (VBR) MPEG files, Xing includes a header which
+        can be used to approximate the (average) bitrate and the duration
+        of the file.
+        """
+        file.seek(0, 0)
+        header = file.read(128)
+
+        i = string.find(header, 'Xing')
+        if i > 0:
+            (flags,) = struct.unpack('>i', header[i+4:i+8])
+            if flags & 3:
+                # flags says "frames" and "bytes" are present. use them.
+                (frames,bytes) = struct.unpack('>ii', header[i+8:i+16])
+
+                if self.samplerate:
+                    self.length = int(round(frames * self.samplesperframe / self.samplerate))
+                    self.bitrate = ((bytes * 8.0 / self.length) / 1000)
+
+class MP3Info(mediainfo.MusicInfo):
+    def __init__(self, file):
+        mediainfo.MusicInfo.__init__(self)
+        self.valid = 0
+        mpeg = MPEG(file)
+        if not mpeg.valid:
+            self.valid = 0
+            return
+        self.info = {}
+        self.samplerate = mpeg.samplerate
+        self.bitrate = mpeg.bitrate * 1000
+        self.length = mpeg.length
+        self.channels = mpeg.mode
+        if self.samplerate and self.channels and self.bitrate:
+            pass
+        else:
+            self.valid = 0
+            return
+        self.type = 'MPEG %1.f' % mpeg.version
+        self.subtype = 'Layer %d' % mpeg.layer
+        self.valid = 1
+        id3 = ID3v1(file)
+        if id3.valid:
+            self.appendtable('id3v1', id3.tags)
+
+        id3v2 = ID3v2(file)
+        if id3.valid:
+            id3 = id3v2
+            self.appendtable('id3v2', id3.tags)
+
+        if id3 is None:
+            return
+
+        # Set the info fields
+        for tag in id3.tags.keys():
+            if tag == 'TT2' or tag == 'TIT2':
+                self.title = id3.tags[tag]
+            elif tag == 'TP1' or tag == 'TPE1':
+                self.artist = id3.tags[tag]
+            elif tag == 'TRK' or tag == 'TRCK':
+                self.trackno = id3.tags[tag]
+            elif tag == 'TYE' or tag == 'TYER':
+                self.date = id3.tags[tag]
+            elif tag == 'COM' or tag == 'COMM':
+                self.comment = id3.tags[tag]
+            elif tag == 'TCM':
+                self.composer = id3.tags[tag]
+            elif tag == 'TAL' or tag == 'TALB':
+                self.album = id3.tags[tag]
+            elif tag == 'TPA':
+                self.disc = id3.tags[tag]
+            elif tag == 'TCO' or tag == 'TCON':
+                genre = self.genre = id3.tags[tag]
+                if genre and genre[0] == '(' and genre[-1] == ')':
+                    try:
+                        self.info['genre'] = _genres[int(genre[1:-1])]
+                    except IndexError:
+                        self.info['genre'] = ""
+            elif tag == 'TEN' or tag == 'TENC':
+                self.encoder = id3.tags[tag]
+
+
+mmpython.registertype( 'audio/mp3', ('mp3',), mediainfo.TYPE_MUSIC, MP3Info )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/pcminfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/pcminfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/pcminfo.py	(revision 4)
@@ -0,0 +1,81 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: pcminfo.py,v 1.8 2003/06/30 13:17:18 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: pcminfo.py,v $
+# Revision 1.8  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.7  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.6  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.4  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.3  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# -----------------------------------------------------------------------
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import sndhdr
+from mmpython import mediainfo
+import mmpython
+
+class PCMInfo(mediainfo.AudioInfo):
+    def _what(self,f):
+        """Recognize sound headers"""
+        h = f.read(512)
+        for tf in sndhdr.tests:
+            res = tf(h, f)
+            if res:
+                return res
+        return None
+
+    def __init__(self,file):
+       mediainfo.AudioInfo.__init__(self)
+       t = self._what(file)
+       if t:
+           (self.type, self.samplerate, self.channels, self.bitrate, self.samplebits) = t
+           self.mime = "audio/%s" % self.type
+           self.valid = 1
+       else:
+           self.valid = 0
+           return
+       
+
+mmpython.registertype( 'application/pcm', ('wav','aif','voc','au'), mediainfo.TYPE_AUDIO, PCMInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/m4ainfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/m4ainfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/m4ainfo.py	(revision 4)
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# Based on a sample implementation posted to daap-dev mailing list by
+# Bob Ippolito <bob@redivi.com>
+#
+# Modifed by Aubin Paul <aubin@outlyer.org> for mmpython/Freevo
+#
+
+import struct
+from mmpython import mediainfo
+import mmpython
+
+#_print = mediainfo._debug
+
+class Mpeg4(mediainfo.MusicInfo):
+    def __init__(self, file):
+        self.containerTags = ('moov', 'udta', 'trak', 'mdia', 'minf', 'dinf', 'stbl',
+                              'meta', 'ilst', '----')
+        self.skipTags = {'meta':4 }
+
+        mediainfo.MusicInfo.__init__(self)
+        self.valid = 0
+        returnval = 0
+        while returnval == 0:
+            try:
+                self.readNextTag(file)
+            except ValueError:
+                returnval = 1
+        if mediainfo.DEBUG and self.valid:
+            print self.title
+            print self.artist
+            print self.album
+            print self.year
+            print self.encoder
+
+    def readNextTag(self, file):
+        length, name = self.readInt(file), self.read(4, file)
+        length -= 8
+        if length < 0 or length > 1000:
+            raise ValueError, "Oops?"
+        #print "%r" % str(name) # (%r bytes, starting at %r)" % \
+        #  (name, length, file.tell() + 8)
+        if name in self.containerTags:
+            self.read(self.skipTags.get(name, 0), file)
+            data = '[container tag]'
+        else:
+            data = self.read(length, file)
+        if name == '\xa9nam':
+            self.title = data[8:]
+            self.valid = 1
+        if name == '\xa9ART':
+            self.artist = data[8:]
+            self.valid = 1
+        if name == '\xa9alb':
+            self.album = data[8:]
+            self.valid = 1
+        if name == 'trkn':
+            # Fix this
+            self.trackno = data
+            self.valid = 1
+        if name == '\xa9day':
+            self.year = data[8:]
+            self.valid = 1
+        if name == '\xa9too':
+            self.encoder = data[8:]
+            self.valid = 1
+        return 0
+        
+    def read(self, b, file):
+        data = file.read(b)
+        if len(data) < b:
+            raise ValueError, "EOF"
+        return data
+
+    def readInt(self, file):
+        return struct.unpack('>I', self.read(4, file))[0]
+        
+mmpython.registertype( 'application/m4a', ('m4a',), mediainfo.TYPE_MUSIC, Mpeg4 )
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/id3.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/id3.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/id3.py	(revision 4)
@@ -0,0 +1,133 @@
+GENRE_LIST = {
+       0 : 'Blues',
+       1 : 'Classic Rock',
+       2 : 'Country',
+       3 : 'Dance',
+       4 : 'Disco',
+       5 : 'Funk',
+       6 : 'Grunge',
+       7 : 'Hip-Hop',
+       8 : 'Jazz',
+       9 : 'Metal',
+      10 : 'New Age',
+      11 : 'Oldies',
+      12 : 'Other',
+      13 : 'Pop',
+      14 : 'R&B',
+      15 : 'Rap',
+      16 : 'Reggae',
+      17 : 'Rock',
+      18 : 'Techno',
+      19 : 'Industrial',
+      20 : 'Alternative',
+      21 : 'Ska',
+      22 : 'Death Metal',
+      23 : 'Pranks',
+      24 : 'Soundtrack',
+      25 : 'Euro-Techno',
+      26 : 'Ambient',
+      27 : 'Trip-Hop',
+      28 : 'Vocal',
+      29 : 'Jazz+Funk',
+      30 : 'Fusion',
+      31 : 'Trance',
+      32 : 'Classical',
+      33 : 'Instrumental',
+      34 : 'Acid',
+      35 : 'House',
+      36 : 'Game',
+      37 : 'Sound Clip',
+      38 : 'Gospel',
+      39 : 'Noise',
+      40 : 'AlternRock',
+      41 : 'Bass',
+      42 : 'Soul',
+      43 : 'Punk',
+      44 : 'Space',
+      45 : 'Meditative',
+      46 : 'Instrumental Pop',
+      47 : 'Instrumental Rock',
+      48 : 'Ethnic',
+      49 : 'Gothic',
+      50 : 'Darkwave',
+      51 : 'Techno-Industrial',
+      52 : 'Electronic',
+      53 : 'Pop-Folk',
+      54 : 'Eurodance',
+      55 : 'Dream',
+      56 : 'Southern Rock',
+      57 : 'Comedy',
+      58 : 'Cult',
+      59 : 'Gangsta',
+      60 : 'Top 40',
+      61 : 'Christian Rap',
+      62 : 'Pop/Funk',
+      63 : 'Jungle',
+      64 : 'Native American',
+      65 : 'Cabaret',
+      66 : 'New Wave',
+      67 : 'Psychadelic',
+      68 : 'Rave',
+      69 : 'Showtunes',
+      70 : 'Trailer',
+      71 : 'Lo-Fi',
+      72 : 'Tribal',
+      73 : 'Acid Punk',
+      74 : 'Acid Jazz',
+      75 : 'Polka',
+      76 : 'Retro',
+      77 : 'Musical',
+      78 : 'Rock & Roll',
+      79 : 'Hard Rock',
+
+      
+    # The following genres are Winamp extensions
+
+      
+      80 : 'Folk',
+      81 : 'Folk-Rock',
+      82 : 'National Folk',
+      83 : 'Swing',
+      84 : 'Fast Fusion',
+      85 : 'Bebob',
+      86 : 'Latin',
+      87 : 'Revival',
+      88 : 'Celtic',
+      89 : 'Bluegrass',
+      90 : 'Avantgarde',
+      91 : 'Gothic Rock',
+      92 : 'Progressive Rock',
+      93 : 'Psychedelic Rock',
+      94 : 'Symphonic Rock',
+      95 : 'Slow Rock',
+      96 : 'Big Band',
+      97 : 'Chorus',
+      98 : 'Easy Listening',
+      99 : 'Acoustic',
+     100 : 'Humour',
+     101 : 'Speech',
+     102 : 'Chanson',
+     103 : 'Opera',
+     104 : 'Chamber Music',
+     105 : 'Sonata',
+     106 : 'Symphony',
+     107 : 'Booty Bass',
+     108 : 'Primus',
+     109 : 'Porn Groove',
+     110 : 'Satire',
+     111 : 'Slow Jam',
+     112 : 'Club',
+     113 : 'Tango',
+     114 : 'Samba',
+     115 : 'Folklore',
+     116 : 'Ballad',
+     117 : 'Power Ballad',
+     118 : 'Rhythmic Soul',
+     119 : 'Freestyle',
+     120 : 'Duet',
+     121 : 'Punk Rock',
+     122 : 'Drum Solo',
+     123 : 'A capella',
+     124 : 'Euro-House',
+     125 : 'Dance Hall'
+}
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/flacinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/flacinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/flacinfo.py	(revision 4)
@@ -0,0 +1,143 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: flacinfo.py,v 1.7 2003/10/05 21:06:24 outlyer Exp $
+# -----------------------------------------------------------------------
+# $Log: flacinfo.py,v $
+# Revision 1.7  2003/10/05 21:06:24  outlyer
+# Cram the VORBIS_COMMENT fields into our standard artist/album/etc. fields
+# so they work in Freevo.
+#
+# The only thing missing from having perfect FLAC support is a way to
+# calculate the song length.
+#
+# Revision 1.6  2003/10/05 20:45:09  outlyer
+# Fix some minor python issues. It works from mediatest.py now, but Freevo
+# isn't using the tag information yet. I don't know why.
+#
+# Revision 1.5  2003/09/22 16:21:20  the_krow
+# o ogg parsing should basically work
+# o utf-8 for vorbis comments
+#
+# Revision 1.4  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.3  2003/08/27 02:53:48  outlyer
+# Still doesn't do anything, but at least compiles now; problem is I don't
+# know how to conver the endian "headers" in to the types we expect, and I'm
+# hardly an expert on binary data.
+#
+# But I flushed out the header types from the FLAC documentation and
+# hopefully Thomas will know what to do...
+#
+# I can provide a FLAC file if necessary...
+#
+# Revision 1.2  2003/08/26 21:21:18  outlyer
+# Fix two more Python 2.3 warnings.
+#
+# Revision 1.1  2003/08/18 13:39:52  the_krow
+# Initial Import. Started on frame parsing.
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+from mmpython import mediainfo
+import mmpython.audio.ogginfo as ogginfo
+import mmpython
+import struct
+import re
+
+# See: http://flac.sourceforge.net/format.html
+
+
+class FlacInfo(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        if file.read(4) != 'fLaC':
+            self.valid = 0
+            return
+        self.valid = 1
+        while 1:
+            (blockheader,) = struct.unpack('>I',file.read(4))
+            lastblock = (blockheader >> 31) & 1
+            type = (blockheader >> 24) & 0x7F
+            numbytes = blockheader & 0xFFFFFF
+            if mmpython.mediainfo.DEBUG:
+                print "Last?: %d, NumBytes: %d, Type: %d" % (lastblock, numbytes, type)                                
+            # Read this blocks the data
+            data = file.read(numbytes)
+            if type == 0:
+                # STREAMINFO
+                bits = struct.unpack('>L', data[10:14])[0]
+                self.samplerate = (bits >> 12) & 0xFFFFF
+                self.channels = ((bits >> 9) & 7) + 1
+                self.samplebits = ((bits >> 4) & 0x1F) + 1
+                md5 = data[18:34]
+            elif type == 1:
+                # PADDING
+                pass            
+            elif type == 2:
+                # APPLICATION 
+                pass            
+            elif type == 3:
+                # SEEKTABLE 
+                pass            
+            elif type == 4:
+                # VORBIS_COMMENT                
+                skip, self.vendor = self._extractHeaderString(data)
+                num, = struct.unpack('<I', data[skip:skip+4])
+                start = skip+4
+                header = {}
+                for i in range(num):
+                    (nextlen, s) = self._extractHeaderString(data[start:])
+                    start += nextlen
+                    a = re.split('=',s)
+                    header[(a[0]).upper()]=a[1]
+                if header.has_key('TITLE'):
+                    self.title = header['TITLE']
+                if header.has_key('ALBUM'):
+                    self.album = header['ALBUM']
+                if header.has_key('ARTIST'):
+                    self.artist = header['ARTIST']            
+                if header.has_key('COMMENT'):
+                    self.comment = header['COMMENT']
+                if header.has_key('DATE'):
+                    self.date = header['DATE']
+                if header.has_key('ENCODER'):
+                    self.encoder = header['ENCODER']
+                if header.has_key('TRACKNUMBER'):
+                    self.trackno = header['TRACKNUMBER']
+ 
+                self.appendtable('VORBISCOMMENT', header)
+            elif type == 5:
+                # CUESHEET 
+                pass
+            else:
+                # UNKNOWN TYPE
+                pass
+            if lastblock:
+                break
+
+    def _extractHeaderString(self,header):
+        len = struct.unpack( '<I', header[:4] )[0]
+        return (len+4,unicode(header[4:4+len], 'utf-8'))
+
+                
+mmpython.registertype( 'application/flac', ('flac',), mediainfo.TYPE_MUSIC, FlacInfo )                
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ac3info.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ac3info.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ac3info.py	(revision 4)
@@ -0,0 +1,128 @@
+from mmpython import mediainfo
+import mmpython
+
+import struct
+
+# http://www.atsc.org/standards/a_52a.pdf
+# fscod: Sample rate code, 2 bits
+#  00  48
+#  01  44.1
+#  10  32
+#  11  reserved
+
+FSCOD = [ 48000, 44100, 32000, 0 ]
+
+# bsmod: Bit stream mode, 3 bits
+# bsmod acmod Type of Service
+#  000  any main audio service: complete main (CM)
+#  001  any main audio service: music and effects (ME)
+#  010  any associated service: visually impaired (VI)
+#  011  any associated service: hearing impaired (HI)
+#  100  any associated service: dialogue (D)
+#  101  any associated service: commentary (C)
+#  110  any associated service: emergency (E)
+#  111  001 associated service: voice over (VO)
+#  111  010 - 111  main audio service: karaoke
+# 
+# acmod: Audio coding mode, 3 bits
+#  000  1+1 2 Ch1, Ch2
+#  001  1/0 1 C
+#  010  2/0 2 L, R
+#  011  3/0 3 L, C, R
+#  100  2/1 3 L, R, S
+#  101  3/1 4 L, C, R, S
+#  110  2/2 4 L, R, SL, SR
+#  111  3/2 5 L, C, R, SL, SR
+
+ACMOD = [ ( '1+1', 2, 'Ch1, Ch2' ),
+          ( '1/0', 1, 'C' ),
+          ( '2/0', 2, 'L, R' ),
+          ( '3/0', 3, 'L, C, R' ),
+          ( '2/1', 3, 'L, R, S' ),
+          ( '3/1', 4, 'L, C, R, S' ),
+          ( '2/2', 4, 'L, R, SL, SR' ),
+          ( '3/2', 5, 'L, C, R, SL, SR' ) ]
+            
+
+# dsurmod: Dolby surround mode, 2 bits
+#  00  not indicated
+#  01  Not Dolby Surround encoded
+#  10  Dolby Surround encoded
+#  11  reserved
+# 
+# lfeon: Low frequency effects channel on, 1 bit
+# This bit has a value of 1 if the lfe (sub woofer) channel is on, and a
+# value of 0 if the lfe channel is off.
+# 
+# frmsizcod:
+#  byte&0x3e = 0x00        \b, 32 kbit/s
+#  byte&0x3e = 0x02        \b, 40 kbit/s
+#  byte&0x3e = 0x04        \b, 48 kbit/s
+#  byte&0x3e = 0x06        \b, 56 kbit/s
+#  byte&0x3e = 0x08        \b, 64 kbit/s
+#  byte&0x3e = 0x0a        \b, 80 kbit/s
+#  byte&0x3e = 0x0c        \b, 96 kbit/s
+#  byte&0x3e = 0x0e        \b, 112 kbit/s
+#  byte&0x3e = 0x10        \b, 128 kbit/s
+#  byte&0x3e = 0x12        \b, 160 kbit/s
+#  byte&0x3e = 0x14        \b, 192 kbit/s
+#  byte&0x3e = 0x16        \b, 224 kbit/s
+#  byte&0x3e = 0x18        \b, 256 kbit/s
+#  byte&0x3e = 0x1a        \b, 320 kbit/s
+#  byte&0x3e = 0x1c        \b, 384 kbit/s
+#  byte&0x3e = 0x1e        \b, 448 kbit/s
+#  byte&0x3e = 0x20        \b, 512 kbit/s
+#  byte&0x3e = 0x22        \b, 576 kbit/s
+#  byte&0x3e = 0x24        \b, 640 kbit/s
+
+FRMSIZCOD = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192,
+              224, 256, 320, 384, 448, 512, 576, 640 ]
+
+class AC3Info(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        if file.name.endswith('.ac3'):
+            # when the ending is ac3, force the detection. It may not be necessary
+            # the the header is at the beginning but in the first 2000 bytes
+            check_length = 1000
+        else:
+            check_length = 1
+        for i in range(check_length):
+            if file.read(2) == '\x0b\x77':
+                break
+        else:
+            self.valid = False
+            return
+
+        info = struct.unpack('<HBBBB',file.read(6))
+        self.samplerate = FSCOD[info[1] >> 6]
+        self.bitrate = FRMSIZCOD[(info[1] & 0x3F) >> 1] * 1000
+        bsmod = info[2] & 0x7
+        channels = ACMOD[info[3] >> 5]
+        acmod = info[3] >> 5
+        self.channels = ACMOD[acmod][1]
+        bits = 0
+        if acmod & 0x01 and not acmod == 0x01:
+            bits += 2
+        if acmod & 0x04:
+            bits += 2
+        if acmod == 0x02:
+            bits += 2
+
+        # info is now 5 bits of info[3] and all bits of info[4] ( == 13 bits)
+        # 'bits' bits (0-6) bits are information we don't need, after that,
+        # the bit we need is lfeon.
+        info = (((info[3] & 0x1F) << 8) + info[4])
+
+        # now we create the mask we need (based on 'bits')
+        # the bit number 13 - 'bits' is what we want to read
+        for i in range(13 - bits - 1):
+            info = info >> 1
+        if info & 1:
+            # subwover
+            self.channels += 1
+        self.valid = True
+        self.codec = 'AC3'
+        self.mime = 'audio/ac3'
+        
+mmpython.registertype( 'audio/ac3', ('ac3',), mediainfo.TYPE_MUSIC, AC3Info )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/binfuncs.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/binfuncs.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/binfuncs.py	(revision 4)
@@ -0,0 +1,123 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#  Copyright (C) 2001  Ryan Finne <ryan@finnie.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+
+# Accepts a string of bytes (chars) and returns an array of bits
+# representing the bytes in big endian byte (Most significant byte/bit first)
+# order.  Each byte can have it's higher bits ignored by passing an sz arg.
+def bytes2bin(bytes, sz = 8):
+   if sz < 1 or sz > 8:
+      raise ValueError("Invalid sz value: " + str(sz));
+
+   retVal = [];
+   for b in bytes:
+      bits = [];
+      b = ord(b);
+      while b > 0:
+         bits.append(b & 1);
+         b >>= 1;
+
+      if len(bits) < sz:
+         bits.extend([0] * (sz - len(bits)));
+      elif len(bits) > sz:
+         bits = bits[:sz];
+
+      # Big endian byte order.
+      bits.reverse();
+      retVal.extend(bits);
+
+   if len(retVal) == 0:
+      retVal = [0];
+   return retVal;
+
+# Convert am array of bits (MSB first) into a string of characters.
+def bin2bytes(x):
+   bits = [];
+   bits.extend(x);
+   bits.reverse();
+
+   i = 0;
+   out = '';
+   multi = 1;
+   ttl = 0;
+   for b in bits:
+      i += 1;
+      ttl += b * multi;
+      multi *= 2;
+      if i == 8:
+         i = 0;
+         out += chr(ttl);
+         multi = 1;
+         ttl = 0;
+
+   if multi > 1:
+      out += chr(ttl);
+
+   out = list(out);
+   out.reverse();
+   out = ''.join(out);
+   return out;
+
+# Convert and array of "bits" (MSB first) to it's decimal value.
+def bin2dec(x):
+   bits = [];
+   bits.extend(x);
+   bits.reverse();
+
+   multi = 1;
+   value = 0;
+   for b in bits:
+      value += b * multi;
+      multi *= 2;
+   return value;
+
+# Convert a decimal value to an array of bits (MSB first), optionally
+# padding the overall size to p bits.
+def dec2bin(n, p = 0):
+   retVal = [];
+
+   while n > 0:
+      retVal.append(n & 1);
+      n >>= 1;
+
+   if p > 0:
+      retVal.extend([0] * (p - len(retVal)));
+   retVal.reverse();
+   return retVal;
+
+# Convert a list of bits (MSB first) to a synch safe list of bits (section 6.2
+# of the ID3 2.4 spec).
+def bin2synchsafe(x):
+   if len(x) > 32 or bin2dec(x) > 268435456:   # 2^28
+      raise ValueError("Invalid value");
+   elif len(x) < 8:
+      return x;
+
+   n = bin2dec(x);
+   bites = "";
+   bites += chr((n >> 21) & 0x7f);
+   bites += chr((n >> 14) & 0x7f);
+   bites += chr((n >>  7) & 0x7f);
+   bites += chr((n >>  0) & 0x7f);
+   bits = bytes2bin(bites);
+   if len(bits) < 32:
+      bits = ([0] * (32 - len(x))) + bits;
+
+   return bits;
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/tag.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/tag.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/tag.py	(revision 4)
@@ -0,0 +1,1638 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+import re, os, string, stat, shutil, tempfile, binascii;
+import mimetypes;
+from stat import *;
+from mmpython.audio.eyeD3 import *;
+
+import utils as utils
+import mp3 as eyeD3_mp3
+
+from frames import *;
+from binfuncs import *;
+
+
+ID3_V1_COMMENT_DESC = "ID3 v1 Comment";
+
+################################################################################
+class TagException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class TagHeader:
+   SIZE = 10;
+
+   version = None;
+   majorVersion = None;
+   minorVersion = None;
+   revVersion = None;
+
+   # Flag bits
+   unsync = 0;
+   extended = 0;
+   experimental = 0;
+   # v2.4 addition
+   footer = 0;
+
+   # The size in the most recently parsed header.
+   tagSize = 0;
+   
+   # Constructor
+   def __init__(self):
+      self.clear();
+
+   def clear(self):
+      self.setVersion(None);
+      self.unsync = 0;
+      self.extended = 0;
+      self.experimental = 0;
+      self.tagSize = 0;
+
+   def setVersion(self, v):
+      if v == None:
+         self.version = None;
+         self.majorVersion = None;
+         self.minorVersion = None;
+         self.revVersion = None;
+         return;
+
+      if v == ID3_CURRENT_VERSION:
+         if self.majorVersion == None or self.minorVersion == None:
+            v = ID3_DEFAULT_VERSION;
+         else:
+            return;
+      elif v == ID3_ANY_VERSION:
+         v = ID3_DEFAULT_VERSION;
+
+      # Handle 3-element lists or tuples.
+      if isinstance(v, tuple) or isinstance(v, list):
+         self.version = utils.versionsToConstant(v);
+         (self.majorVersion,
+          self.minorVersion,
+          self.revVersion) = v;
+      # Handle int constants.
+      elif isinstance(v, int):
+         (self.majorVersion,
+          self.minorVersion,
+          self.revVersion) = utils.constantToVersions(v);
+         self.version = v;
+      else:
+         raise TypeError("Wrong type: %s" % str(type(v)));
+
+   # Given a file handle this method attempts to identify and then parse
+   # a ID3 v2 header.  If successful, the parsed values are stored in
+   # the instance variable.  If the files does not contain an ID3v2 tag
+   # false is returned. A TagException is thrown if a tag is found, but is
+   # not valid or corrupt.
+   def parse(self, f):
+      self.clear();
+
+      # The first three bytes of a v2 header is "ID3".
+      if f.read(3) != "ID3":
+         return 0;
+      TRACE_MSG("Located ID3 v2 tag");
+
+      # The next 2 bytes are the minor and revision versions.
+      version = f.read(2);
+      major = 2;
+      minor = ord(version[0]);
+      rev = ord(version[1]);
+      TRACE_MSG("TagHeader [major]: " + str(major));
+      TRACE_MSG("TagHeader [minor]: " + str(minor));
+      TRACE_MSG("TagHeader [revis]: " + str(rev));
+      if not (major == 2 and (minor == 3 or minor == 4)):
+         raise TagException("ID3 v" + str(major) + "." + str(minor) +\
+                            " is not supported.");
+      # Get all the version madness in sync.
+      self.setVersion([major, minor, rev]);
+
+      # The first 4 bits of the next byte are flags.
+      (self.unsync,
+       self.extended,
+       self.experimental,
+       self.footer) = bytes2bin(f.read(1))[0:4];
+      TRACE_MSG("TagHeader [flags]: unsync(%d) extended(%d) "\
+                "experimental(%d) footer(%d)" % (self.unsync, self.extended,
+                                                 self.experimental,
+                                                 self.footer));
+
+      # The size of the optional extended header, frames, and padding
+      # afer unsynchronization.  This is a sync safe integer, so only the
+      # bottom 7 bits of each byte are used.
+      tagSizeStr = f.read(4);
+      TRACE_MSG("TagHeader [size string]: 0x%02x%02x%02x%02x" %\
+                (ord(tagSizeStr[0]), ord(tagSizeStr[1]),
+                 ord(tagSizeStr[2]), ord(tagSizeStr[3])));
+      self.tagSize = bin2dec(bytes2bin(tagSizeStr, 7));
+      TRACE_MSG("TagHeader [size]: %d (0x%x)" % (self.tagSize, self.tagSize));
+
+      return 1;
+
+   def render(self, tagLen = None):
+      if tagLen != None:
+         self.tagSize = tagLen;
+
+      data = "ID3";
+      data += chr(self.minorVersion) + chr(self.revVersion);
+      # not not the values so we only get 1's and 0's.
+      data += bin2bytes([not not self.unsync,
+                         not not self.extended,
+                         not not self.experimental,
+                         not not self.footer,
+                         0, 0, 0, 0]);
+      TRACE_MSG("Setting tag size to %d" % tagLen);
+      szBytes = bin2bytes(bin2synchsafe(dec2bin(tagLen, 32)));
+      data += szBytes;
+      TRACE_MSG("TagHeader Rendered");
+      return data;
+
+################################################################################
+class ExtendedTagHeader:
+   size = 0;
+   flags = 0;
+   crc = 0;
+   restrictions = 0;
+
+   def isUpdate(self):
+      return self.flags & 0x40;
+   def hasCRC(self):
+      return self.flags & 0x20;
+   def hasRestrictions(self):
+      return self.flags & 0x10;
+
+   def setSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = (v << 6) | (self.restrictions & 0x3f);
+   def getSizeRestrictions(self):
+      return self.restrictions >> 6;
+   def getSizeRestrictionsString(self):
+      val = self.getSizeRestrictions();
+      if val == 0x00:
+         return "No more than 128 frames and 1 MB total tag size.";
+      elif val == 0x01:
+         return "No more than 64 frames and 128 KB total tag size.";
+      elif val == 0x02:
+         return "No more than 32 frames and 40 KB total tag size.";
+      elif val == 0x03:
+         return "No more than 32 frames and 4 KB total tag size.";
+
+   def setTextEncodingRestrictions(self, v):
+      assert(v == 0 or v == 1);
+      self.restrictions ^= 0x20;
+   def getTextEncodingRestrictions(self):
+      return self.restrictions & 0x20;
+   def getTextEncodingRestrictionsString(self):
+      if self.getTextEncodingRestrictions():
+         return "Strings are only encoded with ISO-8859-1 [ISO-8859-1] or "\
+                "UTF-8 [UTF-8].";
+      else:
+         return "None";
+
+   def setTextFieldSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = (v << 3) | (self.restrictions & 0xe7);
+   def getTextFieldSizeRestrictions(self):
+      return (self.restrictions >> 3) & 0x03;
+   def getTextFieldSizeRestrictionsString(self):
+      val = self.getTextFieldSizeRestrictions();
+      if val == 0x00:
+         return "None";
+      elif val == 0x01:
+         return "No string is longer than 1024 characters.";
+      elif val == 0x02:
+         return "No string is longer than 128 characters.";
+      elif val == 0x03:
+         return "No string is longer than 30 characters.";
+
+   def setImageEncodingRestrictions(self, v):
+      assert(v == 0 or v == 1);
+      self.restrictions ^= 0x04;
+   def getImageEncodingRestrictions(self):
+      return self.restrictions & 0x04;
+   def getImageEncodingRestrictionsString(self):
+      if self.getImageEncodingRestrictions():
+         return "Images are encoded only with PNG [PNG] or JPEG [JFIF].";
+      else:
+         return "None";
+
+   def setImageSizeRestrictions(self, v):
+      assert(v >= 0 and v <= 3);
+      self.restrictions = v | (self.restrictions & 0xfc);
+   def getImageSizeRestrictions(self):
+      return self.restrictions & 0x03;
+   def getImageSizeRestrictionsString(self):
+      val = self.getImageSizeRestrictions();
+      if val == 0x00:
+         return "None";
+      elif val == 0x01:
+         return "All images are 256x256 pixels or smaller.";
+      elif val == 0x02:
+         return "All images are 64x64 pixels or smaller.";
+      elif val == 0x03:
+         return "All images are exactly 64x64 pixels, unless required "\
+                "otherwise.";
+
+   def render(self, header, frameData, padding = 0):
+      assert(header.majorVersion == 2);
+
+      data = "";
+      if header.minorVersion == 4:
+         # Version 2.4
+         crc = None;
+         size = 6;
+         # Extended flags.
+         if self.isUpdate():
+            data = "\x00";
+         if self.hasCRC():
+            data += "\x05";
+            self.crc = binascii.crc32(data);
+            data += bin2bytes(dec2bin(self.crc, 40));
+         if self.hasRestrictions():
+            data += "\x01";
+            assert(len(self.restrictions) == 1);
+            data += self.restrictions;
+
+         # Extended header size.
+         size = bin2bytes(bin2synchsafe(dec2bin(len(data) + 6, 32)))
+         assert(len(size) == 4);
+
+         assert(len(self.flags) == 2);
+         data = size + "\x01" + self.flags + data;
+      else:
+         # Version 2.3
+         crc = None;
+         size = 6;
+         # Extended flags.
+         f = [0] * 16;
+         if self.hasCRC():
+            f[0] = 1;
+            self.crc = binascii.crc32(data);
+            crc = bin2bytes(dec2bin(self.crc));
+            assert(len(crc) == 4);
+            size += 4;
+         flags = bin2bytes(f);
+         assert(len(flags) == 2);
+         # Extended header size.
+         size = bin2bytes(dec2bin(size, 32))
+         assert(len(size) == 4);
+         # Padding size
+         paddingSize = bin2bytes(dec2bin(padding, 32));
+
+         data = size + flags + paddingSize;
+         if crc:
+            data += crc;
+      return data; 
+
+   # Only call this when you *know* there is an extened header.
+   def parse(self, fp, header):
+      assert(header.majorVersion == 2);
+
+      # First 4 bytes is the size of the extended header.
+      data = fp.read(4);
+      if header.minorVersion == 4:
+         TRACE_MSG("Parsing extended header for v2.4");
+         # sync-safe
+         sz = bin2dec(bytes2bin(data, 7));
+         TRACE_MSG("Extended header size: %d" % (sz - 4));
+         data = fp.read(sz - 4);
+
+         if ord(data[0]) != 1 or (ord(data[1]) & 0x8f):
+            # As of 2.4 the first byte is 1 and the second can only have
+            # bits 6, 5, and 4 set.
+            raise TagException("Invalid Extended Header");
+
+         offset = 2;
+         self.flags = ord(data[1]);
+         TRACE_MSG("Extended header flags: %x" % self.flags);
+
+         if self.isUpdate():
+            TRACE_MSG("Extended header has update bit set");
+            assert(ord(data[offset]) == 0);
+            offset += 1;
+         if self.hasCRC():
+            TRACE_MSG("Extended header has CRC bit set");
+            assert(ord(data[offset]) == 5);
+            offset += 1;
+            crcData = data[offset:offset + 5];
+            # This is sync-safe.
+            self.crc = bin2dec(bytes2bin(crcData, 7));
+            TRACE_MSG("Extended header CRC: %d" % self.crc);
+            offset += 5;
+         if self.hasRestrictions():
+            TRACE_MSG("Extended header has restrictions bit set");
+            assert(ord(data[offset]) == 5);
+            offset += 1;
+            self.restrictions = ord(data[offset]);
+            offset += 1;
+      else:
+         TRACE_MSG("Parsing extended header for v2.3");
+         # v2.3 is totally different... *sigh*
+         sz = bin2dec(bytes2bin(data));
+         TRACE_MSG("Extended header size: %d" % sz);
+         data = fp.read(sz);
+         tmpFlags = fp.read(2);
+         # Make this look like a v2.4 mask.
+         self.flags = ord(tmpFlags[0]) >> 2;
+         if self.hasCRC():
+            TRACE_MSG("Extended header has CRC bit set");
+            crcData = fp.read(4);
+            self.crc = bin2dec(bytes2bin(crcData));
+            TRACE_MSG("Extended header CRC: %d" % self.crc);
+         # Read the padding size, but it'll be computed during the parse.
+         fp.read(4);
+
+
+################################################################################
+# ID3 tag class.  The class is capable of reading v1 and v2 tags.  ID3 v1.x
+# are converted to v2 frames.
+class Tag:
+   # Latin1 is the default (0x00)
+   encoding = DEFAULT_ENCODING;
+
+   # ID3v1 tags do not contain a header.  The only ID3v1 values stored
+   # in this header are the major/minor version.
+   header = TagHeader();
+
+   # Optional in v2 tags.
+   extendedHeader = ExtendedTagHeader();
+
+   # Contains the tag's frames.  ID3v1 fields are read and converted
+   # the the corresponding v2 frame.  
+   frames = None;
+
+   # Used internally for iterating over frames.
+   iterIndex = None;
+
+   # If this value is None the tag is not linked to any particular file..
+   linkedFile = None;
+
+   # Constructor.  An empty tag is created and the link method is used
+   # to read an mp3 file's v1.x or v2.x tag.  You can optionally set a 
+   # file name, but it will not be read, but may be written to.
+   def __init__(self, fileName = None):
+      if fileName:
+         self.linkedFile = LinkedFile(fileName);
+      self.clear();
+
+   def clear(self):
+      self.header = TagHeader();
+      self.frames = FrameSet(self.header);
+      self.iterIndex = None;
+      linkedFile = None;
+
+   # Returns an read-only iterator for all frames.
+   def __iter__(self):
+      if len(self.frames):
+         self.iterIndex = 0;
+      else:
+         self.iterIndex = None;
+      return self;
+
+   def next(self):
+      if self.iterIndex == None or self.iterIndex == len(self.frames):
+         raise StopIteration;
+      frm = self.frames[self.iterIndex];
+      self.iterIndex += 1;
+      return frm;
+
+   # Returns true when an ID3 tag is read from f which may be a file name
+   # or an aleady opened file object.  In the latter case, the file object 
+   # is not closed when this method returns.
+   #
+   # By default, both ID3 v2 and v1 tags are parsed in that order.
+   # If a v2 tag is found then a v1 parse is not performed.  This behavior
+   # can be refined by passing ID3_V1 or ID3_V2 as the second argument 
+   # instead of the default ID3_ANY_VERSION.
+   #
+   # Converts all ID3v1 data into ID3v2 frames internally.
+   # May throw IOError, or TagException if parsing fails.
+   def link(self, f, v = ID3_ANY_VERSION):
+      self.clear();
+
+      fileName = "";
+      if isinstance(f, file):
+         fileName = f.name;
+      elif isinstance(f, str):
+         fileName = f;
+      else:
+         raise TagException("Invalid type passed to Tag.link: " + 
+                            str(type(f)));
+
+      if v != ID3_V1 and v != ID3_V2 and v != ID3_ANY_VERSION:
+         raise TagException("Invalid version: " + hex(v));
+
+      tagFound = 0;
+      padding = 0;
+      TRACE_MSG("Linking File: " + fileName);
+      if v == ID3_V1:
+         if self.__loadV1Tag(f):
+            tagFound = 1;
+      elif v == ID3_V2:
+         padding = self.__loadV2Tag(f);
+         if padding >= 0:
+            tagFound = 1;
+      elif v == ID3_ANY_VERSION:
+         padding = self.__loadV2Tag(f);
+         if padding >= 0:
+            tagFound = 1;
+         else:
+            padding = 0;
+            if self.__loadV1Tag(f):
+               tagFound = 1;
+
+      self.linkedFile = LinkedFile(fileName);
+      if tagFound:
+         # In the case of a v1.x tag this is zero.
+         self.linkedFile.tagSize = self.header.tagSize;
+         self.linkedFile.tagPadding = padding;
+         return 1;
+      else:
+         self.linkedFile.tagSize = 0;
+         self.linkedFile.tagPadding = 0;
+         return 0;
+
+   # Write the current tag state to the linked file.
+   # The version of the ID3 file format that should be written can
+   # be passed as an argument; the default is ID3_CURRENT_VERSION.
+   def update(self, version = ID3_CURRENT_VERSION, backup = 0):
+      if not self.linkedFile:
+         raise TagException("The Tag is not linked to a file.");
+
+      if backup:
+         shutil.copyfile(self.linkedFile.name, self.linkedFile.name + ".orig");
+
+      self.setVersion(version);
+      version = self.getVersion();
+      # If v1.0 is being for explicitly then so be it, if not and there is
+      # a track number then bumping to v1.1 is /probably/ best.
+      if self.header.majorVersion == 1 and self.header.minorVersion == 0 and\
+         self.getTrackNum()[0] != None and version != ID3_V1_0:
+         version = ID3_V1_1;
+         self.setVersion(version);
+      
+      # If there are no frames then simply remove the current tag.
+      if len(self.frames) == 0:
+         self.remove(version);
+         self.header = TagHeader();
+         self.frames.setTagHeader(self.header);
+         self.linkedFile.tagPadding = 0;
+         self.linkedFile.tagSize = 0;
+         return;
+
+      if version & ID3_V1:
+         self.__saveV1Tag(version);
+         return 1;
+      elif version & ID3_V2:
+         self.__saveV2Tag(version);
+         return 1;
+      else:
+         raise TagException("Invalid version: %s" % hex(version));
+      return 0;
+
+   # Remove the tag.  The version argument can selectively remove specific
+   # ID3 tag versions; the default is ID3_CURRENT_VERSION meaning the version
+   # of the current tag.  A value of ID3_ANY_VERSION causes all tags to be
+   # removed.
+   def remove(self, version = ID3_CURRENT_VERSION):
+      if not self.linkedFile:
+         raise TagException("The Tag is not linked to a file; nothing to "\
+                            "remove.");
+
+      if version == ID3_CURRENT_VERSION:
+         version = self.getVersion();
+
+      retval = 0;   
+      if version & ID3_V1 or version == ID3_ANY_VERSION:
+         tagFile = file(self.linkedFile.name, "r+b");
+         tagFile.seek(-128, 2);
+         if tagFile.read(3) == "TAG":
+            TRACE_MSG("Removing ID3 v1.x Tag");
+            tagFile.seek(-3, 1);
+            tagFile.truncate();
+            retval |= 1;
+         tagFile.close();
+
+      if ((version & ID3_V2) or (version == ID3_ANY_VERSION)) and\
+          self.header.tagSize:
+         tagFile = file(self.linkedFile.name, "r+b");
+         if tagFile.read(3) == "ID3":
+            TRACE_MSG("Removing ID3 v2.x Tag");
+            tagSize = self.header.tagSize + self.header.SIZE;
+            tagFile.seek(tagSize);
+            data = tagFile.read();
+            tagFile.seek(0);
+            tagFile.write(data);
+            tagFile.truncate();
+            tagFile.close();
+            retval |= 1;
+
+      return retval;
+
+
+
+   # Get artist.  There are a few frames that can contain this information,
+   # and they are subtley different. 
+   #   eyeD3.frames.ARTIST_FID - Lead performer(s)/Soloist(s)
+   #   eyeD3.frames.BAND_FID - Band/orchestra/accompaniment
+   #   eyeD3.frames.CONDUCTOR_FID - Conductor/performer refinement
+   #   eyeD3.frames.REMIXER_FID - Interpreted, remixed, or otherwise modified by
+   #
+   # Any of these values can be passed as an argument to select the artist
+   # of interest.  By default, the first one found (searched in the above order)
+   # is the value returned.  Most tags only have the ARTIST_FID, btw.
+   # 
+   # When no artist is found, an empty string is returned.
+   # 
+   def getArtist(self, artistID = ARTIST_FIDS):
+      if isinstance(artistID, list):
+         frameIDs = artistID;
+      else:
+         frameIDs = [artistID];
+
+      for fid in frameIDs:
+         f = self.frames[fid];
+         if f:
+            return f[0].text;
+      return ""; 
+ 
+   def getAlbum(self):
+      f = self.frames[ALBUM_FID];
+      if f:
+         return f[0].text;
+      else:
+         return "";
+
+   # Get the track title.  By default the main title is returned.  Optionally,
+   # you can pass:
+   #   eyeD3.frames.TITLE_FID - The title; the default.
+   #   eyeD3.frames.SUBTITLE_FID - The subtitle.
+   #   eyeD3.frames.CONTENT_TITLE_FID - Conten group description???? Rare.
+   # An empty string is returned when no title exists.
+   def getTitle(self, titleID = TITLE_FID):
+      f = self.frames[titleID];
+      if f:
+         return f[0].text;
+      else:
+         return "";
+
+   def getDate(self, fid = None):
+       if not fid:
+           for fid in ["TDRL", "TDOR", "TDRC",
+                       OBSOLETE_YEAR_FID, OBSOLETE_DATE_FID]:
+               if self.frames[fid]:
+                   return self.frames[fid];
+           return None;
+       return self.frames[fid];
+
+   def getYear(self, fid = None):
+       dateFrame = self.getDate(fid);
+       if dateFrame:
+           return dateFrame[0].getYear();
+       else:
+           return None;
+            
+   # Throws GenreException when the tag contains an unrecognized genre format.
+   # Note this method returns a eyeD3.Genre object, not a raw string.
+   def getGenre(self):
+      f = self.frames[GENRE_FID];
+      if f and f[0].text:
+         g = Genre();
+         g.parse(f[0].text);
+         return g;
+      else:
+         return None;
+
+   # Returns a tuple with the first value containing the track number and the
+   # second the total number of tracks.  One or both of these values may be
+   # None depending on what is available in the tag. 
+   def getTrackNum(self):
+      f = self.frames[TRACKNUM_FID];
+      if f:
+         n = string.split(f[0].text, '/');
+         tn = self.toInt(n[0]);
+         tt = None;
+         if len(n) == 2:
+            tt = self.toInt(n[1]);
+         if tn != None and tt != None:
+            return (tn, tt);
+         elif tn != None:
+            return (tn, None);
+      return (None, None);
+
+   # Since multiple comment frames are allowed this returns a list with 0
+   # or more elements.  The elements are not the comment strings, they are
+   # eyeD3.frames.CommentFrame objects.
+   def getComments(self):
+      return self.frames[COMMENT_FID];
+
+   # Returns a list (possibly empty) of eyeD3.frames.ImageFrame objects.
+   def getImages(self):
+      return self.frames[IMAGE_FID];
+
+   # Returns a list (possibly empty) of eyeD3.frames.URLFrame objects.
+   # Both URLFrame and UserURLFrame objects are returned.  UserURLFrames
+   # add a description and encoding, and have a different frame ID.
+   def getURLs(self):
+      urls = list();
+      for fid in URL_FIDS:
+         urls.extend(self.frames[fid]);
+      urls.extend(self.frames[USERURL_FID]);
+      return urls;
+
+   def getUserTextFrames(self):
+      return self.frames[USERTEXT_FID];
+
+   def getCDID(self):
+      return self.frames[CDID_FID];
+
+   def getVersion(self):
+      return self.header.version;
+
+   def getVersionStr(self):
+      return versionToString(self.header.version);
+
+   # Set the artist name.  Arguments equal to None or "" cause the frame to
+   # be removed. An optional second argument can be passed to select the
+   # actual artist frame that should be set.  By default, the main artist frame
+   # (TPE1) is the value used.
+   def setArtist(self, a, id = ARTIST_FID):
+       self.setTextFrame(id, a);
+
+   def setAlbum(self, a):
+       self.setTextFrame(ALBUM_FID, a);
+
+   def setTitle(self, t, titleID = TITLE_FID):
+       self.setTextFrame(titleID, t);
+
+   def setDate(self, year, month = None, dayOfMonth = None,
+               hour = None, minute = None, second = None, fid = None):
+      if not year and not fid:
+          dateFrame = self.getDate;
+          self.frames.removeFramesByID(dateFrame.id);
+          return;
+      elif not year:
+          self.frames.removeFramesByID(fid);
+
+      dateStr = str(year);
+      if len(dateStr) != 4:
+         raise TagException("Invalid Year field: " + dateStr);
+      if month:
+         dateStr += "-" + self.__padDateField(month);
+         if dayOfMonth:
+            dateStr += "-" + self.__padDateField(dayOfMonth);
+            if hour:
+               dateStr += "T" + self.__padDateField(hour);
+               if minute:
+                  dateStr += ":" + self.__padDateField(minute);
+                  if second:
+                     dateStr += ":" + self.__padDateField(second);
+
+      if not fid:
+          fid = "TDRL";
+      dateFrame = self.frames[fid];
+      try:
+         if dateFrame:
+            dateFrame[0].setDate(self.encoding + dateStr);
+         else:
+            header = FrameHeader(self.header);
+            header.id = fid;
+            dateFrame = DateFrame(self.encoding + dateStr, header);
+            self.frames.addFrame(dateFrame);
+      except FrameException, ex:
+         raise TagException(str(ex));
+
+   # Three types are accepted for the genre parameter.  A Genre object, an
+   # acceptable (see Genre.parse) genre string, or an integer genre id.
+   # Arguments equal to None or "" cause the frame to be removed.
+   def setGenre(self, g):
+      if g == None or g == "":
+         self.frames.removeFramesByID(GENRE_FID);
+         return;
+
+      if isinstance(g, Genre):
+         self.frames.setTextFrame(GENRE_FID, str(g), self.encoding);
+      elif isinstance(g, str):
+         gObj = Genre();
+         gObj.parse(g);
+         self.frames.setTextFrame(GENRE_FID, str(gObj), self.encoding);
+      elif isinstance(g, int):
+         gObj = Genre();
+         gObj.id = g;
+         self.frames.setTextFrame(GENRE_FID, str(gObj), self.encoding);
+      else:
+         raise TagException("Invalid type passed to setGenre: %s" +
+                            str(type(g)));
+
+   # Accepts a tuple with the first value containing the track number and the
+   # second the total number of tracks.  One or both of these values may be
+   # None.  If both values are None, the frame is removed.
+   def setTrackNum(self, n):
+      if n[0] == None and n[1] == None:
+         self.frames.removeFramesByID(TRACKNUM_FID);
+         return;
+
+      totalStr = "";
+      zPadding = 1;
+      if n[1] != None:
+         if n[1] >= 0 and n[1] <= 9:
+            totalStr = "0" + str(n[1]);
+         else:
+            totalStr = str(n[1]);
+         zPadding = len(totalStr) - 1;
+
+      t = n[0];
+      if t == None:
+         t = 0;
+
+      # Pad with zeros according to how large the total count is.
+      trackStr = str(t);
+      if len(trackStr) == 1:
+         trackStr = "0" + trackStr;
+      if len(trackStr) < len(totalStr):
+         trackStr = ("0" * (len(totalStr) - len(trackStr))) + trackStr;
+
+      s = "";
+      if trackStr and totalStr:
+         s = trackStr + "/" + totalStr;
+      elif trackStr and not totalStr:
+         s = trackStr;
+
+      self.frames.setTextFrame(TRACKNUM_FID, s, self.encoding);
+
+   # Add a comment.  This adds a comment unless one is already present with
+   # the same language and description in which case the current value is
+   # either changed (cmt evalues true) or removed (cmt equals "" or None).
+   def addComment(self, cmt, desc = "", lang = DEFAULT_LANG):
+      if not cmt:
+         # A little more then a call to removeFramesByID is involved since we
+         # need to look at more than the frame ID.
+         comments = self.frames[COMMENT_FID];
+         for c in comments:
+            if c.lang == lang and c.description == desc:
+               self.frames.remove(c);
+               break;
+      else:
+         self.frames.setCommentFrame(cmt, desc, lang, self.encoding);
+
+   def removeComments(self):
+       return self.frames.removeFramesByID(COMMENT_FID);
+
+   def addImage(self, type, image_file_path, desc = u""):
+       image_frame = ImageFrame.create(type, image_file_path, desc);
+       self.frames.addFrame(image_frame);
+
+   # Test ID3 major version.
+   def isV1(self):
+      return self.header.majorVersion == 1;
+   def isV2(self):
+      return self.header.majorVersion == 2;
+
+   def setVersion(self, v):
+      if v == ID3_V1:
+         v = ID3_V1_1;
+      elif v == ID3_V2:
+         v = ID3_DEFAULT_VERSION;
+
+      if v != ID3_CURRENT_VERSION:
+         self.header.setVersion(v);
+         self.frames.setTagHeader(self.header);
+   
+   def setTextFrame(self, fid, txt):
+       if not txt:
+          self.frames.removeFramesByID(fid);
+       else:
+          self.frames.setTextFrame(fid, txt, self.encoding);
+
+   def __saveV1Tag(self, version):
+      assert(version & ID3_V1);
+
+      # Build tag buffer.
+      tag = "TAG";
+      tag += self.fixToWidth(self.getTitle().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getArtist().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getAlbum().encode("latin_1"), 30);
+      tag += self.fixToWidth(self.getYear().encode("latin_1"), 4);
+
+      cmt = "";
+      for c in self.getComments():
+         if c.description == ID3_V1_COMMENT_DESC:
+            cmt = c.comment;
+            # We prefer this one over "";
+            break; 
+         elif c.description == "":
+            cmt = c.comment;
+            # Keep searching in case we find the description eyeD3 uses.
+      cmt = self.fixToWidth(cmt, 30);
+      if version != ID3_V1_0:
+         track = self.getTrackNum()[0];
+         if track != None:
+            cmt = cmt[0:28] + "\x00" + chr(int(track) & 0xff);
+      tag += cmt;
+
+      if not self.getGenre():
+         genre = 0;
+      else:
+         genre = self.getGenre().getId();
+      tag += chr(genre & 0xff);
+
+      assert(len(tag) == 128);
+
+      tagFile = file(self.linkedFile.name, "r+b");
+      # Write the tag over top an original or append it.
+      try:
+         tagFile.seek(-128, 2);
+         if tagFile.read(3) == "TAG":
+            tagFile.seek(-128, 2);
+         else:
+            tagFile.seek(0, 2);
+      except IOError:
+         # File is smaller than 128 bytes.
+         tagFile.seek(0, 2);
+
+      tagFile.write(tag);
+      tagFile.flush();
+      tagFile.close();
+      
+   def fixToWidth(self, s, n):
+      retval = str(s);
+      retval = retval[0:n];
+      retval = retval + ("\x00" * (n - len(retval)));
+      return retval;
+
+   # Returns false when an ID3 v1 tag is not present, or contains no data.
+   def __loadV1Tag(self, f):
+      if isinstance(f, str):
+         fp = file(f, "rb")
+         closeFile = 1;
+      else:
+         fp = f;
+         closeFile = 0;
+
+      # Seek to the end of the file where all ID3v1 tags are written.
+      fp.seek(0, 2);
+      if fp.tell() > 127:
+         fp.seek(-128, 2);
+         id3tag = fp.read(128);
+         if id3tag[0:3] == "TAG":
+            TRACE_MSG("Located ID3 v1 tag");
+            # 1.0 is implied until a 1.1 feature is recognized.
+            self.setVersion(ID3_V1_0);
+
+            title = re.sub("\x00+$", "", id3tag[3:33].strip());
+            TRACE_MSG("Tite: " + title);
+            if title:
+               self.setTitle(title);
+
+            artist = re.sub("\x00+$", "", id3tag[33:63].strip());
+            TRACE_MSG("Artist: " + artist);
+            if artist:
+               self.setArtist(artist);
+
+            album = re.sub("\x00+$", "", id3tag[63:93].strip());
+            TRACE_MSG("Album: " + album);
+            if album:
+               self.setAlbum(album);
+
+            year = re.sub("\x00+$", "", id3tag[93:97].strip());
+            TRACE_MSG("Year: " + year);
+            try:
+               if year and int(year):
+                  self.setDate(year);
+            except ValueError:
+               # Bogus year strings.
+               pass;
+
+	    if re.sub("\x00+$", "", id3tag[97:127]):
+	       comment = id3tag[97:127];
+               TRACE_MSG("Comment: " + comment);
+               if comment[-2] == "\x00" and comment[-1] != "\x00":
+                  # Parse track number (added to ID3v1.1) if present.
+                  TRACE_MSG("Comment contains track number per v1.1 spec");
+                  track = ord(comment[-1]);
+                  self.setTrackNum((track, None));
+                  TRACE_MSG("Track: " + str(track));
+                  TRACE_MSG("Track Num found, setting version to v1.1s");
+                  self.setVersion(ID3_V1_1);
+		  comment = comment[:-2];
+               else:
+                  track = None
+               comment = re.sub("\x00+$", "", comment).rstrip();
+               TRACE_MSG("Comment: " + comment);
+               if comment:
+                  self.addComment(comment, ID3_V1_COMMENT_DESC);
+
+            genre = ord(id3tag[127:128])
+            TRACE_MSG("Genre ID: " + str(genre));
+            self.setGenre(genre);
+
+      if closeFile:
+         fp.close()
+      return len(self.frames);
+
+   def __saveV2Tag(self, version):
+      assert(version & ID3_V2);
+      TRACE_MSG("Rendering tag version: " + versionToString(version));
+
+      self.setVersion(version);
+
+      currPadding = 0;
+      currTagSize = 0
+      if currTagSize == 0:
+         # We may be converting from 1.x to 2.x so we need to find any
+         # current v2.x tag otherwise we're gonna hork the file.
+         tmpTag = Tag();
+         if tmpTag.link(self.linkedFile.name, ID3_V2):
+            TRACE_MSG("Found current v2.x tag:");
+            currTagSize = tmpTag.linkedFile.tagSize;
+            TRACE_MSG("Current tag size: %d" % currTagSize);
+            currPadding = tmpTag.linkedFile.tagPadding;
+            TRACE_MSG("Current tag padding: %d" % currPadding);
+
+      # Tag it!
+      if self.header.minorVersion == 4:
+          h = FrameHeader(self.header);
+          h.id = "TDTG";
+          dateFrame = DateFrame(self.encoding +\
+                                time.strftime("%Y-%m-%dT%H:%M:%S"), h);
+          self.frames.removeFramesByID("TDTG");
+          self.frames.addFrame(dateFrame);
+
+      # Render all frames first so the data size is known for the tag header.
+      frameData = "";
+      for f in self.frames:
+         TRACE_MSG("Rendering frame: " + f.header.id);
+         raw_frame = f.render();
+         TRACE_MSG("Rendered %d bytes" % len(raw_frame));
+         frameData += raw_frame;
+
+      TRACE_MSG("Rendered tag size: " + str(len(frameData)));
+
+      rewriteFile = 0;
+      paddingSize = 0;
+      headerData = "";
+
+      # Extended header
+      if self.header.extended:
+         # This is sorta lame.  We don't know the total framesize until
+         # this is rendered, yet we can't render it witout knowing the
+         # amount of padding.  Force it.
+         rewriteFile = 1;
+         paddingSize = 2048;
+         TRACE_MSG("Rendering extended header");
+         headerData += self.extendedHeader.render(self.header, frameData,
+                                                  paddingSize);
+
+      if rewriteFile or (10 + len(headerData) + len(frameData)) >= currTagSize:
+         TRACE_MSG("File rewrite required");
+         rewriteFile = 1;
+         paddingSize = 2048;
+      else:
+         paddingSize = currTagSize - (len(headerData) + len(frameData));
+      frameData += ("\x00" * paddingSize);
+
+      # Render the tag header.
+      TRACE_MSG("Rendering %s tag header with size %d" %\
+                (versionToString(self.getVersion()), len(frameData)));
+      headerData = self.header.render(len(frameData));
+
+      # Assemble frame.
+      tagData = headerData + frameData;
+
+      # Write the tag.
+      if not rewriteFile:
+         tagFile = file(self.linkedFile.name, "r+b");
+         TRACE_MSG("Writing %d bytes of tag data" % len(tagData));
+         tagFile.write(tagData);
+         tagFile.close();
+      else:
+         # Open original
+         tagFile = file(self.linkedFile.name, "rb");
+         # Read all audio data
+         tagFile.seek(currTagSize);
+         audioData = tagFile.read();
+         tagFile.close();
+
+         # Open tmp file
+         tmpName = tempfile.mktemp();
+         tmpFile = file(tmpName, "w+b");
+         TRACE_MSG("Writing %d bytes of tag data" % len(tagData));
+         tmpFile.write(tagData);
+         tmpFile.write(audioData);
+         tmpFile.close();
+
+         # Move tmp to orig.
+         shutil.copyfile(tmpName, self.linkedFile.name);
+         os.unlink(tmpName);
+
+      # Update our state.
+      TRACE_MSG("Tag write complete.  Updating state.");
+      self.linkedFile.tagPadding = paddingSize;
+      # XXX: getSize could cache sizes so to prevent rendering again.
+      self.linkedFile.tagSize = self.frames.getSize();
+
+
+   # Returns >= 0 to indicate the padding size of the read frame; -1 returned
+   # when not tag was found.
+   def __loadV2Tag(self, f):
+      if isinstance(f, str):
+         fp = file(f, "rb")
+         closeFile = 1;
+      else:
+         fp = f;
+         closeFile = 0;
+
+      padding = -1;
+      try:
+         # Look for a tag and if found load it.
+         if not self.header.parse(fp):
+            return -1;
+
+         # Read the extended header if present.
+         if self.header.extended:
+            self.extendedHeader.parse(fp, self.header);
+
+         # Header is definitely there so at least one frame *must* follow.
+         self.frames.setTagHeader(self.header);
+         padding = self.frames.parse(fp, self.header);
+         TRACE_MSG("Tag contains %d bytes of padding." % padding);
+      except FrameException, ex:
+         #fp.close();
+         #raise TagException(str(ex));
+         # Technically, it's not a well-formed MP3, but we can still get data out of it.
+         # it's better than crashing....
+         pass
+      except TagException:
+         fp.close();
+         raise;
+
+      if closeFile:
+         fp.close();
+      return padding;
+
+   def toInt(self, s):
+      try:
+         return int(s);
+      except ValueError:
+         return None;
+      except TypeError:
+         return None;
+
+   def __padDateField(self, f):
+      fStr = str(f);
+      if len(fStr) == 2:
+         pass;
+      elif len(fStr) == 1:
+         fStr = "0" + fStr;
+      else:
+         raise TagException("Invalid date field: " + fStr);
+      return fStr;
+
+   # DEPRECATED
+   # This method will return the first comment in the FrameSet
+   # and not all of them.  Multiple COMM frames are common and useful.  Use
+   # getComments which returns a list.
+   def getComment(self):
+      f = self.frames[COMMENT_FID];
+      if f:
+         return f[0].comment;
+      else:
+         return None;
+
+
+################################################################################
+class GenreException(Exception):
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+
+################################################################################
+class Genre:
+   id = None;
+   name = None;
+
+   def __init__(self):
+      pass;
+
+   def getId(self):
+      return self.id;
+   def getName(self):
+      return self.name;
+
+   # Sets the genre id.  The objects name field is set to the corresponding
+   # value obtained from eyeD3.genres.
+   #
+   # Throws GenreException when name does not map to a valid ID3 v1.1. id.
+   # This behavior can be disabled by passing 0 as the second argument.
+   def setId(self, id, verify = 1):
+      if not isinstance(id, int):
+         raise TypeError("Invalid genre id: " + str(id));
+
+      try:
+         name = genres[id];
+      except Exception, ex:
+         if verify:
+            raise GenreException("Invalid genre id: " + str(id));
+
+      if verify and not name:
+         raise GenreException("Genre id maps to a null name: " + str(id));
+
+      self.id = id;
+      self.name = name;
+
+   # Sets the genre name.  The objects id field is set to the corresponding
+   # value obtained from eyeD3.genres.
+   #
+   # Throws GenreException when name does not map to a valid ID3 v1.1. name.
+   # This behavior can be disabled by passing 0 as the second argument.
+   def setName(self, name, verify = 1):
+      if not isinstance(name, str):
+         raise GenreException("Invalid genre name: " + str(name));
+
+      try:
+         id = genres[name];
+         # Get titled case.
+         name = genres[id];
+      except:
+         if verify:
+            raise GenreException("Invalid genre name: " + name);
+
+      self.id = id;
+      self.name = name;
+
+
+   # Sets the genre id and name. 
+   #
+   # Throws GenreException when eyeD3.genres[id] != name (case insensitive). 
+   # This behavior can be disabled by passing 0 as the second argument.
+   def set(self, id, name, verify = 1):
+      if not isinstance(id, int):
+         raise GenreException("Invalid genre id: " + id);
+      if not isinstance(name, str):
+         raise GenreException("Invalid genre name: " + str(name));
+
+      if not verify:
+         self.id = id;
+         self.name = name;
+      else:
+         try:
+            if genres[name] != id:
+               raise GenreException("eyeD3.genres[" + str(id) + "] " +\
+                                    "does not match " + name);
+            self.id = id;
+            self.name = name;
+         except:
+            raise GenreException("eyeD3.genres[" + str(id) + "] " +\
+                                 "does not match " + name);
+      
+   # Parses genre information from genreStr. 
+   # The following formats are supported:
+   # 01, 2, 23, 125 - ID3 v1 style.
+   # (01), (2), (129)Hardcore, (9)Metal - ID3 v2 style with and without
+   #                                      refinement.
+   #
+   # Throws GenreException when an invalid string is passed.
+   def parse(self, genreStr, verify = 1):
+      genreStr = str(genreStr.encode('utf-8')).strip();
+      self.id = None;
+      self.name = None;
+
+      if not genreStr:
+         return;
+
+      # XXX: Utf-16 conversions leave a null byte at the end of the string.
+      while genreStr[len(genreStr) - 1] == "\x00":
+         genreStr = genreStr[:len(genreStr) - 1];
+
+      # ID3 v1 style.
+      # Match 03, 34, 129.
+      regex = re.compile("[0-9][0-9]?[0-9]?$");
+      if regex.match(genreStr):
+         if len(genreStr) != 1 and genreStr[0] == '0':
+            genreStr = genreStr[1:];
+
+         self.setId(int(genreStr), verify);
+         return;
+
+      # ID3 v2 style.
+      # Match (03), (0)Blues, (15) Rap
+      regex = re.compile("\(([0-9][0-9]?[0-9]?)\)(.*)$");
+      m = regex.match(genreStr);
+      if m:
+         (id, name) = m.groups();
+         if len(id) != 1 and id[0] == '0':
+            id = id[1:];
+            
+         if id and name:
+            self.set(int(id), name.strip(), verify);
+         else:
+            self.setId(int(id), verify);
+         return;
+
+      # Non standard, but witnessed.
+      # Match genreName alone.  e.g. Rap, Rock, blues.
+      regex = re.compile("^[A-Z 0-9+/\-&]+\00*$", re.IGNORECASE);
+      if regex.match(genreStr):
+         self.setName(genreStr, verify);
+         return;
+      else:
+          print regex.pattern;
+      raise GenreException("Genre string cannot be parsed: " + genreStr);
+
+   def __str__(self):
+      s = "";
+      if self.id != None:
+         s += "(" + str(self.id) + ")"
+      if self.name:
+         s += self.name;
+      return s;
+
+################################################################################
+class InvalidAudioFormatException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class Mp3AudioFile:
+   fileName       = str();
+   fileSize       = int();
+   header         = eyeD3_mp3.Header();
+   xingHeader     = None;
+   tag            = Tag();
+   invalidFileExc = InvalidAudioFormatException("File is not mp3");
+   # Number of seconds required to play the audio file.
+   playTime       = None;
+
+   def __init__(self, fileName, tagVersion = ID3_ANY_VERSION):
+      self.playTime = None;
+      self.fileName = fileName;
+
+#      if not isMp3File(fileName):
+#         raise self.invalidFileExc;
+
+      # Parse ID3 tag.
+      f = file(fileName, "rb");
+      tag = Tag();
+      hasTag = tag.link(f, tagVersion);
+      # Find the first mp3 frame.
+      if tag.isV1():
+         framePos = 0;
+      elif not hasTag:
+         framePos = 0;
+         tag = None;
+      else:
+         # XXX: Note that v2.4 allows for appended tags; account for that.
+         framePos = tag.header.SIZE + tag.header.tagSize;
+      f.seek(framePos);
+      bString = f.read(4);
+      if len(bString) < 4:
+         raise InvalidAudioFormatException("Unable to find a valid mp3 "\
+                                           "frame");
+      frameHead = bin2dec(bytes2bin(bString));
+      header = eyeD3_mp3.Header();
+      # Keep reading until we find a valid mp3 frame header.
+      while not header.isValid(frameHead):
+         frameHead <<= 8;
+         bString = f.read(1);
+         if len(bString) != 1:
+            raise InvalidAudioFormatException("Unable to find a valid mp3 "\
+                                              "frame");
+         frameHead |= ord(bString[0]);
+      TRACE_MSG("mp3 header %x found at position: %d (0x%x)" % \
+                (frameHead, f.tell() - 4, f.tell() - 4));
+
+      # Decode the header.
+      try:
+         header.decode(frameHead);
+         # Check for Xing header inforamtion which will always be in the
+         # first "null" frame.
+         f.seek(-4, 1);
+         mp3Frame = f.read(header.frameLength);
+         if mp3Frame.find("Xing") != -1:
+            xingHeader = eyeD3_mp3.XingHeader();
+            if not xingHeader.decode(mp3Frame):
+               raise InvalidAudioFormatException("Corrupt Xing header");
+         else:
+            xingHeader = None;
+      except eyeD3_mp3.Mp3Exception, ex:
+         raise InvalidAudioFormatException(str(ex));
+
+      # Compute track play time.
+      tpf = eyeD3_mp3.computeTimePerFrame(header);
+      if xingHeader:
+         self.playTime = int(tpf * xingHeader.numFrames);
+      else:
+         length = self.getSize();
+         if tag and tag.isV2():
+            length -= tag.header.SIZE + tag.header.tagSize;
+            # Handle the case where there is a v2 tag and a v1 tag.
+            f.seek(-128, 2)
+            if f.read(3) == "TAG":
+               length -= 128;
+         elif tag and tag.isV1():
+            length -= 128;
+         self.playTime = int((length / header.frameLength) * tpf);    
+
+      self.header = header;
+      self.xingHeader = xingHeader;
+      self.tag = tag;
+      f.close();
+
+   def getTag(self):
+      return self.tag;
+
+   def getSize(self):
+      if not self.fileSize:
+         self.fileSize = os.stat(self.fileName)[ST_SIZE];
+      return self.fileSize;
+
+   def getPlayTime(self):
+      return self.playTime;
+
+   def getPlayTimeString(self):
+      total = self.getPlayTime();
+      h = total / 3600;
+      m = (total % 3600) / 60;
+      s = (total % 3600) % 60;
+      if h:
+         timeStr = "%d:%.2d:%.2d" % (h, m, s);
+      else:
+         timeStr = "%d:%.2d" % (m, s);
+      return timeStr;
+
+   # Returns a tuple.  The first value is a boolean which if true means the
+   # bit rate returned in the second value is variable.
+   def getBitRate(self):
+      xHead = self.xingHeader;
+      if xHead:
+         tpf = eyeD3_mp3.computeTimePerFrame(self.header);
+         br = int((xHead.numBytes * 8) / (tpf * xHead.numFrames * 1000));
+         vbr = 1;
+      else:
+         br = self.header.bitRate;
+         vbr = 0;
+      return (vbr, br);
+
+   def getBitRateString(self):
+      (vbr, bitRate) = self.getBitRate();
+      brs = "%d kb/s" % bitRate;
+      if vbr:
+         brs = "~" + brs;
+      return brs;
+
+################################################################################
+def isMp3File(fileName):
+    (type, enc) = mimetypes.guess_type(fileName);
+    return type == "audio/mpeg";
+
+################################################################################
+class GenreMap(list):
+
+   #######################################################################
+   # Accepts both int and string keys. Throws IndexError and TypeError.
+   def __getitem__(self, key):
+      if isinstance(key, int):
+         if key >= 0 and key < len(self):
+            v = list.__getitem__(self, key);
+            if v:
+               return v;
+            else:
+               return None;
+         else:
+            raise IndexError("genre index out of range");
+      elif isinstance(key, str):
+         if self.reverseDict.has_key(key.lower()):
+            return self.reverseDict[key.lower()];
+         else:
+            raise IndexError(key + " genre not found");
+      else:
+         raise TypeError("genre key must be type int or string");
+
+   def __init__(self):
+      self.data = []
+      self.reverseDict = {}
+      # ID3 genres as defined by the v1.1 spec with WinAmp extensions.
+      self.append('Blues');
+      self.append('Classic Rock');
+      self.append('Country');
+      self.append('Dance');
+      self.append('Disco');
+      self.append('Funk');
+      self.append('Grunge');
+      self.append('Hip-Hop');
+      self.append('Jazz');
+      self.append('Metal');
+      self.append('New Age');
+      self.append('Oldies');
+      self.append('Other');
+      self.append('Pop');
+      self.append('R&B');
+      self.append('Rap');
+      self.append('Reggae');
+      self.append('Rock');
+      self.append('Techno');
+      self.append('Industrial');
+      self.append('Alternative');
+      self.append('Ska');
+      self.append('Death Metal');
+      self.append('Pranks');
+      self.append('Soundtrack');
+      self.append('Euro-Techno');
+      self.append('Ambient');
+      self.append('Trip-Hop');
+      self.append('Vocal');
+      self.append('Jazz+Funk');
+      self.append('Fusion');
+      self.append('Trance');
+      self.append('Classical');
+      self.append('Instrumental');
+      self.append('Acid');
+      self.append('House');
+      self.append('Game');
+      self.append('Sound Clip');
+      self.append('Gospel');
+      self.append('Noise');
+      self.append('AlternRock');
+      self.append('Bass');
+      self.append('Soul');
+      self.append('Punk');
+      self.append('Space');
+      self.append('Meditative');
+      self.append('Instrumental Pop');
+      self.append('Instrumental Rock');
+      self.append('Ethnic');
+      self.append('Gothic');
+      self.append('Darkwave');
+      self.append('Techno-Industrial');
+      self.append('Electronic');
+      self.append('Pop-Folk');
+      self.append('Eurodance');
+      self.append('Dream');
+      self.append('Southern Rock');
+      self.append('Comedy');
+      self.append('Cult');
+      self.append('Gangsta Rap');
+      self.append('Top 40');
+      self.append('Christian Rap');
+      self.append('Pop / Funk');
+      self.append('Jungle');
+      self.append('Native American');
+      self.append('Cabaret');
+      self.append('New Wave');
+      self.append('Psychedelic');
+      self.append('Rave');
+      self.append('Showtunes');
+      self.append('Trailer');
+      self.append('Lo-Fi');
+      self.append('Tribal');
+      self.append('Acid Punk');
+      self.append('Acid Jazz');
+      self.append('Polka');
+      self.append('Retro');
+      self.append('Musical');
+      self.append('Rock & Roll');
+      self.append('Hard Rock');
+      self.append('Folk');
+      self.append('Folk-Rock');
+      self.append('National Folk');
+      self.append('Swing');
+      self.append('Fast  Fusion');
+      self.append('Bebob');
+      self.append('Latin');
+      self.append('Revival');
+      self.append('Celtic');
+      self.append('Bluegrass');
+      self.append('Avantgarde');
+      self.append('Gothic Rock');
+      self.append('Progressive Rock');
+      self.append('Psychedelic Rock');
+      self.append('Symphonic Rock');
+      self.append('Slow Rock');
+      self.append('Big Band');
+      self.append('Chorus');
+      self.append('Easy Listening');
+      self.append('Acoustic');
+      self.append('Humour');
+      self.append('Speech');
+      self.append('Chanson');
+      self.append('Opera');
+      self.append('Chamber Music');
+      self.append('Sonata');
+      self.append('Symphony');
+      self.append('Booty Bass');
+      self.append('Primus');
+      self.append('Porn Groove');
+      self.append('Satire');
+      self.append('Slow Jam');
+      self.append('Club');
+      self.append('Tango');
+      self.append('Samba');
+      self.append('Folklore');
+      self.append('Ballad');
+      self.append('Power Ballad');
+      self.append('Rhythmic Soul');
+      self.append('Freestyle');
+      self.append('Duet');
+      self.append('Punk Rock');
+      self.append('Drum Solo');
+      self.append('A Cappella');
+      self.append('Euro-House');
+      self.append('Dance Hall');
+      self.append('Goa');
+      self.append('Drum & Bass');
+      self.append('Club-House');
+      self.append('Hardcore');
+      self.append('Terror');
+      self.append('Indie');
+      self.append('BritPop');
+      self.append('Negerpunk');
+      self.append('Polsk Punk');
+      self.append('Beat');
+      self.append('Christian Gangsta Rap');
+      self.append('Heavy Metal');
+      self.append('Black Metal');
+      self.append('Crossover');
+      self.append('Contemporary Christian');
+      self.append('Christian Rock');
+      self.append('Merengue');
+      self.append('Salsa');
+      self.append('Thrash Metal');
+      self.append('Anime');
+      self.append('JPop');
+      self.append('Synthpop');
+
+      # Pad up to 255 with "Unknown"
+      count = len(self);
+      while count < 256:
+         self.append("Unknown");
+         count += 1;
+      
+      for index in range(len(self)):
+         if self[index]:
+	    self.reverseDict[string.lower(self[index])] = index
+class LinkedFile:
+   name = "";
+   tagPadding = 0;
+   tagSize = 0;  # This includes the padding byte count.
+
+   def __init__(self, fileName):
+      self.name = fileName;
+
+def tagToUserTune(tag):
+    audio_file = None;
+    if isinstance(tag, Mp3AudioFile):
+        audio_file = tag;
+        tag = audio_file.getTag();
+        
+    tune =  "<tune xmlns='http://jabber.org/protocol/tune'>\n";
+    if tag.getArtist():
+        tune += "  <artist>" + tag.getArtist() + "</artist>\n";
+    if tag.getTitle():
+        tune += "  <title>" + tag.getTitle() + "</title>\n";
+    if tag.getAlbum():
+        tune += "  <source>" + tag.getAlbum() + "</source>\n";
+    tune += "  <track>" + "file://" + os.path.abspath(tag.linkedFile.name) +\
+            "</track>\n";
+    if audio_file:
+        # XXX: This should be an xs:duration
+        tune += "  <length>" + audio_file.getPlayTimeString() + "</length>\n";
+    tune += "</tune>\n";
+    return tune;
+
+#
+# Module level globals.
+#
+genres = GenreMap();
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/frames.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/frames.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/frames.py	(revision 4)
@@ -0,0 +1,1441 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#  Copyright (C) 2001  Ryan Finne <ryan@finnie.org>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+import os, os.path, re, zlib, StringIO, time, mimetypes;
+from StringIO import StringIO;
+from utils import *;
+from binfuncs import *;
+
+# Valid time stamp formats per ISO 8601 and used by time.strptime.
+timeStampFormats = ["%Y",
+                    "%Y-%m",
+                    "%Y-%m-%d",
+                    "%Y-%m-%dT%H",
+                    "%Y-%m-%dT%H:%M",
+                    "%Y-%m-%dT%H:%M:%S"];
+
+ARTIST_FID         = "TPE1";
+BAND_FID           = "TPE2";
+CONDUCTOR_FID      = "TPE3";
+REMIXER_FID        = "TPE4";
+COMPOSER_FID       = "TCOM";
+ARTIST_FIDS        = [ARTIST_FID, BAND_FID, CONDUCTOR_FID,
+                      REMIXER_FID, COMPOSER_FID];
+ALBUM_FID          = "TALB";
+TITLE_FID          = "TIT2";
+SUBTITLE_FID       = "TIT3";
+CONTENT_TITLE_FID  = "TIT1";
+TITLE_FIDS         = [TITLE_FID, SUBTITLE_FID, CONTENT_TITLE_FID];
+COMMENT_FID        = "COMM";
+GENRE_FID          = "TCON";
+TRACKNUM_FID       = "TRCK";
+USERTEXT_FID       = "TXXX";
+CDID_FID           = "MCDI";
+IMAGE_FID          = "APIC";
+URL_COMMERCIAL_FID = "WCOM";
+URL_COPYRIGHT_FID  = "WCOP";
+URL_AUDIOFILE_FID  = "WOAF";
+URL_ARTIST_FID     = "WOAR";
+URL_AUDIOSRC_FID   = "WOAS";
+URL_INET_RADIO_FID = "WORS";
+URL_PAYMENT_FID    = "WPAY";
+URL_PUBLISHER_FID  = "WPUB";
+URL_FIDS           = [URL_COMMERCIAL_FID, URL_COPYRIGHT_FID,
+                      URL_AUDIOFILE_FID, URL_ARTIST_FID, URL_AUDIOSRC_FID,
+                      URL_INET_RADIO_FID, URL_PAYMENT_FID,
+                      URL_PUBLISHER_FID];
+USERURL_FID        = "WXXX";
+
+obsoleteFrames = {"EQUA": "Equalisation",
+                  "IPLS": "Involved people list",
+                  "RVAD": "Relative volume adjustment",
+                  "TDAT": "Date",
+                  "TORY": "Original release year",
+                  "TRDA": "Recording dates",
+                  "TYER": "Year"};
+# Both of these are "coerced" into a v2.4 TDRC frame when read, and 
+# recreated when saving v2.3.
+OBSOLETE_DATE_FID            = "TDAT";
+OBSOLETE_YEAR_FID            = "TYER";
+OBSOLETE_TIME_FID            = "TIME";
+OBSOLETE_ORIG_RELEASE_FID    = "TORY";
+OBSOLETE_RECORDING_DATE_FID  = "TRDA";
+
+frameDesc = { "AENC": "Audio encryption",
+              "APIC": "Attached picture",
+              "ASPI": "Audio seek point index",
+
+              "COMM": "Comments",
+              "COMR": "Commercial frame",
+
+              "ENCR": "Encryption method registration",
+              "EQU2": "Equalisation (2)",
+              "ETCO": "Event timing codes",
+
+              "GEOB": "General encapsulated object",
+              "GRID": "Group identification registration",
+
+              "LINK": "Linked information",
+
+              "MCDI": "Music CD identifier",
+              "MLLT": "MPEG location lookup table",
+
+              "OWNE": "Ownership frame",
+
+              "PRIV": "Private frame",
+              "PCNT": "Play counter",
+              "POPM": "Popularimeter",
+              "POSS": "Position synchronisation frame",
+
+              "RBUF": "Recommended buffer size",
+              "RVA2": "Relative volume adjustment (2)",
+              "RVRB": "Reverb",
+
+              "SEEK": "Seek frame",
+              "SIGN": "Signature frame",
+              "SYLT": "Synchronised lyric/text",
+              "SYTC": "Synchronised tempo codes",
+
+              "TALB": "Album/Movie/Show title",
+              "TBPM": "BPM (beats per minute)",
+              "TCOM": "Composer",
+              "TCON": "Content type",
+              "TCOP": "Copyright message",
+              "TDEN": "Encoding time",
+              "TDLY": "Playlist delay",
+              "TDOR": "Original release time",
+              "TDRC": "Recording time",
+              "TDRL": "Release time",
+              "TDTG": "Tagging time",
+              "TENC": "Encoded by",
+              "TEXT": "Lyricist/Text writer",
+              "TFLT": "File type",
+              "TIPL": "Involved people list",
+              "TIT1": "Content group description",
+              "TIT2": "Title/songname/content description",
+              "TIT3": "Subtitle/Description refinement",
+              "TKEY": "Initial key",
+              "TLAN": "Language(s)",
+              "TLEN": "Length",
+              "TMCL": "Musician credits list",
+              "TMED": "Media type",
+              "TMOO": "Mood",
+              "TOAL": "Original album/movie/show title",
+              "TOFN": "Original filename",
+              "TOLY": "Original lyricist(s)/text writer(s)",
+              "TOPE": "Original artist(s)/performer(s)",
+              "TOWN": "File owner/licensee",
+              "TPE1": "Lead performer(s)/Soloist(s)",
+              "TPE2": "Band/orchestra/accompaniment",
+              "TPE3": "Conductor/performer refinement",
+              "TPE4": "Interpreted, remixed, or otherwise modified by",
+              "TPOS": "Part of a set",
+              "TPRO": "Produced notice",
+              "TPUB": "Publisher",
+              "TRCK": "Track number/Position in set",
+              "TRSN": "Internet radio station name",
+              "TRSO": "Internet radio station owner",
+              "TSOA": "Album sort order",
+              "TSOP": "Performer sort order",
+              "TSOT": "Title sort order",
+              "TSRC": "ISRC (international standard recording code)",
+              "TSSE": "Software/Hardware and settings used for encoding",
+              "TSST": "Set subtitle",
+              "TXXX": "User defined text information frame",
+
+              "UFID": "Unique file identifier",
+              "USER": "Terms of use",
+              "USLT": "Unsynchronised lyric/text transcription",
+
+              "WCOM": "Commercial information",
+              "WCOP": "Copyright/Legal information",
+              "WOAF": "Official audio file webpage",
+              "WOAR": "Official artist/performer webpage",
+              "WOAS": "Official audio source webpage",
+              "WORS": "Official Internet radio station homepage",
+              "WPAY": "Payment",
+              "WPUB": "Publishers official webpage",
+              "WXXX": "User defined URL link frame" };
+
+NULL_FRAME_FLAGS = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+TEXT_FRAME_RX = re.compile("^T[A-Z0-9][A-Z0-9][A-Z0-9]$");
+USERTEXT_FRAME_RX = re.compile("^" + USERTEXT_FID + "$");
+URL_FRAME_RX = re.compile("^W[A-Z0-9][A-Z0-9][A-Z0-9]$");
+USERURL_FRAME_RX = re.compile("^" + USERURL_FID + "$");
+COMMENT_FRAME_RX = re.compile("^" + COMMENT_FID + "$");
+CDID_FRAME_RX = re.compile("^" + CDID_FID + "$");
+IMAGE_FRAME_RX = re.compile("^" + IMAGE_FID + "$");
+
+LATIN1_ENCODING   = "\x00";
+UTF_16_ENCODING   = "\x01";
+UTF_16BE_ENCODING = "\x02";
+UTF_8_ENCODING    = "\x03";
+
+DEFAULT_ENCODING = LATIN1_ENCODING;
+DEFAULT_ID3_MAJOR_VERSION = 2;
+DEFAULT_ID3_MINOR_VERSION = 4;
+DEFAULT_LANG = "eng";
+
+def id3EncodingToString(encoding):
+    if encoding == LATIN1_ENCODING:
+        return "latin_1";
+    elif encoding == UTF_8_ENCODING:
+        return "utf_8";
+    elif encoding == UTF_16_ENCODING:
+        return "utf_16";
+    elif encoding == UTF_16BE_ENCODING:
+        return "utf_16_be";
+    else:
+        raise ValueError;
+
+################################################################################
+class FrameException:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+################################################################################
+class FrameHeader:
+   FRAME_HEADER_SIZE = 10;
+   # The tag header
+   majorVersion = DEFAULT_ID3_MAJOR_VERSION;
+   minorVersion = DEFAULT_ID3_MINOR_VERSION;
+   # The 4 character frame ID.
+   id = None;
+   # An array of 16 "bits"...
+   flags = NULL_FRAME_FLAGS;
+   # ...and the info they store.
+   tagAlter = 0;
+   fileAlter = 0;
+   readOnly = 0;
+   compressed = 0;
+   encrypted = 0;
+   grouped = 0;
+   unsync = 0;
+   dataLenIndicator = 0;
+   # The size of the data following this header.
+   dataSize = 0;
+
+   # 2.4 not only added flag bits, but also reordered the previously defined
+   # flags.  So these are mapped once we know the version.
+   TAG_ALTER   = None;   
+   FILE_ALTER  = None;   
+   READ_ONLY   = None;   
+   COMPRESSION = None;   
+   ENCRYPTION  = None;   
+   GROUPING    = None;   
+   UNSYNC      = None;   
+   DATA_LEN    = None;   
+
+   # Constructor.
+   def __init__(self, tagHeader = None):
+      if tagHeader:
+         self.setVersion(tagHeader);
+      else:
+         self.setVersion([DEFAULT_ID3_MAJOR_VERSION,
+                          DEFAULT_ID3_MINOR_VERSION]);
+
+   def setVersion(self, tagHeader):
+      # A slight hack to make the default ctor work.
+      if isinstance(tagHeader, list):
+         self.majorVersion = tagHeader[0];
+         self.minorVersion = tagHeader[1];
+      else:
+         self.majorVersion = tagHeader.majorVersion;
+         self.minorVersion = tagHeader.minorVersion;
+      self.setBitMask();
+
+   def setBitMask(self):
+      major = self.majorVersion;
+      minor = self.minorVersion;
+
+      # 1.x tags are converted to 2.4 frames internally.  These frames are
+      # created with frame flags \x00.
+      if (major == 2 and minor == 3):
+         self.TAG_ALTER   = 0;   
+         self.FILE_ALTER  = 1;   
+         self.READ_ONLY   = 2;   
+         self.COMPRESSION = 8;   
+         self.ENCRYPTION  = 9;   
+         self.GROUPING    = 10;   
+         # This is not really in 2.3 frame header flags, but there is
+         # a "global" unsync bit in the tag header and that is written here
+         # so access to the tag header is not required.
+         self.UNSYNC      = 14;   
+         # And this is mapped to an used bit, so that 0 is returned.
+         self.DATA_LEN    = 4;
+      elif (major == 2 and minor == 4) or \
+           (major == 1 and (minor == 0 or minor == 1)):
+         self.TAG_ALTER   = 1;   
+         self.FILE_ALTER  = 2;   
+         self.READ_ONLY   = 3;   
+         self.COMPRESSION = 12;   
+         self.ENCRYPTION  = 13;   
+         self.GROUPING    = 9;   
+         self.UNSYNC      = 14;   
+         self.DATA_LEN    = 15;   
+      else:
+         raise ValueError("ID3 v" + str(major) + "." + str(minor) +\
+                          " is not supported.");
+
+   def render(self, dataSize):
+      data = self.id;
+
+      if self.minorVersion == 3:
+         data += bin2bytes(dec2bin(dataSize, 32));
+      else:
+         data += bin2bytes(bin2synchsafe(dec2bin(dataSize, 32)));
+
+      self.setBitMask();
+      self.flags = NULL_FRAME_FLAGS;
+      self.flags[self.TAG_ALTER] = self.tagAlter;
+      self.flags[self.FILE_ALTER] = self.fileAlter;
+      self.flags[self.READ_ONLY] = self.readOnly;
+      self.flags[self.COMPRESSION] = self.compressed;
+      self.flags[self.COMPRESSION] = self.compressed;
+      self.flags[self.ENCRYPTION] = self.encrypted;
+      self.flags[self.GROUPING] = self.grouped;
+      self.flags[self.UNSYNC] = self.unsync;
+      self.flags[self.DATA_LEN] = self.dataLenIndicator;
+
+      data += bin2bytes(self.flags);
+
+      return data;
+
+   # Returns 1 on success and 0 when a null tag (marking the beginning of
+   # padding).  In the case of an invalid frame header, a FrameException is 
+   # thrown.
+   def parse(self, f):
+      TRACE_MSG("FrameHeader [start byte]: %d (0x%X)" % (f.tell(),
+                                                         f.tell()));
+      frameId = f.read(4);
+      TRACE_MSG("FrameHeader [id]: %s (0x%x%x%x%x)" % (frameId,
+                                                       ord(frameId[0]),
+                                                       ord(frameId[1]),
+                                                       ord(frameId[2]),
+                                                       ord(frameId[3])));
+
+      if self.isFrameIdValid(frameId):
+         self.id = frameId;
+         # dataSize corresponds to the size of the data segment after
+         # encryption, compression, and unsynchronization.
+         sz = f.read(4);
+         # In ID3 v2.4 this value became a synch-safe integer, meaning only
+         # the low 7 bits are used per byte.
+         if self.minorVersion == 3:
+            self.dataSize = bin2dec(bytes2bin(sz, 8));
+         else:
+            self.dataSize = bin2dec(bytes2bin(sz, 7));
+         TRACE_MSG("FrameHeader [data size]: %d (0x%X)" % (self.dataSize,
+                                                           self.dataSize));
+ 
+         # Frame flags.
+         flags = f.read(2);
+         self.flags = bytes2bin(flags);
+         self.tagAlter = self.flags[self.TAG_ALTER];
+         self.fileAlter = self.flags[self.FILE_ALTER];
+         self.readOnly = self.flags[self.READ_ONLY];
+         self.compressed = self.flags[self.COMPRESSION];
+         self.encrypted = self.flags[self.ENCRYPTION];
+         self.grouped = self.flags[self.GROUPING];
+         self.unsync = self.flags[self.UNSYNC];
+         self.dataLenIndicator = self.flags[self.DATA_LEN];
+         TRACE_MSG("FrameHeader [flags]: ta(%d) fa(%d) ro(%d) co(%d) "\
+                   "en(%d) gr(%d) un(%d) dl(%d)" % (self.tagAlter,
+                                                    self.fileAlter,
+                                                    self.readOnly,
+                                                    self.compressed,
+                                                    self.encrypted,
+                                                    self.grouped,
+                                                    self.unsync,
+                                                    self.dataLenIndicator));
+         if self.minorVersion >= 4 and self.compressed and \
+            not self.dataLenIndicator:
+            raise FrameException("Invalid frame; compressed with no data "
+                                 "length indicator");
+
+      elif frameId == '\x00\x00\x00\x00':
+         TRACE_MSG("FrameHeader: Null frame id found at byte " +\
+                   str(f.tell()));
+         return 0;
+      else:
+         raise FrameException("FrameHeader: Illegal Frame ID: " + frameId);
+      return 1;
+
+
+   def isFrameIdValid(self, id):
+      return re.compile(r"^[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]$").match(id) or \
+             id == 'MP3e' or id[1:] == 'MP3'
+
+   def clearFlags(self):
+      flags = [0] * 16;
+
+################################################################################
+def unsyncData(data):
+   subs = (0, 0);
+   (data, subs[0]) = re.compile("\xff\x00").subn("\xff\x00\x00", data);
+   (data, subs[1]) = re.compile("\xff(?=[\xe0-\xff])").subn("\xff\x00", data);
+   TRACE_MSG("Unsynchronizing data: " + str(subs));
+   return data;
+
+def deunsyncData(data):
+   TRACE_MSG("Frame: [size before deunsync]: " + str(len(data)));
+   data = re.compile("\xff\x00([\xe0-\xff])").sub("\xff\\1", data);
+   TRACE_MSG("Frame: [size after stage #1 deunsync]: " + str(len(data)));
+   data = re.compile("\xff\x00\x00").sub("\xff\x00", data);
+   TRACE_MSG("Frame: [size after deunsync: " + str(len(data)));
+   return data;
+
+################################################################################
+class Frame:
+   header = None;
+   decompressedSize = 0;
+   groupId = 0;
+   encryptionMethod = 0;
+   dataLen = 0;
+
+   def __repr__(self):
+      desc = self.getFrameDesc();
+      return '<%s Frame (%s)>' % (desc, self.header.id);
+
+   def unsync(self, data):
+      if self.header.unsync:
+         data = unsyncData(data);
+      return data;
+
+   def deunsync(self, data):
+      data = deunsyncData(data);
+      return data;
+
+   def decompress(self, data):
+      TRACE_MSG("before decompression: %d bytes" % len(data));
+      data = zlib.decompress(data, 15, self.decompressedSize);
+      TRACE_MSG("after decompression: %d bytes" % len(data));
+      return data;
+
+   def compress(self, data):
+      TRACE_MSG("before compression: %d bytes" % len(data));
+      data = zlib.compress(data);
+      TRACE_MSG("after compression: %d bytes" % len(data));
+      return data;
+
+   def decrypt(self, data):
+      raise FrameException("Ecnyption Not Supported");
+
+   def encrypt(self, data):
+      raise FrameException("Ecnyption Not Supported");
+
+   def disassembleFrame(self, data):
+      # Format flags in the frame header may add extra data to the
+      # beginning of this data.
+      if self.header.minorVersion == 3:
+         # 2.3:  compression(4), encryption(1), group(1) 
+         if self.header.compressed:
+            self.decompressedSize = bin2dec(bytes2bin(data[:4]));
+            data = data[4:];
+            TRACE_MSG("Decompressed Size: %d" % self.decompressedSize);
+         if self.header.encrypted:
+            self.encryptionMethod = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Encryption Method: %d" % self.encryptionMethod);
+         if self.header.grouped:
+            self.groupId = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Group ID: %d" % self.groupId);
+      else:
+         # 2.4:  group(1), encrypted(1), dataLenIndicator(4,7)
+         if self.header.grouped:
+            self.groupId = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+         if self.header.encrypted:
+            self.encryptionMethod = bin2dec(bytes2bin(data[0]));
+            data = data[1:];
+            TRACE_MSG("Encryption Method: %d" % self.encryptionMethod);
+            TRACE_MSG("Group ID: %d" % self.groupId);
+         if self.header.dataLenIndicator:
+            self.dataLen = bin2dec(bytes2bin(data[:4], 7));
+            data = data[4:];
+            TRACE_MSG("Data Length: %d" % self.dataLen);
+            if self.header.compressed:
+               self.decompressedSize = self.dataLen;
+               TRACE_MSG("Decompressed Size: %d" % self.decompressedSize);
+
+      if self.header.unsync:
+         data = self.deunsync(data);
+      if self.header.encrypted:
+         data = self.decrypt(data);
+      if self.header.compressed:
+         data = self.decompress(data);
+      return data;
+
+   def assembleFrame (self, data):
+      formatFlagData = "";
+      if self.header.minorVersion == 3:
+         if self.header.compressed:
+            formatFlagData += bin2bytes(dec2bin(len(data), 32));
+         if self.header.encrypted:
+            formatFlagData += bin2bytes(dec2bin(self.encryptionMethod, 8));
+         if self.header.grouped:
+            formatFlagData += bin2bytes(dec2bin(self.groupId, 8));
+      else:
+         if self.header.grouped:
+            formatFlagData += bin2bytes(dec2bin(self.groupId, 8));
+         if self.header.encrypted:
+            formatFlagData += bin2bytes(dec2bin(self.encryptionMethod, 8));
+         if self.header.compressed or self.header.dataLenIndicator:
+            # Just in case, not sure about this?
+            self.header.dataLenIndicator = 1;
+            formatFlagData += bin2bytes(dec2bin(len(data), 32));
+
+      if self.header.compressed:
+         data = self.compress(data);
+      if self.header.encrypted:
+         data = self.encrypt(data);
+      if self.header.unsync:
+         data = self.unsync(data);
+
+      data = formatFlagData + data;
+      return self.header.render(len(data)) + data;
+
+   def getFrameDesc(self):
+      try:
+         return frameDesc[self.header.id];
+      except KeyError:
+         try:
+            return obsoleteFrames[self.header.id];
+         except KeyError:
+            return "UNKOWN FRAME";
+
+################################################################################
+class TextFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   text = u"";
+
+   # Data string format:
+   # encoding (one byte) + text;
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + text;
+   def set(self, data, frameHeader):
+      fid = frameHeader.id;
+      if not TEXT_FRAME_RX.match(fid) or USERTEXT_FRAME_RX.match(fid):
+         raise FrameException("Invalid frame id for TextFrame: " + fid);
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("TextFrame encoding: %s" % id3EncodingToString(self.encoding));
+      self.text = unicode(data[1:], id3EncodingToString(self.encoding));
+      TRACE_MSG("TextFrame text: %s" % self.text);
+
+   def __repr__(self):
+      return '<%s (%s): %s>' % (self.getFrameDesc(), self.header.id, self.text);
+
+   def render(self):
+       if self.header.minorVersion == 4 and self.header.id == "TSIZ":
+           TRACE_MSG("Dropping deprecated frame TSIZ");
+           return "";
+       data = self.encoding +\
+              self.text.encode(id3EncodingToString(self.encoding));
+       return self.assembleFrame(data);
+
+################################################################################
+class DateFrame(TextFrame):
+   def __init__(self, data, frameHeader):
+      self.date = None;
+      self.date_str = "";
+      self.set(data, frameHeader);
+
+   def set(self, data, frameHeader):
+      TextFrame.set(self, data, frameHeader);
+      if self.header.id[:2] != "TD" and self.header.minorVersion != 3:
+         raise FrameException("Invalid frame id for DateFrame: " + \
+                              self.header.id);
+      self.setDate(self.text);
+   
+   def setDate(self, d):
+      if not d:
+         self.date = None;
+         self.date_str = "";
+         return;
+
+      for fmt in timeStampFormats:
+         try:
+            if isinstance(d, tuple):
+               self.date_str = time.strftime(fmt, d);
+               self.date = d;
+            else:
+               d = d.strip("\x00");
+
+               # Witnessed oddball tags with NULL bytes (ozzy.tag from id3lib)
+               strippedDate = "";
+               for c in d:
+                  if ord(c) != 0:
+                     strippedDate += c;
+               d = strippedDate;
+
+               try:
+                  self.date = time.strptime(d, fmt);
+               except TypeError, ex:
+                  continue;
+               self.date_str = d;
+            break;
+         except ValueError:
+            self.date = None;
+            self.date_str = "";
+            continue;
+      if strictID3() and not self.date:
+         raise FrameException("Invalid Date: " + str(d));
+      self.text = self.date_str;
+
+   def getDate(self):
+      return self.date_str;
+
+   def getYear(self):
+      if self.date:
+	 return self.__padDateField(self.date[0], 4);
+      else:
+         return None;
+
+   def getMonth(self):
+      if self.date:
+	 return self.__padDateField(self.date[1], 2);
+      else:
+         return None;
+
+   def getDay(self):
+      if self.date:
+	 return self.__padDateField(self.date[2], 2);
+      else:
+         return None;
+
+   def getHour(self):
+      if self.date:
+	 return self.__padDateField(self.date[3], 2);
+      else:
+         return None;
+
+   def getMinute(self):
+      if self.date:
+	 return self.__padDateField(self.date[4], 2);
+      else:
+         return None;
+
+   def getSecond(self):
+      if self.date:
+	 return self.__padDateField(self.date[5], 2);
+      else:
+         return None;
+
+   def __padDateField(self, f, sz):
+      fStr = str(f);
+      if len(fStr) == sz:
+         pass;
+      elif len(fStr) < sz:
+         fStr = ("0" * (sz - len(fStr))) + fStr;
+      else:
+         raise TagException("Invalid date field: " + fStr);
+      return fStr;
+
+   def render(self):
+       # Conversion crap
+       if self.header.minorVersion == 4 and\
+          (self.header.id == OBSOLETE_DATE_FID or\
+           self.header.id == OBSOLETE_YEAR_FID or\
+           self.header.id == OBSOLETE_TIME_FID or\
+           self.header.id == OBSOLETE_RECORDING_DATE_FID):
+           self.header.id = "TDRC";
+       elif self.header.minorVersion == 4 and\
+            self.header.id == OBSOLETE_ORIG_RELEASE_FID:
+           self.header.id = "TDOR";
+       elif self.header.minorVersion == 3 and self.header.id == "TDOR":
+           self.header.id = OBSOLETE_ORIG_RELEASE_FID;
+       elif self.header.minorVersion == 3 and self.header.id[:2] == "TD":
+           self.header.id = OBSOLETE_YEAR_FID;
+
+       data = self.encoding + str(self.date_str);
+       data = self.assembleFrame(data);
+       return data;
+
+
+################################################################################
+class UserTextFrame(TextFrame):
+   description = u"";
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + text;
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + text;
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not USERTEXT_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for UserTextFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = USERTEXT_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("UserTextFrame encoding: %s" %\
+                id3EncodingToString(self.encoding));
+      (d, t) = splitUnicode(data[1:], self.encoding);
+      self.description = unicode(d, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserTextFrame description: %s" % self.description);
+      self.text = unicode(t, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserTextFrame text: %s" % self.text);
+
+   def render(self):
+      data = self.encoding +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" +\
+             self.text.encode(id3EncodingToString(self.encoding));
+      return self.assembleFrame(data);
+
+################################################################################
+class URLFrame(Frame):
+   url = "";
+
+   # Data string format:
+   # url
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # url
+   def set(self, data, frameHeader):
+      fid = frameHeader.id;
+      if not URL_FRAME_RX.match(fid) or USERURL_FRAME_RX.match(fid):
+         raise FrameException("Invalid frame id for URLFrame: " + fid);
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.url = data;
+
+   def render(self):
+      data = str(self.url);
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return '<%s (%s): %s>' % (self.getFrameDesc(), self.header.id,
+                                self.url);
+
+################################################################################
+class UserURLFrame(URLFrame):
+   encoding = DEFAULT_ENCODING;
+   description = u"";
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + url;
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + description + "\x00" + url;
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not USERURL_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for UserURLFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = USERURL_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("UserURLFrame encoding: %s" %\
+                id3EncodingToString(self.encoding));
+      (d, u) = splitUnicode(data[1:], self.encoding);
+      self.description = unicode(d, id3EncodingToString(self.encoding));
+      TRACE_MSG("UserURLFrame description: %s" % self.description);
+      self.url = u;
+      TRACE_MSG("UserURLFrame text: %s" % self.url);
+
+   def render(self):
+      data = self.encoding +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" + self.url;
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return '<%s (%s): %s [Encoding: %s] [Desc: %s]>' %\
+             (self.getFrameDesc(), self.header.id,
+              self.url, self.encoding, self.description)
+
+################################################################################
+class CommentFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   lang = u"";
+   description = u"";
+   comment = u"";
+
+   # Data string format:
+   # encoding (one byte) + lang (three byte code) + description + "\x00" +
+   # text
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # Data string format:
+   # encoding (one byte) + lang (three byte code) + description + "\x00" +
+   # text
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not COMMENT_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for CommentFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = COMMENT_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.encoding = data[0];
+      TRACE_MSG("CommentFrame encoding: " + id3EncodingToString(self.encoding));
+      try:
+          self.lang = str(data[1:4]).strip("\x00");
+          self.lang = unicode(self.lang, "ascii");
+          if self.lang and \
+             not re.compile("[A-Z][A-Z][A-Z]", re.IGNORECASE).match(self.lang):
+             if strictID3():
+                 raise FrameException("[CommentFrame] Invalid language "\
+                                       "code: %s" % self.lang);
+      except UnicodeDecodeError, ex:
+          if strictID3():
+              raise FrameException("[CommentFrame] Invalid language code: "\
+                                   "[%s] %s" % (ex.object, ex.reason));
+          else:
+              self.lang = "";
+      try:
+         (d, c) = splitUnicode(data[4:], self.encoding);
+         self.description = unicode(d, id3EncodingToString(self.encoding));
+         self.comment = unicode(c, id3EncodingToString(self.encoding));
+      except ValueError:
+          if strictID3():
+              raise FrameException("Invalid comment; no description/comment");
+          else:
+              self.description = u"";
+              self.comment = u"";
+
+   def render(self):
+      data = self.encoding + self.lang.encode("ascii") +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00" +\
+             self.comment.encode(id3EncodingToString(self.encoding));
+      return self.assembleFrame(data);
+
+   def __repr__(self):
+      return "<%s (%s): %s [Lang: %s] [Desc: %s]>" %\
+             (self.getFrameDesc(), self.header.id, self.comment,
+              self.lang, self.description);
+
+################################################################################
+# This class refers to the APIC frame, otherwise known as an "attached
+# picture".
+class ImageFrame(Frame):
+   encoding = DEFAULT_ENCODING;
+   mimeType = None;
+   pictureType = None;
+   description = u"";
+   # Contains the image data when the mimetype is image type.
+   # Otherwise it is None.
+   imageData = None;
+   # Contains a URL for the image when the mimetype is "-->" per the spec.
+   # Otherwise it is None.
+   imageURL = None;
+   # Declared "picture types".
+   OTHER               = 0x00;
+   ICON                = 0x01; # 32x32 png only.
+   OTHER_ICON          = 0x02;
+   FRONT_COVER         = 0x03;
+   BACK_COVER          = 0x04;
+   LEAFLET             = 0x05;
+   MEDIA               = 0x06; # label side of cd, picture disc vinyl, etc.
+   LEAD_ARTIST         = 0x07;
+   ARTIST              = 0x08;
+   CONDUCTOR           = 0x09;
+   BAND                = 0x0A;
+   COMPOSER            = 0x0B;
+   LYRICIST            = 0x0C;
+   RECORDING_LOCATION  = 0x0D;
+   DURING_RECORDING    = 0x0E;
+   DURING_PERFORMANCE  = 0x0F;
+   VIDEO               = 0x10;
+   BRIGHT_COLORED_FISH = 0x11; # There's always room for porno.
+   ILLUSTRATION        = 0x12; 
+   BAND_LOGO           = 0x13; 
+   PUBLISHER_LOGO      = 0x14; 
+   MIN_TYPE            = OTHER;
+   MAX_TYPE            = PUBLISHER_LOGO;
+
+   def __init__(self, data = None, frameHeader = None):
+       if data:
+           self.set(data, frameHeader);
+
+   # Factory method
+   def create(type, imgFile, desc = u""):
+       if not isinstance(desc, unicode) or \
+          not isinstance(type, int):
+           raise FrameException("Wrong description and/or image-type type.");
+       # Load img
+       fp = file(imgFile, "rb");
+       imgData = fp.read();
+       mt = mimetypes.guess_type(imgFile);
+       if not mt[0]:
+           raise FrameException("Unable to guess mime-type for %s" % (imgFile));
+
+       frameData = DEFAULT_ENCODING;
+       frameData += mt[0] + "\x00";
+       frameData += bin2bytes(dec2bin(type, 8));
+       frameData += desc.encode(id3EncodingToString(DEFAULT_ENCODING)) + "\x00";
+       frameData += imgData;
+
+       return ImageFrame(frameData);
+   # Make create a static method.  Odd....
+   create = staticmethod(create);
+
+   # Data string format:
+   # <Header for 'Attached picture', ID: "APIC">
+   #  Text encoding      $xx
+   #  MIME type          <text string> $00
+   #  Picture type       $xx
+   #  Description        <text string according to encoding> $00 (00)
+   #  Picture data       <binary data>
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not IMAGE_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for ImageFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = IMAGE_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+
+      input = StringIO(data);
+      TRACE_MSG("APIC frame data size: " + str(len(data)));
+      self.encoding = input.read(1);
+      TRACE_MSG("APIC encoding: " + id3EncodingToString(self.encoding));
+
+      self.mimeType = "";
+      ch = input.read(1);
+      while ch != "\x00":
+         self.mimeType += ch;
+         ch = input.read(1);
+      TRACE_MSG("APIC mime type: " + self.mimeType);
+      if strictID3() and not self.mimeType:
+         raise FrameException("APIC frame does not contain a mime type");
+      if self.mimeType.find("/") == -1:
+         self.mimeType = "image/" + self.mimeType;
+
+      pt = ord(input.read(1));
+      TRACE_MSG("Initial APIC picture type: " + str(pt));
+      if pt < self.MIN_TYPE or pt > self.MAX_TYPE:
+          if strictID3():
+              raise FrameException("Invalid APIC picture type: %d" % (pt));
+          # Rather than force this to UNKNOWN, let's assume that they put a
+          # character literal instead of it's byte value.
+          try:
+              pt = int(chr(pt));
+          except:
+              pt = self.OTHER;
+          if pt < self.MIN_TYPE or pt > self.MAX_TYPE:
+              self.pictureType = self.OTHER;
+      self.pictureType = pt;
+      TRACE_MSG("APIC picture type: " + str(self.pictureType));
+
+      self.desciption = u"";
+      buffer = "";
+      ch = input.read(1);
+      while ch != "\x00":
+         buffer += ch;
+         ch = input.read(1);
+      self.description = unicode(buffer, id3EncodingToString(self.encoding));
+      TRACE_MSG("APIC description: " + self.description);
+
+      if self.mimeType.find("-->") != -1:
+         self.imageData = None;
+         self.imageURL = input.read();
+      else:
+         self.imageData = input.read();
+         self.imageURL = None;
+      TRACE_MSG("APIC image data: " + str(len(self.imageData)) + " bytes");
+      if strictID3() and not self.imageData and not self.imageURL:
+         raise FrameException("APIC frame does not contain any image data");
+
+      input.close();
+
+   def writeFile(self, path = "./", name = None):
+      if not self.imageData:
+         raise IOError("Fetching remote image files is not implemented.");
+      if not name:
+         name = self.getDefaultFileName();
+      imageFile = os.path.join(path, name);
+
+      f = file(imageFile, "wb");
+      f.write(self.imageData);
+      f.flush();
+      f.close();
+   def getDefaultFileName(self):
+      nameStr = self.picTypeToString(self.pictureType);
+      nameStr = nameStr +  "." + self.mimeType.split("/")[1];
+      return nameStr;
+
+   def render(self):
+      data = self.encoding + self.mimeType + "\x00" +\
+             bin2bytes(dec2bin(self.pictureType, 8)) +\
+             self.description.encode(id3EncodingToString(self.encoding)) +\
+             "\x00";
+      if self.imageURL:
+          data += self.imageURL.encode("ascii");
+      else:
+          data += self.imageData;
+      return self.assembleFrame(data);
+
+   def stringToPicType(self, s):
+       if s == "OTHER":
+           return self.OTHER;
+       elif s == "ICON":
+           return self.ICON;
+       elif s == "OTHER_ICON":
+           return self.OTHER_ICON;
+       elif s == "FRONT_COVER":
+           return self.FRONT_COVER
+       elif s == "BACK_COVER":
+           return self.BACK_COVER;
+       elif s == "LEAFLET":
+           return self.LEAFLET;
+       elif s == "MEDIA":
+           return self.MEDIA;
+       elif s == "LEAD_ARTIST":
+           return self.LEAD_ARTIST;
+       elif s == "ARTIST":
+           return self.ARTIST;
+       elif s == "CONDUCTOR":
+           return self.CONDUCTOR;
+       elif s == "BAND":
+           return self.BAND;
+       elif s == "COMPOSER":
+           return self.COMPOSER;
+       elif s == "LYRICIST":
+           return self.LYRICIST;
+       elif s == "RECORDING_LOCATION":
+           return self.RECORDING_LOCATION;
+       elif s == "DURING_RECORDING":
+           return self.DURING_RECORDING;
+       elif s == "DURING_PERFORMANCE":
+           return self.DURING_PERFORMANCE;
+       elif s == "VIDEO":
+           return self.VIDEO;
+       elif s == "BRIGHT_COLORED_FISH":
+           return self.BRIGHT_COLORED_FISH;
+       elif s == "ILLUSTRATION":
+           return self.ILLUSTRATION;
+       elif s == "BAND_LOGO":
+           return self.BAND_LOGO;
+       elif s == "PUBLISHER_LOGO":
+           return self.PUBLISHER_LOGO;
+       else:
+         raise FrameException("Invalid APIC picture type: %s" % s);
+
+   def picTypeToString(self, t):
+      if t == self.OTHER:
+         return "OTHER";
+      elif t == self.ICON:
+         return "ICON";
+      elif t == self.OTHER_ICON:
+         return "OTHER_ICON";
+      elif t == self.FRONT_COVER:
+         return "FRONT_COVER";
+      elif t == self.BACK_COVER:
+         return "BACK_COVER";
+      elif t == self.LEAFLET:
+         return "LEAFLET";
+      elif t == self.MEDIA:
+         return "MEDIA";
+      elif t == self.LEAD_ARTIST:
+         return "LEAD_ARTIST";
+      elif t == self.ARTIST:
+         return "ARTIST";
+      elif t == self.CONDUCTOR:
+         return "CONDUCTOR";
+      elif t == self.BAND:
+         return "BAND";
+      elif t == self.COMPOSER:
+         return "COMPOSER";
+      elif t == self.LYRICIST:
+         return "LYRICIST";
+      elif t == self.RECORDING_LOCATION:
+         return "RECORDING_LOCATION";
+      elif t == self.DURING_RECORDING:
+         return "DURING_RECORDING";
+      elif t == self.DURING_PERFORMANCE:
+         return "DURING_PERFORMANCE";
+      elif t == self.VIDEO:
+         return "VIDEO";
+      elif t == self.BRIGHT_COLORED_FISH:
+         return "BRIGHT_COLORED_FISH";
+      elif t == self.ILLUSTRATION:
+         return "ILLUSTRATION";
+      elif t == self.BAND_LOGO:
+         return "BAND_LOGO";
+      elif t == self.PUBLISHER_LOGO:
+         return "PUBLISHER_LOGO";
+      else:
+         raise FrameException("Invalid APIC picture type: %d" % t);
+
+################################################################################
+class UnknownFrame(Frame):
+   data = "";
+
+   def __init__(self, data, frameHeader):
+      self.set(data, frameHeader);
+
+   def set(self, data, frameHeader):
+      self.header = frameHeader;
+      data = self.disassembleFrame(data);
+      self.data = data;
+
+   def render(self):
+      return self.assembleFrame(self.data)
+
+################################################################################
+class MusicCDIdFrame(Frame):
+   toc = "";
+
+   def __init__(self, data, frameHeader = None):
+      self.set(data, frameHeader);
+
+   # TODO: Parse the TOC and comment the format.
+   def set(self, data, frameHeader = None):
+      if frameHeader:
+         if not CDID_FRAME_RX.match(frameHeader.id):
+            raise FrameException("Invalid frame id for MusicCDIdFrame: " +\
+                                 frameHeader.id);
+      else:
+         frameHeader = FrameHeader();
+         frameHeader.id = CDID_FID;
+      self.header = frameHeader;
+
+      data = self.disassembleFrame(data);
+      self.toc = data;
+
+   def render(self):
+      data = self.toc;
+      return self.assembleFrame(data);
+
+################################################################################
+# A class for containing and managing ID3v2.Frame objects.
+class FrameSet(list):
+   tagHeader = None;
+
+   def __init__(self, tagHeader, l = None):
+      self.tagHeader = tagHeader;
+      if l:
+         for f in l:
+            if not isinstance(f, Frame):
+               raise TypeError("Invalid type added to FrameSet: " +\
+                               f.__class__);
+            self.append(f);
+
+   # Setting a FrameSet instance like this 'fs = []' morphs the instance into
+   # a list object.
+   def clear(self):
+      del self[0:];
+
+   # Read frames starting from the current read position of the file object.
+   # Returns the amount of padding which occurs after the tag, but before the
+   # audio content.  A return valule of 0 DOES NOT imply an error.
+   def parse(self, f, tagHeader):
+      self.tagHeader = tagHeader;
+      paddingSize = 0;
+      sizeLeft = tagHeader.tagSize;
+
+      # Handle a tag-level unsync.  Some frames may have their own unsync bit
+      # set instead.
+      tagData = f.read(sizeLeft);
+      if tagHeader.unsync:
+         TRACE_MSG("Tag has unsync bit set");
+         tagData = deunsyncData(tagData);
+         sizeLeft = len(tagData);
+      # Adding 10 to simulate the tag header in the buffer.  This keeps 
+      # f.tell() values the same as in the file.
+      tagBuffer = StringIO((10 * '\x00') + tagData);
+      tagBuffer.seek(10);
+      tagBuffer.tell();
+
+      while sizeLeft > 0:
+         TRACE_MSG("sizeLeft: " + str(sizeLeft));
+         if sizeLeft < (10 + 1):
+            TRACE_MSG("FrameSet: Implied padding (sizeLeft < minFrameSize)");
+            paddingSize = sizeLeft;
+            break;
+
+         TRACE_MSG("+++++++++++++++++++++++++++++++++++++++++++++++++");
+         TRACE_MSG("FrameSet: Reading Frame #" + str(len(self) + 1));
+         frameHeader = FrameHeader(tagHeader);
+         if not frameHeader.parse(tagBuffer):
+            paddingSize = sizeLeft;
+            break;
+
+         # Frame data.
+         TRACE_MSG("FrameSet: Reading %d (0x%X) bytes of data from byte "\
+                   "pos %d (0x%X)" % (frameHeader.dataSize,
+                                      frameHeader.dataSize, tagBuffer.tell(),
+                                      tagBuffer.tell()));
+         data = tagBuffer.read(frameHeader.dataSize);
+         TRACE_MSG("FrameSet: %d bytes of data read" % len(data));
+
+         self.addFrame(createFrame(frameHeader, data));
+
+         # Each frame contains dataSize + headerSize(10) bytes.
+         sizeLeft -= (frameHeader.FRAME_HEADER_SIZE + frameHeader.dataSize);
+
+      return paddingSize;
+
+   # Returrns the size of the frame data.
+   def getSize(self):
+      sz = 0;
+      for f in self:
+         sz += len(f.render());
+      return sz;
+   
+   def setTagHeader(self, tagHeader):
+      self.tagHeader = tagHeader;
+      for f in self:
+         f.header.setVersion(tagHeader);
+
+   # This methods adds the frame if it is addable per the ID3 spec.
+   def addFrame(self, frame):
+      fid = frame.header.id;
+
+      # Text frame restrictions.
+      # No multiples except for TXXX which must have unique descriptions.
+      if strictID3() and TEXT_FRAME_RX.match(fid) and self[fid]:
+         if not USERTEXT_FRAME_RX.match(fid):
+            raise FrameException("Multiple %s frames now allowed." % fid);
+         userTextFrames = self[fid];
+         for frm in userTextFrames:
+            if frm.description == frame.description:
+               raise FrameException("Multiple %s frames with the same\
+                                     description now allowed." % fid);
+
+      # Comment frame restrictions.
+      # Multiples must have a unique description/language combination.
+      if strictID3() and COMMENT_FRAME_RX.match(fid) and self[fid]:
+         commentFrames = self[fid];
+         for frm in commentFrames:
+            if frm.description == frame.description and\
+               frm.lang == frame.lang:
+               raise FrameException("Multiple %s frames with the same\
+                                     language and description now allowed." %\
+                                     fid);
+
+      # URL frame restrictions.
+      # No multiples except for TXXX which must have unique descriptions.
+      if strictID3() and URL_FRAME_RX.match(fid) and self[fid]:
+         if not USERURL_FRAME_RX.match(fid):
+            raise FrameException("Multiple %s frames now allowed." % fid);
+         userUrlFrames = self[fid];
+         for frm in userUrlFrames:
+            if frm.description == frame.description:
+               raise FrameException("Multiple %s frames with the same\
+                                     description now allowed." % fid);
+
+      # Music CD ID restrictions.
+      # No multiples.
+      if strictID3() and CDID_FRAME_RX.match(fid) and self[fid]:
+         raise FrameException("Multiple %s frames now allowed." % fid);
+
+      # Image (attached picture) frame restrictions.
+      # Multiples must have a unique content desciptor.  I'm assuming that
+      # the spec means the picture type.....
+      if IMAGE_FRAME_RX.match(fid) and self[fid]:
+         imageFrames = self[fid];
+         for frm in imageFrames:
+            if frm.pictureType == frame.pictureType:
+               raise FrameException("Multiple %s frames with the same\
+                                     content descriptor now allowed." % fid);
+      self.append(frame);
+
+   # Set a text frame value.  Text frame IDs must be unique.  If a frame with
+   # the same Id is already in the list it's value is changed, otherwise
+   # the frame is added.
+   def setTextFrame(self, frameId, text, encoding = DEFAULT_ENCODING):
+      if not TEXT_FRAME_RX.match(frameId):
+         raise FrameException("Invalid Frame ID: " + frameId);
+      if USERTEXT_FRAME_RX.match(frameId):
+         raise FrameException("Wrong method, use setUserTextFrame");
+
+      if self[frameId]:
+          curr = self[frameId][0];
+          curr.encoding = encoding;
+          if isinstance(curr, DateFrame):
+              curr.setDate(text);
+          else:
+              curr.text = text;
+      else:
+          h = FrameHeader(self.tagHeader);
+          h.id = frameId;
+          self.addFrame(createFrame(h, encoding + text));
+
+   # If a comment frame with the same language and description exists then
+   # the comment text is replaced, otherwise the frame is added.
+   def setCommentFrame(self, comment, description, lang = DEFAULT_LANG,
+                       encoding = DEFAULT_ENCODING):
+
+      if self[COMMENT_FID]:
+         found = 0;
+         for f in self[COMMENT_FID]:
+            if f.lang == lang and f.description == description:
+               f.comment = comment;
+               f.encoding = encoding;
+               found = 1;
+               break;
+         if not found:
+            h = FrameHeader(self.tagHeader);
+            h.id = COMMENT_FID;
+            self.addFrame(CommentFrame(encoding + lang + description + "\x00" +
+                                       comment, h));
+      else:
+         h = FrameHeader(self.tagHeader);
+         h.id = COMMENT_FID;
+         self.addFrame(CommentFrame(encoding + lang + description + "\x00" +
+                                    comment, h));
+         
+   # This method removes all frames with the matching frame ID.
+   # The number of frames removed is returned.
+   # Note that calling this method with a key like "COMM" may remove more
+   # frames then you really want.
+   def removeFramesByID(self, fid):
+      if not isinstance(fid, str):
+         raise FrameException("removeFramesByID only operates on frame IDs");
+
+      i = 0;
+      count = 0;
+      while i < len(self):
+         if self[i].header.id == fid:
+            del self[i];
+            count += 1;
+         else:
+            i += 1;
+      return count;
+
+   # Removes the frame at index.  True is returned if the element was
+   # removed, and false otherwise.
+   def removeFrameByIndex(self, index):
+      if not isinstance(index, int):
+         raise\
+           FrameException("removeFrameByIndex only operates on a frame index");
+      try:
+         del self.frames[key];
+         return 1;
+      except:
+         return 0;
+
+   # Accepts both int (indexed access) and string keys (a valid frame Id).
+   # A list of frames (commonly with only one element) is returned when the
+   # FrameSet is accessed using frame IDs since some frames can appear
+   # multiple times in a tag.  To sum it all up htis method returns
+   # string or None when indexed using an integer, and a 0 to N length
+   # list of strings when indexed with a frame ID.
+   #
+   # Throws IndexError and TypeError.
+   def __getitem__(self, key):
+      if isinstance(key, int):
+         if key >= 0 and key < len(self):
+            return list.__getitem__(self, key);
+         else:
+            raise IndexError("FrameSet index out of range");
+      elif isinstance(key, str):
+         retList = list();
+         for f in self:
+            if f.header.id == key:
+               retList.append(f);
+         return retList;
+      else:
+         raise TypeError("FrameSet key must be type int or string");
+
+#  Mmmmm!  Cheesy!
+def splitUnicode(data, encoding):
+    if encoding == LATIN1_ENCODING or encoding == UTF_8_ENCODING or\
+       encoding == UTF_16BE_ENCODING:
+        return data.split("\x00", 1);
+    elif encoding == UTF_16_ENCODING:
+        (d, t) = data.split("\x00\x00\x00", 1);
+        d += "\x00";
+        t += "\x00";
+        return (d, t);
+
+
+#######################################################################
+# Create and return the appropriate frame.
+# Exceptions: ....
+def createFrame(frameHeader, data):
+  f = None;
+
+  # Text Frames
+  if TEXT_FRAME_RX.match(frameHeader.id):
+     if USERTEXT_FRAME_RX.match(frameHeader.id):
+        f = UserTextFrame(data, frameHeader);
+     else:
+        if frameHeader.id[:2] == "TD" or\
+           frameHeader.id == OBSOLETE_DATE_FID or\
+           frameHeader.id == OBSOLETE_YEAR_FID or \
+           frameHeader.id == OBSOLETE_ORIG_RELEASE_FID:
+           f = DateFrame(data, frameHeader);
+        else:
+           f = TextFrame(data, frameHeader);
+
+  # Comment Frames.
+  elif COMMENT_FRAME_RX.match(frameHeader.id):
+     f = CommentFrame(data, frameHeader);
+
+  # URL Frames.
+  elif URL_FRAME_RX.match(frameHeader.id):
+     if USERURL_FRAME_RX.match(frameHeader.id):
+        f = UserURLFrame(data, frameHeader);
+     else:
+        f = URLFrame(data, frameHeader);
+
+  # CD Id frame.
+  elif CDID_FRAME_RX.match(frameHeader.id):
+     f = MusicCDIdFrame(data, frameHeader);
+
+  # Attached picture
+  elif IMAGE_FRAME_RX.match(frameHeader.id):
+     f = ImageFrame(data, frameHeader);
+
+  if f == None:
+     f = UnknownFrame(data, frameHeader);
+
+  return f;
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/__init__.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/__init__.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/__init__.py	(revision 4)
@@ -0,0 +1,38 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+
+eyeD3Version = "0.6.1"
+eyeD3Maintainer = "Travis Shirk <travis@pobox.com>"
+
+# Version constants
+ID3_CURRENT_VERSION = 0x00; # The version of the linked tag, if any.
+ID3_V1              = 0x10;
+ID3_V1_0            = 0x11;
+ID3_V1_1            = 0x12;
+ID3_V2              = 0x20;
+#ID3_V2_2            = 0x21; # All versions < v2.3 are obsolete.
+ID3_V2_3            = 0x22;
+ID3_V2_4            = 0x24;
+#ID3_V2_5            = 0x28; # This does not seem imminent.
+ID3_DEFAULT_VERSION = ID3_V2_4;
+ID3_ANY_VERSION     = ID3_V1 | ID3_V2;
+
+from tag import *;
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/mp3.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/mp3.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/mp3.py	(revision 4)
@@ -0,0 +1,321 @@
+################################################################################
+#
+#  Copyright (C) 2002-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+################################################################################
+from binfuncs import *;
+from utils import *;
+
+#######################################################################
+class Mp3Exception:
+   msg = "";
+
+   def __init__(self, msg):
+      self.msg = msg;
+
+   def __str__(self):
+      return self.msg;
+
+
+#                   MPEG1  MPEG2  MPEG2.5
+SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
+                     (48000, 24000, 12000),
+                     (32000, 16000, 8000),
+                     (None,  None,  None));
+
+#              V1/L1  V1/L2 V1/L3 V2/L1 V2/L2&L3 
+BIT_RATE_TABLE = ((0,    0,    0,    0,    0),
+                  (32,   32,   32,   32,   8),
+                  (64,   48,   40,   48,   16),
+                  (96,   56,   48,   56,   24),
+                  (128,  64,   56,   64,   32),
+                  (160,  80,   64,   80,   40),
+                  (192,  96,   80,   96,   44),
+                  (224,  112,  96,   112,  56),
+                  (256,  128,  112,  128,  64),
+                  (288,  160,  128,  144,  80),
+                  (320,  192,  160,  160,  96),
+                  (352,  224,  192,  176,  112),
+                  (384,  256,  224,  192,  128),
+                  (416,  320,  256,  224,  144),
+                  (448,  384,  320,  256,  160),
+                  (None, None, None, None, None));
+
+#                             L1    L2    L3
+TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
+
+# Emphasis constants
+EMPHASIS_NONE = "None";
+EMPHASIS_5015 = "50/15 ms";
+EMPHASIS_CCIT = "CCIT J.17";
+
+# Mode constants
+MODE_STEREO              = "Stereo";
+MODE_JOINT_STEREO        = "Joint stereo";
+MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
+MODE_MONO                = "Mono";
+
+# Flag bits
+FRAMES_FLAG    = 0x0001
+BYTES_FLAG     = 0x0002
+TOC_FLAG       = 0x0004
+VBR_SCALE_FLAG = 0x0008
+
+#######################################################################
+def computeTimePerFrame(frameHeader):
+   tpf = TIME_PER_FRAME_TABLE[frameHeader.layer];
+   tpf = float(tpf) / float(frameHeader.sampleFreq);
+   return tpf;
+
+#######################################################################
+class Header:
+   version = float();
+   layer = int();
+   errorProtection = 0;
+   bitRate = int();
+   playTime = long();
+   sampleFreq = int();
+   padding = 0;
+   privateBit = 0;
+   copyright = 0;
+   original = 0;
+   emphasis = str();
+   mode = str();
+   # This value is left as is: 0 <= modeExtension <= 3.  Consult the
+   # mp3 spec here http://www.dv.co.yu/mpgscript/mpeghdr.htm if you wish to 
+   # interpret it.
+   modeExtension = 0;
+
+   # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
+   # header.
+   def isValid(self, header):
+      # Test for the mp3 frame sync: 11 set bits.
+      if (header & 0xffe00000L) != 0xffe00000L:
+         return 0;
+      if not ((header >> 17) & 3):
+         return 0;
+      if ((header >> 12) & 0xf) == 0xf:
+         return 0;
+      if not ((header >> 12) & 0xf):
+         return 0;
+      if ((header >> 10) & 0x3) == 0x3:
+         return 0;
+      if (((header >> 19) & 1) == 1) and (((header >> 17) & 3) == 3) and \
+         (((header >> 16) & 1) == 1):
+         return 0;
+      if (header & 0xffff0000L) == 0xfffe0000L:
+         return 0;
+
+      return 1;
+
+   # This may throw an Mp3Exception if the header is malformed.
+   def decode(self, header):
+      # MPEG audio version from bits 19 and 20.
+      if not header & (1 << 20) and header & (1 << 19):
+         raise Mp3Exception("Illegal MPEG audio version");
+      elif not header & (1 << 20) and not header & (1 << 19):
+         self.version = 2.5;
+      else:
+         if not header & (1 << 19):
+            self.version = 2.0;
+         else:
+            self.version = 1.0;
+
+      
+      # MPEG audio layer from bits 18 and 17.
+      if not header & (1 << 18) and not header & (1 << 17):
+         raise Mp3Exception("Illegal MPEG layer value");
+      elif not header & (1 << 18) and header & (1 << 17):
+         self.layer = 3;
+      elif header & (1 << 18) and not header & (1 << 17):
+         self.layer = 2;
+      else:
+         self.layer = 1;
+
+      # Decode some simple values.
+      self.errorProtection = not (header >> 16) & 0x1;
+      self.padding = (header >> 9) & 0x1;
+      self.privateBit = (header >> 8) & 0x1;
+      self.copyright = (header >> 3) & 0x1;
+      self.original = (header >> 2) & 0x1;
+
+      # Obtain sampling frequency.
+      sampleBits = (header >> 10) & 0x3;
+      if self.version == 2.5:
+         freqCol = 2;
+      else:
+         freqCol = int(self.version - 1);
+      self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
+      if not self.sampleFreq:
+         raise Mp3Exception("Illegal MPEG sampling frequency");
+
+
+      # Compute bitrate.
+      bitRateIndex = (header >> 12) & 0xf;
+      if int(self.version) == 1 and self.layer == 1:
+         bitRateCol = 0;
+      elif int(self.version) == 1 and self.layer == 2:
+         bitRateCol = 1;
+      elif int(self.version) == 1 and self.layer == 3:
+         bitRateCol = 2;
+      elif int(self.version) == 2 and self.layer == 1:
+         bitRateCol = 3;
+      elif int(self.version) == 2 and (self.layer == 2 or \
+                                       self.layer == 3):
+         bitRateCol = 4;
+      else:
+         raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
+                            "combination" % (self.version, self.layer));
+      self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
+      if self.bitRate == None:
+         raise Mp3Exception("Invalid bit rate");
+      # We know know the bit rate specified in this frame, but if the file
+      # is VBR we need to obtain the average from the Xing header.
+      # This is done by the caller since right now all we have is the frame
+      # header.
+
+      # Emphasis; whatever that means??
+      emph = header & 0x3;
+      if emph == 0:
+         self.emphasis = EMPHASIS_NONE;
+      elif emph == 1:
+         self.emphasis = EMPHASIS_5015;
+      elif emph == 2:
+         self.emphasis = EMPHASIS_CCIT;
+      elif strictID3():
+         raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
+
+      # Channel mode.
+      modeBits = (header >> 6) & 0x3;
+      if modeBits == 0:
+         self.mode = MODE_STEREO;
+      elif modeBits == 1:
+         self.mode = MODE_JOINT_STEREO;
+      elif modeBits == 2:
+         self.mode = MODE_DUAL_CHANNEL_STEREO;
+      else:
+         self.mode = MODE_MONO;
+      self.modeExtension = (header >> 4) & 0x3; 
+
+      # Layer II has restrictions wrt to mode and bit rate.  This code
+      # enforces them.
+      if self.layer == 2:
+         m = self.mode;
+         br = self.bitRate;
+         if (br == 32 or br == 48 or br == 56 or br == 80) and \
+            (m != MODE_MONO):
+            raise Mp3Exception("Invalid mode/bitrate combination for layer "\
+                               "II");
+         if (br == 224 or br == 256 or br == 320 or br == 384) and \
+            (m == MODE_MONO):
+            raise Mp3Exception("Invalid mode/bitrate combination for layer "\
+                               "II");
+
+      br = self.bitRate * 1000;
+      sf = self.sampleFreq;
+      p  = self.padding;
+      if self.layer == 1:
+         # Layer 1 uses 32 bit slots for padding.
+         p  = self.padding * 4;
+         self.frameLength = int((((12 * br) / sf) + p) * 4);
+      else:
+         # Layer 2 and 3 uses 8 bit slots for padding.
+         p  = self.padding * 1;
+         self.frameLength = int(((144 * br) / sf) + p);
+
+      # Dump the state.
+      TRACE_MSG("MPEG audio version: " + str(self.version));
+      TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
+      TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
+      TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
+      TRACE_MSG("MPEG channel mode: " + self.mode);
+      TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
+      TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
+      TRACE_MSG("MPEG original: " + str(self.original));
+      TRACE_MSG("MPEG copyright: " + str(self.copyright));
+      TRACE_MSG("MPEG private bit: " + str(self.privateBit));
+      TRACE_MSG("MPEG padding: " + str(self.padding));
+      TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
+      TRACE_MSG("MPEG frame length: " + str(self.frameLength));
+
+#######################################################################
+class XingHeader:
+   numFrames = int();
+   numBytes = int();
+   toc = [0] * 100;
+   vbrScale = int();
+
+   # Pass in the first mp3 frame from the file as a byte string.
+   # If an Xing header is present in the file it'll be in the first mp3
+   # frame.  This method returns true if the Xing header is found in the
+   # frame, and false otherwise.
+   def decode(self, frame):
+      # mp3 version
+      id      = (ord(frame[1]) >> 3) & 0x1;
+      # channel mode.
+      mode    = (ord(frame[3]) >> 6) & 0x3;
+
+      # Find the start of the Xing header.
+      if id:
+         if mode != 3:
+            pos = 32 + 4;
+         else:
+            pos = 17 + 4;
+      else:
+         if mode != 3:
+            pos = 17 + 4;
+         else:
+            pos = 9 + 4;
+      if frame[pos] != 'X' or frame[pos + 1] != 'i' or \
+         frame[pos + 2] != 'n' or frame[pos + 3] != 'g':
+         return 0;
+      TRACE_MSG("Xing header detected");
+      pos += 4;
+
+      # Read Xing flags.
+      headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
+      pos += 4;
+      TRACE_MSG("Xing header flags: 0x%x" % headFlags);
+
+      # Read frames header flag and value if present
+      if headFlags & FRAMES_FLAG:
+         self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing numFrames: %d" % self.numFrames);
+
+      # Read bytes header flag and value if present
+      if headFlags & BYTES_FLAG:
+         self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing numBytes: %d" % self.numBytes);
+
+      # Read TOC header flag and value if present
+      if headFlags & TOC_FLAG:
+         i = 0;
+         self.toc = frame[pos:pos + 100];
+         pos += 100;
+         TRACE_MSG("Xing TOC (100 bytes): PRESENT");
+      else:
+         TRACE_MSG("Xing TOC (100 bytes): NOT PRESENT");
+
+      # Read vbr scale header flag and value if present
+      if headFlags & VBR_SCALE_FLAG:
+         self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
+         pos += 4;
+         TRACE_MSG("Xing vbrScale: %d" % self.vbrScale);
+
+      return 1;
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/utils.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/utils.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyeD3/utils.py	(revision 4)
@@ -0,0 +1,85 @@
+################################################################################
+#  Copyright (C) 2003-2004  Travis Shirk <travis@pobox.com>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#  $Id: utils.py,v 1.3 2004/05/14 14:44:59 outlyer Exp $
+################################################################################
+from mmpython.audio.eyeD3 import *
+
+def versionsToConstant(v):
+   major = v[0];
+   minor = v[1];
+   rev = v[2];
+   if major == 1:
+      if minor == 0:
+	 return ID3_V1_0;
+      elif minor == 1:
+	 return ID3_V1_1;
+   elif major == 2:
+      if minor == 3:
+	 return ID3_V2_3;
+      elif minor == 4:
+	 return ID3_V2_4;
+   raise str("Invalid ID3 version: %s" % str(v));
+
+def versionToString(v):
+   if v & ID3_V1:
+      if v == ID3_V1_0:
+	 return "v1.0";
+      elif v == ID3_V1_1:
+	 return "v1.1";
+      elif v == ID3_V1:
+         return "v1.x";
+   elif v & ID3_V2:
+      if v == ID3_V2_3:
+	 return "v2.3";
+      elif v == ID3_V2_4:
+	 return "v2.4";
+      elif v == ID3_V2:
+         return "v2.x";
+
+   if v == ID3_ANY_VERSION:
+      return "v1.x/v2.x";
+   raise str("versionToString - Invalid ID3 version constant: %s" % hex(v));
+
+def constantToVersions(v):
+   if v & ID3_V1:
+      if v == ID3_V1_0:
+         return [1, 0, 0];
+      elif v == ID3_V1_1:
+         return [1, 1, 0];
+      elif v == ID3_V1:
+         return [1, 1, 0];
+   elif v & ID3_V2:
+      if v == ID3_V2_3:
+         return [2, 3, 0];
+      elif v == ID3_V2_4:
+         return [2, 4, 0];
+      elif v == ID3_V2:
+         return [2, 4, 0];
+   raise str("constantToVersions - Invalid ID3 version constant: %s" % hex(v));
+
+################################################################################
+TRACE = 0;
+prefix = "eyeD3 trace> ";
+def TRACE_MSG(msg):
+   if TRACE:
+      print prefix + msg;
+
+STRICT_ID3 = 0;
+def strictID3():
+   return STRICT_ID3;
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyed3info.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyed3info.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/eyed3info.py	(revision 4)
@@ -0,0 +1,331 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: eyed3info.py,v 1.16 2005/01/01 14:18:11 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: eyed3info.py,v $
+# Revision 1.16  2005/01/01 14:18:11  dischi
+# add samplerate, bitrate and mode
+#
+# Revision 1.15  2004/09/09 02:45:58  outlyer
+# Add the TPOS tag for multiple disc sets.
+#
+# Revision 1.14  2004/07/21 18:54:36  outlyer
+# Big bugfix.
+#
+# If a mp3 lacks a genre, then nothing after the genre parsing works. This breaks
+# calculating the length, among other things because it's all in a try except, so
+# self.length takes on a random value. I was getting track lengths like 20000 seconds
+# until I made this change.
+#
+# Revision 1.13  2004/07/11 12:06:03  dischi
+# add genre parsing
+#
+# Revision 1.12  2004/07/07 09:35:50  dischi
+# remove guessing of tracknum in TCON
+#
+# Revision 1.11  2004/05/29 12:31:36  dischi
+# try to find trackof in TCON or trackno
+#
+# Revision 1.10  2004/02/08 17:42:56  dischi
+# reduce debug
+#
+# Revision 1.9  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.8  2003/07/10 13:05:05  the_krow
+# o id3v2 tabled added to eyed3
+# o type changed to MUSIC
+#
+# Revision 1.7  2003/07/02 20:15:42  dischi
+# return nothing, not 0
+#
+# Revision 1.6  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/30 11:38:22  dischi
+# bugfix
+#
+# Revision 1.4  2003/06/29 18:30:14  dischi
+# many many fixes
+#
+# Revision 1.3  2003/06/29 12:03:41  dischi
+# fixed it to be _real_ eyed3 info
+#
+# Revision 1.2  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.1  2003/06/09 23:13:21  the_krow
+# bugfix: unknown files are now resetted before trying if they are valid
+# first rudimentary eyed3 mp3 parser added
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, et. al
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Most of the code of this module was taken from Vivake Guptas mp3info
+# code. Below is his copyright notice. All credit to him.
+#
+# Copyright (c) 2002 Vivake Gupta (vivakeATomniscia.org).  All rights reserved.
+# This software is maintained by Vivake (vivakeATomniscia.org) and is available at:
+#     http://www.omniscia.org/~vivake/python/MP3Info.py
+#
+#
+
+
+from mmpython import mediainfo
+import mmpython
+
+from eyeD3 import tag as eyeD3_tag
+from eyeD3 import frames as eyeD3_frames
+
+import os
+import struct
+import traceback
+import id3 as id3info
+
+MP3_INFO_TABLE = { "APIC": "picture",
+                   "LINK": "link",
+                   "TALB": "album",
+                   "TCOM": "composer",
+                   "TCOP": "copyright",
+                   "TDOR": "release",
+                   "TYER": "date",
+                   "TEXT": "text",
+                   "TIT2": "title",
+                   "TLAN": "language",
+                   "TLEN": "length",
+                   "TMED": "media_type",
+                   "TPE1": "artist",
+                   "TPE2": "artist",
+                   "TRCK": "trackno",
+                   "TPOS": "discs"}
+
+_bitrates = [
+    [ # MPEG-2 & 2.5
+        [0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,None], # Layer 1
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None], # Layer 2
+        [0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,None]  # Layer 3
+    ],
+
+    [ # MPEG-1
+        [0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,None], # Layer 1
+        [0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,None], # Layer 2
+        [0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,None]  # Layer 3
+    ]
+]
+
+_samplerates = [
+    [ 11025, 12000,  8000, None], # MPEG-2.5
+    [  None,  None,  None, None], # reserved
+    [ 22050, 24000, 16000, None], # MPEG-2
+    [ 44100, 48000, 32000, None], # MPEG-1
+]
+
+_modes = [ "stereo", "joint stereo", "dual channel", "mono" ]
+
+_MP3_HEADER_SEEK_LIMIT = 4096
+
+class eyeD3Info(mediainfo.MusicInfo):
+   
+   fileName       = str();
+   fileSize       = int();
+   
+   def __init__(self, file, tagVersion = eyeD3_tag.ID3_ANY_VERSION):
+      mediainfo.MusicInfo.__init__(self)
+      self.fileName = file.name;
+      self.valid = 1
+      self.mime = 'audio/mp3'
+
+      if not eyeD3_tag.isMp3File(file.name):
+         self.valid = 0
+         return
+
+      id3 = None
+      try:
+         id3 = eyeD3_tag.Mp3AudioFile(file.name)
+      except eyeD3_tag.TagException:
+         try:
+            id3 = eyeD3_tag.Mp3AudioFile(file.name)
+         except eyeD3_tag.InvalidAudioFormatException:
+            # File is not an MP3
+            self.valid = 0
+            return
+         except:
+            # The MP3 tag decoder crashed, assume the file is still
+            # MP3 and try to play it anyway
+            if mediainfo.DEBUG:
+               print 'music: oops, mp3 tag parsing failed!'
+               print 'music: filename = "%s"' % file.name
+               traceback.print_exc()
+      except:
+         # The MP3 tag decoder crashed, assume the file is still
+         # MP3 and try to play it anyway
+         if mediainfo.DEBUG:
+            print 'music: oops, mp3 tag parsing failed!'
+            print 'music: filename = "%s"' % file.name
+            traceback.print_exc()
+
+      if not self.valid:
+         return
+
+      if mediainfo.DEBUG > 1:
+         print id3.tag.frames
+      try:
+         if id3 and id3.tag:
+            for k in MP3_INFO_TABLE:
+               if id3.tag.frames[k]:
+                  if k == 'APIC':
+                     pass 
+                  else:
+                     setattr(self, MP3_INFO_TABLE[k], id3.tag.frames[k][0].text)
+            if id3.tag.getYear():
+               self.date = id3.tag.getYear()
+            tab = {}
+            for f in id3.tag.frames:
+                if f.__class__ is eyeD3_frames.TextFrame:                
+                    tab[f.header.id] = f.text
+                elif f.__class__ is eyeD3_frames.UserTextFrame:
+                    tab[f.header.id] = f.text
+                elif f.__class__ is eyeD3_frames.DateFrame:
+                    tab[f.header.id] = f.date_str
+                elif f.__class__ is eyeD3_frames.CommentFrame:
+                    tab[f.header.id] = f.comment
+                elif f.__class__ is eyeD3_frames.URLFrame:
+                    tab[f.header.id] = f.url
+                elif f.__class__ is eyeD3_frames.UserURLFrame:
+                    tab[f.header.id] = f.url
+                elif mediainfo.DEBUG:
+                   print f.__class__
+            self.appendtable('id3v2', tab, 'en')
+
+            if id3.tag.frames['TCON']:
+               genre = None
+               tcon = id3.tag.frames['TCON'][0].text
+               try:
+                  genre = int(tcon)
+               except:
+                  try:
+                      genre = int(tcon[1:tcon.find(')')])
+                  except ValueError:
+                      pass
+               if genre is not None:
+                  try:
+                     self.genre = id3info.GENRE_LIST[genre]
+                  except:
+                     pass
+            # and some tools store it as trackno/trackof in TRCK
+            if not self['trackof'] and self['trackno'] and self['trackno'].find('/') > 0:
+                self['trackof'] = self['trackno'][self['trackno'].find('/')+1:]
+                self['trackno'] = self['trackno'][:self['trackno'].find('/')]
+         if id3:
+            self.length = id3.getPlayTime()
+      except:
+         if mediainfo.DEBUG:
+            traceback.print_exc()
+      offset, header = self._find_header(file)
+      if offset == -1 or header is None:
+         return
+
+      self._parse_header(header)
+      
+
+   def _find_header(self, file):
+      file.seek(0, 0)
+      amount_read = 0
+      
+      # see if we get lucky with the first four bytes
+      amt = 4
+      
+      while amount_read < _MP3_HEADER_SEEK_LIMIT:
+         header = file.read(amt)
+         if len(header) < amt:
+            # awfully short file. just give up.
+            return -1, None
+
+         amount_read = amount_read + len(header)
+         
+         # on the next read, grab a lot more
+         amt = 500
+         
+         # look for the sync byte
+         offset = header.find(chr(255))
+         if offset == -1:
+            continue
+             
+         # looks good, make sure we have the next 3 bytes after this
+         # because the header is 4 bytes including sync
+         if offset + 4 > len(header):
+            more = file.read(4)
+            if len(more) < 4:
+               # end of file. can't find a header
+               return -1, None
+            amount_read = amount_read + 4
+            header = header + more
+
+         # the sync flag is also in the next byte, the first 3 bits
+         # must also be set
+         if ord(header[offset+1]) >> 5 != 7:
+            continue
+
+         # ok, that's it, looks like we have the header
+         return amount_read - len(header) + offset, header[offset:offset+4]
+
+      # couldn't find the header
+      return -1, None
+
+
+   def _parse_header(self, header):
+      # http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+      bytes = struct.unpack('>i', header)[0]
+      mpeg_version =    (bytes >> 19) & 3
+      layer =           (bytes >> 17) & 3
+      bitrate =         (bytes >> 12) & 15
+      samplerate =      (bytes >> 10) & 3
+      mode =            (bytes >> 6)  & 3
+
+      if mpeg_version == 0:
+         self.version = 2.5
+      elif mpeg_version == 2:
+         self.version = 2
+      elif mpeg_version == 3:
+         self.version = 1
+      else:
+         return
+
+      if layer > 0:
+         layer = 4 - layer
+      else:
+         return
+
+      self.bitrate = _bitrates[mpeg_version & 1][layer - 1][bitrate]
+      self.samplerate = _samplerates[mpeg_version][samplerate]
+
+      if self.bitrate is None or self.samplerate is None:
+         return
+
+      self.mode = _modes[mode]
+      self.keys.append('mode')
+
+
+mmpython.registertype( 'audio/mp3', ('mp3',), mediainfo.TYPE_MUSIC, eyeD3Info )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ogginfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ogginfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/ogginfo.py	(revision 4)
@@ -0,0 +1,171 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: ogginfo.py,v 1.16 2004/05/18 21:56:18 dischi Exp $
+# -----------------------------------------------------------------------
+# $Log: ogginfo.py,v $
+# Revision 1.16  2004/05/18 21:56:18  dischi
+# do not pare the whole file to get the length
+#
+# Revision 1.15  2003/09/22 16:21:20  the_krow
+# o ogg parsing should basically work
+# o utf-8 for vorbis comments
+#
+# Revision 1.14  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.13  2003/06/29 12:03:15  dischi
+# make some debug silent
+#
+# Revision 1.12  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.11  2003/06/10 11:17:39  the_krow
+# - OGG Fixes
+# - changed one DiscInfo reference in vcdinfo I missed before
+#
+# Revision 1.10  2003/06/08 19:53:38  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.9  2003/06/08 13:44:56  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.8  2003/06/08 13:11:25  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.7  2003/06/07 23:32:11  the_krow
+# changed names to new format
+# debug messages
+#
+# Revision 1.6  2003/05/13 15:23:59  the_krow
+# IPTC
+#
+# Revision 1.5  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import os, stat
+import struct
+
+from mmpython import mediainfo
+import mmpython
+
+VORBIS_PACKET_INFO = '\01vorbis'
+VORBIS_PACKET_HEADER = '\03vorbis'
+VORBIS_PACKET_SETUP = '\05vorbis'
+
+_print = mediainfo._debug
+
+class OggInfo(mediainfo.MusicInfo):
+    def __init__(self,file):
+        mediainfo.MusicInfo.__init__(self)
+        h = file.read(4+1+1+20+1)
+        if h[:5] != "OggS\00":
+            _print("Invalid header")
+            self.valid = 0
+            return
+        if ord(h[5]) != 2:
+            _print("Invalid header type flag (trying to go ahead anyway)")
+        self.pageSegCount = ord(h[-1])
+        # Skip the PageSegCount
+        file.seek(self.pageSegCount,1)
+        h = file.read(7)
+        if h != VORBIS_PACKET_INFO:
+            _print("Wrong vorbis header type, giving up.")
+            self.valid = 0
+            return
+        self.valid = 1
+        self.mime = 'application/ogg'
+        header = {}
+        info = file.read(23)
+        self.version, self.channels, self.samplerate, bitrate_max, self.bitrate, bitrate_min, blocksize, framing = struct.unpack('<IBIiiiBB',info[:23])
+        # INFO Header, read Oggs and skip 10 bytes
+        h = file.read(4+10+13)        
+        if h[:4] == 'OggS':
+            (serial, pagesequence, checksum, numEntries) = struct.unpack( '<14xIIIB', h )
+            # skip past numEntries
+            file.seek(numEntries,1)
+            h = file.read(7)
+            if h != VORBIS_PACKET_HEADER:
+                # Not a corrent info header
+                return                        
+            self.encoder = self._extractHeaderString(file)
+            numItems = struct.unpack('<I',file.read(4))[0]
+            for i in range(numItems):
+                s = self._extractHeaderString(file)
+                a = re.split('=',s)
+                header[(a[0]).upper()]=a[1]
+            # Put Header fields into info fields
+            if header.has_key('TITLE'):
+                self.title = header['TITLE']
+            if header.has_key('ALBUM'):
+                self.album = header['ALBUM']
+            if header.has_key('ARTIST'):
+                self.artist = header['ARTIST']            
+            if header.has_key('COMMENT'):
+                self.comment = header['COMMENT']
+            if header.has_key('DATE'):
+                self.date = header['DATE']
+            if header.has_key('ENCODER'):
+                self.encoder = header['ENCODER']
+            if header.has_key('TRACKNUMBER'):
+                self.trackno = header['TRACKNUMBER']
+            self.type = 'OGG Vorbis'
+            self.subtype = ''
+            self.length = self._calculateTrackLength(file)
+            self.appendtable('VORBISCOMMENT',header)
+                                            
+    def _extractHeaderString(self,f):
+        len = struct.unpack( '<I', f.read(4) )[0]
+        return unicode(f.read(len), 'utf-8')
+    
+
+    def _calculateTrackLength(self,f):
+        # seek to the end of the stream, to avoid scanning the whole file
+        if (os.stat(f.name)[stat.ST_SIZE] > 20000):
+            f.seek(os.stat(f.name)[stat.ST_SIZE]-10000)
+
+        # read the rest of the file into a buffer
+        h = f.read()
+        granule_position = 0
+        # search for each 'OggS' in h        
+        if len(h):
+            idx = h.rfind('OggS')
+            if idx < 0:
+                return 0
+            pageSize = 0
+            h = h[idx+4:]
+            (check, type, granule_position, absPos, serial, pageN, crc, segs) = struct.unpack( '<BBIIIIIB', h[:23] )            
+            if check != 0:
+                _print(h[:10])
+                return
+            _print("granule = %d / %d" % (granule_position, absPos))
+        # the last one is the one we are interested in
+        return (granule_position / self.samplerate)
+
+mmpython.registertype( 'application/ogg', ('ogg',), mediainfo.TYPE_MUSIC, OggInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/webradioinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/webradioinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/audio/webradioinfo.py	(revision 4)
@@ -0,0 +1,125 @@
+#if 0
+# -----------------------------------------------------------------------
+# $Id: webradioinfo.py,v 1.7 2003/07/02 11:17:29 the_krow Exp $
+# -----------------------------------------------------------------------
+# $Log: webradioinfo.py,v $
+# Revision 1.7  2003/07/02 11:17:29  the_krow
+# language is now part of the table key
+#
+# Revision 1.6  2003/06/30 13:17:18  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/24 14:37:17  dischi
+# small fix
+#
+# Revision 1.4  2003/06/24 13:52:06  the_krow
+# 302 Handling is done by urllib so no further code for this is
+# needed. Thanks to den_RDC for setting up a server to test it.
+#
+# Revision 1.3  2003/06/24 13:06:46  the_krow
+# stream is being closed in fail-cases.
+#
+# Revision 1.2  2003/06/24 12:59:33  the_krow
+# Added Webradio.
+# Added Stream Type to mediainfo
+#
+# Revision 1.1  2003/06/23 22:23:16  the_krow
+# First Import. Not yet integrated.
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import urlparse
+import string
+import urllib
+
+from mmpython import mediainfo
+import mmpython
+
+_print = mediainfo._debug
+
+# http://205.188.209.193:80/stream/1006
+
+ICY_tags = { 'title': 'icy-name',
+             'genre': 'icy-genre',
+             'bitrate': 'icy-br',
+             'caption': 'icy-url',
+           }
+
+class WebRadioInfo(mediainfo.MusicInfo):
+    def __init__(self, url):
+        mediainfo.MusicInfo.__init__(self)
+        tup = urlparse.urlsplit(url)
+        scheme, location, path, query, fragment = tup
+        if scheme != 'http':
+            self.valid = 0
+            return
+        # Open an URL Connection
+        fi = urllib.urlopen(url)        
+
+        # grab the statusline
+        self.statusline = fi.readline()
+        try:
+            statuslist = string.split(self.statusline)
+        except ValueError:
+            # assume it is okay since so many servers are badly configured
+            statuslist = ["ICY", "200"]
+                    
+        if statuslist[1] != "200":
+            self.valid = 0
+            if fi:
+                fi.close()
+            return
+
+        self.valid = 1
+        self.type = 'audio'
+        self.subtype = 'mp3'
+        # grab any headers for a max of 10 lines
+        linecnt = 0
+        tab = {}
+        lines = fi.readlines(512)        
+        for linecnt in range(0,11):
+            icyline = lines[linecnt]
+            icyline = icyline.rstrip('\r\n')
+            if len(icyline) < 4:
+                break
+            cidx = icyline.find(':')
+            if cidx != -1:
+                # break on short line (ie. really should be a blank line)
+                # strip leading and trailing whitespace                
+                tab[icyline[:cidx].strip()] = icyline[cidx+2:].strip()
+        if fi:
+            fi.close()
+        self.appendtable('ICY', tab)
+        self.tag_map = { ('ICY', 'en') : ICY_tags }
+        # Copy Metadata from tables into the main set of attributes        
+        for k in self.tag_map.keys():
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),self.tag_map[k][x]), self.tag_map[k].keys())
+        self.bitrate = string.atoi(self.bitrate)*1000        
+
+mmpython.registertype( 'text/plain', mediainfo.EXTENSION_STREAM, mediainfo.TYPE_MUSIC, WebRadioInfo )
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/.cvsignore
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/.cvsignore	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/.cvsignore	(revision 4)
@@ -0,0 +1,2 @@
+*.pyc *.html
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/generate
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/generate	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/doc/generate	(revision 4)
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# doc.sh 
+#
+# Dirk Meyer  <dmeyer@tzi.de>
+# $Id: generate,v 1.1 2003/06/08 17:33:59 dischi Exp $
+
+cd `dirname $0`
+
+export PYTHONPATH=../..:$PYTHONPATH
+
+files=`find .. -name \*.py | sed 's/\.py//' | sed 's/^..\//mmpython\//' |\
+     sed 's/\//./g' | sed 's/\.$//' | egrep -v '(build\.|setup|mediatest|cachedir)'`
+
+dirs=`find .. -name __init__.py | grep -v build | sed 's/.__init__.py//' |\
+    sed 's/^..\//mmpython\//' | sed 's/\//./g' | grep -v \\.\\.`
+
+pydoc -w mmpython $files $dirs
+
+# end of doc.sh 
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/asfinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/asfinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/asfinfo.py	(revision 4)
@@ -0,0 +1,374 @@
+#if 0
+# $Id: asfinfo.py,v 1.18 2004/01/31 12:37:25 dischi Exp $
+# $Log: asfinfo.py,v $
+# Revision 1.18  2004/01/31 12:37:25  dischi
+# remove bad chars
+#
+# Revision 1.17  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.16  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.15  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.14  2003/06/12 14:43:21  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+# Revision 1.13  2003/06/12 10:42:47  the_krow
+# Added Bitrate, Extended Info
+# Still need to identify streams by their streamid
+#
+# Revision 1.12  2003/06/12 09:38:24  the_krow
+# ASF Header parser completed. I need test files or a way to generate
+# them.
+#
+# Revision 1.11  2003/06/12 00:36:30  the_krow
+# ASF Audio parsing
+#
+# Revision 1.10  2003/06/12 00:27:25  the_krow
+# More asf parsing: Width, Height, Video Codec
+#
+# Revision 1.9  2003/06/11 20:51:00  the_krow
+# Title, Artist and some other data sucessfully parsed from wmv, asf, wma
+#
+# Revision 1.8  2003/06/11 19:07:57  the_krow
+# asf,wmv,wma now get the guids right...
+#
+# Revision 1.7  2003/06/11 16:11:08  the_krow
+# asf parsing... asf is really an ugly format.
+#
+# Revision 1.6  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 15:40:26  dischi
+# catch exception, raised for small text files
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import fourcc
+import mmpython
+
+from mmpython import mediainfo
+
+def _guid(input):
+    # Remove any '-'
+    s = string.join(string.split(input,'-'), '')
+    r = ''
+    if len(s) != 32:
+        return ''
+    x = ''
+    for i in range(0,16):
+        r+=chr(int(s[2*i:2*i+2],16))
+    guid = struct.unpack('>IHHBB6s',r)
+    return guid
+
+GUIDS = {        
+'ASF_Header_Object' : _guid('75B22630-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Data_Object' : _guid('75B22636-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Simple_Index_Object' : _guid('33000890-E5B1-11CF-89F4-00A0C90349CB'),
+'ASF_Index_Object' : _guid('D6E229D3-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Media_Object_Index_Object' : _guid('FEB103F8-12AD-4C64-840F-2A1D2F7AD48C'),
+'ASF_Timecode_Index_Object' : _guid('3CB73FD0-0C4A-4803-953D-EDF7B6228F0C'),
+
+'ASF_File_Properties_Object' : _guid('8CABDCA1-A947-11CF-8EE4-00C00C205365'),
+'ASF_Stream_Properties_Object' : _guid('B7DC0791-A9B7-11CF-8EE6-00C00C205365'),
+'ASF_Header_Extension_Object' : _guid('5FBF03B5-A92E-11CF-8EE3-00C00C205365'),
+'ASF_Codec_List_Object' : _guid('86D15240-311D-11D0-A3A4-00A0C90348F6'),
+'ASF_Script_Command_Object' : _guid('1EFB1A30-0B62-11D0-A39B-00A0C90348F6'),
+'ASF_Marker_Object' : _guid('F487CD01-A951-11CF-8EE6-00C00C205365'),
+'ASF_Bitrate_Mutual_Exclusion_Object' : _guid('D6E229DC-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Error_Correction_Object' : _guid('75B22635-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Content_Description_Object' : _guid('75B22633-668E-11CF-A6D9-00AA0062CE6C'),
+'ASF_Extended_Content_Description_Object' : _guid('D2D0A440-E307-11D2-97F0-00A0C95EA850'),
+'ASF_Content_Branding_Object' : _guid('2211B3FA-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Stream_Bitrate_Properties_Object' : _guid('7BF875CE-468D-11D1-8D82-006097C9A2B2'),
+'ASF_Content_Encryption_Object' : _guid('2211B3FB-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Extended_Content_Encryption_Object' : _guid('298AE614-2622-4C17-B935-DAE07EE9289C'),
+'ASF_Alt_Extended_Content_Encryption_Obj' : _guid('FF889EF1-ADEE-40DA-9E71-98704BB928CE'),
+'ASF_Digital_Signature_Object' : _guid('2211B3FC-BD23-11D2-B4B7-00A0C955FC6E'),
+'ASF_Padding_Object' : _guid('1806D474-CADF-4509-A4BA-9AABCB96AAE8'),
+
+'ASF_Extended_Stream_Properties_Object' : _guid('14E6A5CB-C672-4332-8399-A96952065B5A'),
+'ASF_Advanced_Mutual_Exclusion_Object' : _guid('A08649CF-4775-4670-8A16-6E35357566CD'),
+'ASF_Group_Mutual_Exclusion_Object' : _guid('D1465A40-5A79-4338-B71B-E36B8FD6C249'),
+'ASF_Stream_Prioritization_Object' : _guid('D4FED15B-88D3-454F-81F0-ED5C45999E24'),
+'ASF_Bandwidth_Sharing_Object' : _guid('A69609E6-517B-11D2-B6AF-00C04FD908E9'),
+'ASF_Language_List_Object' : _guid('7C4346A9-EFE0-4BFC-B229-393EDE415C85'),
+'ASF_Metadata_Object' : _guid('C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA'),
+'ASF_Metadata_Library_Object' : _guid('44231C94-9498-49D1-A141-1D134E457054'),
+'ASF_Index_Parameters_Object' : _guid('D6E229DF-35DA-11D1-9034-00A0C90349BE'),
+'ASF_Media_Object_Index_Parameters_Obj' : _guid('6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7'),
+'ASF_Timecode_Index_Parameters_Object' : _guid('F55E496D-9797-4B5D-8C8B-604DFE9BFB24'),
+
+'ASF_Audio_Media' : _guid('F8699E40-5B4D-11CF-A8FD-00805F5C442B'),
+'ASF_Video_Media' : _guid('BC19EFC0-5B4D-11CF-A8FD-00805F5C442B'),
+'ASF_Command_Media' : _guid('59DACFC0-59E6-11D0-A3AC-00A0C90348F6'),
+'ASF_JFIF_Media' : _guid('B61BE100-5B4E-11CF-A8FD-00805F5C442B'),
+'ASF_Degradable_JPEG_Media' : _guid('35907DE0-E415-11CF-A917-00805F5C442B'),
+'ASF_File_Transfer_Media' : _guid('91BD222C-F21C-497A-8B6D-5AA86BFC0185'),
+'ASF_Binary_Media' : _guid('3AFB65E2-47EF-40F2-AC2C-70A90D71D343'),
+
+'ASF_Web_Stream_Media_Subtype' : _guid('776257D4-C627-41CB-8F81-7AC7FF1C40CC'),
+'ASF_Web_Stream_Format' : _guid('DA1E6B13-8359-4050-B398-388E965BF00C'),
+
+'ASF_No_Error_Correction' : _guid('20FB5700-5B55-11CF-A8FD-00805F5C442B'),
+'ASF_Audio_Spread' : _guid('BFC3CD50-618F-11CF-8BB2-00AA00B4E220'),
+}
+
+_print = mediainfo._debug
+
+class AsfInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/asf'
+        self.type = 'asf video'
+        h = file.read(30)
+        if len(h) < 30:
+            return
+        self.valid = 1
+        (guidstr,objsize,objnum,reserved1,reserved2) = struct.unpack('<16sQIBB',h)                
+        guid = self._parseguid(guidstr)
+        if (guid != GUIDS['ASF_Header_Object']):
+            self.valid = 0
+            return
+        if reserved1 != 0x01 or reserved2 != 0x02:
+            self.valid = 0
+        _print("asf header size: %d / %d objects" % (objsize,objnum))
+        header = file.read(objsize-30)
+        for i in range(0,objnum):
+            h = self._getnextheader(header)
+            header = header[h[1]:]
+            
+    def _printguid(self,guid):
+        r = "%.8X-%.4X-%.4X-%.2X%.2X-%s" % guid
+        return r 
+        
+    def _parseguid(self,string):
+        return struct.unpack('<IHHBB6s', string[:16])
+        
+    def _parsekv(self,s):
+        pos = 0    
+        (descriptorlen,) = struct.unpack('<H', s[pos:pos+2])
+        pos += 2
+        descriptorname = s[pos:pos+descriptorlen]
+        pos += descriptorlen
+        descriptortype, valuelen = struct.unpack('<HH', s[pos:pos+4])
+        pos += 4
+        descriptorvalue = s[pos:pos+valuelen]
+        pos += valuelen
+        value = None
+        if descriptortype == 0x0000:
+            # Unicode string
+            value = descriptorvalue
+        elif descriptortype == 0x0001:
+            # Byte Array
+            value = descriptorvalue
+        elif descriptortype == 0x0002:
+            # Bool (?)
+            value = struct.unpack('<I', descriptorvalue)[0] != 0
+        elif descriptortype == 0x0003:
+            # DWORD
+            value = struct.unpack('<I', descriptorvalue)[0]
+        elif descriptortype == 0x0004:
+            # QWORD
+            value = struct.unpack('<Q', descriptorvalue)[0]
+        elif descriptortype == 0x0005:
+            # WORD
+            value = struct.unpack('<H', descriptorvalue)[0]
+        else:
+            _print("Unknown Descriptor Type %d" % descriptortype)
+        return (pos,descriptorname,value)
+
+    def _parsekv2(self,s):
+        pos = 0    
+        (strno,descriptorlen,descriptortype,valuelen) = struct.unpack('<2xHHHI', s[pos:pos+12])
+        pos += 12
+        descriptorname = s[pos:pos+descriptorlen]
+        pos += descriptorlen
+        descriptorvalue = s[pos:pos+valuelen]
+        pos += valuelen
+        value = None
+        #print "%d %s [%d]" % (strno, descriptorname, valuelen)
+        if descriptortype == 0x0000:
+            # Unicode string
+            value = descriptorvalue
+        elif descriptortype == 0x0001:
+            # Byte Array
+            value = descriptorvalue
+        elif descriptortype == 0x0002:
+            # Bool
+            value = struct.unpack('<H', descriptorvalue)[0] != 0
+            pass
+        elif descriptortype == 0x0003:
+            # DWORD
+            value = struct.unpack('<I', descriptorvalue)[0]
+        elif descriptortype == 0x0004:
+            # QWORD
+            value = struct.unpack('<Q', descriptorvalue)[0]
+        elif descriptortype == 0x0005:
+            # WORD
+            value = struct.unpack('<H', descriptorvalue)[0]
+        else:
+            _print("Unknown Descriptor Type %d" % descriptortype)
+        return (pos,descriptorname,value,strno)
+
+        
+    def _getnextheader(self,s):
+        r = struct.unpack('<16sQ',s[:24])
+        (guidstr,objsize) = r
+        guid = self._parseguid(guidstr)
+        if guid == GUIDS['ASF_File_Properties_Object']:
+            _print("File Properties Object")
+            val = struct.unpack('<16s6Q4I',s[24:24+80])
+            (fileid, size, date, packetcount, duration, \
+             senddur, preroll, flags, minpack, maxpack, maxbr) = \
+             val
+            self.length = duration/10000000
+        elif guid == GUIDS['ASF_Stream_Properties_Object']:
+            _print("Stream Properties Object [%d]" % objsize)                        
+            streamtype = self._parseguid(s[24:40])
+            errortype = self._parseguid(s[40:56])
+            offset, typelen, errorlen, flags = struct.unpack('>QIIH4x', s[56:78])
+            strno = flags & 63
+            encrypted = flags >> 15
+            if streamtype == GUIDS['ASF_Video_Media']:
+                vi = mediainfo.VideoInfo()
+                #vi.width, vi.height, formatsize = struct.unpack('<IIxH', s[78:89])
+                vi.width, vi.height, depth, codec, = struct.unpack('<4xII2xH4s', s[89:89+20])
+                vi.codec = fourcc.RIFFCODEC[codec]
+                vi.id = strno
+                self.video.append(vi)  
+            elif streamtype == GUIDS['ASF_Audio_Media']:
+                ai = mediainfo.AudioInfo()
+                twocc, ai.channels, ai.samplerate, bitrate, block, ai.samplebits, = struct.unpack('<HHIIHH', s[78:78+16])
+                ai.bitrate = 8*bitrate  # XXX Is this right?
+                ai.codec = fourcc.RIFFWAVE[twocc]
+                ai.id = strno
+                self.audio.append(ai)  
+            pass
+        elif guid == GUIDS['ASF_Header_Extension_Object']:
+            _print("ASF_Header_Extension_Object %d" % objsize)
+            size = struct.unpack('<I',s[42:46])[0]
+            data = s[46:46+size]
+            while len(data):
+                _print("Sub:")
+                h = self._getnextheader(data)
+                data = data[h[1]:]
+            
+        elif guid == GUIDS['ASF_Codec_List_Object']:
+            _print("List Object")
+            pass
+        elif guid == GUIDS['ASF_Error_Correction_Object']:
+            _print("Error Correction")
+            pass
+        elif guid == GUIDS['ASF_Content_Description_Object']:
+            _print("Content Description Object")
+            val = struct.unpack('<5H', s[24:24+10])
+            pos = 34
+            strings = []
+            for i in val:
+                strings.append(s[pos:pos+i].replace('\0', '').lstrip().rstrip())
+                pos+=i
+            (self.title, self.artist, self.copyright, self.caption, rating) = tuple(strings)
+        elif guid == GUIDS['ASF_Extended_Content_Description_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            descriptor = {}
+            for i in range(0, count):
+                # Read additional content descriptors
+                d = self._parsekv(s[pos:])
+                pos += d[0]
+                descriptor[d[1]] = d[2]
+            self.appendtable('ASFDESCRIPTOR', descriptor)
+        elif guid == GUIDS['ASF_Metadata_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            descriptor = {}
+            for i in range(0, count):
+                # Read additional content descriptors
+                d = self._parsekv2(s[pos:])
+                pos += d[0]
+                descriptor[d[1]] = d[2]
+            # TODO: Find the stream in self.audio and self.video and
+            #       append it there instead of here
+            self.appendtable('ASFMETADATA%d'%d[3], descriptor)
+        elif guid == GUIDS['ASF_Language_List_Object']:
+            count = struct.unpack('<H', s[24:26])[0]
+            pos = 26
+            lang = []
+            for i in range(0, count):
+                idlen = struct.unpack('<B', s[pos:pos+1])[0]
+                idstring = s[pos+1:pos+1+idlen]
+                _print("Language: %d/%d: %s" % (i+1, count, idstring))
+                lang.append(idstring)
+                pos += 1+idlen
+            if len(lang) == 1:
+                self.language = lang[0]
+            else:
+                self.language = tuple(lang)
+            # TODO: Find the stream in self.audio and self.video and
+            #       set it there instead of here
+        elif guid == GUIDS['ASF_Stream_Bitrate_Properties_Object']:
+            (count,) = struct.unpack('<H', s[24:26])
+            pos = 26
+            for i in range(0,count):
+                strno, avbitrate = struct.unpack('<HI', s[pos:pos+6])
+                strno &= 63
+                _print("Stream %d Bitrate: %d" % (strno, avbitrate))
+            # TODO: Find the stream in self.audio and self.video and
+            #       set it there instead of here
+        else:
+            # Just print the type:
+            bfail = 1
+            for h in GUIDS.keys():
+                if GUIDS[h] == guid:
+                    _print("Unparsed %s [%d]" % (h,objsize))
+                    bfail = 0
+            if bfail:
+                _print("unknown: %s [%d]" % (self._printguid(guid), objsize))
+        return r
+        
+mmpython.registertype( 'video/asf', ('asf','wmv','wma'), mediainfo.TYPE_AV, AsfInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movlanguages.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movlanguages.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movlanguages.py	(revision 4)
@@ -0,0 +1,109 @@
+QTLANGUAGES = {
+    0 : "en",
+    1 : "fr",
+    2 : "de",
+    3 : "it",
+    4 : "nl",
+    5 : "sv",
+    6 : "es",
+    7 : "da",
+    8 : "pt",
+    9 : "no",
+    10 : "he",
+    11 : "ja",
+    12 : "ar",
+    13 : "fi",
+    14 : "el",
+    15 : "is",
+    16 : "mt",
+    17 : "tr",
+    18 : "hr",
+    19 : "Traditional Chinese",
+    20 : "ur",
+    21 : "hi",
+    22 : "th",
+    23 : "ko",
+    24 : "lt",
+    25 : "pl",
+    26 : "hu",
+    27 : "et",
+    28 : "lv",
+    29 : "Lappish",
+    30 : "fo",
+    31 : "Farsi",
+    32 : "ru",
+    33 : "Simplified Chinese",
+    34 : "Flemish",
+    35 : "ga",
+    36 : "sq",
+    37 : "ro",
+    38 : "cs",
+    39 : "sk",
+    40 : "sl",
+    41 : "yi",
+    42 : "sr",
+    43 : "mk",
+    44 : "bg",
+    45 : "uk",
+    46 : "be",
+    47 : "uz",
+    48 : "kk",
+    49 : "az",
+    50 : "AzerbaijanAr",
+    51 : "hy",
+    52 : "ka",
+    53 : "mo",
+    54 : "ky",
+    55 : "tg",
+    56 : "tk",
+    57 : "mn",
+    58 : "MongolianCyr",
+    59 : "ps",
+    60 : "ku",
+    61 : "ks",
+    62 : "sd",
+    63 : "bo",
+    64 : "ne",
+    65 : "sa",
+    66 : "mr",
+    67 : "bn",
+    68 : "as",
+    69 : "gu",
+    70 : "pa",
+    71 : "or",
+    72 : "ml",
+    73 : "kn",
+    74 : "ta",
+    75 : "te",
+    76 : "si",
+    77 : "my",
+    78 : "Khmer",
+    79 : "lo",
+    80 : "vi",
+    81 : "id",
+    82 : "tl",
+    83 : "MalayRoman",
+    84 : "MalayArabic",
+    85 : "am",
+    86 : "ti",
+    87 : "om",
+    88 : "so",
+    89 : "sw",
+    90 : "Ruanda",
+    91 : "Rundi",
+    92 : "Chewa",
+    93 : "mg",
+    94 : "eo",
+    128 : "cy",
+    129 : "eu",
+    130 : "ca",
+    131 : "la",
+    132 : "qu",
+    133 : "gn",
+    134 : "ay",
+    135 : "tt",
+    136 : "ug",
+    137 : "Dzongkha",
+    138 : "JavaneseRom",
+}
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/vcdinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/vcdinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/vcdinfo.py	(revision 4)
@@ -0,0 +1,122 @@
+#if 0 /*
+# -----------------------------------------------------------------------
+# vcdinfo.py - parse vcd track informations from cue/bin files
+# -----------------------------------------------------------------------
+# $Id: vcdinfo.py,v 1.7 2004/06/25 13:20:34 dischi Exp $
+#
+# $Log: vcdinfo.py,v $
+# Revision 1.7  2004/06/25 13:20:34  dischi
+# FreeBSD patches
+#
+# Revision 1.6  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.5  2003/06/29 11:59:55  dischi
+# bugfix
+#
+# Revision 1.4  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.3  2003/06/10 11:17:39  the_krow
+# - OGG Fixes
+# - changed one DiscInfo reference in vcdinfo I missed before
+#
+# Revision 1.2  2003/06/10 10:56:54  the_krow
+# - Build try-except blocks around disc imports to make it run on platforms
+#   not compiling / running the C extensions.
+# - moved DiscInfo class to disc module
+# - changed video.VcdInfo to be derived from CollectionInfo instead of
+#   DiskInfo so it can be used without the cdrom extensions which are
+#   hopefully not needed for bin-files.
+#
+# Revision 1.1  2003/06/09 16:09:18  dischi
+# first version of a cue/bin vcd parser
+#
+#
+# -----------------------------------------------------------------------
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# ----------------------------------------------------------------------- */
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import os
+
+class VCDInfo(mediainfo.CollectionInfo):
+    def __init__(self, file):
+        mediainfo.CollectionInfo.__init__(self)
+        self.context = 'video'
+        self.offset = 0
+        self.valid = self.isVCD(file)
+        self.mime = 'video/vcd'
+        self.type = 'vcd video'        
+
+    def isVCD(self, file):
+        type = None
+
+        buffer = file.readline()
+
+        if not buffer[:6] == 'FILE "':
+            return 0
+
+        bin = os.path.join(os.path.dirname(file.name), buffer[6:buffer[6:].find('"')+6])
+        if not os.path.isfile(bin):
+            return 0
+
+        # At this point this really is a cue/bin disc
+        
+        # brute force reading of the bin to find out if it is a VCD
+        f = open(bin,'rb')
+        f.seek(32768, 0)
+        buffer = f.read(60000)
+        f.close()
+
+        if buffer.find('SVCD') > 0 and buffer.find('TRACKS.SVD') > 0 and \
+               buffer.find('ENTRIES.SVD') > 0:
+            type = 'SVCD'
+
+        elif buffer.find('INFO.VCD') > 0 and buffer.find('ENTRIES.VCD') > 0:
+            type = 'VCD'
+
+        else:
+            return 0
+
+        counter = 0
+        while 1:
+            buffer = file.readline()
+            if not len(buffer):
+                return 1
+            if buffer[:8] == '  TRACK ':
+                counter += 1
+                # the first track is the directory, that doesn't count
+                if counter > 1:
+                    vi = mediainfo.VideoInfo()
+                    if type == 'VCD':
+                        vi.codec = 'MPEG1'
+                    else:
+                        vi.codec = 'MPEG2'
+                    self.tracks.append(vi)
+
+
+mmpython.registertype( 'video/vcd', ('cue',), mediainfo.TYPE_AV, VCDInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mkvinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mkvinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mkvinfo.py	(revision 4)
@@ -0,0 +1,332 @@
+#if 0
+# -----------------------------------------------------------------------
+# mkvinfo.py - Matroska Streaming Video Files
+# -----------------------------------------------------------------------
+# $Id: mkvinfo.py,v 1.3 2004/04/18 17:55:26 dischi Exp $
+#
+# $Log: mkvinfo.py,v $
+# Revision 1.3  2004/04/18 17:55:26  dischi
+# update, including subtitle support
+#
+# Revision 1.2  2004/03/21 08:57:31  dischi
+# major bugfix
+#
+# Revision 1.1  2004/01/31 12:24:15  dischi
+# add basic matroska info
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import struct
+import re
+import stat
+import os
+import math
+from types import *
+from struct import *
+from string import *
+
+_print = mediainfo._debug
+
+# Main IDs for the Matroska streams
+MATROSKA_VIDEO_TRACK     = 0x01
+MATROSKA_AUDIO_TRACK     = 0x02
+MATROSKA_SUBTITLES_TRACK = 0x11
+
+MATROSKA_HEADER_ID  = 0x1A45DFA3
+MATROSKA_TRACKS_ID  = 0x1654AE6B
+MATROSKA_SEGMENT_ID = 0x18538067
+MATROSKA_SEGMENT_INFO_ID      = 0x1549A966
+MATROSKA_CLUSTER_ID           = 0x1F43B675
+MATROSKA_VOID_ID              = 0xEC
+MATROSKA_CRC_ID               = 0xBF
+MATROSKA_TIMECODESCALE_ID     = 0x2AD7B1
+MATROSKA_DURATION_ID          = 0x4489
+MATROSKA_CRC32_ID             = 0xBF
+MATROSKA_TRACK_TYPE_ID        = 0x83
+MATROSKA_TRACK_LANGUAGE_ID    = 0x22B59C
+MATROSKA_TIMECODESCALE_ID     = 0x4489
+MATROSKA_MUXING_APP_ID        = 0x4D80
+MATROSKA_WRITING_APP_ID       = 0x5741
+MATROSKA_CODEC_ID             = 0x86
+MATROSKA_CODEC_NAME_ID        = 0x258688
+MATROSKA_FRAME_DURATION_ID    = 0x23E383
+MATROSKA_VIDEO_SETTINGS_ID    = 0xE0
+MATROSKA_VID_WIDTH_ID         = 0xB0
+MATROSKA_VID_HEIGHT_ID        = 0xBA
+MATROSKA_AUDIO_SETTINGS_ID    = 0xE1
+MATROSKA_AUDIO_SAMPLERATE_ID  = 0xB5
+MATROSKA_AUDIO_CHANNELS_ID    = 0x9F
+MATROSKA_TRACK_UID_ID         = 0x73C5
+MATROSKA_TRACK_NUMBER_ID      = 0xD7
+
+# This is class that is responsible to handle one Ebml entity as described in the Matroska/Ebml spec
+class EbmlEntity:
+    def __init__(self, inbuf):
+        # Compute the EBML id
+        # Set the CRC len to zero
+        self.crc_len = 0
+        # Now loop until we find an entity without CRC
+        self.build_entity(inbuf)
+        while self.get_id() == MATROSKA_CRC32_ID:
+            self.crc_len += self.get_total_len()
+            inbuf = inbuf[self.get_total_len():]
+            self.build_entity(inbuf)
+
+    def build_entity(self, inbuf):
+        self.compute_id(inbuf)
+        #_print("Entity id : %08X" % self.entity_id)
+        if ( self.id_len == 0):
+            self.valid = 0
+            _print("EBML entity not found, bad file format")
+            return
+        self.valid = 1
+        self.entity_len = self.compute_len(inbuf[self.id_len:])
+        # Obviously, the segment can be very long (ie the whole file, so we truncate it at the read buffer size
+        if (self.entity_len == -1):
+            self.entity_data = inbuf[self.id_len+self.len_size:]
+            self.entity_len = len(self.entity_data) # Set the remaining size
+        else:
+            self.entity_data = inbuf[self.id_len+self.len_size:self.id_len+self.len_size+self.entity_len]
+        #_print("Entity len : %d" % self.entity_len)
+        # if the size is 1, 2 3 or 4 it could be a numeric value, so do the job
+        self.value = 0
+        if self.entity_len == 1:
+            self.value = ord(self.entity_data[0])
+        if self.entity_len == 2:
+            self.value = unpack('!H', self.entity_data)[0]
+        if self.entity_len == 3:
+            self.value = ord(self.entity_data[0])<<16 | ord(self.entity_data[1])<<8 | ord(self.entity_data[2])
+        if self.entity_len == 4:
+            self.value = unpack('!I', self.entity_data)[0]
+
+    def compute_id(self, inbuf):
+        first = ord(inbuf[0])
+        self.id_len = 0
+        if (first & 0x80):
+            self.id_len = 1
+            self.entity_id = first
+        elif (first & 0x40):
+            self.id_len = 2
+            self.entity_id = ord(inbuf[0])<<8 | ord(inbuf[1])
+        elif (first & 0x20):
+            self.id_len = 3
+            self.entity_id = (ord(inbuf[0])<<16) | (ord(inbuf[1])<<8) | (ord(inbuf[2]))
+        elif (first & 0x10):
+            self.id_len = 4
+            self.entity_id = (ord(inbuf[0])<<24) | (ord(inbuf[1])<<16) | (ord(inbuf[2])<<8) | (ord(inbuf[3]))
+        self.entity_str = inbuf[0:self.id_len]
+        return
+
+    def compute_len(self, inbuf):
+        # Here we just handle the size up to 4 bytes
+        # The size above will be truncated by the read buffer itself
+        first = ord(inbuf[0])
+        if (first & 0x80):
+            self.len_size = 1
+            return first - 0x80
+        if (first & 0x40):
+            self.len_size = 2
+            (c1,c2) = unpack('BB',inbuf[:2])
+            return ((c1-0x40)<<8) | (c2)
+        if (first & 0x20):
+            self.len_size = 3
+            (c1, c2, c3) = unpack('BBB',inbuf[:3])
+            return ((c1-0x20)<<16) | (c2<<8) | (c3)
+        if (first & 0x10):
+            self.len_size = 4
+            (len) = unpack('!I',inbuf[:4])
+            return len
+        if (first & 0x08):
+            self.len_size = 5
+            return -1
+        if (first & 0x04):
+            self.len_size = 6
+            return -1
+        if (first & 0x02):
+            self.len_size = 7
+            return -1
+        if (first & 0x01):
+            self.len_size = 8
+            return -1
+
+    def get_crc_len(self):
+        return self.crc_len
+
+    def get_value(self):
+        value = self.value
+        return value
+
+    def get_data(self):
+        return self.entity_data
+
+    def get_id(self):
+        return self.entity_id
+
+    def get_str_id(self):
+        return self.entity_str
+
+    def get_len(self):
+        return self.entity_len
+
+    def get_total_len(self):
+        return self.entity_len+self.id_len+self.len_size
+
+
+# This ithe main Matroska object
+class MkvInfo(mediainfo.AVInfo):
+    def __init__(self, file):
+        mediainfo.AVInfo.__init__(self)
+        self.samplerate = 1
+
+        buffer = file.read(80000)
+        if len(buffer) == 0:
+            # Regular File end
+            return None
+
+        # Check the Matroska header
+        header = EbmlEntity(buffer)
+        if ( header.get_id() == MATROSKA_HEADER_ID ):
+            _print("HEADER ID found %08X" % header.get_id() )
+            self.valid = 1
+            self.mime = 'application/mkv'
+            self.type = 'Matroska'
+            # Now get the segment
+            segment = EbmlEntity(buffer[header.get_total_len():])
+            if ( segment.get_id() == MATROSKA_SEGMENT_ID):
+                _print("SEGMENT ID found %08X" % segment.get_id() )
+                #MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
+                #'date', 'keywords', 'country', 'language', 'url']
+                segtab = self.process_one_level(segment)
+                seginfotab = self.process_one_level(segtab[MATROSKA_SEGMENT_INFO_ID])
+                try:
+                    # Express scalecode in ms instead of ns
+                    # Rescale it to the second
+                    scalecode = float(seginfotab[MATROSKA_TIMECODESCALE_ID].get_value() / (1000*1000))
+                except:
+                    scalecode = 1000
+                try:
+                    duration = float(unpack('!f', seginfotab[MATROSKA_DURATION_ID].get_data() )[0])
+                    duration = float(duration / scalecode)
+                    # Express the time in minutes
+                    self.length = int(duration/60)
+                except:
+                    pass
+                try:
+                    _print ("Searching for id : %X" % MATROSKA_TRACKS_ID)
+                    entity = segtab[MATROSKA_TRACKS_ID]
+                    self.process_tracks(entity)
+                except:
+                    _print("TRACKS ID not found !!" )
+            else:
+                _print("SEGMENT ID not found %08X" % segment.get_id() )
+        else:
+            self.valid = 0
+
+    def process_tracks(self, tracks):
+        tracksbuf = tracks.get_data()
+        indice = 0
+        while indice < tracks.get_len():
+            trackelem = EbmlEntity(tracksbuf[indice:])
+            _print ("ELEMENT %X found" % trackelem.get_id())
+            self.process_one_track(trackelem)
+            indice += trackelem.get_total_len() + trackelem.get_crc_len()
+
+    def process_one_level(self, item):
+        buf = item.get_data()
+        indice = 0
+        tabelem = {}
+        while indice < item.get_len():
+            elem = EbmlEntity(buf[indice:])
+            tabelem[elem.get_id()] = elem
+            indice += elem.get_total_len() + elem.get_crc_len()
+        return tabelem
+
+    def process_one_track(self, track):
+        # Process all the items at the track level
+        tabelem = self.process_one_level(track)
+        # We have the dict of track eleme, now build the MMPYTHON information
+        type = tabelem[MATROSKA_TRACK_TYPE_ID]
+        mytype = type.get_value()
+        _print ("Track type found with UID %d" % mytype)
+        if (mytype == MATROSKA_VIDEO_TRACK ):
+            _print("VIDEO TRACK found !!" )
+            #VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'samplebits',
+            #     'width', 'height', 'fps', 'aspect']
+            vi = mediainfo.VideoInfo()
+            try:
+                elem = tabelem[MATROSKA_CODEC_ID]
+                vi.codec = elem.get_data()
+            except:
+                vi.codec = 'Unknown'
+            try:
+                elem = tabelem[MATROSKA_FRAME_DURATION_ID]
+                vi.fps = 1 / (pow(10, -9) * (elem.get_value()))
+            except:
+                vi.fps = 0
+            try:
+                vinfo = tabelem[MATROSKA_VIDEO_SETTINGS_ID]
+                vidtab = self.process_one_level(vinfo)
+                vi.width  = vidtab[MATROSKA_VID_WIDTH_ID].get_value()
+                vi.height = vidtab[MATROSKA_VID_HEIGHT_ID].get_value()
+            except:
+                _print("No other info about video track !!!")
+            self.video.append(vi)
+        elif (mytype == MATROSKA_AUDIO_TRACK ):
+            _print("AUDIO TRACK found !!" )
+            #AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
+            #     'bitrate', 'language']
+            ai = mediainfo.AudioInfo()
+            try:
+                elem = tabelem[MATROSKA_TRACK_LANGUAGE_ID]
+                ai.language = elem.get_data()
+                ai['language'] = elem.get_data()
+            except:
+                ai.language = 'en'
+                ai['language'] = 'en'
+            try:
+                elem = tabelem[MATROSKA_CODEC_ID]
+                ai.codec = elem.get_data()
+            except:
+                ai.codec = "Unknown"
+            try:
+                ainfo = tabelem[MATROSKA_AUDIO_SETTINGS_ID]
+                audtab = self.process_one_level(vinfo)
+                ai.samplerate  = unpack('!f', audtab[MATROSKA_AUDIO_SAMPLERATE_ID].get_value())[0]
+                ai.channels = audtab[MATROSKA_AUDIO_CHANNELS_ID].get_value()
+            except:
+                _print("No other info about audio track !!!")
+            self.audio.append(ai)
+        elif (mytype == MATROSKA_SUBTITLES_TRACK):
+            try:
+                elem = tabelem[MATROSKA_TRACK_LANGUAGE_ID]
+                language = elem.get_data()
+                _print ("Subtitle language found : %s" % elem.get_data() )
+            except:
+                language = "en" # By default
+            self.subtitles.append(language)
+
+        #_print("Found %d elem for this track" % len(tabelem) )
+
+mmpython.registertype( 'application/mkv', ('mkv', 'mka',), mediainfo.TYPE_AV, MkvInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/movinfo.py	(revision 4)
@@ -0,0 +1,375 @@
+#if 0
+# $Id: movinfo.py,v 1.24 2004/07/14 13:42:57 dischi Exp $
+# $Log: movinfo.py,v $
+# Revision 1.24  2004/07/14 13:42:57  dischi
+# small debug updates
+#
+# Revision 1.23  2004/05/24 12:54:35  dischi
+# debug update
+#
+# Revision 1.22  2004/05/11 15:18:59  dischi
+# o more stream infos (like codec)
+# o better error handling for bad i18n tables
+# o language detection
+#
+# Revision 1.21  2004/05/10 15:19:59  dischi
+# o better stream detection
+# o correct length calculation inside the track
+# o support for compressed infos
+#
+# Revision 1.20  2004/03/07 10:27:58  dischi
+# Oops
+#
+# Revision 1.19  2004/03/02 20:48:21  dischi
+# fix gettable
+#
+# Revision 1.18  2003/08/30 09:36:22  dischi
+# turn off some debug based on DEBUG
+#
+# Revision 1.17  2003/07/02 11:17:30  the_krow
+# language is now part of the table key
+#
+# Revision 1.16  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.15  2003/06/29 18:30:56  dischi
+# length is broken, deactivated it until it is fixed
+#
+# Revision 1.14  2003/06/29 11:59:35  dischi
+# make some debug silent
+#
+# Revision 1.13  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.12  2003/06/20 14:53:05  the_krow
+# Metadata are copied from Quicktime Userdata to MediaInfo fields. This
+#  may be broken since it assumes the Quicktime Comment language to be
+#  set to 0.
+#
+# Revision 1.11  2003/06/19 17:31:12  dischi
+# error handling (and nonsense data)
+#
+# Revision 1.10  2003/06/12 18:53:18  the_krow
+# OGM detection added.
+# .ram is a valid extension to real files
+#
+# Revision 1.9  2003/06/12 16:56:53  the_krow
+# Some Quicktime should work.
+#
+# Revision 1.8  2003/06/12 15:58:05  the_krow
+# QT parsing of i18n metadata
+#
+# Revision 1.7  2003/06/12 14:43:22  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+# Revision 1.6  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.5  2003/06/08 15:40:26  dischi
+# catch exception, raised for small text files
+#
+# Revision 1.4  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.3  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.2  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import time
+import zlib
+import fourcc
+import mmpython
+from mmpython import mediainfo
+from movlanguages import *
+
+# http://developer.apple.com/documentation/QuickTime/QTFF/index.html
+
+ATOM_DEBUG = 0
+
+if mediainfo.DEBUG > 1:
+    ATOM_DEBUG = 1
+    
+class MovInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/quicktime'
+        self.type = 'Quicktime Video'
+        h = file.read(8)                
+        (size,type) = struct.unpack('>I4s',h)
+        if type == 'moov':
+            self.valid = 1
+        elif type == 'wide':
+            self.valid = 1
+        else:
+            return
+        # Extended size
+        if size == 1:
+            #print "Extended Size"
+            size = struct.unpack('>Q', file.read(8))                  
+        while self._readatom(file):
+            pass
+        try:
+            info = self.gettable('QTUDTA', 'en')
+            self.setitem('title', info, 'nam')
+            self.setitem('artist', info, 'aut')
+            self.setitem('copyright', info, 'cpy')
+        except:
+            pass
+
+
+    def _readatom(self, file):
+        
+        s = file.read(8)
+        if len(s) < 8:
+            return 0
+
+        atomsize,atomtype = struct.unpack('>I4s', s)
+        if not str(atomtype).decode('latin1').isalnum():
+            # stop at nonsense data
+            return 0
+
+        if mediainfo.DEBUG or ATOM_DEBUG:
+            print "%s [%X]" % (atomtype,atomsize)
+
+        if atomtype == 'udta':
+            # Userdata (Metadata)
+            pos = 0
+            tabl = {}
+            i18ntabl = {}
+            atomdata = file.read(atomsize-8)
+            while pos < atomsize-12:
+                (datasize,datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
+                if ord(datatype[0]) == 169:
+                    # i18n Metadata... 
+                    mypos = 8+pos
+                    while mypos < datasize+pos:
+                        # first 4 Bytes are i18n header
+                        (tlen,lang) = struct.unpack('>HH', atomdata[mypos:mypos+4])
+                        i18ntabl[lang] = i18ntabl.get(lang, {})
+                        i18ntabl[lang][datatype[1:]] = atomdata[mypos+4:mypos+tlen+4]
+                        mypos += tlen+4
+                elif datatype == 'WLOC':
+                    # Drop Window Location
+                    pass
+                else:
+                    if ord(atomdata[pos+8:pos+datasize][0]) > 1:
+                        tabl[datatype] = atomdata[pos+8:pos+datasize]
+                pos += datasize
+            if len(i18ntabl.keys()) > 0:
+                for k in i18ntabl.keys():                
+                    if QTLANGUAGES.has_key(k):
+                        self.appendtable('QTUDTA', i18ntabl[k], QTLANGUAGES[k])
+                        self.appendtable('QTUDTA', tabl, QTLANGUAGES[k])
+            else:
+                #print "NO i18"
+                self.appendtable('QTUDTA', tabl)
+             
+        elif atomtype == 'trak':
+            atomdata = file.read(atomsize-8)
+            pos   = 0
+            vi    = None
+            ai    = None
+            info  = None
+            while pos < atomsize-8:
+                (datasize,datatype) = struct.unpack('>I4s', atomdata[pos:pos+8])
+                if datatype == 'tkhd':
+                    tkhd = struct.unpack('>6I8x4H36xII', atomdata[pos+8:pos+datasize])
+                    vi = mediainfo.VideoInfo()
+                    vi.width = tkhd[10] >> 16
+                    vi.height = tkhd[11] >> 16
+                    vi.id = tkhd[3]
+
+                    ai = mediainfo.AudioInfo()
+                    ai.id = tkhd[3]
+                    
+                    try:
+                        # XXX Date number of Seconds is since January 1st 1904!!!
+                        # XXX 2082844800 is the difference between Unix and Apple time
+                        # XXX Fix me to work on Apple, too
+                        self.date = int(tkhd[1]) - 2082844800
+                        self.date = time.strftime('%y/%m/%d', time.gmtime(self.date))
+                    except Exception, e:
+                        print 'ex', e
+                    
+                elif datatype == 'mdia':
+                    pos      += 8
+                    datasize -= 8
+                    if ATOM_DEBUG:
+                        print '--> mdia information'
+
+                    while datasize:
+                        mdia = struct.unpack('>I4s', atomdata[pos:pos+8])
+                        if mdia[1] == 'mdhd':
+                            mdhd = struct.unpack('>IIIIIhh', atomdata[pos+8:pos+8+24])
+                            # duration / time scale
+                            if vi:
+                                vi.length = mdhd[4] / mdhd[3]
+                            if ai:
+                                ai.length = mdhd[4] / mdhd[3]
+                                if mdhd[5] in QTLANGUAGES:
+                                    ai.language = QTLANGUAGES[mdhd[5]]
+                            # mdhd[6] == quality 
+                            self.length = max(self.length, mdhd[4] / mdhd[3])
+                        elif mdia[1] == 'minf':
+                            # minf has only atoms inside
+                            pos -=      (mdia[0] - 8)
+                            datasize += (mdia[0] - 8)
+                        elif mdia[1] == 'stbl':
+                            # stbl has only atoms inside
+                            pos -=      (mdia[0] - 8)
+                            datasize += (mdia[0] - 8)
+                        elif mdia[1] == 'hdlr':
+                            hdlr = struct.unpack('>I4s4s', atomdata[pos+8:pos+8+12])
+                            if hdlr[1] == 'mhlr':
+                                if hdlr[2] == 'vide' and not vi in self.video:
+                                    self.video.append(vi)
+                                    info = vi
+                                if hdlr[2] == 'soun' and not ai in self.audio:
+                                    self.audio.append(ai)
+                                    info = ai
+                        elif mdia[1] == 'stsd':
+                            stsd = struct.unpack('>2I', atomdata[pos+8:pos+8+8])
+                            if stsd[1] > 0 and info:
+                                codec = struct.unpack('>I4s', atomdata[pos+16:pos+16+8])
+                                info.codec = codec[1]
+                                if info.codec == 'jpeg':
+                                    # jpeg is no video, remove it from the list
+                                    self.video.remove(vi)
+                                    info = None
+
+                        elif mdia[1] == 'dinf':
+                            dref = struct.unpack('>I4s', atomdata[pos+8:pos+8+8])
+                            if ATOM_DEBUG:
+                                print '  --> %s, %s' % mdia
+                                print '    --> %s, %s (reference)' % dref
+                            
+                        elif ATOM_DEBUG:
+                            if mdia[1].startswith('st'):
+                                print '  --> %s, %s (sample)' % mdia
+                            elif mdia[1] in ('vmhd', 'smhd'):
+                                print '  --> %s, %s (media information header)' % mdia
+                            else:
+                                print '  --> %s, %s (unknown)' % mdia
+
+                        pos      += mdia[0]
+                        datasize -= mdia[0]
+
+                elif datatype == 'udta' and ATOM_DEBUG:
+                    print struct.unpack('>I4s', atomdata[:8])
+                elif ATOM_DEBUG:
+                    if datatype == 'edts':
+                        print "--> %s [%d] (edit list)" % (datatype, datasize)
+                    else:
+                        print "--> %s [%d] (unknown)" % (datatype, datasize)
+                pos += datasize
+
+        elif atomtype == 'mvhd':
+            # movie header
+            mvhd = struct.unpack('>6I2h', file.read(28))
+            self.length = max(self.length, mvhd[4] / mvhd[3])
+            self.volume = mvhd[6]
+            file.seek(atomsize-8-28,1)
+
+        elif atomtype == 'cmov':
+            # compressed movie
+            datasize, atomtype = struct.unpack('>I4s', file.read(8))
+            if not atomtype == 'dcom':
+                return atomsize
+
+            method = struct.unpack('>4s', file.read(datasize-8))[0]
+
+            datasize, atomtype = struct.unpack('>I4s', file.read(8))
+            if not atomtype == 'cmvd':
+                return atomsize
+
+            if method == 'zlib':
+                data = file.read(datasize-8)
+                try:
+                    decompressed = zlib.decompress(data)
+                except Exception, e:
+                    try:
+                        decompressed = zlib.decompress(data[4:])
+                    except Exception, e:
+                        if mediainfo.DEBUG:
+                            print 'unable to decompress atom'
+                        return atomsize
+                import StringIO
+                decompressedIO = StringIO.StringIO(decompressed)
+                while self._readatom(decompressedIO):
+                    pass
+                
+            else:
+                if mediainfo.DEBUG:
+                    print 'unknown compression %s' % method
+                # unknown compression method
+                file.seek(datasize-8,1)
+        
+        elif atomtype == 'moov':
+            # decompressed movie info
+            while self._readatom(file):
+                pass
+            
+        elif atomtype == 'mdat':
+            pos = file.tell() + atomsize - 8
+            # maybe there is data inside the mdat
+            if ATOM_DEBUG:
+                print 'parsing mdat'
+            while self._readatom(file):
+                pass
+            if ATOM_DEBUG:
+                print 'end of mdat'
+            file.seek(pos, 0)
+            
+        
+        else:
+            if ATOM_DEBUG and not atomtype in ('wide', 'free'):
+                print 'unhandled base atom %s' % atomtype
+
+            # Skip unknown atoms
+            try:
+                file.seek(atomsize-8,1)
+            except IOError:
+                return 0
+
+        return atomsize
+        
+mmpython.registertype( 'video/quicktime', ('mov', 'qt'), mediainfo.TYPE_AV, MovInfo )
+
+# doc links:
+# [1] http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_2.html#//apple_ref/doc/uid/TP40000939-CH206-BBCBIICE
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/ogminfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/ogminfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/ogminfo.py	(revision 4)
@@ -0,0 +1,362 @@
+#if 0
+# -----------------------------------------------------------------------
+# ogminfo.py - Ogg Streaming Video Files
+# -----------------------------------------------------------------------
+# $Id: ogminfo.py,v 1.16 2004/05/20 19:54:52 dischi Exp $
+#
+# $Log: ogminfo.py,v $
+# Revision 1.16  2004/05/20 19:54:52  dischi
+# more ogm fixes
+#
+# Revision 1.15  2004/05/20 08:49:29  dischi
+# more ogm fixes, better length calc (again)
+#
+# Revision 1.14  2004/05/18 21:55:52  dischi
+# o get correct length for ogm files
+# o set metadat for the different streams
+# o chapter support
+#
+# Revision 1.13  2003/09/22 16:21:54  the_krow
+# utf-8 comment parsing
+#
+# Revision 1.12  2003/09/09 19:57:08  dischi
+# bad hack to make length oggs work
+#
+# Revision 1.11  2003/09/09 19:32:26  dischi
+# bugfix for finding oggs
+#
+# Revision 1.10  2003/08/04 08:44:51  the_krow
+# Maximum iterations field added as suggested by Magnus in the
+# freevo list.
+#
+# Revision 1.9  2003/07/13 15:20:53  dischi
+# make the module quiet
+#
+# Revision 1.8  2003/07/10 11:16:31  the_krow
+# o Added length calculation for audio only files.
+# o In the future we will use this as a general parser for ogm/ogg
+#
+# Revision 1.7  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.6  2003/06/29 12:11:16  dischi
+# changed print to _print
+#
+# Revision 1.5  2003/06/23 20:48:11  the_krow
+# width + height fixes for OGM files
+#
+# Revision 1.4  2003/06/23 13:20:51  the_krow
+# basic parsing should now work.
+#
+#
+#
+# -----------------------------------------------------------------------
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+
+from mmpython import mediainfo
+import mmpython
+import struct
+import re
+import stat
+import os
+
+import fourcc
+
+PACKET_TYPE_HEADER   = 0x01
+PACKED_TYPE_METADATA = 0x03
+PACKED_TYPE_SETUP    = 0x05
+PACKET_TYPE_BITS     = 0x07
+PACKET_IS_SYNCPOINT  = 0x08
+
+#VORBIS_VIDEO_PACKET_INFO = 'video'
+
+STREAM_HEADER_VIDEO = '<4sIQQIIHII'
+STREAM_HEADER_AUDIO = '<4sIQQIIHHHI'
+
+_print = mediainfo._debug
+
+VORBISCOMMENT_tags = { 'title': 'TITLE',
+                       'album': 'ALBUM',
+                       'artist': 'ARTIST',
+                       'comment': 'COMMENT',
+                       'date': 'DATE',
+                       'encoder': 'ENCODER',
+                       'trackno': 'TRACKNUMBER',
+                       'language': 'LANGUAGE',
+                       'genre': 'GENRE',
+                     }
+
+MAXITERATIONS = 10
+
+class OgmInfo(mediainfo.AVInfo):
+    def __init__(self, file):
+        mediainfo.AVInfo.__init__(self)
+        self.samplerate  = 1
+        self.all_streams = []           # used to add meta data to streams
+        self.all_header  = []
+
+        for i in range(MAXITERATIONS):
+            granule, nextlen = self._parseOGGS(file)
+            if granule == None:
+                break
+            elif granule > 0:
+                # ok, file started
+                break
+
+        # seek to the end of the stream, to avoid scanning the whole file
+        if (os.stat(file.name)[stat.ST_SIZE] > 50000):
+            file.seek(os.stat(file.name)[stat.ST_SIZE]-49000)
+
+        # read the rest of the file into a buffer
+        h = file.read()
+
+        # find last OggS to get length info
+        if len(h) > 200:
+            idx = h.find('OggS')
+            pos = -49000 + idx
+            if idx:
+                file.seek(os.stat(file.name)[stat.ST_SIZE] + pos)
+            while 1:
+                granule, nextlen = self._parseOGGS(file)
+                if not nextlen:
+                    break
+
+        # Copy metadata to the streams
+        if len(self.all_header) == len(self.all_streams):
+            for i in range(len(self.all_header)):
+                # set length
+                self.length = max(self.all_streams[i].length, self.length)
+
+                # get meta info
+                for key in self.all_streams[i].keys:
+                    if self.all_header[i].has_key(key):
+                        self.all_streams[i][key] = self.all_header[i][key]
+                        del self.all_header[i][key]
+                    if self.all_header[i].has_key(key.upper()):
+                        self.all_streams[i][key] = self.all_header[i][key.upper()]
+                        del self.all_header[i][key.upper()]
+
+                # Extract subtitles:
+                if hasattr(self.all_streams[i], 'type') and \
+                   self.all_streams[i].type == 'subtitle':
+                    self.subtitles.append(self.all_streams[i].language)
+
+                # Chapter parser
+                if self.all_header[i].has_key('CHAPTER01') and not self.chapters:
+                    while 1:
+                        s = 'CHAPTER0%s' % (len(self.chapters) + 1)
+                        if len(s) < 9:
+                            s = '0' + s
+                        if self.all_header[i].has_key(s) and \
+                               self.all_header[i].has_key(s + 'NAME'):
+                            pos = self.all_header[i][s]
+                            try:
+                                pos = int(pos)
+                            except ValueError:
+                                new_pos = 0
+                                for v in pos.split(':'):
+                                    new_pos = new_pos * 60 + float(v)
+                                pos = int(new_pos)
+                                
+                            c = mediainfo.ChapterInfo(self.all_header[i][s + 'NAME'], pos)
+                            del self.all_header[i][s + 'NAME']
+                            del self.all_header[i][s]
+                            self.chapters.append(c)
+                        else:
+                            break
+
+        for stream in self.all_streams:
+            if not stream.length:
+                stream.length = self.length
+                
+        # Copy Metadata from tables into the main set of attributes        
+        for header in self.all_header:
+            self.appendtable('VORBISCOMMENT', header)
+
+        self.tag_map = { ('VORBISCOMMENT', 'en') : VORBISCOMMENT_tags }
+        for k in self.tag_map.keys():
+            _print(k)
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),
+                                      self.tag_map[k][x]), self.tag_map[k].keys())
+
+        
+    def _parseOGGS(self,file):
+        h = file.read(27)
+        if len(h) == 0:
+            # Regular File end
+            return None, None
+        elif len(h) < 27:
+            _print("%d Bytes of Garbage found after End." % len(h))
+            return None, None
+        if h[:4] != "OggS":        
+            self.valid = 0
+            _print("Invalid Ogg")
+            return None, None
+
+        self.valid = 1
+        version = ord(h[4])
+        if version != 0:
+            _print("Unsupported OGG/OGM Version %d." % version)
+            return None, None
+        head = struct.unpack('<BQIIIB', h[5:])
+        headertype, granulepos, serial, pageseqno, checksum, pageSegCount = head
+
+        self.valid = 1
+        self.mime = 'application/ogm'
+        self.type = 'OGG Media'
+        tab = file.read(pageSegCount)
+        nextlen = 0
+        for i in range(len(tab)):
+            nextlen += ord(tab[i])
+        else:
+            h = file.read(1)
+            packettype = ord(h[0]) & PACKET_TYPE_BITS 
+            if packettype == PACKET_TYPE_HEADER:
+                h += file.read(nextlen-1)
+                self._parseHeader(h, granulepos)
+            elif packettype == PACKED_TYPE_METADATA:
+                h += file.read(nextlen-1)
+                self._parseMeta(h)
+            else:
+                file.seek(nextlen-1,1)
+        if len(self.all_streams) > serial:
+            stream = self.all_streams[serial]
+            if hasattr(stream, 'samplerate') and \
+                   stream.samplerate:
+                stream.length = granulepos / stream.samplerate
+            elif hasattr(stream, 'bitrate') and \
+                     stream.bitrate:
+                stream.length = granulepos / stream.bitrate
+
+        return granulepos, nextlen + 27 + pageSegCount
+
+        
+    def _parseMeta(self,h):
+        flags = ord(h[0])
+        headerlen = len(h)
+        if headerlen >= 7 and h[1:7] == 'vorbis':
+            header = {}
+            nextlen, self.encoder = self._extractHeaderString(h[7:])
+            numItems = struct.unpack('<I',h[7+nextlen:7+nextlen+4])[0]
+            start = 7+4+nextlen
+            for i in range(numItems):
+                (nextlen, s) = self._extractHeaderString(h[start:])
+                start += nextlen
+                if s:
+                    a = re.split('=',s)
+                    header[(a[0]).upper()]=a[1]
+            # Put Header fields into info fields
+            self.type = 'OGG Vorbis'
+            self.subtype = ''
+            self.all_header.append(header)
+
+            
+    def _parseHeader(self,header,granule):
+        headerlen = len(header)
+        flags = ord(header[0])
+
+        if headerlen >= 30 and header[1:7] == 'vorbis':
+            #print("Vorbis Audio Header")
+            ai = mediainfo.AudioInfo()
+            ai.version, ai.channels, ai.samplerate, bitrate_max, ai.bitrate, \
+                        bitrate_min, blocksize, framing = \
+                        struct.unpack('<IBIiiiBB',header[7:7+23])
+            ai.codec = 'Vorbis'
+            #ai.granule = granule
+            #ai.length = granule / ai.samplerate
+            self.audio.append(ai)
+            self.all_streams.append(ai)
+            
+        elif headerlen >= 7 and header[1:7] == 'theora':
+            #print "Theora Header"
+            # Theora Header
+            # XXX Finish Me
+            vi = mediainfo.VideoInfo()
+            vi.codec = 'theora'
+            self.video.append(vi)
+            self.all_streams.append(vi)
+
+        elif headerlen >= 142 and header[1:36] == 'Direct Show Samples embedded in Ogg':
+            #print 'Direct Show Samples embedded in Ogg'
+            # Old Directshow format
+            # XXX Finish Me
+            vi = mediainfo.VideoInfo()
+            vi.codec = 'dshow'
+            self.video.append(vi)
+            self.all_streams.append(vi)
+
+        elif flags & PACKET_TYPE_BITS == PACKET_TYPE_HEADER and headerlen >= struct.calcsize(STREAM_HEADER_VIDEO)+1:
+            #print "New Directshow Format"
+            # New Directshow Format
+            htype = header[1:9]
+
+            if htype[:5] == 'video':
+                streamheader = struct.unpack( STREAM_HEADER_VIDEO, header[9:struct.calcsize(STREAM_HEADER_VIDEO)+9] )
+                vi = mediainfo.VideoInfo()
+                (type, ssize, timeunit, samplerate, vi.length, buffersize, \
+                 vi.bitrate, vi.width, vi.height) = streamheader
+
+                vi.width /= 65536
+                vi.height /= 65536
+                # XXX length, bitrate are very wrong
+                try:
+                    vi.codec = fourcc.RIFFCODEC[type]
+                except:
+                    vi.codec = 'Unknown (%s)' % type
+                vi.fps = 10000000 / timeunit
+                self.video.append(vi)
+                self.all_streams.append(vi)
+
+            elif htype[:5] == 'audio':
+                streamheader = struct.unpack( STREAM_HEADER_AUDIO, header[9:struct.calcsize(STREAM_HEADER_AUDIO)+9] )
+                ai = mediainfo.AudioInfo()
+                (type, ssize, timeunit, ai.samplerate, ai.length, buffersize, ai.bitrate, ai.channels, bloc, ai.bitrate) = streamheader
+                self.samplerate = ai.samplerate
+                _print("Samplerate %d" % self.samplerate)
+                self.audio.append(ai)
+                self.all_streams.append(ai)
+
+            elif htype[:4] == 'text':
+                subtitle = mediainfo.MediaInfo()
+                subtitle.keys.append('language')
+                subtitle.type   = 'subtitle'
+                subtitle.length = 0
+                self.all_streams.append(subtitle)
+                
+        else:
+            _print("Unknown Header")
+              
+
+    def _extractHeaderString(self,header):
+        len = struct.unpack( '<I', header[:4] )[0]
+        try:
+            return (len+4,unicode(header[4:4+len], 'utf-8'))
+        except:
+            return (len+4,None)
+
+
+mmpython.registertype( 'application/ogg', ('ogm', 'ogg',), mediainfo.TYPE_AV, OgmInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/realinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/realinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/realinfo.py	(revision 4)
@@ -0,0 +1,129 @@
+#if 0
+# $Id: realinfo.py,v 1.6 2003/07/02 09:09:41 the_krow Exp $
+# $Log: realinfo.py,v $
+# Revision 1.6  2003/07/02 09:09:41  the_krow
+# i18n stuff added to AVI
+# some debug outputs removed
+#
+# Revision 1.5  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.4  2003/06/29 11:59:35  dischi
+# make some debug silent
+#
+# Revision 1.3  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.2  2003/06/12 18:53:19  the_krow
+# OGM detection added.
+# .ram is a valid extension to real files
+#
+# Revision 1.1  2003/06/12 14:43:22  the_krow
+# Realmedia file parsing. Title, Artist, Copyright work. Couldn't find
+# many technical parameters to retrieve.
+# Some initial QT parsing
+# added Real to __init__.py
+#
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import struct
+import string
+
+from mmpython import mediainfo
+import mmpython
+
+# http://www.pcisys.net/~melanson/codecs/rmff.htm
+# http://www.pcisys.net/~melanson/codecs/
+
+_print = mediainfo._debug
+
+class RealInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.valid = 0
+        self.mime = 'video/real'
+        self.type = 'Real Video'
+        h = file.read(10)        
+        (object_id,object_size,object_version) = struct.unpack('>4sIH',h)
+        if object_id == '.RMF':
+            self.valid = 1
+        else:
+            return
+        file_version, num_headers = struct.unpack('>II', file.read(8))
+        _print("size: %d, ver: %d, headers: %d" % (object_size, file_version,num_headers))
+        for i in range(0,num_headers):            
+            (object_id,object_size,object_version) = struct.unpack('>4sIH',file.read(10))
+            self._read_header(object_id, file.read(object_size-10))
+            _print("%s [%d]" % (object_id,object_size-10))
+        # Read all the following headers
+        
+    def _read_header(self,object_id,s):
+        if object_id == 'PROP':
+            prop = struct.unpack('>9IHH', s)
+            _print(prop)
+        if object_id == 'MDPR':
+            mdpr = struct.unpack('>H7I', s[:30])
+            _print(mdpr)
+            self.length = mdpr[7]/1000
+            (stream_name_size,) = struct.unpack('>B', s[30:31])
+            stream_name = s[31:31+stream_name_size]
+            pos = 31+stream_name_size
+            (mime_type_size,) = struct.unpack('>B', s[pos:pos+1])
+            mime = s[pos+1:pos+1+mime_type_size]
+            pos += mime_type_size+1
+            (type_specific_len,) = struct.unpack('>I', s[pos:pos+4])
+            type_specific = s[pos+4:pos+4+type_specific_len]
+            pos += 4+type_specific_len
+            if mime[:5] == 'audio':
+                ai = mediainfo.AudioInfo()
+                ai.id = mdpr[0]
+                ai.bitrate = mdpr[2]
+                self.audio.append(ai)
+            elif mime[:5] == 'video':
+                vi = mediainfo.VideoInfo()
+                vi.id = mdpr[0]
+                vi.bitrate = mdpr[2]
+                self.video.append(vi)
+            else:
+                _print("Unknown: %s" % mime)
+        if object_id == 'CONT':
+            pos = 0
+            (title_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.title = s[2:title_len+2]
+            pos += title_len+2
+            (author_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.artist = s[pos+2:pos+author_len+2]
+            pos += author_len+2
+            (copyright_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.copyright = s[pos+2:pos+copyright_len+2]
+            pos += copyright_len+2
+            (comment_len,) = struct.unpack('>H', s[pos:pos+2])
+            self.comment = s[pos+2:pos+comment_len+2]
+
+mmpython.registertype( 'video/real', ('rm', 'ra', 'ram'), mediainfo.TYPE_AV, RealInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/fourcc.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/fourcc.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/fourcc.py	(revision 4)
@@ -0,0 +1,429 @@
+#if 0
+# $Id: fourcc.py,v 1.3 2003/05/13 12:31:43 the_krow Exp $
+# $Log: fourcc.py,v $
+# Revision 1.3  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+RIFFWAVE = {}
+RIFFCODEC = {}
+
+RIFFWAVE[0x0000] = 'Microsoft Unknown Wave Format';
+RIFFWAVE[0x0001] = 'Microsoft Pulse Code Modulation (PCM)';
+RIFFWAVE[0x0002] = 'Microsoft ADPCM';
+RIFFWAVE[0x0003] = 'IEEE Float';
+RIFFWAVE[0x0004] = 'Compaq Computer VSELP';
+RIFFWAVE[0x0005] = 'IBM CVSD';
+RIFFWAVE[0x0006] = 'Microsoft A-Law';
+RIFFWAVE[0x0007] = 'Microsoft mu-Law';
+RIFFWAVE[0x0010] = 'OKI ADPCM';
+RIFFWAVE[0x0011] = 'Intel DVI/IMA ADPCM';
+RIFFWAVE[0x0012] = 'Videologic MediaSpace ADPCM';
+RIFFWAVE[0x0013] = 'Sierra Semiconductor ADPCM';
+RIFFWAVE[0x0014] = 'Antex Electronics G.723 ADPCM';
+RIFFWAVE[0x0015] = 'DSP Solutions DigiSTD';
+RIFFWAVE[0x0016] = 'DSP Solutions DigiFIX';
+RIFFWAVE[0x0017] = 'Dialogic OKI ADPCM';
+RIFFWAVE[0x0018] = 'MediaVision ADPCM';
+RIFFWAVE[0x0019] = 'Hewlett-Packard CU';
+RIFFWAVE[0x0020] = 'Yamaha ADPCM';
+RIFFWAVE[0x0021] = 'Speech Compression Sonarc';
+RIFFWAVE[0x0022] = 'DSP Group TrueSpeech';
+RIFFWAVE[0x0023] = 'Echo Speech EchoSC1';
+RIFFWAVE[0x0024] = 'Audiofile AF36';
+RIFFWAVE[0x0025] = 'Audio Processing Technology APTX';
+RIFFWAVE[0x0026] = 'AudioFile AF10';
+RIFFWAVE[0x0027] = 'Prosody 1612';
+RIFFWAVE[0x0028] = 'LRC';
+RIFFWAVE[0x0030] = 'Dolby AC2';
+RIFFWAVE[0x0031] = 'Microsoft GSM 6.10';
+RIFFWAVE[0x0032] = 'MSNAudio';
+RIFFWAVE[0x0033] = 'Antex Electronics ADPCME';
+RIFFWAVE[0x0034] = 'Control Resources VQLPC';
+RIFFWAVE[0x0035] = 'DSP Solutions DigiREAL';
+RIFFWAVE[0x0036] = 'DSP Solutions DigiADPCM';
+RIFFWAVE[0x0037] = 'Control Resources CR10';
+RIFFWAVE[0x0038] = 'Natural MicroSystems VBXADPCM';
+RIFFWAVE[0x0039] = 'Crystal Semiconductor IMA ADPCM';
+RIFFWAVE[0x003A] = 'EchoSC3';
+RIFFWAVE[0x003B] = 'Rockwell ADPCM';
+RIFFWAVE[0x003C] = 'Rockwell Digit LK';
+RIFFWAVE[0x003D] = 'Xebec';
+RIFFWAVE[0x0040] = 'Antex Electronics G.721 ADPCM';
+RIFFWAVE[0x0041] = 'G.728 CELP';
+RIFFWAVE[0x0042] = 'MSG723';
+RIFFWAVE[0x0050] = 'Microsoft MPEG';
+RIFFWAVE[0x0052] = 'RT24';
+RIFFWAVE[0x0053] = 'PAC';
+RIFFWAVE[0x0055] = 'MPEG Layer 3';
+RIFFWAVE[0x0059] = 'Lucent G.723';
+RIFFWAVE[0x0060] = 'Cirrus';
+RIFFWAVE[0x0061] = 'ESPCM';
+RIFFWAVE[0x0062] = 'Voxware';
+RIFFWAVE[0x0063] = 'Canopus Atrac';
+RIFFWAVE[0x0064] = 'G.726 ADPCM';
+RIFFWAVE[0x0065] = 'G.722 ADPCM';
+RIFFWAVE[0x0066] = 'DSAT';
+RIFFWAVE[0x0067] = 'DSAT Display';
+RIFFWAVE[0x0069] = 'Voxware Byte Aligned';
+RIFFWAVE[0x0070] = 'Voxware AC8';
+RIFFWAVE[0x0071] = 'Voxware AC10';
+RIFFWAVE[0x0072] = 'Voxware AC16';
+RIFFWAVE[0x0073] = 'Voxware AC20';
+RIFFWAVE[0x0074] = 'Voxware MetaVoice';
+RIFFWAVE[0x0075] = 'Voxware MetaSound';
+RIFFWAVE[0x0076] = 'Voxware RT29HW';
+RIFFWAVE[0x0077] = 'Voxware VR12';
+RIFFWAVE[0x0078] = 'Voxware VR18';
+RIFFWAVE[0x0079] = 'Voxware TQ40';
+RIFFWAVE[0x0080] = 'Softsound';
+RIFFWAVE[0x0081] = 'Voxware TQ60';
+RIFFWAVE[0x0082] = 'MSRT24';
+RIFFWAVE[0x0083] = 'G.729A';
+RIFFWAVE[0x0084] = 'MVI MV12';
+RIFFWAVE[0x0085] = 'DF G.726';
+RIFFWAVE[0x0086] = 'DF GSM610';
+RIFFWAVE[0x0088] = 'ISIAudio';
+RIFFWAVE[0x0089] = 'Onlive';
+RIFFWAVE[0x0091] = 'SBC24';
+RIFFWAVE[0x0092] = 'Dolby AC3 SPDIF';
+RIFFWAVE[0x0097] = 'ZyXEL ADPCM';
+RIFFWAVE[0x0098] = 'Philips LPCBB';
+RIFFWAVE[0x0099] = 'Packed';
+RIFFWAVE[0x0100] = 'Rhetorex ADPCM';
+RIFFWAVE[0x0101] = 'IBM mu-law';
+RIFFWAVE[0x0102] = 'IBM A-law';
+RIFFWAVE[0x0103] = 'IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)';
+RIFFWAVE[0x0111] = 'Vivo G.723';
+RIFFWAVE[0x0112] = 'Vivo Siren';
+RIFFWAVE[0x0123] = 'Digital G.723';
+RIFFWAVE[0x0140] = 'Windows Media Video V8';
+RIFFWAVE[0x0161] = 'Windows Media Audio V7 / V8 / V9';
+RIFFWAVE[0x0162] = 'Windows Media Audio Professional V9';
+RIFFWAVE[0x0163] = 'Windows Media Audio Lossless V9';
+RIFFWAVE[0x0200] = 'Creative Labs ADPCM';
+RIFFWAVE[0x0202] = 'Creative Labs Fastspeech8';
+RIFFWAVE[0x0203] = 'Creative Labs Fastspeech10';
+RIFFWAVE[0x0220] = 'Quarterdeck';
+RIFFWAVE[0x0300] = 'FM Towns Snd';
+RIFFWAVE[0x0300] = 'Fujitsu FM Towns Snd';
+RIFFWAVE[0x0400] = 'BTV Digital';
+RIFFWAVE[0x0680] = 'VME VMPCM';
+RIFFWAVE[0x1000] = 'Olivetti GSM';
+RIFFWAVE[0x1001] = 'Olivetti ADPCM';
+RIFFWAVE[0x1002] = 'Olivetti CELP';
+RIFFWAVE[0x1003] = 'Olivetti SBC';
+RIFFWAVE[0x1004] = 'Olivetti OPR';
+RIFFWAVE[0x1100] = 'Lernout & Hauspie LH Codec';
+RIFFWAVE[0x1400] = 'Norris';
+RIFFWAVE[0x1401] = 'AT&T ISIAudio';
+RIFFWAVE[0x1500] = 'Soundspace Music Compression';
+RIFFWAVE[0x2000] = 'AC3';
+RIFFWAVE[0x7A21] = 'GSM-AMR (CBR, no SID)';
+RIFFWAVE[0x7A22] = 'GSM-AMR (VBR, including SID)';
+RIFFWAVE[0xFFFF] = 'development';
+
+RIFFCODEC['3IV1'] = '3ivx v1'
+RIFFCODEC['3IV2'] = '3ivx v2'
+RIFFCODEC['AASC'] = 'Autodesk Animator'
+RIFFCODEC['ABYR'] = 'Kensington ?ABYR?'
+RIFFCODEC['AEMI'] = 'Array VideoONE MPEG1-I Capture'
+RIFFCODEC['AFLC'] = 'Autodesk Animator FLC'
+RIFFCODEC['AFLI'] = 'Autodesk Animator FLI'
+RIFFCODEC['AMPG'] = 'Array VideoONE MPEG'
+RIFFCODEC['ANIM'] = 'Intel RDX (ANIM)'
+RIFFCODEC['AP41'] = 'AngelPotion Definitive'
+RIFFCODEC['ASV1'] = 'Asus Video v1'
+RIFFCODEC['ASV2'] = 'Asus Video v2'
+RIFFCODEC['ASVX'] = 'Asus Video 2.0 (audio)'
+RIFFCODEC['AUR2'] = 'Aura 2 Codec - YUV 4:2:2'
+RIFFCODEC['AURA'] = 'Aura 1 Codec - YUV 4:1:1'
+RIFFCODEC['BINK'] = 'RAD Game Tools Bink Video'
+RIFFCODEC['BT20'] = 'Conexant Prosumer Video'
+RIFFCODEC['BTCV'] = 'Conexant Composite Video Codec'
+RIFFCODEC['BW10'] = 'Data Translation Broadway MPEG Capture'
+RIFFCODEC['CC12'] = 'Intel YUV12'
+RIFFCODEC['CDVC'] = 'Canopus DV'
+RIFFCODEC['CFCC'] = 'Digital Processing Systems DPS Perception'
+RIFFCODEC['CGDI'] = 'Microsoft Office 97 Camcorder Video'
+RIFFCODEC['CHAM'] = 'Winnov Caviara Champagne'
+RIFFCODEC['CJPG'] = 'Creative WebCam JPEG'
+RIFFCODEC['CLJR'] = 'Cirrus Logic YUV 4 pixels'
+RIFFCODEC['CMYK'] = 'Common Data Format in Printing'
+RIFFCODEC['CPLA'] = 'Weitek 4:2:0 YUV Planar'
+RIFFCODEC['CRAM'] = 'Microsoft Video 1 (CRAM)'
+RIFFCODEC['CVID'] = 'Radius Cinepak'
+RIFFCODEC['CWLT'] = '?CWLT?'
+RIFFCODEC['CWLT'] = 'Microsoft Color WLT DIB'
+RIFFCODEC['CYUV'] = 'Creative Labs YUV'
+RIFFCODEC['CYUY'] = 'ATI YUV'
+RIFFCODEC['D261'] = 'H.261'
+RIFFCODEC['D263'] = 'H.263'
+RIFFCODEC['DIV3'] = 'DivX v3 MPEG-4 Low-Motion'
+RIFFCODEC['DIV4'] = 'DivX v3 MPEG-4 Fast-Motion'
+RIFFCODEC['DIV5'] = '?DIV5?'
+RIFFCODEC['DIVX'] = 'DivX v4'
+RIFFCODEC['divx'] = 'DivX'
+RIFFCODEC['DMB1'] = 'Matrox Rainbow Runner hardware MJPEG'
+RIFFCODEC['DMB2'] = 'Paradigm MJPEG'
+RIFFCODEC['DSVD'] = '?DSVD?'
+RIFFCODEC['DUCK'] = 'Duck True Motion 1.0'
+RIFFCODEC['DVAN'] = '?DVAN?'
+RIFFCODEC['DVE2'] = 'InSoft DVE-2 Videoconferencing'
+RIFFCODEC['dvsd'] = 'DV'
+RIFFCODEC['DVSD'] = 'DV'
+RIFFCODEC['DVX1'] = 'DVX1000SP Video Decoder'
+RIFFCODEC['DVX2'] = 'DVX2000S Video Decoder'
+RIFFCODEC['DVX3'] = 'DVX3000S Video Decoder'
+RIFFCODEC['DX50'] = 'DivX v5'
+RIFFCODEC['DXT1'] = 'Microsoft DirectX Compressed Texture (DXT1)'
+RIFFCODEC['DXT2'] = 'Microsoft DirectX Compressed Texture (DXT2)'
+RIFFCODEC['DXT3'] = 'Microsoft DirectX Compressed Texture (DXT3)'
+RIFFCODEC['DXT4'] = 'Microsoft DirectX Compressed Texture (DXT4)'
+RIFFCODEC['DXT5'] = 'Microsoft DirectX Compressed Texture (DXT5)'
+RIFFCODEC['DXTC'] = 'Microsoft DirectX Compressed Texture (DXTC)'
+RIFFCODEC['EKQ0'] = 'Elsa ?EKQ0?'
+RIFFCODEC['ELK0'] = 'Elsa ?ELK0?'
+RIFFCODEC['ESCP'] = 'Eidos Escape'
+RIFFCODEC['ETV1'] = 'eTreppid Video ETV1'
+RIFFCODEC['ETV2'] = 'eTreppid Video ETV2'
+RIFFCODEC['ETVC'] = 'eTreppid Video ETVC'
+RIFFCODEC['FLJP'] = 'D-Vision Field Encoded Motion JPEG'
+RIFFCODEC['FRWA'] = 'SoftLab-Nsk Forward Motion JPEG w/ alpha channel'
+RIFFCODEC['FRWD'] = 'SoftLab-Nsk Forward Motion JPEG'
+RIFFCODEC['FVF1'] = 'Iterated Systems Fractal Video Frame'
+RIFFCODEC['GLZW'] = 'Motion LZW (gabest@freemail.hu)'
+RIFFCODEC['GPEG'] = 'Motion JPEG (gabest@freemail.hu)'
+RIFFCODEC['GWLT'] = 'Microsoft Greyscale WLT DIB'
+RIFFCODEC['H260'] = 'Intel ITU H.260 Videoconferencing'
+RIFFCODEC['H261'] = 'Intel ITU H.261 Videoconferencing'
+RIFFCODEC['H262'] = 'Intel ITU H.262 Videoconferencing'
+RIFFCODEC['H263'] = 'Intel ITU H.263 Videoconferencing'
+RIFFCODEC['H264'] = 'Intel ITU H.264 Videoconferencing'
+RIFFCODEC['H265'] = 'Intel ITU H.265 Videoconferencing'
+RIFFCODEC['H266'] = 'Intel ITU H.266 Videoconferencing'
+RIFFCODEC['H267'] = 'Intel ITU H.267 Videoconferencing'
+RIFFCODEC['H268'] = 'Intel ITU H.268 Videoconferencing'
+RIFFCODEC['H269'] = 'Intel ITU H.269 Videoconferencing'
+RIFFCODEC['HFYU'] = 'Huffman Lossless Codec'
+RIFFCODEC['HMCR'] = 'Rendition Motion Compensation Format (HMCR)'
+RIFFCODEC['HMRR'] = 'Rendition Motion Compensation Format (HMRR)'
+RIFFCODEC['i263'] = 'Intel ITU H.263 Videoconferencing (i263)'
+RIFFCODEC['I420'] = 'Intel Indeo 4'
+RIFFCODEC['IAN '] = 'Intel RDX'
+RIFFCODEC['ICLB'] = 'InSoft CellB Videoconferencing'
+RIFFCODEC['IGOR'] = 'Power DVD'
+RIFFCODEC['IJPG'] = 'Intergraph JPEG'
+RIFFCODEC['ILVC'] = 'Intel Layered Video'
+RIFFCODEC['ILVR'] = 'ITU-T H.263+'
+RIFFCODEC['IPDV'] = 'I-O Data Device Giga AVI DV Codec'
+RIFFCODEC['IR21'] = 'Intel Indeo 2.1'
+RIFFCODEC['IRAW'] = 'Intel YUV Uncompressed'
+RIFFCODEC['IV30'] = 'Ligos Indeo 3.0'
+RIFFCODEC['IV31'] = 'Ligos Indeo 3.1'
+RIFFCODEC['IV32'] = 'Ligos Indeo 3.2'
+RIFFCODEC['IV33'] = 'Ligos Indeo 3.3'
+RIFFCODEC['IV34'] = 'Ligos Indeo 3.4'
+RIFFCODEC['IV35'] = 'Ligos Indeo 3.5'
+RIFFCODEC['IV36'] = 'Ligos Indeo 3.6'
+RIFFCODEC['IV37'] = 'Ligos Indeo 3.7'
+RIFFCODEC['IV38'] = 'Ligos Indeo 3.8'
+RIFFCODEC['IV39'] = 'Ligos Indeo 3.9'
+RIFFCODEC['IV40'] = 'Ligos Indeo Interactive 4.0'
+RIFFCODEC['IV41'] = 'Ligos Indeo Interactive 4.1'
+RIFFCODEC['IV42'] = 'Ligos Indeo Interactive 4.2'
+RIFFCODEC['IV43'] = 'Ligos Indeo Interactive 4.3'
+RIFFCODEC['IV44'] = 'Ligos Indeo Interactive 4.4'
+RIFFCODEC['IV45'] = 'Ligos Indeo Interactive 4.5'
+RIFFCODEC['IV46'] = 'Ligos Indeo Interactive 4.6'
+RIFFCODEC['IV47'] = 'Ligos Indeo Interactive 4.7'
+RIFFCODEC['IV48'] = 'Ligos Indeo Interactive 4.8'
+RIFFCODEC['IV49'] = 'Ligos Indeo Interactive 4.9'
+RIFFCODEC['IV50'] = 'Ligos Indeo Interactive 5.0'
+RIFFCODEC['JBYR'] = 'Kensington ?JBYR?'
+RIFFCODEC['JPEG'] = 'Still Image JPEG DIB'
+RIFFCODEC['JPGL'] = 'Webcam JPEG Light?'
+RIFFCODEC['KMVC'] = 'Karl Morton\'s Video Codec'
+RIFFCODEC['LEAD'] = 'LEAD Video Codec'
+RIFFCODEC['Ljpg'] = 'LEAD MJPEG Codec'
+RIFFCODEC['M261'] = 'Microsoft H.261'
+RIFFCODEC['M263'] = 'Microsoft H.263'
+RIFFCODEC['M4S2'] = 'Microsoft MPEG-4 (M4S2)'
+RIFFCODEC['m4s2'] = 'Microsoft MPEG-4 (m4s2)'
+RIFFCODEC['MC12'] = 'ATI Motion Compensation Format (MC12)'
+RIFFCODEC['MCAM'] = 'ATI Motion Compensation Format (MCAM)'
+RIFFCODEC['MJ2C'] = 'Morgan Multimedia Motion JPEG2000'
+RIFFCODEC['mJPG'] = 'IBM Motion JPEG w/ Huffman Tables'
+RIFFCODEC['MJPG'] = 'Motion JPEG DIB'
+RIFFCODEC['MP42'] = 'Microsoft MPEG-4 (low-motion)'
+RIFFCODEC['MP43'] = 'Microsoft MPEG-4 (fast-motion)'
+RIFFCODEC['MP4S'] = 'Microsoft MPEG-4 (MP4S)'
+RIFFCODEC['mp4s'] = 'Microsoft MPEG-4 (mp4s)'
+RIFFCODEC['MPEG'] = 'MPEG 1 Video I-Frame'
+RIFFCODEC['MPG4'] = 'Microsoft MPEG-4 Video High Speed Compressor'
+RIFFCODEC['MPGI'] = 'Sigma Designs MPEG'
+RIFFCODEC['MRCA'] = 'FAST Multimedia Mrcodec'
+RIFFCODEC['MRCA'] = 'Martin Regen Codec'
+RIFFCODEC['MRLE'] = 'Microsoft RLE'
+RIFFCODEC['MRLE'] = 'Run Length Encoding'
+RIFFCODEC['MSVC'] = 'Microsoft Video 1'
+RIFFCODEC['MTX1'] = 'Matrox ?MTX1?'
+RIFFCODEC['MTX2'] = 'Matrox ?MTX2?'
+RIFFCODEC['MTX3'] = 'Matrox ?MTX3?'
+RIFFCODEC['MTX4'] = 'Matrox ?MTX4?'
+RIFFCODEC['MTX5'] = 'Matrox ?MTX5?'
+RIFFCODEC['MTX6'] = 'Matrox ?MTX6?'
+RIFFCODEC['MTX7'] = 'Matrox ?MTX7?'
+RIFFCODEC['MTX8'] = 'Matrox ?MTX8?'
+RIFFCODEC['MTX9'] = 'Matrox ?MTX9?'
+RIFFCODEC['MV12'] = '?MV12?'
+RIFFCODEC['MWV1'] = 'Aware Motion Wavelets'
+RIFFCODEC['nAVI'] = '?nAVI?'
+RIFFCODEC['NTN1'] = 'Nogatech Video Compression 1'
+RIFFCODEC['NVS0'] = 'nVidia GeForce Texture (NVS0)'
+RIFFCODEC['NVS1'] = 'nVidia GeForce Texture (NVS1)'
+RIFFCODEC['NVS2'] = 'nVidia GeForce Texture (NVS2)'
+RIFFCODEC['NVS3'] = 'nVidia GeForce Texture (NVS3)'
+RIFFCODEC['NVS4'] = 'nVidia GeForce Texture (NVS4)'
+RIFFCODEC['NVS5'] = 'nVidia GeForce Texture (NVS5)'
+RIFFCODEC['NVT0'] = 'nVidia GeForce Texture (NVT0)'
+RIFFCODEC['NVT1'] = 'nVidia GeForce Texture (NVT1)'
+RIFFCODEC['NVT2'] = 'nVidia GeForce Texture (NVT2)'
+RIFFCODEC['NVT3'] = 'nVidia GeForce Texture (NVT3)'
+RIFFCODEC['NVT4'] = 'nVidia GeForce Texture (NVT4)'
+RIFFCODEC['NVT5'] = 'nVidia GeForce Texture (NVT5)'
+RIFFCODEC['PDVC'] = 'I-O Data Device Digital Video Capture DV codec'
+RIFFCODEC['PGVV'] = 'Radius Video Vision'
+RIFFCODEC['PHMO'] = 'IBM Photomotion'
+RIFFCODEC['PIM1'] = 'Pegasus Imaging ?PIM1?'
+RIFFCODEC['PIM2'] = 'Pegasus Imaging ?PIM2?'
+RIFFCODEC['PIMJ'] = 'Pegasus Imaging Lossless JPEG'
+RIFFCODEC['PVEZ'] = 'Horizons Technology PowerEZ'
+RIFFCODEC['PVMM'] = 'PacketVideo Corporation MPEG-4'
+RIFFCODEC['PVW2'] = 'Pegasus Imaging Wavelet Compression'
+RIFFCODEC['QPEG'] = 'Q-Team QPEG 1.0'
+RIFFCODEC['qpeq'] = 'Q-Team QPEG 1.1'
+RIFFCODEC['RGBT'] = 'Computer Concepts 32-bit support'
+RIFFCODEC['RLE '] = 'Microsoft Run Length Encoder'
+RIFFCODEC['RLE4'] = 'Run Length Encoded 4'
+RIFFCODEC['RLE8'] = 'Run Length Encoded 8'
+RIFFCODEC['RT21'] = 'Intel Indeo 2.1'
+RIFFCODEC['RT21'] = 'Intel Real Time Video 2.1'
+RIFFCODEC['rv20'] = 'RealVideo G2'
+RIFFCODEC['rv30'] = 'RealVideo 8'
+RIFFCODEC['RVX '] = 'Intel RDX (RVX )'
+RIFFCODEC['s422'] = 'Tekram VideoCap C210 YUV 4:2:2'
+RIFFCODEC['SDCC'] = 'Sun Communication Digital Camera Codec'
+RIFFCODEC['SFMC'] = 'CrystalNet Surface Fitting Method'
+RIFFCODEC['SMSC'] = 'Radius SMSC'
+RIFFCODEC['SMSD'] = 'Radius SMSD'
+RIFFCODEC['smsv'] = 'WorldConnect Wavelet Video'
+RIFFCODEC['SPIG'] = 'Radius Spigot'
+RIFFCODEC['SPLC'] = 'Splash Studios ACM Audio Codec'
+RIFFCODEC['SQZ2'] = 'Microsoft VXTreme Video Codec V2'
+RIFFCODEC['STVA'] = 'ST CMOS Imager Data (Bayer)'
+RIFFCODEC['STVB'] = 'ST CMOS Imager Data (Nudged Bayer)'
+RIFFCODEC['STVC'] = 'ST CMOS Imager Data (Bunched)'
+RIFFCODEC['STVX'] = 'ST CMOS Imager Data (Extended CODEC Data Format)'
+RIFFCODEC['STVY'] = 'ST CMOS Imager Data (Extended CODEC Data Format with Correction Data)'
+RIFFCODEC['SV10'] = 'Sorenson Video R1'
+RIFFCODEC['SVQ1'] = 'Sorenson Video'
+RIFFCODEC['SVQ1'] = 'Sorenson Video R3'
+RIFFCODEC['TLMS'] = 'TeraLogic Motion Intraframe Codec (TLMS)'
+RIFFCODEC['TLST'] = 'TeraLogic Motion Intraframe Codec (TLST)'
+RIFFCODEC['TM20'] = 'Duck TrueMotion 2.0'
+RIFFCODEC['TM2X'] = 'Duck TrueMotion 2X'
+RIFFCODEC['TMIC'] = 'TeraLogic Motion Intraframe Codec (TMIC)'
+RIFFCODEC['TMOT'] = 'Horizons Technology TrueMotion S'
+RIFFCODEC['tmot'] = 'Horizons TrueMotion Video Compression'
+RIFFCODEC['TR20'] = 'Duck TrueMotion RealTime 2.0'
+RIFFCODEC['TSCC'] = 'TechSmith Screen Capture Codec'
+RIFFCODEC['TV10'] = 'Tecomac Low-Bit Rate Codec'
+RIFFCODEC['TY0N'] = 'Trident ?TY0N?'
+RIFFCODEC['TY2C'] = 'Trident ?TY2C?'
+RIFFCODEC['TY2N'] = 'Trident ?TY2N?'
+RIFFCODEC['UCOD'] = 'eMajix.com ClearVideo'
+RIFFCODEC['ULTI'] = 'IBM Ultimotion'
+RIFFCODEC['UYVY'] = 'UYVY 4:2:2 byte ordering'
+RIFFCODEC['V261'] = 'Lucent VX2000S'
+RIFFCODEC['V422'] = '24 bit YUV 4:2:2 Format'
+RIFFCODEC['V655'] = '16 bit YUV 4:2:2 Format'
+RIFFCODEC['VCR1'] = 'ATI VCR 1.0'
+RIFFCODEC['VCR2'] = 'ATI VCR 2.0'
+RIFFCODEC['VCR3'] = 'ATI VCR 3.0'
+RIFFCODEC['VCR4'] = 'ATI VCR 4.0'
+RIFFCODEC['VCR5'] = 'ATI VCR 5.0'
+RIFFCODEC['VCR6'] = 'ATI VCR 6.0'
+RIFFCODEC['VCR7'] = 'ATI VCR 7.0'
+RIFFCODEC['VCR8'] = 'ATI VCR 8.0'
+RIFFCODEC['VCR9'] = 'ATI VCR 9.0'
+RIFFCODEC['VDCT'] = 'Video Maker Pro DIB'
+RIFFCODEC['VDOM'] = 'VDOnet VDOWave'
+RIFFCODEC['VDOW'] = 'VDOnet VDOLive (H.263)'
+RIFFCODEC['VDTZ'] = 'Darim Vison VideoTizer YUV'
+RIFFCODEC['VGPX'] = 'VGPixel Codec'
+RIFFCODEC['VIDS'] = 'Vitec Multimedia YUV 4:2:2 CCIR 601 for V422'
+RIFFCODEC['VIDS'] = 'YUV 4:2:2 CCIR 601 for V422'
+RIFFCODEC['VIFP'] = '?VIFP?'
+RIFFCODEC['VIVO'] = 'Vivo H.263 v2.00'
+RIFFCODEC['vivo'] = 'Vivo H.263'
+RIFFCODEC['VIXL'] = 'Miro Video XL'
+RIFFCODEC['VLV1'] = 'Videologic VLCAP.DRV'
+RIFFCODEC['VP30'] = 'On2 VP3.0'
+RIFFCODEC['VP31'] = 'On2 VP3.1'
+RIFFCODEC['VX1K'] = 'VX1000S Video Codec'
+RIFFCODEC['VX2K'] = 'VX2000S Video Codec'
+RIFFCODEC['VXSP'] = 'VX1000SP Video Codec'
+RIFFCODEC['WBVC'] = 'Winbond W9960'
+RIFFCODEC['WHAM'] = 'Microsoft Video 1 (WHAM)'
+RIFFCODEC['WINX'] = 'Winnov Software Compression'
+RIFFCODEC['WJPG'] = 'AverMedia Winbond JPEG'
+RIFFCODEC['WMV1'] = 'Windows Media Video V7'
+RIFFCODEC['WMV2'] = 'Windows Media Video V8'
+RIFFCODEC['WMV3'] = 'Windows Media Video V9'
+RIFFCODEC['WNV1'] = 'Winnov Hardware Compression'
+RIFFCODEC['x263'] = 'Xirlink H.263'
+RIFFCODEC['XLV0'] = 'NetXL Video Decoder'
+RIFFCODEC['XMPG'] = 'Xing MPEG (I-Frame only)'
+RIFFCODEC['XVID'] = 'XviD MPEG-4'
+RIFFCODEC['XXAN'] = '?XXAN?'
+RIFFCODEC['Y211'] = 'YUV 2:1:1 Packed'
+RIFFCODEC['Y411'] = 'YUV 4:1:1 Packed'
+RIFFCODEC['Y41B'] = 'YUV 4:1:1 Planar'
+RIFFCODEC['Y41P'] = 'PC1 4:1:1'
+RIFFCODEC['Y41T'] = 'PC1 4:1:1 with transparency'
+RIFFCODEC['Y42B'] = 'YUV 4:2:2 Planar'
+RIFFCODEC['Y42T'] = 'PCI 4:2:2 with transparency'
+RIFFCODEC['Y8  '] = 'Grayscale video'
+RIFFCODEC['YC12'] = 'Intel YUV 12 codec'
+RIFFCODEC['YC12'] = 'Intel YUV12 Codec'
+RIFFCODEC['YUV8'] = 'Winnov Caviar YUV8'
+RIFFCODEC['YUV9'] = 'Intel YUV9'
+RIFFCODEC['YUY2'] = 'Uncompressed YUV 4:2:2'
+RIFFCODEC['YUYV'] = 'Canopus YUV'
+RIFFCODEC['YV12'] = 'YVU12 Planar'
+RIFFCODEC['YVU9'] = 'Intel YVU9 Planar'
+RIFFCODEC['YVYU'] = 'YVYU 4:2:2 byte ordering'
+RIFFCODEC['ZLIB'] = '?ZLIB?'
+RIFFCODEC['ZPEG'] = 'Metheus Video Zipper'
+
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/riffinfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/riffinfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/riffinfo.py	(revision 4)
@@ -0,0 +1,539 @@
+#if 0
+# $Id: riffinfo.py,v 1.33 2005/03/15 17:50:45 dischi Exp $
+# $Log: riffinfo.py,v $
+# Revision 1.33  2005/03/15 17:50:45  dischi
+# check for corrupt avi
+#
+# Revision 1.32  2005/03/04 17:41:29  dischi
+# handle broken avi files
+#
+# Revision 1.31  2004/12/13 10:19:07  dischi
+# more debug, support LIST > 20000 (new max is 80000)
+#
+# Revision 1.30  2004/08/25 16:18:14  dischi
+# detect aspect ratio
+#
+# Revision 1.29  2004/05/24 16:17:09  dischi
+# Small changes for future updates
+#
+# Revision 1.28  2004/01/31 12:23:46  dischi
+# remove bad chars from table (e.g. char 0 is True)
+#
+# Revision 1.27  2003/10/04 14:30:08  dischi
+# add audio delay for avi
+#
+# Revision 1.26  2003/07/10 11:18:11  the_krow
+# few more attributes added
+#
+# Revision 1.25  2003/07/07 21:36:44  dischi
+# make fps a float and round it to two digest after the comma
+#
+# Revision 1.24  2003/07/05 19:36:37  the_krow
+# length fixed
+# fps introduced
+#
+# Revision 1.23  2003/07/02 11:17:30  the_krow
+# language is now part of the table key
+#
+# Revision 1.22  2003/07/01 21:06:50  dischi
+# no need to import factory (and when, use "from mmpython import factory"
+#
+# Revision 1.21  2003/06/30 13:17:20  the_krow
+# o Refactored mediainfo into factory, synchronizedobject
+# o Parsers now register directly at mmpython not at mmpython.mediainfo
+# o use mmpython.Factory() instead of mmpython.mediainfo.get_singleton()
+# o Bugfix in PNG parser
+# o Renamed disc.AudioInfo into disc.AudioDiscInfo
+# o Renamed disc.DataInfo into disc.DataDiscInfo
+#
+# Revision 1.20  2003/06/23 20:48:11  the_krow
+# width + height fixes for OGM files
+#
+# Revision 1.19  2003/06/23 20:38:04  the_krow
+# Support for larger LIST chunks because some files did not work.
+#
+# Revision 1.18  2003/06/20 19:17:22  dischi
+# remove filename again and use file.name
+#
+# Revision 1.17  2003/06/20 19:05:56  dischi
+# scan for subtitles
+#
+# Revision 1.16  2003/06/20 15:29:42  the_krow
+# Metadata Mapping
+#
+# Revision 1.15  2003/06/20 14:43:57  the_krow
+# Putting Metadata into MediaInfo from AVIInfo Table
+#
+# Revision 1.14  2003/06/09 16:10:52  dischi
+# error handling
+#
+# Revision 1.13  2003/06/08 19:53:21  dischi
+# also give the filename to init for additional data tests
+#
+# Revision 1.12  2003/06/08 13:44:58  dischi
+# Changed all imports to use the complete mmpython path for mediainfo
+#
+# Revision 1.11  2003/06/08 13:11:38  dischi
+# removed print at the end and moved it into register
+#
+# Revision 1.10  2003/06/07 23:10:50  the_krow
+# Changed mp3 into new format.
+#
+# Revision 1.9  2003/06/07 22:30:22  the_krow
+# added new avinfo structure
+#
+# Revision 1.8  2003/06/07 21:48:47  the_krow
+# Added Copying info
+# started changing riffinfo to new AV stuff
+#
+# Revision 1.7  2003/05/13 12:31:43  the_krow
+# + Copyright Notice
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import struct
+import string
+import fourcc
+# import factory
+
+import mmpython
+from mmpython import mediainfo
+
+
+# List of tags
+# http://kibus1.narod.ru/frames_eng.htm?sof/abcavi/infotags.htm
+# http://www.divx-digest.com/software/avitags_dll.html
+# File Format
+# http://www.taenam.co.kr/pds/documents/odmlff2.pdf
+
+_print = mediainfo._debug
+
+AVIINFO_tags = { 'title': 'INAM',
+                 'artist': 'IART',
+                 'product': 'IPRD',
+                 'date': 'ICRD',
+                 'comment': 'ICMT',
+                 'language': 'ILNG',
+                 'keywords': 'IKEY',
+                 'trackno': 'IPRT',
+                 'trackof': 'IFRM',
+                 'producer': 'IPRO',
+                 'writer': 'IWRI',
+                 'genre': 'IGNR',
+                 'copyright': 'ICOP',
+                 'trackno': 'IPRT',
+                 'trackof': 'IFRM',
+                 'comment': 'ICMT',
+               }
+
+
+
+class RiffInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        # read the header
+        h = file.read(12)
+        if h[:4] != "RIFF" and h[:4] != 'SDSS':
+            self.valid = 0
+            return
+        self.valid = 1
+        self.mime = 'application/x-wave'
+        self.has_idx = False
+        self.header = {}
+        self.junkStart = None
+        self.infoStart = None
+        self.type = h[8:12]
+        self.tag_map = { ('AVIINFO', 'en') : AVIINFO_tags }
+        if self.type == 'AVI ':
+            self.mime = 'video/avi'
+        elif self.type == 'WAVE':
+            self.mime = 'application/x-wave'
+        try:
+            while self.parseRIFFChunk(file):
+                pass
+        except IOError:
+            if mediainfo.DEBUG:
+                print 'error in file, stop parsing'
+
+        self.find_subtitles(file.name)
+        
+        # Copy Metadata from tables into the main set of attributes        
+        for k in self.tag_map.keys():
+            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),self.tag_map[k][x]),
+                self.tag_map[k].keys())
+        if not self.has_idx:
+            _print('WARNING: avi has no index')
+            self.corrupt = 1
+            self.keys.append('corrupt')
+            
+        
+    def _extractHeaderString(self,h,offset,len):
+        return h[offset:offset+len]
+
+    def parseAVIH(self,t):
+        retval = {}
+        v = struct.unpack('<IIIIIIIIIIIIII',t[0:56])
+        ( retval['dwMicroSecPerFrame'],
+          retval['dwMaxBytesPerSec'],           
+          retval['dwPaddingGranularity'], 
+          retval['dwFlags'], 
+          retval['dwTotalFrames'],
+          retval['dwInitialFrames'],
+          retval['dwStreams'],
+          retval['dwSuggestedBufferSize'],
+          retval['dwWidth'],
+          retval['dwHeight'],
+          retval['dwScale'],
+          retval['dwRate'],
+          retval['dwStart'],
+          retval['dwLength'] ) = v
+        if retval['dwMicroSecPerFrame'] == 0:
+            _print("ERROR: Corrupt AVI")
+            self.valid = 0
+            return {}
+        return retval
+        
+    def parseSTRH(self,t):
+        retval = {}
+        retval['fccType'] = t[0:4]
+        _print("parseSTRH(%s) : %d bytes" % ( retval['fccType'], len(t)))
+        if retval['fccType'] != 'auds':
+            retval['fccHandler'] = t[4:8]
+            v = struct.unpack('<IHHIIIIIIIII',t[8:52])
+            ( retval['dwFlags'],
+              retval['wPriority'],
+              retval['wLanguage'],
+              retval['dwInitialFrames'],
+              retval['dwScale'],
+              retval['dwRate'],
+              retval['dwStart'],
+              retval['dwLength'],
+              retval['dwSuggestedBufferSize'],
+              retval['dwQuality'],
+              retval['dwSampleSize'],
+              retval['rcFrame'], ) = v
+        else:
+            try:
+                v = struct.unpack('<IHHIIIIIIIII',t[8:52])
+                ( retval['dwFlags'],
+                  retval['wPriority'],
+                  retval['wLanguage'],
+                  retval['dwInitialFrames'],
+                  retval['dwScale'],
+                  retval['dwRate'],
+                  retval['dwStart'],
+                  retval['dwLength'],
+                  retval['dwSuggestedBufferSize'],
+                  retval['dwQuality'],
+                  retval['dwSampleSize'],
+                  retval['rcFrame'], ) = v
+                self.delay = float(retval['dwStart']) / \
+                             (float(retval['dwRate']) / retval['dwScale'])
+            except:
+                pass
+            
+        return retval
+
+    def parseSTRF(self,t,strh):
+        fccType = strh['fccType']
+        retval = {}
+        if fccType == 'auds':
+            ( retval['wFormatTag'],
+              retval['nChannels'],
+              retval['nSamplesPerSec'],
+              retval['nAvgBytesPerSec'],
+              retval['nBlockAlign'],
+              retval['nBitsPerSample'],
+            ) = struct.unpack('<HHHHHH',t[0:12])
+            ai = mediainfo.AudioInfo()
+            ai.samplerate = retval['nSamplesPerSec']
+            ai.channels = retval['nChannels']
+            ai.samplebits = retval['nBitsPerSample']
+            ai.bitrate = retval['nAvgBytesPerSec'] * 8
+            # TODO: set code if possible
+            # http://www.stats.uwa.edu.au/Internal/Specs/DXALL/FileSpec/Languages
+            # ai.language = strh['wLanguage']
+            try:
+                ai.codec = fourcc.RIFFWAVE[retval['wFormatTag']]
+            except:
+                ai.codec = "Unknown"            
+            self.audio.append(ai)  
+        elif fccType == 'vids':
+            v = struct.unpack('<IIIHH',t[0:16])
+            ( retval['biSize'],
+              retval['biWidth'],
+              retval['biHeight'],
+              retval['biPlanes'],
+              retval['biBitCount'], ) = v
+            retval['fourcc'] = t[16:20]            
+            v = struct.unpack('IIIII',t[20:40])
+            ( retval['biSizeImage'],
+              retval['biXPelsPerMeter'],
+              retval['biYPelsPerMeter'],
+              retval['biClrUsed'],
+              retval['biClrImportant'], ) = v
+            vi = mediainfo.VideoInfo()
+            try:
+                vi.codec = fourcc.RIFFCODEC[t[16:20]]
+            except:
+                vi.codec = "Unknown"
+            vi.width = retval['biWidth']
+            vi.height = retval['biHeight']            
+            vi.bitrate = strh['dwRate']
+            vi.fps = round(float(strh['dwRate'] * 100) / strh['dwScale']) / 100
+            vi.length = strh['dwLength'] / vi.fps 
+            self.video.append(vi)  
+        return retval
+        
+
+    def parseSTRL(self,t):
+        retval = {}
+        size = len(t)
+        i = 0
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i+=8
+        value = t[i:]
+
+        if key == 'strh':
+            retval[key] = self.parseSTRH(value)
+            i += sz
+        else:
+            _print("parseSTRL: Error")
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i+=8
+        value = t[i:]
+
+        if key == 'strf':
+            retval[key] = self.parseSTRF(value, retval['strh'])
+            i += sz
+        return ( retval, i )
+
+            
+    def parseODML(self,t):
+        retval = {}
+        size = len(t)
+        i = 0
+        key = t[i:i+4]
+        sz = struct.unpack('<I',t[i+4:i+8])[0]
+        i += 8
+        value = t[i:]
+        if key == 'dmlh':
+            pass
+        else:
+            _print("parseODML: Error")
+
+        i += sz - 8
+        return ( retval, i )
+
+            
+    def parseVPRP(self,t):
+        retval = {}
+        v = struct.unpack('<IIIIIIIIII',t[:4*10])
+        
+        ( retval['VideoFormat'],
+          retval['VideoStandard'],
+          retval['RefreshRate'],
+          retval['HTotalIn'],
+          retval['VTotalIn'],
+          retval['FrameAspectRatio'],
+          retval['wPixel'],
+          retval['hPixel'] ) = v[1:-1]
+
+        # I need an avi with more informations
+        # enum {FORMAT_UNKNOWN, FORMAT_PAL_SQUARE, FORMAT_PAL_CCIR_601,
+        #    FORMAT_NTSC_SQUARE, FORMAT_NTSC_CCIR_601,...} VIDEO_FORMAT; 
+        # enum {STANDARD_UNKNOWN, STANDARD_PAL, STANDARD_NTSC, STANDARD_SECAM}
+        #    VIDEO_STANDARD; 
+        #
+        r = retval['FrameAspectRatio']
+        r = float(r >> 16) / (r & 0xFFFF)
+        retval['FrameAspectRatio'] = r
+        if self.video:
+            map(lambda v: setattr(v, 'aspect', r), self.video)
+        return ( retval, v[0] )
+
+            
+    def parseLIST(self,t):
+        retval = {}
+        i = 0
+        size = len(t)
+
+        while i < size-8:
+            # skip zero
+            if ord(t[i]) == 0: i += 1
+            key = t[i:i+4]
+            sz = 0
+
+            if key == 'LIST':
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                _print("-> SUBLIST: len: %d, %d" % ( sz, i+4 ))
+                i+=8
+                key = "LIST:"+t[i:i+4]
+                value = self.parseLIST(t[i:i+sz])
+                _print("<-")
+                if key == 'strl':
+                    for k in value.keys():
+                        retval[k] = value[k]
+                else:
+                    retval[key] = value
+                i+=sz
+            elif key == 'avih':
+                _print("SUBAVIH")
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                i += 8
+                value = self.parseAVIH(t[i:i+sz])
+                i += sz
+                retval[key] = value
+            elif key == 'strl':
+                i += 4
+                (value, sz) = self.parseSTRL(t[i:])
+                _print("SUBSTRL: len: %d" % sz)
+                key = value['strh']['fccType']
+                i += sz
+                retval[key] = value
+            elif key == 'odml':
+                i += 4
+                (value, sz) = self.parseODML(t[i:])
+                _print("ODML: len: %d" % sz)
+                i += sz
+            elif key == 'vprp':
+                i += 4
+                (value, sz) = self.parseVPRP(t[i:])
+                _print("VPRP: len: %d" % sz)
+                retval[key] = value
+                i += sz
+            elif key == 'JUNK':
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                i += sz + 8
+                _print("Skipping %d bytes of Junk" % sz)
+            else:
+                sz = struct.unpack('<I',t[i+4:i+8])[0]
+                _print("Unknown Key: %s, len: %d" % (key,sz))
+                i+=8
+                value = self._extractHeaderString(t,i,sz)
+                value = value.replace('\0', '').lstrip().rstrip()
+                if value:
+                    retval[key] = value
+                i+=sz
+        return retval
+        
+
+    def parseRIFFChunk(self,file):
+        h = file.read(8)
+        if len(h) < 4:
+            return False
+        name = h[:4]
+        size = struct.unpack('<I',h[4:8])[0]        
+
+        if name == 'LIST' and size < 80000:
+            pos = file.tell() - 8
+            t = file.read(size)
+            key = t[:4]
+            _print('parse RIFF LIST: %d bytes' % (size))
+            value = self.parseLIST(t[4:])
+            self.header[key] = value
+            if key == 'INFO':
+                self.infoStart = pos
+                self.appendtable( 'AVIINFO', value )
+            elif key == 'MID ':
+                self.appendtable( 'AVIMID', value )
+            elif key in ('hdrl', ):
+                # no need to add this info to a table
+                pass
+            else:
+                _print('Skipping table info %s' % key)
+
+        elif name == 'JUNK':
+            self.junkStart = file.tell() - 8
+            self.junkSize  = size
+            file.seek(size, 1)
+        elif name == 'idx1':
+            self.has_idx = True
+            _print('idx1: %s bytes' % size)
+            # no need to parse this
+            t = file.seek(size,1)
+        elif name == 'LIST':
+            _print('RIFF LIST to long to parse: %s bytes' % size)
+            # no need to parse this
+            t = file.seek(size,1)
+        elif name == 'RIFF':
+            _print("New RIFF chunk, extended avi [%i]" % size)
+            type = file.read(4)
+            if type != 'AVIX':
+                _print("Second RIFF chunk is %s, not AVIX, skipping", type)
+                file.seek(size-4, 1)
+            # that's it, no new informations should be in AVIX
+            return False
+        elif not name.strip(string.printable + string.whitespace):
+            # check if name is something usefull at all, maybe it is no
+            # avi or broken
+            t = file.seek(size,1)
+            _print("Skipping %s [%i]" % (name,size))
+        else:
+            # bad avi
+            _print("Bad or broken avi")
+            return False
+        return True
+
+    def buildTag(self,key,value):
+        text = value + '\0'
+        l = len(text)
+        return struct.pack('<4sI%ds'%l, key[:4], l, text[:l])
+
+
+    def setInfo(self,file,hash):
+        if self.junkStart == None:
+            raise "junkstart missing"
+        tags = []
+        size = 4 # Length of 'INFO'
+        # Build String List and compute req. size
+        for key in hash.keys():
+            tag = self.buildTag( key, hash[key] )
+            if (len(tag))%2 == 1: tag += '\0'
+            tags.append(tag)
+            size += len(tag)
+            _print("Tag [%i]: %s" % (len(tag),tag))
+        if self.infoStart != None:
+            _print("Infostart found. %i" % (self.infoStart))
+            # Read current info size
+            file.seek(self.infoStart,0)
+            s = file.read(12)
+            (list, oldsize, info) = struct.unpack('<4sI4s',s)
+            self.junkSize += oldsize + 8
+        else:
+            self.infoStart = self.junkStart
+            _print("Infostart computed. %i" % (self.infoStart))
+        file.seek(self.infoStart,0)
+        if ( size > self.junkSize - 8 ):
+            raise "Too large"
+        file.write( "LIST" + struct.pack('<I',size) + "INFO" )
+        for tag in tags:
+            file.write( tag )
+        _print("Junksize %i" % (self.junkSize-size-8))
+        file.write( "JUNK" + struct.pack('<I',self.junkSize-size-8) )
+        
+
+
+mmpython.registertype( 'video/avi', ('avi',), mediainfo.TYPE_AV, RiffInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mpeginfo.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mpeginfo.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/video/mpeginfo.py	(revision 4)
@@ -0,0 +1,897 @@
+#if 0
+# $Id: mpeginfo.py,v 1.33 2005/02/15 18:52:51 dischi Exp $
+# $Log: mpeginfo.py,v $
+# Revision 1.33  2005/02/15 18:52:51  dischi
+# some strange bugfix (what is this doing?)
+#
+# Revision 1.32  2005/01/21 16:37:02  dischi
+# try to find bad timestamps
+#
+# Revision 1.31  2005/01/08 12:06:45  dischi
+# make sure the buffer is big enough
+#
+# Revision 1.30  2005/01/02 14:57:27  dischi
+# detect ac3 in normal mpeg2
+#
+# Revision 1.29  2004/11/27 14:42:12  dischi
+# remove future warning
+#
+# Revision 1.28  2004/11/15 21:43:36  dischi
+# remove bad debugging stuff
+#
+# Revision 1.27  2004/11/12 18:10:45  dischi
+# add ac3 support in mpeg streams
+#
+# Revision 1.26  2004/10/04 18:06:54  dischi
+# test length of remaining buffer
+#
+# Revision 1.25  2004/07/11 19:37:25  dischi
+# o read more bytes on ts scan
+# o support for AC3 in private streams
+#
+# Revision 1.24  2004/07/03 09:01:32  dischi
+# o fix PES start detection inside TS
+# o try to find out if the stream is progressive or interlaced
+#
+# Revision 1.23  2004/06/23 19:44:10  dischi
+# better length detection, big cleanup
+#
+# Revision 1.22  2004/06/22 21:37:34  dischi
+# o PES support
+# o basic length detection for TS and PES
+#
+# Revision 1.21  2004/06/21 20:37:34  dischi
+# basic support for mpeg-ts
+#
+# Revision 1.20  2004/03/13 23:41:59  dischi
+# add AudioInfo to mpeg for all streams
+#
+# Revision 1.19  2004/02/11 20:11:54  dischi
+# Updated length calculation for mpeg files. This may not work for all files.
+#
+#
+# MMPython - Media Metadata for Python
+# Copyright (C) 2003 Thomas Schueppel
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
+# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# 
+# -----------------------------------------------------------------------
+#endif
+
+import re
+import os
+import struct
+import string
+import fourcc
+
+from mmpython import mediainfo
+import mmpython
+import stat
+
+##------------------------------------------------------------------------
+## START_CODE
+##
+## Start Codes, with 'slice' occupying 0x01..0xAF
+##------------------------------------------------------------------------
+START_CODE = {
+    0x00 : 'picture_start_code',
+    0xB0 : 'reserved',
+    0xB1 : 'reserved',
+    0xB2 : 'user_data_start_code',
+    0xB3 : 'sequence_header_code',
+    0xB4 : 'sequence_error_code',
+    0xB5 : 'extension_start_code',
+    0xB6 : 'reserved',
+    0xB7 : 'sequence end',
+    0xB8 : 'group of pictures',
+}
+for i in range(0x01,0xAF): 
+    START_CODE[i] = 'slice_start_code'
+
+##------------------------------------------------------------------------
+## START CODES
+##------------------------------------------------------------------------
+PICTURE   = 0x00
+USERDATA  = 0xB2
+SEQ_HEAD  = 0xB3
+SEQ_ERR   = 0xB4
+EXT_START = 0xB5
+SEQ_END   = 0xB7
+GOP       = 0xB8
+
+SEQ_START_CODE  = 0xB3
+PACK_PKT        = 0xBA
+SYS_PKT         = 0xBB
+PADDING_PKT     = 0xBE
+AUDIO_PKT       = 0xC0
+VIDEO_PKT       = 0xE0
+PRIVATE_STREAM1 = 0xBD
+PRIVATE_STREAM2 = 0xBf
+
+TS_PACKET_LENGTH = 188
+TS_SYNC          = 0x47
+
+##------------------------------------------------------------------------
+## FRAME_RATE
+##
+## A lookup table of all the standard frame rates.  Some rates adhere to
+## a particular profile that ensures compatibility with VLSI capabilities
+## of the early to mid 1990s.
+##
+## CPB
+##   Constrained Parameters Bitstreams, an MPEG-1 set of sampling and 
+##   bitstream parameters designed to normalize decoder computational 
+##   complexity, buffer size, and memory bandwidth while still addressing 
+##   the widest possible range of applications.
+##
+## Main Level
+##   MPEG-2 Video Main Profile and Main Level is analogous to MPEG-1's 
+##   CPB, with sampling limits at CCIR 601 parameters (720x480x30 Hz or 
+##   720x576x24 Hz). 
+##
+##------------------------------------------------------------------------ 
+FRAME_RATE = [ 
+      0, 
+      round(24000.0/1001*100)/100, ## 3-2 pulldown NTSC (CPB/Main Level)
+      24,           ## Film (CPB/Main Level)
+      25,           ## PAL/SECAM or 625/60 video
+      round(30000.0/1001*100)/100, ## NTSC (CPB/Main Level)
+      30,           ## drop-frame NTSC or component 525/60  (CPB/Main Level)
+      50,           ## double-rate PAL
+      round(60000.0/1001*100)/100, ## double-rate NTSC
+      60,           ## double-rate, drop-frame NTSC/component 525/60 video
+      ]
+
+##------------------------------------------------------------------------
+## ASPECT_RATIO -- INCOMPLETE?
+##
+## This lookup table maps the header aspect ratio index to a common name.
+## These are just the defined ratios for CPB I believe.  As I understand 
+## it, a stream that doesn't adhere to one of these aspect ratios is
+## technically considered non-compliant.
+##------------------------------------------------------------------------ 
+ASPECT_RATIO = [ 'Forbidden',
+                 '1/1 (VGA)',
+                 '4/3 (TV)',
+                 '16/9 (Large TV)',
+                 '2.21/1 (Cinema)',
+               ]
+ 
+
+class MpegInfo(mediainfo.AVInfo):
+    def __init__(self,file):
+        mediainfo.AVInfo.__init__(self)
+        self.context = 'video'
+        self.sequence_header_offset = 0
+
+        # detect TS (fast scan)
+        self.valid = self.isTS(file) 
+
+        if not self.valid:
+            # detect system mpeg (many infos)
+            self.valid = self.isMPEG(file) 
+
+        if not self.valid:
+            # detect PES
+            self.valid = self.isPES(file) 
+            
+        if self.valid:       
+            self.mime = 'video/mpeg'
+            if not self.video:
+                self.video.append(mediainfo.VideoInfo())
+
+            if self.sequence_header_offset <= 0:
+                return
+
+            self.progressive(file)
+            
+            for vi in self.video:
+                vi.width, vi.height = self.dxy(file)
+                vi.fps, vi.aspect = self.framerate_aspect(file)
+                vi.bitrate = self.bitrate(file)
+                if self.length:
+                    vi.length = self.length
+
+            if not self.type:
+                if self.video[0].width == 480:
+                    self.type = 'MPEG2 video' # SVCD spec
+                elif self.video[0].width == 352:
+                    self.type = 'MPEG1 video' # VCD spec
+                else:
+                    self.type = 'MPEG video'
+
+            if mediainfo.DEBUG > 2:
+                self.__scan__()
+
+            
+    def dxy(self,file):  
+        """
+        get width and height of the video
+        """
+        file.seek(self.sequence_header_offset+4,0)
+        v = file.read(4)
+        x = struct.unpack('>H',v[:2])[0] >> 4
+        y = struct.unpack('>H',v[1:3])[0] & 0x0FFF
+        return (x,y)
+
+        
+    def framerate_aspect(self,file):
+        """
+        read framerate and aspect ratio
+        """
+        file.seek(self.sequence_header_offset+7,0)
+        v = struct.unpack( '>B', file.read(1) )[0] 
+        try:
+            fps = FRAME_RATE[v&0xf]
+        except IndexError:
+            fps = None
+        try:
+            aspect = ASPECT_RATIO[v>>4]
+        except IndexError:
+            if mediainfo.DEBUG:
+                print 'Index error: %s' % (v>>4)
+            aspect = None
+        return (fps, aspect)
+        
+
+    def progressive(self, file):
+        """
+        Try to find out with brute force if the mpeg is interlaced or not.
+        Search for the Sequence_Extension in the extension header (01B5)
+        """
+        file.seek(0)
+        buffer = ''
+        count  = 0
+        while 1:
+            if len(buffer) < 1000:
+                count += 1
+                if count > 1000:
+                    break
+                buffer += file.read(1024)
+            if len(buffer) < 1000:
+                break
+            pos = buffer.find('\x00\x00\x01\xb5')
+            if pos == -1 or len(buffer) - pos < 5:
+                buffer = buffer[-10:]
+                continue
+            ext = (ord(buffer[pos+4]) >> 4)
+            if ext == 8:
+                pass
+            elif ext == 1:
+                if (ord(buffer[pos+5]) >> 3) & 1:
+                    self.keys.append('progressive')
+                    self.progressive = 1
+                else:
+                    self.keys.append('interlaced')
+                    self.interlaced = 1
+                return True
+            else:
+                print 'ext', ext
+            buffer = buffer[pos+4:]
+        return False
+    
+        
+    ##------------------------------------------------------------------------
+    ## bitrate()
+    ##
+    ## From the MPEG-2.2 spec:
+    ##
+    ##   bit_rate -- This is a 30-bit integer.  The lower 18 bits of the 
+    ##   integer are in bit_rate_value and the upper 12 bits are in 
+    ##   bit_rate_extension.  The 30-bit integer specifies the bitrate of the 
+    ##   bitstream measured in units of 400 bits/second, rounded upwards. 
+    ##   The value zero is forbidden.
+    ##
+    ## So ignoring all the variable bitrate stuff for now, this 30 bit integer
+    ## multiplied times 400 bits/sec should give the rate in bits/sec.
+    ##  
+    ## TODO: Variable bitrates?  I need one that implements this.
+    ## 
+    ## Continued from the MPEG-2.2 spec:
+    ##
+    ##   If the bitstream is a constant bitrate stream, the bitrate specified 
+    ##   is the actual rate of operation of the VBV specified in annex C.  If 
+    ##   the bitstream is a variable bitrate stream, the STD specifications in 
+    ##   ISO/IEC 13818-1 supersede the VBV, and the bitrate specified here is 
+    ##   used to dimension the transport stream STD (2.4.2 in ITU-T Rec. xxx | 
+    ##   ISO/IEC 13818-1), or the program stream STD (2.4.5 in ITU-T Rec. xxx | 
+    ##   ISO/IEC 13818-1).
+    ## 
+    ##   If the bitstream is not a constant rate bitstream the vbv_delay 
+    ##   field shall have the value FFFF in hexadecimal.
+    ##
+    ##   Given the value encoded in the bitrate field, the bitstream shall be 
+    ##   generated so that the video encoding and the worst case multiplex 
+    ##   jitter do not cause STD buffer overflow or underflow.
+    ##
+    ##
+    ##------------------------------------------------------------------------ 
+
+
+    ## Some parts in the code are based on mpgtx (mpgtx.sf.net)
+    
+    def bitrate(self,file):
+        """
+        read the bitrate (most of the time broken)
+        """
+        file.seek(self.sequence_header_offset+8,0)
+        t,b = struct.unpack( '>HB', file.read(3) )
+        vrate = t << 2 | b >> 6
+        return vrate * 400
+        
+
+    def ReadSCRMpeg2(self, buffer):
+        """
+        read SCR (timestamp) for MPEG2 at the buffer beginning (6 Bytes)
+        """
+	highbit = (ord(buffer[0])&0x20)>>5
+
+	low4Bytes= ((long(ord(buffer[0])) & 0x18) >> 3) << 30
+	low4Bytes |= (ord(buffer[0]) & 0x03) << 28
+	low4Bytes |= ord(buffer[1]) << 20
+	low4Bytes |= (ord(buffer[2]) & 0xF8) << 12
+	low4Bytes |= (ord(buffer[2]) & 0x03) << 13
+	low4Bytes |= ord(buffer[3]) << 5
+	low4Bytes |= (ord(buffer[4])) >> 3
+
+	sys_clock_ref=(ord(buffer[4]) & 0x3) << 7
+	sys_clock_ref|=(ord(buffer[5]) >> 1)
+
+ 	return (long(highbit * (1<<16) * (1<<16)) + low4Bytes) / 90000
+
+
+    def ReadSCRMpeg1(self, buffer):
+        """
+        read SCR (timestamp) for MPEG1 at the buffer beginning (5 Bytes)
+        """
+	highbit = (ord(buffer[0]) >> 3) & 0x01
+
+	low4Bytes = ((long(ord(buffer[0])) >> 1) & 0x03) << 30
+	low4Bytes |= ord(buffer[1]) << 22;
+	low4Bytes |= (ord(buffer[2]) >> 1) << 15;
+	low4Bytes |= ord(buffer[3]) << 7;
+	low4Bytes |= ord(buffer[4]) >> 1;
+
+	return (long(highbit) * (1<<16) * (1<<16) + low4Bytes) / 90000;
+
+
+    def ReadPTS(self, buffer):
+        """
+        read PTS (PES timestamp) at the buffer beginning (5 Bytes)
+        """
+        high = ((ord(buffer[0]) & 0xF) >> 1)
+        med  = (ord(buffer[1]) << 7) + (ord(buffer[2]) >> 1)
+        low  = (ord(buffer[3]) << 7) + (ord(buffer[4]) >> 1)
+        return ((long(high) << 30 ) + (med << 15) + low) / 90000
+
+
+    def ReadHeader(self, buffer, offset):
+        """
+        Handle MPEG header in buffer on position offset
+        Return -1 on error, new offset or 0 if the new offset can't be scanned
+        """
+        if buffer[offset:offset+3] != '\x00\x00\x01':
+            return -1
+
+        id = ord(buffer[offset+3])
+
+        if id == PADDING_PKT:
+            return offset + (ord(buffer[offset+4]) << 8) + ord(buffer[offset+5]) + 6
+
+        if id == PACK_PKT:
+            if ord(buffer[offset+4]) & 0xF0 == 0x20:
+                self.type     = 'MPEG1 video'
+                self.get_time = self.ReadSCRMpeg1
+                return offset + 12
+            elif (ord(buffer[offset+4]) & 0xC0) == 0x40:
+                self.type     = 'MPEG2 video'
+                self.get_time = self.ReadSCRMpeg2
+                return offset + (ord(buffer[offset+13]) & 0x07) + 14
+            else:
+                # WTF? Very strange
+                return -1
+
+        if 0xC0 <= id <= 0xDF:
+            # code for audio stream
+            for a in self.audio:
+                if a.id == id:
+                    break
+            else:
+                self.audio.append(mediainfo.AudioInfo())
+                self.audio[-1].id = id
+                self.audio[-1].keys.append('id')
+            return 0
+
+        if 0xE0 <= id <= 0xEF:
+            # code for video stream
+            for v in self.video:
+                if v.id == id:
+                    break
+            else:
+                self.video.append(mediainfo.VideoInfo())
+                self.video[-1].id = id
+                self.video[-1].keys.append('id')
+            return 0
+
+        if id == SEQ_HEAD:
+            # sequence header, remember that position for later use
+            self.sequence_header_offset = offset
+            return 0
+
+        if id in (PRIVATE_STREAM1, PRIVATE_STREAM2):
+            # private stream. we don't know, but maybe we can guess later
+            add = ord(buffer[offset+8])
+            # if (ord(buffer[offset+6]) & 4) or 1:
+            # id = ord(buffer[offset+10+add])
+            if buffer[offset+11+add:offset+15+add].find('\x0b\x77') != -1:
+                # AC3 stream
+                for a in self.audio:
+                    if a.id == id:
+                        break
+                else:
+                    self.audio.append(mediainfo.AudioInfo())
+                    self.audio[-1].id = id
+                    self.audio[-1].codec = 'AC3'
+                    self.audio[-1].keys.append('id')
+            return 0
+
+        if id == SYS_PKT:
+            return 0
+        
+        if id == EXT_START:
+            return 0
+        
+        return 0
+
+
+    # Normal MPEG (VCD, SVCD) ========================================
+        
+    def isMPEG(self, file):
+        """
+        This MPEG starts with a sequence of 0x00 followed by a PACK Header
+        http://dvd.sourceforge.net/dvdinfo/packhdr.html
+        """
+        file.seek(0,0)
+        buffer = file.read(10000)
+        offset = 0
+
+        # seek until the 0 byte stop
+        while buffer[offset] == '\0':
+            offset += 1
+        offset -= 2
+
+        # test for mpeg header 0x00 0x00 0x01
+        if not buffer[offset:offset+4] == '\x00\x00\x01%s' % chr(PACK_PKT):
+            return 0
+
+        # scan the 100000 bytes of data
+        buffer += file.read(100000)
+
+        # scan first header, to get basic info about
+        # how to read a timestamp
+        self.ReadHeader(buffer, offset)
+
+        # store first timestamp
+        self.start = self.get_time(buffer[offset+4:])
+        while len(buffer) > offset + 1000 and buffer[offset:offset+3] == '\x00\x00\x01':
+            # read the mpeg header
+            new_offset = self.ReadHeader(buffer, offset)
+
+            # header scanning detected error, this is no mpeg
+            if new_offset == -1:
+                return 0
+
+            if new_offset:
+                # we have a new offset
+                offset = new_offset
+
+                # skip padding 0 before a new header
+                while len(buffer) > offset + 10 and \
+                          not ord(buffer[offset+2]):
+                    offset += 1
+
+            else:
+                # seek to new header by brute force
+                offset += buffer[offset+4:].find('\x00\x00\x01') + 4
+
+        # fill in values for support functions:
+        self.__seek_size__   = 1000000
+        self.__sample_size__ = 10000
+        self.__search__      = self._find_timer_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_(self, buffer):
+        """
+        Return position of timer in buffer or -1 if not found.
+        This function is valid for 'normal' mpeg files
+        """
+        pos = buffer.find('\x00\x00\x01%s' % chr(PACK_PKT))
+        if pos == -1:
+            return -1
+        return pos + 4
+        
+
+
+    # PES ============================================================
+
+
+    def ReadPESHeader(self, offset, buffer, id=0):
+        """
+        Parse a PES header.
+        Since it starts with 0x00 0x00 0x01 like 'normal' mpegs, this
+        function will return (0, -1) when it is no PES header or
+        (packet length, timestamp position (maybe -1))
+        
+        http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
+        """
+        if not buffer[0:3] == '\x00\x00\x01':
+            return 0, -1
+
+        packet_length = (ord(buffer[4]) << 8) + ord(buffer[5]) + 6
+        align         = ord(buffer[6]) & 4
+        header_length = ord(buffer[8])
+
+        # PES ID (starting with 001)
+        if ord(buffer[3]) & 0xE0 == 0xC0:
+            id = id or ord(buffer[3]) & 0x1F
+            for a in self.audio:
+                if a.id == id:
+                    break
+            else:
+                self.audio.append(mediainfo.AudioInfo())
+                self.audio[-1].id = id
+                self.audio[-1].keys.append('id')
+
+        elif ord(buffer[3]) & 0xF0 == 0xE0:
+            id = id or ord(buffer[3]) & 0xF
+            for v in self.video:
+                if v.id == id:
+                    break
+            else:
+                self.video.append(mediainfo.VideoInfo())
+                self.video[-1].id = id
+                self.video[-1].keys.append('id')
+
+            # new mpeg starting
+            if buffer[header_length+9:header_length+13] == \
+                   '\x00\x00\x01\xB3' and not self.sequence_header_offset:
+                # yes, remember offset for later use
+                self.sequence_header_offset = offset + header_length+9
+        elif ord(buffer[3]) == 189 or ord(buffer[3]) == 191:
+            # private stream. we don't know, but maybe we can guess later
+            id = id or ord(buffer[3]) & 0xF
+            if align and buffer[header_length+9:header_length+11] == '\x0b\x77':
+                # AC3 stream
+                for a in self.audio:
+                    if a.id == id:
+                        break
+                else:
+                    self.audio.append(mediainfo.AudioInfo())
+                    self.audio[-1].id = id
+                    self.audio[-1].codec = 'AC3'
+                    self.audio[-1].keys.append('id')
+
+        else:
+            # unknown content
+            pass
+
+        ptsdts = ord(buffer[7]) >> 6
+
+        if ptsdts and ptsdts == ord(buffer[9]) >> 4:
+            if ord(buffer[9]) >> 4 != ptsdts:
+                print 'WARNING: bad PTS/DTS, please contact us'
+                return packet_length, -1
+                
+            # timestamp = self.ReadPTS(buffer[9:14])
+            high = ((ord(buffer[9]) & 0xF) >> 1)
+            med  = (ord(buffer[10]) << 7) + (ord(buffer[11]) >> 1)
+            low  = (ord(buffer[12]) << 7) + (ord(buffer[13]) >> 1)
+            return packet_length, 9
+            
+        return packet_length, -1
+    
+
+
+    def isPES(self, file):
+        if mediainfo.DEBUG:
+            print 'trying mpeg-pes scan'
+        file.seek(0,0)
+        buffer = file.read(3)
+
+        # header (also valid for all mpegs)
+        if not buffer == '\x00\x00\x01':
+            return 0
+
+        self.sequence_header_offset = 0
+        buffer += file.read(10000)
+
+        offset = 0
+        while offset + 1000 < len(buffer):
+            pos, timestamp = self.ReadPESHeader(offset, buffer[offset:])
+            if not pos:
+                return 0
+            if timestamp != -1 and not hasattr(self, 'start'):
+                self.get_time = self.ReadPTS
+                self.start = self.get_time(buffer[offset+timestamp:offset+timestamp+5])
+            if self.sequence_header_offset and hasattr(self, 'start'):
+                # we have all informations we need
+                break
+
+            offset += pos
+            if offset + 1000 < len(buffer) and len(buffer) < 1000000 or 1:
+                # looks like a pes, read more
+                buffer += file.read(10000)
+        
+        if not self.video and not self.audio:
+            # no video and no audio? 
+            return 0
+
+        self.type = 'MPEG-PES'
+
+        # fill in values for support functions:
+        self.__seek_size__   = 10000000  # 10 MB
+        self.__sample_size__ = 500000    # 500 k scanning
+        self.__search__      = self._find_timer_PES_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_PES_(self, buffer):
+        """
+        Return position of timer in buffer or -1 if not found.
+        This function is valid for PES files
+        """
+        pos    = buffer.find('\x00\x00\x01')
+        offset = 0
+        if pos == -1 or offset + 1000 >= len(buffer):
+            return -1
+        
+        retpos   = -1
+        ackcount = 0
+        while offset + 1000 < len(buffer):
+            pos, timestamp = self.ReadPESHeader(offset, buffer[offset:])
+            if timestamp != -1 and retpos == -1:
+                retpos = offset + timestamp
+            if pos == 0:
+                # Oops, that was a mpeg header, no PES header
+                offset  += buffer[offset:].find('\x00\x00\x01')
+                retpos   = -1
+                ackcount = 0
+            else:
+                offset   += pos
+                if retpos != -1:
+                    ackcount += 1
+            if ackcount > 10:
+                # looks ok to me
+                return retpos
+        return -1
+            
+
+    # Transport Stream ===============================================
+    
+    def isTS(self, file):
+        file.seek(0,0)
+
+        buffer = file.read(TS_PACKET_LENGTH * 2)
+        c = 0
+
+        while c + TS_PACKET_LENGTH < len(buffer):
+            if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
+                break
+            c += 1
+        else:
+            return 0
+
+        buffer += file.read(10000)
+        self.type = 'MPEG-TS'
+        
+        while c + TS_PACKET_LENGTH < len(buffer):
+            start = ord(buffer[c+1]) & 0x40
+            # maybe load more into the buffer
+            if c + 2 * TS_PACKET_LENGTH > len(buffer) and c < 500000:
+                buffer += file.read(10000)
+
+            # wait until the ts payload contains a payload header
+            if not start:
+                c += TS_PACKET_LENGTH
+                continue
+
+            tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
+            adapt = (ord(buffer[c+3]) & 0x30) >> 4
+
+            offset = 4
+            if adapt & 0x02:
+                # meta info present, skip it for now
+                adapt_len = ord(buffer[c+offset])
+                offset += adapt_len + 1
+
+            if not ord(buffer[c+1]) & 0x40:
+                # no new pes or psi in stream payload starting
+                pass
+            elif adapt & 0x01:
+                # PES
+                timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:], tsid)[1]
+                if timestamp != -1:
+                    if not hasattr(self, 'start'):
+                        self.get_time = self.ReadPTS
+                        timestamp = c + offset + timestamp
+                        self.start = self.get_time(buffer[timestamp:timestamp+5])
+                    elif not hasattr(self, 'audio_ok'):
+                        timestamp = c + offset + timestamp
+                        start = self.get_time(buffer[timestamp:timestamp+5])
+                        if abs(start - self.start) < 10:
+                            # looks ok
+                            self.audio_ok = True
+                        else:
+                            # timestamp broken
+                            del self.start
+                            if mediainfo.DEBUG:
+                                print 'Timestamp error, correcting'
+                            
+            if hasattr(self, 'start') and self.start and \
+                   self.sequence_header_offset and self.video and self.audio:
+                break
+            
+            c += TS_PACKET_LENGTH
+
+                
+        if not self.sequence_header_offset:
+            return 0
+
+        if hasattr(self, 'start') and self.start:
+            self.keys.append('start')
+            
+        # fill in values for support functions:
+        self.__seek_size__   = 10000000  # 10 MB
+        self.__sample_size__ = 100000    # 100 k scanning
+        self.__search__      = self._find_timer_TS_
+        self.filename        = file.name
+
+        # get length of the file
+        self.length = self.get_length()
+        return 1
+
+
+    def _find_timer_TS_(self, buffer):
+        c = 0
+
+        while c + TS_PACKET_LENGTH < len(buffer):
+            if ord(buffer[c]) == ord(buffer[c+TS_PACKET_LENGTH]) == TS_SYNC:
+                break
+            c += 1
+        else:
+            return -1
+        
+        while c + TS_PACKET_LENGTH < len(buffer):
+            start = ord(buffer[c+1]) & 0x40
+            if not start:
+                c += TS_PACKET_LENGTH
+                continue
+
+            tsid = ((ord(buffer[c+1]) & 0x3F) << 8) + ord(buffer[c+2])
+            adapt = (ord(buffer[c+3]) & 0x30) >> 4
+
+            offset = 4
+            if adapt & 0x02:
+                # meta info present, skip it for now
+                offset += ord(buffer[c+offset]) + 1
+
+            if adapt & 0x01:
+                timestamp = self.ReadPESHeader(c+offset, buffer[c+offset:], tsid)[1]
+                return c + offset + timestamp
+            c += TS_PACKET_LENGTH
+        return -1
+
+
+
+    # Support functions ==============================================
+
+    def get_endpos(self):
+        """
+        get the last timestamp of the mpeg, return -1 if this is not possible
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return -1
+
+        file = open(self.filename)
+        file.seek(os.stat(self.filename)[stat.ST_SIZE]-self.__sample_size__)
+        buffer = file.read(self.__sample_size__)
+
+        end = -1
+        while 1:
+            pos = self.__search__(buffer)
+            if pos == -1:
+                break
+            end    = self.get_time(buffer[pos:])
+            buffer = buffer[pos+100:]
+            
+        file.close()
+        return end
+    
+
+    def get_length(self):
+        """
+        get the length in seconds, return -1 if this is not possible
+        """
+        end = self.get_endpos()
+        if end == -1:
+            return -1
+        if self.start > end:
+            return int(((long(1) << 33) - 1 ) / 90000) - self.start + end
+        return end - self.start
+    
+
+    def seek(self, end_time):
+        """
+        Return the byte position in the file where the time position
+        is 'pos' seconds. Return 0 if this is not possible
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return 0
+
+        file    = open(self.filename)
+        seek_to = 0
+        
+        while 1:
+            file.seek(self.__seek_size__, 1)
+            buffer = file.read(self.__sample_size__)
+            if len(buffer) < 10000:
+                break
+            pos = self.__search__(buffer)
+            if pos != -1:
+                # found something
+                if self.get_time(buffer[pos:]) >= end_time:
+                    # too much, break
+                    break
+            # that wasn't enough
+            seek_to = file.tell()
+
+        file.close()
+        return seek_to
+
+
+    def __scan__(self):
+        """
+        scan file for timestamps (may take a long time)
+        """
+        if not hasattr(self, 'filename') or not hasattr(self, 'start'):
+            return 0
+        file = open(self.filename)
+        print 'scanning file...'
+        while 1:
+            file.seek(self.__seek_size__ * 10, 1)
+            buffer = file.read(self.__sample_size__)
+            if len(buffer) < 10000:
+                break
+            pos = self.__search__(buffer)
+            if pos == -1:
+                continue
+            print self.get_time(buffer[pos:])
+
+        file.close()
+        print 'done'
+        print
+
+    
+    
+mmpython.registertype( 'video/mpeg', ('mpeg','mpg','mp4', 'ts'), mediainfo.TYPE_AV, MpegInfo )
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/COPYING
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/COPYING	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/COPYING	(revision 4)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/PKG-INFO
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/PKG-INFO	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/PKG-INFO	(revision 4)
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: mmpython
+Version: 0.4.9
+Summary: Module for retrieving information about media files
+Home-page: http://mmpython.sf.net
+Author: Thomas Schueppel, Dirk Meyer
+Author-email: freevo-devel@lists.sourceforge.net
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/MANIFEST.in
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/MANIFEST.in	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/MANIFEST.in	(revision 4)
@@ -0,0 +1,4 @@
+include audio/*.py  audio/eyeD3/*.py image/*.py video/*.py disc/*.py disc/*.c misc/*.py
+include doc/* 
+recursive-include i18n  *
+include *.py COPYING CREDITS MANIFEST.in mminfo
Index: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/version.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/version.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/version.py	(revision 4)
@@ -0,0 +1,9 @@
+# the intention of this file is to make it possible to check
+# for the program using this lib if it's an up-to-date version
+
+# "offical" version of mmpython
+VERSION = '0.4.9'
+
+# latest major change (date as integer)
+CHANGED = 20040629
+
Index: trunk/src/testing/app/FileViewer/FileServer/fileServer.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/fileServer.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/fileServer.py	(revision 4)
@@ -0,0 +1,829 @@
+#!/usr/bin/env python
+############################################################################
+#
+# -= FileViewer =-
+#
+# FileServer - receives, provides and organizes multimedia files for use with SAGE
+#
+# Copyright (C) 2005 Electronic Visualization Laboratory,
+# University of Illinois at Chicago
+#
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following disclaimer
+#    in the documentation and/or other materials provided with the distribution.
+#  * Neither the name of the University of Illinois at Chicago nor
+#    the names of its contributors may be used to endorse or promote
+#    products derived from this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Direct questions, comments etc about FileViewer to www.evl.uic.edu/cavern/forum
+#
+# Author: Ratko Jagodic
+#
+############################################################################
+ 
+import os, base64, os.path, socket, shutil, sys, SocketServer, wx, stat, urllib
+from SimpleXMLRPCServer import *
+from threading import Thread
+from time import asctime, time
+import makeThumbs
+
+# miscellaneous stuff (3rd party supporting tools)
+sys.path.append("misc")  #so that we can import packages from "misc" folder
+from imsize import imagesize  # reads the image header and gets the size from it
+import mmpython
+import countPDFpages
+
+# a shortcut
+opj = os.path.join
+
+# for loading the sagePath helper file
+sys.path.append( opj(os.environ["SAGE_DIRECTORY"], "bin" ) )
+from sagePath import getUserPath, getPath
+
+
+## some globals defining the environment
+SCRIPT_PATH = sys.path[0]
+CONFIG_FILE = getPath("fileServer", "fileServer.conf")
+CACHE_DIR = getUserPath("fileServer", "file_server_cache")
+FILES_DIR = opj(SCRIPT_PATH, "file_library")
+REDIRECT = False
+THUMB_DIR = opj(FILES_DIR, "thumbnails")
+RUN_SERVER = True
+
+## holds information about the types that we support (read from the config file)
+dirHash = {}
+viewers = {}
+types = {}
+
+
+def ParseConfigFile():
+    global FILES_DIR
+    global THUMB_DIR
+    global dirHash
+    global types
+    global viewers
+
+    # reinitialize everything
+    FILES_DIR = ""
+    THUMB_DIR = ""
+    dirHash = {}
+    types = {}
+    viewers = {}
+
+    # read the config file
+    f = open(CONFIG_FILE, "r")
+    for line in f:
+        line = line.strip()
+        if line.startswith("FILES_DIR"):
+            FILES_DIR = line.split("=")[1].strip()
+            if not os.path.isabs(FILES_DIR):
+                FILES_DIR = getUserPath("fileServer", FILES_DIR)
+            FILES_DIR = os.path.realpath(FILES_DIR)  #expand any symbolic links in the library directory
+            THUMB_DIR = opj(FILES_DIR, "thumbnails")
+        elif line.startswith("type:"):
+            line = line.split(":",1)[1]
+            (type, extensions) = line.split("=")
+            types[type.strip()] = extensions.strip().split(" ")
+            dirHash[type.strip()] = opj(FILES_DIR, type.strip())
+        elif line.startswith("app:"):
+            line = line.split(":", 1)[1].strip()
+            (type, app) = line.split("=")
+            tpl = app.strip().split(" ", 1)
+            if len(tpl) == 1:  params = ""
+            else:  params = tpl[1].strip()
+            app = tpl[0].strip()
+            viewers[type.strip()] = (app, params)
+    f.close()
+
+
+    # create the folders first if they dont exist
+    if not os.path.isdir(FILES_DIR):
+        os.makedirs(FILES_DIR)
+    if not os.path.isdir(CACHE_DIR):
+        os.makedirs(CACHE_DIR)
+    for type, typeDir in dirHash.items():
+        if not os.path.isdir( ConvertPath(typeDir) ):
+            os.makedirs(typeDir)
+        if not os.path.isdir( ConvertPath( opj(typeDir, "Trash")) ):
+            os.makedirs( opj(typeDir, "Trash") )
+    if not os.path.isdir(THUMB_DIR):
+        os.makedirs(THUMB_DIR)
+
+
+
+# convert the path between the systems (Windows vs. Linux/Mac)
+def ConvertPath(path):
+    return apply(opj, tuple(path.split('\\')))
+
+
+
+
+
+import traceback as tb
+from SocketServer import ThreadingTCPServer, StreamRequestHandler
+
+
+
+class Listener(ThreadingTCPServer):
+    """ the main server listening for connections from HWCapture """
+    
+    allow_reuse_address = True
+    request_queue_size = 2
+    
+    def __init__(self, port, onMsgCallback, fileServer):
+        self.onMsgCallback = onMsgCallback
+        self.fileServer = fileServer
+        ThreadingTCPServer.__init__(self, ('', int(port)), SingleFileUpload)
+        self.socket.settimeout(0.5)
+
+
+    def serve_forever(self):
+        while RUN_SERVER:
+            try:
+                self.handle_request()
+            except socket.timeout:
+                pass
+            except KeyboardInterrupt:
+                break
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                break
+ 
+
+class SingleFileUpload(StreamRequestHandler):      
+    """ one of these per file upload """
+
+    
+    def handle(self):
+        """ this is where we parse the incoming messages """
+        self.request.settimeout(0.5)  # so that we can quit properly
+
+        # read the header
+        header = self.rfile.readline().strip()
+        if len(header) == 0:
+            return
+        (fileName, previewWidth, previewHeight, fileSize) = header.strip().split()
+        previewSize = (int(previewWidth), int(previewHeight))
+        fileSize = int(fileSize)
+        
+        # make sure the filename is ok
+        fileName = os.path.basename(fileName)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.server.fileServer.GetFileType(fileName)
+        if not fileType:
+            return #dont allow upload of anything that doesn't have an extension
+        
+        # make the file
+        fullPath = opj(dirHash[fileType], fileName)
+        try:
+            f=open(fullPath, "wb")
+        except:
+            WriteLog("Cannot create file (have write permissions?):" + filePath)
+            return
+
+        bytesRead = 0
+        while RUN_SERVER and bytesRead < fileSize:
+            try:
+                line = self.rfile.readline()
+                if not line:   # readline doesn't fail when socket is closed... it returns an empty string
+                    f.close()
+                    os.remove(fullPath)
+                    break
+                    
+                bytesRead+=len(line)
+                if bytesRead > fileSize:
+                    line = line.rstrip()   # remove the newline char at the end of transmission
+                f.write(line)
+                
+            except socket.timeout:
+                continue
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                f.close()
+                os.remove(fullPath)
+                break
+        else:
+            f.flush()
+            f.close()
+
+            # tell the client that all went well
+            self.wfile.write("1")  
+            
+            # make the preview if necessary and everything went well
+            self.server.onMsgCallback(fileName, previewSize)
+
+
+
+
+
+
+
+
+class FileLibrary:
+    def __init__(self):
+        ParseConfigFile()
+
+        # start the server that will accept the file data
+        self.fServer = Listener(8802, self.__MakePreview, self)
+        fServerThread = Thread(target=self.fServer.serve_forever)
+        fServerThread.start()
+
+
+        ### used by clients to test the connection with the server
+    def TestConnection(self):
+        return (FILES_DIR, 0)
+
+
+         ### gets the file info:
+        ### full path, file type, application info, size (for images...), file size
+    def GetFileInfo(self, filename, fileSize=-1, path=None):
+        try:
+            ParseConfigFile()
+            fileType = self.GetFileType(filename)
+            size = (-1, -1)
+            fileExists = False
+
+            if fileType:  #is file even supported
+                appName = viewers[fileType][0]
+                params = viewers[fileType][1]
+                if path == None:  # the user dropped a new file on there
+                    fullPath = opj(self.__GetFilePath(fileType), filename)  # return a default path if not passed in
+                    res = self.__FileAlreadyThere(filename, fileType, fileSize)
+                    if res:  #if the file was found it will return its directory
+                        if fileType == "image":   #if the file is an image, return its size
+                            try:
+                                imsize = imagesize(fullPath)
+                                size = (imsize[1], imsize[0])
+                            except:
+                                size = (-1,-1)
+
+                        fullPath = opj(res, filename)  #the path of the found file
+                        fileExists = True
+                        
+                elif not self.__LegalPath(path):
+                    return False
+                else:             # the user is trying to show an existing file
+                    path = ConvertPath(path)
+                    fullPath = opj(path, filename)
+                    ## get the image size... FIX later (remove)
+                    if os.path.isfile(fullPath):
+                        fileExists = True
+                        if fileType == "image":   #if the file is an image, return its size
+                            try:
+                                imsize = imagesize(fullPath)
+                                size = (imsize[1], imsize[0])
+                            except:
+                                size = (-1,-1)
+                return (fileType, size, fullPath, appName, params, fileExists) 
+            else:
+                return False  #file type not supported
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### gets the metadata information about the file
+    def GetMetadata(self, fullPath):
+        fullPath = ConvertPath(fullPath)
+        if not self.__LegalPath(fullPath):
+            return False
+
+        try:
+            fileType = self.GetFileType(fullPath)
+            if not fileType:
+                return False
+            elif fileType == "pdf":    # for pdfs
+                return "Pages: "+str(countPDFpages.getPDFPageCount(fullPath))
+            else:                      # for all other types
+                metadata = mmpython.parse(fullPath)
+                if metadata:   # metadata extracted successfully
+                    return unicode(metadata).encode('latin-1', 'replace')
+                else:
+                    return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1]) )
+            return False
+        
+
+        ### construct a hash of all the files keyed by the directory in which the files
+        ### are and return it
+    def GetFiles(self):
+        ParseConfigFile()
+        numDirs = 0
+        numFiles = 0
+        
+        fileHash = {}
+        for fileType in dirHash.iterkeys():
+            fileHash[fileType] = self.__TraverseDir( self.__GetFilePath(fileType), fileType )
+        return fileHash
+    
+
+        ### deletes a folder and all files and dirs in it
+    # FIX to delete the thumbnails for all the images in this folder
+    def DeleteFolder(self, fullPath):
+        try:
+            if self.__LegalPath(fullPath):  # prevent users from deleting anything
+                shutil.rmtree(ConvertPath(fullPath))
+                return True
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### makes a new folder
+    def NewFolder(self, fullPath):
+        try:
+            if self.__LegalPath(fullPath):  # prevent users from deleting anything
+                os.mkdir(ConvertPath(fullPath))
+                self.__SetWritePermissions(ConvertPath(fullPath))
+                return True
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### move the file to Trash
+    def DeleteFile(self, fullPath):
+        try:
+            fullPath = ConvertPath(fullPath)
+            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
+                return False
+            fileType = self.GetFileType(fullPath)
+            if not fileType:  # no extension so don't allow deletion
+                return False
+
+            trashPath = opj( opj(self.__GetFilePath(fileType), "Trash"), os.path.split(fullPath)[1] )
+            self.MoveFile( fullPath, trashPath )
+            return True
+        
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### deletes the file from the library (also deletes it's thumbnail preview if it exists)
+    def DeleteFilePermanently(self, fullPath):
+        try:
+            fullPath = ConvertPath(fullPath)
+            if not self.__LegalPath(fullPath):  # restrict the users to the FILES_DIR folder
+                return False
+            fileType = self.GetFileType(fullPath)
+            if not fileType:  # no extension so don't allow deletion
+                return False
+
+            previewPath = self.__GetPreviewName(fullPath)
+            if os.path.isfile(fullPath): # prevent users from deleting anything 
+                os.remove( fullPath )      #remove the file itself
+                dxtFilePath = fullPath.rstrip(os.path.splitext(fullPath)[1])+".dxt"
+                if os.path.isfile(dxtFilePath):
+                    os.remove( dxtFilePath )  # remove the dxt file if it exists
+            if os.path.isfile( previewPath ):
+                os.remove( previewPath )  #remove its preview thumbnail
+            return True
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### moves the file from one directory to another
+    def MoveFile(self, oldFullPath, newFullPath):
+        oldFullPath = ConvertPath(oldFullPath)
+        newFullPath = ConvertPath(newFullPath)
+        if not self.__LegalPath(oldFullPath, newFullPath):  # restrict the movement to the FILES_DIR
+            return False
+        if os.path.isfile(oldFullPath):
+            try:
+                shutil.move(oldFullPath, newFullPath)
+                oldDxtFilePath = oldFullPath.rstrip(os.path.splitext(oldFullPath)[1])+".dxt"
+                newDxtFilePath = newFullPath.rstrip(os.path.splitext(newFullPath)[1])+".dxt"
+                if os.path.isfile(oldDxtFilePath):
+                    shutil.move(oldDxtFilePath, newDxtFilePath)
+                return True
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                return False
+        else:
+            return False
+
+
+        ### accepts a file encoded as a base64 string and puts it in
+        ### the default directory for that file type
+    def UploadFile(self, name, data, previewSize=(150, 150)):
+        name = os.path.basename(name)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.GetFileType(name)
+        if not fileType:
+            return False  #dont allow upload of anything that doesn't have an extension
+        try:
+            # write the file
+            f=open( opj(dirHash[fileType], name), "wb")
+            f.write( base64.decodestring(data) )
+            f.close()
+            del data
+
+            self.__MakePreview(name, previewSize)
+
+            return True
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+    def UploadLink(self, url):
+        name = os.path.basename(url)   # strip any directory and just keep the filename (for security reasons)
+        fileType = self.GetFileType(name)
+        if not fileType:
+            return False  #dont allow upload of anything that doesn't have an extension
+
+        try:
+            filename, headers = urllib.urlretrieve(url, opj(dirHash[fileType], name))
+            return True
+        except:
+            return False
+        
+
+        ### looks if there is a preview already saved... if not, create one and send it back
+    def GetPreview(self, fullPath, previewSize=(150,150)):
+        try:
+            res = self.MakeThumbnail(fullPath)
+            if res:
+                return (self.__ReadFile(res), True)
+            else:
+                return False
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+        
+##         fullPath = ConvertPath(fullPath)
+##         if not self.__LegalPath(fullPath):
+##             return False
+##         fileType = self.GetFileType(fullPath)
+
+##         try:
+##             if fileType != "image" or not os.path.isfile(fullPath):
+##                 return False
+##             previewPath = self.__GetPreviewName(fullPath)
+##             wxImageType = self.__GetWxBitmapType(os.path.basename(fullPath))
+##             if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it 
+##                 if wxImageType:               # is writing this file type supported?
+##                     im = wx.Image(fullPath)  # read the original image
+##                     if not im.Ok():   
+##                         return False         # the image is probably corrupted
+##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
+##                     im.SaveFile(previewPath, wxImageType)    # save it back to a file
+##                     self.__SetWritePermissions(previewPath)
+##                 else:     #if writing is not supported, try and read it and resize it on the fly
+##                     im = wx.Image(fullPath)  # read the original image
+##                     if not im.Ok():   
+##                         return False         # the image is probably corrupted
+##                     preview = im.Rescale(previewSize[0], previewSize[1])        # resize it
+##                     data = preview.GetData()
+##                     return (base64.encodestring(data), False)   #return the pixels themselves (isBinary=False)
+            
+##             return (self.__ReadFile(previewPath), True)
+##         except:
+##             WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+##             return False
+
+
+    def MakeThumbnail(self, fullPath):
+        fullPath = ConvertPath(fullPath)
+        if not self.__LegalPath(fullPath):
+            return False
+        fileType = self.GetFileType(fullPath)
+        
+        try:
+            if not os.path.isfile(fullPath):
+                return False
+
+            previewPath = self.__GetPreviewName(fullPath)
+            if not os.path.isfile(previewPath):  #if the preview doesnt exist, make it
+                makeThumbs.makeThumbnail(fullPath, fileType, previewPath)
+                if not os.path.isfile(previewPath):
+                    return False
+                
+            return previewPath
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]))
+            return False
+
+
+
+        ### get the file ready for loading by the app on the "host" machine
+    def PrepareFile(self, fullPath, host):
+        if not self.__LegalPath(fullPath):
+            return False
+        
+        # make the connection with the remote FileServer
+        fileServer = xmlrpclib.ServerProxy("http://"+str(host)+":8800")
+
+        try:
+            # if the file exists already, there's no need to transfer it 
+            filePath = fileServer.FileExists(fullPath, os.stat(fullPath).st_size)
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+        if filePath:
+            return filePath  # if the file is already cached, just send the path back
+        else:
+            try:
+                # file is not cached so read it and send it to the remote FileServer
+                fileData = self.__ReadFile(fullPath)
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                return False
+            else:
+                return fileServer.PutFile(os.path.basename(fullPath), fileData)
+ 
+
+        ### gets the extension of the file that was passed in
+    def GetFileType(self, thefile):
+        try:
+            filename = os.path.basename( thefile )
+            extension = os.path.splitext(filename)[1].lower()
+            fileType = False
+            for fType in types.iterkeys():
+                    if extension in types[ fType ]:
+                        fileType = fType
+            return fileType
+        except:
+            return False
+        
+
+        ### does file exist in the cache already?? if not, someone will have to send it here
+    def FileExists(self, fullPath, size):
+        fullPath = ConvertPath(fullPath)
+        if os.path.isfile(fullPath):  # if the file server is on the same machine then we can 
+            return fullPath           # just read the file directly from the file_library
+        filename = "_".join(os.path.basename(fullPath).split())
+        if filename == "":  # if it's a directory
+            return False
+        path = os.path.abspath( opj(CACHE_DIR, filename) )
+        if os.path.isfile(path) and os.stat(path).st_size==size:  #compare the sizes as well
+            return path
+        else:
+            return False
+
+
+        ### called by the remote FileServer to upload the file 
+    def PutFile(self, filename, data):
+        try:
+            filename = "_".join(os.path.basename(filename).split()) # strip the directory and keep just the name (security reasons)
+            if filename == "":
+                return False
+            f=open( opj(CACHE_DIR, filename), "wb")
+            f.write( base64.decodestring(data) )
+            f.close()
+            self.__SetWritePermissions(opj(CACHE_DIR, filename))
+
+            del data
+            return os.path.abspath( opj(CACHE_DIR, filename) )  #return the path of the file to be passed to the app
+        except:
+            del data
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            return False
+
+
+        ### so that the server can be quit remotely
+    def Quit(self, var):
+        global RUN_SERVER
+        RUN_SERVER = False
+        return 1
+
+
+
+        
+
+#=======================================#
+########    Auxiliary methods    ########
+
+
+        ### constructs the preview name from the filename
+        ### preview name is: filename+fileSize+original_extension
+        ### (such as trees56893.jpg where 56893 is file size in bytes)
+    def __GetPreviewName(self, fullPath):
+        fileType = self.GetFileType(fullPath)
+
+        fileSize = os.stat(fullPath).st_size
+        (root, ext) = os.path.splitext( os.path.basename(fullPath) )
+        previewName = root+str(fileSize)+ext        #construct the preview name
+
+        # all the files have .jpg tacked onto the end
+        previewName += ".jpg"
+            
+        return opj( THUMB_DIR, previewName )
+
+
+    def __MakePreview(self, name, previewSize):
+        try:
+            wxImageType = self.__GetWxBitmapType(name)
+            if wxImageType:     # some types just cant be saved by wxPython
+                fileType = self.GetFileType(name)
+                # write the preview but name it with a filename and filesize so that they are unique
+                previewPath = self.__GetPreviewName(opj(dirHash[fileType], name))
+                im = wx.Image(opj(dirHash[fileType], name))  # read the original image
+
+                if im.Ok():  #the image may be corrupted...
+                    im.Rescale(previewSize[0], previewSize[1])        # resize it
+                    im.SaveFile(previewPath, wxImageType)    # save it back to a file
+                self.__SetWritePermissions(previewPath, opj(dirHash[fileType], name))
+        except:
+            WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+            pass    # no preview was saved... oh well
+
+
+
+        ### change the permission of the settings file to allow everyone to write to it
+    def __SetWritePermissions(self, *files):
+        for filePath in files:
+            try:
+                flags = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP | stat.S_IROTH
+                os.chmod(filePath, flags)
+            except:
+                WriteLog( str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2]) )
+                
+        
+        ### reads a file and encodes it in a string (for transfer over the network)
+    def __ReadFile(self, fullPath):
+        f = open(fullPath, "rb")
+        fileData = base64.encodestring( f.read() )
+        f.close()
+        return fileData
+
+
+        ### looks through all the files of the same type 
+        ### and figures out if the files is already there (optionally compare the file sizes as well)
+        ### if the same file is found, it will return its path
+    def __FileAlreadyThere(self, filename, fileType, size):
+        dirPath = self.__GetFilePath(fileType)
+        fileDir = False
+        
+        def LookForFile(dirPath, fileType, fileDir):
+            if fileDir:
+                return fileDir  #this will prevent the recursion to go on if we found a file (base case)
+            dirPath = ConvertPath(dirPath)
+            items = os.listdir(dirPath)
+            files = []
+            dirs = {}
+            for item in items:   #loop through all the items in this directory (files or dirs)
+                if os.path.isfile( opj(dirPath, item) ):  #is it a file
+                    if item.lower() == filename.lower():  #are their filenames equal
+                        if size==-1 or size==os.stat(opj(dirPath, item)).st_size:
+                            fileDir = dirPath
+                            return dirPath
+                elif os.path.isdir( opj(dirPath, item) ):  #is it a directory
+                    LookForFile( opj(dirPath, item), fileType, fileDir)  #if so, search in it
+            return False
+
+        return LookForFile(dirPath, fileType, fileDir)
+
+
+       ### recursively traverses the given directory
+       ### it return a tuple of (dir-path, list-of-dirs, files)
+    def __TraverseDir(self, dirPath, fileType):
+        dirPath = ConvertPath(dirPath)
+        items = os.listdir(dirPath)
+        files = []
+        dirs = {}
+        for item in items:
+            if os.path.isfile( opj(dirPath, item) ):
+                if self.GetFileType(item):  #if the file is supported, add it to the list, otherwise disregard it
+                    files.append(item)
+            elif os.path.isdir( opj(dirPath, item) ):
+                dirs[item] = self.__TraverseDir( opj(dirPath, item), fileType )
+        return (dirPath, dirs, files, fileType)
+
+
+       ### you pass it in a filename and it figures out the wx.BITMAP_TYPE and returns it
+    def __GetWxBitmapType(self, name):
+        ext = os.path.splitext(name)[1]
+        ext = ext.lower()
+        if ext==".jpg": return wx.BITMAP_TYPE_JPEG
+        elif ext==".png": return wx.BITMAP_TYPE_PNG
+        elif ext==".gif": return wx.BITMAP_TYPE_GIF
+        elif ext==".bmp": return wx.BITMAP_TYPE_BMP
+        elif ext==".pcx": return wx.BITMAP_TYPE_PCX
+        elif ext==".pnm": return wx.BITMAP_TYPE_PNM
+        elif ext==".tif": return wx.BITMAP_TYPE_TIF
+        elif ext==".tiff": return wx.BITMAP_TYPE_TIF
+        elif ext==".xpm": return wx.BITMAP_TYPE_XPM
+        elif ext==".ico": return wx.BITMAP_TYPE_ICO
+        elif ext==".cur": return wx.BITMAP_TYPE_CUR
+        else:
+            return False
+
+
+        ### gets the default path for a certain file type
+    def __GetFilePath(self, type=None):
+        if type == None:
+            return FILES_DIR 
+        else:
+            return dirHash[type]
+
+
+
+        ### Checks whether all the paths are still within FILES_DIR (for security issues)
+    def __LegalPath(self, *pathList):
+        try:
+            normedPathList = []
+            normedPathList.append(FILES_DIR)
+            for path in pathList:
+                if path != "":
+                    normedPathList.append( os.path.normpath( os.path.realpath(path) ) )  # normalize all the paths (remove ../ kinda stuff)
+            return (os.path.commonprefix(normedPathList) == FILES_DIR)
+        except:
+            return False   #if anything fails, it's safer to assume that it's an illegal action
+
+
+    def __IsFolder(self, fullPath):
+        return (os.path.splitext(fullPath)[1] == '')
+    
+
+
+
+# to output all the error messages to a file
+def WriteLog(message):
+    try:
+        print message
+    except:
+        pass
+
+
+
+
+
+
+# a mix-in class for adding the threading support to the XMLRPC server
+class ThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
+    allow_reuse_address = True
+
+
+    # so that we can quit the server properly
+class MyServer(ThreadedXMLRPCServer):
+    def serve_forever(self):
+	while RUN_SERVER:
+	    self.handle_request()
+    
+    
+
+
+def main(argv):
+
+    ## global REDIRECT    
+##     if len(argv) > 2:
+##         if "-v" in argv: 
+##             REDIRECT = False
+##         else:
+
+##             # redirect all the output to nothing
+##             class dummyStream:
+##                 ''' dummyStream behaves like a stream but does nothing. '''
+##                 def __init__(self): pass
+##                 def write(self,data): pass
+##                 def read(self,data): pass
+##                 def flush(self): pass
+##                 def close(self): pass
+##             # and now redirect all default streams to this dummyStream:
+##             sys.stdout = dummyStream()
+##             sys.stderr = dummyStream()
+##             sys.stdin = dummyStream()
+##             sys.__stdout__ = dummyStream()
+##             sys.__stderr__ = dummyStream()
+##             sys.__stdin__ = dummyStream()
+
+
+    wx.InitAllImageHandlers()
+
+    # start the XMLRPC server
+    server = MyServer(("", 8800), SimpleXMLRPCRequestHandler, logRequests=False)
+    server.register_instance(FileLibrary())
+    server.serve_forever()
+
+
+
+if __name__ == '__main__':
+    import sys, os
+    main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
+    
Index: trunk/src/testing/app/FileViewer/FileServer/makeThumbs.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/makeThumbs.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/makeThumbs.py	(revision 4)
@@ -0,0 +1,155 @@
+import os, os.path, sys, wx, stat, shutil
+import subprocess as sp
+import traceback as tb
+
+opj = os.path.join
+
+global FILES_DIR, THUMB_DIR
+
+MPLAYER_DIR = "mplayer"  # change if needed
+CONVERT_DIR = "convert"  # imagemagick's convert
+
+wx.InitAllImageHandlers()
+
+
+
+def __GetThumbName(fullPath, fileType):
+    fileSize = os.stat(fullPath).st_size
+    (root, ext) = os.path.splitext( os.path.basename(fullPath) )
+    thumbName = root+str(fileSize)+ext        #construct the thumb name
+
+    # video files have .jpg tacked onto the end
+    thumbName += ".jpg"
+            
+    return opj( THUMB_DIR, thumbName )
+
+
+
+    ### change the permission of the settings file to allow everyone to write to it
+def __SetWritePermissions(*files):
+    for filePath in files:
+        try:
+            flags = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP | stat.S_IROTH
+            os.chmod(filePath, flags)
+        except:
+            print str(sys.exc_info()[0])+" "+str(sys.exc_info()[1])+" "+str(sys.exc_info()[2])
+
+
+
+def makeVideoThumb(fullPath, thumbPath):
+    print "\n", 80*"-", "\ncreating video thumbnail with command: "
+    # must create two frames because of mplayer bug
+    createCmd = MPLAYER_DIR+" -vo jpeg -quiet -frames 2 -ss 5 "+ fullPath
+    print createCmd
+    try:
+        sp.check_call(createCmd.split())
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+    # delete one of them
+    try:
+        os.remove("00000001.jpg")
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) 
+
+    # resize it to 300x300
+    try:
+        im = wx.Image("00000002.jpg")  # read the original image
+        if im.Ok():  #the image may be corrupted...
+            im.Rescale(300, 300)        # resize it
+            im.SaveFile("00000002.jpg", wx.BITMAP_TYPE_JPEG)    # save it back to a file
+    except: 
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+        
+    # rename the right one
+    try:
+        shutil.move("00000002.jpg", thumbPath)
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) 
+    
+
+
+def makePDFThumb(fullPath, thumbPath):
+    print "\n", 80*"-", "\ncreating PDF thumbnail with command: "
+    createCmd = CONVERT_DIR+" -thumbnail 300x300 "+fullPath+"[0] "+thumbPath
+    print createCmd
+    try:
+        sp.check_call(createCmd.split())
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+         
+
+
+def makeImageThumb(fullPath, thumbPath):
+    def __GetWxBitmapType(name):
+        ext = os.path.splitext(name)[1]
+        ext = ext.lower()
+        if ext==".jpg": return wx.BITMAP_TYPE_JPEG
+        elif ext==".png": return wx.BITMAP_TYPE_PNG
+        elif ext==".bmp": return wx.BITMAP_TYPE_BMP
+        elif ext==".gif": return wx.BITMAP_TYPE_GIF
+        elif ext==".pcx": return wx.BITMAP_TYPE_PCX
+        elif ext==".pnm": return wx.BITMAP_TYPE_PNM
+        elif ext==".tif": return wx.BITMAP_TYPE_TIF
+        elif ext==".tiff": return wx.BITMAP_TYPE_TIF
+        elif ext==".xpm": return wx.BITMAP_TYPE_XPM
+        elif ext==".ico": return wx.BITMAP_TYPE_ICO
+        elif ext==".cur": return wx.BITMAP_TYPE_CUR
+        else:
+            return False
+
+    try:
+        wxImageType = __GetWxBitmapType(os.path.basename(fullPath))
+        if wxImageType:     # some types just cant be saved by wxPython
+            # write the thumb but name it with a filename and filesize so that they are unique
+            #thumbPath = __GetThumbName(fullPath, "image")           
+            im = wx.Image(fullPath)  # read the original image
+
+            if im.Ok():  #the image may be corrupted...
+                im.Rescale(300, 300)        # resize it
+                im.SaveFile(thumbPath, wx.BITMAP_TYPE_JPEG)    # save it back to a file
+    except:
+        print "".join(tb.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
+
+
+
+def makeThumbnail(fullPath, fileType, thumbPath):
+    if not os.path.exists(thumbPath):
+        if fileType == "image":
+            makeImageThumb(fullPath, thumbPath)
+        elif fileType == "video":
+            makeVideoThumb(fullPath, thumbPath)
+        elif fileType == "pdf":
+            makePDFThumb(fullPath, thumbPath)
+        else:
+            print "\nERROR:Don't know how to make thumbnail for:", fileType
+
+        if os.path.exists(thumbPath):
+            __SetWritePermissions(thumbPath)
+            
+
+def main():
+    for d in os.listdir(FILES_DIR):
+        if d=="image" or d=="video" or d=="pdf":
+            for root, dirs, files in os.walk(opj(FILES_DIR, d)):
+                for f in files:
+                    fullPath = opj(root, f)
+                    thumbPath = __GetThumbName(fullPath, d)
+                    if not os.path.exists(thumbPath):
+                        makeThumbnail(fullPath, d, thumbPath)
+
+
+if __name__ == '__main__':
+    import sys, os
+    global FILES_DIR, THUMB_DIR
+
+    if len(sys.argv) < 2:
+        print "USAGE: python makeThumbs.py path_to_file_library"
+    else:
+        FILES_DIR = sys.argv[1]
+        if os.path.exists(FILES_DIR):
+            THUMB_DIR = opj(FILES_DIR, "thumbnails")
+            main()
+        else:
+            print "Given directory doesn't exist... exiting"
+    
Index: trunk/src/testing/app/FileViewer/FileServer/KILL_SERVER.py
===================================================================
--- trunk/src/testing/app/FileViewer/FileServer/KILL_SERVER.py	(revision 4)
+++ trunk/src/testing/app/FileViewer/FileServer/KILL_SERVER.py	(revision 4)
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+
+### script that kills the FileServer running at the optionally specified port
+### this is useful when the FileServer was started by someone else
+### but you don't have the permissions to kill it
+
+import xmlrpclib, sys
+port = str(8800)
+if len(sys.argv) > 1: port = sys.argv[1]
+xmlrpclib.ServerProxy("http://localhost:"+port).Quit(1)
Index: trunk/src/testing/app/FileViewer/PDFViewer/Makefile
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/Makefile	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/Makefile	(revision 4)
@@ -0,0 +1,99 @@
+include ../../../config.mk
+SAGE_DIR = ../../..
+
+# use the PDF Poppler library
+#USE_POPPLER=1
+# minimum poppler version 0.5.x
+USE_POPPLER=$(shell pkg-config --atleast-version=0.5 poppler && echo 1)
+
+SDIR=${SAGE_DIR}
+QUANTA_CFLAGS=-I${SDIR}/QUANTA/include
+QUANTA_LDFLAGS=-L${SDIR}/lib -lquanta
+
+
+ifeq ($(USE_POPPLER), 1)
+
+USE_POPPLER12=$(shell pkg-config --atleast-version=0.12 poppler && echo 1)
+
+ifeq ($(USE_POPPLER12), 1)
+CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=12 `pkg-config --cflags poppler` `Wand-config --cflags --cppflags`  -I$(SAGE_DIR)/include -fno-stack-protector $(QUANTA_CFLAGS) $(PORTAUDIO_CFLAGS)
+LIBS= `pkg-config --libs poppler` `Wand-config --ldflags --libs` -L$(SAGE_DIR)/lib -lsail $(QUANTA_LDFLAGS) $(PAUDIO_LIB) -lpthread
+else
+CFLAGS=-DUSE_POPPLER -DSAGE_POPPLER_VERSION=5 `pkg-config --cflags poppler-glib` `Wand-config --cflags --cppflags`  -I$(SAGE_DIR)/include -fno-stack-protector $(QUANTA_CFLAGS) $(PORTAUDIO_CFLAGS)
+LIBS= `pkg-config --libs poppler-glib` `Wand-config --ldflags --libs` -L$(SAGE_DIR)/lib -lsail $(QUANTA_LDFLAGS) $(PAUDIO_LIB) -lpthread
+endif
+
+else
+
+CFLAGS=`Wand-config --cflags --cppflags`  -I$(SAGE_DIR)/include -fno-stack-protector $(QUANTA_CFLAGS) $(PORTAUDIO_CFLAGS)
+LIBS=`Wand-config --ldflags --libs` -L$(SAGE_DIR)/lib -lsail $(QUANTA_LDFLAGS) $(PAUDIO_LIB) -lpthread -lstdc++
+
+endif
+
+
+#----------------  BEGIN FastDXT stuff  ----------------#
+
+OPTIM=1
+
+ifeq ($(MACHINE), Darwin)
+
+CFLAGS+=-m32
+LIBS+=-L/opt/local/lib
+
+CFLAGS+=-I/opt/local/include
+
+ifeq ($(ARCHITECTURE), i386)
+	# Intel Mac
+
+ifeq ($(OPTIM), 1)
+# MacPro
+# CXXFLAGS+=-march=nocona -msse3 -DDXT_INTR
+
+# MacbookPro
+# CFLAGS+=-march=i686 -msse2 -DDXT_INTR
+CFLAGS+=-DDXT_INTR
+endif
+
+endif
+
+ifeq ($(ARCHITECTURE), powerpc)
+	# PowerPC Mac
+echo "Disabling SSE instructions on PowerPC"
+CFLAGS+=
+endif
+endif
+
+ifeq ($(ARCHITECTURE), x86_64)
+CFLAGS+=-msse2 -DDXT_INTR
+
+else
+
+	# everything considered i386/linux
+CFLAGS+=-msse2 -DDXT_INTR
+
+endif
+
+
+
+#------------------  END FastDXT stuff  -------------------#
+
+
+
+default: pdfviewer
+
+install: pdfviewer
+	/bin/cp -f pdfviewer $(SAGE_DIR)/bin
+
+pdfviewer: pdfviewer.o dxt.o libdxt.o util.o intrinsic.o 
+ifeq ($(MACHINE), Darwin)
+	g++ -m32 -o pdfviewer pdfviewer.o dxt.o libdxt.o intrinsic.o $(LIBS)
+else
+	g++ -o pdfviewer pdfviewer.o dxt.o libdxt.o intrinsic.o $(LIBS)
+endif
+
+%.o: %.cpp
+	g++ $(CFLAGS) -c -o $@ $<
+
+clean:
+	/bin/rm -f *.o *~ pdfviewer
+
Index: trunk/src/testing/app/FileViewer/PDFViewer/util.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/util.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/util.cpp	(revision 4)
@@ -0,0 +1,218 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+void aLog(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+}
+
+void aError(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+
+    exit(1);
+}
+
+
+
+void* aAlloc(size_t const n)
+{
+	void* result;
+#if defined(WIN32)
+	result = LocalAlloc(0,n);
+#else
+	result = malloc(n);
+#endif
+	// Filling with zeros
+	memset(result, 0, n);
+
+	if(!result)
+		aError("Aura: not enough memory for %d bytes",n);
+	return result;
+}
+
+void aFree(void* const p)
+{
+#if defined(WIN32)
+	LocalFree(p);
+#else
+	if (p)
+        free(p);
+    else
+        aError("Alloc> Trying to free a NULL pointer\n");
+#endif
+}
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
Index: trunk/src/testing/app/FileViewer/PDFViewer/dxt.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app/FileViewer/PDFViewer/intrinsic.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app/FileViewer/PDFViewer/util.h
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/util.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/util.h	(revision 4)
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
Index: trunk/src/testing/app/FileViewer/PDFViewer/dxt.h
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/dxt.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/dxt.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app/FileViewer/PDFViewer/libdxt.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/libdxt.cpp	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app/FileViewer/PDFViewer/libdxt.h
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/libdxt.h	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app/FileViewer/PDFViewer/pdfviewer.cpp
===================================================================
--- trunk/src/testing/app/FileViewer/PDFViewer/pdfviewer.cpp	(revision 4)
+++ trunk/src/testing/app/FileViewer/PDFViewer/pdfviewer.cpp	(revision 4)
@@ -0,0 +1,781 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <time.h>
+#include <unistd.h>
+
+
+#if defined(USE_POPPLER)
+
+#if SAGE_POPPLER_VERSION == 5
+// Centos 5.5
+#include "glib/poppler.h"
+PopplerDocument *document;
+PopplerBackend backend;
+PopplerPage *page;
+GEnumValue *enum_value;
+GError *error;
+GdkPixbuf *pixbuf;
+#endif
+
+#if SAGE_POPPLER_VERSION == 12
+#include "poppler/goo/GooString.h"
+#include "poppler/GlobalParams.h"
+#include "poppler/PDFDoc.h"
+#include "poppler/UnicodeMap.h"
+#include "poppler/PDFDocEncoding.h"
+#include "poppler/DateInfo.h"
+#include "poppler/splash/SplashBitmap.h"
+#include "poppler/splash/Splash.h"
+#include "poppler/SplashOutputDev.h"
+// Rendering object
+SplashOutputDev *splashOut;
+PDFDoc *doc;
+#endif
+
+int pg_index;
+double x_resolution;
+double pg_w, pg_h;
+
+#else
+#include <wand/magick-wand.h>
+#endif
+
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+// for dxt compression
+#include "libdxt.h"
+
+
+using namespace std;
+
+// if true, it will show the original image and not the dxt compressed one
+#if defined(USE_POPPLER)
+bool useDXT = false;      // cannot yet since poppler returns RGB instead of RGBA
+#else
+bool useDXT = true;
+#endif
+
+
+// other globals...
+byte *sageBuffer = NULL;  // buffers for sage and dxt data
+byte *dxt = NULL;   
+byte *rgba = NULL;
+unsigned int width, height;  // image size
+string fileName;    
+float lastX = 0;
+float lastY = 0;
+float dist = 0;
+int numImages = 0;
+int firstPage = 0;
+
+
+#if ! defined(USE_POPPLER)
+// use ImageMagick to read all other formats
+MagickBooleanType status;  
+MagickWand *wand;
+#endif
+
+// sail object
+sail sageInf; 
+sailConfig scfg;
+
+
+#define ThrowWandException(wand)		\
+  {						\
+    char					\
+      *description;				\
+						\
+    ExceptionType				\
+      severity;					\
+						    \
+    description=MagickGetException(wand,&severity);			\
+    (void) fprintf(stderr,"%s %s %ld %s\n",GetMagickModule(),description); \
+    description=(char *) MagickRelinquishMemory(description);		\
+    exit(-1);								\
+  }
+
+
+// -----------------------------------------------------------------------------
+
+void getRGBA()
+{
+    // get the pixels
+  memset(rgba, 0, width*height*4);
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  poppler_page_render_to_pixbuf (page, 0, 0, width, height, x_resolution/72.0, 0, pixbuf);
+  memcpy(rgba, gdk_pixbuf_get_pixels(pixbuf), width *height * 3);
+#endif
+
+#if SAGE_POPPLER_VERSION == 12
+  SplashBitmap *bitmap = splashOut->getBitmap();
+  memcpy(rgba, bitmap->getDataPtr(), width *height * 3);
+#endif
+#else
+    MagickGetImagePixels(wand, 0, 0, width, height, "RGBA", CharPixel, rgba);
+#endif
+    
+    if (useDXT) {
+	unsigned int numBytes;
+
+	// compress into DXT
+	memset(dxt, 0, width*height*4/8);
+	numBytes = CompressDXT(rgba, dxt, width, height, FORMAT_DXT1, 1);
+    }
+}
+
+void swapBuffer()
+{
+    // get buffer from SAGE and fill it with dxt data
+    sageBuffer = (byte*)sageInf.getBuffer();      
+    if (useDXT)
+	memcpy(sageBuffer, dxt, width*height*4/8);
+    else
+	memcpy(sageBuffer, rgba, width*height*3);
+    sageInf.swapBuffer();
+
+    // get buffer from SAGE and fill it with dxt data
+    sageBuffer = (byte*)sageInf.getBuffer();      
+    if (useDXT)
+	memcpy(sageBuffer, dxt, width*height*4/8);
+    else
+	memcpy(sageBuffer, rgba, width*height*3);
+    sageInf.swapBuffer();
+}
+
+
+void onHomeBtn()
+{
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  pg_index = 0;
+  page = poppler_document_get_page(document, pg_index);
+#endif
+#if SAGE_POPPLER_VERSION == 12
+  pg_index = 1;
+  doc->displayPageSlice(splashOut, pg_index, x_resolution, x_resolution, 0, gTrue, gFalse, gFalse, 0, 0, pg_w, pg_h);
+#endif
+#else
+    MagickSetImageIndex(wand, 0);
+#endif
+    sage::printLog("Page %d of %d", 1, numImages);
+    getRGBA();
+    swapBuffer();
+}
+
+
+void onEndBtn()
+{
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  pg_index = numImages-1;
+  page = poppler_document_get_page(document, pg_index);
+#endif
+#if SAGE_POPPLER_VERSION == 12
+  pg_index = numImages;
+  doc->displayPageSlice(splashOut, pg_index, x_resolution, x_resolution, 0, gTrue, gFalse, gFalse, 0, 0, pg_w, pg_h);
+#endif
+#else
+    MagickSetImageIndex(wand, numImages-1);
+#endif
+    sage::printLog("Page %d of %d", numImages, numImages);
+    getRGBA();
+    swapBuffer();
+}
+
+void onPrevBtn()
+{
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  pg_index = pg_index - 1;
+  if (pg_index < 0) pg_index = 0;
+  page = poppler_document_get_page(document, pg_index);
+    sage::printLog("Page %ld of %d", pg_index+1, numImages);
+#endif
+#if SAGE_POPPLER_VERSION == 12
+  pg_index = pg_index - 1;
+  if (pg_index < 1) pg_index = 1;
+  doc->displayPageSlice(splashOut, pg_index, x_resolution, x_resolution, 0, gTrue, gFalse, gFalse, 0, 0, pg_w, pg_h);
+    sage::printLog("Page %ld of %d", pg_index, numImages);
+#endif
+#else
+    MagickPreviousImage(wand);
+    sage::printLog("Page %ld of %d", MagickGetImageIndex(wand)+1, numImages);
+#endif
+    getRGBA();
+    swapBuffer();
+}
+
+
+void onNextBtn()
+{
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  pg_index = pg_index + 1;
+  if (pg_index >= numImages) pg_index = numImages-1;
+  page = poppler_document_get_page(document, pg_index);
+    sage::printLog("Page %ld of %d", pg_index+1, numImages);
+#endif
+#if SAGE_POPPLER_VERSION == 12
+  pg_index = pg_index + 1;
+  if (pg_index > numImages) pg_index = numImages;
+  doc->displayPageSlice(splashOut, pg_index, x_resolution, x_resolution, 0, gTrue, gFalse, gFalse, 0, 0, pg_w, pg_h);
+    sage::printLog("Page %ld of %d", pg_index, numImages);
+#endif
+#else
+    MagickNextImage(wand);
+    sage::printLog("Page %ld of %d", MagickGetImageIndex(wand)+1, numImages);
+#endif
+    getRGBA();
+    swapBuffer();
+}
+
+
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+static void
+print_index (PopplerIndexIter *iter)
+{
+  do
+    {
+      PopplerAction *action;
+      PopplerIndexIter *child;
+
+      action = poppler_index_iter_get_action (iter);
+      sage::printLog ("Action: %d", action->type);
+      poppler_action_free (action);
+      child = poppler_index_iter_get_child (iter);
+      if (child)
+	print_index (child);
+      poppler_index_iter_free (child);
+    }
+  while (poppler_index_iter_next (iter));
+}
+
+static void
+print_document_info (PopplerDocument *document)
+{
+  gchar *title, *format, *author, *subject, *keywords, *creator, *producer, *linearized;
+  GTime creation_date, mod_date;
+  PopplerPageLayout layout;
+  PopplerPageMode mode;
+  PopplerViewerPreferences view_prefs;
+  PopplerFontInfo *font_info;
+  PopplerFontsIter *fonts_iter;
+  PopplerIndexIter *index_iter;
+  GEnumValue *enum_value;
+
+  g_object_get (document,
+		"title", &title,
+		"format", &format,
+		"author", &author,
+		"subject", &subject,
+		"keywords", &keywords,
+		"creation-date", &creation_date,
+		"mod-date", &mod_date,
+		"creator", &creator,
+		"producer", &producer,	
+		"linearized", &linearized,
+		"page-mode", &mode,
+		"page-layout", &layout,
+		"viewer-preferences", &view_prefs,
+		NULL);
+
+  sage::printLog ("\t---------------------------------------------------------");
+  sage::printLog ("\tDocument Metadata");
+  sage::printLog ("\t---------------------------------------------------------");
+  if (title)  sage::printLog   ("\ttitle:\t\t%s", title);
+  if (format) sage::printLog   ("\tformat:\t\t%s", format);
+  if (author) sage::printLog   ("\tauthor:\t\t%s", author);
+  if (subject) sage::printLog  ("\tsubject:\t%s", subject);
+  if (keywords) sage::printLog ("\tkeywords:\t%s", keywords);
+  if (creator) sage::printLog ("\tcreator:\t%s", creator);
+  if (producer) sage::printLog ("\tproducer:\t%s", producer);
+  if (linearized) sage::printLog ("\tlinearized:\t%s", linearized);
+  
+  enum_value = g_enum_get_value ((GEnumClass *) g_type_class_peek (POPPLER_TYPE_PAGE_MODE), mode);
+  sage::printLog ("\tpage mode:\t%s", enum_value->value_name);
+  enum_value = g_enum_get_value ((GEnumClass *) g_type_class_peek (POPPLER_TYPE_PAGE_LAYOUT), layout);
+  sage::printLog ("\tpage layout:\t%s", enum_value->value_name);
+
+  sage::printLog ("\tcreation date:\t%d", creation_date);
+  sage::printLog ("\tmodified date:\t%d", mod_date);
+
+  sage::printLog ("\tfonts:");
+  font_info = poppler_font_info_new (document);
+  while (poppler_font_info_scan (font_info, 20, &fonts_iter)) {
+    if (fonts_iter) {
+      do {
+        sage::printLog ("\t\t\t%s", poppler_fonts_iter_get_name (fonts_iter));
+      } while (poppler_fonts_iter_next (fonts_iter));
+      poppler_fonts_iter_free (fonts_iter);
+    }
+  }
+  poppler_font_info_free (font_info);
+
+  index_iter = poppler_index_iter_new (document);
+  if (index_iter)
+    {
+      sage::printLog ("\tindex:");
+      print_index (index_iter);
+      poppler_index_iter_free (index_iter);
+    }
+
+  g_free (title);
+  g_free (format);
+  g_free (author);
+  g_free (subject);
+  g_free (keywords);
+  g_free (creator);
+  g_free (producer); 
+  g_free (linearized);
+}
+
+#endif
+#if SAGE_POPPLER_VERSION == 12
+// -----------------------------------------------------------------------------
+static void printInfoString(Dict *infoDict, char *key, char *text,
+                            UnicodeMap *uMap) {
+  Object obj;
+  GooString *s1;
+  GBool isUnicode;
+  Unicode u;
+  char buf[8];
+  int i, n;
+
+  if (infoDict->lookup(key, &obj)->isString()) {
+    fputs(text, stdout);
+    s1 = obj.getString();
+    if ((s1->getChar(0) & 0xff) == 0xfe &&
+        (s1->getChar(1) & 0xff) == 0xff) {
+      isUnicode = gTrue;
+      i = 2;
+    } else {
+      isUnicode = gFalse;
+      i = 0;
+    }
+    while (i < obj.getString()->getLength()) {
+      if (isUnicode) {
+        u = ((s1->getChar(i) & 0xff) << 8) |
+            (s1->getChar(i+1) & 0xff);
+        i += 2;
+      } else {
+        u = pdfDocEncoding[s1->getChar(i) & 0xff];
+        ++i;
+      }
+      n = uMap->mapUnicode(u, buf, sizeof(buf));
+      fwrite(buf, 1, n, stdout);
+    }
+    fputc('\n', stdout);
+  }
+  obj.free();
+}
+
+
+static void printInfoDate(Dict *infoDict, char *key, char *text) {
+  Object obj;
+  char *s;
+  int year, mon, day, hour, min, sec, tz_hour, tz_minute;
+  char tz;
+  struct tm tmStruct;
+  char buf[256];
+
+  if (infoDict->lookup(key, &obj)->isString()) {
+    fputs(text, stdout);
+    s = obj.getString()->getCString();
+    // TODO do something with the timezone info
+    if ( parseDateString( s, &year, &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute ) ) {
+      tmStruct.tm_year = year - 1900;
+      tmStruct.tm_mon = mon - 1;
+      tmStruct.tm_mday = day;
+      tmStruct.tm_hour = hour;
+      tmStruct.tm_min = min;
+      tmStruct.tm_sec = sec;
+      tmStruct.tm_wday = -1;
+      tmStruct.tm_yday = -1;
+      tmStruct.tm_isdst = -1;
+      // compute the tm_wday and tm_yday fields
+      if (mktime(&tmStruct) != (time_t)-1 &&
+          strftime(buf, sizeof(buf), "%c", &tmStruct)) {
+        fputs(buf, stdout);
+      } else {
+        fputs(s, stdout);
+      }
+    } else {
+      fputs(s, stdout);
+    }
+    fputc('\n', stdout);
+  }
+  obj.free();
+}
+#endif
+#endif
+
+
+// -----------------------------------------------------------------------------
+
+
+
+int main(int argc,char **argv)
+{
+    unsigned int window_width=-1, window_height=-1;  // sage window size
+
+    sage::initUtil();
+
+    // parse command line arguments
+    if (argc < 2){
+	sage::printLog("PDF> pdfviewer filename [width] [height] [-show_original] [-page num]");
+	return 0;
+    }
+    for (int argNum=2; argNum<argc; argNum++)
+    {
+	if (strcmp(argv[argNum], "-show_original") == 0) {
+	    useDXT = false;
+	}
+	else if(strcmp(argv[argNum], "-page") == 0) {
+	    int p = atoi(argv[argNum+1]);
+	    if (p != 0)
+		firstPage = p-1;
+	    argNum++;
+	}
+	else if(atoi(argv[argNum]) != 0 && atoi(argv[argNum+1]) != 0) {
+	    window_width = atoi( argv[argNum] );
+	    window_height = atoi( argv[argNum+1] );
+	    argNum++;  // increment because we read two args here
+	}
+    }
+
+
+    fileName = string(argv[1]);
+
+#if defined(USE_POPPLER)
+#if SAGE_POPPLER_VERSION == 5
+  g_type_init();
+  sage::printLog("PDF> Poppler version %s", poppler_get_version());
+  backend = poppler_get_backend ();
+  enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_BACKEND), backend);
+  sage::printLog ("PDF> Backend is %s", enum_value->value_name);
+
+  error = NULL;
+  const string filename = string((const char*)"file://") + string(argv[1]);
+  document = poppler_document_new_from_file (filename.c_str(), NULL, &error);
+  if (document == NULL) {
+    sage::printLog("PDF> error for [%s]: %s", filename.c_str(), error->message);
+    exit(0);
+  }
+  // get the number of pages
+  numImages = poppler_document_get_n_pages(document);
+
+  pg_index = 0; // index starts at 0
+  page = poppler_document_get_page(document, pg_index);
+  if (page == NULL) {
+    sage::printLog("PDF> error for [%s]: %s", filename.c_str());
+    exit(0);
+  }
+
+  // page size
+  double mwidth, mheight;
+  poppler_page_get_size (page, &mwidth, &mheight);
+  sage::printLog ("PDF> page size: %g by %g ", mwidth, mheight);
+
+  x_resolution = 200.0;
+  pg_w = mwidth  * (x_resolution / 72.0);
+  pg_h = mheight * (x_resolution / 72.0);
+
+  if (pg_w > 4096) {
+	pg_w = 4096.0;
+	pg_h = 4096.0 / (mwidth/mheight);
+	x_resolution = pg_w * 72.0 / mwidth;
+  }
+  if (pg_h > 4096) {
+	pg_w = 4096.0 / (mheight/mwidth);
+	pg_h = 4096.0;
+	x_resolution = pg_h * 72.0 / mheight;
+  }
+
+  width  = (unsigned int)pg_w;
+  height = (unsigned int)pg_h;
+  sage::printLog("PDF> Crop @ %d DPI: width %d height %d", int(x_resolution), int(pg_w), int(pg_h));
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+  gdk_pixbuf_fill (pixbuf, 0xffffffff);
+
+  // print some information
+  print_document_info (document); 
+
+#endif
+#if SAGE_POPPLER_VERSION == 12
+  GooString *fileName;
+  GooString *ownerPW, *userPW;
+  Object info;
+  UnicodeMap *uMap;
+
+  // read config file
+  globalParams = new GlobalParams();
+
+  // get mapping to output encoding
+  if (!(uMap = globalParams->getTextEncoding())) {
+    sage::printLog("PDF> Couldn't get text encoding");
+  }
+
+  fileName = new GooString(argv[1]);
+  ownerPW = NULL;
+  userPW = NULL;
+  doc = new PDFDoc(fileName, ownerPW, userPW, NULL);
+  sage::printLog("PDF> file [%s] is OK: %d", argv[1], doc->isOk() );
+  numImages = doc->getNumPages();
+  sage::printLog("PDF> num pages: %d", numImages );
+
+  SplashColor paperColor;
+  paperColor[0] = 255;
+  paperColor[1] = 255;
+  paperColor[2] = 255;
+
+  splashOut = new SplashOutputDev(splashModeRGB8, 3, gFalse, paperColor);
+  splashOut->startDoc(doc->getXRef());
+
+  pg_index = firstPage+1;
+  double mwidth  = doc->getPageMediaWidth(pg_index);
+  double mheight = doc->getPageMediaHeight(pg_index);
+  sage::printLog("PDF> Media width %d height %d", int(mwidth), int(mheight));
+
+  x_resolution = 200.0;
+  pg_w = mwidth  * (x_resolution / 72.0);
+  pg_h = mheight * (x_resolution / 72.0);
+
+  if (pg_w > 4096) {
+	pg_w = 4096.0;
+	pg_h = 4096.0 / (mwidth/mheight);
+	x_resolution = pg_w * 72.0 / mwidth;
+  }
+  if (pg_h > 4096) {
+	pg_w = 4096.0 / (mheight/mwidth);
+	pg_h = 4096.0;
+	x_resolution = pg_h * 72.0 / mheight;
+  }
+
+  width  = pg_w;
+  height = pg_h;
+  sage::printLog("PDF> Crop @ %d DPI: width %d height %d", int(x_resolution), int(pg_w), int(pg_h));
+
+  doc->displayPageSlice(splashOut, 1, x_resolution, x_resolution, 0, gTrue, gFalse, gFalse, 0, 0, pg_w, pg_h);
+
+  // print doc info
+  doc->getDocInfo(&info);
+  if (info.isDict()) {
+    printInfoString(info.getDict(), (char*)"Title",        (char*)"Title:          ", uMap);
+    printInfoString(info.getDict(), (char*)"Subject",      (char*)"Subject:        ", uMap);
+    printInfoString(info.getDict(), (char*)"Keywords",     (char*)"Keywords:       ", uMap);
+    printInfoString(info.getDict(), (char*)"Author",       (char*)"Author:         ", uMap);
+    printInfoString(info.getDict(), (char*)"Creator",      (char*)"Creator:        ", uMap);
+    printInfoString(info.getDict(), (char*)"Producer",     (char*)"Producer:       ", uMap);
+    printInfoDate(info.getDict(),   (char*)"CreationDate", (char*)"CreationDate:   ");
+    printInfoDate(info.getDict(),   (char*)"ModDate",      (char*)"ModDate:        ");
+  }
+  info.free();
+#endif
+#else
+    // read file
+    wand=NewMagickWand();  
+
+    // set the resolution (pixel density)
+    MagickSetResolution(wand, 200,200);
+    
+    status=MagickReadImage(wand, fileName.data());
+    if (status == MagickFalse)
+	ThrowWandException(wand);
+    numImages = MagickGetNumberImages(wand);
+    MagickSetImageIndex(wand, firstPage);
+
+    // get the image size
+    width = MagickGetImageWidth(wand);
+    height = MagickGetImageHeight(wand);
+
+    // -------  TODO: need to keep track of images that have been flipped already...
+
+    // crop the image if necessary to make sure it's a multiple of 4
+    if (useDXT)
+    {
+	if (width%4 != 0 || height%4 != 0)
+	{
+	    fprintf(stderr, "\n**** Image cropped a few pixels to be a multiple of 4 for dxt");
+	    width -= width%4;
+	    height -= height%4;
+	}
+	
+	// flip the image to have the correct orientation for dxt
+	MagickFlipImage(wand);
+    }
+#endif
+
+    // allocate buffers 
+    rgba = (byte*) memalign(16, width*height*4);
+    if (useDXT)
+	dxt = (byte*) memalign(16, width*height*4/8);
+
+    // get the first page
+    getRGBA();
+
+    // if the user didn't specify the window size, use the image size
+    if (window_height == -1 && window_width == -1)
+    {
+	window_width = width;
+	window_height = height;
+    }
+  
+    // initialize SAIL
+
+    // Search for a configuration file
+    char *tmpconf = getenv("SAGE_APP_CONFIG");
+    if (tmpconf) {
+      sage::printLog("PDFViewer> found SAGE_APP_CONFIG variable: [%s]", tmpconf);
+      scfg.init(tmpconf);
+    }
+    else {
+      sage::printLog("PDFViewer> using default pdfviewer.conf");
+      scfg.init((char*)"pdfviewer.conf");
+    }
+
+    scfg.setAppName("pdfviewer");
+
+    scfg.resX = width;
+    scfg.resY = height;
+
+    // if it hasn't been specified by the config file, use the app-determined size
+    if (scfg.winWidth == -1 || scfg.winHeight == -1) {
+	scfg.winWidth = window_width;
+	scfg.winHeight = window_height;
+    }
+    
+    if (useDXT)
+    {
+	scfg.pixFmt = PIXFMT_DXT;
+	scfg.rowOrd = BOTTOM_TO_TOP;
+    }
+    else
+    {
+	scfg.pixFmt = PIXFMT_888;
+	scfg.rowOrd = TOP_TO_BOTTOM;
+    }
+
+    sageInf.init(scfg);
+
+    // finally swap the first buffer
+    swapBuffer();
+
+
+    // Wait the end
+    while (1)
+    {
+	usleep(50000);  // so that we don't keep spinning too frequently (0.5s)
+	sageMessage msg;
+	if (sageInf.checkMsg(msg, false) > 0) {
+	    char *data = (char*) msg.getData();
+
+	    switch (msg.getCode()) {
+	    case APP_QUIT:
+		// release the memory
+		free(dxt);
+		free(rgba);
+#if ! defined(USE_POPPLER)
+		DestroyMagickWand(wand);
+#endif
+
+		sageInf.shutdown();
+		exit(1);
+		break;
+
+	    case EVT_CLICK:
+		// Click event x and y location normalized to size of window
+		float clickX, clickY;
+
+		// Ckick device Id, button Id, and is down flag
+		int clickDeviceId, clickButtonId, clickIsDown, clickEvent;
+
+		// Parse message
+		sscanf(data, 
+		       "%d %f %f %d %d %d", 
+		       &clickDeviceId, &clickX, &clickY, 
+		       &clickButtonId, &clickIsDown, &clickEvent);
+
+		// record the click position so we know how far we moved
+		if (clickIsDown && clickEvent == EVT_PAN) {
+		    lastX = clickX;
+		    lastY = clickY;
+		}
+
+
+		if (clickIsDown) {
+		    bool doSwap = false;
+#if ! defined(USE_POPPLER)
+		    if (clickButtonId==1)
+			doSwap = MagickPreviousImage(wand);
+		    else if(clickButtonId==2)
+			doSwap = MagickNextImage(wand);
+#endif
+			
+		    // if everything went well, swap the new page
+		    if (doSwap) {
+			getRGBA();
+			swapBuffer();
+		    }
+		}
+		
+
+		break;
+
+
+	    case EVT_PAN: 
+
+		// Pan event properties
+		int panDeviceId;
+		bool doSwap = false;
+
+		// Pan event x and y location and change in x, y and z direction
+		// normalized to size of window
+		float startX, startY, panDX, panDY, panDZ;
+		sscanf(data, 
+		       "%d %f %f %f %f %f", 
+		       &panDeviceId, &startX, &startY, &panDX, &panDY, &panDZ);
+		
+		// keep track of distance
+		dist += panDX;
+
+		// we started a new drag
+		if (lastX != startX) {
+		    lastX = startX;
+		    dist = 0;
+		}
+
+		// if we dragged more than a certain distance, change a page
+		else if( fabs(dist) > 0.07 ) {
+#if ! defined(USE_POPPLER)
+		    if (dist > 0)
+			doSwap = MagickPreviousImage(wand);
+		    else
+			doSwap = MagickNextImage(wand);
+#endif
+
+		    // reset the counter
+		    lastX = startX;
+		    dist = 0;
+
+		    if (doSwap) {
+			getRGBA();
+			swapBuffer();
+			//sprintf(l, "Page %ld of %d", MagickGetImageIndex(wand)+1, numImages);
+		    }
+		}
+
+		break;
+	    }   // end switch
+	}  // end if
+    } // end while
+
+    return 0;
+}
+
Index: trunk/src/testing/app/FileViewer/Makefile
===================================================================
--- trunk/src/testing/app/FileViewer/Makefile	(revision 4)
+++ trunk/src/testing/app/FileViewer/Makefile	(revision 4)
@@ -0,0 +1,38 @@
+SHELL=/bin/bash
+SAGE_DIR = ../..
+VIEWER_DIR = ./ImageViewer
+SERVER_DIR = ./FileServer
+PDF_DIR = ./PDFViewer
+
+
+# Macs dont have -u option on cp
+MACHINE=$(shell uname -s)
+ifeq ($(MACHINE), Darwin)
+	CP=/bin/cp -fr
+else
+	CP=/bin/cp -fru
+endif
+
+
+default: imageviewer pdfviewer
+
+install: imageviewer
+	/bin/mkdir -p -m 775 $(SAGE_DIR)/bin/fileServer
+	cd $(VIEWER_DIR); make install; cd -
+	cd $(PDF_DIR); make install; cd -
+	$(CP) $(SERVER_DIR)/*.py $(SERVER_DIR)/misc $(SAGE_DIR)/bin/fileServer
+
+imageviewer:
+	cd $(VIEWER_DIR); make; cd -
+
+pdfviewer:
+	cd $(PDF_DIR); make; cd -
+
+clean:
+	/bin/rm -f *.o *~
+	cd $(VIEWER_DIR); make clean; cd - 
+	cd $(PDF_DIR); make clean; cd - 
+
+
+.PHONY: imageviewer pdfviewer
+
Index: trunk/src/testing/app/FileViewer/README
===================================================================
--- trunk/src/testing/app/FileViewer/README	(revision 4)
+++ trunk/src/testing/app/FileViewer/README	(revision 4)
@@ -0,0 +1,87 @@
+-----------------------------------------------------
+
+            FILE VIEWER FOR SAGE
+
+-----------------------------------------------------
+Author: Ratko Jagodic
+Last Update: April 12, 2008
+
+
+
+
+PREREQUISITES:
+----------------------------------------------------
+
+- python 2.3 or later
+- wxPython 2.6 or later
+- for ImageViewer: ImageMagick development libraries (if not already installed, these can probably 
+						      be found on your linux distribution discs)
+- SAGE must be installed already and the $SAGE_DIRECTORY environment variable set up
+
+
+
+HOW TO INSTALL:
+----------------------------------------------------
+
+- type "make install" from this directory
+- this will:
+	- compile ImageViewer and imgToDxt
+	- copy imageviewer to $SAGE_DIRECTORY/bin, file_server.py, file_server.conf, imgToDxt and dirToDxt.py to $SAGE_DIRECTORY/bin/file_server
+
+- make an entry in the $SAGE_DIRECTORY/appLauncher/sage.conf for ImageViewer, for example (this should work in most cases):
+
+	imageviewer {
+	configName images
+	nodeNum 1
+	Init 100 100 500 500
+	exec 127.0.0.1 imageviewer 127.0.0.1
+	nwProtocol tvTcpModule.so
+	}
+
+
+
+
+HOW TO RUN:
+----------------------------------------------------
+
+- make sure the FileServer is checked in the SageLauncher and click START (it's checked by default)
+
+
+
+HOW TO SHOW FILES:
+----------------------------------------------------
+
+There are three ways to show files:
+(1) drag and drop onto the SAGE UI
+(2) drag and drop onto the SAGE UI's File Library interface (press F2 or Options->File Library)
+(3) from the File Library interface click "Browse" and select a file from your local file system
+
+- by default, the file server will store all the files in the "file_library" directory that's relative to where
+  the file_server.py is located. This can be changed in the file_server.conf
+
+- take a look at file_server.conf for more information on how to add other file viewers to support other 
+  file types. There you can also change file associations and change the default directory where the files are stored 
+- you have to have file viewers registered with the file server (in file_server.conf) in order to view those types of files. 
+  By default images are supported with the ImageViewer that you compiled above. Also, you can download and 
+  install mplayer from the SAGE website to view a wide variety of movies.
+
+- the ImageViewer will work with images up to roughly 10000 x 10000 pixels and for anything much larger than that, use Magicarpet.
+  Actually, there is no theoretical limit on the image size besides the amount of memory but things will get really slow.
+
+
+
+COMPRESSION:
+----------------------------------------------------
+
+- Imageviewer now compresses all images into DXT1 format which is 1/8 of the size of the original RGBA data. This makes
+  the memory usage much smaller and allows for faster manipulation of image windows. Imageviewer by default checks whether
+  a dxt version of the file already exists in the same directory and it loads that instead. If it doesn't exist it converts
+  the input image to DXT, saves it to the current directory and streams it to SAGE. If you would like to show the original file
+  instead of the DXT version, run Imageviewer with "-show_original" flag.
+
+- if you have a file_library already with a bunch of original files in it, you can run dirToDxt.py and it will make DXT files
+  out of all the images in the input directory. Make sure that imgToDxt is compiled and in the same directory as the dirToDxt.py.
+  
+  Run with something like:
+	python dirToDxt.py image_dir
+
Index: trunk/src/testing/app/atlantis-mpi-head/GO
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/GO	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/GO	(revision 4)
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+## fs.conf
+# atlantis-mpi 1200 600
+# syncMaster 10.0.8.113
+# 3
+# 10.0.8.113 0.0000 0.3333 0.0 1.0
+# 10.0.8.114 0.3333 0.6667 0.0 1.0
+# 10.0.8.117 0.6667 1.0000 0.0 1.0
+##
+
+
+/bin/rm -f .local
+touch .local
+echo "10.0.8.113" >> .local
+echo "10.0.8.114" >> .local
+echo "10.0.8.117" >> .local
+
+mpirun -np 3 -nolocal -machinefile .local atlantis-mpi 512 512
+
+/bin/rm -f .local
+
Index: trunk/src/testing/app/atlantis-mpi-head/GO-ATLANTIS-MPI
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/GO-ATLANTIS-MPI	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/GO-ATLANTIS-MPI	(revision 4)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd /home/evl/bijeong/dev/sage/trunk/app/atlantis-mpi
+mpirun -np $1 -nolocal -machinefile .local atlantis-mpi $2 $3 $4 $5 $6
Index: trunk/src/testing/app/atlantis-mpi-head/atlantis.h
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/atlantis.h	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/atlantis.h	(revision 4)
@@ -0,0 +1,69 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#define RAD 57.295
+#define RRAD 0.01745
+
+#define NUM_SHARKS  75
+#define SHARKSIZE 6000
+#define SHARKSPEED 100.0
+
+#define WHALESPEED 250.0
+
+typedef struct _fishRec {
+    float x, y, z, phi, theta, psi, v;
+    float xt, yt, zt;
+    float htail, vtail;
+    float dtheta;
+    int spurt, attack;
+} fishRec;
+
+extern fishRec sharks[NUM_SHARKS];
+extern fishRec momWhale;
+extern fishRec babyWhale;
+extern fishRec dolph;
+
+extern void FishTransform(fishRec *);
+extern void WhalePilot(fishRec *);
+extern void SharkPilot(fishRec *);
+extern void SharkMiss(int);
+extern void DrawWhale(fishRec *);
+extern void DrawShark(fishRec *);
+extern void DrawDolphin(fishRec *);
+
+#ifdef WINDOWS
+#pragma warning(disable:4305 4101)
+#endif
Index: trunk/src/testing/app/atlantis-mpi-head/atlantis-mpi.conf
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/atlantis-mpi.conf	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/atlantis-mpi.conf	(revision 4)
@@ -0,0 +1,13 @@
+masterIP 10.0.8.131
+nwID     1
+msgPort  23020
+syncPort 13020
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+winX 100
+winY 100
+winWidth 4000
+winHeight 4000
+nwProtocol UDP
+asyncUpdate false
Index: trunk/src/testing/app/atlantis-mpi-head/fsManager.conf
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/fsManager.conf	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/fsManager.conf	(revision 4)
@@ -0,0 +1,16 @@
+fsManager   yorda 10.0.8.120 131.193.78.203
+systemPort  30002
+uiPort      30001
+trackPort   30003
+conManager  131.193.78.203 15556
+
+tileConfiguration stdtile-20.conf
+receiverSyncPort  12000
+receiverStreamPort   22000
+receiverBufSize    100
+fullScreen     1
+winTime		500
+
+rcvNwBufSize 16000000
+sendNwBufSize 16000000
+MTU 1450
Index: trunk/src/testing/app/atlantis-mpi-head/.local
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/.local	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/.local	(revision 4)
@@ -0,0 +1,10 @@
+yorda11-10
+yorda12-10
+yorda14-10
+yorda15-10
+yorda16-10
+yorda17-10
+yorda18-10
+yorda19-10
+yorda20-10
+yorda13-10
Index: trunk/src/testing/app/atlantis-mpi-head/shark.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/shark.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/shark.c	(revision 4)
@@ -0,0 +1,1313 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N002[3] = {0.000077 ,-0.020611 ,0.999788};
+static float N003[3] = {0.961425 ,0.258729 ,-0.093390};
+static float N004[3] = {0.510811 ,-0.769633 ,-0.383063};
+static float N005[3] = {0.400123 ,0.855734 ,-0.328055};
+static float N006[3] = {-0.770715 ,0.610204 ,-0.183440};
+static float N007[3] = {-0.915597 ,-0.373345 ,-0.149316};
+static float N008[3] = {-0.972788 ,0.208921 ,-0.100179};
+static float N009[3] = {-0.939713 ,-0.312268 ,-0.139383};
+static float N010[3] = {-0.624138 ,-0.741047 ,-0.247589};
+static float N011[3] = {0.591434 ,-0.768401 ,-0.244471};
+static float N012[3] = {0.935152 ,-0.328495 ,-0.132598};
+static float N013[3] = {0.997102 ,0.074243 ,-0.016593};
+static float N014[3] = {0.969995 ,0.241712 ,-0.026186};
+static float N015[3] = {0.844539 ,0.502628 ,-0.184714};
+static float N016[3] = {-0.906608 ,0.386308 ,-0.169787};
+static float N017[3] = {-0.970016 ,0.241698 ,-0.025516};
+static float N018[3] = {-0.998652 ,0.050493 ,-0.012045};
+static float N019[3] = {-0.942685 ,-0.333051 ,-0.020556};
+static float N020[3] = {-0.660944 ,-0.750276 ,0.015480};
+static float N021[3] = {0.503549 ,-0.862908 ,-0.042749};
+static float N022[3] = {0.953202 ,-0.302092 ,-0.012089};
+static float N023[3] = {0.998738 ,0.023574 ,0.044344};
+static float N024[3] = {0.979297 ,0.193272 ,0.060202};
+static float N025[3] = {0.798300 ,0.464885 ,0.382883};
+static float N026[3] = {-0.756590 ,0.452403 ,0.472126};
+static float N027[3] = {-0.953855 ,0.293003 ,0.065651};
+static float N028[3] = {-0.998033 ,0.040292 ,0.048028};
+static float N029[3] = {-0.977079 ,-0.204288 ,0.059858};
+static float N030[3] = {-0.729117 ,-0.675304 ,0.111140};
+static float N031[3] = {0.598361 ,-0.792753 ,0.116221};
+static float N032[3] = {0.965192 ,-0.252991 ,0.066332};
+static float N033[3] = {0.998201 ,-0.002790 ,0.059892};
+static float N034[3] = {0.978657 ,0.193135 ,0.070207};
+static float N035[3] = {0.718815 ,0.680392 ,0.142733};
+static float N036[3] = {-0.383096 ,0.906212 ,0.178936};
+static float N037[3] = {-0.952831 ,0.292590 ,0.080647};
+static float N038[3] = {-0.997680 ,0.032417 ,0.059861};
+static float N039[3] = {-0.982629 ,-0.169881 ,0.074700};
+static float N040[3] = {-0.695424 ,-0.703466 ,0.146700};
+static float N041[3] = {0.359323 ,-0.915531 ,0.180805};
+static float N042[3] = {0.943356 ,-0.319387 ,0.089842};
+static float N043[3] = {0.998272 ,-0.032435 ,0.048993};
+static float N044[3] = {0.978997 ,0.193205 ,0.065084};
+static float N045[3] = {0.872144 ,0.470094 ,-0.135565};
+static float N046[3] = {-0.664282 ,0.737945 ,-0.119027};
+static float N047[3] = {-0.954508 ,0.288570 ,0.075107};
+static float N048[3] = {-0.998273 ,0.032406 ,0.048993};
+static float N049[3] = {-0.979908 ,-0.193579 ,0.048038};
+static float N050[3] = {-0.858736 ,-0.507202 ,-0.072938};
+static float N051[3] = {0.643545 ,-0.763887 ,-0.048237};
+static float N052[3] = {0.955580 ,-0.288954 ,0.058068};
+static float N058[3] = {0.000050 ,0.793007 ,-0.609213};
+static float N059[3] = {0.913510 ,0.235418 ,-0.331779};
+static float N060[3] = {-0.807970 ,0.495000 ,-0.319625};
+static float N061[3] = {0.000000 ,0.784687 ,-0.619892};
+static float N062[3] = {0.000000 ,-1.000000 ,0.000000};
+static float N063[3] = {0.000000 ,1.000000 ,0.000000};
+static float N064[3] = {0.000000 ,1.000000 ,0.000000};
+static float N065[3] = {0.000000 ,1.000000 ,0.000000};
+static float N066[3] = {-0.055784 ,0.257059 ,0.964784};
+static float N069[3] = {-0.000505 ,-0.929775 ,-0.368127};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float P002[3] = {0.00, -36.59, 5687.72};
+static float P003[3] = {90.00, 114.73, 724.38};
+static float P004[3] = {58.24, -146.84, 262.35};
+static float P005[3] = {27.81, 231.52, 510.43};
+static float P006[3] = {-27.81, 230.43, 509.76};
+static float P007[3] = {-46.09, -146.83, 265.84};
+static float P008[3] = {-90.00, 103.84, 718.53};
+static float P009[3] = {-131.10, -165.92, 834.85};
+static float P010[3] = {-27.81, -285.31, 500.00};
+static float P011[3] = {27.81, -285.32, 500.00};
+static float P012[3] = {147.96, -170.89, 845.50};
+static float P013[3] = {180.00, 0.00, 2000.00};
+static float P014[3] = {145.62, 352.67, 2000.00};
+static float P015[3] = {55.62, 570.63, 2000.00};
+static float P016[3] = {-55.62, 570.64, 2000.00};
+static float P017[3] = {-145.62, 352.68, 2000.00};
+static float P018[3] = {-180.00, 0.01, 2000.00};
+static float P019[3] = {-178.20, -352.66, 2001.61};
+static float P020[3] = {-55.63, -570.63, 2000.00};
+static float P021[3] = {55.62, -570.64, 2000.00};
+static float P022[3] = {179.91, -352.69, 1998.39};
+static float P023[3] = {150.00, 0.00, 3000.00};
+static float P024[3] = {121.35, 293.89, 3000.00};
+static float P025[3] = {46.35, 502.93, 2883.09};
+static float P026[3] = {-46.35, 497.45, 2877.24};
+static float P027[3] = {-121.35, 293.90, 3000.00};
+static float P028[3] = {-150.00, 0.00, 3000.00};
+static float P029[3] = {-152.21, -304.84, 2858.68};
+static float P030[3] = {-46.36, -475.52, 3000.00};
+static float P031[3] = {46.35, -475.53, 3000.00};
+static float P032[3] = {155.64, -304.87, 2863.50};
+static float P033[3] = {90.00, 0.00, 4000.00};
+static float P034[3] = {72.81, 176.33, 4000.00};
+static float P035[3] = {27.81, 285.32, 4000.00};
+static float P036[3] = {-27.81, 285.32, 4000.00};
+static float P037[3] = {-72.81, 176.34, 4000.00};
+static float P038[3] = {-90.00, 0.00, 4000.00};
+static float P039[3] = {-72.81, -176.33, 4000.00};
+static float P040[3] = {-27.81, -285.31, 4000.00};
+static float P041[3] = {27.81, -285.32, 4000.00};
+static float P042[3] = {72.81, -176.34, 4000.00};
+static float P043[3] = {30.00, 0.00, 5000.00};
+static float P044[3] = {24.27, 58.78, 5000.00};
+static float P045[3] = {9.27, 95.11, 5000.00};
+static float P046[3] = {-9.27, 95.11, 5000.00};
+static float P047[3] = {-24.27, 58.78, 5000.00};
+static float P048[3] = {-30.00, 0.00, 5000.00};
+static float P049[3] = {-24.27, -58.78, 5000.00};
+static float P050[3] = {-9.27, -95.10, 5000.00};
+static float P051[3] = {9.27, -95.11, 5000.00};
+static float P052[3] = {24.27, -58.78, 5000.00};
+static float P058[3] = {0.00, 1212.72, 2703.08};
+static float P059[3] = {50.36, 0.00, 108.14};
+static float P060[3] = {-22.18, 0.00, 108.14};
+static float P061[3] = {0.00, 1181.61, 6344.65};
+static float P062[3] = {516.45, -887.08, 2535.45};
+static float P063[3] = {-545.69, -879.31, 2555.63};
+static float P064[3] = {618.89, -1005.64, 2988.32};
+static float P065[3] = {-635.37, -1014.79, 2938.68};
+static float P066[3] = {0.00, 1374.43, 3064.18};
+static float P069[3] = {0.00, -418.25, 5765.04};
+static float P070[3] = {0.00, 1266.91, 6629.60};
+static float P071[3] = {-139.12, -124.96, 997.98};
+static float P072[3] = {-139.24, -110.18, 1020.68};
+static float P073[3] = {-137.33, -94.52, 1022.63};
+static float P074[3] = {-137.03, -79.91, 996.89};
+static float P075[3] = {-135.21, -91.48, 969.14};
+static float P076[3] = {-135.39, -110.87, 968.76};
+static float P077[3] = {150.23, -78.44, 995.53};
+static float P078[3] = {152.79, -92.76, 1018.46};
+static float P079[3] = {154.19, -110.20, 1020.55};
+static float P080[3] = {151.33, -124.15, 993.77};
+static float P081[3] = {150.49, -111.19, 969.86};
+static float P082[3] = {150.79, -92.41, 969.70};
+static float iP002[3] = {0.00, -36.59, 5687.72};
+static float iP004[3] = {58.24, -146.84, 262.35};
+static float iP007[3] = {-46.09, -146.83, 265.84};
+static float iP010[3] = {-27.81, -285.31, 500.00};
+static float iP011[3] = {27.81, -285.32, 500.00};
+static float iP023[3] = {150.00, 0.00, 3000.00};
+static float iP024[3] = {121.35, 293.89, 3000.00};
+static float iP025[3] = {46.35, 502.93, 2883.09};
+static float iP026[3] = {-46.35, 497.45, 2877.24};
+static float iP027[3] = {-121.35, 293.90, 3000.00};
+static float iP028[3] = {-150.00, 0.00, 3000.00};
+static float iP029[3] = {-121.35, -304.84, 2853.86};
+static float iP030[3] = {-46.36, -475.52, 3000.00};
+static float iP031[3] = {46.35, -475.53, 3000.00};
+static float iP032[3] = {121.35, -304.87, 2853.86};
+static float iP033[3] = {90.00, 0.00, 4000.00};
+static float iP034[3] = {72.81, 176.33, 4000.00};
+static float iP035[3] = {27.81, 285.32, 4000.00};
+static float iP036[3] = {-27.81, 285.32, 4000.00};
+static float iP037[3] = {-72.81, 176.34, 4000.00};
+static float iP038[3] = {-90.00, 0.00, 4000.00};
+static float iP039[3] = {-72.81, -176.33, 4000.00};
+static float iP040[3] = {-27.81, -285.31, 4000.00};
+static float iP041[3] = {27.81, -285.32, 4000.00};
+static float iP042[3] = {72.81, -176.34, 4000.00};
+static float iP043[3] = {30.00, 0.00, 5000.00};
+static float iP044[3] = {24.27, 58.78, 5000.00};
+static float iP045[3] = {9.27, 95.11, 5000.00};
+static float iP046[3] = {-9.27, 95.11, 5000.00};
+static float iP047[3] = {-24.27, 58.78, 5000.00};
+static float iP048[3] = {-30.00, 0.00, 5000.00};
+static float iP049[3] = {-24.27, -58.78, 5000.00};
+static float iP050[3] = {-9.27, -95.10, 5000.00};
+static float iP051[3] = {9.27, -95.11, 5000.00};
+static float iP052[3] = {24.27, -58.78, 5000.00};
+static float iP061[3] = {0.00, 1181.61, 6344.65};
+static float iP069[3] = {0.00, -418.25, 5765.04};
+static float iP070[3] = {0.00, 1266.91, 6629.60};
+/* *INDENT-ON* */
+
+void
+Fish001(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P072);
+    glVertex3fv(P073);
+    glVertex3fv(P074);
+    glVertex3fv(P075);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P077);
+    glVertex3fv(P078);
+    glVertex3fv(P079);
+    glVertex3fv(P080);
+    glVertex3fv(P081);
+    glVertex3fv(P082);
+    glEnd();
+}
+
+void
+Fish002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+}
+
+void
+Fish004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+}
+
+void
+Fish005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Fish006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+}
+
+void
+Fish007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+}
+
+void
+Fish008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish009(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P059);
+    glVertex3fv(P012);
+    glVertex3fv(P009);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P012);
+    glVertex3fv(P004);
+    glVertex3fv(P007);
+    glVertex3fv(P009);
+    glEnd();
+}
+
+void
+Fish_1(void)
+{
+    Fish004();
+    Fish005();
+    Fish003();
+    Fish007();
+    Fish006();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_2(void)
+{
+    Fish005();
+    Fish004();
+    Fish003();
+    Fish008();
+    Fish006();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_3(void)
+{
+    Fish005();
+    Fish004();
+    Fish007();
+    Fish003();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_4(void)
+{
+    Fish005();
+    Fish004();
+    Fish008();
+    Fish003();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_5(void)
+{
+    Fish009();
+    Fish006();
+    Fish007();
+    Fish001();
+    Fish002();
+    Fish003();
+    Fish008();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_6(void)
+{
+    Fish009();
+    Fish006();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_7(void)
+{
+    Fish009();
+    Fish001();
+    Fish007();
+    Fish005();
+    Fish002();
+    Fish008();
+    Fish003();
+    Fish004();
+    Fish006();
+}
+
+void
+Fish_8(void)
+{
+    Fish009();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish005();
+    Fish004();
+    Fish006();
+}
+
+void
+DrawShark(fishRec * fish)
+{
+    int n;
+    float seg1, seg2, seg3, seg4, segup;
+    float thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 50.0 * fish->v;
+
+    seg1 = 0.6 * thrash * sin(fish->htail * RRAD);
+    seg2 = 1.8 * thrash * sin((fish->htail + 45.0) * RRAD);
+    seg3 = 3.0 * thrash * sin((fish->htail + 90.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 110.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P004[1] = iP004[1] + chomp;
+    P007[1] = iP007[1] + chomp;
+    P010[1] = iP010[1] + chomp;
+    P011[1] = iP011[1] + chomp;
+
+    P023[0] = iP023[0] + seg1;
+    P024[0] = iP024[0] + seg1;
+    P025[0] = iP025[0] + seg1;
+    P026[0] = iP026[0] + seg1;
+    P027[0] = iP027[0] + seg1;
+    P028[0] = iP028[0] + seg1;
+    P029[0] = iP029[0] + seg1;
+    P030[0] = iP030[0] + seg1;
+    P031[0] = iP031[0] + seg1;
+    P032[0] = iP032[0] + seg1;
+    P033[0] = iP033[0] + seg2;
+    P034[0] = iP034[0] + seg2;
+    P035[0] = iP035[0] + seg2;
+    P036[0] = iP036[0] + seg2;
+    P037[0] = iP037[0] + seg2;
+    P038[0] = iP038[0] + seg2;
+    P039[0] = iP039[0] + seg2;
+    P040[0] = iP040[0] + seg2;
+    P041[0] = iP041[0] + seg2;
+    P042[0] = iP042[0] + seg2;
+    P043[0] = iP043[0] + seg3;
+    P044[0] = iP044[0] + seg3;
+    P045[0] = iP045[0] + seg3;
+    P046[0] = iP046[0] + seg3;
+    P047[0] = iP047[0] + seg3;
+    P048[0] = iP048[0] + seg3;
+    P049[0] = iP049[0] + seg3;
+    P050[0] = iP050[0] + seg3;
+    P051[0] = iP051[0] + seg3;
+    P052[0] = iP052[0] + seg3;
+    P002[0] = iP002[0] + seg4;
+    P061[0] = iP061[0] + seg4;
+    P069[0] = iP069[0] + seg4;
+    P070[0] = iP070[0] + seg4;
+
+    fish->vtail += ((fish->dtheta - fish->vtail) * 0.1);
+
+    if (fish->vtail > 0.5) {
+        fish->vtail = 0.5;
+    } else if (fish->vtail < -0.5) {
+        fish->vtail = -0.5;
+    }
+    segup = thrash * fish->vtail;
+
+    P023[1] = iP023[1] + segup;
+    P024[1] = iP024[1] + segup;
+    P025[1] = iP025[1] + segup;
+    P026[1] = iP026[1] + segup;
+    P027[1] = iP027[1] + segup;
+    P028[1] = iP028[1] + segup;
+    P029[1] = iP029[1] + segup;
+    P030[1] = iP030[1] + segup;
+    P031[1] = iP031[1] + segup;
+    P032[1] = iP032[1] + segup;
+    P033[1] = iP033[1] + segup * 5.0;
+    P034[1] = iP034[1] + segup * 5.0;
+    P035[1] = iP035[1] + segup * 5.0;
+    P036[1] = iP036[1] + segup * 5.0;
+    P037[1] = iP037[1] + segup * 5.0;
+    P038[1] = iP038[1] + segup * 5.0;
+    P039[1] = iP039[1] + segup * 5.0;
+    P040[1] = iP040[1] + segup * 5.0;
+    P041[1] = iP041[1] + segup * 5.0;
+    P042[1] = iP042[1] + segup * 5.0;
+    P043[1] = iP043[1] + segup * 12.0;
+    P044[1] = iP044[1] + segup * 12.0;
+    P045[1] = iP045[1] + segup * 12.0;
+    P046[1] = iP046[1] + segup * 12.0;
+    P047[1] = iP047[1] + segup * 12.0;
+    P048[1] = iP048[1] + segup * 12.0;
+    P049[1] = iP049[1] + segup * 12.0;
+    P050[1] = iP050[1] + segup * 12.0;
+    P051[1] = iP051[1] + segup * 12.0;
+    P052[1] = iP052[1] + segup * 12.0;
+    P002[1] = iP002[1] + segup * 17.0;
+    P061[1] = iP061[1] + segup * 17.0;
+    P069[1] = iP069[1] + segup * 17.0;
+    P070[1] = iP070[1] + segup * 17.0;
+
+    glPushMatrix();
+
+    glTranslatef(0.0, 0.0, -3000.0);
+
+//    glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0][0]);
+    n = 0;
+/*
+    if (mat[0][2] >= 0.0) {
+        n += 1;
+    }
+    if (mat[1][2] >= 0.0) {
+        n += 2;
+    }
+    if (mat[2][2] >= 0.0) {
+        n += 4;
+    }
+*/
+    glScalef(2.0, 1.0, 1.0);
+
+    glEnable(GL_CULL_FACE);
+    switch (n) {
+    case 0:
+        Fish_1();
+        break;
+    case 1:
+        Fish_2();
+        break;
+    case 2:
+        Fish_3();
+        break;
+    case 3:
+        Fish_4();
+        break;
+    case 4:
+        Fish_5();
+        break;
+    case 5:
+        Fish_6();
+        break;
+    case 6:
+        Fish_7();
+        break;
+    case 7:
+        Fish_8();
+        break;
+    }
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi-head/Makefile
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/Makefile	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/Makefile	(revision 4)
@@ -0,0 +1,19 @@
+PROGRAM = atlantis-mpi
+CC=g++ -I/opt/mpich/include -Wno-deprecated
+
+FILES = atlantis.o dolphin.o shark.o swim.o whale.o
+
+LDFLAGS += -lglut -lGLU -lGL -L/usr/X11R6/lib64 -lXmu -lXi -lX11 -lm -ldl -L../../lib -lsail -L/opt/mpich/ch-p4/lib64 -lmpich
+CFLAGS += -O -fomit-frame-pointer -ffast-math -I../../include
+
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(CC) -o $(PROGRAM) $(FILES) $(LDFLAGS)
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/atlantis-mpi-head/dolphin.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/dolphin.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/dolphin.c	(revision 4)
@@ -0,0 +1,1945 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {-0.005937 ,-0.101998 ,-0.994767};
+static float N002[3] = {0.936780 ,-0.200803 ,0.286569};
+static float N003[3] = {-0.233062 ,0.972058 ,0.028007};
+static float N005[3] = {0.898117 ,0.360171 ,0.252315};
+static float N006[3] = {-0.915437 ,0.348456 ,0.201378};
+static float N007[3] = {0.602263 ,-0.777527 ,0.180920};
+static float N008[3] = {-0.906912 ,-0.412015 ,0.088061};
+static float N012[3] = {0.884408 ,-0.429417 ,-0.182821};
+static float N013[3] = {0.921121 ,0.311084 ,-0.234016};
+static float N014[3] = {0.382635 ,0.877882 ,-0.287948};
+static float N015[3] = {-0.380046 ,0.888166 ,-0.258316};
+static float N016[3] = {-0.891515 ,0.392238 ,-0.226607};
+static float N017[3] = {-0.901419 ,-0.382002 ,-0.203763};
+static float N018[3] = {-0.367225 ,-0.911091 ,-0.187243};
+static float N019[3] = {0.339539 ,-0.924846 ,-0.171388};
+static float N020[3] = {0.914706 ,-0.378617 ,-0.141290};
+static float N021[3] = {0.950662 ,0.262713 ,-0.164994};
+static float N022[3] = {0.546359 ,0.801460 ,-0.243218};
+static float N023[3] = {-0.315796 ,0.917068 ,-0.243431};
+static float N024[3] = {-0.825687 ,0.532277 ,-0.186875};
+static float N025[3] = {-0.974763 ,-0.155232 ,-0.160435};
+static float N026[3] = {-0.560596 ,-0.816658 ,-0.137119};
+static float N027[3] = {0.380210 ,-0.910817 ,-0.160786};
+static float N028[3] = {0.923772 ,-0.358322 ,-0.135093};
+static float N029[3] = {0.951202 ,0.275053 ,-0.139859};
+static float N030[3] = {0.686099 ,0.702548 ,-0.188932};
+static float N031[3] = {-0.521865 ,0.826719 ,-0.210220};
+static float N032[3] = {-0.923820 ,0.346739 ,-0.162258};
+static float N033[3] = {-0.902095 ,-0.409995 ,-0.134646};
+static float N034[3] = {-0.509115 ,-0.848498 ,-0.144404};
+static float N035[3] = {0.456469 ,-0.880293 ,-0.129305};
+static float N036[3] = {0.873401 ,-0.475489 ,-0.105266};
+static float N037[3] = {0.970825 ,0.179861 ,-0.158584};
+static float N038[3] = {0.675609 ,0.714187 ,-0.183004};
+static float N039[3] = {-0.523574 ,0.830212 ,-0.191360};
+static float N040[3] = {-0.958895 ,0.230808 ,-0.165071};
+static float N041[3] = {-0.918285 ,-0.376803 ,-0.121542};
+static float N042[3] = {-0.622467 ,-0.774167 ,-0.114888};
+static float N043[3] = {0.404497 ,-0.908807 ,-0.102231};
+static float N044[3] = {0.930538 ,-0.365155 ,-0.027588};
+static float N045[3] = {0.921920 ,0.374157 ,-0.100345};
+static float N046[3] = {0.507346 ,0.860739 ,0.041562};
+static float N047[3] = {-0.394646 ,0.918815 ,-0.005730};
+static float N048[3] = {-0.925411 ,0.373024 ,-0.066837};
+static float N049[3] = {-0.945337 ,-0.322309 ,-0.049551};
+static float N050[3] = {-0.660437 ,-0.750557 ,-0.022072};
+static float N051[3] = {0.488835 ,-0.871950 ,-0.027261};
+static float N052[3] = {0.902599 ,-0.421397 ,0.087969};
+static float N053[3] = {0.938636 ,0.322606 ,0.122020};
+static float N054[3] = {0.484605 ,0.871078 ,0.079878};
+static float N055[3] = {-0.353607 ,0.931559 ,0.084619};
+static float N056[3] = {-0.867759 ,0.478564 ,0.134054};
+static float N057[3] = {-0.951583 ,-0.296030 ,0.082794};
+static float N058[3] = {-0.672355 ,-0.730209 ,0.121384};
+static float N059[3] = {0.528336 ,-0.842452 ,0.105525};
+static float N060[3] = {0.786913 ,-0.564760 ,0.248627};
+static float N062[3] = {0.622098 ,0.765230 ,0.165584};
+static float N063[3] = {-0.631711 ,0.767816 ,0.106773};
+static float N064[3] = {-0.687886 ,0.606351 ,0.398938};
+static float N065[3] = {-0.946327 ,-0.281623 ,0.158598};
+static float N066[3] = {-0.509549 ,-0.860437 ,0.002776};
+static float N067[3] = {0.462594 ,-0.876692 ,0.131977};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N078[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N079[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N080[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N081[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N082[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N083[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N084[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N085[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N086[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N087[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N088[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N089[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N090[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N097[3] = {-0.697296 ,0.702881 ,0.140491};
+static float N098[3] = {0.918864 ,0.340821 ,0.198819};
+static float N099[3] = {-0.932737 ,0.201195 ,0.299202};
+static float N100[3] = {0.029517 ,0.981679 ,0.188244};
+static float N102[3] = {0.813521 ,-0.204936 ,0.544229};
+static float N110[3] = {-0.781480 ,-0.384779 ,0.491155};
+static float N111[3] = {-0.722243 ,0.384927 ,0.574627};
+static float N112[3] = {-0.752278 ,0.502679 ,0.425901};
+static float N113[3] = {0.547257 ,0.367910 ,0.751766};
+static float N114[3] = {0.725949 ,-0.232568 ,0.647233};
+static float N115[3] = {-0.747182 ,-0.660786 ,0.071280};
+static float N116[3] = {0.931519 ,0.200748 ,0.303270};
+static float N117[3] = {-0.828928 ,0.313757 ,0.463071};
+static float N118[3] = {0.902554 ,-0.370967 ,0.218587};
+static float N119[3] = {-0.879257 ,-0.441851 ,0.177973};
+static float N120[3] = {0.642327 ,0.611901 ,0.461512};
+static float N121[3] = {0.964817 ,-0.202322 ,0.167910};
+static float N122[3] = {0.000000 ,1.000000 ,0.000000};
+static float P001[3] = {5.68, -300.95, 1324.70};
+static float P002[3] = {338.69, -219.63, 9677.03};
+static float P003[3] = {12.18, 474.59, 9138.14};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 68.74, 9427.85};
+static float P007[3] = {156.52, -266.72, 10311.68};
+static float P008[3] = {-185.56, -266.51, 10310.47};
+static float P009[3] = {124.39, -261.46, 1942.34};
+static float P010[3] = {-130.05, -261.46, 1946.03};
+static float P011[3] = {141.07, -320.11, 1239.38};
+static float P012[3] = {156.48, -360.12, 2073.41};
+static float P013[3] = {162.00, -175.88, 2064.44};
+static float P014[3] = {88.16, -87.72, 2064.02};
+static float P015[3] = {-65.21, -96.13, 2064.02};
+static float P016[3] = {-156.48, -180.96, 2064.44};
+static float P017[3] = {-162.00, -368.93, 2082.39};
+static float P018[3] = {-88.16, -439.22, 2082.39};
+static float P019[3] = {65.21, -440.32, 2083.39};
+static float P020[3] = {246.87, -356.02, 2576.95};
+static float P021[3] = {253.17, -111.15, 2567.15};
+static float P022[3] = {132.34, 51.41, 2559.84};
+static float P023[3] = {-97.88, 40.44, 2567.15};
+static float P024[3] = {-222.97, -117.49, 2567.15};
+static float P025[3] = {-252.22, -371.53, 2569.92};
+static float P026[3] = {-108.44, -518.19, 2586.75};
+static float P027[3] = {97.88, -524.79, 2586.75};
+static float P028[3] = {370.03, -421.19, 3419.70};
+static float P029[3] = {351.15, -16.98, 3423.17};
+static float P030[3] = {200.66, 248.46, 3430.37};
+static float P031[3] = {-148.42, 235.02, 3417.91};
+static float P032[3] = {-360.21, -30.27, 3416.84};
+static float P033[3] = {-357.90, -414.89, 3407.04};
+static float P034[3] = {-148.88, -631.35, 3409.90};
+static float P035[3] = {156.38, -632.59, 3419.70};
+static float P036[3] = {462.61, -469.21, 4431.51};
+static float P037[3] = {466.60, 102.25, 4434.98};
+static float P038[3] = {243.05, 474.34, 4562.02};
+static float P039[3] = {-191.23, 474.40, 4554.42};
+static float P040[3] = {-476.12, 111.05, 4451.11};
+static float P041[3] = {-473.36, -470.74, 4444.78};
+static float P042[3] = {-266.95, -748.41, 4447.78};
+static float P043[3] = {211.14, -749.91, 4429.73};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 6360.63};
+static float P046[3] = {371.29, 804.51, 6486.26};
+static float P047[3] = {-291.43, 797.22, 6494.28};
+static float P048[3] = {-784.13, 370.75, 6378.01};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float iP001[3] = {5.68, -300.95, 1324.70};
+static float iP009[3] = {124.39, -261.46, 1942.34};
+static float iP010[3] = {-130.05, -261.46, 1946.03};
+static float iP011[3] = {141.07, -320.11, 1239.38};
+static float iP012[3] = {156.48, -360.12, 2073.41};
+static float iP013[3] = {162.00, -175.88, 2064.44};
+static float iP014[3] = {88.16, -87.72, 2064.02};
+static float iP015[3] = {-65.21, -96.13, 2064.02};
+static float iP016[3] = {-156.48, -180.96, 2064.44};
+static float iP017[3] = {-162.00, -368.93, 2082.39};
+static float iP018[3] = {-88.16, -439.22, 2082.39};
+static float iP019[3] = {65.21, -440.32, 2083.39};
+static float iP020[3] = {246.87, -356.02, 2576.95};
+static float iP021[3] = {253.17, -111.15, 2567.15};
+static float iP022[3] = {132.34, 51.41, 2559.84};
+static float iP023[3] = {-97.88, 40.44, 2567.15};
+static float iP024[3] = {-222.97, -117.49, 2567.15};
+static float iP025[3] = {-252.22, -371.53, 2569.92};
+static float iP026[3] = {-108.44, -518.19, 2586.75};
+static float iP027[3] = {97.88, -524.79, 2586.75};
+static float iP028[3] = {370.03, -421.19, 3419.70};
+static float iP029[3] = {351.15, -16.98, 3423.17};
+static float iP030[3] = {200.66, 248.46, 3430.37};
+static float iP031[3] = {-148.42, 235.02, 3417.91};
+static float iP032[3] = {-360.21, -30.27, 3416.84};
+static float iP033[3] = {-357.90, -414.89, 3407.04};
+static float iP034[3] = {-148.88, -631.35, 3409.90};
+static float iP035[3] = {156.38, -632.59, 3419.70};
+static float iP036[3] = {462.61, -469.21, 4431.51};
+static float iP037[3] = {466.60, 102.25, 4434.98};
+static float iP038[3] = {243.05, 474.34, 4562.02};
+static float iP039[3] = {-191.23, 474.40, 4554.42};
+static float iP040[3] = {-476.12, 111.05, 4451.11};
+static float iP041[3] = {-473.36, -470.74, 4444.78};
+static float iP042[3] = {-266.95, -748.41, 4447.78};
+static float iP043[3] = {211.14, -749.91, 4429.73};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 6360.63};
+static float iP046[3] = {371.29, 804.51, 6486.26};
+static float iP047[3] = {-291.43, 797.22, 6494.28};
+static float iP048[3] = {-784.13, 370.75, 6378.01};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -300.15, 7894.03};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {246.22, 558.53, 8460.50};
+static float P055[3] = {-230.41, 559.84, 8473.23};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 338.75, 9450.30};
+static float P063[3] = {-165.71, 341.04, 9462.35};
+static float P064[3] = {-298.11, 110.13, 10180.37};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -491.45, 9348.73};
+static float P068[3] = {-136.29, -319.84, 1228.73};
+static float P069[3] = {1111.17, -314.14, 1314.19};
+static float P070[3] = {-1167.34, -321.61, 1319.45};
+static float P071[3] = {1404.86, -306.66, 1235.45};
+static float P072[3] = {-1409.73, -314.14, 1247.66};
+static float P073[3] = {1254.01, -296.87, 1544.58};
+static float P074[3] = {-1262.09, -291.70, 1504.26};
+static float P075[3] = {965.71, -269.26, 1742.65};
+static float P076[3] = {-900.97, -276.74, 1726.07};
+static float iP068[3] = {-136.29, -319.84, 1228.73};
+static float iP069[3] = {1111.17, -314.14, 1314.19};
+static float iP070[3] = {-1167.34, -321.61, 1319.45};
+static float iP071[3] = {1404.86, -306.66, 1235.45};
+static float iP072[3] = {-1409.73, -314.14, 1247.66};
+static float iP073[3] = {1254.01, -296.87, 1544.58};
+static float iP074[3] = {-1262.09, -291.70, 1504.26};
+static float iP075[3] = {965.71, -269.26, 1742.65};
+static float iP076[3] = {-900.97, -276.74, 1726.07};
+static float P077[3] = {1058.00, -448.81, 8194.66};
+static float P078[3] = {-1016.51, -456.43, 8190.62};
+static float P079[3] = {-1515.96, -676.45, 7754.93};
+static float P080[3] = {1856.75, -830.34, 7296.56};
+static float P081[3] = {1472.16, -497.38, 7399.68};
+static float P082[3] = {-1775.26, -829.51, 7298.46};
+static float P083[3] = {911.09, -252.51, 7510.99};
+static float P084[3] = {-1451.94, -495.62, 7384.30};
+static float P085[3] = {1598.75, -669.26, 7769.90};
+static float P086[3] = {-836.53, -250.08, 7463.25};
+static float P087[3] = {722.87, -158.18, 8006.41};
+static float P088[3] = {-688.86, -162.28, 7993.89};
+static float P089[3] = {-626.92, -185.30, 8364.98};
+static float P090[3] = {647.72, -189.46, 8354.99};
+static float P091[3] = {0.00, 835.01, 5555.62};
+static float P092[3] = {0.00, 1350.18, 5220.86};
+static float P093[3] = {0.00, 1422.94, 5285.27};
+static float P094[3] = {0.00, 1296.75, 5650.19};
+static float P095[3] = {0.00, 795.63, 6493.88};
+static float iP091[3] = {0.00, 835.01, 5555.62};
+static float iP092[3] = {0.00, 1350.18, 5220.86};
+static float iP093[3] = {0.00, 1422.94, 5285.27};
+static float iP094[3] = {0.00, 1296.75, 5650.19};
+static float iP095[3] = {0.00, 795.63, 6493.88};
+static float P097[3] = {-194.91, -357.14, 10313.32};
+static float P098[3] = {135.35, -357.66, 10307.94};
+static float iP097[3] = {-194.91, -357.14, 10313.32};
+static float iP098[3] = {135.35, -357.66, 10307.94};
+static float P099[3] = {-380.53, -221.14, 9677.98};
+static float P100[3] = {0.00, 412.99, 9629.33};
+static float P102[3] = {59.51, -412.55, 10677.58};
+static float iP102[3] = {59.51, -412.55, 10677.58};
+static float P103[3] = {6.50, 484.74, 9009.94};
+static float P105[3] = {-41.86, 476.51, 9078.17};
+static float P108[3] = {49.20, 476.83, 9078.24};
+static float P110[3] = {-187.62, -410.04, 10674.12};
+static float iP110[3] = {-187.62, -410.04, 10674.12};
+static float P111[3] = {-184.25, -318.70, 10723.88};
+static float iP111[3] = {-184.25, -318.70, 10723.88};
+static float P112[3] = {-179.61, -142.81, 10670.26};
+static float P113[3] = {57.43, -147.94, 10675.26};
+static float P114[3] = {54.06, -218.90, 10712.44};
+static float P115[3] = {-186.35, -212.09, 10713.76};
+static float P116[3] = {205.90, -84.61, 10275.97};
+static float P117[3] = {-230.96, -83.26, 10280.09};
+static float iP118[3] = {216.78, -509.17, 10098.94};
+static float iP119[3] = {-313.21, -510.79, 10102.62};
+static float P118[3] = {216.78, -509.17, 10098.94};
+static float P119[3] = {-313.21, -510.79, 10102.62};
+static float P120[3] = {217.95, 96.34, 10161.62};
+static float P121[3] = {71.99, -319.74, 10717.70};
+static float iP121[3] = {71.99, -319.74, 10717.70};
+static float P122[3] = {0.00, 602.74, 5375.84};
+static float iP122[3] = {0.00, 602.74, 5375.84};
+static float P123[3] = {-448.94, -203.14, 9499.60};
+static float P124[3] = {-442.64, -185.20, 9528.07};
+static float P125[3] = {-441.07, -148.05, 9528.07};
+static float P126[3] = {-443.43, -128.84, 9499.60};
+static float P127[3] = {-456.87, -146.78, 9466.67};
+static float P128[3] = {-453.68, -183.93, 9466.67};
+static float P129[3] = {428.43, -124.08, 9503.03};
+static float P130[3] = {419.73, -142.14, 9534.56};
+static float P131[3] = {419.92, -179.96, 9534.56};
+static float P132[3] = {431.20, -199.73, 9505.26};
+static float P133[3] = {442.28, -181.67, 9475.96};
+static float P134[3] = {442.08, -143.84, 9475.96};
+/* *INDENT-ON* */
+
+void
+Dolphin001(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P072);
+    glVertex3fv(P074);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P072);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P074);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P001);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Dolphin002(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P001);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P075);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P009);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P071);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Dolphin003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Dolphin004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Dolphin005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Dolphin006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Dolphin007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Dolphin008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Dolphin009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Dolphin010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Dolphin011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Dolphin012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+}
+
+void
+Dolphin013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P007);
+    glVertex3fv(P008);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P007);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+}
+
+void
+Dolphin014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P098);
+    glVertex3fv(P097);
+    glVertex3fv(P111);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P099);
+    glVertex3fv(P097);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+Dolphin015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Dolphin016(void)
+{
+
+    glDisable(GL_DEPTH_TEST);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P123);
+    glVertex3fv(P124);
+    glVertex3fv(P125);
+    glVertex3fv(P126);
+    glVertex3fv(P127);
+    glVertex3fv(P128);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P129);
+    glVertex3fv(P130);
+    glVertex3fv(P131);
+    glVertex3fv(P132);
+    glVertex3fv(P133);
+    glVertex3fv(P134);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P103);
+    glVertex3fv(P105);
+    glVertex3fv(P108);
+    glEnd();
+    glEnable(GL_DEPTH_TEST);
+}
+
+void
+DrawDolphin(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch, thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (10.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg3 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.0 * thrash * sin((fish->htail + 4.0) * RRAD);
+    seg2 = 3.0 * thrash * sin((fish->htail + 6.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg5 = 4.5 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg6 = 5.0 * thrash * sin((fish->htail + 20.0) * RRAD);
+    seg7 = 6.0 * thrash * sin((fish->htail + 30.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail + 180.0) * RRAD);
+
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    chomp = 100.0;
+
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3;
+    P122[1] = iP122[1] + seg3 * 1.5;
+
+    P097[1] = iP097[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P102[1] = iP102[1] + chomp;
+    P110[1] = iP110[1] + chomp;
+    P111[1] = iP111[1] + chomp;
+    P121[1] = iP121[1] + chomp;
+    P118[1] = iP118[1] + chomp;
+    P119[1] = iP119[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 7000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+/*	glGetFloatv(GL_MODELVIEW_MATRIX, f);
+	printf("Modelview:\n");
+	printf("%f %f %f %f ", f[0], f[1], f[2], f[3]);
+	printf("%f %f %f %f ", f[4], f[5], f[6], f[7]);
+	printf("%f %f %f %f ", f[8], f[9], f[10], f[11]);
+	printf("%f %f %f %f\n", f[12], f[13], f[14], f[15]);
+*/
+    //glEnable(GL_CULL_FACE);
+    Dolphin014();
+    Dolphin010();
+    Dolphin009();
+    Dolphin012();
+    Dolphin013();
+    Dolphin006();
+    Dolphin002();
+    Dolphin001();
+    Dolphin003();
+    Dolphin015();
+    Dolphin004();
+    Dolphin005();
+    Dolphin007();
+    Dolphin008();
+    Dolphin011();
+    Dolphin016();
+    //glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi-head/atlantis.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/atlantis.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/atlantis.c	(revision 4)
@@ -0,0 +1,579 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#include <sys\timeb.h>
+int gettimeofday(struct timeval *tp, void *tzp);
+#else
+#include <sys/time.h>
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include "atlantis.h"
+
+#include <mpi.h>
+int rank   = 0;  // node rank
+int nprocs = 0;  // number of nodes
+int dimX, dimY, Xidx, Yidx;
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+
+#if defined(WIN32)
+int
+gettimeofday(struct timeval *tp, void *tzp)
+{
+	struct _timeb t;
+
+    _ftime(&t);
+    tp->tv_sec = t.time;
+    tp->tv_usec = t.millitm * 1000;
+    return 0;
+}
+#endif
+
+fishRec sharks[NUM_SHARKS];
+fishRec momWhale;
+fishRec babyWhale;
+fishRec dolph;
+
+GLboolean moving;
+int screenshot = 0;
+float t1,t2;
+struct timeval tv_start;
+
+double getTime()
+{
+    struct timeval tv;
+		        
+    gettimeofday(&tv,0);
+    return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+}
+/*
+float abs(float f)
+{
+    if (f >= 0.0f) return f;
+    else return -f;
+}
+*/
+void
+InitFishs(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        sharks[i].x = 15000.0 + rand() % 6000;
+        sharks[i].y = (rand() % 20000) - 10000;
+        sharks[i].z = (rand() % 6000) - 5000;
+        sharks[i].psi = rand() % 360 - 180.0;
+        sharks[i].v = 1.0;
+    }
+
+    dolph.x = 30000.0;
+    dolph.y = 0.0;
+    dolph.z = 6000.0;
+    dolph.psi = 90.0;
+    dolph.theta = 0.0;
+    dolph.v = 3.0;
+
+    momWhale.x = 70000.0;
+    momWhale.y = 0.0;
+    momWhale.z = 0.0;
+    momWhale.psi = 90.0;
+    momWhale.theta = 0.0;
+    momWhale.v = 3.0;
+
+    babyWhale.x = 60000.0;
+    babyWhale.y = -2000.0;
+    babyWhale.z = -2000.0;
+    babyWhale.psi = 90.0;
+    babyWhale.theta = 0.0;
+    babyWhale.v = 3.0;
+}
+
+void
+Init(void)
+{
+    static float ambient[] =
+    {0.1, 0.1, 0.1, 1.0};
+    static float diffuse[] =
+    {1.0, 1.0, 1.0, 1.0};
+    static float position[] =
+    {0.0, 1.0, 0.0, 0.0};
+    static float mat_shininess[] =
+    {90.0};
+    static float mat_specular[] =
+    {0.8, 0.8, 0.8, 1.0};
+    static float mat_diffuse[] =
+    {0.46, 0.66, 0.795, 1.0};
+    static float mat_ambient[] =
+    {0.0, 0.1, 0.2, 1.0};
+    static float lmodel_ambient[] =
+    {0.4, 0.4, 0.4, 1.0};
+    static float lmodel_localviewer[] =
+    {1.0};
+
+    glFrontFace(GL_CW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    InitFishs();
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+}
+
+void
+Reshape(int width, int height)
+{
+    winWidth = width;
+    winHeight = height;	
+
+    glViewport(0, 0, width, height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(4.0, 2.0, 10000.0, 400000.0);
+    glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+}
+
+void
+Animate(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        SharkPilot(&sharks[i]);
+        SharkMiss(i);
+    }
+    WhalePilot(&dolph);
+    dolph.phi++;
+    glutPostRedisplay();
+    WhalePilot(&momWhale);
+    momWhale.phi++;
+    WhalePilot(&babyWhale);
+    babyWhale.phi++;
+}
+
+/* ARGSUSED1 */
+void
+Key(unsigned char key, int x, int y)
+{
+	(void) x;
+	(void) y;
+    switch (key) 
+	{
+	  case 27:           /* Esc will quit */
+        exit(1);
+        MPI_Finalize();
+        break;
+	  case 's':
+		screenshot++;
+		glutPostRedisplay( );
+		break;
+	  case ' ':          /* space will advance frame */
+        if (!moving) {
+            Animate();
+        }
+    }
+}
+
+
+void
+save_frame( void )
+{
+/*	GLint viewport[4];
+	int x, y, width, height;
+	void *pixels;
+	FILE *f;
+
+	glGetIntegerv( GL_VIEWPORT, viewport );
+
+	x = viewport[0];
+	y = viewport[1];
+	width = viewport[2];
+	height = viewport[3];
+
+	printf( "saving %dx%d screenshot\n", width, height );
+
+	pixels = malloc( width * height * 3 );
+	assert( pixels );
+	memset( pixels, 0, width * height * 3 );
+
+	glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+
+	f = fopen( "screenshot.ppm", "wb" );
+	fprintf( f, "P6\n%d %d\n255\n", width, height );
+	for ( y = height - 1; y >= 0; y-- )
+		fwrite( (char *) pixels + y * width * 3, width, 3, f );
+	fclose( f );
+
+	free( pixels );
+
+	printf( "done\n" );*/
+}
+
+void
+print_performance( void )
+{
+/*	static int first = 1;
+	 = 0
+	static int start, num_frames;
+	int current;
+
+	if ( first )
+	{
+		start = glutGet( GLUT_ELAPSED_TIME );
+		num_frames = 0;
+		first = 0;
+	}
+
+	num_frames++;
+	current = glutGet( GLUT_ELAPSED_TIME );
+
+	if ( current - start > 1000 )
+	{
+		double elapsed = 1e-3 * (double) ( current - start );
+		double rate = (double) num_frames / elapsed;
+		printf( "%5.1f fps\n", rate );
+
+		num_frames = 0;
+		start = current;
+	}*/
+}
+
+void
+Display( void )
+{
+    float ambient[] = {0.1, 0.1, 0.1, 1.0};
+    float diffuse[] = {1.0, 1.0, 1.0, 1.0};
+    float position[] = {0.0, 1.0, 0.0, 0.0};
+    float mat_shininess[] = {90.0};
+    float mat_specular[] = {0.8, 0.8, 0.8, 1.0};
+    float mat_diffuse[] = {0.46, 0.66, 0.795, 1.0};
+    float mat_ambient[] = {0.0, 0.1, 0.2, 1.0};
+    float lmodel_ambient[] = {0.4, 0.4, 0.4, 1.0};
+    float lmodel_localviewer[] = {0.0};
+
+    int i;
+
+    glFrontFace(GL_CCW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+
+
+    //gluPerspective(40.0, 2.0, 10000.0, 400000.0);
+
+    GLfloat fov = 40.0;
+    GLfloat aspect = 2.0;
+    GLfloat near = 10000.0;
+    GLfloat far = 400000.0;
+    GLfloat range = near*tan(M_PI * (fov/2) / 180.0);
+
+#if 0
+	// standard view
+    glFrustum(-range*aspect,range*aspect,-range,range,near,far);
+#else
+	// split view
+    GLfloat Xstep = 2.0*range*aspect / (float)dimX;
+	 GLfloat Ystep = 2.0*range / (float)dimY;
+	 
+    glFrustum(-range*aspect + Xidx*Xstep, -range*aspect + (Xidx+1)*Xstep,
+	 		-range + Yidx*Ystep, -range + (Yidx+1)*Ystep, near, far);
+#endif
+
+    glMatrixMode(GL_MODELVIEW);
+
+	glLoadIdentity();
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  	for (i = 0; i < NUM_SHARKS; i++)
+	{
+		glPushMatrix();
+		FishTransform(&sharks[i]);
+		DrawShark(&sharks[i]);
+		glPopMatrix();
+	}
+
+    glPushMatrix();
+    FishTransform(&dolph);
+    DrawDolphin(&dolph);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&momWhale);
+    DrawWhale(&momWhale);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&babyWhale);
+    glScalef(0.45, 0.45, 0.3);
+    DrawWhale(&babyWhale);
+    glPopMatrix();
+    glFinish();
+
+
+	if (winWidth > 0)	{
+		glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);
+	}	
+
+	MPI_Barrier(MPI_COMM_WORLD);
+	sageInf.swapBuffer();
+	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+	glutSwapBuffers( );
+}
+
+void
+Visible(int state)
+{
+    if (state == GLUT_VISIBLE) {
+        if (moving)
+            glutIdleFunc(Animate);
+    } else {
+        if (moving)
+            glutIdleFunc(NULL);
+    }
+}
+
+void
+menuSelect(int value)
+{
+    switch (value)
+    {
+        case 1:
+            moving = GL_TRUE;
+            glutIdleFunc(Animate);
+            break;
+        case 2:
+            moving = GL_FALSE;;
+            glutIdleFunc(NULL);
+            break;
+        case 3:
+            exit(0);
+            break;
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+	// MPI Initialization
+	MPI_Init(&argc, &argv);
+	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+	MPI_Barrier(MPI_COMM_WORLD);
+	
+	int resX = 1024, resY = 1024;
+	if (argc > 2) {
+		resX = atoi(argv[1]);
+		resY = atoi(argv[2]);
+	}	
+
+	dimX = nprocs-1;
+	dimY = 1;
+	
+	if (argc > 4) {
+		dimX = atoi(argv[3]);
+		dimY = atoi(argv[4]);
+	}	
+	
+	char procname[MPI_MAX_PROCESSOR_NAME];
+	int lenproc;
+	MPI_Get_processor_name(procname, &lenproc);
+	fprintf(stderr, "Processor %2d is machine [%s]\n", rank, procname);
+
+	// control master
+	if (rank == 0) {
+		sailConfig scfg;
+		scfg.init("atlantis-mpi.conf");
+		scfg.setAppName("atlantis-mpi");
+		scfg.rank = rank;
+		scfg.nodeNum = nprocs-1;
+		scfg.master = true;
+		scfg.rendering = false;	
+
+		sageInf.init(scfg);
+
+		std::cerr << "sail initialized " << std::endl;
+		
+		MPI_Barrier(MPI_COMM_WORLD);
+
+		std::cerr << "entering message loop" << std::endl;
+		while(1) {
+			sageMessage msg;
+			if (sageInf.checkMsg(msg, false) > 0) {
+				 switch (msg.getCode()) {
+					 case APP_QUIT : {
+			 			//sageInf.shutdown();
+						int err;
+						MPI_Abort(MPI_COMM_WORLD, err);
+						// finalize
+						MPI_Finalize();
+						exit(0);
+						break;
+					}
+				 }	
+			}
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+	}
+	// rendering slaves
+	else {
+		Xidx = (rank-1)%dimX;
+		Yidx = (rank-1)/dimX;
+
+		printf("Index x=%d y=%d\n", Xidx, Yidx);
+
+		sageRect atlantisImageMap;
+		atlantisImageMap.left = ((float)Xidx) / ((float)dimX);
+		atlantisImageMap.right = ((float)Xidx+1.0) / ((float)dimX);
+		atlantisImageMap.bottom = ((float)Yidx) / ((float)dimY);
+		atlantisImageMap.top = ((float)Yidx+1.0) / ((float)dimY);;
+
+		sailConfig scfg;
+		scfg.init("atlantis-mpi.conf");
+		scfg.setAppName("atlantis-mpi");
+		scfg.rank = rank;
+		scfg.resX = resX;
+		scfg.resY = resY;
+		scfg.imageMap = atlantisImageMap;
+		scfg.pixFmt = PIXFMT_888;
+		scfg.rowOrd = BOTTOM_TO_TOP;
+		scfg.nodeNum = nprocs-1;
+		scfg.master = false;	
+		scfg.rendering = true;
+
+		sageInf.init(scfg);
+
+		std::cerr << "sail initialized " << std::endl;
+
+		//glutInitWindowSize(512, 192);
+		gettimeofday(&tv_start,0);
+
+		glutInitWindowSize(resX, resY);
+		glutInitWindowPosition(0,0);
+		glutInit(&argc, argv);
+		glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+		glutCreateWindow("GLUT Atlantis Demo");
+		printf("sharks: %d\n",NUM_SHARKS);
+		Init();
+		glutDisplayFunc(Display);
+		glutReshapeFunc(Reshape);
+		glutKeyboardFunc(Key);
+		moving = GL_TRUE;
+		glutIdleFunc(Animate);
+		glutVisibilityFunc(Visible);
+		glutCreateMenu(menuSelect);
+		glutAddMenuEntry("Start motion", 1);
+		glutAddMenuEntry("Stop motion", 2);
+		glutAddMenuEntry("Quit", 3);
+		glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+		//glutFullScreen();
+
+		t1 = getTime();
+
+		if (rgbBuffer)
+	   	 delete [] rgbBuffer;
+   	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+		MPI_Barrier(MPI_COMM_WORLD);
+		std::cerr << "entering rendering loop" << std::endl;
+
+		glutMainLoop();
+
+		  // finalize
+		MPI_Finalize();
+	}
+	
+	// exit
+	return EXIT_SUCCESS;
+}
Index: trunk/src/testing/app/atlantis-mpi-head/swim.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/swim.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/swim.c	(revision 4)
@@ -0,0 +1,191 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#include <stdlib.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include "atlantis.h"
+
+void
+FishTransform(fishRec * fish)
+{
+	glTranslatef(fish->y, fish->z, -fish->x);
+	glRotatef(-fish->psi, 0.0, 1.0, 0.0);
+    glRotatef(fish->theta, 1.0, 0.0, 0.0);
+    glRotatef(-fish->phi, 0.0, 0.0, 1.0);
+}
+
+void
+WhalePilot(fishRec * fish)
+{
+
+    fish->phi = -20.0;
+    fish->theta = 0.0;
+    fish->psi -= 0.5;
+
+    fish->x += WHALESPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += WHALESPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += WHALESPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkPilot(fishRec * fish)
+{
+    static int sign = 1;
+    float X, Y, Z, tpsi, ttheta, thetal;
+
+    fish->xt = 60000.0;
+    fish->yt = 0.0;
+    fish->zt = 0.0;
+
+    X = fish->xt - fish->x;
+    Y = fish->yt - fish->y;
+    Z = fish->zt - fish->z;
+
+    thetal = fish->theta;
+
+    ttheta = RAD * atan(Z / (sqrt(X * X + Y * Y)));
+
+    if (ttheta > fish->theta + 0.25) {
+        fish->theta += 0.5;
+    } else if (ttheta < fish->theta - 0.25) {
+        fish->theta -= 0.5;
+    }
+    if (fish->theta > 90.0) {
+        fish->theta = 90.0;
+    }
+    if (fish->theta < -90.0) {
+        fish->theta = -90.0;
+    }
+    fish->dtheta = fish->theta - thetal;
+
+    tpsi = RAD * atan2(Y, X);
+
+    fish->attack = 0;
+
+    if (fabs(tpsi - fish->psi) < 10.0) {
+        fish->attack = 1;
+    } else if (fabs(tpsi - fish->psi) < 45.0) {
+        if (fish->psi > tpsi) {
+            fish->psi -= 0.5;
+            if (fish->psi < -180.0) {
+                fish->psi += 360.0;
+            }
+        } else if (fish->psi < tpsi) {
+            fish->psi += 0.5;
+            if (fish->psi > 180.0) {
+                fish->psi -= 360.0;
+            }
+        }
+    } else {
+        if (rand() % 100 > 98) {
+            sign = 1 - sign;
+        }
+        fish->psi += sign;
+        if (fish->psi > 180.0) {
+            fish->psi -= 360.0;
+        }
+        if (fish->psi < -180.0) {
+            fish->psi += 360.0;
+        }
+    }
+
+    if (fish->attack) {
+        if (fish->v < 1.1) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.2;
+        }
+        if (fish->v > 5.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.2;
+        }
+    } else {
+        if (!(rand() % 400) && (!fish->spurt)) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.05;
+        }
+        if (fish->v > 3.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.05;
+        }
+    }
+
+    fish->x += SHARKSPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += SHARKSPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += SHARKSPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkMiss(int i)
+{
+    int j;
+    float avoid, thetal;
+    float X, Y, Z, R;
+
+    for (j = 0; j < NUM_SHARKS; j++) {
+        if (j != i) {
+            X = sharks[j].x - sharks[i].x;
+            Y = sharks[j].y - sharks[i].y;
+            Z = sharks[j].z - sharks[i].z;
+
+            R = sqrt(X * X + Y * Y + Z * Z);
+
+            avoid = 1.0;
+            thetal = sharks[i].theta;
+
+            if (R < SHARKSIZE) {
+                if (Z > 0.0) {
+                    sharks[i].theta -= avoid;
+                } else {
+                    sharks[i].theta += avoid;
+                }
+            }
+            sharks[i].dtheta += (sharks[i].theta - thetal);
+        }
+    }
+}
Index: trunk/src/testing/app/atlantis-mpi-head/whale.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi-head/whale.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi-head/whale.c	(revision 4)
@@ -0,0 +1,1810 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {0.019249 ,0.011340 ,-0.999750};
+static float N002[3] = {-0.132579 ,0.954547 ,0.266952};
+static float N003[3] = {-0.196061 ,0.980392 ,-0.019778};
+static float N004[3] = {0.695461 ,0.604704 ,0.388158};
+static float N005[3] = {0.870600 ,0.425754 ,0.246557};
+static float N006[3] = {-0.881191 ,0.392012 ,0.264251};
+static float N008[3] = {-0.341437 ,0.887477 ,0.309523};
+static float N009[3] = {0.124035 ,-0.992278 ,0.000000};
+static float N010[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N011[3] = {0.588172 ,0.000000 ,0.808736};
+static float N012[3] = {0.929824 ,-0.340623 ,-0.139298};
+static float N013[3] = {0.954183 ,0.267108 ,-0.134865};
+static float N014[3] = {0.495127 ,0.855436 ,-0.151914};
+static float N015[3] = {-0.390199 ,0.906569 ,-0.160867};
+static float N016[3] = {-0.923605 ,0.354581 ,-0.145692};
+static float N017[3] = {-0.955796 ,-0.260667 ,-0.136036};
+static float N018[3] = {-0.501283 ,-0.853462 ,-0.142540};
+static float N019[3] = {0.405300 ,-0.901974 ,-0.148913};
+static float N020[3] = {0.909913 ,-0.392746 ,-0.133451};
+static float N021[3] = {0.936494 ,0.331147 ,-0.115414};
+static float N022[3] = {0.600131 ,0.793724 ,-0.099222};
+static float N023[3] = {-0.231556 ,0.968361 ,-0.093053};
+static float N024[3] = {-0.844369 ,0.525330 ,-0.105211};
+static float N025[3] = {-0.982725 ,-0.136329 ,-0.125164};
+static float N026[3] = {-0.560844 ,-0.822654 ,-0.093241};
+static float N027[3] = {0.263884 ,-0.959981 ,-0.093817};
+static float N028[3] = {0.842057 ,-0.525192 ,-0.122938};
+static float N029[3] = {0.921620 ,0.367565 ,-0.124546};
+static float N030[3] = {0.613927 ,0.784109 ,-0.090918};
+static float N031[3] = {-0.448754 ,0.888261 ,-0.098037};
+static float N032[3] = {-0.891865 ,0.434376 ,-0.126077};
+static float N033[3] = {-0.881447 ,-0.448017 ,-0.149437};
+static float N034[3] = {-0.345647 ,-0.922057 ,-0.174183};
+static float N035[3] = {0.307998 ,-0.941371 ,-0.137688};
+static float N036[3] = {0.806316 ,-0.574647 ,-0.140124};
+static float N037[3] = {0.961346 ,0.233646 ,-0.145681};
+static float N038[3] = {0.488451 ,0.865586 ,-0.110351};
+static float N039[3] = {-0.374290 ,0.921953 ,-0.099553};
+static float N040[3] = {-0.928504 ,0.344533 ,-0.138485};
+static float N041[3] = {-0.918419 ,-0.371792 ,-0.135189};
+static float N042[3] = {-0.520666 ,-0.833704 ,-0.183968};
+static float N043[3] = {0.339204 ,-0.920273 ,-0.195036};
+static float N044[3] = {0.921475 ,-0.387382 ,-0.028636};
+static float N045[3] = {0.842465 ,0.533335 ,-0.076204};
+static float N046[3] = {0.380110 ,0.924939 ,0.002073};
+static float N047[3] = {-0.276128 ,0.961073 ,-0.009579};
+static float N048[3] = {-0.879684 ,0.473001 ,-0.049250};
+static float N049[3] = {-0.947184 ,-0.317614 ,-0.044321};
+static float N050[3] = {-0.642059 ,-0.764933 ,-0.051363};
+static float N051[3] = {0.466794 ,-0.880921 ,-0.077990};
+static float N052[3] = {0.898509 ,-0.432277 ,0.076279};
+static float N053[3] = {0.938985 ,0.328141 ,0.103109};
+static float N054[3] = {0.442420 ,0.895745 ,0.043647};
+static float N055[3] = {-0.255163 ,0.966723 ,0.018407};
+static float N056[3] = {-0.833769 ,0.540650 ,0.111924};
+static float N057[3] = {-0.953653 ,-0.289939 ,0.080507};
+static float N058[3] = {-0.672357 ,-0.730524 ,0.119461};
+static float N059[3] = {0.522249 ,-0.846652 ,0.102157};
+static float N060[3] = {0.885868 ,-0.427631 ,0.179914};
+static float N062[3] = {0.648942 ,0.743116 ,0.163255};
+static float N063[3] = {-0.578967 ,0.807730 ,0.111219};
+static float N065[3] = {-0.909864 ,-0.352202 ,0.219321};
+static float N066[3] = {-0.502541 ,-0.818090 ,0.279610};
+static float N067[3] = {0.322919 ,-0.915358 ,0.240504};
+static float N068[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N069[3] = {0.000000 ,1.000000 ,0.000000};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N072[3] = {0.000000 ,1.000000 ,0.000000};
+static float N073[3] = {0.000000 ,1.000000 ,0.000000};
+static float N074[3] = {0.000000 ,1.000000 ,0.000000};
+static float N075[3] = {0.031220 ,0.999025 ,-0.031220};
+static float N076[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {0.446821 ,0.893642 ,0.041889};
+static float N078[3] = {0.863035 ,-0.100980 ,0.494949};
+static float N079[3] = {0.585597 ,-0.808215 ,0.062174};
+static float N080[3] = {0.000000 ,1.000000 ,0.000000};
+static float N081[3] = {1.000000 ,0.000000 ,0.000000};
+static float N082[3] = {0.000000 ,1.000000 ,0.000000};
+static float N083[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N084[3] = {-0.478893 ,0.837129 ,-0.264343};
+static float N085[3] = {0.000000 ,1.000000 ,0.000000};
+static float N086[3] = {0.763909 ,0.539455 ,-0.354163};
+static float N087[3] = {0.446821 ,0.893642 ,0.041889};
+static float N088[3] = {0.385134 ,-0.908288 ,0.163352};
+static float N089[3] = {-0.605952 ,0.779253 ,-0.159961};
+static float N090[3] = {0.000000 ,1.000000 ,0.000000};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N096[3] = {0.644444 ,-0.621516 ,0.445433};
+static float N097[3] = {-0.760896 ,-0.474416 ,0.442681};
+static float N098[3] = {0.636888 ,-0.464314 ,0.615456};
+static float N099[3] = {-0.710295 ,0.647038 ,0.277168};
+static float N100[3] = {0.009604 ,0.993655 ,0.112063};
+static float iP001[3] = {18.74, 13.19, 3.76};
+static float P001[3] = {18.74, 13.19, 3.76};
+static float P002[3] = {0.00, 390.42, 10292.57};
+static float P003[3] = {55.80, 622.31, 8254.35};
+static float P004[3] = {20.80, 247.66, 10652.13};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 199.04, 9353.01};
+static float P008[3] = {-34.67, 247.64, 10663.71};
+static float iP009[3] = {97.46, 67.63, 593.82};
+static float iP010[3] = {-84.33, 67.63, 588.18};
+static float iP011[3] = {118.69, 8.98, -66.91};
+static float P009[3] = {97.46, 67.63, 593.82};
+static float P010[3] = {-84.33, 67.63, 588.18};
+static float P011[3] = {118.69, 8.98, -66.91};
+static float iP012[3] = {156.48, -31.95, 924.54};
+static float iP013[3] = {162.00, 110.22, 924.54};
+static float iP014[3] = {88.16, 221.65, 924.54};
+static float iP015[3] = {-65.21, 231.16, 924.54};
+static float iP016[3] = {-156.48, 121.97, 924.54};
+static float iP017[3] = {-162.00, -23.93, 924.54};
+static float iP018[3] = {-88.16, -139.10, 924.54};
+static float iP019[3] = {65.21, -148.61, 924.54};
+static float iP020[3] = {246.87, -98.73, 1783.04};
+static float iP021[3] = {253.17, 127.76, 1783.04};
+static float iP022[3] = {132.34, 270.77, 1783.04};
+static float iP023[3] = {-97.88, 285.04, 1783.04};
+static float iP024[3] = {-222.97, 139.80, 1783.04};
+static float iP025[3] = {-225.29, -86.68, 1783.04};
+static float iP026[3] = {-108.44, -224.15, 1783.04};
+static float iP027[3] = {97.88, -221.56, 1783.04};
+static float iP028[3] = {410.55, -200.66, 3213.87};
+static float iP029[3] = {432.19, 148.42, 3213.87};
+static float iP030[3] = {200.66, 410.55, 3213.87};
+static float iP031[3] = {-148.42, 432.19, 3213.87};
+static float iP032[3] = {-407.48, 171.88, 3213.87};
+static float iP033[3] = {-432.19, -148.42, 3213.87};
+static float iP034[3] = {-148.88, -309.74, 3213.87};
+static float iP035[3] = {156.38, -320.17, 3213.87};
+static float iP036[3] = {523.39, -303.81, 4424.57};
+static float iP037[3] = {574.66, 276.84, 4424.57};
+static float iP038[3] = {243.05, 492.50, 4424.57};
+static float iP039[3] = {-191.23, 520.13, 4424.57};
+static float iP040[3] = {-523.39, 304.01, 4424.57};
+static float iP041[3] = {-574.66, -231.83, 4424.57};
+static float iP042[3] = {-266.95, -578.17, 4424.57};
+static float iP043[3] = {211.14, -579.67, 4424.57};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 5943.46};
+static float iP046[3] = {371.29, 614.13, 5943.46};
+static float iP047[3] = {-291.43, 621.86, 5943.46};
+static float iP048[3] = {-784.13, 362.60, 5943.46};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P012[3] = {156.48, -31.95, 924.54};
+static float P013[3] = {162.00, 110.22, 924.54};
+static float P014[3] = {88.16, 221.65, 924.54};
+static float P015[3] = {-65.21, 231.16, 924.54};
+static float P016[3] = {-156.48, 121.97, 924.54};
+static float P017[3] = {-162.00, -23.93, 924.54};
+static float P018[3] = {-88.16, -139.10, 924.54};
+static float P019[3] = {65.21, -148.61, 924.54};
+static float P020[3] = {246.87, -98.73, 1783.04};
+static float P021[3] = {253.17, 127.76, 1783.04};
+static float P022[3] = {132.34, 270.77, 1783.04};
+static float P023[3] = {-97.88, 285.04, 1783.04};
+static float P024[3] = {-222.97, 139.80, 1783.04};
+static float P025[3] = {-225.29, -86.68, 1783.04};
+static float P026[3] = {-108.44, -224.15, 1783.04};
+static float P027[3] = {97.88, -221.56, 1783.04};
+static float P028[3] = {410.55, -200.66, 3213.87};
+static float P029[3] = {432.19, 148.42, 3213.87};
+static float P030[3] = {200.66, 410.55, 3213.87};
+static float P031[3] = {-148.42, 432.19, 3213.87};
+static float P032[3] = {-407.48, 171.88, 3213.87};
+static float P033[3] = {-432.19, -148.42, 3213.87};
+static float P034[3] = {-148.88, -309.74, 3213.87};
+static float P035[3] = {156.38, -320.17, 3213.87};
+static float P036[3] = {523.39, -303.81, 4424.57};
+static float P037[3] = {574.66, 276.84, 4424.57};
+static float P038[3] = {243.05, 492.50, 4424.57};
+static float P039[3] = {-191.23, 520.13, 4424.57};
+static float P040[3] = {-523.39, 304.01, 4424.57};
+static float P041[3] = {-574.66, -231.83, 4424.57};
+static float P042[3] = {-266.95, -578.17, 4424.57};
+static float P043[3] = {211.14, -579.67, 4424.57};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 5943.46};
+static float P046[3] = {371.29, 614.13, 5943.46};
+static float P047[3] = {-291.43, 621.86, 5943.46};
+static float P048[3] = {-784.13, 362.60, 5943.46};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -332.24, 7902.59};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {321.55, 558.53, 7902.59};
+static float P055[3] = {-260.54, 559.84, 7902.59};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 438.98, 9364.77};
+static float P063[3] = {-165.71, 441.27, 9355.44};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -504.03, 9355.44};
+static float iP068[3] = {-112.44, 9.25, -64.42};
+static float iP069[3] = {1155.63, 0.00, -182.46};
+static float iP070[3] = {-1143.13, 0.00, -181.54};
+static float iP071[3] = {1424.23, 0.00, -322.09};
+static float iP072[3] = {-1368.01, 0.00, -310.38};
+static float iP073[3] = {1255.57, 2.31, 114.05};
+static float iP074[3] = {-1149.38, 0.00, 117.12};
+static float iP075[3] = {718.36, 0.00, 433.36};
+static float iP076[3] = {-655.90, 0.00, 433.36};
+static float P068[3] = {-112.44, 9.25, -64.42};
+static float P069[3] = {1155.63, 0.00, -182.46};
+static float P070[3] = {-1143.13, 0.00, -181.54};
+static float P071[3] = {1424.23, 0.00, -322.09};
+static float P072[3] = {-1368.01, 0.00, -310.38};
+static float P073[3] = {1255.57, 2.31, 114.05};
+static float P074[3] = {-1149.38, 0.00, 117.12};
+static float P075[3] = {718.36, 0.00, 433.36};
+static float P076[3] = {-655.90, 0.00, 433.36};
+static float P077[3] = {1058.00, -2.66, 7923.51};
+static float P078[3] = {-1016.51, -15.47, 7902.87};
+static float P079[3] = {-1363.99, -484.50, 7593.38};
+static float P080[3] = {1478.09, -861.47, 7098.12};
+static float P081[3] = {1338.06, -284.68, 7024.15};
+static float P082[3] = {-1545.51, -860.64, 7106.60};
+static float P083[3] = {1063.19, -70.46, 7466.60};
+static float P084[3] = {-1369.18, -288.11, 7015.34};
+static float P085[3] = {1348.44, -482.50, 7591.41};
+static float P086[3] = {-1015.45, -96.80, 7474.86};
+static float P087[3] = {731.04, 148.38, 7682.58};
+static float P088[3] = {-697.03, 151.82, 7668.81};
+static float P089[3] = {-686.82, 157.09, 7922.29};
+static float P090[3] = {724.73, 147.75, 7931.39};
+static float iP091[3] = {0.00, 327.10, 2346.55};
+static float iP092[3] = {0.00, 552.28, 2311.31};
+static float iP093[3] = {0.00, 721.16, 2166.41};
+static float iP094[3] = {0.00, 693.42, 2388.80};
+static float iP095[3] = {0.00, 389.44, 2859.97};
+static float P091[3] = {0.00, 327.10, 2346.55};
+static float P092[3] = {0.00, 552.28, 2311.31};
+static float P093[3] = {0.00, 721.16, 2166.41};
+static float P094[3] = {0.00, 693.42, 2388.80};
+static float P095[3] = {0.00, 389.44, 2859.97};
+static float iP096[3] = {222.02, -183.67, 10266.89};
+static float iP097[3] = {-128.90, -182.70, 10266.89};
+static float iP098[3] = {41.04, 88.31, 10659.36};
+static float iP099[3] = {-48.73, 88.30, 10659.36};
+static float P096[3] = {222.02, -183.67, 10266.89};
+static float P097[3] = {-128.90, -182.70, 10266.89};
+static float P098[3] = {41.04, 88.31, 10659.36};
+static float P099[3] = {-48.73, 88.30, 10659.36};
+static float P100[3] = {0.00, 603.42, 9340.68};
+static float P104[3] = {-9.86, 567.62, 7858.65};
+static float P105[3] = {31.96, 565.27, 7908.46};
+static float P106[3] = {22.75, 568.13, 7782.83};
+static float P107[3] = {58.93, 568.42, 7775.94};
+static float P108[3] = {55.91, 565.59, 7905.86};
+static float P109[3] = {99.21, 566.00, 7858.65};
+static float P110[3] = {-498.83, 148.14, 9135.10};
+static float P111[3] = {-495.46, 133.24, 9158.48};
+static float P112[3] = {-490.82, 146.23, 9182.76};
+static float P113[3] = {-489.55, 174.11, 9183.66};
+static float P114[3] = {-492.92, 189.00, 9160.28};
+static float P115[3] = {-497.56, 176.02, 9136.00};
+static float P116[3] = {526.54, 169.68, 9137.70};
+static float P117[3] = {523.49, 184.85, 9161.42};
+static float P118[3] = {518.56, 171.78, 9186.06};
+static float P119[3] = {516.68, 143.53, 9186.98};
+static float P120[3] = {519.73, 128.36, 9163.26};
+static float P121[3] = {524.66, 141.43, 9138.62};
+/* *INDENT-ON* */
+
+void
+Whale001(void)
+{
+
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Whale002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Whale003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Whale004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Whale005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Whale006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Whale007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Whale008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Whale009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Whale010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Whale011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Whale012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+}
+
+void
+Whale013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P005);
+    glVertex3fv(P006);
+    glVertex3fv(P099);
+    glVertex3fv(P098);
+    glEnd();
+}
+
+void
+Whale014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P006);
+    glVertex3fv(P005);
+    glVertex3fv(P004);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+}
+
+void
+Whale015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+}
+
+void
+Whale016(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P104);
+    glVertex3fv(P105);
+    glVertex3fv(P106);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P107);
+    glVertex3fv(P108);
+    glVertex3fv(P109);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P110);
+    glVertex3fv(P111);
+    glVertex3fv(P112);
+    glVertex3fv(P113);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P116);
+    glVertex3fv(P117);
+    glVertex3fv(P118);
+    glVertex3fv(P119);
+    glVertex3fv(P120);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+DrawWhale(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch=0.0, thrash, chomp;
+
+
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.5 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.5 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg2 = 3.7 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg3 = 4.8 * thrash * sin((fish->htail + 23.0) * RRAD);
+    seg4 = 6.0 * thrash * sin((fish->htail + 28.0) * RRAD);
+    seg5 = 6.5 * thrash * sin((fish->htail + 35.0) * RRAD);
+    seg6 = 6.5 * thrash * sin((fish->htail + 40.0) * RRAD);
+    seg7 = 6.5 * thrash * sin((fish->htail + 55.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail - 160.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3 * 1.1;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3 * 0.9;
+
+    P099[1] = iP099[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P097[1] = iP097[1] + chomp;
+    P096[1] = iP096[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 8000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+    glScalef(3.0, 3.0, 3.0);
+
+    glEnable(GL_CULL_FACE);
+
+    Whale001();
+    Whale002();
+    Whale003();
+    Whale004();
+    Whale005();
+    Whale006();
+    Whale007();
+    Whale008();
+    Whale009();
+    Whale010();
+    Whale011();
+    Whale012();
+
+
+
+    Whale013();
+
+    Whale014();
+
+    Whale015();
+
+    Whale016();
+
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi/shark.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi/shark.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/shark.c	(revision 4)
@@ -0,0 +1,1313 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N002[3] = {0.000077 ,-0.020611 ,0.999788};
+static float N003[3] = {0.961425 ,0.258729 ,-0.093390};
+static float N004[3] = {0.510811 ,-0.769633 ,-0.383063};
+static float N005[3] = {0.400123 ,0.855734 ,-0.328055};
+static float N006[3] = {-0.770715 ,0.610204 ,-0.183440};
+static float N007[3] = {-0.915597 ,-0.373345 ,-0.149316};
+static float N008[3] = {-0.972788 ,0.208921 ,-0.100179};
+static float N009[3] = {-0.939713 ,-0.312268 ,-0.139383};
+static float N010[3] = {-0.624138 ,-0.741047 ,-0.247589};
+static float N011[3] = {0.591434 ,-0.768401 ,-0.244471};
+static float N012[3] = {0.935152 ,-0.328495 ,-0.132598};
+static float N013[3] = {0.997102 ,0.074243 ,-0.016593};
+static float N014[3] = {0.969995 ,0.241712 ,-0.026186};
+static float N015[3] = {0.844539 ,0.502628 ,-0.184714};
+static float N016[3] = {-0.906608 ,0.386308 ,-0.169787};
+static float N017[3] = {-0.970016 ,0.241698 ,-0.025516};
+static float N018[3] = {-0.998652 ,0.050493 ,-0.012045};
+static float N019[3] = {-0.942685 ,-0.333051 ,-0.020556};
+static float N020[3] = {-0.660944 ,-0.750276 ,0.015480};
+static float N021[3] = {0.503549 ,-0.862908 ,-0.042749};
+static float N022[3] = {0.953202 ,-0.302092 ,-0.012089};
+static float N023[3] = {0.998738 ,0.023574 ,0.044344};
+static float N024[3] = {0.979297 ,0.193272 ,0.060202};
+static float N025[3] = {0.798300 ,0.464885 ,0.382883};
+static float N026[3] = {-0.756590 ,0.452403 ,0.472126};
+static float N027[3] = {-0.953855 ,0.293003 ,0.065651};
+static float N028[3] = {-0.998033 ,0.040292 ,0.048028};
+static float N029[3] = {-0.977079 ,-0.204288 ,0.059858};
+static float N030[3] = {-0.729117 ,-0.675304 ,0.111140};
+static float N031[3] = {0.598361 ,-0.792753 ,0.116221};
+static float N032[3] = {0.965192 ,-0.252991 ,0.066332};
+static float N033[3] = {0.998201 ,-0.002790 ,0.059892};
+static float N034[3] = {0.978657 ,0.193135 ,0.070207};
+static float N035[3] = {0.718815 ,0.680392 ,0.142733};
+static float N036[3] = {-0.383096 ,0.906212 ,0.178936};
+static float N037[3] = {-0.952831 ,0.292590 ,0.080647};
+static float N038[3] = {-0.997680 ,0.032417 ,0.059861};
+static float N039[3] = {-0.982629 ,-0.169881 ,0.074700};
+static float N040[3] = {-0.695424 ,-0.703466 ,0.146700};
+static float N041[3] = {0.359323 ,-0.915531 ,0.180805};
+static float N042[3] = {0.943356 ,-0.319387 ,0.089842};
+static float N043[3] = {0.998272 ,-0.032435 ,0.048993};
+static float N044[3] = {0.978997 ,0.193205 ,0.065084};
+static float N045[3] = {0.872144 ,0.470094 ,-0.135565};
+static float N046[3] = {-0.664282 ,0.737945 ,-0.119027};
+static float N047[3] = {-0.954508 ,0.288570 ,0.075107};
+static float N048[3] = {-0.998273 ,0.032406 ,0.048993};
+static float N049[3] = {-0.979908 ,-0.193579 ,0.048038};
+static float N050[3] = {-0.858736 ,-0.507202 ,-0.072938};
+static float N051[3] = {0.643545 ,-0.763887 ,-0.048237};
+static float N052[3] = {0.955580 ,-0.288954 ,0.058068};
+static float N058[3] = {0.000050 ,0.793007 ,-0.609213};
+static float N059[3] = {0.913510 ,0.235418 ,-0.331779};
+static float N060[3] = {-0.807970 ,0.495000 ,-0.319625};
+static float N061[3] = {0.000000 ,0.784687 ,-0.619892};
+static float N062[3] = {0.000000 ,-1.000000 ,0.000000};
+static float N063[3] = {0.000000 ,1.000000 ,0.000000};
+static float N064[3] = {0.000000 ,1.000000 ,0.000000};
+static float N065[3] = {0.000000 ,1.000000 ,0.000000};
+static float N066[3] = {-0.055784 ,0.257059 ,0.964784};
+static float N069[3] = {-0.000505 ,-0.929775 ,-0.368127};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float P002[3] = {0.00, -36.59, 5687.72};
+static float P003[3] = {90.00, 114.73, 724.38};
+static float P004[3] = {58.24, -146.84, 262.35};
+static float P005[3] = {27.81, 231.52, 510.43};
+static float P006[3] = {-27.81, 230.43, 509.76};
+static float P007[3] = {-46.09, -146.83, 265.84};
+static float P008[3] = {-90.00, 103.84, 718.53};
+static float P009[3] = {-131.10, -165.92, 834.85};
+static float P010[3] = {-27.81, -285.31, 500.00};
+static float P011[3] = {27.81, -285.32, 500.00};
+static float P012[3] = {147.96, -170.89, 845.50};
+static float P013[3] = {180.00, 0.00, 2000.00};
+static float P014[3] = {145.62, 352.67, 2000.00};
+static float P015[3] = {55.62, 570.63, 2000.00};
+static float P016[3] = {-55.62, 570.64, 2000.00};
+static float P017[3] = {-145.62, 352.68, 2000.00};
+static float P018[3] = {-180.00, 0.01, 2000.00};
+static float P019[3] = {-178.20, -352.66, 2001.61};
+static float P020[3] = {-55.63, -570.63, 2000.00};
+static float P021[3] = {55.62, -570.64, 2000.00};
+static float P022[3] = {179.91, -352.69, 1998.39};
+static float P023[3] = {150.00, 0.00, 3000.00};
+static float P024[3] = {121.35, 293.89, 3000.00};
+static float P025[3] = {46.35, 502.93, 2883.09};
+static float P026[3] = {-46.35, 497.45, 2877.24};
+static float P027[3] = {-121.35, 293.90, 3000.00};
+static float P028[3] = {-150.00, 0.00, 3000.00};
+static float P029[3] = {-152.21, -304.84, 2858.68};
+static float P030[3] = {-46.36, -475.52, 3000.00};
+static float P031[3] = {46.35, -475.53, 3000.00};
+static float P032[3] = {155.64, -304.87, 2863.50};
+static float P033[3] = {90.00, 0.00, 4000.00};
+static float P034[3] = {72.81, 176.33, 4000.00};
+static float P035[3] = {27.81, 285.32, 4000.00};
+static float P036[3] = {-27.81, 285.32, 4000.00};
+static float P037[3] = {-72.81, 176.34, 4000.00};
+static float P038[3] = {-90.00, 0.00, 4000.00};
+static float P039[3] = {-72.81, -176.33, 4000.00};
+static float P040[3] = {-27.81, -285.31, 4000.00};
+static float P041[3] = {27.81, -285.32, 4000.00};
+static float P042[3] = {72.81, -176.34, 4000.00};
+static float P043[3] = {30.00, 0.00, 5000.00};
+static float P044[3] = {24.27, 58.78, 5000.00};
+static float P045[3] = {9.27, 95.11, 5000.00};
+static float P046[3] = {-9.27, 95.11, 5000.00};
+static float P047[3] = {-24.27, 58.78, 5000.00};
+static float P048[3] = {-30.00, 0.00, 5000.00};
+static float P049[3] = {-24.27, -58.78, 5000.00};
+static float P050[3] = {-9.27, -95.10, 5000.00};
+static float P051[3] = {9.27, -95.11, 5000.00};
+static float P052[3] = {24.27, -58.78, 5000.00};
+static float P058[3] = {0.00, 1212.72, 2703.08};
+static float P059[3] = {50.36, 0.00, 108.14};
+static float P060[3] = {-22.18, 0.00, 108.14};
+static float P061[3] = {0.00, 1181.61, 6344.65};
+static float P062[3] = {516.45, -887.08, 2535.45};
+static float P063[3] = {-545.69, -879.31, 2555.63};
+static float P064[3] = {618.89, -1005.64, 2988.32};
+static float P065[3] = {-635.37, -1014.79, 2938.68};
+static float P066[3] = {0.00, 1374.43, 3064.18};
+static float P069[3] = {0.00, -418.25, 5765.04};
+static float P070[3] = {0.00, 1266.91, 6629.60};
+static float P071[3] = {-139.12, -124.96, 997.98};
+static float P072[3] = {-139.24, -110.18, 1020.68};
+static float P073[3] = {-137.33, -94.52, 1022.63};
+static float P074[3] = {-137.03, -79.91, 996.89};
+static float P075[3] = {-135.21, -91.48, 969.14};
+static float P076[3] = {-135.39, -110.87, 968.76};
+static float P077[3] = {150.23, -78.44, 995.53};
+static float P078[3] = {152.79, -92.76, 1018.46};
+static float P079[3] = {154.19, -110.20, 1020.55};
+static float P080[3] = {151.33, -124.15, 993.77};
+static float P081[3] = {150.49, -111.19, 969.86};
+static float P082[3] = {150.79, -92.41, 969.70};
+static float iP002[3] = {0.00, -36.59, 5687.72};
+static float iP004[3] = {58.24, -146.84, 262.35};
+static float iP007[3] = {-46.09, -146.83, 265.84};
+static float iP010[3] = {-27.81, -285.31, 500.00};
+static float iP011[3] = {27.81, -285.32, 500.00};
+static float iP023[3] = {150.00, 0.00, 3000.00};
+static float iP024[3] = {121.35, 293.89, 3000.00};
+static float iP025[3] = {46.35, 502.93, 2883.09};
+static float iP026[3] = {-46.35, 497.45, 2877.24};
+static float iP027[3] = {-121.35, 293.90, 3000.00};
+static float iP028[3] = {-150.00, 0.00, 3000.00};
+static float iP029[3] = {-121.35, -304.84, 2853.86};
+static float iP030[3] = {-46.36, -475.52, 3000.00};
+static float iP031[3] = {46.35, -475.53, 3000.00};
+static float iP032[3] = {121.35, -304.87, 2853.86};
+static float iP033[3] = {90.00, 0.00, 4000.00};
+static float iP034[3] = {72.81, 176.33, 4000.00};
+static float iP035[3] = {27.81, 285.32, 4000.00};
+static float iP036[3] = {-27.81, 285.32, 4000.00};
+static float iP037[3] = {-72.81, 176.34, 4000.00};
+static float iP038[3] = {-90.00, 0.00, 4000.00};
+static float iP039[3] = {-72.81, -176.33, 4000.00};
+static float iP040[3] = {-27.81, -285.31, 4000.00};
+static float iP041[3] = {27.81, -285.32, 4000.00};
+static float iP042[3] = {72.81, -176.34, 4000.00};
+static float iP043[3] = {30.00, 0.00, 5000.00};
+static float iP044[3] = {24.27, 58.78, 5000.00};
+static float iP045[3] = {9.27, 95.11, 5000.00};
+static float iP046[3] = {-9.27, 95.11, 5000.00};
+static float iP047[3] = {-24.27, 58.78, 5000.00};
+static float iP048[3] = {-30.00, 0.00, 5000.00};
+static float iP049[3] = {-24.27, -58.78, 5000.00};
+static float iP050[3] = {-9.27, -95.10, 5000.00};
+static float iP051[3] = {9.27, -95.11, 5000.00};
+static float iP052[3] = {24.27, -58.78, 5000.00};
+static float iP061[3] = {0.00, 1181.61, 6344.65};
+static float iP069[3] = {0.00, -418.25, 5765.04};
+static float iP070[3] = {0.00, 1266.91, 6629.60};
+/* *INDENT-ON* */
+
+void
+Fish001(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P072);
+    glVertex3fv(P073);
+    glVertex3fv(P074);
+    glVertex3fv(P075);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P077);
+    glVertex3fv(P078);
+    glVertex3fv(P079);
+    glVertex3fv(P080);
+    glVertex3fv(P081);
+    glVertex3fv(P082);
+    glEnd();
+}
+
+void
+Fish002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+}
+
+void
+Fish004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+}
+
+void
+Fish005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Fish006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+}
+
+void
+Fish007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+}
+
+void
+Fish008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish009(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P059);
+    glVertex3fv(P012);
+    glVertex3fv(P009);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P012);
+    glVertex3fv(P004);
+    glVertex3fv(P007);
+    glVertex3fv(P009);
+    glEnd();
+}
+
+void
+Fish_1(void)
+{
+    Fish004();
+    Fish005();
+    Fish003();
+    Fish007();
+    Fish006();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_2(void)
+{
+    Fish005();
+    Fish004();
+    Fish003();
+    Fish008();
+    Fish006();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_3(void)
+{
+    Fish005();
+    Fish004();
+    Fish007();
+    Fish003();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_4(void)
+{
+    Fish005();
+    Fish004();
+    Fish008();
+    Fish003();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_5(void)
+{
+    Fish009();
+    Fish006();
+    Fish007();
+    Fish001();
+    Fish002();
+    Fish003();
+    Fish008();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_6(void)
+{
+    Fish009();
+    Fish006();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_7(void)
+{
+    Fish009();
+    Fish001();
+    Fish007();
+    Fish005();
+    Fish002();
+    Fish008();
+    Fish003();
+    Fish004();
+    Fish006();
+}
+
+void
+Fish_8(void)
+{
+    Fish009();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish005();
+    Fish004();
+    Fish006();
+}
+
+void
+DrawShark(fishRec * fish)
+{
+    int n;
+    float seg1, seg2, seg3, seg4, segup;
+    float thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 50.0 * fish->v;
+
+    seg1 = 0.6 * thrash * sin(fish->htail * RRAD);
+    seg2 = 1.8 * thrash * sin((fish->htail + 45.0) * RRAD);
+    seg3 = 3.0 * thrash * sin((fish->htail + 90.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 110.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P004[1] = iP004[1] + chomp;
+    P007[1] = iP007[1] + chomp;
+    P010[1] = iP010[1] + chomp;
+    P011[1] = iP011[1] + chomp;
+
+    P023[0] = iP023[0] + seg1;
+    P024[0] = iP024[0] + seg1;
+    P025[0] = iP025[0] + seg1;
+    P026[0] = iP026[0] + seg1;
+    P027[0] = iP027[0] + seg1;
+    P028[0] = iP028[0] + seg1;
+    P029[0] = iP029[0] + seg1;
+    P030[0] = iP030[0] + seg1;
+    P031[0] = iP031[0] + seg1;
+    P032[0] = iP032[0] + seg1;
+    P033[0] = iP033[0] + seg2;
+    P034[0] = iP034[0] + seg2;
+    P035[0] = iP035[0] + seg2;
+    P036[0] = iP036[0] + seg2;
+    P037[0] = iP037[0] + seg2;
+    P038[0] = iP038[0] + seg2;
+    P039[0] = iP039[0] + seg2;
+    P040[0] = iP040[0] + seg2;
+    P041[0] = iP041[0] + seg2;
+    P042[0] = iP042[0] + seg2;
+    P043[0] = iP043[0] + seg3;
+    P044[0] = iP044[0] + seg3;
+    P045[0] = iP045[0] + seg3;
+    P046[0] = iP046[0] + seg3;
+    P047[0] = iP047[0] + seg3;
+    P048[0] = iP048[0] + seg3;
+    P049[0] = iP049[0] + seg3;
+    P050[0] = iP050[0] + seg3;
+    P051[0] = iP051[0] + seg3;
+    P052[0] = iP052[0] + seg3;
+    P002[0] = iP002[0] + seg4;
+    P061[0] = iP061[0] + seg4;
+    P069[0] = iP069[0] + seg4;
+    P070[0] = iP070[0] + seg4;
+
+    fish->vtail += ((fish->dtheta - fish->vtail) * 0.1);
+
+    if (fish->vtail > 0.5) {
+        fish->vtail = 0.5;
+    } else if (fish->vtail < -0.5) {
+        fish->vtail = -0.5;
+    }
+    segup = thrash * fish->vtail;
+
+    P023[1] = iP023[1] + segup;
+    P024[1] = iP024[1] + segup;
+    P025[1] = iP025[1] + segup;
+    P026[1] = iP026[1] + segup;
+    P027[1] = iP027[1] + segup;
+    P028[1] = iP028[1] + segup;
+    P029[1] = iP029[1] + segup;
+    P030[1] = iP030[1] + segup;
+    P031[1] = iP031[1] + segup;
+    P032[1] = iP032[1] + segup;
+    P033[1] = iP033[1] + segup * 5.0;
+    P034[1] = iP034[1] + segup * 5.0;
+    P035[1] = iP035[1] + segup * 5.0;
+    P036[1] = iP036[1] + segup * 5.0;
+    P037[1] = iP037[1] + segup * 5.0;
+    P038[1] = iP038[1] + segup * 5.0;
+    P039[1] = iP039[1] + segup * 5.0;
+    P040[1] = iP040[1] + segup * 5.0;
+    P041[1] = iP041[1] + segup * 5.0;
+    P042[1] = iP042[1] + segup * 5.0;
+    P043[1] = iP043[1] + segup * 12.0;
+    P044[1] = iP044[1] + segup * 12.0;
+    P045[1] = iP045[1] + segup * 12.0;
+    P046[1] = iP046[1] + segup * 12.0;
+    P047[1] = iP047[1] + segup * 12.0;
+    P048[1] = iP048[1] + segup * 12.0;
+    P049[1] = iP049[1] + segup * 12.0;
+    P050[1] = iP050[1] + segup * 12.0;
+    P051[1] = iP051[1] + segup * 12.0;
+    P052[1] = iP052[1] + segup * 12.0;
+    P002[1] = iP002[1] + segup * 17.0;
+    P061[1] = iP061[1] + segup * 17.0;
+    P069[1] = iP069[1] + segup * 17.0;
+    P070[1] = iP070[1] + segup * 17.0;
+
+    glPushMatrix();
+
+    glTranslatef(0.0, 0.0, -3000.0);
+
+//    glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0][0]);
+    n = 0;
+/*
+    if (mat[0][2] >= 0.0) {
+        n += 1;
+    }
+    if (mat[1][2] >= 0.0) {
+        n += 2;
+    }
+    if (mat[2][2] >= 0.0) {
+        n += 4;
+    }
+*/
+    glScalef(2.0, 1.0, 1.0);
+
+    glEnable(GL_CULL_FACE);
+    switch (n) {
+    case 0:
+        Fish_1();
+        break;
+    case 1:
+        Fish_2();
+        break;
+    case 2:
+        Fish_3();
+        break;
+    case 3:
+        Fish_4();
+        break;
+    case 4:
+        Fish_5();
+        break;
+    case 5:
+        Fish_6();
+        break;
+    case 6:
+        Fish_7();
+        break;
+    case 7:
+        Fish_8();
+        break;
+    }
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi/Makefile
===================================================================
--- trunk/src/testing/app/atlantis-mpi/Makefile	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/Makefile	(revision 4)
@@ -0,0 +1,19 @@
+PROGRAM = atlantis-mpi
+CC=g++ -I/opt/mpich/include -Wno-deprecated
+
+FILES = atlantis.o dolphin.o shark.o swim.o whale.o
+
+LDFLAGS += -lglut -lGLU -lGL -L/usr/X11R6/lib64 -lXmu -lXi -lX11 -lm -ldl -L../../lib -lsail -L/opt/mpich/ch-p4/lib64 -lmpich
+CFLAGS += -O -fomit-frame-pointer -ffast-math -I../../include
+
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(CC) -o $(PROGRAM) $(FILES) $(LDFLAGS)
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/atlantis-mpi/dolphin.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi/dolphin.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/dolphin.c	(revision 4)
@@ -0,0 +1,1945 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {-0.005937 ,-0.101998 ,-0.994767};
+static float N002[3] = {0.936780 ,-0.200803 ,0.286569};
+static float N003[3] = {-0.233062 ,0.972058 ,0.028007};
+static float N005[3] = {0.898117 ,0.360171 ,0.252315};
+static float N006[3] = {-0.915437 ,0.348456 ,0.201378};
+static float N007[3] = {0.602263 ,-0.777527 ,0.180920};
+static float N008[3] = {-0.906912 ,-0.412015 ,0.088061};
+static float N012[3] = {0.884408 ,-0.429417 ,-0.182821};
+static float N013[3] = {0.921121 ,0.311084 ,-0.234016};
+static float N014[3] = {0.382635 ,0.877882 ,-0.287948};
+static float N015[3] = {-0.380046 ,0.888166 ,-0.258316};
+static float N016[3] = {-0.891515 ,0.392238 ,-0.226607};
+static float N017[3] = {-0.901419 ,-0.382002 ,-0.203763};
+static float N018[3] = {-0.367225 ,-0.911091 ,-0.187243};
+static float N019[3] = {0.339539 ,-0.924846 ,-0.171388};
+static float N020[3] = {0.914706 ,-0.378617 ,-0.141290};
+static float N021[3] = {0.950662 ,0.262713 ,-0.164994};
+static float N022[3] = {0.546359 ,0.801460 ,-0.243218};
+static float N023[3] = {-0.315796 ,0.917068 ,-0.243431};
+static float N024[3] = {-0.825687 ,0.532277 ,-0.186875};
+static float N025[3] = {-0.974763 ,-0.155232 ,-0.160435};
+static float N026[3] = {-0.560596 ,-0.816658 ,-0.137119};
+static float N027[3] = {0.380210 ,-0.910817 ,-0.160786};
+static float N028[3] = {0.923772 ,-0.358322 ,-0.135093};
+static float N029[3] = {0.951202 ,0.275053 ,-0.139859};
+static float N030[3] = {0.686099 ,0.702548 ,-0.188932};
+static float N031[3] = {-0.521865 ,0.826719 ,-0.210220};
+static float N032[3] = {-0.923820 ,0.346739 ,-0.162258};
+static float N033[3] = {-0.902095 ,-0.409995 ,-0.134646};
+static float N034[3] = {-0.509115 ,-0.848498 ,-0.144404};
+static float N035[3] = {0.456469 ,-0.880293 ,-0.129305};
+static float N036[3] = {0.873401 ,-0.475489 ,-0.105266};
+static float N037[3] = {0.970825 ,0.179861 ,-0.158584};
+static float N038[3] = {0.675609 ,0.714187 ,-0.183004};
+static float N039[3] = {-0.523574 ,0.830212 ,-0.191360};
+static float N040[3] = {-0.958895 ,0.230808 ,-0.165071};
+static float N041[3] = {-0.918285 ,-0.376803 ,-0.121542};
+static float N042[3] = {-0.622467 ,-0.774167 ,-0.114888};
+static float N043[3] = {0.404497 ,-0.908807 ,-0.102231};
+static float N044[3] = {0.930538 ,-0.365155 ,-0.027588};
+static float N045[3] = {0.921920 ,0.374157 ,-0.100345};
+static float N046[3] = {0.507346 ,0.860739 ,0.041562};
+static float N047[3] = {-0.394646 ,0.918815 ,-0.005730};
+static float N048[3] = {-0.925411 ,0.373024 ,-0.066837};
+static float N049[3] = {-0.945337 ,-0.322309 ,-0.049551};
+static float N050[3] = {-0.660437 ,-0.750557 ,-0.022072};
+static float N051[3] = {0.488835 ,-0.871950 ,-0.027261};
+static float N052[3] = {0.902599 ,-0.421397 ,0.087969};
+static float N053[3] = {0.938636 ,0.322606 ,0.122020};
+static float N054[3] = {0.484605 ,0.871078 ,0.079878};
+static float N055[3] = {-0.353607 ,0.931559 ,0.084619};
+static float N056[3] = {-0.867759 ,0.478564 ,0.134054};
+static float N057[3] = {-0.951583 ,-0.296030 ,0.082794};
+static float N058[3] = {-0.672355 ,-0.730209 ,0.121384};
+static float N059[3] = {0.528336 ,-0.842452 ,0.105525};
+static float N060[3] = {0.786913 ,-0.564760 ,0.248627};
+static float N062[3] = {0.622098 ,0.765230 ,0.165584};
+static float N063[3] = {-0.631711 ,0.767816 ,0.106773};
+static float N064[3] = {-0.687886 ,0.606351 ,0.398938};
+static float N065[3] = {-0.946327 ,-0.281623 ,0.158598};
+static float N066[3] = {-0.509549 ,-0.860437 ,0.002776};
+static float N067[3] = {0.462594 ,-0.876692 ,0.131977};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N078[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N079[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N080[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N081[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N082[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N083[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N084[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N085[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N086[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N087[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N088[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N089[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N090[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N097[3] = {-0.697296 ,0.702881 ,0.140491};
+static float N098[3] = {0.918864 ,0.340821 ,0.198819};
+static float N099[3] = {-0.932737 ,0.201195 ,0.299202};
+static float N100[3] = {0.029517 ,0.981679 ,0.188244};
+static float N102[3] = {0.813521 ,-0.204936 ,0.544229};
+static float N110[3] = {-0.781480 ,-0.384779 ,0.491155};
+static float N111[3] = {-0.722243 ,0.384927 ,0.574627};
+static float N112[3] = {-0.752278 ,0.502679 ,0.425901};
+static float N113[3] = {0.547257 ,0.367910 ,0.751766};
+static float N114[3] = {0.725949 ,-0.232568 ,0.647233};
+static float N115[3] = {-0.747182 ,-0.660786 ,0.071280};
+static float N116[3] = {0.931519 ,0.200748 ,0.303270};
+static float N117[3] = {-0.828928 ,0.313757 ,0.463071};
+static float N118[3] = {0.902554 ,-0.370967 ,0.218587};
+static float N119[3] = {-0.879257 ,-0.441851 ,0.177973};
+static float N120[3] = {0.642327 ,0.611901 ,0.461512};
+static float N121[3] = {0.964817 ,-0.202322 ,0.167910};
+static float N122[3] = {0.000000 ,1.000000 ,0.000000};
+static float P001[3] = {5.68, -300.95, 1324.70};
+static float P002[3] = {338.69, -219.63, 9677.03};
+static float P003[3] = {12.18, 474.59, 9138.14};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 68.74, 9427.85};
+static float P007[3] = {156.52, -266.72, 10311.68};
+static float P008[3] = {-185.56, -266.51, 10310.47};
+static float P009[3] = {124.39, -261.46, 1942.34};
+static float P010[3] = {-130.05, -261.46, 1946.03};
+static float P011[3] = {141.07, -320.11, 1239.38};
+static float P012[3] = {156.48, -360.12, 2073.41};
+static float P013[3] = {162.00, -175.88, 2064.44};
+static float P014[3] = {88.16, -87.72, 2064.02};
+static float P015[3] = {-65.21, -96.13, 2064.02};
+static float P016[3] = {-156.48, -180.96, 2064.44};
+static float P017[3] = {-162.00, -368.93, 2082.39};
+static float P018[3] = {-88.16, -439.22, 2082.39};
+static float P019[3] = {65.21, -440.32, 2083.39};
+static float P020[3] = {246.87, -356.02, 2576.95};
+static float P021[3] = {253.17, -111.15, 2567.15};
+static float P022[3] = {132.34, 51.41, 2559.84};
+static float P023[3] = {-97.88, 40.44, 2567.15};
+static float P024[3] = {-222.97, -117.49, 2567.15};
+static float P025[3] = {-252.22, -371.53, 2569.92};
+static float P026[3] = {-108.44, -518.19, 2586.75};
+static float P027[3] = {97.88, -524.79, 2586.75};
+static float P028[3] = {370.03, -421.19, 3419.70};
+static float P029[3] = {351.15, -16.98, 3423.17};
+static float P030[3] = {200.66, 248.46, 3430.37};
+static float P031[3] = {-148.42, 235.02, 3417.91};
+static float P032[3] = {-360.21, -30.27, 3416.84};
+static float P033[3] = {-357.90, -414.89, 3407.04};
+static float P034[3] = {-148.88, -631.35, 3409.90};
+static float P035[3] = {156.38, -632.59, 3419.70};
+static float P036[3] = {462.61, -469.21, 4431.51};
+static float P037[3] = {466.60, 102.25, 4434.98};
+static float P038[3] = {243.05, 474.34, 4562.02};
+static float P039[3] = {-191.23, 474.40, 4554.42};
+static float P040[3] = {-476.12, 111.05, 4451.11};
+static float P041[3] = {-473.36, -470.74, 4444.78};
+static float P042[3] = {-266.95, -748.41, 4447.78};
+static float P043[3] = {211.14, -749.91, 4429.73};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 6360.63};
+static float P046[3] = {371.29, 804.51, 6486.26};
+static float P047[3] = {-291.43, 797.22, 6494.28};
+static float P048[3] = {-784.13, 370.75, 6378.01};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float iP001[3] = {5.68, -300.95, 1324.70};
+static float iP009[3] = {124.39, -261.46, 1942.34};
+static float iP010[3] = {-130.05, -261.46, 1946.03};
+static float iP011[3] = {141.07, -320.11, 1239.38};
+static float iP012[3] = {156.48, -360.12, 2073.41};
+static float iP013[3] = {162.00, -175.88, 2064.44};
+static float iP014[3] = {88.16, -87.72, 2064.02};
+static float iP015[3] = {-65.21, -96.13, 2064.02};
+static float iP016[3] = {-156.48, -180.96, 2064.44};
+static float iP017[3] = {-162.00, -368.93, 2082.39};
+static float iP018[3] = {-88.16, -439.22, 2082.39};
+static float iP019[3] = {65.21, -440.32, 2083.39};
+static float iP020[3] = {246.87, -356.02, 2576.95};
+static float iP021[3] = {253.17, -111.15, 2567.15};
+static float iP022[3] = {132.34, 51.41, 2559.84};
+static float iP023[3] = {-97.88, 40.44, 2567.15};
+static float iP024[3] = {-222.97, -117.49, 2567.15};
+static float iP025[3] = {-252.22, -371.53, 2569.92};
+static float iP026[3] = {-108.44, -518.19, 2586.75};
+static float iP027[3] = {97.88, -524.79, 2586.75};
+static float iP028[3] = {370.03, -421.19, 3419.70};
+static float iP029[3] = {351.15, -16.98, 3423.17};
+static float iP030[3] = {200.66, 248.46, 3430.37};
+static float iP031[3] = {-148.42, 235.02, 3417.91};
+static float iP032[3] = {-360.21, -30.27, 3416.84};
+static float iP033[3] = {-357.90, -414.89, 3407.04};
+static float iP034[3] = {-148.88, -631.35, 3409.90};
+static float iP035[3] = {156.38, -632.59, 3419.70};
+static float iP036[3] = {462.61, -469.21, 4431.51};
+static float iP037[3] = {466.60, 102.25, 4434.98};
+static float iP038[3] = {243.05, 474.34, 4562.02};
+static float iP039[3] = {-191.23, 474.40, 4554.42};
+static float iP040[3] = {-476.12, 111.05, 4451.11};
+static float iP041[3] = {-473.36, -470.74, 4444.78};
+static float iP042[3] = {-266.95, -748.41, 4447.78};
+static float iP043[3] = {211.14, -749.91, 4429.73};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 6360.63};
+static float iP046[3] = {371.29, 804.51, 6486.26};
+static float iP047[3] = {-291.43, 797.22, 6494.28};
+static float iP048[3] = {-784.13, 370.75, 6378.01};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -300.15, 7894.03};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {246.22, 558.53, 8460.50};
+static float P055[3] = {-230.41, 559.84, 8473.23};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 338.75, 9450.30};
+static float P063[3] = {-165.71, 341.04, 9462.35};
+static float P064[3] = {-298.11, 110.13, 10180.37};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -491.45, 9348.73};
+static float P068[3] = {-136.29, -319.84, 1228.73};
+static float P069[3] = {1111.17, -314.14, 1314.19};
+static float P070[3] = {-1167.34, -321.61, 1319.45};
+static float P071[3] = {1404.86, -306.66, 1235.45};
+static float P072[3] = {-1409.73, -314.14, 1247.66};
+static float P073[3] = {1254.01, -296.87, 1544.58};
+static float P074[3] = {-1262.09, -291.70, 1504.26};
+static float P075[3] = {965.71, -269.26, 1742.65};
+static float P076[3] = {-900.97, -276.74, 1726.07};
+static float iP068[3] = {-136.29, -319.84, 1228.73};
+static float iP069[3] = {1111.17, -314.14, 1314.19};
+static float iP070[3] = {-1167.34, -321.61, 1319.45};
+static float iP071[3] = {1404.86, -306.66, 1235.45};
+static float iP072[3] = {-1409.73, -314.14, 1247.66};
+static float iP073[3] = {1254.01, -296.87, 1544.58};
+static float iP074[3] = {-1262.09, -291.70, 1504.26};
+static float iP075[3] = {965.71, -269.26, 1742.65};
+static float iP076[3] = {-900.97, -276.74, 1726.07};
+static float P077[3] = {1058.00, -448.81, 8194.66};
+static float P078[3] = {-1016.51, -456.43, 8190.62};
+static float P079[3] = {-1515.96, -676.45, 7754.93};
+static float P080[3] = {1856.75, -830.34, 7296.56};
+static float P081[3] = {1472.16, -497.38, 7399.68};
+static float P082[3] = {-1775.26, -829.51, 7298.46};
+static float P083[3] = {911.09, -252.51, 7510.99};
+static float P084[3] = {-1451.94, -495.62, 7384.30};
+static float P085[3] = {1598.75, -669.26, 7769.90};
+static float P086[3] = {-836.53, -250.08, 7463.25};
+static float P087[3] = {722.87, -158.18, 8006.41};
+static float P088[3] = {-688.86, -162.28, 7993.89};
+static float P089[3] = {-626.92, -185.30, 8364.98};
+static float P090[3] = {647.72, -189.46, 8354.99};
+static float P091[3] = {0.00, 835.01, 5555.62};
+static float P092[3] = {0.00, 1350.18, 5220.86};
+static float P093[3] = {0.00, 1422.94, 5285.27};
+static float P094[3] = {0.00, 1296.75, 5650.19};
+static float P095[3] = {0.00, 795.63, 6493.88};
+static float iP091[3] = {0.00, 835.01, 5555.62};
+static float iP092[3] = {0.00, 1350.18, 5220.86};
+static float iP093[3] = {0.00, 1422.94, 5285.27};
+static float iP094[3] = {0.00, 1296.75, 5650.19};
+static float iP095[3] = {0.00, 795.63, 6493.88};
+static float P097[3] = {-194.91, -357.14, 10313.32};
+static float P098[3] = {135.35, -357.66, 10307.94};
+static float iP097[3] = {-194.91, -357.14, 10313.32};
+static float iP098[3] = {135.35, -357.66, 10307.94};
+static float P099[3] = {-380.53, -221.14, 9677.98};
+static float P100[3] = {0.00, 412.99, 9629.33};
+static float P102[3] = {59.51, -412.55, 10677.58};
+static float iP102[3] = {59.51, -412.55, 10677.58};
+static float P103[3] = {6.50, 484.74, 9009.94};
+static float P105[3] = {-41.86, 476.51, 9078.17};
+static float P108[3] = {49.20, 476.83, 9078.24};
+static float P110[3] = {-187.62, -410.04, 10674.12};
+static float iP110[3] = {-187.62, -410.04, 10674.12};
+static float P111[3] = {-184.25, -318.70, 10723.88};
+static float iP111[3] = {-184.25, -318.70, 10723.88};
+static float P112[3] = {-179.61, -142.81, 10670.26};
+static float P113[3] = {57.43, -147.94, 10675.26};
+static float P114[3] = {54.06, -218.90, 10712.44};
+static float P115[3] = {-186.35, -212.09, 10713.76};
+static float P116[3] = {205.90, -84.61, 10275.97};
+static float P117[3] = {-230.96, -83.26, 10280.09};
+static float iP118[3] = {216.78, -509.17, 10098.94};
+static float iP119[3] = {-313.21, -510.79, 10102.62};
+static float P118[3] = {216.78, -509.17, 10098.94};
+static float P119[3] = {-313.21, -510.79, 10102.62};
+static float P120[3] = {217.95, 96.34, 10161.62};
+static float P121[3] = {71.99, -319.74, 10717.70};
+static float iP121[3] = {71.99, -319.74, 10717.70};
+static float P122[3] = {0.00, 602.74, 5375.84};
+static float iP122[3] = {0.00, 602.74, 5375.84};
+static float P123[3] = {-448.94, -203.14, 9499.60};
+static float P124[3] = {-442.64, -185.20, 9528.07};
+static float P125[3] = {-441.07, -148.05, 9528.07};
+static float P126[3] = {-443.43, -128.84, 9499.60};
+static float P127[3] = {-456.87, -146.78, 9466.67};
+static float P128[3] = {-453.68, -183.93, 9466.67};
+static float P129[3] = {428.43, -124.08, 9503.03};
+static float P130[3] = {419.73, -142.14, 9534.56};
+static float P131[3] = {419.92, -179.96, 9534.56};
+static float P132[3] = {431.20, -199.73, 9505.26};
+static float P133[3] = {442.28, -181.67, 9475.96};
+static float P134[3] = {442.08, -143.84, 9475.96};
+/* *INDENT-ON* */
+
+void
+Dolphin001(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P072);
+    glVertex3fv(P074);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P072);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P074);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P001);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Dolphin002(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P001);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P075);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P009);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P071);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Dolphin003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Dolphin004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Dolphin005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Dolphin006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Dolphin007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Dolphin008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Dolphin009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Dolphin010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Dolphin011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Dolphin012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+}
+
+void
+Dolphin013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P007);
+    glVertex3fv(P008);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P007);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+}
+
+void
+Dolphin014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P098);
+    glVertex3fv(P097);
+    glVertex3fv(P111);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P099);
+    glVertex3fv(P097);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+Dolphin015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Dolphin016(void)
+{
+
+    glDisable(GL_DEPTH_TEST);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P123);
+    glVertex3fv(P124);
+    glVertex3fv(P125);
+    glVertex3fv(P126);
+    glVertex3fv(P127);
+    glVertex3fv(P128);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P129);
+    glVertex3fv(P130);
+    glVertex3fv(P131);
+    glVertex3fv(P132);
+    glVertex3fv(P133);
+    glVertex3fv(P134);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P103);
+    glVertex3fv(P105);
+    glVertex3fv(P108);
+    glEnd();
+    glEnable(GL_DEPTH_TEST);
+}
+
+void
+DrawDolphin(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch, thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (10.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg3 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.0 * thrash * sin((fish->htail + 4.0) * RRAD);
+    seg2 = 3.0 * thrash * sin((fish->htail + 6.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg5 = 4.5 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg6 = 5.0 * thrash * sin((fish->htail + 20.0) * RRAD);
+    seg7 = 6.0 * thrash * sin((fish->htail + 30.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail + 180.0) * RRAD);
+
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    chomp = 100.0;
+
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3;
+    P122[1] = iP122[1] + seg3 * 1.5;
+
+    P097[1] = iP097[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P102[1] = iP102[1] + chomp;
+    P110[1] = iP110[1] + chomp;
+    P111[1] = iP111[1] + chomp;
+    P121[1] = iP121[1] + chomp;
+    P118[1] = iP118[1] + chomp;
+    P119[1] = iP119[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 7000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+/*	glGetFloatv(GL_MODELVIEW_MATRIX, f);
+	printf("Modelview:\n");
+	printf("%f %f %f %f ", f[0], f[1], f[2], f[3]);
+	printf("%f %f %f %f ", f[4], f[5], f[6], f[7]);
+	printf("%f %f %f %f ", f[8], f[9], f[10], f[11]);
+	printf("%f %f %f %f\n", f[12], f[13], f[14], f[15]);
+*/
+    //glEnable(GL_CULL_FACE);
+    Dolphin014();
+    Dolphin010();
+    Dolphin009();
+    Dolphin012();
+    Dolphin013();
+    Dolphin006();
+    Dolphin002();
+    Dolphin001();
+    Dolphin003();
+    Dolphin015();
+    Dolphin004();
+    Dolphin005();
+    Dolphin007();
+    Dolphin008();
+    Dolphin011();
+    Dolphin016();
+    //glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi/atlantis.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi/atlantis.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/atlantis.c	(revision 4)
@@ -0,0 +1,564 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock.h>
+#include <sys\timeb.h>
+int gettimeofday(struct timeval *tp, void *tzp);
+#else
+#include <sys/time.h>
+#endif
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include "atlantis.h"
+
+#include <mpi.h>
+int rank   = 0;  // node rank
+int nprocs = 0;  // number of nodes
+int dimX, dimY, Xidx, Yidx;
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+
+#if defined(WIN32)
+int
+gettimeofday(struct timeval *tp, void *tzp)
+{
+	struct _timeb t;
+
+    _ftime(&t);
+    tp->tv_sec = t.time;
+    tp->tv_usec = t.millitm * 1000;
+    return 0;
+}
+#endif
+
+fishRec sharks[NUM_SHARKS];
+fishRec momWhale;
+fishRec babyWhale;
+fishRec dolph;
+
+GLboolean moving;
+int screenshot = 0;
+float t1,t2;
+struct timeval tv_start;
+
+double getTime()
+{
+    struct timeval tv;
+		        
+    gettimeofday(&tv,0);
+    return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+}
+/*
+float abs(float f)
+{
+    if (f >= 0.0f) return f;
+    else return -f;
+}
+*/
+void
+InitFishs(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        sharks[i].x = 15000.0 + rand() % 6000;
+        sharks[i].y = (rand() % 20000) - 10000;
+        sharks[i].z = (rand() % 6000) - 5000;
+        sharks[i].psi = rand() % 360 - 180.0;
+        sharks[i].v = 1.0;
+    }
+
+    dolph.x = 30000.0;
+    dolph.y = 0.0;
+    dolph.z = 6000.0;
+    dolph.psi = 90.0;
+    dolph.theta = 0.0;
+    dolph.v = 3.0;
+
+    momWhale.x = 70000.0;
+    momWhale.y = 0.0;
+    momWhale.z = 0.0;
+    momWhale.psi = 90.0;
+    momWhale.theta = 0.0;
+    momWhale.v = 3.0;
+
+    babyWhale.x = 60000.0;
+    babyWhale.y = -2000.0;
+    babyWhale.z = -2000.0;
+    babyWhale.psi = 90.0;
+    babyWhale.theta = 0.0;
+    babyWhale.v = 3.0;
+}
+
+void
+Init(void)
+{
+    static float ambient[] =
+    {0.1, 0.1, 0.1, 1.0};
+    static float diffuse[] =
+    {1.0, 1.0, 1.0, 1.0};
+    static float position[] =
+    {0.0, 1.0, 0.0, 0.0};
+    static float mat_shininess[] =
+    {90.0};
+    static float mat_specular[] =
+    {0.8, 0.8, 0.8, 1.0};
+    static float mat_diffuse[] =
+    {0.46, 0.66, 0.795, 1.0};
+    static float mat_ambient[] =
+    {0.0, 0.1, 0.2, 1.0};
+    static float lmodel_ambient[] =
+    {0.4, 0.4, 0.4, 1.0};
+    static float lmodel_localviewer[] =
+    {1.0};
+
+    glFrontFace(GL_CW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    InitFishs();
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+}
+
+void
+Reshape(int width, int height)
+{
+    winWidth = width;
+    winHeight = height;	
+
+    glViewport(0, 0, width, height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(4.0, 2.0, 10000.0, 400000.0);
+    glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+}
+
+void
+Animate(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        SharkPilot(&sharks[i]);
+        SharkMiss(i);
+    }
+    WhalePilot(&dolph);
+    dolph.phi++;
+    glutPostRedisplay();
+    WhalePilot(&momWhale);
+    momWhale.phi++;
+    WhalePilot(&babyWhale);
+    babyWhale.phi++;
+}
+
+/* ARGSUSED1 */
+void
+Key(unsigned char key, int x, int y)
+{
+	(void) x;
+	(void) y;
+    switch (key) 
+	{
+	  case 27:           /* Esc will quit */
+        exit(1);
+        MPI_Finalize();
+        break;
+	  case 's':
+		screenshot++;
+		glutPostRedisplay( );
+		break;
+	  case ' ':          /* space will advance frame */
+        if (!moving) {
+            Animate();
+        }
+    }
+}
+
+
+void
+save_frame( void )
+{
+/*	GLint viewport[4];
+	int x, y, width, height;
+	void *pixels;
+	FILE *f;
+
+	glGetIntegerv( GL_VIEWPORT, viewport );
+
+	x = viewport[0];
+	y = viewport[1];
+	width = viewport[2];
+	height = viewport[3];
+
+	printf( "saving %dx%d screenshot\n", width, height );
+
+	pixels = malloc( width * height * 3 );
+	assert( pixels );
+	memset( pixels, 0, width * height * 3 );
+
+	glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+
+	f = fopen( "screenshot.ppm", "wb" );
+	fprintf( f, "P6\n%d %d\n255\n", width, height );
+	for ( y = height - 1; y >= 0; y-- )
+		fwrite( (char *) pixels + y * width * 3, width, 3, f );
+	fclose( f );
+
+	free( pixels );
+
+	printf( "done\n" );*/
+}
+
+void
+print_performance( void )
+{
+/*	static int first = 1;
+	 = 0
+	static int start, num_frames;
+	int current;
+
+	if ( first )
+	{
+		start = glutGet( GLUT_ELAPSED_TIME );
+		num_frames = 0;
+		first = 0;
+	}
+
+	num_frames++;
+	current = glutGet( GLUT_ELAPSED_TIME );
+
+	if ( current - start > 1000 )
+	{
+		double elapsed = 1e-3 * (double) ( current - start );
+		double rate = (double) num_frames / elapsed;
+		printf( "%5.1f fps\n", rate );
+
+		num_frames = 0;
+		start = current;
+	}*/
+}
+
+void
+Display( void )
+{
+    float ambient[] = {0.1, 0.1, 0.1, 1.0};
+    float diffuse[] = {1.0, 1.0, 1.0, 1.0};
+    float position[] = {0.0, 1.0, 0.0, 0.0};
+    float mat_shininess[] = {90.0};
+    float mat_specular[] = {0.8, 0.8, 0.8, 1.0};
+    float mat_diffuse[] = {0.46, 0.66, 0.795, 1.0};
+    float mat_ambient[] = {0.0, 0.1, 0.2, 1.0};
+    float lmodel_ambient[] = {0.4, 0.4, 0.4, 1.0};
+    float lmodel_localviewer[] = {0.0};
+
+    int i;
+
+    glFrontFace(GL_CCW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+
+
+    //gluPerspective(40.0, 2.0, 10000.0, 400000.0);
+
+    GLfloat fov = 40.0;
+    GLfloat aspect = 2.0;
+    GLfloat near = 10000.0;
+    GLfloat far = 400000.0;
+    GLfloat range = near*tan(M_PI * (fov/2) / 180.0);
+
+#if 0
+	// standard view
+    glFrustum(-range*aspect,range*aspect,-range,range,near,far);
+#else
+	// split view
+    GLfloat Xstep = 2.0*range*aspect / (float)dimX;
+	 GLfloat Ystep = 2.0*range / (float)dimY;
+	 
+    glFrustum(-range*aspect + Xidx*Xstep, -range*aspect + (Xidx+1)*Xstep,
+	 		-range + Yidx*Ystep, -range + (Yidx+1)*Ystep, near, far);
+#endif
+
+    glMatrixMode(GL_MODELVIEW);
+
+	glLoadIdentity();
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  	for (i = 0; i < NUM_SHARKS; i++)
+	{
+		glPushMatrix();
+		FishTransform(&sharks[i]);
+		DrawShark(&sharks[i]);
+		glPopMatrix();
+	}
+
+    glPushMatrix();
+    FishTransform(&dolph);
+    DrawDolphin(&dolph);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&momWhale);
+    DrawWhale(&momWhale);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&babyWhale);
+    glScalef(0.45, 0.45, 0.3);
+    DrawWhale(&babyWhale);
+    glPopMatrix();
+    glFinish();
+
+
+	if (winWidth > 0)	{
+		glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);	
+		MPI_Barrier(MPI_COMM_WORLD);
+		sageInf.swapBuffer();
+		rgbBuffer = (GLubyte *)sageInf.getBuffer();
+		
+		sageMessage msg;
+		if (sageInf.checkMsg(msg, false) > 0) {
+			 switch (msg.getCode()) {
+				 case APP_QUIT : {
+			 		sageInf.shutdown();
+					int err;
+					MPI_Abort(MPI_COMM_WORLD, err);
+					// finalize
+					MPI_Finalize();
+					exit(0);
+					break;
+				}
+			 }	
+		}
+	}
+
+	glutSwapBuffers( );
+}
+
+void
+Visible(int state)
+{
+    if (state == GLUT_VISIBLE) {
+        if (moving)
+            glutIdleFunc(Animate);
+    } else {
+        if (moving)
+            glutIdleFunc(NULL);
+    }
+}
+
+void
+menuSelect(int value)
+{
+    switch (value)
+    {
+        case 1:
+            moving = GL_TRUE;
+            glutIdleFunc(Animate);
+            break;
+        case 2:
+            moving = GL_FALSE;;
+            glutIdleFunc(NULL);
+            break;
+        case 3:
+            exit(0);
+            break;
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+	// MPI Initialization
+	MPI_Init(&argc, &argv);
+	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+	MPI_Barrier(MPI_COMM_WORLD);
+	
+	int appID;
+	if (argc < 2)
+		appID = 0;
+	else
+		appID = atoi(argv[1]);
+		
+	int resX = 1024, resY = 1024;
+	if (argc > 3) {
+		resX = atoi(argv[2]);
+		resY = atoi(argv[3]);
+	}	
+
+	dimX = nprocs;
+	dimY = 1;
+	
+	if (argc > 5) {
+		dimX = atoi(argv[4]);
+		dimY = atoi(argv[5]);
+	}	
+	
+	char procname[MPI_MAX_PROCESSOR_NAME];
+	int lenproc;
+	MPI_Get_processor_name(procname, &lenproc);
+	fprintf(stderr, "Processor %2d is machine [%s]\n", rank, procname);
+
+	Xidx = rank%dimX;
+	Yidx = rank/dimX;
+	
+	printf("Index x=%d y=%d\n", Xidx, Yidx);
+	
+	sageRect atlantisImageMap;
+	atlantisImageMap.left = ((float)Xidx) / ((float)dimX);
+	atlantisImageMap.right = ((float)Xidx+1.0) / ((float)dimX);
+	atlantisImageMap.bottom = ((float)Yidx) / ((float)dimY);
+	atlantisImageMap.top = ((float)Yidx+1.0) / ((float)dimY);;
+
+	sailConfig scfg;
+	scfg.init("atlantis-mpi.conf");
+	scfg.setAppName("atlantis-mpi");
+	scfg.rank = rank;
+	scfg.appID = appID;
+	scfg.resX = resX;
+	scfg.resY = resY;
+	scfg.imageMap = atlantisImageMap;
+	scfg.pixFmt = PIXFMT_888;
+	scfg.rowOrd = BOTTOM_TO_TOP;
+	scfg.nodeNum = nprocs;
+	
+	if (rank == 0)
+		scfg.master = true;
+	else
+		scfg.master = false;	
+
+	sageInf.init(scfg);
+
+	std::cerr << "sail initialized " << std::endl;
+
+	MPI_Barrier(MPI_COMM_WORLD);
+
+  //glutInitWindowSize(512, 192);
+	gettimeofday(&tv_start,0);
+
+	glutInitWindowSize(resX, resY);
+	glutInitWindowPosition(0,0);
+	glutInit(&argc, argv);
+	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+	glutCreateWindow("GLUT Atlantis Demo");
+	printf("sharks: %d\n",NUM_SHARKS);
+	Init();
+	glutDisplayFunc(Display);
+	glutReshapeFunc(Reshape);
+	glutKeyboardFunc(Key);
+	moving = GL_TRUE;
+	glutIdleFunc(Animate);
+	glutVisibilityFunc(Visible);
+	glutCreateMenu(menuSelect);
+	glutAddMenuEntry("Start motion", 1);
+	glutAddMenuEntry("Stop motion", 2);
+	glutAddMenuEntry("Quit", 3);
+	glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+	//glutFullScreen();
+
+	t1 = getTime();
+
+	if (rgbBuffer)
+	    delete [] rgbBuffer;
+   rgbBuffer = (GLubyte *)sageInf.getBuffer();
+   
+	glutMainLoop();
+
+	  // finalize
+	MPI_Finalize();
+
+	  // exit
+	return EXIT_SUCCESS;
+}
Index: trunk/src/testing/app/atlantis-mpi/swim.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi/swim.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/swim.c	(revision 4)
@@ -0,0 +1,191 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#include <stdlib.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include "atlantis.h"
+
+void
+FishTransform(fishRec * fish)
+{
+	glTranslatef(fish->y, fish->z, -fish->x);
+	glRotatef(-fish->psi, 0.0, 1.0, 0.0);
+    glRotatef(fish->theta, 1.0, 0.0, 0.0);
+    glRotatef(-fish->phi, 0.0, 0.0, 1.0);
+}
+
+void
+WhalePilot(fishRec * fish)
+{
+
+    fish->phi = -20.0;
+    fish->theta = 0.0;
+    fish->psi -= 0.5;
+
+    fish->x += WHALESPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += WHALESPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += WHALESPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkPilot(fishRec * fish)
+{
+    static int sign = 1;
+    float X, Y, Z, tpsi, ttheta, thetal;
+
+    fish->xt = 60000.0;
+    fish->yt = 0.0;
+    fish->zt = 0.0;
+
+    X = fish->xt - fish->x;
+    Y = fish->yt - fish->y;
+    Z = fish->zt - fish->z;
+
+    thetal = fish->theta;
+
+    ttheta = RAD * atan(Z / (sqrt(X * X + Y * Y)));
+
+    if (ttheta > fish->theta + 0.25) {
+        fish->theta += 0.5;
+    } else if (ttheta < fish->theta - 0.25) {
+        fish->theta -= 0.5;
+    }
+    if (fish->theta > 90.0) {
+        fish->theta = 90.0;
+    }
+    if (fish->theta < -90.0) {
+        fish->theta = -90.0;
+    }
+    fish->dtheta = fish->theta - thetal;
+
+    tpsi = RAD * atan2(Y, X);
+
+    fish->attack = 0;
+
+    if (fabs(tpsi - fish->psi) < 10.0) {
+        fish->attack = 1;
+    } else if (fabs(tpsi - fish->psi) < 45.0) {
+        if (fish->psi > tpsi) {
+            fish->psi -= 0.5;
+            if (fish->psi < -180.0) {
+                fish->psi += 360.0;
+            }
+        } else if (fish->psi < tpsi) {
+            fish->psi += 0.5;
+            if (fish->psi > 180.0) {
+                fish->psi -= 360.0;
+            }
+        }
+    } else {
+        if (rand() % 100 > 98) {
+            sign = 1 - sign;
+        }
+        fish->psi += sign;
+        if (fish->psi > 180.0) {
+            fish->psi -= 360.0;
+        }
+        if (fish->psi < -180.0) {
+            fish->psi += 360.0;
+        }
+    }
+
+    if (fish->attack) {
+        if (fish->v < 1.1) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.2;
+        }
+        if (fish->v > 5.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.2;
+        }
+    } else {
+        if (!(rand() % 400) && (!fish->spurt)) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.05;
+        }
+        if (fish->v > 3.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.05;
+        }
+    }
+
+    fish->x += SHARKSPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += SHARKSPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += SHARKSPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkMiss(int i)
+{
+    int j;
+    float avoid, thetal;
+    float X, Y, Z, R;
+
+    for (j = 0; j < NUM_SHARKS; j++) {
+        if (j != i) {
+            X = sharks[j].x - sharks[i].x;
+            Y = sharks[j].y - sharks[i].y;
+            Z = sharks[j].z - sharks[i].z;
+
+            R = sqrt(X * X + Y * Y + Z * Z);
+
+            avoid = 1.0;
+            thetal = sharks[i].theta;
+
+            if (R < SHARKSIZE) {
+                if (Z > 0.0) {
+                    sharks[i].theta -= avoid;
+                } else {
+                    sharks[i].theta += avoid;
+                }
+            }
+            sharks[i].dtheta += (sharks[i].theta - thetal);
+        }
+    }
+}
Index: trunk/src/testing/app/atlantis-mpi/whale.c
===================================================================
--- trunk/src/testing/app/atlantis-mpi/whale.c	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/whale.c	(revision 4)
@@ -0,0 +1,1810 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {0.019249 ,0.011340 ,-0.999750};
+static float N002[3] = {-0.132579 ,0.954547 ,0.266952};
+static float N003[3] = {-0.196061 ,0.980392 ,-0.019778};
+static float N004[3] = {0.695461 ,0.604704 ,0.388158};
+static float N005[3] = {0.870600 ,0.425754 ,0.246557};
+static float N006[3] = {-0.881191 ,0.392012 ,0.264251};
+static float N008[3] = {-0.341437 ,0.887477 ,0.309523};
+static float N009[3] = {0.124035 ,-0.992278 ,0.000000};
+static float N010[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N011[3] = {0.588172 ,0.000000 ,0.808736};
+static float N012[3] = {0.929824 ,-0.340623 ,-0.139298};
+static float N013[3] = {0.954183 ,0.267108 ,-0.134865};
+static float N014[3] = {0.495127 ,0.855436 ,-0.151914};
+static float N015[3] = {-0.390199 ,0.906569 ,-0.160867};
+static float N016[3] = {-0.923605 ,0.354581 ,-0.145692};
+static float N017[3] = {-0.955796 ,-0.260667 ,-0.136036};
+static float N018[3] = {-0.501283 ,-0.853462 ,-0.142540};
+static float N019[3] = {0.405300 ,-0.901974 ,-0.148913};
+static float N020[3] = {0.909913 ,-0.392746 ,-0.133451};
+static float N021[3] = {0.936494 ,0.331147 ,-0.115414};
+static float N022[3] = {0.600131 ,0.793724 ,-0.099222};
+static float N023[3] = {-0.231556 ,0.968361 ,-0.093053};
+static float N024[3] = {-0.844369 ,0.525330 ,-0.105211};
+static float N025[3] = {-0.982725 ,-0.136329 ,-0.125164};
+static float N026[3] = {-0.560844 ,-0.822654 ,-0.093241};
+static float N027[3] = {0.263884 ,-0.959981 ,-0.093817};
+static float N028[3] = {0.842057 ,-0.525192 ,-0.122938};
+static float N029[3] = {0.921620 ,0.367565 ,-0.124546};
+static float N030[3] = {0.613927 ,0.784109 ,-0.090918};
+static float N031[3] = {-0.448754 ,0.888261 ,-0.098037};
+static float N032[3] = {-0.891865 ,0.434376 ,-0.126077};
+static float N033[3] = {-0.881447 ,-0.448017 ,-0.149437};
+static float N034[3] = {-0.345647 ,-0.922057 ,-0.174183};
+static float N035[3] = {0.307998 ,-0.941371 ,-0.137688};
+static float N036[3] = {0.806316 ,-0.574647 ,-0.140124};
+static float N037[3] = {0.961346 ,0.233646 ,-0.145681};
+static float N038[3] = {0.488451 ,0.865586 ,-0.110351};
+static float N039[3] = {-0.374290 ,0.921953 ,-0.099553};
+static float N040[3] = {-0.928504 ,0.344533 ,-0.138485};
+static float N041[3] = {-0.918419 ,-0.371792 ,-0.135189};
+static float N042[3] = {-0.520666 ,-0.833704 ,-0.183968};
+static float N043[3] = {0.339204 ,-0.920273 ,-0.195036};
+static float N044[3] = {0.921475 ,-0.387382 ,-0.028636};
+static float N045[3] = {0.842465 ,0.533335 ,-0.076204};
+static float N046[3] = {0.380110 ,0.924939 ,0.002073};
+static float N047[3] = {-0.276128 ,0.961073 ,-0.009579};
+static float N048[3] = {-0.879684 ,0.473001 ,-0.049250};
+static float N049[3] = {-0.947184 ,-0.317614 ,-0.044321};
+static float N050[3] = {-0.642059 ,-0.764933 ,-0.051363};
+static float N051[3] = {0.466794 ,-0.880921 ,-0.077990};
+static float N052[3] = {0.898509 ,-0.432277 ,0.076279};
+static float N053[3] = {0.938985 ,0.328141 ,0.103109};
+static float N054[3] = {0.442420 ,0.895745 ,0.043647};
+static float N055[3] = {-0.255163 ,0.966723 ,0.018407};
+static float N056[3] = {-0.833769 ,0.540650 ,0.111924};
+static float N057[3] = {-0.953653 ,-0.289939 ,0.080507};
+static float N058[3] = {-0.672357 ,-0.730524 ,0.119461};
+static float N059[3] = {0.522249 ,-0.846652 ,0.102157};
+static float N060[3] = {0.885868 ,-0.427631 ,0.179914};
+static float N062[3] = {0.648942 ,0.743116 ,0.163255};
+static float N063[3] = {-0.578967 ,0.807730 ,0.111219};
+static float N065[3] = {-0.909864 ,-0.352202 ,0.219321};
+static float N066[3] = {-0.502541 ,-0.818090 ,0.279610};
+static float N067[3] = {0.322919 ,-0.915358 ,0.240504};
+static float N068[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N069[3] = {0.000000 ,1.000000 ,0.000000};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N072[3] = {0.000000 ,1.000000 ,0.000000};
+static float N073[3] = {0.000000 ,1.000000 ,0.000000};
+static float N074[3] = {0.000000 ,1.000000 ,0.000000};
+static float N075[3] = {0.031220 ,0.999025 ,-0.031220};
+static float N076[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {0.446821 ,0.893642 ,0.041889};
+static float N078[3] = {0.863035 ,-0.100980 ,0.494949};
+static float N079[3] = {0.585597 ,-0.808215 ,0.062174};
+static float N080[3] = {0.000000 ,1.000000 ,0.000000};
+static float N081[3] = {1.000000 ,0.000000 ,0.000000};
+static float N082[3] = {0.000000 ,1.000000 ,0.000000};
+static float N083[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N084[3] = {-0.478893 ,0.837129 ,-0.264343};
+static float N085[3] = {0.000000 ,1.000000 ,0.000000};
+static float N086[3] = {0.763909 ,0.539455 ,-0.354163};
+static float N087[3] = {0.446821 ,0.893642 ,0.041889};
+static float N088[3] = {0.385134 ,-0.908288 ,0.163352};
+static float N089[3] = {-0.605952 ,0.779253 ,-0.159961};
+static float N090[3] = {0.000000 ,1.000000 ,0.000000};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N096[3] = {0.644444 ,-0.621516 ,0.445433};
+static float N097[3] = {-0.760896 ,-0.474416 ,0.442681};
+static float N098[3] = {0.636888 ,-0.464314 ,0.615456};
+static float N099[3] = {-0.710295 ,0.647038 ,0.277168};
+static float N100[3] = {0.009604 ,0.993655 ,0.112063};
+static float iP001[3] = {18.74, 13.19, 3.76};
+static float P001[3] = {18.74, 13.19, 3.76};
+static float P002[3] = {0.00, 390.42, 10292.57};
+static float P003[3] = {55.80, 622.31, 8254.35};
+static float P004[3] = {20.80, 247.66, 10652.13};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 199.04, 9353.01};
+static float P008[3] = {-34.67, 247.64, 10663.71};
+static float iP009[3] = {97.46, 67.63, 593.82};
+static float iP010[3] = {-84.33, 67.63, 588.18};
+static float iP011[3] = {118.69, 8.98, -66.91};
+static float P009[3] = {97.46, 67.63, 593.82};
+static float P010[3] = {-84.33, 67.63, 588.18};
+static float P011[3] = {118.69, 8.98, -66.91};
+static float iP012[3] = {156.48, -31.95, 924.54};
+static float iP013[3] = {162.00, 110.22, 924.54};
+static float iP014[3] = {88.16, 221.65, 924.54};
+static float iP015[3] = {-65.21, 231.16, 924.54};
+static float iP016[3] = {-156.48, 121.97, 924.54};
+static float iP017[3] = {-162.00, -23.93, 924.54};
+static float iP018[3] = {-88.16, -139.10, 924.54};
+static float iP019[3] = {65.21, -148.61, 924.54};
+static float iP020[3] = {246.87, -98.73, 1783.04};
+static float iP021[3] = {253.17, 127.76, 1783.04};
+static float iP022[3] = {132.34, 270.77, 1783.04};
+static float iP023[3] = {-97.88, 285.04, 1783.04};
+static float iP024[3] = {-222.97, 139.80, 1783.04};
+static float iP025[3] = {-225.29, -86.68, 1783.04};
+static float iP026[3] = {-108.44, -224.15, 1783.04};
+static float iP027[3] = {97.88, -221.56, 1783.04};
+static float iP028[3] = {410.55, -200.66, 3213.87};
+static float iP029[3] = {432.19, 148.42, 3213.87};
+static float iP030[3] = {200.66, 410.55, 3213.87};
+static float iP031[3] = {-148.42, 432.19, 3213.87};
+static float iP032[3] = {-407.48, 171.88, 3213.87};
+static float iP033[3] = {-432.19, -148.42, 3213.87};
+static float iP034[3] = {-148.88, -309.74, 3213.87};
+static float iP035[3] = {156.38, -320.17, 3213.87};
+static float iP036[3] = {523.39, -303.81, 4424.57};
+static float iP037[3] = {574.66, 276.84, 4424.57};
+static float iP038[3] = {243.05, 492.50, 4424.57};
+static float iP039[3] = {-191.23, 520.13, 4424.57};
+static float iP040[3] = {-523.39, 304.01, 4424.57};
+static float iP041[3] = {-574.66, -231.83, 4424.57};
+static float iP042[3] = {-266.95, -578.17, 4424.57};
+static float iP043[3] = {211.14, -579.67, 4424.57};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 5943.46};
+static float iP046[3] = {371.29, 614.13, 5943.46};
+static float iP047[3] = {-291.43, 621.86, 5943.46};
+static float iP048[3] = {-784.13, 362.60, 5943.46};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P012[3] = {156.48, -31.95, 924.54};
+static float P013[3] = {162.00, 110.22, 924.54};
+static float P014[3] = {88.16, 221.65, 924.54};
+static float P015[3] = {-65.21, 231.16, 924.54};
+static float P016[3] = {-156.48, 121.97, 924.54};
+static float P017[3] = {-162.00, -23.93, 924.54};
+static float P018[3] = {-88.16, -139.10, 924.54};
+static float P019[3] = {65.21, -148.61, 924.54};
+static float P020[3] = {246.87, -98.73, 1783.04};
+static float P021[3] = {253.17, 127.76, 1783.04};
+static float P022[3] = {132.34, 270.77, 1783.04};
+static float P023[3] = {-97.88, 285.04, 1783.04};
+static float P024[3] = {-222.97, 139.80, 1783.04};
+static float P025[3] = {-225.29, -86.68, 1783.04};
+static float P026[3] = {-108.44, -224.15, 1783.04};
+static float P027[3] = {97.88, -221.56, 1783.04};
+static float P028[3] = {410.55, -200.66, 3213.87};
+static float P029[3] = {432.19, 148.42, 3213.87};
+static float P030[3] = {200.66, 410.55, 3213.87};
+static float P031[3] = {-148.42, 432.19, 3213.87};
+static float P032[3] = {-407.48, 171.88, 3213.87};
+static float P033[3] = {-432.19, -148.42, 3213.87};
+static float P034[3] = {-148.88, -309.74, 3213.87};
+static float P035[3] = {156.38, -320.17, 3213.87};
+static float P036[3] = {523.39, -303.81, 4424.57};
+static float P037[3] = {574.66, 276.84, 4424.57};
+static float P038[3] = {243.05, 492.50, 4424.57};
+static float P039[3] = {-191.23, 520.13, 4424.57};
+static float P040[3] = {-523.39, 304.01, 4424.57};
+static float P041[3] = {-574.66, -231.83, 4424.57};
+static float P042[3] = {-266.95, -578.17, 4424.57};
+static float P043[3] = {211.14, -579.67, 4424.57};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 5943.46};
+static float P046[3] = {371.29, 614.13, 5943.46};
+static float P047[3] = {-291.43, 621.86, 5943.46};
+static float P048[3] = {-784.13, 362.60, 5943.46};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -332.24, 7902.59};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {321.55, 558.53, 7902.59};
+static float P055[3] = {-260.54, 559.84, 7902.59};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 438.98, 9364.77};
+static float P063[3] = {-165.71, 441.27, 9355.44};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -504.03, 9355.44};
+static float iP068[3] = {-112.44, 9.25, -64.42};
+static float iP069[3] = {1155.63, 0.00, -182.46};
+static float iP070[3] = {-1143.13, 0.00, -181.54};
+static float iP071[3] = {1424.23, 0.00, -322.09};
+static float iP072[3] = {-1368.01, 0.00, -310.38};
+static float iP073[3] = {1255.57, 2.31, 114.05};
+static float iP074[3] = {-1149.38, 0.00, 117.12};
+static float iP075[3] = {718.36, 0.00, 433.36};
+static float iP076[3] = {-655.90, 0.00, 433.36};
+static float P068[3] = {-112.44, 9.25, -64.42};
+static float P069[3] = {1155.63, 0.00, -182.46};
+static float P070[3] = {-1143.13, 0.00, -181.54};
+static float P071[3] = {1424.23, 0.00, -322.09};
+static float P072[3] = {-1368.01, 0.00, -310.38};
+static float P073[3] = {1255.57, 2.31, 114.05};
+static float P074[3] = {-1149.38, 0.00, 117.12};
+static float P075[3] = {718.36, 0.00, 433.36};
+static float P076[3] = {-655.90, 0.00, 433.36};
+static float P077[3] = {1058.00, -2.66, 7923.51};
+static float P078[3] = {-1016.51, -15.47, 7902.87};
+static float P079[3] = {-1363.99, -484.50, 7593.38};
+static float P080[3] = {1478.09, -861.47, 7098.12};
+static float P081[3] = {1338.06, -284.68, 7024.15};
+static float P082[3] = {-1545.51, -860.64, 7106.60};
+static float P083[3] = {1063.19, -70.46, 7466.60};
+static float P084[3] = {-1369.18, -288.11, 7015.34};
+static float P085[3] = {1348.44, -482.50, 7591.41};
+static float P086[3] = {-1015.45, -96.80, 7474.86};
+static float P087[3] = {731.04, 148.38, 7682.58};
+static float P088[3] = {-697.03, 151.82, 7668.81};
+static float P089[3] = {-686.82, 157.09, 7922.29};
+static float P090[3] = {724.73, 147.75, 7931.39};
+static float iP091[3] = {0.00, 327.10, 2346.55};
+static float iP092[3] = {0.00, 552.28, 2311.31};
+static float iP093[3] = {0.00, 721.16, 2166.41};
+static float iP094[3] = {0.00, 693.42, 2388.80};
+static float iP095[3] = {0.00, 389.44, 2859.97};
+static float P091[3] = {0.00, 327.10, 2346.55};
+static float P092[3] = {0.00, 552.28, 2311.31};
+static float P093[3] = {0.00, 721.16, 2166.41};
+static float P094[3] = {0.00, 693.42, 2388.80};
+static float P095[3] = {0.00, 389.44, 2859.97};
+static float iP096[3] = {222.02, -183.67, 10266.89};
+static float iP097[3] = {-128.90, -182.70, 10266.89};
+static float iP098[3] = {41.04, 88.31, 10659.36};
+static float iP099[3] = {-48.73, 88.30, 10659.36};
+static float P096[3] = {222.02, -183.67, 10266.89};
+static float P097[3] = {-128.90, -182.70, 10266.89};
+static float P098[3] = {41.04, 88.31, 10659.36};
+static float P099[3] = {-48.73, 88.30, 10659.36};
+static float P100[3] = {0.00, 603.42, 9340.68};
+static float P104[3] = {-9.86, 567.62, 7858.65};
+static float P105[3] = {31.96, 565.27, 7908.46};
+static float P106[3] = {22.75, 568.13, 7782.83};
+static float P107[3] = {58.93, 568.42, 7775.94};
+static float P108[3] = {55.91, 565.59, 7905.86};
+static float P109[3] = {99.21, 566.00, 7858.65};
+static float P110[3] = {-498.83, 148.14, 9135.10};
+static float P111[3] = {-495.46, 133.24, 9158.48};
+static float P112[3] = {-490.82, 146.23, 9182.76};
+static float P113[3] = {-489.55, 174.11, 9183.66};
+static float P114[3] = {-492.92, 189.00, 9160.28};
+static float P115[3] = {-497.56, 176.02, 9136.00};
+static float P116[3] = {526.54, 169.68, 9137.70};
+static float P117[3] = {523.49, 184.85, 9161.42};
+static float P118[3] = {518.56, 171.78, 9186.06};
+static float P119[3] = {516.68, 143.53, 9186.98};
+static float P120[3] = {519.73, 128.36, 9163.26};
+static float P121[3] = {524.66, 141.43, 9138.62};
+/* *INDENT-ON* */
+
+void
+Whale001(void)
+{
+
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Whale002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Whale003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Whale004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Whale005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Whale006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Whale007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Whale008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Whale009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Whale010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Whale011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Whale012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+}
+
+void
+Whale013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P005);
+    glVertex3fv(P006);
+    glVertex3fv(P099);
+    glVertex3fv(P098);
+    glEnd();
+}
+
+void
+Whale014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P006);
+    glVertex3fv(P005);
+    glVertex3fv(P004);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+}
+
+void
+Whale015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+}
+
+void
+Whale016(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P104);
+    glVertex3fv(P105);
+    glVertex3fv(P106);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P107);
+    glVertex3fv(P108);
+    glVertex3fv(P109);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P110);
+    glVertex3fv(P111);
+    glVertex3fv(P112);
+    glVertex3fv(P113);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P116);
+    glVertex3fv(P117);
+    glVertex3fv(P118);
+    glVertex3fv(P119);
+    glVertex3fv(P120);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+DrawWhale(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch=0.0, thrash, chomp;
+
+
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.5 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.5 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg2 = 3.7 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg3 = 4.8 * thrash * sin((fish->htail + 23.0) * RRAD);
+    seg4 = 6.0 * thrash * sin((fish->htail + 28.0) * RRAD);
+    seg5 = 6.5 * thrash * sin((fish->htail + 35.0) * RRAD);
+    seg6 = 6.5 * thrash * sin((fish->htail + 40.0) * RRAD);
+    seg7 = 6.5 * thrash * sin((fish->htail + 55.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail - 160.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3 * 1.1;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3 * 0.9;
+
+    P099[1] = iP099[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P097[1] = iP097[1] + chomp;
+    P096[1] = iP096[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 8000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+    glScalef(3.0, 3.0, 3.0);
+
+    glEnable(GL_CULL_FACE);
+
+    Whale001();
+    Whale002();
+    Whale003();
+    Whale004();
+    Whale005();
+    Whale006();
+    Whale007();
+    Whale008();
+    Whale009();
+    Whale010();
+    Whale011();
+    Whale012();
+
+
+
+    Whale013();
+
+    Whale014();
+
+    Whale015();
+
+    Whale016();
+
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis-mpi/GO
===================================================================
--- trunk/src/testing/app/atlantis-mpi/GO	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/GO	(revision 4)
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+## fs.conf
+# atlantis-mpi 1200 600
+# syncMaster 10.0.8.113
+# 3
+# 10.0.8.113 0.0000 0.3333 0.0 1.0
+# 10.0.8.114 0.3333 0.6667 0.0 1.0
+# 10.0.8.117 0.6667 1.0000 0.0 1.0
+##
+
+
+/bin/rm -f .local
+touch .local
+echo "10.0.8.113" >> .local
+echo "10.0.8.114" >> .local
+echo "10.0.8.117" >> .local
+
+mpirun -np 3 -nolocal -machinefile .local atlantis-mpi 512 512
+
+/bin/rm -f .local
+
Index: trunk/src/testing/app/atlantis-mpi/GO-ATLANTIS-MPI
===================================================================
--- trunk/src/testing/app/atlantis-mpi/GO-ATLANTIS-MPI	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/GO-ATLANTIS-MPI	(revision 4)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd /home/evl/bijeong/dev/sage/trunk/app/atlantis-mpi
+mpirun -np $1 -nolocal -machinefile .local atlantis-mpi $2 $3 $4 $5 $6
Index: trunk/src/testing/app/atlantis-mpi/atlantis.h
===================================================================
--- trunk/src/testing/app/atlantis-mpi/atlantis.h	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/atlantis.h	(revision 4)
@@ -0,0 +1,69 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#define RAD 57.295
+#define RRAD 0.01745
+
+#define NUM_SHARKS  75
+#define SHARKSIZE 6000
+#define SHARKSPEED 100.0
+
+#define WHALESPEED 250.0
+
+typedef struct _fishRec {
+    float x, y, z, phi, theta, psi, v;
+    float xt, yt, zt;
+    float htail, vtail;
+    float dtheta;
+    int spurt, attack;
+} fishRec;
+
+extern fishRec sharks[NUM_SHARKS];
+extern fishRec momWhale;
+extern fishRec babyWhale;
+extern fishRec dolph;
+
+extern void FishTransform(fishRec *);
+extern void WhalePilot(fishRec *);
+extern void SharkPilot(fishRec *);
+extern void SharkMiss(int);
+extern void DrawWhale(fishRec *);
+extern void DrawShark(fishRec *);
+extern void DrawDolphin(fishRec *);
+
+#ifdef WINDOWS
+#pragma warning(disable:4305 4101)
+#endif
Index: trunk/src/testing/app/atlantis-mpi/atlantis-mpi.conf
===================================================================
--- trunk/src/testing/app/atlantis-mpi/atlantis-mpi.conf	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/atlantis-mpi.conf	(revision 4)
@@ -0,0 +1,13 @@
+masterIP 10.0.8.131
+nwID     1
+msgPort  23020
+syncPort 13020
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+winX 100
+winY 100
+winWidth 4000
+winHeight 4000
+nwProtocol UDP
+asyncUpdate false
Index: trunk/src/testing/app/atlantis-mpi/fsManager.conf
===================================================================
--- trunk/src/testing/app/atlantis-mpi/fsManager.conf	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/fsManager.conf	(revision 4)
@@ -0,0 +1,16 @@
+fsManager   yorda 10.0.8.120 131.193.78.203
+systemPort  30002
+uiPort      30001
+trackPort   30003
+conManager  131.193.78.203 15556
+
+tileConfiguration stdtile-20.conf
+receiverSyncPort  12000
+receiverStreamPort   22000
+receiverBufSize    100
+fullScreen     1
+winTime		500
+
+rcvNwBufSize 16000000
+sendNwBufSize 16000000
+MTU 1450
Index: trunk/src/testing/app/atlantis-mpi/.local
===================================================================
--- trunk/src/testing/app/atlantis-mpi/.local	(revision 4)
+++ trunk/src/testing/app/atlantis-mpi/.local	(revision 4)
@@ -0,0 +1,10 @@
+yorda11-10
+yorda12-10
+yorda14-10
+yorda15-10
+yorda16-10
+yorda17-10
+yorda18-10
+yorda19-10
+yorda20-10
+yorda13-10
Index: trunk/src/testing/app/gl/Makefile.32
===================================================================
--- trunk/src/testing/app/gl/Makefile.32	(revision 4)
+++ trunk/src/testing/app/gl/Makefile.32	(revision 4)
@@ -0,0 +1,16 @@
+PROGRAM = libmyGL32.so
+
+CXX=g++ -m32 -Wno-deprecated
+CXXFLAGS= -I../../include
+
+FILES = gl.o
+
+$(PROGRAM): $(FILES)
+	$(CXX) -shared -o $(PROGRAM) $(FILES) -ldl -lc -L../../lib -lsail
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+	cp $(PROGRAM) ../../lib
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/gl/RUN.mac
===================================================================
--- trunk/src/testing/app/gl/RUN.mac	(revision 4)
+++ trunk/src/testing/app/gl/RUN.mac	(revision 4)
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+#export SAGE_GL_WIDTH=800
+#export SAGE_GL_HEIGHT=600
+
+## For Mac
+export DYLD_INSERT_LIBRARIES=libmyGL.dylib
+export DYLD_FORCE_FLAT_NAMESPACE=1
+export DYLD_LIBRARY_PATH=.:../../lib
+
+$*
+
+export -n LD_PRELOAD
+
+
+
Index: trunk/src/testing/app/gl/gl.cpp
===================================================================
--- trunk/src/testing/app/gl/gl.cpp	(revision 4)
+++ trunk/src/testing/app/gl/gl.cpp	(revision 4)
@@ -0,0 +1,363 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/Xatom.h>
+
+
+#if defined(__APPLE__)
+//#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+//#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+#include <GL/glx.h>
+
+
+#define SAGE2 1
+
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+int winWidth, winHeight;
+int maxwinWidth, maxwinHeight;
+GLubyte *rgbBuffer  = NULL;
+GLubyte *rgbBuffer2 = NULL;
+sail sageInf; // sail object
+
+typedef void (*glXSwapBuffersFunc_t) (Display*, GLXDrawable);
+typedef void (*glViewportFunc_t) (GLint, GLint, GLsizei, GLsizei);
+typedef void (*glFlushFunc_t) (void);
+typedef void (*glFinishFunc_t) (void);
+
+static glXSwapBuffersFunc_t funcswap = NULL;
+static glViewportFunc_t     funcviewport = NULL;
+static glFlushFunc_t        funcflush = NULL;
+static glFinishFunc_t       funcfinish = NULL;
+
+static int count = 0;
+
+void InitTrap()
+{
+    void *result;
+    void* handle;
+
+#if defined(SAGE2)
+        // SAGE Configuration
+    sageRect renderImageMap;
+    sailConfig scfg;
+
+    scfg.init("gl.conf");
+    scfg.setAppName("gl");
+    scfg.rank = 0;
+
+	scfg.resX = maxwinWidth;
+	scfg.resY = maxwinHeight;
+
+        // set the window size to double the movie size
+    scfg.winWidth = scfg.resX*2;
+    scfg.winHeight = scfg.resY*2;
+
+    renderImageMap.left = 0.0;
+    renderImageMap.right = 1.0;
+    renderImageMap.bottom = 0.0;
+    renderImageMap.top = 1.0;
+
+	scfg.imageMap = renderImageMap;
+	scfg.pixFmt = PIXFMT_8888;
+	scfg.rowOrd = BOTTOM_TO_TOP;
+
+	sageInf.init(scfg);
+#else
+
+
+        // Init SAGE
+    sageRect glImageMap;
+    glImageMap.left = 0.0;
+    glImageMap.right = 1.0;
+    glImageMap.bottom = 0.0;
+    glImageMap.top = 1.0;
+
+    sailConfig scfg;
+    scfg.cfgFile = strdup("sage.conf");
+    scfg.appName = strdup("gl");
+    scfg.rank = 0;
+    scfg.execConfig = NULL;
+    scfg.ip = NULL;
+
+    scfg.resX = maxwinWidth;
+    scfg.resY = maxwinHeight;
+    scfg.imageMap = glImageMap;
+    scfg.colorDepth = 32;
+    scfg.pixFmt = TVPIXFMT_8888;
+    scfg.rowOrd = BOTTOM_TO_TOP;
+
+    sageInf.init(scfg);
+#endif
+
+    fprintf(stderr, "GL> sail initialized\n");
+
+        // Get function symbols
+#if defined(__APPLE__)
+    if ( ! (handle =  dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",RTLD_NOW)) )
+#else
+            //if ( ! (handle =  dlopen("/usr/lib/tls/libGL.so.1",RTLD_NOW)) )
+            //if ( ! (handle =  dlopen("/usr/lib64/libGL.so.1",RTLD_NOW)) )
+        char *gllib = getenv("SAGE_GL");
+    if (gllib == NULL)
+        gllib = strdup("/usr/lib64/libGL.so.1");
+
+    fprintf(stderr, "GL> Using [%s] OpenGL library\n", gllib);
+
+    if ( ! (handle =  dlopen(gllib,RTLD_NOW)) )
+    {
+        fprintf(stderr, "GL> Error opening libGL\n");
+        exit(0);
+    }
+#endif
+
+    if ( ! (result = dlsym(handle,"glXSwapBuffers")) )
+    {
+        fprintf(stderr, "GL> Error getting symbol glXSwapBuffers\n");
+        exit(0);
+    }
+    else
+        funcswap     = (glXSwapBuffersFunc_t)result;
+
+    if ( ! (result = dlsym(handle,"glFlush")) )
+    {
+        fprintf(stderr, "GL> Error getting symbol glFlush\n");
+        exit(0);
+    }
+    else
+        funcflush     = (glFlushFunc_t)result;
+
+    if ( ! (result = dlsym(handle,"glFinish")) )
+    {
+        fprintf(stderr, "GL> Error getting symbol glFinish\n");
+        exit(0);
+    }
+    else
+        funcfinish     = (glFinishFunc_t)result;
+
+
+    if ( ! (result = dlsym(handle,"glViewport")) )
+    {
+        fprintf(stderr, "GL> Error getting symbol glViewport\n");
+        exit(0);
+    }
+    else
+        funcviewport = (glViewportFunc_t)result;
+
+        //dlclose(handle);
+
+}
+
+void glFlush(void)
+{
+        // Real call to glFlush
+    if (funcflush) (*funcflush)();
+
+    if (rgbBuffer)
+    {
+        //fprintf(stderr, "GL> GLFlush %d\n", count++);
+
+	glReadBuffer(GL_FRONT);
+
+	if ( (maxwinWidth == winWidth) & (maxwinHeight == winHeight) )
+	{
+#if defined(SAGE2)
+	  rgbBuffer = (unsigned char*)sageInf.getBuffer();
+	  glReadPixels(0, 0, maxwinWidth, maxwinHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer);
+	  sageInf.swapBuffer();
+#else
+	  glReadPixels(0, 0, maxwinWidth, maxwinHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer);
+	  sageInf.swapBuffer((unsigned char *)rgbBuffer);
+#endif
+	}
+	else
+	{
+#if defined(SAGE2)
+        glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer2);
+        rgbBuffer = (unsigned char*)sageInf.getBuffer();
+        memset(rgbBuffer, 0, maxwinWidth*maxwinHeight*4);
+        for (int k=0;k<winHeight;k++)
+	    {
+            memcpy(rgbBuffer+(k*maxwinWidth*4), rgbBuffer2+(k*winWidth*4), winWidth*4);
+	    }
+        sageInf.swapBuffer();
+#else
+	    glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer2);
+	    memset(rgbBuffer, 0, maxwinWidth*maxwinHeight*4);
+	    for (int k=0;k<winHeight;k++)
+	    {
+		memcpy(rgbBuffer+(k*maxwinWidth*4), rgbBuffer2+(k*winWidth*4), winWidth*4);
+	    }
+	    sageInf.swapBuffer((unsigned char *)rgbBuffer);
+#endif
+
+	}
+
+    }
+}
+
+void glFinish(void)
+{
+        // Real call to glFinish
+    if (funcfinish) (*funcfinish)();
+}
+
+void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
+{
+        //fprintf(stderr, "glXSwapBuffers -- rgbBuffer %p\n", rgbBuffer);
+
+#if defined(SAGE2)
+    if (!rgbBuffer2)
+    {
+        maxwinWidth  = DisplayWidth(dpy, DefaultScreen(dpy));
+        maxwinHeight = DisplayHeight(dpy, DefaultScreen(dpy));
+
+        fprintf(stderr, "GL> creating %dx%d buffer\n", maxwinWidth, maxwinHeight);
+
+        rgbBuffer2 = (GLubyte*)malloc(maxwinWidth*maxwinHeight*4);
+        memset(rgbBuffer2, 0, maxwinWidth*maxwinHeight*4);
+
+        InitTrap();
+
+        rgbBuffer = (unsigned char*)sageInf.getBuffer();
+    }
+#else
+    if (!rgbBuffer)
+    {
+        maxwinWidth  = DisplayWidth(dpy, DefaultScreen(dpy));
+        maxwinHeight = DisplayHeight(dpy, DefaultScreen(dpy));
+
+        fprintf(stderr, "GL> creating %dx%d buffer\n", maxwinWidth, maxwinHeight);
+
+        if (rgbBuffer) free(rgbBuffer);
+        rgbBuffer = (GLubyte*)malloc(maxwinWidth*maxwinHeight*4);
+        memset(rgbBuffer, 0, maxwinWidth*maxwinHeight*4);
+        rgbBuffer2 = (GLubyte*)malloc(maxwinWidth*maxwinHeight*4);
+        memset(rgbBuffer2, 0, maxwinWidth*maxwinHeight*4);
+
+        InitTrap();
+    }
+#endif
+
+#if !defined(SAGE2)
+    if (rgbBuffer)
+#endif
+    {
+            //fprintf(stderr, "GL> Reading pixels %dx%d buffer\n", winWidth, winHeight);
+
+	glReadBuffer(GL_BACK);
+
+	if ( (maxwinWidth == winWidth) & (maxwinHeight == winHeight) )
+	{
+#if defined(SAGE2)
+	  rgbBuffer = (unsigned char*)sageInf.getBuffer();
+	  glReadPixels(0, 0, maxwinWidth, maxwinHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer);
+	  sageInf.swapBuffer();
+#else
+	  glReadPixels(0, 0, maxwinWidth, maxwinHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer);
+	  sageInf.swapBuffer((unsigned char *)rgbBuffer);
+#endif
+	}
+	else
+	{
+#if defined(SAGE2)
+	  rgbBuffer = (unsigned char*)sageInf.getBuffer();
+
+	  glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer2);
+	  memset(rgbBuffer, 0, maxwinWidth*maxwinHeight*4);
+	  for (int k=0;k<winHeight;k++)
+	    {
+	      memcpy(rgbBuffer+(k*maxwinWidth*4), rgbBuffer2+(k*winWidth*4), winWidth*4);
+	    }
+
+	  sageInf.swapBuffer();
+#else
+	  glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, rgbBuffer2);
+	  memset(rgbBuffer, 0, maxwinWidth*maxwinHeight*4);
+	  for (int k=0;k<winHeight;k++)
+	    {
+	      memcpy(rgbBuffer+(k*maxwinWidth*4), rgbBuffer2+(k*winWidth*4), winWidth*4);
+	    }
+	  sageInf.swapBuffer((unsigned char *)rgbBuffer);
+#endif
+	}
+
+	count = 0;
+
+        //fprintf(stderr, "GL> Sending pixels\n");
+
+        sageMessage msg;
+         if (sageInf.checkMsg(msg, false) > 0) {
+                 switch (msg.getCode()) {
+                         case APP_QUIT : {
+                                exit(1);
+                                break;
+                         }
+                 }
+         }
+
+    }
+
+        // Real call to glXSwapBuffers
+    if (funcswap) (*funcswap)(dpy,drawable);
+
+}
+
+
+
+void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    fprintf(stderr, "GL> glViewport %d %d %d %d\n", x,y,width,height);
+
+    winWidth = width;
+    winHeight = height;
+
+        // Real call to glViewport
+    if (funcviewport) (*funcviewport)(x,y,width,height);
+}
+
Index: trunk/src/testing/app/gl/RUN
===================================================================
--- trunk/src/testing/app/gl/RUN	(revision 4)
+++ trunk/src/testing/app/gl/RUN	(revision 4)
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+#export SAGE_GL_WIDTH=800
+#export SAGE_GL_HEIGHT=600
+
+export LD_PRELOAD=$SAGE_DIRECTORY/bin/libmyGL.so
+export SAGE_GL=/usr/lib/libGL.so.1
+$*
+export -n LD_PRELOAD
+
+
Index: trunk/src/testing/app/gl/RUN.gl
===================================================================
--- trunk/src/testing/app/gl/RUN.gl	(revision 4)
+++ trunk/src/testing/app/gl/RUN.gl	(revision 4)
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+export LD_PRELOAD=$SAGE_DIRECTORY/bin/libmyGL.so
+export SAGE_GL=/usr/lib64/libGL.so.1
+$*
+export -n LD_PRELOAD
+
+
Index: trunk/src/testing/app/gl/gl.conf
===================================================================
--- trunk/src/testing/app/gl/gl.conf	(revision 4)
+++ trunk/src/testing/app/gl/gl.conf	(revision 4)
@@ -0,0 +1,15 @@
+masterIP 127.0.0.1
+nwID 1
+msgPort 23010
+syncPort 13010
+nodeNum 1
+appID 0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 0
+winY 0
+winWidth 1024
+winHeight 768
+streamType SAGE_BLOCK_HARD_SYNC
+nwProtocol TCP
+asyncUpdate false
Index: trunk/src/testing/app/gl/Makefile.amd64
===================================================================
--- trunk/src/testing/app/gl/Makefile.amd64	(revision 4)
+++ trunk/src/testing/app/gl/Makefile.amd64	(revision 4)
@@ -0,0 +1,16 @@
+PROGRAM = libmyGL.so
+
+CXX=g++ -Wno-deprecated
+CXXFLAGS= -I../../include -fPIC
+
+FILES = gl.o
+
+$(PROGRAM): $(FILES)
+	$(CXX) -shared -o $(PROGRAM) $(FILES) -ldl -lc -L../../lib -lsail
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+	cp $(PROGRAM) ../../lib
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/gl/RUN.gl32
===================================================================
--- trunk/src/testing/app/gl/RUN.gl32	(revision 4)
+++ trunk/src/testing/app/gl/RUN.gl32	(revision 4)
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+export LD_PRELOAD=$SAGE_DIRECTORY/bin/libmyGL.so
+export SAGE_GL=/usr/lib/libGL.so.1
+$*
+export -n LD_PRELOAD
+
+
Index: trunk/src/testing/app/gl/Makefile.mac
===================================================================
--- trunk/src/testing/app/gl/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/gl/Makefile.mac	(revision 4)
@@ -0,0 +1,19 @@
+PROGRAM = libmyGL.dylib
+
+CXX=g++
+CXXFLAGS= -I../../include -O3 -FGLUT -FOpenGL -I/usr/X11R6/include
+
+LDFLAGS= -lm -lpthread -L../../lib -lsail -framework GLUT -framework OpenGL -lobjc -ldl -lstdc++
+
+FILES = gl.o
+
+$(PROGRAM): $(FILES)
+	$(CXX)  -dynamiclib -flat_namespace -undefined suppress -o $(PROGRAM) $(FILES) $(LDFLAGS)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+	cp $(PROGRAM) ../../lib
+
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/bitplay/libimage/name.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/name.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/name.c	(revision 4)
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	isetname and isetcolormap -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	<string.h>
+#include	"image.h"
+
+void isetname( IMAGE *image, char *name )
+{
+    strncpy(image->name,name,80);
+}
+
+void isetcolormap( IMAGE *image, int colormap )
+{
+    image->colormap = colormap;
+}
Index: trunk/src/testing/app/bitplay/libimage/pix.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/pix.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/pix.c	(revision 4)
@@ -0,0 +1,64 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	getpix and putpix -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	"image.h"
+
+#undef getpix
+#undef putpix
+
+IMushort getpix( IMAGE *image )
+{
+    if(--(image)->cnt>=0)
+    	return *(image)->ptr++;
+    else
+	return ifilbuf(image);
+}
+
+IMushort putpix( IMAGE *image, IMushort pix )
+{
+    if(--(image)->cnt>=0)
+        return *(image)->ptr++ = pix;
+    else
+	return iflsbuf(image,pix);
+}
Index: trunk/src/testing/app/bitplay/libimage/flsbuf.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/flsbuf.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/flsbuf.c	(revision 4)
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	iflsbuf -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	"image.h"
+
+int iflsbuf( IMAGE *image, IMushort c )
+{
+	register IMushort *base;
+	register int n, rn;
+	int size;
+
+	if ((image->flags&_IOWRT)==0)
+		return(EOF);
+	if ((base=image->base)==NULL) {
+		size = IBUFSIZE(image->xsize);
+		if ((image->base=base=ibufalloc(image)) == NULL) {
+			i_errhdlr("flsbuf: error on buf alloc\n");
+			return EOF;
+		}
+		rn = n = 0;
+	} else if ((rn = n = image->ptr - base) > 0)  {
+			n = putrow(image,base,image->y,image->z);
+			if(++image->y >= image->ysize) {
+			    image->y = 0;
+			    if(++image->z >= image->zsize) {
+				image->z = image->zsize-1;
+				image->flags |= _IOEOF;
+				return -1;
+			    }
+			}
+ 	}
+	image->cnt = image->xsize-1;
+	*base++ = c;
+	image->ptr = base;
+	if (rn != n) {
+		image->flags |= _IOERR;
+		return(EOF);
+	}
+	return(c);
+}
Index: trunk/src/testing/app/bitplay/libimage/open.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/open.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/open.c	(revision 4)
@@ -0,0 +1,292 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	iopen -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	<stdarg.h>
+#include	<stdlib.h>
+#include	<memory.h>
+#include	<unistd.h>
+#include	<fcntl.h>
+#include	<stdarg.h>
+
+#include	"image.h"
+
+IMAGE *imgopen();
+
+IMAGE *iopen(char *file,
+		register char *mode,
+	       	...)
+{
+    unsigned int type, dim, xsize, ysize, zsize;
+    va_list ap;
+    va_start(ap, mode);
+    type = va_arg(ap, unsigned int);
+    dim  = va_arg(ap, unsigned int);
+    xsize = va_arg(ap, unsigned int);
+    ysize = va_arg(ap, unsigned int);
+    zsize = va_arg(ap, unsigned int);
+    va_end(ap);
+
+    return(imgopen(0, file, mode, type, dim, xsize, ysize, zsize));
+}
+
+IMAGE *fiopen(f, mode, type, dim, xsize, ysize, zsize)
+int f;
+register char *mode;
+unsigned int type, dim, xsize, ysize, zsize;
+{
+    return(imgopen(f, 0, mode, type, dim, xsize, ysize, zsize));
+}
+
+IMAGE *imgopen(f, file, mode, type, dim, xsize, ysize, zsize)
+char *file;
+int f;
+register char *mode;
+unsigned int type, dim, xsize, ysize, zsize;
+{
+	register IMAGE 	*image;
+	extern int errno;
+	register int rw;
+	int tablesize;
+	register int i, max;
+
+	image = (IMAGE*)malloc(sizeof(IMAGE));
+	bzero(image,sizeof(IMAGE));
+	rw = mode[1] == '+';
+	if(rw) {
+	    i_errhdlr("iopen: read/write mode not supported\n");
+		return NULL;
+	}
+	if (*mode=='w') {
+		if (file) {
+		    f = creat(file, 0666);
+		    if (rw && f>=0) {
+			    close(f);
+			    f = open(file, 2);
+		    }
+		}
+		if (f < 0) {
+		    i_errhdlr("iopen: can't open output file %s\n",file);
+		    return NULL;
+		}
+		image->imagic = IMAGIC;
+		image->type = type;
+		image->xsize = xsize;
+		image->ysize = 1;
+		image->zsize = 1;
+		if (dim>1)
+		    image->ysize = ysize;
+		if (dim>2)
+		    image->zsize = zsize;
+		if(image->zsize == 1) {
+		    image->dim = 2;
+		    if(image->ysize == 1)
+			image->dim = 1;
+		} else {
+		    image->dim = 3;
+		}
+		image->min = 10000000;
+		image->max = 0;
+		isetname(image,"no name");
+		image->wastebytes = 0;
+		{
+		    static int one = 1;
+		    /* external format should be big-endian */
+		    image->dorev = (*(char *)&one == 1) ? 1 : 0;
+		}
+		if (write(f,image,sizeof(IMAGE)) != sizeof(IMAGE)) {
+		    i_errhdlr("iopen: error on write of image header\n");
+		    return NULL;
+		}
+	} else {
+		if (file)
+		    f = open(file, rw? 2: 0);
+		if (f < 0)
+		    return(NULL);
+		if (read(f,image,sizeof(IMAGE)) != sizeof(IMAGE)) {
+		    i_errhdlr("iopen: error on read of image header\n");
+		    return NULL;
+		}
+		if( ((image->imagic>>8) | ((image->imagic&0xff)<<8))
+							     == IMAGIC ) {
+		    image->dorev = 1;
+		    cvtimage(image);
+		} else
+		    image->dorev = 0;
+		if (image->imagic != IMAGIC) {
+			i_errhdlr("iopen: bad magic in image file %x\n",image->imagic);
+		    return NULL;
+		}
+	}
+	if (rw)
+	    image->flags = _IORW;
+	else if (*mode != 'r')
+	    image->flags = _IOWRT;
+	else
+	    image->flags = _IOREAD;
+	if(ISRLE(image->type)) {
+	    tablesize = image->ysize*image->zsize*sizeof(IMulong);
+	    image->rowstart = (IMulong *)malloc(tablesize);
+	    image->rowsize = (IMulong *)malloc(tablesize);
+	    if( image->rowstart == 0 || image->rowsize == 0 ) {
+		i_errhdlr("iopen: error on table alloc\n");
+		return NULL;
+	    }
+	    image->rleend = 512L+2*tablesize;
+	    if (*mode=='w') {
+		max = image->ysize*image->zsize;
+		for(i=0; i<max; i++) {
+		    image->rowstart[i] = 0;
+		    image->rowsize[i] = -1;
+		}
+	    } else {
+		tablesize = image->ysize*image->zsize*sizeof(IMulong);
+		lseek(f, 512L, 0);
+		if (read(f,image->rowstart,tablesize) != tablesize) {
+		    i_errhdlr("iopen: error on read of rowstart\n");
+		    return NULL;
+		}
+		if(image->dorev)
+		    cvtlongs(image->rowstart,tablesize);
+		if (read(f,image->rowsize,tablesize) != tablesize) {
+		    i_errhdlr("iopen: error on read of rowsize\n");
+		    return NULL;
+		}
+		if(image->dorev)
+		    cvtlongs(image->rowsize,tablesize);
+	    }
+	}
+	image->cnt = 0;
+	image->ptr = 0;
+	image->base = 0;
+	if( (image->tmpbuf = ibufalloc(image)) == 0 ) {
+	    i_errhdlr("iopen: error on tmpbuf alloc %d\n",image->xsize);
+	    return NULL;
+	}
+	image->x = image->y = image->z = 0;
+	image->file = f;
+	image->offset = 512L;			/* set up for img_optseek */
+	lseek(image->file, 512L, 0);
+	return(image);
+}
+
+IMushort *ibufalloc( IMAGE *image )
+{
+    return (IMushort *)malloc(IBUFSIZE(image->xsize));
+}
+
+int reverse( IMulong lwrd )
+{
+    return ((lwrd>>24) 		|
+	   (lwrd>>8 & 0xff00) 	|
+	   (lwrd<<8 & 0xff0000) |
+	   (lwrd<<24) 		);
+}
+
+void cvtshorts( IMushort *buffer, int nbytes )
+{
+    register short i;
+    register int nshorts = nbytes>>1;
+    register IMushort swrd;
+
+    for(i=0; i<nshorts; i++) {
+	swrd = *buffer;
+	*buffer++ = (swrd>>8) | (swrd<<8);
+    }
+}
+
+void cvtlongs( IMulong *buffer, int nbytes )
+{
+    register short i;
+    register int nlongs = nbytes>>2;
+    register IMulong lwrd;
+
+    for(i=0; i<nlongs; i++) {
+	lwrd = buffer[i];
+	buffer[i] =     ((lwrd>>24) 		|
+	   		(lwrd>>8 & 0xff00) 	|
+	   		(lwrd<<8 & 0xff0000) 	|
+	   		(lwrd<<24) 		);
+    }
+}
+
+void cvtimage( IMAGE *buffer )
+{
+    cvtshorts(&buffer->imagic,12);
+    cvtlongs(&buffer->min,12);
+    cvtlongs(&buffer->colormap,4);
+}
+
+static void (*i_errfunc)();
+
+/*	error handler for the image library.  If the iseterror() routine
+	has been called, sprintf's the args into a string and calls the
+	error function.  Otherwise calls fprintf with the args and then
+	exit.  This allows 'old' programs to assume that no errors
+	ever need be worried about, while programs that know how and
+	want to can handle the errors themselves.  Olson, 11/88
+*/
+void i_errhdlr(char *fmt, ...)	/* most args currently used is 2 */
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	if(i_errfunc) {
+	    char ebuf[2048];	/* be generous; if an error includes a
+		pathname, the maxlen is 1024, so we shouldn't ever
+		overflow this! */
+	    vsprintf(ebuf, fmt, ap);
+	    (*i_errfunc)(ebuf);
+	} else {
+	    vfprintf(stderr, fmt, ap);
+	}
+	va_end(ap);
+	exit(1);
+}
+
+/* this function sets the error handler for i_errhdlr */
+void i_seterror( void (*func)() )
+{
+	i_errfunc = func;
+}
Index: trunk/src/testing/app/bitplay/libimage/rle.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/rle.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/rle.c	(revision 4)
@@ -0,0 +1,207 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	img_getrowsize, img_setrowsize, img_rle_compact, img_rle_expand -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	"image.h"
+
+int img_getrowsize( IMAGE *image )
+{
+    switch(image->dim) {
+	case 1:
+	    return image->rowsize[0];
+	case 2:
+	    return image->rowsize[image->y];
+	case 3:
+	    return image->rowsize[image->y+image->z*image->ysize];
+    }
+    return -1;
+}
+
+void img_setrowsize( IMAGE *image, int cnt, int y, int z )
+{
+    IMulong *sizeptr;
+
+    if(img_badrow(image,y,z))
+	return;
+    switch(image->dim) {
+	case 1:
+	    sizeptr = &image->rowsize[0];
+	    image->rowstart[0] = image->rleend;
+	    break;
+	case 2:
+	    sizeptr = &image->rowsize[y];
+	    image->rowstart[y] = image->rleend;
+	    break;
+	case 3:
+	    sizeptr = &image->rowsize[y+z*image->ysize];
+	    image->rowstart[y+z*image->ysize] = image->rleend;
+	default:
+	    return;
+    }
+    if(*sizeptr != -1)
+	image->wastebytes += *sizeptr;
+    *sizeptr = cnt;
+    image->rleend += cnt;
+}
+
+#define docompact 							\
+	while(iptr<ibufend) {						\
+	    sptr = iptr;						\
+	    iptr += 2;							\
+	    while((iptr<ibufend)&&((iptr[-2]!=iptr[-1])||(iptr[-1]!=iptr[0])))\
+		iptr++;							\
+	    iptr -= 2;							\
+	    count = iptr-sptr;						\
+	    while(count) {						\
+		todo = count>126 ? 126:count; 				\
+		count -= todo;						\
+		*optr++ = 0x80|todo;					\
+		while(todo--)						\
+		    *optr++ = *sptr++;					\
+	    }								\
+	    sptr = iptr;						\
+	    cc = *iptr++;						\
+	    while( (iptr<ibufend) && (*iptr == cc) )			\
+		iptr++;							\
+	    count = iptr-sptr;						\
+	    while(count) {						\
+		todo = count>126 ? 126:count; 				\
+		count -= todo;						\
+		*optr++ = todo;						\
+		*optr++ = cc;						\
+	    }								\
+	}								\
+	*optr++ = 0;
+
+int img_rle_compact( IMushort *expbuf, int ibpp, IMushort *rlebuf, int obpp, int cnt)
+{
+    if(ibpp == 1 && obpp == 1) {
+	register unsigned char *iptr = (unsigned char *)expbuf;
+	register unsigned char *ibufend = iptr+cnt;
+	register unsigned char *sptr;
+	register unsigned char *optr = (unsigned char *)rlebuf;
+	register short todo, cc;
+	register long count;
+
+	docompact;
+	return optr - (unsigned char *)rlebuf;
+    } else if(ibpp == 1 && obpp == 2) {
+	register unsigned char *iptr = (unsigned char *)expbuf;
+	register unsigned char *ibufend = iptr+cnt;
+	register unsigned char *sptr;
+	register unsigned short *optr = rlebuf;
+	register short todo, cc;
+	register long count;
+
+	docompact;
+	return optr - rlebuf;
+    } else if(ibpp == 2 && obpp == 1) {
+	register unsigned short *iptr = expbuf;
+	register unsigned short *ibufend = iptr+cnt;
+	register unsigned short *sptr;
+	register unsigned char *optr = (unsigned char *)rlebuf;
+	register short todo, cc;
+	register long count;
+
+	docompact;
+	return optr - (unsigned char *)rlebuf;
+    } else if(ibpp == 2 && obpp == 2) {
+	register unsigned short *iptr = expbuf;
+	register unsigned short *ibufend = iptr+cnt;
+	register unsigned short *sptr;
+	register unsigned short *optr = rlebuf;
+	register short todo, cc;
+	register long count;
+
+	docompact;
+	return optr - rlebuf;
+    } else  {
+	i_errhdlr("rle_compact: bad bpp: %d %d\n",ibpp,obpp);
+	return 0;
+    }
+}
+
+#define doexpand				\
+	while(1) {				\
+	    pixel = *iptr++;			\
+	    if ( !(count = (pixel & 0x7f)) )	\
+		return;				\
+	    if(pixel & 0x80) {			\
+	       while(count--)			\
+		    *optr++ = *iptr++;		\
+	    } else {				\
+	       pixel = *iptr++;			\
+	       while(count--)			\
+		    *optr++ = pixel;		\
+	    }					\
+	}
+
+void img_rle_expand( IMushort *rlebuf, int ibpp, IMushort *expbuf, int obpp)
+{
+    if(ibpp == 1 && obpp == 1) {
+	register unsigned char *iptr = (unsigned char *)rlebuf;
+	register unsigned char *optr = (unsigned char *)expbuf;
+	register unsigned short pixel,count;
+
+	doexpand;
+    } else if(ibpp == 1 && obpp == 2) {
+	register unsigned char *iptr = (unsigned char *)rlebuf;
+	register unsigned short *optr = expbuf;
+	register unsigned short pixel,count;
+
+	doexpand;
+    } else if(ibpp == 2 && obpp == 1) {
+	register unsigned short *iptr = rlebuf;
+	register unsigned char  *optr = (unsigned char *)expbuf;
+	register unsigned short pixel,count;
+
+	doexpand;
+    } else if(ibpp == 2 && obpp == 2) {
+	register unsigned short *iptr = rlebuf;
+	register unsigned short *optr = expbuf;
+	register unsigned short pixel,count;
+
+	doexpand;
+    } else
+	i_errhdlr("rle_expand: bad bpp: %d %d\n",ibpp,obpp);
+}
Index: trunk/src/testing/app/bitplay/libimage/close.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/close.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/close.c	(revision 4)
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+/*
+ *	iclose and iflush -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	<stdlib.h>
+#include	<unistd.h>
+#include	<fcntl.h>
+#include	"image.h"
+
+int iclose(IMAGE *image)
+{
+    long tablesize;
+
+    iflush(image);
+    img_optseek(image, 0);
+    if (image->flags&_IOWRT) {
+	if(image->dorev)
+	    cvtimage(image);
+	if (img_write(image,(char *)image,sizeof(IMAGE)) != sizeof(IMAGE)) {
+	    i_errhdlr("iflush: error on write of image header\n");
+	    return EOF;
+	}
+	if(image->dorev)
+	    cvtimage(image);
+	if(ISRLE(image->type)) {
+	    img_optseek(image, 512L);
+	    tablesize = image->ysize*image->zsize*sizeof(long);
+	    if(image->dorev)
+		cvtlongs(image->rowstart,tablesize);
+	    if (img_write(image,(char *)image->rowstart,tablesize) != tablesize) {
+		i_errhdlr("iflush: error on write of rowstart\n");
+		return EOF;
+	    }
+	    if(image->dorev)
+		cvtlongs(image->rowsize,tablesize);
+	    if (img_write(image,(char *)image->rowsize,tablesize) != tablesize) {
+		i_errhdlr("iflush: error on write of rowsize\n");
+		return EOF;
+	    }
+	}
+    }
+    if(image->base) {
+	free(image->base);
+	image->base = 0;
+    }
+    if(image->tmpbuf) {
+	free(image->tmpbuf);
+	image->tmpbuf = 0;
+    }
+    if(ISRLE(image->type)) {
+	free(image->rowstart);
+	image->rowstart = 0;
+	free(image->rowsize);
+	image->rowsize = 0;
+    }
+    return(close(image->file));
+}
+
+int iflush(IMAGE *image)
+{
+    IMushort *base;
+
+    if ( (image->flags&_IOWRT)
+     && (base=image->base)!=NULL && (image->ptr-base)>0) {
+	    if (putrow(image, base, image->y,image->z)!=image->xsize) {
+		    image->flags |= _IOERR;
+		    return(EOF);
+	    }
+    }
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/libimage/filbuf.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/filbuf.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/filbuf.c	(revision 4)
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	ifilbuf -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	"image.h"
+
+ifilbuf( IMAGE *image )
+{
+	int size;
+
+	if ((image->flags&_IOREAD) == 0)
+		return(EOF);
+	if (image->base==NULL) {
+		size = IBUFSIZE(image->xsize);
+		if ((image->base = ibufalloc(image)) == NULL) {
+			i_errhdlr("can't alloc image buffer\n");
+			return EOF;
+		}
+	}
+	image->cnt = getrow(image,image->base,image->y,image->z);
+	image->ptr = image->base;
+	if (--image->cnt < 0) {
+		if (image->cnt == -1) {
+			image->flags |= _IOEOF;
+			if (image->flags & _IORW)
+				image->flags &= ~_IOREAD;
+		} else
+			image->flags |= _IOERR;
+		image->cnt = 0;
+		return -1;
+	}
+	if(++image->y >= image->ysize) {
+	    image->y = 0;
+	    if(++image->z >= image->zsize) {
+		image->z = image->zsize-1;
+		image->flags |= _IOEOF;
+		return -1;
+	    }
+	}
+	return *image->ptr++ & 0xffff;
+}
Index: trunk/src/testing/app/bitplay/libimage/image.h
===================================================================
--- trunk/src/testing/app/bitplay/libimage/image.h	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/image.h	(revision 4)
@@ -0,0 +1,229 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States.   Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement.  Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ *	image.h
+ *
+ *	$Revision: 1.2 $
+ *	$Date: 2004/06/25 03:38:23 $
+ */
+
+#ifndef __GL_IMAGE__
+#define __GL_IMAGE__
+
+/*
+ *	Defines for image files . . . .
+ *
+ *  			Paul Haeberli - 1984
+ *
+ *	Brutally hacked into a c++ wrapper by Dave Springer, 1988.
+ *      reworked for C jimh 1991.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>	/* for ushort16 and uint32 */
+
+#ifndef _IOREAD
+#  define _IOREAD 0x01
+#endif
+#ifndef _IOWRT
+#  define _IOWRT  0x02
+#endif
+#ifndef _IORW
+#  define _IORW   0x04
+#endif
+#ifndef _IOEOF
+#  define _IOEOF  0x08
+#endif
+#ifndef _IOERR
+#  define _IOERR  0x10
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef sun
+typedef uint16_t  IMushort;
+typedef uint32_t  IMulong;
+#else
+typedef u_int16_t  IMushort;
+typedef u_int32_t  IMulong;
+#endif
+
+typedef struct {
+    IMushort	imagic;		/* stuff saved on disk . . */
+    IMushort 	type;
+    IMushort 	dim;
+    IMushort 	xsize;
+    IMushort 	ysize;
+    IMushort 	zsize;
+    IMulong 	min;
+    IMulong 	max;
+    IMulong	wastebytes;
+    char	name[80];
+    IMulong	colormap;
+
+    int 	file;		/* stuff used in core only */
+    IMushort 	flags;
+    int16_t	dorev;
+    int16_t	x;
+    int16_t	y;
+    int16_t	z;
+    int16_t	cnt;
+    IMushort	*ptr;
+    IMushort	*base;
+    IMushort	*tmpbuf;
+    IMulong	offset;
+    IMulong	rleend;		/* for rle images */
+    IMulong	*rowstart;	/* for rle images */
+    IMulong	*rowsize;	/* for rle images */
+} IMAGE;
+
+
+typedef struct {
+	IMushort type;
+    	IMulong colormap;
+	int xsize, ysize;
+	IMulong *rowstart;
+	IMulong *rowsize;
+	IMushort *pixels;
+} MEMIMAGE ;
+
+#define IMAGIC 	0732
+
+/* type of the image */
+#define CM_NORMAL		0
+#define CM_DITHERED		1
+#define CM_SCREEN		2
+#define CM_COLORMAP		3
+
+#define TYPEMASK	0xff00
+#define BPPMASK		0x00ff
+#define ITYPE_VERBATIM	0x0000
+#define ITYPE_RLE	0x0100
+#define ISRLE(type)		(((type) & 0xff00) == ITYPE_RLE)
+#define ISVERBATIM(type)	(((type) & 0xff00) == ITYPE_VERBATIM)
+#define BPP(type)		((type) & BPPMASK)
+#define RLE(bpp)		(ITYPE_RLE | (bpp))
+#define VERBATIM(bpp)		(ITYPE_VERBATIM | (bpp))
+#define	IBUFSIZE(pixels)	((pixels+(pixels>>6))<<2)
+#define	RLE_NOP		0x00
+
+#define	ierror(p)	(((p)->flags&_IOERR)!=0)
+#define	ifileno(p)	((p)->file)
+
+#ifdef PIXMACROS
+#define	getpix(p)	(--(p)->cnt>=0? *(p)->ptr++:ifilbuf(p))
+#define putpix(p,x) (--(p)->cnt>=0? ((int)(*(p)->ptr++=(unsigned)(x))):iflsbuf(p,(unsigned)(x)))
+#endif
+
+extern int	iclose(IMAGE* image);
+extern int	iflush(IMAGE* image);
+extern int	ifilbuf(IMAGE* image);
+extern int	iflsbuf(IMAGE* image, IMushort c);
+extern MEMIMAGE	*newimage(int xsize, int ysize, int colormap);
+extern void	freeimage(MEMIMAGE* mimage);
+extern void	drawimage(int xorg, int yorg, MEMIMAGE* mimage);
+extern MEMIMAGE	*readimage(char* name);
+extern MEMIMAGE	*readrleimage(char* name);
+extern void	img_transtoscreen(unsigned short* buf, int n);
+extern void	img_setpixelortho(void);
+extern void	img_makexmap(int colormap);
+extern void	isetname(IMAGE* image, char* name);
+extern void	isetcolormap(IMAGE* image, int colormap);
+extern IMAGE	*iopen(char* file, char* mode, ...);
+/*
+extern IMAGE	*iopen(char* file, char* mode, unsigned int type,
+		       unsigned int dim, unsigned int xsize,
+		       unsigned int ysize, unsigned int zsize);
+*/
+extern IMAGE	*fiopen(int f, char* mode, unsigned int type,
+			unsigned int dim, unsigned int xsize,
+			unsigned int ysize, unsigned int zsize);
+extern IMAGE	*imgopen(int f, char* file, char* mode, unsigned int type,
+			 unsigned int dim, unsigned int xsize,
+			 unsigned int ysize, unsigned int zsize);
+extern unsigned	short* ibufalloc(IMAGE* image);
+extern int	reverse(IMulong lwrd);
+extern void	cvtshorts(IMushort* buffer, int n);
+extern void	cvtlongs(IMulong* buffer, int n);
+extern void	cvtimage(IMAGE *buffer);
+extern IMushort	getpix(IMAGE* image);
+extern IMushort	putpix(IMAGE* image, IMushort pix);
+extern int	img_seek(IMAGE* image, int y, int z);
+extern int	img_write(IMAGE* image, char* buffer, long count);
+extern int	img_read(IMAGE* image, char* buffer, long count);
+extern unsigned	long img_optseek(IMAGE* image, unsigned long offset);
+extern int	img_getrowsize(register IMAGE* image);
+extern void	img_setrowsize(IMAGE* image, int cnt, int y, int z);
+extern int	img_rle_compact(IMushort* expbuf, int ibpp,
+				IMushort* rlebuf, int obpp, int cnt);
+extern void	img_rle_expand(IMushort* rlebuf, int ibpp,
+			       IMushort* expbuf, int obpp);
+extern int	putrow(IMAGE* image, IMushort* buffer, int y, int z);
+extern int	getrow(IMAGE* image, IMushort* buffer, int y, int z);
+
+extern void	i_errhdlr(char *fmt, ...);
+extern int	img_badrow( IMAGE *image, int y, int z );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_IMAGE */
Index: trunk/src/testing/app/bitplay/libimage/row.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/row.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/row.c	(revision 4)
@@ -0,0 +1,238 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	putrow, getrow -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	"image.h"
+
+int putrow( IMAGE *image, IMushort *buffer, int y, int z )
+{
+    register IMushort 	*sptr;
+    register unsigned char      *cptr;
+    register unsigned int x;
+    register IMulong min, max;
+    register int cnt;
+
+    if( !(image->flags & (_IORW|_IOWRT)) )
+	return -1;
+    if(image->dim<3)
+	z = 0;
+    if(image->dim<2)
+	y = 0;
+    if(ISVERBATIM(image->type)) {
+	switch(BPP(image->type)) {
+	    case 1:
+		min = image->min;
+		max = image->max;
+		cptr = (unsigned char *)image->tmpbuf;
+		sptr = buffer;
+		for(x=image->xsize; x--;) {
+		    *cptr = *sptr++;
+		    if (*cptr > max) max = *cptr;
+		    if (*cptr < min) min = *cptr;
+		    cptr++;
+		}
+		image->min = min;
+		image->max = max;
+		img_seek(image,y,z);
+		cnt = image->xsize;
+		if (img_write(image,(char *)image->tmpbuf,cnt) != cnt)
+		    return -1;
+		else
+		    return cnt;
+
+	    case 2:
+		min = image->min;
+		max = image->max;
+		sptr = buffer;
+		for(x=image->xsize; x--;) {
+		    if (*sptr > max) max = *sptr;
+		    if (*sptr < min) min = *sptr;
+		    sptr++;
+		}
+		image->min = min;
+		image->max = max;
+		img_seek(image,y,z);
+		cnt = image->xsize<<1;
+		if(image->dorev)
+		    cvtshorts(buffer,cnt);
+		if (img_write(image,(char *)buffer,cnt) != cnt) {
+		    if(image->dorev)
+			cvtshorts(buffer,cnt);
+		    return -1;
+		} else {
+		    if(image->dorev)
+			cvtshorts(buffer,cnt);
+		    return image->xsize;
+		}
+
+	    default:
+		i_errhdlr("putrow: wierd bpp\n");
+	}
+    } else if(ISRLE(image->type)) {
+	switch(BPP(image->type)) {
+	    case 1:
+		min = image->min;
+		max = image->max;
+		sptr = buffer;
+		for(x=image->xsize; x--;) {
+		    if (*sptr > max) max = *sptr;
+		    if (*sptr < min) min = *sptr;
+		    sptr++;
+		}
+		image->min = min;
+		image->max = max;
+		cnt = img_rle_compact(buffer,2,image->tmpbuf,1,image->xsize);
+		img_setrowsize(image,cnt,y,z);
+		img_seek(image,y,z);
+		if (img_write(image,(char *)image->tmpbuf,cnt) != cnt)
+		    return -1;
+		else
+		    return image->xsize;
+		break;
+
+	    case 2:
+		min = image->min;
+		max = image->max;
+		sptr = buffer;
+		for(x=image->xsize; x--;) {
+		    if (*sptr > max) max = *sptr;
+		    if (*sptr < min) min = *sptr;
+		    sptr++;
+		}
+		image->min = min;
+		image->max = max;
+		cnt = img_rle_compact(buffer,2,image->tmpbuf,2,image->xsize);
+		cnt <<= 1;
+		img_setrowsize(image,cnt,y,z);
+		img_seek(image,y,z);
+		if(image->dorev)
+		    cvtshorts(image->tmpbuf,cnt);
+		if (img_write(image,(char *)image->tmpbuf,cnt) != cnt) {
+		    if(image->dorev)
+			cvtshorts(image->tmpbuf,cnt);
+		    return -1;
+		} else {
+		    if(image->dorev)
+			cvtshorts(image->tmpbuf,cnt);
+		    return image->xsize;
+		}
+		break;
+
+	    default:
+		i_errhdlr("putrow: wierd bpp\n");
+	}
+    } else
+	i_errhdlr("putrow: wierd image type\n");
+    return 0;
+}
+
+int getrow( IMAGE *image, IMushort *buffer, int y, int z )
+{
+    register int i;
+    register unsigned char *cptr;
+    register IMushort *sptr;
+    register int cnt;
+
+    if( !(image->flags & (_IORW|_IOREAD)) )
+	return -1;
+    if(image->dim<3)
+	z = 0;
+    if(image->dim<2)
+	y = 0;
+    img_seek(image, y, z);
+    if(ISVERBATIM(image->type)) {
+	switch(BPP(image->type)) {
+	    case 1:
+		if (img_read(image,(char *)image->tmpbuf,image->xsize)
+							    != image->xsize)
+		    return -1;
+		else {
+		    cptr = (unsigned char *)image->tmpbuf;
+		    sptr = buffer;
+		    for(i=image->xsize; i--;)
+			*sptr++ = *cptr++;
+		}
+		return image->xsize;
+	    case 2:
+		cnt = image->xsize<<1;
+		if (img_read(image,(char *)buffer,cnt) != cnt)
+		    return -1;
+		else {
+		    if(image->dorev)
+			cvtshorts(buffer,cnt);
+		    return image->xsize;
+		}
+	    default:
+		i_errhdlr("getrow: wierd bpp\n");
+		break;
+	}
+    } else if(ISRLE(image->type)) {
+	switch(BPP(image->type)) {
+	    case 1:
+		if( (cnt = img_getrowsize(image)) == -1 )
+		    return -1;
+		if( img_read(image,(char *)image->tmpbuf,cnt) != cnt )
+		    return -1;
+		else {
+		    img_rle_expand(image->tmpbuf,1,buffer,2);
+		    return image->xsize;
+		}
+	    case 2:
+		if( (cnt = img_getrowsize(image)) == -1 )
+		    return -1;
+		if( cnt != img_read(image,(char *)image->tmpbuf,cnt) )
+		    return -1;
+		else {
+		    if(image->dorev)
+			cvtshorts(image->tmpbuf,cnt);
+		    img_rle_expand(image->tmpbuf,2,buffer,2);
+		    return image->xsize;
+		}
+	    default:
+		i_errhdlr("getrow: wierd bpp\n");
+		break;
+	}
+    } else
+	i_errhdlr("getrow: wierd image type\n");
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/libimage/Makefile
===================================================================
--- trunk/src/testing/app/bitplay/libimage/Makefile	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/Makefile	(revision 4)
@@ -0,0 +1,19 @@
+MACHINE=$(shell uname -s)
+ifeq ($(MACHINE), SunOS)
+COPTS = -O2 -xchar=u
+else
+COPTS = -O2 -funsigned-char
+endif
+
+INCL = -I.
+CFLAGS = ${COPTS} ${INCL} 
+OBJS = close.o filbuf.o flsbuf.o name.o open.o pix.o rdwr.o rle.o row.o # dispimg.o
+TARGET = libimage.a
+
+libimage.a:	${OBJS}
+	rm -f $@
+	ar r $@ ${OBJS}
+	ranlib $@
+
+clean:
+	rm -f a.out core *.o ${TARGET}
Index: trunk/src/testing/app/bitplay/libimage/rdwr.c
===================================================================
--- trunk/src/testing/app/bitplay/libimage/rdwr.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimage/rdwr.c	(revision 4)
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ *	img_seek, img_write, img_read, img_optseek -
+ *
+ *				Paul Haeberli - 1984
+ *
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	<unistd.h>
+#include	"image.h"
+
+int img_seek( IMAGE *image, int y, int z )
+{
+    if(img_badrow(image,y,z)) {
+	i_errhdlr("imglib: row number out of range\n");
+	return EOF;
+    }
+    image->x = 0;
+    image->y = y;
+    image->z = z;
+    if(ISVERBATIM(image->type)) {
+	switch(image->dim) {
+	    case 1:
+		return img_optseek(image, 512L);
+	    case 2:
+		return img_optseek(image,512L+(y*image->xsize)*BPP(image->type));
+	    case 3:
+		return img_optseek(image,
+		    512L+(y*image->xsize+z*image->xsize*image->ysize)*
+							BPP(image->type));
+	    default:
+		i_errhdlr("img_seek: wierd dim\n");
+		break;
+	}
+    } else if(ISRLE(image->type)) {
+	switch(image->dim) {
+	    case 1:
+		return img_optseek(image, image->rowstart[0]);
+	    case 2:
+		return img_optseek(image, image->rowstart[y]);
+	    case 3:
+		return img_optseek(image, image->rowstart[y+z*image->ysize]);
+	    default:
+		i_errhdlr("img_seek: wierd dim\n");
+		break;
+	}
+    } else
+	i_errhdlr("img_seek: wierd image type\n");
+    return EOF;
+}
+
+int img_badrow( IMAGE *image, int y, int z )
+{
+    if(y>=image->ysize || z>=image->zsize)
+	return 1;
+    else
+        return 0;
+}
+
+int img_write( IMAGE *image, char *buffer, long count )
+{
+    long retval;
+
+    retval =  write(image->file,buffer,count);
+    if(retval == count)
+	image->offset += count;
+    else
+	image->offset = -1;
+    return retval;
+}
+
+int img_read( IMAGE *image, char *buffer, long count)
+{
+    long retval;
+
+    retval =  read(image->file,buffer,count);
+    if(retval == count)
+	image->offset += count;
+    else
+	image->offset = -1;
+    return retval;
+}
+
+unsigned long img_optseek( IMAGE *image, unsigned long offset )
+{
+    if(image->offset != offset) {
+       image->offset = offset;
+       return lseek(image->file,offset,0);
+   }
+   return offset;
+}
+
Index: trunk/src/testing/app/bitplay/bpio.c
===================================================================
--- trunk/src/testing/app/bitplay/bpio.c	(revision 4)
+++ trunk/src/testing/app/bitplay/bpio.c	(revision 4)
@@ -0,0 +1,447 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#define _GNU_SOURCE	   1		/* for O_DIRECT from <fcntl.h> */
+#define __EXTENSIONS__	   1		/* for directio() in Solaris */
+
+#include "bpio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <memory.h>
+#include <sys/time.h>
+
+extern int verbose;
+
+static bpbuf_t *bpbufinit( bpbuf_t *bpb, bpio_t *bpio, int nbufs )
+{
+    int pagesize = getpagesize();
+    int i, margin, stride;
+    unsigned char *p;
+
+    if(bpb == NULL)
+	bpb = (bpbuf_t *)malloc( sizeof(bpbuf_t) );
+    memset(bpb, 0, sizeof(bpbuf_t));
+
+    bpb->bpio = bpio;
+    pthread_mutex_init( &bpb->bmut, NULL );
+    pthread_cond_init( &bpb->bfillwait, NULL );
+    pthread_cond_init( &bpb->bdrainwait, NULL );
+    bpb->fillwaiting = bpb->drainwaiting = 0;
+    bpb->filepos = 0LL;		/* probably changed later by bpopen() */
+    bpb->wrappos = 0LL;		/* filled in later by bpstart */
+    bpb->eofpos  = 0LL;
+    bpb->wp = bpb->rp = 0;	/* initially empty */
+
+    bpb->bufsize = bpio->bufsize;
+    bpb->readsize = bpio->readsize;
+    stride = (bpb->bufsize + pagesize - 1) & ~(pagesize - 1);
+    bpb->bufspace = (unsigned char *)malloc( pagesize-1 + nbufs*stride );
+
+
+    p = bpb->bufspace;
+    margin = (unsigned long)p & (pagesize - 1);
+    if(margin != 0)
+	p += (pagesize - margin);
+    /* Now p is page-aligned */
+    bpb->bufs = (unsigned char **)malloc( nbufs * sizeof(unsigned char *) );
+    bpb->curpos = (off_t *)malloc( nbufs * sizeof(off_t) );
+    bpb->nbufs = nbufs;
+    for(i = 0; i < nbufs; i++) {
+	bpb->bufs[i] = p + i*stride;
+	bpb->curpos[i] = -1LL;
+    }
+
+    bpb->doloop = 0;
+    bpb->fd = -1;
+    bpb->filling = 0;
+
+    /* Start the thread.  It will realize that filling==0 and go to sleep.
+     */
+    pthread_create( &bpb->bthread, NULL, bpfiller, (void *)bpb );
+
+    return bpb;
+}
+
+void bpforward( bpio_t *bpio, int fwd )
+{
+    int i;
+    off_t incr = (off_t)bpio->bufsize * (fwd * bpio->nfillers);
+
+    if(incr != bpio->bpb[0].incrpos || bpio->fwd != fwd) {
+	off_t here = bptell( bpio );
+
+	for(i = 0; i < bpio->nfillers; i++) {
+	    bpio->bpb[i].incrpos = incr;
+	}
+	bpio->fwd = fwd;
+	bpseek( bpio, here );
+    }
+
+}
+
+bpio_t *bpinit( bpio_t *bpio, int nfillers, int bufsize, int readsize, int nbufseach )
+{
+    int i;
+
+    if(bpio == NULL)
+	bpio = (bpio_t *)malloc( sizeof(bpio_t) );
+    memset(bpio, 0, sizeof(bpio_t));
+    bpio->nfillers = nfillers;
+    bpio->bufsize = bufsize;
+    bpio->readsize = readsize;
+    bpio->bpb = (bpbuf_t *)malloc( nfillers * sizeof(bpbuf_t) );
+    for(i = 0; i < nfillers; i++)
+	bpbufinit( &bpio->bpb[i], bpio, nbufseach );
+    bpforward( bpio, 1 );
+    return bpio;
+}
+
+int bpbempty( bpbuf_t *bpb )
+{
+    return bpb->wp == bpb->rp;
+}
+
+int bpbfull( bpbuf_t *bpb )
+{
+    return (bpb->wp+1) % bpb->nbufs == bpb->rp;
+}
+
+void bpbstop( bpbuf_t *bpb )
+{
+    bpb->filling = 0;
+    if(bpb->fillwaiting)
+	pthread_cond_signal( &bpb->bfillwait );
+    if(bpb->drainwaiting)
+	pthread_cond_signal( &bpb->bdrainwait );
+}
+
+/* file-reader (bpb-queue-filler) thread */
+void *bpfiller( void *vbpb )
+{
+    bpbuf_t *bpb = (bpbuf_t *)vbpb;
+    int want;
+    unsigned char *p;
+    off_t filepos;
+    int normaleof;
+
+    pthread_mutex_lock( &bpb->bmut );
+
+    for(;;) {
+
+	/* Can we run now? */
+	while(!bpb->filling || bpbfull(bpb)) {
+	    /* No, sleep until told to start and have room to put data */
+	    bpb->fillwaiting = 1;
+	    bpb->busy = 0;
+	    pthread_cond_wait( &bpb->bfillwait, &bpb->bmut );
+	    bpb->fillwaiting = 0;
+	}
+
+
+	/* Now we fill bpb->bufs[ bpb->rp ] */
+	/* It's all ours now, so run unlocked */
+
+	want = bpb->bufsize;
+	p = bpb->bufs[ bpb->rp ];
+
+	if(bpb->filepos >= bpb->eofpos) {
+	    if(!bpb->doloop || bpb->wrappos >= bpb->eofpos) {
+		bpb->filling = 0;
+	    } else {
+		/* Going forwards beyond EOF, need to wrap backwards */
+		bpb->filepos = bpb->wrappos + (bpb->filepos - bpb->eofpos);
+	    }
+
+	} else if(bpb->filepos < bpb->wrappos) {
+	    if(!bpb->doloop || bpb->wrappos >= bpb->eofpos) {
+		bpb->filling = 0;
+	    } else {
+		/* Going backwards, need to wrap forwards */
+		bpb->filepos = bpb->eofpos + (bpb->filepos - bpb->wrappos);
+	    }
+	}
+
+	if(bpb->filepos <0||verbose>=3)
+	    printf("T%02d r%02d w%02d: rpos %02lld -> %lld\n",
+		(int) (bpb - bpb->bpio->bpb), bpb->rp, bpb->wp,
+		(long long)(bpb->filepos / bpb->bufsize), (long long)bpb->filepos);
+
+
+	bpb->curpos[ bpb->rp ] = bpb->filepos;
+	filepos = bpb->filepos;
+	bpb->filepos += bpb->incrpos;
+	bpb->busy = 1;
+
+	pthread_mutex_unlock( &bpb->bmut );
+
+	lseek( bpb->fd, filepos, 0 );
+
+	normaleof = 0;
+	while(want > 0 && bpb->filling) {
+	    int now = want < bpb->readsize ? want : bpb->readsize;
+	    int got = read( bpb->fd, p, now );
+	    if(got < 0 && errno == EINTR)
+		continue;
+	    if(got <= 0) {
+		/* 0-fill remainder of this buffer and stop reading. */
+		memset(p, 0, want);
+		bpbstop( bpb );
+		if(got == 0) normaleof = 1;
+		break;
+
+	    } else {
+		want -= got;
+		p += got;
+	    }
+	}
+
+	pthread_mutex_lock( &bpb->bmut );
+
+	if(bpb->filling || normaleof) {
+	    bpb->rp = (bpb->rp + 1) % bpb->nbufs;
+	} else {
+	    bpb->curpos[ bpb->rp] = -1LL;	/* mark buffer as invalid */
+	    bpb->busy = 0;
+	}
+
+	if(bpb->drainwaiting)	/* is drainer waiting for data? */
+	    pthread_cond_signal( &bpb->bdrainwait );
+    }
+
+    /* In case anyone ever 'break's from above loop */
+    pthread_mutex_unlock( &bpb->bmut );
+    return NULL;
+}
+
+void bpclose( bpio_t *bpio )
+{
+    int i;
+
+    for(i = 0; i < bpio->nfillers; i++) {
+	bpbuf_t *bpb = &bpio->bpb[i];
+	bpbstop( bpb );
+	if(bpb->fd >= 0) {
+	    close(bpb->fd);
+	    bpb->fd = -1;
+	}
+    }
+}
+
+/*
+ * bpopen() opens a file across a collection of buffers.
+ */
+int bpopen( bpio_t *bpio, char *fname )
+{
+    int i;
+
+    bpclose( bpio );
+    for(i = 0; i < bpio->nfillers; i++) {
+	bpbuf_t *bpb = &bpio->bpb[i];
+#if defined(O_DIRECT) && !USE_NODIRECT
+	bpb->fd = open(fname, O_RDONLY | O_DIRECT);	/* try direct I/O if available */
+#else
+	bpb->fd = open(fname, O_RDONLY);
+#endif
+	if(bpb->fd < 0) {
+	    perror(fname);
+	    return -1;
+	}
+	/* Request direct I/O in Solaris' way too, but don't worry if we can't */
+#ifdef DIRECTIO_ON
+	directio( bpb->fd, DIRECTIO_ON );
+#endif
+
+    }
+    bprange( bpio, (off_t) 0, (off_t) lseek( bpio->bpb[0].fd, 0, SEEK_END ) );
+    bpseek( bpio, (off_t) 0 );
+    return 0;
+}
+
+/* return pointer to current buffer */
+unsigned char *bpcurbuf( bpio_t *bpio )
+{
+    bpbuf_t *bpb;
+    if(bpio == NULL || (unsigned int)bpio->drain >= bpio->nfillers)
+	return NULL;
+    bpb = &bpio->bpb[ bpio->drain ];
+    if(bpbempty(bpb) || bpb->bufs == NULL)
+	return NULL;
+    return bpb->bufs[ bpb->wp ];
+}
+
+/* Return file offset of current (drain'th) buffer. */
+/* Can be -1 if not read yet. */
+off_t bptell( bpio_t *bpio )
+{
+    bpbuf_t *bpb = &bpio->bpb[ bpio->drain ];
+    return bpb->curpos[ bpb->wp ];
+}
+
+void bpseek( bpio_t *bpio, off_t pos )
+{
+    int i, b;
+
+    if(verbose >= 3) printf("S %02lld -> %lld\n", (long long)(pos / bpio->bufsize), (long long)pos);
+
+    bpstop( bpio );
+    bpsync( bpio );		/* wait until all is stable */
+
+    bpio->drain = 0;		/* next-to-drain is first reader */
+    for(i = 0; i < bpio->nfillers; i++) {
+	bpbuf_t *bpb = &bpio->bpb[i];
+
+	pthread_mutex_lock( &bpb->bmut );
+
+	bpbstop( bpb );
+
+	bpb->rp = bpb->wp = 0;
+	for(b = 0; b < bpb->nbufs; b++)
+	    bpb->curpos[b] = -1LL;
+
+	bpb->filepos = pos + bpio->bufsize * (bpio->fwd * i);
+
+	if(bpb->eofpos > bpb->wrappos) {
+	    while(bpb->filepos > bpb->eofpos)
+		bpb->filepos -= bpb->eofpos - bpb->wrappos;
+	    while(bpb->filepos < bpb->wrappos)
+		bpb->filepos += bpb->eofpos - bpb->wrappos;
+	}
+
+	/* we changed buffer pointers -- awaken any sleepers */
+	if(bpb->drainwaiting)
+	    pthread_cond_signal( &bpb->bdrainwait );
+	if(bpb->fillwaiting)
+	    pthread_cond_signal( &bpb->bfillwait );
+
+	pthread_mutex_unlock( &bpb->bmut );
+    }
+}
+
+void bprange( bpio_t *bpio, off_t from, off_t to )
+{
+    int i;
+    for(i = 0; i < bpio->nfillers; i++) {
+	bpbuf_t *bpb = &bpio->bpb[i];
+	if(from != -1LL) bpb->wrappos = from;
+	if(to != -1LL) bpb->eofpos = to;
+	bpbstop( bpb );
+    }
+}
+
+void bpstart( bpio_t *bpio, int wrap )
+{
+    int i;
+
+    for(i = 0; i < bpio->nfillers; i++) {
+	bpbuf_t *bpb = &bpio->bpb[i];
+	bpb->doloop = wrap;
+	bpb->filling = 1;
+	if(bpb->fillwaiting)
+	    pthread_cond_signal( &bpb->bfillwait );
+    }
+}
+
+/*
+ * If we're supposed to be stopped,
+ * wait until all filler threads have noticed that.
+ */
+void bpsync( bpio_t *bpio )
+{
+    int i, some;
+    int around = 0;
+
+    do {
+	some = 0;
+	for(i = 0; i < bpio->nfillers; i++) {
+	    bpbuf_t *bpb = &bpio->bpb[i];
+	    pthread_mutex_lock( &bpb->bmut );
+	    if(!bpb->filling && bpb->busy)
+		some = 1;
+	    pthread_mutex_unlock( &bpb->bmut );
+	}
+	if(some)
+	    usleep(50000);
+	around += some;
+    } while(some);
+    if(verbose>=2) printf("sync %d\n", around);
+}
+
+void bpstop( bpio_t *bpio )
+{
+    int i;
+    for(i = 0; i < bpio->nfillers; i++)
+	bpbstop( &bpio->bpb[i] );
+}
+
+
+int bpdrain( bpio_t *bpio, int (*sink)( unsigned char *, int, void * ), void *arg )
+{
+    int status;
+
+    for(;;) {
+	bpbuf_t *bpb = &bpio->bpb[ bpio->drain ];
+
+	if(!bpb->filling)	/* if EOF or bpstop() or etc. */
+	    break;
+
+	pthread_mutex_lock( &bpb->bmut );
+	while(bpbempty( bpb )) {
+	    bpb->drainwaiting = 1;
+	    pthread_cond_wait( &bpb->bdrainwait, &bpb->bmut );
+	    bpb->drainwaiting = 0;
+	}
+	pthread_mutex_unlock( &bpb->bmut );
+
+	/* Make use of bpb->bufs[ bpb->wp ] someday */
+
+	status = (*sink)( bpb->bufs[ bpb->wp ], bpb->bufsize, arg );
+	if(status)
+	    return status;
+
+	pthread_mutex_lock( &bpb->bmut );
+	bpb->wp = (bpb->wp + 1) % bpb->nbufs;
+
+	if(bpb->fillwaiting)
+	    pthread_cond_signal( &bpb->bfillwait );
+	pthread_mutex_unlock( &bpb->bmut );
+
+	bpio->drain = (bpio->drain+1) % bpio->nfillers;
+    }
+
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/bpiotest.c
===================================================================
--- trunk/src/testing/app/bitplay/bpiotest.c	(revision 4)
+++ trunk/src/testing/app/bitplay/bpiotest.c	(revision 4)
@@ -0,0 +1,123 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "bpio.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+
+off_t totalbytes = 0;
+int nreads = 0;
+int interval = 200;
+int verbose = 0;
+struct timeval then;
+
+int timesink( unsigned char *buf, int nbytes, void *junk )
+{
+    struct timeval now;
+    static struct timeval prev;
+
+    /* if we're too soon, sleep a while */
+    if(junk && *(int *)junk) {
+	int dmsec;
+	gettimeofday(&now, NULL);
+	if(prev.tv_sec == 0)
+	    prev = now;
+	dmsec = (now.tv_sec - prev.tv_sec) * 1000 + (now.tv_usec - prev.tv_usec) / 1000;
+	dmsec = *(int *)junk - dmsec - 15;	/* -10 ms since that's clock resolution */
+	if(dmsec > 0)
+	    usleep(1000 * dmsec);
+	prev = now;
+    }
+    /* ignore the data, just measure read performance */
+    totalbytes += nbytes;
+    if(nreads % interval == 0) {
+	gettimeofday( &now, NULL );
+	if(nreads > 0) {
+	    double dt = (now.tv_usec - then.tv_usec) * 1e-6 + (now.tv_sec - then.tv_sec);
+	    if(interval > 0)
+		fprintf(stderr, "%.1f ", 1e-6 * totalbytes / dt);
+	    else
+		fprintf(stderr, "%d ", (int)(dt*1000));
+	    totalbytes = 0;
+	}
+	then = now;
+    }
+    nreads++;
+    return 0;
+}
+
+
+int
+main( int argc, char *argv[] )
+{
+    bpio_t bpio;
+    char *fname = argv[1];
+    int nfillers = argc>2 ? atoi(argv[2]) : 10;
+    int bufsize = argc>3 ? atoi(argv[3]) : 65536;
+    int nbufseach = argc>4 ? atoi(argv[4]) : 8;
+    int readsize = bufsize;
+    int mstarget = 0;
+
+    if(argc>3 && strchr(argv[3], '/'))
+	readsize = atoi(strchr(argv[3], '/')+1);
+
+    if(argc > 5) interval = atoi(argv[5]);
+    if(argc > 6) mstarget = atoi(argv[6]);
+
+
+    if(fname == NULL) {
+	fprintf(stderr, "Usage: %s  infilename   [nfillthreads  [bufbytes[/readsize]  [nbufsperthread  [printinterval [mstargetrate]]]]]\n\
+Runs concurrently in 'nfillthreads' threads,\n\
+each reading chunks of 'bufbytes' into queues of 'nbufsperthread' such buffers,\n\
+printing MBytes/sec after every 'printinterval' reads.\n\
+Defaults:  %d threads, %d bytes/buffer, %d buffers/thread, printinterval %d\n", argv[0],
+	    nfillers, bufsize, nbufseach, interval);
+	exit(1);
+    }
+
+    bpinit( &bpio, nfillers, bufsize, readsize, nbufseach );
+    bpopen( &bpio, argv[1] );
+    bpstart( &bpio, 0 );
+
+    // sleep(2);
+    bpdrain( &bpio, timesink, &mstarget );
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/Makefile.mac
===================================================================
--- trunk/src/testing/app/bitplay/Makefile.mac	(revision 4)
+++ trunk/src/testing/app/bitplay/Makefile.mac	(revision 4)
@@ -0,0 +1,54 @@
+CC = g++
+COPTS = -g
+
+GLUTDIR = /usr
+GLUTDEFS =  -FGLUT -FOpenGL
+GLUTLIBS =  -framework GLUT -framework OpenGL -lobjc
+
+DEFS = ${GLUTDEFS}
+CFLAGS = ${COPTS} ${DEFS}
+LIBS = -lpthread
+
+IMGLIB = ./libimg
+IMAGELIB = ./libimage
+IMGLIBS = -L${IMGLIB} -limg -L${IMAGELIB} -limage -ltiff -ljpeg -lm
+IMGINCS = -I${IMGLIB} 
+GLLIBS  = ${GLUTLIBS} -L../../lib -lsail
+GLINCS  = -I../../include
+
+PROGS = bplay img2bmv bpio onethread
+
+default: bplay
+
+install: default
+	/bin/cp -f bplay ../../bin
+
+all: ${PROGS}
+
+clean:
+	cd ${IMGLIB} && make clean
+	cd ${IMAGELIB} && make clean
+	rm -f ${PROGS} *.o
+
+bplay:	bplay.o bpio.o 
+	cd ${IMGLIB} && make
+	cd ${IMAGELIB} && make
+	${CC} -o $@ bplay.o bpio.o ${GLLIBS} ${LIBS}
+
+bplay.o: bplay.c bpio.h bpmovie.h
+	${CC} -c bplay.c ${COPTS} ${DEFS} ${GLINCS}
+
+img2bmv: img2bmv.c bpmovie.h ${IMGLIB}/libimg.a ${IMAGELIB}/libimage.a 
+	${CC} -c ${CFLAGS} ${IMGINCS} img2bmv.c
+	${CC} -o $@ $@.o ${COPTS} ${IMGLIBS}
+
+txspeed: txspeed.c
+	${CC} -o $@ $@.c -g -O ${GLINCS} ${GLLIBS}
+
+bpio:	bpiotest.o bpio.o
+	${CC} -o $@ bpiotest.o bpio.o ${COPTS} ${LIBS}
+
+bpio.o bpiotest.o:	bpio.h
+
+onethread: onethread.o
+	${CC} -o $@ onethread.o ${COPTS}
Index: trunk/src/testing/app/bitplay/Makefile
===================================================================
--- trunk/src/testing/app/bitplay/Makefile	(revision 4)
+++ trunk/src/testing/app/bitplay/Makefile	(revision 4)
@@ -0,0 +1,50 @@
+include ../../config.mk
+QUANTA_DIR=../../QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L../../lib -lquanta
+
+CFLAGS=$(SAGE_CFLAGS) -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(QUANTA_LDFLAGS) $(GLEW_LIB) -L../../lib -lsail
+CC=${COMPILER}
+C-Compiler=gcc
+ifeq ($(MACHINE), SunOS)
+C-Compiler=cc
+endif
+
+IMGLIB = ./libimg
+IMAGELIB = ./libimage
+IMGLIBS = -L${IMGLIB} -limg -L${IMAGELIB} -limage -ltiff -ljpeg -lm
+IMGINCS = -I${IMGLIB} 
+
+PROGS = bplay-noglut img2bmv bpio onethread
+
+default: bplay-noglut
+
+install: default
+	/bin/cp -f bplay-noglut ../../bin
+
+all: ${PROGS}
+
+clean:
+	rm -f ${PROGS} *.o bplay
+
+bplay-noglut:	bplay.o bpio.o 
+	${CC} -o $@ ${SAGE_LDFLAGS} bplay.o bpio.o ${GLLIBS} ${LIBS}
+
+bplay.o: bplay.c bpio.h bpmovie.h
+	${CC}  ${CFLAGS} -c bplay.c ${COPTS} ${DEFS}
+
+img2bmv: img2bmv.c bpmovie.h ${IMGLIB}/libimg.a ${IMAGELIB}/libimage.a 
+	${C-Compiler} -c ${CFLAGS} ${IMGINCS} img2bmv.c
+	${C-Compiler} -o $@ $@.o ${COPTS} ${IMGLIBS}
+
+txspeed: txspeed.c
+	${CC} -o $@ $@.c -g -O ${GLINCS} ${GLLIBS}
+
+bpio:	bpiotest.o bpio.o
+	${CC} -o $@ bpiotest.o bpio.o ${COPTS} ${LIBS}
+
+#bpio.o bpiotest.o:	bpio.h
+
+onethread: onethread.o
+	${CC} -o $@ onethread.o ${COPTS}
Index: trunk/src/testing/app/bitplay/bpio.h
===================================================================
--- trunk/src/testing/app/bitplay/bpio.h	(revision 4)
+++ trunk/src/testing/app/bitplay/bpio.h	(revision 4)
@@ -0,0 +1,113 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef BPIO_H
+#define BPIO_H 1
+
+#define _FILE_OFFSET_BITS  64
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+typedef struct bpbuf_s bpbuf_t;
+
+typedef struct bpio_s {
+    int nfillers;	/* readers read from disk -> bufs */
+    bpbuf_t *bpb;	/* bpb[reader(0..nfillers-1)] */
+    int bufsize;	/* matching that of bpb->bufsize */
+    int readsize;	/* ditto */
+    int drain;		/* next bpbuf_t to drain (dynamic, but owned by drain thread) */
+    int fwd;		/* bpb->incrpos = fwd * nfillers * bufsize */
+
+} bpio_t;
+
+/* Is someone waiting on our condition-variable?  Why? */
+enum business { NO, EMPTY, FULL, PAUSED };
+
+struct bpbuf_s {
+    		/* Static stuff */
+    bpio_t 	  *bpio;
+    int     	  nbufs;	/* number of buffers per reader */
+    int	    	  bufsize;
+    int		  readsize;
+    unsigned char *bufspace;
+    unsigned char **bufs;	/* page-aligned buffers  bufs[0..nbufs-1] */
+    int		  bpbno;	/* our index in parent */
+    int		  fd;		/* file descriptor */
+
+    volatile off_t *curpos;	/* curpos[0..nbufs-1] -- filepos whence read */
+    volatile off_t wrappos;	/* wrap back to poswrap after passing EOF */
+    volatile off_t eofpos;	/* here's the nominal EOF point */
+    volatile off_t incrpos;	/* increment from one read to the next */
+    volatile int  doloop;	/* automatically loop at EOF? */
+
+    		/* Dynamic stuff, held under locks */
+    volatile int     fillwaiting; /* is filler waiting? */
+    volatile int     drainwaiting; /* is drainer waiting? */
+    volatile int     filling;	/* is filler thread supposed to be running? */
+    volatile int     busy;	/* is filler busy reading? (if "filling" was cleared, has it noticed?) */
+
+    volatile off_t	filepos;/* file offset for next buffer to be filled*/
+    volatile int	wp;	/* next-buffer-to-be-drained (to display) index */
+    volatile int	rp;	/* next-buffer-to-be-filled (from file) index */
+
+    pthread_t	     bthread;
+    pthread_mutex_t  bmut;
+    pthread_cond_t   bfillwait;	/* filler waiting (due to not-yet-setup or full queue)? */
+    pthread_cond_t   bdrainwait; /* drainer wait (due to empty queue)? */
+
+};
+
+extern void bpclose( bpio_t *bpio );
+extern int bpopen( bpio_t *bpio, char *fname );
+extern int bpbfull( bpbuf_t *bpb );
+extern int bpbempty( bpbuf_t *bpb );
+extern bpio_t *bpinit( bpio_t *bpio, int nfillers, int bufsize, int readsize, int nbufseach );
+extern void bpseek( bpio_t *bpio, off_t pos );
+extern unsigned char *bpcurbuf( bpio_t *bpio );
+extern off_t bptell( bpio_t *bpio );
+extern void bpstart( bpio_t *bpio, int wrap );
+extern void bpstop( bpio_t *bpio );
+extern void bpforward( bpio_t *bpio, int fwd );
+extern void bprange( bpio_t *bpio, off_t from, off_t to );
+
+extern void *bpfiller( void *vbpb );
+extern int  bpdrain( bpio_t *bpio, int (*sink)( unsigned char *buf, int nbytes, void *arg ), void *arg );
+extern void bpsync( bpio_t *bpio );
+
+#endif
Index: trunk/src/testing/app/bitplay/Makefile.jvcstereo
===================================================================
--- trunk/src/testing/app/bitplay/Makefile.jvcstereo	(revision 4)
+++ trunk/src/testing/app/bitplay/Makefile.jvcstereo	(revision 4)
@@ -0,0 +1,49 @@
+COPTS = -g -O2 -Wall
+
+# GLUTDEFS = -DUSE_FREEGLUT
+# GLUTLIBS = -L/usr/X11R6/lib64 -lfreeglut-1.3 -lglib -lXxf86vm
+
+GLUTDIR = /usr/local/src/grap/glut-3.7
+GLUTDEFS = -I${GLUTDIR}/include
+GLUTLIBS = -L${GLUTDIR}/lib/glut -lglut -L/usr/X11R6/lib64 -lX11 -lXmu
+
+DEFS = ${GLUTDEFS}
+CFLAGS = ${COPTS} ${DEFS}
+LIBS = -lpthread
+
+IMGLIB = /u/src/grap/libimg
+IMAGELIB = /u/src/grap/libimage
+IMGLIBS = -L${IMGLIB} -limg -L${IMAGELIB} -limage -ltiff -ljpeg -lm
+IMGINCS = -I${IMGLIB} 
+GLLIBS  = ${GLUTLIBS} -lGL -lGLU -lm
+GLINCS  = -I/usr/X11R6/include
+
+PROGS = bplay img2bmv bpio
+
+all: ${PROGS}
+
+clean:
+	rm -f ${PROGS} *.o
+
+bplay:	bplay.o bpio.o 
+	${CC} -o $@ bplay.o bpio.o ${GLLIBS} ${LIBS}
+
+bpio.o: bpio.c bpio.h
+	${CC} -c bpio.c ${COPTS} -O0 ${DEFS} ${GLINCS}
+
+bplay.o: bplay.c bpio.h bpmovie.h
+	${CC} -c bplay.c ${COPTS} ${DEFS} ${GLINCS}
+
+img2bmv: img2bmv.c bpmovie.h ${IMGLIB}/libimg.a ${IMAGELIB}/libimage.a 
+	${CC} -c ${CFLAGS} ${IMGINCS} img2bmv.c
+	${CC} -o $@ $@.o ${COPTS} ${IMGLIBS}
+
+txspeed: txspeed.c
+	${CC} -o $@ $@.c -g -O ${GLINCS} ${GLLIBS}
+
+bpio:	bpiotest.o bpio.o
+	${CC} -o $@ bpiotest.o bpio.o ${COPTS} ${LIBS}
+
+bpio.o bpiotest.o:	bpio.h
+
+
Index: trunk/src/testing/app/bitplay/img2bmv.c
===================================================================
--- trunk/src/testing/app/bitplay/img2bmv.c	(revision 4)
+++ trunk/src/testing/app/bitplay/img2bmv.c	(revision 4)
@@ -0,0 +1,529 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#define _LARGEFILE64_SOURCE 1
+#define _FILE_OFFSET_BITS   64
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#ifndef sun
+#include <endian.h>
+#endif
+
+#include "bpmovie.h"
+#include "imginfo.h"
+
+    /* Macros for (A<<24) + (B<<16) + (G<<8) + R-format pixels as from getimgdata */
+
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
+# define ROFF	3
+# define GOFF   2
+# define BOFF   1
+#else	/* assume little-endian */
+# define ROFF   0
+# define GOFF   1
+# define BOFF   2
+#endif
+
+#define PR(p)  (p)[ROFF]
+#define PG(p)  (p)[GOFF]
+#define PB(p)  (p)[BOFF]
+
+char Usage[] = "\
+Usage: %s -o OUTFILE.bmv  [-w XSIZExYSIZE] [-e OFFSET[m|k|f]@OUTDISK] [-p BPP] [-f rate] FROM-TO%%INCR LEFTPATTERN [RIGHTPATTERN]\n\
+Encode a sequence of TIFF/SGI/JPEG/etc. files as a .bmv movie,\n\
+optionally storing the image data in a separate file or disk partition.\n\
+Options:\n\
+    -o outfile.bmv	Write movie (or its header at least) to this file.  Required.\n\
+    -e offset[m|k|f]@outdisk   If given, store the movie data at the given\n\
+    			offset on the given device or file.  THe offset may be\n\
+			specified as a number with suffix 'm', 'k' or 'f'\n\
+			in which case it's in units of 2^20 (MB), 2^10 (KB),\n\
+			or the frame size, respectively.\n\
+    -p bytesperpixel\n\
+    	Selects pixel format:  1: grayscale  2: 16-bit 5-6-5 RGB  3: 24-bit RGB\n\
+    -f rate		preferred frame rate (if any), frames/sec\n\
+\n\
+    from-to%%incr	range of frame numbers to apply to left+righpattern\n\
+    leftpattern		printf format string for image name, e.g. /some/where/left.%%04d.tif\n\
+    rightpattern	similar for right-hand stereo image, or \"-\" to omit\n";
+
+
+char *prog;
+
+static int bytesper[5] = { 0, 1, 2, 3, 4 };	/* indexed by enum pixeltype values */
+
+int skipmissing = 1;
+int prefrate = 0;
+
+#define MAXALIGN	16384	/* largest credible page size */
+
+/* Find head with both hands -- compute tile arrangement */
+void findhead( bpmvhead_t *head, int xwin, int ywin, int xtile, int ytile, enum pixeltype format )
+{
+    head->magic = BPMV3_MAGIC;
+    head->xsize = xwin;
+    head->ysize = ywin;
+    head->format = format;
+    head->xtile = xtile;
+    head->ytile = ytile;
+    head->nxtile = (xwin + xtile - 1) / xtile;
+    head->nytile = (ywin + ytile - 1) / ytile;
+
+    /* Configure for fully packed tiles, which should be most
+     * efficient for stuffing at graphics card
+     */
+
+    head->tilerowstride = bytesper[format] * xtile;
+    head->xtilestride = head->tilerowstride * ytile;
+    head->ytilestride = head->xtilestride * head->nxtile;
+    head->imagestride = (head->ytilestride * head->nytile + MAXALIGN-1) & ~(MAXALIGN-1);
+
+    head->start = head->imagestride;
+}
+
+int writeheader( char *outfname, off_t foffset, bpmvhead_t *head )
+{
+    int outfd;
+
+    outfd = outfname == NULL ? 1 : open(outfname, O_LARGEFILE|O_CREAT|O_TRUNC|O_WRONLY, 0666);
+
+    if(outfd < 0) {
+	fprintf(stderr, "%s: Can't create output: %s: %s\n",
+		prog, outfname, strerror(errno));
+	exit(1);
+    }
+
+    if(head->extfname[0] == '\0') {
+	/* All in one file. */
+	char *headbuf = (char *)malloc( head->start );
+
+	memset(headbuf, 0, head->start);
+	memcpy( headbuf, head, sizeof(*head) );
+	if(write( outfd, headbuf, head->start ) != head->start) {
+	    fprintf(stderr, "%s: %s: can't write %lld-byte header: %s\n",
+		    prog, outfname, head->start, strerror(errno));
+	    exit(1);
+	}
+	free(headbuf);
+	return outfd;
+
+    } else {
+	int headsize = &head->cmd[ strlen(head->cmd) + 1 ] - (char *)head;
+	if(write( outfd, head, headsize ) != headsize) {
+	    fprintf(stderr, "%s: %s: can't write %d-byte header: %s\n",
+		    prog, outfname, headsize, strerror(errno));
+	    exit(1);
+	}
+
+	close(outfd);
+
+	outfd = open( head->extfname, O_LARGEFILE|O_CREAT|O_WRONLY, 0666 );
+	if(outfd < 0) {
+	    fprintf(stderr, "%s: %s: Can't open external-data file for writing: %s\n",
+		    prog, head->extfname, strerror(errno));
+	    exit(1);
+	}
+
+	if(lseek(outfd, head->start, SEEK_SET) < 0) {
+	    fprintf(stderr, "%s: %s: Can't seek to %lld on external-data file: %s\n",
+		    prog, head->extfname, (long long) head->start, strerror(errno));
+	    exit(1);
+	}
+
+	return outfd;
+    }
+}
+
+
+
+unsigned char dither3[8][8];	/* dither bias values as function of position mod 8 */
+
+/* 3-bit (0..7) dither pattern */
+static void initdither3( unsigned char dith3[8][8] )
+{
+    int i, j;
+
+    for(i = 0; i < 8; i++) {
+	for(j = 0; j < 8; j++) {
+	    int ij = i^j;
+
+	    /* Discard bottom 3 bits of 6-bit dither pattern */
+	    dith3[i][j] =
+		( ((ij&4)<<3) | ((i&4)<<2) | ((ij&2)<<2) | ((i&2)<<1) | ((ij&1)<<1) | (i&1)
+		) >> 3;
+	}
+    }
+}
+
+static void encode( unsigned char *aus, bpmvhead_t *head,
+		int aox0, int xwin, int ywin,
+		unsigned char *data, struct imginfo *info )
+{
+    int xtile = head->xtile;
+    int ytile = head->ytile;
+    int xtilestride = head->xtilestride;
+    int ytilestride = head->ytilestride;
+    int tilerowstride = head->tilerowstride;
+    enum pixeltype format = head->format;
+    int obpp = bytesper[ format ];
+
+    int inx, iny;		/* size of intersection between image and output */
+    int ix0, iy0;		/* initial position within image */
+    int irowstride;		/* row-stride in image */
+    int tox0, tox1, toy0, toy1;	/* range of tiles in image-output intersection */
+    int tox, toy;		/* current tile number */
+    unsigned int ox0, oy0;
+
+#define IBPP	4		/* bytes per input-image pixel, as provided by getimgdata() */
+
+
+    irowstride = IBPP * info->xsize; /* getimgdata() was told to make 4-byte-per-pixel format */
+
+    /* How does image fit within [xwin,ywin]? */
+    if(info->xsize <= xwin) {
+	/* Just right or too small.  Center image in output area */
+	ix0 = 0;
+	inx = info->xsize;
+	ox0 = aox0 + (xwin - info->xsize) / 2;
+    } else {
+	/* Too large.  Center and crop image to fit. */
+	ix0 = (info->xsize - xwin) / 2;
+	inx = xwin;
+	ox0 = aox0;
+    }
+    if(info->ysize <= ywin) {
+	/* Just right or too small.  Center image in output area */
+	iy0 = 0;
+	iny = info->ysize;
+	oy0 = (ywin - info->ysize) / 2;
+    } else {
+	/* Too large.  Center and crop image to fit. */
+	iy0 = (info->ysize - ywin) / 2;
+	iny = ywin;
+	oy0 = 0;
+    }
+
+    tox0 = ox0 / xtile;   tox1 = (ox0 + inx-1) / xtile;
+    toy0 = oy0 / ytile;   toy1 = (oy0 + iny-1) / ytile;
+
+    /* Loop over tiles */
+    for(toy = toy0; toy <= toy1; toy++) {
+	int iytile = iy0 + ytile*(toy-toy0);
+	int oytend = (iny - iytile >= ytile) ? ytile : iny - iytile;
+	int oxstart = ox0 % xtile;
+
+	for(tox = tox0; tox <= tox1; tox++, oxstart = 0) {
+	    /* Loop within this tile */
+	    int ixtile = ix0 + xtile*(tox-tox0);
+	    int oxtend = (inx - ixtile >= xtile) ? xtile : inx - ixtile;
+	    unsigned char *ipstart = data + IBPP * ixtile + irowstride * iytile;
+	    unsigned char *opstart = aus
+			+ toy * ytilestride
+			+ tox * xtilestride
+			+ oxstart * obpp;
+	    int oxt, oyt;
+
+	    for(oyt = 0; oyt < oytend; oyt++) {
+		unsigned char *ip = ipstart + oyt * irowstride;
+		unsigned char *op = opstart + oyt * tilerowstride;
+		switch( format ) {
+
+		    case GRAY8:
+			/* Convert RGB to grayscale using NTSC weighting convention */
+			for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op++)
+			    *op = (77*PR(ip) + 151*PG(ip) + 28*PB(ip)) >> 8;
+			break;
+
+		    case RGB565:
+		      {
+			unsigned char *dith3row = &dither3[oyt & 7][0];
+			for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 2) {
+			    /* Apply ordered dither while packing into 5-6-5 format */
+			    unsigned short r, g, b;
+			    unsigned char dith3 = dith3row[oxt & 7] >> 3;
+			    r = PR(ip) + dith3;       if(r > 255) r = 255;
+			    g = PG(ip) + (dith3>>1);  if(g > 255) g = 255;
+			    b = PB(ip) + dith3;       if(b > 255) b = 255;
+			    *(unsigned short *)op =
+				((r & 0xF8) << 8) |
+				((g & 0xFC) << 3) |
+				((b >> 3) & 0x1F);
+			}
+			break;
+		      }
+
+		    case RGB888:
+			for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 3) {
+			    op[0] = PR(ip);
+			    op[1] = PG(ip);
+			    op[2] = PB(ip);
+			}
+			break;
+
+		    case ABGR8888:
+			for(oxt = oxstart; oxt < oxtend; oxt++, ip += IBPP, op += 4) {
+			    op[0] = 255;
+			    op[1] = PB(ip);
+			    op[2] = PG(ip);
+			    op[3] = PR(ip);
+			}
+			break;
+		}
+	    }
+	}
+    }
+}
+
+int main( int argc, char *argv[] )
+{
+    char *outname = NULL;
+    char *extout = NULL;
+    long long outoffset = 0;
+    int offsetframes = 0;
+
+    char *left, *right;
+    int ffrom, fto, finc, frameno;
+    int i, count;
+
+    enum pixeltype pixelformat = RGB565;
+    int xwin = 1920, ywin = 1080;
+    int xtile = 512, ytile = 512;
+    bpmvhead_t head;
+    int outfd = -1;
+    int relshift = 0;
+
+    unsigned char *aus;
+
+    memset( &head, 0, sizeof(head));
+
+    for(i = 0, count = 0; i < argc; i++) {
+	int len = strlen(argv[i]);
+	if(count + len > sizeof(head.cmd)-2)
+	    len = sizeof(head.cmd)-2 - count;
+	memcpy(head.cmd+count, argv[i], len);
+	count += len;
+	head.cmd[count++] = ' ';
+    }
+    head.cmd[--count] = '\0';
+
+    prog = argv[0];
+
+    while(argc>2 && argv[1][0] == '-' && argv[1][1] != '\0') {
+	switch(argv[1][1]) {
+	case 'o':
+	    outname = argv[2];
+	    argc -= 2, argv += 2;
+	    break;
+
+	case 'f':	/* preferred play rate */
+	    prefrate = atoi(argv[2]);
+	    if(strchr(argv[2], 'm') != NULL)
+		prefrate = -abs(prefrate);	/* in ms/frame rather than frames/sec */
+	    argc -= 2, argv += 2;
+	    break;
+
+	case 'e': {
+	    char *cp = strchr(argv[2], '@');
+	    if(cp) {
+		char *ep;
+		outoffset = strtoll(argv[2], &ep, 0);
+		switch(*ep) {
+		case 'k': case 'K': outoffset <<= 10; break;
+		case 'm': case 'M': outoffset <<= 20; break;
+		case 'f': case 'F': offsetframes = 1; break;
+		}
+		extout = cp+1;
+	    } else {
+		extout = argv[2];
+	    }
+	    argc -= 2, argv += 2;
+	  }
+	  break;
+
+	case 'L':
+	  relshift = -atoi(argv[2]);  argc -= 2, argv += 2;
+	  break;
+
+	case 'R':
+	  relshift = atoi(argv[2]);  argc -= 2, argv += 2;
+	  break;
+
+	case 'p':
+	  pixelformat = (enum pixeltype) atoi(argv[2]);
+	  if(pixelformat < 1 || pixelformat > 4) {
+	      fprintf(stderr, "%s -p: expected pixel format 1 (gray), 2 (rgr565), 3 (rgb24), 4 (rgba), not %s\n", prog, argv[2]);
+	      exit(1);
+	  }
+	  argc -= 2, argv += 2;
+	  break;
+
+	case 'w':
+	  sscanf(argv[2], "%d%*c%d", &xwin, &ywin);
+	  argc -= 2, argv += 2;
+	  break;
+
+	default:
+	  argc = 0;
+	}
+    }
+
+    if(argc < 3) {
+	fprintf(stderr, Usage, prog);
+	exit(1);
+    }
+
+    ffrom = 0;
+    fto = -1;
+    finc = 1;
+
+    if(sscanf(argv[1], "%d-%d%%%d", &ffrom, &fto, &finc) <= 0) {
+	fprintf(stderr, "%s: expected from-to%%incr, got %s\n", prog, argv[1]);
+	exit(1);
+    }
+
+    left = argv[2];
+    right = argc>3 ? argv[3] : NULL;
+
+    if(fto < 0)
+	fto = ffrom;
+    if(finc == 0)
+	finc = 1;
+
+    count = (fto - ffrom) / finc + 1;
+
+    findhead( &head, right ? 2*xwin : xwin, ywin, xtile, ytile, pixelformat );
+
+
+    head.nframes = count;
+
+    if(relshift != 0) {
+	head.prefshift = relshift;
+	head.flags |= BPF_PREFSHIFT;
+    }
+
+    if(prefrate != 0) {
+	head.prefrate = prefrate;
+	head.flags |= BPF_PREFRATE;
+    }
+
+    if(right != NULL)
+	head.flags |= BPF_STEREO;
+
+    if(extout != NULL) {
+	if(offsetframes)
+	    outoffset *= head.imagestride;
+	head.flags |= BPF_EXTDATA;
+	head.start = outoffset;
+	strncpy( head.extfname, extout, sizeof(head.extfname)-1 );
+    }
+
+    aus = (unsigned char *) malloc( head.imagestride );
+    if(aus == NULL) {
+	fprintf(stderr, "%s: Can't allocate %d bytes for image buffer\n",
+		prog, head.imagestride);
+	exit(1);
+    }
+    memset(aus, 0, head.imagestride);
+
+    if(pixelformat == RGB565)
+	initdither3( dither3 );
+
+    fprintf(stderr, "RIGHT [%s], XWIN %d YWIN %d XTILE %d YTILE %d\n", right, xwin, ywin, xtile, ytile);
+
+    for(frameno = ffrom, i = 0; i < count; i++, frameno += finc) {
+	struct imginfo lefti, righti;
+	unsigned char *leftd = NULL, *rightd = NULL;
+	char leftname[300], rightname[300];
+
+	/* Find names of images for this frame */
+	sprintf(leftname, left, frameno);
+
+	/* Read images.  Give up if left-hand is missing. */
+	leftd = getimgdata( leftname, NULL, &lefti, 1, 4, 1 );
+	if(leftd == NULL) {
+	    fprintf(stderr, "%s: can't open %s\n", prog, leftname);
+	    if(skipmissing)
+		continue;
+	    else
+		break;
+	}
+
+	/* Is this first time?  Emit header if so. */
+
+	if(i == 0) {
+	    outfd = writeheader( outname, outoffset, &head );
+	}
+
+	/* Re-encode left (or only) image into buffer */
+
+	encode( aus, &head, 0,    xwin, ywin,  leftd, &lefti   );
+
+	if(right != NULL) {
+	    /* If there's a right-hand image, encode it too. */
+	    sprintf(rightname, right, frameno);
+	    rightd = (0==strcmp(rightname, "-")) ? NULL
+		    : getimgdata( rightname, NULL, &righti, 1, 4, 1 );
+	    if(rightd == NULL) {
+		if(rightname[0] != '-')
+		    fprintf(stderr, "%s: can't open %s\n", prog, rightname);
+		rightd = leftd;
+		righti = lefti;
+	    }
+
+	    encode( aus, &head, xwin, xwin, ywin, rightd, &righti );
+	}
+
+	/* DEBUG */
+	*(int *)( aus + head.imagestride-4 ) = frameno;
+
+	errno = 0;
+	if(write( outfd, aus, head.imagestride ) != head.imagestride ) {
+	    fprintf(stderr, "%s: %s: write error: %s\n",
+		    prog, outname ? outname : "stdout", strerror(errno));
+	    exit(1);
+	}
+	free(leftd);
+	if(rightd != leftd && rightd != NULL)
+	    free(rightd);
+    }
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/bpmovie.h
===================================================================
--- trunk/src/testing/app/bitplay/bpmovie.h	(revision 4)
+++ trunk/src/testing/app/bitplay/bpmovie.h	(revision 4)
@@ -0,0 +1,87 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef BPMOVIE_H
+#define BPMOVIE_H 1
+
+#define	BPMV3_MAGIC   ( ('b'<<24) | ('p'<<16) | ('m'<<8) | '3' )
+
+enum pixeltype {
+    GRAY8    = 1,       /* 8-bit grayscale */
+    RGB565   = 2,       /* 16-bit (5-bit-R)<<11 | (6-bit-G)<<5 | (5-bit-R) */
+    RGB888   = 3,       /* 8-bit R, G, B bytes in that order */
+    ABGR8888 = 4,       /* 8-bit A, B, G, R bytes in that order */
+    COMPRESSDXT1 = 5    /* S3TC DXT1 compressed texture (16 texels in 8 bytes) */
+};
+
+typedef struct {
+    int magic;		/* 32-bit int BPMV_MAGIC in native byte order */
+    int xsize;		/* image size */
+    int ysize;
+    enum pixeltype format;
+    int imagestride;	/* bytes per image, including page-alignment padding */
+
+
+    int xtile;		/* X-direction size of each tile */
+    int ytile;		/* Y-direction size of each tile */
+    int nxtile;		/* number of tiles in X-direction */
+    int nytile;		/* number of tiles in Y-direction */
+    int tilerowstride;	/* spacing (bytes) from one row to next within a tile */
+    int xtilestride;	/* spacing (bytes) from one tile to next in X */
+    int ytilestride;	/* spacing (bytes) from one tile to next in Y */
+
+    int nframes;	/* number of frames in movie, if known, else MAXINT */
+
+    int flags;		/* movie-type flags */
+#define BPF_EXTDATA 0x01	/* Image data in separate file 'extfname' */
+#define BPF_STEREO  0x02	/* Each frame is a stereo pair */
+#define BPF_PREFRATE 0x04	/* Has "preferred play rate" setting */
+#define BPF_PREFSHIFT 0x08	/* Has "preferred relative image shift" setting */
+
+    long long start;	/* file offset of first image data */
+
+    int prefrate;	/* preferred play rate, frames/sec */
+    int prefshift;	/* preferred relative image shift, pixels */
+
+    char pad[56];	/* some room for extensions */
+
+    char extfname[1024]; /* name of file with image data, if flags&BPF_EXTDATA */
+    char cmd[1024];	/* command used to generate this */
+
+
+} bpmvhead_t;
+
+#endif
Index: trunk/src/testing/app/bitplay/bplay.c
===================================================================
--- trunk/src/testing/app/bitplay/bplay.c	(revision 4)
+++ trunk/src/testing/app/bitplay/bplay.c	(revision 4)
@@ -0,0 +1,1275 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Bulk movieplayer.  Plays uncompressed movies as encoded by "img2bmv",
+ * using bpio threaded I/O library and OpenGL texturing.
+ *
+ * Stuart Levy, NCSA, University of Illinois Urbana-Champaign, June, 2004.
+ */
+
+#include "bpio.h"	/* Need this first since it #defines some large-file options */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <getopt.h>
+
+#include "bpmovie.h"
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+sail sageInf; // sail object
+unsigned char *rgbBuffer = 0;
+float pixelSize = 3.0;
+
+
+/*
+struct txcodes {
+    int internalfmt;
+    int format;
+    int type;
+} txcode[] = {
+    { 0,0,0 },
+    { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE },
+    { GL_RGB,       GL_RGB,       GL_UNSIGNED_SHORT_5_6_5 },
+    { GL_RGB,       GL_RGB,       GL_UNSIGNED_BYTE },
+    { GL_RGBA,      GL_RGBA,      GL_UNSIGNED_BYTE }
+};
+*/
+
+int nfillers = 4;
+int nbufseach = 5;
+int readsize = 8388608;    // 8MB
+int port = 0;
+
+char *prog;
+
+char *controlfname;
+
+enum stereomode { MONO, CROSSEYED, QUADBUFFERED };
+
+enum stereomode stereo = CROSSEYED;
+
+
+	/* State variables */
+int winx, winy;		/* current window size */
+int newtex = 1;		/* newly minted textures? (need full init rather than subload) */
+
+int paused = 1;		/* Movie paused? */
+int doloop = 0;
+int majorloop = 1;
+int playfwd = 1;
+int quitnow = 0;
+int rateoverride = 0;	/* Should defaultrate override preferred-rate setting in movie? */
+int defaultrate = 10;	/* default target frames/sec */
+int framems = 100;	/* target milliseconds per frame */
+int msfudge = 35;	/* framems = 1000/rate - msfudge */
+int verbose = 0;
+int skipby = 1;		/* skip -- show every Nth frame */
+int preloadms = 0;	/* After switching movies, wait this long for startup */
+int shiftoverride = 0;
+int defaultshift = 0;
+int relshift = 0;
+int nwID = 1;
+
+static int swapinterval = -1;
+
+bpio_t	   *playlist;
+bpmvhead_t *mvlist;
+int	   nplay;
+int	   curplay;
+
+float accumdt = 0, accumweight = 0;
+
+void resumemovie( int loop );
+void pausemovie();
+int openmovie( bpio_t *bpio, char *fname, bpmvhead_t *bpmv );
+
+off_t bpstartpos( bpio_t *bpio )
+{
+    return bpio==NULL ? 0 : bpio->bpb[0].wrappos;
+}
+
+off_t bpendpos( bpio_t *bpio )
+{
+    return bpio==NULL ? 0 : bpio->bpb[0].eofpos;
+}
+
+off_t bpincrpos( bpio_t *bpio )
+{
+    return bpio==NULL ? 0 : bpio->bufsize;
+}
+
+
+int bpawaitone( bpio_t *bpio )
+{
+    bpbuf_t *bpb = &playlist[curplay].bpb[ bpio->drain ];
+
+    pthread_mutex_lock( &bpb->bmut );
+    while(bpbempty( bpb ) && bpb->filling) {
+        bpb->drainwaiting = 1;
+        pthread_cond_wait( &bpb->bdrainwait, &bpb->bmut );
+        bpb->drainwaiting = 0;
+    }
+    pthread_mutex_unlock( &bpb->bmut );
+
+    return !bpbempty(bpb);
+}
+
+int bpconsume1( bpio_t *bpio )
+{
+    bpbuf_t *bpb =  &bpio->bpb[ bpio->drain ];
+
+    if(!bpb->filling)	/* if EOF or bpstop() or etc. */
+        return 0;
+
+    pthread_mutex_lock( &bpb->bmut );
+    bpb->wp = (bpb->wp + 1) % bpb->nbufs;
+
+    if(bpb->fillwaiting)
+        pthread_cond_signal( &bpb->bfillwait );
+    pthread_mutex_unlock( &bpb->bmut );
+
+    bpio->drain = (bpio->drain+1) % bpio->nfillers;
+
+    return bpawaitone( bpio );
+}
+
+int bpframeof( bpio_t *bpio, off_t pos )
+{
+    off_t incr = bpio->bpb[0].incrpos;
+    return incr > 0 ? (pos - bpstartpos(bpio)) / incr :
+	   incr < 0 ? (pos - bpstartpos(bpio)) / (-incr) :
+	   -1;
+}
+
+int defaultratefor( int curplay )
+{
+    return rateoverride
+	 || !(mvlist[curplay].flags & BPF_PREFRATE)
+	 || mvlist[curplay].prefrate == -1  /* bug in some versions of img2bmv */
+	 ? defaultrate : mvlist[curplay].prefrate;
+}
+
+int defaultshiftfor( int curplay )
+{
+    return shiftoverride || !(mvlist[curplay].flags & BPF_PREFSHIFT)
+		? defaultshift : mvlist[curplay].prefshift;
+}
+
+int lasttimems;
+
+int timems()
+{
+    static struct timeval then;
+    struct timeval now;
+
+    gettimeofday( &now, NULL );
+    if(then.tv_sec == 0)
+	then = now;
+    return (now.tv_sec - then.tv_sec) * 1000 + (now.tv_usec - then.tv_usec) / 1000;
+}
+
+int playlistadvance( int sign )
+{
+    bpio_t *bpio;
+    int waspaused = paused;
+    int oldplay = curplay;
+
+    if(curplay >= 0)
+        pausemovie();
+
+    curplay += sign;
+
+    if(majorloop)
+        curplay = (curplay + nplay) % nplay;
+
+    if(curplay < 0 || curplay >= nplay) {
+        pausemovie();
+        return 0;
+    }
+
+    if(oldplay != curplay) {
+        int rate = defaultratefor( curplay );
+
+        framems = (rate > 0) ? 1000 / rate - msfudge: -rate;
+
+        relshift = defaultshiftfor( curplay );
+    }
+
+    bpio = &playlist[curplay];
+
+    bpforward( bpio, playfwd * skipby );
+    bpsync( bpio );
+    bpseek( bpio, playfwd>0 ? bpstartpos( bpio )
+            : bpendpos( bpio ) - bpio->bufsize * skipby );
+
+    if(verbose >= 2)
+        fprintf(stderr, "advance %d  framems %d\n", sign, framems);
+
+    if(!waspaused)
+        resumemovie( doloop );
+
+    if(preloadms)
+        usleep( preloadms * 1000 );
+
+    return 1;
+}
+
+void idler(void);
+
+void showlater( int junk )
+{
+        //glutPostRedisplay();
+        //glutIdleFunc( paused ? NULL : idler );
+}
+
+
+void idler()
+{
+    if(quitnow) {
+        exit(1);
+    }
+    if(verbose>=3) { printf("I"); fflush(stdout); }
+
+    if(bpconsume1( &playlist[curplay] )) {
+            /* Got a buffer ready.  Should we show it now? */
+        if(swapinterval >= 0) {
+                /* Rather than timing here, we'll depend on glXSwapIntervalSGI() */
+                //glutPostRedisplay();
+        } else {
+                /* Nope, we do our own timing */
+            int now = timems();
+            if(now >= lasttimems + framems) {
+                    //glutPostRedisplay();
+            } else {
+                    // glutTimerFunc( (lasttimems + framems) - now, showlater,
+                    //           (lasttimems+framems) - now );
+                    // glutIdleFunc( NULL );
+            }
+        }
+    } else {
+        if( ! playlistadvance( playfwd ) )
+        {
+                // glutIdleFunc( NULL );
+        }
+    }
+}
+
+void catch_quit(int sig) {
+    quitnow = 1;
+}
+
+int ntimes = 50;
+
+void resumemovie( int loop )
+{
+    if(verbose>=3) printf("resume %d p%d\n", loop, paused);
+    bpstart( &playlist[curplay], loop );
+    if(bpawaitone( &playlist[curplay] )) {
+            // glutPostRedisplay();
+        if(paused)
+        {
+                // glutIdleFunc( idler );
+        }
+    } else {
+        printf("resume: bpawaitone -> 0?\n");
+    }
+    paused = 0;
+}
+
+void startmovie( int loop )
+{
+    if(verbose>=2) printf("start %d\n", loop);
+    bpseek( &playlist[curplay], bpstartpos( &playlist[curplay] ) );
+    bpsync( &playlist[curplay] );
+    resumemovie( loop );
+}
+
+void pausemovie()
+{
+        //glutIdleFunc( NULL );
+    paused = 1;
+}
+
+static int val, hasnum;
+
+int getval( int def ) {
+    return hasnum < 0 ? -val : hasnum > 0 ? val : def;
+}
+
+void kb( unsigned char key, int x, int y );
+
+void specialkb( int skey, int x, int y )
+{
+    bpio_t *bpio = &playlist[curplay];
+
+        /*
+    switch(skey) {
+        case GLUT_KEY_PAGE_UP:
+            playlistadvance( -1 );
+            break;
+
+        case GLUT_KEY_PAGE_DOWN:
+            playlistadvance( 1 );
+            break;
+
+        case GLUT_KEY_UP:
+            skipby++;
+            bpforward( bpio, skipby * playfwd );
+            break;
+
+        case GLUT_KEY_DOWN:
+            if(skipby>1)
+                skipby--;
+            bpforward( bpio, skipby * playfwd );
+            break;
+
+        case GLUT_KEY_LEFT:
+            if(glutGetModifiers() & GLUT_ACTIVE_CTRL)
+                kb( 'L', x, y );
+            else
+                kb( '<', x, y );
+            break;
+
+        case GLUT_KEY_RIGHT:
+            if(glutGetModifiers() & GLUT_ACTIVE_CTRL)
+                kb( 'R', x, y );
+            else
+                kb( '>', x, y );
+            break;
+
+        case GLUT_KEY_HOME:
+            startmovie( doloop );
+            break;
+    }
+        */
+    hasnum = val = 0;
+}
+
+void kb( unsigned char key, int x, int y )
+{
+    int isdigit = 0;
+    bpio_t *bpio = &playlist[curplay];
+
+    switch(key) {
+        case '\033':
+            exit(0);
+
+        case ' ':
+            paused = !paused;
+            if(paused)
+                pausemovie();
+            else
+                resumemovie( doloop );
+            break;
+
+        case 'p':
+            pausemovie();
+            break;
+
+        case '.': case '<':
+            bpstop( bpio );
+            bpsync( bpio );
+            bpforward( bpio, skipby );
+            resumemovie( doloop );
+            bpconsume1( bpio );
+            pausemovie();
+            break;
+
+        case ',': case '>':
+            bpstop( bpio );
+            bpsync( bpio );
+            bpforward( bpio, -skipby );
+            resumemovie( doloop );
+            bpconsume1( bpio );
+            pausemovie();
+            break;
+
+        case '-':
+            hasnum = -1;
+            isdigit = 1;
+            break;
+
+        case 'n':
+            if(hasnum)
+                curplay = getval(0) - 1;
+            playlistadvance( 1 );
+            break;
+
+        case 'N':
+            playlistadvance( -1 );
+            break;
+
+        case 'P':
+            preloadms = getval( 500 );
+            break;
+
+        case 'f':
+            playfwd = 1;
+            bpforward( bpio, playfwd * skipby );
+            bpsync( bpio );
+            resumemovie( doloop );
+            break;
+
+        case 'b':
+            playfwd = -1;
+            bpforward( bpio, playfwd * skipby );
+            bpsync( bpio );
+            resumemovie( doloop );
+            break;
+
+        case 'l':
+            doloop = hasnum ? val : !doloop;
+            if(doloop != 0)
+                playfwd = doloop;
+            pausemovie();
+            resumemovie( doloop );
+            break;
+
+        case 'R':
+            relshift = getval( relshift+1 );
+                // glutPostRedisplay();
+            if(verbose>=2) printf("relshift %d\n", relshift);
+            break;
+
+        case 'L':
+            relshift = -getval( -(relshift-1) );
+                // glutPostRedisplay();
+            if(verbose>=2) printf("relshift %d\n", relshift);
+            break;
+
+
+        case 'z':
+            playfwd = 1;
+            skipby = 1;
+            bpforward( bpio, playfwd * skipby );
+            bpsync( bpio );
+            startmovie( doloop );	/* schedule first frame */
+            pausemovie();
+            break;
+
+        case 'v':
+            verbose = getval( !verbose );
+            break;
+
+        case 'g': {
+            int frameno = getval(0);
+            int nframes = mvlist[curplay].nframes;
+            if(frameno >= nframes-1)
+                frameno = nframes-1;
+            else if(frameno < 0)
+                frameno = 0;
+
+            bpseek( bpio, bpstartpos( bpio ) + frameno * (off_t) bpio->bufsize );
+            bpsync( bpio );
+            resumemovie( doloop );
+            bpawaitone( bpio );
+            pausemovie();
+	    }
+            break;
+
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            val = val*10 + key - '0';
+            hasnum = 1;
+            isdigit = 1;
+            break;
+
+
+        case 's': {
+            int rate = getval( defaultratefor(curplay) );
+            framems = (int) ( rate>0 ? 1000.0/rate - msfudge : -rate );
+	    }
+            if(verbose>=2)
+                fprintf(stderr, "%d fps -> allot %d ms/frame with 10ms fudge\n", val, framems);
+            break;
+
+        case 't':
+            framems = getval( framems );
+            break;
+
+        case 'S':
+            skipby = getval( 1 );
+            bpforward( bpio, playfwd * skipby );
+            break;
+
+        case '=': {
+            int frameno = ( bptell( bpio ) - bpstartpos( bpio ) ) / bpincrpos( bpio );
+            float fps = accumdt==0 ? 0 : 1000 * accumweight / accumdt;
+            fprintf(stderr, "frame %04d   %5.1f fps\n", frameno, fps);
+        }
+            break;
+
+        case 'h':
+            fprintf(stderr, "bplay keyboard commands:\n\
+  <NNN>s   aim for NNN frames/sec\n\
+  <NNN>S   skip -- show every NNN'th frame\n\
+  <NNN>g   go to NNN'th frame and pause (first = 0)\n\
+   .       one frame forward\n\
+   ,       one frame backward\n\
+   f       run forward\n\
+   b       run backward\n\
+   v       toggle verbose (on-screen framenumber & fps counter)\n\
+   p       pause\n\
+   l	   toggle loop/stop-at-end\n\
+  SPACE    toggle run/pause\n\
+  HOME     go to beginning of movie and play (like \"0gf\")\n");
+            break;
+
+
+    }
+    if(!isdigit) {
+        if(verbose>=2) {
+            if(hasnum)	printf("\"%d%c\"\n", getval(0), key);
+            else	printf("\"%c\"", key);
+        }
+        val = hasnum = 0;
+    }
+}
+
+void swab32( void *ap, int nbytes )
+{
+    unsigned int *p = (unsigned int *)ap;
+    while((nbytes -= 4) >= 0) {
+        unsigned int v = *p;
+        *p++ = ((v>>24)&0xFF) | ((v>>8)&0xFF00) | ((v&0xFF00)<<8) | ((v&0xFF)<<24);
+    }
+}
+
+void swabbpmv( bpmvhead_t *bpmv )
+{
+    swab32( bpmv, (char *)&bpmv->extfname - (char *)bpmv );
+
+        /* bpmv->start is a 64-bit quantity and needs its words swapped */
+    bpmv->start = ((bpmv->start & 0xFFFFFFFFLL) << 32)
+		| ((bpmv->start >> 32) & 0xFFFFFFFFLL);
+}
+
+
+int openmovie( bpio_t *bpio, char *fname, bpmvhead_t *bpmv )
+{
+    int fd;
+    int n;
+    bpmvhead_t head;
+
+    if(fname == NULL)
+        return -1;
+
+    fd = open(fname, O_RDONLY);
+
+    if(fd < 0) {
+        fprintf(stderr, "%s: %s: can't open: %s\n",
+                prog, fname, strerror(errno));
+        return -1;
+    }
+
+    n = read( fd, &head, sizeof(head) );
+    if(n <= &head.extfname[0] - (char *)&head) {
+        fprintf(stderr, "%s: %s: can't read header: %s\n",
+                prog, fname, strerror(errno));
+        return -1;
+    }
+
+    if(head.magic != BPMV3_MAGIC)
+        swabbpmv( &head );
+    if(head.magic != BPMV3_MAGIC) {
+        fprintf(stderr, "%s: %s doesn't look like a bpmovie file (as made by img2bpmv).\n",
+                prog, fname);
+        return -2;
+    }
+
+    close(fd);
+
+        /* OK then. */
+
+    newtex = 1;
+
+    if(bpio->nfillers == 0)
+        bpinit( bpio, nfillers, head.imagestride, readsize, nbufseach );
+
+    if(head.flags & BPF_EXTDATA) {
+        if(bpopen( bpio, head.extfname ) < 0) {
+            fprintf(stderr, "%s: %s refers to movie data in \"%s\": %s\n",
+                    prog, fname, head.extfname, strerror(errno));
+            return -1;
+        }
+    } else {
+        if(bpopen( bpio, fname ) < 0)
+            return -1;
+    }
+
+    if(bpmv)
+        *bpmv = head;
+
+    if(head.flags & BPF_EXTDATA) {
+        off_t end = head.start + (long long)head.imagestride * (long long)head.nframes;
+        bprange( bpio, head.start, end );
+    } else {
+        bprange( bpio, head.start, -1LL );
+    }
+    bpseek( bpio, head.start );
+    bpsync( bpio );
+
+    return head.nframes;
+}
+
+void draweye( bpmvhead_t *bpmv, unsigned int *txs, unsigned char *tilebuf,
+              float scl, float imxsz, float xoff, float yoff, int x0, int x1, float *xagain )
+{
+        //struct txcodes *txc = &txcode[ bpmv->format ];
+    int i,j,k, ii;
+
+    for(i = k = 0; i < bpmv->nytile; i++) {
+        for(j = x0; j < x1; j++, k++) {
+
+            float xx0 = xoff + scl * j * bpmv->xtile;
+            float xx1 = xoff + scl * (j+1) * bpmv->xtile;
+            float yy0 = yoff + scl * i * bpmv->ytile;
+            float yy1 = yoff + scl * (i+1) * bpmv->ytile;
+
+                /*
+                  fprintf(stderr, "%d %d %d %d - stride %d %d %d\n",
+                  j * bpmv->xtile,
+                  (j+1) * bpmv->xtile,
+                  i * bpmv->ytile,
+                  (i+1) * bpmv->ytile,
+                  bpmv->xtilestride,
+                  bpmv->ytilestride, bpmv->tilerowstride);
+                */
+
+            unsigned char *ptr = tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride;
+            unsigned char *dst = rgbBuffer + int(i*bpmv->xtile*x1*bpmv->ytile*pixelSize) + int(j*bpmv->xtile*pixelSize);
+            for (ii=0;ii<bpmv->ytile;ii++)
+            {
+                memcpy(dst, ptr, int(bpmv->xtile * pixelSize));
+                dst += int(bpmv->xtile * x1 * pixelSize);
+                ptr += int(bpmv->xtile * pixelSize);
+            }
+
+
+                //glBindTexture( GL_TEXTURE_2D, txs[k] );
+
+            if (newtex) {
+
+/*                 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); */
+/*                 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); */
+/*                 glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); */
+
+/*                 glTexImage2D( GL_TEXTURE_2D, 0, */
+/*                               txc->internalfmt, bpmv->xtile, bpmv->ytile, 0, */
+/*                               txc->format, txc->type,  */
+/*                               tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride ); */
+            } else {
+/*                 glTexSubImage2D( GL_TEXTURE_2D, 0,  0,0, */
+/*                                  bpmv->xtile, bpmv->ytile, txc->format, txc->type, */
+/*                                  tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride ); */
+
+            }
+
+/*             glBegin( GL_QUADS ); */
+
+/*             glTexCoord2f( 0, 0 ); */
+/*             glVertex3f( xx0, yy0, 0 ); */
+
+/*             glTexCoord2f( 0, 1 ); */
+/*             glVertex3f( xx0, yy1, 0 ); */
+
+/*             glTexCoord2f( 1, 1 ); */
+/*             glVertex3f( xx1, yy1, 0 ); */
+
+/*             glTexCoord2f( 1, 0 ); */
+/*             glVertex3f( xx1, yy0, 0 ); */
+
+                /* If it's a mono movie and we're in stereo,
+                 * we need to draw this tile twice.
+                 */
+            if(xagain != NULL) {
+/*                 glTexCoord2f( 0, 0 ); */
+/*                 glVertex3f( xx0 + *xagain, yy0, 0 ); */
+
+/*                 glTexCoord2f( 0, 1 ); */
+/*                 glVertex3f( xx0 + *xagain, yy1, 0 ); */
+
+/*                 glTexCoord2f( 1, 1 ); */
+/*                 glVertex3f( xx1 + *xagain, yy1, 0 ); */
+
+/*                 glTexCoord2f( 1, 0 ); */
+/*                 glVertex3f( xx1 + *xagain, yy0, 0 ); */
+            }
+
+/*             glEnd(); */
+
+            {
+/*                 GLuint e = glGetError(); */
+/*                 if(e != 0) fprintf(stderr, "E%d ", e); */
+            }
+        }
+    }
+
+#if 0
+    static int count = 1;
+    char fn[256];
+    sprintf(fn, "out%d.raw", count++);
+    FILE *ff = fopen(fn, "w+");
+    fwrite(rgbBuffer, 1, x1*bpmv->xtile*bpmv->nytile*bpmv->ytile*3, ff);
+    fclose(ff);
+#else
+
+    sageInf.swapBuffer();
+    rgbBuffer = (unsigned char *)sageInf.getBuffer();
+
+#endif
+}
+
+void redraw()
+{
+    static unsigned int *txs;
+    static int ntxs = 0;
+
+    bpmvhead_t *bpmv = &mvlist[curplay];
+    float xscl, yscl, scl, eyex, imxsz, xoff, yoff;
+    float xright;
+
+    unsigned char *tilebuf;
+    int now;
+
+    float dt, decay;
+
+    tilebuf = bpcurbuf( &playlist[curplay] );
+
+    if(tilebuf == NULL) {
+/*         glClearColor( 0, 0, 0.3, 1 ); */
+/*         glClear( GL_COLOR_BUFFER_BIT ); */
+/*         glutSwapBuffers(); */
+        return;
+    }
+
+        /* fprintf(stderr, "<%d:%d> ", playlist[curplay].drain, *(int *)tilebuf); */
+
+    if(playlist[curplay].bufsize != bpmv->imagestride) {
+            /* I/O mismatch */
+/*         glClearColor( 0.5, 0, 0, 1 ); */
+/*         glClear( GL_COLOR_BUFFER_BIT ); */
+/*         glutSwapBuffers(); */
+        return;
+    }
+
+    if(verbose < 4) {
+/*         glClearColor( 0, 0, 0, 1 ); */
+/*         if(stereo != QUADBUFFERED) */
+/*             glClear( GL_COLOR_BUFFER_BIT ); */
+    }
+
+/*     glMatrixMode( GL_MODELVIEW ); */
+/*     glLoadIdentity(); */
+
+        /* OK, use textures from current bpio buffer */
+
+    if(bpmv->nxtile * bpmv->nytile != ntxs) {
+        if(ntxs > 0) {
+                //glDeleteTextures( ntxs, txs );
+            free( txs );
+        }
+
+        ntxs = bpmv->nxtile * bpmv->nytile;
+        txs = (unsigned int *) malloc( ntxs * sizeof(unsigned int) );
+            //glGenTextures( ntxs, txs );
+        newtex = 1;
+    }
+
+        // glEnable( GL_TEXTURE_2D );
+
+        /*
+         * How big should this image be drawn?
+         * Scale to fit the available area, centered.
+         * If image is stereo and we're in crosseyed-stereo mode,
+         * translate to keep center of image on center of display.
+         */
+
+    eyex = (stereo==CROSSEYED) ? winx/2 : winx;
+    imxsz = (bpmv->flags&BPF_STEREO) ? bpmv->xsize/2 : bpmv->xsize;
+    xscl = eyex / (float)imxsz;
+    yscl = winy / (float)bpmv->ysize;
+    scl = (xscl < yscl) ? xscl : yscl;
+    xoff = 0.5f * (eyex - scl * imxsz);
+    yoff = 0.5f * (winy - scl * bpmv->ysize);
+    xright = winx / 2;
+    if(verbose >= 5)
+        fprintf(stderr, "s%.3g xo%g yo%g\n", scl, xoff, yoff);
+
+    if(verbose<4) {
+        int stereomovie = bpmv->flags & BPF_STEREO;
+        float xoff = 0.5f * (eyex - scl * imxsz);
+        float yoff = 0.5f * (winy - scl * bpmv->ysize);
+        int nxtile = bpmv->nxtile;
+
+        switch(stereo) {
+            case MONO:
+                    /*
+                     * If it's a stereo movie and we're in mono mode,
+                     * just display the left half.
+                     */
+                draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff,
+                         0, stereomovie ? nxtile/2 : nxtile, NULL );
+                break;
+
+            case CROSSEYED:
+                if(stereomovie) {
+                    if(relshift == 0) {
+                        draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff, 0, nxtile, NULL );
+                    } else {
+                        draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile/2, NULL );
+                        draweye( bpmv, txs, tilebuf, scl, imxsz, xoff-relshift, yoff, nxtile/2, nxtile, NULL );
+                    }
+                } else {
+                        /* mono movie in stereo mode -- draw twice */
+                    draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff, 0, nxtile, &xright );
+                }
+                break;
+
+            case QUADBUFFERED:
+/*                 if(stereomovie) { */
+/*                     glDrawBuffer( GL_BACK_RIGHT ); */
+/*                     glClear( GL_COLOR_BUFFER_BIT ); */
+/*                     draweye( bpmv, txs, tilebuf, scl, imxsz, xoff-relshift, yoff, nxtile/2, nxtile, NULL ); */
+/*                     glDrawBuffer( GL_BACK_LEFT ); */
+/*                     glClear( GL_COLOR_BUFFER_BIT ); */
+/*                     draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile/2, NULL ); */
+/*                 } else { */
+/*                     glDrawBuffer( GL_BACK ); */
+/*                     glClear( GL_COLOR_BUFFER_BIT ); */
+/*                     draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile, NULL ); */
+/*                 } */
+                break;
+        }
+    }
+
+    if(verbose) {
+        char leg[80];
+        int frameno = *(int *)( tilebuf + bpmv->imagestride - 4); /* img2bmv easter egg */
+        float fps = accumdt==0 ? 0 : 1000 * accumweight / accumdt;
+        bpio_t *bpio = &playlist[curplay];
+        int slotno  = (int) ( (   bptell(bpio) - bpstartpos(bpio) ) / bpincrpos(bpio) );
+        int howmany = (int) ( ( bpendpos(bpio) - bpstartpos(bpio) ) / bpincrpos(bpio) );
+        int i;
+
+        if(frameno > 0 && frameno < 20000)
+            sprintf(leg, "%5d of 0..%-5d  %4.1f fps  frame %04d", slotno, howmany-1, fps, frameno);
+        else
+            sprintf(leg, "%5d of 0..%-5d  %4.1f fps", slotno, howmany-1, fps);
+
+/*         glMatrixMode( GL_MODELVIEW ); */
+/*         glPushMatrix(); */
+
+/*         glTranslatef( 18, winy-20, 0 ); */
+/*         glScalef( 0.1, 0.1, 0.1 ); */
+
+/*         glDisable( GL_TEXTURE_2D ); */
+/*         glColor3f( 1, 1, 0.5 ); */
+
+/*         for(i = 0; leg[i] != '\0'; i++) */
+/*             glutStrokeCharacter( GLUT_STROKE_ROMAN, leg[i] ); */
+
+/*         glPopMatrix(); */
+    }
+
+    if(swapinterval < 0) {
+            /* if we can't depend on glXSwapIntervalSGI() for timing */
+        now = timems();
+    }
+
+        // glutSwapBuffers();
+
+
+    now = timems();
+    dt = (now - lasttimems);
+    decay = exp( - dt / 100 );
+    accumdt =     (accumdt * decay)     + dt;
+    accumweight = (accumweight * decay) + 1;
+
+    lasttimems = now;
+
+    if(verbose >= 2) {
+        bpio_t *bpio = &playlist[curplay];
+        bpbuf_t *bpb = &bpio->bpb[ bpio->drain ];
+        int frameno = tilebuf ? *(int *)( tilebuf + bpmv->imagestride - 4) : -9999; /* img2bmv easter egg */
+        printf("<%02d:%02d~%02d> f%d fw%d r%d dw%d w%d %d..%d  %.0fms\n",
+               bpio->drain,
+               bpb->curpos[bpb->wp] < 0 ? -1 : (int) (bpb->curpos[bpb->wp] / bpio->bufsize),
+               frameno,
+               bpb->filling,
+               bpb->fillwaiting, bpb->rp, bpb->drainwaiting, bpb->wp,
+               (int) (bpb->wrappos / bpio->bufsize),
+               (int) (bpb->eofpos / bpio->bufsize),
+               dt);
+    }
+
+    newtex = 0;
+
+}
+
+void visible( int yes )
+{
+    static int first = 1;
+    if(yes && first)
+        startmovie( doloop );
+    else
+        pausemovie();
+    first = 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int c, i;
+    char *hostIP;
+
+    static char Usage[] = "Usage: %s [options] file.bmv ...\n\
+   Plays uncompressed bulk movies in the format created by img2bmv.\n\
+   Options:\n\
+   -f NNN	target NNN frames/sec or -f NNNm milliseconds/frame\n\
+   -t NTHREADS	number of reader threads\n\
+   -r READSIZE	size of each read() in bytes (default = image size)\n\
+   -M msfudge	fudge factor for ms/frame timing estimates (default %d)\n\
+   -v		verbose\n\
+	-n nwID network ID for SAGE\n";
+
+    prog = argv[0];
+
+    signal(SIGINT, catch_quit);
+
+    hostIP = NULL;
+
+    while((c = getopt(argc, argv, "t:b:r:p:S:F:f:P:L:R:vsmqM:c:n:")) != EOF) {
+        switch(c) {
+	case 'c':
+	    hostIP = strdup(optarg);
+	    break;
+
+	case 't':
+	    nfillers = atoi(optarg);
+	    if(nfillers < 1) {
+		fprintf(stderr, "%s: Need at least 1 reader thread\n",
+			prog);
+		exit(1);
+	    }
+	    break;
+
+	case 'b':
+	    nbufseach = atoi(optarg);
+	    if(nbufseach < 2) {
+		fprintf(stderr, "%s: Need at least 2 buffers per reader thread\n",
+			prog);
+		exit(1);
+	    }
+	    break;
+
+	case 'r':
+	    readsize = atoi(optarg);
+	    if(readsize <= 0 || readsize % getpagesize() != 0) {
+		fprintf(stderr, "%s: readsize must be a multiple of pagesize (%d)\n",
+			prog, getpagesize());
+		exit(1);
+	    }
+	    break;
+
+	case 'p':
+	    port = atoi(optarg);	/* Not implemented yet */
+	    break;
+
+	case 'P':
+	    preloadms = atoi(optarg);
+	    break;
+
+	case 'M':
+	    msfudge = atoi(optarg);
+	    break;
+
+	case 'S':
+	    skipby = atoi(optarg);
+	    if(skipby <= 0) skipby = 1;
+	    break;
+
+	case 'F':
+	    rateoverride = 1;	/* and fall into ... */
+	case 'f':
+	{
+	    double v = atof(optarg);
+	    if(strchr(optarg, '!'))
+		rateoverride = 1;
+	    if(strchr(optarg, 'm'))
+		defaultrate = (int) -v;
+	    else if(v>0)
+		defaultrate = (int) v;
+	    else {
+		fprintf(stderr, "%s: -f %s: expected frame rate (frames/sec) or frame time in milliseconds (with \"m\" suffix).\n",
+			prog, optarg);
+		exit(1);
+	    }
+	}
+	break;
+
+	case 's':
+	    stereo = CROSSEYED;
+	    break;
+
+	case 'm':
+	    stereo = MONO;
+	    break;
+
+	case 'q':
+	    stereo = QUADBUFFERED;	/* Not implemented yet! */
+	    break;
+
+	case 'R':
+	    defaultshift = atoi(optarg);
+	    shiftoverride = (strchr(optarg, '!') != NULL);
+	    break;
+
+	case 'L':
+	    defaultshift = -atoi(optarg);
+	    shiftoverride = (strchr(optarg, '!') != NULL);
+	    break;
+
+	case 'v':
+	    verbose++;
+	    break;
+
+	case 'n':
+	    nwID = atoi(optarg);
+	    break;
+
+	default:
+	    fprintf(stderr, "%s: unknown option -%c\n", prog, c);
+	    argc=1;
+	    break;
+        }
+    }
+
+
+    nplay = argc - optind;
+    playlist = (bpio_t *) calloc( nplay, sizeof(bpio_t) );
+    mvlist = (bpmvhead_t *) calloc( nplay, sizeof(bpmvhead_t) );
+
+    int totalframes=0, frames;
+    for(i = 0; i < nplay; i++) {
+
+        frames =  openmovie( &playlist[i], argv[i+optind], &mvlist[i] );
+        if( frames < 0 ) {
+            fprintf(stderr, "%s: %s: cannot open: %s\n",
+                    prog, argv[i+optind], strerror(errno));
+            exit(1);
+        }
+	totalframes +=  frames;
+    }
+
+    if(nplay <= 0 && port == 0) {
+        fprintf(stderr, Usage, prog, msfudge);
+        exit(1);
+    }
+
+    // ----------------------------
+
+    sageRect hdmovieImageMap;
+    hdmovieImageMap.left = 0.0;
+    hdmovieImageMap.right = 1.0;
+    hdmovieImageMap.bottom = 0.0;
+    hdmovieImageMap.top = 1.0;
+
+    sailConfig scfg;
+    scfg.init("bitplayer.conf");
+    scfg.setAppName("bitplayer");
+    scfg.rank = 0;
+    scfg.totalFrames = totalframes;
+    scfg.asyncUpdate = true;
+
+    int stereomovie = mvlist[0].flags & BPF_STEREO;
+    if (stereomovie)
+        fprintf(stderr, "It's a Stereo Movie !!!\n");
+
+    if (stereomovie && (stereo == MONO))
+        scfg.resX = mvlist[0].nxtile*mvlist[0].xtile/2; // always in mono
+    else
+    scfg.resX = mvlist[0].nxtile*mvlist[0].xtile;
+
+    scfg.resY = mvlist[0].nytile*mvlist[0].ytile;
+    scfg.imageMap = hdmovieImageMap;
+    scfg.rowOrd = BOTTOM_TO_TOP;
+    scfg.nwID = nwID;
+
+    if (stereomovie && (stereo == CROSSEYED)) {
+	scfg.winWidth *= 2; // display it twice as wide as a mono movie
+    }
+
+    if (mvlist[0].format == RGB565)
+    {
+        scfg.pixFmt = PIXFMT_565;
+	pixelSize = 2;
+    }
+    else
+        if (mvlist[0].format == RGB888)
+	{
+            scfg.pixFmt = PIXFMT_888;
+	    pixelSize = 3;
+	}
+        else
+            if (mvlist[0].format == ABGR8888)
+	    {
+                scfg.pixFmt = PIXFMT_8888;
+		pixelSize = 4;
+	    }
+            else
+                if (mvlist[0].format == COMPRESSDXT1)
+		{
+                    scfg.pixFmt = PIXFMT_DXT;
+		    pixelSize = 0.5;
+		}
+                else {
+                    fprintf(stderr, "format not supported\n");
+                    exit(1);
+                }
+
+
+    sageInf.init(scfg);
+
+    rgbBuffer = (unsigned char *)sageInf.getBuffer();
+    memset(rgbBuffer, 0, int(scfg.resX*scfg.resY*pixelSize));
+
+    std::cout << "sail initialized :" << scfg.resX << "x" << scfg.resY << std::endl;
+    // ----------------------------
+
+    curplay = -1;
+    playlistadvance(1);
+
+    startmovie( doloop );
+    sageMessage msg;
+    int firstClickTime = 0, dir=0;
+    double fps, t1, t2;
+
+    while (1)
+    {
+	t1 = sage::getTime();
+
+	if(!paused)
+	{
+	    redraw();
+	    idler();
+	}
+
+	if (sageInf.checkMsg(msg, false) > 0) {
+	    char* data = (char*) msg.getData();
+
+	    switch (msg.getCode()) {
+	    case APP_QUIT : {
+		std::cout << "Quit by SAGE" << std::endl;
+		exit(1);
+		break;
+	    }
+	    case SAGE_EVT_CLICK: {
+		float clickX, clickY;
+		int clickDeviceId, clickButtonId, clickIsDown, clickEvent;
+
+		// Parse message
+		sscanf(data, "%d %f %f %d %d %d",
+		       &clickDeviceId, &clickX, &clickY,
+		       &clickButtonId, &clickIsDown, &clickEvent);
+
+		if(clickIsDown && clickButtonId==1)
+		{
+		    if(!paused)
+			pausemovie();
+		    else
+			resumemovie(doloop);
+		}
+
+		// stop the ff or rewind
+		/*else if(!clickIsDown && clickButtonId==1 && dir!=0)
+		  {
+		  dir = 0;
+		  bpio_t *bpio = &playlist[curplay];
+		  bpforward( bpio, playfwd * skipby );
+		  bpsync( bpio );
+		  resumemovie( doloop );
+		  }*/
+
+		break;
+	    }
+		/*case SAGE_EVT_PAN: {
+		  int panDeviceId;
+		  float panX, panY, panDX, panDY, panDZ;
+		  sscanf(data, "%d %f %f %f %f %f",
+		  &panDeviceId, &panX, &panY, &panDX, &panDY, &panDZ);
+
+		  bpio_t *bpio = &playlist[curplay];
+
+		  // if we weren't ff or rewinding OR the direction changed...
+		  if (dir == 0 || (panDX < 0 && dir > 0) || (panDX > 0 && dir < 0))
+		  {
+		  if(panDX < 0)
+		  dir = -1;
+		  else
+		  dir = 1;
+
+		  bpforward( bpio, dir * 15 );
+		  bpsync( bpio );
+		  resumemovie( doloop );
+		  }
+
+		  break;
+		  }*/
+	    }
+	}
+
+        //sage::usleep( (1000/defaultrate)*1000 );
+	t2 = sage::getTime();
+	fps = (1000000.0/(t2-t1));
+	if (fps > defaultrate) {
+	    sage::usleep( (1000000.0/defaultrate) - (t2-t1)  );
+	}
+
+    }
+
+
+    return 0;
+}
Index: trunk/src/testing/app/bitplay/onethread.c
===================================================================
--- trunk/src/testing/app/bitplay/onethread.c	(revision 4)
+++ trunk/src/testing/app/bitplay/onethread.c	(revision 4)
@@ -0,0 +1,127 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+float dt() {
+    static struct timeval then;
+    struct timeval now;
+    float delta;
+
+    gettimeofday( &now, NULL );
+    if(then.tv_sec == 0)
+	then = now;
+    delta = now.tv_sec - then.tv_sec + 1e-6*(now.tv_usec - then.tv_usec);
+    then = now;
+    return delta;
+}
+
+int main(int argc, char *argv[]) {
+    int pagesize = getpagesize();
+    int pagemask = (pagesize - 1);
+    char *fname = argv[1];
+    int bufsize = ( argc>2 ? atoi(argv[2]) : 128 ) * 1024;
+    char *buf = (char *)malloc( bufsize + pagesize );
+    int count = argc>3 ? atoi( argv[3] ) : 1024;
+    int interval = argc>4 ? atoi(argv[4]) : 32;
+    int offset = 0;
+    int skip = 0;
+    float total = 0;
+    int i, margin, fd;
+    char *p;
+
+    if(argc <= 1) {
+	fprintf(stderr, "Usage: %s [-]infilename  kbyteseach  totalbufs  printinterval\n\
+Read from infilename, in buffers of kbyteseach*1024 bytes (rounded up to 4K page size).\n\
+Read totalbufs times, reporting average MBytes/sec every printinterval times,\n\
+and average transfer rate at end of run.\n", argv[0]);
+	exit(1);
+    }
+
+    if(argc>5)
+	sscanf(argv[5], "%d%*c%d", &offset, &skip);
+
+    bufsize = (bufsize + pagesize - 1) & ~pagemask;
+
+    offset = offset * bufsize;
+
+#ifdef sun
+    fd = open(fname, O_RDONLY);
+    if (fname[0]=='-')
+        directio(fd, DIRECTIO_ON);
+#else
+    fd = fname[0]=='-' ? open(fname+1, O_RDONLY | O_DIRECT) : open(fname, O_RDONLY);
+#endif    
+    if(fd < 0) {
+	perror(fname[0]=='-' ? fname+1 : fname);
+	exit(1);
+    }
+
+    lseek( fd, offset, SEEK_SET );
+
+    margin = (buf - (char *)NULL) & pagemask;
+    p = buf - margin;
+
+    dt();
+    for(i = 0; i < count; i++) {
+	if(read(fd, p, bufsize) < bufsize) {
+	    perror("read");
+	    break;
+	}
+	if(skip > 1)
+	    lseek(fd, (skip-1)*bufsize, SEEK_CUR);
+
+	if(interval>0 && (i+1)%interval == 0) {
+	    float deltat = dt();
+	    total += deltat;
+	    printf("%6.2f ", interval * bufsize / (1048576 * deltat));
+	    fflush(stdout);
+	}
+    }
+    total += dt();
+    if(interval > 0)
+	printf("\n");
+    printf("%.2f\n", i * bufsize / (1048576 * total));
+    return 0;
+}
+
Index: trunk/src/testing/app/bitplay/.gdb_history
===================================================================
--- trunk/src/testing/app/bitplay/.gdb_history	(revision 4)
+++ trunk/src/testing/app/bitplay/.gdb_history	(revision 4)
@@ -0,0 +1,11 @@
+r -m -v ~/Dev/bitplay/st-128.bmv
+where
+q
+r -m -v ~/Dev/bitplay/st-128.bmv
+where
+list
+up
+p dst
+p ptr
+p ii
+q
Index: trunk/src/testing/app/bitplay/txspeed.c
===================================================================
--- trunk/src/testing/app/bitplay/txspeed.c	(revision 4)
+++ trunk/src/testing/app/bitplay/txspeed.c	(revision 4)
@@ -0,0 +1,262 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * cc -o txspeed{,.c} -L/usr/X11R6/lib -lglut -lGL -lX11
+ */
+#include <X11/Xlib.h>
+#include <GL/glut.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include <signal.h>
+
+#ifndef MAXTX
+# define MAXTX 128
+#endif
+
+#ifndef TXROOM
+# define TXROOM  64
+#endif
+
+unsigned char txbuf[ TXROOM * MAXTX * MAXTX * 4 ];
+int width = MAXTX;
+int height = MAXTX;
+int internalfmt = GL_RGB;
+int fmt = GL_RGB;
+int type = GL_UNSIGNED_BYTE;
+
+int newtex = 1;
+
+int justone = 0;
+int justload = 0;
+
+#define TXSLOTS  1024
+
+int winx, winy;
+int nxtx, nytx, ntx;
+GLuint txs[TXSLOTS];
+
+void tick( int start );  /* tick(1) to start, tick(0) to continue, tick(-1) to clean up */
+
+void reshape( int xsize, int ysize )
+{
+    int i;
+
+    winx = xsize;  winy = ysize;
+
+    glMatrixMode( GL_PROJECTION );
+    glLoadIdentity();
+    glOrtho( 0, xsize, 0, ysize, -1, 1 );
+    glViewport( 0, 0, xsize, ysize );
+    glMatrixMode( GL_MODELVIEW );
+    glLoadIdentity();
+
+    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+    glEnable( GL_TEXTURE_2D );
+
+    /* How many textures do we need to fill the screen? */
+    nxtx = winx / MAXTX;  if(nxtx == 0) nxtx = 1;
+    nytx = winy / MAXTX;  if(nytx == 0) nytx = 1;
+    if(nxtx*nytx > TXSLOTS) nytx = TXSLOTS / nxtx;
+
+    /* ensure that that many texture-objects exist */
+    for(i = 0; i < nxtx*nytx; i++) {
+	if(txs[i] == 0) {
+	    glGenTextures( nxtx*nytx-i, &txs[i] );
+	    newtex = 1;
+	    break;
+	}
+    }
+
+    for(i = 0; i < sizeof(txbuf); i+=4) {
+	int v = i ^ (i/MAXTX) ^ (i/MAXTX/MAXTX);
+	txbuf[i] = v;
+	txbuf[i+1] = (v<<1) | (v>>7);
+	txbuf[i+2] = (v<<3) | (v>>5);
+	txbuf[i+3] = (v<<5) | (v>>3);
+    }
+
+    tick(1);
+    printf("reshape %dx%d  %dx%d\n", xsize, ysize, nxtx, nytx);
+}
+
+int quitnow = 0;
+
+void idler()
+{
+    if(quitnow) {
+	tick(-1);
+	exit(1);
+    }
+    glutPostRedisplay();
+}
+
+void catch(int sig) {
+    quitnow = 1;
+}
+
+int ntimes = 50;
+
+void tick( int start )
+{
+    static struct timeval then;
+    struct timeval now;
+    static int count;
+    double dt;
+
+    if(start>0) {
+	count = 0;
+	return;
+    }
+
+    count++;
+
+    if(count == 2) {
+	gettimeofday( &then, NULL );
+    } else if(count == ntimes+2 || start<0) {
+	gettimeofday( &now, NULL );
+	dt = (now.tv_sec - then.tv_sec) + 1e-6*(now.tv_usec - then.tv_usec);
+	if(count > 2)
+	    printf(" %g\n", 1000*dt/(count-2), now.tv_sec, then.tv_sec);
+	else printf("tick done: count %d dt %g\n", count, dt);
+	count = 0;
+    }
+}
+
+void kb( unsigned char key, int x, int y )
+{
+    tick( -1 );
+    exit(0);
+}
+
+void redraw()
+{
+    int i, j, k, start, e;
+    int rowlength = 0;
+
+    glClearColor( .3, newtex, 0, 1 );
+    glClear( GL_COLOR_BUFFER_BIT );
+
+    glEnable( GL_TEXTURE_2D );
+
+    /* Load textures and draw */
+    for(i = k = 0; i < nytx; i++) {
+	for(j = 0; j < nxtx; j++, k++) {
+
+	    int x0 = j*MAXTX;
+	    int x1 = (j+1)*MAXTX;
+	    int y0 = i*MAXTX;
+	    int y1 = (i+1)*MAXTX;
+
+	    if(x1 > winx) x1 = winx;
+	    if(y1 > winy) y1 = winy;
+
+	    if(!justone) glBindTexture( GL_TEXTURE_2D, txs[k] );
+	    if(rowlength == 0)
+		start = (int) ( (((TXROOM-1)*MAXTX*MAXTX)*4) * drand48() );
+	    else
+		start = (int) ((MAXTX*MAXTX*4) * drand48());
+
+	    if(newtex) {
+
+		glPixelStorei( GL_UNPACK_ROW_LENGTH, rowlength );
+		/* glEnable( GL_TEXTURE_2D ); */
+		glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
+		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+		glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+		glTexImage2D( GL_TEXTURE_2D, 0, internalfmt, width, height, 0, fmt, type,
+		    &txbuf[(start / 16) * 16] );
+	    } else {
+		glTexSubImage2D( GL_TEXTURE_2D, 0,  0,0,  width,height, fmt, type,
+		    &txbuf[(start / 16) * 16] );
+	    }
+
+	    if(!justload) {
+	    glBegin( GL_QUADS );
+
+	    glTexCoord2f( 0, 0 );
+	    glVertex3i( x0, y0, 0 );
+
+	    glTexCoord2f( 0, 1 );
+	    glVertex3i( x0, y1, 0 );
+
+	    glTexCoord2f( 1, 1 );
+	    glVertex3i( x1, y1, 0 );
+
+	    glTexCoord2f( 1, 0 );
+	    glVertex3i( x1, y0, 0 );
+	    glEnd();
+	    }
+
+	    e = glGetError();
+	    if(e != 0)
+		fprintf(stderr, "E%d ", e);
+	}
+    }
+
+    glutSwapBuffers();
+
+    newtex = 0;
+
+    tick(0);
+
+}
+
+main(int argc, char *argv[])
+{
+    signal(SIGINT, catch);
+    justone = (getenv("JUSTONE") != NULL);
+    justload = (getenv("JUSTLOAD") != NULL);
+
+    glutInit( &argc, argv );
+    glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
+
+    glutCreateWindow( "eep" );
+    glutFullScreen();
+
+    glutIdleFunc( idler );
+    glutReshapeFunc( reshape );
+    glutDisplayFunc( redraw );
+    glutKeyboardFunc( kb );
+
+    glutMainLoop();
+}
Index: trunk/src/testing/app/bitplay/Makefile.32
===================================================================
--- trunk/src/testing/app/bitplay/Makefile.32	(revision 4)
+++ trunk/src/testing/app/bitplay/Makefile.32	(revision 4)
@@ -0,0 +1,53 @@
+COPTS = -g -O2 -Wall
+
+# GLUTDEFS = -DUSE_FREEGLUT
+# GLUTLIBS = -L/usr/X11R6/lib64 -lfreeglut-1.3 -lglib -lXxf86vm
+
+GLUTDIR = /usr/local/src/grap/glut-3.7.32
+GLUTDEFS = -I${GLUTDIR}/include
+GLUTLIBS = -L${GLUTDIR}/lib/glut -lglut -L/usr/X11R6/lib -lX11 -lXmu
+
+DEFS = ${GLUTDEFS}
+CFLAGS = ${COPTS} ${DEFS}
+LIBS = -lpthread
+
+IMGLIB = /u/src/grap/libimg
+IMAGELIB = /u/src/grap/libimage
+IMGLIBS = -L${IMGLIB} -limg -L${IMAGELIB} -limage -ltiff -ljpeg -lm
+IMGINCS = -I${IMGLIB} 
+GLLIBS  = ${GLUTLIBS} -lGL -lGLU -lm
+GLINCS  = -I/usr/X11R6/include
+
+PROGS = bplay32 img2bmv32 bpio32 onethread32
+
+all: ${PROGS}
+
+clean:
+	rm -f ${PROGS} *.o
+
+bplay32:	bplay32.o bpio32.o 
+	${CC} -o $@ bplay32.o bpio32.o ${GLLIBS} ${LIBS}
+
+bpio32.o: bpio.c bpio.h
+	${CC} -c -o $@ bpio.c ${COPTS} -O0 ${DEFS} ${GLINCS}
+
+bplay32.o: bplay.c bpio.h bpmovie.h
+	${CC} -o $@ -c bplay.c ${COPTS} ${DEFS} ${GLINCS}
+
+img2bmv32: img2bmv.c bpmovie.h ${IMGLIB}/libimg.a ${IMAGELIB}/libimage.a 
+	${CC} -c -o $@.o ${CFLAGS} ${IMGINCS} img2bmv.c
+	${CC} -o $@ $@.o ${COPTS} ${IMGLIBS}
+
+txspeed: txspeed.c
+	${CC} -o $@ $@.c -g -O ${GLINCS} ${GLLIBS}
+
+bpiotest32.o: bpiotest.c
+	${CC} -c -o $@ ${CFLAGS} bpiotest.c
+
+bpio32:	bpiotest32.o bpio32.o
+	${CC} -o $@ bpiotest32.o bpio32.o ${COPTS} ${LIBS}
+
+bpio32.o bpiotest32.o:	bpio.h
+
+onethread32: onethread.c
+	${CC} -o $@ onethread.c ${COPTS}
Index: trunk/src/testing/app/bitplay/libimg/getimginfo.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/getimginfo.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/getimginfo.c	(revision 4)
@@ -0,0 +1,415 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "imginfo.h"
+
+#include <image.h>
+#include <tiffio.h>
+#include <rasterfile.h>
+#include <softpic.h>
+
+/*
+ * Generic image-information routine.
+ * Given a file name, fills in an "imginfo" structure,
+ * and returns the type of image.
+ */
+
+
+char *imgtypename[] = {
+	"unknown", "tiff", "sgi", "ras", "soft", "gif", "pnm", "raw", "jpeg", NULL
+};
+
+#define MAXMAGIC  6
+
+struct imgdesc {
+	short magiclen;	/* Bytes in magic number.  -1 terminates known list. */
+	char magic[MAXMAGIC];	/* magic number */
+	int  (*getinfo)(); /* getinfo(filename) loads our global vars */
+};
+
+static int tiffinfo(), sgiinfo(), rasinfo(), softinfo(), gifinfo(),
+	pnminfo(), rawinfo(), jpeginfo();
+
+static struct imgdesc known[] = {
+	{ 2, { 'M','M' }, tiffinfo },		/* Big-endian Tiff */
+	{ 2, { 'I','I' }, tiffinfo },		/* Little-endian */
+	{ 2, { 0x01,0xDA }, sgiinfo },		/* SGI */
+	{ 4, { 0x59,0xA6,0x6A,0x95 }, rasinfo }, /* Sun */
+	{ 4, { 0x53,0x80,0xF6,0x34 }, softinfo }, /* SoftImage */
+	{ 5, { 'G','I','F','8','7' }, gifinfo }, /* GIF */
+	{ 5, { 'G','I','F','8','9' }, gifinfo }, /* GIF */
+	{ 4, { 0xff, 0xd8, 0xff, 0xe0 }, jpeginfo }, /* JPEG */
+	{ 1, { 'P' }, pnminfo },		/* PBM/PGM/PPM */
+	{ 0, { 0 }, rawinfo },			/* raw + imginfo header */
+	{ -1, { 0 }, NULL }
+};
+
+extern int pnm_getint( FILE * );
+
+int
+getimginfo(fname, info)
+    char *fname;
+    struct imginfo *info;
+{
+    register struct imgdesc *p;
+    int fd;
+    struct imginfo dummy;
+    char buf[MAXMAGIC];
+
+    if(info == NULL)
+	info = &dummy;
+
+    memset(info, 0, sizeof(struct imginfo));	/* Zero all fields */
+    if((fd = open(fname, 0)) < 0) {
+	fprintf(stderr, "%s: ", fname);
+	fflush(stderr);
+	perror("cannot open");
+	return I_UNKNOWN;
+    }
+    memset(buf, -1, MAXMAGIC);
+    (void) read(fd, buf, MAXMAGIC);
+    for(p = known; ; p++) {
+	if(p->magiclen < 0 ||
+	    ((p->magiclen == 0 || memcmp(p->magic, buf, p->magiclen) == 0)
+	     && (*p->getinfo)(info, fname, fd) == 0))
+	    break;
+    }
+    close(fd);
+    return info->kind;
+}
+
+/*
+ * Type-specific interpreters
+ */
+
+static int
+softinfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    struct softpict pic;
+    struct softpack packet;
+    int fields = 0;
+
+    lseek(fd, sizeof(struct softhdr), 0);
+    if(read(fd, &pic, sizeof(struct softpict)) != sizeof(struct softpict) ||
+		pic.id != SPICT_MAGIC)
+	return -1;
+    info->xsize = pic.width;
+    info->ysize = pic.height;
+    do {
+	if(read(fd, &packet, sizeof(struct softpack)) != sizeof(struct softpack))
+	    return -1;
+	packet.fields &= (SPICT_R|SPICT_G|SPICT_B|SPICT_A);
+	if(packet.fields) {
+	    info->sampbits = packet.nbits;
+	    fields |= packet.fields;
+	}
+    } while(packet.chained);
+
+    for(info->nsamp = 0; fields != 0; fields >>= 1)
+	info->nsamp += (fields & 1);
+
+    info->mapsize = info->mapsamp = 0;
+    info->kind = I_SOFT;
+    return 0;
+}
+
+/* big-endian to native conversions */
+
+static uint16 betohs( uint16 bes )
+{
+    static int one = 1;
+    return (*(char *)&one == 0)
+	? bes
+	: ((bes>>8)&0xFF) | (bes&0xFF)<<8;
+}
+
+static int
+sgiinfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    IMAGE imghdr;
+
+    (void) lseek(fd, 0L, 0);
+    (void) read(fd, &imghdr, sizeof(imghdr));
+
+    info->xsize = betohs( imghdr.xsize );
+    info->ysize = betohs( imghdr.ysize );
+    info->nsamp = betohs( imghdr.zsize );
+    info->sampbits = 8;
+    info->mapsize = info->mapsamp = 0;
+    info->kind = I_SGI;
+    return 0;
+}
+
+static int
+rasinfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    struct rasterfile ras;
+
+    lseek(fd, 0L, 0);
+    if(read(fd, &ras, sizeof(ras)) != sizeof(ras))
+	return -1;
+    info->xsize = ras.ras_width;
+    info->ysize = ras.ras_height;
+    info->sampbits = ras.ras_depth == 24 ? 8 : ras.ras_depth;
+    if(ras.ras_maptype != RMT_NONE) {
+	info->mapsize = ras.ras_maplength / 3;
+	info->mapsamp = 3;
+	info->nsamp = 1;
+    } else {
+	info->mapsize = info->mapsamp = 0;
+	info->nsamp = (ras.ras_depth == 24) ? 3 : 1;
+    }
+    info->kind = I_SUNRAS;
+    return 0;
+}
+
+
+static int
+tiffinfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    TIFF *tif;
+    uint16 photometric;
+    uint16 bits = 8;
+    uint16 nsamp = 1;
+    uint32 xsize, ysize;
+
+    tif = TIFFOpen(fname, "r");
+    if(tif == NULL)
+	return -1;
+
+    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &xsize);
+    info->xsize = xsize;
+    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &ysize);
+    info->ysize = ysize;
+    TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits);
+    info->sampbits = bits;
+    TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &nsamp);
+    info->nsamp = nsamp;
+    if(TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric) &&
+			photometric == PHOTOMETRIC_PALETTE) {
+	info->mapsize = 1 << info->sampbits;
+	info->mapsamp = 3;
+    } else {
+	info->mapsize = info->mapsamp = 0;
+    }
+    info->kind = I_TIFF;
+    TIFFClose(tif);
+    return 0;
+}
+
+static int
+gifinfo(info, fname, fd)
+register struct imginfo *info;
+char *fname;
+int fd;
+{
+   unsigned char tmp[10], ch, a, b;
+
+   lseek(fd, 0L, 0);
+   read(fd, tmp, 6);				/* skip magic # */
+   if(tmp[5] != 'a' && tmp[5] != 'A')		/* "GIF87A" or "GIF87a" */
+      return -1;
+   read(fd, &a, 1);
+   read(fd, &b, 1);
+   info->xsize = a + 0x100 * b;
+   read(fd, &a, 1);
+   read(fd, &b, 1);
+   info->ysize = a + 0x100 * b;
+   read(fd, &ch, 1);
+   info->sampbits = (ch & 7) + 1;
+   info->mapsize = 1 << info->sampbits;
+   info->mapsamp = 3;
+   info->nsamp = 1;
+   info->kind = I_GIF;
+   return 0;
+}
+
+#include <jpeglib.h>
+
+static int
+jpeginfo( struct imginfo *info, char *fname, int fd )
+{
+   struct jpeg_decompress_struct jp[1];
+   struct jpeg_error_mgr jerr[1];
+   FILE *jf = fdopen( fd, "r" );
+   int fail = -1;
+
+   if(jf == NULL)
+	return -1;
+   lseek( fd, 0, 0 );
+   jp->err = jpeg_std_error( jerr );
+   jpeg_create_decompress( jp );
+   jpeg_stdio_src( jp, jf );
+   if(jpeg_read_header( jp, TRUE ) != JPEG_HEADER_OK)
+	goto done;
+
+   jpeg_calc_output_dimensions( jp );
+   info->xsize = jp->output_width;
+   info->ysize = jp->output_height;
+   info->nsamp = jp->output_components;
+   info->mapsize = 0;
+   info->mapsamp = 0;
+   info->sampbits = 8;
+   info->kind = I_JPEG;
+   fail = 0;
+ done:
+   jpeg_destroy( (j_common_ptr)jp );
+   fclose(jf);
+   return fail;
+}
+
+static int
+rawinfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    char buf[256];
+    register int i, n;
+
+    for(n = sizeof(buf)-1; (i = read(fd, buf+sizeof(buf)-1-n, n)) > 0; n -= i)
+	;
+
+    n = sizeof(buf)-1 - n;
+    if(n <= 0)
+	return -1;
+    buf[n] = '\0';
+    if(sscanf(buf, "%*s %d %d %d %d %d %d",
+		&info->xsize, &info->ysize, &info->nsamp, &info->mapsize,
+		&info->mapsamp, &info->sampbits) == 6) {
+	info->kind = I_RAW;
+	return 0;
+    }
+    return -1;
+}
+
+static int
+pnminfo(info, fname, fd)
+    register struct imginfo *info;
+    char *fname;
+    int fd;
+{
+    FILE *f = fdopen(fd, "r");
+    int c;
+
+    fseek(f, 1L, 0);
+    c = fgetc(f);
+    info->mapsize = info->mapsamp = 0;
+    switch(c) {
+    case '1': case '4':
+	info->sampbits = 1;
+	info->nsamp = 1;
+	break;
+    case '2': case '5':
+	info->sampbits = 8;
+	info->nsamp = 1;
+	break;
+    case '3': case '6':
+	info->sampbits = 8;
+	info->nsamp = 3;
+	break;
+    default:
+	return -1;
+    }
+
+    info->xsize = pnm_getint(f);
+    info->ysize = pnm_getint(f);
+    fclose(f);
+    if(info->xsize <= 0 || info->ysize <= 0)
+	return -1;
+
+    info->kind = I_PNM;
+    return 0;
+}
+
+int
+pnm_skipwhite(f)
+    register FILE *f;
+{
+    register int c;
+
+    for(;;) {
+	switch(c = fgetc(f)) {
+	case '#':
+	    do { c = fgetc(f); } while(c != '\n' && c != EOF);
+	    if(c == EOF)
+		return EOF;
+	    break;
+	case ' ': case '\t': case '\n': case '\r': break;
+
+	case EOF: return EOF;
+	default:
+	    ungetc(c, f);
+	    return c;
+	}
+    }
+}
+
+int
+pnm_getint(f)
+    register FILE *f;
+{
+    register int n = 0;
+    register int c;
+    register int neg = 0;
+
+    switch(pnm_skipwhite(f)) {
+    case '-': neg = 1;
+    case '+': fgetc(f);
+    }
+    while((c = fgetc(f)) >= '0' && c <= '9')
+	n = n*10 + c-'0';
+    if(c != EOF)
+	ungetc(c, f);
+    return neg ? -n : n;
+}
Index: trunk/src/testing/app/bitplay/libimg/tiffdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/tiffdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/tiffdisp.c	(revision 4)
@@ -0,0 +1,78 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "tiffio.h"
+#include "imginfo.h"
+#include <sys/types.h>
+
+
+#define	rgba(r, g, b, a)	((a)<<24 | (b)<<16 | (g)<<8 | (r))
+#define	rgbi(r, g, b)		(0xFF000000 | (b)<<16 | (g)<<8 | (r))
+
+IMG *
+TIFFmakedisp( char *fname )
+{
+	TIFF *tif;
+	register IMG *im;
+	long width, height;
+
+	tif = TIFFOpen(fname, "r");
+	if(tif == NULL)
+	    return NULL;
+
+	TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
+	TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
+	im = (IMG *)malloc(sizeof(IMG));
+	im->type = IT_LONG;
+	im->rowbytes = width * sizeof(long);
+	im->xsize = width;
+	im->ysize = height;
+	im->data = (unsigned char *)malloc(im->rowbytes * height);
+	if(im->data == NULL) {
+	    fprintf(stderr, "Can't malloc %ld bytes of memory for image\n",
+		(long) (im->rowbytes * height));
+	    exit(2);
+	}
+	if(TIFFReadRGBAImage(tif, width, height, (uint32 *)im->data, 0) == 0) {
+	    free(im->data);
+	    free(im);
+	    im = NULL;
+	}
+	TIFFClose(tif);
+	return im;
+}
Index: trunk/src/testing/app/bitplay/libimg/pnmdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/pnmdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/pnmdisp.c	(revision 4)
@@ -0,0 +1,182 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Given a Sun raster file, return a DISPIMAGE
+ * containing its raster data and with size <= (xsize, ysize).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+/* #include "rasterfile.h" */
+#include "imginfo.h"
+
+extern int pnm_getint( FILE * );
+
+IMG *
+pnmmakedisp(filename)
+    char *filename;
+{
+    register FILE *f;
+    IMG *di = NULL;
+    int maxpix = 0, pnmkind;
+    int xsize, ysize;
+    int y;
+    int c;
+
+    f = fopen(filename, "r");
+    if(f == NULL) {
+	fprintf(stderr, "%s: cannot open: ", filename);
+	perror("");
+	return NULL;
+    }
+
+    if(fgetc(f) != 'P')
+	goto fail;
+
+    pnmkind = fgetc(f);
+
+    xsize = pnm_getint(f);
+    ysize = pnm_getint(f);
+    switch(pnmkind) {
+    case '1': case '4':
+	maxpix = 1;
+	break;
+    case '2': case '5': /* fall into ... */
+    case '3': case '6':
+	maxpix = pnm_getint(f);
+	break;
+    default:
+	goto fail;
+    }
+    if(xsize <= 0 || ysize <= 0 || maxpix <= 0)
+	goto fail;
+
+    if(pnmkind >= '4') {
+	/* Skip to end of line, after which the binary data should follow */
+	while((c = fgetc(f)) != EOF && c != '\n')
+	    ;
+    }
+
+    di = (IMG *)malloc(sizeof(IMG));
+    if(pnmkind == '1' || pnmkind == '4') {
+	di->type = IT_BIT;
+	di->rowbytes = (xsize+31)/32 * 4;
+    } else {
+	di->type = IT_LONG;
+	di->rowbytes = xsize*4;
+    }
+    di->xsize = xsize;
+    di->ysize = ysize;
+    di->data = malloc(di->rowbytes * ysize);
+    if(di->data == NULL) {
+	fprintf(stderr, "Can't malloc %d bytes of memory for image\n",
+	    di->rowbytes*ysize);
+	exit(2);
+    }
+    for(y = ysize; --y >= 0; ) {
+	register int v;
+	register long *rp;
+	register int x;
+
+	rp = (long *)(di->data + y*di->rowbytes);
+	x = xsize;
+	switch(pnmkind) {
+	case '1':
+	    do {
+		*rp++ = 0xff000000 | -pnm_getint(f);
+	    } while(--x > 0);
+	    break;
+	case '2':
+	    do {
+		v = (255 * pnm_getint(f) / maxpix);
+		*rp++ = 0xff000000 | (v << 16) | (v<<8) | v;
+	    } while(--x > 0);
+	    break;
+	case '3':
+	    do {
+		v = (255 * pnm_getint(f) / maxpix);
+		v |= (255 * pnm_getint(f) / maxpix) << 8;
+		*rp++ = v | (255 * pnm_getint(f) / maxpix) << 16;
+	    } while(--x > 0);
+	    break;
+	case '4':
+	    fread(rp, (xsize+7)/8, 1, f);	/* Bit mode */
+	    break;
+	case '5':
+	    if(maxpix != 255) {
+		do {
+		    v = 255 * getc(f) / maxpix;
+		    *rp++ = 0xff000000 | (v << 16) | (v << 8) | v;
+		} while(--x > 0);
+	    } else {
+		do {
+		    v = getc(f);
+		    *rp++ = 0xff000000 | (v << 16) | (v << 8) | v;
+		} while(--x > 0);
+	    }
+	    break;
+	case '6':
+	    if(maxpix != 255) {
+		do {
+		    v = 255 * getc(f) / maxpix;
+		    v |= (255 * getc(f) / maxpix) << 8;
+		    *rp++ = 0xff000000 | ((255 * getc(f) / maxpix) << 16) | v;
+		} while(--x > 0);
+	    } else {
+		do {
+		    v = getc(f);
+		    v |= getc(f) << 8;
+		    *rp++ = 0xff000000 | (getc(f) << 16) | v;
+		} while(--x > 0);
+	    }
+	    break;
+	}
+    }
+
+    if(f != NULL)
+	fclose(f);
+    return di;
+
+  fail:
+    if(di) {
+	if(di->data) free(di->data);
+	free(di);
+    }
+    if(f != NULL)
+	fclose(f);
+    return NULL;
+}
Index: trunk/src/testing/app/bitplay/libimg/softdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/softdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/softdisp.c	(revision 4)
@@ -0,0 +1,252 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "softpic.h"
+#include "imginfo.h"
+
+#define TRUE	1
+#define FALSE	0
+
+#define DEBUG FALSE
+
+static int xsize, ysize, nbits[10], file_chained[10], fields[10], file_type[10], ndsc;
+FILE *in_fle;
+float m, n;
+char *liner, *lineg, *lineb, *linea;
+
+static int check_file_header(fle)
+FILE *fle;
+{
+   struct softhdr hd;
+
+   fread(&hd, sizeof(struct softhdr), 1, fle);
+   if (hd.id != SOFT_MAGIC)
+      return FALSE;
+   if (DEBUG) {
+      fprintf(stderr, "creator version: %f\n", hd.version);
+      fprintf(stderr, "internal comment: %s\n", hd.comment);
+   }
+   return TRUE;
+}
+
+static int check_pic_header(fle)
+FILE *fle;
+{
+   struct softpict hd;
+
+   fread(&hd, sizeof(struct softpict), 1, fle);
+   if (hd.id != SPICT_MAGIC)
+      return FALSE;
+   if (DEBUG) {
+      fprintf(stderr, "picture dimensions: %d X %d.\n", hd.width, hd.height);
+      fprintf(stderr, "picture pixel ratio (X/Y): %f.\n", hd.ratio);
+      fprintf(stderr, "picture fields: %s.\n", (hd.fields == 1)?"odd":(hd.fields == 2)?"even":"full-frame");
+   }
+   xsize = hd.width;
+   ysize = hd.height;
+   liner = (char *)malloc(xsize * sizeof(char));
+   lineg = (char *)malloc(xsize * sizeof(char));
+   lineb = (char *)malloc(xsize * sizeof(char));
+   linea = (char *)malloc(xsize * sizeof(char));
+   bzero(liner, xsize*sizeof(char));
+   bzero(lineg, xsize*sizeof(char));
+   bzero(lineb, xsize*sizeof(char));
+   bzero(linea, xsize*sizeof(char));
+   return TRUE;
+}
+
+static void get_pack_chunk( FILE *fle, int n)
+{
+   struct softpack hd;
+
+   fread(&hd, sizeof(struct softpack), 1, fle);
+   file_chained[n] = hd.chained;
+   nbits[n] = hd.nbits;
+   file_type[n] = hd.type;
+   fields[n] = hd.fields;
+   if (DEBUG) {
+      fprintf(stderr, "pack info #%d:\n", n);
+      fprintf(stderr, "\tnbits = %d\n", nbits[n]);
+      fprintf(stderr, "\ttype = %x\n", file_type[n]);
+      fprintf(stderr, "\tfields = %x\n", fields[n]);
+   }
+   ndsc = n;
+   if (nbits[n] != 8) {
+      fprintf(stderr, "Error: This program only handles 8 bit data.\n");
+      exit(1);
+   }
+   if (file_chained[n] != 0) get_pack_chunk(fle, (n+1));
+}
+
+static void mixed_read_rle_part( FILE *fle, short cnt, int lne, int strt, int fld )
+{
+   register int i;
+   register int mask;
+   char r, g, b, a;
+
+   mask = fields[fld];
+   if ((mask & SPICT_R) != 0)
+      r = getc(fle);
+   if ((mask & SPICT_G) != 0)
+      g = getc(fle);
+   if ((mask & SPICT_B) != 0)
+      b = getc(fle);
+   if ((mask & SPICT_A) != 0)
+      a = getc(fle);
+   for (i = strt; i<=strt+cnt; i++) {
+      if ((mask & SPICT_R) != 0)
+	 liner[i] = r;
+      if ((mask & SPICT_G) != 0)
+	 lineg[i] = g;
+      if ((mask & SPICT_B) != 0)
+	 lineb[i] = b;
+      if ((mask & SPICT_A) != 0)
+	 linea[i] = a;
+   }
+}
+
+static void mixed_read_norm_part( FILE *fle, short cnt, int lne, int strt, int fld )
+{
+   register int i;
+
+   for (i = strt; i<=strt+cnt; i++) {
+      if ((fields[fld] & SPICT_R) != 0)
+	 liner[i] = getc(fle);
+      if ((fields[fld] & SPICT_G) != 0)
+	 lineg[i] = getc(fle);
+      if ((fields[fld] & SPICT_B) != 0)
+	 lineb[i] = getc(fle);
+      if ((fields[fld] & SPICT_A) != 0)
+	 linea[i] = getc(fle);
+   }
+}
+
+static void mixed_read_line( FILE *fle, int lne, int fld )
+{
+   int x = 0;
+   short size;
+   int cnt;
+
+   do {
+       cnt = getc(fle);
+       if (cnt == 0x80) {
+	  size = getc(fle) << 8;
+	  size |= getc(fle);
+	  size--;
+       } else
+	  size = cnt & 0x7f;
+       if ((cnt & 0x80) == 0)
+	  mixed_read_norm_part(fle, size, lne, x, fld);
+       else
+	  mixed_read_rle_part(fle, size, lne, x, fld);
+       x += size + 1;
+   } while (x < xsize);
+}
+
+static void output_line( int lne, IMG *im )
+{
+   int i;
+   register char *l;
+   register char *r, *g, *b, *a;
+
+   l = (char *)&im->data[(ysize - lne - 1)*im->rowbytes];
+   a = linea; r = liner; g = lineg; b = lineb;
+   i = xsize;
+   do {
+	*l++ = *a++;
+	*l++ = *b++;
+	*l++ = *g++;
+	*l++ = *r++;
+   } while(--i > 0);
+}
+
+static void load_file( FILE *fle, IMG *im )
+{
+   int y, fcnt;
+
+   im->xsize = xsize;
+   im->ysize = ysize;
+   im->rowbytes = xsize*sizeof(long);
+   im->data = malloc(ysize * im->rowbytes);
+   for (y = 0; y < ysize; y++) {
+      for (fcnt = 0; fcnt <= ndsc; fcnt++) {
+	 if (file_type[fcnt] == SPICT_MIXEDRLE) {
+	    mixed_read_line(fle, y, fcnt);
+	 } else {
+	    fprintf(stderr, "don't know pack type 0x%x\n", file_type[fcnt]);
+	    exit(1);
+	 }
+      }
+      output_line(y, im);
+   }
+}
+
+static void close_files( FILE *in )
+{
+   fclose(in);
+   free(liner);
+   free(lineg);
+   free(lineb);
+   free(linea);
+}
+
+IMG *softmakedisp(name)
+char *name;
+{
+   IMG *out;
+
+   in_fle = fopen(name, "rb");
+   if(in_fle == NULL)
+	return NULL;
+   if (!check_file_header(in_fle)) {
+      fprintf(stderr, "ERROR in file header! The world has already come to an end!\n");
+      return NULL;
+   }
+   if (!check_pic_header(in_fle)) {
+      fprintf(stderr, "ERROR in picure header! The world will soon come to an end.\n");
+      return NULL;
+   }
+   out = (IMG *)malloc(sizeof(IMG));
+   out->type = IT_LONG;
+   get_pack_chunk(in_fle, 0);
+   load_file(in_fle, out);
+   close_files(in_fle);
+   return out;
+}
Index: trunk/src/testing/app/bitplay/libimg/Makefile
===================================================================
--- trunk/src/testing/app/bitplay/libimg/Makefile	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/Makefile	(revision 4)
@@ -0,0 +1,16 @@
+COPTS = -O2
+INCL  = -I. -I/opt/local/include/
+CFLAGS = ${INCL} ${COPTS}
+OBJS = softdisp.o tiffdisp.o rasdisp.o sgidisp.o jpegdisp.o pnmdisp.o gifdisp.o getimginfo.o getimgdata.o
+
+LIB = libimg.a
+
+${LIB}: ${OBJS}
+	ar rv $@ ${OBJS}
+	ranlib $@
+
+.PRECIOUS: ${LIB}
+
+clean:
+	/bin/rm -f *~ libimg.a *.o
+
Index: trunk/src/testing/app/bitplay/libimg/softpic.h
===================================================================
--- trunk/src/testing/app/bitplay/libimg/softpic.h	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/softpic.h	(revision 4)
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * SoftImage picture file format (.pic).
+ * Transcribed from their printed documentation.
+ *
+ * Ratio: is the aspect ratio of pixels for this image.
+ *  This aspect is the ratio X/Y (if a pixel is 2x wider than tall,
+ *   the ratio is 2.0).  For displaying images on output devices
+ *   with aspect ratio different from 1.0.
+ *
+ * N.B. The pixel ratio is computed according to Full Frame.
+ *
+ * Fields: which scan-lines are present in the picture file.
+ * For normal images this will be Full-frame (3), but if you use video
+ * output you will probably want to double the time sampling and compute
+ * only fields (every alternate scan line).
+ * The field containing the top scan-line is the ODD one (1), the other
+ * is EVEN (2).  The field sequence for NTSC is E-O-E-O...,
+ * while for PAL O-E-O-E...
+ *
+ * Chained: this flag indicates the presence of other packets, generally
+ * it is 1 except for the last packet where it's 0.
+ *
+ * Encoding part: all encoding data are coded byte-by-byte (with some
+ * exceptions) so when we code raw information, we have each byte following
+ * each other.  For example, here is a 512x512 RGBA picture:
+ *
+ * <FILE-CHUNK>
+ *  id = 0x5380f643
+ *  vers = 1.2 (only informatiive info)
+ *  comment = 'none'
+ *
+ * <PICT-CHUNK>
+ *  id='PICT'
+ *  width=512
+ *  height=512
+ *  ratio=1.0
+ *  fields=3 (full-frame)
+ *  padding=(unused)
+ *
+ * <PACK-CHUNK>
+ *  chained=1
+ *  nb bits=8
+ *  type=0
+ *  fields=224 (red+green+blue)
+ *
+ * <PACK-CHUNK>
+ *  chained=0
+ *  nb bits=8
+ *  type=0
+ *  fields=16 (alpha)
+ *
+ * <SCAN-LINE 1>
+ *  R,G,B,... (3x512 bytes)
+ *  A,A,A,... (512 bytes)
+ *
+ * <SCAN-LINE 2>
+ *  R,G,B,...
+ *  A,...
+ * ...
+ *
+ */
+
+/*
+ * All binary files have a similar header:
+ */
+
+struct softhdr {
+	unsigned long id;	/* SoftImage magic number */
+#define SOFT_MAGIC  0x5380f634
+
+	float	version;	/* Version of system that produced it */
+	char	comment[80];	/* user-definable comment */
+};
+
+/*
+ * Then follows the specific chunk for the type of file (here .pic):
+ */
+
+struct softpict {
+	unsigned long	id;	/* 'PICT' */
+#define	SPICT_MAGIC	0x50494354
+
+	short	width, height;	/* in pixels */
+	float	ratio;		/* Pixel ratio (X/Y) */
+	short	fields;		/* 1=odd, 2=even, 3=full-frame */
+	short	padding;	/* (to pad this struct to 4-byte multiple) */
+};
+
+/*
+ * Now the associated data.
+ * For a picture file we find first a list of descriptor packets.
+ * A packet describes how the different fields of an image are coded, i.e.
+ * which fields are coded together, the type of data (integer, float &c)
+ * and the compression technique.
+ */
+
+struct softpack {		/* Pack chunk */
+	unsigned char chained;	/* another pack chunk follows this one */
+	unsigned char nbits;	/* bits per data value (8?) */
+	unsigned char type;	/* bit-field describing data format: */
+#define	SPICT_UINT	0x00	/* unsigned int */
+#define	SPICT_SINT	0x10	/* signed int */
+#define	SPICT_FLOAT	0x20	/* float */
+#define	SPICT_NOCOMP	0x00	/* uncompressed */
+#define	SPICT_PURERLE	0x01	/* "pure" run-length encoded */
+#define	SPICT_MIXEDRLE	0x02	/* "mixed" run-length encoded */
+
+	unsigned char fields;	/* bit-field describing what data are present */
+#define	SPICT_R		0x80	/*  red */
+#define	SPICT_G		0x40	/*  green */
+#define	SPICT_B		0x20	/*  blue */
+#define	SPICT_A		0x10	/*  alpha */
+#define	SPICT_SHADOW	0x08	/*  shadow */
+#define	SPICT_DEPTH	0x04	/*  depth */
+#define	SPICT_AUX1	0x02	/*  auxiliary 1 */
+#define	SPICT_AUX2	0x01	/*  auxiliary 2 */
+
+};
+
Index: trunk/src/testing/app/bitplay/libimg/imginfo.h
===================================================================
--- trunk/src/testing/app/bitplay/libimg/imginfo.h	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/imginfo.h	(revision 4)
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Header for generic-image access routines:
+ *	getimginfo(), getimgdata()
+ */
+
+
+#define	I_UNKNOWN 0		/* unknown type or inaccessible */
+#define	I_TIFF	1		/* TIFF raster image */
+#define	I_SGI	2		/* SGI raster image */
+#define	I_SUNRAS 3		/* Sun raster file */
+#define	I_SOFT	4		/* SoftImage raster image */
+#define I_GIF   5		/* GIF image */
+#define	I_PNM	6		/* Portable bit/gray/pixmap */
+#define	I_RAW	7		/* raw image with imginfo header */
+#define	I_JPEG	8		/* JPEG image */
+
+struct imginfo {
+	int kind;		/* Image type -- I_TIFF, I_SGI, ... */
+	int xsize, ysize;	/* Image size */
+	int nsamp;		/* Samples per pixel of image data */
+	int sampbits;		/* Bits per sample */
+	int mapsize;		/* Colormap entries (0 if absent) */
+	int mapsamp;		/* Samples per colormap entry (0 if absent) */
+};
+
+typedef struct img {
+#define	IT_LONG	0		/* 32 bits per, ABGR, A is low-address byte */
+#define	IT_BIT	1		/* bit packed in bytes, MSB first */
+#define	IT_RGB	2		/* 24 bits per RGB, R is low-address byte */
+#define	IT_BYTE	3		/* 8 bits gray-scale */
+	int type;
+	int xsize, ysize;	/* image size in pixels */
+	int rowbytes;		/* size of each image row, in bytes */
+	unsigned char *data;	/* image data */
+} IMG;
+
+	/*
+	 * getimginfo returns image type, one of the I_* below.
+	 * It prints an error (only) if the file cannot even be opened.
+	 *
+	 * getimgdata diagnoses image type and also
+	 */
+extern int getimginfo( char *fname, struct imginfo *info );
+
+extern unsigned char *getimgdata(
+	const char *fname,		/* file name */
+	const struct imginfo *knowninfo, /* image info, if you have it */
+	struct imginfo *info,		/* image info, filled in by getimgdata */
+	int yup,			/* first row is... 0:bottom, 1:top */
+	int bpp,			/* bytes per pixel, or 0:use image */
+	int byteorder			/* 0: RGBA, 1: ABGR */
+    );
+extern char *imgtypename[];
Index: trunk/src/testing/app/bitplay/libimg/sgidisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/sgidisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/sgidisp.c	(revision 4)
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <image.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <sys/types.h>
+#include "image.h"
+#include "imginfo.h"
+
+IMG *
+SGImakedisp(fname)
+	char *fname;
+{
+	IMAGE *image;
+	register IMG *im;
+	unsigned short *trow;
+	register int k;
+	int width, height;
+	int y, z;
+	static int one = 1;
+
+	int littleendian = (*(char *)&one == 1);
+
+	image = iopen(fname, "r");
+	if(image == NULL)
+	    return NULL;
+
+	width = image->xsize;
+	height = image->ysize;
+	im = (IMG *)malloc(sizeof(IMG));
+	im->rowbytes = sizeof(IMulong) * width;
+	im->type = IT_LONG;
+	im->xsize = width;
+	im->ysize = height;
+	im->data = (unsigned char *)malloc(im->rowbytes * height + (sizeof(short)*width));
+	if(im->data == NULL) {
+	    fprintf(stderr, "Can't malloc %d bytes of memory for image\n",
+		im->rowbytes * height);
+	    exit(2);
+	}
+	trow = (unsigned short *)(im->data + im->rowbytes * height);
+	if(image->zsize == 3)
+	    memset(im->data, 255, im->rowbytes * height);
+
+	for(y = 0; y < image->ysize; y++) {
+	    for(z = 0; z < image->zsize; z++) {
+		register unsigned char *op;
+		register unsigned short *ip;
+
+
+		getrow(image, trow, y, z);
+		k = image->xsize;
+		op = (unsigned char *) (im->data + im->rowbytes * y)
+					+ (littleendian ? z : 3 - z);
+		ip = trow;
+		do {
+		    *op = *ip++;
+		    op += sizeof(IMulong);
+		} while(--k > 0);
+	    }
+	}
+	if(image->zsize == 1) {
+	    register IMulong *op;
+	    register int v;
+
+	    k = image->xsize * image->ysize;
+	    op = (IMulong *)im->data;
+	    do {
+		v = (*op & 0xFF);	/* XXX byte-order dependent */
+		*op++ = v | (v<<8) | (v<<16) | 0xFF000000;
+	    } while(--k > 0);
+	}
+	iclose(image);
+
+	return im;
+}
Index: trunk/src/testing/app/bitplay/libimg/tiffdata.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/tiffdata.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/tiffdata.c	(revision 4)
@@ -0,0 +1,475 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef lint
+static char sccsid[] = "@(#)sgigt.c	1.8 4/25/89";
+#endif
+
+#include <stdio.h>
+#include <gl.h>
+#include <gl/device.h>
+#include "tiffio.h"
+#include "imginfo.h"
+
+static u_long	*raster;			/* displayable image */
+static u_short	bitspersample;
+static u_short	samplesperpixel;
+static u_short	photometric;
+static u_short	orientation;
+static u_short	*redcmap, *greencmap, *bluecmap;/* colormap for palette images */
+
+#define	rgba(r, g, b, a)	((a)<<24 | (b)<<16 | (g)<<8 | (r))
+#define	rgbi(r, g, b)		(0xFF000000 | (b)<<16 | (g)<<8 | (r))
+
+IMG *
+TIFFmakedisp(fname)
+	char *fname;
+{
+	TIFF *tif;
+	short width, height;
+	register IMG *im;
+
+	tif = TIFFOpen(fname, "r");
+	if(tif == NULL)
+	    return NULL;
+
+	TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
+	TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
+	im = (IMG *)malloc(sizeof(IMG));
+	im->type = IT_LONG;
+	im->rowbytes = sizeof(long) * width;
+	im->xsize = width;
+	im->ysize = height;
+	im->data = (unsigned char *)malloc(im->rowbytes * height);
+	if(im->data == NULL) {
+	    fprintf(stderr, "Can't malloc %d bytes of memory for image\n",
+		im->rowbytes * height);
+	    exit(2);
+	}
+	if(tiffgt(tif, width, height, (u_long *)im->data) == 0) {
+	    free(im->data);
+	    free(im);
+	    im = NULL;
+	}
+	TIFFClose(tif);
+	return im;
+}
+
+RGBvalue **BWmap;
+
+static
+tiffgt(tif, w, h, raster)
+	TIFF *tif;
+	int w, h;
+	u_long *raster;
+{
+	u_short minsamplevalue, maxsamplevalue, planarconfig;
+	RGBvalue *Map;
+	int e;
+
+	if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
+		switch (samplesperpixel) {
+		case 1:
+			photometric = PHOTOMETRIC_MINISBLACK;
+			break;
+		case 3: case 4:
+			photometric = PHOTOMETRIC_RGB;
+			break;
+		default:
+			fprintf(stderr, "Missing needed \"%s\" tag.\n",
+			    "PhotometricInterpretation");
+			return (0);
+		}
+		printf("No \"PhotometricInterpretation\" tag, assuming %s.\n",
+		    photometric == PHOTOMETRIC_RGB ? "RGB" : "min-is-black");
+	}
+	if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel))
+		samplesperpixel = 1;
+	if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample))
+		bitspersample = 8;
+	if (!TIFFGetField(tif, TIFFTAG_MINSAMPLEVALUE, &minsamplevalue))
+		minsamplevalue = 0;
+	if (!TIFFGetField(tif, TIFFTAG_MAXSAMPLEVALUE, &maxsamplevalue))
+		maxsamplevalue = (1<<bitspersample)-1;
+	Map = NULL;
+	switch (photometric) {
+	case PHOTOMETRIC_RGB:
+	case PHOTOMETRIC_MINISBLACK:
+		if (minsamplevalue == 0 && maxsamplevalue == 255)
+			break;
+		/* fall thru... */
+	case PHOTOMETRIC_MINISWHITE: {
+		register int x, range;
+
+		range = maxsamplevalue - minsamplevalue + 1;
+		Map = (RGBvalue *)malloc(range * sizeof (RGBvalue));
+		if (Map == NULL) {
+			fprintf(stderr,
+			    "No space for photometric conversion table.\n");
+			return (0);
+		}
+		if (photometric == PHOTOMETRIC_MINISWHITE) {
+			for (x = 0; x < range; x++)
+				Map[x] = ((range - x) * 255) / range;
+		} else {
+			for (x = 0; x < range; x++)
+				Map[x] = (x * 255) / range;
+		}
+		if (bitspersample < 8 && photometric != PHOTOMETRIC_RGB) {
+			if (!makebwmap(Map))
+				return (0);
+			/* no longer need Map, free it */
+			free((char *)Map);
+			Map = NULL;
+		}
+		break;
+	}
+	case PHOTOMETRIC_PALETTE:
+		if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+		    &redcmap, &greencmap, &bluecmap)) {
+			fprintf(stderr, "Missing required \"Colormap\" tag.\n");
+			return (0);
+		}
+		break;
+	}
+	TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
+	if (planarconfig == PLANARCONFIG_SEPARATE)
+		e = gtseparate(tif, raster, Map, h, w);
+	else
+		e = gtcontig(tif, raster, Map, h, w);
+	if (Map)
+		free((char *)Map);
+	return (e);
+}
+
+setorientation(tif, h)
+	TIFF *tif;
+	int h;
+{
+	int y;
+
+	if (!TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation))
+		orientation = ORIENTATION_TOPLEFT;
+	switch (orientation) {
+	case ORIENTATION_BOTRIGHT:
+	case ORIENTATION_RIGHTBOT:	/* XXX */
+	case ORIENTATION_LEFTBOT:	/* XXX */
+		printf("Warning, using bottom-left orientation.\n");
+		orientation = ORIENTATION_BOTLEFT;
+		/* fall thru... */
+	case ORIENTATION_BOTLEFT:
+		y = 0;
+		break;
+	case ORIENTATION_TOPRIGHT:
+	case ORIENTATION_RIGHTTOP:	/* XXX */
+	case ORIENTATION_LEFTTOP:	/* XXX */
+		printf("Warning, using top-left orientation.\n");
+		orientation = ORIENTATION_TOPLEFT;
+		/* fall thru... */
+	case ORIENTATION_TOPLEFT:
+		y = h-1;
+		break;
+	}
+	return (y);
+}
+
+gtcontig(tif, raster, Map, h, w)
+	TIFF *tif;
+	u_long *raster;
+	register RGBvalue *Map;
+	int h, w;
+{
+	register u_char *pp;
+	register u_long *cp;
+	register int x;
+	int scanline, row, y;
+	u_char *buf;
+
+	buf = (u_char *)malloc(TIFFScanlineSize(tif));
+	if (buf == 0) {
+		fprintf(stderr, "No space for scanline buffer\n");
+		return (0);
+	}
+	y = setorientation(tif, h);
+	for (row = 0; row < h; row++) {
+		if (TIFFReadScanline(tif, buf, row, 0) < 0)
+			break;
+		pp = buf;
+		cp = raster + y*w;
+		switch (photometric) {
+		case PHOTOMETRIC_RGB:
+		    rgb:
+			switch (bitspersample) {
+			case 8:
+				if (Map) {
+					for (x = w; x-- > 0;) {
+						pp[0] = Map[pp[0]];
+						pp[1] = Map[pp[1]];
+						pp[2] = Map[pp[2]];
+						pp += samplesperpixel;
+					}
+					pp = buf;
+				}
+				if(samplesperpixel == 4) {
+				    for(x = w; --x >= 0; pp += 4)
+					*cp++ = rgba(pp[0], pp[1], pp[2],pp[3]);
+				} else {
+				    for (x = w; x-- > 0; pp += samplesperpixel)
+					*cp++ = rgbi(pp[0], pp[1], pp[2]);
+				}
+				break;
+			case 16: {
+				register u_short *wp;
+
+				if (Map) {
+					wp = (u_short *)pp;
+					for (x = w; x-- > 0;) {
+						wp[0] = Map[wp[0]];
+						wp[1] = Map[wp[1]];
+						wp[2] = Map[wp[2]];
+						wp += samplesperpixel;
+					}
+				}
+				wp = (u_short *)pp;
+				for (x = w; x-- > 0;) {
+					*cp++ = rgbi(wp[0], wp[1], wp[2]);
+					wp += samplesperpixel;
+				}
+				break;
+			}
+			}
+			break;
+		case PHOTOMETRIC_PALETTE:
+			for (x = w; x-- > 0;) {
+				RGBvalue c = *pp++;
+				*cp++ = rgbi(redcmap[c],
+				    greencmap[c], bluecmap[c]);
+			}
+			break;
+		case PHOTOMETRIC_MINISWHITE:
+		case PHOTOMETRIC_MINISBLACK:
+			if(samplesperpixel > 1)
+				goto rgb;
+
+			if (bitspersample == 8) {
+				register RGBvalue c;
+
+				for (x = w; x-- > 0;) {
+					c = Map[*pp++];
+					*cp++ = rgbi(c, c, c);
+				}
+			} else
+				gtbw(bitspersample, w, cp, pp);
+			break;
+		}
+		y += (orientation == ORIENTATION_TOPLEFT ? -1 : 1);
+	}
+	return (1);
+}
+
+gtseparate(tif, raster, Map, h, w)
+	TIFF *tif;
+	u_long *raster;
+	register RGBvalue *Map;
+	int h, w;
+{
+	register u_long *cp;
+	register int x;
+	u_char *red;
+	int scanline, row, y;
+
+	scanline = TIFFScanlineSize(tif);
+	switch (samplesperpixel) {
+	case 1:
+		red = (u_char *)malloc(scanline);
+		break;
+	case 3: case 4:
+		red = (u_char *)malloc(4*scanline);
+		break;
+	}
+	y = setorientation(tif, h);
+	for (row = 0; row < h; row++) {
+		cp = raster + y*w;
+		if (TIFFReadScanline(tif, red, row, 0) < 0)
+			break;
+		switch (photometric) {
+		case PHOTOMETRIC_RGB: {
+			register u_char *r, *g, *b, *a;
+
+			r = red;
+			if (TIFFReadScanline(tif, g = r + scanline, row, 1) < 0)
+				break;
+			if (TIFFReadScanline(tif, b = g + scanline, row, 2) < 0)
+				break;
+			if(samplesperpixel == 4) {
+			    a = b + scanline;
+			    if(TIFFReadScanline(tif, a, row, 3) < 0)
+				break;
+			}
+			switch (bitspersample) {
+			case 8:
+			    if(samplesperpixel == 4) {
+				for(x = w; --x >= 0; )
+				    *cp++ = rgba(*r++, *g++, *b++, *a++);
+			    } else {
+				for (x = w; x-- > 0;)
+					*cp++ = rgbi(*r++, *g++, *b++);
+			    }
+				break;
+			case 16:
+#define	wp(x)	((u_short *)(x))
+				for (x = 0; x < w; x++)
+					*cp++ = rgbi(
+					    Map[wp(r)[x]],
+					    Map[wp(g)[x]],
+					    Map[wp(b)[x]]);
+				break;
+#undef	wp
+			}
+			break;
+		}
+		case PHOTOMETRIC_PALETTE: {
+			register u_char *pp = red;
+			for (x = w; x-- > 0;) {
+				RGBvalue c = *pp++;
+				*cp++ = rgbi(redcmap[c],
+				    greencmap[c], bluecmap[c]);
+			}
+			break;
+		}
+		case PHOTOMETRIC_MINISWHITE:
+		case PHOTOMETRIC_MINISBLACK:
+			if (bitspersample == 8) {
+				register u_short *pp = (u_short *)red;
+				register RGBvalue c;
+
+				for (x = w; x-- > 0;) {
+					c = Map[*pp++];
+					*cp++ = rgbi(c, c, c);
+				}
+			} else
+				gtbw(bitspersample, w, Map, cp, red);
+			break;
+		}
+		y += (orientation == ORIENTATION_TOPLEFT ? -1 : 1);
+	}
+	if (red)
+		free(red);
+	return (1);
+}
+
+/*
+ * Greyscale images with less than 8 bits/sample are handled
+ * with a table to avoid lots of shits and masks.  The table
+ * is setup so that gtbw (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+makebwmap(Map)
+	RGBvalue *Map;
+{
+	register int i;
+	int nsamples = 8 / bitspersample;
+	register RGBvalue *p;
+
+	BWmap = (RGBvalue **)malloc(
+	    256*sizeof (RGBvalue *)+(256*nsamples*sizeof(RGBvalue)));
+	if (BWmap == NULL) {
+		fprintf(stderr, "No space for B&W mapping table.\n");
+		return (0);
+	}
+	p = (RGBvalue *)(BWmap + 256);
+	for (i = 0; i < 256; i++) {
+		BWmap[i] = p;
+		switch (bitspersample) {
+		case 1:
+			*p++ = Map[i>>7];
+			*p++ = Map[(i>>6)&1];
+			*p++ = Map[(i>>5)&1];
+			*p++ = Map[(i>>4)&1];
+			*p++ = Map[(i>>3)&1];
+			*p++ = Map[(i>>2)&1];
+			*p++ = Map[(i>>1)&1];
+			*p++ = Map[i&1];
+			break;
+		case 2:
+			*p++ = Map[i>>6];
+			*p++ = Map[(i>>4)&3];
+			*p++ = Map[(i>>2)&3];
+			*p++ = Map[i&3];
+			break;
+		case 4:
+			*p++ = Map[i>>4];
+			*p++ = Map[i&0xf];
+			break;
+		}
+	}
+	return (1);
+}
+
+#define	REPEAT8(op)	REPEAT4(op); REPEAT4(op)
+#define	REPEAT4(op)	REPEAT2(op); REPEAT2(op)
+#define	REPEAT2(op)	op; op
+
+gtbw(bitspersample, w, cp, pp)
+	int bitspersample, w;
+	register u_long *cp;
+	register u_char *pp;
+{
+	register RGBvalue c, *bw;
+	register int x;
+
+	switch (bitspersample) {
+	case 1:
+		for (x = w; x > 0; x -= 8) {
+			bw = BWmap[*pp++];
+			REPEAT8(c = *bw++; *cp++ = rgbi(c, c, c));
+		}
+		break;
+	case 2:
+		for (x = w; x > 0; x -= 4) {
+			bw = BWmap[*pp++];
+			REPEAT4(c = *bw++; *cp++ = rgbi(c, c, c));
+		}
+		break;
+	case 4:
+		for (x = w; x > 0; x -= 2) {
+			bw = BWmap[*pp++];
+			REPEAT2(c = *bw++; *cp++ = rgbi(c, c, c));
+		}
+		break;
+	}
+}
Index: trunk/src/testing/app/bitplay/libimg/gifdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/gifdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/gifdisp.c	(revision 4)
@@ -0,0 +1,514 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*-
+ * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
+ *
+ * Copyright (c) 1988 by Patrick J. Naughton
+ *
+ * Author: Patrick J. Naughton
+ * naughton@wind.sun.com
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Comments and additions should be sent to the author:
+ *
+ *                     Patrick J. Naughton
+ *                     Sun Microsystems, Inc.
+ *                     2550 Garcia Ave, MS 14-40
+ *                     Mountain View, CA 94043
+ *                     (415) 336-1080
+ *
+ * Revision History:
+ * 27-Jul-88: Updated to use libpixrect to fix 386i byteswapping problems.
+ * 11-Apr-88: Converted to C and changed to write Sun rasterfiles.
+ * 19-Jan-88: GIFSLOW.PAS posted to comp.graphics by Jim Briebel,
+ *            a Turbo Pascal 4.0 program to painfully slowly display
+ *            GIF images on an EGA equipped IBM-PC.
+ * 13-Jul-90: changed to gif2raw for use by the Geometry Supercomputer Project
+ *            by Cary Sandvig
+ *
+ * Description:
+ *   This program takes a Compuserve "Graphics Interchange Format" or "GIF"
+ * file as input and writes a file known as a Sun rasterfile.  This datafile
+ * can be loaded by the NeWS "readcanvas" operator and is of the same format
+ * as the files in /usr/NeWS/smi/...  Under X11R2 there is a program called
+ * xraster to display these files.
+ *
+ * Portability:
+ *   To make this program convert to some image format other than Sun's
+ * Rasterfile format simply seach for the tag "SS:" in the source and
+ * replace these simple mechanisms with the appropriate ones for the
+ * other output format.  I have marked all (six) Sun Specific pieces
+ * of code with this comment.
+ *
+ * SS: compile with "cc -o gif2raw -O gif2raw.c"
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "softpic.h"
+#include "imginfo.h"
+
+typedef int boolean;
+#define True (1)
+#define False (0)
+
+#define NEXTSHORT (ptr += 2, ptr[-2] + 0x100 * ptr[-1])
+#define NEXTBYTE (*ptr++)
+#define IMAGESEP 0x2c
+#define	EXTENSION '!'
+#define	TRANSPARENCY 0xF9	/* transparency extension-code */
+#define INTERLACEMASK 0x40
+#define COLORMAPMASK 0x80
+
+static int BitOffset = 0,		/* Bit Offset of next code */
+    XC = 0, YC = 0,		/* Output X and Y coords of current pixel */
+    Pass = 0,			/* Used by output routine if interlaced pic */
+    OutCount = 0,		/* Decompressor output 'stack count' */
+    RWidth, RHeight,		/* screen dimensions */
+    Width, Height,		/* image dimensions */
+    LeftOfs, TopOfs,		/* image offset */
+    BitsPerPixel,		/* Bits per pixel, read from GIF header */
+    ColorMapSize,		/* number of colors */
+    CodeSize,			/* Code size, read from GIF header */
+    InitCodeSize,		/* Starting code size, used during Clear */
+    Code,			/* Value returned by ReadCode */
+    MaxCode,			/* limiting value for current code size */
+    ClearCode,			/* GIF clear code */
+    EOFCode,			/* GIF end-of-information code */
+    CurCode, OldCode, InCode,	/* Decompressor variables */
+    FirstFree,			/* First free code, generated per GIF spec */
+    FreeCode,			/* Decompressor, next free slot in hash table */
+    FinChar,			/* Decompressor variable */
+    BitMask,			/* AND mask for data size */
+    ReadMask;			/* Code AND mask for current code size */
+
+static boolean Interlace, HasColormap;
+
+static unsigned char *Image;			/* The result array */
+static unsigned char *RawGIF;			/* The heap array to hold it, raw */
+static unsigned char *Raster;			/* The raster data stream, unblocked */
+
+    /* The hash table used by the decompressor */
+static int Prefix[4096];
+static int Suffix[4096];
+
+    /* An output array used by the decompressor */
+static int OutCode[1025];
+
+    /* The color map, read from the GIF header */
+static unsigned char Red[256], Green[256], Blue[256];
+static long abgr[256];
+
+static char *id, *id2;
+
+static char *pname;			/* program name (used for error messages) */
+
+static int  ReadCode();
+static void AddToPixel(char Index);
+
+static void error( char *s1, char *s2 )
+{
+    fprintf(stderr, s1, pname, s2);
+    exit(1);
+}
+
+
+static void gif_init()
+{
+   BitOffset = 0;
+   XC = 0;
+   YC = 0;
+   Pass = 0;
+   OutCount = 0;
+   id = "GIF87a";
+   id2 = "GIF89a";
+}
+
+IMG *gifmakedisp( char *inname )
+{
+    FILE *fpin;
+    int filesize;
+    register unsigned char ch, ch1;
+    register unsigned char *ptr, *ptr1;
+    IMG *out;
+    int transindex = -1;
+    int i, j;
+
+    gif_init();
+    setbuf(stderr, NULL);
+
+    fpin = fopen(inname, "rb");
+    /* find the size of the file */
+
+    fseek(fpin, 0L, 2);
+    filesize = ftell(fpin);
+    fseek(fpin, 0L, 0);
+
+    if (!(ptr = RawGIF = (unsigned char *) malloc(filesize)))
+	error("%s: not enough memory to read gif file.\n", NULL);
+
+    if (!(Raster = (unsigned char *) malloc(filesize)))
+	error("%s: not enough memory to read gif file.\n", NULL);
+
+    fread(ptr, filesize, 1, fpin);
+
+    if (memcmp(ptr, id, 6) && memcmp(ptr, id2, 6))
+	error("%s: %s is not a GIF file.\n", inname);
+    ptr += 6;
+
+/* Get variables from the GIF screen descriptor */
+
+    RWidth = NEXTSHORT;		/* screen dimensions... not used. */
+    RHeight = NEXTSHORT;
+
+    ch = NEXTBYTE;
+    HasColormap = ((ch & COLORMAPMASK) ? True : False);
+
+    BitsPerPixel = (ch & 7) + 1;
+    ColorMapSize = 1 << BitsPerPixel;
+    BitMask = ColorMapSize - 1;
+
+    ch = NEXTBYTE;		/* background color... not used. */
+
+    (void) NEXTBYTE;		/* what's this? */
+
+/* Read in global colormap. */
+
+    if (HasColormap) {
+/*
+	fprintf(stderr, "%s is %d bits per pixel, (%d colors).\n",
+		inname, BitsPerPixel, ColorMapSize);
+*/
+	for (i = 0; i < ColorMapSize; i++) {
+	    Red[i] = NEXTBYTE;
+	    Green[i] = NEXTBYTE;
+	    Blue[i] = NEXTBYTE;
+	    abgr[i] = 0xFF000000 | (Blue[i]<<16) | (Green[i]<<8) | Red[i];
+	}
+
+    }
+    else error("gifdisp: %s does not have a colormap.\n", inname);
+
+
+    /* Skip any GIF89 extensions */
+    while((i = NEXTBYTE) == EXTENSION) {
+	int extno = NEXTBYTE & 0xFF;
+	int len;
+	unsigned char block[256];
+
+	/* Skip <lengthbyte><data> segments until we see lengthbyte==0. */
+	while((len = NEXTBYTE) != 0) {
+	    for(i = 0; i < len; i++)
+	    	block[i] = NEXTBYTE;
+	}
+	switch(extno) {
+	case 0xF9:		/* Transparency */
+	    if(block[0] & 0x01) {
+		transindex = block[3];
+		if(transindex >= 0 && transindex < ColorMapSize)
+		    abgr[transindex] &= ~0xFF000000;
+	    }
+	    break;
+	}
+    }
+
+    /* Check for image separator */
+    if (i != IMAGESEP)
+	fprintf(stderr, "gifdisp: %s is a corrupt GIF file.\n", inname);
+
+/* Now read in values from the image descriptor */
+
+    LeftOfs = NEXTSHORT;
+    TopOfs = NEXTSHORT;
+    Width = NEXTSHORT;
+    Height = NEXTSHORT;
+    Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
+
+/*
+    fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
+        Width, Height, (Interlace) ? "" : "non-");
+*/
+
+
+/* Note that I ignore the possible existence of a local color map.
+ * I'm told there aren't many files around that use them, and the spec
+ * says it's defined for future use.  This could lead to an error
+ * reading some files.
+ */
+
+/* Start reading the raster data. First we get the intial code size
+ * and compute decompressor constant values, based on this code size.
+ */
+
+    CodeSize = NEXTBYTE;
+    ClearCode = (1 << CodeSize);
+    EOFCode = ClearCode + 1;
+    FreeCode = FirstFree = ClearCode + 2;
+
+/* The GIF spec has it that the code size is the code size used to
+ * compute the above values is the code size given in the file, but the
+ * code size used in compression/decompression is the code size given in
+ * the file plus one. (thus the ++).
+ */
+
+    CodeSize++;
+    InitCodeSize = CodeSize;
+    MaxCode = (1 << CodeSize);
+    ReadMask = MaxCode - 1;
+
+/* Read the raster data.  Here we just transpose it from the GIF array
+ * to the Raster array, turning it from a series of blocks into one long
+ * data stream, which makes life much easier for ReadCode().
+ */
+
+    ptr1 = Raster;
+    do {
+	ch = ch1 = NEXTBYTE;
+	while (ch--) *ptr1++ = NEXTBYTE;
+    } while(ch1);
+
+    free(RawGIF);		/* We're done with the raw data now... */
+
+/*
+    fprintf(stderr, "done.\n");
+    fprintf(stderr, "Decompressing...");
+*/
+
+    Image = (unsigned char *)calloc((Width*Height), sizeof(char));
+
+
+/* Decompress the file, continuing until you see the GIF EOF code.
+ * One obvious enhancement is to add checking for corrupt files here.
+ */
+
+    Code = ReadCode();
+    while (Code != EOFCode) {
+
+/* Clear code sets everything back to its initial value, then reads the
+ * immediately subsequent code as uncompressed data.
+ */
+
+	if (Code == ClearCode) {
+	    CodeSize = InitCodeSize;
+	    MaxCode = (1 << CodeSize);
+	    ReadMask = MaxCode - 1;
+	    FreeCode = FirstFree;
+	    CurCode = OldCode = Code = ReadCode();
+	    FinChar = CurCode & BitMask;
+	    AddToPixel(FinChar);
+	}
+	else {
+
+/* If not a clear code, then must be data: save same as CurCode and InCode */
+
+	    CurCode = InCode = Code;
+
+/* If greater or equal to FreeCode, not in the hash table yet;
+ * repeat the last character decoded
+ */
+
+	    if (CurCode >= FreeCode) {
+		CurCode = OldCode;
+		OutCode[OutCount++] = FinChar;
+	    }
+
+/* Unless this code is raw data, pursue the chain pointed to by CurCode
+ * through the hash table to its end; each code in the chain puts its
+ * associated output code on the output queue.
+ */
+
+	    while (CurCode > BitMask) {
+		OutCode[OutCount++] = Suffix[CurCode];
+		CurCode = Prefix[CurCode];
+	    }
+
+/* The last code in the chain is treated as raw data. */
+
+	    FinChar = CurCode & BitMask;
+	    OutCode[OutCount++] = FinChar;
+
+/* Now we put the data out to the Output routine.
+ * It's been stacked LIFO, so deal with it that way...
+ */
+
+	    for (i = OutCount - 1; i >= 0; i--)
+		AddToPixel(OutCode[i]);
+	    OutCount = 0;
+
+/* Build the hash table on-the-fly. No table is stored in the file. */
+
+	    Prefix[FreeCode] = OldCode;
+	    Suffix[FreeCode] = FinChar;
+	    OldCode = InCode;
+
+/* Point to the next slot in the table.  If we exceed the current
+ * MaxCode value, increment the code size unless it's already 12.  If it
+ * is, do nothing: the next code decompressed better be CLEAR
+ */
+
+	    FreeCode++;
+	    if (FreeCode >= MaxCode) {
+		if (CodeSize < 12) {
+		    CodeSize++;
+		    MaxCode *= 2;
+		    ReadMask = (1 << CodeSize) - 1;
+		}
+	    }
+	}
+	Code = ReadCode();
+    }
+
+    free(Raster);
+
+/*
+    fprintf(stderr, "done.\n");
+
+    fprintf(stderr, "outputting image.\n");
+*/
+
+    out = (IMG *)malloc(sizeof(IMG));
+    out->type = IT_LONG;
+    out->rowbytes = Width * sizeof(long);
+    out->xsize = Width;
+    out->ysize = Height;
+    out->data = (unsigned char *)malloc(4*(Width*Height)*sizeof(char));
+
+    for(j = 0; j<Height; j++)
+       for (i=0; i<Width; i++) {
+	  *(long *)&out->data[4*(((Height - j - 1)*Width)+i)] =
+		abgr[Image[j*Width + i]];
+        }
+
+     free(Image);
+     fclose(fpin);
+     return (out);
+
+/*
+    fprintf(stderr, "done.\n");
+*/
+}
+
+
+/* Fetch the next code from the raster data stream.  The codes can be
+ * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
+ * maintain our location in the Raster array as a BIT Offset.  We compute
+ * the byte Offset into the raster array by dividing this by 8, pick up
+ * three bytes, compute the bit Offset into our 24-bit chunk, shift to
+ * bring the desired code to the bottom, then mask it off and return it.
+ */
+static int ReadCode()
+{
+    int RawCode, ByteOffset;
+
+    ByteOffset = BitOffset / 8;
+    RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
+    if (CodeSize >= 8)
+	RawCode += (0x10000 * Raster[ByteOffset + 2]);
+    RawCode >>= (BitOffset % 8);
+    BitOffset += CodeSize;
+    return(RawCode & ReadMask);
+}
+
+static void AddToPixel(char Index)
+{
+    if((unsigned int)XC >= Width || (unsigned int)YC >= Height) {
+	fprintf(stderr, "[BP] ");
+    } else {
+	*(Image + YC * Width + XC) = Index;
+    }
+
+/* Update the X-coordinate, and if it overflows, update the Y-coordinate */
+
+    if (++XC == Width) {
+
+/* If a non-interlaced picture, just increment YC to the next scan line.
+ * If it's interlaced, deal with the interlace as described in the GIF
+ * spec.  Put the decoded scan line out to the screen if we haven't gone
+ * past the bottom of it
+ */
+
+	XC = 0;
+	if (!Interlace) YC++;
+	else {
+	    switch (Pass) {
+		case 0:
+		    YC += 8;
+		    if (YC >= Height) {
+			Pass++;
+			YC = 4;
+		    }
+		break;
+		case 1:
+		    YC += 8;
+		    if (YC >= Height) {
+			Pass++;
+			YC = 2;
+		    }
+		break;
+		case 2:
+		    YC += 4;
+		    if (YC >= Height) {
+			Pass++;
+			YC = 1;
+		    }
+		break;
+		case 3:
+		    YC += 2;
+		    if(YC >= Height) {
+			fprintf(stderr, "[BG] ");
+			YC = Height-1;	/* eh?? */
+		    }
+		break;
+		default:
+		break;
+	    }
+	}
+    }
+}
Index: trunk/src/testing/app/bitplay/libimg/jpegdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/jpegdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/jpegdisp.c	(revision 4)
@@ -0,0 +1,141 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Given a JPEG file, return a DISPIMAGE
+ * containing its raster data and with size <= (xsize, ysize).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "jpeglib.h"
+#include "imginfo.h"
+
+#ifndef alloca
+# include <alloca.h>
+#endif
+
+IMG *
+jpegmakedisp(char *filename)
+{
+    FILE *f;
+    IMG *di = NULL;
+    int xsize, ysize, zsize;
+    int x, y;
+    struct jpeg_error_mgr jerr[1];
+    struct jpeg_decompress_struct jp[1];
+    JSAMPARRAY yx;
+    JSAMPROW trow;
+
+    f = fopen(filename, "r");
+    if(f == NULL) {
+	fprintf(stderr, "%s: cannot open: ", filename);
+	perror("");
+	return NULL;
+    }
+
+    jp->err = jpeg_std_error( jerr );
+    jpeg_create_decompress( jp );
+    jpeg_stdio_src( jp, f );
+    if(jpeg_read_header( jp, TRUE ) != JPEG_HEADER_OK)
+	goto fail;
+
+    jpeg_start_decompress( jp );
+
+
+    di = (IMG *)malloc(sizeof(IMG));
+    di->xsize = xsize = jp->output_width;
+    di->ysize = ysize = jp->output_height;
+    zsize = jp->output_components;
+    di->data = (unsigned char *)malloc( xsize * ysize * 4 * sizeof(char) );
+    di->type = IT_LONG;
+    if(di->data == NULL) {
+	fprintf(stderr, "Not enough memory for %dx%dx%d image %s!\n",
+		xsize, ysize, zsize, filename);
+	goto fail;
+    }
+
+    yx = (JSAMPARRAY) alloca( jp->rec_outbuf_height * sizeof(JSAMPROW) );
+    trow = (JSAMPROW) alloca( zsize * xsize * jp->rec_outbuf_height * sizeof(JSAMPLE) );
+
+    for(y = 0; y < jp->rec_outbuf_height; y++)
+	yx[y] = &trow[ y * xsize * zsize ];
+
+    while(jp->output_scanline < ysize) {
+	int y, got, nleft;
+	JSAMPLE *ip = trow;
+	y = jp->output_scanline;
+	nleft = ysize - y;
+	if(nleft > jp->rec_outbuf_height) nleft = jp->rec_outbuf_height;
+	got = jpeg_read_scanlines( jp, yx, nleft );
+	if(got <= 0) {
+	    fprintf(stderr, "%s: trouble reading JPEG row %d of 0..%d (nleft %d)\n", filename, y, ysize-1, nleft);
+	    break;
+	}
+	while(--got >= 0) {
+	    unsigned int *op = (unsigned int *)&di->data[ (ysize-1 - y) * xsize * 4 ];
+	    x = xsize;
+	    switch(zsize) {
+	    case 1:
+		do {
+		    *op++ = (0xFF<<24) | (*ip++ * 0x010101);
+		} while(--x > 0);
+		break;
+	    case 3:
+		do {
+		    *op++ = (0xFF<<24) | (ip[2]<<16) | (ip[1]<<8) | (ip[0]);
+		    ip += 3;
+		} while(--x > 0);
+		break;
+	    }
+	    y++;
+	}
+    }
+    jpeg_finish_decompress( jp );
+    jpeg_destroy( (j_common_ptr) jp );
+    fclose(f);
+    return di;
+
+  fail:
+    jpeg_destroy( (j_common_ptr) jp );
+    if(di) {
+	if(di->data) free(di->data);
+	free(di);
+    }
+    if(f != NULL)
+	fclose(f);
+    return NULL;
+}
Index: trunk/src/testing/app/bitplay/libimg/rasdisp.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/rasdisp.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/rasdisp.c	(revision 4)
@@ -0,0 +1,228 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Given a Sun raster file, return an IMG containing its raster data.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "rasterfile.h"
+#include "imginfo.h"
+
+IMG *
+rasmakedisp(filename)
+    char *filename;
+{
+    FILE *inf;
+    struct rasterfile ras;
+    IMG *im = NULL;
+    int xsize, ysize;
+    register long *rp;
+    unsigned char *rowbuf = NULL;
+    long cmap[256];
+
+    inf = fopen(filename, "r");
+    if(inf == NULL) {
+	fprintf(stderr, "%s: cannot open: ", filename);
+	perror("");
+	return NULL;
+    }
+
+    if(fread(&ras, sizeof(ras), 1, inf) <= 0 || ras.ras_magic != RAS_MAGIC)
+	goto fail;
+
+    xsize = ras.ras_width;
+    ysize = ras.ras_height;
+
+    im = (IMG *)malloc(sizeof(IMG));
+    im->rowbytes = xsize * sizeof(long);
+    im->type = IT_LONG;
+    im->xsize = xsize;
+    im->ysize = ysize;
+    im->data = (unsigned char *)malloc(im->rowbytes * ysize);
+    if(im->data == NULL) {
+	fprintf(stderr, "Can't malloc %ld bytes of memory for image\n",
+	    sizeof(long) * xsize * ysize);
+	exit(2);
+    }
+    rp = (long *)im->data;
+
+    switch(ras.ras_maptype) {
+	unsigned char map[768];
+	register int i;
+
+    case RMT_EQUAL_RGB:
+	if(ras.ras_maplength != 3*256) {
+	    fprintf(stderr, "%s: can't handle colormap with %d != 256 entries",
+		filename, ras.ras_maplength / 3);
+	    goto fail;
+	}
+	if(fread(map, sizeof(map), 1, inf) <= 0) {
+	    fprintf(stderr, "%s: premature EOF reading colormap", filename);
+	    goto fail;
+	}
+	for(i = 0; i < 256; i++)
+	    cmap[i] = map[i] | (map[i+256] << 8) | (map[i+512] << 16);
+	break;
+
+    case RMT_NONE:
+	if(ras.ras_depth == 8) {
+	    for(i = 0; i < 256; i++)
+		cmap[i] = i * 0x010101;
+	}
+	break;
+
+    default:
+	fprintf(stderr, "%s: can't handle Sun colormap type %d\n",
+		filename, ras.ras_maptype);
+	goto fail;
+    }
+
+    if(ras.ras_type == RT_BYTE_ENCODED) {
+	if(ras.ras_depth != 8) {
+	    fprintf(stderr, "%s: can't handle byte-encoded %d-bit images\n",
+		filename, ras.ras_depth);
+	    goto fail;
+	}
+	rowbuf = (unsigned char *)malloc(ras.ras_width*sizeof(unsigned char *));
+    }
+
+    if(ras.ras_width > 0) {
+	register int i, c;
+	int row;
+
+	for(row = 0; row < ras.ras_height; row++) {
+	    rp = (long *)(im->data + im->rowbytes*(ysize-1 - row));
+	    i = xsize;
+	    switch(ras.ras_depth) {
+	    case 1:
+		while((c = getc(inf)) != EOF && i >= 8) {
+		    *rp++ = (c&0x80) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x40) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x20) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x10) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x08) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x04) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x02) ? 0xFFFFFF : 0;
+		    *rp++ = (c&0x01) ? 0xFFFFFF : 0;
+		}
+		if(c != EOF) {
+		    while(--i >= 0) {
+			*rp++ = (c&0x80) ? 0xFFFFFF : 0;
+			c <<= 1;
+		    }
+		}
+		break;
+
+	    case 24:
+		do {
+		    c = getc(inf);
+		    c |= getc(inf) << 8;
+		    *rp++ = c | getc(inf) << 16;
+		} while(--i > 0);
+		break;
+
+	    case 8:
+		if(ras.ras_type == RT_BYTE_ENCODED) {
+		    register unsigned char *rowp = rowbuf;
+		    int nleft = ras.ras_width;
+		    int seen = 0;
+
+		    do {
+			seen++;
+			c = getc(inf);
+			if(c == 128) {
+			    seen++;
+			    c = getc(inf);
+			    if(c == 0) {
+				*rowp++ = 128;
+			    } else {
+				seen++;
+				nleft -= c;
+				i = getc(inf);
+				do { *rowp++ = i; } while(--c >= 0);
+			    }
+			} else {
+			    *rowp++ = c;
+			}
+		    } while(--nleft > 0);
+		    if(seen&1)
+			(void) getc(inf);
+		    /*
+		     * Copy uncompressed data.
+		     */
+		    i = xsize;
+		    rowp = rowbuf;
+		    do { *rp++ = cmap[*rowp++]; } while(--i > 0);
+
+		} else {
+
+		    do {
+			*rp++ = cmap[getc(inf)];
+		    } while(--i > 0);
+		}
+		break;
+	    }
+
+	    if(feof(inf)) {
+		fprintf(stderr, "%s: premature EOF reading row %d of %d\n",
+		    filename, row, ras.ras_height);
+		break;
+	    }
+
+	    if(ras.ras_type != RT_BYTE_ENCODED) {
+		i = (((ras.ras_width*ras.ras_depth + 15) & ~15) >> 3) - xsize;
+		while(--i >= 0)
+		    (void) getc(inf);
+	    }
+	}
+    }
+    if(rowbuf != NULL)
+	free(rowbuf);
+    if(inf != NULL)
+	fclose(inf);
+    return im;
+
+  fail:
+    if(im) {
+	if(im->data) free(im->data);
+	free(im);
+    }
+    if(inf != NULL)
+	fclose(inf);
+    return NULL;
+}
Index: trunk/src/testing/app/bitplay/libimg/rasterfile.h
===================================================================
--- trunk/src/testing/app/bitplay/libimg/rasterfile.h	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/rasterfile.h	(revision 4)
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*	@(#)rasterfile.h 1.1 86/07/07 SMI	*/
+
+/*
+ * Description of header for files containing raster images
+ */
+struct rasterfile {
+	int	ras_magic;		/* magic number */
+	int	ras_width;		/* width (pixels) of image */
+	int	ras_height;		/* height (pixels) of image */
+	int	ras_depth;		/* depth (1, 8, or 24 bits) of pixel */
+	int	ras_length;		/* length (bytes) of image */
+	int	ras_type;		/* type of file; see RT_* below */
+	int	ras_maptype;		/* type of colormap; see RMT_* below */
+	int	ras_maplength;		/* length (bytes) of following map */
+	/* color map follows for ras_maplength bytes, followed by image */
+};
+#define	RAS_MAGIC	0x59a66a95
+
+	/* Sun supported ras_type's */
+#define RT_OLD		0	/* Raw pixrect image in 68000 byte order */
+#define RT_STANDARD	1	/* Raw pixrect image in 68000 byte order */
+#define RT_BYTE_ENCODED	2	/* Run-length compression of bytes */
+#define RT_EXPERIMENTAL 0xffff	/* Reserved for testing */
+
+	/* Sun registered ras_maptype's */
+#define RMT_RAW		2
+	/* Sun supported ras_maptype's */
+#define RMT_NONE	0	/* ras_maplength is expected to be 0 */
+#define RMT_EQUAL_RGB	1	/* red[ras_maplength/3],green[],blue[] */
+
+/*
+ * NOTES:
+ * 	Each line of the image is rounded out to a multiple of 16 bits.
+ *   This corresponds to the rounding convention used by the memory pixrect
+ *   package (/usr/include/pixrect/memvar.h) of the SunWindows system.
+ *	The ras_encoding field (always set to 0 by Sun's supported software)
+ *   was renamed to ras_length in release 2.0.  As a result, rasterfiles
+ *   of type 0 generated by the old software claim to have 0 length; for
+ *   compatibility, code reading rasterfiles must be prepared to compute the
+ *   true length from the width, height, and depth fields.
+ */
Index: trunk/src/testing/app/bitplay/libimg/getimgdata.c
===================================================================
--- trunk/src/testing/app/bitplay/libimg/getimgdata.c	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/getimgdata.c	(revision 4)
@@ -0,0 +1,273 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#define USEDISP 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "imginfo.h"
+
+#ifdef sun
+typedef uint32_t u_int32_t;
+#endif
+
+/*
+ * Routine to read an image in simple raster form.
+ * Given a file name, may fill in an "imginfo" structure,
+ * and returns the type of image.
+ */
+#if USEDISP
+extern IMG *TIFFmakedisp(), *SGImakedisp(), *softmakedisp(),
+		 *rasmakedisp(), *gifmakedisp(), *pnmmakedisp(),
+		 *jpegmakedisp();
+
+static IMG *(*imgdatafunc[])() = {
+	NULL,
+	TIFFmakedisp,
+	SGImakedisp,
+	rasmakedisp,
+	softmakedisp,
+	gifmakedisp,
+	pnmmakedisp,
+	NULL/*rawmakedisp?*/,
+	jpegmakedisp
+};
+
+#else /*!USEDISP*/
+
+extern unsigned char *img_tiffdata();
+extern unsigned char *img_sgidata();
+extern unsigned char *img_rasdata();
+extern unsigned char *img_softdata();
+extern unsigned char *img_gifdata();
+extern unsigned char *img_pnmdata();
+extern unsigned char *img_rawdata();
+extern unsigned char *img_jpegdata();
+
+static unsigned char *(*imgdatafunc[])() = {
+	NULL,
+	img_tiffdata,
+	img_sgidata,
+	img_rasdata,
+	img_softdata,
+	img_gifdata,
+	img_pnmdata,
+	/*img_rawdata*/NULL,
+	img_jpegdata,
+};
+#endif /*!USEDISP*/
+
+
+unsigned char *
+getimgdata(
+    const char *fname,		/* file name */
+    const struct imginfo *knowninfo, /* image info if already got by getimginfo */
+    struct imginfo *wantinfo,	/* image info if wanted */
+				/* Flags for desired image format */
+    int yup,			/* Y increases up */
+    int bpp,			/* bytes per pixel, or 0 for image's own */
+    int byteorder)		/* 0: RGBA, 1: ABGR */
+{
+    struct imginfo dummy;
+    struct imginfo *info;
+#if USEDISP
+    register unsigned char *p;
+    register int i, n;
+    int y;
+    IMG *im;
+#endif
+
+    if(knowninfo != NULL) {
+	info = (struct imginfo *)knowninfo;
+    } else {
+	info = wantinfo ? wantinfo : &dummy;
+	getimginfo((char *)fname, info);
+    }
+
+    if((unsigned)info->kind >= sizeof(imgdatafunc)/sizeof(imgdatafunc[0])
+		|| imgdatafunc[info->kind] == NULL)
+	return NULL;
+
+#if USEDISP
+    /* just for now ... (ha!) */
+    if(bpp != 4 && bpp != 0) {
+	fprintf(stderr, "getimgdata: can only handle 4 byte/pixel requests\n");
+	return NULL;
+    }
+    im = (*imgdatafunc[info->kind])(fname);
+    if(im == NULL || im->data == NULL)
+	return NULL;
+    switch(im->type) {
+    case IT_LONG:
+	p = im->data;
+	if(!yup) {
+	    register unsigned char *q = p + 4 * im->xsize * (im->ysize - 1);
+	    if(byteorder) {
+		for(n = im->ysize / 2; --n >= 0; q -= 2*4*im->xsize) {
+		    register int k = im->xsize;
+		    do {
+			i = *(u_int32_t *)p;  *(u_int32_t *)p = *(u_int32_t *)q;  *(u_int32_t *)q = i;
+			p += sizeof(u_int32_t);  q += sizeof(u_int32_t);
+		    } while(--k);
+		}
+	    } else {
+		for(n = im->ysize / 2; --n >= 0; q -= 2*4*im->xsize) {
+		    register int k = im->xsize;
+		    do {
+			i = p[0]; p[0] = q[3]; q[3] = i;
+			i = p[1]; p[1] = q[2]; q[2] = i;
+			i = p[2]; p[2] = q[1]; q[1] = i;
+			i = p[3]; p[3] = q[0]; q[0] = i;
+			p += 4;
+			q += 4;
+		    } while(--k);
+		}
+	    }
+	    if(im->ysize & 1) {
+		register int k = im->xsize;
+		do {
+		    i = p[0]; p[0] = p[3]; p[3] = i;
+		    i = p[1]; p[1] = p[2]; p[2] = i;
+		    p += 4;
+		} while(--k);
+	    }
+	} else if(byteorder) {
+	    i = im->xsize * im->ysize;
+	    do {
+		*(u_int32_t *)p = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+		p += sizeof(u_int32_t);
+	    } while(--i);
+	}
+	p = im->data;
+	break;
+
+    case IT_BIT:
+     {
+	unsigned char *obuf = (unsigned char *)malloc(sizeof(u_int32_t)*(im->xsize*im->ysize + 7));
+	register u_int32_t *q = (u_int32_t *)obuf;
+
+	for(y = im->ysize; --y >= 0; ) {
+	    p = &im->data[y*im->rowbytes];
+	    i = im->xsize >> 3;
+	    do {
+		n = *p++;
+		*q++ = n&0x80 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x40 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x20 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x10 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x08 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x04 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x02 ? 0xFFFFFFFF : 0;
+		*q++ = n&0x01 ? 0xFFFFFFFF : 0;
+	    } while(--i > 0);
+	}
+	free(im->data);
+	p = obuf;
+	break;
+     }
+
+    default:
+	p = NULL;
+	break;
+    }
+    free(im);
+    return p;
+#else /*!USEDISP*/
+    return (*imgdatafunc[info->kind])(fname, info->xsize, info->ysize,
+						yup, bpp, byteorder);
+#endif /*!USEDISP*/
+}
+
+/*
+ * Utility routine shared by some _data routines
+ * Selects/reorders pixels in a row, in place.
+ */
+void
+_img_rerow(row, xsize, hasbpp, wantbpp, reorder)
+    unsigned char *row;
+    int xsize;
+    int hasbpp;
+    int wantbpp;
+    int reorder;
+{
+    register unsigned char *p, *q;
+    register int j, k;
+
+    if(xsize <= 0)
+	return;
+
+    k = xsize;
+    p = row;
+    if(hasbpp == wantbpp) {
+	if(!reorder)
+	    return;
+
+	switch(wantbpp) {
+	case 2:
+	case 3:
+	    do {
+		j = *p;
+		*p = *q;
+		*q = j;
+		p = q;
+		p += wantbpp;
+		q += wantbpp;
+	    } while(--k);
+	    break;
+
+	case 4:
+	    do {
+		j = *p;
+		*p = p[3];
+		p[3] = j;
+		j = p[1];
+		p[1] = p[2];
+		p[2] = j;
+		p += 4;
+	    } while(--k);
+	    break;
+	}
+    } else if(hasbpp > wantbpp) {
+	/* Shorten the row; we can copy scanning forward */
+	q = p;
+	if(reorder) {
+	   /* ... */
+	}
+    } else {
+	/* ... */
+    }
+}
Index: trunk/src/testing/app/bitplay/libimg/image.h
===================================================================
--- trunk/src/testing/app/bitplay/libimg/image.h	(revision 4)
+++ trunk/src/testing/app/bitplay/libimg/image.h	(revision 4)
@@ -0,0 +1,229 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright 1995, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ *
+ * UNPUBLISHED -- Rights reserved under the copyright laws of the United
+ * States.   Use of a copyright notice is precautionary only and does not
+ * imply publication or disclosure.
+ *
+ * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
+ * Use, duplication or disclosure by the Government is subject to restrictions
+ * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
+ * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
+ * in similar or successor clauses in the FAR, or the DOD or NASA FAR
+ * Supplement.  Contractor/manufacturer is Silicon Graphics, Inc.,
+ * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
+ *
+ * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
+ * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
+ * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
+ * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
+ * GRAPHICS, INC.
+ *
+ *	image.h
+ *
+ *	$Revision: 1.2 $
+ *	$Date: 2004/06/25 03:36:29 $
+ */
+
+#ifndef __GL_IMAGE__
+#define __GL_IMAGE__
+
+/*
+ *	Defines for image files . . . .
+ *
+ *  			Paul Haeberli - 1984
+ *
+ *	Brutally hacked into a c++ wrapper by Dave Springer, 1988.
+ *      reworked for C jimh 1991.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>	/* for ushort16 and uint32 */
+
+#ifndef _IOREAD
+#  define _IOREAD 0x01
+#endif
+#ifndef _IOWRT
+#  define _IOWRT  0x02
+#endif
+#ifndef _IORW
+#  define _IORW   0x04
+#endif
+#ifndef _IOEOF
+#  define _IOEOF  0x08
+#endif
+#ifndef _IOERR
+#  define _IOERR  0x10
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef sun
+typedef uint16_t  IMushort;
+typedef uint32_t  IMulong;
+#else
+typedef u_int16_t  IMushort;
+typedef u_int32_t  IMulong;
+#endif
+
+typedef struct {
+    IMushort	imagic;		/* stuff saved on disk . . */
+    IMushort 	type;
+    IMushort 	dim;
+    IMushort 	xsize;
+    IMushort 	ysize;
+    IMushort 	zsize;
+    IMulong 	min;
+    IMulong 	max;
+    IMulong	wastebytes;
+    char	name[80];
+    IMulong	colormap;
+
+    int 	file;		/* stuff used in core only */
+    IMushort 	flags;
+    int16_t	dorev;
+    int16_t	x;
+    int16_t	y;
+    int16_t	z;
+    int16_t	cnt;
+    IMushort	*ptr;
+    IMushort	*base;
+    IMushort	*tmpbuf;
+    IMulong	offset;
+    IMulong	rleend;		/* for rle images */
+    IMulong	*rowstart;	/* for rle images */
+    IMulong	*rowsize;	/* for rle images */
+} IMAGE;
+
+
+typedef struct {
+	IMushort type;
+    	IMulong colormap;
+	int xsize, ysize;
+	IMulong *rowstart;
+	IMulong *rowsize;
+	IMushort *pixels;
+} MEMIMAGE ;
+
+#define IMAGIC 	0732
+
+/* type of the image */
+#define CM_NORMAL		0
+#define CM_DITHERED		1
+#define CM_SCREEN		2
+#define CM_COLORMAP		3
+
+#define TYPEMASK	0xff00
+#define BPPMASK		0x00ff
+#define ITYPE_VERBATIM	0x0000
+#define ITYPE_RLE	0x0100
+#define ISRLE(type)		(((type) & 0xff00) == ITYPE_RLE)
+#define ISVERBATIM(type)	(((type) & 0xff00) == ITYPE_VERBATIM)
+#define BPP(type)		((type) & BPPMASK)
+#define RLE(bpp)		(ITYPE_RLE | (bpp))
+#define VERBATIM(bpp)		(ITYPE_VERBATIM | (bpp))
+#define	IBUFSIZE(pixels)	((pixels+(pixels>>6))<<2)
+#define	RLE_NOP		0x00
+
+#define	ierror(p)	(((p)->flags&_IOERR)!=0)
+#define	ifileno(p)	((p)->file)
+
+#ifdef PIXMACROS
+#define	getpix(p)	(--(p)->cnt>=0? *(p)->ptr++:ifilbuf(p))
+#define putpix(p,x) (--(p)->cnt>=0? ((int)(*(p)->ptr++=(unsigned)(x))):iflsbuf(p,(unsigned)(x)))
+#endif
+
+extern int	iclose(IMAGE* image);
+extern int	iflush(IMAGE* image);
+extern int	ifilbuf(IMAGE* image);
+extern int	iflsbuf(IMAGE* image, IMushort c);
+extern MEMIMAGE	*newimage(int xsize, int ysize, int colormap);
+extern void	freeimage(MEMIMAGE* mimage);
+extern void	drawimage(int xorg, int yorg, MEMIMAGE* mimage);
+extern MEMIMAGE	*readimage(char* name);
+extern MEMIMAGE	*readrleimage(char* name);
+extern void	img_transtoscreen(unsigned short* buf, int n);
+extern void	img_setpixelortho(void);
+extern void	img_makexmap(int colormap);
+extern void	isetname(IMAGE* image, char* name);
+extern void	isetcolormap(IMAGE* image, int colormap);
+extern IMAGE	*iopen(char* file, char* mode, ...);
+/*
+extern IMAGE	*iopen(char* file, char* mode, unsigned int type,
+		       unsigned int dim, unsigned int xsize,
+		       unsigned int ysize, unsigned int zsize);
+*/
+extern IMAGE	*fiopen(int f, char* mode, unsigned int type,
+			unsigned int dim, unsigned int xsize,
+			unsigned int ysize, unsigned int zsize);
+extern IMAGE	*imgopen(int f, char* file, char* mode, unsigned int type,
+			 unsigned int dim, unsigned int xsize,
+			 unsigned int ysize, unsigned int zsize);
+extern unsigned	short* ibufalloc(IMAGE* image);
+extern int	reverse(IMulong lwrd);
+extern void	cvtshorts(IMushort* buffer, int n);
+extern void	cvtlongs(IMulong* buffer, int n);
+extern void	cvtimage(IMAGE *buffer);
+extern IMushort	getpix(IMAGE* image);
+extern IMushort	putpix(IMAGE* image, IMushort pix);
+extern int	img_seek(IMAGE* image, int y, int z);
+extern int	img_write(IMAGE* image, char* buffer, long count);
+extern int	img_read(IMAGE* image, char* buffer, long count);
+extern unsigned	long img_optseek(IMAGE* image, unsigned long offset);
+extern int	img_getrowsize(register IMAGE* image);
+extern void	img_setrowsize(IMAGE* image, int cnt, int y, int z);
+extern int	img_rle_compact(IMushort* expbuf, int ibpp,
+				IMushort* rlebuf, int obpp, int cnt);
+extern void	img_rle_expand(IMushort* rlebuf, int ibpp,
+			       IMushort* expbuf, int obpp);
+extern int	putrow(IMAGE* image, IMushort* buffer, int y, int z);
+extern int	getrow(IMAGE* image, IMushort* buffer, int y, int z);
+
+extern void	i_errhdlr(char *fmt, ...);
+extern int	img_badrow( IMAGE *image, int y, int z );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GL_IMAGE */
Index: trunk/src/testing/app/bitplay/Makefile.64
===================================================================
--- trunk/src/testing/app/bitplay/Makefile.64	(revision 4)
+++ trunk/src/testing/app/bitplay/Makefile.64	(revision 4)
@@ -0,0 +1,50 @@
+COPTS = -g -O2 -Wall
+
+# GLUTDEFS = -DUSE_FREEGLUT
+# GLUTLIBS = -L/usr/X11R6/lib64 -lfreeglut-1.3 -lglib -lXxf86vm
+
+GLUTDIR = /usr/local/src/grap/glut-3.7
+GLUTDEFS = -I${GLUTDIR}/include
+GLUTLIBS = -L${GLUTDIR}/lib/glut -lglut -L/usr/X11R6/lib64 -lX11 -lXmu
+
+DEFS = ${GLUTDEFS}
+CFLAGS = ${COPTS} ${DEFS}
+LIBS = -lpthread
+
+IMGLIB = /u/src/grap/libimg
+IMAGELIB = /u/src/grap/libimage
+IMGLIBS = -L${IMGLIB} -limg -L${IMAGELIB} -limage -ltiff -ljpeg -lm
+IMGINCS = -I${IMGLIB} 
+GLLIBS  = ${GLUTLIBS} -lGL -lGLU -lm
+GLINCS  = -I/usr/X11R6/include
+
+PROGS = bplay img2bmv bpio onethread
+
+all: ${PROGS}
+
+clean:
+	rm -f ${PROGS} *.o
+
+bplay:	bplay.o bpio.o 
+	${CC} -o $@ bplay.o bpio.o ${GLLIBS} ${LIBS}
+
+bpio.o: bpio.c bpio.h
+	${CC} -c bpio.c ${COPTS} -O0 ${DEFS} ${GLINCS}
+
+bplay.o: bplay.c bpio.h bpmovie.h
+	${CC} -c bplay.c ${COPTS} ${DEFS} ${GLINCS}
+
+img2bmv: img2bmv.c bpmovie.h ${IMGLIB}/libimg.a ${IMAGELIB}/libimage.a 
+	${CC} -c ${CFLAGS} ${IMGINCS} img2bmv.c
+	${CC} -o $@ $@.o ${COPTS} ${IMGLIBS}
+
+txspeed: txspeed.c
+	${CC} -o $@ $@.c -g -O ${GLINCS} ${GLLIBS}
+
+bpio:	bpiotest.o bpio.o
+	${CC} -o $@ bpiotest.o bpio.o ${COPTS} ${LIBS}
+
+bpio.o bpiotest.o:	bpio.h
+
+onethread: onethread.o
+	${CC} -o $@ onethread.o ${COPTS}
Index: trunk/src/testing/app/checker/checker.cxx
===================================================================
--- trunk/src/testing/app/checker/checker.cxx	(revision 4)
+++ trunk/src/testing/app/checker/checker.cxx	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu
+ *****************************************************************************/
+ 
+
+//A simple test program that pushes pixels to SAGE frame buffer 
+//written by Byung-il Jeong
+//Feb 2005
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+int main(int argc, char *argv[])
+{
+	double t1, t2, fps;
+	sail sageInf; // sail object
+	int nodeID;
+
+	if (argc < 2)
+		nodeID = 0;
+	else
+		nodeID = atoi(argv[1]);
+		 
+	int resX = 400, resY = 400;
+	if (argc >= 4) {
+		resX = atoi(argv[2]);
+		resY = atoi(argv[3]); 	 
+	}	
+	double rate = 10.0;
+	if (argc >= 5) {
+		rate = atof(argv[4]);
+	}	
+	
+	std::cout << std::endl << "ResX = " << resX << "  ResY = " << resY << std::endl;
+
+	sailConfig scfg;
+	scfg.init("checker.conf");
+	scfg.setAppName("checker");
+	scfg.rank = nodeID;
+			
+	scfg.resX = resX;
+	scfg.resY = resY;
+
+	sageRect renderImageMap;
+	renderImageMap.left = 0.0;
+	renderImageMap.right = 1.0;
+	renderImageMap.bottom = 0.0;
+	renderImageMap.top = 1.0;
+
+	scfg.imageMap = renderImageMap;
+	scfg.pixFmt = PIXFMT_888;
+	scfg.rowOrd = BOTTOM_TO_TOP;
+	scfg.master = true;
+	scfg.nwID = 1;
+	scfg.frameRate = rate;
+	 		 
+	sageInf.init(scfg);	 
+	std::cout << "sail initialized " << std::endl;
+	
+	void *buffer = sageInf.getBuffer();
+	unsigned char color = 200;
+	
+	while(1) {
+		t1 = sage::getTime();
+		memset(buffer, color, resX*resY*3);
+		sageInf.swapBuffer();
+		buffer = sageInf.getBuffer();
+		color = (color + 1) % 129;	
+		sageMessage msg;
+		if (sageInf.checkMsg(msg, false) > 0) {
+			switch (msg.getCode()) {
+				 case APP_QUIT : {
+					sageInf.shutdown();
+					exit(0);
+					break;
+				}
+			}	
+		}
+		t2 = sage::getTime();
+		fps = (1000000.0/(t2-t1));
+		if (fps > rate) {
+			sage::usleep( (1000000.0/rate) - (t2-t1)  );
+		}
+	}
+	
+	return 0;
+}
Index: trunk/src/testing/app/checker/Makefile
===================================================================
--- trunk/src/testing/app/checker/Makefile	(revision 4)
+++ trunk/src/testing/app/checker/Makefile	(revision 4)
@@ -0,0 +1,32 @@
+
+###################################################################
+# Makefile for check
+###################################################################
+
+include ../../config.mk
+QUANTA_DIR=../../QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L../../lib -lquanta
+
+CFLAGS=$(SAGE_CFLAGS) -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+LIBS=-lpthread -lm -ldl $(SAGE_LDFLAGS) $(QUANTA_LDFLAGS) $(GLEW_LIB) -L../../lib -lsail
+CC=$(COMPILER)
+
+
+PROGRAM = checker
+FILES= checker.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(COMPILER) -o $(PROGRAM) $(FILES) $(LIBS)
+
+checker.o: checker.cxx
+	$(COMPILER) $(CFLAGS) -c checker.cxx
+
+
+clean:
+	\rm -f *~ *.o $(PROGRAM)
Index: trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPIDispatch.cpp
===================================================================
--- trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPIDispatch.cpp	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPIDispatch.cpp	(revision 4)
@@ -0,0 +1,94 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+** 
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+** 
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+**/
+
+#include <stdio.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+#include "DeckLinkAPI.h"
+
+#define kDeckLinkAPI_Name "libDeckLinkAPI.so"
+#define KDeckLinkPreviewAPI_Name "libDeckLinkPreviewAPI.so"
+
+typedef IDeckLinkIterator* (*CreateIteratorFunc)(void);
+typedef IDeckLinkGLScreenPreviewHelper* (*CreateOpenGLScreenPreviewHelperFunc)(void);
+
+static pthread_once_t					gDeckLinkOnceControl = PTHREAD_ONCE_INIT;
+static pthread_once_t					gPreviewOnceControl = PTHREAD_ONCE_INIT;
+
+static CreateIteratorFunc				gCreateIteratorFunc = NULL;
+static CreateOpenGLScreenPreviewHelperFunc	gCreateOpenGLPreviewFunc = NULL;
+
+void	InitDeckLinkAPI (void)
+{
+	void *libraryHandle;
+	
+	libraryHandle = dlopen(kDeckLinkAPI_Name, RTLD_NOW|RTLD_GLOBAL);
+	if (!libraryHandle)
+	{
+		fprintf(stderr, "%s\n", dlerror());
+		return;
+	}
+	gCreateIteratorFunc = (CreateIteratorFunc)dlsym(libraryHandle, "CreateDeckLinkIteratorInstance");
+	if (!gCreateIteratorFunc)
+		fprintf(stderr, "%s\n", dlerror());
+}
+
+void	InitDeckLinkPreviewAPI (void)
+{
+	void *libraryHandle;
+	
+	libraryHandle = dlopen(KDeckLinkPreviewAPI_Name, RTLD_NOW|RTLD_GLOBAL);
+	if (!libraryHandle)
+	{
+		fprintf(stderr, "%s\n", dlerror());
+		return;
+	}
+	gCreateOpenGLPreviewFunc = (CreateOpenGLScreenPreviewHelperFunc)dlsym(libraryHandle, "CreateOpenGLScreenPreviewHelper");
+	if (!gCreateOpenGLPreviewFunc)
+		fprintf(stderr, "%s\n", dlerror());
+}
+
+IDeckLinkIterator*		CreateDeckLinkIteratorInstance (void)
+{
+	pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+	
+	if (gCreateIteratorFunc == NULL)
+		return NULL;
+	return gCreateIteratorFunc();
+}
+
+IDeckLinkGLScreenPreviewHelper*		CreateOpenGLScreenPreviewHelper (void)
+{
+	pthread_once(&gDeckLinkOnceControl, InitDeckLinkAPI);
+	pthread_once(&gPreviewOnceControl, InitDeckLinkPreviewAPI);
+	
+	if (gCreateOpenGLPreviewFunc == NULL)
+		return NULL;
+	return gCreateOpenGLPreviewFunc();
+}
+
Index: trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI_v7_1.h
===================================================================
--- trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI_v7_1.h	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI_v7_1.h	(revision 4)
@@ -0,0 +1,198 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+** 
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+** 
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+/* DeckLinkAPI_v7_1.h */
+
+#ifndef __DeckLink_API_v7_1_h__
+#define __DeckLink_API_v7_1_h__
+
+#include "DeckLinkAPI.h"
+
+// "B28131B6-59AC-4857-B5AC-CD75D5883E2F"
+#define IID_IDeckLinkDisplayModeIterator_v7_1	(REFIID){0xB2,0x81,0x31,0xB6,0x59,0xAC,0x48,0x57,0xB5,0xAC,0xCD,0x75,0xD5,0x88,0x3E,0x2F}
+
+// "AF0CD6D5-8376-435E-8433-54F9DD530AC3"
+#define IID_IDeckLinkDisplayMode_v7_1			(REFIID){0xAF,0x0C,0xD6,0xD5,0x83,0x76,0x43,0x5E,0x84,0x33,0x54,0xF9,0xDD,0x53,0x0A,0xC3}
+
+// "EBD01AFA-E4B0-49C6-A01D-EDB9D1B55FD9"
+#define IID_IDeckLinkVideoOutputCallback_v7_1	(REFIID){0xEB,0xD0,0x1A,0xFA,0xE4,0xB0,0x49,0xC6,0xA0,0x1D,0xED,0xB9,0xD1,0xB5,0x5F,0xD9}
+
+// "7F94F328-5ED4-4E9F-9729-76A86BDC99CC"
+#define IID_IDeckLinkInputCallback_v7_1			(REFIID){0x7F,0x94,0xF3,0x28,0x5E,0xD4,0x4E,0x9F,0x97,0x29,0x76,0xA8,0x6B,0xDC,0x99,0xCC}
+
+// "AE5B3E9B-4E1E-4535-B6E8-480FF52F6CE5"
+#define IID_IDeckLinkOutput_v7_1				(REFIID){0xAE,0x5B,0x3E,0x9B,0x4E,0x1E,0x45,0x35,0xB6,0xE8,0x48,0x0F,0xF5,0x2F,0x6C,0xE5}
+
+// "2B54EDEF-5B32-429F-BA11-BB990596EACD"
+#define IID_IDeckLinkInput_v7_1					(REFIID){0x2B,0x54,0xED,0xEF,0x5B,0x32,0x42,0x9F,0xBA,0x11,0xBB,0x99,0x05,0x96,0xEA,0xCD}
+
+// "333F3A10-8C2D-43CF-B79D-46560FEEA1CE"
+#define IID_IDeckLinkVideoFrame_v7_1			(REFIID){0x33,0x3F,0x3A,0x10,0x8C,0x2D,0x43,0xCF,0xB7,0x9D,0x46,0x56,0x0F,0xEE,0xA1,0xCE}
+
+// "C8B41D95-8848-40EE-9B37-6E3417FB114B"
+#define IID_IDeckLinkVideoInputFrame_v7_1		(REFIID){0xC8,0xB4,0x1D,0x95,0x88,0x48,0x40,0xEE,0x9B,0x37,0x6E,0x34,0x17,0xFB,0x11,0x4B}
+
+// "C86DE4F6-A29F-42E3-AB3A-1363E29F0788"
+#define IID_IDeckLinkAudioInputPacket_v7_1		(REFIID){0xC8,0x6D,0xE4,0xF6,0xA2,0x9F,0x42,0xE3,0xAB,0x3A,0x13,0x63,0xE2,0x9F,0x07,0x88}
+
+#if defined(__cplusplus)
+
+class IDeckLinkDisplayModeIterator_v7_1;
+class IDeckLinkDisplayMode_v7_1;
+class IDeckLinkVideoFrame_v7_1;
+class IDeckLinkVideoInputFrame_v7_1;
+class IDeckLinkAudioInputPacket_v7_1;
+
+class IDeckLinkDisplayModeIterator_v7_1 : public IUnknown
+{
+public:
+	virtual	HRESULT	STDMETHODCALLTYPE	Next (IDeckLinkDisplayMode_v7_1* *deckLinkDisplayMode) = 0;
+};
+
+
+class IDeckLinkDisplayMode_v7_1 : public IUnknown
+{
+public:
+	virtual	HRESULT			STDMETHODCALLTYPE	GetName (const char **name) = 0;
+	virtual	BMDDisplayMode	STDMETHODCALLTYPE	GetDisplayMode () = 0;
+	virtual	long			STDMETHODCALLTYPE	GetWidth () = 0;
+	virtual	long			STDMETHODCALLTYPE	GetHeight () = 0;
+	virtual	HRESULT			STDMETHODCALLTYPE	GetFrameRate (BMDTimeValue *frameDuration, BMDTimeScale *timeScale) = 0;
+};
+
+class IDeckLinkVideoOutputCallback_v7_1 : public IUnknown
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE	ScheduledFrameCompleted (IDeckLinkVideoFrame_v7_1* completedFrame, BMDOutputFrameCompletionResult result) = 0;
+};
+
+class IDeckLinkInputCallback_v7_1 : public IUnknown
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE	VideoInputFrameArrived (IDeckLinkVideoInputFrame_v7_1* videoFrame, IDeckLinkAudioInputPacket_v7_1* audioPacket) = 0;
+};
+
+// IDeckLinkOutput_v7_1.  Created by QueryInterface from IDeckLink.
+class IDeckLinkOutput_v7_1 : public IUnknown
+{
+public:
+	// Display mode predicates
+	virtual	HRESULT	STDMETHODCALLTYPE	DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0;
+	virtual HRESULT	STDMETHODCALLTYPE	GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1* *iterator) = 0;
+	
+	
+	// Video output
+	virtual HRESULT STDMETHODCALLTYPE	EnableVideoOutput (BMDDisplayMode displayMode) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	DisableVideoOutput () = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	SetVideoOutputFrameMemoryAllocator (IDeckLinkMemoryAllocator* theAllocator) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	CreateVideoFrame (int32_t width, int32_t height, int32_t rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1* *outFrame) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	CreateVideoFrameFromBuffer (void* buffer, int32_t width, int32_t height, int32_t rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, IDeckLinkVideoFrame_v7_1* *outFrame) = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	DisplayVideoFrameSync (IDeckLinkVideoFrame_v7_1* theFrame) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	ScheduleVideoFrame (IDeckLinkVideoFrame_v7_1* theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	SetScheduledFrameCompletionCallback (IDeckLinkVideoOutputCallback_v7_1* theCallback) = 0;
+	
+	
+	// Audio output
+	virtual HRESULT STDMETHODCALLTYPE	EnableAudioOutput (BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, uint32_t channelCount) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	DisableAudioOutput () = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	WriteAudioSamplesSync (void* buffer, uint32_t sampleFrameCount, uint32_t *sampleFramesWritten) = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	BeginAudioPreroll () = 0;
+	virtual HRESULT STDMETHODCALLTYPE	EndAudioPreroll () = 0;
+	virtual HRESULT STDMETHODCALLTYPE	ScheduleAudioSamples (void* buffer, uint32_t sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, uint32_t *sampleFramesWritten) = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	GetBufferedAudioSampleFrameCount (uint32_t *bufferedSampleCount) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	FlushBufferedAudioSamples () = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE	SetAudioCallback (IDeckLinkAudioOutputCallback* theCallback) = 0;
+	
+	
+	// Output control
+	virtual HRESULT STDMETHODCALLTYPE	StartScheduledPlayback (BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	StopScheduledPlayback (BMDTimeValue stopPlaybackAtTime, BMDTimeValue *actualStopTime, BMDTimeScale timeScale) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	GetHardwareReferenceClock (BMDTimeScale desiredTimeScale, BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0;
+};
+
+// IDeckLinkInput_v7_1.  Created by QueryInterface from IDeckLink.
+class IDeckLinkInput_v7_1 : public IUnknown
+{
+public:
+	virtual	HRESULT	STDMETHODCALLTYPE	DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDDisplayModeSupport *result) = 0;
+	virtual HRESULT	STDMETHODCALLTYPE	GetDisplayModeIterator (IDeckLinkDisplayModeIterator_v7_1 **iterator) = 0;
+	
+	// Video input
+	virtual HRESULT STDMETHODCALLTYPE	EnableVideoInput (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	DisableVideoInput () = 0;
+	
+	// Audio input
+	virtual HRESULT STDMETHODCALLTYPE	EnableAudioInput (BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, uint32_t channelCount) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	DisableAudioInput () = 0;
+	virtual HRESULT STDMETHODCALLTYPE	ReadAudioSamples (void* buffer, uint32_t sampleFrameCount, uint32_t *sampleFramesRead, BMDTimeValue *audioPacketTime, BMDTimeScale timeScale) = 0;
+	virtual HRESULT STDMETHODCALLTYPE	GetBufferedAudioSampleFrameCount (uint32_t *bufferedSampleCount) = 0;
+	
+	// Input control
+	virtual HRESULT	STDMETHODCALLTYPE	StartStreams () = 0;
+	virtual HRESULT	STDMETHODCALLTYPE	StopStreams () = 0;
+	virtual HRESULT	STDMETHODCALLTYPE	PauseStreams () = 0;
+	virtual HRESULT STDMETHODCALLTYPE	SetCallback (IDeckLinkInputCallback_v7_1* theCallback) = 0;
+};
+
+// IDeckLinkVideoFrame_v7_1.  Created by IDeckLinkOutput::CreateVideoFrame.
+class IDeckLinkVideoFrame_v7_1 : public IUnknown
+{
+public:
+	virtual long STDMETHODCALLTYPE					GetWidth () = 0;
+	virtual long STDMETHODCALLTYPE					GetHeight () = 0;
+	virtual long STDMETHODCALLTYPE					GetRowBytes () = 0;
+	virtual BMDPixelFormat STDMETHODCALLTYPE		GetPixelFormat () = 0;
+	virtual BMDFrameFlags STDMETHODCALLTYPE			GetFlags () = 0;
+	virtual HRESULT STDMETHODCALLTYPE				GetBytes (void* *buffer) = 0;
+};
+
+// IDeckLinkVideoInputFrame_v7_1.  Provided by the IDeckLinkInput_v7_1 frame arrival callback.
+class IDeckLinkVideoInputFrame_v7_1 : public IDeckLinkVideoFrame_v7_1
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE			GetFrameTime (BMDTimeValue *frameTime, BMDTimeValue *frameDuration, BMDTimeScale timeScale) = 0;
+};
+
+// IDeckLinkAudioInputPacket_v7_1.  Provided by the IDeckLinkInput_v7_1 callback.
+class IDeckLinkAudioInputPacket_v7_1 : public IUnknown
+{
+public:
+	virtual long STDMETHODCALLTYPE				GetSampleCount () = 0;
+	virtual HRESULT STDMETHODCALLTYPE			GetBytes (void* *buffer) = 0;
+	
+	virtual HRESULT STDMETHODCALLTYPE			GetAudioPacketTime (BMDTimeValue *packetTime, BMDTimeScale timeScale) = 0;
+};
+
+#endif		// defined(__cplusplus)
+
+#endif		// __DeckLink_API_v7_1_h__
+
Index: trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI.h
===================================================================
--- trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI.h	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/include/DeckLinkAPI.h	(revision 4)
@@ -0,0 +1,802 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+** 
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+** 
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+/* DeckLinkAPI.h */
+		
+#ifndef __DeckLink_API_h__
+#define __DeckLink_API_h__
+		
+#include <stdint.h>
+#include "LinuxCOM.h"
+
+/* Type Declarations */
+
+typedef int64_t BMDTimeValue;
+typedef int64_t BMDTimeScale;
+typedef uint32_t BMDTimecodeBCD;
+
+/* End Type Declarations */
+
+/* Interface ID Declarations */
+
+#define IID_IDeckLinkVideoOutputCallback                 /* E763A626-4A3C-49D1-BF13-E7AD3692AE52 */ (REFIID){0xE7,0x63,0xA6,0x26,0x4A,0x3C,0x49,0xD1,0xBF,0x13,0xE7,0xAD,0x36,0x92,0xAE,0x52}
+#define IID_IDeckLinkInputCallback                       /* FD6F311D-4D00-444B-9ED4-1F25B5730AD0 */ (REFIID){0xFD,0x6F,0x31,0x1D,0x4D,0x00,0x44,0x4B,0x9E,0xD4,0x1F,0x25,0xB5,0x73,0x0A,0xD0}
+#define IID_IDeckLinkMemoryAllocator                     /* B36EB6E7-9D29-4AA8-92EF-843B87A289E8 */ (REFIID){0xB3,0x6E,0xB6,0xE7,0x9D,0x29,0x4A,0xA8,0x92,0xEF,0x84,0x3B,0x87,0xA2,0x89,0xE8}
+#define IID_IDeckLinkAudioOutputCallback                 /* 403C681B-7F46-4A12-B993-2BB127084EE6 */ (REFIID){0x40,0x3C,0x68,0x1B,0x7F,0x46,0x4A,0x12,0xB9,0x93,0x2B,0xB1,0x27,0x08,0x4E,0xE6}
+#define IID_IDeckLinkIterator                            /* 74E936FC-CC28-4A67-81A0-1E94E52D4E69 */ (REFIID){0x74,0xE9,0x36,0xFC,0xCC,0x28,0x4A,0x67,0x81,0xA0,0x1E,0x94,0xE5,0x2D,0x4E,0x69}
+#define IID_IDeckLinkDisplayModeIterator                 /* 455D741F-1779-4800-86F5-0B5D13D79751 */ (REFIID){0x45,0x5D,0x74,0x1F,0x17,0x79,0x48,0x00,0x86,0xF5,0x0B,0x5D,0x13,0xD7,0x97,0x51}
+#define IID_IDeckLinkDisplayMode                         /* 87451E84-2B7E-439E-A629-4393EA4A8550 */ (REFIID){0x87,0x45,0x1E,0x84,0x2B,0x7E,0x43,0x9E,0xA6,0x29,0x43,0x93,0xEA,0x4A,0x85,0x50}
+#define IID_IDeckLink                                    /* 62BFF75D-6569-4E55-8D4D-66AA03829ABC */ (REFIID){0x62,0xBF,0xF7,0x5D,0x65,0x69,0x4E,0x55,0x8D,0x4D,0x66,0xAA,0x03,0x82,0x9A,0xBC}
+#define IID_IDeckLinkOutput                              /* 271C65E3-C323-4344-A30F-D908BCB20AA3 */ (REFIID){0x27,0x1C,0x65,0xE3,0xC3,0x23,0x43,0x44,0xA3,0x0F,0xD9,0x08,0xBC,0xB2,0x0A,0xA3}
+#define IID_IDeckLinkInput                               /* 4973F012-9925-458C-871C-18774CDBBECB */ (REFIID){0x49,0x73,0xF0,0x12,0x99,0x25,0x45,0x8C,0x87,0x1C,0x18,0x77,0x4C,0xDB,0xBE,0xCB}
+#define IID_IDeckLinkTimecode                            /* EFB9BCA6-A521-44F7-BD69-2332F24D9EE6 */ (REFIID){0xEF,0xB9,0xBC,0xA6,0xA5,0x21,0x44,0xF7,0xBD,0x69,0x23,0x32,0xF2,0x4D,0x9E,0xE6}
+#define IID_IDeckLinkVideoFrame                          /* A8D8238E-6B18-4196-99E1-5AF717B83D32 */ (REFIID){0xA8,0xD8,0x23,0x8E,0x6B,0x18,0x41,0x96,0x99,0xE1,0x5A,0xF7,0x17,0xB8,0x3D,0x32}
+#define IID_IDeckLinkMutableVideoFrame                   /* 46FCEE00-B4E6-43D0-91C0-023A7FCEB34F */ (REFIID){0x46,0xFC,0xEE,0x00,0xB4,0xE6,0x43,0xD0,0x91,0xC0,0x02,0x3A,0x7F,0xCE,0xB3,0x4F}
+#define IID_IDeckLinkVideoInputFrame                     /* CF317790-2894-11DE-8C30-0800200C9A66 */ (REFIID){0xCF,0x31,0x77,0x90,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}
+#define IID_IDeckLinkVideoFrameAncillary                 /* 732E723C-D1A4-4E29-9E8E-4A88797A0004 */ (REFIID){0x73,0x2E,0x72,0x3C,0xD1,0xA4,0x4E,0x29,0x9E,0x8E,0x4A,0x88,0x79,0x7A,0x00,0x04}
+#define IID_IDeckLinkAudioInputPacket                    /* E43D5870-2894-11DE-8C30-0800200C9A66 */ (REFIID){0xE4,0x3D,0x58,0x70,0x28,0x94,0x11,0xDE,0x8C,0x30,0x08,0x00,0x20,0x0C,0x9A,0x66}
+#define IID_IDeckLinkScreenPreviewCallback               /* 373F499D-4B4D-4518-AD22-6354E5A5825E */ (REFIID){0x37,0x3F,0x49,0x9D,0x4B,0x4D,0x45,0x18,0xAD,0x22,0x63,0x54,0xE5,0xA5,0x82,0x5E}
+#define IID_IDeckLinkGLScreenPreviewHelper               /* BA575CD9-A15E-497B-B2C2-F9AFE7BE4EBA */ (REFIID){0xBA,0x57,0x5C,0xD9,0xA1,0x5E,0x49,0x7B,0xB2,0xC2,0xF9,0xAF,0xE7,0xBE,0x4E,0xBA}
+#define IID_IDeckLinkConfiguration                       /* B8EAD569-B764-47F0-A73F-AE40DF6CBF10 */ (REFIID){0xB8,0xEA,0xD5,0x69,0xB7,0x64,0x47,0xF0,0xA7,0x3F,0xAE,0x40,0xDF,0x6C,0xBF,0x10}
+#define IID_IDeckLinkAttributes                          /* ABC11843-D966-44CB-96E2-A1CB5D3135C4 */ (REFIID){0xAB,0xC1,0x18,0x43,0xD9,0x66,0x44,0xCB,0x96,0xE2,0xA1,0xCB,0x5D,0x31,0x35,0xC4}
+#define IID_IDeckLinkKeyer                               /* 89AFCAF5-65F8-421E-98F7-96FE5F5BFBA3 */ (REFIID){0x89,0xAF,0xCA,0xF5,0x65,0xF8,0x42,0x1E,0x98,0xF7,0x96,0xFE,0x5F,0x5B,0xFB,0xA3}
+
+/* End Interface ID Declarations */
+
+/* Enum BMDDisplayMode - Video display modes */
+
+typedef uint32_t BMDDisplayMode;
+enum _BMDDisplayMode {
+    bmdModeNTSC                                        = /* 'ntsc' */ 0x6E747363,
+    bmdModeNTSC2398                                    = /* 'nt23' */ 0x6E743233, // 3:2 pulldown
+    bmdModePAL                                         = /* 'pal ' */ 0x70616C20,
+
+    /* HD 1080 Modes */
+
+    bmdModeHD1080p2398                                 = /* '23ps' */ 0x32337073,
+    bmdModeHD1080p24                                   = /* '24ps' */ 0x32347073,
+    bmdModeHD1080p25                                   = /* 'Hp25' */ 0x48703235,
+    bmdModeHD1080p2997                                 = /* 'Hp29' */ 0x48703239,
+    bmdModeHD1080p30                                   = /* 'Hp30' */ 0x48703330,
+    bmdModeHD1080i50                                   = /* 'Hi50' */ 0x48693530,
+    bmdModeHD1080i5994                                 = /* 'Hi59' */ 0x48693539,
+    bmdModeHD1080i6000                                 = /* 'Hi60' */ 0x48693630, // N.B. This _really_ is 60.00 Hz.
+    bmdModeHD1080p50                                   = /* 'Hp50' */ 0x48703530,
+    bmdModeHD1080p5994                                 = /* 'Hp59' */ 0x48703539,
+    bmdModeHD1080p6000                                 = /* 'Hp60' */ 0x48703630, // N.B. This _really_ is 60.00 Hz.
+
+    /* HD 720 Modes */
+
+    bmdModeHD720p50                                    = /* 'hp50' */ 0x68703530,
+    bmdModeHD720p5994                                  = /* 'hp59' */ 0x68703539,
+    bmdModeHD720p60                                    = /* 'hp60' */ 0x68703630,
+
+    /* 2k Modes */
+
+    bmdMode2k2398                                      = /* '2k23' */ 0x326B3233,
+    bmdMode2k24                                        = /* '2k24' */ 0x326B3234,
+    bmdMode2k25                                        = /* '2k25' */ 0x326B3235
+};
+
+/* End Enum BMDDisplayMode */
+
+/* Enum BMDFieldDominance - Video field dominance */
+
+typedef uint32_t BMDFieldDominance;
+enum _BMDFieldDominance {
+    bmdUnknownFieldDominance                           = 0,
+    bmdLowerFieldFirst                                 = /* 'lowr' */ 0x6C6F7772,
+    bmdUpperFieldFirst                                 = /* 'uppr' */ 0x75707072,
+    bmdProgressiveFrame                                = /* 'prog' */ 0x70726F67,
+    bmdProgressiveSegmentedFrame                       = /* 'psf ' */ 0x70736620
+};
+
+/* End Enum BMDFieldDominance */
+
+/* Enum BMDPixelFormat - Video pixel formats supported for output/input */
+
+typedef uint32_t BMDPixelFormat;
+enum _BMDPixelFormat {
+    bmdFormat8BitYUV                                   = /* '2vuy' */ 0x32767579,
+    bmdFormat10BitYUV                                  = /* 'v210' */ 0x76323130,
+    bmdFormat8BitARGB                                  = 0x20,
+    bmdFormat8BitBGRA                                  = /* 'BGRA' */ 0x42475241,
+    bmdFormat10BitRGB                                  = /* 'r210' */ 0x72323130
+};
+
+/* End Enum BMDPixelFormat */
+
+/* Enum BMDVideoOutputFlags - Flags to control the output of ancillary data along with video. */
+
+typedef uint32_t BMDVideoOutputFlags;
+enum _BMDVideoOutputFlags {
+    bmdVideoOutputFlagDefault                          = 0,
+    bmdVideoOutputRP188                                = 1 << 0,
+    bmdVideoOutputVANC                                 = 1 << 1
+};
+
+/* End Enum BMDVideoOutputFlags */
+
+/* Enum BMDFrameFlags - Frame flags */
+
+typedef uint32_t BMDFrameFlags;
+enum _BMDFrameFlags {
+    bmdFrameFlagDefault                                = 0,
+    bmdFrameFlagFlipVertical                           = 1 << 0,
+
+    /* Flags that are valid only for frames returned through IDeckLinkInput */
+
+    bmdFrameHasNoInputSource                           = 1 << 31
+};
+
+/* End Enum BMDFrameFlags */
+
+/* Enum BMDVideoInputFlags - Flags applicable to video input */
+
+typedef uint32_t BMDVideoInputFlags;
+enum _BMDVideoInputFlags {
+    bmdVideoInputFlagDefault                           = 0,
+    bmdVideoInputEnableFormatDetection                 = 1 << 0
+};
+
+/* End Enum BMDVideoInputFlags */
+
+/* Enum BMDVideoInputFormatChangedEvents - Bitmask passed to the VideoInputFormatChanged notification to identify the properties of the input signal that have changed */
+
+typedef uint32_t BMDVideoInputFormatChangedEvents;
+enum _BMDVideoInputFormatChangedEvents {
+    bmdVideoInputDisplayModeChanged                    = 1 << 0,
+    bmdVideoInputFieldDominanceChanged                 = 1 << 1,
+    bmdVideoInputColorspaceChanged                     = 1 << 2
+};
+
+/* End Enum BMDVideoInputFormatChangedEvents */
+
+/* Enum BMDDetectedVideoInputFormatFlags - Flags passed to the VideoInputFormatChanged notification to describe the detected video input signal */
+
+typedef uint32_t BMDDetectedVideoInputFormatFlags;
+enum _BMDDetectedVideoInputFormatFlags {
+    bmdDetectedVideoInputYCbCr422                      = 1 << 0,
+    bmdDetectedVideoInputRGB444                        = 1 << 1
+};
+
+/* End Enum BMDDetectedVideoInputFormatFlags */
+
+/* Enum BMDOutputFrameCompletionResult - Frame Completion Callback */
+
+typedef uint32_t BMDOutputFrameCompletionResult;
+enum _BMDOutputFrameCompletionResult {
+    bmdOutputFrameCompleted,                          
+    bmdOutputFrameDisplayedLate,                      
+    bmdOutputFrameDropped,                            
+    bmdOutputFrameFlushed                             
+};
+
+/* End Enum BMDOutputFrameCompletionResult */
+
+/* Enum BMDAudioSampleRate - Audio sample rates supported for output/input */
+
+typedef uint32_t BMDAudioSampleRate;
+enum _BMDAudioSampleRate {
+    bmdAudioSampleRate48kHz                            = 48000
+};
+
+/* End Enum BMDAudioSampleRate */
+
+/* Enum BMDAudioSampleType - Audio sample sizes supported for output/input */
+
+typedef uint32_t BMDAudioSampleType;
+enum _BMDAudioSampleType {
+    bmdAudioSampleType16bitInteger                     = 16,
+    bmdAudioSampleType32bitInteger                     = 32
+};
+
+/* End Enum BMDAudioSampleType */
+
+/* Enum BMDAudioOutputStreamType - Audio output stream type */
+
+typedef uint32_t BMDAudioOutputStreamType;
+enum _BMDAudioOutputStreamType {
+    bmdAudioOutputStreamContinuous,                   
+    bmdAudioOutputStreamContinuousDontResample,       
+    bmdAudioOutputStreamTimestamped                   
+};
+
+/* End Enum BMDAudioOutputStreamType */
+
+/* Enum BMDDisplayModeSupport - Output mode supported flags */
+
+typedef uint32_t BMDDisplayModeSupport;
+enum _BMDDisplayModeSupport {
+    bmdDisplayModeNotSupported                         = 0,
+    bmdDisplayModeSupported,                          
+    bmdDisplayModeSupportedWithConversion             
+};
+
+/* End Enum BMDDisplayModeSupport */
+
+/* Enum BMDTimecodeFormat - Timecode formats for frame metadata */
+
+typedef uint32_t BMDTimecodeFormat;
+enum _BMDTimecodeFormat {
+    bmdTimecodeRP188                                   = /* 'rp18' */ 0x72703138,
+    bmdTimecodeVITC                                    = /* 'vitc' */ 0x76697463,
+    bmdTimecodeSerial                                  = /* 'seri' */ 0x73657269
+};
+
+/* End Enum BMDTimecodeFormat */
+
+/* Enum BMDTimecodeFlags - Timecode flags */
+
+typedef uint32_t BMDTimecodeFlags;
+enum _BMDTimecodeFlags {
+    bmdTimecodeFlagDefault                             = 0,
+    bmdTimecodeIsDropFrame                             = 1 << 0
+};
+
+/* End Enum BMDTimecodeFlags */
+
+/* Enum BMDVideoConnection - Video connection types */
+
+typedef uint32_t BMDVideoConnection;
+enum _BMDVideoConnection {
+    bmdVideoConnectionSDI                              = /* 'sdi ' */ 0x73646920,
+    bmdVideoConnectionHDMI                             = /* 'hdmi' */ 0x68646D69,
+    bmdVideoConnectionOpticalSDI                       = /* 'opti' */ 0x6F707469,
+    bmdVideoConnectionComponent                        = /* 'cpnt' */ 0x63706E74,
+    bmdVideoConnectionComposite                        = /* 'cmst' */ 0x636D7374,
+    bmdVideoConnectionSVideo                           = /* 'svid' */ 0x73766964
+};
+
+/* End Enum BMDVideoConnection */
+
+/* Enum BMDAnalogVideoFlags - Analog video display flags */
+
+typedef uint32_t BMDAnalogVideoFlags;
+enum _BMDAnalogVideoFlags {
+    bmdAnalogVideoFlagCompositeSetup75                 = 1 << 0,
+    bmdAnalogVideoFlagComponentBetacamLevels           = 1 << 1
+};
+
+/* End Enum BMDAnalogVideoFlags */
+
+/* Enum BMDAudioConnection - Audio connection types */
+
+typedef uint32_t BMDAudioConnection;
+enum _BMDAudioConnection {
+    bmdAudioConnectionEmbedded                         = /* 'embd' */ 0x656D6264,
+    bmdAudioConnectionAESEBU                           = /* 'aes ' */ 0x61657320,
+    bmdAudioConnectionAnalog                           = /* 'anlg' */ 0x616E6C67
+};
+
+/* End Enum BMDAudioConnection */
+
+/* Enum BMDVideoOutputConversionMode - Video/audio conversion mode */
+
+typedef uint32_t BMDVideoOutputConversionMode;
+enum _BMDVideoOutputConversionMode {
+    bmdNoVideoOutputConversion                         = /* 'none' */ 0x6E6F6E65,
+    bmdVideoOutputLetterboxDownonversion               = /* 'ltbx' */ 0x6C746278,
+    bmdVideoOutputAnamorphicDownonversion              = /* 'amph' */ 0x616D7068,
+    bmdVideoOutputHD720toHD1080Conversion              = /* '720c' */ 0x37323063,
+    bmdVideoOutputHardwareLetterboxDownconversion      = /* 'HWlb' */ 0x48576C62,
+    bmdVideoOutputHardwareAnamorphicDownconversion     = /* 'HWam' */ 0x4857616D,
+    bmdVideoOutputHardwareCenterCutDownconversion      = /* 'HWcc' */ 0x48576363
+};
+
+/* End Enum BMDVideoOutputConversionMode */
+
+/* Enum BMDVideoInputConversionMode - Video input conversion mode */
+
+typedef uint32_t BMDVideoInputConversionMode;
+enum _BMDVideoInputConversionMode {
+    bmdNoVideoInputConversion                          = /* 'none' */ 0x6E6F6E65,
+    bmdVideoInputLetterboxDownconversionFromHD1080     = /* '10lb' */ 0x31306C62,
+    bmdVideoInputAnamorphicDownconversionFromHD1080    = /* '10am' */ 0x3130616D,
+    bmdVideoInputLetterboxDownconversionFromHD720      = /* '72lb' */ 0x37326C62,
+    bmdVideoInputAnamorphicDownconversionFromHD720     = /* '72am' */ 0x3732616D,
+    bmdVideoInputLetterboxUpconversion                 = /* 'lbup' */ 0x6C627570,
+    bmdVideoInputAnamorphicUpconversion                = /* 'amup' */ 0x616D7570
+};
+
+/* End Enum BMDVideoInputConversionMode */
+
+/* Enum BMDDeckLinkAttributeID - DeckLink Atribute ID */
+
+typedef uint32_t BMDDeckLinkAttributeID;
+enum _BMDDeckLinkAttributeID {
+
+    /* Flags */
+
+    BMDDeckLinkSupportsInternalKeying                  = /* 'keyi' */ 0x6B657969,
+    BMDDeckLinkSupportsExternalKeying                  = /* 'keye' */ 0x6B657965,
+    BMDDeckLinkSupportsHDKeying                        = /* 'keyh' */ 0x6B657968,
+    BMDDeckLinkSupportsInputFormatDetection            = /* 'infd' */ 0x696E6664,
+    BMDDeckLinkHasSerialPort                           = /* 'hspt' */ 0x68737074,
+
+    /* Integers */
+
+    BMDDeckLinkMaximumAudioChannels                    = /* 'mach' */ 0x6D616368,
+
+    /* Strings */
+
+    BMDDeckLinkSerialPortDeviceName                    = /* 'slpn' */ 0x736C706E
+};
+
+/* End Enum BMDDeckLinkAttributeID */
+
+#if defined(__cplusplus)
+
+/* Forward Declarations */
+
+class IDeckLinkVideoOutputCallback;
+class IDeckLinkInputCallback;
+class IDeckLinkMemoryAllocator;
+class IDeckLinkAudioOutputCallback;
+class IDeckLinkIterator;
+class IDeckLinkDisplayModeIterator;
+class IDeckLinkDisplayMode;
+class IDeckLink;
+class IDeckLinkOutput;
+class IDeckLinkInput;
+class IDeckLinkTimecode;
+class IDeckLinkVideoFrame;
+class IDeckLinkMutableVideoFrame;
+class IDeckLinkVideoInputFrame;
+class IDeckLinkVideoFrameAncillary;
+class IDeckLinkAudioInputPacket;
+class IDeckLinkScreenPreviewCallback;
+class IDeckLinkGLScreenPreviewHelper;
+class IDeckLinkConfiguration;
+class IDeckLinkAttributes;
+class IDeckLinkKeyer;
+
+/* End Forward Declarations */
+
+/* Interface IDeckLinkVideoOutputCallback - Frame completion callback. */
+
+class IDeckLinkVideoOutputCallback : public IUnknown
+{
+public:
+    virtual HRESULT ScheduledFrameCompleted (/* in */ IDeckLinkVideoFrame *completedFrame, /* in */ BMDOutputFrameCompletionResult result) = 0;
+    virtual HRESULT ScheduledPlaybackHasStopped (void) = 0;
+
+protected:
+    virtual ~IDeckLinkVideoOutputCallback () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkVideoOutputCallback */
+
+/* Interface IDeckLinkInputCallback - Frame arrival callback. */
+
+class IDeckLinkInputCallback : public IUnknown
+{
+public:
+    virtual HRESULT VideoInputFormatChanged (/* in */ BMDVideoInputFormatChangedEvents notificationEvents, /* in */ IDeckLinkDisplayMode *newDisplayMode, /* in */ BMDDetectedVideoInputFormatFlags detectedSignalFlags) = 0;
+    virtual HRESULT VideoInputFrameArrived (/* in */ IDeckLinkVideoInputFrame *videoFrame, /* in */ IDeckLinkAudioInputPacket *audioPacket) = 0;
+
+protected:
+    virtual ~IDeckLinkInputCallback () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkInputCallback */
+
+/* Interface IDeckLinkMemoryAllocator - Memory allocator for video frames. */
+
+class IDeckLinkMemoryAllocator : public IUnknown
+{
+public:
+    virtual HRESULT AllocateBuffer (uint32_t bufferSize, /* out */ void **allocatedBuffer) = 0;
+    virtual HRESULT ReleaseBuffer (/* in */ void *buffer) = 0;
+
+    virtual HRESULT Commit (void) = 0;
+    virtual HRESULT Decommit (void) = 0;
+};
+
+/* End Interface IDeckLinkMemoryAllocator */
+
+/* Interface IDeckLinkAudioOutputCallback - Optional callback to allow audio samples to be pulled as required. */
+
+class IDeckLinkAudioOutputCallback : public IUnknown
+{
+public:
+    virtual HRESULT RenderAudioSamples (bool preroll) = 0;
+};
+
+/* End Interface IDeckLinkAudioOutputCallback */
+
+/* Interface IDeckLinkIterator - enumerates installed DeckLink hardware */
+
+class IDeckLinkIterator : public IUnknown
+{
+public:
+    virtual HRESULT Next (/* out */ IDeckLink **deckLinkInstance) = 0;
+};
+
+/* End Interface IDeckLinkIterator */
+
+/* Interface IDeckLinkDisplayModeIterator - enumerates over supported input/output display modes. */
+
+class IDeckLinkDisplayModeIterator : public IUnknown
+{
+public:
+    virtual HRESULT Next (/* out */ IDeckLinkDisplayMode **deckLinkDisplayMode) = 0;
+
+protected:
+    virtual ~IDeckLinkDisplayModeIterator () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkDisplayModeIterator */
+
+/* Interface IDeckLinkDisplayMode - represents a display mode */
+
+class IDeckLinkDisplayMode : public IUnknown
+{
+public:
+    virtual HRESULT GetName (/* out */ const char **name) = 0;
+    virtual BMDDisplayMode GetDisplayMode (void) = 0;
+    virtual long GetWidth (void) = 0;
+    virtual long GetHeight (void) = 0;
+    virtual HRESULT GetFrameRate (/* out */ BMDTimeValue *frameDuration, /* out */ BMDTimeScale *timeScale) = 0;
+    virtual BMDFieldDominance GetFieldDominance (void) = 0;
+
+protected:
+    virtual ~IDeckLinkDisplayMode () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkDisplayMode */
+
+/* Interface IDeckLink - represents a DeckLink device */
+
+class IDeckLink : public IUnknown
+{
+public:
+    virtual HRESULT GetModelName (/* out */ const char **modelName) = 0;
+};
+
+/* End Interface IDeckLink */
+
+/* Interface IDeckLinkOutput - Created by QueryInterface from IDeckLink. */
+
+class IDeckLinkOutput : public IUnknown
+{
+public:
+    virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0;
+    virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+    virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+    /* Video Output */
+
+    virtual HRESULT EnableVideoOutput (BMDDisplayMode displayMode, BMDVideoOutputFlags flags) = 0;
+    virtual HRESULT DisableVideoOutput (void) = 0;
+
+    virtual HRESULT SetVideoOutputFrameMemoryAllocator (/* in */ IDeckLinkMemoryAllocator *theAllocator) = 0;
+    virtual HRESULT CreateVideoFrame (int32_t width, int32_t height, int32_t rowBytes, BMDPixelFormat pixelFormat, BMDFrameFlags flags, /* out */ IDeckLinkMutableVideoFrame **outFrame) = 0;
+    virtual HRESULT CreateAncillaryData (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ IDeckLinkVideoFrameAncillary **outBuffer) = 0;
+
+    virtual HRESULT DisplayVideoFrameSync (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+    virtual HRESULT ScheduleVideoFrame (/* in */ IDeckLinkVideoFrame *theFrame, BMDTimeValue displayTime, BMDTimeValue displayDuration, BMDTimeScale timeScale) = 0;
+    virtual HRESULT SetScheduledFrameCompletionCallback (/* in */ IDeckLinkVideoOutputCallback *theCallback) = 0;
+    virtual HRESULT GetBufferedVideoFrameCount (/* out */ uint32_t *bufferedFrameCount) = 0;
+
+    /* Audio Output */
+
+    virtual HRESULT EnableAudioOutput (BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, uint32_t channelCount, BMDAudioOutputStreamType streamType) = 0;
+    virtual HRESULT DisableAudioOutput (void) = 0;
+
+    virtual HRESULT WriteAudioSamplesSync (/* in */ void *buffer, uint32_t sampleFrameCount, /* out */ uint32_t *sampleFramesWritten) = 0;
+
+    virtual HRESULT BeginAudioPreroll (void) = 0;
+    virtual HRESULT EndAudioPreroll (void) = 0;
+    virtual HRESULT ScheduleAudioSamples (/* in */ void *buffer, uint32_t sampleFrameCount, BMDTimeValue streamTime, BMDTimeScale timeScale, /* out */ uint32_t *sampleFramesWritten) = 0;
+
+    virtual HRESULT GetBufferedAudioSampleFrameCount (/* out */ uint32_t *bufferedSampleFrameCount) = 0;
+    virtual HRESULT FlushBufferedAudioSamples (void) = 0;
+
+    virtual HRESULT SetAudioCallback (/* in */ IDeckLinkAudioOutputCallback *theCallback) = 0;
+
+    /* Output Control */
+
+    virtual HRESULT StartScheduledPlayback (BMDTimeValue playbackStartTime, BMDTimeScale timeScale, double playbackSpeed) = 0;
+    virtual HRESULT StopScheduledPlayback (BMDTimeValue stopPlaybackAtTime, /* out */ BMDTimeValue *actualStopTime, BMDTimeScale timeScale) = 0;
+    virtual HRESULT IsScheduledPlaybackRunning (/* out */ bool *active) = 0;
+    virtual HRESULT GetHardwareReferenceClock (BMDTimeScale desiredTimeScale, /* out */ BMDTimeValue *elapsedTimeSinceSchedulerBegan) = 0;
+
+protected:
+    virtual ~IDeckLinkOutput () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkOutput */
+
+/* Interface IDeckLinkInput - Created by QueryInterface from IDeckLink. */
+
+class IDeckLinkInput : public IUnknown
+{
+public:
+    virtual HRESULT DoesSupportVideoMode (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, /* out */ BMDDisplayModeSupport *result) = 0;
+    virtual HRESULT GetDisplayModeIterator (/* out */ IDeckLinkDisplayModeIterator **iterator) = 0;
+
+    virtual HRESULT SetScreenPreviewCallback (/* in */ IDeckLinkScreenPreviewCallback *previewCallback) = 0;
+
+    /* Video Input */
+
+    virtual HRESULT EnableVideoInput (BMDDisplayMode displayMode, BMDPixelFormat pixelFormat, BMDVideoInputFlags flags) = 0;
+    virtual HRESULT DisableVideoInput (void) = 0;
+    virtual HRESULT GetAvailableVideoFrameCount (/* out */ uint32_t *availableFrameCount) = 0;
+
+    /* Audio Input */
+
+    virtual HRESULT EnableAudioInput (BMDAudioSampleRate sampleRate, BMDAudioSampleType sampleType, uint32_t channelCount) = 0;
+    virtual HRESULT DisableAudioInput (void) = 0;
+    virtual HRESULT GetAvailableAudioSampleFrameCount (/* out */ uint32_t *availableSampleFrameCount) = 0;
+
+    /* Input Control */
+
+    virtual HRESULT StartStreams (void) = 0;
+    virtual HRESULT StopStreams (void) = 0;
+    virtual HRESULT PauseStreams (void) = 0;
+    virtual HRESULT FlushStreams (void) = 0;
+    virtual HRESULT SetCallback (/* in */ IDeckLinkInputCallback *theCallback) = 0;
+
+protected:
+    virtual ~IDeckLinkInput () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkInput */
+
+/* Interface IDeckLinkTimecode - Used for video frame timecode representation. */
+
+class IDeckLinkTimecode : public IUnknown
+{
+public:
+    virtual BMDTimecodeBCD GetBCD (void) = 0;
+    virtual HRESULT GetComponents (/* out */ uint8_t *hours, /* out */ uint8_t *minutes, /* out */ uint8_t *seconds, /* out */ uint8_t *frames) = 0;
+    virtual HRESULT GetString (/* out */ const char **timecode) = 0;
+    virtual BMDTimecodeFlags GetFlags (void) = 0;
+
+protected:
+    virtual ~IDeckLinkTimecode () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkTimecode */
+
+/* Interface IDeckLinkVideoFrame - Interface to encapsulate a video frame; can be caller-implemented. */
+
+class IDeckLinkVideoFrame : public IUnknown
+{
+public:
+    virtual long GetWidth (void) = 0;
+    virtual long GetHeight (void) = 0;
+    virtual long GetRowBytes (void) = 0;
+    virtual BMDPixelFormat GetPixelFormat (void) = 0;
+    virtual BMDFrameFlags GetFlags (void) = 0;
+    virtual HRESULT GetBytes (/* out */ void **buffer) = 0;
+
+    virtual HRESULT GetTimecode (BMDTimecodeFormat format, /* out */ IDeckLinkTimecode **timecode) = 0;
+    virtual HRESULT GetAncillaryData (/* out */ IDeckLinkVideoFrameAncillary **ancillary) = 0;
+
+protected:
+    virtual ~IDeckLinkVideoFrame () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkVideoFrame */
+
+/* Interface IDeckLinkMutableVideoFrame - Created by IDeckLinkOutput::CreateVideoFrame. */
+
+class IDeckLinkMutableVideoFrame : public IDeckLinkVideoFrame
+{
+public:
+    virtual HRESULT SetFlags (BMDFrameFlags newFlags) = 0;
+
+    virtual HRESULT SetTimecode (BMDTimecodeFormat format, /* in */ IDeckLinkTimecode *timecode) = 0;
+    virtual HRESULT SetTimecodeFromComponents (BMDTimecodeFormat format, uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t frames, BMDTimecodeFlags flags) = 0;
+    virtual HRESULT SetAncillaryData (/* in */ IDeckLinkVideoFrameAncillary *ancillary) = 0;
+
+protected:
+    virtual ~IDeckLinkMutableVideoFrame () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkMutableVideoFrame */
+
+/* Interface IDeckLinkVideoInputFrame - Provided by the IDeckLinkVideoInput frame arrival callback. */
+
+class IDeckLinkVideoInputFrame : public IDeckLinkVideoFrame
+{
+public:
+    virtual HRESULT GetStreamTime (/* out */ BMDTimeValue *frameTime, /* out */ BMDTimeValue *frameDuration, BMDTimeScale timeScale) = 0;
+
+protected:
+    virtual ~IDeckLinkVideoInputFrame () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkVideoInputFrame */
+
+/* Interface IDeckLinkVideoFrameAncillary - Obtained through QueryInterface() on an IDeckLinkVideoFrame object. */
+
+class IDeckLinkVideoFrameAncillary : public IUnknown
+{
+public:
+
+    virtual HRESULT GetBufferForVerticalBlankingLine (uint32_t lineNumber, /* out */ void **buffer) = 0;
+    virtual BMDPixelFormat GetPixelFormat (void) = 0;
+    virtual BMDDisplayMode GetDisplayMode (void) = 0;
+
+protected:
+    virtual ~IDeckLinkVideoFrameAncillary () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkVideoFrameAncillary */
+
+/* Interface IDeckLinkAudioInputPacket - Provided by the IDeckLinkInput callback. */
+
+class IDeckLinkAudioInputPacket : public IUnknown
+{
+public:
+    virtual long GetSampleFrameCount (void) = 0;
+    virtual HRESULT GetBytes (/* out */ void **buffer) = 0;
+    virtual HRESULT GetPacketTime (/* out */ BMDTimeValue *packetTime, BMDTimeScale timeScale) = 0;
+
+protected:
+    virtual ~IDeckLinkAudioInputPacket () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkAudioInputPacket */
+
+/* Interface IDeckLinkScreenPreviewCallback - Screen preview callback */
+
+class IDeckLinkScreenPreviewCallback : public IUnknown
+{
+public:
+    virtual HRESULT DrawFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+
+protected:
+    virtual ~IDeckLinkScreenPreviewCallback () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkScreenPreviewCallback */
+
+/* Interface IDeckLinkGLScreenPreviewHelper - Created with CoCreateInstance(). */
+
+class IDeckLinkGLScreenPreviewHelper : public IUnknown
+{
+public:
+
+    /* Methods must be called with OpenGL context set */
+
+    virtual HRESULT InitializeGL (void) = 0;
+    virtual HRESULT PaintGL (void) = 0;
+    virtual HRESULT SetFrame (/* in */ IDeckLinkVideoFrame *theFrame) = 0;
+
+protected:
+    virtual ~IDeckLinkGLScreenPreviewHelper () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkGLScreenPreviewHelper */
+
+/* Interface IDeckLinkConfiguration - Created by QueryInterface from IDeckLink. */
+
+class IDeckLinkConfiguration : public IUnknown
+{
+public:
+    virtual HRESULT GetConfigurationValidator (/* out */ IDeckLinkConfiguration **configObject) = 0;
+    virtual HRESULT WriteConfigurationToPreferences (void) = 0;
+
+    /* Video Output Configuration */
+
+    virtual HRESULT SetVideoOutputFormat (BMDVideoConnection videoOutputConnection) = 0;
+    virtual HRESULT IsVideoOutputActive (BMDVideoConnection videoOutputConnection, /* out */ bool *active) = 0;
+
+    virtual HRESULT SetAnalogVideoOutputFlags (BMDAnalogVideoFlags analogVideoFlags) = 0;
+    virtual HRESULT GetAnalogVideoOutputFlags (/* out */ BMDAnalogVideoFlags *analogVideoFlags) = 0;
+
+    virtual HRESULT EnableFieldFlickerRemovalWhenPaused (bool enable) = 0;
+    virtual HRESULT IsEnabledFieldFlickerRemovalWhenPaused (/* out */ bool *enabled) = 0;
+
+    virtual HRESULT Set444And3GBpsVideoOutput (bool enable444VideoOutput, bool enable3GbsOutput) = 0;
+    virtual HRESULT Get444And3GBpsVideoOutput (/* out */ bool *is444VideoOutputEnabled, /* out */ bool *threeGbsOutputEnabled) = 0;
+
+    virtual HRESULT SetVideoOutputConversionMode (BMDVideoOutputConversionMode conversionMode) = 0;
+    virtual HRESULT GetVideoOutputConversionMode (/* out */ BMDVideoOutputConversionMode *conversionMode) = 0;
+
+    virtual HRESULT Set_HD1080p24_to_HD1080i5994_Conversion (bool enable) = 0;
+    virtual HRESULT Get_HD1080p24_to_HD1080i5994_Conversion (/* out */ bool *enabled) = 0;
+
+    /* Video Input Configuration */
+
+    virtual HRESULT SetVideoInputFormat (BMDVideoConnection videoInputFormat) = 0;
+    virtual HRESULT GetVideoInputFormat (/* out */ BMDVideoConnection *videoInputFormat) = 0;
+
+    virtual HRESULT SetAnalogVideoInputFlags (BMDAnalogVideoFlags analogVideoFlags) = 0;
+    virtual HRESULT GetAnalogVideoInputFlags (/* out */ BMDAnalogVideoFlags *analogVideoFlags) = 0;
+
+    virtual HRESULT SetVideoInputConversionMode (BMDVideoInputConversionMode conversionMode) = 0;
+    virtual HRESULT GetVideoInputConversionMode (/* out */ BMDVideoInputConversionMode *conversionMode) = 0;
+
+    virtual HRESULT SetBlackVideoOutputDuringCapture (bool blackOutInCapture) = 0;
+    virtual HRESULT GetBlackVideoOutputDuringCapture (/* out */ bool *blackOutInCapture) = 0;
+
+    virtual HRESULT Set32PulldownSequenceInitialTimecodeFrame (uint32_t aFrameTimecode) = 0;
+    virtual HRESULT Get32PulldownSequenceInitialTimecodeFrame (/* out */ uint32_t *aFrameTimecode) = 0;
+
+    virtual HRESULT SetVancSourceLineMapping (uint32_t activeLine1VANCsource, uint32_t activeLine2VANCsource, uint32_t activeLine3VANCsource) = 0;
+    virtual HRESULT GetVancSourceLineMapping (/* out */ uint32_t *activeLine1VANCsource, /* out */ uint32_t *activeLine2VANCsource, /* out */ uint32_t *activeLine3VANCsource) = 0;
+
+    /* Audio Input Configuration */
+
+    virtual HRESULT SetAudioInputFormat (BMDAudioConnection audioInputFormat) = 0;
+    virtual HRESULT GetAudioInputFormat (/* out */ BMDAudioConnection *audioInputFormat) = 0;
+};
+
+/* End Interface IDeckLinkConfiguration */
+
+/* Interface IDeckLinkAttributes - DeckLink Attribute interface */
+
+class IDeckLinkAttributes : public IUnknown
+{
+public:
+    virtual HRESULT GetFlag (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ bool *value) = 0;
+    virtual HRESULT GetInt (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ int64_t *value) = 0;
+    virtual HRESULT GetFloat (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ double *value) = 0;
+    virtual HRESULT GetString (/* in */ BMDDeckLinkAttributeID cfgID, /* out */ const char **value) = 0;
+
+protected:
+    virtual ~IDeckLinkAttributes () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkAttributes */
+
+/* Interface IDeckLinkKeyer - DeckLink Keyer interface */
+
+class IDeckLinkKeyer : public IUnknown
+{
+public:
+    virtual HRESULT Enable (/* in */ bool isExternal) = 0;
+    virtual HRESULT SetLevel (/* in */ uint8_t level) = 0;
+    virtual HRESULT RampUp (/* in */ uint32_t numberOfFrames) = 0;
+    virtual HRESULT RampDown (/* in */ uint32_t numberOfFrames) = 0;
+    virtual HRESULT Disable (void) = 0;
+
+protected:
+    virtual ~IDeckLinkKeyer () {}; // call Release method to drop reference count
+};
+
+/* End Interface IDeckLinkKeyer */
+
+/* Functions */
+
+extern "C" {
+
+    IDeckLinkIterator *CreateDeckLinkIteratorInstance (void);
+    IDeckLinkGLScreenPreviewHelper *CreateOpenGLScreenPreviewHelper (void);
+
+};
+
+/* End Functions */
+
+#endif      // defined(__cplusplus)
+#endif      // __DeckLink_API_h__
Index: trunk/src/testing/app/DecklinkCapture/include/LinuxCOM.h
===================================================================
--- trunk/src/testing/app/DecklinkCapture/include/LinuxCOM.h	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/include/LinuxCOM.h	(revision 4)
@@ -0,0 +1,99 @@
+/* -LICENSE-START-
+** Copyright (c) 2009 Blackmagic Design
+**
+** Permission is hereby granted, free of charge, to any person or organization
+** obtaining a copy of the software and accompanying documentation covered by
+** this license (the "Software") to use, reproduce, display, distribute,
+** execute, and transmit the Software, and to prepare derivative works of the
+** Software, and to permit third-parties to whom the Software is furnished to
+** do so, all subject to the following:
+** 
+** The copyright notices in the Software and this entire statement, including
+** the above license grant, this restriction and the following disclaimer,
+** must be included in all copies of the Software, in whole or in part, and
+** all derivative works of the Software, unless such copies or derivative
+** works are solely in the form of machine-executable object code generated by
+** a source language processor.
+** 
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+** DEALINGS IN THE SOFTWARE.
+** -LICENSE-END-
+*/
+
+#ifndef __LINUX_COM_H_
+#define __LINUX_COM_H_
+
+struct REFIID
+{	
+	unsigned char byte0;
+	unsigned char byte1;
+	unsigned char byte2;
+	unsigned char byte3;
+	unsigned char byte4;
+	unsigned char byte5;
+	unsigned char byte6;
+	unsigned char byte7;
+	unsigned char byte8;
+	unsigned char byte9;
+	unsigned char byte10;
+	unsigned char byte11;
+	unsigned char byte12;
+	unsigned char byte13;
+	unsigned char byte14;
+	unsigned char byte15;
+};
+
+typedef REFIID CFUUIDBytes;
+#define CFUUIDGetUUIDBytes(x)	x
+
+typedef int HRESULT;
+typedef unsigned long ULONG;
+typedef void *LPVOID;
+
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+#define FAILED(Status) ((HRESULT)(Status)<0)
+
+#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)
+#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
+#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
+#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)
+#define SEVERITY_SUCCESS 0
+#define SEVERITY_ERROR 1
+
+#define MAKE_HRESULT(sev,fac,code) ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_UNEXPECTED ((HRESULT)0x8000FFFFL)
+#define E_NOTIMPL ((HRESULT)0x80000001L)
+#define E_OUTOFMEMORY ((HRESULT)0x80000002L)
+#define E_INVALIDARG ((HRESULT)0x80000003L)
+#define E_NOINTERFACE ((HRESULT)0x80000004L)
+#define E_POINTER ((HRESULT)0x80000005L)
+#define E_HANDLE ((HRESULT)0x80000006L)
+#define E_ABORT ((HRESULT)0x80000007L)
+#define E_FAIL ((HRESULT)0x80000008L)
+#define E_ACCESSDENIED ((HRESULT)0x80000009L)
+
+#define STDMETHODCALLTYPE
+
+#define IID_IUnknown		(REFIID){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}
+#define IUnknownUUID		IID_IUnknown
+
+#ifdef __cplusplus
+class IUnknown
+{
+    public:
+    	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0;
+    	virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
+    	virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
+};
+#endif
+
+#endif 
+
Index: trunk/src/testing/app/DecklinkCapture/YUV2JPG
===================================================================
--- trunk/src/testing/app/DecklinkCapture/YUV2JPG	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/YUV2JPG	(revision 4)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+convert -size 1920x1080 -depth 8 -sampling-factor 4:2:2 $1 $2
+
Index: trunk/src/testing/app/DecklinkCapture/decklinkcapture.cpp
===================================================================
--- trunk/src/testing/app/DecklinkCapture/decklinkcapture.cpp	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/decklinkcapture.cpp	(revision 4)
@@ -0,0 +1,673 @@
+#include "DeckLinkAPI.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+
+void	print_input_modes (IDeckLink* deckLink);
+void	print_output_modes (IDeckLink* deckLink);
+
+void	print_input_capabilities (IDeckLink* deckLink);
+void	print_output_capabilities (IDeckLink* deckLink);
+
+void	print_capabilities();
+void	capture(int device, int mode, int connection);
+
+sail sageInf; // sail object
+void *PixelFrame;
+
+// 1080i
+//int winWidth = 1920;
+//int winHeight = 1080;
+
+// 720p
+//int winWidth = 1280;
+//int winHeight = 720;
+
+// PAL
+int winWidth = 720;
+int winHeight = 576;
+
+// NTSC
+//int winWidth = 720;
+//int winHeight = 486;
+
+
+
+int main (int argc, char** argv)
+{
+    int done = 0;
+    
+
+	if (argc == 1) {
+		fprintf(stderr, "Decklink Capture Program\n");
+	}
+	else {
+		if ( (argc==2) && (!strcmp(argv[1],"-h")) ) {
+			fprintf(stderr, "Usage> %s \n", argv[0]);
+			fprintf(stderr, "\t\t\t -l\tlist capabilities\n");
+			fprintf(stderr, "\t\t\t -i input mode\tSelect a capture settings\n");
+		}
+		if ( (argc==2) && (!strcmp(argv[1],"-l")) ) {
+			print_capabilities();
+		}
+		if ( (argc==4) && (!strcmp(argv[1],"-i")) ) {
+
+		int card = 0;
+		int mode = atoi(argv[2]);
+		int connexion = atoi(argv[3]);
+
+                // SAGE setup
+            sailConfig cfg;
+            cfg.init("decklinkcapture.conf");   // every app has a config file named "appName.conf"
+            std::cout << "SAIL configuration was initialized by decklinkcapture.conf" << std::endl;
+	 
+            cfg.setAppName("decklinkcapture");
+            cfg.rank = 0;
+            cfg.resX = winWidth;
+            cfg.resY = winHeight;
+            cfg.winWidth = winWidth;
+            cfg.winHeight = winHeight;
+
+            sageRect renderImageMap;
+            renderImageMap.left = 0.0;
+            renderImageMap.right = 1.0;
+            renderImageMap.bottom = 0.0;
+            renderImageMap.top = 1.0;
+
+            cfg.imageMap = renderImageMap;
+            cfg.pixFmt = PIXFMT_YUV;
+            cfg.rowOrd = TOP_TO_BOTTOM;
+            cfg.master = true;
+	 		 
+            sageInf.init(cfg);
+            std::cout << "sail initialized " << std::endl;
+            
+                // Capture setup
+		capture(card, mode, connexion);
+            //capture(0, 3, 1); // 0: card0, 3: 1080i 50, 1: HDMI
+            //capture(0, 5, 1); // HD 1080i 59.94
+            //capture(0, 4, 2); // HD 1080i 59.94 Component
+            //capture(0, 5, 1); // HD 1080i 60
+            //capture(0, 2, 1); // PAL
+            //capture(0, 0, 1); // NTSC
+ 
+                // Just wait and process messages
+            while (!done) {
+                sageMessage msg;
+                
+                if (sageInf.checkMsg(msg, false) > 0) {
+                    switch (msg.getCode()) {
+                        case APP_QUIT : {
+                            exit(0);
+                            break;
+                        }
+                    }
+                }   
+                sleep(1);
+            }
+            
+		}
+	}
+
+	return 0;
+}
+
+class VideoDelegate : public IDeckLinkInputCallback
+{
+private:
+	int32_t mRefCount;
+	double  lastTime;
+    int     framecount;
+    
+public:
+    VideoDelegate () {
+         framecount = 0;
+    };
+						
+	virtual HRESULT		QueryInterface (REFIID iid, LPVOID *ppv)
+        {};
+	virtual ULONG		AddRef (void) {
+        return mRefCount++;
+    };
+	virtual ULONG		Release (void) {
+        int32_t		newRefValue;
+        
+        newRefValue = mRefCount--;
+        if (newRefValue == 0)
+        {
+            delete this;
+            return 0;
+        }        
+        return newRefValue;
+    };
+
+	virtual HRESULT	VideoInputFrameArrived (IDeckLinkVideoInputFrame* arrivedFrame,
+                                                IDeckLinkAudioInputPacket*);
+        virtual HRESULT VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags)
+        {};
+
+};
+
+HRESULT	VideoDelegate::VideoInputFrameArrived (IDeckLinkVideoInputFrame* arrivedFrame,
+                                               IDeckLinkAudioInputPacket*)
+{
+		BMDTimeValue		frameTime, frameDuration;
+		int					hours, minutes, seconds, frames;
+		HRESULT				theResult;
+		
+		arrivedFrame->GetStreamTime(&frameTime, &frameDuration, 600);
+		
+		hours = (frameTime / (600 * 60*60));
+		minutes = (frameTime / (600 * 60)) % 60;
+		seconds = (frameTime / 600) % 60;
+		frames = (frameTime / 6) % 100;
+		//fprintf(stderr, "frame> %02d:%02d:%02d:%02d", hours, minutes, seconds, frames);
+		//fprintf(stderr, "\t %dx%d\r", arrivedFrame->GetWidth(), arrivedFrame->GetHeight() );
+
+        arrivedFrame->GetBytes(&PixelFrame);
+        unsigned char *rgbBuffer = (unsigned char *)sageInf.getBuffer();
+        memcpy(rgbBuffer, PixelFrame, arrivedFrame->GetWidth()*arrivedFrame->GetHeight()*2);
+        sageInf.swapBuffer();
+    
+#if 0
+        char fn[128];
+        memset(fn, 0, 128);
+        sprintf(fn, "frame%04d.yuv", framecount);
+        FILE *f=fopen(fn, "w+");
+        fwrite(PixelFrame, 1, 1920*1080*2, f);
+        fclose(f);
+#endif   
+
+        framecount++;
+        
+        return S_OK;
+
+}
+
+
+void capture(int device, int mode, int connection)
+{
+    int dnum, mnum, cnum;
+ 	int	itemCount;
+   
+	IDeckLinkIterator *deckLinkIterator;
+	IDeckLink         *deckLink;
+	HRESULT            result;
+
+	IDeckLinkInput*               deckLinkInput = NULL;
+	IDeckLinkDisplayModeIterator* displayModeIterator = NULL;
+	IDeckLinkDisplayMode*         displayMode = NULL;
+	IDeckLinkConfiguration       *deckLinkConfiguration = NULL;
+    VideoDelegate                *delegate;
+
+//     PixelFrame = (void*)malloc(1920*1080*2);
+//     memset(PixelFrame, 0, 1920*1080*2);;
+    
+
+    fprintf(stderr, "Starting> Capture on device %d, mode %d, connection %d\n", device, mode, connection);
+    
+        // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
+	deckLinkIterator = CreateDeckLinkIteratorInstance();
+	if (deckLinkIterator == NULL)
+	{
+		fprintf(stderr, "A DeckLink iterator could not be created (DeckLink drivers may not be installed).\n");
+		return;
+	}
+
+    dnum = 0;
+    deckLink = NULL;
+    
+	while (deckLinkIterator->Next(&deckLink) == S_OK)
+	{
+        if (device != dnum) {
+            dnum++;
+                // Release the IDeckLink instance when we've finished with it to prevent leaks
+            deckLink->Release();
+            continue;
+        }
+        dnum++;
+        
+		const char *deviceNameString = NULL;
+		
+            // *** Print the model name of the DeckLink card
+		result = deckLink->GetModelName(&deviceNameString);
+		if (result == S_OK)
+		{
+			char deviceName[64];	
+			fprintf(stderr, "Using device [%s]\n", deviceNameString);
+
+                // Query the DeckLink for its configuration interface
+            result = deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput);
+            if (result != S_OK)
+            {
+                fprintf(stderr, "Could not obtain the IDeckLinkInput interface - result = %08x\n", result);
+                return;
+            }
+
+                // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on input
+            result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
+            if (result != S_OK)
+            {
+                fprintf(stderr, "Could not obtain the video input display mode iterator - result = %08x\n", result);
+                return;
+            }
+
+            mnum = 0;
+            while (displayModeIterator->Next(&displayMode) == S_OK)
+            {
+                if (mode != mnum) {
+                    mnum++;
+                        // Release the IDeckLinkDisplayMode object to prevent a leak
+                    displayMode->Release();
+                    continue;
+                }
+                mnum++;                
+     
+                const char *displayModeString = NULL;
+                
+                result = displayMode->GetName(&displayModeString);
+                if (result == S_OK)
+                {
+                    BMDPixelFormat pf = bmdFormat8BitYUV;
+
+                    fprintf(stderr, "Stopping previous streams, if needed\n");
+                    deckLinkInput->StopStreams();
+
+                    const char *displayModeString = NULL;		
+                    displayMode->GetName(&displayModeString);
+                    fprintf(stderr, "Enable video input: %s\n", displayModeString);
+
+                    deckLinkInput->EnableVideoInput(displayMode->GetDisplayMode(), pf, 0);
+
+
+
+                    // Query the DeckLink for its configuration interface
+                    result = deckLinkInput->QueryInterface(IID_IDeckLinkConfiguration, (void**)&deckLinkConfiguration);
+                    if (result != S_OK)
+                    {
+                        fprintf(stderr, "Could not obtain the IDeckLinkConfiguration interface: %08x\n", result);
+                        return;
+                    }
+                    BMDVideoConnection conn;
+                    switch (connection) {
+                        case 0:
+                            conn = bmdVideoConnectionSDI;
+                            break;
+                        case 1:
+                            conn = bmdVideoConnectionHDMI;
+                            break;
+                        case 2:
+                            conn = bmdVideoConnectionComponent;
+                            break;
+                        case 3:
+                            conn = bmdVideoConnectionComposite;
+                            break;
+                        case 4:
+                            conn = bmdVideoConnectionSVideo;
+                            break;
+                        case 5:
+                            conn = bmdVideoConnectionOpticalSDI;
+                            break;
+                        default:
+                            break;
+                    }
+                    
+                    if (deckLinkConfiguration->SetVideoInputFormat(conn) == S_OK) {
+                        fprintf(stderr, "Input set to: %d\n", connection);
+                    }
+                    
+                    delegate = new VideoDelegate();
+                    deckLinkInput->SetCallback(delegate);
+                    
+                    fprintf(stderr, "Start capture\n", connection);
+                    deckLinkInput->StartStreams();
+
+               }
+
+            }
+	
+		}
+	}
+
+
+        // Release the IDeckLink instance when we've finished with it to prevent leaks
+    if (deckLink) deckLink->Release();
+        // Ensure that the interfaces we obtained are released to prevent a memory leak
+	if (displayModeIterator != NULL)
+		displayModeIterator->Release();
+
+   return;
+}
+    
+
+void print_capabilities()
+{
+	IDeckLinkIterator* deckLinkIterator;
+	IDeckLink*         deckLink;
+	int                numDevices = 0;
+	HRESULT            result;
+	
+        // Create an IDeckLinkIterator object to enumerate all DeckLink cards in the system
+	deckLinkIterator = CreateDeckLinkIteratorInstance();
+	if (deckLinkIterator == NULL)
+	{
+		fprintf(stderr, "A DeckLink iterator could not be created (DeckLink drivers may not be installed).\n");
+		return;
+	}
+	
+        // Enumerate all cards in this system
+	printf("Device(s):\n");
+	while (deckLinkIterator->Next(&deckLink) == S_OK)
+	{
+		const char *		deviceNameString = NULL;
+		
+            // *** Print the model name of the DeckLink card
+		result = deckLink->GetModelName(&deviceNameString);
+		if (result == S_OK)
+		{
+			char			deviceName[64];
+			
+			printf("\t%3d: =============== %s ===============\n", numDevices, deviceNameString);
+		}
+		
+            // ** List the video output display modes supported by the card
+		print_input_modes(deckLink);
+		
+            // ** List the input capabilities of the card
+		print_input_capabilities(deckLink);
+		
+            // Release the IDeckLink instance when we've finished with it to prevent leaks
+		deckLink->Release();
+
+            // Increment the total number of DeckLink cards found
+		numDevices++;
+	}
+	
+	
+        // If no DeckLink cards were found in the system, inform the user
+	if (numDevices == 0)
+		printf("No Blackmagic Design devices were found.\n");
+	printf("\n");
+}
+
+
+
+void print_input_modes (IDeckLink* deckLink)
+{
+	IDeckLinkInput*				deckLinkInput = NULL;
+	IDeckLinkDisplayModeIterator*		displayModeIterator = NULL;
+	IDeckLinkDisplayMode*			displayMode = NULL;
+	HRESULT					result;	
+	int mm = 0;
+	
+        // Query the DeckLink for its configuration interface
+	result = deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the IDeckLinkInput interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on input
+	result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the video input display mode iterator - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // List all supported output display modes
+	printf("Supported video input display modes:\n");
+	while (displayModeIterator->Next(&displayMode) == S_OK)
+	{
+		const char *			displayModeString = NULL;
+		
+		result = displayMode->GetName(&displayModeString);
+		if (result == S_OK)
+		{
+			char		modeName[64];
+			int		modeWidth;
+			int		modeHeight;
+			BMDTimeValue	frameRateDuration;
+			BMDTimeScale	frameRateScale;
+			
+			
+                // Obtain the display mode's properties
+			modeWidth = displayMode->GetWidth();
+			modeHeight = displayMode->GetHeight();
+			displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
+			printf("\t%3d) %-20s \t %d x %d \t %g FPS\n", mm, displayModeString, modeWidth, modeHeight, (double)frameRateScale / (double)frameRateDuration);
+			mm++;
+		}
+		
+            // Release the IDeckLinkDisplayMode object to prevent a leak
+		displayMode->Release();
+	}
+	
+	printf("\n");
+	
+  bail:
+        // Ensure that the interfaces we obtained are released to prevent a memory leak
+	if (displayModeIterator != NULL)
+		displayModeIterator->Release();
+	
+	if (deckLinkInput != NULL)
+		deckLinkInput->Release();
+}
+
+
+void	print_output_modes (IDeckLink* deckLink)
+{
+	IDeckLinkOutput*					deckLinkOutput = NULL;
+	IDeckLinkDisplayModeIterator*		displayModeIterator = NULL;
+	IDeckLinkDisplayMode*				displayMode = NULL;
+	HRESULT								result;	
+	
+        // Query the DeckLink for its configuration interface
+	result = deckLink->QueryInterface(IID_IDeckLinkOutput, (void**)&deckLinkOutput);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the IDeckLinkOutput interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output
+	result = deckLinkOutput->GetDisplayModeIterator(&displayModeIterator);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the video output display mode iterator - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // List all supported output display modes
+	printf("Supported video output display modes:\n");
+	while (displayModeIterator->Next(&displayMode) == S_OK)
+	{
+		const char *			displayModeString = NULL;
+		
+		result = displayMode->GetName(&displayModeString);
+		if (result == S_OK)
+		{
+			char			modeName[64];
+			int				modeWidth;
+			int				modeHeight;
+			BMDTimeValue	frameRateDuration;
+			BMDTimeScale	frameRateScale;
+			
+			
+                // Obtain the display mode's properties
+			modeWidth = displayMode->GetWidth();
+			modeHeight = displayMode->GetHeight();
+			displayMode->GetFrameRate(&frameRateDuration, &frameRateScale);
+			printf("\t%-20s \t %d x %d \t %g FPS\n", displayModeString, modeWidth, modeHeight, (double)frameRateScale / (double)frameRateDuration);
+		}
+		
+            // Release the IDeckLinkDisplayMode object to prevent a leak
+		displayMode->Release();
+	}
+	
+	printf("\n");
+	
+  bail:
+        // Ensure that the interfaces we obtained are released to prevent a memory leak
+	if (displayModeIterator != NULL)
+		displayModeIterator->Release();
+	
+	if (deckLinkOutput != NULL)
+		deckLinkOutput->Release();
+}
+
+void	print_input_capabilities (IDeckLink* deckLink)
+{
+	IDeckLinkConfiguration*		deckLinkConfiguration = NULL;
+	IDeckLinkConfiguration*		deckLinkValidator = NULL;
+	int							itemCount;
+	HRESULT						result;	
+	int mm = 0;
+	
+        // Query the DeckLink for its configuration interface
+	result = deckLink->QueryInterface(IID_IDeckLinkConfiguration, (void**)&deckLinkConfiguration);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the IDeckLinkConfiguration interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // Obtain a validator object from the IDeckLinkConfiguration interface.
+        // The validator object implements IDeckLinkConfiguration, however, all configuration changes are ignored
+        // and will not take effect.  However, you can use the returned result code from the validator object
+        // to determine whether the card supports a particular configuration.
+	
+	result = deckLinkConfiguration->GetConfigurationValidator(&deckLinkValidator);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the configuration validator interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+        // Use the validator object to determine which video input connections are available
+	printf("Supported video input connections:\n  ");
+	itemCount = 0;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionSDI) == S_OK)
+	{
+		printf("\t%3d) SDI\n", itemCount);
+	}
+    itemCount++;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionHDMI) == S_OK)
+	{
+		printf("\t%3d) HDMI\n", itemCount);
+	}
+    itemCount++;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionComponent) == S_OK)
+	{
+		printf("\t%3d) Component\n", itemCount);
+	}
+    itemCount++;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionComposite) == S_OK)
+	{
+		printf("\t%3d) Composite\n", itemCount);
+	}
+    itemCount++;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionSVideo) == S_OK)
+	{
+		printf("\t%3d) S-Video\n", itemCount);
+	}
+    itemCount++;
+	if (deckLinkValidator->SetVideoInputFormat(bmdVideoConnectionOpticalSDI) == S_OK)
+	{
+		printf("\t%3d) Optical SDI\n", itemCount);
+	}
+	
+	printf("\n");
+	
+  bail:
+	if (deckLinkValidator != NULL)
+		deckLinkValidator->Release();
+	
+	if (deckLinkConfiguration != NULL)
+		deckLinkConfiguration->Release();
+}
+
+void	print_output_capabilities (IDeckLink* deckLink)
+{
+	IDeckLinkConfiguration*		deckLinkConfiguration = NULL;
+	IDeckLinkConfiguration*		deckLinkValidator = NULL;
+	int							itemCount;
+	HRESULT						result;	
+	
+	// Query the DeckLink for its configuration interface
+	result = deckLink->QueryInterface(IID_IDeckLinkConfiguration, (void**)&deckLinkConfiguration);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the IDeckLinkConfiguration interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+	// Obtain a validator object from the IDeckLinkConfiguration interface.
+	// The validator object implements IDeckLinkConfiguration, however, all configuration changes are ignored
+	// and will not take effect.  However, you can use the returned result code from the validator object
+	// to determine whether the card supports a particular configuration.
+	
+	result = deckLinkConfiguration->GetConfigurationValidator(&deckLinkValidator);
+	if (result != S_OK)
+	{
+		fprintf(stderr, "Could not obtain the configuration validator interface - result = %08x\n", result);
+		goto bail;
+	}
+	
+	// Use the validator object to determine which video output connections are available
+	printf("Supported video output connections:\n  ");
+	itemCount = 0;
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionSDI) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("SDI");
+	}
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionHDMI) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("HDMI");
+	}
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionComponent) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("Component");
+	}
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionComposite) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("Composite");
+	}
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionSVideo) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("S-Video");
+	}
+	if (deckLinkValidator->SetVideoOutputFormat(bmdVideoConnectionOpticalSDI) == S_OK)
+	{
+		if (itemCount++ > 0)
+			printf(", ");
+		printf("Optical SDI");
+	}
+	
+	printf("\n\n");
+	
+bail:
+	if (deckLinkValidator != NULL)
+		deckLinkValidator->Release();
+	
+	if (deckLinkConfiguration != NULL)
+		deckLinkConfiguration->Release();
+}
+
+
Index: trunk/src/testing/app/DecklinkCapture/README.txt
===================================================================
--- trunk/src/testing/app/DecklinkCapture/README.txt	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/README.txt	(revision 4)
@@ -0,0 +1,6 @@
+Luc Renambot (c) 2009
+
+First implementation of a HD capture under Linux, using Blackmagic-design SDK (Declink SDK).
+
+For now, it captures HD video in YUV and sends it.
+
Index: trunk/src/testing/app/DecklinkCapture/decklinkcapture.conf
===================================================================
--- trunk/src/testing/app/DecklinkCapture/decklinkcapture.conf	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/decklinkcapture.conf	(revision 4)
@@ -0,0 +1,14 @@
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    0
+pixelBlockSize 64 64
+blockThreshold 0
+winX 100
+winY 100
+nwProtocol TCP
+asyncUpdate false
+streamType SAGE_BLOCK_HARD_SYNC
+
Index: trunk/src/testing/app/DecklinkCapture/Makefile
===================================================================
--- trunk/src/testing/app/DecklinkCapture/Makefile	(revision 4)
+++ trunk/src/testing/app/DecklinkCapture/Makefile	(revision 4)
@@ -0,0 +1,29 @@
+include ../../config.mk
+
+SDK_PATH=include
+
+COMPILER_FLAGS= -Wno-multichar -I$(SDK_PATH) -fno-rtti $(SAGE_CFLAGS) -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS) $(GLUT_CFLAGS)
+
+ifeq ($(MACHINE), Darwin)
+   COMPILER_FLAGS  += -FGLUT -FOpenGL
+   LIBS=-lpthread -L../../lib -lsail -framework GLUT -framework OpenGL -lobjc -lm 
+else
+   LIBS=-lpthread ${SUN_LIBS} -lm -ldl $(QUANTA_LDFLAGS) $(GLEW_LIB) -L../../lib -lsail -lm -ldl -lpthread
+endif
+
+PROJ_EXE=decklinkcapture
+
+default: $(PROJ_EXE)
+
+install: default
+	cp $(PROJ_EXE) ../../bin
+
+
+decklinkcapture: decklinkcapture.o $(SDK_PATH)/DeckLinkAPIDispatch.o
+	$(COMPILER) $(SAGE_LDFLAGS) -o decklinkcapture decklinkcapture.o $(SDK_PATH)/DeckLinkAPIDispatch.o $(LIBS)
+
+decklinkcapture.o: decklinkcapture.cpp
+	$(COMPILER) $(COMPILER_FLAGS) $(INCLUDE_DIR) -c decklinkcapture.cpp
+
+clean:
+	\rm -f *~ *.o $(PROJ_EXE)
Index: trunk/src/testing/app/fluidsGL/fluidsGL.cu
===================================================================
--- trunk/src/testing/app/fluidsGL/fluidsGL.cu	(revision 4)
+++ trunk/src/testing/app/fluidsGL/fluidsGL.cu	(revision 4)
@@ -0,0 +1,548 @@
+/*
+ * Copyright 1993-2009 NVIDIA Corporation.  All rights reserved.
+ *
+ * NVIDIA Corporation and its licensors retain all intellectual property and 
+ * proprietary rights in and to this software and related documentation and 
+ * any modifications thereto.  Any use, reproduction, disclosure, or distribution 
+ * of this software and related documentation without an express license 
+ * agreement from NVIDIA Corporation is strictly prohibited.
+ * 
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <GL/glew.h>
+#include <cufft.h>
+#include <cutil_inline.h>
+#include <cutil_gl_inline.h>
+#include <cuda_gl_interop.h>
+//#include <rendercheck_gl.h>
+
+#if defined(SAGE_APP)
+#include "sail.h"
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+#endif
+
+#if defined(__APPLE__) || defined(MACOSX)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include "fluidsGL_kernels.cu"
+
+#define MAX_EPSILON_ERROR 1.0f
+
+// Define the files that are to be save and the reference images for validation
+const char *sOriginal[] =
+{
+    "fluidsGL.ppm",
+    NULL
+};
+
+const char *sReference[] =
+{
+    "ref_fluidsGL.ppm",
+    NULL
+};
+
+// CUDA example code that implements the frequency space version of 
+// Jos Stam's paper 'Stable Fluids' in 2D. This application uses the 
+// CUDA FFT library (CUFFT) to perform velocity diffusion and to 
+// force non-divergence in the velocity field at each time step. It uses 
+// CUDA-OpenGL interoperability to update the particle field directly
+// instead of doing a copy to system memory before drawing. Texture is
+// used for automatic bilinear interpolation at the velocity advection step. 
+
+#ifdef __DEVICE_EMULATION__
+#define DIM    64        // Square size of solver domain
+#else
+#define DIM    768       // Square size of solver domani
+#endif
+#define DS    (DIM*DIM)  // Total domain size
+#define CPADW (DIM/2+1)  // Padded width for real->complex in-place FFT
+#define RPADW (2*(DIM/2+1))  // Padded width for real->complex in-place FFT
+#define PDS   (DIM*CPADW) // Padded total domain size
+
+#define DT     0.09f     // Delta T for interative solver
+#define VIS    0.0025f   // Viscosity constant
+#define FORCE (5.8f*DIM) // Force scale factor 
+#define FR     4         // Force update radius
+
+#define TILEX 64 // Tile width
+#define TILEY 64 // Tile height
+#define TIDSX 64 // Tids in X
+#define TIDSY 4  // Tids in Y
+
+void cleanup(void);       
+
+// CUFFT plan handle
+static cufftHandle planr2c;
+static cufftHandle planc2r;
+static cData *vxfield = NULL;
+static cData *vyfield = NULL;
+
+cData *hvfield = NULL;
+cData *dvfield = NULL;
+static int wWidth = max(512,DIM);
+static int wHeight = max(512,DIM);
+
+static int clicked = 0;
+static int fpsCount = 0;
+static int fpsLimit = 1;
+unsigned int timer;
+
+// Particle data
+GLuint vbo = 0;                 // OpenGL vertex buffer object
+static cData *particles = NULL; // particle positions in host memory
+static int lastx = 0, lasty = 0;
+
+// Texture pitch
+size_t tPitch = 0; // Now this is compatible with gcc in 64-bit
+
+bool				  g_bQAReadback     = false;
+bool				  g_bQAAddTestForce = true;
+int					  g_iFrameToCompare = 100;
+int                   g_TotalErrors     = 0;
+
+// CheckFBO/BackBuffer class objects
+//CheckRender       *g_CheckRender = NULL;
+
+void autoTest();
+
+
+void addForces(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r) { 
+
+    dim3 tids(2*r+1, 2*r+1);
+    
+    addForces_k<<<1, tids>>>(v, dx, dy, spx, spy, fx, fy, r, tPitch);
+    cutilCheckMsg("addForces_k failed.");
+}
+
+void advectVelocity(cData *v, float *vx, float *vy,
+                    int dx, int pdx, int dy, float dt) { 
+    
+    dim3 grid((dx/TILEX)+(!(dx%TILEX)?0:1), (dy/TILEY)+(!(dy%TILEY)?0:1));
+
+    dim3 tids(TIDSX, TIDSY);
+
+    updateTexture(v, DIM*sizeof(cData), DIM, tPitch);
+    advectVelocity_k<<<grid, tids>>>(v, vx, vy, dx, pdx, dy, dt, TILEY/TIDSY);
+
+    cutilCheckMsg("advectVelocity_k failed.");
+}
+
+void diffuseProject(cData *vx, cData *vy, int dx, int dy, float dt,
+                    float visc) { 
+    // Forward FFT
+    cufftExecR2C(planr2c, (cufftReal*)vx, (cufftComplex*)vx); 
+    cufftExecR2C(planr2c, (cufftReal*)vy, (cufftComplex*)vy);
+
+    uint3 grid = make_uint3((dx/TILEX)+(!(dx%TILEX)?0:1), 
+                            (dy/TILEY)+(!(dy%TILEY)?0:1), 1);
+
+    uint3 tids = make_uint3(TIDSX, TIDSY, 1);
+    
+    diffuseProject_k<<<grid, tids>>>(vx, vy, dx, dy, dt, visc, TILEY/TIDSY);
+    cutilCheckMsg("diffuseProject_k failed.");
+
+    // Inverse FFT
+    cufftExecC2R(planc2r, (cufftComplex*)vx, (cufftReal*)vx); 
+    cufftExecC2R(planc2r, (cufftComplex*)vy, (cufftReal*)vy);
+}
+
+void updateVelocity(cData *v, float *vx, float *vy, 
+                    int dx, int pdx, int dy) { 
+
+    dim3 grid((dx/TILEX)+(!(dx%TILEX)?0:1), (dy/TILEY)+(!(dy%TILEY)?0:1));
+
+    dim3 tids(TIDSX, TIDSY);
+
+    updateVelocity_k<<<grid, tids>>>(v, vx, vy, dx, pdx, dy, TILEY/TIDSY, tPitch);
+    cutilCheckMsg("updateVelocity_k failed.");
+}
+
+void advectParticles(GLuint buffer, cData *v, int dx, int dy, float dt) {
+    
+    dim3 grid((dx/TILEX)+(!(dx%TILEX)?0:1), (dy/TILEY)+(!(dy%TILEY)?0:1));
+
+    dim3 tids(TIDSX, TIDSY);
+
+    cData *p;
+    cudaGLMapBufferObject((void**)&p, buffer);
+    cutilCheckMsg("cudaGLMapBufferObject failed");
+   
+    advectParticles_k<<<grid, tids>>>(p, v, dx, dy, dt, TILEY/TIDSY, tPitch);
+    cutilCheckMsg("advectParticles_k failed.");
+    
+    cudaGLUnmapBufferObject(buffer);
+    cutilCheckMsg("cudaGLUnmapBufferObject failed");
+}
+
+void display(void) {  
+   cutilCheckError(cutStartTimer(timer));  
+    
+   // simulate fluid
+   advectVelocity(dvfield, (float*)vxfield, (float*)vyfield, DIM, RPADW, DIM, DT);
+   diffuseProject(vxfield, vyfield, CPADW, DIM, DT, VIS);
+   updateVelocity(dvfield, (float*)vxfield, (float*)vyfield, DIM, RPADW, DIM);
+   advectParticles(vbo, dvfield, DIM, DIM, DT);
+   
+   // render points from vertex buffer
+   glClear(GL_COLOR_BUFFER_BIT);
+   glColor4f(0,1,0,0.5f); glPointSize(1);
+   glEnable(GL_POINT_SMOOTH);
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glEnableClientState(GL_VERTEX_ARRAY);    
+   glDisable(GL_DEPTH_TEST);
+   glDisable(GL_CULL_FACE); 
+   glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
+   glVertexPointer(2, GL_FLOAT, 0, NULL);
+   glDrawArrays(GL_POINTS, 0, DS);
+   glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+   glDisableClientState(GL_VERTEX_ARRAY); 
+   glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
+   glDisable(GL_TEXTURE_2D);
+
+   // Finish timing before swap buffers to avoid refresh sync
+   cutilCheckError(cutStopTimer(timer));  
+   glutSwapBuffers();
+    
+   fpsCount++;
+   if (fpsCount == fpsLimit) {
+       char fps[256];
+       float ifps = 1.f / (cutGetAverageTimerValue(timer) / 1000.f);
+       sprintf(fps, "Cuda/GL Stable Fluids (%d x %d): %3.1f fps", DIM, DIM, ifps);  
+       glutSetWindowTitle(fps);
+       fpsCount = 0; 
+       fpsLimit = (int)max(ifps, 1.f);
+       cutilCheckError(cutResetTimer(timer));  
+    }
+
+#if defined(SAGE_APP)
+	glReadPixels(0, 0, wWidth, wHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);
+	sageInf.swapBuffer();
+	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+         sageMessage msg;
+         if (sageInf.checkMsg(msg, false) > 0) {
+                 switch (msg.getCode()) {
+                         case APP_QUIT : {
+                                exit(0);
+                                break;
+                        }
+                 }
+         }
+#endif
+
+    glutPostRedisplay();
+}
+
+void autoTest() 
+{
+	for(int count=0;count<g_iFrameToCompare;count++)
+	{
+		// add in a little force so the automated testing is interesing.
+		if(g_bQAReadback && g_bQAAddTestForce) 
+		{
+			int x = wWidth/(count+1); int y = wHeight/(count+1);
+			float fx = (x / (float)wWidth);        
+			float fy = (y / (float)wHeight);
+			int nx = (int)(fx * DIM);        
+			int ny = (int)(fy * DIM);   
+
+			int ddx = 35;
+			int ddy = 35;
+			fx = ddx / (float)wWidth;
+			fy = ddy / (float)wHeight;
+			int spy = ny-FR;
+			int spx = nx-FR;
+
+            addForces(dvfield, DIM, DIM, spx, spy, FORCE * DT * fx, FORCE * DT * fy, FR);
+            lastx = x; lasty = y;
+			//g_bQAAddTestForce = false; // only add it once
+		}
+        display();
+    }
+
+	// compare to offical reference image, printing PASS or FAIL.
+    /*
+    printf("> (Frame %d) Readback BackBuffer\n", 100);
+    g_CheckRender->readback( wWidth, wHeight, NULL );
+    g_CheckRender->savePPM(sOriginal[0], true, NULL);
+    if (!g_CheckRender->PPMvsPPM(sOriginal[0], sReference[0], MAX_EPSILON_ERROR)) {
+        g_TotalErrors++;
+    }
+    */
+}
+
+
+void idle(void) {
+    glutPostRedisplay();
+}
+
+void initParticles(cData *p, int dx, int dy) {
+    int i, j;
+    for (i = 0; i < dy; i++) {
+        for (j = 0; j < dx; j++) {
+            p[i*dx+j].x = ((j+0.5)/dx) + 
+                          (rand() / (float)RAND_MAX - 0.5f) / dx;
+            p[i*dx+j].y = ((i+0.5)/dy) + 
+                          (rand() / (float)RAND_MAX - 0.5f) / dy;
+        }
+    }
+}
+
+void keyboard( unsigned char key, int x, int y) {
+    switch( key) {
+        case 27:
+#if defined(SAGE_APP)
+                sageInf.shutdown();
+#endif
+		exit (0);
+        case 'r':
+            memset(hvfield, 0, sizeof(cData) * DS);
+            cudaMemcpy(dvfield, hvfield, sizeof(cData) * DS, 
+                       cudaMemcpyHostToDevice);
+
+            initParticles(particles, DIM, DIM);
+
+            cudaGLUnregisterBufferObject(vbo);
+            cutilCheckMsg("cudaGLUnregisterBufferObject failed");
+    
+            glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
+            glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(cData) * DS, 
+                            particles, GL_DYNAMIC_DRAW_ARB);
+            glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+            cudaGLRegisterBufferObject(vbo);
+            cutilCheckMsg("cudaGLRegisterBufferObject failed");
+            break;
+        default: break;
+    }
+}
+
+void click(int button, int updown, int x, int y) {
+    lastx = x; lasty = y;
+    clicked = !clicked;
+}
+
+void motion (int x, int y) {
+    // Convert motion coordinates to domain
+    float fx = (lastx / (float)wWidth);        
+    float fy = (lasty / (float)wHeight);
+    int nx = (int)(fx * DIM);        
+    int ny = (int)(fy * DIM);   
+    
+    if (clicked && nx < DIM-FR && nx > FR-1 && ny < DIM-FR && ny > FR-1) {
+        int ddx = x - lastx;
+        int ddy = y - lasty;
+        fx = ddx / (float)wWidth;
+        fy = ddy / (float)wHeight;
+        int spy = ny-FR;
+        int spx = nx-FR;
+        addForces(dvfield, DIM, DIM, spx, spy, FORCE * DT * fx, FORCE * DT * fy, FR);
+        lastx = x; lasty = y;
+    } 
+    glutPostRedisplay();
+}
+
+void reshape(int x, int y) {
+    // no resize for SAGE
+    //wWidth = x; wHeight = y;
+
+    glViewport(0, 0, x, y);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, 1, 1, 0, 0, 1); 
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glutPostRedisplay();
+}
+
+void cleanup(void) {
+    cudaGLUnregisterBufferObject(vbo);
+    cutilCheckMsg("cudaGLUnregisterBufferObject failed");
+
+    unbindTexture();
+    deleteTexture();
+
+    // Free all host and device resources
+    free(hvfield); free(particles); 
+    cudaFree(dvfield); 
+    cudaFree(vxfield); cudaFree(vyfield);
+    cufftDestroy(planr2c);
+    cufftDestroy(planc2r);
+
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+    glDeleteBuffersARB(1, &vbo);
+    
+    cutilCheckError(cutDeleteTimer(timer));  
+}
+
+int initGL(int argc, char **argv)
+{
+    glutInit(&argc, argv);
+    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
+    glutInitWindowSize(wWidth, wHeight);
+    glutCreateWindow("Compute Stable Fluids");
+    glutDisplayFunc(display);
+    glutKeyboardFunc(keyboard);
+    glutMouseFunc(click);
+    glutMotionFunc(motion);
+    glutReshapeFunc(reshape);
+    glutIdleFunc(idle);
+
+#if defined(SAGE_APP)
+         sageRect cudaMap;
+         cudaMap.left = 0.0;
+         cudaMap.right = 1.0;
+         cudaMap.bottom = 0.0;
+         cudaMap.top = 1.0;
+
+         sailConfig scfg;
+         scfg.init("cuda.conf");
+         scfg.setAppName("cuda");
+         scfg.rank = 0;
+
+         scfg.resX = wWidth;
+         scfg.resY = wHeight;
+         scfg.winX = 0;
+         scfg.winY = 0;
+         scfg.winWidth = 2*wWidth;
+         scfg.winHeight = 2*wHeight;
+         scfg.imageMap = cudaMap;
+         scfg.pixFmt = PIXFMT_888;
+         scfg.rowOrd = BOTTOM_TO_TOP;
+         scfg.master = true;
+
+         sageInf.init(scfg);
+
+	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+         fprintf(stderr, "sail initialized\n");
+#endif
+
+    glewInit();
+    if (! glewIsSupported(
+        "GL_ARB_vertex_buffer_object"
+		)) {
+        fprintf( stderr, "ERROR: Support for necessary OpenGL extensions missing.");
+        fflush( stderr);
+        return CUTFalse;
+    }
+    return CUTTrue;
+}
+
+
+int main(int argc, char** argv) 
+{
+    // First initialize OpenGL context, so we can properly set the GL for CUDA.
+    // This is necessary in order to achieve optimal performance with OpenGL/CUDA interop.
+    if (CUTFalse == initGL(argc, argv)) {
+        return CUTFalse;
+    }
+
+    // use command-line specified CUDA device, otherwise use device with highest Gflops/s
+    if( cutCheckCmdLineFlag(argc, (const char**)argv, "device") )
+        cutilGLDeviceInit(argc, argv);
+    else {
+        cudaGLSetGLDevice( cutGetMaxGflopsDeviceId() );
+    }
+
+	// automatied build testing harness
+    if (cutCheckCmdLineFlag(argc, (const char **)argv, "qatest") ||
+		cutCheckCmdLineFlag(argc, (const char **)argv, "noprompt"))
+    {
+        g_bQAReadback = true;
+    }
+
+    // Allocate and initialize host data
+    GLint bsize;
+
+    cutilCheckError(cutCreateTimer(&timer));
+    cutilCheckError(cutResetTimer(timer));  
+    
+    hvfield = (cData*)malloc(sizeof(cData) * DS);
+    memset(hvfield, 0, sizeof(cData) * DS);
+  
+    // Allocate and initialize device data
+    cudaMallocPitch((void**)&dvfield, &tPitch, sizeof(cData)*DIM, DIM);
+    
+    cudaMemcpy(dvfield, hvfield, sizeof(cData) * DS, 
+               cudaMemcpyHostToDevice); 
+    // Temporary complex velocity field data     
+    cudaMalloc((void**)&vxfield, sizeof(cData) * PDS);
+    cudaMalloc((void**)&vyfield, sizeof(cData) * PDS);
+    
+    setupTexture(DIM, DIM);
+    bindTexture();
+    
+    // Create particle array
+    particles = (cData*)malloc(sizeof(cData) * DS);
+    memset(particles, 0, sizeof(cData) * DS);   
+    
+    initParticles(particles, DIM, DIM); 
+
+    // Create CUFFT transform plan configuration
+    cufftPlan2d(&planr2c, DIM, DIM, CUFFT_R2C);
+    cufftPlan2d(&planc2r, DIM, DIM, CUFFT_C2R);
+#if 0    
+    glutInit(&argc, argv);
+    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
+    glutInitWindowSize(wWidth, wHeight);
+    glutCreateWindow("Compute Stable Fluids");
+    glutDisplayFunc(display);
+    glutKeyboardFunc(keyboard);
+    glutMouseFunc(click);
+    glutMotionFunc(motion);
+    glutReshapeFunc(reshape);
+    glutIdleFunc(idle);
+
+    glewInit();
+    if (! glewIsSupported(
+        "GL_ARB_vertex_buffer_object"
+		)) {
+        fprintf( stderr, "ERROR: Support for necessary OpenGL extensions missing.");
+        fflush( stderr);
+        return CUTFalse;
+    }
+#endif
+    glGenBuffersARB(1, &vbo);
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
+    glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(cData) * DS, 
+                    particles, GL_DYNAMIC_DRAW_ARB);
+
+    glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &bsize); 
+    if (bsize != (sizeof(cData) * DS))
+        goto EXTERR;
+    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+
+    cudaGLRegisterBufferObject(vbo);
+    cutilCheckMsg("cudaGLRegisterBufferObject failed");
+
+    if (g_bQAReadback)
+    {
+/*      g_CheckRender = new CheckBackBuffer(wWidth, wHeight, 4);
+        g_CheckRender->setPixelFormat(GL_RGBA);
+        g_CheckRender->setExecPath(argv[0]);
+        g_CheckRender->EnableQAReadback(true);
+
+        autoTest();
+*/
+    } else {
+        atexit(cleanup); 
+        glutMainLoop();
+    }
+
+    cudaThreadExit();
+    return 0;
+
+EXTERR:
+    printf("Failed to initialize GL extensions.\n");
+
+    cudaThreadExit();
+    return 1;
+}
Index: trunk/src/testing/app/fluidsGL/cuda.conf
===================================================================
--- trunk/src/testing/app/fluidsGL/cuda.conf	(revision 4)
+++ trunk/src/testing/app/fluidsGL/cuda.conf	(revision 4)
@@ -0,0 +1,12 @@
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+pixelBlockSize 64 64
+blockThreshold 0
+winX 0
+winY 0
+nwProtocol TCP
+asyncUpdate false
+streamType SAGE_BLOCK_HARD_SYNC
Index: trunk/src/testing/app/fluidsGL/fluidsGL_kernels.cu
===================================================================
--- trunk/src/testing/app/fluidsGL/fluidsGL_kernels.cu	(revision 4)
+++ trunk/src/testing/app/fluidsGL/fluidsGL_kernels.cu	(revision 4)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1993-2009 NVIDIA Corporation.  All rights reserved.
+ *
+ * NVIDIA Corporation and its licensors retain all intellectual property and 
+ * proprietary rights in and to this software and related documentation and 
+ * any modifications thereto.  Any use, reproduction, disclosure, or distribution 
+ * of this software and related documentation without an express license 
+ * agreement from NVIDIA Corporation is strictly prohibited.
+ * 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "fluidsGL_kernels.h"
+
+// Texture reference for reading velocity field
+texture<float2, 2> texref;
+static cudaArray *array = NULL;
+
+void setupTexture(int x, int y) {
+    // Wrap mode appears to be the new default
+    texref.filterMode = cudaFilterModeLinear;
+    cudaChannelFormatDesc desc = cudaCreateChannelDesc<float2>();
+
+    cudaMallocArray(&array, &desc, y, x);
+    cutilCheckMsg("cudaMalloc failed");
+}
+
+void bindTexture(void) {
+    cudaBindTextureToArray(texref, array);
+    cutilCheckMsg("cudaBindTexture failed");
+}
+
+void unbindTexture(void) {
+    cudaUnbindTexture(texref);
+    cutilCheckMsg("cudaUnbindTexture failed");
+}
+    
+void updateTexture(cData *data, size_t wib, size_t h, size_t pitch) {
+    cudaMemcpy2DToArray(array, 0, 0, data, pitch, wib, h, cudaMemcpyDeviceToDevice);
+    cutilCheckMsg("cudaMemcpy failed"); 
+}
+
+void deleteTexture(void) {
+    cudaFreeArray(array);
+    cutilCheckMsg("cudaFreeArray failed");
+}
+
+// Note that these kernels are designed to work with arbitrary 
+// domain sizes, not just domains that are multiples of the tile
+// size. Therefore, we have extra code that checks to make sure
+// a given thread location falls within the domain boundaries in
+// both X and Y. Also, the domain is covered by looping over
+// multiple elements in the Y direction, while there is a one-to-one
+// mapping between threads in X and the tile size in X.
+// Nolan Goodnight 9/22/06
+
+// This method adds constant force vectors to the velocity field 
+// stored in 'v' according to v(x,t+1) = v(x,t) + dt * f.
+__global__ void 
+addForces_k(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r, size_t pitch) {
+
+    int tx = threadIdx.x;
+    int ty = threadIdx.y;
+    cData *fj = (cData*)((char*)v + (ty + spy) * pitch) + tx + spx;
+
+    cData vterm = *fj;
+    tx -= r; ty -= r;
+    float s = 1.f / (1.f + tx*tx*tx*tx + ty*ty*ty*ty);
+    vterm.x += s * fx;
+    vterm.y += s * fy;
+    *fj = vterm;
+}
+
+// This method performs the velocity advection step, where we
+// trace velocity vectors back in time to update each grid cell.
+// That is, v(x,t+1) = v(p(x,-dt),t). Here we perform bilinear
+// interpolation in the velocity space.
+__global__ void 
+advectVelocity_k(cData *v, float *vx, float *vy,
+                 int dx, int pdx, int dy, float dt, int lb) {
+
+    int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
+    int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
+    int p;
+
+    cData vterm, ploc;
+    float vxterm, vyterm;
+    // gtidx is the domain location in x for this thread
+    if (gtidx < dx) {
+        for (p = 0; p < lb; p++) {
+            // fi is the domain location in y for this thread
+            int fi = gtidy + p;
+            if (fi < dy) {
+                int fj = fi * pdx + gtidx;
+                vterm = tex2D(texref, (float)gtidx, (float)fi);
+                ploc.x = (gtidx + 0.5f) - (dt * vterm.x * dx);
+                ploc.y = (fi + 0.5f) - (dt * vterm.y * dy);
+                vterm = tex2D(texref, ploc.x, ploc.y);
+                vxterm = vterm.x; vyterm = vterm.y; 
+                vx[fj] = vxterm;
+                vy[fj] = vyterm; 
+            }
+        }
+    }
+}
+
+// This method performs velocity diffusion and forces mass conservation 
+// in the frequency domain. The inputs 'vx' and 'vy' are complex-valued 
+// arrays holding the Fourier coefficients of the velocity field in
+// X and Y. Diffusion in this space takes a simple form described as:
+// v(k,t) = v(k,t) / (1 + visc * dt * k^2), where visc is the viscosity,
+// and k is the wavenumber. The projection step forces the Fourier
+// velocity vectors to be orthogonal to the vectors for each
+// wavenumber: v(k,t) = v(k,t) - ((k dot v(k,t) * k) / k^2.
+__global__ void 
+diffuseProject_k(cData *vx, cData *vy, int dx, int dy, float dt, 
+                 float visc, int lb) {
+
+    int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
+    int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
+    int p;
+
+    cData xterm, yterm;
+    // gtidx is the domain location in x for this thread
+    if (gtidx < dx) {
+        for (p = 0; p < lb; p++) {
+            // fi is the domain location in y for this thread
+            int fi = gtidy + p;
+            if (fi < dy) {
+                int fj = fi * dx + gtidx;
+                xterm = vx[fj];
+                yterm = vy[fj];
+
+                // Compute the index of the wavenumber based on the
+                // data order produced by a standard NN FFT.
+                int iix = gtidx;
+                int iiy = (fi>dy/2)?(fi-(dy)):fi;
+
+                // Velocity diffusion
+                float kk = (float)(iix * iix + iiy * iiy); // k^2 
+                float diff = 1.f / (1.f + visc * dt * kk);
+                xterm.x *= diff; xterm.y *= diff;
+                yterm.x *= diff; yterm.y *= diff;
+
+                // Velocity projection
+                if (kk > 0.f) {
+                    float rkk = 1.f / kk;
+                    // Real portion of velocity projection
+                    float rkp = (iix * xterm.x + iiy * yterm.x);
+                    // Imaginary portion of velocity projection
+                    float ikp = (iix * xterm.y + iiy * yterm.y);
+                    xterm.x -= rkk * rkp * iix;
+                    xterm.y -= rkk * ikp * iix;
+                    yterm.x -= rkk * rkp * iiy;
+                    yterm.y -= rkk * ikp * iiy;
+                }
+                
+                vx[fj] = xterm;
+                vy[fj] = yterm;
+            }
+        }
+    }
+}
+
+// This method updates the velocity field 'v' using the two complex 
+// arrays from the previous step: 'vx' and 'vy'. Here we scale the 
+// real components by 1/(dx*dy) to account for an unnormalized FFT. 
+__global__ void 
+updateVelocity_k(cData *v, float *vx, float *vy, 
+                 int dx, int pdx, int dy, int lb, size_t pitch) {
+
+    int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
+    int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
+    int p;
+
+    float vxterm, vyterm;
+    cData nvterm;
+    // gtidx is the domain location in x for this thread
+    if (gtidx < dx) {
+        for (p = 0; p < lb; p++) {
+            // fi is the domain location in y for this thread
+            int fi = gtidy + p;
+            if (fi < dy) {
+                int fjr = fi * pdx + gtidx; 
+                vxterm = vx[fjr];
+                vyterm = vy[fjr];
+
+                // Normalize the result of the inverse FFT
+                float scale = 1.f / (dx * dy);
+                nvterm.x = vxterm * scale;
+                nvterm.y = vyterm * scale;
+               
+                cData *fj = (cData*)((char*)v + fi * pitch) + gtidx;
+                *fj = nvterm;
+            }
+        } // If this thread is inside the domain in Y
+    } // If this thread is inside the domain in X
+}
+
+// This method updates the particles by moving particle positions
+// according to the velocity field and time step. That is, for each
+// particle: p(t+1) = p(t) + dt * v(p(t)).  
+__global__ void 
+advectParticles_k(cData *part, cData *v, int dx, int dy, 
+                  float dt, int lb, size_t pitch) {
+
+    int gtidx = blockIdx.x * blockDim.x + threadIdx.x;
+    int gtidy = blockIdx.y * (lb * blockDim.y) + threadIdx.y * lb;
+    int p;
+
+    // gtidx is the domain location in x for this thread
+    cData pterm, vterm;
+    if (gtidx < dx) {
+        for (p = 0; p < lb; p++) {
+            // fi is the domain location in y for this thread
+            int fi = gtidy + p;
+            if (fi < dy) {
+                int fj = fi * dx + gtidx;
+                pterm = part[fj];
+                
+                int xvi = ((int)(pterm.x * dx));
+                int yvi = ((int)(pterm.y * dy));
+                vterm = *((cData*)((char*)v + yvi * pitch) + xvi);   
+ 
+                pterm.x += dt * vterm.x;
+                pterm.x = pterm.x - (int)pterm.x;            
+                pterm.x += 1.f; 
+                pterm.x = pterm.x - (int)pterm.x;              
+                pterm.y += dt * vterm.y;
+                pterm.y = pterm.y - (int)pterm.y;            
+                pterm.y += 1.f; 
+                pterm.y = pterm.y - (int)pterm.y;                  
+
+                part[fj] = pterm;
+            }
+        } // If this thread is inside the domain in Y
+    } // If this thread is inside the domain in X
+}
Index: trunk/src/testing/app/fluidsGL/fluidsGL_kernels.h
===================================================================
--- trunk/src/testing/app/fluidsGL/fluidsGL_kernels.h	(revision 4)
+++ trunk/src/testing/app/fluidsGL/fluidsGL_kernels.h	(revision 4)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1993-2009 NVIDIA Corporation.  All rights reserved.
+ *
+ * NVIDIA Corporation and its licensors retain all intellectual property and 
+ * proprietary rights in and to this software and related documentation and 
+ * any modifications thereto.  Any use, reproduction, disclosure, or distribution 
+ * of this software and related documentation without an express license 
+ * agreement from NVIDIA Corporation is strictly prohibited.
+ * 
+ */
+#ifndef __STABLEFLUIDS_KERNELS_H_
+#define __STABLEFLUIDS_KERNELS_H_
+
+// Vector data type used to velocity and force fields
+typedef float2 cData;
+
+void setupTexture(int x, int y);
+void bindTexture(void);
+void unbindTexture(void);
+void updateTexture(cData *data, size_t w, size_t h, size_t pitch);
+void deleteTexture(void);
+
+// This method adds constant force vectors to the velocity field 
+// stored in 'v' according to v(x,t+1) = v(x,t) + dt * f.
+__global__ void 
+addForces_k(cData *v, int dx, int dy, int spx, int spy, float fx, float fy, int r, size_t pitch);
+
+// This method performs the velocity advection step, where we
+// trace velocity vectors back in time to update each grid cell.
+// That is, v(x,t+1) = v(p(x,-dt),t). Here we perform bilinear
+// interpolation in the velocity space.
+__global__ void 
+advectVelocity_k(cData *v, float *vx, float *vy,
+                 int dx, int pdx, int dy, float dt, int lb);
+
+// This method performs velocity diffusion and forces mass conservation 
+// in the frequency domain. The inputs 'vx' and 'vy' are complex-valued 
+// arrays holding the Fourier coefficients of the velocity field in
+// X and Y. Diffusion in this space takes a simple form described as:
+// v(k,t) = v(k,t) / (1 + visc * dt * k^2), where visc is the viscosity,
+// and k is the wavenumber. The projection step forces the Fourier
+// velocity vectors to be orthogonal to the wave wave vectors for each
+// wavenumber: v(k,t) = v(k,t) - ((k dot v(k,t) * k) / k^2.
+__global__ void 
+diffuseProject_k(cData *vx, cData *vy, int dx, int dy, float dt, 
+                 float visc, int lb);
+    
+// This method updates the velocity field 'v' using the two complex 
+// arrays from the previous step: 'vx' and 'vy'. Here we scale the 
+// real components by 1/(dx*dy) to account for an unnormalized FFT. 
+__global__ void 
+updateVelocity_k(cData *v, float *vx, float *vy, 
+                 int dx, int pdx, int dy, int lb, size_t pitch);
+
+// This method updates the particles by moving particle positions
+// according to the velocity field and time step. That is, for each
+// particle: p(t+1) = p(t) + dt * v(p(t)).  
+__global__ void 
+advectParticles_k(cData *part, cData *v, int dx, int dy, 
+                  float dt, int lb, size_t pitch);
+
+#endif
+
Index: trunk/src/testing/app/fluidsGL/Makefile
===================================================================
--- trunk/src/testing/app/fluidsGL/Makefile	(revision 4)
+++ trunk/src/testing/app/fluidsGL/Makefile	(revision 4)
@@ -0,0 +1,51 @@
+################################################################################
+#
+# Copyright 1993-2006 NVIDIA Corporation.  All rights reserved.
+#
+# NOTICE TO USER:   
+#
+# This source code is subject to NVIDIA ownership rights under U.S. and 
+# international Copyright laws.  
+#
+# NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE 
+# CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR 
+# IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH 
+# REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF 
+# MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.   
+# IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, 
+# OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 
+# OR PERFORMANCE OF THIS SOURCE CODE.  
+#
+# U.S. Government End Users.  This source code is a "commercial item" as 
+# that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting  of 
+# "commercial computer software" and "commercial computer software 
+# documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) 
+# and is provided to the U.S. Government only as a commercial end item.  
+# Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through 
+# 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the 
+# source code with only those rights set forth herein.
+#
+################################################################################
+#
+# Build script for project
+#
+################################################################################
+
+verbose = 1
+
+# SAGE flags
+COMMONFLAGS = -DSAGE_APP -I${SAGE_DIRECTORY}/include
+
+# Add source files here
+EXECUTABLE	:= fluidsGL
+# Cuda source files (compiled with cudacc)
+CUFILES		+= fluidsGL.cu
+
+################################################################################
+USEGLLIB 	:= 1
+USECUFFT        := 1
+USEGLUT		:= 1
+
+include common.mk
Index: trunk/src/testing/app/fluidsGL/common.mk
===================================================================
--- trunk/src/testing/app/fluidsGL/common.mk	(revision 4)
+++ trunk/src/testing/app/fluidsGL/common.mk	(revision 4)
@@ -0,0 +1,372 @@
+################################################################################
+#
+# Copyright 1993-2006 NVIDIA Corporation.  All rights reserved.
+#
+# NOTICE TO USER:   
+#
+# This source code is subject to NVIDIA ownership rights under U.S. and 
+# international Copyright laws.  
+#
+# NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE 
+# CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR 
+# IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH 
+# REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF 
+# MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.   
+# IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, 
+# OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 
+# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 
+# OR PERFORMANCE OF THIS SOURCE CODE.  
+#
+# U.S. Government End Users.  This source code is a "commercial item" as 
+# that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting  of 
+# "commercial computer software" and "commercial computer software 
+# documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) 
+# and is provided to the U.S. Government only as a commercial end item.  
+# Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through 
+# 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the 
+# source code with only those rights set forth herein.
+#
+################################################################################
+#
+# Common build script
+#
+################################################################################
+
+.SUFFIXES : .cu .cu_dbg.o .c_dbg.o .cpp_dbg.o .cu_rel.o .c_rel.o .cpp_rel.o .cubin .ptx
+
+# Add new SM Versions here as devices with new Compute Capability are released
+SM_VERSIONS := sm_10 sm_11 sm_12 sm_13
+
+CUDA_INSTALL_PATH ?= /usr/local/cuda
+
+ifdef cuda-install
+	CUDA_INSTALL_PATH := $(cuda-install)
+endif
+
+# detect OS
+OSUPPER = $(shell uname -s 2>/dev/null | tr [:lower:] [:upper:])
+OSLOWER = $(shell uname -s 2>/dev/null | tr [:upper:] [:lower:])
+# 'linux' is output for Linux system, 'darwin' for OS X
+DARWIN = $(strip $(findstring DARWIN, $(OSUPPER)))
+
+# detect if 32 bit or 64 bit system
+HP_64 =	$(shell uname -m | grep 64)
+
+# Basic directory setup for SDK
+# (override directories only if they are not already defined)
+SRCDIR     ?= 
+ROOTDIR    ?= ${HOME}/NVIDIA_GPU_Computing_SDK/C
+ROOTBINDIR ?= ${SAGE_DIRECTORY}/bin
+BINDIR     ?= $(ROOTBINDIR)
+ROOTOBJDIR ?= obj
+LIBDIR     := $(ROOTDIR)/lib
+COMMONDIR  := $(ROOTDIR)/common
+
+# Compilers
+ifeq "$(strip $(HP_64))" ""
+   NVCC    := $(CUDA_INSTALL_PATH)/bin/nvcc 
+else
+   NVCC    := $(CUDA_INSTALL_PATH)/bin/nvcc 
+endif
+
+CXX        := g++
+CC         := gcc
+LINK       := g++ -fPIC
+
+# Includes
+INCLUDES  += -I. -I$(CUDA_INSTALL_PATH)/include -I$(COMMONDIR)/inc
+
+# architecture flag for cubin build
+CUBIN_ARCH_FLAG :=
+
+# Warning flags
+CXXWARN_FLAGS := \
+	-W -Wall \
+	-Wimplicit \
+	-Wswitch \
+	-Wformat \
+	-Wchar-subscripts \
+	-Wparentheses \
+	-Wmultichar \
+	-Wtrigraphs \
+	-Wpointer-arith \
+	-Wcast-align \
+	-Wreturn-type \
+	-Wno-unused-function \
+	$(SPACE)
+
+CWARN_FLAGS := $(CXXWARN_FLAGS) \
+	-Wstrict-prototypes \
+	-Wmissing-prototypes \
+	-Wmissing-declarations \
+	-Wnested-externs \
+	-Wmain \
+
+# Compiler-specific flags
+NVCCFLAGS := 
+CXXFLAGS  := $(CXXWARN_FLAGS)
+CFLAGS    := $(CWARN_FLAGS)
+
+# Common flags
+COMMONFLAGS += $(INCLUDES) -DUNIX
+
+# Debug/release configuration
+ifeq ($(dbg),1)
+	COMMONFLAGS += -g
+	NVCCFLAGS   += -D_DEBUG
+	CXXFLAGS    += -D_DEBUG
+	CFLAGS      += -D_DEBUG
+	BINSUBDIR   := debug
+	LIBSUFFIX   := D
+else 
+	COMMONFLAGS += -O2 
+	BINSUBDIR   := release
+	LIBSUFFIX   :=
+	NVCCFLAGS   += --compiler-options -fno-strict-aliasing
+	CXXFLAGS    += -fno-strict-aliasing
+	CFLAGS      += -fno-strict-aliasing
+endif
+
+# append optional arch/SM version flags (such as -arch sm_11)
+#NVCCFLAGS += $(SMVERSIONFLAGS)
+
+# architecture flag for cubin build
+CUBIN_ARCH_FLAG :=
+
+# OpenGL is used or not (if it is used, then it is necessary to include GLEW)
+ifeq ($(USEGLLIB),1)
+
+	ifneq ($(DARWIN),)
+		OPENGLLIB := -L/System/Library/Frameworks/OpenGL.framework/Libraries -lGL -lGLU $(COMMONDIR)/lib/$(OSLOWER)/libGLEW.a
+	else
+		OPENGLLIB := -lGL -lGLU -lX11 -lXi -lXmu
+
+		ifeq "$(strip $(HP_64))" ""
+			OPENGLLIB += -lGLEW -L/usr/X11R6/lib
+		else
+			OPENGLLIB += -lGLEW_x86_64 -L/usr/X11R6/lib64
+		endif
+	endif
+
+	CUBIN_ARCH_FLAG := -m64
+endif
+
+ifeq ($(USEGLUT),1)
+	ifneq ($(DARWIN),)
+		OPENGLLIB += -framework GLUT
+	else
+		OPENGLLIB += -lglut
+	endif
+endif
+
+ifeq ($(USEPARAMGL),1)
+	PARAMGLLIB := -lparamgl$(LIBSUFFIX)
+endif
+
+ifeq ($(USERENDERCHECKGL),1)
+	RENDERCHECKGLLIB := -lrendercheckgl$(LIBSUFFIX)
+endif
+
+ifeq ($(USECUDPP), 1)
+	ifeq "$(strip $(HP_64))" ""
+		CUDPPLIB := -lcudpp
+	else
+		CUDPPLIB := -lcudpp64
+	endif
+
+	CUDPPLIB := $(CUDPPLIB)$(LIBSUFFIX)
+
+	ifeq ($(emu), 1)
+		CUDPPLIB := $(CUDPPLIB)_emu
+	endif
+endif
+
+# Libs
+ifeq "$(strip $(HP_64))" ""
+   LIB       := -L$(CUDA_INSTALL_PATH)/lib -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) 
+else
+   LIB       := -L$(CUDA_INSTALL_PATH)/lib64 -L$(LIBDIR) -L$(COMMONDIR)/lib/$(OSLOWER) 
+endif
+
+# If dynamically linking to CUDA and CUDART, we exclude the libraries from the LIB
+ifeq ($(USECUDADYNLIB),1)
+     LIB += ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) $(CUDPPLIB) ${LIB} -ldl -rdynamic 
+else
+# static linking, we will statically link against CUDA and CUDART
+  ifeq ($(USEDRVAPI),1)
+     LIB += -lcuda   ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) $(CUDPPLIB) ${LIB} 
+  else
+     LIB += -lcudart ${OPENGLLIB} $(PARAMGLLIB) $(RENDERCHECKGLLIB) $(CUDPPLIB) ${LIB}
+  endif
+endif
+
+ifeq ($(USECUFFT),1)
+  ifeq ($(emu),1)
+    LIB += -lcufftemu
+  else
+    LIB += -lcufft
+  endif
+endif
+
+ifeq ($(USECUBLAS),1)
+  ifeq ($(emu),1)
+    LIB += -lcublasemu
+  else
+    LIB += -lcublas
+  endif
+endif
+
+# Lib/exe configuration
+ifneq ($(STATIC_LIB),)
+	TARGETDIR := $(LIBDIR)
+	TARGET   := $(subst .a,$(LIBSUFFIX).a,$(LIBDIR)/$(STATIC_LIB))
+	LINKLINE  = ar rucv $(TARGET) $(OBJS) 
+else
+	ifneq ($(OMIT_CUTIL_LIB),1)
+		LIB += -lcutil$(LIBSUFFIX)
+	endif
+	# Device emulation configuration
+	ifeq ($(emu), 1)
+		NVCCFLAGS   += -deviceemu
+		CUDACCFLAGS += 
+		BINSUBDIR   := emu$(BINSUBDIR)
+		# consistency, makes developing easier
+		CXXFLAGS		+= -D__DEVICE_EMULATION__
+		CFLAGS			+= -D__DEVICE_EMULATION__
+	endif
+	TARGETDIR := $(BINDIR)
+	TARGET    := $(TARGETDIR)/$(EXECUTABLE)
+	LINKLINE  = $(LINK) -o $(TARGET) $(OBJS) $(LIB) -L${SAGE_DIRECTORY}/lib -lsail
+endif
+
+# check if verbose 
+ifeq ($(verbose), 1)
+	VERBOSE :=
+else
+	VERBOSE := @
+endif
+
+################################################################################
+# Check for input flags and set compiler flags appropriately
+################################################################################
+ifeq ($(fastmath), 1)
+	NVCCFLAGS += -use_fast_math
+endif
+
+ifeq ($(keep), 1)
+	NVCCFLAGS += -keep
+	NVCC_KEEP_CLEAN := *.i* *.cubin *.cu.c *.cudafe* *.fatbin.c *.ptx
+endif
+
+ifdef maxregisters
+	NVCCFLAGS += -maxrregcount $(maxregisters)
+endif
+
+# Add cudacc flags
+NVCCFLAGS += $(CUDACCFLAGS)
+
+# Add common flags
+NVCCFLAGS += $(COMMONFLAGS)
+CXXFLAGS  += $(COMMONFLAGS)
+CFLAGS    += $(COMMONFLAGS)
+
+ifeq ($(nvcc_warn_verbose),1)
+	NVCCFLAGS += $(addprefix --compiler-options ,$(CXXWARN_FLAGS)) 
+	NVCCFLAGS += --compiler-options -fno-strict-aliasing
+endif
+
+################################################################################
+# Set up object files
+################################################################################
+OBJDIR := $(ROOTOBJDIR)/$(BINSUBDIR)
+OBJS +=  $(patsubst %.cpp,$(OBJDIR)/%.cpp.o,$(notdir $(CCFILES)))
+OBJS +=  $(patsubst %.c,$(OBJDIR)/%.c.o,$(notdir $(CFILES)))
+OBJS +=  $(patsubst %.cu,$(OBJDIR)/%.cu.o,$(notdir $(CUFILES)))
+
+################################################################################
+# Set up cubin output files
+################################################################################
+CUBINDIR := $(SRCDIR)data
+CUBINS +=  $(patsubst %.cu,$(CUBINDIR)/%.cubin,$(notdir $(CUBINFILES)))
+
+################################################################################
+# Set up PTX output files
+################################################################################
+PTXDIR := $(SRCDIR)data
+PTXBINS +=  $(patsubst %.cu,$(PTXDIR)/%.ptx,$(notdir $(PTXFILES)))
+
+################################################################################
+# Rules
+################################################################################
+$(OBJDIR)/%.c.o : $(SRCDIR)%.c $(C_DEPS)
+	$(VERBOSE)$(CC) $(CFLAGS) -o $@ -c $<
+
+$(OBJDIR)/%.cpp.o : $(SRCDIR)%.cpp $(C_DEPS)
+	$(VERBOSE)$(CXX) $(CXXFLAGS) -o $@ -c $<
+
+$(OBJDIR)/%.cu.o : $(SRCDIR)%.cu $(CU_DEPS)
+	$(VERBOSE)$(NVCC) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $@ -c $<
+
+$(CUBINDIR)/%.cubin : $(SRCDIR)%.cu cubindirectory
+	$(VERBOSE)$(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $@ -cubin $<
+
+$(PTXDIR)/%.ptx : $(SRCDIR)%.cu ptxdirectory
+	$(VERBOSE)$(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(SMVERSIONFLAGS) -o $@ -ptx $<
+
+#
+# The following definition is a template that gets instantiated for each SM
+# version (sm_10, sm_13, etc.) stored in SMVERSIONS.  It does 2 things:
+# 1. It adds to OBJS a .cu_sm_XX.o for each .cu file it finds in CUFILES_sm_XX.
+# 2. It generates a rule for building .cu_sm_XX.o files from the corresponding 
+#    .cu file.
+#
+# The intended use for this is to allow Makefiles that use common.mk to compile
+# files to different Compute Capability targets (aka SM arch version).  To do
+# so, in the Makefile, list files for each SM arch separately, like so:
+#
+# CUFILES_sm_10 := mycudakernel_sm10.cu app.cu
+# CUFILES_sm_12 := anothercudakernel_sm12.cu
+#
+define SMVERSION_template
+OBJS += $(patsubst %.cu,$(OBJDIR)/%.cu_$(1).o,$(notdir $(CUFILES_$(1))))
+$(OBJDIR)/%.cu_$(1).o : $(SRCDIR)%.cu $(CU_DEPS)
+	$(VERBOSE)$(NVCC) -o $$@ -c $$< $(NVCCFLAGS) -arch $(1)
+endef
+
+# This line invokes the above template for each arch version stored in
+# SM_VERSIONS.  The call funtion invokes the template, and the eval
+# function interprets it as make commands.
+$(foreach smver,$(SM_VERSIONS),$(eval $(call SMVERSION_template,$(smver))))
+
+$(TARGET): makedirectories $(OBJS) $(CUBINS) $(PTXBINS) Makefile
+	$(VERBOSE)$(LINKLINE)
+
+install:$(TARGET)
+
+cubindirectory:
+	$(VERBOSE)mkdir -p $(CUBINDIR)
+
+ptxdirectory:
+	$(VERBOSE)mkdir -p $(PTXDIR)
+
+makedirectories:
+	$(VERBOSE)mkdir -p $(LIBDIR)
+	$(VERBOSE)mkdir -p $(OBJDIR)
+	$(VERBOSE)mkdir -p $(TARGETDIR)
+
+
+tidy :
+	$(VERBOSE)find . | egrep "#" | xargs rm -f
+	$(VERBOSE)find . | egrep "\~" | xargs rm -f
+
+clean : tidy
+	$(VERBOSE)rm -f $(OBJS)
+	$(VERBOSE)rm -f $(CUBINS)
+	$(VERBOSE)rm -f $(PTXBINS)
+	$(VERBOSE)rm -f $(TARGET)
+	$(VERBOSE)rm -f $(NVCC_KEEP_CLEAN)
+
+clobber : clean
+	$(VERBOSE)rm -rf $(ROOTOBJDIR)
+
Index: trunk/src/testing/app/ishare/Info.plist
===================================================================
--- trunk/src/testing/app/ishare/Info.plist	(revision 4)
+++ trunk/src/testing/app/ishare/Info.plist	(revision 4)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>iShare</string>
+	<key>CFBundleExecutable</key>
+	<string>iShareUI</string>
+	<key>CFBundleIconFile</key>
+	<string>iShareUIMacIcons.icns</string>
+	<key>CFBundleIdentifier</key>
+	<string>edu.uic.evl.ishare</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>iShare</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+</dict>
+</plist>
Index: trunk/src/testing/app/ishare/ishare.cpp
===================================================================
--- trunk/src/testing/app/ishare/ishare.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/ishare.cpp	(revision 4)
@@ -0,0 +1,174 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "sail.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#include <Carbon/Carbon.h>
+
+#include <sys/time.h>
+
+#include "libdxt.h"
+
+// #define WW 1920
+// #define HH 1200
+
+#define WW 1440
+#define HH 900
+
+//#define WW 1024
+//#define HH 768
+
+
+// headers for SAGE
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+GLubyte *dxtBuffer = 0;
+sail sageInf; // sail object
+
+int capture(char* m_pFrameRGB,int x,int y,int cx,int cy)
+{
+  CGLContextObj	 glContextObj = 0;
+  CGLPixelFormatObj pixelFormatObj ;
+  GLint numPixelFormats ;
+  CGDirectDisplayID	displayId=CGMainDisplayID();
+  CGOpenGLDisplayMask displayMask =
+    CGDisplayIDToOpenGLDisplayMask(displayId);
+
+  CGLPixelFormatAttribute attribs[] =
+    {
+      (CGLPixelFormatAttribute)kCGLPFAFullScreen,
+      (CGLPixelFormatAttribute)kCGLPFADisplayMask,
+      (CGLPixelFormatAttribute)displayMask,
+      (CGLPixelFormatAttribute)0
+    };
+  CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
+  CGLCreateContext( pixelFormatObj, NULL, &glContextObj ) ;
+  CGLDestroyPixelFormat( pixelFormatObj ) ;
+  CGLSetCurrentContext( glContextObj ) ;
+  CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
+
+  glReadBuffer(GL_FRONT);
+  glReadPixels(x,y,cx,cy,GL_RGBA,GL_UNSIGNED_BYTE,m_pFrameRGB);
+
+  CGLSetCurrentContext( NULL );
+  CGLClearDrawable( glContextObj );
+  CGLDestroyContext( glContextObj );
+  return true;
+}
+
+int
+main(int argc, char **argv)
+{
+  int ret;
+  bool done;
+  double rate, fps;
+  double t1, t2;
+
+        // Initialize some timing functions and else (DXT)
+  aInitialize();
+
+
+  sageRect ishareImageMap;
+  ishareImageMap.left = 0.0;
+  ishareImageMap.right = 1.0;
+  ishareImageMap.bottom = 0.0;
+  ishareImageMap.top = 1.0;
+
+  sailConfig scfg;
+  scfg.init("ishare.conf");
+  scfg.setAppName("ishare");
+  scfg.rank = 0;
+
+  scfg.resX = WW;
+  scfg.resY = HH;
+  scfg.winWidth  = WW;
+  scfg.winHeight = HH;
+  scfg.imageMap = ishareImageMap;
+  scfg.pixFmt = PIXFMT_DXT; // PIXFMT_888;
+  scfg.rowOrd = BOTTOM_TO_TOP;
+  scfg.master = true;
+
+  sageInf.init(scfg);
+
+  std::cout << "sail initialized " << std::endl;
+
+  dxtBuffer = (GLubyte *)sageInf.getBuffer();
+  rgbBuffer = (byte*)memalign(16, WW*HH*4);
+  memset(rgbBuffer, 0,  WW*HH*4);
+
+  rate = 15.0;
+
+  done = false;
+  while (not done)
+    {
+      t1 = sage::getTime();
+
+      ret = capture((char*)rgbBuffer,0,0,WW,HH);
+
+      CompressDXT(rgbBuffer, dxtBuffer, WW, HH, FORMAT_DXT1, 2);
+
+      sageInf.swapBuffer();
+
+      sageMessage msg;
+      if (sageInf.checkMsg(msg, false) > 0) {
+	switch (msg.getCode()) {
+	case APP_QUIT:
+	  done = true;
+	  break;
+	}
+      }
+
+      dxtBuffer = (GLubyte *)sageInf.getBuffer();
+
+      t2 = sage::getTime();
+      fps = (1000000.0/(t2-t1));
+      if (fps > rate) {
+	sage::usleep( (1000000.0/rate) - (t2-t1)  );
+      }
+    }
+
+}
Index: trunk/src/testing/app/ishare/FastDXT/dxt.h
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/dxt.h	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/dxt.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <math.h>
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned int dword;
+
+#define C565_5_MASK 0xF8 // 0xFF minus last three bits
+#define C565_6_MASK 0xFC // 0xFF minus last two bits
+
+#define INSET_SHIFT 4 // inset the bounding box with ( range >> shift )
+
+#if !defined(MAX_INT)
+#define       MAX_INT         2147483647      /* max value for an int 32 */
+#define       MIN_INT         (-2147483647-1) /* min value for an int 32 */
+#endif
+
+
+#if defined(__GNUC__)
+#define   ALIGN16(_x)   _x __attribute((aligned(16)))
+#else
+#define   ALIGN16( x ) __declspec(align(16)) x
+#endif
+
+
+// Compress to DXT1 format
+void CompressImageDXT1( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compress to DXT5 format, first convert to YCoCg color space
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height, int &outputBytes );
+
+// Compute error between two images
+double ComputeError( const byte *original, const byte *dxt, int width, int height);
Index: trunk/src/testing/app/ishare/FastDXT/glsl.h
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/glsl.h	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/glsl.h	(revision 4)
@@ -0,0 +1,62 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#define GLSL_YCOCG 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#if defined(WIN32)
+#include <io.h>
+#else
+#include <unistd.h>
+#define GLEW_STATIC 1
+#endif
+
+#if defined(GLSL_YCOCG)
+
+#include <GL/glew.h>
+
+
+extern GLhandleARB PHandle;
+
+int GLSLreadShader(char *fileName, int shaderType, char *shaderText, int size);
+int GLSLreadShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader);
+GLuint GLSLinstallShaders(const GLchar *Vertex, const GLchar *Fragment);
+
+#endif
+
Index: trunk/src/testing/app/ishare/FastDXT/util.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/util.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/util.cpp	(revision 4)
@@ -0,0 +1,356 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "util.h"
+
+
+#if defined(WIN32)
+#include <io.h>
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if !defined(WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+
+
+void aInitialize()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if( perf_conversion == 0.0 )
+	{
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+		// Start of time
+	perf_start = mach_absolute_time();
+
+		// Initialize the random generator
+	srand(getpid());
+#else
+		// Start of time
+	gettimeofday(&tv_start,0);
+		// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double aTime()
+// return time since start of process in seconds
+{
+#if defined(WIN32)
+    LARGE_INTEGER perf_counter;
+#else
+    struct timeval tv;
+#endif
+
+#if defined(WIN32)
+        // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	return (double)(perf_counter.QuadPart - perf_start.QuadPart) / (double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+    uint64_t difference = mach_absolute_time() - perf_start;
+    return perf_conversion * (double) difference;
+#else
+        // UNIX: gettimeofday
+	gettimeofday(&tv,0);
+	return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+#endif
+}
+
+
+
+void aLog(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+}
+
+void aError(char* format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	DWORD res;
+	WriteFile(win_err, line, (DWORD)strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s",line);
+	fflush(stderr);
+
+    exit(1);
+}
+
+
+
+void* aAlloc(size_t const n)
+{
+	void* result;
+#if defined(WIN32)
+	result = LocalAlloc(0,n);
+#else
+	result = malloc(n);
+#endif
+	// Filling with zeros
+	memset(result, 0, n);
+
+	if(!result)
+		aError("Aura: not enough memory for %d bytes",n);
+	return result;
+}
+
+void aFree(void* const p)
+{
+#if defined(WIN32)
+	LocalFree(p);
+#else
+	if (p)
+        free(p);
+    else
+        aError("Alloc> Trying to free a NULL pointer\n");
+#endif
+}
+
+#if defined(WIN32)
+float
+drand48(void)
+{
+	return (((float) rand()) / RAND_MAX);
+}
+#endif
+
+
+void *aligned_malloc(size_t size, size_t align_size) {
+
+  char *ptr,*ptr2,*aligned_ptr;
+  int align_mask = (int)align_size - 1;
+
+  ptr=(char *)malloc(size + align_size + sizeof(int));
+  if(ptr==NULL) return(NULL);
+
+  ptr2 = ptr + sizeof(int);
+  aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
+
+
+  ptr2 = aligned_ptr - sizeof(int);
+  *((int *)ptr2)=(int)(aligned_ptr - ptr);
+
+  return(aligned_ptr);
+}
+
+void aligned_free(void *ptr)
+{
+	int *ptr2=(int *)ptr - 1;
+	ptr = (char*)ptr - *ptr2;
+	free(ptr);
+}
+
+
+/// File findind
+// From Nvidia toolkit
+
+using namespace std;
+
+string data_path::get_path(std::string filename)
+{
+  FILE* fp;
+  bool found = false;
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+	  break;
+        }
+    }
+
+  if (found == false)
+    {
+      path_name = filename;
+      fp = ::fopen(path_name.c_str(),"r");
+      if (fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+        }
+    }
+
+  if (found == false)
+    return "";
+
+  int loc = path_name.rfind('\\');
+  if (loc == -1)
+    {
+      loc = path_name.rfind('/');
+    }
+
+  if (loc != -1)
+    file_path = path_name.substr(0, loc);
+  else
+    file_path = ".";
+  return file_path;
+}
+
+string data_path::get_file(std::string filename)
+{
+  FILE* fp;
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  return path_name;
+        }
+    }
+
+  path_name = filename;
+  fp = ::fopen(path_name.c_str(),"r");
+  if (fp != 0)
+    {
+      fclose(fp);
+      return path_name;
+    }
+  return "";
+}
+
+// data files, for read only
+FILE * data_path::fopen(std::string filename, const char * mode)
+{
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+      FILE * fp = ::fopen(s.c_str(), mode);
+
+      if(fp != 0)
+	return fp;
+      else if (!strcmp(path[i].c_str(),""))
+	{
+	  FILE* fp = ::fopen(filename.c_str(),mode);
+	  if (fp != 0)
+	    return fp;
+	}
+    }
+  // no luck... return null
+  return 0;
+}
+
+//  fill the file stats structure
+//  useful to get the file size and stuff
+int data_path::fstat(std::string filename,
+#ifdef WIN32
+		     struct _stat
+#else
+		     struct stat
+#endif
+		     * stat)
+{
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+#ifdef WIN32
+      int fh = ::_open(s.c_str(), _O_RDONLY);
+#else
+      int fh = ::open(s.c_str(), O_RDONLY);
+#endif
+      if(fh >= 0)
+        {
+#ifdef WIN32
+	  int result = ::_fstat( fh, stat );
+#else
+	  int result = ::fstat (fh,stat);
+#endif
+	  if( result != 0 )
+            {
+	      fprintf( stderr, "An fstat error occurred.\n" );
+	      return 0;
+            }
+#ifdef WIN32
+	  ::_close( fh );
+#else
+	  ::close (fh);
+#endif
+	  return 1;
+    	}
+    }
+  // no luck...
+  return 0;
+}
Index: trunk/src/testing/app/ishare/FastDXT/2dxt.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/2dxt.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/2dxt.cpp	(revision 4)
@@ -0,0 +1,121 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+//
+// Usage: ./2dxt width height type rawfile dxtfile
+//
+
+#define NUMTHREAD 2
+
+#include "libdxt.h"
+
+int
+main(int argc, char** argv)
+{
+  byte *in;
+  byte *out;
+  int nbbytes;
+
+  if (argc != 6)
+  {
+	fprintf(stderr, "Usage: ./2dxt width height type rawfile dxtfile\n");
+	exit(0);
+  }
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  int format = 1;
+  format = atoi(argv[3]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[4], "rb");
+  int res=(int)fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting to raw: %ldx%ld\n", width, height);
+
+  double t1, t2;
+  t1 = aTime();
+  nbbytes = 0;
+  switch (format) {
+  case 1:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT1, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT1: from %d bytes to %ld bytes\n",
+	    width*height*4, nbbytes);
+    break;
+  case 5:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT5, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT5: from %d bytes to %ld bytes\n",
+	  width*height*4, nbbytes);
+    break;
+  case 6:
+    nbbytes = CompressDXT(in, out, width, height, FORMAT_DXT5YCOCG, NUMTHREAD);
+    fprintf(stderr, "Converted to DXT5-YCoCg: from %d bytes to %ld bytes\n",
+	    width*height*4, nbbytes);
+    break;
+  }
+  t2 = aTime();
+
+  fprintf(stderr, "Time %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, 1.0/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+          ((double)(width*height)) / ((t2-t1)*1000000.0) );
+
+  FILE *g=fopen(argv[5], "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  int res2=(int)fwrite(out, 1, nbbytes, g);
+  fclose(g);
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
+
Index: trunk/src/testing/app/ishare/FastDXT/util.h
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/util.h	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/util.h	(revision 4)
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#pragma warning(disable:4786)   // symbol size limitation ... STL
+#endif
+
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+//#include <values.h>
+
+
+void   aInitialize();
+
+double aTime();
+
+void   aLog(char* format,...);
+void aError(char* format,...);
+
+void* aAlloc(size_t const n);
+void aFree(void* const p);
+
+#if defined(WIN32)
+float drand48(void);
+#endif
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+
+#if defined(WIN32)
+void *aligned_malloc(size_t size, size_t align_size);
+#define memalign(x,y) aligned_malloc(y, x)
+void aligned_free(void *ptr);
+#define memfree(x) aligned_free(x)
+#else
+#define memfree(x) free(x)
+#endif
+
+
+// From NVIDIA Toolkit
+
+#ifndef DATA_PATH_H
+#define DATA_PATH_H
+
+class data_path
+{
+public:
+  std::string              file_path;
+  std::string              path_name;
+  std::vector<std::string> path;
+
+  std::string get_path(std::string filename);
+  std::string get_file(std::string filename);
+
+  FILE *fopen(std::string filename, const char * mode = "rb");
+
+#ifdef WIN32
+  int fstat(std::string filename, struct _stat * stat);
+#else
+  int fstat(std::string filename, struct stat * stat);
+#endif
+};
+
+#endif
Index: trunk/src/testing/app/ishare/FastDXT/main.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/main.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/main.cpp	(revision 4)
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+int
+main(int argc, char** argv)
+{
+  ALIGN16( byte *in );
+  ALIGN16( byte *out);
+  double t1, t2;
+  int nbbytes;
+
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[3], "rb");
+  fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting to raw: %ldx%ld\n", width, height);
+
+  t1 = aTime();
+  for (int k=0;k<100;k++)
+    {
+		CompressImageDXT1( in, out, width, height, nbbytes);
+    }
+  t2 = aTime();
+
+  fprintf(stderr, "Converted to DXT: %d byte, compression %ld\n",
+	  nbbytes, (width*height*4) / (nbbytes));
+  fprintf(stderr, "Time %.2f sec, Single %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, (t2-t1)/100.0, 100.0/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+	  ((double)(width*height)) / ((t2-t1)*10000.0) );
+
+#if 1
+  FILE *g=fopen("out.dxt", "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  //nbbytes = width * height * 4 / 4; //DXT5
+  nbbytes = width * height * 3 / 6; // DXT1
+  fwrite(out, 1, nbbytes, g);
+  fclose(g);
+#endif
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
Index: trunk/src/testing/app/ishare/FastDXT/playdxt.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/playdxt.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/playdxt.cpp	(revision 4)
@@ -0,0 +1,274 @@
+/******************************************************************************
+ * a DXT viewing utility
+ *
+ * Author : Robert Kooima
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if !defined(WIN32)
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#define MAXSTR 256
+
+#include "dxt.h"
+#include "glsl.h"
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#endif
+
+#ifdef __linux__
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+#define glGetProcAddress(n) glXGetProcAddressARB((GLubyte *) n)
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include "glext.h"
+#define glGetProcAddress(n) wglGetProcAddress(n)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef GLSL_YCOCG
+#ifndef __APPLE__
+static PFNGLGETCOMPRESSEDTEXIMAGEARBPROC  glGetCompressedTexImage;
+static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC   glCompressedTexImage2D;
+#endif
+#endif
+
+static void init_gl(void)
+{
+#ifndef __APPLE__
+    glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)
+               glGetProcAddress("glGetCompressedTexImageARB");
+    glCompressedTexImage2D  = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)
+               glGetProcAddress("glCompressedTexImage2DARB");
+#endif
+
+    glEnable(GL_TEXTURE_2D);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+static void in_dxt(int w, int h, int format, const char *name)
+{
+    FILE *fin = NULL;
+    static int first = 1;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	if (format == 5 || format == 6)
+	  sz = 4 * w * h / 4;
+	else
+	  sz = 8 * (w / 4) * (h / 4);
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    int ww, hh;
+	    fread( &ww, sizeof( int ), 1, fin );
+	    fread( &hh, sizeof( int ), 1, fin );
+
+            fread(p, 1, sz, fin);
+
+		    if (format == 5 || format == 6)
+		      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+					     GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+					     w, h, 0, sz, p);
+		    else
+		      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+					     GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+					     w, h, 0, sz, p);
+            free(p);
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void display(int w, int h)
+{
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustum(0, w, 0, h, 0, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glClearColor(0,1,0,1);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glBegin(GL_POLYGON);
+    {
+        glTexCoord2i(0, 1); glVertex2i(-1, -1);
+        glTexCoord2i(1, 1); glVertex2i(+1, -1);
+        glTexCoord2i(1, 0); glVertex2i(+1, +1);
+        glTexCoord2i(0, 0); glVertex2i(-1, +1);
+    }
+    glEnd();
+
+    glFinish();
+
+    SDL_GL_SwapBuffers();
+}
+
+/*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+    int w = 1024;
+    int h = 512;
+    int format = 1; // DXT1 or DXT5 or DXT5YCoCg (6)
+    int out = 0;
+    int argi;
+
+    /* Process arguments. */
+
+    for (argi = 1; argi < argc; ++argi)
+        if (strcmp(argv[argi], "-5") == 0) format = 5;
+        else if (strcmp(argv[argi], "-6") == 0) format = 6;
+        else if (strcmp(argv[argi], "-1") == 0) format = 1;
+        else if (strcmp(argv[argi], "-w") == 0) w = atoi(argv[++argi]);
+        else if (strcmp(argv[argi], "-h") == 0) h = atoi(argv[++argi]);
+        else     break;
+
+    /* Use SDL to get an OpenGL context for use as compressor/decompressor. */
+
+    if (SDL_Init(SDL_INIT_VIDEO) == 0)
+    {
+        //SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     8);
+        //SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   8);
+        //SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    8);
+        //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
+        //SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+        if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL))
+        {
+            SDL_Event e;
+
+            init_gl();
+
+            /* Convert and display named files. */
+
+#if defined(GLSL_YCOCG)
+	    // Initialize the "OpenGL Extension Wrangler" library
+	    glewInit();
+
+	    if (!glewIsSupported("GL_VERSION_2_0 "
+				 "GL_ARB_vertex_program "
+				 "GL_ARB_fragment_program "
+				 "GL_ARB_texture_compression "
+				 "GL_EXT_texture_compression_s3tc "
+				 )
+		) {
+	      fprintf(stderr, "GLSL_YCOCG> Unable to load required OpenGL extension\n");
+	      exit(-1);
+	    }
+
+	    // Load the shaders
+	    GLchar *FragmentShaderSource;
+	    GLchar *VertexShaderSource;
+	    GLSLreadShaderSource("ycocg", &VertexShaderSource, &FragmentShaderSource);
+	    PHandle = GLSLinstallShaders(VertexShaderSource, FragmentShaderSource);
+
+	    /* Finally, use the program. */
+	    glUseProgramObjectARB(PHandle);
+
+	    glUseProgramObjectARB(0);
+#endif
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	    {
+			glUseProgramObjectARB(PHandle);
+			glActiveTexture(GL_TEXTURE0);
+			int h=glGetUniformLocationARB(PHandle,"yuvtex");
+			glUniform1iARB(h,0);  /* Bind yuvtex to texture unit 0 */
+	    }
+#endif
+
+
+		for (; argi < argc; ++argi)
+		{
+			in_dxt(w, h, format, argv[argi]);
+			display(w, h);
+
+			while (SDL_PollEvent(&e))
+			    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+				break;
+		}
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      glUseProgramObjectARB(0);
+#endif
+
+		while (SDL_WaitEvent(&e))
+		    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+			break;
+
+        }
+        else fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+
+        SDL_Quit();
+    }
+    else fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/ishare/FastDXT/libdxt.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/libdxt.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/libdxt.cpp	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+#if defined(__APPLE__)
+#define memalign(x,y) malloc((y))
+#else
+#include <malloc.h>
+#endif
+
+#include <pthread.h>
+
+typedef struct _work_t {
+	int width, height;
+	int nbb;
+	byte *in, *out;
+} work_t;
+
+
+
+void *slave1(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT1( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+void *slave5ycocg(void *arg)
+{
+	work_t *param = (work_t*) arg;
+	int nbbytes = 0;
+	CompressImageDXT5YCoCg( param->in, param->out, param->width, param->height, nbbytes);
+	param->nbb = nbbytes;
+	return NULL;
+}
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads)
+{
+  pthread_t *pid;
+  work_t    *job;
+  int        nbbytes;
+
+  if ( (numthreads!=1) && (numthreads!=2) && (numthreads!=4) ) {
+	fprintf(stderr, "DXT> Errror, number of thread should be 1, 2 or 4\n");
+	return 0;
+  }
+
+  job = new work_t[numthreads];
+  pid = new pthread_t[numthreads];
+
+  for (int k=0;k<numthreads;k++)
+    {
+      job[k].width = width;
+      job[k].height = height/numthreads;
+      job[k].nbb = 0;
+      job[k].in =  (byte*)in  + (k*width*4*height/numthreads);
+      if (format == FORMAT_DXT1)
+	job[k].out = out + (k*width*4*height/(numthreads*8));
+      else
+	job[k].out = out + (k*width*4*height/(numthreads*4));
+
+      switch (format) {
+      case FORMAT_DXT1:
+	pthread_create(&pid[k], NULL, slave1, &job[k]);
+	break;
+      case FORMAT_DXT5:
+	pthread_create(&pid[k], NULL, slave5, &job[k]);
+	break;
+      case FORMAT_DXT5YCOCG:
+	pthread_create(&pid[k], NULL, slave5ycocg, &job[k]);
+	break;
+      }
+    }
+
+  // Join all the threads
+  nbbytes = 0;
+  for (int k=0;k<numthreads;k++)
+  {
+    pthread_join(pid[k], NULL);
+    nbbytes += job[k].nbb;
+  }
+  return nbbytes;
+}
Index: trunk/src/testing/app/ishare/FastDXT/bin/dnd.py
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/bin/dnd.py	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/bin/dnd.py	(revision 4)
@@ -0,0 +1,222 @@
+
+import  wx
+import  os, stat
+
+#----------------------------------------------------------------------
+
+PATH2DXT = "/Users/luc/Dev/FastDXT/bin/2dxt"
+
+WIDTH  = 1920
+HEIGHT = 1080
+FORMAT = 1
+#----------------------------------------------------------------------
+
+def mylistdir(directory):
+    """A specialized version of os.listdir() that ignores files that
+    start with a leading period."""
+    filelist = os.listdir(directory)
+    return [x for x in filelist
+            if not (x.startswith('.'))]
+
+def Convert(fn):
+   dn, bs = os.path.split(fn)
+   file, ext = os.path.splitext(bs)
+
+   if ext != ".rgb" and ext != ".rgba":
+      frgb = "%s/%s.%s" % ( dn, file, "rgba" )
+      command = "convert %s -depth 8 RGBA:%s" % (fn, frgb)
+      print command
+      os.system( command )
+
+      fout = "%s/%s.%s" % ( dn, file, "dxt" )
+      command = "%s %d %d %d %s %s && /bin/rm -f %s" % (PATH2DXT, WIDTH, HEIGHT, FORMAT, frgb, fout, frgb)
+   else:
+      fout = "%s/%s.%s" % ( dn, file, "dxt" )
+      command = "%s %d %d %d %s %s" % (PATH2DXT, WIDTH, HEIGHT, FORMAT, fn, fout)
+
+   print command
+   os.system( command )
+
+class MyFileDropTarget(wx.FileDropTarget):
+    def __init__(self, window):
+        wx.FileDropTarget.__init__(self)
+        self.window = window
+
+    def OnDropFiles(self, x, y, filenames):
+        self.window.SetInsertionPointEnd()
+        self.window.Clear()
+
+        fn = list()
+
+        if len(filenames) == 1:
+           mode = os.stat(filenames[0])[stat.ST_MODE]
+           if stat.S_ISDIR(mode):
+              # It's a directory, recurse into it
+              for f in mylistdir(filenames[0]):
+                 full = os.path.join(filenames[0], f)
+                 if stat.S_ISREG( os.stat(full)[stat.ST_MODE] ):
+                    fn.append(full)
+           elif stat.S_ISREG(mode):
+              # It's a file, call the callback function
+              fn.append(filenames[0])
+           else:
+              # Unknown file type, print a message
+              print 'Skipping %s' % pathname
+        else:
+           for f in filenames:
+              fn.append(f)
+
+        fn.sort()
+        max = len(fn)
+
+        self.window.WriteText("\n%d file(s) dropped:\n" % len(fn))
+
+        dlg = wx.ProgressDialog("DXT Conversion", "Converting RAW files to DXT",
+                                maximum = max,
+                                parent=self.window,
+                                style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL| wx.PD_ELAPSED_TIME| wx.PD_REMAINING_TIME)
+            
+        keepGoing = True
+        count = 0
+            
+        while keepGoing and count < max:
+           self.window.WriteText(fn[count] + '\n')
+           (keepGoing, skip) = dlg.Update(count, fn[count])
+           Convert(fn[count])
+           count += 1
+
+        dlg.Destroy()
+       
+
+class FileDropPanel(wx.Panel):
+    def __init__(self, parent):
+        wx.Panel.__init__(self, parent, -1)
+
+        sizer = wx.BoxSizer(wx.VERTICAL)
+
+        # Format selection
+        rb = wx.RadioBox(self, -1, "Select DXT format:", wx.DefaultPosition, wx.DefaultSize,
+                         ['DXT1', 'DXT5', 'DXT6 (5-YCoCg)'], 1, wx.RA_SPECIFY_ROWS)
+        self.Bind(wx.EVT_RADIOBOX, self.OnFormat, rb)
+        sizer.Add(rb, 0, wx.ALL, 5)
+
+        # Width and height setting
+        ssizer = wx.BoxSizer(wx.HORIZONTAL)
+
+        ssizer.Add(wx.StaticText(self, -1, "Width", style=wx.ALIGN_BOTTOM), 0, wx.ALL, 5)
+        sw = wx.SpinCtrl(self, -1, "",  wx.DefaultPosition, (100,-1))
+        sw.SetRange(1,65535)
+        sw.SetValue(WIDTH)
+        self.Bind(wx.EVT_SPINCTRL, self.OnWidth, sw)
+        ssizer.Add(sw, 0, wx.ALL, 0)
+
+        ssizer.Add(wx.StaticText(self, -1, "Height", style=wx.ALIGN_BOTTOM), 0, wx.ALL, 5)
+        sh = wx.SpinCtrl(self, -1, "",  wx.DefaultPosition, (100,-1))
+        sh.SetRange(1,65535)
+        sh.SetValue(HEIGHT)
+        self.Bind(wx.EVT_SPINCTRL, self.OnHeight, sh)
+        ssizer.Add(sh, 0, wx.ALL, 0)
+
+        sizer.Add(ssizer, 0, wx.ALL, 5)
+
+        # Drop box
+        sizer.Add(
+            wx.StaticText(self, -1, " \nDrag some files here:"),
+            0, wx.EXPAND|wx.ALL, 5)
+
+        self.text = wx.TextCtrl(
+                        self, -1, "\n\tImage files ...",
+                        style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY)
+
+        dt = MyFileDropTarget(self)
+        self.text.SetDropTarget(dt)
+        sizer.Add(self.text, 1, wx.EXPAND)
+        
+        self.SetAutoLayout(True)
+        self.SetSizer(sizer)
+
+    def OnWidth(self, arg):
+       global WIDTH
+       WIDTH = arg.GetInt()
+    def OnHeight(self, arg):
+       global HEIGHT
+       HEIGHT = arg.GetInt()
+    def OnFormat(self, arg):
+       global FORMAT
+       f = arg.GetInt()
+       if f == 0:
+          FORMAT = 1
+       if f == 1:
+          FORMAT = 5
+       if f == 2:
+          FORMAT = 6
+
+    def WriteText(self, text):
+        self.text.WriteText(text)
+
+    def Clear(self):
+        self.text.Clear()
+
+    def SetInsertionPointEnd(self):
+        self.text.SetInsertionPointEnd()
+
+
+#----------------------------------------------------------------------
+
+class TestPanel(wx.Panel):
+    def __init__(self, parent):
+        wx.Panel.__init__(self, parent, -1)
+
+        self.SetAutoLayout(True)
+        outsideSizer = wx.BoxSizer(wx.VERTICAL)
+
+        msg = "DXT Conversion Drag-And-Drop"
+        text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE)
+        text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False))
+        text.SetLabel(msg)
+
+        w,h = text.GetTextExtent(msg)
+        text.SetSize(wx.Size(w,h+1))
+        text.SetForegroundColour(wx.BLUE)
+        outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5)
+        outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND)
+
+        inSizer = wx.BoxSizer(wx.HORIZONTAL)
+        inSizer.Add(FileDropPanel(self), 1, wx.EXPAND)
+
+        outsideSizer.Add(inSizer, 1, wx.EXPAND)
+        self.SetSizer(outsideSizer)
+
+
+#----------------------------------------------------------------------
+class MainWindow(wx.Frame):
+   """ This window displays the GUI Widgets. """
+   def __init__(self,parent,id,title):
+       wx.Frame.__init__(self,parent,-4, title, size = (500,300), style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
+       self.SetBackgroundColour(wx.WHITE)
+
+       w = TestPanel(self)
+       
+       # Display the Window
+       self.Show(True)
+
+
+class MyApp(wx.App):
+   """ DXT Conversion """
+   def OnInit(self):
+      """ Initialize the Application """
+      # Declare the Main Application Window
+      frame = MainWindow(None, -1, "DXT Drag and Drop")
+
+      # Show the Application as the top window
+      self.SetTopWindow(frame)
+      return True
+
+
+def runTest(frame, nb, log):
+    win = TestPanel(nb, log)
+    return win
+
+# Declare the Application and start the Main Loop
+app = MyApp(0)
+app.MainLoop()
Index: trunk/src/testing/app/ishare/FastDXT/bin/Makefile
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/bin/Makefile	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/bin/Makefile	(revision 4)
@@ -0,0 +1,43 @@
+
+default: help
+
+help:
+	@echo "Targets: testperf, tetquality, testperf4k, or testquality4k"
+
+testperf: main
+	convert lena.png -depth 8 RGBA:lena.rgba
+	./main 256 256 lena.rgba
+
+testquality: 2dxt
+	convert lena.png -depth 8 RGBA:lena.rgba
+	./2dxt 256 256 1 lena.rgba lena.dxt
+	./viewdxt -w 256 -h 256 -p -o -r lena.rgba lena.dxt
+	./2dxt 256 256 6 lena.rgba lena.dxt
+	./viewdxt -w 256 -h 256 -6 -p -o -r lena.rgba lena.dxt
+
+
+testperf2k: main
+	convert 2k.png -depth 8 RGBA:2k.rgba
+	./main 1920 1080 2k.rgba
+
+testquality2k: 2dxt
+	convert 2k.png -depth 8 RGBA:2k.rgba
+	./2dxt 1920 1080 1 2k.rgba 2k.dxt
+	./viewdxt -w 1920 -h 1080 -o -p -r 2k.rgba 2k.dxt
+	./2dxt 1920 1080 6 2k.rgba 2k.dxt
+	./viewdxt -w 1920 -h 1080 -6 -o -p -r 2k.rgba 2k.dxt
+
+testperf4k: main
+	convert 4k.png -depth 8 RGBA:4k.rgba
+	./main 4096 2048 4k.rgba
+
+testquality4k: 2dxt
+	convert 4k.png -depth 8 RGBA:4k.rgba
+	./2dxt 4096 2048 1 4k.rgba 4k.dxt
+	./viewdxt -w 4096 -h 2048 -o -p -r 4k.rgba 4k.dxt
+	./2dxt 4096 2048 6 4k.rgba 4k.dxt
+	./viewdxt -w 4096 -h 2048 -6 -o -p -r 4k.rgba 4k.dxt
+
+clean:
+	/bin/rm -f *.rgba *.dxt out.*
+
Index: trunk/src/testing/app/ishare/FastDXT/bin/ycocg.frag
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/bin/ycocg.frag	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/bin/ycocg.frag	(revision 4)
@@ -0,0 +1,18 @@
+uniform sampler2D yuvtex;
+
+void main(void)
+{
+  vec4 col = texture2D(yuvtex, gl_TexCoord[0].st);
+
+  float Co = col[0] - 0.5;
+  float Cg = col[1] - 0.375;
+  float  Y = col[3];
+
+  float s = Y - (Cg / 2.0);
+  float G = Cg + s;
+  float B = s - (Co / 2.0);
+  float R = B + Co;
+  
+  gl_FragColor=vec4(R,G,B,1.0);
+}
+
Index: trunk/src/testing/app/ishare/FastDXT/bin/ycocg.vert
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/bin/ycocg.vert	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/bin/ycocg.vert	(revision 4)
@@ -0,0 +1,7 @@
+
+void main()
+{
+        gl_TexCoord[0] = gl_MultiTexCoord0;
+        gl_Position = ftransform();
+} 
+
Index: trunk/src/testing/app/ishare/FastDXT/glext.h
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/glext.h	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/glext.h	(revision 4)
@@ -0,0 +1,6531 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef __glext_h_
+#define __glext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2004 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: This software was created using the
+** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has
+** not been independently verified as being compliant with the OpenGL(R)
+** version 1.2.1 Specification.
+*/
+
+#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+#ifndef GLAPI
+#define GLAPI extern
+#endif
+
+/*************************************************************/
+
+/* Header file version number, required by OpenGL ABI for Linux */
+/* glext.h last updated 2005/06/20 */
+/* Current version at http://oss.sgi.com/projects/ogl-sample/registry/ */
+#define GL_GLEXT_VERSION 29
+
+#ifndef GL_VERSION_1_2
+#define GL_UNSIGNED_BYTE_3_3_2            0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_INT_8_8_8_8           0x8035
+#define GL_UNSIGNED_INT_10_10_10_2        0x8036
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_TEXTURE_BINDING_3D             0x806A
+#define GL_PACK_SKIP_IMAGES               0x806B
+#define GL_PACK_IMAGE_HEIGHT              0x806C
+#define GL_UNPACK_SKIP_IMAGES             0x806D
+#define GL_UNPACK_IMAGE_HEIGHT            0x806E
+#define GL_TEXTURE_3D                     0x806F
+#define GL_PROXY_TEXTURE_3D               0x8070
+#define GL_TEXTURE_DEPTH                  0x8071
+#define GL_TEXTURE_WRAP_R                 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE            0x8073
+#define GL_UNSIGNED_BYTE_2_3_3_REV        0x8362
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV       0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV     0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV     0x8366
+#define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367
+#define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
+#define GL_BGR                            0x80E0
+#define GL_BGRA                           0x80E1
+#define GL_MAX_ELEMENTS_VERTICES          0x80E8
+#define GL_MAX_ELEMENTS_INDICES           0x80E9
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_TEXTURE_MIN_LOD                0x813A
+#define GL_TEXTURE_MAX_LOD                0x813B
+#define GL_TEXTURE_BASE_LEVEL             0x813C
+#define GL_TEXTURE_MAX_LEVEL              0x813D
+#define GL_LIGHT_MODEL_COLOR_CONTROL      0x81F8
+#define GL_SINGLE_COLOR                   0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR        0x81FA
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY  0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY  0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#endif
+
+#ifndef GL_ARB_imaging
+#define GL_CONSTANT_COLOR                 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002
+#define GL_CONSTANT_ALPHA                 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004
+#define GL_BLEND_COLOR                    0x8005
+#define GL_FUNC_ADD                       0x8006
+#define GL_MIN                            0x8007
+#define GL_MAX                            0x8008
+#define GL_BLEND_EQUATION                 0x8009
+#define GL_FUNC_SUBTRACT                  0x800A
+#define GL_FUNC_REVERSE_SUBTRACT          0x800B
+#define GL_CONVOLUTION_1D                 0x8010
+#define GL_CONVOLUTION_2D                 0x8011
+#define GL_SEPARABLE_2D                   0x8012
+#define GL_CONVOLUTION_BORDER_MODE        0x8013
+#define GL_CONVOLUTION_FILTER_SCALE       0x8014
+#define GL_CONVOLUTION_FILTER_BIAS        0x8015
+#define GL_REDUCE                         0x8016
+#define GL_CONVOLUTION_FORMAT             0x8017
+#define GL_CONVOLUTION_WIDTH              0x8018
+#define GL_CONVOLUTION_HEIGHT             0x8019
+#define GL_MAX_CONVOLUTION_WIDTH          0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT         0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE     0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS      0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023
+#define GL_HISTOGRAM                      0x8024
+#define GL_PROXY_HISTOGRAM                0x8025
+#define GL_HISTOGRAM_WIDTH                0x8026
+#define GL_HISTOGRAM_FORMAT               0x8027
+#define GL_HISTOGRAM_RED_SIZE             0x8028
+#define GL_HISTOGRAM_GREEN_SIZE           0x8029
+#define GL_HISTOGRAM_BLUE_SIZE            0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE           0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C
+#define GL_HISTOGRAM_SINK                 0x802D
+#define GL_MINMAX                         0x802E
+#define GL_MINMAX_FORMAT                  0x802F
+#define GL_MINMAX_SINK                    0x8030
+#define GL_TABLE_TOO_LARGE                0x8031
+#define GL_COLOR_MATRIX                   0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB
+#define GL_COLOR_TABLE                    0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2
+#define GL_PROXY_COLOR_TABLE              0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5
+#define GL_COLOR_TABLE_SCALE              0x80D6
+#define GL_COLOR_TABLE_BIAS               0x80D7
+#define GL_COLOR_TABLE_FORMAT             0x80D8
+#define GL_COLOR_TABLE_WIDTH              0x80D9
+#define GL_COLOR_TABLE_RED_SIZE           0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF
+#define GL_CONSTANT_BORDER                0x8151
+#define GL_REPLICATE_BORDER               0x8153
+#define GL_CONVOLUTION_BORDER_COLOR       0x8154
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_TRANSPOSE_MODELVIEW_MATRIX     0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX    0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX       0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX         0x84E6
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+#define GL_MULTISAMPLE_BIT                0x20000000
+#define GL_NORMAL_MAP                     0x8511
+#define GL_REFLECTION_MAP                 0x8512
+#define GL_TEXTURE_CUBE_MAP               0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP         0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+#define GL_COMPRESSED_ALPHA               0x84E9
+#define GL_COMPRESSED_LUMINANCE           0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA     0x84EB
+#define GL_COMPRESSED_INTENSITY           0x84EC
+#define GL_COMPRESSED_RGB                 0x84ED
+#define GL_COMPRESSED_RGBA                0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT       0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE  0x86A0
+#define GL_TEXTURE_COMPRESSED             0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+#define GL_CLAMP_TO_BORDER                0x812D
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_SOURCE0_RGB                    0x8580
+#define GL_SOURCE1_RGB                    0x8581
+#define GL_SOURCE2_RGB                    0x8582
+#define GL_SOURCE0_ALPHA                  0x8588
+#define GL_SOURCE1_ALPHA                  0x8589
+#define GL_SOURCE2_ALPHA                  0x858A
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_SUBTRACT                       0x84E7
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_BLEND_DST_RGB                  0x80C8
+#define GL_BLEND_SRC_RGB                  0x80C9
+#define GL_BLEND_DST_ALPHA                0x80CA
+#define GL_BLEND_SRC_ALPHA                0x80CB
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_GENERATE_MIPMAP                0x8191
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+#define GL_DEPTH_COMPONENT16              0x81A5
+#define GL_DEPTH_COMPONENT24              0x81A6
+#define GL_DEPTH_COMPONENT32              0x81A7
+#define GL_MIRRORED_REPEAT                0x8370
+#define GL_FOG_COORDINATE_SOURCE          0x8450
+#define GL_FOG_COORDINATE                 0x8451
+#define GL_FRAGMENT_DEPTH                 0x8452
+#define GL_CURRENT_FOG_COORDINATE         0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE      0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE    0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER   0x8456
+#define GL_FOG_COORDINATE_ARRAY           0x8457
+#define GL_COLOR_SUM                      0x8458
+#define GL_CURRENT_SECONDARY_COLOR        0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE     0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE     0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE   0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER  0x845D
+#define GL_SECONDARY_COLOR_ARRAY          0x845E
+#define GL_MAX_TEXTURE_LOD_BIAS           0x84FD
+#define GL_TEXTURE_FILTER_CONTROL         0x8500
+#define GL_TEXTURE_LOD_BIAS               0x8501
+#define GL_INCR_WRAP                      0x8507
+#define GL_DECR_WRAP                      0x8508
+#define GL_TEXTURE_DEPTH_SIZE             0x884A
+#define GL_DEPTH_TEXTURE_MODE             0x884B
+#define GL_TEXTURE_COMPARE_MODE           0x884C
+#define GL_TEXTURE_COMPARE_FUNC           0x884D
+#define GL_COMPARE_R_TO_TEXTURE           0x884E
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+#define GL_QUERY_COUNTER_BITS             0x8864
+#define GL_CURRENT_QUERY                  0x8865
+#define GL_QUERY_RESULT                   0x8866
+#define GL_QUERY_RESULT_AVAILABLE         0x8867
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+#define GL_ARRAY_BUFFER_BINDING           0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING    0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING    0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING     0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING     0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING    0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_READ_ONLY                      0x88B8
+#define GL_WRITE_ONLY                     0x88B9
+#define GL_READ_WRITE                     0x88BA
+#define GL_BUFFER_ACCESS                  0x88BB
+#define GL_BUFFER_MAPPED                  0x88BC
+#define GL_BUFFER_MAP_POINTER             0x88BD
+#define GL_STREAM_DRAW                    0x88E0
+#define GL_STREAM_READ                    0x88E1
+#define GL_STREAM_COPY                    0x88E2
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_STATIC_READ                    0x88E5
+#define GL_STATIC_COPY                    0x88E6
+#define GL_DYNAMIC_DRAW                   0x88E8
+#define GL_DYNAMIC_READ                   0x88E9
+#define GL_DYNAMIC_COPY                   0x88EA
+#define GL_SAMPLES_PASSED                 0x8914
+#define GL_FOG_COORD_SRC                  GL_FOG_COORDINATE_SOURCE
+#define GL_FOG_COORD                      GL_FOG_COORDINATE
+#define GL_CURRENT_FOG_COORD              GL_CURRENT_FOG_COORDINATE
+#define GL_FOG_COORD_ARRAY_TYPE           GL_FOG_COORDINATE_ARRAY_TYPE
+#define GL_FOG_COORD_ARRAY_STRIDE         GL_FOG_COORDINATE_ARRAY_STRIDE
+#define GL_FOG_COORD_ARRAY_POINTER        GL_FOG_COORDINATE_ARRAY_POINTER
+#define GL_FOG_COORD_ARRAY                GL_FOG_COORDINATE_ARRAY
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
+#define GL_SRC0_RGB                       GL_SOURCE0_RGB
+#define GL_SRC1_RGB                       GL_SOURCE1_RGB
+#define GL_SRC2_RGB                       GL_SOURCE2_RGB
+#define GL_SRC0_ALPHA                     GL_SOURCE0_ALPHA
+#define GL_SRC1_ALPHA                     GL_SOURCE1_ALPHA
+#define GL_SRC2_ALPHA                     GL_SOURCE2_ALPHA
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_BLEND_EQUATION_RGB             GL_BLEND_EQUATION
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625
+#define GL_CURRENT_VERTEX_ATTRIB          0x8626
+#define GL_VERTEX_PROGRAM_POINT_SIZE      0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE        0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645
+#define GL_STENCIL_BACK_FUNC              0x8800
+#define GL_STENCIL_BACK_FAIL              0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803
+#define GL_MAX_DRAW_BUFFERS               0x8824
+#define GL_DRAW_BUFFER0                   0x8825
+#define GL_DRAW_BUFFER1                   0x8826
+#define GL_DRAW_BUFFER2                   0x8827
+#define GL_DRAW_BUFFER3                   0x8828
+#define GL_DRAW_BUFFER4                   0x8829
+#define GL_DRAW_BUFFER5                   0x882A
+#define GL_DRAW_BUFFER6                   0x882B
+#define GL_DRAW_BUFFER7                   0x882C
+#define GL_DRAW_BUFFER8                   0x882D
+#define GL_DRAW_BUFFER9                   0x882E
+#define GL_DRAW_BUFFER10                  0x882F
+#define GL_DRAW_BUFFER11                  0x8830
+#define GL_DRAW_BUFFER12                  0x8831
+#define GL_DRAW_BUFFER13                  0x8832
+#define GL_DRAW_BUFFER14                  0x8833
+#define GL_DRAW_BUFFER15                  0x8834
+#define GL_BLEND_EQUATION_ALPHA           0x883D
+#define GL_POINT_SPRITE                   0x8861
+#define GL_COORD_REPLACE                  0x8862
+#define GL_MAX_VERTEX_ATTRIBS             0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_MAX_TEXTURE_COORDS             0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS        0x8872
+#define GL_FRAGMENT_SHADER                0x8B30
+#define GL_VERTEX_SHADER                  0x8B31
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS  0x8B4A
+#define GL_MAX_VARYING_FLOATS             0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_SHADER_TYPE                    0x8B4F
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_SAMPLER_1D                     0x8B5D
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_3D                     0x8B5F
+#define GL_SAMPLER_CUBE                   0x8B60
+#define GL_SAMPLER_1D_SHADOW              0x8B61
+#define GL_SAMPLER_2D_SHADOW              0x8B62
+#define GL_DELETE_STATUS                  0x8B80
+#define GL_COMPILE_STATUS                 0x8B81
+#define GL_LINK_STATUS                    0x8B82
+#define GL_VALIDATE_STATUS                0x8B83
+#define GL_INFO_LOG_LENGTH                0x8B84
+#define GL_ATTACHED_SHADERS               0x8B85
+#define GL_ACTIVE_UNIFORMS                0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH      0x8B87
+#define GL_SHADER_SOURCE_LENGTH           0x8B88
+#define GL_ACTIVE_ATTRIBUTES              0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH    0x8B8A
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_SHADING_LANGUAGE_VERSION       0x8B8C
+#define GL_CURRENT_PROGRAM                0x8B8D
+#define GL_POINT_SPRITE_COORD_ORIGIN      0x8CA0
+#define GL_LOWER_LEFT                     0x8CA1
+#define GL_UPPER_LEFT                     0x8CA2
+#define GL_STENCIL_BACK_REF               0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK         0x8CA5
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_TEXTURE0_ARB                   0x84C0
+#define GL_TEXTURE1_ARB                   0x84C1
+#define GL_TEXTURE2_ARB                   0x84C2
+#define GL_TEXTURE3_ARB                   0x84C3
+#define GL_TEXTURE4_ARB                   0x84C4
+#define GL_TEXTURE5_ARB                   0x84C5
+#define GL_TEXTURE6_ARB                   0x84C6
+#define GL_TEXTURE7_ARB                   0x84C7
+#define GL_TEXTURE8_ARB                   0x84C8
+#define GL_TEXTURE9_ARB                   0x84C9
+#define GL_TEXTURE10_ARB                  0x84CA
+#define GL_TEXTURE11_ARB                  0x84CB
+#define GL_TEXTURE12_ARB                  0x84CC
+#define GL_TEXTURE13_ARB                  0x84CD
+#define GL_TEXTURE14_ARB                  0x84CE
+#define GL_TEXTURE15_ARB                  0x84CF
+#define GL_TEXTURE16_ARB                  0x84D0
+#define GL_TEXTURE17_ARB                  0x84D1
+#define GL_TEXTURE18_ARB                  0x84D2
+#define GL_TEXTURE19_ARB                  0x84D3
+#define GL_TEXTURE20_ARB                  0x84D4
+#define GL_TEXTURE21_ARB                  0x84D5
+#define GL_TEXTURE22_ARB                  0x84D6
+#define GL_TEXTURE23_ARB                  0x84D7
+#define GL_TEXTURE24_ARB                  0x84D8
+#define GL_TEXTURE25_ARB                  0x84D9
+#define GL_TEXTURE26_ARB                  0x84DA
+#define GL_TEXTURE27_ARB                  0x84DB
+#define GL_TEXTURE28_ARB                  0x84DC
+#define GL_TEXTURE29_ARB                  0x84DD
+#define GL_TEXTURE30_ARB                  0x84DE
+#define GL_TEXTURE31_ARB                  0x84DF
+#define GL_ACTIVE_TEXTURE_ARB             0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_MULTISAMPLE_ARB                0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F
+#define GL_SAMPLE_COVERAGE_ARB            0x80A0
+#define GL_SAMPLE_BUFFERS_ARB             0x80A8
+#define GL_SAMPLES_ARB                    0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB
+#define GL_MULTISAMPLE_BIT_ARB            0x20000000
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_NORMAL_MAP_ARB                 0x8511
+#define GL_REFLECTION_MAP_ARB             0x8512
+#define GL_TEXTURE_CUBE_MAP_ARB           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_COMPRESSED_ALPHA_ARB           0x84E9
+#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
+#define GL_COMPRESSED_INTENSITY_ARB       0x84EC
+#define GL_COMPRESSED_RGB_ARB             0x84ED
+#define GL_COMPRESSED_RGBA_ARB            0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
+#define GL_TEXTURE_COMPRESSED_ARB         0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_ARB            0x812D
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_POINT_SIZE_MIN_ARB             0x8126
+#define GL_POINT_SIZE_MAX_ARB             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128
+#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_MAX_VERTEX_UNITS_ARB           0x86A4
+#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5
+#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6
+#define GL_VERTEX_BLEND_ARB               0x86A7
+#define GL_CURRENT_WEIGHT_ARB             0x86A8
+#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA
+#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB
+#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC
+#define GL_WEIGHT_ARRAY_ARB               0x86AD
+#define GL_MODELVIEW0_ARB                 0x1700
+#define GL_MODELVIEW1_ARB                 0x850A
+#define GL_MODELVIEW2_ARB                 0x8722
+#define GL_MODELVIEW3_ARB                 0x8723
+#define GL_MODELVIEW4_ARB                 0x8724
+#define GL_MODELVIEW5_ARB                 0x8725
+#define GL_MODELVIEW6_ARB                 0x8726
+#define GL_MODELVIEW7_ARB                 0x8727
+#define GL_MODELVIEW8_ARB                 0x8728
+#define GL_MODELVIEW9_ARB                 0x8729
+#define GL_MODELVIEW10_ARB                0x872A
+#define GL_MODELVIEW11_ARB                0x872B
+#define GL_MODELVIEW12_ARB                0x872C
+#define GL_MODELVIEW13_ARB                0x872D
+#define GL_MODELVIEW14_ARB                0x872E
+#define GL_MODELVIEW15_ARB                0x872F
+#define GL_MODELVIEW16_ARB                0x8730
+#define GL_MODELVIEW17_ARB                0x8731
+#define GL_MODELVIEW18_ARB                0x8732
+#define GL_MODELVIEW19_ARB                0x8733
+#define GL_MODELVIEW20_ARB                0x8734
+#define GL_MODELVIEW21_ARB                0x8735
+#define GL_MODELVIEW22_ARB                0x8736
+#define GL_MODELVIEW23_ARB                0x8737
+#define GL_MODELVIEW24_ARB                0x8738
+#define GL_MODELVIEW25_ARB                0x8739
+#define GL_MODELVIEW26_ARB                0x873A
+#define GL_MODELVIEW27_ARB                0x873B
+#define GL_MODELVIEW28_ARB                0x873C
+#define GL_MODELVIEW29_ARB                0x873D
+#define GL_MODELVIEW30_ARB                0x873E
+#define GL_MODELVIEW31_ARB                0x873F
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_MATRIX_PALETTE_ARB             0x8840
+#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841
+#define GL_MAX_PALETTE_MATRICES_ARB       0x8842
+#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843
+#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844
+#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845
+#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_COMBINE_ARB                    0x8570
+#define GL_COMBINE_RGB_ARB                0x8571
+#define GL_COMBINE_ALPHA_ARB              0x8572
+#define GL_SOURCE0_RGB_ARB                0x8580
+#define GL_SOURCE1_RGB_ARB                0x8581
+#define GL_SOURCE2_RGB_ARB                0x8582
+#define GL_SOURCE0_ALPHA_ARB              0x8588
+#define GL_SOURCE1_ALPHA_ARB              0x8589
+#define GL_SOURCE2_ALPHA_ARB              0x858A
+#define GL_OPERAND0_RGB_ARB               0x8590
+#define GL_OPERAND1_RGB_ARB               0x8591
+#define GL_OPERAND2_RGB_ARB               0x8592
+#define GL_OPERAND0_ALPHA_ARB             0x8598
+#define GL_OPERAND1_ALPHA_ARB             0x8599
+#define GL_OPERAND2_ALPHA_ARB             0x859A
+#define GL_RGB_SCALE_ARB                  0x8573
+#define GL_ADD_SIGNED_ARB                 0x8574
+#define GL_INTERPOLATE_ARB                0x8575
+#define GL_SUBTRACT_ARB                   0x84E7
+#define GL_CONSTANT_ARB                   0x8576
+#define GL_PRIMARY_COLOR_ARB              0x8577
+#define GL_PREVIOUS_ARB                   0x8578
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_DOT3_RGB_ARB                   0x86AE
+#define GL_DOT3_RGBA_ARB                  0x86AF
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_ARB            0x8370
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_DEPTH_COMPONENT16_ARB          0x81A5
+#define GL_DEPTH_COMPONENT24_ARB          0x81A6
+#define GL_DEPTH_COMPONENT32_ARB          0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF
+#endif
+
+#ifndef GL_ARB_window_pos
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_COLOR_SUM_ARB                  0x8458
+#define GL_VERTEX_PROGRAM_ARB             0x8620
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625
+#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626
+#define GL_PROGRAM_LENGTH_ARB             0x8627
+#define GL_PROGRAM_STRING_ARB             0x8628
+#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
+#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F
+#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
+#define GL_CURRENT_MATRIX_ARB             0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
+#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B
+#define GL_PROGRAM_BINDING_ARB            0x8677
+#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
+#define GL_PROGRAM_ERROR_STRING_ARB       0x8874
+#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875
+#define GL_PROGRAM_FORMAT_ARB             0x8876
+#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0
+#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1
+#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
+#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
+#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4
+#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5
+#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
+#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
+#define GL_PROGRAM_PARAMETERS_ARB         0x88A8
+#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9
+#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA
+#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
+#define GL_PROGRAM_ATTRIBS_ARB            0x88AC
+#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD
+#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE
+#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
+#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0
+#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
+#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
+#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
+#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
+#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
+#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
+#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7
+#define GL_MATRIX0_ARB                    0x88C0
+#define GL_MATRIX1_ARB                    0x88C1
+#define GL_MATRIX2_ARB                    0x88C2
+#define GL_MATRIX3_ARB                    0x88C3
+#define GL_MATRIX4_ARB                    0x88C4
+#define GL_MATRIX5_ARB                    0x88C5
+#define GL_MATRIX6_ARB                    0x88C6
+#define GL_MATRIX7_ARB                    0x88C7
+#define GL_MATRIX8_ARB                    0x88C8
+#define GL_MATRIX9_ARB                    0x88C9
+#define GL_MATRIX10_ARB                   0x88CA
+#define GL_MATRIX11_ARB                   0x88CB
+#define GL_MATRIX12_ARB                   0x88CC
+#define GL_MATRIX13_ARB                   0x88CD
+#define GL_MATRIX14_ARB                   0x88CE
+#define GL_MATRIX15_ARB                   0x88CF
+#define GL_MATRIX16_ARB                   0x88D0
+#define GL_MATRIX17_ARB                   0x88D1
+#define GL_MATRIX18_ARB                   0x88D2
+#define GL_MATRIX19_ARB                   0x88D3
+#define GL_MATRIX20_ARB                   0x88D4
+#define GL_MATRIX21_ARB                   0x88D5
+#define GL_MATRIX22_ARB                   0x88D6
+#define GL_MATRIX23_ARB                   0x88D7
+#define GL_MATRIX24_ARB                   0x88D8
+#define GL_MATRIX25_ARB                   0x88D9
+#define GL_MATRIX26_ARB                   0x88DA
+#define GL_MATRIX27_ARB                   0x88DB
+#define GL_MATRIX28_ARB                   0x88DC
+#define GL_MATRIX29_ARB                   0x88DD
+#define GL_MATRIX30_ARB                   0x88DE
+#define GL_MATRIX31_ARB                   0x88DF
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_FRAGMENT_PROGRAM_ARB           0x8804
+#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805
+#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806
+#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807
+#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
+#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
+#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
+#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
+#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
+#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
+#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
+#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
+#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
+#define GL_MAX_TEXTURE_COORDS_ARB         0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_BUFFER_SIZE_ARB                0x8764
+#define GL_BUFFER_USAGE_ARB               0x8765
+#define GL_ARRAY_BUFFER_ARB               0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB                  0x88B8
+#define GL_WRITE_ONLY_ARB                 0x88B9
+#define GL_READ_WRITE_ARB                 0x88BA
+#define GL_BUFFER_ACCESS_ARB              0x88BB
+#define GL_BUFFER_MAPPED_ARB              0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#define GL_STREAM_DRAW_ARB                0x88E0
+#define GL_STREAM_READ_ARB                0x88E1
+#define GL_STREAM_COPY_ARB                0x88E2
+#define GL_STATIC_DRAW_ARB                0x88E4
+#define GL_STATIC_READ_ARB                0x88E5
+#define GL_STATIC_COPY_ARB                0x88E6
+#define GL_DYNAMIC_DRAW_ARB               0x88E8
+#define GL_DYNAMIC_READ_ARB               0x88E9
+#define GL_DYNAMIC_COPY_ARB               0x88EA
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_QUERY_COUNTER_BITS_ARB         0x8864
+#define GL_CURRENT_QUERY_ARB              0x8865
+#define GL_QUERY_RESULT_ARB               0x8866
+#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867
+#define GL_SAMPLES_PASSED_ARB             0x8914
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_PROGRAM_OBJECT_ARB             0x8B40
+#define GL_SHADER_OBJECT_ARB              0x8B48
+#define GL_OBJECT_TYPE_ARB                0x8B4E
+#define GL_OBJECT_SUBTYPE_ARB             0x8B4F
+#define GL_FLOAT_VEC2_ARB                 0x8B50
+#define GL_FLOAT_VEC3_ARB                 0x8B51
+#define GL_FLOAT_VEC4_ARB                 0x8B52
+#define GL_INT_VEC2_ARB                   0x8B53
+#define GL_INT_VEC3_ARB                   0x8B54
+#define GL_INT_VEC4_ARB                   0x8B55
+#define GL_BOOL_ARB                       0x8B56
+#define GL_BOOL_VEC2_ARB                  0x8B57
+#define GL_BOOL_VEC3_ARB                  0x8B58
+#define GL_BOOL_VEC4_ARB                  0x8B59
+#define GL_FLOAT_MAT2_ARB                 0x8B5A
+#define GL_FLOAT_MAT3_ARB                 0x8B5B
+#define GL_FLOAT_MAT4_ARB                 0x8B5C
+#define GL_SAMPLER_1D_ARB                 0x8B5D
+#define GL_SAMPLER_2D_ARB                 0x8B5E
+#define GL_SAMPLER_3D_ARB                 0x8B5F
+#define GL_SAMPLER_CUBE_ARB               0x8B60
+#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61
+#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62
+#define GL_SAMPLER_2D_RECT_ARB            0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64
+#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80
+#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB         0x8B82
+#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84
+#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85
+#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86
+#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
+#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB              0x8B31
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
+#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
+#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89
+#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB            0x8B30
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_POINT_SPRITE_ARB               0x8861
+#define GL_COORD_REPLACE_ARB              0x8862
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ARB           0x8824
+#define GL_DRAW_BUFFER0_ARB               0x8825
+#define GL_DRAW_BUFFER1_ARB               0x8826
+#define GL_DRAW_BUFFER2_ARB               0x8827
+#define GL_DRAW_BUFFER3_ARB               0x8828
+#define GL_DRAW_BUFFER4_ARB               0x8829
+#define GL_DRAW_BUFFER5_ARB               0x882A
+#define GL_DRAW_BUFFER6_ARB               0x882B
+#define GL_DRAW_BUFFER7_ARB               0x882C
+#define GL_DRAW_BUFFER8_ARB               0x882D
+#define GL_DRAW_BUFFER9_ARB               0x882E
+#define GL_DRAW_BUFFER10_ARB              0x882F
+#define GL_DRAW_BUFFER11_ARB              0x8830
+#define GL_DRAW_BUFFER12_ARB              0x8831
+#define GL_DRAW_BUFFER13_ARB              0x8832
+#define GL_DRAW_BUFFER14_ARB              0x8833
+#define GL_DRAW_BUFFER15_ARB              0x8834
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_ARB          0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_RGBA_FLOAT_MODE_ARB            0x8820
+#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A
+#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B
+#define GL_CLAMP_READ_COLOR_ARB           0x891C
+#define GL_FIXED_ONLY_ARB                 0x891D
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_HALF_FLOAT_ARB                 0x140B
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_TEXTURE_RED_TYPE_ARB           0x8C10
+#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11
+#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12
+#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13
+#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14
+#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15
+#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16
+#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17
+#define GL_RGBA32F_ARB                    0x8814
+#define GL_RGB32F_ARB                     0x8815
+#define GL_ALPHA32F_ARB                   0x8816
+#define GL_INTENSITY32F_ARB               0x8817
+#define GL_LUMINANCE32F_ARB               0x8818
+#define GL_LUMINANCE_ALPHA32F_ARB         0x8819
+#define GL_RGBA16F_ARB                    0x881A
+#define GL_RGB16F_ARB                     0x881B
+#define GL_ALPHA16F_ARB                   0x881C
+#define GL_INTENSITY16F_ARB               0x881D
+#define GL_LUMINANCE16F_ARB               0x881E
+#define GL_LUMINANCE_ALPHA16F_ARB         0x881F
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_ABGR_EXT                       0x8000
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_CONSTANT_COLOR_EXT             0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002
+#define GL_CONSTANT_ALPHA_EXT             0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004
+#define GL_BLEND_COLOR_EXT                0x8005
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_POLYGON_OFFSET_EXT             0x8037
+#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038
+#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_ALPHA4_EXT                     0x803B
+#define GL_ALPHA8_EXT                     0x803C
+#define GL_ALPHA12_EXT                    0x803D
+#define GL_ALPHA16_EXT                    0x803E
+#define GL_LUMINANCE4_EXT                 0x803F
+#define GL_LUMINANCE8_EXT                 0x8040
+#define GL_LUMINANCE12_EXT                0x8041
+#define GL_LUMINANCE16_EXT                0x8042
+#define GL_LUMINANCE4_ALPHA4_EXT          0x8043
+#define GL_LUMINANCE6_ALPHA2_EXT          0x8044
+#define GL_LUMINANCE8_ALPHA8_EXT          0x8045
+#define GL_LUMINANCE12_ALPHA4_EXT         0x8046
+#define GL_LUMINANCE12_ALPHA12_EXT        0x8047
+#define GL_LUMINANCE16_ALPHA16_EXT        0x8048
+#define GL_INTENSITY_EXT                  0x8049
+#define GL_INTENSITY4_EXT                 0x804A
+#define GL_INTENSITY8_EXT                 0x804B
+#define GL_INTENSITY12_EXT                0x804C
+#define GL_INTENSITY16_EXT                0x804D
+#define GL_RGB2_EXT                       0x804E
+#define GL_RGB4_EXT                       0x804F
+#define GL_RGB5_EXT                       0x8050
+#define GL_RGB8_EXT                       0x8051
+#define GL_RGB10_EXT                      0x8052
+#define GL_RGB12_EXT                      0x8053
+#define GL_RGB16_EXT                      0x8054
+#define GL_RGBA2_EXT                      0x8055
+#define GL_RGBA4_EXT                      0x8056
+#define GL_RGB5_A1_EXT                    0x8057
+#define GL_RGBA8_EXT                      0x8058
+#define GL_RGB10_A2_EXT                   0x8059
+#define GL_RGBA12_EXT                     0x805A
+#define GL_RGBA16_EXT                     0x805B
+#define GL_TEXTURE_RED_SIZE_EXT           0x805C
+#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D
+#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E
+#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060
+#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061
+#define GL_REPLACE_EXT                    0x8062
+#define GL_PROXY_TEXTURE_1D_EXT           0x8063
+#define GL_PROXY_TEXTURE_2D_EXT           0x8064
+#define GL_TEXTURE_TOO_LARGE_EXT          0x8065
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_PACK_SKIP_IMAGES_EXT           0x806B
+#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C
+#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D
+#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E
+#define GL_TEXTURE_3D_EXT                 0x806F
+#define GL_PROXY_TEXTURE_3D_EXT           0x8070
+#define GL_TEXTURE_DEPTH_EXT              0x8071
+#define GL_TEXTURE_WRAP_R_EXT             0x8072
+#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_FILTER4_SGIS                   0x8146
+#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147
+#endif
+
+#ifndef GL_EXT_subtexture
+#endif
+
+#ifndef GL_EXT_copy_texture
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_HISTOGRAM_EXT                  0x8024
+#define GL_PROXY_HISTOGRAM_EXT            0x8025
+#define GL_HISTOGRAM_WIDTH_EXT            0x8026
+#define GL_HISTOGRAM_FORMAT_EXT           0x8027
+#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028
+#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029
+#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C
+#define GL_HISTOGRAM_SINK_EXT             0x802D
+#define GL_MINMAX_EXT                     0x802E
+#define GL_MINMAX_FORMAT_EXT              0x802F
+#define GL_MINMAX_SINK_EXT                0x8030
+#define GL_TABLE_TOO_LARGE_EXT            0x8031
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_CONVOLUTION_1D_EXT             0x8010
+#define GL_CONVOLUTION_2D_EXT             0x8011
+#define GL_SEPARABLE_2D_EXT               0x8012
+#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013
+#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014
+#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015
+#define GL_REDUCE_EXT                     0x8016
+#define GL_CONVOLUTION_FORMAT_EXT         0x8017
+#define GL_CONVOLUTION_WIDTH_EXT          0x8018
+#define GL_CONVOLUTION_HEIGHT_EXT         0x8019
+#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
+#endif
+
+#ifndef GL_SGI_color_matrix
+#define GL_COLOR_MATRIX_SGI               0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_COLOR_TABLE_SGI                0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2
+#define GL_PROXY_COLOR_TABLE_SGI          0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5
+#define GL_COLOR_TABLE_SCALE_SGI          0x80D6
+#define GL_COLOR_TABLE_BIAS_SGI           0x80D7
+#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8
+#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9
+#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_PIXEL_TEXTURE_SGIS             0x8353
+#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354
+#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355
+#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_PIXEL_TEX_GEN_SGIX             0x8139
+#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130
+#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131
+#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132
+#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133
+#define GL_TEXTURE_4D_SGIS                0x8134
+#define GL_PROXY_TEXTURE_4D_SGIS          0x8135
+#define GL_TEXTURE_4DSIZE_SGIS            0x8136
+#define GL_TEXTURE_WRAP_Q_SGIS            0x8137
+#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138
+#define GL_TEXTURE_4D_BINDING_SGIS        0x814F
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC
+#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_CMYK_EXT                       0x800C
+#define GL_CMYKA_EXT                      0x800D
+#define GL_PACK_CMYK_HINT_EXT             0x800E
+#define GL_UNPACK_CMYK_HINT_EXT           0x800F
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_TEXTURE_PRIORITY_EXT           0x8066
+#define GL_TEXTURE_RESIDENT_EXT           0x8067
+#define GL_TEXTURE_1D_BINDING_EXT         0x8068
+#define GL_TEXTURE_2D_BINDING_EXT         0x8069
+#define GL_TEXTURE_3D_BINDING_EXT         0x806A
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095
+#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096
+#define GL_LINEAR_DETAIL_SGIS             0x8097
+#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098
+#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099
+#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A
+#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B
+#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_LINEAR_SHARPEN_SGIS            0x80AD
+#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE
+#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF
+#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032
+#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034
+#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035
+#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_TEXTURE_MIN_LOD_SGIS           0x813A
+#define GL_TEXTURE_MAX_LOD_SGIS           0x813B
+#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C
+#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_MULTISAMPLE_SGIS               0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F
+#define GL_SAMPLE_MASK_SGIS               0x80A0
+#define GL_1PASS_SGIS                     0x80A1
+#define GL_2PASS_0_SGIS                   0x80A2
+#define GL_2PASS_1_SGIS                   0x80A3
+#define GL_4PASS_0_SGIS                   0x80A4
+#define GL_4PASS_1_SGIS                   0x80A5
+#define GL_4PASS_2_SGIS                   0x80A6
+#define GL_4PASS_3_SGIS                   0x80A7
+#define GL_SAMPLE_BUFFERS_SGIS            0x80A8
+#define GL_SAMPLES_SGIS                   0x80A9
+#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA
+#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB
+#define GL_SAMPLE_PATTERN_SGIS            0x80AC
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_RESCALE_NORMAL_EXT             0x803A
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_VERTEX_ARRAY_EXT               0x8074
+#define GL_NORMAL_ARRAY_EXT               0x8075
+#define GL_COLOR_ARRAY_EXT                0x8076
+#define GL_INDEX_ARRAY_EXT                0x8077
+#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078
+#define GL_EDGE_FLAG_ARRAY_EXT            0x8079
+#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A
+#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B
+#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C
+#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D
+#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E
+#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F
+#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080
+#define GL_COLOR_ARRAY_SIZE_EXT           0x8081
+#define GL_COLOR_ARRAY_TYPE_EXT           0x8082
+#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083
+#define GL_COLOR_ARRAY_COUNT_EXT          0x8084
+#define GL_INDEX_ARRAY_TYPE_EXT           0x8085
+#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086
+#define GL_INDEX_ARRAY_COUNT_EXT          0x8087
+#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A
+#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B
+#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C
+#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D
+#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E
+#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F
+#define GL_COLOR_ARRAY_POINTER_EXT        0x8090
+#define GL_INDEX_ARRAY_POINTER_EXT        0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_GENERATE_MIPMAP_SGIS           0x8191
+#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170
+#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171
+#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172
+#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173
+#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174
+#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175
+#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176
+#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177
+#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178
+#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D
+#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E
+#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_TEXTURE_COMPARE_SGIX           0x819A
+#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B
+#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C
+#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_CLAMP_TO_EDGE_SGIS             0x812F
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_CLAMP_TO_BORDER_SGIS           0x812D
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_FUNC_ADD_EXT                   0x8006
+#define GL_MIN_EXT                        0x8007
+#define GL_MAX_EXT                        0x8008
+#define GL_BLEND_EQUATION_EXT             0x8009
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_FUNC_SUBTRACT_EXT              0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_INTERLACE_SGIX                 0x8094
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E
+#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F
+#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140
+#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141
+#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142
+#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143
+#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144
+#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145
+#endif
+
+#ifndef GL_SGIS_texture_select
+#define GL_DUAL_ALPHA4_SGIS               0x8110
+#define GL_DUAL_ALPHA8_SGIS               0x8111
+#define GL_DUAL_ALPHA12_SGIS              0x8112
+#define GL_DUAL_ALPHA16_SGIS              0x8113
+#define GL_DUAL_LUMINANCE4_SGIS           0x8114
+#define GL_DUAL_LUMINANCE8_SGIS           0x8115
+#define GL_DUAL_LUMINANCE12_SGIS          0x8116
+#define GL_DUAL_LUMINANCE16_SGIS          0x8117
+#define GL_DUAL_INTENSITY4_SGIS           0x8118
+#define GL_DUAL_INTENSITY8_SGIS           0x8119
+#define GL_DUAL_INTENSITY12_SGIS          0x811A
+#define GL_DUAL_INTENSITY16_SGIS          0x811B
+#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C
+#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D
+#define GL_QUAD_ALPHA4_SGIS               0x811E
+#define GL_QUAD_ALPHA8_SGIS               0x811F
+#define GL_QUAD_LUMINANCE4_SGIS           0x8120
+#define GL_QUAD_LUMINANCE8_SGIS           0x8121
+#define GL_QUAD_INTENSITY4_SGIS           0x8122
+#define GL_QUAD_INTENSITY8_SGIS           0x8123
+#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124
+#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SPRITE_SGIX                    0x8148
+#define GL_SPRITE_MODE_SGIX               0x8149
+#define GL_SPRITE_AXIS_SGIX               0x814A
+#define GL_SPRITE_TRANSLATION_SGIX        0x814B
+#define GL_SPRITE_AXIAL_SGIX              0x814C
+#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D
+#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_POINT_SIZE_MIN_EXT             0x8126
+#define GL_POINT_SIZE_MAX_EXT             0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128
+#define GL_DISTANCE_ATTENUATION_EXT       0x8129
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_POINT_SIZE_MIN_SGIS            0x8126
+#define GL_POINT_SIZE_MAX_SGIS            0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128
+#define GL_DISTANCE_ATTENUATION_SGIS      0x8129
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180
+#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179
+#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A
+#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B
+#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_FRAMEZOOM_SGIX                 0x818B
+#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C
+#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#endif
+
+#ifndef GL_FfdMaskSGIX
+#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001
+#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194
+#define GL_TEXTURE_DEFORMATION_SGIX       0x8195
+#define GL_DEFORMATIONS_MASK_SGIX         0x8196
+#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_REFERENCE_PLANE_SGIX           0x817D
+#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_DEPTH_COMPONENT16_SGIX         0x81A5
+#define GL_DEPTH_COMPONENT24_SGIX         0x81A6
+#define GL_DEPTH_COMPONENT32_SGIX         0x81A7
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_FOG_FUNC_SGIS                  0x812A
+#define GL_FOG_FUNC_POINTS_SGIS           0x812B
+#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_FOG_OFFSET_SGIX                0x8198
+#define GL_FOG_OFFSET_VALUE_SGIX          0x8199
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_IMAGE_SCALE_X_HP               0x8155
+#define GL_IMAGE_SCALE_Y_HP               0x8156
+#define GL_IMAGE_TRANSLATE_X_HP           0x8157
+#define GL_IMAGE_TRANSLATE_Y_HP           0x8158
+#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159
+#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A
+#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B
+#define GL_IMAGE_MAG_FILTER_HP            0x815C
+#define GL_IMAGE_MIN_FILTER_HP            0x815D
+#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E
+#define GL_CUBIC_HP                       0x815F
+#define GL_AVERAGE_HP                     0x8160
+#define GL_IMAGE_TRANSFORM_2D_HP          0x8161
+#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162
+#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_IGNORE_BORDER_HP               0x8150
+#define GL_CONSTANT_BORDER_HP             0x8151
+#define GL_REPLICATE_BORDER_HP            0x8153
+#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154
+#endif
+
+#ifndef GL_INGR_palette_buffer
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE
+#endif
+
+#ifndef GL_EXT_color_subtable
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_VERTEX_DATA_HINT_PGI           0x1A22A
+#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B
+#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C
+#define GL_MAX_VERTEX_HINT_PGI            0x1A22D
+#define GL_COLOR3_BIT_PGI                 0x00010000
+#define GL_COLOR4_BIT_PGI                 0x00020000
+#define GL_EDGEFLAG_BIT_PGI               0x00040000
+#define GL_INDEX_BIT_PGI                  0x00080000
+#define GL_MAT_AMBIENT_BIT_PGI            0x00100000
+#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000
+#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000
+#define GL_MAT_EMISSION_BIT_PGI           0x00800000
+#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000
+#define GL_MAT_SHININESS_BIT_PGI          0x02000000
+#define GL_MAT_SPECULAR_BIT_PGI           0x04000000
+#define GL_NORMAL_BIT_PGI                 0x08000000
+#define GL_TEXCOORD1_BIT_PGI              0x10000000
+#define GL_TEXCOORD2_BIT_PGI              0x20000000
+#define GL_TEXCOORD3_BIT_PGI              0x40000000
+#define GL_TEXCOORD4_BIT_PGI              0x80000000
+#define GL_VERTEX23_BIT_PGI               0x00000004
+#define GL_VERTEX4_BIT_PGI                0x00000008
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8
+#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD
+#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE
+#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202
+#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203
+#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204
+#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C
+#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D
+#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E
+#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F
+#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210
+#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211
+#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216
+#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217
+#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218
+#define GL_FULL_STIPPLE_HINT_PGI          0x1A219
+#define GL_CLIP_NEAR_HINT_PGI             0x1A220
+#define GL_CLIP_FAR_HINT_PGI              0x1A221
+#define GL_WIDE_LINE_HINT_PGI             0x1A222
+#define GL_BACK_NORMALS_HINT_PGI          0x1A223
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_COLOR_INDEX1_EXT               0x80E2
+#define GL_COLOR_INDEX2_EXT               0x80E3
+#define GL_COLOR_INDEX4_EXT               0x80E4
+#define GL_COLOR_INDEX8_EXT               0x80E5
+#define GL_COLOR_INDEX12_EXT              0x80E6
+#define GL_COLOR_INDEX16_EXT              0x80E7
+#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_LIST_PRIORITY_SGIX             0x8182
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_IR_INSTRUMENT1_SGIX            0x817F
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E
+#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F
+#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SHADOW_AMBIENT_SGIX            0x80BF
+#endif
+
+#ifndef GL_EXT_index_texture
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_INDEX_MATERIAL_EXT             0x81B8
+#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9
+#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_INDEX_TEST_EXT                 0x81B5
+#define GL_INDEX_TEST_FUNC_EXT            0x81B6
+#define GL_INDEX_TEST_REF_EXT             0x81B7
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_IUI_V2F_EXT                    0x81AD
+#define GL_IUI_V3F_EXT                    0x81AE
+#define GL_IUI_N3F_V2F_EXT                0x81AF
+#define GL_IUI_N3F_V3F_EXT                0x81B0
+#define GL_T2F_IUI_V2F_EXT                0x81B1
+#define GL_T2F_IUI_V3F_EXT                0x81B2
+#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3
+#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8
+#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_CULL_VERTEX_EXT                0x81AA
+#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB
+#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_YCRCB_422_SGIX                 0x81BB
+#define GL_YCRCB_444_SGIX                 0x81BC
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_FRAGMENT_LIGHTING_SGIX         0x8400
+#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401
+#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402
+#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403
+#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404
+#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405
+#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406
+#define GL_LIGHT_ENV_MODE_SGIX            0x8407
+#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408
+#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409
+#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A
+#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B
+#define GL_FRAGMENT_LIGHT0_SGIX           0x840C
+#define GL_FRAGMENT_LIGHT1_SGIX           0x840D
+#define GL_FRAGMENT_LIGHT2_SGIX           0x840E
+#define GL_FRAGMENT_LIGHT3_SGIX           0x840F
+#define GL_FRAGMENT_LIGHT4_SGIX           0x8410
+#define GL_FRAGMENT_LIGHT5_SGIX           0x8411
+#define GL_FRAGMENT_LIGHT6_SGIX           0x8412
+#define GL_FRAGMENT_LIGHT7_SGIX           0x8413
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167
+#define GL_TEXTURE_POST_SPECULAR_HP       0x8168
+#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8
+#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_PHONG_WIN                      0x80EA
+#define GL_PHONG_HINT_WIN                 0x80EB
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_FRAGMENT_MATERIAL_EXT          0x8349
+#define GL_FRAGMENT_NORMAL_EXT            0x834A
+#define GL_FRAGMENT_COLOR_EXT             0x834C
+#define GL_ATTENUATION_EXT                0x834D
+#define GL_SHADOW_ATTENUATION_EXT         0x834E
+#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F
+#define GL_TEXTURE_LIGHT_EXT              0x8350
+#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351
+#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352
+/* reuse GL_FRAGMENT_DEPTH_EXT */
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_ALPHA_MIN_SGIX                 0x8320
+#define GL_ALPHA_MAX_SGIX                 0x8321
+#endif
+
+#ifndef GL_SGIX_impact_pixel_texture
+#define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX   0x8184
+#define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX     0x8185
+#define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX     0x8186
+#define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187
+#define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188
+#define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX    0x8189
+#define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX    0x818A
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_BGR_EXT                        0x80E0
+#define GL_BGRA_EXT                       0x80E1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_ASYNC_MARKER_SGIX              0x8329
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C
+#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D
+#define GL_ASYNC_READ_PIXELS_SGIX         0x835E
+#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F
+#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360
+#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_ASYNC_HISTOGRAM_SGIX           0x832C
+#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D
+#endif
+
+#ifndef GL_INTEL_texture_scissor
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_PARALLEL_ARRAYS_INTEL          0x83F4
+#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5
+#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6
+#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7
+#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_OCCLUSION_TEST_HP              0x8165
+#define GL_OCCLUSION_TEST_RESULT_HP       0x8166
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330
+#define GL_PIXEL_MAG_FILTER_EXT           0x8331
+#define GL_PIXEL_MIN_FILTER_EXT           0x8332
+#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333
+#define GL_CUBIC_EXT                      0x8334
+#define GL_AVERAGE_EXT                    0x8335
+#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336
+#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337
+#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8
+#define GL_SINGLE_COLOR_EXT               0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_COLOR_SUM_EXT                  0x8458
+#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459
+#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A
+#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B
+#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C
+#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D
+#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_PERTURB_EXT                    0x85AE
+#define GL_TEXTURE_NORMAL_EXT             0x85AF
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450
+#define GL_FOG_COORDINATE_EXT             0x8451
+#define GL_FRAGMENT_DEPTH_EXT             0x8452
+#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453
+#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454
+#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
+#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
+#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_SCREEN_COORDINATES_REND        0x8490
+#define GL_INVERTED_SCREEN_W_REND         0x8491
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_TANGENT_ARRAY_EXT              0x8439
+#define GL_BINORMAL_ARRAY_EXT             0x843A
+#define GL_CURRENT_TANGENT_EXT            0x843B
+#define GL_CURRENT_BINORMAL_EXT           0x843C
+#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E
+#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F
+#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440
+#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441
+#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442
+#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443
+#define GL_MAP1_TANGENT_EXT               0x8444
+#define GL_MAP2_TANGENT_EXT               0x8445
+#define GL_MAP1_BINORMAL_EXT              0x8446
+#define GL_MAP2_BINORMAL_EXT              0x8447
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_COMBINE_EXT                    0x8570
+#define GL_COMBINE_RGB_EXT                0x8571
+#define GL_COMBINE_ALPHA_EXT              0x8572
+#define GL_RGB_SCALE_EXT                  0x8573
+#define GL_ADD_SIGNED_EXT                 0x8574
+#define GL_INTERPOLATE_EXT                0x8575
+#define GL_CONSTANT_EXT                   0x8576
+#define GL_PRIMARY_COLOR_EXT              0x8577
+#define GL_PREVIOUS_EXT                   0x8578
+#define GL_SOURCE0_RGB_EXT                0x8580
+#define GL_SOURCE1_RGB_EXT                0x8581
+#define GL_SOURCE2_RGB_EXT                0x8582
+#define GL_SOURCE0_ALPHA_EXT              0x8588
+#define GL_SOURCE1_ALPHA_EXT              0x8589
+#define GL_SOURCE2_ALPHA_EXT              0x858A
+#define GL_OPERAND0_RGB_EXT               0x8590
+#define GL_OPERAND1_RGB_EXT               0x8591
+#define GL_OPERAND2_RGB_EXT               0x8592
+#define GL_OPERAND0_ALPHA_EXT             0x8598
+#define GL_OPERAND1_ALPHA_EXT             0x8599
+#define GL_OPERAND2_ALPHA_EXT             0x859A
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_TRANSFORM_HINT_APPLE           0x85B1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_FOG_SCALE_SGIX                 0x81FC
+#define GL_FOG_SCALE_VALUE_SGIX           0x81FD
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5
+#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_GLOBAL_ALPHA_SUN               0x81D9
+#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_RESTART_SUN                    0x0001
+#define GL_REPLACE_MIDDLE_SUN             0x0002
+#define GL_REPLACE_OLDEST_SUN             0x0003
+#define GL_TRIANGLE_LIST_SUN              0x81D7
+#define GL_REPLACEMENT_CODE_SUN           0x81D8
+#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0
+#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1
+#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2
+#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3
+#define GL_R1UI_V3F_SUN                   0x85C4
+#define GL_R1UI_C4UB_V3F_SUN              0x85C5
+#define GL_R1UI_C3F_V3F_SUN               0x85C6
+#define GL_R1UI_N3F_V3F_SUN               0x85C7
+#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8
+#define GL_R1UI_T2F_V3F_SUN               0x85C9
+#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA
+#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB
+#endif
+
+#ifndef GL_SUN_vertex
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_BLEND_DST_RGB_EXT              0x80C8
+#define GL_BLEND_SRC_RGB_EXT              0x80C9
+#define GL_BLEND_DST_ALPHA_EXT            0x80CA
+#define GL_BLEND_SRC_ALPHA_EXT            0x80CB
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_RED_MIN_CLAMP_INGR             0x8560
+#define GL_GREEN_MIN_CLAMP_INGR           0x8561
+#define GL_BLUE_MIN_CLAMP_INGR            0x8562
+#define GL_ALPHA_MIN_CLAMP_INGR           0x8563
+#define GL_RED_MAX_CLAMP_INGR             0x8564
+#define GL_GREEN_MAX_CLAMP_INGR           0x8565
+#define GL_BLUE_MAX_CLAMP_INGR            0x8566
+#define GL_ALPHA_MAX_CLAMP_INGR           0x8567
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INTERLACE_READ_INGR            0x8568
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_INCR_WRAP_EXT                  0x8507
+#define GL_DECR_WRAP_EXT                  0x8508
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_422_EXT                        0x80CC
+#define GL_422_REV_EXT                    0x80CD
+#define GL_422_AVERAGE_EXT                0x80CE
+#define GL_422_REV_AVERAGE_EXT            0x80CF
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NORMAL_MAP_NV                  0x8511
+#define GL_REFLECTION_MAP_NV              0x8512
+#endif
+
+#ifndef GL_EXT_texture_cube_map
+#define GL_NORMAL_MAP_EXT                 0x8511
+#define GL_REFLECTION_MAP_EXT             0x8512
+#define GL_TEXTURE_CUBE_MAP_EXT           0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_WRAP_BORDER_SUN                0x81D4
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT           0x8501
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_MODELVIEW0_STACK_DEPTH_EXT     GL_MODELVIEW_STACK_DEPTH
+#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502
+#define GL_MODELVIEW0_MATRIX_EXT          GL_MODELVIEW_MATRIX
+#define GL_MODELVIEW1_MATRIX_EXT          0x8506
+#define GL_VERTEX_WEIGHTING_EXT           0x8509
+#define GL_MODELVIEW0_EXT                 GL_MODELVIEW
+#define GL_MODELVIEW1_EXT                 0x850A
+#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B
+#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C
+#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D
+#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E
+#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
+#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_MAX_SHININESS_NV               0x8504
+#define GL_MAX_SPOT_EXPONENT_NV           0x8505
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_NV          0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E
+#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F
+#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520
+#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_REGISTER_COMBINERS_NV          0x8522
+#define GL_VARIABLE_A_NV                  0x8523
+#define GL_VARIABLE_B_NV                  0x8524
+#define GL_VARIABLE_C_NV                  0x8525
+#define GL_VARIABLE_D_NV                  0x8526
+#define GL_VARIABLE_E_NV                  0x8527
+#define GL_VARIABLE_F_NV                  0x8528
+#define GL_VARIABLE_G_NV                  0x8529
+#define GL_CONSTANT_COLOR0_NV             0x852A
+#define GL_CONSTANT_COLOR1_NV             0x852B
+#define GL_PRIMARY_COLOR_NV               0x852C
+#define GL_SECONDARY_COLOR_NV             0x852D
+#define GL_SPARE0_NV                      0x852E
+#define GL_SPARE1_NV                      0x852F
+#define GL_DISCARD_NV                     0x8530
+#define GL_E_TIMES_F_NV                   0x8531
+#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532
+#define GL_UNSIGNED_IDENTITY_NV           0x8536
+#define GL_UNSIGNED_INVERT_NV             0x8537
+#define GL_EXPAND_NORMAL_NV               0x8538
+#define GL_EXPAND_NEGATE_NV               0x8539
+#define GL_HALF_BIAS_NORMAL_NV            0x853A
+#define GL_HALF_BIAS_NEGATE_NV            0x853B
+#define GL_SIGNED_IDENTITY_NV             0x853C
+#define GL_SIGNED_NEGATE_NV               0x853D
+#define GL_SCALE_BY_TWO_NV                0x853E
+#define GL_SCALE_BY_FOUR_NV               0x853F
+#define GL_SCALE_BY_ONE_HALF_NV           0x8540
+#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541
+#define GL_COMBINER_INPUT_NV              0x8542
+#define GL_COMBINER_MAPPING_NV            0x8543
+#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544
+#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545
+#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546
+#define GL_COMBINER_MUX_SUM_NV            0x8547
+#define GL_COMBINER_SCALE_NV              0x8548
+#define GL_COMBINER_BIAS_NV               0x8549
+#define GL_COMBINER_AB_OUTPUT_NV          0x854A
+#define GL_COMBINER_CD_OUTPUT_NV          0x854B
+#define GL_COMBINER_SUM_OUTPUT_NV         0x854C
+#define GL_MAX_GENERAL_COMBINERS_NV       0x854D
+#define GL_NUM_GENERAL_COMBINERS_NV       0x854E
+#define GL_COLOR_SUM_CLAMP_NV             0x854F
+#define GL_COMBINER0_NV                   0x8550
+#define GL_COMBINER1_NV                   0x8551
+#define GL_COMBINER2_NV                   0x8552
+#define GL_COMBINER3_NV                   0x8553
+#define GL_COMBINER4_NV                   0x8554
+#define GL_COMBINER5_NV                   0x8555
+#define GL_COMBINER6_NV                   0x8556
+#define GL_COMBINER7_NV                   0x8557
+/* reuse GL_TEXTURE0_ARB */
+/* reuse GL_TEXTURE1_ARB */
+/* reuse GL_ZERO */
+/* reuse GL_NONE */
+/* reuse GL_FOG */
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_FOG_DISTANCE_MODE_NV           0x855A
+#define GL_EYE_RADIAL_NV                  0x855B
+#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C
+/* reuse GL_EYE_PLANE */
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_EMBOSS_LIGHT_NV                0x855D
+#define GL_EMBOSS_CONSTANT_NV             0x855E
+#define GL_EMBOSS_MAP_NV                  0x855F
+#endif
+
+#ifndef GL_NV_blend_square
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_COMBINE4_NV                    0x8503
+#define GL_SOURCE3_RGB_NV                 0x8583
+#define GL_SOURCE3_ALPHA_NV               0x858B
+#define GL_OPERAND3_RGB_NV                0x8593
+#define GL_OPERAND3_ALPHA_NV              0x859B
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#endif
+
+#ifndef GL_MESA_window_pos
+#endif
+
+#ifndef GL_EXT_texture_compression_s3tc
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_CULL_VERTEX_IBM                103050
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_VERTEX_ARRAY_LIST_IBM          103070
+#define GL_NORMAL_ARRAY_LIST_IBM          103071
+#define GL_COLOR_ARRAY_LIST_IBM           103072
+#define GL_INDEX_ARRAY_LIST_IBM           103073
+#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074
+#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075
+#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076
+#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077
+#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080
+#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081
+#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082
+#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083
+#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084
+#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085
+#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
+#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0
+#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1
+#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2
+#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3
+#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_YCRCB_SGIX                     0x8318
+#define GL_YCRCBA_SGIX                    0x8319
+#endif
+
+#ifndef GL_SGI_depth_pass_instrument
+#define GL_DEPTH_PASS_INSTRUMENT_SGIX     0x8310
+#define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311
+#define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0
+#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_MULTISAMPLE_3DFX               0x86B2
+#define GL_SAMPLE_BUFFERS_3DFX            0x86B3
+#define GL_SAMPLES_3DFX                   0x86B4
+#define GL_MULTISAMPLE_BIT_3DFX           0x20000000
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_MULTISAMPLE_EXT                0x809D
+#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F
+#define GL_SAMPLE_MASK_EXT                0x80A0
+#define GL_1PASS_EXT                      0x80A1
+#define GL_2PASS_0_EXT                    0x80A2
+#define GL_2PASS_1_EXT                    0x80A3
+#define GL_4PASS_0_EXT                    0x80A4
+#define GL_4PASS_1_EXT                    0x80A5
+#define GL_4PASS_2_EXT                    0x80A6
+#define GL_4PASS_3_EXT                    0x80A7
+#define GL_SAMPLE_BUFFERS_EXT             0x80A8
+#define GL_SAMPLES_EXT                    0x80A9
+#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA
+#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB
+#define GL_SAMPLE_PATTERN_EXT             0x80AC
+#define GL_MULTISAMPLE_BIT_EXT            0x20000000
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_VERTEX_PRECLIP_SGIX            0x83EE
+#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_CONVOLUTION_HINT_SGIX          0x8316
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_PACK_RESAMPLE_SGIX             0x842C
+#define GL_UNPACK_RESAMPLE_SGIX           0x842D
+#define GL_RESAMPLE_REPLICATE_SGIX        0x842E
+#define GL_RESAMPLE_ZERO_FILL_SGIX        0x842F
+#define GL_RESAMPLE_DECIMATE_SGIX         0x8430
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0
+#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1
+#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2
+#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3
+#define GL_EYE_POINT_SGIS                 0x81F4
+#define GL_OBJECT_POINT_SGIS              0x81F5
+#define GL_EYE_LINE_SGIS                  0x81F6
+#define GL_OBJECT_LINE_SGIS               0x81F7
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_DOT3_RGB_EXT                   0x8740
+#define GL_DOT3_RGBA_EXT                  0x8741
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_MIRROR_CLAMP_ATI               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743
+#endif
+
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV               0x84F2
+#define GL_FENCE_STATUS_NV                0x84F3
+#define GL_FENCE_CONDITION_NV             0x84F4
+#endif
+
+#ifndef GL_IBM_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_IBM            0x8370
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_EVAL_2D_NV                     0x86C0
+#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1
+#define GL_MAP_TESSELLATION_NV            0x86C2
+#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3
+#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4
+#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5
+#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6
+#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7
+#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8
+#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9
+#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA
+#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB
+#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC
+#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD
+#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE
+#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF
+#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0
+#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1
+#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2
+#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3
+#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4
+#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5
+#define GL_MAX_MAP_TESSELLATION_NV        0x86D6
+#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_DEPTH_STENCIL_NV               0x84F9
+#define GL_UNSIGNED_INT_24_8_NV           0x84FA
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_PER_STAGE_CONSTANTS_NV         0x8535
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_TEXTURE_RECTANGLE_NV           0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C
+#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D
+#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E
+#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9
+#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA
+#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB
+#define GL_DSDT_MAG_INTENSITY_NV          0x86DC
+#define GL_SHADER_CONSISTENT_NV           0x86DD
+#define GL_TEXTURE_SHADER_NV              0x86DE
+#define GL_SHADER_OPERATION_NV            0x86DF
+#define GL_CULL_MODES_NV                  0x86E0
+#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1
+#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2
+#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3
+#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    GL_OFFSET_TEXTURE_MATRIX_NV
+#define GL_OFFSET_TEXTURE_2D_SCALE_NV     GL_OFFSET_TEXTURE_SCALE_NV
+#define GL_OFFSET_TEXTURE_2D_BIAS_NV      GL_OFFSET_TEXTURE_BIAS_NV
+#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4
+#define GL_CONST_EYE_NV                   0x86E5
+#define GL_PASS_THROUGH_NV                0x86E6
+#define GL_CULL_FRAGMENT_NV               0x86E7
+#define GL_OFFSET_TEXTURE_2D_NV           0x86E8
+#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9
+#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA
+#define GL_DOT_PRODUCT_NV                 0x86EC
+#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED
+#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE
+#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0
+#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1
+#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2
+#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3
+#define GL_HILO_NV                        0x86F4
+#define GL_DSDT_NV                        0x86F5
+#define GL_DSDT_MAG_NV                    0x86F6
+#define GL_DSDT_MAG_VIB_NV                0x86F7
+#define GL_HILO16_NV                      0x86F8
+#define GL_SIGNED_HILO_NV                 0x86F9
+#define GL_SIGNED_HILO16_NV               0x86FA
+#define GL_SIGNED_RGBA_NV                 0x86FB
+#define GL_SIGNED_RGBA8_NV                0x86FC
+#define GL_SIGNED_RGB_NV                  0x86FE
+#define GL_SIGNED_RGB8_NV                 0x86FF
+#define GL_SIGNED_LUMINANCE_NV            0x8701
+#define GL_SIGNED_LUMINANCE8_NV           0x8702
+#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703
+#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704
+#define GL_SIGNED_ALPHA_NV                0x8705
+#define GL_SIGNED_ALPHA8_NV               0x8706
+#define GL_SIGNED_INTENSITY_NV            0x8707
+#define GL_SIGNED_INTENSITY8_NV           0x8708
+#define GL_DSDT8_NV                       0x8709
+#define GL_DSDT8_MAG8_NV                  0x870A
+#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B
+#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C
+#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D
+#define GL_HI_SCALE_NV                    0x870E
+#define GL_LO_SCALE_NV                    0x870F
+#define GL_DS_SCALE_NV                    0x8710
+#define GL_DT_SCALE_NV                    0x8711
+#define GL_MAGNITUDE_SCALE_NV             0x8712
+#define GL_VIBRANCE_SCALE_NV              0x8713
+#define GL_HI_BIAS_NV                     0x8714
+#define GL_LO_BIAS_NV                     0x8715
+#define GL_DS_BIAS_NV                     0x8716
+#define GL_DT_BIAS_NV                     0x8717
+#define GL_MAGNITUDE_BIAS_NV              0x8718
+#define GL_VIBRANCE_BIAS_NV               0x8719
+#define GL_TEXTURE_BORDER_VALUES_NV       0x871A
+#define GL_TEXTURE_HI_SIZE_NV             0x871B
+#define GL_TEXTURE_LO_SIZE_NV             0x871C
+#define GL_TEXTURE_DS_SIZE_NV             0x871D
+#define GL_TEXTURE_DT_SIZE_NV             0x871E
+#define GL_TEXTURE_MAG_SIZE_NV            0x871F
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_VERTEX_PROGRAM_NV              0x8620
+#define GL_VERTEX_STATE_PROGRAM_NV        0x8621
+#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623
+#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624
+#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625
+#define GL_CURRENT_ATTRIB_NV              0x8626
+#define GL_PROGRAM_LENGTH_NV              0x8627
+#define GL_PROGRAM_STRING_NV              0x8628
+#define GL_MODELVIEW_PROJECTION_NV        0x8629
+#define GL_IDENTITY_NV                    0x862A
+#define GL_INVERSE_NV                     0x862B
+#define GL_TRANSPOSE_NV                   0x862C
+#define GL_INVERSE_TRANSPOSE_NV           0x862D
+#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E
+#define GL_MAX_TRACK_MATRICES_NV          0x862F
+#define GL_MATRIX0_NV                     0x8630
+#define GL_MATRIX1_NV                     0x8631
+#define GL_MATRIX2_NV                     0x8632
+#define GL_MATRIX3_NV                     0x8633
+#define GL_MATRIX4_NV                     0x8634
+#define GL_MATRIX5_NV                     0x8635
+#define GL_MATRIX6_NV                     0x8636
+#define GL_MATRIX7_NV                     0x8637
+#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640
+#define GL_CURRENT_MATRIX_NV              0x8641
+#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642
+#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643
+#define GL_PROGRAM_PARAMETER_NV           0x8644
+#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645
+#define GL_PROGRAM_TARGET_NV              0x8646
+#define GL_PROGRAM_RESIDENT_NV            0x8647
+#define GL_TRACK_MATRIX_NV                0x8648
+#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649
+#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A
+#define GL_PROGRAM_ERROR_POSITION_NV      0x864B
+#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650
+#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651
+#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652
+#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653
+#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654
+#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655
+#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656
+#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657
+#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658
+#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659
+#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A
+#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B
+#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C
+#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D
+#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E
+#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F
+#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660
+#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661
+#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662
+#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663
+#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664
+#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665
+#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666
+#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667
+#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668
+#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669
+#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A
+#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B
+#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C
+#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D
+#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E
+#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F
+#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670
+#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671
+#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672
+#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673
+#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674
+#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675
+#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676
+#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677
+#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678
+#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679
+#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A
+#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B
+#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C
+#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D
+#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E
+#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369
+#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A
+#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SCALEBIAS_HINT_SGIX            0x8322
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_INTERLACE_OML                  0x8980
+#define GL_INTERLACE_READ_OML             0x8981
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982
+#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983
+#endif
+
+#ifndef GL_OML_resample
+#define GL_PACK_RESAMPLE_OML              0x8984
+#define GL_UNPACK_RESAMPLE_OML            0x8985
+#define GL_RESAMPLE_REPLICATE_OML         0x8986
+#define GL_RESAMPLE_ZERO_FILL_OML         0x8987
+#define GL_RESAMPLE_AVERAGE_OML           0x8988
+#define GL_RESAMPLE_DECIMATE_OML          0x8989
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E
+#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_BUMP_ROT_MATRIX_ATI            0x8775
+#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776
+#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777
+#define GL_BUMP_TEX_UNITS_ATI             0x8778
+#define GL_DUDV_ATI                       0x8779
+#define GL_DU8DV8_ATI                     0x877A
+#define GL_BUMP_ENVMAP_ATI                0x877B
+#define GL_BUMP_TARGET_ATI                0x877C
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_FRAGMENT_SHADER_ATI            0x8920
+#define GL_REG_0_ATI                      0x8921
+#define GL_REG_1_ATI                      0x8922
+#define GL_REG_2_ATI                      0x8923
+#define GL_REG_3_ATI                      0x8924
+#define GL_REG_4_ATI                      0x8925
+#define GL_REG_5_ATI                      0x8926
+#define GL_REG_6_ATI                      0x8927
+#define GL_REG_7_ATI                      0x8928
+#define GL_REG_8_ATI                      0x8929
+#define GL_REG_9_ATI                      0x892A
+#define GL_REG_10_ATI                     0x892B
+#define GL_REG_11_ATI                     0x892C
+#define GL_REG_12_ATI                     0x892D
+#define GL_REG_13_ATI                     0x892E
+#define GL_REG_14_ATI                     0x892F
+#define GL_REG_15_ATI                     0x8930
+#define GL_REG_16_ATI                     0x8931
+#define GL_REG_17_ATI                     0x8932
+#define GL_REG_18_ATI                     0x8933
+#define GL_REG_19_ATI                     0x8934
+#define GL_REG_20_ATI                     0x8935
+#define GL_REG_21_ATI                     0x8936
+#define GL_REG_22_ATI                     0x8937
+#define GL_REG_23_ATI                     0x8938
+#define GL_REG_24_ATI                     0x8939
+#define GL_REG_25_ATI                     0x893A
+#define GL_REG_26_ATI                     0x893B
+#define GL_REG_27_ATI                     0x893C
+#define GL_REG_28_ATI                     0x893D
+#define GL_REG_29_ATI                     0x893E
+#define GL_REG_30_ATI                     0x893F
+#define GL_REG_31_ATI                     0x8940
+#define GL_CON_0_ATI                      0x8941
+#define GL_CON_1_ATI                      0x8942
+#define GL_CON_2_ATI                      0x8943
+#define GL_CON_3_ATI                      0x8944
+#define GL_CON_4_ATI                      0x8945
+#define GL_CON_5_ATI                      0x8946
+#define GL_CON_6_ATI                      0x8947
+#define GL_CON_7_ATI                      0x8948
+#define GL_CON_8_ATI                      0x8949
+#define GL_CON_9_ATI                      0x894A
+#define GL_CON_10_ATI                     0x894B
+#define GL_CON_11_ATI                     0x894C
+#define GL_CON_12_ATI                     0x894D
+#define GL_CON_13_ATI                     0x894E
+#define GL_CON_14_ATI                     0x894F
+#define GL_CON_15_ATI                     0x8950
+#define GL_CON_16_ATI                     0x8951
+#define GL_CON_17_ATI                     0x8952
+#define GL_CON_18_ATI                     0x8953
+#define GL_CON_19_ATI                     0x8954
+#define GL_CON_20_ATI                     0x8955
+#define GL_CON_21_ATI                     0x8956
+#define GL_CON_22_ATI                     0x8957
+#define GL_CON_23_ATI                     0x8958
+#define GL_CON_24_ATI                     0x8959
+#define GL_CON_25_ATI                     0x895A
+#define GL_CON_26_ATI                     0x895B
+#define GL_CON_27_ATI                     0x895C
+#define GL_CON_28_ATI                     0x895D
+#define GL_CON_29_ATI                     0x895E
+#define GL_CON_30_ATI                     0x895F
+#define GL_CON_31_ATI                     0x8960
+#define GL_MOV_ATI                        0x8961
+#define GL_ADD_ATI                        0x8963
+#define GL_MUL_ATI                        0x8964
+#define GL_SUB_ATI                        0x8965
+#define GL_DOT3_ATI                       0x8966
+#define GL_DOT4_ATI                       0x8967
+#define GL_MAD_ATI                        0x8968
+#define GL_LERP_ATI                       0x8969
+#define GL_CND_ATI                        0x896A
+#define GL_CND0_ATI                       0x896B
+#define GL_DOT2_ADD_ATI                   0x896C
+#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D
+#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E
+#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F
+#define GL_NUM_PASSES_ATI                 0x8970
+#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971
+#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972
+#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973
+#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974
+#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975
+#define GL_SWIZZLE_STR_ATI                0x8976
+#define GL_SWIZZLE_STQ_ATI                0x8977
+#define GL_SWIZZLE_STR_DR_ATI             0x8978
+#define GL_SWIZZLE_STQ_DQ_ATI             0x8979
+#define GL_SWIZZLE_STRQ_ATI               0x897A
+#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B
+#define GL_RED_BIT_ATI                    0x00000001
+#define GL_GREEN_BIT_ATI                  0x00000002
+#define GL_BLUE_BIT_ATI                   0x00000004
+#define GL_2X_BIT_ATI                     0x00000001
+#define GL_4X_BIT_ATI                     0x00000002
+#define GL_8X_BIT_ATI                     0x00000004
+#define GL_HALF_BIT_ATI                   0x00000008
+#define GL_QUARTER_BIT_ATI                0x00000010
+#define GL_EIGHTH_BIT_ATI                 0x00000020
+#define GL_SATURATE_BIT_ATI               0x00000040
+#define GL_COMP_BIT_ATI                   0x00000002
+#define GL_NEGATE_BIT_ATI                 0x00000004
+#define GL_BIAS_BIT_ATI                   0x00000008
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_PN_TRIANGLES_ATI               0x87F0
+#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1
+#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2
+#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3
+#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4
+#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5
+#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6
+#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7
+#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_STATIC_ATI                     0x8760
+#define GL_DYNAMIC_ATI                    0x8761
+#define GL_PRESERVE_ATI                   0x8762
+#define GL_DISCARD_ATI                    0x8763
+#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764
+#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765
+#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766
+#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_VERTEX_SHADER_EXT              0x8780
+#define GL_VERTEX_SHADER_BINDING_EXT      0x8781
+#define GL_OP_INDEX_EXT                   0x8782
+#define GL_OP_NEGATE_EXT                  0x8783
+#define GL_OP_DOT3_EXT                    0x8784
+#define GL_OP_DOT4_EXT                    0x8785
+#define GL_OP_MUL_EXT                     0x8786
+#define GL_OP_ADD_EXT                     0x8787
+#define GL_OP_MADD_EXT                    0x8788
+#define GL_OP_FRAC_EXT                    0x8789
+#define GL_OP_MAX_EXT                     0x878A
+#define GL_OP_MIN_EXT                     0x878B
+#define GL_OP_SET_GE_EXT                  0x878C
+#define GL_OP_SET_LT_EXT                  0x878D
+#define GL_OP_CLAMP_EXT                   0x878E
+#define GL_OP_FLOOR_EXT                   0x878F
+#define GL_OP_ROUND_EXT                   0x8790
+#define GL_OP_EXP_BASE_2_EXT              0x8791
+#define GL_OP_LOG_BASE_2_EXT              0x8792
+#define GL_OP_POWER_EXT                   0x8793
+#define GL_OP_RECIP_EXT                   0x8794
+#define GL_OP_RECIP_SQRT_EXT              0x8795
+#define GL_OP_SUB_EXT                     0x8796
+#define GL_OP_CROSS_PRODUCT_EXT           0x8797
+#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798
+#define GL_OP_MOV_EXT                     0x8799
+#define GL_OUTPUT_VERTEX_EXT              0x879A
+#define GL_OUTPUT_COLOR0_EXT              0x879B
+#define GL_OUTPUT_COLOR1_EXT              0x879C
+#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D
+#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E
+#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F
+#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0
+#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1
+#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2
+#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3
+#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4
+#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5
+#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6
+#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7
+#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8
+#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9
+#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA
+#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB
+#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC
+#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD
+#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE
+#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF
+#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0
+#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1
+#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2
+#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3
+#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4
+#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5
+#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6
+#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7
+#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8
+#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9
+#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA
+#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB
+#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC
+#define GL_OUTPUT_FOG_EXT                 0x87BD
+#define GL_SCALAR_EXT                     0x87BE
+#define GL_VECTOR_EXT                     0x87BF
+#define GL_MATRIX_EXT                     0x87C0
+#define GL_VARIANT_EXT                    0x87C1
+#define GL_INVARIANT_EXT                  0x87C2
+#define GL_LOCAL_CONSTANT_EXT             0x87C3
+#define GL_LOCAL_EXT                      0x87C4
+#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5
+#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6
+#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7
+#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8
+#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD
+#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE
+#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF
+#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0
+#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1
+#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2
+#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3
+#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4
+#define GL_X_EXT                          0x87D5
+#define GL_Y_EXT                          0x87D6
+#define GL_Z_EXT                          0x87D7
+#define GL_W_EXT                          0x87D8
+#define GL_NEGATIVE_X_EXT                 0x87D9
+#define GL_NEGATIVE_Y_EXT                 0x87DA
+#define GL_NEGATIVE_Z_EXT                 0x87DB
+#define GL_NEGATIVE_W_EXT                 0x87DC
+#define GL_ZERO_EXT                       0x87DD
+#define GL_ONE_EXT                        0x87DE
+#define GL_NEGATIVE_ONE_EXT               0x87DF
+#define GL_NORMALIZED_RANGE_EXT           0x87E0
+#define GL_FULL_RANGE_EXT                 0x87E1
+#define GL_CURRENT_VERTEX_EXT             0x87E2
+#define GL_MVP_MATRIX_EXT                 0x87E3
+#define GL_VARIANT_VALUE_EXT              0x87E4
+#define GL_VARIANT_DATATYPE_EXT           0x87E5
+#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6
+#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7
+#define GL_VARIANT_ARRAY_EXT              0x87E8
+#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9
+#define GL_INVARIANT_VALUE_EXT            0x87EA
+#define GL_INVARIANT_DATATYPE_EXT         0x87EB
+#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC
+#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_MAX_VERTEX_STREAMS_ATI         0x876B
+#define GL_VERTEX_STREAM0_ATI             0x876C
+#define GL_VERTEX_STREAM1_ATI             0x876D
+#define GL_VERTEX_STREAM2_ATI             0x876E
+#define GL_VERTEX_STREAM3_ATI             0x876F
+#define GL_VERTEX_STREAM4_ATI             0x8770
+#define GL_VERTEX_STREAM5_ATI             0x8771
+#define GL_VERTEX_STREAM6_ATI             0x8772
+#define GL_VERTEX_STREAM7_ATI             0x8773
+#define GL_VERTEX_SOURCE_ATI              0x8774
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ELEMENT_ARRAY_ATI              0x8768
+#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769
+#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_QUAD_MESH_SUN                  0x8614
+#define GL_TRIANGLE_MESH_SUN              0x8615
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SLICE_ACCUM_SUN                0x85CC
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_DEPTH_CLAMP_NV                 0x864F
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_PIXEL_COUNTER_BITS_NV          0x8864
+#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865
+#define GL_PIXEL_COUNT_NV                 0x8866
+#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_POINT_SPRITE_NV                0x8861
+#define GL_COORD_REPLACE_NV               0x8862
+#define GL_POINT_SPRITE_R_MODE_NV         0x8863
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850
+#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852
+#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853
+#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854
+#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856
+#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857
+#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858
+#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859
+#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A
+#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B
+#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C
+#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D
+#define GL_HILO8_NV                       0x885E
+#define GL_SIGNED_HILO8_NV                0x885F
+#define GL_FORCE_BLUE_TO_ONE_NV           0x8860
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910
+#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_ELEMENT_ARRAY_APPLE            0x8768
+#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8769
+#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x876A
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_DRAW_PIXELS_APPLE              0x8A0A
+#define GL_FENCE_APPLE                    0x8A0B
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
+#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
+#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
+#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
+#define GL_STORAGE_CACHED_APPLE           0x85BE
+#define GL_STORAGE_SHARED_APPLE           0x85BF
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_YCBCR_422_APPLE                0x85B9
+#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_RGB_S3TC                       0x83A0
+#define GL_RGB4_S3TC                      0x83A1
+#define GL_RGBA_S3TC                      0x83A2
+#define GL_RGBA4_S3TC                     0x83A3
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_ATI           0x8824
+#define GL_DRAW_BUFFER0_ATI               0x8825
+#define GL_DRAW_BUFFER1_ATI               0x8826
+#define GL_DRAW_BUFFER2_ATI               0x8827
+#define GL_DRAW_BUFFER3_ATI               0x8828
+#define GL_DRAW_BUFFER4_ATI               0x8829
+#define GL_DRAW_BUFFER5_ATI               0x882A
+#define GL_DRAW_BUFFER6_ATI               0x882B
+#define GL_DRAW_BUFFER7_ATI               0x882C
+#define GL_DRAW_BUFFER8_ATI               0x882D
+#define GL_DRAW_BUFFER9_ATI               0x882E
+#define GL_DRAW_BUFFER10_ATI              0x882F
+#define GL_DRAW_BUFFER11_ATI              0x8830
+#define GL_DRAW_BUFFER12_ATI              0x8831
+#define GL_DRAW_BUFFER13_ATI              0x8832
+#define GL_DRAW_BUFFER14_ATI              0x8833
+#define GL_DRAW_BUFFER15_ATI              0x8834
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_TYPE_RGBA_FLOAT_ATI            0x8820
+#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_MODULATE_ADD_ATI               0x8744
+#define GL_MODULATE_SIGNED_ADD_ATI        0x8745
+#define GL_MODULATE_SUBTRACT_ATI          0x8746
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_RGBA_FLOAT32_ATI               0x8814
+#define GL_RGB_FLOAT32_ATI                0x8815
+#define GL_ALPHA_FLOAT32_ATI              0x8816
+#define GL_INTENSITY_FLOAT32_ATI          0x8817
+#define GL_LUMINANCE_FLOAT32_ATI          0x8818
+#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819
+#define GL_RGBA_FLOAT16_ATI               0x881A
+#define GL_RGB_FLOAT16_ATI                0x881B
+#define GL_ALPHA_FLOAT16_ATI              0x881C
+#define GL_INTENSITY_FLOAT16_ATI          0x881D
+#define GL_LUMINANCE_FLOAT16_ATI          0x881E
+#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_FLOAT_R_NV                     0x8880
+#define GL_FLOAT_RG_NV                    0x8881
+#define GL_FLOAT_RGB_NV                   0x8882
+#define GL_FLOAT_RGBA_NV                  0x8883
+#define GL_FLOAT_R16_NV                   0x8884
+#define GL_FLOAT_R32_NV                   0x8885
+#define GL_FLOAT_RG16_NV                  0x8886
+#define GL_FLOAT_RG32_NV                  0x8887
+#define GL_FLOAT_RGB16_NV                 0x8888
+#define GL_FLOAT_RGB32_NV                 0x8889
+#define GL_FLOAT_RGBA16_NV                0x888A
+#define GL_FLOAT_RGBA32_NV                0x888B
+#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C
+#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D
+#define GL_FLOAT_RGBA_MODE_NV             0x888E
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868
+#define GL_FRAGMENT_PROGRAM_NV            0x8870
+#define GL_MAX_TEXTURE_COORDS_NV          0x8871
+#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872
+#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873
+#define GL_PROGRAM_ERROR_STRING_NV        0x8874
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_HALF_FLOAT_NV                  0x140B
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878
+#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879
+#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A
+#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B
+#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C
+#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_PRIMITIVE_RESTART_NV           0x8558
+#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F
+#endif
+
+#ifndef GL_NV_vertex_program2
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_STENCIL_BACK_FUNC_ATI          0x8800
+#define GL_STENCIL_BACK_FAIL_ATI          0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890
+#define GL_DEPTH_BOUNDS_EXT               0x8891
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_MIRROR_CLAMP_EXT               0x8742
+#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743
+#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_BLEND_EQUATION_RGB_EXT         GL_BLEND_EQUATION
+#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_PACK_INVERT_MESA               0x8758
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB
+#define GL_YCBCR_MESA                     0x8757
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB
+#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4
+#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5
+#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6
+#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7
+#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+/* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */
+/* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */
+#endif
+
+#ifndef GL_NV_vertex_program3
+/* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
+#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8
+#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6
+#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
+#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
+#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD
+#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF
+#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT         0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF
+#define GL_DEPTH_ATTACHMENT_EXT           0x8D00
+#define GL_STENCIL_ATTACHMENT_EXT         0x8D20
+#define GL_FRAMEBUFFER_EXT                0x8D40
+#define GL_RENDERBUFFER_EXT               0x8D41
+#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42
+#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
+#define GL_STENCIL_INDEX1_EXT             0x8D46
+#define GL_STENCIL_INDEX4_EXT             0x8D47
+#define GL_STENCIL_INDEX8_EXT             0x8D48
+#define GL_STENCIL_INDEX16_EXT            0x8D49
+#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#endif
+
+
+/*************************************************************/
+
+#include <stddef.h>
+#ifndef GL_VERSION_2_0
+/* GL type for program/shader text */
+typedef char GLchar;			/* native character */
+#endif
+
+#ifndef GL_VERSION_1_5
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptr;
+typedef ptrdiff_t GLsizeiptr;
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+/* GL types for handling large vertex buffer objects */
+typedef ptrdiff_t GLintptrARB;
+typedef ptrdiff_t GLsizeiptrARB;
+#endif
+
+#ifndef GL_ARB_shader_objects
+/* GL types for handling shader object handles and program/shader text */
+typedef char GLcharARB;		/* native character */
+typedef unsigned int GLhandleARB;	/* shader object handle */
+#endif
+
+/* GL types for "half" precision (s10e5) float data in host memory */
+#ifndef GL_ARB_half_float_pixel
+typedef unsigned short GLhalfARB;
+#endif
+
+#ifndef GL_NV_half_float
+typedef unsigned short GLhalfNV;
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_VERSION_1_2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColor (GLclampf, GLclampf, GLclampf, GLclampf);
+GLAPI void APIENTRY glBlendEquation (GLenum);
+GLAPI void APIENTRY glDrawRangeElements (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTable (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTable (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTable (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glColorSubTable (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTable (GLenum, GLsizei, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glConvolutionFilter1D (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterf (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfv (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteri (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameteriv (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilter (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilter (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2D (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+GLAPI void APIENTRY glGetHistogram (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmax (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogram (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmax (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogram (GLenum);
+GLAPI void APIENTRY glResetMinmax (GLenum);
+GLAPI void APIENTRY glTexImage3D (GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_VERSION_1_3 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTexture (GLenum);
+GLAPI void APIENTRY glClientActiveTexture (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1d (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1f (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1i (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1s (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2d (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2f (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2i (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2s (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3d (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3f (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3i (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3s (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4d (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dv (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4f (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4i (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4iv (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4s (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4sv (GLenum, const GLshort *);
+GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *);
+GLAPI void APIENTRY glSampleCoverage (GLclampf, GLboolean);
+GLAPI void APIENTRY glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImage (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_VERSION_1_4
+#define GL_VERSION_1_4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glFogCoordf (GLfloat);
+GLAPI void APIENTRY glFogCoordfv (const GLfloat *);
+GLAPI void APIENTRY glFogCoordd (GLdouble);
+GLAPI void APIENTRY glFogCoorddv (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointer (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glMultiDrawArrays (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElements (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+GLAPI void APIENTRY glPointParameterf (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfv (GLenum, const GLfloat *);
+GLAPI void APIENTRY glPointParameteri (GLenum, GLint);
+GLAPI void APIENTRY glPointParameteriv (GLenum, const GLint *);
+GLAPI void APIENTRY glSecondaryColor3b (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3iv (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ub (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3ui (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3us (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointer (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glWindowPos2d (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2f (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2i (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2iv (const GLint *);
+GLAPI void APIENTRY glWindowPos2s (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2sv (const GLshort *);
+GLAPI void APIENTRY glWindowPos3d (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dv (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3f (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fv (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3i (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3iv (const GLint *);
+GLAPI void APIENTRY glWindowPos3s (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3sv (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_VERSION_1_5
+#define GL_VERSION_1_5 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueries (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueries (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQuery (GLuint);
+GLAPI void APIENTRY glBeginQuery (GLenum, GLuint);
+GLAPI void APIENTRY glEndQuery (GLenum);
+GLAPI void APIENTRY glGetQueryiv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuiv (GLuint, GLenum, GLuint *);
+GLAPI void APIENTRY glBindBuffer (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffers (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffers (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBuffer (GLuint);
+GLAPI void APIENTRY glBufferData (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubData (GLenum, GLintptr, GLsizeiptr, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubData (GLenum, GLintptr, GLsizeiptr, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBuffer (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum);
+GLAPI void APIENTRY glGetBufferParameteriv (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointerv (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_VERSION_2_0
+#define GL_VERSION_2_0 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparate (GLenum, GLenum);
+GLAPI void APIENTRY glDrawBuffers (GLsizei, const GLenum *);
+GLAPI void APIENTRY glStencilOpSeparate (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparate (GLenum, GLenum, GLint, GLuint);
+GLAPI void APIENTRY glStencilMaskSeparate (GLenum, GLuint);
+GLAPI void APIENTRY glAttachShader (GLuint, GLuint);
+GLAPI void APIENTRY glBindAttribLocation (GLuint, GLuint, const GLchar *);
+GLAPI void APIENTRY glCompileShader (GLuint);
+GLAPI GLuint APIENTRY glCreateProgram (void);
+GLAPI GLuint APIENTRY glCreateShader (GLenum);
+GLAPI void APIENTRY glDeleteProgram (GLuint);
+GLAPI void APIENTRY glDeleteShader (GLuint);
+GLAPI void APIENTRY glDetachShader (GLuint, GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glEnableVertexAttribArray (GLuint);
+GLAPI void APIENTRY glGetActiveAttrib (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetActiveUniform (GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
+GLAPI void APIENTRY glGetAttachedShaders (GLuint, GLsizei, GLsizei *, GLuint *);
+GLAPI GLint APIENTRY glGetAttribLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetProgramiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetShaderInfoLog (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI void APIENTRY glGetShaderSource (GLuint, GLsizei, GLsizei *, GLchar *);
+GLAPI GLint APIENTRY glGetUniformLocation (GLuint, const GLchar *);
+GLAPI void APIENTRY glGetUniformfv (GLuint, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformiv (GLuint, GLint, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdv (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfv (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribiv (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgram (GLuint);
+GLAPI GLboolean APIENTRY glIsShader (GLuint);
+GLAPI void APIENTRY glLinkProgram (GLuint);
+GLAPI void APIENTRY glShaderSource (GLuint, GLsizei, const GLchar* *, const GLint *);
+GLAPI void APIENTRY glUseProgram (GLuint);
+GLAPI void APIENTRY glUniform1f (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2f (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3f (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4f (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1i (GLint, GLint);
+GLAPI void APIENTRY glUniform2i (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3i (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4i (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fv (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4iv (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fv (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glValidateProgram (GLuint);
+GLAPI void APIENTRY glVertexAttrib1d (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1f (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1s (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2d (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2f (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2s (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3d (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3f (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3s (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4Niv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4Nub (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bv (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4d (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dv (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4f (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fv (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4iv (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4s (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4sv (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubv (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uiv (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usv (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointer (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_multitexture
+#define GL_ARB_multitexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveTextureARB (GLenum);
+GLAPI void APIENTRY glClientActiveTextureARB (GLenum);
+GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum, GLint);
+GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum, GLshort);
+GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum, const GLshort *);
+GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum, const GLdouble *);
+GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum, const GLfloat *);
+GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum, const GLint *);
+GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum, const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+#endif
+
+#ifndef GL_ARB_transpose_matrix
+#define GL_ARB_transpose_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *);
+GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *);
+GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+#endif
+
+#ifndef GL_ARB_multisample
+#define GL_ARB_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleCoverageARB (GLclampf, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert);
+#endif
+
+#ifndef GL_ARB_texture_env_add
+#define GL_ARB_texture_env_add 1
+#endif
+
+#ifndef GL_ARB_texture_cube_map
+#define GL_ARB_texture_cube_map 1
+#endif
+
+#ifndef GL_ARB_texture_compression
+#define GL_ARB_texture_compression 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum, GLint, GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img);
+#endif
+
+#ifndef GL_ARB_texture_border_clamp
+#define GL_ARB_texture_border_clamp 1
+#endif
+
+#ifndef GL_ARB_point_parameters
+#define GL_ARB_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfARB (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvARB (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_ARB_vertex_blend
+#define GL_ARB_vertex_blend 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWeightbvARB (GLint, const GLbyte *);
+GLAPI void APIENTRY glWeightsvARB (GLint, const GLshort *);
+GLAPI void APIENTRY glWeightivARB (GLint, const GLint *);
+GLAPI void APIENTRY glWeightfvARB (GLint, const GLfloat *);
+GLAPI void APIENTRY glWeightdvARB (GLint, const GLdouble *);
+GLAPI void APIENTRY glWeightubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glWeightusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glWeightuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glWeightPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexBlendARB (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
+#endif
+
+#ifndef GL_ARB_matrix_palette
+#define GL_ARB_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint);
+GLAPI void APIENTRY glMatrixIndexubvARB (GLint, const GLubyte *);
+GLAPI void APIENTRY glMatrixIndexusvARB (GLint, const GLushort *);
+GLAPI void APIENTRY glMatrixIndexuivARB (GLint, const GLuint *);
+GLAPI void APIENTRY glMatrixIndexPointerARB (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_ARB_texture_env_combine
+#define GL_ARB_texture_env_combine 1
+#endif
+
+#ifndef GL_ARB_texture_env_crossbar
+#define GL_ARB_texture_env_crossbar 1
+#endif
+
+#ifndef GL_ARB_texture_env_dot3
+#define GL_ARB_texture_env_dot3 1
+#endif
+
+#ifndef GL_ARB_texture_mirrored_repeat
+#define GL_ARB_texture_mirrored_repeat 1
+#endif
+
+#ifndef GL_ARB_depth_texture
+#define GL_ARB_depth_texture 1
+#endif
+
+#ifndef GL_ARB_shadow
+#define GL_ARB_shadow 1
+#endif
+
+#ifndef GL_ARB_shadow_ambient
+#define GL_ARB_shadow_ambient 1
+#endif
+
+#ifndef GL_ARB_window_pos
+#define GL_ARB_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dARB (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fARB (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iARB (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos2sARB (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svARB (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dARB (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fARB (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivARB (const GLint *);
+GLAPI void APIENTRY glWindowPos3sARB (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svARB (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_ARB_vertex_program
+#define GL_ARB_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttrib1dARB (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fARB (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sARB (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dARB (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fARB (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sARB (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dARB (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fARB (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sARB (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVertexAttrib4dARB (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fARB (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint, const GLint *);
+GLAPI void APIENTRY glVertexAttrib4sARB (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svARB (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint, const GLuint *);
+GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint, const GLushort *);
+GLAPI void APIENTRY glVertexAttribPointerARB (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint);
+GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum, GLuint, GLdouble *);
+GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum, GLuint, GLfloat *);
+GLAPI void APIENTRY glGetProgramivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringARB (GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramARB (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);
+#endif
+
+#ifndef GL_ARB_fragment_program
+#define GL_ARB_fragment_program 1
+/* All ARB_fragment_program entry points are shared with ARB_vertex_program. */
+#endif
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindBufferARB (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteBuffersARB (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenBuffersARB (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsBufferARB (GLuint);
+GLAPI void APIENTRY glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+GLAPI void APIENTRY glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
+GLAPI void APIENTRY glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
+GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum, GLenum);
+GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum);
+GLAPI void APIENTRY glGetBufferParameterivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params);
+#endif
+
+#ifndef GL_ARB_occlusion_query
+#define GL_ARB_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenQueriesARB (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteQueriesARB (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsQueryARB (GLuint);
+GLAPI void APIENTRY glBeginQueryARB (GLenum, GLuint);
+GLAPI void APIENTRY glEndQueryARB (GLenum);
+GLAPI void APIENTRY glGetQueryivARB (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectivARB (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_ARB_shader_objects
+#define GL_ARB_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum);
+GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum);
+GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *);
+GLAPI void APIENTRY glCompileShaderARB (GLhandleARB);
+GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);
+GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB);
+GLAPI void APIENTRY glLinkProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB);
+GLAPI void APIENTRY glValidateProgramARB (GLhandleARB);
+GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat);
+GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform4fARB (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glUniform1iARB (GLint, GLint);
+GLAPI void APIENTRY glUniform2iARB (GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform3iARB (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform4iARB (GLint, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glUniform1fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform2fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform3fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform4fvARB (GLint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glUniform1ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform2ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform3ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *);
+GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *);
+GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
+GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *);
+GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *);
+GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length);
+typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_ARB_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *);
+GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *);
+GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_ARB_fragment_shader 1
+#endif
+
+#ifndef GL_ARB_shading_language_100
+#define GL_ARB_shading_language_100 1
+#endif
+
+#ifndef GL_ARB_texture_non_power_of_two
+#define GL_ARB_texture_non_power_of_two 1
+#endif
+
+#ifndef GL_ARB_point_sprite
+#define GL_ARB_point_sprite 1
+#endif
+
+#ifndef GL_ARB_fragment_program_shadow
+#define GL_ARB_fragment_program_shadow 1
+#endif
+
+#ifndef GL_ARB_draw_buffers
+#define GL_ARB_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersARB (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+#endif
+
+#ifndef GL_ARB_color_buffer_float
+#define GL_ARB_color_buffer_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glClampColorARB (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+#endif
+
+#ifndef GL_ARB_half_float_pixel
+#define GL_ARB_half_float_pixel 1
+#endif
+
+#ifndef GL_ARB_texture_float
+#define GL_ARB_texture_float 1
+#endif
+
+#ifndef GL_ARB_pixel_buffer_object
+#define GL_ARB_pixel_buffer_object 1
+#endif
+
+#ifndef GL_EXT_abgr
+#define GL_EXT_abgr 1
+#endif
+
+#ifndef GL_EXT_blend_color
+#define GL_EXT_blend_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendColorEXT (GLclampf, GLclampf, GLclampf, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+#endif
+
+#ifndef GL_EXT_polygon_offset
+#define GL_EXT_polygon_offset 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);
+#endif
+
+#ifndef GL_EXT_texture
+#define GL_EXT_texture 1
+#endif
+
+#ifndef GL_EXT_texture3D
+#define GL_EXT_texture3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage3DEXT (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGIS_texture_filter4
+#define GL_SGIS_texture_filter4 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum, GLenum, GLsizei, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);
+typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);
+#endif
+
+#ifndef GL_EXT_subtexture
+#define GL_EXT_subtexture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexSubImage1DEXT (GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_EXT_copy_texture
+#define GL_EXT_copy_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
+GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum, GLint, GLint, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_EXT_histogram
+#define GL_EXT_histogram 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetHistogramEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMinmaxEXT (GLenum, GLboolean, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glHistogramEXT (GLenum, GLsizei, GLenum, GLboolean);
+GLAPI void APIENTRY glMinmaxEXT (GLenum, GLenum, GLboolean);
+GLAPI void APIENTRY glResetHistogramEXT (GLenum);
+GLAPI void APIENTRY glResetMinmaxEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_EXT_convolution
+#define GL_EXT_convolution 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum, GLenum, GLint, GLint, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum, GLenum, GLenum, GLvoid *, GLvoid *, GLvoid *);
+GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum, GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+#endif
+
+#ifndef GL_EXT_color_matrix
+#define GL_EXT_color_matrix 1
+#endif
+
+#ifndef GL_SGI_color_table
+#define GL_SGI_color_table 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableSGI (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glColorTableParameterivSGI (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glCopyColorTableSGI (GLenum, GLenum, GLint, GLint, GLsizei);
+GLAPI void APIENTRY glGetColorTableSGI (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_SGIX_pixel_texture
+#define GL_SGIX_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenSGIX (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);
+#endif
+
+#ifndef GL_SGIS_pixel_texture
+#define GL_SGIS_pixel_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum, GLint);
+GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum, GLint *);
+GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_texture4D
+#define GL_SGIS_texture4D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexImage4DSGIS (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels);
+#endif
+
+#ifndef GL_SGI_texture_color_table
+#define GL_SGI_texture_color_table 1
+#endif
+
+#ifndef GL_EXT_cmyka
+#define GL_EXT_cmyka 1
+#endif
+
+#ifndef GL_EXT_texture_object
+#define GL_EXT_texture_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindTextureEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenTexturesEXT (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint);
+GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei, const GLuint *, const GLclampf *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);
+typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);
+typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);
+typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);
+#endif
+
+#ifndef GL_SGIS_detail_texture
+#define GL_SGIS_detail_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_SGIS_sharpen_texture
+#define GL_SGIS_sharpen_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);
+#endif
+
+#ifndef GL_EXT_packed_pixels
+#define GL_EXT_packed_pixels 1
+#endif
+
+#ifndef GL_SGIS_texture_lod
+#define GL_SGIS_texture_lod 1
+#endif
+
+#ifndef GL_SGIS_multisample
+#define GL_SGIS_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskSGIS (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternSGIS (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_EXT_rescale_normal
+#define GL_EXT_rescale_normal 1
+#endif
+
+#ifndef GL_EXT_vertex_array
+#define GL_EXT_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glArrayElementEXT (GLint);
+GLAPI void APIENTRY glColorPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glDrawArraysEXT (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei, GLsizei, const GLboolean *);
+GLAPI void APIENTRY glGetPointervEXT (GLenum, GLvoid* *);
+GLAPI void APIENTRY glIndexPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glNormalPointerEXT (GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glTexCoordPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexPointerEXT (GLint, GLenum, GLsizei, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);
+typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);
+typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params);
+typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_misc_attribute
+#define GL_EXT_misc_attribute 1
+#endif
+
+#ifndef GL_SGIS_generate_mipmap
+#define GL_SGIS_generate_mipmap 1
+#endif
+
+#ifndef GL_SGIX_clipmap
+#define GL_SGIX_clipmap 1
+#endif
+
+#ifndef GL_SGIX_shadow
+#define GL_SGIX_shadow 1
+#endif
+
+#ifndef GL_SGIS_texture_edge_clamp
+#define GL_SGIS_texture_edge_clamp 1
+#endif
+
+#ifndef GL_SGIS_texture_border_clamp
+#define GL_SGIS_texture_border_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_blend_subtract
+#define GL_EXT_blend_subtract 1
+#endif
+
+#ifndef GL_EXT_blend_logic_op
+#define GL_EXT_blend_logic_op 1
+#endif
+
+#ifndef GL_SGIX_interlace
+#define GL_SGIX_interlace 1
+#endif
+
+#ifndef GL_SGIX_pixel_tiles
+#define GL_SGIX_pixel_tiles 1
+#endif
+
+#ifndef GL_SGIX_texture_select
+#define GL_SGIX_texture_select 1
+#endif
+
+#ifndef GL_SGIX_sprite
+#define GL_SGIX_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum, GLint);
+GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_texture_multi_buffer
+#define GL_SGIX_texture_multi_buffer 1
+#endif
+
+#ifndef GL_EXT_point_parameters
+#define GL_EXT_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfEXT (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvEXT (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIS_point_parameters
+#define GL_SGIS_point_parameters 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameterfSGIS (GLenum, GLfloat);
+GLAPI void APIENTRY glPointParameterfvSGIS (GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_instruments
+#define GL_SGIX_instruments 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLint APIENTRY glGetInstrumentsSGIX (void);
+GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei, GLint *);
+GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *);
+GLAPI void APIENTRY glReadInstrumentsSGIX (GLint);
+GLAPI void APIENTRY glStartInstrumentsSGIX (void);
+GLAPI void APIENTRY glStopInstrumentsSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);
+typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);
+typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);
+typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);
+typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);
+#endif
+
+#ifndef GL_SGIX_texture_scale_bias
+#define GL_SGIX_texture_scale_bias 1
+#endif
+
+#ifndef GL_SGIX_framezoom
+#define GL_SGIX_framezoom 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFrameZoomSGIX (GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);
+#endif
+
+#ifndef GL_SGIX_tag_sample_buffer
+#define GL_SGIX_tag_sample_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTagSampleBufferSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_polynomial_ffd
+#define GL_SGIX_polynomial_ffd 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *);
+GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *);
+GLAPI void APIENTRY glDeformSGIX (GLbitfield);
+GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);
+typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);
+typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);
+typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);
+#endif
+
+#ifndef GL_SGIX_reference_plane
+#define GL_SGIX_reference_plane 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);
+#endif
+
+#ifndef GL_SGIX_flush_raster
+#define GL_SGIX_flush_raster 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushRasterSGIX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);
+#endif
+
+#ifndef GL_SGIX_depth_texture
+#define GL_SGIX_depth_texture 1
+#endif
+
+#ifndef GL_SGIS_fog_function
+#define GL_SGIS_fog_function 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogFuncSGIS (GLsizei, const GLfloat *);
+GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);
+typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);
+#endif
+
+#ifndef GL_SGIX_fog_offset
+#define GL_SGIX_fog_offset 1
+#endif
+
+#ifndef GL_HP_image_transform
+#define GL_HP_image_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glImageTransformParameteriHP (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glImageTransformParameterfHP (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glImageTransformParameterivHP (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_HP_convolution_border_modes
+#define GL_HP_convolution_border_modes 1
+#endif
+
+#ifndef GL_SGIX_texture_add_env
+#define GL_SGIX_texture_add_env 1
+#endif
+
+#ifndef GL_EXT_color_subtable
+#define GL_EXT_color_subtable 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorSubTableEXT (GLenum, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum, GLsizei, GLint, GLint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+#endif
+
+#ifndef GL_PGI_vertex_hints
+#define GL_PGI_vertex_hints 1
+#endif
+
+#ifndef GL_PGI_misc_hints
+#define GL_PGI_misc_hints 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glHintPGI (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);
+#endif
+
+#ifndef GL_EXT_paletted_texture
+#define GL_EXT_paletted_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorTableEXT (GLenum, GLenum, GLsizei, GLenum, GLenum, const GLvoid *);
+GLAPI void APIENTRY glGetColorTableEXT (GLenum, GLenum, GLenum, GLvoid *);
+GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_EXT_clip_volume_hint
+#define GL_EXT_clip_volume_hint 1
+#endif
+
+#ifndef GL_SGIX_list_priority
+#define GL_SGIX_list_priority 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetListParameterivSGIX (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glListParameterfSGIX (GLuint, GLenum, GLfloat);
+GLAPI void APIENTRY glListParameterfvSGIX (GLuint, GLenum, const GLfloat *);
+GLAPI void APIENTRY glListParameteriSGIX (GLuint, GLenum, GLint);
+GLAPI void APIENTRY glListParameterivSGIX (GLuint, GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_SGIX_ir_instrument1
+#define GL_SGIX_ir_instrument1 1
+#endif
+
+#ifndef GL_SGIX_calligraphic_fragment
+#define GL_SGIX_calligraphic_fragment 1
+#endif
+
+#ifndef GL_SGIX_texture_lod_bias
+#define GL_SGIX_texture_lod_bias 1
+#endif
+
+#ifndef GL_SGIX_shadow_ambient
+#define GL_SGIX_shadow_ambient 1
+#endif
+
+#ifndef GL_EXT_index_texture
+#define GL_EXT_index_texture 1
+#endif
+
+#ifndef GL_EXT_index_material
+#define GL_EXT_index_material 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_EXT_index_func
+#define GL_EXT_index_func 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIndexFuncEXT (GLenum, GLclampf);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);
+#endif
+
+#ifndef GL_EXT_index_array_formats
+#define GL_EXT_index_array_formats 1
+#endif
+
+#ifndef GL_EXT_compiled_vertex_array
+#define GL_EXT_compiled_vertex_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glLockArraysEXT (GLint, GLsizei);
+GLAPI void APIENTRY glUnlockArraysEXT (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);
+#endif
+
+#ifndef GL_EXT_cull_vertex
+#define GL_EXT_cull_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCullParameterdvEXT (GLenum, GLdouble *);
+GLAPI void APIENTRY glCullParameterfvEXT (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_SGIX_ycrcb
+#define GL_SGIX_ycrcb 1
+#endif
+
+#ifndef GL_SGIX_fragment_lighting
+#define GL_SGIX_fragment_lighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum, GLenum);
+GLAPI void APIENTRY glFragmentLightfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum, GLint);
+GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum, const GLint *);
+GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glLightEnviSGIX (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_IBM_rasterpos_clip
+#define GL_IBM_rasterpos_clip 1
+#endif
+
+#ifndef GL_HP_texture_lighting
+#define GL_HP_texture_lighting 1
+#endif
+
+#ifndef GL_EXT_draw_range_elements
+#define GL_EXT_draw_range_elements 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum, GLuint, GLuint, GLsizei, GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+#endif
+
+#ifndef GL_WIN_phong_shading
+#define GL_WIN_phong_shading 1
+#endif
+
+#ifndef GL_WIN_specular_fog
+#define GL_WIN_specular_fog 1
+#endif
+
+#ifndef GL_EXT_light_texture
+#define GL_EXT_light_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glApplyTextureEXT (GLenum);
+GLAPI void APIENTRY glTextureLightEXT (GLenum);
+GLAPI void APIENTRY glTextureMaterialEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);
+typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);
+typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);
+#endif
+
+#ifndef GL_SGIX_blend_alpha_minmax
+#define GL_SGIX_blend_alpha_minmax 1
+#endif
+
+#ifndef GL_EXT_bgra
+#define GL_EXT_bgra 1
+#endif
+
+#ifndef GL_SGIX_async
+#define GL_SGIX_async 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint);
+GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *);
+GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *);
+GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei);
+GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint, GLsizei);
+GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);
+typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);
+typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);
+typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);
+typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);
+typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);
+#endif
+
+#ifndef GL_SGIX_async_pixel
+#define GL_SGIX_async_pixel 1
+#endif
+
+#ifndef GL_SGIX_async_histogram
+#define GL_SGIX_async_histogram 1
+#endif
+
+#ifndef GL_INTEL_parallel_arrays
+#define GL_INTEL_parallel_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glNormalPointervINTEL (GLenum, const GLvoid* *);
+GLAPI void APIENTRY glColorPointervINTEL (GLint, GLenum, const GLvoid* *);
+GLAPI void APIENTRY glTexCoordPointervINTEL (GLint, GLenum, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_HP_occlusion_test
+#define GL_HP_occlusion_test 1
+#endif
+
+#ifndef GL_EXT_pixel_transform
+#define GL_EXT_pixel_transform 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum, GLenum, GLint);
+GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum, GLenum, GLfloat);
+GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum, GLenum, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);
+#endif
+
+#ifndef GL_EXT_pixel_transform_color_table
+#define GL_EXT_pixel_transform_color_table 1
+#endif
+
+#ifndef GL_EXT_shared_texture_palette
+#define GL_EXT_shared_texture_palette 1
+#endif
+
+#ifndef GL_EXT_separate_specular_color
+#define GL_EXT_separate_specular_color 1
+#endif
+
+#ifndef GL_EXT_secondary_color
+#define GL_EXT_secondary_color 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glSecondaryColor3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *);
+GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *);
+GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *);
+GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *);
+GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort, GLushort, GLushort);
+GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *);
+GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_perturb_normal
+#define GL_EXT_texture_perturb_normal 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureNormalEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+#ifndef GL_EXT_fog_coord
+#define GL_EXT_fog_coord 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFogCoordfEXT (GLfloat);
+GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *);
+GLAPI void APIENTRY glFogCoorddEXT (GLdouble);
+GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *);
+GLAPI void APIENTRY glFogCoordPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
+typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
+typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_REND_screen_coordinates
+#define GL_REND_screen_coordinates 1
+#endif
+
+#ifndef GL_EXT_coordinate_frame
+#define GL_EXT_coordinate_frame 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTangent3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glTangent3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glTangent3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glTangent3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glTangent3ivEXT (const GLint *);
+GLAPI void APIENTRY glTangent3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glTangent3svEXT (const GLshort *);
+GLAPI void APIENTRY glBinormal3bEXT (GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *);
+GLAPI void APIENTRY glBinormal3dEXT (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *);
+GLAPI void APIENTRY glBinormal3fEXT (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *);
+GLAPI void APIENTRY glBinormal3iEXT (GLint, GLint, GLint);
+GLAPI void APIENTRY glBinormal3ivEXT (const GLint *);
+GLAPI void APIENTRY glBinormal3sEXT (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glBinormal3svEXT (const GLshort *);
+GLAPI void APIENTRY glTangentPointerEXT (GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glBinormalPointerEXT (GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);
+typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);
+typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);
+typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);
+typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);
+typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);
+typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);
+typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);
+typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);
+typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);
+typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);
+typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_EXT_texture_env_combine
+#define GL_EXT_texture_env_combine 1
+#endif
+
+#ifndef GL_APPLE_specular_vector
+#define GL_APPLE_specular_vector 1
+#endif
+
+#ifndef GL_APPLE_transform_hint
+#define GL_APPLE_transform_hint 1
+#endif
+
+#ifndef GL_SGIX_fog_scale
+#define GL_SGIX_fog_scale 1
+#endif
+
+#ifndef GL_SUNX_constant_data
+#define GL_SUNX_constant_data 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFinishTextureSUNX (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);
+#endif
+
+#ifndef GL_SUN_global_alpha
+#define GL_SUN_global_alpha 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte);
+GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort);
+GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint);
+GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat);
+GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble);
+GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte);
+GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort);
+GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
+typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);
+#endif
+
+#ifndef GL_SUN_triangle_list
+#define GL_SUN_triangle_list 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint);
+GLAPI void APIENTRY glReplacementCodeusSUN (GLushort);
+GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte);
+GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *);
+GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *);
+GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *);
+GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum, GLsizei, const GLvoid* *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer);
+#endif
+
+#ifndef GL_SUN_vertex
+#define GL_SUN_vertex 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat, GLfloat, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint, GLubyte, GLubyte, GLubyte, GLubyte, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *, const GLfloat *, const GLfloat *, const GLfloat *, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);
+#endif
+
+#ifndef GL_EXT_blend_func_separate
+#define GL_EXT_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_blend_func_separate
+#define GL_INGR_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum, GLenum, GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+#endif
+
+#ifndef GL_INGR_color_clamp
+#define GL_INGR_color_clamp 1
+#endif
+
+#ifndef GL_INGR_interlace_read
+#define GL_INGR_interlace_read 1
+#endif
+
+#ifndef GL_EXT_stencil_wrap
+#define GL_EXT_stencil_wrap 1
+#endif
+
+#ifndef GL_EXT_422_pixels
+#define GL_EXT_422_pixels 1
+#endif
+
+#ifndef GL_NV_texgen_reflection
+#define GL_NV_texgen_reflection 1
+#endif
+
+#ifndef GL_SUN_convolution_border_modes
+#define GL_SUN_convolution_border_modes 1
+#endif
+
+#ifndef GL_EXT_texture_env_add
+#define GL_EXT_texture_env_add 1
+#endif
+
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 1
+#endif
+
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+#ifndef GL_EXT_vertex_weighting
+#define GL_EXT_vertex_weighting 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexWeightfEXT (GLfloat);
+GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *);
+GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei, GLenum, GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_light_max_exponent
+#define GL_NV_light_max_exponent 1
+#endif
+
+#ifndef GL_NV_vertex_array_range
+#define GL_NV_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glFlushVertexArrayRangeNV (void);
+GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer);
+#endif
+
+#ifndef GL_NV_register_combiners
+#define GL_NV_register_combiners 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerParameterfvNV (GLenum, const GLfloat *);
+GLAPI void APIENTRY glCombinerParameterfNV (GLenum, GLfloat);
+GLAPI void APIENTRY glCombinerParameterivNV (GLenum, const GLint *);
+GLAPI void APIENTRY glCombinerParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glCombinerInputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glCombinerOutputNV (GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLenum, GLboolean, GLboolean, GLboolean);
+GLAPI void APIENTRY glFinalCombinerInputNV (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum, GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum, GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum, GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);
+typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_NV_fog_distance
+#define GL_NV_fog_distance 1
+#endif
+
+#ifndef GL_NV_texgen_emboss
+#define GL_NV_texgen_emboss 1
+#endif
+
+#ifndef GL_NV_blend_square
+#define GL_NV_blend_square 1
+#endif
+
+#ifndef GL_NV_texture_env_combine4
+#define GL_NV_texture_env_combine4 1
+#endif
+
+#ifndef GL_MESA_resize_buffers
+#define GL_MESA_resize_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glResizeBuffersMESA (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
+#endif
+
+#ifndef GL_MESA_window_pos
+#define GL_MESA_window_pos 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glWindowPos2dMESA (GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos2fMESA (GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos2iMESA (GLint, GLint);
+GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos2sMESA (GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos3dMESA (GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos3fMESA (GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos3iMESA (GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos3sMESA (GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *);
+GLAPI void APIENTRY glWindowPos4dMESA (GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *);
+GLAPI void APIENTRY glWindowPos4fMESA (GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *);
+GLAPI void APIENTRY glWindowPos4iMESA (GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *);
+GLAPI void APIENTRY glWindowPos4sMESA (GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);
+#endif
+
+#ifndef GL_IBM_cull_vertex
+#define GL_IBM_cull_vertex 1
+#endif
+
+#ifndef GL_IBM_multimode_draw_arrays
+#define GL_IBM_multimode_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *, const GLint *, const GLsizei *, GLsizei, GLint);
+GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *, const GLsizei *, GLenum, const GLvoid* const *, GLsizei, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
+typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride);
+#endif
+
+#ifndef GL_IBM_vertex_array_lists
+#define GL_IBM_vertex_array_lists 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint, const GLboolean* *, GLint);
+GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glIndexPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glNormalPointerListIBM (GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glTexCoordPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+GLAPI void APIENTRY glVertexPointerListIBM (GLint, GLenum, GLint, const GLvoid* *, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride);
+#endif
+
+#ifndef GL_SGIX_subsample
+#define GL_SGIX_subsample 1
+#endif
+
+#ifndef GL_SGIX_ycrcba
+#define GL_SGIX_ycrcba 1
+#endif
+
+#ifndef GL_SGIX_ycrcb_subsample
+#define GL_SGIX_ycrcb_subsample 1
+#endif
+
+#ifndef GL_SGIX_depth_pass_instrument
+#define GL_SGIX_depth_pass_instrument 1
+#endif
+
+#ifndef GL_3DFX_texture_compression_FXT1
+#define GL_3DFX_texture_compression_FXT1 1
+#endif
+
+#ifndef GL_3DFX_multisample
+#define GL_3DFX_multisample 1
+#endif
+
+#ifndef GL_3DFX_tbuffer
+#define GL_3DFX_tbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTbufferMask3DFX (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
+#endif
+
+#ifndef GL_EXT_multisample
+#define GL_EXT_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glSampleMaskEXT (GLclampf, GLboolean);
+GLAPI void APIENTRY glSamplePatternEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);
+typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
+#endif
+
+#ifndef GL_SGIX_vertex_preclip
+#define GL_SGIX_vertex_preclip 1
+#endif
+
+#ifndef GL_SGIX_convolution_accuracy
+#define GL_SGIX_convolution_accuracy 1
+#endif
+
+#ifndef GL_SGIX_resample
+#define GL_SGIX_resample 1
+#endif
+
+#ifndef GL_SGIS_point_line_texgen
+#define GL_SGIS_point_line_texgen 1
+#endif
+
+#ifndef GL_SGIS_texture_color_mask
+#define GL_SGIS_texture_color_mask 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean, GLboolean, GLboolean, GLboolean);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+#endif
+
+#ifndef GL_SGIX_igloo_interface
+#define GL_SGIX_igloo_interface 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params);
+#endif
+
+#ifndef GL_EXT_texture_env_dot3
+#define GL_EXT_texture_env_dot3 1
+#endif
+
+#ifndef GL_ATI_texture_mirror_once
+#define GL_ATI_texture_mirror_once 1
+#endif
+
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GLAPI GLboolean APIENTRY glIsFenceNV (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceNV (GLuint);
+GLAPI void APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFinishFenceNV (GLuint);
+GLAPI void APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+#ifndef GL_NV_evaluators
+#define GL_NV_evaluators 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLint, GLint, GLboolean, const GLvoid *);
+GLAPI void APIENTRY glMapParameterivNV (GLenum, GLenum, const GLint *);
+GLAPI void APIENTRY glMapParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetMapControlPointsNV (GLenum, GLuint, GLenum, GLsizei, GLsizei, GLboolean, GLvoid *);
+GLAPI void APIENTRY glGetMapParameterivNV (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapParameterfvNV (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glEvalMapsNV (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);
+typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
+#endif
+
+#ifndef GL_NV_packed_depth_stencil
+#define GL_NV_packed_depth_stencil 1
+#endif
+
+#ifndef GL_NV_register_combiners2
+#define GL_NV_register_combiners2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum, GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);
+#endif
+
+#ifndef GL_NV_texture_compression_vtc
+#define GL_NV_texture_compression_vtc 1
+#endif
+
+#ifndef GL_NV_texture_rectangle
+#define GL_NV_texture_rectangle 1
+#endif
+
+#ifndef GL_NV_texture_shader
+#define GL_NV_texture_shader 1
+#endif
+
+#ifndef GL_NV_texture_shader2
+#define GL_NV_texture_shader2 1
+#endif
+
+#ifndef GL_NV_vertex_array_range2
+#define GL_NV_vertex_array_range2 1
+#endif
+
+#ifndef GL_NV_vertex_program
+#define GL_NV_vertex_program 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei, const GLuint *, GLboolean *);
+GLAPI void APIENTRY glBindProgramNV (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glExecuteProgramNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glGenProgramsNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum, GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum, GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetProgramivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetProgramStringNV (GLuint, GLenum, GLubyte *);
+GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum, GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint, GLenum, GLdouble *);
+GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint, GLenum, GLvoid* *);
+GLAPI GLboolean APIENTRY glIsProgramNV (GLuint);
+GLAPI void APIENTRY glLoadProgramNV (GLenum, GLuint, GLsizei, const GLubyte *);
+GLAPI void APIENTRY glProgramParameter4dNV (GLenum, GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramParameter4dvNV (GLenum, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameter4fNV (GLenum, GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramParameter4fvNV (GLenum, GLuint, const GLfloat *);
+GLAPI void APIENTRY glProgramParameters4dvNV (GLenum, GLuint, GLuint, const GLdouble *);
+GLAPI void APIENTRY glProgramParameters4fvNV (GLenum, GLuint, GLuint, const GLfloat *);
+GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei, const GLuint *);
+GLAPI void APIENTRY glTrackMatrixNV (GLenum, GLuint, GLenum, GLenum);
+GLAPI void APIENTRY glVertexAttribPointerNV (GLuint, GLint, GLenum, GLsizei, const GLvoid *);
+GLAPI void APIENTRY glVertexAttrib1dNV (GLuint, GLdouble);
+GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib1fNV (GLuint, GLfloat);
+GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib1sNV (GLuint, GLshort);
+GLAPI void APIENTRY glVertexAttrib1svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib2dNV (GLuint, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib2fNV (GLuint, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib2sNV (GLuint, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib2svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib3dNV (GLuint, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib3fNV (GLuint, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib3sNV (GLuint, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib3svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4dNV (GLuint, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVertexAttrib4fNV (GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVertexAttrib4sNV (GLuint, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexAttrib4svNV (GLuint, const GLshort *);
+GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint, GLubyte, GLubyte, GLubyte, GLubyte);
+GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs1svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs2svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs3svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint, GLsizei, const GLdouble *);
+GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint, GLsizei, const GLfloat *);
+GLAPI void APIENTRY glVertexAttribs4svNV (GLuint, GLsizei, const GLshort *);
+GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint, GLsizei, const GLubyte *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);
+typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);
+typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);
+typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer);
+typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLuint count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLuint count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);
+#endif
+
+#ifndef GL_SGIX_texture_coordinate_clamp
+#define GL_SGIX_texture_coordinate_clamp 1
+#endif
+
+#ifndef GL_SGIX_scalebias_hint
+#define GL_SGIX_scalebias_hint 1
+#endif
+
+#ifndef GL_OML_interlace
+#define GL_OML_interlace 1
+#endif
+
+#ifndef GL_OML_subsample
+#define GL_OML_subsample 1
+#endif
+
+#ifndef GL_OML_resample
+#define GL_OML_resample 1
+#endif
+
+#ifndef GL_NV_copy_depth_to_color
+#define GL_NV_copy_depth_to_color 1
+#endif
+
+#ifndef GL_ATI_envmap_bumpmap
+#define GL_ATI_envmap_bumpmap 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glTexBumpParameterivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum, GLint *);
+GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);
+typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);
+typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);
+#endif
+
+#ifndef GL_ATI_fragment_shader
+#define GL_ATI_fragment_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint);
+GLAPI void APIENTRY glBindFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint);
+GLAPI void APIENTRY glBeginFragmentShaderATI (void);
+GLAPI void APIENTRY glEndFragmentShaderATI (void);
+GLAPI void APIENTRY glPassTexCoordATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glSampleMapATI (GLuint, GLuint, GLenum);
+GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint, const GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);
+typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);
+typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);
+typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);
+typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);
+#endif
+
+#ifndef GL_ATI_pn_triangles
+#define GL_ATI_pn_triangles 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPNTrianglesiATI (GLenum, GLint);
+GLAPI void APIENTRY glPNTrianglesfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_vertex_array_object
+#define GL_ATI_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei, const GLvoid *, GLenum);
+GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint, GLuint, GLsizei, const GLvoid *, GLenum);
+GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetObjectBufferivATI (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glFreeObjectBufferATI (GLuint);
+GLAPI void APIENTRY glArrayObjectATI (GLenum, GLint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetArrayObjectivATI (GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glVariantArrayObjectATI (GLuint, GLenum, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);
+typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_EXT_vertex_shader
+#define GL_EXT_vertex_shader 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBeginVertexShaderEXT (void);
+GLAPI void APIENTRY glEndVertexShaderEXT (void);
+GLAPI void APIENTRY glBindVertexShaderEXT (GLuint);
+GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint);
+GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint);
+GLAPI void APIENTRY glShaderOp1EXT (GLenum, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp2EXT (GLenum, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glShaderOp3EXT (GLenum, GLuint, GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glSwizzleEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glWriteMaskEXT (GLuint, GLuint, GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glInsertComponentEXT (GLuint, GLuint, GLuint);
+GLAPI void APIENTRY glExtractComponentEXT (GLuint, GLuint, GLuint);
+GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glSetInvariantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glSetLocalConstantEXT (GLuint, GLenum, const GLvoid *);
+GLAPI void APIENTRY glVariantbvEXT (GLuint, const GLbyte *);
+GLAPI void APIENTRY glVariantsvEXT (GLuint, const GLshort *);
+GLAPI void APIENTRY glVariantivEXT (GLuint, const GLint *);
+GLAPI void APIENTRY glVariantfvEXT (GLuint, const GLfloat *);
+GLAPI void APIENTRY glVariantdvEXT (GLuint, const GLdouble *);
+GLAPI void APIENTRY glVariantubvEXT (GLuint, const GLubyte *);
+GLAPI void APIENTRY glVariantusvEXT (GLuint, const GLushort *);
+GLAPI void APIENTRY glVariantuivEXT (GLuint, const GLuint *);
+GLAPI void APIENTRY glVariantPointerEXT (GLuint, GLenum, GLuint, const GLvoid *);
+GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint);
+GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint);
+GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum, GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum, GLenum);
+GLAPI GLuint APIENTRY glBindParameterEXT (GLenum);
+GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint, GLenum);
+GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVariantPointervEXT (GLuint, GLenum, GLvoid* *);
+GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint, GLenum, GLboolean *);
+GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint, GLenum, GLfloat *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);
+typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);
+typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
+typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
+typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
+typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
+typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
+typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);
+typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);
+typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);
+typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);
+typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);
+typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);
+typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);
+typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);
+typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr);
+typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);
+typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);
+typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);
+typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
+typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
+typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
+#endif
+
+#ifndef GL_ATI_vertex_streams
+#define GL_ATI_vertex_streams 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexStream1sATI (GLenum, GLshort);
+GLAPI void APIENTRY glVertexStream1svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream1iATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexStream1ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream1fATI (GLenum, GLfloat);
+GLAPI void APIENTRY glVertexStream1fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream1dATI (GLenum, GLdouble);
+GLAPI void APIENTRY glVertexStream1dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream2sATI (GLenum, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream2svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream2iATI (GLenum, GLint, GLint);
+GLAPI void APIENTRY glVertexStream2ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream2fATI (GLenum, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream2fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream2dATI (GLenum, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream2dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glVertexStream4sATI (GLenum, GLshort, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glVertexStream4svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glVertexStream4iATI (GLenum, GLint, GLint, GLint, GLint);
+GLAPI void APIENTRY glVertexStream4ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glVertexStream4fATI (GLenum, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glVertexStream4fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glVertexStream4dATI (GLenum, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glVertexStream4dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glNormalStream3bATI (GLenum, GLbyte, GLbyte, GLbyte);
+GLAPI void APIENTRY glNormalStream3bvATI (GLenum, const GLbyte *);
+GLAPI void APIENTRY glNormalStream3sATI (GLenum, GLshort, GLshort, GLshort);
+GLAPI void APIENTRY glNormalStream3svATI (GLenum, const GLshort *);
+GLAPI void APIENTRY glNormalStream3iATI (GLenum, GLint, GLint, GLint);
+GLAPI void APIENTRY glNormalStream3ivATI (GLenum, const GLint *);
+GLAPI void APIENTRY glNormalStream3fATI (GLenum, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glNormalStream3fvATI (GLenum, const GLfloat *);
+GLAPI void APIENTRY glNormalStream3dATI (GLenum, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glNormalStream3dvATI (GLenum, const GLdouble *);
+GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum);
+GLAPI void APIENTRY glVertexBlendEnviATI (GLenum, GLint);
+GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum, GLfloat);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);
+typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);
+typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);
+#endif
+
+#ifndef GL_ATI_element_array
+#define GL_ATI_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerATI (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayATI (GLenum, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum, GLuint, GLuint, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
+#endif
+
+#ifndef GL_SUN_mesh_array
+#define GL_SUN_mesh_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum, GLint, GLsizei, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);
+#endif
+
+#ifndef GL_SUN_slice_accum
+#define GL_SUN_slice_accum 1
+#endif
+
+#ifndef GL_NV_multisample_filter_hint
+#define GL_NV_multisample_filter_hint 1
+#endif
+
+#ifndef GL_NV_depth_clamp
+#define GL_NV_depth_clamp 1
+#endif
+
+#ifndef GL_NV_occlusion_query
+#define GL_NV_occlusion_query 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint);
+GLAPI void APIENTRY glEndOcclusionQueryNV (void);
+GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint, GLenum, GLint *);
+GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint, GLenum, GLuint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);
+typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+#ifndef GL_NV_point_sprite
+#define GL_NV_point_sprite 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPointParameteriNV (GLenum, GLint);
+GLAPI void APIENTRY glPointParameterivNV (GLenum, const GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);
+#endif
+
+#ifndef GL_NV_texture_shader3
+#define GL_NV_texture_shader3 1
+#endif
+
+#ifndef GL_NV_vertex_program1_1
+#define GL_NV_vertex_program1_1 1
+#endif
+
+#ifndef GL_EXT_shadow_funcs
+#define GL_EXT_shadow_funcs 1
+#endif
+
+#ifndef GL_EXT_stencil_two_side
+#define GL_EXT_stencil_two_side 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
+#endif
+
+#ifndef GL_ATI_text_fragment_shader
+#define GL_ATI_text_fragment_shader 1
+#endif
+
+#ifndef GL_APPLE_client_storage
+#define GL_APPLE_client_storage 1
+#endif
+
+#ifndef GL_APPLE_element_array
+#define GL_APPLE_element_array 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glElementPointerAPPLE (GLenum, const GLvoid *);
+GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum, GLint, GLsizei);
+GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, GLint, GLsizei);
+GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum, const GLint *, const GLsizei *, GLsizei);
+GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum, GLuint, GLuint, const GLint *, const GLsizei *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
+typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);
+#endif
+
+#ifndef GL_APPLE_fence
+#define GL_APPLE_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glGenFencesAPPLE (GLsizei, GLuint *);
+GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glSetFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint);
+GLAPI void APIENTRY glFinishFenceAPPLE (GLuint);
+GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum, GLuint);
+GLAPI void APIENTRY glFinishObjectAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);
+typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);
+typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);
+typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);
+typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);
+typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);
+#endif
+
+#ifndef GL_APPLE_vertex_array_object
+#define GL_APPLE_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint);
+GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei, const GLuint *);
+GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+#endif
+
+#ifndef GL_APPLE_vertex_array_range
+#define GL_APPLE_vertex_array_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei, GLvoid *);
+GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum, GLint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
+#endif
+
+#ifndef GL_APPLE_ycbcr_422
+#define GL_APPLE_ycbcr_422 1
+#endif
+
+#ifndef GL_S3_s3tc
+#define GL_S3_s3tc 1
+#endif
+
+#ifndef GL_ATI_draw_buffers
+#define GL_ATI_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDrawBuffersATI (GLsizei, const GLenum *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_ATI_pixel_format_float
+#define GL_ATI_pixel_format_float 1
+/* This is really a WGL extension, but defines some associated GL enums.
+ * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string.
+ */
+#endif
+
+#ifndef GL_ATI_texture_env_combine3
+#define GL_ATI_texture_env_combine3 1
+#endif
+
+#ifndef GL_ATI_texture_float
+#define GL_ATI_texture_float 1
+#endif
+
+#ifndef GL_NV_float_buffer
+#define GL_NV_float_buffer 1
+#endif
+
+#ifndef GL_NV_fragment_program
+#define GL_NV_fragment_program 1
+/* Some NV_fragment_program entry points are shared with ARB_vertex_program. */
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint, GLsizei, const GLubyte *, GLfloat, GLfloat, GLfloat, GLfloat);
+GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint, GLsizei, const GLubyte *, GLdouble, GLdouble, GLdouble, GLdouble);
+GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint, GLsizei, const GLubyte *, const GLfloat *);
+GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint, GLsizei, const GLubyte *, const GLdouble *);
+GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint, GLsizei, const GLubyte *, GLfloat *);
+GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint, GLsizei, const GLubyte *, GLdouble *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);
+typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);
+#endif
+
+#ifndef GL_NV_half_float
+#define GL_NV_half_float 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertex2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertex4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glNormal3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glColor4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV);
+GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum, const GLhalfNV *);
+GLAPI void APIENTRY glFogCoordhNV (GLhalfNV);
+GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *);
+GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV);
+GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib1hNV (GLuint, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib2hNV (GLuint, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib3hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttrib4hNV (GLuint, GLhalfNV, GLhalfNV, GLhalfNV, GLhalfNV);
+GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint, GLsizei, const GLhalfNV *);
+GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint, GLsizei, const GLhalfNV *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);
+typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);
+typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);
+typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);
+typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);
+typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);
+typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);
+typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);
+typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);
+#endif
+
+#ifndef GL_NV_pixel_data_range
+#define GL_NV_pixel_data_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPixelDataRangeNV (GLenum, GLsizei, GLvoid *);
+GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
+#endif
+
+#ifndef GL_NV_primitive_restart
+#define GL_NV_primitive_restart 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glPrimitiveRestartNV (void);
+GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);
+typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);
+#endif
+
+#ifndef GL_NV_texture_expand_normal
+#define GL_NV_texture_expand_normal 1
+#endif
+
+#ifndef GL_NV_vertex_program2
+#define GL_NV_vertex_program2 1
+#endif
+
+#ifndef GL_ATI_map_object_buffer
+#define GL_ATI_map_object_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint);
+GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+#endif
+
+#ifndef GL_ATI_separate_stencil
+#define GL_ATI_separate_stencil 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStencilOpSeparateATI (GLenum, GLenum, GLenum, GLenum);
+GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum, GLenum, GLint, GLuint);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
+#endif
+
+#ifndef GL_ATI_vertex_attrib_array_object
+#define GL_ATI_vertex_attrib_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint, GLint, GLenum, GLboolean, GLsizei, GLuint, GLuint);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint, GLenum, GLfloat *);
+GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint, GLenum, GLint *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);
+#endif
+
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+#ifndef GL_EXT_depth_bounds_test
+#define GL_EXT_depth_bounds_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDepthBoundsEXT (GLclampd, GLclampd);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);
+#endif
+
+#ifndef GL_EXT_texture_mirror_clamp
+#define GL_EXT_texture_mirror_clamp 1
+#endif
+
+#ifndef GL_EXT_blend_equation_separate
+#define GL_EXT_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum, GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+#ifndef GL_MESA_pack_invert
+#define GL_MESA_pack_invert 1
+#endif
+
+#ifndef GL_MESA_ycbcr_texture
+#define GL_MESA_ycbcr_texture 1
+#endif
+
+#ifndef GL_EXT_pixel_buffer_object
+#define GL_EXT_pixel_buffer_object 1
+#endif
+
+#ifndef GL_NV_fragment_program_option
+#define GL_NV_fragment_program_option 1
+#endif
+
+#ifndef GL_NV_fragment_program2
+#define GL_NV_fragment_program2 1
+#endif
+
+#ifndef GL_NV_vertex_program2_option
+#define GL_NV_vertex_program2_option 1
+#endif
+
+#ifndef GL_NV_vertex_program3
+#define GL_NV_vertex_program3 1
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_EXT_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint);
+GLAPI void APIENTRY glBindRenderbufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei, GLuint *);
+GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum, GLenum, GLsizei, GLsizei);
+GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum, GLenum, GLint *);
+GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint);
+GLAPI void APIENTRY glBindFramebufferEXT (GLenum, GLuint);
+GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei, const GLuint *);
+GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei, GLuint *);
+GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum);
+GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum, GLenum, GLenum, GLuint, GLint);
+GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLint);
+GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum, GLenum, GLenum, GLuint);
+GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum, GLenum, GLenum, GLint *);
+GLAPI void APIENTRY glGenerateMipmapEXT (GLenum);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
+typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);
+#endif
+
+#ifndef GL_GREMEDY_string_marker
+#define GL_GREMEDY_string_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei, const GLvoid *);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/src/testing/app/ishare/FastDXT/viewdxt.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/viewdxt.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/viewdxt.cpp	(revision 4)
@@ -0,0 +1,347 @@
+/******************************************************************************
+ * a DXT viewing utility
+ *
+ * Author : Robert Kooima
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if defined(WIN32)
+#define strdup(x) _strdup(x)
+#else
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+#define MAXSTR 256
+
+#include "dxt.h"
+#include "glsl.h"
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#endif
+
+#ifdef __linux__
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+#define glGetProcAddress(n) glXGetProcAddressARB((GLubyte *) n)
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include "glext.h"
+#define glGetProcAddress(n) wglGetProcAddress(n)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+byte *in_data;
+byte *dxt_data;
+byte *ref_data;
+
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef GLSL_YCOCG
+#ifndef __APPLE__
+static PFNGLGETCOMPRESSEDTEXIMAGEARBPROC  glGetCompressedTexImage;
+static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC   glCompressedTexImage2D;
+#endif
+#endif
+
+static void init_gl(void)
+{
+#ifndef __APPLE__
+    glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)
+               glGetProcAddress("glGetCompressedTexImageARB");
+    glCompressedTexImage2D  = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)
+               glGetProcAddress("glCompressedTexImage2DARB");
+#endif
+
+    glEnable(GL_TEXTURE_2D);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void out_rgb(int w, int h, const char *name)
+{
+    double e;
+    FILE *fout = NULL;
+
+    if ((fout = fopen(name, "wb")))
+    {
+        GLsizei sz = 3 * w * h;
+        GLubyte *p;
+
+        if ((p = (GLubyte *) malloc(sz)))
+        {
+	    glReadPixels( 0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, p );
+
+	    dxt_data = p;
+
+            fwrite(p, 1, sz, fout);
+
+            //free(p);
+
+	    // Compute error
+		e = ComputeError(ref_data, dxt_data, w, h);
+	    fprintf(stdout, "RMS Error %.4f\n", e);
+        }
+        fclose(fout);
+    }
+    else perror("fopen");
+}
+
+
+static void in_dxt(int w, int h, int format, const char *name)
+{
+    FILE *fin = NULL;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	if (format == 5 || format == 6)
+	  sz = 4 * w * h / 4;
+	else
+	  sz = 8 * (w / 4) * (h / 4);
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    int ww, hh;
+	    fread( &ww, sizeof( int ), 1, fin );
+	    fread( &hh, sizeof( int ), 1, fin );
+
+            fread(p, 1, sz, fin);
+
+	    if (format == 5 || format == 6)
+	      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+				     GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+				     w, h, 0, sz, p);
+	    else
+	      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+				     GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+				     w, h, 0, sz, p);
+            //free(p);
+	    in_data = p;
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void in_rgb(int w, int h, const char *name)
+{
+    FILE *fin = NULL;
+
+    if ((fin = fopen(name, "rb")))
+      {
+        GLubyte *p;
+	GLsizei sz;
+
+	sz = 4 * w * h;
+
+        if ((p = (GLubyte *) malloc(sz)))
+	  {
+	    memset(p, 0, sz);
+
+            fread(p, 1, sz, fin);
+
+	    ref_data = p;
+	  }
+        fclose(fin);
+      }
+    else perror("fopen");
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void display(int w, int h)
+{
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glFrustum(0, w, 0, h, 0, 1);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+    glClearColor(0,1,0,0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glBegin(GL_POLYGON);
+    {
+        glTexCoord2i(0, 1); glVertex2i(-1, -1);
+        glTexCoord2i(1, 1); glVertex2i(+1, -1);
+        glTexCoord2i(1, 0); glVertex2i(+1, +1);
+        glTexCoord2i(0, 0); glVertex2i(-1, +1);
+    }
+    glEnd();
+
+    SDL_GL_SwapBuffers();
+}
+
+/*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+    int w = 1024;
+    int h = 512;
+    int p = 1;
+    int format = 1; // DXT1 or DXT5 or DXT5YCoCg (6)
+    int out = 0;
+    int argi;
+    char *rgbfile;
+
+    /* Process arguments. */
+
+    for (argi = 1; argi < argc; ++argi)
+        if      (strcmp(argv[argi], "-p") == 0) p = 0;
+        else if (strcmp(argv[argi], "-5") == 0) format = 5;
+        else if (strcmp(argv[argi], "-6") == 0) format = 6;
+        else if (strcmp(argv[argi], "-1") == 0) format = 1;
+        else if (strcmp(argv[argi], "-o") == 0) out = 1;
+        else if (strcmp(argv[argi], "-r") == 0) rgbfile = strdup(argv[++argi]);
+        else if (strcmp(argv[argi], "-w") == 0) w = atoi(argv[++argi]);
+        else if (strcmp(argv[argi], "-h") == 0) h = atoi(argv[++argi]);
+        else     break;
+
+    /* Use SDL to get an OpenGL context for use as compressor/decompressor. */
+
+    if (SDL_Init(SDL_INIT_VIDEO) == 0)
+    {
+        SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     8);
+        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   8);
+        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    8);
+        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,  16);
+        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+        if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL))
+        {
+            SDL_Event e;
+
+            init_gl();
+
+            /* Convert and display named files. */
+
+#if defined(GLSL_YCOCG)
+	    // Initialize the "OpenGL Extension Wrangler" library
+	    glewInit();
+
+	    if (!glewIsSupported("GL_VERSION_2_0 "
+				 "GL_ARB_vertex_program "
+				 "GL_ARB_fragment_program "
+				 "GL_ARB_texture_compression "
+				 "GL_EXT_texture_compression_s3tc "
+				 )
+		) {
+	      fprintf(stderr, "GLSL_YCOCG> Unable to load required OpenGL extension\n");
+	      exit(-1);
+	    }
+
+	    // Load the shaders
+	    GLchar *FragmentShaderSource;
+	    GLchar *VertexShaderSource;
+	    GLSLreadShaderSource("ycocg", &VertexShaderSource, &FragmentShaderSource);
+	    PHandle = GLSLinstallShaders(VertexShaderSource, FragmentShaderSource);
+
+	    /* Finally, use the program. */
+	    glUseProgramObjectARB(PHandle);
+
+	    glUseProgramObjectARB(0);
+#endif
+
+	    in_dxt(w, h, format, argv[argi]);
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      {
+		glUseProgramObjectARB(PHandle);
+		glActiveTexture(GL_TEXTURE0);
+		int h=glGetUniformLocationARB(PHandle,"yuvtex");
+		glUniform1iARB(h,0);  /* Bind yuvtex to texture unit 0 */
+	      }
+#endif
+
+	    display(w, h);
+
+#if defined(GLSL_YCOCG)
+	    if (format == 6)
+	      glUseProgramObjectARB(0);
+#endif
+
+	    if (out)
+	      {
+		in_rgb(w, h, rgbfile);      // ref_data
+		out_rgb(w, h, "out.rgb");   // dxt_data
+	      }
+
+            /* Pause until the user closes the window. */
+
+            if (p)
+            {
+                while (SDL_WaitEvent(&e))
+                    if (e.type == SDL_QUIT || e.type == SDL_KEYDOWN)
+                        break;
+                    else {
+		      //display(w, h);
+		    }
+            }
+        }
+        else fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+
+        SDL_Quit();
+    }
+    else fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
Index: trunk/src/testing/app/ishare/FastDXT/libdxt.h
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/libdxt.h	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/libdxt.h	(revision 4)
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "dxt.h"
+#include "util.h"
+
+#define FORMAT_DXT1      1
+#define FORMAT_DXT5      2
+#define FORMAT_DXT5YCOCG 3
+
+
+int CompressDXT(const byte *in, byte *out, int width, int height, int format, int numthreads);
+
+
Index: trunk/src/testing/app/ishare/FastDXT/example.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/example.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/example.cpp	(revision 4)
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "libdxt.h"
+
+int
+main(int argc, char** argv)
+{
+  byte *in;
+  byte *out;
+  int nbbytes;
+
+	// Initialize some timing functions and else
+  aInitialize();
+
+  /*
+    Read an image.
+  */
+  unsigned long width = atoi(argv[1]);
+  unsigned long height = atoi(argv[2]);
+
+  in = (byte*)memalign(16, width*height*4);
+  memset(in, 0, width*height*4);
+
+  FILE *f=fopen(argv[3], "rb");
+  fread(in, 1, width*height*4, f);
+  fclose(f);
+
+  out = (byte*)memalign(16, width*height*4);
+  memset(out, 0, width*height*4);
+
+  fprintf(stderr, "Converting from raw: %ldx%ld\n", width, height);
+
+#define NUM_LOOPS 100
+
+  double t1, t2;
+
+  t1 = aTime();
+  for (int k=0;k<NUM_LOOPS;k++)
+    {
+      //CompressDXT(in, out, width, height, FORMAT_DXT5YCOCG, 4);
+      //CompressDXT(in, out, width, height, FORMAT_DXT5, 4);
+      CompressDXT(in, out, width, height, FORMAT_DXT1, 2);
+    }
+  t2 = aTime();
+
+  fprintf(stderr, "Time %.2f sec, Single %.2f sec, Freq %.2f Hz\n",
+	  t2-t1, (t2-t1)/(double)NUM_LOOPS, ((double)NUM_LOOPS)/(t2-t1) );
+  fprintf(stderr, "MP/sec %.2f\n",
+	  ((double)(width*height*NUM_LOOPS)) / ((t2-t1)*1000000.0) );
+
+#if 1
+  FILE *g=fopen("out.dxt", "wb+");
+  fwrite(&width, 4, 1, g);
+  fwrite(&height, 4, 1, g);
+  //nbbytes = width * height * 4 / 4; //DXT5
+  nbbytes = width * height * 3 / 6; // DXT1
+  fwrite(out, 1, nbbytes, g);
+  fclose(g);
+#endif
+
+  memfree(in);
+  memfree(out);
+
+  return 0;
+}
+
+
Index: trunk/src/testing/app/ishare/FastDXT/Makefile
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/Makefile	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/Makefile	(revision 4)
@@ -0,0 +1,81 @@
+CC=g++
+CXX=g++
+LDFLAGS=-O3
+LDLIBS=-lpthread
+CXXFLAGS=-O3 -funroll-loops -fomit-frame-pointer 
+
+OPTIM=1
+
+MACHINE=$(shell uname -s)
+ARCHITECTURE=$(shell uname -p)
+
+ifeq ($(MACHINE), Darwin)
+
+CXXFLAGS+=-I/opt/local/include
+LDLIBS+=-framework OpenGL
+
+ifeq ($(ARCHITECTURE), i386)
+	# Intel Mac
+
+ifeq ($(OPTIM), 1)
+# MacPro
+# CXXFLAGS+=-march=nocona -msse3 -DDXT_INTR
+
+# MacbookPro
+CXXFLAGS+=-march=i686 -msse2 -DDXT_INTR
+
+else
+
+#
+CXXFLAGS+=
+CXXFLAGS=-g
+endif
+
+endif
+
+ifeq ($(ARCHITECTURE), powerpc)
+	# PowerPC Mac
+echo "Disabling SSE instructions on PowerPC"
+CXXFLAGS+=
+
+endif
+
+else
+
+LDLIBS+=-lGL
+
+ifeq ($(ARCHITECTURE), x86_64)
+	# Opteron
+CXXFLAGS+=-march=opteron -msse2 -DDXT_INTR
+
+else
+
+	# everything considered i386/linux
+CXXFLAGS+=-msse2 -DDXT_INTR
+
+endif
+
+endif
+
+CFLAGS=$(CXXFLAGS) `sdl-config --cflags` -I/opt/local/include
+
+
+default: main example 2dxt viewdxt playdxt
+
+main: dxt.o main.o util.o intrinsic.o
+example: example.o libdxt.o dxt.o util.o intrinsic.o
+2dxt: dxt.o 2dxt.o libdxt.o util.o intrinsic.o
+
+
+viewdxt:viewdxt.o glsl.o dxt.o
+	${CC} -o viewdxt viewdxt.o glsl.o dxt.o intrinsic.o `sdl-config --libs` $(LDLIBS) -lGLEW
+
+playdxt:playdxt.o glsl.o dxt.o
+	${CC} -o playdxt playdxt.o glsl.o dxt.o intrinsic.o `sdl-config --libs` $(LDLIBS) -lGLEW
+
+install: default
+	/bin/cp -f main example 2dxt playdxt viewdxt bin
+
+clean:
+	/bin/rm -f *.o *~ main example 2dxt playdxt viewdxt *.rgba *.dxt out.*
+
Index: trunk/src/testing/app/ishare/FastDXT/dxt.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/dxt.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/dxt.cpp	(revision 4)
@@ -0,0 +1,578 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+// From:
+//    Real-Time DXT Compression
+//    May 20th 2006 J.M.P. van Waveren
+//    (c) 2006, Id Software, Inc.
+
+#include "dxt.h"
+#include "util.h"
+
+
+#define DXT_INTR 1
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock );
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock );
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor );
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor );
+
+// for DXT5
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor );
+
+
+word ColorTo565( const byte *color );
+
+void EmitByte( byte b, byte*& );
+void EmitWord( word s, byte*& );
+void EmitDoubleWord( dword i, byte*& );
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData );
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData);
+
+// Emit indices for DXT5
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData);
+
+
+void CompressImageDXT1( const byte *inBuf, byte *outBuf,
+			int width, int height, int &outputBytes )
+{
+  ALIGN16( byte *outData );
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+	ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+	ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsByBBox( block, minColor, maxColor );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData );
+      EmitWord( ColorTo565( minColor ), outData );
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = (int) ( outData - outBuf );
+}
+
+void RGBAtoYCoCg(const byte *inBuf, byte *outBuf, int width, int height)
+{
+  for ( int j = 0; j < width*height; j++ ) {
+    byte R = inBuf[j*4+0];
+    byte G = inBuf[j*4+1];
+    byte B = inBuf[j*4+2];
+    byte A = inBuf[j*4+3];
+    int Co = R-B;
+    int t = B + (Co/2);
+    int Cg = G-t;
+    int Y = t + (Cg/2);
+
+    Co += 128;
+    Cg += 96;
+
+//     if (Co < 0 || Co > 255)
+//       fprintf(stderr, "Co: %d\n", Co);
+//     if (Cg < 0 || Cg > 255)
+//       fprintf(stderr, "Cg: %d\n", Cg);
+//     if ( Y < 0 ||  Y > 255)
+//       fprintf(stderr, "Y: %d\n", Y);
+
+    if (Co < 0)   Co=0;
+    if (Co > 255) Co=255;
+    if (Cg < 0)   Cg=0;
+    if (Cg > 255) Cg=255;
+
+    outBuf[j*4+0] = Co;
+    outBuf[j*4+1] = Cg;
+    outBuf[j*4+2] = 0;
+    outBuf[j*4+3] = Y;
+  }
+}
+
+void CompressImageDXT5YCoCg( const byte *inBuf, byte *outBuf, int width, int height,
+			     int &outputBytes )
+{
+  byte *tmpBuf;
+  tmpBuf = (byte*)memalign(16, width*height*4);
+  memset(tmpBuf, 0, width*height*4);
+  RGBAtoYCoCg(inBuf, tmpBuf, width, height);
+  CompressImageDXT5(tmpBuf, outBuf, width, height, outputBytes);
+  memfree(tmpBuf);
+}
+
+
+void CompressImageDXT5( const byte *inBuf, byte *outBuf, int width, int height,
+			int &outputBytes )
+{
+  ALIGN16( byte *outData );
+
+  ALIGN16( byte block[64] );
+  ALIGN16( byte minColor[4] );
+  ALIGN16( byte maxColor[4] );
+
+  outData = outBuf;
+  for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) {
+    for ( int i = 0; i < width; i += 4 ) {
+
+#if defined(DXT_INTR)
+      ExtractBlock_Intrinsics( inBuf + i * 4, width, block );
+#else
+      ExtractBlock( inBuf + i * 4, width, block );
+#endif
+
+#if defined(DXT_INTR)
+      GetMinMaxColors_Intrinsics( block, minColor, maxColor );
+#else
+      GetMinMaxColorsAlpha( block, minColor, maxColor );
+#endif
+
+      EmitByte( maxColor[3], outData);
+      EmitByte( minColor[3], outData);
+
+#if defined(DXT_INTR)
+	  // Not Yet Implemented
+      //EmitAlphaIndices_Intrinsics( block, minColor[3], maxColor[3], outData );
+
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#else
+      EmitAlphaIndicesFast( block, minColor[3], maxColor[3], outData );
+#endif
+
+      EmitWord( ColorTo565( maxColor ), outData);
+      EmitWord( ColorTo565( minColor ), outData);
+
+#if defined(DXT_INTR)
+      EmitColorIndices_Intrinsics( block, minColor, maxColor, outData );
+#else
+      EmitColorIndicesFast( block, minColor, maxColor, outData );
+#endif
+    }
+  }
+  outputBytes = int( outData - outBuf );
+}
+
+
+
+
+void ExtractBlock( const byte *inPtr, int width, byte *colorBlock )
+{
+  for ( int j = 0; j < 4; j++ ) {
+    memcpy( &colorBlock[j*4*4], inPtr, 4*4 );
+    inPtr += width * 4;
+  }
+}
+
+word ColorTo565( const byte *color )
+{
+  return ( ( color[ 0 ] >> 3 ) << 11 ) |
+         ( ( color[ 1 ] >> 2 ) <<  5 ) |
+         (   color[ 2 ] >> 3 );
+}
+
+void EmitByte( byte b, byte *&outData)
+{
+  outData[0] = b;
+  outData += 1;
+}
+
+void EmitWord( word s, byte *&outData)
+{
+  outData[0] = ( s >> 0 ) & 255;
+  outData[1] = ( s >> 8 ) & 255;
+  outData += 2;
+}
+
+void EmitDoubleWord( dword i, byte *&outData)
+{
+  outData[0] = ( i >> 0 ) & 255;
+  outData[1] = ( i >> 8 ) & 255;
+  outData[2] = ( i >> 16 ) & 255;
+  outData[3] = ( i >> 24 ) & 255;
+  outData += 4;
+}
+
+
+int ColorDistance( const byte *c1, const byte *c2 )
+{
+  return ( ( c1[0] - c2[0] ) * ( c1[0] - c2[0] ) ) +
+    ( ( c1[1] - c2[1] ) * ( c1[1] - c2[1] ) ) +
+    ( ( c1[2] - c2[2] ) * ( c1[2] - c2[2] ) );
+}
+
+void SwapColors( byte *c1, byte *c2 )
+{
+  byte tm[3];
+  memcpy( tm, c1, 3 );
+  memcpy( c1, c2, 3 );
+  memcpy( c2, tm, 3 );
+}
+
+void GetMinMaxColors( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxDistance = -1;
+  for ( int i = 0; i < 64 - 4; i += 4 ) {
+    for ( int j = i + 4; j < 64; j += 4 ) {
+      int distance = ColorDistance( &colorBlock[i], &colorBlock[j] );
+      if ( distance > maxDistance ) {
+	maxDistance = distance;
+	memcpy( minColor, colorBlock+i, 3 );
+	memcpy( maxColor, colorBlock+j, 3 );
+      }
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+
+int ColorLuminance( const byte *color )
+{
+  return ( color[0] + color[1] * 2 + color[2] );
+}
+
+
+void GetMinMaxColorsByLuminance( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int maxLuminance = -1, minLuminance = MAX_INT;
+  for (int i = 0; i < 16; i++ ) {
+    int luminance = ColorLuminance( colorBlock+i*4 );
+    if ( luminance > maxLuminance ) {
+      maxLuminance = luminance;
+      memcpy( maxColor, colorBlock+i*4, 3 );
+    }
+    if ( luminance < minLuminance ) {
+      minLuminance = luminance;
+      memcpy( minColor, colorBlock+i*4, 3 );
+    }
+  }
+  if ( ColorTo565( maxColor ) < ColorTo565( minColor ) ) {
+    SwapColors( minColor, maxColor );
+  }
+}
+
+void GetMinMaxColorsByBBox( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[3];
+  minColor[0] = minColor[1] = minColor[2] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = 0;
+  for ( i = 0; i < 16; i++ ) {
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+  }
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+}
+
+
+//
+// GetMinMaxColorsAlpha for DXT5
+//
+void GetMinMaxColorsAlpha(  byte *colorBlock, byte *minColor, byte *maxColor )
+{
+  int i;
+  byte inset[4];
+  byte y,cg, co, r, g, b;
+
+  minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255;
+  maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0;
+
+  for ( i = 0; i < 16; i++ ) {
+    r = colorBlock[i*4+0];
+    g = colorBlock[i*4+1];
+    b = colorBlock[i*4+2];
+    y  = (g>>1) + ((r+b)>>2);
+    cg = g - ((r+b)>>1);
+    co = r - b;
+
+    colorBlock[i*4+0] = co;
+    colorBlock[i*4+1] = cg;
+    colorBlock[i*4+2] = 0;
+    colorBlock[i*4+3] = y;
+
+    if ( colorBlock[i*4+0] < minColor[0] ) { minColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] < minColor[1] ) { minColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] < minColor[2] ) { minColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] < minColor[3] ) { minColor[3] = colorBlock[i*4+3]; }
+    if ( colorBlock[i*4+0] > maxColor[0] ) { maxColor[0] = colorBlock[i*4+0]; }
+    if ( colorBlock[i*4+1] > maxColor[1] ) { maxColor[1] = colorBlock[i*4+1]; }
+    if ( colorBlock[i*4+2] > maxColor[2] ) { maxColor[2] = colorBlock[i*4+2]; }
+    if ( colorBlock[i*4+3] > maxColor[3] ) { maxColor[3] = colorBlock[i*4+3]; }
+  }
+
+  inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_SHIFT;
+  inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_SHIFT;
+  inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_SHIFT;
+  inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_SHIFT;
+
+  minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255;
+  minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255;
+  minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255;
+  minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255;
+
+  maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0;
+  maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0;
+  maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0;
+  maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0;
+}
+
+
+void EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  byte colors[4][4];
+  unsigned int indices[16];
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    unsigned int minDistance = MAX_INT;
+    for ( int j = 0; j < 4; j++ ) {
+      unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] );
+      if ( dist < minDistance ) {
+	minDistance = dist;
+	indices[i] = j;
+      }
+    }
+  }
+  dword result = 0;
+  for ( int i = 0; i < 16; i++ ) {
+    result |= ( indices[i] << (unsigned int)( i << 1 ) );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+void EmitColorIndicesFast( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+  word colors[4][4];
+  dword result = 0;
+
+  colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 );
+  colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 );
+  colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 );
+  colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 );
+  colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 );
+  colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 );
+  colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
+  colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
+  colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
+  colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
+  colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
+  colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
+
+  for ( int i = 15; i >= 0; i-- ) {
+    int c0 = colorBlock[i*4+0];
+    int c1 = colorBlock[i*4+1];
+    int c2 = colorBlock[i*4+2];
+    int d0 = abs( colors[0][0] - c0 ) + abs( colors[0][1] - c1 ) + abs( colors[0][2] - c2 );
+    int d1 = abs( colors[1][0] - c0 ) + abs( colors[1][1] - c1 ) + abs( colors[1][2] - c2 );
+    int d2 = abs( colors[2][0] - c0 ) + abs( colors[2][1] - c1 ) + abs( colors[2][2] - c2 );
+    int d3 = abs( colors[3][0] - c0 ) + abs( colors[3][1] - c1 ) + abs( colors[3][2] - c2 );
+
+    int b0 = d0 > d3;
+    int b1 = d1 > d2;
+    int b2 = d0 > d2;
+    int b3 = d1 > d3;
+    int b4 = d2 > d3;
+
+    int x0 = b1 & b2;
+    int x1 = b0 & b3;
+    int x2 = b0 & b4;
+    result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 );
+  }
+  EmitDoubleWord( result, outData );
+}
+
+
+//
+// Emit indices for DXT5
+//
+void EmitAlphaIndices( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  byte indices[16];
+  byte alphas[8];
+
+  alphas[0] = maxAlpha;
+  alphas[1] = minAlpha;
+  alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / 7;
+  alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / 7;
+  alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / 7;
+  alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / 7;
+  alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / 7;
+  alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / 7;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+    int minDistance = MAX_INT;
+    byte a = colorBlock[i*4];
+    for ( int j = 0; j < 8; j++ ) {
+      int dist = abs( a - alphas[j] );
+      if ( dist < minDistance ) {
+	minDistance = dist; indices[i] = j;
+      }
+    }
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+void EmitAlphaIndicesFast( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData )
+{
+  //assert( maxAlpha > minAlpha );
+
+  byte indices[16];
+  byte mid = ( maxAlpha - minAlpha ) / ( 2 * 7 );
+  byte ab1 = minAlpha + mid;
+  byte ab2 = ( 6 * maxAlpha + 1 * minAlpha ) / 7 + mid;
+  byte ab3 = ( 5 * maxAlpha + 2 * minAlpha ) / 7 + mid;
+  byte ab4 = ( 4 * maxAlpha + 3 * minAlpha ) / 7 + mid;
+  byte ab5 = ( 3 * maxAlpha + 4 * minAlpha ) / 7 + mid;
+  byte ab6 = ( 2 * maxAlpha + 5 * minAlpha ) / 7 + mid;
+  byte ab7 = ( 1 * maxAlpha + 6 * minAlpha ) / 7 + mid;
+
+  colorBlock += 3;
+
+  for ( int i = 0; i < 16; i++ ) {
+
+    byte a = colorBlock[i*4];
+
+    int b1 = ( a <= ab1 );
+    int b2 = ( a <= ab2 );
+    int b3 = ( a <= ab3 );
+    int b4 = ( a <= ab4 );
+    int b5 = ( a <= ab5 );
+    int b6 = ( a <= ab6 );
+    int b7 = ( a <= ab7 );
+
+    int index = ( b1 + b2 + b3 + b4 + b5 + b6 + b7 + 1 ) & 7;
+
+    indices[i] = index ^ ( 2 > index );
+  }
+
+  EmitByte( (indices[ 0] >> 0) | (indices[ 1] << 3) | (indices[ 2] << 6) , outData);
+  EmitByte( (indices[ 2] >> 2) | (indices[ 3] << 1) | (indices[ 4] << 4) | (indices[ 5] << 7) , outData);
+  EmitByte( (indices[ 5] >> 1) | (indices[ 6] << 2) | (indices[ 7] << 5) , outData);
+  EmitByte( (indices[ 8] >> 0) | (indices[ 9] << 3) | (indices[10] << 6) , outData);
+  EmitByte( (indices[10] >> 2) | (indices[11] << 1) | (indices[12] << 4) | (indices[13] << 7) , outData);
+  EmitByte( (indices[13] >> 1) | (indices[14] << 2) | (indices[15] << 5) , outData);
+}
+
+
+double ComputeError( const byte *original, const byte *dxt, int width, int height)
+{
+  // Compute RMS error
+  double error;
+  int s, d;
+
+  error = 0.0;
+
+  // dxt: pointer to data read back from the framebuffer. RGB data upside down.
+  for (int i=0; i<height; i++)
+    {
+      for (int j=0; j<width; j++)
+	{
+	  s = original[4*(width*i+j)+0];
+	  d = dxt[3*(width*(height-i-1)+j)+0];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+1];
+	  d = dxt[3*(width*(height-i-1)+j)+1];
+	  error += (s-d) * (s-d);
+
+	  s = original[4*(width*i+j)+2];
+	  d = dxt[3*(width*(height-i-1)+j)+2];
+	  error += (s-d) * (s-d);
+	}
+    }
+  error = sqrt( error / (double)( width*height ) );
+
+  return error;
+}
Index: trunk/src/testing/app/ishare/FastDXT/glsl.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/glsl.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/glsl.cpp	(revision 4)
@@ -0,0 +1,341 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "glsl.h"
+
+#if defined(GLSL_YCOCG)
+
+GLhandleARB FSHandle,PHandle;
+
+/*---------------------------------------------------------------------------*/
+
+
+#define GLSLVertexShader   1
+#define GLSLFragmentShader 2
+
+int GLSLprintlError(char *file, int line)
+{
+    //
+    // Returns 1 if an OpenGL error occurred, 0 otherwise.
+    //
+    GLenum glErr;
+    int    retCode = 0;
+
+    glErr = glGetError();
+    while (glErr != GL_NO_ERROR)
+    {
+        fprintf(stderr, "GLSL> glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
+        retCode = 1;
+        glErr = glGetError();
+    }
+    return retCode;
+}
+
+//
+// Print out the information log for a shader object
+//
+static
+void GLSLprintShaderInfoLog(GLuint shader)
+{
+    GLint infologLength = 0;
+    GLint charsWritten  = 0;
+    GLchar *infoLog;
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    if (infologLength > 0)
+    {
+        infoLog = (GLchar *)malloc(infologLength);
+        if (infoLog == NULL)
+        {
+            fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+            exit(1);
+        }
+        glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
+        fprintf(stderr, "GLSL> Shader InfoLog:%s\n", infoLog);
+        free(infoLog);
+    }
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+//
+// Print out the information log for a program object
+//
+static
+void GLSLprintProgramInfoLog(GLuint program)
+{
+    GLint infologLength = 0;
+    GLint charsWritten  = 0;
+    GLchar *infoLog;
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
+
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+    if (infologLength > 0)
+    {
+        infoLog = (GLchar *)malloc(infologLength);
+        if (infoLog == NULL)
+        {
+            fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+            exit(1);
+        }
+        glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
+        fprintf(stderr, "GLSL> Program InfoLog:%s\n", infoLog);
+        free(infoLog);
+    }
+    GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+static
+int GLSLShaderSize(char *fileName, int shaderType)
+{
+    //
+    // Returns the size in bytes of the shader fileName.
+    // If an error occurred, it returns -1.
+    //
+    // File name convention:
+    //
+    // <fileName>.vert
+    // <fileName>.frag
+    //
+    int fd;
+    char name[256];
+    int count = -1;
+
+        memset(name, 0, 256);
+    strcpy(name, fileName);
+
+    switch (shaderType)
+    {
+        case GLSLVertexShader:
+            strcat(name, ".vert");
+            break;
+        case GLSLFragmentShader:
+            strcat(name, ".frag");
+            break;
+        default:
+            fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+            exit(1);
+            break;
+    }
+
+    //
+    // Open the file, seek to the end to find its length
+    //
+#ifdef WIN32
+    fd = _open(name, _O_RDONLY);
+    if (fd != -1)
+    {
+        count = _lseek(fd, 0, SEEK_END) + 1;
+        _close(fd);
+    }
+#else
+    fd = open(name, O_RDONLY);
+    if (fd != -1)
+    {
+        count = lseek(fd, 0, SEEK_END) + 1;
+        close(fd);
+    }
+#endif
+    return count;
+}
+
+
+int GLSLreadShader(char *fileName, int shaderType, char *shaderText, int size)
+{
+    //
+    // Reads a shader from the supplied file and returns the shader in the
+    // arrays passed in. Returns 1 if successful, 0 if an error occurred.
+    // The parameter size is an upper limit of the amount of bytes to read.
+    // It is ok for it to be too big.
+    //
+    FILE *fh;
+    char name[100];
+    int count;
+
+    strcpy(name, fileName);
+
+    switch (shaderType)
+    {
+        case GLSLVertexShader:
+            strcat(name, ".vert");
+            break;
+        case GLSLFragmentShader:
+            strcat(name, ".frag");
+            break;
+        default:
+            fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+            exit(1);
+            break;
+    }
+
+    //
+    // Open the file
+    //
+    fh = fopen(name, "r");
+    if (!fh)
+        return -1;
+
+
+    //
+    // Get the shader from a file.
+    //
+    fseek(fh, 0, SEEK_SET);
+    count = (int) fread(shaderText, 1, size, fh);
+    shaderText[count] = '\0';
+
+    if (ferror(fh))
+        count = 0;
+
+    fclose(fh);
+    return count;
+}
+
+int GLSLreadShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)
+{
+    int vSize, fSize;
+
+    //
+    // Allocate memory to hold the source of our shaders.
+    //
+
+    fprintf(stderr, "GLSL> load shader %s\n", fileName);
+    if (vertexShader) {
+        vSize = GLSLShaderSize(fileName, GLSLVertexShader);
+
+        if (vSize == -1) {
+            fprintf(stderr, "GLSL> Cannot determine size of the vertex shader %s\n", fileName);
+            return 0;
+        }
+
+        *vertexShader = (GLchar *) malloc(vSize);
+
+        //
+        // Read the source code
+        //
+        if (!GLSLreadShader(fileName, GLSLVertexShader, *vertexShader, vSize)) {
+            fprintf(stderr, "GLSL> Cannot read the file %s.vert\n", fileName);
+            return 0;
+        }
+    }
+
+    if (fragmentShader) {
+        fSize = GLSLShaderSize(fileName, GLSLFragmentShader);
+
+        if (fSize == -1) {
+            fprintf(stderr, "GLSL> Cannot determine size of the fragment shader %s\n", fileName);
+            return 0;
+        }
+
+        *fragmentShader = (GLchar *) malloc(fSize);
+
+        if (!GLSLreadShader(fileName, GLSLFragmentShader, *fragmentShader, fSize)) {
+            fprintf(stderr, "GLSL> Cannot read the file %s.frag\n", fileName);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+
+GLuint GLSLinstallShaders(const GLchar *Vertex, const GLchar *Fragment)
+{
+        GLuint VS, FS, Prog;   // handles to objects
+        GLint  vertCompiled, fragCompiled;    // status values
+        GLint  linked;
+
+        // Create a program object
+        Prog = glCreateProgram();
+
+        // Create a vertex shader object and a fragment shader object
+        if (Vertex) {
+                VS = glCreateShader(GL_VERTEX_SHADER);
+
+                // Load source code strings into shaders
+                glShaderSource(VS, 1, &Vertex, NULL);
+
+                // Compile the vertex shader, and print out
+                // the compiler log file.
+
+                glCompileShader(VS);
+                GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+                glGetShaderiv(VS, GL_COMPILE_STATUS, &vertCompiled);
+                GLSLprintShaderInfoLog(VS);
+
+                if (!vertCompiled)
+                  return 0;
+
+                glAttachShader(Prog, VS);
+        }
+
+
+        if (Fragment) {
+                FS = glCreateShader(GL_FRAGMENT_SHADER);
+
+                glShaderSource(FS, 1, &Fragment, NULL);
+
+                glCompileShader(FS);
+                GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+                glGetShaderiv(FS, GL_COMPILE_STATUS, &fragCompiled);
+                GLSLprintShaderInfoLog(FS);
+
+                if (!fragCompiled)
+                  return 0;
+
+                glAttachShader(Prog, FS);
+        }
+
+        // Link the program object and print out the info log
+        glLinkProgram(Prog);
+        GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+        glGetProgramiv(Prog, GL_LINK_STATUS, &linked);
+        GLSLprintProgramInfoLog(Prog);
+
+        if (!linked)
+          return 0;
+
+        return Prog;
+}
+
+#endif
+
Index: trunk/src/testing/app/ishare/FastDXT/intrinsic.cpp
===================================================================
--- trunk/src/testing/app/ishare/FastDXT/intrinsic.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/FastDXT/intrinsic.cpp	(revision 4)
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * Fast DXT - a realtime DXT compression tool
+ *
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+/*
+	Code convert from asm to intrinsics from:
+
+		Copyright (C) 2006 Id Software, Inc.
+		Written by J.M.P. van Waveren
+		This code is free software; you can redistribute it and/or
+		modify it under the terms of the GNU Lesser General Public
+		License as published by the Free Software Foundation; either
+		version 2.1 of the License, or (at your option) any later version.
+		This code is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+		Lesser General Public License for more details.
+*/
+
+#include "dxt.h"
+
+#include <emmintrin.h>  // sse2
+
+
+void ExtractBlock_Intrinsics( const byte *inPtr, int width, byte *colorBlock )
+{
+        __m128i t0, t1, t2, t3;
+	register int w = width << 2;  // width*4
+
+        t0 = _mm_load_si128 ( (__m128i*) inPtr );
+        _mm_store_si128 ( (__m128i*) &colorBlock[0], t0 );   // copy first row, 16bytes
+
+        t1 = _mm_load_si128 ( (__m128i*) (inPtr + w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[16], t1 );   // copy second row
+
+        t2 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[32], t2 );   // copy third row
+
+	inPtr = inPtr + w;     // add width, intead of *3
+
+        t3 = _mm_load_si128 ( (__m128i*) (inPtr + 2*w) );
+        _mm_store_si128 ( (__m128i*) &colorBlock[48], t3 );   // copy last row
+}
+
+#define R_SHUFFLE_D( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 ))
+
+ALIGN16( static byte SIMD_SSE2_byte_0[16] ) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void GetMinMaxColors_Intrinsics( const byte *colorBlock, byte *minColor, byte *maxColor )
+{
+    __m128i t0, t1, t3, t4, t6, t7;
+
+    // get bounding box
+    // ----------------
+
+    // load the first row
+    t0 = _mm_load_si128 ( (__m128i*) colorBlock );
+    t1 = _mm_load_si128 ( (__m128i*) colorBlock );
+
+    __m128i t16 = _mm_load_si128 ( (__m128i*) (colorBlock+16) );
+    // Minimum of Packed Unsigned Byte Integers
+    t0 = _mm_min_epu8 ( t0, t16);
+    // Maximum of Packed Unsigned Byte Integers
+    t1 = _mm_max_epu8 ( t1, t16);
+
+    __m128i t32 = _mm_load_si128 ( (__m128i*) (colorBlock+32) );
+    t0 = _mm_min_epu8 ( t0, t32);
+    t1 = _mm_max_epu8 ( t1, t32);
+
+    __m128i t48 = _mm_load_si128 ( (__m128i*) (colorBlock+48) );
+    t0 = _mm_min_epu8 ( t0, t48);
+    t1 = _mm_max_epu8 ( t1, t48);
+
+    // Shuffle Packed Doublewords
+    t3 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t4 = _mm_shuffle_epi32( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t3);
+    t1 = _mm_max_epu8 ( t1, t4);
+
+    // Shuffle Packed Low Words
+    t6 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+    t7 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 2, 3, 2, 3 ) );
+
+    t0 = _mm_min_epu8 ( t0, t6);
+    t1 = _mm_max_epu8 ( t1, t7);
+
+    // inset the bounding box
+    // ----------------------
+
+    // Unpack Low Data
+    //__m128i t66 = _mm_set1_epi8( 0 );
+    __m128i t66 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_0 );
+    t0 = _mm_unpacklo_epi8(t0, t66);
+    t1 = _mm_unpacklo_epi8(t1, t66);
+
+    // copy (movdqa)
+    //__m128i t2 = _mm_load_si128 ( &t1 );
+    __m128i t2 = t1;
+
+    // Subtract Packed Integers
+    t2 = _mm_sub_epi16(t2, t0);
+
+    // Shift Packed Data Right Logical
+    t2 = _mm_srli_epi16(t2, INSET_SHIFT);
+
+    // Add Packed Integers
+    t0 = _mm_add_epi16(t0, t2);
+
+    t1 = _mm_sub_epi16(t1, t2);
+
+    // Pack with Unsigned Saturation
+    t0 = _mm_packus_epi16(t0, t0);
+    t1 = _mm_packus_epi16(t1, t1);
+
+    // store bounding box extents
+    // --------------------------
+    _mm_store_si128 ( (__m128i*) minColor, t0 );
+    _mm_store_si128 ( (__m128i*) maxColor, t1 );
+}
+
+
+ALIGN16( static word SIMD_SSE2_word_0[8] ) = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+ALIGN16( static word SIMD_SSE2_word_1[8] ) = { 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 };
+ALIGN16( static word SIMD_SSE2_word_2[8] ) = { 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002 };
+ALIGN16( static word SIMD_SSE2_word_div_by_3[8] ) = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 };
+ALIGN16( static byte SIMD_SSE2_byte_colorMask[16] ) = { C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00, C565_5_MASK, C565_6_MASK, C565_5_MASK, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+void EmitColorIndices_Intrinsics( const byte *colorBlock, const byte *minColor, const byte *maxColor, byte *&outData )
+{
+	ALIGN16( byte color0[16] );
+	ALIGN16( byte color1[16] );
+	ALIGN16( byte color2[16] );
+	ALIGN16( byte color3[16] );
+	ALIGN16( byte result[16] );
+
+	// mov esi, maxColor
+	// mov edi, minColor
+
+	__m128i t0, t1, t2, t3, t4, t5, t6, t7;
+
+	t7 = _mm_setzero_si128();
+	//t7 = _mm_xor_si128(t7, t7);
+	_mm_store_si128 ( (__m128i*) &result, t7 );
+
+
+	//t0 = _mm_load_si128 ( (__m128i*)  maxColor );
+	t0 = _mm_cvtsi32_si128( *(int*)maxColor);
+
+	// Bitwise AND
+	__m128i tt = _mm_load_si128 ( (__m128i*) SIMD_SSE2_byte_colorMask );
+	t0 = _mm_and_si128(t0, tt);
+
+	t0 = _mm_unpacklo_epi8(t0, t7);
+
+	t4 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t0, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	// Bitwise Logical OR
+	t0 = _mm_or_si128(t0, t4);
+	t0 = _mm_or_si128(t0, t5);   // t0 contains color0 in 565
+
+
+
+
+	//t1 = _mm_load_si128 ( (__m128i*)  minColor );
+	t1 = _mm_cvtsi32_si128( *(int*)minColor);
+
+	t1 = _mm_and_si128(t1, tt);
+
+	t1 = _mm_unpacklo_epi8(t1, t7);
+
+	t4 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 0, 3, 2, 3 ));
+	t5 = _mm_shufflelo_epi16( t1, R_SHUFFLE_D( 3, 1, 3, 3 ));
+
+	t4 = _mm_srli_epi16(t4, 5);
+	t5 = _mm_srli_epi16(t5, 6);
+
+	t1 = _mm_or_si128(t1, t4);
+	t1 = _mm_or_si128(t1, t5);  // t1 contains color1 in 565
+
+
+
+	t2 = t0;
+
+	t2 = _mm_packus_epi16(t2, t7);
+
+	t2 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color0, t2 );
+
+	t6 = t0;
+	t6 = _mm_add_epi16(t6, t0);
+	t6 = _mm_add_epi16(t6, t1);
+
+	// Multiply Packed Signed Integers and Store High Result
+	__m128i tw3 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_div_by_3 );
+	t6 = _mm_mulhi_epi16(t6, tw3);
+	t6 = _mm_packus_epi16(t6, t7);
+
+	t6 = _mm_shuffle_epi32( t6, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color2, t6 );
+
+	t3 = t1;
+	t3 = _mm_packus_epi16(t3, t7);
+	t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 1, 0, 1 ));
+
+	_mm_store_si128 ( (__m128i*) &color1, t3 );
+
+	t1 = _mm_add_epi16(t1, t1);
+	t0 = _mm_add_epi16(t0, t1);
+
+	t0 = _mm_mulhi_epi16(t0, tw3);
+	t0 = _mm_packus_epi16(t0, t7);
+
+	t0 = _mm_shuffle_epi32( t0, R_SHUFFLE_D( 0, 1, 0, 1 ));
+	_mm_store_si128 ( (__m128i*) &color3, t0 );
+
+	__m128i w0 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_0);
+	__m128i w1 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_1);
+	__m128i w2 = _mm_load_si128 ( (__m128i*) SIMD_SSE2_word_2);
+
+	    // mov eax, 32
+	    // mov esi, colorBlock
+	int x = 32;
+	//const byte *c = colorBlock;
+	while (x >= 0)
+	  {
+	    t3 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+0));
+	    t3 = _mm_shuffle_epi32( t3, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+8));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t0 = t3;
+	    t6 = t5;
+	    // Compute Sum of Absolute Difference
+	    __m128i c0 = _mm_load_si128 ( (__m128i*)  color0 );
+	    t0 = _mm_sad_epu8(t0, c0);
+	    t6 = _mm_sad_epu8(t6, c0);
+	    // Pack with Signed Saturation
+	    t0 = _mm_packs_epi32 (t0, t6);
+
+	    t1 = t3;
+	    t6 = t5;
+	    __m128i c1 = _mm_load_si128 ( (__m128i*)  color1 );
+	    t1 = _mm_sad_epu8(t1, c1);
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t1 = _mm_packs_epi32 (t1, t6);
+
+	    t2 = t3;
+	    t6 = t5;
+	    __m128i c2 = _mm_load_si128 ( (__m128i*)  color2 );
+	    t2 = _mm_sad_epu8(t2, c2);
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t2 = _mm_packs_epi32 (t2, t6);
+
+	    __m128i c3 = _mm_load_si128 ( (__m128i*)  color3 );
+	    t3 = _mm_sad_epu8(t3, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t3 = _mm_packs_epi32 (t3, t5);
+
+
+	    t4 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+16));
+	    t4 = _mm_shuffle_epi32( t4, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t5 = _mm_loadl_epi64( (__m128i*) (colorBlock+x+24));
+	    t5 = _mm_shuffle_epi32( t5, R_SHUFFLE_D( 0, 2, 1, 3 ));
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c0);
+	    t7 = _mm_sad_epu8(t7, c0);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t0 = _mm_packs_epi32 (t0, t6);  // d0
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c1);
+	    t7 = _mm_sad_epu8(t7, c1);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t1 = _mm_packs_epi32 (t1, t6);  // d1
+
+	    t6 = t4;
+	    t7 = t5;
+	    t6 = _mm_sad_epu8(t6, c2);
+	    t7 = _mm_sad_epu8(t7, c2);
+	    t6 = _mm_packs_epi32 (t6, t7);
+	    t2 = _mm_packs_epi32 (t2, t6);  // d2
+
+	    t4 = _mm_sad_epu8(t4, c3);
+	    t5 = _mm_sad_epu8(t5, c3);
+	    t4 = _mm_packs_epi32 (t4, t5);
+	    t3 = _mm_packs_epi32 (t3, t4);  // d3
+
+	    t7 = _mm_load_si128 ( (__m128i*) result );
+
+	    t7 = _mm_slli_epi32( t7, 16);
+
+	    t4 = t0;
+	    t5 = t1;
+	    // Compare Packed Signed Integers for Greater Than
+	    t0 = _mm_cmpgt_epi16(t0, t3); // b0
+	    t1 = _mm_cmpgt_epi16(t1, t2); // b1
+	    t4 = _mm_cmpgt_epi16(t4, t2); // b2
+	    t5 = _mm_cmpgt_epi16(t5, t3); // b3
+	    t2 = _mm_cmpgt_epi16(t2, t3); // b4
+
+	    t4 = _mm_and_si128(t4, t1); // x0
+	    t5 = _mm_and_si128(t5, t0); // x1
+	    t2 = _mm_and_si128(t2, t0); // x2
+
+	    t4 = _mm_or_si128(t4, t5);
+	    t2 = _mm_and_si128(t2, w1);
+	    t4 = _mm_and_si128(t4, w2);
+	    t2 = _mm_or_si128(t2, t4);
+
+	    t5 = _mm_shuffle_epi32( t2, R_SHUFFLE_D( 2, 3, 0, 1 ));
+
+	    // Unpack Low Data
+	    t2 = _mm_unpacklo_epi16 ( t2, w0);
+	    t5 = _mm_unpacklo_epi16 ( t5, w0);
+
+	    //t5 = _mm_slli_si128 ( t5, 8);
+	    t5 = _mm_slli_epi32( t5, 8);
+
+	    t7 = _mm_or_si128(t7, t5);
+	    t7 = _mm_or_si128(t7, t2);
+
+	    _mm_store_si128 ( (__m128i*) &result, t7 );
+
+	    x -=32;
+	  }
+
+	t4 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 1, 2, 3, 0 ));
+	t5 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 2, 3, 0, 1 ));
+	t6 = _mm_shuffle_epi32( t7, R_SHUFFLE_D( 3, 0, 1, 2 ));
+
+	t4 = _mm_slli_epi32 ( t4, 2);
+	t5 = _mm_slli_epi32 ( t5, 4);
+	t6 = _mm_slli_epi32 ( t6, 6);
+
+	t7 = _mm_or_si128(t7, t4);
+	t7 = _mm_or_si128(t7, t5);
+	t7 = _mm_or_si128(t7, t6);
+
+	//_mm_store_si128 ( (__m128i*) outData, t7 );
+
+	int r = _mm_cvtsi128_si32 (t7);
+	memcpy(outData, &r, 4);   // Anything better ?
+
+	outData += 4;
+}
+
+
+
+ALIGN16( static byte SIMD_SSE2_byte_1[16] ) = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
+ALIGN16( static byte SIMD_SSE2_byte_2[16] ) = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
+ALIGN16( static byte SIMD_SSE2_byte_7[16] ) = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 };
+ALIGN16( static word SIMD_SSE2_word_div_by_7[8] ) = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 };
+ALIGN16( static word SIMD_SSE2_word_div_by_14[8] ) = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 };
+ALIGN16( static word SIMD_SSE2_word_scale66554400[8] ) = { 6, 6, 5, 5, 4, 4, 0, 0 };
+ALIGN16( static word SIMD_SSE2_word_scale11223300[8] ) = { 1, 1, 2, 2, 3, 3, 0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask0[4] ) = { 7<<0, 0, 7<<0, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask1[4] ) = { 7<<3, 0, 7<<3, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask2[4] ) = { 7<<6, 0, 7<<6, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask3[4] ) = { 7<<9, 0, 7<<9, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask4[4] ) = { 7<<12, 0, 7<<12, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask5[4] ) = { 7<<15, 0, 7<<15, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask6[4] ) = { 7<<18, 0, 7<<18, 0 };
+ALIGN16( static dword SIMD_SSE2_dword_alpha_bit_mask7[4] ) = { 7<<21, 0, 7<<21, 0 };
+
+
+void EmitAlphaIndices_Intrinsics( const byte *colorBlock, const byte minAlpha, const byte maxAlpha, byte *&outData)
+{
+/*
+  __asm {
+    mov esi, colorBlock
+      movdqa xmm0, [esi+ 0]
+      movdqa xmm5, [esi+16]
+      psrld xmm0, 24
+      psrld xmm5, 24
+      packuswb xmm0, xmm5
+
+      movdqa xmm6, [esi+32]
+      movdqa xmm4, [esi+48]
+      psrld xmm6, 24
+      psrld xmm4, 24
+      packuswb xmm6, xmm4
+
+      movzx ecx, maxAlpha
+      movd xmm5, ecx
+      pshuflw xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm5, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm7, xmm5
+
+      movzx edx, minAlpha
+      movd xmm2, edx
+      pshuflw xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm2, xmm2, R_SHUFFLE_D( 0, 0, 0, 0 )
+      movdqa xmm3, xmm2
+
+      movdqa xmm4, xmm5
+      psubw xmm4, xmm2
+      pmulhw xmm4, SIMD_SSE2_word_div_by_14    // * ( ( 1 << 16 ) / 14 + 1 ) ) >> 16
+      movdqa xmm1, xmm2
+      paddw xmm1, xmm4
+      packuswb xmm1, xmm1                      // ab1
+
+      pmullw xmm5, SIMD_SSE2_word_scale66554400
+      pmullw xmm7, SIMD_SSE2_word_scale11223300
+      pmullw xmm2, SIMD_SSE2_word_scale11223300
+      pmullw xmm3, SIMD_SSE2_word_scale66554400
+      paddw xmm5, xmm2
+      paddw xmm7, xmm3
+      pmulhw xmm5, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      pmulhw xmm7, SIMD_SSE2_word_div_by_7 // * ( ( 1 << 16 ) / 7 + 1 ) ) >> 16
+      paddw xmm5, xmm4
+      paddw xmm7, xmm4
+
+      pshufd xmm2, xmm5, R_SHUFFLE_D( 0, 0, 0, 0 )
+      pshufd xmm3, xmm5, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm4, xmm5, R_SHUFFLE_D( 2, 2, 2, 2 )
+      packuswb xmm2, xmm2 // ab2
+      packuswb xmm3, xmm3 // ab3
+      packuswb xmm4, xmm4 // ab4
+
+      packuswb xmm0, xmm6 // alpha values
+
+      pshufd xmm5, xmm7, R_SHUFFLE_D( 2, 2, 2, 2 )
+      pshufd xmm6, xmm7, R_SHUFFLE_D( 1, 1, 1, 1 )
+      pshufd xmm7, xmm7, R_SHUFFLE_D( 0, 0, 0, 0 )
+      packuswb xmm5, xmm5 // ab5
+      packuswb xmm6, xmm6 // ab6
+      packuswb xmm7, xmm7 // ab7
+
+      pminub xmm1, xmm0
+      pminub xmm2, xmm0
+      pminub xmm3, xmm0
+      pcmpeqb xmm1, xmm0
+      pcmpeqb xmm2, xmm0
+      pcmpeqb xmm3, xmm0
+      pminub xmm4, xmm0
+      pminub xmm5, xmm0
+      pminub xmm6, xmm0
+      pminub xmm7, xmm0
+      pcmpeqb xmm4, xmm0
+      pcmpeqb xmm5, xmm0
+      pcmpeqb xmm6, xmm0
+      pcmpeqb xmm7, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pand xmm2, SIMD_SSE2_byte_1
+      pand xmm3, SIMD_SSE2_byte_1
+      pand xmm4, SIMD_SSE2_byte_1
+      pand xmm5, SIMD_SSE2_byte_1
+      pand xmm6, SIMD_SSE2_byte_1
+      pand xmm7, SIMD_SSE2_byte_1
+      movdqa xmm0, SIMD_SSE2_byte_1
+      paddusb xmm0, xmm1
+      paddusb xmm2, xmm3
+      paddusb xmm4, xmm5
+      paddusb xmm6, xmm7
+      paddusb xmm0, xmm2
+      paddusb xmm4, xmm6
+      paddusb xmm0, xmm4
+      pand xmm0, SIMD_SSE2_byte_7
+      movdqa xmm1, SIMD_SSE2_byte_2
+      pcmpgtb xmm1, xmm0
+      pand xmm1, SIMD_SSE2_byte_1
+      pxor xmm0, xmm1
+      movdqa xmm1, xmm0
+      movdqa xmm2, xmm0
+      movdqa xmm3, xmm0
+      movdqa xmm4, xmm0
+      movdqa xmm5, xmm0
+      movdqa xmm6, xmm0
+      movdqa xmm7, xmm0
+      psrlq xmm1, 8- 3
+      psrlq xmm2, 16- 6
+      psrlq xmm3, 24- 9
+
+      psrlq xmm4, 32-12
+      psrlq xmm5, 40-15
+      psrlq xmm6, 48-18
+      psrlq xmm7, 56-21
+      pand xmm0, SIMD_SSE2_dword_alpha_bit_mask0
+      pand xmm1, SIMD_SSE2_dword_alpha_bit_mask1
+      pand xmm2, SIMD_SSE2_dword_alpha_bit_mask2
+      pand xmm3, SIMD_SSE2_dword_alpha_bit_mask3
+      pand xmm4, SIMD_SSE2_dword_alpha_bit_mask4
+      pand xmm5, SIMD_SSE2_dword_alpha_bit_mask5
+      pand xmm6, SIMD_SSE2_dword_alpha_bit_mask6
+      pand xmm7, SIMD_SSE2_dword_alpha_bit_mask7
+      por xmm0, xmm1
+      por xmm2, xmm3
+      por xmm4, xmm5
+      por xmm6, xmm7
+      por xmm0, xmm2
+      por xmm4, xmm6
+      por xmm0, xmm4
+      mov esi, outData
+      movd [esi+0], xmm0
+      pshufd xmm1, xmm0, R_SHUFFLE_D( 2, 3, 0, 1 )
+      movd [esi+3], xmm1
+      }
+  outData += 6;
+*/
+}
+
Index: trunk/src/testing/app/ishare/Makefile
===================================================================
--- trunk/src/testing/app/ishare/Makefile	(revision 4)
+++ trunk/src/testing/app/ishare/Makefile	(revision 4)
@@ -0,0 +1,66 @@
+include ../../config.mk
+
+CFLAGS=-fPIC -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS) `wx-config --cflags`
+CXXFLAGS=$(CFLAGS)
+CC=$(COMPILER)
+
+ifeq ($(MACHINE), Darwin)
+   CFLAGS  += -FGLUT -FOpenGL -IFastDXT -march=i686 -msse2 -DDXT_INTR
+   LIBS=-lpthread -L../../lib -lsail -framework OpenGL -framework Carbon -framework Cocoa -framework IOKit -lobjc -lm
+else
+   LIBS=-lpthread -lm -ldl -lglut $(QUANTA_LIB) $(GLEW_LIB) -L../../lib -lsail
+endif
+
+PROGRAM = ishare
+
+FILES = ishare.o FastDXT/libdxt.o FastDXT/dxt.o FastDXT/util.o FastDXT/intrinsic.o
+
+default: $(PROGRAM) iShareUI iShareUI.app
+
+install: default
+	cp $(PROGRAM) ../../bin
+	cp -r iShareUI.app ../../bin
+
+$(PROGRAM): $(FILES)
+	$(COMPILER) -o $(PROGRAM) $(FILES) $(LIBS)
+
+iShareUI: ui.o
+	g++ -o iShareUI ui.o FastDXT/libdxt.o FastDXT/dxt.o FastDXT/util.o FastDXT/intrinsic.o `wx-config --libs` $(LIBS) -Wl,-install_name,@executable_path/../Frameworks/
+
+iShareUI.app: Info.plist iShareUI version.plist InfoPlist.strings iShareUIMacIcons.icns AnotherResource.txt  
+	/bin/rm -fr iShareUI.app
+	-mkdir iShareUI.app    
+	-mkdir iShareUI.app/Contents
+	-mkdir iShareUI.app/Contents/MacOS
+	-mkdir iShareUI.app/Contents/Resources
+	-mkdir iShareUI.app/Contents/Frameworks
+	-mkdir iShareUI.app/Contents/Resources/English.lproj
+	/bin/cp -f Info.plist iShareUI.app/Contents/
+	/bin/cp -f iShareUI iShareUI.app/Contents/MacOS/iShareUI
+
+	/bin/cp -f ../../lib/libsail.dylib iShareUI.app/Contents/Frameworks
+	/bin/cp -f /opt/local/lib/libGLEW.1.5.0.dylib  iShareUI.app/Contents/Frameworks
+	/bin/cp -f /opt/local/lib/libSDL-1.2.0.dylib iShareUI.app/Contents/Frameworks
+	/bin/cp -f /opt/local/lib/libportaudio.2.dylib iShareUI.app/Contents/Frameworks
+
+	install_name_tool -change /opt/local/lib/libSDL-1.2.0.dylib @executable_path/../Frameworks/libSDL-1.2.0.dylib iShareUI.app/Contents/Frameworks/libsail.dylib
+	install_name_tool -change /opt/local/lib/libGLEW.1.5.0.dylib @executable_path/../Frameworks/libGLEW.1.5.0.dylib iShareUI.app/Contents/Frameworks/libsail.dylib
+	install_name_tool -change /opt/local/lib/libportaudio.2.dylib @executable_path/../Frameworks/libportaudio.2.dylib iShareUI.app/Contents/Frameworks/libsail.dylib
+	install_name_tool -change libsail.dylib @executable_path/../Frameworks/libsail.dylib iShareUI.app/Contents/MacOS/iShareUI
+
+	/bin/cp -f version.plist iShareUI.app/Contents/
+	/bin/cp -f InfoPlist.strings iShareUI.app/Contents/Resources/English.lproj/
+
+	Rez -d __DARWIN__ -t APPL -d __WXMAC__ -i . -d WXUSINGDLL -o iShareUI Carbon.r mac.r
+
+	sed -e "s/IDENTIFIER/`echo . | sed -e 's,\.\./,,g' | sed -e 's,/,.,g'`/" \
+		-e "s/EXECUTABLE/iShareUI/" \
+		-e "s/VERSION/2.8.8/" \
+		Info.plist.in > iShareUI.app/Contents/Info.plist
+
+	echo -n 'APPL????' > iShareUI.app/Contents/PkgInfo
+	/bin/cp -f iShareUIMacIcons.icns AnotherResource.txt iShareUI.app/Contents/Resources/
+
+clean:
+	/bin/rm -fr *~ *.o $(PROGRAM) iShareUI.app iShareUI
+
Index: trunk/src/testing/app/ishare/ui.cpp
===================================================================
--- trunk/src/testing/app/ishare/ui.cpp	(revision 4)
+++ trunk/src/testing/app/ishare/ui.cpp	(revision 4)
@@ -0,0 +1,467 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "wx/wx.h"
+#include "wx/statline.h"
+
+#include "sail.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+//#include <Carbon/Carbon.h>
+
+#include <sys/time.h>
+
+#include "libdxt.h"
+
+
+// headers for SAGE
+GLubyte *rgbBuffer = NULL;
+GLubyte *dxtBuffer = NULL;
+sail sageInf; // sail object
+
+class MyApp: public wxApp
+{
+virtual bool OnInit();
+};
+
+
+class MyFrame: public wxFrame
+{
+public:
+
+  MyFrame(const wxString& title);
+
+  void OnQuit(wxCommandEvent& event);
+  void OnAbout(wxCommandEvent& event);
+  void OnTimer(wxTimerEvent& event);
+  void OnStream(wxCommandEvent& event);
+  void OnStop(wxCommandEvent& event);
+  void OnSlide(wxScrollEvent& event);
+  void OnAddress(wxCommandEvent& event);
+  void OnCompressionNo(wxCommandEvent& event);
+  void OnCompression(wxCommandEvent& event);
+
+  DECLARE_EVENT_TABLE()
+
+private:
+  double startt;
+  int count;
+
+  wxTimer m_timer;
+  int FrameRate;
+  wxString Address;
+  int started;
+  wxCheckBox *rb1, *rb2;
+  int Compression;
+  CGLContextObj  glContextObj;
+  int WW, HH;
+  void capture(char* m_pFrameRGB,int x,int y,int cx,int cy);
+
+};
+
+
+enum
+{
+	ID_Quit = 100,
+	ID_About,
+	TIMER_ID,
+	STREAM_ID,
+	STOP_ID,
+	SLIDER_ID,
+	ADDRESS_ID,
+	COMPRESS_NO_ID, COMPRESS_ID
+};
+
+
+BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+	EVT_MENU(ID_Quit, MyFrame::OnQuit)
+	EVT_MENU(ID_About, MyFrame::OnAbout)
+	EVT_TIMER(TIMER_ID, MyFrame::OnTimer)
+	EVT_BUTTON(STREAM_ID,MyFrame::OnStream)
+	EVT_BUTTON(STOP_ID,MyFrame::OnStop)
+	EVT_COMMAND_SCROLL(SLIDER_ID,MyFrame::OnSlide)
+	EVT_TEXT(ADDRESS_ID, MyFrame::OnAddress)
+	EVT_CHECKBOX(COMPRESS_NO_ID, MyFrame::OnCompressionNo)
+	EVT_CHECKBOX(COMPRESS_ID, MyFrame::OnCompression)
+END_EVENT_TABLE()
+
+
+IMPLEMENT_APP(MyApp)
+
+
+bool MyApp::OnInit()
+{
+  MyFrame *frame = new MyFrame( _T("iShare") );
+  frame->Show(true);
+  SetTopWindow(frame);
+
+   char *sageDir = getenv("SAGE_DIRECTORY");
+   if (!sageDir) {
+      std::cout << "sageVirtualDesktop : cannot find the environment variable SAGE_DIRECTORY" << std::endl;
+      return -1;
+   }
+   int len;
+   char *dir;
+   len = strlen(sageDir);
+   dir = (char*)malloc(len+64);
+   memset(dir, 0, len+64);
+   sprintf(dir, "%s/bin", sageDir);
+   chdir(dir);
+
+
+  return true;
+}
+
+void MyFrame::capture(char* m_pFrameRGB,int x,int y,int cx,int cy)
+{
+  CGLSetCurrentContext( glContextObj ) ;
+  //CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
+  //glReadBuffer(GL_FRONT);
+
+  if (Compression)
+	  glReadPixels(x,y,cx,cy,GL_RGBA,GL_UNSIGNED_BYTE,m_pFrameRGB);
+  else
+	  glReadPixels(x,y,cx,cy,GL_RGB,GL_UNSIGNED_BYTE,m_pFrameRGB);
+
+  CGLSetCurrentContext( NULL );
+}
+
+void MyFrame::OnTimer(wxTimerEvent& event)
+{
+  if (started) {
+      if (Compression)
+	{
+	      capture((char*)rgbBuffer,0,0,WW,HH);
+	      CompressDXT(rgbBuffer, dxtBuffer, WW, HH, FORMAT_DXT1, 1);
+	      sageInf.swapBuffer();
+	      dxtBuffer = (GLubyte *)sageInf.getBuffer();
+	}
+	else
+	{
+	      capture((char*)rgbBuffer,0,0,WW,HH);
+	      sageInf.swapBuffer();
+	      rgbBuffer = (GLubyte *)sageInf.getBuffer();
+	}
+
+      sageMessage msg;
+      if (sageInf.checkMsg(msg, false) > 0) {
+	switch (msg.getCode()) {
+	case APP_QUIT:
+	  Close(true);
+	  break;
+	}
+      }
+
+
+	wxString str;
+	double nowt = aTime();
+	double fps = 1.0 / (nowt - startt);
+	startt = nowt;
+	str.Printf(wxT("Interval %d ms / Rate %.2f / Frame %d / Compression %d / Desktop %dx%d"),
+			event.GetInterval(),fps,count++, Compression, WW, HH);
+	SetStatusText( str );
+
+  }
+}
+
+
+void MyFrame::OnStream(wxCommandEvent& event)
+{
+  if (!started) {
+
+	FindWindow(ADDRESS_ID)->Disable();
+	FindWindow(STREAM_ID)->Disable();
+	FindWindow(COMPRESS_NO_ID)->Disable();
+	FindWindow(COMPRESS_ID)->Disable();
+
+  wxString str;
+  str.Printf(wxT("Stream !"));
+  SetStatusText( str );
+  started = 1;
+
+
+  sageRect ishareImageMap;
+  ishareImageMap.left = 0.0;
+  ishareImageMap.right = 1.0;
+  ishareImageMap.bottom = 0.0;
+  ishareImageMap.top = 1.0;
+
+  sailConfig scfg;
+  scfg.init("ishare.conf");
+  scfg.setAppName("ishare");
+  scfg.rank = 0;
+
+  scfg.resX = WW;
+  scfg.resY = HH;
+  scfg.winWidth  = 2*WW;
+  scfg.winHeight = 2*HH;
+  scfg.imageMap = ishareImageMap;
+
+  if (Compression)
+	  scfg.pixFmt = PIXFMT_DXT; // PIXFMT_888;
+  else
+	  scfg.pixFmt = PIXFMT_888;
+
+  scfg.rowOrd = BOTTOM_TO_TOP;
+  scfg.master = true;
+
+  sageInf.init(scfg);
+
+  if (Compression) {
+	  dxtBuffer = (GLubyte *)sageInf.getBuffer();
+	  if (rgbBuffer) delete [] rgbBuffer;
+	  rgbBuffer = (byte*)memalign(16, WW*HH*4);
+	  memset(rgbBuffer, 0,  WW*HH*4);
+  }
+  else {
+	  rgbBuffer = (GLubyte *)sageInf.getBuffer();
+  }
+
+  // xx second interval
+  m_timer.Start(1000.0/FrameRate, wxTIMER_CONTINUOUS);
+  }
+}
+
+void MyFrame::OnStop(wxCommandEvent& event)
+{
+  wxString str;
+  str.Printf(wxT("Stop !"));
+  SetStatusText( str );
+  started = 0;
+}
+
+void MyFrame::OnSlide(wxScrollEvent& event)
+{
+  FrameRate = event.GetPosition();
+  m_timer.Start(1000.0/FrameRate, wxTIMER_CONTINUOUS);
+}
+
+void MyFrame::OnAddress(wxCommandEvent& event)
+{
+  Address = event.GetString();
+  SetStatusText( Address );
+}
+
+void MyFrame::OnCompression(wxCommandEvent& event)
+{
+  if (!started) {
+  if (event.IsChecked()) {
+    rb2->SetValue(false);
+    Compression = 1;
+  }
+  else {
+    rb2->SetValue(true);
+    Compression = 0;
+  }
+  }
+}
+
+void MyFrame::OnCompressionNo(wxCommandEvent& event)
+{
+  if (event.IsChecked()) {
+    rb1->SetValue(false);
+    Compression = 0;
+  }
+  else {
+    rb1->SetValue(true);
+    Compression = 1;
+  }
+}
+
+
+MyFrame::MyFrame(const wxString& title)
+  : wxFrame((wxFrame *)NULL,wxID_ANY, title, wxDefaultPosition, wxSize(450, 330)),
+    m_timer(this, TIMER_ID), FrameRate(5), started(0), Compression(1)
+{
+        // Initialize some timing functions and else (DXT)
+  aInitialize();
+
+  startt = aTime();
+  count = 0;
+
+  wxColour col1, col2;
+  col1.Set(wxT("#e8e8e8"));
+  col2.Set(wxT("#e8e8e8"));
+
+  // Main panel
+  wxPanel *panel = new wxPanel(this, -1);
+  panel->SetBackgroundColour(col1);
+
+  // Vertical sizer
+  wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
+
+  // Panel inside the sizer
+  wxPanel *midPan = new wxPanel(panel, wxID_ANY);
+  midPan->SetBackgroundColour(col2);
+
+  vbox->Add(midPan, 1, wxEXPAND | wxALL, 20);
+  panel->SetSizer(vbox);
+
+
+  // Labels with text box
+  wxGridSizer *hbox1 = new wxGridSizer(2,2, 10,10);
+
+  Address = wxT("131.193.78.203");
+
+  wxStaticText *st1 =  new wxStaticText(midPan, wxID_ANY, wxT("SAGE IP address"), wxDefaultPosition, wxSize(128,20), wxALIGN_RIGHT);
+  hbox1->Add(st1, 1, wxRIGHT);
+  wxTextCtrl *tc1 = new wxTextCtrl(midPan, ADDRESS_ID, Address, wxDefaultPosition, wxSize(128,20));
+  hbox1->Add(tc1, 1, wxLEFT|wxRIGHT);
+  hbox1->Add(-1, 0);
+  hbox1->Add(-1, 0);
+
+  // Slider with text box
+  wxStaticText *st2 =  new wxStaticText(midPan, wxID_ANY, wxT("Frame rate"), wxDefaultPosition, wxSize(128,20), wxALIGN_RIGHT);
+  hbox1->Add(st2, 1, wxRIGHT);
+  wxSlider *tc2 = new wxSlider(midPan, SLIDER_ID, FrameRate, 1, 30, wxDefaultPosition, wxSize(128,20),
+			       wxSL_HORIZONTAL|wxSL_AUTOTICKS|wxSL_LABELS);
+  hbox1->Add(tc2, 1, wxLEFT);
+
+  // Label with text box
+  wxStaticText *st3 =  new wxStaticText(midPan, wxID_ANY, wxT("Compression"), wxDefaultPosition, wxSize(128,20), wxALIGN_RIGHT);
+  hbox1->Add(-1, 4);
+  hbox1->Add(-1, 4);
+  hbox1->Add(st3, 1, wxRIGHT);
+
+  // Radio buttons
+  wxBoxSizer *hbox4 = new wxBoxSizer(wxHORIZONTAL);
+  rb1 = new wxCheckBox(midPan, COMPRESS_ID, wxT("On"));
+  rb1->SetValue(true);
+  rb2 = new wxCheckBox(midPan, COMPRESS_NO_ID, wxT("Off"));
+  hbox4->Add(rb1, 1, wxEXPAND);
+  hbox4->AddSpacer(20);
+  hbox4->Add(rb2, 1, wxEXPAND);
+  hbox1->Add(hbox4, 1, wxALIGN_LEFT);
+
+
+
+  // Line
+  wxStaticLine *line1 = new wxStaticLine(midPan, -1, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
+
+
+  // Two buttons
+  wxBoxSizer *hbox3 = new wxBoxSizer(wxHORIZONTAL);
+
+  wxButton *ok = new wxButton(midPan, STREAM_ID, wxT("Stream"));
+  wxButton *cancel = new wxButton(midPan, STOP_ID, wxT("Stop"));
+
+  hbox3->Add(ok, 1, wxEXPAND | wxALL, 20);
+  hbox3->Add(cancel, 1, wxEXPAND | wxALL, 20);
+
+  // Vertical sizer for elements
+  wxBoxSizer *vbox2 = new wxBoxSizer(wxVERTICAL);
+
+  vbox2->Add(hbox1, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 10);
+  vbox2->Add(-1, 40);
+
+  vbox2->Add(line1, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
+  vbox2->Add(-1, 10);
+
+  vbox2->Add(hbox3, 1, wxEXPAND);
+
+  midPan->SetSizer(vbox2);
+
+
+  // Menu
+  wxMenu *menuFile = new wxMenu;
+
+  menuFile->Append( ID_About, _T("&About...") );
+  menuFile->AppendSeparator();
+  menuFile->Append( ID_Quit, _T("E&xit") );
+
+  wxMenuBar *menuBar = new wxMenuBar;
+  menuBar->Append( menuFile, _T("&File") );
+
+  SetMenuBar( menuBar );
+
+  CreateStatusBar();
+  SetStatusText( _T("iShare, SAGE desktop sharing for Mac") );
+
+  wxMessageBox(_T("iShare desktop sharing for Mac v1.0"),
+	       _T("iShare"), wxOK | wxICON_INFORMATION, this);
+
+  /////////////////////////
+  // Get the OpenGL context
+  CGLPixelFormatObj pixelFormatObj ;
+  GLint numPixelFormats ;
+  CGDirectDisplayID displayId = CGMainDisplayID();
+  CGRect dRect = CGDisplayBounds( displayId );
+  WW = dRect.size.width;
+  HH = dRect.size.height;
+  CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask(displayId);
+
+  CGLPixelFormatAttribute attribs[] =
+    {
+      (CGLPixelFormatAttribute)kCGLPFAFullScreen,
+      (CGLPixelFormatAttribute)kCGLPFADisplayMask,
+      (CGLPixelFormatAttribute)displayMask,
+      (CGLPixelFormatAttribute)0
+    };
+  CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
+  CGLCreateContext( pixelFormatObj, NULL, &glContextObj ) ;
+  CGLDestroyPixelFormat( pixelFormatObj ) ;
+  CGLSetCurrentContext( glContextObj ) ;
+  glReadBuffer(GL_FRONT);
+  CGLSetFullScreen( glContextObj ) ;///UUUUUUUUUUnbelievable
+  CGLSetCurrentContext( NULL );
+}
+
+
+void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+{
+  CGLClearDrawable( glContextObj );
+  CGLDestroyContext( glContextObj );
+
+  Close(true);
+}
+
+void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+{
+  wxMessageBox(_T("iShare desktop sharing for Mac v1.0"),
+	       _T("iShare"), wxOK | wxICON_INFORMATION, this);
+}
+
+
Index: trunk/src/testing/app/ishare/ishare.conf
===================================================================
--- trunk/src/testing/app/ishare/ishare.conf	(revision 4)
+++ trunk/src/testing/app/ishare/ishare.conf	(revision 4)
@@ -0,0 +1,21 @@
+bridgeOn true
+bridgeIP 131.193.78.203
+bridgePort 42000
+fsIP 131.193.78.203
+fsPort 20002
+masterIP 127.0.0.1
+nwID     1
+msgPort  23010
+syncPort 13010
+nodeNum  1
+appID    2
+pixelBlockSize 64 64
+blockThreshold 0
+winX 0
+winY 0
+winWidth 1024
+winHeight 768
+syncMode 0
+nwProtocol TCP
+asyncUpdate false
+frameRate 30
Index: trunk/src/testing/app/ishare/mac.r
===================================================================
--- trunk/src/testing/app/ishare/mac.r	(revision 4)
+++ trunk/src/testing/app/ishare/mac.r	(revision 4)
@@ -0,0 +1,13 @@
+data 'MBAR' (128) {
+	$"0001 0080"                                          /* ... */
+};
+
+data 'MENU' (128, "Apple") {
+	$"0080 0000 0000 0000 0000 FFFF FFFB 0114"            /* .........ÿÿÿû.. */
+	$"0A41 626F 7574 2046 4C54 4B00 0000 0001"            /* ÂAbout FLTK..... */
+	$"2D00 0000 0000"                                     /* -..... */
+};
+
+data 'carb' (0) {
+};
+
Index: trunk/src/testing/app/render/Makefile
===================================================================
--- trunk/src/testing/app/render/Makefile	(revision 4)
+++ trunk/src/testing/app/render/Makefile	(revision 4)
@@ -0,0 +1,38 @@
+
+###################################################################
+# Makefile for render
+###################################################################
+include ../../config.mk
+QUANTA_DIR=../../QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L../../lib -lquanta
+
+COMPILER_FLAGS=$(SAGE_CFLAGS) -O3 -I../../include $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS) $(GLUT_CFLAGS)
+
+
+ifeq ($(MACHINE), Darwin)
+   COMPILER_FLAGS  += -FGLUT -FOpenGL
+   LIBS=-lpthread -L../../lib -lsail -framework GLUT -framework OpenGL -lobjc -lm 
+else
+   LIBS=-lpthread ${SUN_LIBS} -lm -ldl $(GLUT_LDFLAGS) -lGL -lGLU $(QUANTA_LDFLAGS) $(GLEW_LIB) -L../../lib -lsail
+endif
+
+
+
+default: render
+
+install: default
+	cp render ../../bin
+
+render: render.o
+	$(COMPILER) $(SAGE_LDFLAGS) -o render render.o $(LIBS)
+
+render-mpi: render-mpi.cpp
+	mpiCC -o render-mpi render-mpi.cpp  $(COMPILER_FLAGS) $(INCLUDE_DIR)  $(LIBRARY_DIR) $(LIBRARIES)
+
+render.o:       render.cxx
+	$(COMPILER) $(COMPILER_FLAGS) $(INCLUDE_DIR) -c render.cxx
+
+clean:
+	\rm -f *~ *.o $(PROJ_EXE)
+
Index: trunk/src/testing/app/render/render.cxx
===================================================================
--- trunk/src/testing/app/render/render.cxx	(revision 4)
+++ trunk/src/testing/app/render/render.cxx	(revision 4)
@@ -0,0 +1,476 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu
+ *****************************************************************************/
+ 
+//Shalini Venkataraman
+//A simple glut program that draws spheres and cones, reads the frame buffer 
+//and sends it across to a display client
+//Feb 2004
+//
+//modified by Byungil Jeong
+//July 2004
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include <time.h>
+#ifdef WIN32
+#include "gettimeofday.hxx"
+#else
+#include <sys/timeb.h>
+#include <sys/time.h>
+#endif                        
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+#define PI 3.1415926535898f
+#define DEG_TO_RAD PI/180.0f
+#define TRANSLATION_RATE 0.2f
+#define ROTATION_RATE 0.01f
+
+enum {SPHERE = 1, CONE};
+enum {X, Y, Z};
+
+int winWidth = 400, winHeight = 400;
+bool refresh = false;
+int cnt, target;
+float rgbReadTime;
+GLubyte *rgbBuffer = 0;
+GLfloat transformMatrix[] = {1.0, 0.0, 0.0, 0.0,
+				0.0, 1.0, 0.0, 0.0, 
+				0.0, 0.0, 1.0, 0.0,
+				0.0, 0.0, 0.0, 1.0};
+
+float eyeX, eyeY, eyeZ; //for the camera position for glulookat
+float centreX, centreY, centreZ; //the point the camera looks at in glulookat
+float rot = 0.0f;
+sail sageInf; // sail object
+
+
+double getTimeInSecs() {
+    const double oneMicroSec = 0.000001;
+	struct timeval timeSec;
+	gettimeofday(&timeSec, NULL);
+	return (((double) timeSec.tv_sec) +
+		(((double) timeSec.tv_usec) * oneMicroSec));
+	
+}    
+
+void rotateCameraY(float rot_inc) {
+	rot += rot_inc;
+	centreX = eyeX - sin(rot);
+	centreZ = eyeZ - cos(rot);
+}
+
+void moveCameraZ(float trans_inc) {
+	float inc_x = -trans_inc*sin(rot); //increment in camera X for the given translation
+	float inc_z = -trans_inc*cos(rot); //increment in camera Y for the given translation
+	eyeX += inc_x;
+	eyeZ += inc_z;
+	centreX += inc_x;
+	centreZ += inc_z;
+}
+
+void moveCameraY(float trans_inc) {
+	eyeY += trans_inc;
+	centreY += trans_inc;
+}
+
+GLfloat *make_texture(int maxs, int maxt)
+{
+    int s, t;
+    static GLfloat *texture;
+	
+    texture = (GLfloat *)malloc(3*maxs * maxt * sizeof(GLfloat));
+    for(t = 0; t < maxt; t++) {
+		for(s = 0; s < maxs; s++) {
+			texture[s*3 + 3*maxs * t] = 0.0f;
+			texture[s*3 + 3*maxs * t+1] = 0.4f*(((s >> 4) & 0x1) ^ ((t >> 4) & 0x1));
+			texture[s*3 + 3*maxs * t+2] = 0.0f*(((s >> 4) & 0x1) ^ ((t >> 4) & 0x1));
+		}
+    }
+    return texture;
+}
+
+//writes the grabbed framebuffer to a ppm file
+void writePPM(const char* filename) {
+	if (!rgbBuffer)
+                return;
+        FILE* fp = fopen(filename, "wb");
+        if (fp==NULL) { printf("PPM ERROR (WritePPM) : unable to open %s!\n",filename); return; }
+        fprintf(fp, "P6\n%d %d\n255\n", winWidth, winHeight);
+        fwrite(rgbBuffer,sizeof(GLubyte),winWidth*winHeight*3,fp);
+        fclose(fp);
+	printf("RGB data written to file %s\n",filename); 
+}
+
+//key handler
+//'s' - will save the grabbed image to a ppm file
+void key(unsigned char key, int x, int y)
+{
+	switch(key) {
+		case 's': //save the read pixels to out.ppm
+		writePPM("out.ppm");
+		break;
+	case 't': //display time taken for readpixels
+		printf("Frame Buffer Readback Time: %dx%d %f \n",winWidth, winHeight, rgbReadTime);
+		break;
+	case '\033':
+		sageInf.shutdown();
+		exit(0);
+		break;
+    }
+	glutPostRedisplay();
+}
+
+// The function called whenever a "special" key is pressed.
+void special(int key, int x, int y) 
+{
+	switch (key) {    
+		case GLUT_KEY_UP:
+			moveCameraZ(TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_DOWN:
+			moveCameraZ(-TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_LEFT:
+			rotateCameraY(ROTATION_RATE);
+			break;
+		case GLUT_KEY_RIGHT:
+			rotateCameraY(-ROTATION_RATE);
+			break;
+		case GLUT_KEY_PAGE_UP:
+			moveCameraY(TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_PAGE_DOWN:
+			moveCameraY(-TRANSLATION_RATE);
+			break;
+	}
+	glutPostRedisplay();
+}
+
+void
+motion(int x, int y)
+{
+    y = winHeight - y;
+    glutPostRedisplay();
+	
+}
+
+/*
+//reallocate the rgbBuffer depending on the new window dimesions
+void
+reshape(int width, int height)
+{
+    glViewport(0, 0, width, height);
+    winWidth = width;
+    winHeight = height;	
+    if (rgbBuffer)
+	    delete [] rgbBuffer;
+    rgbBuffer = new GLubyte[width*height*3];
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+	gluPerspective(40.0,(GLfloat)width/ (GLfloat)height, 0.5, 100.0);
+    glMatrixMode(GL_MODELVIEW);
+}
+
+*/
+
+void
+mouse(int button, int state, int x, int y)
+{
+    y = winHeight - y; 
+    if(state == GLUT_DOWN) {
+		switch(button) {
+		case GLUT_LEFT_BUTTON: //rotate
+			break;
+		case GLUT_MIDDLE_BUTTON: //zoom
+			break;
+		case GLUT_RIGHT_BUTTON: 
+			break;
+		}
+	}
+    else {//GLUT_UP 
+		switch(button) {
+		case GLUT_LEFT_BUTTON:
+			break;
+		case GLUT_MIDDLE_BUTTON:
+			break;
+		case GLUT_RIGHT_BUTTON: 
+			break;
+		}
+	}
+	glutPostRedisplay();
+}
+
+
+//display function
+void redraw(void)
+{
+   /* material properties for objects in scene */
+   static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
+   static GLfloat sphere_mat[] = {0.5f, 0.0f, 1.f, 1.f};
+   static GLfloat cone_mat[] = {1.0f, 0.5f, 0.0f, 1.f};
+   static GLfloat sphere_mat2[] = {1.0f, 0.0f, 0.5f, 1.f};
+   static GLfloat cone_mat2[] = {0.0f, 0.5f, 1.0f, 1.f};
+   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+	glClearColor(0.0, 0.0, 0.2, 0.0);
+	glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+	gluLookAt(eyeX, eyeY, eyeZ,
+		centreX, centreY, centreZ,
+		0.0,1.0,0.0);
+   /*
+    ** Note: wall verticies are ordered so they are all front facing
+    ** this lets me do back face culling to speed things up.
+    */
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
+	
+    glEnable(GL_TEXTURE_2D);	
+    glBegin(GL_QUADS);
+    glNormal3f(0.f, 1.f, 0.f);
+    glTexCoord2i(0, 0);
+    glVertex3f(-6.f, -4.f, -2.f);
+    glTexCoord2i(1, 0);
+    glVertex3f( 6.f, -4.f, -2.f);
+    glTexCoord2i(1, 1);
+    glVertex3f( 6.f, -4.f, -15.f);
+    glTexCoord2i(0, 1);
+    glVertex3f(-6.f, -4.f, -15.f);
+    glEnd();	
+    glDisable(GL_TEXTURE_2D);
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
+    glPushMatrix();
+    glTranslatef(-3.f, 0.5f, -10.f);
+    glScalef(1, 1, 1);
+    glCallList(SPHERE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
+    glPushMatrix();
+    glTranslatef(0.f, 0.3f, -3.f);
+    glRotatef(30.f, 2.f, 0.0, -1.0f);
+    glScalef(1.0, 1.0, 1.0);
+    glCallList(CONE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat2);
+    glPushMatrix();
+    glTranslatef(-2.f, -2.f, -7.f);
+    glScalef(1, 1, 1);
+    glCallList(SPHERE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat2);
+    glPushMatrix();
+    glTranslatef(4.f, -2.f, -13.f);
+    glRotatef(-45.f, 1.f, 0.0f, 0.0f);
+    glScalef(0.8, 0.8, 0.8);
+    glCallList(CONE);
+    glPopMatrix();
+	
+    //finished drawing. At this point capture the frame buffer
+    //expensive new!! TODO: put this in reshape
+	
+	double prevtime = getTimeInSecs();
+   glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);
+   rgbReadTime = getTimeInSecs()-prevtime;
+	//TODO-send it to QUANTA
+
+	sageInf.swapBuffer();
+	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+//	if (refresh) {
+//		cnt++;
+//		if (cnt >= target)
+//			refresh = false;
+//	}		
+	
+   glutSwapBuffers();
+}
+
+void update(int value) {
+	//std::cout << "swap buffer " << winWidth << "," << winHeight << std::endl;
+//	sageInf.swapBuffer((void *)rgbBuffer);
+//	sageInf.mainLoop();
+	
+	//glutPostRedisplay();
+	sageMessage msg;
+	
+	if (sageInf.checkMsg(msg, false) > 0) {
+		switch (msg.getCode()) {
+			case APP_QUIT : {
+				exit(0);
+				break;
+			}
+			
+			//case APP_REFRESH_FRAME : {
+				//glutPostRedisplay();
+				//refresh = true;
+				//target = atoi((char *)msg.getData());
+				//cnt = 0;
+				//break;
+		//	} 
+		}	
+	}
+	
+//	if (refresh)	{
+//		glutPostRedisplay();
+//	}
+	
+	glutTimerFunc(50, update, 1);
+}
+
+
+main(int argc, char *argv[])
+{
+    GLfloat *tex;
+    static GLfloat lightpos[] = {10.f, 10.f, -20.0f, 1.f};
+    GLUquadricObj *sphere, *cone, *base;
+	
+    glutInit(&argc, argv);
+	
+    glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
+    glutInitWindowSize(winWidth,winHeight);	 
+    glutCreateWindow("sage render");
+    glutDisplayFunc(redraw);
+    //glutIdleFunc(redraw);
+    glutKeyboardFunc(key);
+    glutMouseFunc(mouse);
+    glutMotionFunc(motion);
+    glutSpecialFunc(special);
+//	glutReshapeFunc(reshape);
+	
+	 glViewport(0, 0, winWidth, winHeight);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+	gluPerspective(40.0,(GLfloat)winWidth/ (GLfloat)winHeight, 0.5, 100.0);
+    glMatrixMode(GL_MODELVIEW);
+	//glutFullScreen();
+	
+    glMatrixMode(GL_MODELVIEW);
+	
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
+	
+    glCullFace(GL_BACK);
+	
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	
+    //create the display list to draw a sphere
+    glNewList(SPHERE, GL_COMPILE);
+    sphere = gluNewQuadric();
+    gluSphere(sphere, 1.f, 20, 20);
+    gluDeleteQuadric(sphere);
+    glEndList();
+	
+    //create the display list to draw a cone
+    glNewList(CONE, GL_COMPILE);
+    cone = gluNewQuadric();
+    base = gluNewQuadric();
+    glRotatef(-90.f, 1.f, 0.f, 0.f);
+    gluQuadricOrientation(base, GLU_INSIDE);
+    gluDisk(base, 0., 1., 20, 1);
+    gluCylinder(cone, 1., 0., 2., 20, 20);
+    gluDeleteQuadric(cone);
+    gluDeleteQuadric(base);
+    glEndList();
+	
+    //create a 2D texture for our floor
+    tex = make_texture(256, 256);
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_FLOAT, tex);
+    free(tex);
+
+    eyeX = eyeY = centreX = centreY = 0.0f;
+    eyeZ = 10.0f; centreZ = 9.0f;
+	 
+	 glutTimerFunc(100, update, 1);
+	 
+	 int appID;
+	 if (argc < 2)
+	 	appID = 0;
+	 else
+	 	appID = atoi(argv[1]);
+		
+	 int nodeID;
+	 if (argc < 3)
+	 	 nodeID = 0;
+	 else
+	 	 nodeID = atoi(argv[2]);
+
+	 sailConfig cfg;
+	 cfg.init("render.conf");   // every app has a config file named "appName.conf"
+ 	 std::cout << "SAIL configuration was initialized by render.conf" << std::endl;
+	 
+	 cfg.setAppName("render");
+	 cfg.rank = nodeID;
+	 //cfg.appID = appID;   //appLauncher will do this
+	 cfg.resX = winWidth;
+	 cfg.resY = winHeight;
+
+	 sageRect renderImageMap;
+	 renderImageMap.left = 0.0;
+	 renderImageMap.right = 1.0;
+	 renderImageMap.bottom = 0.0;
+	 renderImageMap.top = 1.0;
+
+	 cfg.imageMap = renderImageMap;
+	 cfg.pixFmt = PIXFMT_888;
+	 cfg.rowOrd = BOTTOM_TO_TOP;
+	 cfg.master = true;
+	 		 
+	 sageInf.init(cfg);
+	 std::cout << "sail initialized " << std::endl;
+	 	 
+    if (rgbBuffer)
+	    delete [] rgbBuffer;
+    
+	 rgbBuffer = (GLubyte *)sageInf.getBuffer();
+
+	 glutMainLoop();
+	
+    return 0;
+}
Index: trunk/src/testing/app/render/render-mpi.cpp
===================================================================
--- trunk/src/testing/app/render/render-mpi.cpp	(revision 4)
+++ trunk/src/testing/app/render/render-mpi.cpp	(revision 4)
@@ -0,0 +1,439 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu
+ *****************************************************************************/
+
+//Shalini Venkataraman
+//A simple glut program that draws spheres and cones, reads the frame buffer 
+//and sends it across to a display client
+//Feb 2004
+//
+//modified by Byungil Jeong
+//July 2004
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+
+#include <time.h>
+#ifdef WIN32
+#include "gettimeofday.hxx"
+#else
+#include <sys/timeb.h>
+#include <sys/time.h>
+#endif                        
+
+// headers for SAGE
+#include "sail.h"
+#include "misc.h"
+
+#include <mpi.h>
+
+#define PI 3.1415926535898f
+#define DEG_TO_RAD PI/180.0f
+#define TRANSLATION_RATE 0.2f
+#define ROTATION_RATE 0.01f
+
+    int rank = 0;  // node rank
+    int size = 0;  // number of nodes
+
+enum {SPHERE = 1, CONE};
+enum {X, Y, Z};
+
+int winWidth, winHeight;
+float rgbReadTime;
+GLubyte *rgbBuffer = 0;
+GLfloat transformMatrix[] = {1.0, 0.0, 0.0, 0.0,
+				0.0, 1.0, 0.0, 0.0, 
+				0.0, 0.0, 1.0, 0.0,
+				0.0, 0.0, 0.0, 1.0};
+
+float eyeX, eyeY, eyeZ; //for the camera position for glulookat
+float centreX, centreY, centreZ; //the point the camera looks at in glulookat
+float rot = 0.0f;
+sail sageInf; // sail object
+
+
+double getTimeInSecs() {
+    const double oneMicroSec = 0.000001;
+	struct timeval timeSec;
+	gettimeofday(&timeSec, NULL);
+	return (((double) timeSec.tv_sec) +
+		(((double) timeSec.tv_usec) * oneMicroSec));
+	
+}    
+
+void rotateCameraY(float rot_inc) {
+	rot += rot_inc;
+	centreX = eyeX - sin(rot);
+	centreZ = eyeZ - cos(rot);
+}
+
+void moveCameraZ(float trans_inc) {
+	float inc_x = -trans_inc*sin(rot); //increment in camera X for the given translation
+	float inc_z = -trans_inc*cos(rot); //increment in camera Y for the given translation
+	eyeX += inc_x;
+	eyeZ += inc_z;
+	centreX += inc_x;
+	centreZ += inc_z;
+}
+
+void moveCameraY(float trans_inc) {
+	eyeY += trans_inc;
+	centreY += trans_inc;
+}
+
+GLfloat *make_texture(int maxs, int maxt)
+{
+    int s, t;
+    static GLfloat *texture;
+	
+    texture = (GLfloat *)malloc(3*maxs * maxt * sizeof(GLfloat));
+    for(t = 0; t < maxt; t++) {
+		for(s = 0; s < maxs; s++) {
+			texture[s*3 + 3*maxs * t] = 0.0f;
+			texture[s*3 + 3*maxs * t+1] = 0.4f*(((s >> 4) & 0x1) ^ ((t >> 4) & 0x1));
+			texture[s*3 + 3*maxs * t+2] = 0.0f*(((s >> 4) & 0x1) ^ ((t >> 4) & 0x1));
+		}
+    }
+    return texture;
+}
+
+//writes the grabbed framebuffer to a ppm file
+void writePPM(const char* filename) {
+	if (!rgbBuffer)
+                return;
+        FILE* fp = fopen(filename, "wb");
+        if (fp==NULL) { printf("PPM ERROR (WritePPM) : unable to open %s!\n",filename); return; }
+        fprintf(fp, "P6\n%d %d\n255\n", winWidth, winHeight);
+        fwrite(rgbBuffer,sizeof(GLubyte),winWidth*winHeight*3,fp);
+        fclose(fp);
+	printf("RGB data written to file %s\n",filename); 
+}
+
+//key handler
+//'s' - will save the grabbed image to a ppm file
+void key(unsigned char key, int x, int y)
+{
+	switch(key) {
+		case 's': //save the read pixels to out.ppm
+		writePPM("out.ppm");
+		break;
+	case 't': //display time taken for readpixels
+		printf("Frame Buffer Readback Time: %dx%d %f \n",winWidth, winHeight, rgbReadTime);
+		break;
+	case '\033':
+            // finalize
+        MPI_Finalize();
+        
+		exit(0);
+		break;
+    }
+	glutPostRedisplay();
+}
+
+// The function called whenever a "special" key is pressed.
+void special(int key, int x, int y) 
+{
+	switch (key) {    
+		case GLUT_KEY_UP:
+			moveCameraZ(TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_DOWN:
+			moveCameraZ(-TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_LEFT:
+			rotateCameraY(ROTATION_RATE);
+			break;
+		case GLUT_KEY_RIGHT:
+			rotateCameraY(-ROTATION_RATE);
+			break;
+		case GLUT_KEY_PAGE_UP:
+			moveCameraY(TRANSLATION_RATE);
+			break;
+		case GLUT_KEY_PAGE_DOWN:
+			moveCameraY(-TRANSLATION_RATE);
+			break;
+	}
+	glutPostRedisplay();
+}
+
+void idle()
+{
+	glutPostRedisplay();
+}
+
+void
+motion(int x, int y)
+{
+    y = winHeight - y;
+    glutPostRedisplay();
+	
+}
+
+//reallocate the rgbBuffer depending on the new window dimesions
+void
+reshape(int width, int height)
+{
+    glViewport(0, 0, width, height);
+    winWidth = width;
+    winHeight = height;	
+    if (rgbBuffer)
+	    delete [] rgbBuffer;
+    rgbBuffer = new GLubyte[width*height*3];
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+	gluPerspective(40.0,(GLfloat)width/ (GLfloat)height, 0.5, 100.0);
+    glMatrixMode(GL_MODELVIEW);
+}
+
+
+void
+mouse(int button, int state, int x, int y)
+{
+    y = winHeight - y; 
+    if(state == GLUT_DOWN) {
+		switch(button) {
+		case GLUT_LEFT_BUTTON: //rotate
+			break;
+		case GLUT_MIDDLE_BUTTON: //zoom
+			break;
+		case GLUT_RIGHT_BUTTON: 
+			break;
+		}
+	}
+    else {//GLUT_UP 
+		switch(button) {
+		case GLUT_LEFT_BUTTON:
+			break;
+		case GLUT_MIDDLE_BUTTON:
+			break;
+		case GLUT_RIGHT_BUTTON: 
+			break;
+		}
+	}
+	glutPostRedisplay();
+}
+
+
+//display function
+void redraw(void)
+{
+        /* material properties for objects in scene */
+    static GLfloat wall_mat[] = {1.f, 1.f, 1.f, 1.f};
+    static GLfloat sphere_mat[] = {0.5f, 0.0f, 1.f, 1.f};
+    static GLfloat cone_mat[] = {1.0f, 0.5f, 0.0f, 1.f};
+    static GLfloat sphere_mat2[] = {1.0f, 0.0f, 0.5f, 1.f};
+    static GLfloat cone_mat2[] = {0.0f, 0.5f, 1.0f, 1.f};
+    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+	glClearColor(0.0, 0.0, 0.2, 0.0);
+	glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+	gluLookAt(eyeX, eyeY, eyeZ,
+              centreX, centreY, centreZ,
+              0.0,1.0,0.0);
+        /*
+        ** Note: wall verticies are ordered so they are all front facing
+        ** this lets me do back face culling to speed things up.
+        */
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
+	
+    glEnable(GL_TEXTURE_2D);	
+    glBegin(GL_QUADS);
+    glNormal3f(0.f, 1.f, 0.f);
+    glTexCoord2i(0, 0);
+    glVertex3f(-6.f, -4.f, -2.f);
+    glTexCoord2i(1, 0);
+    glVertex3f( 6.f, -4.f, -2.f);
+    glTexCoord2i(1, 1);
+    glVertex3f( 6.f, -4.f, -15.f);
+    glTexCoord2i(0, 1);
+    glVertex3f(-6.f, -4.f, -15.f);
+    glEnd();	
+    glDisable(GL_TEXTURE_2D);
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
+    glPushMatrix();
+    glTranslatef(-3.f, 0.5f, -10.f);
+    glScalef(1, 1, 1);
+    glCallList(SPHERE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
+    glPushMatrix();
+    glTranslatef(0.f, 0.3f, -3.f);
+    glRotatef(30.f, 2.f, 0.0, -1.0f);
+    glScalef(1.0, 1.0, 1.0);
+    glCallList(CONE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat2);
+    glPushMatrix();
+    glTranslatef(-2.f, -2.f, -7.f);
+    glScalef(1, 1, 1);
+    glCallList(SPHERE);
+    glPopMatrix();
+	
+    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat2);
+    glPushMatrix();
+    glTranslatef(4.f, -2.f, -13.f);
+    glRotatef(-45.f, 1.f, 0.0f, 0.0f);
+    glScalef(0.8, 0.8, 0.8);
+    glCallList(CONE);
+    glPopMatrix();
+	
+        //finished drawing. At this point capture the frame buffer
+        //expensive new!! TODO: put this in reshape
+	
+	if (winWidth > 0) {
+		if (sageInf.getBufSize() == 0)
+			sageInf.resizeBuffer(winWidth, winHeight, 24);
+		
+            //cout << "read pixels" << endl;
+		double prevtime = getTimeInSecs();
+        glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);
+        rgbReadTime = getTimeInSecs()-prevtime;
+            //TODO-send it to QUANTA
+
+        cout << rank << " swap buffer " << winWidth << "," << winHeight << endl;
+	
+        MPI_Barrier(MPI_COMM_WORLD);
+
+		sageInf.swapBuffer(rgbBuffer);
+		sageInf.mainLoop();
+
+	}
+	
+    glutSwapBuffers();
+}
+
+void update(int value) {
+	
+	//sageInf.swapBuffer((unsigned char *)rgbBuffer);
+	sageInf.mainLoop();
+	
+        //glutTimerFunc(1000, update, 1);
+}
+
+main(int argc, char *argv[])
+{
+
+        // MPI Initialization
+    MPI_Init(&argc, &argv);
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    MPI_Barrier(MPI_COMM_WORLD);
+
+    GLfloat *tex;
+    static GLfloat lightpos[] = {10.f, 10.f, -20.0f, 1.f};
+    GLUquadricObj *sphere, *cone, *base;
+	
+    glutInit(&argc, argv);
+	
+    glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
+    glutInitWindowSize(1024,1024);	 
+    glutCreateWindow("sage render");
+    glutDisplayFunc(redraw);
+    glutIdleFunc(idle);
+    glutKeyboardFunc(key);
+    glutMouseFunc(mouse);
+        //glutMotionFunc(motion);
+    glutSpecialFunc(special);
+	glutReshapeFunc(reshape);
+        //glutFullScreen();
+	
+    glMatrixMode(GL_MODELVIEW);
+	
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+    glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
+	
+    glCullFace(GL_BACK);
+	
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	
+        //create the display list to draw a sphere
+    glNewList(SPHERE, GL_COMPILE);
+    sphere = gluNewQuadric();
+    gluSphere(sphere, 1.f, 20, 20);
+    gluDeleteQuadric(sphere);
+    glEndList();
+	
+        //create the display list to draw a cone
+    glNewList(CONE, GL_COMPILE);
+    cone = gluNewQuadric();
+    base = gluNewQuadric();
+    glRotatef(-90.f, 1.f, 0.f, 0.f);
+    gluQuadricOrientation(base, GLU_INSIDE);
+    gluDisk(base, 0., 1., 20, 1);
+    gluCylinder(cone, 1., 0., 2., 20, 20);
+    gluDeleteQuadric(cone);
+    gluDeleteQuadric(base);
+    glEndList();
+	
+        //create a 2D texture for our floor
+    tex = make_texture(256, 256);
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_FLOAT, tex);
+    free(tex);
+
+    eyeX = eyeY = centreX = centreY = 0.0f;
+    eyeZ = 10.0f; centreZ = 9.0f;
+	 
+        //glutTimerFunc(100, update, 1);
+	 
+    MPI_Barrier(MPI_COMM_WORLD);
+		 
+    char procname[MPI_MAX_PROCESSOR_NAME];
+    int lenproc;
+    MPI_Get_processor_name(procname, &lenproc);
+    fprintf(stderr, "Processor %2d is machine [%s]\n", rank, procname);
+
+    sageInf.init("sail.conf", "render", rank, 0, 0, 24, TVPIXFMT_888, BOTTOM_TO_TOP);
+
+    MPI_Barrier(MPI_COMM_WORLD);
+    
+    glutMainLoop();
+	
+        // finalize
+    MPI_Finalize();
+
+        // exit
+    return EXIT_SUCCESS;
+}
Index: trunk/src/testing/app/atlantis/Makefile
===================================================================
--- trunk/src/testing/app/atlantis/Makefile	(revision 4)
+++ trunk/src/testing/app/atlantis/Makefile	(revision 4)
@@ -0,0 +1,36 @@
+include ../../config.mk
+QUANTA_DIR=../../QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L../../lib -lquanta
+
+
+CFLAGS=-fPIC -O3 -I../../include $(QUANTA_CFLAGS) 
+CC=$(COMPILER)
+
+ifeq ($(MACHINE), Darwin)
+   CFLAGS+= $(SAGE_CFLAGS) -FGLUT -FOpenGL
+   LIBS= $(SAGE_LDFLAGS) -lpthread -L../../lib -lsail -framework GLUT -framework OpenGL -lobjc -lm 
+else
+ifeq ($(MACHINE), SunOS)
+   CFLAGS=$(SAGE_CFLAGS) -O3 -I../../include $(QUANTA_CFLAGS) $(GLUT_CFLAGS) 
+   LIBS=-lpthread -lm -lGL -lGLU $(QUANTA_LDFLAGS) -L../../lib -lsail $(GLUT_LDFLAGS) 
+else
+   LIBS=-lpthread -lm -lGL -lGLU $(GLUT_LDFLAGS) $(QUANTA_LDFLAGS) $(GLEW_LIB) -L../../lib -lsail
+endif
+endif
+
+PROGRAM = atlantis
+
+FILES = atlantis.o dolphin.o shark.o swim.o whale.o
+
+default: $(PROGRAM)
+
+install: $(PROGRAM)
+	cp $(PROGRAM) ../../bin
+
+$(PROGRAM): $(FILES)
+	$(COMPILER) -o $(PROGRAM) $(FILES) $(SAGE_LDFLAGS) $(CFLAGS) $(LIBS)
+
+clean:
+	/bin/rm -f *~ *.o $(PROGRAM)
+
Index: trunk/src/testing/app/atlantis/dolphin.c
===================================================================
--- trunk/src/testing/app/atlantis/dolphin.c	(revision 4)
+++ trunk/src/testing/app/atlantis/dolphin.c	(revision 4)
@@ -0,0 +1,1945 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h>
+#endif
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {-0.005937 ,-0.101998 ,-0.994767};
+static float N002[3] = {0.936780 ,-0.200803 ,0.286569};
+static float N003[3] = {-0.233062 ,0.972058 ,0.028007};
+static float N005[3] = {0.898117 ,0.360171 ,0.252315};
+static float N006[3] = {-0.915437 ,0.348456 ,0.201378};
+static float N007[3] = {0.602263 ,-0.777527 ,0.180920};
+static float N008[3] = {-0.906912 ,-0.412015 ,0.088061};
+static float N012[3] = {0.884408 ,-0.429417 ,-0.182821};
+static float N013[3] = {0.921121 ,0.311084 ,-0.234016};
+static float N014[3] = {0.382635 ,0.877882 ,-0.287948};
+static float N015[3] = {-0.380046 ,0.888166 ,-0.258316};
+static float N016[3] = {-0.891515 ,0.392238 ,-0.226607};
+static float N017[3] = {-0.901419 ,-0.382002 ,-0.203763};
+static float N018[3] = {-0.367225 ,-0.911091 ,-0.187243};
+static float N019[3] = {0.339539 ,-0.924846 ,-0.171388};
+static float N020[3] = {0.914706 ,-0.378617 ,-0.141290};
+static float N021[3] = {0.950662 ,0.262713 ,-0.164994};
+static float N022[3] = {0.546359 ,0.801460 ,-0.243218};
+static float N023[3] = {-0.315796 ,0.917068 ,-0.243431};
+static float N024[3] = {-0.825687 ,0.532277 ,-0.186875};
+static float N025[3] = {-0.974763 ,-0.155232 ,-0.160435};
+static float N026[3] = {-0.560596 ,-0.816658 ,-0.137119};
+static float N027[3] = {0.380210 ,-0.910817 ,-0.160786};
+static float N028[3] = {0.923772 ,-0.358322 ,-0.135093};
+static float N029[3] = {0.951202 ,0.275053 ,-0.139859};
+static float N030[3] = {0.686099 ,0.702548 ,-0.188932};
+static float N031[3] = {-0.521865 ,0.826719 ,-0.210220};
+static float N032[3] = {-0.923820 ,0.346739 ,-0.162258};
+static float N033[3] = {-0.902095 ,-0.409995 ,-0.134646};
+static float N034[3] = {-0.509115 ,-0.848498 ,-0.144404};
+static float N035[3] = {0.456469 ,-0.880293 ,-0.129305};
+static float N036[3] = {0.873401 ,-0.475489 ,-0.105266};
+static float N037[3] = {0.970825 ,0.179861 ,-0.158584};
+static float N038[3] = {0.675609 ,0.714187 ,-0.183004};
+static float N039[3] = {-0.523574 ,0.830212 ,-0.191360};
+static float N040[3] = {-0.958895 ,0.230808 ,-0.165071};
+static float N041[3] = {-0.918285 ,-0.376803 ,-0.121542};
+static float N042[3] = {-0.622467 ,-0.774167 ,-0.114888};
+static float N043[3] = {0.404497 ,-0.908807 ,-0.102231};
+static float N044[3] = {0.930538 ,-0.365155 ,-0.027588};
+static float N045[3] = {0.921920 ,0.374157 ,-0.100345};
+static float N046[3] = {0.507346 ,0.860739 ,0.041562};
+static float N047[3] = {-0.394646 ,0.918815 ,-0.005730};
+static float N048[3] = {-0.925411 ,0.373024 ,-0.066837};
+static float N049[3] = {-0.945337 ,-0.322309 ,-0.049551};
+static float N050[3] = {-0.660437 ,-0.750557 ,-0.022072};
+static float N051[3] = {0.488835 ,-0.871950 ,-0.027261};
+static float N052[3] = {0.902599 ,-0.421397 ,0.087969};
+static float N053[3] = {0.938636 ,0.322606 ,0.122020};
+static float N054[3] = {0.484605 ,0.871078 ,0.079878};
+static float N055[3] = {-0.353607 ,0.931559 ,0.084619};
+static float N056[3] = {-0.867759 ,0.478564 ,0.134054};
+static float N057[3] = {-0.951583 ,-0.296030 ,0.082794};
+static float N058[3] = {-0.672355 ,-0.730209 ,0.121384};
+static float N059[3] = {0.528336 ,-0.842452 ,0.105525};
+static float N060[3] = {0.786913 ,-0.564760 ,0.248627};
+static float N062[3] = {0.622098 ,0.765230 ,0.165584};
+static float N063[3] = {-0.631711 ,0.767816 ,0.106773};
+static float N064[3] = {-0.687886 ,0.606351 ,0.398938};
+static float N065[3] = {-0.946327 ,-0.281623 ,0.158598};
+static float N066[3] = {-0.509549 ,-0.860437 ,0.002776};
+static float N067[3] = {0.462594 ,-0.876692 ,0.131977};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N078[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N079[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N080[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N081[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N082[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N083[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N084[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N085[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N086[3] = {-0.571197 ,0.816173 ,0.087152};
+static float N087[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N088[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N089[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N090[3] = {-0.880770 ,0.461448 ,0.106351};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N097[3] = {-0.697296 ,0.702881 ,0.140491};
+static float N098[3] = {0.918864 ,0.340821 ,0.198819};
+static float N099[3] = {-0.932737 ,0.201195 ,0.299202};
+static float N100[3] = {0.029517 ,0.981679 ,0.188244};
+static float N102[3] = {0.813521 ,-0.204936 ,0.544229};
+static float N110[3] = {-0.781480 ,-0.384779 ,0.491155};
+static float N111[3] = {-0.722243 ,0.384927 ,0.574627};
+static float N112[3] = {-0.752278 ,0.502679 ,0.425901};
+static float N113[3] = {0.547257 ,0.367910 ,0.751766};
+static float N114[3] = {0.725949 ,-0.232568 ,0.647233};
+static float N115[3] = {-0.747182 ,-0.660786 ,0.071280};
+static float N116[3] = {0.931519 ,0.200748 ,0.303270};
+static float N117[3] = {-0.828928 ,0.313757 ,0.463071};
+static float N118[3] = {0.902554 ,-0.370967 ,0.218587};
+static float N119[3] = {-0.879257 ,-0.441851 ,0.177973};
+static float N120[3] = {0.642327 ,0.611901 ,0.461512};
+static float N121[3] = {0.964817 ,-0.202322 ,0.167910};
+static float N122[3] = {0.000000 ,1.000000 ,0.000000};
+static float P001[3] = {5.68, -300.95, 1324.70};
+static float P002[3] = {338.69, -219.63, 9677.03};
+static float P003[3] = {12.18, 474.59, 9138.14};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 68.74, 9427.85};
+static float P007[3] = {156.52, -266.72, 10311.68};
+static float P008[3] = {-185.56, -266.51, 10310.47};
+static float P009[3] = {124.39, -261.46, 1942.34};
+static float P010[3] = {-130.05, -261.46, 1946.03};
+static float P011[3] = {141.07, -320.11, 1239.38};
+static float P012[3] = {156.48, -360.12, 2073.41};
+static float P013[3] = {162.00, -175.88, 2064.44};
+static float P014[3] = {88.16, -87.72, 2064.02};
+static float P015[3] = {-65.21, -96.13, 2064.02};
+static float P016[3] = {-156.48, -180.96, 2064.44};
+static float P017[3] = {-162.00, -368.93, 2082.39};
+static float P018[3] = {-88.16, -439.22, 2082.39};
+static float P019[3] = {65.21, -440.32, 2083.39};
+static float P020[3] = {246.87, -356.02, 2576.95};
+static float P021[3] = {253.17, -111.15, 2567.15};
+static float P022[3] = {132.34, 51.41, 2559.84};
+static float P023[3] = {-97.88, 40.44, 2567.15};
+static float P024[3] = {-222.97, -117.49, 2567.15};
+static float P025[3] = {-252.22, -371.53, 2569.92};
+static float P026[3] = {-108.44, -518.19, 2586.75};
+static float P027[3] = {97.88, -524.79, 2586.75};
+static float P028[3] = {370.03, -421.19, 3419.70};
+static float P029[3] = {351.15, -16.98, 3423.17};
+static float P030[3] = {200.66, 248.46, 3430.37};
+static float P031[3] = {-148.42, 235.02, 3417.91};
+static float P032[3] = {-360.21, -30.27, 3416.84};
+static float P033[3] = {-357.90, -414.89, 3407.04};
+static float P034[3] = {-148.88, -631.35, 3409.90};
+static float P035[3] = {156.38, -632.59, 3419.70};
+static float P036[3] = {462.61, -469.21, 4431.51};
+static float P037[3] = {466.60, 102.25, 4434.98};
+static float P038[3] = {243.05, 474.34, 4562.02};
+static float P039[3] = {-191.23, 474.40, 4554.42};
+static float P040[3] = {-476.12, 111.05, 4451.11};
+static float P041[3] = {-473.36, -470.74, 4444.78};
+static float P042[3] = {-266.95, -748.41, 4447.78};
+static float P043[3] = {211.14, -749.91, 4429.73};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 6360.63};
+static float P046[3] = {371.29, 804.51, 6486.26};
+static float P047[3] = {-291.43, 797.22, 6494.28};
+static float P048[3] = {-784.13, 370.75, 6378.01};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float iP001[3] = {5.68, -300.95, 1324.70};
+static float iP009[3] = {124.39, -261.46, 1942.34};
+static float iP010[3] = {-130.05, -261.46, 1946.03};
+static float iP011[3] = {141.07, -320.11, 1239.38};
+static float iP012[3] = {156.48, -360.12, 2073.41};
+static float iP013[3] = {162.00, -175.88, 2064.44};
+static float iP014[3] = {88.16, -87.72, 2064.02};
+static float iP015[3] = {-65.21, -96.13, 2064.02};
+static float iP016[3] = {-156.48, -180.96, 2064.44};
+static float iP017[3] = {-162.00, -368.93, 2082.39};
+static float iP018[3] = {-88.16, -439.22, 2082.39};
+static float iP019[3] = {65.21, -440.32, 2083.39};
+static float iP020[3] = {246.87, -356.02, 2576.95};
+static float iP021[3] = {253.17, -111.15, 2567.15};
+static float iP022[3] = {132.34, 51.41, 2559.84};
+static float iP023[3] = {-97.88, 40.44, 2567.15};
+static float iP024[3] = {-222.97, -117.49, 2567.15};
+static float iP025[3] = {-252.22, -371.53, 2569.92};
+static float iP026[3] = {-108.44, -518.19, 2586.75};
+static float iP027[3] = {97.88, -524.79, 2586.75};
+static float iP028[3] = {370.03, -421.19, 3419.70};
+static float iP029[3] = {351.15, -16.98, 3423.17};
+static float iP030[3] = {200.66, 248.46, 3430.37};
+static float iP031[3] = {-148.42, 235.02, 3417.91};
+static float iP032[3] = {-360.21, -30.27, 3416.84};
+static float iP033[3] = {-357.90, -414.89, 3407.04};
+static float iP034[3] = {-148.88, -631.35, 3409.90};
+static float iP035[3] = {156.38, -632.59, 3419.70};
+static float iP036[3] = {462.61, -469.21, 4431.51};
+static float iP037[3] = {466.60, 102.25, 4434.98};
+static float iP038[3] = {243.05, 474.34, 4562.02};
+static float iP039[3] = {-191.23, 474.40, 4554.42};
+static float iP040[3] = {-476.12, 111.05, 4451.11};
+static float iP041[3] = {-473.36, -470.74, 4444.78};
+static float iP042[3] = {-266.95, -748.41, 4447.78};
+static float iP043[3] = {211.14, -749.91, 4429.73};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 6360.63};
+static float iP046[3] = {371.29, 804.51, 6486.26};
+static float iP047[3] = {-291.43, 797.22, 6494.28};
+static float iP048[3] = {-784.13, 370.75, 6378.01};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -300.15, 7894.03};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {246.22, 558.53, 8460.50};
+static float P055[3] = {-230.41, 559.84, 8473.23};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 338.75, 9450.30};
+static float P063[3] = {-165.71, 341.04, 9462.35};
+static float P064[3] = {-298.11, 110.13, 10180.37};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -491.45, 9348.73};
+static float P068[3] = {-136.29, -319.84, 1228.73};
+static float P069[3] = {1111.17, -314.14, 1314.19};
+static float P070[3] = {-1167.34, -321.61, 1319.45};
+static float P071[3] = {1404.86, -306.66, 1235.45};
+static float P072[3] = {-1409.73, -314.14, 1247.66};
+static float P073[3] = {1254.01, -296.87, 1544.58};
+static float P074[3] = {-1262.09, -291.70, 1504.26};
+static float P075[3] = {965.71, -269.26, 1742.65};
+static float P076[3] = {-900.97, -276.74, 1726.07};
+static float iP068[3] = {-136.29, -319.84, 1228.73};
+static float iP069[3] = {1111.17, -314.14, 1314.19};
+static float iP070[3] = {-1167.34, -321.61, 1319.45};
+static float iP071[3] = {1404.86, -306.66, 1235.45};
+static float iP072[3] = {-1409.73, -314.14, 1247.66};
+static float iP073[3] = {1254.01, -296.87, 1544.58};
+static float iP074[3] = {-1262.09, -291.70, 1504.26};
+static float iP075[3] = {965.71, -269.26, 1742.65};
+static float iP076[3] = {-900.97, -276.74, 1726.07};
+static float P077[3] = {1058.00, -448.81, 8194.66};
+static float P078[3] = {-1016.51, -456.43, 8190.62};
+static float P079[3] = {-1515.96, -676.45, 7754.93};
+static float P080[3] = {1856.75, -830.34, 7296.56};
+static float P081[3] = {1472.16, -497.38, 7399.68};
+static float P082[3] = {-1775.26, -829.51, 7298.46};
+static float P083[3] = {911.09, -252.51, 7510.99};
+static float P084[3] = {-1451.94, -495.62, 7384.30};
+static float P085[3] = {1598.75, -669.26, 7769.90};
+static float P086[3] = {-836.53, -250.08, 7463.25};
+static float P087[3] = {722.87, -158.18, 8006.41};
+static float P088[3] = {-688.86, -162.28, 7993.89};
+static float P089[3] = {-626.92, -185.30, 8364.98};
+static float P090[3] = {647.72, -189.46, 8354.99};
+static float P091[3] = {0.00, 835.01, 5555.62};
+static float P092[3] = {0.00, 1350.18, 5220.86};
+static float P093[3] = {0.00, 1422.94, 5285.27};
+static float P094[3] = {0.00, 1296.75, 5650.19};
+static float P095[3] = {0.00, 795.63, 6493.88};
+static float iP091[3] = {0.00, 835.01, 5555.62};
+static float iP092[3] = {0.00, 1350.18, 5220.86};
+static float iP093[3] = {0.00, 1422.94, 5285.27};
+static float iP094[3] = {0.00, 1296.75, 5650.19};
+static float iP095[3] = {0.00, 795.63, 6493.88};
+static float P097[3] = {-194.91, -357.14, 10313.32};
+static float P098[3] = {135.35, -357.66, 10307.94};
+static float iP097[3] = {-194.91, -357.14, 10313.32};
+static float iP098[3] = {135.35, -357.66, 10307.94};
+static float P099[3] = {-380.53, -221.14, 9677.98};
+static float P100[3] = {0.00, 412.99, 9629.33};
+static float P102[3] = {59.51, -412.55, 10677.58};
+static float iP102[3] = {59.51, -412.55, 10677.58};
+static float P103[3] = {6.50, 484.74, 9009.94};
+static float P105[3] = {-41.86, 476.51, 9078.17};
+static float P108[3] = {49.20, 476.83, 9078.24};
+static float P110[3] = {-187.62, -410.04, 10674.12};
+static float iP110[3] = {-187.62, -410.04, 10674.12};
+static float P111[3] = {-184.25, -318.70, 10723.88};
+static float iP111[3] = {-184.25, -318.70, 10723.88};
+static float P112[3] = {-179.61, -142.81, 10670.26};
+static float P113[3] = {57.43, -147.94, 10675.26};
+static float P114[3] = {54.06, -218.90, 10712.44};
+static float P115[3] = {-186.35, -212.09, 10713.76};
+static float P116[3] = {205.90, -84.61, 10275.97};
+static float P117[3] = {-230.96, -83.26, 10280.09};
+static float iP118[3] = {216.78, -509.17, 10098.94};
+static float iP119[3] = {-313.21, -510.79, 10102.62};
+static float P118[3] = {216.78, -509.17, 10098.94};
+static float P119[3] = {-313.21, -510.79, 10102.62};
+static float P120[3] = {217.95, 96.34, 10161.62};
+static float P121[3] = {71.99, -319.74, 10717.70};
+static float iP121[3] = {71.99, -319.74, 10717.70};
+static float P122[3] = {0.00, 602.74, 5375.84};
+static float iP122[3] = {0.00, 602.74, 5375.84};
+static float P123[3] = {-448.94, -203.14, 9499.60};
+static float P124[3] = {-442.64, -185.20, 9528.07};
+static float P125[3] = {-441.07, -148.05, 9528.07};
+static float P126[3] = {-443.43, -128.84, 9499.60};
+static float P127[3] = {-456.87, -146.78, 9466.67};
+static float P128[3] = {-453.68, -183.93, 9466.67};
+static float P129[3] = {428.43, -124.08, 9503.03};
+static float P130[3] = {419.73, -142.14, 9534.56};
+static float P131[3] = {419.92, -179.96, 9534.56};
+static float P132[3] = {431.20, -199.73, 9505.26};
+static float P133[3] = {442.28, -181.67, 9475.96};
+static float P134[3] = {442.08, -143.84, 9475.96};
+/* *INDENT-ON* */
+
+void
+Dolphin001(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P072);
+    glVertex3fv(P074);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P072);
+    glVertex3fv(P070);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P074);
+    glVertex3fv(P070);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P070);
+    glVertex3fv(P068);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P076);
+    glVertex3fv(P068);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P068);
+    glVertex3fv(P001);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Dolphin002(void)
+{
+    glNormal3fv(N071);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P001);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P075);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glEnd();
+    glNormal3fv(N119);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P001);
+    glVertex3fv(P011);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P009);
+    glVertex3fv(P011);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P011);
+    glVertex3fv(P069);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P073);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P069);
+    glVertex3fv(P071);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Dolphin003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Dolphin004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Dolphin005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Dolphin006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N122);
+    glVertex3fv(P122);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Dolphin007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Dolphin008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Dolphin009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Dolphin010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Dolphin011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Dolphin012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+}
+
+void
+Dolphin013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glNormal3fv(N113);
+    glVertex3fv(P113);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N114);
+    glVertex3fv(P114);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P007);
+    glVertex3fv(P008);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P007);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N112);
+    glVertex3fv(P112);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N115);
+    glVertex3fv(P115);
+    glEnd();
+}
+
+void
+Dolphin014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N111);
+    glVertex3fv(P111);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P098);
+    glVertex3fv(P097);
+    glVertex3fv(P111);
+    glVertex3fv(P121);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P002);
+    glVertex3fv(P099);
+    glVertex3fv(P097);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N110);
+    glVertex3fv(P110);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N119);
+    glVertex3fv(P119);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N118);
+    glVertex3fv(P118);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N102);
+    glVertex3fv(P102);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N121);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+Dolphin015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N117);
+    glVertex3fv(P117);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N120);
+    glVertex3fv(P120);
+    glNormal3fv(N116);
+    glVertex3fv(P116);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Dolphin016(void)
+{
+
+    glDisable(GL_DEPTH_TEST);
+    glBegin(GL_POLYGON);
+    glVertex3fv(P123);
+    glVertex3fv(P124);
+    glVertex3fv(P125);
+    glVertex3fv(P126);
+    glVertex3fv(P127);
+    glVertex3fv(P128);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P129);
+    glVertex3fv(P130);
+    glVertex3fv(P131);
+    glVertex3fv(P132);
+    glVertex3fv(P133);
+    glVertex3fv(P134);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P103);
+    glVertex3fv(P105);
+    glVertex3fv(P108);
+    glEnd();
+    glEnable(GL_DEPTH_TEST);
+}
+
+void
+DrawDolphin(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch, thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (10.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg3 = 1.0 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.0 * thrash * sin((fish->htail + 4.0) * RRAD);
+    seg2 = 3.0 * thrash * sin((fish->htail + 6.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg5 = 4.5 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg6 = 5.0 * thrash * sin((fish->htail + 20.0) * RRAD);
+    seg7 = 6.0 * thrash * sin((fish->htail + 30.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail + 180.0) * RRAD);
+
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    chomp = 100.0;
+
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3;
+    P122[1] = iP122[1] + seg3 * 1.5;
+
+    P097[1] = iP097[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P102[1] = iP102[1] + chomp;
+    P110[1] = iP110[1] + chomp;
+    P111[1] = iP111[1] + chomp;
+    P121[1] = iP121[1] + chomp;
+    P118[1] = iP118[1] + chomp;
+    P119[1] = iP119[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 7000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+/*	glGetFloatv(GL_MODELVIEW_MATRIX, f);
+	printf("Modelview:\n");
+	printf("%f %f %f %f ", f[0], f[1], f[2], f[3]);
+	printf("%f %f %f %f ", f[4], f[5], f[6], f[7]);
+	printf("%f %f %f %f ", f[8], f[9], f[10], f[11]);
+	printf("%f %f %f %f\n", f[12], f[13], f[14], f[15]);
+*/
+    //glEnable(GL_CULL_FACE);
+    Dolphin014();
+    Dolphin010();
+    Dolphin009();
+    Dolphin012();
+    Dolphin013();
+    Dolphin006();
+    Dolphin002();
+    Dolphin001();
+    Dolphin003();
+    Dolphin015();
+    Dolphin004();
+    Dolphin005();
+    Dolphin007();
+    Dolphin008();
+    Dolphin011();
+    Dolphin016();
+    //glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis/atlantis.c
===================================================================
--- trunk/src/testing/app/atlantis/atlantis.c	(revision 4)
+++ trunk/src/testing/app/atlantis/atlantis.c	(revision 4)
@@ -0,0 +1,525 @@
+
+/* Copyright (c) Mark J. Kilgard, 1994. */
+
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+
+#include "sail.h"
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/glut.h>
+#include <GL/glu.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(WIN32)
+//#define WIN32_LEAN_AND_MEAN
+//#include <windows.h>
+//#include <winsock.h>
+#include <sys\timeb.h>
+extern int gettimeofday(struct timeval *tp, void *tzp);
+#else
+#include <sys/time.h>
+#endif
+
+
+#include "atlantis.h"
+
+// headers for SAGE
+#include "misc.h"
+int winWidth, winHeight;
+GLubyte *rgbBuffer = 0;
+sail sageInf; // sail object
+FILE *ff;
+#if defined(WIN32)
+/*
+int
+gettimeofday(struct timeval *tp, void *tzp)
+{
+	struct _timeb t;
+
+    _ftime(&t);
+    tp->tv_sec = t.time;
+    tp->tv_usec = t.millitm * 1000;
+    return 0;
+}
+*/
+#endif
+
+fishRec sharks[NUM_SHARKS];
+fishRec momWhale;
+fishRec babyWhale;
+fishRec dolph;
+
+GLboolean moving;
+int screenshot = 0;
+float t1,t2;
+struct timeval tv_start;
+
+double getTime()
+{
+    struct timeval tv;
+		        
+    gettimeofday(&tv,0);
+    return (double)(tv.tv_sec - tv_start.tv_sec) + (double)(tv.tv_usec - tv_start.tv_usec) / 1000000.0;
+}
+/*
+float abs(float f)
+{
+    if (f >= 0.0f) return f;
+    else return -f;
+}
+*/
+void
+InitFishs(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        sharks[i].x = 15000.0 + rand() % 6000;
+        sharks[i].y = (rand() % 20000) - 10000;
+        sharks[i].z = (rand() % 6000) - 5000;
+        sharks[i].psi = rand() % 360 - 180.0;
+        sharks[i].v = 1.0;
+    }
+
+    dolph.x = 30000.0;
+    dolph.y = 0.0;
+    dolph.z = 6000.0;
+    dolph.psi = 90.0;
+    dolph.theta = 0.0;
+    dolph.v = 3.0;
+
+    momWhale.x = 70000.0;
+    momWhale.y = 0.0;
+    momWhale.z = 0.0;
+    momWhale.psi = 90.0;
+    momWhale.theta = 0.0;
+    momWhale.v = 3.0;
+
+    babyWhale.x = 60000.0;
+    babyWhale.y = -2000.0;
+    babyWhale.z = -2000.0;
+    babyWhale.psi = 90.0;
+    babyWhale.theta = 0.0;
+    babyWhale.v = 3.0;
+}
+
+void
+Init(void)
+{
+    static float ambient[] =
+    {0.1, 0.1, 0.1, 1.0};
+    static float diffuse[] =
+    {1.0, 1.0, 1.0, 1.0};
+    static float position[] =
+    {0.0, 1.0, 0.0, 0.0};
+    static float mat_shininess[] =
+    {90.0};
+    static float mat_specular[] =
+    {0.8, 0.8, 0.8, 1.0};
+    static float mat_diffuse[] =
+    {0.46, 0.66, 0.795, 1.0};
+    static float mat_ambient[] =
+    {0.0, 0.1, 0.2, 1.0};
+    static float lmodel_ambient[] =
+    {0.4, 0.4, 0.4, 1.0};
+    static float lmodel_localviewer[] =
+    {1.0};
+
+    glFrontFace(GL_CW);
+
+    glDepthFunc(GL_LEQUAL);
+    glEnable(GL_DEPTH_TEST);
+
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+    glEnable(GL_LIGHTING);
+    glEnable(GL_LIGHT0);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    InitFishs();
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+}
+
+void
+Reshape(int width, int height)
+{
+    winWidth = width;
+    winHeight = height;	
+    
+    glViewport(0, 0, width, height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    gluPerspective(4.0, 2.0, 10000.0, 400000.0);
+    glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+}
+
+void
+Animate(void)
+{
+    int i;
+
+    for (i = 0; i < NUM_SHARKS; i++) {
+        SharkPilot(&sharks[i]);
+        SharkMiss(i);
+    }
+    WhalePilot(&dolph);
+    dolph.phi++;
+    glutPostRedisplay();
+    WhalePilot(&momWhale);
+    momWhale.phi++;
+    WhalePilot(&babyWhale);
+    babyWhale.phi++;
+}
+
+/* ARGSUSED1 */
+void
+Key(unsigned char key, int x, int y)
+{
+	(void) x;
+	(void) y;
+    switch (key) 
+	{
+	  case 27:           /* Esc will quit */
+	  	  sageInf.shutdown();
+        exit(1);
+        break;
+	  case 's':
+		screenshot++;
+		glutPostRedisplay( );
+		break;
+	  case ' ':          /* space will advance frame */
+        if (!moving) {
+            Animate();
+        }
+    }
+}
+
+
+void
+save_frame( void )
+{
+/*	GLint viewport[4];
+	int x, y, width, height;
+	void *pixels;
+	FILE *f;
+
+	glGetIntegerv( GL_VIEWPORT, viewport );
+
+	x = viewport[0];
+	y = viewport[1];
+	width = viewport[2];
+	height = viewport[3];
+
+	printf( "saving %dx%d screenshot\n", width, height );
+
+	pixels = malloc( width * height * 3 );
+	assert( pixels );
+	memset( pixels, 0, width * height * 3 );
+
+	glReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+
+	f = fopen( "screenshot.ppm", "wb" );
+	fprintf( f, "P6\n%d %d\n255\n", width, height );
+	for ( y = height - 1; y >= 0; y-- )
+		fwrite( (char *) pixels + y * width * 3, width, 3, f );
+	fclose( f );
+
+	free( pixels );
+
+	printf( "done\n" );*/
+}
+
+void
+print_performance( void )
+{
+/*	static int first = 1;
+	 = 0
+	static int start, num_frames;
+	int current;
+
+	if ( first )
+	{
+		start = glutGet( GLUT_ELAPSED_TIME );
+		num_frames = 0;
+		first = 0;
+	}
+
+	num_frames++;
+	current = glutGet( GLUT_ELAPSED_TIME );
+
+	if ( current - start > 1000 )
+	{
+		double elapsed = 1e-3 * (double) ( current - start );
+		double rate = (double) num_frames / elapsed;
+		printf( "%5.1f fps\n", rate );
+
+		num_frames = 0;
+		start = current;
+	}*/
+}
+
+void
+Display( void )
+{
+    float ambient[] = {0.1, 0.1, 0.1, 1.0};
+    float diffuse[] = {1.0, 1.0, 1.0, 1.0};
+    float position[] = {0.0, 1.0, 0.0, 0.0};
+    float mat_shininess[] = {90.0};
+    float mat_specular[] = {0.8, 0.8, 0.8, 1.0};
+    float mat_diffuse[] = {0.46, 0.66, 0.795, 1.0};
+    float mat_ambient[] = {0.0, 0.1, 0.2, 1.0};
+    float lmodel_ambient[] = {0.4, 0.4, 0.4, 1.0};
+    float lmodel_localviewer[] = {0.0};
+
+    int i;
+
+#if 0
+	/* stupid WireGL */
+	glViewport (0, 0, 450*3, 170*3);
+#endif
+
+    glFrontFace(GL_CCW);
+
+
+    glDepthFunc(GL_LEQUAL);
+
+    glEnable(GL_DEPTH_TEST);
+
+    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
+
+    glLightfv(GL_LIGHT0, GL_POSITION, position);
+
+    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+
+    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
+
+    glEnable(GL_LIGHTING);
+
+    glEnable(GL_LIGHT0);
+
+	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+
+    glClearColor(0.0, 0.5, 0.9, 0.0);
+
+    glMatrixMode(GL_PROJECTION);
+
+    glLoadIdentity();
+
+    gluPerspective(40.0, 2.0, 10000.0, 400000.0);
+
+    glMatrixMode(GL_MODELVIEW);
+
+	glLoadIdentity();
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  	for (i = 0; i < NUM_SHARKS; i++) {
+        glPushMatrix();
+        FishTransform(&sharks[i]);
+        DrawShark(&sharks[i]);
+        glPopMatrix();
+    }
+
+    glPushMatrix();
+    FishTransform(&dolph);
+    DrawDolphin(&dolph);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&momWhale);
+    DrawWhale(&momWhale);
+    glPopMatrix();
+
+    glPushMatrix();
+    FishTransform(&babyWhale);
+    glScalef(0.45, 0.45, 0.3);
+    DrawWhale(&babyWhale);
+    glPopMatrix();
+    glFinish();
+
+    if (winWidth > 0) {
+		glReadPixels(0, 0, winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, rgbBuffer);	
+		sageInf.swapBuffer();
+    	rgbBuffer = (GLubyte *)sageInf.getBuffer();
+		//usleep(100000);
+	 }
+	 
+	 sageMessage msg;
+	 if (sageInf.checkMsg(msg, false) > 0) {
+		 switch (msg.getCode()) {
+			 case APP_QUIT : {
+				exit(0);
+				break;
+			}
+		 }	
+	 }
+	 
+    glutSwapBuffers();
+}
+
+void
+Visible(int state)
+{
+    if (state == GLUT_VISIBLE) {
+        if (moving)
+            glutIdleFunc(Animate);
+    } else {
+        if (moving)
+            glutIdleFunc(NULL);
+    }
+}
+
+void
+menuSelect(int value)
+{
+    switch (value)
+    {
+        case 1:
+            moving = GL_TRUE;
+            glutIdleFunc(Animate);
+            break;
+        case 2:
+            moving = GL_FALSE;;
+            glutIdleFunc(NULL);
+            break;
+        case 3:
+            exit(0);
+            break;
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+	 int nodeId = 0;
+
+ 	 int resX = 300, resY = 300;
+	 if (argc > 3) {
+		 resX = atoi(argv[2]);
+		 resY = atoi(argv[3]);
+	 }	
+	
+	 sageRect atlantisImageMap;
+	 atlantisImageMap.left = 0.0;
+	 atlantisImageMap.right = 1.0;
+	 atlantisImageMap.bottom = 0.0;
+	 atlantisImageMap.top = 1.0;
+	 
+	 sailConfig scfg;
+	 scfg.init("atlantis.conf");
+	 scfg.setAppName("atlantis");
+	 scfg.rank = nodeId;
+
+	 if (argc >= 2)
+	 	scfg.appID = atoi(argv[1]);
+		
+	 scfg.resX = resX;
+	 scfg.resY = resY;
+	 scfg.imageMap = atlantisImageMap;
+	 scfg.pixFmt = PIXFMT_888;
+	 scfg.rowOrd = BOTTOM_TO_TOP;
+	 scfg.master = true;
+	 scfg.nwID = 1;
+	 
+	 if (argc > 5)
+	 	scfg.nwID = atoi(argv[5]);
+				 
+	 sageInf.init(scfg);
+	
+	 std::cout << "sail initialized " << std::endl;
+
+    //glutInitWindowSize(512, 192);
+    gettimeofday(&tv_start,0);
+	
+    glutInitWindowSize(resX, resY);
+    glutInitWindowPosition(0,0);
+    glutInit(&argc, argv);
+    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+    glutCreateWindow("GLUT Atlantis Demo");
+    printf("sharks: %d\n",NUM_SHARKS);
+    Init();
+    glutDisplayFunc(Display);
+    glutReshapeFunc(Reshape);
+    glutKeyboardFunc(Key);
+    moving = GL_TRUE;
+    glutIdleFunc(Animate);
+    glutVisibilityFunc(Visible);
+    glutCreateMenu(menuSelect);
+    glutAddMenuEntry("Start motion", 1);
+    glutAddMenuEntry("Stop motion", 2);
+    glutAddMenuEntry("Quit", 3);
+    glutAttachMenu(GLUT_RIGHT_BUTTON);
+    glPixelStorei(GL_PACK_ALIGNMENT,1);
+    
+        //glutFullScreen();
+
+	if (rgbBuffer)
+	    delete [] rgbBuffer;
+    rgbBuffer = (GLubyte *)sageInf.getBuffer();
+    
+    t1 = getTime();
+     glutMainLoop();
+    return 0;             /* ANSI C requires main to return int. */
+}
Index: trunk/src/testing/app/atlantis/swim.c
===================================================================
--- trunk/src/testing/app/atlantis/swim.c	(revision 4)
+++ trunk/src/testing/app/atlantis/swim.c	(revision 4)
@@ -0,0 +1,191 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#include <math.h>
+#include <stdlib.h>
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include "atlantis.h"
+
+void
+FishTransform(fishRec * fish)
+{
+	glTranslatef(fish->y, fish->z, -fish->x);
+	glRotatef(-fish->psi, 0.0, 1.0, 0.0);
+    glRotatef(fish->theta, 1.0, 0.0, 0.0);
+    glRotatef(-fish->phi, 0.0, 0.0, 1.0);
+}
+
+void
+WhalePilot(fishRec * fish)
+{
+
+    fish->phi = -20.0;
+    fish->theta = 0.0;
+    fish->psi -= 0.5;
+
+    fish->x += WHALESPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += WHALESPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += WHALESPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkPilot(fishRec * fish)
+{
+    static int sign = 1;
+    float X, Y, Z, tpsi, ttheta, thetal;
+
+    fish->xt = 60000.0;
+    fish->yt = 0.0;
+    fish->zt = 0.0;
+
+    X = fish->xt - fish->x;
+    Y = fish->yt - fish->y;
+    Z = fish->zt - fish->z;
+
+    thetal = fish->theta;
+
+    ttheta = RAD * atan(Z / (sqrt(X * X + Y * Y)));
+
+    if (ttheta > fish->theta + 0.25) {
+        fish->theta += 0.5;
+    } else if (ttheta < fish->theta - 0.25) {
+        fish->theta -= 0.5;
+    }
+    if (fish->theta > 90.0) {
+        fish->theta = 90.0;
+    }
+    if (fish->theta < -90.0) {
+        fish->theta = -90.0;
+    }
+    fish->dtheta = fish->theta - thetal;
+
+    tpsi = RAD * atan2(Y, X);
+
+    fish->attack = 0;
+
+    if (fabs(tpsi - fish->psi) < 10.0) {
+        fish->attack = 1;
+    } else if (fabs(tpsi - fish->psi) < 45.0) {
+        if (fish->psi > tpsi) {
+            fish->psi -= 0.5;
+            if (fish->psi < -180.0) {
+                fish->psi += 360.0;
+            }
+        } else if (fish->psi < tpsi) {
+            fish->psi += 0.5;
+            if (fish->psi > 180.0) {
+                fish->psi -= 360.0;
+            }
+        }
+    } else {
+        if (rand() % 100 > 98) {
+            sign = 1 - sign;
+        }
+        fish->psi += sign;
+        if (fish->psi > 180.0) {
+            fish->psi -= 360.0;
+        }
+        if (fish->psi < -180.0) {
+            fish->psi += 360.0;
+        }
+    }
+
+    if (fish->attack) {
+        if (fish->v < 1.1) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.2;
+        }
+        if (fish->v > 5.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.2;
+        }
+    } else {
+        if (!(rand() % 400) && (!fish->spurt)) {
+            fish->spurt = 1;
+        }
+        if (fish->spurt) {
+            fish->v += 0.05;
+        }
+        if (fish->v > 3.0) {
+            fish->spurt = 0;
+        }
+        if ((fish->v > 1.0) && (!fish->spurt)) {
+            fish->v -= 0.05;
+        }
+    }
+
+    fish->x += SHARKSPEED * fish->v * cos(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->y += SHARKSPEED * fish->v * sin(fish->psi / RAD) * cos(fish->theta / RAD);
+    fish->z += SHARKSPEED * fish->v * sin(fish->theta / RAD);
+}
+
+void
+SharkMiss(int i)
+{
+    int j;
+    float avoid, thetal;
+    float X, Y, Z, R;
+
+    for (j = 0; j < NUM_SHARKS; j++) {
+        if (j != i) {
+            X = sharks[j].x - sharks[i].x;
+            Y = sharks[j].y - sharks[i].y;
+            Z = sharks[j].z - sharks[i].z;
+
+            R = sqrt(X * X + Y * Y + Z * Z);
+
+            avoid = 1.0;
+            thetal = sharks[i].theta;
+
+            if (R < SHARKSIZE) {
+                if (Z > 0.0) {
+                    sharks[i].theta -= avoid;
+                } else {
+                    sharks[i].theta += avoid;
+                }
+            }
+            sharks[i].dtheta += (sharks[i].theta - thetal);
+        }
+    }
+}
Index: trunk/src/testing/app/atlantis/whale.c
===================================================================
--- trunk/src/testing/app/atlantis/whale.c	(revision 4)
+++ trunk/src/testing/app/atlantis/whale.c	(revision 4)
@@ -0,0 +1,1810 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+/* *INDENT-OFF* */
+static float N001[3] = {0.019249 ,0.011340 ,-0.999750};
+static float N002[3] = {-0.132579 ,0.954547 ,0.266952};
+static float N003[3] = {-0.196061 ,0.980392 ,-0.019778};
+static float N004[3] = {0.695461 ,0.604704 ,0.388158};
+static float N005[3] = {0.870600 ,0.425754 ,0.246557};
+static float N006[3] = {-0.881191 ,0.392012 ,0.264251};
+static float N008[3] = {-0.341437 ,0.887477 ,0.309523};
+static float N009[3] = {0.124035 ,-0.992278 ,0.000000};
+static float N010[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N011[3] = {0.588172 ,0.000000 ,0.808736};
+static float N012[3] = {0.929824 ,-0.340623 ,-0.139298};
+static float N013[3] = {0.954183 ,0.267108 ,-0.134865};
+static float N014[3] = {0.495127 ,0.855436 ,-0.151914};
+static float N015[3] = {-0.390199 ,0.906569 ,-0.160867};
+static float N016[3] = {-0.923605 ,0.354581 ,-0.145692};
+static float N017[3] = {-0.955796 ,-0.260667 ,-0.136036};
+static float N018[3] = {-0.501283 ,-0.853462 ,-0.142540};
+static float N019[3] = {0.405300 ,-0.901974 ,-0.148913};
+static float N020[3] = {0.909913 ,-0.392746 ,-0.133451};
+static float N021[3] = {0.936494 ,0.331147 ,-0.115414};
+static float N022[3] = {0.600131 ,0.793724 ,-0.099222};
+static float N023[3] = {-0.231556 ,0.968361 ,-0.093053};
+static float N024[3] = {-0.844369 ,0.525330 ,-0.105211};
+static float N025[3] = {-0.982725 ,-0.136329 ,-0.125164};
+static float N026[3] = {-0.560844 ,-0.822654 ,-0.093241};
+static float N027[3] = {0.263884 ,-0.959981 ,-0.093817};
+static float N028[3] = {0.842057 ,-0.525192 ,-0.122938};
+static float N029[3] = {0.921620 ,0.367565 ,-0.124546};
+static float N030[3] = {0.613927 ,0.784109 ,-0.090918};
+static float N031[3] = {-0.448754 ,0.888261 ,-0.098037};
+static float N032[3] = {-0.891865 ,0.434376 ,-0.126077};
+static float N033[3] = {-0.881447 ,-0.448017 ,-0.149437};
+static float N034[3] = {-0.345647 ,-0.922057 ,-0.174183};
+static float N035[3] = {0.307998 ,-0.941371 ,-0.137688};
+static float N036[3] = {0.806316 ,-0.574647 ,-0.140124};
+static float N037[3] = {0.961346 ,0.233646 ,-0.145681};
+static float N038[3] = {0.488451 ,0.865586 ,-0.110351};
+static float N039[3] = {-0.374290 ,0.921953 ,-0.099553};
+static float N040[3] = {-0.928504 ,0.344533 ,-0.138485};
+static float N041[3] = {-0.918419 ,-0.371792 ,-0.135189};
+static float N042[3] = {-0.520666 ,-0.833704 ,-0.183968};
+static float N043[3] = {0.339204 ,-0.920273 ,-0.195036};
+static float N044[3] = {0.921475 ,-0.387382 ,-0.028636};
+static float N045[3] = {0.842465 ,0.533335 ,-0.076204};
+static float N046[3] = {0.380110 ,0.924939 ,0.002073};
+static float N047[3] = {-0.276128 ,0.961073 ,-0.009579};
+static float N048[3] = {-0.879684 ,0.473001 ,-0.049250};
+static float N049[3] = {-0.947184 ,-0.317614 ,-0.044321};
+static float N050[3] = {-0.642059 ,-0.764933 ,-0.051363};
+static float N051[3] = {0.466794 ,-0.880921 ,-0.077990};
+static float N052[3] = {0.898509 ,-0.432277 ,0.076279};
+static float N053[3] = {0.938985 ,0.328141 ,0.103109};
+static float N054[3] = {0.442420 ,0.895745 ,0.043647};
+static float N055[3] = {-0.255163 ,0.966723 ,0.018407};
+static float N056[3] = {-0.833769 ,0.540650 ,0.111924};
+static float N057[3] = {-0.953653 ,-0.289939 ,0.080507};
+static float N058[3] = {-0.672357 ,-0.730524 ,0.119461};
+static float N059[3] = {0.522249 ,-0.846652 ,0.102157};
+static float N060[3] = {0.885868 ,-0.427631 ,0.179914};
+static float N062[3] = {0.648942 ,0.743116 ,0.163255};
+static float N063[3] = {-0.578967 ,0.807730 ,0.111219};
+static float N065[3] = {-0.909864 ,-0.352202 ,0.219321};
+static float N066[3] = {-0.502541 ,-0.818090 ,0.279610};
+static float N067[3] = {0.322919 ,-0.915358 ,0.240504};
+static float N068[3] = {0.242536 ,0.000000 ,-0.970143};
+static float N069[3] = {0.000000 ,1.000000 ,0.000000};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float N071[3] = {0.000000 ,1.000000 ,0.000000};
+static float N072[3] = {0.000000 ,1.000000 ,0.000000};
+static float N073[3] = {0.000000 ,1.000000 ,0.000000};
+static float N074[3] = {0.000000 ,1.000000 ,0.000000};
+static float N075[3] = {0.031220 ,0.999025 ,-0.031220};
+static float N076[3] = {0.000000 ,1.000000 ,0.000000};
+static float N077[3] = {0.446821 ,0.893642 ,0.041889};
+static float N078[3] = {0.863035 ,-0.100980 ,0.494949};
+static float N079[3] = {0.585597 ,-0.808215 ,0.062174};
+static float N080[3] = {0.000000 ,1.000000 ,0.000000};
+static float N081[3] = {1.000000 ,0.000000 ,0.000000};
+static float N082[3] = {0.000000 ,1.000000 ,0.000000};
+static float N083[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N084[3] = {-0.478893 ,0.837129 ,-0.264343};
+static float N085[3] = {0.000000 ,1.000000 ,0.000000};
+static float N086[3] = {0.763909 ,0.539455 ,-0.354163};
+static float N087[3] = {0.446821 ,0.893642 ,0.041889};
+static float N088[3] = {0.385134 ,-0.908288 ,0.163352};
+static float N089[3] = {-0.605952 ,0.779253 ,-0.159961};
+static float N090[3] = {0.000000 ,1.000000 ,0.000000};
+static float N091[3] = {0.000000 ,1.000000 ,0.000000};
+static float N092[3] = {0.000000 ,1.000000 ,0.000000};
+static float N093[3] = {0.000000 ,1.000000 ,0.000000};
+static float N094[3] = {1.000000 ,0.000000 ,0.000000};
+static float N095[3] = {-1.000000 ,0.000000 ,0.000000};
+static float N096[3] = {0.644444 ,-0.621516 ,0.445433};
+static float N097[3] = {-0.760896 ,-0.474416 ,0.442681};
+static float N098[3] = {0.636888 ,-0.464314 ,0.615456};
+static float N099[3] = {-0.710295 ,0.647038 ,0.277168};
+static float N100[3] = {0.009604 ,0.993655 ,0.112063};
+static float iP001[3] = {18.74, 13.19, 3.76};
+static float P001[3] = {18.74, 13.19, 3.76};
+static float P002[3] = {0.00, 390.42, 10292.57};
+static float P003[3] = {55.80, 622.31, 8254.35};
+static float P004[3] = {20.80, 247.66, 10652.13};
+static float P005[3] = {487.51, 198.05, 9350.78};
+static float P006[3] = {-457.61, 199.04, 9353.01};
+static float P008[3] = {-34.67, 247.64, 10663.71};
+static float iP009[3] = {97.46, 67.63, 593.82};
+static float iP010[3] = {-84.33, 67.63, 588.18};
+static float iP011[3] = {118.69, 8.98, -66.91};
+static float P009[3] = {97.46, 67.63, 593.82};
+static float P010[3] = {-84.33, 67.63, 588.18};
+static float P011[3] = {118.69, 8.98, -66.91};
+static float iP012[3] = {156.48, -31.95, 924.54};
+static float iP013[3] = {162.00, 110.22, 924.54};
+static float iP014[3] = {88.16, 221.65, 924.54};
+static float iP015[3] = {-65.21, 231.16, 924.54};
+static float iP016[3] = {-156.48, 121.97, 924.54};
+static float iP017[3] = {-162.00, -23.93, 924.54};
+static float iP018[3] = {-88.16, -139.10, 924.54};
+static float iP019[3] = {65.21, -148.61, 924.54};
+static float iP020[3] = {246.87, -98.73, 1783.04};
+static float iP021[3] = {253.17, 127.76, 1783.04};
+static float iP022[3] = {132.34, 270.77, 1783.04};
+static float iP023[3] = {-97.88, 285.04, 1783.04};
+static float iP024[3] = {-222.97, 139.80, 1783.04};
+static float iP025[3] = {-225.29, -86.68, 1783.04};
+static float iP026[3] = {-108.44, -224.15, 1783.04};
+static float iP027[3] = {97.88, -221.56, 1783.04};
+static float iP028[3] = {410.55, -200.66, 3213.87};
+static float iP029[3] = {432.19, 148.42, 3213.87};
+static float iP030[3] = {200.66, 410.55, 3213.87};
+static float iP031[3] = {-148.42, 432.19, 3213.87};
+static float iP032[3] = {-407.48, 171.88, 3213.87};
+static float iP033[3] = {-432.19, -148.42, 3213.87};
+static float iP034[3] = {-148.88, -309.74, 3213.87};
+static float iP035[3] = {156.38, -320.17, 3213.87};
+static float iP036[3] = {523.39, -303.81, 4424.57};
+static float iP037[3] = {574.66, 276.84, 4424.57};
+static float iP038[3] = {243.05, 492.50, 4424.57};
+static float iP039[3] = {-191.23, 520.13, 4424.57};
+static float iP040[3] = {-523.39, 304.01, 4424.57};
+static float iP041[3] = {-574.66, -231.83, 4424.57};
+static float iP042[3] = {-266.95, -578.17, 4424.57};
+static float iP043[3] = {211.14, -579.67, 4424.57};
+static float iP044[3] = {680.57, -370.27, 5943.46};
+static float iP045[3] = {834.01, 363.09, 5943.46};
+static float iP046[3] = {371.29, 614.13, 5943.46};
+static float iP047[3] = {-291.43, 621.86, 5943.46};
+static float iP048[3] = {-784.13, 362.60, 5943.46};
+static float iP049[3] = {-743.29, -325.82, 5943.46};
+static float iP050[3] = {-383.24, -804.77, 5943.46};
+static float iP051[3] = {283.47, -846.09, 5943.46};
+static float P012[3] = {156.48, -31.95, 924.54};
+static float P013[3] = {162.00, 110.22, 924.54};
+static float P014[3] = {88.16, 221.65, 924.54};
+static float P015[3] = {-65.21, 231.16, 924.54};
+static float P016[3] = {-156.48, 121.97, 924.54};
+static float P017[3] = {-162.00, -23.93, 924.54};
+static float P018[3] = {-88.16, -139.10, 924.54};
+static float P019[3] = {65.21, -148.61, 924.54};
+static float P020[3] = {246.87, -98.73, 1783.04};
+static float P021[3] = {253.17, 127.76, 1783.04};
+static float P022[3] = {132.34, 270.77, 1783.04};
+static float P023[3] = {-97.88, 285.04, 1783.04};
+static float P024[3] = {-222.97, 139.80, 1783.04};
+static float P025[3] = {-225.29, -86.68, 1783.04};
+static float P026[3] = {-108.44, -224.15, 1783.04};
+static float P027[3] = {97.88, -221.56, 1783.04};
+static float P028[3] = {410.55, -200.66, 3213.87};
+static float P029[3] = {432.19, 148.42, 3213.87};
+static float P030[3] = {200.66, 410.55, 3213.87};
+static float P031[3] = {-148.42, 432.19, 3213.87};
+static float P032[3] = {-407.48, 171.88, 3213.87};
+static float P033[3] = {-432.19, -148.42, 3213.87};
+static float P034[3] = {-148.88, -309.74, 3213.87};
+static float P035[3] = {156.38, -320.17, 3213.87};
+static float P036[3] = {523.39, -303.81, 4424.57};
+static float P037[3] = {574.66, 276.84, 4424.57};
+static float P038[3] = {243.05, 492.50, 4424.57};
+static float P039[3] = {-191.23, 520.13, 4424.57};
+static float P040[3] = {-523.39, 304.01, 4424.57};
+static float P041[3] = {-574.66, -231.83, 4424.57};
+static float P042[3] = {-266.95, -578.17, 4424.57};
+static float P043[3] = {211.14, -579.67, 4424.57};
+static float P044[3] = {680.57, -370.27, 5943.46};
+static float P045[3] = {834.01, 363.09, 5943.46};
+static float P046[3] = {371.29, 614.13, 5943.46};
+static float P047[3] = {-291.43, 621.86, 5943.46};
+static float P048[3] = {-784.13, 362.60, 5943.46};
+static float P049[3] = {-743.29, -325.82, 5943.46};
+static float P050[3] = {-383.24, -804.77, 5943.46};
+static float P051[3] = {283.47, -846.09, 5943.46};
+static float P052[3] = {599.09, -332.24, 7902.59};
+static float P053[3] = {735.48, 306.26, 7911.92};
+static float P054[3] = {321.55, 558.53, 7902.59};
+static float P055[3] = {-260.54, 559.84, 7902.59};
+static float P056[3] = {-698.66, 320.83, 7902.59};
+static float P057[3] = {-643.29, -299.16, 7902.59};
+static float P058[3] = {-341.47, -719.30, 7902.59};
+static float P059[3] = {252.57, -756.12, 7902.59};
+static float P060[3] = {458.39, -265.31, 9355.44};
+static float P062[3] = {224.04, 438.98, 9364.77};
+static float P063[3] = {-165.71, 441.27, 9355.44};
+static float P065[3] = {-473.99, -219.71, 9355.44};
+static float P066[3] = {-211.97, -479.87, 9355.44};
+static float P067[3] = {192.86, -504.03, 9355.44};
+static float iP068[3] = {-112.44, 9.25, -64.42};
+static float iP069[3] = {1155.63, 0.00, -182.46};
+static float iP070[3] = {-1143.13, 0.00, -181.54};
+static float iP071[3] = {1424.23, 0.00, -322.09};
+static float iP072[3] = {-1368.01, 0.00, -310.38};
+static float iP073[3] = {1255.57, 2.31, 114.05};
+static float iP074[3] = {-1149.38, 0.00, 117.12};
+static float iP075[3] = {718.36, 0.00, 433.36};
+static float iP076[3] = {-655.90, 0.00, 433.36};
+static float P068[3] = {-112.44, 9.25, -64.42};
+static float P069[3] = {1155.63, 0.00, -182.46};
+static float P070[3] = {-1143.13, 0.00, -181.54};
+static float P071[3] = {1424.23, 0.00, -322.09};
+static float P072[3] = {-1368.01, 0.00, -310.38};
+static float P073[3] = {1255.57, 2.31, 114.05};
+static float P074[3] = {-1149.38, 0.00, 117.12};
+static float P075[3] = {718.36, 0.00, 433.36};
+static float P076[3] = {-655.90, 0.00, 433.36};
+static float P077[3] = {1058.00, -2.66, 7923.51};
+static float P078[3] = {-1016.51, -15.47, 7902.87};
+static float P079[3] = {-1363.99, -484.50, 7593.38};
+static float P080[3] = {1478.09, -861.47, 7098.12};
+static float P081[3] = {1338.06, -284.68, 7024.15};
+static float P082[3] = {-1545.51, -860.64, 7106.60};
+static float P083[3] = {1063.19, -70.46, 7466.60};
+static float P084[3] = {-1369.18, -288.11, 7015.34};
+static float P085[3] = {1348.44, -482.50, 7591.41};
+static float P086[3] = {-1015.45, -96.80, 7474.86};
+static float P087[3] = {731.04, 148.38, 7682.58};
+static float P088[3] = {-697.03, 151.82, 7668.81};
+static float P089[3] = {-686.82, 157.09, 7922.29};
+static float P090[3] = {724.73, 147.75, 7931.39};
+static float iP091[3] = {0.00, 327.10, 2346.55};
+static float iP092[3] = {0.00, 552.28, 2311.31};
+static float iP093[3] = {0.00, 721.16, 2166.41};
+static float iP094[3] = {0.00, 693.42, 2388.80};
+static float iP095[3] = {0.00, 389.44, 2859.97};
+static float P091[3] = {0.00, 327.10, 2346.55};
+static float P092[3] = {0.00, 552.28, 2311.31};
+static float P093[3] = {0.00, 721.16, 2166.41};
+static float P094[3] = {0.00, 693.42, 2388.80};
+static float P095[3] = {0.00, 389.44, 2859.97};
+static float iP096[3] = {222.02, -183.67, 10266.89};
+static float iP097[3] = {-128.90, -182.70, 10266.89};
+static float iP098[3] = {41.04, 88.31, 10659.36};
+static float iP099[3] = {-48.73, 88.30, 10659.36};
+static float P096[3] = {222.02, -183.67, 10266.89};
+static float P097[3] = {-128.90, -182.70, 10266.89};
+static float P098[3] = {41.04, 88.31, 10659.36};
+static float P099[3] = {-48.73, 88.30, 10659.36};
+static float P100[3] = {0.00, 603.42, 9340.68};
+static float P104[3] = {-9.86, 567.62, 7858.65};
+static float P105[3] = {31.96, 565.27, 7908.46};
+static float P106[3] = {22.75, 568.13, 7782.83};
+static float P107[3] = {58.93, 568.42, 7775.94};
+static float P108[3] = {55.91, 565.59, 7905.86};
+static float P109[3] = {99.21, 566.00, 7858.65};
+static float P110[3] = {-498.83, 148.14, 9135.10};
+static float P111[3] = {-495.46, 133.24, 9158.48};
+static float P112[3] = {-490.82, 146.23, 9182.76};
+static float P113[3] = {-489.55, 174.11, 9183.66};
+static float P114[3] = {-492.92, 189.00, 9160.28};
+static float P115[3] = {-497.56, 176.02, 9136.00};
+static float P116[3] = {526.54, 169.68, 9137.70};
+static float P117[3] = {523.49, 184.85, 9161.42};
+static float P118[3] = {518.56, 171.78, 9186.06};
+static float P119[3] = {516.68, 143.53, 9186.98};
+static float P120[3] = {519.73, 128.36, 9163.26};
+static float P121[3] = {524.66, 141.43, 9138.62};
+/* *INDENT-ON* */
+
+void
+Whale001(void)
+{
+
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N072);
+    glVertex3fv(P072);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N074);
+    glVertex3fv(P074);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N076);
+    glVertex3fv(P076);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N068);
+    glVertex3fv(P068);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glEnd();
+}
+
+void
+Whale002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glNormal3fv(N075);
+    glVertex3fv(P075);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N071);
+    glVertex3fv(P071);
+    glNormal3fv(N073);
+    glVertex3fv(P073);
+    glEnd();
+}
+
+void
+Whale003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N001);
+    glVertex3fv(P001);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glEnd();
+}
+
+void
+Whale004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+}
+
+void
+Whale005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+}
+
+void
+Whale006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N093);
+    glVertex3fv(P093);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N091);
+    glVertex3fv(P091);
+    glNormal3fv(N092);
+    glVertex3fv(P092);
+    glNormal3fv(N094);
+    glVertex3fv(P094);
+    glNormal3fv(N095);
+    glVertex3fv(P095);
+    glEnd();
+}
+
+void
+Whale007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+}
+
+void
+Whale008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+}
+
+void
+Whale009(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+}
+
+void
+Whale010(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N080);
+    glVertex3fv(P080);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N081);
+    glVertex3fv(P081);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N085);
+    glVertex3fv(P085);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N083);
+    glVertex3fv(P083);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N087);
+    glVertex3fv(P087);
+    glNormal3fv(N077);
+    glVertex3fv(P077);
+    glNormal3fv(N090);
+    glVertex3fv(P090);
+    glEnd();
+}
+
+void
+Whale011(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N088);
+    glVertex3fv(P088);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N089);
+    glVertex3fv(P089);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N086);
+    glVertex3fv(P086);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N078);
+    glVertex3fv(P078);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N084);
+    glVertex3fv(P084);
+    glNormal3fv(N082);
+    glVertex3fv(P082);
+    glNormal3fv(N079);
+    glVertex3fv(P079);
+    glEnd();
+}
+
+void
+Whale012(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N057);
+    glVertex3fv(P057);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N056);
+    glVertex3fv(P056);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N053);
+    glVertex3fv(P053);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+}
+
+void
+Whale013(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N067);
+    glVertex3fv(P067);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N096);
+    glVertex3fv(P096);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N098);
+    glVertex3fv(P098);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N097);
+    glVertex3fv(P097);
+    glNormal3fv(N099);
+    glVertex3fv(P099);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P005);
+    glVertex3fv(P006);
+    glVertex3fv(P099);
+    glVertex3fv(P098);
+    glEnd();
+}
+
+void
+Whale014(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P006);
+    glVertex3fv(P005);
+    glVertex3fv(P004);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glEnd();
+}
+
+void
+Whale015(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N055);
+    glVertex3fv(P055);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N054);
+    glVertex3fv(P054);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N100);
+    glVertex3fv(P100);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glEnd();
+}
+
+void
+Whale016(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P104);
+    glVertex3fv(P105);
+    glVertex3fv(P106);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P107);
+    glVertex3fv(P108);
+    glVertex3fv(P109);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P110);
+    glVertex3fv(P111);
+    glVertex3fv(P112);
+    glVertex3fv(P113);
+    glVertex3fv(P114);
+    glVertex3fv(P115);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P116);
+    glVertex3fv(P117);
+    glVertex3fv(P118);
+    glVertex3fv(P119);
+    glVertex3fv(P120);
+    glVertex3fv(P121);
+    glEnd();
+}
+
+void
+DrawWhale(fishRec * fish)
+{
+    float seg0, seg1, seg2, seg3, seg4, seg5, seg6, seg7;
+    float pitch=0.0, thrash, chomp;
+
+
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 70.0 * fish->v;
+
+    seg0 = 1.5 * thrash * sin((fish->htail) * RRAD);
+    seg1 = 2.5 * thrash * sin((fish->htail + 10.0) * RRAD);
+    seg2 = 3.7 * thrash * sin((fish->htail + 15.0) * RRAD);
+    seg3 = 4.8 * thrash * sin((fish->htail + 23.0) * RRAD);
+    seg4 = 6.0 * thrash * sin((fish->htail + 28.0) * RRAD);
+    seg5 = 6.5 * thrash * sin((fish->htail + 35.0) * RRAD);
+    seg6 = 6.5 * thrash * sin((fish->htail + 40.0) * RRAD);
+    seg7 = 6.5 * thrash * sin((fish->htail + 55.0) * RRAD);
+
+    pitch = fish->v * sin((fish->htail - 160.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P012[1] = iP012[1] + seg5;
+    P013[1] = iP013[1] + seg5;
+    P014[1] = iP014[1] + seg5;
+    P015[1] = iP015[1] + seg5;
+    P016[1] = iP016[1] + seg5;
+    P017[1] = iP017[1] + seg5;
+    P018[1] = iP018[1] + seg5;
+    P019[1] = iP019[1] + seg5;
+
+    P020[1] = iP020[1] + seg4;
+    P021[1] = iP021[1] + seg4;
+    P022[1] = iP022[1] + seg4;
+    P023[1] = iP023[1] + seg4;
+    P024[1] = iP024[1] + seg4;
+    P025[1] = iP025[1] + seg4;
+    P026[1] = iP026[1] + seg4;
+    P027[1] = iP027[1] + seg4;
+
+    P028[1] = iP028[1] + seg2;
+    P029[1] = iP029[1] + seg2;
+    P030[1] = iP030[1] + seg2;
+    P031[1] = iP031[1] + seg2;
+    P032[1] = iP032[1] + seg2;
+    P033[1] = iP033[1] + seg2;
+    P034[1] = iP034[1] + seg2;
+    P035[1] = iP035[1] + seg2;
+
+    P036[1] = iP036[1] + seg1;
+    P037[1] = iP037[1] + seg1;
+    P038[1] = iP038[1] + seg1;
+    P039[1] = iP039[1] + seg1;
+    P040[1] = iP040[1] + seg1;
+    P041[1] = iP041[1] + seg1;
+    P042[1] = iP042[1] + seg1;
+    P043[1] = iP043[1] + seg1;
+
+    P044[1] = iP044[1] + seg0;
+    P045[1] = iP045[1] + seg0;
+    P046[1] = iP046[1] + seg0;
+    P047[1] = iP047[1] + seg0;
+    P048[1] = iP048[1] + seg0;
+    P049[1] = iP049[1] + seg0;
+    P050[1] = iP050[1] + seg0;
+    P051[1] = iP051[1] + seg0;
+
+    P009[1] = iP009[1] + seg6;
+    P010[1] = iP010[1] + seg6;
+    P075[1] = iP075[1] + seg6;
+    P076[1] = iP076[1] + seg6;
+
+    P001[1] = iP001[1] + seg7;
+    P011[1] = iP011[1] + seg7;
+    P068[1] = iP068[1] + seg7;
+    P069[1] = iP069[1] + seg7;
+    P070[1] = iP070[1] + seg7;
+    P071[1] = iP071[1] + seg7;
+    P072[1] = iP072[1] + seg7;
+    P073[1] = iP073[1] + seg7;
+    P074[1] = iP074[1] + seg7;
+
+    P091[1] = iP091[1] + seg3 * 1.1;
+    P092[1] = iP092[1] + seg3;
+    P093[1] = iP093[1] + seg3;
+    P094[1] = iP094[1] + seg3;
+    P095[1] = iP095[1] + seg3 * 0.9;
+
+    P099[1] = iP099[1] + chomp;
+    P098[1] = iP098[1] + chomp;
+    P097[1] = iP097[1] + chomp;
+    P096[1] = iP096[1] + chomp;
+
+    glPushMatrix();
+
+    glRotatef(pitch, 1.0, 0.0, 0.0);
+
+    glTranslatef(0.0, 0.0, 8000.0);
+
+    glRotatef(180.0, 0.0, 1.0, 0.0);
+
+    glScalef(3.0, 3.0, 3.0);
+
+    glEnable(GL_CULL_FACE);
+
+    Whale001();
+    Whale002();
+    Whale003();
+    Whale004();
+    Whale005();
+    Whale006();
+    Whale007();
+    Whale008();
+    Whale009();
+    Whale010();
+    Whale011();
+    Whale012();
+
+
+
+    Whale013();
+
+    Whale014();
+
+    Whale015();
+
+    Whale016();
+
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
Index: trunk/src/testing/app/atlantis/atlantis.h
===================================================================
--- trunk/src/testing/app/atlantis/atlantis.h	(revision 4)
+++ trunk/src/testing/app/atlantis/atlantis.h	(revision 4)
@@ -0,0 +1,77 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+
+#ifndef _ATLANTIS_H
+#define _ATLANTIS_H
+
+#define RAD 57.295
+#define RRAD 0.01745
+
+#define NUM_SHARKS  75
+#define SHARKSIZE 6000
+#define SHARKSPEED 100.0
+
+#define WHALESPEED 250.0
+
+typedef struct _fishRec {
+    float x, y, z, phi, theta, psi, v;
+    float xt, yt, zt;
+    float htail, vtail;
+    float dtheta;
+    int spurt, attack;
+} fishRec;
+
+extern fishRec sharks[NUM_SHARKS];
+extern fishRec momWhale;
+extern fishRec babyWhale;
+extern fishRec dolph;
+
+extern void FishTransform(fishRec *);
+extern void WhalePilot(fishRec *);
+extern void SharkPilot(fishRec *);
+extern void SharkMiss(int);
+extern void DrawWhale(fishRec *);
+extern void DrawShark(fishRec *);
+extern void DrawDolphin(fishRec *);
+
+
+#ifdef WINDOWS
+#pragma warning(disable:4305 4101)
+#endif
+
+#endif
+
Index: trunk/src/testing/app/atlantis/shark.c
===================================================================
--- trunk/src/testing/app/atlantis/shark.c	(revision 4)
+++ trunk/src/testing/app/atlantis/shark.c	(revision 4)
@@ -0,0 +1,1316 @@
+/**
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+#if defined(__APPLE__)
+#include <GLUT/glut.h>
+#else
+#include <GL/glut.h> 
+#endif
+#include <math.h>
+#include "atlantis.h"
+
+
+/* *INDENT-OFF* */
+static float N002[3] = {0.000077 ,-0.020611 ,0.999788};
+static float N003[3] = {0.961425 ,0.258729 ,-0.093390};
+static float N004[3] = {0.510811 ,-0.769633 ,-0.383063};
+static float N005[3] = {0.400123 ,0.855734 ,-0.328055};
+static float N006[3] = {-0.770715 ,0.610204 ,-0.183440};
+static float N007[3] = {-0.915597 ,-0.373345 ,-0.149316};
+static float N008[3] = {-0.972788 ,0.208921 ,-0.100179};
+static float N009[3] = {-0.939713 ,-0.312268 ,-0.139383};
+static float N010[3] = {-0.624138 ,-0.741047 ,-0.247589};
+static float N011[3] = {0.591434 ,-0.768401 ,-0.244471};
+static float N012[3] = {0.935152 ,-0.328495 ,-0.132598};
+static float N013[3] = {0.997102 ,0.074243 ,-0.016593};
+static float N014[3] = {0.969995 ,0.241712 ,-0.026186};
+static float N015[3] = {0.844539 ,0.502628 ,-0.184714};
+static float N016[3] = {-0.906608 ,0.386308 ,-0.169787};
+static float N017[3] = {-0.970016 ,0.241698 ,-0.025516};
+static float N018[3] = {-0.998652 ,0.050493 ,-0.012045};
+static float N019[3] = {-0.942685 ,-0.333051 ,-0.020556};
+static float N020[3] = {-0.660944 ,-0.750276 ,0.015480};
+static float N021[3] = {0.503549 ,-0.862908 ,-0.042749};
+static float N022[3] = {0.953202 ,-0.302092 ,-0.012089};
+static float N023[3] = {0.998738 ,0.023574 ,0.044344};
+static float N024[3] = {0.979297 ,0.193272 ,0.060202};
+static float N025[3] = {0.798300 ,0.464885 ,0.382883};
+static float N026[3] = {-0.756590 ,0.452403 ,0.472126};
+static float N027[3] = {-0.953855 ,0.293003 ,0.065651};
+static float N028[3] = {-0.998033 ,0.040292 ,0.048028};
+static float N029[3] = {-0.977079 ,-0.204288 ,0.059858};
+static float N030[3] = {-0.729117 ,-0.675304 ,0.111140};
+static float N031[3] = {0.598361 ,-0.792753 ,0.116221};
+static float N032[3] = {0.965192 ,-0.252991 ,0.066332};
+static float N033[3] = {0.998201 ,-0.002790 ,0.059892};
+static float N034[3] = {0.978657 ,0.193135 ,0.070207};
+static float N035[3] = {0.718815 ,0.680392 ,0.142733};
+static float N036[3] = {-0.383096 ,0.906212 ,0.178936};
+static float N037[3] = {-0.952831 ,0.292590 ,0.080647};
+static float N038[3] = {-0.997680 ,0.032417 ,0.059861};
+static float N039[3] = {-0.982629 ,-0.169881 ,0.074700};
+static float N040[3] = {-0.695424 ,-0.703466 ,0.146700};
+static float N041[3] = {0.359323 ,-0.915531 ,0.180805};
+static float N042[3] = {0.943356 ,-0.319387 ,0.089842};
+static float N043[3] = {0.998272 ,-0.032435 ,0.048993};
+static float N044[3] = {0.978997 ,0.193205 ,0.065084};
+static float N045[3] = {0.872144 ,0.470094 ,-0.135565};
+static float N046[3] = {-0.664282 ,0.737945 ,-0.119027};
+static float N047[3] = {-0.954508 ,0.288570 ,0.075107};
+static float N048[3] = {-0.998273 ,0.032406 ,0.048993};
+static float N049[3] = {-0.979908 ,-0.193579 ,0.048038};
+static float N050[3] = {-0.858736 ,-0.507202 ,-0.072938};
+static float N051[3] = {0.643545 ,-0.763887 ,-0.048237};
+static float N052[3] = {0.955580 ,-0.288954 ,0.058068};
+static float N058[3] = {0.000050 ,0.793007 ,-0.609213};
+static float N059[3] = {0.913510 ,0.235418 ,-0.331779};
+static float N060[3] = {-0.807970 ,0.495000 ,-0.319625};
+static float N061[3] = {0.000000 ,0.784687 ,-0.619892};
+static float N062[3] = {0.000000 ,-1.000000 ,0.000000};
+static float N063[3] = {0.000000 ,1.000000 ,0.000000};
+static float N064[3] = {0.000000 ,1.000000 ,0.000000};
+static float N065[3] = {0.000000 ,1.000000 ,0.000000};
+static float N066[3] = {-0.055784 ,0.257059 ,0.964784};
+static float N069[3] = {-0.000505 ,-0.929775 ,-0.368127};
+static float N070[3] = {0.000000 ,1.000000 ,0.000000};
+static float P002[3] = {0.00, -36.59, 5687.72};
+static float P003[3] = {90.00, 114.73, 724.38};
+static float P004[3] = {58.24, -146.84, 262.35};
+static float P005[3] = {27.81, 231.52, 510.43};
+static float P006[3] = {-27.81, 230.43, 509.76};
+static float P007[3] = {-46.09, -146.83, 265.84};
+static float P008[3] = {-90.00, 103.84, 718.53};
+static float P009[3] = {-131.10, -165.92, 834.85};
+static float P010[3] = {-27.81, -285.31, 500.00};
+static float P011[3] = {27.81, -285.32, 500.00};
+static float P012[3] = {147.96, -170.89, 845.50};
+static float P013[3] = {180.00, 0.00, 2000.00};
+static float P014[3] = {145.62, 352.67, 2000.00};
+static float P015[3] = {55.62, 570.63, 2000.00};
+static float P016[3] = {-55.62, 570.64, 2000.00};
+static float P017[3] = {-145.62, 352.68, 2000.00};
+static float P018[3] = {-180.00, 0.01, 2000.00};
+static float P019[3] = {-178.20, -352.66, 2001.61};
+static float P020[3] = {-55.63, -570.63, 2000.00};
+static float P021[3] = {55.62, -570.64, 2000.00};
+static float P022[3] = {179.91, -352.69, 1998.39};
+static float P023[3] = {150.00, 0.00, 3000.00};
+static float P024[3] = {121.35, 293.89, 3000.00};
+static float P025[3] = {46.35, 502.93, 2883.09};
+static float P026[3] = {-46.35, 497.45, 2877.24};
+static float P027[3] = {-121.35, 293.90, 3000.00};
+static float P028[3] = {-150.00, 0.00, 3000.00};
+static float P029[3] = {-152.21, -304.84, 2858.68};
+static float P030[3] = {-46.36, -475.52, 3000.00};
+static float P031[3] = {46.35, -475.53, 3000.00};
+static float P032[3] = {155.64, -304.87, 2863.50};
+static float P033[3] = {90.00, 0.00, 4000.00};
+static float P034[3] = {72.81, 176.33, 4000.00};
+static float P035[3] = {27.81, 285.32, 4000.00};
+static float P036[3] = {-27.81, 285.32, 4000.00};
+static float P037[3] = {-72.81, 176.34, 4000.00};
+static float P038[3] = {-90.00, 0.00, 4000.00};
+static float P039[3] = {-72.81, -176.33, 4000.00};
+static float P040[3] = {-27.81, -285.31, 4000.00};
+static float P041[3] = {27.81, -285.32, 4000.00};
+static float P042[3] = {72.81, -176.34, 4000.00};
+static float P043[3] = {30.00, 0.00, 5000.00};
+static float P044[3] = {24.27, 58.78, 5000.00};
+static float P045[3] = {9.27, 95.11, 5000.00};
+static float P046[3] = {-9.27, 95.11, 5000.00};
+static float P047[3] = {-24.27, 58.78, 5000.00};
+static float P048[3] = {-30.00, 0.00, 5000.00};
+static float P049[3] = {-24.27, -58.78, 5000.00};
+static float P050[3] = {-9.27, -95.10, 5000.00};
+static float P051[3] = {9.27, -95.11, 5000.00};
+static float P052[3] = {24.27, -58.78, 5000.00};
+static float P058[3] = {0.00, 1212.72, 2703.08};
+static float P059[3] = {50.36, 0.00, 108.14};
+static float P060[3] = {-22.18, 0.00, 108.14};
+static float P061[3] = {0.00, 1181.61, 6344.65};
+static float P062[3] = {516.45, -887.08, 2535.45};
+static float P063[3] = {-545.69, -879.31, 2555.63};
+static float P064[3] = {618.89, -1005.64, 2988.32};
+static float P065[3] = {-635.37, -1014.79, 2938.68};
+static float P066[3] = {0.00, 1374.43, 3064.18};
+static float P069[3] = {0.00, -418.25, 5765.04};
+static float P070[3] = {0.00, 1266.91, 6629.60};
+static float P071[3] = {-139.12, -124.96, 997.98};
+static float P072[3] = {-139.24, -110.18, 1020.68};
+static float P073[3] = {-137.33, -94.52, 1022.63};
+static float P074[3] = {-137.03, -79.91, 996.89};
+static float P075[3] = {-135.21, -91.48, 969.14};
+static float P076[3] = {-135.39, -110.87, 968.76};
+static float P077[3] = {150.23, -78.44, 995.53};
+static float P078[3] = {152.79, -92.76, 1018.46};
+static float P079[3] = {154.19, -110.20, 1020.55};
+static float P080[3] = {151.33, -124.15, 993.77};
+static float P081[3] = {150.49, -111.19, 969.86};
+static float P082[3] = {150.79, -92.41, 969.70};
+static float iP002[3] = {0.00, -36.59, 5687.72};
+static float iP004[3] = {58.24, -146.84, 262.35};
+static float iP007[3] = {-46.09, -146.83, 265.84};
+static float iP010[3] = {-27.81, -285.31, 500.00};
+static float iP011[3] = {27.81, -285.32, 500.00};
+static float iP023[3] = {150.00, 0.00, 3000.00};
+static float iP024[3] = {121.35, 293.89, 3000.00};
+static float iP025[3] = {46.35, 502.93, 2883.09};
+static float iP026[3] = {-46.35, 497.45, 2877.24};
+static float iP027[3] = {-121.35, 293.90, 3000.00};
+static float iP028[3] = {-150.00, 0.00, 3000.00};
+static float iP029[3] = {-121.35, -304.84, 2853.86};
+static float iP030[3] = {-46.36, -475.52, 3000.00};
+static float iP031[3] = {46.35, -475.53, 3000.00};
+static float iP032[3] = {121.35, -304.87, 2853.86};
+static float iP033[3] = {90.00, 0.00, 4000.00};
+static float iP034[3] = {72.81, 176.33, 4000.00};
+static float iP035[3] = {27.81, 285.32, 4000.00};
+static float iP036[3] = {-27.81, 285.32, 4000.00};
+static float iP037[3] = {-72.81, 176.34, 4000.00};
+static float iP038[3] = {-90.00, 0.00, 4000.00};
+static float iP039[3] = {-72.81, -176.33, 4000.00};
+static float iP040[3] = {-27.81, -285.31, 4000.00};
+static float iP041[3] = {27.81, -285.32, 4000.00};
+static float iP042[3] = {72.81, -176.34, 4000.00};
+static float iP043[3] = {30.00, 0.00, 5000.00};
+static float iP044[3] = {24.27, 58.78, 5000.00};
+static float iP045[3] = {9.27, 95.11, 5000.00};
+static float iP046[3] = {-9.27, 95.11, 5000.00};
+static float iP047[3] = {-24.27, 58.78, 5000.00};
+static float iP048[3] = {-30.00, 0.00, 5000.00};
+static float iP049[3] = {-24.27, -58.78, 5000.00};
+static float iP050[3] = {-9.27, -95.10, 5000.00};
+static float iP051[3] = {9.27, -95.11, 5000.00};
+static float iP052[3] = {24.27, -58.78, 5000.00};
+static float iP061[3] = {0.00, 1181.61, 6344.65};
+static float iP069[3] = {0.00, -418.25, 5765.04};
+static float iP070[3] = {0.00, 1266.91, 6629.60};
+/* *INDENT-ON* */
+
+void
+Fish001(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N006);
+    glVertex3fv(P006);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N008);
+    glVertex3fv(P008);
+    glNormal3fv(N060);
+    glVertex3fv(P060);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N009);
+    glVertex3fv(P009);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N010);
+    glVertex3fv(P010);
+    glNormal3fv(N007);
+    glVertex3fv(P007);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N004);
+    glVertex3fv(P004);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N011);
+    glVertex3fv(P011);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glNormal3fv(N005);
+    glVertex3fv(P005);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N059);
+    glVertex3fv(P059);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glNormal3fv(N003);
+    glVertex3fv(P003);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N012);
+    glVertex3fv(P012);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P071);
+    glVertex3fv(P072);
+    glVertex3fv(P073);
+    glVertex3fv(P074);
+    glVertex3fv(P075);
+    glVertex3fv(P076);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P077);
+    glVertex3fv(P078);
+    glVertex3fv(P079);
+    glVertex3fv(P080);
+    glVertex3fv(P081);
+    glVertex3fv(P082);
+    glEnd();
+}
+
+void
+Fish002(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N014);
+    glVertex3fv(P014);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N017);
+    glVertex3fv(P017);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N013);
+    glVertex3fv(P013);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N021);
+    glVertex3fv(P021);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N018);
+    glVertex3fv(P018);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N020);
+    glVertex3fv(P020);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish003(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N023);
+    glVertex3fv(P023);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N024);
+    glVertex3fv(P024);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N031);
+    glVertex3fv(P031);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N027);
+    glVertex3fv(P027);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N028);
+    glVertex3fv(P028);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N030);
+    glVertex3fv(P030);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glEnd();
+}
+
+void
+Fish004(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N041);
+    glVertex3fv(P041);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N042);
+    glVertex3fv(P042);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N033);
+    glVertex3fv(P033);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N034);
+    glVertex3fv(P034);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N035);
+    glVertex3fv(P035);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N036);
+    glVertex3fv(P036);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N037);
+    glVertex3fv(P037);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N038);
+    glVertex3fv(P038);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N039);
+    glVertex3fv(P039);
+    glNormal3fv(N040);
+    glVertex3fv(P040);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glNormal3fv(N070);
+    glVertex3fv(P070);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glNormal3fv(N061);
+    glVertex3fv(P061);
+    glEnd();
+}
+
+void
+Fish005(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glNormal3fv(N045);
+    glVertex3fv(P045);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glNormal3fv(N044);
+    glVertex3fv(P044);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glNormal3fv(N043);
+    glVertex3fv(P043);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N052);
+    glVertex3fv(P052);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N046);
+    glVertex3fv(P046);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N047);
+    glVertex3fv(P047);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N048);
+    glVertex3fv(P048);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N049);
+    glVertex3fv(P049);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N051);
+    glVertex3fv(P051);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N050);
+    glVertex3fv(P050);
+    glNormal3fv(N069);
+    glVertex3fv(P069);
+    glNormal3fv(N002);
+    glVertex3fv(P002);
+    glEnd();
+}
+
+void
+Fish006(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N025);
+    glVertex3fv(P025);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N026);
+    glVertex3fv(P026);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N066);
+    glVertex3fv(P066);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N058);
+    glVertex3fv(P058);
+    glNormal3fv(N015);
+    glVertex3fv(P015);
+    glNormal3fv(N016);
+    glVertex3fv(P016);
+    glEnd();
+}
+
+void
+Fish007(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N022);
+    glVertex3fv(P022);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N062);
+    glVertex3fv(P062);
+    glNormal3fv(N064);
+    glVertex3fv(P064);
+    glNormal3fv(N032);
+    glVertex3fv(P032);
+    glEnd();
+}
+
+void
+Fish008(void)
+{
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N019);
+    glVertex3fv(P019);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glNormal3fv(N063);
+    glVertex3fv(P063);
+    glNormal3fv(N065);
+    glVertex3fv(P065);
+    glNormal3fv(N029);
+    glVertex3fv(P029);
+    glEnd();
+}
+
+void
+Fish009(void)
+{
+    glBegin(GL_POLYGON);
+    glVertex3fv(P059);
+    glVertex3fv(P012);
+    glVertex3fv(P009);
+    glVertex3fv(P060);
+    glEnd();
+    glBegin(GL_POLYGON);
+    glVertex3fv(P012);
+    glVertex3fv(P004);
+    glVertex3fv(P007);
+    glVertex3fv(P009);
+    glEnd();
+}
+
+void
+Fish_1(void)
+{
+    Fish004();
+    Fish005();
+    Fish003();
+    Fish007();
+    Fish006();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_2(void)
+{
+    Fish005();
+    Fish004();
+    Fish003();
+    Fish008();
+    Fish006();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+}
+
+void
+Fish_3(void)
+{
+    Fish005();
+    Fish004();
+    Fish007();
+    Fish003();
+    Fish002();
+    Fish008();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_4(void)
+{
+    Fish005();
+    Fish004();
+    Fish008();
+    Fish003();
+    Fish002();
+    Fish007();
+    Fish009();
+    Fish001();
+    Fish006();
+}
+
+void
+Fish_5(void)
+{
+    Fish009();
+    Fish006();
+    Fish007();
+    Fish001();
+    Fish002();
+    Fish003();
+    Fish008();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_6(void)
+{
+    Fish009();
+    Fish006();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish004();
+    Fish005();
+}
+
+void
+Fish_7(void)
+{
+    Fish009();
+    Fish001();
+    Fish007();
+    Fish005();
+    Fish002();
+    Fish008();
+    Fish003();
+    Fish004();
+    Fish006();
+}
+
+void
+Fish_8(void)
+{
+    Fish009();
+    Fish008();
+    Fish001();
+    Fish002();
+    Fish007();
+    Fish003();
+    Fish005();
+    Fish004();
+    Fish006();
+}
+
+void
+DrawShark(fishRec * fish)
+{
+    int n;
+    float seg1, seg2, seg3, seg4, segup;
+    float thrash, chomp;
+
+    fish->htail = (int) (fish->htail - (int) (5.0 * fish->v)) % 360;
+
+    thrash = 50.0 * fish->v;
+
+    seg1 = 0.6 * thrash * sin(fish->htail * RRAD);
+    seg2 = 1.8 * thrash * sin((fish->htail + 45.0) * RRAD);
+    seg3 = 3.0 * thrash * sin((fish->htail + 90.0) * RRAD);
+    seg4 = 4.0 * thrash * sin((fish->htail + 110.0) * RRAD);
+
+    chomp = 0.0;
+    if (fish->v > 2.0) {
+        chomp = -(fish->v - 2.0) * 200.0;
+    }
+    P004[1] = iP004[1] + chomp;
+    P007[1] = iP007[1] + chomp;
+    P010[1] = iP010[1] + chomp;
+    P011[1] = iP011[1] + chomp;
+
+    P023[0] = iP023[0] + seg1;
+    P024[0] = iP024[0] + seg1;
+    P025[0] = iP025[0] + seg1;
+    P026[0] = iP026[0] + seg1;
+    P027[0] = iP027[0] + seg1;
+    P028[0] = iP028[0] + seg1;
+    P029[0] = iP029[0] + seg1;
+    P030[0] = iP030[0] + seg1;
+    P031[0] = iP031[0] + seg1;
+    P032[0] = iP032[0] + seg1;
+    P033[0] = iP033[0] + seg2;
+    P034[0] = iP034[0] + seg2;
+    P035[0] = iP035[0] + seg2;
+    P036[0] = iP036[0] + seg2;
+    P037[0] = iP037[0] + seg2;
+    P038[0] = iP038[0] + seg2;
+    P039[0] = iP039[0] + seg2;
+    P040[0] = iP040[0] + seg2;
+    P041[0] = iP041[0] + seg2;
+    P042[0] = iP042[0] + seg2;
+    P043[0] = iP043[0] + seg3;
+    P044[0] = iP044[0] + seg3;
+    P045[0] = iP045[0] + seg3;
+    P046[0] = iP046[0] + seg3;
+    P047[0] = iP047[0] + seg3;
+    P048[0] = iP048[0] + seg3;
+    P049[0] = iP049[0] + seg3;
+    P050[0] = iP050[0] + seg3;
+    P051[0] = iP051[0] + seg3;
+    P052[0] = iP052[0] + seg3;
+    P002[0] = iP002[0] + seg4;
+    P061[0] = iP061[0] + seg4;
+    P069[0] = iP069[0] + seg4;
+    P070[0] = iP070[0] + seg4;
+
+    fish->vtail += ((fish->dtheta - fish->vtail) * 0.1);
+
+    if (fish->vtail > 0.5) {
+        fish->vtail = 0.5;
+    } else if (fish->vtail < -0.5) {
+        fish->vtail = -0.5;
+    }
+    segup = thrash * fish->vtail;
+
+    P023[1] = iP023[1] + segup;
+    P024[1] = iP024[1] + segup;
+    P025[1] = iP025[1] + segup;
+    P026[1] = iP026[1] + segup;
+    P027[1] = iP027[1] + segup;
+    P028[1] = iP028[1] + segup;
+    P029[1] = iP029[1] + segup;
+    P030[1] = iP030[1] + segup;
+    P031[1] = iP031[1] + segup;
+    P032[1] = iP032[1] + segup;
+    P033[1] = iP033[1] + segup * 5.0;
+    P034[1] = iP034[1] + segup * 5.0;
+    P035[1] = iP035[1] + segup * 5.0;
+    P036[1] = iP036[1] + segup * 5.0;
+    P037[1] = iP037[1] + segup * 5.0;
+    P038[1] = iP038[1] + segup * 5.0;
+    P039[1] = iP039[1] + segup * 5.0;
+    P040[1] = iP040[1] + segup * 5.0;
+    P041[1] = iP041[1] + segup * 5.0;
+    P042[1] = iP042[1] + segup * 5.0;
+    P043[1] = iP043[1] + segup * 12.0;
+    P044[1] = iP044[1] + segup * 12.0;
+    P045[1] = iP045[1] + segup * 12.0;
+    P046[1] = iP046[1] + segup * 12.0;
+    P047[1] = iP047[1] + segup * 12.0;
+    P048[1] = iP048[1] + segup * 12.0;
+    P049[1] = iP049[1] + segup * 12.0;
+    P050[1] = iP050[1] + segup * 12.0;
+    P051[1] = iP051[1] + segup * 12.0;
+    P052[1] = iP052[1] + segup * 12.0;
+    P002[1] = iP002[1] + segup * 17.0;
+    P061[1] = iP061[1] + segup * 17.0;
+    P069[1] = iP069[1] + segup * 17.0;
+    P070[1] = iP070[1] + segup * 17.0;
+
+    glPushMatrix();
+
+    glTranslatef(0.0, 0.0, -3000.0);
+
+//    glGetFloatv(GL_MODELVIEW_MATRIX, &mat[0][0]);
+    n = 0;
+/*
+    if (mat[0][2] >= 0.0) {
+        n += 1;
+    }
+    if (mat[1][2] >= 0.0) {
+        n += 2;
+    }
+    if (mat[2][2] >= 0.0) {
+        n += 4;
+    }
+*/
+    glScalef(2.0, 1.0, 1.0);
+
+    glEnable(GL_CULL_FACE);
+    switch (n) {
+    case 0:
+        Fish_1();
+        break;
+    case 1:
+        Fish_2();
+        break;
+    case 2:
+        Fish_3();
+        break;
+    case 3:
+        Fish_4();
+        break;
+    case 4:
+        Fish_5();
+        break;
+    case 5:
+        Fish_6();
+        break;
+    case 6:
+        Fish_7();
+        break;
+    case 7:
+        Fish_8();
+        break;
+    }
+    glDisable(GL_CULL_FACE);
+
+    glPopMatrix();
+}
+
Index: trunk/src/testing/configure
===================================================================
--- trunk/src/testing/configure	(revision 4)
+++ trunk/src/testing/configure	(revision 4)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "Done"
+
Index: trunk/src/testing/include/suil.h
===================================================================
--- trunk/src/testing/include/suil.h	(revision 4)
+++ trunk/src/testing/include/suil.h	(revision 4)
@@ -0,0 +1,54 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: suil.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SUIL_H
+#define _SUIL_H
+
+#include "fsClient.h"
+
+class suil : public fsClient {
+
+public:
+   suil() {}
+   ~suil() {}
+   int init(const char *config);
+};
+
+#endif
Index: trunk/src/testing/include/streamProtocol.h
===================================================================
--- trunk/src/testing/include/streamProtocol.h	(revision 4)
+++ trunk/src/testing/include/streamProtocol.h	(revision 4)
@@ -0,0 +1,193 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: streamProtocol.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ * Description: This is the header file for the stream protocol modules of SAGE.
+ *       It gives the interface to be provided by all the protocols included.
+ * Notes : This is based on the TeraVision network protocol.
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _STREAM_PROTOCOL_H
+#define _STREAM_PROTOCOL_H
+
+#include "sageBase.h"
+
+#define REG_MSG_SIZE 1024
+
+class sageBlock;
+class sagePixelBlock;
+class sageBlockPool;
+class sageBlockGroup;
+class sageBlockFrame;
+
+/**
+ * sageNwConfig
+ */
+class sageNwConfig {
+public:
+   int rcvBufSize;
+   int sendBufSize;
+   int mtuSize;
+   int blockSize;
+   int groupSize;
+   double maxBandWidth; // maximum data amount that can be sent in a micro-second on the host
+   int maxCheckInterval;
+   int flowWindow;
+
+   sageNwConfig() : rcvBufSize(8388608), sendBufSize(65536), mtuSize(9000),
+         blockSize(0), groupSize(0), maxBandWidth(1000), maxCheckInterval(1000),
+         flowWindow(5) {}
+};
+
+/**
+ * streamProtocol
+ */
+class streamProtocol{
+
+protected:
+   sageStreamMode sMode;
+   nwProtocol   protocol;
+   int rcvPort;
+   sageNwConfig config;
+   std::vector<int> rcvList;
+   std::vector<int> sendList;
+
+public:
+   streamProtocol() {}
+
+   /**
+    * init
+	*
+	* @param m sageStreamMode, mode of operation
+	* @param p integer, receiver port
+	* @param c sageNwConfig &, configuration info
+	* @return a false if a receiver can't be started at this port p
+	*/
+   int init(sageStreamMode m, int p, sageNwConfig &c);
+
+   /**
+    * returns nwProtocol object (member variable)
+	* @param void
+	* @return member variable protocol
+	*/
+   inline nwProtocol getProtocol() { return protocol; }
+
+   /**
+    * set network configurations for new network connections
+    * sets the member variable config
+	*
+	* @param c sageNwConfig
+	* @return void
+	*/
+   inline void setConfig(sageNwConfig c) { config = c; }
+   // set network configurations for new network connections
+   inline void setConfig(int port, int blockSize = 0, int groupSize = 0, int sendBufSize= 0)
+   {
+      rcvPort = port;
+      if (blockSize > 0)
+         config.blockSize = blockSize;
+      if (groupSize > 0)
+         config.groupSize = groupSize;
+      if (sendBufSize > 0)
+	      config.sendBufSize = sendBufSize;
+   }
+
+   virtual void setupBlockPool(sageBlockPool *pool, int id = -1) = 0;
+   virtual void setFrameSize(int id, int size) = 0;
+   virtual void resetFrameSize(int id) = 0;
+   virtual void setFrameRate(double rate, int id = -1) = 0;
+
+   int duplicate(sageApiOption op);
+
+   virtual int close(int id, int mode = -1);
+
+   /**
+	* For SAGE_RCV or SAGE_BRIDGE mode
+    * checks if there's new sender trying to connect
+	* if yes, create new connection and return the sender ID
+	* if no, return -1
+	* memory bigger than REG_MSG_SIZE should be allocated to msg
+	* @param msg char *, default NULL
+	* @param op sageApiOption, default 0
+	* @return senderID or -1
+	*/
+   virtual int checkConnections(char *msg = NULL, sageApiOption op = 0) = 0; // for SAGE_RCV or SAGE_BRIDGE mode
+
+
+   /**
+	* For SAGE_SEND or SAGE_BRIDGE mode
+    * This function blocks till it connects (or cannot connect)
+    * create a connection to a receiver
+    * and return the receiver ID
+    * the length of string msg should not exceed REG_MSG_SIZE
+	* @param ip char *
+	* @param msg char *, default NULL
+	* @return receiver ID
+	*/
+   virtual int connect(char* ip, char *msg = NULL) = 0; // for SAGE_SEND or SAGE_BRDIGE mode
+
+   virtual int send(int id, sageBlock *sb, sageApiOption op) = 0;
+
+   /**
+       * sungwon experimental, swexp
+       */
+    virtual int sendpixelonly(int id, sageBlockFrame *sb) = 0;
+
+   virtual int recv(int id, sageBlock *sb, sageApiOption op) = 0;
+
+   virtual int sendControl(int id, int frameID, int configID) = 0;
+
+   virtual int sendGrp(int id, sagePixelBlock *sb, int configID) = 0;
+   // id : receiver ID, sb : pixel or control Block
+
+   virtual int recvGrp(int id, sageBlockGroup *sbg) = 0;
+   // id : sender ID, sbg : vacant block group
+
+   virtual int flush(int id, int configID) = 0;
+
+   virtual int getRcvSockFd(int id) = 0;
+
+   /**
+    *  When called, it is expected to close all internal sockets and force any operation
+    * (send/recv) to be interrupted. If this function is not called explicitly the destructor is supposed
+    * to call it before cleaning up
+    */
+   virtual int close() = 0;
+   virtual ~streamProtocol() {}
+};
+
+#endif
Index: trunk/src/testing/include/fsCore.h
===================================================================
--- trunk/src/testing/include/fsCore.h	(revision 4)
+++ trunk/src/testing/include/fsCore.h	(revision 4)
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsCore.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+
+#ifndef _FS_CORE_H
+#define _FS_CORE_H
+
+#include "sage.h"
+
+class fsManager;
+class appInExec;
+
+/**
+ * class fsCore
+ * The core part of the Free Space Manager processing user commands to run applications or send appropriate orders to each part of SAGE
+ */
+class fsCore {
+private:
+   fsManager *fsm;
+   double startTime;
+   int winSteps;
+   
+public:
+   fsCore();
+   ~fsCore();
+   int init(fsManager *fsm);
+   int parseMessage(sageMessage &msg, int clientID);
+   int sendSageStatus(int clientID);
+   int sendAppStatus(int clientID, char *appName);
+   int sendAppInfo(int clientID);
+   int sendAppInfo(int appID, int clientID);
+   int sendDisplayInfo(int clientID);
+   int initDisp(appInExec* app);
+   int initAudio();
+
+   int windowChanged(int winID);
+   int bringToFront(int winID);
+   int rotateWindow(char *msgStr);
+   void clearAppInstance(int id);
+	appInExec* findApp(int id, int& index);
+	int getAvailableInstID(void);
+
+};
+
+#endif
Index: trunk/src/testing/include/overlayPointer.h
===================================================================
--- trunk/src/testing/include/overlayPointer.h	(revision 4)
+++ trunk/src/testing/include/overlayPointer.h	(revision 4)
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: overlayPointer.h
+ * Author : Ratko Jagodic, Byungil Jeong
+ *
+ *   Description: the super class of simple drawing objects 
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+*********************************************************************************/
+
+#ifndef SAGE_POINTER_H
+#define SAGE_POINTER_H
+
+#include "sageDrawObject.h"
+
+
+
+class overlayPointer : public sageDrawObject {
+
+private:
+   void drawCursor(double w, double h);
+   void drawRotateArrows(float radius);
+
+protected:
+   
+public:
+   // this defines what gets drawn
+   int ptrShape;   // influences the shape of the pointer
+   int orientation;  //0=none, 1=bottomleft, 2=topleft, 3=topright, 4=bottomright
+   int angle;   // where the down side of the pointer is
+   bool inApp;  // whether the pointer is in the app mode or not
+
+   // color of pointer for up/down states
+   float up_color[3], down_color[3], in_app_color[3], *color;
+
+   // METHODS
+   overlayPointer();
+   int init(char *name);   
+   int draw();   
+   int destroy();
+   int parseMessage(char *msg);
+};
+
+#endif
Index: trunk/src/testing/include/overlayApp.h
===================================================================
--- trunk/src/testing/include/overlayApp.h	(revision 4)
+++ trunk/src/testing/include/overlayApp.h	(revision 4)
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: overlayApp.h
+ * Author : Ratko Jagodic
+ *
+ *   Description: the super class of simple drawing objects 
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+*********************************************************************************/
+
+#ifndef SAGE_APP_OVERLAY_H
+#define SAGE_APP_OVERLAY_H
+
+#include "sageDrawObject.h"
+
+class overlayApp : public sageDrawObject {
+
+private:
+   void drawOutline();
+   void drawCorners();
+   void drawTop();
+   
+   // this defines what gets drawn
+   int state;     //resize or move
+   int activeCorners[7];  //0=bottom, 1=top, 3=bottomleft, 4=topleft, 5=topright, 6=bottomright
+   float aspectRatio;  //to preserve it during resizing
+   float outline[4];  //left, right, top, bottom
+   int cornerSize;
+   float z;
+
+   // color of pointer for up/down states
+   float border_color[4], corner_color[4], *color;
+
+	bool specialDevice; //is controlled by special device (Wiimote) -> different app behaviour
+
+protected:
+   
+public:
+
+
+   // METHODS
+   overlayApp();
+   int init(char *name);   
+   int draw();   
+   int destroy();
+   int parseMessage(char *msg);
+};
+
+#endif
Index: trunk/src/testing/include/sageStreamer.h
===================================================================
--- trunk/src/testing/include/sageStreamer.h	(revision 4)
+++ trunk/src/testing/include/sageStreamer.h	(revision 4)
@@ -0,0 +1,274 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageStreamer.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGESTREAMER_H_
+#define SAGESTREAMER_H_
+
+#include "sageConfig.h"
+#include "sageBlock.h"
+#include "streamProtocol.h"
+#include "sageDoubleBuf.h"
+#include "sageAudioCircBuf.h"
+#include "sageSync.h"
+#include "streamInfo.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+
+// sungwon exp
+#include <list>
+
+#define ALL_CONNECTION       0
+#define ACTIVE_CONNECTION    1
+#define INACTIVE_CONNECTION  2
+
+typedef struct {
+   int  rcvID;
+   int  nodeID;
+   bool active;
+} streamParam;
+
+class sageBlockFrame;
+class sagePixelBlock;
+class sageBlockPartition;
+class sageBlockGroup;
+
+/**
+ * sageStreamer
+ */
+class sageStreamer {
+protected:
+   streamerConfig config;
+   streamProtocol *nwObj;
+   sageNwConfig nwCfg;
+   int winID;    // display window ID of the application
+   
+   int streamNum;
+   int rcvNodeNum;
+   bool streamerOn;
+   
+   streamParam *params;
+   streamGroup sGrp;
+   bridgeStreamGroup bStreamGrp;
+   sageBlockPartition *partition;
+   
+   int blockSize;
+   //bool reconfigured;   
+   //bool timeBlockFlag;
+   unsigned long totalBandWidth;
+   int frameID;
+   int configID;
+   
+   bool firstConfiguration;
+   pthread_mutex_t *reconfigMutex;
+   std::deque<char *> msgQueue;
+   sageTimer streamTimer;
+   sageCounter frameCounter;
+   double interval;
+   double timeError;
+
+   pthread_t thId;
+
+   /**
+    * invokes streamLoop
+    */
+   static void* nwThread(void *args);
+   
+   //int sendTimeBlock(int frame);
+   
+   virtual int streamLoop() = 0;
+   virtual int reconfigureStreams(char *msgStr);
+
+   /**
+    * called by sageStreamer::initNetworks()
+    * it calls nwObj->connect()
+    *
+    * this function makes connection between sender(SAIL) and receivers(SDM)
+    * sends 1KByte of regMsg to receivers
+    */
+   virtual int connectToRcv(sageToken &tokenBuf, bool localPort = false);
+   virtual void setupBlockPool() {}
+   
+public:
+   sageStreamer();
+   virtual ~sageStreamer();
+
+   /**
+    * creates sageTcpModule object. member var *nwObj will point it
+    * calls connectToRcv()
+    * starts nwThread
+    */
+   virtual int initNetworks(char *data, bool localPort = false);
+   
+   void setWinID(int id) { winID = id; }
+   //void setSyncClient(sageSyncClient *sClient) { syncClientObj = sClient; }
+   int getFrameID() { return frameID; }
+   bool isFirstConfig() { return firstConfiguration; }
+   int enqueMsg(char *data);
+   void checkInterval();
+   void setFrameRate(float frate) { //nwObj->setFrameRate((double)frate); 
+         interval = 1000000.0/frate; }
+   syncGroup* getSyncGroup() { return config.sGroup; }
+   
+   virtual sageDoubleBuf* getDoubleBuffer() { return NULL; }
+   unsigned long getBandWidth() { return totalBandWidth; }
+   void resetBandWidth() { totalBandWidth = 0; }
+   bool isActive() { return streamerOn; }
+   unsigned int getFrameCount() { return frameCounter.getValue(); }
+   void resetFrameCounter() { frameCounter.reset(); }
+   virtual int regeneratePixelBlocks() { return 0; }
+
+   /**
+    * blockSize is calculated here. ceil((blockX * blockY * bytesPerPixel)/compFactor) + BLOCK_HEADER_SIZE
+    * sageBlockGroup object is created here
+    */
+   virtual void setNwConfig(sageNwConfig &nc) { nwCfg = nc; }
+   virtual void shutdown() { streamerOn = false; }
+   inline bool isStreamerOn() { return streamerOn; }
+};
+
+/**
+ * sageBlockStreamer
+ * sail uses this to stream.
+ *
+ * This class is responsible for creating doubleBuffer for sending, getting frame from an application, and streaming it to sage
+ * the size of double buffer is two times of ceil((resX*resY*bytesPerPixel)/(compX*compY)) + BLOCK_HEADER_SIZE
+ */
+class sageBlockStreamer : public sageStreamer {
+protected:
+   sageDoubleBuf  *doubleBuf;
+   int bytesPerPixel;
+   float compX, compY, compFactor;
+	sageBlockGroup *nbg;
+
+	/**
+	 * keeps calling streamPixelData() with one part of the doubleBuf
+	 */
+   virtual int streamLoop();
+   void setupBlockPool();
+   int createDoubleBuffer();
+   int sendPixelBlock(sagePixelBlock *block);
+   int sendControlBlock(int flag, int cond);
+
+   /**
+    * keeps calling sendPixelBlock() with sagePixelBlock extracted from nbg->front()
+    */
+   int streamPixelData(sageBlockFrame *buf);
+   
+   // sungwon exp
+   bool affinityFlag;
+   std::list<int> cpulist;
+   pthread_mutex_t affinityMutex;
+
+
+public:
+   sageBlockStreamer(streamerConfig &conf, int pixSize);
+   
+   sageDoubleBuf* getDoubleBuffer() { return doubleBuf; }
+
+   /**
+    * creates sageBlockPartition object.
+    * calls initFrame with the front and the back buffer of the double buffer
+    *
+    * creates sageBlockGroup object and assigns it to the member variable sageBlockGroup *nbg
+    */
+   virtual void setNwConfig(sageNwConfig &nc);
+   void shutdown(); 
+   virtual ~sageBlockStreamer();
+
+   // sungwon exp
+   void setAffinity(const char *msgdata);
+};
+
+class sageBlockBuf;
+
+class bridgeStreamer : public sageStreamer {
+protected:
+   sageBlockBuf *blockBuffer;
+   int updateType;
+   sageTimer frameTimer;
+   double accInterval;
+   bool firstFrame;
+   
+   virtual int streamLoop();
+   int streamPixelData();
+   void setupBlockPool();
+   int sendPixelBlock(sagePixelBlock *block);
+   int sendControlBlock(int flag, int cond);
+   
+public:
+   bridgeStreamer(streamerConfig &conf, sageBlockBuf *buf, streamProtocol *obj);
+   
+   int initNetworks(char *data, bool localPort = false);
+   int storeStreamConfig(char *msgStr);
+   void shutdown();
+   //void setBlockMutex(pthread_mutex_t *mutex) { blockMutex = mutex; }
+   
+   virtual ~bridgeStreamer() {}
+};
+
+/**
+ * sageAudioStreamer
+ */
+class sageAudioStreamer : public sageStreamer {
+protected:
+   sageAudioCircBuf* buffer;
+   int bytesPerSample;
+
+   virtual int streamLoop();
+   virtual int reconfigureStreams(char *msgStr);   
+   virtual int connectToRcv(sageToken &tokenBuf, bool localPort = false);
+
+   int sendAudioBlock();
+   int sendControlBlock(int flag, int cond);
+   int streamAudioData();
+   
+public:
+   sageAudioStreamer(streamerConfig &conf, int sampleSize, sageAudioCircBuf* buff);
+
+   sageAudioCircBuf* getBuffer() { return buffer; }
+   virtual void setNwConfig(sageNwConfig &nc);
+   virtual ~sageAudioStreamer();
+protected:
+   sageAudioBlock aBlock;
+   int initializeBlock();
+   
+};
+
+#endif
Index: trunk/src/testing/include/tileConfig.h
===================================================================
--- trunk/src/testing/include/tileConfig.h	(revision 4)
+++ trunk/src/testing/include/tileConfig.h	(revision 4)
@@ -0,0 +1,144 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: tileConfig.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGE_TILE_CONFIG_H
+#define SAGE_TILE_CONFIG_H
+
+#include "sageBase.h"
+
+// width : horizontal screen resolution
+// height : vertical screen resolution
+// left : left mullion width
+// right : left mullion width
+// bottom : left mullion width
+// top : left mullion width
+
+#define XID_LEN 5
+
+class displayType : public sageRect {
+public:
+   char name[SAGE_NAME_LEN];
+   int PPI; //pixel per inch
+
+   displayType() : PPI(0) {}
+};
+
+// x, y : lower left corner coordinates in pixels
+// width, height : screen resolution
+// left, right, bottom, top : relative coordinates (0.0 - 1.0)
+class tileInfo : public sageRect {
+public:
+   displayType *tileType;
+   int nodeID, tileID;
+   int xIndex, yIndex;
+   int offsetX, offsetY;
+   
+   tileInfo() : tileType(NULL), nodeID(0), tileID(0), offsetX(0), offsetY(0),
+         xIndex(0), yIndex(0) {}
+};
+
+class displayNode {
+public:
+   char ip[SAGE_IP_LEN];        // IP address of the computer the holds pixels to display
+   char forwardIP[SAGE_IP_LEN]; // IP address of the host which forwards external traffic to the display node
+   std::vector<tileInfo*> tiles;  // tile ID attached to this display node
+   int dimX, dimY;
+   int winX, winY;
+   int port, forwardPort;
+   char Xdisp[XID_LEN];
+      
+   displayNode();
+   ~displayNode();
+   int computeDimension();
+};
+
+
+class audioNode {
+public:
+   char ip[SAGE_IP_LEN];            //ip address of the computer the holds pixels to display
+   std::vector<char*> streamIPs;      // optional parameters to receive streams through separate IPs
+
+   // ?????????????
+   //int  audioDeviceNum;
+   sageSampleFmt sampleFmt;
+   long samplingRate;
+   int  channels;
+   int  framePerBuffer;
+   int  deviceId;
+
+   audioNode();
+   ~audioNode();
+};
+
+class virtualDesktop;
+class appInExec;
+
+class displayConnection {
+public:
+   virtualDesktop *displays[2];
+   int edges[2];
+   int offset;
+};   
+
+// x, y : lower left corner coordinates in pixels on global desktop
+// width, height : virtual desktop resolution
+class virtualDesktop : public sageRect {
+public:   
+   std::vector<tileInfo*> tileList;   
+   std::vector<displayNode*> displayCluster;
+   std::vector<audioNode*> audioCluster;
+   std::vector<displayConnection *> connectionList;
+   
+   int dimX, dimY;
+   char masterIP[SAGE_IP_LEN];
+   displayType globalType;
+   int displayID;
+   bool table;
+   char audioDir[TOKEN_LEN];
+   bool audioServer;
+   
+   virtualDesktop();
+   bool parseConfigfile(FILE *fp, bool configBegin = false);
+   int parseAudioConfigfile(FILE *fp, bool configBegin = false);
+   void locateApp(appInExec *app, displayConnection *connection, int idx = 0);
+   int updateDesktop();
+};
+
+#endif
Index: trunk/src/testing/include/sagePixelType.h
===================================================================
--- trunk/src/testing/include/sagePixelType.h	(revision 4)
+++ trunk/src/testing/include/sagePixelType.h	(revision 4)
@@ -0,0 +1,161 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sagePixelType.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGE_PIXEL_TYPE_H_
+#define SAGE_PIXEL_TYPE_H_
+
+#include "sage.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#if defined (__SVR4) && defined (__sun)
+typedef unsigned int GLenum;
+typedef int GLint;
+typedef unsigned int GLuint;
+#define GL_RGB                            0x1907
+#define GL_RGBA                           0x1908
+#define GL_LUMINANCE_ALPHA                0x190A
+#define GL_UNSIGNED_BYTE                  0x1401
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#if defined(WIN32)
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#endif
+#endif
+#endif
+
+class sagePixelType {
+public:
+   GLenum pixelFormat;
+   GLint  internalFormat;
+   GLenum pixelDataType;
+   int bytesPerPixel;
+   
+   sagePixelType() : pixelFormat(GL_RGB), internalFormat(4), pixelDataType(GL_UNSIGNED_BYTE),
+         bytesPerPixel(3) {}
+   sagePixelType(sagePixFmt pix) { initType(pix); }
+   
+   int initType(sagePixFmt pixelType) 
+   {
+      switch (pixelType)   {
+         case PIXFMT_555:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_RGB;
+            pixelDataType = GL_UNSIGNED_SHORT_5_5_5_1;
+            break;
+
+         case PIXFMT_555_INV:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_BGR;
+            pixelDataType = GL_UNSIGNED_SHORT_5_5_5_1;
+            break;
+
+         case PIXFMT_YUV: 
+#if defined(__APPLE__)
+            internalFormat = GL_RGBA8;
+            pixelFormat = GL_YCBCR_422_APPLE;
+            pixelDataType = GL_UNSIGNED_SHORT_8_8_APPLE;
+#else
+            internalFormat =  2;
+            pixelFormat = GL_LUMINANCE_ALPHA;
+            pixelDataType = GL_UNSIGNED_BYTE;
+#endif            
+            break; 
+            
+         case PIXFMT_DXT:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+            
+         case PIXFMT_565:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_RGB;
+            pixelDataType = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+
+         case PIXFMT_565_INV:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_BGR;
+            pixelDataType = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+
+         case PIXFMT_888:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_RGB;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+
+         case PIXFMT_888_INV:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_BGR;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+
+         case PIXFMT_8888:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_RGBA;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+
+         case PIXFMT_8888_INV:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_BGRA;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+
+         default:
+            internalFormat = GL_RGBA;
+            pixelFormat = GL_RGB;
+            pixelDataType = GL_UNSIGNED_BYTE;
+            break;
+      }
+
+      bytesPerPixel = getPixelSize(pixelType);
+      
+      return bytesPerPixel;      
+   }
+};   
+
+#endif
Index: trunk/src/testing/include/sageBlockPartition.h
===================================================================
--- trunk/src/testing/include/sageBlockPartition.h	(revision 4)
+++ trunk/src/testing/include/sageBlockPartition.h	(revision 4)
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlockPartition.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_BLOCK_PARTITION_H
+#define _SAGE_BLOCK_PARTITION_H
+
+#include "sageBase.h"
+#include "sageBlock.h"
+
+class pixelBlockMap {
+public:
+   int blockID;
+   int infoID;
+   int count;
+   pixelBlockMap *next;
+
+   pixelBlockMap() : blockID(0), infoID(0), next(NULL) {}
+};
+
+class blockMontageMap : public pixelBlockMap {
+public:
+   int x, y;
+   
+   blockMontageMap() : x(0), y(0) { next = NULL; }
+};   
+
+class sageBlockPartition : public sageRect {
+private:
+   int blockWidth, blockHeight;
+   int rowNum, colNum;
+   int blockNum, totalBlockNum;
+   sageRect viewPort;
+   sageRect blockLayout;
+   sageRect displayLayout;
+   int vRowNum, vColNum, vOffsetX, vOffsetY;
+   pixelBlockMap **blockTable;
+   int entryNum;
+
+public:
+   sageBlockPartition(int bw, int bh, int iw, int ih);
+   void getBlock(int id, sagePixelBlock &rect);
+   void setViewPort(sageRect &rect);
+   int getVisibleBlockID(int idx);
+   void getVisibleBlock(int idx, sagePixelBlock &block);
+   void adjustBlockCoord(sagePixelBlock &block);
+   int setStreamInfo(int infoID, sageRect &window);
+   int setStreamInfo(int infoID, int begin, int end);
+   bool insertBlockMap(pixelBlockMap *map);
+   pixelBlockMap* getBlockMap(int blockID);
+   void clearBlockTable();
+   void initBlockTable();
+   void genBlockTable(int monIdx);
+   inline int getBlockNum() { return blockNum; }
+   inline int tableEntryNum() { return entryNum; }
+   inline void setDisplayLayout(sageRect &layout) { displayLayout = layout; }
+   inline sageRect& getViewPort() { return viewPort; }
+   inline sageRect& getBlockLayout() { return blockLayout; }
+   void setTileLayout(sageRect tileRect);
+   void getBlockPosition(sagePixelBlock &block);
+};
+
+#endif
Index: trunk/src/testing/include/audioConverter.h
===================================================================
--- trunk/src/testing/include/audioConverter.h	(revision 4)
+++ trunk/src/testing/include/audioConverter.h	(revision 4)
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: audioConverter.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef AUDIO_CONVERTER_H
+#define AUDIO_CONVERTER_H
+
+#include <stdio.h>
+#include "sageBase.h"
+
+class audioConverter {
+public:
+   audioConverter();
+   virtual ~audioConverter();
+
+   virtual int init(FILE* fp);
+
+   /** Returns a tuple (nchannels, sampwidth, framerate, nframes), 
+       equivalent to output of the get*() methods ??? */   
+   virtual int readHeader(int& nchan, long& samrate, int& nframes, sageSampleFmt& fmt)=0;
+   virtual int writeHeader(int nchan, long samrate, int nframes, int bits)=0;   
+
+   /** Returns a tuple (nchannels, sampwidth, framerate, nframes), 
+       equivalent to output of the get*() methods ??? */
+   int getParams(int& nchan, long& samrate, int& nframes, sageSampleFmt& fmt);
+
+   /** Reads and returns at most n frames of audio, as a string of bytes */
+   virtual int readFrames(void* frames) =0;
+   /** Write n frames of audio, as a string of bytes */
+   virtual int writeFrames(void* frames) =0;   
+
+   /** ewind the file pointer to the beginning of the audio stream */ 
+   virtual void begin();
+
+   virtual void close()=0;
+   
+protected:
+   FILE* fileID;
+   
+   long formatLength;
+   short formatTag;
+   short channels;
+   long sampleRate;
+   long avgBytesSec;
+   short blockAlign;
+   short bitsPerSample;   
+   long dataSize;
+   
+   int framesPerBuffer;
+   sageSampleFmt sampleFmt;
+   long blockSize;
+   long blockCount;
+   long totalBlocks;
+   
+   fpos_t dataPos;
+   int writeMode;
+}; 
+
+#endif
Index: trunk/src/testing/include/sageRect.h
===================================================================
--- trunk/src/testing/include/sageRect.h	(revision 4)
+++ trunk/src/testing/include/sageRect.h	(revision 4)
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageRect.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_RECT_H
+#define _SAGE_RECT_H
+
+#include "sageBase.h"
+
+#define LOWER_LEFT  0
+#define LOWER_RIGHT 1
+#define UPPER_RIGHT 2
+#define UPPER_LEFT  3
+
+#define LEFT_EDGE   0
+#define RIGHT_EDGE  1
+#define BOTTOM_EDGE 2
+#define TOP_EDGE    3
+#define ON_RECT     4
+
+enum sageRotation {CCW_ZERO, CCW_90, CCW_180, CCW_270};
+
+sageRotation operator+(sageRotation r1, sageRotation r2);
+sageRotation operator-(sageRotation r1, sageRotation r2);
+
+class sageRect {
+public:   
+   int x, y, width, height;
+   float left, right, bottom, top;
+protected:
+   sageRotation orientation;
+
+public:
+   sageRect() : x(0), y(0), width(0), height(0), 
+      left(0.0), right(1.0), bottom(0.0), top(1.0), orientation(CCW_ZERO) {}
+      
+   sageRect(float l, float r, float b, float t) 
+      : x(0), y(0), width(0), height(0), 
+      left(l), right(r), bottom(b), top(t), orientation(CCW_ZERO) {}
+
+   sageRect(int rx, int ry, int rw, int rh) 
+      : x(rx), y(ry), width(rw), height(rh), 
+      left(0.0), right(1.0), bottom(0.0), top(1.0), orientation(CCW_ZERO) {}
+      
+   ~sageRect() {}
+
+   //void operator= (sageRect &rect);
+   void operator+= (sageRect &rect);
+   sageRect operator+ (sageRect &rect);
+   sageRect operator/ (float div);
+   sageRect operator/ (sageRect &rect);
+   void operator/= (sageRect &rect);
+   sageRect operator* (sageRect &rect);
+   void operator*= (sageRect &rect);
+   
+   void updateBoundary();
+   void updateBoundary(sageRect &rect);
+   void moveOrigin(sageRect &rect);
+   void scale(float r);
+   void scale(float sx, float sy);
+   void translate(int x, int y);
+   void translate(sageRect &rect);
+   void rotate(sageRotation rot);
+   void setOrientation(sageRotation ori) { orientation = ori; }
+   inline sageRotation getOrientation() { return orientation; }
+   void resetOrientation()  { rotate(CCW_ZERO - orientation); }
+   void shrink(float x, float y);
+   void locate();
+   void normalize(sageRect &rect);
+   int normalize(float x, float y);
+   
+   bool isOverLap(float l, float r, float b, float t, sageRect &com);
+   bool isOverLapX(float l, float r, sageRect &com);
+   bool isOverLapY(float b, float t, sageRect &com);
+
+   bool isOverLap(sageRect &rect);   
+   int  isOverLap(sageRect &rect, float threshold);
+   bool isOverLap(sageRect &rect, sageRect &com);
+   bool isOverLapX(int x2, int w2, sageRect &com);
+   bool isOverLapY(int y2, int h2, sageRect &com);
+
+   bool isInRect(float x, float y);
+   bool isInRect(int x, int y);
+   bool isInRect(sageRect &rect);
+   void genTexCoord(int corner, float &x, float &y);
+   void sprintRect(char *str);
+   void sscanRect(char *str);
+   
+   inline int halfWidth() { return width/2; }
+   inline int halfHeight() { return height/2; }
+   inline int centerX() { return x + halfWidth(); }
+   inline int centerY() { return y + halfHeight(); }
+   //int mask(sageRect &rect);  // crop by the rect which has normalized coordinates
+   bool crop(sageRect &rect);
+};      
+
+#endif
Index: trunk/src/testing/include/sageDraw.h
===================================================================
--- trunk/src/testing/include/sageDraw.h	(revision 4)
+++ trunk/src/testing/include/sageDraw.h	(revision 4)
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDraw.h
+ * Author : Byungil Jeong
+ *
+ *   Description: This is the header file for the simple drawing class of SAGE. 
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+*********************************************************************************/
+
+#ifndef SAGE_DRAW_H
+#define SAGE_DRAW_H
+
+#if defined(__APPLE__)
+#include <ApplicationServices/ApplicationServices.h>
+#include <AGL/agl.h>
+#include <OpenGL/OpenGL.h>
+
+#else
+
+#ifdef sun
+#include <SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+
+#endif
+
+#include <map>
+#include "sage.h"
+#include "sageDrawObject.h"
+
+
+#if defined(__APPLE__)
+#include <OpenGL/gl.h>   // Header File For The OpenGL Library
+#include <OpenGL/glu.h>   // Header File For The GLu Library
+#else
+#include <GL/gl.h>   // Header File For The OpenGL Library
+#include <GL/glu.h>   // Header File For The GLu Library
+#endif
+
+#define SAGE_POST_DRAW  0
+#define SAGE_INTER_DRAW 1
+#define SAGE_PRE_DRAW   2
+
+class sageDraw {
+private:
+   // hashes of drawObjects keyed by their ID for easy access
+   std::map<int, sageDrawObject *> preDrawList;
+   std::map<int, sageDrawObject *> interDrawList;
+   std::map<int, sageDrawObject *> postDrawList;
+   bool &dirtyBit;
+   int displayID;
+
+public:
+   sageDraw(bool &dirty, int dispID);
+   sageDrawObject * createDrawObject(char *name);
+   int preDraw(sageRect rect);  // draw objects to background
+   int interDraw(sageRect rect); 
+   int postDraw(sageRect rect); // draw objects to overlay
+   int addObjectInstance(char *data);
+   int updateObjectPosition(char *data);
+   int removeObject(int id);
+   int showObject(char *data);
+   int forwardObjectMessage(char *data);
+   ~sageDraw();
+};
+
+#endif
Index: trunk/src/testing/include/sageAudioSync.h
===================================================================
--- trunk/src/testing/include/sageAudioSync.h	(revision 4)
+++ trunk/src/testing/include/sageAudioSync.h	(revision 4)
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioSync.h
+ * Author : Hyejung Hur, 
+ * Description : This file contains the class which provides the syncing
+ *               mechanism. 
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_AUDIO_SYNC_H
+#define _SAGE_AUDIO_SYNC_H
+
+#include <vector>
+
+#include "sageBase.h" 
+#include "streamProtocol.h"
+
+class sageSyncInfo {
+public:
+   int m_sourceId;
+   int m_bufferId;
+   int m_keyframeNum;
+   sageAudioSyncType m_syncType;   
+   bool m_updateFlag;
+   int   m_clientSockFd;   
+   int m_passNum;
+   bool m_lockFlag;
+   sageSyncInfo() : m_sourceId(-1), m_bufferId(-1), m_keyframeNum(30), m_syncType(SAGE_SYNC_NONE),
+                  m_updateFlag(false), m_clientSockFd(-1), m_passNum(0), m_lockFlag(false) {}; 
+   ~sageSyncInfo() {};
+};
+
+class sageAudioSync {
+public:
+   sageAudioSync(bool audioRecv=false);
+   ~sageAudioSync();
+
+public:
+   int init(int port);
+   int connect(char* ip); 
+   
+   /** register to buffer information for contol
+   */
+   void registerBuffer(sageAudioSyncType type, int sourceId, int bufferId, int keyframeNum);
+
+   /** remove buffer from the contorl list.
+   */
+   int removeBuffer(int bufferId);
+
+
+   /** check current frame number is keyframe 
+   */
+   bool checkKeyFrame(int bufferId, int frameNum);
+   
+   /** check signal 
+   */
+   bool checkSignal(int bufferId);
+   
+   int sendSignal(int bufferId);
+   
+   int checkConnections();
+   
+protected:
+   int initListener(int port);
+   int initSender(char* ip, int port);
+   
+   bool recvSignal(int socketFd, char* msg, int bufferId);
+   int closeAll();
+
+   int sendSignal(sageSyncInfo* info);   
+   
+   void doKeyFrameAction(sageSyncInfo* info);
+
+protected:
+   /** buffer list
+   */
+   std::vector<sageSyncInfo*> m_syncInfoList;
+
+   int         m_serverSockFd;
+   int         m_clientSockFd;
+   std::vector<int> m_clientSockList;
+   
+   sockaddr_in m_localAddr;
+   sockaddr_in   m_serverAddr;
+      
+   int m_recvPort;
+   int m_sendPort;
+         
+   // for identify receivers. : if it's aStreamRcv, true
+   bool      m_audioReceiver;
+   
+   bool      m_connectedDone;
+   // timer.... 
+   
+};
+
+#endif
Index: trunk/src/testing/include/sageUdpModule.h
===================================================================
--- trunk/src/testing/include/sageUdpModule.h	(revision 4)
+++ trunk/src/testing/include/sageUdpModule.h	(revision 4)
@@ -0,0 +1,146 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageTcpModule.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ * Description:   This is the header file of the UDP code used for trasmitting graphics. 
+ *                The template for the interface is given by the streamProtocol class.
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _SAGE_UDP_MODULE_H
+#define _SAGE_UDP_MODULE_H
+
+#include "streamProtocol.h"
+
+#define FLOW_WINDOW_NUM 5
+
+class sageBlockBuf;
+class sageCircBuf;
+class sageBlockGroup;
+class sageBlockFrame;
+
+class flowHistory {
+public:
+   double startTime;
+   double windowInterval;
+   
+   flowHistory() : startTime(0.0), windowInterval(0.0) {}
+};
+
+class streamFlowData {
+private:
+   flowHistory streamWindow[FLOW_WINDOW_NUM];
+   double nextWindowTime;
+   int totalSentSize;
+   int winIdx;
+   bool firstRound;
+   double startTime;
+   
+public:
+   double frameRate;
+   int nextFrameSize;
+   int frameSize;
+   int configID;
+   
+   int blockSize;
+   bool active;
+   bool closed;
+   
+   sageCircBuf *blockBuf;
+   sageBlockPool *returnPlace;
+   
+   streamFlowData(sageCircBuf *buf);
+   ~streamFlowData();
+
+   inline double elapsedTime(double time) { return time - startTime; }
+   inline double pastTime(double time)    { return time - nextWindowTime; }
+   void insertWindow(double sTime, int dataSize);
+};
+   
+class sageUdpModule : public streamProtocol{
+private:
+   int serverSockFd;
+         
+   std::vector<int> udpRcvList;
+   std::vector<int> udpSendList;
+   std::vector<streamFlowData*> flowList;
+
+   bool notStarted;
+   bool waitData;
+   bool closeFlag;
+
+   pthread_t thId;
+   static void* sendingThread(void *args);
+   int sendLoop();
+   bool setSockOpts(int fd, bool noDelay = false);
+   pthread_mutex_t connectionLock;
+   pthread_cond_t  streamStart;
+   pthread_cond_t  newData;
+   
+   int send(int id, sagePixelBlock *spb);
+   int recv(int id, sagePixelBlock *spb, int pidx);
+   int skipBlock(int id, int pidx);
+
+public:
+   sageUdpModule();
+   int init(sageStreamMode m, int p, sageNwConfig &c);
+   int checkConnections(char *msg = NULL, sageApiOption op = 0);
+   int connect(char* ip, char *msg = NULL);
+   int send(int id, sageBlock *sb, sageApiOption op);
+
+
+   /**
+    * sungwon experimental, swexp
+    */
+   int sendpixelonly(int id, sageBlockFrame *sb);
+
+   int recv(int id, sageBlock *sb, sageApiOption op);
+   int sendControl(int id, int frameID, int configID);
+   int sendGrp(int id, sagePixelBlock *sb, int configID);
+   int recvGrp(int id, sageBlockGroup *sbg);
+   int getRcvSockFd(int id) { return udpSendList[id]; }
+   int flush(int id, int configID);
+   void setupBlockPool(sageBlockPool *pool, int id = -1);
+   void setFrameSize(int id, int size);
+   void resetFrameSize(int id) { setFrameSize(id, 0); }
+   void setFrameRate(double rate, int id = -1);
+   
+   int close(int id, int mode = -1);
+   int close();
+   virtual ~sageUdpModule();
+}; 
+
+#endif
Index: trunk/src/testing/include/sageBlockQueue.h
===================================================================
--- trunk/src/testing/include/sageBlockQueue.h	(revision 4)
+++ trunk/src/testing/include/sageBlockQueue.h	(revision 4)
@@ -0,0 +1,121 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageBlockQueue.h
+ * Author : Byungil Jeong
+ *
+ *   Description: Queue for event driven control in a SAGE component
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+#ifndef _SAGE_BLOCK_QUEUE_H
+#define _SAGE_BLOCK_QUEUE_H
+
+#include "sageBase.h"
+
+class sageBlock;
+
+class sageBlockContainer {
+public:
+   sageBlock *block;
+   sageBlockContainer *next;
+   int rcnt;
+   
+   sageBlockContainer() : block(NULL), next(NULL), rcnt(0) {}
+};
+
+class sageBlockQueue {
+protected:
+   sageBlockContainer *head, *tail;
+   sageBlockContainer invalid;
+   sageBlockContainer *pointerList[MAX_ENDPOINT_NUM];
+
+   pthread_mutex_t *queueLock;
+   pthread_cond_t *notFull;
+   
+   pthread_mutex_t *listLock;
+   pthread_cond_t  *notEmpty;
+   
+   int maxLen, curLen, pointerNum, maxPointerID;
+   bool full;
+   
+   int lastFrame[MAX_ENDPOINT_NUM];
+   int skipFrame[MAX_ENDPOINT_NUM];
+   bool active;
+   int montageID;
+   bool pixelPassed;
+   int lastPixelFrame[MAX_ENDPOINT_NUM];
+   
+public:
+   sageBlockQueue(int len = 2);
+   ~sageBlockQueue();
+   
+   int getLastFrame(int id = 0) { return lastFrame[id]; }
+   bool isActive() { return active; }
+   void setMonID(int id) { montageID = id; }
+   int getMonID() { return montageID; }
+      
+   void setMaxLen(int len) { maxLen = len; }
+   int addReader(int id = 0);
+   int removeReader(int id, pthread_mutex_t &lock);
+   
+   sageBlock* deque(int frame, bool activeMode, int id = 0);
+   void enque(sageBlock* block); 
+   //sageBlock* searchBlock(int x, int y);
+   void skipBlocks(int frame, int id = 0);
+   
+   void initCondVar(pthread_mutex_t *lock, pthread_cond_t *cond);
+   bool isEmpty()  { return (head == NULL); }
+   void clear();   
+};
+
+class blockQueueList {
+protected:
+   std::vector<sageBlockQueue*> queueList;
+   pthread_mutex_t *listLock;
+   pthread_cond_t *notEmpty;
+   
+public:
+   blockQueueList();
+   int addQueue(sageBlockQueue *q);
+   sageBlockQueue* operator[](int id);
+   blockQueueList& operator=(blockQueueList &list);
+   int waitForData();
+   void stopWaiting();
+   int size() {  return  queueList.size(); }
+   ~blockQueueList();
+};
+
+#endif
Index: trunk/src/testing/include/fsServer.h
===================================================================
--- trunk/src/testing/include/fsServer.h	(revision 4)
+++ trunk/src/testing/include/fsServer.h	(revision 4)
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsServer.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+
+#ifndef _FS_SERVER_H
+#define _FS_SERVER_H
+
+#include "sage.h"
+#include "QUANTAnet_tcp_c.hxx"
+
+#define SOCK_BUF_SIZE (1024*1024*32)
+#define READ_BUF_SIZE 4096
+#define SYSTEM_CLIENT_BASE 1000
+
+class fsManager;
+
+/**
+ * read messages from UI and APPs
+ * pass them to appropriate component
+ */
+class fsServer {
+private:
+   QUANTAnet_tcpServer_c *sysServer;
+   QUANTAnet_tcpServer_c *uiServer;
+   
+   fsManager *fsm;
+   std::vector<QUANTAnet_tcpClient_c *> uiClientList;
+   std::vector<QUANTAnet_tcpClient_c *> sysClientList;
+   int numSysClients, numUiClients;
+
+public:
+   fsServer();
+   ~fsServer();
+
+   //unsigned int maxNumOfApp;
+
+   int init(fsManager *fsm);
+   static void* trackingThread(void *args);
+   int checkTrackingMsg();
+   int checkClients();
+   int sendMessage(int cId, int code, int data);
+   int sendMessage(int cId, int code, char* data);
+   int sendMessage(int cId, int code);   
+   int sendMessage(sageMessage &msg);
+};
+
+#endif
Index: trunk/src/testing/include/sageAudioCircBuf.h
===================================================================
--- trunk/src/testing/include/sageAudioCircBuf.h	(revision 4)
+++ trunk/src/testing/include/sageAudioCircBuf.h	(revision 4)
@@ -0,0 +1,218 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageAudioCircBuf.h
+ * Author : Byungil Jeong, Hyejung Hur
+ *
+ *   Description: This is the header file for the circular buffer of sage pixel blocks
+ *
+ *   Notes   :   This class is supposed to provide the common buffers for holding
+ *         the pixel blocks. It also takes care of the reading and writing of pixel blocks
+ *         in a circular fashion. The member functions will be able to provide a complete
+ *         interface to handling these buffers.
+ *
+ *         The algo is that the buffers are writen to and read from in the same direction
+ *         [0 to n and then back to 0]
+ *
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+
+#ifndef _SAGE_AUDIO_CIRCBUF_H
+#define _SAGE_AUDIO_CIRCBUF_H
+
+#include "sageBase.h"
+
+class sageAudioSync;
+class sageSyncClient;
+
+class audioBlock {
+public:
+   long frameIndex;
+   long gframeIndex;
+   int reformatted;
+   void* buff;
+   double timestamp;
+
+   audioBlock(): frameIndex(-1), gframeIndex(-1), reformatted(0), buff(NULL), timestamp(0) {};
+   ~audioBlock() {};
+};
+
+/** todo */
+// need to extend for several readers and writers....
+
+/**
+ * This class is supposed to provide the common buffers for holding the pixel blocks.
+ * It also takes care of the reading and writing of pixel blocks in a circular fashion.
+ */
+class sageAudioCircBuf {
+private:
+   int audioId;
+   int instID;
+
+   int readIndex;
+   int writeIndex;
+
+   pthread_mutex_t *queueLock;
+   pthread_cond_t *notFull;
+
+   /** numbers of audio block
+    */
+   int blocksNum;
+
+   /** audio format : float, short, char, unsigned char
+    */
+   sageSampleFmt sampleFmt;
+
+   /** buffer size in an audio block
+    */
+   int sampleBuffSize;
+
+   /** array of audio block
+    */
+   audioBlock* blockArray;
+
+   /** bytes in an audio block
+    */
+   int bytesBlock;
+
+   bool full;
+   bool empty;
+
+   /** synchronizer for audio and video streaming
+   */
+   sageAudioSync* synchronizer;
+   sageSyncClient *syncClientObj; /**< sageSyncClient object */
+
+   /** make buffer lock- can not write
+   */
+   bool locked;
+
+   /** frame index of last block in writing
+   */
+   int lastFrameIndex;
+   int lastgFrameIndex;
+   int syncKeyFrame; /**< synchronization key frame */
+
+   int refRead;
+   int refMutex;
+   std::vector<int> readers;
+
+protected:
+   void clearBlocks();
+
+public:
+	/**
+	 * keyframe is set to 100 by default<BR>
+	 * every 100 frame, sendslaveupdate will be called
+	 */
+   sageAudioCircBuf(sageSyncClient *sync= NULL, int nID=0, int keyframe = 100);
+   ~sageAudioCircBuf();
+
+   /** create aduio blocks and create buffers in each audio block.
+   * @param id integer
+   * @param blockNum integer
+   * @param fmt sageSampleFmt
+   * @param size integer
+   * @return integer
+   */
+   int init(int id, int blockNum, sageSampleFmt fmt, int size);
+
+   /** get audio block pointer for writing
+   * @param void
+   * @return audioBlock *
+   */
+   audioBlock* getNextWriteBlock();
+
+
+   /** get audio block pointer for read
+   * not good idea to give pointer for reading
+   */
+   audioBlock* readBlock(int Id = 0);
+   audioBlock* readBlock(int Id, int frameNum);
+
+   /** update read index
+    * sendSlaveUpdate() is called here.
+   */
+   int updateReadIndex();
+
+   /** update write index
+   */
+   int updateWriteIndex();
+
+   int getReadIndex();
+   int getWriteIndex();
+
+   /** get numbers of audio blocks
+   */
+   int getSize();
+   int getAudioId();
+   int getBytesBlock();
+
+   int merge(audioBlock* block);
+   int convertToFloat(sageSampleFmt fmt, void* rawdata, audioBlock* block);
+
+
+   void clearBlock(int frameNum);
+   void reset();
+
+   void connectSync(sageAudioSync* synch);
+
+   /**
+    * sends update to syncMaster with the event SAGE_UPDATE_AUDIO
+    */
+   void connectSyncClient(sageSyncClient* synch);
+
+   void setInstID(int ID);
+
+   /** use for synchronization
+   */
+   void setLock();
+   void setFree();
+
+   void setKeyframe(int keyno);
+
+   /** get frame number of recently recored block
+   */
+   int getLastFrameIdx();
+
+   // add
+   int addReader();
+   void deleteReader(int Id);
+};
+
+inline void sageAudioCircBuf::setInstID(int ID) { instID = ID; };
+
+#endif
Index: trunk/src/testing/include/sageSharedData.h
===================================================================
--- trunk/src/testing/include/sageSharedData.h	(revision 4)
+++ trunk/src/testing/include/sageSharedData.h	(revision 4)
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageSharedData.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF 88ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGE_SHARED_DATA_H_
+#define SAGE_SHARED_DATA_H_
+
+#include "sageBase.h"
+//#include <sys/time.h>
+
+class sageDisplay;
+class sageSyncServer;
+class sageSyncClient;
+class sageSyncBBServer;
+class sageMemory;
+class sageEventQueue;
+class displayContext;
+class streamProtocol;
+
+/**
+ * class rcvSharedData
+ */
+class rcvSharedData {
+public:
+   int nodeID; /**< a SDM ID on which sageDisplayManager is running */
+   int bufSize;
+   sageEventQueue *eventQueue; /**< event queue */
+   sageSyncClient *syncClientObj; /**< created in the sageDisplayManager::init() */
+      
+   int nodeNum;
+      
+   rcvSharedData();
+   ~rcvSharedData();
+};
+
+/**
+ * class dispSharedData
+ */
+class dispSharedData : public rcvSharedData {
+public:
+   displayContext *context;
+   sageDisplay   *displayObj; /**< created in the sageDisplayManager::init() */
+   
+   dispSharedData() : displayObj(NULL), context(NULL) {}
+   ~dispSharedData();
+};
+
+/**
+ * class bridgeSharedData
+ */
+class bridgeSharedData : public rcvSharedData {
+public:
+   streamProtocol *sendObj;
+   bool frameDrop;
+   nwProtocol protocol;
+   bridgeSharedData() : sendObj(NULL), frameDrop(true), protocol(SAGE_UDP) {}
+   ~bridgeSharedData();
+};
+
+#endif
Index: trunk/src/testing/include/sageDisplayManager.h
===================================================================
--- trunk/src/testing/include/sageDisplayManager.h	(revision 4)
+++ trunk/src/testing/include/sageDisplayManager.h	(revision 4)
@@ -0,0 +1,221 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDisplayManager.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef sageDisplayManager_H_
+#define sageDisplayManager_H_
+
+#include "fsClient.h"
+#include "streamProtocol.h"
+
+#define DISPLAY_REFRESH_INTERVAL 8333   // 1000000us/120frame = 8333
+//#define DISPLAY_REFRESH_INTERVAL 16666   // 1000000us/60 = 16666
+#define DISPLAY_MAX_FRAME_RATE   MAX_FRAME_RATE
+
+class sageDisplayManager;
+class sageEvent;
+class sageReceiver;
+class sageTcpModule;
+class sageUdpModule;
+class dispSharedData;
+class pixelDownloader;
+
+
+class sageSyncBBServer;
+class sageSyncServer;
+
+typedef struct {
+   sageDisplayManager *This;
+   streamProtocol     *nwObj;
+} nwCheckThreadParam;
+
+/**
+ * class sageDisplayManager
+ */
+class sageDisplayManager : public fsClient {
+private:
+	/**
+	 * This is the pointer that points eventQueue and syncClientObject which are shared to downloaderList<BR>
+	 * pixelDownloader also has pointer to sagePixelReceiver and it's created when pixelDownloader is created.<BR>
+	 * so, sageDisplayManger, pixelDownloader, and sagePixelReceiver all can access same dispSharedData
+	 */
+   dispSharedData *shared;
+   sageNwConfig nwCfg;
+   sageTcpModule *tcpObj;
+   sageUdpModule *udpObj;
+
+
+   bool syncMaster; /**< if syncMaster then syncBBServerObj is created */
+   sageSyncBBServer *syncBBServerObj; /**< instantiated if syncMaster is true */
+   sageSyncServer *syncServerObj;
+
+   int syncPort; /**< syncServer's port */
+   int syncBarrierPort; /**< syncMaster's barrier port (2nd phase) */
+   int syncRefreshRate; /**< This is important parameter. It determines how frequent BBS should broadcast in Hz */
+   int syncMasterPollingInterval; /**< select return timer in usec */
+   int syncLevel;
+
+   //sageReceiver *receiverList[MAX_INST_NUM];
+   std::vector<pixelDownloader *> downloaderList; /**< pixelDownloader object for each application */
+   std::vector<char *> reconfigStr;
+
+   int streamPort;
+   int totalRcvNum; /**< total number of node in the system */
+   bool rcvEnd;
+   int displayID; /**< looks like ]always zero */
+
+   /**
+	* called by the mainLoop().<BR>
+	* It parses sageEvent then calls appropriate functions.
+	*/
+   int parseEvent(sageEvent *event);
+
+   /**
+    * called by parseEvent().<BR>
+    * It parses sageMessage then calls appropriate functions.
+    */
+   int parseMessage(sageMessage *msg);
+   int perfReport(); /**< calls pixelDownloader::evalPerformance() for each element in the downloaderList */
+   int startPerformanceReport(sageMessage *msg);
+   int stopPerformanceReport(sageMessage *msg);
+   int changeBGColor(sageMessage *msg);
+   int changeDepth(sageMessage *msg);
+
+   /**
+	* if appId is -1 then all applications are closed
+	*
+	* @param appId integer
+	* @return 0 on success, -1 otherwise
+	*/
+   int shutdownApp(int appId);
+
+   /**
+	* creates sageTcpModule, sageUdpModule, and generates nwCheckThread
+	*/
+   int initNetworks();
+
+   /**
+	* creates pixelDownloader object if it wasn't created for this instID before.<BR>
+	* If pixelDownloader object already exist then just pixelDownloader::addStream() is called.<BR>
+	* pixelDownloader (per application) reads pixel data from buffer and downloads into texture memory.<BR>
+	* if stream type is SAGE_BLOCK_NO_SYNC then only pixelDownloader::init() is called.<br>
+	* if stream type is SAGE_BLOCK_XXX_SYNC then a syncGroup object is created and syncGroup::init() is called followed by pixelDownloader::init()<br>
+	* If syncMaster is true then the newly created syncGroup object is then added by syncServerObj->addSyncGroup() <br>
+	* finally, pixelDownloader::addStream() is called and this pixelDownloader instance is added into the array downloaderList
+	*
+	* @param msg char *
+	* @param nwObj streamProtocol *
+	* @return 0
+	*/
+   int initStreams(char *msg, streamProtocol *nwObj);
+
+   /**
+    * this function is called when EVENT_SYNC_MESSAGE arrives in the parseEvent() in this class. This event is generated in the syncCheckThread() which is started in the init()<BR>
+    * It finds syncGroup id and syncframe from the msg
+    * then calls pixelDownloader::processSync() of an element in the downloaderList array<BR>
+    * if status of this group is PDL_WAIT_SYNC then, also calls pixelDownloader.fetchSageBlocks()
+    */
+   //int processSync(char *msg);
+   int processSync(sageEvent *e);
+
+
+
+   /**
+    * it's called when a message RCV_UPDATE_DISPLAY is received from fsManager
+    */
+   int updateDisplay(char *msg);
+   int clearDisplay(int instID);
+
+   char CLEAR_STR[TOKEN_LEN];
+
+   /**
+	* keeps checking network connection and generates EVENT_NEW_CONNECTION event if new connection has arrived.
+	*/
+   static void* nwCheckThread(void *args);
+
+   /**
+	* keeps checking message from fsManager(?) by calling fsClient::rcvMessageBlk()<BR>
+	* generates EVENT_NEW_MESSAGE
+	*/
+   static void* msgCheckThread(void *args);
+
+   /**
+	* This thread creates sageEvent type syncEvent (EVENT_SYNC_MESSAGE) if sageSyncClient::waitForSync() is returned.<BR>
+	* In other words, if it gets sync message from the syncMaster then it generates EVENT_SYNC_MESSAGE
+	*/
+   static void* syncCheckThread(void *args);
+
+   /**
+	* the constructor starts this thread.<br>
+	* It keeps calling perfReport()
+	*/
+   static void* perfReportThread(void *args);
+
+   /**
+	* started by pthread_create in the init()<BR>
+	* It keeps sending EVENT_REFRESH_SCREEN event. it causes calling sageDisplay::updateScreen()
+	* refer DISPLAY_REFRESH_INTERVAL
+	*/
+   static void* refreshThread(void *args);
+
+	pixelDownloader* findApp(int id, int& index);
+
+public:
+   /**
+	* if syncMaster is true, sageSyncServer object is created here, and sageSyncServer::init() is called.<BR>
+	* if globalSync(which is argv[6]) is true, then both shared->nodeID and displayID must be zero to syncMaster be true.<BR>
+	* Also starts msgCheckThread() and perfReportThread().
+	*/
+   sageDisplayManager(int argc, char **argv);
+   ~sageDisplayManager();
+
+   /**
+	* sageSyncClient object is created here.<BR>
+	* It starts syncCheckThread() and refreshThread()<BR>
+	* Also, sageDisplay is instantiated here. It draws pixel data onto screen, and all OpenGL related code resides in the sageDisplay
+	*/
+   int init(char *msg);
+
+   /**
+	* It keeps getting an event from the eventQueue, and caliing parseEvent() with new event until rcvEnd is true
+	*/
+   void mainLoop();
+};
+
+#endif
Index: trunk/src/testing/include/pixelDownloader.h
===================================================================
--- trunk/src/testing/include/pixelDownloader.h	(revision 4)
+++ trunk/src/testing/include/pixelDownloader.h	(revision 4)
@@ -0,0 +1,232 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: pixelDownloader.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef PIXEL_DOWNLOADER_H_
+#define PIXEL_DOWNLOADER_H_
+
+#include "sage.h"
+#include "sageSync.h"
+
+
+#include "sageEvent.h"
+
+class pixelDownloader;
+class dispSharedData;
+class sageMontage;
+class sageBlockBuf;
+class sagePixelBlock;
+class displayContext;
+class sageBlockPartition;
+class sagePixelReceiver;
+class streamProtocol;
+
+/**
+ * class montagePair
+ */
+class montagePair {
+private:
+   //int tileID;
+   sageMontage *montage[2];
+   int frontMon;
+   bool renewMontage;
+   bool active;
+   //bool updated;
+   bool clearFlag;
+
+public:
+   montagePair() : renewMontage(false), frontMon(0), active(false),
+         clearFlag(false) {}
+   int init(displayContext *context, sagePixFmt pfmt, int index, float depth);
+   inline sageMontage* getFrontMon() { return montage[frontMon]; }
+   inline sageMontage* getBackMon() { return montage[1-frontMon]; }
+   int setDepth(float depth);
+   int setLocalTileIdx(int idx);
+
+   /**
+    * when a window is moved or resized, the config of back montage is updated immediately,<BR>
+    * the front montage is updated when it is swapped
+    */
+   void swapMontage();
+
+   int deleteMontage();
+   //int getLocalTileIdx() { return montage[0]->tileIdx; }
+   inline bool isActive()  { return active; }
+   inline void activate()  { active = true, clearFlag = false; }
+   inline void deactivate(){ active = false, clearFlag = false; }
+   inline void clear()     { clearFlag = true; }
+   inline bool getClearFlag() { return clearFlag; }
+
+   //void update()    { updated = true; }
+   inline void renew()     { renewMontage = true; }
+   inline bool isRenewed() { return renewMontage; }
+
+   //bool isUpdated() { return updated; }
+   //void resetUpdateFlag() { updated = false; }
+   ~montagePair();
+};
+
+#define PDL_WAIT_CONFIG 1
+#define PDL_WAIT_DATA   2
+#define PDL_WAIT_SYNC   3
+
+/**
+ * \brief class pixelDownloader (per application). It reads pixel data from buffer and downloads into texture memory.
+ */
+class pixelDownloader {
+public:
+   int instID; /**< application ID */
+protected:
+   int streamNum;
+   int tileNum; /**< how many tiles a single node has ? */
+   int updatedFrame, curFrame, syncFrame;
+   int configID, dispConfigID;
+   int groupSize, blockSize;
+   dispSharedData *shared; /**< dispSharedData *. This is assigned at the sageDisplayManager */
+   bool frameCheck;
+   bool syncOn; /**< whether we ensure sync b/w tiles or not */
+   int syncLevel;
+   bool displayActive;
+   int  status; /**< PDL_WAIT_CONFIG 1, PDL_WAIT_DATA 2, and PDL_WAIT_SYNC 3*/
+	bool m_initialized;
+
+   sagePixelReceiver *recv; /**< sagePixelReceiver */
+   sageBlockBuf *blockBuf; /**< sageBlockBuf */
+   montagePair *montageList;
+
+   sageCounter frameCounter;
+   int reportRate;
+   sageTimer perfTimer;
+   unsigned long bandWidth;
+   unsigned long packetLoss;
+   unsigned frameBlockNum; /**< PDL is supposed to received this many blocks for given group */
+   int actualFrameBlockNum;
+   unsigned long frameSize;
+
+   sageBlockPartition *partition;
+   sageRect windowLayout;
+
+   /**
+    * how many sageReceiver involves ?
+    */
+   int activeRcvs;
+   int updateType;
+   bool passiveUpdate;
+
+   /**
+    * stream coming from bridge and it's actually parallel app
+    */
+   bool fromBridgeParallel;
+
+   std::deque<char *> configQueue;
+
+   //int sendPerformanceInfo();
+   int downloadPixelBlock(sagePixelBlock *block, montagePair &monPair);
+   int clearTile(int tileIdx);
+
+   /**
+    * for each tileNum, clearTile() is called
+	*/
+   int clearScreen();
+   int setupSyncInfo(sagePixelBlock *block);
+
+public:
+	/**
+	 * starts with updateType = SAGE_UPDATE_FOLLOW, status = PDL_WAIT_DATA
+	 */
+   pixelDownloader();
+
+   /**
+    * creates montagePair, sageBlockPartition, sageBlockBuf, sagePixelReceiver objects<BR>
+    * this is invoked by initStreams in the sageDisplayManager (when EVENT_NEW_CONNECTION)
+    *
+    * msg contains groupSize and blockSize. These are passed to sageBlockBuf constructor.
+	*/
+   int init(char *msg, dispSharedData *sh, streamProtocol *nwObj, bool sync, int syncLevel);
+
+   /**
+    * Called when EVENT_READ_BLOCK, EVENT_SYNC_MESSAGE, and RCV_UPDATE_DISPLAY<BR>
+    * This function is the one which calls sageSyncClient::sendSlaveUpdate()<BR>
+    * When syncOn is true and updateFrame > curFrame<BR>
+    * <BR>
+    * It first fetches block data from the block buffer by calling sageBlockBuf.front()<BR>
+    * then calculates packet loss.. then..
+    * ..
+    * ..
+    *
+    */
+   int fetchSageBlocks();
+
+   /**
+    * It looks like this function is responsible for syncing b/w tiles<BR>
+    * The first argument frame is the frame that we want to sync to<BR>
+    * <BR>
+    * if this syncSlave's updated frame is equal to the sync frame(argument),
+    * then it swaps texture (swapMontage()) => HARD_SYNC
+    */
+   void processSync(int frame, int cmd = 0);
+
+   int enqueConfig(char *data);
+   int setDepth(float depth);
+
+   /**
+    * just calls sagePixelReceiver::addStream()<BR>
+    * called by sageDisplayManager::initStream()
+	*/
+   int addStream(int senderID);
+
+   /**
+    * When a window is moved or resized, the config of back montage is
+    * updated immediately, the front montage is updated when it is swapped.
+    */
+   int swapMontages();
+   bool reconfigDisplay(int id);
+   int evalPerformance(char **frameStr, char **bandStr); /**< evaluate performance */
+   inline void setReportRate(int rate) { reportRate = rate; }
+   inline void resetTimer() { perfTimer.reset(); }
+   inline void resetBandWidth() { bandWidth = 0; }
+   inline void resetFrame() { frameCounter.reset(); }
+   inline int getInstID() { return instID; }
+   inline int getStatus() { return status; }
+	bool isInitialized(void) { return m_initialized; }
+
+   ~pixelDownloader();
+};
+
+#endif
Index: trunk/src/testing/include/sageAudio.h
===================================================================
--- trunk/src/testing/include/sageAudio.h	(revision 4)
+++ trunk/src/testing/include/sageAudio.h	(revision 4)
@@ -0,0 +1,174 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudio.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _SAGE_AUDIO_H
+#define _SAGE_AUDIO_H
+
+// portaudio header file
+#include <portaudio.h>
+
+#ifdef linux1
+#include <libiec61883/iec61883.h>
+#include <sys/select.h>
+#endif
+
+#include "sageAudioModule.h"
+#include "sageAudioCircBuf.h"
+#include "sageBase.h"
+
+class sageAudio {
+public:
+   /** audio mode
+   */
+   enum {AUDIO_PLAY, AUDIO_PAUSE, AUDIO_STOP};
+public:
+   sageAudio();
+   ~sageAudio();
+
+   /** set parameters for setting audio up and assign pointer of circular buffer  
+   */
+   int init( int id, sageAudioConfig &conf, sageAudioMode mode, sageAudioCircBuf *buf );
+   int reset( int id, sageAudioCircBuf *buf );
+
+   /** open audio stream in play mode or capture mode
+   */
+   virtual int   openStream();
+   
+   /** close audio stream
+   */
+   virtual int   closeStream();
+   
+   int play();
+   int pause();
+   int stop();
+
+   /** test audio input/output device
+   */
+   void testDevices();
+   
+   int getID();
+      
+   /** callback function for play audio stream
+   */
+   static int playCallback( const void *inputBuffer, void *outputBuffer,
+                        unsigned long framesPerBuffer,
+                        const PaStreamCallbackTimeInfo* timeInfo,
+                        PaStreamCallbackFlags statusFlags,
+                        void *userData );
+
+   /** callback function for capture audio stream
+   */
+   static int recordCallback( const void *inputBuffer, void *outputBuffer,
+                        unsigned long framesPerBuffer,
+                        const PaStreamCallbackTimeInfo* timeInfo,
+                        PaStreamCallbackFlags statusFlags,
+                        void *userData );   
+#ifdef linux1
+
+   static void* audioThread(void *args);
+   
+   /** callback function for capture firewire audio stream
+   */
+   static int recordFWCallback(iec61883_amdtp_t amdtp, char *data, 
+                  int nsamples, unsigned int dbc, 
+                  unsigned int dropped, void *callback_data);
+#endif            
+   
+protected:
+   int ID; 
+   
+   /** circular buffer for saving audio stream block
+   */
+   sageAudioCircBuf* buffer;
+   
+   /** audio sample format : float, short, char, unsigned char
+   */
+   sageSampleFmt sampleFmt;
+   
+   /** numbers of audio channel
+   */
+   int  channels;
+   
+   /** object for audio streaming : portaudio object
+   */
+   PaStream*   audioStream;
+
+   /** parameters for audio streaming
+   */
+   PaStreamParameters*   audioParameters;
+
+   /** audio mode : play, capture
+   */
+   sageAudioMode audioMode;
+   
+   /** sound card device number : 0 is default device number
+   */
+   int deviceNum;
+   
+   /** according to audio sample format, byte per sample is different
+   */
+   int bytesPerSample; 
+   
+   /** audio sampling rate : default is 44100
+   * standard sampling rate : 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0, 192000.0
+   */
+   long samplingRate;
+   
+   /** frames per buffer : default is 1024
+   */
+   int  framePerBuffer;
+
+   /** play flag : play, pause, stop
+   */
+   int   playFlag;   
+   
+#ifdef linux1
+   raw1394handle_t handle;
+   iec61883_amdtp_t amdtp;
+#endif
+   
+   /** latency
+   */
+   long minLatency;
+   long maxLatency;
+
+}; 
+
+#endif
Index: trunk/src/testing/include/overlayWall.h
===================================================================
--- trunk/src/testing/include/overlayWall.h	(revision 4)
+++ trunk/src/testing/include/overlayWall.h	(revision 4)
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: overlayPointer.h
+ * Author : Ratko Jagodic, Byungil Jeong
+ *
+ *   Description: the super class of simple drawing objects 
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+ *********************************************************************************/
+
+#ifndef SAGE_WALL_H
+#define SAGE_WALL_H
+
+#include "sageDrawObject.h"
+
+#define TEXTURE_LOAD_ERROR 0
+
+class overlayWall: public sageDrawObject {
+
+private:
+	GLuint logoTexture;
+
+	GLuint loadTextureRAW(const char * filename, bool wrap);
+	GLuint loadTexturePNG(const std::string filename, int &width, int &height);
+	void cropTexture(const unsigned char *in, unsigned char *&out, const unsigned int width);
+	void cropTexture(const unsigned char *in, unsigned char *&out, sageRect &texture);
+
+protected:
+
+public:
+	// METHODS
+	overlayWall();
+	int init(char *name);
+	int draw();
+	int destroy();
+	int parseMessage(char *msg);
+};
+
+#endif
Index: trunk/src/testing/include/sageAppAudio.h
===================================================================
--- trunk/src/testing/include/sageAppAudio.h	(revision 4)
+++ trunk/src/testing/include/sageAppAudio.h	(revision 4)
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAppAudio.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_APP_AUDIO_H
+#define _SAGE_APP_AUDIO_H
+
+#include "sageBase.h"
+
+class sageAudioCircBuf;
+
+class sageAppAudio {
+public:   
+   sageAppAudio(sageAudioCircBuf* audioBuffer, int maxsize);
+   virtual ~sageAppAudio();
+
+public:   
+   //int pushAudioData(int size, void *buf);
+   int swapBuffer(int size, void *buf);
+   int start(void);
+   
+protected:
+   static void* audioThread(void *args);
+
+   int processData();
+
+protected:
+   pthread_mutex_t *queueLock;
+   pthread_cond_t *notFull;
+   pthread_cond_t *notEmpty;
+
+   sageAudioCircBuf* buffer;
+
+   int readIndex;
+   int writeIndex;
+   bool initialized;
+
+   bool full;
+   bool empty;
+   int maxAudioBuffSize;
+   
+   void * audioAppRawBuffer[2];
+   int audiobufSize[2];
+
+   int remainBufSize;
+   void * remainBuf;
+   
+   pthread_t thAppId;
+   
+};
+
+#endif
Index: trunk/src/testing/include/fsManager.h
===================================================================
--- trunk/src/testing/include/fsManager.h	(revision 4)
+++ trunk/src/testing/include/fsManager.h	(revision 4)
@@ -0,0 +1,189 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsManager.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+
+#ifndef _FSManager_H
+#define _FSManager_H
+
+#include "sage.h"
+#include "sageConfig.h"
+#include <map>
+
+class fsCore;
+class displayInstance;
+class fsServer;
+class sageVirtualDesktop;
+
+/**
+ * class rcvInfo
+ *
+ */
+class rcvInfo {
+public:
+	int syncPort;
+	int syncBarrierPort; /**< TCP port number for the barrier server (2nd phase) */
+
+	/**
+	 * This determines the duration of the first phase => eventually frequency of graphics swap buffer call
+	 * in Hz
+	 */
+	int refreshInterval;
+	int syncMasterPollingInterval; /**< (in usec), select() return timer for syncMaster */
+
+	/**
+	 * 0 nosync
+	 * 1 data sync only
+	 * 2 swap buffer sync
+	 * 3 with NTP
+	 */
+	int syncLevel;
+
+	int streamPort;
+	int bufSize;
+	bool fullScreen;
+
+	bool audioOn;
+	int audioPort;
+	int audioSyncPort;
+	int agSyncPort;
+	rcvInfo() : syncPort(11000), syncBarrierPort(11001), refreshInterval(120), syncMasterPollingInterval(100), syncLevel(1), streamPort(21000), bufSize(64), fullScreen(true),
+			audioOn(false), audioSyncPort(13000), audioPort(23000), agSyncPort(15000) {}
+};
+
+class sageNwConfig;
+class displayConnection;
+
+/**
+ * \brief The container of the Free Space Manager components - fsCore, displayInstance, appData, and fsServer.
+ *
+ * The FSManager receives from UI clients various user commands such as application execution, window move, resizing or z-order change and then executes the commands by sending control messages to SAIL nodes or SAGE receivers.
+ *
+ * This class is instanced by main() in the fsMain.cpp,
+ * then member function mainLoop() is called after reading fsManager.conf
+ */
+class fsManager {
+private:
+   fsCore *core;
+   fsServer *server;
+
+	int m_execIndex;
+	int m_execIDList[MAX_INST_NUM];
+
+   rcvInfo rInfo;
+   sageNwConfig *nwInfo;
+
+   std::vector<appInExec *> execList; /**< a list of applications */
+   std::vector<displayInstance *> dispList;
+   std::vector<int> uiList;
+   std::vector<int> appUiList;
+   std::vector<sageRect *> drawObjectList;
+   std::vector<sageVirtualDesktop *> vdtList;
+   std::vector<displayConnection *> dispConnectionList;
+
+   char fsIP[SAGE_IP_LEN];
+   char pubIP[SAGE_IP_LEN];
+   char fsName[SAGE_NAME_LEN];
+   char conManIP[SAGE_IP_LEN];
+   int conManPort;
+   int uiPort, sysPort, trackPort;
+   int winTime;
+   int winStep;
+   bool NRM;
+   bool blockCommands;
+   bool fsmClose;
+   bool globalSync;
+   bool useLocalPort;
+
+   /**
+	* generated by init()
+	* invoke talkToConnectionManager()
+	*/
+   static void* msgThread(void *args);
+
+   /**
+    * connect to connection manager
+    * continuously send message to the connection manager
+    */
+   int talkToConnectionManager();
+
+public:
+   fsManager();
+   ~fsManager();
+
+   /**
+	* reads config file then sets the fsManager member variables.<BR>
+	* creates fsServer and fsCore instances and calls init() of them.<BR>
+	* creates sageVirtualDesktop objects that will launch sageDIsplayManager and sageAudioManager<BR>
+	* starts msgThread().
+	*/
+   int init(const char *config);
+
+   void printAppList();
+   char* getFsIP() { return fsIP; }
+   int getUiPort() { return uiPort; }
+   int getSysPort() { return sysPort; }
+   int getTrackPort() { return trackPort; }
+
+   /**
+	* keeps calling server->checkClients() forever
+	*/
+   void mainLoop();
+
+   int msgToCore(sageMessage &msg, int clientID);
+   int msgToDisp(sageMessage &msg, int clientID);
+   int sendMessage(int cId, int code, int data);
+   int sendMessage(int cId, int code, char* data);
+   int sendMessage(int cId, int code);
+   int sendMessage(sageMessage &msg);
+   int windowChanged(int appId);
+   int parseDisplayConnectionInfo(FILE *fp);
+   int sendToAllRcvs(int code, char *data = NULL);
+   int sendToAllRcvs(int code, int data);
+   int sendToVDT(int vdtID, int code, char *data = NULL);
+   int sendToVDT(int vdtID, int code, int data);
+   int sendToOtherVDT(int vdtID, int code, char *data = NULL);
+   int sendToOtherVDT(int vdtID, int code, int data);
+
+   friend class fsCore;
+   friend class displayInstance;
+   friend class fsServer;
+};
+
+#endif
Index: trunk/src/testing/include/audioFormatManager.h
===================================================================
--- trunk/src/testing/include/audioFormatManager.h	(revision 4)
+++ trunk/src/testing/include/audioFormatManager.h	(revision 4)
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: audioFormatManager.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef AUDIO_FORMAT_MANAGER_H
+#define AUDIO_FORMAT_MANAGER_H
+
+#include <vector>
+#include "audioConverter.h"
+
+class audioFormatManager {
+public:
+   audioFormatManager();
+   ~audioFormatManager();
+   
+   audioConverter* createConverter(char* filename, FILE* fp);
+
+   
+private:
+   std::vector<audioConverter*> converterList;
+
+}; 
+
+#endif
Index: trunk/src/testing/include/sageAudioModule.h
===================================================================
--- trunk/src/testing/include/sageAudioModule.h	(revision 4)
+++ trunk/src/testing/include/sageAudioModule.h	(revision 4)
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioModule.h
+ * Author : Hyejung Hur
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _SAGE_AUDIO_MODULE_H
+#define _SAGE_AUDIO_MODULE_H
+
+#include <vector>
+
+#include "sageBase.h"
+#include "sageAudioCircBuf.h"
+#include "audioFileReader.h"
+#include "audioFileWriter.h"
+#include "audioFormatManager.h"
+
+class sailConfig;
+class sageAudio;
+
+/**
+ * class sageAudioConfig
+ */
+class sageAudioConfig {
+public:
+   int  deviceNum;
+   sageSampleFmt sampleFmt;
+   long samplingRate;
+   int  channels;
+   int  framePerBuffer;
+   sageAudioMode audioMode;
+
+   sageAudioConfig() : deviceNum(-1), sampleFmt(SAGE_SAMPLE_FLOAT32), samplingRate(44100), channels(2), framePerBuffer(1024), audioMode(SAGE_AUDIO_CAPTURE) {}
+   ~sageAudioConfig() { }
+};
+
+
+/**
+ * \brief one instance per sageAudioManager
+ */
+class sageAudioModule {
+public:
+   /** this class is singleton
+   */
+   static sageAudioModule* _instance;
+
+   /** create instance and assign it to _instance
+   */
+   static sageAudioModule* instance();
+
+   /** sets parameters for audio configuration
+   * will call init() after setting parameters
+   */
+   void init(sailConfig &conf);
+   virtual void init(sageAudioConfig &conf);
+   void updateConfig(sageAudioConfig &conf);
+
+   sageAudioCircBuf* load(char* filename, bool loop, int nframes, long totalframes=0);
+   int save(char* filename);
+
+   /** open audio stream and play
+   */
+   int play(int id);
+
+   int pause(int id);
+   int stop(int id);
+
+   /**
+    * sageAudio is instantiated in here
+    */
+   sageAudioCircBuf* createObject(sageAudioConfig &conf, int instID =-1);
+   // temporaly....
+   sageAudioCircBuf* createObject(int instID =-1);
+   int deleteObject(int id);
+
+   sageAudioCircBuf* createBuffer(int instID=-1);
+   sageAudioCircBuf* createBuffer(sageAudioConfig &conf, int size=64, int instID=-1);
+
+   /** test audio input/output device
+   */
+   void testDevices();
+
+   ~sageAudioModule();
+
+   void setgFrameNum(long frames);
+   long getgFrameNum();
+
+   std::vector<sageAudioCircBuf*>& getBufferList(void);
+	sageAudioConfig* getAudioConfig();
+
+protected:
+	/**
+	 * initialize() of PortAudio lib is called
+	 */
+   sageAudioModule();
+
+   /** create audio and create circular buffer for saving audio block.
+    * New audioFormatManager, audioFileReader, and audioFileWriter objects are generated.
+   */
+   void init();
+
+protected:
+   /** audio pointer
+   */
+   //sageAudio* audio;
+   std::vector<sageAudio*> audioList;
+
+   /** audio circular buffer list
+   */
+   std::vector<sageAudioCircBuf*> bufferList;
+
+   /** audio configuration
+   */
+   sageAudioConfig config;
+
+   audioFileReader* fileReader;
+   audioFileWriter* fileWriter;
+   audioFormatManager* formatManager;
+
+   long gFrameNum;
+
+};
+
+#endif
Index: trunk/src/testing/include/sageBuf.h
===================================================================
--- trunk/src/testing/include/sageBuf.h	(revision 4)
+++ trunk/src/testing/include/sageBuf.h	(revision 4)
@@ -0,0 +1,226 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageBuf.h
+ * Author : Byungil Jeong
+ *
+ *	Description: SAGE buffer classes
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+#ifndef _SAGE_BUF_H
+#define _SAGE_BUF_H
+
+#include "sageBase.h"
+
+#define MAX_READER_NUM 100
+
+typedef char* sageBufEntry;
+
+/**
+ * the abstract class of sage buffers
+ */
+class sageBuf {
+protected:
+	int readIdx;
+	int writeIdx;
+	int entryNum;
+	int bufLen;
+	int entrySize;
+   sageBufEntry *entries;
+
+	pthread_mutex_t bufLock;
+	pthread_cond_t notEmpty;
+	bool full, empty;
+
+	void initArray(int size);
+
+public:
+   sageBuf();
+	inline bool isEmpty() { return empty; }
+	inline bool isFull()  { return full; }
+	inline int  size()    { return bufLen; }
+   inline void setEntryNum(int num) { entryNum = num; }
+	inline int  getEntryNum() { return entryNum; }
+   inline int  getReadIdx()  { return readIdx; }
+   inline int  filled()  { return (entryNum*100)/bufLen; }
+
+   sageBufEntry operator[](int idx);
+
+	void reset();
+	void resetIdx();
+	int getStatus() { return entryNum*100/bufLen; }
+   virtual void setBlockingFlag(bool blk) {}
+	virtual bool pushBack(sageBufEntry entry) = 0;
+   virtual sageBufEntry front() = 0;
+   virtual bool next() = 0;
+   virtual sageBufEntry front(int id) { return NULL; }
+   virtual sageBufEntry next(int id) { return NULL; }
+   //virtual int import(sageBuf *buf) = 0;
+   virtual void releaseLock() = 0;
+   ~sageBuf();
+};
+
+/**
+ * no concurrent read and write
+ */
+class sageSerialBuf : public sageBuf {
+public:
+   sageSerialBuf(int len) { initArray(len); }
+	bool pushBack(sageBufEntry entry);
+   sageBufEntry front();
+   bool next();
+   //int import(sageBuf *buf);
+   void releaseLock() {}
+};
+
+/**
+ * sageCircBufSingle
+ * instantiated in sageBlockBuf
+ */
+class sageCircBufSingle : public sageBuf {
+public:
+	int instID;
+
+protected:
+   bool blocking;
+   bool active;
+
+public:
+   sageCircBufSingle(int len, bool blkRead) : blocking(blkRead), active(true), instID(-1)
+      { initArray(len); }
+	bool pushBack(sageBufEntry entry);
+   sageBufEntry front();
+   bool next();
+   bool isActive()  { return active; }
+
+   void setBlockingFlag(bool blk) { blocking = blk; }
+   void releaseLock();
+};
+
+class sageCircBuf : public sageBuf {
+protected:
+	pthread_cond_t notFull;
+
+public:
+   sageCircBuf(int len);
+   bool pushBack(sageBufEntry entry, bool blk);
+   bool pushBack(sageBufEntry entry) { return pushBack(entry, false); }
+	sageBufEntry front(bool blk);
+   sageBufEntry front() { return front(false); }
+   bool next();
+   void releaseLock();
+};
+
+class sageRAB : public sageBuf {
+protected:
+   int *nextIdx;
+   int head;
+   int tail;
+   int freeHead;
+   int freeTail;
+
+public:
+   sageRAB(int len);
+
+   bool insert(sageBufEntry entry);
+   bool remove(int idx, int prev);
+   inline int  start() { return head; }
+   void next(int &idx);
+
+   bool next() { return false; }
+   sageBufEntry front() { return NULL; }
+   bool pushBack(sageBufEntry entry) { return false; }
+   void releaseLock() {}
+};
+
+class readerInfo {
+public:
+   int readIdx;
+   bool empty;
+   bool active;
+
+   readerInfo() : readIdx(0), empty(true), active(false) {}
+};
+
+/**
+ * circular buffer with multiple readers
+ */
+class sageCircBufMulti : public sageBuf {
+private:
+   sageBufEntry front() { return NULL; }
+   bool next();
+   //int import(sageBuf *buf) { return 0; }
+   int distToWriteIdx(int ridx);
+
+protected:
+	bool blocking;
+	int readerNum;
+   int maxReaderID;
+
+	readerInfo readers[MAX_READER_NUM];
+
+public:
+   sageCircBufMulti(int len, bool blkRead) : readerNum(0), blocking(blkRead), maxReaderID(-1)
+      { initArray(len); }
+
+	int addReader(int id);
+	void removeReader(int id);
+   inline bool isActive(int id) { return readers[id].active; }
+
+   bool pushBack(sageBufEntry entry);
+   sageBufEntry front(int id);
+   sageBufEntry next(int id);
+
+   void setBlockingFlag(bool blk) { blocking = blk; }
+   void releaseLock() { blocking=false, empty=false, pthread_cond_broadcast(&notEmpty); }
+};
+
+#endif
+
+/*
+class sageBufMulti : public sageBuf {
+protected:
+	int readerNum;
+	readerInfo readers[MAX_READER_NUM];
+
+public:
+   sageBufMulti(int len) : readerNum(1) { initArray(len); }
+	bool pushBack(sageBufEntry entry);
+   sageBufEntry front();
+   bool next();
+   int import(sageBuf *buf);
+};
+*/
Index: trunk/src/testing/include/sageSync.h
===================================================================
--- trunk/src/testing/include/sageSync.h	(revision 4)
+++ trunk/src/testing/include/sageSync.h	(revision 4)
@@ -0,0 +1,581 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageSync.h
+ * Author : Byungil Jeong, Rajvikram Singh,
+ * Description : This file includes classes to synchronize multiple groups
+ *               of synchronization slaves in the SAGE processes and a class
+ *               to synchronize multiple threads in a SAGE process.
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGESYNC_H
+#define _SAGESYNC_H
+
+#include "sageBase.h"
+#include <list>
+#include <map>
+#include <bitset>
+
+#define SAGE_SYNC_MSG_LEN  1280 // must be equal to SAGE_EVENT_SIZE
+#define MAX_SYNC_GROUP     100
+#define SYNC_MSG_BUF_LEN   64
+
+#define SAGE_UPDATE_SETUP    1
+#define SAGE_UPDATE_FOLLOW   2
+#define SAGE_UPDATE_FRAME    3
+#define SAGE_UPDATE_AUDIO    4
+
+#define SAGE_CONSTANT_SYNC   1
+#define SAGE_ASAP_SYNC_HARD  2
+#define SAGE_ASAP_SYNC_SOFT  3
+
+#define NORMAL_SYNC          1
+#define SKIP_FRAME           2
+
+#ifndef	MSG_DONTWAIT
+#define	MSG_DONTWAIT	0
+#endif
+
+
+/**
+ * class syncSlaveData.
+ */
+class syncSlaveData {
+public:
+
+	/**
+	 * a syncClient's socket file descriptor
+	 */
+   int            clientSockFd;
+
+   /**
+    * another socket for refresh barrier - 2nd phase
+	*/
+   int barrierClientSockFd;
+
+   /**
+    * a syncClient's IP address
+	*/
+   sockaddr_in      clientAddr;
+
+
+   /**
+    * Sungwon
+    * this will be filled in sageSyncServer::syncServerThread() when the object is created
+    */
+   int SDM; // sungwon
+
+   /**
+    * frame number.
+	*/
+   int            frame;
+
+   /**
+    * Constructor.
+    * When a syncClient calls sageSyncClinet::connectToServer(), sageSyncServer::syncServerThread() accepts it<BR>
+    * then the thread creates syncSlaveData object for the client.
+	*/
+   syncSlaveData() : frame(0), SDM(-1) {}
+};
+
+//forward declarations
+class sageSyncClient;
+class sageSyncServer;
+
+#define MAX_INTERVAL_ERROR 0.1
+#define SYNC_TIMEOUT       1667   /**< 1sec/60 * 10% = 1667 us */
+
+/**
+ * class syncGroup.
+ */
+class syncGroup {
+protected:
+   int noOfUpdates; /**< how many displays are updated ? */
+   int slaveNum; /**< how many syncSlaves are involved in this sync group */
+   pthread_mutex_t   *syncMsgLock;
+   std::deque<char *> syncMsgQueue;
+
+   int id, policy, curFrame, audioFrame, videoFrame, keyFrame, skipFrame, audioSyncCnt;
+
+   /**
+    * minimum sync signal interval<BR>
+    * Even though a sync group is ready to proceed to the next frame,<BR>
+    * the sync master waits until the minimum interval is reached.
+    */
+   double interval;
+
+   double timeError;
+   bool syncEnd;
+
+   /**
+    * when sageSyncServer::addSyncGroup() is called, the sync server object calling addSyncGroup() is assigned.
+    */
+   sageSyncServer *syncServer;
+   pthread_t threadID;
+   sageTimer timer;
+   pthread_mutex_t  syncLock;
+   pthread_cond_t   resumeSync; /**< condition variable */
+
+   bool holdSync; /**< if true, then it will make checkHold() to wait on condition resumeSync */
+   bool waitingInterval; /**< whether syncGroup is waiting to reach the interval */
+   bool waitForKeyFrame;
+
+public:
+   /**
+    * Constructor.
+	*/
+   syncGroup() : id(0), noOfUpdates(0), curFrame(0), slaveNum(0), syncEnd(false), interval(0.0),
+      policy(SAGE_ASAP_SYNC_SOFT), videoFrame(0), audioFrame(-1), keyFrame(100), holdSync(false),
+      timeError(0.0), waitingInterval(false), waitForKeyFrame(false), skipFrame(0), audioSyncCnt(0)
+   { syncMsgQueue.clear(); }
+
+   int init(int startFrame, int _policy_, int groupID, int frameRate = 1, int sNum = 1); /**< syncGroup::init() */
+   int setFrameRate(float frameRate);
+
+   /**
+    * TRUE, if this syncGroup reached the interval
+    */
+   bool checkInterval();
+
+   /**
+    * IMPORTANT<BR>
+    * This function is called by sageSyncServer::manageUpdate()<BR>
+    *
+    * HARD_SYNC implemented<BR>
+    * A syncGroup maintains the number of syncSlaves. Whenever slave sends an update, noOfUpdates increases<BR>
+    * HARD_SYNC ensures every display for an app can maintain same frame number<BR>
+    * by updated frame can be propagated only when noOfUpdates == number of slaves<BR>
+    * i.e. all syncSlaves for an application should sends udpate
+    *
+    * @return 0 or NORMAL_SYNC
+    */
+   int processUpdate(char *data);
+
+   int enqueSyncMsg(char *msg); /**< enqueue sync message<BR>thread safe*/
+   char* dequeSyncMsg(); /**< dequeue sync message<BR>thread sage*/
+   int getSyncID() { return id; }
+   bool checkTimeOut();
+   void blockSync(); /**< sets holdSync = true */
+   void unblockSync(); /**< sets holdSync = false */
+
+   /**
+    * waits on condition resumeSync if holdSync is true
+    */
+   void checkHold();
+   inline bool isWaiting() { return waitingInterval; }
+
+   friend class sageSyncServer;
+   friend class sageSyncClient;
+};
+
+/**
+ * class sageSyncBBServer
+ */
+class sageSyncBBServer {
+protected:
+   int serverSockFd; /**< syncServer's socket */
+   int maxSyncGroupID;
+   int maxSlaveSockFd;
+   bool syncEnd;
+
+   /**
+    * -1 old sync
+    *  0 no sync
+    *  1 data sync only
+    *  2 two phase
+    *  3 one phase
+    */
+   int syncLevel;
+
+   sockaddr_in serverAddr;
+   fd_set slaveFds;
+
+   pthread_t syncThreadID, syncServerThreadID;
+
+   std::vector<syncSlaveData> syncSlaves; /**< a list of sync slaves */
+
+   /**
+    * a list of sync slaves
+    * key is SDM id
+    * value is its data(mainly socket)
+    */
+   std::map<int,syncSlaveData> syncSlavesMap;
+
+   sockaddr_in barrierServerAddr;
+   int barrierServerSockFd;
+   int barrierPort;
+
+   fd_set barrierSlaveFds;
+   int maxBarrierSlaveSockFd;
+
+   pthread_t syncBarrierServerThreadID;
+   static void* syncBarrierServerThread(void *);
+
+   /**
+    * waits syncClient's connection by calling accept() syscall<br>
+    * if one connects, then it creates syncSlaveData object for it, and adds it to the vector syncSlaves
+    */
+   static void* syncServerThread(void*);
+
+   /**
+    * This thread is created whenever addSyncGroup() is called and under some condition.<BR>
+    * 1. when the policy is SAGE_CONSTANT_SYNC<BR>
+    * 2. 1 is not true and asapSyncGroupNum == 0<BR>
+    * <BR>
+    * if syncGroup's policy is SAGE_CONSTANT_SYNC, then this thread periodicaly sends sync(sendSync()) signal to its syncGroup.<BR>
+    * Otherwise it sends sync signal(by calling manageUpdate()) only when syncClient asks ??<BR>
+    * The period is defined in the syncGroup.interval
+    */
+   static void* mainLoopThread(void*);
+
+   sageTimer timer;
+
+public:
+	/**
+	 *  Constructor. Called in sageDisplayManager::sageDisplayManager() and sail::init()
+	 */
+   sageSyncBBServer(int syncLevel = 2);
+   ~sageSyncBBServer();
+
+   /**
+    * creates syncServer socket, and starts syncServerThread
+    */
+   int init(int port);
+
+   /**
+    * create barrierServerSockFd
+    */
+   int initBarrier(int barrierPort);
+
+   int totalRcvNum;
+   int refreshInterval;
+   int syncMasterPollingInterval;
+   int startManagerThread(int totalRcvNum, int refreshInterval, int syncMasterPollingInterval);
+
+   void killAllClients();  /**< closes all the open client sockets */
+   int checkTimeOut();
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * class sageSyncServer. It is created when syncMaster == true
+ */
+class sageSyncServer {
+protected:
+   int serverSockFd; /**< syncServer's socket */
+   int asapSyncGroupNum, maxSyncGroupID;
+   int maxSlaveSockFd;
+   bool syncEnd;
+
+   sockaddr_in serverAddr;
+   fd_set slaveFds;
+
+   pthread_t   syncThreadID, syncServerThreadID;
+   pthread_t   groupThreadID;
+
+   std::vector<syncSlaveData> syncSlaves; /**< a list of sync slaves */
+
+   /**
+    * key - sdm id
+	*/
+   std::map<int,syncSlaveData> syncSlavesMap;
+
+
+   //syncGroup *syncGroupArray[MAX_SYNC_GROUP]; /**< an array of sync groups */
+   std::vector<syncGroup *> syncGroupArray; /**< an array of sync groups */
+
+   /**
+    * waits syncClient's connection by calling accept() syscall<br>
+    * if one connects, then it creates syncSlaveData object for it, and adds it to the vector syncSlaves
+    */
+   static void* syncServerThread(void*);
+
+   /**
+    * This thread is created whenever addSyncGroup() is called and under some condition.<BR>
+    * 1. when the policy is SAGE_CONSTANT_SYNC<BR>
+    * 2. 1 is not true and asapSyncGroupNum == 0<BR>
+    * <BR>
+    * if syncGroup's policy is SAGE_CONSTANT_SYNC, then this thread periodicaly sends sync(sendSync()) signal to its syncGroup.<BR>
+    * Otherwise it sends sync signal(by calling manageUpdate()) only when syncClient asks ??<BR>
+    * The period is defined in the syncGroup.interval
+    */
+   static void* managerThread(void*);
+   static void* managerConstantThread(void*);
+
+   /**
+    * It seems that each syncGroup has corresponding managerThread.<BR>
+    *
+    * This function waits this syncServer object's syncSlaves' update from socket connection<BR>
+    * then, extracts and identifies groupID from a slave's message<BR>
+    * then, calls corresponding syncGroup's syncGroup::processUpdate()<BR>
+    * If syncGroup's processUpdate() returns NORMAL_SYNC<BR>
+    * then, syncGroup::checkInterval(), syncGroup::checkHold(), syndSync() could be called.
+    *
+    * respond with sync signal ( sendSync() ) when a syncClient sends sageSyncClient::sendSlaveUpdate().
+    */
+   int manageUpdate();
+
+   /**
+    * sends sync message (group's current frame: grp->curFrame) to the syncSlaves.<BR>
+    * sync message includes grp->id, grp->curFrame, dataLen, cmd<BR>
+    * if grp->syncGroup::dequeSyncMsg() returns data then sends the data as well
+    */
+   int sendSync(syncGroup *grp, int cmd = NORMAL_SYNC);
+   sageTimer timer;
+
+	syncGroup* findSyncGroup(int id, int& index);
+
+public:
+	/**
+	 *  Constructor. Called in sageDisplayManager::sageDisplayManager() and sail::init()
+	 */
+   sageSyncServer();
+   ~sageSyncServer();
+
+   /**
+    * creates syncServer socket, and starts syncServerThread
+    */
+   int init(int port);
+
+   /**
+    * Adds syncGroup into syncGroupArray and creates corresponding managerThread() if group's policy is SAGE_CONSTANT_SYNC<BR>
+    * or policy is not SAGE_CONSTANT_SYNC and asapSyncGroupNum == 0<BR>
+    * triggered by sageDisplayManager::initStreams() and sail
+    */
+   int addSyncGroup(syncGroup *grp);
+
+   int removeSyncGroup(int id);
+
+   void killAllClients();  /**< closes all the open client sockets */
+   int checkTimeOut();
+}; // End of sageSyncServer
+
+class sageCircBufSingle;
+
+/**
+ * class syncMsgStruct
+ */
+class syncMsgStruct {
+public:
+   int frameID;
+   char *data;
+
+   syncMsgStruct() : frameID(0), data(NULL) {}
+   syncMsgStruct(int size) : frameID(0) { data = new char[size]; }
+   ~syncMsgStruct() { if (data) delete [] data; }
+};
+
+/**
+ * class sageSyncClient
+ */
+class sageSyncClient {
+private:
+	int syncLevel;
+
+   int clientSockFd;
+
+   int barrierClientSockFd;
+   int refreshBarrierDeltaT;
+
+   int maxGroupID;
+   //sageCircBufSingle *syncMsgBuf[MAX_SYNC_GROUP];
+   std::vector<sageCircBufSingle *> syncMsgBuf;
+   bool syncEnd;
+   pthread_t syncThreadID;
+
+   /**
+    * keeps trying to receive message from syncServer by calling readSyncMsg()<BR>
+    * started by addSyncGroup()
+	*/
+   static void* syncClientThread(void *args);
+
+   /**
+    * receive messages from sageSyncServer::sendSync()<BR>
+    * receives message(syncgroupID, frameNum, dataLen) from syncServer by calling sage::recv() and reads sync data.<BR>
+    * This function is continuously called by syncClientThread().
+	*/
+   int readSyncMsg();
+
+	sageCircBufSingle* findSyncGroup(int id, int& index);
+
+public:
+   /**
+	* creates socket(clientSockFd) and sets TCP_NODELAY, SO_OOBINLINE socket option
+	*/
+   sageSyncClient(int syncLevel = -1);
+
+   /**
+    * shuts down the socket, and calls pthread_join
+	*/
+   ~sageSyncClient();
+
+   /**
+    * connects to a syncServer
+	*
+	* @param syncServerIP a char *
+	* @param port an integer
+	* @return -1 on error, 0 otherwise
+	*/
+   int connectToServer(const char *serverIP, int port, int SDMnum=-1);
+
+   int connectToBarrierServer(const char *serverIP, int port, int SDMnum=-1);
+
+
+   /**
+    * creates sageCircBufSingle object, assigns it into syncMsgBuf array<BR>
+    * starts syncClientThread() if no other syncgroup was added.<BR>
+    * So, syncClientThread() is started when the first syncgroup is added.
+	*
+	* @param id an integer, sync group id
+	* @return -1 on error, 0 otherwise
+	*/
+   int addSyncGroup(int id);
+
+
+   /**
+    * removes element(id) from syncMsgBuf array
+	*
+	* @param id an integer
+	* @return -1 on error, 0 otherwise
+	*/
+   int removeSyncGroup(int id);
+
+
+   /**
+    * sends update msg to the syncServer.<BR>
+    * sageSyncServer::manageUpdate() will respond to this.<BR>
+    *
+    * Triggered by below events and message<BR>
+    * EVENT_READ_BLOCK (pixelDownloader::fetchSageBlocks()) <BR>
+    * EVENT_SYNC_MESSAGE (sageDisplayManager::processSync() -> pixelDownloader::fetchSageBlocks()) <BR>
+    * RCV_UPDATE_DISPLAY (sageDisplayManager::updateDisplay() -> pixelDownloader::fetchSageBlocks()) <BR>
+    * <BR>
+    * in the sageAudioManager::initStream()<BR>
+    * in the sageAudioCircBuf::updateReadIndex() <- (sageAudioReceiver::readData(), sageAudioStreamer::streamLoop())<BR>
+    *
+	*
+	* @param frame an integer frame number
+	* @param id an integer, default 0
+	* @param rcvNum an integer, default 0
+	* @param type an integer, default SAGE_UPDATE_FOLLOW
+	* @return -1 on error, 0 otherwise
+	*/
+   int sendSlaveUpdate(int frame, int id = 0, int rcvNum = 0, int type = SAGE_UPDATE_FOLLOW, int nodeID=-1);
+
+   /**
+    * when a PDL received new frame (END_FRAME flag) it reports to the syncMaster before doing swapMontage()
+	*/
+   int sendSlaveUpdateToBBS(int frame, int id = 0, int rcvNum = 0, int SDMnum = -1, int delayCompenLatency=0);
+
+   /** THE FINAL CASE , sageSync_theFinal.cpp */
+   int sendRefreshBarrier(int nodeID);
+   int recvRefreshBarrier(bool nonblock=false); // block or nonblock
+   /** end THE FINAL CASE */
+
+   /**
+    * receives sync message without additional data
+	*
+	* @param msg a char *
+	* @return -1 on error, 0 otherwise
+	*/
+   int waitForSync(char* msg, int len = -1);
+
+   /**
+    * It uses MSG_PEEK to find out the length of sync message
+    *
+    * @param void
+    * @return -1 on error, message size otherwise
+    */
+   int waitForSyncPeek();
+
+   /**
+    * receives sync message with group ID and additional data
+	*
+	* @param id an integer
+	* @return syncMsg, NULL on error
+	*/
+   syncMsgStruct* waitForSync(int id);
+
+   /**
+    * receives sync message with additional data
+	*
+	* @param data a char *
+	* @return -1 on error, 0 otherwise
+	*/
+   int waitForSyncData(char* &data);
+
+
+   /**
+    * ch
+	*/
+   int checkSync(char* &msg);
+}; // End of tvSyncClient
+
+
+/**
+ * For synchronization among master and slave threads
+ */
+class sageThreadSync {
+private:
+   pthread_mutex_t   *slaveLock;
+   pthread_mutex_t   *masterLock;
+   int slaveNum;
+
+public:
+   sageThreadSync(int sNum = 1);
+   ~sageThreadSync();
+
+   int synchronize(int rank = 0);
+};
+
+#endif
Index: trunk/src/testing/include/sageAudioBridge.h
===================================================================
--- trunk/src/testing/include/sageAudioBridge.h	(revision 4)
+++ trunk/src/testing/include/sageAudioBridge.h	(revision 4)
@@ -0,0 +1,156 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioBridge.h
+ * Author : Hyejung Hur, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef _SAGE_AUDIO_BRIDGE_H_
+#define _SAGE_AUDIO_BRIDGE_H_
+
+#include "streamProtocol.h"
+#include "sageBlock.h"
+
+class sageAudioBridge;
+class sageAudioDup;
+class sageTcpModule;
+class sageUdpModule;
+class messageInterface;
+class bridgeSharedData;
+
+typedef struct {
+   sageAudioBridge *This;
+   streamProtocol   *nwObj;
+} nwAudioCheckThreadParam;
+
+typedef struct {
+   sageAudioDup *This;
+   streamProtocol   *nwObj;
+} nwStreamThreadParam;
+
+typedef struct {
+	char* rcvIP;
+   int  rcvID;
+   int  nodeID;
+	int fsIdx;
+   bool active;
+   int sendPort;
+} streamBridgeParam;
+
+class sageAudioDup {
+private:
+   int sailNodeNum;
+	int streamType;
+	int blockSize;
+	int frameRate; 
+	int syncType;
+	int keyframe;
+	int sampleFmt;
+	int samplingRate;
+	int channels;
+	int framePerBuffer;
+   
+   pthread_t thId;
+   
+protected:
+	std::vector<streamBridgeParam*> paramList;
+	int instID;
+	int senderID;
+	streamProtocol* instNWObj;
+
+   bool initialized;
+   bool bridgeEnd;
+
+ 	int rcvNodeNum;
+	sageAudioBlock audioNBlock;
+			
+   static void* nwStreamThread(void *args);
+		
+public:
+   sageAudioDup(int appID);
+   ~sageAudioDup(void);
+
+	int init(void);
+	int addStream(char *msg, streamProtocol *nwObj);
+	int addReceiver(char *msg, int fsIdx);
+	void shutdownAllStreams(void);
+   void shutdownStreams(int fsIdx);   
+		
+   friend class sageAudioBridge;
+
+};
+
+class sageAudioBridge {
+private:
+   sageTcpModule *tcpObj;
+   sageUdpModule *udpObj;
+   sageNwConfig nwCfg;
+   
+   sageAudioDup *dupList[MAX_INST_NUM];
+   char audioIP[SAGE_IP_LEN];
+   int audioPort;
+   bool bridgeEnd;
+ 
+   int initNetworks();
+   messageInterface *msgInf;
+   bridgeSharedData *shared;
+   
+   static void* nwCheckThread(void *args);
+   
+public:
+   // ip, port  : IP address and port number where listening audio stream connections
+   // inf  :  message communication object for sending messages to SAIL.
+   sageAudioBridge(char *ip, int port, messageInterface *inf, bridgeSharedData *sh);
+   
+   // send SAIL_CONNECT_TO_ARCV to SAIL 
+   int startAudioStream(int instID, int sailClientID);
+
+   // accept streams from app
+   int initStreams(char *msg, streamProtocol *nwObj);   
+
+   // start audio stream from sageBridge to an endpoint (ARCV)
+   int duplicate(int instID, char *msg, int fsIdx);
+   
+   // delete a duplicator instance
+   int shutdownDup(int instID);
+   
+   // shutdown streams to an endpoint
+   int shutdownStreams(int instID, int fsIdx);
+   
+   ~sageAudioBridge();
+};
+
+#endif
Index: trunk/src/testing/include/sage.h
===================================================================
--- trunk/src/testing/include/sage.h	(revision 4)
+++ trunk/src/testing/include/sage.h	(revision 4)
@@ -0,0 +1,231 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sage.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_H
+#define _SAGE_H
+
+#include "sageBase.h"
+
+#define SAGE_BLOCK_NO_SYNC  100
+#define SAGE_BLOCK_CONST_SYNC  101
+#define SAGE_BLOCK_SOFT_SYNC   102
+#define SAGE_BLOCK_HARD_SYNC   103
+
+// Message Start Point
+#define FS_CORE_MESSAGE 0
+#define SAGE_UI_TO_FSM 1000
+#define APP_UI_TO_FSM 2000
+#define APP_TO_FSM 3000
+#define DISP_MESSAGE 10000
+#define GRCV_MESSAGE 20000
+#define SAIL_MESSAGE 30000
+#define APP_MESSAGE 31000
+#define FSM_TO_SAGE_UI 40000
+#define FSM_TO_APP_UI  41000
+#define BRIDGE_MESSAGE 50000
+#define ARCV_MESSAGE 15000
+
+// fsManager Messages
+#define REG_APP  FS_CORE_MESSAGE + 1  // app_name block_width block_height pixel_size sync_mode
+#define REG_GRCV FS_CORE_MESSAGE + 2
+#define FS_APPDISP_KILLED  FS_CORE_MESSAGE + 3
+#define FS_TIME_MSG FS_CORE_MESSAGE + 4
+#define REG_ARCV FS_CORE_MESSAGE + 5
+#define SYNC_INIT_ARCV FS_CORE_MESSAGE + 6
+#define NOTIFY_APP_SHUTDOWN    FS_CORE_MESSAGE + 7
+
+// UI to fsManager
+#define SAGE_UI_REG   SAGE_UI_TO_FSM 
+#define EXEC_APP      SAGE_UI_TO_FSM + 1
+#define SHUTDOWN_APP  SAGE_UI_TO_FSM + 2
+#define MOVE_WINDOW   SAGE_UI_TO_FSM + 3
+#define RESIZE_WINDOW   SAGE_UI_TO_FSM + 4
+#define PERF_INFO_REQ   SAGE_UI_TO_FSM + 5 
+#define STOP_PERF_INFO  SAGE_UI_TO_FSM + 6
+#define SAGE_BG_COLOR   SAGE_UI_TO_FSM + 7
+#define SAGE_Z_VALUE      SAGE_UI_TO_FSM + 8
+#define SAGE_ADMIN_CHECK  SAGE_UI_TO_FSM + 9
+#define BRING_TO_FRONT    SAGE_UI_TO_FSM + 10
+#define UPDATE_WIN_PROP   SAGE_UI_TO_FSM + 11
+#define APP_FRAME_RATE    SAGE_UI_TO_FSM + 12
+#define APP_PAUSE_INTV    SAGE_UI_TO_FSM + 13
+#define SAGE_APP_SHARE    SAGE_UI_TO_FSM + 14
+#define SAGE_FLIP_WINDOW   SAGE_UI_TO_FSM + 15
+#define SAGE_CHECK_LATENCY SAGE_UI_TO_FSM + 17
+#define ROTATE_WINDOW      SAGE_UI_TO_FSM + 18
+
+#define NETWORK_RESERVED   SAGE_UI_TO_FSM + 50
+
+#define SAGE_SHUTDOWN    SAGE_UI_TO_FSM + 100
+#define STREAM_PAUSE     SAGE_UI_TO_FSM + 101
+#define STREAM_RESUME    SAGE_UI_TO_FSM + 102
+
+#define ADD_OBJECT      SAGE_UI_TO_FSM + 200
+#define MOVE_OBJECT     SAGE_UI_TO_FSM + 201
+#define REMOVE_OBJECT   SAGE_UI_TO_FSM + 202
+#define OBJECT_MESSAGE  SAGE_UI_TO_FSM + 203
+#define SHOW_OBJECT     SAGE_UI_TO_FSM + 204
+
+#define APP_UI_REG   APP_UI_TO_FSM
+
+// displayInstance Messages from SAIL
+#define DISP_STREAM_INFO      DISP_MESSAGE
+#define DISP_SAIL_RESUME       DISP_MESSAGE + 4
+#define DISP_SAIL_PERF_RPT     DISP_MESSAGE + 5
+
+// displayInstance Messages from SAGE Receiver
+#define DISP_START_STREAM      DISP_MESSAGE + 100
+#define DISP_APP_CONNECTED     DISP_MESSAGE + 101
+#define DISP_DEPTH_CHANGED     DISP_MESSAGE + 103
+#define DISP_RCV_FRATE_RPT     DISP_MESSAGE + 104
+#define DISP_RCV_BANDWITH_RPT  DISP_MESSAGE + 105
+
+// gStreamRcv Messages
+#define RCV_INIT               GRCV_MESSAGE
+#define RCV_UPDATE_DISPLAY     GRCV_MESSAGE + 1
+#define RCV_CLEAR_DISPLAY      GRCV_MESSAGE + 2
+#define SHUTDOWN_RECEIVERS     GRCV_MESSAGE + 3
+#define RCV_CHANGE_BGCOLOR     GRCV_MESSAGE + 4
+#define RCV_SHUTDOWN_APP       GRCV_MESSAGE + 5
+#define RCV_CHANGE_DEPTH       GRCV_MESSAGE + 6
+#define RCV_PERF_INFO_REQ      GRCV_MESSAGE + 7
+#define RCV_PERF_INFO_STOP     GRCV_MESSAGE + 8
+#define UPDATE_OBJECT_POSITION GRCV_MESSAGE + 9
+
+// aStreamRcv Messages
+#define ARCV_AUDIO_INIT        ARCV_MESSAGE
+#define ARCV_SYNC_INIT         ARCV_MESSAGE + 1
+#define ARCV_SHUTDOWN_APP      ARCV_MESSAGE + 2
+
+// sage bridge messages
+#define BRIDGE_REG_NODE        BRIDGE_MESSAGE
+#define BRIDGE_SLAVE_INIT      BRIDGE_MESSAGE + 1
+#define BRIDGE_SHUTDOWN        BRIDGE_MESSAGE + 2
+#define BRIDGE_SHUTDOWN_APP    BRIDGE_MESSAGE + 3
+#define BRIDGE_SLAVE_PERF      BRIDGE_MESSAGE + 4
+#define BRIDGE_SYNC_ID         BRIDGE_MESSAGE + 5
+#define BRIDGE_APP_REG         BRIDGE_MESSAGE + 6
+#define BRIDGE_SLAVE_READY     BRIDGE_MESSAGE + 7
+#define BRIDGE_STREAM_INIT     BRIDGE_MESSAGE + 8
+#define BRIDGE_UI_REG          BRIDGE_MESSAGE + 9
+#define BRIDGE_APP_INST_READY BRIDGE_MESSAGE + 10
+#define CLEAR_APP_INSTANCE    BRIDGE_MESSAGE + 11 
+
+// fsManager to UI : 40000
+#define SAGE_STATUS      FSM_TO_SAGE_UI 
+#define APP_INFO_RETURN  FSM_TO_SAGE_UI + 1
+#define UI_PERF_INFO     FSM_TO_SAGE_UI + 2
+#define UI_APP_SHUTDOWN    FSM_TO_SAGE_UI + 3
+#define SAGE_DISPLAY_INFO  FSM_TO_SAGE_UI + 4
+#define Z_VALUE_RETURN     FSM_TO_SAGE_UI + 5
+#define APP_EXEC_CONFIG    FSM_TO_SAGE_UI + 6
+#define DISP_CONNECTION_INFO  FSM_TO_SAGE_UI + 7
+#define UI_ADMIN_INFO         FSM_TO_SAGE_UI + 8
+#define UI_MOVE_FAIL          FSM_TO_SAGE_UI + 15
+#define UI_RESIZE_FAIL        FSM_TO_SAGE_UI + 16
+#define UI_PERF_REQ_FAIL      FSM_TO_SAGE_UI + 17
+#define UI_OBJECT_INFO        FSM_TO_SAGE_UI + 18
+
+#define REQUEST_BANDWIDTH  FSM_TO_SAGE_UI + 100
+
+#define POINTER_STATUS     FSM_TO_SAGE_UI + 200
+
+#define APP_STATUS         FSM_TO_APP_UI
+
+// SAIL Messages
+#define SAIL_UI_CLIENT        SAIL_MESSAGE + 1
+#define SAIL_SLAVE_REG        SAIL_MESSAGE + 2
+#define SAIL_SHUTDOWN         SAIL_MESSAGE + 3
+#define SAIL_STREAM_START     SAIL_MESSAGE + 4
+#define SAIL_CONNECTED_TO_RCV  SAIL_MESSAGE + 5
+#define SAIL_PERF_INFO         SAIL_MESSAGE + 6
+#define SAIL_SEND_TIME_BLOCK   SAIL_MESSAGE + 7
+#define SAIL_CONFIG_STREAM     SAIL_MESSAGE + 8
+#define SAIL_INIT_STREAM       SAIL_MESSAGE + 9
+
+#define SAIL_CONNECT_TO_RCV  SAIL_MESSAGE + 101
+#define SAIL_INIT_MSG        SAIL_MESSAGE + 102
+#define SAIL_PERF_INFO_REQ   SAIL_MESSAGE + 103
+#define SAIL_PERF_INFO_STOP  SAIL_MESSAGE + 104
+#define SAIL_FRAME_RATE      SAIL_MESSAGE + 105
+#define SAIL_FLIP_WINDOW     SAIL_MESSAGE + 106
+#define SAIL_CONNECT_TO_ARCV SAIL_MESSAGE + 107
+#define SAIL_RESEND_FRAME    SAIL_MESSAGE + 108
+#define SAIL_CONNECT_TO_RCV_PORT SAIL_MESSAGE + 109
+#define SAIL_SET_RAIL			SAIL_MESSAGE + 110 // sungwon experimental
+
+// App UI to APP
+#define SAGE_EVT_CLICK            APP_MESSAGE
+#define SAGE_EVT_DOUBLE_CLICK    (APP_MESSAGE + 1)
+#define SAGE_EVT_MOVE             (APP_MESSAGE + 2)
+#define SAGE_EVT_ANALOG1          (APP_MESSAGE + 3)
+#define SAGE_EVT_PAN              (APP_MESSAGE + 3)
+#define SAGE_EVT_ANALOG2          (APP_MESSAGE + 4)
+#define SAGE_EVT_ROTATE           (APP_MESSAGE + 4)
+#define SAGE_EVT_ANALOG3          (APP_MESSAGE + 5)
+#define SAGE_EVT_ZOOM             (APP_MESSAGE + 5)
+#define SAGE_EVT_ARROW            (APP_MESSAGE + 6)
+#define SAGE_EVT_KEY              (APP_MESSAGE + 7)
+
+//aliases
+#define EVT_CLICK            SAGE_EVT_CLICK
+#define EVT_DOUBLE_CLICK     SAGE_EVT_DOUBLE_CLICK
+#define EVT_MOVE             SAGE_EVT_MOVE
+#define EVT_ANALOG1          SAGE_EVT_ANALOG1
+#define EVT_PAN              SAGE_EVT_PAN
+#define EVT_ANALOG2          SAGE_EVT_ANALOG2
+#define EVT_ROTATE           SAGE_EVT_ROTATE
+#define EVT_ANALOG3          SAGE_EVT_ANALOG3
+#define EVT_ZOOM             SAGE_EVT_ZOOM
+#define EVT_ARROW            SAGE_EVT_ARROW
+#define EVT_KEY              SAGE_EVT_KEY
+
+// FSM to APP
+#define APP_QUIT             APP_MESSAGE + 2000
+#define APP_REFRESH_FRAME    APP_MESSAGE + 2001
+
+#if defined(WIN32)
+// Conversion from 'size_t' to 'int'
+#pragma warning (disable: 4267)  //disable warning 4267
+// Nonstandard extension used : zero-sized array in struct/union
+#pragma warning (disable: 4200)  //disable warning 4267
+#endif
+
+#endif
Index: trunk/src/testing/include/sageVirtualDesktop.h
===================================================================
--- trunk/src/testing/include/sageVirtualDesktop.h	(revision 4)
+++ trunk/src/testing/include/sageVirtualDesktop.h	(revision 4)
@@ -0,0 +1,106 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageVirtualDesktop.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_VIRTUAL_DESKTOP_H
+#define _SAGE_VIRTUAL_DESKTOP_H
+
+#include "sage.h"
+#include "tileConfig.h"
+
+class streamInfo;
+class streamGroup;
+class fsManager;
+class appInExec;
+
+class sageVirtualDesktop : public virtualDesktop {
+public:   
+   std::vector<int> tileNodeList;   // nodeIDs of display nodes
+   std::vector<int> clientList;      // clientIDs of display nodes
+
+   std::vector<int> audioNodeList;         // nodeIDs of audio nodes
+   std::vector<int> audioClientList;       // clientIDs of audio nodes
+
+   fsManager *fsm;
+
+   sageVirtualDesktop(fsManager *f, int id);
+   ~sageVirtualDesktop();
+   int generateStreamInfo(streamGroup &sGrp, std::vector<int> &rcvList, int offset = 0);
+
+   /**
+    * launches the binary sageDisplayManager
+    */
+   int launchReceivers(char *fsIP, int port, int syncPort, bool globalSync = true, int syncBarrierPort=11001, int refreshInterval=60, int syncMasterPollingInterval=1000, int syncLevel=2 );
+
+   /**
+    * launches the binary sageAudioManager
+    */
+   int launchAudioReceivers(char *fsIP, int port, int syncPort);
+   
+   int getRcvId(int nodeId);
+   int getNodeNum() { return displayCluster.size(); }
+   int getTileNum() { return tileList.size(); }
+   int getNodeId(int tileId) { return tileList[tileId]->nodeID; }
+   int getNodeIPs(int nodeId, char *ipStr);
+   int getForwardIP(int nodeId, char *ipStr);
+   
+   int getRcvInfo(int nodeID, char *info);
+   int regRcv(int cId, int nodeID);
+   int getLocalPort(int nodeID);
+   int getForwardPort(int nodeID);
+
+   int getAudioRcvId(int nodeId);
+   int getAudioRcvInfo(int nodeId, char *info);
+   int regAudioRcv(int cId, int nodeId);
+   int getAudioNodeIPs(int nodeId, char *ipStr);
+   int generateAudioStreamInfo(streamGroup &sGrp, std::vector<int> &rcvList);
+   int generateAudioRcvInfo(int port, char* msgStr);
+   int generateAudioRcvInfo(char* ip, int port, char* msgStr);
+
+   std::vector<int> getRcvClientList() { return clientList; }
+   std::vector<int> getAudioRcvClientList() { return audioClientList; }
+   int changeBGColor(int red, int green, int blue);
+   int sendToAll(int code, char *data);
+   int convertYaxis(int y) { return height - y; }   
+   bool checkLayout(appInExec* app);
+   void checkNeighbors(appInExec *app, int edge);
+};   
+
+#endif
+
Index: trunk/src/testing/include/appleMultiContext.h
===================================================================
--- trunk/src/testing/include/appleMultiContext.h	(revision 4)
+++ trunk/src/testing/include/appleMultiContext.h	(revision 4)
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: appleMultiContext.h
+ * Author : Luc Renambot, Byungil Jeong
+ *
+ *   Description:   This is the header file for the video display module of SAGE. 
+ *
+ *   Notes   :    Since the display window may receive its many pieces from many servers, we need to pass multiple buffers
+ *         to this class. Each of the buffers passed contains a frame which forms a part (or whole) of the image on
+ *         the display side.
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+***************************************************************************************************************************/
+
+#ifndef APPLE_MULTI_CONTEXT_H
+#define APPLE_MULTI_CONTEXT_H
+
+#if defined(__APPLE__)
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/gl.h>   // Header File For The OpenGL Library
+#include <OpenGL/glu.h>   // Header File For The GLu Library
+#include <OpenGL/OpenGL.h>
+#include <AGL/agl.h>
+
+#include "displayContext.h"
+
+///////////////////////////
+// Define a playback window
+class Window {
+
+public:
+
+   Window(const Rect & rect, int fulls);
+
+   ~Window() {
+      aglDestroyContext(m_ctx);
+      DisposeWindow(m_win);
+   }
+
+   void clear() {
+      aglSetCurrentContext(m_ctx);
+
+      glClearColor(0,0,0,1);
+      glClear(GL_COLOR_BUFFER_BIT);
+
+      glFlush();
+
+      aglSwapBuffers(m_ctx);
+   }
+
+   void clearOpenGLData() {
+      m_init = false;
+   }
+
+   WindowRef theWindow() {
+      return m_win;
+   }
+
+   void beginGL() {
+      aglSetCurrentContext(m_ctx);
+      glClear(GL_COLOR_BUFFER_BIT);
+   }
+
+   void endGL() {
+      glFlush();
+      aglSwapBuffers(m_ctx);
+   }
+  
+   void contextSwitching() {
+      aglSetCurrentContext(m_ctx);
+   }
+
+protected:
+
+   // Carbon API window reference:
+   WindowRef m_win;
+
+   // Window geometry:
+   Rect m_rect;
+
+   // OpenGL context:
+   AGLContext m_ctx;
+
+   // OpenGL data:
+   bool m_init;
+};
+
+class appleMultiContext : public displayContext {
+protected:
+   Window *windows[MAX_TILES_PER_NODE];
+   
+public:
+   int init(struct sageDisplayConfig &cfg);   
+   void clearScreen() {}
+   void setupViewport(int i, sageRect &tileRect);
+   void refreshTile(int i) { windows[i]->endGL(); }
+   void refreshScreen() {}
+   void changeBackground(int red, int green, int blue);
+   void switchContext(int i) { windows[i]->contextSwitching(); }
+   void checkEvent();
+};
+
+#endif
+
+#endif
Index: trunk/src/testing/include/sageEvent.h
===================================================================
--- trunk/src/testing/include/sageEvent.h	(revision 4)
+++ trunk/src/testing/include/sageEvent.h	(revision 4)
@@ -0,0 +1,136 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageEvent.h
+ * Author : Byungil Jeong
+ *
+ *   Description: Queue for event driven control in a SAGE component
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+#ifndef _SAGE_EVENT_H
+#define _SAGE_EVENT_H
+
+#include "sageBase.h"
+#include <queue>
+
+#define SAGE_EVENT_SIZE 1280
+
+#define EVENT_NEW_MESSAGE    100
+#define EVENT_NEW_CONNECTION 101
+#define EVENT_READ_BLOCK     102
+#define EVENT_REFRESH_SCREEN 103
+#define EVENT_SYNC_MESSAGE   104
+#define EVENT_APP_CONNECTED  105
+#define EVENT_AUDIO_CONNECTION 106
+
+#define EVENT_SLAVE_PERF_INFO  200
+#define EVENT_MASTER_PERF_INFO 201
+#define EVENT_APP_SHUTDOWN     202
+#define EVENT_BRIDGE_SHUTDOWN  203
+
+/**
+ * sageEvent
+ */
+class sageEvent {
+public:
+   int eventType;
+   char eventMsg[SAGE_EVENT_SIZE];
+   void *param;
+
+
+	/**
+	 * size of the event message.
+	 * this is updated when eventMsg is allocated or copied by user
+	 */
+	int buflen;
+
+   sageEvent() : eventType(0), param(NULL), buflen(0) {}
+   sageEvent(int type, char* msg, void *p = NULL);
+
+   void setMsg(char *msg) { if (msg) strcpy(eventMsg, msg); }
+};
+
+/**
+ * sageSyncEvent
+ * by sungwon
+ * With no MAX_INST_NUM fix from Hyejung, sync algorithm can't use array
+ * However, there must be upper bound for the number of application instances that can exist simultaneously.
+ * Otherwise, there's no way to determine the size of the sync msg (in the 1st phase of syncMaster).
+ * So, this is temporary fix to increase the msg size a little bit more.
+ * Or this class can be used more cleverly.
+ */
+class sageSyncEvent : public sageEvent {
+	public:
+	//char eventMsg[SAGE_SYNC_MSG_LEN]; /**< overrides sageEvent::eventMsg[] */
+	char *eventMsg;
+
+	/**
+	 * sets buflen
+	 * returns the size of message
+	 * -1 on error
+	 */
+	int setMsg(char *msg);
+
+	sageSyncEvent() : eventMsg(NULL) {}
+	sageSyncEvent(int type, int bl, void *p=NULL);
+};
+
+/**
+ * sageEventQueue
+ */
+class sageEventQueue {
+protected:
+   std::deque<sageEvent*> eventQueue;
+
+   pthread_mutex_t *queueLock;
+   pthread_cond_t *notEmpty;
+
+   bool empty;
+
+public:
+   sageEventQueue();
+
+   sageEvent* getEvent();  // get event from the queue
+   void appendEvent(sageEvent* event);
+   void appendEvent(int type, char *msg = NULL, void *param = NULL);
+   void appendEvent(int type, int info, void *param = NULL);
+   void prependEvent(sageEvent* event);
+
+   bool isEmpty()  { return (eventQueue.size() == 0); }
+   ~sageEventQueue();
+};
+
+#endif
Index: trunk/src/testing/include/sageBlockPool.h
===================================================================
--- trunk/src/testing/include/sageBlockPool.h	(revision 4)
+++ trunk/src/testing/include/sageBlockPool.h	(revision 4)
@@ -0,0 +1,209 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageBlockPool.h
+ * Author : Byungil Jeong
+ *
+ *	Description: Pool (block group and block buffer) of sage pixel blocks
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+#ifndef _SAGE_BLOCK_POOL_H
+#define _SAGE_BLOCK_POOL_H
+
+#include "sageBuf.h"
+
+#define MAX_READER_NUM 100
+
+class sagePixelBlock;
+class sageBlockGroup;
+
+/**
+ * sageBlockPool
+ */
+class sageBlockPool {
+protected:
+   bool memAlloc;
+
+public:
+	sageBlockPool()  {}
+	virtual bool isFull() = 0;
+	virtual bool pushBack(sagePixelBlock* block) = 0;
+	virtual int returnBG(sageBlockGroup* grp) = 0;
+	virtual int returnBlocks(sageBlockGroup* grp) = 0;
+	virtual int returnBlock(sagePixelBlock* block) = 0;
+   virtual bool garbageCollection() { return false; }
+};
+
+// group options
+#define GRP_MEM_ALLOC    1
+#define GRP_CIRCULAR     2
+#define GRP_MULTI_READER 4
+#define GRP_USE_IOV      8
+
+#define GROUP_HEADER_SIZE 32
+
+/**
+ * class sageBlockGroup can have many sageBlock objects
+ */
+class sageBlockGroup : public sageBlockPool {
+protected:
+   sageBuf *buf;
+   int flag;
+   int blockSize, frameSize;
+   int frameID;
+   int configID;
+   int refCnt;
+   int deRefCnt;
+   char header[GROUP_HEADER_SIZE];
+
+   int blockNum;
+
+#ifdef WIN32
+   WSABUF *iovs;
+#else
+   struct iovec *iovs;
+#endif
+
+public:
+   static const int PIXEL_DATA;
+   static const int CONFIG_UPDATE;
+   static const int END_FRAME;
+
+   sageBlockGroup() : buf(NULL), iovs(NULL), frameID(0), flag(sageBlockGroup::END_FRAME),
+         blockNum(0), refCnt(0), deRefCnt(0), frameSize(0) {}
+   sageBlockGroup(int blkSize, int grpSize, char opt);
+   bool pushBack(sagePixelBlock* block);
+   sagePixelBlock* front();
+   bool next();
+   void resetGrp();
+   void resetIdx();
+   bool isEmpty();
+
+   bool isFull();
+   int returnBG(sageBlockGroup* grp) { return returnBlocks(grp); }
+   int returnBlocks(sageBlockGroup* grp);
+	int returnBlock(sagePixelBlock *block);
+
+   int size();
+   int getBlockNum();
+   sagePixelBlock* operator[] (int idx);
+
+   inline int getDataSize() { return blockSize*getBlockNum(); }
+   inline int getFlag()     { return flag; }
+   inline void setFlag(int f)    { flag = f; }
+   inline int getConfigID() { return configID; }
+   inline void setConfigID(int id) { configID = id; }
+   inline int getFrameID()  { return frameID; }
+   inline void setFrameID(int id) { frameID = id; }
+   inline void reference(int cnt) { refCnt += cnt; }
+   inline int dereference() { deRefCnt++; return (refCnt - deRefCnt); }
+   inline int getRefCnt() { return (refCnt - deRefCnt); }
+   inline void setFrameSize(int size) { frameSize = size; }
+   inline int getFrameSize() { return frameSize; }
+
+   void clearBlocks();
+   bool updateConfig();
+   bool updateConfig(int num, int frame, int config);
+   bool genIOV();
+   bool setRefCnt();
+
+   //bool dereferenceAll();
+   int sendData(int sockFd);
+   int readData(int sockFd);
+   int sendDatagram(int sockFd);
+   int readDatagram(int sockFd);
+   void clear();
+   ~sageBlockGroup();
+};
+
+// buffer options
+#define BUF_MEM_ALLOC     1
+#define BUF_MULTI_READER  2
+#define BUF_BLOCKING_READ 4
+#define BUF_CTRL_GROUP    8
+#define INTERVAL_EVAL_COUNT 100
+
+/**
+ * sageBlockBuf can have many sageBlockGroup
+ */
+class sageBlockBuf : public sageBlockPool {
+protected:
+   sageBuf *buf;
+   sageCircBufSingle *dataPool;
+   sageRAB *vacantPool;
+   sageCircBufSingle *ctrlPool;
+   bool waitingData;
+   bool multiReader;
+   double frameInterval;
+
+   sageTimer frameTimer;
+   sageCounter frameCounter;
+   bool firstGroup;
+
+   int findNextFrame(int id);
+
+public:
+   sageBlockBuf(int bufSize, int grpSize, int blkSize, char opt);
+   int entryNum() { return buf->getEntryNum(); }
+   sageBlockGroup* getFreeBlocks();
+   sageBlockGroup* getCtrlGroup(int flag);
+   sageBlockGroup* front(int id = 0, int minFrame = 0);
+   bool next(int id = 0);
+   inline bool isEmpty() { return buf->isEmpty(); }
+   bool pushBack(sageBlockGroup* grp);
+   bool pushBack(sagePixelBlock* block) { return false; };
+
+   bool finishFrame();
+   int returnBG(sageBlockGroup* grp);
+   int returnBlocks(sageBlockGroup* grp);
+	int returnBlock(sagePixelBlock *block);
+
+   bool isFull() { return false; }
+   void getBufInfo(char *bufStatus);
+
+   inline bool isWaitingData() { return waitingData; }
+
+   int addReader(int id);
+   inline void removeReader(int id) { ((sageCircBufMulti *)buf)->removeReader(id); }
+   bool clear(sageBuf *groupBuf);
+   void releaseLock();
+
+   double getFrameInterval() { return frameInterval; }
+
+   ~sageBlockBuf();
+};
+
+#endif
Index: trunk/src/testing/include/audioFileReader.h
===================================================================
--- trunk/src/testing/include/audioFileReader.h	(revision 4)
+++ trunk/src/testing/include/audioFileReader.h	(revision 4)
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: audioFileReader.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _AUDIO_FILE_READER_H
+#define _AUDIO_FILE_READER_H
+
+#include "sageAudioCircBuf.h"
+#include "audioConverter.h"
+#include "audioFormatManager.h"
+
+class sageAudioConfig;
+
+class audioFileReader {
+public:
+   audioFileReader(audioFormatManager* fm);
+   ~audioFileReader();
+   void init();
+   
+   sageAudioCircBuf* load(char* filename, bool loop, int nframes, long totalframes);
+   
+   int start();
+   int stop();
+
+   static void* readThread(void *args);
+   
+private:
+   sageAudioCircBuf* buffer;
+   
+   audioConverter* converter;
+   audioFormatManager* formatManager;   
+
+   int framePerBuffer;
+   int channels;
+   int bytesPerSample;
+   sageSampleFmt sampleFmt;
+   float gapTime;
+      
+   char* fileName;
+   
+   FILE* fileID;
+   
+   long totalLoadedFrames;
+   long totalBlocks;
+   
+   bool startFlag;
+   bool loopFlag;
+}; 
+
+#endif
Index: trunk/src/testing/include/sageDrawObject.h
===================================================================
--- trunk/src/testing/include/sageDrawObject.h	(revision 4)
+++ trunk/src/testing/include/sageDrawObject.h	(revision 4)
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDrawObject.h
+ * Author : Byungil Jeong
+ *
+ *   Description: the super class of simple drawing objects 
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+*********************************************************************************/
+
+#ifndef SAGE_DRAW_OBJECT_H
+#define SAGE_DRAW_OBJECT_H
+
+#include "sageBase.h"
+
+#if defined(__APPLE__)
+#include <OpenGL/gl.h>   // Header File For The OpenGL Library
+#include <OpenGL/glu.h>   // Header File For The GLu Library
+#include <OpenGL/OpenGL.h>
+
+#else
+#include <GL/gl.h>   // Header File For The OpenGL Library
+#include <GL/glu.h>   // Header File For The GLu Library
+#endif
+
+class sageDrawObject : public sageRect {
+protected:
+   char objName[SAGE_NAME_LEN];
+   int objectID;
+   bool global;
+   sageRect tileRect;
+
+   int setGlobalView();
+   int setLocalView();
+      
+public:
+   int displayID;
+   bool visible;
+   sageDrawObject() : objectID(0), displayID(0), global(true), visible(true) {}
+   void setName(char *name);
+   char *getName() { return objName; }
+   int getID() { return objectID; }
+   void init(int id, char *name, sageRect &layout, bool g, int dispId);   
+   void updatePosition(int nx, int ny) { x = nx; y = ny; }
+   int setViewport(sageRect &rect);
+   void showObject(bool doShow);
+   
+   virtual int init(char *name) = 0;   
+   virtual int draw() = 0;   
+   virtual int destroy() = 0;
+   virtual int parseMessage(char *msg) = 0;
+};
+
+#endif
Index: trunk/src/testing/include/sageVersion.h
===================================================================
--- trunk/src/testing/include/sageVersion.h	(revision 4)
+++ trunk/src/testing/include/sageVersion.h	(revision 4)
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sail.h
+ * Author : Luc Renambot
+ *
+ * Copyright (C) 2010 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to admin@sagecommons.org or 
+ * http://www.sagecommons.org
+ *
+ * $Rev:: 158                                                                 $
+ * $Author:: renambot                                                         $
+ * $Date:: 2010-03-26 07:19:46 +0100 (piÄ
+)                                   $
+ *****************************************************************************/
+
+#ifndef SAGEVERSION_H_
+#define SAGEVERSION_H_
+
+
+// This is the main version number
+#define SAGE_BASE_VERSION 3.2
+
+// Utility macros to join and convert to string some values
+#define SAGE_STR(XX) #XX
+#define SAGE_XSTR(XX) SAGE_STR(XX)
+#define SAGE_JOIN(XX, YY) SAGE_JOIN_AGAIN(XX, YY)
+#define SAGE_JOIN_AGAIN(XX, YY) XX ## . ## YY
+
+#if defined(SAGE_REVISION)
+	// If there's a revision number from SVN,
+	// we add it to the base version number
+#define SAGE_VERSION SAGE_XSTR(SAGE_JOIN(SAGE_BASE_VERSION, SAGE_REVISION))
+
+#else
+	// Just make it a string
+#define SAGE_VERSION SAGE_XSTR( SAGE_BASE_VERSION )
+
+#endif
+
+
+#endif
+
Index: trunk/src/testing/include/wavConverter.h
===================================================================
--- trunk/src/testing/include/wavConverter.h	(revision 4)
+++ trunk/src/testing/include/wavConverter.h	(revision 4)
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: wavConverter.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef WAV_CONVERTER_H
+#define WAV_CONVERTER_H
+
+#include "audioConverter.h"
+
+class wavConverter : public audioConverter 
+{
+public:
+   wavConverter();
+   virtual ~wavConverter();
+
+   virtual int readHeader(int& nchan, long& samrate, int& nframes, sageSampleFmt& fmt);
+   virtual int writeHeader(int nchan, long samrate, int nframes, int bits);   
+      
+   /** Reads and returns at most n frames of audio, as a string of bytes */
+   virtual int readFrames(void* frames);
+
+   /** Write n frames of audio, as a string of bytes */
+   virtual int writeFrames(void* frames);
+   
+   /** ewind the file pointer to the beginning of the audio stream */ 
+   virtual void begin();
+   
+   virtual void close();   
+
+protected:
+
+}; 
+
+#endif
Index: trunk/src/testing/include/sageAudioReceiver.h
===================================================================
--- trunk/src/testing/include/sageAudioReceiver.h	(revision 4)
+++ trunk/src/testing/include/sageAudioReceiver.h	(revision 4)
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioReceiver.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGEAUDIORECEIVER_H_
+#define SAGEAUDIORECEIVER_H_
+
+#include "sageReceiver.h"
+#include "sageBlock.h"
+
+class sageAudioCircBuf;
+class sageEventQueue;
+
+/**
+ * \brief instantiated by initStream message in sageAudioManager
+ */
+class sageAudioReceiver : public sageReceiver {
+protected:
+
+   int bytesPerSample;
+   sageAudioBlock audioNBlock;
+   sageAudioCircBuf* buffer; /**< sageAudioCircBuf */
+
+   int syncFrame; /**< sync frame number */
+
+   sageEventQueue *eventQueue;
+   sageSampleFmt sampleFmt;
+	streamData *streamList; /**< list of streams */
+	int streamIdx;
+
+   int oldFrame;
+   int updateFrame;
+   int reportRate;
+   sageTimer perfTimer;
+   unsigned long bandWidth;
+   unsigned packetLoss;
+
+   bool activeRecv;
+   bool masterFlag;
+   bool resetFlag;
+   int  m_senderID;
+
+public:
+	/**
+	 * starts sageReceiver::nwReadThread()<BR>
+	 * sageReceiver::readData() is pure virtual, so it should be overriden here.<BR>
+	 * sageReceiver::nwReadThread() is just calling sageReceiver::readData().
+	 */
+   virtual int addStream(int senderID);
+
+   sageAudioReceiver(char *msg, sageEventQueue *queue, streamProtocol *obj, sageAudioCircBuf *buff);
+   //virtual int readAudioData(int senderID);
+   //virtual int readData(int senderID, sageBlockQueue *queue);
+
+   /**
+    * It defines function body of sageReceiver::readData() which is pure virtual
+    */
+   virtual int readData();
+   virtual ~sageAudioReceiver() {}
+
+   /**
+    * just sets sageAudioReceiver::syncFrame = frame
+    */
+   virtual void processSync(int frame);
+
+public:
+   int getInstID();
+   int getSenderID();
+   bool isActive();
+   int getAudioId();
+   void setMaster(bool flag);
+   bool isMaster(void);
+
+   void setResetFlag(void);
+   int evalPerformance(char **frameStr, char **bandStr);
+   inline void setReportRate(int rate) { reportRate = rate; }
+   inline void resetTimer() { perfTimer.reset(); }
+   inline void resetBandWidth() { bandWidth = 0; }
+   inline void resetFrame() { oldFrame = updateFrame; }
+
+};
+
+inline int sageAudioReceiver::getInstID()
+{
+   return instID;
+}
+
+inline int sageAudioReceiver::getSenderID()
+{
+   return m_senderID;
+}
+
+#endif
Index: trunk/src/testing/include/sail.h
===================================================================
--- trunk/src/testing/include/sail.h	(revision 4)
+++ trunk/src/testing/include/sail.h	(revision 4)
@@ -0,0 +1,205 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sail.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAIL_H_
+#define SAIL_H_
+
+#include "sageConfig.h"
+
+#ifndef GL_ABGR_EXT
+   #  define GL_ABGR_EXT 0x8000
+#endif
+#ifndef GL_BGR
+   #  define GL_BGR 0x80E0
+#endif
+#ifndef GL_BGRA
+   #  define GL_BGRA 0x80E1
+#endif
+
+
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+   #  define GL_UNSIGNED_SHORT_5_6_5      0x8363
+#endif
+
+// awf: more (similar) defines for win32...
+#ifndef GL_UNSIGNED_SHORT_5_5_5_1   
+   #  define GL_UNSIGNED_SHORT_5_5_5_1      0x8034
+#endif
+#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
+   #  define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8066
+#endif
+
+#include "sagePixelType.h"
+
+class envInterface;
+class sageStreamer;
+class streamProtocol;
+class sageSyncServer;
+class sageSyncClient;
+class sageDoubleBuf;
+class syncGroup;
+#ifdef SAGE_AUDIO
+class sageAudioCircBuf;
+class sageAudioModule;
+class sageAppAudio;
+#endif
+
+/**
+ * \brief SAGE applicatoins communicate with the FSManager and stream pixels to SAGE receivers through SAIL
+ */
+class sail {
+private:   
+   envInterface    *envIntf;
+   sageStreamer    *pixelStreamer; /**< pixel streamer */
+   sageStreamer    *audioStreamer; /**< audio streamer */
+   sailConfig        config;
+   sagePixelType    pInfo;
+
+   bool             sailOn;
+   bool audioOn;            // audio on/off flag
+            
+   int bufSize;
+   int winID;
+   
+   std::deque<sageMessage> appMsgQueue;
+   
+   int bufID;
+   sageDoubleBuf *doubleBuf;
+
+#ifdef SAGE_AUDIO
+   sageAudioCircBuf* audioBuffer;
+   sageAudioModule* audioModule;
+   sageAppAudio* audioAppDataHander;
+#endif
+
+   int waitNodes;
+   int connectedNode;
+   bool connectionDone;
+   
+   int reconfigStep;
+   
+   //double reportTime;
+   sageTimer perfTimer;
+   double frameRate;
+   double bandWidth;
+   double totalBand;
+   int perfWait;
+   int reportRate;
+   double frameInterval;
+
+   pthread_mutex_t   *msgMutex;   
+   pthread_cond_t    *notEmpty;
+   sageSyncServer *syncServerObj; /**< sageSyncServer object for master node */
+   syncGroup *sGroup;
+
+   /**
+    * invoked by init() member function
+    *
+    * keeps calling readMessage(), sendPerformanceInfo(), and
+    * if config.master then also calling envIntf->checkClient(),
+    * and for each client, calls readClientMsg() followed by parseMessage()
+    *
+	*/
+
+   pthread_t msgThreadID;
+   static void* msgThread(void *args);
+
+   int checkSyncServer();
+   int generateSageBlocks();
+   
+public:
+   sail();
+   ~sail();
+
+   /**
+    * accepts sailConfig object and sets necessary parameters
+	* ready audioBuffer if SAGE_AUDIO
+	* creates pthreads mutex and condition variable.
+	* if it runs on the master node then creates sageSyncServer object.
+	* followed by sync related code
+	* followed by creation of sageBlockStreamer object
+	* followed by SAGE_AUDIO part
+	* finally pthread_create 'msgThread'
+	*
+	* @return 0 on success, -1 otherwise
+	*/
+   int init(sailConfig &conf);
+
+   /**
+    * getting message through envInf
+    */
+   int readMessage();
+   int sendMessage(sageMessage &msg);
+   int sendMessage(int code);
+   int sendMessage(int code, int data);
+   int sendMessage(int code, char *data);
+   int parseMessage(sageMessage &msg);   
+   int swapBuffer(int mode = SAGE_BLOCKING);
+#ifdef SAGE_AUDIO
+   /**
+    * calls audioAppDataHander->swapBuffer(size, buf);
+    */
+   int pushAudioData(int size, void *buf);
+#endif
+   
+   void* getBuffer();
+   int initPixelBlocks();
+   int streamPixelBlocks(int blockFrame);
+   int streamFBO();
+
+   //int resizeBuffer(int x, int y, int depth);
+   int getRowOrder() { return config.rowOrd; }
+   int getBufSize() { return bufSize; }
+   int checkMsg(sageMessage &msg, bool blocking);
+   int requestNewFrame();
+   int shutdown();
+   int sendPerformanceInfo();
+   
+   int initFrameBufferObject();  // initailize FBO of SAIL
+   int bindFrameBufferObject();  // bind the FBO of SAIL
+   int releaseFrameBufferObject();  // back to regular frame buffer
+   int transferFBO();      // transfer pixels written into FBO to SAGE
+   
+   inline bool isSailOn() { return sailOn; }
+   
+   friend class envInterface;
+};
+
+#endif
Index: trunk/src/testing/include/sdlSingleContext.h
===================================================================
--- trunk/src/testing/include/sdlSingleContext.h	(revision 4)
+++ trunk/src/testing/include/sdlSingleContext.h	(revision 4)
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sdlSingleContext.h
+ * Author : Byungil Jeong
+ *
+ *   Description:   This is the header file for the video display module of SAGE. 
+ *
+ *   Notes   :    Since the display window may receive its many pieces from many servers, we need to pass multiple buffers
+ *         to this class. Each of the buffers passed contains a frame which forms a part (or whole) of the image on
+ *         the display side.
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+***************************************************************************************************************************/
+
+#ifndef SDL_SINGLE_CONTEXT_H
+#define SDL_SINGLE_CONTEXT_H
+
+#include "displayContext.h"
+
+#if defined(__APPLE__)
+#include <OpenGL/gl.h>  // Header File For The OpenGL Library
+#include <OpenGL/glu.h> // Header File For The GLu Library
+#else
+#include <GL/gl.h>      // Header File For The OpenGL Library
+#include <GL/glu.h>     // Header File For The GLu Library
+#endif
+
+#ifdef sun
+#include <SDL.h>
+#elif defined(__APPLE__)
+#include <SDL.h>
+#else
+#include <SDL/SDL.h>
+#endif
+
+
+class sdlSingleContext : public displayContext {
+protected:
+   SDL_Surface *surface;
+   int window_width, window_height;
+
+public:
+   int init(struct sageDisplayConfig &cfg);   
+   void clearScreen();
+   void setupViewport(int i, sageRect &tileRect);
+   void refreshScreen();
+   void changeBackground(int red, int green, int blue);
+   ~sdlSingleContext();
+   void checkEvent();
+};
+
+#endif
Index: trunk/src/testing/include/sageFrame.h
===================================================================
--- trunk/src/testing/include/sageFrame.h	(revision 4)
+++ trunk/src/testing/include/sageFrame.h	(revision 4)
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageFrame.h - classes for storing and manipulating image frames
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_FRAME_H
+#define _SAGE_FRAME_H
+
+#include "sageBlock.h"
+
+class sageFrame;
+class sageBlockFrame;
+class sageBlockPartition;
+
+class sageSubFrame : public sagePixelData {
+public:
+   std::vector<int> blockList;
+   sageBlockFrame *mainFrame;
+   
+   int computeFrameRect();
+};
+
+class sageBlockFrame : public sagePixelData {
+protected:
+   sagePixelBlock *blocks;
+   int idx;
+   int numCol, numRow, subBlockNum;
+   int pixelSize; // Byte per pixel
+   int memWidth;
+   sageBlockPartition *partition;
+   
+public:
+   sageBlockFrame(int w, int h, int bytes, float compX = 1.0, float compY = 1.0);
+   
+   //inline void setBlockSize(int w, int h) { blockWidth = w, blockHeight = h; }
+   int initFrame(sageBlockPartition *part);
+   inline void resetBlockIndex() { idx = 0; }
+   bool extractPixelBlock(sagePixelBlock *block, int rowOrder);
+   
+   int generateBlocks(int rowOrd);
+   int generateSubFrame(sageRect &subRect, sageSubFrame &sFrame);
+   bool updateBlockConfig() { return false; }
+
+   /**
+    * override virtual function
+    */
+   int updateBufferHeader() { return 0; }
+
+   /**
+    * for sagenext, embed frame number
+    */
+   int updateBufferHeader(int fnum);
+
+   virtual ~sageBlockFrame();
+   
+   friend class sageSubFrame;
+};
+
+#endif
Index: trunk/src/testing/include/displayInstance.h
===================================================================
--- trunk/src/testing/include/displayInstance.h	(revision 4)
+++ trunk/src/testing/include/displayInstance.h	(revision 4)
@@ -0,0 +1,118 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: displayInstance.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef _DISPLAY_MANAGER_H
+#define _DISPLAY_MANAGER_H
+
+#include "sage.h"
+#include "sageConfig.h"
+
+class fsManager;
+class appInExec;
+class sageVirtualDesktop;
+class streamInfo;
+class connectionInfo;
+
+/**
+ * class displayInstance
+ */
+class displayInstance {
+public:
+   int winID;
+private:
+   fsManager *fsm;
+   appInExec *appExec;
+   sageVirtualDesktop *vdt;
+   
+   std::vector<int> receiverList;
+   streamGroup streamGrp;
+
+   int tileNum;
+   int dispNodeNum;
+   int streamNum;
+   int sailClient;
+   int zValue;
+   int rcvFlagCnt;
+   int syncMode;
+   int waitNodes;
+   int imageSize;
+   float rcvFrate, rcvBwidth, rcvLoss, accBwidth, accLoss;
+   float sendFrate;
+   int accFSize;
+
+   char winTitle[SAGE_NAME_LEN];
+   int borderColor[3];
+   int titleColor[3];
+      
+   bool *rcvFlag;
+
+   void reportPerformance(char *sailPerf);
+   int accumulateBandwidth(char *rcvBand);
+   void generateStreamInfo(void); 
+   int streamInfoToSender(void);   
+
+   int shutdownApp();
+   
+public:
+   displayInstance(fsManager *f, int id, appInExec* app);
+   ~displayInstance() {}
+   int getReceiverNum() { return receiverList.size(); }
+   int getReceiver(int i) { return receiverList[i]; }
+   int getStreamNum() { return streamNum; }
+   int getSailClient() { return sailClient; }
+   int parseMsg(sageMessage &msg);
+   int getWinID() { return winID; }
+   //int shutdownReceivers();
+   int changeWindow(sageRect &devRect, int steps);
+   int modifyStream(void);
+   int connectSenders(); /**< send messages to sail client */
+   int initStreams();
+   int getZValue() { return zValue; }
+   int setZValue(int z) { zValue = z; return 1;}
+   int increaseZ() { zValue++; return 1;}
+   int requestPerformanceInfo(int rate);
+   int stopPerformanceInfo();
+   int updateWinProp(char *info);
+   int updateBorders(char *title);
+   
+   friend class fsCore;
+};
+
+#endif
Index: trunk/src/testing/include/sageBlock.h
===================================================================
--- trunk/src/testing/include/sageBlock.h	(revision 4)
+++ trunk/src/testing/include/sageBlock.h	(revision 4)
@@ -0,0 +1,251 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlock.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_BLOCK_H
+#define _SAGE_BLOCK_H
+
+#include "sageRect.h"
+
+#define BLOCK_HEADER_SIZE 128
+
+#define SAGE_PIXEL_BLOCK   1
+#define SAGE_UPDATE_BLOCK  2
+
+//#define SAGE_BUFFER_BLOCK   2
+//#define SAGE_IOVEC_FRAME   3
+//#define SAGE_RLE_BLOCK      4
+#define SAGE_AUDIO_BLOCK  5
+
+#define SAGE_FRAME_BLOCK   100
+#define SAGE_STOP_BLOCK 101
+#define SAGE_TIME_BLOCK   102
+#define SAGE_ACK_BLOCK   103
+#define SAGE_SKIP_BLOCK 105
+#define SAGE_CLEAR_BLOCK 106
+
+/**
+ * sageBLock
+ */
+class sageBlock {
+protected:
+   char *buffer;
+   int bufSize;
+   int flag;      //   specify the function of block
+   int rcnt;
+   int blockID;
+
+public:
+   sageBlock() : flag(SAGE_PIXEL_BLOCK), buffer(NULL), bufSize(0), rcnt(0) {}
+
+   inline int getFlag() { return flag; }
+   inline void setFlag(int f) { flag = f; }
+   inline char *getBuffer() { return buffer; }
+   inline int getBufSize() { return bufSize; }
+   inline void setRefCnt(int cnt = 0) { rcnt = cnt; }
+   inline int getRefCnt() { return rcnt; }
+   inline int reference(int cnt = 1) { rcnt += cnt; return rcnt; }
+   inline int dereference(int cnt = 1) { rcnt -= cnt; return rcnt; }
+   inline void setID(int id) { blockID = id; }
+   inline int getID() { return blockID; }
+
+   virtual int updateBufferHeader() = 0;
+   virtual bool updateBlockConfig() = 0;
+   virtual int getFrameID() = 0;
+   virtual ~sageBlock() {}
+};
+
+/**
+ * sagePixelData
+ */
+class sagePixelData : public sageRect, public sageBlock {
+protected:
+   char *pixelData; // starting address of image buffer
+   int frameID;  // frame to which this block belongs
+   sagePixFmt pixelType;   // pixel format of block
+   int bytesPerPixel;
+   float compressX, compressY;
+
+   int initBuffer();
+   int releaseBuffer();
+   int allocateBuffer(int size);
+
+public:
+   sagePixelData() : pixelData(NULL), frameID(0), pixelType(PIXFMT_888),
+         bytesPerPixel(3), compressX(1.0), compressY(1.0) {}
+
+   virtual int getFrameID() { return frameID; }
+   void operator=(sageRect &rect);
+   inline void setFrameID(int id) { frameID = id; }
+   inline sagePixFmt getPixelType() { return pixelType; }
+   inline void setPixelType(sagePixFmt type) { pixelType = type; }
+   inline int getBytesPerPixel() { return bytesPerPixel; }
+   inline void setBytesPerPixel(int byte) { bytesPerPixel = byte; }
+   inline char *getPixelBuffer() { return pixelData; }
+};
+
+class sageBlockGroup;
+
+/**
+ * sagePixelBlock
+ *
+ * sageBlockGroup object has (grpSize/blockSize) of this sagePixelBlock object in its sageCircBufSingle
+ */
+class sagePixelBlock : public sagePixelData {
+protected:
+   bool valid, dirty;
+   sageBlockGroup *grp;
+	int configID;
+   int headerLen;
+
+public:
+   sagePixelBlock() : valid(true), grp(NULL), dirty(false), headerLen(0) {}
+   sagePixelBlock(int size);
+   sagePixelBlock(sagePixelBlock& block);
+   //sagePixelBlock(int w, int h, int bytes, float compX, float compY,
+   //   int frame, int confID);
+
+   inline sageBlockGroup* getGroup() { return grp; }
+   inline void setGroup(sageBlockGroup *parent) { grp = parent; }
+	inline void setConfigID(int id) { configID = id; }
+	inline int  getConfigID() { return configID; }
+   inline void clearHeader() { memset(buffer, 0, BLOCK_HEADER_SIZE); }
+   inline void clearBuffer() { memset(buffer, 0, bufSize); }
+   inline bool isDirty() { return dirty; }
+   inline void setDirty() { dirty = true; }
+   void clearPixelBlock();
+   int updateBufferHeader();
+   int updateHeader(int pid, int configID);
+   bool updateBlockConfig();
+
+   inline int getHeaderLen(){ return headerLen; }
+   inline bool isValid()    { return valid; }
+   inline void invalidate() { valid = false; }
+   inline void validate()   { valid = true; }
+
+   //void recalcBufSize();
+
+   virtual ~sagePixelBlock();
+};
+
+/**
+ * sageAudioBlock
+ */
+class sageAudioBlock : public sageBlock {
+protected:
+   int frameID;    // audio frame to which this block belongs
+   int gframeID;   // video frame to which this block belong
+
+   sageSampleFmt sampleFmt;   // sample format of block
+   int bytesPerSample;
+   int channels;
+   int framePerBuffer;
+   long sampleRate;
+   char* audioData;
+
+   char *extraInfo;
+   int tileID;
+   int nodeID;
+
+   int releaseBuffer();
+   int allocateBuffer(int size);
+
+public:
+   sageAudioBlock();
+   sageAudioBlock(int frame, sageSampleFmt type, int byte, int rate, int chan, int framesperbuffer);
+   virtual ~sageAudioBlock();
+
+   int initBuffer();
+   int initBuffer(int size);
+
+public:
+   int updateBufferHeader();
+   virtual bool updateBlockConfig();
+   virtual int getTileID() { return tileID; }
+
+   inline void setTileID(int id) { tileID = id; }
+   inline int getNodeID() { return nodeID; }
+   inline void setNodeID(int id) { nodeID = id; }
+
+   virtual int getFrameID() { return frameID; }
+   void operator=(sageAudioBlock &rect);
+   inline void setFrameID(int id) { frameID = id; }
+
+   virtual int getgFrameID() { return gframeID; }
+   inline void setgFrameID(int id) { gframeID = id; }
+
+   inline sageSampleFmt getSampleFormat() { return sampleFmt; }
+   inline void setSampleFormat(sageSampleFmt type) { sampleFmt = type; }
+
+   inline int getBytesPerSample() { return bytesPerSample; }
+   inline void setBytesPerSample(int byte) { bytesPerSample = byte; }
+
+   inline int getChannel() { return channels; }
+   inline void setChannel(int num) { channels = num; }
+
+   inline int getFramePerBuffer() { return framePerBuffer; }
+   inline void setFramePerBuffer(int num) { framePerBuffer = num; }
+
+   inline int getSampleRate() { return sampleRate; }
+   inline void setSampleRate(int rate) { sampleRate = rate; }
+
+   char *getExtraInfo() { return extraInfo; }
+
+   inline char *getAudioBuffer() { return audioData; }
+};
+
+
+/*
+class sageControlBlock : public sageBlock {
+protected:
+   int frameID;
+   char ctrlInfo[TOKEN_LEN];
+
+public:
+   sageControlBlock(int f, int frame, int size = 0);
+   virtual ~sageControlBlock();
+
+   int updateBufferHeader(char *info);
+   virtual int updateBlockConfig();
+   virtual int getFrameID() { return frameID; }
+   char *getControlInfo() { return ctrlInfo; }
+};
+*/
+
+#endif
Index: trunk/src/testing/include/misc.h
===================================================================
--- trunk/src/testing/include/misc.h	(revision 4)
+++ trunk/src/testing/include/misc.h	(revision 4)
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: misc.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef _MISC_H
+#define _MISC_H
+
+#define TOKEN_LEN 1024
+#define STRBUF_SIZE 1024
+#define MAX_TOKENS 10000
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#include "sageBase.h"
+
+int getToken(char *, char *);
+int getToken(char *, char *, char **);
+int getToken(FILE *, char *);
+int execRemBin(char *ip, char *com, char *xid = NULL);
+
+int getMax2n(int val);
+int getPixelSize(sagePixFmt type);
+
+long getnumber( char *str );
+
+#if defined(WIN32)
+int gettimeofday(struct timeval *, void *);
+
+#pragma warning( disable : 4244) // time_t and long mismatch
+#pragma warning( disable : 4267) // size_t and int mismatch
+#pragma warning( disable : 4018) // '<' : signed/unsigned mismatch
+#endif
+
+namespace sage {
+   void usleep(unsigned long usec);
+   unsigned int sleep(unsigned int seconds);
+   void switchThread();
+   int condition_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, time_t miliSec);
+   int toupper(char *str);
+   int tolower(char *str);
+   bool isDataReady(int sockFd, int sec = 0, int usec = 0);
+   int send(int fd, void *buf, int len);
+   int recv(int fd, void *buf, int len, int flags = 0);
+   void transformFrameNum(int blockFrame, int &curFrame);
+   char *tokenSeek(char *buf, int tnum); // return the string pointer from which (tnum+1)th token starts
+   void printLog(const char *format,...);
+   void initUtil();
+   double getTime();
+#if defined(WIN32)
+   void win32Init();
+#endif
+}
+
+class sageToken {
+private:
+   char *tokenBuf;
+   int idx;
+   int strLen;
+   
+public:
+   sageToken(char *str);
+   sageToken(int len);
+   ~sageToken();
+   
+   int getToken(char *token);
+   int putToken(char *token);
+   char* getBuffer() { return tokenBuf; }
+};
+
+class sageTimer {
+private:
+   //struct timespec startTime;
+   double startTime;
+   double accumulatedTime;
+   bool paused;
+public:
+   sageTimer() { reset(); }
+   void resume();
+   void reset();
+   void pausedReset();
+   void pause(); 
+   double getTimeUS(bool resetFlag = false);  // return elapsed time in micro second
+   double getTimeSec();  // return elapsed time in second
+};
+
+class sageCounter {
+private:
+   unsigned int count;
+   
+public:
+   sageCounter() : count(0) {}
+   void reset() { count = 0; }
+   unsigned int getValue() { return count; }
+   void operator++(int) { count++; }
+};
+
+class sageIndexTable {
+private:
+   int *table;
+   int minID, maxID;
+   std::vector<int> entries;
+      
+public:
+   sageIndexTable() : table(NULL), minID(0), maxID(0) { entries.clear(); }
+   void addEntry(int id) { entries.push_back(id); }
+   int generateTable();
+   int setTable(int id, int index);
+   int getIndex(int id);
+   int getID(int idx);
+   int size() { return entries.size(); }
+   ~sageIndexTable();   
+};
+
+// Inspired by NVIDIA Toolkit
+
+class data_path
+{
+public:
+  std::string              file_path;
+  std::string              path_name;
+  std::vector<std::string> path;
+
+  data_path(std::string subdir="");
+
+	// Finds and returns the directory (or NULL) to a given filename
+  std::string get_path(std::string filename);
+	// Finds and returns the complete path (or NULL) to a given filename
+  std::string get_file(std::string filename);
+
+	// Finds and opens a given filename
+  FILE *fopen(std::string filename, const char * mode = "rb");
+
+	// Prints the list of directories in the search list
+  void print();
+
+#ifdef WIN32
+  int fstat(std::string filename, struct _stat * stat);
+#else
+  int fstat(std::string filename, struct stat * stat);
+#endif
+};
+
+
+#endif
Index: trunk/src/testing/include/sageTcpModule.h
===================================================================
--- trunk/src/testing/include/sageTcpModule.h	(revision 4)
+++ trunk/src/testing/include/sageTcpModule.h	(revision 4)
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageTcpModule.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ * Description:   This is the header file the TCP code used for trasmitting graphics.
+ *                The template for the interface is given by the streamProtocol class.
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _SAGE_TCP_MODULE_H
+#define _SAGE_TCP_MODULE_H
+
+#include "streamProtocol.h"
+
+class sageBlockFrame;
+
+/**
+ * sageTcpModule
+ */
+class sageTcpModule : public streamProtocol{
+private:
+   int serverSockFd;
+   struct sockaddr_in localAddr, clientAddr, serverAddr;
+   int setSockOpts(int);
+   sageBlockPool *returnPlace;
+   std::vector<sageBlockGroup*> bufList;
+
+public:
+   sageTcpModule();
+   int init(sageStreamMode m, int p, sageNwConfig &c);
+   int checkConnections(char *msg = NULL, sageApiOption op = 0);
+   int connect(char* ip, char *msg = NULL);
+   int send(int id, sageBlock *sb, sageApiOption op);
+
+   /**
+    * sungwon experimental, swexp
+    */
+   int sendpixelonly(int id, sageBlockFrame *sb);
+
+   int recv(int id, sageBlock *sb, sageApiOption op);
+   int sendControl(int id, int frameID, int configID);
+   int sendGrp(int id, sagePixelBlock *sb, int configID);
+
+   /**
+    * class sageBlockGroup::readData() followed by sageBlockGroup::updateConfig()
+    */
+   int recvGrp(int id, sageBlockGroup *sbg);
+   int flush(int id, int configID);
+   int getRcvSockFd(int id) { return sendList[id]; }
+
+   void setupBlockPool(sageBlockPool *pool, int id = -1) { returnPlace = pool; }
+   void setFrameSize(int id, int size) {}
+   void resetFrameSize(int id) {}
+   void setFrameRate(double rate, int id = -1) {}
+
+   int close();
+   virtual ~sageTcpModule();
+};
+
+#endif
Index: trunk/src/testing/include/sageAudioManager.h
===================================================================
--- trunk/src/testing/include/sageAudioManager.h	(revision 4)
+++ trunk/src/testing/include/sageAudioManager.h	(revision 4)
@@ -0,0 +1,141 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioManager.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_AUDIO_MANAGER_H_
+#define _SAGE_AUDIO_MANAGER_H_
+
+#include "fsClient.h"
+#include "streamProtocol.h"
+#include "sageAudioModule.h"
+
+class sageAudioManager;
+class sageEvent;
+class sageAudioReceiver;
+class sageTcpModule;
+class sageUdpModule;
+class sageEventQueue;
+class sageSyncClient;
+
+typedef struct {
+   sageAudioManager *This;
+   streamProtocol     *nwObj;
+} nwCheckThreadParam;
+
+/**
+ * \brief The binary of this class is executed by sageVirtualDesktop.launchAudioReceiver()
+ *
+ * This class is very similar to the class sageDisplayManager
+ */
+class sageAudioManager : public fsClient {
+private:
+   int nodeID;
+   sageTcpModule *tcpObj; /**< TCP module */
+   sageUdpModule *udpObj; /**< UDP module */
+   sageNwConfig nwCfg;
+   sageEventQueue *eventQueue; /**< event queue. continuously checked in the mainLoop() */
+   sageSyncClient *syncClientObj; /**< sageSyncClient object*/
+
+   sageAudioModule *audioModule; /**< sageAudioModule */
+   sageAudioConfig audioCfg;
+
+
+   std::vector<sageAudioReceiver *> receiverList; /**< a list of sageAudioReceiver object. It responsible for receiving streams from sageAudioStreamer */
+
+   int syncPort, streamPort;
+   int totalRcvNum;
+   int memSize;
+   bool rcvEnd;
+
+   /**
+    * handles below events <BR>
+    * EVENT_NEW_CONNECTION -> initStreams()<BR>
+    * EVENT_NEW_MESSAGE -> parseMessage()<BR>
+    * EVENT_SYNC_MESSAGE -> processSync()
+    */
+   int parseEvent(sageEvent *event);
+   int parseMessage(sageMessage *msg);
+   int perfReport();
+   int startPerformanceReport(sageMessage *msg);
+   int stopPerformanceReport(sageMessage *msg);
+   int shutdownApp(int appId);
+
+   /**
+    * sets tcpObj, udpObj and starts nwCheckThread() for each protocol
+    */
+   int initNetworks();
+
+   /**
+    * This function is called when EVENT_NEW_CONNECTION arrives<BR>
+    * sageAudioCircBuffer is created and passed to sageAudioReceiver::sageAudioReceiver<BR>
+    * sageAudioReceiver::addStream() is called for each element in the receiverList.<BR>
+    * The first receiver object becomes Master
+    *
+    */
+   int initStreams(char *msg, streamProtocol *nwObj);
+
+   /**
+    * calls sageAudioReceiver.processSync() for each element in the receiverList
+    */
+   int processSync(char *msg);
+   int checkConnection();
+
+   static void* nwCheckThread(void *args); /**< keeps checking connection, if one has found, then generates EVENT_NEW_CONNECTION */
+   static void* msgCheckThread(void *args); /**< receives new message and generates EVENT_NEW_MESSAGE */
+   static void* syncCheckThread(void *args); /**< calls sageSyncClient::waitForSync() then generates EVENT_SYNC_MESSAGE */
+   static void* perfReportThread(void *args);
+   static void* refreshThread(void *args);
+
+public:
+   sageAudioManager(int argc, char **argv);
+   ~sageAudioManager();
+
+   /**
+    * creates sageAudioModule object and sageSyncClient object. calls sageSyncClient::connectToServer()<BR>
+    * starts syncCheckThread() and refreshThread()
+    */
+   int init(char *msg);
+
+   /**
+    * keeps getting new event from the eventQueue then calls parseEvent()
+    */
+   void mainLoop();
+};
+
+#endif
Index: trunk/src/testing/include/sageBridge.h
===================================================================
--- trunk/src/testing/include/sageBridge.h	(revision 4)
+++ trunk/src/testing/include/sageBridge.h	(revision 4)
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBridge.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef SAGEBRIDGE_H_
+#define SAGEBRIDGE_H_
+
+#include "sage.h"
+
+#define MAX_BRIDGE_NODE 100
+
+class messageInterface;
+class sageBridge;
+class streamProtocol;
+class bridgeSharedData;
+class sageTcpModule;
+class sageUdpModule;
+class sageNwConfig;
+class appInstance;
+class sageSyncServer;
+class syncGroup;
+class sageEvent;
+class sageAudioBridge;
+
+
+typedef struct {
+   sageBridge     *This;
+   streamProtocol *nwObj;
+} nwCheckThreadParam;
+
+class sageBridge {
+protected:
+   bridgeSharedData *shared;
+   sageTcpModule *tcpObj;
+   sageUdpModule *udpObj;
+   sageNwConfig *nwCfg;
+   sageAudioBridge *audioBridge;
+
+   bool master;
+   char masterIP[SAGE_IP_LEN];
+   int streamPort, msgPort, syncPort, audioPort;
+   int slaveNum;
+   int memSize;
+   int allocPolicy;
+   char slaveIPs[MAX_BRIDGE_NODE][SAGE_IP_LEN];
+   int slaveList[MAX_BRIDGE_NODE];
+   
+   messageInterface *msgInf;
+   std::vector<appInstance*> appInstList;
+   int instNum;
+   sageSyncServer *syncServerObj;   
+   //sageSyncClient *syncClientObj;
+
+   bool bridgeEnd;
+   int syncGroupID;
+   
+   int initMaster(const char *cFile);
+   int initSlave(char *data);
+   int launchSlaves();
+   int regApp(sageMessage &msg, int clientID);
+   int shareApp(char *msgData, int clientID);
+   int connectApp(appInstance *inst);
+   int sendStreamInfo(appInstance *inst);
+   
+	appInstance* findApp(int id, int& index);
+
+   int connectToFSManager(appInstance *inst);
+   int connectToFSManager(appInstance *inst, char *ip, int port);
+   syncGroup* addSyncGroup();
+   
+   appInstance* clientIDtoAppInstance(int clientID, int &orgIdx);
+   appInstance* forwardToAppinstance(sageMessage &msg, int clientID);
+   appInstance* findAppInstance(int instID);
+   appInstance* delieverMessage(sageMessage &msg, int clientID);
+   int parseMessage(sageMessage &msg, int clientID);
+   int parseEvent(sageEvent *event);
+
+   int findMinLoadNode();  
+   int startPerformanceReport(sageMessage &msg);
+   int stopPerformanceReport(sageMessage &msg);   
+   int perfReport();
+   int shutdownApp(int instID, bool fsmToApp);
+   int forwardToSail(int instID, sageMessage &msg);
+   int shutdownAllApps();
+
+   int initNetworks();
+   int checkNetworks();
+   int initStreams(char *msg, streamProtocol *nwObj);
+   
+   
+   static void* msgCheckThread(void *args);
+   static void* perfReportThread(void *args);
+   static void* nwCheckThread(void *args);
+   
+public:
+   sageBridge(int argc, char **argv);
+   ~sageBridge();
+   void mainLoop();
+   
+   friend class appInstance;
+};
+
+#endif
Index: trunk/src/testing/include/audioFileWriter.h
===================================================================
--- trunk/src/testing/include/audioFileWriter.h	(revision 4)
+++ trunk/src/testing/include/audioFileWriter.h	(revision 4)
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: audioFileWriter.h
+ * Author : Hyejung Hur
+ * 
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ ***************************************************************************************************************************/
+
+#ifndef _AUDIO_FILE_WRITER_H
+#define _AUDIO_FILE_WRITER_H
+
+#include "sageAudioCircBuf.h"
+#include "audioConverter.h"
+#include "audioFormatManager.h"
+
+class sageAudioConfig;
+
+class audioFileWriter {
+public:
+   audioFileWriter(audioFormatManager* fm);
+   ~audioFileWriter();
+   void init();
+   
+   int write(char* filename, sageAudioConfig &config, sageAudioCircBuf* buf);
+   
+   int start();
+   int stop();
+   
+   static void* writeThread(void *args);
+
+private:
+   sageAudioCircBuf* buffer;
+   audioConverter* converter;
+   audioFormatManager* formatManager;
+
+   long samplingRate;;
+   int framePerBuffer;
+   int channels;
+   int bytesPerSample;
+
+   char* fileName;
+   
+   FILE* fileID;
+   
+   bool startFlag;
+
+}; 
+
+#endif
Index: trunk/src/testing/include/sageReceiver.h
===================================================================
--- trunk/src/testing/include/sageReceiver.h	(revision 4)
+++ trunk/src/testing/include/sageReceiver.h	(revision 4)
@@ -0,0 +1,144 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageReceiver.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGERECEIVER_H_
+#define SAGERECEIVER_H_
+
+#include "sage.h"
+
+#define STREAM_ACTIVE   1
+#define STREAM_INACTIVE 2
+#define STREAM_WAITING  3
+
+class sageReceiver;
+class sageBlockQueue;
+class rcvSharedData;
+class streamProtocol;
+
+/**
+ * class sageReceiver
+ */
+class sageReceiver {
+protected:
+   int instID, senderNum, blockSize;
+   streamProtocol *nwObj;
+   bool endFlag;
+   pthread_t thId;
+
+   /**
+    * It just calls virtual member function readData()<BR>
+    *
+    * This thread is started in the sageAudioReceiver::addStream()<BR>
+    * sagePixelReciever's Constructor
+    * <BR>
+    * So, when a pixelDownloader is instantiated and initiated, sagePixelReceiver starts<BR>
+    * then this network thread starts.
+    *
+    */
+   static void* nwReadThread(void *args);
+   virtual int readData() = 0; /**< pure virtual member function */
+
+public:
+   sageReceiver() : endFlag(false) {}
+
+   int getInstID() { return instID; }
+   virtual int addStream(int senderID) = 0; /**< pure virtual member function */
+
+   int getSenderNum() {return senderNum;}
+};
+
+class sageBlockGroup;
+class sageBlockBuf;
+
+/**
+ * class streamData
+ */
+class streamData {
+public:
+   int senderID;
+   int dataSockFd;
+   int curFrame;
+   bool dataReady;
+   sageBlockGroup* bGroup;
+
+   streamData() : curFrame(0), bGroup(NULL), dataReady(false) {}
+};
+
+/**
+ * class sagePixelReceiver
+ */
+class sagePixelReceiver : public sageReceiver {
+protected:
+   rcvSharedData *shared;
+   sageBlockBuf *blockBuf;
+   streamData *streamList;
+   int streamIdx;
+   int groupSize;
+   int configID;
+
+   pthread_mutex_t streamLock;
+   pthread_cond_t  connectionDone;
+   bool connecting;
+   int curFrame;
+   fd_set streamFds;
+   int maxSockFd;
+
+   /**
+    * Receiving pixel data from an application<BR>
+    * Generates EVENT_READ_BLOCK
+    */
+   int readData();
+   int checkStreams();
+
+public:
+	/**
+	 * constructor starts nwReadThread of the super class<BR>
+	 * This thread just calls virtual function readData()
+	 */
+   sagePixelReceiver(char *msg, rcvSharedData *sh, streamProtocol *obj, sageBlockBuf *buf);
+
+   /**
+    * creates EVENT_APP_CONNECTED. This leads invoking fsClient::sendMessage() with the code DISP_APP_CONNECTED
+    */
+   int addStream(int senderID);
+   ~sagePixelReceiver();
+};
+
+#endif
Index: trunk/src/testing/include/appInstance.h
===================================================================
--- trunk/src/testing/include/appInstance.h	(revision 4)
+++ trunk/src/testing/include/appInstance.h	(revision 4)
@@ -0,0 +1,141 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: appInstance.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef APPINSTANCE_H_
+#define APPINSTANCE_H_
+
+#include "sageDisplay.h"
+#include "sage.h"
+#include "sageSync.h"
+#include "sageConfig.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+#include "streamInfo.h"
+#include "sageStreamer.h"
+
+class appInstance;
+class sagePixelReceiver;
+class bridgeSharedData;
+class sageBlockPartition;
+
+#define ALLOC_LOAD_BALANCING 0
+#define ALLOC_SINGLE_NODE    1
+
+class nodeAllocInfo {
+public:
+   int nodeID;
+   int blockID;
+   
+   nodeAllocInfo() : nodeID(-1), blockID(-1) {}
+};
+
+class appInstance : public appInExec {
+public:
+   int instID;
+protected:
+   bridgeSharedData *shared;
+   sagePixelReceiver *recv;
+   bridgeStreamer *streamerList[MAX_ENDPOINT_NUM];
+   float slaveFRate[MAX_ENDPOINT_NUM];
+   int maxStreamerIdx;
+   
+   streamerConfig sConfig;
+   
+   bool initialized;
+   int nodeNum;
+   int blockSize, groupSize;
+   int blockX, blockY;
+   sageBlockBuf *blockBuf;
+   int blockNum;
+   std::vector<nodeAllocInfo> allocInfoList;
+   
+   sageRect imageMap;
+   sageMessage nodeAlloc;
+   syncGroup *firstSyncGroup;
+   int firstSyncID;
+   
+   std::vector<int> fsList;
+   int waitNodes;
+   int validIdx;  // a vaild streamer index
+
+   sageTimer perfTimer;
+   int reportRate;
+   float slaveBandWidth, accBandWidth, curBandWidth;
+   unsigned packetLoss;
+   float accLoss, slaveLoss;
+   int  reportCnt;
+   
+   /**
+    * if greater than 1 , then it's parallel app
+    */
+   int numOfSenders;
+
+   int sendPerformanceInfo();
+   int addStreamer(int fsIdx, int orgIdx = 0, syncGroup *sGroup = NULL, int syncID = 0);
+   
+   int shutdownAllStreams();   
+   int startPerformanceReport(sageMessage &msg);
+   int findValidIdx();
+   
+public:
+   appInstance(char *msgStr, int id, bridgeSharedData *sh);
+   ~appInstance();
+
+   /**
+    * sageBridget::initStreams()
+    * receiver buffer(sageBlockBuf) and sageReceiver object is created here
+    */
+   int init(char *msg, streamProtocol *nwObj);
+
+   /**
+    * bridgeStreamer object is created here
+    */
+   int addStream(int senderID);
+   void fillAppInfo(char *msgStr);
+   int connectToFSManager();
+   int connectToFSManager(char *fsIP, int fsPort);   
+   int parseMessage(sageMessage &msg, int fsIdx);
+   bool isActive();
+   int accumulateBandWidth(char *data);
+   int allocateNodes(int policy, int nodeID = 0);
+   friend class sageBridge;
+};
+
+#endif
Index: trunk/src/testing/include/sageDisplay.h
===================================================================
--- trunk/src/testing/include/sageDisplay.h	(revision 4)
+++ trunk/src/testing/include/sageDisplay.h	(revision 4)
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDisplay.h
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ *   Description:   This is the header file for the video display module of SAGE.
+ *
+ *   Notes   :    Since the display window may receive its many pieces from many servers, we need to pass multiple buffers
+ *         to this class. Each of the buffers passed contains a frame which forms a part (or whole) of the image on
+ *         the display side.
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#ifndef SAGE_DISPLAY_H
+#define SAGE_DISPLAY_H
+
+#ifndef GL_ABGR_EXT
+   #  define GL_ABGR_EXT 0x8000
+#endif
+#ifndef GL_BGR
+   #  define GL_BGR 0x80E0
+#endif
+#ifndef GL_BGRA
+   #  define GL_BGRA 0x80E1
+#endif
+
+
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+   #  define GL_UNSIGNED_SHORT_5_6_5      0x8363
+#endif
+
+// awf: more (similar) defines for win32...
+#ifndef GL_UNSIGNED_SHORT_5_5_5_1
+   #  define GL_UNSIGNED_SHORT_5_5_5_1      0x8034
+#endif
+#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
+   #  define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8066
+#endif
+
+#include "displayContext.h"
+#include "sageDraw.h"
+#include "sagePixelType.h"
+#include "sageSharedData.h"
+
+
+
+#define MAX_MONTAGE_NUM    100
+
+class sageBlock;
+class sagePixelBlock;
+
+// The following structure holds the parameters of the montage comprising the final window
+
+/**
+ * This holds the parameters of the montage comprising the final window
+ */
+class sageMontage : public sageRect {
+private:
+   displayContext *context;
+   sagePixelType pInfo;
+
+   int      texWidth, texHeight;      // current texture size for this montage
+   //bool     validTexCoord;
+   //sageRect imgInfo;
+   sageRect texInfo;
+
+   GLubyte *texture;
+
+public:
+   int       texHandle;
+   sageRect texCoord;
+   sagePixFmt pixelType;
+   float    depth;
+   int      monIdx;
+   int      tileIdx;
+   bool      visible;
+   //int id;
+
+   sageMontage(displayContext *dct, sagePixFmt pfmt);
+
+   int init(sageRect &viewPort, sageRect &blockLayout,
+         sageRotation orientation);
+   int copyConfig(sageMontage &mon);
+   bool checkDispInfo(sagePixelBlock *block);
+   int renewTexture();
+   int deleteTexture();
+   bool genTexCoord();
+   int loadPixelBlock(sagePixelBlock *block);  // load a pixel block into texture memory
+
+   //inline void getImageOrg(int &x, int &y) { x = imgInfo.x, y = imgInfo.y; }
+};
+
+/**
+ * \brief The video display module of SAGE.
+ *
+ * This class is for drawing pixel data onto screen, and all OpenGL related codes are here
+ *
+ * Since the display window may receive its many pieces from many servers, we need to pass multiple buffers to this class.
+ * Each of the buffers passed contains a frame which forms a part (or whole) of the image on the display side.
+ */
+class sageDisplay {
+protected:
+   displayContext *context;
+   sageDisplayConfig configStruct;
+
+   sageMontage*       montages[MAX_TILES_PER_NODE][MAX_MONTAGE_NUM];
+   int noOfMontages[MAX_TILES_PER_NODE];
+
+   int tileNum;
+   bool dirty;
+   sageDraw drawObj;
+
+public:
+   sageDisplay(displayContext *dct, struct sageDisplayConfig &cfg);
+   int addMontage(sageMontage *mon);  // register a new montage into the montage list
+   int replaceMontage(sageMontage *mon); // replace the current montage by another montage
+   int removeMontage(sageMontage *mon);  // delete montage from the montage list
+   int updateScreen(dispSharedData *shared=NULL, bool barrierFlag=false); /**< draw montages onto screen */
+   int changeBGColor(int red, int green, int blue);
+
+   int addDrawObjectInstance(char *data);
+   int updateObjectPosition(char *data);
+   int removeDrawObject(char *data);
+   int forwardObjectMessage(char *data);
+   int showObject(char *data);
+
+   inline void setDirty() { dirty = true; }
+   inline bool isDirty() { return dirty; }
+   inline sageRect& getTileRect(int idx) { return configStruct.tileRect[idx]; }
+   inline int getTileNum() { return tileNum; }
+//   int setupWinBorders(char *info);
+//   int drawWinBorders();
+//   int updateWinBorders(char *info);
+//   int updateWinDepth(int appID, float depth, float titleOffset);
+//   int deleteWinBorders(int appID);
+
+   ~sageDisplay();
+};
+
+#endif
Index: trunk/src/testing/include/messageInterface.h
===================================================================
--- trunk/src/testing/include/messageInterface.h	(revision 4)
+++ trunk/src/testing/include/messageInterface.h	(revision 4)
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: messageInterface.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _MSGINTF_H
+#define _MSGINTF_H
+
+#include "sage.h"
+#include "QUANTAnet_tcp_c.hxx"
+
+class msgInfConfig {
+public:
+   bool   master;
+   char   serverIP[SAGE_IP_LEN];
+   int   serverPort;
+
+   msgInfConfig() : serverPort(0), master(true) { serverIP[0] = '\0'; }
+};
+
+class messageInterface {
+private:
+   QUANTAnet_tcpServer_c *msgServer;
+   std::vector<QUANTAnet_tcpClient_c *> msgClientList;
+   msgInfConfig config;
+   int readIdx;
+   int maxClientSockFd;
+   fd_set clientFds;
+   static void* connectionThread(void *args);
+   bool infEnd;
+   pthread_t conThreadID;
+   
+public:
+   messageInterface();
+   ~messageInterface();
+   int init(msgInfConfig &conf);
+   int connect(char *ip, int port);
+   int checkClients();
+   int waitForConnection();
+   int readMsg(sageMessage *msg, int timeOut = -1);
+   // return (clientID+1) : data read, return 0 : no data, return -1 : error
+   // timeOut < 0 : blocking read (default)
+   // timeOut = 0 : non-blocking read 
+   // timeOut > 0 : blocking read with time-out in micro second
+   
+   int distributeMessage(sageMessage &msg, int *clientList, int clientNum);
+   int distributeMessage(int code, int instID, int *clientList, int clientNum);
+   int distributeMessage(int code, int instID, int data, int *clientList, int clientNum);
+   int distributeMessage(int code, int instID, char *data, int *clientList, int clientNum);
+   int msgToClient(sageMessage &msg);
+   int msgToClient(int cId, int instID, int code);
+   int msgToClient(int cId, int instID, int code, int data);
+   int msgToClient(int cId, int instID, int code, char *data);
+   int msgToServer(int instID, int code);
+   int msgToServer(int instID, int code, int data);
+   int msgToServer(int instID, int code, char *data);
+   int getNumClients() { return msgClientList.size(); }
+   int shutdown();
+};
+
+#endif
Index: trunk/src/testing/include/sageConfig.h
===================================================================
--- trunk/src/testing/include/sageConfig.h	(revision 4)
+++ trunk/src/testing/include/sageConfig.h	(revision 4)
@@ -0,0 +1,160 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageConfig.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef SAGE_CONFIG_H_
+#define SAGE_CONFIG_H_
+
+#include "sage.h"
+
+class sageSyncServer;
+class sageSyncClient;
+class syncGroup;
+
+class streamerConfig {
+public:
+   int   blockX, blockY, blockSize;
+   nwProtocol protocol;
+
+   int   totalWidth, totalHeight;   
+   int   rank;      // the rank of this node   
+   int   resX;      // the width of application buffer in pixels
+   int   resY;      // the height of application buffer in pixels
+   sageRect   imageMap;  // the location of sub-image rendered by this node in the whole app image
+   sagePixFmt pixFmt;    // pixel format defined in sage.h 
+   int   nodeNum;     // number of rendering nodes for an app instance   
+   int   rowOrd;      // row order flag 
+   bool  master;      // is master node or not
+   bool  asyncUpdate;
+   sageCompressType compression;
+   int  frameRate;
+   int  syncMode;
+   int  streamType; // SAGE_BLOCK_HARD_SYNC, NO_SYNC
+   int  streamerID;
+   int  groupSize;
+   int  maxBandwidth;  // maximum hardware bandwidth of sending node
+   int  maxCheckInterval;
+   int  flowWindow;
+   bool autoBlockSize;
+   bool frameDrop;
+      
+////////
+   long totalFrames;
+   bool bridgeOn;   
+   bool audioOn;                   // audio on/off flag
+   nwProtocol audioProtocol;
+   int audioKeyFrame; 
+   sageAudioMode audioMode;        // audio mode : capture, play, read, write
+   int  audioPort;                 // audio port number
+   int  audioDeviceNum;            // device number
+   sageSampleFmt sampleFmt;        // audio sampling format : float, short, char, unsigned char
+   long samplingRate;              // audio sampling rate : default-44100
+   int  channels;                  // number of audio channel
+   int  framePerBuffer;            // audio frames per buffer
+   int  bytesPerSample;
+   sageAudioSyncType syncType;
+   char  audioFileName[SAGE_NAME_LEN];  // application name
+   int   audioBuffSize;
+   
+   int  syncPolicy, syncID;
+   syncGroup *sGroup;
+   sageSyncClient *syncClientObj;
+   
+   bool swexp; // sungwon experimental
+   bool fromBridgeParallel;
+
+   streamerConfig();
+};   
+
+class sailConfig : public streamerConfig {
+public:
+   char  appName[SAGE_NAME_LEN];  // application name
+   char  masterIP[SAGE_IP_LEN];  // the SAIL Master IP
+   int   nwID;
+   char  fsIP[SAGE_IP_LEN];
+   int   fsPort;
+   char    bridgeIP[SAGE_IP_LEN];
+   int    bridgePort;
+
+   int   syncPort;
+   int   msgPort;
+   int   appID;   // ID for each app instance
+   char  launcherID[SAGE_NAME_LEN];  // which appLauncher started this app
+
+   int   winX, winY, winWidth, winHeight; //window position and size on tiled display
+   
+   int   syncMode;
+   int   streamMode;
+   int   rcvBufSize;  // stream receiving buffer size
+   
+   bool  rendering;   // rendering or control only
+   char streamIP[SAGE_IP_LEN];
+
+   int   portForwarding;
+      
+   sailConfig();
+   int init(const char *fname); //initialize app configuration by config file
+   int setAppName(const char *name);
+};   
+
+class appInExec : public sageRect {
+public:   
+   int uiClient;
+   int sailClient;
+   char appName[SAGE_NAME_LEN];
+   int instID;
+	int fsInstID;
+   char launcherID[SAGE_NAME_LEN];
+   nwProtocol protocol;
+   int nwID;
+   char fsIP[SAGE_IP_LEN];
+   int fsPort;
+   int imageWidth, imageHeight;
+   //int bytesPerPixel;
+   int bandWidth;
+   int frameRate;
+   int displayID;
+   bool audioOn;
+   char renderNodeIP[SAGE_IP_LEN];
+   int portForwarding;   
+
+   appInExec() : displayID(0) {}
+};
+
+#endif
Index: trunk/src/testing/include/sageDoubleBuf.h
===================================================================
--- trunk/src/testing/include/sageDoubleBuf.h	(revision 4)
+++ trunk/src/testing/include/sageDoubleBuf.h	(revision 4)
@@ -0,0 +1,84 @@
+/***************************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module:  sageDoubleBuf.h
+ * Author : Byungil Jeong
+ *
+ *   Description: double buffer of sage pixel blocks for sageStreamer
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+*****************************************************************************************/
+
+#ifndef _SAGEDOUBLEBUF_H
+#define _SAGEDOUBLEBUF_H
+
+#include "sageBase.h"
+
+class sagePixelData;
+
+class sageDoubleBuf {
+private:
+   int bufID;
+   sagePixelData **blockBuf;   
+      
+   pthread_mutex_t *bufLock;
+   pthread_cond_t *notFull;
+   pthread_cond_t *notEmpty;
+   
+   bool full, empty;
+   bool firstFrameReady;
+   int queueLen;
+      
+public:
+   sageDoubleBuf() : full(false), empty(true), queueLen(0), firstFrameReady(false) {}
+   int init(sagePixelData **bufs);   
+   
+   sagePixelData* getBuffer(int id);  // get buffer without checking availability
+   sagePixelData* getBackBuffer();    // get the pixel block on which pixel data has been written 
+   int releaseBackBuffer();
+   int bufSize();
+   
+   // get the empty block on which application can write safely
+   sagePixelData* getFrontBuffer();
+   
+   int swapBuffer();
+   int resendBuffer(int num);
+   void enQueue()  { queueLen++; }
+   bool isEmpty()  { return (queueLen == 0); }
+   bool isFirstFrameReady() { return firstFrameReady; }
+   void releaseLocks();
+   ~sageDoubleBuf();
+};
+
+#endif
Index: trunk/src/testing/include/fsClient.h
===================================================================
--- trunk/src/testing/include/fsClient.h	(revision 4)
+++ trunk/src/testing/include/fsClient.h	(revision 4)
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsClient.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#ifndef _FSCLIENT_H
+#define _FSCLIENT_H
+
+#include "sage.h"
+#include "QUANTAnet_tcp_c.hxx"
+
+
+#define SOCK_BUF_SIZE (1024*1024*32)
+#define READ_BUF_SIZE 4096
+#define FS_ID 0 
+
+/**
+ * class fsClient
+ */
+class fsClient {
+protected:
+   QUANTAnet_tcpClient_c *client;
+   char *fsIp; /**< fsManager IP address */
+   int portNum;
+
+public:
+   fsClient() {}
+   ~fsClient(); 
+   int init(const char *config, const char *portType);
+   int init(int port);
+   int connect(char *ip); /**< connects to sage */
+   int getSelfIP(char *ip);
+   int sendMessage(sageMessage &msg);
+   int sendMessage(int code);  
+   int sendMessage(int code, int data);
+   int sendMessage(int code, const char *data); // string data 
+   int sendMessage(int code, int size, void *data);
+   int sendMessage(int dst, int code, int data);
+   int sendMessage(int dst, int code, int app, const char *data);
+   int sendMessage(int dst, int code, int app, int size, void *data); /**< send message to fsManager */
+   int rcvMessage(sageMessage &msg);
+   int rcvMessageBlk(sageMessage &msg); /**< blocking read of SAGE messages. return the message size */
+};
+
+
+#endif
Index: trunk/src/testing/include/streamInfo.h
===================================================================
--- trunk/src/testing/include/streamInfo.h	(revision 4)
+++ trunk/src/testing/include/streamInfo.h	(revision 4)
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: streamInfo.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _STREAM_INFO_H
+#define _STREAM_INFO_H
+
+#include "sageBase.h"
+
+class sageBlock;
+
+class streamInfo : public sageRect {
+public:
+   sageRect imgCoord;   
+   int receiverID;  // Display Node ID
+   int rcvNum;
+   int connectionIdx;
+      
+   streamInfo() : receiverID(0), rcvNum(0) {}
+   ~streamInfo() {}
+
+   void printImageInfo();
+   int generateInitBlock(sageBlock *block, int margin);
+};   
+
+class streamGroup : public sageRect {
+private:   
+   std::vector<streamInfo> streamList;
+   int rcvNum;
+   
+public:
+   streamGroup();
+   ~streamGroup() {}
+   void init();
+   void operator=(sageRect& rect) { sageRect::operator=(rect); }
+
+   streamInfo* getStream(int i) { return &streamList[i]; }
+   std::vector<streamInfo> getStreamList() { return streamList; }
+   int streamNum() { return streamList.size(); }
+   int getRcvNum() { return rcvNum; }
+   void setRcvNum(int num) { rcvNum = num; }
+   
+   int addStream(streamInfo &s);
+   int addImageInfo(sageRect &imgRect);
+   void createMessage(sageMessage &msg, int code);
+   void createRcvMsg(int winID, char *msgStr);
+   void parseMessage(char *str);
+};
+
+class bridgeStreamInfo {
+public:
+   int firstID, lastID;   
+   int receiverID;
+   
+   bridgeStreamInfo() : firstID(0), lastID(0), receiverID(0) {}
+};
+
+class bridgeStreamGroup {
+public:
+   bridgeStreamInfo *streamList;
+   int streamNum;
+
+   bridgeStreamGroup() : streamNum(0), streamList(NULL) {}
+   void parseMessage(char *str);
+};
+
+#endif
Index: trunk/src/testing/include/envInterface.h
===================================================================
--- trunk/src/testing/include/envInterface.h	(revision 4)
+++ trunk/src/testing/include/envInterface.h	(revision 4)
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: envInterface.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+
+#ifndef _ENVINTF_H
+#define _ENVINTF_H
+
+#include "fsClient.h"
+#include "sail.h"
+
+/**
+ * class envInterface
+ */
+class envInterface : public fsClient {
+private:
+   sailConfig config;
+   QUANTAnet_tcpServer_c *sailServer;
+   int numClients;
+   std::vector<QUANTAnet_tcpClient_c *> sailClientList;
+   
+public:
+   envInterface() : sailServer(NULL) {}
+   ~envInterface();
+   int init(sailConfig &conf);
+   int init(sailConfig &conf, char *ip, int port);   
+   int checkClients();
+   int readClientMsg(sageMessage &msg, int idx);   
+   int distributeMessage(sageMessage &msg);
+   int distributeMessage(int code);
+   int msgToClient(sageMessage &msg);
+   int msgToClient(int cId, int code);
+   int msgToClient(int cId, int code, int data);
+   int msgToClient(int cId, int code, char *data);
+   int getNumClients() { return numClients; }
+   
+};
+
+
+#endif
Index: trunk/src/testing/include/sageBase.h
===================================================================
--- trunk/src/testing/include/sageBase.h	(revision 4)
+++ trunk/src/testing/include/sageBase.h	(revision 4)
@@ -0,0 +1,172 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBase.h
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#ifndef _SAGE_BASE_H
+#define _SAGE_BASE_H
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <vector>
+#include <deque>
+#include <algorithm>
+#include <numeric>
+#include <pthread.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+
+#if defined(WIN32)
+   #include <io.h>
+   #include <process.h>
+
+   #define _WIN32_WINNT    0x0501  // Macro for getting the switchToThread() to work
+   #if defined(N_PLAT_NLM)
+      #include <ws2nlm.h>
+   #else
+      #include <winsock2.h>
+   #endif
+   #include <ws2tcpip.h>
+   #define WIN32_LEAN_AND_MEAN
+   #include <windows.h>
+#else
+   #include <strings.h>
+   #include <sys/time.h>
+   #include <unistd.h>
+   #include <sys/types.h>
+   #include <sys/wait.h>
+   #include <sys/socket.h>
+   #include <netinet/in.h>
+   #include <arpa/inet.h>
+   #include <netinet/tcp.h>
+   #include <sys/stat.h>
+   #include <sys/uio.h>
+   #include <sys/select.h>
+#endif
+
+#include <fcntl.h>
+
+
+#define SAGE_IP_LEN 128
+#define SAGE_MAX_DOMAIN 10
+#define SAGE_CMD_LEN 1024
+#define SAGE_NAME_LEN 256
+#define MAX_TILES_PER_NODE 100
+#define TRACKING_DATA_SIZE 256
+#define SAGE_PERF_START 10
+#define CMAN_MSG_SIZE 2048
+#define DISPLAY_BUF_NUM 2
+#define BRIDGE_BUF_NUM  5
+#define MAX_ENDPOINT_NUM 100
+#define MAX_INST_NUM   100
+#define MAX_FRAME_RATE 120
+#define DEFAULT_IMAGE_SIZE 3145728
+
+#define MESSAGE_HEADER_SIZE 36
+#define MESSAGE_FIELD_SIZE 9
+
+#define TOP_TO_BOTTOM 0
+#define BOTTOM_TO_TOP 1
+
+typedef unsigned sageApiOption;
+#define SAGE_BLOCKING     1
+#define SAGE_NON_BLOCKING 2
+#define SAGE_BACKWARD     4
+#define SAGE_CONTROL      8
+
+#define SAGE_TIMEOUT 1
+#define SAGE_INT_MAX 2147483647
+
+enum nwProtocol {SAGE_TCP, SAGE_UDP, LAMBDA_STREAM};
+enum sageStreamMode {SAGE_RCV, SAGE_ARCV, SAGE_SEND, SAGE_BRIDGE};
+enum sagePixFmt {PIXFMT_NULL, PIXFMT_555, PIXFMT_555_INV, PIXFMT_565, PIXFMT_565_INV,
+      PIXFMT_888, PIXFMT_888_INV, PIXFMT_8888, PIXFMT_8888_INV, PIXFMT_RLE, PIXFMT_LUV,
+      PIXFMT_DXT, PIXFMT_YUV};
+enum sageCompressType {NO_COMP, RLE_COMP, LUV_COMP, DXT_COMP};
+
+enum sageSampleFmt {SAGE_SAMPLE_FLOAT32, SAGE_SAMPLE_INT16, SAGE_SAMPLE_INT8, SAGE_SAMPLE_UINT8};
+enum sageAudioMode {SAGE_AUDIO_CAPTURE = 1, SAGE_AUDIO_PLAY = 2, SAGE_AUDIO_READ = 4, SAGE_AUDIO_WRITE = 8, SAGE_AUDIO_APP = 16, SAGE_AUDIO_FWCAPTURE = 32};
+enum sageAudioSyncType {SAGE_SYNC_NONE, SAGE_SYNC_AUDIO_DRIVEN, SAGE_SYNC_GRAPHIC_DRIVEN};
+
+class sageMessage {
+private:
+   char *dest;
+   char *code;
+   char *appCode;
+   char *size;
+
+   void *data;
+   char *buffer;
+   int bufSize;
+   int clientID;
+
+public:
+   sageMessage();
+   ~sageMessage();
+   // init by message contents
+   int init(int dst, int co, int app, int sz, const void *dat);
+   // init by message buffer size
+   //void init();
+   int init(int);
+   int destroy();
+   int set(int dst, int co, int app, int sz, const void *dat);
+   int getDest();
+   int getCode();
+   int getAppCode();
+   int getSize();
+   int getBufSize() { return bufSize; }
+   void* getData();
+   char* getBuffer();
+   int getClientID() { return clientID; }
+
+   int setDest(int);
+   int setCode(int);
+   int setAppCode(int);
+   int setSize(int s);
+   int setData(int, void*);
+   void setClientID(int id) { clientID = id; }
+};
+
+#include "misc.h"
+#include "sageRect.h"
+
+#endif
Index: trunk/src/testing/include/displayContext.h
===================================================================
--- trunk/src/testing/include/displayContext.h	(revision 4)
+++ trunk/src/testing/include/displayContext.h	(revision 4)
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: displayContext.h
+ * Author : Byungil Jeong
+ *
+ *   Description:   This is the header file for the video display module of SAGE. 
+ *
+ *   Notes   :    Since the display window may receive its many pieces from many servers, we need to pass multiple buffers
+ *         to this class. Each of the buffers passed contains a frame which forms a part (or whole) of the image on
+ *         the display side.
+ *
+ * Copyright (C) 2007 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *         
+***************************************************************************************************************************/
+
+#ifndef DISPLAY_CONTEXT_H
+#define DISPLAY_CONTEXT_H
+
+#include "sage.h"
+
+/**
+ * sageDisplayConfig
+ */
+struct sageDisplayConfig{
+   int   width;
+   int   height;
+   int   dimX;
+   int   dimY;
+   sageRect   tileRect[MAX_TILES_PER_NODE];
+
+   int   mullionX;
+   int   mullionY;
+   int   xpos;
+   int   ypos;
+   int   red, green, blue;
+   int   displayID;
+   int   winX;
+   int   winY;
+   
+   bool  fullScreenFlag;
+};
+
+/**
+ * class displayContext
+ */
+class displayContext {
+protected:
+   sageDisplayConfig configStruct;
+   bool winCreatFlag;
+   int tileNum;
+   bool singleContext;
+   
+public:
+   displayContext() : winCreatFlag(false) {}
+   virtual int init(struct sageDisplayConfig &cfg) = 0;   
+   virtual void clearScreen() {}
+   virtual void setupViewport(int i, sageRect &tileRect) {}
+   virtual void refreshTile(int i) {}
+   virtual void refreshScreen() {}
+   virtual void changeBackground(int red, int green, int blue) {}
+   virtual void switchContext(int i) {}
+   virtual void checkEvent() {}
+};
+
+#endif
Index: trunk/src/testing/.project
===================================================================
--- trunk/src/testing/.project	(revision 4)
+++ trunk/src/testing/.project	(revision 4)
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>SAGE_experimental</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>
Index: trunk/src/testing/.cproject
===================================================================
--- trunk/src/testing/.cproject	(revision 4)
+++ trunk/src/testing/.cproject	(revision 4)
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.base.762576472">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.762576472" moduleId="org.eclipse.cdt.core.settings" name="Default">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.base.762576472" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.base.762576472.738315068" name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.462756114" name="cdt.managedbuild.toolchain.gnu.base" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.2121228631" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder id="cdt.managedbuild.target.gnu.builder.base.339421169" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.118094814" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1561529287" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1416124110" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1355266493" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1304048103" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1713118595" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.4189394" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.873013966" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.2057742730" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<option id="gnu.both.asm.option.include.paths.1799929092" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/SAGE_experimental/include}&quot;"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1820127030" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="SAGE.null.527126392" name="SAGE"/>
+	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="1">
+		<resource resourceType="PROJECT" workspacePath="/SAGE_testing"/>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.762576472;cdt.managedbuild.toolchain.gnu.base.762576472.738315068;cdt.managedbuild.tool.gnu.c.compiler.base.1355266493;cdt.managedbuild.tool.gnu.c.compiler.input.1304048103">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.762576472;cdt.managedbuild.toolchain.gnu.base.762576472.738315068;cdt.managedbuild.tool.gnu.cpp.compiler.base.1561529287;cdt.managedbuild.tool.gnu.cpp.compiler.input.1416124110">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+</cproject>
Index: trunk/src/testing/src/envInterface.cpp
===================================================================
--- trunk/src/testing/src/envInterface.cpp	(revision 4)
+++ trunk/src/testing/src/envInterface.cpp	(revision 4)
@@ -0,0 +1,329 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: envInterface.cpp - a part of SAGE Application Interface Library
+ *            taking care of communcation with the Free Space Manager.
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "sageVersion.h"
+#include "envInterface.h"
+
+envInterface::~envInterface()
+{
+   if (sailServer)
+      delete sailServer;
+}
+      
+int envInterface::init(sailConfig &conf)
+{
+	config = conf;
+	
+	if (config.master) {
+		
+        char *sageDir = getenv("SAGE_DIRECTORY");
+        if (!sageDir) {
+			sage::printLog("envInterface: cannot find the environment variable SAGE_DIRECTORY");
+			return -1;
+        }
+		
+        data_path path;
+        std::string found = path.get_file("fsManager.conf");
+        if (found.empty()) {
+			sage::printLog("envInterface: cannot find the file [%s]", "fsManager.conf");
+			return -1;
+        }
+        const char *fsConfigFile = found.c_str();
+        sage::printLog("envInterface: SAGE version [%s]", SAGE_VERSION);
+        sage::printLog("envInterface: using [%s] configuration file", fsConfigFile);
+		
+		
+		fsClient::init(fsConfigFile, "systemPort");
+		
+		while(connect(NULL) < 0)
+			sage::sleep(1);
+		
+		numClients = 0;
+		if (config.nodeNum > 1) {
+			sailServer = new QUANTAnet_tcpServer_c;
+			sailServer->init(config.msgPort + config.appID);
+			sailServer->setSockOptions(QUANTAnet_tcpServer_c::READ_BUFFER_SIZE, 65536);
+			sailServer->setSockOptions(QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE, 65536);
+		}
+		else
+			sailServer = NULL;
+	}
+	else if (config.nodeNum > 1) {
+		fsClient::init(config.msgPort + config.appID);
+		
+		while(connect(config.masterIP) < 0) {
+			sage::sleep(1);
+			std::cout << "envInterface::init() : retry to connect to master" << std::endl;
+		}   
+	}
+	
+	return 0;
+}
+
+int envInterface::init(sailConfig &conf, char *ip, int port)
+{
+   config = conf;
+   if (config.master) {
+      std::cout << "try to connect to " << ip << ":" << port << std::endl;
+      fsClient::init(port);
+      while(connect(ip) < 0)
+         sage::sleep(1);
+      
+      numClients = 0;
+      if (config.nodeNum > 1) {
+         sailServer = new QUANTAnet_tcpServer_c;
+         sailServer->init(config.msgPort + config.appID);
+         sailServer->setSockOptions(QUANTAnet_tcpServer_c::READ_BUFFER_SIZE, 65536);
+         sailServer->setSockOptions(QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE, 65536);
+      }   
+      else
+         sailServer = NULL;
+   }
+   else if (config.nodeNum > 1) {
+      fsClient::init(config.msgPort + config.appID);
+      
+      while(connect(config.masterIP) < 0) {
+         sage::sleep(1);
+         std::cout << "envInterface::init() : retry to connect to master" << std::endl;
+      }   
+   }
+      
+   return 0;
+}
+
+/*
+int envInterface::checkMsg()
+{
+   sageMessage msg;
+   
+   if (rcvMessage(msg) < 0)
+      return -1;
+   else {
+      if (msg.getCode() < SAIL_MESSAGE   + 100) {
+         sailPt->parseMessage(msg);
+         msg.destroy();
+      }   
+      else if (msg.getCode() < SAIL_MESSAGE + 200) {
+         if (sailPt->config.master)
+            distributeMessage(msg);
+         sailPt->parseMessage(msg);
+         msg.destroy();
+      }   
+      else if (msg.getCode() >= APP_MESSAGE) {
+         sailPt->appMsgQueue.push_back(msg);
+         pthread_mutex_unlock(sailPt->msgMutex);
+      }
+   }
+
+   return 0;
+}   
+*/
+
+int envInterface::checkClients()
+{
+   if (!config.master) {
+      std::cout << "envInterface::checkClients() : this function cannot be called by slaves" <<
+         std::endl;
+      return -1;
+   }
+   
+   if (!sailServer)
+      return 0;
+      
+   QUANTAnet_tcpClient_c *aClient;
+
+   // If a connection is established, accept it and create
+   // a new socket for that connection to communicate with.
+   
+   aClient = sailServer->checkForNewConnections();
+
+   if (aClient) {
+      printf("sailClient %d connected\n", numClients);
+
+      sailClientList.push_back(aClient);
+      numClients++;
+   }
+   
+   return 0;
+}
+
+
+int envInterface::readClientMsg(sageMessage &msg, int idx)
+{
+   int dataSize;
+   int status;
+
+   if (sailClientList[idx]) {
+      char msgSize[MESSAGE_FIELD_SIZE];
+      dataSize = MESSAGE_FIELD_SIZE;
+      status = sailClientList[idx]->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::NON_BLOCKING);
+
+      if (status == QUANTAnet_tcpClient_c::OK)  {
+         msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+         dataSize = atoi(msgSize);
+         msg.init(dataSize);
+         dataSize = dataSize - MESSAGE_FIELD_SIZE;
+         sailClientList[idx]->read((char *)msg.getBuffer()+MESSAGE_FIELD_SIZE, 
+               &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+         //printf("Read in message from client %d\n",idx);
+         //std::cout << "messge : " << msg.getCode() << std::endl; 
+         //      << (char *)msg.getData() << std::endl;
+         return 1;
+      } 
+      else if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED) {
+         std::cout << "connection to client " << idx << " was terminated" << std::endl;
+         sailClientList[idx] = NULL;
+         return -1;
+      }
+   }   
+
+   return 0;
+}
+
+int envInterface::distributeMessage(sageMessage &msg)
+{
+   if (!config.master) {
+      std::cout << "envInterface::distributeMessage() : this function cannot be called by slaves" <<
+         std::endl;
+      return -1;
+   }
+   
+   int dataSize = msg.getBufSize();
+   for (int i = 0; i < numClients; i++) {
+      if (!sailClientList[i])
+         continue;
+
+      int status = sailClientList[i]->write((char *)msg.getBuffer(), &dataSize, 
+                  QUANTAnet_tcpClient_c::BLOCKING);  
+
+      if (status == QUANTAnet_tcpClient_c::OK)  {
+         //std::cout << "Send message to sail client " << i << std::endl;
+         //std::cout << "message : " << msg.getCode() << " " 
+         //      << (char *)msg.getData() << std::endl;
+      }
+      else
+         std::cout << "envInterface::distributeMessage() : Fail to send message to sail client " << i << std::endl;
+   }   
+      
+   return 0;
+}
+
+int envInterface::distributeMessage(int code)
+{
+   sageMessage msg;
+   
+   if (msg.init(0, code, 0, 0, NULL) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+   
+   int retVal = distributeMessage(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int envInterface::msgToClient(sageMessage &msg)
+{
+   if (!config.master) {
+      std::cout << "envInterface::msgToClient() : this function cannot be called by slaves" <<
+         std::endl;
+      return -1;
+   }
+   
+   int dataSize = msg.getBufSize();
+   int cId = msg.getDest();
+
+   if (!sailClientList[cId])
+      return -1;
+
+   int status = sailClientList[cId]->write((char *)msg.getBuffer(), &dataSize, 
+               QUANTAnet_tcpClient_c::BLOCKING);  
+   
+   if (status == QUANTAnet_tcpClient_c::OK)  {
+      //std::cout << "Send message to client " << cId << std::endl;
+      //std::cout << "messge : " << msg.getCode() << " " 
+      //      << (char *)msg.getData() << std::endl;
+   }
+   else 
+      return -1;
+
+   return 0;
+}
+
+int envInterface::msgToClient(int cId, int code)
+{
+   sageMessage msg;
+   
+   if (msg.init(cId, code, 0, 0, NULL) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int envInterface::msgToClient(int cId, int code, int data)
+{
+   char msgStr[TOKEN_LEN];
+   sprintf(msgStr, "%d", data);
+   
+   return msgToClient(cId, code, msgStr);
+}
+
+int envInterface::msgToClient(int cId, int code, char *data)
+{
+   sageMessage msg;
+   
+   if (msg.init(cId, code, 0, strlen(data)+1, data) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
Index: trunk/src/testing/src/suil.cpp
===================================================================
--- trunk/src/testing/src/suil.cpp	(revision 4)
+++ trunk/src/testing/src/suil.cpp	(revision 4)
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: suil.cpp - SAGE User Interface Library
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageVersion.h"
+#include "suil.h"
+
+int suil::init(const char *config)
+{
+	data_path path;
+	std::string found = path.get_file(config);
+	if (found.empty()) {
+		sage::printLog("suil: cannot find any file called [%s]", config);
+		return -1;
+	}
+	else {
+		sage::printLog("suil: SAGE version [%s]", SAGE_VERSION);
+		sage::printLog("suil: using file [%s]", found.c_str());
+		fsClient::init(found.c_str(), "uiPort");
+		return 0;
+	}
+}
+
Index: trunk/src/testing/src/streamProtocol.cpp
===================================================================
--- trunk/src/testing/src/streamProtocol.cpp	(revision 4)
+++ trunk/src/testing/src/streamProtocol.cpp	(revision 4)
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: streamProtocol.cpp 
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "streamProtocol.h"
+#include "sageBlock.h"
+
+int streamProtocol::init(sageStreamMode m, int p, sageNwConfig &c) 
+{
+   sMode = m;
+   rcvPort = p;
+   config = c;
+   rcvList.clear();
+   sendList.clear();
+
+   return 0;
+}
+
+int streamProtocol::close(int id, int mode)
+{
+   if (mode == -1)
+      mode = sMode;
+      
+   if (mode == SAGE_RCV || mode == SAGE_ARCV) {
+      if (sendList[id] >= 0) {
+      #ifdef WIN32   
+         closesocket(sendList[id]);
+      #else
+         shutdown(sendList[id], SHUT_RDWR);
+      #endif
+      }
+   }
+   
+   if (mode == SAGE_SEND) {
+      if (rcvList[id] >= 0) {
+      #ifdef WIN32   
+         closesocket(rcvList[id]);
+      #else
+         shutdown(rcvList[id], SHUT_RDWR);
+      #endif
+      }
+   }
+   
+   return 0;
+}
+
+
+
Index: trunk/src/testing/src/bridgeConsole.cpp
===================================================================
--- trunk/src/testing/src/bridgeConsole.cpp	(revision 4)
+++ trunk/src/testing/src/bridgeConsole.cpp	(revision 4)
@@ -0,0 +1,199 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: bridgeConsole.cpp - experimental user console for SAGE Bridge
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "sageVersion.h"
+#include "messageInterface.h"
+#include "misc.h"
+#include <pthread.h>
+
+void* readThread(void *args)
+{
+   messageInterface *msgInf = (messageInterface *)args;
+   
+   while(1) {
+      sageMessage msg;
+      //msg.init(READ_BUF_SIZE);
+      if (msgInf->readMsg(&msg) > 0)
+         std::cout << "Message : " << msg.getCode() << std::endl << (char *)msg.getData() 
+         << std::endl << std::endl;
+      sage::usleep(100000);   
+   }
+
+   return NULL;
+} 
+
+int initInterface(messageInterface &inf, const char *configFile)
+{
+	msgInfConfig conf;
+	conf.master = false;
+	
+	
+	data_path path;
+	std::string found = path.get_file(configFile);
+	if (found.empty()) {
+		sage::printLog("bridgeConsole: cannot find the file [%s]", configFile);
+		return -1;
+	}
+	const char *bridgeConfigFile = found.c_str();
+	sage::printLog("bridgeConsole: SAGE version [%s]", SAGE_VERSION);
+	sage::printLog("bridgeConsole: using [%s] configuration file", bridgeConfigFile);
+	
+	FILE *fileBridgeConf = fopen(bridgeConfigFile, "r");
+	
+	if (!fileBridgeConf) {
+		sage::printLog("bridgeConsole: fail to open SAGE Bridge config file [%s]\n", bridgeConfigFile);
+		return -1;
+	}
+	
+	char token[TOKEN_LEN];
+	int tokenIdx = getToken(fileBridgeConf, token);
+	
+	while(tokenIdx != EOF) {
+		if (strcmp(token, "masterIP") == 0) {
+			getToken(fileBridgeConf, conf.serverIP);
+		}
+		else if (strcmp(token, "msgPort") == 0) {   
+			getToken(fileBridgeConf, token);
+			conf.serverPort = atoi(token);
+		}
+		
+		tokenIdx = getToken(fileBridgeConf, token);
+	}
+	
+	inf.init(conf);
+	
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+   char token[TOKEN_LEN];
+   bool flag = true;
+   int code;
+
+   messageInterface msgInf;
+   
+   if (argc == 2)
+      initInterface(msgInf, argv[1]);
+   else
+      initInterface(msgInf, "sageBridge.conf");
+
+   //msgInf.msgToServer(0, BRIDGE_UI_REG);
+
+   pthread_t thId;
+
+   if (pthread_create(&thId, 0, readThread, (void*)&msgInf) != 0){
+      return -1;
+   }
+
+   while(flag) {
+      std::cin >> token;
+   
+      if (strcmp(token, "exit") == 0 || strcmp(token, "quit") == 0) {
+         flag = false;
+      } 
+      else if (strcmp(token, "share") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, SAGE_APP_SHARE, token);
+      }
+      else if (strcmp(token, "perf") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         msgInf.msgToServer(0, PERF_INFO_REQ, cmd);
+      }            
+      else if (strcmp(token, "stopperf") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, STOP_PERF_INFO, token);
+      }
+      else if (strcmp(token, "kill") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, SHUTDOWN_APP, token);
+      }            
+      else if (strcmp(token, "shutdown") == 0) {
+         msgInf.msgToServer(0, BRIDGE_SHUTDOWN);
+         _exit(0);
+      }            
+      else if (strcmp(token, "exec") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, EXEC_APP, token);
+      }            
+      else if (strcmp(token, "move") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, MOVE_WINDOW, token);
+      }            
+      else if (strcmp(token, "resize") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, RESIZE_WINDOW, token);
+      }            
+      else if (strcmp(token, "bg") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, SAGE_BG_COLOR, token);
+      }            
+      else if (strcmp(token, "depth") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         msgInf.msgToServer(0, SAGE_Z_VALUE, cmd);
+      }                        
+      else if (strcmp(token, "admin") == 0) {
+         msgInf.msgToServer(0, SAGE_ADMIN_CHECK);
+      }            
+      else if (strcmp(token, "rate") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         msgInf.msgToServer(0, APP_FRAME_RATE, token);
+      }            
+                  
+
+      else if (strcmp(token, "help") == 0) {
+         std::cout << std::endl;
+         std::cout << "exec   app_name config_num (init_x init_y) : execute an app" << std::endl;
+         std::cout << "move   app_id dx dy                  : move window of an app" << std::endl;
+         std::cout << "resize app_id left right bottom top  : resize window of an app" << std::endl;
+         std::cout << "bg     red green blue                : change background color" << std::endl;
+         std::cout << "depth  num_of_change app_id zVal...  : change z-order of windows" << std::endl;
+         std::cout << "perf   app_id report_period(sec)     : request performance info" << std::endl;
+         std::cout << "stopperf  app_id                     : stop performance info report" << std::endl;
+         std::cout << "kill      app_id                     : shutdown an app" << std::endl;
+         std::cout << "shutdown                             : shutdown SAGE" << std::endl;
+         std::cout << "admin                                : get administrative info" << std::endl;
+      }            
+      
+      std::cout << std::endl;
+   }
+}
Index: trunk/src/testing/src/sageEvent.cpp
===================================================================
--- trunk/src/testing/src/sageEvent.cpp	(revision 4)
+++ trunk/src/testing/src/sageEvent.cpp	(revision 4)
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageEvent.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageEvent.h"
+
+sageEvent::sageEvent(int type, char *msg, void *p)
+{
+   eventType = type;
+   setMsg(msg);
+   param = p;
+   buflen = 0;
+}
+
+
+sageSyncEvent::sageSyncEvent(int type, int bl, void *p) {
+	eventType = type;
+	param = p;
+	buflen = bl;
+
+	if ( bl > 0 ) {
+		eventMsg = (char *)malloc(sizeof(char) * bl);
+	}
+}
+
+int sageSyncEvent::setMsg(char *msg) {
+	if (eventMsg && msg) {
+		if ( ! strcpy(eventMsg, msg) ) return -1;
+		buflen = strlen(eventMsg);
+
+		if ( buflen <= 0 ) return -1;
+
+		return buflen;
+	}
+	return -1;
+}
+
+sageEventQueue::sageEventQueue() : empty(true)
+{
+   eventQueue.clear();
+
+   queueLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(queueLock, NULL);
+   pthread_mutex_unlock(queueLock);
+   notEmpty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notEmpty, NULL);
+}
+
+sageEvent* sageEventQueue::getEvent()
+{
+   pthread_mutex_lock(queueLock);
+
+   while (isEmpty()) {
+      pthread_cond_wait(notEmpty, queueLock);
+   }
+
+   sageEvent *event = eventQueue.front();
+   eventQueue.pop_front();
+
+   pthread_mutex_unlock(queueLock);
+
+   return event;
+}
+
+void sageEventQueue::appendEvent(sageEvent* event)
+{
+   pthread_mutex_lock(queueLock);
+   eventQueue.push_back(event);
+   pthread_mutex_unlock(queueLock);
+   pthread_cond_signal(notEmpty);
+}
+
+void sageEventQueue::prependEvent(sageEvent* event)
+{
+   pthread_mutex_lock(queueLock);
+   eventQueue.push_front(event);
+   pthread_mutex_unlock(queueLock);
+   pthread_cond_signal(notEmpty);
+}
+
+void sageEventQueue::appendEvent(int type, char *msg, void *p)
+{
+   sageEvent *event = new sageEvent(type, msg, p);
+   appendEvent(event);
+}
+
+void sageEventQueue::appendEvent(int type, int info, void *p)
+{
+   sageEvent *event = new sageEvent(type, NULL, p);
+   sprintf(event->eventMsg, "%d", info);
+   appendEvent(event);
+}
+
+sageEventQueue::~sageEventQueue()
+{
+   if (queueLock)
+      free(queueLock);
+
+   if (notEmpty)
+      free(notEmpty);
+
+   //eventQueue.clear();
+}
Index: trunk/src/testing/src/overlayApp.cpp
===================================================================
--- trunk/src/testing/src/overlayApp.cpp	(revision 4)
+++ trunk/src/testing/src/overlayApp.cpp	(revision 4)
@@ -0,0 +1,473 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: overlayApp.cpp
+ * Author : Ratko Jagodic
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "overlayApp.h"
+
+
+// custom messages for the appOverlay
+#define RESET  0
+#define DRAG   1
+#define RESIZE 2
+#define Z_CHANGE 3
+#define ON_CORNER 4
+#define ON_APP 5
+#define ROTATE 6
+
+#define SPECIAL_DEVICE 100
+
+
+// STATES for drawing pointers
+#define NORMAL_STATE 10
+#define DRAG_STATE   11
+#define RESIZE_STATE 12
+
+
+// areas
+#define BOTTOM       0
+#define TOP          1
+#define BOTTOM_LEFT  3
+#define TOP_LEFT     4
+#define TOP_RIGHT    5
+#define BOTTOM_RIGHT 6
+
+
+// boundaries
+#define L 0
+#define R 1
+#define T 2
+#define B 3
+
+
+overlayApp::overlayApp()
+{
+   state = NORMAL_STATE;
+   aspectRatio = 1;
+   z = 0;
+   cornerSize = 250;
+
+   for(int i=0; i<7; i++)
+      activeCorners[i] = 0;
+
+   outline[L] = 0.0;
+   outline[R] = 100.0;
+   outline[T] = 100.0;
+   outline[B] = 0.0;
+
+   border_color[0] = 1.0;
+   border_color[1] = 1.0;
+   border_color[2] = 1.0;
+   border_color[3] = 1.0;
+
+   corner_color[0] = 1.0;//0.059;
+   corner_color[1] = 1.0;//0.57;
+   corner_color[2] = 1.0;//0.345;
+   corner_color[3] = 0.3;
+
+   color = border_color;
+
+   specialDevice = false;
+}
+
+
+
+int overlayApp::init(char *name)
+{
+   setName(name);
+   return 0;
+}
+
+
+
+int overlayApp::draw()
+{
+   glDisable(GL_TEXTURE_2D);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glPushMatrix();
+
+   //fprintf(stderr, "\nDRAWING AT: %f %f %f %f", outline[L], outline[R], outline[T], outline[B]);
+
+   /**********    DRAW THE STUFF   ***********/
+   if (state == NORMAL_STATE)
+   {
+      drawOutline();
+
+      glEnable(GL_LINE_STIPPLE);
+      glLineStipple(8, 21845);
+
+      if (!specialDevice){
+		  drawCorners();
+		  drawTop();
+      }
+
+      glDisable(GL_LINE_STIPPLE);
+   }
+   else if (state == DRAG_STATE || state == RESIZE_STATE)
+   {
+	  if (!specialDevice){
+		  glEnable(GL_LINE_STIPPLE);
+		  glLineStipple(8, 21845);
+		  drawOutline();
+		  drawCorners();
+		  drawTop();
+		  glDisable(GL_LINE_STIPPLE);
+	  } else {
+		  drawOutline();
+      }
+
+
+   }
+
+   glPopMatrix();
+   glDisable(GL_BLEND);
+   glDisable(GL_DEPTH_TEST);
+   glEnable(GL_TEXTURE_2D);
+
+   return 0;
+}
+
+void overlayApp::drawOutline()
+{
+   // draw the outline of the app we are resizing
+
+   if (specialDevice){
+	   glColor4f(0.0,0.0,0.6,color[3] * 3);
+	   glLineWidth(10);
+	   glBegin(GL_LINE_LOOP);
+		  glVertex3f(outline[L], outline[B], z);
+		  glVertex3f(outline[L], outline[T], z);
+		  glVertex3f(outline[R], outline[T], z);
+		  glVertex3f(outline[R], outline[B], z);
+	   glEnd();
+	   glColor4f(color[0], color[1], color[2], color[3]);
+	   glBegin(GL_QUADS);
+		  glVertex3f(outline[L], outline[B], z);
+		  glVertex3f(outline[L], outline[T], z);
+		  glVertex3f(outline[R], outline[T], z);
+		  glVertex3f(outline[R], outline[B], z);
+	   glEnd();
+   } else {
+	   glBegin(GL_LINE_LOOP);
+		  glVertex3f(outline[L], outline[B], z);
+		  glVertex3f(outline[L], outline[T], z);
+		  glVertex3f(outline[R], outline[T], z);
+		  glVertex3f(outline[R], outline[B], z);
+	   glEnd();
+   }
+}
+
+
+void overlayApp::drawCorners()
+{
+   glLineWidth(2);
+
+
+   // top_left
+   if(activeCorners[TOP_LEFT] == 1)
+   {
+      glBegin(GL_LINE_STRIP);
+         glVertex3f(outline[L], outline[T]-cornerSize, z);
+         glVertex3f(outline[L]+cornerSize, outline[T]-cornerSize, z);
+         glVertex3f(outline[L]+cornerSize, outline[T], z);
+      glEnd();
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[L], outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[T], z+0.05);
+         glVertex3f(outline[L], outline[T], z+0.05);
+         glVertex3f(outline[L], outline[T]-cornerSize, z+0.05);
+      glEnd();
+   }
+
+   // top_right
+   if(activeCorners[TOP_RIGHT] == 1)
+   {
+      glBegin(GL_LINE_STRIP);
+         glVertex3f(outline[R]-cornerSize, outline[T], z);
+         glVertex3f(outline[R]-cornerSize, outline[T]-cornerSize, z);
+         glVertex3f(outline[R], outline[T]-cornerSize, z);
+      glEnd();
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[R]-cornerSize, outline[T], z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[R], outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[R], outline[T], z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[T], z+0.05);
+      glEnd();
+   }
+
+   // bottom_right
+   if(activeCorners[BOTTOM_RIGHT] == 1)
+   {
+      glColor4f(color[0], color[1], color[2], 0.5);
+      glBegin(GL_LINE_STRIP);
+         glVertex3f(outline[R]-cornerSize, outline[B], z);
+         glVertex3f(outline[R]-cornerSize, outline[B]+cornerSize, z);
+         glVertex3f(outline[R], outline[B]+cornerSize, z);
+      glEnd();
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[R]-cornerSize, outline[B], z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[R], outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[R], outline[B], z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[B], z+0.05);
+      glEnd();
+   }
+
+   // bottom_left
+   if(activeCorners[BOTTOM_LEFT] == 1)
+   {
+      glColor4f(color[0], color[1], color[2], 0.5);
+      glBegin(GL_LINE_STRIP);
+         glVertex3f(outline[L], outline[B]+cornerSize, z);
+         glVertex3f(outline[L]+cornerSize, outline[B]+cornerSize, z);
+         glVertex3f(outline[L]+cornerSize, outline[B], z);
+      glEnd();
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[L], outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[B], z+0.05);
+         glVertex3f(outline[L], outline[B], z+0.05);
+         glVertex3f(outline[L], outline[B]+cornerSize, z+0.05);
+      glEnd();
+   }
+}
+
+
+
+void overlayApp::drawTop()
+{
+   glColor4f(color[0], color[1], color[2], 0.5);
+   glLineWidth(2);
+
+   if(activeCorners[TOP] == 1)
+   {
+      glBegin(GL_LINES);
+         glVertex3f(outline[L]+cornerSize, outline[T], z);
+         glVertex3f(outline[L]+cornerSize, outline[T]-cornerSize, z);
+
+         glVertex3f(outline[L]+cornerSize, outline[T]-cornerSize, z);
+         glVertex3f(outline[R]-cornerSize, outline[T]-cornerSize, z);
+
+         glVertex3f(outline[R]-cornerSize, outline[T], z);
+         glVertex3f(outline[R]-cornerSize, outline[T]-cornerSize, z);
+      glEnd();
+
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[L]+cornerSize, outline[T], z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[T]-cornerSize, z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[T], z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[T], z+0.05);
+      glEnd();
+   }
+
+   if(activeCorners[BOTTOM] == 1)
+   {
+      glBegin(GL_LINES);
+         glVertex3f(outline[L]+cornerSize, outline[B], z);
+         glVertex3f(outline[L]+cornerSize, outline[B]+cornerSize, z);
+
+         glVertex3f(outline[L]+cornerSize, outline[B]+cornerSize, z);
+         glVertex3f(outline[R]-cornerSize, outline[B]+cornerSize, z);
+
+         glVertex3f(outline[R]-cornerSize, outline[B]+cornerSize, z);
+         glVertex3f(outline[R]-cornerSize, outline[B], z);
+      glEnd();
+
+
+      glColor4f(corner_color[0], corner_color[1],
+         corner_color[2], corner_color[3]);
+      glBegin(GL_POLYGON);
+         glVertex3f(outline[L]+cornerSize, outline[B], z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[B]+cornerSize, z+0.05);
+         glVertex3f(outline[R]-cornerSize, outline[B], z+0.05);
+         glVertex3f(outline[L]+cornerSize, outline[B], z+0.05);
+      glEnd();
+   }
+}
+
+
+
+
+int overlayApp::destroy()
+{
+   return 0;
+}
+
+
+
+int overlayApp::parseMessage(char *msg)
+{
+   int id, code;
+   sscanf(msg, "%d %d", &id, &code);
+
+   switch(code)
+   {
+      case DRAG: {
+         int dx, dy, cId;
+         sscanf(msg, "%d %d %d %d %d", &id, &code, &dx, &dy, &cId);
+         cId += 2;  // the corners in the interaction manager are smaller by 2
+         outline[L] += dx;
+         outline[R] += dx;
+         outline[T] += dy;
+         outline[B] += dy;
+         state = DRAG_STATE;
+         activeCorners[cId] = 1;
+         //fprintf(stderr, "\nDRAG (%d): %.1f %.1f %.1f %.1f", objectID, outline[L], outline[R], outline[T], outline[B]);
+         break;
+      }
+      case RESIZE: {
+         int dx,dy,cId;
+         state = RESIZE_STATE;
+         sscanf(msg, "%d %d %d %d %d", &id, &code, &dx, &dy, &cId);
+         cId += 2;  // the corners in the interaction manager are smaller by 2
+         if (cId == BOTTOM_LEFT)
+         {
+            outline[L] += dx;
+            outline[B] += dx/aspectRatio;
+         }
+         else if(cId == TOP_LEFT)
+         {
+            outline[L] += dx;
+            outline[T] -= dx/aspectRatio;
+         }
+         else if(cId == TOP_RIGHT)
+         {
+            outline[R] += dx;
+            outline[T] += dx/aspectRatio;
+         }
+         else if(cId == BOTTOM_RIGHT)
+         {
+            outline[R] += dx;
+            outline[B] -= dx/aspectRatio;
+         }
+         //fprintf(stderr, "\nRESIZE (%d): %.1f %.1f %.1f %.1f", objectID, outline[L], outline[R], outline[T], outline[B]);
+         activeCorners[cId] = 1;
+         break;
+      }
+      case RESET: {
+         int l,r,t,b,appZ,cs,dispId;
+         state = NORMAL_STATE;
+         sscanf(msg, "%d %d %d %d %d %d %d %d %d", &id, &code, &l, &r, &t, &b, &appZ, &cs, &dispId);
+         outline[L] = l;
+         outline[R] = r;
+         outline[T] = t;
+         outline[B] = b;
+         aspectRatio = (r-l)/float(t-b);
+         cornerSize = cs;
+         displayID = dispId;
+         color = border_color;
+         for(int i=0; i<7; i++)
+            activeCorners[i] = 0;
+         z = -(appZ + 0.1);  // negative cause sage does it this way...
+
+         //fprintf(stderr, "\nRESET (%d): %f %d %d %d %d %f", objectID, aspectRatio, l, r, t, b, z);
+         break;
+      }
+      case Z_CHANGE:{
+         int appZ;
+         sscanf(msg, "%d %d %d", &id, &code, &appZ);
+         z = -(appZ + 0.1);  // negative cause sage does it this way...
+         break;
+      }
+      case ON_CORNER: {
+         int cId, isOn;
+         sscanf(msg, "%d %d %d %d", &id, &code, &cId, &isOn);
+         cId += 2;  // the corners in the interaction manager are smaller by 2
+         activeCorners[cId] = isOn;
+         break;
+      }
+      case ON_APP: {
+		if (specialDevice){
+			int isOn;
+			sscanf(msg, "%d %d %d", &id, &code, &isOn);
+			if (isOn == 0)
+				border_color[3] = 0.0;
+			else if (isOn == 1)
+				border_color[3] = 0.3;
+			break;
+		}
+      }
+      case SPECIAL_DEVICE: {
+		int isSpecial;
+		sscanf(msg, "%d %d %d", &id, &code, &isSpecial);
+		if (isSpecial == 0){
+			specialDevice = false;
+			border_color[3] = 1.0;
+		} else if (isSpecial == 1) {
+			specialDevice = true;
+			border_color[0] = 0.5;
+			border_color[1] = 0.5;
+			border_color[2] = 1.0;
+			border_color[3] = 0.0;
+		}
+		break;
+      }
+   }
+
+   return 0;
+
+}
+
+
+
+
+
+
+
+
Index: trunk/src/testing/src/sageStreamer.cpp
===================================================================
--- trunk/src/testing/src/sageStreamer.cpp	(revision 4)
+++ trunk/src/testing/src/sageStreamer.cpp	(revision 4)
@@ -0,0 +1,288 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageStreamer.cpp - streaming pixels to displays
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageStreamer.h"
+#include "sageFrame.h"
+#include "streamInfo.h"
+#include "sageBlockPartition.h"
+
+sageStreamer::sageStreamer() : params(NULL), streamerOn(true), configID(0),
+      totalBandWidth(0), frameID(1), firstConfiguration(true), timeError(0.0) 
+{
+   //std::cerr << "init config ID " << configID << std::endl;
+   msgQueue.clear();
+   
+   reconfigMutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(reconfigMutex, NULL);
+   pthread_mutex_lock(reconfigMutex);
+}
+
+sageStreamer::~sageStreamer()
+{
+   if (params)
+      delete params;
+   
+   if (reconfigMutex)
+      free(reconfigMutex);
+      
+   msgQueue.clear();   
+}
+
+int sageStreamer::enqueMsg(char *data)
+{
+   if (!data) {
+      sage::printLog("sageStreamer::enqueMsg : string is NULL");
+      return -1;
+   }
+   
+   char *msgStr = new char[strlen(data)+1];   
+   strcpy(msgStr, data);
+   
+   if (!firstConfiguration) 
+      pthread_mutex_lock(reconfigMutex);
+   //std::cout << "enque stream info" << std::endl;
+   msgQueue.push_back(msgStr);
+   pthread_mutex_unlock(reconfigMutex);
+   
+   return 0;
+}
+
+int sageStreamer::initNetworks(char *data, bool localPort)
+{
+   char token[TOKEN_LEN];
+   sageToken tokenBuf(data);
+   tokenBuf.getToken(token);
+
+   // e.g.   rcvStreamPort 22000,  rcvNodeNum 1  131.193.78.140   0
+      
+   //std::cout << "connection info " << data << std::endl;
+   
+   int rcvPort = atoi(token) + (int)config.protocol;
+   fprintf(stderr, "sageStreamer::%s() : rcvPort = %d + %d = %d\n", __FUNCTION__, atoi(token), (int)config.protocol, rcvPort);
+   
+   sageTcpModule *tcpObj;
+   sageUdpModule *udpObj;
+
+   switch (config.protocol) {
+      case SAGE_TCP :
+         tcpObj = new sageTcpModule;
+         tcpObj->init(SAGE_SEND, rcvPort, nwCfg); // does nothing
+         nwObj = (streamProtocol *)tcpObj;
+         sage::printLog("sageStreamer::initNetworks : initialize TCP object"); 
+         break;
+      case SAGE_UDP :
+         udpObj = new sageUdpModule;
+         udpObj->init(SAGE_SEND, rcvPort, nwCfg); // start sendingThread
+         nwObj = (streamProtocol *)udpObj;
+         sage::printLog("sageStreamer::initNetworks : initialize UDP object");
+         break;
+      case LAMBDA_STREAM :
+         break;
+      default :
+         std::cerr << "sageStreamer::initNetworks() - error : no network protocol specified" << std::endl;
+         return -1;
+         break;   
+   }      
+
+   sage::printLog("sageStreamer::%s() : network object was initialized successfully", __FUNCTION__);
+   
+   connectToRcv(tokenBuf, localPort);
+   setupBlockPool();
+   nwObj->setFrameRate((double)config.frameRate);
+   streamTimer.reset();
+   
+   // starts the streamLoop
+   if (pthread_create(&thId, 0, nwThread, (void*)this) != 0) {
+      sage::printLog("sageBlockStreamer : can't create nwThread");
+   }
+   
+   return 0;
+}
+
+int sageStreamer::connectToRcv(sageToken &tokenBuf, bool localPort /* = false */)
+{
+   char token[TOKEN_LEN];
+   tokenBuf.getToken(token);
+   rcvNodeNum = atoi(token);
+   
+   params = new streamParam[rcvNodeNum];
+
+   for (int i=0; i<rcvNodeNum; i++) {
+      char rcvIP[SAGE_IP_LEN];
+      tokenBuf.getToken(rcvIP);
+
+      if (localPort) {
+         tokenBuf.getToken(token);
+         int port = atoi(token) + (int)config.protocol;
+         nwObj->setConfig(port);
+         sage::printLog("sageStreamer::%s() : Connecting to %s:%d, port is %d+%d",__FUNCTION__, rcvIP, port, atoi(token), (int)config.protocol);
+      }
+
+      tokenBuf.getToken(token);
+      params[i].nodeID = atoi(token);
+      params[i].active = false;
+      
+	// Check that a group can fit at least one block
+      if (blockSize>config.groupSize) {
+		config.groupSize = blockSize;
+		sage::printLog("sageStreamer::connectToRcv> increased config.groupSize to %d", config.groupSize);
+	}
+
+      char regMsg[REG_MSG_SIZE];
+      sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d %d",
+    		  config.streamType,
+    		  config.frameRate,
+    		  winID,
+    		  config.groupSize,
+    		  blockSize,
+    		  config.nodeNum,
+    		  (int)config.pixFmt,
+    		  config.blockX,
+    		  config.blockY,
+    		  config.totalWidth,
+    		  config.totalHeight,
+    		  config.fromBridgeParallel);
+
+      fprintf(stderr,"sageStreamer::%s() : connecting to rcv(s) with the msg [%s]\n", __FUNCTION__, regMsg);
+
+      // nwObj->connect() returns vector index. and the vector hold socketDescriptor
+      // so, params[i].rcvID represents vector index for the corresponding receiver.
+      params[i].rcvID = nwObj->connect(rcvIP, regMsg); // returns receiver ID
+
+      if (params[i].rcvID >= 0)
+         sage::printLog("sageStreamer::%s() : Connected to %s", __FUNCTION__, rcvIP);
+      else
+         sage::printLog("sageStreamer::%s() : Failed to connect to %s", __FUNCTION__, rcvIP);
+   }
+   
+   sage::printLog("sageStreamer::%s() : %d connections are established", __FUNCTION__, rcvNodeNum);
+      
+   return 0;
+}
+
+int sageStreamer::reconfigureStreams(char *msgStr)
+{
+   if (!partition) {
+      sage::printLog("sageStreamer::reconfigureStreams : block partition is not initialized");
+      return -1;
+   }   
+   partition->clearBlockTable();
+
+   for(int j=0; j<rcvNodeNum; j++) {   
+      params[j].active = false;
+   }
+
+   if (config.bridgeOn) {
+      std::cout << "config message " << msgStr << std::endl;
+      bStreamGrp.parseMessage(msgStr);
+      streamNum = bStreamGrp.streamNum;  
+   }
+   else {
+      // parsing the information of application window on tiled display
+      sGrp.parseMessage(msgStr);
+      sageRect imageRect(0, 0, config.totalWidth, config.totalHeight);
+      sGrp.addImageInfo(imageRect);
+
+      streamNum = sGrp.streamNum();
+   }
+
+   for(int j=0; j<rcvNodeNum; j++) {   
+      int blockNum = 0;
+      for(int i=0; i<streamNum; i++) {
+         if (config.bridgeOn) {
+            bridgeStreamInfo *sInfo = &bStreamGrp.streamList[i];
+
+            // pick connections for streaming
+            if (sInfo->receiverID == params[j].nodeID) {
+               std::cout << "map " << j << " " << sInfo->firstID << " , " << sInfo->lastID <<
+               std::endl;
+               blockNum += partition->setStreamInfo(j, sInfo->firstID, sInfo->lastID);
+            }
+         }
+         else {         
+            streamInfo *sInfo = sGrp.getStream(i);
+
+            // pick connections for streaming
+            if (sInfo->receiverID == params[j].nodeID) {
+               blockNum += partition->setStreamInfo(j, sInfo->imgCoord);
+            }
+         }
+      }
+      
+      if (blockNum > 0)
+         nwObj->setFrameSize(params[j].rcvID, blockNum*blockSize);
+      else
+         nwObj->setFrameSize(params[j].rcvID, blockSize);
+   }         
+      
+   configID++;
+      
+   return 0;
+}
+
+void sageStreamer::checkInterval()
+{
+   double curTime = streamTimer.getTimeUS();
+	if(curTime == 0) return;   
+   double maxErr = interval*MAX_INTERVAL_ERROR;
+   double err = curTime - (interval - timeError);
+
+   while (err < -maxErr) {
+      sage::usleep(SYNC_TIMEOUT);
+      curTime = streamTimer.getTimeUS();
+      err = curTime - (interval - timeError);
+   }
+      
+   if (timeError > maxErr)
+      timeError = 0.0;
+   else
+      timeError = err;   
+
+   streamTimer.reset();   
+}
+
+void* sageStreamer::nwThread(void *args)
+{
+   sageStreamer *This = (sageStreamer *)args;
+   This->streamLoop();
+      
+   pthread_exit(NULL);
+   return NULL;
+}
Index: trunk/src/testing/src/tileConfig.cpp
===================================================================
--- trunk/src/testing/src/tileConfig.cpp	(revision 4)
+++ trunk/src/testing/src/tileConfig.cpp	(revision 4)
@@ -0,0 +1,598 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: tileConfig.cpp - Contains all class details/implementation 
+ *       for building a description of a tile display system, at run time
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "tileConfig.h"
+#include "sageConfig.h"
+
+displayNode::displayNode() : dimX(0), dimY(0), port(0) 
+{
+   dimX = 0, dimY = 0;
+   memset((void *)ip, 0, SAGE_IP_LEN);
+   tiles.clear();
+   sprintf(Xdisp, "0.0");
+   winX = 0, winY = 0;
+}
+
+displayNode::~displayNode()
+{
+   for (int i=0; i<tiles.size(); i++) {
+      tiles[i] = NULL;
+   }      
+   tiles.clear();
+}
+
+int displayNode::computeDimension()
+{
+   dimX = dimY = 1;
+   
+   for (int i=1; i<tiles.size(); i++) {
+      bool uniqueX = true, uniqueY = true;   
+      for (int j=0; j<i; j++) {
+         uniqueX = uniqueX && (tiles[i]->xIndex != tiles[j]->xIndex);
+         uniqueY = uniqueY && (tiles[i]->yIndex != tiles[j]->yIndex);
+      }
+      if (uniqueX)
+         dimX++;
+      if (uniqueY)
+         dimY++;   
+   }
+   
+   return 0;
+}
+
+audioNode::audioNode() :
+   sampleFmt(SAGE_SAMPLE_FLOAT32), samplingRate(44100), channels(2), framePerBuffer(512), deviceId(-1)
+{
+   memset((void *)ip, 0, SAGE_IP_LEN);
+   streamIPs.clear();
+   //tiles.clear();
+}
+
+audioNode::~audioNode()
+{
+   for (int i=0; i<streamIPs.size(); i++) {
+      if (streamIPs[i]) {
+         delete [] streamIPs[i];
+         //free streamIPs[i];
+         streamIPs[i] = NULL;
+      }
+   }
+   streamIPs.clear();
+}
+
+
+virtualDesktop::virtualDesktop() : dimX(0), dimY(0), table(false), audioServer(false) 
+{
+   tileList.clear();
+   displayCluster.clear();
+   audioCluster.clear();
+   sprintf(globalType.name, "global");
+   memset(masterIP, 0, SAGE_IP_LEN);
+   masterIP[0] = '\0';
+   audioDir[0] = '\0';
+}
+
+int virtualDesktop::updateDesktop()
+{
+   int *xOffset = new int[dimY];
+   int *yOffset = new int[dimX];
+
+   for (int yIdx = 0; yIdx < dimY; yIdx++)
+      xOffset[yIdx] = x;
+      
+   for (int xIdx = 0; xIdx < dimX; xIdx++) {
+      yOffset[xIdx] = y;
+      
+      for (int i=0; i<tileList.size(); i++) {
+         if (tileList[i]->xIndex == xIdx) {
+            int leftMullion = (int)floor(tileList[i]->tileType->left*tileList[i]->tileType->PPI+0.5);
+            int rightMullion = (int)floor(tileList[i]->tileType->right*tileList[i]->tileType->PPI+0.5);
+         
+            if (xIdx > 0)
+               xOffset[tileList[i]->yIndex] += leftMullion;
+            
+            //xOffset[tileList[i]->yIndex] += tileList[i]->offsetX;   
+            
+            tileList[i]->x = xOffset[tileList[i]->yIndex];
+            
+            if (xIdx < dimX-1)
+               xOffset[tileList[i]->yIndex] += tileList[i]->width + rightMullion;
+            else
+               xOffset[tileList[i]->yIndex] += tileList[i]->width;
+         }
+      }
+   }
+   
+   for (int yIdx = 0; yIdx < dimY; yIdx++) {
+      for (int i=0; i<tileList.size(); i++) {
+         if (tileList[i]->yIndex == yIdx) {
+            int topMullion = (int)floor(tileList[i]->tileType->top*tileList[i]->tileType->PPI+0.5);
+            int bottomMullion = (int)floor(tileList[i]->tileType->bottom*tileList[i]->tileType->PPI+0.5);
+
+            if (yIdx > 0)
+               yOffset[tileList[i]->xIndex] += bottomMullion;
+            
+            //yOffset[tileList[i]->xIndex] += tileList[i]->offsetY;
+               
+            tileList[i]->y = yOffset[tileList[i]->xIndex];
+            
+            if (yIdx < dimY-1)
+               yOffset[tileList[i]->xIndex] += tileList[i]->height + topMullion;
+            else   
+               yOffset[tileList[i]->xIndex] += tileList[i]->height;
+         }
+      }
+   }
+
+   width = xOffset[dimY-1];
+   height = yOffset[dimX-1];
+   
+   for (int i=0; i<tileList.size(); i++) {
+      tileList[i]->x += tileList[i]->offsetX;
+      tileList[i]->y += tileList[i]->offsetY;
+      (*(sageRect *)tileList[i]) /= (*(sageRect *)this);
+   }
+   return 0;
+}
+
+bool virtualDesktop::parseConfigfile(FILE *fp, bool configBegin)
+{
+   char token[TOKEN_LEN];
+   displayNode *newNode = NULL;
+   tileInfo *newTile = NULL;
+   bool fileContinue = false;
+   bool parseNodeInfo = false;
+   
+   while (getToken(fp, token) != EOF) {
+      sage::toupper(token);
+      if (strcmp(token, "TILEDISPLAY") == 0) {
+         if (!configBegin)
+            configBegin = true;
+         else {
+            fileContinue = true;
+            break;   
+         }   
+      }
+      else if (strcmp(token, "DIMENSIONS") == 0) {
+         getToken(fp, token);
+         dimX = atoi(token);
+         getToken(fp, token);
+         dimY = atoi(token);
+      }
+      else if (strcmp(token, "MULLIONS") == 0) {
+         getToken(fp, token);
+         globalType.left = (float)atof(token);
+         getToken(fp, token);
+         globalType.right = (float)atof(token);
+         getToken(fp, token);
+         globalType.bottom = (float)atof(token);
+         getToken(fp, token);
+         globalType.top = (float)atof(token);
+      }
+      else if (strcmp(token, "RESOLUTION") == 0) {
+         getToken(fp, token);
+         globalType.width = atoi(token);
+         getToken(fp, token);
+         globalType.height = atoi(token);
+      }
+      else if (strcmp(token, "PPI") == 0) {
+         getToken(fp, token);
+         globalType.PPI = atoi(token);
+      }
+      //else if (strcmp(token, "MASTER") == 0) {
+      //   getToken(fp, masterIP);
+      //}
+      //else if (strcmp(token, "DISPLAYID") == 0) {
+      //   getToken(fp, token);
+      //   displayID = atoi(token);
+      //}
+      else if (strcmp(token, "TABLE") == 0) {
+         getToken(fp, token);
+         sage::toupper(token);
+         table = (strcmp(token, "YES") == 0);
+      }
+      else if (strcmp(token, "DISPLAYNODE") == 0) {
+         if (parseNodeInfo && newNode) {
+            if (newNode->dimX*newNode->dimY == 0)
+               newNode->computeDimension();
+            
+            displayCluster.push_back(newNode);               
+         }
+         
+         parseNodeInfo = true;   
+         newNode = new displayNode;
+      }
+      else if (strcmp(token, "IP") == 0) {
+         getToken(fp, token);
+         char *ipToken = strtok(token, ":");
+         if (ipToken) {
+            strcpy(newNode->ip, ipToken);
+            ipToken = strtok(NULL, ":");
+            if (ipToken) {
+               newNode->port = atoi(ipToken);
+               ipToken = strtok(NULL, ":");
+               if (ipToken) 
+                  strcpy(newNode->Xdisp, ipToken);
+            }
+         }
+         else {
+            sage::printLog("virtualDesktop::parseConfigfile : no IP address specified for a node");
+            return false;
+         }   
+      }
+      else if (strcmp(token, "FORWARD") == 0) {
+         getToken(fp, token);
+         char *ipToken = strtok(token, ":");
+         if (ipToken) {
+            strcpy(newNode->forwardIP, ipToken);
+            ipToken = strtok(NULL, ":");
+            if (ipToken) {
+               newNode->forwardPort = atoi(ipToken);
+            }
+         }
+         else {
+            sage::printLog("virtualDesktop::parseConfigfile : no forward infoIP specified for a node");
+            return false;
+         }   
+      }
+      else if (strcmp(token, "MONITORS") == 0) {
+         getToken(fp, token);
+         int tileNum = atoi(token);
+         for (int i=0; i<tileNum; i++) {
+            getToken(fp, token);
+            if (strcmp(token, "(") != 0) {
+               sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \"(\" expected");
+               return false;
+            }
+            
+            newTile = new tileInfo;
+            getToken(fp, token);
+            newTile->xIndex = atoi(token);
+            getToken(fp, token);
+            newTile->yIndex = atoi(token);
+
+            getToken(fp, token);
+            if (strcmp(token, ")") != 0) {
+               newTile->offsetX = atoi(token);
+               getToken(fp, token);
+               newTile->offsetY = atoi(token);
+               
+               getToken(fp, token);
+               if (strcmp(token, ")") != 0) {
+                  sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \")\" expected");
+                  return false;
+               }   
+            }
+            
+            newTile->tileType = &globalType;
+            newTile->nodeID = displayCluster.size();
+            newTile->tileID = tileList.size();
+            newTile->width = newTile->tileType->width;
+            newTile->height = newTile->tileType->height;
+            tileList.push_back(newTile);
+            newNode->tiles.push_back(newTile);
+         } // end for
+      }
+      else if (strcmp(token, "DIM") == 0) {
+         getToken(fp, token);
+         if (strcmp(token, "(") != 0) {
+            sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \"(\" expected");
+            return false;
+         }
+
+         getToken(fp, token);
+         newNode->dimX = atoi(token);
+         getToken(fp, token);
+         newNode->dimY = atoi(token);
+
+         getToken(fp, token);
+         if (strcmp(token, ")") != 0) {
+            sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \")\" expected");
+            return false;
+         }
+      }
+      else if (strcmp(token, "POS") == 0) {
+         getToken(fp, token);
+         if (strcmp(token, "(") != 0) {
+            sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \"(\" expected");
+            return false;
+         }
+
+         getToken(fp, token);
+         newNode->winX = atoi(token);
+         getToken(fp, token);
+         newNode->winY = atoi(token);
+         
+         getToken(fp, token);
+         if (strcmp(token, ")") != 0) {
+            sage::printLog("virtualDesktop::parseConfigfile : invalid file format - \")\" expected");
+            return false;
+         }
+      }   
+      else if (strcmp(token, "DISPLAY_CONNECTIONS") == 0) {
+         fileContinue = false;
+         break;
+      }   
+   }      
+   
+   if (parseNodeInfo) {
+      if (newNode->dimX*newNode->dimY == 0)
+         newNode->computeDimension();
+
+      displayCluster.push_back(newNode);               
+   }
+
+   updateDesktop();
+   
+   return fileContinue;
+}
+
+void virtualDesktop::locateApp(appInExec *app, displayConnection *connection, int idx)
+{
+   // a single table display, multiple vertical displays
+   
+   sageRect newLayout = *(sageRect *)app;
+   
+   if (connection) {
+      sageRect neighbor = *(sageRect *)connection->displays[1-idx];
+      int offset = connection->offset;
+      
+      if (table) {
+         // vertical to table
+         switch(connection->edges[idx]) {
+            case LEFT_EDGE:
+               newLayout.rotate(CCW_90);
+               newLayout.x = 0;
+               offset = connection->offset*(1-idx*2);
+               newLayout.y = app->x - neighbor.halfWidth() + halfHeight() + offset;
+               break;
+            case RIGHT_EDGE:
+               newLayout.rotate(CCW_270);
+               newLayout.x = width - newLayout.width;
+               newLayout.y = halfHeight() + offset - (app->x - neighbor.halfWidth())
+                        - newLayout.height;
+               break;
+            case BOTTOM_EDGE:
+               newLayout.rotate(CCW_180);
+               newLayout.x = halfWidth() + offset - (app->x - neighbor.halfWidth())
+                        - newLayout.width;
+               newLayout.y = 0;
+               break;
+            case TOP_EDGE:
+               offset = connection->offset*(1-idx*2);
+               newLayout.x = halfWidth() + offset + (app->x - neighbor.halfWidth());
+               newLayout.y = width - newLayout.height;
+               break;   
+         }      
+      }
+      else {
+         // table to vertical
+         if (connection->displays[1-idx]->table) {
+            newLayout.resetOrientation();
+            switch(connection->edges[1-idx]) {
+               case LEFT_EDGE:
+                  offset = connection->offset*(1-idx*2);
+                  newLayout.x = halfWidth() + offset - newLayout.halfWidth() 
+                        + app->centerY() - neighbor.halfHeight();
+                  break;
+               case RIGHT_EDGE:
+                  newLayout.x = halfWidth() + offset - newLayout.halfWidth() 
+                        - (app->centerY() - neighbor.halfHeight());
+                  break;
+               case BOTTOM_EDGE:
+                  newLayout.x = halfWidth() + offset - newLayout.halfWidth() 
+                        - (app->centerX() - neighbor.halfWidth());
+                  break;
+               case TOP_EDGE:
+                  offset = connection->offset*(1-idx*2);               
+                  newLayout.x = halfWidth() + offset - newLayout.halfWidth() 
+                        + (app->centerX() - neighbor.halfWidth());
+                  break;
+            }
+            
+            newLayout.y = 0;
+         }
+         else {
+            // vertical to vertical
+            switch(connection->edges[idx]) {
+               case LEFT_EDGE:
+                  newLayout.x = 0;
+                  break;
+               case RIGHT_EDGE:
+                  newLayout.x = width - newLayout.width;
+                  break;
+            }      
+                  
+            offset = connection->offset*(1-idx*2);
+            newLayout.y = halfHeight() + offset + app->y - neighbor.halfHeight();
+         }
+      }
+   }
+
+   if (newLayout.centerX() < 0)
+      newLayout.x = 1 - newLayout.halfWidth();
+   else if (newLayout.centerX() > width)
+      newLayout.x = width - newLayout.halfWidth() - 1;   
+      
+   if (newLayout.x < 0 && newLayout.x + newLayout.width > width) {
+      float leftScale = (float)newLayout.centerX()/(newLayout.halfWidth()+1); 
+      float rightScale = (float)(width-newLayout.centerX())/(newLayout.halfWidth()+1);
+      float scaleRatio = MAX(leftScale, rightScale);
+      newLayout.scale(scaleRatio);
+   }   
+   
+   if (newLayout.centerY() < 0)
+      newLayout.y = 1 - newLayout.halfHeight();
+   else if (newLayout.centerY() > height)
+      newLayout.y = height - newLayout.halfHeight() - 1;
+      
+   if (newLayout.y < 0 && newLayout.y + newLayout.height > height) {
+      float bottomScale = (float)newLayout.centerY()/(newLayout.halfHeight()+1); 
+      float topScale = (float)(height-newLayout.centerY())/(newLayout.halfHeight()+1);
+      float scaleRatio = MAX(bottomScale, topScale);
+      newLayout.scale(scaleRatio);
+   }   
+   
+   if (connection) {
+      switch(connection->edges[idx]) {
+         case LEFT_EDGE:
+            newLayout.x = 0;
+            break;
+         case RIGHT_EDGE:
+            newLayout.x = width - newLayout.width;
+            break;
+         case BOTTOM_EDGE:
+            newLayout.y = 0;
+            break;
+         case TOP_EDGE:
+            newLayout.y = width - newLayout.height;
+            break;   
+      }
+   }
+   
+   *(sageRect *)app = newLayout;
+}
+
+int virtualDesktop::parseAudioConfigfile(FILE *fp, bool configBegin)
+{
+   char token[TOKEN_LEN];
+   audioNode *newNode = NULL;
+   bool fileContinue = false;
+   bool parseNodeInfo = false;
+
+   sageSampleFmt sampleFmt;
+   long samplingRate;
+   int  channels;
+   int  framePerBuffer;
+   int ip_length = SAGE_IP_LEN;
+   char *attachedIP;
+   int  deviceId=-1;
+
+   while (getToken(fp, token) != EOF) {
+      sage::toupper(token);
+      if (strcmp(token, "AUDIOTILEDISPLAY") == 0) {
+         if (!configBegin)
+            configBegin = true;
+         else {
+            fileContinue = true;
+            break;
+         }
+      }
+      else if (strcmp(token, "SAMPLEFORMAT") == 0) {
+         getToken(fp, token);
+         sage::tolower(token);
+         if (strcmp(token, "float32") == 0) {
+            sampleFmt = SAGE_SAMPLE_FLOAT32;
+         }
+         else if (strcmp(token, "int16") == 0) {
+            sampleFmt = SAGE_SAMPLE_INT16;
+         }
+         else if (strcmp(token, "int8") == 0) {
+            sampleFmt = SAGE_SAMPLE_INT8;
+         }
+         else if (strcmp(token, "uint8") == 0) {
+            sampleFmt = SAGE_SAMPLE_UINT8;
+         }
+      }
+      else if (strcmp(token, "SAMPLINGRATE") == 0) {
+         getToken(fp, token);
+         samplingRate = atoi(token);
+      }
+      else if (strcmp(token, "CHANNELS") == 0) {
+         getToken(fp, token);
+         channels = atoi(token);
+      }
+      else if (strcmp(token, "FRAMEPERBUFFER") == 0) {
+         getToken(fp, token);
+         framePerBuffer = atoi(token);
+      }
+      else if (strcmp(token, "DEVICEID") == 0) {
+         getToken(fp, token);
+         deviceId = atoi(token);
+      }
+      else if (strcmp(token, "AUDIONODE") == 0) {
+         if (parseNodeInfo && newNode) {
+            audioCluster.push_back(newNode);
+         }
+
+         parseNodeInfo = true;
+         newNode = new audioNode;
+      }
+      else if (strcmp(token, "IP") == 0) {
+         if(newNode) {
+            getToken(fp, newNode->ip);
+            newNode->sampleFmt = sampleFmt;
+            newNode->samplingRate = samplingRate;
+            newNode->channels = channels;
+            newNode->framePerBuffer = framePerBuffer;
+            newNode->deviceId = deviceId;
+         }
+      }
+      else if (strcmp(token, "ATTACH") == 0) {
+         if(newNode) {
+            getToken(fp, token);
+            int nodeNum = atoi(token);
+
+            for (int i=0; i<nodeNum; i++) {
+               attachedIP = (char*) malloc(ip_length * sizeof(char));
+               getToken(fp, attachedIP);
+               newNode->streamIPs.push_back(attachedIP);
+               sage::printLog("------------> attached node : %d", attachedIP);
+            }
+
+         }
+      }
+      else if (strcmp(token, "AUDIODIR") == 0) {
+         getToken(fp, audioDir);
+         audioServer = true;
+      }   
+   }
+
+
+   if (parseNodeInfo && newNode) {
+      audioCluster.push_back(newNode);
+   }
+
+   if (fileContinue)
+         return 1;
+   else
+         return 0;
+}
Index: trunk/src/testing/src/sageBlockPartition.cpp
===================================================================
--- trunk/src/testing/src/sageBlockPartition.cpp	(revision 4)
+++ trunk/src/testing/src/sageBlockPartition.cpp	(revision 4)
@@ -0,0 +1,275 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlockPartition.cpp - handling block partition info
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBlockPartition.h"
+
+sageBlockPartition::sageBlockPartition(int bw, int bh, int iw, int ih) : blockWidth(bw), 
+      blockHeight(bh), entryNum(0) 
+{
+   x = y = 0;
+   width = iw;
+   height = ih;
+   rowNum = (int)ceil((float)height/blockHeight);
+   colNum = (int)ceil((float)width/blockWidth);
+   totalBlockNum = rowNum*colNum;
+   blockTable = NULL;
+}
+
+void sageBlockPartition::initBlockTable()
+{
+   blockTable = new pixelBlockMap*[totalBlockNum];
+   for (int i=0; i<totalBlockNum; i++)
+      blockTable[i] = NULL;
+}      
+
+void sageBlockPartition::getBlock(int id, sagePixelBlock &block)
+{
+   if (id > totalBlockNum)
+      sage::printLog("sageBlockPartition::getBlock : block ID %d is out of scope", id);
+      
+   int row = id/colNum;
+   int col = id%colNum;
+   block.x = col*blockWidth;
+   block.y = row*blockHeight;
+   block.width = blockWidth;
+   block.height = blockHeight;
+   block.setID(id);
+}
+
+void sageBlockPartition::setViewPort(sageRect &rect) 
+{
+   viewPort = rect; 
+   vOffsetX = viewPort.x/blockWidth;
+   vOffsetY = viewPort.y/blockHeight;
+   blockLayout.x = vOffsetX*blockWidth;
+   blockLayout.y = vOffsetY*blockHeight;
+   int rightBound = (int)ceil((float)(viewPort.x + viewPort.width)/blockWidth)*blockWidth;
+   int topBound = (int)ceil((float)(viewPort.y + viewPort.height)/blockHeight)*blockHeight;
+   blockLayout.width = rightBound - blockLayout.x;
+   blockLayout.height = topBound - blockLayout.y;
+   vRowNum = blockLayout.height/blockHeight;
+   vColNum = blockLayout.width/blockWidth;
+   blockNum = vRowNum * vColNum;
+}
+
+int sageBlockPartition::getVisibleBlockID(int idx)
+{
+   if (idx >= blockNum) {
+      sage::printLog("sageBlockPartition::getVisbleBlockID : index is out of scope");
+      return -1;
+   }
+   
+   int row = idx/vColNum;
+   int col = idx%vColNum;
+   int blockID = (vOffsetY+row)*colNum + vOffsetX+col;
+   
+   return blockID;
+}
+
+// get blocks within or on the edges of the viewport
+// blocks on the edges are cropped
+void sageBlockPartition::getVisibleBlock(int idx, sagePixelBlock &block)
+{
+   int blockID = getVisibleBlockID(idx);
+   if (blockID >= 0) {
+      getBlock(blockID, block);
+      block.crop(viewPort);
+   }   
+}
+
+void sageBlockPartition::adjustBlockCoord(sagePixelBlock &block)
+{
+   sagePixelBlock stdBlock;
+   getBlock(block.getID(), stdBlock);
+   block.moveOrigin((sageRect &)stdBlock);
+}
+
+void sageBlockPartition::genBlockTable(int monIdx)
+{
+   for (int i=0; i<blockNum; i++) {
+      blockMontageMap *map = new blockMontageMap;
+      
+      map->blockID = getVisibleBlockID(i);
+      map->infoID = monIdx;
+      
+      sagePixelBlock stdBlock;
+      getBlock(map->blockID, stdBlock);
+      stdBlock.moveOrigin(blockLayout);
+      map->x = stdBlock.x;
+      map->y = stdBlock.y;
+      
+      insertBlockMap(map);
+   }
+}
+
+int sageBlockPartition::setStreamInfo(int infoID, sageRect &window)
+{
+   setViewPort(window);
+   int mapNum = 0;
+   
+   for (int i=0; i<blockNum; i++) {
+      pixelBlockMap *map = new pixelBlockMap;
+      map->blockID = getVisibleBlockID(i);
+      map->infoID = infoID;
+      if (insertBlockMap(map))
+         mapNum++;
+   }
+   
+   return mapNum;   
+}
+
+int sageBlockPartition::setStreamInfo(int infoID, int begin, int end)
+{
+   if (begin > end) {
+      sage::printLog("sageBlockPartition::setStreamInfo : invalid block ID scope");
+      return -1;
+   }
+   
+   begin = MIN(totalBlockNum, begin);
+   end = MIN(totalBlockNum, end);
+      
+   int mapNum = 0;
+   for (int i=begin; i<=end; i++) {
+      pixelBlockMap *map = new pixelBlockMap;
+      map->blockID = i;
+      map->infoID = infoID;
+      if (insertBlockMap(map))
+         mapNum++;
+   }
+   
+   return mapNum;
+}
+
+bool sageBlockPartition::insertBlockMap(pixelBlockMap *map)
+{
+   if (!map) {
+      sage::printLog("sageBlockPartition::insertBlockMap : block map is NULL");
+      return false;
+   }   
+      
+   int index = map->blockID;
+   if (index >= totalBlockNum) {
+      sage::printLog("sageBlockPartition::insertBlockMap : blockID is out of scope");
+      return false;
+   }
+      
+   if (!blockTable) {
+      sage::printLog("blockTable is not initialized");
+      return false;
+   }   
+   
+   if (blockTable[index] == NULL) {
+      blockTable[index] = map;
+      blockTable[index]->count = 1;
+      entryNum++;
+   }   
+   else {
+      pixelBlockMap *iter = blockTable[index];
+      if (iter->infoID == map->infoID) {
+         delete map;
+         return false;
+      }
+         
+      while(iter->next) { 
+         iter = iter->next;
+         if (iter->infoID == map->infoID) {
+            delete map;
+            return false;
+         }   
+      }      
+      iter->next = map;
+      blockTable[index]->count++;
+   }
+   
+   return true;
+}
+
+pixelBlockMap* sageBlockPartition::getBlockMap(int blockID)
+{
+   if (blockID >= totalBlockNum) {
+      sage::printLog("sageBlockPartition::getBlockMap : blockID %d is out of scope", blockID);
+      return NULL;
+   }
+
+   if (!blockTable) {
+      sage::printLog("blockTable is not initialized");
+      return NULL;
+   }
+      
+   return blockTable[blockID];
+}
+
+void sageBlockPartition::clearBlockTable()
+{
+   if (!blockTable) {
+      sage::printLog("blockTable is not initialized"); 
+      return;
+   }
+   
+   for (int i=0; i<totalBlockNum; i++) {
+      pixelBlockMap *iter = blockTable[i];
+      while(iter) {
+         pixelBlockMap *map = iter;
+         iter = iter->next;
+         delete map;
+      }
+      blockTable[i] = NULL;
+   }
+   
+   entryNum = 0;
+}
+
+void sageBlockPartition::setTileLayout(sageRect tileRect)
+{
+   tileRect.normalize(displayLayout);
+   sageRect renderingLayout = (*(sageRect*)this);
+   sageRect imgRect = renderingLayout*tileRect;
+   setViewPort(imgRect);
+}
+
+// get block position in block layout
+void sageBlockPartition::getBlockPosition(sagePixelBlock &block)
+{
+   sagePixelBlock stdBlock;
+   getBlock(block.getID(), stdBlock);
+   stdBlock.moveOrigin(blockLayout);
+   block.translate(stdBlock);
+}
+
Index: trunk/src/testing/src/sageBlockPool.cpp
===================================================================
--- trunk/src/testing/src/sageBlockPool.cpp	(revision 4)
+++ trunk/src/testing/src/sageBlockPool.cpp	(revision 4)
@@ -0,0 +1,999 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlockPool.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBlockPool.h"
+#include "sageBlock.h"
+
+const int sageBlockGroup::PIXEL_DATA    = 1;
+const int sageBlockGroup::CONFIG_UPDATE = 2;
+const int sageBlockGroup::END_FRAME     = 3;
+
+sageBlockGroup::sageBlockGroup(int blkSize, int grpSize, char opt) : frameSize(0),
+   flag(sageBlockGroup::PIXEL_DATA), blockNum(0), frameID(0), refCnt(0), deRefCnt(0)
+{
+   blockSize = blkSize;
+   int bufLen = grpSize / blkSize; // # of blocks in this group
+
+   if (opt & GRP_CIRCULAR) {
+      buf = new sageCircBufSingle(bufLen, true);
+   }
+   else {
+      buf = new sageSerialBuf(bufLen);
+   }
+
+   if (opt & GRP_MEM_ALLOC) {
+      for (int i=0; i<bufLen; i++) {
+         sagePixelBlock *newBlock = new sagePixelBlock(blkSize);
+         if (!newBlock) {
+            sage::printLog("sageBlockGroup::sageBlockGroup : fail to create a new block");
+            break;
+         }
+
+         newBlock->setGroup(this);
+
+         if (!buf->pushBack((sageBufEntry)newBlock)) {
+            sage::printLog("sageBlockGroup::sageBlockGroup : fail to add a block");
+            break;
+         }
+      }
+      memAlloc = true;
+   }
+   else {
+      memAlloc = false;
+   }
+
+   if (opt & GRP_USE_IOV) {
+#ifdef WIN32
+      iovs = new WSABUF[bufLen+1];
+#else
+      iovs = new struct iovec[bufLen+1];
+#endif
+	  if (memAlloc)
+         genIOV();
+   }
+   else
+      iovs = NULL;
+}
+
+bool sageBlockGroup::pushBack(sagePixelBlock* block)
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::pushBack : block buffer is NULL");
+      return false;
+   }
+
+   if (!buf->pushBack((sageBufEntry)block)) {
+      //sage::printLog("sageBlockGroup::pushBack : block buffer is full");
+      return false;
+   }
+
+   return true;
+}
+
+sagePixelBlock* sageBlockGroup::front()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::front : block buffer is NULL");
+      return NULL;
+   }
+
+   return (sagePixelBlock *)buf->front();
+}
+
+bool sageBlockGroup::next()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::next : block buffer is NULL");
+      return false;
+   }
+
+   if (!buf->next())
+      sage::printLog("sageBlockGroup::next : block buffer is empty");
+
+   return true;
+}
+
+void sageBlockGroup::resetGrp()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::resetGrp : block buffer is NULL");
+      return;
+   }
+
+   buf->reset();
+}
+
+void sageBlockGroup::resetIdx()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::resetIdx : block buffer is NULL");
+      return;
+   }
+
+   buf->resetIdx();
+}
+
+bool sageBlockGroup::isEmpty()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::isEmpty : block buffer is NULL");
+      return true;
+   }
+
+   return buf->isEmpty();
+}
+
+bool sageBlockGroup::isFull()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::isFull : block buffer is NULL");
+      return false;
+   }
+
+   return buf->isFull();
+}
+
+int sageBlockGroup::size()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::size : block buffer is NULL");
+      return -1;
+   }
+
+   return buf->size();
+}
+
+int sageBlockGroup::getBlockNum()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::getBlockNum : block buffer is NULL");
+      return -1;
+   }
+
+   return buf->getEntryNum();
+}
+
+sagePixelBlock* sageBlockGroup::operator[] (int idx)
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::operator[] : block buffer is NULL");
+      return NULL;
+   }
+
+   return (sagePixelBlock *)(*buf)[idx];
+}
+
+int sageBlockGroup::returnBlock(sagePixelBlock *block)
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::returnBlock : block buffer is NULL");
+      return -1;
+   }
+
+   if (block && block->dereference() == 0) {
+      if (!buf->pushBack((sageBufEntry)block)) {
+         return -1;
+      }
+   }
+   
+   return 0;
+}
+
+int sageBlockGroup::returnBlocks(sageBlockGroup* grp)
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::returnBlocks : block buffer is NULL");
+      return -1;
+   }
+
+   int retVal = -1;
+
+   for (int i=0; i<grp->buf->getEntryNum(); i++) {
+      sagePixelBlock *pBlock = (sagePixelBlock *)(*grp->buf)[i];
+      if (pBlock && pBlock->dereference() == 0) {
+         if (!buf->pushBack((sageBufEntry)pBlock)) {
+            retVal = i;
+            break;
+         }
+      }
+   }
+
+   return retVal;
+}
+
+bool sageBlockGroup::setRefCnt()
+{
+   refCnt = 0;
+   deRefCnt = 0;
+
+   return true;
+}
+
+bool sageBlockGroup::genIOV()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::genIOV : block buffer is NULL");
+      return false;
+   }
+
+   if (!iovs) {
+      sage::printLog("sageBlockGroup::genIOV : iovec is not enabled");
+      return false;
+   }
+
+#ifdef WIN32
+   iovs[0].buf = header;
+   iovs[0].len = GROUP_HEADER_SIZE;
+#else
+   iovs[0].iov_base = header;
+   iovs[0].iov_len = GROUP_HEADER_SIZE;
+#endif
+   blockNum = buf->getEntryNum();
+   for (int i=0; i<blockNum; i++) {
+      sagePixelBlock *block = (sagePixelBlock *)(*buf)[i];
+#ifdef WIN32
+      iovs[i+1].buf = block->getBuffer();
+      iovs[i+1].len = blockSize;
+#else
+      iovs[i+1].iov_base = block->getBuffer();
+      iovs[i+1].iov_len = blockSize;
+#endif
+   }
+
+   return true;
+}
+
+int sageBlockGroup::sendData(int sockFd)
+{
+   if (!iovs) {
+      sage::printLog("sageBlockGroup::sendData : iovec is not enabled");
+      return -1;
+   }
+
+   int sendSize = 0;
+   sprintf(header, "%d %d %d", blockNum, frameID, configID);
+
+   //std::cout << "send " << header << std::endl;
+   //for (int i=1; i<=blockNum; i++)
+   //   std::cout << "header " << (char *)iovs[i].iov_base << std::endl;
+
+   int writtenBlocks = 0, bOffset = 0;
+   int iovNum = blockNum+1;
+
+   while (writtenBlocks < iovNum) {
+      int writtenSize = 0;
+
+#ifdef WIN32
+	  if (bOffset > 0) {
+		 iovs[writtenBlocks].buf = (char *)(iovs[writtenBlocks].buf) + bOffset;
+         iovs[writtenBlocks].len -= bOffset;
+      }
+
+	  DWORD WSAFlags = 0;
+      ::WSASend(sockFd, iovs+writtenBlocks, iovNum-writtenBlocks, (DWORD*)&writtenSize,
+            WSAFlags, NULL, NULL);
+
+	  if (bOffset > 0) {
+		 iovs[writtenBlocks].buf = (char *)(iovs[writtenBlocks].buf) - bOffset;
+         iovs[writtenBlocks].len += bOffset;
+	  }
+#else
+	  if (bOffset > 0) {
+		 iovs[writtenBlocks].iov_base = (char *)(iovs[writtenBlocks].iov_base) + bOffset;
+         iovs[writtenBlocks].iov_len -= bOffset;
+	  }
+
+	  writtenSize = ::writev(sockFd, iovs+writtenBlocks, iovNum-writtenBlocks);
+
+	  if (bOffset > 0) {
+         iovs[writtenBlocks].iov_base = (char *)(iovs[writtenBlocks].iov_base) - bOffset;
+         iovs[writtenBlocks].iov_len += bOffset;
+	  }
+#endif
+
+      if (writtenSize <= 0)
+         return -1;
+
+      sendSize += writtenSize;
+      bOffset = (sendSize-GROUP_HEADER_SIZE)%blockSize;
+      if (sendSize < GROUP_HEADER_SIZE) {
+         writtenBlocks = 0;
+         bOffset = sendSize;
+      }
+      else
+         writtenBlocks = 1 + (sendSize-GROUP_HEADER_SIZE)/blockSize;
+
+      //std::cout << "written blocks " << writtenBlocks << std::endl;
+   }
+
+   return sendSize;
+}
+
+int sageBlockGroup::readData(int sockFd)
+{
+   if (!iovs) {
+      sage::printLog("sageBlockGroup::readData : iovec is not enabled");
+      return -1;
+   }
+
+   int headerSize = 0, recvSize = 0;
+   headerSize = sage::recv(sockFd, (void *)header, GROUP_HEADER_SIZE, MSG_PEEK);
+   if (headerSize > 0)
+      sscanf(header, "%d %d %d", &blockNum, &frameID, &configID);
+   else
+      return -1;
+
+   //std::cout << "iov num " << blockNum+1 << std::endl;
+   //for (int i=0; i<blockNum+1; i++)
+   //  std::cout << "iov size " << iovs[i].iov_len << std::endl;
+
+   int readBlocks = 0, bOffset = 0;
+   int iovNum = blockNum+1;
+
+   while (readBlocks < iovNum) {
+      int readSize = 0;
+
+#ifdef WIN32
+      if (bOffset > 0) {
+         iovs[readBlocks].buf = (char *)(iovs[readBlocks].buf) + bOffset;
+         iovs[readBlocks].len -= bOffset;
+      }
+
+      DWORD WSAFlags = 0;
+      ::WSARecv(sockFd, iovs+readBlocks, iovNum - readBlocks, (DWORD*)&readSize, &WSAFlags, NULL, NULL);
+
+	  if (bOffset > 0) {
+         iovs[readBlocks].buf = (char *)(iovs[readBlocks].buf) - bOffset;
+         iovs[readBlocks].len += bOffset;
+      }
+#else
+      if (bOffset > 0) {
+         iovs[readBlocks].iov_base = (char *)(iovs[readBlocks].iov_base) + bOffset;
+         iovs[readBlocks].iov_len -= bOffset;
+      }
+
+      readSize = ::readv(sockFd, iovs+readBlocks, iovNum - readBlocks);
+
+	  if (bOffset > 0) {
+         iovs[readBlocks].iov_base = (char *)(iovs[readBlocks].iov_base) - bOffset;
+         iovs[readBlocks].iov_len += bOffset;
+      }
+#endif
+
+      if (readSize <= 0) {
+         sage::printLog("sageBlockGroup::readData : error in reading io_vec");
+         return -1;
+      }
+
+      recvSize += readSize;
+      bOffset = (recvSize-GROUP_HEADER_SIZE)%blockSize;
+      if (recvSize < GROUP_HEADER_SIZE) {
+         readBlocks = 0;
+         bOffset = recvSize;
+      }
+      else
+         readBlocks = 1 + (recvSize-GROUP_HEADER_SIZE)/blockSize;
+
+   } // end of while
+
+   //std::cout << "group " << header << " data size " << recvSize << std::endl;
+   //for (int i=1; i<=blockNum; i++)
+      //std::cout << "block header " << (char *)iovs[i].iov_base << std::endl;
+
+   return recvSize;
+}
+
+int sageBlockGroup::sendDatagram(int sockFd)
+{
+   if (!iovs) {
+      sage::printLog("sageBlockGroup::sendData : iovec is not enabled");
+      return -1;
+   }
+
+   int sendSize = 0;
+   sprintf(header, "%d %d %d", blockNum, frameID, configID);
+
+   int iovNum = blockNum+1;
+
+#ifdef WIN32
+   DWORD WSAFlags = 0;
+   ::WSASend(sockFd, iovs, iovNum, (DWORD*)&sendSize,
+         WSAFlags, NULL, NULL);
+#else
+   struct msghdr blockMsgHdr;
+   bzero((void *)&blockMsgHdr, sizeof(blockMsgHdr));
+   
+   blockMsgHdr.msg_iov = iovs;
+   blockMsgHdr.msg_iovlen = iovNum;
+
+   sendSize = ::sendmsg(sockFd, &blockMsgHdr, 0);
+#endif
+
+   return sendSize;
+}
+
+int sageBlockGroup::readDatagram(int sockFd)
+{
+   if (!iovs) {
+      sage::printLog("sageBlockGroup::readDatagram : iovec is not enabled");
+      return -1;
+   }
+
+   int headerSize = 0, recvSize = 0;
+   headerSize = sage::recv(sockFd, (void *)header, GROUP_HEADER_SIZE, MSG_PEEK);
+      if (headerSize > 0)
+         sscanf(header, "%d %d %d", &blockNum, &frameID, &configID);
+      else
+         return -1;
+
+   //blockNum = buf->getEntryNum();
+   int dataSize = blockNum*blockSize + GROUP_HEADER_SIZE;
+      int iovNum = blockNum+1;
+
+#ifdef WIN32
+      DWORD WSAFlags = 0;
+      ::WSARecv(sockFd, iovs, iovNum, (DWORD*)&recvSize, &WSAFlags, NULL, NULL);
+#else
+   struct msghdr blockMsgHdr;
+   bzero((void*)&blockMsgHdr, sizeof(blockMsgHdr));
+   blockMsgHdr.msg_iov = iovs;
+   blockMsgHdr.msg_iovlen = iovNum;
+   
+   recvSize = ::recvmsg(sockFd, &blockMsgHdr, MSG_WAITALL);
+#endif
+
+   if (recvSize < dataSize)
+      std::cout << "data loss " << dataSize << " , " <<  recvSize << "Bytes" << blockNum << " " <<
+      frameID << " " << configID << std::endl; 
+   
+      if (recvSize <= 0) {
+         sage::printLog("sageBlockGroup::readDatagram : error in reading io_vec");
+         std::cout << "iov_num " << iovNum << " frameID " << frameID << std::endl;
+         return -1;
+      }
+
+   return recvSize;
+}
+
+bool sageBlockGroup::updateConfig()
+{
+   if (!buf) {
+      sage::printLog("sageBlockGroup::updateConfig() : block buffer is NULL");
+      return false;
+   }
+
+   if (blockNum > 0)
+      flag = sageBlockGroup::PIXEL_DATA;
+   else
+      flag = sageBlockGroup::CONFIG_UPDATE;
+
+   for (int i=0; i<blockNum; i++) {
+      sagePixelBlock *block = (sagePixelBlock *)(*buf)[i];
+      if (block)
+         block->updateBlockConfig();
+   }
+
+   buf->setEntryNum(blockNum);
+
+   return true;
+}
+
+
+
+bool sageBlockGroup::updateConfig(int num, int frame, int conf)
+{
+   blockNum = num;
+   frameID = frame;
+   configID = conf;
+   
+   return updateConfig();
+   }
+
+
+void sageBlockGroup::clearBlocks()
+{
+   assert(buf);
+
+   for (int i=0; i<buf->size(); i++) {
+      sagePixelBlock *block = (sagePixelBlock *)(*buf)[i];
+      block->clearPixelBlock();
+   }
+}
+
+void sageBlockGroup::clear()
+{
+#ifdef DEBUG_MEMORY
+	fprintf(stderr, "SBG::clear() : delete pixel blocks in this group\n");
+#endif
+   buf->setBlockingFlag(false);
+   sagePixelBlock *pBlock;
+   while (pBlock = front()) {
+      delete pBlock;
+      next();
+   }
+}
+
+sageBlockGroup::~sageBlockGroup()
+{
+#ifdef DEBUG_MEMORY
+	fprintf(stderr, "SBG::~SBG()\n");
+#endif
+   if (buf) {
+      if (memAlloc)
+         clear();
+
+      delete buf;
+   }
+
+   if (iovs)
+      delete [] iovs;
+}
+
+sageBlockBuf::sageBlockBuf(int bufSize, int grpSize, int blkSize, char opt) : waitingData(false),
+   frameInterval(100000), firstGroup(true)
+{
+   if (bufSize <= 0 || grpSize <= 0 || blkSize <= 0) {
+      sage::printLog("sageBlockBuf::sageBlockBuf : error in buffer parameter");
+      sage::printLog("buffer size : %d   group size : %d  block size : %d", bufSize,
+            grpSize, blkSize);
+      return;
+   }
+   int blockNum, bufLen, bScale;
+   if (grpSize>=blkSize)
+       blockNum = grpSize / blkSize; // number of blocks in a blockGroup
+   else
+       sage::printLog("sageBlockBuf::sageBlockBuf> groupsize (%d) smaller than blocksize (%d) (increase groupsize)", grpSize, blkSize);
+
+   bufLen = bufSize / (blockNum * blkSize); // number of blockGroups in a bufSize
+   bScale = 1;
+
+   //std::cout << "buf size " << bufSize << "  group size " << grpSize << "  block size " << blkSize << std::endl;
+#ifdef DEBUG_MEMORY
+   fprintf(stderr, "sageBlockBuf::sageBlockBuf(bufSize %d, grpSize %d, blkSize %d) : %d blocks, bufLen(number of SBGs) %d\n", bufSize, grpSize, blkSize, blockNum, bufLen);
+#endif
+
+   if (opt & BUF_CTRL_GROUP) {
+      ctrlPool = new sageCircBufSingle(bufLen, true);
+      bScale = 2;
+   }
+   else
+      ctrlPool = NULL;
+
+   if (opt & BUF_MULTI_READER) {
+      multiReader = true;
+      dataPool = new sageCircBufSingle(bufLen, true);
+      vacantPool = new sageRAB(bufLen);
+      buf = new sageCircBufMulti(bufLen*bScale, true);
+   }
+   else {
+      multiReader = false;
+      dataPool = new sageCircBufSingle(bufLen, true);
+      vacantPool = NULL;
+      if (opt & BUF_BLOCKING_READ) {
+         buf = new sageCircBufSingle(bufLen*bScale, true);
+      }
+      else {
+         buf = new sageCircBufSingle(bufLen*bScale, false);
+         waitingData = true;
+      }
+   }
+
+   if (!buf)
+      sage::printLog("sageBlockBuf::sageBlockBuf : fail to allocate block buffer");
+
+   for (int i=0; i<bufLen; i++) {
+      sageBlockGroup *newGrp;
+      if (opt & BUF_MEM_ALLOC) {
+         newGrp = new sageBlockGroup(blkSize, grpSize, GRP_MEM_ALLOC | GRP_USE_IOV);
+         memAlloc = true;
+      }
+      else {
+         newGrp = new sageBlockGroup(blkSize, grpSize, GRP_USE_IOV);
+         memAlloc = false;
+      }
+
+      if (!newGrp) {
+         sage::printLog("sageBlockBuf::sageBlockBuf : fail to create a new block group");
+         break;
+      }
+
+      if (!dataPool->pushBack((sageBufEntry)newGrp)) {
+         sage::printLog("sageBlockBuf::sageBlockBuf : fail to add a block group");
+         break;
+      }
+
+      if (ctrlPool) {
+         newGrp = new sageBlockGroup;
+         if (!newGrp) {
+            sage::printLog("sageBlockBuf::sageBlockBuf : fail to create a new control group");
+            break;
+         }
+
+         if (!ctrlPool->pushBack((sageBufEntry)newGrp)) {
+            sage::printLog("sageBlockBuf::sageBlockBuf : fail to add a ctrl group");
+            break;
+         }
+      }
+   }
+}
+
+bool sageBlockBuf::pushBack(sageBlockGroup* grp)
+{
+   if (buf) {
+      if (multiReader)
+         grp->setRefCnt();
+
+      if (!buf->pushBack((sageBufEntry)grp)) {
+         sage::printLog("sageBlockBuf::pushBack : error in pushing back to buffer");
+         return false;
+      }
+
+      if (firstGroup) {
+         frameTimer.reset();
+         firstGroup = false;
+      }
+
+      return true;
+   }
+
+   sage::printLog("sageBlockBuf::pushBack : buf is NULL");
+   return false;
+}
+
+int sageBlockBuf::findNextFrame(int id)
+{
+   if (multiReader) {
+      sageCircBufMulti *mBuf = (sageCircBufMulti *)buf;
+      if (!mBuf->isActive(id))
+         return -1;
+   }
+
+   bool loop = true;
+   sageBlockGroup *sbg = NULL;
+   while (loop) {
+      sbg = front(id);
+
+      while(!sbg) {
+         next(id);
+         sbg = front(id);
+      }
+
+      if (sbg->getFlag() == sageBlockGroup::END_FRAME)
+         loop = false;
+
+      next(id);
+   }
+
+   sbg = front(id);
+   int nextFrame = 1;
+   if (sbg)
+      nextFrame = sbg->getFrameID();
+
+   return nextFrame;
+}
+
+int sageBlockBuf::addReader(int id)
+{
+   if (!buf) {
+      sage::printLog("sageBlockBuf::addReader : buffer is NULL");
+      return -1;
+   }
+
+   if (!multiReader) {
+      sage::printLog("sageBlockBuf::addReader : can't add reader to a single reader buffer");
+      return -1;
+   }
+
+   sageCircBufMulti *mBuf = (sageCircBufMulti *)buf;
+   mBuf->addReader(id);
+
+   int startFrame = 1;
+   if (id > 0)
+      startFrame = findNextFrame(id);
+
+   return startFrame;
+}
+
+sageBlockGroup* sageBlockBuf::front(int id, int minFrame)
+{
+   sageBlockGroup *sbg = NULL;
+
+   if (multiReader) {
+      sageCircBufMulti *mBuf = (sageCircBufMulti *)buf;
+      sbg = (sageBlockGroup *)mBuf->front(id);
+      if (!mBuf->isActive(id))
+         return NULL;
+
+      if (sbg && sbg->getFlag() == sageBlockGroup::PIXEL_DATA && sbg->getFrameID() < minFrame) {
+         while(findNextFrame(id) < minFrame);
+         sbg = (sageBlockGroup *)mBuf->front(id);
+      }
+   }
+   else {
+      sbg = (sageBlockGroup *)buf->front();
+
+      if (!sbg)
+         waitingData = true;
+      else
+         waitingData = false;
+   }
+
+   return sbg;
+}
+
+bool sageBlockBuf::next(int id)
+{
+   if (multiReader) {
+      sageCircBufMulti *mBuf = (sageCircBufMulti *)buf;
+      if (!mBuf->isActive(id))
+         return false;
+
+      sageBlockGroup *sbg = (sageBlockGroup *)mBuf->next(id);
+      if (sbg) {
+         returnBG(sbg);
+      }
+
+      return true;
+   }
+
+   return buf->next();
+}
+
+sageBlockGroup* sageBlockBuf::getFreeBlocks()
+{
+   // blocked if no block group is available
+   sageBlockGroup* freeGroup = (sageBlockGroup *)dataPool->front();
+   dataPool->next();
+   return freeGroup;
+}
+
+sageBlockGroup* sageBlockBuf::getCtrlGroup(int flag)
+{
+   if (ctrlPool) {
+      sageBlockGroup* ctrlGroup = (sageBlockGroup *)ctrlPool->front();
+      ctrlPool->next();
+      ctrlGroup->setFlag(flag);
+      return ctrlGroup;
+   }
+
+   sage::printLog("sageBlockBuf::getCtrlGroup : control group pool is disabled");
+   return NULL;
+}
+
+bool sageBlockBuf::finishFrame()
+{
+   if (ctrlPool) {
+      sageBlockGroup* ctrlGroup = (sageBlockGroup *)ctrlPool->front();
+      ctrlPool->next();
+      ctrlGroup->setFlag(sageBlockGroup::END_FRAME);
+      if (!buf->pushBack((sageBufEntry)ctrlGroup))
+         sage::printLog("sageBlockBuf::finishFrame : error in pushing back to buffer");
+      //std::cout << "finish frame" << std::endl;
+
+      frameCounter++;
+      if (frameCounter.getValue() == INTERVAL_EVAL_COUNT) {
+         frameInterval = frameTimer.getTimeUS() / 100;
+         frameTimer.reset();
+         frameCounter.reset();
+      }
+
+      return true;
+   }
+
+   sage::printLog("sageBlockBuf::finishFrame : control group pool is disabled");
+   return false;
+}
+
+int sageBlockBuf::returnBG(sageBlockGroup* grp)
+{
+   if (!grp) {
+      sage::printLog("sageBlockBuf::returnBG : returned group is NULL");
+      return -1;
+   }
+
+   if (grp->getFlag() == sageBlockGroup::PIXEL_DATA) {
+		//std::cout << "push back (datapool)---> " << grp->getRefCnt() << " " << grp->getFrameID() << std::endl;
+
+      if (multiReader && grp->getRefCnt() > 0) {
+         if (!vacantPool->insert((sageBufEntry)grp)) {
+            sage::printLog("sageBlockBuf::returnBG : error in pushing back to vacant pool");
+            char info[TOKEN_LEN];
+            getBufInfo(info);
+            std::cout << info << std::endl;
+         }
+      }
+      else {
+         if (!dataPool->pushBack((sageBufEntry)grp))
+            sage::printLog("sageBlockBuf::returnBG : error in pushing back to data pool");
+      }
+   }
+   else {
+		//std::cout << "push back (ctrlPool)---> " << grp->getRefCnt() << " " << grp->getFrameID() << std::endl;
+
+      if (!ctrlPool->pushBack((sageBufEntry)grp))
+         sage::printLog("sageBlockBuf::returnBG : error in pushing back to control pool");
+   }
+
+   return 0;
+}
+
+int sageBlockBuf::returnBlock(sagePixelBlock *block)
+{
+   if (!vacantPool) {
+      sage::printLog("sageBlockBuf : vacant block group pool is NULL");
+      return -1;
+   }
+
+   if (block) {
+      //std::cout << "return block" << std::endl;
+      sageBlockGroup *parent = block->getGroup();
+      assert(parent);
+      if (parent && (parent->dereference() <= 0)) {
+         //std::cout << "return group" << std::endl;
+         int prev = -1;
+         for (int j=vacantPool->start(); j>=0; vacantPool->next(j)) {
+            sageBlockGroup *sbg = (sageBlockGroup *)(*vacantPool)[j];
+            if (sbg && (sbg == parent || sbg->getRefCnt() <= 0)) {
+               //std::cout << "move group" << std::endl;
+               vacantPool->remove(j, prev);
+               if (!dataPool->pushBack((sageBufEntry)sbg))
+                  sage::printLog("sageBlockBuf::garbageCollection : error in pushing back to data pool");
+               break;
+            }
+            prev = j;
+         }
+      }
+   }
+
+   return 0;
+}
+
+int sageBlockBuf::returnBlocks(sageBlockGroup* grp)
+{
+   if (!grp) {
+      sage::printLog("sageBlockBuf : group pointer is NULL");
+      return -1;
+   }
+
+   if (!vacantPool) {
+      sage::printLog("sageBlockBuf : vacant block group pool is NULL");
+      return -1;
+   }
+
+   for (int i=0; i<grp->getBlockNum(); i++) {
+      sagePixelBlock *block = (*grp)[i];
+
+      if (block) {
+         //std::cout << "return block" << std::endl;
+         sageBlockGroup *parent = block->getGroup();
+         if (parent && (parent->dereference() <= 0)) {
+            //std::cout << "return group" << std::endl;
+            int prev = -1;
+            for (int j=vacantPool->start(); j>=0; vacantPool->next(j)) {
+               sageBlockGroup *sbg = (sageBlockGroup *)(*vacantPool)[j];
+               if (sbg && (sbg == parent || sbg->getRefCnt() <= 0)) {
+                  //std::cout << "move group" << std::endl;
+                  vacantPool->remove(j, prev);
+                  if (!dataPool->pushBack((sageBufEntry)sbg))
+                     sage::printLog("sageBlockBuf::garbageCollection : error in pushing back to data pool");
+                  break;
+               }
+               prev = j;
+            }
+         }
+      }
+   }
+
+   return 0;
+}
+
+void sageBlockBuf::releaseLock()
+{
+   buf->releaseLock();
+   if (dataPool)
+      dataPool->releaseLock();
+   if (vacantPool)
+      vacantPool->releaseLock();
+   if (ctrlPool)
+      ctrlPool->releaseLock();
+}
+
+bool sageBlockBuf::clear(sageBuf *groupBuf)
+{
+   if (groupBuf) {
+      groupBuf->setBlockingFlag(false);
+      sageBlockGroup *sbg;
+      while (sbg = (sageBlockGroup *)groupBuf->front()) {
+         delete sbg;
+         groupBuf->next();
+      }
+
+      return true;
+   }
+
+   return false;
+}
+
+void sageBlockBuf::getBufInfo(char *bufStatus)
+{
+   int ctrlStat = 0;
+   int vacantStat = 0;
+
+   if (ctrlPool)
+      ctrlStat = ctrlPool->getStatus();
+
+   if (vacantPool)
+      vacantStat = vacantPool->getStatus();
+
+   sprintf(bufStatus, "data buffer : %d %% , data pool : %d %% , ctrl pool : %d %% , vacant pool : %d %%",
+      buf->getStatus(), dataPool->getStatus(), ctrlStat, vacantStat);
+}
+
+sageBlockBuf::~sageBlockBuf()
+{
+   if (clear(buf)) {
+#ifdef DEBUG_MEMORY
+	   fprintf(stderr, "sageBlockBuf::~sageBlockBuf() : delete buf\n");
+#endif
+	   delete buf;
+   }
+
+   if (clear(dataPool)) {
+#ifdef DEBUG_MEMORY
+	   fprintf(stderr, "sageBlockBuf::~sageBlockBuf() : delete dataPool\n");
+#endif
+      delete dataPool;
+   }
+
+   if (clear(vacantPool)) {
+#ifdef DEBUG_MEMORY
+	   fprintf(stderr, "sageBlockBuf::~sageBlockBuf() : delete vacantPool\n");
+#endif
+      delete vacantPool;
+   }
+
+   if (clear(ctrlPool)) {
+#ifdef DEBUG_MEMORY
+	   fprintf(stderr, "sageBlockBuf::~sageBlockBuf() : delete ctrlPool\n");
+#endif
+      delete ctrlPool;
+   }
+}
+
Index: trunk/src/testing/src/displayInstance.cpp
===================================================================
--- trunk/src/testing/src/displayInstance.cpp	(revision 4)
+++ trunk/src/testing/src/displayInstance.cpp	(revision 4)
@@ -0,0 +1,403 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: displayInstance.cpp - a part of free space manager controlling each
+ *         application instance. 
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "streamInfo.h"
+#include "displayInstance.h"
+#include "fsManager.h"
+#include "fsCore.h"
+#include "sageVirtualDesktop.h"
+
+displayInstance::displayInstance(fsManager *f, int id, appInExec* app) : fsm(f), winID(id), appExec(app)
+{
+   //appExec = fsm->execList[id];
+   receiverList.clear();
+   sailClient = appExec->sailClient;
+   zValue = 0;
+   
+   //imageSize = appExec->imageWidth * appExec->imageHeight * appExec->bytesPerPixel;
+   //if (imageSize == 0) {
+   //   sage::printLog("displayInstance::displayInstance : image_size = 0, using default size");
+   //   imageSize = DEFAULT_IMAGE_SIZE;
+   //}
+   
+   streamNum = 0;   
+   rcvFrate = 0.0;
+   rcvBwidth = 0.0;
+   accBwidth = 0.0;
+   accFSize = 0;
+   sendFrate = appExec->frameRate;
+   dispNodeNum = 0;
+   tileNum = 0;
+   
+   for (int i=0; i<fsm->vdtList.size(); i++) {
+      dispNodeNum += fsm->vdtList[i]->getNodeNum();
+      tileNum += fsm->vdtList[i]->getTileNum();
+   }
+   
+   waitNodes = dispNodeNum;
+   rcvFlagCnt = 0;
+   
+   sage::printLog("displayInstance::%s() : Establishing network connections for streams.", __FUNCTION__);
+   connectSenders();
+   initStreams();
+   
+   memset(winTitle, 0, SAGE_NAME_LEN);
+}
+
+void displayInstance::generateStreamInfo(void)
+{
+   fsm->vdtList[appExec->displayID]->checkLayout(appExec);
+   streamGrp = *(sageRect *)appExec;
+   
+   int offset = 0;
+   for (int i=0; i<appExec->displayID; i++)
+      offset += fsm->vdtList[i]->getNodeNum();
+   fsm->vdtList[appExec->displayID]->generateStreamInfo(streamGrp, receiverList, offset);
+   streamGrp.setRcvNum(receiverList.size());
+}
+
+int displayInstance::streamInfoToSender(void)
+{
+   // send new stream info to recevers
+   char msgStr[TOKEN_LEN];
+   streamGrp.createRcvMsg(winID, msgStr);
+   fsm->sendToVDT(appExec->displayID, RCV_UPDATE_DISPLAY, msgStr);
+   fsm->sendToOtherVDT(appExec->displayID, RCV_CLEAR_DISPLAY, winID); 
+   
+   //std::cout << "displayInstance : send stream info to SAIL" << std::endl;
+   sageMessage msg;
+   streamGrp.createMessage(msg, SAIL_INIT_STREAM);
+   msg.setDest(sailClient);
+
+   if (fsm->sendMessage(msg) < 0) {
+      sage::printLog("displayInstance::%s() : %s(%d) is stuck or shutdown", __FUNCTION__,  appExec->appName, winID);
+      return -1;
+   }
+   
+   return 0;
+}
+
+int displayInstance::connectSenders()
+{
+   int msgLen = 8 + SAGE_IP_LEN * dispNodeNum;
+   char *msgStr = new char[msgLen];
+   
+   sprintf(msgStr, "%d %d ", fsm->rInfo.streamPort, dispNodeNum);
+   int nodeID = 0;
+   
+   for (int j=0; j<fsm->vdtList.size(); j++) {
+      // list ip addresses for each display node
+      for (int i=0; i<fsm->vdtList[j]->getNodeNum(); i++) {
+         char ipStr[TOKEN_LEN];
+         char tileStr[TOKEN_LEN];
+         
+         if (appExec->portForwarding) {
+            fsm->vdtList[j]->getForwardIP(i, ipStr);
+            int forwardPort = fsm->vdtList[j]->getForwardPort(i);
+            sprintf(tileStr, "%s %d %d ", ipStr, forwardPort, nodeID++);
+         }
+         else if (fsm->useLocalPort) {
+            fsm->vdtList[j]->getNodeIPs(i, ipStr);
+            int localPort = fsm->vdtList[j]->getLocalPort(i);
+            sprintf(tileStr, "%s %d %d ", ipStr, localPort, nodeID++);
+         }
+         else {
+            fsm->vdtList[j]->getNodeIPs(i, ipStr);  
+            sprintf(tileStr, "%s %d ", ipStr, nodeID++);
+         }
+            
+         strcat(msgStr, tileStr);
+      }
+   }
+   
+   int connectMsg;
+   if (fsm->useLocalPort || appExec->portForwarding) {
+      connectMsg = SAIL_CONNECT_TO_RCV_PORT;
+      fprintf(stderr, "displayInstance::%s() : winID %d, sending msg SAIL_CONNECT_TO_RCV_PORT. [%s]\n", __FUNCTION__, winID, msgStr);
+   }
+   else {
+	   connectMsg = SAIL_CONNECT_TO_RCV;
+	   fprintf(stderr, "displayInstance::%s() : winID %d, sending msg SAIL_CONNECT_TO_RCV. [%s] \n", __FUNCTION__, winID, msgStr);
+   }
+   
+   if (fsm->sendMessage(sailClient, connectMsg, msgStr) < 0) {
+      sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+      return -1;
+   }
+   
+   return 0;
+}
+
+int displayInstance::initStreams()
+{
+   generateStreamInfo();
+   if (streamInfoToSender() < 0)
+      return -1;
+
+   return 0;
+}
+
+int displayInstance::modifyStream(void)
+{
+   streamGrp.init();
+   receiverList.clear();
+   generateStreamInfo();
+   if (streamInfoToSender() < 0)
+      return -1;
+   
+   if (appExec->protocol == SAGE_UDP) {
+      sendFrate = appExec->frameRate;
+      if (fsm->sendMessage(sailClient, SAIL_FRAME_RATE, appExec->frameRate) < 0) {
+         sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+         return -1;
+      }
+   }
+      
+   return 0;
+}   
+
+int displayInstance::changeWindow(sageRect &devRect, int steps)
+{
+   sageRect deltaRect = devRect/steps;
+   sageRect initWindow = *(sageRect *)appExec;
+   
+   for (int i=0; i<steps; i++) {   
+      streamGrp.init();
+      receiverList.clear();
+      
+      if (i == steps-1) {
+         *(sageRect *)appExec = initWindow + devRect;
+      }
+      else {
+         *(sageRect *)appExec += deltaRect;
+      }
+      
+      bool inScope = fsm->vdtList[appExec->displayID]->checkLayout(appExec);
+   
+      streamGrp = *(sageRect*)appExec;
+      int offset = 0;
+      for (int i=0; i<appExec->displayID; i++)
+         offset += fsm->vdtList[i]->getNodeNum();
+
+      fsm->vdtList[appExec->displayID]->generateStreamInfo(streamGrp, receiverList, offset);
+      streamGrp.setRcvNum(receiverList.size());
+      if (streamInfoToSender() < 0)
+         return -1;
+      if (!inScope)
+         break;
+   }
+   
+   if (appExec->protocol == SAGE_UDP) {
+      sendFrate = appExec->frameRate;
+      if (fsm->sendMessage(sailClient, SAIL_FRAME_RATE, appExec->frameRate) < 0) {
+         sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+         return -1;
+      }
+   }
+   
+   return 0;
+}   
+
+int displayInstance::accumulateBandwidth(char *rcvBand)
+{
+	//fprintf(stderr, "displayInstance::%s() : %s\n", __FUNCTION__, rcvBand);
+	//fprintf(stderr, "displayInstance::%s() : DISP_RCV_BANDWIDTH_RPT. msg [%s]\n", __FUNCTION__, rcvBand);
+
+/*
+   char token[TOKEN_LEN];
+   char *tokenbuf;
+
+   getToken(rcvBand, token, &tokenbuf);
+   int instID = atoi(token);
+
+   getToken(rcvBand, token, &tokenbuf);
+   float bWidth = atof(token);
+
+   getToken(NULL, token, &tokenbuf);
+   float pLoss = atof(token);
+
+   getToken(NULL, token, &tokenbuf);
+   int fSize = atoi(token);
+   */
+
+	float bWidth = 0.0, pLoss=0.0;
+	int instID=0, fSize=0;
+	sscanf((const char *)rcvBand, "%d %f %f %d", &instID, &bWidth, &pLoss, &fSize);
+   
+   accBwidth += bWidth;
+   accLoss += pLoss;
+   accFSize += fSize;
+   //fprintf(stderr, "displayInstance::%s() : winID %d. accBwidth %7.2f, accLoss %7.2f, accFsize %d\n", __FUNCTION__, winID, accBwidth, accLoss, accFSize);
+   
+   rcvFlagCnt++;
+
+   if (rcvFlagCnt >= dispNodeNum) {
+      rcvBwidth = accBwidth;
+      rcvLoss = accLoss;
+
+      //fprintf(stderr, "displayInstance::%s() : winID %d. rcvFlagCnt %d. rcvBwidth %7.2f, rcvLoss %7.2f\n", __FUNCTION__, winID, rcvFlagCnt, rcvBwidth, rcvLoss);
+
+      accBwidth = 0.0;
+      accLoss = 0.0;
+      rcvFlagCnt = 0;
+
+      if (rcvLoss > 0 && appExec->protocol == SAGE_UDP) {
+         float newFrameRate = (rcvBwidth*990000.0)/(accFSize*8.0); 
+         newFrameRate = MAX(newFrameRate, sendFrate*0.9);
+         newFrameRate = MIN(newFrameRate, sendFrate*1.1);
+         sendFrate = newFrameRate;
+         
+         std::cout << "=== " << appExec->appName << " " << winID << " ===" << std::endl;
+         std::cout << "Data loss = " << rcvLoss << "Mbps" << std::endl;
+         std::cout << "New Frame Rate = " << newFrameRate << "fps" << std::endl;
+         
+         char frateStr[TOKEN_LEN];
+         sprintf(frateStr, "%7.2f", newFrameRate);
+         
+         if (fsm->sendMessage(sailClient, SAIL_FRAME_RATE, frateStr) < 0) {
+            sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+            return -1;
+         }        
+      }
+      
+      accFSize = 0;
+   }      
+   
+   return 0;
+}
+
+void displayInstance::reportPerformance(char *sailPerf)
+{
+   float packetLoss = 0;
+   if (rcvBwidth + rcvLoss > 0) {
+      packetLoss = rcvLoss*100/(rcvBwidth + rcvLoss);
+      //fprintf(stderr, "displayInstance::%s() : winID %d.  packetLoss %.3f = {rcvLoss %.3f / (rcvBwidth %.3f + rcvLoss %.3f)} * 100\n", __FUNCTION__, winID, packetLoss, rcvLoss, rcvBwidth, rcvLoss);
+   }
+      
+   int receiverNum = receiverList.size();   
+   
+   char msgStr[TOKEN_LEN];
+
+   sprintf(msgStr, "%d\nDisplay %7.2f %7.2f %7.2f %d\nRendering %s", winID, 
+      rcvBwidth, rcvFrate, packetLoss, receiverNum, sailPerf);
+
+   //fprintf(stderr, "displayInstance::%s() : msgStr. [%s]\n", __FUNCTION__, msgStr);
+
+   int uiNum = fsm->uiList.size();
+   for (int j=0; j<uiNum; j++) {
+      if (fsm->uiList[j] < 0)
+         continue;
+			
+      if (fsm->sendMessage(fsm->uiList[j], UI_PERF_INFO, msgStr) < 0) {
+         sage::printLog("displayInstance : uiClient(%d) is stuck or shutdown", j);
+         fsm->uiList[j] = -1;
+      }
+   }   
+}
+
+int displayInstance::requestPerformanceInfo(int rate)
+{   
+   char perfStr[TOKEN_LEN];
+   sprintf(perfStr, "%d %d", winID, rate);
+      
+   fsm->sendToAllRcvs(RCV_PERF_INFO_REQ, perfStr);
+   if (fsm->sendMessage(sailClient, SAIL_PERF_INFO_REQ, rate) < 0) {
+      sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+      return -1;
+   }
+
+   return 0;   
+}
+
+int displayInstance::stopPerformanceInfo()
+{   
+   //fsm->sendToAllRcvs(RCV_PERF_INFO_STOP, winID);
+   if (fsm->sendMessage(sailClient, SAIL_PERF_INFO_STOP) < 0) {
+      sage::printLog("displayInstance : %s(%d) is stuck or shutdown", appExec->appName, winID);
+      return -1;
+   }
+   
+   return 0;   
+}
+
+int displayInstance::parseMsg(sageMessage &msg)
+{
+   switch (msg.getCode()) {
+      case DISP_RCV_FRATE_RPT : {
+    	  int instID;
+    	  sscanf((char *)msg.getData(), "%d %f", &instID, &rcvFrate);
+         //char token[TOKEN_LEN];
+         //getToken((char *)msg.getData(), token);
+         //rcvFrate = atof(token);
+
+    	  //fprintf(stderr, "displayInstance::%s() : DISP_RCV_FRATE_RPT. instID %d, rcvFrate %.3f\n", __FUNCTION__, instID, rcvFrate);
+         break;
+      }
+
+      case DISP_RCV_BANDWITH_RPT : {
+    	  /*
+    	  int instID, frameSize;
+    	  double bandwidth, packetloss;
+    	  sscanf((char *)msg.getData(), "%d %7.2f %7.2f %d", &instID, &bandwidth, &packetloss, &frameSize);
+    	  accumulateBandwidth(bandwidth, packetloss, frameSize);
+    	  */
+         accumulateBandwidth((char *)msg.getData());
+         break;
+      }
+
+      case DISP_SAIL_PERF_RPT : {
+    	 // fprintf(stderr, "displayInstance::%s() : DISP_SAIL_PERF_RPT. [%s]\n", __FUNCTION__, (char *)msg.getData());
+         reportPerformance((char *)msg.getData());
+         break;
+      }
+
+      case DISP_APP_CONNECTED : {
+         waitNodes--;
+         if (waitNodes == 0) {
+            fsm->core->windowChanged(winID);
+            fsm->core->bringToFront(winID);
+         }   
+         break;
+      }
+   }
+
+   return 0;
+}   
Index: trunk/src/testing/src/sageRect.cpp
===================================================================
--- trunk/src/testing/src/sageRect.cpp	(revision 4)
+++ trunk/src/testing/src/sageRect.cpp	(revision 4)
@@ -0,0 +1,574 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageRect.cpp - a few geometrical operations for rectangles used in SAGE
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageRect.h"
+
+sageRotation operator+(sageRotation r1, sageRotation r2)
+{
+   int sum = ((int)r1 + (int)r2)%4;
+   return (sageRotation)sum;
+}
+
+sageRotation operator-(sageRotation r1, sageRotation r2)
+{
+   int diff = ((int)r1 - (int)r2 + 4)%4;
+   return (sageRotation)diff; 
+}
+
+/*
+void sageRect::operator= (sageRect &rect)
+{
+   x = rect.x;
+   y = rect.y;
+   width = rect.width;
+   height = rect.height;
+   left = rect.left;
+   right = rect.right;
+   bottom = rect.bottom;
+   top = rect.top;
+}
+*/
+   
+sageRect sageRect::operator+ (sageRect &rect)
+{
+   sageRect res = *this;
+   res += rect;
+   
+   return res;
+}
+
+void sageRect::operator+= (sageRect &rect)
+{
+   x += rect.x;
+   y += rect.y;
+   width += rect.width;
+   height += rect.height;
+}
+
+
+sageRect sageRect::operator/ (float val)
+{
+   sageRect res;
+   
+   res.x = (int)floor(x/val+0.5);
+   res.y = (int)floor(y/val+0.5);
+   res.width = (int)floor(width/val+0.5);
+   res.height = (int)floor(height/val+0.5);
+   
+   return res;
+}
+
+sageRect sageRect::operator/ (sageRect &rect)
+{
+   sageRect res;
+   
+   res.left = (x - rect.x)/(float)rect.width;
+   res.right = (x + width - rect.x)/(float)rect.width;
+   res.bottom = (y - rect.y)/(float)rect.height;
+   res.top = (y + height - rect.y)/(float)rect.height;
+   
+   return res;
+}
+
+void sageRect::operator/= (sageRect &rect)
+{
+   left = (x - rect.x)/(float)rect.width;
+   right = (x + width - rect.x)/(float)rect.width;
+   bottom = (y - rect.y)/(float)rect.height;
+   top = (y + height - rect.y)/(float)rect.height;
+}
+
+sageRect sageRect::operator* (sageRect &rect)
+{
+   sageRect res;
+   
+   res.x = (int)floor(width*rect.left+0.5);
+   res.y = (int)floor(height*rect.bottom+0.5);
+   res.width = (int)floor(width*rect.right+0.5) - res.x;
+   res.height = (int)floor(height*rect.top+0.5) - res.y;
+   res.translate(x, y);
+   
+   return res;
+}
+
+void sageRect::operator*= (sageRect &rect)
+{
+   sageRect res;
+   
+   res.x = (int)floor(width*rect.left+0.5);
+   res.y = (int)floor(height*rect.bottom+0.5);
+   res.width = (int)floor(width*rect.right+0.5) - res.x;
+   res.height = (int)floor(height*rect.top+0.5) - res.y;
+   res.translate(x, y);
+   
+   *this = res;
+}
+
+void sageRect::updateBoundary()
+{
+   left = (float)x;
+   right = (float)(x + width);
+   bottom = (float)y;
+   top = (float)(y + height);
+}
+
+void sageRect::updateBoundary(sageRect &rect)
+{
+   left = (float)rect.x;
+   right = (float)(rect.x + rect.width);
+   bottom = (float)rect.y;
+   top = (float)(rect.y + rect.height);
+}
+
+// move the origin to the lowerleft corner of rect
+void sageRect::moveOrigin(sageRect &rect)
+{
+   translate(-rect.x, -rect.y);
+}
+
+void sageRect::scale(float r)
+{
+   int oldHalfWidth = halfWidth();
+   int oldHalfHeight = halfHeight();
+   
+   width = (int)floor(width*r + 0.5);
+   height = (int)floor(height*r + 0.5);
+   
+   x = x + oldHalfWidth - halfWidth();
+   y = y + oldHalfHeight - halfHeight();
+}
+
+void sageRect::scale(float sx, float sy)
+{
+   left *= sx;
+   right *= sx;
+   bottom *= sy;
+   top *= sy;
+}
+
+void sageRect::translate(int dx, int dy)
+{
+   x += dx;
+   y += dy;
+}
+
+void sageRect::translate(sageRect &rect)
+{
+   translate(rect.x, rect.y);
+}
+
+void sageRect::shrink(float dx, float dy)
+{   
+   left += dx;
+   right -= dx;
+   bottom += dy;
+   top -= dy;
+}   
+
+void sageRect::locate()
+{
+   x = (int)floor(left*width/(right-left)+0.5);
+   y = (int)floor(bottom*height/(top-bottom)+0.5);
+}
+
+/*
+int sageRect::mask(sageRect &rect)
+{
+   float width = right - left;
+   float height = top - bottom;
+   
+   sageRect tmpRect = rect;
+   tmpRect.scale(width, height);
+   tmpRect.translate(left, bottom);
+   *this = tmpRect;
+   
+   return 0;
+}
+
+int sageRect::normalize(sageRect &rect)
+{   
+   if (rect.left == rect.right || rect.bottom == rect.top) {
+      std::cout << "Can't divide by 0 : fail to normalize rect" << std::endl;
+      return -1;
+   }   
+
+   float width = rect.right - rect.left;
+   float height = rect.top - rect.bottom;
+   
+   moveOrigin(rect);
+   
+   left /= width;
+   right /= width;
+   bottom /= height;
+   top /= height;
+
+   return 0;
+}   
+*/
+
+void sageRect::normalize(sageRect &rect)
+{
+   switch(rect.orientation) {
+      case CCW_ZERO: {
+         left = (x - rect.x)/(float)rect.width;
+         right = (x + width - rect.x)/(float)rect.width;
+         bottom = (y - rect.y)/(float)rect.height;
+         top = (y + height - rect.y)/(float)rect.height;   
+         break;
+      }
+      case CCW_90: {
+         left = (y - rect.y)/(float)rect.height;
+         right = (y + height - rect.y)/(float)rect.height;
+         bottom = (rect.x + rect.width - x - width)/(float)rect.width;
+         top = (rect.x + rect.width - x)/(float)rect.width;
+         break;
+      }
+      case CCW_180: {
+         left = (rect.x + rect.width - x - width)/(float)rect.width;
+         right = (rect.x + rect.width - x)/(float)rect.width;
+         bottom = (rect.y + rect.height - y - height)/(float)rect.height;
+         top = (rect.y + rect.height - y)/(float)rect.height;
+         break;
+      }
+      case CCW_270: {
+         left = (rect.y + rect.height - y - height)/(float)rect.height;
+         right = (rect.y + rect.height - y)/(float)rect.height;
+         bottom = (x - rect.x)/(float)rect.width;
+         top = (x + width - rect.x)/(float)rect.width;
+         break;
+      }
+   }      
+}
+
+int sageRect::normalize(float x, float y)
+{   
+   if (x == 0 || y == 0) {
+      std::cout << "Can't divide by 0 : fail to normalize rect" << std::endl;
+         return -1;
+   }   
+
+   left /= x;
+   right /= x;
+   bottom /= y;
+   top /= y;
+
+   return 0;
+}   
+
+void sageRect::rotate(sageRotation rot)
+{
+   int halfW = halfWidth();
+   int halfH = halfHeight();
+   int centerX = x + halfW;
+   int centerY = y + halfH;
+   orientation = orientation + rot;
+   
+   if (rot == CCW_90 || rot == CCW_270) {
+      x = centerX - halfH;
+      y = centerY - halfW;
+      int oldWidth = width;
+      width = height;
+      height = oldWidth;
+   }
+}
+
+bool sageRect::isOverLapX(float l, float r, sageRect &common) 
+{
+   if (l <= right && r >= left) {
+      common.left = MAX(l, left);
+      common.right = MIN(r, right);
+      return true;
+   }
+   else 
+      return false;
+}
+
+bool sageRect::isOverLapY(float b, float t, sageRect &common) 
+{
+   if (b <= top && t >= bottom) {
+      common.bottom = MAX(b, bottom);
+      common.top = MIN(t, top);
+      return true;
+   }
+   else 
+      return false;
+}
+
+bool sageRect::isOverLap(float l, float r, float b, float t, sageRect &common) 
+{
+   return (isOverLapX(l, r, common) && isOverLapY(b, t, common));
+}   
+
+bool sageRect::isOverLapX(int x2, int w2, sageRect &common) 
+{
+   int r1 = x+width-1;
+   int r2 = x2+w2-1;
+   
+   if (x2 <= r1 && r2 >= x) {
+      common.x = MAX(x2, x);
+      int rCommon = MIN(r1, r2);
+      common.width = rCommon-common.x+1;
+      return true;
+   }
+   else 
+      return false;
+}
+
+bool sageRect::isOverLapY(int y2, int h2, sageRect &common) 
+{
+   int t1 = y+height-1;
+   int t2 = y2+h2-1;
+   
+   if (y2 <= t1 && t2 >= y) {
+      common.y = MAX(y2, y);
+      int tCommon = MIN(t1, t2);
+      common.height = tCommon-common.y+1;
+      return true;
+   }
+   else 
+      return false;
+}
+
+bool sageRect::isOverLap(sageRect &rect, sageRect &com)
+{
+   return (isOverLapX(rect.x, rect.width, com) && isOverLapY(rect.y, rect.height, com));
+}
+
+bool sageRect::isOverLap(sageRect &rect)
+{
+   sageRect dummy;
+   return isOverLap(rect, dummy);
+}
+
+bool sageRect::crop(sageRect &rect)
+{
+   int r1 = x+width-1;
+   int r2 = rect.x+rect.width-1;
+   int t1 = y+height-1;
+   int t2 = rect.y+rect.height-1;
+   
+   if (rect.y <= t1 && y <= t2 && rect.x <= r1 && x <= r2) {
+      y = MAX(rect.y, y);
+      int tCommon = MIN(t1, t2);
+      height = tCommon-y+1;
+      
+      x = MAX(rect.x, x);
+      int rCommon = MIN(r1, r2);
+      width = rCommon-x+1;
+      return true;
+   }
+   else 
+      return false;
+}
+
+int sageRect::isOverLap(sageRect &rect, float threshold)
+{
+   float outX = 0.0, outY = 0.0;
+   bool leftOut = false, bottomOut = false;
+
+   if (rect.x < x) {
+      outX = (float)(x - rect.x)/rect.width;
+      leftOut = true;
+   }   
+   
+   if (rect.x + rect.width > x + width) {
+      float tmpOutX = (float)(rect.x + rect.width - x - width)/rect.width;
+      if (tmpOutX > outX) {
+         leftOut = false;
+         outX = tmpOutX;
+      }   
+   }   
+   
+   if (rect.y < y) {
+      outY = (float)(y - rect.y)/rect.height;
+      bottomOut = true;
+   }   
+   
+   if (rect.y + rect.height > y + height) {
+      float tmpOutY = (float)(rect.y + rect.height - y - height)/rect.height;
+      if (tmpOutY > outY) {
+         bottomOut = false;
+         outY = tmpOutY;
+      }   
+   }   
+   
+   int result = ON_RECT;
+   
+   if (outX > threshold) {
+      if (leftOut)
+         result = LEFT_EDGE;
+      else
+         result = RIGHT_EDGE;
+   }
+   
+   if (outY > threshold && (outX <= threshold || outY > outX)) {
+      if (bottomOut)
+         result = BOTTOM_EDGE;
+      else
+         result = TOP_EDGE;
+   }
+   
+   return result;
+}
+
+bool sageRect::isInRect(int px, int py) 
+{
+   if (x <= px && x+width > px && y <= py && y+height > py)
+      return true;
+   else
+      return false;
+}
+
+bool sageRect::isInRect(float x, float y) 
+{
+   updateBoundary();
+   
+   if (left <= x && right >= x && bottom <= y && top >= y)
+      return true;
+   else
+      return false;
+}   
+
+bool sageRect::isInRect(sageRect &rect) 
+{
+   updateBoundary();
+   rect.updateBoundary();
+   
+   if (left <= rect.left && right >= rect.right && bottom <= rect.bottom && top >= rect.top)
+      return true;
+   else
+      return false;
+}
+
+void sageRect::sprintRect(char *str)
+{
+   sprintf(str, "%d %d %d %d %f %f %f %f", x, y, width, height, left, right, bottom, top);
+}
+
+void sageRect::sscanRect(char *str)
+{
+   sscanf(str, "%d %d %d %d %f %f %f %f", &x, &y, &width, &height, &left, &right, &bottom, &top);
+}
+
+void sageRect::genTexCoord(int corner, float &x, float &y)
+{
+   bool lowerCorner, leftCorner;
+   
+   switch(corner) {
+      case LOWER_LEFT: {
+         lowerCorner = true;
+         leftCorner = true;
+         break;
+      }
+      case LOWER_RIGHT: {
+         lowerCorner = true;
+         leftCorner = false;
+         break;
+      }   
+      case UPPER_RIGHT: {
+         lowerCorner = false;
+         leftCorner = false;
+         break;
+      }   
+      case UPPER_LEFT: {
+         lowerCorner = false;
+         leftCorner = true;
+         break;
+      }
+   }
+   
+   switch(orientation) {
+      case CCW_ZERO: {
+         if (leftCorner)
+            x = left;
+         else
+            x = right;
+            
+         if (lowerCorner)
+            y = bottom;
+         else
+            y = top;
+         
+         break;
+      }      
+      
+      case CCW_90: {
+         if (leftCorner)
+            y = top;
+         else
+            y = bottom;
+         
+         if (lowerCorner)
+            x = left;
+         else
+            x = right;
+            
+         break;
+      }
+      
+      case CCW_180: {
+         if (leftCorner)
+            x = right;
+         else
+            x = left;
+            
+         if (lowerCorner)
+            y = top;
+         else
+            y = bottom;
+            
+         break;                           
+      }
+      
+      case CCW_270: {
+         if (leftCorner)
+            y = bottom;
+         else
+            y = top;
+         
+         if (lowerCorner)
+            x = right;
+         else
+            x = left;
+            
+         break;
+      }
+   }
+}
Index: trunk/src/testing/src/audioFileWriter.cpp
===================================================================
--- trunk/src/testing/src/audioFileWriter.cpp	(revision 4)
+++ trunk/src/testing/src/audioFileWriter.cpp	(revision 4)
@@ -0,0 +1,178 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  audioFileWriter.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for 
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+********************************************************************************/
+
+#include "audioFileWriter.h"
+#include "sageAudioModule.h"
+
+audioFileWriter::audioFileWriter(audioFormatManager* fm)
+: buffer(NULL),  formatManager(fm), converter(NULL), fileName(NULL), 
+   fileID(NULL), startFlag(false)
+{
+}
+
+
+audioFileWriter::~audioFileWriter()
+{
+   // delete audiolist
+}
+
+void audioFileWriter::init()
+{
+   startFlag = false;
+   converter = NULL;
+   fileID = NULL;
+   buffer = NULL;
+   fileName = NULL;
+}
+
+int audioFileWriter::write(char* filename, sageAudioConfig &config, sageAudioCircBuf* buf)
+{
+   if(filename == NULL) return -1;
+   if(formatManager == NULL) return -1;
+   if(buf == NULL) return -1;
+         
+   buffer = buf;
+   
+   framePerBuffer = config.framePerBuffer;
+   channels = config.channels;
+   samplingRate = config.samplingRate;   
+   
+   switch(config.sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         break;
+      case SAGE_SAMPLE_INT16 : 
+         bytesPerSample = sizeof(short);
+         break;
+      case SAGE_SAMPLE_INT8 : 
+         bytesPerSample = sizeof(char);
+         break;      
+      case SAGE_SAMPLE_UINT8 : 
+         bytesPerSample = sizeof(unsigned char);
+         break;         
+      default :
+         bytesPerSample = sizeof(float);
+         break;
+   } 
+   
+   fileName = filename;
+   fileID = NULL;
+   fileID = fopen(fileName, "wb");
+   if( fileID == NULL )
+   {
+      std::cerr << "Could not open file :" << fileName << std::endl;
+      return -1;
+   }
+   startFlag = true;
+   
+   converter = formatManager->createConverter(fileName, fileID);
+   if(converter == NULL) {
+      std::cerr << "Could not support format :" << fileName << std::endl;
+      return NULL;   
+   }
+   converter->writeHeader(channels, samplingRate, framePerBuffer, bytesPerSample*8);
+   
+   /*int length = strlen(headerInfo);
+   std::cout << headerInfo;
+   fwrite( headerInfo, length * sizeof(char), length, fileID );*/
+   
+   return 0;
+      
+}
+
+int audioFileWriter::start()
+{
+   startFlag = true;
+   pthread_t thId;
+   
+   if (pthread_create(&thId, 0, writeThread, (void*)this) != 0) {
+      std::cerr << "audioFileWriter : can't create writerThread" << std::endl;
+         return -1;
+   }
+   
+   return 0;
+}
+ 
+int audioFileWriter::stop()
+{
+   startFlag = false;
+   return 0;
+}
+   
+void* audioFileWriter::writeThread(void *args)
+{
+   audioFileWriter *This = (audioFileWriter *)args;
+   
+   if(This == NULL) {
+      fclose(This->fileID);
+      pthread_exit(NULL);
+      return NULL;
+   } 
+   
+   int Id = This->buffer->addReader();
+         
+   // write data
+   // #data
+   audioBlock* bufferBlock = NULL;
+   while(This->startFlag) {
+   
+      bufferBlock = This->buffer->readBlock(Id);
+      if(bufferBlock != NULL) {
+         This->converter->writeFrames(bufferBlock->buff);
+         This->buffer->updateReadIndex();
+         sage::usleep(100);
+      } 
+      else {
+         sage::usleep(1000);
+      }      
+      
+   }   
+   
+   std::cout << "audioFileWriter :end writeThread" << std::endl;
+   This->buffer->deleteReader(Id);   
+      
+   This->converter->close();   
+   fclose(This->fileID);
+   pthread_exit(NULL);
+   return NULL;
+
+}
+
Index: trunk/src/testing/src/sageAudioCircBuf.cpp
===================================================================
--- trunk/src/testing/src/sageAudioCircBuf.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioCircBuf.cpp	(revision 4)
@@ -0,0 +1,686 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sagesageAudioCircBuf.cpp - the circular buffer to managing audio sample blocks
+ * Author : Byungil Jeong, Hyejung Hur
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageAudioCircBuf.h"
+#include "sageAudioSync.h"
+#include "sageSync.h"
+#include "sageAudioModule.h"
+
+#define UINT8_TO_FLOAT(x) ( ((float)(x) -128.0)/ 127.0 )
+#define INT8_TO_FLOAT(x) ( (float) (x) / 127.0 )
+#define INT16_TO_FLOAT(x) ( (float)(x) / 32768.0 )
+#define FLOAT_TO_FLOAT(x) ( (float)(x) )
+
+sageAudioCircBuf::sageAudioCircBuf(sageSyncClient *sync, int nID, int keyframe)
+: readIndex(0), writeIndex(0), blocksNum(0), full(false), empty(true), bytesBlock(0),
+   sampleFmt(SAGE_SAMPLE_FLOAT32), sampleBuffSize(0), blockArray(NULL), audioId(-1), 
+   synchronizer(NULL), syncClientObj(sync), locked(false), lastFrameIndex(-1), refRead(0), refMutex(0),
+   instID(nID), syncKeyFrame(keyframe), lastgFrameIndex(-0)
+{
+   queueLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(queueLock, NULL);
+   pthread_mutex_unlock(queueLock);
+   notFull = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notFull, NULL);
+}
+
+void sageAudioCircBuf::setKeyframe(int keyno)
+{
+   syncKeyFrame = keyno;
+}   
+
+sageAudioCircBuf::~sageAudioCircBuf()
+{
+   pthread_cond_signal(notFull);
+
+   //pthread_mutex_unlock(queueLock);
+
+   if(blockArray != NULL) {
+      clearBlocks();
+   }
+   
+   if(queueLock)
+      free(queueLock);
+   if(notFull)
+      free(notFull);   
+}
+
+
+int sageAudioCircBuf::init(int id, int blockNum, sageSampleFmt fmt, int size)
+{
+   audioId = id;
+   
+   refRead =0;
+   refMutex =0;
+   readers.clear();
+   readers.push_back(0);
+
+   if(blockArray != NULL) {
+      clearBlocks();
+   }
+
+   // initialize variables
+   writeIndex = readIndex = 0;
+   blocksNum = blockNum;
+   sampleFmt = fmt;
+   sampleBuffSize = size;
+         
+   blockArray = new audioBlock[blocksNum];
+   
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *array;
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = new float[sampleBuffSize];
+               //array = (float*) malloc(sizeof(float) * sampleBuffSize);
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 0.0;
+               }         
+               blockArray[j].buff = (void*) array;
+            }
+            bytesBlock = sizeof(float) * sampleBuffSize;   
+         }
+         break;
+      case SAGE_SAMPLE_INT16 :
+         {
+            short *array;   
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = new short[sampleBuffSize];
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 0;
+               }         
+               blockArray[j].buff = (void*) array;         
+            }
+            bytesBlock = sizeof(short) * sampleBuffSize;   
+         }   
+         break;
+      case SAGE_SAMPLE_INT8 :
+         {
+            char *array;         
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = new char[sampleBuffSize];
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = '0';
+               }         
+               blockArray[j].buff = (void*) array;         
+            }
+            bytesBlock = sizeof(char) * sampleBuffSize;         
+         }      
+         break; 
+      case SAGE_SAMPLE_UINT8 :
+         {
+            unsigned char *array;      
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = new unsigned char[sampleBuffSize];
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 128;
+               }         
+               blockArray[j].buff = (void*) array;               
+            }      
+            bytesBlock = sizeof(unsigned char) * sampleBuffSize;   
+         }      
+         break;
+   }
+   
+   full = false;
+   empty = true;
+   locked = false;
+   lastFrameIndex = -1;
+   synchronizer = NULL;
+   
+   return 0;
+}
+
+void sageAudioCircBuf::clearBlocks()
+{
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *array; 
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (float*) blockArray[j].buff;
+               delete[] array; 
+               blockArray[j].buff = NULL;
+            }   
+         }
+         break;
+      case SAGE_SAMPLE_INT16 :
+         {
+            short *array; 
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (short*) blockArray[j].buff;
+               delete[] array; 
+               blockArray[j].buff = NULL;
+            }
+         }   
+         break;
+      case SAGE_SAMPLE_INT8 :
+         {
+            char *array; 
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (char*) blockArray[j].buff;
+               delete[] array; 
+               blockArray[j].buff = NULL;
+            }
+         }      
+         break; 
+      case SAGE_SAMPLE_UINT8 :
+         {
+            unsigned char *array; 
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (unsigned char*) blockArray[j].buff;
+               delete[] array; 
+               blockArray[j].buff = NULL;
+            }
+         }      
+         break;
+      default :
+         break;
+   }
+   delete [] blockArray;
+   blockArray = NULL;   
+   
+}
+
+void sageAudioCircBuf::reset()
+{
+   readIndex = 0;
+   writeIndex = 0;
+   full = false;
+   empty = true;
+   locked = false;
+   lastFrameIndex = -1;
+   //synchronizer = NULL;
+
+   refMutex =0;   
+   refRead =0;
+   readers.clear();
+   readers.push_back(0);   
+
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *array;
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (float*) blockArray[j].buff;
+               blockArray[j].reformatted = 0;            
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 0.0;
+               }         
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT16 :
+         {
+            short *array;   
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (short*) blockArray[j].buff;
+               blockArray[j].reformatted = 0;               
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 0;
+               }         
+            }
+         }   
+         break;
+      case SAGE_SAMPLE_INT8 :
+         {
+            char *array;         
+            for( int j=0; j<blocksNum ; j++ ) {
+               array = (char*) blockArray[j].buff;
+               blockArray[j].reformatted = 0;               
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = '0';
+               }         
+            }
+         }      
+         break; 
+      case SAGE_SAMPLE_UINT8 :
+         {
+            unsigned char *array;      
+            for( int j=0; j<blocksNum ; j++ ) {
+               array =(unsigned char*) blockArray[j].buff;
+               blockArray[j].reformatted = 0;               
+               for( int k=0; k< sampleBuffSize ; k++ ) {
+                  array[k] = 128;
+               }         
+            }
+         }      
+         break;
+   }
+   
+   pthread_cond_signal(notFull);
+   //pthread_mutex_unlock(queueLock);   
+
+}
+
+
+
+audioBlock* sageAudioCircBuf::readBlock(int Id)
+{
+   if(refMutex == 1) return NULL;
+   if (empty) {
+      return NULL;
+   }
+   else {
+      if(readers[Id] == 0) {
+         readers[Id] = 1;
+         refRead++;
+      } else {
+         return NULL;
+      }
+   }
+   //std::cout << "readBlock " << std::endl;
+
+   return &blockArray[readIndex];
+}
+
+audioBlock* sageAudioCircBuf::readBlock(int Id, int frameNum)
+{
+   if(refMutex == 1) return NULL;
+   
+   if (empty) {
+      return NULL;
+   }
+   else   {
+      // ????? - not working correctly
+      if(readers[Id] == 0) {
+         readers[Id] = 1;
+         refRead++;
+      } else {
+         return NULL;
+      }
+            
+      //if (frameNum%10000 >= blockArray[readIndex].frameIndex) {
+      if (frameNum >= blockArray[readIndex].frameIndex) {
+         return &blockArray[readIndex];
+      }   
+   }   
+      
+   return NULL;
+}
+/*
+audioBlock* sageAudioCircBuf::readBlock()
+{
+   if (empty) {
+      return NULL;
+   }
+   else   
+      return &blockArray[readIndex];
+}
+
+audioBlock* sageAudioCircBuf::readBlock(int frameNum)
+{
+   if (empty) {
+      return NULL;
+   }
+   else   {   
+      //if (frameNum%10000 >= blockArray[readIndex].frameIndex) {
+      if (frameNum >= blockArray[readIndex].frameIndex) {
+         return &blockArray[readIndex];
+      }   
+   }   
+      
+   return NULL;
+}
+*/
+
+audioBlock* sageAudioCircBuf::getNextWriteBlock()
+{
+   if(synchronizer) {
+      if(locked == true) {
+         // waiting for signal from graphic stream receiver
+         locked = !synchronizer->checkSignal(audioId);
+         if(locked == true) {
+            //std::cout << "checkSignal : locked " << std::endl; 
+         } else 
+         {
+            std::cout << "checkSignal : free " << std::endl;
+         }
+      }
+   }
+
+   // if buffer is full or if buffer is locked for writing
+   pthread_mutex_lock(queueLock);
+   while (full) {
+      pthread_cond_wait(notFull, queueLock);
+      //return NULL;
+   }   
+   pthread_mutex_unlock(queueLock);
+   if (locked) {
+      return NULL;
+   }       
+   audioBlock *block = &blockArray[writeIndex];
+   clearBlock(writeIndex);
+
+   //std::cout << "wrote " << std::endl;
+
+   return block;
+}
+
+
+int sageAudioCircBuf::updateReadIndex()
+{
+   refMutex = 1;
+   int gframeIndex=0;
+   int size = readers.size();
+   if(refRead == size) {
+      gframeIndex = blockArray[readIndex].frameIndex;
+      clearBlock(readIndex);
+      readIndex = (readIndex+1) % blocksNum;
+      
+      full = false;
+      //pthread_mutex_unlock(queueLock);
+      pthread_cond_signal(notFull);
+            
+      if (readIndex == writeIndex) {
+         empty = true;
+      }
+      refRead = 0;
+      for(int i=0; i <size; i++)
+      {
+         readers[i] =0;
+      }
+   }
+   
+   if(syncClientObj)
+   {
+      int tempIndex = gframeIndex % syncKeyFrame;
+      int diff = lastgFrameIndex - tempIndex;
+      
+      if(diff > 0) 
+      {
+         tempIndex = gframeIndex -tempIndex;
+         //std::cout << "-------> sync signal -- audio update" << tempIndex << instID << std::endl;
+         syncClientObj->sendSlaveUpdate(tempIndex, instID, syncKeyFrame, SAGE_UPDATE_AUDIO);
+
+         //syncClientObj->sendSlaveUpdate(gframeIndex + 1, instID,1, SAGE_UPDATE_AUDIO);
+      }
+      lastgFrameIndex = gframeIndex % syncKeyFrame;
+   }            
+   refMutex =0;   
+   return readIndex;
+}
+
+
+/*
+int sageAudioCircBuf::updateReadIndex()
+{
+   clearBlock(readIndex);
+   readIndex = (readIndex+1) % blocksNum;
+   full = false;
+   if (readIndex == writeIndex)
+      empty = true;
+      
+   return 0;
+}
+*/
+
+int sageAudioCircBuf::updateWriteIndex()
+{
+   audioBlock *block = &blockArray[writeIndex];
+   lastFrameIndex = block->frameIndex;
+
+   writeIndex = (writeIndex+1) % blocksNum;
+   int nextIndex = (writeIndex+1) % blocksNum;
+   if (nextIndex == readIndex) {
+      full = true;
+      //pthread_mutex_lock(queueLock);
+   }   
+
+   empty = false;
+
+   // check keyframe 
+   if(synchronizer) {
+      locked = synchronizer->checkKeyFrame(audioId, lastFrameIndex);
+   }
+   //std::cout << "checkKeyFrame : " << lastFrameIndex << std::endl; 
+   if(locked) {
+      std::cout << "checkKeyFrame : keyframe -> locked : " << lastFrameIndex << std::endl; 
+   } 
+   return 0;
+}
+
+int sageAudioCircBuf::getReadIndex() 
+{ 
+   return readIndex; 
+}
+int sageAudioCircBuf::getWriteIndex() 
+{ 
+   return writeIndex; 
+}
+
+int sageAudioCircBuf::convertToFloat(sageSampleFmt fmt, void* rawdata, audioBlock* block)
+{
+   if(sampleFmt != SAGE_SAMPLE_FLOAT32) return -1;
+
+   float *wptr = (float*) block->buff;
+
+   switch(fmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *rptr = (float*) rawdata;
+            for( int i=0; i< sampleBuffSize; i++ ) 
+            {
+               *wptr++ = FLOAT_TO_FLOAT(*rptr);
+               rptr++;
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT16 :
+         {
+            short *rptr = (short*) rawdata;
+            for( int i=0; i< sampleBuffSize; i++ ) 
+            {
+               *wptr++ = INT16_TO_FLOAT(*rptr);
+               rptr++;
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT8 :
+         {
+            char *rptr = (char*) rawdata;
+            for( int i=0; i< sampleBuffSize; i++ ) 
+            {
+               *wptr++ = INT8_TO_FLOAT(*rptr);
+               rptr++;
+            }
+         }
+         break;
+      case SAGE_SAMPLE_UINT8 :
+         {
+            unsigned char *rptr = (unsigned char*) rawdata;
+         
+            for( int i=0; i< sampleBuffSize; i++ ) 
+            {
+               *wptr++ = UINT8_TO_FLOAT(*rptr);
+               rptr++;
+            }
+         }
+         break;
+   }
+
+   return 1;
+}
+
+int sageAudioCircBuf::merge(audioBlock* block) 
+{
+   std::vector<sageAudioCircBuf*> bufferList = sageAudioModule::_instance->getBufferList();
+
+   float size = 1.0 / bufferList.size();
+
+   float *wptr = (float*) block->buff;
+   /*for( int i=0; i< sampleBuffSize; i++ )
+   {
+      *wptr = *wptr * size ;
+      //*wptr = *wptr * 0.0 ;
+      wptr++;
+   }*/
+   float *rptr = NULL;
+
+   std::vector<sageAudioCircBuf*>::iterator iterBuffer;
+   sageAudioCircBuf* temp = NULL;
+   audioBlock *secondblock = NULL; 
+   for(iterBuffer = bufferList.begin(); iterBuffer != bufferList.end(); iterBuffer++)
+   {
+      temp = (sageAudioCircBuf*) *iterBuffer;
+      if(temp->getAudioId() != audioId)
+      {
+         secondblock = temp->readBlock();
+         if(secondblock == NULL) continue;
+         if(secondblock->reformatted != 1) continue;
+
+         wptr = (float*) block->buff;
+         rptr = (float*) secondblock->buff;
+         for( int i=0; i< sampleBuffSize; i++ )
+         {
+            //*wptr = *rptr;
+            //*wptr = *wptr + size * (*rptr);
+            *wptr = *wptr + (*rptr);
+            //std::cout << *wptr << std::endl;
+            wptr++;
+            rptr++;
+         }
+         //std::cout << "merging " << temp->getAudioId() << ", mine: " << audioId << " size : " << size << std::endl;
+
+         temp->updateReadIndex();
+      }
+   }
+
+   return 1;
+}
+
+int sageAudioCircBuf::getSize() 
+{ 
+   return blocksNum; 
+}
+
+int sageAudioCircBuf::getAudioId()
+{
+   return audioId;
+}
+   
+void sageAudioCircBuf::clearBlock(int frameNum)
+{
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *array = (float*) blockArray[frameNum].buff; 
+            for( int j=0; j< sampleBuffSize ; j++ ) {
+               array[j] = 0;
+            }      
+         }
+         break;
+      case SAGE_SAMPLE_INT16 :
+         {
+            short *array = (short*) blockArray[frameNum].buff; 
+            for( int j=0; j< sampleBuffSize ; j++ ) {
+               array[j] = 0;
+            }      
+         }   
+         break;
+      case SAGE_SAMPLE_INT8 :
+         {
+            char *array = (char*) blockArray[frameNum].buff; 
+            for( int j=0; j< sampleBuffSize ; j++ ) {
+               array[j] = '0';
+            }
+         }      
+         break; 
+      case SAGE_SAMPLE_UINT8 :
+         {
+            unsigned char *array = (unsigned char*) blockArray[frameNum].buff; 
+            for( int j=0; j< sampleBuffSize ; j++ ) {
+               array[j] = '0';
+            }         
+         }      
+         break;
+      default :
+         break;
+   }
+
+}
+
+int sageAudioCircBuf::getBytesBlock()
+{
+   return bytesBlock;
+}
+
+void sageAudioCircBuf::connectSync(sageAudioSync* synch)
+{
+   synchronizer = synch;
+
+}
+
+void sageAudioCircBuf::connectSyncClient(sageSyncClient* synch)
+{
+   syncClientObj = synch;
+   if(syncClientObj != NULL)
+   {
+      syncClientObj->sendSlaveUpdate(1, instID, syncKeyFrame, SAGE_UPDATE_AUDIO);
+   } 
+}
+   
+void sageAudioCircBuf::setLock()
+{
+   //locked = true;
+}
+
+void sageAudioCircBuf::setFree()
+{
+   //locked = false;
+}
+
+int sageAudioCircBuf::getLastFrameIdx()
+{
+   return lastFrameIndex;
+}
+
+int sageAudioCircBuf::addReader()
+{
+   int index = readers.size();
+   readers.push_back(0);
+   return index;   
+}
+
+void sageAudioCircBuf::deleteReader(int Id)
+{
+   readers[Id] = -1;
+}
Index: trunk/src/testing/src/sageBlockQueue.cpp
===================================================================
--- trunk/src/testing/src/sageBlockQueue.cpp	(revision 4)
+++ trunk/src/testing/src/sageBlockQueue.cpp	(revision 4)
@@ -0,0 +1,420 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlockQueue.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBlock.h"
+#include "sageBlockQueue.h"
+
+sageBlockQueue::sageBlockQueue(int len) : full(false), curLen(0), active(true), 
+      pointerNum(0), maxPointerID(0), listLock(NULL), notEmpty(NULL), pixelPassed(false)
+{
+   queueLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(queueLock, NULL);
+   pthread_mutex_unlock(queueLock);
+   notFull = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notFull, NULL);
+
+   maxLen = len;
+   head = tail = NULL;
+
+   for (int i=0; i<MAX_ENDPOINT_NUM; i++) {
+      pointerList[i] = &invalid;
+      skipFrame[i] = -1;
+      lastFrame[i] = 0;
+      lastPixelFrame[i] = 1;
+   }
+   
+   addReader();
+}
+
+int sageBlockQueue::addReader(int id)
+{
+   pthread_mutex_lock(queueLock);
+   pointerList[id] = NULL;
+   pointerNum++;
+   maxPointerID = MAX(id, maxPointerID);
+   pthread_mutex_unlock(queueLock);
+   
+   return 0;
+}
+
+int sageBlockQueue::removeReader(int id, pthread_mutex_t &lock)
+{
+   pthread_mutex_lock(queueLock);
+   
+   while (pointerList[id]) {
+      sageBlockContainer *curEntry = pointerList[id];
+      sageBlock *block = curEntry->block;
+   
+      curEntry->rcnt--;
+      pointerList[id] = curEntry->next;
+      
+      if (curEntry->rcnt <= 0) {
+         head = curEntry->next;
+         curLen--;
+         delete curEntry;
+         
+         full = (curLen >= maxLen);
+         if (!full)
+            pthread_cond_signal(notFull);      
+         
+         if (block) {
+            pthread_mutex_lock(&lock);
+            block->dereference();
+            if (block->getRefCnt() <= 0)
+               delete block;
+            pthread_mutex_unlock(&lock);   
+         }   
+      }
+   }
+      
+   pointerList[id] = &invalid;
+   pointerNum--;
+   pthread_mutex_unlock(queueLock);
+   
+   return 0;
+}
+
+void sageBlockQueue::enque(sageBlock* block)
+{
+   pthread_mutex_lock(queueLock);
+   
+   while (full) {
+      //std::cout << "wait not full " << block->frameNum << std::endl;
+      pthread_cond_wait(notFull, queueLock);
+   }
+   
+   sageBlockContainer *newEntry = new sageBlockContainer;
+   newEntry->block = block;
+   newEntry->rcnt = pointerNum;
+   block->setRefCnt(pointerNum);
+   
+   if (isEmpty()) {
+      head = tail = newEntry;   
+   }
+   else {
+      tail->next = newEntry;
+      tail = newEntry;
+   }
+   
+   for (int i=0; i<=maxPointerID; i++) {
+      if (!pointerList[i])
+         pointerList[i] = newEntry;
+   }
+   
+   curLen++;
+   full = (curLen >= maxLen);
+   
+   pthread_mutex_unlock(queueLock);
+   
+   if (listLock && notFull) {
+      pthread_mutex_lock(listLock);
+      pthread_cond_broadcast(notEmpty);
+      pthread_mutex_unlock(listLock);
+   }   
+}
+
+sageBlock* sageBlockQueue::deque(int frame, bool activeMode, int id)
+{
+   pthread_mutex_lock(queueLock);
+
+   if (id > maxPointerID) {
+      sage::printLog("sageBlockQueue::deque : invalid pointer ID");
+      pthread_mutex_unlock(queueLock);   
+      return NULL;
+   }   
+   
+   if (isEmpty()) {
+      pthread_mutex_unlock(queueLock);
+      return NULL;
+   }   
+
+   sageBlockContainer *curEntry = pointerList[id];
+   sageBlock *block = NULL;
+      
+   if (curEntry) {
+      block = curEntry->block;
+
+      if (block) {
+         if (pixelPassed && (lastPixelFrame[id] < block->getFrameID()))
+            lastFrame[id] = block->getFrameID() - 1;
+            
+         if (activeMode && (block->getFrameID() > frame+1)) {
+            pthread_mutex_unlock(queueLock);
+            return NULL;
+         }
+      
+         curEntry->rcnt--;
+         pointerList[id] = curEntry->next;
+         
+         if (curEntry->rcnt <= 0) {
+            if (curEntry != head) {
+               sage::printLog("sageBlockQueue::deque : queueing system error");
+               pthread_mutex_unlock(queueLock);
+               return NULL;
+            }   
+            else {
+               head = curEntry->next;
+            }
+            
+            curLen--;
+            delete curEntry;
+         }
+      
+         switch(block->getFlag()) {
+            case SAGE_SKIP_BLOCK:
+               skipFrame[id] = block->getFrameID();
+               pixelPassed = false;
+               break;
+            case SAGE_STOP_BLOCK:
+            case SAGE_CLEAR_BLOCK:
+               active = false;
+               pixelPassed = false;
+               break;
+            case SAGE_PIXEL_BLOCK:
+               active = true;
+               pixelPassed = true;
+               lastPixelFrame[id] = block->getFrameID();
+               break;   
+         }      
+      }
+                  
+      full = (curLen >= maxLen);
+      if (!full)
+         pthread_cond_signal(notFull);
+   }
+   else {
+      //sage::printLog("sageBlockQueue::deque() : no new pixel data for the endpoint");
+   }   
+      
+   pthread_mutex_unlock(queueLock);
+   
+   return block;
+}
+
+void sageBlockQueue::skipBlocks(int frame, int id)
+{
+/*
+   pthread_mutex_lock(queueLock);
+
+   if (isEmpty()) {
+      pthread_mutex_unlock(queueLock);
+      return;
+   }   
+
+   if (id > maxPointerID) {
+      sage::printLog("sageBlockQueue::skipBlocks : invalid pointer ID");
+      pthread_mutex_unlock(queueLock);   
+      return;
+   }   
+   
+   sageBlockContainer *curEntry = pointerList[id];
+   sageBlock *block = NULL;
+   
+   while (curEntry) {
+      block = curEntry->block;
+      if (block) {
+         lastFrame[id] = block->getFrameID() - 1;
+         if (block->getFlag() == SAGE_STOP_BLOCK)
+            active = false;
+         else
+            active = true;   
+
+         if (block->getFrameID() >= frame)
+            break;
+      }      
+      
+      curEntry->rcnt--;
+      
+      if (curEntry->rcnt <= 0) {
+         if (curEntry != head) {
+            sage::printLog("sageBlockQueue::skipBlocks : queueing system error");
+            pthread_mutex_unlock(queueLock);
+            return;
+         }   
+         else {
+            head = curEntry->next;
+         }
+
+         curLen--;
+         delete curEntry;
+         if (block)
+            delete block;   
+      }
+      
+      curEntry = curEntry->next;
+   }
+   
+   pointerList[id] = curEntry;
+   full = (curLen >= maxLen);
+   if (!full)
+      pthread_cond_signal(notFull);   
+
+   pthread_mutex_unlock(queueLock);
+*/   
+}
+
+/*
+sageBlock* sageBlockQueue::searchBlock(int x, int y)
+{
+   if (!head)
+      return NULL;
+      
+   pthread_mutex_lock(queueLock);
+   
+   sageBlockContainer *curEntry = head;
+   sagePixelBlock *block = NULL;
+   
+   while(curEntry) {
+      block = (sagePixelBlock *)curEntry->block;   
+      if (block && (block->getFlag() == SAGE_PIXEL_BLOCK) && block->isInRect(x,y)) {
+         pthread_mutex_unlock(queueLock);
+         return block;
+      }   
+      curEntry = curEntry->next;
+   }
+   
+   pthread_mutex_unlock(queueLock);
+   
+   return NULL;
+}
+*/
+
+void sageBlockQueue::clear()
+{
+   pthread_mutex_lock(queueLock);
+   while(!isEmpty()) {
+      sageBlockContainer *curEntry = head;
+      head = head->next;
+      curLen--;
+            
+      if (curEntry) {
+         sageBlock *block = curEntry->block;
+         if (block)
+            delete block;
+         delete curEntry;   
+      }      
+   }
+   
+   tail = NULL;
+   pthread_mutex_unlock(queueLock);
+   
+   full = false;
+   pthread_cond_signal(notFull);
+}
+
+void sageBlockQueue::initCondVar(pthread_mutex_t *lock, pthread_cond_t *cond)
+{ 
+   listLock = lock; 
+   notEmpty = cond;   
+}
+
+sageBlockQueue::~sageBlockQueue()
+{
+   if (queueLock)
+      free(queueLock);
+   
+   if (notFull)
+      free(notFull);
+}
+
+
+blockQueueList::blockQueueList()
+{
+   queueList.clear();
+
+   listLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(listLock, NULL);
+   pthread_mutex_unlock(listLock);
+   notEmpty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notEmpty, NULL);
+}
+
+int blockQueueList::addQueue(sageBlockQueue *q)
+{
+   q->initCondVar(listLock, notEmpty);
+   queueList.push_back(q);
+   
+   return queueList.size();
+}
+
+sageBlockQueue* blockQueueList::operator[](int id)
+{
+   return queueList[id];
+}
+
+blockQueueList& blockQueueList::operator=(blockQueueList &list)
+{
+   queueList = list.queueList;
+   listLock = list.listLock;
+   notEmpty = list.notEmpty;
+
+   return *this;
+}
+
+int blockQueueList::waitForData()
+{
+   int streamNum = queueList.size();
+   int empty = true;
+   
+   pthread_mutex_lock(listLock);
+   
+   for (int i=0; i<streamNum; i++) {   
+      empty = empty && queueList[i]->isEmpty();
+   }
+   
+   if (empty)
+      pthread_cond_wait(notEmpty, listLock);
+   
+   pthread_mutex_unlock(listLock);
+      
+   return 0;   
+}
+
+void blockQueueList::stopWaiting()
+{
+   pthread_mutex_lock(listLock);
+   pthread_cond_broadcast(notEmpty);
+   pthread_mutex_unlock(listLock);
+}
+
+blockQueueList::~blockQueueList()
+{
+   queueList.clear();
+}
Index: trunk/src/testing/src/sageDisplayManager.cpp
===================================================================
--- trunk/src/testing/src/sageDisplayManager.cpp	(revision 4)
+++ trunk/src/testing/src/sageDisplayManager.cpp	(revision 4)
@@ -0,0 +1,1242 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDisplayManager.cpp
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageVersion.h"
+
+#if defined(__APPLE__)
+#include "appleMultiContext.h"
+#else
+#include "sdlSingleContext.h"
+#endif
+
+#include "sageDisplayManager.h"
+#include "sageSharedData.h"
+#include "sageEvent.h"
+#include "sageReceiver.h"
+#include "sageSync.h"
+#include "sageDisplay.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+#include "pixelDownloader.h"
+#include "sageBlockQueue.h"
+
+sageDisplayManager::~sageDisplayManager()
+{
+   if (shared)
+      delete shared;
+
+   if (tcpObj)
+      delete tcpObj;
+
+   if (udpObj)
+      delete udpObj;
+
+   if (syncBBServerObj)
+      delete syncBBServerObj;
+
+
+   if (syncServerObj)
+      delete syncServerObj;
+
+	std::vector<pixelDownloader*>::iterator iter;
+	std::vector<char*>::iterator iter_str= reconfigStr.begin();
+
+	pixelDownloader* temp_app= NULL;
+	char* temp_str= NULL;
+	for(iter = downloaderList.begin(); iter != downloaderList.end(); iter++, iter_str++)
+	{
+		temp_app = (pixelDownloader*) *iter;
+		if(!temp_app) continue;
+		delete temp_app;
+		temp_str = (char*) *iter_str;
+		if(!temp_str) continue;
+		delete temp_str;
+	}
+	downloaderList.clear();
+	reconfigStr.clear();
+}
+
+sageDisplayManager::sageDisplayManager(int argc, char **argv)
+{
+   if (argc < 7) {
+      sage::printLog("SAGE receiver : More arguments are needed");
+      exit(0);
+   }
+
+   shared = new dispSharedData;
+
+   /**
+    * for example,
+    * 1, 67.58.62.100 // fs IP
+    * 2. 20002 // fs port
+    * 3. 17 // node number)
+    * 4. 12000 // sync port
+    * 5. 0 // display ID
+    * 6, 1 // global sync
+    *
+    * 7, 11001 // sync barrier port
+    * 8, 100 // refresh rate in Hz
+    * 9, syncMaster polling interval (in while loop, how long select() waits
+    * 10, 0 nosync, 1 data sync only, 2 swapbuffer sync(default), 3 NTP
+    */
+
+   shared->nodeID = atoi(argv[3]); // node number on which this object is running
+
+   syncPort = atoi(argv[4]);
+   displayID = atoi(argv[5]);
+
+
+   syncBarrierPort = atoi(argv[7]);
+   syncRefreshRate = atoi(argv[8]); // Hz
+   syncMasterPollingInterval = atoi(argv[9]); // in usec, 1000 = 1ms
+   syncLevel = atoi(argv[10]);
+
+   /**
+    * 0th node (67.58.62.93) will become the syncMaster
+    */
+   bool globalSync = (bool)atoi(argv[6]);
+   if (globalSync)
+      syncMaster = ((shared->nodeID == 0) && (displayID == 0));
+   else
+	   syncMaster = (shared->nodeID == 0);
+
+
+   /**
+    * creating syncServerObject
+    */
+   if (syncMaster && syncLevel > 0) {
+	   syncServerObj = NULL;
+	   sage::printLog("\nSDM::SDM() : SDM %d creating the syncBBServer.", shared->nodeID);
+
+	   syncBBServerObj = new sageSyncBBServer(syncLevel);
+
+	   // init opens socket and starts syncServerThread
+	   if (syncBBServerObj->init(syncPort) < 0) {
+		   sage::printLog("SAGE receiver : Error init'ing the sync server object");
+		   delete syncBBServerObj;
+		   exit(0);
+	   }
+
+	   // two phase
+	   if ( syncLevel == 2 ) {
+		   sage::printLog("\nSDM::SDM() : SDM %d initializing syncBarrierServer", shared->nodeID);
+		   if ( syncBBServerObj->initBarrier(syncBarrierPort) < 0 ) {
+			   sage::printLog("sageDisplayManager::sageDisplayManager() : Error in sageSyncServer::initBarrier(%d)", syncBarrierPort);
+			   delete syncBBServerObj;
+			   exit(0);
+		   }
+	   }
+   }
+   else if (syncMaster && syncLevel == -1) { // OLD one
+	   syncBBServerObj = NULL;
+	   sage::printLog("\nSDM SyncMaster : start OLD Sync Server");
+	   syncServerObj = new sageSyncServer;
+
+	   if (syncServerObj->init(syncPort) < 0) {
+		   sage::printLog("SAGE receiver : Error init'ing the sync server object");
+		   delete syncServerObj;
+		   exit(0);
+	   }
+   }
+
+   char fsIP[SAGE_IP_LEN];
+   strcpy(fsIP, argv[1]);
+   int fsPort = atoi(argv[2]);
+
+   /**
+    * connecting to fsManager
+    */
+   fsClient::init(fsPort);
+   connect(fsIP);
+
+   //sage::printLog("sageDisplayManager::sageDisplayManager() : SDM %d register to a Free Space Manager",shared->nodeID);
+   char regMsg[TOKEN_LEN];
+   sprintf(regMsg, "%d %d", shared->nodeID, displayID);
+   sendMessage(REG_GRCV, regMsg);
+
+   rcvEnd = false;
+   sprintf(CLEAR_STR, "0 0 0 0 0 0");
+
+   pthread_t thId;
+
+   if (pthread_create(&thId, 0, msgCheckThread, (void*)this) != 0) {
+      sage::printLog("sageDisplayManager: can't create message checking thread");
+   }
+
+   if (pthread_create(&thId, 0, perfReportThread, (void*)this) != 0) {
+      sage::printLog("sageDisplayManager: can't create performance report thread");
+   }
+}
+
+int sageDisplayManager::init(char *data)
+{
+   char token[TOKEN_LEN];
+   char masterIp[SAGE_IP_LEN];
+   int screenWidth, screenHeight;
+   int dimX, dimY;
+   int revY[MAX_TILES_PER_NODE];
+   sageDisplayConfig dispCfg;
+/*
+   getToken(data, token);
+   nwCfg.rcvBufSize = atoi(token);
+
+   getToken(data, token);
+   nwCfg.sendBufSize = atoi(token);
+
+   getToken(data, token);
+   nwCfg.mtuSize = atoi(token);
+
+   getToken(data, token);
+   streamPort = atoi(token);
+
+   getToken(data, token);
+   shared->bufSize = atoi(token)*1048576; // receiverBufSize to MB
+
+   getToken(data, token);
+   int fullScreen = atoi(token);
+
+   int tokenNum = getToken(data, token);
+   totalRcvNum = atoi(token);
+
+   if (tokenNum < 1) {
+      sage::printLog("sageDisplayManager::init() : insufficient parameters in RCV_INIT message");
+      return -1;
+   }
+
+   getToken(data, masterIp);
+
+   getToken(data, token);
+   screenWidth = atoi(token);
+   getToken(data, token);
+   screenHeight = atoi(token);
+   getToken(data, token);
+   dimX = atoi(token);
+   getToken(data, token);
+   dimY = atoi(token);
+   getToken(data, token);
+   dispCfg.winX = atoi(token);
+   tokenNum = getToken(data, token);
+   dispCfg.winY = atoi(token);
+
+   if (tokenNum < 1) {
+      sage::printLog("[%d] SDM::init() : insufficient parameters in RCV_INIT message !", shared->nodeID);
+      return -1;
+   }
+
+   for (int i=0; i<dimY; i++) {
+      for (int j=0; j<dimX; j++) {
+         getToken(data, token);  // will remove this line (tile id read) later.....
+         //shared->tileTable.addEntry(atoi(token));
+         getToken(data, token);
+         dispCfg.tileRect[i*dimX + j].x = atoi(token);
+         getToken(data, token);
+         dispCfg.tileRect[i*dimX + j].y = atoi(token);
+         dispCfg.tileRect[i*dimX + j].width = screenWidth;
+         dispCfg.tileRect[i*dimX + j].height = screenHeight;
+         getToken(data, token);
+         revY[i*dimX + j] = atoi(token);
+      }
+   }
+   */
+   char *tokenbuf;
+
+   getToken(data, token, &tokenbuf);
+      nwCfg.rcvBufSize = atoi(token);
+
+      getToken(NULL, token, &tokenbuf);
+      nwCfg.sendBufSize = atoi(token);
+
+      getToken(NULL, token, &tokenbuf);
+      nwCfg.mtuSize = atoi(token);
+
+      getToken(NULL, token, &tokenbuf);
+      streamPort = atoi(token);
+
+      getToken(NULL, token, &tokenbuf);
+      shared->bufSize = atoi(token)*1048576; // receiverBufSize to MB
+
+      getToken(NULL, token, &tokenbuf);
+      int fullScreen = atoi(token);
+
+      getToken(NULL, token, &tokenbuf);
+      totalRcvNum = atoi(token);
+
+
+      getToken(NULL, token, &tokenbuf);
+      strcpy(masterIp, token);
+
+      getToken(NULL, token, &tokenbuf);
+      screenWidth = atoi(token);
+      getToken(NULL, token, &tokenbuf);
+      screenHeight = atoi(token);
+      getToken(NULL, token, &tokenbuf);
+      dimX = atoi(token);
+      getToken(NULL, token, &tokenbuf);
+      dimY = atoi(token);
+      getToken(NULL, token, &tokenbuf);
+      dispCfg.winX = atoi(token);
+      getToken(NULL, token, &tokenbuf);
+      dispCfg.winY = atoi(token);
+
+      for (int i=0; i<dimY; i++) {
+         for (int j=0; j<dimX; j++) {
+            getToken(NULL, token, &tokenbuf); // will remove this line (tile id read) later.....
+            //shared->tileTable.addEntry(atoi(token));
+            getToken(NULL, token, &tokenbuf);
+            dispCfg.tileRect[i*dimX + j].x = atoi(token);
+            getToken(NULL, token, &tokenbuf);
+            dispCfg.tileRect[i*dimX + j].y = atoi(token);
+            dispCfg.tileRect[i*dimX + j].width = screenWidth;
+            dispCfg.tileRect[i*dimX + j].height = screenHeight;
+            getToken(NULL, token, &tokenbuf);
+            revY[i*dimX + j] = atoi(token);
+         }
+      }
+
+   //shared->tileTable.generateTable();
+
+   //sage::printLog("SDM::init() : SDM %d init message has successfully parsed",shared->nodeID);
+
+   dispCfg.width = screenWidth;
+   dispCfg.height = screenHeight;
+   dispCfg.dimX = dimX;
+   dispCfg.dimY = dimY;
+
+   if (dimX > 1)
+      dispCfg.mullionX = (int)floor((dispCfg.tileRect[1].x - dispCfg.tileRect[0].x - screenWidth)/2.0 + 0.5);
+   else
+      dispCfg.mullionX = 0;
+
+   if (dimY > 1)
+      dispCfg.mullionY = (int)floor((revY[0] - revY[dimX*(dimY-1)] - screenHeight)/2.0 + 0.5);
+   else
+      dispCfg.mullionY = 0;
+
+   dispCfg.xpos = dispCfg.tileRect[0].x;
+   dispCfg.ypos = revY[dimX*(dimY-1)];
+   dispCfg.fullScreenFlag = fullScreen;
+   dispCfg.red = 0;
+   dispCfg.green = 0;
+   dispCfg.blue = 0;
+   dispCfg.displayID = displayID;
+
+#if defined(__APPLE__)
+   shared->context = (displayContext *) new appleMultiContext;
+#else
+   shared->context = (displayContext *) new sdlSingleContext;
+#endif
+   if (shared->context->init(dispCfg) < 0) {
+      sage::printLog("[%d] SDM::init() : Error creating display object ", shared->nodeID);
+      return -1;
+   }
+
+   // clear the screen after startup
+   shared->context->clearScreen();
+   shared->context->refreshScreen();
+
+   //sage::printLog("sageDisplayManager::init() : SDM %d is creating sageDisplay object", shared->nodeID);
+   shared->displayObj = new sageDisplay(shared->context, dispCfg);
+
+   if (initNetworks() < 0)
+      return -1;
+
+   // sageSyncClient
+	pthread_t thId;
+   if ( syncLevel > 0 ) {
+		shared->syncClientObj = new sageSyncClient(syncLevel);
+
+   // connect to syncMaster
+	   // The parameter shared->nodeID will trigger send() which is for new sync
+	   if (shared->syncClientObj->connectToServer(masterIp, syncPort, shared->nodeID) < 0) {
+		   sage::printLog("SDM::init() : SDM %d, Fail to connect to syncServer !", shared->nodeID);
+		   return -1;
+	   }
+	   else {
+		   //sage::printLog("SDM::init() : SDM %d, Connected to sync master %s:%d", shared->nodeID, masterIp, syncPort);
+	   }
+
+	   sage::sleep(1);
+	   if ( syncLevel == 2 ) {
+		   if (shared->syncClientObj->connectToBarrierServer(masterIp, syncBarrierPort, shared->nodeID) < 0) {
+			   sage::printLog("[%d] SDM::init() : Failed to connect to syncBarrierServer !", shared->nodeID);
+			   return -1;
+		   }
+		   else {
+			   //sage::printLog("SDM::init() : SDM %d, Connected to sync master barrier %s:%d", shared->nodeID, masterIp, syncBarrierPort);
+		   }
+	   }
+
+	   // start syncCheckThread
+	   // this thread will continuously call shared->syncClinetObj->waitForSync()
+	   if (pthread_create(&thId, 0, syncCheckThread, (void*)this) != 0) {
+		   sage::printLog("[%d] SDM::init() : Failed to create syncCheckThread !", shared->nodeID);
+		   return -1;
+	   }
+
+	   // starting sync mainLoop
+	   if (syncMaster) {
+		   syncBBServerObj->startManagerThread(totalRcvNum, syncRefreshRate, syncMasterPollingInterval);
+	   }
+   }
+   else if ( syncLevel == -1 ) {
+	   shared->syncClientObj = new sageSyncClient(syncLevel);
+		// connect to syncMaster
+		if (shared->syncClientObj->connectToServer(masterIp, syncPort) < 0) {
+			sage::printLog("SDM::init() : SDM %d, Fail to connect to syncServer !", shared->nodeID);
+			return -1;
+		}
+		//sage::printLog("Connected to sync master %s:%d", masterIp, syncPort);
+
+		pthread_t thId;
+
+		// start syncCheckThread
+		// this thread will continuously call shared->syncClinetObj->waitForSync()
+		if (pthread_create(&thId, 0, syncCheckThread, (void*)this) != 0) {
+			sage::printLog("[%d] SDM::init() : Failed to create syncCheckThread !", shared->nodeID);
+			return -1;
+		}
+	   //sage::printLog("SDM::init() : old synch client is created. ");
+
+   }
+
+   if ( syncLevel == 0 || syncLevel == -1 ) {
+		if (pthread_create(&thId, 0, refreshThread, (void*)this) != 0) {
+		   sage::printLog("[%d] SDM::init() : Failed to create refreshThread !", shared->nodeID);
+		   return -1;
+		}
+   }
+
+   return 0;
+}
+
+void* sageDisplayManager::refreshThread(void *args) {
+   sageDisplayManager *This = (sageDisplayManager *)args;
+
+   while (!This->rcvEnd) {
+      This->shared->eventQueue->appendEvent(EVENT_REFRESH_SCREEN);
+      sage::usleep(DISPLAY_REFRESH_INTERVAL);
+   }
+
+   //sage::printLog("sageDisplayManager::refreshThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageDisplayManager::msgCheckThread(void *args)
+{
+   sageDisplayManager *This = (sageDisplayManager *)args;
+
+   sageMessage *msg;
+
+   while (!This->rcvEnd) {
+      msg = new sageMessage;
+      if (This->rcvMessageBlk(*msg) > 0 && !This->rcvEnd) {
+         //std::cout << "message arrive" << std::endl;
+         This->shared->eventQueue->appendEvent(EVENT_NEW_MESSAGE, 0, (void *)msg);
+      }
+   }
+
+   sage::printLog("sageDisplayManager::msgCheckThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageDisplayManager::syncCheckThread(void *args)
+{
+	sageDisplayManager *This = (sageDisplayManager *)args;
+	sage::printLog("sageDisplayManager::syncCheckThread() has started at SDM %d", This->shared->nodeID);
+
+	int syncMsgLen = -1;
+	while (!This->rcvEnd) {
+		sageEvent *syncEvent = NULL;
+
+		if ( This->syncLevel == -1 ) {
+			syncEvent = new sageEvent;
+			syncEvent->eventType = EVENT_SYNC_MESSAGE;
+			syncMsgLen = -1;
+		}
+		else {
+			// use MSG_PEEK to find out message length
+			syncMsgLen = This->shared->syncClientObj->waitForSyncPeek();
+			if ( syncMsgLen <= 0 ) {
+				fprintf(stderr, "[%d] SDM::syncCheckThread() : syncMsgLen %d\n", This->shared->nodeID, syncMsgLen);
+				//continue;
+				break;
+			}
+			else {
+				syncEvent = new sageSyncEvent(EVENT_SYNC_MESSAGE, syncMsgLen, NULL);
+			}
+		}
+
+		char *syncMsg = syncEvent->eventMsg;
+		if (This->shared->syncClientObj->waitForSync(syncMsg, syncMsgLen) == 0) {
+			//std::cout << "rcv sync " << syncEvent->eventMsg << std::endl;
+			/**
+			* This is important !
+			*/
+			This->shared->eventQueue->prependEvent(syncEvent);
+		}
+	}
+
+	sage::printLog("sageDisplayManager::syncCheckThread : exit");
+	pthread_exit(NULL);
+	return NULL;
+}
+
+void* sageDisplayManager::perfReportThread(void *args)
+{
+   sageDisplayManager *This = (sageDisplayManager *)args;
+
+   while (!This->rcvEnd) {
+      This->perfReport();
+      // if (This->shared->context && !This->rcvEnd) This->shared->context->checkEvent();
+      sage::usleep(100000);
+   }
+
+   sage::printLog("sageDisplayManager::perfReportThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageDisplayManager::initNetworks()
+{
+   sage::printLog("SDM::initNetworks() : SDM %d is now initializing network objects.", displayID);
+
+   tcpObj = new sageTcpModule;
+   if (tcpObj->init(SAGE_RCV, streamPort, nwCfg) == 1) {
+      sage::printLog("SDM::initNetworkds() : tcpObj->init() failed. SDM %d is already running", displayID);
+      return -1;
+   }
+
+   sage::printLog("SDM::initNetworks() : SDM %d is waiting TCP connections on port %d", displayID, streamPort);
+
+   udpObj = new sageUdpModule;
+   udpObj->init(SAGE_RCV, streamPort+(int)SAGE_UDP, nwCfg);
+
+   sage::printLog("SAGE Display Manager : waiting UDP connections at port %d", streamPort+(int)SAGE_UDP);
+
+   pthread_t thId;
+   nwCheckThreadParam *param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = tcpObj;
+
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("SDM::initNetwork() : SDM %d failed creating nwCheckThread (TCP)", displayID);
+      return -1;
+   }
+
+   param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = udpObj;
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("SDM::initNetwork() : SDM %d failed creating nwCheckThread (UDP)", displayID);
+      return -1;
+   }
+
+   return 0;
+}
+
+void* sageDisplayManager::nwCheckThread(void *args)
+{
+   nwCheckThreadParam *param = (nwCheckThreadParam *)args;
+   streamProtocol *nwObj = (streamProtocol *)param->nwObj;
+   sageDisplayManager *This = (sageDisplayManager *)param->This;
+
+   int senderID = -1;
+   char regMsg[SAGE_EVENT_SIZE];
+
+   if (nwObj) {
+      while (!This->rcvEnd) {
+         senderID = nwObj->checkConnections(regMsg);
+         if (senderID >= 0 && !This->rcvEnd) {
+            This->shared->eventQueue->appendEvent(EVENT_NEW_CONNECTION, regMsg, (void *)nwObj);
+         }
+      }
+   }
+
+   sage::printLog("SDM::nwCheckThread() : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageDisplayManager::initStreams(char *msg, streamProtocol *nwObj)
+{
+   int senderID, instID, streamType, frameRate;
+
+   sscanf(msg, "%d %d %d %d", &senderID, &streamType, &frameRate, &instID);
+
+   if ( syncLevel == 0 ) {
+	   streamType = SAGE_BLOCK_NO_SYNC;
+   }
+
+   //std::cout << "stream info " << msg << std::endl;
+
+   /**
+    * if pixelDownloader object for this application hasn't created before, then create one
+	*/
+	int index;
+	pixelDownloader*  dwloader = findApp(instID, index);
+
+   if (dwloader) {
+		if (dwloader->isInitialized() == true)  {
+      	dwloader->addStream(senderID); // EVENT_APP_CONNECTED will be arisen
+			return 0;
+		}
+	} else {
+		dwloader = new pixelDownloader;
+		dwloader->instID = instID;
+		downloaderList.push_back(dwloader);
+		reconfigStr.push_back(NULL);
+		index = downloaderList.size()-1;
+	}
+
+   //creates pixelDownloader if it's not there.
+	switch(streamType) {
+         case SAGE_BLOCK_NO_SYNC : {
+            if (syncMaster) {
+			   sage::printLog("\nSDM::initStreams() : Application %d is starting. NO_SYNC", instID);
+            }
+		   dwloader->init(msg, shared, nwObj, false, syncLevel);
+            break;
+         }
+         case SAGE_BLOCK_HARD_SYNC : {
+		   if ( syncMaster ) {
+			   sage::printLog("\nSDM::initStreams() : Application %d is starting. SYNC", instID);
+		   }
+		   dwloader->init(msg, shared, nwObj, true, syncLevel);
+
+		   // syncLevel == -1 // OLD sync
+			if (syncLevel == -1 && syncMaster && syncServerObj) {
+               syncGroup *sGroup = new syncGroup;
+               sGroup->init(0, SAGE_ASAP_SYNC_HARD, instID, DISPLAY_MAX_FRAME_RATE);
+               syncServerObj->addSyncGroup(sGroup);
+            }
+            break;
+         }
+	}
+
+	if (reconfigStr[index])
+		dwloader->enqueConfig(reconfigStr[index]);
+
+	dwloader->addStream(senderID);
+   return 0;
+}
+
+pixelDownloader* sageDisplayManager::findApp(int id, int& index)
+{
+	pixelDownloader* temp_app= NULL;
+	std::vector<pixelDownloader*>::iterator iter;
+	index = 0;
+	for(iter = downloaderList.begin(); iter != downloaderList.end(); iter++, index++)
+	{
+		if ((*iter)->instID == id)
+		{
+			temp_app =(pixelDownloader*) *iter;
+			break;
+		}
+	}
+	return temp_app;
+}
+
+int sageDisplayManager::shutdownApp(int instID)
+{
+	//fprintf(stderr, "[%d] SDM::shutdownApp(%d) \n", shared->nodeID, instID);
+   bool appShutdown = false;
+	pixelDownloader* temp_app= NULL;
+	char* temp_str= NULL;
+
+   if (instID == -1) {
+      sage::printLog("sageDisplayManager::shutdownApp() : SDM %d is shutting down all applications", shared->nodeID);
+		std::vector<pixelDownloader*>::iterator iter;
+		std::vector<char*>::iterator iter_str = reconfigStr.begin();
+		for(iter = downloaderList.begin(); iter != downloaderList.end(); iter++,iter_str++)
+		{
+			temp_app =(pixelDownloader*) *iter;
+			if (syncLevel == -1 && syncMaster && syncServerObj)
+				syncServerObj->removeSyncGroup(temp_app->instID);
+			delete temp_app;
+			temp_app = NULL;
+			temp_str =(char*) *iter_str;
+			delete temp_str;
+			temp_str = NULL;
+		}
+		if(downloaderList.size() > 0)
+			appShutdown = true;
+		downloaderList.clear();
+		reconfigStr.clear();
+   }
+   else if (instID >= 0) {
+		int index;
+		temp_app = findApp(instID, index);
+		if (temp_app)
+		{
+			delete temp_app;
+			temp_app = NULL;
+			temp_str = (char*) reconfigStr[index];
+			delete temp_str;
+			temp_str = NULL;
+			downloaderList.erase(downloaderList.begin() + index);
+			reconfigStr.erase(reconfigStr.begin() + index);
+      	appShutdown = true;
+			//shared->displayObj->onAppShutdown(instID);
+			if (syncLevel== -1 && syncMaster && syncServerObj)
+				syncServerObj->removeSyncGroup(instID);
+		}
+   }
+
+   if (appShutdown)
+      shared->displayObj->setDirty();
+   else {
+      sage::printLog("sageDisplayManager::shutdownApp : no apps to be shutdown");
+      return -1;
+   }
+
+   return 0;
+}
+
+int sageDisplayManager::updateDisplay(char *msg)
+{
+   int instID;
+   sscanf(msg, "%d", &instID);
+   char *updateInfo = sage::tokenSeek(msg, 1);
+	int index;
+	pixelDownloader* temp_app = findApp(instID, index);
+
+	if (temp_app) {
+      temp_app->enqueConfig(updateInfo);
+      if (temp_app->getStatus() == PDL_WAIT_CONFIG)
+         temp_app->fetchSageBlocks();
+   }
+   else {
+		/*
+      if (reconfigStr[index]) {
+         sage::printLog("sageDisplayManager::updateDisplay : invalid instance ID");
+         return -1;
+      }
+		*/
+		pixelDownloader *dwloader = new pixelDownloader;
+		dwloader->instID = instID;
+		downloaderList.push_back(dwloader);
+
+		char* str_config = new char[strlen(updateInfo)+1];
+      strcpy(str_config, updateInfo);
+		reconfigStr.push_back(str_config);
+   }
+
+   return 0;
+}
+
+int sageDisplayManager::clearDisplay(int instID)
+{
+	int index;
+	pixelDownloader*  temp_app = findApp(instID, index);
+
+   if (temp_app)
+	{
+      temp_app->enqueConfig(CLEAR_STR);
+   }
+	else {
+		/*
+      if (reconfigStr[instID]) {
+         sage::printLog("sageDisplayManager::clearDisplay : invalid instance ID");
+         return -1;
+      }
+		*/
+		pixelDownloader *dwloader = new pixelDownloader;
+		dwloader->instID = instID;
+		downloaderList.push_back(dwloader);
+
+		char* str_config = new char[strlen(CLEAR_STR)+1];
+      strcpy(str_config, CLEAR_STR);
+		reconfigStr.push_back(str_config);
+   }
+	return 1;
+}
+
+int sageDisplayManager::changeBGColor(sageMessage *msg)
+{
+   char *colorStr = (char *)msg->getData();
+   int red, green, blue;
+
+   sscanf(colorStr, "%d %d %d", &red, &green, &blue);
+
+   shared->displayObj->changeBGColor(red, green, blue);
+
+   return 0;
+}
+
+int sageDisplayManager::changeDepth(sageMessage *msg)
+{
+   char *depthStr = (char *)msg->getData();
+   char token[TOKEN_LEN];
+   char *tokenbuf; // strtok_r requires 3rd parameter
+
+   //int tokenNum = getToken(depthStr, token);
+   getToken(depthStr, token, &tokenbuf);
+
+   int numOfChange = atoi(token);
+   bool zOrderChange = false;
+
+	int index;
+	pixelDownloader*  temp_app;
+	int instID, zValue;
+   for (int i=0; i<numOfChange; i++) {
+/*
+      if (tokenNum > 0) {
+         tokenNum = getToken(depthStr, token);
+         instID = atoi(token);
+      }
+      else {
+         sage::printLog("More arguments are needed for this command ");
+         return -1;
+      }
+
+      if (tokenNum > 0) {
+         tokenNum = getToken(depthStr, token);
+         zValue = atoi(token);
+      }
+      else {
+         sage::printLog("More arguments are needed for this command ");
+         return -1;
+      }
+      */
+	   getToken(NULL, token, &tokenbuf);
+	   instID = atoi(token);
+	   getToken(NULL, token, &tokenbuf);
+	   zValue = atoi(token);
+
+		temp_app = findApp(instID, index);
+      if (temp_app) {
+         float depth = 1.0f + zValue - 0.01f*index;
+         //float depth = 1.0f + zValue;
+         temp_app->setDepth(depth);
+         zOrderChange = true;
+      }
+   }
+
+   if (zOrderChange)
+      shared->displayObj->setDirty();
+
+   return 0;
+}
+
+int sageDisplayManager::parseEvent(sageEvent *event)
+{
+   if (!event) {
+      sage::printLog("sageDisplayManager::parseEvent : event object is Null");
+      return -1;
+   }
+
+   switch (event->eventType) {
+      case EVENT_NEW_CONNECTION : {
+         initStreams(event->eventMsg, (streamProtocol *)event->param);
+         break;
+      }
+
+      case EVENT_NEW_MESSAGE : {
+         parseMessage((sageMessage *)event->param);
+         break;
+      }
+
+      case EVENT_SYNC_MESSAGE : {
+         //processSync((char *)event->eventMsg);
+    	  processSync( event );
+         break;
+      }
+
+      case EVENT_REFRESH_SCREEN : {
+         if (shared->displayObj->isDirty())
+            shared->displayObj->updateScreen(shared, false);
+
+         if (shared->context)
+            shared->context->checkEvent();
+         break;
+      }
+
+      case EVENT_READ_BLOCK : {
+         int instID = atoi((char *)event->eventMsg);
+			if (0 > instID) break;
+
+			int index;
+			pixelDownloader*  temp_app = findApp(instID, index);
+			if (temp_app) {
+            if (temp_app->getStatus() == PDL_WAIT_DATA)
+               temp_app->fetchSageBlocks();
+         }
+         break;
+      }
+
+		case EVENT_APP_CONNECTED : {
+         int instID = atoi((char *)event->eventMsg);
+			if (0 > instID) break;
+
+			int index;
+			pixelDownloader*  temp_app = findApp(instID, index);
+
+			if (temp_app) {
+            sendMessage(DISP_APP_CONNECTED, instID);
+         }
+         break;
+		}
+   }
+
+   delete event;
+
+   return 0;
+}
+
+int sageDisplayManager::parseMessage(sageMessage *msg)
+{
+   if (!msg) {
+      sage::printLog("sageDisplayManager::parseMessage : message is NULL");
+      return -1;
+   }
+
+   switch (msg->getCode()) {
+      case RCV_INIT : {
+         //std::cout << "rcv init : " << (char *)msg->getData() << std::endl;
+         if (init((char *)msg->getData()) < 0)
+            rcvEnd = true;
+         break;
+      }
+
+      case RCV_UPDATE_DISPLAY : {
+         updateDisplay((char *)msg->getData());
+         break;
+      }
+
+      case RCV_CLEAR_DISPLAY : {
+         clearDisplay(atoi((char *)msg->getData()));
+         break;
+      }
+
+      case SHUTDOWN_RECEIVERS : {
+         shutdownApp(-1);
+         //std::cout << "all apps are shutdown" << std::endl;
+         //sage::sleep(1);
+         rcvEnd = true;
+         //delete shared->displayObj;
+         //_exit(0);
+         break;
+      }
+
+      case RCV_CHANGE_BGCOLOR : {
+         changeBGColor(msg);
+         break;
+      }
+
+      case RCV_CHANGE_DEPTH : {
+         changeDepth(msg);
+         break;
+      }
+
+      case RCV_SHUTDOWN_APP : {
+         shutdownApp(atoi((char *)msg->getData()));
+         break;
+      }
+
+      case RCV_PERF_INFO_REQ : {
+         startPerformanceReport(msg);
+         break;
+      }
+
+      case RCV_PERF_INFO_STOP : {
+         stopPerformanceReport(msg);
+         break;
+      }
+
+      case ADD_OBJECT : {
+         shared->displayObj->addDrawObjectInstance((char *)msg->getData());
+         break;
+      }
+
+      case UPDATE_OBJECT_POSITION : {
+         shared->displayObj->updateObjectPosition((char *)msg->getData());
+         break;
+      }
+
+      case REMOVE_OBJECT : {
+         shared->displayObj->removeDrawObject((char *)msg->getData());
+         break;
+      }
+
+      case OBJECT_MESSAGE : {
+         shared->displayObj->forwardObjectMessage((char *)msg->getData());
+         break;
+      }
+
+      case SHOW_OBJECT : {
+         shared->displayObj->showObject((char *)msg->getData());
+         break;
+      }
+   }
+
+   msg->destroy();
+   delete msg;
+
+   return 0;
+}
+
+int sageDisplayManager::processSync(sageEvent *e)
+{
+	if ( syncLevel == -1 ) {
+		int groupID, syncFrame, dataLen, cmd;
+		sscanf(e->eventMsg, "%d %d %d %d", &groupID, &syncFrame, &dataLen, &cmd);
+
+		int index;
+		pixelDownloader *loader = findApp(groupID, index);
+		if (loader) {
+			loader->processSync(syncFrame, cmd);
+			if (loader->getStatus() == PDL_WAIT_SYNC)
+				loader->fetchSageBlocks();
+		}
+		return 0;
+	}
+
+	int *intMsg=(int *)(e->eventMsg); // one for pdl id one for syncFrame
+	//int pdlID, activeRcvs, curFrame, updatedFrame, syncFrame;
+	bool swapMontageDone = false;
+
+	pixelDownloader *PDL = NULL;
+	//std::vector<pixelDownloader*>::iterator iter;
+	int index;
+	int numIndex = e->buflen / sizeof(int);
+	numIndex = numIndex - 1; // The first element is the message length in Byte
+	numIndex = numIndex / 2; // this is the number of app which have updated in this round
+	for ( int i=0; i<numIndex; i++ ) {
+		/**
+		* if it's unsigned type, then it should be checked with UINT_MAX or ULONG_MAX or ULLONG_MAX
+		*/
+		//if ( intMsg[2*i+1] < 0 ) break;
+
+		PDL = findApp(intMsg[2*i+1], index);
+		if ( PDL ) {
+			swapMontageDone = true;
+
+#ifdef DEBUG_SYNC
+			fprintf(stderr, "[%d,%d] SDM::processSync() : It's ready for frame %d\n", shared->nodeID, intMsg[2*i], intMsg[2*i+1]);
+#endif
+
+			// trigger to swapMontage
+			PDL->processSync(intMsg[2*i+2]);
+
+			// if PDL is waiting sync
+			/*
+			if (PDL->getStatus() == PDL_WAIT_SYNC) {
+
+				// wake it up
+				PDL->fetchSageBlocks(); // should change PDL status
+			}
+			 */
+		}
+	}
+
+	switch(syncLevel) {
+	case 1:
+		// data sync only
+		// 1st phase only
+		//		shared->displayObj->update(); // ratko version only
+		if ( swapMontageDone ) {
+			shared->displayObj->updateScreen(shared, false); // barrier flag false
+		}
+		else if ( shared->displayObj->isDirty() ) {
+			shared->displayObj->updateScreen(NULL, false);
+		}
+		else {
+			// do nothing
+		}
+		break;
+	case 2:
+		// swap buffer sync. default
+		// 2nd phase
+		//		shared->displayObj->update();
+		if ( swapMontageDone ) {
+			shared->displayObj->updateScreen(shared, true); // barrier flag true
+		}
+		else if ( shared->displayObj->isDirty() ) {
+			// no precise sync is needed
+			// refresh needed for Ratko
+
+			// comment out below two when using SELECTIVE barrier
+			shared->syncClientObj->sendRefreshBarrier(shared->nodeID);
+			shared->syncClientObj->recvRefreshBarrier(true); // nonblocking = true
+
+			shared->displayObj->updateScreen(shared, false); // barrier flag must be false here, otherwise it will enter barrier in sageDisplay::updateScreen() again
+		}
+		else  {
+			// no precise sync is needed. just execute barrier here
+			// no refreshing needed
+
+			// comment out below two when using SELECTIVE barrier
+			shared->syncClientObj->sendRefreshBarrier(shared->nodeID);
+			shared->syncClientObj->recvRefreshBarrier(true); // nonblocking = true
+
+			// NO SCREEN REFRESH
+			//shared->displayObj->updateScreen(shared, false);
+		}
+		break;
+	case 3:
+		// NTP method
+		/** delay compensation after 1st phase.
+		* This replaces 2nd phase entirely
+		* effectively reducing 2n messages
+		*/
+		//int index = SAGE_SYNC_MSG_LEN / sizeof(int); // array index
+		/*
+		int index = SAGE_SYNC_MSG_LEN / sizeof(long long); // array index
+		shared->deltaT = intMsg[index-1];
+		shared->syncMasterT.tv_sec = (time_t)intMsg[index-2];
+		shared->syncMasterT.tv_usec = (suseconds_t)intMsg[index-3];
+		 */
+		break;
+	}
+
+	for ( int i=0; i<numIndex; i++ ) {
+		PDL = findApp(intMsg[2*i+1], index);
+		// if PDL is waiting sync
+		if (PDL  &&  PDL->getStatus() == PDL_WAIT_SYNC) {
+			// wake it up
+			PDL->fetchSageBlocks(); // should change PDL status
+		}
+	}
+	return 0;
+}
+
+void sageDisplayManager::mainLoop()
+{
+   while(!rcvEnd) {
+      sageEvent *newEvent = shared->eventQueue->getEvent();
+      //std::cout << "get the event " << newEvent->eventType << std::endl;
+      parseEvent(newEvent);
+   }
+}
+
+int sageDisplayManager::perfReport()
+{
+	std::vector<pixelDownloader*>::iterator iter;
+	pixelDownloader* temp_app= NULL;
+	char *frameStr = NULL;
+	char *bandStr = NULL;
+	for (iter =downloaderList.begin(); iter != downloaderList.end(); iter++) {
+		temp_app = (pixelDownloader*) *iter;
+
+		if (temp_app) {
+         frameStr = NULL;
+         bandStr = NULL;
+         temp_app->evalPerformance(&frameStr, &bandStr);
+         if (frameStr) {
+            sendMessage(DISP_RCV_FRATE_RPT, frameStr);
+            //std::cout << "send frame rate " << frameStr << std::endl;
+            delete [] frameStr;
+         }
+
+         if (bandStr) {
+            sendMessage(DISP_RCV_BANDWITH_RPT, bandStr);
+            //std::cout << "send bandwidth " << bandStr << std::endl;
+            delete [] bandStr;
+         }
+      }
+   }
+
+   return 0;
+}
+
+int sageDisplayManager::startPerformanceReport(sageMessage *msg)
+{
+   char *perfStr = (char *)msg->getData();
+   int instID, rate;
+   sscanf(perfStr, "%d %d", &instID, &rate);
+
+   //std::cout << "start perf report " << rate << std::endl;
+
+	int index;
+	pixelDownloader *loader = findApp(instID, index);
+   if (loader) {
+      //loader->setReportRate(rate);
+      //loader->resetTimer();
+      //loader->resetBandWidth();
+      //loader->resetFrame();
+   }
+   else {
+      sage::printLog("sageDisplayManager::startPerformanceReport : invalid app instance ID");
+      return -1;
+   }
+
+   return 0;
+}
+
+int sageDisplayManager::stopPerformanceReport(sageMessage *msg)
+{
+/*
+   int instID = atoi((char *)msg->getData());
+
+	int index;
+	pixelDownloader *loader = findApp(instID, index);
+
+   if (loader) {
+      loader->setReportRate(0);
+   }
+   else {
+      sage::printLog("sageDisplayManager::stopPerformanceReport : invalid app instance ID");
+      return -1;
+   }
+*/
+   return 0;
+}
+
+#if defined(_WIN32) || defined(__APPLE__)
+extern "C" int SDL_main(int argc, char **argv)
+#else
+int main(int argc, char **argv)
+#endif
+{
+#ifdef WIN32
+   sage::win32Init();
+#endif
+   sage::initUtil();
+
+   sage::printLog("sageDisplayManager: SAGE version [%s]", SAGE_VERSION);
+
+   sageDisplayManager manager(argc, argv);
+   manager.mainLoop();
+
+   return 0;
+}
+
Index: trunk/src/testing/src/sageAppAudio.cpp
===================================================================
--- trunk/src/testing/src/sageAppAudio.cpp	(revision 4)
+++ trunk/src/testing/src/sageAppAudio.cpp	(revision 4)
@@ -0,0 +1,219 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAppAudio.cpp - 
+ * Author : Byungil Jeong, Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageAppAudio.h"
+#include "sageAudioCircBuf.h"
+#include "sageAudioModule.h"
+
+sageAppAudio::sageAppAudio(sageAudioCircBuf* audioBuffer, int maxsize) : buffer(audioBuffer), initialized(false)
+{
+	maxAudioBuffSize = maxsize+512;
+	queueLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+	pthread_mutex_init(queueLock, NULL);
+	pthread_mutex_unlock(queueLock);
+	notFull = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+	pthread_cond_init(notFull, NULL);
+	notEmpty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+	pthread_cond_init(notEmpty, NULL);
+	  
+	audioAppRawBuffer[0] = malloc(maxAudioBuffSize);
+	audioAppRawBuffer[1] = malloc(maxAudioBuffSize);
+	audiobufSize[0] = maxAudioBuffSize;
+	audiobufSize[1] = maxAudioBuffSize;
+
+	remainBufSize =0;
+	remainBuf = NULL;
+
+
+	full = false;
+	empty = true;
+	writeIndex = 0;
+	readIndex = 0;
+
+	/*if (pthread_create(&thAppId, 0, audioThread, (void*)this) != 0) {
+	  std::cerr << "sageAppAudio : can't create audioThread" << std::endl;
+	}*/
+      
+}
+
+sageAppAudio::~sageAppAudio()
+{
+   if(queueLock)
+      free(queueLock);
+
+   if(notFull)
+      free(notFull);
+
+   pthread_join(thAppId, NULL);
+         
+   if(audioAppRawBuffer[0]) 
+   {
+      free(audioAppRawBuffer[0]);
+      audioAppRawBuffer[0] = NULL;
+   }
+   if(audioAppRawBuffer[1]) 
+   {
+      free(audioAppRawBuffer[1]);
+      audioAppRawBuffer[1] = NULL;
+   }
+}
+
+int sageAppAudio::start(void)
+{
+	if (pthread_create(&thAppId, 0, audioThread, (void*)this) != 0) {
+      std::cerr << "sageAppAudio : can't create audioThread" << std::endl;
+   }
+	initialized = true;
+	return 1;
+}
+
+void* sageAppAudio::audioThread(void *args)
+{
+   sageAppAudio *This = (sageAppAudio *)args;
+
+   bool loop = true;
+   while(loop) {
+      This->processData();
+   }   
+   
+   sage::printLog("sail::audioThread : exit the application audio thread");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+
+int sageAppAudio::processData()
+{
+	pthread_mutex_lock(queueLock);
+
+	while (empty) {
+		pthread_cond_wait(notEmpty, queueLock);
+	}
+
+	char * buf = (char *)audioAppRawBuffer[readIndex];
+
+	int byteBlock = buffer->getBytesBlock();
+
+	int numBlock = audiobufSize[readIndex] / byteBlock;
+	remainBufSize = audiobufSize[readIndex] % byteBlock;
+	//remainBufSize = 0;
+
+	audioBlock *block;
+	for(int i=0; i < numBlock ; i++)
+	{
+		//sage::printLog("sageAppAudio::processData : size %d %d \n", i, numBlock);
+
+		block = buffer->getNextWriteBlock();
+		while(block == NULL) {
+			sage::usleep(10);
+			block = buffer->getNextWriteBlock();
+			sage::printLog("sageAppAudio::processData : trying to get buffer : %d %d\n", i, numBlock);
+			//std::cout << "trying to get buffer..." << std::endl;
+		}
+
+		if(block != NULL)
+		{
+			memcpy(block->buff, buf, byteBlock);
+			block->frameIndex = buffer->getWriteIndex();
+			block->gframeIndex = sageAudioModule::_instance->getgFrameNum();
+			block->reformatted = 1;   
+			buffer->updateWriteIndex();
+			buf += byteBlock;
+		}
+	}
+
+	//sage::printLog("%d - %d\n\n", byteBlock, remainBufSize);
+
+	if(remainBufSize > 0) {
+		remainBuf = buf;
+	}
+
+	readIndex = (readIndex +1) % 2;
+	if (writeIndex == readIndex) {
+		empty = true;
+		pthread_cond_signal(notFull);
+	}   
+	full = false;
+
+	pthread_mutex_unlock(queueLock);
+
+	return 0;
+}
+
+int sageAppAudio::swapBuffer(int size, void *buf)
+{
+	if(initialized == false) return 0;
+	if(buf == NULL) return 0;
+
+	pthread_mutex_lock(queueLock);
+
+	//sage::printLog("sageAppAudio::swapBuffer : size %d %d\n", size, remainBufSize);
+
+	while (full) {
+		pthread_cond_wait(notFull, queueLock);
+	}
+
+	char * bufaudio = (char *) audioAppRawBuffer[writeIndex];
+	memset(bufaudio, 0, maxAudioBuffSize);
+	if(remainBufSize > 0) {
+		memcpy(bufaudio, remainBuf, remainBufSize);
+		bufaudio += remainBufSize;
+		remainBufSize=0;
+	}
+
+	memcpy(bufaudio, buf, size);
+	audiobufSize[writeIndex] = size + remainBufSize;
+
+
+	writeIndex = (writeIndex +1) % 2;
+	//int nextIdx = (writeIdx+1) % 2;
+	if (writeIndex == readIndex) {
+		full = true;
+	}   
+	empty = false;
+
+	pthread_cond_signal(notEmpty);
+
+	pthread_mutex_unlock(queueLock);      
+	             
+	return 0;
+}
+
+
Index: trunk/src/testing/src/monitorPerf.cpp
===================================================================
--- trunk/src/testing/src/monitorPerf.cpp	(revision 4)
+++ trunk/src/testing/src/monitorPerf.cpp	(revision 4)
@@ -0,0 +1,332 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: monitorPerf.cpp - monitoring performance data of SAGE 
+ * Author : Luc Renambot, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "suil.h"
+#include "misc.h"
+#include <pthread.h>
+
+char *gr_server;
+QUANTAnet_tcpClient_c *draw[20];
+int timestep = 1;
+
+
+void* readThread(void *args)
+{
+   int status, dataSize;
+   char buffer[65];
+
+   suil *uiLib = (suil *)args;
+   
+   while(1) {
+      sageMessage msg;
+
+      msg.init(READ_BUF_SIZE);
+      uiLib->rcvMessageBlk(msg);
+
+      if (msg.getCode() == APP_INFO_RETURN)
+      {
+         char appname[256], cmd[256];
+         int ret;
+         int appID, left, right, bottom, top, sailID, zValue;
+
+         ret = sscanf((char*)msg.getData(), "%s %d %d %d %d %d %d %d",
+                        appname, &appID, &left, &right, &bottom, &top, &sailID, &zValue);
+
+         if (ret != 8)
+               fprintf(stderr, "Something wrong, got only %d fields\n", ret);
+         else
+         {
+            if (draw[appID*2] == NULL)
+            {
+               fprintf(stderr, "New application: %d %s\n", appID, appname);
+
+               memset(cmd, 0, 256);
+               sprintf(cmd, "%d", appID);
+               uiLib->sendMessage(STOP_PERF_INFO, cmd);
+
+               memset(cmd, 0, 256);
+               sprintf(cmd, "%d %d", appID, 1); // every second
+               uiLib->sendMessage(PERF_INFO_REQ, cmd);
+                
+               draw[appID*2] = new QUANTAnet_tcpClient_c;
+                
+               if (draw[appID*2]->connectToServer(gr_server, 50008) < 0)
+               {
+                  fprintf(stderr, "Cannot connecy to drawing server\n");
+                  exit(1);
+               }
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "lines");
+               dataSize = 64;
+               status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error1: %d\n", status);    
+
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%37s - Display Bandwidth (Mbps)", appname);
+               dataSize = 64;
+               status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error2: %d\n", status);
+    
+
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "Time (sec)");
+               dataSize = 64;
+               status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error3: %d\n", status);
+    
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%6d", 1);
+               dataSize = 6;
+               status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error4: %d\n", status);
+    
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "Display Bandwidth (Mbps)");
+               dataSize = 64;
+               status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error5: %d\n", status);
+    
+               dataSize = 1;
+               memset(buffer, 0, 65);
+               status = draw[appID*2]->read(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+                
+               if (status == QUANTAnet_tcpClient_c::OK)
+                        printf("Got [%s]\n", buffer);
+               else
+                        fprintf(stderr, "Error7: %d\n", status);
+
+                
+               draw[appID*2+1] = new QUANTAnet_tcpClient_c;
+                
+               if (draw[appID*2+1]->connectToServer(gr_server, 50008) < 0)
+               {
+                  fprintf(stderr, "Cannot connecy to drawing server\n");
+                  exit(1);
+               }
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "lines");
+               dataSize = 64;
+               status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error1: %d\n", status);    
+
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%43s - Display Rate (fps)", appname);
+               dataSize = 64;
+               status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error2: %d\n", status);
+    
+
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "Time (sec)");
+               dataSize = 64;
+               status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error3: %d\n", status);
+    
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%6d", 1);
+               dataSize = 6;
+               status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error4: %d\n", status);
+    
+    
+               memset(buffer, 0, 65);
+               sprintf(buffer, "%64s", "Display Rate (fps)");
+               dataSize = 64;
+               status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               if (status != QUANTAnet_tcpClient_c::OK)
+                        fprintf(stderr, "Error6: %d\n", status);
+
+               dataSize = 1;
+               memset(buffer, 0, 65);
+               status = draw[appID*2+1]->read(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+                
+               if (status == QUANTAnet_tcpClient_c::OK)
+                        printf("Got [%s]\n", buffer);
+               else
+                        fprintf(stderr, "Error7: %d\n", status);
+            }
+         }
+      }
+      else if (msg.getCode() == UI_PERF_INFO)
+      {
+         char appname[256], cmd[256];
+         int ret;
+         int appID, dispNodes, numStreamD, renderNodes, numStreamR;
+         float dispBandWidth, dispFrameRate, renderBandWidth, renderFrameRate;
+
+         ret = sscanf((char*)msg.getData(), "%d\nDisplay %f %f %d %d\nRendering %f %f %d %d",
+                        &appID,
+                        &dispBandWidth, &dispFrameRate, &dispNodes, &numStreamD,
+                        &renderBandWidth, &renderFrameRate, &renderNodes, &numStreamR);
+
+         if (ret != 9)
+               fprintf(stderr, "Something wrong, got only %d fields\n", ret);
+         else
+         {
+            //fprintf(stderr, "displayBw %f displayFPS %f, renderBW %f, renderFPS %f\n",
+            // dispBandWidth, dispFrameRate, renderBandWidth, renderFrameRate);
+
+            memset(buffer, 0, 65);
+            sprintf(buffer, "%12.6f %12.6f", (float)timestep, dispBandWidth);
+            dataSize = 2*12+1;
+            status = draw[appID*2]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);        
+            if (status != QUANTAnet_tcpClient_c::OK)
+                  fprintf(stderr, "Error\n");
+        
+            memset(buffer, 0, 65);
+            sprintf(buffer, "%12.6f %12.6f", (float)timestep, dispFrameRate);
+            dataSize = 2*12+1;
+            status = draw[appID*2+1]->write(buffer, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);        
+            if (status != QUANTAnet_tcpClient_c::OK)
+                  fprintf(stderr, "Error\n");
+        
+            timestep += 1;
+         }
+      }
+      else
+      {
+         std::cout << "Message : " << msg.getCode() << std::endl << (char *)msg.getData() << std::endl << std::endl;
+      }
+   }
+} 
+
+int main(int argc, char **argv)
+{
+   char token[TOKEN_LEN];
+   bool flag = true;
+   int code;
+
+   int status, dataSize;
+   char buffer[65];
+
+   suil uiLib;
+   uiLib.init("fsManager.conf");
+   uiLib.connect(NULL);
+   
+   uiLib.sendMessage(SAGE_UI_REG," ");
+
+   pthread_t thId;
+   
+   if(pthread_create(&thId, 0, readThread, (void*)&uiLib) != 0){
+      return -1;
+   }
+
+   gr_server = strdup(argv[1]);
+
+   for (int k=0;k<20;k++) draw[k] = NULL;
+
+   while(flag) {
+      std::cin >> token;
+   
+      if (strcmp(token, "exit") == 0) {
+         flag = false;
+      } 
+      else if (strcmp(token, "exec") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(EXEC_APP, token);
+      }            
+      else if (strcmp(token, "move") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(MOVE_WINDOW, token);
+      }            
+      else if (strcmp(token, "resize") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(RESIZE_WINDOW, token);
+      }            
+      else if (strcmp(token, "bg") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SAGE_BG_COLOR, token);
+      }            
+      else if (strcmp(token, "depth") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         uiLib.sendMessage(SAGE_Z_VALUE, cmd);
+      }            
+      else if (strcmp(token, "perf") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         uiLib.sendMessage(PERF_INFO_REQ, cmd);
+      }            
+      else if (strcmp(token, "stopperf") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(STOP_PERF_INFO, token);
+      }            
+      else if (strcmp(token, "kill") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SHUTDOWN_APP, token);
+      }            
+      else if (strcmp(token, "shutdown") == 0) {
+         uiLib.sendMessage(SAGE_SHUTDOWN);
+         _exit(0);
+      }            
+      else if (strcmp(token, "admin") == 0) {
+         uiLib.sendMessage(SAGE_ADMIN_CHECK);
+      }            
+      else if (strcmp(token, "help") == 0) {
+         std::cout << std::endl;
+         std::cout << "exec   app_name init_x init_y        : execute an app" << std::endl;
+         std::cout << "move   app_id dx dy                  : move window of an app" << std::endl;
+         std::cout << "resize app_id left right bottom top  : resize window of an app" << std::endl;
+         std::cout << "bg     red green blue                : change background color" << std::endl;
+         std::cout << "depth  num_of_change app_id zVal...  : change z-order of windows" << std::endl;
+         std::cout << "perf   app_id report_period(sec)     : request performance info" << std::endl;
+         std::cout << "stopperf  app_id                     : stop performance info report" << std::endl;
+         std::cout << "kill      app_id                     : shutdown an app" << std::endl;
+         std::cout << "shutdown                             : shutdown SAGE" << std::endl;
+         std::cout << "admin                                : get administrative info" << std::endl;
+      }            
+      
+      std::cout << std::endl;
+   }
+}
Index: trunk/src/testing/src/sageAudioStreamer.cpp
===================================================================
--- trunk/src/testing/src/sageAudioStreamer.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioStreamer.cpp	(revision 4)
@@ -0,0 +1,308 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioStreamer.cpp - straightforward audio block streaming  
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageStreamer.h"
+#include "streamInfo.h"
+
+using namespace std;
+sageAudioStreamer::sageAudioStreamer(streamerConfig &conf, int sampleSize, sageAudioCircBuf* buff) : 
+   buffer(buff), bytesPerSample(sampleSize)
+{
+   config = conf;
+   config.protocol = config.audioProtocol;
+   //blockSize = config.blockSize;
+   blockSize = buff->getBytesBlock() + BLOCK_HEADER_SIZE;
+
+   if (config.protocol == SAGE_TCP) {
+      blockSize = buff->getBytesBlock() + BLOCK_HEADER_SIZE; // sizeof(float) /// if not sampleBuffSize 
+   
+      std::cout << "block size = " << blockSize << std::endl;
+   }
+   initializeBlock();
+}
+
+int sageAudioStreamer::connectToRcv(sageToken &tokenBuf, bool localPort)
+{
+   // 26000 1 127.0.0.1 0 
+   // port number ip id
+    
+   char token[TOKEN_LEN];
+   tokenBuf.getToken(token);
+   rcvNodeNum = atoi(token);
+
+   params = new streamParam[rcvNodeNum];
+   for (int i=0; i<rcvNodeNum; i++) {
+      char rcvIP[SAGE_IP_LEN];
+      tokenBuf.getToken(rcvIP);
+      tokenBuf.getToken(token);
+      params[i].nodeID = atoi(token);
+      params[i].active = false;
+      //params[i].sInfo = NULL;
+
+      char regMsg[REG_MSG_SIZE];
+      sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d", config.streamType, winID,
+                        config.nodeNum, blockSize, config.syncType, (int)config.sampleFmt, 
+                        config.samplingRate, config.channels, config.framePerBuffer,  config.frameRate, config.audioKeyFrame);
+      std::cout << "winID : " << winID << std::endl;
+
+      cout << "------------> " << regMsg << endl;
+
+      params[i].rcvID = nwObj->connect(rcvIP, regMsg);
+   }
+   std::cout << rcvNodeNum <<      " connections are established" << std::endl;
+
+   return 0;
+}
+
+
+int sageAudioStreamer::sendControlBlock(int flag, int cond)
+{
+   for (int j=0; j<rcvNodeNum; j++) {   
+      bool sendCond = false;
+      
+      switch(cond) {
+         case ALL_CONNECTION :
+            sendCond = true;
+            break;
+         case ACTIVE_CONNECTION :
+            sendCond = params[j].active;
+            break;
+         case INACTIVE_CONNECTION :
+            sendCond = !params[j].active;
+            break;         
+      }
+      
+      if (sendCond) {
+         // HYEJUNG NEED
+         //sageAudioBlock ctrlBlock(blockSize); // ?????
+         sageAudioBlock ctrlBlock; // ?????
+         ctrlBlock.setFlag(flag);
+         ctrlBlock.setFrameID(frameID);
+         ctrlBlock.updateBufferHeader();
+
+         int dataSize = nwObj->send(params[j].rcvID, &ctrlBlock, SAGE_BLOCKING);
+         if (dataSize > 0)
+            totalBandWidth += dataSize;
+         else {
+            sage::printLog("sageAudioStreamer::sendControlBlock : fail to send control block\n");
+            return -1;
+         }
+      }
+   }   
+      
+   return 0;
+}
+
+void sageAudioStreamer::setNwConfig(sageNwConfig &nc) 
+{
+   nwCfg = nc;
+
+   if (config.protocol == SAGE_UDP) {
+      blockSize = buffer->getBytesBlock() + BLOCK_HEADER_SIZE; // sizeof(float) /// if not sampleBuffSize 
+      std::cout << "block size = " << blockSize << std::endl;
+      // HYEJUNG CHECK
+   }   
+}
+
+int sageAudioStreamer::sendAudioBlock()
+{
+   // std::cerr << "SAGE audio streamer " << config.rank << " : init Streams" << std::endl;
+   // initBlock.flag = SAGE_INIT_BLOCK;
+
+   /*aBlock.setSampleFormat(config.sampleFmt);
+   aBlock.setSampleRate(config.samplingRate);
+   aBlock.setChannel(config.channels);
+   aBlock.setFramePerBuffer(config.framePerBuffer);
+   aBlock.setBytesPerSample(bytesPerSample);
+   */
+
+   for(int i=0; i<rcvNodeNum; i++) {
+
+      if (params[i].active) {
+         //audioBlock.setTileID(sInfo->tileID);
+         aBlock.setNodeID(params[i].nodeID);
+         //audioBlock.updateBufferHeader(sInfo->infoString);
+         //std::cout << "sending block header " << (char *)block->getBuffer() << std::endl;
+         
+         int dataSize = nwObj->send(params[i].rcvID, &aBlock, SAGE_BLOCKING);
+         
+         //std::cout << "frame  : " << aBlock.getFrameID() << " graphic frame : " << aBlock.getgFrameID() << " " << dataSize << std::endl;
+
+
+         if (dataSize > 0) {
+            totalBandWidth += dataSize;
+            //cout << "------> datasize : " << dataSize << endl;
+         }   
+         else {
+            sage::printLog("sageAudioStreamer::sendAudioBlock : fail to send audio block\n");
+            return -1;
+         }   
+      }   
+   }
+   
+   return 0;
+
+}
+
+int sageAudioStreamer::streamAudioData()
+{
+   if (rcvNodeNum < 1) {
+      sage::printLog("sageAudioStreamer::streamAudioData : No Active Streams\n");
+      return -1;
+   }
+   
+   bool flag = true;
+   
+   //std::cout << config.rank << " stream frame " << frameID << std::endl;
+
+   aBlock.setFrameID(buffer->getReadIndex());
+
+   audioBlock *bufferBlock = buffer->readBlock();
+   if(bufferBlock == NULL) return 0;
+
+   if(bufferBlock->reformatted != 1) return 0;
+   char* tempbuff = aBlock.getAudioBuffer(); 
+   memcpy(tempbuff,  bufferBlock->buff, buffer->getBytesBlock());
+
+   aBlock.setgFrameID(bufferBlock->gframeIndex);
+
+   aBlock.updateBufferHeader();
+
+   int cnt = 0;
+
+   if (sendAudioBlock() < 0)
+      return -1;
+         
+   //std::cout << "frame " << frameID << " transmitted" << std::endl;
+   
+   if (sendControlBlock(SAGE_STOP_BLOCK, INACTIVE_CONNECTION) < 0)
+      return -1;
+   frameID++;
+   bufferBlock->reformatted = 0;
+   buffer->updateReadIndex();
+
+   /*
+   if (streamTimer.getTimeUS() < 25000)
+      sage::usleep(25000 - (int)streamTimer.getTimeUS());
+   streamTimer.reset();
+   */
+         
+   //if (sendControlBlock(SAGE_UPDATE_BLOCK, ALL_CONNECTION) < 0)
+   //   return -1;
+   return 0;
+}
+
+int sageAudioStreamer::streamLoop()
+{
+   //streamTimer.reset();
+
+   while (streamerOn) {
+      //std::cout << "pt0" << std::endl;
+      //std::cout << "get a new frame" << config.nodeNum << std::endl;
+      
+      int syncFrame = 0;
+      char *msgStr = NULL;
+      if (config.nodeNum > 1) {
+		  if(config.syncClientObj != NULL)
+		  {
+			syncFrame = config.syncClientObj->waitForSyncData(msgStr);
+			if (msgStr) {
+				std::cout << "reconfigure " << msgStr << std::endl;
+				reconfigureStreams(msgStr);
+			}
+         }   
+      }
+      else {
+         pthread_mutex_lock(reconfigMutex);
+         if (msgQueue.size() > 0) {
+            msgStr = msgQueue.front();
+            reconfigureStreams(msgStr);
+            msgQueue.pop_front();
+            firstConfiguration = false;
+         }
+         pthread_mutex_unlock(reconfigMutex);
+      }
+      
+      if (streamAudioData() < 0) {
+         streamerOn = false;
+         //std::cout << "pt1" << std::endl;
+      }
+         
+      //std::cout << "pt1" << std::endl;
+
+   }   
+   
+   std::cout << "sageAudioStreamer : network thread exit" << std::endl;
+   //sage::printLog("sageAudioStreamer : network thread exit");
+   
+   return 0;
+}
+
+sageAudioStreamer::~sageAudioStreamer()
+{
+   streamerOn = false;
+}
+
+int sageAudioStreamer::initializeBlock()
+{
+   aBlock.setFlag(SAGE_AUDIO_BLOCK);
+   aBlock.setSampleFormat(config.sampleFmt);
+   aBlock.setSampleRate(config.samplingRate);
+   aBlock.setChannel(config.channels);
+   aBlock.setFramePerBuffer(config.framePerBuffer);
+   aBlock.setBytesPerSample(bytesPerSample);   
+   aBlock.initBuffer(blockSize);   
+   return 0;
+}
+
+int sageAudioStreamer::reconfigureStreams(char *msgStr)
+{
+   for(int j=0; j<rcvNodeNum; j++)
+   {
+      //params[j].sInfo = NULL;
+      params[j].active = true;
+   }
+   
+   //cout << "------> " << msgStr << endl;
+   // 26000 1 127.0.0.1 0 
+   // port number ip id
+    
+   return 0;
+}
Index: trunk/src/testing/src/sageDisplay.cpp
===================================================================
--- trunk/src/testing/src/sageDisplay.cpp	(revision 4)
+++ trunk/src/testing/src/sageDisplay.cpp	(revision 4)
@@ -0,0 +1,657 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDisplay.cpp - the display module in SAGE Receiver
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#if defined(GLSL_YUV)
+#if !defined(WIN32)
+#define GLEW_STATIC 1
+#endif
+#include <GL/glew.h>
+#include <GL/glu.h>
+#include <fcntl.h>
+extern GLhandleARB PHandle;
+#endif
+
+
+#include "sageDisplay.h"
+#include "sageBlock.h"
+#include "pixelDownloader.h"
+
+#if defined(WIN32)
+
+#define glGetProcAddress(n) wglGetProcAddress(n)
+#if ! defined(GLSL_YUV)
+typedef void (*PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+typedef void (*PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+#endif
+#if !defined(WIN32)
+static PFNGLCOMPRESSEDTEXIMAGE2DARBPROC    glCompressedTexImage2D    = 0;
+static PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2D = 0;
+#endif
+#else
+#if !defined(GLSL_YUV)
+extern "C" void glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *);
+extern "C" void glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *);
+#endif
+#endif
+
+
+int GLprintError(const char *file, int line)
+{
+   //
+   // Returns 1 if an OpenGL error occurred, 0 otherwise.
+   //
+   GLenum glErr;
+   int    retCode = 0;
+
+   glErr = glGetError();
+   while (glErr != GL_NO_ERROR)
+   {
+      fprintf(stderr, "GL> glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
+      retCode = 1;
+      glErr = glGetError();
+   }
+   return retCode;
+}
+
+
+sageMontage::sageMontage(displayContext *dct, sagePixFmt pfmt) : texWidth(0), texHeight(0), 
+      texture(NULL), texHandle(-1), pixelType(pfmt), depth(1.0), monIdx(-1), tileIdx(-1), 
+      visible(true), context(dct) 
+{  
+   pInfo.initType(pfmt); 
+   
+#if (!defined(__APPLE__) && !defined(GLSL_YUV))
+   // If no shader and not apple hardware, we have to convert YUV to RGB on CPU
+   //    so data size is now 3 bytes
+   if (pfmt == PIXFMT_YUV)
+      pInfo.bytesPerPixel = 3;
+#endif
+
+}
+
+int sageMontage::init(sageRect &viewPort, sageRect &blockLayout, sageRotation orientation)
+{
+   texCoord = viewPort;
+   texCoord.setOrientation(orientation);
+   texInfo = blockLayout;
+   texInfo.x = texInfo.y = 0;
+
+   updateBoundary();
+   //std::cout << "pt6");
+   renewTexture();
+   
+   genTexCoord();
+   //std::cerr << "gen tex coord " << texCoord.left << " " << texCoord.right << " " << texCoord.bottom << " " << texCoord.top << std::endl;   
+   return 0;
+}
+
+int sageMontage::copyConfig(sageMontage &mon)
+{
+   //*(sageRect*)this = (sageRect&)mon;
+   x = mon.x;
+   y = mon.y;
+   width = mon.width;
+   height = mon.height;
+   left = mon.left;
+   right = mon.right;
+   bottom = mon.bottom;
+   top = mon.top;
+   
+   //std::cerr << "copy config " << left << " " << right << " " << bottom << " " << top << std::endl;
+   
+   pInfo = mon.pInfo;
+   pixelType = mon.pixelType;
+   texCoord = mon.texCoord;
+   texInfo = mon.texInfo;
+   
+   //std::cerr << "copy tex coord " << texCoord.left << " " << texCoord.right << " " << texCoord.bottom << " " << texCoord.top << std::endl;
+   renewTexture();
+   //genTexCoord();
+   
+   return 0;
+}
+
+bool sageMontage::genTexCoord()
+{
+#if defined(GLSL_YUV)
+   if (pixelType == PIXFMT_YUV) {
+      texCoord.updateBoundary();
+   }
+   else {
+      sageRect texRect(0, 0, texWidth, texHeight);
+      texCoord /= texRect;
+   }
+#else
+   sageRect texRect(0, 0, texWidth, texHeight);
+   //std::cerr << "tex size " << texWidth << " " << texHeight << std::endl;
+   char msg[TOKEN_LEN];
+   texCoord.sprintRect(msg);
+   //std::cerr << "tex rect " << msg << std::endl;
+   texCoord /= texRect;
+#endif
+
+   return true;
+}
+
+int sageMontage::loadPixelBlock(sagePixelBlock *block)
+{
+   //printf("\nheader %x\npixelBuffer %x\n\n", block->getBuffer(), block->getPixelBuffer()); 
+   
+   context->switchContext(tileIdx);
+   
+   glBindTexture(GL_TEXTURE_2D, texHandle);
+   
+   if (pixelType == PIXFMT_DXT) {
+      //std::cout << "width " << block->width << " , height " << block->height 
+      // << ", size " << (block->width*block->height)/2 << std::endl;
+      //   fprintf(stderr, "GL> POS %d %d\n", posX, posY);
+      
+      glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, block->x, block->y, 
+               block->width, block->height,
+               pInfo.pixelFormat,
+               (block->width*block->height)/2,
+               block->getPixelBuffer());
+
+      GLprintError(__FILE__, __LINE__);  // Check for OpenGL errors
+      return 0;
+   }
+   
+#if !defined(__APPLE__)
+
+#define clip(A) ( ((A)<0) ? 0 : ( ((A)>255) ? 255 : (A) ) )
+
+#define YUV444toRGB888(Y,U,V,R,G,B) \
+   R = clip(( 298 * (Y-16)                 + 409 * (V-128) + 128) >> 8); \
+      G = clip(( 298 * (Y-16) - 100 * (U-128) - 208 * (V-128) + 128) >> 8); \
+      B = clip(( 298 * (Y-16) + 516 * (U-128)                 + 128) >> 8);
+   
+   if (pixelType == PIXFMT_YUV) {
+#if defined(GLSL_YUV)
+      glDisable(GL_TEXTURE_2D);
+      glEnable(GL_TEXTURE_RECTANGLE_ARB);
+      glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texHandle);
+      glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, block->x, block->y, block->width, block->height,
+         pInfo.pixelFormat, pInfo.pixelDataType, block->getPixelBuffer());
+      glDisable(GL_TEXTURE_RECTANGLE_ARB);
+      glEnable(GL_TEXTURE_2D);
+#else
+      unsigned char *yuv = (unsigned char*)block->getPixelBuffer();
+      unsigned char u,v,y1,y2;
+      unsigned char r1,r2,g1,g2,b1,b2;
+      int i, k;
+      k = 0;
+      for (i=0;i< (block->width*block->height)/2;i++) {
+         u  = yuv[4*i+0];
+         y1 = yuv[4*i+1];
+         v  = yuv[4*i+2];
+         y2 = yuv[4*i+3];
+       
+         YUV444toRGB888(y1, u, v, r1,g1,b1);
+         YUV444toRGB888(y2, u, v, r2,g2,b2);
+         texture[k + 0] = r1;
+         texture[k + 1] = g1;
+         texture[k + 2] = b1;
+         texture[k + 3] = r2;
+         texture[k + 4] = g2;
+         texture[k + 5] = b2;
+         k += 6;
+      }
+      glTexSubImage2D(GL_TEXTURE_2D, 0, block->x, block->y, block->width, block->height,
+         GL_RGB, GL_UNSIGNED_BYTE, texture);
+#endif
+   }
+   else {
+      //std::cerr << "block download " << block->x << " , " << block->y << " , " <<
+      //   block->width << " , " << block->height << std::endl;   
+
+      glTexSubImage2D(GL_TEXTURE_2D, 0, block->x, block->y, block->width, block->height,
+         pInfo.pixelFormat, pInfo.pixelDataType, block->getPixelBuffer());
+   }   
+#else
+   glTexSubImage2D(GL_TEXTURE_2D, 0, block->x, block->y, block->width, block->height,
+         pInfo.pixelFormat, pInfo.pixelDataType, block->getPixelBuffer());
+#endif
+
+   return 0;
+}
+
+int sageMontage::renewTexture()
+{
+   context->switchContext(tileIdx);
+   
+   //generate the textures which will be used
+   int newWidth, newHeight;
+   newWidth = getMax2n(texInfo.width);
+   newHeight = getMax2n(texInfo.height);
+   
+   int maxt;
+//HYEJUNG
+   glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&maxt);
+//HYEJUNG
+   if (newWidth > maxt)  {
+      fprintf(stderr, "Warning: trying to create texture %d, bigger than maximun %d\n", newWidth, maxt);
+      newWidth = maxt;
+   }
+   if (newHeight > maxt) {
+      fprintf(stderr, "Warning: trying to create texture %d, bigger than maximun %d\n", newHeight, maxt);
+      newHeight = maxt;
+   }
+
+   if (newWidth <= texWidth && newHeight <= texHeight) {
+      //std::cout << "reuse texture : " << texWidth << " , " << texHeight);
+      return 1;
+   }
+   
+   texWidth = newWidth;
+   texHeight = newHeight;
+
+   deleteTexture();
+
+   GLuint handle;      
+   glGenTextures(1, &handle);
+   texHandle = handle;
+
+   // Create GL texture object
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+   // Create dummy texture image.
+   if (pixelType == PIXFMT_DXT) {
+      if (texWidth < 64)
+         texWidth = 64;
+      if (texHeight < 64)
+         texHeight = 64;
+
+      texture = (GLubyte *) malloc(texWidth * texHeight / 2);
+      memset(texture, 0, texWidth * texHeight / 2);
+
+      // fprintf(stderr, "Create DXT texture: format %d, width %d height %d, size %d\n",
+      //   pInfo.pixelFormat, texWidth, texHeight, texWidth * texHeight / 2);
+
+      glEnable(GL_TEXTURE_2D);
+      glBindTexture(GL_TEXTURE_2D, handle);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      
+      glCompressedTexImage2D(GL_TEXTURE_2D, 0,
+                  pInfo.pixelFormat,
+                  texWidth, texHeight, 0,
+                  texWidth * texHeight / 2, texture);
+      
+      GLprintError(__FILE__, __LINE__);  // Check for OpenGL errors
+   }
+   else {
+      //texture = (GLubyte *) malloc(texWidth * texHeight * pInfo.bytesPerPixel);
+      //memset(texture, 0, texWidth * texHeight * pInfo.bytesPerPixel);
+
+      if (pixelType == PIXFMT_YUV) {
+#if defined(GLSL_YUV)
+         texture = (GLubyte *) malloc(texWidth * texHeight * pInfo.bytesPerPixel);
+         memset(texture, 0, texWidth * texHeight * pInfo.bytesPerPixel);
+         glDisable(GL_TEXTURE_2D);
+         glEnable(GL_TEXTURE_RECTANGLE_ARB);
+         glBindTexture(GL_TEXTURE_RECTANGLE_ARB, handle);
+         glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+         glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+         glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, pInfo.internalFormat, texWidth, texHeight, 0, 
+            pInfo.pixelFormat, pInfo.pixelDataType, texture);
+#else
+         texture = (GLubyte *) malloc(texWidth * texHeight * 3);
+         memset(texture, 0, texWidth * texHeight * 3);
+         glEnable(GL_TEXTURE_2D);
+         glBindTexture(GL_TEXTURE_2D, handle);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, 
+            GL_RGB, GL_UNSIGNED_BYTE, texture);
+#endif
+      }
+      else {
+         texture = (GLubyte *) malloc(texWidth * texHeight * pInfo.bytesPerPixel);
+         memset(texture, 0, texWidth * texHeight * pInfo.bytesPerPixel);
+         glEnable(GL_TEXTURE_2D);
+         glBindTexture(GL_TEXTURE_2D, handle);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+         
+         glTexImage2D(GL_TEXTURE_2D, 0, pInfo.internalFormat, texWidth, texHeight, 0, 
+            pInfo.pixelFormat, pInfo.pixelDataType, texture);
+      }
+   }
+   
+   return 0;
+} //End of renewTexture
+
+int sageMontage::deleteTexture()
+{
+   GLuint handle;
+   
+   if (texHandle >= 0) {
+      handle = (GLuint)texHandle;
+      glDeleteTextures(1, &handle);
+      if (texture)
+         free(texture);
+   }
+   return 0;
+}
+
+sageDisplay::sageDisplay(displayContext *dct, struct sageDisplayConfig &cfg): context(dct), 
+         dirty(false), drawObj(dirty, cfg.displayID) 
+{
+   configStruct = cfg;
+   tileNum = cfg.dimX * cfg.dimY;
+   if (tileNum > MAX_TILES_PER_NODE) {
+      sage::printLog("sageDisplay::init() : The tile number exceeds the maximum"); 
+   }
+      
+   for (int i=0; i<tileNum; i++) {
+      noOfMontages[i] = 0;
+      for (int j=0; j<MAX_MONTAGE_NUM; j++)
+         montages[i][j] = NULL;
+   }
+
+#if defined(WIN32)
+   fprintf(stderr, "Init GL functions: %p %p\n", glCompressedTexImage2D, glCompressedTexSubImage2D);
+   glCompressedTexImage2D  = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)
+      glGetProcAddress("glCompressedTexImage2D");
+   glCompressedTexSubImage2D  = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)
+      glGetProcAddress("glCompressedTexSubImage2D");
+   fprintf(stderr, "----> GL functions: %p %p\n", glCompressedTexImage2D, glCompressedTexSubImage2D);
+#endif
+}
+
+int sageDisplay::changeBGColor(int red, int green, int blue)
+{   
+   context->changeBackground(red, green, blue);
+   dirty = true;
+   
+   return 0;
+}
+
+int sageDisplay::addMontage(sageMontage *mon)
+{
+   if (!mon) {
+      sage::printLog("sageDisplay::addMontage : Error - input is NULL");
+      return -1;
+   }
+   
+   if (mon->tileIdx < 0)
+      return -1;
+      
+   mon->visible = false;
+   
+   for (int i=0; i<MAX_MONTAGE_NUM; i++) {
+      if (montages[mon->tileIdx][i] == NULL) {
+         montages[mon->tileIdx][i] = mon;
+         mon->monIdx = i;
+         if (i+1 > noOfMontages[mon->tileIdx])
+            noOfMontages[mon->tileIdx] = i+1;
+         return i;
+      }
+   }
+      
+   sage::printLog("sageDisplay::addMontage : Error - montage list is full");
+   return -1;
+}
+
+int sageDisplay::removeMontage(sageMontage *mon)
+{
+   if (!mon) {
+      sage::printLog("sageDisplay::removeMontage : Error - input is NULL");
+      return -1;
+   }
+   
+   if (mon->tileIdx < 0 || mon->monIdx < 0)
+      return 0;
+      
+   montages[mon->tileIdx][mon->monIdx] = NULL;
+   mon->monIdx = -1;
+   
+   return 0;
+}
+
+int sageDisplay::replaceMontage(sageMontage *mon)
+{
+   if (!mon) {
+      sage::printLog("sageDisplay::replaceMontage : Error - input is NULL");
+      return -1;
+   }
+   
+   if (mon->tileIdx < 0 || mon->monIdx < 0)
+      return -1;
+      
+   mon->visible = true;
+   montages[mon->tileIdx][mon->monIdx] = mon;
+   return 0;
+}
+
+int sageDisplay::updateScreen(dispSharedData *shared, bool barrierFlag)
+{
+   context->clearScreen();
+
+   for (int i=0; i<tileNum; i++)   {
+      sageRect tileRect = configStruct.tileRect[i];
+      tileRect.updateBoundary();
+      
+      int tileX = (i % configStruct.dimX) * configStruct.width;
+      int tileY = (i / configStruct.dimX) * configStruct.height;
+      tileRect.x = tileX;
+      tileRect.y = tileY;
+
+      context->setupViewport(i, tileRect);
+
+      drawObj.preDraw(tileRect);
+      glMatrixMode(GL_PROJECTION);
+      glLoadIdentity();
+      glOrtho(tileRect.left, tileRect.right, tileRect.bottom, tileRect.top, 0, 100);
+      glMatrixMode(GL_MODELVIEW);
+      for (int j=0; j<noOfMontages[i]; j++) {
+         sageMontage *mon = montages[i][j];
+
+         if (!mon)
+            continue;
+            
+         if (!mon->visible) 
+            continue;
+            
+         //if (!mon->isValidTexCoord()) {
+         //sage::printLog("sageDisplay::updateScreen : montage %d of tile %d doesn't have valid texture coordinates", mon->id, i);
+         //continue;
+         //}
+         
+         if (mon->pixelType == PIXFMT_YUV) {
+#if defined(GLSL_YUV)
+            glDisable(GL_TEXTURE_2D);
+            glEnable(GL_TEXTURE_RECTANGLE_ARB);
+            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mon->texHandle);
+            glUseProgramObjectARB(PHandle);
+            glActiveTexture(GL_TEXTURE0);
+            int h=glGetUniformLocationARB(PHandle,"yuvtex");
+            glUniform1iARB(h,0);  /* Bind yuvtex to texture unit 0 */
+            glBindTexture(GL_TEXTURE_RECTANGLE_ARB,mon->texHandle);
+#else
+            glBindTexture(GL_TEXTURE_2D, mon->texHandle);
+#endif
+         }
+         else {
+            glBindTexture(GL_TEXTURE_2D, mon->texHandle);
+         }
+         
+         //GLenum error = glGetError();
+         //gluGetErrorString( error ) ) );
+
+         float depth = -mon->depth;
+         glBegin(GL_QUADS);
+            float texX, texY;
+            mon->texCoord.genTexCoord(LOWER_LEFT, texX, texY);
+            //   std::cerr << "LL " << texX << " , " << texY << " , " ;
+            glTexCoord2f(texX, texY);
+            glVertex3f(mon->left, mon->bottom, depth);
+				//std::cout << " drawing... " << mon->left <<  " " << mon->bottom << " " << depth << std::endl;
+
+            mon->texCoord.genTexCoord(LOWER_RIGHT, texX, texY);
+            //   std::cerr << "LR " << texX << " , " << texY << " , " ;
+            glTexCoord2f(texX, texY);
+            glVertex3f(mon->right, mon->bottom, depth);
+
+            mon->texCoord.genTexCoord(UPPER_RIGHT, texX, texY);
+            //   std::cerr << "UR " << texX << " , " << texY << " , " ;
+            
+            glTexCoord2f(texX, texY);
+            glVertex3f(mon->right, mon->top, depth);
+            
+            mon->texCoord.genTexCoord(UPPER_LEFT, texX, texY);
+            //   std::cerr << "UL " << texX << " , " << texY << std::endl;
+   
+            glTexCoord2f(texX, texY);
+            glVertex3f(mon->left, mon->top, depth);
+         glEnd();
+
+         if (mon->pixelType == PIXFMT_YUV) {
+#if defined(GLSL_YUV)
+            glUseProgramObjectARB(0);
+            glDisable(GL_TEXTURE_RECTANGLE_ARB);
+            glEnable(GL_TEXTURE_2D);
+#endif
+         }
+
+      }
+      drawObj.interDraw(tileRect);
+      drawObj.postDraw(tileRect);
+
+      context->refreshTile(i);
+   }   
+   
+   //gettimeofday(&tve,NULL);   
+  
+   //double e = ((double)tve.tv_sec + 0.000001*(double)tve.tv_usec) - ((double)tvs.tv_sec + 0.000001*(double)tvs.tv_usec);
+   //printf("%.9f elapsed\n", e); 
+   //context->refreshScreen();
+   
+      /** BARRIER **/
+
+   if ( barrierFlag ) {
+	   shared->syncClientObj->sendRefreshBarrier(shared->nodeID);
+	   //printf("node %d sent to barrier\n", shared->nodeID);
+	   shared->syncClientObj->recvRefreshBarrier(false); // blocking (set true for nonblock)
+	   //printf("node %d recved frm barrier\n", shared->nodeID);
+
+   }
+
+#ifdef DELAY_COMPENSATION
+   if ( shared ) {
+	   gettimeofday(&shared->localT, NULL); // my time
+
+	   //fprintf(stderr,"SM sent %ld,%ld\n", shared->syncMasterT.tv_sec, shared->syncMasterT.tv_usec);
+	   //fprintf(stderr,"SDM%d is %ld,%ld\n", shared->nodeID, shared->localT.tv_sec, shared->localT.tv_usec);
+	   
+	   double A = (double)shared->syncMasterT.tv_sec + 0.000001*(double)shared->syncMasterT.tv_usec;
+	   A = A + ((double)shared->deltaT * 0.000001);
+	   double B = (double)shared->localT.tv_sec + 0.000001*(double)shared->localT.tv_usec;
+	   double wait = A - B;
+	   wait *= 1000000.0;
+	   
+	   int llBusyWait = (int)wait;
+	   if (  llBusyWait > 0 ) {
+	     __usecDelay_RDTSC( llBusyWait );
+	   }
+
+	   //printf("SDM %d: %.6f msec waited\n", shared->nodeID, elapsed*1000.0);
+   }
+#endif
+
+   context->refreshScreen();  // actual swapBuffer occurs in here at displayConext's instance
+   dirty = false;
+   
+   return 0;
+}
+
+int sageDisplay::addDrawObjectInstance(char *data)
+{
+   drawObj.addObjectInstance(data);
+   dirty = true;
+   
+   return 0;
+}
+
+int sageDisplay::updateObjectPosition(char *data)
+{
+   drawObj.updateObjectPosition(data);
+   dirty = true;
+      
+   return 0;
+}
+
+int sageDisplay::removeDrawObject(char *data)
+{
+   int id;
+   sscanf(data, "%d", &id);
+   drawObj.removeObject(id);
+   dirty = true;
+      
+   return 0;
+}
+
+int sageDisplay::forwardObjectMessage(char *data)
+{
+   drawObj.forwardObjectMessage(data);
+   dirty = true;
+      
+   return 0;
+}
+
+int sageDisplay::showObject(char *data)
+{
+   drawObj.showObject(data);
+   dirty = true;
+      
+   return 0;
+}
+
+sageDisplay::~sageDisplay()
+{
+} //End of sageDisplay::~sageDisplay()
Index: trunk/src/testing/src/sageDrawObject.cpp
===================================================================
--- trunk/src/testing/src/sageDrawObject.cpp	(revision 4)
+++ trunk/src/testing/src/sageDrawObject.cpp	(revision 4)
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDrawObject.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageDrawObject.h"
+
+void sageDrawObject::setName(char *name)
+{
+   if (name)
+      strcpy(objName, name);
+}
+
+void sageDrawObject::init(int id, char *name, sageRect &layout, bool g, int dID)
+{
+   objectID = id;
+   if (name)
+      strcpy(objName, name);
+   (sageRect &)*this = layout;
+   global = g;
+   displayID = dID;
+}
+
+int sageDrawObject::setGlobalView()
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(tileRect.left, tileRect.right, tileRect.bottom, tileRect.top, 0, 100);
+   glMatrixMode(GL_MODELVIEW);
+
+   return 0;
+}
+
+int sageDrawObject::setLocalView()
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(tileRect.x, tileRect.x+tileRect.width, tileRect.y, tileRect.y+tileRect.height, 0, 100);
+   glMatrixMode(GL_MODELVIEW);
+
+   return 0;
+}
+
+void sageDrawObject::showObject(bool doShow)
+{
+   visible = doShow;
+}
+
+int sageDrawObject::setViewport(sageRect &rect)
+{
+   tileRect = rect;
+
+   if (global) 
+      setGlobalView();
+   else
+      setLocalView();
+
+   return 0;   
+}
+
Index: trunk/src/testing/src/wavConverter.cpp
===================================================================
--- trunk/src/testing/src/wavConverter.cpp	(revision 4)
+++ trunk/src/testing/src/wavConverter.cpp	(revision 4)
@@ -0,0 +1,301 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  wavConverter.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for 
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "wavConverter.h"
+
+wavConverter::wavConverter()
+{
+}
+
+
+wavConverter::~wavConverter()
+{
+}
+
+int wavConverter::readHeader(int& nchan, long& samrate, int& nframes, sageSampleFmt& fmt)
+{
+   if(fileID == NULL) return -1;
+   blockCount =0; 
+   //dataPos = -1;
+   
+   char id[4];
+   long size;      //32 bit value to hold file size
+   
+   // 16 bit values : short
+   // 32 bit values : long
+   bool done = false;
+   
+   fread(id, sizeof(char), 4, fileID); //read in first four bytes
+   /** strange facts:: id has strange string more... so......i also did strangely....*/
+   //std::cout << "-------------------check name : " << id << " sizechar : " << sizeof(char) << " sizelong : " <<  sizeof(long) << " sizeshort: " << sizeof(short) << std::endl;   
+   if ((id[0] =='R') && (id[1] =='I') && (id[2] =='F') && (id[3] =='F')) { // RIFF
+      //we had 'RIFF' let's continue
+      //fread(&size,sizeof(long) , 1, fileID); //read in 32bit size value
+      fread(&size, 4, 1, fileID); //read in 32bit size value
+      //std::cout << "-------------------check size : " << size << std::endl;   
+      fread(&id, sizeof(char), 4, fileID); //read in 4 byte string now
+      //std::cout << "-------------------check name : " << id << std::endl;   
+      if ((id[0] == 'W') && (id[1] == 'A') && (id[2] == 'V') && (id[3] == 'E')) { // WAVE
+         //this is probably a wave file since it contained "WAVE"
+         fread(id, sizeof(char), 4, fileID); //read in 4 bytes "fmt ";
+         if ((id[0] == 'f') && (id[1] == 'm') && (id[2] == 't'))  { // fmt 
+            //fread(&formatLength, sizeof(long),1,fileID);
+            fread(&formatLength, 4,1,fileID);
+
+            fread(&formatTag, sizeof(short), 1, fileID); //check mmreg.h (i think?) for other 
+            // possible format tags like ADPCM
+            fread(&channels, sizeof(short),1,fileID); //1 mono, 2 stereo
+         
+            //fread(&sampleRate, sizeof(long), 1, fileID); //like 44100, 22050, etc...
+            //fread(&avgBytesSec, sizeof(long), 1, fileID);
+            fread(&sampleRate, 4, 1, fileID); //like 44100, 22050, etc...
+            fread(&avgBytesSec, 4, 1, fileID);
+         
+            fread(&blockAlign, sizeof(short), 1, fileID); 
+            fread(&bitsPerSample, sizeof(short), 1, fileID); //8 bit or 16 bit file?
+            fread(id, sizeof(char), 4, fileID); //read in 'data'
+            if((id[0] == 'd') && (id[1] == 'a') && (id[2] == 't') && (id[3] == 'a'))  { // data
+               //fread(&dataSize, sizeof(long), 1, fileID); //how many bytes of sound data we have
+               fread(&dataSize, 4, 1, fileID); //how many bytes of sound data we have
+               done = true;
+            }
+            fgetpos(fileID, &dataPos); 
+         }
+      }
+      else {
+         std::cerr << "Error: RIFF file but not a wave file" << std::endl;
+      }
+   }
+   else {
+      std::cerr << "Error: not a RIFF file" << std::endl;
+   }
+   
+   if(done) {
+      std::cout << "formatLength: " << formatLength << std::endl;
+      std::cout << "formatTag: " << formatTag << std::endl;
+
+      std::cout << "channels: " <<  channels << std::endl;
+      std::cout << "sampleRate: " <<  sampleRate << std::endl;   
+      std::cout << "avgBytesSec: " <<  avgBytesSec << std::endl;   
+      std::cout << "blockAlign: " <<  blockAlign << std::endl;         
+      std::cout << "bitsPerSample: " <<  bitsPerSample << std::endl;         
+      std::cout << "dataSize: " << dataSize << std::endl;   
+
+      // temporaly
+      framesPerBuffer = nframes;
+      
+      blockSize =  channels * framesPerBuffer; 
+            
+      if(bitsPerSample == 8) {
+         sampleFmt = SAGE_SAMPLE_INT8;
+         totalBlocks = dataSize / blockSize;
+      } else if(bitsPerSample == 16) {
+         sampleFmt = SAGE_SAMPLE_INT16;
+         totalBlocks = dataSize / (blockSize * 2);
+      } // about 32 bit:: check IEEE FLOAT
+      std::cout << "totalBlocks: " << totalBlocks << std::endl;   
+      
+   }
+   
+   nchan = channels;
+   samrate = sampleRate;
+   fmt =sampleFmt;
+   //nframes = framesPerBuffer;   
+            
+   return totalBlocks;
+}
+
+int wavConverter::writeHeader(int nchan, long samrate, int nframes, int bits)
+{
+   if(fileID == NULL) return -1;
+   blockCount =0; 
+#ifdef WIN32
+   dataPos = -1;
+#endif
+   writeMode = 1;
+   
+   channels = nchan;
+   sampleRate = samrate;
+   framesPerBuffer = nframes;
+   bitsPerSample = bits;   
+   
+   char headerInfo[255];
+   long size;      //32 bit value to hold file size
+   
+   // 16 bit values : short
+   // 32 bit values : long
+   bool done = false;
+   formatLength = bitsPerSample;
+   formatTag = 1;   // PCM
+   blockAlign = (channels * bitsPerSample) / 8 ;  
+   avgBytesSec = sampleRate * blockAlign; 
+   
+   fwrite( "RIFF", sizeof(char), 4, fileID );
+   fwrite( &size, sizeof(long), 1, fileID );
+   fwrite( "WAVEfmt ", sizeof(char), 8, fileID ); 
+   fwrite( &formatLength, sizeof(long), 1,fileID );   // ??
+   fwrite( &formatTag, sizeof(short), 1, fileID );   // ??
+   fwrite( &channels, sizeof(short),1,fileID ); 
+   fwrite( &sampleRate, sizeof(long), 1, fileID); 
+   fwrite( &avgBytesSec, sizeof(long), 1, fileID);   // ?
+   fwrite( &blockAlign, sizeof(short), 1, fileID);   // ?
+   fwrite( &bitsPerSample, sizeof(short), 1, fileID);   // ??
+   fwrite( "data", sizeof(char), 4, fileID); 
+   // later...
+   //fwrite( dataSize, sizeof(long), 1, fileID); //how many bytes of sound data we have
+   dataSize =0;
+   fgetpos(fileID, &dataPos);    
+      
+   blockSize =  channels * framesPerBuffer; 
+               
+   std::cout << "formatLength: " << formatLength << std::endl;
+   std::cout << "formatTag: " << formatTag << std::endl;
+
+   std::cout << "channels: " <<  channels << std::endl;
+   std::cout << "sampleRate: " <<  sampleRate << std::endl;   
+   std::cout << "avgBytesSec: " <<  avgBytesSec << std::endl;   
+   std::cout << "blockAlign: " <<  blockAlign << std::endl;         
+   std::cout << "bitsPerSample: " <<  bitsPerSample << std::endl;         
+   std::cout << "dataSize: " << dataSize << std::endl;   
+   std::cout << "blockSize: " << blockSize << std::endl;   
+
+                     
+   if(bitsPerSample == 8) {
+      sampleFmt = SAGE_SAMPLE_INT8;
+   } else if(bitsPerSample == 16) {
+      sampleFmt = SAGE_SAMPLE_INT16;
+   } // about 32 bit:: check IEEE FLOAT
+      
+   return 0;
+      
+}
+   
+
+int wavConverter::readFrames(void* frames)
+{
+   if(blockCount >= dataSize) return -1;
+   int size = blockSize + blockCount;         
+   if(size > dataSize) {
+      size = dataSize - blockCount;
+   } 
+   else {
+      size = blockSize;
+   }
+
+   size_t result;   
+   if(sampleFmt == SAGE_SAMPLE_INT8) {         
+      char* buff = (char*) frames;
+      result = fread(buff, sizeof(char), size, fileID); //read in our whole sound data chunk
+      for(int i=0; i < blockSize - size; i++)   {
+         *buff++ = '0';   
+      }
+      //std::cout << "SAGE_SAMPLE_INT8 test : " << result << std::endl;
+   } else if(sampleFmt == SAGE_SAMPLE_INT16) {   // short
+      short* buff = (short*) frames;
+      result = fread(buff, sizeof(short), size, fileID); //read in our whole sound data chunk
+      for(int i=0; i < blockSize - size; i++)   {
+         *buff++ = 0;   
+      }   
+      //std::cout << "SAGE_SAMPLE_INT16 test : " << result << std::endl;
+   } // about 32 bit:: check IEEE FLOAT
+
+   if(result == 0) {
+      //std::cout << "readFrames : end of file " << std::endl;
+      return -1;
+   }
+   
+   blockCount += size;
+   return 0;
+
+}
+
+int wavConverter::writeFrames(void* frames)
+{
+   size_t result;   
+   if(sampleFmt == SAGE_SAMPLE_INT8) {         // char
+      char* buff = (char*) frames;
+      result = fwrite(buff, sizeof(char), blockSize, fileID); //read in our whole sound data chunk
+      //std::cout << "SAGE_SAMPLE_INT8 test : " << result << std::endl;
+   } else if(sampleFmt == SAGE_SAMPLE_INT16) {   // short
+      short* buff = (short*) frames;
+      result = fwrite(buff, sizeof(short), blockSize, fileID); //read in our whole sound data chunk
+      //std::cout << "SAGE_SAMPLE_INT16 test : " << result << std::endl;
+   } // about 32 bit:: check IEEE FLOAT
+      
+   if(result == 0) {
+      //std::cout << "writeFrames : could not write " << std::endl;
+      return -1;
+   }   
+   dataSize += result;
+         
+   return 0;
+}
+
+/** Rewind the file pointer to the beginning of the audio stream */ 
+void wavConverter::begin()
+{
+   if(fileID) {
+      rewind(fileID);
+#ifdef WIN32
+      fseek (fileID, dataPos, SEEK_SET);
+#else
+      fseek (fileID, 0L, SEEK_SET);
+      fsetpos(fileID, &dataPos);
+#endif
+      blockCount =0;
+   }
+}
+
+void wavConverter::close()
+{
+   size_t result;   
+   if(writeMode == 1) {
+      rewind(fileID);
+#ifdef WIN32
+      fseek (fileID, dataPos, SEEK_SET);   
+#else
+      fseek (fileID, 0L, SEEK_SET);
+      fsetpos(fileID, &dataPos);
+#endif
+      result = fwrite(&dataSize, sizeof(long), 1, fileID); //read in our whole sound data chunk
+   }
+   std::cout << "dataSize: " << dataSize << std::endl;   
+}
Index: trunk/src/testing/src/fsConsole.cpp
===================================================================
--- trunk/src/testing/src/fsConsole.cpp	(revision 4)
+++ trunk/src/testing/src/fsConsole.cpp	(revision 4)
@@ -0,0 +1,835 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsConsole.cpp - a UI console to control the Free Space Manager
+ * Author : Luc Renambot, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "suil.h"
+#include "misc.h"
+#include <pthread.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#if defined(SAGE_NETLOG)
+#include "nl_log.h"
+#endif
+
+// SAGE object
+suil uiLib;
+
+// Application list
+typedef struct _application_t
+{
+   char *name;
+   int   id;
+   FILE *log;
+} application_t;
+
+application_t *Applications[64];
+FILE *playback;
+
+// When non-zero, this means the user is done using this program.
+int done;
+bool zeroPerf;
+char execArg[256];
+int noRecv, noSend, dispX, dispY, rendX, wholeX, intval = 0;
+
+// A static variable for holding the line.
+static char *line_read = (char *)NULL;
+static char current_command[256];
+static char exec_arg[256];
+
+// The names of functions that actually do the work
+int com_help     (char *arg);
+int com_exit     (char *arg);
+int com_exec     (char *arg);
+int com_move     (char *arg);
+int com_resize   (char *arg);
+int com_bg       (char *arg);
+int com_depth    (char *arg);
+int com_perf     (char *arg);
+int com_zeroperf (char *arg);
+int com_stopperf (char *arg);
+int com_kill     (char *arg);
+int com_shutdown (char *arg);
+int com_admin    (char *arg);
+int com_rate     (char *arg);
+int com_intval   (char *arg);
+int com_ptr      (char *arg);
+int com_share    (char *arg);
+
+
+
+// A structure which contains information on the commands
+// this program can understand.
+
+typedef struct {
+   const char *name;                   // User printable name of the function.
+   rl_icpfunc_t *func;           // Function to call to do the job.
+   const char *doc;                    // Documentation for this function.
+} COMMAND;
+
+//###
+COMMAND commands[] = {
+
+   { "exec",     com_exec,
+     "Execute an application: <exec app_name config_num (init_x init_y)>" },
+   { "move",     com_move,
+     "Move the window of an application: <move app_id dx dy>" },
+   { "resize",   com_resize,
+     "Resize the window of an application: <resize app_id left right bottom top>" },
+   { "bg",       com_bg,
+     "Change background color: <bg red green blue>" },
+   { "depth",    com_depth,
+     "Change z-order of the windows: <depth #_of_change app_id1 zVal1 ...>" },
+   { "perf",     com_perf,
+     "Request performance information: <perf app_id report_period(sec)>" },
+   { "stopperf", com_stopperf,
+     "Stop performance information report: <stopperf app_id>" },
+   { "zeroperf", com_zeroperf,
+     "set performance numbers zero: <zeroperf>" },
+   { "kill",     com_kill,
+     "Kill an application: <kill app_id>" },
+   { "shutdown", com_shutdown,
+     "Shutdown SAGE: <shutdown>" },
+   { "admin",    com_admin,
+     "Get administrative information and status: <admin>" },
+
+   { "ptr", com_ptr, "Move the pointer: <move dx dy>" },
+
+   { "help", com_help, "Display this text: <help>" },
+   { "exit", com_exit, "Quit the console: <exit>" },
+   { "quit", com_exit, "Quit the console: <quit>" },
+   { "rate", com_rate, "change the frame rate of apps: <rate app_id frame_rate>" },
+   { "intval", com_intval, "change the pause interval of the udp stream : <intval app_id interval>" },
+   { "share", com_share, "sharing app to another fsManager : <share app_id fs_IP fs_port>" },
+   { "?",    com_help, "Synonym for help: <?>" },
+
+   { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
+};
+//###
+
+
+// Functions locally defined
+void*  readThread(void *args);
+char*  dupstr (char *s);
+char*  rl_gets (const char *prompt);
+char*  command_generator (const char * text, int state);
+char** fileman_completion (const char * text, int start, int end);
+char*  stripwhite (char *thestring);
+int    execute_line (char *line);
+
+COMMAND* find_command (char *name);
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+void* readThread(void *args)
+{
+   suil *uiLib = (suil *)args;
+   int timestep = 1;
+
+   while (1)
+   {
+      sageMessage msg;
+
+      msg.init(READ_BUF_SIZE);
+      uiLib->rcvMessageBlk(msg);
+
+      if (msg.getCode() == APP_INFO_RETURN)
+      {
+         char appname[256], cmd[256];
+         int ret;
+         int appID, left, right, bottom, top, sailID, zValue;
+
+         ret = sscanf((char*)msg.getData(), "%s %d %d %d %d %d %d %d",
+                        appname, &appID, &left, &right, &bottom, &top, &sailID, &zValue);
+
+         if (ret != 8)
+               fprintf(stderr, "Something wrong, got only %d fields\n", ret);
+         else
+         {
+            if (Applications[appID] == NULL)
+            {
+               Applications[appID] = (application_t*)malloc(sizeof(application_t));
+               Applications[appID]->id   = appID;
+               Applications[appID]->name = strdup(appname);
+ 
+               // Get local time
+               time_t local = time(NULL);
+               struct tm *current = localtime( & local );
+
+               // Create a file for each application
+               char fn[256];
+               memset(fn, 0, 256);
+
+		char *sageDir = getenv("SAGE_DIRECTORY");
+		if (!sageDir) {
+			sage::printLog("fsConsole: cannot find the environment variable SAGE_DIRECTORY");
+			return NULL;
+		}
+
+		data_path path;
+		std::string found = path.get_file("log");
+		if (found.empty()) {
+			sage::printLog("fsConsole: cannot find the directory [%s]", "log");
+			return NULL;
+		}
+		const char *logPath = found.c_str();
+                        
+                    /*
+                    if (noRecv == 0) {
+                       sprintf(fn, "log/%s-%d-%d-%d-%d-%d-%d.log", // year-month-day hour-minute-second
+                            Applications[appID]->name,
+                            current->tm_year, current->tm_mon, current->tm_mday,
+                            current->tm_hour, current->tm_min, current->tm_sec);
+                    }
+                    else {   
+                        sprintf(fn, "log/%s-r%d-s%d-%dx%d-i%d.log", Applications[appID]->name,
+                              noRecv, noSend, dispX, dispY, intval);
+                    }         
+                    */
+
+		sprintf(fn, "%s/%s-%s.log", logPath, Applications[appID]->name, execArg);
+		sage::printLog("fsConsole: opening [%s] log file", fn);
+               Applications[appID]->log = fopen(fn, "w+");
+                    
+               if (noRecv > 0) {
+                  fprintf(Applications[appID]->log, 
+                           "%s rcv %d send %d dispRes %d %d rendRes %d %d whole %d %d int %d\n", 
+                           Applications[appID]->name,
+                           noRecv, noSend, dispX, dispY, rendX, dispY, wholeX, dispY, intval);
+               }      
+
+#if defined(SAGE_NETLOG)
+               memset(fn, 0, 256);
+               sprintf(fn, "log/%s-%d-%d-%d-%d-%d-%d.nlg", // year-month-day hour-minute-second
+               Applications[appID]->name,
+                           current->tm_year, current->tm_mon, current->tm_mday,
+                           current->tm_hour, current->tm_min, current->tm_sec);
+               NL_logger_module( Applications[appID]->name, fn, NL_LVL_INFO, NL_TYPE_APP, "" );
+#endif
+
+               memset(cmd, 0, 256);
+               sprintf(cmd, "%d", appID);
+               uiLib->sendMessage(STOP_PERF_INFO, cmd);
+                    
+               memset(cmd, 0, 256);
+               sprintf(cmd, "%d %d", appID, 1); // every second
+               uiLib->sendMessage(PERF_INFO_REQ, cmd);                    
+            }
+         }
+      }
+        
+      else if (msg.getCode() == UI_APP_SHUTDOWN)
+      {
+         int ret;
+         int appID;
+
+         ret = sscanf((char*)msg.getData(), "%d", &appID);
+         if (ret != 1)
+               fprintf(stderr, "Something wrong, got only %d fields\n", ret);
+         else
+         {
+            if (Applications[appID]->log)
+            {
+               fprintf(stderr, "Closing log file for application [%s]\n", Applications[appID]->name);
+               fclose(Applications[appID]->log);
+            }
+         }
+            
+      }
+        
+      else if (msg.getCode() == UI_PERF_INFO)
+      {
+         char appname[256], cmd[256];
+         int ret;
+         int appID, dispNodes, renderNodes, numStreamR;
+         float dispBandWidth, dispFrameRate, renderBandWidth, renderFrameRate, packetLoss;
+
+         ret = sscanf((char*)msg.getData(), "%d\nDisplay %f %f %f %d\nRendering %f %f %d",
+                        &appID,
+                        &dispBandWidth, &dispFrameRate, &packetLoss, &dispNodes,
+                        &renderBandWidth, &renderFrameRate, &renderNodes);
+
+         if (ret != 8)
+               fprintf(stderr, "Something wrong, got only %d fields\n", ret);
+         else
+         {
+            if (zeroPerf) {
+               fprintf(Applications[appID]->log, "%d 0.0 0.0 0.0 0.0 %d %d %s\n", timestep, dispNodes, renderNodes, exec_arg);
+            }
+            else {         
+               fprintf(Applications[appID]->log, "%d %f %f %f %f %f %d %d %s\n",
+                        timestep, dispBandWidth, dispFrameRate, packetLoss, renderBandWidth, 
+                        renderFrameRate, dispNodes, renderNodes, exec_arg);
+            }
+                        
+            fflush(Applications[appID]->log);
+                
+#if defined(SAGE_NETLOG)
+            NL_flush = 1;
+            NL_write( Applications[appID]->name, NL_LVL_INFO, "display", "bandwidth=d framerate=d", dispBandWidth, dispFrameRate);
+            NL_write( Applications[appID]->name, NL_LVL_INFO, "render",  "bandwidth=d framerate=d", renderBandWidth, renderFrameRate);
+#endif
+
+            timestep += 1;
+         }
+      }
+
+      else
+      {
+         fprintf(stdout, "\n\tMessage: %d\n\t[%s]\n", msg.getCode(), (char *)msg.getData());
+      }
+
+   }
+
+   return NULL;
+}
+
+
+
+char *dupstr (const char *s)
+{
+   char *r;
+
+   r = (char*)malloc (strlen (s) + 1);
+   strcpy (r, s);
+   return (r);
+}
+
+// Read a string, and return a pointer to it.
+// Returns NULL on EOF.
+char *rl_gets (const char *prompt)
+{
+  /* If the buffer has already been allocated,
+     return the memory to the free pool. */
+   if (line_read)
+   {
+      free (line_read);
+      line_read = (char *)NULL;
+   }
+
+  /* Get a line from the user. */
+   line_read = readline (prompt);
+
+  /* If the line has any text in it,
+     save it on the history. */
+   if (line_read && *line_read) add_history (line_read);
+
+   return (line_read);
+}
+
+// Generator function for command completion.  STATE lets us
+//   know whether to start from scratch; without any state
+//   (i.e. STATE == 0), then we start at the top of the list.
+char*
+command_generator (const char * text, int state)
+{
+   static int list_index, len;
+   const char *name;
+
+        /* If this is a new word to complete, initialize now.  This
+           includes saving the length of TEXT for efficiency, and
+           initializing the index variable to 0. */
+   if (!state)
+   {
+      list_index = 0;
+      len = strlen (text);
+   }
+
+        /* Return the next name which partially matches from the
+           command list. */
+   while (name = commands[list_index].name)
+   {
+      list_index++;
+
+      if (strncmp (name, text, len) == 0)
+      {
+         memset(current_command, 0, 256);
+         strcpy(current_command, name);
+         return dupstr(name);
+      }
+   }
+
+        /* If no names matched, then return NULL. */
+   return ((char *)NULL);
+}
+
+// Attempt to complete on the contents of TEXT.  START and END
+//   bound the region of rl_line_buffer that contains the word to
+//   complete.  TEXT is the word to complete.  We can use the entire
+//   contents of rl_line_buffer in case we want to do some simple
+//   parsing.  Returnthe array of matches, or NULL if there aren't any.
+char**
+fileman_completion (const char * text, int start, int end)
+{
+   char **matches;
+    
+   matches = (char **)NULL;
+
+        /* If this word is at the start of the line, then it is a command
+           to complete.  Otherwise it is the name of a file in the current
+           directory. */
+   if (start == 0)
+   {
+      matches = rl_completion_matches (text, command_generator);
+   }
+   else
+   {
+      // If match found, display the corresponding documentation
+      COMMAND *cm = find_command(current_command);
+      if (cm)
+      {
+         matches = (char**)malloc(3*sizeof(char*));
+         matches[0] = dupstr("");
+         matches[1] = dupstr(cm->doc);
+         matches[2] = NULL;
+      }
+   }
+    
+   return (matches);
+}
+
+// Look up NAME as the name of a command, and return a pointer to that
+//   command.  Return a NULL pointer if NAME isn't a command name.
+COMMAND *find_command (char *name)
+{
+   register int i;
+
+   for (i = 0; commands[i].name; i++)
+      if (strcmp (name, commands[i].name) == 0)
+      return (&commands[i]);
+
+   return ((COMMAND *)NULL);
+}
+
+// Strip whitespace from the start and end of STRING.  Return a pointer
+//   into STRING.
+char* stripwhite (char *thestring)
+{
+   register char *s, *t;
+
+   for (s = thestring; whitespace (*s); s++)
+      ;
+    
+   if (*s == 0)
+      return (s);
+
+   t = s + strlen (s) - 1;
+   while (t > s && whitespace (*t))
+      t--;
+   *++t = '\0';
+
+   return s;
+}
+
+
+
+// Execute a command line
+int execute_line (char *line)
+{
+   register int i;
+   COMMAND *command;
+   char *word;
+
+        /* Isolate the command word. */
+   i = 0;
+   while (line[i] && whitespace (line[i]))
+      i++;
+   word = line + i;
+
+   while (line[i] && !whitespace (line[i]))
+      i++;
+
+   if (line[i])
+      line[i++] = '\0';
+
+   command = find_command (word);
+
+   if (!command)
+   {
+      fprintf (stderr, "%s: No such command.\n", word);
+      return (-1);
+   }
+
+        /* Get argument to command, if any. */
+   while (whitespace (line[i]))
+      i++;
+
+   word = line + i;
+
+        /* Call the function. */
+   return ((*(command->func)) (word));
+}
+
+
+int
+main(int argc, char **argv)
+{
+   pthread_t thId;   
+   char *line, *s;
+   char com[256];
+
+   zeroPerf = false;
+   
+   // File containing commands
+   playback = NULL;
+   if (argc >= 2)
+   {
+      playback = fopen(argv[1], "r");
+      if (playback == NULL)
+            fprintf(stderr, "Cannot open playback file <%s>\n", argv[1]);   
+   }
+
+   if (argc > 2) {
+      strcpy(execArg, argv[2]);
+   }
+   else 
+      strcpy(execArg, "no");
+      
+   if (argc > 8)
+      intval = atoi(argv[8]);   
+    
+   // Setup the completion function
+   rl_attempted_completion_function = fileman_completion;
+    
+   // Clear application list
+   for (int k=0;k<64;k++) Applications[k] = NULL;
+
+   // Connect to SAGE
+   uiLib.init("fsManager.conf");
+   uiLib.connect(NULL);
+   
+   uiLib.sendMessage(SAGE_UI_REG," ");
+
+   // Start the receiving thread
+   if(pthread_create(&thId, 0, readThread, (void*)&uiLib) != 0)
+   {
+      return -1;
+   }
+
+#if defined(SAGE_NETLOG)
+   // Get local time
+   time_t local = time(NULL);
+   struct tm *current = localtime( & local );
+   char fn[256];
+    
+   memset(fn, 0, 256);
+   sprintf(fn, "log/%s-%d-%d-%d-%d-%d-%d.nlg", // year-month-day hour-minute-second
+   "fsConsole",
+            current->tm_year, current->tm_mon, current->tm_mday,
+            current->tm_hour, current->tm_min, current->tm_sec);
+   NL_logger_module( "fsConsole", fn, NL_LVL_INFO, NL_TYPE_APP, "" );
+#endif
+
+        /* Loop reading and executing lines until the user quits. */
+   for ( ; done == 0; )
+   {
+      if (playback && !feof(playback))
+      {
+         memset(com, 0, 256);
+         if ( fgets(com, 256, playback) )
+         {
+            // trailing \n
+            com[ strlen(com)-1 ] = '\0';
+            s = stripwhite (com);
+            int v, pause;   
+            v = sscanf(s, "pause %d", &pause);
+            if (v == 1)
+            {
+               fprintf(stderr, "PB> Pausing %d sec\n", pause);
+               sleep(pause);
+            }
+            else
+                  if (*s)
+            {
+               add_history (s);
+               fprintf(stderr, "PB> Exec <%s>\n", s);
+               execute_line (s);
+            }
+         }
+      }
+      else
+      {
+         line = rl_gets(">>> ");
+        
+         if (!line) break;
+     
+                /* Remove leading and trailing whitespace from the line.
+                   Then, if there is anything left, add it to the history list
+                   and execute it. */
+         s = stripwhite (line);
+     
+         if (*s)
+         {
+            add_history (s);
+            execute_line (s);
+         }
+      }
+   }
+    
+   // Close the command file
+   if (playback != NULL)
+      fclose(playback);
+    
+   return 0;
+}
+
+
+
+
+
+// ****************************************************************
+//                                                                 
+//                               Commands                          
+//                                                                 
+// ****************************************************************
+
+
+int com_exec (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "exec", "arg=s", arg);
+#endif
+   uiLib.sendMessage(EXEC_APP, arg);    
+   strcpy(exec_arg, arg);
+   return 0;
+}
+
+int com_move (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "move", "arg=s", arg);
+#endif
+   uiLib.sendMessage(MOVE_WINDOW, arg);
+   return 0;
+}
+
+int com_ptr (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "ptr", "arg=s", arg);
+#endif
+   uiLib.sendMessage(MOVE_OBJECT, arg);
+   return 0;
+}
+
+int com_resize (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "resize", "arg=s", arg);
+#endif
+   uiLib.sendMessage(RESIZE_WINDOW, arg);
+   return 0;
+}
+
+int com_bg (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "bg", "arg=s", arg);
+#endif
+   uiLib.sendMessage(SAGE_BG_COLOR, arg);
+   return 0;
+}
+
+int com_depth (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "depth", "arg=s", arg);
+#endif
+   uiLib.sendMessage(SAGE_Z_VALUE, arg);
+   return 0;
+}
+
+int com_zeroperf (char *arg)
+{
+   zeroPerf = true;
+   return 0;
+}
+
+int com_rate (char *arg)
+{
+   uiLib.sendMessage(APP_FRAME_RATE, arg);
+   return 0;
+}
+
+int com_intval (char *arg)
+{
+   uiLib.sendMessage(APP_PAUSE_INTV, arg);
+   return 0;
+}
+
+int com_share (char *arg)
+{
+   uiLib.sendMessage(SAGE_APP_SHARE, arg);
+   return 0;
+}
+
+int com_perf (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "perf", "arg=s", arg);
+#endif
+   zeroPerf = false;
+   uiLib.sendMessage(PERF_INFO_REQ, arg);
+   return 0;
+}
+
+int com_stopperf (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "stopperf", "arg=s", arg);
+#endif
+   uiLib.sendMessage(STOP_PERF_INFO, arg);
+   return 0;
+}
+
+int com_kill (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "kill", "arg=s", arg);
+#endif
+   uiLib.sendMessage(SHUTDOWN_APP, arg);
+   return 0;
+}
+
+int com_shutdown (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   //NL_flush = 1;
+   //NL_write( "fsConsole", NL_LVL_INFO, "shutdown", "arg=s", arg);
+#endif
+   // Close all the log files
+   for (int k=0;k<64;k++)
+      if (Applications[k])
+      fclose(Applications[k]->log);
+
+#if defined(SAGE_NETLOG)
+   NL_logger_del();
+#endif
+
+   // Send the message
+   uiLib.sendMessage(SAGE_SHUTDOWN, "shutdown");
+   done = 1;
+    
+   return 0;
+}
+
+int com_admin (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "admin", "arg=s", arg);
+#endif
+   uiLib.sendMessage(SAGE_ADMIN_CHECK, "admin");
+   return 0;
+}
+
+
+// Print out help for ARG, or for all of the commands
+//   if ARG is not present.
+int com_help (char *arg)
+{
+   register int i;
+   int printed = 0;
+
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "help", "arg=s", arg);
+#endif
+
+   for (i = 0; commands[i].name; i++)
+   {
+      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+      {
+         printf ("%-8s\t\t%s.\n", commands[i].name, commands[i].doc);
+         printed++;
+      }
+   }
+
+   if (!printed)
+   {
+      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+
+      for (i = 0; commands[i].name; i++)
+      {
+                /* Print in six columns. */
+         if (printed == 6)
+         {
+            printed = 0;
+            printf ("\n");
+         }
+
+         printf ("%s\t", commands[i].name);
+         printed++;
+      }
+
+      if (printed)
+            printf ("\n");
+   }
+   return (0);
+}
+
+// The user wishes to quit using this program.
+//   Just set DONE non-zero.
+int com_exit (char *arg)
+{
+#if defined(SAGE_NETLOG)
+   NL_flush = 1;
+   NL_write( "fsConsole", NL_LVL_INFO, "exit", "arg=s", arg);
+#endif
+
+   std::cout << "\t Done with SAGE..." << std::endl;
+
+   done = 1;
+   return (0);
+}
Index: trunk/src/testing/src/sageAudioManager.cpp
===================================================================
--- trunk/src/testing/src/sageAudioManager.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioManager.cpp	(revision 4)
@@ -0,0 +1,680 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioManager.cpp 
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageAudioManager.h"
+
+#include "sageEvent.h"
+#include "sageAudioReceiver.h"
+#include "sageSync.h"
+
+#include "sageAudioCircBuf.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+
+sageAudioManager::~sageAudioManager()
+{
+   if(eventQueue)
+   {
+      delete eventQueue;
+      eventQueue = NULL;
+   }
+   
+   if(syncClientObj)
+   {
+      delete syncClientObj;
+      syncClientObj = NULL;
+   }
+   
+   if(tcpObj)
+   {
+      delete tcpObj;
+      tcpObj = NULL;
+   }
+   
+   if(udpObj)
+   {
+      delete udpObj;
+      udpObj = NULL;
+   }
+   
+   if(audioModule) 
+   {
+      delete audioModule;
+      audioModule = NULL;
+   }
+            
+}
+
+sageAudioManager::sageAudioManager(int argc, char **argv)
+{
+   if (argc < 5) {
+      sage::printLog("SAGE Audio receiver : More arguments are needed");   
+      exit(0);
+   }
+
+   nodeID = atoi(argv[3]);
+   syncPort = atoi(argv[4]);
+
+   char fsIP[SAGE_IP_LEN];
+   strcpy(fsIP, argv[1]);
+   int fsPort = atoi(argv[2]);
+   
+   fsClient::init(fsPort);
+   connect(fsIP);
+   
+   //cout << "initialize : " << fsIP << " " << fsPort << " sync port : " << syncPort << endl;
+   
+   sage::printLog("SAGE Audio Manager : register to a Free Space Manager");   
+   sendMessage(REG_ARCV, argv[3]);
+      
+   rcvEnd = false;   
+   receiverList.clear();
+   
+   eventQueue = new sageEventQueue;
+         
+   pthread_t thId;
+   
+   if (pthread_create(&thId, 0, msgCheckThread, (void*)this) != 0) {
+      sage::printLog("sageAudioManager: can't create message checking thread");
+   }
+   
+   if (pthread_create(&thId, 0, perfReportThread, (void*)this) != 0) {
+      sage::printLog("sageAudioManager: can't create performance report thread");
+   }
+}   
+
+int sageAudioManager::init(char *data)
+{
+///////////////////
+//   sprintf(msgStr, "%d %d %d %d %d %d %d %s", fsm->nwInfo->rcvBufSize, 
+//         fsm->nwInfo->sendBufSize, fsm->nwInfo->mtuSize,   fsm->rInfo.audioSyncPort, 
+//         fsm->rInfo.audioPort, fsm->rInfo.bufSize, fsm->vdt->getNodeNum(), info);
+//////////////////
+   std::cout << "---> message : " << data << std::endl;
+
+   char token[TOKEN_LEN];
+
+   getToken(data, token);
+   nwCfg.rcvBufSize = atoi(token);
+
+   getToken(data, token);
+   nwCfg.sendBufSize = atoi(token);
+
+   getToken(data, token);
+   nwCfg.mtuSize = atoi(token);
+   
+   getToken(data, token);
+   //syncPort = atoi(token);
+
+   getToken(data, token);
+   streamPort = atoi(token);
+
+   getToken(data, token);
+   int agSyncPort = atoi(token);
+
+   getToken(data, token);
+   //bufSize = atoi(token);
+
+   int tokenNum = getToken(data, token);
+   totalRcvNum = atoi(token);
+   
+   if (tokenNum < 1) {
+      std::cout << "aStreamRcv::init : insufficient parameters in RCV_INIT message" << std::endl;
+      return -1;
+   }
+   
+   //audioOn = true;
+   
+///////////////////   
+//   sprintf(info, "%s %d %d %ld %d %d", ipStr, audio->deviceId, (int)audio->sampleFmt, audio->samplingRate,
+//          audio->channels, audio->framePerBuffer); 
+///////////////////          
+   char masterIp[SAGE_IP_LEN];
+   getToken(data, masterIp);
+   
+   getToken(data, token);
+   audioCfg.deviceNum = atoi(token);
+   //std::cout << "---------> devce " << audioCfg.deviceNum << std::endl;
+
+   getToken(data, token);
+   audioCfg.sampleFmt = (sageSampleFmt) atoi(token);
+   
+   getToken(data, token);
+   audioCfg.samplingRate = atoi(token);
+   
+   getToken(data, token);
+   audioCfg.channels = atoi(token);
+   
+   getToken(data, token);
+   audioCfg.framePerBuffer = atoi(token);
+
+   audioCfg.audioMode = SAGE_AUDIO_PLAY;
+   
+   //std::cout << "SAGE Receiver : initialization message was successfully parsed" << std::endl;
+
+   sageAudioModule::instance();
+   audioModule = sageAudioModule::_instance;
+   audioModule->init(audioCfg);
+
+   if (initNetworks() < 0)
+      return -1;
+
+   syncClientObj = new sageSyncClient;
+
+   if (syncClientObj->connectToServer(masterIp, syncPort) < 0) {
+      sage::printLog("SAGE receiver : Fail to connect to sync master");
+      return -1;
+   }
+   
+   sendMessage(SYNC_INIT_ARCV, nodeID);
+
+   pthread_t thId;
+   
+   if (pthread_create(&thId, 0, syncCheckThread, (void*)this) != 0) {
+      sage::printLog("sageAudioManager::init : can't create sync checking thread");
+   }
+   
+   if (pthread_create(&thId, 0, refreshThread, (void*)this) != 0) {
+      sage::printLog("sageAudioManager: can't create UI event check thread");
+   }
+      
+   return 0;
+}
+
+void* sageAudioManager::msgCheckThread(void *args)
+{
+   sageAudioManager *This = (sageAudioManager *)args;
+   
+   sageMessage *msg;
+
+   while (!This->rcvEnd) {
+      msg = new sageMessage;
+      if (This->rcvMessageBlk(*msg) > 0 && !This->rcvEnd) {
+         //std::cout << "----> message arrive" << std::endl;
+         This->eventQueue->appendEvent(EVENT_NEW_MESSAGE, 0, (void *)msg);
+      }   
+   }
+   
+   sage::printLog("sageAudioManager::msgCheckThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageAudioManager::syncCheckThread(void *args)
+{
+   sageAudioManager *This = (sageAudioManager *)args;
+   
+   while (!This->rcvEnd) {
+      sageEvent *syncEvent = new sageEvent;
+      syncEvent->eventType = EVENT_SYNC_MESSAGE;
+      char *syncMsg = syncEvent->eventMsg;
+      if (This->syncClientObj->waitForSync(syncMsg) == 0) {
+         //std::cout << "rcv sync " << syncEvent->eventMsg << std::endl;
+         This->eventQueue->appendEvent(syncEvent);
+      }   
+   }
+   
+   sage::printLog("sageAudioManager::syncCheckThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageAudioManager::perfReportThread(void *args)
+{
+   sageAudioManager *This = (sageAudioManager *)args;
+   
+   while (!This->rcvEnd) {
+      This->perfReport();
+      // if (This->shared->context && !This->rcvEnd) This->shared->context->checkEvent();
+      sage::usleep(100000);
+   }
+   
+   sage::printLog("sageAudioManager::perfReportThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageAudioManager::refreshThread(void *args)
+{
+   sageAudioManager *This = (sageAudioManager *)args;
+   
+   while (!This->rcvEnd) {
+      This->eventQueue->appendEvent(EVENT_REFRESH_SCREEN);
+      sage::usleep(16666);  // 1/60fps = 0.016666sec/frame
+   }
+   
+   sage::printLog("sageAudioManager::refreshThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageAudioManager::initNetworks()
+{
+   sage::printLog("Audio Manager is initializing network objects....");
+
+   tcpObj = new sageTcpModule;
+   if (tcpObj->init(SAGE_ARCV, streamPort, nwCfg) == 1) {
+      sage::printLog("sageAudioManager is already running");
+      return -1;
+   }
+   
+   sage::printLog("SAGE sageAudioManager Manager : tcp network object was initialized successfully");
+   
+   udpObj = new sageUdpModule;
+   udpObj->init(SAGE_ARCV, streamPort+(int)SAGE_UDP, nwCfg);
+   
+   sage::printLog("SAGE sageAudioManager Manager : udp network object was initialized successfully");
+   
+   pthread_t thId;
+   nwCheckThreadParam *param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = tcpObj;
+   
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("sageAudioManager::initNetwork : can't create network checking thread");
+         return -1;
+   }
+   
+   param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = udpObj;
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("sageAudioManager::initNetwork : can't create network checking thread");
+         return -1;
+   }
+   
+   return 0;
+}
+
+void* sageAudioManager::nwCheckThread(void *args)
+{
+   nwCheckThreadParam *param = (nwCheckThreadParam *)args;
+   streamProtocol *nwObj = (streamProtocol *)param->nwObj;
+   sageAudioManager *This = (sageAudioManager *)param->This;
+   
+   int senderID = -1;
+   char regMsg[SAGE_EVENT_SIZE];
+   
+   if (nwObj) {
+      while (!This->rcvEnd) {
+         senderID = nwObj->checkConnections(regMsg);
+         if (senderID >= 0 && !This->rcvEnd) {
+            This->eventQueue->appendEvent(EVENT_NEW_CONNECTION, regMsg, (void *)nwObj);
+         }   
+      }
+   }
+   
+   sage::printLog("sageAudioManager::nwCheckThread : exit");   
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageAudioManager::initStreams(char *msg, streamProtocol *nwObj)
+{
+   int senderID, instID, sailNodeNum, streamType, blockSize, frameRate;
+   int syncType, keyframe;
+   
+   // sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d", config.streamType, winID,
+   //  config.nodeNum, blockSize, config.syncMode, (int)config.sampleFmt, 
+   //  config.samplingRate, config.channels, config.framePerBuffer,  config.frameRate);
+   // 100 6881394 1 2176 0 1 44100 2 512 1      
+                                 
+   sscanf(msg, "%d %d %d %d %d %d %d %d %d %d %d %d", &senderID, &streamType, &instID, &sailNodeNum, &blockSize, 
+      &syncType, (int*) &audioCfg.sampleFmt, &audioCfg.samplingRate, &audioCfg.channels, &audioCfg.framePerBuffer, &frameRate, &keyframe);
+
+   std::cout << "stream info " << msg << std::endl;
+   
+   bool instExist = false;
+   for (int i=0; i<receiverList.size(); i++) {
+      if (!receiverList[i])
+         continue;
+
+      std::cout << "-------> " << receiverList[i]->getInstID() << " , " << instID << std::endl;
+      if (receiverList[i]->getInstID() == instID) {
+         instExist = true;
+         receiverList[i]->addStream(senderID);
+         std::cout << "existing stream " << instID << std::endl;
+         return 0;
+      }
+   }
+
+   if (instExist == false) {  
+      
+      audioModule->updateConfig(audioCfg);
+      /*
+      if (receiverList.size() >= 1) {
+         int tempId = receiverList.size() -1;
+         audioModule->deleteObject(tempId);   
+      
+         //audioObj->updateConfig(audioCfg);      
+         instExist = true;
+         //audioInstList[tempId]->buffer->reset();
+      }
+      */
+
+      sageAudioCircBuf *buffer = audioModule->createObject(instID);
+
+      if(buffer != NULL) {
+         buffer->setInstID(instID);
+         buffer->setKeyframe(keyframe);
+         if(streamType == SAGE_BLOCK_NO_SYNC)
+         {
+            std::cout << "SAGE_BLOCK_NO_SYNC" << std::endl;
+         } else 
+         {
+            buffer->connectSyncClient(syncClientObj);
+         }
+
+         sageAudioReceiver *recv = new sageAudioReceiver(msg, eventQueue, nwObj, buffer);
+         if(receiverList.size() == 0)
+         {
+            // set it as master receiver
+            recv->setMaster(true);
+         }
+
+         std::cout << "--------> audio receiver is created " << msg << std::endl;
+         std::cout << "inst init " << instID << std::endl;
+      
+         recv->addStream(senderID);
+         if(receiverList.size() == 0)
+         {
+            audioModule->play(buffer->getAudioId());
+         }
+         receiverList.push_back(recv);
+
+      }
+                        
+   }      
+   
+   return 0;
+}
+
+int sageAudioManager::shutdownApp(int instID)
+{
+   sage::printLog("sageAudioManager is shutting down an application");
+   int audioID = -1;
+   sageAudioReceiver *newMaster = NULL;
+   
+   std::vector<sageAudioReceiver*>::iterator iter = receiverList.begin(); 
+
+   std::cout << "receiverList size : " << receiverList.size() << " inst id = " << instID << std::endl;
+   for (int i=0; i<receiverList.size(); i++, iter++) {
+      if (!receiverList[i])
+         continue;
+      
+      std::cout << "shutdown app searching: inst=" <<  receiverList[i]->getInstID() << " , sender=" << receiverList[i]->getSenderID() << " ,"  << instID << std::endl; 
+      if (instID == -1 || receiverList[i]->getInstID() == instID) {
+         if(audioModule) {
+            audioID = audioModule->stop(receiverList[i]->getInstID());
+            std::cout << "--------------------shutdown app : " << instID << " " << receiverList[i]->getAudioId() << std::endl; 
+         }   
+         // check receiverList then if it's master,
+         if((receiverList[i]->isMaster() == true) && (audioID >=0))
+         { 
+            receiverList[i]->setMaster(false);
+			std::cout << "----- master is shutting down" << std::endl;
+
+            // then find another available receiver 
+            for (int j=0; j<receiverList.size(); j++) {
+               if (!receiverList[j])
+                  continue;
+			  std::cout << "----- receiverList id= " << receiverList[j]->getAudioId() << " audioID = " << audioID << std::endl;
+               if(receiverList[j]->getAudioId() == audioID) {
+                  newMaster = receiverList[j];
+				  std::cout << "----- found new master" << std::endl;
+                  break;
+               }
+            }
+
+            // if there is, set another reciver as a master
+            if(newMaster != NULL) {
+               newMaster->setMaster(true);
+               std::cout << "master is changed to " << audioID << std::endl; 
+               // set reset flag
+               newMaster->setResetFlag();
+               audioModule->play(newMaster->getAudioId());
+            }  
+         }
+         //delete receiverList[i];
+         receiverList[i] = NULL;
+         receiverList.erase(iter);
+         break;
+      }   
+   }
+   
+   return 0;
+}
+
+int sageAudioManager::parseEvent(sageEvent *event)
+{   
+   if (!event) {
+      sage::printLog("sageAudioManager::parseEvent : event object is Null");
+      return -1;
+   }
+   
+   switch (event->eventType) {
+      case EVENT_NEW_CONNECTION : {
+         initStreams(event->eventMsg, (streamProtocol *)event->param);
+         break;
+      }
+      
+      case EVENT_NEW_MESSAGE : {
+         parseMessage((sageMessage *)event->param);
+         break;
+      }
+      
+      case EVENT_SYNC_MESSAGE : {
+         processSync((char *)event->eventMsg);
+         break;
+      }
+   }
+
+   delete event;
+   
+   return 0;
+}
+
+int sageAudioManager::parseMessage(sageMessage *msg)
+{   
+   if (!msg) {
+      sage::printLog("sageAudioManager::parseMessage : message is NULL");
+      return -1;
+   }
+      
+   switch (msg->getCode()) {
+      case ARCV_AUDIO_INIT : {
+         //std::cout << "rcv init : " << (char *)msg->getData() << std::endl;
+         if (init((char *)msg->getData()) < 0) 
+            rcvEnd = true;
+         //std::cout << "-----> rcv init : " << (char *)msg->getData() << " rcvEnd : " << rcvEnd << std::endl;
+         break;
+      }
+
+      case SHUTDOWN_RECEIVERS : {
+         shutdownApp(-1);
+         
+         if(audioModule) {
+            delete audioModule; 
+            audioModule = NULL;
+         }
+         if(syncClientObj) {
+            delete syncClientObj;
+            syncClientObj = NULL;
+         }   
+         
+         rcvEnd = true;
+         break;
+      }         
+      case ARCV_SHUTDOWN_APP : {
+         std::cout << "message: " <<  msg << std::endl;
+         shutdownApp(atoi((char *)msg->getData()));
+
+         break;
+      }
+
+      case RCV_PERF_INFO_REQ : {
+         startPerformanceReport(msg);   
+         break;
+      }
+
+      case RCV_PERF_INFO_STOP : {
+         stopPerformanceReport(msg);   
+         break;
+      }         
+
+   }
+      
+   msg->destroy();
+   delete msg;
+   
+   return 0;
+}
+
+int sageAudioManager::processSync(char *msg)
+{
+   int groupID, syncFrame;
+   sscanf(msg, "%d %d", &groupID, &syncFrame);
+   
+   sageAudioReceiver *recv;
+   
+   for (int i=0; i<receiverList.size(); i++) {
+      recv = receiverList[i];
+      
+      if (!recv)
+         continue;
+
+      if (recv->getInstID() == groupID) {
+         recv->processSync(syncFrame);   
+         break;   
+      }      
+   }
+   
+   return 0;
+}
+
+void sageAudioManager::mainLoop()
+{
+   while(!rcvEnd) {
+      //std::cout << "---->wait a event" << std::endl;
+      sageEvent *newEvent = eventQueue->getEvent();
+      //std::cout << "----->get the event " << newEvent->eventType << std::endl;
+      parseEvent(newEvent);
+
+   }
+}
+
+int sageAudioManager::perfReport()
+{
+   for (int i=0; i<receiverList.size(); i++) {
+      if (receiverList[i]) {
+         char *frameStr = NULL;
+         char *bandStr = NULL;
+         receiverList[i]->evalPerformance(&frameStr, &bandStr);
+         if (frameStr) {
+            sendMessage(DISP_RCV_FRATE_RPT, frameStr);
+            //std::cout << "send frame rate " << frameStr << std::endl;
+            delete [] frameStr;
+         }
+         
+         if (bandStr) {   
+            sendMessage(DISP_RCV_BANDWITH_RPT, bandStr);
+            //std::cout << "send bandwidth " << bandStr << std::endl;
+            delete [] bandStr;
+         }
+      }   
+   }
+   
+   return 0;
+}
+
+int sageAudioManager::startPerformanceReport(sageMessage *msg)
+{
+   char *perfStr = (char *)msg->getData();
+   int instID, rate;
+   sscanf(perfStr, "%d %d", &instID, &rate);
+   
+   //std::cout << "start perf report " << rate << std::endl;
+   
+   for (int i=0; i<receiverList.size(); i++) {
+      if (!receiverList[i])
+         continue;
+      
+      if (receiverList[i]->getInstID() == instID) {
+         receiverList[i]->setReportRate(rate);
+         receiverList[i]->resetTimer();
+         receiverList[i]->resetBandWidth();
+         receiverList[i]->resetFrame();
+         break;
+      }
+   }
+   return 0;
+}
+
+int sageAudioManager::stopPerformanceReport(sageMessage *msg)
+{
+   int instID = atoi((char *)msg->getData());
+
+   for (int i=0; i<receiverList.size(); i++) {
+      if (!receiverList[i])
+         continue;
+      
+      if (receiverList[i]->getInstID() == instID) {
+         receiverList[i]->setReportRate(0);
+         break;
+      }
+   }
+   
+   return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+#if defined(WIN32)
+   sage::win32Init();
+#endif
+   sage::initUtil();
+
+   sageAudioManager manager(argc, argv);
+   manager.mainLoop();
+   
+   return 0;
+}
+
Index: trunk/src/testing/src/SDLMain.h
===================================================================
--- trunk/src/testing/src/SDLMain.h	(revision 4)
+++ trunk/src/testing/src/SDLMain.h	(revision 4)
@@ -0,0 +1,11 @@
+/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
+       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
+       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
+
+    Feel free to customize this file to suit your needs
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@interface SDLMain : NSObject
+@end
Index: trunk/src/testing/src/sageBridge.cpp
===================================================================
--- trunk/src/testing/src/sageBridge.cpp	(revision 4)
+++ trunk/src/testing/src/sageBridge.cpp	(revision 4)
@@ -0,0 +1,1143 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBridge.cpp - the SAGE component to distribute pixels to multiple
+ *         SAGE displays
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageVersion.h"
+#include "sageBridge.h"
+#include "sageAudioBridge.h"
+#include "messageInterface.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+#include "sageSharedData.h"
+#include "appInstance.h"
+#include "sageSync.h"
+#include "sageBlockQueue.h"
+#include "sageEvent.h"
+
+sageBridge::~sageBridge()
+{
+   if (shared)
+      delete shared;
+      
+   if (msgInf) {
+      msgInf->shutdown();
+      delete msgInf;
+   }   
+}
+
+sageBridge::sageBridge(int argc, char **argv) : syncPort(0), syncGroupID(0), audioPort(44000),
+      allocPolicy(ALLOC_SINGLE_NODE)
+{
+	nwCfg = new sageNwConfig;
+	/*
+	for (int i=0; i<MAX_INST_NUM; i++)
+		appInstList[i] = NULL;
+		*/
+	appInstList.clear();
+	instNum = 0;   
+	
+	if (argc < 2) {  // master mode with default configuration file
+		initMaster("sageBridge.conf");
+	}
+	else if (strcmp(argv[1], "slave") != 0) {  // master mode with user configuration file
+		initMaster(argv[1]);
+	}   
+	else {  // slave mode
+		if (argc < 5) {
+			sage::printLog("sageBridge::sageBridge() : more arguments are needed for SAGE bridge slaves" );
+			exit(0);
+		}
+		
+		shared = new bridgeSharedData;
+		master = false;
+		strcpy(masterIP, argv[2]);
+		
+		msgPort = atoi(argv[3]);
+		
+		msgInfConfig conf;
+		conf.master = false;
+		strcpy(conf.serverIP, masterIP);
+		conf.serverPort = msgPort;
+		
+		msgInf = new messageInterface();
+		msgInf->init(conf);
+		msgInf->msgToServer(0, BRIDGE_REG_NODE, argv[4]);
+		
+		shared->nodeID = atoi(argv[4]);
+		sage::printLog("sageBridge : start slave node %d", shared->nodeID);
+		
+		tcpObj = NULL;
+		udpObj = NULL;
+		bridgeEnd = false;   
+		
+		pthread_t thId;
+		
+		if (pthread_create(&thId, 0, msgCheckThread, (void*)this) != 0) {
+			sage::printLog("sageBridge::initSlave : can't create message checking thread");
+		}
+		
+		if (pthread_create(&thId, 0, perfReportThread, (void*)this) != 0) {
+			sage::printLog("sageBrdige::initSlave : can't create performance report thread");
+		}
+	}
+}   
+
+int sageBridge::initMaster(const char *cFile)
+{
+	shared = new bridgeSharedData;
+	shared->nodeID = 0;
+	master = true;
+	bridgeEnd = false;
+	
+	data_path path;
+	std::string found = path.get_file(cFile);
+	if (found.empty()) {
+		sage::printLog("sageBridge: cannot find the file [%s]", cFile);
+		return -1;
+	}
+	const char *bridgeConfigFile = found.c_str();
+	sage::printLog("sageBridge: SAGE version [%s]", SAGE_VERSION);
+	sage::printLog("sageBridge: using [%s] configuration file", bridgeConfigFile);
+	
+	FILE *fileBridgeConf = fopen(bridgeConfigFile, "r");
+	
+	if (!fileBridgeConf) {
+		sage::printLog("sageBridge: fail to open SAGE Bridge config file [%s]\n",bridgeConfigFile);
+		return -1;
+	}
+	
+	char token[TOKEN_LEN];
+	int tokenIdx = getToken(fileBridgeConf, token);
+	
+	while(tokenIdx != EOF) {
+		if (strcmp(token, "masterIP") == 0) {
+			getToken(fileBridgeConf, masterIP);
+		}
+		else if (strcmp(token, "slaveList") == 0) {   
+			getToken(fileBridgeConf, token);
+			slaveNum = atoi(token);
+			shared->nodeNum = slaveNum + 1;
+			for (int i=0; i<slaveNum; i++)
+				getToken(fileBridgeConf, slaveIPs[i]);
+		}
+		else if (strcmp(token, "streamPort") == 0) {   
+			getToken(fileBridgeConf, token);
+			streamPort = atoi(token);
+		}
+		else if (strcmp(token, "msgPort") == 0) {   
+			getToken(fileBridgeConf, token);
+			msgPort = atoi(token);
+		}
+		else if (strcmp(token, "syncPort") == 0) {
+			getToken(fileBridgeConf, token);
+			syncPort = atoi(token);
+		}
+		else if (strcmp(token, "audioPort") == 0) {
+			getToken(fileBridgeConf, token);
+			audioPort = atoi(token);
+		}
+		else if (strcmp(token, "rcvNwBufSize") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->rcvBufSize = getnumber(token); //atoi(token);
+		}
+		else if (strcmp(token, "sendNwBufSize") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->sendBufSize = getnumber(token); //atoi(token);
+		}
+		else if (strcmp(token, "MTU") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->mtuSize = atoi(token);
+		}
+		else if (strcmp(token, "maxBandWidth") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->maxBandWidth = atoi(token);
+		}
+		else if (strcmp(token, "maxCheckInterval") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->maxCheckInterval = atoi(token);
+		}
+		else if (strcmp(token, "flowWindowSize") == 0) {
+			getToken(fileBridgeConf, token);
+			nwCfg->flowWindow = atoi(token);
+		}
+		else if (strcmp(token, "memSize") == 0) {
+			getToken(fileBridgeConf, token);
+			shared->bufSize = atoi(token) * 1024*1024;
+		}
+		else if (strcmp(token, "nodeAllocation") == 0) {
+			getToken(fileBridgeConf, token);
+			if (strcmp(token, "single") == 0) 
+				allocPolicy = ALLOC_SINGLE_NODE;
+			else if (strcmp(token, "balanced") == 0)
+				allocPolicy = ALLOC_LOAD_BALANCING;
+		}
+		else if (strcmp(token, "frameDrop") == 0) {
+			getToken(fileBridgeConf, token);
+			if (strcmp(token, "true") == 0)
+				shared->frameDrop = true;
+			else
+				shared->frameDrop = false;
+		}
+		else if (strcmp(token, "nwProtocol") == 0) {
+			getToken(fileBridgeConf, token);
+			sage::toupper(token);
+			if (strcmp(token, "TCP") == 0) 
+				shared->protocol = SAGE_TCP;
+			else if (strcmp(token, "UDP") == 0)
+				shared->protocol = SAGE_UDP;   
+		}
+		
+		tokenIdx = getToken(fileBridgeConf, token);
+	}
+	
+	msgInfConfig conf;
+	conf.master = true;
+	conf.serverPort = msgPort;
+	
+	msgInf = new messageInterface;
+	msgInf->init(conf);
+	
+	syncServerObj = new sageSyncServer;
+	
+	if (syncServerObj->init(syncPort) < 0) {
+		sage::printLog("SAGE Bridge : Error init'ing the sync server object" );
+		bridgeEnd = true;   
+		return -1;
+	}
+	
+	pthread_t thId;
+	
+	if (pthread_create(&thId, 0, msgCheckThread, (void*)this) != 0) {
+		sage::printLog("sageBridge::initMaster : can't create message checking thread");
+	}
+	
+	if (pthread_create(&thId, 0, perfReportThread, (void*)this) != 0) {
+		sage::printLog("sageBrdige::initMaster : can't create performance report thread");
+	}
+	
+	shared->syncClientObj = new sageSyncClient;
+	
+	if (shared->syncClientObj->connectToServer(strdup("127.0.0.1"), syncPort) < 0) {
+		sage::printLog("SAGE Bridge : Fail to connect to sync master" );
+		return -1;
+	}
+	
+	launchSlaves();
+	initNetworks();
+	
+	//audioBridge = new sageAudioBridge(masterIP, audioPort, msgInf, shared);
+	
+	return 0;
+}
+
+int sageBridge::launchSlaves()
+{
+   char *sageDir = getenv("SAGE_DIRECTORY");
+
+   if (!sageDir) {
+      sage::printLog("sageBridge : cannot find the environment variable SAGE_DIRECTORY" );
+      return -1;
+   }
+
+   for (int i=0; i<slaveNum; i++) {
+      char command[TOKEN_LEN];
+      sprintf(command, "%s/bin/sageBridge slave %s %d %d", sageDir, masterIP, msgPort, i+1); 
+      execRemBin(slaveIPs[i], command);
+   }
+   
+   return 0;
+}
+
+int sageBridge::initSlave(char *data)
+{
+   sage::printLog("sageBridge : initialize slave %d", shared->nodeID);
+   
+   sscanf(data, "%d %d %d %d %d %d %d %d %d %d", &nwCfg->rcvBufSize, &nwCfg->sendBufSize,
+      &nwCfg->mtuSize, (int *)&nwCfg->maxBandWidth, &nwCfg->maxCheckInterval, &nwCfg->flowWindow,
+      &syncPort, &streamPort, &shared->nodeNum, &shared->bufSize);
+
+   std::cout << "slave init info " << data << std::endl;
+   
+   initNetworks();
+   
+   syncServerObj = NULL;
+   shared->syncClientObj = new sageSyncClient;
+
+   if (shared->syncClientObj->connectToServer(masterIP, syncPort) < 0) {
+      sage::printLog("SAGE Bridge : Fail to connect to sync master");
+      return -1;
+   }
+
+   return 0;
+}
+
+int sageBridge::initNetworks()
+{
+   nwCfg->blockSize = 9000;
+   nwCfg->groupSize = 65536;
+   sageUdpModule *sendObj = new sageUdpModule;
+   sendObj->init(SAGE_SEND, 0, *nwCfg); // starts sageUdpModule::sendingThread()
+   shared->sendObj = (streamProtocol *)sendObj;
+   fprintf(stderr,"sageBridge::%s() : UDP sending object init-ed", __FUNCTION__);
+
+   tcpObj = new sageTcpModule;
+   if (tcpObj->init(SAGE_RCV, streamPort, *nwCfg) == 1) {
+      sage::printLog("sageBridge : error in initializing TCP object");
+      bridgeEnd = true;
+      return -1;
+   }
+   sage::printLog("sageBridge::%s() : tcp network object was initialized.", __FUNCTION__ );
+   
+   udpObj = new sageUdpModule;
+   if (udpObj->init(SAGE_RCV, streamPort+(int)SAGE_UDP, *nwCfg) == 1) {
+      sage::printLog("sageBridge : error in initializing UDP object");
+      bridgeEnd = true;
+      return -1;
+   }
+   sage::printLog("sageBridge::%s() : udp network object was initialized.", __FUNCTION__ );
+
+   pthread_t thId;
+   nwCheckThreadParam *param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = tcpObj;
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("sageBridge::initNetwork : can't create network checking thread");
+         return -1;
+   }
+   
+   param = new nwCheckThreadParam;
+   param->This = this;
+   param->nwObj = udpObj;
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+      sage::printLog("sageBridge::initNetwork : can't create network checking thread");
+         return -1;
+   }
+   
+   return 0;
+}
+
+// Thread Functions
+
+void* sageBridge::msgCheckThread(void *args)
+{
+   sageBridge *This = (sageBridge *)args;
+   
+   sageMessage *msg;
+
+   while (!This->bridgeEnd) {
+      msg = new sageMessage;
+      //std::cout << "waiting for message" << std::endl;
+      int clientID = This->msgInf->readMsg(msg, 100000) - 1;
+            
+      if (clientID >= 0 && !This->bridgeEnd) {
+         //std::cout << "read a message" << std::endl;
+         This->shared->eventQueue->appendEvent(EVENT_NEW_MESSAGE, clientID, (void *)msg);
+      }   
+   }
+   
+   sage::printLog("sageBridge::msgCheckThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageBridge::perfReportThread(void *args)
+{
+   sageBridge *This = (sageBridge *)args;
+   
+   while (!This->bridgeEnd) {
+      This->perfReport();
+      sage::usleep(100000);
+   }
+   
+   sage::printLog("sageBridge::perfReportThread : exit");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageBridge::nwCheckThread(void *args)
+{
+   nwCheckThreadParam *param = (nwCheckThreadParam *)args;
+   streamProtocol *nwObj = (streamProtocol *)param->nwObj;
+   sageBridge *This = (sageBridge *)param->This;
+   
+   int senderID = -1;
+   char regMsg[SAGE_EVENT_SIZE];
+   
+   if (nwObj) {
+      while (!This->bridgeEnd) {
+         senderID = nwObj->checkConnections(regMsg);
+         if (!This->bridgeEnd) {
+            if (senderID >= 0)
+               This->shared->eventQueue->appendEvent(EVENT_NEW_CONNECTION, regMsg, (void *)nwObj);
+            else
+               break;   
+         }
+      }
+   }
+
+   sage::printLog("sageBridge::nwCheckThread : exit");   
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageBridge::perfReport()
+{
+	appInstance* app_inst = NULL;
+	std::vector<appInstance*>::iterator iter;
+	for(iter = appInstList.begin(); iter != appInstList.end(); iter++)
+	{
+		app_inst = (appInstance*) *iter;
+		if(!app_inst) continue;
+		app_inst->sendPerformanceInfo();
+	}
+
+   return 0;
+}
+
+int sageBridge::findMinLoadNode()
+{
+   int nodeSel = 0;
+   double minLoad = 0;
+
+	appInstance* app_inst = NULL;
+	std::vector<appInstance*>::iterator iter;   
+	double loadSum = 0.0;
+   
+   for (int i=0; i<shared->nodeNum; i++) {
+		loadSum = 0.0;
+		for(iter = appInstList.begin(); iter != appInstList.end(); iter++) 
+		{
+			app_inst = (appInstance*) *iter;
+			if(!app_inst) continue;
+         if (app_inst->allocInfoList[0].nodeID == i)
+            loadSum += app_inst->curBandWidth;
+      }
+      
+      if (i == 0) {
+         minLoad = loadSum;
+      }
+      else if (minLoad > loadSum) {
+         nodeSel = i;
+         minLoad = loadSum;
+      }
+      
+      std::cout << "node " << i << " load " << loadSum << std::endl;      
+   }
+
+   return nodeSel;
+}
+
+int sageBridge::regApp(sageMessage &msg, int clientID)
+{
+   char *data = (char *)msg.getData();
+   fprintf(stderr, "sageBridge::%s() : msg [%s], clientID %d\n", __FUNCTION__, data, clientID);
+   
+   if (master) {
+      appInstance *inst = new appInstance(data, instNum, shared);
+      
+      inst->sailClient = clientID;   
+      inst->waitNodes = slaveNum;
+      
+      if (allocPolicy == ALLOC_LOAD_BALANCING) {
+         inst->allocateNodes(allocPolicy);
+      }   
+      else  {
+         int selNode = findMinLoadNode();
+         sage::printLog("sageBridge::%s() : allocate app to node %d", __FUNCTION__, selNode);
+         inst->allocateNodes(allocPolicy, selNode);
+      }   
+      
+      appInstList.push_back(inst);
+
+      syncGroup *sGroup = NULL;
+      char regStr[TOKEN_LEN];
+      sprintf(regStr, "%s %d 0", data, inst->nodeNum);
+      
+      if (inst->nodeNum > 1) {
+         sGroup = addSyncGroup();
+         inst->firstSyncGroup = sGroup;
+
+         if (sGroup)
+            sprintf(regStr, "%s %d %d", data, inst->nodeNum, sGroup->getSyncID());
+      }
+      
+      fprintf(stderr, "sageBridge::%s() : distributing BRIDGE_APP_REG message. regStr[%s] \n", __FUNCTION__, regStr);
+
+      msgInf->distributeMessage(BRIDGE_APP_REG, instNum, regStr, slaveList, slaveNum);
+      
+
+
+      char sailInitMsg[TOKEN_LEN];
+      sprintf(sailInitMsg, "%d %d %d %d", instNum , nwCfg->rcvBufSize, nwCfg->sendBufSize, nwCfg->mtuSize);
+      fprintf(stderr, "sageBridge::%s() : sending SAIL_INIT_MSG [%s] \n", __FUNCTION__, sailInitMsg);
+      msgInf->msgToClient(clientID, 0, SAIL_INIT_MSG, sailInitMsg);
+      
+      if (inst->waitNodes == 0) {
+         connectApp(inst);
+         inst->waitNodes = inst->nodeNum;
+         sendStreamInfo(inst);
+         if (inst->audioOn)
+            audioBridge->startAudioStream(instNum, clientID);
+      }
+      
+      instNum++;
+   }
+   else {
+      std::cout << "register app on node " << shared->nodeID << std::endl;
+      int instID = msg.getDest();   
+      appInstance *inst = new appInstance(data, instID, shared);
+		appInstList.push_back(inst);
+
+      instNum = MAX(instID+1, instNum);
+      msgInf->msgToServer(instID, BRIDGE_APP_INST_READY);
+   }   
+   return 0;   
+}
+
+int sageBridge::connectApp(appInstance *inst)
+{
+   int msgLen = 8 + SAGE_IP_LEN * inst->nodeNum;
+   char *msgStr = new char[msgLen];
+   
+   sprintf(msgStr, "%d %d ", streamPort, inst->nodeNum);
+
+   // list the ip addresses of all bridge nodes
+   for (int i=0; i<inst->nodeNum; i++) {
+      int nodeID = inst->allocInfoList[i].nodeID;
+      char nodeStr[TOKEN_LEN];
+      if (nodeID == 0)
+         sprintf(nodeStr, "%s %d ", masterIP, nodeID);
+      else   
+         sprintf(nodeStr, "%s %d ", slaveIPs[nodeID-1], nodeID);
+      strcat(msgStr, nodeStr);
+   }
+   
+   sage::printLog("app-brige connection info : %s", msgStr);
+   
+   msgInf->msgToClient(inst->sailClient, 0, SAIL_CONNECT_TO_RCV, msgStr);
+
+   return 0;
+}
+
+int sageBridge::sendStreamInfo(appInstance *inst)
+{
+   int msgLen = 4 + SAGE_IP_LEN*inst->nodeNum;
+   char *msgStr = new char[msgLen];
+      
+   sprintf(msgStr, "%d ", inst->nodeNum);
+   
+   for (int i=0; i<inst->nodeNum; i++) {
+      char str[TOKEN_LEN];
+      sprintf(str, "%d %d ", inst->allocInfoList[i].blockID, inst->allocInfoList[i].nodeID);
+      strcat(msgStr, str);
+   }
+
+   msgInf->msgToClient(inst->sailClient, 0, SAIL_INIT_STREAM, msgStr);
+   sage::printLog("sageBridge : stream info sent to app");
+   
+   return 0;
+}
+
+appInstance* sageBridge::findApp(int id, int& index)
+{
+	index =0;
+	appInstance* app_inst = NULL;
+	std::vector<appInstance*>::iterator iter;   
+	for(iter = appInstList.begin(); iter != appInstList.end(); iter++) 
+	{
+		if((*iter)->instID == id)
+		{
+			app_inst = (appInstance*) *iter;
+			break;
+		}
+	}
+	return app_inst;
+}
+
+int sageBridge::shutdownApp(int instID, bool fsmToApp)
+{
+	int index;
+   appInstance *inst = findApp(instID, index);      
+   
+   if (inst) {
+      if (master && !inst->isActive()) {
+         int clientID = inst->sailClient;
+   
+         if (fsmToApp) {
+            msgInf->msgToClient(clientID, 0, APP_QUIT);
+         }
+         
+         if (audioBridge && inst->audioOn)
+            audioBridge->shutdownDup(instID);
+         
+         std::cout << "send clear app inst message" << std::endl;
+         msgInf->distributeMessage(CLEAR_APP_INSTANCE, instID, slaveList, slaveNum);
+         appInstList.erase(appInstList.begin() +index);
+         delete inst;
+      }   
+   }
+   else {
+      sage::printLog("sageBridge::shutdownApp : invalid app instance ID");
+      return -1;
+   }   
+       
+   return 0;
+}
+
+int sageBridge::forwardToSail(int instID, sageMessage &msg)
+{
+	int index;
+   appInstance *inst = findApp(instID, index);      
+   
+   if (inst) {
+      int clientID = inst->sailClient;
+      msg.setClientID(clientID);
+      msgInf->msgToClient(msg);         
+   }   
+
+   return 0;
+}
+
+int sageBridge::shutdownAllApps()
+{
+	appInstance* inst = NULL;
+	std::vector<appInstance*>::iterator iter;   
+	for(iter = appInstList.begin(); iter != appInstList.end(); iter++) 
+	{
+		inst = (appInstance*) *iter;
+		if(!inst) continue;
+
+		// ????????? 
+      msgInf->msgToClient(inst->sailClient, 0, APP_QUIT);
+      inst->shutdownAllStreams();
+      delete inst;
+   }
+	appInstList.clear();
+      
+   return 0;
+}
+
+int sageBridge::initStreams(char *msg, streamProtocol *nwObj)
+{
+	int senderID, instID, frameRate, streamType;
+
+	sscanf(msg, "%d %d %d %d", &senderID, &streamType, &frameRate, &instID);
+
+	//std::cout << "sender " << senderID << " connected to node " << shared->nodeID << std::endl;
+	fprintf(stderr,"sageBridge::%s() : msg [%s]\n", __FUNCTION__, msg);
+
+	int index;
+	appInstance *inst = findApp(instID, index);
+	if (inst) {
+		if (!inst->initialized)
+			inst->init(msg, nwObj);
+
+		//std::cout << "node " << shared->nodeID << " init instance" << std::endl;
+
+		int streamNum = inst->addStream(senderID);
+		//std::cout << "node " << shared->nodeID << " add stream" << std::endl;
+	}
+	else {
+		sage::printLog("sageBridge::initStreams : invalid instance ID");
+		return -1;
+	}
+
+	return 0;
+}
+
+syncGroup* sageBridge::addSyncGroup()
+{
+   if (!master)
+      return NULL;
+      
+   std::cout << "add sync group : sync node num " << shared->nodeNum << std::endl;
+      
+   syncGroup *sGroup = NULL;
+   
+   if (syncServerObj) {
+      sGroup = new syncGroup;
+      sGroup->init(0, SAGE_ASAP_SYNC_HARD, syncGroupID, MAX_FRAME_RATE, shared->nodeNum);
+      syncServerObj->addSyncGroup(sGroup);
+      sGroup->blockSync();
+      syncGroupID++;
+   }
+   else
+      sage::printLog("sageBridge::addSyncGroup : syncServerObj is NULL");
+      
+   return sGroup;   
+}
+
+int sageBridge::connectToFSManager(appInstance *inst)
+{
+   return connectToFSManager(inst, inst->fsIP, inst->fsPort);
+}
+
+int sageBridge::connectToFSManager(appInstance *inst, char *ip, int port)
+{
+   int fsID = msgInf->connect(ip, port);
+   int fsIdx = inst->fsList.size();
+   inst->fsList.push_back(fsID);
+   
+   char msgStr[TOKEN_LEN];
+   inst->fillAppInfo(msgStr);
+   
+   msgInf->msgToClient(fsID, 0, REG_APP, msgStr);
+   
+   return fsIdx;
+}
+
+appInstance* sageBridge::findAppInstance(int instID)
+{
+   //if (!appInstList[instID])
+      //sage::printLog("sageBridge : can't find app instance" );
+	int index;
+	return findApp(instID, index);
+         
+   //return appInstList[instID];
+}
+
+appInstance* sageBridge::clientIDtoAppInstance(int clientID, int &orgIdx)
+{
+   for (int i=0; i<instNum; i++) {
+      appInstance *inst = appInstList[i];
+      if (inst) {
+         int fsNum = inst->fsList.size();
+         for (int j=0; j<fsNum; j++) {
+            if (inst->fsList[j] == clientID) {
+               orgIdx = j;
+               return inst;   
+            }   
+         }
+               
+         if (inst->sailClient == clientID) {
+            return inst;         
+         }   
+      }
+   }
+   
+   return NULL;            
+}
+
+appInstance* sageBridge::forwardToAppinstance(sageMessage &msg, int clientID)
+{
+	appInstance* inst = NULL;
+	std::vector<appInstance*>::iterator iter;   
+   //for (int i=0; i<instNum; i++) {
+	for(iter = appInstList.begin(); iter != appInstList.end(); iter++) 
+	{
+		inst = (appInstance*) *iter;
+		if(!inst) continue;
+
+		int fsNum = inst->fsList.size();
+		for (int j=0; j<fsNum; j++) {
+			if (inst->fsList[j] == clientID) {
+				inst->parseMessage(msg, j);
+				msg.setDest(inst->instID);
+				msg.setAppCode(j);
+				return inst;
+			}   
+		}
+		if (inst->sailClient == clientID) {
+			inst->parseMessage(msg, 0);
+			msg.setDest(inst->instID);
+			msg.setAppCode(0);
+			return inst;
+      }   
+   }
+   
+   return NULL;
+}
+
+appInstance* sageBridge::delieverMessage(sageMessage &msg, int clientID)
+{
+   appInstance *inst = NULL;
+   
+   if (master)   {
+      inst = forwardToAppinstance(msg, clientID);
+      //if (!inst)
+      //   sage::printLog("sageBridge : can't forward to an app instance : %d", msg.getCode());
+
+      msgInf->distributeMessage(msg, slaveList, slaveNum);               
+   }
+   else {
+      int instID = msg.getDest();
+      //inst = findAppInstance(instID);
+		int index;
+      inst = findApp(instID, index);
+      int fsIdx = msg.getAppCode();
+      if (inst)
+         inst->parseMessage(msg, fsIdx);
+   }
+   
+   return inst;
+}
+
+int sageBridge::shareApp(char *msgData, int clientID) 
+{
+   if (master)   {
+      int fsPort;
+      char fsIP[SAGE_IP_LEN];
+      sscanf(msgData, "%s %d", fsIP, &fsPort);
+      //std::cout << "app share message : " << msgData << std::endl;
+
+      int orgIdx = 0;
+      appInstance *inst = clientIDtoAppInstance(clientID, orgIdx);
+      
+      if (!inst)
+         return -1;
+         
+      int newIdx = connectToFSManager(inst, fsIP, fsPort);
+      sage::printLog("sageBridge::%s() : connected to fsManager %s:%d", __FUNCTION__, fsIP, fsPort);
+      
+      syncGroup *sGroup = NULL;
+      if (inst->nodeNum > 1)
+         sGroup = addSyncGroup();
+      
+      int syncID = 0;
+      if (sGroup) {
+         syncID = sGroup->getSyncID();
+      }
+      
+      //sage::printLog("added sync group %d for app instance %d", syncID, inst->instID);
+      inst->addStreamer(newIdx, orgIdx, sGroup);
+      sage::printLog("sageBridge::%s() : new streamer added for %s:%d", __FUNCTION__, fsIP, fsPort);
+      
+      char msgStr[TOKEN_LEN];
+      sprintf(msgStr, "%d %d %d %d", inst->instID, orgIdx, newIdx, syncID);
+      msgInf->distributeMessage(SAGE_APP_SHARE, 0, msgStr, slaveList, slaveNum);
+      
+      //std::cout << "pt4" << std::endl;
+   }
+   else {
+      int instID, orgIdx, newIdx, syncID;
+      sscanf(msgData, "%d %d %d %d", &instID, &orgIdx, &newIdx, &syncID);
+		int index;
+      appInstance *inst = findApp(instID, index);
+      if (inst)
+         inst->addStreamer(newIdx, orgIdx, NULL, syncID);
+   }
+   
+   return 0;
+}
+
+int sageBridge::parseMessage(sageMessage &msg, int clientID)
+{
+   if (clientID >= 0){
+      char *msgData;
+      if (msg.getData())
+         msgData = (char *)msg.getData();
+      else
+         msgData = (char *)strdup("\0");
+            
+      sageToken tokenBuf(msgData);
+      char token[TOKEN_LEN];
+   
+      switch (msg.getCode()) {
+         case BRIDGE_REG_NODE : {
+            tokenBuf.getToken(token);
+            int slaveID = atoi(token);
+            // store client ID of a slave
+            slaveList[slaveID-1] = clientID;
+
+            char msgStr[TOKEN_LEN];
+            sprintf(msgStr, "%d %d %d %d %d %d %d %d %d %d", nwCfg->rcvBufSize, nwCfg->sendBufSize, 
+               nwCfg->mtuSize, (int)nwCfg->maxBandWidth, nwCfg->maxCheckInterval, nwCfg->flowWindow,
+               syncPort, streamPort, shared->nodeNum, shared->bufSize);
+            msgInf->msgToClient(clientID, 0, BRIDGE_SLAVE_INIT, msgStr);
+            break;
+         }
+         
+         case BRIDGE_SLAVE_INIT : {
+            initSlave(msgData);
+            break;
+         }
+         
+         case BRIDGE_APP_REG : {
+            regApp(msg, clientID);
+            break;
+         }
+         
+         case BRIDGE_SLAVE_READY : {
+            int instID = msg.getDest();
+				int index;
+            appInstance *inst = findApp(instID, index);
+   
+            if (inst) {
+               inst->waitNodes--;
+               // make sure if app instances are ready on all slaves
+               if (inst->waitNodes == 0) {
+                  inst->waitNodes = slaveNum;
+                  connectToFSManager(inst);
+               }   
+            }
+            else {   
+               sage::printLog("sageBridge::parseMessage : invalid instance ID");
+            }
+
+            break;
+         }
+            
+         case BRIDGE_SHUTDOWN : {
+            std::cout << "shuting down sage bridge...." << std::endl;
+            if (master)
+               msgInf->distributeMessage(msg, slaveList, slaveNum);
+            
+            shutdownAllApps();
+            shared->eventQueue->appendEvent(EVENT_BRIDGE_SHUTDOWN);
+            break;
+         }         
+      
+         case BRIDGE_SLAVE_PERF : {
+            int instID = msg.getDest();
+				int index;
+            appInstance *inst = findApp(instID, index);
+            if (inst)
+               inst->accumulateBandWidth(msgData);
+            break;
+         }
+         
+         case BRIDGE_APP_INST_READY : {
+            int instID = msg.getDest();
+			int index;
+            appInstance *inst = findApp(instID, index);
+   
+            if (inst) {
+               inst->waitNodes--;
+               // make sure if app instances are ready on all slaves
+               if (inst->waitNodes == 0) {
+                  connectApp(inst);
+                  sendStreamInfo(inst);
+                  inst->waitNodes = inst->nodeNum;
+                  if (inst->audioOn)
+                     audioBridge->startAudioStream(instID, inst->sailClient);
+               }
+            }
+            else {   
+               sage::printLog("sageBridge::parseMessage : invalid instance ID");
+            }
+
+            break;
+         }
+         
+         case SAGE_APP_SHARE : {   
+            shareApp(msgData, clientID);
+            break;
+         }
+         
+         case APP_QUIT : {
+            appInstance *inst = delieverMessage(msg, clientID);
+            if (inst) {
+               if (audioBridge && inst->audioOn) {
+                  int fsIdx;
+                  clientIDtoAppInstance(clientID, fsIdx);
+                  audioBridge->shutdownStreams(inst->instID, fsIdx);   
+               }
+               
+               shutdownApp(inst->instID, true);
+            }
+               
+            break;   
+         }
+         
+         case SAIL_CONNECT_TO_ARCV : {
+            int fsIdx;
+            appInstance *inst = clientIDtoAppInstance(clientID, fsIdx);
+            if (inst && audioBridge) {
+               audioBridge->duplicate(inst->instID, msgData, fsIdx);
+				}
+            break;
+         }
+         
+         case NOTIFY_APP_SHUTDOWN : {
+            appInstance *inst = delieverMessage(msg, clientID);
+            if (inst)
+               shutdownApp(inst->instID, false);
+            break;
+         }
+         
+         case CLEAR_APP_INSTANCE : {
+            int instID = msg.getDest();
+				int index;
+            appInstance *inst = findApp(instID, index);
+            appInstList[instID] = NULL;
+            if (inst)
+               delete inst;
+            std::cout << "app instance cleared at node " << shared->nodeID << std::endl;
+            break;
+         }   
+            
+         case SAIL_SEND_TIME_BLOCK : {
+            appInstance *inst = delieverMessage(msg, clientID);
+            if (inst)
+               msgInf->msgToClient(inst->sailClient, 0, SAIL_SEND_TIME_BLOCK);               
+            break;
+         }
+         
+         case SAIL_INIT_STREAM : {
+            delieverMessage(msg, clientID);
+            break;
+         }   
+         
+         default : {
+            appInstance *inst = delieverMessage(msg, clientID);
+            break;
+         }   
+      }
+      
+      // forward app events
+      if (APP_MESSAGE <= msg.getCode() && msg.getCode() < APP_MESSAGE+1000) {
+         appInstance *inst = delieverMessage(msg, clientID);
+         if (inst)
+            forwardToSail(inst->instID, msg);
+      }
+   }   
+   
+   msg.destroy();
+      
+   return 0;
+}
+
+int sageBridge::parseEvent(sageEvent *event)
+{   
+   if (!event) {
+      sage::printLog("sageBridge::parseEvent : event object is Null");
+      return -1;
+   }
+   
+   switch (event->eventType) {
+      case EVENT_NEW_CONNECTION : {
+         initStreams(event->eventMsg, (streamProtocol *)event->param);
+         break;
+      }
+      
+      case EVENT_NEW_MESSAGE : {
+         int clientID = atoi(event->eventMsg);
+         sageMessage *msg = (sageMessage *)event->param;
+         parseMessage(*msg, clientID);
+         delete msg;
+         break;
+      }
+      
+      case EVENT_APP_CONNECTED : {
+         int instID;
+         sscanf(event->eventMsg, "%d", &instID);
+
+         appInstance *inst = appInstList[instID];      
+
+         if (inst) {
+            if (master) {
+               inst->waitNodes--;
+               if (inst->waitNodes == 0) {
+                  connectToFSManager(inst);
+                  inst->waitNodes = slaveNum;
+               }   
+            }
+            else
+               msgInf->msgToServer(instID, BRIDGE_SLAVE_READY);
+         }      
+         break;
+      }
+      
+      case EVENT_SLAVE_PERF_INFO : {
+         int instID;
+         sscanf(event->eventMsg, "%d", &instID);
+         char *msgStr = sage::tokenSeek(event->eventMsg, 1);
+         msgInf->msgToServer(instID, BRIDGE_SLAVE_PERF, msgStr);
+         break;
+      }   
+      
+      case EVENT_MASTER_PERF_INFO : {
+         int fsClientID;
+         sscanf(event->eventMsg, "%d", &fsClientID);
+         char *msgStr = sage::tokenSeek(event->eventMsg, 1);
+         msgInf->msgToClient(fsClientID, 0, DISP_SAIL_PERF_RPT, msgStr);
+         //std::cout << "bridge perf " << msgStr << std::endl;
+         break;
+      }
+      
+      case EVENT_APP_SHUTDOWN : {
+         int fsClientID;
+         sscanf(event->eventMsg, "%d", &fsClientID);
+         msgInf->msgToClient(fsClientID, 0, NOTIFY_APP_SHUTDOWN);
+         break;
+      }
+      
+      case EVENT_BRIDGE_SHUTDOWN : {
+         bridgeEnd = true;
+         delete tcpObj;
+         delete udpObj;
+         if (syncServerObj)
+            delete syncServerObj;
+            
+         break;
+      }
+      
+      case EVENT_AUDIO_CONNECTION : {
+         if (audioBridge)
+            audioBridge->initStreams(event->eventMsg, (streamProtocol *)event->param);
+         break;
+      }
+   }
+
+   delete event;
+   
+   return 0;
+}
+
+void sageBridge::mainLoop()
+{
+   while(!bridgeEnd) {
+      sageEvent *newEvent = shared->eventQueue->getEvent();
+      //std::cout << "get the event " << newEvent->eventType << std::endl;
+      parseEvent(newEvent);
+   }
+}
+
+int main(int argc, char **argv)
+{
+#ifdef WIN32
+   sage::win32Init();
+#endif
+   sage::initUtil();
+   
+   sageBridge bridge(argc, argv);
+   bridge.mainLoop();
+   _exit(0);
+}   
Index: trunk/src/testing/src/sageBlockStreamer.cpp
===================================================================
--- trunk/src/testing/src/sageBlockStreamer.cpp	(revision 4)
+++ trunk/src/testing/src/sageBlockStreamer.cpp	(revision 4)
@@ -0,0 +1,411 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlockStreamer.cpp - straightforward pixel block streaming to displays
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageStreamer.h"
+#include "sageFrame.h"
+//#include "streamInfo.h"
+#include "sageBlockPartition.h"
+#include "sageBlockPool.h"
+
+// char hostname[SAGE_NAME_LEN];
+
+sageBlockStreamer::sageBlockStreamer(streamerConfig &conf, int pixSize) : compFactor(1.0), 
+   compX(1.0), compY(1.0), doubleBuf(NULL) 
+{
+   config = conf;
+   blockSize = config.blockSize;
+   bytesPerPixel = pixSize;
+
+   interval = 1000000.0/config.frameRate;
+  
+   //int memSize = (config.resX*config.resY*bytesPerPixel + BLOCK_HEADER_SIZE 
+   //   + sizeof(sageMemSegment)) * 4;
+   //memObj = new sageMemory(memSize);
+   
+   createDoubleBuffer();
+   
+   // sungwon exp
+   affinityFlag = false;
+   cpulist.clear();
+   if ( pthread_mutex_init(&affinityMutex, 0) != 0 ) {
+	   perror("pthread_mutex_init");
+   }
+   pthread_mutex_unlock(&affinityMutex);
+
+// gethostname(hostname, SAGE_NAME_LEN);
+}
+
+int sageBlockStreamer::createDoubleBuffer()
+{
+   if (doubleBuf) {
+      sage::printLog("sageStreamer::createDoubleBuffer : double buffer exist already");
+      return -1;
+   }
+   
+   // can create different type of pixel blocks
+   sagePixelData **pixelBuf = new sagePixelData*[2];
+   
+   if (config.pixFmt == PIXFMT_DXT) {
+      compX = 4.0;
+      compY = 4.0;
+      compFactor = 16.0;
+   }
+      
+   for (int i=0; i<2; i++) {
+      pixelBuf[i] = new sageBlockFrame(config.resX, config.resY, bytesPerPixel,  
+               compX, compY);
+      *pixelBuf[i] = config.imageMap;
+   }   
+   
+   doubleBuf = new sageDoubleBuf;
+   doubleBuf->init(pixelBuf);
+   
+   return 0;
+}
+
+void sageBlockStreamer::setNwConfig(sageNwConfig &nc) 
+{
+   nwCfg = nc;
+
+   if (config.protocol == SAGE_UDP && config.autoBlockSize) {
+      double payLoadSize = nwCfg.mtuSize - BLOCK_HEADER_SIZE;
+      double pixelNum = payLoadSize/bytesPerPixel*compFactor;
+
+      config.blockX = (int)floor(sqrt(pixelNum));
+      if ( (config.pixFmt == PIXFMT_DXT) || (config.pixFmt == PIXFMT_YUV) ) {
+         config.blockX = (config.blockX/4)*4;
+      }
+      
+      config.blockY = (int)floor(pixelNum/config.blockX);
+      if (config.pixFmt == PIXFMT_DXT) {
+         config.blockY = (config.blockY/4)*4;
+      }
+   }   
+
+   if ( config.swexp ) {
+	   partition = 0;
+   }
+   else {
+   partition = new sageBlockPartition(config.blockX, config.blockY, config.totalWidth, config.totalHeight);
+   
+   sageBlockFrame *buf = (sageBlockFrame *)doubleBuf->getBuffer(0);
+   buf->initFrame(partition);
+   buf = (sageBlockFrame *)doubleBuf->getBuffer(1);
+   buf->initFrame(partition);
+   blockSize = (int)ceil(config.blockX*config.blockY*bytesPerPixel/compFactor) + BLOCK_HEADER_SIZE;
+   partition->initBlockTable();
+   }
+	
+   nwCfg.blockSize = blockSize;
+   nwCfg.groupSize = config.groupSize;
+   nwCfg.maxBandWidth = (double)config.maxBandwidth/8.0; // bytes/micro-second
+   nwCfg.maxCheckInterval = config.maxCheckInterval;  // in micro-second
+   nwCfg.flowWindow = config.flowWindow;
+
+   if ( config.swexp )
+	   nbg = 0;
+   else
+	   nbg = new sageBlockGroup(blockSize, doubleBuf->bufSize(), GRP_MEM_ALLOC | GRP_CIRCULAR);
+}
+
+void sageBlockStreamer::setupBlockPool()
+{ 
+   nwObj->setupBlockPool(nbg); 
+}
+
+int sageBlockStreamer::sendPixelBlock(sagePixelBlock *block)
+{
+   if (!partition) {
+      sage::printLog("sageBlockStreamer::sendPixelBlock : block partition is not initialized");
+      return -1;
+   }
+      
+   pixelBlockMap *map = partition->getBlockMap(block->getID());
+   
+   if (!map) {
+      //std::cerr << "---" <<  hostname << " pBlock " << block->getID() << " out of screen" << std::endl;
+      nbg->pushBack(block);
+      return 0;   
+   }
+   
+   block->setRefCnt(map->count);
+      block->setFrameID(frameID);
+      block->updateBufferHeader();
+   
+   while(map) {
+      //std::cerr << "---" <<  hostname << " pBlock " << block->getBuffer() << "  sent to " <<
+      //   params[map->infoID].rcvID << std::endl;
+      
+      params[map->infoID].active = true;
+      int dataSize = nwObj->sendGrp(params[map->infoID].rcvID, block, configID);
+      if (dataSize > 0) {
+         totalBandWidth += dataSize;
+      }   
+      else if (dataSize < 0) {
+         sage::printLog("sageBlockStreamer::sendPixelBlock : fail to send pixel block");
+         return -1;
+      }   
+      map = map->next;
+   }   
+      
+   return 0;
+}
+
+int sageBlockStreamer::sendControlBlock(int flag, int cond)
+{
+   for (int j=0; j<rcvNodeNum; j++) {   
+      bool sendCond = false;
+      
+      switch(cond) {
+         case ALL_CONNECTION :
+            sendCond = true;
+            break;
+         case ACTIVE_CONNECTION :
+            sendCond = params[j].active;
+            break;
+         case INACTIVE_CONNECTION :
+            sendCond = !params[j].active;
+            break;         
+      }
+      
+      if (sendCond) {
+         int dataSize = nwObj->sendControl(params[j].rcvID, frameID, configID);
+         if (dataSize > 0)
+            totalBandWidth += dataSize;
+         else if (dataSize < 0) {
+            sage::printLog("sageBlockStreamer::sendControlBlock : fail to send control block");
+            return -1;
+         }
+      }
+   }   
+
+   return 0;
+}
+
+int sageBlockStreamer::streamPixelData(sageBlockFrame *buf)
+{
+   if (streamNum < 1) {
+      sage::printLog("sageBlockStreamer::streamPixelData : No Active Streams");
+      return -1;
+   }
+
+   bool flag = true;
+   buf->resetBlockIndex();
+
+   //std::cout << config.rank << " stream frame " << frameID << std::endl;
+
+   int cnt = 0;
+   while (flag) {
+      sagePixelBlock *pBlock = nbg->front();
+      nbg->next();
+      if (!pBlock) {
+         sage::printLog("sageBlockStreamer::streamPixelData : pixel block is NULL");
+         continue;
+      }   
+      flag = buf->extractPixelBlock(pBlock, config.rowOrd);
+
+      if (sendPixelBlock(pBlock) < 0)
+         return -1;
+   }
+
+   if (sendControlBlock(SAGE_UPDATE_BLOCK, ALL_CONNECTION) < 0)
+      return -1;
+
+   //std::cerr << hostname << " frame " << frameID << " transmitted" << std::endl;
+
+   frameID++;
+   frameCounter++;
+   //frameID = frameID + 10;
+
+	for (int j=0; j<rcvNodeNum; j++) {
+		int dataSize = nwObj->flush(params[j].rcvID, configID);
+      if (dataSize > 0) {
+         totalBandWidth += dataSize;
+      }   
+      else if (dataSize < 0) {
+         sage::printLog("sageBlockStreamer::streamPixelData : fail to send pixel block");
+         return -1;
+      }   
+	}
+   
+   return 0;
+}
+
+int sageBlockStreamer::streamLoop()
+{
+   while (streamerOn) {
+      //int syncFrame = 0;
+      //sage::printLog("\n========= wait for a frame ========\n");
+      sageBlockFrame *buf = (sageBlockFrame *)doubleBuf->getBackBuffer();
+      //sage::printLog("\n========= got a frame ==========\n");
+      
+      /* sungwon experimental */
+
+      if ( affinityFlag ) {
+#if ! defined (__APPLE__)
+    	  cpu_set_t cpuset;
+    	  CPU_ZERO(&cpuset);
+
+    	  pthread_mutex_lock(&affinityMutex);
+    	  std::list<int>::iterator it;
+    	  for ( it=cpulist.begin(); it!=cpulist.end(); it++) {
+    		  CPU_SET((*it), &cpuset);
+    	  }
+    	  affinityFlag = false; // reset flag
+    	  pthread_mutex_unlock(&affinityMutex);
+
+    	  if ( pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) != 0 ) {
+    		  perror("\n\npthread_setaffinity_np\n");
+    	  }
+
+    	  if ( pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) != 0 ) {
+    		  perror("pthread_getaffinity_np");
+    	  }
+    	  else {
+    		  fprintf(stderr,"SBS::%s() : current CPU affinity : ", __FUNCTION__);
+    		  for (int i=0; i<CPU_SETSIZE; i++) {
+    			  if (CPU_ISSET(i, &cpuset)) {
+    				  fprintf(stderr, "%d ", i);
+    			  }
+    		  }
+    		  fprintf(stderr,"\n");
+    	  }
+#endif
+      }
+
+      if ( config.swexp ) {
+    	  //buf->updateBufferHeader(frameID, config.resX, config.resY);
+    	  if ( nwObj->sendpixelonly(0, buf) <= 0 ) {
+    		  streamerOn = false;
+    	  }
+    	  else {
+    		  //fprintf(stderr, "sageBlockStreamer::%s() : frame %d sent \n", __FUNCTION__, frameID);
+    	  }
+    	  doubleBuf->releaseBackBuffer();
+    	  frameID++;
+    	  frameCounter++;
+    	  continue;
+      }
+
+      char *msgStr = NULL;
+      if (config.nodeNum > 1) {
+         config.syncClientObj->sendSlaveUpdate(frameID);
+         //sage::printLog("send update %d", config.rank);
+         config.syncClientObj->waitForSyncData(msgStr);
+         //sage::printLog("receive sync %d", config.rank);
+         if (msgStr) {
+            //std::cout << "reconfigure " << msgStr << std::endl;
+            reconfigureStreams(msgStr);
+            //firstConfiguration = false;
+         }   
+      }
+      else {
+         pthread_mutex_lock(reconfigMutex);
+         if (msgQueue.size() > 0) {
+            msgStr = msgQueue.front();
+            reconfigureStreams(msgStr);
+            //std::cout << "config ID : " << configID << std::endl;
+            msgQueue.pop_front();
+            firstConfiguration = false;
+         }
+         pthread_mutex_unlock(reconfigMutex);
+      }
+      
+      if (config.nodeNum == 1)
+         checkInterval();
+      
+      if (streamPixelData(buf) < 0) {
+         streamerOn = false;
+      }
+         
+      doubleBuf->releaseBackBuffer();
+      //std::cout << "pt1" << std::endl;
+   }   
+
+   // for quiting other processes waiting a sync signal
+   if (config.nodeNum > 1) {
+      config.syncClientObj->sendSlaveUpdate(frameID);
+   }
+   
+   sage::printLog("sageStreamer : network thread exit");
+   
+   return 0;
+}
+
+void sageBlockStreamer::shutdown()
+{ 
+   streamerOn = false; 
+   if (doubleBuf)
+      doubleBuf->releaseLocks();
+      
+   pthread_join(thId, NULL);
+}
+
+sageBlockStreamer::~sageBlockStreamer()
+{
+   if (doubleBuf)
+      delete doubleBuf;
+      
+   if (nwObj)
+      delete nwObj;
+
+   pthread_mutex_unlock(&affinityMutex);
+   pthread_mutex_destroy(&affinityMutex);
+}
+
+void sageBlockStreamer::setAffinity(const char *msgdata) {
+	pthread_mutex_lock(&affinityMutex);
+	cpulist.clear();
+
+	int len = 0;
+	sscanf(msgdata, "%d", &len);
+
+	char digit[2];
+	digit[1] = '\0';
+	for (int i=0; i<len; i++) {
+		if ( msgdata[3+i] == '1' ) {
+			fprintf(stderr,"SBS::setAffinity() : cpu %d is iset in the message\n", i);
+			cpulist.push_back(i);
+		}
+	}
+
+	affinityFlag = true; // set flag
+	pthread_mutex_unlock(&affinityMutex);
+}
Index: trunk/src/testing/src/sageUdpModule.cpp
===================================================================
--- trunk/src/testing/src/sageUdpModule.cpp	(revision 4)
+++ trunk/src/testing/src/sageUdpModule.cpp	(revision 4)
@@ -0,0 +1,1219 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  sageUdpModule.cpp
+ * Author   :   Byungil Jeong, Rajvikram Singh
+ * Description:   Code file for the UDP network stream of SAGE
+ * Notes   :   The class uses UDP/TCP sockets with the options optimized for graphics streaming
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************/
+
+#include "sageUdpModule.h"
+#include "sageBlock.h"
+#include "sageFrame.h"
+#include "sageBlockPool.h"
+
+#if defined(WIN32)
+#include <winsock2.h>
+#include <mswsock.h>
+#endif
+
+streamFlowData::streamFlowData(sageCircBuf *buf) : frameRate(60.0), configID(0), nextFrameSize(3072),
+      frameSize(3072), winIdx(-1), returnPlace(NULL), nextWindowTime(0.0), startTime(0.0),
+      totalSentSize(0), blockSize(0), active(true), closed(false), firstRound(true)
+{
+   blockBuf = buf;
+}   
+
+streamFlowData::~streamFlowData()
+{
+   if (blockBuf)
+      delete blockBuf;     
+}
+
+void streamFlowData::insertWindow(double sTime, int dataSize)
+{  
+   if (firstRound && winIdx+1 == FLOW_WINDOW_NUM)
+      firstRound = false;
+
+   winIdx = (winIdx+1)%FLOW_WINDOW_NUM;
+   streamWindow[winIdx].startTime = sTime;
+   startTime = sTime;
+   
+   double dataRate = frameRate*frameSize;
+   assert(dataRate > 0);
+   streamWindow[winIdx].windowInterval = dataSize/dataRate*1000000.0;
+   
+   int totalInterval = 0;
+   for (int i=0; i<FLOW_WINDOW_NUM; i++)
+      totalInterval += streamWindow[winIdx].windowInterval;
+   
+   int oldest = 0;
+   if (!firstRound)
+      oldest = (winIdx+1)%FLOW_WINDOW_NUM;
+   
+   nextWindowTime = streamWindow[oldest].startTime + totalInterval;
+}
+
+sageUdpModule::sageUdpModule() : closeFlag(false), notStarted(true), waitData(true)
+{
+#ifdef WIN32
+   // Initialize Winsock
+   WSADATA wsaData;
+   WSAStartup(MAKEWORD(2,2), &wsaData);
+#endif
+
+   protocol = SAGE_UDP;
+   pthread_mutex_init(&connectionLock, NULL);
+   pthread_mutex_unlock(&connectionLock);
+   pthread_cond_init(&streamStart, NULL);
+   pthread_cond_init(&newData, NULL);
+   
+}//End of sageUdp:sageUdp
+
+int sageUdpModule::init(sageStreamMode m, int p, sageNwConfig &c)
+{
+   streamProtocol::init(m, p, c);
+      
+   // create the actual network objects
+   switch(sMode)   {
+      case SAGE_RCV:
+      case SAGE_ARCV:
+      case SAGE_BRIDGE: {  // prepare a server socket
+         // create the sockets
+         if((serverSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
+            sage::printLog("sageUdpModule::init(): Creating TCP socket failed");
+            return -1;
+         }
+            
+         setSockOpts(serverSockFd, true);
+                  
+         struct sockaddr_in localAddr;
+         // bind to port
+         memset(&localAddr, 0, sizeof(localAddr));
+         localAddr.sin_family = AF_INET;
+         localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+         localAddr.sin_port = htons(rcvPort);
+
+         if (bind(serverSockFd, (struct sockaddr *)&localAddr, sizeof(struct sockaddr_in)) != 0) {
+            sage::printLog("sageUdpModule::init() : error in binding socket");
+            return -1;
+         }
+         
+         // put in listen mode      
+         ::listen(serverSockFd, 5);
+      
+         break;
+      }
+         
+      case SAGE_SEND: {
+         if (config.blockSize > 0 && config.groupSize > 0) {
+            if (pthread_create(&thId, 0, sendingThread, (void*)this) != 0) {
+               sage::printLog("sageUdpModule::init() : can't create sendingThread");
+            }
+         }
+         break;
+      }
+         
+      default:   
+         return -1;
+   
+   } //End of switch(opMode)
+      
+   return 0;
+}//End of sageUdpModule::init()
+
+void sageUdpModule::setupBlockPool(sageBlockPool *pool, int id)
+{
+   int flowNum = flowList.size()-1;
+   
+   if (id > flowNum) {
+      sage::printLog("sageUdpModule::setupBlockPool() : invalid receiver ID");
+      return;
+   }
+   else if (id == -1) {
+      for (int i=0; i<flowList.size(); i++)
+         flowList[i]->returnPlace = pool;
+   }
+   else
+      flowList[id]->returnPlace = pool;
+}
+
+void sageUdpModule::setFrameSize(int id, int size)
+{
+   int flowNum = flowList.size()-1;
+   
+   if (id < 0 || id > flowNum) {
+      sage::printLog("sageUdpModule::setFrameSize() : invalid receiver ID");
+      return;
+   }
+   
+   flowList[id]->nextFrameSize = size;
+}      
+
+void sageUdpModule::setFrameRate(double rate, int id)
+{
+   int flowNum = flowList.size()-1;
+   
+   if (id > flowNum) {
+      sage::printLog("sageUdpModule::setFrameRate() : invalid receiver ID");
+      return;
+   }
+   else if (id == -1) {
+      for (int i=0; i<flowList.size(); i++)
+         flowList[i]->frameRate = rate;
+   }
+   else
+      flowList[id]->frameRate = rate;
+}
+
+int sageUdpModule::checkConnections(char *msg, sageApiOption op)
+{
+   if(sMode == SAGE_SEND) {
+      sage::printLog("sageUdpModule::checkConnection() cannot be used for senders");
+      return -1;
+   }
+   
+   if (op & SAGE_NON_BLOCKING) 
+      if (!sage::isDataReady(serverSockFd)) {
+      return -1;
+   }
+         
+   //accept client connections
+   int addrLen;
+   struct sockaddr_in clientAddr;
+   addrLen = sizeof(clientAddr);
+   
+   int clientSockFd;
+   if((clientSockFd = ::accept(serverSockFd, (struct sockaddr *)&clientAddr, (socklen_t*)&addrLen)) == -1){
+      sage::printLog("sageUdpModule::checkConnections() - error in accepting control connection");
+      return -1;
+   }
+
+   sendList.push_back(clientSockFd);
+
+   // read registration message
+   int idx = sendList.size()-1;
+
+   char regMsg[REG_MSG_SIZE];
+   int retVal = sage::recv(clientSockFd, (void *)regMsg, REG_MSG_SIZE);
+   if (retVal == -1) {
+      return -1;
+   }
+   else if (retVal == 0) {
+      #ifdef WIN32   
+      closesocket(clientSockFd);
+      #else
+      shutdown(clientSockFd, SHUT_RDWR);
+      #endif
+
+      sendList[idx] = -1;
+      return -1;
+   }
+
+   if (msg) {
+      sprintf(msg, "%d %s", idx, regMsg);
+   }
+   else {
+      sage::printLog("sageUdpModule::checkConnections() : registraion message buffer is NULL");
+      return -1;
+   }
+   
+   // creating UDP socket
+   int udpSockFd;
+/*   
+   if((udpSockFd = ::accept(serverSockFd, (struct sockaddr *)&clientAddr, (socklen_t*)&addrLen)) == -1){
+      sage::printLog("sageUdpModule::checkConnections()");
+      return -1;
+   }
+*/
+
+   //std::cout << "sageUdpModule::checkConnections() : create UDP socket" << std::endl;
+   if ((udpSockFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+      sage::printLog("sageUdpModule::checkConnections(): Creating UDP socket failed");
+      return -1;
+   }
+
+   setSockOpts(udpSockFd, false);
+   
+   struct sockaddr_in udpLocalAddr;
+   memset(&udpLocalAddr, 0, sizeof(udpLocalAddr));
+   udpLocalAddr.sin_family = AF_INET;
+   udpLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   udpLocalAddr.sin_port = htons(rcvPort+10);
+
+   //std::cout << "sageUdpModule::checkConnections() : bind UDP socket" << std::endl;
+   if (bind(udpSockFd, (struct sockaddr *)&udpLocalAddr, sizeof(struct sockaddr_in)) != 0) {
+      sage::printLog("sageUdpModule::checkConnections() : Error binding UDP socket");
+      return -1;
+   }
+
+   socklen_t nameLen = sizeof(udpLocalAddr);
+   memset(&udpLocalAddr, 0, sizeof(udpLocalAddr));
+   if (getsockname(udpSockFd, (struct sockaddr *)&udpLocalAddr, &nameLen) != 0) {
+      sage::printLog("sageUdpModule::checkConnections() : Error getting the name of UDP socket");
+      return -1;
+   }
+
+   int udpPort = (int)ntohs(udpLocalAddr.sin_port);
+   char addrMsg[TOKEN_LEN];
+   sprintf(addrMsg, "%d", udpPort);
+   //std::cout << "sageUdpModule::checkConnections() : send UDP server port " << udpPort << std::endl;
+      
+   if (sage::send(clientSockFd, (void *)addrMsg, TOKEN_LEN) < 0) {
+      sage::printLog("sageUdpModule::checkConnections()");
+      return -1;
+   }
+   
+   if (sage::recv(clientSockFd, (void *)addrMsg, TOKEN_LEN) <= 0) {
+      sage::printLog("sageUdpModule::checkConnections()");
+      return -1;
+   }
+   
+   sscanf(addrMsg, "%d", &udpPort);
+   clientAddr.sin_port = htons(udpPort);
+   //std::cout << "sageUdpModule::checkConnections() : UDP client port is " << udpPort << std::endl;
+   
+   if (::connect(udpSockFd, (struct sockaddr *)&clientAddr, sizeof(struct sockaddr)) == -1) {
+      sage::printLog("sageUdpModule::checkConnections()");
+      return -1;
+   }
+   //std::cout << "sageUdpModule::checkConnections() : connected back to UDP client " << std::endl;
+      
+   udpSendList.push_back(udpSockFd);
+   if (idx != (udpSendList.size()-1)) {
+      std::cerr << "sageUdpModule::checkConnections() - Error : socket list index mismatch" <<
+         std::endl;
+      return -1;      
+   }
+   
+   return idx;
+}//End of sageUdpModule::listen()
+
+int sageUdpModule::connect(char *ip, char *msg)
+{
+   if(sMode == SAGE_RCV) {
+      std::cerr << "sageUdpModule::connect() cannot be used for receivers" << std::endl;
+      return -1;
+   }
+
+   // create the sockets
+   int clientSockFd;
+   if((clientSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1)   {
+      sage::printLog("sageUdpModule::connect(): Creating TCP socket failed");
+      return -1;
+   }
+   
+   setSockOpts(clientSockFd, true);
+
+   // connect to the server
+   struct sockaddr_in serverAddr;
+   memset(&serverAddr, 0, sizeof(serverAddr));
+   serverAddr.sin_family = AF_INET;
+   serverAddr.sin_addr.s_addr = inet_addr(ip);
+   serverAddr.sin_port = htons(rcvPort);
+
+   fprintf(stderr, "sageUdpModule::%s() : connecting to receiver %s::%d\n", __FUNCTION__, ip, rcvPort);
+   if(::connect(clientSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) {
+      sage::printLog("sageUdpModule::connect() : connect error");
+      return -1;
+   }
+      
+   rcvList.push_back(clientSockFd);
+   //sendAck.push_back(false);
+   
+   //std::cout << "UDP reg send" << std::endl;
+   
+   if (msg) {
+      if (sage::send(clientSockFd, msg, REG_MSG_SIZE) == -1) {
+         sage::printLog("sageUdpModule::connect() : send error");
+         return -1;
+      }   
+   }
+   
+   int idx = rcvList.size()-1;
+   
+   // creating UDP socket
+   int udpSockFd;
+
+/*   
+   if((udpSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1)   {
+      sage::printLog("sageUdpModule::connect(): Creating TCP socket failed");
+      return -1;
+   }
+   
+   setSockOpts(udpSockFd);
+
+
+   if(::connect(udpSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) {
+      sage::printLog("sageUdpModule::connect()");
+      return -1;
+   }
+*/
+   
+   //std::cout << "sageUdpModule::connect() : create UDP socket" << std::endl;   
+   if ((udpSockFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+      sage::printLog("sageUdpModule::connect(): Creating UDP socket failed");
+      return -1;
+   }
+   
+   setSockOpts(udpSockFd);
+   
+   struct sockaddr_in udpLocalAddr;
+   memset(&udpLocalAddr, 0, sizeof(udpLocalAddr));
+   udpLocalAddr.sin_family = AF_INET;
+   udpLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   udpLocalAddr.sin_port = htons(0);
+
+   //std::cout << "sageUdpModule::connect() : bind UDP socket" << std::endl;   
+   if (bind(udpSockFd, (struct sockaddr *)&udpLocalAddr, sizeof(struct sockaddr_in)) != 0) {
+      sage::printLog("sageUdpModule::connect() : Error binding UDP socket");
+      return -1;
+   }
+
+   socklen_t nameLen = sizeof(udpLocalAddr);
+   memset(&udpLocalAddr, 0, sizeof(udpLocalAddr));
+   if (getsockname(udpSockFd, (struct sockaddr *)&udpLocalAddr, &nameLen) != 0) {
+      sage::printLog("sageUdpModule::connect() : Error getting the name of UDP socket");
+      return -1;
+   }
+
+   int udpPort;
+   char addrMsg[TOKEN_LEN];
+   
+   std::cout << "sageUdpModule::connect() : waiting for receiver to send udp port number..." << std::endl;   
+   if (sage::recv(clientSockFd, (void *)addrMsg, TOKEN_LEN) < 0) {
+      sage::printLog("sageUdpModule::connect()");
+      return -1;
+   }
+      
+   sscanf(addrMsg, "%d", &udpPort);
+   std::cout << "sageUdpModule::connect() : receiver UDP port is " << udpPort << std::endl;
+   
+   serverAddr.sin_port = htons(udpPort);
+
+   if (::connect(udpSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) {
+      sage::printLog("sageUdpModule::connect() : connect with UDP error");
+      return -1;
+   }
+      
+   udpPort = (int)ntohs(udpLocalAddr.sin_port);
+   sprintf(addrMsg, "%d", udpPort);
+   std::cout << "sageUdpModule::connect() : send my UDP port number " << udpPort << std::endl;
+   
+   if (sage::send(clientSockFd, (void *)addrMsg, TOKEN_LEN) <= 0) {
+      sage::printLog("sageUdpModule::connect() - error in sending UDP port");
+      return -1;
+   }
+      
+   udpRcvList.push_back(udpSockFd);
+   if (idx != (udpRcvList.size()-1)) {
+      sage::printLog("sageUdpModule::connect() - socket list index mismatch");
+      return -1;      
+   }
+   
+   if (config.blockSize > 0 && config.groupSize > 0) {
+      sageCircBuf *buf = new sageCircBuf(config.sendBufSize/config.blockSize);
+      
+      streamFlowData *flowData = new streamFlowData(buf);
+      
+      pthread_mutex_lock(&connectionLock);
+      flowList.push_back(flowData);
+     
+      if (notStarted) {
+         pthread_cond_signal(&streamStart);
+         notStarted = false;
+      }
+         
+      pthread_mutex_unlock(&connectionLock);
+   }   
+	else {
+		sage::printLog("sageUdpModule::connect() : invalid block size or group size");
+		return -1;
+	}   
+   
+   std::cerr << "send buf " << config.sendBufSize << std::endl
+         << "mtu " << config.mtuSize << std::endl
+         << "blockSize " << config.blockSize << std::endl;
+   
+   return idx;
+}//End of sageUdpModule::connect()
+
+// send pixel block data packet by packet
+int sageUdpModule::send(int id, sagePixelBlock *spb)
+{
+   int totalSendSize = 0;
+   int blockDataSize = config.blockSize - BLOCK_HEADER_SIZE;
+   int packetDataSize = config.mtuSize - BLOCK_HEADER_SIZE;
+   int packetNum = ((blockDataSize-1)/packetDataSize + 1); 
+      
+   for (int pidx = 0; pidx < packetNum; pidx++) {
+      int sendSize;
+      int dataPt = packetDataSize*pidx;
+      int dataBufSize = MIN(blockDataSize - dataPt, packetDataSize);
+        
+      spb->updateHeader(pidx, spb->getConfigID());
+      
+//std::cerr << "frameID " << spb->getFrameID() << " blockID " << spb->getID() << " pid " << pidx << std::endl;
+            
+      #ifdef WIN32
+      WSABUF iovs[2];
+      iovs[0].buf = spb->getBuffer();
+      iovs[0].len = BLOCK_HEADER_SIZE;
+      iovs[1].buf = spb->getPixelBuffer() + dataPt;
+      iovs[1].len = dataBufSize;
+
+      DWORD WSAFlags = 0;
+      int udpSockFd = udpRcvList[id];
+      ::WSASend(udpSockFd, iovs, 2, (DWORD*)&sendSize, WSAFlags, NULL, NULL);
+      #else
+      struct iovec iovs[2];
+      iovs[0].iov_base = spb->getBuffer();
+      iovs[0].iov_len = BLOCK_HEADER_SIZE;
+      iovs[1].iov_base = spb->getPixelBuffer() + dataPt;
+      iovs[1].iov_len = dataBufSize;
+
+      struct msghdr blockMsgHdr;
+      bzero((void *)&blockMsgHdr, sizeof(blockMsgHdr));
+
+      blockMsgHdr.msg_iov = iovs;
+      blockMsgHdr.msg_iovlen = 2;
+
+      int udpSockFd = udpRcvList[id];
+         sendSize = ::sendmsg(udpSockFd, &blockMsgHdr, 0);
+      #endif
+
+      if (sendSize <= 0)
+         return -1;
+      else
+         if (sendSize < (BLOCK_HEADER_SIZE + dataBufSize))
+            sage::printLog("sageUdpModule::send() : a part of the message was not sent");
+
+      totalSendSize += sendSize;
+      if (spb->getFlag() == SAGE_UPDATE_BLOCK)
+         break;
+   }
+   
+   return totalSendSize;
+}
+
+int sageUdpModule::send(int id, sageBlock *sb, sageApiOption op)
+{
+	if (id < 0 || id > rcvList.size()-1) {
+		sage::printLog("sageUdpModule::send() : invalid receiver ID");
+		return -1;
+	}
+
+	if (!sb) {
+		sage::printLog("sageUdpModule::send() : null sage block");
+		return 1;
+	}
+
+	int dataSize;
+
+	if (op & SAGE_CONTROL) {
+		int clientSockFd = rcvList[id];
+		if (op & SAGE_BACKWARD)
+			clientSockFd = sendList[id];
+
+		if ((dataSize = sage::send(clientSockFd, sb->getBuffer(), BLOCK_HEADER_SIZE)) < 0)
+			return -1;
+	}
+	else {
+		//std::cout << "block size " << sb->getBufSize() << "bytes" << std::endl;
+
+		// send data using UDP channel
+		int udpSockFd = udpRcvList[id];
+		dataSize = sage::send(udpSockFd, sb->getBuffer(), sb->getBufSize());
+		if (dataSize < 0)
+			return -1;
+		//std::cout << dataSize << " bytes sent" << std::endl;
+	}
+
+	return dataSize;
+}//End of sageUdpModule::send()
+
+int sageUdpModule::sendpixelonly(int id, sageBlockFrame *sb) {
+	if (id < 0 || id > rcvList.size()-1) {
+		sage::printLog("sageUdpModule::%s() : invalid receiver ID %d", __FUNCTION__, id);
+		return -1;
+	}
+
+	if (!sb) {
+		sage::printLog("sageUdpModule::%s() : null sage block", __FUNCTION__);
+		return -1;
+	}
+
+	//std::cout << "block size " << sb->getBufSize() << std::endl;
+	// send data
+	int dataSize = sage::send(udpRcvList[id], sb->getPixelBuffer(), sb->getBufSize() - BLOCK_HEADER_SIZE);
+	if (dataSize < 0) {
+		return -1;
+	}
+
+	return dataSize;
+}
+
+int sageUdpModule::sendControl(int id, int frameID, int configID)
+{
+	if (id < 0 || id > rcvList.size()-1) {
+      sage::printLog("sageUdpModule::send() : invalid receiver ID");
+      return -1;
+   }
+
+   sagePixelBlock *cBlock = new sagePixelBlock(config.blockSize);
+   cBlock->setFlag(SAGE_UPDATE_BLOCK);
+	cBlock->setFrameID(frameID);
+   cBlock->setConfigID(configID);
+   cBlock->updateBufferHeader();
+
+   flowList[id]->blockBuf->pushBack((sageBufEntry)cBlock, true);
+   waitData = false;
+   pthread_cond_signal(&newData);
+   
+   return GROUP_HEADER_SIZE;
+}
+
+int sageUdpModule::sendGrp(int id, sagePixelBlock *sb, int configID)
+{
+   if (id < 0 || id > rcvList.size()-1) {
+      sage::printLog("sageUdpModule::send() : invalid receiver ID");
+      return -1;
+   }
+         
+   if (!sb) {
+      sage::printLog("sageUdpModule::send() : null sage block");
+      return 1;
+   }
+
+   sb->setConfigID(configID);
+   
+   flowList[id]->blockBuf->pushBack((sageBufEntry)sb, true);
+      waitData = false;
+      pthread_cond_signal(&newData);
+   
+   return sb->getBufSize();   
+}//End of sageUdpModule::sendGrp()
+
+int sageUdpModule::flush(int id, int configID)
+{
+      return 0;
+}//End of sageUdpModule::flush()
+
+int sageUdpModule::sendLoop()
+{
+   double maxPriority = 0;
+   double curTime = 0;
+   sageTimer flowTimer;
+   
+   pthread_mutex_lock(&connectionLock);
+   if (notStarted)
+      pthread_cond_wait(&streamStart, &connectionLock);
+   pthread_mutex_unlock(&connectionLock);
+   
+   while(!closeFlag) {
+      pthread_mutex_lock(&connectionLock);
+      int streamNum = flowList.size();
+      pthread_mutex_unlock(&connectionLock);
+      
+      maxPriority = 0;   
+      int selectedStream = -1;
+      
+      curTime = flowTimer.getTimeUS();
+      waitData = true;
+      
+      // select a stream to send      
+      for (int i=0; i<streamNum; i++) {
+         if (flowList[i]->active) {
+            if (flowList[i]->blockBuf->isEmpty())
+               continue;
+
+            double priority; 
+            if (curTime > 0)
+               priority = flowList[i]->elapsedTime(curTime)*flowList[i]->blockBuf->getEntryNum();
+            else
+               priority = flowList[i]->blockBuf->getEntryNum();   
+
+            if (maxPriority < priority) {
+               maxPriority = priority;
+               selectedStream = i;
+            }
+         }
+         else if (!flowList[i]->closed) {
+            while (!flowList[i]->blockBuf->isEmpty()) {
+               sagePixelBlock *pBlock = (sagePixelBlock *)flowList[i]->blockBuf->front(false);
+               flowList[i]->blockBuf->next();
+
+               if (pBlock) {
+                  if (pBlock->getFlag() == SAGE_PIXEL_BLOCK)
+                     flowList[i]->returnPlace->returnBlock(pBlock);
+                  else
+                     delete pBlock;
+            }
+            }
+            
+            flowList[i]->closed = true;
+            delete flowList[i]->blockBuf;
+         }   
+      }
+
+      //std::cout << "selected stream " << selectedStream << std::endl;
+      
+      if (selectedStream == -1) {
+         pthread_mutex_lock(&connectionLock);
+         while (waitData)
+            sage::condition_wait(&newData, &connectionLock, 10);
+         pthread_mutex_unlock(&connectionLock);
+      }
+      else {
+         curTime = flowTimer.getTimeUS();
+         unsigned sentDataSize = 0;
+         if (flowList[selectedStream]->pastTime(curTime) >= 0) {
+			   sagePixelBlock *block = (sagePixelBlock *)flowList[selectedStream]->blockBuf->front(false);
+         flowList[selectedStream]->blockBuf->next();
+         
+            while (block) {
+               if (block->getConfigID() > flowList[selectedStream]->configID) {
+                  flowList[selectedStream]->configID = block->getConfigID();
+                  flowList[selectedStream]->frameSize = flowList[selectedStream]->nextFrameSize;
+            }
+               
+               int sentSize = send(selectedStream, block);
+               if (block->getFlag() == SAGE_PIXEL_BLOCK)
+                  flowList[selectedStream]->returnPlace->returnBlock(block);
+            else
+                  delete block;
+               
+               if (sentSize > 0) {
+                  sentDataSize += sentSize;
+                  if (sentDataSize > config.sendBufSize/config.flowWindow)
+                     break;
+         }
+         else
+                  flowList[selectedStream]->active = false;
+      
+               block = (sagePixelBlock*)flowList[selectedStream]->blockBuf->front(false);
+               flowList[selectedStream]->blockBuf->next();
+            }
+            flowList[selectedStream]->insertWindow(curTime, sentDataSize);
+         }
+      }
+   }
+   
+   return 0;
+}
+
+void* sageUdpModule::sendingThread(void *args)
+{
+   sageUdpModule *This = (sageUdpModule *)args;
+   This->sendLoop();
+      
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageUdpModule::recv(int id, sageBlock *sb, sageApiOption op)
+{
+   if (id < 0 || id > sendList.size()-1) {
+      sage::printLog("sageUdpModule::recv() : invalid sender ID");
+      return -1;
+   }
+   
+   int udpSockFd = udpSendList[id];
+   
+   if (op & SAGE_NON_BLOCKING) {
+      if (!sage::isDataReady(udpSockFd)) {
+         return 0;
+      }
+   }   
+      
+   char *bufP = sb->getBuffer();
+   if (!bufP) {
+      sage::printLog("sageUdpModule::recv - block buffer is null");
+      return -1;
+   }
+   
+   int retVal = sage::recv(udpSockFd, (void *)bufP, sb->getBufSize());
+
+   if (retVal < 0) {
+      return -1;
+   }
+   else if (retVal == 0) {
+      #ifdef WIN32   
+      closesocket(sendList[id]);
+      #else
+      shutdown(sendList[id], SHUT_RDWR);
+      #endif
+      sendList[id] = -1;
+      return -1;
+   }
+
+   sb->updateBlockConfig();
+   
+   return retVal;
+}//End of sageUdpModule::recv()
+
+int sageUdpModule::recv(int id, sagePixelBlock *spb, int pidx)
+{
+   int blockDataSize = spb->getBufSize() - BLOCK_HEADER_SIZE;
+   int packetDataSize = config.mtuSize - BLOCK_HEADER_SIZE;
+   int dataPt = packetDataSize*pidx;
+   int dataBufSize = MIN(blockDataSize - dataPt, packetDataSize);
+   
+//std::cerr << "block " << spb->getBufSize() << " mtu " << config.mtuSize << " pid " << pidx << std::endl;   
+   
+   char dummy[BLOCK_HEADER_SIZE];
+   char *packetHeader;
+   if (spb->isDirty())
+      packetHeader = dummy;
+   else
+      packetHeader = spb->getBuffer();
+   
+   int recvSize = 0;;   
+   int udpSockFd = udpSendList[id];
+   
+//std::cerr << "data buf size " << dataBufSize << std::endl;   
+   
+#if defined(WIN32)
+   WSABUF iovs[2];
+   iovs[0].buf = packetHeader;
+   iovs[0].len = BLOCK_HEADER_SIZE;
+   iovs[1].buf = spb->getPixelBuffer() + dataPt;
+   iovs[1].len = dataBufSize;
+
+   DWORD WSAFlags = 0;
+   //::WSARead(udpSockFd, iovs, 2, (DWORD*)&recvSize, WSAFlags, NULL, NULL);
+   WSARecv(udpSockFd, iovs, 2, (DWORD*)&recvSize, &WSAFlags, NULL, NULL);
+#else
+   struct iovec iovs[2];
+   iovs[0].iov_base = packetHeader;
+   iovs[0].iov_len = BLOCK_HEADER_SIZE;
+   iovs[1].iov_base = spb->getPixelBuffer() + dataPt;
+   iovs[1].iov_len = dataBufSize;
+
+   struct msghdr blockMsgHdr;
+   bzero((void *)&blockMsgHdr, sizeof(blockMsgHdr));
+
+   blockMsgHdr.msg_iov = iovs;
+   blockMsgHdr.msg_iovlen = 2;
+
+   recvSize = ::recvmsg(udpSockFd, &blockMsgHdr, MSG_WAITALL);
+//std::cerr << "msg read size " << recvSize << std::endl;   
+#endif
+   
+   if (recvSize < 0) {
+      perror("sageUdpModule::recv :"); 
+   }   
+   
+   if (recvSize > 0 && recvSize < (BLOCK_HEADER_SIZE + dataBufSize))
+      sage::printLog("sageUdpModule::recv - message size error");
+      
+   return recvSize;   
+}
+
+int sageUdpModule::skipBlock(int id, int pidx)
+{
+   int blockDataSize = config.blockSize - BLOCK_HEADER_SIZE;
+   int packetDataSize = config.mtuSize - BLOCK_HEADER_SIZE;
+   int dataPt = packetDataSize*pidx;
+   int dataBufSize = MIN(blockDataSize - dataPt, packetDataSize);
+   int udpSockFd = udpSendList[id];
+   int recvSize;
+
+   //char dummy[config.blockSize];
+   char dummy[BLOCK_HEADER_SIZE];
+
+#if defined(WIN32)
+   WSABUF iovs[2];
+   iovs[0].buf = dummy;
+   iovs[0].len = BLOCK_HEADER_SIZE;
+   iovs[1].buf = dummy + BLOCK_HEADER_SIZE;
+   iovs[1].len = dataBufSize;
+
+   DWORD WSAFlags = 0;
+   //::WSARead(udpSockFd, iovs, 2, (DWORD*)&recvSize, WSAFlags, NULL, NULL);
+   WSARecv(udpSockFd, iovs, 2, (DWORD*)&recvSize, &WSAFlags, NULL, NULL);
+#else
+   struct iovec iovs[2];
+   iovs[0].iov_base = dummy;
+   iovs[0].iov_len = BLOCK_HEADER_SIZE;
+   iovs[1].iov_base = dummy + BLOCK_HEADER_SIZE;
+   iovs[1].iov_len = dataBufSize;
+
+   struct msghdr blockMsgHdr;
+   bzero((void *)&blockMsgHdr, sizeof(blockMsgHdr));
+
+   blockMsgHdr.msg_iov = iovs;
+   blockMsgHdr.msg_iovlen = 2;
+
+   recvSize = ::recvmsg(udpSockFd, &blockMsgHdr, MSG_WAITALL);
+#endif
+   
+   
+   if (recvSize < 0) {
+      perror("sageUdpModule::recv :"); 
+   }   
+   
+   if (recvSize > 0 && recvSize < (BLOCK_HEADER_SIZE + dataBufSize))
+      sage::printLog("sageUdpModule::skipBlock - message size error");
+      
+   return recvSize;   
+}
+
+int sageUdpModule::recvGrp(int id, sageBlockGroup *sbg)
+{
+   if (id < 0 || id > sendList.size()-1) {
+      sage::printLog("sageUdpModule::recv() : invalid sender ID");
+      return -1;
+   }
+   
+   int udpSockFd = udpSendList[id];
+   
+   if (udpSockFd < 0) {
+      sage::printLog("sageUdpModule::recvGrp : the socket is closed");
+      return -1;
+   }      
+      
+   if (!sbg) {
+      sage::printLog("sageUdpModule::recvGrp - block group ptr is null");
+      return -1;
+   }
+   
+   int curFrame = sbg->getFrameID();
+   int blockIdx = 0, maxBlockID = -1, grpConfigID = -1;
+   int totalReadSize = 0;
+   sbg->clearBlocks();
+   bool firstRead = true;
+   
+   while (blockIdx <sbg->size()) {
+      int flag, frameID, blockID, packetID, configID;
+      char header[BLOCK_HEADER_SIZE];
+      memset(header,0, BLOCK_HEADER_SIZE);
+      int headerSize = -1;
+      while (headerSize < 0) {
+         headerSize = sage::recv(udpSockFd, (void *)header, BLOCK_HEADER_SIZE, MSG_PEEK);
+      }
+      
+      if (headerSize == 0) {
+         #ifdef WIN32   
+         closesocket(sendList[id]);
+         #else
+         shutdown(sendList[id], SHUT_RDWR);
+         #endif
+         sendList[id] = -1;
+
+         sage::printLog("sageUdpModule::recvGrp : shutdown connection");
+      return -1;
+   }
+      
+//std::cerr << "header " << header << std::endl;
+      char *msgStr = sage::tokenSeek(header, 1);
+
+//std::cerr << "msg1 " << msgStr << std::endl;
+      sscanf(msgStr, "%d", &flag);
+      msgStr = sage::tokenSeek(header, 6);
+
+//std::cerr << "msg2 " << msgStr << std::endl;
+      sscanf(msgStr, "%d %d %d %d", &frameID, &blockID, &packetID, &configID);
+      
+//std::cerr << "packet header " << frameID << " " << blockID << " " << packetID << " " << configID
+//      << std::endl;
+
+//std::cerr << "cur frame " << curFrame << std::endl;
+      
+      sagePixelBlock *curBlock = (*sbg)[blockIdx];
+      bool nextBlock = false;
+      
+      if (frameID < curFrame) {
+         int readSize = -1; 
+         
+         while (readSize < 0) {
+            readSize = skipBlock(id, packetID);
+         }
+         
+         if (readSize == 0) {
+      #ifdef WIN32   
+      closesocket(sendList[id]);
+      #else
+      shutdown(sendList[id], SHUT_RDWR);
+      #endif
+      sendList[id] = -1;
+            
+            sage::printLog("sageUdpModule::recvGrp : shutdown connection");
+      return -1;
+   }
+
+         totalReadSize += readSize;
+         curBlock = NULL;
+      }
+      else if (!firstRead && (frameID > curFrame || flag == SAGE_UPDATE_BLOCK)) {
+         blockIdx++;  // for counting block number
+         break;
+      }   
+      else if (frameID > curFrame)
+         curFrame = frameID;
+   
+      if (curBlock && curBlock->isDirty()) {
+         if (curBlock->getID() != blockID) {
+            if (blockID > maxBlockID)
+               nextBlock = true;
+            else {
+               for (int i=blockIdx-1; i>=0; i--) {
+                  if ((*sbg)[i]->getID() == blockID) {
+                     curBlock = (*sbg)[i];
+                     break;
+                  }   
+               }
+               
+               if (curBlock->getID() != blockID)
+                  nextBlock = true;
+            }
+         }
+      }
+      
+      if (nextBlock) {  
+         blockIdx++;
+         if (blockIdx < sbg->size())
+            curBlock = (*sbg)[blockIdx];
+         else 
+            curBlock = NULL;     
+      }
+      
+      if (curBlock) {     
+         int readSize = -1;
+         while (readSize < 0) {
+            readSize = recv(id, curBlock, packetID);
+         }
+         
+         if (readSize == 0) {
+            #ifdef WIN32   
+            closesocket(sendList[id]);
+            #else
+            shutdown(sendList[id], SHUT_RDWR);
+            #endif
+            sendList[id] = -1;
+            
+            sage::printLog("sageUdpModule::recvGrp : shutdown connection");
+            return -1;
+         }
+         
+         totalReadSize += readSize;
+         curBlock->setID(blockID);
+         curBlock->setDirty();
+         firstRead = false;
+         
+         if (grpConfigID < 0) {
+            grpConfigID = configID;
+         }
+         else {
+            assert(grpConfigID == configID);
+         }   
+      }
+      
+      if (flag == SAGE_UPDATE_BLOCK) {
+         break;
+      }
+   }
+   
+//std::cerr << "group config " << blockIdx << " " << curFrame << " " << grpConfigID << std::endl;
+
+   sbg->updateConfig(blockIdx, curFrame, grpConfigID); 
+   
+//std::cerr << "read size " << totalReadSize << std::endl;
+   
+   return totalReadSize;
+}//End of sageUdpModule::recvGrp()
+
+int sageUdpModule::close(int id, int mode)
+{
+   if (mode == -1)
+      mode = sMode;
+      
+   streamProtocol::close(id, mode);
+   
+   if (mode == SAGE_RCV || mode == SAGE_ARCV) {
+      if (udpSendList[id] >= 0) {
+      #ifdef WIN32   
+         closesocket(udpSendList[id]);
+      #else
+         shutdown(udpSendList[id], SHUT_RDWR);
+      #endif
+      }
+   }
+   
+   if (mode == SAGE_SEND) {
+      if (config.groupSize > 0 && flowList[id])
+         flowList[id]->active = false;
+       
+      if (udpRcvList[id] >= 0) {
+      #ifdef WIN32   
+         closesocket(udpRcvList[id]);
+      #else
+         shutdown(udpRcvList[id], SHUT_RDWR);
+      #endif
+      }
+   }
+   
+   return 0;
+}
+
+int sageUdpModule::close()
+{
+   closeFlag = true;
+   
+   int rcvNum = rcvList.size();
+   int sendNum = sendList.size();
+   
+   if (sMode != SAGE_SEND) {
+#ifdef WIN32   
+      closesocket(serverSockFd);
+#else
+      shutdown(serverSockFd, SHUT_RDWR);
+#endif
+
+      for (int i=0; i<sendNum; i++) {
+         if (sendList[i] < 0)
+            continue;
+#ifdef WIN32   
+         closesocket(sendList[i]);
+         closesocket(udpSendList[i]);
+#else
+         shutdown(sendList[i], SHUT_RDWR);
+         shutdown(udpSendList[i], SHUT_RDWR);
+#endif
+      }
+   }
+   
+   if (sMode != SAGE_RCV && sMode != SAGE_ARCV) {
+      for (int i=0; i<rcvNum; i++) {
+#ifdef WIN32   
+         closesocket(rcvList[i]);
+         closesocket(udpRcvList[i]);
+#else
+         shutdown(rcvList[i], SHUT_RDWR);
+         shutdown(udpRcvList[i], SHUT_RDWR);
+#endif
+      }
+   }
+   
+   return 0;
+}
+
+bool sageUdpModule::setSockOpts(int fd, bool noDelay)
+{
+   int optVal, optLen;
+
+#if defined(WIN32) || defined(__APPLE__) || defined(__sun)
+   
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1;
+   optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+   {
+      std::cerr << "\nsageUdpModule::setSockOpts(): Error setting SO_REUSEADDR" <<  std::endl;
+      return false;
+   }
+
+   optVal= config.sendBufSize, optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&optVal, optLen) !=0)
+   {
+      std::cerr << "sageUdpModule::setSockOpts(): Error setting SO_SNDBUF to " << optVal << " bytes";
+      return false;
+   }
+
+   optVal= config.rcvBufSize; optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&optVal, optLen) !=0)
+   {
+      std::cerr << "sageUdpModule::setSockOpts(): Error setting SO_RCVBUF to " << optVal << " bytes";
+      return false;
+   }
+   
+   if (noDelay) {
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+         std::cerr << "sageUdpModule::setSockOpts(): Error switching off Nagle's algorithm." << std::endl;
+   }
+#else
+   int reuseFlag = 1;
+   optLen = sizeof(reuseFlag);
+   if (setsockopt(fd, SOL_SOCKET,SO_REUSEADDR, (char *) &reuseFlag, optLen) < 0)
+   {
+      std::cerr << "sageUdpModule::SetSockOpts(): Cannot set SO_REUSEADDR on socket" << std::endl;
+      return false;
+   }
+   
+std::cerr << "sendBufSize " << config.sendBufSize << std::endl;   
+   optVal= config.sendBufSize;   
+   optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&optVal, (socklen_t)optLen) != 0)
+   {
+      std::cerr << "sageUdpModule::SetSockOpts(): Error setting SO_SNDBUF to " << config.sendBufSize << " bytes" << std::endl;
+      return false;
+   }
+
+std::cerr << "rcvBufSize " << config.rcvBufSize << std::endl;   
+   optVal= config.rcvBufSize; optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&optVal, (socklen_t)optLen) != 0)
+   {
+      std::cerr << "sageUdpModule::SetSockOpts(): Error setting SO_SNDBUF to " << config.rcvBufSize << " bytes" << std::endl;
+      return false;
+   }
+
+   if (noDelay) {
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+         std::cerr << "sageUdpModule::setSockOpts(): Error switching off Nagle's algorithm." << std::endl;
+   }   
+#endif
+
+   return true;
+} //End of sageUdpModule::setSockOpts()
+
+sageUdpModule::~sageUdpModule()
+{
+   close();
+
+   for (int i=0; i<flowList.size(); i++) {
+      streamFlowData *fData = flowList[i];
+      if (fData)
+         delete fData;
+   }
+
+   flowList.clear();   
+
+   pthread_join(thId, NULL);
+}
Index: trunk/src/testing/src/sageAudio.cpp
===================================================================
--- trunk/src/testing/src/sageAudio.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudio.cpp	(revision 4)
@@ -0,0 +1,904 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  sageAudio.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for audio capture and play
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "sageAudio.h" 
+#include "sageAudioModule.h"
+
+sageAudio::sageAudio()
+: audioStream(NULL), audioParameters(NULL), audioMode(SAGE_AUDIO_CAPTURE), deviceNum(-1),
+   sampleFmt(SAGE_SAMPLE_FLOAT32), samplingRate(44100), channels(2), framePerBuffer(1024),
+   playFlag(AUDIO_STOP), buffer(NULL), minLatency(1000), maxLatency(0), ID(-1)
+{   
+}
+
+sageAudio::~sageAudio()
+{
+   closeStream();
+   
+   if( audioParameters != NULL) {
+      delete audioParameters;
+      audioParameters = NULL;
+   }
+}
+
+int sageAudio::init(int id, sageAudioConfig &config, sageAudioMode mode, sageAudioCircBuf *buf)
+{
+   ID = id;
+   
+   // initialize audio setting variables
+   sampleFmt = config.sampleFmt;
+   samplingRate = config.samplingRate;
+   channels = config.channels;
+   framePerBuffer = config.framePerBuffer;
+   deviceNum = config.deviceNum;
+   
+   std::cout << "sageAudio:: samplingRate: " <<  samplingRate << " channels: " << channels << " framePerBuffer: " << framePerBuffer << std::endl;
+   std::cout << "sageAudio:: sampleFmt: ";
+      
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         std::cout << "SAGE_SAMPLE_FLOAT32" ;
+         break;
+      case SAGE_SAMPLE_INT16 : 
+         bytesPerSample = sizeof(short);
+         std::cout << "SAGE_SAMPLE_INT16" ;
+         break;
+      case SAGE_SAMPLE_INT8 : 
+         bytesPerSample = sizeof(char);
+         std::cout << "SAGE_SAMPLE_INT8" ;
+         break;      
+      case SAGE_SAMPLE_UINT8 : 
+         bytesPerSample = sizeof(unsigned char);
+         std::cout << "SAGE_SAMPLE_UINT8" ;
+         break;         
+      default :
+         bytesPerSample = sizeof(float);
+         sampleFmt = SAGE_SAMPLE_FLOAT32;
+         break;
+   } 
+
+   audioMode = mode;
+   buffer = buf;
+
+   std::cout << " mode: ";
+    
+   if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+   
+#ifdef linux1      
+      handle = raw1394_new_handle_on_port (0);
+      if(!handle)
+      {
+         std::cout << "sageAudio::init: failed to get libraw1394 handle" << std::endl;
+         return -1;
+      }
+      // to capture
+      // All audio data must be signed 16bit 44.1KHz stereo PCM
+      sampleFmt = SAGE_SAMPLE_UINT8;
+      samplingRate = 44100;
+      channels = 2;
+#endif      
+      
+      std::cout << "SAGE_AUDIO_FWCAPTURE" << std::endl;   
+   } 
+   else {
+      // set audio parameters
+      audioParameters = new PaStreamParameters();
+      switch(audioMode) {
+         case SAGE_AUDIO_CAPTURE :
+         /** todo */
+            // device id...........
+            audioParameters->device =  Pa_GetDefaultInputDevice();
+            std::cout << "SAGE_AUDIO_CAPTURE" ;
+            break;
+         case SAGE_AUDIO_PLAY :
+            if(deviceNum == -1) 
+            {
+               audioParameters->device = Pa_GetDefaultOutputDevice();
+            } else 
+            {
+               audioParameters->device =  deviceNum;
+            }
+            std::cout << "SAGE_AUDIO_PLAY : " << audioParameters->device  ;
+            break;
+         default :
+            break;
+      }
+      std::cout << std::endl;
+      if(audioParameters->device < 0) {
+         std::cerr << "sageAudio::init: could not find default device" << std::endl;
+         return -1;
+      }
+         
+      audioParameters->channelCount = channels;
+      switch(sampleFmt)
+      {
+         case SAGE_SAMPLE_FLOAT32 :
+            audioParameters->sampleFormat = paFloat32;
+            break;
+         case SAGE_SAMPLE_INT16 : 
+            audioParameters->sampleFormat = paInt16;
+            break;
+         case SAGE_SAMPLE_INT8 : 
+            audioParameters->sampleFormat = paInt8;
+            break;      
+         case SAGE_SAMPLE_UINT8 : 
+            audioParameters->sampleFormat = paUInt8;
+            break;         
+         default :
+            break;   
+      }
+      audioParameters->suggestedLatency = Pa_GetDeviceInfo( audioParameters->device )->defaultLowOutputLatency;
+      audioParameters->hostApiSpecificStreamInfo = NULL;
+   }
+   //std::cout << "sageAudio::init: initialized" << std::endl;
+   
+   return 0;
+}
+
+int sageAudio::reset( int id, sageAudioCircBuf *buf )
+{
+   ID = id;
+   buffer = buf;
+   std::cout << "sageAudio::reset " << ID << std::endl;
+   return 0;
+}
+
+int   sageAudio::openStream()
+{
+   if( buffer == NULL ) {
+      std::cerr << "audio stream could not open because buffer is NULL" << std::endl;
+      return -1;
+   }
+   
+   if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+
+#ifdef linux1
+      /*amdtp = iec61883_amdtp_recv_init (handle, sageAudio::recordFWCallback, (void *)this );
+      if( amdtp == NULL)
+      {
+         std::cerr << "audio firewire stream could not be initiated" << std::endl;
+         return -1;
+      }*/
+#endif
+
+   }
+   else {
+   
+      PaError err;
+      if( audioStream != NULL ) {
+         std::cerr << "audio stream is already opened" << std::endl;
+         return -1;   
+      }
+      
+      if( audioMode == SAGE_AUDIO_CAPTURE )
+      {
+         err = Pa_OpenStream(
+               &audioStream,
+               audioParameters,
+               NULL,                  // no outputParameters
+               samplingRate,
+               framePerBuffer,
+               paClipOff,         // we won't output out of range samples so don't bother clipping them  
+               sageAudio::recordCallback,
+               this );
+
+         if( err != paNoError ) {
+            std::cerr << "audio stream could not open" << std::endl;
+            return err;
+         }
+
+      } else if ( audioMode == SAGE_AUDIO_PLAY )
+      {
+         err = Pa_OpenStream(
+            &audioStream,
+            NULL,                  // no inputParameters 
+            audioParameters,
+            samplingRate,
+            framePerBuffer,
+            paClipOff,            // we won't output out of range samples so don't bother clipping them 
+            sageAudio::playCallback,
+            this );
+
+         if( err != paNoError ) {
+            std::cerr << "audio stream could not open" << std::endl;
+            return err;      
+         }
+         std::cout << "audio stream is opened" << std::endl;
+      }
+      /** todo */
+      //startTime = Pa_GetStreamTime( audioStream );
+   }
+
+   return 0;
+}
+
+int   sageAudio::closeStream()
+{
+   if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+
+#ifdef linux1
+      iec61883_amdtp_close (amdtp);
+#endif
+   
+   }
+   else {
+      if(audioStream == NULL) {
+         return -1;
+      }
+      
+      buffer = NULL;
+      PaError err;
+      err = Pa_CloseStream( audioStream );
+      if( err != paNoError ) {
+         std::cerr << "audio stream could not close" << std::endl;
+         return err;
+      }
+	  std::cerr << "audio stream is closed" << std::endl;
+      audioStream = NULL;
+   }
+
+   return 0;
+}
+
+#ifdef linux1
+void* sageAudio::audioThread(void *args)
+{
+   sageAudio* This = (sageAudio*) args;
+
+   This->amdtp = iec61883_amdtp_recv_init (This->handle, recordFWCallback, (void *)This );
+   if( !This->amdtp )
+   {
+      std::cerr << "audio firewire stream could not be initiated" << std::endl;
+      return NULL;
+   }
+   if( iec61883_amdtp_recv_start (This->amdtp, 63) < 0 )
+   {
+      std::cerr << "audio firewire stream could not be started" << std::endl;
+      return NULL;
+   }
+
+   int fd = raw1394_get_fd(This->handle);
+   struct timeval tv;
+   fd_set rfds;
+   int result = 0;
+      
+   std::cerr << "sageAudio::audioThread:: starting to receive : fd: " << fd << std::endl;
+
+   do {
+      FD_ZERO (&rfds);
+      FD_SET (fd, &rfds);
+      tv.tv_sec = 0;
+      tv.tv_usec = 20000;
+         
+      if (select (fd + 1, &rfds, NULL, NULL, &tv) > 0) {
+         if(FD_ISSET(fd, &rfds)) {
+            result = raw1394_loop_iterate (This->handle);
+            //std::cerr << "sageAudio::audioThread:: 1394 loop : " << result << std::endl;
+         }
+      }
+      
+   } while ((This->playFlag != AUDIO_STOP) && (result == 0));
+       
+   std::cerr << "sageAudio::audioThread:: done" << std::endl;
+
+}
+#endif
+ 
+/** todo */
+// more ......
+int sageAudio::play()
+{
+   if(playFlag != AUDIO_PLAY) 
+   {   
+      if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+
+#ifdef linux1
+         /*if( iec61883_amdtp_recv_start (amdtp, 63) < 0 )
+         {
+            std::cerr << "audio firewire stream could not be started" << std::endl;
+            return -1;
+         }*/
+         pthread_t thId;
+         if (pthread_create(&thId, 0, audioThread, (void*)this) != 0) {
+            std::cerr << "sageAudio::play : can't create audioThread" << std::endl;
+               return -1;
+         }
+#endif
+
+      }
+      else {
+         PaError err;   
+         err = Pa_StartStream( audioStream );
+         if( err != paNoError ) {
+            std::cerr << "audio stream could not open" << std::endl;
+            return err;   
+         }
+      }
+   }
+   playFlag = AUDIO_PLAY;      
+   return 0;
+}
+
+int sageAudio::pause()
+{
+   if(playFlag == AUDIO_PLAY) 
+   {
+      if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+
+#ifdef linux1
+         iec61883_amdtp_recv_stop (amdtp);
+#endif
+
+      }
+      else {
+         PaError err;
+         err = Pa_StopStream( audioStream );
+         if( err != paNoError ) {
+            std::cerr << "audio stream could not stop" << std::endl;
+            return err;
+         }
+      }
+   } 
+   
+   playFlag = AUDIO_PAUSE;      
+   return 0;
+}
+
+int sageAudio::stop()
+{
+   if(playFlag == AUDIO_PLAY) 
+   {
+      if(audioMode == SAGE_AUDIO_FWCAPTURE) {
+
+#ifdef linux1
+         iec61883_amdtp_recv_stop (amdtp);
+#endif
+
+      }
+      else {   
+         PaError err;
+         err = Pa_StopStream( audioStream );
+         std::cout << "audio stream stop" << std::endl;
+         if( err != paNoError ) {
+            std::cerr << "audio stream could not stop" << std::endl;
+            return err;
+         }
+      }
+   }
+   playFlag = AUDIO_STOP;
+   return 0;
+}
+
+/** This routine will be called by the PortAudio engine when audio is needed.
+    It may be called at interrupt level on some machines so don't do anything
+    that could mess up the system like calling malloc() or free(). 
+*/
+int sageAudio::playCallback( const void *inputBuffer, void *outputBuffer,
+                        unsigned long framesPerBuffer,
+                        const PaStreamCallbackTimeInfo* timeInfo,
+                        PaStreamCallbackFlags statusFlags,
+                        void *userData )
+{
+	if( outputBuffer == NULL ) {
+		//std::cerr << "playCallback is return 1" << std::endl;
+		return 1;
+	}
+   
+   sageAudio *This = (sageAudio*)userData;
+   //if (This ==  NULL) return 0;      // for safety.... it needs, but it's not possible to get NULL 
+   //if(This->buffer == NULL) return 0;
+   audioBlock *block = This->buffer->readBlock();   
+
+   /** todo */   
+   // check later... it can make strange noisy  
+   if(block == NULL) {
+	  //std::cerr << "playCallback is return 0" << std::endl;
+      return 0;
+   }   
+   if(block->reformatted != 1) {
+	   //std::cerr << "playCallback is return 0" << std::endl;	
+	   return 0;   
+   }
+   //if(This->playFlag != AUDIO_PLAY) return 0;
+   
+   //std::cout << "playback : ";   
+   
+   /*if( block->timestamp > 0) {   // neet to modify
+      PaTime time = Pa_GetStreamTime(This->audioStream) - block->timestamp;
+      double latency = time / framesPerBuffer;
+         
+      if( This->minLatency >= latency ) {
+            This->minLatency = latency;
+      }
+      if( This->maxLatency <= latency ) {
+            This->maxLatency = latency;
+      }
+   }*/
+         
+   
+   switch(This->sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *rptr = (float*) block->buff;
+            float *wptr = (float*) outputBuffer;
+
+            if( block->reformatted != 1 ) {
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = 0;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0.0;
+                  }
+               }
+            }
+            else {
+               // update data for play
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = *rptr;
+                  *rptr=0;
+                  rptr++;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr;   
+                     *rptr=0;
+                     rptr++;
+                  }
+               }
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT16 : 
+         {
+            short *rptr = (short*) block->buff;
+            short *wptr = (short*) outputBuffer;
+
+            if( block->reformatted != 1 ) {
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = 0;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0;
+                  }
+               }
+            }
+            else {
+               // update data for play
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = *rptr;
+                  *rptr=0;
+                  rptr++;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr;       
+                     *rptr=0;
+                     rptr++;
+                  }
+               }
+            }
+         }      
+         break;
+      case SAGE_SAMPLE_INT8 : 
+         {
+            char *rptr = (char*) block->buff;
+            char *wptr = (char*) outputBuffer;
+
+            if( block->reformatted != 1 ) {
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = '0';         // not sure....  it's right or not
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = '0';
+                  }
+               }
+            }
+            else {
+               // update data for play
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = *rptr;
+                  *rptr='0';
+                  rptr++;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr;       
+                     *rptr='0';
+                     rptr++;
+                  }
+               }
+            }
+         }      
+         break;      
+      case SAGE_SAMPLE_UINT8 : 
+         {
+            unsigned char *rptr = (unsigned char*) block->buff;
+            unsigned char *wptr = (unsigned char*) outputBuffer;
+
+            if( block->reformatted != 1 ) {
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = '0';
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = '0';
+                  }
+               }
+            }
+            else {
+               // update data for play
+               for( int i=0; i< framesPerBuffer; i++ ) {
+                  *wptr++ = *rptr;
+                  *rptr='0';
+                  rptr++;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr;       
+                     *rptr='0';
+                     rptr++;
+                  }
+               }
+            }
+         }   
+         break;
+      default :
+         break;
+   }
+   
+   // reset
+   block->reformatted = 0;
+   //std::cout <<  block->frameIndex << ": " << This->buffer->getReadIndex();
+   // update index
+   This->buffer->updateReadIndex();
+   
+   //std::cout << ": " << This->buffer->getReadIndex() << std::endl;
+     
+
+   return 0;
+}
+
+#ifdef linux1
+int sageAudio::recordFWCallback(iec61883_amdtp_t amdtp, char *data, int nsamples,
+         unsigned int dbc, unsigned int dropped, void *callback_data)
+{
+   sageAudio *This = (sageAudio *) callback_data;
+   static int total_packets = 0;
+
+   std::cout << "read_packet...." << std::endl;
+   if (total_packets == 0) {
+      std::cout << "format=0x" << iec61883_amdtp_get_format (amdtp) << " sample_format=0x" <<  iec61883_amdtp_get_sample_format (amdtp) <<
+               " channels=" <<  iec61883_amdtp_get_dimension (amdtp) << " rate=" << iec61883_amdtp_get_rate (amdtp) << std::endl;
+      // later can change....
+      // have to check nsamples & framesPerBuffer
+   }
+
+   // TODO: convert to additional formats (20 or 24-bits).
+   if (iec61883_amdtp_get_format (amdtp) == IEC61883_AMDTP_FORMAT_RAW && iec61883_amdtp_get_sample_format (amdtp) == IEC61883_AMDTP_INPUT_LE16 &&
+      iec61883_amdtp_get_dimension (amdtp) == 2)
+   {
+      audioBlock *block = This->buffer->getNextWriteBlock();
+      if(block == NULL) {
+         //std::cout << "no block " << std::endl;
+         return 0;      
+      }
+      unsigned char *rptr = (unsigned char*) data;
+      //quadlet_t *rptr = (quadlet_t *) data;
+      unsigned char *wptr = (unsigned char*) block->buff;
+ 
+      // update audio data
+      if( data == NULL ) {
+         for( int i=0; i < This->framePerBuffer; i++ ) {
+            *wptr++ = 0;         
+            for( int j= 1; j < This->channels; j++) {
+               *wptr++ = 0;       
+            }
+         }
+      }
+      else {
+         for( int i=0; i < This->framePerBuffer; i++ )
+         {
+            *wptr++ = *rptr++;      
+            for( int j= 1; j < This->channels; j++) {
+               *wptr++ = *rptr++;       
+            }
+         }
+      }
+      /*for (int i = 0; i < nsamples; i++) {
+         // the first byte contains a label - skip it
+         *wptr++ = (sample[i] >> 8);
+         *wptr++ = (sample[i] >> 16);
+      }*/
+   }
+   return 0;
+}
+#endif
+
+/** This routine will be called by the PortAudio engine when audio is needed.
+    It may be called at interrupt level on some machines so don't do anything
+    that could mess up the system like calling malloc() or free().
+*/
+int sageAudio::recordCallback( const void *inputBuffer, void *outputBuffer,
+                           unsigned long framesPerBuffer,
+                           const PaStreamCallbackTimeInfo* timeInfo,
+                           PaStreamCallbackFlags statusFlags,
+                           void *userData )
+{
+   if(inputBuffer == NULL) return 1;
+   
+   sageAudio *This = (sageAudio*)userData;
+   //if (This ==  NULL) return 0;      // for safety.... it needs, but it's not possible to get NULL 
+   //if(This->buffer == NULL) return 0;
+   audioBlock *block = This->buffer->getNextWriteBlock();
+
+   while(block == NULL) {
+      sage::usleep(10);
+      block = This->buffer->getNextWriteBlock();
+      //std::cout << "trying to get buffer..." << std::endl;
+   }
+
+   
+   /** todo */   
+   // check later... it can make strange noisy  
+   if(block == NULL) {
+      //std::cout << "no block " << std::endl;
+      return 0;      
+   }
+   //if(block->reformatted != 1) return 0;
+   //if(This->playFlag != AUDIO_PLAY) return -1;
+   
+   switch(This->sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         {
+            float *rptr = (float*) inputBuffer;
+            float *wptr = (float*) block->buff;
+
+            // update audio data
+            if( inputBuffer == NULL ) {
+               for( int i=0; i < framesPerBuffer; i++ ) {
+                  *wptr++ = 0;         
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0;       
+                  }
+               }
+
+            }
+            else {
+               for( int i=0; i < framesPerBuffer; i++ )
+               {
+                  *wptr++ = *rptr++;
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr++;   
+                  }
+               }
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT16 : 
+         {
+            short *rptr = (short*) inputBuffer;
+            short *wptr = (short*) block->buff;
+
+            // update audio data
+            if( inputBuffer == NULL ) {
+               for( int i=0; i < framesPerBuffer; i++ ) {
+                  *wptr++ = 0;         
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0;       
+                  }
+               }
+
+            }
+            else {
+               for( int i=0; i < framesPerBuffer; i++ )
+               {
+                  *wptr++ = *rptr++;      
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr++;       
+                  }
+               }
+            }
+         }
+         break;
+      case SAGE_SAMPLE_INT8 : 
+         {
+            char *rptr = (char*) inputBuffer;
+            char *wptr = (char*) block->buff;
+
+            // update audio data
+            if( inputBuffer == NULL ) {
+               for( int i=0; i < framesPerBuffer; i++ ) {
+                  *wptr++ = 0;         
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0;       
+                  }
+               }
+
+            }
+            else {
+               for( int i=0; i < framesPerBuffer; i++ )
+               {
+                  *wptr++ = *rptr++;      
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr++;       
+                  }
+               }
+            }
+         }
+         break;      
+      case SAGE_SAMPLE_UINT8 : 
+         {
+            unsigned char *rptr = (unsigned char*) inputBuffer;
+            unsigned char *wptr = (unsigned char*) block->buff;
+
+            // update audio data
+            if( inputBuffer == NULL ) {
+               for( int i=0; i < framesPerBuffer; i++ ) {
+                  *wptr++ = 0;         
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = 0;       
+                  }
+               }
+
+            }
+            else {
+               for( int i=0; i < framesPerBuffer; i++ )
+               {
+                  *wptr++ = *rptr++;      
+                  for( int j= 1; j < This->channels; j++) {
+                     *wptr++ = *rptr++;       
+                  }
+               }
+            }
+         }
+         break;         
+      default :
+         break;            
+   }
+
+   //block->frameIndex = This->frameIndex;
+   block->frameIndex = This->buffer->getWriteIndex();
+   block->gframeIndex = sageAudioModule::_instance->getgFrameNum();
+   block->reformatted = 1;
+   block->timestamp = Pa_GetStreamTime(This->audioStream);   
+
+   // update writeIndex
+   This->buffer->updateWriteIndex();
+
+   //std::cout << "recordCallback : " << block->frameIndex << ": " << This->buffer->getWriteIndex() << std::endl;
+         
+   return 0;
+}
+
+/** test each output device, through its full range of capabilities. 
+*/
+void sageAudio::testDevices()
+{
+   int     i, numDevices, defaultDisplayed;
+   const   PaDeviceInfo *deviceInfo;
+   PaStreamParameters inputParameters, outputParameters;
+   PaError err;
+            
+   numDevices = Pa_GetDeviceCount();
+   if( numDevices < 0 )
+   {
+      std::cerr << "Pa_CountDevices returned 0x" <<  numDevices << std::endl;
+      err = numDevices;
+      return;
+   }
+    
+   std::cout << "number of devices = " << numDevices << std::endl;
+   for( i=0; i<numDevices; i++ )
+   {
+      deviceInfo = Pa_GetDeviceInfo( i );
+      std::cout << "--------------------------------------- device #" << i << std::endl;
+                
+      /* Mark global and API specific default devices */
+      defaultDisplayed = 0;
+      if( i == Pa_GetDefaultInputDevice() )
+      {
+         std::cout << "[ Default Input";
+         defaultDisplayed = 1;
+      }
+      else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
+      {
+         const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+         std::cout << "[ Default " << hostInfo->name  << " Input" ;
+         defaultDisplayed = 1;
+      }
+
+      if( i == Pa_GetDefaultOutputDevice() )
+      {
+         std::cout << (defaultDisplayed ? "," : "[");
+         std::cout << " Default Output";
+         defaultDisplayed = 1;
+      }
+      else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
+      {
+         const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+         std::cout << (defaultDisplayed ? "," : "[") ;                
+         std::cout << " Default " << hostInfo->name << " Output";
+         defaultDisplayed = 1;
+      }
+
+      if( defaultDisplayed )
+         std::cout << " ]" << std::endl;
+
+      /* print device info fields */
+      std::cout << "Name                        = " << deviceInfo->name << std::endl;
+      std::cout << "Host API                    = " << Pa_GetHostApiInfo( deviceInfo->hostApi )->name << std::endl;
+      std::cout << "Max inputs = " << deviceInfo->maxInputChannels;
+      std::cout << ", Max outputs = " << deviceInfo->maxOutputChannels  << std::endl;
+
+      std::cout << "Default low input latency   = " << deviceInfo->defaultLowInputLatency  << std::endl;
+      std::cout << "Default low output latency  = " << deviceInfo->defaultLowOutputLatency  << std::endl;
+      std::cout << "Default high input latency  = " << deviceInfo->defaultHighInputLatency  << std::endl;
+      std::cout << "Default high output latency = " << deviceInfo->defaultHighOutputLatency << std::endl;
+
+      std::cout << "Default sample rate         = " << deviceInfo->defaultSampleRate << std::endl;
+
+      /* poll for standard sample rates */
+      inputParameters.device = i;
+      inputParameters.channelCount = deviceInfo->maxInputChannels;
+      inputParameters.sampleFormat = paInt16;
+      inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+      inputParameters.hostApiSpecificStreamInfo = NULL;
+        
+      outputParameters.device = i;
+      outputParameters.channelCount = deviceInfo->maxOutputChannels;
+      outputParameters.sampleFormat = paInt16;
+      outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+      outputParameters.hostApiSpecificStreamInfo = NULL;
+
+      if( inputParameters.channelCount > 0 )
+      {
+         std::cout << "Supported standard sample rates\n for half-duplex 16 bit" << inputParameters.channelCount << "  channel input = " << std::endl;
+         std::cout << "8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 2250.0, 24000.0, 32000.0, " << std::endl;
+         std::cout << "44100.0, 48000.0, 88200.0, 96000.0, 192000.0" << std::endl;
+      }
+      if( outputParameters.channelCount > 0 )
+      {
+         std::cout << "Supported standard sample rates\n for half-duplex 16 bit" << outputParameters.channelCount << "  channel output = " << std::endl;
+         std::cout << "8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 2250.0, 24000.0, 32000.0, " << std::endl;
+         std::cout << "44100.0, 48000.0, 88200.0, 96000.0, 192000.0" << std::endl;
+      }
+      if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 )
+      {
+         std::cout << "Supported standard sample rates\n for half-duplex 16 bit" << inputParameters.channelCount << "  channel input, " << outputParameters.channelCount << "  channel output = " << std::endl;
+         std::cout << "8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 2250.0, 24000.0, 32000.0, " << std::endl;
+         std::cout << "44100.0, 48000.0, 88200.0, 96000.0, 192000.0" << std::endl;      
+      }
+   }
+}
+
+
+int sageAudio::getID()
+{
+   return ID;
+}
Index: trunk/src/testing/src/SDLMain.m
===================================================================
--- trunk/src/testing/src/SDLMain.m	(revision 4)
+++ trunk/src/testing/src/SDLMain.m	(revision 4)
@@ -0,0 +1,383 @@
+/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
+       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
+       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
+
+    Feel free to customize this file to suit your needs
+*/
+
+#import "SDL/SDL.h"
+#import "SDLMain.h"
+#import <sys/param.h> /* for MAXPATHLEN */
+#import <unistd.h>
+
+/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
+ but the method still is there and works. To avoid warnings, we declare
+ it ourselves here. */
+@interface NSApplication(SDL_Missing_Methods)
+- (void)setAppleMenu:(NSMenu *)menu;
+@end
+
+/* Use this flag to determine whether we use SDLMain.nib or not */
+#define		SDL_USE_NIB_FILE	0
+
+/* Use this flag to determine whether we use CPS (docking) or not */
+#define		SDL_USE_CPS		1
+#ifdef SDL_USE_CPS
+/* Portions of CPS.h */
+typedef struct CPSProcessSerNum
+{
+	UInt32		lo;
+	UInt32		hi;
+} CPSProcessSerNum;
+
+extern OSErr	CPSGetCurrentProcess( CPSProcessSerNum *psn);
+extern OSErr 	CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+extern OSErr	CPSSetFrontProcess( CPSProcessSerNum *psn);
+
+#endif /* SDL_USE_CPS */
+
+static int    gArgc;
+static char  **gArgv;
+static BOOL   gFinderLaunch;
+static BOOL   gCalledAppMainline = FALSE;
+
+static NSString *getApplicationName(void)
+{
+    NSDictionary *dict;
+    NSString *appName = 0;
+
+    /* Determine the application name */
+    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
+    if (dict)
+        appName = [dict objectForKey: @"CFBundleName"];
+    
+    if (![appName length])
+        appName = [[NSProcessInfo processInfo] processName];
+
+    return appName;
+}
+
+#if SDL_USE_NIB_FILE
+/* A helper category for NSString */
+@interface NSString (ReplaceSubString)
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
+@end
+#endif
+
+@interface SDLApplication : NSApplication
+@end
+
+@implementation SDLApplication
+/* Invoked from the Quit menu item */
+- (void)terminate:(id)sender
+{
+    /* Post a SDL_QUIT event */
+    SDL_Event event;
+    event.type = SDL_QUIT;
+    SDL_PushEvent(&event);
+}
+@end
+
+/* The main class of the application, the application's delegate */
+@implementation SDLMain
+
+/* Set the working directory to the .app's parent directory */
+- (void) setupWorkingDirectory:(BOOL)shouldChdir
+{
+    if (shouldChdir)
+    {
+        char parentdir[MAXPATHLEN];
+		CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
+		CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
+		if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
+	        assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
+		}
+		CFRelease(url);
+		CFRelease(url2);
+	}
+
+}
+
+#if SDL_USE_NIB_FILE
+
+/* Fix menu to contain the real app name instead of "SDL App" */
+- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
+{
+    NSRange aRange;
+    NSEnumerator *enumerator;
+    NSMenuItem *menuItem;
+
+    aRange = [[aMenu title] rangeOfString:@"SDL App"];
+    if (aRange.length != 0)
+        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
+
+    enumerator = [[aMenu itemArray] objectEnumerator];
+    while ((menuItem = [enumerator nextObject]))
+    {
+        aRange = [[menuItem title] rangeOfString:@"SDL App"];
+        if (aRange.length != 0)
+            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
+        if ([menuItem hasSubmenu])
+            [self fixMenu:[menuItem submenu] withAppName:appName];
+    }
+    [ aMenu sizeToFit ];
+}
+
+#else
+
+static void setApplicationMenu(void)
+{
+    /* warning: this code is very odd */
+    NSMenu *appleMenu;
+    NSMenuItem *menuItem;
+    NSString *title;
+    NSString *appName;
+    
+    appName = getApplicationName();
+    appleMenu = [[NSMenu alloc] initWithTitle:@""];
+    
+    /* Add menu items */
+    title = [@"About " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+
+    [appleMenu addItem:[NSMenuItem separatorItem]];
+
+    title = [@"Hide " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+
+    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
+    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+
+    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+
+    [appleMenu addItem:[NSMenuItem separatorItem]];
+
+    title = [@"Quit " stringByAppendingString:appName];
+    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+
+    
+    /* Put menu into the menubar */
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+    [menuItem setSubmenu:appleMenu];
+    [[NSApp mainMenu] addItem:menuItem];
+
+    /* Tell the application object that this is now the application menu */
+    [NSApp setAppleMenu:appleMenu];
+
+    /* Finally give up our references to the objects */
+    [appleMenu release];
+    [menuItem release];
+}
+
+/* Create a window menu */
+static void setupWindowMenu(void)
+{
+    NSMenu      *windowMenu;
+    NSMenuItem  *windowMenuItem;
+    NSMenuItem  *menuItem;
+
+    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
+    
+    /* "Minimize" item */
+    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
+    [windowMenu addItem:menuItem];
+    [menuItem release];
+    
+    /* Put menu into the menubar */
+    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
+    [windowMenuItem setSubmenu:windowMenu];
+    [[NSApp mainMenu] addItem:windowMenuItem];
+    
+    /* Tell the application object that this is now the window menu */
+    [NSApp setWindowsMenu:windowMenu];
+
+    /* Finally give up our references to the objects */
+    [windowMenu release];
+    [windowMenuItem release];
+}
+
+/* Replacement for NSApplicationMain */
+static void CustomApplicationMain (int argc, char **argv)
+{
+    NSAutoreleasePool	*pool = [[NSAutoreleasePool alloc] init];
+    SDLMain				*sdlMain;
+
+    /* Ensure the application object is initialised */
+    [SDLApplication sharedApplication];
+    
+#ifdef SDL_USE_CPS
+    {
+        CPSProcessSerNum PSN;
+        /* Tell the dock about us */
+        if (!CPSGetCurrentProcess(&PSN))
+            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
+                if (!CPSSetFrontProcess(&PSN))
+                    [SDLApplication sharedApplication];
+    }
+#endif /* SDL_USE_CPS */
+
+    /* Set up the menubar */
+    [NSApp setMainMenu:[[NSMenu alloc] init]];
+    setApplicationMenu();
+    setupWindowMenu();
+
+    /* Create SDLMain and make it the app delegate */
+    sdlMain = [[SDLMain alloc] init];
+    [NSApp setDelegate:sdlMain];
+    
+    /* Start the main event loop */
+    [NSApp run];
+    
+    [sdlMain release];
+    [pool release];
+}
+
+#endif
+
+
+/*
+ * Catch document open requests...this lets us notice files when the app
+ *  was launched by double-clicking a document, or when a document was
+ *  dragged/dropped on the app's icon. You need to have a
+ *  CFBundleDocumentsType section in your Info.plist to get this message,
+ *  apparently.
+ *
+ * Files are added to gArgv, so to the app, they'll look like command line
+ *  arguments. Previously, apps launched from the finder had nothing but
+ *  an argv[0].
+ *
+ * This message may be received multiple times to open several docs on launch.
+ *
+ * This message is ignored once the app's mainline has been called.
+ */
+- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
+{
+    const char *temparg;
+    size_t arglen;
+    char *arg;
+    char **newargv;
+
+    if (!gFinderLaunch)  /* MacOS is passing command line args. */
+        return FALSE;
+
+    if (gCalledAppMainline)  /* app has started, ignore this document. */
+        return FALSE;
+
+    temparg = [filename UTF8String];
+    arglen = SDL_strlen(temparg) + 1;
+    arg = (char *) SDL_malloc(arglen);
+    if (arg == NULL)
+        return FALSE;
+
+    newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
+    if (newargv == NULL)
+    {
+        SDL_free(arg);
+        return FALSE;
+    }
+    gArgv = newargv;
+
+    SDL_strlcpy(arg, temparg, arglen);
+    gArgv[gArgc++] = arg;
+    gArgv[gArgc] = NULL;
+    return TRUE;
+}
+
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+    int status;
+
+    /* Set the working directory to the .app's parent directory */
+    [self setupWorkingDirectory:gFinderLaunch];
+
+#if SDL_USE_NIB_FILE
+    /* Set the main menu to contain the real app name instead of "SDL App" */
+    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
+#endif
+
+    /* Hand off to main application code */
+    gCalledAppMainline = TRUE;
+    status = SDL_main (gArgc, gArgv);
+
+    /* We're done, thank you for playing */
+    exit(status);
+}
+@end
+
+
+@implementation NSString (ReplaceSubString)
+
+- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
+{
+    unsigned int bufferSize;
+    unsigned int selfLen = [self length];
+    unsigned int aStringLen = [aString length];
+    unichar *buffer;
+    NSRange localRange;
+    NSString *result;
+
+    bufferSize = selfLen + aStringLen - aRange.length;
+    buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
+    
+    /* Get first part into buffer */
+    localRange.location = 0;
+    localRange.length = aRange.location;
+    [self getCharacters:buffer range:localRange];
+    
+    /* Get middle part into buffer */
+    localRange.location = 0;
+    localRange.length = aStringLen;
+    [aString getCharacters:(buffer+aRange.location) range:localRange];
+     
+    /* Get last part into buffer */
+    localRange.location = aRange.location + aRange.length;
+    localRange.length = selfLen - localRange.location;
+    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
+    
+    /* Build output string */
+    result = [NSString stringWithCharacters:buffer length:bufferSize];
+    
+    NSDeallocateMemoryPages(buffer, bufferSize);
+    
+    return result;
+}
+
+@end
+
+
+
+#ifdef main
+#  undef main
+#endif
+
+
+/* Main entry point to executable - should *not* be SDL_main! */
+int main (int argc, char **argv)
+{
+    /* Copy the arguments into a global variable */
+    /* This is passed if we are launched by double-clicking */
+    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
+        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
+        gArgv[0] = argv[0];
+        gArgv[1] = NULL;
+        gArgc = 1;
+        gFinderLaunch = YES;
+    } else {
+        int i;
+        gArgc = argc;
+        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
+        for (i = 0; i <= argc; i++)
+            gArgv[i] = argv[i];
+        gFinderLaunch = NO;
+    }
+
+#if SDL_USE_NIB_FILE
+    [SDLApplication poseAsClass:[NSApplication class]];
+    NSApplicationMain (argc, argv);
+#else
+    CustomApplicationMain (argc, argv);
+#endif
+    return 0;
+}
Index: trunk/src/testing/src/fsManager.cpp
===================================================================
--- trunk/src/testing/src/fsManager.cpp	(revision 4)
+++ trunk/src/testing/src/fsManager.cpp	(revision 4)
@@ -0,0 +1,586 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsManager.cpp - the container of the Free Space Manager components
+ *            - fsCore, displayInstance, appData and fsServer
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageVersion.h"
+#include "fsManager.h"
+#include "fsServer.h"
+#include "fsCore.h"
+#include "streamInfo.h"
+#include "sageVirtualDesktop.h"
+#include "displayInstance.h"
+#include "streamProtocol.h"
+
+fsManager::fsManager() : NRM(false), fsmClose(false), globalSync(true), useLocalPort(false)
+{
+   core = NULL;
+   server = NULL;
+   vdtList.clear();
+   dispConnectionList.clear();
+
+   winTime = 100;
+   winStep = 0;
+	m_execIndex = 0;
+}
+
+fsManager::~fsManager()
+{
+   delete core;
+   delete server;
+
+   for(int i=0; i<execList.size(); i++)
+      if (execList[i])
+      delete execList[i];
+}
+
+int fsManager::init(const char *conf_file)
+{
+	char *sageDir = getenv("SAGE_DIRECTORY");
+	if (!sageDir) {
+		sage::printLog("fsManager: cannot find the environment variable SAGE_DIRECTORY");
+		return -1;
+	}
+	
+	// Path variable already filled by SAGE default paths (see misc.pp)
+	data_path path;
+	std::string found = path.get_file(conf_file);
+	if (found.empty()) {
+		sage::printLog("fsManager: cannot find the file [%s]", conf_file);
+		return -1;
+	}
+	const char *fsConfigFile = found.c_str();
+	sage::printLog("fsManager: SAGE version [%s]", SAGE_VERSION);
+	sage::printLog("fsManager: using [%s] configuration file", fsConfigFile);
+	
+	
+	FILE *fileFsConf = fopen(fsConfigFile, "r");
+	
+	if (!fileFsConf) {
+		sage::printLog("fsManager: fail to open fsManager config file [%s]\n", fsConfigFile);
+		return -1;
+	}
+	
+	char token[TOKEN_LEN];
+	int tokenIdx = getToken(fileFsConf, token);
+	bool tokenAcquired;
+	bool conManEnabled = false;
+	char tileConfigFile[TOKEN_LEN];
+	nwInfo = new sageNwConfig;
+	
+	char audioConfigFile[TOKEN_LEN];
+	
+	while(tokenIdx != EOF) {
+		tokenAcquired = false;
+		if (strcmp(token, "fsManager") == 0) {
+			getToken(fileFsConf, token);
+			strcpy(fsName, token);
+			getToken(fileFsConf, token);
+			strcpy(fsIP, token);
+			tokenIdx = getToken(fileFsConf, token);
+			if (strcmp(token, "systemPort") != 0) {
+				strcpy(pubIP, token);
+			}
+			else {
+				tokenAcquired = true;
+				strcpy(pubIP, fsIP);
+			}
+		}
+		else if (strcmp(token, "systemPort") == 0) {
+			getToken(fileFsConf, token);
+			sysPort = atoi(token);
+		}
+		else if (strcmp(token, "uiPort") == 0) {
+			getToken(fileFsConf, token);
+			uiPort = atoi(token);
+		}
+		else if (strcmp(token, "trackPort") == 0) {
+			getToken(fileFsConf, token);
+			trackPort = atoi(token);
+		}
+		else if (strcmp(token, "conManager") == 0) {
+			getToken(fileFsConf, token);
+			strcpy(conManIP, token);
+			getToken(fileFsConf, token);
+			conManPort = atoi(token);
+			conManEnabled = true;
+		}
+		else if (strcmp(token, "tileConfiguration") == 0) {
+			getToken(fileFsConf, token);
+			data_path path;
+			std::string found = path.get_file(token);
+			if (found.empty()) {
+				sage::printLog("fsManager: cannot find the tileConfiguration file [%s]", token);
+				return -1;
+			}			
+			strcpy(tileConfigFile, found.c_str());
+			sage::printLog("fsManager: using [%s] tile configuration file", tileConfigFile);
+		}
+		else if (strcmp(token, "globalSync") == 0) {
+			getToken(fileFsConf, token);
+			sage::toupper(token);
+			if (strcmp(token, "NO") == 0)
+				globalSync = false;
+			else
+				globalSync = true;
+		}
+		else if (strcmp(token, "receiverSyncPort") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.syncPort = atoi(token);
+		}
+		else if (strcmp(token, "receiverStreamPort") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.streamPort = atoi(token);
+		}
+		else if (strcmp(token, "receiverBufSize") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.bufSize = atoi(token);
+		}
+		else if (strcmp(token, "fullScreen") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.fullScreen = (bool)atoi(token);
+		}
+		else if (strcmp(token, "rcvNwBufSize") == 0) {
+			getToken(fileFsConf, token);
+			nwInfo->rcvBufSize = getnumber(token); // atoi(token);
+		}
+		else if (strcmp(token, "sendNwBufSize") == 0) {
+			getToken(fileFsConf, token);
+			nwInfo->sendBufSize = getnumber(token); // atoi(token);
+		}
+		else if (strcmp(token, "MTU") == 0) {
+			getToken(fileFsConf, token);
+			nwInfo->mtuSize = atoi(token);
+		}
+		else if (strcmp(token, "winTime") == 0) {
+			getToken(fileFsConf, token);
+			winTime = atoi(token);
+		}
+		else if (strcmp(token, "winStep") == 0) {
+			getToken(fileFsConf, token);
+			winStep = atoi(token);
+		}
+		else if (strcmp(token, "NRM") == 0) {
+			getToken(fileFsConf, token);
+			NRM = (bool)atoi(token);
+		}
+		else if (strcmp(token, "audioConfiguration") == 0) {
+			getToken(fileFsConf, token);
+			if (rInfo.audioOn) {
+				data_path path;
+				std::string found = path.get_file(token);
+				if (found.empty()) {
+					sage::printLog("fsManager: cannot find the audioConfigFile file [%s]", token);
+					return -1;
+				}			
+				strcpy(audioConfigFile, found.c_str());
+				sage::printLog("fsManager: using [%s] audio configuration file", audioConfigFile);
+			}
+		}
+		else if (strcmp(token, "audio") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.audioOn = (bool) (strcmp(token, "true") == 0);
+		}
+		else if (strcmp(token, "receiverAudioSyncPort") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.audioSyncPort = atoi(token);
+		}
+		else if (strcmp(token, "receiverAudioPort") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.audioPort = atoi(token);
+		}
+		else if (strcmp(token, "syncPort") == 0) {
+			getToken(fileFsConf, token);
+			rInfo.agSyncPort = atoi(token);
+		}
+		else if ( strcmp(token, "syncBarrierPort") == 0 ) {
+			getToken(fileFsConf, token);
+			rInfo.syncBarrierPort = atoi(token); // SUNGWON
+		}
+		else if ( strcmp(token, "refreshInterval") == 0 ) {
+			getToken(fileFsConf, token);
+			rInfo.refreshInterval = atoi(token); // SUNGWON
+		}
+		else if ( strcmp(token, "syncMasterPollingInterval") == 0 ) {
+			getToken(fileFsConf, token);
+			rInfo.syncMasterPollingInterval = atoi(token); // SUNGWON
+		}
+		else if ( strcmp(token, "syncLevel") == 0 ) {
+			getToken(fileFsConf, token);
+			rInfo.syncLevel = atoi(token); // SUNGWON
+		}
+		if (!tokenAcquired)
+			tokenIdx = getToken(fileFsConf, token);
+	}
+	
+	for(int i=0; i<MAX_INST_NUM; i++)
+	{
+		m_execIDList[i] = 0;
+	}
+	
+	server = new fsServer;
+	server->init(this);
+	
+	core = new fsCore;
+	core->init(this);
+	
+	FILE *tileFp = fopen(tileConfigFile, "r");
+	if (!tileFp) {
+		printf("fsManager::init() : fail to open tile config file [%s]\n", tileConfigFile);
+		return -1;
+	}
+	
+	bool nextDisplay = true;
+	int displayID = 0;
+	
+	while (nextDisplay) {
+		sageVirtualDesktop *vdt = new sageVirtualDesktop(this, displayID);
+		nextDisplay = vdt->parseConfigfile(tileFp, displayID > 0);
+		if (globalSync && displayID > 0)
+			strcpy(vdt->masterIP, vdtList[0]->masterIP);
+		vdt->launchReceivers(fsIP, sysPort, rInfo.syncPort, globalSync, rInfo.syncBarrierPort, rInfo.refreshInterval, rInfo.syncMasterPollingInterval, rInfo.syncLevel); // SUNGWON
+		vdtList.push_back(vdt);
+		displayID++;
+	}
+	
+	if (vdtList.size() > 1)
+		parseDisplayConnectionInfo(tileFp);
+	
+#ifdef SAGE_AUDIO
+	if(rInfo.audioOn) {
+		FILE *audioFp = fopen(audioConfigFile, "r");
+		std::cout << "audio on " << std::endl;
+		
+		if (!audioFp) {
+			printf("fsManager::init() : fail to open tile config file [%s]\n", audioConfigFile);
+			return -1;
+		}
+		vdtList[0]->parseAudioConfigfile(audioFp);
+		vdtList[0]->launchAudioReceivers(fsIP, sysPort, rInfo.syncPort);
+		
+		fclose(audioFp);
+	}
+#endif
+	
+	blockCommands = false;
+	
+	pthread_t thId;
+	
+	if (conManEnabled && pthread_create(&thId, 0, msgThread, (void*)this) != 0) {
+		std::cerr << "fsManager : can't create msgThread" << std::endl;
+		return -1;
+	}
+	
+	return 0;
+}
+
+int fsManager::talkToConnectionManager()
+{
+	int dimX = vdtList[0]->dimX;
+	int dimY = vdtList[0]->dimY;
+	int vdtWidth = vdtList[0]->width;
+	int vdtHeight = vdtList[0]->height;
+	int tileWidth = vdtList[0]->globalType.width;
+	int tileHeight = vdtList[0]->globalType.height;
+
+	char fsMsg[CMAN_MSG_SIZE];
+	memset((void *)fsMsg, 0, CMAN_MSG_SIZE);
+	sprintf(fsMsg, "100\n%s %s\n%s %d\n%s %d\n%d %d %d %d %d %d", fsName, SAGE_VERSION, fsIP, sysPort, pubIP, uiPort,
+			dimX, dimY, vdtWidth, vdtHeight,   tileWidth, tileHeight);
+
+	int dataSize = CMAN_MSG_SIZE;
+	QUANTAnet_tcpClient_c *client = new QUANTAnet_tcpClient_c;
+	client->setTimeOut(1);
+
+	//sage::printLog("fsManager::talkToConnectionManager() : try to connect to Connection Manager at %s:%d", conManIP, conManPort);
+	while (client->connectToServer(conManIP, conManPort) < 0) {
+		sage::printLog("fsManager::%s() : fail to connect to the connection manager", __FUNCTION__);
+		sage::sleep(1);
+	}
+	sage::printLog("fsManager::talkToConnectionManager() : connected to the connection manager %s:%d", conManIP, conManPort);
+
+	bool reconnect = false;
+
+	while (!fsmClose) {
+		int status = client->write(fsMsg, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+		if (status != QUANTAnet_tcpClient_c::OK) {
+			reconnect = true;
+		}
+		//else
+			//   std::cout << "message sent to connection manager : " << fsMsg << std::endl;
+
+		sage::sleep(5);
+
+		if (reconnect) {
+			sage::printLog("fsManager::talkToConnectionManager() : failed to send message to the connection manager. Reconnecting. %s:%d", conManIP, conManPort);
+			while (client->connectToServer(conManIP, conManPort) < 0) {
+				sage::printLog("fsManager::%s() : fail to connect to the connection manager", __FUNCTION__);
+				sage::sleep(1);
+			}
+			sage::printLog("fsManager::talkToConnectionManager() : connected to connection manager %s : %d", conManIP, conManPort);
+			reconnect = false;
+		}
+	}
+	return 0;
+}
+
+void* fsManager::msgThread(void *args)
+{
+   fsManager *This = (fsManager *)args;
+
+   This->talkToConnectionManager();
+
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void fsManager::mainLoop()
+{
+   while (!fsmClose) {
+      server->checkClients();
+//      std::cout << "check clients " << std::endl;
+      sage::usleep(100);
+   }
+}
+
+int fsManager::msgToCore(sageMessage &msg, int clientID)
+{
+   return core->parseMessage(msg, clientID);
+}
+
+int fsManager::msgToDisp(sageMessage &msg, int clientID)
+{
+   int dispNum = dispList.size();
+
+   // find associated display manager and forward this message
+   if (msg.getCode() < DISP_MESSAGE + 100) {
+      for(int i=0; i<dispNum; i++) {
+         if (!dispList[i])
+            continue;
+
+         if (dispList[i]->getSailClient() == clientID) {
+            return dispList[i]->parseMsg(msg);
+         }
+      }
+   }
+   else {
+	   /*
+      char token[TOKEN_LEN];
+      getToken((char *)msg.getData(), token);
+      int winId = atoi(token);
+      */
+
+	   int winId = atoi( (char *)msg.getData() );
+
+      //      std::cout << "disp message win id " << winId << std::endl;
+      //if (winId >= dispNum) {
+      //   sage::printLog("fsManager::msgToDisp : window ID is out of scope");
+      //   return -1;
+      //}
+
+		displayInstance* disp = NULL;
+		std::vector<displayInstance*>::iterator iter_disp;
+		for(iter_disp = dispList.begin(); iter_disp != dispList.end(); iter_disp++)
+		{
+			if ((*iter_disp)->winID == winId)
+			{
+				disp = (displayInstance*) *iter_disp;
+				break;
+			}
+		}
+
+		if (!disp) {
+         sage::printLog("fsManager::msgToDisp : window %d doesn't exist", winId);
+         return -1;
+      }
+
+		return disp->parseMsg(msg);
+   }
+
+   return 0;
+}
+
+int fsManager::sendMessage(int cId, int code, int data)
+{
+   return server->sendMessage(cId, code, data);
+}
+
+int fsManager::sendMessage(int cId, int code, char* data)
+{
+   return server->sendMessage(cId, code, data);
+}
+
+int fsManager::sendMessage(int cId, int code)
+{
+   return server->sendMessage(cId, code);
+}
+
+int fsManager::sendMessage(sageMessage &msg)
+{
+   return server->sendMessage(msg);
+}
+
+int fsManager::windowChanged(int winId)
+{
+   blockCommands = false;
+   //std::cout << std::endl << "window changed " << std::endl << std::endl;
+
+   return core->windowChanged(winId);
+}
+
+int fsManager::parseDisplayConnectionInfo(FILE *fp)
+{
+   char token[TOKEN_LEN];
+   displayConnection *connection = NULL;
+
+   while (getToken(fp, token) != EOF) {
+      sage::toupper(token);
+      if (strcmp(token, "CONNECTION") == 0) {
+         connection = new displayConnection;
+         for (int i=0; i<2; i++) {
+            getToken(fp, token);
+            int dispID = atoi(token);
+            int j = 0;
+            for ( ; j<vdtList.size(); j++) {
+               if (vdtList[j]->displayID == dispID) {
+                  connection->displays[i] = vdtList[j];
+                  vdtList[j]->connectionList.push_back(connection);
+                  break;
+               }
+            }
+
+            if (j == vdtList.size()) {
+               sage::printLog("Can't find a display specified in display connection");
+                  return -1;
+            }
+
+            getToken(fp, token);
+            if (strcmp(token, "LEFT") == 0)
+               connection->edges[i] = LEFT_EDGE;
+            else if (strcmp(token, "RIGHT") == 0)
+               connection->edges[i] = RIGHT_EDGE;
+            else if (strcmp(token, "BOTTOM") == 0)
+               connection->edges[i] = BOTTOM_EDGE;
+            else if (strcmp(token, "TOP") == 0)
+               connection->edges[i] = TOP_EDGE;
+            else {
+               sage::printLog("Error in parsing display connection : invalid edge name");
+               return -1;
+            }
+         }
+
+         getToken(fp, token);
+         connection->offset = atoi(token);
+         dispConnectionList.push_back(connection);
+
+         /*
+         int vdtNum = vdtList.size();
+         int vdtCnt = 0;
+         for (int i=0; i<vdtNum; i++) {
+            if ((connection->displays[0]->displayID == vdtList[i]->displayID) ||
+               (connection->displays[1]->displayID == vdtList[i]->displayID)) {
+               vdtList[i]->connectionList.push_back(connection);
+               vdtCnt++;
+            }
+         }
+
+
+         if (vdtCnt < 2) {
+            sage::printLog("Can't find a display specified in display connection");
+            return -1;
+         }
+         */
+      }
+   }
+
+   return 0;
+}
+
+int fsManager::sendToVDT(int vdtID, int code, char *data)
+{
+   vdtList[vdtID]->sendToAll(code,data);
+
+   return 0;
+}
+
+int fsManager::sendToOtherVDT(int vdtID, int code, char *data)
+{
+   for (int i=0; i<vdtList.size(); i++) {
+      if (i != vdtID)
+         vdtList[i]->sendToAll(code,data);
+   }
+
+   return 0;
+}
+
+int fsManager::sendToVDT(int vdtID, int code, int data)
+{
+   char token[TOKEN_LEN];
+   sprintf(token, "%d", data);
+   sendToVDT(vdtID, code, token);
+
+   return 0;
+}
+
+int fsManager::sendToOtherVDT(int vdtID, int code, int data)
+{
+   char token[TOKEN_LEN];
+   sprintf(token, "%d", data);
+   sendToOtherVDT(vdtID, code, token);
+
+   return 0;
+}
+
+int fsManager::sendToAllRcvs(int code, char *data)
+{
+   for (int i=0; i<vdtList.size(); i++) {
+      vdtList[i]->sendToAll(code, data);
+   }
+
+   return 0;
+}
+
+int fsManager::sendToAllRcvs(int code, int data)
+{
+   char token[TOKEN_LEN];
+   sprintf(token, "%d", data);
+   sendToAllRcvs(code, token);
+
+   return 0;
+}
Index: trunk/src/testing/src/sageReceiver.cpp
===================================================================
--- trunk/src/testing/src/sageReceiver.cpp	(revision 4)
+++ trunk/src/testing/src/sageReceiver.cpp	(revision 4)
@@ -0,0 +1,374 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageReceiver.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageReceiver.h"
+#include "streamProtocol.h"
+#include "sageBlock.h"
+#include "sageBlockPool.h"
+#include "sageSharedData.h"
+#include "sageEvent.h"
+
+// char hostname[SAGE_NAME_LEN];
+
+void* sageReceiver::nwReadThread(void *args)
+{
+   sageReceiver *This = (sageReceiver *)args;
+
+   This->readData();
+
+   pthread_exit(NULL);
+   return NULL;
+}
+
+sagePixelReceiver::sagePixelReceiver(char *msg, rcvSharedData *sh,
+                                    streamProtocol *obj, sageBlockBuf *buf)
+{
+   char *msgPt = sage::tokenSeek(msg, 3);
+   sscanf(msgPt, "%d %d %d %d", &instID, &groupSize, &blockSize, &senderNum);
+
+   nwObj = obj;
+   shared = sh;
+   blockBuf = buf;
+   FD_ZERO(&streamFds);
+   maxSockFd = 0;
+   streamList = new streamData[senderNum];
+   streamIdx = 0;
+   configID = 0;
+   curFrame = 1;
+
+   connecting = true;
+
+   pthread_mutex_init(&streamLock, NULL);
+   pthread_mutex_unlock(&streamLock);
+   pthread_cond_init(&connectionDone, NULL);
+
+   if (pthread_create(&thId, 0, nwReadThread, (void*)this) != 0) {
+      sage::printLog("sagePixelReceiver : can't create network reading thread");
+   }
+
+// gethostname(hostname, SAGE_NAME_LEN);
+}
+
+int sagePixelReceiver::addStream(int senderID)
+{
+   if (streamIdx >= senderNum) {
+      sage::printLog("[%d,%d] sagePixelReceiver::addStream() : stream number exceeded correct number", shared->nodeID, instID);
+      return -1;
+   }
+
+   streamList[streamIdx].senderID = senderID;
+   streamList[streamIdx].dataSockFd = nwObj->getRcvSockFd(senderID);
+   maxSockFd = MAX(maxSockFd, streamList[streamIdx].dataSockFd);
+   FD_SET(streamList[streamIdx].dataSockFd, &streamFds);
+
+   streamIdx++;
+
+   if (streamIdx == senderNum) {
+      pthread_mutex_lock(&streamLock);
+      connecting = false;
+      pthread_cond_signal(&connectionDone);
+      pthread_mutex_unlock(&streamLock);
+
+      shared->eventQueue->appendEvent(EVENT_APP_CONNECTED, instID);
+   }
+
+   return streamIdx;
+}
+
+int sagePixelReceiver::checkStreams()
+{
+   fd_set sockFds = streamFds;
+   int retVal = select(maxSockFd+1, &sockFds, NULL, NULL, NULL);
+   if (retVal <= 0) {
+      sage::printLog("sagePixelReceiver::checkStreams : error in stream checking");
+      return -1;
+   }
+
+   for (int i=0; i<senderNum; i++) {
+      if (FD_ISSET(streamList[i].dataSockFd, &sockFds)) {
+         streamList[i].dataReady = true;
+      }
+   }
+
+   return 0;
+}
+
+int sagePixelReceiver::readData()
+{
+	if (!shared) {
+		sage::printLog("sagePixelReceiver::readData : shared object is null");
+		return -1;
+	}
+
+	if (!nwObj)  {
+		sage::printLog("sagePixelReceiver::readData : network object is null");
+		return -1;
+	}
+
+	if (!blockBuf)  {
+		sage::printLog("sagePixelReceiver::readData : block buffer is null");
+		return -1;
+	}
+
+	pthread_mutex_lock(&streamLock);
+	if (connecting)
+		pthread_cond_wait(&connectionDone, &streamLock);
+	pthread_mutex_unlock(&streamLock);
+
+	bool reuseBlockGroup = false;
+	bool updated = false;
+
+	sageBlockGroup *sbg = NULL;
+
+#ifdef DEBUG_RECEIVER
+	fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : START! (%d senders, grpSize %d, blkSize %d\n", shared->nodeID, instID, senderNum, groupSize, blockSize);
+#endif
+
+	while(!endFlag) {
+		if (checkStreams() < 0)
+			return -1;
+
+		//std::cout << "pt4" << std::endl;
+
+		int nextFrame = SAGE_INT_MAX;
+
+		for (int i=0; i<senderNum; i++) {
+			if (streamList[i].dataReady) {
+				if (!reuseBlockGroup) {
+					sbg = blockBuf->getFreeBlocks();
+					if (!sbg) {
+						endFlag = true;
+						return -1;
+					}
+				}
+				else {
+					reuseBlockGroup = false;
+				}
+
+				//std::cout << "pt5" << std::endl;
+				sbg->setFrameID(curFrame);
+				int rcvSize = nwObj->recvGrp(streamList[i].senderID, sbg);
+				streamList[i].dataReady = false;
+
+				//std::cout << "pt6" << std::endl;
+
+				if (rcvSize > 0) {
+					if (sbg->getFrameID() == curFrame) {
+#ifdef DEBUG_RECEIVER
+						fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : continuous data for curFrame %d\n", shared->nodeID,instID, curFrame);
+#endif
+						if (sbg->getFlag() == sageBlockGroup::PIXEL_DATA) {
+#ifdef DEBUG_RECEIVER
+							//fprintf(stderr, "\t[%d,%d] : and it's pixel\n", shared->nodeID,instID);
+#endif
+							blockBuf->pushBack(sbg);
+							//std::cout << "push back " << rcvSize << " " << sbg->getFrameID() << std::endl;
+							if (curFrame == 1 && configID == 0)
+								configID = sbg->getConfigID();
+
+							//std::cout << "push back frame " << sbg->getFrameID() << std::endl;
+							updated = true; // sets flag
+
+							// generate the receive event
+							if (blockBuf->isWaitingData())
+								shared->eventQueue->appendEvent(EVENT_READ_BLOCK, instID);
+						}
+						else {
+#ifdef DEBUG_RECEIVER
+							fprintf(stderr, "\n\t[%d,%d] : and it's NOT a pixel group\n", shared->nodeID,instID);
+#endif
+							reuseBlockGroup = true;
+							if (sbg->getConfigID() > configID) {
+#ifdef DEBUG_RECEIVER
+								fprintf(stderr, "\t\t[%d,%d] : it's new config %d\n", shared->nodeID, instID, sbg->getConfigID());
+#endif
+								configID = sbg->getConfigID();
+								sageBlockGroup *cbg = blockBuf->getCtrlGroup(sageBlockGroup::CONFIG_UPDATE);
+								cbg->setFrameID(sbg->getFrameID());
+								cbg->setConfigID(configID);
+								blockBuf->pushBack(cbg);
+							}
+							else {
+								streamList[i].bGroup = NULL;
+#ifdef DEBUG_RECEIVER
+								fprintf(stderr, "\t\t[%d,%d] : it's not new config. sbg's configID %d. streamList[%d].bGroup is now NULL\n", shared->nodeID, instID, sbg->getConfigID(), i);
+#endif
+							}
+
+							/**
+							 * SBS always sends control block after sending a frame
+							 * Once this arrived, we now know that current frame is done
+							 */
+							streamList[i].curFrame = sbg->getFrameID()+1;
+#ifdef DEBUG_RECEIVER
+							fprintf(stderr, "\t[%d,%d] : Received control data. streamList[%d].curFrame has incremented to %d\n", shared->nodeID, instID, i, streamList[i].curFrame);
+#endif
+							FD_CLR(streamList[i].dataSockFd, &streamFds);
+						}
+					}
+
+					//
+					// new/next frame
+					//
+					else if (sbg->getFrameID() > curFrame) {
+#ifdef DEBUG_RECEIVER
+						fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : The next data of frame %d\n", shared->nodeID, instID, sbg->getFrameID());
+#endif
+						if (sbg->getFlag() == sageBlockGroup::PIXEL_DATA) {
+							//std::cout << "new block (pixel data) " << rcvSize << " " << sbg->getFrameID() <<  std::endl;
+
+							streamList[i].bGroup = sbg;
+							configID = MAX(configID, sbg->getConfigID());
+#ifdef DEBUG_RECEIVER
+							fprintf(stderr, "\t[%d,%d] : and it's pixel. my configID is now %d\n", shared->nodeID, instID, configID);
+#endif
+						}
+						else {
+							//std::cout << "new block " << rcvSize << " " << sbg->getFrameID() <<  std::endl;
+#ifdef DEBUG_RECEIVER
+							fprintf(stderr, "\t[%d,%d] : and it's NOT pixel.\n", shared->nodeID, instID);
+#endif
+
+							reuseBlockGroup = true;
+							if (sbg->getConfigID() > configID) {
+#ifdef DEBUG_RECEIVER
+								fprintf(stderr, "\t\t[%d,%d] : it's new config %d\n", shared->nodeID, instID, sbg->getConfigID());
+#endif
+								configID = sbg->getConfigID();
+								streamList[i].bGroup = blockBuf->getCtrlGroup(sageBlockGroup::CONFIG_UPDATE);
+								streamList[i].bGroup->setFrameID(sbg->getFrameID());
+								streamList[i].bGroup->setConfigID(configID);
+							}
+							else {
+								streamList[i].bGroup = NULL;
+#ifdef DEBUG_RECEIVER
+								fprintf(stderr, "\t\t[%d,%d] : it's what? streamList[%d].bGroup is now NULL\n", shared->nodeID, instID, i);
+#endif
+							}
+						}
+						streamList[i].curFrame = sbg->getFrameID();
+#ifdef DEBUG_RECEIVER
+						fprintf(stderr, "\t[%d,%d] : streamList[%d].curFrame updated to %d\n", shared->nodeID, instID, i, streamList[i].curFrame);
+#endif
+						FD_CLR(streamList[i].dataSockFd, &streamFds);
+						//std::cout << ">>>>> " << hostname << " cleaer stream " << i << std::endl;
+					}
+					else {
+						// sbg->getFrameID() < curFrame
+						sage::printLog("sagePixelReceiver::readData() : received PAST frame!! (received %d, but curFrame %d)", sbg->getFrameID(), curFrame);
+					}
+				} // end if (rcvSize>0)
+
+				else {
+					sage::printLog("[%d,%d] sagePixelReceiver::readData() : rcvSize %d, exit loop", shared->nodeID, instID, rcvSize);
+					endFlag = true;
+					break;
+				}
+			} // end if (streamList[i].dataReady )
+
+			// update nextFrame. nextFrame is reset to INT_MAX at the beginning of this while loop
+#ifdef DEBUG_RECEIVER
+			fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : Updating nextFrame = MIN(%d, %d)\n", shared->nodeID, instID,nextFrame, streamList[i].curFrame);
+#endif
+			nextFrame = MIN(nextFrame, streamList[i].curFrame);
+
+		} // end for each sender
+
+		if (nextFrame < SAGE_INT_MAX && nextFrame > curFrame) {
+#ifdef DEBUG_RECEIVER
+			fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : nextFrame %d > curFrame %d. curFrame is updated.\n", shared->nodeID, instID, nextFrame, curFrame);
+#endif
+			curFrame = nextFrame;
+			int pushNum = 0;
+			if (updated) {
+#ifdef DEBUG_RECEIVER
+				fprintf(stderr, "\t[%d,%d] sagePixelReceiver::readData() : marking END_FRAME\n", shared->nodeID, instID);
+#endif
+				blockBuf->finishFrame();
+				pushNum++;
+				//std::cout << "finish frame " << std::endl;
+
+				if (blockBuf->isWaitingData())
+					shared->eventQueue->appendEvent(EVENT_READ_BLOCK, instID);
+				updated = false;
+			}
+
+			//std::cout << "frame num is updated....  " << curFrame << " " << senderNum  << std::endl;
+
+			for (int i=0; i<senderNum; i++) {
+				FD_SET(streamList[i].dataSockFd, &streamFds);
+				sageBlockGroup *bGrp = streamList[i].bGroup;
+
+				//std::cout << "pt2" << std::endl;
+				if (bGrp && bGrp->getFrameID() == curFrame) {
+					if (bGrp->getFlag() == sageBlockGroup::PIXEL_DATA)
+						updated = true;
+					blockBuf->pushBack(bGrp);
+					//std::cout << "push back frame " << bGrp->getFrameID() << std::endl;
+					pushNum++;
+				}
+			}
+
+			//std::cout << "pt3" << std::endl;
+			if (blockBuf->isWaitingData())
+				shared->eventQueue->appendEvent(EVENT_READ_BLOCK, instID);
+		} // end if (nextFrame)
+	} // end while
+
+   fprintf(stderr, "[%d,%d] sagePixelReceiver::readData() : exit.\n", shared->nodeID, instID);
+   return 0;
+}
+
+sagePixelReceiver::~sagePixelReceiver()
+{
+	fprintf(stderr,"[%d,%d] sagePixelReceiver::%s()\n", shared->nodeID, instID, __FUNCTION__);
+   endFlag = true;
+   blockBuf->releaseLock();
+
+   for (int i=0; i<senderNum; i++) {
+      if (nwObj)
+         nwObj->close(streamList[i].senderID);
+   }
+
+   pthread_join(thId, NULL);
+
+   delete [] streamList;
+
+}
Index: trunk/src/testing/src/messageInterface.cpp
===================================================================
--- trunk/src/testing/src/messageInterface.cpp	(revision 4)
+++ trunk/src/testing/src/messageInterface.cpp	(revision 4)
@@ -0,0 +1,423 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: messageInterface.cpp - communcation interface among SAGE components.
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "messageInterface.h"
+
+messageInterface::messageInterface() : msgServer(NULL), readIdx(0), maxClientSockFd(0),
+      infEnd(false)
+{
+   msgClientList.clear();
+   FD_ZERO(&clientFds);
+}
+
+messageInterface::~messageInterface()
+{
+   int numClients = msgClientList.size();
+   
+   for (int i=0; i<numClients; i++) {
+      if (msgClientList[i]) {
+         delete msgClientList[i];
+      }   
+   }
+   
+   msgClientList.clear();
+   
+   if (msgServer)
+      delete msgServer;   
+}
+      
+int messageInterface::init(msgInfConfig &conf)
+{
+   config = conf;
+
+   if (config.master) {
+      msgServer = new QUANTAnet_tcpServer_c;
+      msgServer->init(config.serverPort);
+      msgServer->setSockOptions(QUANTAnet_tcpServer_c::READ_BUFFER_SIZE, 65536);
+      msgServer->setSockOptions(QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE, 65536);
+      
+      if (pthread_create(&conThreadID, 0, connectionThread, (void*)this) != 0) {
+         sage::printLog("messageInterface: can't create message checking thread");
+      }
+   }
+   else {
+      while (connect(config.serverIP, config.serverPort) < 0) {
+         sage::sleep(1);
+         std::cout << "messageInterface::init() : retry to connect to master" << std::endl;
+      }   
+   }
+      
+   return 0;
+}
+
+int messageInterface::connect(char *ip, int port)
+{
+   QUANTAnet_tcpClient_c *msgClient = new QUANTAnet_tcpClient_c;
+   msgClient->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, 65536);
+   msgClient->setSockOptions(QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE, 65536);
+   if (msgClient->connectToServer(ip, port) < 0) {
+      std::cout << "messageInterface::connect : server is not ready" << std::endl; 
+      delete msgClient;
+      return -1;
+   }
+   
+   int clientID = msgClientList.size();
+   msgClientList.push_back(msgClient);
+   maxClientSockFd = MAX(maxClientSockFd, msgClient->getSocketId());
+   FD_SET(msgClient->getSocketId(), &clientFds);
+   
+   return clientID;
+}
+
+int messageInterface::checkClients()
+{
+   if (!config.master) {
+      std::cout << "messageInterface::checkClients() : this function cannot be called by slaves" <<
+         std::endl;
+      return -1;
+   }
+   
+   QUANTAnet_tcpClient_c *msgClient;
+   int numClients = msgClientList.size();
+   
+   // If a connection is established, accept it and create
+   // a new socket for that connection to communicate with.
+   
+   msgClient = msgServer->checkForNewConnections();
+      
+   if (msgClient) {
+      printf("msgClient %d connected\n", numClients);
+
+      msgClientList.push_back(msgClient);
+      maxClientSockFd = MAX(maxClientSockFd, msgClient->getSocketId());
+      FD_SET(msgClient->getSocketId(), &clientFds);
+   }
+   
+   return numClients;
+}
+
+// waiting for a new client to connect
+int messageInterface::waitForConnection()
+{
+   if (!config.master) {
+      std::cout << "messageInterface::waitForConnection() : this function cannot be called by slaves" <<
+         std::endl;
+      return -1;
+   }
+   
+   QUANTAnet_tcpClient_c *msgClient;
+   int numClients = msgClientList.size();
+   
+   // If a connection is established, accept it and create
+   // a new socket for that connection to communicate with.
+   
+   msgClient = msgServer->waitForNewConnection();
+      
+   if (msgClient) {
+      printf("msgClient %d connected\n", numClients);
+
+      msgClientList.push_back(msgClient);
+      maxClientSockFd = MAX(maxClientSockFd, msgClient->getSocketId());
+      FD_SET(msgClient->getSocketId(), &clientFds);
+   }
+   
+   return numClients;
+}
+
+void* messageInterface::connectionThread(void *args)
+{
+   messageInterface *This = (messageInterface *)args;
+   
+   while (!This->infEnd) {
+      This->waitForConnection();
+   }
+
+   sage::printLog("messageInterface::connectionThread : exit");   
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int messageInterface::readMsg(sageMessage *msg, int timeOut)
+{
+   int dataSize, status;
+   fd_set readFds = clientFds;
+   
+   struct timeval *pTimeOut = NULL;
+   if (timeOut >= 0) {
+      pTimeOut = new struct timeval;
+      pTimeOut->tv_sec = 0;
+      pTimeOut->tv_usec = timeOut;
+   }
+   
+   int ready = select(maxClientSockFd+1, &readFds, NULL, NULL, pTimeOut);   
+   if (ready < 0) {
+      sage::printLog("messageInterface::readMsg : error in waiting update message");
+      return -1;
+   }   
+   else if (ready == 0)
+      return 0;
+
+   int numClients = msgClientList.size();
+   for (int i=readIdx; i<numClients; i++) {
+      if (msgClientList[i]) {
+         char msgSize[MESSAGE_FIELD_SIZE];
+         dataSize = MESSAGE_FIELD_SIZE;
+
+         if (FD_ISSET(msgClientList[i]->getSocketId(), &readFds)) {
+            status = msgClientList[i]->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+            if (status == QUANTAnet_tcpClient_c::OK) {
+               msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+               dataSize = atoi(msgSize);
+               msg->init(dataSize);
+               dataSize = dataSize - MESSAGE_FIELD_SIZE;
+               msgClientList[i]->read((char *)msg->getBuffer()+MESSAGE_FIELD_SIZE, 
+                     &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+               
+               readIdx = (i+1) % numClients;
+               //printf("Read in message from client %d\n",i);
+               //sage::printLog("messge : " << msg->getCode() << std::endl; 
+               //      << (char *)msg->getData() << std::endl;
+               return i+1;
+            } 
+            else {
+               if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED) 
+                  sage::printLog("messageInterface::readMsg : connection to client %d was shutdown", i);
+               else
+                  sage::printLog("messageInterface::readMsg : error in the connection to client ", i);   
+               FD_CLR(msgClientList[i]->getSocketId(), &clientFds);
+               msgClientList[i] = NULL;
+               readIdx = (i+1) % numClients;
+               return -1;
+            }
+         }   
+      }   
+   }
+   
+   readIdx = 0;
+   
+   return 0;
+}
+
+int messageInterface::distributeMessage(sageMessage &msg, int *clientList, int clientNum)
+{
+   if (!config.master) {
+      sage::printLog("messageInterface::distributeMessage() : this function cannot be called by slaves");
+      return -1;
+   }
+   
+   int dataSize = msg.getBufSize();
+   for (int i = 0; i < clientNum; i++) {
+      int clientID = clientList[i];
+      if (!msgClientList[clientID])
+         continue;
+
+      int status = msgClientList[clientID]->write((char *)msg.getBuffer(), &dataSize, 
+                  QUANTAnet_tcpClient_c::BLOCKING);  
+
+      if (status == QUANTAnet_tcpClient_c::OK)  {
+         //sage::printLog("Send message to msg client " << i << std::endl;
+         //sage::printLog("message : " << msg.getCode() << " " 
+         //      << (char *)msg.getData() << std::endl;
+      }
+      else
+         sage::printLog("messageInterface::distributeMessage() : Fail to send message to msg client ", i);
+   }   
+      
+   return 0;
+}
+
+int messageInterface::distributeMessage(int code, int instID, int *clientList, int clientNum)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, 0, NULL) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   int retVal = distributeMessage(msg, clientList, clientNum);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::distributeMessage(int code, int instID, char *data, int *clientList, int clientNum)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, strlen(data)+1, data) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   int retVal = distributeMessage(msg, clientList, clientNum);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::distributeMessage(int code, int instID, int data, int *clientList, int clientNum)
+{
+   char msgStr[TOKEN_LEN];
+   sprintf(msgStr, "%d", data);
+
+   return distributeMessage(code, instID, msgStr, clientList, clientNum);
+}
+
+int messageInterface::msgToClient(sageMessage &msg)
+{
+   int dataSize = msg.getBufSize();
+   int cId = msg.getClientID();
+
+   if (!msgClientList[cId])
+      return -1;
+
+   int status = msgClientList[cId]->write((char *)msg.getBuffer(), &dataSize, 
+               QUANTAnet_tcpClient_c::BLOCKING);  
+   
+   if (status == QUANTAnet_tcpClient_c::OK)  {
+      //sage::printLog("Send message to client " << cId << std::endl;
+      //sage::printLog("messge : " << msg.getCode() << " " 
+      //      << (char *)msg.getData() << std::endl;
+   }
+   else 
+      return -1;
+
+   return 0;
+}
+
+int messageInterface::msgToClient(int cId, int instID, int code)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, 0, NULL) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   msg.setClientID(cId);
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::msgToClient(int cId, int instID, int code, int data)
+{
+   char msgStr[TOKEN_LEN];
+   sprintf(msgStr, "%d", data);
+   
+   return msgToClient(cId, instID, code, msgStr);
+}
+
+int messageInterface::msgToClient(int cId, int instID, int code, char *data)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, strlen(data)+1, data) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   msg.setClientID(cId);
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::msgToServer(int instID, int code)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, 0, NULL) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   msg.setClientID(0);
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::msgToServer(int instID, int code, int data)
+{
+   char msgStr[TOKEN_LEN];
+   sprintf(msgStr, "%d", data);
+   
+   return msgToServer(instID, code, msgStr);
+}
+
+int messageInterface::msgToServer(int instID, int code, char *data)
+{
+   sageMessage msg;
+   
+   if (msg.init(instID, code, 0, strlen(data)+1, data) < 0) {
+      sage::printLog("fail to init the message!");
+      return -1;
+   }
+   
+   msg.setClientID(0);
+   
+   int retVal = msgToClient(msg);
+   msg.destroy();
+   
+   return retVal;
+}
+
+int messageInterface::shutdown()
+{
+   infEnd = true;
+   
+   if (msgServer) {
+      msgServer->close();      
+      delete msgServer;
+   }   
+   
+   //pthread_join(conThreadID, NULL);
+   
+   return 0;
+}
Index: trunk/src/testing/src/sageAudioModule.cpp
===================================================================
--- trunk/src/testing/src/sageAudioModule.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioModule.cpp	(revision 4)
@@ -0,0 +1,511 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  sageAudioModule.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for managing audio module-create audio, play, capture, save it
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "sageAudioModule.h"
+#include "sageAudio.h"
+#include "sail.h" 
+
+sageAudioModule* sageAudioModule::_instance = NULL;
+
+sageAudioModule::sageAudioModule()
+: fileReader(NULL), fileWriter(NULL), formatManager(NULL), gFrameNum(0)
+{
+   audioList.clear();
+   PaError err = Pa_Initialize();
+   if( err != paNoError ) {
+      std::cerr << "portaudio could not initializ" << std::endl;
+   }
+}
+
+sageAudioModule::~sageAudioModule()
+{
+   if(fileWriter != NULL) {
+      fileWriter->stop();
+   }
+   
+   if(fileReader != NULL) {
+      fileReader->stop();
+   }
+   
+   sage::usleep(1000);      
+
+   std::vector<sageAudio*>::iterator iter;
+   sageAudio* audio = NULL;
+   for(iter = audioList.begin(); iter != audioList.end(); iter++)
+   {
+      std::cout << "-------------------> 2" << std::endl;
+      audio = (sageAudio*) *iter;
+      audio->stop();
+      audio->closeStream();
+   }
+
+   Pa_Terminate();
+   sage::usleep(2000);   
+      
+   for(iter = audioList.begin(); iter != audioList.end(); iter++)
+   {
+      audio = (sageAudio*) *iter;
+      delete audio;
+      audio = NULL;      
+   }
+   audioList.clear();
+
+   if(fileReader != NULL) {
+      delete fileReader;
+      fileReader = NULL;
+   }
+   
+   if(fileWriter != NULL) {
+      delete fileWriter;
+      fileWriter = NULL;
+   }
+   
+   if(formatManager != NULL) {
+      delete formatManager;
+      formatManager = NULL;
+   }
+
+   std::vector<sageAudioCircBuf*>::iterator iterBuffer;
+   sageAudioCircBuf* buffer = NULL;
+   for(iterBuffer = bufferList.begin(); iterBuffer != bufferList.end(); iterBuffer++)
+   {
+      buffer = (sageAudioCircBuf*) *iterBuffer;
+      delete buffer;
+      buffer = NULL;      
+   }
+   bufferList.clear();
+}
+
+
+sageAudioModule* sageAudioModule::instance()
+{
+   if(_instance == NULL) {
+      _instance = new sageAudioModule();
+   } 
+   return _instance;
+}
+
+void sageAudioModule::init(sailConfig &conf)
+{
+   config.deviceNum = conf.audioDeviceNum;
+   config.sampleFmt = conf.sampleFmt;
+   config.samplingRate = conf.samplingRate;
+   config.channels = conf.channels;
+   config.framePerBuffer = conf.framePerBuffer;
+   config.audioMode = conf.audioMode;
+
+   init();
+}
+
+void sageAudioModule::init(sageAudioConfig &conf)
+{
+   config.deviceNum = conf.deviceNum;
+   config.sampleFmt = conf.sampleFmt;
+   config.samplingRate = conf.samplingRate;
+   config.channels = conf.channels;
+   config.framePerBuffer = conf.framePerBuffer;
+   config.audioMode = conf.audioMode;
+   
+   init();
+}
+
+void sageAudioModule::init()
+{
+   // create audio format manager
+   if(formatManager != NULL) {
+      delete formatManager;
+      formatManager = NULL;
+   }
+   formatManager = new audioFormatManager();
+   
+   // create objects for reading and writing audio files 
+   if(fileReader != NULL) {
+      delete fileReader;
+      fileReader = NULL;
+   }
+   fileReader = new audioFileReader(formatManager);
+   fileReader->init();
+      
+   if(fileWriter != NULL) {
+      delete fileWriter;
+      fileWriter = NULL;
+   }
+   fileWriter = new audioFileWriter(formatManager);
+   fileWriter->init();
+   
+   std::cout << "sageAudioModule::init: initialized" << std::endl;
+
+}
+
+sageAudioConfig* sageAudioModule::getAudioConfig()
+{
+   return &config;
+}
+
+void sageAudioModule::updateConfig(sageAudioConfig &conf)
+{
+   config.deviceNum = conf.deviceNum;
+   config.sampleFmt = conf.sampleFmt;
+   config.samplingRate = conf.samplingRate;
+   config.channels = conf.channels;
+   config.framePerBuffer = conf.framePerBuffer;
+   config.audioMode = conf.audioMode;
+   
+   //std::cout << "----" << conf.framePerBuffer << std::endl;
+}
+
+sageAudioCircBuf* sageAudioModule::load(char* filename, bool loop, int nframes, long totalframes)
+{
+   /** todo */
+   // give the loading job to fileReader
+   if(fileReader != NULL) {
+      return (fileReader->load(filename, loop, nframes, totalframes));
+   }
+   
+   return NULL;
+}
+
+int sageAudioModule::save(char* filename)
+{
+   /** todo */
+   // give the loading job to fileReader
+   if(fileWriter != NULL) {
+      fileWriter->write(filename, config, bufferList[0]);   // need to change...
+   }
+   
+   return 0;
+}
+
+int sageAudioModule::play(int id)
+{
+   sageAudio* audio = NULL;
+   if(config.audioMode == SAGE_AUDIO_CAPTURE || config.audioMode == SAGE_AUDIO_FWCAPTURE || config.audioMode == SAGE_AUDIO_PLAY) {
+      std::vector<sageAudio*>::iterator iter;
+	  std::cout << "audioList size = " << audioList.size() << std::endl;
+ 	  for( iter = audioList.begin(); iter != audioList.end(); iter++)
+      {
+         audio = (sageAudio*) *iter;
+		 std::cout << "audio id = " << id << " " << audio->getID() << "?" << std::endl;
+         if(audio->getID() == id)
+         {
+            audio->play();
+            return 0;
+         }
+      }
+   } 
+    
+   if(config.audioMode == SAGE_AUDIO_READ) {
+      fileReader->start();
+   } else if(config.audioMode == SAGE_AUDIO_WRITE) {
+      fileWriter->start();
+   }         
+
+   // for testing
+   /*f(config.audioMode == SAGE_AUDIO_APP) {
+      fileWriter->start();
+   }*/
+
+   if(config.audioMode == SAGE_AUDIO_PLAY) {
+      // find it from buffer
+      std::vector<sageAudioCircBuf*>::iterator iterBuffer;
+      sageAudioCircBuf* temp = NULL;
+      for(iterBuffer = bufferList.begin(); iterBuffer != bufferList.end(); iterBuffer++)
+      {
+         temp = (sageAudioCircBuf*) *iterBuffer;
+         if(temp->getAudioId() == id)
+         {
+            break;
+         }
+      }
+      // apply it to audio
+      if((temp != NULL) && (audioList.size() > 0))
+      {
+		 std::cout << " audio id " << temp->getAudioId() << std::endl;
+         audio = audioList[0];
+         audio->reset(id, temp);
+         audio->openStream();
+         audio->play();
+      }
+   }
+
+   return 0;
+}
+
+int sageAudioModule::pause(int id)
+{
+   if(config.audioMode == SAGE_AUDIO_CAPTURE || config.audioMode == SAGE_AUDIO_PLAY) {
+      std::vector<sageAudio*>::iterator iter;
+      sageAudio* audio = NULL;
+      for( iter = audioList.begin(); iter != audioList.end(); iter++)
+      {
+         audio = (sageAudio*) *iter;
+         if(audio->getID() == id)
+         {
+            audio->pause();
+         }
+      }
+   }
+   else if(config.audioMode == SAGE_AUDIO_READ) {
+      //fileReader->();
+   }
+   else if(config.audioMode == SAGE_AUDIO_WRITE) {
+   }   
+   
+   return 0;
+}
+
+int sageAudioModule::stop(int id)
+{
+   sageAudio* audio = NULL;
+   if(config.audioMode == SAGE_AUDIO_CAPTURE || config.audioMode == SAGE_AUDIO_PLAY) {
+      std::vector<sageAudio*>::iterator iter;
+      for( iter = audioList.begin(); iter != audioList.end(); iter++)
+      {
+         audio = (sageAudio*) *iter;
+         if(audio->getID() == id)
+         {
+            audio->stop();
+            audio->closeStream();
+         }
+      }
+   }
+   else if(config.audioMode == SAGE_AUDIO_READ) {
+      fileReader->stop();
+   }
+   else if(config.audioMode == SAGE_AUDIO_WRITE) {
+   }
+
+   if(config.audioMode == SAGE_AUDIO_PLAY) {
+      // delete buffer
+      // audio create for  
+      if(audio != NULL)
+      {
+         // find buffer and delete it
+         std::vector<sageAudioCircBuf*>::iterator iterBuffer;
+         sageAudioCircBuf* temp = NULL;
+		 std::cout << "bufferlist size = " << bufferList.size() << " id "<< std::endl;
+         for(iterBuffer = bufferList.begin(); iterBuffer != bufferList.end(); iterBuffer++)
+         {
+            temp = (sageAudioCircBuf*) *iterBuffer;
+			 std::cout << "buffer  : " << temp->getAudioId() << " " << audio->getID() << std::endl;
+            //if(temp->getAudioId() == audio->getID())
+			if(temp->getAudioId() == id)
+            {
+               bufferList.erase(iterBuffer);
+               break;
+            }
+         }
+         
+		 std::cout << "bufferlist size = " << bufferList.size() << std::endl;
+         // check buffer size 
+         // if buffer size is still more then one
+         if(bufferList.size() > 0)
+         {
+            // return next buffer's audio id
+			 std::cout << "return  : " << bufferList[0]->getAudioId() << std::endl;
+            return bufferList[0]->getAudioId();
+         } else 
+         {
+			std::cout << "delete audio" << std::endl;
+            delete audio;
+            audio = NULL;
+            audioList.clear();
+         }
+      }
+   }
+   
+   return -1;
+}
+
+void sageAudioModule::testDevices()
+{
+   std::vector<sageAudio*>::iterator iter;
+   sageAudio* audio = NULL;
+   iter = audioList.begin();
+   audio = (sageAudio*) *iter;
+   if(audio != NULL)
+   {
+      audio->testDevices();
+   }
+}
+
+std::vector<sageAudioCircBuf*>& sageAudioModule::getBufferList(void)
+{
+   return bufferList;
+}
+
+sageAudioCircBuf* sageAudioModule::createObject(int instID)
+{
+   return createObject(config, instID);
+}
+
+sageAudioCircBuf* sageAudioModule::createObject(sageAudioConfig &conf, int instID)
+{
+   int id = bufferList.size();
+   if(instID >= 0)
+	   id = instID;
+
+   // create shared circular buffer for audio data
+   sageAudioCircBuf *objectBuffer= new sageAudioCircBuf();
+   int bufferBlockNum = 16; 
+   //int bufferBlockNum = 64; 
+   int newBufSize = conf.framePerBuffer * conf.channels;
+
+   int err = -1;
+   // according to mode, create objects and set init values to the objects
+   // create audio 
+   sageAudio* audio = NULL;
+   if(conf.audioMode == SAGE_AUDIO_CAPTURE)   
+   {
+      objectBuffer->init(id, bufferBlockNum, conf.sampleFmt, newBufSize);
+      audio = new sageAudio();
+      err = audio->init(id, conf, SAGE_AUDIO_CAPTURE, objectBuffer);
+      if(err <0) {
+         delete objectBuffer;
+         delete audio;
+         objectBuffer = NULL;
+         audio = NULL;
+         std::cerr << "sageAudioModule::createObject: failed" << std::endl;
+         return NULL;
+      }
+      audio->openStream();   
+      std::cout << "sageAudioModule::createObject: audio object is created" << std::endl;
+   }  
+   else if(conf.audioMode == SAGE_AUDIO_PLAY) 
+   {
+      conf.sampleFmt = SAGE_SAMPLE_FLOAT32;
+      objectBuffer->init(id, bufferBlockNum, conf.sampleFmt, newBufSize);
+      if(audioList.size() == 0)
+      {
+         audio = new sageAudio();
+         err = audio->init(id, conf, SAGE_AUDIO_PLAY, objectBuffer);
+         if(err <0) {
+            delete objectBuffer;
+            delete audio;
+            objectBuffer = NULL;
+            audio = NULL;
+            std::cerr << "sageAudioModule::createObject: failed" << std::endl;
+            return NULL;
+         }
+         audio->openStream();   
+         std::cout << "sageAudioModule::createObject: audio object is created" << std::endl;
+      }
+      else 
+      {
+         std::cout << "sageAudioModule::createObject: audio buffer is created" << std::endl;
+      }         
+   }
+   else if(conf.audioMode == SAGE_AUDIO_FWCAPTURE) 
+   {
+      objectBuffer->init(id, bufferBlockNum, conf.sampleFmt, newBufSize);
+      audio = new sageAudio();
+      err = audio->init(id, conf, SAGE_AUDIO_FWCAPTURE, objectBuffer);
+      if(err <0) {
+         delete objectBuffer;
+         delete audio;
+         objectBuffer = NULL;
+         audio = NULL;
+         std::cerr << "sageAudioModule::createObject: failed" << std::endl;
+         return NULL;
+      }
+      audio->openStream();   
+      std::cout << "sageAudioModule::createObject: audio object is created" << std::endl;
+   }
+
+   bufferList.push_back(objectBuffer);   
+   if(audio)
+      audioList.push_back(audio);
+   
+   return objectBuffer;
+   
+}   
+
+int sageAudioModule::deleteObject(int id)
+{
+
+   stop(id);
+   /** todo */
+   // delete object
+   // delete buffer
+   // remove from the list
+   
+   return 0;
+}
+
+sageAudioCircBuf* sageAudioModule::createBuffer(int instID)
+{   
+   return createBuffer(config);
+}
+
+sageAudioCircBuf* sageAudioModule::createBuffer(sageAudioConfig &conf, int size, int instID)
+{
+   int id = -1;
+   if(instID >= 0)
+	   id = instID;
+
+   // create shared circular buffer for audio data
+   sageAudioCircBuf *objectBuffer= new sageAudioCircBuf();
+   //int bufferBlockNum = 16; 
+   int bufferBlockNum = size; 
+   int newBufSize = conf.framePerBuffer * conf.channels;
+   objectBuffer->init(id, bufferBlockNum, conf.sampleFmt, newBufSize);
+
+   bufferList.push_back(objectBuffer);   
+   
+   std::cout << "sageAudioModule::createBuffer: audio buffer is created" << std::endl;
+
+	config.sampleFmt = conf.sampleFmt;
+	config.samplingRate = conf.samplingRate;
+	config.channels = conf.channels;
+	config.framePerBuffer = conf.framePerBuffer;
+   
+   return objectBuffer;
+   
+}   
+
+void sageAudioModule::setgFrameNum(long frames)
+{
+   gFrameNum = frames;
+}
+long sageAudioModule::getgFrameNum()
+{
+   return gFrameNum;
+}
Index: trunk/src/testing/src/streamInfo.cpp
===================================================================
--- trunk/src/testing/src/streamInfo.cpp	(revision 4)
+++ trunk/src/testing/src/streamInfo.cpp	(revision 4)
@@ -0,0 +1,179 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: streamInfo.cpp - operations for the stream information class
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "streamInfo.h"
+#include "sageBlock.h"
+#include <math.h>
+
+void streamInfo::printImageInfo() 
+{
+   std::cout << "Display Info : " << x << " " << y << " " << width << " " << height << std::endl;
+   std::cout << "Image Info : " << imgCoord.x << " " << imgCoord.y << " " 
+            << imgCoord.width << " " << imgCoord.height << std::endl;
+}   
+
+streamGroup::streamGroup() : rcvNum(0)
+{ 
+   init();
+}
+
+void streamGroup::init() 
+{ 
+   if (streamList.size() > 0)
+      streamList.clear();
+}
+
+int streamGroup::addStream(streamInfo &s)
+{
+   streamList.push_back(s);
+   
+   return 0;
+}
+
+int streamGroup::addImageInfo(sageRect &imgRect)
+{
+   int streamNum = streamList.size();
+   //sageRect dispRect(x, y, width, height);
+   
+   for(int i=0; i<streamNum; i++) {
+      sageRect normRect = streamList[i];
+      normRect.normalize(*this);
+      streamList[i].imgCoord = imgRect*normRect;
+   }
+   
+   return 0;
+}
+
+void streamGroup::createRcvMsg(int winID, char *msgStr)
+{
+   sprintf(msgStr, "%d %d %d %d %d %d %d", winID, x, y, width, height, rcvNum, (int)orientation);   
+}
+
+void streamGroup::createMessage(sageMessage &msg, int code)
+{
+   int streamNum = streamList.size();
+   int dataSize = (streamNum + 1) * 128;   
+   msg.init(0, code, 0, dataSize, NULL);
+   
+   char *info = (char *)msg.getData();
+   sprintf(info, "%d %d %d %d %d ", x, y, width, height, (int)orientation);
+   
+   for (int i=0; i<streamNum; i++) {
+      char str[TOKEN_LEN];
+      sprintf(str, "%d %d %d %d %d ", streamList[i].x, streamList[i].y,
+               streamList[i].width, streamList[i].height, streamList[i].receiverID);
+      strcat(info, str);
+   }
+   
+   dataSize = strlen(info)+1;
+   msg.setSize(dataSize);
+}
+
+void streamGroup::parseMessage(char *str)
+{
+   init();
+   
+   char token[TOKEN_LEN];
+   streamInfo info;
+   sageToken tokenBuf(str);
+   
+   tokenBuf.getToken(token);
+   x = atoi(token);
+   tokenBuf.getToken(token);
+   y = atoi(token);
+   tokenBuf.getToken(token);
+   width = atoi(token);
+   tokenBuf.getToken(token);
+   height = atoi(token);
+   int bufLen = tokenBuf.getToken(token);
+   orientation = (sageRotation)atoi(token);
+   
+   if (bufLen < 1) {
+      std::cout << "streamGroup::parseMessage() : error while parsing stream info message" <<
+         std::endl;
+   }
+   
+   while(bufLen > 0) {
+      bufLen = tokenBuf.getToken(token);
+      if (bufLen < 1)
+         break;
+         
+      info.x = atoi(token);
+
+      tokenBuf.getToken(token);
+      info.y = atoi(token);
+         
+      tokenBuf.getToken(token);
+      info.width = atoi(token);
+         
+      tokenBuf.getToken(token);
+      info.height = atoi(token);
+
+      tokenBuf.getToken(token);
+      info.receiverID = atoi(token);
+         
+      streamList.push_back(info);
+   }
+}
+
+void bridgeStreamGroup::parseMessage(char *str)
+{
+   char token[TOKEN_LEN];
+   bridgeStreamInfo info;
+   sageToken tokenBuf(str);
+   
+   tokenBuf.getToken(token);
+   streamNum = atoi(token);
+
+   if (streamList)
+      delete streamList;
+   streamList = new bridgeStreamInfo[streamNum];
+   
+   for (int i=0; i<streamNum; i++) {
+      if (i>=1)
+         streamList[i].firstID = streamList[i-1].lastID+1;
+         
+      tokenBuf.getToken(token);
+      streamList[i].lastID = atoi(token);
+      
+      tokenBuf.getToken(token);
+      streamList[i].receiverID = atoi(token);
+   }
+}
Index: trunk/src/testing/src/fsClient.cpp
===================================================================
--- trunk/src/testing/src/fsClient.cpp	(revision 4)
+++ trunk/src/testing/src/fsClient.cpp	(revision 4)
@@ -0,0 +1,247 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsClient.cpp - the base class of Free Space Manager Clients
+ *          including the modules to communicate with Free Space Manager
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "fsClient.h"
+
+int fsClient::init(int port)
+{
+   client = new QUANTAnet_tcpClient_c;
+
+   portNum = port;
+   
+   return 0;
+}
+
+int fsClient::init(const char *config, const char *portType)
+{
+   client = new QUANTAnet_tcpClient_c;
+
+   FILE *fp = fopen(config, "r");
+   
+   if (!fp) {
+      printf("fail to open fsClient config file\n");
+      return -1;
+   }
+
+   char token[TOKEN_LEN];
+   while(getToken(fp, token) != EOF) {
+      if (strcmp(token, "fsManager") == 0) {
+         getToken(fp, token);
+         getToken(fp, token);
+         fsIp = new char[strlen(token) + 1];
+         strcpy(fsIp, token);
+      }
+      else if (strcmp(token, portType) == 0) {
+         getToken(fp, token);
+         portNum = atoi(token);
+      } 
+   }
+
+   fclose(fp);
+
+   return 0;
+}
+
+fsClient::~fsClient()
+{
+   if (client)
+      delete client;
+}
+
+int fsClient::connect(char *ip)
+{
+   int retVal = -1;
+
+   char sIp[SAGE_IP_LEN];
+
+   if (!ip)
+      strcpy(sIp, fsIp);
+   else
+      strcpy(sIp, ip);
+
+   client->setSockOptions(QUANTAnet_tcpClient_c::READ_BUFFER_SIZE, 65536);
+   client->setSockOptions(QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE, 65536);
+   
+   if (client->connectToServer(sIp, portNum) < 0) {
+      std::cout << "fsClient::connect : server is not ready" << std::endl; 
+      return -1;
+   }
+   
+   //std::cout << "connected to " << ip << ":" << portNum << std::endl;
+   
+   return 0;
+}
+
+int fsClient::getSelfIP(char *ip)
+{
+   if (!ip) {
+      std::cout << "fsClient : invalid string buffer for self IP" << std::endl;
+      return -1;
+   }
+   
+   client->getSelfIP(ip);
+   return 0;
+}
+
+int fsClient::sendMessage(sageMessage &msg)
+{
+   //int dataSize = msg.getSize() + MESSAGE_HEADER_SIZE;
+   int dataSize = msg.getBufSize();
+   
+   int status = client->write((const char *)msg.getBuffer(), &dataSize,
+               QUANTAnet_tcpClient_c::BLOCKING);
+   if (status != QUANTAnet_tcpClient_c::OK) {
+      std::cerr << "fail to send the message!" << std::endl;
+      std::cerr << "\t status: " << status << std::endl;
+      return -1;
+   }
+
+   return 0;
+}
+
+int fsClient::sendMessage(int code)
+{
+   return sendMessage(FS_ID, code, 0, 0, NULL);
+}
+
+int fsClient::sendMessage(int code, int data)
+{
+   char token[TOKEN_LEN];
+   sprintf(token, "%d", data);
+   return sendMessage(FS_ID, code, 0, strlen(token)+1, (void *)token);
+}
+
+int fsClient::sendMessage(int code, const char* data)
+{
+   return sendMessage(FS_ID, code, 0, strlen(data)+1, (void *)data);
+}
+
+int fsClient::sendMessage(int code, int size, void *data)
+{
+   return sendMessage(FS_ID, code, 0, size, data);
+}
+
+int fsClient::sendMessage(int dst, int code, int data)
+{
+   char dataStr[TOKEN_LEN];
+   sprintf(dataStr, "%d", data);
+   
+   return sendMessage(dst, code, 0, strlen(dataStr)+1, (void *)dataStr);
+}
+
+int fsClient::sendMessage(int dst, int code, int app, const char *data)
+{
+   return sendMessage(dst, code, app, strlen(data)+1, (void *)data);
+}
+
+int fsClient::sendMessage(int dst, int code, int app, int size, void *data)
+{
+   sageMessage msg;
+
+   if (msg.init(dst, code, app, size, data) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+
+   int dataSize = msg.getBufSize();
+   int status = client->write((const char *)msg.getBuffer(), &dataSize,
+               QUANTAnet_tcpClient_c::BLOCKING);
+
+   msg.destroy();
+
+   if (status != QUANTAnet_tcpClient_c::OK) {
+      std::cerr << "fail to send the message!" << std::endl;
+      std::cerr << "\t status: " << status << std::endl;
+      return -1;
+   }
+   
+   return 0;
+}
+
+int fsClient::rcvMessage(sageMessage &msg)
+{
+   char msgSize[MESSAGE_FIELD_SIZE];
+   int dataSize = MESSAGE_FIELD_SIZE;
+
+   int status = client->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::NON_BLOCKING);
+   if (status == QUANTAnet_tcpClient_c::OK) {
+      msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+      dataSize = atoi(msgSize);
+      msg.init(dataSize);
+      dataSize = dataSize - MESSAGE_FIELD_SIZE;
+      client->read((char *)msg.getBuffer()+MESSAGE_FIELD_SIZE, 
+            &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+   }
+   else if (status == QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA)
+      return 0;
+   else
+      return -1;
+   
+   return dataSize;
+}
+
+int fsClient::rcvMessageBlk(sageMessage &msg)
+{
+   char msgSize[MESSAGE_FIELD_SIZE];
+   int dataSize = MESSAGE_FIELD_SIZE;
+
+   int status = client->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+   if (status != QUANTAnet_tcpClient_c::OK) {
+      std::cout << "can't read messages from fsManager" << std::endl;
+#if defined(linux) || defined(__APPLE__)      
+      sleep(1);
+#endif
+
+#ifdef WIN32
+      Sleep(1);
+#endif      
+      return -1;
+   }
+   
+   msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+   dataSize = atoi(msgSize);
+   msg.init(dataSize);
+   dataSize = dataSize - MESSAGE_FIELD_SIZE;
+   client->read((char *)msg.getBuffer()+MESSAGE_FIELD_SIZE, 
+         &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+   return dataSize;
+}
Index: trunk/src/testing/src/sageBuf.cpp
===================================================================
--- trunk/src/testing/src/sageBuf.cpp	(revision 4)
+++ trunk/src/testing/src/sageBuf.cpp	(revision 4)
@@ -0,0 +1,562 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBuf.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBuf.h"
+
+sageBuf::sageBuf() : entryNum(0), full(false), empty(true),
+      readIdx(0), writeIdx(0), bufLen(0)
+{
+   entrySize = sizeof(sageBufEntry);
+	pthread_mutex_init(&bufLock, NULL);
+   pthread_mutex_unlock(&bufLock); 
+	pthread_cond_init(&notEmpty, NULL);   
+}
+
+void sageBuf::reset() 
+{
+   entryNum = 0;
+   full = false;
+   empty = true;
+   resetIdx();
+}
+
+void sageBuf::resetIdx() 
+{
+   readIdx = 0;
+   writeIdx = 0;
+}
+
+void sageBuf::initArray(int size)
+{  
+   bufLen = size;
+   
+   if (bufLen > 0) {
+      entries = new sageBufEntry[bufLen]; 
+      for (int i=0; i<bufLen; i++)
+   	   entries[i] = NULL;
+   }
+   else
+      sage::printLog("sageBuf::initArray : invalid array length %d", size);
+}	   
+
+sageBufEntry sageBuf::operator[](int idx)
+{
+   if (!entries)
+      sage::printLog("sageBuf::operator[] : buffer is NULL");
+   else if (idx >= bufLen || idx < 0)
+      sage::printLog("sageBuf::operator[] : invalid index %d", idx);
+   else      
+      return entries[idx];
+   
+   return NULL;   
+}
+
+sageBuf::~sageBuf()
+{
+   if (entries)
+      delete [] entries;
+}
+
+bool sageSerialBuf::pushBack(sageBufEntry entry) 
+{
+   bool retVal = true;
+   
+   pthread_mutex_lock(&bufLock); 
+   if (full) {     
+      retVal = false;
+   }
+   else {   
+      entries[writeIdx++] = entry;
+      empty = false;
+
+      if (writeIdx >= bufLen)
+         full = true;
+
+      entryNum++;
+      retVal = true;
+   }
+   pthread_mutex_unlock(&bufLock); 
+         
+   return retVal;   
+}
+
+sageBufEntry sageSerialBuf::front() 
+{
+   if (empty)
+      return NULL;
+   
+   return entries[readIdx];
+}   
+
+bool sageSerialBuf::next() 
+{
+   if (empty) {
+      sage::printLog("sageSerialBuf::next : buffer is empty");
+      return false;
+   }
+
+   entries[readIdx] = NULL;      
+   readIdx++;
+   if (readIdx == writeIdx)
+      empty = true;
+   
+   entryNum--;
+         
+   return true;
+}
+
+/*
+int sageSerialBuf::import(sageBuf *buf)
+{
+   if (full) {
+      sage::printLog("sageSerialBuf::import : buffer is full");
+      return -1;
+   }
+   
+   sageSerialBuf *sBuf = (sageSerialBuf *)buf;
+   
+   int importSize = 0, retVal = -1;
+   if ((bufLen-writeIdx) < sBuf->entryNum) {
+      importSize = bufLen-writeIdx;
+      sBuf->readIdx = importSize;
+      writeIdx = bufLen;
+      full = true;
+      retVal = importSize;
+   }   
+   else {
+      importSize = sBuf->entryNum;   
+      sBuf->readIdx = 0;
+      writeIdx += importSize;
+   }
+   
+   entryNum += importSize;
+   void *writePt = (void *)&entries[writeIdx];
+   void *readPt = (void *)&sBuf->entries[sBuf->readIdx];
+
+   memcpy(writePt, readPt, importSize*entrySize);
+      
+   return retVal;
+}
+*/
+
+bool sageCircBufSingle::pushBack(sageBufEntry entry)
+{
+   if (full) {
+      sage::printLog("sageCircBufSingle::pushBack : buffer is full");
+      return false;
+   }
+         
+   pthread_mutex_lock(&bufLock);
+   entries[writeIdx] = entry;
+   
+   writeIdx++;      
+   if (writeIdx >= bufLen)
+      writeIdx = writeIdx - bufLen;
+      
+   if (readIdx == writeIdx)   
+      full = true;
+   
+   if (blocking) {
+      empty = false;
+      pthread_cond_signal(&notEmpty);
+   }
+   else
+      empty = false;   
+   
+   entryNum++;
+   pthread_mutex_unlock(&bufLock);   
+   
+   return true;   
+}
+
+void sageCircBufSingle::releaseLock() 
+{ 
+   blocking = false;
+   empty = false;
+   active = false;
+   pthread_cond_signal(&notEmpty);    
+}
+
+sageBufEntry sageCircBufSingle::front()
+{
+   if (blocking) {
+      pthread_mutex_lock(&bufLock);
+      while(empty) {
+         pthread_cond_wait(&notEmpty, &bufLock);
+      }   
+      pthread_mutex_unlock(&bufLock);
+   }  
+   else if (empty)
+      return NULL;
+   
+   return entries[readIdx];   
+}
+
+bool sageCircBufSingle::next()
+{
+   if (empty) {
+      return false;
+   }
+      
+   pthread_mutex_lock(&bufLock);    
+   entries[readIdx] = NULL;
+   while(!empty && !entries[readIdx]) {
+      readIdx++;
+      if (readIdx >= bufLen)
+         readIdx = readIdx - bufLen;
+
+      if (readIdx == writeIdx)
+         empty = true;
+   }
+   
+   entryNum--;
+   full = false;
+   pthread_mutex_unlock(&bufLock);
+            
+   return true;
+}
+
+sageCircBuf::sageCircBuf(int len)
+{
+	initArray(len);
+	pthread_cond_init(&notFull, NULL);
+   pthread_cond_init(&notEmpty, NULL);
+}
+
+bool sageCircBuf::pushBack(sageBufEntry entry, bool blk)
+{
+   if (blk && full) {
+      pthread_mutex_lock(&bufLock);
+      while(full) {
+         pthread_cond_wait(&notFull, &bufLock);
+      }   
+      pthread_mutex_unlock(&bufLock); 
+   }
+	else if (!blk && full)
+		return false;
+         
+   entries[writeIdx] = entry;
+   
+	pthread_mutex_lock(&bufLock);     
+   writeIdx++;      
+   if (writeIdx >= bufLen)
+      writeIdx = writeIdx - bufLen;
+
+   if (readIdx == writeIdx)   
+      full = true;
+   
+	entryNum++;
+   empty = false;
+   pthread_cond_signal(&notEmpty);
+   pthread_mutex_unlock(&bufLock);   
+   
+   return true;   
+}
+
+sageBufEntry sageCircBuf::front(bool blk)
+{
+   if (blk) {
+      pthread_mutex_lock(&bufLock);
+      while(empty) {
+         pthread_cond_wait(&notEmpty, &bufLock);
+      }   
+      pthread_mutex_unlock(&bufLock);
+   }  
+   else if (empty)
+      return NULL;
+   
+   return entries[readIdx];   
+}
+
+bool sageCircBuf::next()
+{
+   if (empty) {
+      return false;
+   }
+      
+   pthread_mutex_lock(&bufLock);    
+   entries[readIdx] = NULL;
+   while(!empty && !entries[readIdx]) {
+      readIdx++;
+      if (readIdx >= bufLen)
+         readIdx = readIdx - bufLen;
+
+      if (readIdx == writeIdx)
+         empty = true;
+   }
+   
+   entryNum--;
+   full = false;
+	pthread_cond_signal(&notFull);
+   pthread_mutex_unlock(&bufLock);
+            
+   return true;
+}
+
+void sageCircBuf::releaseLock() 
+{ 
+   empty = false;
+	full = false;
+   pthread_cond_signal(&notEmpty);
+	pthread_cond_signal(&notFull);  
+}
+
+sageRAB::sageRAB(int len) : head(-1), tail(-1), freeHead(0), freeTail(len-1)
+{
+   initArray(len);
+   nextIdx = new int[len]; 
+   for (int i=0; i<len; i++)
+   	nextIdx[i] = i+1;
+   nextIdx[len-1] = -1;   
+}
+
+void sageRAB::next(int &idx)
+{
+   if (idx < 0 || idx >= bufLen) {
+      sage::printLog("sageRAB::next : invalid index");
+      return;
+   }   
+   
+   pthread_mutex_lock(&bufLock);
+   idx = nextIdx[idx];
+   pthread_mutex_unlock(&bufLock);
+}
+
+bool sageRAB::insert(sageBufEntry entry)
+{
+   bool flag = true;
+
+   if (freeHead > -1) {
+      pthread_mutex_lock(&bufLock);
+      entries[freeHead] = entry;
+      
+      if (tail == -1) {
+         tail = head = freeHead;
+      }
+      else {
+         nextIdx[tail] = freeHead;
+         tail = freeHead;
+      }   
+         
+      freeHead = nextIdx[freeHead];
+      if (freeHead < 0)
+         freeTail = -1;
+      
+      nextIdx[tail] = -1;
+      pthread_mutex_unlock(&bufLock);
+      
+      entryNum++;
+   }
+   else {
+      sage::printLog("sageRAB::insert : buffer is full");
+      flag = false;
+   }
+
+   return flag;   
+}
+
+bool sageRAB::remove(int idx, int prev)
+{
+   pthread_mutex_lock(&bufLock);
+   if (idx == head) {
+      head = nextIdx[idx];
+      if (idx == tail)
+         tail = -1;
+   }
+   else {
+      if (idx == tail) {
+         tail = prev;
+      }   
+      nextIdx[prev] = nextIdx[idx];
+   }
+      
+   nextIdx[idx] = -1;
+   entries[idx] = NULL;
+   
+   if (freeHead < 0) {
+      freeHead = freeTail = idx;
+   }
+   else {
+      nextIdx[freeTail] = idx;
+      freeTail = idx;
+   }
+   pthread_mutex_unlock(&bufLock);
+      
+   entryNum--;
+            
+   return true;
+}
+
+int sageCircBufMulti::addReader(int id)
+{
+   pthread_mutex_lock(&bufLock);
+   readers[id].readIdx = readIdx;
+   readers[id].empty = empty;
+   readers[id].active = true;
+ 	maxReaderID = MAX(id, maxReaderID);
+	pthread_mutex_unlock(&bufLock);
+   
+	return 0;
+}
+
+bool sageCircBufMulti::pushBack(sageBufEntry entry)
+{
+   if (full) {
+      sage::printLog("sageCircBufMulti::pushBack : buffer is full");
+      return false;
+   }
+         
+   pthread_mutex_lock(&bufLock);
+   entries[writeIdx] = entry;
+   
+   writeIdx++;      
+   if (writeIdx >= bufLen)
+      writeIdx = writeIdx - bufLen;
+      
+   if (readIdx == writeIdx)   
+      full = true;
+   
+   empty = false;
+   for (int i=0; i<=maxReaderID; i++) {
+      if (readers[i].active)
+         readers[i].empty = false;
+   }
+
+   if (blocking) {
+      pthread_cond_broadcast(&notEmpty);
+   }
+   
+   entryNum++;
+   pthread_mutex_unlock(&bufLock);   
+   
+   return true;   
+}
+
+sageBufEntry sageCircBufMulti::front(int id)
+{
+   if (!readers[id].active)
+      return NULL;
+      
+   if (blocking) {
+      pthread_mutex_lock(&bufLock);
+      while(readers[id].empty) {
+         pthread_cond_wait(&notEmpty, &bufLock);
+      }   
+      pthread_mutex_unlock(&bufLock);
+   }  
+   else if (readers[id].empty)
+      return NULL;
+   
+   return entries[readers[id].readIdx];   
+}
+
+sageBufEntry sageCircBufMulti::next(int id)
+{
+   if (readers[id].empty || !readers[id].active) {
+      return NULL;
+   }
+
+   pthread_mutex_lock(&bufLock);    
+   readers[id].readIdx++;
+   if (readers[id].readIdx >= bufLen)
+      readers[id].readIdx = readers[id].readIdx - bufLen;
+   
+   int dist = distToWriteIdx(readers[id].readIdx);
+   if (dist == 0) 
+      readers[id].empty = true;
+
+   int maxDist = dist;
+   
+   for (int i=0; i<=maxReaderID; i++) {
+      if (readers[i].active)
+         maxDist = MAX(maxDist, distToWriteIdx(readers[i].readIdx));
+   }
+   pthread_mutex_unlock(&bufLock);
+   
+   sageBufEntry retVal = entries[readIdx];
+   
+   if (maxDist == dist)
+      next();
+   else {
+      retVal = NULL;   
+   }   
+            
+   return retVal;
+}
+
+bool sageCircBufMulti::next()
+{
+   pthread_mutex_lock(&bufLock);
+   readIdx++;
+   if (readIdx >= bufLen)
+      readIdx = readIdx - bufLen;
+
+   if (readIdx == writeIdx) {
+      empty = true;
+   }
+   entryNum--;
+   full = false;
+   pthread_mutex_unlock(&bufLock);
+   
+   return true;
+}
+
+int sageCircBufMulti::distToWriteIdx(int ridx)
+{
+   int dist = 0;
+
+   if (writeIdx >= ridx)
+      dist = writeIdx - ridx;
+   else
+      dist = writeIdx - ridx + bufLen;
+
+   return dist;
+}
+
+void sageCircBufMulti::removeReader(int id)
+{ 
+   pthread_mutex_lock(&bufLock);
+   readers[id].active = false;
+   if (blocking && readers[id].empty) {
+      readers[id].empty = false;
+      pthread_cond_broadcast(&notEmpty);
+   }   
+   pthread_mutex_unlock(&bufLock);
+}
Index: trunk/src/testing/src/sageAudioBridge.cpp
===================================================================
--- trunk/src/testing/src/sageAudioBridge.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioBridge.cpp	(revision 4)
@@ -0,0 +1,424 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioBridge.cpp - the SAGE component to distribute audio samples to multiple
+ *         SAGE nodes 
+ * Author :  Hyejung Hur, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageAudioBridge.h"
+#include "messageInterface.h"
+#include "sageTcpModule.h"
+#include "sageUdpModule.h"
+#include "sageBlock.h"
+#include "sageEvent.h"
+#include "sageSharedData.h"
+
+sageAudioDup::sageAudioDup(int appID)
+: instID(appID), initialized(false), 
+  rcvNodeNum(0), bridgeEnd(false), instNWObj(NULL)
+{
+}
+
+sageAudioDup::~sageAudioDup(void)
+{
+   shutdownAllStreams();
+   
+	std::vector<streamBridgeParam*>::iterator i;
+	streamBridgeParam* param = NULL;
+   for (i = paramList.begin(); i != paramList.end(); i++) {
+      param = (streamBridgeParam*)*i;
+		delete param;
+		param = NULL;
+   }
+	paramList.clear();
+}
+
+int sageAudioDup::init(void)
+{
+	return 0;
+}
+
+int sageAudioDup::addStream(char *msg, streamProtocol *nwObj)
+{
+   // sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d", config.streamType, winID,
+   //  config.nodeNum, blockSize, config.syncMode, (int)config.sampleFmt, 
+   //  config.samplingRate, config.channels, config.framePerBuffer,  config.frameRate);
+   // 100 6881394 1 2176 0 1 44100 2 512 1      
+   sscanf(msg, "%d %d %d %d %d %d %d %d %d %d %d %d", &senderID, &streamType, &instID, &sailNodeNum, &blockSize, 
+		&syncType, &sampleFmt, &samplingRate, &channels, &framePerBuffer, &frameRate, &keyframe);
+   
+   std::cout << "stream info " << msg << std::endl;
+   instNWObj = nwObj;
+   initialized = true;
+
+   int bytesPerSample;
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         break;
+      case SAGE_SAMPLE_INT16 :
+         bytesPerSample = sizeof(short);
+         break;
+      case SAGE_SAMPLE_INT8 :
+         bytesPerSample = sizeof(int);
+         break;
+      case SAGE_SAMPLE_UINT8 :
+         bytesPerSample = sizeof(unsigned int);
+         break;            
+      default :
+         break;
+   }
+   audioNBlock.setSampleFormat((sageSampleFmt)sampleFmt);
+   audioNBlock.setSampleRate(samplingRate);
+   audioNBlock.setChannel(channels);
+   audioNBlock.setFramePerBuffer(framePerBuffer);
+   audioNBlock.setBytesPerSample(bytesPerSample);   
+   audioNBlock.initBuffer(blockSize);   
+
+   char regMsg[REG_MSG_SIZE];
+   std::vector<streamBridgeParam*>::iterator i;
+   streamBridgeParam* param = NULL;
+   sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d", streamType, instID, sailNodeNum, blockSize, 
+		syncType, (int)sampleFmt, samplingRate, channels, framePerBuffer, frameRate, keyframe);
+
+   int sendPort;
+   for (i = paramList.begin(); i != paramList.end(); i++) {
+      param = (streamBridgeParam*)*i;
+      if(param->active == false)
+      {
+         sendPort = param->sendPort + instNWObj->getProtocol();
+         instNWObj->setConfig(sendPort, 0, 0);
+         param->rcvID = nwObj->connect(param->rcvIP, regMsg);
+         param->active = true;
+         std::cout << " Add stream : port : " << sendPort << " connected "<< std::endl;
+      }
+   }
+   	   
+   nwStreamThreadParam* threadparam = new nwStreamThreadParam;
+   threadparam->This = this;
+   threadparam->nwObj = nwObj;
+   if (pthread_create(&thId, 0, nwStreamThread, (void*)threadparam) != 0) 
+   {
+      sage::printLog("sageAudioDup : can't create network stream thread");
+      return -1;
+   }
+
+   return 0;
+}
+  
+int sageAudioDup::addReceiver(char *msg, int fsIdx)
+{
+	// ??????
+
+   std::cout << "fs message " << msg << std::endl;
+
+   char token[TOKEN_LEN];
+   sageToken tokenBuf(msg);
+   tokenBuf.getToken(token);  // port #
+   int basePort = atoi(token);
+   int sendPort = basePort;
+   if(initialized)
+   {
+      sendPort += instNWObj->getProtocol();
+      instNWObj->setConfig(sendPort, 0, 0);
+      std::cout << " addReceiver : port : " << sendPort << std::endl;
+   }
+
+   tokenBuf.getToken(token);  // node #
+   int nodeNum = atoi(token);
+
+   int winID = atoi(sage::tokenSeek(msg,nodeNum*2+2));
+   std::cout << "winID : " << winID << std::endl;
+
+   streamBridgeParam* param = NULL;
+   char rcvIP[SAGE_IP_LEN];
+
+   char regMsg[REG_MSG_SIZE];
+   sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d", streamType, winID, sailNodeNum, blockSize, 
+							syncType, (int)sampleFmt, samplingRate, channels, framePerBuffer, frameRate, keyframe);
+
+   char* ip = NULL;
+   for (int i=0; i<nodeNum; i++) {
+      param = new streamBridgeParam;	
+      tokenBuf.getToken(rcvIP);
+      tokenBuf.getToken(token);
+		
+      param->rcvIP = (char*) malloc(sizeof(char) * SAGE_IP_LEN);
+      strcpy(param->rcvIP, rcvIP);
+      param->nodeID = atoi(token);
+      param->fsIdx = fsIdx;
+      param->sendPort = basePort;
+      param->active = false;
+      if (initialized ) {
+         std::cout << "connect - add receiver" << std::endl;
+         instNWObj->setConfig(sendPort, 0, 0);
+         param->rcvID = instNWObj->connect(param->rcvIP, regMsg);
+         param->active = true;
+      }   
+      paramList.push_back(param);
+   }
+   rcvNodeNum += nodeNum;
+
+   std::cout << "receiver added " << std::endl;
+
+   return 0;
+} 
+  
+void* sageAudioDup::nwStreamThread(void *args)
+{
+	nwStreamThreadParam *argparam = (nwStreamThreadParam *)args;
+	streamProtocol *nwObj = (streamProtocol *)argparam->nwObj;
+	sageAudioDup *This = (sageAudioDup *)argparam->This;	
+	
+	int rcvSize, streamSize;
+	std::vector<streamBridgeParam*>::iterator i;	
+	streamBridgeParam* param= NULL;
+
+	// receive data -> send data
+	while (!This->bridgeEnd) {
+
+		rcvSize = nwObj->recv(This->senderID, &This->audioNBlock, SAGE_BLOCKING);
+      if (rcvSize <= 0) {
+         sage::printLog("sageAudioDup::nwStreamThread : exit loop");
+			break;
+      }
+      else {
+			// send data
+			for (i = This->paramList.begin(); i != This->paramList.end(); i++) {
+				param = (streamBridgeParam*)*i;
+            if(param == NULL) continue;
+				if (param->active && param->rcvID >= 0) {
+					streamSize = nwObj->send(param->rcvID, &This->audioNBlock, SAGE_BLOCKING);	
+				}
+			}		
+		
+		}	
+	
+	}
+
+	sage::printLog("sageAudioDup::nwStreamThread : exit");   
+	pthread_exit(NULL);
+	return NULL;
+} 
+
+void sageAudioDup::shutdownStreams(int fsIdx)
+{
+   streamBridgeParam* param= NULL;  
+   std::vector<streamBridgeParam*>::iterator i;
+   for (i = paramList.begin(); i != paramList.end(); i++) {
+      param = (streamBridgeParam*)*i;
+      if (param->fsIdx == fsIdx && param->active) {
+         param->active = false;
+         instNWObj->close(param->rcvID, SAGE_SEND);
+      }
+   }   
+}
+
+void sageAudioDup::shutdownAllStreams(void)
+{
+	bridgeEnd = true;
+   if (instNWObj)
+      instNWObj->close(senderID, SAGE_ARCV);
+
+   streamBridgeParam* param= NULL;  
+   std::vector<streamBridgeParam*>::iterator i;
+   for (i = paramList.begin(); i != paramList.end(); i++) {
+		param = (streamBridgeParam*)*i;
+		if (param->active) {
+         instNWObj->close(param->rcvID, SAGE_SEND);
+      }
+   }   
+      
+   pthread_join(thId, NULL);
+}
+	
+// ip, port  : IP address and port number where listening audio stream connections
+// inf  :  message communication object for sending messages to SAIL.
+sageAudioBridge::sageAudioBridge(char *ip, int port, messageInterface *inf, bridgeSharedData *sh)
+      : audioPort(port), bridgeEnd(false), msgInf(inf), shared(sh)
+{
+   strcpy(audioIP, ip);
+   
+	tcpObj = NULL;
+	udpObj = NULL;
+	for(int i=0; i < MAX_INST_NUM; i++) {
+	   dupList[i] = NULL;
+	}
+
+	initNetworks();
+}
+
+sageAudioBridge::~sageAudioBridge()
+{
+   for(int i=0; i < MAX_INST_NUM; i++) {
+		if(dupList[i] != NULL) {
+			delete dupList[i];
+			dupList[i] = NULL;
+		}
+	}
+	
+}
+
+int sageAudioBridge::initNetworks()
+{
+	// open audio port
+	
+	// nwCfg setting?????? 
+	tcpObj = new sageTcpModule;
+	if (tcpObj->init(SAGE_ARCV, audioPort, nwCfg) == 1) {
+		sage::printLog("sageAudioBridge is already running");
+		bridgeEnd = true;
+		return -1;
+	}
+	sage::printLog("SAGE Audio Bridge : tcp network object was initialized successfully " );
+
+	udpObj = new sageUdpModule;
+	udpObj->init(SAGE_ARCV, audioPort+(int)SAGE_UDP, nwCfg);
+	sage::printLog("SAGE Audio Bridge : udp network object was initialized successfully" );
+
+   pthread_t thId;
+	nwAudioCheckThreadParam *param = new nwAudioCheckThreadParam;
+	param->This = this;
+	param->nwObj = tcpObj;
+
+   if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+		sage::printLog("sageAudioBridge::initNetwork : can't create network checking thread");
+		return -1;
+	}
+
+   param = new nwAudioCheckThreadParam;
+	param->This = this;
+	param->nwObj = udpObj;
+	if (pthread_create(&thId, 0, nwCheckThread, (void*)param) != 0) {
+		sage::printLog("sageAudioBridge::initNetwork : can't create network checking thread");
+		return -1;
+	}
+
+	return 0;
+}
+
+void* sageAudioBridge::nwCheckThread(void *args)
+{
+	nwAudioCheckThreadParam *param = (nwAudioCheckThreadParam *)args;
+	streamProtocol *nwObj = (streamProtocol *)param->nwObj;
+	sageAudioBridge *This = (sageAudioBridge *)param->This;
+	int senderID = -1;
+	char regMsg[SAGE_EVENT_SIZE];
+   if (nwObj) {
+		while (!This->bridgeEnd) {
+			senderID = nwObj->checkConnections(regMsg);
+			if (senderID >= 0 && !This->bridgeEnd) {
+            This->shared->eventQueue->appendEvent(EVENT_AUDIO_CONNECTION, regMsg, (void *)nwObj);
+            std::cout << "detect new connection " << regMsg << std::endl;
+				//This->initStreams(regMsg, nwObj);
+			}
+		}
+	}
+
+	sage::printLog("sageAudioBridge::nwCheckThread : exit");   
+	pthread_exit(NULL);
+	return NULL;
+}
+
+int sageAudioBridge::initStreams(char *msg, streamProtocol *nwObj)
+{
+   int senderID, instID, streamType;
+   sscanf(msg, "%d %d %d", &senderID, &streamType, &instID);
+	//cout << "sageAudioBridge::initStreams --> senderID=" << senderID << " instID=" << instID << endl;
+   
+	if(instID > MAX_INST_NUM) return -1;
+			
+	sageAudioDup *inst = dupList[instID];
+	if(inst == NULL) return -1;
+
+	inst->addStream(msg, nwObj);
+	
+	return 0;
+}
+
+int sageAudioBridge::startAudioStream(int instID, int sailClientID)
+{
+    if(instID > MAX_INST_NUM) return -1;
+			
+    sageAudioDup *inst = dupList[instID];
+    if(inst == NULL)
+    {
+	inst = new sageAudioDup(instID);
+	dupList[instID] = inst;
+    }
+   
+    char audioInitMsg[TOKEN_LEN];
+    sprintf(audioInitMsg, "%d 1 %s 0", audioPort, audioIP);  
+    std::cout << "start audio stream " << audioInitMsg <<  std::endl; 
+    msgInf->msgToClient(sailClientID, 0, SAIL_CONNECT_TO_ARCV, audioInitMsg);
+   
+    return 0;
+}
+
+int sageAudioBridge::duplicate(int instID, char *msg, int fsIdx)
+{
+	if (instID > MAX_INST_NUM) return -1;
+	
+   sageAudioDup *inst = dupList[instID];
+	if (inst) {
+   	inst->addReceiver(msg, fsIdx);
+   }
+   
+	return 0;
+}
+
+int sageAudioBridge::shutdownStreams(int instID, int fsIdx)
+{
+   sageAudioDup *inst = dupList[instID];
+	if (inst) {
+      inst->shutdownStreams(fsIdx);
+   }
+   
+   return 0;
+}
+
+int sageAudioBridge::shutdownDup(int instID)
+{
+	// NEED TO CHANGE
+	sageAudioDup *inst = dupList[instID];
+	if (inst) {
+		delete inst;
+		dupList[instID] = NULL;
+	}
+	
+	return 0;
+}
Index: trunk/src/testing/src/appleMultiContext.cpp
===================================================================
--- trunk/src/testing/src/appleMultiContext.cpp	(revision 4)
+++ trunk/src/testing/src/appleMultiContext.cpp	(revision 4)
@@ -0,0 +1,270 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: appleMultiContext.cpp
+ * Author : Luc Renambot, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "appleMultiContext.h"
+
+#if defined(__APPLE__)
+
+// Shared AGL pixel format and context:
+AGLPixelFormat agl_fmt = 0;
+AGLContext agl_ctx = 0;
+
+// Critical section object:
+MPCriticalRegionID cr = 0;
+
+///////////////////////////
+// Define a playback window
+
+OSStatus
+keyboard_handler(EventHandlerCallRef,
+   EventRef event,
+   void *)
+{
+   unsigned char key;
+   GetEventParameter(event,kEventParamKeyMacCharCodes,typeChar,0,sizeof(key),0,&key);
+ 
+   MPEnterCriticalRegion(cr,kDurationForever);
+
+   if (key == 27) {
+      exit(0);
+   }
+
+   MPExitCriticalRegion(cr);
+
+   return noErr;
+}
+
+
+Window::Window(const Rect & rect, int fulls)
+{ 
+   m_rect = rect;
+   m_win = 0;
+   m_init = false;
+   m_ctx = 0;
+  
+   //
+   // Create the Carbon window:
+   OSStatus s;
+
+   if ( fulls ) {
+      s = CreateNewWindow(kOverlayWindowClass,
+         kWindowStandardHandlerAttribute | kWindowCompositingAttribute,
+         &m_rect, &m_win);
+      if(s != noErr) {
+         fprintf(stderr,"failed to create window at %i,%i,%i,%i\n",m_rect.left,m_rect.top,m_rect.right,m_rect.bottom);
+         abort();
+      }
+
+      // Hide Cursor
+      CGCaptureAllDisplays();
+      CGDisplayHideCursor(kCGDirectMainDisplay); 
+      CGReleaseAllDisplays();
+    
+   }
+   else
+   {
+      // just a little offset when opening the window
+      s = CreateNewWindow(kDocumentWindowClass,
+         kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute| kWindowInWindowMenuAttribute,
+         &m_rect, &m_win);
+      if(s != noErr) {
+         fprintf(stderr,"failed to create window at %i,%i,%i,%i\n",m_rect.left,m_rect.top,m_rect.right,m_rect.bottom);
+         abort();
+      }
+
+      // Put a title
+      SetWindowTitleWithCFString (m_win, CFSTR("SAGE GStream Receiver"));
+   }
+
+   SetWindowActivationScope(m_win,kWindowActivationScopeAll);
+   ShowWindow(m_win);
+   ActivateWindow(m_win, true);
+
+
+   if ( ! fulls ) {
+      Rect arect;
+      short hGlobal, vGlobal;
+      GetWindowBounds(m_win, kWindowStructureRgn, &arect);
+      MoveWindow (m_win, arect.left, (arect.top < 0) ? 40 : arect.top+50, true);
+   }
+
+   // Create context
+   m_ctx = aglCreateContext(agl_fmt,0);
+   if(m_ctx == 0) {
+      fprintf(stderr,"failed to create OpenGL context\n");
+      abort();
+   }
+
+   // Set the global context, shared by other windows:
+   if(agl_ctx == 0) {
+      agl_ctx = m_ctx;
+   }
+
+   //
+   // All your window are belong to us:
+   GLboolean e;
+   e = aglSetDrawable(m_ctx,GetWindowPort(m_win));
+   if(!e) {
+      fprintf(stderr,"failed aglSetDrawable\n");
+      abort();
+   }
+
+   // Initialize the OpenGL
+   aglSetCurrentContext(m_ctx);
+   glViewport(0,0,m_rect.right - m_rect.left,m_rect.bottom - rect.top);
+    
+    /* glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(m_rect.left,m_rect.right,m_rect.top,m_rect.bottom,-1,1);
+    
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    */
+    
+   glClearColor(0,0,0,1);
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   aglSwapBuffers(m_ctx);
+}
+
+// Note that this function has to be called once. To recreate textures, call the renewTex() member function.
+int appleMultiContext::init(struct sageDisplayConfig &cfg)
+{
+   // Make this a "faceful app" that can receive input events:
+   ProcessSerialNumber psn;
+   OSStatus s;
+   s = GetCurrentProcess(&psn); assert(s == noErr);
+   s = TransformProcessType(&psn,kProcessTransformToForegroundApplication); assert(s == noErr);
+   s = SetFrontProcess(&psn); assert(s == noErr);
+
+   singleContext = false;
+   
+   configStruct = cfg;
+   tileNum = cfg.dimX * cfg.dimY;
+   if (tileNum > MAX_TILES_PER_NODE) {
+      sage::printLog("displayContext::init() : The tile number exceeds the maximum"); 
+      return -1;
+   }
+
+   if (!winCreatFlag) {
+      //
+      // Set up us the OpenGL:
+      // Choose global pixel format:
+      static GLint agl_fmt_list[] = { AGL_RGBA,
+               AGL_RED_SIZE, 8,
+               AGL_GREEN_SIZE, 8,
+               AGL_BLUE_SIZE, 8,
+               AGL_ALPHA_SIZE, 8,
+               AGL_DEPTH_SIZE, 24,
+               AGL_DOUBLEBUFFER,
+               AGL_NONE };
+      agl_fmt = aglChoosePixelFormat(0,0,agl_fmt_list);
+      if (agl_fmt == 0) {
+         fprintf(stderr,"failed to choose OpenGL pixel format\n");
+         abort();
+      }
+     
+      // The critical region object
+      MPCreateCriticalRegion(&cr);
+
+      // Install event handlers
+      //
+      EventTargetRef target = GetApplicationEventTarget();
+     
+      EventTypeSpec eventTypes[] = {
+         { kEventClassKeyboard, kEventRawKeyDown }
+      };
+     
+      InstallEventHandler(target,NewEventHandlerUPP(keyboard_handler),
+               sizeof(eventTypes) / sizeof(EventTypeSpec),eventTypes,
+               0,0);
+
+      // Create Windows
+      for (int k = 0; k < tileNum; k++) {
+         int tileX = (k % cfg.dimX) * cfg.tileRect[k].width;
+         int tileY = (k / cfg.dimX) * cfg.tileRect[k].height;
+
+         Rect wrect;
+         wrect.left = tileX; // cfg.tileRect[k].x;
+         wrect.top = tileY;  // cfg.tileRect[k].y;
+         wrect.right  = wrect.left + cfg.tileRect[k].width;
+         wrect.bottom = wrect.top  + cfg.tileRect[k].height;
+                  
+         //fprintf(stderr,"Create window %d at %i,%i,%i,%i\n",k, wrect.left,wrect.top,wrect.right,wrect.bottom);
+
+         windows[k] = new Window(wrect, configStruct.fullScreenFlag);
+         windows[k]->beginGL();
+         glEnable(GL_DEPTH_TEST);
+         glEnable(GL_TEXTURE_2D);
+      }
+      
+      winCreatFlag = true;
+   }
+
+   return 0;
+} // End of appleMultiContext::init()
+
+void appleMultiContext::setupViewport(int i, sageRect &tileRect)
+{
+   windows[i]->beginGL();
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void appleMultiContext::changeBackground(int red, int green, int blue)
+{
+   for (int i=0; i<tileNum; i++) { 
+      windows[i]->contextSwitching();
+      glClearColor((float)red/255.0, (float)green/255.0, (float)blue/255.0, 0.0f);
+   }   
+}
+
+void appleMultiContext::checkEvent() 
+{
+   // Event management for Apple
+   EventRef theEvent;
+   EventTargetRef theTarget;
+   theTarget = GetEventDispatcherTarget();
+   while (ReceiveNextEvent(0, NULL,kEventDurationNoWait,true, &theEvent) == noErr) {
+      SendEventToEventTarget (theEvent, theTarget);
+      ReleaseEvent(theEvent);
+   }
+}
+
+#endif
Index: trunk/src/testing/src/fsCore.cpp
===================================================================
--- trunk/src/testing/src/fsCore.cpp	(revision 4)
+++ trunk/src/testing/src/fsCore.cpp	(revision 4)
@@ -0,0 +1,1363 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsCore.cpp - the core part of the Free Space Manager processing
+ *         user commands to run applications or send appropriate orders 
+ *         to each part of SAGE.
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *   
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "fsCore.h"
+#include "fsManager.h"
+#include "streamInfo.h"
+#include "misc.h"
+#include "displayInstance.h"
+#include "sageVirtualDesktop.h"
+#include "streamProtocol.h"
+#include "sageDrawObject.h"
+
+FILE *logFile;
+
+fsCore::fsCore()
+{
+   fsm = NULL;
+}
+
+fsCore::~fsCore()
+{
+}
+
+int fsCore::init(fsManager *m)
+{
+   fsm = m;
+   winSteps = (int)ceil(m->winTime/20.0);
+   logFile = fopen("window.log","w+");
+   return 0;
+}
+
+int fsCore::initDisp(appInExec* app)
+{
+   displayInstance *disp = new displayInstance(fsm, fsm->m_execIndex, app);
+   fsm->dispList.push_back(disp);
+   
+   return 0;
+}
+
+int fsCore::initAudio()
+{
+   appInExec *appExec;
+   int execNum = fsm->execList.size();
+
+   //int msgLen = 8 + SAGE_IP_LEN * execNum;
+   int msgLen = 8 + SAGE_IP_LEN * fsm->vdtList[0]->getNodeNum();
+   char *msgStr = new char[msgLen];
+   memset(msgStr, 0, msgLen);
+
+   int i = execNum -1;
+	i =  fsm->m_execIndex;
+   appExec = fsm->execList[i];
+   if (!appExec) {
+      //continue;
+   }
+   else 
+   {
+      fsm->vdtList[0]->generateAudioRcvInfo(fsm->rInfo.audioPort, msgStr);
+      //printf("initaudio --> %s\n", msgStr);
+      char conMessage[TOKEN_LEN];
+      sprintf(conMessage, "%s %d", msgStr, i);
+      if (fsm->sendMessage(appExec->sailClient, SAIL_CONNECT_TO_ARCV, conMessage) < 0) {
+			sage::printLog("fsCore : %s(%d) is stuck or shutdown", appExec->appName, i);
+			clearAppInstance(i);
+		}		
+   }
+
+   return 0;
+}
+
+void fsCore::clearAppInstance(int id)
+{
+	int index = 0;
+	appInExec* app = findApp(id, index);
+	if (!app)
+	{
+		std::cout << "fsCore::clearAppInstance() : ERROR : " << id << " app instance is not found" << std::endl;
+		return;
+	}
+   
+   // clear app instance on display nodes
+   fsm->sendToAllRcvs(RCV_SHUTDOWN_APP, id);
+
+   // clear app instance on audio nodes
+   if (app->audioOn) {
+      std::vector<int> arcvList = fsm->vdtList[0]->getAudioRcvClientList();
+      int arcvNum = arcvList.size();
+      for(int i=0; i<arcvNum; i++)
+         fsm->sendMessage(arcvList[i], ARCV_SHUTDOWN_APP, id);
+   }
+      
+   // clear app instace on ui clients
+   int uiNum = fsm->uiList.size();
+   for (int j=0; j<uiNum; j++) {
+      if (fsm->uiList[j] < 0)
+         continue;
+
+      if (fsm->sendMessage(fsm->uiList[j], UI_APP_SHUTDOWN, id) < 0) {
+         sage::printLog("fsCore::clearAppInstance() : uiClient(%d) is stuck or shutdown", j);
+         fsm->uiList[j] = -1;
+      }
+   }	
+
+	// RE-GENERATING ID (1/2) 
+	//fsm->m_execIDList[id] = 0;
+   // release data structure
+  	delete app;
+	app = NULL;
+	fsm->execList.erase(fsm->execList.begin() + index);
+   
+	displayInstance* temp_disp = (displayInstance*) fsm->dispList[index];
+   if (temp_disp) {
+      delete temp_disp;
+		fsm->dispList.erase(fsm->dispList.begin() + index);
+   }
+	//std::cout << "FsCore : " << id << " app instance is cleared (index:  " << index << ")" << std::endl;	
+
+}
+
+int fsCore::getAvailableInstID(void)
+{
+	for(int i=0; i<MAX_INST_NUM; i++)
+	{
+		if (fsm->m_execIDList[i] == 0)
+			return i;
+	}
+	return -1;
+}
+
+appInExec* fsCore::findApp(int id, int& index)
+{
+	std::vector<appInExec*>::iterator iter_exec;
+	appInExec* temp_exec = NULL;
+	index = 0;
+	for(iter_exec = fsm->execList.begin(); iter_exec != fsm->execList.end(); iter_exec++, index++)
+	{
+		if ((*iter_exec)->fsInstID == id)
+		{
+			temp_exec = (appInExec*) *iter_exec;
+			break;
+		}
+	}
+	return temp_exec;
+}
+
+
+//#define MAX_SAGE_WINDOW_SIZE 4096
+#define MAX_SAGE_WINDOW_SIZE 8192
+
+int fsCore::parseMessage(sageMessage &msg, int clientID)
+{
+	appInExec *app;
+	displayInstance *disp;
+
+	char token[TOKEN_LEN], dataStr[TOKEN_LEN];
+	int tokenNum;
+
+	if (msg.getData())
+		strcpy(dataStr, (char *)msg.getData());
+
+	switch(msg.getCode()) {
+	case REG_APP : {
+		app = new appInExec;
+		memset(app->launcherID, 0, SAGE_NAME_LEN);
+		sscanf((char *)msg.getData(), "%s %d %d %d %d %d %s %d %d %d %d %d %d %s %d", app->appName, &app->x, &app->y,
+				&app->width, &app->height, &app->bandWidth, app->renderNodeIP, &app->imageWidth,
+				&app->imageHeight, (int *)&app->audioOn, (int *)&app->protocol, &app->frameRate,
+				&app->instID, app->launcherID, &app->portForwarding );
+
+		// adjust app window size considering image resolution
+		float ar = (float)(app->imageWidth) / (float)(app->imageHeight);
+		if ((app->imageWidth > MAX_SAGE_WINDOW_SIZE && app->width < MAX_SAGE_WINDOW_SIZE) ||
+				(app->imageHeight > MAX_SAGE_WINDOW_SIZE && app->height < MAX_SAGE_WINDOW_SIZE)) {
+			if (ar > 1) {
+				app->width = MAX_SAGE_WINDOW_SIZE;
+				app->height = (int)(MAX_SAGE_WINDOW_SIZE/ar);
+			}
+			else {
+				app->height = MAX_SAGE_WINDOW_SIZE;
+				app->width = (int)(MAX_SAGE_WINDOW_SIZE*ar);
+			}
+		}
+
+		app->sailClient = clientID;
+
+		char sailInitMsg[TOKEN_LEN];
+		memset(sailInitMsg, 0, TOKEN_LEN);
+
+		// RE-GENERATING ID (2/2)
+		//fsm->m_execIndex = getAvailableInstID();
+		//fsm->m_execIDList[fsm->m_execIndex] = 1;
+		app->fsInstID  = fsm->m_execIndex;
+		std::cout << "[fsCore::parseMessage] REG_APP inst id : " << app->fsInstID << std::endl;
+
+		sprintf(sailInitMsg, "%d %d %d %d", fsm->m_execIndex, fsm->nwInfo->rcvBufSize,
+				fsm->nwInfo->sendBufSize, fsm->nwInfo->mtuSize);
+
+		if (fsm->sendMessage(clientID, SAIL_INIT_MSG, sailInitMsg) < 0) {
+			sage::printLog("fsCore::parseMessage() : REG_APP : %s is stuck or shutdown", app->appName);
+		}
+		else
+			fsm->execList.push_back(app);
+
+		if (fsm->NRM) {
+			char rcvIP[SAGE_IP_LEN];
+			fsm->vdtList[0]->getNodeIPs(0, rcvIP);
+			char msgStr[TOKEN_LEN];
+			memset(msgStr, 0, TOKEN_LEN);
+			sprintf(msgStr, "%s %s %d %d", app->renderNodeIP, rcvIP, app->bandWidth,
+					fsm->m_execIndex);
+
+			int uiNum = fsm->uiList.size();
+			for (int j=0; j<uiNum; j++) {
+				if (fsm->uiList[j] < 0)
+					continue;
+
+				if (fsm->sendMessage(fsm->uiList[j], REQUEST_BANDWIDTH, msgStr) < 0) {
+					sage::printLog("fsCore : uiClient(%d) is stuck or shutdown", j);
+					fsm->uiList[j] = -1;
+				}
+			}
+		}
+		else {
+			initDisp(app);
+			if (app->audioOn) {
+				std::cout << "initAudio is called" << std::endl;
+				initAudio();
+			}
+
+			//windowChanged(fsm->execList.size()-1);
+			//bringToFront(fsm->execList.size()-1);
+			fsm->m_execIndex++;
+		}
+
+		break;
+	}
+
+	case NOTIFY_APP_SHUTDOWN : {
+/*
+		getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		*/
+		int appID;
+		sscanf((char *)msg.getData(), "%d", &appID);
+
+#ifdef DEBUG_KILL
+		fprintf(stderr, "fsCore::parseMsg() : NOTIFY_APP_SHUTDOWN. app %d\n", appID);
+#endif
+		int index =0;
+		app = findApp(appID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		clearAppInstance(appID);
+		break;
+	}
+
+	case NETWORK_RESERVED : {
+		//std::cout << "network_reserved is called ------------------- " << std::endl;
+		if (fsm->NRM) {
+			int appID = fsm->execList.size()-1;
+			app = fsm->execList[appID];
+
+			int success = atoi(dataStr);
+			if (success) {
+				initDisp(app);
+				if (app->audioOn)
+					initAudio();
+				windowChanged(fsm->execList.size()-1);
+				bringToFront(fsm->execList.size()-1);
+			}
+			else {
+				if (fsm->sendMessage(app->sailClient, APP_QUIT) < 0) {
+					//sage::printLog("fsCore : %s(%d) is stuck or shutdown", app->appName, app->fsInstID);
+					//clearAppInstance(appID);
+					clearAppInstance(app->fsInstID);
+				}
+
+				fsm->execList.pop_back();
+			}
+		}
+		break;
+	}
+
+	case REG_GRCV : {
+		int nodeID, dispID;
+				sscanf((char *)msg.getData(), "%d %d", &nodeID, &dispID);
+				/*
+		getToken((char *)msg.getData(), token);
+		int nodeID = atoi(token);
+		getToken((char *)msg.getData(), token);
+		int dispID = atoi(token);
+		*/
+		// store client ID of receivers
+		fsm->vdtList[dispID]->regRcv(clientID, nodeID);
+
+		char info[TOKEN_LEN];
+		// get the tile config info of display node
+		fsm->vdtList[dispID]->getRcvInfo(nodeID, info);
+		int streamPort = fsm->vdtList[dispID]->getLocalPort(nodeID);
+		if (streamPort < 1024)
+			streamPort = fsm->rInfo.streamPort;
+		else
+			fsm->useLocalPort = true;
+
+		char msgStr[TOKEN_LEN];
+		memset(msgStr, 0, TOKEN_LEN);
+		sprintf(msgStr, "%d %d %d %d %d %d %d %s", fsm->nwInfo->rcvBufSize,
+				fsm->nwInfo->sendBufSize, fsm->nwInfo->mtuSize,
+				streamPort, fsm->rInfo.bufSize, (int)fsm->rInfo.fullScreen,
+				fsm->vdtList[dispID]->getNodeNum(), info);
+
+		if (fsm->sendMessage(clientID, RCV_INIT, msgStr) < 0) {
+			sage::printLog("fsCore : displaynode(%d) doesn't respond", nodeID);
+		}
+		break;
+	}
+
+	case REG_ARCV : {
+		int nodeID;
+		sscanf((char *)msg.getData(), "%d", &nodeID);
+		/*
+		getToken((char *)msg.getData(), token);
+		int nodeID = atoi(token);
+		*/
+		// store client ID of receivers
+		fsm->vdtList[0]->regAudioRcv(clientID, nodeID);
+
+		char info[TOKEN_LEN];
+		// get the tile config info of display node
+		fsm->vdtList[0]->getAudioRcvInfo(nodeID, info);
+		char msgStr[TOKEN_LEN];
+		sprintf(msgStr, "%d %d %d %d %d %d %d %d %s", fsm->nwInfo->rcvBufSize,
+				fsm->nwInfo->sendBufSize, fsm->nwInfo->mtuSize,   fsm->rInfo.audioSyncPort,
+				fsm->rInfo.audioPort, fsm->rInfo.agSyncPort, fsm->rInfo.bufSize, fsm->vdtList[0]->getNodeNum(), info);
+
+		//cout << " ----> fsCore : " << msgStr << endl;
+		fsm->sendMessage(clientID, ARCV_AUDIO_INIT, msgStr);
+		break;
+	}
+
+	/*case SYNC_INIT_ARCV : {
+         // find gStreamRcvs connected to this aStreamRcv
+         getToken((char *)msg.getData(), token);
+         int nodeID = atoi(token);
+         //fsm->vdt->getgRcvs(nodeID);
+         char info[TOKEN_LEN];
+         fsm->vdt->getAudioNodeIPs(nodeID, info);
+
+         // send message to gStreamRcvs      
+
+         // for testing 
+         std::vector<int> rcvList = fsm->vdt->getRcvClientList();
+         int rcvNum = rcvList.size();   
+         for(int i=0; i<rcvNum; i++) {
+            fsm->sendMessage(rcvList[i], RCV_SYNC_INIT, info);
+         }
+
+         break;
+         }*/
+
+	case SHUTDOWN_APP : {
+		int appID = -1;
+		//tokenNum = getToken((char *)msg.getData(), token);
+		//appID = atoi(token);
+		sscanf((char *)msg.getData(), "%d", &appID);
+		fprintf(stderr, "fsCore::parseMessage() : SHUTDOWN_APP : %d\n", appID);
+
+		int index = 0;
+		app = findApp(appID, index);
+		if (!app) {
+			fprintf(stderr, "fsCore::parseMessage() : SHUTDOWN_APP : appID %d doesn't exist in the app vector\n", appID);
+			break;
+		}
+
+#ifdef DEBUG_KILL
+		fprintf(stderr, "fsCore::parseMsg() : SHUTDOWN_APP : sendMessage(%d, APP_QUIT)\n", app->sailClient);
+#endif
+		if (fsm->sendMessage(app->sailClient, APP_QUIT) < 0) {
+			sage::printLog("fsCore::parseMessage() : SHUTDOWN_APP : %s(%d) exist in the app vector but fsClient doesn't exist\n", app->appName, appID);
+		}
+
+		clearAppInstance(appID);
+
+		break;
+	}
+
+	case SAGE_APP_SHARE : {
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		*/
+
+		int appID, fsPort, index=0;
+		char fsIP[SAGE_IP_LEN];
+		sscanf((char *)msg.getData(), "%d %s %d", &appID, &fsIP[0], &fsPort);
+
+		app = findApp(appID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		/*
+		getToken((char *)msg.getData(), fsIP);
+		getToken((char *)msg.getData(), token);
+		*/
+		//int fsPort = atoi(token);
+		char msgData[TOKEN_LEN];
+		memset(msgData, 0, TOKEN_LEN);
+		sprintf(msgData, "%s %d", fsIP, fsPort);
+
+		//std::cout << fsIP << ":" << fsPort << std::endl;
+
+		if (fsm->sendMessage(app->sailClient, SAGE_APP_SHARE, msgData) < 0) {
+			sage::printLog("fsCore : %s(%d) is stuck or shutdown", app->appName, appID);
+			clearAppInstance(appID);
+		}
+
+		break;
+	}
+
+	case MOVE_WINDOW : {
+		sageRect devRect;
+		int winID, index;
+		float x,y;
+		sscanf((char *)msg.getData(), "%d %f %f", &winID, &x, &y);
+		     devRect.x = int(x);
+		     devRect.y = int(y);
+/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int winID = atoi(token);
+		int index =0;
+		*/
+		app = findApp(winID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< winID << " doesn't exist" << std::endl;
+			break;
+		}
+/*
+		// change x position(left) of app window
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		devRect.x = atoi(token);
+
+		// change y position(bottom) of app windows
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		devRect.y = atoi(token);
+*/
+		//fsm->dispList[index]->modifyStream();
+
+		startTime = sage::getTime();
+		if (fsm->winStep > 0)
+			winSteps = fsm->winStep;
+
+		if (fsm->dispList[index]->changeWindow(devRect, winSteps) < 0)
+			clearAppInstance(winID);
+		else
+			windowChanged(winID);
+
+		break;
+	}
+
+	case ADD_OBJECT : {
+		if (!msg.getData())
+			break;
+
+		sageRect *obj = new sageRect;
+		char objectName[SAGE_NAME_LEN];
+		sscanf(dataStr, "%s %d %d %d %d", objectName, &obj->x, &obj->y,
+				&obj->width, &obj->height);
+		int objectID = fsm->drawObjectList.size();
+		fsm->drawObjectList.push_back(obj);
+
+		char msgStr[TOKEN_LEN];
+		sprintf(msgStr, "%d %s", objectID, dataStr);
+		fsm->sendToAllRcvs(ADD_OBJECT, msgStr);
+		fsm->sendMessage(clientID, UI_OBJECT_INFO, msgStr);
+
+		break;
+	}
+
+	case MOVE_OBJECT : {
+		if (!msg.getData())
+			break;
+
+		int id, dx, dy;
+		sscanf(dataStr, "%d %d %d", &id, &dx, &dy);
+
+		if (id >= fsm->drawObjectList.size())
+			break;
+
+		sageRect *obj = fsm->drawObjectList[id];
+		obj->x += dx;
+		obj->y += dy;
+
+		char msgStr[TOKEN_LEN];
+		sprintf(msgStr, "%d %d %d", id, obj->x, obj->y);
+		fsm->sendToAllRcvs(UPDATE_OBJECT_POSITION, msgStr);
+
+		break;
+	}
+
+	case REMOVE_OBJECT : {
+		if (!msg.getData())
+			break;
+
+		int id;
+		sscanf(dataStr, "%d", &id);
+
+		if (id >= fsm->drawObjectList.size()) {
+			std::cout << "fsCore: invalid object ID " << id << std::endl;
+			break;
+		}
+
+		fsm->sendToAllRcvs(REMOVE_OBJECT, dataStr);
+
+		break;
+	}
+
+	case OBJECT_MESSAGE : {
+		if (!msg.getData())
+			break;
+
+		int id;
+		sscanf(dataStr, "%d", &id);
+
+		if (id >= fsm->drawObjectList.size()) {
+			std::cout << "fsCore: invalid object ID " << id << std::endl;
+			break;
+		}
+
+		fsm->sendToAllRcvs(OBJECT_MESSAGE, dataStr);
+
+		break;
+	}
+
+	case SHOW_OBJECT : {
+		if (!msg.getData())
+			break;
+
+		int id;
+		sscanf(dataStr, "%d", &id);
+
+		if (id >= fsm->drawObjectList.size()) {
+			std::cout << "fsCore: invalid object ID " << id << std::endl;
+			break;
+		}
+
+		fsm->sendToAllRcvs(SHOW_OBJECT, dataStr);
+
+		break;
+	}
+
+	case FS_TIME_MSG : {
+		double endTime = sage::getTime();
+		double bigTime = floor(endTime/1000000.0)*1000000.0;
+		endTime = (endTime - bigTime)/1000.0;
+		double sageLatency = (endTime - startTime)/1000.0;
+		//std::cout << "total latency = " << sageLatency << "ms" << std::endl;
+		std::cout << "Time Block received at " << endTime << "ms" << std::endl;
+
+		/*
+         double endTime = sageGetTime();
+         double winTime = (endTime - startTime)/1000.0;
+         double singleLatency = winTime / winSteps;
+
+         //std::cout << winTime << std::endl;
+
+         //std::cout << "total time = " << winTime << "ms for " << winSteps << " move/resizing" << std::endl;
+         //std::cout << "single move/resizing time = " << singleLatency << "ms" << std::endl;
+         winSteps = (int)(ceil)(fsm->winTime /singleLatency);
+         //std::cout << "# of window change steps changed to " << winSteps << std::endl;
+		 */
+
+		break;
+	}
+
+	case RESIZE_WINDOW : {
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int winID = atoi(token);
+		sageRect devRect;
+		int index =0;
+		*/
+		int winID, index, left, right, bottom, top;
+		sscanf((char *)msg.getData(), "%d %d %d %d %d", &winID, &left, &right, &bottom, &top);
+
+		app = findApp(winID, index);
+
+		if (!app) {
+			std::cout << "FsCore : app "<< winID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		sageRect devRect;
+/*
+		// change x position(left) of app window
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		int left, right, bottom, top;
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		left = atoi(token);
+
+		// change width of app window
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		right = atoi(token);
+
+		// change y position(bottom) of app window
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		bottom = atoi(token);
+
+		// change height of app windows
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		top = atoi(token);
+		**/
+
+		// adjust app window size considering image resolution
+		float ar = (float)(right - left) / (float)(top - bottom);
+		if (ar > 1 && app->imageWidth > MAX_SAGE_WINDOW_SIZE && right - left < MAX_SAGE_WINDOW_SIZE) {
+			right = left + MAX_SAGE_WINDOW_SIZE;
+			top = bottom + (int)(MAX_SAGE_WINDOW_SIZE/ar);
+		}
+
+		if (ar <= 1 && app->imageHeight > MAX_SAGE_WINDOW_SIZE && top - bottom < MAX_SAGE_WINDOW_SIZE) {
+			top = bottom + MAX_SAGE_WINDOW_SIZE;
+			right = left + (int)(MAX_SAGE_WINDOW_SIZE*ar);
+		}
+
+		devRect.x = left - app->x;
+		devRect.width = right - (app->width+app->x) - devRect.x;
+		devRect.y = bottom - app->y;
+		devRect.height = top - (app->y+app->height) - devRect.y;
+
+		startTime = sage::getTime();
+
+		if (fsm->winStep > 0)
+			winSteps = fsm->winStep;
+
+		if (fsm->dispList[index]->changeWindow(devRect, winSteps) < 0)
+			clearAppInstance(winID);
+		else
+			windowChanged(winID);
+
+		break;
+	}
+
+	case ROTATE_WINDOW : {
+		rotateWindow((char *)msg.getData());
+		break;
+	}
+
+	case SAGE_UI_REG : {
+		fsm->uiList.push_back(clientID);
+		sendDisplayInfo(clientID);
+		sendSageStatus(clientID);
+		sendAppInfo(clientID);
+		break;
+	}
+
+	case APP_UI_REG : {
+		fsm->appUiList.push_back(clientID);
+		fprintf(stderr,"fsCore::%s() : APP_UI_REG : %s\n", __FUNCTION__, (char *)msg.getData());
+		tokenNum = getToken((char *)msg.getData(), token);
+
+		if (strlen(token) > 0) {
+			sendAppStatus(clientID, token);
+		}
+		else {
+			std::cout << "More arguments are needed for this command " << std::endl;
+		}
+		break;
+	}
+
+	case APP_FRAME_RATE : {
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		int index =0;
+		*/
+		int appID, index;
+		      char msgData[TOKEN_LEN];
+		      sscanf((char *)msg.getData(), "%d %s", &appID, msgData);
+
+		app = findApp(appID, index);
+
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		//getToken((char *)msg.getData(), token);
+		if (fsm->sendMessage(app->sailClient, SAIL_FRAME_RATE, token) < 0) {
+			sage::printLog("fsCore : %s(%d) is stuck or shutdown", app->appName, appID);
+			clearAppInstance(appID);
+		}
+
+		break;
+	}
+
+	case PERF_INFO_REQ : {
+		//int dispNum = fsm->dispList.size();
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		int index =0;
+		 */
+		int appID, sendingRate, index;
+		sscanf((char *)msg.getData(), "%d %d", &appID, &sendingRate);
+
+		app = findApp(appID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+		disp = fsm->dispList[index];
+		/*
+		int sendingRate;
+
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			break;
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		sendingRate = atoi(token);
+		 */
+
+		if (disp->requestPerformanceInfo(sendingRate) < 0)
+			clearAppInstance(appID);
+
+		break;
+	}
+
+	case STOP_PERF_INFO : {
+		//int dispNum = fsm->dispList.size();
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		int index =0;
+		*/
+		 int appID, index;
+				     sscanf((char *)msg.getData(), "%d", &appID);
+
+		app = findApp(appID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+		disp = fsm->dispList[index];
+
+		if (disp->stopPerformanceInfo() < 0)
+			clearAppInstance(appID);
+		break;
+	}
+
+	case SAGE_BG_COLOR : {
+		int red, green, blue;
+		     sscanf((char *)msg.getData(), "%d %d %d", &red, &green, &blue);
+		     /*
+		tokenNum = getToken((char *)msg.getData(), token);
+		red = atoi(token);
+
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			_exit(0);
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		green = atoi(token);
+
+		if (tokenNum < 1) {
+			std::cout << "More arguments are needed for this command " << std::endl;
+			_exit(0);
+		}
+
+		tokenNum = getToken((char *)msg.getData(), token);
+		blue = atoi(token);
+		*/
+
+		for (int i=0; i<fsm->vdtList.size(); i++)
+			fsm->vdtList[i]->changeBGColor(red, green, blue);
+
+		break;
+	}
+
+	case UPDATE_WIN_PROP : {
+		//int dispNum = fsm->dispList.size();
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		int index =0;
+		*/
+		int appID, index;
+		      sscanf((char *)msg.getData(), "%d", &appID);
+
+		app = findApp(appID, index);
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+		//disp = fsm->dispList[index];
+
+		//disp->updateWinProp((char *)msg.getData());
+		windowChanged(appID);
+		break;
+	}
+
+	case BRING_TO_FRONT : {
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int winID = atoi(token);
+		*/
+		int winID;
+		sscanf((char *)msg.getData(), "%d", &winID);
+		bringToFront(winID);
+		break;
+	}
+
+	case SAGE_FLIP_WINDOW : {
+		//int execNum = fsm->execList.size();
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		*/
+		int appID;
+		sscanf((char *)msg.getData(), "%d", &appID);
+
+		int index =0;
+		app = findApp(appID, index);
+
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		if (fsm->sendMessage(app->sailClient, SAIL_FLIP_WINDOW) < 0) {
+			sage::printLog("fsCore : %s(%d) is stuck or shutdown", app->appName, appID);
+			clearAppInstance(appID);
+		}
+
+		break;
+	}
+
+	case SAGE_CHECK_LATENCY : {
+		//int execNum = fsm->execList.size();
+		/*
+		tokenNum = getToken((char *)msg.getData(), token);
+		int appID = atoi(token);
+		*/
+		int appID;
+		sscanf((char *)msg.getData(), "%d", &appID);
+
+		int index =0;
+		app = findApp(appID, index);
+
+		if (!app) {
+			std::cout << "FsCore : app "<< appID << " doesn't exist" << std::endl;
+			break;
+		}
+
+		if (fsm->sendMessage(app->sailClient, SAIL_SEND_TIME_BLOCK) < 0) {
+			sage::printLog("fsCore : %s(%d) is stuck or shutdown", app->appName, appID);
+			clearAppInstance(appID);
+		}
+		startTime = sage::getTime();
+
+		break;
+	}
+
+	case SAGE_Z_VALUE : {
+		fsm->sendToAllRcvs(RCV_CHANGE_DEPTH, dataStr);
+
+		int uiNum = fsm->uiList.size();
+
+		for (int j=0; j<uiNum; j++) {
+			if (fsm->uiList[j] < 0)
+				continue;
+
+			if (fsm->sendMessage(fsm->uiList[j], Z_VALUE_RETURN, dataStr) < 0) {
+				sage::printLog("fsCore : uiClient(%d) is stuck or shutdown", j);
+				fsm->uiList[j] = -1;
+			}
+		}
+
+		char *tokenbuf;
+		getToken((char *)msg.getData(), token, &tokenbuf);
+		int numOfChange = atoi(token);
+
+		int index =0;
+		int appID, zValue;
+		for (int i=0; i<numOfChange; i++) {
+/*
+			if (tokenNum > 0) {
+				tokenNum = getToken((char *)msg.getData(), token);
+				appID = atoi(token);
+			}
+			else {
+				std::cout << "More arguments are needed for this command " << std::endl;
+				_exit(0);
+			}   
+
+			if (tokenNum > 0) {
+				tokenNum = getToken((char *)msg.getData(), token);
+				zValue = atoi(token);
+			}
+			else {
+				std::cout << "More arguments are needed for this command " << std::endl;
+				_exit(0);
+			}
+*/
+			getToken(NULL, token, &tokenbuf);
+			appID = atoi(token);
+			getToken(NULL, token, &tokenbuf);
+			zValue = atoi(token);
+
+			app = findApp(appID, index);
+			if(!app) continue;
+
+			fsm->dispList[index]->setZValue(zValue);
+		}
+
+		break;
+	}
+
+	case SAGE_ADMIN_CHECK : {
+		int execNum = fsm->execList.size();
+
+		for (int i=0; i<execNum; i++) {
+			app = fsm->execList[i];
+			if (!app)
+				continue;
+
+			displayInstance *disp = fsm->dispList[i];
+
+			int left = app->x;
+			int bottom = app->y;
+			int right = app->x + app->width;
+			int top = app->y + app->height;
+
+			int dispNodes = 0; //disp->getReceiverNum();
+			int renderNodes = 0;//app->nodeNum;
+			int numStream = 0; //disp->getStreamNum();
+
+			char msgStr[512];
+			memset(msgStr, 0, 512);
+			sprintf(msgStr, "App Name : %s\n   App Instance ID : %d\n",
+					app->appName, app->fsInstID);
+			sprintf(token, "   position (left, right, bottom, top) : ( %d , %d , %d , %d )\n",
+					left, right, bottom, top);
+			strcat(msgStr, token);
+			sprintf(token, "   Z-Value : %d\n", disp->getZValue());
+			strcat(msgStr, token);
+			sprintf(token, "   %d Rendering Nodes    %d Display Nodes    %d Streams\n",
+					renderNodes, dispNodes, numStream );
+			strcat(msgStr, token);
+
+			fsm->sendMessage(clientID, UI_ADMIN_INFO, msgStr);
+		}
+
+		break;
+	}
+
+	case SAGE_SHUTDOWN : {
+		std::cout << "shutdown SAGE" << std::endl;
+		int execNum = fsm->execList.size();
+
+		for (int i=0; i<execNum; i++) {
+			app = fsm->execList[i];
+			if (!app)
+				continue;
+
+			fsm->sendMessage(app->sailClient, APP_QUIT);
+		}
+
+		fsm->sendToAllRcvs(SHUTDOWN_RECEIVERS);
+
+		std::vector<int> arcvList = fsm->vdtList[0]->getAudioRcvClientList();
+		int arcvNum = arcvList.size();
+		for(int i=0; i<arcvNum; i++)
+			fsm->sendMessage(arcvList[i], SHUTDOWN_RECEIVERS);
+
+		fsm->fsmClose = true;
+		break;
+	}
+	}
+
+	return 0;
+}
+
+int fsCore::rotateWindow(char *msgStr)
+{
+   //char token[TOKEN_LEN];
+   //int tokenNum = getToken(msgStr, token);
+   //int winID = atoi(token);
+
+   int winID, rotation;
+   sscanf( msgStr, "%d %d", &winID, &rotation);
+
+   appInExec *app = NULL;
+	int index =0;
+	app = findApp(winID, index);
+   if (!app) {
+      sage::printLog("fsCore::rotateWindow : app %d doesn't exist", winID);
+         return -1;   
+   }   
+/*
+   if (tokenNum < 1) {
+      sage::printLog("fsCore::rotateWindow : more arguments are needed for this command");
+      return -1;   
+   }
+
+   getToken(msgStr, token);
+   int rotation = atoi(token);
+   */
+   switch(rotation) {
+      case 90:
+         app->rotate(CCW_90);
+         break;
+      case 180:
+         app->rotate(CCW_180);
+         break;
+      case 270:
+         app->rotate(CCW_270);
+         break;
+      case -90:
+         app->rotate(CCW_270);
+         break;
+      case -180:
+         app->rotate(CCW_180);
+         break;
+      case -270:
+         app->rotate(CCW_90);
+         break;
+      default:
+         sage::printLog("rotation commnad error : invalid rotation degree");
+         break;
+   }
+   
+   if (fsm->dispList[index]->modifyStream() < 0)
+      clearAppInstance(winID);
+   else   
+      windowChanged(winID);
+   
+   return 0;
+}
+         
+int fsCore::windowChanged(int appId)
+{      
+   int uiNum = fsm->uiList.size();
+   for (int j=0; j<uiNum; j++) {
+      if (fsm->uiList[j] < 0)
+         continue;
+
+      if (sendAppInfo(appId, fsm->uiList[j]) < 0) {
+			sage::printLog("fsCore : uiClient(%d) is stuck or shutdown", j);
+			fsm->uiList[j] = -1;
+		}
+	}	
+
+   return 0;
+}         
+      
+int fsCore::sendSageStatus(int clientID)
+{
+/*
+   int numApps = fsm->appDataList.size();
+   
+   char statusStr[SAGE_MESSAGE_SIZE], token[TOKEN_LEN];
+   
+   memset(statusStr, 0, SAGE_MESSAGE_SIZE);
+   sprintf(statusStr, "%d\n", numApps);
+   
+   for (int i=0; i<numApps; i++) {
+      appDataNode *dataNode = fsm->appDataList[i];
+      int instNum = dataNode->instList.size();
+      int execNum = dataNode->execs.size();
+      
+      sprintf(token, "%s %d %d ", dataNode->app, execNum, instNum);
+      strcat(statusStr, token);
+      
+      for (int j=0; j<instNum; j++) {
+         sprintf(token, "%d ", dataNode->instList[j]);
+         strcat(statusStr, token);
+      }
+      strcat(statusStr, "\n");
+   }
+   
+   fsm->sendMessage(clientID, SAGE_STATUS, statusStr);
+   
+   memset(statusStr, 0, SAGE_MESSAGE_SIZE);
+
+   for (int i=0; i<numApps; i++) {   
+      appDataNode *dataNode = fsm->appDataList[i];
+      int execNum = dataNode->execs.size();
+      
+      sprintf(statusStr, "%s\n", dataNode->app);
+      
+      for(int j=0; j<execNum; j++) {
+         sprintf(token,  "config %s : nodeNum=%d initX=%d initY=%d dimX=%d dimY=%d\n",
+               dataNode->execs[j].name, dataNode->execs[j].nodeNum, dataNode->execs[j].posX,
+               dataNode->execs[j].posY, dataNode->execs[j].dimX,
+               dataNode->execs[j].dimY);
+         strcat(statusStr, token);
+               
+         int cmdNum = dataNode->execs[j].cmdList.size();
+         for (int k=0; k<cmdNum; k++) {
+            sprintf(token, "exec %s %s\n", dataNode->execs[j].cmdList[k].ip, 
+               dataNode->execs[j].cmdList[k].cmd);
+            strcat(statusStr, token);   
+         }   
+         sprintf(token, "nwProtocol=%s\n", dataNode->execs[j].nwProtocol);
+         strcat(statusStr, token);   
+         sprintf(token, "bufNum=%d\n", dataNode->execs[j].bufNum);
+         strcat(statusStr, token);   
+         sprintf(token, "syncMode=%d\n", dataNode->execs[j].syncMode);
+         strcat(statusStr, token);   
+      }   
+      
+      fsm->sendMessage(clientID, APP_EXEC_CONFIG, statusStr);
+   }
+*/      
+   return 0;
+}
+
+int fsCore::sendDisplayInfo(int clientID)
+{
+   char displayStr[STRBUF_SIZE];
+   memset(displayStr, 0, STRBUF_SIZE);
+   displayStr[0] = '\0';
+   
+   for (int i=0; i<fsm->vdtList.size(); i++) {
+      int tileNum = fsm->vdtList[i]->getTileNum();
+      int dimX = fsm->vdtList[i]->dimX;
+      int dimY = fsm->vdtList[i]->dimY;
+      int vdtWidth = fsm->vdtList[i]->width;
+      int vdtHeight = fsm->vdtList[i]->height;
+      int tileWidth = fsm->vdtList[i]->tileList[0]->width;
+      int tileHeight = fsm->vdtList[i]->tileList[0]->height;
+      int id = fsm->vdtList[i]->displayID;
+
+      char info[STRBUF_SIZE];
+      memset(info, 0, STRBUF_SIZE);
+      sprintf(info, "%d %d %d\n%d %d\n%d %d %d\n", tileNum, dimX, dimY, vdtWidth, vdtHeight,
+                           tileWidth, tileHeight, id);
+      strcat(displayStr, info);
+   }
+      
+   fsm->sendMessage(clientID, SAGE_DISPLAY_INFO, displayStr);
+   
+   memset(displayStr, 0, STRBUF_SIZE);
+   displayStr[0] = '\0';
+   
+   for (int i=0; i<fsm->dispConnectionList.size(); i++) {
+      int disp0 = fsm->dispConnectionList[i]->displays[0]->displayID;
+      int disp1 = fsm->dispConnectionList[i]->displays[1]->displayID;
+      int edge0 = fsm->dispConnectionList[i]->edges[0];
+      int edge1 = fsm->dispConnectionList[i]->edges[1];
+      int offset = fsm->dispConnectionList[i]->offset;
+      
+      char info[STRBUF_SIZE];
+      memset(info, 0, STRBUF_SIZE);
+      sprintf(info, "%d %d %d %d %d\n", disp0, edge0, disp1, edge1, offset);
+      strcat(displayStr, info);
+   }
+   
+   if (fsm->dispConnectionList.size() > 0)
+      fsm->sendMessage(clientID, DISP_CONNECTION_INFO, displayStr);
+   
+   return 0;
+}
+
+int fsCore::sendAppInfo(int appID, int clientID)
+{
+   appInExec *app;
+	int index =0;
+	app = findApp(appID, index);
+	if(!app)
+	{
+      std::cout << "FsCore::Invalid App ID " << appID << std::endl;
+		return 1;
+	}
+
+
+   int zValue = 0;   
+   char appInfoStr[TOKEN_LEN];
+	zValue = fsm->dispList[index]->getZValue();
+
+   int left = app->x;
+   int bottom = app->y;
+   int right = app->x + app->width;
+   int top = app->y + app->height;
+   int sailID = app->sailClient;
+   int degree = 90 * (int)app->getOrientation();
+   
+   memset(appInfoStr, 0, TOKEN_LEN);
+   sprintf(appInfoStr, "%s %d %d %d %d %d %d %d %d %d %d %s %s", app->appName, appID, 
+	   left, right, bottom, top, sailID, zValue, degree, app->displayID, 
+	   app->fsInstID, app->launcherID, fsm->dispList[index]->winTitle);
+   
+	return fsm->sendMessage(clientID, APP_INFO_RETURN, appInfoStr);
+}
+
+int fsCore::sendAppInfo(int clientID)
+{
+   int appInstNum = fsm->execList.size();
+   appInExec *app  = NULL;
+   
+	int retVal = 0;
+   for (int i=0; i<appInstNum; i++) 
+	{
+		app = (appInExec*) fsm->execList[i];
+		if (!app) continue;
+		if (sendAppInfo(app->fsInstID, clientID) < 0)
+			retVal = 1;
+	}
+      
+   return retVal;   
+}   
+
+int fsCore::sendAppStatus(int clientID, char *appName)
+{
+   int appInstNum = fsm->execList.size();
+   appInExec *app;
+   int instNum = 0;
+   char statusMsg[TOKEN_LEN];
+   statusMsg[0] = '\0';
+   
+   for (int i=0; i<appInstNum; i++) {
+      app = fsm->execList[i];
+      if (!app)
+         return -1;
+      if (strcmp(app->appName, appName) == 0) {
+         instNum++;
+         char instStr[TOKEN_LEN];
+         sprintf(instStr, " %d %d", app->fsInstID, app->sailClient);
+         strcat(statusMsg, instStr);
+      }      
+   }
+   
+   char msgStr[TOKEN_LEN];
+   memset(msgStr, 0, TOKEN_LEN);
+   sprintf(msgStr, "%d%s", instNum, statusMsg);
+   fsm->sendMessage(clientID, APP_STATUS, msgStr);
+   
+   return 0;
+}
+
+int fsCore::bringToFront(int winID)
+{
+   appInExec *app;
+
+   int execNum = fsm->execList.size();      
+   int numOfWin = 0;
+   char depthStr[TOKEN_LEN];
+   depthStr[0] = '\0';
+
+   for (int i=0; i<execNum; i++) {
+      app = fsm->execList[i];
+      if (!app)
+         continue;
+
+      displayInstance *disp = fsm->dispList[i];
+      if (app->fsInstID != winID)
+         disp->increaseZ();
+      else
+         disp->setZValue(0);
+         
+      numOfWin++;   
+      char zVal[TOKEN_LEN];
+      sprintf(zVal, "%d %d ", app->fsInstID, disp->getZValue());
+      strcat(depthStr, zVal);
+   }
+
+   char msgStr[TOKEN_LEN];
+   memset(msgStr, 0, TOKEN_LEN);
+   sprintf(msgStr, "%d %s", numOfWin, depthStr);
+   
+   fsm->sendToAllRcvs(RCV_CHANGE_DEPTH, msgStr);
+   
+   int uiNum = fsm->uiList.size();
+
+   for (int j=0; j<uiNum; j++) {
+      if (fsm->uiList[j] < 0)
+         continue;
+	
+	   if (fsm->sendMessage(fsm->uiList[j], Z_VALUE_RETURN, msgStr) < 0) {
+			sage::printLog("fsCore : uiClient(%d) is stuck or shutdown", j);
+			fsm->uiList[j] = -1;
+		}
+	}	
+   
+   return 0;
+}
Index: trunk/src/testing/src/overlayPointer.cpp
===================================================================
--- trunk/src/testing/src/overlayPointer.cpp	(revision 4)
+++ trunk/src/testing/src/overlayPointer.cpp	(revision 4)
@@ -0,0 +1,459 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sagePointer.cpp
+ * Author : Ratko Jagodic, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "overlayPointer.h"
+
+
+// custom messages for the pointers
+#define RESET  0
+#define MOVE   1
+#define DRAG   2
+#define RESIZE 3
+#define DOWN   4
+#define UP     5
+#define IN_APP 6  // just a color change
+#define ANGLE  7
+#define ZOOM   8
+#define ROTATE 9
+
+
+// STATES for drawing pointers
+#define NORMAL_SHAPE 10
+#define DRAG_SHAPE 11
+#define RESIZE_SHAPE 12
+#define ZOOM_SHAPE 13
+#define ROTATE_SHAPE 14
+
+
+const float DEG2RAD = 3.14159/180;
+float z = 0;
+
+overlayPointer::overlayPointer()
+{
+   ptrShape = NORMAL_SHAPE;
+   orientation = 0;
+   angle = 0;
+   inApp = false;
+
+   up_color[0] = 0.1;
+   up_color[1] = 0.1;
+   up_color[2] = 0.6;
+   
+   down_color[0] = 0.5;
+   down_color[1] = 0.5;
+   down_color[2] = 0.9;
+
+   in_app_color[0] = 0.8;
+   in_app_color[1] = 0.85;
+   in_app_color[2] = 0.0;
+
+   color = up_color;
+}
+
+
+
+int overlayPointer::init(char *name)
+{
+   setName(name);
+   return 0;
+}
+
+
+
+int overlayPointer::draw()
+{
+   glDisable(GL_TEXTURE_2D);
+   //glEnable(GL_DEPTH_TEST);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glEnable(GL_BLEND);
+
+   float w = 100;
+   float h = w*1.5;
+
+   // set the pointer color depending on the state it's in
+   glColor4f(color[0], color[1], color[2], 1.0);
+
+   glPushMatrix();
+
+   
+
+   /**********    DRAW CURSOR   ***********/
+   int i = 0;      
+   if (ptrShape == DRAG_SHAPE)
+   {
+//      w = w/2;
+//      h = h/2;
+      for(i; i<4; i++)
+      {
+         glPushMatrix();
+         
+         glTranslatef(x, y, 0);    
+         glRotatef(90*i+angle, 0,0,1);                   
+         glTranslatef(0, h+10, 0);
+         drawCursor(w, h);
+
+         glPopMatrix();
+      }
+   }
+
+   else if(ptrShape == RESIZE_SHAPE)
+   {
+//      w = w/1.5;
+//      h = h/1.5;
+      int deg = 0;
+      if (orientation == 1 || orientation == 3)
+         deg = 135;
+      else
+         deg = 45;
+
+      for(i; i<2; i++)
+      {
+         glPushMatrix();
+         
+         glTranslatef(x, y, 0);    
+         glRotatef(deg + 180*i, 0,0,1);       
+         glTranslatef(0, h, 0);
+         drawCursor(w, h);
+         
+         glPopMatrix();
+      }
+   }
+
+   else if(ptrShape == ZOOM_SHAPE)
+   {
+      float degInRad = 0.0;
+      float radius = w/2;
+      float hl = 270 - radius * 0.1;  //handle left
+      float hr = 270 + radius * 0.1;  //handle right
+      float hh = radius*1.7;  //handle height
+
+      glPushMatrix();
+      
+      // translate and rotate to the position of the pointer
+      glTranslatef(x, y, 0);    
+      glRotated(angle, 0,0,1);
+
+
+      /**************  draw magnifying glass ****************/
+
+      glPushMatrix();   
+      glRotated(35, 0,0,1);       
+      
+      
+      // inner transparent circle
+      glColor4f(1.0, 1.0, 1.0, 0.2);  
+      glBegin(GL_POLYGON);
+         for (int i=0; i < 360; i++)
+         {
+            degInRad = i*DEG2RAD;
+            glVertex3f(cos(degInRad)*radius,sin(degInRad)*radius, z);
+         }
+         glVertex3f(cos(DEG2RAD)*radius,sin(DEG2RAD)*radius, z); //final point
+      glEnd();
+
+      
+      // outline of the circle
+      glColor4f(1, 1, 1, 1.0);
+      glLineWidth(radius/10);
+      glBegin(GL_LINE_LOOP);
+         for (int i=0; i < 360; i++)
+         {
+            degInRad = i*DEG2RAD;
+            glVertex3f(cos(degInRad)*radius,sin(degInRad)*radius, z);
+         }
+      glEnd();
+
+      
+      // draw the handle of the zoom lens
+      glBegin(GL_POLYGON);
+         glVertex3f(cos(hl*DEG2RAD)*radius,sin(hl*DEG2RAD)*radius, z);
+         glVertex3f(cos(hl*DEG2RAD)*radius,sin(hl*DEG2RAD)*radius - radius*1.7, z);
+         glVertex3f(cos(hr*DEG2RAD)*radius,sin(hl*DEG2RAD)*radius - radius*1.7, z);
+         glVertex3f(cos(hr*DEG2RAD)*radius,sin(hl*DEG2RAD)*radius, z);
+         glVertex3f(cos(hl*DEG2RAD)*radius,sin(hl*DEG2RAD)*radius, z);
+      glEnd();
+
+      glPopMatrix();
+
+
+      // plus/minus 
+      float pw = radius - radius*0.1;  // line length
+      float po = radius - radius*0.5;  // plus/minus offset
+
+      glBegin(GL_LINES);
+         // plus
+         glVertex3f(-pw/2, po/2, z);
+         glVertex3f(pw/2,  po/2, z);
+         glVertex3f(0, -pw/2+po/2, z);
+         glVertex3f(0,  pw/2+po/2, z);
+         
+         // minus
+         glVertex3f(-pw/2, -po, z);
+         glVertex3f(pw/2, -po, z);
+      glEnd();
+      
+      
+      
+      
+
+      /**************  draw up/down arrows ****************/
+   
+      glPushMatrix();
+      w = radius * 0.7; 
+      h = w*1.5;
+
+      glTranslatef(radius+w, 0, 0);    
+      for(int i=0; i<2; i++)
+      {
+         glPushMatrix();
+         
+         glRotated(180*i, 0,0,1); 
+         glTranslatef(0, h, 0);      
+         drawCursor(w, h);
+         
+         glPopMatrix();
+      }
+      glPopMatrix();
+      
+
+      glPopMatrix();
+   }
+
+   else if (ptrShape == ROTATE_SHAPE)
+   {
+      w = w/1.5;
+      h = h/1.5;      
+      float radius = w*1.2;
+      glPushMatrix();
+      
+      // translate and rotate to the position of the pointer
+      glTranslatef(x, y, 0);    
+      glRotated(angle, 0,0,1);
+      //glRotated(45, 1,1,0);
+
+      glColor4f(1, 1, 1, 1.0);
+      glLineWidth(radius/10);
+      
+      // the rotate arrows
+      glPushMatrix();
+      drawRotateArrows(radius);
+      glRotated(180,0,0,1);
+      drawRotateArrows(radius);
+      glPopMatrix();
+      
+      
+      // the inner directional arrows
+      for(int i=0; i<4; i++)
+      {
+         glPushMatrix();
+         
+         //glTranslatef(x, y, 0);    
+         glRotatef(90*i+angle, 0,0,1);                   
+         glTranslatef(0, h/2.5+10, 0);
+         drawCursor(w/2.5, h/2.5);
+
+         glPopMatrix();
+      }
+   
+      glPopMatrix();
+   }
+
+   else // NORMAL_SHAPE
+   {
+      glTranslatef(x, y, 0);    
+      glRotatef(30+angle, 0,0,1);       
+      drawCursor(w, h);
+   }
+   
+
+   glPopMatrix();
+
+   glDisable(GL_BLEND);   
+   //glDisable(GL_DEPTH_TEST);
+   glEnable(GL_TEXTURE_2D);
+
+   return 0;
+}
+
+
+void overlayPointer::drawRotateArrows(float radius)
+{
+   float degInRad = 0.0;
+
+   // half circle
+   glBegin(GL_LINE_STRIP);
+      for (int i=0; i < 150; i++)
+      {
+         degInRad = i*DEG2RAD;
+         glVertex3f(cos(degInRad)*radius,sin(degInRad)*radius, z);
+      }
+   glEnd();
+
+   // arrow
+   glPushMatrix();
+   glTranslatef(radius,0, 0);
+   glBegin(GL_LINES);
+      glVertex3f(0,0,z);
+      glVertex3f(-radius/5, radius/3, z);
+      glVertex3f(0,0,z);
+      glVertex3f(radius/5, radius/3, z);
+   glEnd();
+   glPopMatrix();
+}
+
+void overlayPointer::drawCursor(double w, double h)
+{
+   // draw the outline of the cursor
+   glColor4f(1.0, 1.0, 1.0, 1.0);  
+   glBegin(GL_POLYGON);
+      glVertex3f(0, 0, z);
+      glVertex3f(-w/2, -h, z);
+      glVertex3f(0, -h+h/5, z);
+   glEnd();
+   glBegin(GL_POLYGON);
+      glVertex3f(0, 0, z);
+      glVertex3f(0, -h+h/5, z);
+      glVertex3f(w/2, -h, z);
+   glEnd();
+
+   // draw the filled polygon
+   glTranslatef(0, -h*0.15/2, 0);
+   glColor4f(color[0], color[1], color[2], 1.0);
+   double sw = w - w*0.15;
+   double sh = h - h*0.15;
+   glBegin(GL_POLYGON);
+      glVertex3f(0, 0, z);
+      glVertex3f(-sw/2, -sh, z);
+      glVertex3f(0, -sh+sh/5, z);
+   glEnd();
+   glBegin(GL_POLYGON);
+      glVertex3f(0, 0, z);
+      glVertex3f(0, -sh+sh/5, z);
+      glVertex3f(sw/2, -sh, z);
+   glEnd();
+}
+
+
+
+int overlayPointer::destroy()
+{
+   return 0;
+}
+
+
+
+int overlayPointer::parseMessage(char *msg)
+{
+   int id, code;
+   sscanf(msg, "%d %d", &id, &code);
+
+   switch(code) 
+   {
+      case MOVE: {
+         int newx,newy;
+         sscanf(msg, "%d %d %d %d", &id, &code, &newx, &newy); 
+         x = newx;
+         y = newy;
+         break;
+      }
+      case DRAG: {
+         ptrShape = DRAG_SHAPE;
+         break;
+      }
+      case RESIZE: {
+         int cId;
+         ptrShape = RESIZE_SHAPE;
+         sscanf(msg, "%d %d %d", &id, &code, &cId);
+         orientation = cId;
+         break;
+      }
+      case DOWN: {
+         color = down_color;
+         break;
+      }
+      case UP: {
+         color = up_color;
+         ptrShape = NORMAL_SHAPE;
+         break;
+      }
+      case RESET: {
+         ptrShape = NORMAL_SHAPE;
+         //color = up_color;
+         orientation = 0;
+         break;
+      }
+      case IN_APP: {
+         int i;
+         sscanf(msg, "%d %d %d", &id, &code, &i); 
+         if(i==0)
+         {
+            color = up_color;
+            inApp = false;
+         }
+         else
+         {
+            color = in_app_color;
+            inApp = true;
+         }
+         break;
+      }
+      case ANGLE: {
+         int a;
+         sscanf(msg, "%d %d %d", &id, &code, &a);
+         angle = a;
+         break;
+      }
+      case ZOOM: {
+         ptrShape = ZOOM_SHAPE;
+         break;
+      }
+      case ROTATE: {
+         ptrShape = ROTATE_SHAPE;
+         break;
+      }
+
+   }
+     
+   return 0;
+   
+}
+
+
+
Index: trunk/src/testing/src/audioFileReader.cpp
===================================================================
--- trunk/src/testing/src/audioFileReader.cpp	(revision 4)
+++ trunk/src/testing/src/audioFileReader.cpp	(revision 4)
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  audioFileReader.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for 
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+********************************************************************************/
+
+#include "audioFileReader.h"
+#include "sageAudioModule.h"
+
+audioFileReader::audioFileReader(audioFormatManager* fm)
+: startFlag(false), formatManager(fm), converter(NULL),
+   fileID(NULL), buffer(NULL),  fileName(NULL), gapTime(0), 
+   totalLoadedFrames(0), totalBlocks(0), loopFlag(false)
+{
+}
+
+
+audioFileReader::~audioFileReader()
+{
+   // delete audiolist
+}
+
+void audioFileReader::init()
+{
+   startFlag = false;
+   loopFlag = false;
+   converter = NULL;
+   fileID = NULL;
+   buffer = NULL;
+   fileName = NULL;
+}
+
+sageAudioCircBuf* audioFileReader::load(char* filename, bool loop, int nframes, long totalframes)
+{
+   if(filename == NULL) return NULL;
+   if(formatManager == NULL) return NULL;
+   
+   fileName = filename;
+   fileID = fopen(fileName, "rb");
+   if( fileID == NULL ) {
+      std::cerr << "Could not open file :" << fileName << std::endl;
+      return NULL;
+   }
+   startFlag = true;
+
+   converter = formatManager->createConverter(fileName, fileID);
+   if(converter == NULL) {
+      std::cerr << "Could not support format :" << fileName << std::endl;
+      return NULL;   
+   }
+   
+   sageAudioConfig config;
+   config.framePerBuffer = nframes;
+   totalBlocks = converter->readHeader(config.channels, config.samplingRate, config.framePerBuffer, config.sampleFmt);
+   if(totalBlocks <=0) totalBlocks = 1;
+   
+   switch(config.sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         break;
+      case SAGE_SAMPLE_INT16 : 
+         bytesPerSample = sizeof(short);
+         break;
+      case SAGE_SAMPLE_INT8 : 
+         bytesPerSample = sizeof(char);
+         break;      
+      case SAGE_SAMPLE_UINT8 : 
+         bytesPerSample = sizeof(unsigned char);
+         break;         
+      default :
+         bytesPerSample = sizeof(float);
+         break;
+   } 
+   //buffer = sageAudioModule::_instance->createBuffer(config, 32);
+   buffer = sageAudioModule::_instance->createBuffer(config, 8);
+   if(buffer == NULL) {
+      std::cerr << "Could not create Buffer" << std::endl;
+      return NULL;
+   }
+   gapTime = 1000000/ (config.samplingRate / config.framePerBuffer * config.channels); 
+   //gapTime *=  0.3; 
+   std::cout << "----------gaptime "  << gapTime << std::endl;
+   if(gapTime < 100) gapTime = 1000;
+   
+   totalLoadedFrames = totalframes;
+   loopFlag = loop;
+   return buffer;
+      
+}
+
+int audioFileReader::start()
+{
+   startFlag = true;
+   pthread_t thId;
+
+   if (pthread_create(&thId, 0, readThread, (void*)this) != 0) {
+      std::cerr << "audioFileReader : can't create readThread" << std::endl;
+         return -1;
+   }
+   return 0;
+}
+
+int audioFileReader::stop()
+{
+   startFlag = false;
+   return 0;
+}
+   
+void* audioFileReader::readThread(void *args)
+{      
+   audioFileReader *This = (audioFileReader *)args;
+   audioBlock* bufferBlock = NULL;
+   int result =0;
+   int blockIndex =0;
+   
+   while(This->startFlag) {
+      bufferBlock = This->buffer->getNextWriteBlock();
+      if(bufferBlock != NULL) {
+         result = This->converter->readFrames(bufferBlock->buff);
+         if(result >= 0)  {
+            bufferBlock->frameIndex = This->buffer->getWriteIndex();
+            if(This->totalLoadedFrames <= 0) {
+               bufferBlock->gframeIndex = sageAudioModule::_instance->getgFrameNum();
+               //std::cout << "gframeIndex(from current) : " << bufferBlock->gframeIndex << std::endl;
+            } else {
+               bufferBlock->gframeIndex = (This->totalLoadedFrames * blockIndex) / This->totalBlocks;
+               //std::cout << "gframeIndex(from calcurate) : " << bufferBlock->gframeIndex << std::endl;
+            }
+            bufferBlock->reformatted = 1;      
+            This->buffer->updateWriteIndex();
+            blockIndex++;
+         } else {
+            //std::cout << "result --- finish???" << std::endl;
+            if(This->loopFlag) {
+               This->converter->begin();
+               //blockIndex =0;
+            } else {
+               This->startFlag = false;
+            }
+         }
+      } else {
+         //std::cout << "buffer null" << std::endl;
+         //sage::usleep(This->gapTime);
+      }
+      sage::usleep(This->gapTime);
+   }   
+      
+   std::cout << "audioFileReader :end readThread" << std::endl;
+   This->converter->close();
+   fclose(This->fileID);
+   pthread_exit(NULL);
+   return NULL;
+}
Index: trunk/src/testing/src/sageAudioReceiver.cpp
===================================================================
--- trunk/src/testing/src/sageAudioReceiver.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioReceiver.cpp	(revision 4)
@@ -0,0 +1,272 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioReceiver.cpp 
+ * Author : Hyejung Hur, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "sageAudioReceiver.h"
+#include "streamProtocol.h"
+#include "sageAudioCircBuf.h"
+#include "sageEvent.h"
+
+sageAudioReceiver::sageAudioReceiver(char *msg, sageEventQueue *queue, streamProtocol *obj, sageAudioCircBuf *buff)
+: sageReceiver(), activeRecv(true), masterFlag(false), m_senderID(-1)
+{
+   buffer = buff;
+   nwObj = obj;
+   eventQueue = queue;
+   
+   char *msgPt = sage::tokenSeek(msg, 2);
+
+   int syncMode, samplingRate, channels, framePerBuffer, keyFrame, frameRate;
+   
+   //6881394 1 0 
+   // 0
+   // 1 44100 2 512 1
+   //std::cout << "--------> receiver : " << msgPt << std::endl;
+    
+   sscanf(msgPt, "%d %d %d %d %d %d %d %d %d %d", &instID, &senderNum, &blockSize, &syncMode, (int*) &sampleFmt,
+                                 &samplingRate, &channels, &framePerBuffer, &frameRate, &keyFrame);
+   buffer->setKeyframe(keyFrame);
+   std::cout << "------------------>audioReceiver : " << instID << " keyFrame : " << keyFrame << std::endl;
+	streamList = new streamData[senderNum];
+	streamIdx = 0;
+   
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         break;
+      case SAGE_SAMPLE_INT16 :
+         bytesPerSample = sizeof(short);
+         break;
+      case SAGE_SAMPLE_INT8 :
+         bytesPerSample = sizeof(int);
+         break;
+      case SAGE_SAMPLE_UINT8 :
+         bytesPerSample = sizeof(unsigned int);
+         break;            
+      default :
+         break;
+   }
+   audioNBlock.setSampleFormat(sampleFmt);
+   audioNBlock.setSampleRate(samplingRate);
+   audioNBlock.setChannel(channels);
+   audioNBlock.setFramePerBuffer(framePerBuffer);
+   audioNBlock.setBytesPerSample(bytesPerSample);   
+   audioNBlock.initBuffer(blockSize);   
+   
+   audioNBlock.updateBufferHeader(); 
+
+}
+
+void sageAudioReceiver::processSync(int frame)
+{
+   syncFrame = frame;
+
+   //std::cout << "   receive sync " << syncFrame << std::endl;
+
+   //if (updateFrame == syncFrame-1) {
+   //swapMontages();
+   //}
+}
+
+void sageAudioReceiver::setMaster(bool flag)
+{
+   masterFlag = flag;
+}
+
+bool sageAudioReceiver::isMaster(void)
+{
+   return masterFlag;
+}
+
+void sageAudioReceiver::setResetFlag(void)
+{
+   resetFlag = true;
+}
+
+int sageAudioReceiver::addStream(int senderID)
+{
+   //readThreadParam *param = new readThreadParam;
+   //param->This = this;
+   //param->senderID = senderID;
+
+	m_senderID = senderID;
+	streamList[streamIdx].senderID = senderID;
+	streamList[streamIdx].dataSockFd = nwObj->getRcvSockFd(senderID);
+	streamIdx++;
+
+   // buffer reset
+   buffer->reset();
+   
+   //if (pthread_create(&param->thId, 0, nwReadThread, (void*)param) != 0) 
+   if (pthread_create(&thId, 0, nwReadThread, (void*)this) != 0) 
+   {
+      sage::printLog("sageReceiver : can't create network reading thread");
+         return -1;
+   }
+
+   //threadList.push_back(param);
+   //return threadList.size();
+
+	return streamIdx;
+}
+
+
+//int sageAudioReceiver::readData(int senderID, sageBlockQueue *queue)
+int sageAudioReceiver::readData()
+{
+   if (!eventQueue) {
+      sage::printLog("sageAudioReceiver::readSampleData : event queue is null");   
+      return -1;
+   }
+   
+   if (!buffer) {
+      sage::printLog("sageAudioReceiver::readSampleData : buffer is null");   
+      return -1;
+   }
+      
+   if (!nwObj)  {
+      sage::printLog("sageAudioReceiver::readSampleData : network object is null");   
+      return -1;
+   }   
+   
+   audioBlock* block;
+   while(!endFlag) {
+      
+      if(resetFlag == true) {
+         buffer->reset();
+         std::cout << "buffer is reset" << std::endl;
+         resetFlag = false;
+      }
+
+      block = buffer->getNextWriteBlock();
+      if(block == NULL) {
+         std::cout << "could not get buffer for writing" << std::endl;
+         return -1;
+      }
+
+      int rcvSize = nwObj->recv(streamList[0].senderID, &audioNBlock, SAGE_BLOCKING);
+      if (rcvSize <= 0) {
+         activeRecv = false;
+         sage::printLog("sageAudioReceiver::readSampleData : exit loop");
+         endFlag = true;
+      }
+      else {
+
+         bandWidth += rcvSize;
+         //std::cout << "enqueued a block : " << (char *)freeBlock->getBuffer() << std::endl;
+         if(audioNBlock.getFlag() == SAGE_AUDIO_BLOCK)  {
+            //std::cout << "---------->audioInstance::rcvStream " << buffer->getAudioId() << " " <<  audioNBlock.getFrameID() << std::endl;
+            char* tempbuff = audioNBlock.getAudioBuffer(); 
+            buffer->convertToFloat(sampleFmt, tempbuff, block);
+
+            block->frameIndex = audioNBlock.getgFrameID();
+            if(masterFlag == true)
+            {
+               // merge current available version
+               buffer->merge(block);
+            }
+         
+            block->reformatted = 1;
+            buffer->updateWriteIndex();
+         }         
+         
+      }      
+   } 
+
+   // delete buffer
+   if(buffer) {
+      delete buffer;
+      buffer = NULL;
+   }
+   
+   return 0;
+}
+
+bool sageAudioReceiver::isActive()
+{
+   return activeRecv;
+}
+
+int sageAudioReceiver::getAudioId()
+{
+   if(buffer)
+   {
+      return buffer->getAudioId();
+   }
+   return -1;
+}
+   
+
+int sageAudioReceiver::evalPerformance(char **frameStr, char **bandStr)
+{
+   //Calculate performance here
+   double elapsedTime = perfTimer.getTimeUS();
+   
+   if (elapsedTime > 1000000.0*reportRate && reportRate > 0) {
+      *bandStr = new char[TOKEN_LEN];
+   
+      float obsBandWidth = (float) (bandWidth * 8.0 / (elapsedTime));
+      float obsLoss = (float) (packetLoss * 8.0 / (elapsedTime));
+      bandWidth = 0;
+      packetLoss = 0;
+// HYEJUNG
+      /*
+      sprintf(*bandStr, "%d %d %7.2f %7.2f", instID, shared->nodeID, obsBandWidth, obsLoss);      
+      
+      bool active = false;
+      for (int i=0; i<streamNum; i++) {
+         if (queueList[i]->isActive()) {
+            active = true;
+            break;
+         }
+      }
+
+      if (active) {
+         *frameStr = new char[TOKEN_LEN];
+         float frameRate = (float) ((updateFrame - oldFrame)*1000000.0/elapsedTime);
+         oldFrame = updateFrame;
+         sprintf(*frameStr, "%d %f", instID, frameRate);
+      }*/
+// HYEJUNG      
+      
+      perfTimer.reset();
+   }
+   
+   return 0;
+}
Index: trunk/src/testing/src/audioConverter.cpp
===================================================================
--- trunk/src/testing/src/audioConverter.cpp	(revision 4)
+++ trunk/src/testing/src/audioConverter.cpp	(revision 4)
@@ -0,0 +1,87 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  audioConverter.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for 
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "audioConverter.h"
+
+audioConverter::audioConverter() 
+: totalBlocks(0), blockCount(0), writeMode(0)
+{
+#ifdef WIN32
+   dataPos = -1;
+#endif
+}
+
+audioConverter::~audioConverter()
+{
+}
+
+int audioConverter::init(FILE* fp)
+{
+   fileID = fp;
+   blockCount =0;
+   //dataPos = -1;
+   if(fileID == NULL) return -1;
+   
+   return 0;
+}
+
+
+/** Returns a tuple (nchannels, sampwidth, framerate, nframes, comptype, compname), 
+    equivalent to output of the get*() methods ??? */
+int audioConverter::getParams(int& nchan, long& samrate, int& nframes, sageSampleFmt& fmt)
+{
+   if(fileID == NULL) return -1;
+   nchan = channels;
+   samrate = sampleRate;
+   fmt =sampleFmt;
+   nframes = framesPerBuffer;   
+   return totalBlocks;   
+}
+
+
+/** Rewind the file pointer to the beginning of the audio stream */ 
+void audioConverter::begin()
+{
+   if(fileID) {
+      rewind(fileID);
+      blockCount =0;
+   }
+}
Index: trunk/src/testing/src/sageBlock.cpp
===================================================================
--- trunk/src/testing/src/sageBlock.cpp	(revision 4)
+++ trunk/src/testing/src/sageBlock.cpp	(revision 4)
@@ -0,0 +1,356 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageBlock.cpp - a few geometrical operations for rectangles used in SAGE
+ * Author : Byungil Jeong, Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBlock.h"
+
+void sagePixelData::operator=(sageRect &rect)
+{
+   sageRect::operator=(rect);
+}
+
+int sagePixelData::initBuffer()
+{
+   int size = (int)ceil(width*height*bytesPerPixel/(compressX*compressY)) + BLOCK_HEADER_SIZE;
+
+   if (size <= BLOCK_HEADER_SIZE) {
+      sage::printLog("sagePixelBlock::initBuffer() : The size of a pixelblock must be greater than BLOCK_HEADER_SIZE(%d)", BLOCK_HEADER_SIZE);
+      return -1;
+   }
+   
+   releaseBuffer();
+
+#ifdef DEBUG_MEMORY
+   fprintf(stderr, "sagePixelData::initBuffer() : HEADER + ( w x h x Bpp  /  compX x compY ) : %d = %d + ((%d x %d x %d)/(%.1f x %1.f))\n", size, BLOCK_HEADER_SIZE, width, height, bytesPerPixel, compressX, compressY);
+#endif
+   if (allocateBuffer(size) < 0)
+      return -1;
+
+   //std::cout << "allocate " << size << " bytes" << std::endl;
+   pixelData = buffer + BLOCK_HEADER_SIZE;
+   
+   return 0;
+}
+
+int sagePixelData::releaseBuffer()
+{
+   if (buffer) {
+#ifdef DEBUG_MEMORY
+	fprintf(stderr,"sagePixelData::releaseBuffer() : freeing the buffer\n");
+#endif
+      free((void *)buffer);
+      buffer = 0;
+   }
+
+   return 0;
+}
+
+int sagePixelData::allocateBuffer(int size)
+{
+	if ( buffer ) {
+		releaseBuffer();
+	}
+   buffer = (char *)malloc(size);
+   if (!buffer) {
+      sage::printLog("sageBlock::allocateBuffer : fail to allocate %d bytes", size);
+      return -1;
+   }
+   bufSize = size;      
+   
+   return 0;
+}
+
+sagePixelBlock::sagePixelBlock(int size) : valid(false), dirty(false), headerLen(0)
+{
+   flag = SAGE_PIXEL_BLOCK;
+   allocateBuffer(size);
+
+   //std::cout << "allocate " << size << " bytes" << std::endl;
+   pixelData = buffer + BLOCK_HEADER_SIZE;
+}
+
+sagePixelBlock::sagePixelBlock(sagePixelBlock &block) 
+{
+   allocateBuffer(block.bufSize);
+   pixelData = buffer + BLOCK_HEADER_SIZE;
+   
+   memcpy(buffer, block.buffer, bufSize);
+   updateBlockConfig();
+}
+
+int sagePixelBlock::updateBufferHeader()
+{   
+   if (!buffer) {
+      sage::printLog("sagePixelBlock::updateBufferHeader : buffer is null");   
+      return -1;
+   }
+   
+   memset(buffer, 0, BLOCK_HEADER_SIZE);
+   headerLen = sprintf(buffer, "%d %d %d %d %d %d %d %d",
+         bufSize, flag, x, y, width, height, frameID, blockID);
+         
+   if (headerLen >= BLOCK_HEADER_SIZE) {
+      sage::printLog("sagePixelBlock::updateBufferHeader : block header exceeds the maximum length");
+      return -1;
+   }
+   
+   return 0;
+}
+
+int sagePixelBlock::updateHeader(int pid, int configID)
+{   
+   if (!buffer) {
+      sage::printLog("sagePixelBlock::updateBufferHeader : buffer is null");   
+      return -1;
+   }
+   
+   memset(buffer, 0, BLOCK_HEADER_SIZE);
+   headerLen = sprintf(buffer, "%d %d %d %d %d %d %d %d %d %d",
+         bufSize, flag, x, y, width, height, frameID, blockID, pid, configID);
+         
+   if (headerLen >= BLOCK_HEADER_SIZE) {
+      sage::printLog("sagePixelBlock::updateBufferHeader : block header exceeds the maximum length");
+      return -1;
+   }
+   
+   return 0;
+}
+
+bool sagePixelBlock::updateBlockConfig()
+{
+   if (!buffer) {
+      sage::printLog("sagePixelBlock::updateBlockConfig : buffer is null");
+      return false;
+   }
+   
+   //std::cout << "buf : " << buffer << std::endl;
+   
+   sscanf(buffer, "%d %d %d %d %d %d %d %d", &bufSize, &flag, &x, &y, &width, &height, 
+               &frameID, &blockID);
+         
+   return true;
+}
+
+void sagePixelBlock::clearPixelBlock()
+{
+   dirty = false;
+   valid = true;
+   clearBuffer();
+}
+
+sagePixelBlock::~sagePixelBlock()
+{
+#ifdef DEBUG_MEMORY
+	fprintf(stderr, "sagePixelBlock destructor. This could call sagePixelData::releaseBuffer()\n");
+#endif
+   releaseBuffer();
+}
+
+sageAudioBlock::sageAudioBlock() : frameID(0), gframeID(0),
+                        bytesPerSample(4), sampleFmt(SAGE_SAMPLE_FLOAT32),
+                        sampleRate(0), channels(0), framePerBuffer(0),
+                        extraInfo(NULL), tileID(0), nodeID(0)
+{
+   flag = SAGE_AUDIO_BLOCK;
+}
+
+sageAudioBlock::sageAudioBlock(int frame, sageSampleFmt type, int byte, int rate, int chan, int framesperbuffer)
+:                       frameID(frame), gframeID(0),
+   bytesPerSample(byte), sampleFmt(type),
+   sampleRate(rate), channels(chan), framePerBuffer(framesperbuffer),
+   extraInfo(NULL), tileID(0), nodeID(0)
+{
+   flag = SAGE_AUDIO_BLOCK;
+   initBuffer();
+}
+
+sageAudioBlock::~sageAudioBlock()
+{
+   releaseBuffer();
+}
+
+int sageAudioBlock::initBuffer()
+{
+   int newBufSize = framePerBuffer * channels * bytesPerSample;
+   initBuffer(newBufSize);
+   return 0;
+}
+
+int sageAudioBlock::initBuffer(int size)
+{
+   if (buffer) 
+   {
+      releaseBuffer();
+   }
+
+   if (allocateBuffer(size) < 0)
+               return -1;
+   
+   bufSize = size;               
+   audioData = buffer + BLOCK_HEADER_SIZE;   
+   return 0;
+}
+
+int sageAudioBlock::releaseBuffer()
+{
+   //std::cout << "release buffer" << std::endl;
+   if (buffer) {
+      free(buffer);
+      buffer = NULL;
+      //if (buffer)
+      //delete [] buffer;
+   }
+
+   return 0;
+}
+
+int sageAudioBlock::allocateBuffer(int size)
+{
+
+   buffer = (char*)malloc(size);
+   bufSize = size;
+
+   return 0;
+}
+
+int sageAudioBlock::updateBufferHeader()
+{
+   if (!buffer) {
+      sage::printLog("sageAudioBlock::updateBufferHeader : buffer is null");
+      return -1;
+   }
+
+   memset(buffer, 0, BLOCK_HEADER_SIZE);
+   int headerSize = 0;
+
+   /*
+        if (frameID >= 0)
+                frameID = frameID % 10000;      // 4 digit frame number
+
+        if (gframeID >= 0)
+                gframeID = gframeID % 10000; // 4 digit frame number
+   */
+
+
+#if defined(WIN32)
+   headerSize = _snprintf(buffer, BLOCK_HEADER_SIZE, "%d %d %d %d %d %d %d %d %d %d",
+         bufSize, flag,(int)sampleFmt, sampleRate, channels, framePerBuffer, frameID, gframeID, tileID, nodeID);
+#else
+   headerSize = snprintf(buffer, BLOCK_HEADER_SIZE, "%d %d %d %d %d %d %d %d %d %d",
+         bufSize, flag, (int)sampleFmt, sampleRate, channels, framePerBuffer, frameID, gframeID, tileID, nodeID);
+#endif
+
+   if (headerSize >= BLOCK_HEADER_SIZE) {
+      sage::printLog("sageAudioBlock::updateBufferHeader : block header has been truncated.");
+      return -1;
+   }
+
+   return 0;
+}
+
+bool sageAudioBlock::updateBlockConfig()
+{
+   /*
+        if (frameID >= 0)
+                frameID = frameID % 10000;      // 4 digit frame number
+
+        if (gframeID >= 0)
+                gframeID = gframeID % 10000; // 4 digit frame number
+   */
+
+
+   if (!buffer) {
+      sage::printLog("sageAudioBlock::updateBlockConfig : buffer is null");
+      return false;
+   }
+
+   sscanf(buffer, "%d %d %d %d %d %d %d %d %d %d", &bufSize, &flag, &sampleFmt, &sampleRate, 
+         &channels, &framePerBuffer, &frameID,  &gframeID, &tileID, &nodeID);
+
+   //std::cout << buffer << std::endl;
+   extraInfo = sage::tokenSeek(buffer, 10);
+   if (!extraInfo && flag == SAGE_AUDIO_BLOCK) {
+      // sage::printLog("sageAudioBlock::updateBlockConfig : extraInfo is NULL");
+   }
+
+   return true;
+}
+
+
+/*
+sageControlBlock::sageControlBlock(int f, int frame, int size) : frameID(frame)
+{
+   flag = f;
+   bufSize = size;
+   
+   if (size > 0)
+      buffer = new char[size];
+}
+
+int sageControlBlock::updateBufferHeader(char *info)
+{
+   if (!buffer) {
+      sage::printLog("sageControlBlock::updateBufferHeader : buffer is null");   
+      return -1;
+   }
+   
+   memset(buffer, 0, BLOCK_HEADER_SIZE);
+   sprintf(buffer, "%d %d %d %s", bufSize, flag, frameID, info);
+         
+   return 0;
+}
+
+int sageControlBlock::updateBlockConfig()
+{
+   if (!buffer) {
+      sage::printLog("sageControlBlock::updateBlockConfig : buffer is null");   
+      return -1;
+   }
+   
+   sscanf(buffer, "%d %d %d %s", &bufSize, &flag, &frameID, ctrlInfo);
+   
+   return 0;
+}
+
+sageControlBlock::~sageControlBlock()
+{
+   if (buffer)
+      delete [] buffer;
+}
+*/
Index: trunk/src/testing/src/sageFrame.cpp
===================================================================
--- trunk/src/testing/src/sageFrame.cpp	(revision 4)
+++ trunk/src/testing/src/sageFrame.cpp	(revision 4)
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageFrame.cpp - functions manipulate image frames in SAGE
+ * Author : Byungil Jeong, Luc Renambot
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "sageFrame.h"
+#include "streamInfo.h"
+#include "sageBlockPartition.h"
+
+sageBlockFrame::sageBlockFrame(int w, int h, int bytes, float compX, float compY)
+      : blocks(NULL)
+{
+   width = w;
+   height = h;
+   bytesPerPixel = bytes;
+
+   compressX = compX;
+   compressY = compY;
+
+   initBuffer();
+}
+
+int sageBlockFrame::initFrame(sageBlockPartition *part)
+{
+   partition = new sageBlockPartition(*part);
+   partition->setViewPort(*this);
+   pixelSize = (int)ceil(bytesPerPixel/compressX);
+   memWidth = width*pixelSize;
+
+   return 0;
+}
+
+bool sageBlockFrame::extractPixelBlock(sagePixelBlock *block, int rowOrder)
+{
+   if (!block) {
+      sage::printLog("sageBlockFrame::extractPixelBlock : block is NULL");
+      //return false;
+   }
+   
+   partition->getVisibleBlock(idx, *block);
+   sageRect blockRect = *block;
+   blockRect.moveOrigin(*this);
+
+   char *blockAddr;
+   int yPos = 0;
+   //std::cerr << "block addr " << blockRect.y*memWidth + blockRect.x*pixelSize << std::endl;
+   if (rowOrder == BOTTOM_TO_TOP)
+      yPos = (int)ceil(blockRect.y/compressY);
+   else
+      yPos = (int)ceil((height-1-blockRect.y)/compressY);
+
+   blockAddr = pixelData + yPos*memWidth + blockRect.x*pixelSize;
+
+   char *blockBuf = block->getPixelBuffer();
+
+   int srcHeight = (int)ceil(block->height/compressY);
+   int srcWidth = block->width*pixelSize;
+
+   for (int i=0; i<srcHeight; i++) {
+      memcpy(blockBuf, blockAddr, srcWidth);
+      blockBuf += srcWidth;
+      if (rowOrder == BOTTOM_TO_TOP) {
+         blockAddr += memWidth;
+      }
+      else {
+         blockAddr -= memWidth;
+      }
+   }
+
+   partition->adjustBlockCoord(*block);
+   
+   idx++;
+
+   if (idx == partition->getBlockNum()) {
+      resetBlockIndex();
+      return false;  // finish extraction of a frame
+   }
+
+   return true;  // continue extraction
+}
+
+int sageBlockFrame::generateBlocks(int rowOrd)
+{
+   return 0;
+}
+
+int sageBlockFrame::generateSubFrame(sageRect &rect, sageSubFrame &s)
+{
+   return 0;
+}
+
+/**
+ * sagenext
+ */
+int sageBlockFrame::updateBufferHeader(int fnum) {
+	if (!buffer) {
+		sage::printLog("sageBlockFrame::%s() : buffer is null", __FUNCTION__);
+		return -1;
+	}
+
+	memset(buffer, 0, BLOCK_HEADER_SIZE);
+
+	// frameNumber, pixelSize, memwidth, bufSize
+	int headerLen = sprintf(buffer, "%d %d %d %d", fnum, pixelSize, memWidth, bufSize);
+
+	if (headerLen >= BLOCK_HEADER_SIZE) {
+		sage::printLog("sageBlockFrame::%s() : block header exceeds the maximum length %d Byte", __FUNCTION__, BLOCK_HEADER_SIZE);
+		return -1;
+	}
+
+	return 0;
+}
+
+sageBlockFrame::~sageBlockFrame()
+{
+   if (blocks) {
+      delete [] blocks;
+   }
+
+   releaseBuffer();
+}
+
+/*
+int sageUdpFrame::computeBlockSize(int packetSize, )
+{
+   double payLoadSize = packetSize - BLOCK_HEADER_SIZE;
+   if (config.protocol == SAGE_UDP) {
+      config.blockX = (int)floor(sqrt(payLoadSize/bytesPerPixel));
+      config.blockY = config.blockX;
+   }
+}
+*/
Index: trunk/src/testing/src/sageTcpModule.cpp
===================================================================
--- trunk/src/testing/src/sageTcpModule.cpp	(revision 4)
+++ trunk/src/testing/src/sageTcpModule.cpp	(revision 4)
@@ -0,0 +1,595 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  sageTcpModule.cpp
+ * Author   :   Byungil Jeong, Rajvikram Singh
+ * Description:   Code file for the TCP network stream of SAGE
+ * Notes   :   The class primarily uses TCP sockets with the options optimized for graphics streaming
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "sageTcpModule.h"
+#include "sageBlock.h"
+#include "sageFrame.h"
+#include "sageBlockPool.h"
+#include <fcntl.h>
+
+sageTcpModule::sageTcpModule() : returnPlace(NULL)
+{
+#ifdef WIN32
+   // Initialize Winsock
+   WSADATA wsaData;
+   WSAStartup(MAKEWORD(2,2), &wsaData);
+
+#endif
+
+   protocol = SAGE_TCP;
+   bufList.clear(); 
+}//End of sageTcp:sageTcp
+
+int sageTcpModule::init(sageStreamMode m, int p, sageNwConfig &c)
+{
+   streamProtocol::init(m, p, c);
+   
+   // create the actual network objects
+   switch(sMode)   {
+      case SAGE_RCV:
+      case SAGE_ARCV:
+      case SAGE_BRIDGE:   // prepare a server socket
+         // create the sockets
+         if((serverSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
+            perror("sageTcpModule::init(): Creating TCP socket failed");
+            return 1;
+         }
+   
+         setSockOpts(serverSockFd);
+         
+         // bind to port
+         memset(&localAddr, 0, sizeof(localAddr));
+         localAddr.sin_family = AF_INET;
+         localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+         localAddr.sin_port = htons(rcvPort);
+
+         if(bind(serverSockFd, (struct sockaddr *)&localAddr, sizeof(struct sockaddr_in)) != 0) {
+            perror("sageTcpModule::init()");
+            return 1;
+         }
+         
+         // put in listen mode      
+         ::listen(serverSockFd, 5);
+      
+         break;
+         
+      case SAGE_SEND:
+         return 0;
+         break;
+      default:   return 1;
+   
+   } //End of switch(opMode)
+   
+   return 0;
+}//End of sageTcpModule::init()
+
+int sageTcpModule::checkConnections(char *msg, sageApiOption op)
+{
+   if(sMode == SAGE_SEND) {
+      std::cout << "sageTcpModule::checkConnection() cannot be used for senders" << std::endl;
+      return -1;
+   }
+   
+   if (op & SAGE_NON_BLOCKING) {
+      if (!sage::isDataReady(serverSockFd))
+         return -1;
+   }   
+   
+   //accept client connections
+   int addrLen;
+   addrLen = sizeof(clientAddr);
+   
+   int clientSockFd;
+   if ((clientSockFd = ::accept(serverSockFd, (struct sockaddr *)&clientAddr, (socklen_t*)&addrLen)) == -1){
+      perror("sageTcpModule::checkConnections()");
+      return -1;
+   }
+   
+   //fcntl(clientSockFd, F_SETFL, 0);
+   setSockOpts(clientSockFd);
+      
+   sendList.push_back(clientSockFd);
+
+   // read registration message
+   int idx = sendList.size()-1;
+   
+   char regMsg[REG_MSG_SIZE];
+   int retVal = sage::recv(clientSockFd, (void *)regMsg, REG_MSG_SIZE);
+   if (retVal == -1) {
+      return -1;
+   }
+   else if (retVal == 0) {
+      #ifdef WIN32   
+      closesocket(clientSockFd);
+      #else
+      shutdown(clientSockFd, SHUT_RDWR);
+      #endif
+      
+      sendList[idx] = -1;
+      return -1;
+   }
+   
+   if (msg) {
+      sprintf(msg, "%d %s", idx, regMsg);
+   }
+   else {
+      sage::printLog("sageTcpModule::checkConnections() : registraion message buffer is NULL");
+      return -1;
+   }
+   
+   return idx;
+}//End of sageTcpModule::listen()
+
+int sageTcpModule::connect(char *ip, char *msg)
+{
+   if(sMode == SAGE_RCV) {
+      std::cout << "sageTcpModule::connect() cannot be used for receivers" << std::endl;
+      return -1;
+   }
+
+   // create the sockets
+   int clientSockFd;
+   if((clientSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1)   {
+      perror("sageTcpModule::init(): Creating TCP socket failed");
+      return -1;
+   }
+   
+   setSockOpts(clientSockFd);
+
+   // connect to the server
+   memset(&serverAddr, 0, sizeof(serverAddr));
+   serverAddr.sin_family = AF_INET;
+   serverAddr.sin_addr.s_addr = inet_addr(ip);
+   serverAddr.sin_port = htons(rcvPort);
+
+   if(::connect(clientSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) == -1) {
+      perror("sageTcpModule::connect()");
+      return -1;
+   }
+      
+   rcvList.push_back(clientSockFd);
+   
+   if (config.blockSize > 0 && config.groupSize > 0) {
+	// make sure a block fits in a group
+      if (config.blockSize>config.groupSize) config.groupSize = config.blockSize;
+      sageBlockGroup *sbg = new sageBlockGroup(config.blockSize, config.groupSize, GRP_USE_IOV);
+      bufList.push_back(sbg);
+   }   
+   
+   if (msg) {
+      if (sage::send(clientSockFd, msg, REG_MSG_SIZE) == -1) {
+         perror("sageTcpModule::send()");
+         return -1;
+      }   
+   }
+      
+   return (rcvList.size()-1);
+}//End of sageTcpModule::connect()
+
+int sageTcpModule::send(int id, sageBlock *sb, sageApiOption op)
+{
+   if (id < 0 || id > rcvList.size()-1) {
+      sage::printLog("sageTcpModule::send() : invalid receiver ID %d", id);
+      return -1;
+   }
+   
+   int clientSockFd;
+   if (op & SAGE_BACKWARD)
+      clientSockFd = sendList[id];
+   else
+      clientSockFd = rcvList[id];   
+   
+   if (!sb) {
+      sage::printLog("sageTcpModule::send() : null sage block");
+      return -1;
+   }
+   
+   //std::cout << "block size " << sb->getBufSize() << std::endl;
+   // send data
+   int dataSize = sage::send(clientSockFd, sb->getBuffer(), sb->getBufSize());
+   if (dataSize < 0) {
+      return -1;
+   }
+   
+   return dataSize;
+}//End of sageTcpModule::send()
+
+/**
+ * sungwon experimental, swexp
+ */
+int sageTcpModule::sendpixelonly(int id, sageBlockFrame *sb) {
+	if (id < 0 || id > rcvList.size()-1) {
+		sage::printLog("sageTcpModule::%s() : invalid receiver ID %d", __FUNCTION__, id);
+		return -1;
+	}
+
+	if (!sb) {
+		sage::printLog("sageTcpModule::%s() : null sage block", __FUNCTION__);
+		return -1;
+	}
+
+	//std::cout << "block size " << sb->getBufSize() << std::endl;
+	// send data
+	assert(sb);
+
+
+	int totalsent = 0;
+	int dataSize = 0;
+	char *buf = sb->getPixelBuffer();
+	int frameSize = sb->getBufSize() - BLOCK_HEADER_SIZE;
+	while ( totalsent < frameSize ) {
+
+		if ( frameSize - totalsent < config.groupSize ) {
+			dataSize = sage::send(rcvList[id], buf, frameSize-totalsent);
+		}
+		else {
+			dataSize = sage::send(rcvList[id], buf, config.groupSize);
+		}
+		if (dataSize < 0) { return -1; }
+
+		buf += dataSize;
+
+		totalsent += dataSize;
+	}
+
+		/*
+	int dataSize = sage::send(rcvList[id], sb->getPixelBuffer(), sb->getBufSize() - BLOCK_HEADER_SIZE);
+	if (dataSize < 0) { return -1; }
+	*/
+
+	return dataSize;
+}
+
+
+int sageTcpModule::sendControl(int id, int frameID, int configID)
+{
+   if (flush(id, configID) < 0) {
+      return -1;
+   }
+   
+   int clientSockFd = rcvList[id];   
+   
+   char header[GROUP_HEADER_SIZE];
+   sprintf(header, "0 %d %d", frameID, configID);
+   int dataSize = sage::send(clientSockFd, header, GROUP_HEADER_SIZE);
+   if (dataSize < 0) {
+      return -1;
+   }
+   
+   return dataSize;
+}
+
+int sageTcpModule::sendGrp(int id, sagePixelBlock *sb, int configID)
+{
+   if (id < 0 || id > rcvList.size()-1) {
+      sage::printLog("sageTcpModule::send() : invalid receiver ID %d", id);
+      return -1;
+   }
+   
+   int clientSockFd = rcvList[id];   
+   
+   if (!sb) {
+      sage::printLog("sageTcpModule::sendGrp() : null sage block");
+      return -1;
+   }
+   
+   if (config.groupSize == 0) {
+      sage::printLog("sageTcpModule::sendGrp() : group transfer is not enabled");
+      return -1;
+   }
+   
+   sageBlockGroup* bGrp = bufList[id];
+   bGrp->pushBack(sb);
+   //std::cout << "send : " << (char *)sb->getBuffer() << std::endl;
+   
+   int dataSize = 0;
+   if (bGrp->isFull()) {
+      bGrp->genIOV();
+      bGrp->setFrameID(sb->getFrameID());
+      bGrp->setConfigID(configID);
+      dataSize = bGrp->sendData(clientSockFd);
+      //std::cout << "send grp " << dataSize << std::endl;
+      if (returnPlace) {
+         if (returnPlace->returnBlocks(bGrp) > 0)
+            sage::printLog("sageTcpModule::sendGrp : block pool overflow...");
+      }
+      else {
+         sage::printLog("sageTcpModule::sendGrp : no block return place");
+      }
+      bGrp->resetGrp();
+   }
+   
+   return dataSize;
+}//End of sageTcpModule::send()
+
+int sageTcpModule::flush(int id, int configID)
+{
+   if (id < 0 || id > rcvList.size()-1) {
+      sage::printLog("sageTcpModule::send() : invalid receiver ID %d", id);
+      return -1;
+   }
+   
+   int clientSockFd = rcvList[id];   
+   
+   if (config.groupSize == 0) {
+      sage::printLog("sageTcpModule::sendGrp() : group transfer is not enabled");
+      return -1;
+   }
+   
+   sageBlockGroup* bGrp = bufList[id];
+   if (bGrp->isEmpty())
+      return 0;
+   
+   int dataSize = 0;
+   bGrp->genIOV();
+   bGrp->setConfigID(configID);
+   int frameID = bGrp->front()->getFrameID(); 
+   bGrp->setFrameID(frameID);
+   
+   dataSize = bGrp->sendData(clientSockFd);
+   //std::cout << "flush grp " << dataSize << std::endl;
+   
+   if (returnPlace) {
+      if (returnPlace->returnBlocks(bGrp) > 0) {
+         sage::printLog("sageTcpModule::sendGrp : block pool overflow...");
+      }
+   }   
+   else {
+      sage::printLog("sageTcpModule::sendGrp : no block return place");
+   }
+   
+   bGrp->resetGrp();
+   
+   return dataSize;
+}//End of sageTcpModule::send()
+
+int sageTcpModule::recv(int id, sageBlock *sb, sageApiOption op)
+{
+   if (id < 0 || id > sendList.size()-1) {
+      std::cout << "sageTcpModule::recv() : invalid sender ID" << std::endl;
+      return -1;
+   }
+
+   int clientSockFd;
+   if (op & SAGE_BACKWARD)
+      clientSockFd = rcvList[id];   
+   else   
+      clientSockFd = sendList[id];
+      
+   if (clientSockFd < 0) {
+      //std::cout << "socket closed" << std::endl;
+      return -1;
+   }   
+   
+   if (op & SAGE_NON_BLOCKING) {
+      if (!sage::isDataReady(clientSockFd)) {
+         //std::cout << "no data" << std::endl;
+         return 0;
+      }   
+   }
+   
+   //std::cout << "block size = " << sb->getBufSize() << std::endl;
+   char *bufP = sb->getBuffer();
+   if (!bufP) {
+      sage::printLog("sageTcpModule::recv - block buffer is null");
+      return -1;
+   }
+   
+   int retVal = sage::recv(clientSockFd, (void *)bufP, sb->getBufSize());
+   if (retVal < 0) {
+      return -1;
+   }
+   else if (retVal == 0) {
+      #ifdef WIN32   
+      closesocket(sendList[id]);
+      #else
+      shutdown(sendList[id], SHUT_RDWR);
+      #endif
+      sendList[id] = -1;
+      return -1;
+   }
+
+   sb->updateBlockConfig();
+   
+   return sb->getBufSize();
+}//End of sageTcpModule::recv()
+
+int sageTcpModule::recvGrp(int id, sageBlockGroup *sbg)
+{
+   if (id < 0 || id > sendList.size()-1) {
+      std::cout << "sageTcpModule::recv() : invalid sender ID" << std::endl;
+      return -1;
+   }
+
+   int clientSockFd = sendList[id];
+      
+   if (clientSockFd < 0) {
+      sage::printLog("sageTcpModule::recvGrp : the socket is closed");
+      return -1;
+   }   
+   
+   if (!sbg) {
+      sage::printLog("sageTcpModule::recvGrp - block group ptr is null");
+      return -1;
+   }
+   
+   int retVal = sbg->readData(clientSockFd);
+   
+   if (retVal < 0) {
+      return -1;
+   }
+   else if (retVal == 0) {
+      #ifdef WIN32   
+      closesocket(sendList[id]);
+      #else
+      shutdown(sendList[id], SHUT_RDWR);
+      #endif
+      sendList[id] = -1;
+      return -1;
+   }
+   
+   sbg->updateConfig();
+   
+   return retVal;
+}//End of sageTcpModule::recv()
+
+int sageTcpModule::close()
+{
+   int rcvNum = rcvList.size();
+   int sendNum = sendList.size();
+   
+   if (sMode != SAGE_SEND) {
+#ifdef WIN32   
+      closesocket(serverSockFd);
+#else
+      shutdown(serverSockFd, SHUT_RDWR);
+#endif
+
+      for (int i=0; i<sendNum; i++) {
+         if (sendList[i] < 0)
+            continue;
+#ifdef WIN32   
+         closesocket(sendList[i]);
+#else
+         shutdown(sendList[i], SHUT_RDWR);
+#endif
+      }
+   }
+   
+   if (sMode != SAGE_RCV && sMode != SAGE_ARCV) {
+      for (int i=0; i<rcvNum; i++) {
+#ifdef WIN32   
+         closesocket(rcvList[i]);
+#else
+         shutdown(rcvList[i], SHUT_RDWR);
+#endif
+      }
+   }
+   
+   rcvList.clear();
+   sendList.clear();
+   
+   return 0;
+}
+
+int sageTcpModule::setSockOpts(int fd)
+{
+   int optVal, optLen;
+
+#if defined(WIN32) || defined(__APPLE__)
+   
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1;
+   optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+   {
+      std::cout << "\ntvUdp::init(): Error setting SO_REUSEADDR" <<  std::endl;
+      return false;
+   }
+
+   optVal= config.sendBufSize, optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&optVal, optLen) !=0)
+   {
+      std::cout << "sageTcpModule::setSockOpts(): Error setting SO_SNDBUF to " << optVal << " bytes";
+      return false;
+   }
+
+   optVal= config.rcvBufSize; optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&optVal, optLen) !=0)
+   {
+      std::cout << "sageTcpModule::setSockOpts(): Error setting SO_RCVBUF to " << optVal << " bytes";
+      return false;
+   }
+   
+   /*
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      std::cout << "sageTcpModule::setSockOpts(): Error switching off Nagle's algorithm." << std::endl;
+   */
+#else
+   int reuseFlag =1;
+   optLen = sizeof(reuseFlag);
+   if (setsockopt(fd, SOL_SOCKET,SO_REUSEADDR, (char *) &reuseFlag, optLen) < 0)
+   {
+      std::cout << "sageTcpModule::SetSockOpts(): Cannot set SO_REUSEADDR on socket" << std::endl;
+      return false;
+   }
+   
+   optVal= config.sendBufSize, optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&optVal, (socklen_t)optLen) != 0)
+   {
+      std::cout << "sageTcpModule::SetSockOpts(): Error setting SO_SNDBUF to " << config.sendBufSize << " bytes" << std::endl;
+      return false;
+   }
+
+   optVal= config.rcvBufSize; optLen = sizeof(optVal);
+   if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&optVal, (socklen_t)optLen) != 0)
+   {
+      std::cout << "sageTcpModule::SetSockOpts(): Error setting SO_SNDBUF to " << config.rcvBufSize << " bytes" << std::endl;
+      return false;
+   }
+   
+   /*
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cout << "sageTcpModule::setSockOpts(): Error switching off Nagle's algorithm." << std::endl;
+   */
+#endif
+
+   return true;
+} //End of sageTcpModule::setSockOpts()
+
+sageTcpModule::~sageTcpModule()
+{
+   close();
+   
+   for (int i=0; i<bufList.size(); i++) {
+      sageBlockGroup *sbg = bufList[i];
+      if (sbg)
+         delete sbg;
+   }
+
+   bufList.clear();   
+}//End of sageTcpModule::~sageTcpModule()
+
Index: trunk/src/testing/src/sageDraw.cpp
===================================================================
--- trunk/src/testing/src/sageDraw.cpp	(revision 4)
+++ trunk/src/testing/src/sageDraw.cpp	(revision 4)
@@ -0,0 +1,259 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDraw.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageDraw.h"
+#include "overlayPointer.h"
+#include "overlayApp.h"
+#include "overlayWall.h"
+
+sageDraw::sageDraw(bool &dirty, int dispID) : dirtyBit(dirty), displayID(dispID)
+{
+   preDrawList.clear();
+   postDrawList.clear();
+   interDrawList.clear();
+}
+
+sageDraw::~sageDraw()
+{
+   std::map<int, sageDrawObject *>::iterator iter;
+
+   for (iter = preDrawList.begin(); iter != preDrawList.end(); iter++) {
+      if ((*iter).second )
+         (*iter).second->destroy();
+   }
+   
+   for (iter = postDrawList.begin(); iter != postDrawList.end(); iter++) {
+      if ((*iter).second) 
+         (*iter).second->destroy();
+   }
+
+   for (iter = interDrawList.begin(); iter != interDrawList.end(); iter++) {
+      if ((*iter).second) 
+         (*iter).second->destroy();
+   }
+
+   preDrawList.clear();
+   postDrawList.clear();
+   interDrawList.clear();
+}
+
+sageDrawObject* sageDraw::createDrawObject(char *name)
+{
+   sageDrawObject *newObj = NULL;
+   
+   if (strcmp(name, "pointer") == 0) {
+      newObj = (sageDrawObject *)new overlayPointer;
+   }
+   else if (strcmp(name, "app") == 0) {
+      newObj = (sageDrawObject *)new overlayApp;
+   }
+   else if (strcmp(name, "wall") == 0) {
+	   newObj = (sageDrawObject *)new overlayWall;
+   }
+      
+   return newObj;
+}
+
+int sageDraw::preDraw(sageRect rect) 
+{
+   glDisable(GL_DEPTH_TEST);
+
+   std::map<int, sageDrawObject *>::iterator iter;
+   for (iter = preDrawList.begin(); iter != preDrawList.end(); iter++) {
+      if ((*iter).second && (*iter).second->visible && displayID==(*iter).second->displayID) {
+         (*iter).second->setViewport(rect);
+         (*iter).second->draw();
+         glColor4f(1.0, 1.0, 1.0, 1.0);   // reset the color      
+      }
+   }
+
+   glEnable(GL_DEPTH_TEST);
+
+   return 0;
+}
+
+int sageDraw::postDraw(sageRect rect) 
+{
+   glDisable(GL_DEPTH_TEST);
+
+   std::map<int, sageDrawObject *>::iterator iter;
+   for (iter = postDrawList.begin(); iter != postDrawList.end(); iter++) {
+      if ((*iter).second && (*iter).second->visible && displayID==(*iter).second->displayID) {
+         (*iter).second->setViewport(rect);
+         (*iter).second->draw();
+         glColor4f(1.0, 1.0, 1.0, 1.0);   // reset the color      
+      }
+   }
+   
+   glEnable(GL_DEPTH_TEST);
+   
+   return 0;
+}
+
+int sageDraw::interDraw(sageRect rect) 
+{
+   std::map<int, sageDrawObject *>::iterator iter;
+   for (iter = interDrawList.begin(); iter != interDrawList.end(); iter++) {
+      if ((*iter).second && (*iter).second->visible && displayID==(*iter).second->displayID) {
+         (*iter).second->setViewport(rect);
+         (*iter).second->draw();
+         glColor4f(1.0, 1.0, 1.0, 1.0);   // reset the color      
+      }
+   }
+   return 0;
+}
+
+
+// add object instances to be drawn in run-time
+int sageDraw::addObjectInstance(char *data)
+{
+   char objectName[SAGE_NAME_LEN];
+   int objID, global, drawOrder = 0, dispId=0;
+   sageRect layout;
+   sscanf(data, "%d %s %d %d %d %d %d %d %d", &objID, objectName, &layout.x, &layout.y, 
+               &layout.width, &layout.height, &global, &drawOrder, &dispId);
+
+   sageDrawObject *newInst = createDrawObject(objectName);
+   if (newInst == NULL){
+	   std::cout << "Overlay " << objectName << " not known in SAGE\n" << std::endl;
+	   return 0;
+   }
+   newInst->init(objID, objectName, layout, global, dispId);
+   
+   if (drawOrder == SAGE_POST_DRAW) { // post-draw
+      postDrawList[objID] = newInst;
+   }
+   else if (drawOrder == SAGE_INTER_DRAW) { // inter-draw (window border)
+      interDrawList[objID] = newInst;
+   }
+   else { // pre-draw
+      preDrawList[objID] = newInst;
+   }
+   
+   return 0;
+}
+
+int sageDraw::updateObjectPosition(char *data)
+{
+   int x, y, id = -1;
+   sscanf(data, "%d %d %d", &id, &x, &y);
+   
+   // find the object we are changing and update it
+   if (preDrawList.count(id) > 0)
+      preDrawList[id]->updatePosition(x,y);
+
+   else if (postDrawList.count(id) > 0)
+      postDrawList[id]->updatePosition(x,y);
+
+   else if (interDrawList.count(id) > 0)
+      interDrawList[id]->updatePosition(x,y);
+
+   return 0;
+}
+
+int sageDraw::removeObject(int id)
+{
+   // find the object we are removing and erase it
+   if (preDrawList.count(id) > 0) {
+      preDrawList[id]->destroy();
+      delete preDrawList[id];
+      preDrawList.erase(id);
+   }
+
+   else if (postDrawList.count(id) > 0) {
+      postDrawList[id]->destroy();
+      delete postDrawList[id];
+      postDrawList.erase(id);
+   }
+
+   else if (interDrawList.count(id) > 0) {
+      interDrawList[id]->destroy();
+      delete interDrawList[id];
+      interDrawList.erase(id);
+   }
+
+   return 0;
+}
+
+int sageDraw::showObject(char *data)
+{
+   int id = -1;
+   int doShow = 1;
+   sscanf(data, "%d %d", &id, &doShow);
+   
+   // find the object we are changing and update it
+   if (preDrawList.count(id) > 0)
+      preDrawList[id]->showObject(bool(doShow));
+
+   else if (postDrawList.count(id) > 0)
+      postDrawList[id]->showObject(bool(doShow));
+
+   else if (interDrawList.count(id) > 0)
+      interDrawList[id]->showObject(bool(doShow));
+
+   return 0;
+}
+
+int sageDraw::forwardObjectMessage(char *data)
+{
+   int id;
+
+   // loop through the whole message, split it by newlines 
+   // and send them off to the right objects
+
+   char *oneMessage = strtok(data, "\n");
+
+   while (oneMessage != NULL) {
+      sscanf(oneMessage, "%d", &id);
+
+      if (preDrawList.count(id) > 0)
+         preDrawList[id]->parseMessage( oneMessage );
+
+      else if (postDrawList.count(id) > 0)
+         postDrawList[id]->parseMessage( oneMessage );
+      
+      else if (interDrawList.count(id) > 0)
+         interDrawList[id]->parseMessage( oneMessage );
+
+      oneMessage = strtok(NULL, "\n");
+   }
+
+   return 0;
+}
Index: trunk/src/testing/src/bridgeStreamer.cpp
===================================================================
--- trunk/src/testing/src/bridgeStreamer.cpp	(revision 4)
+++ trunk/src/testing/src/bridgeStreamer.cpp	(revision 4)
@@ -0,0 +1,333 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: bridgeStreamer.cpp - distributes pixel blocks 
+ *         to multiple tiled displays
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageStreamer.h"
+#include "sageBlockPool.h"
+//#include "streamInfo.h"
+#include "sageBlockPartition.h"
+
+bridgeStreamer::bridgeStreamer(streamerConfig &conf, sageBlockBuf *buf, streamProtocol *obj) 
+{
+   config = conf; 
+   nwObj = obj;
+   partition = new sageBlockPartition(config.blockX, config.blockY, config.totalWidth,
+      config.totalHeight);
+   partition->initBlockTable();
+   blockSize = conf.blockSize;
+      
+   blockBuffer = buf;
+   frameID = blockBuffer->addReader(config.streamerID);
+   if (config.streamerID > 0)
+      updateType = SAGE_UPDATE_FRAME;
+   else
+      updateType = SAGE_UPDATE_FOLLOW;   
+   
+   interval = 1000000.0/config.frameRate;
+   firstFrame = true;
+   accInterval = 0.0;
+}
+
+int bridgeStreamer::initNetworks(char *data, bool localPort)
+{
+   char token[TOKEN_LEN];
+   sageToken tokenBuf(data);
+   tokenBuf.getToken(token);
+      
+	int rcvPort = atoi(token) + (int)config.protocol;
+   if (nwObj) {   
+   nwObj->setConfig(rcvPort, config.blockSize, config.groupSize);
+   sage::printLog("bridgeStreamer : network object was initialized successfully");
+   std::cout << "block size = " << config.blockSize << std::endl;
+   	std::cout << "group size = " << config.groupSize << std::endl;
+	}
+	else {
+		nwCfg.blockSize = config.blockSize;
+   	nwCfg.groupSize = config.groupSize;
+		nwObj = (streamProtocol *)new sageTcpModule;
+      nwObj->init(SAGE_SEND, rcvPort, nwCfg);
+      sage::printLog("bridgeStreamer::initNetworks : initialize TCP object");
+	}
+   
+   connectToRcv(tokenBuf, localPort);
+   setupBlockPool();
+   nwObj->setFrameRate((double)config.frameRate);
+   streamTimer.reset();
+   
+   if (pthread_create(&thId, 0, nwThread, (void*)this) != 0) {
+      sage::printLog("sageBlockStreamer : can't create nwThread");
+      return -1;
+   }
+   
+   return 0;
+}
+
+void bridgeStreamer::setupBlockPool()
+{ 
+   for (int i=0; i<rcvNodeNum; i++) {
+      nwObj->setupBlockPool(blockBuffer, params[i].rcvID); 
+   }
+}
+
+int bridgeStreamer::storeStreamConfig(char *msgStr)
+{
+   if (config.nodeNum > 1) { 
+      if (config.master) {
+         config.sGroup->enqueSyncMsg(msgStr);
+         config.sGroup->unblockSync();   
+      }   
+      //config.syncClientObj->sendSlaveUpdate(1);   
+   }
+   else {
+      enqueMsg(msgStr);
+   }
+   
+   return 0;
+}
+
+int bridgeStreamer::streamLoop()
+{
+   std::cout << "node " << config.rank << " stream loop started " << std::endl;
+   while (streamerOn) {
+      char *msgStr = NULL;
+      
+      if (config.nodeNum > 1){
+         //std::cout << "node " << config.rank << " syncGroup " << config.syncID << " send update " << frameID << std::endl;
+         config.syncClientObj->sendSlaveUpdate(frameID, config.syncID, config.nodeNum, updateType);
+         updateType = SAGE_UPDATE_FOLLOW;
+         syncMsgStruct *syncMsg = config.syncClientObj->waitForSync(config.syncID);
+         if (syncMsg) {
+            frameID = syncMsg->frameID;
+         
+            //std::cout << "node " << config.rank << " syncGroup " << config.syncID << " receive sync " << frameID << std::endl;
+
+            if (syncMsg->data) {
+               reconfigureStreams(syncMsg->data);
+               //std::cout << "node " << config.rank << " streamer " << config.streamerID << "reconfigure streams" << std::endl;
+            }   
+            
+            delete syncMsg;
+         }   
+      }
+      else {
+         pthread_mutex_lock(reconfigMutex);
+         if (msgQueue.size() > 0) {
+            msgStr = msgQueue.front();
+            reconfigureStreams(msgStr);
+            msgQueue.pop_front();
+            delete [] msgStr;
+            firstConfiguration = false;
+            //std::cout << "reconfigure bridge streamer" << std::endl;
+         }
+         pthread_mutex_unlock(reconfigMutex);
+      }
+      
+      if (config.nodeNum == 1)
+         checkInterval();
+      
+      if (streamPixelData() < 0) {
+         streamerOn = false;
+      }
+   }   
+   
+   sage::printLog("bridgeStreamer : network thread exit");
+   
+   return 0;
+}
+
+int bridgeStreamer::streamPixelData()
+{
+   if (streamNum < 1) {
+      sage::printLog("bridgeStreamer::streamPixelData : No Active Streams");
+      return -1;
+   }
+
+   // fetch block data from block buffer
+   bool loop = true;
+   int curFrame = 0;
+   
+   while (loop) {
+      //std::cout << "waiting for data" << std::endl;
+      sageBlockGroup *sbg = blockBuffer->front(config.streamerID, frameID);
+      //std::cout << "get data" << std::endl;
+      
+      while (streamerOn && !sbg) {
+         blockBuffer->next(config.streamerID);
+         sbg = blockBuffer->front(config.streamerID);
+      }
+      
+      if (!sbg)
+         return -1;
+   
+      int flag = sbg->getFlag();
+   
+      if (flag == sageBlockGroup::PIXEL_DATA) {
+         curFrame = sbg->getFrameID();
+         for (int i=0; i<sbg->getBlockNum(); i++) {
+            sagePixelBlock *block = (*sbg)[i];
+            
+            if (!block)
+               continue;
+               
+            sendPixelBlock(block);
+         }   
+      }
+      else if (flag == sageBlockGroup::END_FRAME) {
+         loop = false;
+      }
+         
+      blockBuffer->next(config.streamerID);
+   }
+   
+   if (sendControlBlock(SAGE_UPDATE_BLOCK, ALL_CONNECTION) < 0)
+      return -1;
+   
+   frameID = curFrame + 1;
+      
+   if (firstFrame) {
+      firstFrame = false;
+      frameTimer.reset();
+      accInterval = 0.0;
+   }
+   else if (config.frameDrop && config.nodeNum == 1) {
+      accInterval += blockBuffer->getFrameInterval();
+      //accInterval += 1000000.0/config.frameRate;
+
+      if (frameTimer.getTimeUS() > accInterval+blockBuffer->getFrameInterval()) {
+         std::cout << "drop frame " << frameID << std::endl;
+         frameID++;  
+
+         accInterval = 0.0;
+         frameTimer.reset();   
+      }
+   }
+   
+   frameCounter++;
+
+   for (int j=0; j<rcvNodeNum; j++) {
+      if (!params[j].active)
+         nwObj->setFrameSize(params[j].rcvID, blockSize);
+         
+		int dataSize = nwObj->flush(params[j].rcvID, configID);
+      if (dataSize > 0) {
+         totalBandWidth += dataSize;
+      }   
+      else if (dataSize < 0) {
+         sage::printLog("bridgeStreamer::streamPixelData : fail to flush pixel block group");
+         return -1;
+      }   
+	}
+   
+   return 0;
+}
+
+int bridgeStreamer::sendPixelBlock(sagePixelBlock *block)
+{
+   if (!partition)
+      sage::printLog("bridgeStreamer::sendPixelBlock : block partition is not initialized");
+   pixelBlockMap *map = partition->getBlockMap(block->getID());
+   
+   if (map)
+      block->getGroup()->reference(map->count);
+   
+   while(map) {
+      params[map->infoID].active = true;
+      int dataSize = nwObj->sendGrp(params[map->infoID].rcvID, block, configID);
+      if (dataSize > 0) {
+         totalBandWidth += dataSize;
+      }   
+      else if (dataSize < 0) {
+         sage::printLog("sageBlockStreamer::sendPixelBlock : fail to send pixel block");
+         return -1;
+      }   
+      map = map->next;
+   }   
+
+   return 0;
+}
+
+int bridgeStreamer::sendControlBlock(int flag, int cond)
+{
+   for (int j=0; j<rcvNodeNum; j++) {   
+      bool sendCond = false;
+      
+      switch(cond) {
+         case ALL_CONNECTION :
+            sendCond = true;
+            break;
+         case ACTIVE_CONNECTION :
+            sendCond = params[j].active;
+            break;
+         case INACTIVE_CONNECTION :
+            sendCond = !params[j].active;
+            break;         
+      }
+      
+      if (sendCond) {
+         int dataSize = nwObj->sendControl(params[j].rcvID, frameID, configID);
+         if (dataSize > 0)
+            totalBandWidth += dataSize;
+         else if (dataSize < 0) {
+            sage::printLog("bridgeStreamer::sendControlBlock : fail to send control block");
+            return -1;
+         }
+      }
+   }   
+      
+   return 0;
+}
+
+void bridgeStreamer::shutdown()
+{
+   streamerOn = false;
+   std::cout << "pt0" << std::endl;
+   if (config.nodeNum > 1){
+      config.syncClientObj->removeSyncGroup(config.syncID);
+   }
+   blockBuffer->removeReader(config.streamerID);
+   std::cout << "pt1" << std::endl;
+   pthread_join(thId, NULL);
+   std::cout << "pt2" << std::endl;
+   
+   for (int j=0; j<rcvNodeNum; j++)
+      nwObj->close(params[j].rcvID, SAGE_SEND);
+         
+   sage::printLog("< bridgeStreamer shutdown >");
+}
Index: trunk/src/testing/src/fsServer.cpp
===================================================================
--- trunk/src/testing/src/fsServer.cpp	(revision 4)
+++ trunk/src/testing/src/fsServer.cpp	(revision 4)
@@ -0,0 +1,367 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsServer.cpp - a component of the Free Space Manager which takes care
+ *         of communication with Free Space Manager Clients
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "fsServer.h"
+#include "fsManager.h"
+
+fsServer::fsServer()
+{
+   sysServer = NULL;
+   uiServer = NULL;
+   fsm = NULL;
+
+   //maxNumOfApp = 0;
+}
+
+fsServer::~fsServer()
+{
+   if (sysServer)
+      delete sysServer;
+
+   if (uiServer)
+      delete uiServer;
+}
+
+int fsServer::init(fsManager *m)
+{
+   fsm = m;
+   numSysClients = 0;
+   numUiClients = 0;
+
+   sysServer = new QUANTAnet_tcpServer_c;
+   sysServer->init(fsm->getSysPort());
+   sysServer->setSockOptions(QUANTAnet_tcpServer_c::READ_BUFFER_SIZE, 65536);
+   sysServer->setSockOptions(QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE, 65536);
+
+   uiServer = new QUANTAnet_tcpServer_c;
+   uiServer->init(fsm->getUiPort());
+   uiServer->setSockOptions(QUANTAnet_tcpServer_c::READ_BUFFER_SIZE, 65536);
+   uiServer->setSockOptions(QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE, 65536);
+
+   return 0;
+}
+
+int fsServer::checkClients()
+{
+   QUANTAnet_tcpClient_c *aClient;
+
+   // If a connection is established, accept it and create
+   // a new socket for that connection to communicate with.
+
+   aClient = sysServer->checkForNewConnections();
+
+   if (aClient) {
+      printf("sysClient %d connected\n", numSysClients);
+		aClient->setTimeOut(1);
+      sysClientList.push_back(aClient);
+      numSysClients++;
+   }
+
+   aClient = uiServer->checkForNewConnections();
+
+   if (aClient) {
+      printf("uiClient %d connected\n", numUiClients);
+		aClient->setTimeOut(1);
+      uiClientList.push_back(aClient);
+      numUiClients++;
+   }
+
+   sageMessage msg;
+
+   int dataSize;
+   int status;
+
+   for (int i = 0; i < numSysClients; i++) {
+      if (sysClientList[i]) {
+         char msgSize[MESSAGE_FIELD_SIZE];
+         dataSize = MESSAGE_FIELD_SIZE;
+         status = sysClientList[i]->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::NON_BLOCKING);
+
+         if (status == QUANTAnet_tcpClient_c::OK)  {
+            msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+            dataSize = atoi(msgSize);
+            msg.init(dataSize);
+            dataSize = dataSize - MESSAGE_FIELD_SIZE;
+            sysClientList[i]->read((char *)msg.getBuffer()+MESSAGE_FIELD_SIZE, &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+           /*
+               printf("Read in message from client %d\n",i+SYSTEM_CLIENT_BASE);
+               std::cout << "\tmessage code: " << msg.getCode() << std::endl;
+               if (msg.getData())
+                  std::cout << "\t" << (char *)msg.getData() << std::endl;
+               else
+                  std::cout << std::endl;
+				  */
+
+            /**
+			if ( msg.getCode() == REG_APP ) {
+				maxNumOfApp++;
+				fprintf(stderr,"fsServer::checkClients() : maxNumOfApp %u\n", maxNumOfApp);
+				if ( maxNumOfApp > (SAGE_SYNC_MSG_LEN/sizeof(int))/2 ) {
+					fprintf(stderr,"fsServer::checkClients() : max num of app %d has reached. \n", (SAGE_SYNC_MSG_LEN/sizeof(int))/2);
+					sendMessage(i+SYSTEM_CLIENT_BASE, APP_QUIT);
+					msg.destroy();
+					break;
+				}
+				else {
+				}
+			}
+			**/
+
+
+            if (msg.getCode() < DISP_MESSAGE) {
+               fsm->msgToCore(msg, i+SYSTEM_CLIENT_BASE);
+            }
+            else if (msg.getCode() < GRCV_MESSAGE) {
+               fsm->msgToDisp(msg, i+SYSTEM_CLIENT_BASE);
+            }
+            else
+               sendMessage(msg);
+
+            msg.destroy();
+         }
+         else if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED) {
+            std::cout << "fsServer::checkClients() : connection to client " << i+SYSTEM_CLIENT_BASE << " was terminated" << std::endl;
+            sysClientList[i] = NULL;
+
+            /*
+			maxNumOfApp--;
+			fprintf(stderr,"fsServer::checkClients() : maxNumOfApp %u\n", maxNumOfApp);
+			*/
+
+            return 1;
+         }
+      }
+   }
+
+   for (int i = 0; i < numUiClients; i++) {
+      if (uiClientList[i]) {
+         bool flag = true;
+         while(flag) {
+            flag = false;
+            char msgSize[MESSAGE_FIELD_SIZE];
+            dataSize = MESSAGE_FIELD_SIZE;
+
+            status = uiClientList[i]->read(msgSize, &dataSize, QUANTAnet_tcpClient_c::NON_BLOCKING);
+
+            if (status == QUANTAnet_tcpClient_c::OK)  {
+               flag = true;
+               msgSize[MESSAGE_FIELD_SIZE-1] = '\0';
+               dataSize = atoi(msgSize);
+               msg.init(dataSize);
+               dataSize = dataSize - MESSAGE_FIELD_SIZE;
+               uiClientList[i]->read((char *)msg.getBuffer()+MESSAGE_FIELD_SIZE,
+                  &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+               //printf("Read in message from client %d\n",i);
+               //std::cout << "messge : " << msg.getCode() << std::endl;
+               //if (msg.getData())
+               //   std::cout << (char *)msg.getData() << std::endl;
+               //else
+               //   std::cout << std::endl;
+
+               if (msg.getCode() < DISP_MESSAGE) {
+                  fsm->msgToCore(msg, i);
+               }
+               else
+                  sendMessage(msg);
+
+               msg.destroy();
+            }
+            else if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED) {
+               std::cout << "fsCore::checkClients() : connection to client " << i << " was terminated" << std::endl;
+               uiClientList[i] = NULL;
+               return 1;
+            }
+         } // end while
+      } // end if
+   } // end for
+
+   return 0;
+}
+
+int fsServer::sendMessage(int cId, int code, int data)
+{
+	QUANTAnet_tcpClient_c *aClient = NULL;
+   if (cId >= SYSTEM_CLIENT_BASE)
+		aClient = sysClientList[cId-SYSTEM_CLIENT_BASE];
+	else
+		aClient = uiClientList[cId];
+
+   if (!aClient) {
+		return -1;
+   }
+
+   sageMessage msg;
+   char msgStr[TOKEN_LEN];
+   sprintf(msgStr, "%d", data);
+
+   if (msg.init(cId, code, 0, strlen(msgStr)+1, msgStr) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+
+   int dataSize = msg.getBufSize();
+   int status = aClient->write((char *)msg.getBuffer(), &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+   if (status == QUANTAnet_tcpClient_c::TIMED_OUT ||
+		status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED)  {
+      if (cId >= SYSTEM_CLIENT_BASE)
+			sysClientList[cId-SYSTEM_CLIENT_BASE] = NULL;
+		else
+			uiClientList[cId] = NULL;
+		msg.destroy();
+      return -1;
+   }
+
+   msg.destroy();
+
+   return 0;
+}
+
+int fsServer::sendMessage(int cId, int code, char* data)
+{
+	QUANTAnet_tcpClient_c *aClient = NULL;
+   if (cId >= SYSTEM_CLIENT_BASE)
+		aClient = sysClientList[cId-SYSTEM_CLIENT_BASE];
+	else
+		aClient = uiClientList[cId];
+
+   if (!aClient) {
+		return -1;
+   }
+
+   sageMessage msg;
+
+   if (msg.init(cId, code, 0, strlen(data)+1, data) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+
+   int dataSize = msg.getBufSize();
+   int status = aClient->write((char *)msg.getBuffer(), &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+   if (status == QUANTAnet_tcpClient_c::TIMED_OUT ||
+		status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED)  {
+      if (cId >= SYSTEM_CLIENT_BASE)
+			sysClientList[cId-SYSTEM_CLIENT_BASE] = NULL;
+		else
+			uiClientList[cId] = NULL;
+		msg.destroy();
+      return -1;
+   }
+
+   msg.destroy();
+
+   return 0;
+}
+
+int fsServer::sendMessage(int cId, int code)
+{
+	QUANTAnet_tcpClient_c *aClient = NULL;
+   if (cId >= SYSTEM_CLIENT_BASE)
+		aClient = sysClientList[cId-SYSTEM_CLIENT_BASE];
+	else
+		aClient = uiClientList[cId];
+
+   if (!aClient) {
+		return -1;
+   }
+
+   sageMessage msg;
+
+   if (msg.init(cId, code, 0, 0, NULL) < 0) {
+      std::cerr << "fail to init the message!" << std::endl;
+      return -1;
+   }
+
+   int dataSize = msg.getBufSize();
+   int status = aClient->write((char *)msg.getBuffer(), &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+   if (status == QUANTAnet_tcpClient_c::TIMED_OUT ||
+		status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED)  {
+      if (cId >= SYSTEM_CLIENT_BASE)
+			sysClientList[cId-SYSTEM_CLIENT_BASE] = NULL;
+		else
+			uiClientList[cId] = NULL;
+		msg.destroy();
+      return -1;
+   }
+
+   msg.destroy();
+
+   return 0;
+}
+
+int fsServer::sendMessage(sageMessage &msg)
+{
+   int dataSize = msg.getBufSize();
+   int cId = msg.getDest();
+
+	QUANTAnet_tcpClient_c *aClient = NULL;
+   if (cId >= SYSTEM_CLIENT_BASE)
+		aClient = sysClientList[cId-SYSTEM_CLIENT_BASE];
+	else
+		aClient = uiClientList[cId];
+
+   if (!aClient) {
+		return -1;
+   }
+
+   /*
+   char abc[1024];
+   aClient->getRemoteIP(abc);
+   fprintf(stderr,"fsServer::sendMessage() : write to %s, data %s\n", abc, (char*)msg.getData());
+   */
+
+   int status = aClient->write((char *)msg.getBuffer(), &dataSize, QUANTAnet_tcpClient_c::BLOCKING);
+
+   if (status == QUANTAnet_tcpClient_c::TIMED_OUT ||
+		status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED)  {
+      if (cId >= SYSTEM_CLIENT_BASE)
+			sysClientList[cId-SYSTEM_CLIENT_BASE] = NULL;
+		else
+			uiClientList[cId] = NULL;
+      return -1;
+   }
+
+   return 0;
+}
Index: trunk/src/testing/src/sageSharedData.cpp
===================================================================
--- trunk/src/testing/src/sageSharedData.cpp	(revision 4)
+++ trunk/src/testing/src/sageSharedData.cpp	(revision 4)
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageSharedData.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageSharedData.h"
+#include "streamProtocol.h"
+#include "sageEvent.h"
+#include "sageDisplay.h"
+#include "sageSync.h"
+
+rcvSharedData::rcvSharedData() : nodeID(-1), syncClientObj(NULL), bufSize(8388608) 
+{
+   eventQueue = new sageEventQueue;
+}
+
+rcvSharedData::~rcvSharedData()
+{
+   //std::cout << "delete eventQueue" << std::endl;   
+   if (eventQueue)
+      delete eventQueue;
+}
+
+dispSharedData::~dispSharedData()
+{
+   //std::cout << "delete displayObject" << std::endl;   
+   //if (displayObj)
+   //   delete displayObj;
+
+   //std::cout << "delete syncClientObject" << std::endl;               
+   //if (syncClientObj)
+   //   delete syncClientObj;
+}
+
+bridgeSharedData::~bridgeSharedData()
+{
+   delete sendObj;
+}
Index: trunk/src/testing/src/audioFormatManager.cpp
===================================================================
--- trunk/src/testing/src/audioFormatManager.cpp	(revision 4)
+++ trunk/src/testing/src/audioFormatManager.cpp	(revision 4)
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module   :  audioFormatManager.cpp
+ *   Author   :   Hyejung Hur
+ *   Description:   Code file for 
+ *   
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+***************************************************************************************************************************/
+
+#include "audioFormatManager.h"
+#include "wavConverter.h"
+
+audioFormatManager::audioFormatManager()
+{
+   converterList.clear();
+}
+
+
+audioFormatManager::~audioFormatManager()
+{
+}
+
+
+audioConverter* audioFormatManager::createConverter(char* filename, FILE* fp)
+{
+   int len = strlen(filename);
+   int i=0, j=0;
+   char tag[25];
+   for(i =0; i <25 ; i++) tag[i] = '\0';
+   
+   for(i=len-1; i >= 0; i--, j++) {
+      if(filename[i] == '.') {
+         break;
+      } 
+   }
+
+   if(i > 0) {
+      j=i+1;
+      i =0;
+      for(; j < len; j++, i++) {
+         tag[i] = filename[j];
+      }
+   }
+   
+   std::cout << " audioFormatManager::createConverter: " << tag << " : " << filename << std::endl; 
+   int result;
+   if( (strcmp(tag, "wav") ==0) || (strcmp(tag, "wave")==0) ) {
+      wavConverter* object = new wavConverter();
+      result = object->init(fp);
+      if(result < 0) {
+         delete object;
+         object = NULL;
+      } 
+      else {
+         converterList.push_back(object);   
+      }
+      return object;
+   }
+   return NULL;
+   
+}
Index: trunk/src/testing/src/appInstance.cpp
===================================================================
--- trunk/src/testing/src/appInstance.cpp	(revision 4)
+++ trunk/src/testing/src/appInstance.cpp	(revision 4)
@@ -0,0 +1,500 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: appInstance.cpp - manaing each application instance of SAGE Bridge
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "appInstance.h"
+#include "messageInterface.h"
+#include "sageReceiver.h"
+#include "sageSharedData.h"
+#include "sageEvent.h"
+#include "sageBlockPool.h"
+
+appInstance::appInstance(char *msgStr, int id, bridgeSharedData *sh) : instID(id), shared(sh),
+      firstSyncGroup(NULL), firstSyncID(0), initialized(false), maxStreamerIdx(0), 
+      blockSize(0), groupSize(0)
+{
+   sscanf(msgStr, "%s %d %d %d %d %d %s %d %d %d %d %d", appName, &x, &y, &width, &height, 
+      (int *)&sConfig.protocol, fsIP, &fsPort, &imageWidth, &imageHeight, &blockNum, 
+      (int *)&audioOn);
+   
+   std::cout << "create app instance on node " << shared->nodeID << std::endl;
+      
+   if (shared && shared->nodeID > 0) {
+      sscanf(sage::tokenSeek(msgStr, 12), "%d %d", &nodeNum, &firstSyncID);
+   }   
+   
+   allocInfoList.clear();
+   for (int i=0; i<MAX_ENDPOINT_NUM; i++) {
+      streamerList[i] = NULL;
+      slaveFRate[i] = 0.0;
+   }   
+      
+   validIdx = 0;
+   reportRate = 1;
+   reportCnt = 0;
+   slaveBandWidth = 0.0;
+   accBandWidth = 0.0;
+   curBandWidth = 0.0;
+   accLoss = 0.0;
+   slaveLoss = 0.0;
+   packetLoss = 0;
+   perfTimer.reset();
+
+   numOfSenders = 1;
+}
+
+appInstance::~appInstance()
+{
+   delete recv;
+   delete blockBuf;
+}   
+
+int appInstance::allocateNodes(int policy, int nID)
+{
+   if (policy == ALLOC_LOAD_BALANCING) {
+      nodeNum = shared->nodeNum;
+      if (nodeNum < 1) {
+         sage::printLog("appInstance::allocateNodes : error in bridge node number : %d", nodeNum);
+         return -1;
+      }   
+      float partition = ((float)blockNum)/nodeNum;
+      for (int i=0; i<nodeNum; i++) {
+         nodeAllocInfo info;
+         info.nodeID = i;
+         info.blockID = (int)floor(partition*(i+1) + 0.5) - 1;
+         allocInfoList.push_back(info);
+      }
+   }
+   else if (policy == ALLOC_SINGLE_NODE) {
+      nodeNum = 1;
+      nodeAllocInfo info;
+      info.nodeID = nID;
+      info.blockID = blockNum - 1;
+      allocInfoList.push_back(info);
+   }
+   
+   return 0;
+}
+
+/**
+ * from sageBridge::initStreams()
+ */
+int appInstance::init(char *msg, streamProtocol *nwObj)
+{   
+	/*
+	sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d %d",
+	    		  config.streamType,
+	    		  config.frameRate,
+	    		  winID,
+	    		  config.groupSize,
+	    		  blockSize,
+	    		  config.nodeNum,
+	    		  (int)config.pixFmt,
+	    		  config.blockX,
+	    		  config.blockY,
+	    		  config.totalWidth,
+	    		  config.totalHeight,
+	    		  config.fromBridgeParallel); */
+	//sageBridge::initStreams() : msg [2 103 60 1 131072 12416 4 5 64 64 800 800 0]
+
+   initialized = true;   
+
+   int dummy;
+   sscanf(msg, "%d %d %d %d %d %d %d %d %d %d",
+		   &dummy,
+		   &sConfig.streamType,
+		   &sConfig.frameRate,
+		   &dummy,
+		   &groupSize,
+		   &blockSize,
+		   &numOfSenders,
+		   (int *)&sConfig.pixFmt,
+		   &sConfig.blockX,
+		   &sConfig.blockY
+		   );
+
+   /*
+   char *msgPt = sage::tokenSeek(msg, 1);
+   sscanf(msgPt, "%d %d", &sConfig.streamType, &sConfig.frameRate);
+   
+   msgPt = sage::tokenSeek(msg, 4);
+   sscanf(msgPt, "%d %d", &groupSize, &blockSize);   
+   
+   msgPt = sage::tokenSeek(msg, 6);
+   sscanf(msgPt, "%d %d %d %d", &numOfSenders, (int *)&sConfig.pixFmt, &sConfig.blockX, &sConfig.blockY);
+   */
+   
+   std::cout << "block buffer size " << shared->bufSize << std::endl;
+   
+   blockBuf = new sageBlockBuf(shared->bufSize, groupSize, blockSize, 
+         BUF_MEM_ALLOC | BUF_CTRL_GROUP | BUF_MULTI_READER);
+
+   addStreamer(0, 0, firstSyncGroup, firstSyncID);      
+   recv = new sagePixelReceiver(msg, shared, nwObj, blockBuf);
+   
+   return 0;
+}
+
+int appInstance::addStreamer(int fsIdx, int orgIdx, syncGroup *sGroup, int syncID)
+{
+   if (!initialized)
+      return 0;
+      
+   // add a sage streamer to the app instance
+   sConfig.master = (shared->nodeID == 0);
+   sConfig.nodeNum = nodeNum;
+   sConfig.rank = shared->nodeID;
+   sConfig.streamerID = fsIdx;
+   sConfig.sGroup = sGroup;
+   if (sGroup) {
+      sConfig.syncID = sGroup->getSyncID();
+      sGroup->setFrameRate(sConfig.frameRate);
+   }
+   else
+      sConfig.syncID = syncID;
+   sConfig.blockSize = blockSize;
+   sConfig.groupSize = groupSize;
+   sConfig.totalWidth = imageWidth;
+   sConfig.totalHeight = imageHeight;
+    
+   sConfig.syncClientObj = shared->syncClientObj;   
+   sConfig.syncClientObj->addSyncGroup(sConfig.syncID);
+   //sConfig.frameDrop = shared->frameDrop;
+   sConfig.frameDrop = false;
+   
+   bridgeStreamer *streamer = NULL;
+   sConfig.protocol = shared->protocol;
+
+   if ( numOfSenders > 1 )
+	   sConfig.fromBridgeParallel = true; //sungwon
+      
+   if (shared->protocol == SAGE_TCP)
+      streamer = new bridgeStreamer(sConfig, blockBuf, NULL);
+   else
+      streamer = new bridgeStreamer(sConfig, blockBuf, shared->sendObj);
+      
+   streamerList[fsIdx] = streamer;
+   maxStreamerIdx = MAX(maxStreamerIdx, fsIdx);
+   
+   return 0;
+}
+
+int appInstance::addStream(int senderID)
+{
+   int streamNum = recv->addStream(senderID);
+   
+   return streamNum;
+}
+
+int appInstance::sendPerformanceInfo()
+{
+   //Calculate performance here
+   //if (validIdx < 0)
+   //   return 0;
+   
+   double elapsedTime = perfTimer.getTimeUS();
+         
+   if (reportRate > 0 && elapsedTime > (1000000.0 * reportRate)) {
+      if (initialized) {
+         unsigned long bandWidth = 0;
+         for (int i=0; i<=maxStreamerIdx; i++) {
+            if (streamerList[i]) {
+               bandWidth += streamerList[i]->getBandWidth();
+               streamerList[i]->resetBandWidth();
+            }   
+         }   
+
+         float obsBandWidth = (float) (bandWidth * 8.0f / elapsedTime);
+         //float obsLoss = (float) (packetLoss * 8.0 / elapsedTime);
+         //packetLoss = 0;
+
+         char msgStr[TOKEN_LEN];
+
+         if (shared->nodeID == 0) {
+            float totalBandWidth = slaveBandWidth+obsBandWidth;
+            curBandWidth = totalBandWidth;
+            
+            //float totalLoss = slaveLoss+obsLoss;
+            //float lossPercent = totalLoss*100/(totalBandWidth+totalLoss);
+
+            for (int i=0; i<=maxStreamerIdx; i++) {
+               if (streamerList[i]) {
+                  float frameRate = (float)((streamerList[i]->getFrameCount())*1000000.0/elapsedTime);
+                  streamerList[i]->resetFrameCounter();
+                  sprintf(msgStr, "%d %7.2f %7.2f %7.2f", fsList[i], totalBandWidth, frameRate, 0.0);
+                  shared->eventQueue->appendEvent(EVENT_MASTER_PERF_INFO, msgStr);
+               }   
+            }   
+         }
+         else {
+            sageToken frameToken(TOKEN_LEN);
+            int tokenCnt = 0;
+            for (int i=0; i<=maxStreamerIdx; i++) {
+               if (streamerList[i]) {
+                  float frameRate = (float)((streamerList[i]->getFrameCount())*1000000.0/elapsedTime);
+                  streamerList[i]->resetFrameCounter();
+                  char frameRateStr[TOKEN_LEN];
+                  sprintf(frameRateStr, "%d %7.2f", i, frameRate);
+                  frameToken.putToken(frameRateStr);
+                  tokenCnt++;
+               }   
+            }
+            
+            //std::cout << "frame token " << frameToken.getBuffer() << std::endl;
+                     
+            sprintf(msgStr, "%d %7.2f %7.2f %d %s", instID, obsBandWidth, 0.0, tokenCnt, frameToken.getBuffer());
+            shared->eventQueue->appendEvent(EVENT_SLAVE_PERF_INFO, msgStr);
+         }
+
+         char bufInfo[TOKEN_LEN];
+         blockBuf->getBufInfo(bufInfo);
+         //std::cout << "<buffer status> sb " << shared->nodeID << " " << bufInfo << std::endl;
+      }
+      else {
+         char msgStr[TOKEN_LEN];
+
+         if (shared->nodeID == 0) {
+            curBandWidth = slaveBandWidth;
+            for (int i=0; i<fsList.size(); i++) {
+               if (fsList[i] >= 0) {
+                  //std::cout << "slave frame rate " << slaveFRate[i] << std::endl;
+                  sprintf(msgStr, "%d %7.2f %7.2f %7.2f", fsList[i], slaveBandWidth, slaveFRate[i], 0.0);
+                  shared->eventQueue->appendEvent(EVENT_MASTER_PERF_INFO, msgStr);
+               }
+            }   
+         }
+      }
+            
+      perfTimer.reset();
+   }
+   
+   
+   return 0;   
+}
+
+int appInstance::startPerformanceReport(sageMessage &msg)
+{
+   int rate = atoi((char *)msg.getData());
+   
+   reportRate = rate;
+   perfTimer.reset();
+   
+   for (int i=0; i<=maxStreamerIdx; i++) {
+      if (streamerList[i]) {
+         streamerList[i]->resetBandWidth();
+         streamerList[i]->resetFrameCounter();
+      }   
+   }   
+   
+   return 0;
+}
+
+int appInstance::accumulateBandWidth(char *data)
+{
+   //std::cout << "slave perf data " << data << std::endl;
+   float bWidth, pLoss;
+   int frateNum;
+   sscanf(data, "%f %f %d", &bWidth, &pLoss, &frateNum);
+   
+   accBandWidth += bWidth;
+   accLoss += pLoss;
+   reportCnt++;
+   
+   int perfWait = nodeNum-1;
+   if (!initialized) {
+      perfWait = nodeNum;
+      char *frateStr = sage::tokenSeek(data, 3);
+      
+      for (int i=0; i<frateNum; i++) {
+         int idx;
+         float frameRate;
+         sscanf(frateStr, "%d %f", &idx, &frameRate);
+         //std::cout << "slave " << idx << " frate " << token << std::endl;
+         
+         slaveFRate[idx] = frameRate;
+      }
+   }
+   
+   if (reportCnt >= perfWait) {
+      slaveBandWidth = accBandWidth;
+      slaveLoss = accLoss;
+      accBandWidth = 0.0;
+      accLoss = 0.0;
+      reportCnt = 0;
+   }
+   
+   return 0;
+}
+
+int appInstance::findValidIdx()
+{
+   int i=0;
+   for ( ; i<=maxStreamerIdx; i++) {
+      if (streamerList[i]) {
+         validIdx = i;
+         break;
+      }
+   }
+   
+   if (i > maxStreamerIdx) {
+      validIdx = -1;
+   }   
+      
+   return validIdx;      
+}
+
+int appInstance::parseMessage(sageMessage &msg, int fsIdx)
+{
+   char *msgData = (char *)msg.getData();
+   
+   switch (msg.getCode()) {
+      case SAIL_INIT_MSG : {
+         if (initialized) {
+            int winID;
+            sageNwConfig nwCfg;
+            sscanf(msgData, "%d %d %d %d", &winID, &nwCfg.rcvBufSize, &nwCfg.sendBufSize,
+                  &nwCfg.mtuSize);      
+
+            streamerList[fsIdx]->setWinID(winID);
+	    if (shared->protocol == SAGE_TCP)
+               streamerList[fsIdx]->setNwConfig(nwCfg);
+         }   
+         break;
+      }
+      
+      case SAIL_CONNECT_TO_RCV : {
+         //sage::printLog("connect to rcv");
+         if (initialized)
+            streamerList[fsIdx]->initNetworks(msgData);
+         break;
+      }   
+      
+      case SAIL_CONNECT_TO_RCV_PORT : {
+         //sage::printLog("connect to rcv");
+         if (initialized)
+            streamerList[fsIdx]->initNetworks(msgData, true);
+         break;
+      }
+      
+      case SAIL_INIT_STREAM : {
+         sage::printLog("init stream endpoint %d", fsIdx);
+         if (initialized)
+            streamerList[fsIdx]->storeStreamConfig(msgData);
+         break;
+      }
+   
+      case APP_QUIT : {
+         if (initialized) {
+            streamerList[fsIdx]->shutdown();
+            delete streamerList[fsIdx];
+            streamerList[fsIdx] = NULL;
+         }
+         
+         if (shared->nodeID == 0) {   
+            fsList[fsIdx] = -1;
+            std::cout << "clear fs idx" << std::endl;
+         }   
+         break;
+      }
+      
+      case NOTIFY_APP_SHUTDOWN : {
+         //std::cout << "shutdown all streams" << std::endl;
+         shutdownAllStreams();
+         break;
+      }
+      
+      case SAIL_FRAME_RATE : {
+         if (initialized) {
+            //float frate = atof(msgData);
+            //if (nodeNum > 1 && shared->nodeID == 0)
+            //   streamerList[fsIdx]->getSyncGroup()->setFrameRate(frate);
+            //else   
+            //   streamerList[fsIdx]->setFrameRate(frate);
+         }      
+         break;   
+      }
+      
+      case SAIL_PERF_INFO_REQ : {
+         startPerformanceReport(msg);
+         break;
+      }
+      
+      case SAIL_PERF_INFO_STOP :   {
+         reportRate = 0;
+         break;
+      }
+   }
+   
+   return 0;
+}
+
+void appInstance::fillAppInfo(char *msgStr)
+{
+   sprintf(msgStr, "%s %d %d %d %d 0 . %d %d %d %d %d", appName, x, y, width, height, imageWidth,
+         imageHeight, (int)audioOn, (int)sConfig.protocol, sConfig.frameRate);
+}
+
+bool appInstance::isActive()
+{
+   bool active = false;
+   for (int j=0; j<fsList.size(); j++) {
+      if (initialized && streamerList[j])
+         active = true;
+      else if (shared->nodeID == 0 && fsList[j] >= 0)
+         active = true;
+   }
+   
+   return active;      
+}
+
+int appInstance::shutdownAllStreams()
+{
+   for (int i=0; i<=maxStreamerIdx; i++) {
+      if (shared->nodeID == 0 && fsList[i] >= 0)
+         shared->eventQueue->appendEvent(EVENT_APP_SHUTDOWN, fsList[i]);
+         
+      if (streamerList[i]) {
+         streamerList[i]->shutdown();
+         delete streamerList[i];
+         streamerList[i] = NULL;
+      }
+   }   
+   
+   return 0;
+}
Index: trunk/src/testing/src/sageDoubleBuf.cpp
===================================================================
--- trunk/src/testing/src/sageDoubleBuf.cpp	(revision 4)
+++ trunk/src/testing/src/sageDoubleBuf.cpp	(revision 4)
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageDoubleBuf.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageDoubleBuf.h"
+#include "sageBlock.h"
+
+int sageDoubleBuf::init(sagePixelData **bufs)
+{
+   bufID = 0;
+   blockBuf = bufs;
+
+   bufLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(bufLock, NULL);
+   pthread_mutex_unlock(bufLock);
+   notFull = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notFull, NULL);
+   notEmpty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notEmpty, NULL);
+
+   return 0;
+}//End of sageDoubleBuf()
+
+sagePixelData* sageDoubleBuf::getBuffer(int id)
+{ 
+   if (id < 0 || id > 1) {
+      sage::printLog("sageDoubleBuf::getBuffer : invalid buffer access");
+      return NULL;
+   }
+      
+   return blockBuf[id]; 
+}
+
+sagePixelData *sageDoubleBuf::getFrontBuffer()
+{ 
+   return blockBuf[bufID]; 
+}  
+
+sagePixelData* sageDoubleBuf::getBackBuffer()
+{
+   pthread_mutex_lock(bufLock);
+
+   while(queueLen == 0) {
+      //std::cerr << "=== waiting for new frames === " << std::endl;
+      pthread_cond_wait(notEmpty, bufLock);
+   }
+
+   return blockBuf[1-bufID];
+}
+
+int sageDoubleBuf::bufSize()
+{
+   if (blockBuf)
+      return (blockBuf[0]->getBufSize() * 2);
+   
+   sage::printLog("sageDoubleBuf::bufSize : buffers are not initialized");
+   return -1;
+}
+
+int sageDoubleBuf::releaseBackBuffer()
+{
+   queueLen--;   
+   pthread_mutex_unlock(bufLock);   
+
+   if (queueLen == 0) {
+      pthread_cond_signal(notFull);
+   }   
+   
+   return 0;
+}
+
+int sageDoubleBuf::swapBuffer()
+{
+   pthread_mutex_lock(bufLock);
+   
+   while(queueLen > 0) {
+      pthread_cond_wait(notFull, bufLock);
+   }
+
+   if (queueLen == 0) {
+      bufID = 1 - bufID;
+      queueLen++;
+   }
+   
+   pthread_mutex_unlock(bufLock);
+   pthread_cond_signal(notEmpty);
+
+   firstFrameReady = true; 
+   return 0;
+}
+
+int sageDoubleBuf::resendBuffer(int num)
+{
+   pthread_mutex_lock(bufLock);
+   queueLen += num;
+   pthread_mutex_unlock(bufLock);
+   pthread_cond_signal(notEmpty);
+      
+   return 0;
+}
+
+void sageDoubleBuf::releaseLocks()
+{
+   pthread_mutex_lock(bufLock);
+   queueLen = -1;
+   pthread_cond_signal(notEmpty);
+   pthread_cond_signal(notFull);
+   pthread_mutex_unlock(bufLock);
+}
+
+sageDoubleBuf::~sageDoubleBuf()
+{
+   if (bufLock)
+      free(bufLock);
+   
+   if (notFull)   
+      free(notFull);
+      
+   if (notEmpty)
+      free(notEmpty);
+      
+   if (blockBuf) {   
+      if (blockBuf[0])
+         delete blockBuf[0];
+
+      if (blockBuf[1])
+         delete blockBuf[1];
+      
+      delete [] blockBuf;
+   }   
+}//End of ~sageDoubleBuf()
Index: trunk/src/testing/src/sageSync.cpp
===================================================================
--- trunk/src/testing/src/sageSync.cpp	(revision 4)
+++ trunk/src/testing/src/sageSync.cpp	(revision 4)
@@ -0,0 +1,2176 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageSync.cpp - This file contains the class which provides the syncing
+ *            mechanism for keeping all the sage processes in sync.
+ * Author : Byungil Jeong, Rajvikram Singh
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageSync.h"
+#include "sageBuf.h"
+
+#if defined(WIN32)
+#define MSG_WAITALL  0x8
+#endif
+
+int syncGroup::init(int startFrame, int p, int groupID, int frameRate, int sNum)
+{
+   slaveNum = sNum;
+   curFrame = startFrame;
+
+   policy = p;
+   id = groupID;
+   setFrameRate((float)frameRate);
+
+   syncMsgLock = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(syncMsgLock, NULL);
+   pthread_mutex_unlock(syncMsgLock);
+
+   pthread_mutex_init(&syncLock, NULL);
+   pthread_mutex_unlock(&syncLock);
+   pthread_cond_init(&resumeSync, NULL);
+
+   timer.reset();
+
+   return 0;
+}
+
+int syncGroup::setFrameRate(float frameRate)
+{
+   if (frameRate > 0)
+      interval = 1000000.0/frameRate; // in micro second
+   else {
+      sage::printLog("syncGroup::setFrameRate : can't set frame rate to zero");
+      interval = 16666.6;
+   }
+
+   return 0;
+}
+
+bool syncGroup::checkInterval()
+{
+   double curTime = timer.getTimeUS();
+   double maxErr = interval*MAX_INTERVAL_ERROR;
+   double err = curTime - (interval - timeError);
+   if (err > -maxErr) {
+      if (timeError > maxErr)
+         timeError = 0.0;
+      else
+         timeError = err;
+      timer.reset();
+      waitingInterval = false;
+      return true;
+   }
+
+   waitingInterval = true;
+   return false;
+}
+
+int syncGroup::processUpdate(char *data)
+{
+   //std::cerr << "process update " << data << std::endl;
+
+   int groupID, frameNum, updateParam, updateType;
+   sscanf(data, "%d %d %d %d", &groupID, &frameNum, &updateParam, &updateType);
+
+   //fprintf(stderr, "syncGroup::processUpdate : for group %d, frameNum %d, updateParam %d, updateType %d \n", groupID, frameNum, updateParam, updateType);
+
+   float hardness = 1.0;
+   if (policy == SAGE_ASAP_SYNC_HARD)
+      hardness = 1.0;
+   else if (policy == SAGE_ASAP_SYNC_SOFT)
+      hardness = 0.5;
+
+   switch(updateType) {
+      // used in SAGE Bridge only (no audio sync)
+      case SAGE_UPDATE_FRAME: {
+         noOfUpdates++;
+         skipFrame = MAX(skipFrame, frameNum);
+
+         if (noOfUpdates >= slaveNum*hardness) {
+            curFrame = MAX(curFrame, skipFrame);
+            noOfUpdates = 0;
+            return NORMAL_SYNC;
+         }
+
+         break;
+      }
+
+      case SAGE_UPDATE_SETUP: {
+         //sage::printLog("newFrame %d  curFrame %d\n", frameNum, curFrame);
+    	  //sungwon
+    	  //fprintf(stderr, "syncGroup::processUpdate(SAGE_UPDATE_SETUP) : newFrame %d, curFrame %d, rcvNum %d, noOfUpdates %d\n", frameNum, curFrame, updateParam, noOfUpdates);
+
+         if (frameNum > curFrame) {
+            videoFrame = frameNum;
+            slaveNum = updateParam; // the number of receivers
+            noOfUpdates++;
+
+            if (noOfUpdates >= slaveNum*hardness) {
+               if (audioFrame > 0 && frameNum >= keyFrame*audioSyncCnt && audioFrame < keyFrame*audioSyncCnt) {
+                  waitForKeyFrame = true;
+                  return 0;
+               }
+               else {
+                  curFrame = frameNum; // update frame
+                  noOfUpdates = 0; // reset counter
+                  return NORMAL_SYNC; // will result calling sendSync() -> sending group's currentFrame
+               }
+            }
+         }
+         break;
+      }
+
+      case SAGE_UPDATE_FOLLOW: { // no window change
+         if (frameNum > curFrame) {
+            videoFrame = frameNum;
+            noOfUpdates++;
+
+            if (noOfUpdates >= slaveNum*hardness) {
+               if (audioFrame > 0 && frameNum >= keyFrame*audioSyncCnt && audioFrame < keyFrame*audioSyncCnt) {
+                  waitForKeyFrame = true; // video waits audio
+                  return 0; // sendSync() is not called
+               }
+               else {
+                  curFrame = MAX(skipFrame, frameNum); // update group's current frame number
+                  noOfUpdates = 0; // reset counter
+                  return NORMAL_SYNC; // call sendSync()
+               }
+            }
+         }
+
+         break;
+      }
+
+      case SAGE_UPDATE_AUDIO: {
+		    //sungwon
+   		//fprintf(stderr, "syncGroup::processUpdate(SAGE_UPDATE_AUDIO) : for group %d, frameNum %d, updateParam %d, updateType %d \n", groupID, frameNum, updateParam, updateType);
+
+
+         audioFrame = frameNum;
+         keyFrame = updateParam;
+         audioSyncCnt++;
+         //std::cerr << "syncGroup::processUpdate : audio " << audioFrame << " video " << videoFrame << "noOfUpdate " << noOfUpdates << "slaveNum " << slaveNum << "curFrame " << curFrame << "videoFrame " << videoFrame << std::endl;
+
+         if (waitForKeyFrame) {
+            waitForKeyFrame = false;
+            if (policy == SAGE_ASAP_SYNC_HARD) {
+               if (noOfUpdates == slaveNum) {
+                  curFrame = videoFrame;
+                  noOfUpdates = 0;
+                  return NORMAL_SYNC;
+               }
+            }
+            else if (policy == SAGE_ASAP_SYNC_SOFT) {
+               if (noOfUpdates >= slaveNum*0.5) {
+                  curFrame = videoFrame;
+                  noOfUpdates = 0;
+                  return NORMAL_SYNC;
+               }
+            }
+         }
+      }
+   }
+
+   return 0;
+}
+
+/*
+bool syncGroup::checkTimeOut()
+{
+   if (noOfUpdates > 0 && timer.getTimeSec() > 1.0) {
+      curFrame++;
+      noOfUpdates = 0;
+      timer.reset();
+      sage::printLog("sync group %d : time out", id);
+      return true;
+   }
+
+   return false;
+}
+*/
+
+void syncGroup::checkHold()
+{
+   pthread_mutex_lock(&syncLock);
+   while(holdSync)
+      pthread_cond_wait(&resumeSync, &syncLock);
+   pthread_mutex_unlock(&syncLock);
+}
+
+void syncGroup::blockSync()
+{
+   pthread_mutex_lock(&syncLock);
+   holdSync = true;
+   pthread_mutex_unlock(&syncLock);
+}
+
+void syncGroup::unblockSync()
+{
+   pthread_mutex_lock(&syncLock);
+   holdSync = false;
+   pthread_mutex_unlock(&syncLock);
+   pthread_cond_signal(&resumeSync);
+}
+
+int syncGroup::enqueSyncMsg(char *msg)
+{
+   char *syncMsg = new char[strlen(msg)+1];
+   strcpy(syncMsg, msg);
+
+   pthread_mutex_lock(syncMsgLock);
+   syncMsgQueue.push_back(syncMsg);
+   pthread_mutex_unlock(syncMsgLock);
+
+   return 0;
+}
+
+char* syncGroup::dequeSyncMsg()
+{
+   char *msg = NULL;
+   pthread_mutex_lock(syncMsgLock);
+   if (syncMsgQueue.size() > 0) {
+      msg = syncMsgQueue.front();
+      syncMsgQueue.pop_front();
+   }
+   pthread_mutex_unlock(syncMsgLock);
+
+   return msg;
+}
+
+
+
+
+//--------------------------------------------  S E R V E R   C O D E  ---------------------------------------------//
+sageSyncBBServer::sageSyncBBServer(int sl) : maxSyncGroupID(-1), syncEnd(false), maxSlaveSockFd(0), maxBarrierSlaveSockFd(0)
+{
+   //for (int i=0; i<MAX_SYNC_GROUP; i++) {
+     // syncGroupArray[i] = NULL;
+   //}
+
+   FD_ZERO(&slaveFds);
+   FD_ZERO(&barrierSlaveFds);
+
+   syncLevel = sl;
+
+   barrierPort = 0;
+   syncSlavesMap.clear();
+}
+
+int sageSyncBBServer::init(int port)
+{
+   int optVal, optLen;
+
+   // create the server socket
+   if((serverSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+      sage::printLog("sageSyncBBServer::init(): Creating server socket failed");
+      return -1;
+   }
+
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::init(): Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::init(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::init(): Error switching on OOBINLINE.");
+
+#else
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, (void*)&optVal, (socklen_t)optLen) !=0)
+      perror("sageSyncBBServer::init():: Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::init(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::init(): Error switching on OOBINLINE.");
+
+#endif
+
+   memset(&serverAddr, 0, sizeof(serverAddr));
+   serverAddr.sin_family = AF_INET;
+   serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   serverAddr.sin_port = htons(port);
+
+   if (bind(serverSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in)) != 0) {
+      sage::printLog("sageSyncBBServer::init():: Error binding server socket");
+      return -1;
+   }
+
+   // put in listen mode
+   listen(serverSockFd, 10);
+
+   // create the syncServerThread
+   if (pthread_create(&syncServerThreadID, NULL, syncServerThread, (void*) this) !=0) {
+      sage::printLog("sageSyncBBServer::init(): Creating syncServerThread failed");
+      return -1;
+   }
+
+   //timer.reset();
+
+   return 0;
+}
+
+int sageSyncBBServer::initBarrier(int barrierPort)
+{
+   int optVal, optLen;
+
+   // create the server socket
+   if((barrierServerSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+      sage::printLog("sageSyncBBServer::initBarrier(): Creating server socket failed");
+      return -1;
+   }
+
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+   if(setsockopt(barrierServerSockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::initBarrier(): Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(barrierServerSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::initBarrier(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(barrierServerSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::initBarrier(): Error switching on OOBINLINE.");
+
+#else
+   if(setsockopt(barrierServerSockFd, SOL_SOCKET, SO_REUSEADDR, (void*)&optVal, (socklen_t)optLen) !=0)
+      perror("sageSyncBBServer::initBarrier():: Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(barrierServerSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::initBarrier(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(barrierServerSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncBBServer::initBarrier(): Error switching on OOBINLINE.");
+#endif
+
+   memset(&barrierServerAddr, 0, sizeof(barrierServerAddr));
+   barrierServerAddr.sin_family = AF_INET;
+   barrierServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   barrierServerAddr.sin_port = htons(barrierPort);
+
+   if (bind(barrierServerSockFd, (struct sockaddr *)&barrierServerAddr, sizeof(struct sockaddr_in)) != 0) {
+      sage::printLog("sageSyncBBServer::initBarrier():: Error binding server socket");
+      return -1;
+   }
+
+   // put in listen mode
+   listen(barrierServerSockFd, 10);
+
+   // create the syncBarrierServerThread
+   if (pthread_create(&syncBarrierServerThreadID, NULL, syncBarrierServerThread, (void*) this) !=0) {
+      sage::printLog("sageSyncBBServer::initBarrier(): Creating syncBarrierServerThread failed");
+      return -1;
+   }
+
+   return 0;
+}
+
+// The sync server thread, which is responsible for listening for new sync clients
+// This thread also polls each connected slave to look for frame updates
+// and then updates the slave data vector
+
+void* sageSyncBBServer :: syncServerThread(void *args)
+{
+   sageSyncBBServer *This;
+   This = (sageSyncBBServer *)args;
+
+   int tempSockFd;
+   int tempBarrierSockFd;
+   int addrLen;
+   int optVal,optLen;
+
+   sockaddr_in clientAddr;
+
+   while (!This->syncEnd)   {
+      // accept connections
+      addrLen = sizeof(clientAddr);
+
+      if ((tempSockFd = accept(This->serverSockFd, (struct sockaddr *)&clientAddr,(socklen_t*)&addrLen)) == -1) {
+         sage::printLog("sageSyncBBServer::syncServerThread()::Quitting sync server thread.");
+         pthread_exit(NULL);
+         continue;
+      }
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncBBServer: Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncBBServer: Error switching on OOBINLINE.");
+
+#else
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+         sage::printLog("\nsageSyncBBServer: Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncBBServer: Error switching on OOBINLINE.");
+
+#endif
+
+      // add the client's info to the list
+      syncSlaveData newClient;
+      newClient.clientSockFd = tempSockFd;
+      memcpy((void *)&(newClient.clientAddr), (void *)&clientAddr, sizeof(clientAddr));
+      This->maxSlaveSockFd = MAX(This->maxSlaveSockFd, tempSockFd);
+      FD_SET(tempSockFd, &This->slaveFds);
+
+      //This->syncSlaves[ This->syncSlaves.size() - 1 ];
+      // syncSlave sends its SDM number
+      sage::recv(tempSockFd, (void*)&newClient.SDM, sizeof(int), MSG_WAITALL);
+
+      //This->syncSlaves.push_back(newClient); // copy occurs here
+      This->syncSlavesMap[newClient.SDM] = newClient; // copy occurs
+
+      sage::printLog("\nsageSyncBBServer::syncServerThread() : SDM %d (socket %d) has connected. MaxFD is %d", newClient.SDM, This->syncSlavesMap[newClient.SDM].clientSockFd, This->maxSlaveSockFd);
+
+   } // end of while(!This->syncEnd)
+   //pacify compiler
+   return NULL;
+} // end of sageSyncBBServer :: syncServerThread()
+
+void* sageSyncBBServer::syncBarrierServerThread(void *args)
+{
+	sage::printLog("sageSyncBBServer::syncBarrierServerThread() : started.");
+
+   sageSyncBBServer *This = (sageSyncBBServer *)args;
+
+   int tempBarrierSockFd;
+   int addrLen;
+   int optVal,optLen;
+
+   sockaddr_in clientAddr;
+   int sdm = 0;
+
+   while (!This->syncEnd)   {
+      // accept connections
+      addrLen = sizeof(clientAddr);
+
+      if ((tempBarrierSockFd = accept(This->barrierServerSockFd, (struct sockaddr *)&clientAddr,(socklen_t*)&addrLen)) == -1) {
+         sage::printLog("sageSyncBBServer::syncBarrierServerThread()::Quitting sync server thread.");
+         pthread_exit(NULL);
+      }
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempBarrierSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempBarrierSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : Error switching on OOBINLINE.");
+
+#else
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempBarrierSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+         sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempBarrierSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+    	  sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : Error switching on OOBINLINE.");
+
+#endif
+
+      sage::recv(tempBarrierSockFd, (void*)&sdm, sizeof(int), MSG_WAITALL);
+
+      ((This->syncSlavesMap)[sdm]).barrierClientSockFd = tempBarrierSockFd;
+
+      This->maxBarrierSlaveSockFd = MAX(This->maxBarrierSlaveSockFd, tempBarrierSockFd);
+
+      FD_SET(tempBarrierSockFd, &This->barrierSlaveFds);
+
+      sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : SDM %d (socket %d) has connected. MaxFD is %d", sdm, This->syncSlavesMap[sdm].barrierClientSockFd, This->maxBarrierSlaveSockFd);
+
+
+      /*
+      std::map<int, syncSlaveData*>::iterator it;
+      it = This->syncSlavesMap.find( sdm );
+
+      if ( it != This->syncSlavesMap.end() ) {
+    	  if ( (it->second)->SDM == sdm ) {
+    		  (it->second)->barrierClientSockFd = tempBarrierSockFd;
+    		  This->maxBarrierSlaveSockFd = MAX(This->maxBarrierSlaveSockFd, tempBarrierSockFd);
+    		  FD_SET(tempBarrierSockFd, &This->barrierSlaveFds);
+
+    		  sage::printLog("sageSyncBBServer::syncBarrierServerThread() : syncSlave %d has registered to barrier with socket(%d), Max is %d\n", it->second->SDM, it->second->barrierClientSockFd, This->maxBarrierSlaveSockFd);
+    	  }
+    	  else {
+    		  sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : nodeID in the map is different from that of syncSlaveData\n");
+    	  }
+      }
+	  else {
+		  sage::printLog("\nsageSyncBBServer::syncBarrierServerThread() : map iterator hit the end with SDM %d\n", sdm);
+	  }
+	  */
+   } // end of while(!This->syncEnd)
+   //pacify compiler
+   return NULL;
+} // end of sageSyncBBServer :: syncBarrierServerThread()
+
+int sageSyncBBServer::startManagerThread(int totalRcvNum, int refreshInterval, int syncMasterPollingInterval) {
+	this->totalRcvNum = totalRcvNum;
+	this->refreshInterval = refreshInterval;
+	this->syncMasterPollingInterval = syncMasterPollingInterval;
+
+	while(1) {
+		sage::sleep(1);
+		if ( totalRcvNum == syncSlavesMap.size() ) {
+			fprintf(stderr, "sageSyncBBServer::startManagerThread() : All %d sync clients have connected.\n", syncSlavesMap.size());
+			fflush(stderr);
+			sage::sleep(1);
+			break;
+		}
+	}
+
+
+	if (pthread_create(&syncThreadID, NULL, mainLoopThread, (void*) this) !=0) {
+		sage::printLog("sageSyncBBServer::startManagerThread(): Creating mainLoopThread failed");
+		return -1;
+	}
+}
+
+void* sageSyncBBServer::mainLoopThread(void *args)
+{
+	sageSyncBBServer *This = (sageSyncBBServer *)args;
+
+	/**
+	 * speed of syncMaster
+	 */
+	double interval = 1.0 / (double)(This->refreshInterval); // second
+
+	/**
+	 * polling interval
+	 */
+	struct timeval selTimer;
+	selTimer.tv_sec = 0;
+	selTimer.tv_usec = This->syncMasterPollingInterval;
+	//selTimer.tv_usec = 1000; // 1msec
+
+	sage::printLog("\n\nsageSyncBBServer::mainLoopThread() has started !! TotalRcvNum %d, refreshInterval %d Hz(%.6f sec), select polling interval %ld usec\n", This->totalRcvNum, This->refreshInterval, interval, selTimer.tv_usec);
+	if ( This->syncLevel == 1 ) {
+		sage::printLog("Data Sync Only\n");
+	}
+	else if ( This->syncLevel == 2 ) {
+		sage::printLog("Two-Phase : SwapBuffer Barrier\n");
+	}
+	else if ( This->syncLevel == 3 ) {
+		sage::printLog("One-Phase : SYNC with NTP\n");
+	}
+
+#ifdef PROFILING_SYNCMASTER
+	FILE *profile = NULL;
+	char fname[10];
+	sprintf(fname, "/home/evl/snam5/synchProfile/syncMaster_%d", This->totalRcvNum);
+	profile = fopen(fname, "w+");
+	struct timeval pTimer;
+	unsigned long loopCounter = 0;
+#endif
+
+	/**
+	 * for selective barrier
+	 */
+	/*
+	bool activeNodes[This->totalRcvNum];
+	for ( int i=0; i<This->totalRcvNum; i++ ) {
+		activeNodes[i] = false;
+	}
+	*/
+
+	//bool SDMlistBoolset[MAX_INST_NUM][This->totalRcvNum]; // faster
+
+	//std::vector<int> listOfApps[This->totalRcvNum];
+
+	/**
+	 * number of current total SDM invovled in the application indexed by array index, array index is APP id(PDL id)
+	 */
+	//int slaveNumArray[MAX_INST_NUM];
+
+
+
+	/**
+	 * list of SDM involved in the application indexed by array index,
+	 * array index is APP id(PDL id)
+	 * SDMlistBitset[0].set(3) means SDM 3 has PDL 0
+	 */
+	//std::bitset<50> SDMlistBitset[MAX_INST_NUM]; // space efficient
+
+	std::map<int, std::bitset<100> > SDMlistBitsetMap;
+	SDMlistBitsetMap.clear();
+
+	/**
+	 * The syncFrame of each App(PDL)
+	 */
+	//int syncFrameArray[MAX_INST_NUM];
+	std::map<int, int> syncFrameMap; // appID, frameNumber
+	syncFrameMap.clear();
+
+	// max frame number for each APP to determine who's leading or lagging
+	//int maxFrameNum[MAX_INST_NUM];
+
+	/**
+	 * Is this application ready ?
+	 * Or  slaveNum(activeRcvs) == SDMlistBitset[App].count() then it's ready
+	 */
+	//bool isReadyToSwapMon[MAX_INST_NUM];
+	std::map<int,bool> isReadyToSwapMonMap; // appID, value
+	isReadyToSwapMonMap.clear();
+
+	/**
+	 * init data structure
+	 */
+	/*
+	for ( int i=0; i<MAX_INST_NUM; i++ ) {
+		//slaveNumArray[i] = 0;
+		syncFrameArray[i] = 0;
+		isReadyToSwapMon[i] = false;
+		SDMlistBitset[i].reset();
+	}
+	*/
+
+	/**
+	 * message container for receiving PDL's update
+	 */
+	char msg[SAGE_SYNC_MSG_LEN]; // this is still needed to receive sync message from clients
+	//std::map<int,int> msgMap; // appID, syncFrame
+	//msgMap.clear();
+
+	/**
+	 * message container for broadcasting to nodes
+	 * it tells which app is ready for which frame
+	 * intMsg[4] == 1 then PDL 4 is ready AND intMsg[5] = syncFrame
+	 * In 64bit machine, MAX_INST_NUM should be less than or equal to 80 if SAGE_SYNC_MSG_LEN is 1280 Byte
+	 */
+#ifdef DELAY_COMPENSATION
+	long long intMsg[ SAGE_SYNC_MSG_LEN / sizeof(long long) ]; // 1280 / 8 = 160
+#else
+	//int intMsg[ SAGE_SYNC_MSG_LEN / sizeof(int) ]; // 1280 / 4 = 320 or 1280 / 8 = 160
+	//int intMsg[ 8000 / sizeof(int) ];
+#endif
+
+	int sdm,pdl,slaveNum,updatedFrame;
+
+	/**
+	 * Delay compensation thing
+	 */
+	int nodeLatency; // delay compensation. in usec
+	int maxNodeLatency = 0;
+
+	int barrierCount = 0;
+	int selectRetval;
+	int netStatus;
+	bool swapMontageReady = false;
+
+	struct timeval tvs,tve;
+	double elapsed = 0.0;
+
+	int numUpdatedApps = 0; // how many apps are updated in this round
+	int *intMsg = NULL;
+	int intMsg_byteLen = 0;
+
+	while(!This->syncEnd) {
+		while(1) {
+			gettimeofday(&tvs, NULL);
+
+			fd_set rfds = This->slaveFds;
+			selectRetval = select( This->maxSlaveSockFd+1, &rfds, NULL, NULL, &selTimer ); // polling
+			if ( selectRetval < 0 ) {
+				sage::printLog("sageSyncBBServer::managerThread() : select error\n");
+				continue;
+			}
+
+			// for all node
+			if ( selectRetval > 0 ) {
+				for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+					if ( FD_ISSET( This->syncSlavesMap[i].clientSockFd, &rfds ) ) {
+
+						//status = recv(array[i], (void*)dataArray, 4*sizeof(int), MSG_WAITALL);
+						netStatus = sage::recv(This->syncSlavesMap[i].clientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN);
+						if ( netStatus == 0 ) {
+							// close the socket and mark it as dead
+#ifdef WIN32
+							closesocket(This->syncSlaves[i].clientSockFd);
+#else
+							shutdown(This->syncSlavesMap[i].clientSockFd, SHUT_RDWR);
+							close(This->syncSlavesMap[i].clientSockFd);
+#endif
+							FD_CLR(This->syncSlavesMap[i].clientSockFd, &(This->slaveFds));
+							This->syncSlavesMap[i].clientSockFd = -1;
+						}
+						else {
+							//id, frame, rcvNum, type, SDMnum
+							// receive message from a node
+							sscanf(msg, "%d %d %d %d %d", &pdl, &updatedFrame, &slaveNum, &sdm, &nodeLatency);
+
+#ifdef DELAY_COMPENSATION
+							maxNodeLatency = MAX(maxNodeLatency, nodeLatency);
+#endif
+
+							//printf("\t SDM %d PDL %d : upFrm %d, actRcvs %d\n", sdm, pdl, updatedFrame, slaveNum);
+#ifdef DEBUG_SYNC
+							fprintf(stderr, "\trecved update : [%d,%d] updF %d, activeRcv %d\n", sdm, pdl, updatedFrame, slaveNum);
+#endif
+
+							// add this node to the activeNode per application
+							// update reported node list for this application(pdl id)
+							//SDMlistBitset[pdl].set(sdm, 1);
+
+							// bitset will be initialized with zeros
+							(SDMlistBitsetMap[pdl]).set(sdm, 1);
+
+							// update frame number of each PDL of each SDM
+							//frameNumOfEachSDM[pdl][sdm] = updatedFrame;
+
+							// find number of SDM involved in this application
+							// update number of active node for this application(pdl id)
+							//slaveNumArray[pdl] = slaveNum;
+
+							// this should be same for all nodes of this application
+							//syncFrameArray[pdl] = updatedFrame;
+							syncFrameMap[pdl] = updatedFrame;
+
+							//frameNumOfEachSDM[pdl][sdm] = updatedFrame;
+
+							// list of apps that this node has
+							//listOfApps[sdm].push_back(pdl);
+
+							// if all nodes of this application reported
+							//if ( slaveNumArray[pdl] <= SDMlistBitset[pdl].count() ) {
+							if ( slaveNum == (SDMlistBitsetMap[pdl]).count() ) {
+								swapMontageReady = true;
+								numUpdatedApps++;
+
+
+#ifdef DEBUG_SYNC
+								fprintf(stderr, "\tIt's ready : App %d is ready. SF %d\n", pdl, syncFrameMap[pdl]);
+#endif
+
+								// then they can do swapMontage
+								//isReadyToSwapMon[pdl] = true;
+								isReadyToSwapMonMap[pdl] = true;
+
+								// reset data structure for next round
+								// comment this out for SELECTIVE barrier
+								(SDMlistBitsetMap[pdl]).reset(); // must be here for BROADCAST barrier, comment out for selective barrier
+
+								// lots of contention will be happening
+								//if ( This->syncLevel == 1 ) break;
+							}
+							else if ( slaveNum < (SDMlistBitsetMap[pdl]).count() ) {
+								fprintf(stderr,"\n\t ActRcv %d > SDMlist %d\n", slaveNum, (SDMlistBitsetMap[pdl]).count() );
+							}
+						} // if ( netStatus > 0) // sage::recv() returned with data
+						//break; // exit for loop -> time check after every message receive
+					} // if (FD_ISSET)
+				} // foreach node
+			} // if (selectRetval > 0)
+
+			// still contention
+			//if ( This->syncLevel == 1 && swapMontageReady ) break;
+
+			gettimeofday(&tve, NULL);
+			elapsed += ((double)tve.tv_sec + 0.000001*(double)tve.tv_usec)-((double)tvs.tv_sec + 0.000001*(double)tvs.tv_usec);
+			//printf("%.6f\n", elapsed);
+			if ( elapsed >= interval ) {
+				// 0.0083 sec =  8.3 msec = 120Hz
+				// 0.0167 sec = 16.7 msec =  60Hz
+				//printf("%.6f msec \n", elapsed*1000.0);
+
+				elapsed = 0.0;
+				break; // break while(1) loop
+			}
+		} // end while(1)
+
+		//printf("\nTIMEOUT\n");
+
+		// for each application
+		// it memset with zeros, then SDM::processSync will read wrong value
+		// if it's unsigned type, then it will become UINT_MAX, ULONG_MAX, or ULLONG_MAX
+		intMsg_byteLen = sizeof(int) + (sizeof(int) * numUpdatedApps * 2); // sizeof(int) byte is for MSG_PEEK at the SDM
+		intMsg = (int *)malloc(intMsg_byteLen);
+		memset(intMsg, -1, intMsg_byteLen);
+		intMsg[0] = intMsg_byteLen;
+
+		if ( swapMontageReady ) {
+			// then we need to prepare message for them
+			swapMontageReady = false; // reset
+
+			// for each App
+			int intMsgIndex = 0; // the first index is byte length.
+			for ( std::map<int,bool>::iterator it=isReadyToSwapMonMap.begin(); it!=isReadyToSwapMonMap.end(); it++ ) {
+				int appID = (*it).first;
+				// if it's ready ( all node that have this app reported )
+
+				if ( (*it).second ) {
+					isReadyToSwapMonMap[ appID ] = false; // reset
+
+					intMsg[2*intMsgIndex + 1] = appID;
+					intMsg[2*intMsgIndex + 2] = syncFrameMap[appID];
+					intMsgIndex++;
+				}
+				if ( intMsgIndex >= numUpdatedApps ) {
+					break;
+				}
+			}
+		}
+
+#ifdef DEBUG_SYNC
+		fprintf(stderr, "\tUpdatedApps : ");
+		for ( int i=0; i<numUpdatedApps; i++ ) {
+			fprintf(stderr, "(%d,%d) ", intMsg[2*i], intMsg[2*i+1]);
+		}
+		fprintf(stderr, "\n");
+#endif
+		numUpdatedApps = 0; // reset
+
+		/** temporary delat_compensation for 1st phase only */
+		if ( This->syncLevel == 3 ) {
+			//int intMsg[ SAGE_SYNC_MSG_LEN / sizeof(int) ];
+			//int index = SAGE_SYNC_MSG_LEN / sizeof(int); // 320 when 4byte int
+			int index = SAGE_SYNC_MSG_LEN / sizeof(long long); // 160
+
+			struct timeval initT;
+			gettimeofday(&initT, NULL);
+			//sprintf(msg, "%d %d %d", initT.tv_sec, initT.tv_usec, maxDeltaT);
+
+			//intMsg[index-1] = maxNodeLatency; // in usec
+			intMsg[index-1] = 7000; // Presentation Time Offset in usec
+			intMsg[index-2] = initT.tv_sec;
+			intMsg[index-3] = initT.tv_usec;
+			maxNodeLatency = 0;
+		}
+		/** temporary delat_compensation for 1st phase only */
+
+		// Broadcast -> will trigger EVENT_SYNC_MESSAGE on all node
+#ifdef PROFILING_SYNCMASTER
+		// node%d:pdl%d:frame%d:ITEM:%d:%d
+		gettimeofday(&pTimer, NULL);
+		fprintf(profile, "%d:%d:%lu:Broadcast_B:%ld:%ld\n", -1,-1,loopCounter,pTimer.tv_sec, pTimer.tv_usec);
+#endif
+		for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+			if ( sage::send(This->syncSlavesMap[i].clientSockFd, (void*)intMsg, intMsg_byteLen) < intMsg_byteLen ) {
+				sage::printLog("sageSyncBBServer::mainLoopThread() : send() error at the 1st phase\n");
+			}
+		}
+#ifdef PROFILING_SYNCMASTER
+		// node%d:pdl%d:frame%d:ITEM:%d:%d
+		gettimeofday(&pTimer, NULL);
+		fprintf(profile, "%d:%d:%lu:Broadcast_E:%ld:%ld\n", -1,-1,loopCounter,pTimer.tv_sec, pTimer.tv_usec);
+#endif
+		if (intMsg) {
+			free(intMsg);
+			intMsg = NULL;
+		}
+
+		/**
+		 * Barrier Before SwapBuffer
+		 */
+		 //printf("\nBARRIER\n");
+
+		/* SELECTIVE BARRIER */
+		/**
+		int activeNodeSize = 0;
+		for ( int i=0; i<MAX_INST_NUM; i++ ) {
+			if ( isReadyToSwapMon[i] ) {
+				isReadyToSwapMon[i] = false;
+				for ( int j=0; j<SDMlistBitset[i].size(); j++ ) {
+					if ( SDMlistBitset[i].test(j) ) {
+						activeNodes[j] = true;
+						activeNodeSize++;
+					}
+				}
+				SDMlistBitset[i].reset(); // bitset is being reset here !!
+			}
+		}
+		while ( barrierCount < activeNodeSize ) {
+			fd_set rfds2 = This->barrierSlaveFds;
+			selectRetval = select( This->maxBarrierSlaveSockFd+1, &rfds2, NULL, NULL, NULL ); // blocking
+			if ( selectRetval < 0 ) {
+				sage::printLog("sageSyncBBServer::mainLoopThread() : select(refresh barrier) error\n");
+				exit(1);
+			}
+			for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+
+				if ( !activeNodes[i] ) continue;
+
+				if ( FD_ISSET( This->syncSlavesMap[i].barrierClientSockFd, &rfds2 ) ) {
+
+					netStatus = sage::recv(This->syncSlavesMap[i].barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN);
+					//netStatus = ::recv(This->syncSlavesMap[i].barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN, 0);
+
+					if ( netStatus <= 0 ) {
+						fprintf(stdout, "sageSyncBBServer::mainLoopThread() : recv error at the barrier entry phase\n");
+					}
+					barrierCount++;
+				}
+			}
+		}
+		for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+			if ( activeNodes[i] ) {
+				activeNodes[i] = false;
+
+				// NON_BLOCKING
+				//netStatus = ::send(This->syncSlavesMap[i].barrierClientSockFd, msg, SAGE_SYNC_MSG_LEN, MSG_DONTWAIT);
+
+				//printf("BARRIER send to node%d\n", i);
+				//netStatus = ::send(This->syncSlavesMap[i].barrierClientSockFd, msg, SAGE_SYNC_MSG_LEN, 0);
+
+
+				// BLOCING
+				netStatus = sage::send(This->syncSlavesMap[i].barrierClientSockFd, msg, SAGE_SYNC_MSG_LEN);
+
+				if ( netStatus <= 0 ) {
+					sage::printLog("sageSyncBBServer::mainLoopThread() : send error when barrier broadcasting\n");
+				}
+			}
+		}
+		barrierCount = 0;
+		activeNodeSize = 0;
+		**/
+		/* Ends SELECTIVE barrier */
+
+
+
+		/** BROADCASTING BARRIER ***/
+		if ( This->syncLevel == 2 ) {
+
+#ifdef PROFILING_SYNCMASTER
+			// node%d:pdl%d:frame%d:ITEM:%d:%d
+			gettimeofday(&pTimer, NULL);
+			fprintf(profile, "%d:%d:%lu:Barrier_B:%ld:%ld\n", -1,-1,loopCounter,pTimer.tv_sec, pTimer.tv_usec);
+#endif
+			int nodeID,deltaT; // in usec
+			int maxDeltaT = 0;
+
+			while(barrierCount < This->syncSlavesMap.size()) {
+				fd_set rfds2 = This->barrierSlaveFds;
+				selectRetval = select( This->maxBarrierSlaveSockFd+1, &rfds2, NULL, NULL, NULL ); // blocking
+				if ( selectRetval < 0 ) {
+					sage::printLog("sageSyncBBServer::mainLoopThread() : select(refresh barrier) error\n");
+					exit(1);
+				}
+				for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+					if ( FD_ISSET( This->syncSlavesMap[i].barrierClientSockFd, &rfds2 ) ) {
+						netStatus = sage::recv(This->syncSlavesMap[i].barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN);
+						/*
+#ifdef DELAY_COMPENSATION
+					sscanf(msg, "%d %d", &nodeID, &deltaT);
+					maxDeltaT = MAX(maxDeltaT, deltaT);
+#endif
+						 */
+						if ( netStatus <= 0 ) {
+							fprintf(stdout, "sageSyncBBServer::mainLoopThread() : recv error at the barrier entry phase\n");
+						}
+						barrierCount++;
+					}
+				}
+			} // end barrier loop
+			barrierCount = 0;
+
+			/*
+#ifdef DELAY_COMPENSATION
+		struct timeval initT;
+		gettimeofday(&initT, NULL);
+		sprintf(msg, "%d %d %d", initT.tv_sec, initT.tv_usec, maxDeltaT);
+#endif
+			 */
+			for ( int i=0; i<This->syncSlavesMap.size(); i++ ) {
+				netStatus = ::send(This->syncSlavesMap[i].barrierClientSockFd, msg, SAGE_SYNC_MSG_LEN, MSG_DONTWAIT); // non-block
+				//netStatus = ::send(This->syncSlavesMap[i].barrierClientSockFd, msg, SAGE_SYNC_MSG_LEN, 0); // blocking
+				if ( netStatus <= 0 ) {
+					sage::printLog("sageSyncBBServer::mainLoopThread() : Refresh Barrier send error to node %d", This->syncSlavesMap[i].SDM);
+				}
+			}
+		} // if ( syncLevel == 2)
+#ifdef PROFILING_SYNCMASTER
+		// node%d:pdl%d:frame%d:ITEM:%d:%d
+		gettimeofday(&pTimer, NULL);
+		fprintf(profile, "%d:%d:%lu:Barrier_E:%ld:%ld\n", -1,-1,loopCounter,pTimer.tv_sec, pTimer.tv_usec);
+#endif
+		/* BROADCAST Barrier ends */
+
+#ifdef PROFILING_SYNCMASTER
+		loopCounter++;
+#endif
+	} // end while(syncEnd)
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+void sageSyncBBServer::killAllClients()
+{
+   int noOfSyncSlaves = syncSlaves.size();
+   int i;
+
+   for(i=0; i< noOfSyncSlaves; i++)   {
+      // Check to see if the client has been removed
+      if(syncSlaves[i].clientSockFd == -1) continue;
+
+#ifdef WIN32
+      closesocket(syncSlaves[i].clientSockFd);
+#else
+      shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+      close(syncSlaves[i].clientSockFd);
+#endif
+   }
+
+   noOfSyncSlaves = 0;
+}
+
+sageSyncBBServer :: ~sageSyncBBServer()
+{
+#ifdef WIN32
+   closesocket(serverSockFd);
+   closesocket(barrierServerSockFd);
+#else
+   shutdown(serverSockFd, SHUT_RDWR);
+   shutdown(barrierServerSockFd, SHUT_RDWR);
+   close(serverSockFd);
+   close(barrierServerSockFd);
+#endif
+
+   int noOfSyncSlaves = syncSlaves.size();
+   int i;
+
+   for (i=0; i< noOfSyncSlaves; i++)   {
+      // Check to see if the client has been removed
+      if(syncSlaves[i].clientSockFd == -1)
+         continue;
+
+#ifdef WIN32
+      closesocket(syncSlaves[i].clientSockFd);
+#else
+      shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+      shutdown(syncSlaves[i].barrierClientSockFd, SHUT_RDWR);
+      close(syncSlaves[i].clientSockFd);
+      close(syncSlaves[i].barrierClientSockFd);
+#endif
+
+   }
+
+   //wait for the thread to quit
+   pthread_join(syncThreadID, NULL);
+
+} // End of ~sageSyncBBServer()
+
+
+
+
+
+sageSyncServer::sageSyncServer() : asapSyncGroupNum(0), maxSyncGroupID(-1), syncEnd(false),
+      maxSlaveSockFd(0)
+{
+   FD_ZERO(&slaveFds);
+}
+
+int sageSyncServer::init(int port)
+{
+   int optVal, optLen;
+
+   // create the server socket
+   if((serverSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+      sage::printLog("sageSyncServer::init(): Creating server socket failed");
+      return -1;
+   }
+
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncServer::init(): Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncServer::init(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncServer::init(): Error switching on OOBINLINE.");
+
+#else
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_REUSEADDR, (void*)&optVal, (socklen_t)optLen) !=0)
+      perror("sageSyncServer::init():: Error setting SO_REUSEADDR");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      sage::printLog("\nsageSyncServer::init(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncServer::init(): Error switching on OOBINLINE.");
+
+#endif
+
+   memset(&serverAddr, 0, sizeof(serverAddr));
+   serverAddr.sin_family = AF_INET;
+   serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   serverAddr.sin_port = htons(port);
+
+   if (bind(serverSockFd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr_in)) != 0) {
+      sage::printLog("sageSyncServer::init():: Error binding server socket");
+      return -1;
+   }
+
+   // put in listen mode
+   listen(serverSockFd, 10);
+
+   // create the syncServerThread
+   if (pthread_create(&syncThreadID, NULL, syncServerThread, (void*) this) !=0) {
+      sage::printLog("sageSyncServer::init(): Creating sync thread failed");
+      return -1;
+   }
+
+	if (pthread_create(&groupThreadID, NULL, managerThread, (void*)this) !=0) {
+		sage::printLog("sageSyncServer::init(): Creating manager thread failed");
+		return -1;
+	}
+
+   //timer.reset();
+
+   return 0;
+}
+
+// The sync server thread, which is responsible for listening for new sync clients
+// This thread also polls each connected slave to look for frame updates
+// and then updates the slave data vector
+
+void* sageSyncServer :: syncServerThread(void *args)
+{
+   sageSyncServer *This;
+   This = (sageSyncServer *)args;
+
+   int tempSockFd;
+   int addrLen;
+   int optVal,optLen;
+
+   sockaddr_in clientAddr;
+
+   while (!This->syncEnd)   {
+
+      // accept connections
+      addrLen = sizeof(clientAddr);
+
+      if ((tempSockFd = accept(This->serverSockFd, (struct sockaddr *)&clientAddr,
+            (socklen_t*)&addrLen)) == -1) {
+         sage::printLog("sageSyncServer::syncServerThread()::Quitting sync server thread.");
+         pthread_exit(NULL);
+         continue;
+      }
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncServer: Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncServer: Error switching on OOBINLINE.");
+
+#else
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+         sage::printLog("\nsageSyncServer: Error switching off Nagle's algorithm.");
+
+      optVal = 1;
+      optLen=sizeof(optVal);
+      if(setsockopt(tempSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+         sage::printLog("\nsageSyncServer: Error switching on OOBINLINE.");
+
+#endif
+
+      // add the client's info to the list
+      syncSlaveData newClient;
+      newClient.clientSockFd = tempSockFd;
+      memcpy((void *)&(newClient.clientAddr), (void *)&clientAddr, sizeof(clientAddr));
+      This->syncSlaves.push_back(newClient);
+      This->maxSlaveSockFd = MAX(This->maxSlaveSockFd, tempSockFd);
+      FD_SET(tempSockFd, &This->slaveFds);
+   }
+
+   //pacify compiler
+   return NULL;
+} // end of sageSyncServer :: syncServerThread()
+
+int sageSyncServer::sendSync(syncGroup *grp, int cmd)
+{
+   if (!grp) {
+      sage::printLog("sageSyncServer::sendSync : invalid sync group ID");
+      return -1;
+   }
+
+   char *data = grp->dequeSyncMsg();
+
+   int msgSize = SAGE_SYNC_MSG_LEN;
+   char msg[SAGE_SYNC_MSG_LEN];
+   int dataLen = 0;
+
+   if (data)
+      dataLen = strlen(data) + 1;
+   sprintf(msg, "%d %d %d %d", grp->id, grp->curFrame, dataLen, cmd);
+
+   //std::cout << "send sync " << msg << std::endl;
+
+   int noOfSyncSlaves = syncSlaves.size();
+
+   // send the sync message to all the slaves listed with the server
+   for (int i=0; i<noOfSyncSlaves; i++) {
+      // Check to see if the client has been removed
+      if (syncSlaves[i].clientSockFd == -1)
+         continue;
+
+
+      //sungwon
+      //fprintf(stderr, "sageSyncServer::sendSync: sending sync msg to slave %d, (%s)\n", i, msg);
+      //fflush(stderr);
+
+      /// sends sync message here
+      int sentSize = sage::send(syncSlaves[i].clientSockFd, (void *)msg, msgSize);
+
+      if (sentSize == 0) {
+         sage::printLog("sageSyncServer::sendSync : connection shutdown - client ",
+               (char *)inet_ntoa(syncSlaves[i].clientAddr.sin_addr));
+         // Assuming that something went wrong with the socket connection. Closing it and marking it as dead
+#ifdef WIN32
+         closesocket(syncSlaves[i].clientSockFd);
+#else
+         shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+         close(syncSlaves[i].clientSockFd);
+#endif
+         syncSlaves[i].clientSockFd = -1;
+         return -1;
+      }
+      else if (sentSize < 0) {
+         return -1;
+      }
+      else if (data) {
+
+    	  //sungwon
+	  //fprintf(stderr, "sageSyncServer::sendSync: syncGroup %d has data(%s) in sync msg\n", grp->id, data);
+
+         sage::send(syncSlaves[i].clientSockFd, (void *)data, dataLen);
+      }
+   }
+
+   if (data)
+      delete [] data;
+
+   return 0;
+}
+
+int sageSyncServer::removeSyncGroup(int id)
+{
+   /*if (id < 0) {
+      sage::printLog("sageSyncClient::removeSyncGroup : group ID is out of scope");
+      return -1;
+   }*/
+	int index;
+	syncGroup* grp= findSyncGroup(id, index);
+	if(grp)
+	{
+		//std::cout << "sageSyncServer: found... trying to kill... thread.." << id << " " << index << std::endl;
+		if (grp->policy == SAGE_CONSTANT_SYNC) {
+			// kill thread...
+			grp->syncEnd = true;
+			pthread_join(grp->threadID, NULL);
+		}
+
+		// remove object
+		delete grp;
+		grp = NULL;
+
+		syncGroupArray.erase(syncGroupArray.begin() + index);
+		//std::cout << "---------------------" << std::endl;
+		//asapSyncGroupNum--;
+	}
+	return 0;
+}
+
+int sageSyncServer::addSyncGroup(syncGroup *grp)
+{
+   grp->syncServer = (sageSyncServer *)this;
+   if (grp->id >= 0) {
+		 //sungwon
+		//fprintf(stderr, "sageSyncServer::addSyncGroup: adding group %d\n", grp->id);
+
+      //syncGroupArray[grp->id] = grp;
+      syncGroupArray.push_back(grp);
+   }
+   else {
+      sage::printLog("sageSyncServer::addSyncGroup : invalid sync group ID");
+      return -1;
+   }
+
+	//std::cout << "sageSyncServer: Add Sync Group : " << grp->id << std::endl;
+	maxSyncGroupID = MAX(grp->id, maxSyncGroupID);
+
+   if (grp->policy == SAGE_CONSTANT_SYNC) {
+      if (pthread_create(&grp->threadID, NULL, managerConstantThread, (void*)grp) !=0) {
+         sage::printLog("sageSyncServer::init(): Creating manager thread failed");
+         return -1;
+      }
+   }
+
+   return 0;
+}
+
+void* sageSyncServer::managerConstantThread(void *args)
+{
+   syncGroup *grp = (syncGroup *)args;
+   sageSyncServer *This = (sageSyncServer *)grp->syncServer;
+
+   while (!grp->syncEnd) {
+		This->sendSync(grp);
+		sage::usleep((int)floor(grp->interval+0.5));
+   }
+
+   pthread_exit(NULL);
+   return NULL;
+}
+
+void* sageSyncServer::managerThread(void *args)
+{
+   sageSyncServer *This;
+   This = (sageSyncServer *)args;
+
+   while (!This->syncEnd)   {
+		This->manageUpdate();
+   }
+
+   pthread_exit(NULL);
+   return NULL;
+}
+
+syncGroup* sageSyncServer::findSyncGroup(int id, int& index)
+{
+	syncGroup *grp = NULL;
+	index =0;
+	std::vector<syncGroup *>::iterator iter;
+	for(iter = syncGroupArray.begin(); iter != syncGroupArray.end(); iter++, index++)
+	{
+		if((*iter)->getSyncID() == id)
+		{
+			grp = (syncGroup*) (*iter);
+			return grp;
+		}
+	}
+	index = -1;
+	return NULL;
+}
+
+int sageSyncServer::manageUpdate()
+{
+	int maxSyncGroup = syncGroupArray.size();
+	if (maxSyncGroup == 0) return -1;
+
+   int noOfSyncSlaves = syncSlaves.size();
+   char data[SAGE_SYNC_MSG_LEN];
+   fd_set readFds = slaveFds;
+
+   struct timeval timeOut;
+   timeOut.tv_sec = 0;
+   timeOut.tv_usec = SYNC_TIMEOUT;
+
+   //std::cout << "waiting update" << std::endl;
+   int returnVal = select(maxSlaveSockFd+1, &readFds, NULL, NULL, &timeOut);
+
+   if (returnVal < 0) {
+      sage::printLog("sageSyncServer::manageUpdate : error in waiting update message");
+      return -1;
+   }
+
+   /**
+    * Each sync group has its own maximum frame rate (or minimum interval).
+Even though a sync group is ready to proceed to the next frame,
+the sync master waits until the minimum interval is reached.
+Thus, a sync group can have two states:
+waiting for updates from slaves or waiting for the minimum interval.
+This code fragment was inserted to take care of the latter cases.
+
+If syncGroup::isWaiting() is true, the sync group has the latter state.
+syncGroup::checkInterval() returns if it reaches the interval or not.
+
+This code checks there is a sync group
+which is waiting for the interval.
+If yes and the interval is reached,
+it sends sync signal to the group members immediately
+because all the sync slaves are already ready to proceed the next frame.
+    */
+   //for (int i=0; i<=maxSyncGroupID; i++) {
+   //   syncGroup *grp = syncGroupArray[i];
+	syncGroup *grp = NULL;
+   for (int i=0; i< maxSyncGroup; i++) {
+		grp = syncGroupArray[i];
+		if(!grp) continue;
+
+      // if it's waiting to reach the interval
+      if (grp && grp->isWaiting()) {
+
+    	  // interval reached?
+         if (grp->checkInterval()) {
+
+        	 // if this syncGroup's sync is holding then waits on the condition resumeSync
+            grp->checkHold();
+
+            // send sync signal
+            sendSync(grp);
+         }
+      }
+   }
+
+   for (int i=0; i < noOfSyncSlaves; i++)   {
+      // Check to see if the client has been removed
+      if (syncSlaves[i].clientSockFd == -1)
+         continue;
+
+      if (FD_ISSET(syncSlaves[i].clientSockFd, &readFds)) {
+         int status = sage::recv(syncSlaves[i].clientSockFd, (void*)data, SAGE_SYNC_MSG_LEN);
+
+         if (status == 0) {
+            // close the socket and mark it as dead
+            #ifdef WIN32
+            closesocket(syncSlaves[i].clientSockFd);
+            #else
+            shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+            close(syncSlaves[i].clientSockFd);
+            #endif
+            FD_CLR(syncSlaves[i].clientSockFd, &slaveFds);
+            syncSlaves[i].clientSockFd = -1;
+         }
+         else {
+            int groupID;
+            sscanf(data, "%d", &groupID);
+            //syncGroup *grp = syncGroupArray[groupID];
+				int index;
+				syncGroup *grp = findSyncGroup(groupID, index);
+
+            if (!grp) {
+               sage::printLog("sageSyncServer::manageUpdate : invalid groupID %d", groupID);
+               return -1;
+            }
+
+            //sungwon
+            //fprintf(stderr, "sageSyncServer::manageUpdate: calling grp %d's processUpdate\n", grp->id);
+
+            int cmd = grp->processUpdate(data);
+            if (cmd > 0) {
+               //fprintf(stderr, "send sync %d\n", grp->curFrame);
+               if (grp->checkInterval()) {
+                  grp->checkHold();
+
+            //sungwon
+            //fprintf(stderr, "sageSyncServer::manageUpdate: calling sendSync(%d, %d)\n", grp->id, cmd);
+
+                  sendSync(grp, cmd);
+               }
+            }
+         }
+      } // end if
+   } // end for
+
+   //if (timer.getTimeSec() > 1.0) {
+   //   checkTimeOut();
+   //   timer.reset();
+   //}
+
+   return 0;
+}
+
+/*
+int sageSyncServer::checkTimeOut()
+{
+   for (int i=0; i<=maxSyncGroupID; i++) {
+      syncGroup *grp = syncGroupArray[i];
+      if (grp && grp->checkTimeOut()) {
+         grp->checkHold();
+         sendSync(grp);
+      }
+   }
+
+   return 0;
+}
+
+int sageSyncServer::queueData(char *data, int id)
+{
+   char *syncMsg = new char[strlen(data)+1];
+   strcpy(syncMsg, data);
+   syncGroupList[id]->syncMsgQueue.push_back(syncMsg);
+
+   return 0;
+}
+*/
+
+void sageSyncServer::killAllClients()
+{
+   int noOfSyncSlaves = syncSlaves.size();
+   int i;
+
+   for(i=0; i< noOfSyncSlaves; i++)   {
+      // Check to see if the client has been removed
+      if(syncSlaves[i].clientSockFd == -1) continue;
+
+#ifdef WIN32
+      closesocket(syncSlaves[i].clientSockFd);
+#else
+      shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+      close(syncSlaves[i].clientSockFd);
+#endif
+
+   }
+
+   noOfSyncSlaves = 0;
+}
+
+
+sageSyncServer :: ~sageSyncServer()
+{
+   syncEnd = true;
+   
+#ifdef WIN32
+   closesocket(serverSockFd);
+#else
+   shutdown(serverSockFd, SHUT_RDWR);
+   close(serverSockFd);
+#endif
+
+   int noOfSyncSlaves = syncSlaves.size();
+   int i;
+
+   for (i=0; i< noOfSyncSlaves; i++)   {
+      // Check to see if the client has been removed
+      if(syncSlaves[i].clientSockFd == -1)
+         continue;
+
+#ifdef WIN32
+      closesocket(syncSlaves[i].clientSockFd);
+#else
+      shutdown(syncSlaves[i].clientSockFd, SHUT_RDWR);
+      close(syncSlaves[i].clientSockFd);
+#endif
+
+   }
+
+   //wait for the thread to quit
+   pthread_join(syncThreadID, NULL);
+	pthread_join(groupThreadID, NULL);
+
+} // End of ~sageSyncServer()
+
+
+//--------------------------------------------  C L I E N T   C O D E  ---------------------------------------------//
+
+
+
+
+sageSyncClient::sageSyncClient(int sl) : maxGroupID(-1), syncEnd(false)
+{
+	syncLevel = sl;
+   int optVal, optLen;
+
+   // create the client socket
+   if((clientSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+   {
+      perror("sageSyncClient::sageSyncClient(): Creating server socket failed");
+   }
+
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+
+   sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching on OOBINLINE.");
+
+#else
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching off Nagle's algorithm.");
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching on OOBINLINE.");
+
+#endif
+
+   if ( syncLevel == 2 ) {
+	   if((barrierClientSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
+		   perror("sageSyncClient::sageSyncClient(): Creating server socket failed");
+	   }
+
+	   // loosen the rules for check during bind to allow mutiple binds on the same port
+	   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined (__sun)
+	   optVal = 1;
+	   optLen=sizeof(optVal);
+	   if(setsockopt(barrierClientSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+		   sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching off Nagle's algorithm.");
+
+	   optVal = 1;
+	   optLen=sizeof(optVal);
+	   if(setsockopt(barrierClientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+
+		   sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching on OOBINLINE.");
+#else
+	   optVal = 1;
+	   optLen=sizeof(optVal);
+	   if(setsockopt(barrierClientSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+		   sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching off Nagle's algorithm.");
+
+	   optVal = 1;
+	   optLen=sizeof(optVal);
+	   if(setsockopt(barrierClientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+		   sage::printLog("\nsageSyncClient::sageSyncClient(): Error switching on OOBINLINE.");
+
+#endif
+   }
+} // End of sageSyncClient :: sageSyncClient()
+
+int sageSyncClient::connectToServer(const char *syncServIP, int port, int SDMnum)
+{
+   int noOfConnAttempts = 0;
+   sockaddr_in tempAddr;
+
+   memset(&tempAddr, 0, sizeof(tempAddr));
+   tempAddr.sin_family = AF_INET;
+   tempAddr.sin_addr.s_addr = inet_addr(syncServIP);
+   tempAddr.sin_port = htons(port);
+
+   // try a few times before giving up
+   //connect to the server
+   while (noOfConnAttempts < 50) {
+      if (connect(clientSockFd, (struct sockaddr *)&tempAddr, sizeof(struct sockaddr)) != 0) {
+         char msg[TOKEN_LEN];
+         sprintf(msg, "sageSyncClient :: connectToServer(): sync server %s : %d is not ready\n",
+            syncServIP, port);
+         sage::printLog(msg);
+         noOfConnAttempts++;
+      }
+      else {
+		  if ( SDMnum != -1 ) { // it means new sync
+			  //fprintf(stderr, "sageSyncClient::connectToServer() : Sending SDM %d\n", SDMnum);
+			  //fflush(stderr);
+			sage::send(clientSockFd, (void *)&SDMnum, sizeof(int));
+		  }
+         return 0;
+      }
+      sage::sleep(1);
+   }
+
+   sage::printLog("sageSyncClient :: connectToServer(): Giving up after trying a few times");
+
+   return -1;
+}
+
+int sageSyncClient::connectToBarrierServer(const char *syncServIP, int port, int SDMnum)
+{
+	if ( syncLevel != 2 ) {
+		fprintf(stderr,"sageSyncClient::connectToBarrierServer() : syncLevel id %d. No swapbuffer barrier\n", syncLevel);
+		return -1;
+	}
+   int noOfConnAttempts = 0;
+   sockaddr_in tempAddr;
+
+   memset(&tempAddr, 0, sizeof(tempAddr));
+   tempAddr.sin_family = AF_INET;
+   tempAddr.sin_addr.s_addr = inet_addr(syncServIP);
+   tempAddr.sin_port = htons(port);
+
+   // try a few times before giving up
+   //connect to the server
+   while (noOfConnAttempts < 50) {
+      if (connect(barrierClientSockFd, (struct sockaddr *)&tempAddr, sizeof(struct sockaddr)) != 0) {
+         char msg[TOKEN_LEN];
+         sprintf(msg, "sageSyncClient :: connectToBarrierServer(): sync server %s : %d is not ready\n",syncServIP, port);
+         sage::printLog(msg);
+         noOfConnAttempts++;
+      }
+      else {
+    	  sage::send(barrierClientSockFd, (void *)&SDMnum, sizeof(int));
+    	  return 0;
+      }
+      sage::sleep(1);
+   }
+   sage::printLog("sageSyncClient :: connectToBarrierServer(): Giving up after trying a few times");
+   return -1;
+}
+
+int sageSyncClient::addSyncGroup(int id)
+{
+   if (id < 0) {
+      sage::printLog("sageSyncClient::addSyncGroup : group ID is out of scope");
+      return -1;
+   }
+
+   sageCircBufSingle* buf = new sageCircBufSingle(SYNC_MSG_BUF_LEN, true);
+	buf->instID = id;
+   syncMsgBuf.push_back(buf);
+
+   if (maxGroupID < 0) {
+      maxGroupID = id;
+
+      //sungwon
+      //fprintf(stderr, "sageSyncClient::addSyncGroup: starting syncClientThread for the group %d\n", id);
+
+      if (pthread_create(&syncThreadID, NULL, syncClientThread, (void*) this) !=0) {
+         sage::printLog("sageSyncClient::addSyncGroup(): Creating sync client thread failed");
+         return -1;
+      }
+   }
+   else
+      maxGroupID = MAX(maxGroupID, id);
+
+   std::cout << "added sync group " << id << std::endl;
+
+   return 0;
+}
+
+int sageSyncClient::removeSyncGroup(int id)
+{
+   if (id < 0) {
+      sage::printLog("sageSyncClient::removeSyncGroup : group ID is out of scope");
+      return -1;
+   }
+
+	int index;
+	sageCircBufSingle* buf = findSyncGroup(id, index);
+	if(buf)
+	{
+		//std::cout << "sageSyncClient: found... trying to kill... thread.." << std::endl;
+		buf->releaseLock();
+		delete buf;
+		buf = NULL;
+		syncMsgBuf.erase(syncMsgBuf.begin() + index);
+		//std::cout << "...." << std::endl;
+	}
+   //if (syncMsgBuf[id])
+   //   syncMsgBuf[id]->releaseLock();
+
+   return 0;
+}
+
+sageCircBufSingle* sageSyncClient::findSyncGroup(int id, int& index)
+{
+	sageCircBufSingle *buf = NULL;
+	index =0;
+	std::vector<sageCircBufSingle *>::iterator iter;
+	for(iter = syncMsgBuf.begin(); iter != syncMsgBuf.end(); iter++, index++)
+	{
+		if((*iter)->instID == id)
+		{
+			buf = (sageCircBufSingle*) (*iter);
+			return buf;
+		}
+	}
+	index = -1;
+	return NULL;
+}
+
+void* sageSyncClient::syncClientThread(void* args)
+{
+   //sungwon
+   //fprintf(stderr, "sageSyncClient::syncClientThread started\n");
+
+   sageSyncClient *This = (sageSyncClient *)args;
+
+   while (!This->syncEnd) {
+      if (This->readSyncMsg() < 0)
+         This->syncEnd = true;
+   }
+
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sageSyncClient::sendSlaveUpdate(int frame, int id, int rcvNum, int type, int SDMnum)
+{
+   int dataSize = SAGE_SYNC_MSG_LEN;
+   char msg[SAGE_SYNC_MSG_LEN];
+   sprintf(msg, "%d %d %d %d %d", id, frame, rcvNum, type, SDMnum);
+
+   int status = sage::send(clientSockFd, (void *)msg, dataSize);
+
+   if (status !=  dataSize) {
+      perror("sageSyncClient :: sendSlaveUpdate(): Error sending update message to sync master");
+      return -1;
+   }
+
+   return 0;
+}
+
+
+int sageSyncClient::sendSlaveUpdateToBBS(int frame, int id, int rcvNum, int SDMnum, int delayCompenLatency)
+{
+   int dataSize = SAGE_SYNC_MSG_LEN;
+   char msg[SAGE_SYNC_MSG_LEN];
+   sprintf(msg, "%d %d %d %d %d", id, frame, rcvNum, SDMnum, delayCompenLatency);
+#ifdef DEBUG_SYNC
+   fprintf(stderr,"[%d,%d] sageSyncClient::sendSlaveUpdateToBBS() : updateFrame %d\n", SDMnum, id, frame);
+#endif
+
+	//printf("SDM %d PDL %d sendUp frm %d rcvNum %d\n", SDMnum, id, frame, rcvNum);
+
+   int status = sage::send(clientSockFd, (void *)msg, dataSize);
+
+   if (status !=  dataSize) {
+      perror("sageSyncClient :: sendSlaveUpdate(): Error sending update message to sync master");
+      return -1;
+   }
+
+   return 0;
+} //End of sageSyncClient :: sendSlaveUpdate()
+
+int sageSyncClient::sendRefreshBarrier(int nodeID) {
+	char msg[SAGE_SYNC_MSG_LEN];
+	sprintf(msg, "%d %d", nodeID, refreshBarrierDeltaT);
+
+	// barrierClient->getSocketId();
+	//int status = ::send(barrierClientSockFd, (void *)msg, SAGE_SYNC_MSG_LEN, 0);
+
+	//printf("SDM%d send delta %d\n", nodeID, refreshBarrierDeltaT);
+
+	int status = sage::send(barrierClientSockFd, (void *)msg, SAGE_SYNC_MSG_LEN);
+
+	//if (status != SAGE_SYNC_MSG_LEN) {
+		//sage::printLog("sageSyncClient::reportMontageUpdate(): SDM %d PDL %d, Error sending update message to barrier", nodeID, groupID);
+		//return -1;
+	//}
+	return status;
+}
+int sageSyncClient::recvRefreshBarrier(bool nonblock) {
+	char msg[SAGE_SYNC_MSG_LEN];
+
+	//int status = ::recv(barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN, MSG_DONTWAIT);
+	//int status = ::recv(barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN, MSG_WAITALL);
+	//int status = ::recv(barrierClientSockFd, (void*)msg, SAGE_SYNC_MSG_LEN, 0);
+
+	int status = 0;
+	if ( nonblock ) {
+		status = ::recv(barrierClientSockFd, (char*)msg, SAGE_SYNC_MSG_LEN, MSG_DONTWAIT);
+	}
+	else {
+		status = ::recv(barrierClientSockFd, (char*)msg, SAGE_SYNC_MSG_LEN, 0);
+	}
+	return status;
+}
+
+
+
+int sageSyncClient::readSyncMsg()
+{
+   int dataSize = SAGE_SYNC_MSG_LEN;
+   char msg[SAGE_SYNC_MSG_LEN];
+   int groupID = -1;
+
+   // read a message but leave it in socket buffer
+   int status = sage::recv(clientSockFd, (void*)msg, dataSize);
+
+   //sungwon
+   //fprintf(stderr, "sageSyncClient::readSyncMsg: recved msg (%s)\n", msg);
+
+   if (status !=  dataSize) {
+      perror("sageSyncClient :: waitForSync(): Error receiving sync from master");
+      sage::sleep(1);
+      return -1;
+   }
+
+   int frameNum, dataLen;
+   sscanf(msg, "%d %d %d", &groupID, &frameNum, &dataLen);
+
+   if (groupID >= 0) {
+      syncMsgStruct *syncMsg;
+
+      if (dataLen > 0) {
+         syncMsg = new syncMsgStruct(dataLen);
+         sage::recv(clientSockFd, (void*)syncMsg->data, dataLen);
+      }
+      else {
+         syncMsg = new syncMsgStruct;
+      }
+
+      syncMsg->frameID = frameNum;
+
+      //sageCircBufSingle *msgBuf = syncMsgBuf[groupID];
+		int index;
+      sageCircBufSingle *msgBuf = findSyncGroup(groupID, index);
+      if (msgBuf && msgBuf->isActive()) {
+         if (!msgBuf->pushBack((sageBufEntry)syncMsg)) {
+            sage::printLog("sageSyncClient::readSyncMsg : sync message buffer is full");
+            delete syncMsg;
+         }
+      }
+      else
+         delete syncMsg;
+   }
+   else
+      sage::printLog("sageSyncClient::readSyncMsg : invalid group ID");
+
+   return 0;
+}
+
+// receive sync message with group ID and additional data
+syncMsgStruct* sageSyncClient::waitForSync(int id)
+{
+	if (id < 0) {
+      sage::printLog("sageSyncClient::waitForSync : group ID is out of scope");
+      return NULL;
+   }
+
+   //sageCircBufSingle *msgBuf = syncMsgBuf[id];
+	int index;
+   sageCircBufSingle *msgBuf = findSyncGroup(id, index);
+	//std::cout << "wait for sync : " << id << " " << index << std::endl;
+
+   if (msgBuf) {
+      syncMsgStruct *syncMsg = (syncMsgStruct *)msgBuf->front();
+      if (msgBuf->isActive()) {
+         if (!syncMsg) {
+            sage::printLog("sageSyncClient::waitForSync : syncMsg is NULL");
+         }
+         msgBuf->next();
+
+         return syncMsg;
+      }
+   }
+
+   return NULL;
+}
+
+// receive sync message with additional data
+int sageSyncClient::waitForSyncData(char* &data)
+{
+   int dataSize = SAGE_SYNC_MSG_LEN;
+   char msg[SAGE_SYNC_MSG_LEN];
+   int groupID = -1;
+   int frameNum, dataLen;
+   int status = sage::recv(clientSockFd, (void*)msg, dataSize);
+
+   if (status !=  dataSize) {
+      sage::printLog("sageSyncClient :: waitForSync(): Error receiving sync from master");
+      sage::sleep(1);
+      return -1;
+   }
+
+   sscanf(msg, "%d %d %d", &groupID, &frameNum, &dataLen);
+
+   if (dataLen > 0) {
+      data = new char[dataLen];
+      sage::recv(clientSockFd, (void*)data, dataLen);
+   }
+
+   return frameNum;
+}
+
+int sageSyncClient::waitForSyncPeek() {
+	int size = 0;
+	int status = ::recv(clientSockFd, (char *)&size, sizeof(int), MSG_PEEK);
+
+	if ( status != sizeof(int) ) {
+		perror("sageSyncClient::waitForSyncPeek() : recv");
+		return -1;
+	}
+	return size;
+}
+
+// receive sync message with no additional data
+int sageSyncClient::waitForSync(char* msg, int len)
+{
+	int dataSize = 0;
+	if ( syncLevel == -1 ) {
+		dataSize = SAGE_SYNC_MSG_LEN;
+	}
+	else {
+		if ( len > 0 )
+			dataSize = len;
+		else
+			dataSize = SAGE_SYNC_MSG_LEN;
+	}
+
+	int status = sage::recv(clientSockFd, (void*)msg, dataSize);
+
+	if (status != dataSize) {
+		fprintf(stderr,"sageSyncClient::waitForSync(): syncLevel %d, msgLen %d, Error receiving sync from master",syncLevel, len);
+		sage::sleep(1);
+		return -1;
+	}
+
+	return 0;
+}
+
+int sageSyncClient::checkSync(char* &msg)
+{
+   int dataSize = SAGE_SYNC_MSG_LEN;
+
+   if (sage::isDataReady(clientSockFd)) {
+      int status=sage::recv(clientSockFd, (void*)msg, dataSize);
+      if (status !=  dataSize) {
+         perror("sageSyncClient :: checkSync(): Error receiving sync from master");
+         sage::sleep(1);
+         return -1;
+      }
+
+      return 1;
+   }
+   else
+      return 0;
+}
+
+sageSyncClient :: ~sageSyncClient()
+{
+   syncEnd = true;
+
+#ifdef WIN32
+   closesocket(clientSockFd);
+#else
+   shutdown(clientSockFd, SHUT_RDWR);
+   close(clientSockFd);
+#endif
+
+   pthread_join(syncThreadID, NULL);
+
+	int maxGroupID = syncMsgBuf.size();
+   for (int i=0; i<maxGroupID; i++)
+      if (syncMsgBuf[i])
+         delete syncMsgBuf[i];
+}
+
+sageThreadSync::sageThreadSync(int sNum)
+{
+   slaveNum = sNum;
+   masterLock = new pthread_mutex_t[slaveNum];
+   slaveLock = new pthread_mutex_t[slaveNum];
+
+   for (int i=0; i<slaveNum; i++) {
+      pthread_mutex_init(&masterLock[i], NULL);
+      pthread_mutex_lock(&masterLock[i]);
+   }
+
+   for (int i=0; i<slaveNum; i++) {
+      pthread_mutex_init(&slaveLock[i], NULL);
+      pthread_mutex_lock(&slaveLock[i]);
+   }
+}
+
+sageThreadSync::~sageThreadSync()
+{
+   if (masterLock)
+      delete [] masterLock;
+
+   if (slaveLock)
+      delete [] slaveLock;
+}
+
+int sageThreadSync::synchronize(int rank)
+{
+   //sage::printLog("rank " << rank << std::endl << "slave num " << slaveNum);
+   if (rank == 0) {
+      for (int i=0; i<slaveNum; i++) {
+         pthread_mutex_unlock(&slaveLock[i]);
+      }
+      //sage::printLog("unlock slave lock");
+      //sage::printLog("waiting master lock");
+      for (int i=0; i<slaveNum; i++) {
+         pthread_mutex_lock(&masterLock[i]);
+      }
+      //sage::printLog("obtain master lock");
+   }
+   else if (rank <= slaveNum) {
+      //sage::printLog("==== waiting slave lock");
+      pthread_mutex_lock(&slaveLock[rank-1]);
+      //sage::printLog("==== obtain slave lock");
+      pthread_mutex_unlock(&masterLock[rank-1]);
+      //sage::printLog("==== unlock master lock");
+   }
+
+   return 0;
+}
+
+
+
+
+
+
Index: trunk/src/testing/src/fsMain.cpp
===================================================================
--- trunk/src/testing/src/fsMain.cpp	(revision 4)
+++ trunk/src/testing/src/fsMain.cpp	(revision 4)
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: fsMain.cpp - the main function of the Free Space Manager
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/ 
+
+#include "sageVersion.h"
+#include "fsManager.h"
+
+int main(int argc, char *argv[])
+{
+#if defined(WIN32)
+   sage::win32Init();
+#endif
+
+   fsManager fsm;
+
+   sage::printLog("fsManager: SAGE version [%s]", SAGE_VERSION);
+   
+   if (argc > 1) {
+      sage::printLog("fsManager: using configuration file [%s]\n", argv[1]);
+      if (fsm.init(argv[1]) < 0)
+         exit(-1);
+   }
+   else {
+      sage::printLog("fsManager: using default configuration file [fsManager.conf]\n");
+      if (fsm.init("fsManager.conf") < 0)
+         exit(-1);
+   }
+   
+   fsm.mainLoop();
+}
+
Index: trunk/src/testing/src/sageVirtualDesktop.cpp
===================================================================
--- trunk/src/testing/src/sageVirtualDesktop.cpp	(revision 4)
+++ trunk/src/testing/src/sageVirtualDesktop.cpp	(revision 4)
@@ -0,0 +1,446 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageVirtualDesktop.cpp - providing operations needed for the desktop
+ *           management for tiled display
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+#include "sageVirtualDesktop.h"
+#include "streamInfo.h"
+#include "fsManager.h"
+#include "fsCore.h"
+
+sageVirtualDesktop::sageVirtualDesktop(fsManager *f, int id)
+{
+   fsm = f;
+   displayID = id;
+
+   clientList.clear();
+   audioClientList.clear();
+}
+
+sageVirtualDesktop::~sageVirtualDesktop()
+{
+   clientList.clear();
+   audioClientList.clear();
+}
+
+int sageVirtualDesktop::getRcvId(int nodeId)
+{
+   for(int i=0; i<tileNodeList.size(); i++) {
+      if (tileNodeList[i] == nodeId)
+         return clientList[i];
+   }
+
+   return -1;
+}
+
+int sageVirtualDesktop::regRcv(int cId, int nodeID)
+{
+   tileNodeList.push_back(nodeID);
+   clientList.push_back(cId);
+
+   return 0;
+}
+
+int sageVirtualDesktop::getNodeIPs(int nodeId, char *ipStr)
+{
+   strcpy(ipStr, displayCluster[nodeId]->ip);
+
+   return 0;
+}
+
+int sageVirtualDesktop::getForwardIP(int nodeId, char *ipStr)
+{
+   strcpy(ipStr, displayCluster[nodeId]->forwardIP);
+
+   return 0;
+}
+
+int sageVirtualDesktop::changeBGColor(int red, int green, int blue)
+{
+   for (int i=0; i<clientList.size(); i++) {
+      char colorStr[TOKEN_LEN];
+      sprintf(colorStr, "%d %d %d", red, green, blue);
+      fsm->sendMessage(clientList[i], RCV_CHANGE_BGCOLOR, colorStr);
+   }
+   return 0;
+}
+
+int sageVirtualDesktop::sendToAll(int code, char *data)
+{
+   for (int i=0; i<clientList.size(); i++) {
+      if (data)
+         fsm->sendMessage(clientList[i], code, data);
+      else
+         fsm->sendMessage(clientList[i], code);
+   }
+
+   return 0;
+}
+
+int sageVirtualDesktop::launchReceivers(char *fsIP, int port, int syncPort, bool globalSync, int syncBarrierPort, int refreshInterval, int syncMasterPollingInterval, int syncLevel)
+{
+   char *sageDir = getenv("SAGE_DIRECTORY");
+   if (!sageDir) {
+      std::cout << "sageVirtualDesktop : cannot find the environment variable SAGE_DIRECTORY" << std::endl;
+      return -1;
+   }
+
+   char *dispBinPath = getenv("SAGE_DISPLAY_BIN_PATH");
+
+   for (int i=0; i<displayCluster.size(); i++) {
+      char command[TOKEN_LEN];
+
+#if defined(WIN32)
+      sprintf(command, "start  /D%s\\bin %s\\bin\\sageDisplayManager %s %d %d %d %d %d %d %d %d %d",
+         sageDir,
+		 sageDir, fsIP, port, i, syncPort, displayID, (int)globalSync, syncBarrierPort, refreshInterval, syncMasterPollingInterval, syncLevel);
+
+      std::cout << "ATTENTION: SAGE on Windows works only locally, no remote execution" << std::endl;
+      std::cout << "\t" << command << std::endl;
+      system( command );
+#elif defined(__APPLE__)
+      sprintf(command, "%s/bin//sageDisplayManager.app/Contents/MacOS/sageDisplayManager %s %d %d %d %d %d %d %d %d %d",
+		sageDir, fsIP, port, i,
+		syncPort, displayID, (int)globalSync, syncBarrierPort, refreshInterval, syncMasterPollingInterval, syncLevel);
+      if (execRemBin(displayCluster[i]->ip, command, displayCluster[i]->Xdisp) < 0)
+         return -1;
+#else
+      if (dispBinPath) {
+         sprintf(command, "%s/sageDisplayManager %s %d %d %d %d %d %d %d %d %d", dispBinPath,
+            fsIP, port, i, syncPort, displayID, (int)globalSync, syncBarrierPort, refreshInterval, syncMasterPollingInterval, syncLevel);
+      }
+      else {
+         sprintf(command, "sageDisplayManager %s %d %d %d %d %d %d %d %d %d", fsIP, port, i,
+            syncPort, displayID, (int)globalSync, syncBarrierPort, refreshInterval, syncMasterPollingInterval, syncLevel);
+      }
+
+      if (execRemBin(displayCluster[i]->ip, command, displayCluster[i]->Xdisp) < 0)
+         return -1;
+#endif
+   }
+
+   if (masterIP[0] == '\0')
+      getNodeIPs(0, masterIP);
+
+   return 0;
+}
+
+int sageVirtualDesktop::getRcvInfo(int nodeID, char *info)
+{
+   displayNode *disp = displayCluster[nodeID];
+   if (!disp) {
+      sage::printLog("sageVirtualDesktop : Can't find the display node %d", nodeID);
+      return -1;
+   }
+
+   sprintf(info, "%s %d %d %d %d %d %d", masterIP, disp->tiles[0]->width, disp->tiles[0]->height,
+         disp->dimX, disp->dimY, disp->winX, disp->winY);
+
+   char tileInfo[TOKEN_LEN];
+   for (int i=0; i<disp->tiles.size(); i++) {
+      int tileX = disp->tiles[i]->x;
+      int tileY = disp->tiles[i]->y;
+      // get the top-left corner of the tile
+      int revY = convertYaxis(disp->tiles[i]->y + disp->tiles[i]->height);
+      sprintf(tileInfo, " %d %d %d %d", disp->tiles[i]->tileID, tileX, tileY, revY);
+      strcat(info, tileInfo);
+   }
+
+   //std::cout << "recv " << nodeID << " : " << info << std::endl;
+
+   return 0;
+}
+
+int sageVirtualDesktop::getLocalPort(int nodeID)
+{
+   displayNode *disp = displayCluster[nodeID];
+   if (!disp) {
+      sage::printLog("sageVirtualDesktop : Can't find the display node %d", nodeID);
+      return -1;
+   }
+
+   return disp->port;
+}
+
+int sageVirtualDesktop::getForwardPort(int nodeID)
+{
+   displayNode *disp = displayCluster[nodeID];
+   if (!disp) {
+      sage::printLog("sageVirtualDesktop : Can't find the display node %d", nodeID);
+      return -1;
+   }
+
+   return disp->forwardPort;
+}
+
+int sageVirtualDesktop::generateStreamInfo(streamGroup &sGrp, std::vector<int> &rcvList, int offset)
+{
+   for (int i=0; i<tileList.size(); i++) {
+      streamInfo newStream;
+
+      // set the stream image area to the overlap of a tile area and
+      // an area mapped to a sender
+      sageRect appWindow = (sageRect &)sGrp;
+      if (appWindow.isOverLap(*(sageRect *)tileList[i], (sageRect &)newStream)) {
+         newStream.receiverID = tileList[i]->nodeID + offset;
+         //newStream.tileID = i;
+
+         sGrp.addStream(newStream);
+         int cnt = 0;
+#ifdef __SUNPRO_CC
+         std::count(rcvList.begin(), rcvList.end(), tileList[i]->nodeID, cnt);
+#else
+         cnt = std::count(rcvList.begin(), rcvList.end(), tileList[i]->nodeID);
+#endif
+
+         if (cnt == 0)
+            rcvList.push_back(tileList[i]->nodeID);
+      }
+   }
+
+   return 0;
+}
+
+bool sageVirtualDesktop::checkLayout(appInExec* app)
+{
+   int checkResult = isOverLap(*(sageRect *)app, 0.5);
+   if (checkResult == ON_RECT)
+      return true;
+   else  {
+      checkNeighbors(app, checkResult);
+      return false;
+   }
+}
+
+void sageVirtualDesktop::checkNeighbors(appInExec *app, int edge)
+{
+   //std::cerr << "check neighbor " << edge << std::endl;
+   bool relocate = false;
+   for (int i=0; i<connectionList.size(); i++) {
+      for (int j=0; j<2; j++) {
+         //std::cerr << "display " << connectionList[i]->displays[j]->displayID << std::endl;
+         //std::cerr << "edge " << connectionList[i]->edges[j] << std::endl;
+         if (connectionList[i]->displays[j]->displayID == displayID &&
+               connectionList[i]->edges[j] == edge) {
+            connectionList[i]->displays[1-j]->locateApp(app, connectionList[i], 1-j);
+            relocate = true;
+            app->displayID = connectionList[i]->displays[1-j]->displayID;
+         }
+      }
+      if (relocate)
+         break;
+   }
+
+   if (!relocate)
+      locateApp(app, NULL);
+}
+
+int sageVirtualDesktop::getAudioRcvId(int nodeId)
+{
+   for(int i=0; i<audioNodeList.size(); i++) {
+      if (audioNodeList[i] == nodeId)
+         return audioClientList[i];
+   }
+
+   return -1;
+}
+
+int sageVirtualDesktop::regAudioRcv(int cId, int nodeId)
+{
+   audioNodeList.push_back(nodeId);
+   audioClientList.push_back(cId);
+
+   return 0;
+}
+
+int sageVirtualDesktop::getAudioNodeIPs(int nodeId, char *ipStr)
+{
+   strcpy(ipStr, audioCluster[nodeId]->ip);
+
+   return 1;
+}
+
+int sageVirtualDesktop::launchAudioReceivers(char *fsIP, int port, int syncPort)
+{
+   char *sageDir;
+   if (audioServer)
+      sageDir = audioDir;
+   else
+      sageDir = getenv("SAGE_DIRECTORY");
+
+   if (!sageDir) {
+      std::cout << "sageVirtualDesktop : cannot find the environment variable SAGE_DIRECTORY" << std::endl;
+      return -1;
+   }
+
+   int audioSyncPort = 14999;
+   for (int i=0; i< audioCluster.size(); i++) {
+      char command[TOKEN_LEN];
+
+#if defined(WIN32)
+      sprintf(command, "start /B /D%s %s\\bin\\sageAudioManager %s %d %d %d",
+         sageDir, sageDir, fsIP, port, i, syncPort/*,audioSyncPort*/);
+
+      std::cout << "ATTENTION: SAGE on Windows works only locally, no remote execution" << std::endl;
+      std::cout << "\t" << command << std::endl;
+      system( command );
+#else
+      sprintf(command, "%s/bin/sageAudioManager %s %d %d %d", sageDir, fsIP, port, i, syncPort /*, audioSyncPort*/);
+      std::cout << "audio " << command << std::endl;
+      if (execRemBin(audioCluster[i]->ip, command) < 0)
+         return -1;
+#endif
+
+   }
+
+   return 0;
+}
+
+int sageVirtualDesktop::getAudioRcvInfo(int nodeID, char *info)
+{
+   char *ipStr;
+
+   // if (nodeID == 0)
+   //        ipStr = "127.0.0.1";
+   // else
+   //        ipStr = audioCluster[0]->ip;
+   ipStr = displayCluster[0]->ip;
+
+
+   audioNode *audio = audioCluster[nodeID];
+
+// need to modify
+   sprintf(info, "%s %d %d %ld %d %d", ipStr, audio->deviceId, (int)audio->sampleFmt, audio->samplingRate,
+                        audio->channels, audio->framePerBuffer);
+
+   std::cout << "recv " << nodeID << " : " << info << std::endl;
+
+   return 0;
+}
+
+int sageVirtualDesktop::generateAudioRcvInfo(int port, char* msgStr)
+{
+   int tileNum = audioCluster.size();
+
+   char tileInfoStr[TOKEN_LEN];
+   memset(tileInfoStr, 0, TOKEN_LEN);
+   sprintf(tileInfoStr, "%d %d ", port, tileNum);
+   strcat(msgStr, tileInfoStr);
+   //printf("---------%s \n", tileInfoStr);
+
+   // list ip addresses for each tile
+   for (int i=0; i<tileNum; i++) {
+
+      char tileStr[TOKEN_LEN];
+      sprintf(tileStr, "%s %d ", audioCluster[i]->ip, i);
+      strcat(msgStr, tileStr);
+   }
+
+   return 0;
+}
+
+int sageVirtualDesktop::generateAudioRcvInfo(char* ip, int port, char* msgStr)
+{
+        /*int tileNum = audioCluster.size();
+        tileNum = 1;    // assumption
+
+        char tileInfoStr[TOKEN_LEN];
+        memset(tileInfoStr, 0, TOKEN_LEN);
+        sprintf(tileInfoStr, "%d %d ", port, tileNum);
+        strcat(msgStr, tileInfoStr);
+
+        int attachedNum;
+        // list ip addresses for each tile
+        char tileStr[TOKEN_LEN];
+
+        for (int i=0; i<tileNum; i++) {
+
+                attachedNum = audioCluster[i]->streamIPs.size();
+                for(int j =0; j < attachedNum; j++) {
+                         if(strcmp(audioCluster[i]->streamIPs[j], ip) == 0) {
+
+                         }
+                }
+
+                sprintf(tileStr, "%s %d ", audioCluster[i]->ip, i);
+                strcat(msgStr, tileStr);
+        }*/
+
+   // new --- test
+   int tileNum =1;
+   char tileInfoStr[TOKEN_LEN];
+   memset(tileInfoStr, 0, TOKEN_LEN);
+   sprintf(tileInfoStr, "%d %d ", port, tileNum);
+   //printf("---------%s \n", tileInfoStr);
+   //printf("---------%d %d \n", port, tileNum);
+   strcat(msgStr, tileInfoStr);
+
+   // list ip addresses for each tile
+   char tileStr[TOKEN_LEN];
+   sprintf(tileStr, "%s %d ", audioCluster[0]->ip, 0);
+   //audioCluster[0]->nodeCount++;
+   strcat(msgStr, tileStr);
+
+   return 0;
+}
+
+int sageVirtualDesktop::generateAudioStreamInfo(streamGroup &sGrp, std::vector<int> &rcvList)
+{
+/*      for (int i=0; i<audioList.size(); i++) {
+                streamInfo newStream;
+
+// need to modify
+
+                // set the stream image area to the overlap of a tile area and
+                // an area mapped to a sender
+                sageRect appWindow = (sageRect &)sGrp;
+                if (appWindow.isOverLap(*(sageRect *)tileList[i], (sageRect &)newStream)) {
+                        newStream.receiverId = audioList[i]->nodeID;
+                        newStream.tileID = i;
+
+                        sGrp.addStream(newStream);
+                        int cnt = 0;
+                        cnt = std::count(rcvList.begin(), rcvList.end(), audioList[i]->nodeID);
+
+                        if (cnt == 0)
+                                rcvList.push_back(audioList[i]->nodeID);
+                }
+        }*/
+
+   return 0;
+}
Index: trunk/src/testing/src/sageMessage.cpp
===================================================================
--- trunk/src/testing/src/sageMessage.cpp	(revision 4)
+++ trunk/src/testing/src/sageMessage.cpp	(revision 4)
@@ -0,0 +1,249 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageMessage.cpp - interface functions of the sageMessage class
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageBase.h"
+
+sageMessage::sageMessage() : clientID(0)
+{
+   dest = NULL;
+   code = NULL;
+   appCode = NULL;
+   size = NULL;
+   data = NULL;
+   buffer = NULL;
+}
+
+sageMessage::~sageMessage()
+{
+}
+
+int sageMessage::destroy()
+{
+   if (buffer)
+      delete [] buffer;
+   
+   return 0;   
+}   
+
+/*
+void sageMessage::init() 
+{
+   int fSize = MESSAGE_FIELD_SIZE;
+   
+   size = buffer;   
+   dest = &buffer[fSize];
+   code = &buffer[2*fSize];
+   appCode = &buffer[3*fSize];
+   data = (void *)&buffer[4*fSize];
+}
+*/
+
+int sageMessage::init(int buf_size) 
+{
+   buffer = new char[buf_size+1];
+   memset(buffer, 0, buf_size+1);   
+   int fSize = MESSAGE_FIELD_SIZE;
+   size = buffer;   
+   dest = &buffer[fSize];
+   code = &buffer[2*fSize];
+   appCode = &buffer[3*fSize];
+   if (buf_size > MESSAGE_HEADER_SIZE)
+      data = (void *)&buffer[4*fSize];
+   bufSize = buf_size;
+   sprintf(size,"%d\0", bufSize);
+   
+   return buf_size;
+}
+
+int sageMessage::init(int dst, int co, int app, 
+                        int sz, const void *dat)
+{
+   if ((bufSize = init(sz + MESSAGE_HEADER_SIZE)) < 0)
+      return -1;
+
+   sprintf(dest,"%d\0", dst);
+   sprintf(code,"%d\0", co);
+   sprintf(appCode,"%d\0", app);
+   
+   if (dat)
+      memcpy(data, dat, sz);
+
+   return bufSize;
+}
+
+int sageMessage::set(int dst, int co, int app, 
+                        int sz, const void *dat)
+{
+   sprintf(dest,"%d\0", dst);
+   sprintf(code,"%d\0", co);
+   sprintf(appCode,"%d\0", app);
+   sprintf(size,"%d\0", sz + MESSAGE_HEADER_SIZE);
+   memcpy(data, dat, sz);
+
+   return 0;
+}
+
+int sageMessage::getDest()
+{
+   if (dest) {
+      dest[8] = '\0';
+      return atoi(dest);
+   }   
+   else {
+      std::cerr << "fail to get destination" << std::endl;
+      return 0;
+   }
+}
+
+int sageMessage::getCode()
+{
+   if (code) {
+      code[8] = '\0';
+      return atoi(code);
+   }   
+   else {
+      std::cerr << "fail to get code" << std::endl;
+      return 0;
+   }
+}
+
+int sageMessage::getAppCode()
+{
+   if (appCode) {
+      appCode[8] = '\0';
+      return atoi(appCode);
+   }   
+   else {
+      std::cerr << "fail to get application code" << std::endl;
+      return 0;
+   }
+}
+
+int sageMessage::getSize()
+{
+   if (size) {
+      size[8] = '\0';
+      return (atoi(size) - MESSAGE_HEADER_SIZE);
+   }   
+   else {
+      std::cerr << "fail to get size of message" << std::endl;
+      return 0;
+   }
+}
+
+void* sageMessage::getData()
+{
+   if (data)
+      return data;
+   else {
+      return NULL;
+   }
+}
+
+char* sageMessage::getBuffer()
+{
+   return buffer;
+}
+
+int sageMessage::setSize(int s)
+{
+   if (s > bufSize - MESSAGE_HEADER_SIZE) {
+      std::cout << "sage message buffer overflow" << std::endl;
+      return -1;
+   }
+   
+   bufSize = s + MESSAGE_HEADER_SIZE;
+   sprintf(size,"%d\0", bufSize);
+   return 0;
+}   
+   
+int sageMessage::setDest(int dst)
+{
+   if (dest)
+      sprintf(dest,"%d\0", dst);
+   else {
+      std::cerr << "fail to set destination" << std::endl;
+      return -1;
+   }
+   return 0;
+}
+
+int sageMessage::setCode(int co)
+{
+   if (code)
+      sprintf(code,"%d\0", co);
+   else {
+      std::cerr << "fail to set code" << std::endl;
+      return -1;
+   }
+   return 0;
+}
+
+int sageMessage::setAppCode(int app)
+{
+   if (appCode)
+      sprintf(appCode,"%d\0", app);
+   else {
+      std::cerr << "fail to set application code" << std::endl;
+      return -1;
+   }
+   return 0;
+}
+
+int sageMessage::setData(int sz, void* dat)
+{
+   if (sz > bufSize - MESSAGE_HEADER_SIZE) {
+      std::cout << "sage message buffer overflow" << std::endl;
+      return -1;
+   }
+   
+   bufSize = sz + MESSAGE_HEADER_SIZE;
+   
+   if (size && data) {
+      sprintf(size,"%d\0", bufSize);
+      memcpy(data, dat, sz);
+   }
+   else {
+      std::cerr << "fail to set data" << std::endl;
+      return -1;
+   }
+   return 0;
+}
+
Index: trunk/src/testing/src/sail.cpp
===================================================================
--- trunk/src/testing/src/sail.cpp	(revision 4)
+++ trunk/src/testing/src/sail.cpp	(revision 4)
@@ -0,0 +1,976 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sail.cpp - the main source of SAGE Application Interface Library
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sail.h"
+#include "envInterface.h"
+
+#if defined(WIN32)
+   #include <time.h>
+   #include <GL/gl.h>
+#else
+   #include "unistd.h"  //for getting and writing the PID to a temp file
+#endif
+
+#include "sageSync.h"
+#include "streamProtocol.h"
+#include "sageDoubleBuf.h"
+#include "sageStreamer.h"
+#include "sageBlock.h"
+
+#ifdef SAGE_AUDIO
+#include "sageAudioCircBuf.h"
+#include "sageAudioModule.h"
+#include "sageAppAudio.h"
+#endif
+
+// To detect libsail with automake/autoconf
+#ifdef __cplusplus
+extern "C" {
+   extern int findsage(char *c) { return 1; }
+}
+#endif
+
+
+sail::sail() : winID(0), bufID(0), sailOn(false), audioOn(false), sGroup(NULL), syncServerObj(NULL)
+{
+   envIntf = NULL;
+   pixelStreamer = NULL;
+   audioStreamer = NULL;
+#ifdef SAGE_AUDIO
+   audioModule = NULL;
+   audioBuffer = NULL;
+   audioAppDataHander = NULL;
+#endif
+   msgThreadID = 0;
+
+}
+
+sail::~sail()
+{
+	if (msgThreadID) {
+   	pthread_join(msgThreadID, NULL);
+	}
+
+#ifdef SAGE_AUDIO
+   if (audioStreamer) {
+      delete audioStreamer;
+      audioStreamer = NULL;
+   }
+   if(audioAppDataHander) {
+      delete audioAppDataHander;
+      audioAppDataHander = NULL;
+   }
+   if(audioModule) {
+      delete audioModule;
+      audioModule = NULL;
+   }
+#endif
+   if (msgMutex)
+      free(msgMutex);
+
+   if (notEmpty)
+      free(notEmpty);
+
+   if (envIntf) {
+      delete envIntf;
+      envIntf = NULL;
+   }
+
+   if (pixelStreamer) {
+      delete pixelStreamer;
+      pixelStreamer = NULL;
+   }
+
+   if (syncServerObj) {
+      delete syncServerObj;
+   }
+}
+
+int sail::init(sailConfig &conf)
+{
+   config = conf;
+
+   // check that winWidth and winHeight has been set, if not, it to 500,500
+   if (config.winWidth == -1 || config.winHeight == -1)
+   {
+       config.winWidth = config.resX;
+       config.winHeight = config.resY;
+   }
+
+
+   sage::initUtil();
+#ifdef WIN32
+   static int WinSockInitialized = 0;
+   WORD wVersionRequested;
+   WSADATA wsaData;
+   int err;
+
+   wVersionRequested = MAKEWORD(1, 1); // It requires Winsock version 2.
+
+   err = WSAStartup(wVersionRequested, &wsaData);
+   if (err != 0) {
+      fprintf(stderr, "Cannot load the valid winsock 2 dll. Program will be terminated.\n");
+      exit(1);
+   }
+   else {
+      fprintf(stderr, "Winsock 2 dll loaded\n");
+   }
+
+   WinSockInitialized = 1; // Winsock dll is loaded.
+#else
+   // write the PID to a temp file named: $HOME/.sageConfig/applications/pid/appName_appID.pid
+   char fileName[100];
+   memset(fileName,' ', 100);
+   char *sageDir = getenv("HOME");
+   sprintf(fileName, "%s/.sageConfig/applications/pid/%s_%d.pid", sageDir, config.appName, config.appID);
+   FILE *fp1 = fopen(fileName, "w");
+   if (!fp1) {
+      printf("failed to create a pid file %s\n", fileName);
+   }
+   else {
+      // change the permission of the file so that anybody can write/read it
+      chmod(fileName, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
+      fprintf(fp1, "%d", getpid());
+      fclose(fp1);
+   }
+   // done writing
+#endif
+
+   sailOn = true;
+   pInfo.initType(config.pixFmt);
+
+   if (config.rendering) {
+
+      // rounding error may occur...
+      if (config.totalWidth > 0 && config.totalHeight > 0) {
+         config.resX = (int)floor(config.totalWidth *
+               (config.imageMap.right - config.imageMap.left) + 0.5);
+         config.resY = (int)floor(config.totalHeight *
+               (config.imageMap.top - config.imageMap.bottom) + 0.5);
+      }
+      else {
+         config.totalWidth = (int)floor((config.resX/
+               (config.imageMap.right - config.imageMap.left) + 0.5));
+         config.totalHeight = (int)floor((config.resY/
+               (config.imageMap.top - config.imageMap.bottom) + 0.5));
+      }
+
+      config.imageMap.width = config.resX;
+      config.imageMap.height = config.resY;
+
+      // rounding error may occur...
+      config.imageMap.locate();
+   }
+
+   connectedNode = 0;
+   connectionDone = false;
+
+   frameRate = 0;
+   bandWidth = 0;
+   totalBand = 0.0;
+   perfWait = config.nodeNum;
+   reportRate = 0;
+   frameInterval = 0.0;
+
+#ifdef SAGE_AUDIO
+   int audioBuffSize = 0;
+   if(config.audioOn) {
+      switch(config.sampleFmt) {
+         case SAGE_SAMPLE_FLOAT32 :
+            config.bytesPerSample = sizeof(float);
+            break;
+         case SAGE_SAMPLE_INT16 :
+            config.bytesPerSample = sizeof(short);
+            break;
+         case SAGE_SAMPLE_INT8 :
+            config.bytesPerSample = sizeof(int);
+            break;
+         case SAGE_SAMPLE_UINT8 :
+            config.bytesPerSample = sizeof(unsigned int);
+            break;
+         default :
+            break;
+      }
+      audioBuffSize = config.framePerBuffer * config.channels * config.bytesPerSample;
+   }
+#endif
+
+   //std::cout << "SAIL buffer allocated" << std::endl;
+
+   int syncPort = config.syncPort + config.appID;
+
+   msgMutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+   pthread_mutex_init(msgMutex, NULL);
+   pthread_mutex_unlock(msgMutex);
+   notEmpty = (pthread_cond_t*)malloc(sizeof(pthread_cond_t));
+   pthread_cond_init(notEmpty, NULL);
+
+   if (config.master && config.nodeNum > 1) {
+      syncServerObj = new sageSyncServer;
+      if (syncServerObj->init(syncPort) < 0) {
+         sage::printLog("SAIL : Error init'ing the sync server object\n");
+            return -1;
+      }
+      sage::printLog("SAIL sync server created\n");
+   }
+   else
+      syncServerObj = NULL;
+
+   envIntf = new envInterface;
+   if (config.bridgeOn)
+      envIntf->init(config, config.bridgeIP, config.bridgePort);
+   else if (config.fsIP[0] != '\0' && config.fsPort > 0)
+      envIntf->init(config, config.fsIP, config.fsPort);
+   else
+      envIntf->init(config);
+
+   if (config.master) {
+      char selfIP[SAGE_IP_LEN];
+      envIntf->getSelfIP(selfIP);
+
+      waitNodes = config.nodeNum;
+      if (config.rendering) {
+         waitNodes--;
+
+         if (config.nodeNum > 1) {
+            config.syncClientObj = new sageSyncClient;
+
+            if (config.syncClientObj->connectToServer("127.0.0.1", syncPort) < 0) {
+               sage::printLog("Sail::init() : fail to connect to sync master\n");
+               return -1;
+            }
+            else
+               sage::printLog("Connected to SAIL sync master\n");
+         }
+         else
+            config.syncClientObj = NULL;
+
+         if (waitNodes < 1) {
+            char msgStr[TOKEN_LEN];
+
+            if (config.bridgeOn) {
+               int rowNum = (int)ceil((float)config.totalHeight/config.blockY);
+               int colNum = (int)ceil((float)config.totalWidth/config.blockX);
+               int blockNum = rowNum*colNum;  // total block number of this app
+               sprintf(msgStr, "%s %d %d %d %d %d %s %d %d %d %d %d",
+                  config.appName, config.winX, config.winY, config.winWidth, config.winHeight,
+                  config.protocol, config.fsIP, config.fsPort, config.totalWidth, config.totalHeight,
+                  blockNum, (int)config.audioOn);
+
+               sage::printLog("send SAIL register message to sage bridge\n");
+               sendMessage(BRIDGE_APP_REG, msgStr);
+            }
+            else {
+               double resX = config.resX/(config.imageMap.right-config.imageMap.left);
+               double resY = config.resY/(config.imageMap.top-config.imageMap.bottom);
+               double totalBandWidth = config.frameRate*resX*resY*pInfo.bytesPerPixel*8;
+               int bandWidthReq = (int)floor(totalBandWidth/1000000.0+0.5);
+
+               sprintf(msgStr, "%s %d %d %d %d %d %s %d %d %d %d %d %d %s %d",
+                  config.appName, config.winX, config.winY, config.winWidth, config.winHeight,
+                  bandWidthReq, config.streamIP, config.totalWidth, config.totalHeight,
+                  (int)config.audioOn, config.protocol, config.frameRate, config.appID,
+		  config.launcherID, config.portForwarding );
+
+               sendMessage(REG_APP, msgStr);
+            }
+
+         }
+      }
+   }
+   else {
+      if (config.nodeNum > 1) {
+         config.syncClientObj = new sageSyncClient;
+
+         if (config.syncClientObj->connectToServer(config.masterIP, syncPort) < 0) {
+            sage::printLog("Sail::init() : fail to connect to sync master\n");
+            return -1;
+         }
+         sage::printLog("Connected to SAIL sync master\n");
+      }
+      else
+         config.syncClientObj = NULL;
+
+      char msgStr[TOKEN_LEN];
+      sprintf(msgStr, "%d %d", config.totalWidth, config.totalHeight);
+      sendMessage(SAIL_SLAVE_REG, msgStr);
+   }
+
+   appMsgQueue.clear();
+
+   if (config.rendering) {
+      pixelStreamer = new sageBlockStreamer((streamerConfig &)config, pInfo.bytesPerPixel);
+
+      doubleBuf = pixelStreamer->getDoubleBuffer();
+   }
+   else {
+      if (!config.master) {
+         sage::printLog("sail::init() : incorrect configuration in rendering/master option\n");
+         return -1;
+      }
+
+      config.imageMap.left = config.imageMap.right = config.imageMap.top = config.imageMap.bottom = 0;
+      pixelStreamer = NULL;
+   }
+
+#ifdef SAGE_AUDIO
+   if(audioStreamer != NULL) {
+      delete audioStreamer;
+      audioStreamer = NULL;
+   }
+   if (config.audioOn) {
+
+      // create audio module
+      sageAudioModule::instance();
+      audioModule = sageAudioModule::_instance;
+      audioModule->init(config);
+      sageAudioCircBuf* buffer = NULL;
+      if(config.audioMode == SAGE_AUDIO_CAPTURE || config.audioMode == SAGE_AUDIO_FWCAPTURE || config.audioMode == SAGE_AUDIO_PLAY) {
+         buffer = audioModule->createObject();
+      }
+      else if(config.audioMode == SAGE_AUDIO_APP) {
+         buffer = audioModule->createBuffer();
+         audioAppDataHander = new sageAppAudio(buffer, config.audioBuffSize);
+         //audioObj->save("c.wav");   // testing...
+      }
+      else if(config.audioMode == SAGE_AUDIO_READ) {
+		  buffer = audioModule->load(config.audioFileName, true, config.framePerBuffer, config.totalFrames);   // for the test
+			sageAudioConfig* audioConfig = audioModule->getAudioConfig();
+			config.sampleFmt = audioConfig->sampleFmt;
+			config.samplingRate = audioConfig->samplingRate;
+			config.channels = audioConfig->channels;
+			config.framePerBuffer = audioConfig->framePerBuffer;
+
+         //buffer = audioObj->load(config.audioFileName, true);   // for the test
+         if(buffer != NULL) {
+            audioModule->play(0);
+         }
+      }
+
+      if(buffer != NULL) {
+         sage::printLog("audio module is created and connected to audio streamer");
+         audioBuffer = buffer;
+
+         // if audio == true,
+         // create audio streamer
+         audioStreamer = new sageAudioStreamer(config, audioBuffSize, buffer);
+         sage::printLog("audio streamer initialized");
+      }
+   }
+#endif
+
+   if (pthread_create(&msgThreadID, 0, msgThread, (void*)this) != 0) {
+      sage::printLog("SAIL : can't create msgThread\n");
+         return -1;
+   }
+
+   return 0;
+}
+
+/*
+int sail::resizeBuffer(int x, int y, int depth)
+{
+   bufSize = x * y * depth/8;
+
+   gStreamer->resize(x, y, depth);
+
+   return 0;
+}
+*/
+
+int sail::swapBuffer(int mode)
+{
+   if (!config.rendering) {
+      sage::printLog("sail::swapBuffer() : this node is not configured to stream pixels\n");
+      return -1;
+   }
+
+   if (mode == SAGE_NON_BLOCKING && !doubleBuf->isEmpty()) {
+      return 1;
+   }
+
+   /**
+      * if the streaming thread is finished. sail::swapBuffer() will block permanently.
+      * (because of semaphore operation on the double buffer b/w sail::swapBuffer() and SBS::streamLoop() )
+      * If it blocks permanently, app could never get sageMessage which causes the killing app instance issue.
+      * So, if the streaming thread is finished, then swapBuffer() should return with error.
+      
+     if ( ! pixelStreamer->isStreamerOn() ) {
+  	   fprintf(stderr,"sail::%s() : streamerOn is false\n", __FUNCTION__);
+  	   sageMessage msg;
+  	   msg.init(0, APP_QUIT, 0, 0, NULL);
+  	   pthread_mutex_lock(msgMutex);
+  	   appMsgQueue.push_front(msg);
+  	   pthread_mutex_unlock(msgMutex);
+  	   return -1;
+     }
+   */
+
+   doubleBuf->swapBuffer();
+
+#ifdef SAGE_AUDIO
+   if(audioModule)
+   {
+      audioModule->setgFrameNum(pixelStreamer->getFrameID());
+   }
+#endif
+
+   return 0;
+}
+
+void* sail::getBuffer()
+{
+   //std::cout << "pt4" << std::endl;
+   //printf("buffer address %x\n" , doubleBuf->getFrontBuffer()->getPixelBuffer());
+
+   return (void *)(doubleBuf->getFrontBuffer()->getPixelBuffer());
+}
+
+int sail::checkSyncServer()
+{
+/*
+   if (connectionDone) {
+      if (syncServerObj->checkUpdates() == 0) {
+
+         if (!pauseSync) {
+            if (syncMsgQueue.size() > 0) {
+               //sage::printLog("==== distribute stream info" << std::endl;
+               char *syncMsg = syncMsgQueue.front();
+               syncMsgQueue.pop_front();
+               masterFrameNum = syncServerObj->distributeSync(syncMsg);
+               delete [] syncMsg;
+            }
+            else
+               masterFrameNum = syncServerObj->distributeSync(NULL);
+            //std::cout << "master frame " << masterFrameNum << std::endl;
+         }
+
+      }
+   }
+*/
+   return 0;
+}
+
+int sail::sendPerformanceInfo()
+{
+   double elapsedTime = perfTimer.getTimeUS();
+
+   if (elapsedTime > 1000000.0 * reportRate && reportRate > 0) {
+      if (config.rendering) {
+         bandWidth = pixelStreamer->getBandWidth()*8.0f / elapsedTime;
+         pixelStreamer->resetBandWidth();
+      }
+
+      if (config.master) {
+         if (config.rendering) {
+            frameRate = (float) (pixelStreamer->getFrameCount() * 1000000.0 / elapsedTime);
+            pixelStreamer->resetFrameCounter();
+
+            perfWait--;
+            totalBand += bandWidth;
+
+            if (perfWait < 1) {
+               char msgStr[TOKEN_LEN];
+               sprintf(msgStr, "%7.2f %7.2f %7.2f", totalBand, frameRate, 0.0);
+               sendMessage(DISP_SAIL_PERF_RPT, msgStr);
+               totalBand = 0.0;
+               perfWait = config.nodeNum;
+            }
+         }
+      }
+      else {
+         char bandStr[TOKEN_LEN];
+         sprintf(bandStr, "%7.2f", bandWidth);
+         sendMessage(SAIL_PERF_INFO, bandStr);
+      }
+
+      perfTimer.reset();
+   }
+
+   return 0;
+}
+
+void* sail::msgThread(void *args)
+{
+   sail *This = (sail *)args;
+
+   while(This->sailOn) {
+      if (This->readMessage() < 0) {
+         This->shutdown();
+         break;
+      }
+
+      This->sendPerformanceInfo();
+
+      if (This->config.master && This->config.nodeNum > 1) {
+         This->envIntf->checkClients();
+
+         sageMessage msg;
+         for (int i = 0; i < This->envIntf->getNumClients(); i++) {
+            if (This->envIntf->readClientMsg(msg, i) > 0) {
+               if (This->parseMessage(msg) < 0) {
+                  This->shutdown();
+                  msg.destroy();
+                  break;
+               }
+               msg.destroy();
+            }
+         }
+      }
+      sage::usleep(1000);
+   }
+
+   sage::printLog("sail::msgThread : exit the message thread\n");
+   pthread_exit(NULL);
+   return NULL;
+}
+
+int sail::readMessage()
+{
+   sageMessage msg;
+
+   int status = envIntf->rcvMessage(msg);
+
+   if (status > 0) {
+      if (msg.getCode() < SAIL_MESSAGE   + 100) {
+         if (parseMessage(msg) < 0)
+            return -1;
+         msg.destroy();
+      }
+      else if (msg.getCode() < SAIL_MESSAGE + 200) {
+         if (config.master) {
+            envIntf->distributeMessage(msg);
+         }
+         if (parseMessage(msg) < 0)
+            return -1;
+         msg.destroy();
+      }
+      else if (msg.getCode() >= APP_MESSAGE) {
+//#ifdef DEBUG_KILL
+    	  fprintf(stderr,"sail::readMsg() push_back msg code %d, %s\n", msg.getCode(), (char *)msg.getData());
+//#endif
+         if (msg.getCode() == APP_QUIT) {
+            shutdown();
+         }
+         
+         pthread_mutex_lock(msgMutex);
+         appMsgQueue.push_back(msg);
+         pthread_mutex_unlock(msgMutex);
+      }
+   }
+
+   return status;
+}
+
+int sail::parseMessage(sageMessage &msg)
+{
+   char *msgData = (char *)msg.getData();
+
+   switch (msg.getCode()) {
+      case SAIL_INIT_MSG : {
+         if (msgData) {
+            sageNwConfig nwCfg;
+            sscanf(msgData, "%d %d %d %d", &winID, &nwCfg.rcvBufSize, &nwCfg.sendBufSize,
+                  &nwCfg.mtuSize);
+
+            if (config.rendering) {
+               pixelStreamer->setWinID(winID);
+               pixelStreamer->setNwConfig(nwCfg);
+            }
+
+            if (config.audioOn) {
+               if(audioStreamer)
+               {
+                  audioStreamer->setWinID(winID);
+                  audioStreamer->setNwConfig(nwCfg);
+               }
+            }
+         }
+         else {
+            sage::printLog("sail::parseMessage : SAGE_INIT_MSG is NULL\n");
+            return -1;
+         }
+
+         break;
+      }
+
+      case SAIL_SLAVE_REG : {
+         waitNodes--;
+
+         if (msgData && (config.totalWidth == 0 || config.totalHeight == 0))
+            sscanf(msgData, "%d %d", &config.totalWidth, &config.totalHeight);
+
+         if (waitNodes < 1) {
+            if (config.nodeNum > 1) {
+               sGroup = new syncGroup;
+               //std::cout << "frame rate = " << config.frameRate << std::endl;
+               sGroup->init(0, SAGE_ASAP_SYNC_HARD, 0, config.frameRate, config.nodeNum);
+               sGroup->blockSync();
+               syncServerObj->addSyncGroup(sGroup);
+            }
+
+            sage::printLog("send SAIL register message to fsManager\n");
+            char msgStr[TOKEN_LEN];
+
+            if (config.bridgeOn) {
+               int rowNum = (int)ceil((float)config.totalHeight/config.blockY);
+               int colNum = (int)ceil((float)config.totalWidth/config.blockX);
+               int blockNum = rowNum*colNum; // total block number of this app
+               sprintf(msgStr, "%s %d %d %d %d %d %s %d %d %d %d %d",
+                  config.appName, config.winX, config.winY, config.winWidth, config.winHeight,
+                  config.protocol, config.fsIP, config.fsPort, config.totalWidth,
+                  config.totalHeight, blockNum, (int)config.audioOn);
+
+               sendMessage(BRIDGE_APP_REG, msgStr);
+            }
+            else {
+               // calculate total app image resolution
+               // for NRM
+               double resX = config.resX/(config.imageMap.right-config.imageMap.left);
+               double resY = config.resY/(config.imageMap.top-config.imageMap.bottom);
+               double totalBandWidth = config.frameRate*resX*resY*pInfo.bytesPerPixel*8;
+               int bandWidthReq = (int)floor(totalBandWidth/1000000.0+0.5);
+               sprintf(msgStr, "%s %d %d %d %d %d %s %d %d %d %d %d %d %s %d",
+                  config.appName, config.winX, config.winY, config.winWidth, config.winHeight,
+                  bandWidthReq, config.streamIP, config.totalWidth, config.totalHeight,
+                  (int)config.audioOn, config.protocol, config.frameRate, config.appID,
+		  config.launcherID, config.portForwarding );
+
+               sendMessage(REG_APP, msgStr);
+            }
+         }
+         break;
+      }
+
+      case SAIL_CONNECT_TO_RCV : {
+         if (config.rendering) {
+            if (!pixelStreamer)
+               sage::printLog("sail::parseMessage : No pixelStreamer object\n");
+
+            sage::printLog("SAIL is initializing network connections for streaming\n");
+            if (pixelStreamer->initNetworks(msgData) < 0)
+               return -1;
+
+            if (config.master)
+               connectedNode++;
+         }
+
+         if (config.master) {
+            if (connectedNode == config.nodeNum) {
+               connectionDone = true;
+               sage::printLog("SAIL: Network connection Done\n");
+            }
+         }
+         else {
+            sendMessage(SAIL_CONNECTED_TO_RCV);
+         }
+
+         break;
+      }
+
+      case SAIL_CONNECT_TO_RCV_PORT : {
+         if (config.rendering) {
+            if (!pixelStreamer)
+               sage::printLog("sail::parseMessage : No pixelStreamer object\n");
+
+            sage::printLog("SAIL is initializing network connections for streaming\n");
+            if (pixelStreamer->initNetworks(msgData, true) < 0)
+               return -1;
+
+            if (config.master)
+               connectedNode++;
+         }
+
+         if (config.master) {
+            if (connectedNode == config.nodeNum) {
+               connectionDone = true;
+               sage::printLog("SAIL: Network connection Done\n");
+            }
+         }
+         else {
+            sendMessage(SAIL_CONNECTED_TO_RCV);
+         }
+
+         break;
+      }
+
+      case SAIL_CONNECT_TO_ARCV : {
+#ifdef SAGE_AUDIO
+         if (config.audioOn) {
+            if (!audioStreamer)
+               sage::printLog("sail::parseMessage : No audioStreamer object\n");
+			else {
+				sage::printLog("SAIL is initializing network connections for audio streaming\n");
+
+				audioStreamer->initNetworks(msgData);
+
+				audioStreamer->enqueMsg(msgData);
+				if(config.audioMode == SAGE_AUDIO_CAPTURE || config.audioMode == SAGE_AUDIO_PLAY) {
+				   audioModule->play(0);
+				} else if(config.audioMode ==  SAGE_AUDIO_APP && audioAppDataHander){
+					audioAppDataHander->start();
+				}
+			}
+         }
+#endif
+         break;
+      }
+      case SAIL_CONNECTED_TO_RCV : {
+         connectedNode++;
+         if (connectedNode == config.nodeNum) {
+            connectionDone = true;
+            sage::printLog("SAIL: Network connection Done\n");
+         }
+         break;
+      }
+
+      case SAIL_FLIP_WINDOW : {
+         if (config.rendering) {
+            if (config.rowOrd == BOTTOM_TO_TOP)
+               config.rowOrd = TOP_TO_BOTTOM;
+            else
+               config.rowOrd = BOTTOM_TO_TOP;
+
+            pixelStreamer->regeneratePixelBlocks();
+
+            if (doubleBuf->isFirstFrameReady() && config.asyncUpdate)
+               doubleBuf->resendBuffer(1);
+         }
+
+         break;
+      }
+
+      case SAIL_INIT_STREAM : {
+         //sage::printLog("SAIL : initialize SAGE streams");
+
+         if (config.nodeNum > 1) {
+            sGroup->enqueSyncMsg(msgData);
+            sGroup->unblockSync();
+            if (config.asyncUpdate)
+               envIntf->distributeMessage(SAIL_RESEND_FRAME);
+         }
+         else if (config.rendering) {
+            pixelStreamer->enqueMsg(msgData);
+            if (doubleBuf->isFirstFrameReady() && config.asyncUpdate)
+               doubleBuf->resendBuffer(1);
+         }
+
+         break;
+      }
+
+      case SAIL_RESEND_FRAME : {
+         if (config.rendering && doubleBuf->isFirstFrameReady() && config.asyncUpdate)
+            doubleBuf->resendBuffer(1);
+         break;
+      }
+
+      case SAIL_SHUTDOWN : {
+#ifdef DEBUG_KILL
+    	  fprintf(stderr,"sail::parseMessage() : SAIL_SHUTDOWN. will set streamerOn = false\n");
+#endif
+         shutdown();
+         break;
+      }
+
+      case SAIL_FRAME_RATE : {
+/*
+         float frate = atof(msgData);
+         if (config.master && config.nodeNum > 1)
+            sGroup->setFrameRate(frate);
+         else if (config.rendering)
+            pixelStreamer->setFrameRate(frate);
+         break;
+*/
+      }
+
+      case SAIL_PERF_INFO : {
+         double bandData = atof(msgData);
+         totalBand += bandData;
+         perfWait--;
+
+         if (perfWait < 1) {
+            char msgStr[TOKEN_LEN];
+            sprintf(msgStr, "%7.2f %5.2f %d", totalBand, frameRate, config.nodeNum);
+            sendMessage(DISP_SAIL_PERF_RPT, msgStr);
+            perfWait = config.nodeNum;
+            totalBand = 0.0;
+         }
+         break;
+      }
+
+      case SAIL_PERF_INFO_REQ : {
+         perfTimer.reset();
+         reportRate = atoi(msgData);
+         break;
+      }
+
+      case SAIL_PERF_INFO_STOP : {
+         reportRate = 0;
+         break;
+      }
+
+      case SAIL_SEND_TIME_BLOCK : {
+         if (config.rendering) {
+            //gStreamer->timeBlockFlag = true;
+         }
+         else {
+            if (config.master)
+               envIntf->msgToClient(0, SAIL_SEND_TIME_BLOCK);
+            else
+               sage::printLog("sail::parseMessage : invalid sail slave configuration\n");
+         }
+         break;
+      }
+      // sungwon experimental
+      case SAIL_SET_RAIL : {
+    	  fprintf(stderr, "sail::%s() : SAIL_SET_RAIL [%s]\n", __FUNCTION__, msgData);
+    	  static_cast<sageBlockStreamer *>(pixelStreamer)->setAffinity(msgData);
+    	  break;
+      }
+      default :
+         sage::printLog("sail::parseMessage() : sail received an invalid message \n");
+   }
+
+   return 0;
+}
+
+int sail::sendMessage(sageMessage &msg)
+{
+   return envIntf->sendMessage(msg);
+}
+
+int sail::sendMessage(int code)
+{
+   return envIntf->sendMessage(code);
+}
+
+int sail::sendMessage(int code, int data)
+{
+   return envIntf->sendMessage(code, data);
+}
+
+int sail::sendMessage(int code, char *data)
+{
+   return envIntf->sendMessage(code, data);
+}
+
+
+int sail::checkMsg(sageMessage &msg, bool blocking)
+{
+   int retVal = 0;
+   pthread_mutex_lock(msgMutex);
+   while (blocking && appMsgQueue.size() == 0)
+               pthread_cond_wait(notEmpty, msgMutex);
+
+   if (appMsgQueue.size() > 0) {
+      msg = appMsgQueue.front();
+      appMsgQueue.pop_front();
+      retVal = 1;
+   }
+
+   pthread_mutex_unlock(msgMutex);
+
+   return retVal;
+}
+
+int sail::shutdown()
+{
+   if (!sailOn)
+      return 0;
+      
+   if (config.master) {
+      if(envIntf)
+      {
+         envIntf->distributeMessage(SAIL_SHUTDOWN);
+      }
+      // inform fsManager that this app is shutting down
+      sage::printLog("Quit app\n");
+      sendMessage(NOTIFY_APP_SHUTDOWN, winID);
+   }
+
+   sailOn = false;
+
+   if (pixelStreamer) {
+      pixelStreamer->shutdown();
+   }   
+
+   return 0;
+}
+
+
+/////////////////////////////////////////
+
+/*
+int sail::generateSageBlocks()
+{
+   for (int i=0; i<2; i++) {
+      (sageRect &)sailBlock[i] = config.imageMap;
+      sailBlock[i].buffer = sailBuffer[i];
+      sailBlock[i].subWidth = config.blockX;
+      sailBlock[i].subHeight = config.blockY;
+      sailBlock[i].bytesPerPixel = bytesPerPixel;
+
+      if (config.bridgeOn && config.streamMode == 1) {
+         sailBlock[i].flag = SAGE_BUFFER_BLOCK;
+         sailBlock[i].rowOrd = config.rowOrd;
+      }
+      else {
+         sailBlock[i].flag = SAGE_PIXEL_BLOCK;
+         sailBlock[i].generatePixelBlocks(config.rowOrd);
+      }
+   }
+
+   return 0;
+}
+*/
+
+
+#ifdef SAGE_AUDIO
+int sail::pushAudioData(int size, void *buf)
+{
+   if(audioAppDataHander != NULL)
+               audioAppDataHander->swapBuffer(size, buf);
+   else
+               return -1;
+
+   return 0;
+}
+#endif
+
Index: trunk/src/testing/src/sdlSingleContext.cpp
===================================================================
--- trunk/src/testing/src/sdlSingleContext.cpp	(revision 4)
+++ trunk/src/testing/src/sdlSingleContext.cpp	(revision 4)
@@ -0,0 +1,526 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sdlSingleContext.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#if defined(GLSL_YUV)
+#if !defined(WIN32)
+#define GLEW_STATIC 1
+#endif
+#include <GL/glew.h>
+#include <GL/glu.h>
+#include <fcntl.h>
+GLhandleARB FSHandle,PHandle;
+#endif
+
+#include "sdlSingleContext.h"
+
+#if defined(GLSL_YUV)
+
+#define GLSLVertexShader   1
+#define GLSLFragmentShader 2
+
+int GLSLprintlError(char *file, int line)
+{
+   //
+   // Returns 1 if an OpenGL error occurred, 0 otherwise.
+   //
+   GLenum glErr;
+   int    retCode = 0;
+
+   glErr = glGetError();
+   while (glErr != GL_NO_ERROR)
+   {
+      fprintf(stderr, "GLSL> glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
+      retCode = 1;
+      glErr = glGetError();
+   }
+   return retCode;
+}
+
+
+//
+// Print out the information log for a shader object
+//
+static
+void GLSLprintShaderInfoLog(GLuint shader)
+{
+   int infologLength = 0;
+   int charsWritten  = 0;
+   GLchar *infoLog;
+
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+   glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLength);
+
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+   if (infologLength > 0)
+   {
+      infoLog = (GLchar *)malloc(infologLength);
+      if (infoLog == NULL)
+      {
+         fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+         exit(1);
+      }
+      glGetShaderInfoLog(shader, infologLength, &charsWritten, infoLog);
+      fprintf(stderr, "GLSL> Shader InfoLog:%s\n", infoLog);
+      free(infoLog);
+   }
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+//
+// Print out the information log for a program object
+//
+static
+void GLSLprintProgramInfoLog(GLuint program)
+{
+   int infologLength = 0;
+   int charsWritten  = 0;
+   GLchar *infoLog;
+
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+   glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infologLength);
+
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+
+   if (infologLength > 0)
+   {
+      infoLog = (GLchar *)malloc(infologLength);
+      if (infoLog == NULL)
+      {
+         fprintf(stderr, "GLSL> ERROR: Could not allocate InfoLog buffer\n");
+         exit(1);
+      }
+      glGetProgramInfoLog(program, infologLength, &charsWritten, infoLog);
+      fprintf(stderr, "GLSL> Program InfoLog:%s\n", infoLog);
+      free(infoLog);
+   }
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+}
+
+static
+int GLSLShaderSize(char *fileName, int shaderType)
+{
+   //
+   // Returns the size in bytes of the shader fileName.
+   // If an error occurred, it returns -1.
+   //
+   // File name convention:
+   //
+   // <fileName>.vert
+   // <fileName>.frag
+   //
+   int fd;
+   char name[256];
+   int count = -1;
+
+   memset(name, 0, 256);
+   strcpy(name, fileName);
+
+   switch (shaderType)
+   {
+      case GLSLVertexShader:
+         strcat(name, ".vert");
+         break;
+      case GLSLFragmentShader:
+         strcat(name, ".frag");
+         break;
+      default:
+         fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+         exit(1);
+         break;
+   }
+
+   //
+   // Open the file, seek to the end to find its length
+   //
+#ifdef WIN32
+   fd = _open(name, _O_RDONLY);
+   if (fd != -1)
+   {
+      count = _lseek(fd, 0, SEEK_END) + 1;
+      _close(fd);
+   }
+#else
+   fd = open(name, O_RDONLY);
+   if (fd != -1)
+   {
+      count = lseek(fd, 0, SEEK_END) + 1;
+      close(fd);
+   }
+#endif
+   return count;
+}
+
+static
+int GLSLreadShader(char *fileName, int shaderType, char *shaderText, int size)
+{
+   //
+   // Reads a shader from the supplied file and returns the shader in the
+   // arrays passed in. Returns 1 if successful, 0 if an error occurred.
+   // The parameter size is an upper limit of the amount of bytes to read.
+   // It is ok for it to be too big.
+   //
+   FILE *fh;
+   char name[100];
+   int count;
+
+   strcpy(name, fileName);
+
+   switch (shaderType) 
+   {
+      case GLSLVertexShader:
+         strcat(name, ".vert");
+         break;
+      case GLSLFragmentShader:
+         strcat(name, ".frag");
+         break;
+      default:
+         fprintf(stderr, "GLSL> ERROR: unknown shader file type\n");
+         exit(1);
+         break;
+   }
+
+   //
+   // Open the file
+   //
+   fh = fopen(name, "r");
+   if (!fh)
+      return -1;
+
+   //
+   // Get the shader from a file.
+   //
+   fseek(fh, 0, SEEK_SET);
+   count = (int) fread(shaderText, 1, size, fh);
+   shaderText[count] = '\0';
+
+   if (ferror(fh))
+      count = 0;
+
+   fclose(fh);
+   return count;
+}
+
+
+int GLSLreadShaderSource(char *fileName, GLchar **vertexShader, GLchar **fragmentShader)
+{
+   int vSize, fSize;
+
+   //
+   // Allocate memory to hold the source of our shaders.
+   //
+
+   fprintf(stderr, "GLSL> load shader %s\n", fileName);
+   if (vertexShader) {
+      vSize = GLSLShaderSize(fileName, GLSLVertexShader);
+
+      if (vSize == -1) {
+         fprintf(stderr, "GLSL> Cannot determine size of the vertex shader %s\n", fileName);
+         return 0;
+      }
+      
+      *vertexShader = (GLchar *) malloc(vSize);
+   
+      //
+      // Read the source code
+      //
+      if (!GLSLreadShader(fileName, GLSLVertexShader, *vertexShader, vSize)) {
+         fprintf(stderr, "GLSL> Cannot read the file %s.vert\n", fileName);
+         return 0;
+      }
+   }
+   
+   if (fragmentShader) {
+      fSize = GLSLShaderSize(fileName, GLSLFragmentShader);
+
+      if (fSize == -1) {
+         fprintf(stderr, "GLSL> Cannot determine size of the fragment shader %s\n", fileName);
+         return 0;
+      }
+
+      *fragmentShader = (GLchar *) malloc(fSize);
+
+      if (!GLSLreadShader(fileName, GLSLFragmentShader, *fragmentShader, fSize)) {
+         fprintf(stderr, "GLSL> Cannot read the file %s.frag\n", fileName);
+         return 0;
+      }
+   }
+   
+   return 1;
+}
+
+GLuint GLSLinstallShaders(const GLchar *Vertex, const GLchar *Fragment)
+{
+   GLuint VS, FS, Prog;   // handles to objects
+   GLint  vertCompiled, fragCompiled;    // status values
+   GLint  linked;
+
+   // Create a program object
+   Prog = glCreateProgram();
+   
+   // Create a vertex shader object and a fragment shader object
+   if (Vertex) {
+      VS = glCreateShader(GL_VERTEX_SHADER);
+      
+      // Load source code strings into shaders
+      glShaderSource(VS, 1, &Vertex, NULL);
+
+      // Compile the vertex shader, and print out
+      // the compiler log file.
+
+      glCompileShader(VS);
+      GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+      glGetShaderiv(VS, GL_COMPILE_STATUS, &vertCompiled);
+      GLSLprintShaderInfoLog(VS);
+
+      if (!vertCompiled)
+         return 0;
+        
+      glAttachShader(Prog, VS); 
+   }
+   
+   if (Fragment) {
+      FS = glCreateShader(GL_FRAGMENT_SHADER);
+
+      glShaderSource(FS, 1, &Fragment, NULL);
+
+      glCompileShader(FS);
+      GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+      glGetShaderiv(FS, GL_COMPILE_STATUS, &fragCompiled);
+      GLSLprintShaderInfoLog(FS);
+
+      if (!fragCompiled)
+         return 0;
+        
+      glAttachShader(Prog, FS);
+   }
+   
+   // Link the program object and print out the info log
+   glLinkProgram(Prog);
+   GLSLprintlError(__FILE__, __LINE__);  // Check for OpenGL errors
+   glGetProgramiv(Prog, GL_LINK_STATUS, &linked);
+   GLSLprintProgramInfoLog(Prog);
+
+   if (!linked)
+      return 0;
+
+   return Prog;     
+}
+
+#endif
+
+int sdlSingleContext::init(struct sageDisplayConfig &cfg)
+{
+   singleContext = true;
+   configStruct = cfg;
+
+#if defined(WIN32)
+   // Weird position with windows
+   _putenv("SDL_VIDEO_CENTERED=1");
+#endif
+
+   if ( configStruct.fullScreenFlag ) {
+      char posStr[SAGE_NAME_LEN];
+      sprintf(posStr, "SDL_VIDEO_WINDOW_POS=%d,%d",configStruct.winX, configStruct.winY);
+      putenv(posStr);
+   }   
+
+   if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+      sage::printLog("Unable to initialize SDL: %s", SDL_GetError());
+      return -1;
+   }
+
+
+   tileNum = cfg.dimX * cfg.dimY;
+   if (tileNum > MAX_TILES_PER_NODE) {
+      sage::printLog("sdlSingleContext::init() : The tile number exceeds the maximum"); 
+      return -1;
+   }
+
+   if (!winCreatFlag) {
+      Uint32 flags = SDL_OPENGL;
+      if ( configStruct.fullScreenFlag ) {
+         flags |= SDL_NOFRAME;
+         flags |= SDL_RESIZABLE;
+         //flags |= SDL_FULLSCREEN;
+      }
+      
+      window_width  = cfg.width*cfg.dimX;
+      window_height = cfg.height*cfg.dimY;
+      surface = SDL_SetVideoMode(window_width, window_height, 0, flags);
+      if (surface == NULL) {
+         sage::printLog("Unable to create OpenGL screen: %s", SDL_GetError());
+         SDL_Quit();
+         exit(2);
+      }
+      
+      SDL_WM_SetCaption("SAGE DISPLAY", NULL);
+      winCreatFlag = true;
+      
+      if ( configStruct.fullScreenFlag )
+         SDL_ShowCursor(SDL_DISABLE);
+
+      glEnable(GL_DEPTH_TEST);
+      glEnable(GL_TEXTURE_2D);
+      
+#if defined(GLSL_YUV)
+      // Initialize the "OpenGL Extension Wrangler" library
+      glewInit();
+
+      // Load the shaders
+
+      GLchar *FragmentShaderSource;
+      GLchar *VertexShaderSource;
+
+      char *sfn, *sd;
+      sfn = (char*)malloc(256);
+      memset(sfn, 0, 256);
+      sd = getenv("SAGE_DIRECTORY");
+      sprintf(sfn, "%s/bin/yuv", sd);
+
+      GLSLreadShaderSource(sfn, &VertexShaderSource, &FragmentShaderSource);
+      PHandle = GLSLinstallShaders(VertexShaderSource, FragmentShaderSource);
+
+      /* Finally, use the program. */
+      glUseProgramObjectARB(PHandle);
+
+      free(sfn);
+
+      glUseProgramObjectARB(0);
+#endif
+
+      sage::printLog("sdlSingleContext:init(): Window created");
+   }
+
+   return 0;
+} // End of sdlSingleContext::init()
+
+void sdlSingleContext::clearScreen()
+{
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void sdlSingleContext::setupViewport(int i, sageRect &tileRect)
+{
+   glViewport(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
+}
+
+void sdlSingleContext::refreshScreen()
+{
+   SDL_GL_SwapBuffers();
+}
+
+void sdlSingleContext::changeBackground(int red, int green, int blue)
+{
+   glClearColor((float)red/255.0f, (float)green/255.0f, (float)blue/255.0f, 0.0f);
+}
+
+sdlSingleContext::~sdlSingleContext()
+{
+   SDL_Quit();
+} //End of sageDisplay::~sageDisplay()
+
+
+void sdlSingleContext::checkEvent()
+{
+   // Event management with SDL
+   SDL_Event e;
+ 
+   // Service all queued events
+   while (SDL_PollEvent(&e))
+   {
+      // Handle control keys
+      if (e.type == SDL_KEYDOWN)
+      {
+         switch (e.key.keysym.sym)
+         {
+            case SDLK_ESCAPE:
+               e.type = SDL_QUIT;
+               break;
+            case SDLK_PRINT:
+               break;
+            default:
+               break;
+         }
+      }
+
+      // More events
+      switch (e.type)
+      {
+         case SDL_MOUSEMOTION:
+            break;
+         case SDL_MOUSEBUTTONDOWN:
+            break;
+         case SDL_MOUSEBUTTONUP:
+            break;
+         case SDL_JOYBUTTONDOWN:
+            break;
+         case SDL_JOYBUTTONUP:
+            break;
+         case SDL_KEYDOWN:
+            break;
+         case SDL_KEYUP:
+            break;
+         case SDL_USEREVENT:
+            break;
+         case SDL_VIDEOEXPOSE:
+            break;
+         default:
+            break;
+      }
+  
+      // Handle a clean exit.
+      if (e.type == SDL_QUIT)
+      {
+         sage::printLog("Quitting\n");
+         SDL_Quit();
+         exit(2);
+      }
+
+		//It makes flickering when you move mouse
+		//It was happended from OS: CentOS, Touch screen. 
+		//We don't need to refresh screen by mouse/keyboard event.
+		//So, refreshScreen function call is blocked
+		//-H
+      //refreshScreen();
+   }
+}
Index: trunk/src/testing/src/misc.cpp
===================================================================
--- trunk/src/testing/src/misc.cpp	(revision 4)
+++ trunk/src/testing/src/misc.cpp	(revision 4)
@@ -0,0 +1,887 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: misc.cpp - miscellaneous functions for SAGE
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include <string>
+#include "misc.h"
+#include <errno.h>
+#include <sched.h>
+#include <stdarg.h>
+
+#if defined(WIN32)
+LARGE_INTEGER perf_freq;
+LARGE_INTEGER perf_start;
+HANDLE win_err; // stderr in a console
+#elif defined(__APPLE__)
+#include <mach/mach_time.h>
+static double perf_conversion = 0.0;
+static uint64_t perf_start;
+#else
+struct timeval tv_start;
+#endif
+
+#if defined(WIN32)
+#include <sys/timeb.h>
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+int
+gettimeofday(struct timeval *tp, void *tzp)
+{
+    struct _timeb t;
+
+    _ftime(&t);
+    tp->tv_sec = t.time;
+    tp->tv_usec = t.millitm * 1000;
+    return 0;
+}
+#endif
+
+int getToken(char *str, char *token)
+{
+   char seps[] = " ,\t\r\n";
+   static char token_buf[MAX_TOKENS][TOKEN_LEN];
+   static int token_num = 0;
+   static int token_idx = 0;
+   char *p_token;
+
+   if (token_num > 0) {
+      strcpy(token, token_buf[token_idx]);
+      token_num--;
+      token_idx++;
+   }   
+   else {
+      if ( (p_token = strtok(str, seps)) )
+         strcpy(token, p_token);
+      else {
+         token[0] = '\0';
+         return 0;
+      }
+
+      while(p_token = strtok(NULL, seps)) { 
+         strcpy(token_buf[token_num], p_token);
+         token_num++;
+         if (token_num > MAX_TOKENS) {
+            std::cout << "SAGE getToken : token num overflow" << std::endl;
+            _exit(0);
+         }   
+      }   
+      token_idx = 0;
+   }
+
+   return token_num;
+}
+
+int getToken(char *str, char *token, char **buf)
+{
+   char seps[] = " ,\t\r\n";
+   char *p_token;
+
+   if ( (p_token = strtok_r(str, seps, buf)) )
+      strcpy(token, p_token);
+   else {
+      token[0] = '\0';
+      return 0;
+   }
+
+   return strlen(token);
+}
+
+int getToken(FILE *fp, char *token)
+{
+   char seps[] = " ,\t\r\n{}()";
+   int token_idx = 0;
+
+   int curChar;
+   bool flag = true;
+   
+   while(token_idx == 0 && flag) {       
+      curChar = fgetc(fp);
+      while(curChar != EOF && !strchr(seps, curChar)) {
+         token[token_idx] = curChar;
+         token_idx++;
+         curChar = fgetc(fp);
+      }
+      
+      if (curChar == EOF)
+         flag = false;
+         
+      if (strchr("{}()", curChar)) {
+         if (token_idx == 0) {
+            token[token_idx] = curChar;
+            token_idx++;
+         }
+         else {
+            fseek(fp, -1, SEEK_CUR);
+         }   
+      }
+   }   
+
+   if (flag == false && token_idx == 0)
+      return EOF;   
+   
+   token[token_idx] = '\0';
+   return token_idx;
+}
+
+char* sage::tokenSeek(char *buf, int tnum)
+{
+   if (!buf) {
+      sage::printLog("sage::tokenSeek : buffer is null");
+      return NULL;
+   }
+
+   char seps[] = " ,\t\r\n{}()";      
+   int strLen = strlen(buf);
+   int tokenCnt = 0;
+   bool tokenStart = false;
+   
+   for (int i=0; i<strLen; i++) {
+      if (!strchr(seps, buf[i])) {
+         tokenStart = true;
+         if (tokenCnt == tnum)
+            return buf+i;
+      }
+      else {
+         if (tokenStart)
+            tokenCnt++;
+         tokenStart = false;
+      }
+   }
+   
+   return NULL;
+}
+
+void sage::initUtil()
+{
+#if defined(WIN32)
+	QueryPerformanceCounter(&perf_start);
+	QueryPerformanceFrequency(&perf_freq);
+	AllocConsole();
+	win_err =  GetStdHandle(STD_ERROR_HANDLE);
+#elif defined(__APPLE__)
+	if ( perf_conversion == 0.0 ) {
+		mach_timebase_info_data_t info;
+		kern_return_t err = mach_timebase_info( &info );
+
+		//Convert the timebase into seconds
+		if( err == 0  )
+			perf_conversion = 1e-9 * (double) info.numer / (double) info.denom;
+	}
+	// Start of time
+	perf_start = mach_absolute_time();
+
+	// Initialize the random generator
+	srand(getpid());
+#else
+	// Start of time
+	gettimeofday(&tv_start,0);
+	// Initialize the random generator
+	srand(getpid());
+#endif
+}
+
+double sage::getTime() 
+{
+   double timeStamp;
+
+#if defined(WIN32)
+   LARGE_INTEGER perf_counter;
+#else
+   struct timeval tv;
+#endif
+
+#if defined(WIN32)
+   // Windows: get performance counter and subtract starting mark
+	QueryPerformanceCounter(&perf_counter);
+	timeStamp = (double)(perf_counter.QuadPart-perf_start.QuadPart)*1000000.0/(double)perf_freq.QuadPart;
+#elif defined(__APPLE__)
+   uint64_t difference = mach_absolute_time() - perf_start;
+   timeStamp = perf_conversion*(double)difference*1000000.0;
+#else
+   // UNIX: gettimeofday
+	gettimeofday(&tv, NULL);
+	timeStamp = (double)(tv.tv_sec-tv_start.tv_sec)*1000000.0+(double)(tv.tv_usec-tv_start.tv_usec);
+#endif
+
+   return timeStamp;
+}
+
+
+
+int sage::condition_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, 
+                        time_t miliSec)
+{
+   struct timespec abstime;
+   timeval t;
+   gettimeofday(&t, NULL);   
+   abstime.tv_sec = (long)t.tv_sec;
+   abstime.tv_nsec = t.tv_usec*1000 + miliSec*1000000;
+
+   if (pthread_cond_timedwait(cond, mutex, &abstime) == ETIMEDOUT)
+      return SAGE_TIMEOUT;
+
+   return 0;
+}
+
+void sageTimer::reset()
+{
+   startTime = sage::getTime();
+   accumulatedTime = 0.0;
+   paused = false;
+}
+
+void sageTimer::pausedReset()
+{
+   startTime = sage::getTime();
+   accumulatedTime = 0.0;
+   paused = true;
+}
+
+void sageTimer::pause()
+{
+   if (!paused)
+      accumulatedTime += sage::getTime() - startTime;
+   paused = true;
+}
+
+void sageTimer::resume()
+{
+   startTime = sage::getTime();
+   paused = false;
+}
+
+double sageTimer::getTimeUS(bool resetFlag)
+{
+   double curTime = sage::getTime();
+   double time_diff = 0.0;
+   if (!paused)
+      time_diff = curTime - startTime;
+   
+   double diff_us = time_diff + accumulatedTime;
+   
+   if (resetFlag) {
+      startTime = curTime;
+      accumulatedTime = 0.0;
+      paused = false;
+   }
+      
+   return diff_us;
+}
+
+double sageTimer::getTimeSec()
+{
+   double time_diff = 0.0;
+   if (!paused)
+      time_diff = sage::getTime() - startTime;
+   
+   double elapsed = (time_diff + accumulatedTime)/1000000.0;
+   
+   return elapsed;
+}
+
+void sage::usleep(unsigned long usec)
+{
+#ifdef WIN32
+   if (usec <= 1000) 
+      ::Sleep(1);
+   else
+      ::Sleep((int)(usec/1000));
+#else
+   ::usleep(usec);
+#endif
+}
+
+unsigned int sage::sleep(unsigned int seconds)
+{
+#ifdef WIN32
+   ::Sleep(seconds);
+   return seconds;
+#else   
+   return ::sleep(seconds);
+#endif
+}
+
+void sage::switchThread()
+{
+#if defined(linux) || defined(__APPLE__)
+   sched_yield();
+#endif
+ 
+#ifdef WIN32
+   SwitchToThread();
+#endif   
+}
+
+int getMax2n(int val)
+{
+   int pow = 1;
+   float root = (float)val;
+   
+   while (root > 1) {
+      root /= 2.0;
+      pow *= 2;
+   }
+   
+   return pow;
+}
+
+int getPixelSize(sagePixFmt type)
+{
+   int bytesPerPixel = 0;
+   
+   switch(type) {
+      case PIXFMT_555:
+      case PIXFMT_555_INV:
+      case PIXFMT_565:
+      case PIXFMT_565_INV:
+      case PIXFMT_YUV:
+         bytesPerPixel = 2;
+         break;
+      case PIXFMT_888:
+      case PIXFMT_888_INV:
+         bytesPerPixel = 3;
+         break;
+
+      case PIXFMT_8888:
+      case PIXFMT_8888_INV:
+         bytesPerPixel = 4;
+         break;
+      
+      case PIXFMT_DXT:
+         bytesPerPixel = 8;
+         break;      
+      
+      default:
+         bytesPerPixel = 3;
+         break;
+   }
+   
+   return bytesPerPixel;         
+}   
+
+sageToken::sageToken(char *str)
+{
+   strLen = strlen(str);
+   tokenBuf = new char[strLen+1];
+   idx = 0;
+   
+   strcpy(tokenBuf, str);
+}
+
+sageToken::sageToken(int len)
+{
+   tokenBuf = new char[len+1];
+   idx = 0;
+}
+
+sageToken::~sageToken()
+{
+   if (tokenBuf)
+      delete [] tokenBuf;
+}
+
+int sageToken::getToken(char *token)
+{
+   char seps[] = " ,\t\r\n\0";
+   int tokenIdx = 0;
+   int i;
+   
+   for (i=idx; i<strLen; i++) {
+      char curChar = tokenBuf[i];
+      if (!strchr(seps, curChar)) {
+         token[tokenIdx] = curChar;
+         tokenIdx++;
+      }
+      else if (tokenIdx > 0) {
+         break;
+      }
+   }   
+
+   idx = i;
+   token[tokenIdx] = '\0';
+   
+   return strLen-idx;
+}
+
+int sageToken::putToken(char *token)
+{
+   char *tokenPt = tokenBuf + idx;
+   sprintf(tokenPt, "%s ", token);
+   idx = strlen(tokenBuf);
+   
+   return idx;
+}
+
+int sage::toupper(char *str)
+{
+   int len = strlen(str);
+   
+   for (int i=0; i<len; i++) {
+      str[i] = ::toupper(str[i]);   
+   }
+   
+   return 0;
+}   
+
+int sage::tolower(char *str)
+{
+   int len = strlen(str);
+   
+   for (int i=0; i<len; i++) {
+      str[i] = ::tolower(str[i]);   
+   }
+   
+   return 0;
+}   
+
+bool sage::isDataReady(int sockFd, int sec, int usec)
+{
+   fd_set readFds;
+
+   FD_ZERO(&readFds);
+   FD_SET(sockFd, &readFds);
+
+   struct timeval timeOut;
+   timeOut.tv_sec = sec;
+   timeOut.tv_usec = usec;
+
+   int ready_fd = select(sockFd+1, &readFds, NULL, NULL, &timeOut);
+   if (ready_fd <= 0 || !FD_ISSET(sockFd, &readFds))
+      return false;
+   else
+      return true;   
+}
+
+int sage::send(int fd, void *buf, int len)   // on both platforms. 
+{
+   if (!buf) {
+      sage::printLog("sage::send() - data buffer is null");
+      return -1;
+   }
+   else if (fd < 0) {
+      sage::printLog("sage::send() - invalid file descriptor: %d", fd);
+      return -1;
+   }
+   else if (len <= 0) {
+      sage::printLog("sage::send() - message length should be larger then zero");
+      return -1;
+   }
+
+   int bytesSent = 0;
+   int bytes = len;
+   int actualSend = 0;
+   char *buffer = NULL;
+   
+   while (bytesSent < len) { 
+      buffer = ((char *)buf) + bytesSent;
+#if defined(WIN32)
+      actualSend = ::send(fd, (char *)buffer, bytes, 0); 
+#else
+      actualSend = ::send(fd, (void *)buffer, bytes, 0); 
+#endif
+      if (actualSend < 0) {
+         sage::printLog("sage::send() - error in send() system call");
+         sage::printLog("=== sent data: %d bytes, remaining %d bytes", bytesSent, bytes);
+         return -1;
+      }
+      else if (actualSend == 0) {
+         sage::printLog("sage::send() : connection shutdown");
+         return 0;
+      }
+
+      bytesSent += actualSend;
+      bytes = len - bytesSent;
+   }   
+
+   return bytesSent;
+} // end of sage::send()
+
+int sage::recv(int fd, void *buf, int len, int flags)
+{
+   int bytesRead = 0;
+   int bytes = len;
+   int actualRead = 0;
+
+   while (bytesRead < len) {
+      char *buffer = (char *)buf + bytesRead;
+#if defined(WIN32)
+      actualRead = ::recv(fd, (char *)buffer, bytes, flags);
+#else
+      actualRead = ::recv(fd, (void *)buffer, bytes, flags);
+#endif
+      if (actualRead < 0) {
+         sage::printLog("sage::recv() - error in recv() system call");
+         sage::printLog("=== received data: %d bytes, remaining %d bytes", bytesRead, bytes);
+         return -1;
+      }
+      else if (actualRead == 0) {
+         sage::printLog("sage::recv() : connection shutdown");
+         return 0;
+      }
+      
+      if ((flags|MSG_PEEK) && actualRead < len)
+         bytesRead = 0;
+      else {
+         bytesRead += actualRead;
+         bytes = len - bytesRead;
+      }   
+   }
+   
+   return bytesRead;
+} // end of sage::recv()
+
+void sage::printLog(const char *format,...)
+{
+	va_list vl;
+	char line[2048];
+
+	va_start(vl,format);
+	vsprintf(line,format,vl);
+	va_end(vl);
+
+#if defined(WIN32)
+	unsigned long res;
+	WriteFile(win_err, line, strlen(line), &res, NULL);
+#endif
+	fprintf(stderr,"%s\n",line);
+	fflush(stderr);
+}
+
+void sage::transformFrameNum(int blockFrame, int &curFrame)
+{
+   int dev = blockFrame - (curFrame%10000);
+   if (dev > 0)
+      curFrame += dev;
+   else if (dev < -9000) 
+      curFrame += (dev + 10000);
+}
+
+int execRemBin(char *ip, char *com, char *xid) 
+{
+   char sshCmd[SAGE_CMD_LEN];
+
+   if (xid) 
+      sprintf(sshCmd, "/usr/bin/ssh -fx %s \"env DISPLAY=:%s %s \" ", ip, xid, com);
+   else
+      sprintf(sshCmd, "/usr/bin/ssh -fx %s \"env DISPLAY=:0.0 %s \" ", ip, com);
+
+   // Launch the process
+   system(sshCmd);
+
+   std::cout << " sshCmd = " << sshCmd << std::endl;
+   std::cout << std::endl;
+   
+   return 0;   
+}
+
+#if defined(WIN32)
+void sage::win32Init()
+{
+   // Initialize Winsock
+   WSADATA wsaData;
+   WSAStartup(MAKEWORD(2,2), &wsaData);
+}
+#endif
+
+
+// Function from Stuart Levy, NCSA
+// Reads a string with a unit, K or M
+long getnumber( char *str )
+{
+    char *ep;
+    long v = strtoul( str, &ep, 0 );
+    switch(*ep) {        
+        case '\0': case '/': return v;
+        case 'k': case 'K': return v << 10;
+        case 'm': case 'M': return v << 20;
+        default:
+            fprintf(stderr, "expected a number (with optional 'k'/'m' suffix), not \"%s\"\n", str);
+            exit(1);
+    }
+}
+
+int sageIndexTable::generateTable()
+{
+   int entrySize = entries.size();
+   if (entrySize < 1) {
+      sage::printLog("sageIndexTable::generateTable : no table entry");
+      return -1;
+   }
+      
+   minID = entries[0];
+   maxID = entries[0];
+   for (int i=0; i<entrySize; i++) {
+      minID = MIN(minID, entries[i]);
+      maxID = MAX(maxID, entries[i]);
+   }
+      
+   int size = maxID - minID + 1;
+   if (size > 0) {
+      table = new int[size];
+      for (int i=0; i<size; i++)
+         table[i] = -1;
+      for (int i=0; i<entrySize; i++)
+         table[entries[i]-minID] = i;   
+   }      
+   else {
+      table = NULL;
+      sage::printLog("sageIndexTable::generateTable : invalid table size");
+      return -1;
+   }
+      
+   return 0;   
+}
+
+int sageIndexTable::setTable(int id, int index)
+{
+   if (id > maxID || id < minID) {
+      sage::printLog("sageIndexTable::setIndex : ID is out of range");
+      return -1;
+   }
+   
+   table[id-minID] = index;
+   
+   return 0;   
+}
+
+int sageIndexTable::getIndex(int id)
+{
+   if (id > maxID || id < minID) {
+      sage::printLog("sageIndexTable::getIndex : ID is out of range");
+      return -1;
+   }   
+   
+   return table[id-minID];
+}
+
+int sageIndexTable::getID(int idx)
+{
+   if (idx >= entries.size() || idx < 0) {
+      sage::printLog("sageIndexTable::getID : Index is out of range");
+      return -1;
+   }
+   
+   return entries[idx];
+}
+
+sageIndexTable::~sageIndexTable() 
+{ 
+   if (table)
+      delete [] table;
+      
+   entries.clear();    
+}
+
+
+
+// Inspired by Nvidia toolkit
+
+using namespace std;
+
+data_path::data_path(std::string subdir)
+{
+    char *sageDir = getenv("SAGE_DIRECTORY");
+	if (!sageDir) {
+		sage::printLog("data_path: cannot find the environment variable SAGE_DIRECTORY");
+	}
+    std::string sagedir = std::string( sageDir ) + "/sageConfig/" + subdir;
+    // First search in current directory
+    path.push_back( "." );
+#if !defined(WIN32)
+	std::string homedir = std::string( getenv("HOME") ) + std::string("/.sageConfig/") + subdir;
+    // Then search in ~/.sageConfig/ directory
+    path.push_back( homedir );
+#endif
+    // Finally search in SAGE_DIRECTORY/sageConfig directory
+    path.push_back( sagedir );
+}
+
+
+string data_path::get_path(std::string filename)
+{
+  FILE* fp;
+  bool found = false;
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+	  break;
+        }
+    }
+
+  if (found == false)
+    {
+      path_name = filename;
+      fp = ::fopen(path_name.c_str(),"r");
+      if (fp != 0)
+        {
+	  fclose(fp);
+	  found = true;
+        }
+    }
+
+  if (found == false)
+    return "";
+
+  int loc = path_name.rfind('\\');
+  if (loc == -1)
+    {
+      loc = path_name.rfind('/');
+    }
+
+  if (loc != -1)
+    file_path = path_name.substr(0, loc);
+  else
+    file_path = ".";
+  return file_path;
+}
+
+string data_path::get_file(std::string filename)
+{
+  FILE* fp;
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      path_name = path[i] + "/" + filename;
+      fp = ::fopen(path_name.c_str(), "r");
+
+      if(fp != 0)
+        {
+	  fclose(fp);
+	  return path_name;
+        }
+    }
+
+  path_name = filename;
+  fp = ::fopen(path_name.c_str(),"r");
+  if (fp != 0)
+    {
+      fclose(fp);
+      return path_name;
+    }
+  return "";
+}
+
+// Print the list of directories
+void data_path::print()
+{
+  std::cout << "---------------------" << std::endl;
+  std::cout << "File search list:" << std::endl;
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::cout << "\t" << path[i] << std::endl;
+    }
+  std::cout << "---------------------" << std::endl;
+}
+
+
+// data files, for read only
+FILE * data_path::fopen(std::string filename, const char * mode)
+{
+
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+      FILE * fp = ::fopen(s.c_str(), mode);
+
+      if(fp != 0)
+	return fp;
+      else if (!strcmp(path[i].c_str(),""))
+	{
+	  FILE* fp = ::fopen(filename.c_str(),mode);
+	  if (fp != 0)
+	    return fp;
+	}
+    }
+  // no luck... return null
+  return 0;
+}
+
+//  fill the file stats structure
+//  useful to get the file size and stuff
+int data_path::fstat(std::string filename,
+#ifdef WIN32
+		     struct _stat
+#else
+		     struct stat
+#endif
+		     * stat)
+{
+  for(unsigned int i=0; i < path.size(); i++)
+    {
+      std::string s = path[i] + "/" + filename;
+#ifdef WIN32
+      int fh = ::_open(s.c_str(), _O_RDONLY);
+#else
+      int fh = ::open(s.c_str(), O_RDONLY);
+#endif
+      if(fh >= 0)
+        {
+#ifdef WIN32
+	  int result = ::_fstat( fh, stat );
+#else
+	  int result = ::fstat (fh,stat);
+#endif
+	  if( result != 0 )
+            {
+	      fprintf( stderr, "An fstat error occurred.\n" );
+	      return 0;
+            }
+#ifdef WIN32
+	  ::_close( fh );
+#else
+	  ::close (fh);
+#endif
+	  return 1;
+    	}
+    }
+  // no luck...
+  return 0;
+}
+
+
Index: trunk/src/testing/src/Makefile
===================================================================
--- trunk/src/testing/src/Makefile	(revision 4)
+++ trunk/src/testing/src/Makefile	(revision 4)
@@ -0,0 +1,145 @@
+#
+#	Makefile for sage
+#	
+
+include ../config.mk
+
+# SAGE global revision number from SVN
+SAGE_REVISION := -DSAGE_REVISION=$(shell svnversion -n ..)
+
+
+QUANTA_DIR=../QUANTA
+QUANTA_CFLAGS=-I${QUANTA_DIR}/include
+QUANTA_LDFLAGS=-L../lib -lquanta
+
+MYFLAGS=${SAGE_CFLAGS} -O3 -I../include $(SDL_CFLAGS) $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS) $(SUN_INCLUDE) ${SAGE_REVISION}
+#-DDEBUG_RECEIVER
+#-DBRIDGE_DEBUG_
+
+ifdef AUDIO
+LIBS=-L../lib $(PAUDIO_LIB) $(SDL_LIBS) $(XLIBS) -lpthread -lm -ldl $(QUANTA_LDFLAGS) $(GLEW_LIB) $(SUN_LIBS) $(SAGE_LDFLAGS)
+else
+LIBS=-L../lib $(SDL_LIBS) $(XLIBS) -lpthread -lm -ldl -lpng $(QUANTA_LDFLAGS) $(GLEW_LIB) $(SUN_LIBS) $(SAGE_LDFLAGS)
+endif
+
+
+COMMON_OBJ= misc.o sageMessage.o sageRect.o streamInfo.o sageBlock.o sageBuf.o sageBlockPool.o sageFrame.o sageBlockPartition.o
+
+FSM_OBJ=fsManager.o fsServer.o fsCore.o sageVirtualDesktop.o \
+	tileConfig.o displayInstance.o fsMain.o
+
+RCV_OBJ=sageDisplayManager.o fsClient.o sageSync.o sageDisplay.o pixelDownloader.o \
+	streamProtocol.o sageTcpModule.o sageUdpModule.o sageReceiver.o \
+	sageDraw.o sageDrawObject.o overlayPointer.o overlayApp.o overlayWall.o sageBlockQueue.o \
+	sageSharedData.o sageEvent.o sdlSingleContext.o
+ifeq ($(MACHINE), Darwin)
+RCV_OBJ+=appleMultiContext.o
+endif
+
+
+ifeq ($(MACHINE), Darwin)
+RCV_OBJ += SDLMain.o
+endif
+
+
+ifdef AUDIO
+ARCV_OBJ=sageAudioManager.o fsClient.o sageSync.o sageEvent.o \
+	sageReceiver.o sageAudioReceiver.o sageBlockQueue.o \
+	streamProtocol.o sageTcpModule.o sageUdpModule.o \
+        sageAudioCircBuf.o sageAudio.o sageAudioModule.o sageAudioSync.o \
+	audioFileReader.o audioFileWriter.o audioFormatManager.o \
+	audioConverter.o wavConverter.o
+endif
+
+BRIDGE_OBJ=sageBridge.o sageAudioBridge.o messageInterface.o sageSync.o \
+	streamProtocol.o sageTcpModule.o sageUdpModule.o sageSharedData.o \
+	appInstance.o sageStreamer.o bridgeStreamer.o sageBlockQueue.o \
+	sageEvent.o sageConfig.o sageReceiver.o sageDoubleBuf.o
+
+ifdef AUDIO
+SAIL_OBJ= sail.o envInterface.o fsClient.o sageSync.o \
+	streamProtocol.o sageTcpModule.o sageUdpModule.o \
+	sageDoubleBuf.o sageConfig.o sageStreamer.o sageBlockStreamer.o \
+	sageAudioCircBuf.o sageAudio.o sageAudioModule.o sageAudioSync.o \
+	audioFileReader.o audioFileWriter.o audioFormatManager.o sageAppAudio.o \
+	audioConverter.o wavConverter.o sageAudioStreamer.o
+else
+SAIL_OBJ= sail.o envInterface.o fsClient.o sageSync.o \
+	streamProtocol.o sageTcpModule.o sageUdpModule.o \
+	sageDoubleBuf.o sageConfig.o sageStreamer.o sageBlockStreamer.o
+
+endif
+
+
+DIRT= *.o core core.* *.so $(PROJ_EXE)
+
+ifndef SAIL_ONLY
+ifdef AUDIO
+PROJ_EXE=fsManager sageDisplayManager sageAudioManager uiConsole sageBridge bridgeConsole $(FS_CONSOLE) 
+else
+PROJ_EXE=fsManager sageDisplayManager uiConsole sageBridge bridgeConsole $(FS_CONSOLE)
+endif
+endif
+
+build: $(PROJ_EXE) $(SAIL_LIB)
+
+install: build
+	cp $(SAIL_LIB) ../lib
+	for i in $(PROJ_EXE); do cp -f $$i ../bin/; done
+ifeq ($(MACHINE), Darwin)
+	/bin/rm -fr ../bin/sageDisplayManager.app
+	/bin/cp -fr sageDisplayManager.app ../bin
+endif
+
+
+clean:
+	rm -f $(DIRT)
+	cd ../bin; rm -f $(PROJ_EXE)
+	cd ../lib; rm -f $(SAIL_LIB); cd ../src
+
+SDLMain.o: SDLMain.m
+	$(COMPILER) $(SAGE_LDFLAGS) -m32 -c SDLMain.m
+
+fsManager: $(COMMON_OBJ) $(FSM_OBJ)
+	$(COMPILER) ${MYFLAGS} $(COMMON_OBJ) $(FSM_OBJ) $(LIBS) -o fsManager
+
+
+sageDisplayManager: $(COMMON_OBJ) $(RCV_OBJ)
+	$(COMPILER) $(MYFLAGS) $(COMMON_OBJ) $(RCV_OBJ) $(LIBS) -o sageDisplayManager
+ifeq ($(MACHINE), Darwin)
+	/bin/rm -fr sageDisplayManager.app
+	mkdir -p sageDisplayManager.app/Contents/MacOS
+	mkdir -p sageDisplayManager.app/Contents/Resources
+	echo "APPL????" > sageDisplayManager.app/Contents/PkgInfo
+	install sageDisplayManager sageDisplayManager.app/Contents/MacOS/
+	install Info.plist sageDisplayManager.app/Contents/
+	touch sageDisplayManager.app/Contents/Resources/empty.lproj
+endif
+
+
+ifdef AUDIO
+sageAudioManager: $(COMMON_OBJ) $(ARCV_OBJ)
+	$(COMPILER) $(MYFLAGS) $(COMMON_OBJ) $(ARCV_OBJ) $(LIBS) -o sageAudioManager
+endif
+
+sageBridge: $(COMMON_OBJ) $(BRIDGE_OBJ)
+	$(COMPILER) $(MYFLAGS) $(COMMON_OBJ) $(BRIDGE_OBJ) $(LIBS) -o sageBridge
+
+uiConsole: uiConsole.o fsClient.o suil.o sageMessage.o misc.o 
+	$(COMPILER) ${SAGE_CFLAGS} uiConsole.o fsClient.o suil.o sageMessage.o misc.o $(LIBS) -o uiConsole
+
+bridgeConsole: bridgeConsole.o messageInterface.o sageMessage.o misc.o 
+	$(COMPILER) ${SAGE_CFLAGS} bridgeConsole.o messageInterface.o sageMessage.o misc.o $(LIBS) -o bridgeConsole
+
+fsConsole: fsConsole.o fsClient.o suil.o  sageMessage.o misc.o
+	$(COMPILER) ${SAGE_CFLAGS} fsConsole.o fsClient.o suil.o sageMessage.o misc.o $(LIBS) $(READLINE_LIB) -o fsConsole
+
+$(SAIL_LIB): $(COMMON_OBJ) $(SAIL_OBJ)
+	$(COMPILER) $(SHLD_FLAGS) $(COMMON_OBJ) $(SAIL_OBJ) $(LIBS) -o $(SAIL_LIB)
+
+.cpp.o :
+	$(COMPILER) $(MYFLAGS) -c -o $@ $<
+
+fsConsole.o: fsConsole.cpp
+	$(COMPILER) $(MYFLAGS) $(READLINE_CFLAGS) -c fsConsole.cpp
+
Index: trunk/src/testing/src/sageAudioSync.cpp
===================================================================
--- trunk/src/testing/src/sageAudioSync.cpp	(revision 4)
+++ trunk/src/testing/src/sageAudioSync.cpp	(revision 4)
@@ -0,0 +1,579 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageAudioSync.cpp - This file contains the class which provides the syncing
+ *            mechanism.
+ * Author : Hyejung Hur
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "sageAudioSync.h"
+
+sageAudioSync::sageAudioSync(bool audioRecv) :
+   m_audioReceiver(audioRecv), m_connectedDone(false),
+   m_recvPort(-1), m_sendPort(-1) 
+{
+}
+
+sageAudioSync::~sageAudioSync()
+{
+   closeAll();
+   
+   sageSyncInfo* info;
+   // clear memory
+   std::vector<sageSyncInfo*>::iterator iter;
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      delete info;
+      info = NULL;
+   }
+   m_syncInfoList.clear();
+}
+
+int sageAudioSync::init(int port)
+{
+   // connect networking....
+   m_recvPort = port;
+   m_sendPort = port+1;
+   if(m_audioReceiver) {
+      m_recvPort = port +1;
+      m_sendPort = port;
+   }
+    
+   if(initListener(m_recvPort) < 0) {
+      return -1;
+   }
+   
+   return 0;
+}
+
+int sageAudioSync::connect(char* ip)
+{
+   if(initSender(ip, m_sendPort) < 0) {
+      return -1;
+   }
+   return 0;
+}
+   
+void sageAudioSync::registerBuffer(sageAudioSyncType type, int sourceId, int bufferId, int keyframeNum)
+{
+   sageSyncInfo* info = new sageSyncInfo();
+   info->m_sourceId = sourceId;
+   info->m_bufferId = bufferId;
+   info->m_keyframeNum = keyframeNum;
+   info->m_syncType = type;
+   m_syncInfoList.push_back(info);
+   
+   // for testing
+   if(info->m_syncType == SAGE_SYNC_AUDIO_DRIVEN) {
+      if(m_audioReceiver) {
+         std::cout << "SAGE_SYNC_AUDIO_DRIVEN : audio " << std::endl;
+      } else {
+         std::cout << "SAGE_SYNC_AUDIO_DRIVEN : graphic " << std::endl;      
+      }
+   } else if(info->m_syncType == SAGE_SYNC_GRAPHIC_DRIVEN) {
+      if(m_audioReceiver) {
+         std::cout << "SAGE_SYNC_GRAPHIC_DRIVEN : audio " << std::endl;      
+      } else {
+         std::cout << "SAGE_SYNC_GRAPHIC_DRIVEN : graphic " << std::endl;   
+      }
+   }
+      
+}
+
+int sageAudioSync::removeBuffer(int bufferId)
+{
+   sageSyncInfo* info;
+   std::vector<sageSyncInfo*>::iterator iter;
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      if(info->m_bufferId == bufferId) {
+         m_syncInfoList.erase(iter);
+         delete info;
+         info = NULL;
+         return 0;
+      }
+   }
+   return -1;   
+}
+
+bool sageAudioSync::checkKeyFrame(int bufferId, int frameNum)
+{
+   bool found = false;
+   sageSyncInfo* info;
+   std::vector<sageSyncInfo*>::iterator iter;
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      if(info->m_bufferId == bufferId) {
+         found = true;
+         break;
+      }
+   }
+   
+   if(found) {
+      if(info->m_passNum == frameNum) return false;
+      // i am not sure.. it can make bug...
+      if(info->m_passNum > frameNum) {
+         int diff = info->m_passNum - frameNum;
+         if(diff  < info->m_keyframeNum) return false;
+      }
+      if((frameNum > (9999 - info->m_keyframeNum)) && (info->m_passNum < info->m_keyframeNum)) {
+         return false;
+      } 
+      
+
+      if(info->m_syncType == SAGE_SYNC_NONE) return false;
+      int result = frameNum % (info->m_keyframeNum);
+      int gap = (info->m_passNum / info->m_keyframeNum) - (frameNum / info->m_keyframeNum);
+      if((result == 0) || (gap != 0)) {
+         //std::cout << "1 past: " << info->m_passNum << " 2 keyframe: " << info->m_keyframeNum << " 3 framenum: " << frameNum << std::endl;
+         info->m_passNum = frameNum;
+         info->m_lockFlag = true;
+         doKeyFrameAction(info);
+         return true;   // then buffer will set lock
+      }
+   }
+   
+   return false;
+}
+
+void sageAudioSync::doKeyFrameAction(sageSyncInfo* info)
+{
+   if(info->m_syncType == SAGE_SYNC_AUDIO_DRIVEN) {
+      if(m_audioReceiver) {
+         // send signal to gStreamRcv
+         /** need to check */
+         sendSignal(info);
+      } else {
+         // send signal to aStreamRcv 
+         /** need to check */
+         sendSignal(info);
+      }
+   } else if(info->m_syncType == SAGE_SYNC_GRAPHIC_DRIVEN) {
+      if(m_audioReceiver) {
+         // nothing to do -> just return true;
+      } else {
+         // send signal to aStreamRcv 
+         sendSignal(info);
+      }
+   }
+}
+
+bool sageAudioSync::checkSignal(int bufferId)
+{
+   bool found = false;
+   sageSyncInfo* info;
+   std::vector<sageSyncInfo*>::iterator iter;   
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      if(info->m_bufferId == bufferId) {
+         if(info->m_updateFlag) {
+            info->m_updateFlag = false;
+            return true;
+         }      
+         found = true;   
+         break;
+      }
+   }
+   
+   if(!found) {
+      return false;
+   }
+   
+   if(info->m_syncType == SAGE_SYNC_NONE) return false;
+
+   if(info->m_syncType == SAGE_SYNC_GRAPHIC_DRIVEN) {
+      if (!m_audioReceiver) { // graphics receiver
+         if(info->m_lockFlag == true) {
+            info->m_lockFlag = false;
+            return true;
+         } else {
+            return false;
+         }
+      }
+   }
+   
+   char msg[REG_MSG_SIZE];      
+   bool retVal = false;
+   int size = m_clientSockList.size();
+   if(size <= 0) {
+      if(info->m_clientSockFd >= 0) {
+         retVal = recvSignal(info->m_clientSockFd, msg, bufferId);
+         if(retVal) {
+            info->m_lockFlag = false;
+            return true;
+         }
+      } 
+      if(m_clientSockFd >= 0) {
+         retVal = recvSignal(m_clientSockFd, msg, bufferId);
+         if(retVal) {
+            info->m_lockFlag = false;
+            return true;
+         }
+      }
+   } else {
+      for(int i=0; i < size; i++) {
+         retVal = recvSignal(m_clientSockList[i], msg, bufferId);
+         if(retVal) {
+            info->m_lockFlag = false;
+            return true;
+         }
+      }
+   }
+
+   return retVal;
+}
+   
+bool sageAudioSync::recvSignal(int socketFd, char* msg, int bufferId)
+{
+   if (!sage::isDataReady(socketFd)) {
+      return false;
+   }   
+
+   int retVal = sage::recv(socketFd, (void *)msg, REG_MSG_SIZE);
+   int sourceID, frameNum;
+   double timeStamp;
+   if (retVal > 0) {
+      char token[TOKEN_LEN];
+      getToken(msg, token);
+      sourceID = atoi(token);
+      getToken(msg, token);
+      frameNum = atoi(token);
+      getToken(msg, token);
+      timeStamp = atof(token);
+   }
+   else if (retVal <= 0) {
+      return false;
+   }
+
+   //std::cout << "received---------> : sourceid : " << sourceID << "frameNum : " << frameNum << "timestamp : " << timeStamp <<  std::endl;
+   sageSyncInfo* info;
+   std::vector<sageSyncInfo*>::iterator iter;
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      if(info->m_sourceId == sourceID) {
+         if(info->m_bufferId == bufferId) {
+            info->m_updateFlag = false;
+            //std::cout << "info->m_sourceId == sourceID :: info->m_bufferId == bufferId " << std::endl;
+            return true;
+         }
+         std::cout << "info->m_sourceId == sourceID" << std::endl;
+         info->m_clientSockFd = socketFd;
+         info->m_updateFlag = true;
+         break;
+      } 
+   }   
+   return false;
+}
+
+int sageAudioSync::sendSignal(int bufferId)
+{   
+   bool found = false;
+   sageSyncInfo* info;
+   std::vector<sageSyncInfo*>::iterator iter;   
+   for(iter=m_syncInfoList.begin(); iter != m_syncInfoList.end(); iter++) {
+      info = (sageSyncInfo*) (*iter);
+      if(info->m_bufferId == bufferId) {
+         found = true;   
+         break;
+      }
+   }
+   
+   if(!found) {
+      return -1;
+   }   
+   
+   std::cerr << "called---------> : "<<  std::endl;
+   
+   char msg[REG_MSG_SIZE];
+   // sourceID, frameNumber, timeStamp
+   sprintf(msg, "%d %d %f", info->m_sourceId, 1, 1.0);
+
+   if (sage::send(m_clientSockFd, msg, REG_MSG_SIZE) <= 0) {
+      std::cerr << "sageAudioSync::sendSignal() : could not send message" <<  std::endl;
+      return -1;
+   }
+   return 0;
+}
+
+int sageAudioSync::sendSignal(sageSyncInfo* info)
+{   
+   std::cerr << "called---------> : "<<  std::endl;
+   
+   char msg[REG_MSG_SIZE];
+   // sourceID, frameNumber, timeStamp
+   sprintf(msg, "%d %d %f", info->m_sourceId, 1, 1.0);
+
+   if(m_audioReceiver) { // audio receiver
+      if (sage::send(m_clientSockList[0], msg, REG_MSG_SIZE) <= 0) {
+         std::cerr << "sageAudioSync::sendSignal() : could not send message" <<  std::endl;
+         return -1;
+      }
+   } else {
+      if (sage::send(m_clientSockFd, msg, REG_MSG_SIZE) <= 0) {
+         std::cerr << "sageAudioSync::sendSignal() : could not send message" <<  std::endl;
+         return -1;
+      }
+   }
+   return 0;
+}
+
+int sageAudioSync::initListener(int port)
+{
+   int optVal, optLen;
+   // open listener socket
+
+   // create the server socket
+   if((m_serverSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+   {
+      std::cerr << "sageAudioSync::init(): Creating socket failed" <<  std::endl;
+      return -1;
+   }
+   
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined(__sun)
+   if(setsockopt(m_serverSockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error setting SO_REUSEADDR" <<  std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_serverSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching off Nagle's algorithm." << std::endl;
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching on OOBINLINE." << std::endl;
+
+#else
+   if(setsockopt(m_serverSockFd, SOL_SOCKET, SO_REUSEADDR, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cerr << "sageAudioSync::init():: Error setting SO_REUSEADDR" << std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_serverSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching off Nagle's algorithm." << std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_serverSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching on OOBINLINE." << std::endl;
+
+#endif
+      
+   memset(&m_localAddr, 0, sizeof(sockaddr_in));
+   m_localAddr.sin_family = AF_INET;
+   m_localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+   m_localAddr.sin_port = htons(port);
+   
+   if (bind(m_serverSockFd, (struct sockaddr *)&m_localAddr, sizeof(struct sockaddr_in)) != 0) {
+      std::cerr << "sageAudioSync::init(): Error binding server socket" << std::endl;
+      return -1;
+   }
+   
+   // put in listen mode      
+   listen(m_serverSockFd, 5);
+   std::cout << "sageAudioSync::initListener() : initialized for listen : port " << port << std::endl;
+   
+   return 0;
+
+}
+
+int sageAudioSync::initSender(char* ip, int port)
+{
+   int optVal, optLen;
+   
+   // open sender/client socket
+   if((m_clientSockFd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+   {
+      std::cerr << "sageAudioSync::initSender(): Creating server socket failed" << std::endl;
+      return -1;
+   }
+   
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+
+#if defined(WIN32) || defined(__APPLE__) || defined(__sun)
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_clientSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::initSender(): Error switching off Nagle's algorithm." << std::endl;
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+
+   std::cerr << "sageAudioSync::initSender(): Error switching on OOBINLINE." << std::endl;
+#else
+   
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_clientSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cerr << "sageAudioSync::initSender(): Error switching off Nagle's algorithm." << std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(m_clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::initSender(): Error switching on OOBINLINE." << std::endl;
+
+#endif
+   // connect to the server
+   memset(&m_serverAddr, 0, sizeof(sockaddr_in));
+   m_serverAddr.sin_family = AF_INET;
+   m_serverAddr.sin_addr.s_addr = inet_addr(ip);
+   m_serverAddr.sin_port = htons(port);
+
+   if(::connect(m_clientSockFd, (struct sockaddr *)&m_serverAddr, sizeof(struct sockaddr)) == -1) {
+      std::cerr << "sageAudioSync::initSender() : Fail to connect" << std::endl;
+      return -1;
+   }
+   
+   // check message
+   // source id
+   char msg[REG_MSG_SIZE];
+   // sourceID, frameNumber, timeStamp
+   sprintf(msg, "%d %d %f", -1, 1, 1.0);
+   if (sage::send(m_clientSockFd, msg, REG_MSG_SIZE) == -1) {
+      std::cerr << "sageAudioSync::initSender() : send message  " << std::endl;
+      return -1;
+   }
+   std::cout << "sageAudioSync::initSender() : sended message for initialize : port " << port << std::endl;
+
+   return 0;
+}
+
+int sageAudioSync::checkConnections()
+{
+   if(!m_connectedDone) { 
+      /*if(initSender(ip, port) < 0) {
+         return -1;
+      }*/
+      m_connectedDone = true;
+      return -1;
+   }
+   if (!sage::isDataReady(m_serverSockFd)) {
+      return -1;
+   }   
+
+   //accept client connections
+   int addrLen;
+   sockaddr_in clientAddr;
+   addrLen = sizeof(clientAddr);
+   
+   int clientSockFd;
+   if((clientSockFd = ::accept(m_serverSockFd, (struct sockaddr *)&clientAddr, (socklen_t*)&addrLen)) == -1){
+      std::cerr << "sageAudioSync::checkConnections() : accept error" << std::endl;
+      return -1;
+   }
+   int optVal, optLen;
+   // loosen the rules for check during bind to allow mutiple binds on the same port
+   optVal=1; optLen = sizeof(optVal);
+   
+#if defined(WIN32) || defined(__APPLE__) || defined(__sun)
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error setting SO_REUSEADDR" <<  std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching off Nagle's algorithm." << std::endl;
+
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching on OOBINLINE." << std::endl;
+
+#else
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_REUSEADDR, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cerr << "sageAudioSync::init():: Error setting SO_REUSEADDR" << std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_TCP, TCP_NODELAY, (void*)&optVal, (socklen_t)optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching off Nagle's algorithm." << std::endl;
+      
+   optVal = 1;
+   optLen=sizeof(optVal);
+   if(setsockopt(clientSockFd, SOL_SOCKET, SO_OOBINLINE, (const char*)&optVal, optLen) !=0)
+      std::cerr << "sageAudioSync::init(): Error switching on OOBINLINE." << std::endl;
+
+#endif   
+   
+   m_clientSockList.push_back(clientSockFd);
+
+   char msg[REG_MSG_SIZE];
+   int retVal = sage::recv(clientSockFd, (void *)msg, REG_MSG_SIZE);
+   if (retVal == -1) {
+      std::cerr << "sageAudioSync::checkConnections() : receive error" << std::endl;
+      return -1;
+   }
+   else if (retVal == 0) {
+      return -1;
+   }
+   
+   std::cout << "sageAudioSync::checkConnections() : new client is connected " << std::endl;
+
+   return 0;
+}
+
+int sageAudioSync::closeAll()
+{   
+   int rcvNum = m_clientSockList.size();
+
+#ifdef WIN32   
+   closesocket(m_clientSockFd);
+
+   for (int i=0; i< rcvNum ; i++) {
+      if (m_clientSockList[i] < 0) continue;
+      closesocket(m_clientSockList[i]);
+   }
+   closesocket(m_serverSockFd);
+#else
+   shutdown(m_serverSockFd, SHUT_RDWR);
+   close(m_serverSockFd);
+
+   for (int i=0; i< rcvNum ; i++) {
+      if (m_clientSockList[i] < 0) continue;
+      shutdown(m_clientSockList[i], SHUT_RDWR);
+      close(m_clientSockList[i]);
+   }
+   shutdown(m_clientSockFd, SHUT_RDWR);
+   close(m_clientSockFd);
+#endif
+
+   return 0;
+}
Index: trunk/src/testing/src/pixelDownloader.cpp
===================================================================
--- trunk/src/testing/src/pixelDownloader.cpp	(revision 4)
+++ trunk/src/testing/src/pixelDownloader.cpp	(revision 4)
@@ -0,0 +1,788 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: pixelDownloader.cpp - manaing each application instance of SAGE Receiver
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "pixelDownloader.h"
+#include "sageDisplay.h"
+#include "sageSync.h"
+#include "sageBlockPool.h"
+#include "sageSharedData.h"
+#include "sageBlock.h"
+#include "sageEvent.h"
+#include "sageBlockPartition.h"
+#include "sageReceiver.h"
+
+int montagePair::init(displayContext *context, sagePixFmt pfmt, int index, float depth)
+{
+   montage[0] = new sageMontage(context, pfmt);
+   montage[1] = new sageMontage(context, pfmt);
+   //tileID = id;
+   setLocalTileIdx(index);
+   setDepth(depth);
+
+   return 0;
+}
+
+void montagePair::swapMontage()
+{
+   // when a window is moved or resized, the config of back montage is
+   // updated immediately, the front montage is updated when it is swapped
+
+	//struct timeval start,end;
+   if (renewMontage) {
+	   //gettimeofday(&start, 0);
+      // copying the config of back montage to front montage
+      montage[frontMon]->copyConfig(*montage[1-frontMon]);
+      //gettimeofday(&end, 0);
+      //fprintf(stderr, "swapMon: %.5f msec\n", 1000 * (((double)end.tv_sec + 0.000001*(double)end.tv_usec) - ((double)start.tv_sec+0.000001*(double)start.tv_usec)));
+
+      renewMontage = false;
+   }
+
+   frontMon = 1 - frontMon;
+}
+
+int montagePair::deleteMontage()
+{
+   montage[0]->deleteTexture();
+   montage[1]->deleteTexture();
+
+   return 0;
+}
+
+int montagePair::setDepth(float depth)
+{
+   montage[0]->depth = depth;
+   montage[1]->depth = depth;
+
+   return 0;
+}
+
+int montagePair::setLocalTileIdx(int idx)
+{
+   montage[0]->tileIdx = idx;
+   montage[1]->tileIdx = idx;
+
+   return 0;
+}
+
+montagePair::~montagePair()
+{
+   delete montage[0];
+   delete montage[1];
+}
+
+pixelDownloader::pixelDownloader() : reportRate(1), updatedFrame(0), curFrame(0), recv(NULL),
+   streamNum(0), bandWidth(0), montageList(NULL), configID(0), frameCheck(false),
+   syncFrame(0), updateType(SAGE_UPDATE_FOLLOW), activeRcvs(0), passiveUpdate(false),
+   dispConfigID(0), displayActive(false), status(PDL_WAIT_DATA), frameBlockNum(0), frameSize(0),
+   partition(NULL), blockBuf(NULL),
+	m_initialized(false)
+{
+   perfTimer.reset();
+
+   // is this from bridge and actually parallel app?
+   fromBridgeParallel = false;
+}
+
+int pixelDownloader::init(char *msg, dispSharedData *sh, streamProtocol *nwObj, bool sync, int sl)
+{
+	/* from sageStreamer::connectToRcv()
+	char regMsg[REG_MSG_SIZE];
+	      sprintf(regMsg, "%d %d %d %d %d %d %d %d %d %d %d %d",
+	    		  config.streamType,
+	    		  config.frameRate,
+	    		  winID,
+	    		  config.groupSize,
+	    		  blockSize,
+	    		  config.nodeNum,
+	    		  (int)config.pixFmt,
+	    		  config.blockX,
+	    		  config.blockY,
+	    		  config.totalWidth,
+	    		  config.totalHeight,
+	    		  config.fromBridge);
+
+	      */
+   char *msgPt = sage::tokenSeek(msg, 3);
+   sscanf(msgPt, "%d %d %d", &instID, &groupSize, &blockSize);
+
+   int blockX, blockY, imgWidth, imgHeight;
+   sagePixFmt pixFmt;
+   int temp = 0;
+
+   msgPt = sage::tokenSeek(msg, 7);
+   sscanf(msgPt, "%d %d %d %d %d %d", (int *)&pixFmt, &blockX, &blockY, &imgWidth, &imgHeight, &temp);
+   if ( temp ) fromBridgeParallel = true;
+
+   if ( fromBridgeParallel ) {
+	   fprintf(stderr,"PDL::%s() : fromBridgeParallel true\n", __FUNCTION__);
+   }
+
+   if (partition) {
+	   delete partition;
+   }
+   partition = new sageBlockPartition(blockX, blockY, imgWidth, imgHeight);
+   if (!partition) {
+		sage::printLog("[%d,%d] PDL::init() : unable to create block partition", shared->nodeID, instID);
+      return -1;
+   }
+   partition->initBlockTable();
+
+   shared = sh;
+   syncOn = sync;
+   syncLevel = sl;
+
+   // how many tiles a node has
+   tileNum = shared->displayObj->getTileNum();
+
+   // montage INSTANTIATION
+   if ( montageList ) delete [] montageList;
+
+   montageList = new montagePair[tileNum];
+   float depth = 1.0f - 0.01f*instID;
+
+   for (int i=0; i<tileNum; i++) {
+      montageList[i].init(shared->context, pixFmt, i, depth);
+   }
+
+   configQueue.clear();
+
+   if ( blockBuf ) delete blockBuf;
+   if (blockSize>groupSize) {
+	sage::printLog("pixelDownloader> groupSize (%d) smaller than blockSize (%d)", groupSize, blockSize);
+	groupSize = blockSize;
+	sage::printLog("pixelDownloader> New groupSize (%d)", groupSize);
+   }
+
+   if ( shared->bufSize < groupSize ) {
+	sage::printLog("pixelDownloader> receiver buffer size must be greater than group size. New receiver buffer size (%d)", shared->bufSize);
+	shared->bufSize = groupSize;
+   }
+
+   blockBuf = new sageBlockBuf(shared->bufSize, groupSize, blockSize, BUF_MEM_ALLOC | BUF_CTRL_GROUP);
+
+   if ( recv ) delete recv;
+   recv = new sagePixelReceiver(msg, (rcvSharedData *)shared, nwObj, blockBuf);
+
+	m_initialized = true;
+
+   return 0;
+}
+
+int pixelDownloader::addStream(int senderID)
+{
+   if (recv) {
+      recv->addStream(senderID);
+   }
+   else {
+      sage::printLog("pixelDownloader::addStream : receiver obj is NULL");
+      return -1;
+   }
+
+   return 0;
+}
+
+int pixelDownloader::clearTile(int tileIdx)
+{
+   montagePair &monPair = montageList[tileIdx];
+   sageMontage *mon = monPair.getFrontMon();
+   shared->displayObj->removeMontage(mon);
+   monPair.deactivate();
+
+   return 0;
+}
+
+int pixelDownloader::clearScreen()
+{
+   for (int i=0; i<tileNum; i++) {
+      clearTile(i);
+   }
+
+   return 0;
+}
+
+int pixelDownloader::swapMontages()
+{
+   bool activeMontage = false;
+
+   for (int i=0; i<tileNum; i++) {
+      montagePair &monPair = montageList[i];
+
+      if (monPair.isActive()) {
+         if (monPair.getClearFlag()) {
+            clearTile(i);
+         }
+         else {
+            monPair.swapMontage();
+            shared->displayObj->replaceMontage(monPair.getFrontMon());
+         }
+         activeMontage = true;
+      }
+   }
+
+   if (activeMontage) {
+      shared->displayObj->setDirty();
+   }
+
+   return 0;
+}
+
+void pixelDownloader::processSync(int frame, int cmd)
+{
+   if (!syncOn)
+      return;
+
+
+
+   syncFrame = frame;
+   //if (shared->nodeID == 0)
+   //std::cout << "receive sync " << syncFrame << std::endl;
+
+   //sungwon
+   //fprintf(stderr, "pixelDownloader::processSync(syncFrame %d, cmd %d), instID %d, streamNum %d, tileNum %d, updatedFrame %d\n",frame, cmd,instID, streamNum, tileNum, updatedFrame);
+
+
+   // when the sync slave keeps the pace
+   if (updatedFrame == syncFrame) {
+      swapMontages(); // swap textures (one for display, one for pixel downloading)
+   }
+
+   // when the sync slave runs behind and the screen needs to be cleared (only for SOFT_SYNC mode)
+   else {
+      bool screenUpdate = false;
+      for (int i=0; i<tileNum; i++) {
+         montagePair &monPair = montageList[i];
+         if (monPair.getClearFlag()) {
+            clearTile(i);
+            screenUpdate = true;
+         }
+      }
+      if (screenUpdate)
+         shared->displayObj->setDirty();
+
+      if (cmd == SKIP_FRAME) {
+         updatedFrame = syncFrame;
+
+
+      }
+   }
+
+
+   /**
+    * SAGE display has two textures for each image fragment.
+One for display. The other to be written new pixels on.
+Two textures are swapped once a sync signal arrived
+and a new image shows up when the screen is refreshed.
+This only happens when the frame number of the image
+loaded on the new texture to be shown matches the sync
+frame number.
+It should match always for HARD-SYNC mode.
+But it may not for SOFT-SYNC mode
+for which sync frame can proceed even though some slaves
+are not ready for going to the next frame.
+But I can't guarantee the stability of the SOFT-SYNC mode
+of the current implementation (especially for parallel apps).
+CONSTANT-SYNC mode was not complete either.
+
+HARD-SYNC and NO-SYNC mode are mostly tested so far.
+    */
+}
+
+int pixelDownloader::enqueConfig(char *data)
+{
+   char *configData = new char[strlen(data)+1];
+   if (!configData) {
+      sage::printLog("pixelDownloader::enqueConfig : unable to allocate memory");
+      return -1;
+   }
+
+   strcpy(configData, data);
+   configQueue.push_back(configData);
+
+   return 0;
+}
+
+bool pixelDownloader::reconfigDisplay(int confID)
+{
+   if (dispConfigID >= confID) {
+		sage::printLog("[%d,%d] PDL::reconfigDisplay(%d) : configuration ID error", shared->nodeID, instID, confID);
+      return false;
+   }
+
+   char *configStr = NULL;
+   while (dispConfigID < confID) {
+      if (configQueue.size() == 0)
+         return false;
+
+      configStr = configQueue.front();
+      dispConfigID++;
+      configQueue.pop_front();
+   }
+
+   int oldRcvs = activeRcvs;
+   displayActive = false;
+
+   sageRotation orientation;
+   sscanf(configStr, "%d %d %d %d %d %d", &windowLayout.x, &windowLayout.y,
+      &windowLayout.width, &windowLayout.height, &activeRcvs, (int *)&orientation);
+   windowLayout.setOrientation(orientation);
+
+   // when the window locates on a neighbor tiled display
+   if (windowLayout.width == 0 || windowLayout.height == 0) {
+      if (syncOn) {
+         for (int i=0; i<tileNum; i++)
+            montageList[i].clear();
+      }
+      else {
+         clearScreen();
+         shared->displayObj->setDirty();
+      }
+      return true;
+   }
+
+   partition->setDisplayLayout(windowLayout);
+   partition->clearBlockTable();
+
+   for (int i=0; i<tileNum; i++) {
+      montagePair &monPair = montageList[i];
+      sageMontage *mon = NULL;
+
+      sageRect tileRect = shared->displayObj->getTileRect(i);
+      if (!tileRect.crop(windowLayout)) {
+         if (syncOn)
+            monPair.clear();
+         else {
+            clearTile(i);
+            shared->displayObj->setDirty();
+         }
+         continue;
+      }
+
+      displayActive = true;
+
+      partition->setTileLayout(tileRect);
+      sageRect viewPort = partition->getViewPort();
+      sageRect blockLayout = partition->getBlockLayout();
+
+      viewPort.moveOrigin(blockLayout);
+
+      if (monPair.isActive()) {
+         //if (shared->nodeID == 5)
+         //   std::cerr << "montage active" << std::endl;
+         mon = monPair.getBackMon();
+         *(sageRect *)mon = tileRect;
+         mon->init(viewPort, blockLayout, orientation);
+         monPair.renew();
+      }
+      else {
+         //if (shared->nodeID == 5)
+         //   std::cerr << "montage inactive" << std::endl;
+         mon = monPair.getFrontMon();
+         //*(sageRect *)mon = tileRect;
+         //mon->init(viewPort, blockLayout, orientation);
+         int monIdx = shared->displayObj->addMontage(mon);
+
+         mon = monPair.getBackMon();
+         *(sageRect *)mon = tileRect;
+         mon->init(viewPort, blockLayout, orientation);
+         mon->monIdx = monIdx;
+         monPair.renew();
+
+         monPair.activate();
+      }
+
+      partition->genBlockTable(i);
+   }
+
+   frameSize = blockSize * partition->tableEntryNum();
+
+   if (oldRcvs != activeRcvs)
+      updateType = SAGE_UPDATE_SETUP;
+
+   return true;
+}
+
+int pixelDownloader::downloadPixelBlock(sagePixelBlock *block, montagePair &monPair)
+{
+   sageMontage *mon = monPair.getBackMon();
+
+   mon->loadPixelBlock(block);
+   //monPair.update();
+
+   return 0;
+}
+
+int pixelDownloader::fetchSageBlocks()
+{
+
+	//bool flag = false;
+	//struct timeval start,end;
+
+   // fetch block data from the block buffer
+   sageBlockGroup *sbg;
+
+	// will use this instead of END_FRAME flag
+	bool useLastBlock = true; // must be TCP
+	bool proceedSwap = false;
+
+   while (sbg = blockBuf->front()) {
+
+		 /**
+		  * the difference between updatedFrame and syncFrame should always 1
+		  * because the new frame it gets is always right next frame of current frame
+		  * otherwise, PDL should WAIT until others catch up
+		  *
+		  * This is the most important pre-requisite of the sync algorithm
+		  */
+	   if ( syncOn && (sbg->getFrameID() > syncFrame + 1) ) {
+			 status = PDL_WAIT_SYNC; // wait for others to catch up
+		   return status;
+	   }
+
+		 //
+		 // pixelReceiver received entire frame
+		 //
+			 /** lastblock used
+		 if (sbg->getFlag() == sageBlockGroup::END_FRAME) { // END_FRAME flag is set at the sagePixelReceiver::readData()
+			// now the most recent frame I got(curFrame) becomes updateFrame.
+			// this means that because of swapMontages() curFrames will become front montage which means it can be displayed
+			// therefore, it's updatedFrame
+         updatedFrame = curFrame;
+
+			//fprintf(stderr,"SDM %d PDL %d END_FRAME, Frame %d, syncFrame %d\n", shared->nodeID, instID, updatedFrame, syncFrame);
+			//fflush(stderr);
+
+         frameCounter++;
+
+         // calculate packet loss
+         packetLoss += frameSize-(frameBlockNum*blockSize);
+         frameBlockNum = 0;
+
+         if (syncOn) {
+            if (updatedFrame <= syncFrame) {
+               swapMontages();
+            }
+            else {
+
+            	//sungwon
+            	//fprintf(stderr, "pixelDownloader::fetchSageBlocks() : instID %d, stremNum %d, tileNum %d sendSlaveUpdate(updatedFrame %d, instID %d, activeRcvs %d, updateType %d)\n"
+            	//		,instID, streamNum, tileNum, updatedFrame, instID, activeRcvs, updateType);
+
+            	// frame, id, rcvNum, type
+            	// activeRcv is the number of receiver(number of tiles)
+               shared->syncClientObj->sendSlaveUpdate(updatedFrame, instID, activeRcvs, updateType);
+               updateType = SAGE_UPDATE_FOLLOW;
+               //std::cout << "send update " << updatedFrame << std::endl;
+               status = PDL_WAIT_SYNC;
+
+               blockBuf->next();
+               blockBuf->returnBG(sbg);
+
+               return status;
+            }
+         }
+         else {
+            swapMontages();
+         }
+		} // end of if(END_FRAME)
+			**/
+
+
+		//
+		// pixelReceiver received new CONFIG
+		//
+      if (sbg->getFlag() == sageBlockGroup::CONFIG_UPDATE) {
+         if (configID < sbg->getConfigID()) {
+            if (reconfigDisplay(sbg->getConfigID()))
+               configID = sbg->getConfigID();
+            else {
+               status = PDL_WAIT_CONFIG;
+               return status;
+            }
+         }
+      }
+
+		//
+		// continuous next frame received (it means this node was displaying this app already)
+		//
+      else if (sbg->getFlag() == sageBlockGroup::PIXEL_DATA && sbg->getFrameID() > updatedFrame) {
+    	  if (configID < sbg->getConfigID()) {
+    		  if (reconfigDisplay(sbg->getConfigID()))
+    			  configID = sbg->getConfigID();
+    		  else {
+    			  status = PDL_WAIT_CONFIG;
+    			  return status;
+    		  }
+    	  }
+
+    	  bandWidth += sbg->getDataSize() + GROUP_HEADER_SIZE;
+    	  //if ( curFrame != sbg->getFrameID() ) {flag = true; shared->dl.count++;}
+    	  curFrame = sbg->getFrameID();
+    	  frameBlockNum += sbg->getBlockNum();
+
+
+
+    	  for (int i=0; i<sbg->getBlockNum(); i++) {
+    		  sagePixelBlock *block = (*sbg)[i];
+
+    		  if (!block)
+    			  continue;
+
+    		  //std::cout << "block header " << (char *)block->getBuffer() << std::endl;
+
+    		  blockMontageMap *map = (blockMontageMap *)partition->getBlockMap(block->getID());
+    		  int bx = block->x, by = block->y;
+
+    		  //gettimeofday(&start, 0);
+
+    		  while(map) {
+    			  block->translate(map->x, map->y);
+    			  //std::cout << "block montage " << map->infoID << " id " << block->getID() << " pos " << block->x << " , " << block->y << std::endl;
+
+    			  /* unpack pixels to framebuffer */
+    			  downloadPixelBlock(block, montageList[map->infoID]);
+
+    			  //gettimeofday(&end, 0);
+
+    			//shared->dl.elapsed += ((double)end.tv_sec + 0.000001*(double)end.tv_usec) - ((double)start.tv_sec+0.000001*(double)start.tv_usec);
+    			  //start = end;
+
+    			  block->x = bx;
+    			  block->y = by;
+    			  map = (blockMontageMap *)map->next;
+    		  }
+    	  } // end of foreach block
+
+    	  if ( !fromBridgeParallel && recv->getSenderNum() == 1 ) {
+    		  if ( partition && frameBlockNum >= partition->tableEntryNum() ) { // whole frame received
+    			  useLastBlock = true; // setting flag for swapMontages to be executed, since END_FRAME
+    			  proceedSwap = true;
+    		  }
+    		  else {
+    			  useLastBlock = false;
+    		  }
+    	  }
+    	  else {
+			  //fprintf(stderr,"[%d,%d] PDL::fetch() : parallel sender %d \n", shared->nodeID, instID, recv->getSenderNum());
+    		  // if it's parallel app (multiple sender), we have to use END_FRAME. Because senders(for this PDL) can send duplicate blocks. This can cause one frame behind issue.
+    		  // If we use counting number of blocks method, we will see black spots on the screen
+    		  useLastBlock = false;
+    	  }
+      }
+
+
+		//
+		// if UDP, lastBlock checking method could fail when a block is dropped, END_FRAME flag is used in that case
+		// IMPORTANT
+		// When in UDP, sync performance could be very bad.
+		// Because some node can use END_FRAME while others don't
+		// In that case, the node that used END_FRAME will become the slowest one, and others will have to wait for this node.
+		//
+		else if (sbg->getFlag() == sageBlockGroup::END_FRAME) { // END_FRAME flag is set at the sagePixelReceiver::readData()
+			//fprintf(stderr, "[%d,%d] PDL::fetch() : END_FRAME; updF %d, curF %d, syncF %d\n", shared->nodeID, instID, updatedFrame, curFrame, syncFrame);
+
+			if ( updatedFrame == curFrame ) {
+				// already swapMontage-ed, do nothing
+				// if syncOn then, updatedF == curF == synchF
+			}
+			else if ( updatedFrame > curFrame ) {
+				// something is badly wrong
+				fprintf(stderr,"[%d,%d] PDL::fetch() : END_FRAME flag!!! FATAL_ERROR!!! curF %d, updF %d, syncF %d\n", shared->nodeID, instID, curFrame, updatedFrame, syncFrame);
+			}
+			else {
+#ifdef DEBUG_PDL
+				fprintf(stderr,"[%d,%d] PDL::fetch() : END_FRAME flag!!! Before proceeding, curF %d, updF %d, syncF %d\n", shared->nodeID, instID, curFrame, updatedFrame, syncFrame);
+#endif
+				proceedSwap = true;
+				useLastBlock = false;
+			}
+		}
+
+		//
+		// unexpected case
+		//
+		else {
+			//sage::printLog("\n[%d,%d] PDL::fetch() : invalid block order.",shared->nodeID, instID);
+#ifdef DEBUG_PDL
+			fprintf(stderr, "\tcurF %d, updF %d, syncF %d, curF %d, cfgID %d\n",curFrame, updatedFrame, syncFrame, configID);
+			fprintf(stderr, "\tsbg->getFlag() %d, sbg->getFrameID() %d, sbg->getConfigID() %d\n", sbg->getFlag(), sbg->getFrameID(), sbg->getConfigID());
+			fflush(stderr);
+#endif
+		}
+
+
+		// to fix END_FRAME recognition.
+		// Originally, frame n is recognized as complete (END_FRAME) when blocks of frame n+1 is received
+		// This causes frame being displayed is always behind actual config ->  config l is applied but frame l-1 is displayed
+		if ( proceedSwap ) {
+			proceedSwap = false;
+
+			// now the most recent frame I got(curFrame) becomes updateFrame.
+			// this means that because of swapMontages(), curFrames will become front montage which means it can be displayed.
+			// therefore, it's updatedFrame.
+			updatedFrame = curFrame;
+#ifdef DEBUG_PDL
+			if (useLastBlock) {
+				//fprintf(stderr,"[%d,%d] PDL::fetch() : !!! ProceedSwap !!! using LastBlock fBN %d of %d; updF %d, syncF %d, cfID %d\n", shared->nodeID, instID, frameBlockNum, partition->tableEntryNum(), updatedFrame, syncFrame, configID);
+			}
+			else {
+				//fprintf(stderr,"[%d,%d] PDL::fetch() : !!! ProceedSwap !!! using END_FRAME fBN %d of %d; updF %d, syncF %d, cfID %d\n", shared->nodeID, instID, frameBlockNum, partition->tableEntryNum(), updatedFrame, syncFrame, configID);
+			}
+#endif
+			frameCounter++;
+
+			// calculate packet loss
+			packetLoss += frameSize-(frameBlockNum*blockSize);
+			frameBlockNum = 0; //reset
+			//actualFrameBlockNum = 0;
+
+			if (syncOn) {
+				if ( updatedFrame > syncFrame) {
+					// if this is the case, I'm too fast. I must wait for others
+
+#ifdef DELAY_COMPENSATION
+					//shared->syncClientObj->sendSlaveUpdateToBBS(updatedFrame, instID, activeRcvs, shared->nodeID, shared->latency);
+#else
+					if ( syncLevel == -1 ) {
+						shared->syncClientObj->sendSlaveUpdate(updatedFrame, instID, activeRcvs, updateType); // old sage sync
+					}
+					else {
+						shared->syncClientObj->sendSlaveUpdateToBBS(updatedFrame, instID, activeRcvs, shared->nodeID, 0);
+					}
+#endif
+					updateType = SAGE_UPDATE_FOLLOW;
+					status = PDL_WAIT_SYNC;
+
+					blockBuf->next();
+					blockBuf->returnBG(sbg);
+
+					return status;
+				}
+				else if ( updatedFrame == syncFrame ) {
+#ifdef DEBUG_PDL
+					//fprintf(stderr, "\nPDL::fetch() : [%d,%d] updatedFrame == synchFrame %d, don't we need swapMontages() ? \n", syncFrame);
+#endif
+					//swapMontages();
+				}
+				else {
+					fprintf(stderr, "\nPDL::fetch() : [%d,%d] FatalError! updF %d , syncF %d\n", shared->nodeID, instID, updatedFrame, syncFrame);
+					fflush(stderr);
+				}
+			}
+			else {
+				// PDL::processSync() will never be called. So let's do swapMontages here.
+				//fprintf(stderr, "download a group for frame %d:  %.5f msec\n", updatedFrame, shared->dl.elapsed * 1000.0);
+				//shared->dl.elapsed = 0;
+				swapMontages();
+			}
+		} // end of if(proceedSwap)
+
+
+		blockBuf->next();
+		blockBuf->returnBG(sbg); // pushback this grp to blockBuf's dataPool (if PIXEL_DATA) or ctrlPool
+
+   } // end of while(blockBuf->front())
+
+   status = PDL_WAIT_DATA;
+   return status;
+}
+
+int pixelDownloader::evalPerformance(char **frameStr, char **bandStr)
+{
+   //Calculate performance here
+   double elapsedTime = perfTimer.getTimeUS();
+
+   if (elapsedTime > 1000000.0*reportRate && reportRate > 0) {
+      *bandStr = new char[TOKEN_LEN];
+
+      float obsBandWidth = (float) (bandWidth * 8.0 / (elapsedTime));
+      float obsLoss = (float) (packetLoss * 8.0 / (elapsedTime));
+      bandWidth = 0;
+      packetLoss = 0;
+      sprintf(*bandStr, "%d %f %f %d", instID, obsBandWidth, obsLoss, frameSize);
+
+      if (displayActive) {
+         *frameStr = new char[TOKEN_LEN];
+         float frameRate = (float) (frameCounter.getValue() * 1000000.0 / elapsedTime);
+         frameCounter.reset();
+         sprintf(*frameStr, "%d %f", instID, frameRate);
+      }
+
+      perfTimer.reset();
+   }
+
+   return 0;
+}
+
+int pixelDownloader::setDepth(float depth)
+{
+   for (int i=0; i<tileNum; i++) {
+      montageList[i].setDepth(depth);
+   }
+
+   return 0;
+}
+
+pixelDownloader::~pixelDownloader()
+{
+	fprintf(stderr, "[%d,%d] PDL::~PDL()\n", shared->nodeID, instID);
+
+   for (int i=0; i<tileNum; i++) {
+      montagePair &monPair = montageList[i];
+      sageMontage* mon = monPair.getFrontMon();
+      shared->displayObj->removeMontage(mon);
+      monPair.deleteMontage();
+   }
+
+   shared->displayObj->setDirty();
+
+   delete [] montageList;
+   delete recv;
+   delete blockBuf;
+
+   for (int i=0; i<configQueue.size(); i++) {
+      char *configData = configQueue.front();
+      configQueue.pop_front();
+      delete [] configData;
+   }
+#ifdef DEBUG_PDL
+   fprintf(stderr, "[%d,%d] PDL::~PDL()\n", shared->nodeID, instID);
+#endif
+}
Index: trunk/src/testing/src/uiConsole.cpp
===================================================================
--- trunk/src/testing/src/uiConsole.cpp	(revision 4)
+++ trunk/src/testing/src/uiConsole.cpp	(revision 4)
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: uiConsole.cpp - experimental user console for SAGE
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+ 
+#include "suil.h"
+#include "misc.h"
+#include <pthread.h>
+
+void* readThread(void *args)
+{
+   suil *uiLib = (suil *)args;
+   
+   while(1) {
+      sageMessage msg;
+      msg.init(READ_BUF_SIZE);
+      uiLib->rcvMessageBlk(msg);
+      std::cout << "Message : " << msg.getCode() << std::endl << (char *)msg.getData() << std::endl << std::endl;
+   }
+
+   return NULL;
+} 
+
+int main(int argc, char *argv[])
+{
+   char token[TOKEN_LEN];
+   bool flag = true;
+
+#if defined(WIN32)
+   sage::win32Init();
+#endif
+	   
+   suil uiLib;
+   if (argc == 2)
+      uiLib.init(argv[1]);
+   else
+      uiLib.init("fsManager.conf");
+
+   uiLib.connect(NULL);
+   
+   uiLib.sendMessage(SAGE_UI_REG," ");
+
+   pthread_t thId;
+   
+   if(pthread_create(&thId, 0, readThread, (void*)&uiLib) != 0){
+      return -1;
+   }
+
+   while(flag) {
+      std::cin >> token;
+   
+      if (strcmp(token, "exit") == 0) {
+         flag = false;
+      } 
+      else if (strcmp(token, "exec") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(EXEC_APP, token);
+      }            
+      else if (strcmp(token, "move") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(MOVE_WINDOW, token);
+      }            
+      else if (strcmp(token, "resize") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(RESIZE_WINDOW, token);
+      }            
+      else if (strcmp(token, "bg") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SAGE_BG_COLOR, token);
+      }            
+      else if (strcmp(token, "depth") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         uiLib.sendMessage(SAGE_Z_VALUE, cmd);
+      }            
+      else if (strcmp(token, "perf") == 0) {
+         char cmd[TOKEN_LEN];
+         fgets(cmd, TOKEN_LEN, stdin);         
+         uiLib.sendMessage(PERF_INFO_REQ, cmd);
+      }            
+      else if (strcmp(token, "stopperf") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(STOP_PERF_INFO, token);
+      }            
+      else if (strcmp(token, "kill") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SHUTDOWN_APP, token);
+      }            
+      else if (strcmp(token, "shutdown") == 0) {
+         uiLib.sendMessage(SAGE_SHUTDOWN, " ");
+         _exit(0);
+      }            
+      else if (strcmp(token, "admin") == 0) {
+         uiLib.sendMessage(SAGE_ADMIN_CHECK);
+      }            
+      else if (strcmp(token, "rate") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(APP_FRAME_RATE, token);
+      }            
+      else if (strcmp(token, "share") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SAGE_APP_SHARE, token);
+      }            
+      else if (strcmp(token, "flip") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SAGE_FLIP_WINDOW, token);
+      }
+      else if (strcmp(token, "latency") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(SAGE_CHECK_LATENCY, token);
+      }         
+      else if (strcmp(token, "reserved") == 0) {
+         uiLib.sendMessage(NETWORK_RESERVED);
+      }
+      else if (strcmp(token, "add_object") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(ADD_OBJECT, token);
+      }
+      else if (strcmp(token, "move_object") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(MOVE_OBJECT, token);
+      }
+      else if (strcmp(token, "remove_object") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(REMOVE_OBJECT, token);
+      }
+      else if (strcmp(token, "object_msg") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(OBJECT_MESSAGE, token);
+      }
+      else if (strcmp(token, "rotate") == 0) {
+         fgets(token, TOKEN_LEN, stdin);
+         uiLib.sendMessage(ROTATE_WINDOW, token);
+      }
+      else if (strcmp(token, "help") == 0) {
+         std::cout << std::endl;
+         std::cout << "exec   app_name config_num (init_x init_y) : execute an app" << std::endl;
+         std::cout << "move   app_id dx dy                  : move window of an app" << std::endl;
+         std::cout << "resize app_id left right bottom top  : resize window of an app" << std::endl;
+         std::cout << "bg     red green blue                : change background color" << std::endl;
+         std::cout << "depth  num_of_change app_id zVal...  : change z-order of windows" << std::endl;
+         std::cout << "perf   app_id report_period(sec)     : request performance info" << std::endl;
+         std::cout << "stopperf  app_id                     : stop performance info report" << std::endl;
+         std::cout << "kill      app_id                     : shutdown an app" << std::endl;
+         std::cout << "shutdown                             : shutdown SAGE" << std::endl;
+         std::cout << "admin                                : get administrative info" << std::endl;
+      }            
+      
+      std::cout << std::endl;
+   }
+}
Index: trunk/src/testing/src/overlayWall.cpp
===================================================================
--- trunk/src/testing/src/overlayWall.cpp	(revision 4)
+++ trunk/src/testing/src/overlayWall.cpp	(revision 4)
@@ -0,0 +1,390 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sagePointer.cpp
+ * Author : Ratko Jagodic, Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "overlayWall.h"
+#include <string>
+#include <png.h>
+
+using namespace std;
+
+// custom messages for the pointers
+#define WALL_RESOLUTION  0
+
+overlayWall::overlayWall(){
+	logoTexture = TEXTURE_LOAD_ERROR;
+}
+
+int overlayWall::init(char *name) {
+	setName(name);
+	return 0;
+}
+
+int overlayWall::draw() {
+	//First draw called
+	if (logoTexture == TEXTURE_LOAD_ERROR) {
+//		if (tileRect.left > 12000)
+//			return 0;
+
+		char *sageDir = getenv("SAGE_DIRECTORY");
+		string path(sageDir);
+
+//		path += "/dim/pcss_SAGE.raw";
+//		logoTexture = loadTextureRAW(path.c_str(),false);
+
+		int width, height;
+		path += "/dim/pcss_wall.png";
+		logoTexture = loadTexturePNG(path, width, height);
+	}
+
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glEnable(GL_BLEND);
+	glPushMatrix();
+		glBindTexture(GL_TEXTURE_2D, logoTexture);
+		glBegin(GL_QUADS);
+		if (tileRect.left > 0.6*width){
+			glTexCoord2d(0.0, 0.0); glVertex3f(tileRect.left, tileRect.bottom, 0);
+			glTexCoord2d(0.0, 1.0); glVertex3f(tileRect.left, tileRect.top, 0);
+			glTexCoord2d(1.0, 1.0);	glVertex3f(width, tileRect.top, 0);
+			glTexCoord2d(1.0, 0.0);	glVertex3f(width, tileRect.bottom, 0);
+		} else {
+			glTexCoord2d(0.0, 0.0); glVertex3f(tileRect.left, tileRect.bottom, 0);
+			glTexCoord2d(0.0, 1.0); glVertex3f(tileRect.left, tileRect.top, 0);
+			glTexCoord2d(1.0, 1.0);	glVertex3f(tileRect.right, tileRect.top, 0);
+			glTexCoord2d(1.0, 0.0);	glVertex3f(tileRect.right, tileRect.bottom, 0);
+		}
+		glEnd();
+	glPopMatrix();
+
+	glDisable(GL_BLEND);
+
+	return 0;
+}
+
+int overlayWall::destroy() {
+	glDeleteTextures(1, &logoTexture);
+	return 0;
+}
+
+int overlayWall::parseMessage(char *msg) {
+	int id, code;
+	sscanf(msg, "%d %d", &id, &code);
+
+	switch (code) {
+	case WALL_RESOLUTION: {
+		int newWidth, newHeight;
+		sscanf(msg, "%d %d %d %d", &id, &code, &newWidth, &newHeight);
+		width = newWidth;
+		height = newHeight;
+		break;
+	}
+	}
+	return 0;
+
+}
+
+GLuint overlayWall::loadTextureRAW(const char * filename, bool wrap) {
+	GLuint texture;
+	int width, height;
+	unsigned char * data;
+	FILE * file;
+
+	// open texture data
+	file = fopen(filename, "rb");
+	if (file == NULL) {
+		cout << "No such file" << endl;
+		return 0;
+	}
+
+	// allocate buffer
+	width = 1648;
+	height = 1056;
+	data = (unsigned char *) malloc(width * height * 3);
+
+	// read texture data
+	fread(data, width * height * 3, 1, file);
+	fclose(file);
+
+	// allocate a texture name
+	glGenTextures(1, &texture);
+
+	// select our current texture
+	glBindTexture(GL_TEXTURE_2D, texture);
+
+	// select modulate to mix texture with color for shading
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	// when texture area is small, bilinear filter the closest mipmap
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			GL_LINEAR_MIPMAP_NEAREST);
+	// when texture area is large, bilinear filter the first mipmap
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	// if wrap is true, the texture wraps over at the edges (repeat)
+	//       ... false, the texture ends at the edges (clamp)
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+			wrap ? GL_REPEAT : GL_CLAMP);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
+			wrap ? GL_REPEAT : GL_CLAMP);
+
+	// build our texture mipmaps
+//	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, tileRect.width, tileRect.height, GL_RGB, GL_UNSIGNED_BYTE,
+//			cropped);
+	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE,
+			data);
+
+	// free buffer
+	free(data);
+
+	return texture;
+}
+
+using namespace std;
+/** loadTexture
+ *     loads a png file into an opengl texture object, using cstdio , libpng, and opengl.
+ *
+ *     \param filename : the png file to be loaded
+ *     \param width : width of png, to be updated as a side effect of this function
+ *     \param height : height of png, to be updated as a side effect of this function
+ *
+ *     \return GLuint : an opengl texture id.  Will be 0 if there is a major error,
+ *                                     should be validated by the client of this function.
+ *
+ */
+GLuint overlayWall::loadTexturePNG(const string filename, int &width,
+		int &height) {
+	//header for testing if it is a png
+	png_byte header[8];
+
+	//open file as binary
+	FILE *fp = fopen(filename.c_str(), "rb");
+	if (!fp) {
+		return TEXTURE_LOAD_ERROR;
+	}
+
+	//read the header
+	fread(header, 1, 8, fp);
+
+	//test if png
+	int is_png = !png_sig_cmp(header, 0, 8);
+	if (!is_png) {
+		fclose(fp);
+		return TEXTURE_LOAD_ERROR;
+	}
+
+	//create png struct
+	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
+			NULL, NULL);
+	if (!png_ptr) {
+		fclose(fp);
+		return (TEXTURE_LOAD_ERROR);
+	}
+
+	//create png info struct
+	png_infop info_ptr = png_create_info_struct(png_ptr);
+	if (!info_ptr) {
+		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
+		fclose(fp);
+		return (TEXTURE_LOAD_ERROR);
+	}
+
+	//create png info struct
+	png_infop end_info = png_create_info_struct(png_ptr);
+	if (!end_info) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+		fclose(fp);
+		return (TEXTURE_LOAD_ERROR);
+	}
+
+	//png error stuff, not sure libpng man suggests this.
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		fclose(fp);
+		return (TEXTURE_LOAD_ERROR);
+	}
+
+	//init png reading
+	png_init_io(png_ptr, fp);
+
+	//let libpng know you already read the first 8 bytes
+	png_set_sig_bytes(png_ptr, 8);
+
+	// read all the info up to the image data
+	png_read_info(png_ptr, info_ptr);
+
+	//variables to pass to get info
+	int bit_depth, color_type;
+	png_uint_32 twidth, theight;
+
+	// get info about png
+	png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
+			NULL, NULL, NULL);
+
+	//update width and height based on png info
+	width = twidth;
+	height = theight;
+
+	// Update the png info struct.
+	png_read_update_info(png_ptr, info_ptr);
+
+	// Row size in bytes.
+	int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+	// Allocate the image_data as a big block, to be given to opengl
+	png_byte *image_data = new png_byte[rowbytes * height];
+
+	if (!image_data) {
+		//clean up memory and close stuff
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		fclose(fp);
+		return TEXTURE_LOAD_ERROR;
+	}
+
+	//row_pointers is for pointing to image_data for reading the png with libpng
+	png_bytep *row_pointers = new png_bytep[height];
+	if (!row_pointers) {
+		//clean up memory and close stuff
+		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+		delete[] image_data;
+		fclose(fp);
+		return TEXTURE_LOAD_ERROR;
+	}
+	// set the individual row_pointers to point at the correct offsets of image_data
+	for (int i = 0; i < height; ++i)
+		row_pointers[height - 1 - i] = image_data + i * rowbytes;
+
+	//read the png into image_data through row_pointers
+	png_read_image(png_ptr, row_pointers);
+
+	unsigned char *cropped = NULL;
+	sageRect textureSize(0,0,width,height);
+	cropTexture(image_data, cropped, textureSize);
+
+	//Now generate the OpenGL texture object
+	GLuint texture;
+
+	// allocate a texture name
+	glGenTextures(1, &texture);
+
+	// select our current texture
+	glBindTexture(GL_TEXTURE_2D, texture);
+
+	// select modulate to mix texture with color for shading
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	// when texture area is small, bilinear filter the closest mipmap
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			GL_LINEAR_MIPMAP_NEAREST);
+	// when texture area is large, bilinear filter the first mipmap
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+	// build our texture mipmaps
+	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, textureSize.width, textureSize.height, GL_RGB,
+			GL_UNSIGNED_BYTE, cropped);
+
+	//clean up memory and close stuff
+	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+	delete[] image_data;
+	delete[] row_pointers;
+	delete[] cropped;
+	fclose(fp);
+
+	return texture;
+}
+
+void overlayWall::cropTexture(const unsigned char *in, unsigned char *&out,
+		const unsigned int width) {
+	unsigned int index = 0;
+	unsigned int rowWidth = width * 3;
+
+	out = (unsigned char *) malloc(tileRect.width * tileRect.height * 3);
+
+	for (unsigned int y = tileRect.bottom; y < tileRect.top; y++) {
+		for (unsigned int x = tileRect.left; x < tileRect.right; x++) {
+			out[index++] = in[y * rowWidth + x * 3];
+			out[index++] = in[y * rowWidth + x * 3 + 1];
+			out[index++] = in[y * rowWidth + x * 3 + 2];
+		}
+	}
+
+}
+
+void overlayWall::cropTexture(const unsigned char *in, unsigned char *&out, sageRect &texture) {
+
+	unsigned int index = 0;
+	unsigned int rowWidth = texture.width * 3;
+
+	unsigned int xStart;
+	unsigned int xStop;
+	unsigned int yStart;
+	unsigned int yStop;
+
+	if (tileRect.left > 0.6*width){
+		xStart = (unsigned int)((float) tileRect.left / width * texture.width);
+		xStop = (unsigned int)((float) width / width * texture.width);
+		yStart = (unsigned int)((float) tileRect.bottom / height * texture.height);
+		yStop = (unsigned int)((float) tileRect.top / height * texture.height);
+	} else {
+		xStart = (unsigned int)((float) tileRect.left / width * texture.width);
+		xStop = (unsigned int)((float) tileRect.right / width * texture.width);
+		yStart = (unsigned int)((float) tileRect.bottom / height * texture.height);
+		yStop = (unsigned int)((float) tileRect.top / height * texture.height);
+	}
+
+	out = (unsigned char *) malloc((xStop - xStart) * (yStop - yStart) * 3);
+
+	cout << "Rect:[" << tileRect.left << ";" << tileRect.right << ";" << tileRect.bottom << ";" << tileRect.top << "]\tTex:[" << xStart << ";" << xStop << "][" << yStart << ";" << yStop <<"]" << endl;
+
+
+	for (unsigned int y = yStart; y < yStop; y++) {
+		for (unsigned int x = xStart; x < xStop; x++) {
+			out[index++] = in[y * rowWidth + x * 3];
+			out[index++] = in[y * rowWidth + x * 3 + 1];
+			out[index++] = in[y * rowWidth + x * 3 + 2];
+		}
+	}
+
+	texture.width = xStop - xStart;
+	texture.height = yStop - yStart;
+
+}
+
Index: trunk/src/testing/src/Info.plist
===================================================================
--- trunk/src/testing/src/Info.plist	(revision 4)
+++ trunk/src/testing/src/Info.plist	(revision 4)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleExecutable</key>
+       <string>sageDisplayManager</string>
+       <key>CFBundleGetInfoString</key>
+       <string>Created by EVL/UIC</string>
+       <key>CFBundleIdentifier</key>
+       <string>sage.sageDisplayManager</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>LSUIPresentationMode</key>
+       <integer>4</integer>
+</dict>
+</plist>
Index: trunk/src/testing/src/sageConfig.cpp
===================================================================
--- trunk/src/testing/src/sageConfig.cpp	(revision 4)
+++ trunk/src/testing/src/sageConfig.cpp	(revision 4)
@@ -0,0 +1,393 @@
+/******************************************************************************
+ * SAGE - Scalable Adaptive Graphics Environment
+ *
+ * Module: sageConfig.cpp
+ * Author : Byungil Jeong
+ *
+ * Copyright (C) 2004 Electronic Visualization Laboratory,
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about SAGE to sage_users@listserv.uic.edu or 
+ * http://www.evl.uic.edu/cavern/forum/
+ *
+ *****************************************************************************/
+
+#include "sageVersion.h"
+#include "sageConfig.h"
+#include "sageSync.h"
+
+streamerConfig::streamerConfig() : rank(0), resX(0), resY(0), rowOrd(TOP_TO_BOTTOM), 
+      master(true), protocol(SAGE_TCP), asyncUpdate(true), blockX(64), blockY(64), blockSize(0), 
+      compression(NO_COMP), pixFmt(PIXFMT_888), streamType(SAGE_BLOCK_HARD_SYNC), 
+      syncClientObj(NULL), frameRate(60), totalWidth(0), totalHeight(0), groupSize(131072),
+      audioOn(false), audioPort(0), audioDeviceNum(0), audioKeyFrame(100), audioProtocol(SAGE_TCP),
+      sampleFmt(SAGE_SAMPLE_FLOAT32), samplingRate(44100), channels(2), framePerBuffer(1024),
+      syncType(SAGE_SYNC_NONE), totalFrames(0), syncPolicy(SAGE_ASAP_SYNC_HARD),
+      autoBlockSize(false), maxBandwidth(1000), maxCheckInterval(1000), flowWindow(2),
+      bridgeOn(false), frameDrop(true)
+{
+   switch(sampleFmt) {
+      case SAGE_SAMPLE_FLOAT32 :
+         bytesPerSample = sizeof(float);
+         break;
+      case SAGE_SAMPLE_INT16 :
+         bytesPerSample = sizeof(short);
+         break;
+      case SAGE_SAMPLE_INT8 :
+         bytesPerSample = sizeof(int);
+         break;
+      case SAGE_SAMPLE_UINT8 :
+         bytesPerSample = sizeof(unsigned int);
+         break;            
+      default :
+         break;
+   }
+
+   swexp = false;
+   fromBridgeParallel = false;
+
+}
+
+sailConfig::sailConfig() : nwID(1), fsPort(0), syncPort(0), msgPort(0), appID(0), 
+      rendering(true), winX(100), winY(100), winWidth(-1), winHeight(-1),
+      rcvBufSize(0), syncMode(0), bridgePort(0), portForwarding(0)
+{
+   memset(appName, 0, SAGE_NAME_LEN);
+   memset(masterIP, 0, SAGE_IP_LEN);
+   memset(fsIP, 0, SAGE_IP_LEN);
+   memset(launcherID, 0, SAGE_NAME_LEN);
+   strcpy(launcherID, "none");
+   appName[0] = '\0';
+   masterIP[0] = '\0';
+   bridgeIP[0] = '\0';
+   fsIP[0] = '\0';
+   sprintf(streamIP, "127.0.0.1");
+}
+
+int sailConfig::setAppName(const char *name)
+{
+   int len = strlen(name);
+   if (len > SAGE_NAME_LEN) {
+      std::cerr << "sailConfig::setAppName : the length of application name exceed SAGE_NAME_LEN" <<
+         std::endl;
+      return -1;
+   }
+   
+   strcpy(appName, name);
+   
+   return 0;
+}
+
+int sailConfig::init(const char *fname)
+{
+	data_path path("applications");
+	std::string found = path.get_file(fname);
+	if (found.empty()) {
+		sage::printLog("sailConfig: cannot find the file [%s]", fname);
+		return -1;
+	}
+	const char *configName = found.c_str();
+	sage::printLog("sailConfig: SAGE version [%s]", SAGE_VERSION);
+	sage::printLog("sailConfig: using [%s] configuration file", configName);
+	
+	
+	FILE *fp = fopen(configName, "r");   
+	if (!fp) {
+		sage::printLog("sailConfig: fail to open sail config file [%s]\n", configName);
+		return -1;
+	}
+	
+	char token[TOKEN_LEN];
+	while(getToken(fp, token) != EOF) {
+		sage::toupper(token);
+		if (strcmp(token, "APPNAME") == 0) {
+			getToken(fp, appName);
+		}
+		else if (strcmp(token, "FSIP") == 0) {
+			getToken(fp, fsIP);
+		}
+		else if (strcmp(token, "FSPORT") == 0) {
+			getToken(fp, token);
+			fsPort = atoi(token);
+		}
+		else if (strcmp(token, "BRIDGEON") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			bridgeOn = (strcmp(token, "true") == 0);
+		}
+		else if (strcmp(token, "BRIDGEIP") == 0) {
+			getToken(fp, bridgeIP);
+		}
+		else if (strcmp(token, "BRIDGEPORT") == 0) {
+			getToken(fp, token);
+			bridgePort = atoi(token);
+		}
+		else if (strcmp(token, "MASTERIP") == 0) {
+			getToken(fp, masterIP);
+		}
+		else if (strcmp(token, "NWID") == 0) {
+			getToken(fp, token);
+			nwID = atoi(token);
+		}
+		else if (strcmp(token, "MSGPORT") == 0) {
+			getToken(fp, token);
+			msgPort = atoi(token);
+		} 
+		else if (strcmp(token, "SYNCPORT") == 0) {
+			getToken(fp, token);
+			syncPort = atoi(token);
+		}
+		else if (strcmp(token, "NODENUM") == 0) {
+			getToken(fp, token);
+			nodeNum = atoi(token);
+		}          
+		else if (strcmp(token, "APPID") == 0) {
+			getToken(fp, token);
+			appID = atoi(token);
+		}
+		else if (strcmp(token, "LAUNCHERID") == 0) {
+			getToken(fp, launcherID);
+		}
+		else if (strcmp(token, "PIXELBLOCKSIZE") == 0) {
+			getToken(fp, token);
+			blockX = atoi(token);
+			getToken(fp, token);
+			blockY = atoi(token);
+		}
+		else if (strcmp(token, "BLOCKTHRESHOLD") == 0) {
+			getToken(fp, token);
+			blockSize = atoi(token);
+		}
+		else if (strcmp(token, "WINX") == 0) {
+			getToken(fp, token);
+			winX = atoi(token);
+		}
+		else if (strcmp(token, "WINY") == 0) {
+			getToken(fp, token);
+			winY = atoi(token);
+		}
+		else if (strcmp(token, "WINWIDTH") == 0) {
+			getToken(fp, token);
+			winWidth = atoi(token);
+		}
+		else if (strcmp(token, "WINHEIGHT") == 0) {
+			getToken(fp, token);
+			winHeight = atoi(token);
+		}          
+		else if (strcmp(token, "NWPROTOCOL") == 0) {
+			getToken(fp, token);
+			sage::toupper(token);
+			if (strcmp(token, "TCP") == 0) 
+				protocol = SAGE_TCP;
+			else if (strcmp(token, "UDP") == 0)
+				protocol = SAGE_UDP;   
+		}
+		else if (strcmp(token, "ASYNCUPDATE") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			asyncUpdate = (strcmp(token, "true") == 0);
+		}   
+		else if (strcmp(token, "SYNCMODE") == 0) {
+			getToken(fp, token);
+			syncMode = atoi(token);
+		}
+		else if (strcmp(token, "STREAMIP") == 0) {
+			getToken(fp, streamIP);
+		}
+		else if (strcmp(token, "FRAMERATE") == 0) {
+			getToken(fp, token);
+			frameRate = atoi(token);
+		}          
+		else if (strcmp(token, "COMPRESSION") == 0) {
+			getToken(fp, token);
+			if (strcmp(token, "RLE") == 0)
+				compression = RLE_COMP;
+			else if (strcmp(token, "LUV") == 0)
+				compression = LUV_COMP;   
+			else if (strcmp(token, "DXT") == 0)
+				compression = DXT_COMP;   
+			else
+				compression = NO_COMP;   
+		}
+		else if (strcmp(token, "STREAMTYPE") == 0) {
+			getToken(fp, token);
+			if (strcmp(token, "SAGE_BLOCK_NO_SYNC") == 0) {
+				streamType = SAGE_BLOCK_NO_SYNC;
+			}   
+			else if (strcmp(token, "SAGE_BLOCK_CONST_SYNC") == 0) {
+				streamType = SAGE_BLOCK_CONST_SYNC;   
+			}   
+			else if (strcmp(token, "SAGE_BLOCK_SOFT_SYNC") == 0) {
+				streamType = SAGE_BLOCK_SOFT_SYNC;
+			}
+			else if (strcmp(token, "SAGE_BLOCK_HARD_SYNC") == 0) {
+				streamType = SAGE_BLOCK_HARD_SYNC;
+			}
+			else {
+				streamType = SAGE_BLOCK_NO_SYNC;
+			}   
+		}
+		else if (strcmp(token, "GROUPSIZE") == 0) {
+			getToken(fp, token);
+			groupSize = atoi(token);
+		}
+		else if (strcmp(token, "AUTOBLOCKSIZE") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			autoBlockSize = (strcmp(token, "true") == 0);
+		}
+		else if (strcmp(token, "MAXBANDWIDTH") == 0) {
+			getToken(fp, token);
+			maxBandwidth = atoi(token);
+		}
+		else if (strcmp(token, "MAXCHECKINTERVAL") == 0) {
+			getToken(fp, token);
+			maxCheckInterval = atoi(token);
+		}
+		else if (strcmp(token, "FLOWCONTROL") == 0) {
+			getToken(fp, token);
+			flowWindow = atoi(token);
+		}
+		else if (strcmp(token, "PORTFORWARDING") == 0) {
+			getToken(fp, token);
+			portForwarding = atoi(token);
+		}
+		else if (strcmp(token, "AUDIOON") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			audioOn = (strcmp(token, "true") == 0);
+		}
+		else if (strcmp(token, "AUDIO") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			audioOn = (strcmp(token, "true") == 0);
+		}
+		else if (strcmp(token, "AUDIOKEYFRAME") == 0) {
+			getToken(fp, token);
+			audioKeyFrame = atoi(token);
+		}
+		else if(strcmp(token, "AUDIOTYPE") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			if(strcmp(token, "capture") == 0) {
+				audioMode = SAGE_AUDIO_CAPTURE;
+			}
+			else if(strcmp(token, "fwcapture") == 0) {
+				audioMode = SAGE_AUDIO_FWCAPTURE;
+			}
+			else if(strcmp(token, "play") == 0) {
+				audioMode = SAGE_AUDIO_PLAY;
+			}
+			else if(strcmp(token, "read") == 0) {
+				audioMode = SAGE_AUDIO_READ;
+			}
+			else if(strcmp(token, "appData") == 0) {
+				audioMode = SAGE_AUDIO_APP;
+			}
+		}
+		else if(strcmp(token, "AUDIOFILE") == 0) {
+			getToken(fp, audioFileName);
+		}
+		else if (strcmp(token, "AUDIOPORT") == 0) {
+			getToken(fp, token);
+			audioPort = atoi(token);
+		}
+		else if (strcmp(token, "DEVICENUM") == 0) {
+			getToken(fp, token);
+			audioDeviceNum = atoi(token);
+		}
+		else if (strcmp(token, "SAMPLINGRATE") == 0) {
+			getToken(fp, token);
+			samplingRate = atoi(token);
+		}
+		else if (strcmp(token, "SAMPLEFORMAT") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			if (strcmp(token, "float32") == 0) {
+				sampleFmt = SAGE_SAMPLE_FLOAT32;
+			}
+			else if (strcmp(token, "int16") == 0) {
+				sampleFmt = SAGE_SAMPLE_INT16;
+			}
+			else if (strcmp(token, "int8") == 0) {
+				sampleFmt = SAGE_SAMPLE_INT8;
+			}
+			else if (strcmp(token, "uint8") == 0) {
+				sampleFmt = SAGE_SAMPLE_UINT8;
+			}
+		}
+		else if (strcmp(token, "CHANNELS") == 0) {
+			getToken(fp, token);
+			channels = atoi(token);
+		}
+		else if (strcmp(token, "FRAMEPERBUFFER") == 0) {
+			getToken(fp, token);
+			framePerBuffer = atoi(token);
+		}
+		else if (strcmp(token, "SYNCTYPE") == 0) {
+			getToken(fp, token);
+			sage::tolower(token);
+			if (strcmp(token, "none") == 0) {
+				syncType = SAGE_SYNC_NONE;
+			}
+			else if (strcmp(token, "audiodriven") == 0) {
+				syncType = SAGE_SYNC_AUDIO_DRIVEN;
+			}
+			else if (strcmp(token, "graphicdriven") == 0) {
+				syncType = SAGE_SYNC_GRAPHIC_DRIVEN;
+			}
+		}
+		else if (strcmp(token, "AUDIONWPROTOCOL") == 0) {
+			getToken(fp, token);
+			sage::toupper(token);
+			if (strcmp(token, "TCP") == 0) 
+				audioProtocol = SAGE_TCP;
+			else if (strcmp(token, "UDP") == 0)
+				audioProtocol = SAGE_UDP;   
+		}
+		else if (strcmp(token, "RENDERBUFX") == 0) {
+			getToken(fp, token);
+			resX = atoi(token);
+		}
+		else if (strcmp(token, "RENDERBUFY") == 0) {
+			getToken(fp, token);
+			resY = atoi(token);
+		}
+		else if (strcmp(token, "SWEXP") == 0 ) {
+			getToken(fp, token);
+			if ( atoi(token) == 1 ) {
+				swexp = true;
+			}
+		}
+	}
+	
+	fclose(fp);
+	
+	return 0;
+}
Index: trunk/src/testing/QUANTA/src/QUANTAnet_perfDaemon_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_perfDaemon_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_perfDaemon_c.cxx	(revision 4)
@@ -0,0 +1,255 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#include "QUANTAnet_perfDaemon_c.hxx"
+#include "QUANTAnet_datapack_c.hxx"
+#include "QUANTAnet_tcp_c.hxx"
+
+#include <string.h>
+
+const int QUANTAnet_perfDaemon_c::OK = 0;
+const int QUANTAnet_perfDaemon_c::FAILED = 1;
+const int QUANTAnet_perfDaemon_c::MEM_ALLOC_ERR = 2;
+const int QUANTAnet_perfDaemon_c::NEW_CONNECTION_ESTABLISHED = 4;
+const int QUANTAnet_perfDaemon_c::TOO_MANY_CLIENTS = 5;
+const int QUANTAnet_perfDaemon_c::NO_NEW_CONNECTION= 6;
+const int QUANTAnet_perfDaemon_c::NON_BLOCKING_HAS_NO_DATA=7;
+const int QUANTAnet_perfDaemon_c::SKIP_DISTRIBUTION=8;
+const int QUANTAnet_perfDaemon_c::DEFAULT_PORT=PERF_DAEMON_DEFAULT_PORT;
+
+QUANTAnet_perfDaemon_c :: QUANTAnet_perfDaemon_c(FILE* File)
+{
+	server = new QUANTAnet_tcpServer_c;
+	interceptCallback = NULL;
+	interceptUserData = NULL;
+	interceptNewConnectionCallback = NULL;
+	interceptNewConnectionUserData = NULL;
+	LogFile = File;
+}
+
+
+QUANTAnet_perfDaemon_c :: ~QUANTAnet_perfDaemon_c()
+{
+	if (server) delete server;
+	closeDownSockets();
+}
+
+int QUANTAnet_perfDaemon_c :: init(int incomingPort, int maxClients)
+{
+	maxNumClients = maxClients;
+
+	// Initialize the incoming socket
+	if (server && server->init(incomingPort) == 0)	{
+		return QUANTAnet_perfDaemon_c::FAILED;
+	}
+
+	// Create an array of pointers to track the incoming connections.
+	clients = new PerfDaemonClient*[maxNumClients];
+	if (clients == NULL) return QUANTAnet_perfDaemon_c::MEM_ALLOC_ERR;
+
+	for(int i = 0; i < maxNumClients; i++) clients[i] = NULL;
+
+	return QUANTAnet_perfDaemon_c::OK;
+}
+
+int QUANTAnet_perfDaemon_c :: checkForNewClients()
+{
+	QUANTAnet_tcpClient_c *aClient;
+	/* If a connection is established, accept it and create
+	 * a new socket for that connection to communicate with.
+	 *
+	 */
+	aClient = server->checkForNewConnections();
+
+	// If a new client connects then add it to an empty slot in the array of clients.
+	if (aClient) {
+		QUANTAnet_perfDaemonClient_c *newClient = new QUANTAnet_perfDaemonClient_c(aClient);
+
+		// Turn the timeout off. In general this is necessary because in a
+		// TCP stream if you lose some data you won't be able to figure out
+		// where the head of the next message will be.
+		aClient->setTimeOut(QUANTAnet_tcpClient_c::NO_TIME_OUT);
+
+		for (int i = 0; i < maxNumClients; i++) {
+			if (clients && clients[i] == NULL){
+                clients[i] = new PerfDaemonClient;
+				clients[i]->Client = newClient;
+				clients[i]->IsPerfClient = 0;
+				clients[i]->Started = 0;
+
+				char remoteIP[256];
+				int remotePort;
+				newClient->getRemoteIP(remoteIP);
+				remotePort = newClient->getRemotePort();
+				printf("QUANTAnet_perfDaemon_c: New Client: %s:%d\n",remoteIP, remotePort);
+
+				//sprintf(clients[i]->FileName, "%s_%d", remoteIP, remotePort);
+
+				if (interceptNewConnectionCallback)
+					interceptNewConnectionCallback(newClient, 
+                                                   interceptNewConnectionUserData);
+
+				return QUANTAnet_perfDaemon_c::NEW_CONNECTION_ESTABLISHED;
+			}
+		}
+
+		// If user callback specified then call it.
+
+		// If cannot host any more clients then report it.
+		return QUANTAnet_perfDaemon_c::TOO_MANY_CLIENTS;
+	}
+	return QUANTAnet_perfDaemon_c::NO_NEW_CONNECTION;
+}
+
+void QUANTAnet_perfDaemon_c :: intercept(int (*callback) (QUANTAnet_perfDaemonClient_c *, char** buffer, int *datasize, void *userData), void* userData)
+{
+	interceptCallback = callback;
+	interceptUserData = userData;
+}
+
+void QUANTAnet_perfDaemon_c :: interceptNewConnection(void (*callback) (QUANTAnet_perfDaemonClient_c *newClient, void* userData), void *userData)
+{
+	interceptNewConnectionCallback = callback;
+	interceptNewConnectionUserData = userData;
+}
+
+
+int QUANTAnet_perfDaemon_c :: process()
+{
+    int status;
+    int incomingSize = 0;
+    char *buffer;
+
+    // Check for any new clients.
+    checkForNewClients();
+
+    // Go through array of clients and read from them.
+    for (int i = 0; i < maxNumClients; i++) {
+		if (clients && clients[i]) {
+		    status = clients[i]->Client->read(&buffer, &incomingSize,
+					  QUANTAnet_perfDaemonClient_c::NON_BLOCKING);
+		    if (status == QUANTAnet_perfDaemonClient_c::MEM_ALLOC_ERR) 
+		        return QUANTAnet_perfDaemon_c::MEM_ALLOC_ERR;
+		    if (status == QUANTAnet_perfDaemonClient_c::OK) {
+		        if (clients[i]->Started == 0) {
+				    if (strncmp(REGISTER_PERF_CLIENT, buffer, REGISTER_PERF_CLIENT_LENGTH) == 0) {
+					    clients[i]->IsPerfClient = 1;
+						clients[i]->Started = 1;
+						delete buffer;
+						return QUANTAnet_perfDaemon_c::OK;
+				    }
+				    else if (strncmp(SEND_STAT_CLIENT, buffer, SEND_STAT_CLIENT_LENGTH) == 0) {
+					    clients[i]->IsPerfClient = 0;
+						clients[i]->Started = 1;
+						delete buffer;
+						return QUANTAnet_perfDaemon_c::OK;
+				    }
+				}
+				if (interceptCallback) {
+				    if (interceptCallback(clients[i]->Client, &buffer, 
+										&incomingSize, interceptUserData) 
+						== QUANTAnet_perfDaemon_c::SKIP_DISTRIBUTION) {
+					    delete buffer;
+						continue;
+				    }
+				}
+
+				// append to the logfile
+				if (LogFile) {
+                    fprintf(LogFile, "%s\n", buffer); 
+                    fflush(LogFile);
+                }
+
+				// Reflect the data to all connected clients except
+				// the client that originated the message.
+				distributeDataToPerfClients(buffer, incomingSize);
+				delete buffer;
+		    } 
+		    else if (status != QUANTAnet_perfDaemonClient_c::NON_BLOCKING_HAS_NO_DATA){
+		        removeClient(i);
+                printf("client %d is removed.\n", i);
+            }
+		}
+    }
+    return QUANTAnet_perfDaemon_c::OK;
+}
+
+int QUANTAnet_perfDaemon_c :: distributeDataToPerfClients(char* buf, int incomingSize)
+{
+	// Iterate thru the array of clients and send the message to all of them
+	// except the one indicated by clientToIgnore
+	if (clients) {
+		for (int i = 0; i < maxNumClients; i++) {
+			if (clients[i]) {
+				if (clients[i]->IsPerfClient 
+				              && clients[i]->Client->write(buf, &incomingSize) != QUANTAnet_perfDaemonClient_c::OK) {
+					removeClient(i);
+				}
+			}
+		}
+	}
+	return QUANTAnet_perfDaemon_c::OK;
+}
+
+int QUANTAnet_perfDaemon_c::sendToAll(char* buf, int incomingSize)
+{
+    return distributeDataToPerfClients(buf, incomingSize);
+}
+
+void QUANTAnet_perfDaemon_c :: removeClient(int i)
+{
+	if (clients && clients[i])	{
+		delete clients[i];
+    }
+	clients[i] = NULL;
+}
+
+void QUANTAnet_perfDaemon_c :: closeDownSockets()
+{
+	int count;
+
+	// Iterate thru list of clients and close them down.
+	if (clients) {
+		for (count = 0; count < maxNumClients; count++) {
+			if (clients[count]) {
+				clients[count]->Client->close();
+				delete clients[count];
+			}
+		}
+		delete clients;
+	}
+	server->close();
+	delete server;
+}
+
Index: trunk/src/testing/QUANTA/src/QUANTAnet_socketbase_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_socketbase_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_socketbase_c.cxx	(revision 4)
@@ -0,0 +1,598 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifdef QUANTA_USE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <netdb.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif /* !WIN32 */
+
+#ifndef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WIN32
+#include <QUANTA/gettimeofday.hxx>
+#endif
+
+//#include "QUANTAinit.hxx"
+#include "QUANTAnet_socketbase_c.hxx"
+
+const int QUANTAnet_socketbase_c::FAILED = 0;
+const int QUANTAnet_socketbase_c::OK = 1;
+const int QUANTAnet_socketbase_c::TIMED_OUT = 0;
+
+QUANTAnet_socketbase_c :: QUANTAnet_socketbase_c() {
+    initialReadTime = initialSentTime = getTimeInSecs();
+	previousSentTime = initialSentTime;
+	previousReadTime = initialReadTime;
+
+	totalDataRead = totalDataSent = prevTotalDataRead = prevTotalDataSent = 0;
+	latCount = readCount = sentCount =0;
+	instLat = latTotal = maxLat = minLat = avgLat = 0;
+	instDelay = maxDelay = minDelay = avgDelay = totalDelay = 0;
+   instReadBandwidth= instSendBandwidth= avgReadBandwidth= avgSendBandwidth =0;
+    
+    jitter = burstiness = STALatency =STABandwidth =0;
+    for (int i=0; i<LATENCY_BUF_SIZE; i++, latencyBuffer[i] = bandwidthBuffer[i] =0);
+    STlatencySum = STbandwidthSum =0;    
+    tempLatCounter = tempBWCounter = 0;  
+}
+
+double QUANTAnet_socketbase_c :: getTimeInSecs()
+{
+/*#ifdef WIN32 //using either high performance counter or _ftime in Windows 
+	if (UseFTime) { // Use _ftime. Precision is limited to milliseconds level.
+	    const double oneMilliSec = 0.001;	
+		struct _timeb timeSec;
+
+		_ftime(&timeSec);
+
+		return (((double) timeSec.time) + (((double) timeSec.millitm) * oneMilliSec));
+	}
+	else { // Use high performance counter. Precision is in microseconds level.
+		LARGE_INTEGER endCounter;	
+		double tempL;
+
+		QueryPerformanceCounter(&endCounter);
+		return StartTime + (double) ((endCounter.QuadPart - StartCounter.QuadPart) / (double) Frequency.QuadPart);
+	}
+#else //using gettimeofday() otherwise - gives time with microsecond level precision*/
+    const double oneMicroSec = 0.000001;
+	struct timeval timeSec;
+
+	gettimeofday(&timeSec, NULL);
+
+	return (((double) timeSec.tv_sec) +
+		(((double) timeSec.tv_usec) * oneMicroSec));
+//#endif
+}
+
+void QUANTAnet_socketbase_c::ipNumToString(unsigned int ipnum, char *ipstring)
+{
+#if 0
+	/* Old implementation disabled. */
+	char *name = (char*) &ipnum;
+
+	int a,b,c,d;
+	a = (unsigned char) name[0];
+	b = (unsigned char) name[1];
+	c = (unsigned char) name[2];
+	d = (unsigned char)  name[3];
+	sprintf(ipstring,"%d.%d.%d.%d",a,b,c,d);
+#endif
+	if (ipnum && ipstring) {
+	  struct in_addr addr;
+	  memcpy(&addr, &ipnum, sizeof(ipnum));
+
+	  char *ipAddr = inet_ntoa(addr);
+	  if (ipAddr)
+	    strcpy(ipstring, ipAddr);
+	  else
+	    *ipstring = '\0';
+	} else if (ipstring)
+	  *ipstring = '\0';
+}
+
+void QUANTAnet_socketbase_c :: expandHostName(const char *src, char* newname, int len)
+{
+	struct hostent *	hp_ptr;
+
+        hp_ptr = gethostbyname(src);
+        if (hp_ptr != NULL) {
+		struct in_addr      addr;
+
+		memcpy(&(addr.s_addr), hp_ptr->h_addr, hp_ptr->h_length);
+		hp_ptr = gethostbyaddr((char *)&addr,sizeof(addr),AF_INET);
+		if (hp_ptr != NULL && strcmp(hp_ptr->h_name, src) != 0){
+			strncpy(newname, hp_ptr->h_name,len);
+		}
+		else {
+			hp_ptr = NULL;
+		}
+	}
+	if (hp_ptr == NULL) {
+		strncpy(newname,src,len);
+	}
+
+}
+
+void QUANTAnet_socketbase_c :: getHostName(char *name, int len)
+{
+	static char hostname[256];
+
+	if (gethostname(hostname,256) < 0) {
+		name[0] = '\0';
+		return;
+	}
+
+	expandHostName(hostname, name, len);
+}
+
+long QUANTAnet_socketbase_c::getSelfIP()
+{
+  const int maxhostnamelen = 250;
+  char hostname[maxhostnamelen];
+
+  // First get the name of the current host.
+  if (gethostname(hostname, maxhostnamelen) == -1) {
+    printf("Error calling gethostname.\n");
+    return 0;
+  }
+  // Look up the host entry for the current host.
+  struct hostent* he = gethostbyname(hostname);
+  if (he == NULL) {
+    printf("Error calling gethostbyname.\n");
+    return 0;
+  }
+  // Process the list of addresses.
+  long ipnum;
+  for (int i = 0; he->h_addr_list[i] != 0; ++i) {
+    if (he->h_addrtype == AF_INET) {
+      memcpy(&ipnum, he->h_addr_list[i], sizeof(ipnum));
+      return ipnum;
+    }
+  }
+  return 0;
+}
+
+void QUANTAnet_socketbase_c::getSelfIP(char* name)
+{
+  ipNumToString(getSelfIP(), name);
+}
+
+int QUANTAnet_socketbase_c::hostnameToIP(const char* hostname, char* hostIP)
+{
+#ifndef WIN32
+	extern int h_errno;
+#endif
+	struct hostent* host;
+
+	host = gethostbyname(hostname);
+
+	if (!host) {
+		// check if hostname is a dotted ip address
+                unsigned a, b, c, d;
+                int result = sscanf(hostname, "%u.%u.%u.%u", &a, &b, &c,&d);	
+		printf("Unable to resolve hostname: %s\n",hostname);
+		if (result == 0 || result == EOF) {
+        	         printf("Unable to resolve hostname:%s\n",hostname);
+
+                        /* This is needed becoz on the Sun
+                         * gethostbyname returns nothing if
+                         * the explicit IP address is specified,
+                         * whereas on the SGI the same IP is
+                         * returned.
+                         */
+
+                        sprintf(hostIP,"?.?.?.?");
+
+                        return FAILED;
+                }
+                else {
+                        if (a > 255 || b > 255 || c > 255 || d > 255) {
+                                printf("Unable to resolve host name: %s \n", hostname); 
+                                sprintf(hostIP, "?.?.?.?");
+                                return FAILED;
+                        }
+                        else {
+                                unsigned addr, addr2;
+
+                                addr = (a << 24) + ((b << 16) &
+0x00FF0000) + ((c << 8) & 0x0000FF00) + (d & 0x000000FF);
+                                addr2 = htonl(addr);
+                                ipNumToString(addr2, hostIP);
+                                return OK;
+                        }
+                }
+        }
+        unsigned int* addr;
+        addr = (unsigned int*) host->h_addr_list[0];
+        ipNumToString(*addr, hostIP);
+        return OK;
+}
+
+unsigned int QUANTAnet_socketbase_c::getTotalDataSent()
+{
+	return totalDataSent;
+}
+
+unsigned int QUANTAnet_socketbase_c::getTotalDataRead()
+{
+	return totalDataRead;
+}
+
+double QUANTAnet_socketbase_c::getInstantSendBandwidth(){
+	return instSendBandwidth;
+}
+
+double QUANTAnet_socketbase_c::getInstantReceiveBandwidth(){
+	return instReadBandwidth;
+}
+
+double QUANTAnet_socketbase_c::getAverageSendBandwidth()
+{
+	return avgSendBandwidth;
+}
+
+
+double QUANTAnet_socketbase_c::getAverageReceiveBandwidth()
+{
+	return avgReadBandwidth;
+}
+
+void QUANTAnet_socketbase_c::computeInstantSendBandwidth()
+{
+	/* Figure out what time it is */
+
+	currentTime = getTimeInSecs();
+    if (!sentCount)
+    {
+        initialSentTime = currentTime;
+    }
+    else
+    {
+         double sentDifference = currentTime - previousSentTime ;
+        if (sentDifference > 0)
+            instSendBandwidth = double(totalDataSent - prevTotalDataSent) / (currentTime-previousSentTime);
+        //else instSendBandwidth is the previous instantaneous SBW value
+    }
+    prevTotalDataSent = totalDataSent;		
+	previousSentTime = currentTime;
+}
+
+void QUANTAnet_socketbase_c::computeInstantReceiveBandwidth()
+{
+	/* Figure out what time it is */
+	currentTime = getTimeInSecs();
+    if (!readCount)
+    {
+        initialReadTime = currentTime;
+    }
+    else
+    {
+        double readDifference = currentTime - previousReadTime ;
+        if (readDifference > 0)
+            instReadBandwidth = double(totalDataRead - prevTotalDataRead) / (currentTime-previousReadTime);
+        //else instReadBandwidth is the previous inst.RBW
+    }
+    prevTotalDataRead = totalDataRead;
+    previousReadTime = currentTime;
+}
+
+void QUANTAnet_socketbase_c::computeAverageReceiveBandwidth()
+{
+    //Average bandwidth calculated from the second packet received
+    if (readCount)
+    {        
+        currentTime = getTimeInSecs();
+        avgReadBandwidth = double(totalDataRead)/(currentTime-initialReadTime);
+    }
+    //calculate the burstiness with the inst read bandwidth
+    calculateBurstiness(instReadBandwidth);
+}
+
+void QUANTAnet_socketbase_c::computeAverageSendBandwidth()
+{
+    //Average bandwidth calculated from the second packet sent
+	if (sentCount)
+    {
+        currentTime = getTimeInSecs();
+        avgSendBandwidth = double(totalDataSent)/(currentTime-initialSentTime);
+    } 
+}
+
+double QUANTAnet_socketbase_c :: getInstantLatency()
+{
+	return instLat;
+}
+
+double QUANTAnet_socketbase_c :: getAverageLatency()
+{
+    return avgLat;
+}
+
+void QUANTAnet_socketbase_c::setInstantLatency(double lat)
+{
+    double curTime = getTimeInSecs();
+	if (latCount == 0){
+		minLat = lat;
+	}
+	instLat = lat;
+	if (lat > maxLat) maxLat = lat;
+	if (lat < minLat) minLat = lat;
+
+    //Calculate the jitter with the inst.latency -also increment latency count and total latency calculated
+    calculateJitter(lat);
+}
+
+double QUANTAnet_socketbase_c::getMinLatency()
+{
+	return minLat;
+}
+
+double QUANTAnet_socketbase_c::getMaxLatency()
+{
+	return maxLat;
+}
+
+void QUANTAnet_socketbase_c::incrementDataSent(unsigned long size)
+{
+    totalDataSent+=size;
+    computeInstantSendBandwidth();
+    computeAverageSendBandwidth();
+    sentCount++;
+}
+
+void QUANTAnet_socketbase_c::incrementDataRead(unsigned long size)
+{
+    double curTime = getTimeInSecs();
+    totalDataRead+=size;
+	if (!readCount)
+    {
+        prevLocalTime = curTime;
+    }
+    if (readCount)
+    { 
+        instDelay = curTime - prevLocalTime; 
+        if (readCount == 1) minDelay = instDelay;
+        totalDelay+=instDelay;
+        prevLocalTime = curTime; 
+        if (instDelay>maxDelay) maxDelay = instDelay;
+        if (instDelay<minDelay) minDelay = instDelay; 
+    }
+
+    computeInstantReceiveBandwidth();
+    computeAverageReceiveBandwidth();
+}
+
+double QUANTAnet_socketbase_c::getInstantInterMesgDelay()
+{
+	return instDelay;
+}
+
+double QUANTAnet_socketbase_c::getMaxInterMesgDelay()
+{
+	return maxDelay;
+}
+
+double QUANTAnet_socketbase_c::getMinInterMesgDelay()
+{
+	return minDelay;
+}
+
+double QUANTAnet_socketbase_c::getAverageInterMesgDelay()
+{
+    return avgDelay;
+}
+
+unsigned long QUANTAnet_socketbase_c :: getPacketsRead()
+{
+    return readCount;
+}
+
+unsigned long QUANTAnet_socketbase_c :: getPacketsSent()
+{
+    return sentCount;
+}
+
+double QUANTAnet_socketbase_c::getSTALatency()
+{
+	return STALatency;
+}
+
+double QUANTAnet_socketbase_c::getJitter()
+{
+	return jitter;
+}
+
+double QUANTAnet_socketbase_c::getSTABandwidth()
+{
+	return STABandwidth;
+}
+
+double QUANTAnet_socketbase_c::getBurstiness()
+{
+	return burstiness;
+}
+
+void QUANTAnet_socketbase_c :: calculateJitter (double lat)
+{
+    int lastnumber;
+    int i;
+    double devn;    
+    //find the absolute latency
+    lat=fabs(lat);
+    
+    if (latCount <  LATENCY_BUF_SIZE)
+         lastnumber = tempLatCounter+1;
+    else 
+        lastnumber = LATENCY_BUF_SIZE;
+    
+    
+    //calculate the cumulative sum of the latencies
+    latTotal+= lat;        
+    latencyBuffer[tempLatCounter] = lat;                     
+    
+    STlatencySum =0;
+    for (i=0; i<lastnumber; i++)
+    {
+        STlatencySum+= latencyBuffer[i];        
+    }
+    
+    STALatency = STlatencySum / lastnumber;
+    
+    //calculating jitter for the latencies in the buffer
+    
+    jitter =0;    
+    for (i=0; i<lastnumber; i++)
+    {
+        devn = fabs(latencyBuffer[i] - STALatency);
+        jitter+= devn;
+    }
+    jitter = jitter/lastnumber;        
+    
+    latCount++;
+    avgLat = (double)latTotal/(double)latCount;
+
+    if (tempLatCounter ==  LATENCY_BUF_SIZE -1)    
+        tempLatCounter =0;        
+    else
+        tempLatCounter++;
+}
+
+
+void QUANTAnet_socketbase_c :: calculateBurstiness (double bw)
+{
+    int i;
+    int lastnumber; 
+    double devn;    
+    //find the absolute bandwidth
+    bw = fabs(bw);
+    if (readCount)
+    {        
+        if (readCount <=  BANDWIDTH_BUF_SIZE)
+            lastnumber = tempBWCounter+1;
+        else 
+            lastnumber = BANDWIDTH_BUF_SIZE;
+        
+        bandwidthBuffer[tempBWCounter] = bw;    
+        
+        STbandwidthSum =0;
+        for (i=0; i<lastnumber; i++)
+        {
+            STbandwidthSum+= bandwidthBuffer[i];        
+        }
+    
+        STABandwidth = STbandwidthSum / lastnumber;
+        
+        //calculating burstiness for the bandwitdh values in the buffer
+        
+        burstiness =0;    
+        for (i=0; i<lastnumber; i++)
+        {
+            devn = fabs(bandwidthBuffer[i] - STABandwidth);
+            burstiness+= devn;
+        }
+        burstiness = burstiness/lastnumber;
+    }
+    
+    readCount++;
+
+    //Delay is calculated from the second packet onwards
+    if (readCount >1)
+    {
+        avgDelay = (double )(totalDelay /(readCount -1));
+        if (tempBWCounter == BANDWIDTH_BUF_SIZE -1)    
+            tempBWCounter = 0;        
+        else
+            tempBWCounter++;
+    }
+    else
+        avgDelay = 0;
+}
+
+int QUANTAnet_socketbase_c::getSocketId()
+{
+        printf("In Socketbase\n");
+        return 0;
+}
+
+int QUANTAnet_socketbase_c::selectSock(void * ptr, int *status, int numSocks, 
+ struct timeval * timeout)
+{
+	fd_set rset;
+	int maxfd=0;
+	int i, retval;
+
+	QUANTAnet_socketbase_c **arrayOfSocks = (QUANTAnet_socketbase_c**) ptr;
+	FD_ZERO(&rset);
+
+	for(i = 0; i < numSocks; i++)
+	{
+		if (arrayOfSocks[i]!= NULL)
+		{
+			FD_SET(arrayOfSocks[i]->getSocketId(), &rset);
+			if (arrayOfSocks[i]->getSocketId() > maxfd) 
+				maxfd = arrayOfSocks[i]->getSocketId();
+		}
+	}
+
+	retval = select(maxfd+1, &rset, NULL, NULL, timeout);
+
+	if (retval < 0)
+		return FAILED;
+
+	if (retval == 0)
+		return TIMED_OUT;
+
+	for(i = 0; i < numSocks; i++)
+	{
+		if (arrayOfSocks[i]!= NULL)
+		{
+			if(FD_ISSET(arrayOfSocks[i]->getSocketId(), &rset))
+				status[i] = 1;
+			else
+				status[i] = 0;
+		}
+	}
+	return OK;
+}
Index: trunk/src/testing/QUANTA/src/QUANTAnet_perfMonitor_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_perfMonitor_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_perfMonitor_c.cxx	(revision 4)
@@ -0,0 +1,262 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+
+#ifdef QUANTA_USE_PTHREADS
+#include <pthread.h>
+#endif
+       
+#include <errno.h>
+#include <string.h>
+
+#include "QUANTAnet_perfClient_c.hxx"
+#include "QUANTAnet_perfMonitor_c.hxx"
+
+const int QUANTAnet_perfMonitor_c::FAILED = 0;
+const int QUANTAnet_perfMonitor_c::OK = 1;
+
+const int _DEFAULT_PERF_BUFFER_SIZE = 1024;
+const int _STREAM_INFO_SIZE = 256;
+
+QUANTAnet_perfMonitor_c::QUANTAnet_perfMonitor_c()
+{
+    resultantStats = new char[_DEFAULT_PERF_BUFFER_SIZE];
+    resultantStats[0] = '\0';
+    selfIp = new char[_STREAM_INFO_SIZE];
+    remoteIp = new char[_STREAM_INFO_SIZE];
+    aClient = NULL;	
+}
+
+// css: The copy constructor is required due to operations like
+// QUANTAnet_udp_c::clone() which copy one class to another. By default, C++
+// only does a shallow copy. This means that the pointers are copied rather
+// than the values they contain. As a result, the cloned object can easily
+// lead to memory corruption. This copy constructor initializes the new
+// object and copies values from the original one.
+QUANTAnet_perfMonitor_c::QUANTAnet_perfMonitor_c(const QUANTAnet_perfMonitor_c& original)
+{
+  resultantStats = new char[_DEFAULT_PERF_BUFFER_SIZE];
+  resultantStats[0] = '\0';
+  selfIp = new char[_STREAM_INFO_SIZE];
+  remoteIp = new char[_STREAM_INFO_SIZE];
+
+  // With everything allocated, now do a deep copy.
+  aClient = original.aClient;
+  strncpy(selfIp, original.selfIp, _STREAM_INFO_SIZE);
+  strncpy(remoteIp, original.remoteIp, _STREAM_INFO_SIZE);
+}
+
+QUANTAnet_perfMonitor_c::~QUANTAnet_perfMonitor_c()
+{
+  if (resultantStats)
+    delete[] resultantStats;
+  if (selfIp)
+    delete[] selfIp;
+  if (remoteIp)
+    delete[] remoteIp;
+  if (aClient)
+    delete aClient;
+}
+
+void QUANTAnet_perfMonitor_c::setIPs(const char* _selfIp, const char* _remoteIp)
+{
+  if (_selfIp)
+    strncpy(this->selfIp, _selfIp, _STREAM_INFO_SIZE);
+
+  if (_remoteIp)
+    strncpy(this->remoteIp, _remoteIp, _STREAM_INFO_SIZE);
+}
+
+void QUANTAnet_perfMonitor_c::setPorts(int _selfPort, int _remotePort)
+{
+    selfPort = _selfPort;
+    remotePort = _remotePort;    
+}
+
+void QUANTAnet_perfMonitor_c::showStats(char* streamInfo, char* comment)
+{ 
+    //update the resultant buffer with the calculated information
+    updateStats(streamInfo, comment);
+    printf("\n%s\n", resultantStats);    
+}
+
+int QUANTAnet_perfMonitor_c::logStats(char* streamInfo, char* comment, FILE* filePtr)
+{
+	if (filePtr) {
+		//update the resultant buffer with the calculated information
+		updateStats(streamInfo, comment);
+  
+		if ((fprintf(filePtr, "%s\n", resultantStats)) != (strlen(resultantStats) + 1)) {
+			printf("\nWarning: Error writing to logfile - data may be truncated or  not written at all\n");
+			return QUANTAnet_perfMonitor_c::FAILED;
+		}    
+		fflush(filePtr);
+	}
+	else {
+	    printf("File pointer must be given to use logStats.\n");
+		return QUANTAnet_perfMonitor_c::FAILED;
+	}
+    return QUANTAnet_perfMonitor_c::OK;
+}
+
+int QUANTAnet_perfMonitor_c::initSendStats(const char* monitorClientIP, int port)
+{
+	if (monitorClientIP) {
+		if (aClient) {
+			delete aClient;
+			aClient = NULL;// close current connection first.
+		}
+		aClient = new QUANTAnet_perfDaemonClient_c;
+		if (aClient == NULL) {
+		    printf("Cannot create perfDaemonClient.\n");
+			return QUANTAnet_perfMonitor_c::FAILED;
+		}
+
+		if (aClient->connectToServer(monitorClientIP, port) == QUANTAnet_perfDaemonClient_c::FAILED) {
+			printf("\nCannot connect to perf_daemon\n");
+      		delete aClient;        
+			aClient = NULL;
+			return QUANTAnet_perfMonitor_c::FAILED;
+		}
+		int len = SEND_STAT_CLIENT_LENGTH + 1; // including terminating null char
+		if (aClient->write(SEND_STAT_CLIENT, &len) != QUANTAnet_perfDaemonClient_c::OK) {
+		    printf("Cannot connect to perf_daemon\n");
+			delete aClient;
+			aClient = NULL;
+			return QUANTAnet_perfMonitor_c::FAILED;
+		}
+	}
+	else {
+	    printf("Invalid ip address for perf_daemon is given. Please verify the address again.\n");
+		return QUANTAnet_perfMonitor_c::FAILED;
+	}
+    return QUANTAnet_perfMonitor_c::OK;
+}
+
+int QUANTAnet_perfMonitor_c::sendStats(char* streamInfo, char* comment)
+{
+	if (aClient == NULL) {
+		printf("PerfDaemonClient is not initialized. No data will be sent to perf_daemon\n");
+	    return QUANTAnet_perfMonitor_c::FAILED;
+	}
+
+	//update the resultant buffer with the calculated information
+	updateStats(streamInfo, comment);
+
+	int nbytes = strlen(resultantStats) + 1;
+
+	//transmitting data to perfdaemon    
+	int status = aClient->write(resultantStats, &nbytes);
+	if (status != QUANTAnet_perfDaemonClient_c::OK) {
+		aClient->showStatus(status, nbytes);
+		delete aClient;
+		aClient = NULL;
+		return QUANTAnet_perfMonitor_c::FAILED;
+	}
+
+    return QUANTAnet_perfMonitor_c::OK;
+}
+
+void QUANTAnet_perfMonitor_c::exitSendStats()
+{
+	if (aClient) {
+		delete aClient;
+		aClient = NULL;
+	}
+}
+
+void QUANTAnet_perfMonitor_c::updateStats(char* streamInfo, char* comment)
+{
+  //update the resultant stats buffer
+  if (resultantStats) {
+    char *tempStreamInfo, *tempComment;
+    char tempMsg[] = "NULL";
+
+    tempComment = (comment == NULL) ? tempMsg : comment;        
+    tempStreamInfo = (streamInfo == NULL) ? tempMsg : streamInfo;
+
+    // css: When copying into the resultantStats buffer, try to avoid a
+    // buffer overflow by limiting the operation with snprintf().
+#ifdef WIN32
+    _snprintf(resultantStats, _DEFAULT_PERF_BUFFER_SIZE,
+              "TIME=%lf SELF_IP=%s REMOTE_IP=%s SELF_PORT=%d " \
+              "REMOTE_PORT=%d STREAM_INFO=%s COMMENT=%s MIN_LAT=%lf " \
+              "AVG_LAT=%lf MAX_LAT=%lf INST_LAT=%lf STAL=%lf JITTER=%lf " \
+              "MIN_IMD=%lf AVG_IMD=%lf MAX_IMD=%lf INST_IMD=%lf " \
+              "AVG_RBW=%lf INST_RBW=%lf AVG_SBW=%lf INST_SBW=%lf " \
+              "STAB=%lf BURSTINESS=%lf TOTAL_READ=%d TOTAL_SENT=%d " \
+              "PACKETS_READ=%ld PACKETS_SENT=%ld", getTimeInSecs(),
+              selfIp, remoteIp, selfPort, remotePort, tempStreamInfo,
+              tempComment,  getMinLatency(), getAverageLatency(),
+              getMaxLatency(), getInstantLatency(), getSTALatency(),
+              getJitter(),  getMinInterMesgDelay(),
+              getAverageInterMesgDelay(), getMaxInterMesgDelay(),
+              getInstantInterMesgDelay(), getAverageReceiveBandwidth(),
+              getInstantReceiveBandwidth(),  getAverageSendBandwidth(),
+              getInstantSendBandwidth(), getSTABandwidth(),
+              getBurstiness(), getTotalDataRead(),  getTotalDataSent(),
+              getPacketsRead(), getPacketsSent());
+#else /* WIN32 */
+    snprintf(resultantStats, _DEFAULT_PERF_BUFFER_SIZE,
+             "TIME=%lf SELF_IP=%s REMOTE_IP=%s SELF_PORT=%d " \
+             "REMOTE_PORT=%d STREAM_INFO=%s COMMENT=%s MIN_LAT=%lf " \
+             "AVG_LAT=%lf MAX_LAT=%lf INST_LAT=%lf STAL=%lf JITTER=%lf " \
+             "MIN_IMD=%lf AVG_IMD=%lf MAX_IMD=%lf INST_IMD=%lf " \
+             "AVG_RBW=%lf INST_RBW=%lf AVG_SBW=%lf INST_SBW=%lf " \
+             "STAB=%lf BURSTINESS=%lf TOTAL_READ=%d TOTAL_SENT=%d " \
+             "PACKETS_READ=%ld PACKETS_SENT=%ld", getTimeInSecs(),
+             selfIp, remoteIp, selfPort, remotePort, tempStreamInfo,
+             tempComment,  getMinLatency(), getAverageLatency(),
+             getMaxLatency(), getInstantLatency(), getSTALatency(),
+             getJitter(),  getMinInterMesgDelay(),
+             getAverageInterMesgDelay(), getMaxInterMesgDelay(),
+             getInstantInterMesgDelay(), getAverageReceiveBandwidth(),
+             getInstantReceiveBandwidth(),  getAverageSendBandwidth(),
+             getInstantSendBandwidth(), getSTABandwidth(),
+             getBurstiness(), getTotalDataRead(),  getTotalDataSent(),
+             getPacketsRead(), getPacketsSent());
+#endif /* WIN32 */
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
Index: trunk/src/testing/QUANTA/src/QUANTAnet_iovec_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_iovec_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_iovec_c.cxx	(revision 4)
@@ -0,0 +1,144 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+/*
+ * File name: QUANTAnet_iovec.cxx
+ *
+ * Description: Wrapper class for the iovec structure
+ *
+ * Comments:
+ *
+ * Change Log:
+ */
+
+#include "QUANTAnet_iovec_c.hxx"
+
+//constructor
+QUANTAnet_iovec_c :: QUANTAnet_iovec_c(int size)
+{ 	
+	num_of_elements = 0; 						
+	nalloc = size; 
+	bufList = NULL;			
+}
+
+//destructor
+QUANTAnet_iovec_c :: ~QUANTAnet_iovec_c()
+{	
+	
+	if (bufList) {
+		free(bufList);
+		bufList = NULL;
+	}
+	 
+}
+
+//add pointer and its length to the array
+bool QUANTAnet_iovec_c :: add(void* buff, int length)
+{
+	if(bufList == NULL)
+	{
+#ifdef WIN32
+		bufList = (WSABUF *) malloc (sizeof (WSABUF) * nalloc);
+#else
+		bufList = (struct iovec*) malloc (sizeof (iovec) * nalloc);
+#endif
+
+		//if malloc can not allocate memory
+		if(bufList == NULL)
+		{
+			printf("QUANTAnet_iovec_c :: add() :: malloc - out of memory");
+			return false;
+		}		
+	}	
+	
+	else if(num_of_elements >= nalloc)		
+	{
+		nalloc = nalloc*2; //nalloc is doubled to reallocate twice number of elements									
+#ifdef WIN32
+		bufList = (WSABUF *)realloc((WSABUF *)bufList, nalloc * sizeof(WSABUF));	
+#else
+		bufList = (struct iovec*)realloc((iovec *)bufList, nalloc * sizeof(iovec));
+#endif
+
+		//if realloc can not allocate memory
+		if(bufList == NULL)
+		{
+			printf("QUANTAnet_iovec_c :: add() :: realloc - out of memory");			
+			return false;
+		}				
+	}
+		
+#ifdef WIN32
+	bufList[num_of_elements].buf = (char*)buff;
+	bufList[num_of_elements].len = length;	
+#else
+	bufList[num_of_elements].iov_base = (char *)buff;
+	bufList[num_of_elements].iov_len = length;
+#endif
+
+	++num_of_elements;				
+	return true;
+}
+
+//remove the entry at index
+bool QUANTAnet_iovec_c :: removeAt(int index)
+{		
+	--num_of_elements;
+	
+	if(index > num_of_elements)
+		return false;
+	else
+	{
+		for(int i = index; i < num_of_elements; i++)
+			bufList[i] = bufList[i + 1];	
+		return true;	
+	}
+}
+
+//clear the array
+void QUANTAnet_iovec_c :: removeAll()
+{
+	num_of_elements = 0;
+	bufList = NULL;
+	
+}
+//returns the size fo teh array
+int QUANTAnet_iovec_c :: size()
+{
+	return num_of_elements;
+}
+
+
+
+
Index: trunk/src/testing/QUANTA/src/QUANTAnet_tcp_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_tcp_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_tcp_c.cxx	(revision 4)
@@ -0,0 +1,1127 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#include "QUANTAnet_tcp_c.hxx"
+#include <string.h>
+
+#ifndef WIN32
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#ifndef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef errno
+extern int errno;
+#endif /* errno */
+#endif /* !WIN32 */
+
+#ifdef _WIN32_WCE
+#include <errno.h>
+#endif
+
+const int QUANTAnet_tcpServer_c::OK = 1;
+const int QUANTAnet_tcpServer_c::FAILED = 0;
+const int QUANTAnet_tcpServer_c::READ_BUFFER_SIZE = 2;
+const int QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE = 3;
+
+#ifdef sun
+long gethostid(void);
+#endif
+
+#ifdef WIN32
+#define MAXHOSTNAME   128   /* Maximum length of a DNS hostname */
+#define DEFAULT_BUFFER_SIZE 32766 /* Default socket bufffer size */
+#else
+#define DEFAULT_BUFFER_SIZE 1024
+#endif /* WIN32 */
+
+#ifdef WIN32
+// This function is excerpted from "Windows Sockets Network Programming"
+// by Bob Quinn and Dave Shute published from Addison-Wesley.
+static long gethostid(void)
+{
+	char szLclHost [MAXHOSTNAME];
+	LPHOSTENT lpstHostent;
+	SOCKADDR_IN stLclAddr;
+	SOCKADDR_IN stRmtAddr;
+	int nAddrSize = sizeof(SOCKADDR);
+	SOCKET hSock;
+	int nRet;
+
+	/* Init local address (to zero) */
+	stLclAddr.sin_addr.s_addr = INADDR_ANY;
+
+	/* Get the local hostname */
+	nRet = gethostname(szLclHost, MAXHOSTNAME); 
+	if (nRet != SOCKET_ERROR) {
+		/* Resolve hostname for local address */
+		lpstHostent = gethostbyname((LPSTR)szLclHost);
+		if (lpstHostent)
+			stLclAddr.sin_addr.s_addr = *((u_long FAR*) (lpstHostent->h_addr));
+	} 
+
+	/* If still not resolved, then try second strategy */
+	if (stLclAddr.sin_addr.s_addr == INADDR_ANY) {
+		/* Get a UDP socket */
+		hSock = socket(AF_INET, SOCK_DGRAM, 0);
+		if (hSock != INVALID_SOCKET)  {
+			/* Connect to arbitrary port and address (NOT loopback) */
+			stRmtAddr.sin_family = AF_INET;
+			stRmtAddr.sin_port   = htons(IPPORT_ECHO);
+			stRmtAddr.sin_addr.s_addr = inet_addr("128.127.50.1");
+			nRet = connect(hSock, (LPSOCKADDR)&stRmtAddr,
+						   sizeof(SOCKADDR));
+			if (nRet != SOCKET_ERROR) {
+				/* Get local address */
+				getsockname(hSock, (LPSOCKADDR)&stLclAddr, 
+							(int FAR*)&nAddrSize);
+			}
+			closesocket(hSock);   /* we're done with the socket */
+		}
+	}
+	return (stLclAddr.sin_addr.s_addr);
+}
+#endif
+
+QUANTAnet_tcpServer_c::QUANTAnet_tcpServer_c()
+{
+	/***** Open a TCP socket (an Internet stream socket). */
+	/* Notice we want Internet, stream socket and not datagram */
+#ifdef WIN32
+	if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET) {
+	        printf("QUANTAnet_tcpServer_c::FAILED. Cannot create socket\n");
+        }
+#else
+        if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
+                printf("QUANTAnet_tcpServer_c::FAILED. Cannot create socket\n");
+        }
+#endif
+
+	timeOutPeriod = QUANTAnet_tcpClient_c::DEFAULT_TIME_OUT;
+}
+
+int QUANTAnet_tcpServer_c::close()
+{
+  int closeResult;
+#ifdef WIN32
+	if (sockfd >= 0) closeResult = ::closesocket(sockfd);
+#else
+	if (sockfd >= 0) closeResult = ::close(sockfd);
+#endif
+	sockfd = 0;
+  return closeResult;
+}
+
+void QUANTAnet_tcpServer_c::setSockOptions(int option, int buffersize)
+{
+        /*Change the socket buffer size if default is not to be used*/
+        int optlen = sizeof(buffersize);
+
+        if (option == QUANTAnet_tcpServer_c::READ_BUFFER_SIZE)
+                if (setsockopt(sockfd,SOL_SOCKET, SO_RCVBUF, (char *) &buffersize, optlen) < 0)
+                        printf("QUANTAnet_tcpClient_c::setSockOptions: Cannot create a large enough socket buffer for Read.\n");
+
+        if (option == QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE)
+                if (setsockopt(sockfd,SOL_SOCKET, SO_SNDBUF, (char *) &buffersize, optlen) < 0)
+                        printf("QUANTAnet_tcpClient_c::setSockOptions: Cannot create a large enough socket buffer for Write.\n");
+}
+
+int QUANTAnet_tcpServer_c::init(int port)
+{
+	int optlen;
+
+	/* Set no delay to stop TCP/IP from buffering */
+	int noDelay = 0;// Set to 0 for no buffering. Set to 1 for buffering.
+	optlen = sizeof(noDelay);
+
+	if (setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY, (char *) &noDelay, optlen) < 0) 
+		printf("QUANTAnet_tcpServer_c::init: Cannot set no delay, you may experience sluggish performance.\n");
+
+	/* Use this to try to eliminate the problem of being unable to rebind to a static port */
+	int reuseFlag = 1;
+	optlen = sizeof(reuseFlag);
+	if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR, (char *) &reuseFlag, optlen) < 0) 
+		printf("QUANTAnet_tcpServer_c::init: Cannot reuse port address.\n");
+	/***** Bind our local address so that the client can send to us. */
+
+	struct linger lingerData;
+	lingerData.l_onoff = 1;
+	lingerData.l_linger = 1000;
+
+	optlen = sizeof(lingerData);
+	if (setsockopt(sockfd,SOL_SOCKET,SO_LINGER, (char *) &lingerData, optlen) < 0)
+		printf("QUANTAnet_tcpServer_c::init: setsockopt: SO_LINGER failed.\n");
+
+	/* Clear out the structure */
+	memset((char *) &serverInfo, 0, sizeof(serverInfo));
+
+	serverInfo.sin_family = AF_INET;
+	serverInfo.sin_addr.s_addr = htonl(INADDR_ANY);
+	serverInfo.sin_port = htons(port);
+
+	if (bind(sockfd, (struct sockaddr *) &serverInfo, sizeof(serverInfo)) < 0) {
+		printf("QUANTAnet_tcpServer_c::init: Can't bind local address.\n");
+		return QUANTAnet_tcpServer_c::FAILED;
+	}
+
+	/* Listen for a connection. Allow queuing for 5 connection requests.
+	 */
+	listen(sockfd,5);
+
+	/* Non blocking from now on. This is necessary in order for checkForNewConnections() to work.But this seems to be the main thing that is screwing up
+	   with threads.
+	 */
+	//	fcntl(sockfd,F_SETFL,FNDELAY);
+
+	return QUANTAnet_tcpServer_c::OK;
+}
+
+const int QUANTAnet_tcpClient_c::BLOCKING = 1;
+const int QUANTAnet_tcpClient_c::NON_BLOCKING= 2;
+const int QUANTAnet_tcpClient_c::NO_TIME_OUT = -1;
+const int QUANTAnet_tcpClient_c::DEFAULT_TIME_OUT = NO_TIME_OUT; 
+const int QUANTAnet_tcpClient_c::SOCKET_NOT_OPEN = -1;
+const int QUANTAnet_tcpClient_c::CONNECTION_TERMINATED = -2;
+const int QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA =-3;
+const int QUANTAnet_tcpClient_c::TIMED_OUT = -4;
+const int QUANTAnet_tcpClient_c::OK = 1;
+const int QUANTAnet_tcpClient_c::NON_BLOCKING_NOT_READY_TO_WRITE = -6;
+const int QUANTAnet_tcpClient_c::NOT_READY = -7;
+const int QUANTAnet_tcpClient_c::READY_TO_READ = -8;
+const int QUANTAnet_tcpClient_c::READY_TO_WRITE = -9;
+const int QUANTAnet_tcpClient_c::READY_TO_READ_AND_WRITE = -10;
+const int QUANTAnet_tcpClient_c::READ_BUFFER_SIZE = -11;  
+const int QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE = -12;
+
+QUANTAnet_tcpClient_c*
+QUANTAnet_tcpServer_c::checkForNewConnections(const int& blockingTime)
+{
+    struct sockaddr_in clientInfo;
+    #ifdef HAVE_SOCKLEN_T
+        socklen_t clilen;
+    #else
+        int clilen;
+    #endif
+    // Perform a non-blocking check to see if socket is ready for
+    // an incoming connection.
+    fd_set read_set;
+    struct timeval timeout;
+    timeout.tv_sec = blockingTime;
+    timeout.tv_usec = 0;
+    int ready_fd;
+
+    FD_ZERO(&read_set);
+    FD_SET(sockfd, &read_set);
+    ready_fd = select( sockfd+1, &read_set, NULL, NULL, &timeout);
+
+    // If it is not ready then return.
+    if ((ready_fd <= 0)  ||  (!FD_ISSET( sockfd, &read_set))) return NULL;
+
+    clilen = sizeof(clientInfo);
+    int newsockfd = accept(sockfd,
+                   (struct sockaddr *) &clientInfo,
+                   (socklen_t*)&clilen);
+    if (newsockfd > 0) {
+        struct linger lingerData;
+        lingerData.l_onoff = 1;
+        lingerData.l_linger = 1000;
+
+        int optlen = sizeof(lingerData);
+
+        if (setsockopt(newsockfd,SOL_SOCKET,SO_LINGER, (char *) &lingerData, optlen) < 0)
+            printf("QUANTAnet_tcpServer_c::checkForNewConnections: setsockopt: SO_LINGER failed.\n");
+
+        QUANTAnet_tcpClient_c *clientObj;
+
+        clientObj = new QUANTAnet_tcpClient_c;
+        clientObj->timeOutPeriod = timeOutPeriod;
+        clientObj->clientInfo = clientInfo;
+        clientObj->clientSockFd = newsockfd;
+        //      clientObj->makeNonBlocking();
+        return clientObj;
+    } else return NULL;
+}
+
+
+QUANTAnet_tcpClient_c*
+QUANTAnet_tcpServer_c::waitForNewConnection()
+{
+  struct sockaddr_in clientInfo;
+#ifdef HAVE_SOCKLEN_T
+  socklen_t clilen;
+#else
+  int clilen;
+#endif
+
+  // Perform a blocking check to see if socket is ready for an
+  // incoming connection.
+  fd_set read_set;
+  int ready_fd;
+
+  FD_ZERO(&read_set);
+  FD_SET(sockfd, &read_set);
+  ready_fd = select( sockfd+1, &read_set, NULL, NULL, NULL);
+
+  // If it is not ready then return.
+  if ((ready_fd <= 0)  ||  (!FD_ISSET( sockfd, &read_set))) return NULL;
+
+  clilen = sizeof(clientInfo);
+  int newsockfd = accept(sockfd,
+			 (struct sockaddr *) &clientInfo,
+			 (socklen_t*)&clilen);
+  if (newsockfd > 0) {
+    struct linger lingerData;
+    lingerData.l_onoff = 1;
+    lingerData.l_linger = 1000;
+
+    int optlen = sizeof(lingerData);
+
+    if (setsockopt(newsockfd, SOL_SOCKET, SO_LINGER,
+		   reinterpret_cast<char*>(&lingerData), optlen) < 0) {
+      printf("QUANTAnet_tcpServer_c::waitForNewConnection: setsockopt: SO_LINGER failed.\n");
+    }
+
+    QUANTAnet_tcpClient_c *clientObj = new QUANTAnet_tcpClient_c;
+    clientObj->timeOutPeriod = timeOutPeriod;
+    clientObj->clientInfo = clientInfo;
+    clientObj->clientSockFd = newsockfd;
+    return clientObj;
+  } else {
+    return NULL;
+  }
+}
+
+/*
+ * For the blockingtype parameter:
+ * NEVER_TIMEOUT_BLOCKING means the timeout period is bypassed so that it will
+ * continue to read forever unless there is a break in the connection.
+ *
+ * NON_BLOCKING means that if there is no data to be read this call will
+ * return immediately.
+ *
+ * BLOCKING means that it will block waiting for data or until the timeout
+ * period expires. 
+ * Change the timeout period (in seconds) by changing the timeoutPeriod
+ * member variable.
+ *
+ */
+
+void QUANTAnet_tcpClient_c::setSockOptions(int option, int buffersize)
+{
+	/*Change the socket buffer size if default is not to be used*/	
+	int optlen = sizeof(buffersize);
+
+	if (option == QUANTAnet_tcpClient_c::READ_BUFFER_SIZE)
+		if (setsockopt(clientSockFd,SOL_SOCKET, SO_RCVBUF, (char *) &buffersize, optlen) < 0)
+			printf("QUANTAnet_tcpClient_c::setSockOptions: Cannot create a large enough socket buffer for Read.\n");
+
+	if (option == QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE)
+		if (setsockopt(clientSockFd,SOL_SOCKET, SO_SNDBUF, (char *) &buffersize, optlen) < 0)
+			printf("QUANTAnet_tcpClient_c::setSockOptions: Cannot create a large enough socket buffer for Write.\n");
+
+}
+
+int QUANTAnet_tcpClient_c::isReadyToRead()
+{
+	struct timeval timeoutDelay;
+	fd_set readfds;
+
+	timeoutDelay.tv_sec = 0;
+	timeoutDelay.tv_usec = 0;
+
+	FD_ZERO(&readfds);
+	FD_SET(clientSockFd, &readfds);
+	select(clientSockFd+1,&readfds,NULL,NULL, &timeoutDelay);
+	
+	if (!(FD_ISSET(clientSockFd, &readfds)))
+		return NOT_READY;
+	else
+		return READY_TO_READ;
+}
+
+int QUANTAnet_tcpClient_c::isReadyToWrite()
+{
+	struct timeval timeoutDelay;
+	fd_set writefds;
+
+	timeoutDelay.tv_sec = 0;
+	timeoutDelay.tv_usec = 0;
+
+	FD_ZERO(&writefds);
+	FD_SET(clientSockFd, &writefds);
+	select(clientSockFd+1,NULL,&writefds,NULL, &timeoutDelay);
+	
+	if (!(FD_ISSET(clientSockFd, &writefds)))
+		return NOT_READY;
+	else
+		return READY_TO_WRITE;
+}
+
+int QUANTAnet_tcpClient_c::isReady()
+{
+	struct timeval timeoutDelay;
+	fd_set writefds, readfds;
+
+	timeoutDelay.tv_sec = 0;
+	timeoutDelay.tv_usec = 0;
+
+	FD_ZERO(&writefds);
+	FD_ZERO(&readfds);
+	FD_SET(clientSockFd, &writefds);
+	FD_SET(clientSockFd, &readfds);
+	select(clientSockFd+1,&readfds,&writefds,NULL, &timeoutDelay);
+	
+	if (FD_ISSET(clientSockFd, &writefds)
+	    &&
+	    FD_ISSET(clientSockFd, &readfds)) return READY_TO_READ_AND_WRITE;
+	if (FD_ISSET(clientSockFd, &writefds)) return READY_TO_WRITE;
+	if (FD_ISSET(clientSockFd, &readfds)) return READY_TO_READ;
+
+	return NOT_READY;
+}
+
+int QUANTAnet_tcpClient_c::read(char *ptr, int *nbytes, int blockingType)
+{
+
+    //used for bandwidth calculations
+ //   int totalDataRead =0;    
+
+	struct timeval timeoutDelay;
+	fd_set readfds;
+
+	if (clientSockFd < 0) {
+		printf("QUANTAnet_tcpClient_c::Read: This connection is not open.\n");
+		return SOCKET_NOT_OPEN;
+	}
+
+	int nleft, nread;
+	nleft = *nbytes;
+	timeOutStatus = 0;
+
+	while (nleft > 0) {
+
+        /*The totalDataRead is incremented  each time something is read - in case of an error 
+		this is passed on to the performance monitoring instance using the incrementDataRead() function 
+		for bandwidth calculations - to calculate the bandwidth for the data read till the break in loop*/
+
+        FD_ZERO(&readfds);
+		FD_SET(clientSockFd, &readfds);
+
+		if (blockingType == NON_BLOCKING) {
+			timeoutDelay.tv_sec = 0;
+			timeoutDelay.tv_usec = 0;
+		}
+		if (blockingType == BLOCKING) {
+			timeoutDelay.tv_sec = timeOutPeriod;
+			timeoutDelay.tv_usec = 0;
+		}
+
+		errno = 0;
+
+		// Wait for some file descriptor to be ready
+		// If no timeout then wait indefinitely until data arrives
+#ifdef WIN32
+		int error;
+
+		if ((blockingType == BLOCKING) &&
+			(timeOutPeriod == NO_TIME_OUT))
+				error = select(clientSockFd+1,&readfds,NULL,NULL, NULL);
+		else
+			error = select(clientSockFd+1,&readfds,NULL,NULL, &timeoutDelay);
+		if (error == SOCKET_ERROR) {
+			errno = WSAGetLastError();
+			return errno;
+		}
+#else
+		// This one may not work as it should be..
+		// Unix socket's man page doesn't say select will alter the
+		// value of errno...
+		if ((blockingType == BLOCKING) &&
+			(timeOutPeriod == NO_TIME_OUT))
+				select(clientSockFd+1,&readfds,NULL,NULL, NULL);
+		else
+			select(clientSockFd+1,&readfds,NULL,NULL, &timeoutDelay);
+		if (errno) {
+			return errno;
+		}
+#endif
+
+
+		// If fd is not set
+		if (!(FD_ISSET(clientSockFd, &readfds))) {
+			// If non blocking then it simply means there is no data.
+			if (blockingType == NON_BLOCKING) 
+				return NON_BLOCKING_HAS_NO_DATA;
+
+			// If blocking then timed out waiting for data.
+			if (blockingType == BLOCKING) {
+				timeOutStatus = 1;
+				return TIMED_OUT;
+			}
+
+		}
+
+		// If it passes this stage then things are set as blocking.
+		blockingType = BLOCKING;
+
+#ifdef WIN32
+		nread = ::recv(clientSockFd, ptr, nleft, 0);
+
+		if (nread == SOCKET_ERROR) {
+			*nbytes = nread;
+			errno = WSAGetLastError();
+			if (errno == WSAECONNRESET) 
+				return CONNECTION_TERMINATED;
+			return errno;
+		}
+#else
+		errno = 0;
+		nread = ::read(clientSockFd,ptr,nleft);
+
+		if (errno) {
+			*nbytes = nread;
+			return errno;
+		}
+#endif
+
+		if (nread == 0) {
+			*nbytes = (*nbytes - nleft);
+			return CONNECTION_TERMINATED;
+		}
+
+		if (nread > 0) {
+			nleft -= nread;
+			ptr += nread;
+            pmonitor.incrementDataRead(nread);
+		}
+
+	}
+	*nbytes = *nbytes - nleft;
+    return OK;
+}
+
+int QUANTAnet_tcpClient_c::write(const char *ptr, int  *nbytes, int blockingType)
+{
+    //used for bandwidth calculations
+//    int totalDataSent =0;
+
+	// Place here to prevent crashes when write occurs to a socket
+	// closed by an external source.
+#ifndef WIN32
+	signal(SIGPIPE,SIG_IGN);
+#endif
+
+	struct timeval timeoutDelay;
+	fd_set writefds;
+
+	if (clientSockFd < 0) {
+		printf("QUANTAnet_tcpClient_c::Write: This connection is not open.\n");
+		return SOCKET_NOT_OPEN;
+	}
+
+	int nleft, nwrite;
+	nleft = *nbytes;
+	timeOutStatus = 0;
+
+	while (nleft > 0) {
+		
+  /*The totalDataSent is incremented  each time something is written - in case of an error this is passed on to the performance monitoring instance using the incrementDataSent() function for bandwidth calculations - to calculate the bandwidth for the data written till the break in the loop*/
+
+        FD_ZERO(&writefds);
+		FD_SET(clientSockFd, &writefds);
+
+		if (blockingType == NON_BLOCKING) {
+			timeoutDelay.tv_sec = 0;
+			timeoutDelay.tv_usec = 0;
+		}
+		if (blockingType == BLOCKING) {
+			timeoutDelay.tv_sec = timeOutPeriod;
+			timeoutDelay.tv_usec = 0;
+		}
+
+		errno = 0;
+
+		// Wait for some file descriptor to be ready
+#ifdef WIN32
+		int error;
+
+		if ((blockingType == BLOCKING) &&
+			(timeOutPeriod == NO_TIME_OUT))
+			error = select(clientSockFd+1,NULL,&writefds,NULL, NULL);
+		else
+			error = select(clientSockFd+1,NULL,&writefds,NULL, &timeoutDelay);
+		if (error == SOCKET_ERROR) {
+			errno = WSAGetLastError();
+			return errno;
+		}
+#else
+		// This one may not work as it should be..
+		// Unix socket's man page doesn't say select will alter the
+		// value of errno...
+		if ((blockingType == BLOCKING) &&
+			(timeOutPeriod == NO_TIME_OUT))
+			select(clientSockFd+1,NULL,&writefds,NULL, NULL);
+		else
+			select(clientSockFd+1,NULL,&writefds,NULL, &timeoutDelay);
+		if (errno) {
+			return errno;
+		}
+#endif
+
+		// If fd is not set
+		if (!(FD_ISSET(clientSockFd, &writefds))) {
+
+			// If non blocking then it simply means there is no data.
+			if (blockingType == NON_BLOCKING) 
+				return NON_BLOCKING_NOT_READY_TO_WRITE;
+
+			// If blocking then timed out waiting for data.
+			if (blockingType == BLOCKING) {
+				timeOutStatus = 1;
+				return TIMED_OUT;
+			}
+		}
+
+
+		// If it passes this stage then things are set as blocking.
+		blockingType = BLOCKING;
+
+#ifdef WIN32
+		nwrite = ::send(clientSockFd, ptr, nleft, 0);
+        if (nwrite == SOCKET_ERROR) {
+		    *nbytes = nwrite;
+            errno = WSAGetLastError(); 
+		    return errno;
+		}
+#else
+		errno = 0;
+		nwrite = ::write(clientSockFd,ptr,nleft);
+
+		if (errno) {
+			*nbytes = nwrite;
+			return errno;
+		}
+#endif
+
+		if (nwrite == 0) {
+			*nbytes = (*nbytes - nleft);
+			return CONNECTION_TERMINATED;
+		}
+
+		if (nwrite > 0) {
+			nleft -= nwrite;
+			ptr += nwrite;
+            pmonitor.incrementDataSent(nwrite);
+		}
+
+	}
+	*nbytes = *nbytes - nleft;
+	return OK;
+
+}
+
+int  QUANTAnet_tcpClient_c::connectToServer(const char* ip, int port)
+{
+
+	char serverAddr[128];
+
+	int status = hostnameToIP(ip, serverAddr);
+	
+
+	if (status == 0) {
+		printf("QUANTAnet_tcpClient_c::Connect: Host IP address %s is invalid.\n", ip);
+		return -1;
+	}
+
+	/* Fill in the structure "clientInfo" with the address of the
+	 * server that we want to connect with.
+	 */
+
+
+
+	memset((char *) &clientInfo,0, sizeof(clientInfo));
+
+	clientInfo.sin_family = AF_INET;
+	clientInfo.sin_addr.s_addr = inet_addr(serverAddr);
+	clientInfo.sin_port = htons(port);
+
+	int optlen;
+
+	/* Set no delay to stop TCP/IP from buffering */
+	int noDelay = 1;
+	optlen = sizeof(noDelay);
+
+	if (setsockopt(clientSockFd,IPPROTO_TCP,TCP_NODELAY, (char *) &noDelay, optlen) < 0) 
+		printf("QUANTAnet_tcpClient_c::Open: Cannot set no delay, you may experience sluggish performance.\n");
+
+	/* Use this to try to eliminate the problem of being unable to rebind to a static port */
+	int reuseFlag = 1;
+	optlen = sizeof(reuseFlag);
+	if (setsockopt(clientSockFd,SOL_SOCKET,SO_REUSEADDR, (char *) &reuseFlag, optlen) < 0) 
+		printf("QUANTAnet_tcpClient_c::Open: Cannot reuse port address.\n");
+	/***** Bind our local address so that the client can send to us. */
+
+	struct linger lingerData;
+	lingerData.l_onoff = 1;
+	lingerData.l_linger = 1000;
+
+	optlen = sizeof(lingerData);
+	if (setsockopt(clientSockFd,SOL_SOCKET,SO_LINGER, (char *) &lingerData, optlen) < 0)
+		printf("QUANTAnet_tcpClient_c::Open: setsockopt: SO_LINGER failed.\n");
+
+	/* Connect to server. */
+    int connectResult;
+	if ((connectResult = connect(clientSockFd, (struct sockaddr *) &clientInfo, sizeof(clientInfo))) < 0) {
+		printf("QUANTAnet_tcpClient_c::Connect: Can't connect to server.\n");
+		return connectResult;
+	}
+	return clientSockFd;
+}
+
+void QUANTAnet_tcpClient_c::makeNonBlocking()
+{
+#ifdef __sgi
+	fcntl(clientSockFd, F_SETFL, FNDELAY);
+#endif
+#ifdef linux
+	fcntl(clientSockFd, F_SETFL, O_NONBLOCK);
+#endif
+#ifdef sun
+	fcntl(clientSockFd, F_SETFL, O_NDELAY);
+#endif
+#ifdef WIN32
+    u_long nonBlockingMode = 1L;
+
+    ioctlsocket(clientSockFd, FIONBIO, &nonBlockingMode);
+#endif
+}
+
+int QUANTAnet_tcpClient_c::close()
+{
+  int closeResult;
+#ifdef WIN32
+	if (clientSockFd > 0) closeResult = ::closesocket(clientSockFd);
+#else
+	if (clientSockFd > 0) closeResult = ::close(clientSockFd);
+#endif
+	clientSockFd = 0;
+  return closeResult;
+}
+
+QUANTAnet_tcpClient_c::QUANTAnet_tcpClient_c() {
+	timeOutPeriod = QUANTAnet_tcpClient_c::DEFAULT_TIME_OUT;
+	clientSockFd = 0;
+	#ifdef WIN32_WCE
+		clientSockFd = -1;
+	#endif
+
+	/* Open a TCP socket (an Internet stream socket). */
+#ifdef WIN32
+        if ((clientSockFd = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET) {
+                printf("QUANTAnet_tcpClient_c: Can't open stream socket.\n");
+        }
+#else
+        if ((clientSockFd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
+                printf("QUANTAnet_tcpClient_c: Can't open stream socket.\n");
+        }
+#endif
+
+}
+
+void QUANTAnet_tcpClient_c::showStatus(int status, int nbytes)
+{
+	switch (status) {
+	case SOCKET_NOT_OPEN:
+		printf("QUANTAnet_tcpClient_c::showStatus: Socket not open.\n");
+		break;
+	case CONNECTION_TERMINATED:
+		printf("QUANTAnet_tcpClient_c::showStatus: Connection terminated with %d bytes transacted.\n", nbytes);
+		break;
+	case NON_BLOCKING_HAS_NO_DATA:
+		printf("QUANTAnet_tcpClient_c::showStatus: Non-blocking read found no data on stream.\n");
+		break;
+	case NON_BLOCKING_NOT_READY_TO_WRITE:
+		printf("QUANTAnet_tcpClient_c::showStatus: Non-blocking connection is not ready to write.\n");
+		break;
+	case TIMED_OUT:
+		printf("QUANTAnet_tcpClient_c::showStatus: Transaction timed out after %d seconds.\n", timeOutPeriod);
+		break;
+		//	case NON_BLOCKING_WROTE_NO_DATA:
+		//		printf("Non-blocking write wrote no data.\n");
+		//		break;
+	case OK:
+		printf("QUANTAnet_tcpClient_c::showStatus: Transaction ok.\n");
+		break;
+	default:
+		printf("QUANTAnet_tcpClient_c::showStatus: UNIX Socket error no: %d\n ",errno);
+		//perror("");
+		break;
+	}
+	fflush(stdout);
+}
+
+
+unsigned int QUANTAnet_tcpClient_c :: getRemoteIP() {
+	return clientInfo.sin_addr.s_addr;
+}
+
+void QUANTAnet_tcpClient_c :: getRemoteIP(char* name)
+{
+	ipNumToString(getRemoteIP(),name);
+
+}
+
+int QUANTAnet_tcpClient_c :: getSelfPort() {
+	struct sockaddr_in name;
+    #ifdef HAVE_SOCKLEN_T
+        socklen_t size;
+    #else
+        int size;
+    #endif
+	size = sizeof(name);
+	getsockname (clientSockFd, (sockaddr *)&name, (socklen_t*)&size);
+	return ntohs(name.sin_port);
+}
+
+/* Get the port # of the client connection */
+int QUANTAnet_tcpClient_c :: getRemotePort() {
+	return ntohs(clientInfo.sin_port);
+}
+
+//Functions added for performance monitoring interface
+
+void QUANTAnet_tcpClient_c ::showStats(char* streamInfo, char* comment)
+{
+    char *selfIp = new char[256];
+    char *remoteIp = new char[256];   
+    QUANTAnet_socketbase_c::getSelfIP(selfIp);
+    getRemoteIP(remoteIp);
+    pmonitor.setIPs(selfIp, remoteIp);
+    pmonitor.setPorts(getSelfPort(), getRemotePort());
+    pmonitor.showStats(streamInfo, comment);
+    delete[] selfIp;
+    delete[] remoteIp;
+}
+
+int QUANTAnet_tcpClient_c ::logStats(char* streamInfo, char* comment, FILE* filePtr)
+{
+    char *selfIp = new char[256];
+    char *remoteIp = new char[256];   
+    QUANTAnet_socketbase_c::getSelfIP(selfIp);
+    getRemoteIP(remoteIp);
+    pmonitor.setIPs(selfIp, remoteIp);
+    pmonitor.setPorts(getSelfPort(), getRemotePort());
+    int result = pmonitor.logStats(streamInfo, comment, filePtr);
+    delete[] selfIp;
+    delete[] remoteIp;
+    return result;
+}
+
+
+int QUANTAnet_tcpClient_c::sendStats(char* streamInfo, char* comment)
+{
+    char *selfIp = new char[256];
+    char *remoteIp = new char[256];   
+    QUANTAnet_socketbase_c::getSelfIP(selfIp);
+    getRemoteIP(remoteIp);
+    pmonitor.setIPs(selfIp, remoteIp);
+    pmonitor.setPorts(getSelfPort(), getRemotePort());
+    int result = pmonitor.sendStats(streamInfo, comment);
+    delete[] selfIp;
+    delete[] remoteIp;
+    return result;
+}
+
+int QUANTAnet_tcpClient_c::initSendStats(const char* monitorClientIP, int port)
+{
+    return pmonitor.initSendStats(monitorClientIP, port);
+}
+
+void QUANTAnet_tcpClient_c::exitSendStats()
+{
+    pmonitor.exitSendStats();
+}
+
+void QUANTAnet_tcpClient_c::setInstantaneousLatency(double latency)
+{
+    pmonitor.setInstantLatency(latency);    
+}
+
+int QUANTAnet_tcpClient_c::getSocketId()
+{
+    return clientSockFd;
+}
+
+
+//Readv() method to read iovec
+
+int QUANTAnet_tcpClient_c::readv(QUANTAnet_iovec_c recv_iovec, int blockingType)
+{
+	struct timeval timeoutDelay;
+	fd_set readfds;
+
+	if (clientSockFd < 0) {
+		printf("QUANTAnet_tcpClient_c::Read: This connection is not open.\n");
+		return SOCKET_NOT_OPEN;
+	}
+
+	int nread;	
+	timeOutStatus = 0;
+
+
+    FD_ZERO(&readfds);
+	FD_SET(clientSockFd, &readfds);
+
+	if (blockingType == NON_BLOCKING) {
+		timeoutDelay.tv_sec = 0;
+		timeoutDelay.tv_usec = 0;
+	}
+	if (blockingType == BLOCKING) {
+		timeoutDelay.tv_sec = timeOutPeriod;
+		timeoutDelay.tv_usec = 0;
+	}
+
+	errno = 0;
+
+		// Wait for some file descriptor to be ready
+		// If no timeout then wait indefinitely until data arrives
+#ifdef WIN32
+	int error;
+
+	if ((blockingType == BLOCKING) &&
+		(timeOutPeriod == NO_TIME_OUT))
+			error = select(clientSockFd+1,&readfds,NULL,NULL, NULL);
+	else
+		error = select(clientSockFd+1,&readfds,NULL,NULL, &timeoutDelay);
+	if (error == SOCKET_ERROR) {
+		errno = WSAGetLastError();
+		return errno;
+	}
+#else
+	// This one may not work as it should be..
+	// Unix socket's man page doesn't say select will alter the
+	// value of errno...
+	if ((blockingType == BLOCKING) &&
+		(timeOutPeriod == NO_TIME_OUT))
+			select(clientSockFd+1,&readfds,NULL,NULL, NULL);
+	else
+		select(clientSockFd+1,&readfds,NULL,NULL, &timeoutDelay);
+	if (errno) {
+		return errno;
+	}
+#endif
+
+
+	// If fd is not set
+	if (!(FD_ISSET(clientSockFd, &readfds))) {
+		// If non blocking then it simply means there is no data.
+		if (blockingType == NON_BLOCKING) 
+			return NON_BLOCKING_HAS_NO_DATA;
+
+		// If blocking then timed out waiting for data.
+		if (blockingType == BLOCKING) {
+			timeOutStatus = 1;
+			return TIMED_OUT;
+		}
+
+	}
+
+	// If it passes this stage then things are set as blocking.
+	blockingType = BLOCKING;
+
+#ifdef WIN32
+	DWORD noOfBytesRecvd;
+	DWORD WSAFlags = 0;
+	nread = ::WSARecv(clientSockFd, recv_iovec.getBuffer(),recv_iovec.size(),&noOfBytesRecvd,&WSAFlags,NULL,NULL);
+
+	if (nread == SOCKET_ERROR) {
+		//*nbytes = nread;
+		errno = WSAGetLastError();
+		if (errno == WSAECONNRESET) 
+			return CONNECTION_TERMINATED;
+		return errno;
+	}
+	else
+	{
+		nread = noOfBytesRecvd;
+	}
+#else
+	errno = 0;	
+
+	nread = ::readv(clientSockFd, recv_iovec.getBuffer(), recv_iovec.size());
+			
+	if(errno != 0)		
+	{
+		perror("QUANTAnet_tcp_c :: readv - could not read");			
+		return errno;
+	}
+
+#endif
+
+	if (nread == 0) 
+	{
+		//*nbytes = (*nbytes - nleft);
+		return CONNECTION_TERMINATED;
+	}	
+
+	if (nread > 0) 
+	{
+      pmonitor.incrementDataRead(nread);
+	}
+
+	return OK;
+}
+
+//writev() method to write iovec
+
+int QUANTAnet_tcpClient_c::writev(QUANTAnet_iovec_c send_iovec, int blockingType)
+{
+
+#ifndef WIN32
+	signal(SIGPIPE,SIG_IGN);
+#endif
+
+	struct timeval timeoutDelay;
+	fd_set writefds;
+
+	if (clientSockFd < 0) {
+		printf("QUANTAnet_tcpClient_c::Writev: This connection is not open.\n");
+		return SOCKET_NOT_OPEN;
+	}
+	
+	int	nwrite;	
+	timeOutStatus = 0;	
+		
+  /*The totalDataSent is incremented  each time something is written - in case of an error this is passed on to the 
+	performance monitoring instance using the incrementDataSent() function for bandwidth calculations - 
+	to calculate the bandwidth for the data written till the break in the loop*/
+
+    FD_ZERO(&writefds);
+	FD_SET(clientSockFd, &writefds);
+
+	if (blockingType == NON_BLOCKING) {
+		timeoutDelay.tv_sec = 0;
+		timeoutDelay.tv_usec = 0;
+	}
+	if (blockingType == BLOCKING) {
+		timeoutDelay.tv_sec = timeOutPeriod;
+		timeoutDelay.tv_usec = 0;
+	}
+
+	errno = 0;
+
+		// Wait for some file descriptor to be ready
+#ifdef WIN32
+	int error;
+
+	if ((blockingType == BLOCKING) &&
+		(timeOutPeriod == NO_TIME_OUT))
+		error = select(clientSockFd+1,NULL,&writefds,NULL, NULL);
+	else
+		error = select(clientSockFd+1,NULL,&writefds,NULL, &timeoutDelay);
+	if (error == SOCKET_ERROR) {
+		errno = WSAGetLastError();
+		return errno;
+	}
+#else
+	// This one may not work as it should be..
+	// Unix socket's man page doesn't say select will alter the
+	// value of errno...
+	if ((blockingType == BLOCKING) &&
+		(timeOutPeriod == NO_TIME_OUT))
+		select(clientSockFd+1,NULL,&writefds,NULL, NULL);
+	else
+		select(clientSockFd+1,NULL,&writefds,NULL, &timeoutDelay);
+	if (errno) {
+		return errno;
+	}
+#endif
+
+	// If fd is not set
+	if (!(FD_ISSET(clientSockFd, &writefds))) {
+
+		// If non blocking then it simply means there is no data.
+		if (blockingType == NON_BLOCKING) 
+			return NON_BLOCKING_NOT_READY_TO_WRITE;
+
+		// If blocking then timed out waiting for data.
+		if (blockingType == BLOCKING) {
+			timeOutStatus = 1;
+			return TIMED_OUT;
+		}
+	}
+
+
+	// If it passes this stage then things are set as blocking.
+	blockingType = BLOCKING;
+
+#ifdef WIN32
+	DWORD noOfBytesSent;
+	DWORD WSAFlags = 0;
+
+	nwrite = ::WSASend(clientSockFd,send_iovec.getBuffer(),send_iovec.size(),&noOfBytesSent,WSAFlags,NULL,NULL);
+    if (nwrite == SOCKET_ERROR) {
+		//*nbytes = noOfBytesSent;
+        errno = WSAGetLastError(); 
+		return errno;
+	}
+	else {
+		nwrite = noOfBytesSent;
+	}
+#else
+	errno = 0;
+	nwrite = ::writev(clientSockFd, send_iovec.getBuffer(), send_iovec.size());
+
+	if (errno != 0) {
+		//*nbytes = nwrite;
+		return errno;
+	}
+#endif
+
+	if (nwrite == 0) 
+	{		
+		return CONNECTION_TERMINATED;
+	}		
+
+	if (nwrite > 0) 
+	{
+      pmonitor.incrementDataSent(nwrite);
+	}
+
+	return OK;
+}
+
Index: trunk/src/testing/QUANTA/src/QUANTAnet_datapack_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_datapack_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_datapack_c.cxx	(revision 4)
@@ -0,0 +1,937 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "QUANTAnet_datapack_c.hxx"
+
+const int QUANTAnet_datapack_c::FAILED = -1;
+const int QUANTAnet_datapack_c::OK = 0;
+
+/* 1. QUANTA_LITTLE_ENDIAN_FORMAT must be defined for all 
+      machines that uses little endian byte ordering scheme.
+      Most popular machines using little endian are Intel and
+      Alpha processor. 
+
+   2. Note that using different byte order is not dependent on
+      Operating system. It is closely tied to the processor type
+	  the system is based on. Thus, linux which runs on different
+	  processors may have different byte ordering scheme.
+
+   3. With a simple test program, it looks like that at least
+      Sparc machines from SUN, SGI, and Intel use the same 
+	  format to store the floating point values except they must
+	  be stored using different byte ordering scheme. Probably
+	  they are all following the IEEE standard to store all 
+	  floating point values.
+
+   4. Thus, if you want to port these functions to some other
+      platforms with different processors, you have to carefully
+	  check what format they are using to store floating point 
+	  values and how each byte is stored in memory for the specific
+	  processors.
+*/
+
+typedef union {
+	int value;
+	unsigned char bytes[INT_SIZE];
+} INT_VALUE;
+
+typedef union {
+	int32 value;
+	unsigned char bytes[INT32_SIZE];
+} INT32_VALUE;
+
+typedef union {
+	int64 value;
+	unsigned char bytes[INT64_SIZE];
+} INT64_VALUE;
+
+typedef union {
+	long value;
+	unsigned char bytes[LONG_SIZE];
+} LONG_VALUE;
+
+typedef union {
+    unsigned long value;
+    unsigned char bytes[UNSIGNED_LONG_SIZE];
+} UNSIGNED_LONG_VALUE;
+
+typedef union {
+	float value;
+	unsigned char bytes[FLOAT_SIZE];
+} FLOAT_VALUE;
+
+typedef union {
+	double value;
+	unsigned char bytes[DOUBLE_SIZE];
+} DOUBLE_VALUE;
+
+void QUANTAnet_datapack_c::initPack(char *buffer, int buffersize)
+{
+  if (buffer == NULL)
+    fprintf(stderr, "QUANTAnet_datapack_c::initPack WARNING: "
+            "buffer is NULL\n");
+	start = (unsigned char *) buffer;
+	running = (unsigned char *) buffer;
+	size = buffersize;
+}
+
+void QUANTAnet_datapack_c::initUnpack(char *buffer, int buffersize)
+{
+  if (buffer == NULL)
+    fprintf(stderr, "QUANTAnet_datapack_c::initUnpack WARNING: "
+            "buffer is NULL\n");
+	start = (unsigned char *) buffer;
+	running = (unsigned char *) buffer;
+	size = buffersize;
+}
+
+
+/// Floats 
+int QUANTAnet_datapack_c::packFloat(float val)
+{
+	FLOAT_VALUE oldVal;
+
+	if (checkspace(FLOAT_SIZE) != OK) return FAILED; // not enough buffer space
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	// reverse the order to make the format to BigEndian
+	for (i = FLOAT_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, FLOAT_SIZE);
+#endif // QUANTA_LITTLE_ENDIAN_FORMAT
+
+	running += FLOAT_SIZE; // increment the pointer
+	return OK;
+
+}
+
+/// Int
+int QUANTAnet_datapack_c::packInt(int val) 
+{
+
+	INT_VALUE oldVal;
+
+	if (checkspace(INT_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = INT_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, INT_SIZE);
+#endif
+
+	running += INT_SIZE;
+	return OK;
+}
+
+/// Int32
+int QUANTAnet_datapack_c::packInt32(int32 val) 
+{
+
+	INT32_VALUE oldVal;
+
+	if (checkspace(INT32_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = INT32_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, INT32_SIZE);
+#endif
+
+	running += INT32_SIZE;
+	return OK;
+}
+
+/// Long
+int QUANTAnet_datapack_c::packLong(long val) 
+{
+
+	LONG_VALUE oldVal;
+
+	if (checkspace(LONG_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = LONG_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, LONG_SIZE);
+#endif
+
+	running += LONG_SIZE;
+	return OK;
+}
+
+/// Unsigned long
+int QUANTAnet_datapack_c::packUnsignedLong(unsigned long val) 
+{
+
+	UNSIGNED_LONG_VALUE oldVal;
+
+	if (checkspace(UNSIGNED_LONG_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = UNSIGNED_LONG_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, UNSIGNED_LONG_SIZE);
+#endif
+
+	running += UNSIGNED_LONG_SIZE;
+	return OK;
+}
+
+
+
+/// Int64
+int QUANTAnet_datapack_c::packInt64(int64 val) 
+{
+	INT64_VALUE oldVal;
+
+	if (checkspace(INT64_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = INT64_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, INT64_SIZE);
+#endif
+
+	running += INT64_SIZE;
+	return OK;
+}
+
+/// Double
+int QUANTAnet_datapack_c::packDouble(double val)
+{
+
+	DOUBLE_VALUE oldVal;
+
+	if (checkspace(DOUBLE_SIZE) != OK) return FAILED;
+
+	oldVal.value = val;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+
+	for (i = DOUBLE_SIZE - 1, j = 0; i >= 0; i--, j++)
+		running[j] = oldVal.bytes[i];
+#else
+	memcpy(running, oldVal.bytes, DOUBLE_SIZE);
+#endif
+
+	running += DOUBLE_SIZE;
+	return OK;
+}
+
+
+/// Char
+int QUANTAnet_datapack_c::packChar(char val) 
+{
+
+	if (checkspace(CHAR_SIZE) != OK) 
+		return FAILED;
+
+	*running++ = (unsigned char) val;
+	return OK;
+}
+
+/// UNICODE Char
+#ifdef _WIN32_WCE
+int QUANTAnet_datapack_c::packChar(TCHAR val) // for unicode support
+{
+        if (checkspace(CHAR_SIZE) != OK)
+                return FAILED;
+
+        char newVal;
+
+        WideCharToMultiByte(CP_ACP, 0, &val, 1, &newVal, 1, NULL, NULL);
+        *running++ = (unsigned char) newVal;
+
+        return OK;
+}
+#endif  // _WIN32_WCE
+
+/*
+int QUANTAnet_datapack_c::packString(char* val)
+{
+  if (val == NULL)
+    return FAILED;
+
+  // Note that strlen() returns the length of the string exclude the
+  // terminating null character. The null value should be included
+  // during transmission, so add one to the size.
+  int stringSize = strlen(val) + 1;
+  int status = this->packInt(stringSize);
+  if (status == OK) {
+    status = this->pack(val, stringSize);
+  }
+  return status;
+}
+*/
+int QUANTAnet_datapack_c::pack(char* val, int sz)
+{
+  if ((checkspace(CHAR_SIZE * sz) != OK) || (val == NULL))
+    return FAILED;
+
+	memcpy(running, val, CHAR_SIZE * sz);
+	running += (CHAR_SIZE * sz);
+	return OK;
+}
+
+#ifdef _WIN32_WCE
+int QUANTAnet_datapack_c::pack(TCHAR* val, int sz)
+{
+  if ((checkspace(CHAR_SIZE * sz) != OK) || (val == NULL))
+    return FAILED;
+
+        WideCharToMultiByte(CP_ACP, 0, val, sz, (char *) running, sz, NULL, NULL);
+
+        running += (CHAR_SIZE * sz);
+        return OK;
+}
+#endif // _WIN32_WCE
+
+//pack an array of floats
+int QUANTAnet_datapack_c::packFloatArray(float* val, int sz)
+{
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+#endif
+
+	FLOAT_VALUE* oldArray = new FLOAT_VALUE[sz];       
+    if (checkspace(FLOAT_SIZE * sz) != OK) return FAILED;
+    //For each float, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= FLOAT_SIZE-1, j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, FLOAT_SIZE);
+        #endif        
+	    running += (FLOAT_SIZE);
+        
+     }
+    delete[] oldArray; 
+    return OK;
+}
+
+//pack an array of doubles
+int QUANTAnet_datapack_c::packDoubleArray(double* val, int sz)
+{
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+#endif
+
+    DOUBLE_VALUE* oldArray = new DOUBLE_VALUE[sz];       
+    if (checkspace(DOUBLE_SIZE * sz) != OK) return FAILED;
+    
+    //For each double, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= DOUBLE_SIZE-1, j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, DOUBLE_SIZE);
+        #endif        
+	    running += (DOUBLE_SIZE);
+        
+     }   
+    delete[] oldArray;
+    return OK;
+}
+
+//pack an array of int values
+int QUANTAnet_datapack_c::packIntArray(int* val, int sz)
+{
+
+	INT_VALUE* oldArray = new INT_VALUE[sz];       
+    if (checkspace(INT_SIZE * sz) != OK) return FAILED;
+   
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+#endif   
+    
+    //For each int value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= INT_SIZE-1, j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, INT_SIZE);
+        #endif        
+	    running += (INT_SIZE);
+        
+     }   
+    delete[] oldArray;
+    return OK;
+}
+
+//pack an array of int32 values
+int QUANTAnet_datapack_c::packInt32Array(int32* val, int sz)
+{
+	INT32_VALUE* oldArray = new INT32_VALUE[sz];       
+    if (checkspace(INT32_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+#endif
+    
+    //For each int32 value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= INT32_SIZE-1,j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, INT32_SIZE);
+        #endif        
+	    running += (INT32_SIZE);
+        
+     }   
+    delete[] oldArray;
+    return OK;
+}
+
+//pack an array of int64 values
+int QUANTAnet_datapack_c::packInt64Array(int64* val, int sz)
+{
+	INT64_VALUE* oldArray = new INT64_VALUE[sz];       
+    if (checkspace(INT64_SIZE * sz) != OK) return FAILED;
+    
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;   
+#endif
+
+    //For each int64 value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= INT64_SIZE-1, j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, INT64_SIZE);
+        #endif        
+	    running += (INT64_SIZE);
+        
+     }   
+    delete[] oldArray;
+    return OK;
+}
+
+//pack an array of long values
+int QUANTAnet_datapack_c::packLongArray(long* val, int sz)
+{
+	LONG_VALUE* oldArray = new LONG_VALUE[sz];       
+    if (checkspace(LONG_SIZE * sz) != OK) return FAILED;
+    
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;   
+#endif
+     
+    //For each long value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {
+        oldArray[count].value = val[count];
+        
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            for(i= LONG_SIZE-1, j=0; i>=0; i--, j++)
+                running[j] = oldArray[count].bytes[i];
+        #else
+            memcpy(running, oldArray[count].bytes, LONG_SIZE);
+        #endif        
+	    running += (LONG_SIZE);
+        
+     }   
+    delete[] oldArray;
+    return OK;
+}
+
+/// Float
+int QUANTAnet_datapack_c::unpackFloat(float *Answer) 
+{
+	FLOAT_VALUE newVal;
+
+	if (checkspace(FLOAT_SIZE) != OK) return FAILED; // not enough buffer space
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[FLOAT_SIZE];
+
+	memcpy(buffer, running, FLOAT_SIZE);
+
+	// reverse the order to make the format from BigEndian to LittleEndian
+	for (i = FLOAT_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, FLOAT_SIZE);
+#endif // QUANTA_LITTLE_ENDIAN_FORMAT
+
+	*Answer = newVal.value;
+	running += FLOAT_SIZE; // increment the pointer
+	return OK;
+}
+
+/// Int
+int QUANTAnet_datapack_c::unpackInt(int *Answer)
+{
+	INT_VALUE newVal;
+
+	if (checkspace(INT_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[INT_SIZE];
+
+	memcpy(buffer, running, INT_SIZE);
+
+	for (i = INT_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, INT_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += INT_SIZE;
+	return OK;
+}
+
+/// Int32
+int QUANTAnet_datapack_c::unpackInt32(int32 *Answer)
+{
+	INT32_VALUE newVal;
+
+	if (checkspace(INT32_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[INT32_SIZE];
+
+	memcpy(buffer, running, INT32_SIZE);
+
+	for (i = INT32_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, INT32_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += INT32_SIZE;
+	return OK;
+}
+
+/// Long
+int QUANTAnet_datapack_c::unpackLong(long *Answer)
+{
+	LONG_VALUE newVal;
+
+	if (checkspace(LONG_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[LONG_SIZE];
+
+	memcpy(buffer, running, LONG_SIZE);
+
+	for (i = LONG_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, LONG_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += LONG_SIZE;
+	return OK;
+}
+
+/// Unsigned Long
+int QUANTAnet_datapack_c::unpackUnsignedLong(unsigned long *Answer)
+{
+	UNSIGNED_LONG_VALUE newVal;
+
+	if (checkspace(UNSIGNED_LONG_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[UNSIGNED_LONG_SIZE];
+
+	memcpy(buffer, running, UNSIGNED_LONG_SIZE);
+
+	for (i = UNSIGNED_LONG_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, UNSIGNED_LONG_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += UNSIGNED_LONG_SIZE;
+	return OK;
+}
+
+int QUANTAnet_datapack_c::unpackInt64(int64 *Answer)
+{
+	INT64_VALUE newVal;
+
+	if (checkspace(INT64_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[INT64_SIZE];
+
+	memcpy(buffer, running, INT64_SIZE);
+
+	for (i = INT64_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, INT64_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += INT64_SIZE;
+	return OK;
+}
+
+/// Double
+int QUANTAnet_datapack_c::unpackDouble(double  *Answer)
+{
+	DOUBLE_VALUE newVal;
+
+	if (checkspace(DOUBLE_SIZE) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+	int i, j;
+	char buffer[DOUBLE_SIZE];
+
+	memcpy(buffer, running, DOUBLE_SIZE);
+
+	for (i = DOUBLE_SIZE - 1, j = 0; i >= 0; i--, j++)
+		newVal.bytes[j] = buffer[i];
+#else
+	memcpy(newVal.bytes, running, DOUBLE_SIZE);
+#endif
+
+	*Answer = newVal.value;
+	running += DOUBLE_SIZE;
+	return OK;
+}
+
+/// Char
+int QUANTAnet_datapack_c::unpackChar(char *Answer)
+{
+	if (checkspace(CHAR_SIZE) != OK) return FAILED;
+
+	*Answer = *running++;
+	return OK;
+}
+
+
+/// UNICODE Char
+#ifdef _WIN32_WCE
+int QUANTAnet_datapack_c::unpackChar(TCHAR *Answer)
+{
+  if (checkspace(CHAR_SIZE) != OK)
+    return FAILED;
+
+        MultiByteToWideChar(CP_ACP, 0, (char *) running, 1, Answer, 1);
+
+        running++;
+        return OK;
+}
+#endif // _WIN32_WCE
+/*
+int QUANTAnet_datapack_c::unpackString(char* answer, const int& sz)
+{
+  if (answer == NULL)
+    return FAILED;
+
+  int stringSize = 0;
+  int status = this->unpackInt(&stringSize);
+  if (status == OK) {
+    // Check to make sure that the answer buffer is large enough to
+    // unpack the string.
+    if (sz >= stringSize) {
+      status = this->unpack(answer, sz);
+    } else {
+      fprintf(stderr, "QUANTAnet_datapack_c::unpackString ERROR: "
+              "not enough room to unpack the string!\n");
+      status = FAILED;
+    }
+  }
+  return status;
+}
+*/
+int QUANTAnet_datapack_c::unpack(char *Answer, int sz)
+{
+  if ((checkspace(CHAR_SIZE * sz) != OK) || (Answer == NULL))
+    return FAILED;
+
+	memcpy(Answer, running, CHAR_SIZE * sz);
+	running += (CHAR_SIZE * sz);
+	return OK;
+}
+
+#ifdef _WIN32_WCE
+int QUANTAnet_datapack_c::unpack(TCHAR *Answer, int sz)
+{
+  if ((checkspace(CHAR_SIZE * sz) != OK) || (Answer == NULL))
+    return FAILED;
+
+        MultiByteToWideChar(CP_ACP, 0, (char *) running, sz, Answer, sz);
+
+        running += (CHAR_SIZE * sz);
+        return OK;
+}
+#endif // _WIN32_WCE
+
+//unpack an array of floats
+int QUANTAnet_datapack_c::unpackFloatArray(float* Answer, int sz)
+{
+	FLOAT_VALUE* newArray = new FLOAT_VALUE[sz];       
+    if (checkspace(FLOAT_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+    char buffer[FLOAT_SIZE];
+#endif
+
+    //For each float, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, FLOAT_SIZE);
+            for(i= FLOAT_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, FLOAT_SIZE);
+        #endif        
+	    running += (FLOAT_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+//unpack an array of doubles
+int QUANTAnet_datapack_c::unpackDoubleArray(double* Answer, int sz)
+{
+	DOUBLE_VALUE* newArray = new DOUBLE_VALUE[sz];       
+    if (checkspace(DOUBLE_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT    
+    int i,j;
+    char buffer[DOUBLE_SIZE];
+#endif
+
+    //For each value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, DOUBLE_SIZE);
+            for(i= DOUBLE_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, DOUBLE_SIZE);
+        #endif        
+	    running += (DOUBLE_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+//unpack an array of int values
+int QUANTAnet_datapack_c::unpackIntArray(int* Answer, int sz)
+{
+	INT_VALUE* newArray = new INT_VALUE[sz];       
+    if (checkspace(INT_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+    char buffer[INT_SIZE];
+#endif
+
+    //For each value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, INT_SIZE);
+            for(i= INT_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, INT_SIZE);
+        #endif        
+	    running += (INT_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+//unpack an array of int32 values
+int QUANTAnet_datapack_c::unpackInt32Array(int32* Answer, int sz)
+{
+	INT32_VALUE* newArray = new INT32_VALUE[sz];       
+    if (checkspace(INT32_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+    int i,j;
+    char buffer[INT32_SIZE];
+#endif
+ 
+    //For each value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, INT32_SIZE);
+            for(i= INT32_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, INT32_SIZE);
+        #endif        
+	    running += (INT32_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+//unpack an array of int64 values
+int QUANTAnet_datapack_c::unpackInt64Array(int64* Answer, int sz)
+{
+	INT64_VALUE* newArray = new INT64_VALUE[sz];       
+    if (checkspace(INT64_SIZE * sz) != OK) return FAILED;
+
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT 
+    int i,j;
+    char buffer[INT64_SIZE];
+#endif    
+    
+    //For each value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, INT64_SIZE);
+            for(i= INT64_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, INT64_SIZE);
+        #endif        
+	    running += (INT64_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+//unpack an array of long values
+int QUANTAnet_datapack_c::unpackLongArray(long* Answer, int sz)
+{
+	LONG_VALUE* newArray = new LONG_VALUE[sz];       
+    if (checkspace(LONG_SIZE * sz) != OK) return FAILED;
+    
+#ifdef QUANTA_LITTLE_ENDIAN_FORMAT    
+    int i,j;
+    char buffer[LONG_SIZE];
+#endif    
+    
+    //For each long value, copy the bytes and reverse the ordering for little endian conversion
+    for (int count=0; count<sz; count++)
+    {   
+        #ifdef QUANTA_LITTLE_ENDIAN_FORMAT
+            memcpy(buffer, running, LONG_SIZE);
+            for(i= LONG_SIZE-1, j=0; i>=0; i--, j++)
+                newArray[count].bytes[j] = buffer[i];
+        #else
+            memcpy(newArray[count].bytes, running, LONG_SIZE);
+        #endif        
+	    running += (LONG_SIZE); 
+        Answer[count] = newArray[count].value;
+     }   
+    delete[] newArray;
+    return OK;
+}
+
+int QUANTAnet_datapack_c::checkspace(unsigned int incoming_size)
+{
+	unsigned int remaining;
+
+	remaining = start + size - running;
+
+	if (remaining < incoming_size)
+		return FAILED;
+	else
+		return OK;
+}
Index: trunk/src/testing/QUANTA/src/Makefile
===================================================================
--- trunk/src/testing/QUANTA/src/Makefile	(revision 4)
+++ trunk/src/testing/QUANTA/src/Makefile	(revision 4)
@@ -0,0 +1,31 @@
+#
+#	Makefile for QUANTA SAGE version
+#	
+
+include ../../config.mk
+
+#MYFLAGS=-g -Wno-deprecated -fPIC -O3 -I../include $(SDL_CFLAGS) $(QUANTA_CFLAGS) $(GLEW_CFLAGS) $(GLSL_YUV_DEFINE) $(PORTAUDIO_CFLAGS)
+MYFLAGS=${SAGE_CFLAGS} -O3 -I../include  
+
+LIBS= -lpthread -lm -ldl $(SUN_LIBS)
+
+
+OBJS=QUANTAnet_tcp_c.o QUANTAnet_socketbase_c.o QUANTAnet_iovec_c.o QUANTAglobals.o QUANTAnet_perfMonitor_c.o QUANTAnet_perfDaemon_c.o QUANTAnet_perfClient_c.o QUANTAnet_datapack_c.o
+
+DIRT= *.o core core.* *.so 
+
+build: $(QUANTA_LIB)
+
+install: build
+	cp $(QUANTA_LIB) ../../lib
+
+clean:
+	rm -f $(DIRT)
+	cd ../../lib; rm -f $(QUANTA_LIB); cd ../QUANTA/src
+
+
+$(QUANTA_LIB): $(OBJS) 
+	$(COMPILER) $(SHLD_FLAGS) $(OBJS) $(LIBS) -o $(QUANTA_LIB)
+
+%.o : %.cxx 
+	$(COMPILER) $(MYFLAGS) -c -o $@ $<
Index: trunk/src/testing/QUANTA/src/QUANTAglobals.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAglobals.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAglobals.cxx	(revision 4)
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+#include "QUANTAglobals.hxx"
+
+#ifdef WIN32
+#ifndef __HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define __HAVE_WINSOCK2_H
+#endif /* __HAVE_WINSOCK2_H */
+#else
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#ifdef QUANTA_STRCASECMP 
+extern int strcasecmp(const char *first, const char *second) 
+{ 
+	while(*first && *second)
+	{ 
+		if(toupper((int)*first) != toupper((int)*second)) 
+			break; 
+		first++; 
+		second++; 
+	} 
+	return toupper((int)*first) - toupper((int)*second); 
+}
+#endif
+
+void QUANTAsleep(const unsigned int& seconds)
+{
+#ifdef WIN32
+  Sleep(seconds * 1000);
+#else
+#ifdef HAVE_SLEEP
+  sleep(seconds);
+#endif
+#endif
+}
+
+void QUANTAusleep(const unsigned int& microseconds)
+{
+#ifdef WIN32
+  Sleep(microseconds / 1000);
+#else
+#ifdef HAVE_USLEEP
+  usleep(microseconds);
+#endif
+#endif
+}
Index: trunk/src/testing/QUANTA/src/QUANTAnet_perfClient_c.cxx
===================================================================
--- trunk/src/testing/QUANTA/src/QUANTAnet_perfClient_c.cxx	(revision 4)
+++ trunk/src/testing/QUANTA/src/QUANTAnet_perfClient_c.cxx	(revision 4)
@@ -0,0 +1,315 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#include "QUANTAnet_perfClient_c.hxx"
+#include "QUANTAnet_datapack_c.hxx"
+#include "QUANTAnet_tcp_c.hxx"
+
+#include <string.h>
+#ifndef WIN32
+#include <sys/errno.h>
+#ifndef errno
+extern int errno;
+#endif /* errno */
+#endif
+
+const int QUANTAnet_perfDaemonClient_c::OK = 1;
+const int QUANTAnet_perfDaemonClient_c::FAILED = 2;
+const int QUANTAnet_perfDaemonClient_c::MEM_ALLOC_ERR = 3;
+const int QUANTAnet_perfDaemonClient_c::NON_BLOCKING_HAS_NO_DATA = 7;
+const int QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED=8;
+const int QUANTAnet_perfDaemonClient_c::NOT_READY=9;
+const int QUANTAnet_perfDaemonClient_c::READY_TO_READ=10;
+const int QUANTAnet_perfDaemonClient_c::READY_TO_WRITE=11;
+const int QUANTAnet_perfDaemonClient_c::READY_TO_READ_AND_WRITE=12;
+const int QUANTAnet_perfDaemonClient_c::BLOCKING=QUANTAnet_tcpClient_c::BLOCKING;
+const int QUANTAnet_perfDaemonClient_c::NON_BLOCKING=QUANTAnet_tcpClient_c::NON_BLOCKING;
+const int QUANTAnet_perfDaemonClient_c::NO_TIME_OUT=QUANTAnet_tcpClient_c::NO_TIME_OUT;
+
+QUANTAnet_perfDaemonClient_c :: QUANTAnet_perfDaemonClient_c(int isPerfClient)
+{
+	connectionAlive = 0;
+	client = new QUANTAnet_tcpClient_c;
+    perfClient = isPerfClient;
+	// Turn the timeout off. In general this is necessary because in a
+	// TCP stream if you lose some data you won't be able to figure out
+	// where the head of the next message will be.
+	if (client) client->setTimeOut(QUANTAnet_perfDaemonClient_c::NO_TIME_OUT);
+	timeOut = QUANTAnet_perfDaemonClient_c::NO_TIME_OUT;
+}
+
+QUANTAnet_perfDaemonClient_c::QUANTAnet_perfDaemonClient_c(QUANTAnet_tcpClient_c *aclient, int isPerfClient)
+{
+	connectionAlive = 1;
+	client = aclient;
+    perfClient = isPerfClient;
+	if (client) client->setTimeOut(QUANTAnet_perfDaemonClient_c::NO_TIME_OUT);
+	timeOut = QUANTAnet_perfDaemonClient_c::NO_TIME_OUT;
+}
+
+void QUANTAnet_perfDaemonClient_c :: setTimeOut(int timeout)
+{
+	if (client) {
+		client->setTimeOut(timeout);
+		timeOut =  timeout;
+	}
+}
+
+QUANTAnet_perfDaemonClient_c :: ~QUANTAnet_perfDaemonClient_c()
+{
+	if (client)
+		delete client;
+}
+
+int QUANTAnet_perfDaemonClient_c :: connectToServer(const char *ip, int port)
+{
+	if (client && (client->connectToServer(ip,port) >= 0)) {
+		connectionAlive = 1;
+
+		if (perfClient) {
+            int len = strlen(REGISTER_PERF_CLIENT) + 1;
+
+            if (write(REGISTER_PERF_CLIENT, &len) != QUANTAnet_perfDaemonClient_c::OK) {
+			    printf("Cannot connect to perf_daemon\n");
+				connectionAlive = 0;
+				return QUANTAnet_perfDaemonClient_c::FAILED;
+			}
+        }
+
+		return QUANTAnet_perfDaemonClient_c::OK;
+	} 
+	else {
+	    printf("Cannot connect to perf_daemon\n");
+		connectionAlive = 0;
+		return QUANTAnet_perfDaemonClient_c::FAILED;
+	}
+}
+
+
+int QUANTAnet_perfDaemonClient_c :: read(char **ret, int *nbytes, int blockingType)
+{
+	if (connectionAlive == 0 || client == NULL) return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+	
+	QUANTAnet_datapack_c packer;
+	char *read_buffer;
+	int dataSize;
+	int status;
+//	char header[sizeof(int)];
+
+	// Read the header.	
+	dataSize = packer.sizeof_int();
+	read_buffer = new char[dataSize];
+	status = client->read((char*) read_buffer, &dataSize, blockingType);
+	if (status == QUANTAnet_tcpClient_c::OK)  {                                                     
+		// The header is simply the # of bytes that follows.
+		int incomingSize = 0;
+                                                  
+	    packer.initUnpack((char *)read_buffer,dataSize);
+		packer.unpackInt(&incomingSize);
+	    delete[] read_buffer;                           
+
+		char *buffer = new char[incomingSize];
+		if (buffer == NULL) {
+			*ret = NULL;
+			connectionAlive = 0;
+			return QUANTAnet_perfDaemonClient_c::MEM_ALLOC_ERR;
+		}
+
+		// Read the body
+		status = client->read(buffer, &incomingSize, QUANTAnet_tcpClient_c::BLOCKING);
+		if (status == QUANTAnet_tcpClient_c::OK)  {
+			*nbytes = incomingSize;
+			*ret = buffer;
+			return QUANTAnet_perfDaemonClient_c::OK;
+		} else {
+			connectionAlive = 0;
+			*nbytes = 0;
+			delete[] buffer;
+			*ret = NULL;
+			if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED)
+				return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+			else
+				return QUANTAnet_perfDaemonClient_c::FAILED;
+		}
+	}
+
+	if (read_buffer)
+		delete[] read_buffer;
+	*nbytes = 0;
+	*ret = NULL;
+	if (status == QUANTAnet_tcpClient_c::NON_BLOCKING_HAS_NO_DATA) 
+		return QUANTAnet_perfDaemonClient_c::NON_BLOCKING_HAS_NO_DATA;
+	if (status == QUANTAnet_tcpClient_c::CONNECTION_TERMINATED) {
+		connectionAlive = 0;
+		return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+	}
+	if (status == QUANTAnet_tcpClient_c::TIMED_OUT) {
+		connectionAlive = 0;
+		return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+	}
+
+	return QUANTAnet_perfDaemonClient_c::FAILED;
+
+}
+
+
+int QUANTAnet_perfDaemonClient_c :: write(const char *ptr, int *nbytes)
+{
+	QUANTAnet_datapack_c packer;
+	char *send_buffer;
+
+	if (connectionAlive == 0 || client == NULL) return QUANTAnet_perfDaemonClient_c::FAILED;
+
+	int  dataSize = packer.sizeof_int();
+	int status;
+
+	// Send the header
+	send_buffer = new char[dataSize];
+	packer.initPack(send_buffer, dataSize);
+	packer.packInt(*nbytes);
+	status = client->write(send_buffer,&dataSize,QUANTAnet_tcpClient_c::BLOCKING);
+	delete[] send_buffer;
+	if (status != QUANTAnet_tcpClient_c::OK) {
+		connectionAlive = 0;
+		return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+	}
+				
+	status = client->write(ptr, nbytes, QUANTAnet_tcpClient_c::BLOCKING);
+	if (status != QUANTAnet_tcpClient_c::OK) {
+		connectionAlive = 0;
+		return QUANTAnet_perfDaemonClient_c::CONNECTION_TERMINATED;
+	}
+
+	return QUANTAnet_perfDaemonClient_c::OK;
+}
+
+int QUANTAnet_perfDaemonClient_c :: isReadyToRead()
+{
+
+	if (connectionAlive == 0 || client == NULL) return QUANTAnet_perfDaemonClient_c::NOT_READY;
+
+	int status= client->isReadyToRead();
+
+	if (QUANTAnet_tcpClient_c::READY_TO_READ == status)
+		return QUANTAnet_perfDaemonClient_c::READY_TO_READ;
+
+	else //we got QUANTAnet_tcpClient_c::NOT_READY
+		return QUANTAnet_perfDaemonClient_c::NOT_READY;
+}
+
+
+int QUANTAnet_perfDaemonClient_c :: isReadyToWrite() {
+
+	if (connectionAlive == 0 || client == NULL) return QUANTAnet_perfDaemonClient_c::NOT_READY;
+
+	int status =  client->isReadyToWrite();
+
+	if (QUANTAnet_tcpClient_c::READY_TO_WRITE == status)
+		return QUANTAnet_perfDaemonClient_c::READY_TO_WRITE;
+
+	else // we got QUANTAnet_tcpClient_c::NOT_READY
+		return QUANTAnet_perfDaemonClient_c::NOT_READY;
+
+
+}
+
+int QUANTAnet_perfDaemonClient_c :: isReady() {
+
+	if (connectionAlive == 0 || client == NULL) return QUANTAnet_perfDaemonClient_c::NOT_READY;
+
+	int status =  client->isReady();
+
+	if (QUANTAnet_tcpClient_c::READY_TO_READ == status)
+		return QUANTAnet_perfDaemonClient_c::READY_TO_READ;
+
+	else if (QUANTAnet_tcpClient_c::READY_TO_WRITE == status)
+		return QUANTAnet_perfDaemonClient_c::READY_TO_WRITE;
+
+	else if (QUANTAnet_tcpClient_c::READY_TO_READ_AND_WRITE == status)
+		return QUANTAnet_perfDaemonClient_c::READY_TO_READ_AND_WRITE;
+
+	else //we got QUANTAnet_tcpClient_c::NOT_READY
+		return QUANTAnet_perfDaemonClient_c::NOT_READY;
+
+}
+
+void QUANTAnet_perfDaemonClient_c::showStatus(int status, int nbytes)
+{
+	switch (status) {
+	case CONNECTION_TERMINATED:
+		printf("QUANTAnet_perfDaemonClient_c::showStatus: Connection terminated with %d bytes transacted.\n", nbytes);
+		break;
+	case NON_BLOCKING_HAS_NO_DATA:
+		printf("QUANTAnet_perfDaemonClient_c::showStatus: Non-blocking read found no data on stream.\n");
+		break;
+	case OK:
+		printf("QUANTAnet_perfDaemonClient_c::showStatus: Transaction ok.\n");
+		break;
+	default:
+#ifdef WIN32
+		printf("QUANTAnet_perfDaemonClient_c::showStatus: UNIX Socket error no: %d ",WSAGetLastError());
+#else
+		printf("QUANTAnet_perfDaemonClient_c::showStatus: UNIX Socket error no: %d ",errno);
+		perror("");
+#endif
+		break;
+	}
+	fflush(stdout);
+}
+
+unsigned int QUANTAnet_perfDaemonClient_c::getRemoteIP() 
+{ 
+	return (client) ? client->getRemoteIP() : 0; 
+};
+
+void QUANTAnet_perfDaemonClient_c::getRemoteIP(char* name) 
+{ 
+	if (client) client->getRemoteIP(name); 
+}
+
+int QUANTAnet_perfDaemonClient_c::getSelfPort() 
+{ 
+	return (client) ? client->getSelfPort() : 0; 
+}
+
+int QUANTAnet_perfDaemonClient_c::getRemotePort() 
+{ 
+	return (client) ? client->getRemotePort() : 0; 
+}
+
+void QUANTAnet_perfDaemonClient_c::close() 
+{ 
+	connectionAlive = 0; 
+	if (client) client->close(); 
+}
Index: trunk/src/testing/QUANTA/include/QUANTAnet_perfDaemon_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_perfDaemon_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_perfDaemon_c.hxx	(revision 4)
@@ -0,0 +1,191 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTAPLUS_PERF_DAEMON_C
+#define _QUANTAPLUS_PERF_DAEMON_C
+
+#ifndef __HAVE_STDIO_H
+#include <stdio.h>
+#define __HAVE_STDIO_H
+#endif
+
+#include "QUANTAnet_perfClient_c.hxx"
+
+class QUANTAnet_tcpServer_c;
+
+struct PerfDaemonClient
+{
+    QUANTAnet_perfDaemonClient_c *Client;
+    int IsPerfClient;
+    int Started;
+};
+
+/** QUANTA performance monitoring daemon class. This class treats TCP 
+streams as discrete packets/messages that can be reflected to multiple 
+connected performance monitoring clients. Clients must be created using 
+QUANTAnet_perfDaemonClient_c. Hence do NOT attempt to use 
+QUANTAnet_tcpClient_c to connect to a perf daemon class. This class has 
+2 main functions: checkForNewClients() and process(). checkForNewClients, 
+as the name suggests, checks to see if any new clients wish to connect 
+to the reflector. Process() does the actual work of data reflection.
+
+checkForNewClients is called everytime process() is called. If you want 
+the check to be done more frequently you need to do it yourself. Similarly 
+if you want the process() call done more frequently it is up to you to do it. 
+I recommend threading those two off and setting up a mutex so that you do 
+not do process() and checkForNewClients() at the same time.
+
+@author cavern@evl.uic.edu
+@version 3/28/2000
+
+*/
+class QUANTAnet_perfDaemon_c
+{
+public:
+        /**
+        Constructor of performance monitoring daemon class. 
+      
+        @param File
+        Optional parameter. If file pointer is given here, it will be used 
+        to save all log information.
+        */
+	QUANTAnet_perfDaemon_c(FILE* File = NULL);
+	~QUANTAnet_perfDaemon_c();
+
+	//@{
+	/// Status ok.
+	static const int OK/* = 0*/;
+
+	/// Status failed.
+	static const int FAILED/* = 1*/;
+
+	/// Memory allocation error.
+	static const int MEM_ALLOC_ERR/* = 2*/;
+
+	/// New client has been connected.
+	static const int NEW_CONNECTION_ESTABLISHED/* = 4*/;
+
+	/// Reflector cannot handle any more connections
+	static const int TOO_MANY_CLIENTS/* = 5*/;
+
+	/// No new connection.
+	static const int NO_NEW_CONNECTION/* = 6*/;
+
+	/// A non-blocking read had no data available to read.
+	static const int NON_BLOCKING_HAS_NO_DATA/* = 7*/;
+
+	/// Skip the data distribution process. Used in user callback. See intercept().
+	static const int SKIP_DISTRIBUTION/* = 8*/;
+
+	static const int DEFAULT_PORT/* = 9500*/;
+	//@}
+
+	/** Initialize the reflector.
+	    @param incomingPort is listening port for incoming connections. Default is 7000.
+	    @param maxClients is the max number of clients the reflector will manage.
+	    @return Either QUANTAnet_perfDaemon_c::OK,FAILED,MEM_ALLOC_ERR.
+	 */
+	int init(int incomingPort=PERF_DAEMON_DEFAULT_PORT, int maxClients = 64);
+
+	/** Call this within a while loop to let the reflector continuously
+	    do its processing.
+	    @return Either QUANTAnet_perfDaemon_c::OK,MEM_ALLOC_ERR
+	*/
+	int process();
+
+	/** Call this as often as you wish to check for new clients.
+	    Note. If you do this in a separate thread then you must set up a mutex
+	    so that you do not call the proces() call and this call at the same time.
+	    The process() call itself has imbedded in it 1 check for each time you
+	    call it.
+	    @return Either QUANTAnet_perfDaemon_c::NEW_CONNECTION_ESTABLISHED, NO_NEW_CONNECTION, TOO_MANY_CLIENTS.
+	*/
+	int checkForNewClients();
+
+	/** Intercept incoming messages and call a user-defined callback function.
+	    If you want you can also alter the buffer completely so that the reflector will reflect an
+	    entirely different message. You can do this by changing the contents of the buffer or
+	    by replacing the buffer entirely by allocating memory for a new buffer and stuffing it
+	    with your own data. If you choose to allocate a totally new buffer you must remember
+	    to deallocate memory for the original
+	    buffer before substituting it with yours.
+
+	    If after your callback function exits you do not wish the reflector to forward
+	    the contents of the buffer, return with QUANTA_tcpReflector_c::SKIP_DISTRIBUTION. Otherwise
+	    just return QUANTA_tcpReflector_c::OK.
+
+	    Note also that the callback function will also be given a pointer to a
+	    QUANTAnet_perfDaemonClient_c object that
+	    can then be used to send data directly to the client that originally sent the message.
+	*/
+	void intercept(int (*callback) (QUANTAnet_perfDaemonClient_c *client, char** buffer, 
+		                            int *bufferSize,  void *userData), void* userData);
+
+	/** Intercept any new connections that are formed.
+	    This allows you to send private data to the newly formed connection before it assumes its data
+	    reflection duties.
+	    Callback function will be given a pointer to the QUANTAnet_perfDaemonClient_c object that
+	    can then be used to send data directly to the client.
+	*/
+	void interceptNewConnection(void (*callback) (QUANTAnet_perfDaemonClient_c *newClient, void* userData), void *userData);
+
+        int sendToAll(char* buf, int incomingSize);
+
+private:
+	PerfDaemonClient **clients;
+	QUANTAnet_tcpServer_c *server;
+	unsigned short incomingPort;
+	FILE* LogFile;
+
+	int (*interceptCallback) (QUANTAnet_perfDaemonClient_c *newClient, char** buffer, 
+		                      int* bufsize, void *userData);
+	void *interceptUserData;
+
+	void (*interceptNewConnectionCallback) (QUANTAnet_perfDaemonClient_c *newClient, void *userData);
+	void *interceptNewConnectionUserData;
+
+	// Distribute the data to all connected performance monitoring clients.
+	// Specify -1 if want to send to all.
+	int distributeDataToPerfClients(char* buf, int incomingSize);
+
+	// Remove a client from the client array.
+	void removeClient(int clientNum);
+
+	// Close all client sockets and remove them. Used by destructor.
+	// Also closes down and deallocates the server.
+	void closeDownSockets();
+	int maxNumClients;
+};
+
+#endif
Index: trunk/src/testing/QUANTA/include/QUANTAnet_socketbase_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_socketbase_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_socketbase_c.hxx	(revision 4)
@@ -0,0 +1,232 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTAPLUS_SOCKETBASE_C
+#define _QUANTAPLUS_SOCKETBASE_C
+
+#ifndef _WIN32_WCE
+   #include <fcntl.h>
+#endif
+
+#ifdef WIN32
+#ifndef __HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define __HAVE_WINSOCK2_H
+#endif /* __HAVE_WINSOCK2_H */
+#else
+#ifndef __HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#define __HAVE_ARPA_INET_H
+#endif
+#ifndef __HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#define __HAVE_ARPA_INET_H
+#endif
+#endif /* WIN32 */
+
+#include "QUANTAglobals.hxx"
+
+//These are the number of packets for which all calculations are done -
+//this is to be changed as desired
+
+#define LATENCY_BUF_SIZE 100
+#define BANDWIDTH_BUF_SIZE 100
+
+/** A base level socket class subclassed by QUANTAnet_tcp_c, QUANTAnet_udp_c, QUANTAnet_mcast_c, QUANTAnet_parallelTcp_c,  and QUANTAnet_perfMonitor_c. The class itself does no networking. It provides some common member functions that are useful for network coding. In general one does not create an instance of this type.
+
+    This class also offers information about the bandwidth, latency, Inter-Message_delay, Jitter and Burstiness values associated with the individual socket connections. Latency and Jitter calculations are offered only if the individual subclasses have implemented and enabled it. Otherwise values will be zero.
+ These calculations are used by the QUANTAnet_perfMonitor_c class
+*/
+
+class QUANTAnet_socketbase_c {
+public:
+
+	///Socketbase class return values
+	//@{
+	/// Operation went ok
+	static const int OK/* = 1*/;
+	/// Operation failed
+	static const int FAILED/* = 0*/;
+	/// Operation timed out
+	static const int TIMED_OUT/* = 2 */;
+	//@}
+
+	QUANTAnet_socketbase_c();
+  virtual ~QUANTAnet_socketbase_c() {}
+
+	/// Convert a hostname to an ip address of xxx.xxx.xxx.xxx
+	static int hostnameToIP(const char* hostname, char* hostIP);
+
+	/// Convert ip address to a string of xxx.xxx.xxx.xxx
+	static void ipNumToString(unsigned int ip, char* ipstring);
+
+	/// Get time in secs with microsecond accuracy
+	static double getTimeInSecs();
+
+	/// Get the full host name of a local client
+	static void getHostName(char* name, int len);
+
+	/// If hostname is not fully expanded (ie does not include its domain) then expand it.
+	static void expandHostName(const char* src, char* newname, int len);
+
+	/// Get the host IP address as a long integer.
+	static long getSelfIP();
+
+	/// Get the host IP address as a character string.
+	static void getSelfIP(char*);
+
+	/// Get the total data sent by a connection.
+	unsigned int getTotalDataSent();
+
+	/// Get total data received by a connection.
+	unsigned int getTotalDataRead();
+
+	/// Get total instantaneous incoming bandwidth by a connection.
+	double getInstantReceiveBandwidth();
+
+	/// Get total instantaneous outgoing bandwidth by a connection.
+	double getInstantSendBandwidth();
+
+	/// Get average incoming bandwidth by a connection.
+	double getAverageReceiveBandwidth();
+
+	/// Get average outgoing bandwidth by a connection.
+	double getAverageSendBandwidth();
+
+    ///Set the instantaneous latency and also calculate the STALatency and Jitter values automatically
+	void setInstantLatency(double lat);
+
+	/// Retrieve most recent incoming packet's latency.
+	double getInstantLatency();
+
+	/// Retrieve average incoming latency.
+	double getAverageLatency();
+
+	/// Retrieve max latency so far.
+	double getMaxLatency();
+
+	/// Retrieve min latency so far.
+	double getMinLatency();
+
+	/// Record amount of data sent.
+	void incrementDataSent(unsigned long size);
+
+    /// Record amount of data read - and also compute instantaneous, average bandwidths along with the inter message delay values
+	void incrementDataRead(unsigned long size);
+
+	/// Get instantaneous inter-message delay (jitter)
+	double getInstantInterMesgDelay();
+
+	/// Get max inter-message delay (jitter)
+	double getMaxInterMesgDelay();
+
+	/// Get min inter-message delay (jitter)
+	double getMinInterMesgDelay();
+
+	/// Get average inter-message delay (jitter)
+	double getAverageInterMesgDelay();
+
+   ///Get the Short Term Average Bandwidth -over a fixed number of packets (defined by BANDWIDTH_BUF_SIZE)
+    double getSTABandwidth();
+
+    ///Get the Short Term Average Latency -over a number of packets (defined by LATENCY_BUF_SIZE)
+    double getSTALatency();
+
+    ///get the burstinesss
+    double getBurstiness();   
+
+    ///Get the Jitter 
+    double getJitter();
+
+    ///Return the total number of packets read
+    unsigned long getPacketsRead();
+
+    ///Return the total number of packets sent
+    unsigned long getPacketsSent();
+
+    ///Returns the socket id
+    virtual int getSocketId();
+
+    ///Returns the status of the sockets being polled
+    static int selectSock(void *ptr, int *status, int numSocks, 
+struct timeval *timeout);  
+
+
+protected:
+	double instLat, latTotal, minLat, maxLat, avgLat;
+	unsigned long latCount,sentCount, readCount;
+	double instDelay, totalDelay, minDelay, maxDelay, avgDelay, prevLocalTime;
+	double currentTime, previousSentTime, previousReadTime,initialSentTime, initialReadTime;
+	unsigned long prevTotalDataRead, prevTotalDataSent, totalDataRead, totalDataSent;
+	double instReadBandwidth, instSendBandwidth, avgReadBandwidth, avgSendBandwidth;
+
+	//STA - Short Term Average -calculated for  a specified number of packets (calcualted over a number of packets defined by LATENCY_BUF_SIZE)
+
+    //Jitter is the average of the deviations of the instantaneous latencies from the STALatency
+
+    //Burstiness(for bandwidths) is calculated the same way as Jitter is calculated for latencies
+
+    double STALatency, STABandwidth, jitter, burstiness;
+
+    //The latencies and bandwidth are stored in a buffer of defined size and the short term sums -(STlatencySum and STBandwidthSum) are calculated
+    double latencyBuffer[LATENCY_BUF_SIZE];
+    double bandwidthBuffer[BANDWIDTH_BUF_SIZE];  
+    double STlatencySum, STbandwidthSum;
+
+    //to simplify Short Term Average calculations
+    int tempLatCounter, tempBWCounter;
+
+    ///Calculate the instantaneous outgoing bandwidth 
+	void computeInstantSendBandwidth();
+
+    ///Calculate the instantaneous incoming bandwidth 
+    void computeInstantReceiveBandwidth();
+
+    ///Calculate the average incoming bandwidth 
+	void computeAverageReceiveBandwidth();
+
+    ///Calculate the average outgoing bandwidth 
+    void computeAverageSendBandwidth();
+
+    ///Calculate the jitter over a specified number of packets 
+    void calculateJitter(double lat);
+    
+    ///Calculate the burstiness over a specified number of packets 
+    void calculateBurstiness(double bw);
+
+
+};
+
+
+#endif
Index: trunk/src/testing/QUANTA/include/QUANTAnet_perfMonitor_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_perfMonitor_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_perfMonitor_c.hxx	(revision 4)
@@ -0,0 +1,194 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTANET_PERFMONITOR_C
+#define _QUANTANET_PERFMONITOR_C
+
+
+#include "QUANTAnet_socketbase_c.hxx"
+#include "QUANTAnet_perfDaemon_c.hxx"
+
+class QUANTAnet_perfDaemonClient_c;
+
+
+/**
+This class does the performance monitoring calculations for QUANTA. 
+The calculations in the QUANTAnet_socketbase class are used by an instance
+of this class, included in other higher level modules (an instance of this class is not generally created by the user).
+
+Along with the API documentation, is also included, a note on the calculated parameters, the units of calculation and how they are calculated.
+
+As mentioned, in general, an instance of this class need not be created by the user. Instead the API's provided in the higher level classes (like the showStats, logStats and sendStats) should be directly invoked whenever network monitoring statistics is required. This is because the monitoring is done in all the networking classes automatically for every data flow over a network, using an instance of this class. The user can hence use the API's of the higher level classes as mentioned above, which would ensure statistics to be extracted whenever required.
+
+API calls should be made by the user as often as required to obtain the
+monitored statistics in the netlogger format ( <label,value> pairs). 
+
+Currectly, the following capabilities have been provided with the performance monitoring: statistics can be displayed instantaneously, logged into a user specified logfile or sent to another remote daemon for further analysis 
+ */
+
+
+
+class QUANTAnet_perfMonitor_c: public QUANTAnet_socketbase_c
+{
+public:
+    
+    ///Return values
+    //@{
+    ///Operation successful
+    static const int OK; //=0
+    
+    ///Operation Failed
+    static const int FAILED;  //=1
+    //@}
+    /// Default constructor allocates memory for IP strings.
+    QUANTAnet_perfMonitor_c();
+    /// Copy constructor creates a deep copy of another object.
+    QUANTAnet_perfMonitor_c(const QUANTAnet_perfMonitor_c&);
+
+    virtual ~QUANTAnet_perfMonitor_c();
+
+    //set the source and destination IPs of the machines communicating over the network - not to be used by the user
+    void setIPs(const char* selfIp, const char* remoteIp);
+   
+    //set the source and destination ports of the machines communicating over the network - not to be used by the user
+
+    void setPorts(int selfPort, int remotePort);
+    
+       /**
+       Displays the resultant statistics instantaneously in the netlogger format - this should be typically done after a read/write is done  a network.
+
+Also, it should be noted that a showStats call should be made at the end of atleast one send and receive for two-way information (the same applies for logStats and sendStats)
+
+       	@param streamInfo
+        A label describing the stream that is being monitored.
+
+        @param comment
+        A comment on the event that marks the time at which the stream is being monitored
+     */
+
+    void showStats(char* streamInfo, char* comment);
+
+   /**
+       This logs performance statistics in a file. The user opens a file and passes the file pointer with this function and results of monitoring are written into the logfile.
+      
+       @param streamInfo
+        A label describing the stream that is being monitored.
+
+        @param comment
+        A comment on the event that marks the time at which the stream is being monitored
+        
+        @param filePtr
+        File pointer to the file in which the results of monitoring are to be stored
+
+        @return
+        Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+     */
+    
+    int logStats(char* streamInfo, char* comment, FILE* filePtr);
+
+   /**
+       Sends the performance statistics to a remote perfdaemon -for further analysis of the monitored data - the initSendStats API should be called first, before calling a sendStats (In order to connect to the perfdaemon initially) 
+
+(Note: A typical example of sendStats is given in the (QUANTA_DISTRIB_DIR/demos/tcpreflector/ directory)
+
+       @param streamInfo
+        A label describing the stream that is being monitored.
+
+        @param comment
+        A comment on the event that marks the time at which the stream is being monitored
+ 
+        @return
+        Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+       
+     */
+
+    int sendStats(char* streamInfo, char* comment);
+    
+    /**
+       Initialize sendStats - provide the IP of the perfDaemon and an optional port number to connect to. This should be done initially  before using the sendStats API.
+
+       @param monitorClientIP
+       IP address of the perfDameon to connect to
+       
+       @param port
+       Port number at which the perfDaemon is running -this is optional. The default port number for perfDaemon is 9500 -so a different port number has to be specified if the perfDaemon is running on a different port.
+
+       @return
+       Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+     */
+
+
+    int initSendStats(const char* monitorClientIP, int port = QUANTAnet_perfDaemon_c::DEFAULT_PORT);
+    
+    /**
+       Properly delete the perfDaemonClient after sendStats is done
+     */
+
+    void exitSendStats();
+    
+private:
+
+    //source and destination IP's of the machines communicating over the network
+    char *selfIp, *remoteIp;
+    
+   //source and destination ports of the machines communicating over the network    
+
+    int selfPort, remotePort;
+    
+    //The buffer in which the resultant stats is stored in netlogger format
+
+    char* resultantStats;
+    
+    //A perfDaemonClient used to connect to a perfDaemon to send the resultant statistics
+
+    QUANTAnet_perfDaemonClient_c* aClient;
+    
+    //Upate the performance statistics
+    void updateStats(char* streamInfo, char* comment);
+    
+    
+};
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
Index: trunk/src/testing/QUANTA/include/QUANTAnet_iovec_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_iovec_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_iovec_c.hxx	(revision 4)
@@ -0,0 +1,144 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+/*
+ * File name: QUANTAnet_iovec.hxx
+ *
+ * Description: This class is a container class for the iovec structure 
+ *
+ * Usasge: 1) readv(), writev() Methods in QUANTAnet_tcp_c class
+ *         2) recvmsg(), sendmsg() Methods in QUANRTAnet_udp_c class
+ *
+ * Comments: QUANTAnet_iovec_c is a dynamic array of Iovec structures
+ *			 Each Iovec strucure contains two values
+ *           1) base pointer 2) its length
+ *           You can add diffrenet type of objects to the QUANTAnet_iovec_c
+ *  
+ * How to use -> See: /QUANTA/demos/network/tcp/ioservertcp.cxx
+ *											    ioclienttcp.cxx
+ *
+ * Change Log:
+ */
+
+
+#ifndef _QUANTANET_IOVEC
+#define _QUANTANET_IOVEC
+
+#ifndef __HAVE_STDIO_H
+#include <stdio.h>
+#define __HAVE_STDIO_H
+#endif
+#include <stdlib.h>
+
+
+#include "QUANTAglobals.hxx"
+
+#ifdef WIN32
+#ifndef __HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define __HAVE_WINSOCK2_H
+#endif /* __HAVE_WINSOCK2_H */
+#else
+#include <sys/uio.h>
+#endif
+
+class QUANTAnet_iovec_c
+{
+	private:
+		
+		//keeps the number of elements in the iovec array
+		int num_of_elements;
+
+		//keeps the number of elements dynamically allocated
+		int nalloc;
+		
+		//base pointer of the iovec dynamic array
+#ifdef WIN32
+		WSABUF* bufList;
+#else
+		struct iovec* bufList;
+#endif
+							
+	public:		
+
+		//constructor
+		//By default bufList is allocated 512 entries because 
+		//512*sizeof(iovec) = 4K(Page Size) to avoid page fault
+		QUANTAnet_iovec_c(int size = 512);
+		
+		//destructor
+		~QUANTAnet_iovec_c();
+		
+		/**
+		@desc add the pointer and its length to the iovec array
+		@param buff void*
+    	@param length int
+	    @return true or false
+	    **/
+		bool add(void* buff, int length);
+			
+		/**
+		@desc remove the specific iovec entry			
+    	@param index int
+	    @return true or false
+	    **/
+		bool removeAt(int index);				
+				
+		/**
+		@desc clear all entry in iovec array
+	    @return void
+	    **/
+		void removeAll();
+				
+		/**
+		@desc returns size of the iovec array    	
+	    @return size int
+	    **/
+		int size();
+
+		/**
+		@desc used in readv(), writev() methods (internal use only)    	
+	    @return base pointer of the dynamic array of iovec structures    			
+	    **/
+		
+#ifdef WIN32
+		WSABUF* getBuffer() {return bufList;}
+#else
+		const iovec* getBuffer() {return bufList;}
+#endif
+
+};
+
+#endif
+
Index: trunk/src/testing/QUANTA/include/QUANTAnet_tcp_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_tcp_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_tcp_c.hxx	(revision 4)
@@ -0,0 +1,458 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+/*
+This is a C++ class to support TCP/IP sockets.
+The 2 main classes are QUANTAnet_tcpClient_c and QUANTAnet_tcpServer_c.
+
+If you are writing a server you need to instantiate a tcpServer object.
+Likewise if you are writing a client you need to instantiate a tcpClient
+object.
+
+*/
+
+#ifndef _QUANTAPLUS_TCP_C
+#define _QUANTAPLUS_TCP_C
+
+#include "QUANTAnet_socketbase_c.hxx"
+#include "QUANTAnet_perfMonitor_c.hxx"
+#include "QUANTAnet_iovec_c.hxx"
+//#include <QUANTAnet_perfDaemon_c.hxx>
+
+class QUANTAnet_perfMonitor_c;
+class QUANTAnet_tcpServer_c;
+//class QUANTAnet_perfDaemon_c;
+
+/** TCP Class for creating client connections. This class bypasses QUANTA's standard method for establishing connections and provides the user with direct control of TCP connections.
+
+*/
+class QUANTAnet_tcpClient_c : public QUANTAnet_socketbase_c {
+
+	// Allow QUANTAnet_tcpServer_c objects to call MakeNonBlocking.
+	friend class QUANTAnet_tcpServer_c;
+
+protected:
+	/* Not to be called by user */
+	void makeNonBlocking();
+
+	struct sockaddr_in clientInfo;
+	int clientSockFd;
+	int clientStatus;
+	int timeOutStatus;
+	int timeOutPeriod;
+    QUANTAnet_perfMonitor_c pmonitor;
+public:
+
+	/// Blocking parameter values for Read/Write method.
+	//@{
+	/// Make the connection blocking but time out eventually.
+	static const int BLOCKING/* = 1*/;
+
+	/// Make the connection non blocking.
+	static const int NON_BLOCKING/* = 2*/;
+
+	// Make the conncection blocking and never time out.
+	//static const int NEVER_TIME_OUT_BLOCKING/* = 3*/;
+
+	//@}
+
+	/// Time out values.
+	//@{
+	/// Used to set time out period to never time out.
+	static const int NO_TIME_OUT/* = -1*/;
+
+	/// Default time out is no time out.
+	static const int DEFAULT_TIME_OUT/* = NO_TIME_OUT*/; 
+	//@}
+
+	/// Return values from Read/Write methods.
+	//@{
+	/// Socket is not open.
+	static const int SOCKET_NOT_OPEN/* = -1*/;
+
+	/// Connection you attempted to read/write is terminated.
+	static const int CONNECTION_TERMINATED/* = -2*/;
+
+	/// You attempted to read with non blocking and there was not data.
+	static const int NON_BLOCKING_HAS_NO_DATA/* = -3*/;
+
+	/// The read/write timed out.
+	static const int TIMED_OUT/* = -4*/;
+
+	/// Read/Write succeeded.
+	static const int OK/* = 1*/;
+
+	/// You attempted to write with non blocking and socket was not ready.
+	static const int NON_BLOCKING_NOT_READY_TO_WRITE/* = -6*/;
+
+	/// Socket was not ready.
+	static const int NOT_READY/* = -7*/;
+
+	/// Socket ready to read.
+	static const int READY_TO_READ/* = -8*/;
+
+	/// Socket ready to write.
+	static const int READY_TO_WRITE/* = -9*/;
+
+	/// Socket ready to read and write.
+	static const int READY_TO_READ_AND_WRITE/* = -10*/;
+
+    /// Change the socket buffer size before Read().
+    static const int READ_BUFFER_SIZE/* = -11*/;
+
+    /// Change the socket buffer size before Write().
+    static const int WRITE_BUFFER_SIZE/* = -12*/;
+	//@}
+
+	
+	/** Set timeout period when performing read() or write() operations.
+	    @param t Time out period in seconds. Set to QUANTAnet_tcpClient_c::NO_TIME_OUT to set no time out period.
+	*/
+	void setTimeOut(int t) {timeOutPeriod = t;}
+
+	/// Get timeout period
+	int getTimeOut() {return timeOutPeriod;}
+
+	/** Set client info. For internal use.
+	    @param info client information
+	*/
+	void setClientInfo(struct sockaddr_in* info) { clientInfo = *info; }
+
+	/** Set client socket. For internal use.
+	    @param sockfd client socket
+	*/
+	void setClientSockFd(int sockfd) { clientSockFd = sockfd; }
+
+	QUANTAnet_tcpClient_c();
+	virtual ~QUANTAnet_tcpClient_c() { if (clientSockFd) close(); }
+
+	/// Accessor functions
+	//@{
+	/** Get the IP address of remote connection.
+	If you are a client this returns the ip of the destination server.
+	If you are a server this returns the ip of the destination client.
+	*/
+	unsigned int getRemoteIP();
+
+	/** Get the IP address of remote connection.
+	If you are a client this returns the ip of the destination server.
+	If you are a server this returns the ip of the destination client.
+	*/
+	void getRemoteIP(char* name);
+
+	/// Get port of self.
+	int  getSelfPort();
+
+	/// Get port of client.
+	int  getRemotePort();
+
+	/// Get socket id
+	int getSocketId();
+	//@}
+
+	/**@name Read and Write calls.*/
+	//@{
+	/**
+	  @param nbytes
+
+	  Fill nbytes with num bytes you want to read.
+	  nbytes will return with number of bytes successfully read.
+
+	  @param blockingtype
+
+	  BLOCKING means that it will block waiting for data or until
+	  the timeout period expires.  Change the timeout period by
+	  calling setTimeOut().
+
+	  NON_BLOCKING means that if there is no data to be read this call will
+	  return immediately. If it does get some data it will keep reading
+	  until the specified number of bytes is received, or if it timesout, or if
+	  the connection is broken. In the latter two cases the number of bytes
+	  it was able to read is returned.
+
+	  In either the BLOCKING or NON_BLOCKING case you can set the
+	  time out period to never time out by setting the timeout
+	  time to: NO_TIME_OUT.  
+
+	  @return SOCKET_NOT_OPEN, NON_BLOCKING_HAS_NO_DATA, TIMED_OUT, CONNECTION_TERMINATED, OK, errno
+	  */
+	int read(char *ptr, int *nbytes, int blockingType);
+
+	/** Allows you to change the parameters to the setsockopt() options.Currently this member allows you to change socket buffer size.
+
+	    @param option 
+	    Specify QUANTAnet_tcpClient_c::READ_BUFFER_SIZE if you want to change the size of the receive buffer.
+	    Specify QUANTAnet_tcpClient_c::WRITE_BUFFER_SIZE if you want to change the size of the send buffer			
+
+	    @param buffersize
+	    Specify the size.
+	*/	
+	void setSockOptions(int option, int buffersize);	
+
+
+	/** Determines if a socket has data available to read.
+	    @return Either: QUANTAnet_tcpClient_c::NOT_READY
+	    or QUANTAnet_tcpClient_c::READY_TO_READ
+	*/
+	int isReadyToRead();
+
+	/** Determines if a socket is ready to write.
+	    @return Either: QUANTAnet_tcpClient_c::NOT_READY
+	    or QUANTAnet_tcpClient_c::READY_TO_WRITE
+	*/
+	int isReadyToWrite();
+
+	/** Determines if a socket is ready to write or read or both.
+	    @return Either: QUANTAnet_tcpClient_c::NOT_READY
+	    or QUANTAnet_tcpClient_c::READY_TO_WRITE
+	    or QUANTAnet_tcpClient_c::READY_TO_READ
+	    or QUANTAnet_tcpClient_c::READY_TO_READ_AND_WRITE
+	*/
+	int isReady();
+
+	/** Write data to socket.
+	@return SOCKET_NOT_OPEN, NON_BLOCKING_NOT_READY_TO_WRITE, TIMED_OUT, CONNECTION_TERMINATED, OK
+	*/
+	int write(const char *ptr, int  *nbytes, int blockingType);
+
+	/// Show status of connection in English.
+	void showStatus(int status, int nbytes);
+
+	/// Close the current client connection.
+	int close();
+
+	/** Connect to a server.
+	    @return A negative number(that is returned by a socket sonnect() call if failed. 
+		Else returns client's socket file descriptor. (note: the return value in the previous 
+		versions was a zero in case of an error - this has been changed to a negative value from version 1.2)
+	*/
+	int connectToServer(const char *ip, int port);
+
+
+    //Functions added for performance monitoring interface
+    /**
+       Displays the resultant statistics instantaneously in the netlogger format - 
+	   this should be typically done after a read/write is done over a network.
+       
+       Also, it should be noted that a showStats call should be made at the end of atleast one send 
+	   and receive for two-way information (the same applies for logStats and sendStats)
+       
+       @param streamInfo
+       A label describing the stream that is being monitored.
+       
+       @param comment
+       A comment on the event that marks the time at which the stream is being monitored
+    */
+
+    void showStats(char* streamInfo, char* comment);
+    
+    /**
+       This logs performance statistics in a file. The user opens a file and passes the file pointer 
+	   with this function and results of monitoring are written into the logfile.
+      
+       @param streamInfo
+        A label describing the stream that is being monitored.
+
+        @param comment
+        A comment on the event that marks the time at which the stream is being monitored
+        
+        @param filePtr
+        File pointer to the file in which the results of monitoring are to be stored
+
+        @return
+        Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+     */
+
+
+    int logStats(char* streamInfo, char* comment, FILE* filePtr);
+
+    /**
+       Sends the performance statistics to a remote perfdaemon -for further analysis of the monitored data - 
+	   the initSendStats API should be called first, before calling a sendStats (In order to connect to the perfdaemon initially) 
+
+       @param streamInfo
+       A label describing the stream that is being monitored.
+       
+       @param comment
+       A comment on the event that marks the time at which the stream is being monitored
+       
+       @return
+       Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+       
+     */
+
+    int sendStats(char* streamInfo, char* comment);
+
+    /**
+       Initialize sendStats - provide the IP of the perfDaemon and an optional port number to connect to. 
+	   This should be done initially  before using the sendStats API.
+       
+       @param monitorClientIP
+       IP address of the perfDameon to connect to
+       
+       @param port
+       Port number at which the perfDaemon is running -this is optional. The default port number for perfDaemon is 9500 
+	   -so a different port number has to be specified if the perfDaemon is running ona different port.
+       
+       @return
+       Either QUANTAnet_perfMonitor_c::OK or QUANTAnet_perfMonitor_c::FAILED
+    */
+
+    int initSendStats(const char* monitorClientIP, int port = PERF_DAEMON_DEFAULT_PORT);
+    
+    /**
+       Properly delete the perFDaemon Client after sendStats is done
+     */
+
+    void exitSendStats();
+
+    //Set the instantaneous latency 
+    void setInstantaneousLatency(double latency);
+
+	/**
+	  @param q_iovec QUANTAnet_iovec_c 
+	  @param blockingtype QUANTAnet_tcpClient_c::BLOCKING or, NON_BLOCKING
+	  @return 1 if succed, or errno if fails 
+	  comment:readv gives bad address error when iovec pointer is not initialized.
+	*/
+	int readv(QUANTAnet_iovec_c q_iovec, int blockingType);
+
+
+   /** 
+	  @param q_iovec QUANTAnet_iovec_c	  
+	  @param blockingtype QUANTAnet_tcpClient_c::BLOCKING or, NON_BLOCKING	   
+	  @return 1 if succed, or errno if fails 	
+	  comment:writev gives invalid argument error when iovec length is not initialized.	
+	*/
+	int writev(QUANTAnet_iovec_c q_iovec, int blockingType);	
+};
+
+/** TCP Class for creating servers. This class bypasses QUANTA's standard method for 
+establishing connections and provides the user with direct control of TCP connections.
+*/
+
+class QUANTAnet_tcpServer_c : public QUANTAnet_socketbase_c {
+
+
+protected:
+	int serverPort;
+
+	int timeOutPeriod;
+	int sockfd;
+	struct sockaddr_in  serverInfo;
+
+public:
+
+	//@{
+	/// Status ok.
+	static const int OK/* = 1*/;
+
+	/// Status failed.
+	static const int FAILED/* = 0*/;
+
+	/// Change the socket buffer size before read().
+	static const int READ_BUFFER_SIZE/* = 2*/;
+
+	/// Change the socket buffer size before write().
+	static const int WRITE_BUFFER_SIZE/* = 3*/;
+
+	//@}
+
+	//	static int QUANTAnet_tcpServer_c::NO_TIME_OUT;
+
+	/** Set timeout period when performing read() or write() operations.
+	    @param t Time out period in seconds. Set to QUANTAnet_tcpClient_c::NO_TIME_OUT to set no time out period.
+	*/
+	void setTimeOut(int t) {timeOutPeriod = t;}
+
+	/// Get timeout period.
+	int getTimeOut() {return timeOutPeriod;}
+
+	QUANTAnet_tcpServer_c();
+	virtual ~QUANTAnet_tcpServer_c() { if (sockfd) close(); }
+
+	/// Get server's port.
+	int getSelfPort() {
+		return ntohs(serverInfo.sin_port);
+	}
+
+	/** Open the server on a port.
+	 Typically after this call you sit in a loop and call
+	 checkForNewConnections to wait for incoming connections.
+	 @return FAILED if failed, OK if success
+	 */
+	int init(int port);
+
+	/** Allows you to change the parameters to the setsockopt() options.Currently this member allows you to change socket buffer size.
+	 
+	 @param option
+	 Specify QUANTAnet_tcpServer_c::READ_BUFFER_SIZE if you want to change the size of the receive buffer.
+	 Specify QUANTAnet_tcpServer_c::WRITE_BUFFER_SIZE if you want to change the size of the send buffer
+	
+	 @param buffersize
+	 Specify the size.
+       */
+        void setSockOptions(int option, int buffersize);
+
+	/// Close the server port.
+	int close();
+
+	/** Check to see if there is a request from clients for connection.
+	    This function checks for new connections. If there is a
+	    new connection, then a new QUANTAnet_tcpClient_c object is
+	    returned, and that object can be used to talk to the new
+	    client.
+
+	    @param blockingTime time to block while checking
+	    @return a new QUANTAnet_tcpClient_c object
+	    @see QUANTAnet_tcpClient_c class.
+    	*/
+	QUANTAnet_tcpClient_c* checkForNewConnections(const int& blockingTime=0);
+
+  /** Blocks while waiting for a new connection.
+     While waiting for new connections to arrive, the server blocks
+     until a new client has connected. This blocking wait results in
+     better performance than the checkForNewConnections
+     implementation. The server will block until a new client has
+     connected, and when a client connects, a pointer to the new
+     client object is returned.
+
+     @return a new QUANTAnte_tcpClient_c object
+     @see QUANTAnet_tcpClient_c class.
+  */
+  QUANTAnet_tcpClient_c* waitForNewConnection();
+
+};
+
+#endif
Index: trunk/src/testing/QUANTA/include/QUANTAnet_datapack_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_datapack_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_datapack_c.hxx	(revision 4)
@@ -0,0 +1,718 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTA_DATAPACK_C_H
+#define _QUANTA_DATAPACK_C_H
+
+#define FLOAT_SIZE 4
+#define DOUBLE_SIZE 8
+#define INT_SIZE 4
+#if (_MIPS_SZLONG==64)
+#define LONG_SIZE 8
+#define UNSIGNED_LONG_SIZE 8
+#else
+#define LONG_SIZE 4
+#define UNSIGNED_LONG_SIZE 4
+#endif
+#define INT32_SIZE 4
+#define INT64_SIZE 8
+#define CHAR_SIZE 1
+
+typedef int int32;
+
+#ifdef WIN32 
+typedef __int64	int64;
+#elif (_MIPS_SZLONG==64)
+typedef long int64;
+#else 
+typedef long long int64;
+#endif
+
+#ifdef _WIN32_WCE
+#ifndef __HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define __HAVE_WINSOCK2_H
+#endif /* __HAVE_WINSOCK2_H */
+#endif
+
+/**
+Data packing class. It is basically a glorified memcpy().  The idea is
+that you create an object to help you pack data for transmission over
+networks.
+
+Sending and packing data: First you create a QUANTAnet_datapack_c
+object. Then using the InitPack() method, assign to it a pre-allocated
+memory buffer (SEE BELOW FOR IMPORTANT NOTES.)
+Then using the various QUANTAnet_datapack_c::pack*()
+member functions, you can pack integers, chars, floats, and doubles
+into the buffer. The buffer is now ready for big-endian to
+little-endian transmission. (And vice-versa).
+
+Receiving and unpacking data: Similarly if you receive a buffer of
+data from the network, you assign this buffer to a
+QUANTAnet_datapack_c object using the InitUnpack() method.  Finally,
+we unpack its constituent components using the
+QUANTAnet_datapack_c::unpack*() member functions.
+
+IMPORTANT NOTES:
+
+It is important to compute the length of the buffer using the various
+QUANTAnet_datapack_c::sizeof_*() methods where possible as additional
+buffer space is needed to encode platform-specific information. If in
+doubt always allocate 1 more byte than necessary. The sizeof_() calls
+will make sure that extra byte is included.
+
+To make your application as portable as possible, please take a look at
+packInt32 and packInt64 and counter functions that unpacks the data.
+These functions should be more portable than packInt and packLong functions
+since there is not specification about the size of int and lont int types
+in C or C++ language reference manual. 
+
+For example, on SGI, int is going to be treated as 32bits no matter what
+kind of binary format you are using. However, long int is going to be treated
+as 32bits if you use 32 or n32 for your binary format, whereas it would take
+64bits if you use 64 as your binary format. On Win32 and linux running on
+Intel processors, both int and long takes 32bit space. 
+
+Finally remember the order in which you packed your data. You need to
+use the same order to unpack them correctly.
+
+@version: 12/1/1999
+
+*/
+
+class QUANTAnet_datapack_c {
+
+
+public:
+	QUANTAnet_datapack_c() {
+		running = 0; size = 0;
+		start = 0;
+	}
+
+	
+	///Datapack class return values
+	//@{
+	/// Operation went ok
+	static const int OK/* = 0*/;
+	/// Operation failed
+	static const int FAILED/* = -1*/;
+	//@}
+
+	/**
+	Before we do any actual packing, we first call this method to attach the datapack object to some buffer
+
+	@param buffer
+	This buffer provided by the API user is where the packed data will be stored
+
+	@param buffersize
+	The size in bytes of the buffer above
+	*/
+	void initPack(char *buffer, int buffersize);
+
+	/**
+	Before we do any actual unpacking, we first call this method to attach the datapack object to some buffer
+
+	@param buffer
+	This buffer where the packed data is stored
+
+	@param buffersize
+	The size in bytes of the buffer above
+	*/
+	void initUnpack(char *buffer, int buffersize);
+
+	/**
+	Given a datapack class, this method gives us a pointer to the buffer where the packed data is stored
+
+	@return 
+	A pointer to the beginning of the packed data stream
+
+
+	*/
+	char *getBuffer() { return (char *)start;}
+
+	/**
+	Gives us the size of the buffer attached to this datapack object
+
+	@return 
+	Size in bytes of the attached buffer
+
+	*/
+	int getBufferMaxSize() { return size;}
+
+	/**
+	Gives us the size in bytes of available space left in the attached buffer
+
+	@return
+	Size in bytes of the remaining space available in the attached buffer
+	*/
+	int getBufferFilledSize() {return running - start;}
+
+	/** 
+	Insert a variable of type float into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The float variable to be packed
+	*/
+	int packFloat(float val);
+
+	/** 
+	Insert a variable of type int into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The int variable to be packed
+	*/
+	int packInt(int val) ;
+
+        /**
+        Insert a variable of type 32-bit integer into the buffer
+
+        @return
+        OK or FAILED
+
+
+	@param val
+	The 32bit integer variable to be packed
+	*/
+	int packInt32(int32 val);
+
+	/** 
+	Insert a variable of type long into the buffer. Note that long takes 8
+        bytes when it is compiled with 64-bit compiler on SGI.
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The long variable to be packed
+	*/
+	int packLong(long val) ;
+
+	/** 
+	Insert a variable of type 64-bit integer into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The 64-bit integer variable to be packed
+	*/
+	int packInt64(int64 val);
+
+	/** 
+	Insert a variable of type double into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The double variable to be packed
+	*/
+	int packDouble(double val);
+
+
+	#ifdef _WIN32_WCE
+	/** 
+	Insert a variable of type char into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The Unicode char variable to be packed
+	*/
+	int packChar(TCHAR val) ;
+	#endif
+
+	/** 
+	Insert a variable of type char into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The char variable to be packed
+	*/
+	int packChar(char val) ;
+
+  /** Pack a null-terminated character string.
+      This convenience functions packs a null-terminated character
+      string into the buffer. The length of the string in bytes is
+      internally encoded. This reduces network traffic as only the
+      required number of bytes are sent across the network.
+
+      @param val null-terminated character string to pack
+      @return OK or FAILED
+  */
+  int packString(char* val);
+
+	#ifdef _WIN32_WCE
+	/** 
+	Pack raw characters into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The Unicode char array to be packed
+	@param sz
+	Num chars to pack
+	*/
+	int pack(TCHAR* val, int sz) ;
+	#endif	
+
+	/** 
+	Pack raw characters into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The char array to be packed
+	@param sz
+	Num chars to pack
+	*/
+	int pack(char* val, int sz) ;
+	
+	/** 
+	Pack floats of a float array into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The float array to be packed
+	@param sz
+	Num floats in the array 
+	*/
+	int packFloatArray(float* val, int sz) ;
+
+	/** 
+	Pack doubles of a double array into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The double array to be packed
+	@param sz
+	Num doubles in the array 
+	*/
+	int packDoubleArray(double* val, int sz) ;
+
+	/** 
+	Pack an array with int type values into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The int array to be packed
+	@param sz
+	Num int values in the array 
+	*/
+	int packIntArray(int* val, int sz) ;
+
+	/** 
+	Pack an array with int32 type values into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The int32 array to be packed
+	@param sz
+	Num int32 values in the array 
+	*/
+	int packInt32Array(int32* val, int sz) ;
+   
+    /** 
+	Pack an array with int64 type values into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The int64 array to be packed
+	@param sz
+	Num int64 values in the array 
+	*/
+	int packInt64Array(int64* val, int sz) ;
+
+    /** 
+	Pack an array with long type values into the buffer
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The long array to be packed
+	@param sz
+	Num long values in the array 
+	*/
+	int packLongArray(long* val, int sz) ;
+
+    /** 
+	Insert a variable of type unsigned long into the buffer. Note that long 		takes 8 bytes when it is compiled with 64-bit compiler on SGI.
+
+	@return 
+	OK or FAILED
+
+	@param val
+	The unsigned long variable to be packed
+	*/
+
+    	int packUnsignedLong(unsigned long val);
+    
+    /**
+	Extract a variable of type float from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided float variable where we store the extracted value
+	*/
+	int unpackFloat(float *Answer) ;
+
+	/**
+	Extract a variable of type int from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided int variable where we store the extracted value
+	*/
+	int unpackInt(int *Answer) ;
+
+/**
+	Extract a variable of type 32bit integer from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided 32bit integer variable where we store the extracted value
+	*/
+	int unpackInt32(int32 *Answer) ;
+
+	/**
+	Extract a variable of type long from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided long variable where we store the extracted value
+	*/
+	int unpackLong(long *Answer) ;
+
+	/**
+	Extract a variable of type unsigned long from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided unsigned long variable where we store the extracted value
+	*/
+	int unpackUnsignedLong(unsigned long *Answer) ;
+
+
+	/**
+	Extract a variable of type 64-bit integer from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided 64-bit integer variable where we store the extracted value
+	*/
+	int unpackInt64(int64 *Answer) ;
+
+	/**
+	Extract a variable of type double from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided double variable where we store the extracted value
+	*/
+	int unpackDouble(double *Answer)  ;
+
+
+	#ifdef _WIN32_WCE
+	/**
+	Extract a variable of type char from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided Unicode char variable where we store the extracted value
+	*/
+	int unpackChar(TCHAR *Answer) ;
+	#endif
+
+	/**
+	Extract a variable of type char from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided char variable where we store the extracted value
+	*/
+	int unpackChar(char *Answer) ;
+
+  /** Pack a null-terminated character string.
+      This convenience functions packs a null-terminated character
+      string into the buffer. The length of the string in bytes is
+      internally encoded when extracting the string. If sz indicates
+      that val does not have enough space to unpack the string, then
+      the unpack function will fail. The unpacked value does include
+      the terminating null character '\\0'.
+
+      @param val character buffer to stored unpacked string.
+      @param sz size in bytes of the val buffer.
+      @return OK or FAILED
+  */
+  int unpackString(char* val, const int& sz);
+
+	#ifdef _WIN32_WCE
+	/**
+	Extract the packed chars from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided Unicode char array where we store the extracted value
+	*/
+	int unpack(TCHAR *Answer, int sz) ;
+	#endif
+
+	/**
+	Extract the packed chars from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided char array where we store the extracted value
+  @param sz
+  Size in bytes of the provided char array
+	*/
+	int unpack(char *Answer, int sz) ;
+
+	/**
+	Extract the packed float array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided float array where the extracted floats are stored
+	
+    @param sz
+    The size of the array in which the extracted floats are stored
+    */
+    int unpackFloatArray(float* Answer, int sz);
+   
+	/**
+	Extract the packed double array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided double array where the extracted doubles are stored
+	
+    @param sz
+    The size of the array in which the extracted doubles are stored
+    */
+    int unpackDoubleArray(double* Answer, int sz);
+   
+	/**
+	Extract the packed int array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided int array where the extracted int values are stored
+	
+    @param sz
+    The size of the array in which the extracted int values are stored
+    */
+    int unpackIntArray(int* Answer, int sz);
+   
+	/**
+	Extract the packed int32 array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided array where the extracted int32 values are stored
+	
+    @param sz
+    The size of the array in which the extracted int32 values are stored
+    */
+    int unpackInt32Array(int32* Answer, int sz);
+
+	/**
+	Extract the packed int64 array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided array where the extracted int64 values are stored
+	
+    @param sz
+    The size of the array in which the extracted int64 values are stored
+    */
+    int unpackInt64Array(int64* Answer, int sz);
+   
+	/**
+	Extract the packed long array from the buffer
+
+	@return 
+	OK or FAILED
+
+	@param Answer
+	A user provided array where the extracted long values are stored
+	
+    @param sz
+    The size of the array in which the extracted long values are stored
+    */
+    int unpackLongArray(long* Answer, int sz);
+    
+    /**
+	This function tells us if there is enough incoming_size bytes in the buffer to perform the operation.
+
+	@return OK or FAILED
+
+	@param incoming_size
+	The size in bytes of to be tested.
+	*/
+	int checkspace(unsigned int incoming_size);
+
+	/**
+	Gives us a cross-platform safe float size
+	
+	@return 
+	The number of bytes in an int (+ 1 byte for machine code storage)
+	*/
+	static int sizeof_float(unsigned int cnt=1){return FLOAT_SIZE * cnt;};
+	/**
+	Gives us a cross-platform safe int size
+	
+	@return 
+	The number of bytes in an int (+ 1 byte for machine code storage)
+	*/
+	static int sizeof_int(unsigned int cnt=1){return INT_SIZE * cnt;};
+
+	/**
+	Gives us a cross-platform safe 64-bit int size
+	
+	@return 
+	The number of bytes in an 64-bit int
+	*/
+	static int sizeof_int64(unsigned int cnt=1){return INT64_SIZE * cnt;};
+
+	/**
+	Gives us a cross-platform safe 32-bit int size
+	
+	@return 
+	The number of bytes in an 32-bit int
+	*/
+	static int sizeof_int32(unsigned int cnt=1){return INT32_SIZE * cnt;};
+	
+	/**
+	Gives us a cross-platform safe long size
+	
+	@return 
+	The number of bytes in a long (+ 1 byte for machine code storage)
+	*/
+	static int sizeof_long(unsigned int cnt=1){return LONG_SIZE * cnt;};
+
+	/**
+	Gives us a cross-platform safe unsigned long size
+	
+	@return 
+	The number of bytes in unsigned long (+ 1 byte for machine code storage)
+	*/
+	static int sizeof_unsignedLong(unsigned int cnt=1){return UNSIGNED_LONG_SIZE * cnt;};
+
+	/**
+	Gives us a cross-platform safe char size
+	
+	@return 
+	The number of bytes in a char 1 byte for machine code storage)
+	*/
+	static int sizeof_char(unsigned int cnt=1){return CHAR_SIZE * cnt;};
+
+	/**
+	Gives us a cross-platform safe double size
+	
+	@return 
+	The number of bytes in a double (+ 1 byte for machine code storage)
+	*/
+	static int sizeof_double(unsigned int cnt=1){return DOUBLE_SIZE * cnt;};
+
+  /** Gives us a cross-platform safe string size encoded with its length.
+      @return The number of bytes used to encode a string.
+  */
+  static int sizeof_string(unsigned int cnt=1)
+    { return sizeof_int() + sizeof_char(cnt); }
+
+
+private:
+	unsigned long size;
+	unsigned char *running;
+	unsigned char *start;
+
+};
+
+#endif
Index: trunk/src/testing/QUANTA/include/QUANTAglobals.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAglobals.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAglobals.hxx	(revision 4)
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTA_GLOBALS_H
+#define _QUANTA_GLOBALS_H
+
+#include <ctype.h>
+
+//#include "QUANTAconfig.h"
+
+// add bool, true, false support for irix o32 format
+#if (defined(__sgi) && defined(HAVE_BINARY_TYPE_32) && !defined(_BOOL))
+typedef int bool;
+#define false 0
+#define true 1
+#endif
+
+
+// disable ms visual c++ warnings
+#ifdef WIN32
+// disable ms visual c++ warning - "C++ Exception Specification ignored"
+#pragma warning(disable : 4290)
+
+// disable ms visual c++ warning - "deletion of an array expression; conversion to pointer supplied"
+// maybe look into this one more
+#pragma warning(disable : 4154)
+#endif
+
+
+// add a case sensitive string compare if not available
+#ifdef WIN32
+#	ifndef HAVE_STRCASECMP 
+#		ifdef HAVE_STRICMP 
+#			define strcasecmp(x,y) stricmp(x,y) 
+#		elif defined(HAVE_STRCMPI) 
+#				define strcasecmp(x,y) strcmpi(x,y) 
+#		else // no case insensitive function available
+#			define QUANTA_STRCASECMP 
+extern int strcasecmp(const char *first, const char *second);
+#		endif
+#	endif
+#endif
+
+/** Platform-independent sleep function.
+    Different platforms and APIs have different methods for implementing
+    ways to suspect program activity. This function serves as a wrapper
+    which internally calls usleep() or Sleep() as needed.
+    @param microseconds number of microseconds to wait.
+*/
+void QUANTAsleep(const unsigned int& seconds);
+
+/** Platform-independent usleep function.
+*/
+void QUANTAusleep(const unsigned int& microseconds);
+
+#if defined(linux) || defined(__APPLE__)
+#define HAVE_SOCKLEN_T
+#endif
+
+// add socklen_t to systems that do not provide it (sgi..)
+#if !defined(HAVE_SOCKLEN_T)
+typedef int socklen_t;
+#endif
+
+
+#endif
Index: trunk/src/testing/QUANTA/include/QUANTAnet_perfClient_c.hxx
===================================================================
--- trunk/src/testing/QUANTA/include/QUANTAnet_perfClient_c.hxx	(revision 4)
+++ trunk/src/testing/QUANTA/include/QUANTAnet_perfClient_c.hxx	(revision 4)
@@ -0,0 +1,211 @@
+/******************************************************************************
+ * QUANTA - A toolkit for High Performance Data Sharing
+ * Copyright (C) 2003 Electronic Visualization Laboratory,  
+ * University of Illinois at Chicago
+ *
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the distribution.
+ *  * Neither the name of the University of Illinois at Chicago nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Direct questions, comments etc about Quanta to cavern@evl.uic.edu
+ *****************************************************************************/
+
+#ifndef _QUANTAPLUS_PERF_CLIENT
+#define _QUANTAPLUS_PERF_CLIENT
+
+#define PERF_DAEMON_DEFAULT_PORT	9500
+#define REGISTER_PERF_CLIENT "$$QUANTA_PERF_DAEMON_CLASS$$"
+#define SEND_STAT_CLIENT     "$$SEND_STAT_PERF_CLIENT$$$$$"
+#define REGISTER_PERF_CLIENT_LENGTH 28 // length of REGISTER_PERF_CLIENT string
+#define SEND_STAT_CLIENT_LENGTH 28 // length of SEND_STAT_CLIENT string
+#define CLOSING_STAT_CLIENT  "$$CLOSING_STAT_PERF_CLIENT$$"
+#define CLOSING_STAT_CLIENT_LENGTH 28
+#define CLOSING_PERF_CLIENT  "$$CLOSING_PERF_DAEMON_CLASS$"
+#define CLOSING_PERF_CLIENT_LENGTH 28
+
+class QUANTAnet_tcpClient_c;
+
+/** This class is a very low-level class that is designed for specific uses.
+If what you want to do is checking performance characteristics of your 
+application, you don't have to use this class at all. All QUANTA  
+classes are updated with instrumentation features. 
+
+QUANTAnet_perfDaemonClient_c is a specially designed class
+specifically for use with QUANTAnet_perfDaemon_c class or performance 
+monitoring daemon application that instantiates and utilizes QUANTAnet_perfDaemon_c class. 
+This class can be used if you want to do one of the following:
+
+First, it can be used to communicate directly with performance daemon. If you want
+to send special messages to the daemon, you can use this class for the purpose.
+Second, you are developing real time performance monitoring applications like QoSiMoto.
+
+If you want to send your own special messages to performance monitoring daemon, 
+you have to simply instantiate this class and use provided methods to send special 
+messages to the performance daemon. If your interest is in monitoring the performance 
+characteristics of other applications then you need to register as performance 
+monitoring client when you instantiate this class. Read the description of constructors
+to find out how to register your application as performance monitoring client.
+*/
+class QUANTAnet_perfDaemonClient_c 
+{
+private:
+	QUANTAnet_tcpClient_c *client;
+	int timeOut;
+	int connectionAlive;
+    int perfClient;
+
+public:
+	//@{
+	/// Status ok.
+	static const int OK/* = 1*/;
+
+	/// Status failed.
+	static const int FAILED/* = 2*/;
+
+	/// Memory allocation error.
+	static const int MEM_ALLOC_ERR/* = 3*/;
+
+	/// A non-blocking read had no data available to read.
+	static const int NON_BLOCKING_HAS_NO_DATA/* = 7*/;
+
+	/// Connection terminated.
+	static const int CONNECTION_TERMINATED/* = 8*/;
+
+	/// Connection not ready for use.
+	static const int NOT_READY/* = 9*/;
+
+	/// Connection has data available to read.
+	static const int READY_TO_READ/* = 10*/;
+
+	/// Connection is ready to write.
+	static const int READY_TO_WRITE/* = 11*/;
+
+	/// Connection has data available to read and is ready to write.
+	static const int READY_TO_READ_AND_WRITE/* = 12*/;
+
+	static const int BLOCKING/* = QUANTAnet_tcpClient_c::BLOCKING*/;
+	static const int NON_BLOCKING/* = QUANTAnet_tcpClient_c::NON_BLOCKING*/;
+
+	static const int NO_TIME_OUT/* = QUANTAnet_tcpClient_c::NO_TIME_OUT*/;
+
+	//@}
+
+        /** Constructor
+	    @param isPerfClient 1 if your application is designed to monitor 
+	    the performance characteristics of other applications like QoSiMoto.
+	    Otherwise, specify 0.
+	 */
+	QUANTAnet_perfDaemonClient_c(int isPerfClient = 0);       
+
+	/// Use this constructor if you have a pre-opened socket
+	QUANTAnet_perfDaemonClient_c(QUANTAnet_tcpClient_c*, int isPerfClient = 0);
+	~QUANTAnet_perfDaemonClient_c();
+
+	/** Read data from a reflector (if available).
+	    @param blockingType set to either QUANTAnet_perfDaemonClient_c::BLOCKING, NON_BLOCKING.
+	    @param ret set to a pointer to a char*. Read will allocate memory for the
+	    buffer and assign it to your pointer. You are responsible for deleteing
+	    the buffer once you are done with it.
+	    @param nbytes returns the number of bytes in the buffer.
+	    @return Either QUANTAnet_perfDaemonClient_c::MEM_ALLOC_ERR, OK, FAILED, NON_BLOCKING_HAS_NO_DATA, CONNECTION_TERMINATED.
+	*/
+	int read(char** ret, int* nbytes, int blockingType);
+
+	/** Write data to the reflector.
+	    @param outgoingData set to your buffer containing data.
+	    @param nbytes set to size of the buffer refered to by outgoingData
+	    @return Either QUANTAnet_perfDaemonClient_c::OK,CONNECTION_TERMINATED.
+	*/
+	int write(const char* outgoingData, int* nbytes);
+
+	/** Determines if a socket has data available to read.
+	    @return Either: QUANTAnet_perfDaemonClient_c::NOT_READY
+	    or QUANTAnet_perfDaemonClient_c::READY_TO_READ
+	*/
+	int isReadyToRead();
+
+	/** Determines if a socket is ready to write.
+	    @return Either: QUANTAnet_perfDaemonClient_c::NOT_READY
+	    or QUANTAnet_perfDaemonClient_c::READY_TO_WRITE
+	*/
+	int isReadyToWrite();
+
+	/** Determines if a socket is ready to write or read or both.
+	    @return Either: QUANTAnet_perfDaemonClient_c::NOT_READY
+	    or QUANTAnet_perfDaemonClient_c::READY_TO_WRITE
+	    or QUANTAnet_perfDaemonClient_c::READY_TO_READ
+	    or QUANTAnet_perfDaemonClient_c::READY_TO_READ_AND_WRITE
+	*/
+	int isReady();
+
+	/// Accessor functions
+	//@{
+	/** Get the IP address of remote connection.
+	If you are a client this returns the ip of the destination server.
+	If you are a server this returns the ip of the destination client.
+	*/
+	unsigned int getRemoteIP();
+
+	/** Get the IP address of remote connection.
+	If you are a client this returns the ip of the destination server.
+	If you are a server this returns the ip of the destination client.
+	*/
+	void getRemoteIP(char* name);
+
+	/// Get port of self.
+	int  getSelfPort();
+
+	/// Get port of client.
+	int  getRemotePort();
+	//@}
+
+	/// Show status of connection in English.
+	void showStatus(int status, int nbytes);
+
+	/// Show statistics of a connection.
+	void showStats();
+
+	/// Close the current client connection.
+	void close();
+
+	/** Connect to a server.
+	    @param ip IP address to connect to.
+	    @param port Port to connect to.
+	    @return Either: QUANTAnet_perfDaemonClient_c::OK or FAILED
+	*/
+	int connectToServer(const char* ip, int port=PERF_DAEMON_DEFAULT_PORT);
+
+	/** Set timeout for read and writes. By default no time out is set.
+	    Setting time out means that if the read or write is unsuccessful
+	    after a certain amount of time the connection will be terminated.
+	    This is to prevent you from doing subsequent writes or reads
+	    from the stream and getting incorrect data.
+	    In order to re-establish the connection you need to instantiate another
+	    object of this type.
+	*/
+	void setTimeOut(int timeout=QUANTAnet_perfDaemonClient_c::NO_TIME_OUT);
+};
+#endif
+
Index: trunk/src/testing/.pydevproject
===================================================================
--- trunk/src/testing/.pydevproject	(revision 4)
+++ trunk/src/testing/.pydevproject	(revision 4)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?>
+
+<pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
